Reference → Refunds — Reference

Refunds — Reference

The Refunds surface is the money-back plane for every SGEN ecommerce site. It owns the refund record, the scope-and-amount composer that drives each refund, the refund-reason taxonomy, the restock decision, the tax-recovery logic, and the handoff to the configured payment provider that moves funds. Anything that returns value to a customer after capture traces back to a record managed here.

This page is a reference for platform engineers and integrators who need to understand the surface before extending it, scripting against it, or reconciling against an external accounting system. Customer-facing how-tos live in the customer docs set; this page describes the shape of the surface, not the steps to drive it.


Overview

Refunds live under the Refunds sub-module inside the ecommerce surface in SG-Admin. The module renders three primary views — the refund list, the refund composer (scope, amount, reason, restock, tax), and the refund detail page (status, provider response, ledger entries) — and exposes a small set of write operations for issue, retry, cancel-pending, and soft delete.

The module is paired by convention with the Orders surface and, by extension, with Invoices. Every refund record links back to a parent order (and optionally to an invoice); the parent's refundable balance is the upper bound on what a refund can return. Refunds are append-only against the parent — a failed refund records a failure but does not consume any refundable balance; a successful refund consumes the refunded amount permanently.

A second surface — payment-provider handoff — sits underneath every refund. The refund record initiates the operation; the configured payment provider determines whether the operation completes. Providers vary in their support for partial refunds, line-level refunds, and asynchronous-vs-synchronous response — the surface normalizes the response into a stable refund-status lifecycle regardless of provider.

Where it lives in SG-Admin:

  • Sidebar: SG-Admin → Ecommerce → Refunds (and inline on the order detail page)
  • URL prefix: /sg-admin/refunds/
  • View templates: application/views/Admin/Refunds/
The module surface is intentionally narrow — every refund is initiated against a parent order or invoice, and the structural variations (full / partial-line / partial-amount / restock-only / tax-only) are scope flags on a single record shape. Adjacent surfaces (Orders, Invoices, Tax, Inventory) shape what a refund can contain and how it cascades; this page covers only the refund record and the operations that act on it.
┌──────────────────────────────────────────────────────────────────────┐│ SG-Admin → Ecommerce → Refunds [+ New refund] │├──────────────────────────────────────────────────────────────────────┤│ # Order Amount Scope Status Issued ││ ───── ────── ──────── ──────────── ────────── ────────────────││ RF-308 1042 $148.00 Full Completed 2 min ago ││ RF-307 1040 $ 75.50 Partial-line Completed 18 min ago ││ RF-306 1039 $ 14.00 Tax-only Completed yesterday ││ RF-305 1038 $ 32.50 Partial-amt Pending 3 hours ago ││ RF-304 1037 $ 89.00 Full Failed 1 day ago ││ ││ Filter: [Status ▼] [Reason ▼] [Date range] Bulk: [Export] │└──────────────────────────────────────────────────────────────────────┘

Actions

The Refunds surface exposes the following operations. Each is described by what it does to the data, not by its internal method name.

List and search

Returns the refund records visible to the current operator, paginated, with refund number, parent order, amount, scope, status, and issued-at columns. Supports column sort, free-text filter, status filter, scope filter, reason filter, and date-range filter. Driven by the data-table contract used across SG-Admin modules.

View refund detail

Loads the full refund record into a read-mostly detail page — parent order summary, scope and amount breakdown, reason and operator note, restock decision, tax-recovery line, payment-provider response, and the running status history. Editable fields are gated behind separate actions; the detail page itself does not write.

Issue refund

Opens the refund composer against a named parent order. Operator picks scope (full / partial-line / partial-amount / tax-only / restock-only), enters reason from the configured taxonomy, optionally adds an operator note, and decides whether to restock the affected line items. The surface validates the refund against the parent's remaining refundable balance, computes the tax-recovery portion based on the configured tax rules, calls the configured payment provider, writes the refund record, and updates the parent order's refund ledger.

