# Dimension-Based Inventory System Design

## Executive Summary

This document outlines the design for implementing a dimension-based inventory system for Raw Materials (RM), specifically for clothing/fabric materials. This system will track materials by dimensions (length × width) with units, manage waste/reusable pieces, and support cutting operations that generate usable products and waste.

## Current System Analysis

### Current State
- **BOM Items**: Track `quantity_per_unit` (DECIMAL) - simple quantity-based
- **RM Inventory**: Tracked by quantity only (no dimensions)
- **RM Products**: Use `track_inventory = false` (quantity-based, not UUID-based)
- **Production**: Consumes RM by quantity, creates FG by quantity
- **Procurement (GRN)**: Receives RM by quantity and unit_cost

### Critical Requirement
**For RM products, dimension-based tracking is MANDATORY - there is no shortcut or fallback to quantity-based tracking.**
- All RM products MUST use dimension-based tracking
- Production for RM MUST use dimension-based material allocation
- Procurement (GRN) for RM MUST create dimension-based inventory pieces
- No quantity-based fallback for RM products

### Special Items (Non-Dimension RM)
**Important**: Not all RM products work with length × width dimensions. Some items like zippers, buttons, threads, snaps, and other hardware/accessories are needed to complete a garment but are tracked by quantity, not dimensions.
- These items are still RM products but use quantity-based tracking (not dimension-based)
- They must be included in BOMs for complete garment production
- They require inventory tracking but by quantity (not l×w)
- Examples: Zippers, buttons, snaps, hooks, threads, labels, tags, etc.

### Limitations
1. Cannot track materials by dimensions (e.g., 6m × 4m fabric)
2. Cannot specify BOM requirements by dimensions (e.g., need 2m × 1.5m per garment)
3. Cannot track waste/reusable pieces after cutting
4. Cannot reuse waste from one production for another product
5. Cannot track usable vs. available dimensions for materials
6. Cannot handle dimension-based purchasing (e.g., buy 6m × 6m fabric)

## Requirements

### 1. Dimension-Based Purchasing
- Purchase materials by dimensions: `length × width × quantity` (e.g., 6m × 6m × 2 pieces)
- Support multiple units: inches, cm, meters
- Store unit of measure per product
- Calculate total area/volume for cost allocation
- **Multiple Dimension Scenarios**: The same product can be purchased/received in different dimensions
  - Example: "Cotton Fabric" received as:
    - 2m × 2m × 5 pieces
    - 3m × 3m × 3 pieces  
    - 6m × 6m × 2 pieces
    - 6m × 2m × 4 pieces
    - 2m × 6m × 4 pieces
  - Each dimension set creates separate inventory pieces (tracked individually)
  - All pieces belong to the same product but have different dimensions
  - System tracks each piece separately in `rm_inventory_pieces` table

### 2. Dimension-Based BOM
- BOM items specify required dimensions (length × width) with units
- Example: "Fabric: 2m × 1.5m per unit" instead of "Fabric: 3m² per unit"
- Support multiple dimensions per BOM item (if needed)
- Validate that available material dimensions are sufficient

### 3. Waste Tracking
- Track three types of material states:
  - **Remaining/Usable**: Material that can still be used for production
  - **Waste (Reusable)**: Cut pieces that can be used by other products if dimensions are sufficient
  - **Scrap (Non-Reusable)**: Material that cannot be used (to be written off)

### 4. Waste Reuse
- Waste pieces can be allocated to other BOM items if dimensions meet requirements
- System should suggest waste pieces that match BOM requirements
- Waste pieces become "usable" when allocated to a production order

### 5. RM Inventory Tracking
- **NOT by UUIDs** (different from Finished Goods)
- Track by:
  - **Quantity**: Number of pieces
  - **Full Dimensions**: Original dimensions of each piece (l × w × units)
  - **Usable Dimensions**: Dimensions still available for use (after cuts)
  - **Available Dimensions (to be written off)**: Scrap dimensions

### 6. Production Operations
- Production can reduce material size:
  - Cut material → Creates FG product
  - Remaining material → Becomes usable piece or waste
  - Small pieces → Become scrap (written off)

## Proposed System Design

### 1. Database Schema Changes

#### 1.1 Product Model Enhancement
Add dimension tracking fields to `products` table:
```sql
ALTER TABLE products ADD COLUMN unit_of_measure ENUM('inch', 'cm', 'm') DEFAULT 'm';
ALTER TABLE products ADD COLUMN track_by_dimensions BOOLEAN DEFAULT FALSE;
```

