def process( business: Business, # pylint: disable=too-many-branches filing: Dict, filing_rec: Filing, filing_meta: FilingMeta): # pylint: disable=too-many-branches """Process the incoming incorporation filing.""" # Extract the filing information for incorporation incorp_filing = filing.get('filing', {}).get('incorporationApplication') is_correction = filing_rec.filing_type == 'correction' filing_meta.incorporation_application = {} if not incorp_filing: raise QueueException( f'IA legal_filing:incorporationApplication missing from {filing_rec.id}' ) if business and not is_correction: raise QueueException( f'Business Already Exist: IA legal_filing:incorporationApplication {filing_rec.id}' ) business_info_obj = incorp_filing.get('nameRequest') if is_correction: business_info.set_legal_name(business.identifier, business, business_info_obj) else: if filing_rec.colin_event_ids: corp_num = filing['filing']['business']['identifier'] else: # Reserve the Corp Number for this entity corp_num = get_next_corp_num(business_info_obj['legalType']) if not corp_num: raise QueueException( f'incorporationApplication {filing_rec.id} unable to get a business registration number.' ) # Initial insert of the business record business = Business() business = business_info.update_business_info(corp_num, business, business_info_obj, filing_rec) business = _update_cooperative(incorp_filing, business, filing_rec) if nr_number := business_info_obj.get('nrNumber', None): filing_meta.incorporation_application = { **filing_meta.incorporation_application, **{ 'nrNumber': nr_number, 'legalName': business_info_obj.get('legalName', None) } } if not business: raise QueueException( f'IA incorporationApplication {filing_rec.id}, Unable to create business.' )
async def test_should_correctly_track_retries_for_failed_processing( tracker_app, tracker_db, session): """Assert that message processing retries are properly tracked.""" message_id = '16fd2111-8baf-433b-82eb-8c7fada84eee' message_payload = { 'specversion': '1.x-wip', 'type': 'bc.registry.names.request', 'source': 'nr_pay', 'id': message_id, 'time': '', 'datacontenttype': 'application/json', 'identifier': '781020202', 'data': { 'header': { 'nrNum': '781020202' }, 'paymentToken': '234234234324asjdkfhjsdhf23949239423', 'statusCode': 'PAID' } } mock_msg = create_mock_message(message_payload) # mock out process_email function to throw exception to simulate failed scenario with patch.object(worker, 'process_email', side_effect=QueueException('Queue Error.')): for x in range(5): await worker.cb_subscription_handler(mock_msg) result = MessageProcessing.find_message_by_message_id( message_id=message_id) assert result assert result.status == 'FAILED' assert result.message_seen_count == 5 assert result.last_error == 'QueueException, Exception - Queue Error.'
def process(business: Business, filing: Dict): """Render the annual_report onto the business model objects.""" if not (dissolution_filing := filing.get('filing', {}).get('voluntaryDissolution')): logger.error('Could not find Voluntary Dissolution in: %s', filing) raise QueueException( f'legal_filing:voluntaryDissolution missing from {filing}')
async def process_event(event_message, flask_app): """Render the org status.""" if not flask_app: raise QueueException('Flask App not available.') with flask_app.app_context(): message_type = event_message.get('type', None) data = event_message.get('data') org_id = data.get('accountId') org: OrgModel = OrgModel.find_by_org_id(org_id) if org is None: logger.error('Unknown org for orgid %s', org_id) return if message_type == LOCK_ACCOUNT_MESSAGE_TYPE: org.status_code = OrgStatus.NSF_SUSPENDED.value org.suspended_on = datetime.now() await publish_mailer_events(LOCK_ACCOUNT_MESSAGE_TYPE, org_id) elif message_type == UNLOCK_ACCOUNT_MESSAGE_TYPE: org.status_code = OrgStatus.ACTIVE.value await publish_mailer_events(UNLOCK_ACCOUNT_MESSAGE_TYPE, org_id) else: logger.error('Unknown Message Type : %s', message_type) return org.flush() db.session.commit()
def process(business: Business, filing_rec: Filing, filing: Dict, filing_meta: FilingMeta): # pylint: disable=too-many-locals; 1 extra """Process the incoming transition filing.""" # Extract the filing information for transition application if not (transition_filing := filing.get('transition')): # pylint: disable=superfluous-parens; raise QueueException( f'legal_filing:transition data missing from {filing_rec.id}')
def process_filing(filing_msg: Dict, flask_app: Flask): """Render the filings contained in the submission.""" if not flask_app: raise QueueException('Flask App not available.') with flask_app.app_context(): filing_submission = Filing.find_by_id(filing_msg['filing']['id']) if not filing_submission: raise QueueException if filing_submission.status == Filing.Status.COMPLETED.value: logger.warning('QueueFiler: Attempting to reprocess business.id=%s, filing.id=%s filing=%s', filing_submission.business_id, filing_submission.id, filing_msg) return legal_filings = filing_submission.legal_filings() if legal_filings: uow = versioning_manager.unit_of_work(db.session) transaction = uow.create_transaction(db.session) business = Business.find_by_internal_id(filing_submission.business_id) for filing in legal_filings: if filing.get('annualReport'): annual_report.process(business, filing) elif filing.get('changeOfAddress'): change_of_address.process(business, filing) elif filing.get('changeOfDirectors'): filing['colinIds'] = filing_submission.colin_event_ids change_of_directors.process(business, filing) elif filing.get('changeOfName'): change_of_name.process(business, filing) elif filing.get('specialResolution'): pass # nothing to do here elif filing.get('voluntaryDissolution'): voluntary_dissolution.process(business, filing) elif filing.get('incorporationApplication'): incorporation_filing.process(business, filing, flask_app) filing_submission.transaction_id = transaction.id filing_submission.set_processed() db.session.add(business) db.session.add(filing_submission) db.session.commit() publish_event(business, filing_submission) return
def process_email(email_dict: dict, flask_app: Flask, token: str): # pylint: disable=too-many-branches """Process the email contained in the message.""" if not flask_app: raise QueueException('Flask App not available.') with flask_app.app_context(): logger.debug('Attempting to process email: %s', email_dict.get('recipients', '')) # get type from email notification_service.send_email(email_dict, token=token)
async def process_payment(payment_token, flask_app): """Render the payment status.""" if not flask_app: raise QueueException('Flask App not available.') with flask_app.app_context(): # try to find the filing 5 times before putting back on the queue - in case payment token ends up on the queue # before it is assigned to filing. counter = 1 filing_submission = None while not filing_submission and counter <= 5: filing_submission = get_filing_by_payment_id(payment_token['paymentToken'].get('id')) counter += 1 if not filing_submission: await asyncio.sleep(0.2) if not filing_submission: raise FilingException if filing_submission.status == Filing.Status.COMPLETED.value: # log and skip this # it shouldn't be an error, but there could be something to investigate if # multiple retries are happening on something that should have been completed. logger.warning('Queue: Attempting to reprocess business.id=%s, filing.id=%s payment=%s', filing_submission.business_id, filing_submission.id, payment_token) capture_message(f'Queue Issue: Attempting to reprocess business.id={filing_submission.business_id},' 'filing.id={filing_submission.id} payment={payment_token}') return if payment_token['paymentToken'].get('statusCode') == 'TRANSACTION_FAILED': # TODO: The customer has cancelled out of paying, so we could note this better # technically the filing is still pending payment/processing return if payment_token['paymentToken'].get('statusCode') == Filing.Status.COMPLETED.value: filing_submission.payment_completion_date = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc) db.session.add(filing_submission) db.session.commit() if not filing_submission.effective_date or \ filing_submission.effective_date <= \ datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc): # if we're not a future effective date, then submit for processing try: await publish_filing(filing_submission) except Exception as err: # pylint: disable=broad-except, unused-variable # noqa F841; # mark any failure for human review capture_message( 'Queue Error: Failied to place filing:{filing_submission.id} on Queue with error:{err}', level='error') return # if we're here and haven't been able to action it, # then we've received an unknown status and should throw an error logger.error('Unknown payment status given: %s', payment_token['paymentToken'].get('statusCode')) raise QueueException
def process_email(email_msg: dict, flask_app: Flask): # pylint: disable=too-many-branches """Process the email contained in the submission.""" if not flask_app: raise QueueException('Flask App not available.') with flask_app.app_context(): logger.debug('Attempting to process email: %s', email_msg) token = AccountService.get_bearer_token() etype = email_msg.get('type', None) if etype and etype == 'bc.registry.names.request': option = email_msg.get('data', {}).get('request', {}).get('option', None) if option and option in [ nr_notification.Option.BEFORE_EXPIRY.value, nr_notification.Option.EXPIRED.value, nr_notification.Option.RENEWAL.value, nr_notification.Option.UPGRADE.value, nr_notification.Option.REFUND.value ]: email = nr_notification.process(email_msg, option) else: email = name_request.process(email_msg) send_email(email, token) elif etype and etype == 'bc.registry.affiliation': email = affiliation_notification.process(email_msg, token) send_email(email, token) else: etype = email_msg['email']['type'] option = email_msg['email']['option'] if etype == 'businessNumber': email = bn_notification.process(email_msg['email']) send_email(email, token) elif etype == 'incorporationApplication' and option == 'mras': email = mras_notification.process(email_msg['email']) send_email(email, token) elif etype == 'annualReport' and option == 'reminder': email = ar_reminder_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) elif etype in filing_notification.FILING_TYPE_CONVERTER.keys(): if etype == 'annualReport' and option == Filing.Status.COMPLETED.value: logger.debug('No email to send for: %s', email_msg) else: email = filing_notification.process( email_msg['email'], token) if email: send_email(email, token) else: # should only be if this was for a a coops filing logger.debug('No email to send for: %s', email_msg) else: logger.debug('No email to send for: %s', email_msg)
async def process_event(event_message, flask_app): """Render the org status.""" if not flask_app: raise QueueException('Flask App not available.') with flask_app.app_context(): message_type = event_message.get('type', None) if message_type == 'bc.registry.names.events': await process_name_events(event_message)
def process( business: Business, # pylint: disable=too-many-branches filing: Dict, filing_rec: Filing, filing_meta: FilingMeta): # pylint: disable=too-many-branches """Process the incoming historic conversion filing.""" # Extract the filing information for incorporation if not (conversion_filing := filing.get('filing', {}).get('conversion')): raise QueueException( f'CONVL legal_filing:conversion missing from {filing_rec.id}')
async def process_event(event_message, flask_app): """Render the payment status.""" if not flask_app: raise QueueException('Flask App not available.') with flask_app.app_context(): if event_message.get( 'type', None) == 'bc.registry.payment.casSettlementUploaded': await _reconcile_payments(event_message) else: raise Exception('Invalid type')
async def process_event(event_message, flask_app): """Render the payment status.""" if not flask_app: raise QueueException('Flask App not available.') with flask_app.app_context(): if (message_type := event_message.get( 'type', None)) == 'bc.registry.payment.casSettlementUploaded': await reconcile_payments(event_message) elif message_type == 'bc.registry.payment.cgi.ACKReceived': await reconcile_distributions(event_message)
def process(business: Business, filing: Dict, filing_rec: Filing): # pylint: disable=too-many-locals; 1 extra """Process the incoming incorporation filing.""" # Extract the filing information for incorporation incorp_filing = filing.get('incorporationApplication') is_correction = filing_rec.filing_type == 'correction' if not incorp_filing: raise QueueException( f'IA legal_filing:incorporationApplication missing from {filing_rec.id}' ) if business and not is_correction: raise QueueException( f'Business Already Exist: IA legal_filing:incorporationApplication {filing_rec.id}' ) business_info_obj = incorp_filing.get('nameRequest') if is_correction: business_info.set_legal_name(business.identifier, business, business_info_obj) else: # Reserve the Corp Number for this entity corp_num = get_next_corp_num(business_info_obj['legalType']) if not corp_num: raise QueueException( f'incorporationApplication {filing_rec.id} unable to get a business registration number.' ) # Initial insert of the business record business = Business() business = business_info.update_business_info(corp_num, business, business_info_obj, filing_rec) if not business: raise QueueException( f'IA incorporationApplication {filing_rec.id}, Unable to create business.' ) if offices := incorp_filing['offices']: update_offices(business, offices)
async def process_event(event_message, flask_app): """Insert into Activity log table.""" if not flask_app: raise QueueException('Flask App not available.') with flask_app.app_context(): data = event_message.get('data') logger.debug('message_type received %s', data) activity_model: ActivityLogModel = ActivityLogModel( actor_id=data.get('actor'), action=data.get('action'), item_type=data.get('itemType'), item_name=data.get('itemName'), item_id=data.get('itemId'), remote_addr=data.get('remoteAddr'), created=data.get('createdAt'), org_id=data.get('orgId')) activity_model.save() logger.debug('activity log saved')
async def process_event(event_message, flask_app): """Render the payment status.""" if not flask_app: raise QueueException('Flask App not available.') with flask_app.app_context(): if event_message.get('type', None) == INCORPORATION_TYPE \ and 'tempidentifier' in event_message \ and event_message.get('tempidentifier', None) is not None: old_identifier = event_message.get('tempidentifier') new_identifier = event_message.get('identifier') logger.debug('Received message to update %s to %s', old_identifier, new_identifier) # Find all invoice records which have the old corp number invoices = Invoice.find_by_business_identifier(old_identifier) for inv in invoices: inv.business_identifier = new_identifier inv.flush() db.session.commit()
async def process_event(event_message: dict, flask_app): """Process the incoming queue event message.""" if not flask_app: raise QueueException('Flask App not available.') with flask_app.app_context(): message_type = event_message.get('type', None) email_msg = None email_dict = None token = RestService.get_service_account_token() if message_type == 'account.mailer': email_msg = json.loads(event_message.get('data')) email_dict = payment_completed.process(email_msg) elif message_type == 'bc.registry.payment.refundRequest': email_msg = event_message.get('data') email_dict = refund_requested.process(email_msg) elif event_message.get('type', None) == 'bc.registry.payment.padAccountCreate': email_msg = event_message.get('data') email_dict = pad_confirmation.process(email_msg, token) logger.debug('Extracted email msg: %s', email_dict) process_email(email_dict, FLASK_APP, token)
def process_email(email_msg: dict, flask_app: Flask): # pylint: disable=too-many-branches """Process the email contained in the submission.""" if not flask_app: raise QueueException('Flask App not available.') with flask_app.app_context(): logger.debug('Attempting to process email: %s', email_msg) token = AccountService.get_bearer_token() etype = email_msg.get('type', None) if etype and etype == 'bc.registry.names.request': email = name_request.process(email_msg) send_email(email, token) else: etype = email_msg['email']['type'] option = email_msg['email']['option'] if etype == 'businessNumber': email = bn_notification.process(email_msg['email']) send_email(email, token) elif etype == 'incorporationApplication' and option == 'mras': email = mras_notification.process(email_msg['email']) send_email(email, token) elif etype in filing_notification.FILING_TYPE_CONVERTER.keys(): if etype == 'annualReport' and option == Filing.Status.COMPLETED.value: logger.debug('No email to send for: %s', email_msg) # Remove this when self serve alteration is implemented. elif etype == 'alteration' and option == Filing.Status.PAID.value: logger.debug('No email to send for: %s', email_msg) else: email = filing_notification.process( email_msg['email'], token) if email: send_email(email, token) else: # should only be if this was for a a coops filing logger.debug('No email to send for: %s', email_msg) else: logger.debug('No email to send for: %s', email_msg)
from entity_filer.filing_processors.filing_components import aliases, business_info, business_profile, shares from entity_filer.filing_processors.filing_components.offices import update_offices from entity_filer.filing_processors.filing_components.parties import update_parties def process(business: Business, filing: Dict, filing_rec: Filing): # pylint: disable=too-many-branches """Process the incoming historic conversion filing.""" # Extract the filing information for incorporation if not (conversion_filing := filing.get('filing', {}).get('conversion')): raise QueueException( f'CONVL legal_filing:conversion missing from {filing_rec.id}') if business: raise QueueException( f'Business Already Exist: CONVL legal_filing:conversion {filing_rec.id}' ) if not (corp_num := filing.get('filing', {}).get('business', {}).get('identifier')): raise QueueException( f'conversion {filing_rec.id} missing the business idnetifier.') # Initial insert of the business record business_info_obj = conversion_filing.get('nameRequest') if not (business := business_info.update_business_info( corp_num, Business(), business_info_obj, filing_rec)): raise QueueException( f'CONVL conversion {filing_rec.id}, Unable to create business.') if offices := conversion_filing.get('offices'):
def process(business: Business, filing: Dict, filing_rec: Filing): # pylint: disable=too-many-locals; 1 extra """Process the incoming incorporation filing.""" # Extract the filing information for incorporation incorp_filing = filing.get('incorporationApplication') if not incorp_filing: raise QueueException( f'IA legal_filing:incorporationApplication missing from {filing_rec.id}' ) if business: raise QueueException( f'Business Already Exist: IA legal_filing:incorporationApplication {filing_rec.id}' ) offices = incorp_filing.get('offices', None) parties = incorp_filing.get('parties', None) business_info = incorp_filing.get('nameRequest') share_classes = incorp_filing['shareClasses'] # Reserve the Corp Numper for this entity corp_num = get_next_corp_num(business_info['legalType']) if not corp_num: raise QueueException( f'incorporationApplication {filing_rec.id} unable to get a business registration number.' ) # Initial insert of the business record business = Business() business = update_business_info(corp_num, business, business_info, incorp_filing, filing_rec) if not business: raise QueueException( f'IA incorporationApplication {filing_rec.id}, Unable to create business.' ) for office_type, addresses in offices.items(): office = create_office(business, office_type, addresses) business.offices.append(office) if parties: for party_info in parties: party = create_party(business_id=business.id, party_info=party_info, create=False) for role_type in party_info.get('roles'): role = { 'roleType': role_type.get('roleType'), 'appointmentDate': role_type.get('appointmentDate', None), 'cessationDate': role_type.get('cessationDate', None) } party_role = create_role(party=party, role_info=role) business.party_roles.append(party_role) if share_classes: for share_class_info in share_classes: share_class = create_share_class(share_class_info) business.share_classes.append(share_class) ia_json = copy.deepcopy(filing_rec.filing_json) ia_json['filing']['business']['identifier'] = business.identifier ia_json['filing']['business'][ 'foundingDate'] = business.founding_date.isoformat() filing_rec._filing_json = ia_json # pylint: disable=protected-access; bypass to update filing data return business, filing_rec
async def process_filing(filing_msg: Dict, flask_app: Flask): # pylint: disable=too-many-branches,too-many-statements """Render the filings contained in the submission.""" if not flask_app: raise QueueException('Flask App not available.') with flask_app.app_context(): filing_submission = Filing.find_by_id(filing_msg['filing']['id']) if not filing_submission: raise QueueException if filing_submission.status == Filing.Status.COMPLETED.value: logger.warning( 'QueueFiler: Attempting to reprocess business.id=%s, filing.id=%s filing=%s', filing_submission.business_id, filing_submission.id, filing_msg) return None, None if legal_filings := filing_submission.legal_filings(): uow = versioning_manager.unit_of_work(db.session) transaction = uow.create_transaction(db.session) business = Business.find_by_internal_id( filing_submission.business_id) for filing in legal_filings: if filing.get('alteration'): alteration.process(business, filing_submission, filing) if filing.get('annualReport'): annual_report.process(business, filing) elif filing.get('changeOfAddress'): change_of_address.process(business, filing) elif filing.get('changeOfDirectors'): filing['colinIds'] = filing_submission.colin_event_ids change_of_directors.process(business, filing) elif filing.get('changeOfName'): change_of_name.process(business, filing) elif filing.get('voluntaryDissolution'): voluntary_dissolution.process(business, filing) elif filing.get('incorporationApplication'): business, filing_submission = incorporation_filing.process( business, filing, filing_submission) if filing.get('correction'): filing_submission = correction.process( filing_submission, filing) if filing.get('transition'): filing_submission = transition.process( business, filing_submission, filing) filing_submission.transaction_id = transaction.id filing_submission.set_processed() db.session.add(business) db.session.add(filing_submission) db.session.commit() # post filing changes to other services if any('alteration' in x for x in legal_filings): if name_request.has_new_nr_for_alteration( business, filing_submission.filing_json): name_request.consume_nr( business, filing_submission, '/filing/alteration/nameRequest/nrNumber') alteration.post_process(business, filing_submission) db.session.add(business) db.session.commit() AccountService.update_entity( business_registration=business.identifier, business_name=business.legal_name, corp_type_code=business.legal_type) if any('incorporationApplication' in x for x in legal_filings): if any('correction' in x for x in legal_filings): if name_request.has_new_nr_for_correction( filing_submission.filing_json): name_request.consume_nr(business, filing_submission) else: filing_submission.business_id = business.id db.session.add(filing_submission) db.session.commit() incorporation_filing.update_affiliation( business, filing_submission) name_request.consume_nr(business, filing_submission) incorporation_filing.post_process(business, filing_submission) try: await publish_email_message( qsm, APP_CONFIG.EMAIL_PUBLISH_OPTIONS['subject'], filing_submission, 'mras') except Exception as err: # pylint: disable=broad-except, unused-variable # noqa F841; # mark any failure for human review capture_message( f'Queue Error: Failed to place email for filing:{filing_submission.id}' f'on Queue with error:{err}', level='error') try: await publish_email_message( qsm, APP_CONFIG.EMAIL_PUBLISH_OPTIONS['subject'], filing_submission, filing_submission.status) except Exception as err: # pylint: disable=broad-except, unused-variable # noqa F841; # mark any failure for human review capture_message( f'Queue Error: Failed to place email for filing:{filing_submission.id}' f'on Queue with error:{err}', level='error') try: await publish_event(business, filing_submission) except Exception as err: # pylint: disable=broad-except, unused-variable # noqa F841; # mark any failure for human review capture_message( f'Queue Error: Failed to publish event for filing:{filing_submission.id}' f'on Queue with error:{err}', level='error')
from entity_filer.filing_processors.filing_components import aliases, shares from entity_filer.filing_processors.filing_components.offices import update_offices from entity_filer.filing_processors.filing_components.parties import update_parties def process(business: Business, filing_rec: Filing, filing: Dict, filing_meta: FilingMeta): # pylint: disable=too-many-locals; 1 extra """Process the incoming transition filing.""" # Extract the filing information for transition application if not (transition_filing := filing.get('transition')): # pylint: disable=superfluous-parens; raise QueueException( f'legal_filing:transition data missing from {filing_rec.id}') if not business: raise QueueException( f'Business does not exist: legal_filing:transitionApplication {filing_rec.id}' ) # Initial insert of the business record business.restriction_ind = transition_filing.get('hasProvisions') if offices := transition_filing['offices']: update_offices(business, offices) if parties := transition_filing.get('parties'): update_parties(business, parties) if share_structure := transition_filing['shareStructure']: shares.update_share_structure(business, share_structure) if name_translations := transition_filing.get('nameTranslations'):
async def process_event(event_message: dict, flask_app): """Process the incoming queue event message.""" if not flask_app: raise QueueException('Flask App not available.') with flask_app.app_context(): message_type = event_message.get('type', None) email_msg = event_message.get('data') email_msg['logo_url'] = minio_service.MinioService.get_minio_public_url('bc_logo_for_email.png') email_dict = None token = RestService.get_service_account_token() logger.debug('message_type recieved %s', message_type) if message_type == 'account.mailer': email_dict = payment_completed.process(email_msg) elif message_type == MessageType.REFUND_REQUEST.value: email_dict = refund_requested.process(email_msg) elif message_type == MessageType.PAD_ACCOUNT_CREATE.value: email_msg['registry_logo_url'] = minio_service.MinioService.get_minio_public_url('bc_registry_logo_pdf.svg') email_dict = pad_confirmation.process(email_msg, token) elif message_type == MessageType.NSF_LOCK_ACCOUNT.value: logger.debug('lock account message recieved:') template_name = TemplateType.NSF_LOCK_ACCOUNT_TEMPLATE_NAME.value org_id = email_msg.get('accountId') admin_coordinator_emails = get_member_emails(org_id, (ADMIN, COORDINATOR)) subject = SubjectType.NSF_LOCK_ACCOUNT_SUBJECT.value logo_url = email_msg.get('logo_url') email_dict = common_mailer.process(org_id, admin_coordinator_emails, template_name, subject, logo_url=logo_url) elif message_type == MessageType.NSF_UNLOCK_ACCOUNT.value: logger.debug('unlock account message recieved') template_name = TemplateType.NSF_UNLOCK_ACCOUNT_TEMPLATE_NAME.value org_id = email_msg.get('accountId') admin_coordinator_emails = get_member_emails(org_id, (ADMIN, COORDINATOR)) subject = SubjectType.NSF_UNLOCK_ACCOUNT_SUBJECT.value logo_url = email_msg.get('logo_url') email_dict = common_mailer.process(org_id, admin_coordinator_emails, template_name, subject, logo_url=logo_url) elif message_type == MessageType.ACCOUNT_CONFIRMATION_PERIOD_OVER.value: template_name = TemplateType.ACCOUNT_CONF_OVER_TEMPLATE_NAME.value org_id = email_msg.get('accountId') nsf_fee = email_msg.get('nsfFee') admin_coordinator_emails = get_member_emails(org_id, (ADMIN,)) subject = SubjectType.ACCOUNT_CONF_OVER_SUBJECT.value logo_url = email_msg.get('logo_url') email_dict = common_mailer.process(org_id, admin_coordinator_emails, template_name, subject, nsf_fee=nsf_fee, logo_url=logo_url) elif message_type in (MessageType.TEAM_MODIFIED.value, MessageType.TEAM_MEMBER_INVITED.value): logger.debug('Team Modified message received') template_name = TemplateType.TEAM_MODIFIED_TEMPLATE_NAME.value org_id = email_msg.get('accountId') admin_coordinator_emails = get_member_emails(org_id, (ADMIN,)) subject = SubjectType.TEAM_MODIFIED_SUBJECT.value logo_url = email_msg.get('logo_url') email_dict = common_mailer.process(org_id, admin_coordinator_emails, template_name, subject, logo_url=logo_url) elif message_type == MessageType.ADMIN_REMOVED.value: logger.debug('ADMIN_REMOVED message received') template_name = TemplateType.ADMIN_REMOVED_TEMPLATE_NAME.value org_id = email_msg.get('accountId') recipient_email = email_msg.get('recipientEmail') subject = SubjectType.ADMIN_REMOVED_SUBJECT.value logo_url = email_msg.get('logo_url') email_dict = common_mailer.process(org_id, recipient_email, template_name, subject, logo_url=logo_url) elif message_type == MessageType.PAD_INVOICE_CREATED.value: template_name = TemplateType.PAD_INVOICE_CREATED_TEMPLATE_NAME.value org_id = email_msg.get('accountId') admin_coordinator_emails = get_member_emails(org_id, (ADMIN,)) subject = SubjectType.PAD_INVOICE_CREATED.value args = { 'nsf_fee': email_msg.get('nsfFee'), 'invoice_total': email_msg.get('invoice_total'), } logo_url = email_msg.get('logo_url') email_dict = common_mailer.process(org_id, admin_coordinator_emails, template_name, subject, logo_url=logo_url, **args) elif message_type in (MessageType.ONLINE_BANKING_OVER_PAYMENT.value, MessageType.ONLINE_BANKING_UNDER_PAYMENT.value, MessageType.ONLINE_BANKING_PAYMENT.value): if message_type == MessageType.ONLINE_BANKING_OVER_PAYMENT.value: template_name = TemplateType.ONLINE_BANKING_OVER_PAYMENT_TEMPLATE_NAME.value elif message_type == MessageType.ONLINE_BANKING_UNDER_PAYMENT.value: template_name = TemplateType.ONLINE_BANKING_UNDER_PAYMENT_TEMPLATE_NAME.value else: template_name = TemplateType.ONLINE_BANKING_PAYMENT_TEMPLATE_NAME.value org_id = email_msg.get('accountId') admin_emails = get_member_emails(org_id, (ADMIN,)) subject = SubjectType.ONLINE_BANKING_PAYMENT_SUBJECT.value args = { 'title': subject, 'paid_amount': email_msg.get('amount'), 'credit_amount': email_msg.get('creditAmount'), } logo_url = email_msg.get('logo_url') email_dict = common_mailer.process(org_id, admin_emails, template_name, subject, logo_url=logo_url, **args) elif message_type == MessageType.PAD_SETUP_FAILED.value: template_name = TemplateType.PAD_SETUP_FAILED_TEMPLATE_NAME.value org_id = email_msg.get('accountId') admin_coordinator_emails = get_member_emails(org_id, (ADMIN,)) subject = SubjectType.PAD_SETUP_FAILED.value args = { 'accountId': email_msg.get('accountId'), } logo_url = email_msg.get('logo_url') email_dict = common_mailer.process(org_id, admin_coordinator_emails, template_name, subject, logo_url=logo_url, **args) elif message_type == MessageType.PAYMENT_PENDING.value: template_name = TemplateType.PAYMENT_PENDING_TEMPLATE_NAME.value org_id = email_msg.get('accountId') admin_coordinator_emails = get_member_emails(org_id, (ADMIN,)) subject = SubjectType.PAYMENT_PENDING.value args = { 'accountId': email_msg.get('accountId'), 'cfsAccountId': email_msg.get('cfsAccountId'), 'transactionAmount': email_msg.get('transactionAmount'), } logo_url = email_msg.get('logo_url') email_dict = common_mailer.process(org_id, admin_coordinator_emails, template_name, subject, logo_url=logo_url, **args) elif message_type == MessageType.EJV_FAILED.value: email_dict = ejv_failures.process(email_msg) if email_dict: logger.debug('Extracted email msg Recipient: %s ', email_dict.get('recipients', '')) process_email(email_dict, FLASK_APP, token) else: # TODO probably an unhandled event.handle better logger.error('No email content generated')
async def process_filing(filing_msg: Dict, flask_app: Flask): # pylint: disable=too-many-branches,too-many-statements """Render the filings contained in the submission. Start the migration to using core/Filing """ if not flask_app: raise QueueException('Flask App not available.') with flask_app.app_context(): # filing_submission = Filing.find_by_id(filing_msg['filing']['id']) filing_core_submission = FilingCore.find_by_id( filing_msg['filing']['id']) if not filing_core_submission: raise QueueException filing_submission = filing_core_submission.storage if filing_core_submission.status == Filing.Status.COMPLETED: logger.warning( 'QueueFiler: Attempting to reprocess business.id=%s, filing.id=%s filing=%s', filing_submission.business_id, filing_submission.id, filing_msg) return None, None # convenience flag to set that the envelope is a correction is_correction = (filing_core_submission.filing_type == FilingCore.FilingTypes.CORRECTION) if legal_filings := filing_core_submission.legal_filings( with_diff=False): uow = versioning_manager.unit_of_work(db.session) transaction = uow.create_transaction(db.session) business = Business.find_by_internal_id( filing_submission.business_id) filing_meta = FilingMeta( application_date=filing_submission.effective_date, legal_filings=[ item for sublist in [list(x.keys()) for x in legal_filings] for item in sublist ]) for filing in legal_filings: if filing.get('alteration'): alteration.process(business, filing_submission, filing, filing_meta, is_correction) elif filing.get('annualReport'): annual_report.process(business, filing, filing_meta) elif filing.get('changeOfAddress'): change_of_address.process(business, filing, filing_meta) elif filing.get('changeOfDirectors'): filing['colinIds'] = filing_submission.colin_event_ids change_of_directors.process(business, filing, filing_meta) elif filing.get('changeOfName'): change_of_name.process(business, filing, filing_meta) elif filing.get('dissolution'): dissolution.process(business, filing, filing_meta) elif filing.get('incorporationApplication'): business, filing_submission, filing_meta = incorporation_filing.process( business, filing_core_submission.json, filing_submission, filing_meta) elif filing.get('conversion'): business, filing_submission = conversion.process( business, filing_core_submission.json, filing_submission, filing_meta) elif filing.get('courtOrder'): court_order.process(filing_submission, filing, filing_meta) elif filing.get('registrarsNotation'): registrars_notation.process(filing_submission, filing, filing_meta) elif filing.get('registrarsOrder'): registrars_order.process(filing_submission, filing, filing_meta) elif filing.get('correction'): filing_submission = correction.process( filing_submission, filing, filing_meta) elif filing.get('transition'): filing_submission = transition.process( business, filing_submission, filing, filing_meta) filing_submission.transaction_id = transaction.id filing_submission.set_processed() filing_submission._meta_data = json.loads( # pylint: disable=W0212 json.dumps(filing_meta.asjson, default=json_serial)) db.session.add(business) db.session.add(filing_submission) db.session.commit() # post filing changes to other services if any('alteration' in x for x in legal_filings): alteration.post_process(business, filing_submission, correction) db.session.add(business) db.session.commit() AccountService.update_entity( business_registration=business.identifier, business_name=business.legal_name, corp_type_code=business.legal_type) if any('incorporationApplication' in x for x in legal_filings): if any('correction' in x for x in legal_filings): if name_request.has_new_nr_for_correction( filing_submission.filing_json): name_request.consume_nr(business, filing_submission) else: filing_submission.business_id = business.id db.session.add(filing_submission) db.session.commit() incorporation_filing.update_affiliation( business, filing_submission) name_request.consume_nr(business, filing_submission) incorporation_filing.post_process(business, filing_submission) try: await publish_email_message( qsm, APP_CONFIG.EMAIL_PUBLISH_OPTIONS['subject'], filing_submission, 'mras') except Exception as err: # pylint: disable=broad-except, unused-variable # noqa F841; # mark any failure for human review capture_message( f'Queue Error: Failed to place email for filing:{filing_submission.id}' f'on Queue with error:{err}', level='error') if any('conversion' in x for x in legal_filings): filing_submission.business_id = business.id db.session.add(filing_submission) db.session.commit() conversion.post_process(business, filing_submission) try: await publish_email_message( qsm, APP_CONFIG.EMAIL_PUBLISH_OPTIONS['subject'], filing_submission, filing_submission.status) except Exception as err: # pylint: disable=broad-except, unused-variable # noqa F841; # mark any failure for human review capture_message( f'Queue Error: Failed to place email for filing:{filing_submission.id}' f'on Queue with error:{err}', level='error') try: await publish_event(business, filing_submission) except Exception as err: # pylint: disable=broad-except, unused-variable # noqa F841; # mark any failure for human review print(err) capture_message( f'Queue Error: Failed to publish event for filing:{filing_submission.id}' f'on Queue with error:{err}', level='error')
def process(business: Business, filing: Dict, filing_meta: FilingMeta): """Render the dissolution filing unto the model objects.""" if not (dissolution_filing := filing.get('dissolution')): logger.error('Could not find Dissolution in: %s', filing) raise QueueException(f'legal_filing:Dissolution missing from {filing}')
async def process_notification(notification_id: int, db_session): """Send the notification to smtp server.""" try: notification: Notification = await NotifyService.find_notification( db_session, notification_id) if not notification.status_code == NotificationStatusEnum.DELIVERED: sender: str = app_config.MAIL_FROM_ID recipients: [] = [ s.strip() for s in notification.recipients.split(',') ] encoding = 'utf-8' message = MIMEMultipart() message['Subject'] = notification.content.subject message['From'] = sender message['To'] = notification.recipients message.attach( MIMEText(notification.content.body, 'html', encoding)) if notification.content.attachments: for attachment in notification.content.attachments: part = MIMEBase('application', 'octet-stream') part.set_payload(attachment.file_bytes) encode_base64(part) spaces = re.compile(r'[\s]+', re.UNICODE) filename = unicodedata.normalize('NFKD', attachment.file_name) filename = filename.encode('ascii', 'ignore').decode('ascii') filename = spaces.sub(u' ', filename).strip() try: filename and filename.encode('ascii') except UnicodeEncodeError: filename = ('UTF8', '', filename) part.add_header('Content-Disposition', 'attachment; filename=' + filename) message.attach(part) sent_status = await send_with_send_message(message, recipients) if not sent_status: raise QueueException( 'Could not send email through SMTP server.') update_notification: NotificationUpdate = NotificationUpdate( id=notification_id, sent_date=datetime.utcnow(), notify_status=NotificationStatusEnum.DELIVERED) await NotifyService.update_notification_status( db_session, update_notification) except (QueueException, Exception) as err: # pylint: disable=broad-except logger.error('Notify Job (process_notification) Error: %s', err) update_notification: NotificationUpdate = NotificationUpdate( id=notification_id, sent_date=datetime.utcnow(), notify_status=NotificationStatusEnum.FAILURE) await NotifyService.update_notification_status(db_session, update_notification) return
async def process_event(event_message: dict, flask_app): """Process the incoming queue event message.""" if not flask_app: raise QueueException('Flask App not available.') with flask_app.app_context(): message_type = event_message.get('type', None) email_msg = event_message.get('data') email_msg[ 'logo_url'] = minio_service.MinioService.get_minio_public_url( 'bc_logo_for_email.png') email_dict = None token = RestService.get_service_account_token() logger.debug('message_type recieved %s', message_type) if message_type == 'account.mailer': email_dict = payment_completed.process(email_msg) elif message_type in ([ MessageType.REFUND_DIRECT_PAY_REQUEST.value, MessageType.REFUND_DRAWDOWN_REQUEST.value ]): email_dict = refund_requested.process(event_message) elif message_type == MessageType.PAD_ACCOUNT_CREATE.value: email_msg[ 'registry_logo_url'] = minio_service.MinioService.get_minio_public_url( 'bc_registry_logo_pdf.svg') email_dict = pad_confirmation.process(email_msg, token) elif message_type == MessageType.NSF_LOCK_ACCOUNT.value: logger.debug('lock account message recieved:') template_name = TemplateType.NSF_LOCK_ACCOUNT_TEMPLATE_NAME.value org_id = email_msg.get('accountId') admin_coordinator_emails = get_member_emails( org_id, (ADMIN, COORDINATOR)) subject = SubjectType.NSF_LOCK_ACCOUNT_SUBJECT.value logo_url = email_msg.get('logo_url') email_dict = common_mailer.process(org_id, admin_coordinator_emails, template_name, subject, logo_url=logo_url) elif message_type == MessageType.NSF_UNLOCK_ACCOUNT.value: logger.debug('unlock account message recieved') template_name = TemplateType.NSF_UNLOCK_ACCOUNT_TEMPLATE_NAME.value org_id = email_msg.get('accountId') admin_coordinator_emails = get_member_emails( org_id, (ADMIN, COORDINATOR)) subject = SubjectType.NSF_UNLOCK_ACCOUNT_SUBJECT.value logo_url = email_msg.get('logo_url') email_dict = common_mailer.process(org_id, admin_coordinator_emails, template_name, subject, logo_url=logo_url) elif message_type == MessageType.ACCOUNT_CONFIRMATION_PERIOD_OVER.value: template_name = TemplateType.ACCOUNT_CONF_OVER_TEMPLATE_NAME.value org_id = email_msg.get('accountId') nsf_fee = email_msg.get('nsfFee') admin_coordinator_emails = get_member_emails(org_id, (ADMIN, )) subject = SubjectType.ACCOUNT_CONF_OVER_SUBJECT.value logo_url = email_msg.get('logo_url') email_dict = common_mailer.process(org_id, admin_coordinator_emails, template_name, subject, nsf_fee=nsf_fee, logo_url=logo_url) elif message_type in (MessageType.TEAM_MODIFIED.value, MessageType.TEAM_MEMBER_INVITED.value): logger.debug('Team Modified message received') template_name = TemplateType.TEAM_MODIFIED_TEMPLATE_NAME.value org_id = email_msg.get('accountId') admin_coordinator_emails = get_member_emails(org_id, (ADMIN, )) subject = SubjectType.TEAM_MODIFIED_SUBJECT.value logo_url = email_msg.get('logo_url') email_dict = common_mailer.process(org_id, admin_coordinator_emails, template_name, subject, logo_url=logo_url) elif message_type == MessageType.ADMIN_REMOVED.value: logger.debug('ADMIN_REMOVED message received') template_name = TemplateType.ADMIN_REMOVED_TEMPLATE_NAME.value org_id = email_msg.get('accountId') recipient_email = email_msg.get('recipientEmail') subject = SubjectType.ADMIN_REMOVED_SUBJECT.value logo_url = email_msg.get('logo_url') email_dict = common_mailer.process(org_id, recipient_email, template_name, subject, logo_url=logo_url) elif message_type == MessageType.PAD_INVOICE_CREATED.value: template_name = TemplateType.PAD_INVOICE_CREATED_TEMPLATE_NAME.value org_id = email_msg.get('accountId') admin_coordinator_emails = get_member_emails(org_id, (ADMIN, )) subject = SubjectType.PAD_INVOICE_CREATED.value invoice_process_date = datetime.fromisoformat( email_msg.get('invoice_process_date')) args = { 'nsf_fee': email_msg.get('nsfFee'), 'invoice_total': email_msg.get('invoice_total'), 'invoice_process_date': get_local_formatted_date(invoice_process_date, '%m-%d-%Y') } logo_url = email_msg.get('logo_url') email_dict = common_mailer.process(org_id, admin_coordinator_emails, template_name, subject, logo_url=logo_url, **args) elif message_type in (MessageType.ONLINE_BANKING_OVER_PAYMENT.value, MessageType.ONLINE_BANKING_UNDER_PAYMENT.value, MessageType.ONLINE_BANKING_PAYMENT.value): if message_type == MessageType.ONLINE_BANKING_OVER_PAYMENT.value: template_name = TemplateType.ONLINE_BANKING_OVER_PAYMENT_TEMPLATE_NAME.value elif message_type == MessageType.ONLINE_BANKING_UNDER_PAYMENT.value: template_name = TemplateType.ONLINE_BANKING_UNDER_PAYMENT_TEMPLATE_NAME.value else: template_name = TemplateType.ONLINE_BANKING_PAYMENT_TEMPLATE_NAME.value org_id = email_msg.get('accountId') admin_emails = get_member_emails(org_id, (ADMIN, )) subject = SubjectType.ONLINE_BANKING_PAYMENT_SUBJECT.value args = { 'title': subject, 'paid_amount': email_msg.get('amount'), 'credit_amount': email_msg.get('creditAmount'), } logo_url = email_msg.get('logo_url') email_dict = common_mailer.process(org_id, admin_emails, template_name, subject, logo_url=logo_url, **args) elif message_type == MessageType.PAD_SETUP_FAILED.value: template_name = TemplateType.PAD_SETUP_FAILED_TEMPLATE_NAME.value org_id = email_msg.get('accountId') admin_coordinator_emails = get_member_emails(org_id, (ADMIN, )) subject = SubjectType.PAD_SETUP_FAILED.value args = { 'accountId': email_msg.get('accountId'), } logo_url = email_msg.get('logo_url') email_dict = common_mailer.process(org_id, admin_coordinator_emails, template_name, subject, logo_url=logo_url, **args) elif message_type == MessageType.PAYMENT_PENDING.value: template_name = TemplateType.PAYMENT_PENDING_TEMPLATE_NAME.value org_id = email_msg.get('accountId') admin_coordinator_emails = get_member_emails(org_id, (ADMIN, )) subject = SubjectType.PAYMENT_PENDING.value args = { 'accountId': email_msg.get('accountId'), 'cfsAccountId': email_msg.get('cfsAccountId'), 'transactionAmount': email_msg.get('transactionAmount'), } logo_url = email_msg.get('logo_url') email_dict = common_mailer.process(org_id, admin_coordinator_emails, template_name, subject, logo_url=logo_url, **args) elif message_type == MessageType.EJV_FAILED.value: email_dict = ejv_failures.process(email_msg) elif message_type == MessageType.RESET_PASSCODE.value: template_name = TemplateType.RESET_PASSCODE_TEMPLATE_NAME.value subject = SubjectType.RESET_PASSCODE.value email_msg.update({'header': Constants.RESET_PASSCODE_HEADER.value}) email_dict = common_mailer.process( org_id=None, recipients=email_msg.get('emailAddresses'), template_name=template_name, subject=subject, **email_msg) else: if any(x for x in MessageType if x.value == message_type): title = TitleType[MessageType(message_type).name].value subject = SubjectType[MessageType(message_type).name].value\ .format(user_first_name=email_msg.get('userFirstName'), user_last_name=email_msg.get('userLastName'), product_name=email_msg.get('productName'), account_name=email_msg.get('orgName') ) template_name = TemplateType[ f'{MessageType(message_type).name}_TEMPLATE_NAME'].value else: return kwargs = { 'title': title, 'user_first_name': email_msg.get('userFirstName'), 'user_last_name': email_msg.get('userLastName'), 'context_url': email_msg.get('contextUrl'), 'role': email_msg.get('role'), 'label': email_msg.get('label'), 'product_name': email_msg.get('productName'), 'remarks': email_msg.get('remarks'), 'applicationDate': email_msg.get('applicationDate') } org_id = email_msg.get('accountId') logo_url = email_msg.get('logo_url') email_dict = common_mailer.process( org_id=org_id, recipients=email_msg.get('emailAddresses'), template_name=template_name, logo_url=logo_url, subject=subject, **kwargs) if email_dict: logger.debug('Extracted email msg Recipient: %s ', email_dict.get('recipients', '')) process_email(email_dict, FLASK_APP, token) else: # TODO probably an unhandled event.handle better logger.error('No email content generated')