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

801 lines
31 KiB
Markdown

# Domain Model Schema (Toon Format)
> Part of `Nop.Plugin.Misc.FruitBankPlugin`. See `README.md` for project overview.
> Full domain model in Toon (Token-Oriented Object Notation) format — see `AyCode.Core/Serializers/Toons/README.md` (in AyCode.Core solution).
> This is the authoritative schema for entities, DTOs, and enums in the FruitBank domain.
> For behavioral documentation (workflows, lifecycles, event cascades) see `docs/DOMAIN_MODEL.md`.
@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", "PreOrderItemStatus", "PreOrderStatus", "DocumentType", "Files", "Pallet", "ProductDto", "Customer", "PreOrderItem", "PreOrder", "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
PreOrderItemStatus: enum
underlying-type: "int"
default-value: 0
values:
Pending = 0
Fulfilled = 10
PartiallyFulfilled = 20
Dropped = 30
PreOrderStatus: enum
underlying-type: "int"
default-value: 0
values:
Pending = 0
Confirmed = 10
PartiallyFulfilled = 20
Cancelled = 30
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
PreOrderItem: "Single product line of a customer preorder with fulfilment tracking"
table-name: "fbPreOrderItem"
purpose: "A requested product line within a PreOrder. Tracks requested versus cumulatively fulfilled quantity as incoming stock is allocated across one or more shipping-document conversion runs."
FulfilledQuantity: int
purpose: "Quantity allocated from incoming stock so far; accumulates across conversion runs until it reaches RequestedQuantity."
business-logic: "this >= 0 && this <= RequestedQuantity"
PreOrderId: int
purpose: "FK to the parent PreOrder."
ProductId: int
purpose: "FK to the nopCommerce Product being preordered."
RequestedQuantity: int
purpose: "Quantity of the product the customer requested."
constraints: "positive"
Status: PreOrderItemStatus
purpose: "Item lifecycle: Pending / Fulfilled (fully allocated) / PartiallyFulfilled (partly allocated) / Dropped (expired or no incoming stock)."
business-logic: "set during conversion: FulfilledQuantity >= RequestedQuantity ? Fulfilled : FulfilledQuantity > 0 ? PartiallyFulfilled : Dropped; stays Pending until first allocation"
UnitPriceInclTax: decimal
purpose: "Gross unit price locked at preorder time. Used as the order-item price on conversion for non-measurable products; measurable products are priced 0 at conversion and weighed afterwards."
constraints: "non-negative"
Id: int
purpose: "Primary key / unique identification"
primary-key: true
PreOrder: "Customer advance order placed before the goods physically arrive"
table-name: "fbPreOrder"
purpose: "Header of a customer pre-order against an upcoming inbound delivery. When a supplier shipping document confirms incoming stock, pending items are allocated first-come-first-served by PreOrderId (only within the conversion window — PreOrderConversionWindowDays, 4 days, of DateOfReceipt) and the preorder is converted into a real NopCommerce Order once any quantity is fulfilled. Preorders past DateOfReceipt are swept closed, dropping any still-Pending items."
CreatedOnUtc: DateTime
CustomerId: int
purpose: "FK to the nopCommerce Customer who placed the preorder."
CustomerNote: string
purpose: "Optional free-text note entered by the customer when placing the preorder."
DateOfReceipt: DateTime
purpose: "Requested delivery date. Drives the conversion window (only preorders within PreOrderConversionWindowDays — 4 days — of this date are eligible for allocation) and the expiry sweep — once this date is past, any still-Pending items are Dropped."
OrderId: int?
purpose: "FK to the real NopCommerce Order created from this preorder. Null until the first item is fulfilled; set once on first conversion and reused so subsequent shipping documents append items to the same order."
PreOrderItems: List<PreOrderItem>
other-key: "PreOrderId"
navigation: "one-to-many"
Status: PreOrderStatus
purpose: "Header lifecycle: Pending / Confirmed (all items Fulfilled) / PartiallyFulfilled (some Dropped or partial, none left Pending) / Cancelled."
business-logic: "set by RefreshPreOrderStatusAsync from item states: items.All(Fulfilled) => Confirmed; (any Dropped or PartiallyFulfilled) && none Pending => PartiallyFulfilled; else Pending. Cancelled is set explicitly."
StoreId: int
purpose: "nopCommerce multi-store scope."
UpdatedOnUtc: DateTime
purpose: "Bumped to UtcNow on every status / allocation change."
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"
PreOrders: List<PreOrder>
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, used to verify that the net weight being sent to the customer is accurate and audited. NOTE: Despite the 'Pallet' name, this is a general measurement record that is ALWAYS created for every item. If the product is not measurable (IsMeasurable=false), weights are recorded as 0.0 and only TrayQuantity is stored."
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?
ForeignKey: int
business-logic: "get => ForeignItemId"
constraints: "readonly, not-mapped"
GrossWeight: double
purpose: "Measured gross weight; 0.0 if product is not measurable"
IsMeasured: bool
purpose: "Status flag"
MeasuringStatus: MeasuringStatus
business-logic: "get => IsMeasured ? MeasuringStatus.Finnished : Id > 0 ? MeasuringStatus.Started : MeasuringStatus.NotStarted"
constraints: "readonly, not-mapped"
Modified: DateTime
ModifierId: int?
NetWeight: double
business-logic: "get => GrossWeight - PalletWeight - (TrayQuantity * TareWeight)"
constraints: "readonly, not-mapped"
PalletWeight: double
purpose: "Weight of the physical pallet if used; 0.0 if goods arrive without a pallet"
TareWeight: double
TrayQuantity: int
purpose: "Always recorded, regardless of measurability"
Id: int
purpose: "Primary key / unique identification"
primary-key: true
Partner: "Business partner with address and tax information"
table-name: "fbPartner"
purpose: "Represents an external legal entity, specifically a Supplier who provides goods or a business partner involved in the procurement chain"
ShippingDocuments: List<ShippingDocument>
other-key: "PartnerId"
navigation: "one-to-many"
inverse-property: "Partner"
CertificationNumber: string
City: string
Country: string
CountryCode: string
County: string
Created: DateTime
Modified: DateTime
Name: string
PostalCode: string
State: string
Street: string
TaxId: string
Id: int
purpose: "Primary key / unique identification"
primary-key: true
Shipping: "Shipping record with documents and measurement tracking"
table-name: "fbShipping"
purpose: "Represents a physical inbound delivery event (truck arrival) at the warehouse, tracking the vehicle and the overall measurement status of the shipment"
CargoCompany: string
Comment: string
Created: DateTime
IsAllMeasured: bool
purpose: "Status flag"
LicencePlate: string
MeasuredDate: DateTime?
Modified: DateTime
ShippingDate: DateTime
ShippingDocuments: List<ShippingDocument>
other-key: "ShippingId"
navigation: "one-to-many"
inverse-property: "Shipping"
Id: int
purpose: "Primary key / unique identification"
primary-key: true
ShippingDocument: "Shipping document with partner, items and files"
table-name: "fbShippingDocument"
purpose: "A digital representation of a supplier's delivery note or invoice associated with the shipment, used for reconciling paper-based data with measured reality"
Comment: string
Country: string
Created: DateTime
DocumentIdNumber: string
IsAllMeasured: bool
purpose: "Status flag"
Modified: DateTime
Partner: Partner
foreign-key: "PartnerId"
navigation: "many-to-one"
inverse-property: "ShippingDocuments"
PartnerId: int
PdfFileName: string
Shipping: Shipping
foreign-key: "ShippingId"
navigation: "many-to-one"
inverse-property: "ShippingDocuments"
ShippingDate: DateTime
ShippingDocumentToFiles: List<ShippingDocumentToFiles>
other-key: "ShippingDocumentId"
navigation: "one-to-many"
inverse-property: "ShippingDocument"
ShippingId: int?
ShippingItems: List<ShippingItem>
other-key: "ShippingDocumentId"
navigation: "one-to-many"
inverse-property: "ShippingDocument"
TotalPallets: int
Id: int
purpose: "Primary key / unique identification"
primary-key: true
ShippingDocumentToFiles: "Links shipping documents to files with document type"
table-name: "fbShippingDocumentToFiles"
purpose: "A many-to-many link table that associates general uploaded files with specific shipping documents, assigning a functional context (DocumentType) to each file, such as identifying which PDF is the supplier's invoice versus the packing list"
Created: DateTime
DocumentType: DocumentType
purpose: "Enum wrapper"
business-logic: "get, set => DocumentTypeId"
constraints: "not-mapped"
DocumentTypeId: int
constraints: "enum-reference: DocumentType, enum-type: DocumentType"
FilesId: int
Modified: DateTime
ShippingDocument: ShippingDocument
foreign-key: "ShippingDocumentId"
navigation: "many-to-one"
inverse-property: "ShippingDocumentToFiles"
ShippingDocumentFile: Files
foreign-key: "FilesId"
navigation: "many-to-one"
ShippingDocumentId: int
Id: int
purpose: "Primary key / unique identification"
primary-key: true
ShippingItem: "Shipping document item with measurements and pallets"
table-name: "fbShippingItem"
purpose: "Represents a specific product line item within a shipping document, storing the discrepancy between the supplier's declared weight/quantity and the warehouse's measured values"
Created: DateTime
GrossWeightOnDocument: double
HungarianName: string
IsMeasurable: bool
purpose: "Status flag"
IsMeasured: bool
purpose: "Status flag"
MeasuredGrossWeight: double
constraints: "range: 1-100000"
MeasuredNetWeight: double
constraints: "range: 1-100000"
MeasuredQuantity: int
constraints: "range: 1-100000"
MeasuringCount: int
constraints: "range: 1-100000, non-negative"
MeasuringStatus: MeasuringStatus
business-logic: "get => complex conditional logic based on IsMeasured and ShippingItemPallets status"
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?
ProductName: string
business-logic: "get => ProductDto?.Name ?? Name"
constraints: "readonly, not-mapped"
QuantityOnDocument: int
ShippingDocument: ShippingDocument
foreign-key: "ShippingDocumentId"
navigation: "many-to-one"
inverse-property: "ShippingItems"
ShippingDocumentId: int
ShippingItemPallets: List<ShippingItemPallet>
other-key: "ShippingItemId"
navigation: "one-to-many"
inverse-property: "ShippingItem"
UnitPriceOnDocument: double
Id: int
purpose: "Primary key / unique identification"
primary-key: true
ShippingItemPallet: "Pallet measurements for shipping items"
table-name: "fbShippingItemPallet"
purpose: "The smallest unit of measurement tracking, representing a single physical measurement event. NOTE: Technically named 'Pallet' for legacy reasons, but it is ALWAYS created even if goods arrive without a physical pallet. For non-measurable products, weights are 0.0 and only TrayQuantity is tracked for tare-weight calculations."
ShippingItem: ShippingItem
foreign-key: "ShippingItemId"
navigation: "many-to-one"
inverse-property: "ShippingItemPallets"
ShippingItemId: int
Created: DateTime
CreatorId: int?
ForeignKey: int
business-logic: "get => ForeignItemId"
constraints: "readonly, not-mapped"
GrossWeight: double
purpose: "Measured gross weight; 0.0 if product is not measurable"
IsMeasured: bool
purpose: "Status flag"
MeasuringStatus: MeasuringStatus
business-logic: "get => IsMeasured ? MeasuringStatus.Finnished : Id > 0 ? MeasuringStatus.Started : MeasuringStatus.NotStarted"
constraints: "readonly, not-mapped"
Modified: DateTime
ModifierId: int?
NetWeight: double
business-logic: "get => GrossWeight - PalletWeight - (TrayQuantity * TareWeight)"
constraints: "readonly, not-mapped"
PalletWeight: double
purpose: "Weight of the physical pallet if used; 0.0 if goods arrive without a pallet"
TareWeight: double
TrayQuantity: int
purpose: "Always recorded, regardless of measurability"
Id: int
purpose: "Primary key / unique identification"
primary-key: true
StockTaking: "Inventory session record"
table-name: "fbStockTaking"
purpose: "Orchestrates inventory sessions by freezing logical stock states"
Created: DateTime
Creator: int
IsClosed: bool
purpose: "Status flag"
Modified: DateTime
StartDateTime: DateTime
StockTakingItems: List<StockTakingItem>
other-key: "StockTakingId"
navigation: "one-to-many"
inverse-property: "StockTaking"
Id: int
purpose: "Primary key / unique identification"
primary-key: true
StockTakingItem: "Line item for product reconciliation"
table-name: "fbStockTakingItem"
purpose: "Reconciles snapshot quantity with physical count to calculate final stock delta"
DisplayText: string
business-logic: "get => conditional string based on IsInvalid, IsMeasured, IsRequiredForMeasuring"
constraints: "readonly, not-mapped"
InProcessOrdersQuantity: int
purpose: "Reserved stock buffer (not yet shipped) to prevent double-deduction during closing"
IsInvalid: bool
purpose: "Status flag"
business-logic: "get => TotalOriginalQuantity < 0"
constraints: "readonly, not-mapped"
IsMeasurable: bool
purpose: "Status flag"
IsRequiredForMeasuring: bool
purpose: "Status flag"
business-logic: "get => !IsInvalid && (TotalOriginalQuantity != 0 || OriginalNetWeight != 0)"
constraints: "readonly, not-mapped"
MeasuredNetWeight: double
NetWeightDiff: double
business-logic: "get => IsMeasurable && IsMeasured ? double.Round(MeasuredNetWeight - OriginalNetWeight, 1) : 0d"
constraints: "readonly, not-mapped"
OriginalNetWeight: double
QuantityDiff: int
purpose: "Final adjustment value for Product.StockQuantity"
business-logic: "get => IsMeasured ? MeasuredStockQuantity - TotalOriginalQuantity : 0"
constraints: "readonly, not-mapped"
StockTakingItemPallets: List<StockTakingItemPallet>
other-key: "StockTakingItemId"
navigation: "one-to-many"
inverse-property: "StockTakingItem"
TotalOriginalQuantity: int
purpose: "Snapshot of total logical stock at session start"
business-logic: "get => OriginalStockQuantity + InProcessOrdersQuantity"
constraints: "readonly, not-mapped"
Created: DateTime
IsMeasured: bool
purpose: "Status flag"
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"
inverse-property: "StockTakingItems"
StockTakingId: int
Id: int
purpose: "Primary key / unique identification"
primary-key: true
StockTakingItemPallet: "Weight record for inventory item"
table-name: "fbStockTakingItemPallet"
purpose: "Granular weight-based evidence for a stock taking line item. NOTE: This record is mandatory for every inventory item. If weighing is skipped (non-measurable), it serves as a container for TrayQuantity with zeroed weight fields. The term 'Pallet' is a legacy naming convention."
StockTakingItem: StockTakingItem
foreign-key: "StockTakingItemId"
navigation: "many-to-one"
inverse-property: "StockTakingItemPallets"
StockTakingItemId: int
Created: DateTime
CreatorId: int?
ForeignKey: int
business-logic: "get => ForeignItemId"
constraints: "readonly, not-mapped"
GrossWeight: double
purpose: "Measured gross weight; 0.0 if product is not measurable"
IsMeasured: bool
purpose: "Status flag"
MeasuringStatus: MeasuringStatus
business-logic: "get => IsMeasured ? MeasuringStatus.Finnished : Id > 0 ? MeasuringStatus.Started : MeasuringStatus.NotStarted"
constraints: "readonly, not-mapped"
Modified: DateTime
ModifierId: int?
NetWeight: double
business-logic: "get => GrossWeight - PalletWeight - (TrayQuantity * TareWeight)"
constraints: "readonly, not-mapped"
PalletWeight: double
purpose: "Weight of the physical pallet if used; 0.0 if goods arrive without a pallet"
TareWeight: double
TrayQuantity: int
purpose: "Always recorded, regardless of measurability"
Id: int
purpose: "Primary key / unique identification"
primary-key: true
}