示例#1
0
    def test_balance_on_date(self):
        import pytz

        start_date = dt.datetime(2019, 1, 1, 0, 0, 0, 0, tzinfo=pytz.UTC)
        invoice_date = dt.datetime(2019, 1, 15, 0, 0, 0, 0, tzinfo=pytz.UTC)
        payment_date = dt.datetime(2019, 1, 17, 0, 0, 0, 0, tzinfo=pytz.UTC)
        mid_date = dt.datetime(2019, 1, 20, 0, 0, 0, 0, tzinfo=pytz.UTC)

        from silver.overpayment_checker import OverpaymentChecker

        # 0 for easy asserting.
        customer = CustomerFactory(sales_tax_percent=0,
                                   currency='USD',
                                   first_name="Bob",
                                   last_name="Smith")
        customer.save()

        assert customer.balance_on_date(date=start_date) == Decimal(0)

        ## Now we create an invoice situation after the start date...

        # Create customer payment method
        payment_method = PaymentMethodFactory.create(
            payment_processor=triggered_processor,
            customer=customer,
            canceled=False)
        payment_method.save()

        # Create a simple invoice
        entry = DocumentEntryFactory(quantity=1, unit_price=150)
        entry.save()
        invoice = InvoiceFactory.create(invoice_entries=[entry],
                                        due_date=invoice_date,
                                        customer=customer,
                                        transaction_currency='USD')
        invoice.issue()
        invoice.save()

        # Customer overpays by 2x
        transaction = TransactionFactory.create(
            invoice=invoice,
            payment_method=payment_method,
            created_at=payment_date,
            updated_at=payment_date,
            overpayment=True,
            amount=300,
            state=Transaction.States.Initial)
        transaction.settle()
        transaction.save()

        invoice.pay()

        assert invoice.state == Invoice.STATES.PAID
        assert customer.balance_on_date(date=start_date) == Decimal(0)
        assert customer.balance_on_date(date=payment_date) == Decimal(0)
        # This balance should be 150, but it's not yet.
        assert customer.balance_on_date(date=mid_date) == Decimal(150)
        return

        # Grab the overpayment defaults
        op = OverpaymentChecker()

        # Run the overpayment process
        call_command('check_overpayments',
                     billing_date=timezone.now().date(),
                     stdout=self.output)

        # An invoice has been issued a for the correct amount.
        repayment = Invoice.objects.filter(
            provider=op.default_provider).first()
        assert Invoice.objects.filter(
            provider=op.default_provider).count() == 1
        assert repayment.total_in_transaction_currency == -150
        assert repayment.state == Invoice.STATES.ISSUED

        # Customer balance is still the same; payment has not occurred
        # yet.
        assert customer.balance == Decimal(150)

        # Run the overpayment process a couple more times, does it duplicate
        # things?
        call_command('check_overpayments',
                     billing_date=timezone.now().date(),
                     stdout=self.output)

        call_command('check_overpayments',
                     billing_date=timezone.now().date(),
                     stdout=self.output)

        call_command('check_overpayments',
                     billing_date=timezone.now().date(),
                     stdout=self.output)

        assert Invoice.objects.filter(
            provider=op.default_provider).count() == 1
        assert repayment.total_in_transaction_currency == -150
        assert repayment.state == Invoice.STATES.ISSUED

        # Customer balance is still the same; payment has not occurred
        # yet.
        assert customer.balance == Decimal(150)

        # Create the repayment transaction, this is supposed to happen
        # somewhere automatically.
        amt = repayment.total_in_transaction_currency
        repayment_tx = Transaction.objects.create(
            invoice=repayment,
            amount=amt,
            overpayment=True,
            state=Transaction.States.Initial,
            payment_method=payment_method)
        repayment_tx.settle()
        repayment_tx.save()

        # There's one transaction issued for this doc, and it has set
        # the state of the invoice to PAID. The customer's balance is
        # now 0.
        assert repayment.state == Invoice.STATES.PAID
        assert repayment.transactions.count() == 1
        assert repayment.amount_paid_in_transaction_currency == -150
        assert repayment.customer.balance == Decimal(0)