**For RM Products**:
- **Dimension-Based RM** (fabric, leather, etc.):
  - `track_by_dimensions`: MUST be `TRUE` for dimension-based RM products (enforced at application level)
  - `unit_of_measure`: Default unit for this product (can be overridden per inventory piece)
  - Validation: If `product_type = 'RM'` and product is dimension-based, then `track_by_dimensions = TRUE` (enforced)
- **Special Items RM** (zippers, buttons, etc.):
  - `track_by_dimensions`: MUST be `FALSE` for special items (quantity-based tracking)
  - These items use standard quantity-based inventory tracking (not dimension-based)
  - Examples: Zippers, buttons, snaps, threads, labels, tags, hooks, etc.
- Migration: Set `track_by_dimensions = TRUE` for existing dimension-based RM products, `FALSE` for special items

**Note**: 
- FG products can use UUID-based tracking
- Dimension-based RM products MUST use dimension-based tracking (l×w)
- Special items RM use quantity-based tracking (no dimensions)

#### 1.2 New Table: `rm_inventory_pieces`
Store individual pieces of RM with dimensions:
```sql
CREATE TABLE rm_inventory_pieces (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  product_id BIGINT NOT NULL,
  grn_item_id BIGINT NULL, -- Link to original GRN item
  piece_number INT NOT NULL, -- Piece number within a purchase (e.g., piece 1 of 2)
  
  -- Dimensions
  length DECIMAL(12, 3) NOT NULL,
  width DECIMAL(12, 3) NOT NULL,
  unit ENUM('inch', 'cm', 'm') NOT NULL DEFAULT 'm',
  
  -- Status tracking
  status ENUM('FULL', 'USABLE', 'WASTE', 'SCRAP') NOT NULL DEFAULT 'FULL',
  
  -- Current usable dimensions (after cuts)
  usable_length DECIMAL(12, 3) NULL,
  usable_width DECIMAL(12, 3) NULL,
  
  -- Scrap dimensions (to be written off)
  scrap_length DECIMAL(12, 3) DEFAULT 0,
  scrap_width DECIMAL(12, 3) DEFAULT 0,
  
  -- Metadata
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
  updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  
  FOREIGN KEY (product_id) REFERENCES products(id) ON DELETE CASCADE,
  FOREIGN KEY (grn_item_id) REFERENCES grn_items(id) ON DELETE SET NULL,
  INDEX idx_product_status (product_id, status),
  INDEX idx_status (status)
);
```

#### 1.3 New Table: `rm_cutting_operations`
Track cutting operations and resulting pieces:
```sql
CREATE TABLE rm_cutting_operations (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  production_order_id BIGINT NOT NULL,
  rm_piece_id BIGINT NOT NULL, -- Original piece being cut
  bom_item_id BIGINT NOT NULL,
  
  -- Dimensions cut
  cut_length DECIMAL(12, 3) NOT NULL,
  cut_width DECIMAL(12, 3) NOT NULL,
  unit ENUM('inch', 'cm', 'm') NOT NULL,
  
  -- Resulting pieces
  remaining_piece_id BIGINT NULL, -- If piece has remaining usable material
  waste_pieces JSON NULL, -- Array of waste pieces created: [{length, width, status: 'WASTE'}]
  scrap_dimensions JSON NULL, -- Scrap dimensions: {length, width}
  
  -- Metadata
  cut_by_user_id BIGINT NULL,
  cut_at DATETIME DEFAULT CURRENT_TIMESTAMP,
  
  FOREIGN KEY (production_order_id) REFERENCES production_orders(id) ON DELETE CASCADE,
  FOREIGN KEY (rm_piece_id) REFERENCES rm_inventory_pieces(id) ON DELETE CASCADE,
  FOREIGN KEY (bom_item_id) REFERENCES bom_items(id) ON DELETE CASCADE,
  FOREIGN KEY (cut_by_user_id) REFERENCES users(id) ON DELETE SET NULL,
  INDEX idx_production_order (production_order_id),
  INDEX idx_rm_piece (rm_piece_id)
);
```

#### 1.4 Enhanced BOMItem Model
Add dimension requirements to `bom_items` table:
```sql
ALTER TABLE bom_items ADD COLUMN required_length DECIMAL(12, 3) NULL;
ALTER TABLE bom_items ADD COLUMN required_width DECIMAL(12, 3) NULL;
ALTER TABLE bom_items ADD COLUMN dimension_unit ENUM('inch', 'cm', 'm') NULL;
ALTER TABLE bom_items ADD COLUMN use_dimensions BOOLEAN DEFAULT FALSE;
```
- `use_dimensions`: Flag to enable dimension-based BOM (vs. quantity-based)
- `required_length`, `required_width`: Required dimensions per unit of FG
- `dimension_unit`: Unit for dimensions

