# Item Weight Field Design

## Overview

Add a "Weight" field to support more accurate cost estimation in the tender management system. Weight serves as a flexible numeric multiplier for cost calculations (quantity × weight × rate).

## Requirements Summary

- Add Weight field at project-item level, with master-item default
- Editable both in project detail and via import
- Integrate into cost calculation and reports
- Include in import templates

---

## Database Changes

### 1. Item Model (Master Items)

Add `defaultWeight` field:

```prisma
model Item {
  // ... existing fields
  defaultWeight Decimal? @db.Decimal(12, 4)
  // ...
}
```

- **Type**: Decimal(12, 4) — allows precision for dimensional calculations
- **Nullable**: Yes — optional, only set when needed
- **Purpose**: Default weight for this item type; auto-fills when adding to project

### 2. ProjectItem Model

Add `weight` field:

```prisma
model ProjectItem {
  // ... existing fields
  weight Decimal? @db.Decimal(12, 4)
  // ...
}
```

- **Type**: Decimal(12, 4)
- **Nullable**: Yes — uses defaultWeight if not set
- **Purpose**: Project-specific weight override

### 3. ProjectSpecificItem Model

Add `weight` field:

```prisma
model ProjectSpecificItem {
  // ... existing fields
  weight Decimal? @db.Decimal(12, 4)
  // ...
}
```

- **Type**: Decimal(12, 4)
- **Nullable**: Yes
- **Purpose**: Weight for custom/non-catalog items

---

## Cost Calculation Formula

```
effectiveWeight = projectItem.weight ?? projectSpecificItem.weight ?? item.defaultWeight ?? 1.0
totalCost = quantity × effectiveWeight × estimatedRate
```

### Implementation

Create a helper function:

```typescript
function calculateItemTotal(
  quantity: Decimal,
  estimatedRate: Decimal,
  weight?: Decimal | null,
  defaultWeight?: Decimal | null
): Decimal {
  const effectiveWeight = weight ?? defaultWeight ?? new Decimal(1.0);
  return quantity.mul(effectiveWeight).mul(estimatedRate);
}
```

### Affected Calculations

| Component | File(s) | Update Required |
|-----------|---------|------------------|
| Project item totals | `project.router.ts` | Recalculate on save |
| BOQ totals | `boq.router.ts` | Include weight |
| Category bundle aggregation | `categoryTender.service.ts` | Include weight |
| Reports | `report.router.ts` | Include in outputs |
| Print exports | `print-export.ts` | Include column |
| Bid comparison | `bidComparisonTable.tsx` | Show weight-adjusted totals |

---

## API Changes

### Item Router

Add `defaultWeight` to create/input:

```typescript
item.create: adminProcedure
  .input(z.object({
    // ... existing
    defaultWeight: z.number().optional(),
  }))
```

### Project Router

Add `weight` to item operations:

```typescript
project.addItems: adminProcedure
  .input(z.object({
    items: z.array(z.object({
      // ... existing
      weight: z.number().optional(),
    })),
  }))

project.updateItem: adminProcedure
  .input(z.object({
    itemId: z.string(),
    quantity: z.number(),
    estimatedRate: z.number().optional(),
    weight: z.number().optional(),  // NEW
  }))
```

---

## UI Changes

### 1. Project Detail Page (`/projects/[id]`)

**Item Table** — Add Weight column:

| Code | Name | Unit | Quantity | Weight | Rate | Total |
|------|------|------|----------|--------|------|------|
| ITM-001 | PCC (1:2:4) | m³ | 150 | 1.0 | 4500 | 675,000 |

- Add inline edit for Weight (decimal input)
- Show effective weight (project weight or default from master)

### 2. Item Catalog Page (`/items`)

**Add/Edit Form** — Add defaultWeight field:

```
- Default Weight: [________] ( optional, defaults to 1.0 if empty )
```

### 3. BOQ Page

Include Weight in table and exports.

---

## Import Templates

### 1. Item Import Template (`items_import_template.xlsx`)

Add column:

| code | name | description | unit | categoryCode | rate | defaultWeight |
|------|------|-------------|------|---------------|------|---------------|
| ITM-001 | PCC (1:2:4) | Concrete mix | m³ | CONCRETE | 4500 | 1.0 |

### 2. Project Items Import Template (`import_template.csv`)

Update headers:

```
Item Code,Quantity,Estimated Rate,Weight,Notes
ITM-001,150,4500,1.0,Foundation work
```

---

## Validation Rules

1. **Numeric**: Weight must be a valid number
2. **Non-negative**: Weight >= 0 (zero weight = no quantity)
3. **Range**: Recommended 0.001 - 9999.9999 (configurable)
4. **Default**: If null, uses 1.0 for calculations

---

## Reports & Print Exports

### BOQ Report

Show columns:
- Item Code, Name, Unit, Quantity, **Weight**, Rate, Total

### Tender Document

Include weight information per item.

### Bid Comparison

Show weight-adjusted totals in comparison table.

---

## Backward Compatibility

- **Default to 1.0**: Null weight treated as 1.0, so existing calculations unchanged
- **Migration**: All existing items get weight = null (uses default 1.0)
- **No breaking changes**: Existing tender logic continues to work

---

## Files to Modify

| # | File | Change |
|---|------|--------|
| 1 | `prisma/schema.prisma` | Add fields |
| 2 | `src/lib/types/item.ts` | Add type |
| 3 | `src/server/routers/item.router.ts` | Update CRUD |
| 4 | `src/server/routers/project.router.ts` | Update item ops |
| 5 | `src/server/routers/boq.router.ts` | Add weight to calculation |
| 6 | `src/app/(dashboard)/projects/[projectId]/page.tsx` | Add UI column |
| 7 | `src/app/(dashboard)/items/page.tsx` | Add defaultWeight field |
| 8 | `src/app/(dashboard)/items/import/page.tsx` | Update template |
| 9 | `src/components/project/import-items-dialog.tsx` | Update template |
| 10 | `src/lib/print-export.ts` | Add weight column |
| 11 | `src/components/bids/BidComparisonTable.tsx` | Show weight |
| 12 | `src/server/routers/report.router.ts` | Add weight to reports |

---

## Testing Considerations

1. Unit tests for calculation helper
2. Import validation tests
3. UI behavior tests (inline edit)
4. Integration tests (full tender flow with weight)