This set of classes models the part of a finance application that models payments and invoices. It is assumed that invoices are raised before payments are received, and so overpayments will be rejected. A number of cases need to be handled:
- One payment pays off one invoice
- One payment pays off multiple invoices
- Multiple payments pay off one invoice
Given the combination of these factors, the classes have been built to account for edge-cases like a payment paying off one whole invoice, and then part of another.
In reality we would be using a relational database to model these items, with an ORM in
between. Classes would have ids, etc, and PaymentInvoice
would be a join table.
Given that we would be using a database, get_balance
would be implemented via queries,
rather than a series of loops.
Additionally, we would use the transactional nature of the database to revert a series
of updates to payments that result in an error (chiefly at the moment, the OverpaymentException
). As the code stands it will make an unsafe series of edits that can't be reverted. In code this code be addressed by modeling the series of edits as events, and then later applying this series once we know it's safe.
To execute the test suite run pytest test_finance.py
pytest
has been used as it is quite powerful. A series of test cases have been set up
via a custom dataclass so as to keep the self-documenting ids alongside the test cases
that they refer to, while still being able to use pytest.mark.parametrize
. This can
also be done with the more expansive pytest-cases
library.
Hypothesis has been used in order to make the tests more robust.