示例#2
0
    def test_customer_balance_gte_zero(self):
        """ Create a zero and positive balance, and rerun the
        overpayment process: no invoices should be issued. """

        from silver.overpayment_checker import OverpaymentChecker

        # 0 for easy asserting.
        customer = CustomerFactory(sales_tax_percent=0,
                                   currency='USD',
                                   first_name="Bob",
                                   last_name="Smith")
        customer.save()

        # Create customer payment method
        payment_method = PaymentMethodFactory.create(
            payment_processor=triggered_processor,
            customer=customer,
            canceled=False)
        payment_method.save()

        # Create a simple invoice
        entry = DocumentEntryFactory(quantity=1, unit_price=150)
        entry.save()
        invoice = InvoiceFactory.create(invoice_entries=[entry],
                                        customer=customer,
                                        transaction_currency='USD')
        invoice.issue()
        invoice.save()

        # Customer pays an accurate amount.
        transaction = TransactionFactory.create(
            invoice=invoice,
            payment_method=payment_method,
            amount=150,
            state=Transaction.States.Initial)
        transaction.settle()
        transaction.save()

        assert invoice.state == Invoice.STATES.PAID
        assert Invoice.objects.filter(customer=customer).count() == 1
        assert customer.balance == Decimal(0)

        # Run the overpayment process
        call_command('check_overpayments',
                     billing_date=timezone.now().date(),
                     stdout=self.output)

        provider = OverpaymentChecker().default_provider
        assert Invoice.objects.filter(provider=provider).count() == 0

        # Run the overpayment process a couple more times, does it duplicate
        # things?
        call_command('check_overpayments',
                     billing_date=timezone.now().date(),
                     stdout=self.output)

        call_command('check_overpayments',
                     billing_date=timezone.now().date(),
                     stdout=self.output)

        call_command('check_overpayments',
                     billing_date=timezone.now().date(),
                     stdout=self.output)

        assert Invoice.objects.filter(provider=provider).count() == 0
示例#3
0
    def test_correct_overpayment(self):
        """ An invoice is issued, and it is overpaid. A correction is issued
            """

        # 0 for easy asserting.
        customer = CustomerFactory(sales_tax_percent=0,
                                   currency='USD',
                                   first_name="Bob",
                                   last_name="Smith")
        customer.save()

        payment_method = PaymentMethodFactory.create(
            payment_processor=triggered_processor,
            customer=customer,
            canceled=False)

        # Create a simple invoice
        entry = DocumentEntryFactory(quantity=1, unit_price=150)
        invoice = InvoiceFactory.create(invoice_entries=[entry],
                                        customer=customer,
                                        transaction_currency='USD')
        invoice.issue()
        invoice.save()

        assert PaymentMethod.objects.count() == 1
        assert Invoice.objects.count() == 1
        assert BillingDocumentBase.objects.count() == 1

        # Customer overpays by 2x
        transaction = TransactionFactory.create(
            invoice=invoice,
            payment_method=payment_method,
            overpayment=True,
            amount=300,
            state=Transaction.States.Initial)
        transaction.settle()
        transaction.save()

        invoice.pay()

        assert invoice.state == Invoice.STATES.PAID
        assert PaymentMethod.objects.count() == 1
        assert Invoice.objects.count() == 1
        # Proforma issued as well
        assert BillingDocumentBase.objects.count() == 2
        assert customer.balance == Decimal(150)

        # # Create a repayment invoice
        entry = DocumentEntryFactory(quantity=1, unit_price=-150)
        invoice = InvoiceFactory.create(invoice_entries=[entry],
                                        customer=customer,
                                        state=Invoice.STATES.DRAFT,
                                        transaction_currency='USD')
        invoice.save()
        assert customer.balance == Decimal(150)

        invoice.issue()
        invoice.save()
        assert customer.balance == Decimal(150)

        # This is the transaction to correct the balance. We're using
        # .settle() here, but we will need another method (forthcoming).
        transaction = TransactionFactory.create(
            invoice=invoice,
            payment_method=payment_method,
            overpayment=True,
            amount=-150,
            state=Transaction.States.Initial)

        transaction.settle()
        transaction.save()

        assert invoice.state == Invoice.STATES.PAID
        assert customer.balance == Decimal(0)
