You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							1375 lines
						
					
					
						
							39 KiB
						
					
					
				
			
		
		
	
	
							1375 lines
						
					
					
						
							39 KiB
						
					
					
				| ---
 | |
| #check options
 | |
| -
 | |
|     name: check OPTIONS for customers
 | |
|     type: item
 | |
|     method: OPTIONS
 | |
|     path: /api/customers/
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 200
 | |
|             header:
 | |
|                 Accept-Post: application/hal+json; profile=http://purl.org/sipwise/ngcp-api/#rel-customers
 | |
|         ok:
 | |
|             options:
 | |
|                 - GET
 | |
|                 - HEAD
 | |
|                 - OPTIONS
 | |
|                 - POST
 | |
| 
 | |
| #create a BillingProfile
 | |
| -
 | |
|     name: create a BillingProfile
 | |
|     type: item
 | |
|     thread: 1
 | |
|     method: POST
 | |
|     path: /api/billingprofiles/
 | |
|     header:
 | |
|         Content-Type: application/json
 | |
|         Prefer: return=representation
 | |
|     content:
 | |
|         name: test profile ${unique_id}
 | |
|         handle: test_profile_handle${unique_id}
 | |
|         reseller_id: 1
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 201
 | |
|     retain:
 | |
|         billing_profile_id: header.location
 | |
| 
 | |
| #create a Customer Contact
 | |
| -
 | |
|     name: create a Customer Contact
 | |
|     type: item
 | |
|     method: POST
 | |
|     path: /api/customercontacts/
 | |
|     header:
 | |
|         Content-Type: application/json
 | |
|     content:
 | |
|         firstname: cust_contact_first
 | |
|         lastname: cust_contact_last
 | |
|         email: cust_contact@custcontact.invalid
 | |
|         reseller_id: 1
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 201
 | |
|     retain:
 | |
|         customer_contact_path: header.location
 | |
|         customer_contact_id: header.location
 | |
| 
 | |
| #check CustomerContact
 | |
| -
 | |
|     name: check CustomerContact
 | |
|     type: item
 | |
|     method: GET
 | |
|     path: '/${customer_contact_path}'
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 200
 | |
| 
 | |
| #create a System Contact
 | |
| -
 | |
|     name: create a System Contact
 | |
|     type: item
 | |
|     method: POST
 | |
|     path: /api/systemcontacts/
 | |
|     header:
 | |
|         Content-Type: application/json
 | |
|     content:
 | |
|         firstname: sys_contact_first
 | |
|         lastname: sys_contact_last
 | |
|         email: sys_contact@syscontact.invalid
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 201
 | |
|     retain:
 | |
|         system_contact_path: header.location
 | |
|         system_contact_id: header.location
 | |
| 
 | |
| #get System Contact
 | |
| -
 | |
|     name: get System Contact
 | |
|     type: item
 | |
|     method: GET
 | |
|     path: '/${system_contact_path}'
 | |
|     retain:
 | |
|         system_contact: body
 | |
| 
 | |
| #create batch
 | |
| -
 | |
|     name: create batch
 | |
|     type: batch
 | |
|     method: POST
 | |
|     path: '/api/customers/'
 | |
|     iterations: 6
 | |
|     header:
 | |
|         Content-Type: application/json
 | |
|     content:
 | |
|         status: active
 | |
|         contact_id: ${customer_contact_id}
 | |
|         type: sipaccount
 | |
|         billing_profile_id: ${billing_profile_id}
 | |
|         max_subscribers: null
 | |
|         external_id: null
 | |
|     retain:
 | |
|         customer_path: header.location
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 201
 | |
| 
 | |
| #create invalid Customer with wrong type
 | |
| -
 | |
|     name: create invalid Customer with wrong type
 | |
|     type: item
 | |
|     method: POST
 | |
|     path: '/api/customers/'
 | |
|     header:
 | |
|         Content-Type: application/json
 | |
|     content:
 | |
|         status: active
 | |
|         contact_id: ${customer_contact_id}
 | |
|         billing_profile_id: ${billing_profile_id}
 | |
|         type: invalid
 | |
|         max_subscribers: null
 | |
|         external_id: null
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 422
 | |
|             body.code: 422
 | |
|         like:
 | |
|             body.message: is not a valid value
 | |
| 
 | |
| #create invalid Customer with wrong billing profile
 | |
| -
 | |
|     name: create invalid Customer with wrong billing profile
 | |
|     type: item
 | |
|     method: POST
 | |
|     path: '/api/customers/'
 | |
|     header:
 | |
|         Content-Type: application/json
 | |
|     content:
 | |
|         status: active
 | |
|         contact_id: ${customer_contact_id}
 | |
|         billing_profile_id: 999999
 | |
|         type: sipaccount
 | |
|         max_subscribers: null
 | |
|         external_id: null
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 422
 | |
|             body.code: 422
 | |
|         like:
 | |
|             body.message: Invalid 'billing_profile_id'
 | |
| 
 | |
| #create invalid Customer with systemcontact
 | |
| -
 | |
|     name: create invalid Customer with systemcontact
 | |
|     type: item
 | |
|     method: POST
 | |
|     path: '/api/customers/'
 | |
|     header:
 | |
|         Content-Type: application/json
 | |
|     content:
 | |
|         status: active
 | |
|         type: sipaccount
 | |
|         billing_profile_id: ${billing_profile_id}
 | |
|         contact_id: ${system_contact_id}
 | |
|         max_subscribers: null
 | |
|         external_id: null
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 422
 | |
|             body.code: 422
 | |
|         like:
 | |
|             body.message: The contact_id is not a valid ngcp:customercontacts item
 | |
| 
 | |
| #create invalid Customer without contact
 | |
| -
 | |
|     name: create invalid Customer without contact
 | |
|     type: item
 | |
|     method: POST
 | |
|     path: '/api/customers/'
 | |
|     header:
 | |
|         Content-Type: application/json
 | |
|     content:
 | |
|         status: active
 | |
|         type: sipaccount
 | |
