diff --git a/jobs/furnishings/src/furnishings/stage_processors/stage_one.py b/jobs/furnishings/src/furnishings/stage_processors/stage_one.py index 59fdc8494f..b1640b5cb9 100644 --- a/jobs/furnishings/src/furnishings/stage_processors/stage_one.py +++ b/jobs/furnishings/src/furnishings/stage_processors/stage_one.py @@ -1,4 +1,4 @@ -# Copyright © 2021 Province of British Columbia +# Copyright © 2024 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. diff --git a/jobs/furnishings/src/furnishings/stage_processors/stage_two.py b/jobs/furnishings/src/furnishings/stage_processors/stage_two.py new file mode 100644 index 0000000000..448f80b692 --- /dev/null +++ b/jobs/furnishings/src/furnishings/stage_processors/stage_two.py @@ -0,0 +1,68 @@ +# Copyright © 2024 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. +"""Furnishings job procssing rules for stage two of involuntary dissolution.""" +from datetime import datetime + +from flask import Flask +from legal_api.models import Batch, BatchProcessing, Business, Furnishing, db +from sqlalchemy import exists, not_ + + +def process(app: Flask): + """Run process to manage and track notifications for dissolution stage two process.""" + try: + furnishing_subquery = exists().where( + Furnishing.batch_id == BatchProcessing.batch_id, + Furnishing.business_id == BatchProcessing.business_id, + Furnishing.furnishing_name.in_([ + Furnishing.FurnishingName.INTENT_TO_DISSOLVE, + Furnishing.FurnishingName.INTENT_TO_DISSOLVE_XPRO + ]) + ) + batch_processings = ( + db.session.query(BatchProcessing) + .filter(BatchProcessing.status == BatchProcessing.BatchProcessingStatus.PROCESSING) + .filter(BatchProcessing.step == BatchProcessing.BatchProcessingStep.WARNING_LEVEL_2) + .filter(Batch.id == BatchProcessing.batch_id) + .filter(Batch.batch_type == Batch.BatchType.INVOLUNTARY_DISSOLUTION) + .filter(Batch.status == Batch.BatchStatus.PROCESSING) + .filter(not_(furnishing_subquery)) + ).all() + + grouping_identifier = Furnishing.get_next_grouping_identifier() + + for batch_processing in batch_processings: + business = batch_processing.business + furnishing_name = ( + Furnishing.FurnishingName.INTENT_TO_DISSOLVE_XPRO + if business.legal_type == Business.LegalTypes.EXTRA_PRO_A.value + else Furnishing.FurnishingName.INTENT_TO_DISSOLVE + ) + new_furnishing = Furnishing( + furnishing_type=Furnishing.FurnishingType.GAZETTE, + furnishing_name=furnishing_name, + batch_id=batch_processing.batch_id, + business_id=batch_processing.business_id, + business_identifier=batch_processing.business_identifier, + created_date=datetime.utcnow(), + last_modified=datetime.utcnow(), + status=Furnishing.FurnishingStatus.QUEUED, + grouping_identifier=grouping_identifier + ) + new_furnishing.save() + # TODO: create data files and SFTPing to BC Laws + # TODO: mark furnishings entry processed + + except Exception as err: + app.logger.error(err) diff --git a/jobs/furnishings/src/furnishings/worker.py b/jobs/furnishings/src/furnishings/worker.py index fe9fd5aa4f..3441689e09 100644 --- a/jobs/furnishings/src/furnishings/worker.py +++ b/jobs/furnishings/src/furnishings/worker.py @@ -26,7 +26,7 @@ from sentry_sdk.integrations.logging import LoggingIntegration from furnishings.config import get_named_config # pylint: disable=import-error -from furnishings.stage_processors import stage_one +from furnishings.stage_processors import stage_one, stage_two from furnishings.utils.logging import setup_logging # pylint: disable=import-error @@ -117,6 +117,6 @@ async def run(application: Flask, qsm: QueueService): # pylint: disable=redefin if stage_1_valid: await stage_one.process(application, qsm) if stage_2_valid: - pass + stage_two.process(application) if stage_3_valid: pass diff --git a/jobs/furnishings/tests/unit/__init__.py b/jobs/furnishings/tests/unit/__init__.py index 5af03f6bc1..506581251e 100644 --- a/jobs/furnishings/tests/unit/__init__.py +++ b/jobs/furnishings/tests/unit/__init__.py @@ -18,7 +18,7 @@ from datedelta import datedelta from freezegun import freeze_time -from legal_api.models import Batch, BatchProcessing, Business, Filing, db +from legal_api.models import Batch, BatchProcessing, Business, Filing, Furnishing, db from legal_api.models.colin_event_id import ColinEventId from sqlalchemy_continuum import versioning_manager @@ -127,3 +127,27 @@ def factory_completed_filing(business, colin_event.save() filing.save() return filing + + +def factory_furnishing(batch_id, + business_id, + identifier, + furnishing_name=Furnishing.FurnishingName.DISSOLUTION_COMMENCEMENT_NO_AR, + furnishing_type=Furnishing.FurnishingType.EMAIL, + status=Furnishing.FurnishingStatus.QUEUED, + created_date=datetime.datetime.utcnow(), + last_modified=datetime.datetime.utcnow() + ): + """Create a furnishing entry.""" + furnishing = Furnishing( + batch_id=batch_id, + business_id=business_id, + business_identifier=identifier, + furnishing_name=furnishing_name, + furnishing_type=furnishing_type, + status=status, + created_date=created_date, + last_modified=last_modified, + ) + furnishing.save() + return furnishing diff --git a/jobs/furnishings/tests/unit/stage_processors/test_stage_one.py b/jobs/furnishings/tests/unit/stage_processors/test_stage_one.py index e81029c199..58d3795149 100644 --- a/jobs/furnishings/tests/unit/stage_processors/test_stage_one.py +++ b/jobs/furnishings/tests/unit/stage_processors/test_stage_one.py @@ -14,7 +14,7 @@ """Tests for the Furnishings Job. -Test suite to ensure that the Furnishings Job is working as expected. +Test suite to ensure that the Furnishings Job stage one is working as expected. """ import copy from unittest.mock import MagicMock, patch diff --git a/jobs/furnishings/tests/unit/stage_processors/test_stage_two.py b/jobs/furnishings/tests/unit/stage_processors/test_stage_two.py new file mode 100644 index 0000000000..e970ec3d1d --- /dev/null +++ b/jobs/furnishings/tests/unit/stage_processors/test_stage_two.py @@ -0,0 +1,97 @@ +# Copyright © 2024 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. + +"""Tests for the Furnishings Job. + +Test suite to ensure that the Furnishings Job stage two is working as expected. +""" +from datetime import datetime + +import pytest +from datedelta import datedelta +from legal_api.models import BatchProcessing, Business, Furnishing + +from furnishings.stage_processors.stage_two import process + +from .. import factory_batch, factory_batch_processing, factory_business, factory_furnishing + + +@pytest.mark.parametrize( + 'test_name, entity_type, step, new_entry', [ + ( + 'BC_NEW_FURNISHING', + Business.LegalTypes.COMP.value, + BatchProcessing.BatchProcessingStep.WARNING_LEVEL_2, + True + ), + ( + 'XPRO_NEW_FURNISHING', + Business.LegalTypes.EXTRA_PRO_A.value, + BatchProcessing.BatchProcessingStep.WARNING_LEVEL_2, + True + ), + ( + 'STAGE_2_ALREADY_RUN', + Business.LegalTypes.COMP.value, + BatchProcessing.BatchProcessingStep.WARNING_LEVEL_2, + False + ), + ( + 'NOT_IN_STAGE_2', + Business.LegalTypes.COMP.value, + BatchProcessing.BatchProcessingStep.WARNING_LEVEL_1, + False + ) + ] +) +def test_process_create_furnishings(app, session, test_name, entity_type, step, new_entry): + """Assert that new furnishing entries are created correctly.""" + business = factory_business(identifier='BC1234567', entity_type=entity_type) + batch = factory_batch() + factory_batch_processing( + batch_id=batch.id, + business_id=business.id, + identifier=business.identifier, + step=step + ) + + if test_name == 'STAGE_2_ALREADY_RUN': + existing_furnishing = factory_furnishing( + batch_id=batch.id, + business_id=business.id, + identifier=business.identifier, + furnishing_name=Furnishing.FurnishingName.INTENT_TO_DISSOLVE, + furnishing_type=Furnishing.FurnishingType.GAZETTE, + created_date=datetime.utcnow()+datedelta(years=1), + last_modified=datetime.utcnow()+datedelta(years=1) + ) + + process(app) + + furnishings = Furnishing.find_by(business_id=business.id) + if new_entry: + assert len(furnishings) == 1 + furnishing = furnishings[0] + assert furnishing.furnishing_type == Furnishing.FurnishingType.GAZETTE + if entity_type == Business.LegalTypes.EXTRA_PRO_A.value: + assert furnishing.furnishing_name == Furnishing.FurnishingName.INTENT_TO_DISSOLVE_XPRO + else: + assert furnishing.furnishing_name == Furnishing.FurnishingName.INTENT_TO_DISSOLVE + else: + if test_name == 'STAGE_2_ALREADY_RUN': + assert len(furnishings) == 1 + furnishing = furnishings[0] + assert furnishing == existing_furnishing + else: + assert len(furnishings) == 0