Amirali YaghoutiSenior Software Engineer

woocommerce Case study

A2 Order Fix Box: Order Replacement and Price Fix Tools

A watch arrives damaged and is replaced with a different reference. A customer pays part of the bill in cash at the counter. A price was entered wrong. WooCommerce has no safe path for any of these once an order is paid, so I built A2 Order Fix Box: a metabox on the order edit screen of the Javaherian Gallery store where staff swap items, add a shipping line or correct a price without touching the payment gateway or the order status.

The business problem

In a watch and jewellery store, orders change after payment more often than you would expect. A customer picks a different model, a line total turns out wrong, or an extra courier trip is needed. Editing a paid order in WooCommerce is possible and dangerous: the admin lets you change line items, but nothing records what the order looked like before, there is no undo, and any change that touches the payment total risks disagreeing with what the gateway actually captured. Hand edits produced recalculated totals nobody could trace, and any slip risked corrupting the payment record. The team needed to make these three corrections routinely, and I needed a repair tool that leaves the gateway and the order status completely alone.

What I delivered

  • a2-order-replacement-box.php, a 3,294-line metabox on the order edit screen with three operations: replace an item with one or more products, add a shipping line, or correct the line total of an existing item.
  • A full order snapshot in _a2_fix_snapshot_v1 taken before any change, with one-click Undo handled by wp_ajax_a2_fix_undo that restores it, so a mistaken correction is reversed rather than repaired by hand a second time.
  • A split-payment record that separates what came through the gateway from card-to-card and other off-gateway receipts, stored as breakdown rows in _a2_fix_offline_rows_json, with the remainder split between what is owed to the gateway and what came in by card transfer.
  • A history log in _a2_fix_history with a human-readable Persian summary per fix, plus an order note per action, so the sequence of corrections is readable months later.
  • A fixed-order badge, column and filter view on both the legacy shop_order list and the HPOS wc-orders table, so corrected orders are findable in bulk rather than one at a time.
  • Internal refund registration meta, so money returned outside the gateway is recorded on the order instead of in someone's memory.
  • A hard rule, stated in the plugin's own name: order status and payment gateway are never modified.

Technical approach

  • Snapshot before mutate is the invariant the whole tool is built on. Nothing changes an order until the previous state is stored.
  • Every action runs through admin-ajax behind a nonce and a capability gate (manage_woocommerce or edit_shop_orders).
  • A calculation step (wp_ajax_a2_fix_calc) previews old total, new total and the signed difference before anything is applied.
  • The gateway boundary is a deliberate refusal. The tool corrects what the shop owes and what it received, and never reconciles that back into the payment record, because the gateway is the authority on what was actually captured. It never transitions status either; it only edits items, fees and its own meta keys under the _a2_fix_ prefix.
  • Off-gateway receipts are recorded as their own category rather than folded into the order total, so the accounting stays separable afterwards.
  • Numeric inputs normalize Persian and Arabic digits and strip thousand separators before parsing, because staff paste amounts from invoices.
  • The audit trail is a side effect of using the tool, not a step someone has to remember: each applied fix appends to the history log and writes an order note.
  • The public showcase repo generalizes the same pattern: admin-only controllers with capability checks, operation logic in services rather than UI handlers, operational flags stored apart from payment data, screen-scoped asset loading and a PHP syntax check over the samples. It is a showcase, not a production package.

Result and evidence

The module is running on the live store admin. I have not formally measured the time saved. What is verified: every write is gated by a nonce and a capability check, a snapshot exists before any mutation and Undo restores it, off-gateway receipts sit in their own rows, and fixed orders show up on both order tables. The practical evidence is that the three routine corrections became routine. Staff repair exceptional orders inside one box with an undo path instead of through raw order edits, and the order history now explains itself, which is what made the accounting reconciliation tractable.

Commercial value

This is where operations meets accounting. Order repairs used to be a task only I could do safely; now sales staff handle them. Corrections were always going to happen in jewellery retail; the question was whether they would leave a trail. Now they do, and the accounting picture of each corrected order stays coherent for whoever reads it later.

implementation-brief.readme

Readable implementation brief

implementation_brief {
  project: "A2 Order Fix Box"
  stack: "WordPress MU plugin, WooCommerce, admin-ajax"
  module: "a2-order-replacement-box.php (3,294 lines)"
  operations: "replace item (1..n products), extra shipping line,
               price correction on the same item"
  ajax: "a2_fix_calc, a2_fix_apply, a2_fix_rebuild_totals, a2_fix_undo"
  meta: "_a2_fix_snapshot_v1, _a2_fix_history, _a2_fix_offline_rows_json"
  invariant: "snapshot before mutate; undo restores it"
  never: "no gateway calls, no status transitions"
  accounting: "off-gateway receipts recorded separately;
               remainder split gateway vs card transfer"
  audit: "history meta + order note per action, nonce + capability gated"
  discovery: "fixed badge, column and filter on shop_order and HPOS wc-orders"
  showcase: "github.com/shiny-a2/a2-woocommerce-admin-ops-toolkit"
  status: "in production on the store admin"
}

What this project shows

This is back-office engineering next to real money, and the interesting part is not the UI. The most important line in this project is the one about not touching the gateway. It would have been easy to make the numbers look tidy by adjusting the payment record, and that is exactly the change that makes reconciliation impossible later. So the tool is defined by what it must never do: no gateway calls, no status transitions, no silent edits.

I scoped the write surface to a set of prefixed meta keys and made every mutation reversible. Snapshot and undo were not a feature request; they were the condition under which I was willing to give staff a tool that edits paid orders. That is how I build anything that sits beside payment data.