|         billing_profile_id: ${billing_profile_id}
 | |
|         max_subscribers: null
 | |
|         external_id: null
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 422
 | |
| 
 | |
| #create invalid Customer with invalid status
 | |
| -
 | |
|     name: create invalid Customer with invalid status
 | |
|     type: item
 | |
|     method: POST
 | |
|     path: '/api/customers/'
 | |
|     header:
 | |
|         Content-Type: application/json
 | |
|     content:
 | |
|         status: invalid
 | |
|         type: sipaccount
 | |
|         billing_profile_id: ${billing_profile_id}
 | |
|         contact_id: ${customer_contact_id}
 | |
|         max_subscribers: null
 | |
|         external_id: null
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 422
 | |
|             body.code: 422
 | |
|         like:
 | |
|             body.message: field='status'
 | |
| 
 | |
| #create invalid Customer with invalid max_subscribers
 | |
| -
 | |
|     name: create invalid Customer with invalid status
 | |
|     type: item
 | |
|     method: POST
 | |
|     path: '/api/customers/'
 | |
|     header:
 | |
|         Content-Type: application/json
 | |
|     content:
 | |
|         status: active
 | |
|         type: sipaccount
 | |
|         billing_profile_id: ${billing_profile_id}
 | |
|         contact_id: ${customer_contact_id}
 | |
|         max_subscribers: 'abc'
 | |
|         external_id: null
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 422
 | |
|             body.code: 422
 | |
|         like:
 | |
|             body.message: field='max_subscribers'
 | |
| 
 | |
| #verify pagination
 | |
| -
 | |
|     skip: 1
 | |
|     name: verify pagination
 | |
|     type: pagination
 | |
|     method: GET
 | |
|     path: '/api/customers/?page=1&rows=5'
 | |
|     retain:
 | |
|         collection: body
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 200
 | |
| 
 | |
| #check options on customer
 | |
| -
 | |
|     name: check OPTIONS on customer
 | |
|     type: item
 | |
|     method: OPTIONS
 | |
|     path: '/${customer_path}'
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 200
 | |
|         ok:
 | |
|             options:
 | |
|                 - GET
 | |
|                 - HEAD
 | |
|                 - OPTIONS
 | |
|                 - PUT
 | |
|                 - PATCH
 | |
| 
 | |
| #get customer
 | |
| -
 | |
|     name: GET customer
 | |
|     type: item
 | |
|     method: GET
 | |
|     path: '/${customer_path}'
 | |
|     retain:
 | |
|         customer: body
 | |
|     perl_code: !!perl/code |
 | |
|         {
 | |
|             my ($retained) = @_;
 | |
|             map { delete $_->{effective_start_time}; $_; } @{$retained->{customer}->{all_billing_profiles}};
 | |
|         }        
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 200
 | |
|         ok:
 | |
|             '${customer}.status': defined
 | |
|             '${customer}.type': defined
 | |
|             '${customer}.billing_profile_id': defined
 | |
|             '${customer}.contact_id': defined
 | |
|             '${customer}.id': defined
 | |
|             '${customer}.all_billing_profiles': defined
 | |
|             '${customer}.product_id': undefined
 | |
|         like:
 | |
|             '${customer}.billing_profile_id': '[0-9]+'
 | |
|             '${customer}.contact_id': '[0-9]+'
 | |
|             '${customer}.id': '[0-9]+'
 | |
|         is_deeply:
 | |
|             '${customer}.all_billing_profiles':
 | |
|                 -
 | |
|                     profile_id: ${billing_profile_id}
 | |
|                     start: null
 | |
|                     stop: null
 | |
|                     network_id: null
 | |
| 
 | |
| #put customer with missing content-type
 | |
| -
 | |
|     name: PUT customer with missing content-type
 | |
|     type: item
 | |
|     method: PUT
 | |
|     path: '/${customer_path}'
 | |
|     header:
 | |
|         Prefer: return=minimal
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 415
 | |
| 
 | |
| #put customer with unsupported content type
 | |
| -
 | |
|     name: PUT customer with unsupported Content-Type
 | |
|     type: item
 | |
|     method: PUT
 | |
|     path: '/${customer_path}'
 | |
|     header:
 | |
|         Content-Type: application/xxx
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 415
 | |
| 
 | |
| #put customer with missing body
 | |
| -
 | |
|     name: PUT customer with missing body
 | |
|     type: item
 | |
|     method: PUT
 | |
|     path: '/${customer_path}'
 | |
|     header:
 | |
|         Content-Type: application/json
 | |
|         Prefer: return=representation
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 400
 | |
| 
 | |
| #put customer
 | |
| -
 | |
|     name: PUT customer
 | |
|     type: item
 | |
|     method: PUT
 | |
|     path: '/${customer_path}'
 | |
|     header:
 | |
|         Content-Type: application/json
 | |
|         Prefer: return=representation
 | |
|     content: '${customer}'
 | |
|     retain:
 | |
|         new_customer: body
 | |
|     perl_code: !!perl/code |
 | |
|         {
 | |
|             my ($retained) = @_;
 | |
|             map { delete $_->{effective_start_time}; $_; } @{$retained->{new_customer}->{all_billing_profiles}};
 | |
|             delete $retained->{customer}->{modify_timestamp};
 | |
|             delete $retained->{new_customer}->{modify_timestamp};
 | |
|         }        
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 200
 | |
|         is_deeply:
 | |
|             '${customer}': ${new_customer}
 | |
|         ok:
 | |
|             '${new_customer}._links.ngcp:customercontacts': defined
 | |
|             '${new_customer}._links.ngcp:billingprofiles': defined
 | |
| 
 | |
| #modify customer status
 | |
| -
 | |
|     name: modify customer status
 | |
|     type: item
 | |
|     method: PATCH
 | |
|     path: '/${customer_path}'
 | |
|     header:
 | |
|         Content-Type: application/json-patch+json
 | |
|         Prefer: return=representation
 | |
|     content:
 | |
|         -
 | |
|             op: replace
 | |
