Skip to content

Commit

Permalink
refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
kzdev420 committed Jul 16, 2024
1 parent 48fd9fe commit 5bbbed0
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 89 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
# 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 stage 1 overdue ARs notifications."""
"""Email processing rules and actions for involuntary_dissolution stage 1 overdue ARs notifications."""
from __future__ import annotations

from pathlib import Path
Expand All @@ -24,21 +24,34 @@
from entity_emailer.email_processors import (
get_entity_dashboard_url,
get_jurisdictions,
get_recipient_from_auth,
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
]

PROCESSABLE_LEGAL_TYPES = [
Business.LegalTypes.COMP,
Business.LegalTypes.BC_ULC_COMPANY,
Business.LegalTypes.BC_CCC,
Business.LegalTypes.BCOMP
]


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('ar_overdue_stage_1_notification: %s', email_info)
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 = get_business_by_furnishing_id(furnishing_id)
business = furnishing.business
business_identifier = business.identifier
template = Path(
f'{current_app.config.get("TEMPLATE_PATH")}/AR_OVERDUE_STAGE_1.html'
f'{current_app.config.get("TEMPLATE_PATH")}/INVOL-DIS-STAGE-1.html'
).read_text()
filled_template = substitute_template_parts(template)
# render template with vars
Expand Down Expand Up @@ -85,16 +98,17 @@ def get_extra_provincials(response: dict):
return extra_provincials


def update_furnishing_status(furnishing_id: int, status: str):
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.status = Furnishing.FurnishingStatus[status]
furnishing.save()


def get_business_by_furnishing_id(furnishing_id: int):
"""Return the business from furnishing."""
def is_processable(email_msg):
"""Determine if furnishing needs to be processed."""
furnishing_id = email_msg['data']['furnishing']['furnishingId']
furnishing = Furnishing.find_by_id(furnishing_id)
business_identifier = furnishing.business_identifier
business = Business.find_by_identifier(business_identifier)
return business
business = furnishing.business
return True if business.legal_type in PROCESSABLE_LEGAL_TYPES else False
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from flask import current_app
from legal_api.models import Business, Furnishing

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

Expand Down Expand Up @@ -62,14 +62,13 @@ 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':
message_id = email_msg.get('id', None)
identifier = email_msg.get('identifier', None)
furnishing_id = email_msg['data']['furnishing']['furnishingId']
business = ar_overdue_stage_1_notification.get_business_by_furnishing_id(furnishing_id)
if business.legal_type in ['BC', 'ULC', 'CC', 'BEN']:
if involuntary_dissolution_stage_1_notification.is_processable(email_msg):
source = email_msg.get('source', None)
return create_message_context_properties(etype, message_id, source, identifier, False)
return create_message_context_properties(etype, None, None, None, False)
else:
email = email_msg.get('email', None)
etype = email_msg.get('email', {}).get('type', None)
Expand Down Expand Up @@ -184,26 +183,12 @@ def complete_tracking_message(tracker_msg: MessageProcessing, email_msg):
"""Update existing message state to COMPLETED."""
update_message_status_to_complete(tracker_msg)

# Update corresponding furnishings entry as PROCESSED
etype = email_msg.get('type', None)
if etype and etype == 'bc.registry.dissolution':
furnishing_id = email_msg['data']['furnishing']['furnishingId']
ar_overdue_stage_1_notification.update_furnishing_status(furnishing_id,
Furnishing.FurnishingStatus.PROCESSED)


def mark_tracking_message_as_failed(message_context_properties: dict,
email_msg: dict,
existing_tracker_msg: MessageProcessing,
error_details: str):
"""Create a new message with FAILED status or update an existing message to FAILED status."""
# Update corresponding furnishings entry as FAILED
etype = email_msg.get('type', None)
if etype and etype == 'bc.registry.dissolution':
furnishing_id = email_msg['data']['furnishing']['furnishingId']
ar_overdue_stage_1_notification.update_furnishing_status(furnishing_id,
Furnishing.FurnishingStatus.FAILED)

if error_details and len(error_details) > 1000:
error_details = error_details[:1000]