示例#4
0
    def test_overpayment_checker_process(self):
        from silver.overpayment_checker import OverpaymentChecker

        customer = CustomerFactory(
            sales_tax_percent=0,  # 0 for easy asserting.
            currency='USD',
            first_name="Bob",
            last_name="Smith")
        customer.save()

        # Create customer payment method
        #
        payment_method = PaymentMethodFactory.create(
            payment_processor=triggered_processor,
            customer=customer,
            canceled=False)
        payment_method.save()

        # Create a simple invoice.
        #
        entry = DocumentEntryFactory(quantity=1, unit_price=150)
        entry.save()
        invoice = InvoiceFactory.create(invoice_entries=[entry],
                                        customer=customer,
                                        transaction_currency='USD')
        invoice.issue()
        invoice.save()

        # Customer overpays by 2x
        #
        transaction = TransactionFactory.create(
            invoice=invoice,
            payment_method=payment_method,
            overpayment=True,
            amount=300,
            state=Transaction.States.Initial)
        transaction.settle()
        transaction.save()

        invoice.pay()

        assert invoice.state == Invoice.STATES.PAID
        assert customer.balance == Decimal(150)

        # Grab the overpayment defaults
        op = OverpaymentChecker()

        # Run the overpayment process
        call_command('check_overpayments',
                     billing_date=timezone.now().date(),
                     stdout=self.output)

        # An invoice has been issued a for the correct amount.
        repayment = Invoice.objects.filter(
            provider=op.default_provider).first()
        assert Invoice.objects.filter(
            provider=op.default_provider).count() == 1
        assert repayment.total_in_transaction_currency == -150
        assert repayment.state == Invoice.STATES.ISSUED

        # Customer balance is still the same; payment has not occurred
        # yet.
        #
        assert customer.balance == Decimal(150)

        # Create the repayment transaction, this is supposed to happen
        # somewhere automatically.
        #
        repayment_tx = Transaction.objects.create(
            invoice=repayment,
            amount=repayment.total_in_transaction_currency,
            overpayment=True,
            state=Transaction.States.Initial,
            payment_method=payment_method)
        repayment_tx.settle()
        repayment_tx.save()

        # There's one transaction issued for this doc, and it has set
        # the state of the invoice to PAID. The customer's balance is
        # now 0.
        #
        assert repayment.state == Invoice.STATES.PAID
        assert repayment.transactions.count() == 1
        assert repayment.amount_paid_in_transaction_currency == -150
        assert repayment.customer.balance == Decimal(0)
示例#5
0
    def test_customer_balance_calculation_with_overpayments(self):
        """ An invoice is issued, and it is paid in two transactions:
            one for half the amount, and another for well over the
            amount. """
        # 0 for easy asserting.
        customer = CustomerFactory(sales_tax_percent=0,
                                   currency='USD',
                                   first_name="Bob",
                                   last_name="Smith")
        customer.save()

        payment_method = PaymentMethodFactory.create(
            payment_processor=triggered_processor,
            customer=customer,
            canceled=False)

        # Create a simple invoice
        entry = DocumentEntryFactory(quantity=1, unit_price=250)
        invoice = InvoiceFactory.create(invoice_entries=[entry],
                                        customer=customer)
        invoice.issue()

        # Customer underpays by half
        transaction = TransactionFactory.create(
            invoice=invoice,
            payment_method=payment_method,
            amount=125.00,
            state=Transaction.States.Initial)

        transaction.settle()
        transaction.save()

        assert invoice.state != Invoice.STATES.PAID

        # Customer overpays by double
        transaction_over = TransactionFactory.create(
            invoice=invoice,
            payment_method=payment_method,
            amount=500,
            # NB:
            overpayment=True,
            state=Transaction.States.Initial)

        transaction_over.settle()
        transaction_over.save()

        assert invoice.state != Invoice.STATES.PAID

        invoice.pay()
        assert invoice.state == Invoice.STATES.PAID

        # Payment calculation works even with overpayment.
        assert invoice.amount_paid_in_transaction_currency == \
            ((invoice.total_in_transaction_currency / 2) + \
             (invoice.total_in_transaction_currency * 2))

        # Customer paid 625 total, for an invoice of 250
        # Current balance: 375.00
        overpayment = abs(
            invoice.total_in_transaction_currency - \
                ((invoice.total_in_transaction_currency / 2) + \
                 (invoice.total_in_transaction_currency * 2))
        )

        assert invoice.total_in_transaction_currency == 250.00
        assert overpayment == Decimal(375.00)
        assert customer.balance == overpayment