def test_get_payment_system_url_service_fees(session, public_user_mock): """Assert that the url returned is correct.""" today = current_local_time().strftime(PAYBC_DATE_FORMAT) payment_account = factory_payment_account() payment = factory_payment() payment_account.save() payment.save() invoice = factory_invoice(payment_account) invoice.save() invoice_ref = factory_invoice_reference(invoice.id).save() fee_schedule = FeeSchedule.find_by_filing_type_and_corp_type('CP', 'OTANN') distribution_code = DistributionCodeModel.find_by_active_for_fee_schedule(fee_schedule.fee_schedule_id) distribution_code_svc = DistributionCode() distribution_code_payload = get_distribution_code_payload() # Set service fee distribution distribution_code_payload.update({'serviceFeeDistributionCodeId': distribution_code.distribution_code_id}) # update the existing gl code with new values distribution_code_svc.save_or_update(distribution_code_payload, distribution_code.distribution_code_id) service_fee = 100 line = factory_payment_line_item(invoice.id, fee_schedule_id=fee_schedule.fee_schedule_id, service_fees=service_fee) line.save() direct_pay_service = DirectPayService() payment_response_url = direct_pay_service.get_payment_system_url_for_invoice(invoice, invoice_ref, 'google.com') url_param_dict = dict(urllib.parse.parse_qsl(urllib.parse.urlsplit(payment_response_url).query)) assert url_param_dict['trnDate'] == today assert url_param_dict['glDate'] == today assert url_param_dict['description'] == 'Direct_Sale' assert url_param_dict['pbcRefNumber'] == current_app.config.get('PAYBC_DIRECT_PAY_REF_NUMBER') assert url_param_dict['trnNumber'] == generate_transaction_number(invoice.id) assert url_param_dict['trnAmount'] == str(invoice.total) assert url_param_dict['paymentMethod'] == 'CC' assert url_param_dict['redirectUri'] == 'google.com' revenue_str = f"1:{distribution_code_payload['client']}." \ f"{distribution_code_payload['responsibilityCentre']}." \ f"{distribution_code_payload['serviceLine']}." \ f"{distribution_code_payload['stob']}." \ f"{distribution_code_payload['projectCode']}." \ f'000000.0000:10.00' revenue_str_service_fee = f"2:{distribution_code_payload['client']}." \ f"{distribution_code_payload['responsibilityCentre']}." \ f"{distribution_code_payload['serviceLine']}." \ f"{distribution_code_payload['stob']}." \ f"{distribution_code_payload['projectCode']}." \ f'000000.0000:{format(service_fee, DECIMAL_PRECISION)}' assert url_param_dict['revenue'] == f'{revenue_str}|{revenue_str_service_fee}' urlstring = f"trnDate={today}&pbcRefNumber={current_app.config.get('PAYBC_DIRECT_PAY_REF_NUMBER')}&" \ f'glDate={today}&description=Direct_Sale&' \ f'trnNumber={generate_transaction_number(invoice.id)}&' \ f'trnAmount={invoice.total}&' \ f'paymentMethod=CC&' \ f'redirectUri=google.com&' \ f'currency=CAD&' \ f'revenue={revenue_str}|' \ f'{revenue_str_service_fee}' expected_hash_str = HashingService.encode(urlstring) assert expected_hash_str == url_param_dict['hashValue']
def _create_nsf_invoice(cls, cfs_account: CfsAccountModel, rs_number: str, payment_account: PaymentAccountModel) -> InvoiceModel: """Create Invoice, line item and invoice reference records.""" fee_schedule: FeeScheduleModel = FeeScheduleModel.find_by_filing_type_and_corp_type(corp_type_code='BCR', filing_type_code='NSF') invoice = InvoiceModel( bcol_account=payment_account.bcol_account, payment_account_id=payment_account.id, cfs_account_id=cfs_account.id, invoice_status_code=InvoiceStatus.CREATED.value, total=fee_schedule.fee.amount, service_fees=0, paid=0, payment_method_code=PaymentMethod.INTERNAL.value, corp_type_code='BCR', created_on=datetime.now(), created_by='SYSTEM', routing_slip=rs_number ) invoice = invoice.save() distribution: DistributionCodeModel = DistributionCodeModel.find_by_active_for_fee_schedule( fee_schedule.fee_schedule_id) line_item = PaymentLineItemModel( invoice_id=invoice.id, total=invoice.total, fee_schedule_id=fee_schedule.fee_schedule_id, description=fee_schedule.filing_type.description, filing_fees=invoice.total, gst=0, priority_fees=0, pst=0, future_effective_fees=0, line_item_status_code=LineItemStatus.ACTIVE.value, service_fees=0, fee_distribution_id=distribution.distribution_code_id) line_item.save() invoice_response = CFSService.create_account_invoice(transaction_number=invoice.id, line_items=invoice.payment_line_items, cfs_account=cfs_account) invoice_number = invoice_response.json().get('invoice_number', None) current_app.logger.info(f'invoice_number {invoice_number} created in CFS for NSF.') InvoiceReferenceModel( invoice_id=invoice.id, invoice_number=invoice_number, reference_number=invoice_response.json().get('pbc_ref_number', None), status_code=InvoiceReferenceStatus.ACTIVE.value ).save() return invoice
def factory_payment_line_item(invoice_id: str, fee_schedule_id: int, filing_fees: int = 10, total: int = 10, service_fees: int = 0, status: str = LineItemStatus.ACTIVE.value): """Return Factory.""" return PaymentLineItem( invoice_id=invoice_id, fee_schedule_id=fee_schedule_id, filing_fees=filing_fees, total=total, service_fees=service_fees, line_item_status_code=status, fee_distribution_id=DistributionCode.find_by_active_for_fee_schedule(fee_schedule_id).distribution_code_id )
def _create_nsf_invoice(cfs_account: CfsAccountModel, inv_number: str, payment_account: PaymentAccountModel) -> InvoiceModel: """Create Invoice, line item and invoice referwnce records.""" fee_schedule: FeeScheduleModel = FeeScheduleModel.find_by_filing_type_and_corp_type( corp_type_code='BCR', filing_type_code='NSF') invoice = InvoiceModel(bcol_account=payment_account.bcol_account, payment_account_id=payment_account.id, cfs_account_id=cfs_account.id, invoice_status_code=InvoiceStatus.CREATED.value, total=fee_schedule.fee.amount, service_fees=0, paid=0, payment_method_code=PaymentMethod.CC.value, corp_type_code='BCR', created_on=datetime.now(), created_by='SYSTEM') invoice = invoice.save() distribution: DistributionCodeModel = DistributionCodeModel.find_by_active_for_fee_schedule( fee_schedule.fee_schedule_id) line_item = PaymentLineItemModel( invoice_id=invoice.id, total=invoice.total, fee_schedule_id=fee_schedule.fee_schedule_id, description=fee_schedule.filing_type.description, filing_fees=invoice.total, gst=0, priority_fees=0, pst=0, future_effective_fees=0, line_item_status_code=LineItemStatus.ACTIVE.value, service_fees=0, fee_distribution_id=distribution.distribution_code_id if distribution else 1) # TODO line_item.save() inv_ref: InvoiceReferenceModel = InvoiceReferenceModel( invoice_id=invoice.id, invoice_number=inv_number, reference_number=InvoiceReferenceModel. find_any_active_reference_by_invoice_number( invoice_number=inv_number).reference_number, status_code=InvoiceReferenceStatus.ACTIVE.value) inv_ref.save() return invoice
def create(invoice_id: int, fee: FeeSchedule, **kwargs): """Create Payment Line Item record.""" current_app.logger.debug('<create') user: UserContext = kwargs['user'] p = PaymentLineItem() p.invoice_id = invoice_id p.total = fee.total_excluding_service_fees p.fee_schedule_id = fee.fee_schedule_id p.description = fee.description p.filing_fees = fee.fee_amount p.gst = fee.gst p.priority_fees = fee.priority_fee p.pst = fee.pst p.future_effective_fees = fee.future_effective_fee p.quantity = fee.quantity if fee.quantity else 1 p.line_item_status_code = LineItemStatus.ACTIVE.value p.waived_fees = fee.waived_fee_amount p.service_fees = fee.service_fees # Set distribution details to line item distribution_code = None if p.total > 0: distribution_code = DistributionCodeModel.find_by_active_for_fee_schedule( fee.fee_schedule_id) p.fee_distribution_id = distribution_code.distribution_code_id if fee.waived_fee_amount > 0: if user.has_role(Role.STAFF.value): p.waived_by = user.user_name else: raise BusinessException(Error.FEE_OVERRIDE_NOT_ALLOWED) p_dao = p.flush() p = PaymentLineItem() p._dao = p_dao # pylint: disable=protected-access # Set distribution model to avoid more queries to DB p.fee_distribution = distribution_code current_app.logger.debug('>create') return p
async def test_failed_payment_ejv_reconciliations(session, app, stan_server, event_loop, client_id, events_stan, future, mock_publish): """Test Reconciliations worker.""" # Call back for the subscription from reconciliations.worker import cb_subscription_handler # Create a Credit Card Payment # register the handler to test it await subscribe_to_queue( events_stan, current_app.config.get('SUBSCRIPTION_OPTIONS').get('subject'), current_app.config.get('SUBSCRIPTION_OPTIONS').get('queue'), current_app.config.get('SUBSCRIPTION_OPTIONS').get('durable_name'), cb_subscription_handler) # 1. Create EJV payment accounts # 2. Create invoice and related records # 3. Create a feedback file and assert status corp_type = 'BEN' filing_type = 'BCINC' # Find fee schedule which have service fees. fee_schedule: FeeScheduleModel = FeeScheduleModel.find_by_filing_type_and_corp_type( corp_type, filing_type) # Create a service fee distribution code service_fee_dist_code = factory_distribution(name='service fee', client='112', reps_centre='99999', service_line='99999', stob='9999', project_code='9999999') service_fee_dist_code.save() dist_code: DistributionCodeModel = DistributionCodeModel.find_by_active_for_fee_schedule( fee_schedule.fee_schedule_id) # Update fee dist code to match the requirement. dist_code.client = '112' dist_code.responsibility_centre = '22222' dist_code.service_line = '33333' dist_code.stob = '4444' dist_code.project_code = '5555555' dist_code.service_fee_distribution_code_id = service_fee_dist_code.distribution_code_id dist_code.save() # GA jv_account_1 = factory_create_ejv_account(auth_account_id='1') jv_account_2 = factory_create_ejv_account(auth_account_id='2') # GI jv_account_3 = factory_create_ejv_account(auth_account_id='3', client='111') jv_account_4 = factory_create_ejv_account(auth_account_id='4', client='111') # Now create JV records. # Create EJV File model file_ref = f'INBOX.{datetime.now()}' ejv_file: EjvFileModel = EjvFileModel( file_ref=file_ref, disbursement_status_code=DisbursementStatus.UPLOADED.value, is_distribution=False).save() ejv_file_id = ejv_file.id feedback_content = f'..BG...........00000000{ejv_file_id}...\n' \ f'..BH...0000.................................................................................' \ f'.....................................................................CGI\n' jv_accounts = [jv_account_1, jv_account_2, jv_account_3, jv_account_4] inv_ids = [] jv_account_ids = [] inv_total_amount = 101.5 for jv_acc in jv_accounts: jv_account_ids.append(jv_acc.id) inv = factory_invoice(payment_account=jv_acc, corp_type_code=corp_type, total=inv_total_amount, status_code=InvoiceStatus.APPROVED.value, payment_method_code=None) factory_invoice_reference(inv.id) line: PaymentLineItemModel = factory_payment_line_item( invoice_id=inv.id, fee_schedule_id=fee_schedule.fee_schedule_id, filing_fees=100, total=100, service_fees=1.5, fee_dist_id=dist_code.distribution_code_id) inv_ids.append(inv.id) ejv_header: EjvHeaderModel = EjvHeaderModel( disbursement_status_code=DisbursementStatus.UPLOADED.value, ejv_file_id=ejv_file.id, payment_account_id=jv_acc.id).save() EjvInvoiceLinkModel( invoice_id=inv.id, ejv_header_id=ejv_header.id, disbursement_status_code=DisbursementStatus.UPLOADED.value).save() inv_total = f'{inv.total:.2f}'.zfill(15) pay_line_amount = f'{line.total:.2f}'.zfill(15) service_fee_amount = f'{line.service_fees:.2f}'.zfill(15) jh_and_jd = f'..JH...FI0000000{ejv_header.id}.........................{inv_total}.....................' \ f'............................................................................................' \ f'............................................................................................' \ f'.........1111ERROR..........................................................................' \ f'.......................................................................CGI\n' \ f'..JD...FI0000000{ejv_header.id}00001........................................................' \ f'...........{pay_line_amount}D.................................................................' \ f'...................................{inv.id} ' \ f' 1111ERROR...................' \ f'............................................................................................' \ f'..................................CGI\n' \ f'..JD...FI0000000{ejv_header.id}00002........................................................' \ f'...........{pay_line_amount}C.................................................................' \ f'...................................{inv.id} ' \ f' 1111ERROR...................' \ f'............................................................................................' \ f'..................................CGI\n' \ f'..JD...FI0000000{ejv_header.id}00003...........................................................' \ f'........{service_fee_amount}D.................................................................' \ f'...................................{inv.id} ' \ f' 1111ERROR...................' \ f'............................................................................................' \ f'..................................CGI\n' \ f'..JD...FI0000000{ejv_header.id}00004........................................................' \ f'...........{service_fee_amount}C..............................................................' \ f'......................................{inv.id} ' \ f' 1111ERROR...................' \ f'............................................................................................' \ f'..................................CGI\n' feedback_content = feedback_content + jh_and_jd feedback_content = feedback_content + f'..BT.......FI0000000{ejv_header.id}000000000000002{inv_total}0000.......' \ f'.........................................................................' \ f'......................................................................CGI' ack_file_name = f'ACK.{file_ref}' with open(ack_file_name, 'a+') as jv_file: jv_file.write('') jv_file.close() # Now upload the ACK file to minio and publish message. upload_to_minio(file_name=ack_file_name, value_as_bytes=str.encode('')) await helper_add_ejv_event_to_queue(events_stan, file_name=ack_file_name) # Query EJV File and assert the status is changed ejv_file = EjvFileModel.find_by_id(ejv_file_id) assert ejv_file.disbursement_status_code == DisbursementStatus.ACKNOWLEDGED.value feedback_file_name = f'FEEDBACK.{file_ref}' with open(feedback_file_name, 'a+') as jv_file: jv_file.write(feedback_content) jv_file.close() # Now upload the ACK file to minio and publish message. with open(feedback_file_name, 'rb') as f: upload_to_minio(f.read(), feedback_file_name) await helper_add_ejv_event_to_queue(events_stan, file_name=feedback_file_name, message_type='FEEDBACKReceived') # Query EJV File and assert the status is changed ejv_file = EjvFileModel.find_by_id(ejv_file_id) assert ejv_file.disbursement_status_code == DisbursementStatus.COMPLETED.value # Assert invoice and receipt records for inv_id in inv_ids: invoice: InvoiceModel = InvoiceModel.find_by_id(inv_id) assert invoice.disbursement_status_code is None assert invoice.invoice_status_code == InvoiceStatus.APPROVED.value # Will stay as original status invoice_ref: InvoiceReferenceModel = InvoiceReferenceModel.find_reference_by_invoice_id_and_status( inv_id, InvoiceReferenceStatus.COMPLETED.value) assert invoice_ref is None # No completed inv ref receipt = ReceiptModel.find_by_invoice_id_and_receipt_number( invoice_id=inv_id) assert receipt is None # NO receipt # Assert payment records for jv_account_id in jv_account_ids: account = PaymentAccountModel.find_by_id(jv_account_id) payment: PaymentModel = PaymentModel.search_account_payments( auth_account_id=account.auth_account_id, payment_status=PaymentStatus.COMPLETED.value, page=1, limit=100)[0] assert len(payment) == 0
def test_payments_for_gov_accounts(session, monkeypatch): """Test payments for gov accounts. Steps: 1) Update a distribution code with client code 112. 2) Create multiple gov accounts for GA - 112 3) Create multiple gov accounts for GI - NOT 112 4) Create some transactions for these accounts 5) Run the job and assert results. """ monkeypatch.setattr('pysftp.Connection.put', lambda *args, **kwargs: None) corp_type = 'BEN' filing_type = 'BCINC' # Find fee schedule which have service fees. fee_schedule: FeeSchedule = FeeSchedule.find_by_filing_type_and_corp_type(corp_type, filing_type) # Create a service fee distribution code service_fee_dist_code = factory_distribution(name='service fee', client='112', reps_centre='99999', service_line='99999', stob='9999', project_code='9999999') service_fee_dist_code.save() dist_code: DistributionCode = DistributionCode.find_by_active_for_fee_schedule(fee_schedule.fee_schedule_id) # Update fee dist code to match the requirement. dist_code.client = '112' dist_code.responsibility_centre = '22222' dist_code.service_line = '33333' dist_code.stob = '4444' dist_code.project_code = '5555555' dist_code.service_fee_distribution_code_id = service_fee_dist_code.distribution_code_id dist_code.save() # GA jv_account_1 = factory_create_ejv_account(auth_account_id='1') jv_account_2 = factory_create_ejv_account(auth_account_id='2') # GI jv_account_3 = factory_create_ejv_account(auth_account_id='3', client='111') jv_account_4 = factory_create_ejv_account(auth_account_id='4', client='111') jv_accounts = [jv_account_1, jv_account_2, jv_account_3, jv_account_4] inv_ids = [] for jv_acc in jv_accounts: inv = factory_invoice(payment_account=jv_acc, corp_type_code=corp_type, total=101.5, status_code=InvoiceStatus.APPROVED.value, payment_method_code=None) factory_payment_line_item(invoice_id=inv.id, fee_schedule_id=fee_schedule.fee_schedule_id, filing_fees=100, total=100, service_fees=1.5, fee_dist_id=dist_code.distribution_code_id) inv_ids.append(inv.id) EjvPaymentTask.create_ejv_file() # Lookup invoice and assert invoice status for inv_id in inv_ids: invoice_ref = InvoiceReference.find_reference_by_invoice_id_and_status(inv_id, InvoiceReferenceStatus.ACTIVE.value) assert invoice_ref ejv_inv_link = db.session.query(EjvInvoiceLink).filter(EjvInvoiceLink.invoice_id == inv_id).first() assert ejv_inv_link ejv_header = db.session.query(EjvHeader).filter(EjvHeader.id == ejv_inv_link.ejv_header_id).first() assert ejv_header.disbursement_status_code == DisbursementStatus.UPLOADED.value assert ejv_header ejv_file: EjvFile = EjvFile.find_by_id(ejv_header.ejv_file_id) assert ejv_file assert ejv_file.disbursement_status_code == DisbursementStatus.UPLOADED.value assert not ejv_file.is_distribution