Expand Down
17 changes: 14 additions & 3 deletions queue_services/entity-emailer/src/entity_emailer/worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
agm_extension_notification,
agm_location_change_notification,
amalgamation_notification,
ar_overdue_stage_1_notification,
involuntary_dissolution_stage_1_notification,
ar_reminder_notification,
bn_notification,
change_of_registration_notification,
Expand Down Expand Up @@ -144,8 +144,19 @@ def process_email(email_msg: dict, flask_app: Flask): # pylint: disable=too-man
email = bn_notification.process_bn_move(email_msg, token)
send_email(email, token)
elif etype and etype == 'bc.registry.dissolution':
email = ar_overdue_stage_1_notification.process(email_msg, token)
send_email(email, token)
email = involuntary_dissolution_stage_1_notification.process(email_msg, token)
# Confirm the data.furnishingName
furnishing_name = email_msg['data']['furnishing']['furnishingName']
if furnishing_name not in involuntary_dissolution_stage_1_notification.PROCESSABLE_FURNISHING_NAMES:
raise QueueException('Furnishing name is not valid.')
try:
send_email(email, token)
# Update corresponding furnishings entry as PROCESSED
involuntary_dissolution_stage_1_notification.post_process(email_msg, 'PROCESSED')
except:
# Update corresponding furnishings entry as FAILED
involuntary_dissolution_stage_1_notification.post_process(email_msg, 'FAILED')
raise
else:
etype = email_msg['email']['type']
option = email_msg['email']['option']
Expand Down
4 changes: 2 additions & 2 deletions queue_services/entity-emailer/tests/unit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -719,11 +719,11 @@ def create_batch():
return batch