|             path: /status
 | |
|             value: pending
 | |
|     retain:
 | |
|         modified_customer: body
 | |
|     conditions:
 | |
|         is: 
 | |
|             code: 200
 | |
|             '${modified_customer}.status': pending
 | |
|             '${modified_customer}._links.self.href': ${customer_path}
 | |
|             '${modified_customer}._links.collection.href': /api/customers/
 | |
| 
 | |
| #check patch with status undef
 | |
| -
 | |
|     name: check patch with status undef
 | |
|     type: item
 | |
|     method: PATCH
 | |
|     path: '/${customer_path}'
 | |
|     header:
 | |
|         Content-Type: application/json-patch+json
 | |
|         Prefer: return=representation
 | |
|     content:
 | |
|         -
 | |
|             op: replace
 | |
|             path: /status
 | |
|             value: null
 | |
|     conditions:
 | |
|         is: 
 | |
|             code: 422
 | |
| 
 | |
| #check patch with invalid status
 | |
| -
 | |
|     name: check patch with invalid status
 | |
|     type: item
 | |
|     method: PATCH
 | |
|     path: '/${customer_path}'
 | |
|     header:
 | |
|         Content-Type: application/json-patch+json
 | |
|         Prefer: return=representation
 | |
|     content:
 | |
|         -
 | |
|             op: replace
 | |
|             path: /status
 | |
|             value: invalid
 | |
|     conditions:
 | |
|         is: 
 | |
|             code: 422
 | |
| 
 | |
| #check patch with invalid contact_id
 | |
| -
 | |
|     name: check patch with invalid contact_id
 | |
|     type: item
 | |
|     method: PATCH
 | |
|     path: '/${customer_path}'
 | |
|     header:
 | |
|         Content-Type: application/json-patch+json
 | |
|         Prefer: return=representation
 | |
|     content:
 | |
|         -
 | |
|             op: replace
 | |
|             path: /contact_id
 | |
|             value: 99999
 | |
|     conditions:
 | |
|         is: 
 | |
|             code: 422
 | |
| 
 | |
| #check patch with system contact_id
 | |
| -
 | |
|     name: check patch with system contact_id
 | |
|     type: item
 | |
|     method: PATCH
 | |
|     path: '/${customer_path}'
 | |
|     header:
 | |
|         Content-Type: application/json-patch+json
 | |
|         Prefer: return=representation
 | |
|     content:
 | |
|         -
 | |
|             op: replace
 | |
|             path: /contact_id
 | |
|             value: ${system_contact_id}
 | |
|     conditions:
 | |
|         is: 
 | |
|             code: 422
 | |
| 
 | |
| #check patch with undef billing_profile_id
 | |
| -
 | |
|     name: check patch with undef billing_profile_id
 | |
|     type: item
 | |
|     method: PATCH
 | |
|     path: '/${customer_path}'
 | |
|     header:
 | |
|         Content-Type: application/json-patch+json
 | |
|         Prefer: return=representation
 | |
|     content:
 | |
|         -
 | |
|             op: replace
 | |
|             path: /billing_profile_id
 | |
|             value: null
 | |
|     conditions:
 | |
|         is: 
 | |
|             code: 422
 | |
| 
 | |
| #check patch with invalid billing_profile_id
 | |
| -
 | |
|     name: check patch with invalid billing_profile_id
 | |
|     type: item
 | |
|     method: PATCH
 | |
|     path: '/${customer_path}'
 | |
|     header:
 | |
|         Content-Type: application/json-patch+json
 | |
|         Prefer: return=representation
 | |
|     content:
 | |
|         -
 | |
|             op: replace
 | |
|             path: /billing_profile_id
 | |
|             value: 99999
 | |
|     conditions:
 | |
|         is: 
 | |
|             code: 422
 | |
| 
 | |
| #check patch with invalid max_subscribers
 | |
| -
 | |
|     name: check patch with invalid billing_profile_id
 | |
|     type: item
 | |
|     method: PATCH
 | |
|     path: '/${customer_path}'
 | |
|     header:
 | |
|         Content-Type: application/json-patch+json
 | |
|         Prefer: return=representation
 | |
|     content:
 | |
|         -
 | |
|             op: replace
 | |
|             path: /max_subscribers
 | |
|             value: 'abc'
 | |
|     conditions:
 | |
|         is: 
 | |
|             code: 422
 | |
| 
 | |
| #multi-bill-prof: create another test billing profile
 | |
| -
 | |
|     name: 'multi-bill-prof: create another test billing profile'
 | |
|     type: item
 | |
|     method: POST
 | |
|     path: '/api/billingprofiles/'
 | |
|     header:
 | |
|         Content-Type: application/json
 | |
|         Prefer: return=representation
 | |
|     content:
 | |
|         name: SECOND test profile ${unique_id}
 | |
|         handle: second_testprofile${unique_id}
 | |
|         reseller_id: 1
 | |
|     retain:
 | |
|         second_billing_profile_id: header.location
 | |
|     conditions:
 | |
|         is: 
 | |
|             code: 201
 | |
| 
 | |
| #multi-bill-prof: create test billing network
 | |
| -
 | |
|     name: 'multi-bill-prof: create test billing network'
 | |
|     type: item
 | |
|     method: POST
 | |
|     path: '/api/billingnetworks/'
 | |
|     header:
 | |
|         Content-Type: application/json
 | |
|         Prefer: return=representation
 | |
|     content:
 | |
|         name: test billing network ${unique_id}
 | |
|         description: test billing network description ${unique_id}
 | |
|         reseller_id: 1
 | |
|         blocks:
 | |
|             -
 | |
|                 ip: '10.0.4.7'
 | |
|                 mask: '26'
 | |
|             -
 | |
|                 ip: '10.0.4.99'
 | |
|                 mask: '26'
 | |
|             -
 | |
|                 ip: '10.0.5.9'
 | |
|                 mask: '24'
 | |
|             -
 | |
|                 ip: '10.0.6.9'
 | |
