Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 19 additions & 19 deletions queue_services/business-filer/poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion queue_services/business-filer/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "business-filer"
version = "3.0.11"
version = "3.0.12"
description = "Business Registry Filer Service"
authors = [
{name = "thor",email = "1042854+thorwolpert@users.noreply.github.com"}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@
shares,
update_address,
)
from business_filer.filing_processors.filing_components.relationships import (
cease_relationships,
create_relationships,
update_relationship_addresses,
update_relationship_entity_info,
)

CEASE_ROLE_MAPPING = {
**dict.fromkeys(Business.CORPS, PartyRole.RoleTypes.DIRECTOR.value),
Expand Down Expand Up @@ -114,6 +120,22 @@
party_json = dpath.get(correction_filing, "/correction/parties")
update_parties(business, party_json, correction_filing_rec)

# Update relationships (newer schema for parties)
with suppress(IndexError, KeyError, TypeError):
relationships = dpath.get(correction_filing, "/correction/relationships")
create_relationships(relationships, business, correction_filing_rec)
cease_relationships(relationships,
business,
[
PartyRole.RoleTypes.DIRECTOR.value,
PartyRole.RoleTypes.LIQUIDATOR.value,
PartyRole.RoleTypes.RECEIVER.value
],
filing_meta.application_date)
update_relationship_addresses(relationships, business)
update_relationship_entity_info(relationships, business)
_set_lear_only(correction_filing, correction_filing_rec, relationships, business)

# update court order, if any is present
with suppress(IndexError, KeyError, TypeError):
court_order_json = dpath.get(correction_filing, "/correction/courtOrder")
Expand Down Expand Up @@ -276,3 +298,29 @@
address = Address.find_by_id(updated_address.get("id"))
if address:
update_address(address, updated_address)


def _set_lear_only(correction_filing: dict, filing_rec: Filing, relationships: list[dict], business: Business):

Check warning on line 303 in queue_services/business-filer/src/business_filer/filing_processors/filing_components/correction.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove the unused function parameter "business".

See more on https://sonarcloud.io/project/issues?id=bcgov_lear&issues=AZz4ZkxLEi8P_DWfrRly&open=AZz4ZkxLEi8P_DWfrRly&pullRequest=4151
"""Set lear_only if the only changes are to receivers and/or liquidators."""
def _has_director_role(relationship: dict):
"""Return True if the relationship contains a director role."""
return any(role for role in relationship["roles"] if role["roleType"].lower() == "director")

if (
(
not any((
# below are the only changes the colin api supports for corrections
bool(dpath.get(correction_filing, "/correction/nameRequest", default=None)),
bool(dpath.get(correction_filing, "/correction/nameTranslations", default=None)),
bool(dpath.get(correction_filing, "/correction/offices", default=None)),
bool(dpath.get(correction_filing, "/correction/parties", default=None)),
bool(dpath.get(correction_filing, "/correction/shareStructure", default=None)),
bool(dpath.get(correction_filing, "/correction/resolution", default=None)))
)) and (
relationships and
# colin-api only supports relationships changes to directors
not any(relationship for relationship in relationships if _has_director_role(relationship))
)
):
filing_rec.lear_only = True

139 changes: 139 additions & 0 deletions queue_services/business-filer/tests/unit/test_filer/test_correction.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
# 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.
"""The Test Suite to ensure that the worker is operating correctly for corrections."""
import copy
import pytest
import random

from business_model.models import Business, Filing, PartyRole
from registry_schemas.example_data import (
CHANGE_OF_DIRECTORS,
CHANGE_OF_RECEIVERS,
CHANGE_OF_LIQUIDATORS,
CORRECTION_COL,
CORRECTION_COR,
FILING_TEMPLATE
)

from business_filer.common.filing_message import FilingMessage
from business_filer.services.filer import process_filing
from tests.unit import create_business, create_filing


COD = copy.deepcopy(CHANGE_OF_DIRECTORS)
COD['directors'][0]['actions'] = ['appointed']
COD['directors'][1]['actions'] = ['appointed']

CORRECTION_COD = copy.deepcopy(CORRECTION_COL)
CORRECTION_COD['filing']['correction']['correctedFilingType'] = 'changeOfDirectors'
CORRECTION_COD['filing']['correction']['relationships'][0]['roles'][0]['roleType'] = 'Director'


def _assert_common_data(business: Business, filing: Filing):
"""Assert the expected common data was updated by the filing processing."""
assert filing.transaction_id
assert filing.business_id == business.id
assert filing.status == Filing.Status.COMPLETED.value


def _get_filing(filing_type: str, data: dict, identifier = 'BC1234567', needs_template = True):
"""Return the filing json, payment id and identifier."""
payment_id = str(random.SystemRandom().getrandbits(0x58))
if needs_template:
filing = copy.deepcopy(FILING_TEMPLATE)
filing['filing'][filing_type] = copy.deepcopy(data)
else:
filing = copy.deepcopy(data)

filing['filing']['header']['name'] = filing_type
filing['filing']['business']['identifier'] = identifier
filing['filing']['business']['legalType'] = 'BC'
return filing, payment_id, identifier


@pytest.mark.parametrize('filing_name, original_data, correction_data, expected_lear_only', [
('changeOfDirectors', COD, CORRECTION_COD, False),
('changeOfLiquidators', CHANGE_OF_LIQUIDATORS, CORRECTION_COL, True),
('changeOfReceivers', CHANGE_OF_RECEIVERS, CORRECTION_COR, True),
])
def test_process_correction_filing_with_relationships(app, session, mocker, filing_name, original_data, correction_data, expected_lear_only):
"""Assert that correction filings can be applied to the model correctly."""
# mock out the email sender and event publishing
mocker.patch('business_filer.services.publish_event.PublishEvent.publish_email_message', return_value=None)
mocker.patch('business_filer.services.publish_event.PublishEvent.publish_event', return_value=None)
mocker.patch('business_filer.filing_processors.filing_components.business_profile.update_business_profile',
return_value=None)
mocker.patch('business_filer.services.AccountService.update_entity', return_value=None)

orig_filing, payment_id, identifier = _get_filing(filing_name, original_data)
business = create_business(identifier)
orig_filing_rec = create_filing(payment_id, orig_filing, business.id)

# process original filing
filing_msg = FilingMessage(filing_identifier=orig_filing_rec.id)
process_filing(filing_msg)
orig_processed_filing: Filing = Filing.find_by_id(orig_filing_rec.id)
# sanity checks
_assert_common_data(business, orig_processed_filing)
party_roles = business.party_roles.all()
assert len(party_roles) == 2

# setup correction
correction_filing, corrected_payment_id, _ = _get_filing('correction', correction_data, business.identifier, False)
expected_given_name = 'corrected given name'
expected_mailing_street = 'corrected mailing street'
expected_delivery_street = 'corrected delivery street'
corrected_party_id = party_roles[0].party.id
correction_filing['filing']['correction']['correctedFilingId'] = orig_filing_rec.id
correction_filing['filing']['correction']['relationships'][0]['entity']['identifier'] = corrected_party_id
correction_filing['filing']['correction']['relationships'][0]['entity']['givenName'] = expected_given_name
correction_filing['filing']['correction']['relationships'][0]['mailingAddress']['streetAddress'] = expected_mailing_street
correction_filing['filing']['correction']['relationships'][0]['deliveryAddress']['streetAddress'] = expected_delivery_street

correction_filing_rec = create_filing(corrected_payment_id, correction_filing, business.id)

# process original filing
correction_filing_msg = FilingMessage(filing_identifier=correction_filing_rec.id)
process_filing(correction_filing_msg)
correction_processed_filing: Filing = Filing.find_by_id(correction_filing_rec.id)
# assert changes

Check warning on line 130 in queue_services/business-filer/tests/unit/test_filer/test_correction.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this commented out code.

See more on https://sonarcloud.io/project/issues?id=bcgov_lear&issues=AZzpCaTPh1oMZE21Xbtb&open=AZzpCaTPh1oMZE21Xbtb&pullRequest=4151
_assert_common_data(business, correction_processed_filing)
assert correction_processed_filing.lear_only == expected_lear_only
party_roles: list[PartyRole] = business.party_roles.all()
assert len(party_roles) == 2
for role in party_roles:
if role.party.id == corrected_party_id:
assert role.party.first_name == expected_given_name.upper()
assert role.party.mailing_address.street == expected_mailing_street
assert role.party.delivery_address.street == expected_delivery_street
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,8 @@ def tests_filer_resolution_dates_change(app, session, mocker, test_name, legal_t

# Check outcome
business = Business.find_by_internal_id(business_id)
filing = Filing.find_by_id(filing_id)
assert filing.lear_only == False

resolution_dates = [res.resolution_date for res in business.resolutions.all()]
if 'add_resolution_dates' in test_name:
Expand Down Expand Up @@ -839,6 +841,8 @@ def tests_filer_share_class_and_series_change(app, session, mocker, test_name, l

# Check outcome
business = Business.find_by_internal_id(business_id)
filing = Filing.find_by_id(filing_id)
assert filing.lear_only == False

if 'add_share_class' in test_name:
assert len(business.share_classes.all()) == 4
Expand Down Expand Up @@ -912,6 +916,7 @@ def test_comment_only_correction(app, session, mocker, test_name):
process_filing(filing_msg)

final_filing = Filing.find_by_id(filing_id)
assert final_filing.lear_only == False
meta_data = final_filing.meta_data.get('correction', {})
assert meta_data.get('commentOnly')

Expand Down