# Sales & Purchases UI Architecture Map

**Visual reference showing how Sales and Purchases forms share patterns and reusable components**

---

## Current Architecture (Before Refactoring)

```
┌─────────────────────────────────────────────────────────────────┐
│                    Purchases Invoice Form                       │
│  components/admin/purchase-order-form.tsx (~1500 lines)        │
├─────────────────────────────────────────────────────────────────┤
│  • Supplier selection (inline)                                  │
│  • Line items table (500 lines, inline)                        │
│  • Column resizing, keyboard nav (inline)                      │
│  • Calculations (inline)                                       │
│  • Party logic (supplier/customer toggle, inline)              │
│  • Payment methods (inline)                                    │
│  • Currency/Exchange (inline)                                  │
│  • Discount & Tax (inline)                                     │
│  • Documents upload (inline)                                   │
└─────────────────────────────────────────────────────────────────┘
                            ↓ Uses
        ┌─────────────────────────────────────────────┐
        │       Base UI Components (shadcn/ui)        │
        │  Card, Form, Input, Select, Table, etc.    │
        └─────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────┐
│                    Sales Invoice Form                           │
│  components/admin/sales-invoice-form.tsx (~600 lines)          │
├─────────────────────────────────────────────────────────────────┤
│  • Customer selection (duplicate logic from Purchases)         │
│  • Line items table (120 lines, different from Purchases)      │
│  • Basic calculations (inline)                                 │
│  • Simpler structure (fewer features)                          │
│  • NO: Payment methods, currency, documents, complex tax       │
└─────────────────────────────────────────────────────────────────┘
                            ↓ Uses
        ┌─────────────────────────────────────────────┐
        │       Base UI Components (shadcn/ui)        │
        │  Card, Form, Input, Select, Table, etc.    │
        └─────────────────────────────────────────────┘

PROBLEM: ~200+ lines of duplicated logic (table, party selection, calculations)
         No consistency in UX between Purchases and Sales
         Hard to maintain, sync, or reuse
```

---

## Target Architecture (After Refactoring)

