# POS System - Complete Requirements Specification

## Table of Contents
1. [Product Types & Sellability](#product-types--sellability)
2. [Stock Management & Fulfillment](#stock-management--fulfillment)
3. [Payment System](#payment-system)
4. [M-Pesa Integration](#mpesa-integration)
5. [Role-Based Permissions](#role-based-permissions)
6. [User Interface Requirements](#user-interface-requirements)

---

## 1. Product Types & Sellability

### 1.1 Product Classification
- **FG (Finished Goods)**: Default sellable on POS (`sell_on_pos = true` by default)
- **RM (Raw Materials)**: Default NOT sellable (`sell_on_pos = false` by default)
  - Can be enabled for POS sales via:
    - Product flag: `sell_on_pos = true`
    - Manager approval at time of sale
    - System-wide policy (configurable)

### 1.2 RM Sales Rules
- ✅ **Allowed** when:
  - `sell_on_pos = true` flag is set
  - Manager approves (manager/admin role)
  - System policy allows RM sales
- ❌ **Blocked** by default to prevent accidental BOM input sales
- **Notification**: Cashier must be warned when selling RM items

---

## 2. Stock Management & Fulfillment

### 2.1 Stock Checking
**When Adding to Cart:**
- System checks `available_quantity` vs `requested_quantity`
- **Sufficient Stock**: Add normally, no warning
- **Insufficient Stock**: 
  - ⚠️ Show warning: "Only X available, Y requested. Will create preorder for (Y-X)"
  - Allow cashier to proceed
  - Track separately for fulfillment

**Visual Indicators:**
- ✅ Green badge: "In Stock" (sufficient)
- ⚠️ Yellow badge: "Low Stock" (< threshold)
- 🔴 Red badge: "Out of Stock" (0 available)
- 📋 Blue badge: "Preorder Required" (insufficient)

### 2.2 Auto-Split Fulfillment
**At Checkout:**
- **Available Quantity**: Sold immediately (POS_SALE type)
  - Stock deducted immediately
  - Normal receipt generated
- **Shortfall Quantity**: Auto-converted to ORDER/PREORDER
  - No stock deduction for shortfall
  - Separate line item with status "PREORDERED"
  - Deposit requirement applied (manager-configurable %)

**Example:**
```
Product: Winter Jacket
Requested: 5
Available: 2
→ 2 sold immediately (stock deducted)
→ 3 preordered (no stock deduction, deposit required)
```

### 2.3 Deposit Policy
- **Manager Configurable**: 
  - Minimum deposit % (e.g., 50%)
  - Default deposit % for preorders
  - Store in system settings/config table
- **Applied to**: All preordered/backordered items
- **Payment Methods**: Any allowed (Cash, M-Pesa, Card, etc.)

### 2.4 Sale Types / Fulfillment Intent

| Type | Stock Deduction | Payment Required | When Used |
|------|----------------|------------------|-----------|
| `POS_SALE` | Immediate | Full | All items available, immediate sale |
| `ORDER` | Reserved (optional) | Deposit (manager-set %) | Stock shortfall, customer waiting |
| `PREORDER` | None | Deposit (manager-set %) | Not in inventory yet |
| `LAYAWAY` | Reserved | Partial payments | Installment plan sales |
| `SPLIT_FULFILLMENT` | Partial | Mixed | Some items available, some preordered |

### 2.5 Tracking Requirements
- **Sold Items**: Linked to `POS_SALE`, stock deducted
- **Preordered Items**: Linked to `ORDER`/`PREORDER`, separate fulfillment queue
- **Notifications**: Manager/admin can see fulfillment queue
- **Separate Receipts**: 
  - Receipt for immediate sale
  - Order confirmation for preordered items

---

## 3. Payment System

### 3.1 Split Payment Support
**Maximum Tenders**: **2 payments per sale**

**Tender Types:**
| Code | Label | Processing | Change Given? |
|------|-------|------------|---------------|
| `CASH` | Cash | Instant | ✅ Yes |
| `MPESA` | M-Pesa | Pending (STK/C2B) | ❌ No |
| `CARD` | Card (Manual) | Instant (manual entry) | ❌ No |
| `BANK_TRANSFER` | Bank Transfer | Manual confirmation | ❌ No |

### 3.2 Split Payment Rules
- Sum of tenders **≥ Sale Total** (or allow partial for preorders with deposit)
- **Change Calculation**: Only from Cash tenders
  - If M-Pesa overpaid, no change (refund if necessary)
- **Order Matters**: 
  - Cash entered first → change from cash
  - M-Pesa/Card first → may need cash top-up for change
- **Validation**:
  - At least 1 tender required
  - Maximum 2 tenders
  - Total must cover sale amount (or meet deposit requirement for preorders)

### 3.3 Payment Status Flow

**M-Pesa Tender:**
```
PENDING → STK Requested → [Customer accepts] → CONFIRMED
                              OR
                         → [Timeout/Queue] → Fallback to C2B → CONFIRMED
                              OR
                         → [Manual confirmation] → CONFIRMED (manager)
```

**Cash/Card/Other:**
```
PENDING → [Cashier confirms] → CONFIRMED
```

### 3.4 Card Payment Manual Entry
- Cashier enters:
  - Transaction Reference (from external PDQ machine)
  - Amount
  - (Optional) Last 4 digits of card
- Status: Confirmed immediately (no callback needed)
- Receipt: Shows "Card Payment - Ref: XXXXX"

---

## 4. M-Pesa Integration

### 4.1 Primary Method: STK Push (Lipa Na M-Pesa)

**Flow:**
1. Cashier selects M-Pesa tender, enters customer phone number
2. System sends STK Push request to Daraja API
3. Customer receives prompt on phone → Enters PIN
4. Safaricom sends callback to our server
5. System updates payment status to "CONFIRMED"
6. POS UI updates in real-time

**STK Push Retry Logic:**
- If timeout (> 60 seconds) or no response:
  - Retry once automatically
  - If still fails → Offer fallback options (C2B or manual confirmation)

**Timeout Handling:**
- Default: 60 seconds
- Configurable in system settings
- Show countdown timer on POS screen

### 4.2 Fallback: C2B Paybill

**When Used:**
- STK Push queue is long (too many requests)
- STK Push times out after retry
- Customer prefers manual payment

**Flow:**
1. Cashier selects "M-Pesa C2B" option
2. System generates Paybill number + Account Number
3. Cashier displays to customer
4. Customer initiates payment manually
5. System polls Daraja C2B API or receives callback
6. Payment confirmed when matched

**Display Format:**
```
Paybill: 123456
Account: INV-20250105-00123
Amount: Ksh 1,500.00
```

### 4.3 M-Pesa Configuration
- **Daraja API Credentials**: Store securely (env variables)
- **Callback URL**: Configured in Safaricom Developer Portal
- **Environment**: Sandbox (dev) vs Production (live)
- **Transaction Reference**: Format: `POS-{timestamp}-{sale_id}`

### 4.4 Manual M-Pesa Confirmation (Manager Only)
- If STK/C2B fails completely
- Manager can manually confirm M-Pesa payment
- Requires:
  - Transaction Code (from customer's confirmation SMS)
  - Amount
  - Phone Number
- Logged as "Manual Confirmation" with manager ID

---

## 5. Role-Based Permissions

### 5.1 Cashier Permissions
**Allowed:**
- ✅ Sell FG products (in stock)
- ✅ Sell RM products (if `sell_on_pos = true` or manager enabled)
- ✅ Create orders/preorders for out-of-stock items
- ✅ Process split payments (max 2 tenders)
- ✅ Request M-Pesa STK Push
- ✅ Enter card payments manually
- ✅ View own sales/orders for current shift

**Restricted:**
- ❌ Override stock limits (sell negative)
- ❌ Manual M-Pesa confirmation
- ❌ Void/cancel completed sales
- ❌ Process refunds
- ❌ Change deposit % policy
- ❌ Enable/disable RM sales flag

### 5.2 Manager Permissions
**All Cashier Permissions +:**
- ✅ Override stock (sell negative with reason log)
- ✅ Manual M-Pesa confirmation (fallback)
- ✅ Void/cancel sales (with reason)
- ✅ Process refunds
- ✅ Configure deposit % policy
- ✅ Enable/disable RM sales per product
- ✅ View all sales/orders (all shifts, all cashiers)
- ✅ Manage fulfillment queue (convert preorder → sale when stock arrives)
- ✅ Approve RM sales in real-time

### 5.3 Admin Permissions
**All Manager Permissions +:**
- ✅ System-wide configuration
- ✅ Payment gateway settings (Daraja API keys)
- ✅ Role management
- ✅ Audit logs access

---

## 6. User Interface Requirements

### 6.1 Cart Component Updates
**Stock Warnings:**
- When adding item with insufficient stock:
  ```
  ⚠️ Stock Alert
  Only 2 available, 5 requested.
  2 will be sold immediately, 3 will be preordered.
  [Cancel] [Proceed]
  ```

**Visual Badges:**
- Each cart item shows:
  - ✅ "In Stock" (green)
  - ⚠️ "Partial: X available, Y preordered" (yellow)
  - 📋 "Preorder Only" (blue) if 0 in stock

**Separate Line Items:**
- Sold items: Normal display
- Preordered items: Different styling (blue border, "PREORDER" badge)

### 6.2 Checkout/Payment Modal Updates
**Payment Tender Entry:**
```
┌─────────────────────────────────────────────────┐
│ PAYMENT TENDERS (Max 2)          [+ Add Tender]│
├─────────────────────────────────────────────────┤
│ Tender 1:                                        │
│ [Method: Cash ▼] [Amount: 2,000.00] ✅ Received │
│                                                  │
│ Tender 2:                                        │
│ [Method: M-Pesa ▼] [Phone: 0712xxx] ⏳ Pending  │
│ [Request STK Push] [Use C2B]                   │
│                                                  │
│ Total Tendered: 2,000.00                         │
│ Sale Total: 1,850.00                             │
│ Remaining: 0.00                                  │
│ Change (Cash): 150.00                            │
└─────────────────────────────────────────────────┘
```

**M-Pesa STK Push UI:**
- Phone number input
- "Request Payment" button
- Loading spinner with countdown timer
- Status: "Waiting for customer..." / "Payment confirmed" / "Timeout - Retry?"
- Retry button if timeout
- Fallback to C2B button

**Preorder Summary:**
```
┌─────────────────────────────────────────────────┐
│ PREORDER SUMMARY                                │
├─────────────────────────────────────────────────┤
│ Winter Jacket x3                                │
│ Deposit Required: 50% = Ksh 4,500.00            │
│ Balance Due: Ksh 4,500.00 (on delivery)         │
│ Expected Delivery: TBD                          │
└─────────────────────────────────────────────────┘
```

### 6.3 Product Grid Updates
- **RM Products**: Show "RM" badge (warning color)
- **Stock Status**: Real-time stock levels
- **Disabled State**: Gray out if 0 stock AND not allowed for preorder
- **Tooltip**: On hover, show stock info and sellability

### 6.4 Category Filter
**Current Issue**: Categories not working
**Requirements:**
- Filter products by category
- "All Products" shows everything (FG + RM if enabled)
- Category selection updates product grid immediately
- Persist selected category during session

---

## 7. Database Schema Updates Needed

### 7.1 Product Table
```sql
ALTER TABLE products ADD COLUMN sell_on_pos BOOLEAN DEFAULT TRUE;
-- FG: TRUE by default
-- RM: FALSE by default
```

### 7.2 Sale/SaleItem Table
```sql
-- Add fulfillment type
ALTER TABLE sales ADD COLUMN fulfillment_type ENUM('POS_SALE', 'ORDER', 'PREORDER', 'LAYAWAY', 'SPLIT_FULFILLMENT');

-- Add preorder tracking
ALTER TABLE sale_items ADD COLUMN quantity_fulfilled DECIMAL(12,3) DEFAULT 0;
ALTER TABLE sale_items ADD COLUMN quantity_preordered DECIMAL(12,3) DEFAULT 0;
```

### 7.3 Payment Table
```sql
-- Support multiple payments per sale
-- Already exists, just need to ensure one sale can have multiple payments
-- Add tender sequence/order
ALTER TABLE payments ADD COLUMN tender_number INT DEFAULT 1;
ALTER TABLE payments ADD COLUMN mpesa_phone_number VARCHAR(20);
ALTER TABLE payments ADD COLUMN mpesa_transaction_code VARCHAR(50);
ALTER TABLE payments ADD COLUMN card_reference VARCHAR(100);
```

### 7.4 Settings/Config Table
```sql
-- Deposit policy
INSERT INTO settings (key, value, description) VALUES
('preorder_deposit_percentage', '50', 'Minimum deposit % for preorders'),
('mpesa_stk_timeout_seconds', '60', 'STK Push timeout in seconds'),
('mpesa_stk_retry_enabled', 'true', 'Enable STK Push retry');
```

---

## 8. API Endpoints Needed

### 8.1 M-Pesa Integration
- `POST /api/payments/mpesa/stk-push` - Initiate STK Push
- `POST /api/payments/mpesa/callback` - Safaricom callback handler
- `POST /api/payments/mpesa/c2b` - C2B payment confirmation
- `POST /api/payments/mpesa/manual-confirm` - Manual confirmation (manager)

### 8.2 Fulfillment
- `GET /api/sales/preorders` - List pending preorders
- `POST /api/sales/preorders/:id/fulfill` - Convert preorder to sale (when stock arrives)
- `PUT /api/sales/preorders/:id` - Update preorder details

### 8.3 Stock Checking
- `GET /api/products/:id/availability` - Check real-time stock
- `POST /api/sales/check-stock` - Bulk stock check for cart items

---

## 9. Implementation Priority

### Phase 1: Core Split Fulfillment
1. ✅ Stock checking in cart
2. ✅ Auto-split sold vs preordered
3. ✅ Separate tracking for preorders
4. ✅ Deposit calculation

### Phase 2: Split Payments
1. ✅ Multiple tenders per sale (max 2)
2. ✅ Change calculation from cash
3. ✅ Tender status tracking

### Phase 3: M-Pesa Integration
1. ✅ STK Push implementation
2. ✅ Retry logic
3. ✅ C2B fallback
4. ✅ Callback handling
5. ✅ Manual confirmation (manager)

### Phase 4: UI Polish
1. ✅ Category filter fix
2. ✅ Stock warnings
3. ✅ RM badge/indicators
4. ✅ Payment tender UI
5. ✅ Preorder summary display

---

## 10. Testing Scenarios

### 10.1 Stock Scenarios
- ✅ Add item with sufficient stock → No warning
- ✅ Add item with insufficient stock → Warning shown
- ✅ Add 5, only 2 available → Split into 2 sold + 3 preordered
- ✅ Add RM item (not enabled) → Blocked/warning

### 10.2 Payment Scenarios
- ✅ Single cash payment → Change calculated
- ✅ Cash + M-Pesa split → Change from cash only
- ✅ M-Pesa STK success → Payment confirmed
- ✅ M-Pesa STK timeout → Retry offered
- ✅ M-Pesa STK retry fails → C2B fallback
- ✅ Card manual entry → Confirmed immediately
- ✅ Try to add 3rd tender → Blocked (max 2)

### 10.3 M-Pesa Scenarios
- ✅ STK Push initiated → Phone prompt received
- ✅ Customer accepts → Payment confirmed
- ✅ Customer declines → Payment failed
- ✅ Timeout → Retry or C2B fallback
- ✅ Callback received → Status updated

---

## Notes
- All requirements approved and finalized
- Ready for implementation
- No coding started yet - this is the specification document

