From 734d16409e68fff32d39d4bac20f76c9e2806e94 Mon Sep 17 00:00:00 2001 From: Kevin Zhang <54437031+kzdev420@users.noreply.github.com> Date: Thu, 18 Jan 2024 02:11:42 +0800 Subject: [PATCH 1/2] 18502 Filer conversion filing updates (#2377) * 18502 filer - conversion filing updates * add missing * fix naming * update start date * reuse exsiting func * rename * fix typo, start_date logic * fix missing --- .../change_of_registration.py | 142 ++----------- .../filing_processors/conversion.py | 45 ++-- .../filing_components/alternate_name.py | 195 ++++++++++++++++++ .../filing_processors/registration.py | 31 +-- 4 files changed, 225 insertions(+), 188 deletions(-) create mode 100644 queue_services/entity-filer/src/entity_filer/filing_processors/filing_components/alternate_name.py diff --git a/queue_services/entity-filer/src/entity_filer/filing_processors/change_of_registration.py b/queue_services/entity-filer/src/entity_filer/filing_processors/change_of_registration.py index 0d294ba8d7..e159a16449 100644 --- a/queue_services/entity-filer/src/entity_filer/filing_processors/change_of_registration.py +++ b/queue_services/entity-filer/src/entity_filer/filing_processors/change_of_registration.py @@ -29,6 +29,7 @@ ) from entity_filer.filing_processors.filing_components.parties import get_or_create_party, merge_all_parties from entity_filer.filing_processors.registration import get_partnership_name +from entity_filer.filing_processors.filing_components.alternate_name import update_partner_change, update_proprietor_change def process( @@ -41,18 +42,20 @@ def process( filing_meta.change_of_registration = {} match legal_entity.entity_type: case LegalEntity.EntityTypes.PARTNERSHIP: - _update_partner_change( - legal_entity, - change_filing_rec, - change_filing, - filing_meta + update_partner_change( + legal_entity=legal_entity, + filing_type="changeOfRegistration", + change_filing_rec=change_filing_rec, + change_filing=change_filing, + filing_meta=filing_meta.change_of_registration ) case _: # LegalEntity.EntityTypes.SOLE_PROP: # legal_entity might be a proprietor? - _update_sp_change( - legal_entity, - change_filing_rec, - change_filing, - filing_meta + update_proprietor_change( + legal_entity=legal_entity, + filing_type="changeOfRegistration", + change_filing_rec=change_filing_rec, + change_filing=change_filing, + filing_meta=filing_meta.change_of_registration ) # Update business office if present @@ -85,122 +88,3 @@ def post_process(business: LegalEntity, filing: Filing): THIS SHOULD NOT ALTER THE MODEL """ name_request.consume_nr(business, filing, "changeOfRegistration") - -def _update_partner_change( - legal_entity: LegalEntity, - change_filing_rec: Filing, - change_filing: Dict, - filing_meta: FilingMeta, -): - name_request = dpath.util.get(change_filing, "/changeOfRegistration/nameRequest", default=None) - if name_request and (to_legal_name := name_request.get("legalName")): - alternate_name = AlternateName.find_by_identifier(legal_entity.identifier) - parties_dict = dpath.util.get(change_filing, "/changeOfRegistration/parties") - - legal_entity.legal_name = get_partnership_name(parties_dict) - - legal_entity.alternate_names.remove(alternate_name) - alternate_name.end_date = change_filing_rec.effective_date - alternate_name.change_filing_id = change_filing_rec.id - # alternate_name.delete() - db.session.add(alternate_name) - db.session.commit() - db.session.delete(alternate_name) - db.session.commit() - - - new_alternate_name = AlternateName( - bn15=alternate_name.bn15, - change_filing_id=change_filing_rec.id, - end_date=None, - identifier=legal_entity.identifier, - name=to_legal_name, - name_type=AlternateName.NameType.OPERATING, - start_date=alternate_name.start_date, - registration_date=change_filing_rec.effective_date, - ) - legal_entity.alternate_names.append(new_alternate_name) - - filing_meta.change_of_registration = { - **filing_meta.change_of_registration, - "fromLegalName": alternate_name.name, - "toLegalName": to_legal_name, - } - - # Update Nature of LegalEntity - if ( - naics := change_filing.get("changeOfRegistration", {}) - .get("business", {}) - .get("naics") - ) and (naics_code := naics.get("naicsCode")): - if legal_entity.naics_code != naics_code: - filing_meta.change_of_registration = { - **filing_meta.change_of_registration, - **{ - "fromNaicsCode": legal_entity.naics_code, - "toNaicsCode": naics_code, - "naicsDescription": naics.get("naicsDescription"), - }, - } - legal_entity_info.update_naics_info(legal_entity, naics) - - -def _update_sp_change( - legal_entity: LegalEntity, - change_filing_rec: Filing, - change_filing: Dict, - filing_meta: FilingMeta, -): - name_request = dpath.util.get(change_filing, "/changeOfRegistration/nameRequest", default=None) - identifier = dpath.util.get(change_filing_rec.filing_json, "filing/business/identifier") - if name_request and (to_legal_name := name_request.get("legalName")): - alternate_name = AlternateName.find_by_identifier(identifier) - parties_dict = dpath.util.get(change_filing, "/changeOfRegistration/parties") - - # Find the Proprietor - proprietor = None - for party in parties_dict: - for role in party.get("roles"): - if role.get("roleType") == "Proprietor": - proprietor_dict = party - break - if proprietor_dict: - break - - if not proprietor_dict: - raise DefaultException( - f"No Proprietor in the SP registration for filing:{change_filing_rec.id}" - ) - - proprietor, delivery_address, mailing_address = get_or_create_party( - proprietor_dict, change_filing_rec - ) - if not proprietor: - raise DefaultException( - f"No Proprietor in the SP registration for filing:{change_filing_rec.id}" - ) - - alternate_name.end_date = change_filing_rec.effective_date - alternate_name.change_filing_id = change_filing_rec.id - # alternate_name.delete() - db.session.add(alternate_name) - db.session.commit() - db.session.delete(alternate_name) - db.session.commit() - - new_alternate_name = AlternateName( - identifier=identifier, - name_type=AlternateName.NameType.OPERATING, - change_filing_id=change_filing_rec.id, - end_date=None, - name=to_legal_name, - start_date=alternate_name.start_date, - registration_date=change_filing_rec.effective_date, - ) - proprietor.alternate_names.append(new_alternate_name) - - filing_meta.change_of_registration = { - **filing_meta.change_of_registration, - "fromLegalName": alternate_name.name, - "toLegalName": to_legal_name, - } diff --git a/queue_services/entity-filer/src/entity_filer/filing_processors/conversion.py b/queue_services/entity-filer/src/entity_filer/filing_processors/conversion.py index b961cfad05..78bedaa5ea 100644 --- a/queue_services/entity-filer/src/entity_filer/filing_processors/conversion.py +++ b/queue_services/entity-filer/src/entity_filer/filing_processors/conversion.py @@ -42,6 +42,7 @@ ) from entity_filer.filing_processors.filing_components.offices import update_offices from entity_filer.filing_processors.filing_components.parties import merge_all_parties +from entity_filer.filing_processors.filing_components.alternate_name import update_partner_change, update_proprietor_change def process( @@ -111,36 +112,22 @@ def _process_firms_conversion( filing_rec: Filing, filing_meta: FilingMeta, ): - # Name change if present - with suppress(IndexError, KeyError, TypeError): - name_request_json = dpath.util.get( - conversion_filing, "/filing/conversion/nameRequest" - ) - if name_request_json.get("legalName"): - from_legal_name = legal_entity.legal_name - legal_entity_info.set_legal_name( - legal_entity.identifier, legal_entity, name_request_json + match legal_entity.entity_type: + case LegalEntity.EntityTypes.PARTNERSHIP: + update_partner_change( + legal_entity=legal_entity, + filing_type="conversion", + change_filing_rec=filing_rec, + change_filing=conversion_filing, + filing_meta=filing_meta.conversion + ) + case _: # LegalEntity.EntityTypes.PERSON: # legal_entity might be a proprietor? + update_proprietor_change( + filing_type="conversion", + change_filing_rec=filing_rec, + change_filing=conversion_filing, + filing_meta=filing_meta.conversion ) - if from_legal_name != legal_entity.legal_name: - filing_meta.conversion = { - **filing_meta.conversion, - **{ - "fromLegalName": from_legal_name, - "toLegalName": legal_entity.legal_name, - }, - } - # Update Nature of Business - if ( - naics := conversion_filing.get("filing", {}) - .get("conversion", {}) - .get("legal_entity", {}) - .get("naics") - ) and naics.get("naicsDescription"): - legal_entity_info.update_naics_info(legal_entity, naics) - filing_meta.conversion = { - **filing_meta.conversion, - **{"naicsDescription": naics.get("naicsDescription")}, - } # Update legal_entity office if present with suppress(IndexError, KeyError, TypeError): diff --git a/queue_services/entity-filer/src/entity_filer/filing_processors/filing_components/alternate_name.py b/queue_services/entity-filer/src/entity_filer/filing_processors/filing_components/alternate_name.py new file mode 100644 index 0000000000..737b36ed13 --- /dev/null +++ b/queue_services/entity-filer/src/entity_filer/filing_processors/filing_components/alternate_name.py @@ -0,0 +1,195 @@ +# Copyright © 2020 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. +"""Manages the parties and party roles for a LegalEntity.""" +from __future__ import annotations + +import datetime +import dpath +from typing import Dict, List, Optional, Tuple + +from business_model import db +from business_model import AlternateName +from business_model import Filing +from business_model import LegalEntity + +from entity_filer import db +from entity_filer.exceptions import DefaultException +from entity_filer.filing_meta import FilingMeta +from entity_filer.filing_processors.filing_components import legal_entity_info +from entity_filer.filing_processors.filing_components.parties import get_or_create_party +from entity_filer.utils.legislation_datetime import LegislationDatetime + + +def update_partner_change( + legal_entity: LegalEntity, + filing_type: str, + change_filing_rec: Filing, + change_filing: Dict, + filing_meta: Dict, +): + name_request = dpath.util.get(change_filing, f"/{filing_type}/nameRequest", default=None) + if name_request and (to_legal_name := name_request.get("legalName")): + alternate_name = AlternateName.find_by_identifier(legal_entity.identifier) + parties_dict = dpath.util.get(change_filing, f"/{filing_type}/parties") + + legal_entity.legal_name = get_partnership_name(parties_dict) + + legal_entity.alternate_names.remove(alternate_name) + alternate_name.end_date = change_filing_rec.effective_date + alternate_name.change_filing_id = change_filing_rec.id + + if start := change_filing.get("filing", {}).get(f"{filing_type}", {}).get("startDate"): + start_date = LegislationDatetime.as_utc_timezone_from_legislation_date_str( + start + ) + else: + start_date = alternate_name.start_date + # alternate_name.delete() + db.session.add(alternate_name) + db.session.commit() + db.session.delete(alternate_name) + db.session.commit() + + + new_alternate_name = AlternateName( + bn15=alternate_name.bn15, + change_filing_id=change_filing_rec.id, + end_date=None, + identifier=legal_entity.identifier, + name=to_legal_name, + name_type=AlternateName.NameType.OPERATING, + start_date=start_date, + registration_date=change_filing_rec.effective_date, + ) + legal_entity.alternate_names.append(new_alternate_name) + + filing_meta = { + **filing_meta, + "fromLegalName": alternate_name.name, + "toLegalName": to_legal_name, + } + + # Update Nature of LegalEntity + if ( + naics := change_filing.get(f"{filing_type}", {}) + .get("business", {}) + .get("naics") + ) and (naics_code := naics.get("naicsCode")): + if legal_entity.naics_code != naics_code: + filing_meta = { + **filing_meta, + **{ + "fromNaicsCode": legal_entity.naics_code, + "toNaicsCode": naics_code, + "naicsDescription": naics.get("naicsDescription"), + }, + } + legal_entity_info.update_naics_info(legal_entity, naics) + + +def update_proprietor_change( + filing_type: str, + change_filing_rec: Filing, + change_filing: Dict, + filing_meta: Dict, +): + name_request = dpath.util.get(change_filing, f"/{filing_type}/nameRequest", default=None) + identifier = dpath.util.get(change_filing_rec.filing_json, "filing/business/identifier") + if name_request and (to_legal_name := name_request.get("legalName")): + alternate_name = AlternateName.find_by_identifier(identifier) + parties_dict = dpath.util.get(change_filing, f"/{filing_type}/parties") + + # Find the Proprietor + proprietor = None + for party in parties_dict: + for role in party.get("roles"): + if role.get("roleType") == "Proprietor": + proprietor_dict = party + break + if proprietor_dict: + break + + if not proprietor_dict: + raise DefaultException( + f"No Proprietor in the SP {filing_type} for filing:{change_filing_rec.id}" + ) + + proprietor, delivery_address, mailing_address = get_or_create_party( + proprietor_dict, change_filing_rec + ) + if not proprietor: + raise DefaultException( + f"No Proprietor in the SP {filing_type} for filing:{change_filing_rec.id}" + ) + + if start := change_filing.get("filing", {}).get(f"{filing_type}", {}).get("startDate"): + start_date = LegislationDatetime.as_utc_timezone_from_legislation_date_str( + start + ) + else: + start_date = alternate_name.start_date + + alternate_name.end_date = change_filing_rec.effective_date + alternate_name.change_filing_id = change_filing_rec.id + # alternate_name.delete() + db.session.add(alternate_name) + db.session.commit() + db.session.delete(alternate_name) + db.session.commit() + + new_alternate_name = AlternateName( + identifier=identifier, + name_type=AlternateName.NameType.OPERATING, + change_filing_id=change_filing_rec.id, + end_date=None, + name=to_legal_name, + start_date=start_date, + registration_date=change_filing_rec.effective_date, + ) + proprietor.alternate_names.append(new_alternate_name) + + filing_meta = { + **filing_meta, + "fromLegalName": alternate_name.name, + "toLegalName": to_legal_name, + } + + +def get_partnership_name(parties_dict: dict): + """Set the legal_name of the partnership.""" + parties = [] + # get all parties in an array + for party in parties_dict: + if officer := party.get("officer"): + if org_name := officer.get("organizationName"): + parties.append(org_name.upper()) + continue + + name = officer["lastName"] + if first_name := officer.get("firstName"): + name = f"{name} {first_name}" + if middle_name := officer.get("middleName"): + name = f"{name} {middle_name}" + parties.append(name.upper()) + + if len(parties) < 2: + return parties[0] + + parties.sort() + if parties and len(parties) > 2: + legal_name_str = ", ".join(parties[:2]) + legal_name_str = f"{legal_name_str}, et al" + else: + legal_name_str = ", ".join(parties) + return legal_name_str diff --git a/queue_services/entity-filer/src/entity_filer/filing_processors/registration.py b/queue_services/entity-filer/src/entity_filer/filing_processors/registration.py index 510ab0ab7b..96796aceee 100644 --- a/queue_services/entity-filer/src/entity_filer/filing_processors/registration.py +++ b/queue_services/entity-filer/src/entity_filer/filing_processors/registration.py @@ -35,7 +35,7 @@ create_entity_with_addresses, ) from entity_filer.filing_processors.filing_components.parties import get_or_create_party - +from entity_filer.filing_processors.filing_components.alternate_name import get_partnership_name def update_affiliation(business: LegalEntity, filing: Filing): """Create an affiliation for the business and remove the bootstrap.""" @@ -300,32 +300,3 @@ def set_naics(legal_entity: LegalEntity, naics_dict: dict): """Set the NAICS fields for a business.""" legal_entity.naics_code = naics_dict["naicsCode"] legal_entity.naics_description = naics_dict["naicsDescription"] - - -def get_partnership_name(parties_dict: dict): - """Set the legal_name of the partnership.""" - parties = [] - # get all parties in an array - for party in parties_dict: - if officer := party.get("officer"): - if org_name := officer.get("organizationName"): - parties.append(org_name.upper()) - continue - - name = officer["lastName"] - if first_name := officer.get("firstName"): - name = f"{name} {first_name}" - if middle_name := officer.get("middleName"): - name = f"{name} {middle_name}" - parties.append(name.upper()) - - if len(parties) < 2: - return parties[0] - - parties.sort() - if parties and len(parties) > 2: - legal_name_str = ", ".join(parties[:2]) - legal_name_str = f"{legal_name_str}, et al" - else: - legal_name_str = ", ".join(parties) - return legal_name_str From 50cf58e44242bb5e7e96272d5a9c10598ed52515 Mon Sep 17 00:00:00 2001 From: Hongjing <60866283+chenhongjing@users.noreply.github.com> Date: Fri, 19 Jan 2024 11:14:29 -0800 Subject: [PATCH 2/2] 19191 Updated models in legal-api to use NAICS fields in AlternateName (#2396) * 19191-updates for legal-api Signed-off-by: Hongjing Chen * remove unused constant Signed-off-by: Hongjing Chen * revert Signed-off-by: Hongjing Chen * revert-2 Signed-off-by: Hongjing Chen --------- Signed-off-by: Hongjing Chen --- .../src/legal_api/models/alternate_name.py | 12 ++++++++++++ legal-api/src/legal_api/models/legal_entity.py | 17 +++++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/legal-api/src/legal_api/models/alternate_name.py b/legal-api/src/legal_api/models/alternate_name.py index ecac1fc949..1e1b9e70fd 100644 --- a/legal-api/src/legal_api/models/alternate_name.py +++ b/legal-api/src/legal_api/models/alternate_name.py @@ -40,6 +40,9 @@ class NameType(BaseEnum): "name", "name_type", "start_date", + "naics_key", + "naics_code", + "naics_description" ] } @@ -50,6 +53,9 @@ class NameType(BaseEnum): bn15 = db.Column("bn15", db.String(20), nullable=True) start_date = db.Column("start_date", db.DateTime(timezone=True), nullable=False) end_date = db.Column("end_date", db.DateTime(timezone=True), nullable=True) + naics_key = db.Column("naics_key", db.String(50), nullable=True) + naics_code = db.Column("naics_code", db.String(10), nullable=True) + naics_description = db.Column("naics_description", db.String(300), nullable=True) # parent keys legal_entity_id = db.Column("legal_entity_id", db.Integer, db.ForeignKey("legal_entities.id")) @@ -62,3 +68,9 @@ def save(self): """Save the object to the database immediately.""" db.session.add(self) db.session.commit() + + @classmethod + def find_by_identifier(cls, identifier: str) -> AlternateName | None: + """Return None or the AlternateName found by its registration number.""" + alternate_name = cls.query.filter_by(identifier=identifier).one_or_none() + return alternate_name diff --git a/legal-api/src/legal_api/models/legal_entity.py b/legal-api/src/legal_api/models/legal_entity.py index 40cc857f02..e423acd522 100644 --- a/legal-api/src/legal_api/models/legal_entity.py +++ b/legal-api/src/legal_api/models/legal_entity.py @@ -786,9 +786,22 @@ def find_by_legal_name(cls, legal_name: str = None): @classmethod def find_by_identifier(cls, identifier: str = None): """Return a Business by the id assigned by the Registrar.""" + if not identifier or not cls.validate_identifier( + entity_type=None, identifier=identifier + ): + return None + legal_entity = None - if identifier: - non_entity_types = [LegalEntity.EntityTypes.PERSON.value, LegalEntity.EntityTypes.ORGANIZATION.value] + + if identifier.startswith("FM"): + if alt_name := AlternateName.find_by_identifier(identifier): + legal_entity = cls.find_by_id(alt_name.legal_entity_id) + else: + non_entity_types = [ + LegalEntity.EntityTypes.PERSON.value, + LegalEntity.EntityTypes.ORGANIZATION.value, + ] + legal_entity = ( cls.query.filter(~LegalEntity.entity_type.in_(non_entity_types)) .filter_by(identifier=identifier)