Exemplo n.º 1
0
    def create_account_payment(auth_account_id: str,
                               is_retry_payment: bool) -> Payment:
        """Create a payment record for the account."""
        payment: Payment = None
        if is_retry_payment:
            # If there are multiple failed payments, consolidate them
            # Else clone failed payment
            # Find all failed payments.
            payments = Payment.get_failed_payments(auth_account_id)
            can_consolidate_invoice: bool = True
            if len(payments) == 1:
                can_consolidate_invoice = False
                failed_payment = payments[0]
            else:
                # Here iterate the payments and see if there is a failed PARTIAL payment.
                for payment in payments:
                    paid_amount = payment.paid_amount or 0
                    if payment.payment_status_code == PaymentStatus.FAILED.value and paid_amount > 0:
                        failed_payment = payment
                        can_consolidate_invoice = False
                        break

            if not can_consolidate_invoice:
                # Find if there is a payment for the same invoice number, with status CREATED.
                # If yes, use that record
                # Else create new one.
                stale_payments = PaymentModel.find_payment_by_invoice_number_and_status(
                    inv_number=failed_payment.invoice_number,
                    payment_status=PaymentStatus.CREATED.value)
                # pick the first one. Ideally only one will be there, but a race condition can cause multiple.
                if len(stale_payments) > 0:
                    payment = Payment._populate(stale_payments[0])

                # For consolidated payment status will be CREATED, if so don't create another payment record.
                elif failed_payment.payment_status_code == PaymentStatus.FAILED.value:
                    invoice_total = 0
                    for inv in InvoiceModel.find_invoices_for_payment(
                            payment_id=failed_payment.id):
                        invoice_total += inv.total

                    payment = Payment.create(
                        payment_method=PaymentMethod.CC.value,
                        payment_system=PaymentSystem.PAYBC.value,
                        invoice_number=failed_payment.invoice_number,
                        invoice_amount=invoice_total -
                        float(failed_payment.paid_amount or 0),
                        payment_account_id=failed_payment.payment_account_id)
                else:
                    payment = Payment._populate(failed_payment)

            else:  # Consolidate invoices into a single payment.
                payment = Payment._consolidate_payments(
                    auth_account_id, payments)

        current_app.logger.debug('>create_account_payment')
        return payment
Exemplo n.º 2
0
def _process_failed_payments(row):
    """Handle failed payments."""
    # 1. Set the cfs_account status as FREEZE.
    # 2. Call cfs api to Stop further PAD on this account.
    # 3. Reverse the invoice_reference status to ACTIVE, invoice status to SETTLEMENT_SCHED, and delete receipt.
    # 4. Create an NSF invoice for this account.
    # 5. Create invoice reference for the newly created NSF invoice.
    # 6. Adjust invoice in CFS to include NSF fees.
    inv_number = _get_row_value(row, Column.TARGET_TXN_NO)
    # If there is a FAILED payment record for this; it means it's a duplicate event. Ignore it.
    payment: PaymentModel = PaymentModel.find_payment_by_invoice_number_and_status(
        inv_number, PaymentStatus.FAILED.value)
    if payment:
        logger.info('Ignoring duplicate NSF message for invoice : %s ',
                    inv_number)
        return

    # Set CFS Account Status.
    payment_account: PaymentAccountModel = _get_payment_account(row)
    cfs_account: CfsAccountModel = CfsAccountModel.find_effective_by_account_id(
        payment_account.id)
    logger.info('setting payment account id : %s status as FREEZE',
                payment_account.id)
    cfs_account.status = CfsAccountStatus.FREEZE.value
    # Call CFS to stop any further PAD transactions on this account.
    CFSService.suspend_cfs_account(cfs_account)
    # Find the invoice_reference for this invoice and mark it as ACTIVE.
    inv_references: List[InvoiceReferenceModel] = db.session.query(InvoiceReferenceModel). \
        filter(InvoiceReferenceModel.status_code == InvoiceReferenceStatus.COMPLETED.value). \
        filter(InvoiceReferenceModel.invoice_number == inv_number). \
        all()

    # Update status to ACTIVE, if it was marked COMPLETED
    for inv_reference in inv_references:
        inv_reference.status_code = InvoiceReferenceStatus.ACTIVE.value
        # Find receipt and delete it.
        receipt: ReceiptModel = ReceiptModel.find_by_invoice_id_and_receipt_number(
            invoice_id=inv_reference.invoice_id)
        if receipt:
            db.session.delete(receipt)
        # Find invoice and update the status to SETTLEMENT_SCHED
        invoice: InvoiceModel = InvoiceModel.find_by_id(
            identifier=inv_reference.invoice_id)
        invoice.invoice_status_code = InvoiceStatus.SETTLEMENT_SCHEDULED.value
        invoice.paid = 0

    # Create an invoice for NSF for this account
    invoice = _create_nsf_invoice(cfs_account, inv_number, payment_account)
    # Adjust CFS invoice
    CFSService.add_nsf_adjustment(cfs_account=cfs_account,
                                  inv_number=inv_number,
                                  amount=invoice.total)