Reference → Bundles — Reference

Bundles — Reference

The Bundles surface is the grouped-purchase plane for SGEN commerce. It owns the records that join several catalog products into a single buyable unit — fixed kits with predetermined contents, configurable bundles where the shopper picks components from defined slots, and bundle-level pricing that overrides the sum of the parts.

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 kitting 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

Bundles lives under the Commerce module in SG-Admin. The module renders three primary views — the bundle list, the bundle create / edit form (with the component slot table), and the inventory view that resolves bundle stock against the stock of each component — and exposes a small set of write operations for create, edit, add / remove components, set pricing, pause, resume, and archive.

The module is paired by convention: one half renders the views and prepares the bundle and component 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.

Bundles are distinct from Upsells. A bundle is a single catalog entity the shopper adds as one line; an upsell is a suggestion that adds a separate line to an existing cart. Both surfaces participate in the merchandising pipeline, but the entry points and the cart shape differ. Upsell rules live under the adjacent Upsells surface; this page covers grouped-purchase units only.

Where it lives in SG-Admin:

  • Sidebar: SG-Admin → Commerce → Bundles
  • URL prefix: /sg-admin/bundles/
  • View templates: application/views/Admin/Commerce/Bundles/
The module surface is intentionally small. Catalog rendering, inventory reservation, fulfillment line splitting, and refund unwinding live in adjacent surfaces — this page covers only the bundle definition, the component slot model, the pricing override, and the inventory resolution rule.
┌──────────────────────────────────────────────────────────────────────┐│ SG-Admin → Commerce → Bundles [ + Add bundle ] │├──────────────────────────────────────────────────────────────────────┤│ Name Type Slots Price Status ││ ──────────────────── ───────────── ────── ────────── ──────────││ Starter Kit fixed 3 $79.00 active ││ Pick-3 Snack Box configurable 3 of 8 $29.00 active ││ Office Setup fixed 5 $429.00 active ││ Build-Your-Tea configurable 4 of 12 $34.00 active ││ Holiday Gift Bundle fixed 4 $99.00 scheduled ││ ││ Active: 8 · Scheduled: 2 · Out-of-stock-locked: 1 · Archived: 3││ [ Edit ] [ Components ] [ Pricing ] [ Pause ] [ Archive ] │└──────────────────────────────────────────────────────────────────────┘

Actions

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

List bundles

Returns the bundle catalog visible to the current operator, paginated, with name, type (fixed / configurable), slot count, bundle price, status (active, scheduled, out-of-stock-locked, paused, archived), and an inventory-availability flag. Supports filter by type, by status, and by component-product reference. The default view excludes archived bundles — they remain queryable via the explicit filter.

View bundle

Returns the full record for a single bundle — name, type, component slot table, bundle price or pricing rule, schedule window, inventory resolution policy, and the per-component substitution table for configurable bundles. The slot table is rendered with each slot's component options and any min / max constraints.

Create bundle

Opens an empty bundle form. Required fields at minimum: name, type, and either a fixed component list or a slot definition for configurable bundles. Optional fields cover bundle price (or a discount-from-sum-of-parts rule), schedule window, inventory resolution policy, image override, and per-slot constraints. On submit, the surface validates that every component exists in the catalog, persists the record, and returns the new identifier.

Edit bundle

Loads an existing record into the same form shape used for create, pre-populated. Submit replaces the stored bundle with the posted values; fields left blank do not clear server-side values (the form is partial-update by default). Edits to an active bundle take effect on the next cart evaluation — carts already at checkout retain the previously composed line.

Add, edit, and remove components

The slot table is editable inline. For fixed bundles, each slot carries a single component reference and a quantity; for configurable bundles, each slot carries a list of allowed components and an inclusive min_pick / max_pick range. Adding a slot inserts a row; editing rewrites slot contents; removing detaches the slot from the bundle without affecting the underlying catalog products.

Set bundle pricing

Bundle pricing is one of three modes — fixed_price, sum_minus_discount, or sum_of_parts. fixed_price quotes a flat number regardless of which components are picked. sum_minus_discount quotes the catalog total of the selected components minus a percent or flat amount. sum_of_parts quotes the unmodified catalog total and is included for completeness; it is rarely used in production because it removes the incentive to buy as a bundle.

Pause and resume

Toggles the bundle between active and paused without altering its definition. Paused bundles are excluded from catalog rendering but retain their components, pricing, and configuration. Resume restores the bundle to active.

Schedule

Sets the start / end window during which the bundle is eligible for purchase. Scheduled bundles move automatically between scheduled, active, and expired status as the window opens and closes. Outside the window, the bundle is hidden from storefront and search.

Archive

Marks the bundle inactive without removing it from the database. Archived bundles disappear from the default list view but remain queryable via the archived filter. Historical orders referencing the bundle retain their references; the bundle itself is excluded from future purchases.

Engineering note. Component edits on a fixed bundle do not propagate to historical orders. An order placed before the edit retains its original component composition for fulfillment and refund.