#### 1.5 Enhanced GRNItem Model
Add dimension fields to `grn_items` table:
```sql
ALTER TABLE grn_items ADD COLUMN piece_length DECIMAL(12, 3) NULL;
ALTER TABLE grn_items ADD COLUMN piece_width DECIMAL(12, 3) NULL;
ALTER TABLE grn_items ADD COLUMN dimension_unit ENUM('inch', 'cm', 'm') NULL;
ALTER TABLE grn_items ADD COLUMN pieces_count INT DEFAULT 1;
```
- `piece_length`, `piece_width`: Dimensions of each piece
- `pieces_count`: Number of pieces (e.g., 2 pieces of 6m × 6m)
- `dimension_unit`: Unit for dimensions

#### 1.6 Enhanced Inventory Model (for RM)
Add dimension summary fields to `inventories` table:
```sql
ALTER TABLE inventories ADD COLUMN total_full_area DECIMAL(15, 3) NULL;
ALTER TABLE inventories ADD COLUMN total_usable_area DECIMAL(15, 3) NULL;
ALTER TABLE inventories ADD COLUMN total_waste_area DECIMAL(15, 3) NULL;
ALTER TABLE inventories ADD COLUMN total_scrap_area DECIMAL(15, 3) NULL;
ALTER TABLE inventories ADD COLUMN dimension_unit ENUM('inch', 'cm', 'm') NULL;
```
These are calculated/aggregated fields for quick reporting (denormalized).

### 2. Business Logic Changes

#### 2.1 Procurement (GRN Processing)
**Current**: Create inventory by quantity
**New (MANDATORY for RM)**: 
- **For RM products**: Dimension-based tracking is REQUIRED
  - Validate: If `product.product_type = 'RM'`, dimensions MUST be provided
  - Create `rm_inventory_pieces` records (one per piece)
  - Set `status = 'FULL'`, store `length`, `width`, `unit`
  - Update `inventories` quantity (count of pieces) and area fields
  - Reject GRN items for RM products without dimensions
- **For FG products**: Continue using existing UUID-based logic

#### 2.2 BOM Definition
**Current**: `quantity_per_unit` (e.g., 3m²)
**New**:
- **For Dimension-Based RM products in BOM**: Dimension-based requirements are REQUIRED
  - `use_dimensions` MUST be `TRUE` for dimension-based RM products
  - Specify `required_length × required_width` with `dimension_unit`
  - Validate units match between BOM and material pieces
  - Calculate area requirement: `required_length × required_width × production_quantity`
  - Reject BOM items for dimension-based RM products without dimensions
- **For Special Items RM in BOM**: Quantity-based requirements
  - `use_dimensions` MUST be `FALSE` for special items
  - Use `quantity_per_unit` (standard quantity-based tracking)
  - Example: "Zipper: 1 per unit", "Button: 6 per unit"
  - These items are tracked by quantity in inventory
- **For non-RM materials**: Can use quantity-based if needed

#### 2.3 Production Order - Material Allocation
**Current**: Check quantity availability, consume by quantity
**New**:
1. **Material Selection Algorithm**:
   - **For Dimension-Based RM products**: MUST use dimension-based allocation
     - Find available pieces that meet dimension requirements
     - Prefer FULL pieces, then USABLE pieces, then WASTE pieces
     - Consider waste pieces if dimensions are sufficient
     - Validate: `piece.usable_length >= required_length AND piece.usable_width >= required_width`
     - Unit conversion: Convert between units if needed (inch/cm/m)
     - Reject production if no pieces meet dimension requirements
   - **For Special Items RM**: Use quantity-based allocation
     - Check quantity availability from standard inventory
     - Consume by quantity (standard inventory decrement)
     - Example: Allocate 10 zippers, 60 buttons, etc.

2. **Cutting Operation**:
   - Create `rm_cutting_operations` record
   - Update piece status:
     - If piece fully consumed: Set status to 'SCRAP' or mark as consumed
     - If piece partially used: Update `usable_length`/`usable_width`, set status to 'USABLE'
   - Create waste pieces: If cut leaves usable pieces, create new `rm_inventory_pieces` with status 'WASTE'
   - Track scrap dimensions: Small unusable pieces

