fix(SEPA Payment Order): avoid overpaying for PIs with relevant returns#364
fix(SEPA Payment Order): avoid overpaying for PIs with relevant returns#364PatrickDEissler wants to merge 1 commit into
Conversation
Greptile SummaryThis PR fixes SEPA Payment Order overpayment when a Purchase Invoice has associated return PIs that reduce
Confidence Score: 3/5The fix solves the stated single-row case but leaves a logic gap for invoices with multiple payment schedule rows that could still result in the same overpayment it aims to prevent. The min(scheduled_payment.outstanding, doc.outstanding_amount) cap is applied independently to each payment schedule row. Because doc.outstanding_amount is a document-level total rather than a per-row budget, a return smaller than any individual row leaves all rows uncapped while their combined total still exceeds the actual outstanding. Installment-payment invoices (two or more rows) hit this path, so the issue is not confined to an exotic configuration. banking/custom/purchase_invoice.py — specifically the get_sepa_payment_amount function and how its result interacts with multi-row payment schedules in make_sepa_payment_order. Important Files Changed
|
| return 0 | ||
|
|
||
| # Also consider doc.outstanding_amount to avoid overpaying (typical case: Return PIs reduced the outstanding amount) | ||
| outstanding = min(scheduled_payment.outstanding, doc.outstanding_amount) |
There was a problem hiding this comment.
Multi-row payment schedule: cap is per-row, not per-document
When a Purchase Invoice has multiple payment schedule rows (installment payments), this cap can fail to prevent overpayment. doc.outstanding_amount is the total remaining balance for the entire document, not for an individual row. If the return amount is smaller than any individual row's outstanding, the min() leaves every row unchanged, yet their sum still exceeds doc.outstanding_amount.
Concrete example: two rows with outstanding = [15_000, 24_000], a 10 000 return leaves doc.outstanding_amount = 29_000. min(15_000, 29_000) and min(24_000, 29_000) are both uncapped, so the total paid is 39 000 instead of 29 000.
A correct cap would subtract the outstanding of the other rows from doc.outstanding_amount before capping, or use a proportional allocation across rows.
Case
update_outstanding_for_selfdeactivated) -> Result: The Purchase Invoice has a reducedoutstanding_amount.See example of a Purchase Invoice 1:

-> Previous outstanding of 39.000€ (see
grand_total) was reduced by 10k (seeoutstanding_amount)Before
Cause
Only
outstanding_amountfrompayment_scheduleis used to determine the default payment amount.Problem is, that this field is not (and can not be) updated by returns.
After fix
Also for discounted payments the minimum will be considered as base (before discounting).