Engineering note: the surface treats the provider call as the authoritative truth. A successful provider response advances the refund to completed; a failure marks the refund failed with the provider error attached and leaves the parent's refundable balance unchanged. No partial state is recorded on the parent — the refund record holds the failure detail in isolation.

Issue refund against invoice

A variant entry. Refunds against a paid invoice (rather than directly against an order) record the same refund shape but link to the invoice instead of an order. The invoice's payment-event ledger gets a reversal entry; the invoice's paid total drops; status may transition back to partially-paid or sent depending on the resulting balance.

Retry failed refund

A focused write path. Re-runs the provider call against an existing refund record in failed status. Useful when the original failure was transient (provider downtime, rate limiting, expired authorization). The record carries a retry counter visible in the detail view; provider configuration determines the maximum allowed retries.

Cancel pending refund

Aborts a refund that is in pending status (the surface is awaiting the provider's asynchronous response). Cancel issues a cancellation call to the provider where supported and marks the local record cancelled. Providers that do not support cancellation return a structured error and the record remains pending until the provider finalizes.

Set refund reason

Updates the reason on an existing refund record without changing amount or scope. Useful for correcting a misclassified reason after the fact. Only the reason taxonomy slug is editable; the human-readable description on the operator note is editable separately. Both edits are tracked in the audit log.

Restock line items

A focused write path that runs alongside issue refund. When the operator opts in at refund time, the surface adjusts inventory levels for the affected line items by the refunded quantity. Restocking can be skipped (operator opts out) for damaged returns or for service refunds where no physical good moves. Restock decisions are immutable after the refund completes; correcting a missed or unwanted restock requires a manual inventory adjustment.

Soft delete

Marks the record inactive without removing it from the database. Soft-deleted refunds disappear from the default list view but remain queryable via the archive filter and continue to back reporting and reconciliation queries. Available only for refunds in failed or cancelled status; completed refunds cannot be soft-deleted (they represent real money movement and must remain visible).

Restore

Reverses a soft delete. The record returns to the active list with its prior scope, status, and provider response intact.


Data model

A refund record carries the following fields. Field names below are the conceptual shape — the on-disk column names match closely but are not contractually stable across releases.

FieldTypeNotes
idintegerPrimary key. Stable across edits.
refund_numberstringOperator-facing identifier. Configurable prefix.
order_idintegerReferences the parent order. Required unless invoice_id is set.
invoice_idintegerReferences the parent invoice. Optional.
scopeenumfull, partial-line, partial-amount, tax-only, restock-only.
amountdecimalThe cash-recovery portion of the refund.
tax_recoverydecimalThe tax-recovery portion. Sum of amount + tax_recovery is the total returned to the customer.
currencystringInherits from the parent. Immutable after create.
line_targetsarraySet for partial-line scope — per-line refund quantities and amounts.
reason_slugstringOne of the configured reason taxonomy slugs.
reason_notestringOptional human-readable operator note.
restockbooleanTrue if affected line items should be returned to inventory.
statusenumpending, completed, failed, cancelled.
provider_referencestringReturned by the payment provider on success.
provider_responseobjectRaw provider response cached for audit.
retry_countintegerIncremented on each retry attempt.
issued_attimestampSet when the refund leaves pending.
completed_attimestampSet when status reaches completed.
created_attimestampSet on create, immutable.
updated_attimestampTouched on any edit.
Scope semantics: full returns the parent's full grand total; partial-line returns a subset of line items at specified quantities; partial-amount returns a fixed amount independent of line items; tax-only returns the tax portion of a prior amount (used for tax-correction after the fact); restock-only returns no money but adjusts inventory.

Tax-recovery semantics: the surface computes the tax portion of a refund using the same tax rules that were applied to the parent at capture time, not the current live tax rules. This matters for jurisdictions that change tax rates after a sale — the refund returns the customer's exact paid tax, not a recomputation against a different rate.

Provider response semantics: provider_status is whatever the provider returned; the surface maps it to the normalized refund-status enum but preserves the raw response in provider_response for reconciliation. Failed refunds keep the provider error attached for as long as the record exists.

REFUND RECORD├── id integer primary key├── refund_number string operator-facing identifier├── parent order_id OR invoice_id (one required)├── scope enum full | partial-line | partial-amount | tax-only | restock-only├── amount decimal cash-recovery portion├── tax_recovery decimal tax portion (against original tax rules, not live)├── line_targets array set for partial-line scope├── reason reason_slug + reason_note├── restock boolean inventory cascade decision├── status enum pending → completed | failed | cancelled├── provider provider_reference + provider_response (raw)├── retry_count integer└── timestamps issued_at, completed_at, created_at, updated_at↓ updates parentORDER / INVOICE REFUND LEDGERrefunded_total += amount (on completion only)

Permissions

Access to the Refunds surface is gated at two layers.

Layer 1 — admin gate. Every action under SG-Admin passes through the platform's standard admin access check at request entry. An unauthenticated request never reaches the Refunds surface.

Layer 2 — per-action capability. Within SG-Admin, each Refunds action checks a capability associated with the calling operator's role. The default role configuration ships with three refund-relevant roles — Store Manager, Support Operator, Accounts Receivable — layered on top of the platform's base roles. The capability map is:

CapabilityAdministratorStore ManagerSupportA/R
List refunds
View detail
Issue refund
Issue refund against invoice
Retry failed refund
Cancel pending refund
Set refund reason
Restock decision
Soft delete (failed/cancelled only)
Export
Custom roles defined under Settings → Roles override the default map. The capability slugs are stable; the role slugs are configurable.

Self-protection rules. A refund cannot exceed the parent's remaining refundable balance (parent's captured amount minus the sum of completed refunds). A completed refund cannot be soft-deleted — completed refunds represent real money movement and remain visible. A refund whose parent order is itself soft-deleted can still be viewed but cannot be retried; the parent must be restored first. Restock decisions on restock-only scope are mandatory; the surface rejects the record otherwise.