|                 mask: '24'
 | |
|     retain:
 | |
|         billing_network_id: header.location
 | |
|     conditions:
 | |
|         is: 
 | |
|             code: 201
 | |
|     perl_code: !!perl/code |
 | |
|         {
 | |
|             my ( $retained ) = @_;
 | |
| 
 | |
|             my $dtf = DateTime::Format::Strptime->new(
 | |
|                 pattern => '%F %T',
 | |
|             ); #DateTime::Format::Strptime->new( pattern => '%Y-%m-%d %H:%M:%S' );
 | |
|             my $now = DateTime->now(
 | |
|                 time_zone => DateTime::TimeZone->new(name => 'local')
 | |
|             );
 | |
|             my $t1 = $now->clone->add(days => 1);
 | |
|             my $t2 = $now->clone->add(days => 2);
 | |
|             my $t3 = $now->clone->add(days => 3);
 | |
| 
 | |
|             my $billing_profile_id = $retained->{billing_profile_id};
 | |
| 
 | |
|             $retained->{malformed_profilemappings1} = [ { profile_id => $billing_profile_id,
 | |
|                                                           start => $dtf->format_datetime($now),
 | |
|                                                           stop => $dtf->format_datetime($now),} ];
 | |
|             $retained->{malformed_profilemappings2} = [ { profile_id => $billing_profile_id,
 | |
|                                                           start => $dtf->format_datetime($t1),
 | |
|                                                           stop => $dtf->format_datetime($t1),} ];
 | |
|             $retained->{malformed_profilemappings3} = [ { profile_id => $billing_profile_id,
 | |
|                                                           start => undef,
 | |
|                                                           stop => $dtf->format_datetime($now),},];
 | |
|             $retained->{malformed_profilemappings4} = [ { profile_id => $billing_profile_id,
 | |
|                                                           start => $dtf->format_datetime($t1),
 | |
|                                                           stop => $dtf->format_datetime($t2),}, ];
 | |
|             $retained->{correct_profile_mappings1} = [ { profile_id => $retained->{second_billing_profile_id},
 | |
|                                                         start => undef,
 | |
|                                                         stop => undef,
 | |
|                                                         network_id => undef },
 | |
|                                                       { profile_id => $billing_profile_id,
 | |
|                                                         start => $dtf->format_datetime($t1),
 | |
|                                                         stop => $dtf->format_datetime($t2),
 | |
|                                                         network_id => undef },
 | |
|                                                        { profile_id => $billing_profile_id,
 | |
|                                                          start => $dtf->format_datetime($t2),
 | |
|                                                          stop => $dtf->format_datetime($t3),
 | |
|                                                          network_id => undef }
 | |
|                                                     ];
 | |
|             $retained->{correct_profile_mappings2} = [ { profile_id => $billing_profile_id,
 | |
|                                                         start => $dtf->format_datetime($t1),
 | |
|                                                         stop => $dtf->format_datetime($t2),
 | |
|                                                         network_id=> undef },
 | |
|                                                       { profile_id => $billing_profile_id,
 | |
|                                                         start => $dtf->format_datetime($t2),
 | |
|                                                         stop => $dtf->format_datetime($t3),
 | |
|                                                         network_id => undef },
 | |
|                                                        { profile_id => $retained->{second_billing_profile_id},
 | |
|                                                          start => $dtf->format_datetime($t3),
 | |
|                                                          stop => undef,
 | |
|                                                          network_id => $retained->{billing_network_id} }
 | |
|                                                     ];
 | |
|         }        
 | |
| 
 | |
| #multi-bill-prof POST: check 'start' timestamp is not in future
 | |
| -
 | |
|     name: 'multi-bill-prof POST: check "start" timestamp is not in future'
 | |
|     type: item
 | |
|     method: POST
 | |
|     path: '/api/customers/'
 | |
|     header:
 | |
|         Content-Type: application/json
 | |
|     content:
 | |
|         status: active
 | |
|         contact_id: ${customer_contact_id}
 | |
|         type: sipaccount
 | |
|         max_subscriber: null
 | |
|         external_id: null
 | |
|         billing_profile_definition: profiles
 | |
|         billing_profiles: ${malformed_profilemappings1}
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 422
 | |
| 
 | |
| #multi-bill-prof POST: check 'start' timestamp has to be before 'stop' timestamp
 | |
| -
 | |
|     name: 'multi-bill-prof POST: check "start" timestamp has to be before "stop" timestamp'
 | |
|     type: item
 | |
|     method: POST
 | |
|     path: '/api/customers/'
 | |
|     header:
 | |
|         Content-Type: application/json
 | |
|     content:
 | |
|         status: active
 | |
|         contact_id: ${customer_contact_id}
 | |
|         type: sipaccount
 | |
|         max_subscriber: null
 | |
|         external_id: null
 | |
|         billing_profile_definition: profiles
 | |
|         billing_profiles: ${malformed_profilemappings2}
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 422
 | |
| 
 | |
| #multi-bill-prof POST: check Interval with 'stop' timestamp but no 'start' timestamp specified
 | |
| -
 | |
|     name: 'multi-bill-prof POST: check "Interval with "stop" timestamp but no "start" timestamp specified"'
 | |
|     type: item
 | |
|     method: POST
 | |
|     path: '/api/customers/'
 | |
|     header:
 | |
|         Content-Type: application/json
 | |
|     content:
 | |
|         status: active
 | |
|         contact_id: ${customer_contact_id}
 | |
|         type: sipaccount
 | |
|         max_subscriber: null
 | |
|         external_id: null
 | |
|         billing_profile_definition: profiles
 | |
|         billing_profiles: ${malformed_profilemappings3}
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 422
 | |
| 
 | |
| #multi-bill-prof POST: check An initial interval without 'start' and 'stop' timestamps is required
 | |
| -
 | |
|     name: 'multi-bill-prof POST: check An initial interval without "start" and "stop" timestamps is required'
 | |
|     type: item
 | |
|     method: POST
 | |
|     path: '/api/customers/'
 | |
