client platform ERP-first migration
Yuzu Marketing Sdn Bhd on FTEG Business OS (sme-erp, tenant ymsb).
9981 Yuzu is their ecommerce + events channel — not a second company OS.
| Layer | What | System |
|---|---|---|
| Company | Yuzu Marketing Sdn Bhd (1406927-K) | Business OS + fteg-store buyer ymsb |
| Brand | 9981 Yuzu — fruit alcohol, online + expo | 9981 ecommerce (9981beelongz) |
| B2B customers | Bars, hotels, distributors | CRM clients (erp_clients, segment b2b) |
| B2C shoppers | Online + Loyverse walk-in | 9981 users / orders — not every row in CRM |
fteg-store (billing, portal, metrics)
│
├── sme-erp / ymsb ← company OS (CRM, quotes, invoices, catalogue master)
│ └── launcher → 9981 BO
│
└── 9981 Yuzu ← sales channels (web, Loyverse expo, events)
└── stock / Loyverse ops (until ERP inventory freeze)
fteg-commerce work while YMSB still needs company-OS depth
(pricing live, purchasing, stock visibility). 9981 stays frozen-legacy: no new price columns, no rewrite in place.
ymsb-erp transitional shell is frozen — use ymsb.sme-erp.fteg.dev.
| Data | Master | Notes |
|---|---|---|
| B2B clients | Business OS CRM | Quotations, invoices, e-Invoice B2B |
| Suppliers | erp_suppliers | live Import: ymsb:import-suppliers-from-9981 |
| Trade SKUs | erp_skus | live Import: trade:import-skus-from-9981 |
| Price book | ERP erp_price_tiers + erp_sku_prices | live One matrix for B2C + B2B. Ecommerce does not own prices. |
| Storefront / PDP / promos | 9981 (legacy) | Display + promo only. Sell price = ERP tier. 9981 stays frozen; new shop is Ecommerce 2.0. |
| B2C orders | 9981 orders | source: online-ticket or loyverse |
| Stock ops (today) | 9981 + Google Sheets + Loyverse | ERP v1 is a thin move log only. Shop/POS still issue from 9981 / Sheets. |
| Inventory (target) | ERP lot ledger | One stock book for all channels. Shops issue from ERP — they do not JIT-procure. See §8. |
| Channel | How sale enters | orders.source |
|---|---|---|
| Online ecommerce | 9981 storefront checkout | online-ticket |
| Expo / booth | Loyverse POS → sync → gg_orders. Planned replacement: FTEG POS (do not dual-run) | loyverse |
| Social / manual BO | Staff order in 9981 BO (WhatsApp, IG, FB) | manual + platform |
| Marketplace | Shopee / Lazada (Sheets or API → orders) | platform + external_id |
| B2B wholesale | Sales team → Business OS quote → invoice or logged-in trade reorder (later) | ERP (not a second public shop) |
Expo linkage: event_lists.event_id + Loyverse Cashier Event Binding. Guide: /srv/www/9981beelongz/docs/EVENT_SALES_SETUP_GUIDE.md
Identity model: Most B2C sales are anonymous transactions (expo cash, marketplaces) — not CRM clients. See Sales Channels & Identity.
| Layer | Owns | Does not own |
|---|---|---|
| ERP | Tiers per channel (b2c / b2b), per-SKU amounts, client price_tier_id | PDP copy, promos, cart UX |
| Ecommerce | Who is buying → which tier → charge that cell | A second price list |
| 9981 legacy | product_skus.price as a copy of ERP retail (optional trade:sync-skus-to-9981) | Member vs gold vs distributor (loyalty tiers are points, not sell price) |
| Yuzu Marketing site | Brochure + become-a-partner lead | Checkout / cart — ymsbcorporate.fteg.dev stays CMS |
Default tiers (per tenant): B2C retail (default) + member; B2B reseller + distributor (default). Add more (gold, hotel, …) in Price tiers. Client with no assigned tier uses the channel default.
| Buyer | Tier used |
|---|---|
| Guest / not logged in | B2C default (retail) |
| 9981 / shop member | B2C member (or assigned gold, etc.) |
| Hotel / reseller / distributor | That CRM client’s B2B tier |
One ecommerce, two channels — not two shops. Same SKU, same stock. Public cart = B2C. Logged-in /trade (Ecommerce 2.0) = B2B self-order at the client’s ERP tier. Sales can still quote in ERP for negotiated deals.
Promos / vouchers discount the tier price. Shopee and Loyverse keep their own channel prices; they are not the web shop book.
b2b, TIN/BRN) + assign price tierQT-… in remark)| Phase | Status | Deliverable |
|---|---|---|
| 0 | done | Business OS live for YMSB; 9981 unchanged |
| 1a | done | erp_suppliers + BO + import from 9981 |
| 1b | done | erp_skus + trade pricing + import from 9981 |
| 2 | done | SKU picker on quotations |
| 3 | done | Prove B2B flow in ERP (quote → order → invoice → e-Invoice) |
| 4 | done | trade:sync-skus-to-9981 — preview by default. Never writes 0; drops > 20% need --force. ERP retail was refreshed from live 9981 (import). Do not push stale ERP onto the shop. |
| 5 | done | ERP dashboard: online vs Loyverse GMV (read-only from 9981) |
| 6 | done | ymsb:fulfilment-handoff CLI + Sales order → 9981 handoff page |
| 7 | done | Promote 9981 member → Inbox / pipeline (one-way; company name required; no auto-merge) |
| 8 | done | ERP price tiers + SKU matrix + client assignment. Live on YMSB sqlite (4 default tiers, SKU prices backfilled). 9981 still charges product_skus.price until sync. |
| 9–11, 13–28 | done | Purchasing + stock glance + quote economics + follow-up (quotes / POs / invoices). PO tables and supplier email live. |
| 29 | done | Purchasing module complete (no stock ledger). Draft → sent → received/cancelled. PDF, email, copy, draft-from-glance, due/overdue, spend, receive confirm. Closed POs are read-only. |
| 30 | done | Client price list PDF (that client’s tier) + SKU matrix CSV. Last pricing deliverable before inventory. |
| 12 | done | Inventory v1 — signed moves (opening / receive / adjust). Does not write 9981. Sales still 9981. |
| 12b | done | UOM packs — one stock SKU in base units; CTN/BTL on erp_sku_uoms. Carton is not a second SKU. Stock shows bottles + cartons. Still no sale-out / lots. |
| 12c | done | Locations — erp_warehouses (HQ / expo / consignment). Moves + PO receive scoped; transfer_out/in. Light WH, not WMS. |
| 12d | done | Lot ledger — erp_sku_ins / erp_sku_outs / erp_sku_balances. On-hand from balances; FIFO issue; PO receive creates costed lots. Moves stay audit. |
| 12e | done | B2B sale issue — accept quotation → FIFO sale outs from default sellable WH. Hard-block if ERP short. 9981 unchanged. |
| 12f | done | Event load-in — expo locations per concurrent event; multi-SKU transfer HQ↔event (not a sale). Return leftovers the same way. |
| 12g | done | Channel / POS sale issue — POST /api/v1/channel/sales with warehouse + external_id; FIFO out; open-bottle write-off preset. Glass = POS revenue only. |
| 12h | done | Event ↔ location link — erp_warehouses.external_event_id = 9981 event_lists.event_id. Channel API accepts event_id or warehouse_code. Same event can carry tickets + POS; ERP only issues bottle stock. |
| 12i | done | B2B reverse-out — cancel sales order restores lots at same WH/cost (sale_reverse). Idempotent. 9981 unchanged. |
| 12j | done | Soft reserve — mark-sent holds lots (erp_sku_reserves + lot reserve_qty). Reject releases; accept converts to FIFO sale. Hard-block send if available short. |
| 12k | done | Monthly close / COGS — outs × lot cost for YYYY-MM; snapshot on erp_inventory_closes; closed month blocks new lot moves. Sheets still ops until cutover. |
| 12l | built | 9981 → ERP issue bridge (ERP-side only) — ymsb:bridge-9981-sales reads 9981 DB paid orders and issues via channel service. Zero 9981 code changes; never writes 9981. Unmapped lines skipped. Loyverse only as 9981 orders.source when present. |
| — | paused | Ecommerce 2.0 — not the current track. Resume only after ERP purchasing is usable and BD is quoting from the price book. |
Do not create a second inventory SKU when you want to sell bottles from a carton. That doubles stock and needs a pack-break every time someone opens a box.
Infinity model (locked for ERP):
| Layer | What it is | Example |
|---|---|---|
| Inventory SKU | One stock item, counted in base unit | GOD-NIG-001 on-hand = bottles |
sku_uoms | Pack sizes on that SKU | BTL = 1, CTN = 6 |
| Sellable (PSKU / offer) | How the shop sells it; uom_qty = bottles taken | Bottle offer → 1; Carton offer → 6 |
floor(bottles / 6). Sell 1 bottle → cartons drop when remainder < 6.sku_uoms without a second stock code.Pack-break (out 1 carton-SKU, in 6 bottle-SKU) only if the carton is a different physical item that must stay sealed (gift set, bonded case). Default: do not.
ERP today: erp_skus.unit defaults to bottle (1:1 with 9981). Target adds pack UOMs + sellable offers on the same erp_sku.
| Feature | v1 now | Target (covers Infinity + gg_inventory_logs) |
|---|---|---|
| Lot ledger + cost on in | erp_sku_ins/outs/balances (12d) | In lot; out consumes a lot (FIFO); closings later |
| Locations | erp_warehouses + move/PO WH (12c) | Warehouse / entity (HQ, expo, consignment) + more kinds as needed |
| Receive | PO receive | PO / supplier invoice, partial GRN |
| Issue | B2B accept (HQ) + channel API by WH (12e/12g) | Web, POS, B2B, event, marketplace — all post out |
| Transfer | WH → WH (transfer_out + transfer_in) | WH → WH with lot awareness |
| Adjust / write-off | adjust + open-bottle presets (12g) | Broken, stolen, defect, tasting, internal, CN, consignment return |
| Reserve / pending | soft hold on sent quotes (12j) | Hold on lot; pending order does not write cache |
| UOM / packs | erp_sku_uoms (12b) | §8.1 — one stock SKU, many sell packs |
| Close + COGS | monthly close snapshot (12k) | Monthly close; COGS = out × lot cost |
| Channel API | POST /api/v1/channel/sales (12g/12h) — ready for callers | ERP-side job/command reads 9981 and issues (12l). No 9981 patches. Source tag = 9981 order source. |
Until cutover: 9981 still owns live B2C stock qty; ERP ledger mirrors via pull bridge. After cutover: ERP is truth; 9981 reads available / stops local deduct (that cutover would touch 9981 — separate phase).
| Surface | URL |
|---|---|
| Business OS (YMSB) | ymsb.sme-erp.fteg.dev |
| 9981 storefront | 9981wine.fteg.dev |
| 9981 BO | 9981yuzu-bo152310.fteg.dev |
| YMSB corporate | ymsbcorporate.fteg.dev |
| Legacy ymsb-erp | ymsb-erp-bo.fteg.dev (frozen) |
/srv/www/hubs/sme-erp — Business OS (canonical ERP dev tree)/srv/www/9981beelongz — 9981 ecommerce + ops/srv/www/hubs/fteg-store — buyer ymsb, metrics API/srv/www/hubs/ymsb-erp — transitional (do not expand)/srv/www/hubs/GROUP-ARCHITECTURE.md/srv/www/hubs/ymsb-erp/DESIGN.mdYuzu Platform · Loading version…