Ejemplo n.º 1
0
    def _update_receipt_details(invoices, payment, receipt_details,
                                transaction_dao):
        """Update receipt details to invoice."""
        payment.paid_amount = receipt_details[2]
        payment.completed_on = datetime.now()
        transaction_dao.status_code = TransactionStatus.COMPLETED.value

        if float(payment.paid_amount) < float(payment.invoice_amount):
            current_app.logger.critical(
                'ALERT : Paid Amount is less than owed amount.  Paid : %s, Owed- %s',
                payment.paid_amount, payment.invoice_amount)
            capture_message(
                f'ALERT : Paid Amount is less than owed amount.  Paid : {payment.paid_amount}, '
                f'Owed: {payment.invoice_amount}',
                level='error')
        else:
            payment.payment_status_code = PaymentStatus.COMPLETED.value

            for invoice in invoices:
                # Save receipt details for each invoice
                PaymentTransaction.__save_receipt(invoice, receipt_details)
                invoice.paid = invoice.total  # set the paid amount as total
                invoice.invoice_status_code = InvoiceStatus.PAID.value
                invoice_reference = InvoiceReference.find_active_reference_by_invoice_id(
                    invoice.id)
                invoice_reference.status_code = InvoiceReferenceStatus.COMPLETED.value
                # TODO If it's not PAD, publish message. Refactor and move to pay system service later.
                if invoice.payment_method_code != PaymentMethod.PAD.value:
                    PaymentTransaction.publish_status(transaction_dao, invoice)
Ejemplo n.º 2
0
    def _build_pay_system_url_for_invoice(invoice: Invoice, pay_system_service: PaymentSystemService,
                                          transaction_id: uuid, pay_return_url: str):
        """Build pay system url which will be used to redirect to the payment system."""
        current_app.logger.debug('<build_pay_system_url')
        invoice_reference = InvoiceReference.find_active_reference_by_invoice_id(invoice.id)
        return_url = f'{pay_return_url}/{invoice.id}/transaction/{transaction_id}'

        current_app.logger.debug('>build_pay_system_url')
        return pay_system_service.get_payment_system_url_for_invoice(invoice, invoice_reference, return_url)
Ejemplo n.º 3
0
    def build_pay_system_url(payment: Payment, transaction_id: uuid, pay_return_url: str):
        """Build pay system url which will be used to redirect to the payment system."""
        current_app.logger.debug('<build_pay_system_url')
        pay_system_service: PaymentSystemService = PaymentSystemFactory.create_from_system_code(
            payment_system=payment.payment_system_code
        )
        invoice = InvoiceModel.find_by_payment_id(payment.id)
        invoice_reference = InvoiceReference.find_active_reference_by_invoice_id(invoice.id)
        return_url = f'{pay_return_url}/{payment.id}/transaction/{transaction_id}'

        current_app.logger.debug('>build_pay_system_url')
        return pay_system_service.get_payment_system_url(Invoice.populate(invoice), invoice_reference, return_url)
Ejemplo n.º 4
0
def test_active_reference_by_invoice_id(session):
    """Assert that the invoice reference lookup is working."""
    payment_account = factory_payment_account()
    payment = factory_payment()
    payment_account.save()
    payment.save()
    i = factory_invoice(payment=payment, payment_account=payment_account)
    i.save()

    InvoiceReference.create(i.id, 'TEST_INV_NUMBER', 'TEST_REF_NUMBER')

    # Do a look up
    invoice_reference = InvoiceReference.find_active_reference_by_invoice_id(i.id)

    assert invoice_reference is not None
    assert invoice_reference.id is not None
    assert invoice_reference.invoice_id == i.id
Ejemplo n.º 5
0
    def process_cfs_refund(self, invoice: InvoiceModel) -> str:  # pylint:disable=unused-argument
        """Do nothing to process refund; as the refund is handled by CRON job.

        Return the status after checking invoice status.
            1. If invoice status is APPROVED:
            1.1 return REFUND_REQUESTED if there is an ACTIVE invoice_reference
            1.2 else return REFUNDED (as no refund process is needed for this as JV hasn't started yet)
            2. If invoice status is PAID
            2.1 Return REFUND_REQUESTED
        """
        current_app.logger.info(
            f'Received JV refund for invoice {invoice.id}, {invoice.invoice_status_code}'
        )
        if invoice.invoice_status_code == InvoiceStatus.APPROVED.value:
            if InvoiceReference.find_active_reference_by_invoice_id(
                    invoice.id):
                return InvoiceStatus.REFUND_REQUESTED.value
            return InvoiceStatus.REFUNDED.value
        return InvoiceStatus.REFUND_REQUESTED.value
