diff --git a/legal-api/pyproject.toml b/legal-api/pyproject.toml index 6a0c91de97..8f30f852c9 100644 --- a/legal-api/pyproject.toml +++ b/legal-api/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "legal-api" -version = "3.0.0" +version = "3.0.1" description = "" authors = [ {name = "thor",email = "1042854+thorwolpert@users.noreply.github.com"} diff --git a/legal-api/report-templates/template-parts/common/businessDetails.html b/legal-api/report-templates/template-parts/common/businessDetails.html index 288d85ddc6..f981e20481 100644 --- a/legal-api/report-templates/template-parts/common/businessDetails.html +++ b/legal-api/report-templates/template-parts/common/businessDetails.html @@ -361,12 +361,7 @@ {% endif %} - -{% if reportType == 'summary' %} -
Information current as of {{report_date_time}}
-{% else %} -
Document retrieved on {{report_date_time}}
-{% endif %} +
diff --git a/legal-api/src/legal_api/core/filing.py b/legal-api/src/legal_api/core/filing.py index 3c450e43cc..440f831be1 100644 --- a/legal-api/src/legal_api/core/filing.py +++ b/legal-api/src/legal_api/core/filing.py @@ -26,6 +26,7 @@ from legal_api.core.meta import FilingMeta from legal_api.models import Business, Document, DocumentType, UserRoles from legal_api.models import Filing as FilingStorage +from legal_api.reports.document_service import DocumentService from legal_api.services import VersionedBusinessDetailsService from legal_api.services.authz import has_roles, is_competent_authority @@ -402,6 +403,9 @@ def ledger(business_id: int, # noqa: PLR0913 query = query.order_by(desc(FilingStorage.filing_date)) + drs_service: DocumentService = DocumentService() + drs_docs = drs_service.get_documents_by_business_id(business.identifier) if business else [] + ledger = [] for filing in query.all(): @@ -443,6 +447,10 @@ def ledger(business_id: int, # noqa: PLR0913 if filing.court_order_file_number or filing.order_details: Filing._add_ledger_order(filing, ledger_filing) + core_filing: Filing = Filing() # Filing.get_document_list needs a core Filing. + core_filing._storage = filing # pylint: disable=protected-access + filing_docs = Filing.get_document_list(business, core_filing, jwt) + ledger_filing["documents"] = drs_service.update_filing_documents(drs_docs, filing_docs, filing) ledger.append(ledger_filing) return ledger @@ -480,7 +488,7 @@ def _add_ledger_order(filing: FilingStorage, ledger_filing: dict) -> dict: ledger_filing["data"]["order"] = court_order_data @staticmethod - def get_document_list(business, # noqa: PLR0912 + def get_document_list(business, # noqa: PLR0912, PLR0915 NOSONAR(S3776) filing, jwt: JwtManager) -> dict | None: """Return a list of documents for a particular filing.""" @@ -512,7 +520,6 @@ def get_document_list(business, # noqa: PLR0912 identifier = withdrawn_filing.storage.temp_reg doc_url = url_for("API2.get_documents", identifier=identifier, filing_id=filing.id, legal_filing_name=None) - documents = {"documents": {}} # for paper_only filings return and empty documents list if filing.storage and filing.storage.paper_only: @@ -531,6 +538,8 @@ def get_document_list(business, # noqa: PLR0912 Document.type == DocumentType.COURT_ORDER.value).one_or_none()): documents["documents"]["uploadedCourtOrder"] = f"{base_url}{doc_url}/uploadedCourtOrder" documents["documents"]["receipt"] = f"{base_url}{doc_url}/receipt" + elif filing.storage and filing.storage.source == filing.storage.Source.COLIN.value: + documents["documents"]["receipt"] = f"{base_url}{doc_url}/receipt" no_outputs_except_receipt = filing.filing_type in [ Filing.FilingTypes.CHANGEOFLIQUIDATORS.value, @@ -568,10 +577,13 @@ def get_document_list(business, # noqa: PLR0912 del documents["documents"]["receipt"] return documents + legal_filings = filing.storage.meta_data.get("legalFilings") if filing.storage.meta_data else None + if not legal_filings and filing.storage and filing.storage.source == filing.storage.Source.COLIN.value: + legal_filings = [filing.filing_type] if ( filing.status in (Filing.Status.COMPLETED, Filing.Status.CORRECTED) and filing.storage.meta_data and - (legal_filings := filing.storage.meta_data.get("legalFilings")) + legal_filings and not (no_outputs_except_receipt or no_outputs_except_receipt_dissolution) ): legal_filings_copy = copy.deepcopy(legal_filings) @@ -612,7 +624,6 @@ def get_document_list(business, # noqa: PLR0912 adds = [FilingMeta.get_all_outputs(business.legal_type, doc) for doc in legal_filings] additional = {item for sublist in adds for item in sublist} - FilingMeta.alter_outputs(filing.storage, business, additional) for doc in additional: documents["documents"][doc] = f"{base_url}{doc_url}/{doc}" diff --git a/legal-api/src/legal_api/reports/document_service.py b/legal-api/src/legal_api/reports/document_service.py index ffdb6ddcc4..63e07fe22b 100644 --- a/legal-api/src/legal_api/reports/document_service.py +++ b/legal-api/src/legal_api/reports/document_service.py @@ -18,8 +18,58 @@ from flask import current_app, jsonify from legal_api.exceptions import BusinessException -from legal_api.models import Business, Document +from legal_api.models import Business, Document, Filing from legal_api.services import AccountService +from legal_api.utils.base import BaseEnum + +BUSINESS_DOCS_PATH: str = "{url}/application-reports/history/{product}/{business_id}?includeDocuments=true" +GET_REPORT_PATH: str = "{url}/application-reports/{product}/{drsId}" +GET_REPORT_CERTIFIED_PATH: str = "{url}/application-reports/{product}/{drsId}?certifiedCopy=true" +POST_REPORT_PATH: str = "{url}/application-reports/{product}/{bus_id}/{filing_id}/{report_type}" +POST_REPORT_PARAMS: str = "?consumerFilingDate={filing_date}&consumerFilename={filename}" +GET_DOCUMENT_PATH: str = "{url}/searches/{document_class}?documentServiceId={drs_id}" +FILING_DOCS_PATH: str = "{url}/application-reports/events/{product}/{business_id}/{filing_id}?includeDocuments=true" +DRS_REPORT_PARAMS: str = "?reportType={report_type}&drsId={drs_id}" +DRS_DOCUMENT_PARAMS: str = "?documentClass={document_class}&drsId={drs_id}" +# Used for audit trail and db queries. +BUSINESS_API_ACCOUNT_ID: str = "business-api" +FILING_DOCUMENTS = { + "certifiedRules": { + "documentType": "COOP_RULES", + "documentClass": "COOP" + }, + "certifiedMemorandum": { + "documentType": "COOP_MEMORANDUM", + "documentClass": "COOP" + }, + "affidavit": { + "documentType": "CORP_AFFIDAVIT", # "COSD", + "documentClass": "CORP" + }, + "uploadedCourtOrder": { + "documentType": "CRT", + "documentClass": "CORP" + } +} +STATIC_DOCUMENTS = { + "Unlimited Liability Corporation Information": { + "documentType": "DIRECTOR_AFFIDAVIT", + "documentClass": "CORP" + } +} +APP_JSON = "application/json" +APP_PDF = "application/pdf" +DOC_PATH = "/documents" +BEARER = "Bearer " + + +class ReportTypes(BaseEnum): + """Render an Enum of the document service report types.""" + + CERT = "CERT" + FILING = "FILING" + NOA = "NOA" + RECEIPT = "RECEIPT" class DocumentService: @@ -99,17 +149,13 @@ def create_document( """ if self.has_document(business_identifier, filing_identifier, report_type): raise BusinessException("Document already exists", HTTPStatus.CONFLICT) - - token = AccountService.get_bearer_token() - headers = { - "Content-Type": "application/json", - "X-ApiKey": self.api_key, - "Account-Id": account_id, - "Authorization": "Bearer " + token - } - post_url = (f"{self.url}/application-reports/" + headers = self._get_request_headers(account_id) + filename: str = f"{business_identifier}_{filing_identifier}_{report_type}.pdf" + url: str = self.url.replace(DOC_PATH, "") + post_url = (f"{url}/application-reports/" f"{self.product_code}/{business_identifier}/" - f"{filing_identifier}/{report_type}") + f"{filing_identifier}/{report_type}?consumerFiliename={filename}") + # Include filing date if available. response = requests.post(url=post_url, headers=headers, data=binary_or_url) content = self.get_content(response) if response.status_code != HTTPStatus.CREATED: @@ -117,7 +163,7 @@ def create_document( self.create_document_record( Business.find_by_identifier(business_identifier).id, filing_identifier, report_type, content["identifier"], - f"{business_identifier}_{filing_identifier}_{report_type}.pdf" + filename ) return content, response.status_code @@ -138,21 +184,16 @@ def get_document( account_id: The account id. return: The document url (or binary). """ - token = AccountService.get_bearer_token() - headers = { - "X-ApiKey": self.api_key, - "Account-Id": account_id, - "Content-Type": "application/pdf", - "Authorization": "Bearer " + token - } + headers = self._get_request_headers(account_id) + url: str = self.url.replace(DOC_PATH, "") get_url = "" if file_key is not None: - get_url = f"{self.url}/application-reports/{self.product_code}/{file_key}" + get_url = f"{url}/application-reports/{self.product_code}/{file_key}" else: document = self.has_document(business_identifier, filing_identifier, report_type) if document is False: raise BusinessException("Document not found", HTTPStatus.NOT_FOUND) - get_url = f"{self.url}/application-reports/{self.product_code}/{document.file_key}" + get_url = f"{url}/application-reports/{self.product_code}/{document.file_key}" if get_url != "": response = requests.get(url=get_url, headers=headers) @@ -161,3 +202,256 @@ def get_document( return jsonify(message=str(content)), response.status_code return content, response.status_code return jsonify(message="Document not found"), HTTPStatus.NOT_FOUND + + def get_documents_by_business_id(self, business_identifier: str) -> list: + """ + Get all available document information from the DRS by business identifier. + + business_identifier: The business identifier. + return: The list of available filing reports and documents for the business, or [] if there is a problem. + """ + try: + if not business_identifier: + return [] + headers = self._get_request_headers(BUSINESS_API_ACCOUNT_ID) + url: str = self.url.replace(DOC_PATH, "") + get_url = BUSINESS_DOCS_PATH.format(url=url, product=self.product_code, business_id=business_identifier) + response = requests.get(url=get_url, headers=headers) + content = self.get_content(response) + if response.status_code not in (HTTPStatus.OK, HTTPStatus.NOT_FOUND): + current_app.logger.error(f"DRS call {get_url} failed status={response.status_code}: {content}") + return content if response.status_code == HTTPStatus.OK else [] + except Exception: + return [] + + def get_documents_by_filing_id(self, business_identifier: str, filing_identifier: str) -> list: + """ + Get all available document information from the DRS by filing identifier. + + business_identifier: The business identifier. + filing_identifier: The filing identifier. + return: The list of available filing reports and documents for the filing, or [] if there is a problem or none. + """ + try: + if not business_identifier or not filing_identifier: + return [] + headers = self._get_request_headers(BUSINESS_API_ACCOUNT_ID) + url: str = self.url.replace(DOC_PATH, "") + get_url = FILING_DOCS_PATH.format( + url=url, + product=self.product_code, + business_id=business_identifier, + filing_id=filing_identifier + ) + response = requests.get(url=get_url, headers=headers) + content = self.get_content(response) + if response.status_code not in (HTTPStatus.OK, HTTPStatus.NOT_FOUND): + current_app.logger.error(f"DRS call {get_url} failed status={response.status_code}: {content}") + return content if response.status_code == HTTPStatus.OK else [] + except Exception: + return [] + + def update_document_list(self, drs_docs: list, document_list: list) -> list: + """ + Update document_list urls with DRS information if a filing document maps to a DRS output or document. + + drs_docs: The DRS reports/documents for the filing identifier. + document_list: The business list of reports/documents for the filing. + return: The updated list of filing reports and documents for the filing. + """ + if not drs_docs or not document_list or not document_list.get("documents"): + return document_list + doc_list = document_list.get("documents") + for doc in drs_docs: + if doc.get("reportType") and doc.get("reportType") == "RECEIPT" and doc_list.get("receipt"): + query_params: str = DRS_REPORT_PARAMS.format(report_type="RECEIPT", drs_id=doc.get("identifier")) + doc_list["receipt"] = doc_list["receipt"] + query_params + elif doc.get("reportType") and doc.get("reportType") == "NOA" and doc_list.get("noticeOfArticles"): + query_params: str = DRS_REPORT_PARAMS.format(report_type="NOA", drs_id=doc.get("identifier")) + doc_list["noticeOfArticles"] = doc_list["noticeOfArticles"] + query_params + elif doc.get("reportType") and doc.get("reportType") == "FILING" and doc_list.get("legalFilings"): + query_params: str = DRS_REPORT_PARAMS.format(report_type="FILING", drs_id=doc.get("identifier")) + filing = doc_list["legalFilings"][0] + filing_key = next(iter(filing.keys())) + filing[filing_key] = filing[filing_key] + query_params + elif doc.get("reportType") and doc.get("reportType") == "CERT": + query_params: str = DRS_REPORT_PARAMS.format(report_type="CERT", drs_id=doc.get("identifier")) + for key in doc_list: + if str(key).find("certificate") > -1: + doc_list[key] = doc_list[key] + query_params + break + elif doc.get("documentClass"): + doc_list = self._update_static_document(doc, doc_list) + return document_list + + def update_filing_documents(self, drs_docs: list, filing_docs: list, filing: Filing) -> list: # noqa: PLR0912 + """ + Get outputs and documents for a ledger filing, adding DRS information if available by mapping on the filing ID. + + drs_docs: The DRS reports/documents for the business identifier. + filing_docs: The filing list of reports/documents. + return: The updated list of filing reports and documents for the filing. + """ + doc_list = filing_docs.get("documents") if filing_docs else None + if not filing_docs or not doc_list: + return [] + if not drs_docs or not filing or filing.paper_only: + return doc_list + drs_filing_id: int = filing.id + # If DRS reports/documents exist add the DRS download info to the document URLs. + if filing and filing.source == filing.Source.COLIN.value: + meta_data = filing.meta_data + if meta_data and meta_data.get("colinFilingInfo") and meta_data["colinFilingInfo"].get("eventId"): + drs_filing_id = meta_data["colinFilingInfo"].get("eventId") + + for doc in drs_docs: + if doc.get("eventIdentifier", 0) == drs_filing_id: + if doc.get("reportType") and doc.get("reportType") == "RECEIPT" and doc_list.get("receipt"): + query_params: str = DRS_REPORT_PARAMS.format(report_type="RECEIPT", drs_id=doc.get("identifier")) + doc_list["receipt"] = doc_list["receipt"] + query_params + elif doc.get("reportType") and doc.get("reportType") == "NOA" and doc_list.get("noticeOfArticles"): + query_params: str = DRS_REPORT_PARAMS.format(report_type="NOA", drs_id=doc.get("identifier")) + doc_list["noticeOfArticles"] = doc_list["noticeOfArticles"] + query_params + elif doc.get("reportType") and doc.get("reportType") == "FILING" and doc_list.get("legalFilings"): + query_params: str = DRS_REPORT_PARAMS.format(report_type="FILING", drs_id=doc.get("identifier")) + legal_filing = doc_list["legalFilings"][0] + filing_key = next(iter(legal_filing.keys())) + legal_filing[filing_key] = legal_filing[filing_key] + query_params + elif doc.get("reportType") and doc.get("reportType") == "CERT": + query_params: str = DRS_REPORT_PARAMS.format(report_type="CERT", drs_id=doc.get("identifier")) + for key in doc_list: + if str(key).find("certificate") > -1: + doc_list[key] = doc_list[key] + query_params + break + elif doc.get("documentClass"): + doc_list = self._update_static_document(doc, doc_list) + return doc_list + + def get_filing_report(self, drs_id: str, report_type: str): + """ + Get a filing report document from the document service by unique DRS identifier. + + drs_id: The unique DRS identifier for the requested document. + report_type: The report type: request a certified copy for NOA and FILING report types. + return: The document binary data. + """ + headers = self._get_request_headers(BUSINESS_API_ACCOUNT_ID) + url: str = self.url.replace(DOC_PATH, "") + get_url = GET_REPORT_PATH + if report_type in (ReportTypes.FILING.value, ReportTypes.NOA.value): + get_url = GET_REPORT_CERTIFIED_PATH + get_url = get_url.format(url=url, product=self.product_code, drsId=drs_id) + response = requests.get(url=get_url, headers=headers) + if response.status_code not in (HTTPStatus.OK, HTTPStatus.NOT_FOUND): + current_app.logger.error(f"DRS call {get_url} failed status={response.status_code}: {response.content}") + return response + + def get_filing_document(self, drs_id: str, doc_class: str): + """ + Get a filing document from the document service by unique DRS identifier. + + drs_id: The unique DRS identifier for the requested document. + document_class: The DRS document class for the business to filter on. + return: The document binary data. + """ + headers = self._get_request_headers(BUSINESS_API_ACCOUNT_ID) + url: str = self.url.replace(DOC_PATH, "") + get_url = GET_DOCUMENT_PATH.format(url=url, document_class=doc_class, drs_id=drs_id) + response = requests.get(url=get_url, headers=headers) + if response.status_code not in (HTTPStatus.OK, HTTPStatus.NOT_FOUND): + current_app.logger.error(f"DRS call {get_url} failed status={response.status_code}: {response.content}") + return response + + def create_filing_report( + self, + business_identifier: str, + filing: Filing, + report_meta: dict, + report_response + ): + """ + Create a DRS application report record with a report service report. + + business_identifier: Required - associates the report with the business. + filing: Required - contains the filing ID and filing date. + report_type: Required - the DRS report type. + report_response: Required - contains the report binary data + return: The DRS API response. + """ + if not business_identifier or not filing or not report_meta or not report_meta.get("reportType"): + return report_response + headers = self._get_request_headers(BUSINESS_API_ACCOUNT_ID) + url: str = self.url.replace(DOC_PATH, "") + report_type: str = report_meta.get("reportType") + filename: str = report_meta.get("fileName") + ".pdf" + filing_date: str = filing.effective_date.isoformat()[:10] + post_url = POST_REPORT_PATH.format( + url=url, + product=self.product_code, + bus_id=business_identifier, + filing_id=filing.id, + report_type=report_type + ) + post_url += POST_REPORT_PARAMS.format(filing_date=filing_date, filename=filename) + response = requests.post(url=post_url, headers=headers, data=report_response.content) + if response.status_code not in (HTTPStatus.OK, HTTPStatus.CREATED): + current_app.logger.error(f"DRS call {post_url} failed status={response.status_code}: {response.content}") + return report_response + if report_type == ReportTypes.CERT.value: + return report_response + # Get the certified copy of the NOA and FILING report types. + response_json = json.loads(response.content) + if response_json and response_json.get("identifier"): + response2 = self.get_filing_report(response_json.get("identifier"), report_type) + if response2.status_code == HTTPStatus.OK: + return response2 + return report_response + + def _update_static_document(self, doc: dict, doc_list: list) -> list: + """ + Update static document urls in the document_list if a DRS match is found. + + docs: The DRS document information to match on. + doc_list: The business list of reports/documents for the filing. + return: The updated list of static documents for the filing. + """ + query_params: str = DRS_DOCUMENT_PARAMS.format( + document_class=doc.get("documentClass"), + drs_id=doc.get("identifier") + ) + for key in doc_list: + if key == "staticDocuments": + for static_doc in doc_list.get("staticDocuments"): + name: str = static_doc.get("name") + if (name and name == doc.get("name")) or ( + name and STATIC_DOCUMENTS.get(name) and + doc.get("documentClass") == STATIC_DOCUMENTS[name].get("documentClass") and + doc.get("documentType") == STATIC_DOCUMENTS[name].get("documentType") + ): + static_doc["url"] = static_doc["url"] + query_params + break + elif ( + FILING_DOCUMENTS.get(key) and + doc.get("documentClass") == FILING_DOCUMENTS[key].get("documentClass") and + doc.get("documentType") == FILING_DOCUMENTS[key].get("documentType") + ): + doc_list[key] = doc_list[key] + query_params + break + return doc_list + + + def _get_request_headers(self, account_id: str) -> dict: + """ + Get request headers for the DRS api call. + + account_id: The account use if not the default. + return: The request headers. + """ + token = AccountService.get_bearer_token() + headers = { + "x-apikey": self.api_key, + "Account-Id": account_id if account_id else BUSINESS_API_ACCOUNT_ID, + "Content-Type": APP_PDF, + "Authorization": BEARER + token + } + return headers diff --git a/legal-api/src/legal_api/reports/report.py b/legal-api/src/legal_api/reports/report.py index 6aa09098ab..9e1d8eafb9 100644 --- a/legal-api/src/legal_api/reports/report.py +++ b/legal-api/src/legal_api/reports/report.py @@ -36,7 +36,7 @@ PartyRole, ) from legal_api.models.business import ASSOCIATION_TYPE_DESC -from legal_api.reports.document_service import DocumentService +from legal_api.reports.document_service import DocumentService, ReportTypes from legal_api.reports.registrar_meta import RegistrarInfo from legal_api.services import VersionedBusinessDetailsService, flags from legal_api.utils.auth import jwt @@ -78,21 +78,20 @@ def _get_static_report(self): ) def _get_report(self): - if flags.is_on("enable-document-records"): - account_id = request.headers.get("Account-Id", None) - if account_id is not None and self._business is not None: - document, status = self._document_service.get_document( - self._business.identifier, - self._filing.id, - self._report_key, - account_id + account_id = request.headers.get("Account-Id", None) + if account_id is not None and self._business is not None: + document, status = self._document_service.get_document( + self._business.identifier, + self._filing.id, + self._report_key, + account_id + ) + if status == HTTPStatus.OK: + return current_app.response_class( + response=document, + status=status, + mimetype="application/pdf" ) - if status == HTTPStatus.OK: - return current_app.response_class( - response=document, - status=status, - mimetype="application/pdf" - ) if self._filing.business_id: self._business = Business.find_by_internal_id(self._filing.business_id) @@ -114,32 +113,15 @@ def _get_report(self): if response.status_code != HTTPStatus.OK: return jsonify(message=str(response.content)), response.status_code - if flags.is_on("enable-document-records"): - create_document = account_id is not None - create_filing_types = [ - "incorporationApplication", - "continuationIn", - "amalgamation", - "registration" - ] - if self._filing.filing_type in create_filing_types: - create_document = create_document and self._business and self._business.tax_id - else: - create_document = create_document and \ - self._filing.status in (Filing.Status.COMPLETED, Filing.Status.CORRECTED) - - if create_document: - self._document_service.create_document( - self._business.identifier, - self._filing.id, - self._report_key, - account_id, - response.content - ) - + response_drs = self._document_service.create_filing_report( + self._business.identifier, + self._filing, + ReportMeta.reports.get(self._report_key), + response + ) return current_app.response_class( - response=response.content, - status=response.status_code, + response=response_drs.content, + status=response_drs.status_code, mimetype="application/pdf" ) @@ -1291,6 +1273,10 @@ def _format_office_data(self, filing, prev_completed_filing: Filing): def _format_party_data(self, filing, prev_completed_filing: Filing): filing["parties"] = filing.get("correction").get("parties", []) + if relationships := filing.get("correction").get("relationships"): + # map relationships to parties for pdf templates + filing["parties"].extend([self._map_relationship_to_party(relationship) for relationship in relationships]) + if filing.get("parties"): self._format_directors(filing["parties"]) filing["partyChange"] = False @@ -1491,6 +1477,24 @@ def _get_environment(): return "TEST" return "" + @staticmethod + def _map_relationship_to_party(relationship): + # FUTURE: update pdf templates to expect relationships schema and remove this + organization_name = relationship["entity"].get("businessName") + return { + "officer": { + "id": relationship["entity"].get("identifier"), + "firstName": relationship["entity"].get("givenName"), + "middleName": relationship["entity"].get("middleInitial"), + "lastName": relationship["entity"].get("familyName"), + "organizationName": organization_name, + "partyType": "organization" if organization_name else "person" + }, + "deliveryAddress": relationship.get("deliveryAddress"), + "mailingAddress": relationship.get("mailingAddress"), + "roles": relationship.get("roles", []) + } + class ReportMeta: # pylint: disable=too-few-public-methods """Helper class to maintain the report meta information.""" @@ -1498,35 +1502,43 @@ class ReportMeta: # pylint: disable=too-few-public-methods reports = { "amalgamationApplication": { "filingDescription": "Amalgamation Application", - "fileName": "amalgamationApplication" + "fileName": "amalgamationApplication", + "reportType": ReportTypes.FILING.value }, "certificateOfAmalgamation": { "filingDescription": "Certificate Of Amalgamation", - "fileName": "certificateOfAmalgamation" + "fileName": "certificateOfAmalgamation", + "reportType": ReportTypes.CERT.value }, "certificateOfIncorporation": { "filingDescription": "Certificate of Incorporation", - "fileName": "certificateOfIncorporation" + "fileName": "certificateOfIncorporation", + "reportType": ReportTypes.CERT.value }, "incorporationApplication": { "filingDescription": "Incorporation Application", - "fileName": "incorporationApplication" + "fileName": "incorporationApplication", + "reportType": ReportTypes.FILING.value }, "noticeOfArticles": { "filingDescription": "Notice of Articles", - "fileName": "noticeOfArticles" + "fileName": "noticeOfArticles", + "reportType": ReportTypes.NOA.value }, "alterationNotice": { "filingDescription": "Alteration Notice", - "fileName": "alterationNotice" + "fileName": "alterationNotice", + "reportType": ReportTypes.FILING.value }, "transition": { "filingDescription": "Transition Application", - "fileName": "transitionApplication" + "fileName": "transitionApplication", + "reportType": ReportTypes.FILING.value }, "changeOfAddress": { "hasDifferentTemplates": True, "filingDescription": "Change of Address", + "reportType": ReportTypes.FILING.value, "default": { "fileName": "bcAddressChange" }, @@ -1537,6 +1549,7 @@ class ReportMeta: # pylint: disable=too-few-public-methods "changeOfDirectors": { "hasDifferentTemplates": True, "filingDescription": "Change of Directors", + "reportType": ReportTypes.FILING.value, "default": { "fileName": "bcDirectorChange" }, @@ -1547,6 +1560,7 @@ class ReportMeta: # pylint: disable=too-few-public-methods "annualReport": { "hasDifferentTemplates": True, "filingDescription": "Annual Report", + "reportType": ReportTypes.FILING.value, "default": { "fileName": "bcAnnualReport" }, @@ -1556,55 +1570,68 @@ class ReportMeta: # pylint: disable=too-few-public-methods }, "changeOfName": { "filingDescription": "Change of Name", - "fileName": "changeOfName" + "fileName": "changeOfName", + "reportType": ReportTypes.FILING.value }, "specialResolution": { "filingDescription": "Special Resolution", - "fileName": "specialResolution" + "fileName": "specialResolution", + "reportType": ReportTypes.FILING.value }, "specialResolutionApplication": { "filingDescription": "Special Resolution Application", - "fileName": "specialResolutionApplication" + "fileName": "specialResolutionApplication", + "reportType": ReportTypes.FILING.value }, "voluntaryDissolution": { "filingDescription": "Voluntary Dissolution", - "fileName": "voluntaryDissolution" + "fileName": "voluntaryDissolution", + "reportType": ReportTypes.FILING.value }, "certificateOfNameChange": { "filingDescription": "Certificate of Name Change", - "fileName": "certificateOfNameChange" + "fileName": "certificateOfNameChange", + "reportType": ReportTypes.CERT.value }, "certificateOfNameCorrection": { "filingDescription": "Certificate of Name Correction", - "fileName": "certificateOfNameChange" + "fileName": "certificateOfNameChange", + "reportType": ReportTypes.CERT.value }, "certificateOfDissolution": { "filingDescription": "Certificate of Dissolution", - "fileName": "certificateOfDissolution" + "fileName": "certificateOfDissolution", + "reportType": ReportTypes.CERT.value }, "dissolution": { "filingDescription": "Dissolution Application", - "fileName": "dissolution" + "fileName": "dissolution", + "reportType": ReportTypes.FILING.value }, "registration": { "filingDescription": "Statement of Registration", - "fileName": "registration" + "fileName": "registration", + "reportType": ReportTypes.FILING.value }, "amendedRegistrationStatement": { "filingDescription": "Amended Registration Statement", - "fileName": "amendedRegistrationStatement" + "fileName": "amendedRegistrationStatement", + "reportType": ReportTypes.FILING.value }, "correctedRegistrationStatement": { "filingDescription": "Corrected Registration Statement", - "fileName": "amendedRegistrationStatement" + "fileName": "amendedRegistrationStatement", + "reportType": ReportTypes.FILING.value }, "changeOfRegistration": { "filingDescription": "Change of Registration", - "fileName": "changeOfRegistration" + "fileName": "changeOfRegistration", + "reportType": ReportTypes.FILING.value }, "correction": { "hasDifferentTemplates": True, "filingDescription": "Correction", + "reportType": ReportTypes.FILING.value, "default": { "fileName": "correction" }, @@ -1617,31 +1644,38 @@ class ReportMeta: # pylint: disable=too-few-public-methods }, "certificateOfRestoration": { "filingDescription": "Certificate of Restoration", - "fileName": "certificateOfRestoration" + "fileName": "certificateOfRestoration", + "reportType": ReportTypes.FILING.value }, "restoration": { "filingDescription": "Restoration Application", - "fileName": "restoration" + "fileName": "restoration", + "reportType": ReportTypes.FILING.value }, "letterOfConsent": { "filingDescription": "Letter Of Consent", - "fileName": "letterOfConsent" + "fileName": "letterOfConsent", + "reportType": ReportTypes.FILING.value }, "letterOfConsentAmalgamationOut": { "filingDescription": "Letter Of Consent", - "fileName": "letterOfConsentAmalgamationOut" + "fileName": "letterOfConsentAmalgamationOut", + "reportType": ReportTypes.FILING.value }, "letterOfAgmExtension": { "filingDescription": "Letter Of AGM Extension", - "fileName": "letterOfAgmExtension" + "fileName": "letterOfAgmExtension", + "reportType": ReportTypes.FILING.value }, "letterOfAgmLocationChange": { "filingDescription": "Letter Of AGM Location Change", - "fileName": "letterOfAgmLocationChange" + "fileName": "letterOfAgmLocationChange", + "reportType": ReportTypes.FILING.value }, "continuationIn": { "filingDescription": "Continuation Application", - "fileName": "continuationApplication" + "fileName": "continuationApplication", + "reportType": ReportTypes.FILING.value }, "certificateOfContinuation": { "filingDescription": "Certificate of Continuation", @@ -1649,15 +1683,18 @@ class ReportMeta: # pylint: disable=too-few-public-methods }, "noticeOfWithdrawal": { "filingDescription": "Notice of Withdrawal", - "fileName": "noticeOfWithdrawal" + "fileName": "noticeOfWithdrawal", + "reportType": ReportTypes.FILING.value }, "appointReceiver": { "filingDescription": "Appoint Receiver", - "fileName": "appointReceiver" + "fileName": "appointReceiver", + "reportType": ReportTypes.FILING.value }, "ceaseReceiver": { "filingDescription": "Cease Receiver", - "fileName": "ceaseReceiver" + "fileName": "ceaseReceiver", + "reportType": ReportTypes.FILING.value } } 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 e89306619d..8ba369352e 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 @@ -27,6 +27,7 @@ from legal_api.models import Business, Document from legal_api.models import Filing as FilingModel from legal_api.reports import get_pdf +from legal_api.reports.document_service import DocumentService from legal_api.resources.v2.business.bp import bp from legal_api.services import MinioService, authorized from legal_api.utils.auth import jwt @@ -37,6 +38,12 @@ DOCUMENTS_BASE_ROUTE: Final = "//filings//documents" +PARAM_REPORT_TYPE: str = "reportType" +PARAM_DOC_CLASS = "documentClass" +PARAM_DRS_ID = "drsId" +APP_PDF = "application/pdf" +CONTENT_JSON = {"Content-Type": "application/json"} +CONTENT_PDF = {"Content-Type": APP_PDF} @cors_preflight("GET, POST") @@ -55,7 +62,6 @@ def get_documents(identifier: str, # noqa: PLR0911, PLR0912 return jsonify( message=get_error_message(ErrorCode.NOT_AUTHORIZED, identifier=identifier) ), HTTPStatus.UNAUTHORIZED - if identifier.startswith("T"): filing_model = FilingModel.get_temp_reg_filing(identifier) business = Business.find_by_internal_id(filing_model.business_id) @@ -87,7 +93,7 @@ def get_documents(identifier: str, # noqa: PLR0911, PLR0912 return {"documents": {}}, HTTPStatus.OK return _get_document_list(business, filing) - if "application/pdf" in request.accept_mimetypes: + if APP_PDF in request.accept_mimetypes: file_name = (legal_filing_name or file_key) if not _is_document_available(business, filing, file_name): return jsonify( @@ -95,6 +101,9 @@ def get_documents(identifier: str, # noqa: PLR0911, PLR0912 file_name=file_name, filing_id=filing_id, identifier=identifier) ), HTTPStatus.NOT_FOUND + if drs_params := _get_drs_params(): + return _get_drs_documents(drs_params) + if legal_filing_name: if legal_filing_name.lower().startswith("receipt"): return _get_receipt(business, filing, jwt.get_token_auth_header()) @@ -106,12 +115,38 @@ def get_documents(identifier: str, # noqa: PLR0911, PLR0912 return current_app.response_class( response=response.data, status=response.status, - mimetype="application/pdf" + mimetype=APP_PDF ) return {}, HTTPStatus.NOT_FOUND +def _get_drs_params() -> dict: + """Extract DRS parameters from the request.""" + params: dict = {} + if request.args.get(PARAM_REPORT_TYPE): + params["reportType"] = request.args.get(PARAM_REPORT_TYPE) + if request.args.get(PARAM_DRS_ID): + params["drsId"] = request.args.get(PARAM_DRS_ID) + if request.args.get(PARAM_DOC_CLASS): + params["documentClass"] = request.args.get(PARAM_DOC_CLASS) + return params + + +def _get_drs_documents(drs_params: dict): + """Return an indvidual DRS document as binary data, or a DRS JSON error.""" + doc_service: DocumentService = DocumentService() + drs_id: str = drs_params.get(PARAM_DRS_ID) + response = None + if drs_params.get(PARAM_REPORT_TYPE): + response = doc_service.get_filing_report(drs_id, drs_params.get(PARAM_REPORT_TYPE)) + else: + response = doc_service.get_filing_document(drs_id, drs_params.get(PARAM_DOC_CLASS)) + + content_type: str = CONTENT_PDF if response.status_code == HTTPStatus.OK else CONTENT_JSON + return response.content, response.status_code, content_type + + def _is_document_available(business, filing, file_name): """Check if the document is available.""" document_list = Filing.get_document_list(business, filing, jwt) @@ -128,11 +163,23 @@ def _is_document_available(business, filing, file_name): return file_name in documents -def _get_document_list(business, filing): +def _get_document_list(business: Business, filing: Filing): """Get list of document outputs.""" - if not (document_list := Filing.get_document_list(business, filing, jwt)): + document_list = Filing.get_document_list(business, filing, jwt) + if not (document_list): return {}, HTTPStatus.NOT_FOUND - + storage: FilingModel = filing.storage + # If DRS reports/documents exist add the DRS download info to the document URLs. + if storage and not storage.paper_only: + drs_filing_id: int = storage.id + if storage.source and storage.source == storage.Source.COLIN.value and storage.meta_data: + meta_data = storage.meta_data + if meta_data and meta_data.get("colinFilingInfo") and meta_data["colinFilingInfo"].get("eventId"): + drs_filing_id = meta_data["colinFilingInfo"].get("eventId") + identifier = business.identifier if business else storage.temp_reg + doc_service: DocumentService = DocumentService() + drs_docs: list = doc_service.get_documents_by_filing_id(identifier, drs_filing_id) + document_list = doc_service.update_document_list(drs_docs, document_list) return jsonify(document_list), HTTPStatus.OK diff --git a/legal-api/tests/conftest.py b/legal-api/tests/conftest.py index 841884e684..d13c6185bb 100644 --- a/legal-api/tests/conftest.py +++ b/legal-api/tests/conftest.py @@ -313,7 +313,7 @@ def _mock_get_side_effect(request, context): DOCUMENT_API_URL = 'http://document-api.com' DOCUMENT_API_VERSION = '/api/v1' -DOCUMENT_SVC_URL = f'{DOCUMENT_API_URL + DOCUMENT_API_VERSION}/documents' +DOCUMENT_SVC_URL = f'{DOCUMENT_API_URL + DOCUMENT_API_VERSION}' DOCUMENT_PRODUCT_CODE = 'BUSINESS' @pytest.fixture() @@ -331,4 +331,21 @@ def mock_doc_service(): mock.get(re.compile(f"{get_url}.*"), status_code=HTTPStatus.OK, text=json.dumps(mock_response)) + get_url2 = f'{DOCUMENT_SVC_URL}/application-reports/history/{DOCUMENT_PRODUCT_CODE}/' + mock.get(re.compile(f"{get_url2}.*"), + status_code=HTTPStatus.OK, + text=json.dumps(mock_response)) yield mock + + +@pytest.fixture() +def mock_drs_service(): + mock_response = [] + with requests_mock.Mocker(real_http=True) as m: + get_url = f'{DOCUMENT_SVC_URL}/application-reports/{DOCUMENT_PRODUCT_CODE}/' + get_url2 = f'{DOCUMENT_SVC_URL}/application-reports/history/{DOCUMENT_PRODUCT_CODE}/' + get_url3 = f'{DOCUMENT_SVC_URL}/application-reports/events/{DOCUMENT_PRODUCT_CODE}/' + m.register_uri('GET', re.compile(f"{get_url}.*"), json=mock_response, status_code=HTTPStatus.OK) + m.register_uri('GET', re.compile(f"{get_url2}.*"), json=mock_response, status_code=HTTPStatus.OK) + m.register_uri('GET', re.compile(f"{get_url3}.*"), json=mock_response, status_code=HTTPStatus.OK) + yield m diff --git a/legal-api/tests/unit/core/test_filing_ledger.py b/legal-api/tests/unit/core/test_filing_ledger.py index 06cdebb81a..1a7cb29582 100644 --- a/legal-api/tests/unit/core/test_filing_ledger.py +++ b/legal-api/tests/unit/core/test_filing_ledger.py @@ -17,14 +17,16 @@ import datedelta import pytest +from flask import current_app from registry_schemas.example_data import FILING_TEMPLATE from legal_api.core import Filing as CoreFiling from legal_api.models import Business, Comment, Filing, UserRoles from legal_api.models.user import UserRoles +from legal_api.services.authz import STAFF_ROLE from legal_api.utils.datetime import datetime from tests.unit.models import factory_business, factory_completed_filing, factory_user -from tests.unit.services.utils import helper_create_jwt +from tests.unit.services.utils import helper_create_jwt, create_header def load_ledger(business, founding_date): @@ -65,16 +67,23 @@ def load_ledger(business, founding_date): return i -def test_simple_ledger_search(session): +def test_simple_ledger_search(app, session, client, jwt, monkeypatch, mock_drs_service, mocker): """Assert that the ledger returns values for all the expected keys.""" # setup identifier = 'BC1234567' founding_date = datetime.utcnow() - datedelta.datedelta(months=len(Filing.FILINGS.keys())) business = factory_business(identifier=identifier, founding_date=founding_date, last_ar_date=None, entity_type=Business.LegalTypes.BCOMP.value) num_of_files = load_ledger(business, founding_date) + token = helper_create_jwt(jwt, roles=[STAFF_ROLE], username='testuser') + headers = {'Authorization': 'Bearer ' + token, 'Account-Id': 1} - # test - ledger = CoreFiling.ledger(business.id) + def mock_auth(one, two): # pylint: disable=unused-argument; mocks of library methods + return headers[one] + + # test + with app.test_request_context(): + monkeypatch.setattr('flask.request.headers.get', mock_auth) + ledger = CoreFiling.ledger(business.id, jwt) # Did we get the full set assert len(ledger) == num_of_files @@ -83,7 +92,7 @@ def test_simple_ledger_search(session): alteration = next((f for f in ledger if f.get('name') == 'alteration'), None) assert alteration - assert 18 == len(alteration.keys()) + assert 18 <= len(alteration.keys()) assert 'availableOnPaperOnly' in alteration assert 'effectiveDate' in alteration assert 'filingId' in alteration @@ -100,7 +109,7 @@ def test_simple_ledger_search(session): # assert alteration['filingLink'] -def test_common_ledger_items(session): +def test_common_ledger_items(session,): """Assert that common ledger items works as expected.""" identifier = 'BC1234567' founding_date = datetime.utcnow() - datedelta.datedelta(months=len(Filing.FILINGS.keys())) diff --git a/legal-api/tests/unit/reports/test_document_service.py b/legal-api/tests/unit/reports/test_document_service.py index c8f982134a..7038a78e3f 100644 --- a/legal-api/tests/unit/reports/test_document_service.py +++ b/legal-api/tests/unit/reports/test_document_service.py @@ -17,12 +17,300 @@ from datetime import datetime from http import HTTPStatus import datedelta +import json +import pytest + +from legal_api.models import Filing from legal_api.reports.document_service import DocumentService from tests.unit.models import factory_business, factory_completed_filing from registry_schemas.example_data import FILING_TEMPLATE +META_COLIN = { + "colinFilingInfo": { + "eventId": 7678798, + "eventType": "FILE", + "filingType": "NOCDR" + } +} +META_MODERN = {} +DOCS_MODERN = { + "documents": { + "certificateOfIncorporation": "https://test.com/BC0888490/filings/2405954/documents/certificateOfIncorporation", + "legalFilings": [ + {"incorporationApplication": "https://test.com/BC0888490/filings/2405954/documents/incorporationApplication"} + ], + "noticeOfArticles": "https://test.com/BC0888490/filings/2405954/documents/noticeOfArticles", + "receipt": "https://test.com/BC0888490/filings/2405954/documents/receipt" + } +} +DOCS_COLIN = { + "documents": { + "certificateOfIncorporation": "https://test.com/BC0791952/filings/515091/documents/certificateOfIncorporation", + "legalFilings": [ + {"incorporationApplication": "https://test.com/BC0791952/filings/515091/documents/incorporationApplication"} + ], + "noticeOfArticles": "https://test.com/BC0791952/filings/515091/documents/noticeOfArticles", + "receipt": "https://test.com/BC0791952/filings/515091/documents/receipt" + } +} +DOCS_STATIC1 = { + "documents": { + "certificateOfIncorporation": "https://test.com/CP1044798/filings/233791/documents/certificateOfIncorporation", + "certifiedMemorandum": "https://test.com/CP1044798/filings/233791/documents/certifiedMemorandum", + "certifiedRules": "https://test.com/CP1044798/filings/233791/documents/certifiedRules", + "legalFilings": [ + {"incorporationApplication": "https://test.com/CP1044798/filings/233791/documents/incorporationApplication"} + ], + "receipt": "https://test.com/CP1044798/filings/233791/documents/receipt" + } +} +DOCS_STATIC2 = { + "documents": { + "certificateOfContinuation": "https://test.com/C9900863/filings/155753/documents/certificateOfContinuation", + "legalFilings": [ + {"continuationIn": "https://test.com/C9900863/filings/155753/documents/continuationIn"} + ], + "noticeOfArticles": "https://test.com/C9900863/filings/155753/documents/noticeOfArticles", + "receipt": "https://test.com/C9900863/filings/155753/documents/receipt", + "staticDocuments": [ + { + "name": "Unlimited Liability Corporation Information", + "url": "https://test.com/C9900863/filings/155753/documents/static/DS0000100741" + }, + { + "name": "20250107-Authorization1.pdf", + "url": "https://test.com/C9900863/filings/155753/documents/static/DS0000100740" + } + ] + } +} +DRS_NONE = [] +DRS_MODERN = [ + { + "dateCreated": "2026-03-11T15:45:51+00:00", + "datePublished": "2026-03-03T20:00:00+00:00", + "entityIdentifier": "BC0888490", + "eventIdentifier": 2405954, + "identifier": "DSR0000100951", + "name": "certificateOfIncorporation.pdf", + "productCode": "BUSINESS", + "reportType": "CERT", + "url": "" + }, + { + "dateCreated": "2026-03-11T15:53:19+00:00", + "datePublished": "2026-03-03T20:00:00+00:00", + "entityIdentifier": "BC0888490", + "eventIdentifier": 2405954, + "identifier": "DSR0000100952", + "name": "noticeOfArticles.pdf", + "productCode": "BUSINESS", + "reportType": "NOA", + "url": "" + }, + { + "dateCreated": "2026-03-11T16:09:51+00:00", + "datePublished": "2026-03-03T20:00:00+00:00", + "entityIdentifier": "BC0888490", + "eventIdentifier": 2405954, + "identifier": "DSR0000100954", + "name": "incorporationApplication.pdf", + "productCode": "BUSINESS", + "reportType": "FILING", + "url": "" + } +] +DRS_COLIN = [ + { + "dateCreated": "2026-02-24T23:15:35+00:00", + "datePublished": "2007-05-23T18:40:59+00:00", + "entityIdentifier": "BC0791952", + "eventIdentifier": 7678798, + "identifier": "DSR0000100896", + "name": "BC0791952-ICORP-RECEIPT.pdf", + "productCode": "BUSINESS", + "reportType": "RECEIPT", + "url": "" + }, + { + "dateCreated": "2026-02-24T23:15:37+00:00", + "datePublished": "2007-05-23T18:40:59+00:00", + "entityIdentifier": "BC0791952", + "eventIdentifier": 7678798, + "identifier": "DSR0000100897", + "name": "BC0791952-ICORP-FILING.pdf", + "productCode": "BUSINESS", + "reportType": "FILING", + "url": "" + }, + { + "dateCreated": "2026-02-24T23:15:41+00:00", + "datePublished": "2007-05-23T18:40:59+00:00", + "entityIdentifier": "BC0791952", + "eventIdentifier": 7678798, + "identifier": "DSR0000100898", + "name": "BC0791952-ICORP-NOA.pdf", + "productCode": "BUSINESS", + "reportType": "NOA", + "url": "" + }, + { + "dateCreated": "2026-02-24T23:15:45+00:00", + "datePublished": "2007-05-23T18:40:59+00:00", + "entityIdentifier": "BC0791952", + "eventIdentifier": 7678798, + "identifier": "DSR0000100899", + "name": "BC0791952-ICORP-CERT.pdf", + "productCode": "BUSINESS", + "reportType": "CERT", + "url": "" + } +] +DRS_STATIC1 = [ + { + "consumerDocumentId": "0100000525", + "dateCreated": "2026-03-11T19:19:32+00:00", + "datePublished": "2026-01-22T00:00:00+00:00", + "documentClass": "COOP", + "documentType": "COOP_MEMORANDUM", + "documentTypeDescription": "Cooperative Memorandum", + "entityIdentifier": "CP1044798", + "eventIdentifier": 233791, + "identifier": "DS0000101630", + "name": "", + "url": "" + }, + { + "consumerDocumentId": "0100000526", + "dateCreated": "2026-03-11T19:19:37+00:00", + "datePublished": "2026-01-22T00:00:00+00:00", + "documentClass": "COOP", + "documentType": "COOP_RULES", + "documentTypeDescription": "Cooperative Rules", + "entityIdentifier": "CP1044798", + "eventIdentifier": 233791, + "identifier": "DS0000101631", + "name": "", + "url": "" + } +] +DRS_STATIC2 = [ + { + "consumerDocumentId": "0100000193", + "dateCreated": "2025-01-07T16:11:59+00:00", + "datePublished": "2025-01-07T20:00:00+00:00", + "documentClass": "CORP", + "documentType": "CNTA", + "documentTypeDescription": "Continuation in Authorization", + "entityIdentifier": "C9900863", + "eventIdentifier": 155753, + "identifier": "DS0000100740", + "name": "20250107-Authorization1.pdf", + "url": "" + }, + { + "consumerDocumentId": "0100000193", + "dateCreated": "2025-01-07T16:12:05+00:00", + "datePublished": "2025-01-07T20:00:00+00:00", + "documentClass": "CORP", + "documentType": "DIRECTOR_AFFIDAVIT", + "documentTypeDescription": "Director Affidavit", + "entityIdentifier": "C9900863", + "eventIdentifier": 155753, + "identifier": "DS0000100741", + "name": "20250107-Affidavit.pdf", + "url": "" + } +] + +# testdata pattern is ({description}, {doc_data}, {drs_data}, {receipt}, {filing}, {noa}, {cert}, {static}) +TEST_FILING_UPDATE_DATA = [ + ("No docs", DOCS_MODERN, DRS_NONE, None, None, None, None, None), + ("Modern docs", DOCS_MODERN, DRS_MODERN, None, "reportType=FILING&drsId=DSR0000100954", "reportType=NOA&drsId=DSR0000100952", "reportType=CERT&drsId=DSR0000100951", None), + ("Colin docs", DOCS_COLIN, DRS_COLIN, "reportType=RECEIPT&drsId=DSR0000100896", "reportType=FILING&drsId=DSR0000100897", "reportType=NOA&drsId=DSR0000100898", "reportType=CERT&drsId=DSR0000100899", None), + ("Static 1", DOCS_STATIC1, DRS_STATIC1, None, None, None, None, "documentClass=COOP&drsId=DS0000101630"), + ("Static 2", DOCS_STATIC2, DRS_STATIC2, None, None, None, None, "documentClass=CORP&drsId=DS0000100741"), +] +# testdata pattern is ({description}, {doc_data}, {drs_data}, {receipt}, {filing}, {noa}, {cert}, {static}, {meta}, {filing_id}) +TEST_BUSINESS_UPDATE_DATA = [ + ("No docs", DOCS_MODERN, DRS_NONE, None, None, None, None, None, META_MODERN, 2405954), + ("Modern docs", DOCS_MODERN, DRS_MODERN, None, "reportType=FILING&drsId=DSR0000100954", "reportType=NOA&drsId=DSR0000100952", "reportType=CERT&drsId=DSR0000100951", None, META_MODERN, 2405954), + ("Colin docs", DOCS_COLIN, DRS_COLIN, "reportType=RECEIPT&drsId=DSR0000100896", "reportType=FILING&drsId=DSR0000100897", "reportType=NOA&drsId=DSR0000100898", "reportType=CERT&drsId=DSR0000100899", None, META_COLIN, 0), + ("Static 1", DOCS_STATIC1, DRS_STATIC1, None, None, None, None, "documentClass=COOP&drsId=DS0000101630", META_MODERN, 233791), + ("Static 2", DOCS_STATIC2, DRS_STATIC2, None, None, None, None, "documentClass=CORP&drsId=DS0000100741", META_MODERN, 155753), +] + + +@pytest.mark.parametrize("desc,doc_data,drs_data,receipt,filing,noa,cert,static", TEST_FILING_UPDATE_DATA) +def test_update_filing_docs(session, desc, doc_data, drs_data, receipt, filing, noa, cert,static): + """Assert that updating filing output url's with DRS info works as expected.""" + doc_service: DocumentService = DocumentService() + filing_docs = copy.deepcopy(doc_data) + results = doc_service.update_document_list(drs_data, filing_docs) + assert results + text_results: str = json.dumps(results) + if not receipt: + assert text_results.find("reportType=RECEIPT") < 1 + else: + assert text_results.find(receipt) > 0 + if not filing: + assert text_results.find("reportType=FILING") < 1 + else: + assert text_results.find(filing) > 0 + if not noa: + assert text_results.find("reportType=NOA") < 1 + else: + assert text_results.find(noa) > 0 + if not cert: + assert text_results.find("reportType=CERT") < 1 + else: + assert text_results.find(cert) > 0 + if not static: + assert text_results.find("documentClass=") < 1 + else: + assert text_results.find(static) > 0 + + +@pytest.mark.parametrize("desc,doc_data,drs_data,receipt,filing,noa,cert,static,meta,filing_id", TEST_BUSINESS_UPDATE_DATA) +def test_update_ledger_docs(session, desc, doc_data, drs_data, receipt, filing, noa, cert,static, meta, filing_id): + """Assert that updating business ledger filing output url's with DRS info works as expected.""" + doc_service: DocumentService = DocumentService() + filing_docs = copy.deepcopy(doc_data) + filing1: Filing = Filing() + filing1.id = filing_id + filing1._meta_data = meta # pylint: disable=protected-access + filing1.paper_only = False + if filing_id == 0: + filing1.source = filing1.Source.COLIN.value + else: + filing1.source = filing1.Source.LEAR.value + results = doc_service.update_filing_documents(drs_data, filing_docs, filing1) + assert results + text_results: str = json.dumps(results) + if not receipt: + assert text_results.find("reportType=RECEIPT") < 1 + else: + assert text_results.find(receipt) > 0 + if not filing: + assert text_results.find("reportType=FILING") < 1 + else: + assert text_results.find(filing) > 0 + if not noa: + assert text_results.find("reportType=NOA") < 1 + else: + assert text_results.find(noa) > 0 + if not cert: + assert text_results.find("reportType=CERT") < 1 + else: + assert text_results.find(cert) > 0 + if not static: + assert text_results.find("documentClass=") < 1 + else: + assert text_results.find(static) > 0 + + def test_create_document(session, mock_doc_service, mocker): mocker.patch('legal_api.services.AccountService.get_bearer_token', return_value='') founding_date = datetime.utcnow() 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 8b002f28ba..73905583a7 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 @@ -21,6 +21,7 @@ import re from datetime import datetime from http import HTTPStatus +import requests_mock import pytest from flask import current_app @@ -1464,7 +1465,7 @@ def test_unpaid_filing(session, client, jwt): HTTPStatus.OK, '2024-09-26' ) ]) -def test_document_list_for_various_filing_states(session, mocker, client, jwt, +def test_document_list_for_various_filing_states(app, session, mocker, client, jwt, monkeypatch, mock_drs_service, test_name, identifier, entity_type, @@ -1516,9 +1517,21 @@ def test_document_list_for_various_filing_states(session, mocker, client, jwt, '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)) + account_id: str = '1' + headers=create_header(jwt, [STAFF_ROLE], identifier, account_id=account_id) + def mock_auth(one, two): # pylint: disable=unused-argument; mocks of library methods + return headers[one] + + # test + with app.test_request_context(): + monkeypatch.setattr('flask.request.headers.get', mock_auth) + account_products_mock = [] + with requests_mock.Mocker() as m: + mock_url = f"{app.config['AUTH_SVC_URL']}/orgs/{account_id}/products?include_hidden=true" + m.get(mock_url, json=account_products_mock, status_code=HTTPStatus.OK) + rv = client.get(f'/api/v2/businesses/{business.identifier}/filings/{filing.id}/documents', + headers=headers) + m.reset_mock() # remove the filing ID rv_data = json.loads(re.sub("/\d+/", "/", rv.data.decode("utf-8")).replace("\n", "")) @@ -1625,7 +1638,7 @@ def filer_action(filing_name, filing_json, meta_data, business): {'documents': {}}, HTTPStatus.OK ), ]) -def test_temp_document_list_for_various_filing_states(mocker, session, client, jwt, +def test_temp_document_list_for_various_filing_states(app, mocker, session, client, jwt, monkeypatch, mock_drs_service, test_name, temp_identifier, identifier, @@ -1656,10 +1669,21 @@ def test_temp_document_list_for_various_filing_states(mocker, session, client, j filing._payment_completion_date = '2017-10-01' 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)) + account_id: str = '1' + headers=create_header(jwt, [STAFF_ROLE], temp_identifier, account_id=account_id) + def mock_auth(one, two): # pylint: disable=unused-argument; mocks of library methods + return headers[one] + + # test + with app.test_request_context(): + monkeypatch.setattr('flask.request.headers.get', mock_auth) + account_products_mock = [] + with requests_mock.Mocker() as m: + mock_url = f"{app.config['AUTH_SVC_URL']}/orgs/{account_id}/products?include_hidden=true" + m.get(mock_url, json=account_products_mock, status_code=HTTPStatus.OK) + rv = client.get(f'/api/v2/businesses/{temp_identifier}/filings/{filing.id}/documents', + headers=headers) + m.reset_mock() # remove the filing ID rv_data = json.loads(re.sub("/\d+/", "/", rv.data.decode("utf-8")).replace("\n", "")) @@ -1795,7 +1819,7 @@ def test_get_receipt_no_receipt_ca(session, client, jwt, requests_mock): HTTPStatus.OK ) ]) -def test_temp_document_list_for_now(mocker, session, client, jwt, +def test_temp_document_list_for_now(app, mocker, session, client, jwt, monkeypatch, mock_drs_service, test_name, temp_identifier, entity_type, @@ -1830,10 +1854,20 @@ def test_temp_document_list_for_now(mocker, session, client, jwt, filing.temp_reg = None filing.withdrawn_filing_id = withdrawn_filing.id 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)) + account_id: str = '1' + headers=create_header(jwt, [STAFF_ROLE], temp_identifier, account_id=account_id) + def mock_auth(one, two): # pylint: disable=unused-argument; mocks of library methods + return headers[one] + + # test + with app.test_request_context(): + monkeypatch.setattr('flask.request.headers.get', mock_auth) + account_products_mock = [] + with requests_mock.Mocker() as m: + mock_url = f"{app.config['AUTH_SVC_URL']}/orgs/{account_id}/products?include_hidden=true" + m.get(mock_url, json=account_products_mock, status_code=HTTPStatus.OK) + rv = client.get(f'/api/v2/businesses/{temp_identifier}/filings/{filing.id}/documents', headers=headers) + m.reset_mock() # remove the filing ID rv_data = json.loads(re.sub("/\d+/", "/", rv.data.decode("utf-8")).replace("\n", "")) diff --git a/legal-api/tests/unit/resources/v2/test_business_filings/test_filings_ledger.py b/legal-api/tests/unit/resources/v2/test_business_filings/test_filings_ledger.py index 27e5a8eb56..a5481fef7d 100644 --- a/legal-api/tests/unit/resources/v2/test_business_filings/test_filings_ledger.py +++ b/legal-api/tests/unit/resources/v2/test_business_filings/test_filings_ledger.py @@ -59,7 +59,7 @@ from tests.unit.services.utils import create_header REGISTER_CORRECTION_APPLICATION = 'Register Correction Application' -def test_get_all_business_filings_only_one_in_ledger(session, client, jwt): +def test_get_all_business_filings_only_one_in_ledger(app, session, client, jwt, monkeypatch, mock_drs_service, mocker): """Assert that the business info can be received in a valid JSONSchema format.""" import copy identifier = 'CP7654321' @@ -71,15 +71,21 @@ def test_get_all_business_filings_only_one_in_ledger(session, client, jwt): ar['filing']['header']['colinIds'] = [] print('test_get_all_business_filings - filing:', filings) + headers=create_header(jwt, [STAFF_ROLE], identifier) + def mock_auth(one, two): # pylint: disable=unused-argument; mocks of library methods + return headers[one] - rv = client.get(f'/api/v2/businesses/{identifier}/filings', - headers=create_header(jwt, [STAFF_ROLE], identifier)) + # test + with app.test_request_context(): + monkeypatch.setattr('flask.request.headers.get', mock_auth) + rv = client.get(f'/api/v2/businesses/{identifier}/filings', + headers=headers) assert rv.status_code == HTTPStatus.OK assert len(rv.json.get('filings')) == 0 # The endpoint will return only completed filings -def test_get_all_business_filings_multi_in_ledger(session, client, jwt): +def test_get_all_business_filings_multi_in_ledger(app, session, client, jwt, monkeypatch, mock_drs_service, mocker): """Assert that the business info can be received in a valid JSONSchema format.""" import copy from tests import add_years @@ -95,25 +101,36 @@ def test_get_all_business_filings_multi_in_ledger(session, client, jwt): ar['filing']['annualReport']['annualGeneralMeetingDate'] = \ datetime.date(add_years(datetime(2001, 8, 5, 7, 7, 58, 272362), i)).isoformat() factory_filing(b, ar) + headers=create_header(jwt, [STAFF_ROLE], identifier) + def mock_auth(one, two): # pylint: disable=unused-argument; mocks of library methods + return headers[one] - rv = client.get(f'/api/v2/businesses/{identifier}/filings', - headers=create_header(jwt, [STAFF_ROLE], identifier)) + # test + with app.test_request_context(): + monkeypatch.setattr('flask.request.headers.get', mock_auth) + rv = client.get(f'/api/v2/businesses/{identifier}/filings', + headers=headers) assert rv.status_code == HTTPStatus.OK assert len(rv.json.get('filings')) == 0 -def test_ledger_search(session, client, jwt): +def test_ledger_search(app, session, client, jwt, monkeypatch, mock_drs_service, mocker): """Assert that the ledger returns values for all the expected keys.""" # setup identifier = 'BC1234567' founding_date = datetime.utcnow() - datedelta.datedelta(months=len(FILINGS.keys())) business = factory_business(identifier=identifier, founding_date=founding_date, last_ar_date=None, entity_type=Business.LegalTypes.BCOMP.value) num_of_files = load_ledger(business, founding_date) + headers=create_header(jwt, [UserRoles.system], identifier) + def mock_auth(one, two): # pylint: disable=unused-argument; mocks of library methods + return headers[one] # test - rv = client.get(f'/api/v2/businesses/{identifier}/filings', - headers=create_header(jwt, [UserRoles.system], identifier)) + with app.test_request_context(): + monkeypatch.setattr('flask.request.headers.get', mock_auth) + rv = client.get(f'/api/v2/businesses/{identifier}/filings', + headers=headers) ledger = rv.json @@ -124,7 +141,7 @@ def test_ledger_search(session, client, jwt): alteration = next((f for f in ledger['filings'] if f.get('name') == 'alteration'), None) assert alteration - assert 18 == len(alteration.keys()) + assert 18 <= len(alteration.keys()) assert 'availableOnPaperOnly' in alteration assert 'effectiveDate' in alteration assert 'filingId' in alteration @@ -159,7 +176,7 @@ def ledger_element_setup_filing(business, filing_name, filing_date, filing_dict= return f -def test_ledger_comment_count(session, client, jwt): +def test_ledger_comment_count(app, session, client, jwt, monkeypatch, mock_drs_service, mocker): """Assert that the ledger returns the correct number of comments.""" # setup identifier = 'BC1234567' @@ -170,10 +187,15 @@ def test_ledger_comment_count(session, client, jwt): comment.comment = f'this comment {c}' filing_storage.comments.append(comment) filing_storage.save() + headers=create_header(jwt, [UserRoles.system], identifier) + def mock_auth(one, two): # pylint: disable=unused-argument; mocks of library methods + return headers[one] # test - rv = client.get(f'/api/v2/businesses/{identifier}/filings', - headers=create_header(jwt, [UserRoles.system], identifier)) + with app.test_request_context(): + monkeypatch.setattr('flask.request.headers.get', mock_auth) + rv = client.get(f'/api/v2/businesses/{identifier}/filings', + headers=headers) # validate assert rv.json['filings'][0]['commentsCount'] == number_of_comments @@ -191,7 +213,8 @@ def test_ledger_comment_count(session, client, jwt): ('filing-status-Withdrawn', Filing.Status.WITHDRAWN.value, 1), ]) -def test_get_all_business_filings_permitted_statuses(session, client, jwt, test_name, filing_status, expected): +def test_get_all_business_filings_permitted_statuses(app, session, client, jwt, test_name, filing_status, expected, + monkeypatch, mock_drs_service, mocker): """Assert that the ledger only shows filings with permitted statuses.""" # setup identifier = 'BC1234567' @@ -209,10 +232,15 @@ def test_get_all_business_filings_permitted_statuses(session, client, jwt, test_ filing_storage._status = filing_status filing_storage.skip_status_listener = True filing_storage.save() + headers=create_header(jwt, [UserRoles.system], identifier) + def mock_auth(one, two): # pylint: disable=unused-argument; mocks of library methods + return headers[one] # test - rv = client.get(f'/api/v2/businesses/{identifier}/filings', - headers=create_header(jwt, [UserRoles.system], identifier)) + with app.test_request_context(): + monkeypatch.setattr('flask.request.headers.get', mock_auth) + rv = client.get(f'/api/v2/businesses/{identifier}/filings', + headers=headers) # validate assert len(rv.json.get('filings')) == expected @@ -233,7 +261,8 @@ def test_get_all_business_filings_permitted_statuses(session, client, jwt, test_ ['fileNumber', 'orderDetails']), ]) -def test_ledger_court_order(session, client, jwt, test_name, file_number, order_date, effect_of_order, order_details, expected): +def test_ledger_court_order(app, session, client, jwt, test_name, file_number, order_date, effect_of_order, order_details, expected, + monkeypatch, mock_drs_service, mocker): """Assert that the ledger returns court_order values.""" # setup identifier = 'BC1234567' @@ -245,10 +274,15 @@ def test_ledger_court_order(session, client, jwt, test_name, file_number, order_ filing_storage.order_details = order_details filing_storage.save() + headers=create_header(jwt, [UserRoles.system], identifier) + def mock_auth(one, two): # pylint: disable=unused-argument; mocks of library methods + return headers[one] # test - rv = client.get(f'/api/v2/businesses/{identifier}/filings', - headers=create_header(jwt, [UserRoles.system], identifier)) + with app.test_request_context(): + monkeypatch.setattr('flask.request.headers.get', mock_auth) + rv = client.get(f'/api/v2/businesses/{identifier}/filings', + headers=headers) # validate assert rv.json['filings'][0] @@ -260,7 +294,7 @@ def test_ledger_court_order(session, client, jwt, test_name, file_number, order_ assert not filing_json.get('data') -def test_ledger_display_name_annual_report(session, client, jwt): +def test_ledger_display_name_annual_report(app, session, client, jwt, monkeypatch, mock_drs_service, mocker): """Assert that the ledger returns the correct number of comments.""" # setup identifier = 'BC1234567' @@ -275,10 +309,15 @@ def test_ledger_display_name_annual_report(session, client, jwt): business, filing_storage = ledger_element_setup_help(identifier, 'annualReport') filing_storage._meta_data = meta_data filing_storage.save() + headers=create_header(jwt, [UserRoles.system], identifier) + def mock_auth(one, two): # pylint: disable=unused-argument; mocks of library methods + return headers[one] # test - rv = client.get(f'/api/v2/businesses/{identifier}/filings', - headers=create_header(jwt, [UserRoles.system], identifier)) + with app.test_request_context(): + monkeypatch.setattr('flask.request.headers.get', mock_auth) + rv = client.get(f'/api/v2/businesses/{identifier}/filings', + headers=headers) # validate assert rv.json['filings'][0] @@ -287,7 +326,7 @@ def test_ledger_display_name_annual_report(session, client, jwt): assert filing_json['displayName'] == f'Annual Report ({date.fromisoformat(today).year})' -def test_ledger_display_unknown_name(session, client, jwt): +def test_ledger_display_unknown_name(app, session, client, jwt, monkeypatch, mock_drs_service, mocker): """Assert that the ledger returns the correct number of comments.""" # setup identifier = 'BC1234567' @@ -296,10 +335,15 @@ def test_ledger_display_unknown_name(session, client, jwt): business, filing_storage = ledger_element_setup_help(identifier, 'someAncientNamedReport') filing_storage._meta_data = meta_data filing_storage.save() + headers=create_header(jwt, [UserRoles.system], identifier) + def mock_auth(one, two): # pylint: disable=unused-argument; mocks of library methods + return headers[one] # test - rv = client.get(f'/api/v2/businesses/{identifier}/filings', - headers=create_header(jwt, [UserRoles.system], identifier)) + with app.test_request_context(): + monkeypatch.setattr('flask.request.headers.get', mock_auth) + rv = client.get(f'/api/v2/businesses/{identifier}/filings', + headers=headers) # validate assert rv.json['filings'][0] @@ -308,7 +352,7 @@ def test_ledger_display_unknown_name(session, client, jwt): assert filing_json['displayName'] == 'Some Ancient Named Report' -def test_ledger_display_alteration_report(session, client, jwt): +def test_ledger_display_alteration_report(app, session, client, jwt, monkeypatch, mock_drs_service, mocker): """Assert that the ledger returns the correct number of comments.""" # setup identifier = 'BC1234567' @@ -322,10 +366,15 @@ def test_ledger_display_alteration_report(session, client, jwt): business, filing_storage = ledger_element_setup_help(identifier, 'alteration') filing_storage._meta_data = meta_data filing_storage.save() + headers=create_header(jwt, [UserRoles.system], identifier) + def mock_auth(one, two): # pylint: disable=unused-argument; mocks of library methods + return headers[one] # test - rv = client.get(f'/api/v2/businesses/{identifier}/filings', - headers=create_header(jwt, [UserRoles.system], identifier)) + with app.test_request_context(): + monkeypatch.setattr('flask.request.headers.get', mock_auth) + rv = client.get(f'/api/v2/businesses/{identifier}/filings', + headers=headers) # validate assert rv.json['filings'][0] @@ -340,7 +389,8 @@ def test_ledger_display_alteration_report(session, client, jwt): ('limitedRestorationExtension', 'Limited Restoration Extension Application'), ('limitedRestorationToFull', 'Conversion to Full Restoration Application'), ]) -def test_ledger_display_restoration(session, client, jwt, restoration_type, expected_display_name): +def test_ledger_display_restoration(app, session, client, jwt, restoration_type, expected_display_name, + monkeypatch, mock_drs_service, mocker): """Assert that the ledger returns the correct names of the four restoration types.""" # setup identifier = 'BC1234567' @@ -360,10 +410,15 @@ def test_ledger_display_restoration(session, client, jwt, restoration_type, expe filing['filing']['restoration']['type'] = restoration_type factory_completed_filing(business, filing, filing_date=filing_date) + headers=create_header(jwt, [UserRoles.system], identifier) + def mock_auth(one, two): # pylint: disable=unused-argument; mocks of library methods + return headers[one] # test - rv = client.get(f'/api/v2/businesses/{identifier}/filings', - headers=create_header(jwt, [UserRoles.system], identifier)) + with app.test_request_context(): + monkeypatch.setattr('flask.request.headers.get', mock_auth) + rv = client.get(f'/api/v2/businesses/{identifier}/filings', + headers=headers) # validate assert rv.json['filings'] @@ -378,7 +433,8 @@ def test_ledger_display_restoration(session, client, jwt, restoration_type, expe ('CC', Business.LegalTypes.BC_CCC.value, 'BC Community Contribution Company Incorporation Application'), ('BC', Business.LegalTypes.COMP.value, 'BC Limited Company Incorporation Application'), ]) -def test_ledger_display_incorporation(session, client, jwt, test_name, entity_type, expected_display_name): +def test_ledger_display_incorporation(app, session, client, jwt, test_name, entity_type, expected_display_name, + monkeypatch, mock_drs_service, mocker): """Assert that the ledger returns the correct number of comments.""" # setup identifier = 'BC1234567' @@ -407,17 +463,22 @@ def test_ledger_display_incorporation(session, client, jwt, test_name, entity_ty 'legalName': business_name} } f._meta_data = {**{'applicationDate': today}, **ia_meta} + headers=create_header(jwt, [UserRoles.system], identifier) + def mock_auth(one, two): # pylint: disable=unused-argument; mocks of library methods + return headers[one] # test - rv = client.get(f'/api/v2/businesses/{identifier}/filings', - headers=create_header(jwt, [UserRoles.system], identifier)) + with app.test_request_context(): + monkeypatch.setattr('flask.request.headers.get', mock_auth) + rv = client.get(f'/api/v2/businesses/{identifier}/filings', + headers=headers) # validate assert rv.json['filings'] assert rv.json['filings'][0]['displayName'] == expected_display_name -def test_ledger_display_corrected_incorporation(session, client, jwt): +def test_ledger_display_corrected_incorporation(app, session, client, jwt, monkeypatch, mock_drs_service, mocker): """Assert that the ledger returns the correct number of comments.""" # setup identifier = 'BC1234567' @@ -425,10 +486,15 @@ def test_ledger_display_corrected_incorporation(session, client, jwt): correction = ledger_element_setup_filing(business, 'correction', filing_date=business.founding_date + datedelta.datedelta(months=3)) original.parent_filing_id = correction.id original.save() + headers=create_header(jwt, [UserRoles.system], identifier) + def mock_auth(one, two): # pylint: disable=unused-argument; mocks of library methods + return headers[one] # test - rv = client.get(f'/api/v2/businesses/{identifier}/filings', - headers=create_header(jwt, [UserRoles.system], identifier)) + with app.test_request_context(): + monkeypatch.setattr('flask.request.headers.get', mock_auth) + rv = client.get(f'/api/v2/businesses/{identifier}/filings', + headers=headers) # validate assert rv.json['filings'] @@ -441,7 +507,7 @@ def test_ledger_display_corrected_incorporation(session, client, jwt): assert False -def test_ledger_display_corrected_annual_report(session, client, jwt): +def test_ledger_display_corrected_annual_report(app, session, client, jwt, monkeypatch, mock_drs_service, mocker): """Assert that the ledger returns the correct number of comments.""" # setup identifier = 'BC1234567' @@ -460,10 +526,15 @@ def test_ledger_display_corrected_annual_report(session, client, jwt): correction_meta = {'legalFilings': ['annualReport', 'correction']} correction._meta_data = {**{'applicationDate': today}, **correction_meta} correction.save() + headers=create_header(jwt, [UserRoles.system], identifier) + def mock_auth(one, two): # pylint: disable=unused-argument; mocks of library methods + return headers[one] # test - rv = client.get(f'/api/v2/businesses/{identifier}/filings', - headers=create_header(jwt, [UserRoles.system], identifier)) + with app.test_request_context(): + monkeypatch.setattr('flask.request.headers.get', mock_auth) + rv = client.get(f'/api/v2/businesses/{identifier}/filings', + headers=headers) # validate assert rv.json['filings'] @@ -490,7 +561,8 @@ def test_ledger_display_corrected_annual_report(session, client, jwt): ('unknown-public', None, UserRoles.public_user, 'some-user', '', '', 'some-user'), ] ) -def test_ledger_redaction(session, client, jwt, test_name, submitter_role, jwt_role, username, firstname, lastname, expected): +def test_ledger_redaction(app, session, client, jwt, test_name, submitter_role, jwt_role, username, firstname, lastname, expected, + monkeypatch, mock_drs_service, mocker): """Assert that the core filing is saved to the backing store.""" from legal_api.core.filing import Filing as CoreFiling try: @@ -520,9 +592,15 @@ def test_ledger_redaction(session, client, jwt, test_name, submitter_role, jwt_r new_filing.submitter_roles = submitter_role setattr(new_filing, 'skip_status_listener', True) # skip status listener new_filing.save() - - rv = client.get(f'/api/v2/businesses/{identifier}/filings', - headers=create_header(jwt, [jwt_role], identifier)) + headers=create_header(jwt, [jwt_role], identifier) + def mock_auth(one, two): # pylint: disable=unused-argument; mocks of library methods + return headers[one] + + # test + with app.test_request_context(): + monkeypatch.setattr('flask.request.headers.get', mock_auth) + rv = client.get(f'/api/v2/businesses/{identifier}/filings', + headers=headers) except Exception as err: print(err) @@ -530,7 +608,7 @@ def test_ledger_redaction(session, client, jwt, test_name, submitter_role, jwt_r assert rv.json['filings'][0]['submitter'] == expected -def test_ledger_display_special_resolution_correction(session, client, jwt): +def test_ledger_display_special_resolution_correction(app, session, client, jwt, monkeypatch, mock_drs_service, mocker): """Assert that the ledger returns the correct number of comments.""" # setup identifier = 'CP1234567' @@ -567,10 +645,15 @@ def test_ledger_display_special_resolution_correction(session, client, jwt): correction_2_meta = {'legalFilings': ['correction']} correction_2._meta_data = {**{'applicationDate': today}, **correction_2_meta} correction_2.save() + headers=create_header(jwt, [UserRoles.system], identifier) + def mock_auth(one, two): # pylint: disable=unused-argument; mocks of library methods + return headers[one] # test - rv = client.get(f'/api/v2/businesses/{identifier}/filings', - headers=create_header(jwt, [UserRoles.system], identifier)) + with app.test_request_context(): + monkeypatch.setattr('flask.request.headers.get', mock_auth) + rv = client.get(f'/api/v2/businesses/{identifier}/filings', + headers=headers) # validate assert rv.json['filings'] @@ -583,7 +666,7 @@ def test_ledger_display_special_resolution_correction(session, client, jwt): assert False -def test_ledger_display_non_special_resolution_correction_name(session, client, jwt): +def test_ledger_display_non_special_resolution_correction_name(app, session, client, jwt, monkeypatch, mock_drs_service, mocker): """Assert that the ledger returns the correct number of comments.""" # setup identifier = 'CP1234567' @@ -604,10 +687,15 @@ def test_ledger_display_non_special_resolution_correction_name(session, client, correction_meta = {'legalFilings': ['correction']} correction._meta_data = {**{'applicationDate': today}, **correction_meta} correction.save() + headers=create_header(jwt, [UserRoles.system], identifier) + def mock_auth(one, two): # pylint: disable=unused-argument; mocks of library methods + return headers[one] # test - rv = client.get(f'/api/v2/businesses/{identifier}/filings', - headers=create_header(jwt, [UserRoles.system], identifier)) + with app.test_request_context(): + monkeypatch.setattr('flask.request.headers.get', mock_auth) + rv = client.get(f'/api/v2/businesses/{identifier}/filings', + headers=headers) # validate assert rv.json['filings']