|     header:
 | |
|         Content-Type: application/json
 | |
|     content:
 | |
|         status: active
 | |
|         contact_id: ${customer_contact_id}
 | |
|         type: sipaccount
 | |
|         max_subscriber: null
 | |
|         external_id: null
 | |
|         billing_profile_definition: profiles
 | |
|         billing_profiles: ${malformed_profilemappings4}
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 422
 | |
| 
 | |
| #multi-bill-prof: create test customer
 | |
| -
 | |
|     name: 'multi-bill-prof: create test customer'
 | |
|     type: item
 | |
|     method: POST
 | |
|     path: '/api/customers/'
 | |
|     header:
 | |
|         Content-Type: application/json
 | |
|     content:
 | |
|         status: active
 | |
|         contact_id: ${customer_contact_id}
 | |
|         type: sipaccount
 | |
|         max_subscriber: null
 | |
|         external_id: null
 | |
|         billing_profile_definition: profiles
 | |
|         billing_profiles: ${correct_profile_mappings1}
 | |
|     retain:
 | |
|         customer_path: header.location
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 201
 | |
| 
 | |
| #get customer
 | |
| -
 | |
|     name: GET customer
 | |
|     type: item
 | |
|     method: GET
 | |
|     path: '/${customer_path}'
 | |
|     retain:
 | |
|         customer: body
 | |
|     perl_code: !!perl/code |
 | |
|         {
 | |
|             my ($retained) = @_;
 | |
|             map { delete $_->{effective_start_time}; $_; } @{$retained->{customer}->{all_billing_profiles}};
 | |
|             $retained->{malformed_profilemappings4} = [ { profile_id => $retained->{billing_profile_id},
 | |
|                                                           start => undef,
 | |
|                                                           stop => undef,}, ];
 | |
|         }        
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 200
 | |
|             '${customer}.billing_profile_id': ${second_billing_profile_id}
 | |
|         ok:
 | |
|             '${customer}.billing_profile_id': defined
 | |
|             '${customer}.billing_profiles': defined
 | |
|             '${customer}.all_billing_profiles': defined
 | |
|         is_deeply:
 | |
|             '${customer}.all_billing_profiles': ${correct_profile_mappings1}
 | |
| 
 | |
| #multi-bill-prof PATCH: check 'start' timestamp is not in future
 | |
| -
 | |
|     name: 'multi-bill-prof PATCH: check "start" timestamp is not in future'
 | |
|     type: item
 | |
|     method: PATCH
 | |
|     path: '/${customer_path}'
 | |
|     header:
 | |
|         Content-Type: application/json-patch+json
 | |
|         Prefer: return=representation
 | |
|     content:
 | |
|         -
 | |
|             op: replace
 | |
|             path: /billing_profiles
 | |
|             value: ${malformed_profilemappings1}
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 422
 | |
| 
 | |
| #multi-bill-prof PATCH: check 'start' timestamp has to be before 'stop' timestamp
 | |
| -
 | |
|     name: 'multi-bill-prof PATCH: check "start" timestamp has to be before "stop" timestamp'
 | |
|     type: item
 | |
|     method: PATCH
 | |
|     path: '/${customer_path}'
 | |
|     header:
 | |
|         Content-Type: application/json-patch+json
 | |
|         Prefer: return=representation
 | |
|     content:
 | |
|         -
 | |
|             op: replace
 | |
|             path: /billing_profiles
 | |
|             value: ${malformed_profilemappings2}
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 422
 | |
| 
 | |
| #multi-bill-prof PATCH: check Interval with 'stop' timestamp but no 'start' timestamp specified
 | |
| -
 | |
|     name: 'multi-bill-prof PATCH: check Interval with "stop" timestamp but no "start" timestamp specified'
 | |
|     type: item
 | |
|     method: PATCH
 | |
|     path: '/${customer_path}'
 | |
|     header:
 | |
|         Content-Type: application/json-patch+json
 | |
|         Prefer: return=representation
 | |
|     content:
 | |
|         -
 | |
|             op: replace
 | |
|             path: /billing_profiles
 | |
|             value: ${malformed_profilemappings3}
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 422
 | |
| 
 | |
| #multi-bill-prof PATCH: check Adding intervals without 'start' and 'stop' timestamps is not allowed.
 | |
| -
 | |
|     name: 'multi-bill-prof PATCH: check Adding intervals without "start" and "stop" timestamps is not allowed.'
 | |
|     type: item
 | |
|     method: PATCH
 | |
|     path: '/${customer_path}'
 | |
|     header:
 | |
|         Content-Type: application/json-patch+json
 | |
|         Prefer: return=representation
 | |
|     content:
 | |
|         -
 | |
|             op: replace
 | |
|             path: /billing_profiles
 | |
|             value: ${malformed_profilemappings4}
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 422
 | |
| 
 | |
| #multi-bill-prof PATCH: test customer with new billing profile
 | |
| -
 | |
|     name: 'multi-bill-prof PATCH: test customer with new billing profile'
 | |
|     type: item
 | |
|     method: PATCH
 | |
|     path: '/${customer_path}'
 | |
|     header:
 | |
|         Content-Type: application/json-patch+json
 | |
|         Prefer: return=representation
 | |
|     retain:
 | |
|         patched_customer: body
 | |
|     content:
 | |
|         -
 | |
|             op: replace
 | |
|             path: /billing_profile_id
 | |
|             value: ${billing_profile_id}
 | |
|     perl_code: !!perl/code |
 | |
