Skip to content

Commit

Permalink
21760 involuntary dissolution stage 1 overdue ARs notification (#2836)
Browse files Browse the repository at this point in the history
* 21760 create email template

* Added new process for involuntary dissoultion and tracker

* Updated involuntary dissolution notification part and traker.

* added mras call if corp has EP in another jurisdiction

* Updated email template for involuntary dissoultion notification

* Fixed lint issues

* update process name, add test

* fix lint issue

* add url in email template

* update get_business_method

* fix broken test --wip

* refactor

* fix lint issue

* fix lint issue

* fix broken test  --wip

* fix broken test

* remove BC check

* fix lint issue

* fix lint issue

* update misc

* fix data type in test

* update the furnishing name validate process

* fix test

* update misc

* fix lint issue, temp fix for broken test

* fix lint issue

* fix broken test --wip
  • Loading branch information
kzdev420 authored Jul 19, 2024
1 parent 271c9f3 commit ef01856
Show file tree
Hide file tree
Showing 9 changed files with 387 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -194,3 +194,17 @@ def substitute_template_parts(template_code: str) -> str:
template_code = template_code.replace('[[{}.html]]'.format(template_part), template_part_code)

return template_code


def get_jurisdictions(identifier: str, token: str) -> str:
"""Get jurisdictions call."""
headers = {
'Accept': 'application/json',
'Authorization': f'Bearer {token}'
}

response = requests.get(
f'{current_app.config.get("LEGAL_API_URL")}/mras/{identifier}', headers=headers
)

return response
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# 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.
"""Email processing rules and actions for involuntary_dissolution stage 1 overdue ARs notifications."""
from __future__ import annotations

from pathlib import Path

from entity_queue_common.service_utils import logger
from flask import current_app
from jinja2 import Template
from legal_api.models import Furnishing

from entity_emailer.email_processors import get_entity_dashboard_url, get_jurisdictions, substitute_template_parts


PROCESSABLE_FURNISHING_NAMES = [
Furnishing.FurnishingName.DISSOLUTION_COMMENCEMENT_NO_AR.name,
Furnishing.FurnishingName.DISSOLUTION_COMMENCEMENT_NO_TR.name,
Furnishing.FurnishingName.DISSOLUTION_COMMENCEMENT_NO_AR_XPRO.name,
Furnishing.FurnishingName.DISSOLUTION_COMMENCEMENT_NO_TR_XPRO.name
]


def process(email_info: dict, token: str) -> dict: # pylint: disable=too-many-locals, , too-many-branches
"""Build the email for Involuntary dissolution notification."""
logger.debug('involuntary_dissolution_stage_1_notification: %s', email_info)
# get business
furnishing_id = email_info['data']['furnishing']['furnishingId']
furnishing = Furnishing.find_by_id(furnishing_id)
business = furnishing.business
business_identifier = business.identifier
template = Path(
f'{current_app.config.get("TEMPLATE_PATH")}/INVOL-DIS-STAGE-1.html'
).read_text()
filled_template = substitute_template_parts(template)
# render template with vars
jnja_template = Template(filled_template, autoescape=True)
# get response from get jurisdictions
jurisdictions_response = get_jurisdictions(business_identifier, token)
# get extra provincials array
extra_provincials = get_extra_provincials(jurisdictions_response)
html_out = jnja_template.render(
business=business.json(),
entity_dashboard_url=get_entity_dashboard_url(business_identifier, token),
extra_provincials=extra_provincials
)
# get recipients
recipients = []
recipients.append(furnishing.email) # furnishing email

recipients = list(set(recipients))
recipients = ', '.join(filter(None, recipients)).strip()

legal_name = business.legal_name
subject = f'Attention {business_identifier} - {legal_name}'

return {
'recipients': recipients,
'requestBy': '[email protected]',
'content': {
'subject': subject,
'body': f'{html_out}'
}
}


def get_extra_provincials(response: dict):
"""Get extra provincials name."""
extra_provincials = []
if response:
jurisdictions = response.get('jurisdictions', [])
for jurisdiction in jurisdictions:
name = jurisdiction.get('name')
if name:
extra_provincials.append(name)

return extra_provincials


def post_process(email_msg: dict, status: str):
"""Update corresponding furnishings entry as PROCESSED or FAILED depending on notification status."""
furnishing_id = email_msg['data']['furnishing']['furnishingId']
furnishing = Furnishing.find_by_id(furnishing_id)
furnishing.status = status
furnishing.save()
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<!DOCTYPE html>
<html lang="en">
<head>
<base href="/">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="referrer" content="origin-when-cross-origin"/>
<meta name="author" content="BC Registries and Online Services">
<title>Attention {{ business.identifier }} {{ business.legalName }}</title>
[[style.html]]
</head>

<body>
<table class="body-table" role="presentation">
<tr>
<td>
[[header.html]]

<div class="container">
<p class="title-message bold">
<span>Attention {{ business.identifier }} {{ business.legalName }}<span>
</p>

[[20px.html]]

<p>Your business is in the process of being dissolved because it hasn't
filed its required annual reports. Please file your overdue annual
reports as soon as possible by <a href="{{ entity_dashboard_url }}">logging into your Business Page</a>.
</p>

[[whitespace-16px.html]]

<p>
Under the Business Corporations Act, if you don't file these reports
within one month from today, the Registrar will post a public notice
on <a href="https://www.bclaws.gov.bc.ca/">www.bclaws.ca</a>. This notice will state that your company may be
dissolved if the annual reports aren't filed after one month.
</p>

[[whitespace-16px.html]]

{% if extra_provincials %}
<p>
Our records indicate your company is registered in
{% for province in extra_provincials %}{{ province }}{% if not loop.last %} and {% endif %}{% endfor %}
as an extraprovincial company. Therefore, if your company is dissolved, its registration as an extraprovincial company
in {% for province in extra_provincials %}{{ province }}{% if not loop.last %} and {% endif %}{% endfor %}
will automatically be cancelled as well.
</p>
{% endif %}

[[whitespace-16px.html]]
[[divider.html]]
[[whitespace-16px.html]]

<p>
You can ask for more time by requesting a delay of the dissolution or
cancellation process. Go to your <a href="{{ entity_dashboard_url }}">business Page</a> and click on “Request
Delay of Dissolution or Cancellation" under the “More Actions” menu.
</p>
[[whitespace-16px.html]]
[[divider.html]]
[[whitespace-16px.html]]

<p>
The following document is attached to this email:
</p>

<ul class="outputs">
<li>Notice of Commencement of Dissolution
</li>
</ul>

[[whitespace-16px.html]]
[[business-dashboard-link.html]]

[[20px.html]]
[[footer.html]]
</div>
</td>
</tr>
</table>
</body>
</html>
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import nats
from flask import current_app

from entity_emailer.email_processors import filing_notification
from entity_emailer.email_processors import filing_notification, involuntary_dissolution_stage_1_notification
from tracker.models import MessageProcessing
from tracker.services import MessageProcessingService

Expand Down Expand Up @@ -61,6 +61,14 @@ def get_message_context_properties(queue_msg: nats.aio.client.Msg):
identifier = email_msg.get('identifier', None)
message_id = f'{etype}_{filing_id}'
return create_message_context_properties(etype, message_id, None, identifier, False)

if etype == 'bc.registry.dissolution':
furnishing_name = email_msg.get('data', {}).get('furnishing', {}).get('furnishingName', None)
if furnishing_name \
and furnishing_name in involuntary_dissolution_stage_1_notification.PROCESSABLE_FURNISHING_NAMES:
source = email_msg.get('source', None)
identifier = email_msg.get('identifier', None)
return create_message_context_properties(etype, message_id, source, identifier, False)
else:
email = email_msg.get('email', None)
etype = email_msg.get('email', {}).get('type', None)
Expand Down
21 changes: 20 additions & 1 deletion queue_services/entity-emailer/src/entity_emailer/worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
from entity_queue_common.service_utils import EmailException, QueueException, logger
from flask import Flask
from legal_api import db
from legal_api.models import Filing
from legal_api.models import Filing, Furnishing
from legal_api.services.bootstrap import AccountService
from legal_api.services.flags import Flags
from sqlalchemy.exc import OperationalError
Expand All @@ -55,6 +55,7 @@
correction_notification,
dissolution_notification,
filing_notification,
involuntary_dissolution_stage_1_notification,
mras_notification,
name_request,
nr_notification,
Expand Down Expand Up @@ -142,6 +143,24 @@ def process_email(email_msg: dict, flask_app: Flask): # pylint: disable=too-man
elif etype and etype == 'bc.registry.bnmove':
email = bn_notification.process_bn_move(email_msg, token)
send_email(email, token)
elif etype and etype == 'bc.registry.dissolution':
# Confirm the data.furnishingName
furnishing_name = email_msg.get('data', {}).get('furnishing', {}).get('furnishingName', None)
if furnishing_name \
and furnishing_name in involuntary_dissolution_stage_1_notification.PROCESSABLE_FURNISHING_NAMES:
email = involuntary_dissolution_stage_1_notification.process(email_msg, token)
try:
send_email(email, token)
# Update corresponding furnishings entry as PROCESSED
involuntary_dissolution_stage_1_notification.post_process(email_msg,
Furnishing.FurnishingStatus.PROCESSED)
except Exception as _: # noqa B902; pylint: disable=W0703
# Update corresponding furnishings entry as FAILED
involuntary_dissolution_stage_1_notification.post_process(email_msg,
Furnishing.FurnishingStatus.FAILED)
raise
else:
logger.debug('Furnishing name is not valid. Skipping processing of email_msg: %s', email_msg)
else:
etype = email_msg['email']['type']
option = email_msg['email']['option']
Expand Down
35 changes: 34 additions & 1 deletion queue_services/entity-emailer/tests/unit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from random import randrange
from unittest.mock import Mock

from legal_api.models import Business, Filing, RegistrationBootstrap, User
from legal_api.models import Batch, Business, Filing, Furnishing, RegistrationBootstrap, User
from registry_schemas.example_data import (
AGM_EXTENSION,
AGM_LOCATION_CHANGE,
Expand Down Expand Up @@ -708,3 +708,36 @@ def create_mock_message(message_payload: dict):
json_msg_payload = json.dumps(message_payload)
mock_msg.data.decode = Mock(return_value=json_msg_payload)
return mock_msg


def create_batch():
"""Return a test batch."""
batch = Batch()
batch.batch_type = Batch.BatchType.INVOLUNTARY_DISSOLUTION
batch.status = Batch.BatchStatus.PROCESSING
batch.save()
return batch


def create_furnishing(session, business=None, batch_id=None,
email='[email protected]', furnishing_name='DISSOLUTION_COMMENCEMENT_NO_AR'):
"""Return a test furnishing."""
furnishing = Furnishing()
furnishing.furnishing_type = 'EMAIL'
furnishing.furnishing_name = furnishing_name
furnishing.status = Furnishing.FurnishingStatus.QUEUED
furnishing.email = email
if business:
furnishing.business_id = business.id
furnishing.business_identifier = business.identifier
else:
business = create_business(identifier='BC123232', legal_type='BC', legal_name='Test Business')
furnishing.business_id = business.id
furnishing.business_identifier = business.identifier
if not batch_id:
batch = create_batch()
furnishing.batch_id = batch.id
else:
furnishing.batch_id = batch_id
furnishing.save()
return furnishing
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# 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.
"""The Unit Tests for the involuntary_dissolution_stage_1_notification processor."""
from entity_emailer.email_processors import involuntary_dissolution_stage_1_notification
from tests.unit import create_business, create_furnishing # noqa: I003


def test_involuntary_dissolution_stage_1_notification(app, session, mocker):
"""Assert that the test_involuntary_dissolution_stage_1_notification can be processed."""
token = 'token'
message_id = '16fd2111-8baf-433b-82eb-8c7fada84ccc'
business_identifier = 'BC1234567'
business = create_business(business_identifier, 'BC', 'Test Business')
furnishing = create_furnishing(session, business=business)
message_payload = {
'specversion': '1.x-wip',
'type': 'bc.registry.dissolution',
'source': 'furnishingsJob',
'id': message_id,
'time': '',
'datacontenttype': 'application/json',
'identifier': business_identifier,
'data': {
'furnishing': {
'type': 'INVOLUNTARY_DISSOLUTION',
'furnishingId': furnishing.id,
'furnishingName': furnishing.furnishing_name
}
}
}

# test processor
mocker.patch(
'entity_emailer.email_processors.involuntary_dissolution_stage_1_notification.get_jurisdictions',
return_value=[])
email = involuntary_dissolution_stage_1_notification.process(message_payload, token)

assert email['content']['subject'] == f'Attention {business_identifier} - Test Business'
assert email['recipients'] == '[email protected]'
assert email['content']['body']
17 changes: 17 additions & 0 deletions queue_services/entity-emailer/tests/unit/test_tracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,23 @@
}
}
}),
('f36e3af7-90c3-4859-a6f6-2feefbdc1e30',
{
'specversion': '1.x-wip',
'type': 'bc.registry.dissolution',
'source': 'furnishingsJob',
'id': 'f36e3af7-90c3-4859-a6f6-2feefbdc1e30',
'time': '',
'datacontenttype': 'application/json',
'identifier': 'BC123223',
'data': {
'furnishing': {
'type': 'INVOLUNTARY_DISSOLUTION',
'furnishingId': 1,
'furnishingName': 'DISSOLUTION_COMMENCEMENT_NO_AR'
}
}
}),
('bc.registry.affiliation_1',
{
'type': 'bc.registry.affiliation',
Expand Down
Loading

0 comments on commit ef01856

Please sign in to comment.