3. **Waste Reuse**:
   - When allocating materials, check waste pieces first
   - If waste piece dimensions match requirements, allocate it
   - Update waste piece status to 'USABLE' when allocated

#### 2.4 Inventory Queries
**Current**: `SELECT quantity FROM inventories WHERE product_id = X`
**New**:
- Quantity: Count of pieces (`SELECT COUNT(*) FROM rm_inventory_pieces WHERE product_id = X AND status IN ('FULL', 'USABLE', 'WASTE')`)
- Full Area: Sum of FULL pieces area
- Usable Area: Sum of USABLE pieces usable area + WASTE pieces area
- Available Area (to write off): Sum of SCRAP area

### 3. API Changes

#### 3.1 BOM API
- `POST /api/production/boms`: Accept dimension fields in items
- `GET /api/production/boms/:id`: Return dimension fields
- Validation: If `use_dimensions = true`, require `required_length`, `required_width`

#### 3.2 GRN API
- `POST /api/procurement/grns`: Accept dimension fields in items
- `POST /api/procurement/grns/:id/process`: Create `rm_inventory_pieces` if `track_by_dimensions = true`

#### 3.3 Production API
- `POST /api/production/orders/:id/confirm`: 
  - Allocate materials by dimensions
  - Create cutting operations
  - Handle waste/scrap creation
- `GET /api/production/orders/:id/material-allocation`: Show allocated pieces with dimensions

#### 3.4 Inventory API
- `GET /api/inventory/rm/:productId/pieces`: List all pieces with dimensions
- `GET /api/inventory/rm/:productId/summary`: Get aggregated dimensions (full/usable/waste/scrap)
- `POST /api/inventory/rm/:productId/write-off`: Write off scrap dimensions

### 4. Frontend Changes

#### 4.1 Product Form
- Add "Track by Dimensions" checkbox for RM products
- Add "Unit of Measure" dropdown (inch/cm/m)

#### 4.2 BOM Form
- Add "Use Dimensions" toggle per BOM item
- If enabled, show length/width/unit fields instead of quantity
- Show calculated area (l × w) for reference

#### 4.3 GRN Form
- If product `track_by_dimensions = true`:
  - Show length/width/unit fields
  - Show pieces count
  - Hide quantity field (or make it calculated)

#### 4.4 Production Order
- Show material allocation with dimensions
- Show available pieces with dimensions
- Allow manual piece selection
- Show cutting operation results (waste/scrap created)

#### 4.5 Inventory Page (RM)
- Show dimension summary (full/usable/waste/scrap areas)
- List individual pieces with dimensions
- Filter by status (FULL/USABLE/WASTE/SCRAP)
- Show cutting history per piece

## Implementation Phases

### Phase 1: Database Schema
1. Create migration scripts for all schema changes
2. Add new models (RMInventoryPiece, RMCuttingOperation)
3. Update existing models (Product, BOMItem, GRNItem, Inventory)

### Phase 2: Backend Core Logic
1. Update GRN processing to create dimension-based pieces
2. Update BOM validation and creation
3. Implement material allocation algorithm
4. Implement cutting operation logic
5. Update inventory queries and services

### Phase 3: API Updates
1. Update BOM APIs
2. Update GRN APIs
3. Update Production APIs
4. Create new Inventory RM APIs

### Phase 4: Frontend Implementation
1. Update Product form
2. Update BOM form
3. Update GRN form
4. Update Production order interface
5. Update Inventory RM pages

### Phase 5: Testing & Migration
1. Unit tests for dimension calculations
2. Integration tests for cutting operations
3. Migration script for existing data (if applicable)
4. User acceptance testing

## Edge Cases & Considerations

1. **Unit Conversions**: Handle conversions between inch/cm/m
2. **Fractional Dimensions**: Support decimal dimensions (e.g., 1.5m)
3. **Orientation**: Consider material orientation (length vs width) - may need rotation logic
4. **Minimum Usable Size**: Define minimum dimensions for "usable" vs "scrap"
5. **Waste Matching**: Algorithm to match waste pieces to BOM requirements
6. **Multiple Cuts**: Handle pieces that are cut multiple times
7. **Cost Allocation**: How to allocate cost to waste/scrap pieces
8. **Reporting**: Reports for waste utilization, material efficiency

## Migration Strategy

