# FruitBank.Common Domain Rules & Glossary

> This file acts as the single source of truth for the core Measurement System and Common Traps shared across all FruitBank applications (Hybrid App, Blazor, and nopCommerce server plugin).

## Measurement System

| Term | Definition |
|---|---|
| **IsMeasurable** | Product-level flag. If `false`: weights = 0.0, only `TrayQuantity` matters. A Pallet record is still created. |
| **NetWeight** | `GrossWeight − PalletWeight − (TrayQuantity × TareWeight)` — universal formula across all three hierarchies. |
| **TrayQuantity** | Always recorded, regardless of measurability. Count of trays/crates. |
| **GrossWeight** | Total weight including pallet and packaging. 0.0 if not measurable. |
| **PalletWeight** | Weight of the physical pallet. 0.0 if goods arrive without one. |
| **TareWeight** | Weight of a single tray/crate. Used in NetWeight calculation. |
| **AverageWeight** | Per-pallet average: `NetWeight / TrayQuantity`. Validated against threshold. |
| **MeasuringStatus** | NotStarted(0) → Started(10) → **Finnished**(20) → Audited(30). Note: "Finnished" is intentional. |
| **RevisorId** | Quality auditor's Customer ID. OrderItemPallet becomes "Audited" when RevisorId > 0. |

## Three Measurement Hierarchies

All share `MeasuringItemPalletBase` with the same NetWeight formula:

| Flow         | Parent          | Pallet Record           | Extra                                 |
|--------------|-----------------|-------------------------|---------------------------------------|
| **Inbound**  | ShippingItem    | ShippingItemPallet      | Declared vs measured discrepancy      |
| **Outbound** | OrderItemDto    | OrderItemPallet         | RevisorId for audit                   |
| **Inventory**| StockTakingItem | StockTakingItemPallet   | QuantityDiff for stock adjustment       |

## Common Traps

| Trap | Correct Behavior |
|---|---|
| "Pallet" = physical pallet | ❌ It's a measurement record. Always created. |
| Shipping = outgoing | ❌ Shipping = INBOUND. Order = OUTBOUND. |
| Fix "Finnished" spelling | ❌ Intentional legacy typo. Do NOT fix. |
| IsMeasurable=false means no Pallet | ❌ Pallet is always created, weights just = 0.0 |
| NetWeight is stored/settable | ❌ It is calculated. The setter throws an Exception! It only exists to satisfy the `IMeasuringItemPalletBase` interface boundary. Set `GrossWeight`, `PalletWeight`, `TareWeight` instead. |
| Setting MeasuringStatus | ❌ It's a calculated property (evaluates `IsMeasured`, `Id`, or child pallets). Do not try to set it. |
| Setting ForeignKey | ❌ `ForeignKey` is read-only. Use `SetForeignKey(id)` method instead. |
| GenericAttribute is simple | ❌ It's polymorphic: KeyGroup determines which entity type owns the record |