Repository: SplashSync/Wordpress
Plugin version: 2.1.0 (code identical at current master HEAD)
WooCommerce: 11.0.1 · Target node: Dolibarr module 2.23.3
Type: feature gap
Summary
WooCommerce records refunds as first-class objects — one shop_order_refund post per refund,
carrying its own amount, date, reason, author and gateway reference. The connector ignores them
entirely. There is no CreditNote object type, and no hook on the refund lifecycle, so a refund
never reaches the target node in any form.
The result is an accounting divergence that grows silently: the shop knows money went back, the ERP
does not, and the source invoice stays settled at its full amount forever.
What the connector exposes today
src/Objects/ -> Address.php Invoice.php Order.php Page.php Post.php Product.php ThirdParty.php
No CreditNote. And no refund hook anywhere in the plugin:
grep -rniE "woocommerce_(order_refunded|refund_created|refund_deleted)" src/ -> no match
refund appears in exactly four places, all of them about the order status, never about the
refund object:
src/Core/InvoiceStatusManager.php:36 "cancelled", "refunded", "trash",
src/Core/OrderStatusManager.php:39 OrderStatus::CANCELED => array("cancelled", "refunded", "trash"),
src/Objects/Order/PaymentsTrait.php:100 if ($this->object->get_date_paid() && ("refunded" != $this->object->get_status()))
src/Objects/Order/StatusTrait.php:180 case 'refunded':
Why the status mapping does not cover it
That mapping only fires on a full refund, which moves the order to wc-refunded. A partial
refund leaves the order in completed or processing — WooCommerce's intended behaviour — so
nothing whatsoever changes in what Splash exports. The order is committed again with the same
totals, and the target sees no difference.
Even for a full refund, mapping to OrderStatus::CANCELED tells the ERP the order was cancelled, not
that a refund was issued for a given amount on a given date. Those are different accounting events
and only one of them is true.
Measured on a production install
|
|
shop_order_refund posts |
448 |
orders carrying _stripe_refund_id |
359 |
| refunds visible to the target node |
0 |
Cross-checking one season against the Dolibarr node: 34 refunded orders, 2 991,20 €, all present
in WooCommerce, none of them present in the ERP — no credit note, no negative payment, no bank
movement. All 34 source invoices are still paye = 1 at their full amount.
The data is all there
Per shop_order_refund post:
| Meta |
Content |
_refund_amount |
refunded amount |
_refund_reason |
free-text reason |
_refunded_by |
user id who issued it |
_refunded_payment |
1 if it went through the gateway, empty if recorded manually |
post_date |
when |
post_parent |
the order it belongs to |
And on the parent order, for Stripe: _stripe_refund_id (re_… / pyr_…) and _transaction_id
(ch_… / py_…).
_refunded_payment is worth passing through as-is: it is the difference between "the money left" and
"someone typed a number into the admin", and the target cannot guess it.
WooCommerce also exposes this natively — $order->get_refunds(), WC_Order_Refund::get_amount(),
get_reason(), get_refunded_by() — so no direct meta reads are needed.
The other half of the chain already exists
SplashSync/Dolibarr ships a CreditNote object (src/Objects/CreditNote.php), whose CRUDTrait
sets type = Facture::TYPE_CREDIT_NOTE on create and whose trigger dispatches credit notes back as
CreditNote. The target is ready to receive them. Only the source side is missing.
Suggested implementation
- A
CreditNote object type, listing shop_order_refund posts, with the refund amount, date,
reason, gateway reference, and an object link to the source order or invoice.
- Hooks on the refund lifecycle —
woocommerce_order_refunded and woocommerce_refund_deleted
— committing CreditNote / SPL_A_CREATE and SPL_A_DELETE. Both fire reliably in WooCommerce for
admin, REST and gateway-initiated refunds.
- Line detail where it exists. WooCommerce can attach line items to a refund, but rarely does:
on this install, 4 line items across 448 refunds. So a single-line credit note at the refund
amount must be the supported case, with line detail as a bonus rather than a requirement.
Related
Linking the resulting credit note to the right invoice requires fk_facture_source on the Dolibarr
side, which is not exposed either — filed separately on SplashSync/Dolibarr.
Repository: SplashSync/Wordpress
Plugin version: 2.1.0 (code identical at current
masterHEAD)WooCommerce: 11.0.1 · Target node: Dolibarr module 2.23.3
Type: feature gap
Summary
WooCommerce records refunds as first-class objects — one
shop_order_refundpost per refund,carrying its own amount, date, reason, author and gateway reference. The connector ignores them
entirely. There is no
CreditNoteobject type, and no hook on the refund lifecycle, so a refundnever reaches the target node in any form.
The result is an accounting divergence that grows silently: the shop knows money went back, the ERP
does not, and the source invoice stays settled at its full amount forever.
What the connector exposes today
No
CreditNote. And no refund hook anywhere in the plugin:refundappears in exactly four places, all of them about the order status, never about therefund object:
Why the status mapping does not cover it
That mapping only fires on a full refund, which moves the order to
wc-refunded. A partialrefund leaves the order in
completedorprocessing— WooCommerce's intended behaviour — sonothing whatsoever changes in what Splash exports. The order is committed again with the same
totals, and the target sees no difference.
Even for a full refund, mapping to
OrderStatus::CANCELEDtells the ERP the order was cancelled, notthat a refund was issued for a given amount on a given date. Those are different accounting events
and only one of them is true.
Measured on a production install
shop_order_refundposts_stripe_refund_idCross-checking one season against the Dolibarr node: 34 refunded orders, 2 991,20 €, all present
in WooCommerce, none of them present in the ERP — no credit note, no negative payment, no bank
movement. All 34 source invoices are still
paye = 1at their full amount.The data is all there
Per
shop_order_refundpost:_refund_amount_refund_reason_refunded_by_refunded_payment1if it went through the gateway, empty if recorded manuallypost_datepost_parentAnd on the parent order, for Stripe:
_stripe_refund_id(re_…/pyr_…) and_transaction_id(
ch_…/py_…)._refunded_paymentis worth passing through as-is: it is the difference between "the money left" and"someone typed a number into the admin", and the target cannot guess it.
WooCommerce also exposes this natively —
$order->get_refunds(),WC_Order_Refund::get_amount(),get_reason(),get_refunded_by()— so no direct meta reads are needed.The other half of the chain already exists
SplashSync/Dolibarrships aCreditNoteobject (src/Objects/CreditNote.php), whoseCRUDTraitsets
type = Facture::TYPE_CREDIT_NOTEon create and whose trigger dispatches credit notes back asCreditNote. The target is ready to receive them. Only the source side is missing.Suggested implementation
CreditNoteobject type, listingshop_order_refundposts, with the refund amount, date,reason, gateway reference, and an object link to the source order or invoice.
woocommerce_order_refundedandwoocommerce_refund_deleted— committing
CreditNote / SPL_A_CREATEandSPL_A_DELETE. Both fire reliably in WooCommerce foradmin, REST and gateway-initiated refunds.
on this install, 4 line items across 448 refunds. So a single-line credit note at the refund
amount must be the supported case, with line detail as a bonus rather than a requirement.
Related
Linking the resulting credit note to the right invoice requires
fk_facture_sourceon the Dolibarrside, which is not exposed either — filed separately on
SplashSync/Dolibarr.