def create_furnishing(business=None, batch_id=None, email='[email protected]'):
def create_furnishing(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 = 'DISSOLUTION_COMMENCEMENT_NO_AR'
furnishing.furnishing_name = furnishing_name
furnishing.status = Furnishing.FurnishingStatus.QUEUED
furnishing.email = email
if business:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@
# 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 stage 1 overdue ARs email processor."""
"""The Unit Tests for the involuntary_dissolution_stage_1_notification processor."""
from unittest.mock import patch

from entity_emailer.email_processors import ar_overdue_stage_1_notification
from entity_emailer.email_processors import involuntary_dissolution_stage_1_notification
from tests.unit import create_business, create_furnishing # noqa: I003


def test_ar_overdue_stage_1_notification(app, session, mocker):
"""Assert that the stage 1 overdue ARs notification can be processed."""
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'
Expand All @@ -44,10 +44,9 @@ def test_ar_overdue_stage_1_notification(app, session, mocker):

# test processor
mocker.patch(
'entity_emailer.email_processors.ar_overdue_stage_1_notification.get_jurisdictions',
'entity_emailer.email_processors.involuntary_dissolution_stage_1_notification.get_jurisdictions',
return_value=[])
with patch.object(ar_overdue_stage_1_notification, 'get_recipient_from_auth', return_value='[email protected]'):
email = ar_overdue_stage_1_notification.process(message_payload, token)
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]'
Expand Down
31 changes: 17 additions & 14 deletions queue_services/entity-emailer/tests/unit/test_tracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -524,18 +524,19 @@ async def test_should_correctly_track_retries_for_failed_processing(tracker_app,


@pytest.mark.asyncio
@pytest.mark.parametrize(['test_name', 'exception', 'legal_type', 'expected_status'], [
('When email is failed', EmailException, 'BC', 'FAILED'),
('When email is completed', None, 'BC', 'PROCESSED'),
('If legal_type is not in BC', None, 'CCC', 'QUEUED')
@pytest.mark.parametrize(['test_name', 'message_id', 'legal_type', 'is_processable'], [
('Will process the notification', 'BC-16fd2111-8baf-433b-82eb', 'BC', True),
('Will process the notification', 'ULC-16fd2111-8baf-433b-82eb', 'ULC', True),
('Will process the notification', 'CC-16fd2111-8baf-433b-82eb', 'CC', True),
('Will process the notification', 'BEN-16fd2111-8baf-433b-82eb', 'BEN', True),
('Will not process the notification', 'SP-16fd2111-8baf-433b-82eb', 'SP', False)
])
async def test_should_update_furnishing_status_with_message_status(tracker_app, tracker_db, session,
test_name, exception, legal_type, expected_status):
test_name, message_id, legal_type, is_processable):
"""Assert that furnishing is marked with message status."""
message_id = '16fd2111-8baf-433b-82eb-8c7fada84ccc'
business_identifier = 'BC1234567'
business = create_business(business_identifier, legal_type, 'Test Business')
furnishing = create_furnishing(session, business)
furnishing = create_furnishing(business=business)
message_payload = {
'specversion': '1.x-wip',
'type': 'bc.registry.dissolution',
Expand All @@ -554,11 +555,13 @@ async def test_should_update_furnishing_status_with_message_status(tracker_app,
}
mock_msg = create_mock_message(message_payload)

with patch.object(worker, 'process_email', return_value=True, side_effect=exception):
if exception:
with pytest.raises(exception):
await worker.cb_subscription_handler(mock_msg)
else:
await worker.cb_subscription_handler(mock_msg)
with patch.object(worker, 'process_email', return_value=True):
await worker.cb_subscription_handler(mock_msg)

assert furnishing.status.name == expected_status
result = MessageProcessing.find_message_by_message_id(message_id)
if is_processable:
assert result
assert result.message_id == message_id
assert result.status == 'COMPLETE'
else:
assert result is None
77 changes: 45 additions & 32 deletions queue_services/entity-emailer/tests/unit/test_worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@
from unittest.mock import patch

import pytest
from entity_queue_common.service_utils import QueueException
from entity_queue_common.service_utils import EmailException, QueueException
from legal_api.models import Business
from legal_api.services import NameXService
from legal_api.services.bootstrap import AccountService
from legal_api.utils.legislation_datetime import LegislationDatetime

from entity_emailer import worker
from entity_emailer.email_processors import (
ar_overdue_stage_1_notification,
involuntary_dissolution_stage_1_notification,
ar_reminder_notification,
correction_notification,
filing_notification,
Expand Down Expand Up @@ -471,40 +471,53 @@ def test_send_email_with_incomplete_payload(app, session, email_msg):
assert 'Unsuccessful sending email' in str(excinfo)


def test_ar_overdue_stage_1_notification(app, session, mocker):
@pytest.mark.parametrize(['test_name', 'exception', 'furnishing_name', 'expected_furnishing_status'], [
('Will be failed with invalid furnishing_name', QueueException, 'INVALID_NAME', 'QUEUED'),
('Will be processed with valid furnishing_name', None, 'DISSOLUTION_COMMENCEMENT_NO_AR', 'PROCESSED'),
('Will be processed with valid furnishing_name', None, 'DISSOLUTION_COMMENCEMENT_NO_TR', 'PROCESSED'),
('Will be processed with valid furnishing_name', None, 'DISSOLUTION_COMMENCEMENT_NO_AR_XPRO', 'PROCESSED'),
('Will be processed with valid furnishing_name', None, 'DISSOLUTION_COMMENCEMENT_NO_TR_XPRO', 'PROCESSED'),
('When email is failed', EmailException, 'DISSOLUTION_COMMENCEMENT_NO_AR', 'FAILED')
])
def test_involuntary_dissolution_stage_1_notification(app, db, session, mocker, test_name, exception, furnishing_name, expected_furnishing_status):
"""Assert that the stage 1 overdue ARs notification can be processed."""
token = 'token'
business_identifier = 'BC1234567'
business = create_business(business_identifier, 'BC', 'Test Business')
furnishing = create_furnishing(business)
furnishing = create_furnishing(business=business)

mocker.patch(
'entity_emailer.email_processors.ar_overdue_stage_1_notification.get_jurisdictions',
'entity_emailer.email_processors.involuntary_dissolution_stage_1_notification.get_jurisdictions',
return_value=[])


message_payload = {
'specversion': '1.x-wip',
'type': 'bc.registry.dissolution',
'source': 'furnishingsJob',
'id': '16fd2111-8baf-433b-82eb-8c7fada84ccc',
'time': '',
'datacontenttype': 'application/json',
'identifier': business_identifier,
'data': {
'furnishing': {
'type': 'PROCESSING',
'furnishingId': furnishing.id,
'furnishingName': furnishing_name
}
}
}

# run worker
with patch.object(AccountService, 'get_bearer_token', return_value=token):
with patch.object(worker, 'send_email', return_value='success') as mock_send_email:
with patch.object(ar_overdue_stage_1_notification, 'get_recipient_from_auth', return_value='[email protected]'):
worker.process_email({
'specversion': '1.x-wip',
'type': 'bc.registry.dissolution',
'source': 'furnishingsJob',
'id': 'f36e3af7-90c3-4859-a6f6-2feefbdc1e37',
'time': '',
'datacontenttype': 'application/json',
'identifier': business_identifier,
'data': {
'furnishing': {
'type': 'PROCESSING',
'furnishingId': furnishing.id,
'furnishingName': furnishing.furnishing_name
}
}
}, app)

call_args = mock_send_email.call_args
assert call_args[0][0]['content']['subject'] == f'Attention {business_identifier} - Test Business'
assert call_args[0][0]['recipients'] == '[email protected]'
assert call_args[0][0]['content']['body']
assert call_args[0][1] == token
with patch.object(worker, 'send_email', return_value='success', side_effect=exception) as mock_send_email:
if exception:
with pytest.raises(exception):
worker.process_email(message_payload, app)
else:
worker.process_email(message_payload, app)

if furnishing_name != 'INVALID_NAME':
call_args = mock_send_email.call_args
assert call_args[0][0]['content']['subject'] == f'Attention {business_identifier} - Test Business'
assert call_args[0][0]['recipients'] == '[email protected]'
assert call_args[0][0]['content']['body']

assert furnishing.status.name == expected_furnishing_status

0 comments on commit 5bbbed0

Please sign in to comment.