Skip to content

FIX never close an invoice the recorded payments do not cover - #31

Open
Pichinov-Jose wants to merge 1 commit into
SplashSync:2.0from
Pichinov-Jose:fix/never-close-uncovered-invoice
Open

Pichinov-Jose wants to merge 1 commit into
SplashSync:2.0from
Pichinov-Jose:fix/never-close-uncovered-invoice

Conversation

@Pichinov-Jose

Copy link
Copy Markdown

Bug

setPaidFlag() (Invoice MainTrait) closes the invoice as soon as the source announces paid, without checking that a single cent is recorded against it. The source's opinion is allowed to extinguish a receivable on its own.

A shop has one paid/unpaid state where accounting has a running balance. A schedule of cheques, a deposit, a settlement part vouchers part transfer — all are announced as paid the day the arrangement is agreed, while the invoice is only extinguished when the last movement lands. The connector closes it on day one.

Combined with a source that mis-reports its paid flag (see SplashSync/Wordpress#19), invoices are closed with nothing behind them at all.

Observed in production on one shop: 3 invoices closed by the splashsync user with no payment covering them, 704.85 € of receivables that disappeared from the books while still owed — one of them 612.85 € with zero recorded against it.

An invoice closed early is also an encaissement that will never be declared: under the French e-invoicing regime each payment is reported with its own date.

Fix

Before closing, count what the invoice already carries — payments, credit notes and deposits — and leave it open when that does not cover the total, logging a warning. Credit notes and deposits count, because an invoice closed by a payment plus a discount is settled just as surely as one closed by payments alone.

A human may still close a residue by hand in Dolibarr; writing off a few cents is a decision. A connector may not.

This is the symmetric half of #30 (never unpay an invoice that carries real payments): together they say that the money recorded in Dolibarr decides, in both directions. The two touch different branches of the same if/else and merge cleanly in either order.

🤖 Generated with Claude Code

setPaidFlag() closes the invoice as soon as the source announces "paid",
without checking that a single cent is recorded against it. A shop has one
paid/unpaid state where accounting has a running balance, so a cheque
schedule, a deposit or a part-voucher part-transfer settlement is announced
as paid the day the arrangement is agreed, while the invoice is only
extinguished when the last movement lands.

Count what the invoice already carries — payments, credit notes and
deposits — and leave it open when that does not cover the total, logging a
warning. Mirrors the philosophy of the payments-list protections: recorded
money outranks the source's opinion.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant