- Shipped
- November 11, 2026 at 10:41 AM UTC
- Author
- Kamo
- Commit
- b05a5db
RecordInvoiceController is the Invoice tab's door for any record - list, Create Invoice, read, PDF, Record Payment, Void Invoice, delivery, send, link - with only the rights, the id, the create call and the ownership check left to each record. ServiceJobInvoiceController (same routes, same rights) becomes one; OrderInvoiceController under **************** is the other (View/Create & Edit Orders). Void Invoice (POST .../{invoice}/void, the record's manage right, a reason required): InvoicingService refuses an invoice with payments; on success every customer link is stamped ended here, as the relay's void already did. Email Receipt: once an invoice is Paid, send() emails commerce.invoice_receipt (amount paid, paid date, never 'amount due') instead of refusing, with the PDF and a fresh link; the link row records email_kind INVOICE or RECEIPT and Sent and Shared shows which. The member's note is now HTML-escaped in both emails (the renderer escapes nothing). Retail order payments are the order's: Record Payment on an order's invoice is refused (409, 'use Take Payment'), and OrderInvoiceSettlement asks InvoicingService to settle the invoice after Take Payment and void it after Cancel (in **************** best-effort), and when the order's Invoice tab opens on a paid or cancelled order.
