def test_update_pad_account(session): """Test update account.""" # Create a pending account first, then call the job account = factory_create_pad_account(auth_account_id='2') CreateAccountTask.create_accounts() account = PaymentAccount.find_by_id(account.id) cfs_account = CfsAccount.find_effective_by_account_id(account.id) assert cfs_account.payment_instrument_number # Now update the account. new_payment_details = { 'bankInstitutionNumber': '111', 'bankTransitNumber': '222', 'bankAccountNumber': '3333333333' } PadService().update_account(name='Test', cfs_account=cfs_account, payment_info=new_payment_details) cfs_account = CfsAccount.find_by_id(cfs_account.id) # Run the job again CreateAccountTask.create_accounts() updated_cfs_account: CfsAccount = CfsAccount.find_effective_by_account_id(account.id) assert updated_cfs_account.id != cfs_account.id assert updated_cfs_account.bank_account_number == new_payment_details.get('bankAccountNumber') assert updated_cfs_account.bank_branch_number == new_payment_details.get('bankTransitNumber') assert updated_cfs_account.bank_number == new_payment_details.get('bankInstitutionNumber') assert cfs_account.status == CfsAccountStatus.INACTIVE.value assert updated_cfs_account.status == CfsAccountStatus.PENDING_PAD_ACTIVATION.value assert updated_cfs_account.payment_instrument_number
def _validate_account(inv: InvoiceModel, row: Dict[str, str]): """Validate any mismatch in account number.""" # This should never happen, just in case cfs_account: CfsAccountModel = CfsAccountModel.find_by_id( inv.cfs_account_id) if (account_number := _get_row_value( row, Column.CUSTOMER_ACC)) != cfs_account.cfs_account: logger.error('Customer Account received as %s, but expected %s.', account_number, cfs_account.cfs_account) capture_message( f'Customer Account received as {account_number}, but expected {cfs_account.cfs_account}.', level='error') raise Exception('Invalid Account Number')
def test_link_rs(session): """Test link routing slip.""" child_rs_number = '1234' parent_rs_number = '89799' factory_routing_slip_account(number=child_rs_number, status=CfsAccountStatus.ACTIVE.value) factory_routing_slip_account(number=parent_rs_number, status=CfsAccountStatus.ACTIVE.value) child_rs = RoutingSlipModel.find_by_number(child_rs_number) parent_rs = RoutingSlipModel.find_by_number(parent_rs_number) # Do Link child_rs.status = RoutingSlipStatus.LINKED.value child_rs.parent_number = parent_rs.number child_rs.save() payment_account: PaymentAccountModel = PaymentAccountModel.find_by_id( child_rs.payment_account_id) cfs_account: CfsAccountModel = CfsAccountModel.find_effective_by_account_id( payment_account.id) with patch('pay_api.services.CFSService.reverse_rs_receipt_in_cfs' ) as mock_cfs_reverse: with patch('pay_api.services.CFSService.create_cfs_receipt' ) as mock_create_cfs: RoutingSlipTask.link_routing_slips() mock_cfs_reverse.assert_called() mock_cfs_reverse.assert_called_with(cfs_account, child_rs.number) mock_create_cfs.assert_called() # child_rs = RoutingSlipModel.find_by_number(child_rs_number) # parent_rs = RoutingSlipModel.find_by_number(parent_rs_number) # PS This has changed, no longer updating child rs payment account with parent. # assert child_rs.payment_account_id == parent_rs.payment_account_id cfs_account: CfsAccountModel = CfsAccountModel.find_by_id(cfs_account.id) assert cfs_account.status == CfsAccountStatus.INACTIVE.value # make sure next invocation doesnt fetch any records with patch('pay_api.services.CFSService.reverse_rs_receipt_in_cfs' ) as mock_cfs_reverse: with patch('pay_api.services.CFSService.create_cfs_receipt' ) as mock_create_cfs: RoutingSlipTask.link_routing_slips() mock_cfs_reverse.assert_not_called() mock_create_cfs.assert_not_called()
def test_create_pad_account_system_error(session): """Test create account.""" # Create a pending account first, then call the job account = factory_create_pad_account(auth_account_id='1') cfs_account: CfsAccount = CfsAccount.find_effective_by_account_id( account.id) assert cfs_account.status == CfsAccountStatus.PENDING.value mock_response = requests.models.Response() mock_response.headers['CAS-Returned-Messages'] = '[CFS Down]' mock_response.status_code = 404 side_effect = HTTPError(response=mock_response) with patch.object(mailer, 'publish_mailer_events') as mock_mailer: with patch('pay_api.services.CFSService.create_cfs_account', side_effect=side_effect): CreateAccountTask.create_accounts() mock_mailer.assert_not_called() account = PaymentAccount.find_by_id(account.id) cfs_account: CfsAccount = CfsAccount.find_by_id(cfs_account.id) assert cfs_account.status == CfsAccountStatus.PENDING.value
def _create_pad_invoices(cls): # pylint: disable=too-many-locals """Create PAD invoices in to CFS system.""" # Find all accounts which have done a transaction with PAD transactions inv_subquery = db.session.query(InvoiceModel.payment_account_id) \ .filter(InvoiceModel.payment_method_code == PaymentMethod.PAD.value) \ .filter(InvoiceModel.invoice_status_code == PaymentStatus.CREATED.value).subquery() # Exclude the accounts which are in FREEZE state. pad_accounts: List[PaymentAccountModel] = db.session.query(PaymentAccountModel) \ .join(CfsAccountModel, CfsAccountModel.account_id == PaymentAccountModel.id) \ .filter(CfsAccountModel.status != CfsAccountStatus.FREEZE.value) \ .filter(PaymentAccountModel.id.in_(inv_subquery)).all() current_app.logger.info( f'Found {len(pad_accounts)} with PAD transactions.') for account in pad_accounts: # Find all PAD invoices for this account account_invoices = db.session.query(InvoiceModel) \ .filter(InvoiceModel.payment_account_id == account.id) \ .filter(InvoiceModel.payment_method_code == PaymentMethod.PAD.value) \ .filter(InvoiceModel.invoice_status_code == InvoiceStatus.CREATED.value) \ .order_by(InvoiceModel.created_on.desc()).all() # Get cfs account payment_account: PaymentAccountService = PaymentAccountService.find_by_id( account.id) current_app.logger.debug( f'Found {len(account_invoices)} invoices for account {payment_account.auth_account_id}' ) if len(account_invoices) == 0: continue cfs_account: CfsAccountModel = CfsAccountModel.find_effective_by_account_id( payment_account.id) if cfs_account is None: # Get the last invoice and look up cfs_account for it, as the account might have got upgraded. cfs_account = CfsAccountModel.find_by_id( account_invoices[0].cfs_account_id) # If the CFS Account status is not ACTIVE, raise error and continue if cfs_account.status not in (CfsAccountStatus.ACTIVE.value, CfsAccountStatus.INACTIVE.value): capture_message( f'CFS Account status is not ACTIVE. for account {payment_account.auth_account_id} ' f'is {payment_account.cfs_account_status}', level='error') current_app.logger.error( f'CFS status for account {payment_account.auth_account_id} ' f'is {payment_account.cfs_account_status}') continue # Add all lines together lines = [] invoice_total: float = 0 for invoice in account_invoices: lines.append(*invoice.payment_line_items) invoice_total += invoice.total try: # Get the first invoice id as the trx number for CFS invoice_response = CFSService.create_account_invoice( transaction_number=account_invoices[0].id, line_items=lines, payment_account=cfs_account) except Exception as e: # pylint: disable=broad-except capture_message( f'Error on creating PAD invoice: account id={payment_account.id}, ' f'auth account : {payment_account.auth_account_id}, ERROR : {str(e)}', level='error') current_app.logger.error(e) continue # emit account mailer event mailer.publish_mailer_events('pad.invoiceCreated', payment_account, {'invoice_total': invoice_total}) # Iterate invoice and create invoice reference records for invoice in account_invoices: # Create invoice reference, payment record and a payment transaction InvoiceReference.create( invoice_id=invoice.id, invoice_number=invoice_response.json().get( 'invoice_number'), reference_number=invoice_response.json().get( 'pbc_ref_number', None)) # Misc invoice.cfs_account_id = payment_account.cfs_account_id invoice.invoice_status_code = InvoiceStatus.SETTLEMENT_SCHEDULED.value invoice.save()
def create_invoice_pdf(identifier: int, **kwargs) -> Tuple: """Find invoice by id.""" invoice_dao: InvoiceModel = InvoiceModel.find_by_id(identifier) if not invoice_dao: raise BusinessException(Error.INVALID_INVOICE_ID) payment_account: PaymentAccountModel = PaymentAccountModel.find_by_id( invoice_dao.payment_account_id) cfs_account: CfsAccountModel = CfsAccountModel.find_by_id( invoice_dao.cfs_account_id) org_response = OAuthService.get( current_app.config.get('AUTH_API_ENDPOINT') + f'orgs/{payment_account.auth_account_id}', kwargs['user'].bearer_token, AuthHeaderType.BEARER, ContentType.JSON).json() org_contact_response = OAuthService.get( current_app.config.get('AUTH_API_ENDPOINT') + f'orgs/{payment_account.auth_account_id}/contacts', kwargs['user'].bearer_token, AuthHeaderType.BEARER, ContentType.JSON).json() org_contact = org_contact_response.get( 'contacts')[0] if org_contact_response.get('contacts', None) else {} invoice_number: str = invoice_dao.references[0].invoice_number if invoice_dao.references \ else generate_transaction_number(invoice_dao.id) filing_types: List[Dict[str, str]] = [] for line_item in invoice_dao.payment_line_items: business_identifier = invoice_dao.business_identifier \ if not invoice_dao.business_identifier.startswith('T') \ else '' filing_types.append({ 'folioNumber': invoice_dao.folio_number, 'description': line_item.description, 'businessIdentifier': business_identifier, 'createdOn': get_local_formatted_date(invoice_dao.created_on), 'filingTypeCode': line_item.fee_schedule.filing_type_code, 'fee': line_item.total, 'gst': line_item.gst, 'serviceFees': line_item.service_fees, 'total': line_item.total + line_item.service_fees }) template_vars: Dict[str, any] = { 'invoiceNumber': invoice_number, 'createdOn': get_local_formatted_date(invoice_dao.created_on), 'accountNumber': cfs_account.cfs_account if cfs_account else None, 'total': invoice_dao.total, 'gst': 0, 'serviceFees': invoice_dao.service_fees, 'fees': invoice_dao.total - invoice_dao.service_fees, 'filingTypes': filing_types, 'accountContact': { 'name': org_response.get('name'), 'city': org_contact.get('city', None), 'country': org_contact.get('country', None), 'postalCode': org_contact.get('postalCode', None), 'region': org_contact.get('region', None), 'street': org_contact.get('street', None), 'streetAdditional': org_contact.get('streetAdditional', None) } } invoice_pdf_dict = { 'templateName': 'invoice', 'reportName': invoice_number, 'templateVars': template_vars } current_app.logger.info('Invoice PDF Dict %s', invoice_pdf_dict) pdf_response = OAuthService.post( current_app.config.get('REPORT_API_BASE_URL'), kwargs['user'].bearer_token, AuthHeaderType.BEARER, ContentType.JSON, invoice_pdf_dict) current_app.logger.debug('<OAuthService responded to receipt.py') return pdf_response, invoice_pdf_dict.get('reportName')