```
┌────────────────────────────────────────────────────────────────────────────┐
│                         Invoice Shared Components                          │
│                  components/invoice-shared/ (NEW)                          │
├────────────────────────────────────────────────────────────────────────────┤
│                                                                            │
│  ┌──────────────────────────────────────────────────────────────────────┐ │
│  │  LineItemsTable<T> Component                                        │ │
│  │  • Generic table for any line items                                 │ │
│  │  • Column definitions (configurable)                               │ │
│  │  • Resizable columns (localStorage persistence)                    │ │
│  │  • Keyboard navigation (Tab, F2, arrow keys)                       │ │
│  │  • Row management (add, delete, reorder)                           │ │
│  │  • Dynamic calculations                                            │ │
│  │  • ~350 lines of clean, reusable code                             │ │
│  └──────────────────────────────────────────────────────────────────────┘ │
│                                                                            │
│  ┌──────────────────────────────────────────────────────────────────────┐ │
│  │  PartySelector Component                                            │ │
│  │  • Customer or Supplier selection (type-based)                     │ │
│  │  • Searchable combobox                                             │ │
│  │  • Filterable list (type = 'customer' | 'supplier')               │ │
│  │  • ~150 lines, fully reusable                                     │ │
│  └──────────────────────────────────────────────────────────────────────┘ │
│                                                                            │
│  ┌──────────────────────────────────────────────────────────────────────┐ │
│  │  CalculationDisplay Component                                       │ │
│  │  • Shows subtotal, discount, tax, grand total                      │ │
│  │  • Currency-aware formatting                                       │ │
│  │  • Optional balance display                                        │ │
│  │  • ~100 lines, fully reusable                                     │ │
│  └──────────────────────────────────────────────────────────────────────┘ │
│                                                                            │
│  ┌──────────────────────────────────────────────────────────────────────┐ │
│  │  Helper Functions (lib/modules/shared/)                            │ │
│  │  • calculateTotals(items, discounts, tax, method)                 │ │
│  │  • Shared calculation logic                                        │ │
│  │  • Domain-agnostic (works for Purchases & Sales)                 │ │
│  └──────────────────────────────────────────────────────────────────────┘ │
│                                                                            │
└────────────────────────────────────────────────────────────────────────────┘
                            ↑ Used by both
              ┌─────────────────────────────────┐
              │       Base UI Components         │
              │   (shadcn/ui: Card, Form, etc)  │
              └─────────────────────────────────┘


┌───────────────────────────────────────────────────────────────────────┐
│            Purchases Invoice Form (Refactored)                        │
│  components/admin/purchase-order-form.tsx (~1000 lines)              │
├───────────────────────────────────────────────────────────────────────┤
│                                                                       │
│  const purchaseLineItemColumns = [                                   │
│    { key: 'materialId', label: 'Material', ... },                   │
│    { key: 'quantity', label: 'Qty', ... },                          │
│    { key: 'unitPrice', label: 'Unit Price', ... },                  │
│    { key: 'bonus', label: 'Bonus', ... },         ← Purchases-only │
│    { key: 'taxRate', label: 'Tax %', ... },        ← Purchases-only │
│    // ...                                                            │
│  ];                                                                   │
│                                                                       │
│  <LineItemsTable                                                      │
│    items={gridItems}                                                │
│    columns={purchaseLineItemColumns}  ← Customized columns          │
│    onItemsChange={setGridItems}                                    │
│    storageKey="purchase-order-table-preferences"                  │
│  />                                                                   │
│                                                                       │
│  <PartySelector                                                       │
│    partyType="supplier"    ← Purchases-specific                    │
│    parties={supplierList}                                          │
│    selectedPartyId={selectedSupplierId}                            │
│  />                                                                   │
│                                                                       │
│  BENEFITS:                                                            │
│  ✅ ~500 lines removed (cleaner, more maintainable)                │
│  ✅ All functionality preserved                                    │
│  ✅ Same keyboard nav, resizing, UX                                │
│  ✅ Tests continue to pass                                         │
│                                                                       │
└───────────────────────────────────────────────────────────────────────┘


┌───────────────────────────────────────────────────────────────────────┐
│            Sales Invoice Form (Adapted)                              │
│  components/admin/sales-invoice-form.tsx (~400 lines)               │
├───────────────────────────────────────────────────────────────────────┤
│                                                                       │
│  const salesLineItemColumns = [                                      │
│    { key: 'materialId', label: 'Product', ... },                   │
│    { key: 'quantity', label: 'Qty', ... },                         │
│    { key: 'unitPrice', label: 'Unit Price', ... },                 │
│    { key: 'discount', label: 'Discount', ... },                    │
│    // NO bonus, NO taxRate (sales-specific difference)             │
│  ];                                                                   │
│                                                                       │
│  <LineItemsTable                                                      │
│    items={gridItems}                                                │
│    columns={salesLineItemColumns}  ← Different columns, same table  │
│    onItemsChange={setGridItems}                                    │
│    storageKey="sales-invoice-table-preferences"                   │
│  />                                                                   │
│                                                                       │
│  <PartySelector                                                       │
│    partyType="customer"    ← Sales-specific                        │
│    parties={customers}                                             │
│    selectedPartyId={customerId}                                    │
│  />                                                                   │
│                                                                       │
│  BENEFITS:                                                            │
│  ✅ ~200 lines removed (previously ~600 total)                    │
│  ✅ ~40% code reduction vs previous sales form                    │
│  ✅ Same UX as Purchases (familiar patterns)                      │
│  ✅ Keyboard nav, resizing, error handling all consistent         │
│  ✅ Easy to extend (add new columns to definition)                │
│  ✅ Ready for new Sales features (tax, documents, etc)           │
│                                                                       │
└───────────────────────────────────────────────────────────────────────┘

RESULT: Shared components, zero UI duplication, consistent UX
        Both forms evolve together (fixes benefit both)
        Foundation for future multi-line-item forms (Returns, Credit Notes, etc)
```

---

## Component Hierarchy

```
PurchaseOrderForm
├── <LineItemsTable<PurchaseLineItem>>
│   ├── purchaseLineItemColumns config
│   ├── Column definitions (Material, Qty, Price, Bonus, Tax, etc)
│   └── Uses: Table, Button, Input, Trash2 icon
│
├── <PartySelector>
│   ├── partyType="supplier"
│   ├── supplierList
│   └── Uses: Popover, Button, Input, ScrollArea
│
└── Form fields (existing purchase-specific logic)
    ├── Payment methods
    ├── Currency/Exchange
    ├── Discount & Tax
    └── Documents


SalesInvoiceForm
├── <LineItemsTable<SalesLineItem>>
│   ├── salesLineItemColumns config
│   ├── Column definitions (Product, Qty, Price, Discount only)
│   └── Uses: Table, Button, Input, Trash2 icon
│
├── <PartySelector>
│   ├── partyType="customer"
│   ├── customerList
│   └── Uses: Popover, Button, Input, ScrollArea
│
└── Form fields (existing sales-specific logic)
    ├── Basic calculations
    └── Optional warehouse/shelf
```

---

## Configuration-Driven Design

### Column Definition Example

