G Gaia

Switch factory

CYTO-11 — Balakong Jaya CTSB CYTO-29 CTSB CYTOWELL-54 — Taming Jaya PIC/S CTWSB CYTOCNGZ-602 — Guangzhou CTCNGZ

Only factories you are granted appear here (Filament tenant menu).

Leo Lim

leo@navi.my · Owner / Admin

Profile settings Change password

Theme

Sign out
RetailSellR&DMakeBuyStockPlanItemsGMPAdminInsights
← Retail sales / New

New sale

will post as RS-26-042 · staff quick entry — big targets, no menus to hunt through

1 · Customer

Recent:

Haggles hard · floor 3.00 on Kopi Cik Abang · usual cadence ~10 days (from CRM book — same customers table, channel-scoped).

2 · Lines

price auto-fills from what this customer last paid

3 · Payment

Confirmable total MYR

Locked lines don't total: the below-floor line is excluded until the owner approves — + 🔒 ≠ tonight's cash drawer.

Draft RS-26-042 saved — the locked 2.80 line stays attached; completes in one tap after owner approval (Retail → Price lists · approvals queue). View sales list →
On confirm: posts FEFO retail_sale stock movements (FG lots spent, batch trace intact) · updates this customer's price memory · joins the July consolidated e-invoice at month end (B2B-flagged customers export individually instead).

Project Gaia — static mockup in Filament v3 idiom. No backend. Retail module; customer data shared with OEM underneath (channel-flagged), screens separated. Quick-sale form is the "monkey-proof" flow: memory fills the price, the floor does the arguing.

New retail sale — field manifest

FieldFilament componentTypeSourceFK target
PageRetailSaleResource CreateRecord (custom, big-target layout)formcreates: retail_sales + retail_sale_lines; next number from the RS- series (separate from OEM SO series)
CustomerSelect + recent-chips shortcutFK nullablecustomers scoped to channel ∈ {retail, both}; chips = this user's most recent sales; Walk-in ⇒ customer_id null (still consolidates, no price memory)customers
+ New customer (slide-over)CreateAction slideOver(), inline from the Selectformcreates: customers (display_name, phone, area, channel enum oem/retail/both, terms, b2b_einvoice, notes) — same table Sell → Customers writes; creation here defaults channel=retail; on create the new customer is selected for this sale (create-inline-then-sell)customers
LinesRepeater (product, qty, price)rowsretail_sale_lines; stock hint = live FG on-hand at current factory + first FEFO lot previewvariants / batches
Price autofillTextInput, afterStateUpdated querymoney, derived defaultquery: last price this customer paid for this variant (OEM SO lines + retail sale lines feed ONE memory); sub-line shows last paid · band · floor livesale history / variant_prices
Floor lockValidation + policy (hard)ruleprice < variant_prices.floor_price ⇒ line locked + approval_requests row to owner; Confirm disabled while any line is locked. NOT a warning — staff cannot override. Identical to OEMvariant_prices / approval_requests
PaymentToggleButtons (large)enum cash / transfer / unpaidretail_sales.payment_status; Unpaid sets due_date = today + customer terms and feeds the follow-up list
ConfirmCreateActionactionposts FEFO retail_sale stock movements; updates price memory; sale joins consolidation_runs for the month (unless customer B2B-flagged → individual QBO export)stock_movements / consolidation_runs

Engine notes

  • Shared-data doctrine: ONE customers table (channel enum oem / retail / both) and ONE variant_prices table — data shared, views scoped. What separates Retail from Sell: screens, numbering series (RS- vs SO-), CRM shape (book vs pipeline), e-invoicing path (consolidated vs per-order).
  • Price memory autofill is the speed trick: staff confirm what the customer paid last time instead of asking the boss; the band sub-line gives negotiation room at a glance.
  • Floor policy is a hard lock, not a nag — the 2.80 line here is the live Kedai Pak Din case pending on Retail → Price lists and the owner's approvals queue. "Approve once" clears this line only; the 3.00 floor stays.
  • Save draft keeps locked lines attached so the sale completes in one tap after approval — nothing is retyped, nothing ships early.

Customer

Not saved

The one required field.

ONE customers table shared with OEM. both = also visible in Sell → Customers and gets a per-sale B2B e-invoice instead of joining the monthly consolidation. A kedai that grows into OEM just flips to both and keeps its history.

Routes e-invoicing per sale via QBO. Auto-on (and locked) when channel = both.

No price fields here — price memory builds itself from confirmed sales; the floor lives in variant_prices (owner-edited in Sell → Price lists).