Skip to content

Commit

Permalink
17930 - AGM Extensions Emailer (#2327)
Browse files Browse the repository at this point in the history
* 17930 - AGM Extensions Emailer

* fixed lint issue

* updated business schema version to include agm extensions

* More lint fixes

* fixed agm location change test

* Fixed in response to Argus' comments
  • Loading branch information
JazzarKarim authored Nov 27, 2023
1 parent bb4218d commit 16e5417
Show file tree
Hide file tree
Showing 11 changed files with 308 additions and 6 deletions.
2 changes: 1 addition & 1 deletion queue_services/entity-emailer/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,6 @@ webcolors==1.13
Werkzeug==1.0.1
yarl==1.8.2
zipp==3.15.0
git+https://github.com/bcgov/[email protected].14#egg=registry_schemas
git+https://github.com/bcgov/[email protected].17#egg=registry_schemas
git+https://github.com/bcgov/lear.git#egg=legal_api&subdirectory=legal-api
git+https://github.com/bcgov/lear.git#egg=entity_queue_common&subdirectory=queue_services/common
1 change: 1 addition & 0 deletions queue_services/entity-emailer/src/entity_emailer/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ class _Config(): # pylint: disable=too-few-public-methods
CORP_FORMS_URL = os.getenv('CORP_FORMS_URL', '')
SOCIETIES_URL = os.getenv('SOCIETIES_URL', '')


class DevConfig(_Config): # pylint: disable=too-few-public-methods
"""Creates the Development Config object."""

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
# Copyright © 2023 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 AGM Extension notifications."""
from __future__ import annotations

import base64
import re
from http import HTTPStatus
from pathlib import Path

import requests
from entity_queue_common.service_utils import logger
from flask import current_app
from jinja2 import Template
from legal_api.models import Business, Filing

from entity_emailer.email_processors import get_filing_info, get_recipient_from_auth, substitute_template_parts


def _get_pdfs(
token: str,
business: dict,
filing: Filing,
filing_date_time: str,
effective_date: str) -> list:
# pylint: disable=too-many-locals, too-many-branches, too-many-statements, too-many-arguments
"""Get the pdfs for the AGM Extension output."""
pdfs = []
attach_order = 1
headers = {
'Accept': 'application/pdf',
'Authorization': f'Bearer {token}'
}

# add filing pdf
filing_pdf = requests.get(
f'{current_app.config.get("LEGAL_API_URL")}/businesses/{business["identifier"]}/filings/{filing.id}'
'?type=letterOfAgmExtension', headers=headers
)
if filing_pdf.status_code != HTTPStatus.OK:
logger.error('Failed to get pdf for filing: %s', filing.id)
else:
filing_pdf_encoded = base64.b64encode(filing_pdf.content)
pdfs.append(
{
'fileName': 'Letter of AGM Extension Approval.pdf',
'fileBytes': filing_pdf_encoded.decode('utf-8'),
'fileUrl': '',
'attachOrder': attach_order
}
)
attach_order += 1

# add receipt pdf
corp_name = business.get('legalName')
business_data = Business.find_by_internal_id(filing.business_id)
receipt = requests.post(
f'{current_app.config.get("PAY_API_URL")}/{filing.payment_token}/receipts',
json={
'corpName': corp_name,
'filingDateTime': filing_date_time,
'effectiveDateTime': effective_date if effective_date != filing_date_time else '',
'filingIdentifier': str(filing.id),
'businessNumber': business_data.tax_id if business_data and business_data.tax_id else ''
},
headers=headers
)
if receipt.status_code != HTTPStatus.CREATED:
logger.error('Failed to get receipt pdf for filing: %s', filing.id)
else:
receipt_encoded = base64.b64encode(receipt.content)
pdfs.append(
{
'fileName': 'Receipt.pdf',
'fileBytes': receipt_encoded.decode('utf-8'),
'fileUrl': '',
'attachOrder': attach_order
}
)
attach_order += 1

return pdfs


def process(email_info: dict, token: str) -> dict: # pylint: disable=too-many-locals, too-many-branches
"""Build the email for AGM Extension notification."""
logger.debug('agm_extension_notification: %s', email_info)
# get template and fill in parts
filing_type, status = email_info['type'], email_info['option']
# get template vars from filing
filing, business, leg_tmz_filing_date, leg_tmz_effective_date = get_filing_info(email_info['filingId'])
filing_name = filing.filing_type[0].upper() + ' '.join(re.findall('[a-zA-Z][^A-Z]*', filing.filing_type[1:]))

template = Path(
f'{current_app.config.get("TEMPLATE_PATH")}/AGM-EXT-{status}.html'
).read_text()
filled_template = substitute_template_parts(template)
# render template with vars
jnja_template = Template(filled_template, autoescape=True)
filing_data = (filing.json)['filing'][f'{filing_type}']
html_out = jnja_template.render(
business=business,
filing=filing_data,
header=(filing.json)['filing']['header'],
filing_date_time=leg_tmz_filing_date,
effective_date_time=leg_tmz_effective_date,
entity_dashboard_url=current_app.config.get('DASHBOARD_URL') +
(filing.json)['filing']['business'].get('identifier', ''),
email_header=filing_name.upper(),
filing_type=filing_type
)

# get attachments
pdfs = _get_pdfs(token, business, filing, leg_tmz_filing_date, leg_tmz_effective_date)

# get recipients
identifier = filing.filing_json['filing']['business']['identifier']
recipients = []
recipients.append(get_recipient_from_auth(identifier, token))

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

# assign subject
subject = 'AGM Extension Documents from the Business Registry'

legal_name = business.get('legalName', None)
legal_name = 'Numbered Company' if legal_name.startswith(identifier) else legal_name
subject = f'{legal_name} - {subject}' if legal_name else subject

return {
'recipients': recipients,
'requestBy': '[email protected]',
'content': {
'subject': subject,
'body': f'{html_out}',
'attachments': pdfs
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,12 @@ def __is_colin(legal_type):
colin_list = ['CR', 'UL', 'CC', 'XCR', 'XUL', 'RLC']
return legal_type in colin_list


def _is_society(legal_type):
society_list = ['SO', 'XSO']
return legal_type in society_list

society_list = ['SO', 'XSO']
return legal_type in society_list


def __get_instruction_group(legal_type):
if __is_modernized(legal_type):
return 'modernized'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<!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>Confirmation of AGM Extension</title>
[[style.html]]
</head>

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

<div class="container">

[[20px.html]]

<p class="title-message bold">
<span>Your AGM Extension Request<span>
</p>

[[whitespace-16px.html]]

<p>In response to your request for an AGM extension, please see attached.</p>

[[whitespace-24px.html]]
[[divider.html]]
[[20px.html]]

<p class="title-message bold">
<span>Attached to this Email<span>
</p>

[[whitespace-16px.html]]

<p>The following documents are attached to this email:</p>
<ul class="outputs">
<li>Letter of AGM Extension Approval</li>
<li>Receipt</li>
</ul>

[[business-dashboard-link.html]]

[[whitespace-24px.html]]
[[footer.html]]
</div>
</td>
</tr>
</table>
</body>
</html>
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<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>Confirmation of continuation out</title>
<title>Confirmation of AGM Location Change</title>
[[style.html]]
</head>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ def get_message_context_properties(queue_msg: nats.aio.client.Msg):
message_id = f'{etype}_{option}_{ar_year}_{business_id}'
return create_message_context_properties(etype, message_id, None, None, False)

if etype == 'agmLocationChange' \
if etype in ('agmLocationChange', 'agmExtension') \
and (option := email.get('option', None)) \
and option == 'COMPLETED' \
and (filing_id := email.get('filingId', None)):
Expand Down
4 changes: 4 additions & 0 deletions queue_services/entity-emailer/src/entity_emailer/worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
from entity_emailer import config
from entity_emailer.email_processors import (
affiliation_notification,
agm_extension_notification,
agm_location_change_notification,
ar_reminder_notification,
bn_notification,
Expand Down Expand Up @@ -155,6 +156,9 @@ def process_email(email_msg: dict, flask_app: Flask): # pylint: disable=too-man
elif etype == 'agmLocationChange' and option == Filing.Status.COMPLETED.value:
email = agm_location_change_notification.process(email_msg['email'], token)
send_email(email, token)
elif etype == 'agmExtension' and option == Filing.Status.COMPLETED.value:
email = agm_extension_notification.process(email_msg['email'], token)
send_email(email, token)
elif etype == 'dissolution':
email = dissolution_notification.process(email_msg['email'], token)
send_email(email, token)
Expand Down
27 changes: 27 additions & 0 deletions queue_services/entity-emailer/tests/unit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

from legal_api.models import Business, Filing, RegistrationBootstrap, User
from registry_schemas.example_data import (
AGM_EXTENSION,
AGM_LOCATION_CHANGE,
ALTERATION,
ALTERATION_FILING_TEMPLATE,
Expand Down Expand Up @@ -411,6 +412,32 @@ def prep_agm_location_change_filing(identifier, payment_id, legal_type, legal_na
return filing


def prep_agm_extension_filing(identifier, payment_id, legal_type, legal_name):
"""Return a new AGM extension filing prepped for email notification."""
business = create_business(identifier, legal_type, legal_name)
filing_template = copy.deepcopy(FILING_HEADER)
filing_template['filing']['header']['name'] = 'agmExtension'

filing_template['filing']['agmExtension'] = copy.deepcopy(AGM_EXTENSION)
filing_template['filing']['business'] = {
'identifier': business.identifier,
'legalType': legal_type,
'legalName': legal_name
}

filing = create_filing(
token=payment_id,
filing_json=filing_template,
business_id=business.id)
filing.payment_completion_date = filing.filing_date

user = create_user('test_user')
filing.submitter_id = user.id

filing.save()
return filing


def prep_maintenance_filing(session, identifier, payment_id, status, filing_type, submitter_role=None):
"""Return a new maintenance filing prepped for email notification."""
business = create_business(identifier, Business.LegalTypes.BCOMP.value, LEGAL_NAME)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Copyright © 2023 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 AGM extension email processor."""
from unittest.mock import patch

import pytest
from legal_api.models import Business

from entity_emailer.email_processors import agm_extension_notification
from tests.unit import prep_agm_extension_filing


@pytest.mark.parametrize('status,legal_name,is_numbered', [
('COMPLETED', 'test business', False),
('COMPLETED', 'BC1234567', True),
])
def test_agm_extension_notification(app, session, status, legal_name, is_numbered):
"""Assert that the agm extension email processor works as expected."""
# setup filing + business for email
filing = prep_agm_extension_filing('BC1234567', '1', Business.LegalTypes.COMP.value, legal_name)
token = 'token'
# test processor
with patch.object(agm_extension_notification, '_get_pdfs', return_value=[]) as mock_get_pdfs:
with patch.object(agm_extension_notification, 'get_recipient_from_auth',
return_value='[email protected]'):
email = agm_extension_notification.process(
{'filingId': filing.id, 'type': 'agmExtension', 'option': status}, token)

if (is_numbered):
assert email['content']['subject'] == \
'Numbered Company - AGM Extension Documents from the Business Registry'
else:
assert email['content']['subject'] == \
legal_name + ' - AGM Extension Documents from the Business Registry'

assert '[email protected]' in email['recipients']
assert email['content']['body']
assert email['content']['attachments'] == []
assert mock_get_pdfs.call_args[0][0] == token
assert mock_get_pdfs.call_args[0][1]['identifier'] == 'BC1234567'
assert mock_get_pdfs.call_args[0][1]['legalName'] == legal_name
assert mock_get_pdfs.call_args[0][1]['legalType'] == Business.LegalTypes.COMP.value
assert mock_get_pdfs.call_args[0][2] == filing
8 changes: 8 additions & 0 deletions queue_services/entity-emailer/tests/unit/test_tracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,14 @@
'filingId': '1112223333'
}
}),
('agmExtension_COMPLETED_1112223333',
{
'email': {
'type': 'agmExtension',
'option': 'COMPLETED',
'filingId': '1112223333'
}
}),
('alteration_PAID_1112223333',
{
'email': {
Expand Down

0 comments on commit 16e5417

Please sign in to comment.