Esempio n. 1
0
    def handle(self, *args, **options):
        proforma = ProformaFactory.create(proforma_entries=[DocumentEntryFactory.create()],
                                          state=Proforma.STATES.ISSUED)
        proforma.create_invoice()

        invoice = InvoiceFactory.create(invoice_entries=[DocumentEntryFactory.create()],
                                        state=Invoice.STATES.ISSUED,
                                        related_document=None)
        TransactionFactory.create(state=Transaction.States.Settled,
                                  invoice=invoice,
                                  payment_method__customer=invoice.customer,
                                  proforma=None)
        InvoiceFactory.create_batch(size=3,
                                    invoice_entries=[DocumentEntryFactory.create()],
                                    state=Invoice.STATES.PAID,
                                    related_document=None)
        InvoiceFactory.create_batch(size=3,
                                    invoice_entries=[DocumentEntryFactory.create()],
                                    state=Invoice.STATES.DRAFT,
                                    related_document=None)

        InvoiceFactory.create_batch(size=3,
                                    invoice_entries=[DocumentEntryFactory.create()],
                                    state=Invoice.STATES.CANCELED,
                                    related_document=None)
Esempio n. 2
0
    def handle(self, *args, **options):
        proforma = ProformaFactory.create(proforma_entries=[DocumentEntryFactory.create()],
                                          state=Proforma.STATES.ISSUED)
        proforma.create_invoice()

        invoice = InvoiceFactory.create(invoice_entries=[DocumentEntryFactory.create()],
                                        state=Invoice.STATES.ISSUED,
                                        related_document=None)
        TransactionFactory.create(state=Transaction.States.Settled,
                                  invoice=invoice,
                                  payment_method__customer=invoice.customer,
                                  proforma=None)
        InvoiceFactory.create_batch(size=3,
                                    invoice_entries=[DocumentEntryFactory.create()],
                                    state=Invoice.STATES.PAID,
                                    related_document=None)
        InvoiceFactory.create_batch(size=3,
                                    invoice_entries=[DocumentEntryFactory.create()],
                                    state=Invoice.STATES.DRAFT,
                                    related_document=None)

        InvoiceFactory.create_batch(size=3,
                                    invoice_entries=[DocumentEntryFactory.create()],
                                    state=Invoice.STATES.CANCELED,
                                    related_document=None)
    def test_proforma_total_before_tax_decimal_places(self):
        proforma_entries = DocumentEntryFactory.create_batch(3)
        proforma = ProformaFactory.create(proforma_entries=proforma_entries)

        proforma.sales_tax_percent = Decimal('20.00')

        assert self._get_decimal_places(proforma.total_before_tax) == 2
Esempio n. 4
0
    def test_create_negative_document(self):
        """ Confirm that an invoice can be issued with a negative value. """

        # 0 for easy asserting.
        customer = CustomerFactory(sales_tax_percent=0, currency='USD')

        entry = DocumentEntryFactory(quantity=1, unit_price=-150)
        invoice = InvoiceFactory.create(invoice_entries=[entry],
                                        customer=customer)
        invoice.issue()

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

        transaction = TransactionFactory.create(
            invoice=invoice,
            payment_method=payment_method,
            amount=invoice.total_in_transaction_currency,
            state=Transaction.States.Initial)

        assert invoice.transactions.count() == 1
        assert invoice.total_in_transaction_currency == -150
        assert transaction.amount == -150
Esempio n. 5
0
    def test_documents_list_case_1(self):
        """
            One proforma, one invoice, without related documents
        """
        proforma = ProformaFactory.create()
        invoice_entries = DocumentEntryFactory.create_batch(3)
        invoice = InvoiceFactory.create(invoice_entries=invoice_entries)
        invoice.issue()
        payment_method = PaymentMethodFactory.create(customer=invoice.customer)
        transaction = TransactionFactory.create(payment_method=payment_method,
                                                invoice=invoice)

        url = reverse('document-list')

        with patch('silver.utils.payments._get_jwt_token',
                   new=self._jwt_token):
            response = self.client.get(url)

        # ^ there's a bug where specifying format='json' doesn't work
        response_data = response.data

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response_data), 2)

        self.assertIn(self._get_expected_data(invoice, [transaction]),
                      response_data)

        self.assertIn(self._get_expected_data(proforma), response_data)
    def test_proforma_total_with_tax_integrity(self):
        proforma_entries = DocumentEntryFactory.create_batch(5)
        proforma = ProformaFactory.create(proforma_entries=proforma_entries)

        proforma.sales_tax_percent = Decimal('20.00')

        assert proforma.total == proforma.total_before_tax + proforma.tax_value
