# Domain Model — Behavioral Documentation > Part of `Nop.Plugin.Misc.FruitBankPlugin`. See `README.md` for project overview. > For entity definitions, properties, and relationships see `docs/SCHEMA.md` (authoritative TOON schema). > For measurement workflows see `docs/MEASUREMENT.md`. > For data layer details see `docs/DATA_LAYER.md`. > For core measurement system rules and common domain traps, see: `../../../../../FruitBankHybridApp/FruitBank.Common/docs/GLOSSARY.md` This document explains **how the domain model behaves** in the plugin. For **what the entities are** (properties, types, relationships), see `docs/SCHEMA.md`. ## Weight Formula All three pallet types (ShippingItemPallet, OrderItemPallet, StockTakingItemPallet) use the same formula: ``` NetWeight = GrossWeight - PalletWeight - (TrayQuantity * TareWeight) ``` | Field | Meaning | |---|---| | `GrossWeight` | Scale reading (total weight). 0.0 if product is not measurable | | `PalletWeight` | Weight of the physical pallet. 0.0 if goods arrive without pallet | | `TareWeight` | Weight of one tray/crate (per unit) | | `TrayQuantity` | Number of trays/crates. Always recorded, even for non-measurable products | | `NetWeight` | Computed, read-only, not-mapped (setter exists for shared interface but throws Exception) | ## MeasuringStatus Lifecycle ``` NotStarted (0) → Started (10) → Finnished (20) → Audited (30) [no record] [record created] [IsMeasured=true] [RevisorId > 0] ``` - **NotStarted**: No pallet record exists yet - **Started**: Pallet record created (Id > 0) but `IsMeasured = false` - **Finnished**: `IsMeasured = true` — weights recorded - **Audited**: `RevisorId > 0` — quality auditor confirmed (OrderItemPallet only) ## IsMeasurable Flag `ProductDto.IsMeasurable` is the master toggle (stored as GenericAttribute). When `false`: - Weight validation is bypassed - One pallet record is still created with `GrossWeight = 0.0` - Only `TrayQuantity` is recorded - Product is not included in average weight checks ## GenericAttribute Keys Custom product/order properties are stored via nopCommerce's GenericAttribute table. The DTO classes expose these as computed, not-mapped properties. ### Product attributes (saved by FruitBankEventConsumer) | Key | Type | Purpose | |---|---|---| | `IsMeasurable` | bool | Master flag for weight validation | | `NetWeight` | double | Product net weight | | `Tare` | double | Tare weight per tray | | `AverageWeight` | double | Expected average weight per tray | | `AverageWeightTreshold` | double | Max allowed deviation % from AverageWeight | | `IncomingQuantity` | int | Incoming stock not yet received | ### Order attributes | Key | Type | Purpose | |---|---|---| | `DateOfReceipt` | DateTime | Scheduled delivery date | | `MeasurementOwnerId` | int | User who started measuring | | `RevisorId` | int | Quality auditor user ID | ## Entity Hierarchy Overview ### Inbound Delivery (Shipping) ``` Shipping (fbShipping) ← truck arrival └─ ShippingDocument (fbShippingDocument) ← supplier delivery note [1:N] ├─ ShippingItem (fbShippingItem) ← product line [1:N] │ └─ ShippingItemPallet ← measurement event [1:N] ├─ ShippingDocumentToFiles ← uploaded PDFs [1:N] │ └─ Files (fbFiles) [N:1] └─ Partner (fbPartner) ← supplier [N:1] ``` ### Outbound Order ``` OrderDto (Order) ← nopCommerce order ├─ OrderItemDto (OrderItem) ← line item [1:N] │ ├─ OrderItemPallet (fbOrderItemPallet) ← measurement record [1:N] │ └─ ProductDto (Product) [N:1] ├─ Customer [N:1] └─ GenericAttributeDto ← custom attributes [1:N] ``` ### Inventory (StockTaking) ``` StockTaking (fbStockTaking) ← inventory session └─ StockTakingItem (fbStockTakingItem) ← product line [1:N] ├─ StockTakingItemPallet ← measurement record [1:N] └─ ProductDto (Product) [N:1] ``` ## FullProcessModel Container for bulk data sync between server and FruitBankHybridApp via SignalR: | Property | Type | Purpose | |---|---|---| | `Orders` | `List` | All active orders with full graph | | `Shippings` | `List` | All active shipments with full graph | | `StockTakings` | `List` | All active inventory sessions | ## Note on "Pallet" Naming The term "Pallet" in `OrderItemPallet`, `ShippingItemPallet`, and `StockTakingItemPallet` is a legacy naming convention. These are **general measurement records** that are always created for every item, regardless of whether goods arrive on a physical pallet. For non-measurable products, weight fields are 0.0 and only `TrayQuantity` is tracked.