diff --git a/lib/NGCP/Panel/Controller/API/Contracts.pm b/lib/NGCP/Panel/Controller/API/Contracts.pm index 8c0c62ed93..e941d3e7c6 100644 --- a/lib/NGCP/Panel/Controller/API/Contracts.pm +++ b/lib/NGCP/Panel/Controller/API/Contracts.pm @@ -37,11 +37,24 @@ sub query_params { }, { param => 'status', - description => 'Filter for contracts with a specific status (except "terminated")', + description => 'Filter for contracts with a specific status (comma-separated list of statuses to include possible)', query => { first => sub { my $q = shift; - { 'me.status' => $q }; + my @l = split /,/, $q; + { 'me.status' => { -in => \@l }}; + }, + second => sub {}, + }, + }, + { + param => 'not_status', + description => 'Filter for contracts not having a specific status (comma-separated list of statuses to exclude possible)', + query => { + first => sub { + my $q = shift; + my @l = split /,/, $q; + { 'me.status' => { -not_in => \@l }}; }, second => sub {}, }, @@ -92,7 +105,10 @@ sub GET :Allow { my $guard = $c->model('DB')->txn_scope_guard; { my $now = NGCP::Panel::Utils::DateTime::current_local; - my $contracts_rs = $self->item_rs($c,0,$now); + my $include_terminated = + defined $c->request->query_params->{status} + || defined $c->request->query_params->{not_status}; + my $contracts_rs = $self->item_rs($c, $include_terminated ? 1 : 0, $now); (my $total_count, $contracts_rs, my $contracts_rows) = $self->paginate_order_collection($c, $contracts_rs); my $contracts = NGCP::Panel::Utils::Contract::acquire_contract_rowlocks( c => $c, diff --git a/t/api-rest/api-contracts.t b/t/api-rest/api-contracts.t index 0f040ea463..fc4c2c304d 100644 --- a/t/api-rest/api-contracts.t +++ b/t/api-rest/api-contracts.t @@ -677,6 +677,48 @@ my @allcontracts = (); $res = $ua->request($req); is($res->code, 404, "check fetching of terminated contract"); + my $contact_q = 'contact_id='.$syscontact->{id}; + + $res = $ua->get($uri.'/api/contracts/?page=1&rows=50&'.$contact_q); + is($res->code, 200, "fetch unfiltered contracts for terminated contact"); + my $unfiltered_items = JSON::from_json($res->decoded_content)->{_embedded}{'ngcp:contracts'}; + my @unfiltered_items = !$unfiltered_items ? () : (ref $unfiltered_items eq 'ARRAY' ? @$unfiltered_items : ($unfiltered_items)); + foreach my $item (@unfiltered_items) { + ok($item->{status} ne "terminated", "unfiltered collection still excludes terminated contracts"); + } + + $res = $ua->get($uri.'/api/contracts/?page=1&rows=50&status=terminated&'.$contact_q); + is($res->code, 200, "fetch contracts with status=terminated"); + my $terminated_items = JSON::from_json($res->decoded_content)->{_embedded}{'ngcp:contracts'}; + my @terminated_items = !$terminated_items ? () : (ref $terminated_items eq 'ARRAY' ? @$terminated_items : ($terminated_items)); + ok(scalar(@terminated_items) > 0, "status=terminated returns contracts"); + my %terminated_found; + foreach my $item (@terminated_items) { + is($item->{status}, "terminated", "status=terminated item is terminated"); + $terminated_found{$item->{_links}->{self}->{href}} = 1; + } + foreach my $loc (@allcontracts) { + ok($terminated_found{$loc}, "terminated test contract $loc found via status=terminated"); + } + + $res = $ua->get($uri.'/api/contracts/?page=1&rows=50¬_status=terminated'); + is($res->code, 200, "fetch contracts with not_status=terminated"); + my $not_term_items = JSON::from_json($res->decoded_content)->{_embedded}{'ngcp:contracts'}; + my @not_term_items = !$not_term_items ? () : (ref $not_term_items eq 'ARRAY' ? @$not_term_items : ($not_term_items)); + foreach my $item (@not_term_items) { + ok($item->{status} ne "terminated", "not_status=terminated excludes terminated"); + ok(!$terminated_found{$item->{_links}->{self}->{href}}, "terminated test contract not returned by not_status=terminated"); + } + + $res = $ua->get($uri.'/api/contracts/?page=1&rows=50&status=active,pending'); + is($res->code, 200, "fetch contracts with status=active,pending"); + my $ap_items = JSON::from_json($res->decoded_content)->{_embedded}{'ngcp:contracts'}; + my @ap_items = !$ap_items ? () : (ref $ap_items eq 'ARRAY' ? @$ap_items : ($ap_items)); + ok(scalar(@ap_items) > 0, "status=active,pending returns contracts"); + foreach my $item (@ap_items) { + ok($item->{status} eq "active" || $item->{status} eq "pending", "status=active,pending item has allowed status"); + } + # check if deletion of contact is now ok # TODO: are we supposed to be able to delete a contact for a terminated # contract? there are still DB contstraints in the way! diff --git a/t/api-rest2/Contracts.yaml b/t/api-rest2/Contracts.yaml index b99bddcd33..fe543321e9 100644 --- a/t/api-rest2/Contracts.yaml +++ b/t/api-rest2/Contracts.yaml @@ -932,6 +932,72 @@ is: code: 404 +#GET contracts with status=terminated +- + name: GET contracts with status=terminated + type: item + method: GET + path: '/api/contracts/?page=1&rows=50&status=terminated&contact_id=${system_contact_id}' + retain: + terminated_contracts: body + perl_code: !!perl/code | + { + my ($retained) = @_; + my $embedded = $retained->{terminated_contracts}->{_embedded}->{'ngcp:contracts'}; + my @items = !$embedded ? () : (ref $embedded eq 'ARRAY' ? @$embedded : ($embedded)); + $retained->{terminated_statuses_ok} = (grep { $_->{status} ne 'terminated' } @items) ? 0 : 1; + $retained->{terminated_found} = (grep { ($_->{_links}{self}{href} // '') eq $retained->{contract_path} } @items) ? 1 : 0; + } + conditions: + is: + code: 200 + '${terminated_statuses_ok}': 1 + '${terminated_found}': 1 + +#GET contracts with not_status=terminated +- + name: GET contracts with not_status=terminated + type: item + method: GET + path: '/api/contracts/?page=1&rows=50¬_status=terminated' + retain: + not_terminated_contracts: body + perl_code: !!perl/code | + { + my ($retained) = @_; + my $embedded = $retained->{not_terminated_contracts}->{_embedded}->{'ngcp:contracts'}; + my @items = !$embedded ? () : (ref $embedded eq 'ARRAY' ? @$embedded : ($embedded)); + $retained->{not_terminated_statuses_ok} = (grep { $_->{status} eq 'terminated' } @items) ? 0 : 1; + $retained->{not_terminated_excludes_contract} = (grep { ($_->{_links}{self}{href} // '') eq $retained->{contract_path} } @items) ? 0 : 1; + } + conditions: + is: + code: 200 + '${not_terminated_statuses_ok}': 1 + '${not_terminated_excludes_contract}': 1 + +#GET contracts with status=active,pending +- + name: GET contracts with status=active,pending + type: item + method: GET + path: '/api/contracts/?page=1&rows=50&status=active,pending' + retain: + active_pending_contracts: body + perl_code: !!perl/code | + { + my ($retained) = @_; + my $embedded = $retained->{active_pending_contracts}->{_embedded}->{'ngcp:contracts'}; + my @items = !$embedded ? () : (ref $embedded eq 'ARRAY' ? @$embedded : ($embedded)); + $retained->{active_pending_count_ok} = scalar(@items) > 0 ? 1 : 0; + $retained->{active_pending_statuses_ok} = (grep { $_->{status} ne 'active' && $_->{status} ne 'pending' } @items) ? 0 : 1; + } + conditions: + is: + code: 200 + '${active_pending_count_ok}': 1 + '${active_pending_statuses_ok}': 1 + #terminate billingprofile - name: 'terminate billingprofile'