```typescript
// Same component, different configurations

// PURCHASES: Full-featured line items
const purchaseLineItemColumns = [
  { key: 'materialId', label: 'Material', type: 'select', minWidth: 200 },
  { key: 'quantity', label: 'Qty', type: 'number' },
  { key: 'unitPrice', label: 'Unit Price', type: 'number' },
  { key: 'lineDiscountPercent', label: 'Discount %', type: 'number' },
  { key: 'lineDiscountAmount', label: 'Discount Amount', type: 'number' },
  { key: 'bonus', label: 'Bonus', type: 'number' },         // ← Purchases only
  { key: 'taxRate', label: 'Tax %', type: 'number' },       // ← Purchases only
  { key: 'warehouse', label: 'Warehouse', type: 'select' },
  { key: 'shelf', label: 'Shelf', type: 'select' },
];

// SALES: Simpler line items
const salesLineItemColumns = [
  { key: 'materialId', label: 'Product', type: 'select', minWidth: 200 },
  { key: 'quantity', label: 'Qty', type: 'number' },
  { key: 'unitPrice', label: 'Unit Price', type: 'number' },
  { key: 'lineDiscountPercent', label: 'Discount %', type: 'number' },
  { key: 'lineDiscountAmount', label: 'Discount Amount', type: 'number' },
  // NO bonus, NO taxRate
  { key: 'warehouse', label: 'Warehouse', type: 'select' },
  { key: 'shelf', label: 'Shelf', type: 'select' },
];

// Same component, different columns: <LineItemsTable columns={???} />
```

---

## File Structure After Implementation

```
components/
├── invoice-shared/                    ← NEW: Shared components
│   ├── index.ts
│   ├── line-items-table.tsx          (~350 lines, fully generic)
│   ├── party-selector.tsx             (~150 lines, type-based)
│   ├── calculation-display.tsx        (~100 lines, optional)
│   └── utils/
│       └── line-item-calculations.ts  (shared calculation logic)
│
├── admin/
│   ├── purchase-order-form.tsx        (REFACTORED: -500 lines, cleaner)
│   ├── sales-invoice-form.tsx         (ADAPTED: -200 lines, reuses components)
│   ├── purchase-return-form.tsx       (Can reuse in future)
│   └── ... other forms
│
└── ui/
    └── ... (base components, unchanged)

lib/
├── modules/
│   └── shared/
│       └── invoice-calculations.ts    (Shared calculation functions)
└── ... (existing)
```

---

## Shared Patterns Visualization

```
┌─────────────────────────────────────────────────────────────┐
│         PURCHASES & SALES SHARED PATTERNS                  │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  Pattern 1: Line Item Table                               │
│  ┌───────────────────────────────────────────────────────┐ │
│  │ <LineItemsTable columns={PURCHASES|SALES}_columns /> │ │
│  │ • Column resizing ✅ Both                             │ │
│  │ • Keyboard nav    ✅ Both                             │ │
│  │ • Row ops         ✅ Both                             │ │
│  │ • localStorage    ✅ Both (different keys)           │ │
│  └───────────────────────────────────────────────────────┘ │
│                                                             │
│  Pattern 2: Party Selection                               │
│  ┌───────────────────────────────────────────────────────┐ │
│  │ <PartySelector partyType={SUPPLIER|CUSTOMER} />      │ │
│  │ • Search         ✅ Both                              │ │
│  │ • Filter         ✅ Both                              │ │
│  │ • Selection      ✅ Both                              │ │
│  │ • Type detection ✅ Different (supplier vs customer)  │ │
│  └───────────────────────────────────────────────────────┘ │
│                                                             │
│  Pattern 3: Calculations                                  │
│  ┌───────────────────────────────────────────────────────┐ │
│  │ calculateTotals({ ... }) → { subtotal, tax, total } │ │
│  │ • Discount calc  ✅ Both (same logic)                 │ │
│  │ • Tax calc       ✅ Both (same logic)                 │ │
│  │ • Rounding       ✅ Both (same logic)                 │ │
│  └───────────────────────────────────────────────────────┘ │
│                                                             │
│  CUSTOMIZATION POINTS:                                    │
│  • Column definitions (Purchases: bonus + tax rate)      │
│  • Party type (Purchases: supplier, Sales: customer)     │
│  • Business rules (Purchases: lock, duplicate check)     │
│  • Payment methods (Purchases: full, Sales: none)        │
│                                                             │
└─────────────────────────────────────────────────────────────┘
```

---

## Testing Architecture

