# Product Need Documentation

## Product Need Overview

Product Need view shows product stock balance development and future needs based on sales orders, production orders, and purchase orders.

## Features

### Progressive Loading

First load returns only product list quickly. Then system calculates weekly needs in background.

- **First call**: Returns product list (`load_mode: 'product_list'`)
- **Second call**: Returns full calculation with weekly needs

### Incremental Update

System sends only changed data when `rec.incremental_update` is enabled.

- **`incremental_update: true`**: Use incremental updates (reduces data transfer)
- **`last_modify_id`**: Tracks latest modify ID for each table

### Constants (rec.json)

| Name | Default | Description |
|------|---------|-------------|
| `incremental_update` | `true` | Use incremental updates |
| `last_modify_id` | `{}` | Last modify ID per table |
| `weekly_need` | `false` | Show weekly view |
| `hide_empty` | `true` | Hide empty rows |
| `only_need` | `true` | Show only products with need |
| `has_error` | `false` | Show only errors |
| `find_text` | `""` | Search text |
| `find_delay_seconds` | `0.4` | Search delay in seconds |
| `find_min_characters` | `1` | Minimum characters for search |

### Views (view)

| Value | Description |
|-------|-------------|
| `product-need` | Product need view |
| `graph` | Graph view |
| `planned` | Planned |
| `actual` | Actual |
| `checked` | Checked |
| `timecard` | Timecard |
| `capacity` | Capacities |
| `resource_efficiency` | Resource efficiency |
| `shift` | Shifts |

### Need Views (need_view)

| Value | Description |
|-------|-------------|
| `balance` | Balance view (weekly) |
| `need` | Need view (detailed) |

### Chart Types (chart_type)

| Value | Description |
|-------|-------------|
| `stock_balance` | Stock balances |
| `product_tree` | Product tree |
| `work_phase` | Work phases |
| `product-need` | Product need (disabled) |

### Calculation Parameters

| Parameter | Description |
|-----------|-------------|
| `reload_data` | Force full reload |
| `create_schedule` | Create schedule |
| `virtual_production_order` | Virtual production order |
| `estimate_order` | Estimate order |
| `old_work_date` | Old work date |
| `max_need_down_loop_count` | Max need calculation loop |
| `minimum_stock` | Minimum stock |
| `action_limit` | Action limit |
| `negative_start_balance` | Negative start balance |
| `negative_end_balance` | Negative end balance |
| `critical_date` | Critical date |
| `only_sales_need` | Only sales need |
| `load_mode` | Load mode (`'product_list'` or undefined) |

## Grids

### product

Product information grid contains basic data:

- `record_id` - Unique record identifier
- `product_id` - Product identifier
- `name` - Product name
- `json_data` - JSON data contains stock balance
- `stock_type` - Stock type
- `minimum_stock` - Minimum stock
- `minimum_order_amount` - Minimum order amount
- `default_supplier_id` - Default supplier
- `modify_id` - Modify ID for incremental updates

### product_need

Detailed need grid:

- `idx` - Row number
- `record_id` - Unique record identifier
- `product_id` - Product identifier
- `date` - Date (Unix timestamp)
- `balance` - Balance
- `coming_amount` - Coming amount
- `going_amount` - Going amount
- `free_amount` - Free amount
- `need_down` - Need down
- `first_row` - First row
- `last_row` - Last row
- `from_row` - Upper level row
- `error` - Error message
- `is_empty` - Is empty

### product_need_weekly

Weekly summary:

- `idx` - Row number
- `record_id` - Unique record identifier
- `product_id` - Product identifier
- `calc_idx` - Link to product_need grid
- `amount` - Amount
- `date` - Date
- `company_id` - Company ID (supplier)
- `order_amount` - Order amount
- `error` - Error message

## Technical Implementation

### Backend (product-need.lua)

```lua
-- Progressive loading
local loadMode = rec.load_mode
if loadMode == "product_list" then
    -- Return only product list
    return { grid = { product = {...} } }
end

-- Incremental update
if rec.incremental_update and next(lastModifyId) then
    changeArr = changeData.setIncrementalChange(data, lastModifyId, deleted)
    return { change_arr = changeArr, rec = { last_modify_id = ... } }
else
    return { grid = {...}, rec = { last_modify_id = ... } }
end
```

### Frontend (change-data.js)

```javascript
// Incremental update
export function incrementalUpdate(state, response) {
    const wasIncremental = response.change_arr
    if (wasIncremental) {
        applyIncrementalChanges(state, response.change_arr)
    } else if (response.grid) {
        state.grid.product_need = response.grid.product_need
        state.grid.product_need_weekly = response.grid.product_need_weekly
        state.grid.product = response.grid.product
    }
    state.rec.last_modify_id = response.rec.last_modify_id
    return wasIncremental
}
```

### Usage (nc-production.js)

```javascript
// Progressive loading
nc.callServer(state, 'calc/product-need', {
    parameter: { load_mode: 'product_list' }
}, ret => {
    incrementalUpdate(state, ret)
    // Show products immediately
    if (ret.grid?.product) {
        state.grid.product = ret.grid.product
    }
    // Get full calculation
    loadFullCalculation()
})

// Incremental update
const wasIncremental = incrementalUpdate(state, ret)
if (!wasIncremental && ret.grid?.product_need) {
    updateData(ret)
}
```

## Database Requirements

Tables must have `modify_id` field for incremental updates:

```sql
ALTER TABLE product ADD COLUMN modify_id TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
```

## Row Highlighting

System highlights grid rows with different colors based on row state:

### Highlight Types

| Class | Color | Description |
|-------|-------|-------------|
| (no class) | Grid default | User-selected row |
| `highlight-upper` | Golden yellow | Upper level product (parent) |
| `highlight-lower` | Light green | Lower level product (child) |
| `highlight-found` | Purple | Search-found row |
| `highlight-error` | Red | Error row (insufficient data) |

### Scope Column

The **Scope** column shows the hierarchical scope of each row:

- **↑N ↓M**: The row(s) you clicked (N=upper count, M=lower count)
- **upper**: Parent/upper level components
- **lower**: Child/lower level components
- **found**: Rows found by search
- **no-info**: Missing order information (for purchase order validation)

### Upper and Lower Level Selection

When you select a row in the grid:

- **Select upper** -highlighting: Shows all upper level products (parent products) that lead to this product
- **Select lower** -highlighting: Shows all lower level products (child products) that derive from this product

Highlighting is based on CSS classes on rows, so it doesn't interfere with actual selection.

## Add Order

In balance view, you can add purchase orders for selected rows.

### Usage

1. Select one or more rows in the grid
2. Set order amount (`order_amount`) for each selected row
3. Set supplier (`company_id`) for each selected row
4. Click "Add order" button

### Validation

If any selected row lacks required data:

- System shows error message: "Please set order amount and supplier company id to all selected rows before adding a new purchase order"
- Incomplete rows are highlighted in red (`highlight-error` class)
- You must fix the data before adding purchase order

### Required Fields

Each selected row must have:

- `order_amount` - Greater than 0
- `company_id` - Supplier identifier set

## Error Handling

- If incremental update fails, system falls back to full reload
- Missing `modify_id` fields are handled gracefully
- Malformed responses trigger full reload
- When adding purchase order, system validates that all selected rows have required data
