Skip to content

Commit

Permalink
19794 colin sync for amalgamationApplication (bcgov#2837)
Browse files Browse the repository at this point in the history
  • Loading branch information
vysakh-menon-aot authored Jul 17, 2024
1 parent 4830d33 commit a628d79
Show file tree
Hide file tree
Showing 11 changed files with 279 additions and 80 deletions.
1 change: 1 addition & 0 deletions colin-api/src/colin_api/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Model imports."""
from .address import Address
from .business import Business
from .corp_involved import CorpInvolved
from .corp_name import CorpName
from .corp_party import Party
from .filing_type import FilingType
Expand Down
6 changes: 5 additions & 1 deletion colin-api/src/colin_api/models/business.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ class CorpStateTypes(Enum):

VOLUNTARY_DISSOLUTION = 'HDV'
ADMINISTRATIVE_DISSOLUTION = 'HDA'
AMALGAMATED = 'HAM'

NUMBERED_CORP_NAME_SUFFIX = {
TypeCodes.BCOMP.value: 'B.C. LTD.',
Expand Down Expand Up @@ -173,7 +174,10 @@ def _get_bn_15s(cls, cursor, identifiers: List) -> Dict:
for row in cursor.fetchall():
row = dict(zip([x[0].lower() for x in cursor.description], row))
if row['bn_15']:
bn_15s[f'BC{row["corp_num"]}'] = row['bn_15']
if row['corp_num'].isdecimal(): # valid only for BC
bn_15s[f'BC{row["corp_num"]}'] = row['bn_15']
else:
bn_15s[row['corp_num']] = row['bn_15']
return bn_15s

except Exception as err:
Expand Down
121 changes: 121 additions & 0 deletions colin-api/src/colin_api/models/corp_involved.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# 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.
"""Meta information about the service.
Currently this only provides API versioning information
"""
from __future__ import annotations

from typing import List

from flask import current_app

from colin_api.resources.db import DB


class CorpInvolved:
"""Corp Involved object."""

event_id = None
corp_involve_id = None
corp_num = None
can_jur_typ_cd = None
adopted_corp_ind = None
home_juri_num = None
othr_juri_desc = None
foreign_nme = None

def __init__(self):
"""Initialize with all values None."""

def as_dict(self):
"""Return dict camel case version of self."""
return {
'eventId': self.event_id,
'corpInvolveId': self.corp_involve_id,
'corpNum': self.corp_num,
'canJurTypCd': self.can_jur_typ_cd,
'adoptedCorpInd': self.adopted_corp_ind,
'homeJuriNum': self.home_juri_num,
'othrJuriDesc': self.othr_juri_desc,
'foreignName': self.foreign_nme,
}

@classmethod
def _create_corp_involved_objs(cls, cursor) -> List:
"""Return a CorpInvolved obj by parsing cursor."""
corps_involved = cursor.fetchall()

corp_involved_objs = []
for corp_involved in corps_involved:
corp_involved = dict(zip([x[0].lower() for x in cursor.description], corp_involved))
corp_involved_obj = CorpInvolved()
corp_involved_obj.event_id = corp_involved['event_id']
corp_involved_obj.corp_involve_id = corp_involved['corp_involve_id']
corp_involved_obj.corp_num = corp_involved['corp_num']
corp_involved_obj.can_jur_typ_cd = corp_involved['can_jur_typ_cd']
corp_involved_obj.adopted_corp_ind = corp_involved['adopted_corp_ind']
corp_involved_obj.home_juri_num = corp_involved['home_juri_num']
corp_involved_obj.othr_juri_desc = corp_involved['othr_juri_desc']
corp_involved_obj.foreign_nme = corp_involved['foreign_nme']
corp_involved_objs.append(corp_involved_obj)

return corp_involved_objs

@classmethod
def create_corp_involved(cls, cursor, corp_involved_obj) -> CorpInvolved:
"""Add record to the CORP INVOLVED table."""
try:
cursor.execute(
"""
insert into CORP_INVOLVED (EVENT_ID, CORP_INVOLVE_ID, CORP_NUM, CAN_JUR_TYP_CD, ADOPTED_CORP_IND,
HOME_JURI_NUM, OTHR_JURI_DESC, FOREIGN_NME)
values (:event_id, :corp_involve_id, :corp_num, :can_jur_typ_cd, :adopted_corp_ind,
:home_juri_num, :othr_juri_desc, :foreign_nme)
""",
event_id=corp_involved_obj.event_id,
corp_involve_id=corp_involved_obj.corp_involve_id,
corp_num=corp_involved_obj.corp_num,
can_jur_typ_cd=corp_involved_obj.can_jur_typ_cd,
adopted_corp_ind=corp_involved_obj.adopted_corp_ind,
home_juri_num=corp_involved_obj.home_juri_num,
othr_juri_desc=corp_involved_obj.othr_juri_desc,
foreign_nme=corp_involved_obj.foreign_nme,
)

except Exception as err:
current_app.logger.error(f'Error inserting corp involved for event {corp_involved_obj.event_id}.')
raise err

@classmethod
def get_by_event(cls, cursor, event_id: str) -> List[CorpInvolved]:
"""Get the corps involved with the given event id."""
querystring = (
"""
select event_id, corp_involve_id, corp_num, can_jur_typ_cd, adopted_corp_ind, home_juri_num,
othr_juri_desc, foreign_nme, dd_event_id
from corp_involved
where event_id=:event_id
"""
)

try:
if not cursor:
cursor = DB.connection.cursor()
cursor.execute(querystring, event_id=event_id)
return cls._create_corp_involved_objs(cursor=cursor)

except Exception as err:
current_app.logger.error(f'error getting corp involved for event {event_id}')
raise err
127 changes: 90 additions & 37 deletions colin-api/src/colin_api/models/filing.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
PartiesNotFoundException, # noqa: I001
UnableToDetermineCorpTypeException, # noqa: I001
) # noqa: I001
from colin_api.models import Business, CorpName, FilingType, Office, Party, ShareObject
from colin_api.models import Business, CorpInvolved, CorpName, FilingType, Office, Party, ShareObject
from colin_api.resources.db import DB
from colin_api.utils import convert_to_json_date, convert_to_json_datetime, convert_to_snake

Expand Down Expand Up @@ -111,8 +111,30 @@ class FilingSource(Enum):
Business.TypeCodes.COOP.value: 'OTSPE',
},
'amalgamationApplication': {
'type_code_list': ['OTAMA'],
Business.TypeCodes.COOP.value: 'OTAMA',
'sub_type_property': 'type',
'sub_type_list': ['regular', 'horizontal', 'vertical'],
'type_code_list': ['OTAMA', 'AMALR', 'AMLRU', 'AMALH', 'AMLHU', 'AMALV', 'AMLVU'],
'regular': {
Business.TypeCodes.COOP.value: 'OTAMA',
Business.TypeCodes.BCOMP.value: 'AMALR',
Business.TypeCodes.BC_COMP.value: 'AMALR',
Business.TypeCodes.ULC_COMP.value: 'AMLRU',
Business.TypeCodes.CCC_COMP.value: 'AMALR'
},
'horizontal': {
Business.TypeCodes.COOP.value: 'OTAMA',
Business.TypeCodes.BCOMP.value: 'AMALH',
Business.TypeCodes.BC_COMP.value: 'AMALH',
Business.TypeCodes.ULC_COMP.value: 'AMLHU',
Business.TypeCodes.CCC_COMP.value: 'AMALH'
},
'vertical': {
Business.TypeCodes.COOP.value: 'OTAMA',
Business.TypeCodes.BCOMP.value: 'AMALV',
Business.TypeCodes.BC_COMP.value: 'AMALV',
Business.TypeCodes.ULC_COMP.value: 'AMLVU',
Business.TypeCodes.CCC_COMP.value: 'AMALV'
}
},
'dissolved': {
'type_code_list': ['OTDIS'],
Expand Down Expand Up @@ -425,35 +447,19 @@ def _insert_filing(cls, cursor, filing, ar_date: str, agm_date: str): # pylint:
effective_dt=filing.effective_date,
filing_date=filing.filing_date
)
elif filing_type_code in ['NOCAD', 'BEINC', 'ICORP', 'ICORU', 'ICORC', 'CRBIN', 'TRANS']:
insert_stmnt = insert_stmnt + ', arrangement_ind, ods_typ_cd) '
values_stmnt = values_stmnt + ", 'N', 'F')"
cursor.execute(
insert_stmnt + values_stmnt,
event_id=filing.event_id,
filing_type_code=filing_type_code,
effective_dt=filing.effective_date
)
elif filing_type_code in ['NOALA', 'NOALB', 'NOALC', 'NOALE', 'NOALR', 'NOALU']:
arragement_ind = 'N'
elif filing_type_code in ['NOCAD', 'CRBIN', 'TRANS',
'BEINC', 'ICORP', 'ICORU', 'ICORC',
'AMALR', 'AMALH', 'AMALV',
'NOALA', 'NOALB', 'NOALC', 'NOALE', 'NOALR', 'NOALU',
'REGSN', 'REGSO', 'COURT']:
arrangement_ind = 'N'
court_order_num = None
if court_order := filing.body.get('courtOrder', None):
arragement_ind = 'Y' if court_order.get('effectOfOrder', None) else 'N'
court_order_num = court_order['fileNumber']

insert_stmnt = insert_stmnt + ', arrangement_ind, court_order_num, ods_typ_cd) '
values_stmnt = values_stmnt + ", :arragement_ind, :court_order_num, 'F')"
cursor.execute(
insert_stmnt + values_stmnt,
event_id=filing.event_id,
filing_type_code=filing_type_code,
effective_dt=filing.effective_date,
arragement_ind=arragement_ind,
court_order_num=court_order_num
)
elif filing_type_code in ['REGSN', 'REGSO', 'COURT']:
arrangement_ind = 'Y' if filing.body.get('effectOfOrder', '') == 'planOfArrangement' else 'N'
court_order_num = filing.body.get('fileNumber', None)
if filing_type_code in ['REGSN', 'REGSO', 'COURT']:
arrangement_ind = 'Y' if filing.body.get('effectOfOrder', '') == 'planOfArrangement' else 'N'
court_order_num = filing.body.get('fileNumber', None)
elif court_order := filing.body.get('courtOrder', None):
arrangement_ind = 'Y' if court_order.get('effectOfOrder', None) else 'N'
court_order_num = court_order.get('fileNumber', None)

insert_stmnt = insert_stmnt + ', arrangement_ind, court_order_num, ods_typ_cd) '
values_stmnt = values_stmnt + ", :arrangement_ind, :court_order_num, 'F')"
Expand Down Expand Up @@ -990,10 +996,10 @@ def add_administrative_dissolution_event(cls, con, corp_num) -> int:
def add_filing(cls, con, filing: Filing) -> int:
"""Add new filing to COLIN tables."""
try:
if filing.filing_type not in ['annualReport', 'changeOfAddress', 'changeOfDirectors',
'incorporationApplication', 'alteration', 'transition', 'correction',
'registrarsNotation', 'registrarsOrder', 'courtOrder', 'dissolution',
'specialResolution']:
if filing.filing_type not in ['alteration', 'amalgamationApplication', 'annualReport', 'changeOfAddress',
'changeOfDirectors', 'correction', 'courtOrder', 'dissolution',
'incorporationApplication', 'registrarsNotation', 'registrarsOrder',
'specialResolution', 'transition']:
raise InvalidFilingTypeException(filing_type=filing.filing_type)

if filing.filing_sub_type \
Expand All @@ -1020,6 +1026,9 @@ def add_filing(cls, con, filing: Filing) -> int:
# create new filing
cls._insert_filing(cursor=cursor, filing=filing, ar_date=ar_date, agm_date=agm_date)

if filing.filing_type == 'amalgamationApplication':
cls._process_amalgamating_businesses(cursor, filing)

if filing.filing_type == 'correction':
cls._process_correction(cursor, business, filing, corp_num)
else:
Expand Down Expand Up @@ -1133,6 +1142,50 @@ def is_filing_type_match(cls, filing: Filing, filing_type: str, filing_sub_type:
"""Return whether filing has specificed filing type and filing sub-type."""
return filing.filing_type == filing_type and filing.filing_sub_type == filing_sub_type

@classmethod
def _process_amalgamating_businesses(cls, cursor, filing):
"""Process amalgamating businesses."""
for index, amalgamating_business in enumerate(filing.body.get('amalgamatingBusinesses', [])):
corp_involved = CorpInvolved()
corp_involved.event_id = filing.event_id
corp_involved.corp_involve_id = index

identifier = amalgamating_business.get('identifier')

if ((foreign_jurisdiction := amalgamating_business.get('foreignJurisdiction', {})) and
not (identifier.startswith('A') and # is expro
foreign_jurisdiction.get('country') == 'CA' and
foreign_jurisdiction.get('region') == 'BC')):
corp_involved.home_juri_num = identifier
corp_involved.foreign_nme = amalgamating_business.get('legalName')

country_code = foreign_jurisdiction.get('country').upper()
region_code = (foreign_jurisdiction.get('region') or '').upper()
if country_code == 'CA':
if region_code == 'FEDERAL':
corp_involved.can_jur_typ_cd = 'FD'
else:
corp_involved.can_jur_typ_cd = region_code
else:
corp_involved.can_jur_typ_cd = 'OT'
corp_involved.othr_juri_desc = \
f'{country_code}, {region_code}' if region_code else country_code
else:
# strip prefix BC
if identifier.startswith('BC'):
identifier = identifier[-7:]
corp_involved.corp_num = identifier

if amalgamating_business['role'] in ['holding', 'primary']:
corp_involved.adopted_corp_ind = 'Y'

Business.update_corp_state(cursor,
filing.event_id,
identifier,
Business.CorpStateTypes.AMALGAMATED.value)

CorpInvolved.create_corp_involved(cursor, corp_involved)

@classmethod
# pylint: disable=too-many-arguments;
def _process_ar(cls, cursor, filing: Filing, corp_num: str, ar_date: str, agm_date: str, filing_source: str) -> str:
Expand Down Expand Up @@ -1185,7 +1238,7 @@ def _process_office(cls, cursor, filing: Filing) -> str:
office_type=office_type
)
# create new ledger text for address change
if filing.filing_type != 'incorporationApplication':
if filing.filing_type not in ['amalgamationApplication', 'incorporationApplication']:
office_desc = (office_type.replace('O', ' O')).title()
if text:
text = f'{text} Change to the {office_desc}.'
Expand Down Expand Up @@ -1249,7 +1302,7 @@ def _process_directors(cls, cursor, filing: Filing, business: Business, corp_num
@classmethod
def _create_corp_name(cls, cursor, filing: Filing, corp_num: str, name: str = None):
"""Create name."""
if filing.filing_type == 'incorporationApplication':
if filing.filing_type in ['amalgamationApplication', 'incorporationApplication']:
# create corp state
Business.create_corp_state(cursor=cursor, corp_num=corp_num, event_id=filing.event_id)
elif filing.filing_type == 'alteration':
Expand Down
2 changes: 1 addition & 1 deletion colin-api/src/colin_api/models/reset.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ def reset_filings(cls, start_date: str = None, end_date: str = None, identifiers
raise err

@classmethod
def reset_filings_by_event(cls, event_ids: list = []):
def reset_filings_by_event(cls, event_ids: list = []): # pylint: disable=dangerous-default-value
"""Reset changes made for given event ids."""
# initialize reset object
reset_obj = Reset()
Expand Down
3 changes: 2 additions & 1 deletion colin-api/src/colin_api/resources/business.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,8 @@ def get(info_type, legal_type=None, identifier=None): # pylint: disable = too-m
if not json_data or not json_data['identifiers']:
return jsonify({'message': 'No input data provided'}), HTTPStatus.BAD_REQUEST
# remove the BC prefix
identifiers = [x[-7:] for x in json_data['identifiers']]
identifiers = [x[-7:] if identifier.startswith('BC') else x
for x in json_data['identifiers']]
bn_15s = Business._get_bn_15s( # pylint: disable = protected-access; internal call
cursor=cursor,
identifiers=identifiers
Expand Down
7 changes: 4 additions & 3 deletions colin-api/src/colin_api/resources/filing.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ def post(legal_type, identifier, **kwargs):
'changeOfDirectors': json_data.get('changeOfDirectors', None),
'annualReport': json_data.get('annualReport', None),
'incorporationApplication': json_data.get('incorporationApplication', None),
'amalgamationApplication': json_data.get('amalgamationApplication', None),
'alteration': json_data.get('alteration', None),
'transition': json_data.get('transition', None),
'registrarsNotation': json_data.get('registrarsNotation', None),
Expand Down Expand Up @@ -213,10 +214,10 @@ def _add_filings(con, json_data: dict, filing_list: list, identifier: str) -> li
# get utc lear effective date and convert to pacific time for insert into oracle
filing.effective_date = convert_to_pacific_time(filing.header['learEffectiveDate'])

if filing_type != 'incorporationApplication':
filing.business = Business.find_by_identifier(identifier, con=con)
else:
if filing_type in ['amalgamationApplication', 'incorporationApplication']:
filing.business = Business.create_corporation(con, json_data)
else:
filing.business = Business.find_by_identifier(identifier, con=con)
# add the new filing
event_id = Filing.add_filing(con, filing)
filings_added.append({'event_id': event_id,
Expand Down
Loading

0 comments on commit a628d79

Please sign in to comment.