Esempio n. 7
0
    def test_invoice_total_with_tax_integrity(self):
        invoice_entries = DocumentEntryFactory.create_batch(5)
        invoice = InvoiceFactory.create(invoice_entries=invoice_entries)

        invoice.sales_tax_percent = Decimal('20.00')

        assert invoice.total == invoice.total_before_tax + invoice.tax_value
Esempio n. 8
0
    def test_invoice_tax_value_decimal_places(self):
        invoice_entries = DocumentEntryFactory.create_batch(3)
        invoice = InvoiceFactory.create(invoice_entries=invoice_entries)

        invoice.sales_tax_percent = Decimal('20.00')

        assert self._get_decimal_places(invoice.tax_value) == 2
Esempio n. 9
0
    def test_proforma_tax_value_decimal_places(self):
        proforma_entries = DocumentEntryFactory.create_batch(3)
        proforma = ProformaFactory.create(proforma_entries=proforma_entries)

        proforma.sales_tax_percent = Decimal('20.00')

        assert self._get_decimal_places(proforma.tax_value) == 2
Esempio n. 10
0
    def test_proforma_total_with_tax_integrity(self):
        proforma_entries = DocumentEntryFactory.create_batch(5)
        proforma = ProformaFactory.create(proforma_entries=proforma_entries)

        proforma.sales_tax_percent = Decimal('20.00')

        assert proforma.total == proforma.total_before_tax + proforma.tax_value
Esempio n. 11
0
    def test_invoice_total_with_tax_integrity(self):
        invoice_entries = DocumentEntryFactory.create_batch(5)
        invoice = InvoiceFactory.create(invoice_entries=invoice_entries)

        invoice.sales_tax_percent = Decimal('20.00')

        self.assertEqual(invoice.total, invoice.total_before_tax + invoice.tax_value)
Esempio n. 12
0
    def test_invoice_tax_value_decimal_places(self):
        invoice_entries = DocumentEntryFactory.create_batch(3)
        invoice = InvoiceFactory.create(invoice_entries=invoice_entries)

        invoice.sales_tax_percent = Decimal('20.00')

        assert self._get_decimal_places(invoice.tax_value) == 2
Esempio n. 13
0
    def test_documents_list_case_1(self):
        """
            One proforma, one invoice, without related documents
        """
        proforma = ProformaFactory.create()
        invoice_entries = DocumentEntryFactory.create_batch(3)
        invoice = InvoiceFactory.create(invoice_entries=invoice_entries)
        invoice.issue()
        payment_method = PaymentMethodFactory.create(customer=invoice.customer)
        transaction = TransactionFactory.create(payment_method=payment_method,
                                                invoice=invoice)

        url = reverse('document-list')

        with patch('silver.utils.payments._get_jwt_token',
                   new=self._jwt_token):
            response = self.client.get(url)

        # ^ there's a bug where specifying format='json' doesn't work
        response_data = response.data

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response_data), 2)

        self.assertIn(self._get_expected_data(invoice, [transaction]),
                      response_data)

        self.assertIn(self._get_expected_data(proforma), response_data)
