Mango.Nop.Plugins/Nop.Plugin.Misc.AIPlugin/docs/DOMAIN_MODEL.md

117 lines
5.0 KiB
Markdown

# 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<OrderDto>` | All active orders with full graph |
| `Shippings` | `List<Shipping>` | All active shipments with full graph |
| `StockTakings` | `List<StockTaking>` | 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.