# Estimate Need: Period Growth & Query Redesign

## Constants

| Constant | Default | Purpose |
|---|---|---|
| `estimate_need_last_days` | 78 | "last" method trailing window |
| `estimate_period_before_days` | 45 | "period" method: days before anchor |
| `estimate_period_after_days` | 77 | "period" method: days after anchor |
| `period_compare_days` | 365 | shift for growth comparison |
| `estimate_need_growth_rate` | 1.0 | manual extra multiplier (layoffs etc) |

## Methods

### "last" method

```text
trailing window = [today - estimate_need_last_days, today)
daily rate = consumption / estimate_need_last_days
growth rate = none
```

### "period" method

```text
anchor = today - period_compare_days
period = [anchor - estimate_period_before_days, anchor + estimate_period_after_days)
base = same period shifted -period_compare_days (2 years ago)

growth_rate = period_consumption / base_consumption
daily rate = period_consumption / period_days * growth_rate * growth_rate_manual
```

## Example: June 15, 2026

```text
estimate_need_last_days = 78
estimate_period_before_days = 45
estimate_period_after_days = 77
period_compare_days = 365
```

### "last"

```text
window:       [2026-03-29 → 2026-06-15)
daily rate:   consumption / 78
```

### "period"

```text
anchor:       2025-06-15  (today - 365)
period:       [2025-05-01 → 2025-08-31)  (anchor - 45, anchor + 77)
base:         [2024-05-01 → 2024-08-31)  (period - 365)
period_days:  122

growth_rate = period_consumption / base_consumption
daily rate = period_consumption / 122 * growth_rate * estimate_need_growth_rate
```

## Query: ONE File, Loaded Dynamically

**`order_row-sales--estimate-need.json`** — NOT in `tableArray`. Loaded dynamically only when estimate need is in use.

### Why not in tableArray

The estimate-need query is expensive (delivered rows over 2+ years). It should only load when:

1. `estimate_need_last_days > 0` (estimate need configured)
2. During calculation, not during data preload

### How: loadGrid function in estimate-need.lua

```lua
function estimateNeed.loadGrid(param, grid, calcLoadData, constant, rec)
	if (constant.estimate_need_last_days or 0) <= 0 then return end
	estimateNeed.setRecDate(rec, constant)
	local queryParam = { organization_id = param.auth.organization_id }
	queryParam.estimate_need_start_date = rec.estimate_need_start_date
	queryParam.estimate_need_end_date = rec.estimate_need_end_date
	calcLoadData.queryData("order_row-sales--estimate-need", param, queryParam, param.grid.info.stat, grid)
end
```

### Where called: product-need.lua productNeed.calculate

```lua
estimateNeed.loadGrid(param, grid, calcLoadData, constant, rec)
```

Called after `setRecDate` sets the date params, before `addSourceArray`.

## Param Dates — setRecDate in estimate-need.lua

```lua
function estimateNeed.setRecDate(rec, constant)
	rec.estimate_need_end_date = dt.currentDate()
	rec.estimate_need_start_date = dt.daysAdd(rec.estimate_need_end_date, -(constant.estimate_need_last_days or 0))
	if constant.estimate_need_last_days and constant.estimate_need_last_days > 0 then
		local periodCompareDays = constant.period_compare_days or 365
		local periodAnchor = dt.daysAdd(rec.estimate_need_end_date, -periodCompareDays)
		rec.estimate_period_start_date = dt.daysAdd(periodAnchor, -(constant.estimate_period_before_days or 0))
		rec.estimate_period_end_date = dt.daysAdd(periodAnchor, constant.estimate_period_after_days or 0)
		rec.estimate_period_base_start_date = dt.daysAdd(rec.estimate_period_start_date, -periodCompareDays)
		rec.estimate_period_base_end_date = dt.daysAdd(rec.estimate_period_end_date, -periodCompareDays)
		if rec.estimate_period_base_start_date < rec.estimate_need_start_date then
			rec.estimate_need_start_date = rec.estimate_period_base_start_date
		end
	end
end
```

## tableArray

**REMOVE** `order_row-sales--estimate-need` from tableArray entirely. No estimate-need entry there at all.

## nc-calc-server-calc.lua changes

1. **REMOVE** from `setParamRec`: the `estimateNeed.setRecDate(rec, constant)` call — dates are now set in `productNeed.calculate` via `estimateNeed.loadGrid`
2. **REMOVE** from `setTableArray`: the conditional `order_row-sales--estimate-need` entry
3. **REMOVE** from queryParam section: the `estimate_need_start_date`/`estimate_need_end_date` params
4. Keep `calcLoadData` import accessible for passing to estimateNeed

## product-need.lua changes

In `productNeed.calculate`, after constant/rec setup, before `addSourceArray`:

```lua
estimateNeed.loadGrid(param, grid, calcLoadData, constant, rec)
```

This sets rec dates AND loads the grid in one call.

## Files to Change

1. **`constant.json`**: rename `estimate_need_days` → `estimate_need_last_days`, add `estimate_period_before_days`, `estimate_period_after_days`, `period_compare_days` (DONE)
2. **`nc-calc-server-calc.lua`**: REMOVE estimate-need from setParamRec, setTableArray, queryParam (3 removals)
3. **`query/order_row-sales--estimate-need.json`**: single query file (DONE)
4. **`estimate-need.lua`**: add `loadGrid`, keep `setRecDate`, single grid, date bucketing, auto growth
5. **`product-need.lua`**: call `estimateNeed.loadGrid` before addSourceArray, pass new dates
