Verdict Your requirement is ~70% aligned with the system's design — the engine already does almost everything you described — but 4 concrete defects currently make it not work in the stores. The good news: nothing about your requirement fights the architecture; the fixes are targeted, not a rebuild. What already works (verified end-to-end in code) Master product → all stores sync exists and copies sub_unit_ids and both default units on create and update, remapping unit IDs per business by name. The 3-level unit hierarchy is exactly representable and already set up correctly in your master business: Tablets (base) ← Stripe(1/10) (×10) ← Baby Box(1/10) (×100, intermediate = Strip). Medicine B just uses different unit rows (Stripe(1/15) ×15, Baby Box(1/15) ×225) — that's the intended pattern for per-medicine pack sizes. POS multi-unit selling works exactly as you described (verified trace): cashier picks Strip, qty 1 → screen shows ₹100 (price auto-scales from the per-tablet base price ×10); picks Tablet → ₹10. Stock check converts to the chosen unit ("50 Strip available"), the sale stores 10 tablets @ ₹10 in base units, stock drops by 10, and the receipt prints "1 Strip @ 100". Returns also convert correctly. Purchasing in Baby Box works end-to-end for fresh purchases and purchase orders: 1 Box @ ₹1000 → purchase_lines gets 100 tablets @ ₹10, stock +100 tablets, and the box shows back as "1 Baby Box @ 1000" on edit/print. The default purchase unit preselect works (the field we fixed yesterday). The 4 blockers 1. Store businesses have broken (flat) units — the biggest one. When the sync copies a master product to a store, resolveUnitForBusiness (SuperadminProductController.php:651-668) creates units by name only — no base_unit_id, no multiplier, no intermediate link, and allow_decimal forced to 0. Live DB confirms: all units in stores 2–8 have NULL base/multiplier. The POS unit dropdown is built from the base_unit_id chain, so in those stores the Strip/Tablet selector can never even appear, and any conversion would silently use ×1. (Store 9 works only because its units were hand-built — and even there, one chain is wrong: Stripe(1/50) was made a base with tablet under it.) Unit-definition changes in the master business also never propagate to stores. 2. Default sell unit at POS is dead code. products.default_sell_sub_unit_id is saved and the POS row template checks it, but getDetailsFromVariation (ProductUtil.php:498-549) doesn't select that column, so the preselect silently falls back to the first unit (usually loose Tablet). Your "default = Strip" requirement currently never happens. One-line fix. 3. "Sell only Strip/Tablet, purchase only Box" is not expressible. There's a single per-product unit whitelist (products.sub_unit_ids) feeding both the POS and purchase dropdowns. You can restrict a product to Box-only — but then you can't sell it in Strips. There is no sell-vs-purchase unit split anywhere. This needs a small schema + code change (e.g. sell_sub_unit_ids / purchase_sub_unit_ids columns, a context parameter on getSubUnits(), and server-side validation so POS rejects Box lines and purchases reject Strip/Tablet lines). 4. PO → Purchase conversion is now broken (regression from the preselect). When pulling PO/requisition lines into a purchase, quantities render in base units (100 tablets) while the dropdown now preselects Baby Box — on save it multiplies again → 1 Box PO becomes 10,000 tablets, and the JS also clobbers the PO's negotiated price with default price × multiplier (PurchaseController.php:1235-1271, purchase.js:826-828). Since your flow is "PO in Box → purchase in Box", this must be fixed before go-live. Smaller gaps to plan for enable_sub_units is OFF for store businesses 2–8 (only master and store 9 have it on) — it only gates the product-form UI, but should be enabled everywhere for consistency, including at store creation. Purchase requisitions have no unit support at creation (always base units); opening stock and purchase-CSV-import are base-unit only (import is actively unsafe with a purchase default set — it reinterprets imported quantities as boxes). POS trusts the browser-posted multiplier instead of re-deriving it from the units table (purchase side already re-derives — sell side should match; it's a data-integrity hole). "Prev. unit price" hint on purchase rows shows the per-tablet price next to a per-box input (₹10 vs ₹1000 — confusing but cosmetic). Data hygiene: master product Product CCB references a soft-deleted unit as its default purchase unit; store 9's Stripe(1/50) unit chain needs correction. Recommended implementation order Fix resolveUnitForBusiness to replicate the full hierarchy (base link mapped by name, multiplier, intermediate link, allow_decimal) + a one-time repair command for the existing flat units in stores 2–8 and store 9's bad chain. One-line fix for the POS default-sell-unit preselect. Sell/purchase unit split (two columns + getSubUnits context + server validation + sync them in master-product sync). Fix PO/requisition → purchase conversion (convert quantities to the line's unit before rendering, and stop the price-overwrite on programmatic preselect). Enable enable_sub_units for all stores + on new store creation; then the hardening items (server-side multiplier re-derivation, price hint, requisition units) as a follow-up. With 1, 2, 4 and the store-unit repair done, your exact scenario — superadmin adds Medicine A once; every store sells it in Strip (default) or loose Tablet at auto-scaled prices; purchasing happens in Baby Box — works with the standard pharmacy billing behavior you described. Item 3 is what makes the unit restrictions enforced rather than just defaulted. Say the word and I'll start implementing in that order.