FIX ispaid must reflect the real payment status, not the delivery workflow - #19
Pichinov-Jose wants to merge 2 commits into
Conversation
…kflow The ispaid flag was computed as "order is validated OR delivered", which says nothing about payment. Any shop that ships before payment (B2B wire transfers) had its delivered-but-unpaid orders announced as paid — and on the Dolibarr side this flag drives Invoice::setPaid(), so unpaid invoices were being classified as paid with zero payment attached. WooCommerce already knows the truth: $order->is_paid() is driven by wc_get_is_paid_statuses(), which custom status plugins feed correctly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
is_paid() reads the CURRENT status, and wc_get_is_paid_statuses() excludes 'refunded'. A refunded order is therefore announced as never paid — true of the order, false of the invoice, since the reversal is a credit note and the original invoice stays paid. get_date_paid() cannot stand alone either: WooCommerce stamps it on every transition into a paid status, even when no money moved. Measured on a 3 998-order shop — wrong announcements: 37 with the original workflow heuristic, 136 with is_paid() alone, 87 with get_date_paid() alone (81 completed orders carry no payment date), 0 with both plus the status. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Amended:
So the commit asks both and lets the status arbitrate. Wrong announcements over 3 998 orders: 37 with the original heuristic, 136 with Worth knowing for anyone running the previous version of this branch: with |
Bug
The
ispaidflag (Order + Invoice objects,StatusFlagsTrait) is computed as order is validated OR delivered — a delivery-workflow heuristic that says nothing about payment.Any shop that ships before payment (typical B2B wire-transfer flows, expressed through custom order statuses) gets its delivered-but-unpaid orders announced as paid. On the Dolibarr connector side this flag feeds
Invoice::setPaid(), so real unpaid invoices end up classified as paid with zero payment attached.Fix
Neither WooCommerce signal answers the question on its own, so the fix asks both and lets the status arbitrate.
is_paid()reads the current status, andwc_get_is_paid_statuses()excludesrefunded. A refunded order is therefore announced as never paid — true of the order, false of the invoice. A refund is a credit note: a separate document, and the original invoice stays paid. Getting this wrong pushes the Dolibarr side to reopen settled invoices.get_date_paid()reads the past, but WooCommerce stamps it on every transition into a paid status (maybe_set_date_paid()), even when no money moved — zero-value orders, and orders switched toprocessingand cancelled the same day, all carry one.Measured
On a 3 998-order shop, number of orders whose
ispaidannouncement is wrong:failedannounced paid,creditannounced unpaid)is_paid()alonerefundedorders)get_date_paid()alonecompletedorders carry no payment date, 6cancelledones do)The 81
completedorders without a payment date are whyget_date_paid()cannot replaceis_paid(), and the 136 refunds are whyis_paid()cannot stand alone.Scope
This fixes what the source announces. It cannot say how much of an invoice was actually received — a shop has one paid/unpaid state where accounting has a running balance, so a cheque schedule or a deposit is announced as paid on day one. That belongs on the consuming side: SplashSync/Dolibarr#30 (never unpay an invoice carrying real payments) and #31 (never close one the payments do not cover).
🤖 Generated with Claude Code