Boomerang for Craft CMS

Lite free · Pro $129

The whole return, not just the refund

Craft Commerce can refund a payment. That is all it can do about a return. Everything else — the customer asking, the merchant deciding, the goods coming back, the stock going back on the shelf, the money going back as cash, credit or replacement goods — is left to a shared inbox and a spreadsheet, or to a developer building the same half of it again. Boomerang is the loop around the refund.

Boomerang

One verdict, everywhere

Whether an order can be returned is decided in exactly one place, and the portal, the control panel, the console and your templates all read the same answer — so the sentence a customer is refused with is the one the merchant sees on the RMA.

twig
{# Can this order be returned, and which of it? #}
{% set verdict = craft.boomerang.eligibility(order) %}

{% if verdict.isEligible %}
    <a href="{{ craft.boomerang.portalUrl }}">Start a return</a>
    <p>{{ verdict.daysRemaining }} days left</p>
{% else %}
    {# The same sentence the merchant sees, not a second implementation of it #}
    <p>{{ verdict.firstMessage }}</p>
{% endif %}

{# The signed-in customer's returns and balance #}
{% for return in craft.boomerang.myReturns() %}
    {{ return.reference }} — {{ return.state.name }}
{% endfor %}

<p>Store credit: {{ craft.boomerang.balance|commerceCurrency(cart.currency) }}</p>

{# Returns are elements, so the usual query methods work #}
{% set open = craft.boomerang.returns().isOpen(true).all() %}

Features

Everything between a customer wanting to send something back and the money or the goods moving.

A customer returns portal

At /returns on the day you install it. A signed-in customer sees their own orders; a guest looks one up by number and email together — never the number alone.

  • A wrong number and a wrong email get the same sentence, so the form is not an order-number oracle
  • Rate limited per IP per hour, and status pages sit behind a 32-character token compared in constant time
  • Every page is an ordinary Twig template you can copy out and restyle, without the URLs moving

States are yours to name

Requested → approved → received → resolved is the shape, not the vocabulary. The plugin reads each state's kind, so renaming one is a rename and not a bug.

  • Each state can email the customer, restock the goods, carry out the resolution and offer a label
  • Leave a transition list empty for “anywhere” — the escape hatch a returns desk needs on a Friday
  • An append-only history of who moved it, when, and everything the move did

Store credit that spends

A Commerce payment method with its own gateway, not a discount that lies about the subtotal. The customer sees “Store credit — $40.00” beside the card at checkout.

  • Partial payment is the normal case: $40 against a $95 order pays $40 and the card pays $55
  • Issued in lots with their own expiry, spent oldest-expiry first, allocated under SELECT … FOR UPDATE
  • A balance is a sum over unexpired lots, never a stored number somebody has to keep correct

Back on the right shelf

Restocking into Commerce 5 inventory locations, with the shelf chosen by the condition the goods came back in.

  • Resellable goods to available, damaged to damaged, anything questionable to quality control
  • An inventory adjustment rather than a restock movement, so fulfilled stock never goes negative
  • Idempotent per item, however many times a transition is retried

Money, credit or goods

What the customer gets back is chosen per RMA and carried out once, on arrival at a state that resolves.

  • Refunds run through Commerce's own gateway transactions, and a partial success is recorded before it throws
  • creditBonusPercent turns a $50 refund into $55 of credit — the lever that makes customers pick it
  • Exchange and replacement orders carry a credit for what came back, so the customer pays the difference

Which ones were your fault

A return rate that mixes “we got it wrong” with “they ordered two sizes on purpose” tells you nothing, so the reason carries which it was.

  • Return rate against what was actually sold in the same period, per reason and per SKU
  • Median days to settle, and what proportion of the goods went back on the shelf
  • Credit issued, spent, expired, outstanding and redeemed — redeemed is a customer who came back

Boomerang in the control panel

The returns desk, one return with everything that happened to it, what the store owes in credit, and which returns were the store's own fault.

The Boomerang returns index in the Craft control panel, listing thirteen RMAs across requested, approved, in transit, received, resolved and rejected states, each with the order it came from, the customer, the number of items, the resolution it is heading for and its value
A single Boomerang RMA showing the returned line with its reason, condition and snapshot value, the resolution panel with goods, payable and credited amounts, the return label panel, and an append-only history listing the state changes, the restock, the credit issued and every notification sent
The Boomerang store credit screen showing outstanding, issued, spent, redeemed and expired totals across the store, then each customer's balance, how many lots it is made of, and the date their next lot expires
The Boomerang analytics screen reporting return count, value, rate, the share that were the store's own fault, median days to settle and how much went back on the shelf, with returns per day charted and every reason ranked by what it cost

Screenshots from a live install, not mockups.

Frequently Asked Questions

The questions worth answering before you install it.

Install it and open the portal

The install seeds a working state machine and eight return reasons, so the first screen you open already does something. Lite is free and covers the portal, the state machine, eligibility, refunds and notifications — the whole loop except the wallet, exchanges, inventory restocking, labels and analytics.