Ejemplo n.º 1
0
 def save(self, commit=True):
     instance = self.instance
     assert isinstance(instance, Invoice)
     entries = super().save(commit)
     settlement_account = Account.objects.get(
         type__code=settings.ACCOUNT_SETTLEMENTS)
     assert isinstance(settlement_account, Account)
     for e in entries:
         if settlement_account.needs_settling(e):
             settle_assigned_invoice(instance.receivables_account, e,
                                     AccountEntry)
     return entries
Ejemplo n.º 2
0
    def test_settlements_with_assigned_invoices(self):
        print("test_settlements_with_assigned_invoices")

        e_capital = EntryType.objects.get(code=E_CAPITAL)
        e_fee = EntryType.objects.get(code=E_FEE)
        e_interest = EntryType.objects.get(code=E_INTEREST)
        e_settlement = EntryType.objects.get(code=E_SETTLEMENT)
        e_overpayment = EntryType.objects.get(code=E_OVERPAYMENT)

        # invoice: cap 100, fee 10, interest 5
        invoice_components = [
            (e_capital, 100),
            (e_fee, 10),
            (e_interest, 5),
        ]
        settlement_acc = Account.objects.create(type=AccountType.objects.get(
            code=ACCOUNT_SETTLEMENTS))
        receivables_acc = Account.objects.create(type=AccountType.objects.get(
            code=ACCOUNT_RECEIVABLES))
        invoice = Invoice.objects.create(due_date=now())
        assert isinstance(receivables_acc, Account)
        assert isinstance(settlement_acc, Account)
        assert isinstance(invoice, Invoice)
        for ae_type, amt in invoice_components:
            AccountEntry.objects.create(account=receivables_acc,
                                        source_invoice=invoice,
                                        type=ae_type,
                                        amount=Decimal(amt))

        # paybacks
        # order (see setUp): cap, fee, interest
        paybacks_and_unpaid_components = [
            (None, 115),
            (20, 95),
            (80, 15),
            (10, 5),
            (5, 0),
        ]
        AccountEntry.objects.distinct("type").order_by("type__payback_order")
        for payback, unpaid in paybacks_and_unpaid_components:
            if payback:
                payback = AccountEntry.objects.create(account=settlement_acc,
                                                      settled_invoice=invoice,
                                                      type=e_settlement,
                                                      amount=Decimal(payback))
                settle_assigned_invoice(receivables_acc, payback, AccountEntry)
            bal = invoice.get_balance(invoice.receivables_account)
            self.assertEqual(bal, unpaid)
Ejemplo n.º 3
0
    def test_credit_note(self):
        print("test_credit_note")

        # create invoice
        e_capital = EntryType.objects.get(code=E_CAPITAL)
        e_fee = EntryType.objects.get(code=E_FEE)
        invoice_components = [
            (e_capital, Decimal(100)),
            (e_fee, Decimal(10)),
        ]
        settlement_acc = Account.objects.create(type=AccountType.objects.get(
            code=ACCOUNT_SETTLEMENTS))
        receivables_acc = Account.objects.create(type=AccountType.objects.get(
            code=ACCOUNT_RECEIVABLES))
        invoice = Invoice.objects.create(due_date=now())
        assert isinstance(receivables_acc, Account)
        assert isinstance(settlement_acc, Account)
        assert isinstance(invoice, Invoice)
        for ae_type, amt in invoice_components:
            AccountEntry.objects.create(account=receivables_acc,
                                        source_invoice=invoice,
                                        type=ae_type,
                                        amount=amt)

        invoice.update_cached_fields()

        # ensure balances
        self.assertEqual(invoice.get_unpaid_amount(), Decimal("110.00"))
        self.assertEqual(invoice.get_paid_amount(), Decimal("0.00"))
        self.assertEqual(invoice.get_amount(), Decimal("110.00"))
        self.assertEqual(invoice.get_overpaid_amount(), Decimal("0.00"))

        # create credit note
        e_capital = EntryType.objects.get(code=E_CAPITAL)
        invoice_components = [
            (e_capital, Decimal(-110)),
        ]
        credit_note = Invoice.objects.create(due_date=now(),
                                             type=INVOICE_CREDIT_NOTE)
        assert isinstance(credit_note, Invoice)
        for ae_type, amt in invoice_components:
            AccountEntry.objects.create(account=receivables_acc,
                                        source_invoice=credit_note,
                                        type=ae_type,
                                        amount=amt)

        credit_note.update_cached_fields()

        # ensure balances
        self.assertEqual(credit_note.get_unpaid_amount(), Decimal("-110.00"))
        self.assertEqual(credit_note.get_paid_amount(), Decimal("0.00"))
        self.assertEqual(credit_note.get_amount(), Decimal("-110.00"))
        self.assertEqual(credit_note.get_overpaid_amount(), Decimal("0.00"))

        # settle credit note
        e_credit_note = EntryType.objects.get(
            code=E_CREDIT_NOTE_RECONCILIATION)
        pmts = settle_credit_note(credit_note,
                                  invoice,
                                  AccountEntry,
                                  settlement_acc,
                                  entry_type=e_credit_note)
        for pmt in pmts:
            settle_assigned_invoice(receivables_acc, pmt, AccountEntry)

        # ensure balances
        self.assertEqual(credit_note.get_unpaid_amount(), Decimal("0.00"))
        self.assertEqual(credit_note.get_paid_amount(), Decimal("-110.00"))
        self.assertEqual(credit_note.get_amount(), Decimal("-110.00"))
        self.assertEqual(credit_note.get_overpaid_amount(), Decimal("0.00"))
        self.assertEqual(invoice.get_unpaid_amount(), Decimal("0.00"))
        self.assertEqual(invoice.get_paid_amount(), Decimal("110.00"))
        self.assertEqual(invoice.get_amount(), Decimal("110.00"))
        self.assertEqual(invoice.get_overpaid_amount(), Decimal("0.00"))
Ejemplo n.º 4
0
    def test_invoice(self):
        print("test_invoice")
        settlements = create_account_by_type(ACCOUNT_SETTLEMENTS)
        receivables_acc = create_account_by_type(ACCOUNT_RECEIVABLES)
        assert isinstance(settlements, Account)

        # create invoices
        t = parse_datetime("2016-05-05")
        amounts = [
            Decimal("120.00"),
            Decimal("100.00"),
            Decimal("50.00"),
            Decimal("40.00"),
        ]
        n = len(amounts)
        times = [add_month(t, i) for i in range(n)]
        invoices = []
        for t, amount in zip(times, amounts):
            invoice = Invoice(due_date=t)
            invoice.full_clean()
            invoice.save()
            AccountEntry.objects.create(
                account=receivables_acc,
                source_invoice=invoice,
                type=EntryType.objects.get(code=E_RENT),
                amount=amount)
            invoice.update_cached_fields()
            self.assertEqual(invoice.unpaid_amount, amount)
            invoices.append(invoice)
            # print(invoice)
        unpaid_invoices = [i for i in invoices]

        # create payments
        payment_ops = [
            (None, [
                Decimal("120.00"),
                Decimal("100.00"),
                Decimal("50.00"),
                Decimal("40.00")
            ]),
            (Decimal("50.00"), [
                Decimal("70.00"),
                Decimal("100.00"),
                Decimal("50.00"),
                Decimal("40.00")
            ]),
            (Decimal("70.50"), [
                Decimal("00.00"),
                Decimal("100.00"),
                Decimal("50.00"),
                Decimal("40.00")
            ]),
            (Decimal("100.00"), [
                Decimal("00.00"),
                Decimal("00.00"),
                Decimal("50.00"),
                Decimal("40.00")
            ]),
            (Decimal("100.00"), [
                Decimal("00.00"),
                Decimal("00.00"),
                Decimal("00.00"),
                Decimal("40.00")
            ]),
        ]
        for j in range(len(payment_ops)):
            print("test_invoice: Payment op test", j)
            for i in range(n):
                inv = invoices[i]
                assert isinstance(inv, Invoice)
            paid_amount, unpaid_amounts = payment_ops[j]
            if paid_amount is not None:
                p = AccountEntry.objects.create(
                    account=settlements,
                    settled_invoice=unpaid_invoices[0],
                    amount=paid_amount,
                    type=EntryType.objects.get(code=E_MANUAL_SETTLEMENT),
                )
                settle_assigned_invoice(receivables_acc, p, AccountEntry)
                if unpaid_invoices[0].is_paid:
                    unpaid_invoices = unpaid_invoices[1:]
            for i in range(n):
                inv = invoices[i]
                assert isinstance(inv, Invoice)
            for i in range(n):
                paid_amount_real = invoices[i]
                unpaid_amount_real = invoices[i].get_unpaid_amount()
                unpaid_amount_ref = unpaid_amounts[i]
                print(
                    "checking invoice {} payment status after payment op {} (real {}, expected {})"
                    .format(i, j, unpaid_amount_real, unpaid_amount_ref))
                self.assertEqual(unpaid_amount_real, unpaid_amount_ref,
                                 "[{}][{}]".format(j, i))

        # create another acc set
        settlements = create_account_by_type(ACCOUNT_SETTLEMENTS)
        assert isinstance(settlements, Account)
        receivables_acc = create_account_by_type(ACCOUNT_RECEIVABLES)
        assert isinstance(receivables_acc, Account)

        # create invoices
        t = parse_datetime("2016-05-05")
        amounts = [
            Decimal("120.00"),
            Decimal("100.00"),
            Decimal("50.00"),
            Decimal("40.00")
        ]
        n = len(amounts)
        times = [add_month(t, i) for i in range(n)]
        invoices = []
        for t, amount in zip(times, amounts):
            invoice = Invoice(due_date=t)
            invoice.full_clean()
            invoice.save()
            AccountEntry.objects.create(
                account=receivables_acc,
                source_invoice=invoice,
                type=EntryType.objects.get(code=E_RENT),
                amount=amount)
            invoice.update_cached_fields()
            self.assertEqual(invoice.unpaid_amount, amount)
            invoices.append(invoice)
            print("invoice created", invoice)
        unpaid_invoices = [i for i in invoices]

        # create payments:
        # paid_amount, unpaid_amounts (after payment)
        payment_ops = [
            (None, [
                Decimal("120.00"),
                Decimal("100.00"),
                Decimal("50.00"),
                Decimal("40.00")
            ]),
            (Decimal("250.00"), [
                Decimal("0.00"),
                Decimal("100.00"),
                Decimal("50.00"),
                Decimal("40.00")
            ]),
        ]
        for j in range(len(payment_ops)):
            paid_amount, unpaid_amounts = payment_ops[j]
            if paid_amount is not None and paid_amount > Decimal("0.00"):
                invoice = unpaid_invoices[0]
                print("Targeting settlement amount", paid_amount, "to invoice",
                      invoice, "invoice.amount", invoice.amount)
                p = AccountEntry.objects.create(
                    account=settlements,
                    amount=paid_amount,
                    settled_invoice=invoice,
                    type=EntryType.objects.get(code=E_MANUAL_SETTLEMENT),
                )
                settle_assigned_invoice(receivables_acc, p, AccountEntry)
                if invoice.is_paid:
                    unpaid_invoices = unpaid_invoices[1:]
                    print("invoice paid, now left", unpaid_invoices)
            for i in range(n):
                unpaid_amount_real = invoices[i].get_unpaid_amount()
                unpaid_amount_ref = unpaid_amounts[i]
                self.assertEqual(unpaid_amount_real, unpaid_amount_ref,
                                 "[{}][{}]".format(j, i))

        # check that the first payment has E_RENT 120
        inv = invoices[0]
        assert isinstance(inv, Invoice)
        es = inv.receivables.order_by("id")
        self.assertEqual(es[0].amount, Decimal("120.00"))
        self.assertEqual(es[1].amount, Decimal("-120.00"))
        self.assertIsNotNone(es[1].parent)
        self.assertTrue(es[1].parent.type.is_settlement)
        self.assertEqual(es[1].parent.amount, Decimal("250.00"))