---
title: "Ring ERP"
description: "Operator cockpit for multi-vendor inventory, settlements, and vendor ops — stock invariant, paid commit, commissions hub"
locale: "en"
---
# Ring ERP

Ring ERP is the **operator cockpit** over the multi-vendor store: warehouse stock, checkout holds, paid-sale commit, and the vendor settlements ledger. It does **not** invent a second stock system — it extends `ERPStockService`, `inventory-sync`, and PaymentConductor paid handlers.

> **Info**
> Use the docs sidebar **Founder** / **Developer** tabs to filter this page. Affiliate token minting stays on [Affiliate enablement](/docs/features/affiliate-enablement.md) / [Refcodes](/docs/features/refcodes.md) — ERP owns stock + the `settlements` ledger + hub UI.

  
- **[Inventory & stock](/docs/features/erp/inventory.md)** — Locked invariant, checkout reserve, commitSaleForOrder, cancel/refund restore.

  
- **[Commissions & settlements](/docs/features/erp/commissions.md)** — Settlements ledger, hold/release, dry-run payouts, referral rates.

  
- **[Vendor management](/docs/features/erp/vendor-management.md)** — Vendor lifecycle, stock ownership, earnings surfaces.

  
- **[Multi-vendor store](/docs/features/store.md)** — Catalog, cart, checkout — ERP reacts after payment.

### For founders

## What you get as an operator

| Surface | Route | Day-1 job |
|---------|-------|-----------|
| Store hub overview | `/admin/store` | Stock summary + pending settlements at a glance |
| Products / Orders | `/admin/store/products`, `/admin/store/orders` | Catalog approval and fulfillment status |
| Stock | `/admin/store/stock` | Low-stock filters, reason-coded restock, movement timeline |
| Commissions | `/admin/store/commissions` | Hold/release, dry-run due payouts, then process |
| Vendor stock | `/vendor/stock` | Own-product restock (bulk), low-stock badges |
| Vendor earnings | `/vendor/earnings` | Pending + history from `settlements` |

### Typical scenarios

1. **Prevent oversell** — Checkout reserves **sellable** units (`available`). A second checkout cannot take reserved stock.
2. **Paid order** — PaymentConductor marks paid → stock commits once (idempotent) → settlement row appears for each vendor slice.
3. **Buyer cancels unpaid** — Holds release; sellable returns. **Refund after paid** restores stock from sale movements (WayForPay Refunded/Voided wired).
4. **Payout day** — Dry-run due settlements, then Process due payouts (simulated badge until on-chain mode is verified).

> **Tip**
> Default warehouse label is `zero-warehouse` (store id `1`). Nova Poshta pickup points in shipping APIs are **not** ERP warehouses.

### Shipped vs backlog

**Shipped (hub P0):** stock invariant, `commitSaleForOrder`, admin hub landing, stock/commissions depth, vendor ownership on restock.

### For developers

## Architecture (verified)

```mermaid
sequenceDiagram
  participant CO as Checkout_Orders
  participant INV as inventory_sync
  participant PC as PaymentConductor
  participant SALE as commitSaleForOrder
  participant VS as VendorSettlementService
  participant DB as PostgreSQL

  CO->>INV: reserveInventoryForOrder
  INV->>DB: available-=q reserved+=q stock unchanged
  PC->>SALE: paid isNew
  SALE->>DB: fulfill reserved-=q then stock-=q
  PC->>VS: processSettlements
  VS->>DB: settlements ledger
```

| Module | Path | Role |
|--------|------|------|
| Constants | `features/store/constants/stock.ts` | `ZERO_WAREHOUSE_ID`, `DEFAULT_INVENTORY_STORE_ID` |
| ERP stock | `features/store/services/erp-stock-service.ts` | Restock/adjust; levels-aware `getStockLevel` |
| Inventory sync | `features/store/services/inventory-sync.ts` | Reserve, fulfill, `commitSaleForOrder`, restore |
| Settlements | `features/store/services/settlement.ts` + `settlement-pipeline.ts` | Ledger + referral assists |
| Admin actions | `app/_actions/admin-store-erp.ts` | Init stock, hold/release, dry-run, adjust |
| Paid handlers | `lib/payments/conductor/handlers/store-order*.ts` + credit/token routes | Call `commitSaleForOrder` |

**Invariant:** `store_products.stock === inventory_levels.available + inventory_levels.reserved` · sellable = `available`.

ProcessConductor owns TTL cleanup (`cleanup-reservations`) and `settlement-payout` cron — do not duplicate.

## Roadmap phases

1. **Surface enablement (shipped)** — Thin `/admin/store` tabs + vendor pages + EN ERP docs.
2. **Hub P0 (shipped 2026-07)** — Invariant + paid commit + reverse paths + hub depth.
3. **Expansion waves** — Cart soft-holds, transfers UI, RMA, Greenfood lots/FEFO (see empire plan; not clone-docs fiction).

  
- [features/erp/inventory](/docs/features/erp/inventory.md) — Deep-dive: stock invariant, reserve, commitSaleForOrder, cancel/refund.

  
- [features/erp/commissions](/docs/features/erp/commissions.md) — Same-workflow: settlements ledger after paid commit.

  
- [features/payment-conductor](/docs/features/payment-conductor.md) — Depends-on: PaymentConductor remains payment SSOT; ERP reacts to paid/refund.

  
- [features/store](/docs/features/store.md) — Prerequisite: multi-vendor catalog and checkout before ERP ops.

  
- [features/affiliate-enablement](/docs/features/affiliate-enablement.md) — See-also: dual-rail referral — ERP ledger vs refcodes token rewards.
