Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

17930 - AGM Extensions Emailer #2327

Merged
merged 6 commits into from
Nov 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
argush3 marked this conversation as resolved.
Show resolved Hide resolved
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
chenhongjing marked this conversation as resolved.
Show resolved Hide resolved
)
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

Copy link
Collaborator Author

@JazzarKarim JazzarKarim Nov 24, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lint errors from previous PRs (not ours).


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>
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found this small typo.

[[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
Loading