Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

21475 Filer - Update Change of Address filing processor to delay dissolution #2750

Merged
merged 10 commits into from
Jun 20, 2024
7 changes: 6 additions & 1 deletion .github/workflows/entity-filer-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:

strategy:
matrix:
python-version: [3.8]
python-version: [3.9.19]

steps:
- uses: actions/checkout@v3
Expand Down Expand Up @@ -72,10 +72,15 @@ jobs:
ACCOUNT_SVC_AUTH_URL: https://mock_account_svc_auth_url
ACCOUNT_SVC_CLIENT_ID: account_svc_client_id
ACCOUNT_SVC_CLIENT_SECRET: account_svc_client_secret
BUSINESS_EVENTS_TOPIC: projects/project-id/topics/test


runs-on: ubuntu-20.04

strategy:
matrix:
python-version: [3.9.19]

services:
postgres:
image: postgres:12
Expand Down
9 changes: 7 additions & 2 deletions queue_services/entity-filer/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ CURRENT_ABS_DIR:=$(patsubst %/,%,$(dir $(MKFILE_PATH)))
PROJECT_NAME:=entity_filer
DOCKER_NAME:=entity-filer

# TODO remove this when the conversion to the new queue is completed
export PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python

#################################################################################
# COMMANDS -- Setup #
#################################################################################
Expand Down Expand Up @@ -39,7 +42,8 @@ clean-test: ## clean test files
build-req: clean ## Upgrade requirements
test -f venv/bin/activate || python3 -m venv $(CURRENT_ABS_DIR)/venv ;\
. venv/bin/activate ;\
pip install pip==20.1.1 ;\
pip install pip==24.0 ;\
pip install wheel==0.43.0 ;\
pip install -Ur requirements/prod.txt ;\
pip freeze | sort > requirements.txt ;\
cat requirements/bcregistry-libraries.txt >> requirements.txt ;\
Expand All @@ -48,7 +52,8 @@ build-req: clean ## Upgrade requirements
install: clean ## Install python virtrual environment
test -f venv/bin/activate || python3 -m venv $(CURRENT_ABS_DIR)/venv ;\
. venv/bin/activate ;\
pip install pip==20.1.1 ;\
pip install pip==24.0 ;\
pip install wheel==0.43.0 ;\
pip install -Ur requirements.txt

install-dev: ## Install local application
Expand Down
5 changes: 5 additions & 0 deletions queue_services/entity-filer/flags.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"flagValues": {
"enable-involuntary-dissolution": true
}
}
2 changes: 1 addition & 1 deletion queue_services/entity-filer/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ reportlab==3.6.12
git+https://github.com/bcgov/sbc-connect-common.git#egg=gcp-queue&subdirectory=python/gcp-queue
git+https://github.com/bcgov/[email protected]#egg=registry_schemas
git+https://github.com/bcgov/lear.git#egg=entity_queue_common&subdirectory=queue_services/common
git+https://github.com/thorwolpert/lear.git@requirements-split-nats-2#egg=legal_api&subdirectory=legal-api
git+https://github.com/bcgov/lear.git#egg=legal_api&subdirectory=legal-api
2 changes: 2 additions & 0 deletions queue_services/entity-filer/src/entity_filer/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ class _Config(): # pylint: disable=too-few-public-methods

FONTS_PATH = os.getenv('FONTS_PATH', 'fonts')

LD_SDK_KEY = os.getenv('LD_SDK_KEY', None)

# POSTGRESQL
DB_USER = os.getenv('DATABASE_USERNAME', '')
DB_PASSWORD = os.getenv('DATABASE_PASSWORD', '')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@
"""File processing rules and actions for the change of address."""
from typing import Dict

from legal_api.models import Business
from datedelta import datedelta
from legal_api.models import BatchProcessing, Business
from legal_api.utils.datetime import date, datetime

from entity_filer.filing_meta import FilingMeta
from entity_filer.filing_processors.filing_components import create_address, update_address


def process(business: Business, filing: Dict, filing_meta: FilingMeta):
def process(business: Business, filing: Dict, filing_meta: FilingMeta, flag_on: bool):
"""Render the change_of_address onto the business model objects."""
# offices_array = json.dumps(filing['changeOfAddress']['offices'])
# Only retrieve the offices component from the filing json
Expand All @@ -39,3 +41,21 @@ def process(business: Business, filing: Dict, filing_meta: FilingMeta):
else:
address = create_address(new_address, k)
office.addresses.append(address)