|         {
 | |
|             my ($retained) = @_;
 | |
| 
 | |
|             $retained->{posted_profiles_number} = scalar @{$retained->{correct_profile_mappings1}} + 1;
 | |
|             $retained->{actual_profiles_number} = scalar @{$retained->{patched_customer}->{all_billing_profiles}};
 | |
| 
 | |
|             my $now = DateTime->now(
 | |
|                 time_zone => DateTime::TimeZone->new(name => 'local')
 | |
|             );
 | |
|             foreach my $m ( @{$retained->{patched_customer}->{billing_profiles}} ) {
 | |
|                 if (!defined $m->{start}) {
 | |
|                     push(@{$retained->{expected_mappings}},$m);
 | |
|                     next;
 | |
|                 }
 | |
|                 my $s = $m->{start};
 | |
|                 $s =~ s/^(\d{4}\-\d{2}\-\d{2})\s+(\d.+)$/$1T$2/;
 | |
|                 my $start = DateTime::Format::ISO8601->parse_datetime($s);
 | |
|                 $start->set_time_zone( DateTime::TimeZone->new(name => 'local') );
 | |
|                 push(@{$retained->{expected_mappings}},$m) if ($start <= $now);
 | |
|             }
 | |
|             push ( @{$retained->{expected_mappings}}, @{$retained->{correct_profile_mappings2}} );
 | |
|         }        
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 200
 | |
|             '${patched_customer}.billing_profile_id': ${billing_profile_id}
 | |
|             '${posted_profiles_number}': '${actual_profiles_number}'
 | |
|         ok:
 | |
|             '${patched_customer}.billing_profile_id': defined
 | |
|             '${patched_customer}.billing_profiles': defined
 | |
|             '${patched_customer}.all_billing_profiles': defined
 | |
| 
 | |
| #multi-bill-prof: patch test customer
 | |
| -
 | |
|     name: 'multi-bill-prof: patch test customer'
 | |
|     type: item
 | |
|     method: PATCH
 | |
|     path: '/${customer_path}'
 | |
|     header:
 | |
|         Content-Type: application/json-patch+json
 | |
|         Prefer: return=representation
 | |
|     retain:
 | |
|         patched_customer: body
 | |
|     content:
 | |
|         -
 | |
|             op: replace
 | |
|             path: /billing_profiles
 | |
|             value: ${correct_profile_mappings2}
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 200
 | |
| 
 | |
| #get customer
 | |
| -
 | |
|     name: GET customer
 | |
|     type: item
 | |
|     method: GET
 | |
|     path: '/${customer_path}'
 | |
|     retain:
 | |
|         got_customer: body
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 200
 | |
|             '${patched_customer}.billing_profile_id': ${billing_profile_id}
 | |
|         ok:
 | |
|             '${patched_customer}.billing_profile_id': defined
 | |
|             '${patched_customer}.billing_profiles': defined
 | |
|         is_deeply:
 | |
|             '${got_customer}': '${patched_customer}'
 | |
| 
 | |
| #multi-bill-prof: put test customer
 | |
| -
 | |
|     name: 'multi-bill-prof: put test customer'
 | |
|     type: item
 | |
|     method: PUT
 | |
|     path: '/${customer_path}'
 | |
|     header:
 | |
|         Content-Type: application/json
 | |
|         Prefer: return=representation
 | |
|     retain:
 | |
|         updated_customer: body
 | |
|     content:
 | |
|         status: active
 | |
|         contact_id: ${customer_contact_id}
 | |
|         type: sipaccount
 | |
|         max_subscriber: null
 | |
|         external_id: null
 | |
|         billing_profile_definition: profiles
 | |
|         billing_profiles: ${correct_profile_mappings2}
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 200
 | |
| 
 | |
| #get customer
 | |
| -
 | |
|     name: GET customer
 | |
|     type: item
 | |
|     method: GET
 | |
|     path: '/${customer_path}'
 | |
|     retain:
 | |
|         got_customer: body
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 200
 | |
|             '${updated_customer}.billing_profile_id': ${billing_profile_id}
 | |
|         ok:
 | |
|             '${updated_customer}.billing_profile_id': defined
 | |
|             '${updated_customer}.billing_profiles': defined
 | |
|         is_deeply:
 | |
|             '${got_customer}': '${updated_customer}'
 | |
| 
 | |
| 
 | |
| #multi-bill-prof: terminate customer
 | |
| -
 | |
|     name: 'multi-bill-prof: terminate customer'
 | |
|     type: item
 | |
|     method: PATCH
 | |
|     path: '/${customer_path}'
 | |
|     header:
 | |
|         Content-Type: application/json-patch+json
 | |
|         Prefer: return=representation
 | |
|     content:
 | |
|         -
 | |
|             op: replace
 | |
|             path: /status
 | |
|             value: terminated
 | |
|     perl_code: !!perl/code |
 | |
|         {
 | |
|             my ($retained) = @_;
 | |
|             map { delete $_->{effective_start_time}; $_; } @{$retained->{patched_customer}->{billing_profiles}};
 | |
|             map { delete $_->{effective_start_time}; $_; } @{$retained->{updated_customer}->{billing_profiles}};
 | |
|         }        
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 200
 | |
|         is_deeply:
 | |
|             #perform tests against stripped mapping here, because deleting start_time would have affected previous is_deeply verification
 | |
|             '${patched_customer}.billing_profiles': '${expected_mappings}'
 | |
|             '${updated_customer}.billing_profiles': '${expected_mappings}'
 | |
| 
 | |
| #terminate billingprofile
 | |
| -
 | |
|     name: 'terminate billingprofile'
 | |
|     type: item
 | |
|     method: PATCH
 | |
|     path: '/api/billingprofiles/${second_billing_profile_id}'
 | |
|     header:
 | |
|         Content-Type: application/json-patch+json
 | |
|         Prefer: return=representation
 | |
|     content:
 | |
|         -
 | |
|             op: replace
 | |
|             path: /status
 | |
|             value: terminated
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 200
 | |
| 
 | |
| #terminate billingnetwork
 | |
| -
 | |
|     name: 'terminate billingnetwork'
 | |
|     type: item
 | |
|     method: PATCH
 | |
|     path: '/api/billingnetworks/${billing_network_id}'
 | |
|     header:
 | |
|         Content-Type: application/json-patch+json
 | |
|         Prefer: return=representation
 | |
|     content:
 | |
|         -
 | |
|             op: replace
 | |
|             path: /status
 | |
|             value: terminated
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 200
 | |
| 
 | |