1. **Mandatory Dimension-Based for RM**: All RM products MUST use dimension-based tracking
2. **Data Migration**: 
   - Existing RM inventory: Need to convert quantity-based to dimension-based
   - Options:
     a) Manual entry: User enters dimensions for existing stock
     b) Default dimensions: Assign default dimensions based on product type (with user confirmation)
     c) Mark as "needs dimension entry" and require before next operation
3. **No Fallback**: RM products cannot use quantity-based logic - dimensions are required
4. **Enforcement**: 
   - Validation at product creation: RM products must have `track_by_dimensions = TRUE`
   - Validation at GRN: RM products must have dimensions
   - Validation at BOM: RM items must have dimension requirements
   - Validation at Production: RM allocation must use dimensions

## Open Questions

1. Should we support 3D dimensions (length × width × height) for some materials?
2. How to handle material thickness (if relevant)?
3. Should waste pieces be automatically allocated, or manual selection?
4. How to handle material that degrades over time (e.g., fabric that shrinks)?
5. Should we track material orientation (grain direction for fabric)?
6. **Migration of existing RM inventory**: How to handle existing quantity-based RM stock?
   - Option A: Require manual dimension entry before next operation
   - Option B: Assign default dimensions with user confirmation
   - Option C: Create "unknown dimension" pieces that must be updated

## Next Steps

1. Review and approve this design document
2. Create detailed database migration scripts
3. Implement Phase 1 (Database Schema)
4. Implement Phase 2 (Backend Core Logic)
5. Continue with remaining phases

---

## Critical Implementation Notes

### Enforcement Rules (MANDATORY)
1. **Product Creation**: 
   - If `product_type = 'RM'` and product is dimension-based (fabric, leather, etc.), automatically set `track_by_dimensions = TRUE` (cannot be disabled)
   - If `product_type = 'RM'` and product is special item (zippers, buttons, etc.), set `track_by_dimensions = FALSE` (quantity-based)
2. **GRN Processing**: 
   - Dimension-based RM products MUST have `piece_length`, `piece_width`, `pieces_count`, and `dimension_unit` - reject if missing
   - Special items RM use standard quantity-based GRN processing (no dimensions required)
3. **BOM Creation**: 
   - Dimension-based RM products in BOM MUST have `use_dimensions = TRUE` with `required_length`, `required_width`, `dimension_unit` - reject if missing
   - Special items RM in BOM MUST have `use_dimensions = FALSE` with `quantity_per_unit` - reject if missing
4. **Production Confirmation**: 
   - Dimension-based RM allocation MUST use dimension-based algorithm (no quantity fallback)
   - Special items RM allocation uses standard quantity-based inventory consumption
5. **Inventory Queries**: 
   - Dimension-based RM products MUST query `rm_inventory_pieces` table, not just `inventories.quantity`
   - Special items RM products use standard `inventories.quantity` tracking

### Validation Points (Enforce at Each Layer)
- **Product Model**: 
  - Validate dimension-based RM products have `track_by_dimensions = TRUE` (auto-set if not)
  - Validate special items RM have `track_by_dimensions = FALSE` (quantity-based)
- **GRN Service**: 
  - Validate dimension-based RM items have dimensions before processing
  - Allow special items RM to use standard quantity-based processing
- **BOM Service**: 
  - Validate dimension-based RM items have dimension requirements before saving
  - Validate special items RM have quantity requirements (not dimensions)
- **Production Service**: 
  - Validate dimension-based allocation for dimension-based RM (reject quantity-based)
  - Allow quantity-based allocation for special items RM
- **Inventory Service**: 
  - Use `rm_inventory_pieces` for dimension-based RM products
  - Use standard `inventories.quantity` for special items RM products

### No Shortcuts Policy
- **Procurement**: 
  - Dimension-based RM products CANNOT be received without dimensions
  - Special items RM can be received with standard quantity-based processing
- **Production**: 
  - Dimension-based RM materials CANNOT be allocated without dimension matching
  - Special items RM use standard quantity-based allocation
- **BOM**: 
  - Dimension-based RM items CANNOT be added without dimension requirements
  - Special items RM items CANNOT be added without quantity requirements
- **Inventory**: 
  - Dimension-based RM stock CANNOT be tracked by quantity alone (must use dimensions)
  - Special items RM stock are tracked by quantity (standard inventory)

---

**Document Version**: 1.1  
**Date**: 2026-01-13  
**Last Updated**: 2026-01-13  
**Author**: System Design Team  
**Status**: Ready for Implementation - Dimension-based tracking is MANDATORY for RM (no shortcuts)