if flag_on:
if business.in_dissolution:
batch_processings = BatchProcessing.find_by(business_id=business.id)
for batch_processing in batch_processings:
if batch_processing.status not in [
BatchProcessing.BatchProcessingStatus.COMPLETED,
BatchProcessing.BatchProcessingStatus.WITHDRAWN
] and datetime.utcnow() + datedelta(days=60) > batch_processing.trigger_date:
batch_processing.trigger_date = datetime.utcnow() + datedelta(days=62)
batch_processing.meta_data = {
**batch_processing.meta_data,
'changeOfAddressDelay': True
}
target_dissolution_date = date.fromisoformat(batch_processing.meta_data['targetDissolutionDate'])
target_dissolution_date += datedelta(days=62)
batch_processing.meta_data['targetDissolutionDate'] = target_dissolution_date.isoformat()
batch_processing.last_modified = datetime.utcnow()
10 changes: 8 additions & 2 deletions queue_services/entity-filer/src/entity_filer/worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
from legal_api import db
from legal_api.core import Filing as FilingCore
from legal_api.models import Business, Filing
from legal_api.services import Flags
from legal_api.utils.datetime import datetime, timezone
from sentry_sdk import capture_message
from sqlalchemy.exc import OperationalError
Expand Down Expand Up @@ -83,6 +84,10 @@
FLASK_APP.config.from_object(APP_CONFIG)
db.init_app(FLASK_APP)
gcp_queue.init_app(FLASK_APP)
flags = Flags()

if FLASK_APP.config.get('LD_SDK_KEY', None):
flags.init_app(FLASK_APP)


