Skip to content

Never rewrite the lines of a validated invoice - #40

Open
Pichinov-Jose wants to merge 1 commit into
SplashSync:2.0from
Pichinov-Jose:fix/lock-lines-of-validated-invoice
Open

Pichinov-Jose wants to merge 1 commit into
SplashSync:2.0from
Pichinov-Jose:fix/lock-lines-of-validated-invoice

Conversation

@Pichinov-Jose

Copy link
Copy Markdown

Bug

BaseItemsTrait::setItemsFields() writes invoice lines with FactureLigne::update() / insert() and then calls Facture::update_price(). Unlike Facture::updateline() / addline(), none of these check the invoice status.

As a result, when a source order changes after invoicing, its lines are written into the validated invoice whenever the invoice does not go back to draft first. That happens when the source status keeps it validated or paid, or when the back-to-draft is refused, as proposed in #38.

The amounts change under the same reference. Nothing reaches the unalterable log, because BILL_MODIFY is not a logged event. The only trace is an agenda event AC_BILL_MODIFY by the Splash user.

Seen in production (Dolibarr 23, Splash 2.23.3, WooCommerce, blockedlog active):

  • An invoice was validated at 950.00 and paid by card plus bank transfer.
  • A 10% discount was typed on two course lines of the WooCommerce order.
  • On the next sync, the two invoice lines became 225.00 instead of 250.00, and the invoice total became 900.00 under the same reference.
  • The unalterable log still shows 950.00 as the last validated amount for that invoice.

With the unalterable log active — mandatory in France — a validated invoice must never be edited. A change made in the source after invoicing must become a credit note.

Fix

  • loadPayments() records the invoice status as it stands in database, before the request writes anything (invoiceStatusAtLoad). It reads facture or facture_fourn, so it works for customer invoices, credit notes and supplier invoices.
  • setItemsFields() keeps the lines as issued, and ignores the source's lines with a Splash warning, when the invoice:
    • was already validated when loaded, and
    • is still not a draft when its lines arrive.

What does not change:

  • Invoices created by the request are not locked, even if the same request validates them before writing their lines.
  • Invoices that did go back to draft in the same request are updated exactly as before.
  • Orders, quotes and supplier orders do not carry the property and are never affected.

Relation to the other PRs:

Tests

Real invoices and orders, through load() then setItemsFields("lines", …) with a 10% discount added on one line, in a rolled-back transaction with Splash triggers disabled:

Case Before After
Validated paid invoice lines and total rewritten kept
Validated invoice sent back to draft in the request rewritten rewritten (unchanged)
Draft invoice rewritten rewritten (unchanged)
Invoice not loaded by the request (creation), validated in memory rewritten rewritten (unchanged)
Validated order rewritten rewritten (not affected)

Deployed in production on the instance where the issue was found. Replaying the WooCommerce lines above against the restored invoice leaves it at 950.00.

🤖 Generated with Claude Code

Invoice lines are written with FactureLigne::update() / insert() and
Facture::update_price(), which do not check the invoice status the way
Facture::updateline() / addline() do. When the invoice does not go back to
draft first, the source's lines land in the validated invoice: amounts
change under the same reference, and nothing reaches the unalterable log
because BILL_MODIFY is not a logged event.

The invoice status is captured when payments are loaded, before the request
writes anything. An invoice that was already validated when loaded, and is
still not a draft when its lines arrive, keeps them as issued; the source's
lines are ignored with a warning. Invoices created by the request, invoices
that did go back to draft, orders, quotes and supplier orders are unchanged.

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