Esempio n. 14
0
    def test_filter_min_max_amount(self):
        payment_method = PaymentMethodFactory.create(
            payment_processor=triggered_processor, )
        customer = payment_method.customer

        entry = DocumentEntryFactory(quantity=1, unit_price=100)
        invoice = InvoiceFactory.create(invoice_entries=[entry],
                                        customer=customer)
        invoice.issue()

        transaction = TransactionFactory.create(payment_method=payment_method,
                                                invoice=invoice)

        transaction_data = self._transaction_data(transaction)

        urls = [
            reverse('payment-method-transaction-list',
                    kwargs={
                        'customer_pk': customer.pk,
                        'payment_method_id': payment_method.pk
                    }),
            reverse('transaction-list', kwargs={'customer_pk': customer.pk})
        ]

        for url in urls:
            url_with_filterable_data = url + '?min_amount=10'
            url_no_output = url + '?min_amount=150'

            with patch('silver.utils.payments._get_jwt_token') as mocked_token:
                mocked_token.return_value = 'token'

                response = self.client.get(url_with_filterable_data,
                                           format='json')

                transaction.refresh_from_db()
                transaction_data['updated_at'] = response.data[0]['updated_at']

                self.assertEqual(response.status_code, status.HTTP_200_OK)
                self.assertEqual(response.data[0], transaction_data)

                response = self.client.get(url_no_output, format='json')
                self.assertEqual(response.status_code, status.HTTP_200_OK)
                self.assertEqual(response.data, [])

                url_with_filterable_data = url + '?max_amount=1050'
                url_no_output = url + '?max_amount=10'

                response = self.client.get(url_with_filterable_data,
                                           format='json')

                transaction.refresh_from_db()
                transaction_data['updated_at'] = response.data[0]['updated_at']

                self.assertEqual(response.status_code, status.HTTP_200_OK)
                self.assertEqual(response.data[0], transaction_data)

                response = self.client.get(url_no_output, format='json')
                self.assertEqual(response.status_code, status.HTTP_200_OK)
                self.assertEqual(response.data, [])
Esempio n. 15
0
    def test_add_transaction_without_currency_and_amount(self):
        customer = CustomerFactory.create()
        payment_method = PaymentMethodFactory.create(customer=customer)

        entries = DocumentEntryFactory.create_batch(2)
        proforma = ProformaFactory.create(customer=customer,
                                          state=Proforma.STATES.ISSUED,
                                          issue_date=timezone.now().date(),
                                          currency='USD',
                                          transaction_currency='RON',
                                          transaction_xe_rate=Decimal('0.25'),
                                          proforma_entries=entries)
        proforma.create_invoice()
        invoice = proforma.invoice

        valid_until = datetime.now().replace(microsecond=0) + timedelta(
            minutes=30)
        url = reverse('payment-method-transaction-list',
                      kwargs={
                          'customer_pk': customer.pk,
                          'payment_method_id': payment_method.pk
                      })

        payment_method_url = reverse('payment-method-detail',
                                     kwargs={
                                         'customer_pk': customer.pk,
                                         'payment_method_id': payment_method.id
                                     })
        invoice_url = reverse('invoice-detail', args=[invoice.pk])
        proforma_url = reverse('proforma-detail', args=[proforma.pk])
        data = {
            'payment_method':
            reverse('payment-method-detail',
                    kwargs={
                        'customer_pk': customer.pk,
                        'payment_method_id': payment_method.id
                    }),
            'valid_until':
            valid_until,
            'invoice':
            invoice_url,
            'proforma':
            proforma_url
        }

        response = self.client.post(url, format='json', data=data)

        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        self.assertEqual(response.data['payment_method'], payment_method_url)
        self.assertEqual(response.data['valid_until'][:-1],
                         valid_until.isoformat())
        self.assertEqual(response.data['can_be_consumed'], True)
        self.assertEqual(response.data['amount'],
                         unicode(Decimal('0.00') + invoice.transaction_total))
        self.assertEqual(response.data['invoice'], invoice_url)
        self.assertEqual(response.data['proforma'], proforma_url)
        self.assertEqual(response.data['currency'],
                         invoice.transaction_currency)
Esempio n. 16
0
    def test_invoice_create_storno_from_paid_state(self):
        invoice = InvoiceFactory.create(
            invoice_entries=[DocumentEntryFactory.create()])
        invoice.issue()
        invoice.pay()
        storno = invoice.create_storno()

        assert -invoice.total == storno.total != 0
        assert storno.related_document == invoice
        assert invoice.customer == storno.customer
        assert invoice.provider == storno.provider
Esempio n. 17
0
    def test_add_transaction(self):
        customer = CustomerFactory.create()
        payment_method = PaymentMethodFactory.create(customer=customer)

        entry = DocumentEntryFactory(quantity=1, unit_price=200)
        proforma = ProformaFactory.create(customer=customer,
                                          proforma_entries=[entry])
        proforma.issue()
        proforma.create_invoice()
        proforma.refresh_from_db()
        invoice = proforma.related_document

        payment_method_url = reverse('payment-method-detail',
                                     kwargs={'customer_pk': customer.pk,
                                             'payment_method_id': payment_method.id})

        invoice_url = reverse('invoice-detail', args=[invoice.pk])
        proforma_url = reverse('proforma-detail', args=[proforma.pk])

        url = reverse('payment-method-transaction-list',
                      kwargs={'customer_pk': customer.pk,
                              'payment_method_id': payment_method.pk})

        valid_until = datetime.now().replace(microsecond=0) + timedelta(minutes=30)

        currency = invoice.transaction_currency

        data = {
            'payment_method': reverse('payment-method-detail',
                                      kwargs={'customer_pk': customer.pk,
                                              'payment_method_id': payment_method.id}),
            'amount': invoice.total_in_transaction_currency,
            'invoice': invoice_url,
            'proforma': proforma_url,
            'valid_until': valid_until,
            'currency': currency,
        }

        response = self.client.post(url, format='json', data=data)

        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        self.assertEqual(response.data['payment_method'], payment_method_url)
        self.assertEqual(response.data['valid_until'][:-1], valid_until.isoformat())
        self.assertEqual(response.data['can_be_consumed'], True)
        self.assertEqual(response.data['amount'],
                         force_text(invoice.total_in_transaction_currency))
        self.assertEqual(response.data['invoice'], invoice_url)
        self.assertEqual(response.data['proforma'], proforma_url)
        self.assertEqual(response.data['currency'], currency)

        self.assertTrue(Transaction.objects.filter(uuid=response.data['id']))
    def test_no_transaction_creation_for_issued_documents_case3(self):
        """
            There are 1 pending and 1 settled transactions that together cover the document amount.
        """
        entry = DocumentEntryFactory(quantity=1, unit_price=100)
        invoice = InvoiceFactory.create(invoice_entries=[entry])
        invoice.issue()

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

        TransactionFactory.create(
            invoice=invoice,
            payment_method=payment_method,
            amount=invoice.total_in_transaction_currency / 2,
            state=Transaction.States.Settled)

        TransactionFactory.create(
            invoice=invoice,
            payment_method=payment_method,
            amount=invoice.total_in_transaction_currency / 2,
            state=Transaction.States.Pending)

        mock_execute = MagicMock()
        with patch.multiple(TriggeredProcessor,
                            execute_transaction=mock_execute):
            expected_exception = ValidationError
            expected_message = "Amount is greater than the amount that should be " \
                               "charged in order to pay the billing document."
            try:
                TransactionFactory.create(invoice=invoice,
                                          payment_method=payment_method,
                                          amount=1)

                self.fail('{} not raised.'.format(str(expected_exception)))
            except expected_exception as e:
                self.assertTrue(expected_message in str(e))

            transactions = Transaction.objects.filter(
                payment_method=payment_method,
                invoice=invoice,
            )
            self.assertEqual(len(transactions), 2)

            self.assertEqual(mock_execute.call_count, 0)