| #prof-package: create another test billing profile
 | |
| -
 | |
|     name: 'prof-package: create another test billing profile'
 | |
|     type: item
 | |
|     method: POST
 | |
|     path: '/api/billingprofiles/'
 | |
|     header:
 | |
|         Content-Type: application/json
 | |
|         Prefer: return=representation
 | |
|     content:
 | |
|         name: THIRD test profile ${unique_id}
 | |
|         handle: third_testprofile${unique_id}
 | |
|         reseller_id: 1
 | |
|     retain:
 | |
|         third_billing_profile_id: header.location
 | |
|     conditions:
 | |
|         is: 
 | |
|             code: 201
 | |
| 
 | |
| #prof-package: create test billingnetwork
 | |
| -
 | |
|     name: 'prof-package: create test billingnetwork'
 | |
|     type: item
 | |
|     method: POST
 | |
|     path: '/api/billingnetworks/'
 | |
|     header:
 | |
|         Content-Type: application/json
 | |
|         Prefer: return=representation
 | |
|     content:
 | |
|         name: another test billing network ${unique_id}
 | |
|         description: another test billing network description ${unique_id}
 | |
|         reseller_id: 1
 | |
|         blocks:
 | |
|             -
 | |
|                 ip: '10.0.4.7'
 | |
|                 mask: '26'
 | |
|             -
 | |
|                 ip: '10.0.4.99'
 | |
|                 mask: '26'
 | |
|             -
 | |
|                 ip: '10.0.5.9'
 | |
|                 mask: '24'
 | |
|             -
 | |
|                 ip: '10.0.6.9'
 | |
|                 mask: '24'
 | |
|     retain:
 | |
|         second_billing_network_id: header.location
 | |
|     conditions:
 | |
|         is: 
 | |
|             code: 201
 | |
|     perl_code: !!perl/code |
 | |
|         {
 | |
|             my ($retained) = @_;
 | |
|             $retained->{initial_profiles} = [ { profile_id => $retained->{billing_profile_id} },
 | |
|                                               { 
 | |
|                                                 profile_id => $retained->{third_billing_profile_id},
 | |
|                                                 network_id => $retained->{second_billing_network_id}
 | |
|                                               }
 | |
|                                             ]
 | |
|         }        
 | |
| 
 | |
| #prof-package: create test profile package
 | |
| -
 | |
|     name: 'prof-package: create test profile package'
 | |
|     type: item
 | |
|     method: POST
 | |
|     path: '/api/profilepackages/'
 | |
|     header:
 | |
|         Content-Type: application/json
 | |
|         Prefer: return=representation
 | |
|     content:
 | |
|         name: test profile package ${unique_id}
 | |
|         description: test profile package description ${unique_id}
 | |
|         reseller_id: 1
 | |
|         initial_profiles: ${initial_profiles}
 | |
|     retain:
 | |
|         profile_package_id: header.location
 | |
|     conditions:
 | |
|         is: 
 | |
|             code: 201
 | |
| 
 | |
| #prof-package: create second test profile package
 | |
| -
 | |
|     name: 'prof-package: create second test profile package'
 | |
|     type: item
 | |
|     method: POST
 | |
|     path: '/api/profilepackages/'
 | |
|     header:
 | |
|         Content-Type: application/json
 | |
|         Prefer: return=representation
 | |
|     content:
 | |
|         name: second test profile package ${unique_id}
 | |
|         description: second test profile package description ${unique_id}
 | |
|         reseller_id: 1
 | |
|         initial_profiles: ${initial_profiles}
 | |
|     retain:
 | |
|         second_profile_package_id: header.location
 | |
|     conditions:
 | |
|         is: 
 | |
|             code: 201
 | |
| 
 | |
| #prof-package: create test customer
 | |
| -
 | |
|     name: 'prof-package: create test customer'
 | |
|     type: item
 | |
|     method: POST
 | |
|     path: '/api/customers/'
 | |
|     header:
 | |
|         Content-Type: application/json
 | |
|     content:
 | |
|         status: active
 | |
|         contact_id: ${customer_contact_id}
 | |
|         type: sipaccount
 | |
|         billing_profile_definition: package
 | |
|         max_subscribers: null
 | |
|         external_id: null
 | |
|         profile_package_id: ${profile_package_id}
 | |
|     retain:
 | |
|         customer_path: header.location
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 201
 | |
| 
 | |
| #prof-package: get test customer
 | |
| -
 | |
|     name: 'prof-package: get test customer'
 | |
|     type: item
 | |
|     method: GET
 | |
|     path: '${customer_path}'
 | |
|     header:
 | |
|         Content-Type: application/json
 | |
|     retain:
 | |
|         customer: body
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 200
 | |
|             '${customer}.billing_profile_id': ${third_billing_profile_id}
 | |
|             '${customer}.profile_package_id': ${profile_package_id}
 | |
|         ok:
 | |
|             '${customer}.billing_profile_id': defined
 | |
|             '${customer}.profile_package_id': defined
 | |
|     perl_code: !!perl/code |
 | |
|         {
 | |
|             my ($retained) = @_;
 | |
| 
 | |
|             my $dtf = DateTime::Format::Strptime->new(
 | |
|                 pattern => '%F %T',
 | |
|             );
 | |
|             my $now = DateTime->now(
 | |
|                 time_zone => DateTime::TimeZone->new(name => 'local')
 | |
|             );
 | |
|             my $t1 = $now->clone->add(days => 1);
 | |
|             my $t2 = $now->clone->add(days => 2);
 | |
|             my $t3 = $now->clone->add(days => 3);
 | |
| 
 | |
|             $retained->{billing_profiles} = [ { profile_id => $retained->{billing_profile_id},
 | |
|                                             start => $dtf->format_datetime($t1),
 | |
|                                             stop => $dtf->format_datetime($t2) } ,
 | |
|                                           { profile_id => $retained->{third_billing_profile_id},
 | |
|                                             network_id => $retained->{second_billing_network_id},
 | |
|                                             start => $dtf->format_datetime($t2),
 | |
|                                             stop => $dtf->format_datetime($t3) } ];
 | |
|         }        
 | |