```
Components
├── invoice-shared/
│   ├── LineItemsTable.test.ts
│   │   ├── ✅ Renders columns from definition
│   │   ├── ✅ Column resize works
│   │   ├── ✅ localStorage persistence
│   │   ├── ✅ Keyboard navigation
│   │   └── ✅ Row operations (add/delete)
│   │
│   └── PartySelector.test.ts
│       ├── ✅ Filters by search term
│       ├── ✅ Shows correct party type
│       └── ✅ Selection works

Forms
├── purchase-order-form.test.ts
│   ├── ✅ Line items table with purchase columns
│   ├── ✅ Supplier selection works
│   ├── ✅ Calculations correct
│   ├── ✅ Keyboard nav works
│   └── ✅ All existing tests pass
│
└── sales-invoice-form.test.ts
    ├── ✅ Line items table with sales columns
    ├── ✅ Customer selection works
    ├── ✅ Calculations work
    ├── ✅ Column consistency with Purchases
    └── ✅ No regressions
```

---

## Migration Path

```
PHASE 1: Extract Components (Week 1)
├── Create components/invoice-shared/
├── Extract LineItemsTable
├── Extract PartySelector
├── Extract CalculationDisplay
└── ✅ Shared components ready

PHASE 2: Refactor Purchases (Week 1-2)
├── Import shared components
├── Define purchaseLineItemColumns
├── Replace inline table code
├── Replace inline party selection
├── npm run test:purchases → ✅ PASS
└── ✅ Purchases using shared components (no visual change)

PHASE 3: Adapt Sales (Week 2-3)
├── Import shared components
├── Define salesLineItemColumns
├── Use LineItemsTable with sales columns
├── Use PartySelector with customer type
├── Import shared calculations
├── npm run test:sales → ✅ PASS
└── ✅ Sales using shared components (40% code reduction)

OUTCOME: Shared patterns, zero duplication, consistent UX
```

---

## Key Metrics

| Metric | Before | After | Change |
|--------|--------|-------|--------|
| **Purchases LOC** | 1500 | 1000 | -500 (-33%) |
| **Sales LOC** | 600 | 400 | -200 (-33%) |
| **Shared Pattern LOC** | 0 | 600 | +600 |
| **Total LOC** | 2100 | 2000 | -100 (-5%) |
| **Duplicated Logic** | 200+ | 0 | -100% ✅ |
| **Shared Components** | 0 | 3 | +3 |
| **Future Forms** | N/A | Reusable | ✅ |

---

## Benefits

✅ **For Developers**:
- Less code to maintain (base maintained in shared component)
- Faster implementation of new forms
- Consistent UX patterns
- Easier to fix bugs (one fix benefits all)

✅ **For Users**:
- Same keyboard shortcuts everywhere
- Same column resizing behavior
- Same search/filter patterns
- Familiar UI across all forms

✅ **For Business**:
- Faster feature rollout (reuse proven patterns)
- Lower bug rate (shared = well-tested)
- Easier to scale (new forms = new column definitions)

---

## Example: Adding New Column

### Before (Duplicated Code)

```typescript
// In purchase-order-form.tsx
const renderShippingCost = (value: number) => (
  <Input
    type="number"
    value={value}
    onChange={(e) => handleCellEdit('shippingCost', e.target.value)}
  />
);

// In sales-invoice-form.tsx (DUPLICATED)
const renderShippingCost = (value: number) => (
  <Input
    type="number"
    value={value}
    onChange={(e) => handleCellEdit('shippingCost', e.target.value)}
  />
);
```

### After (Single Definition)

```typescript
// In purchase-order-form.tsx
const purchaseLineItemColumns = [
  // ... existing columns ...
  {
    key: 'shippingCost',
    label: 'Shipping Cost',
    type: 'number',
    minWidth: 100,
  },
];

// In sales-invoice-form.tsx (SAME as Purchases, just different columns)
const salesLineItemColumns = [
  // ... existing columns ...
  {
    key: 'shippingCost',
    label: 'Shipping Cost',
    type: 'number',
    minWidth: 100,
  },
];

// Both use: <LineItemsTable columns={...} />
// No rendering code duplication ✅
```

---

## Future Extensibility

```
Forms that can reuse LineItemsTable:
├── ✅ Purchase Orders (DONE)
├── ✅ Sales Invoices (Phase 3)
├── Purchase Returns (Just define returns columns)
├── Sales Credit Notes (Just define credit note columns)
├── Inventory Adjustments (Just define adjustment columns)
├── Material Requisitions (Just define requisition columns)
└── Work Order Line Items (Just define work order columns)

All sharing:
├── Same keyboard navigation
├── Same column resizing
├── Same calculation patterns
├── Same UI look & feel
└── Same testing patterns
```

---

## Summary

**Goal**: Zero UI duplication between Purchases and Sales

**Approach**: Extract reusable components + configure with column definitions

**Result**: 
- Both forms use shared LineItemsTable component
- Different columns = different forms
- Same UX = consistent experience
- Easy maintenance = shared bugs fixed once

**Timeline**: 2-3 weeks for full implementation

**Outcome**: Foundation for all future multi-line-item forms
