Skip to content

Commit

Permalink
23348 - Add allowable actions for notice of withdrawal (bcgov#3014)
Browse files Browse the repository at this point in the history
* Add notice of withdrawal for existing business
  • Loading branch information
AimeeGao authored Oct 8, 2024
1 parent 0a2c234 commit 9227509
Show file tree
Hide file tree
Showing 2 changed files with 212 additions and 6 deletions.
31 changes: 30 additions & 1 deletion legal-api/src/legal_api/services/authz.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class BusinessBlocker(str, Enum):
NOT_IN_GOOD_STANDING = 'NOT_IN_GOOD_STANDING'
AMALGAMATING_BUSINESS = 'AMALGAMATING_BUSINESS'
IN_DISSOLUTION = 'IN_DISSOLUTION'
FILING_WITHDRAWAL = 'FILING_WITHDRAWAL'


class BusinessRequirement(str, Enum):
Expand Down Expand Up @@ -314,6 +315,12 @@ def get_allowable_filings_dict():
'business': [BusinessBlocker.DEFAULT]
}
}
},
'noticeOfWithdrawal': {
'legalTypes': ['BC', 'BEN', 'CC', 'ULC', 'C', 'CBEN', 'CUL', 'CCC'],
'blockerChecks': {
'business': [BusinessBlocker.FILING_WITHDRAWAL]
}
}
},
Business.State.HISTORICAL: {
Expand Down Expand Up @@ -648,7 +655,8 @@ def business_blocker_check(business: Business, is_ignore_draft_blockers: bool =
BusinessBlocker.DRAFT_PENDING: False,
BusinessBlocker.NOT_IN_GOOD_STANDING: False,
BusinessBlocker.AMALGAMATING_BUSINESS: False,
BusinessBlocker.IN_DISSOLUTION: False
BusinessBlocker.IN_DISSOLUTION: False,
BusinessBlocker.FILING_WITHDRAWAL: False
}

if not business:
Expand All @@ -671,6 +679,9 @@ def business_blocker_check(business: Business, is_ignore_draft_blockers: bool =
if business.in_dissolution:
business_blocker_checks[BusinessBlocker.IN_DISSOLUTION] = True

if has_notice_of_withdrawal_filing_blocker(business):
business_blocker_checks[BusinessBlocker.FILING_WITHDRAWAL] = True

return business_blocker_checks


Expand Down Expand Up @@ -791,6 +802,24 @@ def has_blocker_warning_filing(warnings: List, blocker_checks: dict):
return warning_matches


def has_notice_of_withdrawal_filing_blocker(business: Business):
"""Check if there are any blockers specific to Notice of Withdrawal."""
if business.admin_freeze:
return True

filing_statuses = [Filing.Status.DRAFT.value,
Filing.Status.PENDING.value,
Filing.Status.PENDING_CORRECTION.value,
Filing.Status.ERROR.value]
blocker_filing_matches = Filing.get_filings_by_status(business.id, filing_statuses)
if any(blocker_filing_matches):
return True

now = datetime.now(timezone.utc)
paid_filings = Filing.get_filings_by_status(business.id, [Filing.Status.PAID.value])
return not any(f.effective_date and f.effective_date > now for f in paid_filings)


def get_allowed(state: Business.State, legal_type: str, jwt: JwtManager):
"""Get allowed type of filing types for the current user."""
user_role = 'general'
Expand Down
187 changes: 182 additions & 5 deletions legal-api/tests/unit/services/test_authorization.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ class FilingKey(str, Enum):
AMALGAMATION_REGULAR = 'AMALGAMATION_REGULAR'
AMALGAMATION_VERTICAL = 'AMALGAMATION_VERTICAL'
AMALGAMATION_HORIZONTAL = 'AMALGAMATION_HORIZONTAL'
NOTICE_OF_WITHDRAWAL = 'NOTICE_OF_WITHDRAWAL'


EXPECTED_DATA = {
Expand Down Expand Up @@ -219,7 +220,8 @@ class FilingKey(str, Enum):
FilingKey.PUT_BACK_ON: {'displayName': 'Correction - Put Back On', 'feeCode': 'NOFEE', 'name': 'putBackOn'},
FilingKey.AMALGAMATION_REGULAR: {'name': 'amalgamationApplication', 'type': 'regular', 'displayName': 'Amalgamation Application (Regular)', 'feeCode': 'AMALR'},
FilingKey.AMALGAMATION_VERTICAL: {'name': 'amalgamationApplication', 'type': 'vertical', 'displayName': 'Amalgamation Application Short-form (Vertical)', 'feeCode': 'AMALV'},
FilingKey.AMALGAMATION_HORIZONTAL: {'name': 'amalgamationApplication', 'type': 'horizontal', 'displayName': 'Amalgamation Application Short-form (Horizontal)', 'feeCode': 'AMALH'}
FilingKey.AMALGAMATION_HORIZONTAL: {'name': 'amalgamationApplication', 'type': 'horizontal', 'displayName': 'Amalgamation Application Short-form (Horizontal)', 'feeCode': 'AMALH'},
FilingKey.NOTICE_OF_WITHDRAWAL: {'displayName': 'Notice of Withdrawal', 'feeCode': 'NWITH', 'name': 'noticeOfWithdrawal'}
}

EXPECTED_DATA_CONT_IN = {
Expand Down Expand Up @@ -297,7 +299,9 @@ class FilingKey(str, Enum):
'displayName': 'Amalgamation Application Short-form (Vertical)', 'feeCode': None},
FilingKey.AMALGAMATION_HORIZONTAL: {'name': 'amalgamationApplication', 'type': 'horizontal',
'displayName': 'Amalgamation Application Short-form (Horizontal)',
'feeCode': None}
'feeCode': None},
FilingKey.NOTICE_OF_WITHDRAWAL: {'displayName': 'Notice of Withdrawal', 'feeCode': 'NWITH',
'name': 'noticeOfWithdrawal'}
}