| 
 | |
| #prof-package: patch test customer
 | |
| -
 | |
|     name: 'prof-package: patch test customer'
 | |
|     type: item
 | |
|     method: PATCH
 | |
|     path: '${customer_path}'
 | |
|     header:
 | |
|         Content-Type: application/json-patch+json
 | |
|         Prefer: return=representation
 | |
|     content:
 | |
|         -
 | |
|             op: replace
 | |
|             path: /billing_profiles
 | |
|             value: ${billing_profiles}
 | |
|     retain:
 | |
|         customer: body
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 200
 | |
|             '${customer}.billing_profile_id': ${third_billing_profile_id}
 | |
|             '${customer}.profile_package_id': ${profile_package_id}
 | |
|         ok:
 | |
|             '${customer}.billing_profile_id': defined
 | |
|             '${customer}.profile_package_id': defined
 | |
| 
 | |
| #prof-package: patch test customer
 | |
| -
 | |
|     name: 'prof-package: patch test customer'
 | |
|     type: item
 | |
|     method: PATCH
 | |
|     path: '${customer_path}'
 | |
|     header:
 | |
|         Content-Type: application/json-patch+json
 | |
|         Prefer: return=representation
 | |
|     content:
 | |
|         -
 | |
|             op: replace
 | |
|             path: /billing_profile_id
 | |
|             value: ${billing_profile_id}
 | |
|     retain:
 | |
|         customer: body
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 200
 | |
|             '${customer}.billing_profile_id': ${billing_profile_id}
 | |
|             '${customer}.profile_package_id': ${profile_package_id}
 | |
|         ok:
 | |
|             '${customer}.billing_profile_id': defined
 | |
|             '${customer}.profile_package_id': defined
 | |
| 
 | |
| #prof-package: patch test customer
 | |
| -
 | |
|     name: 'prof-package: patch test customer'
 | |
|     type: item
 | |
|     method: PATCH
 | |
|     path: '${customer_path}'
 | |
|     header:
 | |
|         Content-Type: application/json-patch+json
 | |
|         Prefer: return=representation
 | |
|     content:
 | |
|         -
 | |
|             op: replace
 | |
|             path: /profile_package_id
 | |
|             value: ${profile_package_id}
 | |
|     retain:
 | |
|         customer: body
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 200
 | |
|             '${customer}.billing_profile_id': ${billing_profile_id}
 | |
|             '${customer}.profile_package_id': ${profile_package_id}
 | |
|         ok:
 | |
|             '${customer}.billing_profile_id': defined
 | |
|             '${customer}.profile_package_id': defined
 | |
| 
 | |
| #prof-package: patch test customer
 | |
| -
 | |
|     name: 'prof-package: patch test customer'
 | |
|     type: item
 | |
|     method: PATCH
 | |
|     path: '${customer_path}'
 | |
|     header:
 | |
|         Content-Type: application/json-patch+json
 | |
|         Prefer: return=representation
 | |
|     content:
 | |
|         -
 | |
|             op: replace
 | |
|             path: /profile_package_id
 | |
|             value: ${second_profile_package_id}
 | |
|     retain:
 | |
|         customer: body
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 200
 | |
|             '${customer}.billing_profile_id': ${third_billing_profile_id}
 | |
|             '${customer}.profile_package_id': ${second_profile_package_id}
 | |
|         ok:
 | |
|             '${customer}.billing_profile_id': defined
 | |
|             '${customer}.profile_package_id': defined
 | |
| 
 | |
| #prof-package: terminate customer
 | |
| -
 | |
|     name: 'prof-package: terminate customer'
 | |
|     type: item
 | |
|     method: PATCH
 | |
|     path: '/${customer_path}'
 | |
|     header:
 | |
|         Content-Type: application/json-patch+json
 | |
|         Prefer: return=representation
 | |
|     content:
 | |
|         -
 | |
|             op: replace
 | |
|             path: /status
 | |
|             value: terminated
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 200
 | |
| 
 | |
| #prof-package: delete profile package
 | |
| -
 | |
|     name: 'prof-package: delete profile package'
 | |
|     type: item
 | |
|     method: DELETE
 | |
|     path: '/api/profilepackages/${profile_package_id}'
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 204
 | |
| 
 | |
| #prof-package: delete second profile package
 | |
| -
 | |
|     name: 'prof-package: delete second profile package'
 | |
|     type: item
 | |
|     method: DELETE
 | |
|     path: '/api/profilepackages/${second_profile_package_id}'
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 204
 | |
| 
 | |
| #prof-package: terminate third billing profile
 | |
| -
 | |
|     name: 'prof-package: terminate third billing profile'
 | |
|     type: item
 | |
|     method: PATCH
 | |
|     path: '/api/billingprofiles/${third_billing_profile_id}'
 | |
|     header:
 | |
|         Content-Type: application/json-patch+json
 | |
|         Prefer: return=representation
 | |
|     content:
 | |
|         -
 | |
|             op: replace
 | |
|             path: /status
 | |
|             value: terminated
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 200
 | |
| 
 | |
| #prof-package: terminate second billing network
 | |
| -
 | |
|     name: 'prof-package: terminate second billing network'
 | |
|     type: item
 | |
|     method: PATCH
 | |
|     path: '/api/billingnetworks/${second_billing_network_id}'
 | |
|     header:
 | |
|         Content-Type: application/json-patch+json
 | |
|         Prefer: return=representation
 | |
|     content:
 | |
|         -
 | |
|             op: replace
 | |
|             path: /status
 | |
|             value: terminated
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 200
 | |
| 
 | |
| #check locked status for deleting used contact
 | |
| -
 | |
|     name: check locked status for deleting used contact
 | |
|     type: item
 | |
|     method: DELETE
 | |
|     path: '/${customer_contact_path}'
 | |
|     conditions:
 | |
|         is:
 | |
|             code: 423
 |