From 9ef825e0e850f6ae713093cbcb7509a5767ec072 Mon Sep 17 00:00:00 2001 From: Hongjing <60866283+chenhongjing@users.noreply.github.com> Date: Wed, 13 Dec 2023 16:45:57 -0800 Subject: [PATCH] 18784 Update allowable actions for amalgamation (#2352) * 18784 Signed-off-by: Hongjing Chen * 18784 Signed-off-by: Hongjing Chen * rename amalgamation to amalgamationApplication Signed-off-by: Hongjing Chen * fix unit tests Signed-off-by: Hongjing Chen * update schema version Signed-off-by: Hongjing Chen * update blocker check for FED Signed-off-by: Hongjing Chen * fixlinting Signed-off-by: Hongjing Chen * fix linting Signed-off-by: Hongjing Chen * rename & fix typo Signed-off-by: Hongjing Chen * simplify FED checks Signed-off-by: Hongjing Chen * update fed checks Signed-off-by: Hongjing Chen * Add future effective pending dissolution test for amalgamating businesses --------- Signed-off-by: Hongjing Chen Co-authored-by: argush3 --- legal-api/requirements.txt | 2 +- .../requirements/bcregistry-libraries.txt | 2 +- legal-api/src/legal_api/core/filing.py | 1 - legal-api/src/legal_api/core/meta/filing.py | 4 +- legal-api/src/legal_api/models/filing.py | 6 +- legal-api/src/legal_api/reports/report.py | 4 +- .../resources/v2/business/business.py | 2 +- .../business_filings/business_filings.py | 2 +- legal-api/src/legal_api/services/authz.py | 96 +++++++++++++------ .../tests/unit/core/test_filing_ledger.py | 6 +- legal-api/tests/unit/models/__init__.py | 6 +- .../tests/unit/resources/v2/test_business.py | 6 +- .../tests/unit/services/test_authorization.py | 68 +++++++++++-- 13 files changed, 148 insertions(+), 57 deletions(-) diff --git a/legal-api/requirements.txt b/legal-api/requirements.txt index 8c53dae3d5..07c82a3d53 100755 --- a/legal-api/requirements.txt +++ b/legal-api/requirements.txt @@ -60,5 +60,5 @@ minio==7.0.2 PyPDF2==1.26.0 reportlab==3.6.12 html-sanitizer==1.9.3 -git+https://github.com/bcgov/business-schemas.git@2.18.16#egg=registry_schemas +git+https://github.com/bcgov/business-schemas.git@2.18.18#egg=registry_schemas diff --git a/legal-api/requirements/bcregistry-libraries.txt b/legal-api/requirements/bcregistry-libraries.txt index 7c5614980b..aeb50703bd 100644 --- a/legal-api/requirements/bcregistry-libraries.txt +++ b/legal-api/requirements/bcregistry-libraries.txt @@ -1 +1 @@ -git+https://github.com/bcgov/business-schemas.git@2.18.16#egg=registry_schemas +git+https://github.com/bcgov/business-schemas.git@2.18.18#egg=registry_schemas diff --git a/legal-api/src/legal_api/core/filing.py b/legal-api/src/legal_api/core/filing.py index 6ae3f0a23c..107edc1404 100644 --- a/legal-api/src/legal_api/core/filing.py +++ b/legal-api/src/legal_api/core/filing.py @@ -60,7 +60,6 @@ class FilingTypes(str, Enum): AGMEXTENSION = 'agmExtension' AGMLOCATIONCHANGE = 'agmLocationChange' ALTERATION = 'alteration' - AMALGAMATION = 'amalgamation' AMALGAMATIONAPPLICATION = 'amalgamationApplication' AMENDEDAGM = 'amendedAGM' AMENDEDANNUALREPORT = 'amendedAnnualReport' diff --git a/legal-api/src/legal_api/core/meta/filing.py b/legal-api/src/legal_api/core/meta/filing.py index 2bbe489598..0a7db59abb 100644 --- a/legal-api/src/legal_api/core/meta/filing.py +++ b/legal-api/src/legal_api/core/meta/filing.py @@ -124,8 +124,8 @@ class FilingTitles(str, Enum): {'types': 'BC,BEN,BC,CC,ULC', 'outputs': ['noticeOfArticles', ]}, ] }, - 'amalgamation': { - 'name': 'amalgamation', + 'amalgamationApplication': { + 'name': 'amalgamationApplication', 'additional': [ {'types': 'BC,ULC,BEN,CC', 'outputs': ['noticeOfArticles', 'certificate']}, ], diff --git a/legal-api/src/legal_api/models/filing.py b/legal-api/src/legal_api/models/filing.py index 315afda0ee..1f76aef410 100644 --- a/legal-api/src/legal_api/models/filing.py +++ b/legal-api/src/legal_api/models/filing.py @@ -96,8 +96,8 @@ class Source(Enum): 'CC': 'ALTER' } }, - 'amalgamation': { - 'name': 'amalgamation', + 'amalgamationApplication': { + 'name': 'amalgamationApplication', 'temporaryCorpTypeCode': 'ATMP', 'regular': { 'name': 'regularAmalgamation', @@ -351,7 +351,7 @@ class Source(Enum): # breaking and more testing was req'd so did not make refactor when introducing this dictionary. 'dissolution': 'dissolutionType', 'restoration': 'type', - 'amalgamation': 'type' + 'amalgamationApplication': 'type' } __tablename__ = 'filings' diff --git a/legal-api/src/legal_api/reports/report.py b/legal-api/src/legal_api/reports/report.py index 596444fda8..a920695214 100644 --- a/legal-api/src/legal_api/reports/report.py +++ b/legal-api/src/legal_api/reports/report.py @@ -1091,9 +1091,9 @@ class ReportMeta: # pylint: disable=too-few-public-methods """Helper class to maintain the report meta information.""" reports = { - 'amalgamation': { + 'amalgamationApplication': { 'filingDescription': 'Amalgamation Application', - 'fileName': 'amalgamation' + 'fileName': 'amalgamationApplication' }, 'certificate': { 'filingDescription': 'Certificate of Incorporation', diff --git a/legal-api/src/legal_api/resources/v2/business/business.py b/legal-api/src/legal_api/resources/v2/business/business.py index c2fe1a3655..2936f6e64c 100644 --- a/legal-api/src/legal_api/resources/v2/business/business.py +++ b/legal-api/src/legal_api/resources/v2/business/business.py @@ -105,7 +105,7 @@ def post_businesses(): valid_filing_types = [ Filing.FILINGS['incorporationApplication']['name'], Filing.FILINGS['registration']['name'], - Filing.FILINGS['amalgamation']['name'] + Filing.FILINGS['amalgamationApplication']['name'] ] try: diff --git a/legal-api/src/legal_api/resources/v2/business/business_filings/business_filings.py b/legal-api/src/legal_api/resources/v2/business/business_filings/business_filings.py index dc49d00060..bcfc8ae22d 100644 --- a/legal-api/src/legal_api/resources/v2/business/business_filings/business_filings.py +++ b/legal-api/src/legal_api/resources/v2/business/business_filings/business_filings.py @@ -429,7 +429,7 @@ def put_basic_checks(identifier, filing_id, client_request, business) -> Tuple[d if filing_type not in [ Filing.FILINGS['incorporationApplication']['name'], Filing.FILINGS['registration']['name'], - Filing.FILINGS['amalgamation']['name'] + Filing.FILINGS['amalgamationApplication']['name'] ] and business is None: return ({'message': 'A valid business is required.'}, HTTPStatus.BAD_REQUEST) diff --git a/legal-api/src/legal_api/services/authz.py b/legal-api/src/legal_api/services/authz.py index defb30d3ea..3a11c0e88d 100644 --- a/legal-api/src/legal_api/services/authz.py +++ b/legal-api/src/legal_api/services/authz.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. """This manages all of the authentication and authorization service.""" -from datetime import datetime +from datetime import datetime, timezone from enum import Enum from http import HTTPStatus from typing import Final, List @@ -50,6 +50,14 @@ class BusinessBlocker(str, Enum): NOT_IN_GOOD_STANDING = 'NOT_IN_GOOD_STANDING' +class BusinessRequirement(str, Enum): + """Define an enum for business requirement scenarios.""" + + EXIST = 'EXIST' + NOT_EXIST = 'NOT_EXIST' + NO_RESTRICTION = 'NO_RESTRICTION' + + def authorized( # pylint: disable=too-many-return-statements identifier: str, jwt: JwtManager, action: List[str]) -> bool: """Assert that the user is authorized to create filings against the business identifier.""" @@ -138,26 +146,27 @@ def has_roles(jwt: JwtManager, roles: List[str]) -> bool: 'business': [BusinessBlocker.DEFAULT] } }, - 'amalgamation': { + 'amalgamationApplication': { + 'businessRequirement': BusinessRequirement.NO_RESTRICTION, 'regular': { 'legalTypes': ['BEN', 'BC', 'ULC', 'CC'], - 'ignoreBlockerChecksBusinessNotExists': True, 'blockerChecks': { - 'business': [BusinessBlocker.BUSINESS_FROZEN] + 'business': [BusinessBlocker.BUSINESS_FROZEN], + 'futureEffectiveFilings': ['dissolution'] } }, 'vertical': { 'legalTypes': ['BEN', 'BC', 'ULC', 'CC'], - 'ignoreBlockerChecksBusinessNotExists': True, 'blockerChecks': { - 'business': [BusinessBlocker.BUSINESS_FROZEN] + 'business': [BusinessBlocker.BUSINESS_FROZEN], + 'futureEffectiveFilings': ['dissolution'] } }, 'horizontal': { 'legalTypes': ['BEN', 'BC', 'ULC', 'CC'], - 'ignoreBlockerChecksBusinessNotExists': True, 'blockerChecks': { - 'business': [BusinessBlocker.BUSINESS_FROZEN] + 'business': [BusinessBlocker.BUSINESS_FROZEN], + 'futureEffectiveFilings': ['dissolution'] } } }, @@ -230,7 +239,8 @@ def has_roles(jwt: JwtManager, roles: List[str]) -> bool: }, 'incorporationApplication': { 'legalTypes': ['CP', 'BC', 'BEN', 'ULC', 'CC'], - 'businessExists': False # only show filing when providing allowable filings not specific to a business + # only show filing when providing allowable filings not specific to a business + 'businessRequirement': BusinessRequirement.NOT_EXIST }, 'registrarsNotation': { 'legalTypes': ['SP', 'GP', 'CP', 'BC', 'BEN', 'CC', 'ULC'] @@ -240,7 +250,8 @@ def has_roles(jwt: JwtManager, roles: List[str]) -> bool: }, 'registration': { 'legalTypes': ['SP', 'GP'], - 'businessExists': False # only show filing when providing allowable filings not specific to a business + # only show filing when providing allowable filings not specific to a business + 'businessRequirement': BusinessRequirement.NOT_EXIST }, 'specialResolution': { 'legalTypes': ['CP'], @@ -322,26 +333,27 @@ def has_roles(jwt: JwtManager, roles: List[str]) -> bool: 'business': [BusinessBlocker.DEFAULT] } }, - 'amalgamation': { + 'amalgamationApplication': { + 'businessRequirement': BusinessRequirement.NO_RESTRICTION, 'regular': { 'legalTypes': ['BEN', 'BC', 'ULC', 'CC'], - 'ignoreBlockerChecksBusinessNotExists': True, 'blockerChecks': { - 'business': [BusinessBlocker.BUSINESS_FROZEN] + 'business': [BusinessBlocker.BUSINESS_FROZEN], + 'futureEffectiveFilings': ['dissolution'] } }, 'vertical': { 'legalTypes': ['BEN', 'BC', 'ULC', 'CC'], - 'ignoreBlockerChecksBusinessNotExists': True, 'blockerChecks': { - 'business': [BusinessBlocker.BUSINESS_FROZEN] + 'business': [BusinessBlocker.BUSINESS_FROZEN], + 'futureEffectiveFilings': ['dissolution'] } }, 'horizontal': { 'legalTypes': ['BEN', 'BC', 'ULC', 'CC'], - 'ignoreBlockerChecksBusinessNotExists': True, 'blockerChecks': { - 'business': [BusinessBlocker.BUSINESS_FROZEN] + 'business': [BusinessBlocker.BUSINESS_FROZEN], + 'futureEffectiveFilings': ['dissolution'] } } }, @@ -387,11 +399,13 @@ def has_roles(jwt: JwtManager, roles: List[str]) -> bool: }, 'incorporationApplication': { 'legalTypes': ['CP', 'BC', 'BEN', 'ULC', 'CC'], - 'businessExists': False # only show filing when providing allowable filings not specific to a business + # only show filing when providing allowable filings not specific to a business + 'businessRequirement': BusinessRequirement.NOT_EXIST }, 'registration': { 'legalTypes': ['SP', 'GP'], - 'businessExists': False # only show filing when providing allowable filings not specific to a business + # only show filing when providing allowable filings not specific to a business + 'businessRequirement': BusinessRequirement.NOT_EXIST }, 'specialResolution': { 'legalTypes': ['CP'], @@ -475,16 +489,16 @@ def get_allowed_filings(business: Business, for allowable_filing_key, allowable_filing_value in allowable_filings.items(): # skip if business does not exist and filing is not required # skip if this filing does not need to be returned for existing businesses - # might re-active after update the amalgamation filing allowable method - # if bool(business) ^ allowable_filing_value.get('businessExists', True): - # continue + + business_status = allowable_filing_value.get('businessRequirement', BusinessRequirement.EXIST) + + if business_status != BusinessRequirement.NO_RESTRICTION and \ + bool(business) ^ (business_status == BusinessRequirement.EXIST): + continue allowable_filing_legal_types = allowable_filing_value.get('legalTypes', []) if allowable_filing_legal_types: - # will remove after update the amalgamation filing allowable method - if bool(business) ^ allowable_filing_value.get('businessExists', True): - continue is_blocker = has_blocker(business, state_filing, allowable_filing_value, business_blocker_dict) is_include_legal_type = legal_type in allowable_filing_legal_types is_allowable = not is_blocker and is_include_legal_type @@ -497,7 +511,9 @@ def get_allowed_filings(business: Business, continue filing_sub_type_items = \ - filter(lambda x: legal_type in x[1].get('legalTypes', []), allowable_filing_value.items()) + filter(lambda x: isinstance(x[1], dict) and legal_type in + x[1].get('legalTypes', []), allowable_filing_value.items()) + for filing_sub_type_item_key, filing_sub_type_item_value in filing_sub_type_items: is_allowable = not has_blocker(business, state_filing, filing_sub_type_item_value, business_blocker_dict) @@ -518,8 +534,7 @@ def get_allowed_filings(business: Business, def has_blocker(business: Business, state_filing: Filing, allowable_filing: dict, business_blocker_dict: dict): """Return True if allowable filing has a blocker.""" - ignore_blocker_checks_no_business = allowable_filing.get('ignoreBlockerChecksBusinessNotExists', False) - if ignore_blocker_checks_no_business and not bool(business): + if not business: return False if not (blocker_checks := allowable_filing.get('blockerChecks', {})): @@ -534,10 +549,10 @@ def has_blocker(business: Business, state_filing: Filing, allowable_filing: dict if has_blocker_invalid_state_filing(state_filing, blocker_checks): return True - if not bool(business): + if has_blocker_completed_filing(business, blocker_checks): return True - if has_blocker_completed_filing(business, blocker_checks): + if has_blocker_future_effective_filing(business, blocker_checks): return True if has_blocker_warning_filing(business.warnings, blocker_checks): @@ -645,6 +660,24 @@ def has_blocker_completed_filing(business: Business, blocker_checks: dict): return True +def has_blocker_future_effective_filing(business: Business, blocker_checks: dict): + """Check if business has a future effective filing.""" + if not (fed_filing_types := blocker_checks.get('futureEffectiveFilings', [])): + return False + + filing_type_pairs = [(parse_filing_info(x)) for x in fed_filing_types] + + pending_filings = Filing.get_filings_by_type_pairs(business.id, + filing_type_pairs, + [Filing.Status.PENDING.value], + True) + + now = datetime.utcnow().replace(tzinfo=timezone.utc) + is_fed = any(f.effective_date > now for f in pending_filings) + + return is_fed + + def has_filing_match(filing: Filing, filing_types: list): """Return if filing matches any filings provided in filing_types arg .""" for filing_type in filing_types: @@ -696,7 +729,8 @@ def get_allowed(state: Business.State, legal_type: str, jwt: JwtManager): if legal_type in legal_types: allowable_filing_types.append(allowable_filing_key) else: - sub_filing_types = [x for x in allowable_filing_value.items() if legal_type in x[1].get('legalTypes')] + sub_filing_types = [x for x in allowable_filing_value.items() + if isinstance(x[1], dict) and legal_type in x[1].get('legalTypes')] if sub_filing_types: allowable_filing_types.append({ allowable_filing_key: [sub_filing_type[0] for sub_filing_type in sub_filing_types] diff --git a/legal-api/tests/unit/core/test_filing_ledger.py b/legal-api/tests/unit/core/test_filing_ledger.py index 548335553d..bb9f1634cd 100644 --- a/legal-api/tests/unit/core/test_filing_ledger.py +++ b/legal-api/tests/unit/core/test_filing_ledger.py @@ -39,9 +39,9 @@ def load_ledger(business, founding_date): elif filing_meta['name'] == 'dissolution': filing['filing']['dissolution'] = {} filing['filing']['dissolution']['dissolutionType'] = 'voluntary' - elif filing_meta['name'] == 'amalgamation': - filing['filing']['amalgamation'] = {} - filing['filing']['amalgamation']['type'] = 'regular' + elif filing_meta['name'] == 'amalgamationApplication': + filing['filing']['amalgamationApplication'] = {} + filing['filing']['amalgamationApplication']['type'] = 'regular' f = factory_completed_filing(business, filing, filing_date=founding_date + datedelta.datedelta(months=i)) for c in range(i): comment = Comment() diff --git a/legal-api/tests/unit/models/__init__.py b/legal-api/tests/unit/models/__init__.py index b1c2631b98..6a7e9ea168 100644 --- a/legal-api/tests/unit/models/__init__.py +++ b/legal-api/tests/unit/models/__init__.py @@ -16,6 +16,7 @@ import base64 import uuid +from datedelta import datedelta from freezegun import freeze_time from registry_schemas.example_data import ANNUAL_REPORT from sqlalchemy_continuum import versioning_manager @@ -182,7 +183,8 @@ def factory_business_mailing_address(business): def factory_filing(business, data_dict, filing_date=FROZEN_DATETIME, filing_type=None, - filing_sub_type=None): + filing_sub_type=None, + is_future_effective=False): """Create a filing.""" filing = Filing() filing.business_id = business.id @@ -192,6 +194,8 @@ def factory_filing(business, data_dict, filing._filing_type = filing_type if filing_sub_type: filing._filing_sub_type = filing_sub_type + if is_future_effective: + filing.effective_date = datetime.utcnow() + datedelta(days=5) try: filing.save() except Exception as err: diff --git a/legal-api/tests/unit/resources/v2/test_business.py b/legal-api/tests/unit/resources/v2/test_business.py index ae27d96f39..98f8a8636a 100644 --- a/legal-api/tests/unit/resources/v2/test_business.py +++ b/legal-api/tests/unit/resources/v2/test_business.py @@ -74,7 +74,7 @@ def test_create_bootstrap_failure_filing(client, jwt): @pytest.mark.parametrize('filing_name', [ 'incorporationApplication', 'registration', - 'amalgamation' + 'amalgamationApplication' ]) def test_create_bootstrap_minimal_draft_filing(client, jwt, filing_name): """Assert that a minimal filing can be used to create a draft filing.""" @@ -349,7 +349,7 @@ def test_post_affiliated_businesses(session, client, jwt): draft_businesses = [ (identifiers[2], 'registration', Business.LegalTypes.BCOMP.value, None), (identifiers[3], 'incorporationApplication', Business.LegalTypes.SOLE_PROP.value, 'NR 1234567'), - (identifiers[4], 'amalgamation', Business.LegalTypes.COMP.value, 'NR 1234567')] + (identifiers[4], 'amalgamationApplication', Business.LegalTypes.COMP.value, 'NR 1234567')] # NB: these are real businesses now so temp should not get returned old_draft_businesses = [identifiers[4]] @@ -378,7 +378,7 @@ def test_post_affiliated_businesses(session, client, jwt): json_data['filing'][filing_name] = { 'nameRequest': {'nrNumber': draft_business[3]} } - if filing_name == 'amalgamation': + if filing_name == 'amalgamationApplication': json_data['filing'][filing_name] = { **json_data['filing'][filing_name], 'type': 'regular' diff --git a/legal-api/tests/unit/services/test_authorization.py b/legal-api/tests/unit/services/test_authorization.py index 63822efb77..a6cb6c9c36 100644 --- a/legal-api/tests/unit/services/test_authorization.py +++ b/legal-api/tests/unit/services/test_authorization.py @@ -205,9 +205,9 @@ class FilingKey(str, Enum): FilingKey.RESTRN_LTD_TO_FULL_LLC: {'displayName': 'Conversion to Full Restoration Application', 'feeCode': None, 'name': 'restoration', 'type': 'limitedRestorationToFull'}, FilingKey.PUT_BACK_ON: {'displayName': 'Correction - Put Back On', 'feeCode': 'NOFEE', 'name': 'putBackOn'}, - FilingKey.AMALGAMATION_REGULAR: {'name': 'amalgamation', 'type': 'regular', 'displayName': 'Regular Amalgamation', 'feeCode': 'AMALR'}, - FilingKey.AMALGAMATION_VERTICAL: {'name': 'amalgamation', 'type': 'vertical', 'displayName': 'Vertical Amalgamation', 'feeCode': 'AMALV'}, - FilingKey.AMALGAMATION_HORIZONTAL: {'name': 'amalgamation', 'type': 'horizontal', 'displayName': 'Horizontal Amalgamation', 'feeCode': 'AMALH'} + FilingKey.AMALGAMATION_REGULAR: {'name': 'amalgamationApplication', 'type': 'regular', 'displayName': 'Regular Amalgamation', 'feeCode': 'AMALR'}, + FilingKey.AMALGAMATION_VERTICAL: {'name': 'amalgamationApplication', 'type': 'vertical', 'displayName': 'Vertical Amalgamation', 'feeCode': 'AMALV'}, + FilingKey.AMALGAMATION_HORIZONTAL: {'name': 'amalgamationApplication', 'type': 'horizontal', 'displayName': 'Horizontal Amalgamation', 'feeCode': 'AMALH'} } BLOCKER_FILING_STATUSES = factory_incomplete_statuses() @@ -424,7 +424,7 @@ def mock_auth(one, two): # pylint: disable=unused-argument; mocks of library me 'registrarsNotation', 'registrarsOrder', 'specialResolution']), ('staff_active_corps', Business.State.ACTIVE, ['BC', 'BEN', 'CC', 'ULC'], 'staff', [STAFF_ROLE], ['adminFreeze', 'agmExtension', 'agmLocationChange', 'alteration', - {'amalgamation': ['regular', 'vertical', 'horizontal']}, 'annualReport', 'changeOfAddress', + {'amalgamationApplication': ['regular', 'vertical', 'horizontal']}, 'annualReport', 'changeOfAddress', 'changeOfDirectors', 'consentContinuationOut', 'continuationOut', 'correction', 'courtOrder', {'dissolution': ['voluntary', 'administrative']}, 'incorporationApplication', 'registrarsNotation', 'registrarsOrder', 'transition', @@ -439,7 +439,7 @@ def mock_auth(one, two): # pylint: disable=unused-argument; mocks of library me ['annualReport', 'changeOfAddress', 'changeOfDirectors', {'dissolution': ['voluntary']}, 'incorporationApplication', 'specialResolution']), ('user_active_corps', Business.State.ACTIVE, ['BC', 'BEN', 'CC', 'ULC'], 'general', [BASIC_USER], - ['agmExtension', 'agmLocationChange', 'alteration', {'amalgamation': ['regular', 'vertical', 'horizontal']}, + ['agmExtension', 'agmLocationChange', 'alteration', {'amalgamationApplication': ['regular', 'vertical', 'horizontal']}, 'annualReport', 'changeOfAddress', 'changeOfDirectors', 'consentContinuationOut', {'dissolution': ['voluntary']}, 'incorporationApplication', 'transition']), ('user_active_llc', Business.State.ACTIVE, ['LLC'], 'general', [BASIC_USER], []), @@ -1462,6 +1462,55 @@ def mock_auth(one, two): # pylint: disable=unused-argument; mocks of library me assert allowed_filing_types == expected +@pytest.mark.parametrize( + 'test_name,state,legal_types,username,roles,filing_types,filing_statuses,is_fed,expected', + [ + # active business - staff user + ('staff_active_corps', Business.State.ACTIVE, ['BC', 'BEN', 'CC', 'ULC'], 'staff', [STAFF_ROLE], + ['dissolution'], [Filing.Status.PENDING.value], True, + expected_lookup([FilingKey.ADMN_FRZE, + FilingKey.COURT_ORDER, + FilingKey.REGISTRARS_NOTATION, + FilingKey.REGISTRARS_ORDER, + FilingKey.TRANSITION])), + + # active business - general user + ('general_user_corps', Business.State.ACTIVE, ['BC', 'BEN', 'CC', 'ULC'], 'general', [BASIC_USER], + ['dissolution'], [Filing.Status.PENDING.value], True, expected_lookup([FilingKey.TRANSITION])) + ] +) +def test_allowed_filings_blocker_filing_amalgamations(monkeypatch, app, session, jwt, test_name, state, + legal_types, username, roles, filing_types, filing_statuses, + is_fed, + expected): + """Assert that get allowed returns valid filings when amalgamating business has blocker filings. + + A blocker filing in this instance is a pending future effective dissolution filing. + """ + token = helper_create_jwt(jwt, roles=roles, username=username) + headers = {'Authorization': 'Bearer ' + token} + + def mock_auth(one, two): # pylint: disable=unused-argument; mocks of library methods + return headers[one] + + with app.test_request_context(): + monkeypatch.setattr('flask.request.headers.get', mock_auth) + + for legal_type in legal_types: + for filing_status in filing_statuses: + for filing_type in filing_types: + business = create_business(legal_type, state) + filing_dict = FILING_DATA.get(filing_type, None) + create_incomplete_filing(business=business, + filing_name=filing_type, + filing_status=filing_status, + filing_dict=filing_dict, + filing_type=filing_type, + is_future_effective=is_fed) + allowed_filing_types = get_allowed_filings(business, state, legal_type, jwt) + assert allowed_filing_types == expected + + @pytest.mark.parametrize( 'test_name,state,legal_types,username,roles,expected', [ @@ -2261,15 +2310,20 @@ def create_incomplete_filing(business, filing_status, filing_dict: dict = copy.deepcopy(ANNUAL_REPORT), filing_type=None, - filing_sub_type=None): + filing_sub_type=None, + is_future_effective=False): """Create an incomplete filing of a given status.""" filing_dict['filing']['header']['name'] = filing_name if filing_dict: filing_dict = copy.deepcopy(filing_dict) - filing = factory_filing(business=business, data_dict=filing_dict, filing_sub_type=filing_sub_type) + filing = factory_filing(business=business, + data_dict=filing_dict, + filing_sub_type=filing_sub_type, + is_future_effective=is_future_effective) filing.skip_status_listener = True filing._status = filing_status filing._filing_type = filing_type + filing._filing_sub_type = filing_sub_type return filing