We built DEV3 AI Returns & RMA Manager as a WooCommerce plugin in PHP, with a React admin app and a small portal app that inherits the store's theme. Every feature works without AI.
Key design decisions
- Returnable quantity from WooCommerce's own records. Each line's available quantity is bought minus
get_qty_refunded_for_item() minus units in open requests, so refunds made from the normal order screen count too. Rejected and cancelled requests release their units.
- Policy by precedence. Global window and resolutions, then product rules, then category rules (including parent categories), then product-level overrides and a filter. The window can start at completion, payment or order date, and sale items can be excluded.
- Refunds through
wc_create_refund. Refund lines are split per item and per tax rate; partial amounts scale every line; the amount is capped at the order's remaining refundable total; the gateway is used only when it supports refunds.
- Restock exactly once. WooCommerce's refund restock is turned off and the plugin restocks per item with a flag, so marking an item received and refunding it can't add stock twice.
- Store credit with a carry-over balance. Credit is an email-restricted coupon whose amount is reduced by the discount actually applied on each paid order, once per order, on classic and block checkout.
- Guest access without accounts. Lookup by order number and billing email (rate-limited, constant-time comparison) returns a short-lived HMAC token bound to that order; emails link with the request's own random key.
- Private evidence. Photos and labels live in a private uploads folder with deny rules and random names, and are served only through signed, expiring URLs.
- AI drafts, admins act. Optional triage with the Google Gemini API classifies the reason, reviews up to 3 downscaled photos against the claim and suggests a resolution and reply. Output is sanitised and clamped to the request's value, and "Use suggestion" only pre-fills the refund dialog.
Architecture
Requests, items and timeline events live in three custom tables, with order links stored through WooCommerce CRUD so HPOS works. The portal is a REST client of a public, same-origin, rate-limited namespace; the admin app uses a separate capability- and nonce-checked namespace for the queue, request detail, resolutions, labels, analytics and CSV export. Shopper and store notifications are WooCommerce email classes that merchants can edit or disable. AI runs only in admin or background jobs, never on the storefront. The API client, settings, usage logs and job runner come from a shared core used across DEV3's plugins.