Skip to content

Commit

Permalink
25038 25039 putbackoff filing (#3151)
Browse files Browse the repository at this point in the history
  • Loading branch information
vysakh-menon-aot authored Dec 27, 2024
1 parent 71abcb9 commit 80b86c3
Show file tree
Hide file tree
Showing 18 changed files with 246 additions and 26 deletions.
11 changes: 6 additions & 5 deletions jobs/involuntary-dissolutions/involuntary_dissolutions.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ def create_invountary_dissolution_filing(business_id: int):
}
}

filing.hide_in_ledger = True
filing.save()

return filing
Expand Down Expand Up @@ -199,7 +200,7 @@ def stage_1_process(app: Flask): # pylint: disable=redefined-outer-name,too-man
step=BatchProcessing.BatchProcessingStep.WARNING_LEVEL_1,
status=BatchProcessing.BatchProcessingStatus.PROCESSING,
created_date=datetime.utcnow(),
trigger_date=datetime.utcnow()+stage_1_delay,
trigger_date=datetime.utcnow() + stage_1_delay,
batch_id=batch.id,
business_id=business.id)

Expand All @@ -222,10 +223,10 @@ def _check_stage_1_furnishing_entries(furnishings):
2. only available to send mail out, and it's processed.
"""
email_processed = any(
furnishing.furnishing_type == Furnishing.FurnishingType.EMAIL
and furnishing.status == Furnishing.FurnishingStatus.PROCESSED
for furnishing in furnishings
)
furnishing.furnishing_type == Furnishing.FurnishingType.EMAIL
and furnishing.status == Furnishing.FurnishingStatus.PROCESSED
for furnishing in furnishings
)

expected_mail_status = [Furnishing.FurnishingStatus.PROCESSED]
# if SFTP function is off, we expect the mail status will be QUEUED or PROCESSED
Expand Down
29 changes: 29 additions & 0 deletions legal-api/migrations/versions/f99e7bda56bb_hide_in_ledger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"""hide-in-ledger
Revision ID: f99e7bda56bb
Revises: f3b30f43aa86
Create Date: 2024-12-20 13:59:15.359911
"""
from alembic import op
import sqlalchemy as sa

# revision identifiers, used by Alembic.
revision = 'f99e7bda56bb'
down_revision = 'f3b30f43aa86'
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('filings', sa.Column('hide_in_ledger', sa.Boolean(), nullable=False, server_default='False'))
op.execute("UPDATE filings SET hide_in_ledger = true WHERE filing_type = 'adminFreeze'")
op.execute("UPDATE filings SET hide_in_ledger = true WHERE filing_type = 'dissolution' and filing_sub_type = 'involuntary'")
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('filings', 'hide_in_ledger')
# ### end Alembic commands ###
2 changes: 1 addition & 1 deletion legal-api/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,5 @@ PyPDF2==1.26.0
reportlab==3.6.12
html-sanitizer==2.4.1
lxml==5.2.2
git+https://github.com/bcgov/[email protected].31#egg=registry_schemas
git+https://github.com/bcgov/[email protected].32#egg=registry_schemas
git+https://github.com/bcgov/lear.git#egg=sql-versioning&subdirectory=python/common/sql-versioning
4 changes: 2 additions & 2 deletions legal-api/requirements/bcregistry-libraries.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
git+https://github.com/bcgov/[email protected].31#egg=registry_schemas
git+https://github.com/bcgov/lear.git#egg=sql-versioning&subdirectory=python/common/sql-versioning
git+https://github.com/bcgov/[email protected].32#egg=registry_schemas
git+https://github.com/bcgov/lear.git#egg=sql-versioning&subdirectory=python/common/sql-versioning
16 changes: 3 additions & 13 deletions legal-api/src/legal_api/core/filing.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ class FilingTypes(str, Enum):
DISSOLVED = 'dissolved'
INCORPORATIONAPPLICATION = 'incorporationApplication'
NOTICEOFWITHDRAWAL = 'noticeOfWithdrawal'
PUTBACKOFF = 'putBackOff'
PUTBACKON = 'putBackOn'
REGISTRARSNOTATION = 'registrarsNotation'
REGISTRARSORDER = 'registrarsOrder'
Expand Down Expand Up @@ -434,7 +435,7 @@ def common_ledger_items(business_identifier: str, filing_storage: FilingStorage)
filing = Filing()
filing._storage = filing_storage # pylint: disable=protected-access
return {
'displayLedger': Filing._is_display_ledger(filing_storage),
'displayLedger': not filing_storage.hide_in_ledger,
'commentsCount': filing_storage.comments_count,
'commentsLink': f'{base_url}/{business_identifier}/filings/{filing_storage.id}/comments',
'documentsLink': f'{base_url}/{business_identifier}/filings/{filing_storage.id}/documents' if
Expand All @@ -457,18 +458,6 @@ def _add_ledger_order(filing: FilingStorage, ledger_filing: dict) -> dict:
ledger_filing['data'] = {}
ledger_filing['data']['order'] = court_order_data

@staticmethod
def _is_display_ledger(filing: FilingStorage) -> bool:
"""Return boolean that display the ledger."""
# If filing is NOT an admin freeze or involuntary dissolution, we will display it on ledger
return not (
filing.filing_type == Filing.FilingTypes.ADMIN_FREEZE or
(
filing.filing_type == Filing.FilingTypes.DISSOLUTION and
filing.filing_sub_type == 'involuntary'
)
)

@staticmethod
def get_document_list(business, # pylint: disable=too-many-locals disable=too-many-branches
filing,
Expand All @@ -477,6 +466,7 @@ def get_document_list(business, # pylint: disable=too-many-locals disable=too-m
no_output_filings = [
Filing.FilingTypes.CONVERSION.value,
Filing.FilingTypes.COURTORDER.value,
Filing.FilingTypes.PUTBACKOFF.value,
Filing.FilingTypes.PUTBACKON.value,
Filing.FilingTypes.REGISTRARSNOTATION.value,
Filing.FilingTypes.REGISTRARSORDER.value,
Expand Down
6 changes: 6 additions & 0 deletions legal-api/src/legal_api/core/meta/filing.py
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,12 @@ class FilingTitles(str, Enum):
'CCC': 'NWITH'
}
},
'putBackOff': {
'name': 'putBackOff',
'title': 'Put Back Off',
'displayName': 'Correction - Put Back Off',
'code': 'NOFEE'
},
'putBackOn': {
'name': 'putBackOn',
'title': 'Put Back On',
Expand Down
8 changes: 8 additions & 0 deletions legal-api/src/legal_api/models/business.py
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,14 @@ def get_all_by_no_tax_id(cls):
.all())
return businesses

@classmethod
def get_expired_restoration(cls):
"""Return all identifier with an expired restoration_expiry_date."""
businesses = (db.session.query(Business.identifier)
.filter(Business.restoration_expiry_date <= datetime.utcnow())
.all())
return businesses

@classmethod
def get_filing_by_id(cls, business_identifier: int, filing_id: str):
"""Return the filings for a specific business and filing_id."""
Expand Down
3 changes: 3 additions & 0 deletions legal-api/src/legal_api/models/filing.py
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,7 @@ class Source(Enum):
# for all the business the fee code remain same as NOFEE (Staff)
'adminFreeze': {'name': 'adminFreeze', 'title': 'Admin Freeze', 'code': 'NOFEE'},
'courtOrder': {'name': 'courtOrder', 'title': 'Court Order', 'code': 'NOFEE'},
'putBackOff': {'name': 'putBackOff', 'title': 'Put Back Off', 'code': 'NOFEE'},
'putBackOn': {'name': 'putBackOn', 'title': 'Put Back On', 'code': 'NOFEE'},
'registrarsNotation': {'name': 'registrarsNotation', 'title': 'Registrars Notation', 'code': 'NOFEE'},
'registrarsOrder': {'name': 'registrarsOrder', 'title': 'Registrars Order', 'code': 'NOFEE'}
Expand Down Expand Up @@ -492,6 +493,7 @@ class Source(Enum):
'court_order_effect_of_order',
'court_order_file_number',
'deletion_locked',
'hide_in_ledger',
'effective_date',
'order_details',
'paper_only',
Expand Down Expand Up @@ -535,6 +537,7 @@ class Source(Enum):
application_date = db.Column('application_date', db.DateTime(timezone=True))
notice_date = db.Column('notice_date', db.DateTime(timezone=True))
resubmission_date = db.Column('resubmission_date', db.DateTime(timezone=True))
hide_in_ledger = db.Column('hide_in_ledger', db.Boolean, unique=False, default=False)

# # relationships
transaction_id = db.Column('transaction_id', db.BigInteger,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -620,12 +620,24 @@ def save_filing(client_request: LocalProxy, # pylint: disable=too-many-return-s
datetime.datetime.fromisoformat(filing.filing_json['filing']['header']['effectiveDate']) \
if filing.filing_json['filing']['header'].get('effectiveDate', None) else datetime.datetime.utcnow()

filing.hide_in_ledger = ListFilingResource._hide_in_ledger(filing)
filing.save()
except BusinessException as err:
return None, None, {'error': err.error}, err.status_code

return business or bootstrap, filing, None, None

@staticmethod
def _hide_in_ledger(filing: Filing) -> bool:
"""Hide the filing in the ledger."""
hide_in_ledger = str(request.headers.get('hide-in-ledger', None)).lower()
if (filing.filing_type == 'adminFreeze' or
(filing.filing_type == 'dissolution' and filing.filing_sub_type == 'involuntary') or
(jwt.validate_roles([SYSTEM_ROLE]) and hide_in_ledger == 'true')):
return True

return False

@staticmethod
def _save_colin_event_ids(filing: Filing, business: Union[Business, RegistrationBootstrap]):
try:
Expand Down Expand Up @@ -683,7 +695,8 @@ def get_filing_types(business: Business, filing_json: dict): # pylint: disable=
legal_type,
priority_flag,
waive_fees_flag))
elif filing_type in ['courtOrder', 'registrarsNotation', 'registrarsOrder', 'putBackOn', 'adminFreeze']:
elif filing_type in ('adminFreeze', 'courtOrder', 'putBackOff', 'putBackOn',
'registrarsNotation', 'registrarsOrder'):
filing_type_code = Filing.FILINGS.get(filing_type, {}).get('code')
filing_types.append({
'filingTypeCode': filing_type_code,
Expand Down
9 changes: 9 additions & 0 deletions legal-api/src/legal_api/resources/v2/internal_services.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,15 @@ def get_future_effective_filing_ids():
return jsonify(filing_ids), HTTPStatus.OK


@bp.route('/expired_restoration', methods=['GET'])
@cross_origin(origin='*')
@jwt.has_one_of_roles([UserRoles.system])
def get_identifiers_of_expired_restoration():
"""Return all identifiers (if limited restoration has expired)."""
businesses = Business.get_expired_restoration()
return jsonify({'identifiers': [business.identifier for business in businesses]}), HTTPStatus.OK


@bp.route('/bnmove', methods=['POST'])
@cross_origin(origin='*')
@jwt.has_one_of_roles([UserRoles.system])
Expand Down
3 changes: 3 additions & 0 deletions legal-api/src/legal_api/services/authz.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,9 @@ def get_allowable_filings_dict():
# only show filing when providing allowable filings not specific to a business
'businessRequirement': BusinessRequirement.NOT_EXIST
},
'putBackOff': {
'legalTypes': ['BEN', 'BC', 'CC', 'ULC', 'C', 'CBEN', 'CUL', 'CCC']
},
'registrarsNotation': {
'legalTypes': ['SP', 'GP', 'CP', 'BC', 'BEN', 'CC', 'ULC', 'C', 'CBEN', 'CUL', 'CCC']
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# 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 Put Back Off filing."""
from http import HTTPStatus
from typing import Dict, Final, Optional