Audit. Every write — issue, retry, cancel, reason update, restock cascade, soft delete, restore — emits an Activity Log entry and an entry to the refund's own status history. The log records the acting operator, the target refund, the parent reference, and the change shape. Provider responses are cached on the record itself for reconciliation. Activity Log retention is governed by the site's general settings.

REQUEST│▼┌───────────────────────────┐│ Admin gate │ unauth → reject└─────────────┬─────────────┘│ authed▼┌───────────────────────────┐│ Capability check │ role lacks cap → reject│ (per-action, per-role) │└─────────────┬─────────────┘│ allowed▼┌───────────────────────────┐│ Balance + scope guards │ amount > remaining → reject│ │ delete-completed → reject└─────────────┬─────────────┘│ passes▼┌───────────────────────────┐│ Payment provider handoff │ pending → completed | failed└─────────────┬─────────────┘│ on completion▼Parent refund ledger updatedInventory adjusted (if restock)Activity Log entry written

Related references

  • Orders — Reference. Refunds against orders read from the order's captured-amount and produce entries in the order's refund ledger. Most refund traffic enters via the order detail page.
  • Invoices — Reference. Refunds against paid invoices record a reversal in the invoice's payment-event ledger and drop the paid total.
  • Inventory — Reference. Restock decisions on a refund cascade into inventory-level adjustments per line item.
  • Settings — Reference. Owns the refund reason taxonomy, the payment provider configuration, the retry limits, and the tax rules that drive tax-recovery calculations.
  • Users — Reference. Operator identity on every refund record is the acting user_id; re-attribution applies on permanent user delete.
  • Custom Codes — Reference. Refund confirmation email templates are themed through the template surfaces.
For the corresponding customer-facing walkthrough — issuing a refund, restocking on return, retrying a failed refund — see the Refunds section of the customer docs at /docs/refunds.
On this page