def consume_nr( business: Business, filing: Filing, nr_num_path='/filing/incorporationApplication/nameRequest/nrNumber'): """Update the nr to a consumed state.""" try: nr_num = get_str(filing.filing_json, nr_num_path) # skip this if none (nrNumber will not be available for numbered company) if nr_num: bootstrap = RegistrationBootstrap.find_by_identifier( filing.temp_reg) namex_svc_url = current_app.config.get('NAMEX_API') token = AccountService.get_bearer_token() # Create an entity record data = json.dumps({'consume': {'corpNum': business.identifier}}) rv = requests.patch( url=''.join([namex_svc_url, nr_num]), headers={ **AccountService.CONTENT_TYPE_JSON, 'Authorization': AccountService.BEARER + token }, data=data, timeout=AccountService.timeout) if not rv.status_code == HTTPStatus.OK: raise QueueException # remove the NR from the account AccountService.delete_affiliation(bootstrap.account, nr_num) except KeyError: pass # return except Exception: # pylint: disable=broad-except; note out any exception, but don't fail the call sentry_sdk.capture_message( f'Queue Error: Consume NR error for filing:{filing.id}', level='error')
def account(app): """Create an account to be used for testing.""" with app.app_context(): account_url = current_app.config.get('ACCOUNT_SVC_AFFILIATE_URL') account_url = account_url[:account_url.rfind('{') - 1] org_data = json.dumps({'name': str(uuid.uuid4())}) token = AccountService.get_bearer_token() # with app.app_context(): rv = requests.post( url=account_url, data=org_data, headers={ **AccountService.CONTENT_TYPE_JSON, 'Authorization': AccountService.BEARER + token }, timeout=20) account_id = rv.json()['id'] yield account_id rv = requests.delete( url=f'{account_url}/{account_id}', headers={'Authorization': AccountService.BEARER + token}, timeout=20) print(rv)
async def send_outstanding_bcomps_ar_reminder(app: Flask, qsm: QueueService): # pylint: disable=redefined-outer-name """Find outstanding bcomps to send annual report reminder.""" try: # get token token = AccountService.get_bearer_token() ar_fee = get_ar_fee(app, Business.LegalTypes.BCOMP.value, token) app.logger.debug('Getting outstanding bcomps to send AR reminder') where_clause = text( 'CASE WHEN last_ar_date IS NULL THEN date(founding_date) ELSE date(last_ar_date) END' + " <= CURRENT_DATE - interval '1 year'") businesses = db.session.query(Business).filter( Business.legal_type == Business.LegalTypes.BCOMP.value, where_clause).all() app.logger.debug('Processing outstanding bcomps to send AR reminder') for business in businesses: ar_year = (business.last_ar_year if business.last_ar_year else business.founding_date.year) + 1 await send_email(business.id, ar_fee, str(ar_year), app, qsm) app.logger.debug( f'Successfully queued ar reminder for business id {business.id} for year {ar_year}.' ) except Exception as err: # pylint: disable=broad-except, unused-variable # noqa F841; app.logger.error(err)
async def find_and_send_ar_reminder(app: Flask, qsm: QueueService): # pylint: disable=redefined-outer-name """Find business to send annual report reminder.""" try: legal_types = [Business.LegalTypes.BCOMP.value ] # entity types to send ar reminder ar_fees = {} # get token token = AccountService.get_bearer_token() for legal_type in legal_types: ar_fees[legal_type] = get_ar_fee(app, legal_type, token) app.logger.debug('Getting businesses to send AR reminder today') businesses = get_businesses(legal_types) app.logger.debug('Processing businesses to send AR reminder') for business in businesses: ar_year = (business.last_ar_year if business.last_ar_year else business.founding_date.year) + 1 await send_email(business.id, ar_fees[business.legal_type], str(ar_year), app, qsm) app.logger.debug( f'Successfully queued ar reminder for business id {business.id}.' ) except Exception as err: # pylint: disable=broad-except, unused-variable # noqa F841; app.logger.error(err)
def consume_nr( business: Business, filing: Filing, nr_num_path='/filing/incorporationApplication/nameRequest/nrNumber'): """Update the nr to a consumed state.""" try: # skip this if none (nrNumber will not be available for numbered company) if nr_num := get_str(filing.filing_json, nr_num_path): namex_svc_url = current_app.config.get('NAMEX_API') token = AccountService.get_bearer_token() # Create an entity record data = json.dumps({'consume': {'corpNum': business.identifier}}) rv = requests.patch( url=''.join([namex_svc_url, nr_num]), headers={ **AccountService.CONTENT_TYPE_JSON, 'Authorization': AccountService.BEARER + token }, data=data, timeout=AccountService.timeout) if not rv.status_code == HTTPStatus.OK: raise QueueException # remove the NR from the account if filing.temp_reg and (bootstrap := RegistrationBootstrap.find_by_identifier( filing.temp_reg)): AccountService.delete_affiliation(bootstrap.account, nr_num)
def update_business_profile(business: Business, profile_info: Dict) -> Dict: """Set the legal type of the business.""" if not business or not profile_info: return {'error': babel('Business and profile_info required.')} # contact phone is optional phone = profile_info.get('phone', '') error = {'error': 'Unknown handling'} if email := profile_info.get('email'): # assume the JSONSchema ensures it is a valid email format token = AccountService.get_bearer_token() account_svc_entity_url = current_app.config['ACCOUNT_SVC_ENTITY_URL'] # Create an entity record data = json.dumps({ 'email': email, 'phone': phone, 'phoneExtension': '' }) url = ''.join( [account_svc_entity_url, '/', business.identifier, '/contacts']) rv = requests.post( url=url, headers={ **AccountService.CONTENT_TYPE_JSON, 'Authorization': AccountService.BEARER + token }, data=data, timeout=AccountService.timeout) if rv.status_code in (HTTPStatus.OK, HTTPStatus.CREATED): error = None if rv.status_code == HTTPStatus.NOT_FOUND: error = {'error': 'No business profile found.'} if rv.status_code == HTTPStatus.METHOD_NOT_ALLOWED: error = { 'error': 'Service account missing privileges to update business profiles' } if rv.status_code == HTTPStatus.BAD_REQUEST and \ 'DATA_ALREADY_EXISTS' in rv.text: put = requests.put( url=''.join([account_svc_entity_url, '/', business.identifier]), headers={ **AccountService.CONTENT_TYPE_JSON, 'Authorization': AccountService.BEARER + token }, data=data, timeout=AccountService.timeout) if put.status_code in (HTTPStatus.OK, HTTPStatus.CREATED): error = None else: error = { 'error': 'Unable to update existing business profile.' }
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 update_business_nos(application): # pylint: disable=redefined-outer-name """Update the tax_ids for corps with new bn_15s.""" try: # get updater-job token token = AccountService.get_bearer_token() # get identifiers with outstanding tax_ids application.logger.debug('Getting businesses with outstanding tax ids from legal api...') response = requests.get( application.config['LEGAL_URL'] + '/internal/tax_ids', headers={'Content-Type': 'application/json', 'Authorization': f'Bearer {token}'} ) if response.status_code != 200: application.logger.error('legal-updater failed to get identifiers from legal-api.') raise Exception identifiers = response.json() if identifiers['identifiers']: # get tax ids that exist for above entities application.logger.debug(f'Getting tax ids for {identifiers["identifiers"]} from colin api...') response = requests.get( application.config['COLIN_URL'] + '/internal/tax_ids', json=identifiers, headers={'Content-Type': 'application/json', 'Authorization': f'Bearer {token}'} ) if response.status_code != 200: application.logger.error('legal-updater failed to get tax_ids from colin-api.') raise Exception tax_ids = response.json() if tax_ids.keys(): # update lear with new tax ids from colin application.logger.debug(f'Updating tax ids for {tax_ids.keys()} in lear...') response = requests.post( application.config['LEGAL_URL'] + '/internal/tax_ids', json=tax_ids, headers={'Content-Type': 'application/json', 'Authorization': f'Bearer {token}'} ) if response.status_code != 201: application.logger.error('legal-updater failed to update tax_ids in lear.') raise Exception await send_emails(tax_ids, application) application.logger.debug('Successfully updated tax ids in lear.') else: application.logger.debug('No tax ids in colin to update in lear.') else: application.logger.debug('No businesses in lear with outstanding tax ids.') except Exception as err: application.logger.error(err)
def run(): """Get filings that haven't been synced with colin and send them to the colin-api.""" application = create_app() corps_with_failed_filing = [] with application.app_context(): try: # get updater-job token token = AccountService.get_bearer_token() filings = get_filings(app=application) if not filings: # pylint: disable=no-member; false positive application.logger.debug( 'No completed filings to send to colin.') for filing in filings: filing_id = filing['filingId'] identifier = filing['filing']['business']['identifier'] if identifier in corps_with_failed_filing or is_test_coop( identifier): # pylint: disable=no-member; false positive application.logger.debug( f'Skipping filing {filing_id} for' f' {filing["filing"]["business"]["identifier"]}.') else: colin_ids = send_filing(app=application, filing=filing, filing_id=filing_id) update = None if colin_ids: update = update_colin_id(app=application, filing_id=filing_id, colin_ids=colin_ids, token=token) if update: # pylint: disable=no-member; false positive application.logger.debug( f'Successfully updated filing {filing_id}') else: corps_with_failed_filing.append( filing['filing']['business']['identifier']) # pylint: disable=no-member; false positive application.logger.error( f'Failed to update filing {filing_id} with colin event id.' ) except Exception as err: # pylint: disable=no-member; false positive application.logger.error(err)
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)
def update_filings(application): # pylint: disable=redefined-outer-name, too-many-branches """Get filings in colin that are not in lear and send them to lear.""" successful_filings = 0 failed_filing_events = [] corps_with_failed_filing = [] skipped_filings = [] first_failed_id = None try: # pylint: disable=too-many-nested-blocks # get updater-job token token = AccountService.get_bearer_token() # check if there are filings to send to legal manual_filings_info = check_for_manual_filings(application, token) max_event_id = 0 if len(manual_filings_info) > 0: for event_info in manual_filings_info: # Make sure this coop has no outstanding filings that failed to be applied. # This ensures we don't apply filings out of order when one fails. if event_info['corp_num'] not in corps_with_failed_filing: filing = get_filing(event_info, application) # call legal api with filing application.logger.debug(f'sending filing with event info: {event_info} to legal api.') response = requests.post( f'{application.config["LEGAL_URL"]}/{event_info["corp_num"]}/filings', json=filing, headers={'Content-Type': 'application/json', 'Authorization': f'Bearer {token}'} ) if response.status_code != 201: if not first_failed_id: first_failed_id = event_info['event_id'] failed_filing_events.append(event_info) corps_with_failed_filing.append(event_info['corp_num']) application.logger.error(f'Legal failed to create filing for {event_info["corp_num"]}') else: # update max_event_id entered successful_filings += 1 if int(event_info['event_id']) > max_event_id: max_event_id = int(event_info['event_id']) else: skipped_filings.append(event_info) else: application.logger.debug('0 filings updated in legal db.') application.logger.debug(f'successful filings: {successful_filings}') application.logger.debug(f'skipped filings due to related erred filings: {len(skipped_filings)}') application.logger.debug(f'failed filings: {len(failed_filing_events)}') application.logger.debug(f'failed filings event info: {failed_filing_events}') # if manually bringing across filings, set to first id so you don't skip any filings on the next run if SET_EVENTS_MANUALLY: first_failed_id = 102125621 # if one of the events failed then save that id minus one so that the next run will try it again # this way failed filings wont get buried/forgotten after multiple runs if first_failed_id: max_event_id = first_failed_id - 1 if max_event_id > 0: # update max_event_id in legal_db application.logger.debug('setting last_event_id in legal_db to {}'.format(max_event_id)) response = requests.post( f'{application.config["LEGAL_URL"]}/internal/filings/colin_id/{max_event_id}', headers={'Content-Type': 'application/json', 'Authorization': f'Bearer {token}'} ) if response.status_code != 201: application.logger.error( f'Error adding {max_event_id} colin_last_update table in legal db {response.status_code}' ) else: if dict(response.json())['maxId'] != max_event_id: application.logger.error('Updated colin id is not max colin id in legal db.') else: application.logger.debug('Successfully updated colin id in legal db.') else: application.logger.debug('colin_last_update not updated in legal db.') except Exception as err: application.logger.error(err)