# Online Multi-Store Fulfillment — Full Analysis

**For owners / managers** · Version 2026-09  
**Technical companion:** `docs/ONLINE_MULTI_STORE_FULFILLMENT.php`

---

## Short answer (your scenario)

You have **two warehouses**. A customer places **one order with two items**:

| Item | Available where |
|------|-----------------|
| Item A | Store / Warehouse 1 only |
| Item B | Store / Warehouse 2 only |

### What happens now (Split Orders ON)

1. Website shows both as **In Stock** using the **sum** of Fulfills-online stock.
2. Cart allows both if totals are enough.
3. Checkout prefers **one** location that has both items.
4. If none can, **Split Orders** allocates Item A to Loc1 and Item B to Loc2.
5. Admin order page shows **Fulfillment Locations** so staff pack two shipments.

Keep both locations **Active + Fulfills online = Yes**. Split Orders stays ON under Inventory → Allocation Rules.

---

## How online users see stock

| What customer sees | Source | Meaning |
|--------------------|--------|---------|
| Product page “In Stock (N)” | Sum of available stock at **Fulfills online** locations | Company online sellable qty (e.g. 10@A + 2@B = **12**) |
| Cart / checkout rules | Same online available sum | Can buy if total online stock enough |
| Per-location API | `/api/products/{id}/store-availability` | Which Fulfills-online locations have it |

**Example**

| Product | Branch A | Branch B | Online shown |
|---------|----------|----------|--------------|
| Item 1 | 10 | 2 | **12** |
| Item 2 | 0 | 10 | **10** |

Both products stay visible online while that total is &gt; 0.

---

## How an online order reaches a store / warehouse

```text
Browse → Cart → Checkout → Pay/COD
              → Allocate & Reserve stock
              → Prefer ONE location that has every line
              → Else SPLIT (if Split Orders ON) — each line to best location
              → After payment: stock confirmed
              → Admin packs per Fulfillment Locations on the order
```

### Allocation logic (current)

1. Candidates: **Active + Fulfills online** (or Delivery Zone locations)
2. Prefer a location that can fulfill the **whole** cart
3. If not: **Split Orders** (default ON) — Item A from Loc1, Item B from Loc2
4. Else try central warehouse for the full cart
5. Else fail with a clear stock message

Checkout shows: *“This order may ship from more than one store…”* when a split is expected.

Admin order screen shows a **Fulfillment Locations** packing table for split orders.

---

## Allocation rules (admin)

| Priority | Rule | Default | Real effect today |
|----------|------|---------|-------------------|
| 10 | Store Preference | ON | Pickup / preferred store |
| 20 | Delivery Zone | ON | Pincode → preferred locations |
| 30 | Nearest Store | ON | Weak on web (no lat/lng from checkout) |
| 40 | Highest Stock | ON | Prefers location with more cart stock |
| 50 | Priority Store | ON | Uses location Priority field |
| 90 | Warehouse Fallback | ON | Tries **one** central warehouse |
| 100 | Split Orders | **ON** | Splits lines across locations when needed |
| 110 | Back Orders | **OFF** | Not implemented |

Admin can turn Split OFF under Inventory → Allocation Rules if you want single-shipper-only mode.

---

## Two warehouses — how they work

Both can participate in online allocation if:

- Active = Yes  
- **Fulfills online** = Yes  

They compete like stores (stock + priority).

**Fallback after failure** uses only **`centralWarehouse()`** (default / primary warehouse).  
Your **second warehouse is not auto-tried** as fallback unless it already won as a full-cart candidate.

---

## Worked examples

### Example 1 — Works (one place has both)

- Central WH: Ring ×5, Chain ×5  
- Customer buys Ring + Chain  
→ Order allocates to Central WH → **one shipment**

### Example 2 — Cross-branch cart (Split ON)

- WH Warangal: Ring ×5, Chain ×0  
- WH Hyderabad: Ring ×0, Chain ×5  
- Customer buys Ring + Chain  
→ Cart OK → Checkout **splits** → Ring @ Warangal, Chain @ Hyderabad → two packs

### Example 3 — Prefer single branch when possible

- Branch B: Item1 ×2, Item2 ×10  
- Branch A: Item1 ×10  
- Customer buys Item1 ×1 + Item2 ×1  
→ Branch B can fulfill both → **one shipment from B** (no split)

### Example 4 — POS vs Online

- POS Warangal only sells Warangal stock  
- Online only pulls from locations with **Fulfills online**

---

## Recommended setup (split + multi-branch stock)

1. Mark every location that can ship website orders **Active + Fulfills online = Yes**.  
2. Keep stock in balances at those locations (website “In Stock” = sum of available).  
3. Leave **Split Orders ON** (default) so cross-branch carts can check out.  
4. Optional: Delivery Zones map pincodes → preferred locations.  
5. Pack from Admin → Order → **Fulfillment Locations** when an order splits.  
6. Turn Split OFF only if you want single-shipper-only (then consolidate stock into one location).

**Simpler single-shipper mode:** one warehouse Fulfills online; others No; Split OFF.

---

## Owner decision checklist

- [ ] Who ships website orders? (one WH / each store / multi-ship split)  
- [ ] Which locations have **Fulfills online = Yes**?  
- [ ] Is website sellable stock physically in those locations?  
- [ ] Delivery zones set for your pincodes?  
- [ ] Split Orders ON (default) — staff know to pack per Fulfillment Locations?  
- [ ] Confirm online “In Stock (N)” matches sum of Fulfills-online available  

---

## Diagram (current default)

```text
Cart: Item A + Item B
        │
        ▼
Online stock totals OK? (sum of Fulfills-online)
   no → cannot buy
   yes ↓
Prefer one Fulfills-online location with A AND B
        │
        ▼
Found?
   yes → Reserve all there → Pay → Ship once
   no  ↓
Split Orders ON? (default YES)
   yes → Ship A from Loc1, B from Loc2 → pack per allocations
   no  ↓
Central warehouse has A AND B?
   yes → Ship from central WH
   no  → ORDER FAILS
```
