Currencies — Reference
The Currencies surface is the monetary master list for an SGEN site. It owns the catalog of currency records — ISO 4217 codes, display symbols, decimal precision, format rules, exchange rates against the base currency, and the base-currency lock that anchors every price calculation on the site. Anything that displays a price, accepts a payment, calculates tax, or settles a refund 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 scoping a multi-currency model. 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
Currencies lives under the Settings module in SG-Admin, in the localization group. The module renders three primary views — the currency list, the currency detail / edit form, and the exchange-rate history view — and exposes a small set of write operations for enable, disable, edit format rules, refresh exchange rates, and rotate the base currency.
The module is paired by convention: one half renders the views and prepares the catalog and rate-history data, the other half handles writes and returns AJAX responses. Engineers reading the SG-Admin source will see this split across two controller files; the reference below describes the combined surface as it appears to a calling integration.
The base currency is a special concept. Every currency record stores a rate relative to the base. The base record itself stores a rate of 1.0. Switching the base currency is a heavy operation — it rewrites every other rate, surfaces in the Activity Log as a base rotation, and is gated behind an explicit confirmation. Most sites set the base once and never change it.
Where it lives in SG-Admin:
- Sidebar: SG-Admin → Settings → Localization → Currencies
- URL prefix:
/sg-admin/currencies/ - View templates:
application/views/Admin/Settings/Currencies/
┌──────────────────────────────────────────────────────────────────────┐│ SG-Admin → Settings → Localization → Currencies [ Refresh rates ] │├──────────────────────────────────────────────────────────────────────┤│ ISO Symbol Name Rate to base Format State ││ ──── ────── ─────────────────── ───────────── ──────── ──────││ PHP ₱ Philippine peso 1.0000 (BASE) ₱1,234.56 ✔ ││ USD $ US dollar 0.01793 $1,234.56 ✔ ││ EUR € Euro 0.01640 €1.234,56 ✔ ││ GBP £ Pound sterling 0.01402 £1,234.56 ✔ ││ AUD A$ Australian dollar 0.02712 A$1,234.56 ✔ ││ JPY ¥ Japanese yen 2.7100 ¥1,235 — ││ ││ Enabled: 12 · Base: PHP · Rates last refreshed: 2 hrs ago ││ [ Edit format ] [ Rate history ] [ Rotate base ] │└──────────────────────────────────────────────────────────────────────┘Actions
The Currencies surface exposes the following operations. Each is described by what it does to the data, not by its internal method name.
List and filter
Returns the currency catalog paginated, with ISO-4217 code, symbol, display name, current rate against the base currency, format-rule summary, enabled flag, and base-flag. Supports filter by enabled state, by symbol, and by free-text on name. The base currency is pinned to the top of the list regardless of sort.
View currency
Returns the full record for a single currency — ISO code, symbol, display name, decimal precision, thousand-separator character, decimal-separator character, symbol position (prefix or suffix), space rule, current rate against base, last-refreshed timestamp, enabled flag, and base flag. Includes the rate-history ledger with one entry per refresh.
Create currency
Opens an empty currency form. Required fields at minimum: ISO-4217 code, symbol, display name, decimal precision. Optional fields cover format rules (separators, symbol position, space rule), initial exchange rate, and the enabled flag. On submit, the surface validates the ISO code against the upstream 4217 list, validates that no existing record uses the same code, persists the record, and returns the new identifier.
Edit format rules
Loads the format-rule subset of the currency record into a focused form. Editable fields cover decimal precision, thousand and decimal separators, symbol position, and space-between-symbol-and-amount rule. The exchange rate and base flag are handled by separate dedicated paths to avoid accidental rate edits during cosmetic changes.
Enable or disable currency
Dedicated toggle that flips the enabled flag. A disabled currency does not appear in the storefront currency selector but remains queryable in admin views and remains attached to historical orders. The base currency cannot be disabled — the surface returns a structured rejection.
Refresh exchange rates
Pulls the latest rates from the configured rate provider, applies them to every enabled non-base currency, and writes one row per currency into the rate-history ledger. Supports both scheduled refresh (background job) and operator-initiated refresh (synchronous). The base currency's rate is always 1.0 and is never overwritten by the refresh.
Engineering note. Refresh is idempotent within a refresh window — re-running the refresh inside the configured throttle window returns the cached rates rather than re-pulling from the provider.
Rotate base currency
Heavy operation. Designates a different currency as the new base. The surface recomputes every other rate so the new base reads as 1.0, writes the rotation event into the Activity Log, and bumps every rate-history entry with a rotation marker. Existing orders are unaffected — their captured rate is frozen at order time. New carts pick up the new base on next evaluation.
View rate history
Returns the rate-history ledger for a single currency. Each entry records the rate value, the refresh timestamp, the rate source (provider name or manual), the operator (for manual entries), and the rotation marker (set when this row corresponds to a base rotation). Used for refund math, audit trails, and diagnosing rate-driven price drift.
Data model
A currency 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.
| Field | Type | Notes |
|---|---|---|
id | integer | Primary key. Stable across edits. |
iso_4217 | string | Three-letter ISO 4217 code. Unique. Required. |
symbol | string | Display symbol. Not unique (the dollar sign is used by many currencies). |
name | string | Display name. |
decimal_precision | integer | Decimals shown in formatted prices (0 for JPY, 2 for most, 3 for some). |
thousand_separator | string | Single character. Common: comma, period, space. |
decimal_separator | string | Single character. Common: period, comma. |
symbol_position | enum | prefix or suffix. |
symbol_space | boolean | Whether to render a space between symbol and amount. |
rate_to_base | decimal | Multiplier against the base currency. Base records carry 1.0. |
rate_refreshed_at | timestamp | Last refresh timestamp. |
is_base | boolean | Exactly one currency record carries true. |
enabled | boolean | Whether the currency appears in the storefront selector. |
created_at | timestamp | Set on create, immutable. |
updated_at | timestamp | Touched on any edit. |
currency_id, rate_value, refreshed_at, source (provider name or manual), operator_id (for manual entries), rotation_marker (set during base rotation).Base-currency invariant: exactly one currency record has is_base = true at any time. Insertion and rotation are the only paths that satisfy this invariant; both are gated and audit-logged.
Order-time rate freeze: when an order is placed, the rate against base is captured into the order record. Refunds and downstream settlements use the captured rate, not the current rate. Rate refreshes never rewrite historical order math.
RATE PROVIDER (external)│ scheduled or operator-initiated refresh▼┌───────────────────────────────────────────┐│ Refresh job ││ for each enabled non-base currency: ││ ▶ pull latest rate ││ ▶ write rate-history row ││ ▶ update currency.rate_to_base ││ ▶ update rate_refreshed_at ││ ││ base currency: rate locked at 1.0 │└───────────────────────┬───────────────────┘│▼┌─────────┴─────────┐▼ ▼STOREFRONT ADMIN VIEWnew prices rate history(existing orders (audit trail)keep captured rate)Permissions
Access to the Currencies 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 Currencies surface.
Layer 2 — per-action capability. Within SG-Admin, each Currencies action checks a capability associated with the calling operator's role. The default role configuration ships with three roles — Administrator, Editor, Viewer — and the capability map is:
| Capability | Administrator | Editor | Viewer |
|---|---|---|---|
| List currencies | ✔ | ✔ | ✔ |
| View currency detail | ✔ | ✔ | ✔ |
| View rate history | ✔ | ✔ | ✔ |
| Create currency | ✔ | — | — |
| Edit format rules | ✔ | ✔ | — |
| Enable or disable currency | ✔ | ✔ | — |
| Refresh rates (operator-initiated) | ✔ | ✔ | — |
| Manual rate override | ✔ | — | — |
| Rotate base currency | ✔ | — | — |
Self-protection rules. The base currency cannot be disabled. The base currency cannot be deleted. Exactly one currency must carry the base flag at all times; the rotate action handles the transition atomically. A currency referenced by an open cart or an unsettled refund cannot be deleted — the surface returns a structured rejection naming the blocking record. Manual rate overrides are scoped to Administrator and emit a distinct Activity Log event for audit.
Audit. Every write — create, edit, enable, disable, rate refresh, manual rate override, base rotation — emits an Activity Log entry. The log records the acting operator, the currency identifier, and the change shape. Base rotations write a dedicated rotation event in addition to the per-currency rate updates.
REQUEST│▼┌───────────────────────────┐│ Admin gate │ unauth → reject│ (every /sg-admin/* call) │└─────────────┬─────────────┘│ authed▼┌───────────────────────────┐│ Capability check │ role lacks cap → reject│ (per-action) │ (custom roles override defaults)└─────────────┬─────────────┘│ allowed▼┌───────────────────────────┐│ Self-protection rules │ base disable / referenced row /│ │ zero-base → reject└─────────────┬─────────────┘│ passes▼action executes│▼Activity Log + rate historyRelated references
- Countries — Reference. Each country carries a
currency_hintthat points here. The storefront defaults the currency selector to the hint for the visitor's country. - Products — Reference. Per-product price overrides can pin a specific amount in a specific currency, overriding the base-currency conversion for that product.
- Orders — Reference. Order records freeze the rate at order time. Refunds use the frozen rate, not the current rate.
- Payment Gateways — Reference. Each gateway carries a settlement-currency mapping. A non-base settlement currency requires the gateway to convert at its own rate; the order captures the merchant's view at base.
- Tax Zones — Reference. Tax math runs in the cart's chosen currency, then converts to base for ledger storage.
- Activity Log — Reference. Rate refreshes, manual overrides, and base rotations all surface here. Base rotations carry a dedicated event type for audit clarity.
- Settings — Reference. Owns the rate-provider configuration, the refresh schedule, the throttle window, and the per-currency format defaults seed. Changes there reshape the refresh cadence.
/docs/currencies.