BLOCKER_FILING_STATUSES = factory_incomplete_statuses()
Expand Down Expand Up @@ -527,13 +531,14 @@ def mock_auth(one, two): # pylint: disable=unused-argument; mocks of library me
'changeOfDirectors', 'consentContinuationOut', 'continuationOut', 'correction', 'courtOrder',
{'dissolution': ['voluntary', 'administrative']}, 'incorporationApplication',
'registrarsNotation', 'registrarsOrder', 'transition',
{'restoration': ['limitedRestorationExtension', 'limitedRestorationToFull']}]),
{'restoration': ['limitedRestorationExtension', 'limitedRestorationToFull']}, 'noticeOfWithdrawal']),
('staff_active_continue_in_corps', Business.State.ACTIVE, ['C', 'CBEN', 'CUL', 'CCC'], 'staff', [STAFF_ROLE],
['adminFreeze', 'agmExtension', 'agmLocationChange', 'alteration',
{'amalgamationApplication': ['regular', 'vertical', 'horizontal']}, 'annualReport', 'changeOfAddress',
'changeOfDirectors', 'continuationIn', 'consentContinuationOut', 'continuationOut', 'correction',
'courtOrder', {'dissolution': ['voluntary', 'administrative']}, 'registrarsNotation', 'registrarsOrder',
'transition', {'restoration': ['limitedRestorationExtension', 'limitedRestorationToFull']}]),
'transition', {'restoration': ['limitedRestorationExtension', 'limitedRestorationToFull']},
'noticeOfWithdrawal']),
('staff_active_llc', Business.State.ACTIVE, ['LLC'], 'staff', [STAFF_ROLE], []),
('staff_active_firms', Business.State.ACTIVE, ['SP', 'GP'], 'staff', [STAFF_ROLE],
['adminFreeze', 'changeOfRegistration', 'conversion', 'correction', 'courtOrder',
Expand Down Expand Up @@ -1938,7 +1943,13 @@ def mock_auth(one, two): # pylint: disable=unused-argument; mocks of library me
filing_sub_type=filing_sub_type,
is_future_effective=is_fed)
allowed_filing_types = get_allowed_filings(business, state, legal_type, jwt)
assert allowed_filing_types == expected

current_expected = expected.copy()
if username == 'staff' and filing_status == Filing.Status.PAID.value:
notice_of_withdrawal = expected_lookup([FilingKey.NOTICE_OF_WITHDRAWAL])[0]
if notice_of_withdrawal not in current_expected:
current_expected.append(notice_of_withdrawal)
assert allowed_filing_types == current_expected


@pytest.mark.parametrize(
Expand Down Expand Up @@ -2674,6 +2685,172 @@ def mock_auth(one, two): # pylint: disable=unused-argument; mocks of library me
filing_types = get_allowed_filings(business, state, legal_type, jwt)
assert filing_types == expected

@pytest.mark.parametrize(
'test_name,state,legal_types,username,roles,blocker_status,expected',
[
# active business - staff user
('staff_active_cp', Business.State.ACTIVE, ['CP'], 'staff', [STAFF_ROLE], None,
expected_lookup([FilingKey.ADMN_FRZE,
FilingKey.AR_CP,
FilingKey.COA_CP,
FilingKey.COD_CP,
FilingKey.CORRCTN,
FilingKey.COURT_ORDER,
FilingKey.ADM_DISS,
FilingKey.REGISTRARS_NOTATION,
FilingKey.REGISTRARS_ORDER,
FilingKey.SPECIAL_RESOLUTION])),
('staff_active_corps',
Business.State.ACTIVE, ['BC', 'BEN', 'CC', 'ULC'], 'staff', [STAFF_ROLE], None,
expected_lookup([FilingKey.ADMN_FRZE,
FilingKey.ALTERATION,
FilingKey.AR_CORPS,
FilingKey.COA_CORPS,
FilingKey.COD_CORPS,
FilingKey.CORRCTN,
FilingKey.COURT_ORDER,
FilingKey.ADM_DISS,
FilingKey.REGISTRARS_NOTATION,
FilingKey.REGISTRARS_ORDER,
FilingKey.TRANSITION,
])),
('staff_active_corps_with_FED',
Business.State.ACTIVE, ['BC', 'BEN', 'CC', 'ULC'], 'staff', [STAFF_ROLE], 'FUTURE_EFFECTIVE',
expected_lookup([FilingKey.ADMN_FRZE,
FilingKey.COURT_ORDER,
FilingKey.REGISTRARS_NOTATION,
FilingKey.REGISTRARS_ORDER,
FilingKey.TRANSITION,
FilingKey.NOTICE_OF_WITHDRAWAL
])),
('staff_active_corps_business_frozen',
Business.State.ACTIVE, ['BC', 'BEN', 'CC', 'ULC'], 'staff', [STAFF_ROLE], 'FROZEN',
expected_lookup([FilingKey.ADMN_FRZE,
FilingKey.COURT_ORDER,
FilingKey.ADM_DISS,
FilingKey.REGISTRARS_NOTATION,
FilingKey.REGISTRARS_ORDER,
FilingKey.TRANSITION,
])),
('staff_active_corps_with_draft_filing',
Business.State.ACTIVE, ['BC', 'BEN', 'CC', 'ULC'], 'staff', [STAFF_ROLE], 'DRAFT',
expected_lookup([FilingKey.ADMN_FRZE,
FilingKey.COURT_ORDER,
FilingKey.REGISTRARS_NOTATION,
FilingKey.REGISTRARS_ORDER,
FilingKey.TRANSITION
])),
('staff_active_continue_in_corps', Business.State.ACTIVE, ['C', 'CBEN', 'CCC', 'CUL'], 'staff', [STAFF_ROLE],
None,
expected_lookup([
FilingKey.ADMN_FRZE,
FilingKey.ALTERATION,
FilingKey.AR_CORPS,
FilingKey.COA_CORPS,
FilingKey.COD_CORPS,
FilingKey.CORRCTN,
FilingKey.COURT_ORDER,
FilingKey.ADM_DISS,
FilingKey.REGISTRARS_NOTATION,
FilingKey.REGISTRARS_ORDER,
FilingKey.TRANSITION])),
('staff_active_llc', Business.State.ACTIVE, ['LLC'], 'staff', [STAFF_ROLE], None, []),
('staff_active_firms', Business.State.ACTIVE, ['SP', 'GP'], 'staff', [STAFF_ROLE], None,
expected_lookup([FilingKey.ADMN_FRZE,
FilingKey.CHANGE_OF_REGISTRATION,
FilingKey.CONV_FIRMS,
FilingKey.CORRCTN_FIRMS,
FilingKey.COURT_ORDER,
FilingKey.VOL_DISS_FIRMS,
FilingKey.ADM_DISS_FIRMS,
FilingKey.REGISTRARS_NOTATION,
FilingKey.REGISTRARS_ORDER])),
# active business - general user
('general_user_cp', Business.State.ACTIVE, ['CP'], 'general', [BASIC_USER], None,
expected_lookup([FilingKey.AR_CP,
FilingKey.COA_CP,
FilingKey.COD_CP,
FilingKey.SPECIAL_RESOLUTION])),
('general_user_corps', Business.State.ACTIVE, ['BC', 'BEN', 'CC', 'ULC'], 'general', [BASIC_USER], None,
expected_lookup([
FilingKey.ALTERATION,
FilingKey.AR_CORPS,
FilingKey.COA_CORPS,
FilingKey.COD_CORPS,
FilingKey.TRANSITION])),
('general_user_continue_in_corps', Business.State.ACTIVE, ['C', 'CBEN', 'CCC', 'CUL'], 'general', [BASIC_USER],
None,
expected_lookup([FilingKey.ALTERATION,
FilingKey.AR_CORPS,
FilingKey.COA_CORPS,
FilingKey.COD_CORPS,
FilingKey.TRANSITION])),
('general_user_llc', Business.State.ACTIVE, ['LLC'], 'general', [BASIC_USER], None, []),
('general_user_firms', Business.State.ACTIVE, ['SP', 'GP'], 'general', [BASIC_USER], None,
expected_lookup([FilingKey.CHANGE_OF_REGISTRATION,
FilingKey.VOL_DISS_FIRMS])),
# historical business - staff user
('staff_historical_corps', Business.State.HISTORICAL, ['BC', 'BEN', 'CC', 'ULC'], 'staff', [STAFF_ROLE], None,
expected_lookup([FilingKey.COURT_ORDER,
FilingKey.PUT_BACK_ON,
FilingKey.REGISTRARS_NOTATION,
FilingKey.REGISTRARS_ORDER,
FilingKey.RESTRN_FULL_CORPS,
FilingKey.RESTRN_LTD_CORPS])),
('staff_historical_continue_in_corps', Business.State.HISTORICAL, ['C', 'CBEN', 'CCC', 'CUL'], 'staff',
[STAFF_ROLE], None,
expected_lookup([FilingKey.COURT_ORDER,
FilingKey.PUT_BACK_ON,
FilingKey.REGISTRARS_NOTATION,
FilingKey.REGISTRARS_ORDER,
FilingKey.RESTRN_FULL_CORPS,
FilingKey.RESTRN_LTD_CORPS])),
# historical business - general user
('general_user_historical_corps', Business.State.HISTORICAL, ['BC', 'BEN', 'CC', 'ULC'], 'general',
[BASIC_USER], None, []),
('general_user_historical_continue_in_corps', Business.State.HISTORICAL, ['C', 'CBEN', 'CCC', 'CUL'],
'general', [BASIC_USER], None, []),
]
)
def test_allowed_filings_notice_of_withdrawal(monkeypatch, app, session, jwt, test_name, state, legal_types, username,
roles, blocker_status, expected):
"""Assert that get allowed returns valid filings for notice of withdrawal."""
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:
identifier = (f'BC{random.SystemRandom().getrandbits(0x58)}')[:9]
business = factory_business(identifier=identifier,
entity_type=legal_type,
state=state)

if blocker_status == 'FROZEN':
business = factory_business(identifier=identifier,
entity_type=legal_type,
state=state,
admin_freeze=True)
elif blocker_status == 'DRAFT':
create_incomplete_filing(business=business,
filing_name='unknownFiling',
filing_status='DRAFT')
elif blocker_status == 'FUTURE_EFFECTIVE':
create_incomplete_filing(business=business,
filing_name='unknownFiling',
filing_status='PAID',
is_future_effective=True)

allowed_filing_types = get_allowed_filings(business, state, legal_type, jwt)
assert allowed_filing_types == expected


@patch('legal_api.models.User.find_by_jwt_token', return_value=User(id=1, login_source='BCSC'))
@patch('legal_api.services.authz.is_self_registered_owner_operator', return_value=True)
Expand Down

0 comments on commit 9227509

Please sign in to comment.