Skip to content

Commit

Permalink
19649 filer - short form amalgamation (bcgov#2445)
Browse files Browse the repository at this point in the history
  • Loading branch information
vysakh-menon-aot authored Feb 7, 2024
1 parent b724198 commit e30435a
Show file tree
Hide file tree
Showing 3 changed files with 268 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,26 @@
import sentry_sdk
from entity_queue_common.service_utils import QueueException
from legal_api import db
from legal_api.models import AmalgamatingBusiness, Amalgamation, Business, Filing, RegistrationBootstrap
from legal_api.models import (
AmalgamatingBusiness,
Amalgamation,
Business,
Filing,
OfficeType,
PartyRole,
RegistrationBootstrap,
)
from legal_api.services.bootstrap import AccountService

from entity_filer.filing_meta import FilingMeta
from entity_filer.filing_processors.filing_components import aliases, business_info, business_profile, filings, shares
from entity_filer.filing_processors.filing_components import (
JSON_ROLE_CONVERTER,
aliases,
business_info,
business_profile,
filings,
shares,
)
from entity_filer.filing_processors.filing_components.offices import update_offices
from entity_filer.filing_processors.filing_components.parties import update_parties

Expand Down Expand Up @@ -107,10 +122,10 @@ def dissolve_amalgamating_business(business: Business, filing_rec: Filing):
db.session.add(business)


def process(business: Business, # pylint: disable=too-many-branches
def process(business: Business, # pylint: disable=too-many-branches, too-many-locals
filing: Dict,
filing_rec: Filing,
filing_meta: FilingMeta): # pylint: disable=too-many-branches
filing_meta: FilingMeta):
"""Process the incoming amalgamation application filing."""
# Extract the filing information for amalgamation
amalgamation_filing = filing.get('filing', {}).get('amalgamationApplication')
Expand Down Expand Up @@ -138,7 +153,8 @@ def process(business: Business, # pylint: disable=too-many-branches
business.state = Business.State.ACTIVE

amalgamation.filing_id = filing_rec.id
amalgamation.amalgamation_type = amalgamation_filing.get('type')
amalgamation_type = amalgamation_filing.get('type')
amalgamation.amalgamation_type = amalgamation_type
amalgamation.amalgamation_date = filing_rec.effective_date
amalgamation.court_approval = bool(amalgamation_filing.get('courtApproval'))
create_amalgamating_businesses(amalgamation_filing, amalgamation, filing_rec)
Expand All @@ -152,6 +168,18 @@ def process(business: Business, # pylint: disable=too-many-branches
if not business:
raise QueueException(f'amalgamationApplication {filing_rec.id}, Unable to create business.')

if amalgamation_type in [Amalgamation.AmalgamationTypes.horizontal.name,
Amalgamation.AmalgamationTypes.vertical.name]:
# Include/Replace director, office and shares by finding holding or primary business (won't be a foreign)
amalgamating_business = next(x for x in amalgamation.amalgamating_businesses
if x.role in [AmalgamatingBusiness.Role.holding.name,
AmalgamatingBusiness.Role.primary.name])
primary_or_holding_business = Business.find_by_internal_id(amalgamating_business.business_id)

_set_parties(primary_or_holding_business, filing_rec, amalgamation_filing)
_set_offices(primary_or_holding_business, amalgamation_filing)
_set_shares(primary_or_holding_business, amalgamation_filing)

if offices := amalgamation_filing.get('offices'):
update_offices(business, offices)

Expand Down Expand Up @@ -180,6 +208,68 @@ def process(business: Business, # pylint: disable=too-many-branches
return business, filing_rec, filing_meta


def _set_parties(primary_or_holding_business, filing_rec, amalgamation_filing):
parties = []
active_directors = PartyRole.get_active_directors(primary_or_holding_business.id,
filing_rec.effective_date.date())
# copy director
for director in active_directors:
director_json = director.json
director_json['roles'] = [{
'roleType': 'Director',
'appointmentDate': filing_rec.effective_date.isoformat()
}]

# cleanup director json
del director_json['officer']['id']
del director_json['role']
del director_json['appointmentDate']
if 'cessationDate' in director_json:
del director_json['cessationDate']
if 'deliveryAddress' in director_json:
del director_json['deliveryAddress']['id']
if 'mailingAddress' in director_json:
del director_json['mailingAddress']['id']

parties.append(director_json)

# copy completing party from filing json
for party_info in amalgamation_filing.get('parties'):
if comp_party_role := next((x for x in party_info.get('roles')
if JSON_ROLE_CONVERTER.get(x['roleType'].lower(), '')
== PartyRole.RoleTypes.COMPLETING_PARTY.value), None):
party_info['roles'] = [comp_party_role] # override roles to have only completing party
parties.append(party_info)
break
amalgamation_filing['parties'] = parties


def _set_offices(primary_or_holding_business, amalgamation_filing):
# copy offices
offices = {}
officelist = primary_or_holding_business.offices.all()
for i in officelist:
if i.office_type in [OfficeType.REGISTERED, OfficeType.RECORDS]:
offices[i.office_type] = {}
for address in i.addresses:
address_json = address.json
del address_json['id']
offices[i.office_type][f'{address.address_type}Address'] = address_json
amalgamation_filing['offices'] = offices


def _set_shares(primary_or_holding_business, amalgamation_filing):
# copy shares
share_classes = []
for share_class in primary_or_holding_business.share_classes.all():
share_class_json = share_class.json
del share_class_json['id']
for series in share_class_json.get('series', []):
del series['id']
share_classes.append(share_class_json)
amalgamation_filing['shareStructure'] = {'shareClasses': share_classes}


def post_process(business: Business, filing: Filing):
"""Post processing activities for amalgamation application.
Expand Down
32 changes: 31 additions & 1 deletion queue_services/entity-filer/tests/unit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
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
from legal_api.models import db, Filing, ShareClass, ShareSeries
from legal_api.models.colin_event_id import ColinEventId

AR_FILING = {
Expand Down Expand Up @@ -530,6 +530,36 @@ def create_party_role(business, party, roles, appointment_date):
return business



def create_share_class(business, no_of_shares=1, no_of_series_in_each_share=2):
"""Create a new share class and associated series."""
for i in range(no_of_shares):
share_class = ShareClass(
name=f'{business.identifier} Share Class {i}',
priority=1,
max_share_flag=True,
max_shares=100,
par_value_flag=True,
par_value=10,
currency='CAD',
special_rights_flag=False
)

share_class.series = []
for j in range(no_of_series_in_each_share):
share_series = ShareSeries(
name=f'{business.identifier} Share {i} Series {j}',
priority=1,
max_share_flag=True,
max_shares=50,
special_rights_flag=False
)
share_class.series.append(share_series)

business.share_classes.append(share_class)
business.save()


def factory_completed_filing(business, data_dict, filing_date=FROZEN_DATETIME, payment_token=None, colin_id=None):
"""Create a completed filing."""
if not payment_token:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@
from unittest.mock import patch

import pytest
from legal_api.models import Amalgamation, Business, Filing
from legal_api.models import AmalgamatingBusiness, Amalgamation, Business, Filing
from registry_schemas.example_data import AMALGAMATION_APPLICATION

from entity_filer.filing_processors.filing_components import business_info, business_profile
from entity_filer.worker import process_filing
from tests.unit import create_entity, create_filing
from tests.unit import create_entity, create_filing, create_office, create_office_address, create_party, create_party_role, create_share_class


async def test_amalgamation_application_process(app, session):
Expand All @@ -42,13 +42,14 @@ async def test_amalgamation_application_process(app, session):
filing['filing']['header'] = {'name': filing_type, 'date': '2019-04-08',
'certifiedBy': 'full name', 'email': '[email protected]', 'filingId': 1}
filing['filing'][filing_type] = copy.deepcopy(AMALGAMATION_APPLICATION)
del filing['filing'][filing_type]['amalgamatingBusinesses'][0]
filing['filing'][filing_type]['amalgamatingBusinesses'] = [
{
'role': 'amalgamating',
'role': AmalgamatingBusiness.Role.amalgamating.name,
'identifier': amalgamating_identifier_1
},
{
'role': 'amalgamating',
'role': AmalgamatingBusiness.Role.amalgamating.name,
'identifier': amalgamating_identifier_2
}
]
Expand Down Expand Up @@ -92,9 +93,140 @@ async def test_amalgamation_application_process(app, session):
assert amalgamation.court_approval == filing['filing'][filing_type]['courtApproval']

for amalgamating_business in amalgamation.amalgamating_businesses:
assert amalgamating_business.role.name == 'amalgamating'
assert amalgamating_business.business_id in [amalgamating_business_1_id, amalgamating_business_2_id]
dissolved_business = Business.find_by_internal_id(amalgamating_business.business_id)
assert dissolved_business.state == Business.State.HISTORICAL
assert dissolved_business.state_filing_id == filing_rec.id
assert dissolved_business.dissolution_date == effective_date
assert amalgamating_business.role.name == AmalgamatingBusiness.Role.amalgamating.name
if amalgamating_business.business_id:
assert amalgamating_business.business_id in [amalgamating_business_1_id, amalgamating_business_2_id]
dissolved_business = Business.find_by_internal_id(amalgamating_business.business_id)
assert dissolved_business.state == Business.State.HISTORICAL
assert dissolved_business.state_filing_id == filing_rec.id
assert dissolved_business.dissolution_date == effective_date
else:
assert amalgamating_business.foreign_jurisdiction
assert amalgamating_business.foreign_jurisdiction_region
assert amalgamating_business.foreign_name
assert amalgamating_business.foreign_identifier


@pytest.mark.parametrize(
'amalgamation_type, amalgamating_role',
[
(Amalgamation.AmalgamationTypes.horizontal.name, AmalgamatingBusiness.Role.primary.name),
(Amalgamation.AmalgamationTypes.vertical.name, AmalgamatingBusiness.Role.holding.name)
]
)
async def test_short_form_amalgamation_application_process(app, session, amalgamation_type, amalgamating_role):
"""Assert that the amalgamation application object is correctly populated to model objects."""
filing_type = 'amalgamationApplication'
amalgamating_identifier_1 = 'BC9891234'
amalgamating_identifier_2 = 'BC9891235'
nr_identifier = 'NR 1234567'
next_corp_num = 'BC0001095'

amalgamating_business_1 = create_entity(amalgamating_identifier_1, 'BC', f'{amalgamating_role} business 1')

office = create_office(amalgamating_business_1, 'registeredOffice')
office_delivery_address = create_office_address(amalgamating_business_1, office, 'delivery')
office_mailing_address = create_office_address(amalgamating_business_1, office, 'mailing')

create_share_class(amalgamating_business_1)

party = create_party({
'officer': {
'firstName': f'{amalgamating_business_1.identifier} first_name',
'lastName': 'Director',
'middleName': 'P',
},
'mailingAddress': {
'streetAddress': f'{amalgamating_business_1.identifier} mailing_address',
'addressCity': 'mailing_address city',
'addressCountry': 'CA',
'postalCode': 'H0H0H0',
'addressRegion': 'BC'
},
'deliveryAddress': {
'streetAddress': f'{amalgamating_business_1.identifier} delivery_address',
'addressCity': 'delivery_address city',
'addressCountry': 'CA',
'postalCode': 'H0H0H0',
'addressRegion': 'BC'
}
})
create_party_role(amalgamating_business_1, party, ['director'], datetime.utcnow())


amalgamating_business_1_id = amalgamating_business_1.id
amalgamating_business_2_id = create_entity(amalgamating_identifier_2, 'BC', 'amalgamating business 2').id

filing = {'filing': {}}
filing['filing']['header'] = {'name': filing_type, 'date': '2019-04-08',
'certifiedBy': 'full name', 'email': '[email protected]', 'filingId': 1}
filing['filing'][filing_type] = copy.deepcopy(AMALGAMATION_APPLICATION)
filing['filing'][filing_type]['type'] = amalgamation_type
del filing['filing'][filing_type]['amalgamatingBusinesses'][0]
filing['filing'][filing_type]['amalgamatingBusinesses'] = [
{
'role': amalgamating_role,
'identifier': amalgamating_identifier_1
},
{
'role': AmalgamatingBusiness.Role.amalgamating.name,
'identifier': amalgamating_identifier_2
}
]

filing['filing'][filing_type]['nameRequest']['nrNumber'] = nr_identifier

del filing['filing'][filing_type]['offices']
del filing['filing'][filing_type]['shareStructure']
del filing['filing'][filing_type]['parties'][0]['roles'][1]

filing_rec = create_filing('123', filing)
effective_date = datetime.now(timezone.utc)
filing_rec.effective_date = effective_date
filing_rec.save()

# test
filing_msg = {'filing': {'id': filing_rec.id}}
with patch.object(business_info, 'get_next_corp_num', return_value=next_corp_num):
with patch.object(business_profile, 'update_business_profile', return_value=HTTPStatus.OK):
await process_filing(filing_msg, app)

# Assertions
filing_rec = Filing.find_by_id(filing_rec.id)
business = Business.find_by_identifier(next_corp_num)

assert filing_rec.business_id == business.id
assert filing_rec.status == Filing.Status.COMPLETED.value
assert business.identifier
assert business.founding_date == effective_date
assert business.legal_type == filing['filing'][filing_type]['nameRequest']['legalType']
assert business.legal_name == filing['filing'][filing_type]['nameRequest']['legalName']
assert business.state == Business.State.ACTIVE

assert len(business.share_classes.all()) == 1
assert len(business.offices.all()) == 1
assert len(business.aliases.all()) == len(filing['filing'][filing_type]['nameTranslations'])
assert business.party_roles[0].role == 'director'
assert filing_rec.filing_party_roles[0].role == 'completing_party'

assert business.amalgamation
amalgamation: Amalgamation = business.amalgamation[0]
assert amalgamation.amalgamation_date == effective_date
assert amalgamation.filing_id == filing_rec.id
assert amalgamation.amalgamation_type.name == filing['filing'][filing_type]['type']
assert amalgamation.court_approval == filing['filing'][filing_type]['courtApproval']

for amalgamating_business in amalgamation.amalgamating_businesses:
assert amalgamating_business.role.name in [amalgamating_role, AmalgamatingBusiness.Role.amalgamating.name]
if amalgamating_business.business_id:
assert amalgamating_business.business_id in [amalgamating_business_1_id, amalgamating_business_2_id]
dissolved_business = Business.find_by_internal_id(amalgamating_business.business_id)
assert dissolved_business.state == Business.State.HISTORICAL
assert dissolved_business.state_filing_id == filing_rec.id
assert dissolved_business.dissolution_date == effective_date
else:
assert amalgamating_business.foreign_jurisdiction
assert amalgamating_business.foreign_jurisdiction_region
assert amalgamating_business.foreign_name
assert amalgamating_business.foreign_identifier

0 comments on commit e30435a

Please sign in to comment.