Data model

A bundle 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.
namestringOperator-facing label. Customer-visible.
typeenumfixed, configurable.
pricing_modeenumfixed_price, sum_minus_discount, sum_of_parts.
pricenumericUsed when pricing_mode = fixed_price.
discount_valuenumericUsed when pricing_mode = sum_minus_discount.
discount_kindenumflat, percent. Pairs with discount_value.
inventory_policyenumlock_to_lowest_component, decoupled, virtual_only.
statusenumactive, scheduled, paused, expired, out_of_stock_locked, archived.
starts_attimestampOptional schedule start.
ends_attimestampOptional schedule end.
image_urlstringOptional override; falls back to the first component's image.
created_attimestampSet on create, immutable.
updated_attimestampTouched on any edit or slot change.
Component slot row: bundle_id, slot_position, slot_label, min_pick, max_pick, plus a list of allowed-component references. Fixed bundles have min_pick = max_pick = 1 per slot. Configurable bundles permit ranges, including optional slots where min_pick = 0.

Allowed-component row: slot_id, product_id or variant_id, default_quantity, optional surcharge. Surcharge lets one option inside a slot cost extra without changing the bundle's base price.

Inventory semantics: lock_to_lowest_component exposes the bundle's available stock as the minimum of its components' stocks divided by their required quantities — the default and safest mode. decoupled ignores component stock and uses a separate counter on the bundle record. virtual_only is for bundles whose components are services or downloads with no stock concept.

BUNDLE (configurable) "Pick-3 Snack Box" pricing_mode = fixed_price = $29│├── SLOT 1 "Chips" min_pick=1 max_pick=1│ ├── product: Salt Chips default_qty 1│ ├── product: BBQ Chips default_qty 1│ └── product: Sour Cream Chips default_qty 1│├── SLOT 2 "Cookies" min_pick=1 max_pick=1│ ├── product: Choc Chip Cookie default_qty 2│ └── product: Oatmeal Cookie default_qty 2│└── SLOT 3 "Drink" min_pick=1 max_pick=1├── product: Cola default_qty 1├── product: Lemonade default_qty 1└── product: Sparkling Water default_qty 1 surcharge +$1.00INVENTORY lock_to_lowest_component↓bundle available = min(chips stock, cookies stock, drinks stock)

Permissions

Access to the Bundles 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 Bundles surface.

Layer 2 — per-action capability. Within SG-Admin, each Bundles 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:

CapabilityAdministratorEditorViewer
List bundles
View bundle
Create bundle
Edit bundle
Add / edit / remove slots
Set bundle pricing
Change inventory policy
Schedule
Pause / resume
Archive bundle
Restore archived bundle
Custom roles defined under Settings → Roles override the default map. The capability slugs are stable; the role slugs are configurable.

Self-protection rules. A bundle with open orders in flight (cart-stage or fulfillment-stage) cannot be archived without confirmation — the surface returns a structured rejection naming the open order count. A configurable bundle cannot have its min_pick raised above max_pick. A component cannot be removed from a slot while it is the only allowed option for that slot in a min_pick ≥ 1 configuration.

Audit. Every write — create, edit, slot change, pricing change, schedule, pause, resume, archive, restore — emits an Activity Log entry. The log records the acting operator, the bundle identifier, and the change shape (field-level diff for edits, slot-diff for component changes). Bundle purchases also write a line-composition entry to the order, snapshotting the component selection for later refund or return.

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 │ open-order archive /│ │ min>max pick / last-option│ │ removal → reject└─────────────┬─────────────┘│ passes▼action executes│▼Activity Log + order line-composition snapshot

Related references

  • Products — Reference. Owns the components referenced by bundle slots. A product cannot be deleted while it is referenced by an active bundle slot; the surface returns a structured rejection.
  • Price Lists — Reference. Bundles can carry a fixed bundle price or be subject to per-customer-group pricing. When both exist, the price-list quote on the bundle line wins over the bundle's own fixed_price.
  • Discounts — Reference. Discount rules apply on top of the bundle line price. Component-level discounts do not apply to bundled components — the line is treated as a single unit for discount evaluation.
  • Upsells — Reference. Bundles may appear as upsell suggestions on related product pages. The upsell engine references the bundle's catalog identifier, not its slot composition.
  • Orders — Reference. Records the bundle line plus a snapshot of the selected components. Partial refunds on bundles unwind to the line, not to individual components, unless the refund policy is configured for component-level unwinding.
  • Inventory — Reference. Owns the stock counters that feed the lock_to_lowest_component resolution. Reservation and release semantics for bundle lines are documented there.
  • Settings — Reference. Owns the default inventory policy, the default pricing mode, and the catalog-rendering rules for bundle cards. Changes there reshape Bundles defaults but do not retroactively affect existing records.
For the corresponding customer-facing walkthrough — creating a fixed kit, building a configurable bundle with multiple slots, scheduling a holiday bundle — see the Bundles section of the customer docs at /docs/bundles.
On this page