diff --git a/services/common/src/components/projectSummary/ApplicationSummary.tsx b/services/common/src/components/projectSummary/ApplicationSummary.tsx index 3d2868d575..9e0dc15257 100644 --- a/services/common/src/components/projectSummary/ApplicationSummary.tsx +++ b/services/common/src/components/projectSummary/ApplicationSummary.tsx @@ -77,8 +77,8 @@ export const ApplicationSummary: FC = () => { permit.project_summary_permit_type .map((projectType: string) => { const project_type = parseProjectTypeLabel(projectType); - if (projectType === "AMENDMENT") { - return permit.existing_permits_authorizations.map((guid) => ({ + if (projectType === "AMENDMENT" && permit?.existing_permits_authorizations) { + return permit?.existing_permits_authorizations?.map((guid) => ({ project_type, permit_no: getPermitNumber(guid), })); diff --git a/services/common/src/components/projectSummary/PaymentContact.tsx b/services/common/src/components/projectSummary/PaymentContact.tsx index 6479adbd0c..e68b737274 100644 --- a/services/common/src/components/projectSummary/PaymentContact.tsx +++ b/services/common/src/components/projectSummary/PaymentContact.tsx @@ -26,8 +26,10 @@ export const PaymentContact: FC = () => { const provinceOptions = useSelector(getDropdownProvinceOptions); useEffect(() => { - dispatch(change(FORM.ADD_EDIT_PROJECT_SUMMARY, "payment_contact.party_type_code", "PER")); - if (!payment_contact.address) { + if (payment_contact?.party_type_code !== "PER" || !payment_contact?.party_type_code) { + dispatch(change(FORM.ADD_EDIT_PROJECT_SUMMARY, "payment_contact.party_type_code", "PER")); + } + if (!payment_contact?.address) { dispatch( change(FORM.ADD_EDIT_PROJECT_SUMMARY, "payment_contact.address[0].address_line_1", null) ); @@ -40,7 +42,7 @@ export const PaymentContact: FC = () => { dispatch(change(FORM.ADD_EDIT_PROJECT_SUMMARY, "payment_contact.address[0].city", null)); dispatch(change(FORM.ADD_EDIT_PROJECT_SUMMARY, "payment_contact.address[0].post_code", null)); } - }, []); + }, [payment_contact.party_type_code, payment_contact.address]); return (
diff --git a/services/core-api/.env-example b/services/core-api/.env-example index b2a07e2dd3..aa65697dce 100644 --- a/services/core-api/.env-example +++ b/services/core-api/.env-example @@ -139,3 +139,6 @@ JWT_OIDC_KEY_DQ='ANtbSY6njfpPploQsF9sU26U0s7MsuLljM1E8uml8bVJE1mNsiu9MgpUvg39jEu JWT_OIDC_KEY_QI='XLE5O360x-MhsdFXx8Vwz4304-MJg-oGSJXCK_ZWYOB_FGXFRTfebxCsSYi0YwJo-oNu96bvZCuMplzRI1liZw' JWT_OIDC_TEST_PRIVATE_KEY_PEM="-----BEGIN RSA PRIVATE KEY-----\nMIICXQIBAAKBgQDfn1nKQshOSj8xw44oC2klFWSNLmK3BnHONCJ1bZfq0EQ5gIfg\ntlvB+Px8Ya+VS3OnK7Cdi4iU1fxO9ktN6c6TjmmmFevk8wIwqLthmCSF3r+3+h4e\nddj7hucMsXWv05QUrCPoL6YUUz7Cgpz7ra24rpAmK5z7lsV+f3BEvXkrUQIDAQAB\nAoGAC0G3QGI6OQ6tvbCNYGCqq043YI/8MiBl7C5dqbGZmx1ewdJBhMNJPStuckhs\nkURaDwk4+8VBW9SlvcfSJJrnZhgFMjOYSSsBtPGBIMIdM5eSKbenCCjO8Tg0BUh/\nxa3CHST1W4RQ5rFXadZ9AeNtaGcWj2acmXNO3DVETXAX3x0CQQD13LrBTEDR44ei\nlQ/4TlCMPO5bytd1pAxHnrqgMnWovSIPSShAAH1feFugH7ZGu7RoBO7pYNb6N3ia\nC1idc7yjAkEA6Nfc6c8meTRkVRAHCF24LB5GLfsjoMB0tOeEO9w9Ous1a4o+D24b\nAePMUImAp3woFoNDRfWtlNktOqLel5PjewJBAN9kBoA5o6/Rl9zeqdsIdWFmv4DB\n5lEqlEnC7HlAP+3oo3jWFO9KQqArQL1V8w2D4aCd0uJULiC9pCP7aTHvBhcCQQDb\nW0mOp436T6ZaELBfbFNulNLOzLLi5YzNRPLppfG1SRNZjbIrvTIKVL4N/YxLvQbT\nNrQw+2OdQACBJiEHsdZzAkBcsTk7frTH4yGx0VfHxXDPjfTj4wmD6gZIlcIr9lZg\n4H8UZcVFN95vEKxJiLRjAmj6g273pu9kK4ymXNEjWWJn\n-----END RSA PRIVATE KEY-----" + +AMS_BEARER_TOKEN=5c6d9ClIrJS5N0PsrunACaHZUCkMcrm41oDne2KvY19D1+fKxOheeVhhf3NaBGpWr8XtmpLeGvFqnY+6RnoAOBYQYyHVKZF3T6bwJ+qh1xNoATlbUTpEvopbO47rH3xU +AMS_URL=https://test.j200.gov.bc.ca/ws/EM_CORE_NET3/auth \ No newline at end of file diff --git a/services/core-api/app/api/municipalities/models/municipality.py b/services/core-api/app/api/municipalities/models/municipality.py index 0b84c7711f..0ade892445 100644 --- a/services/core-api/app/api/municipalities/models/municipality.py +++ b/services/core-api/app/api/municipalities/models/municipality.py @@ -18,5 +18,4 @@ def get_all(cls): @classmethod def find_by_guid(cls, municipality_guid): - current_app.logger.debug(f"Looking for municipality with {municipality_guid}") return cls.query.filter_by(municipality_guid=municipality_guid).first() diff --git a/services/core-api/app/api/projects/project_summary/models/project_summary.py b/services/core-api/app/api/projects/project_summary/models/project_summary.py index 96b85a54e7..907a69f8b8 100644 --- a/services/core-api/app/api/projects/project_summary/models/project_summary.py +++ b/services/core-api/app/api/projects/project_summary/models/project_summary.py @@ -20,7 +20,8 @@ from app.api.projects.project_contact.models.project_contact import ProjectContact from app.api.projects.project_summary.models.project_summary_contact import ProjectSummaryContact from app.api.projects.project_summary.models.project_summary_authorization import ProjectSummaryAuthorization -from app.api.projects.project_summary.models.project_summary_authorization_document_xref import ProjectSummaryAuthorizationDocumentXref +from app.api.projects.project_summary.models.project_summary_authorization_document_xref import \ + ProjectSummaryAuthorizationDocumentXref from app.api.projects.project_summary.models.project_summary_permit_type import ProjectSummaryPermitType from app.api.parties.party.models.party import Party from app.api.parties.party.models.address import Address @@ -32,7 +33,9 @@ from app.api.utils.feature_flag import is_feature_enabled, Feature -from app.api.utils.common_validation_schemas import primary_address_schema, base_address_schema, address_na_schema, address_int_schema, party_base_schema, project_summary_base_schema +from app.api.utils.common_validation_schemas import primary_address_schema, base_address_schema, address_na_schema, \ + address_int_schema, party_base_schema, project_summary_base_schema + class ProjectSummary(SoftDeleteMixin, AuditMixin, Base): __tablename__ = 'project_summary' @@ -98,7 +101,7 @@ class ProjectSummary(SoftDeleteMixin, AuditMixin, Base): facility_operator = db.relationship( 'Party', lazy='joined', foreign_keys=facility_operator_guid ) - + nearest_municipality = db.relationship( 'Municipality', lazy='joined', foreign_keys=nearest_municipality_guid ) @@ -170,7 +173,6 @@ def mine_guid(cls): else_=None ) - @hybrid_property def mine_name(self): if self.project.mine_guid: @@ -278,73 +280,73 @@ def create_or_update_party(cls, party_data, job_title_code, existing_party): return new_party def create_or_update_authorization(self, authorization): - updated_authorization_guid = authorization.get('project_summary_authorization_guid') - - if updated_authorization_guid: - updated_authorization = ProjectSummaryAuthorization.find_by_project_summary_authorization_guid( - updated_authorization_guid) - updated_authorization.project_summary_permit_type = authorization.get( - 'project_summary_permit_type') - updated_authorization.existing_permits_authorizations = authorization.get( - 'existing_permits_authorizations') - updated_authorization.amendment_changes = authorization.get('amendment_changes') - updated_authorization.amendment_severity = authorization.get('amendment_severity') - updated_authorization.is_contaminated = authorization.get('is_contaminated') - updated_authorization.new_type = authorization.get('new_type') - updated_authorization.authorization_description = authorization.get('authorization_description') - updated_authorization.exemption_reason = authorization.get('exemption_reason') - updated_authorization.exemption_requested = authorization.get('exemption_requested') - updated_authorization.ams_tracking_number = authorization.get('ams_tracking_number') - updated_authorization.ams_outcome = authorization.get('ams_outcome') - updated_authorization.ams_status_code = authorization.get('ams_status_code') - - if authorization.get('amendment_documents') is not None: - for doc in authorization.get('amendment_documents'): - if doc.get('mine_document_guid') is None: - mine_doc = MineDocument( - mine_guid=self.mine_guid, - document_name=doc.get('document_name'), - document_manager_guid=doc.get('document_manager_guid')) - project_summary_authorization_doc = ProjectSummaryAuthorizationDocumentXref( - mine_document_guid=mine_doc.mine_document_guid, - project_summary_authorization_guid=updated_authorization.project_summary_authorization_guid, - project_summary_document_type_code=doc.get('project_summary_document_type_code')) - project_summary_authorization_doc.mine_document = mine_doc - updated_authorization.amendment_documents.append(project_summary_authorization_doc) - else: - new_authorization = ProjectSummaryAuthorization( - project_summary_guid=self.project_summary_guid, - project_summary_authorization_type=authorization.get( - 'project_summary_authorization_type'), - project_summary_permit_type=authorization.get('project_summary_permit_type'), - existing_permits_authorizations=authorization.get( - 'existing_permits_authorizations'), - amendment_changes=authorization.get('amendment_changes'), - amendment_severity=authorization.get('amendment_severity'), - is_contaminated=authorization.get('is_contaminated'), - new_type=authorization.get('new_type'), - authorization_description=authorization.get('authorization_description'), - exemption_reason=authorization.get('exemption_reason'), - exemption_requested=authorization.get('exemption_requested'), - ams_tracking_number=authorization.get('ams_tracking_number'), - ams_outcome=authorization.get('ams_outcome') - ) -# Check only for new files - if authorization.get('amendment_documents') is not None: - for doc in authorization.get('amendment_documents'): - if doc.get('mine_document_guid') is None: - mine_doc = MineDocument( - mine_guid=self.mine_guid, - document_name=doc.get('document_name'), - document_manager_guid=doc.get('document_manager_guid')) - project_summary_authorization_doc = ProjectSummaryAuthorizationDocumentXref( - mine_document_guid=mine_doc.mine_document_guid, - project_summary_authorization_guid=new_authorization.project_summary_authorization_guid, - project_summary_document_type_code=doc.get('project_summary_document_type_code')) - project_summary_authorization_doc.mine_document = mine_doc - new_authorization.amendment_documents.append(project_summary_authorization_doc) - - self.authorizations.append(new_authorization) + updated_authorization_guid = authorization.get('project_summary_authorization_guid') + + if updated_authorization_guid: + updated_authorization = ProjectSummaryAuthorization.find_by_project_summary_authorization_guid( + updated_authorization_guid) + updated_authorization.project_summary_permit_type = authorization.get( + 'project_summary_permit_type') + updated_authorization.existing_permits_authorizations = authorization.get( + 'existing_permits_authorizations') + updated_authorization.amendment_changes = authorization.get('amendment_changes') + updated_authorization.amendment_severity = authorization.get('amendment_severity') + updated_authorization.is_contaminated = authorization.get('is_contaminated') + updated_authorization.new_type = authorization.get('new_type') + updated_authorization.authorization_description = authorization.get('authorization_description') + updated_authorization.exemption_reason = authorization.get('exemption_reason') + updated_authorization.exemption_requested = authorization.get('exemption_requested') + updated_authorization.ams_tracking_number = authorization.get('ams_tracking_number') + updated_authorization.ams_outcome = authorization.get('ams_outcome') + updated_authorization.ams_status_code = authorization.get('ams_status_code') + + if authorization.get('amendment_documents') is not None: + for doc in authorization.get('amendment_documents'): + if doc.get('mine_document_guid') is None: + mine_doc = MineDocument( + mine_guid=self.mine_guid, + document_name=doc.get('document_name'), + document_manager_guid=doc.get('document_manager_guid')) + project_summary_authorization_doc = ProjectSummaryAuthorizationDocumentXref( + mine_document_guid=mine_doc.mine_document_guid, + project_summary_authorization_guid=updated_authorization.project_summary_authorization_guid, + project_summary_document_type_code=doc.get('project_summary_document_type_code')) + project_summary_authorization_doc.mine_document = mine_doc + updated_authorization.amendment_documents.append(project_summary_authorization_doc) + else: + new_authorization = ProjectSummaryAuthorization( + project_summary_guid=self.project_summary_guid, + project_summary_authorization_type=authorization.get( + 'project_summary_authorization_type'), + project_summary_permit_type=authorization.get('project_summary_permit_type'), + existing_permits_authorizations=authorization.get( + 'existing_permits_authorizations'), + amendment_changes=authorization.get('amendment_changes'), + amendment_severity=authorization.get('amendment_severity'), + is_contaminated=authorization.get('is_contaminated'), + new_type=authorization.get('new_type'), + authorization_description=authorization.get('authorization_description'), + exemption_reason=authorization.get('exemption_reason'), + exemption_requested=authorization.get('exemption_requested'), + ams_tracking_number=authorization.get('ams_tracking_number'), + ams_outcome=authorization.get('ams_outcome') + ) + # Check only for new files + if authorization.get('amendment_documents') is not None: + for doc in authorization.get('amendment_documents'): + if doc.get('mine_document_guid') is None: + mine_doc = MineDocument( + mine_guid=self.mine_guid, + document_name=doc.get('document_name'), + document_manager_guid=doc.get('document_manager_guid')) + project_summary_authorization_doc = ProjectSummaryAuthorizationDocumentXref( + mine_document_guid=mine_doc.mine_document_guid, + project_summary_authorization_guid=new_authorization.project_summary_authorization_guid, + project_summary_document_type_code=doc.get('project_summary_document_type_code')) + project_summary_authorization_doc.mine_document = mine_doc + new_authorization.amendment_documents.append(project_summary_authorization_doc) + + self.authorizations.append(new_authorization) @classmethod def validate_project_party(cls, party, section): @@ -383,7 +385,7 @@ def validate_project_party(cls, party, section): 'post_code': { 'type': 'string', 'nullable': True, - }, + }, } party_na_phone_schema = { @@ -405,7 +407,9 @@ def validate_project_party(cls, party, section): party_type_code = party.get('party_type_code', None) address_data = party.get('address') base_schema = person_schema if (party_type_code == None or party_type_code == 'PER') else org_schema - address_type_code = address_data[0].get('address_type_code') if isinstance(address_data, list) else address_data.get('address_type_code') + address_type_code = address_data[0].get('address_type_code') if isinstance(address_data, + list) else address_data.get( + 'address_type_code') if address_type_code == 'INT': base_schema |= party_int_phone_schema @@ -420,7 +424,7 @@ def validate_project_party(cls, party, section): 'email': { 'required': True, 'type': 'string', - }, + }, } if section == 'applicant': @@ -437,30 +441,30 @@ def validate_project_party(cls, party, section): } base_schema |= { - 'address': { - 'required': True, - 'anyof': [ - { - 'type': 'list', - 'empty': False, - 'schema': { - 'type': 'dict', - 'schema': address_schema, - }, - }, - { + 'address': { + 'required': True, + 'anyof': [ + { + 'type': 'list', + 'empty': False, + 'schema': { 'type': 'dict', 'schema': address_schema, }, - ], - }, + }, + { + 'type': 'dict', + 'schema': address_schema, + }, + ], + }, } - + v = Validator(base_schema, purge_unknown=True) if not v.validate(party): return json.dumps(v.errors) return True - + @classmethod def validate_mine_component_offsite_infrastructure(self, data): draft_mine_offsite_schema = { @@ -516,7 +520,7 @@ def validate_mine_component_offsite_infrastructure(self, data): } v = Validator(mine_offsite_schema, purge_unknown=True) - + if not v.validate(data): return json.dumps(v.errors) return True @@ -543,112 +547,112 @@ def validate_legal_land(self, data): 'legal_land_owner_contact_number': { 'required': True, 'type': 'string', - 'regex': '[0-9]{3}-[0-9]{3}-[0-9]{4}', + 'regex': '[0-9]{3}-[0-9]{3}-[0-9]{4}', }, 'legal_land_owner_email_address': { 'required': True, - 'type': 'string', + 'type': 'string', }, } v = Validator(legal_land_owner_schema, purge_unknown=True) - + if not v.validate(data): return json.dumps(v.errors) return True - + @classmethod def validate_location_access(self, data): draft_location_access_schema = { - 'facility_latitude': { - 'nullable': True, - 'min': 47, - 'max': 60, - 'type': 'number', - }, - 'facility_longitude': { - 'nullable': True, - 'min': -140, - 'max': -113, - 'type': 'number', - }, - 'facility_coords_source': { - 'nullable': True, - 'type': 'string', - 'allowed': ['GPS', 'SUR', 'GGE', 'OTH'], - }, - 'nearest_municipality': { - 'nullable': True, - 'type': 'string', - }, - 'municipality': { - 'nullable': True, - 'type': 'dict', - 'schema': { - 'municipality_guid': { - 'required': True, - 'type': 'string', - }, - 'municipality_name': { - 'required': True, - 'type': 'string', - }, + 'facility_latitude': { + 'nullable': True, + 'min': 47, + 'max': 60, + 'type': 'number', + }, + 'facility_longitude': { + 'nullable': True, + 'min': -140, + 'max': -113, + 'type': 'number', + }, + 'facility_coords_source': { + 'nullable': True, + 'type': 'string', + 'allowed': ['GPS', 'SUR', 'GGE', 'OTH'], + }, + 'nearest_municipality': { + 'nullable': True, + 'type': 'string', + }, + 'municipality': { + 'nullable': True, + 'type': 'dict', + 'schema': { + 'municipality_guid': { + 'required': True, + 'type': 'string', + }, + 'municipality_name': { + 'required': True, + 'type': 'string', }, }, - 'facility_lease_no': { - 'nullable': True, - 'type': 'string', - }, - 'facility_pid_pin_crown_file_no': { - 'nullable': True, - 'type': 'string', - }, - 'legal_land_desc': { - 'nullable': True, - 'type': 'string', - }, + }, + 'facility_lease_no': { + 'nullable': True, + 'type': 'string', + }, + 'facility_pid_pin_crown_file_no': { + 'nullable': True, + 'type': 'string', + }, + 'legal_land_desc': { + 'nullable': True, + 'type': 'string', + }, } submission_location_access_schema = { - 'facility_latitude': { - 'required': True, - 'min': 47, - 'max': 60, - 'type': 'number', - }, - 'facility_longitude': { - 'required': True, - 'min': -140, - 'max': -113, - 'type': 'number', - }, - 'facility_coords_source': { - 'required': True, - 'type': 'string', - 'allowed': ['GPS', 'SUR', 'GGE', 'OTH'], - }, - 'nearest_municipality': { - 'nullable': True, - 'type': 'string', - }, - 'municipality': { - 'nullable': True, - 'type': 'dict', - 'schema': { - 'municipality_guid': { - 'required': True, - 'type': 'string', - }, - 'municipality_name': { - 'required': True, - 'type': 'string', - }, + 'facility_latitude': { + 'required': True, + 'min': 47, + 'max': 60, + 'type': 'number', + }, + 'facility_longitude': { + 'required': True, + 'min': -140, + 'max': -113, + 'type': 'number', + }, + 'facility_coords_source': { + 'required': True, + 'type': 'string', + 'allowed': ['GPS', 'SUR', 'GGE', 'OTH'], + }, + 'nearest_municipality': { + 'nullable': True, + 'type': 'string', + }, + 'municipality': { + 'nullable': True, + 'type': 'dict', + 'schema': { + 'municipality_guid': { + 'required': True, + 'type': 'string', + }, + 'municipality_name': { + 'required': True, + 'type': 'string', }, }, - 'facility_lease_no': { - 'required': True, - 'type': 'string', - } + }, + 'facility_lease_no': { + 'required': True, + 'type': 'string', + } } status_code = data.get('status_code') @@ -660,7 +664,8 @@ def validate_location_access(self, data): location_access_data_to_validate = data if facility_latitude != None and facility_longitude != None: - location_access_data_to_validate = {**data, 'facility_latitude': float(facility_latitude), 'facility_longitude': float(facility_longitude)} + location_access_data_to_validate = {**data, 'facility_latitude': float(facility_latitude), + 'facility_longitude': float(facility_longitude)} location_access_schema = draft_location_access_schema if status_code == 'SUB': @@ -704,11 +709,11 @@ def validate_location_access(self, data): 'facility_coords_source_desc': { 'required': True, 'type': 'string', - }, + }, } v = Validator(location_access_schema, purge_unknown=True) - + if not v.validate(location_access_data_to_validate): return json.dumps(v.errors) return True @@ -743,7 +748,7 @@ def validate_declaration(self, data): } v = Validator(declaration_schema, purge_unknown=True) - + if not v.validate(data): return json.dumps(v.errors) return True @@ -761,7 +766,7 @@ def validate_project_summary_surface_level_data(self, data): def validate_project_summary(cls, data): status_code = data.get('status_code') ams_authorizations = data.get('ams_authorizations', None) - authorizations = data.get('authorizations',[]) + authorizations = data.get('authorizations', []) contacts = data.get('contacts') applicant = data.get('applicant', None) agent = data.get('agent', None) @@ -803,14 +808,14 @@ def validate_project_summary(cls, data): 'mine_component_and_offsite': [], 'declaration': [], } - + # Validate Authorizations Involved if (status_code == 'SUB' - and len(ams_authorizations.get('amendments', [])) == 0 - and len(ams_authorizations.get('new', [])) == 0 - and len(authorizations) == 0): + and len(ams_authorizations.get('amendments', [])) == 0 + and len(ams_authorizations.get('new', [])) == 0 + and len(authorizations) == 0): errors_found['authorizations'].append('Authorizations Involved not provided') - + for authorization in authorizations: authorization_validation = ProjectSummaryAuthorization.validate_authorization(authorization, False) if authorization_validation != True: @@ -818,12 +823,14 @@ def validate_project_summary(cls, data): if ams_authorizations: for authorization in ams_authorizations.get('amendments', []): - ams_authorization_amendments_validation = ProjectSummaryAuthorization.validate_authorization(authorization, True) + ams_authorization_amendments_validation = ProjectSummaryAuthorization.validate_authorization( + authorization, True) if ams_authorization_amendments_validation != True: errors_found['authorizations'].append(ams_authorization_amendments_validation) for authorization in ams_authorizations.get('new', []): - ams_authorization_new_validation = ProjectSummaryAuthorization.validate_authorization(authorization, True) + ams_authorization_new_validation = ProjectSummaryAuthorization.validate_authorization(authorization, + True) if ams_authorization_new_validation != True: errors_found['authorizations'].append(ams_authorization_new_validation) @@ -842,18 +849,19 @@ def validate_project_summary(cls, data): agent_validation = ProjectSummary.validate_project_party(agent, 'agent') if agent_validation != True: errors_found['agent'].append(agent_validation) - + # Validate Mine Components and Offsite Infrastructure if status_code == 'SUB' and facility_operator == None: errors_found['mine_component_and_offsite'].append('Facility address info not provided') elif facility_operator != None: - mine_offsite_party_validation = ProjectSummary.validate_project_party(facility_operator, 'mine_component_and_offsite') + mine_offsite_party_validation = ProjectSummary.validate_project_party(facility_operator, + 'mine_component_and_offsite') if mine_offsite_party_validation != True: errors_found['mine_component_and_offsite'].append(mine_offsite_party_validation) mine_offsite_validation = ProjectSummary.validate_mine_component_offsite_infrastructure(data) if mine_offsite_validation != True: - errors_found['mine_component_and_offsite'].append(mine_offsite_validation) + errors_found['mine_component_and_offsite'].append(mine_offsite_validation) # Validate Location, Access and Land Use if status_code == 'SUB' and is_legal_land_owner == None: @@ -882,7 +890,7 @@ def get_ams_tracking_details(self, ams_tracking_results, project_summary_authori ams_tracking_result = next((item for item in ams_tracking_results if item.get( 'project_summary_authorization_guid') == project_summary_authorization_guid), None) return ams_tracking_result - + @classmethod def create(cls, project, @@ -933,7 +941,6 @@ def create(cls, for authorization in ams_authorizations.get('new', []): project_summary.create_or_update_authorization(authorization) - if add_to_session: project_summary.save(commit=False) @@ -991,7 +998,7 @@ def update(self, regional_district_id=None, payment_contact=None, add_to_session=True): - + # Update simple properties. # If we assign a project lead update status to Assigned and vice versa Submitted. if project_lead_party_guid and project.project_lead_party_guid is None: @@ -1120,11 +1127,11 @@ def update(self, regional_district_name = regional_district_id is not None and Regions.find_by_id( regional_district_id).name or None - if ams_authorizations: - ams_results = [] + new_ams_results = [] + amendment_ams_results = [] if self.status_code == 'SUB': - ams_results = AMSApiService.create_new_ams_authorization( + new_ams_results = AMSApiService.create_new_ams_authorization( ams_authorizations, applicant, nearest_municipality, @@ -1151,12 +1158,50 @@ def update(self, zoning_reason, regional_district_name) + amendment_ams_results = AMSApiService.create_amendment_ams_authorization( + ams_authorizations, + applicant, + nearest_municipality, + agent, + contacts, + facility_type, + facility_desc, + facility_latitude, + facility_longitude, + facility_coords_source, + facility_coords_source_desc, + legal_land_desc, + facility_operator, + legal_land_owner_name, + legal_land_owner_contact_number, + legal_land_owner_email_address, + is_landowner_aware_of_discharge_application, + has_landowner_received_copy_of_application, + facility_pid_pin_crown_file_no, + company_alias, + zoning, + zoning_reason, + regional_district_name, + is_legal_land_owner, + is_crown_land_federal_or_provincial + ) + for authorization in ams_authorizations.get('amendments', []): + if amendment_ams_results: + ams_tracking_details = self.get_ams_tracking_details(amendment_ams_results, + authorization.get( + 'project_summary_authorization_guid')) + if ams_tracking_details: + # if result does not have a statusCode attribute, it means the outcome is successful. + authorization['ams_status_code'] = ams_tracking_details.get('statusCode', '200') + authorization['ams_tracking_number'] = ams_tracking_details.get('trackingnumber', '0') + authorization['ams_outcome'] = ams_tracking_details.get('outcome', ams_tracking_details.get( + 'errorMessage')) self.create_or_update_authorization(authorization) for authorization in ams_authorizations.get('new', []): - if ams_results: - ams_tracking_details = self.get_ams_tracking_details(ams_results, + if new_ams_results: + ams_tracking_details = self.get_ams_tracking_details(new_ams_results, authorization.get( 'project_summary_authorization_guid')) if ams_tracking_details: diff --git a/services/core-api/app/api/services/ams_api_service.py b/services/core-api/app/api/services/ams_api_service.py index 738bebb16b..e81de6bcf5 100644 --- a/services/core-api/app/api/services/ams_api_service.py +++ b/services/core-api/app/api/services/ams_api_service.py @@ -1,6 +1,7 @@ -import requests import json +import traceback +import requests from flask import current_app from app.api.municipalities.models.municipality import Municipality @@ -27,15 +28,23 @@ def __get_mapped_permit_type(cls, data): } return permit_type_mapping[data] + @classmethod + def __get_mapped_amendment_type(cls, data): + amendment_type_mapping = { + "MIN": "Minor", + "SIG": "Significant", + } + return amendment_type_mapping[data] + @classmethod def __create_full_address(cls, address_line1, city, sub_division_code, post_code): return f"{address_line1}, {city}, {sub_division_code}, {post_code}" @classmethod - def __get_new_authorization_details(cls, ams_authorizations): + def __get_authorization_details(cls, ams_authorizations, detail_type): new_authorization_values = [] - if len(ams_authorizations['new']) > 0: - for item in ams_authorizations['new']: + if len(ams_authorizations[detail_type]) > 0: + for item in ams_authorizations[detail_type]: new_authorization_values.append({ 'project_summary_authorization_guid': item.get('project_summary_authorization_guid', ''), 'project_summary_guid': item.get('project_summary_guid'), @@ -46,7 +55,11 @@ def __get_new_authorization_details(cls, ams_authorizations): 'new_type': item.get('new_type'), 'exemption_requested': item.get('exemption_requested') or False, 'is_contaminated': item.get('is_contaminated') or False, - 'ams_status_code': item.get('ams_status_code') or '0' # This will be used to track new authorizations that have been submitted successfully + 'amendment_severity': item.get('amendment_severity') or None, + 'amendment_changes': item.get('amendment_changes') or None, + 'existing_permits_authorizations': item.get('existing_permits_authorizations') or None, + 'ams_status_code': item.get('ams_status_code') or '0', + # This will be used to track new authorizations that have been submitted successfully }) return new_authorization_values @@ -60,6 +73,93 @@ def __boolean_to_yes_no(cls, value): return 'No' return 'Yes' if value else 'No' + @classmethod + def __set_contact_details(cls, contact): + contact_details = { + 'em_lastname': contact.get('last_name', ''), + 'em_firstname': contact.get('first_name', ''), + 'em_title': contact.get('job_title', ''), + 'em_businessphone': cls.__format_phone_number(contact.get('phone_number')), + 'em_email': contact.get('email', ''), + 'em_mailingaddress': cls.__create_full_address( + contact['address'].get('address_line_1', ''), + contact['address'].get('city', ''), + contact['address'].get('sub_division_code', ''), + contact['address'].get('post_code', '') + ) if contact.get('address') else '' + } + return contact_details + + @classmethod + def __set_applicant_details(cls, applicant, company_alias): + applicant_details = { + 'applicanttype': cls.__get_mapped_party_type(applicant.get('party_type_code')), + 'em_companyname': applicant.get('party_name', ''), + 'em_firstname': applicant.get('first_name', ''), + 'em_middlename': applicant.get('middle_name', ''), + 'em_lastname': applicant.get('party_name', ''), + 'em_doingbusinessas': company_alias, + 'bccompanyregistrationnumber': applicant.get('party_orgbook_entity', {}).get('registration_id', ''), + 'em_businessphone': cls.__format_phone_number(applicant.get('phone_no', '')), + 'em_email': applicant.get('email', ''), + 'legaladdress': cls.__create_full_address( + applicant.get('address')[1].get('address_line_1', ''), + applicant.get('address')[1].get('city', ''), + applicant.get('address')[1].get('sub_division_code', ''), + applicant.get('address')[1].get('post_code')), + 'mailingaddress': cls.__create_full_address( + applicant.get('address')[0].get('address_line_1', ''), + applicant.get('address')[0].get('city', ''), + applicant.get('address')[0].get('sub_division_code', ''), + applicant.get('address')[0].get('post_code')), + 'billingaddress': cls.__create_full_address( + applicant.get('address')[2].get('address_line_1', ''), + applicant.get('address')[2].get('city', ''), + applicant.get('address')[2].get('sub_division_code', ''), + applicant.get('address')[2].get('post_code')), + 'billingemailaddress': '' + } + return applicant_details + + @classmethod + def __set_agent_details(cls, agent): + agent_details = { + 'em_lastname': agent.get('party_name', '') if agent else '', + 'em_firstname': agent.get('first_name', '') if agent else '', + 'em_email': agent.get('email', '') if agent else '', + 'em_companyname': agent.get('party_name', '') if agent else '', + 'em_mailingaddress': cls.__create_full_address( + agent.get('address').get('address_line_1', ''), + agent.get('address').get('city', ''), + agent.get('address').get('sub_division_code', ''), + agent.get('address').get('post_code')) if agent else '', + 'em_businessphone': cls.__format_phone_number(agent.get('phone_no')) if agent else '', + 'em_title': agent.get('job_title', '') if agent else '', + } + return agent_details + + @classmethod + def __set_facility_address_details(cls, facility_operator, address_type=None): + facility_address = { + 'suitenumber': facility_operator.get('address').get('suite_no', ''), + 'streetnumber': facility_operator.get('address').get('suite_no', ''), + 'street': facility_operator.get('address').get('address_line_1', ''), + 'line2': facility_operator.get('address').get('address_line_2', ''), + 'municipality': facility_operator.get('address').get('city', ''), + 'province': 'British Columbia', + 'country': 'Canada', + 'postalcode': facility_operator.get('address').get('post_code'), + 'otheraddress': cls.__create_full_address( + facility_operator.get('address').get('address_line_1'), + facility_operator.get('address').get('city'), + facility_operator.get('address').get('sub_division_code'), + facility_operator.get('address').get('post_code')) + } + if address_type is not None: + facility_address['addresstype'] = address_type + return facility_address + + @classmethod def create_new_ams_authorization(cls, ams_authorizations, @@ -100,124 +200,190 @@ def create_new_ams_authorization(cls, if nearest_municipality: nearest_municipality_name = Municipality.find_by_guid(nearest_municipality).municipality_name - authorization_list = cls.__get_new_authorization_details(ams_authorizations) + authorization_list = cls.__get_authorization_details(ams_authorizations, 'new') + if authorization_list.__len__() > 0: + for authorization in authorization_list: + existing_ams_status_code = authorization.get('ams_status_code') + if existing_ams_status_code != '200': + ams_authorization_data = { + 'isauthamendment': 'No', + 'authorizationtype': { + 'authorizationname': cls.__get_mapped_permit_type(authorization.get('new_type')), + }, + 'receiveddate': get_date_iso8601_string(), + 'majorcentre': { + 'name': nearest_municipality_name + }, + 'applicant': cls.__set_applicant_details(applicant, company_alias), + 'agent': cls.__set_agent_details(agent), + 'purposeofapplication': authorization.get('authorization_description', ''), + 'preappexemptionrequest': cls.__boolean_to_yes_no(authorization.get('exemption_requested')), + 'preappexemptionrequestreason': authorization.get('authorization_description', + 'Not Applicable'), + 'iscontaminatedsite': cls.__boolean_to_yes_no(authorization.get('is_contaminated')), + 'contact': cls.__set_contact_details(contacts[0]), + 'facilitytype': facility_type, + 'facilitydescription': facility_desc, + 'latitude': str(facility_latitude), + 'longitude': str(abs(facility_longitude)), + 'sourceofdata': facility_coords_source, + 'sourceofdatadescription': facility_coords_source_desc, + 'legallanddescription': legal_land_desc, + 'pidpincrownfilenumber': facility_pid_pin_crown_file_no, + 'facilityaddress': cls.__set_facility_address_details(facility_operator, "Other / International"), + 'facilityopphonenumberext': facility_operator.get('phone_ext', ''), + 'isappropriatezoning': cls.__boolean_to_yes_no(zoning), + 'isappropriatezoningreason': zoning_reason, + 'landownername': legal_land_owner_name, + 'landownerphonenumber': cls.__format_phone_number(legal_land_owner_contact_number), + 'landowneremail': legal_land_owner_email_address, + 'istheapplicantthelandowner': cls.__boolean_to_yes_no(is_legal_land_owner), + 'landfedorprov': cls.__boolean_to_yes_no(is_crown_land_federal_or_provincial), + 'landownerawareofapplication': cls.__boolean_to_yes_no( + is_landowner_aware_of_discharge_application), + 'landownerreceivedcopy': cls.__boolean_to_yes_no(has_landowner_received_copy_of_application), + 'facilityoperator': facility_operator.get('name', ''), + 'facilityoperatorphonenumber': cls.__format_phone_number(facility_operator.get('phone_no', '')), + 'facilityoperatoremail': facility_operator.get('email', ''), + 'facilityoperatortitle': facility_operator.get('job_title', ''), + 'regionaldistrict': { + 'name': regional_district_name + } + } + payload = json.dumps(ams_authorization_data) + response = requests.post(Config.AMS_URL, data=payload, headers=headers) + ams_result = response.json() + ams_result['project_summary_authorization_guid'] = authorization.get( + 'project_summary_authorization_guid') + ams_result['project_summary_guid'] = authorization.get('project_summary_guid') + ams_result['project_summary_authorization_type'] = authorization.get( + 'project_summary_authorization_type') + ams_results.append(ams_result) + except requests.exceptions.HTTPError as http_err: + current_app.logger.error(f'AMS Service HTTP error occurred for POST request: {http_err}') + except requests.exceptions.ConnectionError as conn_err: + current_app.logger.error(f'AMS Service Connection error occurred for POST request: {conn_err}') + except requests.exceptions.Timeout as timeout_err: + current_app.logger.error(f'AMS Service Timeout error occurred for POST request: {timeout_err}') + except Exception as err: + current_app.logger.error(f'AMS Input Exception error occurred for POST request: {err}') + current_app.logger.error(traceback.format_exc()) + + return ams_results + + @classmethod + def create_amendment_ams_authorization(cls, + ams_authorizations, + applicant, + nearest_municipality, + agent, + contacts, + facility_type, + facility_desc, + facility_latitude, + facility_longitude, + facility_coords_source, + facility_coords_source_desc, + legal_land_desc, + facility_operator, + legal_land_owner_name, + legal_land_owner_contact_number, + legal_land_owner_email_address, + is_landowner_aware_of_discharge_application, + has_landowner_received_copy_of_application, + facility_pid_pin_crown_file_no, + company_alias, + zoning, + zoning_reason, + regional_district_name, + is_legal_land_owner, + is_crown_land_federal_or_provincial + ): + """Creates an AMS authorization application amendment""" + + ams_results = [] + headers = { + 'bearer': Config.AMS_BEARER_TOKEN, + 'Content-Type': 'application/json' + } + try: + nearest_municipality_name = '' + if nearest_municipality: + nearest_municipality_name = Municipality.find_by_guid(nearest_municipality).municipality_name + + authorization_list = cls.__get_authorization_details(ams_authorizations, 'amendments') + for authorization in authorization_list: existing_ams_status_code = authorization.get('ams_status_code') + amendment_changes = authorization.get('amendment_changes', []) + existing_permits_authorizations = authorization.get('existing_permits_authorizations', []) if existing_ams_status_code != '200': ams_authorization_data = { - 'isauthamendment': 'No', - 'authorizationtype': { - 'authorizationname': cls.__get_mapped_permit_type(authorization.get('new_type')), - }, + 'isauthamendment': 'Yes', 'receiveddate': get_date_iso8601_string(), - 'majorcentre': { - 'name': nearest_municipality_name - }, - 'applicant': { - 'applicanttype': cls.__get_mapped_party_type(applicant.get('party_type_code')), - 'em_companyname': applicant.get('party_name', ''), - 'em_businessphone': cls.__format_phone_number(applicant.get('phone_no', '')), - 'em_firstname': applicant.get('first_name', ''), - 'em_middlename': applicant.get('middle_name', ''), - 'em_lastname': applicant.get('party_name', ''), - 'em_email': applicant.get('email', ''), - 'billingaddress': cls.__create_full_address( - applicant.get('address')[2].get('address_line_1', ''), - applicant.get('address')[2].get('city', ''), - applicant.get('address')[2].get('sub_division_code', ''), - applicant.get('address')[2].get('post_code')), - 'em_doingbusinessas': company_alias, - 'legaladdress': cls.__create_full_address( - applicant.get('address')[1].get('address_line_1', ''), - applicant.get('address')[1].get('city', ''), - applicant.get('address')[1].get('sub_division_code', ''), - applicant.get('address')[1].get('post_code')), - 'mailingaddress': cls.__create_full_address( - applicant.get('address')[0].get('address_line_1', ''), - applicant.get('address')[0].get('city', ''), - applicant.get('address')[0].get('sub_division_code', ''), - applicant.get('address')[0].get('post_code')), - 'bccompanyregistrationnumber': applicant.get('party_orgbook_entity').get('registration_id', '') - }, - 'agent': { - 'em_lastname': agent.get('party_name', '') if agent else '', - 'em_firstname': agent.get('first_name', '') if agent else '', - 'em_email': agent.get('email', '') if agent else '', - 'em_companyname': agent.get('party_name', '') if agent else '', - 'em_mailingaddress': cls.__create_full_address( - agent.get('address').get('address_line_1', ''), - agent.get('address').get('city', ''), - agent.get('address').get('sub_division_code', ''), - agent.get('address').get('post_code')) if agent else '', - 'em_businessphone': cls.__format_phone_number(agent.get('phone_no')) if agent else '', - 'em_title': agent.get('job_title', '') if agent else '', + 'authorizationnumber': existing_permits_authorizations[0], + 'amendmenttype': cls.__get_mapped_amendment_type(authorization.get('amendment_severity')), + 'amendmentobjectives': { + 'increasedischargelimitslt10': str('ILT' in amendment_changes).capitalize(), + 'increasedischargelimitsgt10': str('IGT' in amendment_changes).capitalize(), + 'decreasedischargelimits': str('DDL' in amendment_changes).capitalize(), + 'namechange': str('NAM' in amendment_changes).capitalize(), + 'transfer': str('TRA' in amendment_changes).capitalize(), + 'modifymonitoringrequirements': str('MMR' in amendment_changes).capitalize(), + 'regulatorychange': str('RCH' in amendment_changes).capitalize(), + 'other': str('OTH' in amendment_changes).capitalize() }, 'purposeofapplication': authorization.get('authorization_description', ''), - 'preappexemptionrequest': cls.__boolean_to_yes_no(authorization.get('exemption_requested')), - 'preappexemptionrequestreason': authorization.get('exemption_reason', 'Not Applicable'), - 'iscontaminatedsite': cls.__boolean_to_yes_no(authorization.get('is_contaminated')), - 'contact': { - 'em_lastname': contacts[0].get('last_name', ''), - 'em_firstname': contacts[0].get('first_name', ''), - 'em_title': contacts[0].get('job_title', ''), - 'em_businessphone': cls.__format_phone_number(contacts[0].get('phone_number')), - 'em_email': contacts[0].get('email', ''), - 'em_mailingaddress': cls.__create_full_address( - contacts[0].get('address').get('address_line_1', ''), - contacts[0].get('address').get('city', ''), - contacts[0].get('address').get('sub_division_code', ''), - contacts[0].get('address').get('post_code')), - }, - 'facilitytype': facility_type, - 'facilitydescription': facility_desc, - 'latitude': str(facility_latitude), - 'longitude': str(abs(facility_longitude)), - 'sourceofdata': facility_coords_source, - 'sourceofdatadescription': facility_coords_source_desc, - 'legallanddescription': legal_land_desc, - 'pidpincrownfilenumber': facility_pid_pin_crown_file_no, - 'facilityaddress': { - 'addresstype': 'Other / International', - 'suitenumber': facility_operator.get('address').get('suite_no', ''), - 'streetnumber': facility_operator.get('address').get('suite_no', ''), - 'street': facility_operator.get('address').get('address_line_1', ''), - 'line2': facility_operator.get('address').get('address_line_2', ''), - 'municipality': facility_operator.get('address').get('city', ''), - 'province': 'British Columbia', - 'country': 'Canada', - 'postalcode': facility_operator.get('address').get('post_code'), - 'otheraddress': cls.__create_full_address( - facility_operator.get('address').get('address_line_1'), - facility_operator.get('address').get('city'), - facility_operator.get('address').get('sub_division_code'), - facility_operator.get('address').get('post_code')) + 'newmajorcentre': { + 'name': nearest_municipality_name }, - 'facilityopphonenumberext': facility_operator.get('phone_ext', ''), - 'isappropriatezoning': cls.__boolean_to_yes_no(zoning), - 'isappropriatezoningreason': zoning_reason, - 'landownername': legal_land_owner_name, - 'landownerphonenumber': cls.__format_phone_number(legal_land_owner_contact_number), - 'landowneremail': legal_land_owner_email_address, - 'istheapplicantthelandowner': cls.__boolean_to_yes_no(is_legal_land_owner), - 'landfedorprov': cls.__boolean_to_yes_no(is_crown_land_federal_or_provincial), - 'landownerawareofapplication': cls.__boolean_to_yes_no(is_landowner_aware_of_discharge_application), - 'landownerreceivedcopy': cls.__boolean_to_yes_no(has_landowner_received_copy_of_application), - 'facilityoperator': facility_operator.get('name', ''), - 'facilityoperatorphonenumber': cls.__format_phone_number(facility_operator.get('phone_no', '')), - 'facilityoperatoremail': facility_operator.get('email', ''), - 'facilityoperatortitle': facility_operator.get('job_title', ''), - 'regionaldistrict': { + 'preappexemptionrequest': cls.__boolean_to_yes_no(authorization.get('exemption_requested')), + 'preappexemptionrequestreason': authorization.get('authorization_description', + 'Not Applicable'), + 'newapplicant': cls.__set_applicant_details(applicant, company_alias), + 'newcontact': cls.__set_contact_details(contacts[0]), + 'newagent': cls.__set_agent_details(agent), + 'newfacilitytype': facility_type, + 'newfacilitydescrption': facility_desc, + 'newregionaldistrict': { 'name': regional_district_name - } + }, + 'newlatitude': str(facility_latitude), + 'newlongitude': str(abs(facility_longitude)), + 'newsourceofdata': facility_coords_source, + 'newsourceofdatadescription': facility_coords_source_desc, + 'newlegallanddescription': legal_land_desc, + 'newpidpincrownfilenumber': facility_pid_pin_crown_file_no, + 'newfacilityaddress': cls.__set_facility_address_details(facility_operator, "Other / International"), + 'newisappropriatezoning': cls.__boolean_to_yes_no(zoning), + 'newisappropriatezoningreason': zoning_reason, + 'newfacilityoperator': facility_operator.get('name', ''), + 'newfacilityoperatortitle': facility_operator.get('job_title', ''), + 'newfacilityoperatorphonenumber': cls.__format_phone_number( + facility_operator.get('phone_no', '')), + 'newfacilityopphonenumberext': facility_operator.get('phone_ext', ''), + 'newfacilityoperatoremail': facility_operator.get('email', ''), + 'newlandownerawareofapplication': cls.__boolean_to_yes_no( + is_landowner_aware_of_discharge_application), + 'newlandownerreceivedcopy': cls.__boolean_to_yes_no(has_landowner_received_copy_of_application), + 'newlandownername': legal_land_owner_name, + 'newlandownerphonenumber': cls.__format_phone_number(legal_land_owner_contact_number), + 'newlandowneremail': legal_land_owner_email_address, + 'newistheapplicantthelandowner': cls.__boolean_to_yes_no(is_legal_land_owner), + 'newlandfedorprov': cls.__boolean_to_yes_no(is_crown_land_federal_or_provincial) } payload = json.dumps(ams_authorization_data) response = requests.post(Config.AMS_URL, data=payload, headers=headers) ams_result = response.json() - ams_result['project_summary_authorization_guid'] = authorization.get('project_summary_authorization_guid') + current_app.logger.error(f'AMS Result: {ams_result}') + ams_result['project_summary_authorization_guid'] = authorization.get( + 'project_summary_authorization_guid') ams_result['project_summary_guid'] = authorization.get('project_summary_guid') ams_result['project_summary_authorization_type'] = authorization.get( 'project_summary_authorization_type') ams_results.append(ams_result) + + except requests.exceptions.HTTPError as http_err: current_app.logger.error(f'AMS Service HTTP error occurred for POST request: {http_err}') except requests.exceptions.ConnectionError as conn_err: @@ -226,5 +392,6 @@ def create_new_ams_authorization(cls, current_app.logger.error(f'AMS Service Timeout error occurred for POST request: {timeout_err}') except Exception as err: current_app.logger.error(f'AMS Input Exception error occurred for POST request: {err}') + current_app.logger.error(traceback.format_exc()) return ams_results diff --git a/services/core-api/tests/services/test_ams_api_service.py b/services/core-api/tests/services/test_ams_api_service.py index df2b111bfa..2816b1480b 100644 --- a/services/core-api/tests/services/test_ams_api_service.py +++ b/services/core-api/tests/services/test_ams_api_service.py @@ -199,3 +199,157 @@ def test_create_new_ams_authorization_successful_outcome(test_client): data.get('zoning_reason')) mock_create_new_ams_authorization.assert_called_once() assert result[0]['trackingnumber'] == '123456' + +def test_create_amendment_ams_authorization_successful_outcome(test_client): + data = { + 'documents': [], + 'company_alias': 'Test', + 'contacts': [{ + 'project_contact_guid': '5ba69052-ebf7-433d-8a31-e277b412f232', + 'project_guid': '4f3ce441-05a4-4df0-b51a-3726e1e78ee3', + 'email': 'test@test.com', + 'phone_number': '123-456-7890', + 'first_name': 'Tester', + 'last_name': 'Tester', + 'address': { + 'suite_no': '15', + 'address_line_1': 'Pump Street', + 'city': 'Victoria', + 'sub_division_code': 'BC', + 'post_code': 'V9B2T8', + 'address_type_code': 'CAN' + } + }], + 'ams_authorizations': { + 'amendment': [ + { + 'project_summary_authorization_guid': 'xyz123', + 'project_summary_guid': 'abcde12345', + 'new_type': 'PER', + 'authorization_description': 'Test desc', + 'exemption_requested': True, + 'is_contaminated': True + } + ] + }, + 'agent': { + 'party_guid': '81406c88-277b-402f-a9d9-38db3f00904b', + 'party_type_code': 'ORG', + 'phone_no': '123-456-7890', + 'email': 'test@test.com', + 'party_name': 'Test Agent Name', + 'name': 'Test Agent Name', + 'address': { + 'suite_no': '20', + 'address_line_1': 'Pump Street', + 'city': 'Victoria', + 'sub_division_code': 'BC', + 'post_code': 'V9B2T3', + 'address_type_code': 'CAN' + } + }, + 'is_legal_land_owner': False, + 'is_crown_land_federal_or_provincial': True, + 'is_landowner_aware_of_discharge_application': True, + 'has_landowner_received_copy_of_application': True, + 'legal_land_owner_name': 'Test Land owner', + 'legal_land_owner_contact_number': '123-456-7890', + 'legal_land_owner_email_address': 'test@test.com', + 'facility_operator': { + 'party_guid': '3a532eee-9d43-4662-b11d-a81e5fbc4543', + 'party_type_code': 'PER', + 'phone_no': '123-456-7890', + 'party_name': 'Last name', + 'name': 'First Last name', + 'first_name': 'First', + 'address': { + 'suite_no': '15', + 'address_line_1': 'Pump Street', + 'city': 'Victoria', + 'sub_division_code': 'BC', + 'post_code': 'V9B2T8', + 'address_type_code': 'CAN' + }, + }, + 'zoning': True, + 'facility_pid_pin_crown_file_no': '12345', + 'facility_type': 'Test Facility', + 'facility_desc': 'Test Facility', + 'facility_latitude': '47.0000000', + 'facility_longitude': '-113.0000000', + 'facility_coords_source': 'GPS', + 'nearest_municipality': 'abcde12345', + 'is_legal_address_same_as_mailing_address': False, + 'is_billing_address_same_as_mailing_address': False, + 'is_billing_address_same_as_legal_address': True, + 'applicant': { + 'party_guid': '58336bde-ee23-4b58-ba0a-864fa033e343', + 'party_type_code': 'ORG', + 'phone_no': '123-456-7890', + 'email': 'test@gold.com', + 'party_name': 'SELECT REALTY', + 'name': 'SELECT REALTY', + 'address': [ + { + 'suite_no': '35', + 'address_line_1': '15 Cancun Street', + 'city': 'Victoria', + 'sub_division_code': 'BC', + 'post_code': 'V9B2T9', + 'address_type_code': 'CAN' + }, + { + 'suite_no': '27B', + 'address_line_1': '35 Ade street', + 'city': 'Pretoria', + 'sub_division_code': None, + 'post_code': '29192', + 'address_type_code': 'INT' + }, + { + 'suite_no': '27B', + 'address_line_1': '35 Ade street', + 'city': 'Pretoria', + 'sub_division_code': None, + 'post_code': '29192', + 'address_type_code': 'INT' + } + ], + } + } + + mock_return_value = [ + {'trackingnumber': '123456', 'outcome': 'Successfull', + 'project_summary_authorization_guid': 'xyz123'} + ] + with current_app.test_request_context() as a, patch( + "app.api.services.ams_api_service.AMSApiService.create_amendment_ams_authorization", + return_value=mock_return_value + ) as create_amendment_ams_authorization: + service = AMSApiService() + result = service.create_amendment_ams_authorization(data.get('ams_authorizations'), + data.get('applicant'), + data.get('nearest_municipality'), + data.get('agent'), + data.get('contacts'), + data.get('facility_type'), + data.get('facility_desc'), + data.get('facility_latitude'), + data.get('facility_longitude'), + data.get('facility_coords_source'), + data.get('facility_coords_source_desc'), + data.get('legal_land_desc'), + data.get('facility_operator'), + data.get('legal_land_owner_name'), + data.get('legal_land_owner_contact_number'), + data.get('legal_land_owner_email_address'), + data.get('is_legal_land_owner'), + data.get('is_crown_land_federal_or_provincial'), + data.get('is_landowner_aware_of_discharge_application'), + data.get('has_landowner_received_copy_of_application'), + data.get('facility_pid_pin_crown_file_no'), + data.get('company_alias'), + data.get('zoning'), + data.get('zoning_reason')) + create_amendment_ams_authorization.assert_called_once() + assert result[0]['trackingnumber'] == '123456'