Ejemplo n.º 6
0
    def create_transaction_for_invoice(
            invoice_id: int, request_json: Dict) -> PaymentTransaction:
        """Create transaction record for invoice, by creating a payment record if doesn't exist."""
        current_app.logger.debug('<create transaction')
        # Lookup invoice record
        invoice: Invoice = Invoice.find_by_id(invoice_id, skip_auth_check=True)
        if not invoice.id:
            raise BusinessException(Error.INVALID_INVOICE_ID)
        if invoice.payment_method_code == PaymentMethod.PAD.value:  # No transaction needed for PAD invoices.
            raise BusinessException(Error.INVALID_TRANSACTION)

        pay_system_service: PaymentSystemService = PaymentSystemFactory.create_from_payment_method(
            payment_method=invoice.payment_method_code)
        # Check if return url is valid
        PaymentTransaction._validate_redirect_url_and_throw_error(
            invoice.payment_method_code, request_json.get('clientSystemUrl'))

        # Check if there is a payment created. If not, create a payment record with status CREATED
        payment: Payment = Payment.find_payment_for_invoice(invoice_id)
        if not payment:
            # Transaction is against payment, so create a payment if not present.
            invoice_reference = InvoiceReference.find_active_reference_by_invoice_id(
                invoice.id)

            # Create a payment record
            payment = Payment.create(
                payment_method=pay_system_service.get_payment_method_code(),
                payment_system=pay_system_service.get_payment_system_code(),
                payment_status=pay_system_service.get_default_payment_status(),
                invoice_number=invoice_reference.invoice_number,
                invoice_amount=invoice.total,
                payment_account_id=invoice.payment_account_id)

        transaction = PaymentTransaction._create_transaction(payment,
                                                             request_json,
                                                             invoice=invoice)
        current_app.logger.debug('>create transaction')

        return transaction
Ejemplo n.º 7
0
def test_invoice_invalid_lookup(session):
    """Test invalid lookup."""
    inv_reference = InvoiceReference.find_active_reference_by_invoice_id(999)
    assert inv_reference is None
Ejemplo n.º 8
0
    def update_transaction(payment_identifier: int, transaction_id: uuid,  # pylint: disable=too-many-locals
                           receipt_number: str):
        """Update transaction record.

        Does the following:
        1. Find the payment record with the id
        2. Find the invoice record using the payment identifier
        3. Call the pay system service and get the receipt details
        4. Save the receipt record
        5. Change the status of Invoice
        6. Change the status of Payment
        7. Update the transaction record
        """
        transaction_dao: PaymentTransactionModel = PaymentTransactionModel.find_by_id_and_payment_id(
            transaction_id, payment_identifier
        )
        if not transaction_dao:
            raise BusinessException(Error.INVALID_TRANSACTION_ID)
        if transaction_dao.status_code == TransactionStatus.COMPLETED.value:
            raise BusinessException(Error.INVALID_TRANSACTION)

        payment: Payment = Payment.find_by_id(payment_identifier, skip_auth_check=True)

        if payment.payment_status_code == PaymentStatus.COMPLETED.value:
            raise BusinessException(Error.COMPLETED_PAYMENT)

        pay_system_service: PaymentSystemService = PaymentSystemFactory.create_from_system_code(
            payment_system=payment.payment_system_code
        )

        invoice = Invoice.find_by_payment_identifier(payment_identifier, skip_auth_check=True)
        invoice_reference = InvoiceReference.find_active_reference_by_invoice_id(invoice.id)
        payment_account = PaymentAccount.find_by_pay_system_id(
            credit_account_id=invoice.credit_account_id,
            internal_account_id=invoice.internal_account_id,
            bcol_account_id=invoice.bcol_account_id)

        try:
            receipt_details = pay_system_service.get_receipt(payment_account, receipt_number, invoice_reference)
            txn_reason_code = None
        except ServiceUnavailableException as exc:
            txn_reason_code = exc.status
            receipt_details = None

        if receipt_details:
            # Find if a receipt exists with same receipt_number for the invoice
            receipt = PaymentTransaction.__save_receipt(invoice, receipt_details)

            invoice.paid = receipt.receipt_amount

            if invoice.paid == invoice.total:
                invoice.invoice_status_code = InvoiceStatus.PAID.value
                payment.payment_status_code = PaymentStatus.COMPLETED.value
                payment.save()

                invoice_reference.status_code = InvoiceReferenceStatus.COMPLETED.value
                invoice_reference.save()

            invoice.save()

            transaction_dao.status_code = TransactionStatus.COMPLETED.value
        else:
            transaction_dao.status_code = TransactionStatus.FAILED.value

        transaction_dao.transaction_end_time = datetime.now()

        # Publish status to Queue
        PaymentTransaction.publish_status(transaction_dao, payment, invoice.filing_id)

        transaction_dao = transaction_dao.save()

        transaction = PaymentTransaction()
        transaction._dao = transaction_dao  # pylint: disable=protected-access
        transaction.pay_system_reason_code = txn_reason_code

        current_app.logger.debug('>update_transaction')
        return transaction