Enforce strict AI agent protocol, doc sync, and glossary
- Added "AI AGENT CORE PROTOCOL" to all copilot-instructions.md files: mandates [LOADED_DOCS] prefix, hard-gates tool usage, enforces no-re-read of .md files, and requires user consent for doc/code changes. - Updated CLAUDE.md to require reading copilot-instructions.md first. - Added topic-based doc separation and folder navigation rules. - Changed doc sync: agent now passively detects discrepancies and asks before updating docs. - Every code-modifying response must end with a [DOCUMENTATION CHECK] section. - Centralized measurement system and domain traps in new FruitBank.Common/docs/GLOSSARY.md; updated references in FruitBankHybridApp GLOSSARY.md. - Clarified schema and doc locations in FruitBankHybridApp README.md. - Added hybrid execution model section to AyCode.Core BINARY_FEATURES.md. - Removed unnecessary BeginUpdate/EndUpdate calls in MgGridBase.cs for layout persistence. - Removed full Toon schema from plugin SCHEMA.md to avoid duplication.
This commit is contained in:
parent
3f49945bfb
commit
dbccbf487d
File diff suppressed because one or more lines are too long
|
|
@ -1 +1 @@
|
||||||
Always read `.github/copilot-instructions.md` first — it is the single source of truth for this repo.
|
CRITICAL: Your FIRST action in every session MUST be reading `.github/copilot-instructions.md`. Execute ALL session-start instructions found there before responding to any user query. It is the single source of truth for this repo.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
# 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 |
|
||||||
|
|
@ -14,7 +14,7 @@ Domain rules and critical pitfalls live in a single file: [`.github/copilot-inst
|
||||||
| Claude Code | ✅ `CLAUDE.md` → references above | None |
|
| Claude Code | ✅ `CLAUDE.md` → references above | None |
|
||||||
| Cursor / Windsurf | ✅ `README.md` | Read `copilot-instructions.md` via @file |
|
| Cursor / Windsurf | ✅ `README.md` | Read `copilot-instructions.md` via @file |
|
||||||
|
|
||||||
Detailed docs: [`docs/`](docs/) — GLOSSARY.md, ARCHITECTURE.md, CONVENTIONS.md, SCHEMA.md
|
Detailed docs: `docs/` — GLOSSARY.md, ARCHITECTURE.md, CONVENTIONS.md. Domain model schema (TOON) lives in the plugin: `NopCommerce.Common/4.70/Plugins/Nop.Plugin.Misc.AIPlugin/docs/SCHEMA.md`
|
||||||
|
|
||||||
## Solution Structure
|
## Solution Structure
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
> For core framework glossary see: `GLOSSARY.md` (in AyCode.Core repo)
|
> For core framework glossary see: `GLOSSARY.md` (in AyCode.Core repo)
|
||||||
> For UI framework glossary see: `GLOSSARY.md` (in AyCode.Blazor repo)
|
> For UI framework glossary see: `GLOSSARY.md` (in AyCode.Blazor repo)
|
||||||
|
> For core measurement system rules and common domain traps, see: `../FruitBank.Common/docs/GLOSSARY.md`
|
||||||
|
|
||||||
Domain terminology for the FruitBank system. **Read this before making changes.**
|
Domain terminology for the FruitBank system. **Read this before making changes.**
|
||||||
|
|
||||||
|
|
@ -18,30 +19,6 @@ Domain terminology for the FruitBank system. **Read this before making changes.*
|
||||||
| **StockTaking** | Leltározás | Inventory session that freezes logical stock and reconciles with physical count. |
|
| **StockTaking** | Leltározás | Inventory session that freezes logical stock and reconciles with physical count. |
|
||||||
| **GenericAttribute** | Generikus attribútum | nopCommerce polymorphic key-value store. KeyGroup = owner type, EntityId = owner ID. |
|
| **GenericAttribute** | Generikus attribútum | nopCommerce polymorphic key-value store. KeyGroup = owner type, EntityId = owner ID. |
|
||||||
|
|
||||||
## 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 (Shipping)** | ShippingItem | ShippingItemPallet | Declared vs measured discrepancy |
|
|
||||||
| **Outbound (Order)** | OrderItemDto | OrderItemPallet | RevisorId for audit |
|
|
||||||
| **Inventory (StockTaking)** | StockTakingItem | StockTakingItemPallet | QuantityDiff for stock adjustment |
|
|
||||||
|
|
||||||
## nopCommerce Entities
|
## nopCommerce Entities
|
||||||
|
|
||||||
These are **NOT custom FruitBank entities** — they come from nopCommerce:
|
These are **NOT custom FruitBank entities** — they come from nopCommerce:
|
||||||
|
|
@ -51,17 +28,6 @@ FruitBank extends them via:
|
||||||
- **DTOs** (OrderDto, OrderItemDto, ProductDto) that wrap nopCommerce entities with measurement properties
|
- **DTOs** (OrderDto, OrderItemDto, ProductDto) that wrap nopCommerce entities with measurement properties
|
||||||
- **GenericAttributes** for storing custom values (IsMeasurable, Tare, AverageWeight, etc.)
|
- **GenericAttributes** for storing custom values (IsMeasurable, Tare, AverageWeight, etc.)
|
||||||
|
|
||||||
## 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 | ❌ It's calculated: GrossWeight − PalletWeight − (TrayQuantity × TareWeight) |
|
|
||||||
| GenericAttribute is simple | ❌ It's polymorphic: KeyGroup determines which entity type owns the record |
|
|
||||||
|
|
||||||
## UI / Grid Components
|
## UI / Grid Components
|
||||||
|
|
||||||
For MgGrid framework terms (MgGridBase, MgGridWithInfoPanel, MgGridToolbarBase, MgGridDataColumn, MgGridInfoPanel, IMgGridBase, etc.) see `GLOSSARY.md` (in AyCode.Blazor repo) and `AyCode.Blazor.Components/docs/MGGRID.md` (in AyCode.Blazor repo).
|
For MgGrid framework terms (MgGridBase, MgGridWithInfoPanel, MgGridToolbarBase, MgGridDataColumn, MgGridInfoPanel, IMgGridBase, etc.) see `GLOSSARY.md` (in AyCode.Blazor repo) and `AyCode.Blazor.Components/docs/MGGRID.md` (in AyCode.Blazor repo).
|
||||||
|
|
|
||||||
635
docs/SCHEMA.md
635
docs/SCHEMA.md
|
|
@ -1,635 +0,0 @@
|
||||||
# Domain Model Schema (Toon Format)
|
|
||||||
|
|
||||||
> Full domain model in Toon (Token-Oriented Object Notation) format — see `AyCode.Core/Serializers/Toons/README.md` (in AyCode.Core repo).
|
|
||||||
> This is the authoritative schema for entities, DTOs, and enums in the FruitBank domain.
|
|
||||||
|
|
||||||
@meta {
|
|
||||||
version = "1.0"
|
|
||||||
format = "toon"
|
|
||||||
source-code-language = "C#"
|
|
||||||
context = "This is a nopCommerce plugin developed for FruitBank, a fruit and vegetable wholesaler. The plugin manages supplier inbound delivery (receiving), warehouse weighing (net/gross/pallet/tare weights), and inventory stocktaking. The business logic is centered around FruitBank's requirement for precise physical measurement and quantity tracking."
|
|
||||||
types = ["OrderStatus", "ShippingStatus", "PaymentStatus", "GenericAttributeDto", "MeasuringStatus", "VatNumberStatus", "TaxDisplayType", "OrderNote", "DocumentType", "Files", "Pallet", "ProductDto", "Customer", "FullProcessModel", "OrderDto", "OrderItemDto", "OrderItemPallet", "Partner", "Shipping", "ShippingDocument", "ShippingDocumentToFiles", "ShippingItem", "ShippingItemPallet", "StockTaking", "StockTakingItem", "StockTakingItemPallet"]
|
|
||||||
}
|
|
||||||
|
|
||||||
@types {
|
|
||||||
OrderStatus: enum
|
|
||||||
underlying-type: "int"
|
|
||||||
default-value: 10
|
|
||||||
values:
|
|
||||||
Pending = 10
|
|
||||||
Processing = 20
|
|
||||||
Complete = 30
|
|
||||||
Cancelled = 40
|
|
||||||
|
|
||||||
ShippingStatus: enum
|
|
||||||
underlying-type: "int"
|
|
||||||
default-value: 10
|
|
||||||
values:
|
|
||||||
ShippingNotRequired = 10
|
|
||||||
NotYetShipped = 20
|
|
||||||
PartiallyShipped = 25
|
|
||||||
Shipped = 30
|
|
||||||
Delivered = 40
|
|
||||||
|
|
||||||
PaymentStatus: enum
|
|
||||||
underlying-type: "int"
|
|
||||||
default-value: 10
|
|
||||||
values:
|
|
||||||
Pending = 10
|
|
||||||
Authorized = 20
|
|
||||||
Paid = 30
|
|
||||||
PartiallyRefunded = 35
|
|
||||||
Refunded = 40
|
|
||||||
Voided = 50
|
|
||||||
|
|
||||||
GenericAttributeDto: "Data transfer object for GenericAttribute"
|
|
||||||
table-name: "GenericAttribute"
|
|
||||||
related-type: "dto-of GenericAttribute"
|
|
||||||
CreatedOrUpdatedDateUTC: DateTime?
|
|
||||||
EntityId: int
|
|
||||||
constraints: "polymorphic-fk(KeyGroup)"
|
|
||||||
Key: string
|
|
||||||
KeyGroup: string
|
|
||||||
StoreId: int
|
|
||||||
Value: string
|
|
||||||
purpose: "Raw string representation of the Key's value"
|
|
||||||
Id: int
|
|
||||||
purpose: "Primary key / unique identification"
|
|
||||||
primary-key: true
|
|
||||||
|
|
||||||
MeasuringStatus: enum
|
|
||||||
underlying-type: "int"
|
|
||||||
default-value: 0
|
|
||||||
values:
|
|
||||||
NotStarted = 0
|
|
||||||
Started = 10
|
|
||||||
Finnished = 20
|
|
||||||
Audited = 30
|
|
||||||
|
|
||||||
VatNumberStatus: enum
|
|
||||||
underlying-type: "int"
|
|
||||||
default-value: 0
|
|
||||||
values:
|
|
||||||
Unknown = 0
|
|
||||||
Empty = 10
|
|
||||||
Valid = 20
|
|
||||||
Invalid = 30
|
|
||||||
|
|
||||||
TaxDisplayType: enum
|
|
||||||
underlying-type: "int"
|
|
||||||
default-value: 0
|
|
||||||
values:
|
|
||||||
IncludingTax = 0
|
|
||||||
ExcludingTax = 10
|
|
||||||
|
|
||||||
OrderNote: "NopCommerce order note entity"
|
|
||||||
table-name: "OrderNote"
|
|
||||||
CreatedOnUtc: DateTime
|
|
||||||
DisplayToCustomer: bool
|
|
||||||
DownloadId: int
|
|
||||||
Note: string
|
|
||||||
OrderId: int
|
|
||||||
description: "Foreign key to parent Order"
|
|
||||||
Id: int
|
|
||||||
purpose: "Primary key / unique identification"
|
|
||||||
primary-key: true
|
|
||||||
|
|
||||||
DocumentType: enum
|
|
||||||
underlying-type: "int"
|
|
||||||
default-value: 0
|
|
||||||
values:
|
|
||||||
NotSet = 0
|
|
||||||
Unknown = 5
|
|
||||||
ShippingDocument = 10
|
|
||||||
OrderConfirmation = 15
|
|
||||||
Invoice = 20
|
|
||||||
|
|
||||||
Files: "Uploaded file with extracted text content"
|
|
||||||
table-name: "fbFiles"
|
|
||||||
purpose: "A centralized repository for all uploaded binary content and metadata, featuring a 'RawText' field that stores OCR-extracted information for full-text search and automated data validation across the system"
|
|
||||||
Created: DateTime
|
|
||||||
FileExtension: string
|
|
||||||
FileHash: string
|
|
||||||
FileName: string
|
|
||||||
FileSubPath: string
|
|
||||||
IsCompressed: bool
|
|
||||||
purpose: "Status flag"
|
|
||||||
Modified: DateTime
|
|
||||||
RawText: string
|
|
||||||
Id: int
|
|
||||||
purpose: "Primary key / unique identification"
|
|
||||||
primary-key: true
|
|
||||||
|
|
||||||
Pallet: "Pallet type definition with size and weight"
|
|
||||||
table-name: "fbPallet"
|
|
||||||
Created: DateTime
|
|
||||||
Modified: DateTime
|
|
||||||
Name: string
|
|
||||||
Size: string
|
|
||||||
Weight: double?
|
|
||||||
Id: int
|
|
||||||
purpose: "Primary key / unique identification"
|
|
||||||
primary-key: true
|
|
||||||
|
|
||||||
ProductDto: "Product data with measurements and generic attributes"
|
|
||||||
table-name: "Product"
|
|
||||||
related-type: "dto-of Product"
|
|
||||||
AvailableQuantity: int
|
|
||||||
business-logic: "get => StockQuantity + IncomingQuantity"
|
|
||||||
constraints: "readonly, not-mapped"
|
|
||||||
AverageWeight: double
|
|
||||||
business-logic: "get => GenericAttributes.GetValueOrDefault<double>('AverageWeight')"
|
|
||||||
constraints: "readonly, not-mapped"
|
|
||||||
AverageWeightTreshold: double
|
|
||||||
business-logic: "get => GenericAttributes.GetValueOrDefault<double>('AverageWeightTreshold')"
|
|
||||||
constraints: "readonly, not-mapped"
|
|
||||||
GenericAttributes: List<GenericAttributeDto>
|
|
||||||
navigation: "one-to-many"
|
|
||||||
IncomingQuantity: int
|
|
||||||
business-logic: "get => GenericAttributes.GetValueOrDefault<int>('IncomingQuantity')"
|
|
||||||
constraints: "not-mapped"
|
|
||||||
IsMeasurable: bool
|
|
||||||
purpose: "Master flag: if false, the system bypasses weight validation but still creates one Measurement Record (PalletItem) with TrayQuantity."
|
|
||||||
business-logic: "get => GenericAttributes.GetValueOrDefault<bool>('IsMeasurable')"
|
|
||||||
constraints: "not-mapped"
|
|
||||||
NetWeight: double
|
|
||||||
business-logic: "get => GenericAttributes.GetValueOrDefault<double>('NetWeight')"
|
|
||||||
constraints: "not-mapped"
|
|
||||||
Tare: double
|
|
||||||
business-logic: "get => GenericAttributes.GetValueOrDefault<double>('Tare')"
|
|
||||||
constraints: "not-mapped"
|
|
||||||
Deleted: bool
|
|
||||||
FullDescription: string
|
|
||||||
Height: decimal
|
|
||||||
Length: decimal
|
|
||||||
LimitedToStores: bool
|
|
||||||
Name: string
|
|
||||||
ParentGroupedProductId: int
|
|
||||||
Price: decimal
|
|
||||||
ProductCost: decimal
|
|
||||||
ProductTypeId: int
|
|
||||||
ShortDescription: string
|
|
||||||
StockQuantity: int
|
|
||||||
SubjectToAcl: bool
|
|
||||||
WarehouseId: int
|
|
||||||
Weight: decimal
|
|
||||||
Width: decimal
|
|
||||||
Id: int
|
|
||||||
purpose: "Primary key / unique identification"
|
|
||||||
primary-key: true
|
|
||||||
|
|
||||||
Customer: "NopCommerce customer entity"
|
|
||||||
table-name: "Customer"
|
|
||||||
Active: bool
|
|
||||||
AdminComment: string
|
|
||||||
AffiliateId: int
|
|
||||||
BillingAddressId: int?
|
|
||||||
CannotLoginUntilDateUtc: DateTime?
|
|
||||||
City: string
|
|
||||||
Company: string
|
|
||||||
CountryId: int
|
|
||||||
County: string
|
|
||||||
CreatedOnUtc: DateTime
|
|
||||||
CurrencyId: int?
|
|
||||||
CustomCustomerAttributesXML: string
|
|
||||||
CustomerGuid: Guid
|
|
||||||
DateOfBirth: DateTime?
|
|
||||||
Deleted: bool
|
|
||||||
Email: string
|
|
||||||
constraints: "email-format"
|
|
||||||
EmailToRevalidate: string
|
|
||||||
constraints: "email-format"
|
|
||||||
FailedLoginAttempts: int
|
|
||||||
Fax: string
|
|
||||||
FirstName: string
|
|
||||||
Gender: string
|
|
||||||
HasShoppingCartItems: bool
|
|
||||||
IsSystemAccount: bool
|
|
||||||
purpose: "Status flag"
|
|
||||||
IsTaxExempt: bool
|
|
||||||
purpose: "Status flag"
|
|
||||||
LanguageId: int?
|
|
||||||
constraints: "range: 0-150"
|
|
||||||
LastActivityDateUtc: DateTime
|
|
||||||
LastIpAddress: string
|
|
||||||
LastLoginDateUtc: DateTime?
|
|
||||||
LastName: string
|
|
||||||
MustChangePassword: bool
|
|
||||||
Phone: string
|
|
||||||
RegisteredInStoreId: int
|
|
||||||
RequireReLogin: bool
|
|
||||||
ShippingAddressId: int?
|
|
||||||
StateProvinceId: int
|
|
||||||
StreetAddress: string
|
|
||||||
StreetAddress2: string
|
|
||||||
SystemName: string
|
|
||||||
TaxDisplayType: TaxDisplayType?
|
|
||||||
TaxDisplayTypeId: int?
|
|
||||||
TimeZoneId: string
|
|
||||||
Username: string
|
|
||||||
VatNumber: string
|
|
||||||
VatNumberStatus: VatNumberStatus
|
|
||||||
VatNumberStatusId: int
|
|
||||||
VendorId: int
|
|
||||||
ZipPostalCode: string
|
|
||||||
Id: int
|
|
||||||
purpose: "Primary key / unique identification"
|
|
||||||
primary-key: true
|
|
||||||
|
|
||||||
FullProcessModel: "Object of type FullProcessModel"
|
|
||||||
table-name: "FullProcessModel"
|
|
||||||
purpose: "Container model for Shipping, Order"
|
|
||||||
Orders: List<OrderDto>
|
|
||||||
navigation: "one-to-many"
|
|
||||||
Shippings: List<Shipping>
|
|
||||||
navigation: "one-to-many"
|
|
||||||
StockTakings: List<StockTaking>
|
|
||||||
navigation: "one-to-many"
|
|
||||||
|
|
||||||
OrderDto: "Data transfer object for Order"
|
|
||||||
table-name: "Order"
|
|
||||||
related-type: "dto-of Order"
|
|
||||||
DateOfReceipt: DateTime?
|
|
||||||
business-logic: "get => GenericAttributes.GetValueOrNull<DateTime>('DateOfReceipt')"
|
|
||||||
constraints: "readonly, not-mapped"
|
|
||||||
DateOfReceiptOrCreated: DateTime
|
|
||||||
constraints: "readonly, not-mapped"
|
|
||||||
GenericAttributes: List<GenericAttributeDto>
|
|
||||||
navigation: "one-to-many"
|
|
||||||
IsAllOrderItemAudited: bool
|
|
||||||
purpose: "Status flag"
|
|
||||||
business-logic: "get => OrderItemDtos.Count > 0 && OrderItemDtos.All(oi => oi.IsAudited)"
|
|
||||||
constraints: "readonly, not-mapped"
|
|
||||||
IsAllOrderItemAvgWeightValid: bool
|
|
||||||
purpose: "Status flag"
|
|
||||||
business-logic: "get => OrderItemDtos.All(oi => oi.AverageWeightIsValid)"
|
|
||||||
constraints: "readonly, not-mapped"
|
|
||||||
IsComplete: bool
|
|
||||||
purpose: "Status flag"
|
|
||||||
business-logic: "get => OrderStatus == OrderStatus.Complete"
|
|
||||||
constraints: "readonly, not-mapped"
|
|
||||||
IsMeasurable: bool
|
|
||||||
purpose: "Status flag"
|
|
||||||
business-logic: "get => OrderItemDtos.Any(oi => oi.IsMeasurable)"
|
|
||||||
constraints: "readonly, not-mapped"
|
|
||||||
IsMeasured: bool
|
|
||||||
purpose: "Status flag"
|
|
||||||
business-logic: "get => Id > 0 && OrderItemDtos.Count > 0 && OrderItemDtos.All(x => x.IsMeasured)"
|
|
||||||
constraints: "readonly, not-mapped"
|
|
||||||
MeasurementOwnerId: int
|
|
||||||
business-logic: "get => GenericAttributes.GetValueOrDefault('MeasurementOwnerId', 0)"
|
|
||||||
constraints: "readonly, not-mapped"
|
|
||||||
MeasuringStatus: MeasuringStatus
|
|
||||||
constraints: "readonly, not-mapped"
|
|
||||||
RevisorId: int
|
|
||||||
business-logic: "get => GenericAttributes.GetValueOrDefault('RevisorId', 0)"
|
|
||||||
constraints: "readonly, not-mapped"
|
|
||||||
TimeOfReceiptText: string
|
|
||||||
constraints: "readonly, not-mapped"
|
|
||||||
CreatedOnUtc: DateTime
|
|
||||||
CustomOrderNumber: string
|
|
||||||
CustomValuesXml: string
|
|
||||||
Customer: Customer
|
|
||||||
foreign-key: "CustomerId"
|
|
||||||
navigation: "many-to-one"
|
|
||||||
CustomerId: int
|
|
||||||
Deleted: bool
|
|
||||||
OrderDiscount: decimal
|
|
||||||
OrderGuid: Guid
|
|
||||||
OrderItemDtos: List<OrderItemDto>
|
|
||||||
other-key: "OrderId"
|
|
||||||
navigation: "one-to-many"
|
|
||||||
inverse-property: "OrderDto"
|
|
||||||
OrderNotes: List<OrderNote>
|
|
||||||
other-key: "OrderId"
|
|
||||||
navigation: "one-to-many"
|
|
||||||
OrderStatus: OrderStatus
|
|
||||||
purpose: "Enum wrapper"
|
|
||||||
business-logic: "get, set => OrderStatusId"
|
|
||||||
OrderStatusId: int
|
|
||||||
OrderTotal: decimal
|
|
||||||
PaidDateUtc: DateTime?
|
|
||||||
PaymentStatus: PaymentStatus
|
|
||||||
purpose: "Enum wrapper"
|
|
||||||
business-logic: "get, set => PaymentStatusId"
|
|
||||||
PaymentStatusId: int
|
|
||||||
ShippingMethod: string
|
|
||||||
ShippingStatus: ShippingStatus
|
|
||||||
purpose: "Enum wrapper"
|
|
||||||
business-logic: "get, set => ShippingStatusId"
|
|
||||||
ShippingStatusId: int
|
|
||||||
StoreId: int
|
|
||||||
Id: int
|
|
||||||
purpose: "Primary key / unique identification"
|
|
||||||
primary-key: true
|
|
||||||
|
|
||||||
OrderItemDto: "Order item with measurements, pallets, and validation"
|
|
||||||
table-name: "OrderItem"
|
|
||||||
related-type: "dto-of OrderItem"
|
|
||||||
AverageWeight: double
|
|
||||||
business-logic: "get => IsMeasurable && OrderItemPallets.Count > 0 ? double.Round(OrderItemPallets.Sum(oip => oip.AverageWeight) / OrderItemPallets.Count, 1) : 0d"
|
|
||||||
constraints: "readonly, not-mapped"
|
|
||||||
AverageWeightDifference: double
|
|
||||||
business-logic: "get => IsMeasurable ? double.Round(ProductDto!.AverageWeight - AverageWeight, 1) : 0"
|
|
||||||
constraints: "readonly, not-mapped"
|
|
||||||
AverageWeightIsValid: bool
|
|
||||||
business-logic: "get => !IsMeasurable || (ProductDto!.AverageWeight > 0 && ((AverageWeightDifference / ProductDto!.AverageWeight) * 100) < ProductDto!.AverageWeightTreshold)"
|
|
||||||
constraints: "readonly, not-mapped"
|
|
||||||
GenericAttributes: List<GenericAttributeDto>
|
|
||||||
navigation: "one-to-many"
|
|
||||||
GrossWeight: double
|
|
||||||
business-logic: "get => double.Round(OrderItemPallets.Sum(x => x.NetWeight), 1)"
|
|
||||||
constraints: "not-mapped"
|
|
||||||
IsAudited: bool
|
|
||||||
purpose: "Status flag"
|
|
||||||
business-logic: "get => OrderItemPallets.Count > 0 && OrderItemPallets.All(oip => oip.IsAudited)"
|
|
||||||
constraints: "readonly, not-mapped"
|
|
||||||
IsMeasurable: bool
|
|
||||||
purpose: "Status flag"
|
|
||||||
business-logic: "get => ProductDto!.IsMeasurable"
|
|
||||||
constraints: "not-mapped"
|
|
||||||
IsMeasured: bool
|
|
||||||
purpose: "Status flag"
|
|
||||||
business-logic: "get => IsMeasuredAndValid()"
|
|
||||||
constraints: "not-mapped"
|
|
||||||
MeasuringStatus: MeasuringStatus
|
|
||||||
business-logic: "get => complex conditional logic based on IsAudited, IsMeasured, and OrderItemPallets status"
|
|
||||||
constraints: "readonly, not-mapped"
|
|
||||||
NetWeight: double
|
|
||||||
business-logic: "get => double.Round(OrderItemPallets.Sum(x => x.NetWeight), 1)"
|
|
||||||
constraints: "not-mapped"
|
|
||||||
OrderDto: OrderDto
|
|
||||||
foreign-key: "OrderId"
|
|
||||||
navigation: "many-to-one"
|
|
||||||
inverse-property: "OrderItemDtos"
|
|
||||||
OrderItemPallets: List<OrderItemPallet>
|
|
||||||
other-key: "OrderItemId"
|
|
||||||
navigation: "one-to-many"
|
|
||||||
inverse-property: "OrderItemDto"
|
|
||||||
TrayQuantity: int
|
|
||||||
business-logic: "get => OrderItemPallets.Sum(x => x.TrayQuantity)"
|
|
||||||
constraints: "not-mapped"
|
|
||||||
AttributesXml: string
|
|
||||||
ItemWeight: decimal?
|
|
||||||
OrderId: int
|
|
||||||
OrderItemGuid: Guid
|
|
||||||
PriceExclTax: decimal
|
|
||||||
PriceInclTax: decimal
|
|
||||||
ProductDto: ProductDto
|
|
||||||
foreign-key: "ProductId"
|
|
||||||
navigation: "many-to-one"
|
|
||||||
ProductId: int
|
|
||||||
ProductName: string
|
|
||||||
business-logic: "get => ProductDto?.Name ?? 'ProductDto is null!!!'"
|
|
||||||
constraints: "readonly"
|
|
||||||
Quantity: int
|
|
||||||
UnitPriceExclTax: decimal
|
|
||||||
UnitPriceInclTax: decimal
|
|
||||||
Id: int
|
|
||||||
purpose: "Primary key / unique identification"
|
|
||||||
primary-key: true
|
|
||||||
|
|
||||||
OrderItemPallet: "Pallet measurements for order items with audit tracking"
|
|
||||||
table-name: "fbOrderItemPallet"
|
|
||||||
purpose: "A measurement record for outgoing goods. NOTE: Despite the 'Pallet' name, this is a general measurement record that is ALWAYS created for every item."
|
|
||||||
AverageWeight: double
|
|
||||||
business-logic: "get => double.Round(NetWeight / TrayQuantity, 1)"
|
|
||||||
constraints: "readonly, not-mapped"
|
|
||||||
IsAudited: bool
|
|
||||||
purpose: "Status flag"
|
|
||||||
business-logic: "get => RevisorId > 0"
|
|
||||||
constraints: "readonly, not-mapped"
|
|
||||||
MeasuringStatus: MeasuringStatus
|
|
||||||
business-logic: "get => IsAudited ? MeasuringStatus.Audited : base.MeasuringStatus"
|
|
||||||
constraints: "readonly, not-mapped"
|
|
||||||
OrderItemDto: OrderItemDto
|
|
||||||
foreign-key: "OrderItemId"
|
|
||||||
navigation: "many-to-one"
|
|
||||||
inverse-property: "OrderItemPallets"
|
|
||||||
OrderItemId: int
|
|
||||||
RevisorId: int
|
|
||||||
purpose: "User/Customer ID of the quality auditor"
|
|
||||||
Created: DateTime
|
|
||||||
CreatorId: int?
|
|
||||||
GrossWeight: double
|
|
||||||
IsMeasured: bool
|
|
||||||
Modified: DateTime
|
|
||||||
ModifierId: int?
|
|
||||||
NetWeight: double
|
|
||||||
business-logic: "get => GrossWeight - PalletWeight - (TrayQuantity * TareWeight)"
|
|
||||||
constraints: "readonly, not-mapped"
|
|
||||||
PalletWeight: double
|
|
||||||
TareWeight: double
|
|
||||||
TrayQuantity: int
|
|
||||||
Id: int
|
|
||||||
primary-key: true
|
|
||||||
|
|
||||||
Partner: "Business partner with address and tax information"
|
|
||||||
table-name: "fbPartner"
|
|
||||||
purpose: "External supplier providing goods"
|
|
||||||
CertificationNumber: string
|
|
||||||
City: string
|
|
||||||
Country: string
|
|
||||||
County: string
|
|
||||||
Created: DateTime
|
|
||||||
Modified: DateTime
|
|
||||||
Name: string
|
|
||||||
PostalCode: string
|
|
||||||
ShippingDocuments: List<ShippingDocument>
|
|
||||||
navigation: "one-to-many"
|
|
||||||
State: string
|
|
||||||
Street: string
|
|
||||||
TaxId: string
|
|
||||||
Id: int
|
|
||||||
primary-key: true
|
|
||||||
|
|
||||||
Shipping: "Inbound delivery event at warehouse"
|
|
||||||
table-name: "fbShipping"
|
|
||||||
CargoCompany: string
|
|
||||||
Comment: string
|
|
||||||
Created: DateTime
|
|
||||||
IsAllMeasured: bool
|
|
||||||
LicencePlate: string
|
|
||||||
MeasuredDate: DateTime?
|
|
||||||
Modified: DateTime
|
|
||||||
ShippingDate: DateTime
|
|
||||||
ShippingDocuments: List<ShippingDocument>
|
|
||||||
navigation: "one-to-many"
|
|
||||||
Id: int
|
|
||||||
primary-key: true
|
|
||||||
|
|
||||||
ShippingDocument: "Supplier delivery note or invoice"
|
|
||||||
table-name: "fbShippingDocument"
|
|
||||||
Comment: string
|
|
||||||
Country: string
|
|
||||||
Created: DateTime
|
|
||||||
DocumentIdNumber: string
|
|
||||||
IsAllMeasured: bool
|
|
||||||
Modified: DateTime
|
|
||||||
Partner: Partner
|
|
||||||
foreign-key: "PartnerId"
|
|
||||||
navigation: "many-to-one"
|
|
||||||
PartnerId: int
|
|
||||||
PdfFileName: string
|
|
||||||
Shipping: Shipping
|
|
||||||
foreign-key: "ShippingId"
|
|
||||||
navigation: "many-to-one"
|
|
||||||
ShippingDate: DateTime
|
|
||||||
ShippingDocumentToFiles: List<ShippingDocumentToFiles>
|
|
||||||
navigation: "one-to-many"
|
|
||||||
ShippingId: int?
|
|
||||||
ShippingItems: List<ShippingItem>
|
|
||||||
navigation: "one-to-many"
|
|
||||||
TotalPallets: int
|
|
||||||
Id: int
|
|
||||||
primary-key: true
|
|
||||||
|
|
||||||
ShippingDocumentToFiles: "Links documents to files with type"
|
|
||||||
table-name: "fbShippingDocumentToFiles"
|
|
||||||
Created: DateTime
|
|
||||||
DocumentType: DocumentType
|
|
||||||
DocumentTypeId: int
|
|
||||||
FilesId: int
|
|
||||||
Modified: DateTime
|
|
||||||
ShippingDocument: ShippingDocument
|
|
||||||
foreign-key: "ShippingDocumentId"
|
|
||||||
navigation: "many-to-one"
|
|
||||||
ShippingDocumentFile: Files
|
|
||||||
foreign-key: "FilesId"
|
|
||||||
navigation: "many-to-one"
|
|
||||||
ShippingDocumentId: int
|
|
||||||
Id: int
|
|
||||||
primary-key: true
|
|
||||||
|
|
||||||
ShippingItem: "Product line on shipping document"
|
|
||||||
table-name: "fbShippingItem"
|
|
||||||
Created: DateTime
|
|
||||||
GrossWeightOnDocument: double
|
|
||||||
HungarianName: string
|
|
||||||
IsMeasurable: bool
|
|
||||||
IsMeasured: bool
|
|
||||||
MeasuredGrossWeight: double
|
|
||||||
MeasuredNetWeight: double
|
|
||||||
MeasuredQuantity: int
|
|
||||||
MeasuringCount: int
|
|
||||||
MeasuringStatus: MeasuringStatus
|
|
||||||
constraints: "readonly, not-mapped"
|
|
||||||
Modified: DateTime
|
|
||||||
Name: string
|
|
||||||
NameOnDocument: string
|
|
||||||
NetWeightOnDocument: double
|
|
||||||
Pallet: Pallet
|
|
||||||
foreign-key: "PalletId"
|
|
||||||
navigation: "many-to-one"
|
|
||||||
PalletId: int?
|
|
||||||
PalletsOnDocument: int
|
|
||||||
ProductDto: ProductDto
|
|
||||||
foreign-key: "ProductId"
|
|
||||||
navigation: "many-to-one"
|
|
||||||
ProductId: int?
|
|
||||||
QuantityOnDocument: int
|
|
||||||
ShippingDocument: ShippingDocument
|
|
||||||
foreign-key: "ShippingDocumentId"
|
|
||||||
navigation: "many-to-one"
|
|
||||||
ShippingDocumentId: int
|
|
||||||
ShippingItemPallets: List<ShippingItemPallet>
|
|
||||||
navigation: "one-to-many"
|
|
||||||
UnitPriceOnDocument: double
|
|
||||||
Id: int
|
|
||||||
primary-key: true
|
|
||||||
|
|
||||||
ShippingItemPallet: "Measurement record for incoming goods"
|
|
||||||
table-name: "fbShippingItemPallet"
|
|
||||||
purpose: "Always created even without physical pallet"
|
|
||||||
ShippingItem: ShippingItem
|
|
||||||
foreign-key: "ShippingItemId"
|
|
||||||
navigation: "many-to-one"
|
|
||||||
ShippingItemId: int
|
|
||||||
Created: DateTime
|
|
||||||
CreatorId: int?
|
|
||||||
GrossWeight: double
|
|
||||||
IsMeasured: bool
|
|
||||||
MeasuringStatus: MeasuringStatus
|
|
||||||
constraints: "readonly, not-mapped"
|
|
||||||
Modified: DateTime
|
|
||||||
ModifierId: int?
|
|
||||||
NetWeight: double
|
|
||||||
business-logic: "get => GrossWeight - PalletWeight - (TrayQuantity * TareWeight)"
|
|
||||||
constraints: "readonly, not-mapped"
|
|
||||||
PalletWeight: double
|
|
||||||
TareWeight: double
|
|
||||||
TrayQuantity: int
|
|
||||||
Id: int
|
|
||||||
primary-key: true
|
|
||||||
|
|
||||||
StockTaking: "Inventory session record"
|
|
||||||
table-name: "fbStockTaking"
|
|
||||||
Created: DateTime
|
|
||||||
Creator: int
|
|
||||||
IsClosed: bool
|
|
||||||
Modified: DateTime
|
|
||||||
StartDateTime: DateTime
|
|
||||||
StockTakingItems: List<StockTakingItem>
|
|
||||||
navigation: "one-to-many"
|
|
||||||
Id: int
|
|
||||||
primary-key: true
|
|
||||||
|
|
||||||
StockTakingItem: "Line item for product reconciliation"
|
|
||||||
table-name: "fbStockTakingItem"
|
|
||||||
purpose: "Reconciles snapshot quantity with physical count"
|
|
||||||
InProcessOrdersQuantity: int
|
|
||||||
IsInvalid: bool
|
|
||||||
constraints: "readonly, not-mapped"
|
|
||||||
IsMeasurable: bool
|
|
||||||
IsRequiredForMeasuring: bool
|
|
||||||
constraints: "readonly, not-mapped"
|
|
||||||
MeasuredNetWeight: double
|
|
||||||
NetWeightDiff: double
|
|
||||||
constraints: "readonly, not-mapped"
|
|
||||||
OriginalNetWeight: double
|
|
||||||
QuantityDiff: int
|
|
||||||
constraints: "readonly, not-mapped"
|
|
||||||
StockTakingItemPallets: List<StockTakingItemPallet>
|
|
||||||
navigation: "one-to-many"
|
|
||||||
TotalOriginalQuantity: int
|
|
||||||
constraints: "readonly, not-mapped"
|
|
||||||
Created: DateTime
|
|
||||||
IsMeasured: bool
|
|
||||||
MeasuredStockQuantity: int
|
|
||||||
Modified: DateTime
|
|
||||||
OriginalStockQuantity: int
|
|
||||||
Product: ProductDto
|
|
||||||
foreign-key: "ProductId"
|
|
||||||
navigation: "many-to-one"
|
|
||||||
ProductId: int
|
|
||||||
StockTaking: StockTaking
|
|
||||||
foreign-key: "StockTakingId"
|
|
||||||
navigation: "many-to-one"
|
|
||||||
StockTakingId: int
|
|
||||||
Id: int
|
|
||||||
primary-key: true
|
|
||||||
|
|
||||||
StockTakingItemPallet: "Weight record for inventory item"
|
|
||||||
table-name: "fbStockTakingItemPallet"
|
|
||||||
purpose: "Mandatory for every inventory item, even non-measurable"
|
|
||||||
StockTakingItem: StockTakingItem
|
|
||||||
foreign-key: "StockTakingItemId"
|
|
||||||
navigation: "many-to-one"
|
|
||||||
StockTakingItemId: int
|
|
||||||
Created: DateTime
|
|
||||||
CreatorId: int?
|
|
||||||
GrossWeight: double
|
|
||||||
IsMeasured: bool
|
|
||||||
MeasuringStatus: MeasuringStatus
|
|
||||||
constraints: "readonly, not-mapped"
|
|
||||||
Modified: DateTime
|
|
||||||
ModifierId: int?
|
|
||||||
NetWeight: double
|
|
||||||
business-logic: "get => GrossWeight - PalletWeight - (TrayQuantity * TareWeight)"
|
|
||||||
constraints: "readonly, not-mapped"
|
|
||||||
PalletWeight: double
|
|
||||||
TareWeight: double
|
|
||||||
TrayQuantity: int
|
|
||||||
Id: int
|
|
||||||
primary-key: true
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue