Problem statement
Design the object model and core APIs for an invoice generator a freelancer or small business uses to assemble line items, apply discounts and taxes, issue an immutable invoice, and track payment against it.
Operating context. Single tenant, in-process, single currency. An invoice carries an issuer, a customer, dates, and a list of line items (description, quantity, unit price). Discounts apply at line or invoice level (percentage or fixed); taxes apply per line as a rate (e.g. a GST or VAT band). An invoice is a draft that can be edited freely, then it is issued: it receives a unique sequential number, its contents freeze, and it becomes immutable. Payments (full or partial) are recorded against an issued invoice; a mistake is corrected only by issuing a credit note that reverses part or all of it.
Out of scope. PDF rendering and email delivery, a persistence layer, payment-gateway integration, multi-currency and FX, and posting entries into a general ledger.
What to produce. The class hierarchy (Invoice, LineItem, Money value object, discount and tax policies, the invoice-number sequence, CreditNote), the public APIs each exposes, the computation order for discount versus tax, and the invoice state machine (draft, issued, partially paid, paid, void). Be explicit about how issuance makes the invoice immutable and how the number sequence stays unique and gap-free under concurrent issuance.
Must do 5
Functional requirements
- Add, update, and remove line items on a draft invoice, each with a description, quantity, and unit price.
- Apply line-level and invoice-level discounts and per-line taxes, then compute subtotal, tax total, and grand total.
- Assign a unique sequential number and freeze the invoice's contents when it is issued.
- Record full or partial payments against an issued invoice and update its paid and outstanding amounts.
- Issue a credit note that reverses all or part of an already-issued invoice without mutating the original.