Esempio n. 19
0
    def test_create_invoice_overpayment_transaction(self):
        """ An invoice is issued, and it is paid in two transactions:
            one for half the amount, and another for well over the
            amount. """

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

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

        transaction = TransactionFactory.create(
            invoice=invoice,
            payment_method=payment_method,
            amount=invoice.total_in_transaction_currency / 2,
            state=Transaction.States.Initial)

        transaction.settle()
        transaction.save()

        assert invoice.state != Invoice.STATES.PAID

        transaction_over = TransactionFactory.create(
            invoice=invoice,
            payment_method=payment_method,
            amount=invoice.total_in_transaction_currency * 2,
            # 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

        assert invoice.total_in_transaction_currency != \
                invoice.amount_paid_in_transaction_currency

        # 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))
    def test_clone_proforma_into_draft(self):
        proforma = ProformaFactory.create()
        proforma.issue()
        proforma.pay()

        entries = DocumentEntryFactory.create_batch(3)
        proforma.proforma_entries.add(*entries)

        clone = proforma.clone_into_draft()

        assert clone.state == Proforma.STATES.DRAFT
        assert clone.paid_date is None
        assert clone.issue_date is None
        assert clone.related_document is None
        assert (clone.series != proforma.series
                or clone.number != proforma.number)
        assert clone.sales_tax_percent == proforma.sales_tax_percent
        assert clone.sales_tax_name == proforma.sales_tax_name

        assert not clone.archived_customer
        assert not clone.archived_provider
        assert clone.customer == proforma.customer
        assert clone.provider == proforma.provider

        assert clone.currency == proforma.currency
        assert clone._last_state == clone.state
        assert clone.pk != proforma.pk
        assert clone.id != proforma.id
        assert not clone.pdf

        assert clone.proforma_entries.count() == 3
        assert proforma.proforma_entries.count() == 3

        entry_fields = [
            entry.name for entry in DocumentEntry._meta.get_fields()
        ]
        for clone_entry, original_entry in zip(
                clone.proforma_entries.all(), proforma.proforma_entries.all()):
            for entry in entry_fields:
                if entry not in ('id', 'proforma', 'invoice'):
                    assert getattr(clone_entry, entry) == \
                        getattr(original_entry, entry)

        assert proforma.state == Proforma.STATES.PAID
Esempio n. 21
0
    def test_clone_proforma_into_draft(self):
        proforma = ProformaFactory.create()
        proforma.issue()
        proforma.pay()
        proforma.save()

        entries = DocumentEntryFactory.create_batch(3)
        proforma.proforma_entries.add(*entries)

        clone = proforma.clone_into_draft()

        assert clone.state == Proforma.STATES.DRAFT
        assert clone.paid_date is None
        assert clone.issue_date is None
        assert clone.invoice is None
        assert (clone.series != proforma.series or
                clone.number != proforma.number)
        assert clone.sales_tax_percent == proforma.sales_tax_percent
        assert clone.sales_tax_name == proforma.sales_tax_name

        assert not clone.archived_customer
        assert not clone.archived_provider
        assert clone.customer == proforma.customer
        assert clone.provider == proforma.provider

        assert clone.currency == proforma.currency
        assert clone._last_state == clone.state
        assert clone.pk != proforma.pk
        assert clone.id != proforma.id
        assert not clone.pdf

        assert clone.proforma_entries.count() == 3
        assert proforma.proforma_entries.count() == 3

        entry_fields = [entry.name for entry in DocumentEntry._meta.get_fields()]
        for clone_entry, original_entry in zip(clone.proforma_entries.all(),
                                               proforma.proforma_entries.all()):
            for entry in entry_fields:
                if entry not in ('id', 'proforma', 'invoice'):
                    assert getattr(clone_entry, entry) == \
                        getattr(original_entry, entry)

        assert proforma.state == Proforma.STATES.PAID
Esempio n. 22
0
    def test_proforma_total_decimal_points(self):
        proforma_entries = DocumentEntryFactory.create_batch(3)
        proforma = ProformaFactory.create(proforma_entries=proforma_entries)

        assert self._get_decimal_places(proforma.total) == 2
Esempio n. 23
0
    def test_invoice_total_decimal_points(self):
        invoice_entries = DocumentEntryFactory.create_batch(3)
        invoice = InvoiceFactory.create(invoice_entries=invoice_entries)

        assert self._get_decimal_places(invoice.total) == 2
Esempio n. 24
0
    def test_invoice_total_decimal_points(self):
        invoice_entries = DocumentEntryFactory.create_batch(3)
        invoice = InvoiceFactory.create(invoice_entries=invoice_entries)

        assert self._get_decimal_places(invoice.total) == 2
Esempio n. 25
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)
    def test_proforma_total_decimal_points(self):
        proforma_entries = DocumentEntryFactory.create_batch(3)
        proforma = ProformaFactory.create(proforma_entries=proforma_entries)

        assert self._get_decimal_places(proforma.total) == 2
Esempio n. 27
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
Esempio n. 28
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)
Esempio n. 29
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)
Esempio n. 30
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