forked from bcgov/lear
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
23349 - validation notice of withdrawal (bcgov#3020)
* implement validation logic for NoW * update schema version number in requirements * exclude the new business scenario
- Loading branch information
1 parent
9227509
commit 81df1ed
Showing
4 changed files
with
170 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -59,4 +59,4 @@ PyPDF2==1.26.0 | |
reportlab==3.6.12 | ||
html-sanitizer==2.4.1 | ||
lxml==5.2.2 | ||
git+https://github.com/bcgov/[email protected].28#egg=registry_schemas | ||
git+https://github.com/bcgov/[email protected].30#egg=registry_schemas |
72 changes: 72 additions & 0 deletions
72
legal-api/src/legal_api/services/filings/validations/notice_of_withdrawal.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
# 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. | ||
"""Validation for the Notice of Withdrawal filing.""" | ||
from http import HTTPStatus | ||
from typing import Dict, Final, Optional | ||
|
||
from flask_babel import _ as babel # noqa: N813, I004, I001, I003; | ||
|
||
from legal_api.errors import Error | ||
from legal_api.models import Filing | ||
from legal_api.models.db import db # noqa: I001 | ||
from legal_api.services.utils import get_int | ||
from legal_api.utils.datetime import datetime as dt | ||
|
||
|
||
def validate(filing: Dict) -> Optional[Error]: | ||
"""Validate the Notice of Withdrawal filing.""" | ||
if not filing: | ||
return Error(HTTPStatus.BAD_REQUEST, [{'error': babel('A valid filing is required.')}]) | ||
|
||
msg = [] | ||
|
||
withdrawn_filing_id_path: Final = '/filing/noticeOfWithdrawal/filingId' | ||
withdrawn_filing_id = get_int(filing, withdrawn_filing_id_path) | ||
if not withdrawn_filing_id: | ||
msg.append({'error': babel('Filing Id is required.'), 'path': withdrawn_filing_id_path}) | ||
return msg # cannot continue validation without the to be withdrawn filing id | ||
|
||
err = validate_withdrawn_filing(withdrawn_filing_id) | ||
if err: | ||
msg.extend(err) | ||
|
||
if msg: | ||
return Error(HTTPStatus.BAD_REQUEST, msg) | ||
return None | ||
|
||
|
||
def validate_withdrawn_filing(withdrawn_filing_id: int): | ||
"""Validate the to be withdrawn filing id exists, the filing has a FED, the filing status is PAID.""" | ||
msg = [] | ||
# check whether the filing ID exists | ||
withdrawn_filing = db.session.query(Filing). \ | ||
filter(Filing.id == withdrawn_filing_id).one_or_none() | ||
if not withdrawn_filing: | ||
msg.append({'error': babel('The filing to be withdrawn cannot be found.')}) | ||
return msg # cannot continue if the withdrawn filing doesn't exist | ||
|
||
# check whether the filing has a Future Effective Date(FED) | ||
now = dt.utcnow() | ||
filing_effective_date = dt.fromisoformat(str(withdrawn_filing.effective_date)) | ||
if filing_effective_date < now: | ||
msg.append({'error': babel('Only filings with a future effective date can be withdrawn.')}) | ||
|
||
# check the filing status | ||
filing_status = withdrawn_filing.status | ||
if filing_status != Filing.Status.PAID.value: | ||
msg.append({'error': babel('Only paid filings with a future effective date can be withdrawn.')}) | ||
|
||
if msg: | ||
return msg | ||
return None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
93 changes: 93 additions & 0 deletions
93
legal-api/tests/unit/services/filings/validations/test_notice_of_withdrawal.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
# 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. | ||
"""Test suite to ensure the Notice of Withdrawal filing is validated correctly.""" | ||
import copy | ||
from datetime import datetime, timedelta | ||
from http import HTTPStatus | ||
|
||
import pytest | ||
|
||
from legal_api.models import Filing, RegistrationBootstrap | ||
from legal_api.services.filings import validate | ||
from legal_api.services.filings.validations.notice_of_withdrawal import ( | ||
validate_withdrawn_filing, | ||
validate as validate_in_notice_of_withdrawal | ||
) | ||
from tests.unit.models import factory_pending_filing, factory_business | ||
from . import lists_are_equal | ||
|
||
from registry_schemas.example_data import FILING_HEADER, NOTICE_OF_WITHDRAWAL, DISSOLUTION, INCORPORATION | ||
|
||
|
||
# setup | ||
FILING_NOT_EXIST_MSG = {'error': 'The filing to be withdrawn cannot be found.'} | ||
FILING_NOT_FED_MSG = {'error': 'Only filings with a future effective date can be withdrawn.'} | ||
FILING_NOT_PAID_MSG = {'error': 'Only paid filings with a future effective date can be withdrawn.'} | ||
MISSING_FILING_DICT_MSG = {'error': 'A valid filing is required.'} | ||
|
||
|
||
# tests | ||
|
||
@pytest.mark.parametrize( | ||
'test_name, is_filing_exist, withdrawn_filing_status, is_future_effective, has_filing_id, expected_code, expected_msg',[ | ||
('EXIST_BUSINESS_SUCCESS', True, Filing.Status.PAID, True, True, None, None), | ||
('EXIST_BUSINESS_FAIL_NOT_PAID', True, Filing.Status.PENDING, True, True, HTTPStatus.BAD_REQUEST, [FILING_NOT_PAID_MSG]), | ||
('EXIST_BUSINESS_FAIL_NOT_FED', True, Filing.Status.PAID, False, True, HTTPStatus.BAD_REQUEST, [FILING_NOT_FED_MSG]), | ||
('EXIST_BUSINESS_FAIL_FILING_NOT_EXIST', False, Filing.Status.PAID, True, True, HTTPStatus.BAD_REQUEST, [FILING_NOT_EXIST_MSG]), | ||
('EXIST_BUSINESS_FAIL_MISS_FILING_ID', True, Filing.Status.PAID, True, False, HTTPStatus.UNPROCESSABLE_ENTITY, ''), | ||
('EXIST_BUSINESS_FAIL_NOT_PAID_NOT_FED', True, Filing.Status.PENDING, False, True, HTTPStatus.BAD_REQUEST, [FILING_NOT_FED_MSG, FILING_NOT_PAID_MSG]) | ||
] | ||
) | ||
def test_validate_notice_of_withdrawal(session, test_name, is_filing_exist, withdrawn_filing_status, is_future_effective, has_filing_id, expected_code, expected_msg): | ||
"""Assert that notice of withdrawal flings can be validated""" | ||
today = datetime.utcnow().date() | ||
future_effective_date = today + timedelta(days=5) | ||
future_effective_date = future_effective_date.isoformat() | ||
identifier = 'BC1234567' | ||
business = factory_business(identifier) | ||
# file a voluntary dissolution with a FED | ||
if is_filing_exist: | ||
withdrawn_json = copy.deepcopy(FILING_HEADER) | ||
withdrawn_json['filing']['header']['name'] = 'dissolution' | ||
withdrawn_json['filing']['business']['legalType'] = 'BC' | ||
withdrawn_json['filing']['dissolution'] = copy.deepcopy(DISSOLUTION) | ||
withdrawn_json['filing']['dissolution']['dissolutionDate'] = future_effective_date | ||
withdrawn_filing = factory_pending_filing(business, withdrawn_json) | ||
if is_filing_exist: | ||
if is_future_effective: | ||
withdrawn_filing.effective_date = future_effective_date | ||
if withdrawn_filing_status == Filing.Status.PAID: | ||
withdrawn_filing.payment_completion_date = datetime.utcnow().isoformat() | ||
withdrawn_filing.save() | ||
withdrawn_filing_id = withdrawn_filing.id | ||
|
||
# create a notice of withdrawal filing json | ||
filing_json = copy.deepcopy(FILING_HEADER) | ||
filing_json['filing']['header']['name'] = 'noticeOfWithdrawal' | ||
filing_json['filing']['business']['legalType'] = 'BC' | ||
filing_json['filing']['noticeOfWithdrawal'] = copy.deepcopy(NOTICE_OF_WITHDRAWAL) | ||
if has_filing_id: | ||
if is_filing_exist: | ||
filing_json['filing']['noticeOfWithdrawal']['filingId'] = withdrawn_filing_id | ||
else: | ||
del filing_json['filing']['noticeOfWithdrawal']['filingId'] | ||
|
||
err = validate(business, filing_json) | ||
if expected_code: | ||
assert err.code == expected_code | ||
if has_filing_id: # otherwise, won't pass schema validation, and the error msg will be very long | ||
assert lists_are_equal(err.msg, expected_msg) | ||
else: | ||
assert err is None | ||
|