def test_create_payment_record_with_internal_pay(session, public_user_mock): """Assert that the payment records are created.""" # Create invoice without routing slip. payment_response = PaymentService.create_invoice( get_routing_slip_payment_request(), get_auth_staff()) account_model = PaymentAccount.find_by_auth_account_id(get_auth_staff().get('account').get('id')) account_id = account_model.id assert account_id is not None assert payment_response.get('id') is not None rs_number = '123456789' rs = factory_routing_slip(number=rs_number, payment_account_id=account_id, remaining_amount=50.00) rs.save() # Create another invoice with a routing slip. PaymentService.create_invoice(get_routing_slip_payment_request(), get_auth_staff()) account_model = PaymentAccount.find_by_auth_account_id(get_auth_staff().get('account').get('id')) assert account_id == account_model.id rs = RoutingSlipModel.find_by_number(rs_number) assert rs.remaining_amount == 0.0 """12033 - Scenario 1. Manual transaction reduces RS to 0.00 Routing slip status becomes Completed """ assert rs.status == RoutingSlipStatus.COMPLETE.name
def test_internal_rs_back_active(session, public_user_mock): """12033 - Scenario 2. Routing slip is complete and a transaction is cancelled the balance is restored - Should move back to Active """ payment_response = PaymentService.create_invoice( get_routing_slip_payment_request(), get_auth_staff()) account_model = PaymentAccount.find_by_auth_account_id(get_auth_staff().get('account').get('id')) account_id = account_model.id assert account_id is not None assert payment_response.get('id') is not None rs_number = '123456789' rs = factory_routing_slip(number=rs_number, payment_account_id=account_id, remaining_amount=50.00) rs.save() # Create another invoice with a routing slip. invoice = PaymentService.create_invoice(get_routing_slip_payment_request(), get_auth_staff()) account_model = PaymentAccount.find_by_auth_account_id(get_auth_staff().get('account').get('id')) assert account_id == account_model.id rs = RoutingSlipModel.find_by_number(rs_number) assert rs.remaining_amount == 0.0 assert rs.status == RoutingSlipStatus.COMPLETE.name invoice = Invoice.find_by_id(invoice['id']) InternalPayService().process_cfs_refund(invoice) assert rs.status == RoutingSlipStatus.ACTIVE.name
def test_create_payment_record(session, public_user_mock): """Assert that the payment records are created.""" payment_response = PaymentService.create_invoice(get_payment_request(), get_auth_basic_user()) account_model = PaymentAccount.find_by_auth_account_id(get_auth_basic_user().get('account').get('id')) account_id = account_model.id assert account_id is not None assert payment_response.get('id') is not None # Create another payment with same request, the account should be the same PaymentService.create_invoice(get_payment_request(), get_auth_basic_user()) account_model = PaymentAccount.find_by_auth_account_id(get_auth_basic_user().get('account').get('id')) assert account_id == account_model.id
def test_create_payment_record_with_direct_pay(session, public_user_mock): """Assert that the payment records are created.""" current_app.config['DIRECT_PAY_ENABLED'] = True payment_response = PaymentService.create_invoice( get_payment_request(), get_auth_basic_user(PaymentMethod.DIRECT_PAY.value)) account_model = PaymentAccount.find_by_auth_account_id(get_auth_basic_user().get('account').get('id')) account_id = account_model.id assert account_id is not None assert payment_response.get('id') is not None # Create another payment with same request, the account should be the same PaymentService.create_invoice(get_payment_request(), get_auth_basic_user()) account_model = PaymentAccount.find_by_auth_account_id(get_auth_basic_user().get('account').get('id')) assert account_id == account_model.id
def create_payment_receipt(auth_account_id: str, credit_request: Dict[str, str], **kwargs) -> Payment: """Create a payment record for the account.""" pay_account: PaymentAccountModel = PaymentAccountModel.find_by_auth_account_id( auth_account_id) cfs_account: CfsAccountModel = CfsAccountModel.find_effective_by_account_id( pay_account.id) # Create a payment record # Create a receipt in CFS for the amount. payment = Payment.create( payment_method=credit_request.get('paymentMethod'), payment_system=PaymentSystem.PAYBC.value, payment_account_id=pay_account.id) receipt_number: str = generate_receipt_number(payment.id) receipt_date = credit_request.get('paymentDate') amount = credit_request.get('paidAmount') receipt_response = CFSService.create_cfs_receipt( cfs_account=cfs_account, rcpt_number=receipt_number, rcpt_date=receipt_date, amount=amount, payment_method=credit_request.get('paymentMethod')) payment.receipt_number = receipt_response.get('receipt_number', receipt_number) payment.paid_amount = amount payment.created_by = kwargs['user'].user_name payment.payment_date = parser.parse(receipt_date) payment.payment_status_code = PaymentStatus.COMPLETED.value payment.save() return payment
def delete_account(cls, auth_account_id: str) -> PaymentAccount: """Delete the payment account.""" current_app.logger.debug('<delete_account') pay_account: PaymentAccountModel = PaymentAccountModel.find_by_auth_account_id( auth_account_id) cfs_account: CfsAccountModel = CfsAccountModel.find_effective_by_account_id( pay_account.id) # 1 - Check if account have any credits # 2 - Check if account have any PAD transactions done in last N (10) days. if pay_account.credit and pay_account.credit > 0: raise BusinessException(Error.OUTSTANDING_CREDIT) # Check if account is frozen. cfs_status: str = cfs_account.status if cfs_account else None if cfs_status == CfsAccountStatus.FREEZE.value: raise BusinessException(Error.FROZEN_ACCOUNT) if InvoiceModel.find_outstanding_invoices_for_account( pay_account.id, get_outstanding_txns_from_date()): # Check if there is any recent PAD transactions in N days. raise BusinessException(Error.TRANSACTIONS_IN_PROGRESS) # If CFS Account present, mark it as INACTIVE. if cfs_status and cfs_status != CfsAccountStatus.INACTIVE.value: cfs_account.status = CfsAccountStatus.INACTIVE.value # If account is active or pending pad activation stop PAD payments. if pay_account.payment_method == PaymentMethod.PAD.value \ and cfs_status in [CfsAccountStatus.ACTIVE.value, CfsAccountStatus.PENDING_PAD_ACTIVATION.value]: CFSService.suspend_cfs_account(cfs_account) cfs_account.save() if pay_account.statement_notification_enabled: pay_account.statement_notification_enabled = False pay_account.save()
def test_create_ejv_payment_request(session, client, jwt, app): """Assert payment request works for EJV accounts.""" token = jwt.create_jwt(get_claims(role=Role.SYSTEM.value), token_header) headers = { 'Authorization': f'Bearer {token}', 'content-type': 'application/json' } # Create account first rv = client.post('/api/v1/accounts', data=json.dumps(get_gov_account_payload(account_id=1234)), headers=headers) auth_account_id = rv.json.get('authAccountId') payment_account: PaymentAccountModel = PaymentAccountModel.find_by_auth_account_id( auth_account_id) dist_code: DistributionCodeModel = DistributionCodeModel.find_by_active_for_account( payment_account.id) assert dist_code assert dist_code.account_id == payment_account.id token = jwt.create_jwt(get_claims(), token_header) headers = { 'Authorization': f'Bearer {token}', 'content-type': 'application/json', 'Account-Id': auth_account_id } rv = client.post('/api/v1/payment-requests', data=json.dumps(get_payment_request()), headers=headers) assert rv.json.get('paymentMethod') == PaymentMethod.EJV.value assert rv.json.get('statusCode') == InvoiceStatus.APPROVED.value
def activate_pad_account(auth_account_id: str): """Activate the pad account.""" payment_account: PaymentAccount = PaymentAccount.find_by_auth_account_id(auth_account_id) payment_account.pad_activation_date = datetime.now() payment_account.save() cfs_account: CfsAccount = CfsAccount.find_effective_by_account_id(payment_account.id) cfs_account.status = 'ACTIVE' cfs_account.save()
def test_create_payment_record_with_service_charge(session, public_user_mock): """Assert that the payment records are created.""" # Create a payment request for corp type BC payment_response = PaymentService.create_invoice(get_payment_request_with_service_fees(), get_auth_basic_user()) account_model = PaymentAccount.find_by_auth_account_id(get_auth_basic_user().get('account').get('id')) account_id = account_model.id assert account_id is not None assert payment_response.get('id') is not None assert payment_response.get('service_fees') == 1.50
def get_account_fees(cls, auth_account_id: str): """Save multiple fee settings against the account.""" payment_account: PaymentAccountModel = PaymentAccountModel.find_by_auth_account_id( auth_account_id) return { 'accountFees': AccountFeeSchema().dump(AccountFeeModel.find_by_account_id( payment_account.id), many=True) }
def save_account_fee(cls, auth_account_id: str, product: str, account_fee_request: dict): """Save fee overrides against the account.""" payment_account: PaymentAccountModel = PaymentAccountModel.find_by_auth_account_id( auth_account_id) cls._create_or_update_account_fee(account_fee_request, payment_account, product) return AccountFeeSchema().dump( AccountFeeModel.find_by_account_id_and_product( payment_account.id, product))
def find_by_auth_account_id(cls, auth_account_id: str) -> PaymentAccount: """Find payment account by corp number, corp type and payment system code.""" current_app.logger.debug('<find_by_auth_account_id') payment_account: PaymentAccountModel = PaymentAccountModel.find_by_auth_account_id( auth_account_id) p = None if payment_account: p = PaymentAccount() p._dao = payment_account # pylint: disable=protected-access current_app.logger.debug('>find_payment_account') return p
def update(cls, auth_account_id: str, account_request: Dict[str, Any]) -> PaymentAccount: """Create or update payment account record.""" current_app.logger.debug('<update payment account') try: account = PaymentAccountModel.find_by_auth_account_id( auth_account_id) PaymentAccount._save_account(account_request, account) except ServiceUnavailableException as e: current_app.logger.error(e) raise current_app.logger.debug('>create payment account') return cls.find_by_id(account.id)
def test_create_pad_payment_receipt(session, client, jwt, app): """Assert payment request works for PAD accounts.""" token = jwt.create_jwt(get_claims(role=Role.SYSTEM.value), token_header) headers = { 'Authorization': f'Bearer {token}', 'content-type': 'application/json' } # Create account first rv = client.post('/api/v1/accounts', data=json.dumps( get_unlinked_pad_account_payload(account_id=1234)), headers=headers) auth_account_id = rv.json.get('accountId') # Update the payment account as ACTIVE payment_account: PaymentAccountModel = PaymentAccountModel.find_by_auth_account_id( auth_account_id) payment_account.pad_activation_date = datetime.now() payment_account.save() cfs_account: CfsAccountModel = CfsAccountModel.find_effective_by_account_id( payment_account.id) cfs_account.status = 'ACTIVE' cfs_account.save() token = jwt.create_jwt(get_claims(), token_header) headers = { 'Authorization': f'Bearer {token}', 'content-type': 'application/json', 'Account-Id': auth_account_id } rv = client.post('/api/v1/payment-requests', data=json.dumps( get_payment_request_with_no_contact_info( corp_type='BEN', filing_type_code='BCINC', payment_method=PaymentMethod.PAD.value)), headers=headers) assert rv.json.get('paymentMethod') == PaymentMethod.PAD.value inv_id = rv.json.get('id') filing_data = { 'corpName': 'CP0001234', 'filingDateTime': 'June 27, 2019', 'fileName': 'director-change' } rv = client.post(f'/api/v1/payment-requests/{inv_id}/receipts', data=json.dumps(filing_data), headers=headers) assert rv.status_code == 201
def save_account_fees(cls, auth_account_id: str, account_fee_request: dict): """Save multiple fee settings against the account.""" payment_account: PaymentAccountModel = PaymentAccountModel.find_by_auth_account_id( auth_account_id) for fee in account_fee_request.get('accountFees'): cls._create_or_update_account_fee(fee, payment_account, fee.get('product')) return { 'accountFees': AccountFeeSchema().dump(AccountFeeModel.find_by_account_id( payment_account.id), many=True) }
def update(cls, auth_account_id: str, account_request: Dict[str, Any]) -> PaymentAccount: """Create or update payment account record.""" current_app.logger.debug('<update payment account') try: account = PaymentAccountModel.find_by_auth_account_id( auth_account_id) # TODO Remove it later, this is to help migration from auth to pay. if not account: return PaymentAccount.create(account_request) PaymentAccount._save_account(account_request, account) except ServiceUnavailableException as e: current_app.logger.error(e) raise current_app.logger.debug('>create payment account') return cls.find_by_id(account.id)
def create(business_info: Dict[str, Any], account_details: Dict[str, str], payment_system: str, authorization: Dict[str, Any]): """Create Payment account record.""" current_app.logger.debug('<create') auth_account_id = get_str_by_path(authorization, 'account/id') payment_account: PaymentAccountModel = PaymentAccountModel.find_by_auth_account_id(auth_account_id) new_payment_account: bool = False is_premium_payment: bool = False if not payment_account: payment_account = PaymentAccountModel() payment_account.auth_account_id = auth_account_id payment_account = payment_account.save() new_payment_account = True dao = None if payment_system == PaymentSystem.BCOL.value: dao = BcolPaymentAccount() dao.account_id = payment_account.id dao.bcol_account_id = account_details.get('bcol_account_id', None) dao.bcol_user_id = account_details.get('bcol_user_id', None) is_premium_payment = True elif payment_system == PaymentSystem.INTERNAL.value: dao = InternalPaymentAccount() dao.corp_number = business_info.get('businessIdentifier', None) dao.corp_type_code = business_info.get('corpType', None) dao.account_id = payment_account.id elif payment_system == PaymentSystem.PAYBC.value: dao = CreditPaymentAccount() dao.corp_number = business_info.get('businessIdentifier', None) dao.corp_type_code = business_info.get('corpType', None) dao.paybc_account = account_details.get('account_number', None) dao.paybc_party = account_details.get('party_number', None) dao.paybc_site = account_details.get('site_number', None) dao.account_id = payment_account.id dao = dao.save() if new_payment_account and is_premium_payment: PaymentAccount._persist_default_statement_frequency(payment_account.id) p = PaymentAccount() p.populate(dao) # pylint: disable=protected-access current_app.logger.debug('>create') return p
def create(cls, account_request: Dict[str, Any] = None) -> PaymentAccount: """Create new payment account record.""" current_app.logger.debug('<create payment account') auth_account_id = account_request.get('accountId') # If an account already exists, throw error. if PaymentAccountModel.find_by_auth_account_id(str(auth_account_id)): raise BusinessException(Error.ACCOUNT_EXISTS) account = PaymentAccountModel() PaymentAccount._save_account(account_request, account) PaymentAccount._persist_default_statement_frequency(account.id) payment_account = PaymentAccount() payment_account._dao = account # pylint: disable=protected-access payment_account.publish_account_mailer_event() current_app.logger.debug('>create payment account') return payment_account
def test_payment_request_online_banking_with_credit(session, client, jwt, app): """Assert that the endpoint returns 201.""" token = jwt.create_jwt(get_claims(role=Role.SYSTEM.value), token_header) headers = { 'Authorization': f'Bearer {token}', 'content-type': 'application/json' } rv = client.post( '/api/v1/accounts', data=json.dumps( get_basic_account_payload( payment_method=PaymentMethod.ONLINE_BANKING.value)), headers=headers) auth_account_id = rv.json.get('authAccountId') # Update the payment account as ACTIVE payment_account: PaymentAccountModel = PaymentAccountModel.find_by_auth_account_id( auth_account_id) payment_account.credit = 51 payment_account.save() token = jwt.create_jwt(get_claims(), token_header) headers = { 'Authorization': f'Bearer {token}', 'content-type': 'application/json' } rv = client.post('/api/v1/payment-requests', data=json.dumps( get_payment_request_with_payment_method( business_identifier='CP0002000', payment_method='ONLINE_BANKING')), headers=headers) invoice_id = rv.json.get('id') rv = client.patch( f'/api/v1/payment-requests/{invoice_id}?applyCredit=true', data=json.dumps({}), headers=headers) payment_account: PaymentAccountModel = PaymentAccountModel.find_by_auth_account_id( auth_account_id) assert payment_account.credit == 1 # Now set the credit less than the total of invoice. payment_account.credit = 49 headers = { 'Authorization': f'Bearer {token}', 'content-type': 'application/json' } rv = client.post('/api/v1/payment-requests', data=json.dumps( get_payment_request_with_payment_method( business_identifier='CP0002000', payment_method='ONLINE_BANKING')), headers=headers) invoice_id = rv.json.get('id') rv = client.patch( f'/api/v1/payment-requests/{invoice_id}?applyCredit=true', data=json.dumps({}), headers=headers) # Credit won't be applied as the invoice total is 50 and the credit should remain as 0. payment_account: PaymentAccountModel = PaymentAccountModel.find_by_auth_account_id( auth_account_id) assert payment_account.credit == 0
def _consolidate_payments(cls, auth_account_id: str, failed_payments: List[PaymentModel]) -> Payment: # If the payment is for consolidating failed payments, # 1. Cancel the invoices in CFS # 2. Update status of invoice_reference to CANCELLED # 3. Create new consolidated invoice in CFS. # 4. Create new invoice reference records. # 5. Create new payment records for the invoice as CREATED. pay_account: PaymentAccountModel = PaymentAccountModel.find_by_auth_account_id( auth_account_id) cfs_account: CfsAccountModel = CfsAccountModel.find_effective_by_account_id( pay_account.id) consolidated_invoices: List[InvoiceModel] = [] consolidated_line_items: List[PaymentLineItem] = [] invoice_total: float = 0 for failed_payment in failed_payments: # Reverse invoice balance CFSService.reverse_invoice( inv_number=failed_payment.invoice_number) # Find all invoices for this payment. # Add all line items to the array for invoice in InvoiceModel.find_invoices_for_payment( payment_id=failed_payment.id): consolidated_invoices.append(invoice) invoice_total += invoice.total consolidated_line_items.append(*invoice.payment_line_items) # Create consolidated invoice invoice_response = CFSService.create_account_invoice( transaction_number=str(consolidated_invoices[-1].id) + '-C', line_items=consolidated_line_items, cfs_account=cfs_account) invoice_number: str = invoice_response.json().get('invoice_number') # Mark all invoice references to status CANCELLED, and create a new one for the new invoice number. for invoice in consolidated_invoices: inv_ref: InvoiceReferenceModel = InvoiceReferenceModel.find_reference_by_invoice_id_and_status( invoice_id=invoice.id, status_code=InvoiceReferenceStatus.ACTIVE.value) inv_ref.status_code = InvoiceReferenceStatus.CANCELLED.value InvoiceReferenceModel( invoice_id=invoice.id, status_code=InvoiceReferenceStatus.ACTIVE.value, invoice_number=invoice_number, reference_number=invoice_response.json().get( 'pbc_ref_number')).flush() payment = Payment.create(payment_method=PaymentMethod.CC.value, payment_system=PaymentSystem.PAYBC.value, invoice_number=invoice_number, invoice_amount=invoice_total, payment_account_id=pay_account.id) # Update all failed payment with consolidated invoice number. for failed_payment in failed_payments: failed_payment.cons_inv_number = invoice_number # If the payment status is CREATED, which means we consolidated one payment which was already consolidated. # Set the status as DELETED if failed_payment.payment_status_code == PaymentStatus.CREATED.value: failed_payment.payment_status_code = PaymentStatus.DELETED.value # commit transaction BaseModel.commit() return payment
def test_create_pad_refund(session, client, jwt, app, stan_server): """Assert that the endpoint returns 202 and creates a credit on the account.""" # 1. Create a PAD payment_account and cfs_account. # 2. Create a PAD invoice and mark as PAID. # 3. Issue a refund and assert credit is reflected on payment_account. # 4. Create an invoice again and assert that credit is updated. auth_account_id = 1234 token = jwt.create_jwt(get_claims(role=Role.SYSTEM.value), token_header) headers = { 'Authorization': f'Bearer {token}', 'content-type': 'application/json' } client.post( '/api/v1/accounts', data=json.dumps( get_unlinked_pad_account_payload(account_id=auth_account_id)), headers=headers) pay_account: PaymentAccountModel = PaymentAccountModel.find_by_auth_account_id( auth_account_id) cfs_account: CfsAccountModel = CfsAccountModel.find_by_account_id( pay_account.id)[0] cfs_account.cfs_party = '1111' cfs_account.cfs_account = '1111' cfs_account.cfs_site = '1111' cfs_account.status = CfsAccountStatus.ACTIVE.value cfs_account.save() pay_account.pad_activation_date = datetime.now() pay_account.save() token = jwt.create_jwt(get_claims(), token_header) headers = { 'Authorization': f'Bearer {token}', 'content-type': 'application/json', 'Account-Id': auth_account_id } rv = client.post('/api/v1/payment-requests', data=json.dumps( get_payment_request_with_payment_method( payment_method=PaymentMethod.PAD.value)), headers=headers) inv_id = rv.json.get('id') inv_total = rv.json.get('total') inv: InvoiceModel = InvoiceModel.find_by_id(inv_id) inv.invoice_status_code = InvoiceStatus.PAID.value inv.save() token = jwt.create_jwt(get_claims(app_request=app, role=Role.SYSTEM.value), token_header) headers = { 'Authorization': f'Bearer {token}', 'content-type': 'application/json' } rv = client.post(f'/api/v1/payment-requests/{inv_id}/refunds', data=json.dumps({'reason': 'Test'}), headers=headers) assert rv.status_code == 202 assert rv.json.get('message') == REFUND_SUCCESS_MESSAGES['PAD.PAID'] # Assert credit is updated. pay_account: PaymentAccountModel = PaymentAccountModel.find_by_auth_account_id( auth_account_id) credit = pay_account.credit assert pay_account.credit == inv_total # Create an invoice again and assert that credit is updated. token = jwt.create_jwt(get_claims(), token_header) headers = { 'Authorization': f'Bearer {token}', 'content-type': 'application/json', 'Account-Id': auth_account_id } rv = client.post('/api/v1/payment-requests', data=json.dumps( get_payment_request_with_service_fees( corp_type='CP', filing_type='OTADD')), headers=headers) inv_total = rv.json.get('total') pay_account: PaymentAccountModel = PaymentAccountModel.find_by_auth_account_id( auth_account_id) credit -= inv_total assert pay_account.credit == credit # Create an invoice again and assert that credit is updated. token = jwt.create_jwt(get_claims(), token_header) headers = { 'Authorization': f'Bearer {token}', 'content-type': 'application/json', 'Account-Id': auth_account_id } rv = client.post('/api/v1/payment-requests', data=json.dumps( get_payment_request_with_payment_method( payment_method=PaymentMethod.PAD.value)), headers=headers) inv_total = rv.json.get('total') # Credit must be zero now as the new invoice amount exceeds remaining credit. assert pay_account.credit == 0