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 has_new_nr_for_alteration(business: Business, filing: dict): """Return whether a alteration filing has new NR.""" nr_number = get_str(filing, '/filing/alteration/nameRequest/nrNumber') legal_name = get_str(filing, '/filing/alteration/nameRequest/legalName') if nr_number and legal_name: # legal api validates legal name in filing json, confirm both are different return legal_name.lower() != business.legal_name.lower() return False
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 test_get_str(f, p): """Assert the get_date extracts the date from the JSON file.""" d = get_str(f, p) if not d: assert True else: assert isinstance(d, str)
def share_structure_validation(filing): """Validate share structure.""" share_structure_path: Final = '/filing/alteration/shareStructure' if get_str(filing, share_structure_path): err = validate_share_structure(filing, Filing.FilingTypes.ALTERATION.value) if err: return err return []
def court_order_validation(filing): """Validate court order.""" court_order_path: Final = '/filing/alteration/courtOrder' if get_str(filing, court_order_path): err = validate_court_order(court_order_path, filing['filing']['alteration']['courtOrder']) if err: return err return []
def type_change_validation(filing): """Validate type change.""" msg = [] legal_type_path: Final = '/filing/alteration/business/legalType' # you must alter to a bc benefit company if get_str(filing, legal_type_path) != Business.LegalTypes.BCOMP.value: msg.append({'error': babel('Your business type has not been updated to a BC Benefit Company.'), 'path': legal_type_path}) return msg return []
def _create_invoice(business: Business, filing: Filing, filing_types: list, user_jwt: JwtManager) \ -> Tuple[int, dict, int]: """Create the invoice for the filing submission. Returns: { int: the paymentToken (id), or None dict: a dict of errors, or None int: the HTTPStatus error code, or None } """ payment_svc_url = current_app.config.get('PAYMENT_SVC_URL') mailing_address = business.mailing_address.one_or_none() payload = { 'paymentInfo': {'methodOfPayment': 'CC'}, 'businessInfo': { 'businessIdentifier': f'{business.identifier}', 'corpType': f'{business.identifier[:-7]}', 'businessName': f'{business.legal_name}', 'contactInfo': {'city': mailing_address.city, 'postalCode': mailing_address.postal_code, 'province': mailing_address.region, 'addressLine1': mailing_address.street, 'country': mailing_address.country} }, 'filingInfo': { 'filingTypes': filing_types } } if user_jwt.validate_roles([STAFF_ROLE]): routing_slip_number = get_str(filing.filing_json, 'filing/header/routingSlipNumber') if routing_slip_number: payload['accountInfo'] = {'routingSlip': routing_slip_number} try: token = user_jwt.get_token_auth_header() headers = {'Authorization': 'Bearer ' + token} rv = requests.post(url=payment_svc_url, json=payload, headers=headers, timeout=20.0) except (exceptions.ConnectionError, exceptions.Timeout) as err: current_app.logger.error(f'Payment connection failure for {business.identifier}: filing:{filing.id}', err) return {'message': 'unable to create invoice for payment.'}, HTTPStatus.PAYMENT_REQUIRED if rv.status_code == HTTPStatus.OK or rv.status_code == HTTPStatus.CREATED: pid = rv.json().get('id') filing.payment_token = pid filing.save() return None, None return {'message': 'unable to create invoice for payment.'}, HTTPStatus.PAYMENT_REQUIRED
def company_name_validation(filing): """Validate share structure.""" msg = [] nr_path: Final = '/filing/alteration/nameRequest/nrNumber' if nr_number := get_str(filing, nr_path): # ensure NR is approved or conditionally approved nr_response = namex.query_nr_number(nr_number) validation_result = namex.validate_nr(nr_response) if not nr_response['requestTypeCd'] in ('CCR', 'CCP', 'BEC'): msg.append({ 'error': babel( 'Alteration only available for Change of Name Name requests.' ), 'path': nr_path }) if not validation_result['is_approved']: msg.append({ 'error': babel('Alteration of Name Request is not approved.'), 'path': nr_path }) # ensure NR request has the same legal name legal_name_path: Final = '/filing/alteration/nameRequest/legalName' legal_name = get_str(filing, legal_name_path) nr_name = namex.get_approved_name(nr_response) if nr_name != legal_name: msg.append({ 'error': babel( 'Alteration of Name Request has a different legal name.'), 'path': legal_name_path })
def validate(business: Business, filing_json: Dict) -> Error: # pylint: disable=too-many-branches """Validate the filing JSON.""" err = validate_against_schema(filing_json) if err: return err err = None # check if this is a correction - if yes, ignore all other filing types in the filing since they will be validated # differently in a future version of corrections if 'correction' in filing_json['filing'].keys(): err = correction_validate(business, filing_json) if err: return err # For now the correction validators will get called here, these might be the same rules # so these 2 sections could get collapsed for k in filing_json['filing'].keys(): # Check if the JSON key exists in the FILINGS reference Dictionary if Filing.FILINGS.get(k, None): if k == Filing.FILINGS['changeOfAddress'].get('name'): err = coa_validate(business, filing_json) elif k == Filing.FILINGS['incorporationApplication'].get( 'name'): err = validate_correction_ia(filing_json) if err: return err elif 'dissolution' in filing_json['filing'].keys() \ and (dissolution_type := filing_json['filing']['dissolution'].get('dissolutionType', None)) \ and dissolution_type == 'voluntary': err = dissolution_validate(business, filing_json) if err: return err legal_type = get_str(filing_json, '/filing/business/legalType') if legal_type == Business.LegalTypes.COOP.value: if 'specialResolution' in filing_json['filing'].keys(): err = special_resolution_validate(business, filing_json) else: err = Error( HTTPStatus.BAD_REQUEST, [{ 'error': babel('Special Resolution is required.'), 'path': '/filing/specialResolution' }]) if err: return err
# ensure NR request has the same legal name legal_name_path: Final = '/filing/alteration/nameRequest/legalName' legal_name = get_str(filing, legal_name_path) nr_name = namex.get_approved_name(nr_response) if nr_name != legal_name: msg.append({ 'error': babel( 'Alteration of Name Request has a different legal name.'), 'path': legal_name_path }) else: # ensure legalType is valid legal_type_path: Final = '/filing/business/legalType' if get_str(filing, legal_type_path) not in ('ULC', 'BC', 'BEN'): msg.append({ 'error': babel('Alteration not valid for selected Legal Type.'), 'path': legal_type_path }) # ensure company is named if being altered to numbered legal_name_path: Final = '/filing/business/legalName' if not get_str(filing, legal_name_path): msg.append({ 'error': babel( 'Alteration to Numbered Company can only be done for a Named Company.' ),
def _create_invoice(business: Business, # pylint: disable=too-many-locals filing: Filing, filing_types: list, user_jwt: JwtManager, payment_account_id: str = None) \ -> Tuple[int, dict, int]: """Create the invoice for the filing submission. Returns: { int: the paymentToken (id), or None dict: a dict of errors, or None int: the HTTPStatus error code, or None } """ payment_svc_url = current_app.config.get('PAYMENT_SVC_URL') if filing.filing_type == Filing.FILINGS[ 'incorporationApplication'].get('name'): mailing_address = Address.create_address( filing.json['filing']['incorporationApplication']['offices'] ['registeredOffice']['mailingAddress']) corp_type = filing.json['filing']['business'].get( 'legalType', Business.LegalTypes.BCOMP.value) try: business.legal_name = filing.json['filing'][ 'incorporationApplication']['nameRequest']['legalName'] except KeyError: business.legal_name = business.identifier else: mailing_address = business.mailing_address.one_or_none() corp_type = business.legal_type if business.legal_type else \ filing.json['filing']['business'].get('legalType') payload = { 'businessInfo': { 'businessIdentifier': f'{business.identifier}', 'corpType': f'{corp_type}', 'businessName': f'{business.legal_name}', 'contactInfo': { 'city': mailing_address.city, 'postalCode': mailing_address.postal_code, 'province': mailing_address.region, 'addressLine1': mailing_address.street, 'country': mailing_address.country } }, 'filingInfo': { 'filingTypes': filing_types } } folio_number = filing.json['filing']['header'].get('folioNumber', None) if folio_number: payload['filingInfo']['folioNumber'] = folio_number if user_jwt.validate_roles([STAFF_ROLE]) or \ user_jwt.validate_roles([SYSTEM_ROLE]): account_info = {} routing_slip_number = get_str(filing.filing_json, 'filing/header/routingSlipNumber') if routing_slip_number: account_info['routingSlip'] = routing_slip_number bcol_account_number = get_str(filing.filing_json, 'filing/header/bcolAccountNumber') if bcol_account_number: account_info['bcolAccountNumber'] = bcol_account_number dat_number = get_str(filing.filing_json, 'filing/header/datNumber') if dat_number: account_info['datNumber'] = dat_number if account_info: payload['accountInfo'] = account_info try: token = user_jwt.get_token_auth_header() headers = { 'Authorization': 'Bearer ' + token, 'Content-Type': 'application/json' } rv = requests.post(url=payment_svc_url, json=payload, headers=headers, timeout=20.0) except (exceptions.ConnectionError, exceptions.Timeout) as err: current_app.logger.error( f'Payment connection failure for {business.identifier}: filing:{filing.id}', err) return { 'message': 'unable to create invoice for payment.' }, HTTPStatus.PAYMENT_REQUIRED if rv.status_code in (HTTPStatus.OK, HTTPStatus.CREATED): pid = rv.json().get('id') filing.payment_token = pid filing.payment_status_code = rv.json().get('statusCode', '') filing.payment_account = payment_account_id filing.save() return { 'isPaymentActionRequired': rv.json().get('isPaymentActionRequired', False) }, HTTPStatus.CREATED if rv.status_code == HTTPStatus.BAD_REQUEST: # Set payment error type used to retrieve error messages from pay-api error_type = rv.json().get('type') filing.payment_status_code = error_type filing.save() return { 'payment_error_type': error_type, 'message': rv.json().get('detail') }, HTTPStatus.PAYMENT_REQUIRED return { 'message': 'unable to create invoice for payment.' }, HTTPStatus.PAYMENT_REQUIRED
msg.append({'error': babel('Alteration only available for Change of Name Name requests.'), 'path': nr_path}) if not validation_result['is_consumable']: msg.append({'error': babel('Alteration of Name Request is not approved.'), 'path': nr_path}) # ensure NR request has the same legal name legal_name_path: Final = '/filing/alteration/nameRequest/legalName' legal_name = get_str(filing, legal_name_path) nr_name = namex.get_approved_name(nr_response) if nr_name != legal_name: msg.append({'error': babel('Alteration of Name Request has a different legal name.'), 'path': legal_name_path}) else: # ensure legalType is valid legal_type_path: Final = '/filing/business/legalType' if get_str(filing, legal_type_path) not in \ (Business.LegalTypes.BC_ULC_COMPANY.value, Business.LegalTypes.COMP.value, Business.LegalTypes.BCOMP.value): msg.append({'error': babel('Alteration not valid for selected Legal Type.'), 'path': legal_type_path}) # ensure company is named if being altered to numbered legal_name_path: Final = '/filing/business/legalName' if not get_str(filing, legal_name_path): msg.append({'error': babel('Alteration to Numbered Company can only be done for a Named Company.'), 'path': legal_name_path}) return msg def type_change_validation(filing):