diff --git a/legal-api/src/legal_api/core/filing.py b/legal-api/src/legal_api/core/filing.py index 973380e725..ba0fb11969 100644 --- a/legal-api/src/legal_api/core/filing.py +++ b/legal-api/src/legal_api/core/filing.py @@ -456,7 +456,7 @@ def _is_display_ledger(filing: FilingStorage) -> bool: @staticmethod def get_document_list(business, # pylint: disable=too-many-locals disable=too-many-branches filing, - request) -> Optional[dict]: + jwt: JwtManager) -> Optional[dict]: """Return a list of documents for a particular filing.""" no_output_filings = [ Filing.FilingTypes.CONVERSION.value, @@ -557,4 +557,8 @@ def get_document_list(business, # pylint: disable=too-many-locals disable=too-m for doc in additional: documents['documents'][doc] = f'{base_url}{doc_url}/{doc}' + if has_roles(jwt, [UserRoles.staff]): + if static_docs := FilingMeta.get_static_documents(filing.storage, f'{base_url}{doc_url}/static'): + documents['documents']['staticDocuments'] = static_docs + return documents diff --git a/legal-api/src/legal_api/core/meta/filing.py b/legal-api/src/legal_api/core/meta/filing.py index a5a55640be..4f90fa64c0 100644 --- a/legal-api/src/legal_api/core/meta/filing.py +++ b/legal-api/src/legal_api/core/meta/filing.py @@ -585,13 +585,14 @@ def alter_outputs_alteration(filing, outputs): def alter_outputs_correction(filing, business, outputs): """Handle output file list modification for corrections.""" if filing.filing_type == 'correction': - if filing.meta_data.get('correction', {}).get('toLegalName'): + correction = filing.meta_data.get('correction', {}) + if correction.get('toLegalName'): outputs.add('certificateOfNameCorrection') - if filing.meta_data.get('correction', {}).get('uploadNewRules'): + if correction.get('uploadNewRules'): outputs.add('certifiedRules') - if filing.meta_data.get('correction', {}).get('uploadNewMemorandum'): + if correction.get('uploadNewMemorandum'): outputs.add('certifiedMemorandum') - if filing.meta_data.get('correction', {}).get('hasResolution'): + if correction.get('hasResolution'): outputs.add('specialResolution') return outputs @@ -619,6 +620,26 @@ def alter_outputs_special_resolution(filing, outputs): outputs.remove('certifiedRules') return outputs + @staticmethod + def get_static_documents(filing, url_prefix): + """Get static documents.""" + outputs = [] + if filing.filing_type == 'continuationIn': + continuation_in = filing.meta_data.get('continuationIn', {}) + if file_key := continuation_in.get('affidavitFileKey'): + outputs.append({ + 'name': 'Director Affidavit', + 'url': f'{url_prefix}/{file_key}' + }) + if authorization_files := continuation_in.get('authorizationFiles'): + for file in authorization_files: + file_key = file.get('fileKey') + outputs.append({ + 'name': file.get('fileName'), + 'url': f'{url_prefix}/{file_key}' + }) + return outputs + @staticmethod def get_display_name(legal_type: str, filing_type: str, filing_sub_type: str = None) -> str: """Return display name for filing.""" diff --git a/legal-api/src/legal_api/reports/report.py b/legal-api/src/legal_api/reports/report.py index 84c17f851a..9308c37c0e 100644 --- a/legal-api/src/legal_api/reports/report.py +++ b/legal-api/src/legal_api/reports/report.py @@ -1387,9 +1387,6 @@ class ReportMeta: # pylint: disable=too-few-public-methods 'affidavit': { 'documentType': 'affidavit' }, - 'directorAffidavit': { - 'documentType': 'director_affidavit' - }, 'uploadedCourtOrder': { 'documentType': 'court_order' } diff --git a/legal-api/src/legal_api/resources/v2/business/business_filings/business_documents.py b/legal-api/src/legal_api/resources/v2/business/business_filings/business_documents.py index d470b5e42e..f321e39703 100644 --- a/legal-api/src/legal_api/resources/v2/business/business_filings/business_documents.py +++ b/legal-api/src/legal_api/resources/v2/business/business_filings/business_documents.py @@ -24,9 +24,9 @@ from legal_api.core import Filing from legal_api.exceptions import ErrorCode, get_error_message -from legal_api.models import Business, Filing as FilingModel # noqa: I001 +from legal_api.models import Business, Document, Filing as FilingModel # noqa: I001 from legal_api.reports import get_pdf -from legal_api.services import authorized +from legal_api.services import MinioService, authorized from legal_api.utils.auth import jwt from legal_api.utils.legislation_datetime import LegislationDatetime from legal_api.utils.util import cors_preflight @@ -43,9 +43,10 @@ @cors_preflight('GET, POST') @bp.route(DOCUMENTS_BASE_ROUTE, methods=['GET', 'OPTIONS']) @bp.route(DOCUMENTS_BASE_ROUTE + '/', methods=['GET', 'OPTIONS']) +@bp.route(DOCUMENTS_BASE_ROUTE + '/static/', methods=['GET', 'OPTIONS']) @cross_origin(origin='*') @jwt.requires_auth -def get_documents(identifier: str, filing_id: int, legal_filing_name: str = None): +def get_documents(identifier: str, filing_id: int, legal_filing_name: str = None, file_key: str = None): """Return a JSON object with meta information about the Service.""" # basic checks if not authorized(identifier, jwt, ['view', ]): @@ -70,23 +71,32 @@ def get_documents(identifier: str, filing_id: int, legal_filing_name: str = None **{'filing_id': filing_id, 'identifier': identifier}) ), HTTPStatus.NOT_FOUND - if not legal_filing_name: + if not legal_filing_name and not file_key: if identifier.startswith('T') and filing.status == Filing.Status.COMPLETED: - return {}, HTTPStatus.NOT_FOUND + return {'documents': {}}, HTTPStatus.OK return _get_document_list(business, filing) - if legal_filing_name and ('application/pdf' in request.accept_mimetypes): - if legal_filing_name.lower().startswith('receipt'): - return _get_receipt(business, filing, jwt.get_token_auth_header()) - - return get_pdf(filing.storage, legal_filing_name) + if 'application/pdf' in request.accept_mimetypes: + if legal_filing_name: + if legal_filing_name.lower().startswith('receipt'): + return _get_receipt(business, filing, jwt.get_token_auth_header()) + + return get_pdf(filing.storage, legal_filing_name) + elif file_key and (document := Document.find_by_file_key(file_key)): + if document.filing_id == filing.id: # make sure the file belongs to this filing + response = MinioService.get_file(document.file_key) + return current_app.response_class( + response=response.data, + status=response.status, + mimetype='application/pdf' + ) return {}, HTTPStatus.NOT_FOUND def _get_document_list(business, filing): """Get list of document outputs.""" - if not (document_list := Filing.get_document_list(business, filing, request)): + if not (document_list := Filing.get_document_list(business, filing, jwt)): return {}, HTTPStatus.NOT_FOUND return jsonify(document_list), HTTPStatus.OK diff --git a/legal-api/tests/unit/resources/v2/test_business_filings/test_filing_documents.py b/legal-api/tests/unit/resources/v2/test_business_filings/test_filing_documents.py index c547337faa..9ae1817fc4 100644 --- a/legal-api/tests/unit/resources/v2/test_business_filings/test_filing_documents.py +++ b/legal-api/tests/unit/resources/v2/test_business_filings/test_filing_documents.py @@ -36,6 +36,8 @@ CHANGE_OF_ADDRESS, CHANGE_OF_DIRECTORS, CHANGE_OF_REGISTRATION, + CONTINUATION_IN, + CONTINUATION_OUT, CORRECTION_AR, CORRECTION_CP_SPECIAL_RESOLUTION, CORRECTION_INCORPORATION, @@ -49,7 +51,6 @@ RESTORATION, SPECIAL_RESOLUTION, TRANSITION_FILING_TEMPLATE, - CONTINUATION_OUT, ) from registry_schemas.example_data.schema_data import ALTERATION, INCORPORATION, CONTINUATION_IN @@ -887,7 +888,7 @@ def test_unpaid_filing(session, client, jwt): Business.LegalTypes.BCOMP.value, 'agmExtension', AGM_EXTENSION, None, None, Filing.Status.COMPLETED, {'documents': { - 'letterOfAgmExtension': 'https://LEGAL_API_BASE_URL/api/v2/businesses/BC7654321/filings/documents/letterOfAgmExtension', + 'letterOfAgmExtension': f'{base_url}/api/v2/businesses/BC7654321/filings/documents/letterOfAgmExtension', 'receipt': f'{base_url}/api/v2/businesses/BC7654321/filings/1/documents/receipt' } }, @@ -906,7 +907,7 @@ def test_unpaid_filing(session, client, jwt): Business.LegalTypes.BCOMP.value, 'agmLocationChange', AGM_LOCATION_CHANGE, None, None, Filing.Status.COMPLETED, {'documents': { - 'letterOfAgmLocationChange': 'https://LEGAL_API_BASE_URL/api/v2/businesses/BC7654321/filings/documents/letterOfAgmLocationChange', + 'letterOfAgmLocationChange': f'{base_url}/api/v2/businesses/BC7654321/filings/documents/letterOfAgmLocationChange', 'receipt': f'{base_url}/api/v2/businesses/BC7654321/filings/1/documents/receipt' } }, @@ -1246,7 +1247,7 @@ def test_unpaid_filing(session, client, jwt): HTTPStatus.OK, None ) ]) -def test_document_list_for_various_filing_states(session, client, jwt, +def test_document_list_for_various_filing_states(session, mocker, client, jwt, test_name, identifier, entity_type, @@ -1283,6 +1284,22 @@ def test_document_list_for_various_filing_states(session, client, jwt, filing._meta_data = filer_action(filing_name_1, filing_json, meta_data, business) filing.save() + if filing_name_1 == 'continuationIn': + affidavit_file_key = meta_data['continuationIn']['affidavitFileKey'] + expected_msg['documents']['staticDocuments'] = [ + { + 'name': 'Director Affidavit', + 'url': f'{base_url}/api/v2/businesses/{identifier}/filings/1/documents/static/{affidavit_file_key}' + } + ] + for file in meta_data['continuationIn']['authorizationFiles']: + file_key = file.get('fileKey') + expected_msg['documents']['staticDocuments'].append({ + 'name': file.get('fileName'), + 'url': f'{base_url}/api/v2/businesses/{identifier}/filings/1/documents/static/{file_key}' + }) + + mocker.patch('legal_api.core.filing.has_roles', return_value=True) rv = client.get(f'/api/v2/businesses/{business.identifier}/filings/{filing.id}/documents', headers=create_header(jwt, [STAFF_ROLE], business.identifier)) @@ -1302,6 +1319,12 @@ def filer_action(filing_name, filing_json, meta_data, business): meta_data['alteration']['fromLegalName'] = business.legal_name meta_data['alteration']['toLegalName'] = legal_name + if filing_name == 'continuationIn': + continuation_in = filing_json['filing']['continuationIn'] + meta_data['continuationIn'] = {} + meta_data['continuationIn']['affidavitFileKey'] = continuation_in['foreignJurisdiction']['affidavitFileKey'] + meta_data['continuationIn']['authorizationFiles'] = continuation_in['authorization']['files'] + if filing_name == 'correction' and business.legal_type == 'CP': meta_data['correction'] = {} if (legal_name := filing_json['filing']['correction'].get('nameRequest', {}).get('legalName')): @@ -1335,7 +1358,7 @@ def filer_action(filing_name, filing_json, meta_data, business): ), ('ben_ia_completed', 'Tb31yQIuBw', 'BC7654321', Business.LegalTypes.BCOMP.value, 'incorporationApplication', INCORPORATION, Filing.Status.COMPLETED, - {}, HTTPStatus.NOT_FOUND + {'documents': {}}, HTTPStatus.OK ), ('ben_amalgamation_paid', 'Tb31yQIuBw', None, Business.LegalTypes.BCOMP.value, 'amalgamationApplication', AMALGAMATION_APPLICATION, Filing.Status.PAID, @@ -1349,7 +1372,19 @@ def filer_action(filing_name, filing_json, meta_data, business): ), ('ben_amalgamation_completed', 'Tb31yQIuBw', 'BC7654321', Business.LegalTypes.BCOMP.value, 'amalgamationApplication', AMALGAMATION_APPLICATION, Filing.Status.COMPLETED, - {}, HTTPStatus.NOT_FOUND + {'documents': {}}, HTTPStatus.OK + ), + ('cben_ci_paid', 'Tb31yQIuBw', None, Business.LegalTypes.BCOMP_CONTINUE_IN.value, + 'continuationIn', CONTINUATION_IN, Filing.Status.PAID, + {'documents': {'receipt': f'{base_url}/api/v2/businesses/Tb31yQIuBw/filings/1/documents/receipt', + 'legalFilings': [ + {'continuationIn': f'{base_url}/api/v2/businesses/Tb31yQIuBw/filings/1/documents/continuationIn'}, + ]}}, + HTTPStatus.OK + ), + ('cben_ci_completed', 'Tb31yQIuBw', 'BC7654321', Business.LegalTypes.BCOMP_CONTINUE_IN.value, + 'continuationIn', CONTINUATION_IN, Filing.Status.COMPLETED, + {'documents': {}}, HTTPStatus.OK ), ('sp_registration_paid', 'Tb31yQIuBw', None, Business.LegalTypes.SOLE_PROP.value, 'registration', REGISTRATION, Filing.Status.PAID, @@ -1362,10 +1397,10 @@ def filer_action(filing_name, filing_json, meta_data, business): ), ('sp_registration_completed', 'Tb31yQIuBw', 'FM7654321', Business.LegalTypes.SOLE_PROP.value, 'registration', REGISTRATION, Filing.Status.COMPLETED, - {}, HTTPStatus.NOT_FOUND + {'documents': {}}, HTTPStatus.OK ), ]) -def test_temp_document_list_for_various_filing_states(session, client, jwt, +def test_temp_document_list_for_various_filing_states(mocker, session, client, jwt, test_name, temp_identifier, identifier, @@ -1397,6 +1432,7 @@ def test_temp_document_list_for_various_filing_states(session, client, jwt, filing.temp_reg = temp_identifier filing.save() + mocker.patch('legal_api.core.filing.has_roles', return_value=True) rv = client.get(f'/api/v2/businesses/{temp_identifier}/filings/{filing.id}/documents', headers=create_header(jwt, [STAFF_ROLE], temp_identifier))