from flask_babel import _ as babel # noqa: N813, I004, I001; importing camelcase '_' as a name
# noqa: I004
from legal_api.errors import Error
from legal_api.models import Business

from .common_validations import validate_court_order
from ...utils import get_str # noqa: I003; needed as the linter gets confused from the babel override above.


def validate(business: Business, put_back_off: Dict) -> Optional[Error]:
"""Validate the Court Order filing."""
if not business or not put_back_off:
return Error(HTTPStatus.BAD_REQUEST, [{'error': babel('A valid business and filing are required.')}])
msg = []

if not get_str(put_back_off, '/filing/putBackOff/details'):
msg.append({'error': babel('Put Back Off details are required.'), 'path': '/filing/putBackOff/details'})

msg.extend(_validate_court_order(put_back_off))

if msg:
return Error(HTTPStatus.BAD_REQUEST, msg)
return None


def _validate_court_order(filing):
"""Validate court order."""
if court_order := filing.get('filing', {}).get('putBackOff', {}).get('courtOrder', None):
court_order_path: Final = '/filing/putBackOff/courtOrder'
err = validate_court_order(court_order_path, court_order)
if err:
return err
return []
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
from .dissolution import validate as dissolution_validate
from .incorporation_application import validate as incorporation_application_validate
from .notice_of_withdrawal import validate as notice_of_withdrawal_validate
from .put_back_off import validate as put_back_off_validate
from .put_back_on import validate as put_back_on_validate
from .registrars_notation import validate as registrars_notation_validate
from .registrars_order import validate as registrars_order_validate
Expand Down Expand Up @@ -186,6 +187,9 @@ def validate(business: Business, # pylint: disable=too-many-branches,too-many-s
elif k == Filing.FILINGS['noticeOfWithdrawal'].get('name'):
err = notice_of_withdrawal_validate(filing_json)

elif k == Filing.FILINGS['putBackOff'].get('name'):
err = put_back_off_validate(business, filing_json)

if err:
return err

Expand Down
5 changes: 5 additions & 0 deletions legal-api/tests/unit/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,11 @@ def factory_completed_filing(business,
filing._filing_type = filing_type
if filing_sub_type:
filing._filing_sub_type = filing_sub_type

if (filing.filing_type == 'adminFreeze' or
(filing.filing_type == 'dissolution' and filing.filing_sub_type == 'involuntary')):
filing.hide_in_ledger = True

filing.save()

uow = versioning_manager.unit_of_work(db.session)
Expand Down
6 changes: 5 additions & 1 deletion legal-api/tests/unit/resources/v2/test_business.py
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,10 @@ def test_get_could_file(session, client, jwt):
"displayName": "BC Limited Company Incorporation Application",
"name": "incorporationApplication"
},
{
"displayName": "Correction - Put Back Off",
"name": "putBackOff",
},
{
"displayName": "Registrar's Notation",
"name": "registrarsNotation"
Expand Down Expand Up @@ -659,4 +663,4 @@ def test_get_could_file(session, client, jwt):
assert rv.json['couldFile']['filing']
assert rv.json['couldFile']['filing']['filingTypes']
assert len(rv.json['couldFile']['filing']['filingTypes']) > 0
assert rv.json['couldFile']['filing']['filingTypes'] == expected
assert rv.json['couldFile']['filing']['filingTypes'] == expected
23 changes: 23 additions & 0 deletions legal-api/tests/unit/resources/v2/test_internal_services.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,29 @@ def test_get_future_effective_filing_ids(session, client, jwt):
assert len(rv.json) == 0


@pytest.mark.parametrize(
'test_name, expired', [
('LIMITED_RESTORATION', True),
('LIMITED_RESTORATION_EXPIRED', False)
]
)
def test_get_businesses_expired_restoration(session, client, jwt, test_name, expired):
"""Assert that expired restoration can be fetched."""
identifier = 'BC1234567'
business = factory_business(identifier=identifier, entity_type=Business.LegalTypes.COMP.value)
business.restoration_expiry_date = (datetime.now(timezone.utc) +
datedelta.datedelta(days=-1 if expired else 1))
business.save()
rv = client.get('/api/v2/internal/expired_restoration', headers=create_header(jwt, [UserRoles.system]))
if expired:
assert rv.status_code == HTTPStatus.OK
assert len(rv.json) == 1
assert rv.json['identifiers'][0] == identifier
else:
assert rv.status_code == HTTPStatus.OK
assert len(rv.json['identifiers']) == 0


def test_update_bn_move(session, client, jwt):
"""Assert that the endpoint updates tax_id."""
identifier = 'FM0000001'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# 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 Put back off validations."""
import copy

from registry_schemas.example_data import PUT_BACK_OFF, FILING_HEADER

from legal_api.services.filings.validations.put_back_off import validate

from tests.unit.models import factory_business


def test_put_back_off(session):
"""Assert valid put back off."""
identifier = 'CP1234567'
business = factory_business(identifier)

filing_json = copy.deepcopy(FILING_HEADER)
filing_json['filing']['business']['identifier'] = identifier
filing_json['filing']['putBackOff'] = copy.deepcopy(PUT_BACK_OFF)

err = validate(business, filing_json)
assert err is None
Loading

0 comments on commit 80b86c3

Please sign in to comment.