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

858 lines
33 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", "CargoPartner", "CargoTruck", "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
CargoPartner: "Transport / haulage company (carrier) with its vehicle fleet"
table-name: "fbCargoPartner"
purpose: "A carrier that delivers goods to the warehouse and owns the CargoTrucks (both trucks and trailers). Distinct from Partner, which is the goods supplier. Name, address and tax fields are inherited from PartnerBase."
CargoTrucks: List<CargoTruck>
other-key: "CargoPartnerId"
navigation: "one-to-many"
inverse-property: "CargoPartner"
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
CargoTruck: "Cargo vehicle — truck or trailer — owned by a transport partner"
table-name: "fbCargoTruck"
purpose: "A single vehicle in a transport company's fleet. One table holds both tractor units and trailers, distinguished by IsTrailer. Truck and trailer are tracked as separate vehicles because Hungarian EKÁER road-freight reporting (NAV) declares the towing vehicle and the trailer as distinct entries (vehicle / vehicle2), each with its own licence plate and country code — i.e. these shipments carry an EKÁER declaration obligation."
CargoPartner: CargoPartner
foreign-key: "CargoPartnerId"
navigation: "many-to-one"
inverse-property: "CargoTrucks"
CargoPartnerId: int
purpose: "FK to the owning transport company (CargoPartner) — the carrier, not the goods supplier."
CargoPartnerName: string
constraints: "readonly, not-mapped"
CountryCode: string
Created: DateTime
IsTrailer: bool
purpose: "Discriminates the shared table: false = tractor/truck unit, true = trailer."
LicencePlate: string
Modified: DateTime
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"
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: "Inbound delivery event (truck arrival) at the warehouse. Created early and filled progressively — carrier, truck and trailer are assigned later."
CargoCompany: string
CargoPartner: CargoPartner
purpose: "Carrier (transport company); assigned later, null until known. Supplier is separate — see ShippingDocument.Partner."
foreign-key: "CargoPartnerId"
navigation: "many-to-one"
CargoPartnerId: int?
CargoTrailer: CargoTruck
purpose: "Trailer (CargoTruck table, IsTrailer=true); optional, assigned later — null if none or not yet known."
foreign-key: "CargoTrailerId"
navigation: "many-to-one"
CargoTrailerId: int?
CargoTruck: CargoTruck
purpose: "Tractor unit (CargoTruck, IsTrailer=false) from the carrier's fleet; assigned later, null until known."
foreign-key: "CargoTruckId"
navigation: "many-to-one"
CargoTruckId: int?
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: "Supplier's delivery note or invoice for the shipment; reconciles paper data with measured reality. Populated progressively — much entered at order time, the rest as it becomes known."
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
}