def get_filing_types(legal_filings: dict):
Expand Down Expand Up @@ -139,7 +144,7 @@ def publish_gcp_queue_event(business: Business, filing: Filing):
"""Publish the filing message onto the GCP-QUEUE filing subject."""
try:
subject = APP_CONFIG.BUSINESS_EVENTS_TOPIC
data= {
data = {
'filing': {
'header': {'filingId': filing.id,
'effectiveDate': filing.effective_date.isoformat()
Expand Down Expand Up @@ -238,7 +243,8 @@ async def process_filing(filing_msg: Dict, flask_app: Flask): # pylint: disable
annual_report.process(business, filing, filing_meta)

elif filing.get('changeOfAddress'):
change_of_address.process(business, filing, filing_meta)
flag_on = flags.is_on('enable-involuntary-dissolution')
change_of_address.process(business, filing, filing_meta, flag_on)

elif filing.get('changeOfDirectors'):
filing['colinIds'] = filing_submission.colin_event_ids
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from testcontainers.core.waiting_utils import wait_for_logs


@pytest.mark.skip
def test_publish_gcp_queue_event(app, session):
"""Assert that filing event is placed on the queue."""
# Call back for the subscription
Expand Down
48 changes: 47 additions & 1 deletion queue_services/entity-filer/tests/unit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@
import base64
import uuid

from datedelta import datedelta
from datetime import datetime
from freezegun import freeze_time
from sqlalchemy_continuum import versioning_manager
from legal_api.utils.datetime import datetime, timezone
from tests import EPOCH_DATETIME, FROZEN_DATETIME
from legal_api.models import db, Filing, ShareClass, ShareSeries
from legal_api.models import db, Batch, BatchProcessing, Filing, ShareClass, ShareSeries
from legal_api.models.colin_event_id import ColinEventId

AR_FILING = {
Expand Down Expand Up @@ -586,3 +588,47 @@ def factory_completed_filing(business, data_dict, filing_date=FROZEN_DATETIME, p
colin_event.save()
filing.save()
return filing


def factory_batch(batch_type=Batch.BatchType.INVOLUNTARY_DISSOLUTION,
status=Batch.BatchStatus.HOLD,
size=3,
notes=''):
"""Create a batch."""
batch = Batch(
batch_type=batch_type,
status=status,
size=size,
notes=notes
)
batch.save()
return batch


def factory_batch_processing(batch_id,
business_id,
identifier,
step=BatchProcessing.BatchProcessingStep.WARNING_LEVEL_1,
status=BatchProcessing.BatchProcessingStatus.PROCESSING,
created_date=datetime.utcnow(),
trigger_date=datetime.utcnow()+datedelta(days=42),
last_modified=datetime.utcnow(),
notes=''):
"""Create a batch processing entry."""
batch_processing = BatchProcessing(
batch_id=batch_id,
business_id=business_id,
business_identifier=identifier,
step=step,
status=status,
created_date=created_date,
trigger_date=trigger_date,
last_modified=last_modified,
notes=notes
)
target_dissolution_date = created_date + datedelta(days=72)
batch_processing.meta_data = {
'targetDissolutionDate': target_dissolution_date.date().isoformat()
}
batch_processing.save()
return batch_processing
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# 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.
"""The Unit Tests for the Change of Address filing."""
import copy
from datetime import datetime

import pytest
from datedelta import datedelta
from legal_api.models import BatchProcessing
from registry_schemas.example_data import CHANGE_OF_ADDRESS, FILING_TEMPLATE

from entity_filer.filing_meta import FilingMeta
from entity_filer.filing_processors import change_of_address
from tests.unit import create_business, factory_batch, factory_batch_processing


CHANGE_OF_ADDRESS_FILING = copy.deepcopy(FILING_TEMPLATE)
CHANGE_OF_ADDRESS_FILING['filing']['changeOfAddress'] = copy.deepcopy(CHANGE_OF_ADDRESS)
CHANGE_OF_ADDRESS_FILING['filing']['changeOfAddress']['offices']['registeredOffice'] = {
'deliveryAddress': {
'streetAddress': 'new delivery_address',
'addressCity': 'new delivery_address city',
'addressCountry': 'Canada',
'postalCode': 'H0H0H0',
'addressRegion': 'BC',
},
'mailingAddress': {
'streetAddress': 'new mailing_address',
'addressCity': 'new mailing_address city',
'addressCountry': 'Canada',
'postalCode': 'H0H0H0',
'addressRegion': 'BC',
}
}


def test_change_of_address_process(app, session):
"""Assert that the address is changed."""
identifier = 'CP1234567'
business = create_business(identifier)

filing_meta = FilingMeta()
change_of_address.process(business, CHANGE_OF_ADDRESS_FILING['filing'], filing_meta, False)

delivery_address = business.delivery_address.one_or_none()
assert delivery_address
assert delivery_address.street == 'new delivery_address'
assert delivery_address.city == 'new delivery_address city'


@pytest.mark.parametrize('test_name, status, step, trigger_date, delay', [
(
'DELAY_IN_DISSOLUTION_STAGE_1',
BatchProcessing.BatchProcessingStatus.PROCESSING,
BatchProcessing.BatchProcessingStep.WARNING_LEVEL_1,
datetime.utcnow()+datedelta(days=42),
True
),
(
'DELAY_IN_DISSOLUTION_STAGE_2',
BatchProcessing.BatchProcessingStatus.PROCESSING,
BatchProcessing.BatchProcessingStep.WARNING_LEVEL_2,
datetime.utcnow()+datedelta(days=42),
True
),
(
'NO_DELAY_NOT_IN_DISSOLUTION_1',
BatchProcessing.BatchProcessingStatus.COMPLETED,
BatchProcessing.BatchProcessingStep.DISSOLUTION,
datetime.utcnow()+datedelta(days=42),
False
),
(
'NO_DELAY_NOT_IN_DISSOLUTION_2',
BatchProcessing.BatchProcessingStatus.WITHDRAWN,
BatchProcessing.BatchProcessingStep.WARNING_LEVEL_1,
datetime.utcnow()+datedelta(days=42),
False
),
(
'NO_DELAY_TRIGGER_DATE_MORE_THAN_60_DAYS_STAGE_1',
BatchProcessing.BatchProcessingStatus.PROCESSING,
BatchProcessing.BatchProcessingStep.WARNING_LEVEL_1,
datetime.utcnow()+datedelta(days=70),
False
),
(
'NO_DELAY_TRIGGER_DATE_MORE_THAN_60_DAYS_STAGE_2',
BatchProcessing.BatchProcessingStatus.PROCESSING,
BatchProcessing.BatchProcessingStep.WARNING_LEVEL_1,
datetime.utcnow()+datedelta(days=70),
False
)
])
def test_change_of_address_delay_dissolution(app, session, test_name, status, step, trigger_date, delay):
"""Assert that involuntary dissolution is delayed."""
identifier = 'CP1234567'
business = create_business(identifier)
batch = factory_batch()
batch_processing = factory_batch_processing(batch_id=batch.id,
business_id=business.id,
identifier=business.identifier,
status=status,
step=step,
trigger_date=trigger_date)

utc_now = datetime.utcnow()
dissolution_date = utc_now + datedelta(days=72)
trigger_date = batch_processing.trigger_date
delay_dissolution_date = utc_now + datedelta(days=134)
delay_trigger_date = utc_now + datedelta(days=62)

filing_meta = FilingMeta()

change_of_address.process(business, CHANGE_OF_ADDRESS_FILING['filing'], filing_meta, True)

if delay:
assert batch_processing.trigger_date.date() == delay_trigger_date.date()
assert batch_processing.meta_data.get('changeOfAddressDelay') is True
assert batch_processing.meta_data.get('targetDissolutionDate') == delay_dissolution_date.date().isoformat()
else:
assert batch_processing.trigger_date == trigger_date
assert batch_processing.meta_data.get('changeOfAddressDelay') is None
assert batch_processing.meta_data.get('targetDissolutionDate') == dissolution_date.date().isoformat()
Loading