From 17f5cb4cb35404067b295371524eb29b469cb405 Mon Sep 17 00:00:00 2001 From: Vysakh Menon Date: Fri, 13 Sep 2024 12:06:36 -0700 Subject: [PATCH] 21754 continuationOut colin sync (#2987) --- colin-api/src/colin_api/models/__init__.py | 1 + colin-api/src/colin_api/models/business.py | 1 + colin-api/src/colin_api/models/cont_out.py | 110 ++++++++++++++++++ colin-api/src/colin_api/models/filing.py | 57 ++++++++- colin-api/src/colin_api/resources/filing.py | 5 +- .../resources/v2/business/colin_sync.py | 1 + 6 files changed, 170 insertions(+), 5 deletions(-) create mode 100644 colin-api/src/colin_api/models/cont_out.py diff --git a/colin-api/src/colin_api/models/__init__.py b/colin-api/src/colin_api/models/__init__.py index 29c6ddaaa..e2ec54740 100644 --- a/colin-api/src/colin_api/models/__init__.py +++ b/colin-api/src/colin_api/models/__init__.py @@ -1,6 +1,7 @@ """Model imports.""" from .address import Address from .business import Business +from .cont_out import ContOut from .corp_involved import CorpInvolved from .corp_name import CorpName from .corp_party import Party diff --git a/colin-api/src/colin_api/models/business.py b/colin-api/src/colin_api/models/business.py index bc8efc923..2b7c0156f 100644 --- a/colin-api/src/colin_api/models/business.py +++ b/colin-api/src/colin_api/models/business.py @@ -67,6 +67,7 @@ class CorpStateTypes(Enum): INVOLUNTARY_DISSOLUTION_NO_AR = 'HDF' INVOLUNTARY_DISSOLUTION_NO_TR = 'HDT' CONTINUE_IN = 'HCI' + CONTINUE_OUT = 'HCO' NUMBERED_CORP_NAME_SUFFIX = { TypeCodes.BCOMP.value: 'B.C. LTD.', diff --git a/colin-api/src/colin_api/models/cont_out.py b/colin-api/src/colin_api/models/cont_out.py new file mode 100644 index 000000000..92cbd8400 --- /dev/null +++ b/colin-api/src/colin_api/models/cont_out.py @@ -0,0 +1,110 @@ +# 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. +"""This module holds data about cont_out table.""" +from __future__ import annotations + +from typing import List + +from flask import current_app + +from colin_api.resources.db import DB + + +class ContOut: + """ContOut object.""" + + corp_num = None + start_event_id = None + can_jur_typ_cd = None + cont_out_dt = None + othr_juri_desc = None + home_company_nme = None + + def __init__(self): + """Initialize with all values None.""" + + def as_dict(self): + """Return dict camel case version of self.""" + return { + 'corpNum': self.corp_num, + 'startEventId': self.start_event_id, + 'canJurTypCd': self.can_jur_typ_cd, + 'contOutDt': self.cont_out_dt, + 'othrJuriDesc': self.othr_juri_desc, + 'homeCompanyNme': self.home_company_nme, + } + + @classmethod + def _create_cont_out_objs(cls, cursor) -> List: + """Return a cont_out obj by parsing cursor.""" + cont_outs = cursor.fetchall() + + cont_out_objs = [] + for cont_out in cont_outs: + cont_out = dict(zip([x[0].lower() for x in cursor.description], cont_out)) + cont_out_obj = ContOut() + cont_out_obj.corp_num = cont_out['corp_num'] + cont_out_obj.start_event_id = cont_out['start_event_id'] + cont_out_obj.can_jur_typ_cd = cont_out['can_jur_typ_cd'] + cont_out_obj.cont_out_dt = cont_out['cont_out_dt'] + cont_out_obj.othr_juri_desc = cont_out['othr_juri_desc'] + cont_out_obj.home_company_nme = cont_out['home_company_nme'] + cont_out_objs.append(cont_out_obj) + + return cont_out_objs + + @classmethod + def create_cont_out(cls, cursor, cont_out_obj) -> ContOut: + """Add record to the cont_out table.""" + try: + cursor.execute( + """ + insert into cont_out + (CORP_NUM, START_EVENT_ID, CAN_JUR_TYP_CD, CONT_OUT_DT, OTHR_JURI_DESC, HOME_COMPANY_NME) + values + (:corp_num, :start_event_id, :can_jur_typ_cd, TO_DATE(:cont_out_dt, 'YYYY-mm-dd'), + :othr_juri_desc, :home_company_nme) + """, + corp_num=cont_out_obj.corp_num, + start_event_id=cont_out_obj.start_event_id, + can_jur_typ_cd=cont_out_obj.can_jur_typ_cd, + cont_out_dt=cont_out_obj.cont_out_dt, + othr_juri_desc=cont_out_obj.othr_juri_desc, + home_company_nme=cont_out_obj.home_company_nme, + ) + + except Exception as err: + current_app.logger.error(f'Error inserting cont_out for event {cont_out_obj.event_id}.') + raise err + + @classmethod + def get_by_event(cls, cursor, event_id: str) -> List[ContOut]: + """Get the cont out with the given event id.""" + querystring = ( + """ + select corp_num, start_event_id, can_jur_typ_cd, cont_out_dt, othr_juri_desc, home_company_nme + from cont_out + where start_event_id=:event_id + """ + ) + + try: + if not cursor: + cursor = DB.connection.cursor() + cursor.execute(querystring, event_id=event_id) + return cls._create_cont_out_objs(cursor=cursor) + + except Exception as err: + current_app.logger.error(f'Error getting cont_out for event {event_id}') + raise err diff --git a/colin-api/src/colin_api/models/filing.py b/colin-api/src/colin_api/models/filing.py index a74a3ac83..655137345 100644 --- a/colin-api/src/colin_api/models/filing.py +++ b/colin-api/src/colin_api/models/filing.py @@ -35,6 +35,7 @@ ) # noqa: I001 from colin_api.models import ( # noqa: I001 Business, # noqa: I001 + ContOut, # noqa: I001 CorpInvolved, # noqa: I001 CorpName, # noqa: I001 FilingType, # noqa: I001 @@ -223,6 +224,17 @@ class FilingSource(Enum): Business.TypeCodes.ULC_CONTINUE_IN.value: 'CONTO', Business.TypeCodes.CCC_CONTINUE_IN.value: 'CONTO', }, + 'continuationOut': { + 'type_code_list': ['COUTI'], + Business.TypeCodes.BCOMP.value: 'COUTI', + Business.TypeCodes.BC_COMP.value: 'COUTI', + Business.TypeCodes.ULC_COMP.value: 'COUTI', + Business.TypeCodes.CCC_COMP.value: 'COUTI', + Business.TypeCodes.BCOMP_CONTINUE_IN.value: 'COUTI', + Business.TypeCodes.CONTINUE_IN.value: 'COUTI', + Business.TypeCodes.ULC_CONTINUE_IN.value: 'COUTI', + Business.TypeCodes.CCC_CONTINUE_IN.value: 'COUTI', + }, 'changeOfName': { 'type_code_list': ['OTNCN'], Business.TypeCodes.COOP.value: 'OTNCN', @@ -525,8 +537,9 @@ def _insert_filing(cls, cursor, filing, ar_date: str, agm_date: str): # pylint: 'AMLHB', 'AMALH', 'AMLHU', 'AMLHC', 'AMLVB', 'AMALV', 'AMLVU', 'AMLVC', 'CONTB', 'CONTI', 'CONTU', 'CONTC', - 'NOABE', 'NOALE', 'NOALR', 'NOALD', 'NOALA', 'NOALB', 'NOALU', 'NOALC', - 'CONTO', + 'NOABE', 'NOALE', 'NOALR', 'NOALD', + 'NOALA', 'NOALB', 'NOALU', 'NOALC', + 'CONTO', 'COUTI', 'REGSN', 'REGSO', 'COURT']: arrangement_ind = 'N' court_order_num = None @@ -1105,7 +1118,7 @@ def add_filing(cls, con, filing: Filing) -> int: try: if filing.filing_type not in ['alteration', 'amalgamationApplication', 'annualReport', 'changeOfAddress', 'changeOfDirectors', 'consentContinuationOut', 'continuationIn', - 'correction', 'courtOrder', + 'continuationOut', 'correction', 'courtOrder', 'dissolution', 'incorporationApplication', 'registrarsNotation', 'registrarsOrder', 'specialResolution', 'transition']: raise InvalidFilingTypeException(filing_type=filing.filing_type) @@ -1138,6 +1151,8 @@ def add_filing(cls, con, filing: Filing) -> int: cls._process_amalgamating_businesses(cursor, filing) elif filing.filing_type == 'continuationIn': cls._process_continuation_in(cursor, filing) + elif filing.filing_type == 'continuationOut': + cls._process_continuation_out(cursor, filing) if filing.filing_type == 'correction': cls._process_correction(cursor, business, filing, corp_num) @@ -1268,6 +1283,42 @@ 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_continuation_out(cls, cursor, filing): + """Process continuation out.""" + corp_num = filing.get_corp_num() + + cont_out = ContOut() + cont_out.corp_num = corp_num + cont_out.start_event_id = filing.event_id + cont_out.cont_out_dt = filing.body.get('continuationOutDate') + cont_out.home_company_nme = filing.body.get('legalName') + + foreign_jurisdiction = filing.body.get('foreignJurisdiction') + country_code = foreign_jurisdiction.get('country').upper() + region_code = (foreign_jurisdiction.get('region') or '').upper() + if country_code == 'CA': + if region_code == 'FEDERAL': + cont_out.can_jur_typ_cd = 'FD' + else: + cont_out.can_jur_typ_cd = region_code + else: + cont_out.can_jur_typ_cd = 'OT' + cont_out.othr_juri_desc = \ + f'{country_code}, {region_code}' if region_code else country_code + + ContOut.create_cont_out(cursor, cont_out) + + continued_to = cont_out.othr_juri_desc if cont_out.can_jur_typ_cd == 'OT' else cont_out.can_jur_typ_cd + cont_out_dt_str = datetime.datetime.fromisoformat(cont_out.cont_out_dt).strftime('%B %-d, %Y') + cls._insert_ledger_text( + cursor, + filing, + f'CONTINUED TO {continued_to} EFFECTIVE {cont_out_dt_str} UNDER THE NAME "{cont_out.home_company_nme}"' + ) + + Business.update_corp_state(cursor, filing.event_id, corp_num, Business.CorpStateTypes.CONTINUE_OUT.value) + @classmethod def _process_continuation_in(cls, cursor, filing): """Process continuation in.""" diff --git a/colin-api/src/colin_api/resources/filing.py b/colin-api/src/colin_api/resources/filing.py index a5b1815b9..76eff1e36 100644 --- a/colin-api/src/colin_api/resources/filing.py +++ b/colin-api/src/colin_api/resources/filing.py @@ -131,6 +131,7 @@ def post(legal_type, identifier, **kwargs): 'changeOfDirectors': json_data.get('changeOfDirectors', None), 'consentContinuationOut': json_data.get('consentContinuationOut', None), 'continuationIn': json_data.get('continuationIn', None), + 'continuationOut': json_data.get('continuationOut', None), 'courtOrder': json_data.get('courtOrder', None), 'dissolution': json_data.get('dissolution', None), 'incorporationApplication': json_data.get('incorporationApplication', None), @@ -214,7 +215,7 @@ def _add_filings(con, json_data: dict, filing_list: list, identifier: str) -> li for filing_type in filing_list: filing = Filing() filing.header = json_data['header'] - filing.filing_date = filing.header['date'] + filing.filing_date = convert_to_pacific_time(filing.header['date']) filing.filing_type = filing_type filing_body = filing_list[filing_type] filing.filing_sub_type = Filing.get_filing_sub_type(filing_type, filing_body) @@ -315,7 +316,7 @@ def delete(identifier, **kwargs): with con.cursor() as cursor: # Delete from AR prompt for the given corporation delete_ar_prompt = """ - DELETE FROM AR_PROMPT + DELETE FROM AR_PROMPT WHERE corp_num = :identifier """ cursor.execute(delete_ar_prompt, {'identifier': identifier}) diff --git a/legal-api/src/legal_api/resources/v2/business/colin_sync.py b/legal-api/src/legal_api/resources/v2/business/colin_sync.py index ea85be70a..bc41d5d2e 100644 --- a/legal-api/src/legal_api/resources/v2/business/colin_sync.py +++ b/legal-api/src/legal_api/resources/v2/business/colin_sync.py @@ -56,6 +56,7 @@ def get_completed_filings_for_colin(): if filing_json and filing.filing_type != 'lear_epoch' and \ (filing.filing_type != 'correction' or business.legal_type != Business.LegalTypes.COOP.value): filing_json['filingId'] = filing.id + filing_json['filing']['header']['date'] = filing.filing_date.isoformat() filing_json['filing']['header']['learEffectiveDate'] = filing.effective_date.isoformat() if not filing_json['filing'].get('business'): # ideally filing should have transaction_id once completed.