diff --git a/queue_services/business-filer/devops/vaults.gcp.env b/queue_services/business-filer/devops/vaults.gcp.env index 82ba9a05ee..2361bc9d14 100644 --- a/queue_services/business-filer/devops/vaults.gcp.env +++ b/queue_services/business-filer/devops/vaults.gcp.env @@ -38,6 +38,7 @@ BUSINESS_EVENTS_TOPIC="op://gcp-queue/$APP_ENV/topics/BUSINESS_EVENTS_TOPIC" BUSINESS_MAILER_TOPIC="op://gcp-queue/$APP_ENV/topics/BUSINESS_EMAILER_TOPIC" BUSINESS_PAY_TOPIC="op://gcp-queue/$APP_ENV/topics/BUSINESS_PAY_TOPIC" DOC_CREATE_REC_TOPIC="op://gcp-queue/$APP_ENV/topics/DOC_CREATE_REC_TOPIC" +DOC_UPDATE_REC_TOPIC="op://gcp-queue/$APP_ENV/topics/DOC_UPDATE_REC_TOPIC" NAMEX_PAY_TOPIC="op://gcp-queue/$APP_ENV/topics/NAMEX_PAY_TOPIC" VPC_CONNECTOR="op://CD/$APP_ENV/base/VPC_CONNECTOR" diff --git a/queue_services/business-filer/src/business_filer/config.py b/queue_services/business-filer/src/business_filer/config.py index 92c50bbae1..a4ba1974a6 100644 --- a/queue_services/business-filer/src/business_filer/config.py +++ b/queue_services/business-filer/src/business_filer/config.py @@ -92,6 +92,7 @@ class _Config: # pylint: disable=too-few-public-methods BUSINESS_MAILER_TOPIC = os.getenv("BUSINESS_MAILER_TOPIC", "business-mailer-dev") BUSINESS_PAY_TOPIC = os.getenv("BUSINESS_PAY_TOPIC", "business-pay-dev") DOC_CREATE_REC_TOPIC = os.getenv("DOC_CREATE_REC_TOPIC") + DOC_UPDATE_REC_TOPIC = os.getenv("DOC_UPDATE_REC_TOPIC") NAMEX_PAY_TOPIC = os.getenv("NAMEX_PAY_TOPIC", "namex-pay-dev") SUB_AUDIENCE = os.getenv("SUB_AUDIENCE", "") SUB_SERVICE_ACCOUNT = os.getenv("SUB_SERVICE_ACCOUNT", "") @@ -132,6 +133,7 @@ class TestConfig(_Config): # pylint: disable=too-few-public-methods # Faked out publishing DOC_CREATE_REC_TOPIC = os.getenv("TEST_DOC_CREATE_REC_TOPIC", "fake-doc-create-rec-topic") + DOC_UPDATE_REC_TOPIC = os.getenv("TEST_DOC_UPDATE_REC_TOPIC", "fake-doc-update-rec-topic") class ProdConfig(_Config): # pylint: disable=too-few-public-methods diff --git a/queue_services/business-filer/src/business_filer/filing_processors/filing_components/document_records.py b/queue_services/business-filer/src/business_filer/filing_processors/filing_components/document_records.py deleted file mode 100644 index 39b9da275f..0000000000 --- a/queue_services/business-filer/src/business_filer/filing_processors/filing_components/document_records.py +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright © 2026 Province of British Columbia -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""Updates client document records with filing/business information once a filing completes, -so the document shows up correctly in the ledger and is searchable in the DRS UI. -""" -import re - -from business_model.models import Business, Document, Filing -from flask import current_app - -from business_filer.services import document_service - -_DRS_KEY_PATTERN = re.compile(r"^[A-Z]+-DS\d+$") - - -def update_document_records(business: Business, filing: Filing): - """Update the document record(s) for any client documents uploaded via DRS associated with a filing. - - business: The business record associated with the filing. - filing: The completed filing record. - """ - - documents = _find_documents_for_filing(filing.id) - - if not documents: - return - - update_info = _build_update_info(business, filing) - - for document in documents: - if not _is_drs_document(document.file_key): - continue - try: - response = document_service.update_document_record(document.file_key, dict(update_info)) - if response is not None and not response.ok: - current_app.logger.warning( - f"Failed to update document record for document id={document.id}, " - f"file_key={document.file_key}, filing={filing.id}: " - f"status={response.status_code}, body={document_service.get_content(response)}" - ) - except Exception as err: # pylint: disable=broad-except - current_app.logger.warning( - f"Error updating document record for document id={document.id}, " - f"file_key={document.file_key}, filing={filing.id}: {err}" - ) - - -def _find_documents_for_filing(filing_id: int) -> list[Document]: - """Find all documents for a filing.""" - return Document.query.filter_by(filing_id=filing_id).all() - - -def _build_update_info(business: Business, filing: Filing) -> dict: - """Build the update payload.""" - update_info = { - "filingId": filing.id, - "filingDate": filing.completion_date.isoformat() if filing.completion_date else None, - } - if business: - update_info["businessIdentifier"] = business.identifier - return {k: v for k, v in update_info.items() if v is not None} - - -def _is_drs_document(file_key: str) -> bool: - """Return True if the file_key is a DRS key. - - DRS keys are formatted as "{documentClass}-{documentServiceId}", e.g. "COOP-DS0000101951". - Legacy Minio keys (UUIDs) do not match this pattern. - """ - return bool(file_key) and bool(_DRS_KEY_PATTERN.match(file_key)) diff --git a/queue_services/business-filer/src/business_filer/services/__init__.py b/queue_services/business-filer/src/business_filer/services/__init__.py index 04fbd6e653..4e52d7b98b 100644 --- a/queue_services/business-filer/src/business_filer/services/__init__.py +++ b/queue_services/business-filer/src/business_filer/services/__init__.py @@ -36,7 +36,6 @@ from ..common.services.account_service import AccountService # noqa: TID252 from ..common.services.flag_manager import Flags # noqa: TID252 -from . import document_service from .gcp_auth import verify_gcp_jwt flags = Flags() diff --git a/queue_services/business-filer/src/business_filer/services/document_service.py b/queue_services/business-filer/src/business_filer/services/document_service.py deleted file mode 100644 index e876c6aa1f..0000000000 --- a/queue_services/business-filer/src/business_filer/services/document_service.py +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright © 2026 Province of British Columbia -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""Manages Filer -> DRS integration for updating client document records after a filing completes.""" -import json - -import requests -from flask import current_app - -from business_filer.services import AccountService - -PATCH_DOCUMENT_PATH: str = "{url}/documents/client/{document_key}" -SERVICE_TIMEOUT = 30.0 - - -def update_document_record(document_key: str, update_info: dict): - """Update document record properties via the Business API documents endpoint. - - Business API reference: PATCH /business/api/v2/documents/client/{documentKey} - - document_key: The business documents table file_key value, formatted as - "{documentClass}-{documentServiceId}". - update_info: The properties to update - any of filingId, filingDate, businessIdentifier. - return: The Business API response, or None if no document_key is available to update. - """ - if not document_key: - current_app.logger.info("update_document_record aborted: no document file_key.") - return None - url = PATCH_DOCUMENT_PATH.format( - url=str(current_app.config.get("LEGAL_API_URL")).rstrip("/"), - document_key=document_key - ) - headers = _get_request_headers() - current_app.logger.info(f"Business API update_document_record url={url}") - response = requests.patch(url=url, headers=headers, timeout=SERVICE_TIMEOUT, json=update_info) - current_app.logger.info(f"Business API patch call {url} status={response.status_code}") - if not response.ok: - current_app.logger.error(f"Business API patch call {url} response={response.content}") - return response - - -def _get_request_headers() -> dict: - """Get request headers.""" - headers = { - **AccountService.CONTENT_TYPE_JSON - } - - if current_app.config.get("ACCOUNT_SVC_CLIENT_SECRET"): - token = AccountService.get_bearer_token() - headers["Authorization"] = AccountService.BEARER + token - - return headers - - -def get_content(response): - """Get the content of the response useful for test methods.""" - content = response.content - try: - content = content.decode() - content = json.loads(content) - except Exception: # pylint: disable=broad-except; best-effort parsing only - pass - return content diff --git a/queue_services/business-filer/src/business_filer/services/filer.py b/queue_services/business-filer/src/business_filer/services/filer.py index d191652078..fc3ffb8d10 100644 --- a/queue_services/business-filer/src/business_filer/services/filer.py +++ b/queue_services/business-filer/src/business_filer/services/filer.py @@ -78,7 +78,7 @@ transition, transparency_register, ) -from business_filer.filing_processors.filing_components import business_profile, document_records, name_request +from business_filer.filing_processors.filing_components import business_profile, name_request from business_filer.services import Flags from business_filer.services.publish_event import PublishEvent @@ -326,9 +326,14 @@ def process_filing(filing_message: FilingMessage): # noqa: PLR0915, PLR0912 if not Flags.is_on("enable-sandbox"): PublishEvent.publish_email_message(current_app, business, filing_submission, filing_submission.status) - # Update the document record(s) for any client-submitted documents on this filing with - # the filing id, filing date, and business identifier - document_records.update_document_records(business, filing_submission) + try: + # Update the DRS record(s) for any client-submitted documents on this filing with + # the filing id, filing date, and business identifier + PublishEvent.publish_drs_update_message(current_app, business, filing_submission) + except Exception as err: + # log error for ops, but don't prevent filing from completing + current_app.logger.warning(err.with_traceback(None)) + current_app.logger.warning(f"Failed to publish DRS update for {filing_submission.id}.") if filing_type in [ FilingTypes.CHANGEOFLIQUIDATORS, diff --git a/queue_services/business-filer/src/business_filer/services/publish_event.py b/queue_services/business-filer/src/business_filer/services/publish_event.py index b95b1ba804..824045e094 100644 --- a/queue_services/business-filer/src/business_filer/services/publish_event.py +++ b/queue_services/business-filer/src/business_filer/services/publish_event.py @@ -1,8 +1,9 @@ +import re import uuid from datetime import UTC, datetime # if TYPE_CHECKING: -from business_model.models import Business, Filing +from business_model.models import Business, Document, Filing from flask import Flask from business_filer.common.filing import FilingTypes @@ -10,6 +11,10 @@ from business_filer.services import Flags, gcp_queue from gcp_queue import SimpleCloudEvent, to_queue_message +# DRS keys are formatted as "{documentClass}-{documentServiceId}", e.g. "COOP-DS0000101951". +# Legacy Minio keys (UUIDs) do not match this pattern. +_DRS_KEY_PATTERN = re.compile(r"^[A-Z]+-DS\d+$") + class PublishEvent: """Service to publish specific events onto the GCP Queue.""" @@ -78,6 +83,39 @@ def publish_drs_create_message(app: Flask, business: Business, filing: Filing): except Exception as err: # pylint: disable=broad-except; raise PublishException(err) from err + @staticmethod + def publish_drs_update_message(app: Flask, business: Business, filing: Filing): + """Publish a drs update record message for each DRS document uploaded with the filing. + + Updates the document record(s) with filing/business information once a filing completes, + so the document shows up correctly in the ledger and is searchable in the DRS UI. + """ + try: + subject = app.config.get("DOC_UPDATE_REC_TOPIC") + documents = Document.query.filter_by(filing_id=filing.id).all() + for document in documents: + if not PublishEvent._is_drs_document(document.file_key): + continue + data = { + "accountId": "business-api", + "fileKey": document.file_key, + "businessIdentifier": business.identifier if business else None, + "filingDate": filing.completion_date.isoformat() if filing.completion_date else None, + "filingId": filing.id + } + data = {k: v for k, v in data.items() if v is not None} + + ce = PublishEvent._create_cloud_event(app, business, filing, subject, data) + gcp_queue.publish(subject, to_queue_message(ce)) + + except Exception as err: # pylint: disable=broad-except; + raise PublishException(err) from err + + @staticmethod + def _is_drs_document(file_key: str) -> bool: + """Return True if the file_key is a DRS key.""" + return bool(file_key) and bool(_DRS_KEY_PATTERN.match(file_key)) + @staticmethod def publish_mras_email(app: Flask, business: Business, filing: Filing): """Publish MRAS email message onto the NATS emailer subject.""" diff --git a/queue_services/business-filer/tests/unit/filing_processors/filing_components/test_document_records.py b/queue_services/business-filer/tests/unit/filing_processors/filing_components/test_document_records.py deleted file mode 100644 index 94128b36b7..0000000000 --- a/queue_services/business-filer/tests/unit/filing_processors/filing_components/test_document_records.py +++ /dev/null @@ -1,129 +0,0 @@ -# Copyright © 2026 Province of British Columbia -# -# Licensed under the BSD 3 Clause License, (the "License"); -# you may not use this file except in compliance with the License. -# The template for the license can be found here -# https://opensource.org/license/bsd-3-clause/ -# -# Redistribution and use in source and binary forms, -# with or without modification, are permitted provided that the -# following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# 3. Neither the name of the copyright holder nor the names of its contributors -# may be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -"""Unit tests for document_records filing component processor.""" - -from unittest.mock import Mock, patch - -from business_model.models import Business, Document, Filing - -from business_filer.filing_processors.filing_components import document_records - - -def test_skip_when_no_documents(): - """Assert nothing happens when no documents exist.""" - - business = Business(identifier="BC1234567") - filing = Filing(id=1) - - mock_query = Mock() - mock_query.filter_by.return_value.all.return_value = [] - - with patch.object(Document, "query", mock_query), \ - patch.object(document_records.document_service, "update_document_record") as mock_update: - - document_records.update_document_records(business, filing) - - mock_update.assert_not_called() - - -def test_updates_drs_document(): - """Assert DRS documents are updated.""" - - business = Business(identifier="BC1234567") - - filing = Filing(id=1) - filing._completion_date = None - - document = Document( - id=10, - filing_id=1, - file_key="COOP-DS0000001234" - ) - - mock_query = Mock() - mock_query.filter_by.return_value.all.return_value = [document] - - response = Mock() - response.ok = True - - with patch.object(Document, "query", mock_query), \ - patch.object(document_records.document_service, - "update_document_record", - return_value=response) as mock_update: - - document_records.update_document_records(business, filing) - - mock_update.assert_called_once() - - args = mock_update.call_args[0] - - assert args[0] == "COOP-DS0000001234" - assert args[1]["filingId"] == 1 - assert args[1]["businessIdentifier"] == "BC1234567" - - -def test_skip_legacy_document(): - """Assert legacy Minio documents are ignored.""" - - business = Business(identifier="BC1234567") - filing = Filing(id=1) - - document = Document( - id=10, - filing_id=1, - file_key="550e8400-e29b-41d4-a716-446655440000" - ) - - mock_query = Mock() - mock_query.filter_by.return_value.all.return_value = [document] - - with patch.object(Document, "query", mock_query), \ - patch.object(document_records.document_service, - "update_document_record") as mock_update: - - document_records.update_document_records(business, filing) - - mock_update.assert_not_called() - - -def test_is_drs_document(): - """Assert DRS document detection.""" - assert document_records._is_drs_document("COOP-DS0000123456") - assert document_records._is_drs_document("BEN-DS123456") - - assert not document_records._is_drs_document( - "550e8400-e29b-41d4-a716-446655440000" - ) - assert not document_records._is_drs_document("") - assert not document_records._is_drs_document(None) diff --git a/queue_services/business-filer/tests/unit/test_publish/test_publish_drs_update.py b/queue_services/business-filer/tests/unit/test_publish/test_publish_drs_update.py new file mode 100644 index 0000000000..ddb9023de7 --- /dev/null +++ b/queue_services/business-filer/tests/unit/test_publish/test_publish_drs_update.py @@ -0,0 +1,190 @@ +# Copyright © 2026 Province of British Columbia +# +# Licensed under the BSD 3 Clause License, (the "License"); +# you may not use this file except in compliance with the License. +# The template for the license can be found here +# https://opensource.org/license/bsd-3-clause/ +# +# Redistribution and use in source and binary forms, +# with or without modification, are permitted provided that the +# following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +"""Unit tests for PublishEvent.publish_drs_update_message.""" +import json +from datetime import UTC, datetime +from unittest.mock import Mock, patch + +from business_model.models import Business, Document, Filing + +from business_filer.services import gcp_queue +from business_filer.services.publish_event import PublishEvent + +IDENTIFIER = 'BC1234567' +FILING_ID = 1438352 +COMPLETION_DATE = '2026-06-09T23:02:02+00:00' +FILE_KEY_1 = 'COOP-DS0000101951' +FILE_KEY_2 = 'BEN-DS0000101952' + +def _make_minimal_filing(): + filing = Filing() + filing.id = FILING_ID + filing._filing_type = 'continuationIn' + filing._completion_date = datetime.fromisoformat(COMPLETION_DATE) + return filing + + +def test_publish_drs_update_no_documents(app): + """Assert nothing is published when the filing has no documents.""" + business = Business(identifier=IDENTIFIER) + filing = _make_minimal_filing() + + mock_query = Mock() + mock_query.filter_by.return_value.all.return_value = [] + + with patch.object(Document, 'query', mock_query), \ + patch.object(gcp_queue, 'publish') as mock_publish: + + PublishEvent.publish_drs_update_message(app, business, filing) + + mock_publish.assert_not_called() + + +def test_publish_drs_update_drs_document(app): + """Assert a drs update message is published for a DRS document.""" + business = Business(identifier=IDENTIFIER) + filing = _make_minimal_filing() + + document = Document( + id=10, + filing_id=filing.id, + file_key=FILE_KEY_1 + ) + + mock_query = Mock() + mock_query.filter_by.return_value.all.return_value = [document] + + with patch.object(Document, 'query', mock_query), \ + patch.object(gcp_queue, 'publish') as mock_publish: + + PublishEvent.publish_drs_update_message(app, business, filing) + + mock_publish.assert_called_once() + subject, payload = mock_publish.call_args.args + assert subject == app.config['DOC_UPDATE_REC_TOPIC'] + payload_data = (json.loads(payload)).get('data') + assert payload_data == { + 'accountId': 'business-api', + 'fileKey': FILE_KEY_1, + 'businessIdentifier': IDENTIFIER, + 'filingDate': COMPLETION_DATE, + 'filingId': FILING_ID + } + + +def test_publish_drs_update_multiple_documents(app): + """Assert one message is published per DRS document, skipping legacy keys.""" + business = Business(identifier=IDENTIFIER) + filing = _make_minimal_filing() + + documents = [ + Document(id=10, filing_id=filing.id, file_key=FILE_KEY_1), + Document(id=11, filing_id=filing.id, file_key='550e8400-e29b-41d4-a716-446655440000'), + Document(id=12, filing_id=filing.id, file_key=FILE_KEY_2), + ] + + mock_query = Mock() + mock_query.filter_by.return_value.all.return_value = documents + + with patch.object(Document, 'query', mock_query), \ + patch.object(gcp_queue, 'publish') as mock_publish: + + PublishEvent.publish_drs_update_message(app, business, filing) + + assert mock_publish.call_count == 2 + file_keys = [ + (json.loads(call.args[1])).get('data', {}).get('fileKey') + for call in mock_publish.call_args_list + ] + assert file_keys == [FILE_KEY_1, FILE_KEY_2] + + +def test_publish_drs_update_skip_legacy_document(app): + """Assert legacy Minio documents are ignored.""" + business = Business(identifier=IDENTIFIER) + filing = _make_minimal_filing() + + document = Document( + id=10, + filing_id=filing.id, + file_key='550e8400-e29b-41d4-a716-446655440000' + ) + + mock_query = Mock() + mock_query.filter_by.return_value.all.return_value = [document] + + with patch.object(Document, 'query', mock_query), \ + patch.object(gcp_queue, 'publish') as mock_publish: + + PublishEvent.publish_drs_update_message(app, business, filing) + + mock_publish.assert_not_called() + + +def test_publish_drs_update_omits_empty_values(app): + """Assert filingDate is omitted when the filing has no completion date.""" + business = Business(identifier=IDENTIFIER) + filing = _make_minimal_filing() + filing._completion_date = None + + document = Document( + id=10, + filing_id=filing.id, + file_key=FILE_KEY_1 + ) + + mock_query = Mock() + mock_query.filter_by.return_value.all.return_value = [document] + + with patch.object(Document, 'query', mock_query), \ + patch.object(gcp_queue, 'publish') as mock_publish: + + PublishEvent.publish_drs_update_message(app, business, filing) + + mock_publish.assert_called_once() + payload_data = (json.loads(mock_publish.call_args.args[1])).get('data') + assert 'filingDate' not in payload_data + assert payload_data.get('filingId') == FILING_ID + + +def test_is_drs_document(): + """Assert DRS document detection.""" + assert PublishEvent._is_drs_document(FILE_KEY_1) + assert PublishEvent._is_drs_document(FILE_KEY_2) + assert PublishEvent._is_drs_document('COOP-DS0000123456') + assert PublishEvent._is_drs_document('BEN-DS123456') + + assert not PublishEvent._is_drs_document('550e8400-e29b-41d4-a716-446655440000') + assert not PublishEvent._is_drs_document('') + assert not PublishEvent._is_drs_document(None)