ZuloOne
English
Sign in
Menu

05 · Purchasing — purchase orders, receipts, returns, and vendor payments

Updated

Solution layer. Depends on Accounting, Common, Inventory, Organization, and Tax. Purchasing covers goods inflow: supplier order, receipt into the store, accounts-payable settlement, and the mirror correction documents: purchase return and purchase credit note.

← General specification

Purpose#

PurchaseOrder moves through Draft → Ordered → Received. On Received it moves Stock, calculates input VAT through the Tax engine, recognizes the vendor liability in Payable, and creates a PutAwayTask for storage. Receipt cancellation is split into two documents with different responsibility. PurchaseReturn returns physical goods and the net amount to the supplier: store and net payable. PurchaseCreditNote adjusts only input VAT and the tax part of the payable. They complement each other; they do not replace each other. VendorPayment settles the payable as a separate document, not as an order subtype. It mirrors CustomerPayment in Sales and PayrollPayment in HR.

Process description for analysts: Sales and purchasing. This page is the object-level reference.

What is created (object map)#

Kind Name Purpose
Model Purchasing module model, Solution(2) layer
NumberSequence PurchaseOrderSeq, PurchaseReturnSeq, PurchaseCreditNoteSeq, VendorPaymentSeq, SupplierInvoiceSeq, PurchasingSettingsSeq numbering
Dictionary PurchasingSettings module settings (singleton): auto-receipt and default payment term
TablePart PurchaseOrderLines, PurchaseReturnLines, PurchaseCreditNoteLines, VendorPaymentLines, SupplierInvoiceLines lines
Document PurchaseOrder order/receipt (Draft→Ordered→Received)
Document PurchaseReturn return to supplier: store minus and payable minus (net)
Document PurchaseCreditNote input VAT and the tax part of the payable, without stock movement
Document SupplierInvoice the supplier's own paper (Draft→Registered): books only the difference from what the receipt accrued
Document VendorPayment payment to supplier, separate document
Register Payable accounts payable by supplier
Analytic Supplier reused analytic over the Supplier dictionary, for Payable
Service PurchaseReceiptService order receipt, including partial receipt
Service SupplierInvoiceMatchService accrued vs invoiced totals and the tolerance check
Menu menu.json module menu
— reused — Item/Supplier/StoreCell/Stock/IStoreCellService/IStockAvailabilityService/IPricingService (Inventory), Money (Accounting), PaymentTerm/IRecordDefaults/IPaymentDueService (Common), LegalEntity (Organization), tax engine (Tax) not created here

Total: 1 model, 6 number sequences, 1 dictionary (singleton), 5 table parts, 5 documents, 1 register, 2 services, 8 commands, and menu. The model has no own EDTs and no link tables. All reference fields use EDTs from other models; document links use the common document-reference graph, not LT_* objects.

model.json#

Solution(2) layer. Dependencies: Accounting (≥1.0.0), Common (≥1.10.0), Inventory (≥1.0.0), Organization (≥1.0.0), Tax (≥1.0.0).

The dependency on Accounting is only for the Money EDT. Purchasing itself does not depend on Accounting just for the type any more: receipt, return and payment write their own ledger legs (PurchaseReceiptGLTx, PurchaseReturnGLTx, VendorPaymentGLTx) through IGeneralLedgerService.EntryAsync; see Who writes the general ledger.

Number sequences#

PurchaseOrderSeq, PurchaseReturnSeq, PurchaseCreditNoteSeq, VendorPaymentSeq, SupplierInvoiceSeq, PurchasingSettingsSeq (the singleton dictionary also has a sequence).

Table parts#

PurchaseOrderLines: Item→Item (required), Quantity Qty (required, unit is Unit, normalized into hidden BaseQuantity), UnitPrice Money (required), ReceiveQty Qty (optional, “receive now” for partial receipt; see PurchaseReceiptService).

SupplierInvoiceLines: Item (required), Quantity (required), UnitPrice (required) — the supplier's own figures, which are allowed to disagree with the order the invoice is linked to.

PurchaseReturnLines, PurchaseCreditNoteLines: Item (required), Quantity (required), UnitPrice (required). They have no unit field and no BaseQuantity: the line repeats the original receipt position, where unit conversion has already happened.

VendorPaymentLines: Supplier→Supplier (required), Amount Money (required). Supplier is on the line, not the header: one payment can close debt for several suppliers.

EDT#

None. RefSupplier/RefStoreCell/RefItem/RefUnitOfMeasure/Qty come from Inventory, RefLegalEntity from Organization, RefPaymentTerm from Common, TaxRateValue from Tax, and Money from Accounting.

Dictionaries#

PurchasingSettings#

One record per tenant (isSingleton, isCached).

AutoReceiveOnOrder Boolean (optional): when an order is confirmed, it tries to receive immediately; without the flag, receipt is a separate step. See the PlaceOrder command. DefaultPaymentTerm→PaymentTerm (optional), DefaultPaymentTermDays Integer (optional, hidden): stamped from DefaultPaymentTerm.Days in OnBeforeSaveAsync. If the link is empty, OnAfterLoadAsync restores DefaultPaymentTerm by reverse lookup on DefaultPaymentTermDays. This is the compatibility path for settings stored before the link field existed.

InvoiceMatchTolerance Decimal 18,2 (optional): the largest difference RegisterSupplierInvoice accepts between the invoice and what the receipts accrued. Zero means no limit.

Documents#

PurchaseOrder#

  • Header: Supplier→Supplier (required) · Location→StoreCell (required, caption “Cell”) · PaymentTerm→PaymentTerm (optional) · DueDate DateTime (optional, stamped on each save from the contract/module payment term) · ExpectedReceipt DateTime (optional, expected shelf date, not derived from DueDate) · LegalEntity→LegalEntity (optional, buyer; normally stamped by the server from the cell chain on Received, not entered manually) · NonRecoverableVat Decimal(18,2) (optional, hidden: the input VAT share that cannot be deducted and is capitalized into stock cost by Costing).
  • TP-Lines (PurchaseOrderLines): see Table parts.
  • Subtypes: Draft (initial) → Ordered → Received (isReadOnly). The metadata declares only Draft→Ordered. Ordered→Received happens programmatically inside PurchaseReceiptService, which is legal for services; the user path goes through a command.
  • Events:
    • OnBeforeCreateAsync: fills LegalEntity/PaymentTerm/DueDate through IRecordDefaults.SeedAsync, if they are empty.
    • OnBeforeSaveAsync: rereads ExpectedReceipt from the raw save package before next() because otherwise a partial update of one subtype erases the field. It stamps DueDate through IPaymentDueService from the contract payment term or the module default (PurchasingSettings.DefaultPaymentTermDays).
    • OnBeforePostAsync: refuses empty lines or lines with Quantity ≤ 0. Only on Received, Location must be a receiving cell (IStoreCellService.IsCellAllowedForAsync(…, Receiving), the store discipline); a tax rate must exist on the date if a tax code is specified. It calculates and stamps NonRecoverableVat. If LegalEntity is still a placeholder, it resolves it from the receipt cell chain Cell→Zone→Store→Division through IStoreCellService.GetLegalEntityAsync. This is a point header-only update, not a full save.
    • OnAfterPostAsync (Received): opens an INPUT tax calculation (ITaxService.CreateCalculationAsync, tax point = document date) and links it to the order through the document-reference graph (IDocumentManager.AddLinkAsync, not a link table). If store discipline is enabled, it idempotently creates a Draft PutAwayTask with lines from the order, searched by the same reference graph.
  • Posting subtype Received (executionOrder): GoodsReceiptStockTx (Purchasing, +Stock by Item/Cell=Location) → GoodsReceiptPayableTx (Purchasing, +Payable by Supplier) → ReceiptCostTx/ReceiptFifoTx (Costing, open the InventoryValue/ItemCostFifo layer) → UaPurchaseReceiptTx (22-Ukraine, first event).

PurchaseReturn#

Only physical goods and the net amount. It does not touch the tax part; that is the job of PurchaseCreditNote.

  • Header: Supplier (required) · Location→StoreCell (required, caption “Return Cell”) · OriginalOrder — plain Guid, not a Reference EDT. This is the only known deviation in the whole model from the rule “every reference to an entity uses a Reference EDT”. Fix it on the next object edit; do not silently document it as an EDT.
  • TP-Lines (PurchaseReturnLines): Item, Quantity, UnitPrice (all required).
  • Subtypes: Draft → Posted (isReadOnly).
  • Events: OnBeforeSaveAsync copies Supplier/Location and all lines from OriginalOrder if it is specified and the return has no lines yet. OnBeforePostAsync (Posted) refuses no lines, lines with Quantity ≤ 0, and missing Supplier/Location. It checks physical balance for every position through IStockAvailabilityService.HasSufficientStockAsync and refuses with “need/have” when stock is short.
  • Posting subtype Posted: PurchaseReturnStockTx (−Stock) → PurchaseReturnPayableTx (−Payable by Supplier).

PurchaseCreditNote#

Only the tax part and its share in the payable for an already received order. The order stays Received; it is not cancelled. Stock and net amount are handled by PurchaseReturn. The two documents solve different parts of the same “wrong receipt” problem. They are usually issued together, but independently.

  • Header: Supplier (required) · LegalEntity (optional, “buyer's legal entity”) · OriginalOrder, the same plain Guid deviation as in PurchaseReturn · TaxRateApplied→TaxRateValue (Tax) optional.
  • TP-Lines (PurchaseCreditNoteLines): Item, Quantity, UnitPrice (all required). These lines are the base for VAT recalculation, not a physical return.
  • Subtypes: Draft → Posted (isReadOnly).
  • Events: OnBeforeCreateAsync seeds LegalEntity. OnBeforeSaveAsync, when OriginalOrder is set, pulls Supplier from the order if it is empty; resolves LegalEntity from the receipt cell while the current value is still the module placeholder (otherwise the tenant default would be stamped instead of the real buyer); stamps TaxRateApplied with the current rate on the order date (ITaxService.ResolveDefaultTaxCodeAsync/ResolveRateAsync) if it is not already set; and copies lines from the order if lines are empty. OnBeforePostAsync (Posted) refuses missing OriginalOrder; the order must exist, be Received, and have the same Supplier; while LegalEntity is still a placeholder, it recalculates and rewrites the header only, then refuses if it is still empty; refuses no lines or lines with Quantity ≤ 0; refuses TaxRateApplied ≤ 0 with the meaning “there was no VAT on the receipt, so there is nothing to credit.” OnAfterPostAsync builds the tax context (legal entity, supplier, item group), calls ITaxService.CreateReversalAsync in the INPUT direction, and links the calculation to the note.
  • Posting subtype Posted: PurchaseCreditNotePayableTx (Purchasing) calculates VAT from the line base using TaxRateApplied, writes −Payable for Supplier, and skips zero/negative rates. 22-Ukraine writes a first-event reversal. The note has no own GL extension: the GL effect goes through the same tax reversal seam (TaxCalculation) as any other VAT. See Tax.

SupplierInvoice#

The supplier's own paper, entered after the goods are in. It exists because the receipt and the invoice are different events: the receipt accrues the payable at the ordered price, the invoice arrives later and may disagree.

It books only the difference. GoodsReceiptPayableTx already added the net line amounts to Payable on Received, and the purchase tax seam added input VAT on top; booking the invoice in full would owe the supplier twice.

  • Header: Supplier (required) · LegalEntity (optional) · SupplierNumber (String 50, indexed, not required at field level) · InvoiceDate · DueDate · PaymentTerm · TaxRateApplied · MatchedAmount · Difference (both Decimal 18,2, stamped by the command).
  • TP-Lines (SupplierInvoiceLines): Item, Quantity, UnitPrice.
  • Subtypes: Draft → Registered (isReadOnly).
  • The order is not a Guid column. Invoice and order are joined through the document-family graph (IDocumentManager.AddLinkAsync), so one invoice can cover several receipts. This is deliberately unlike PurchaseCreditNote / PurchaseReturn, which still carry the plain OriginalOrder deviation.
  • SupplierNumber is required by the command, not by the field. The draft is created from a received order before the supplier's paper exists, so a required field would make EnterSupplierInvoice unable to save what it creates. RegisterSupplierInvoice is the only door into Registered, so the invariant has exactly one enforcement point.
  • Empty dates are clamped to 1901-01-01 in OnBeforeSaveAsync, the same sentinel PurchaseOrderEventHandler uses: an optional document DateTime is non-nullable and unset reads as 0001-01-01, which overflows SqlDateTime. DueDate is computed from PaymentTerm through IPaymentDueService when it is not already set. TaxPointOf treats anything below 1902 as empty, so the sentinel never becomes the day a rate is read on.
  • Events: OnBeforeCreateAsync seeds LegalEntity from IRecordDefaults. OnBeforeSaveAsync clamps the dates and stamps TaxRateApplied from the default tax code on the invoice date. OnBeforePostAsync re-reads the document (the subtype UPDATE carries only the subtype) and refuses a missing supplier, a blank SupplierNumber, no lines, Quantity ≤ 0, a supplier that disagrees with a linked order, and any MatchProblemAsync. OnAfterPostAsync creates a TaxCalculation in the INPUT direction for a positive difference or a reversal for a negative one, and links it. OnBeforeUnpostAsync / OnBeforeDeleteAsync withdraw and delete those calculations.
  • Posting subtype Registered: SupplierInvoicePayableTx (order 1) adds the gross difference — difference plus tax at TaxRateApplied — to Payable for the supplier, and writes nothing when the difference is zero. SupplierInvoiceGLTx (order 7) books Math.Abs(difference) through IGeneralLedgerService.EntryAsync, swapping debit and credit for a negative difference because the service refuses a non-positive amount.
  • The tax seam that adds input VAT to Payable only fires when it can resolve a PurchaseOrder behind the calculation, so it does not double the invoice's own tax.

Example

A purchase order for 4 bolts at 25 is received. VAT is 15%.

Step Payable MatchedAmount Difference TaxCalculation
Receipt 115.00 — — +15.00
Invoice for 4 × 25 115.00 100.00 0.00 none
Invoice for 4 × 30 138.00 100.00 20.00 +3.00
Invoice for 4 × 20 92.00 100.00 −20.00 −3.00

A standalone invoice with no linked order accrues nothing, so the difference is the whole invoice: 2 × 50 becomes 115.00 of payable.

Partial invoicing. SupplierInvoiceMatchService.AccruedAmountAsync matches each invoice line against the receipt price of the same quantity (several order lines of one item average), so a receipt can be invoiced in parts. DoubleBillingProblemAsync refuses an invoice that, with the Registered invoices on the same receipts, bills more of an item than was received; RemainingToInvoiceAsync is what Enter supplier invoice drafts.

VendorPayment#

  • Header: LegalEntity→LegalEntity (optional). Empty leaves the payable repaid, but without GL posting. Supplier is not on the header; it is on the line.
  • TP-Lines (VendorPaymentLines): Supplier (required), Amount (required).
  • Subtypes: Draft → Paid (isReadOnly).
  • Events: OnBeforeCreateAsync seeds LegalEntity. OnBeforePostAsync (Paid) refuses no lines and lines with Amount ≤ 0. There is no balance limit: Payable intentionally allows a negative balance, because overpayment and advance payments are valid. The engine does not cut payment to the balance.
  • Posting subtype Paid: VendorPaymentTx (−Payable for each line.Supplier, not for a header supplier). 22-Ukraine writes the full tax-included amount, unlike Received, where the first event writes the tax-exclusive base.

Exchange differences: Supplier.Currency, ExchangeRate, PayableRevaluation#

Purchasing has no contract, so the supplier's billing currency is the Currency field of the Supplier.Purchasing extension on the supplier card. An extension field is not on the typed class; PurchaseFx reads it through IDataService. Empty, or equal to the buyer entity's currency, means rate 1.

PurchaseOrder stamps ExchangeRate (supplier currency to the entity's, on the receipt date) in OnBeforePost on Received and refuses without a rate. SupplierInvoice stamps the rate on its invoice date; PurchaseReturn and PurchaseCreditNote take the original order's. Payable keeps Amount in the supplier's currency and AmountFunc in the entity's; the receipt ledger leg, InventoryValue / ItemCostFifo (Costing), the input-tax base and NonRecoverableVat are amount × rate. The tax seam posts the calculation's tax to Payable as Amount = tax / rate, AmountFunc = tax.

VendorPaymentLines stamp ExchangeRate (payment date) and CarryingAmount (the supplier slice's average); VendorPaymentGLTx books the gap to FxGainAccountCode / FxLossAccountCode — paying more than carried is a loss. PayableRevaluation (Draft → Posted; commands FillPayableRevaluation, PostPayableRevaluation, CancelPayableRevaluation) revalues open foreign payables at the period-end rate: a rising rate is a loss.

Payable carries a LegalEntity analytic (optional; older movements have none and count only in the supplier's total), written by every payable document from its legal entity; PurchaseFx slices by supplier × legal entity, so each entity's payables are revalued and paid in its own currency. A supplier's Currency cannot change while the supplier is owed anything (SupplierPurchasingEventHandler, an extension of Supplier). Process view: exchange differences.

Example#

Supplier Vendor-1, item Widget, receipt cell Cell-2. Before the scenario, Cell-2 has no goods and payable to Vendor-1 is 0.00. Tax entries are omitted for clarity: the receipt actually writes the INPUT tax calculation and the ItemCostFifo/InventoryValue entry. See Costing and Tax.

Document Action Stock (Widget, Cell-2) Payable (Vendor-1)
— before scenario 0 0.00
PurchaseOrder PO-1 Received: 50 at 8.00 50 400.00
PurchaseReturn RET-1 return 5 pcs (net −40.00) 45 360.00
PurchaseCreditNote CN-1 VAT on PO-1 was overstated by 20.00, without stock movement 45 340.00
VendorPayment PAY-1 300.00 45 40.00

Scenario result: 45 units of Widget remain in the receipt cell, and payable to Vendor-1 is 40.00. Notice that PurchaseReturn and PurchaseCreditNote hit different columns: return moves stock and payable; the note moves only payable.

Registers#

Register dimensions and resources: see Payable in Objects below.

Written by: GoodsReceiptPayableTx (+, receipt), PurchaseReturnPayableTx (−, net return), PurchaseCreditNotePayableTx (−, VAT share only), VendorPaymentTx (−, payment by line). allowNegativeBalance: true means overpayment and advance payment to a supplier are valid; the engine does not block them.

Report PayableBySupplier (Reports/Views/) shows turnover by Supplier with opening/closing balance and nonZeroBalance: true.

Services#

PurchaseReceiptService#

ValidateReceiveAsync(orderId) → string? (null means receipt is possible): the order exists, has lines, all Quantity > 0, Location is a receiving cell, and a tax rate exists on the date when a tax code is present.

ReceiveAsync(orderId) → string? (null means success): runs ValidateReceiveAsync, then performs partial receipt. Lines with ReceiveQty filled are split into a new remainder order by SplitRemainderAsync. Lines without a partial-receipt mark go to the remainder in full; marked lines leave only ReceiveQty on the current order, and the difference goes to the remainder. The remainder order is copied by Supplier/Location/DocumentDate/ LegalEntity/PaymentTerm/ExpectedReceipt, saved, moved to Ordered, and linked to the original order through the document-reference graph. If all ReceiveQty ≤ 0, there is no split: everything is received. After the split, the current order moves to Received.

Cross-model services (IStoreCellService, ITaxService) are injected lazily through ScriptServices.Get<T>(), not through the constructor. This is the same pattern as SalesFulfillmentService in Sales, so the factory does not refuse to start.

SupplierInvoiceMatchService#

The single matching predicate; both transaction scripts and RegisterSupplierInvoice ask it rather than repeating the arithmetic.

MatchedOrdersAsync(invoiceId) → the Received purchase orders in the invoice's document family. AccruedAmountAsync(invoiceId) → the sum of their line amounts. InvoicedAmountAsync(invoiceId) → the sum of the invoice's own lines. Both use IPricingService.LineAmount, the same formula the receipt and the credit note use. ToleranceAsync() → the absolute PurchasingSettings.InvoiceMatchTolerance. MatchProblemAsync(difference) → null when the difference is acceptable; a zero tolerance means no limit.

Commands#

PlaceOrder (“Place order”, Draft→Ordered) refuses no lines or lines with Quantity ≤ 0. If PurchasingSettings.AutoReceiveOnOrder is off, it only moves to Ordered. If it is on, it runs PurchaseReceiptService.ValidateReceiveAsync while the document is still Draft, so a blocked receipt does not leave the order suspended in Ordered. Only then it moves to Ordered and immediately calls ReceiveAsync, which may receive everything or split the remainder.

ReceiveOrder (“Receive order”, Ordered) delegates to PurchaseReceiptService.ReceiveAsync. The message text distinguishes full receipt from receipt with a separated remainder.

FillPurchasePrices (“Fill prices”, Draft) prices lines with UnitPrice ≤ 0 through IPricingService.ResolvePurchasePriceAsync(Item, Unit, Supplier, DocumentDate). Prices entered manually are not changed.

PayVendor (“Pay vendor”, Draft→Paid on VendorPayment) refuses no lines or lines with Amount ≤ 0; there is no balance limit.

PostPurchaseReturn (“Post purchase return”, Draft→Posted on PurchaseReturn) refuses no lines or lines with Quantity ≤ 0, then IStockAvailabilityService checks each position and refuses with “need X, have Y” when stock is short.

EnterSupplierInvoice (“Enter supplier invoice”, Received on PurchaseOrder) creates a SupplierInvoice draft, copies supplier, document date, payment term, due date and the order lines, resolves LegalEntity from the receiving cell (falling back to the order header), links the two documents, and opens the new one.

RegisterSupplierInvoice (“Register”, Draft→Registered on SupplierInvoice) re-reads the document, refuses a missing supplier, a blank SupplierNumber, no lines, Quantity ≤ 0, and a difference beyond the tolerance. It then stamps MatchedAmount and Difference with a plain save while the document is still Draft, and only afterwards moves the subtype, so the operator sees the number before it is posted. The transaction scripts do not depend on those stamps — they re-ask the service — so a programmatic transition posts the same amounts.

PostPurchaseCreditNote (“Post purchase credit note”, Draft→Posted on PurchaseCreditNote) refuses missing OriginalOrder, no lines, or lines with Quantity ≤ 0. Deeper checks, such as the order being Received and the rate being positive, belong to the document OnBeforePostAsync; the command does not duplicate them.

Business logic and invariants#

Ordered→Received is not a declarative transition. Metadata declares only Draft→Ordered. A service moves the order to Received programmatically. The user path still goes through a command (ReceiveOrder, or auto-receipt inside PlaceOrder), but there is no separate transition arc in the subtype table.

Partial receipt is implemented. ReceiveQty on an order line plus SplitRemainderAsync in PurchaseReceiptService moves the unreceived balance into a new linked Ordered order. Earlier versions of this document called it an open question; it is now the working path.

Return and credit note are not alternatives. PurchaseReturn moves stock and net payable. PurchaseCreditNote moves only the tax part of payable. A wrong receipt is usually covered by both documents; neither substitutes for the other.

Payable has no ceiling. Payable.allowNegativeBalance = true. Overpayment and advance payment to a supplier are valid; VendorPayment does not block them.

Historical integrity. Price and tax rate are fixed on the line at receipt or note time. Later edits to the dictionary or rate do not change an already posted document.

Document links use the graph, not link tables. Order → PutAwayTask, order → TaxCalculation, order → remainder order, and note → tax reversal are all edges in the common document graph (IDocumentManager.AddLinkAsync/ GetDocumentFamilyAsync). Purchasing has no own link table.

The supplier invoice books the difference, not the invoice. The receipt already accrued the payable, so posting the invoice in full would owe the supplier twice. A matching invoice posts nothing at all. See SupplierInvoice.

A command-enforced invariant is enforced once. SupplierNumber is optional at field level because EnterSupplierInvoice creates the draft before the supplier's paper exists. RegisterSupplierInvoice is the only door into Registered, so the requirement has exactly one place to live.

An empty optional document date is 1901-01-01. The column is non-nullable and a DateTime parameter is sent as SqlDbType.DateTime whatever the column type is, so DateTime.MinValue overflows in the driver before SQL Server ever sees it. PurchaseOrder, SupplierInvoice and DeliveryTrip all clamp to the same sentinel and all test emptiness with Year < 1902.

Known deviation. PurchaseReturn.OriginalOrder and PurchaseCreditNote.OriginalOrder are plain Guid fields, not Reference EDTs. This is the only place in the model where that is true.

The Purchasing group → Documents (PurchaseOrder, SupplierInvoice, VendorPayment, PurchaseReturn, PurchaseCreditNote) · Dictionaries (Supplier, whose menu item lives here although the object belongs to Inventory) · Registers (Payable) · Settings (PurchasingSettings).

  • Outgoing: Inventory — Item/Supplier/StoreCell/ Stock, IStoreCellService/IStockAvailabilityService/IPricingService; Tax — rate engine, TaxCalculation; Organization — LegalEntity; Common — PaymentTerm, IRecordDefaults, IPaymentDueService; Accounting — only the Money EDT.
  • Incoming: Costing writes InventoryValue/ItemCostFifo on PurchaseOrder.Received (ReceiptCostTx/ReceiptFifoTx); Purchasing's own transaction scripts post receipt (Dr Inventory / Cr Payable, with the NonRecoverableVat share), return (Dr Payable / Cr Inventory), and payment (Dr Payable / Cr Cash, only if LegalEntity is filled) to GL; Purchasing's TaxCalculationPayableSeamEventHandler adds input VAT of a receipt to the supplier's Payable; 22-Ukraine writes UaPurchaseFirstEvent for receipt, notes, and payment — the input-VAT first event.

Objects#

Generated from workspace metadata by node tools/gen-reference.mjs; edit the metadata, not this block.

Dictionaries#

LegacyPayableBasis — Legacy payable bases

Supplier order of the predecessor system with open debt, not migrated as a document. MetaId equals the Basis used in PayableByBasis.

Field Caption Type Required
DocumentDate Document date DateTime Yes
ID Code String(50) Yes
Number Number String(50) No
Source Source String(100) No
SourceKey Source key String(100) No
Supplier Supplier → Supplier Yes
SupplierContract Supplier contract → SupplierContract No

PurchasingSettings — Purchasing settings

Field Caption Type Required
ApprovalThreshold Approval threshold Decimal(18,2) No
AutoReceiveOnOrder Auto-receive on order Boolean No
DefaultPaymentTerm Default payment term → PaymentTerm No
DefaultPaymentTermDays Default payment term (days) Integer No
ID ID String(50) Yes
InvoiceMatchTolerance Invoice match tolerance Decimal(18,2) No

SupplierContract — Supplier contracts

Contract with a supplier: the debt to the supplier is kept per contract (Payable, PayableByBasis). A supplier may hold several live contracts at once.

Field Caption Type Required
Currency Currency → Currency No
EffectiveFrom Effective from DateTime No
EffectiveTo Effective to DateTime No
ID Code String(50) Yes
IsDisabled Disabled Boolean No
LegalEntity Buying legal entity → LegalEntity No
Name Name String(160) Yes
Notes Notes String(2000) No
Number Contract No. String(50) No
Supplier Supplier → Supplier Yes

Documents#

PayableRevaluation — Payable revaluation

Period-end revaluation of foreign-currency payables. Fill revaluation lists every supplier billing in a currency other than the legal entity's, with an open payable, at the rate on the document date; Post revaluation moves Payable.AmountFunc to the revalued amount and books the unrealised exchange difference. The revalued carrying value stays: the next payment's realised difference is measured against it.

Header fields:

Field Caption Type Required
ID Number String(50) Yes
LegalEntity Legal entity → LegalEntity Yes

Subtypes:

Subtype Caption
Draft Draft
Posted Posted

Commands:

Command Caption Target subtype
CancelPayableRevaluation Cancel revaluation —
FillPayableRevaluation Fill revaluation —
PostPayableRevaluation Post revaluation —

PurchaseCreditNote — Purchase credit note

Header fields:

Field Caption Type Required
Contract Supplier contract → SupplierContract No
ExchangeRate Exchange rate Decimal(18,8) No
ID Number String(50) Yes
LegalEntity Buying legal entity → LegalEntity No
OriginalOrder Original order Guid No
Supplier Supplier → Supplier Yes
TaxRateApplied Applied tax rate TaxRateValue No

Subtypes:

Subtype Caption
Draft Draft
Posted Posted

Commands:

Command Caption Target subtype
PostPurchaseCreditNote Post purchase credit note —

PurchaseOrder — Purchase order

Header fields:

Field Caption Type Required
ApprovedAmount Approved amount Decimal(18,2) No
Contract Supplier contract → SupplierContract No
DueDate Due date DateTime No
ExchangeRate Exchange rate Decimal(18,8) No
ExpectedReceipt Expected receipt DateTime No
ID Number String(50) Yes
LegalEntity Legal entity → LegalEntity No
Location Receiving location → StoreCell Yes
NonRecoverableVat Non-recoverable VAT Decimal(18,2) No
Notes Notes String(2000) No
PaymentTerm Payment term → PaymentTerm No
Supplier Supplier → Supplier Yes
VendorDocumentDate Supplier document date DateTime No
VendorDocumentNumber Supplier document No. String(50) No

Subtypes:

Subtype Caption
Draft Draft
Ordered Ordered
Received Received

Commands:

Command Caption Target subtype
PlaceOrder Place order —
ReceiveOrder Receive order —
ApprovePurchaseOrder Approve order —
FillPurchasePrices Fill prices —
EnterSupplierInvoice Enter supplier invoice —

PurchaseReturn — Purchase return

Header fields:

Field Caption Type Required
Contract Supplier contract → SupplierContract No
ExchangeRate Exchange rate Decimal(18,8) No
ID Number String(50) Yes
Location Return from → StoreCell Yes
OriginalOrder Original order Guid No
Supplier Supplier → Supplier Yes

Subtypes:

Subtype Caption
Draft Draft
Posted Posted

Commands:

Command Caption Target subtype
PostPurchaseReturn Post purchase return —

SupplierInvoice — Supplier invoice

Header fields:

Field Caption Type Required
Contract Supplier contract → SupplierContract No
Difference Difference Decimal(18,2) No
DueDate Due date DateTime No
ExchangeRate Exchange rate Decimal(18,8) No
ID Number String(50) Yes
InvoiceDate Supplier's date DateTime No
LegalEntity Legal entity → LegalEntity No
MatchedAmount Accrued by receipts Decimal(18,2) No
PaymentTerm Payment term → PaymentTerm No
Supplier Supplier → Supplier Yes
SupplierNumber Supplier's number String(50) No
TaxRateApplied Tax rate TaxRateValue No

Subtypes:

Subtype Caption
Draft Draft
Registered Registered

Commands:

Command Caption Target subtype
RegisterSupplierInvoice Register —

SupplierPriceSetting — Supplier price setting

Header fields:

Field Caption Type Required
ID Number String(50) Yes
Notes Notes String(1000) No
PriceType Price type → PriceType No
Supplier Supplier → Supplier Yes

Subtypes:

Subtype Caption
Draft Draft
Posted Posted

Commands:

Command Caption Target subtype
PostSupplierPriceSetting Post supplier prices —

VendorPayment — Vendor payment

Header fields:

Field Caption Type Required
BankAccount Bank account → BankAccount No
CashDesk Cash desk → CashDesk No
ID Number String(50) Yes
LegalEntity Legal entity → LegalEntity No
Notes Notes String(2000) No

Subtypes:

Subtype Caption
Draft Draft
Paid Paid

Commands:

Command Caption Target subtype
PayVendor Pay vendor —

VendorRefund — Supplier refund

Money a supplier pays back into a cash desk or a bank account (overpayment, returned goods). Posting raises the payable to the supplier back toward zero, raises the desk or account balance and debits its ledger account against payables.

Header fields:

Field Caption Type Required
Amount Amount Money Yes
BankAccount Bank account → BankAccount No
Basis Basis Guid No
CashDesk Cash desk → CashDesk No
Contract Supplier contract → SupplierContract No
ExchangeRate Exchange rate Decimal(18,8) No
ID Number String(50) Yes
LegalEntity Legal entity → LegalEntity Yes
Notes Notes String(2000) No
Supplier Supplier → Supplier Yes

Subtypes:

Subtype Caption
Draft Draft
Paid Paid

Commands:

Command Caption Target subtype
ReceiveVendorRefund Receive refund —

Registers#

Payable — Accounts payable

Amount owed to suppliers, by supplier; by supplier contract when the document names one (empty contract — no contract analytic)

Resources:

Resource Caption Type Required
Amount Amount Money —
AmountFunc Amount in functional currency Money —

Analytics:

Analytic Caption Type Required
Payable-LegalEntity Payable-LegalEntity — No
Payable-Supplier Payable-Supplier — Yes
Payable-SupplierContract Payable-SupplierContract — No

PayableBasis — Accounts payable by basis

Companion of Payable: the same debt to a supplier split by the purchase order it belongs to. Empty basis is an advance.

Dimensions:

Dimension Caption Type Required
Basis Basis PayableBasisKey —
Supplier Supplier → Supplier —

Resources:

Resource Caption Type Required
Amount Amount Money —

PayableByBasis — Accounts payable by basis

Companion of Payable: the same debt to a supplier split by the purchase order it belongs to. Empty basis is an advance. The supplier contract is an optional analytic, not a dimension: the balance table stays keyed by supplier x basis.

Dimensions:

Dimension Caption Type Required
Basis Basis PayableBasisKey —
Supplier Supplier → Supplier —

Resources:

Resource Caption Type Required
Amount Amount Money —

Analytics:

Analytic Caption Type Required
PayableByBasis-SupplierContract PayableByBasis-SupplierContract — No

Purchases — Purchases

Turnover of goods received from suppliers: quantity and amount by item and supplier. Not on-hand stock — Stock stays item and cell. A return reverses the same cut.

Resources:

Resource Caption Type Required
Amount Amount Money —
AmountFunc Amount in functional currency Money —
Qty Qty Qty —

Analytics:

Analytic Caption Type Required
Purchases-Cell Purchases-Cell — No
Purchases-Item Purchases-Item — Yes
Purchases-LegalEntity Purchases-LegalEntity — No
Purchases-Supplier Purchases-Supplier — Yes
Purchases-SupplierContract Purchases-SupplierContract — No

Table parts#

PayableRevaluationLines — Lines

Used by: PayableRevaluation.

Field Caption Type Required
AmountCur Open amount Decimal(18,2) No
Carrying Carrying amount Decimal(18,2) No
Currency Currency → Currency Yes
Difference Difference Decimal(18,2) No
Rate Rate Decimal(18,8) No
Revalued Revalued amount Decimal(18,2) No
Supplier Supplier → Supplier Yes
SupplierContract Supplier contract → SupplierContract No

PurchaseCreditNoteLines — Lines

Used by: PurchaseCreditNote.

Field Caption Type Required
Item Item → Item Yes
Quantity Quantity Qty Yes
UnitPrice Unit price Money Yes

PurchaseOrderLines — Lines

Used by: PurchaseOrder.

Field Caption Type Required
Amount Amount Money No
BaseQuantity Qty in base unit Qty No
Item Item → Item Yes
Location Warehouse cell → StoreCell No
PackQty Packages Qty No
PackUnit Package unit → UnitOfMeasure No
Quantity Quantity Qty Yes
ReceiveQty Receive now Qty No
SupplierPrice Supplier price Money No
TaxAmount VAT amount Money No
TaxCode VAT rate → TaxCode No
Unit Unit → UnitOfMeasure No
UnitPrice Unit price Money Yes

PurchaseReturnLines — Lines

Used by: PurchaseReturn.

Field Caption Type Required
Amount Amount Money No
BaseQuantity Qty in base unit Qty No
Item Item → Item Yes
Location Warehouse cell → StoreCell No
OriginalReceipt Receipt Guid No
PackQty Packages Qty No
PackUnit Package unit → UnitOfMeasure No
Quantity Quantity Qty Yes
TaxAmount VAT amount Money No
TaxCode VAT rate → TaxCode No
Unit Unit → UnitOfMeasure No
UnitPrice Unit price Money Yes

SupplierInvoiceLines — Lines

Used by: SupplierInvoice.

Field Caption Type Required
Amount Amount Money No
BaseQuantity Qty in base unit Qty No
Item Item → Item Yes
PackQty Packages Qty No
PackUnit Package unit → UnitOfMeasure No
Quantity Quantity Qty Yes
TaxAmount VAT amount Money No
TaxCode VAT rate → TaxCode No
Unit Unit → UnitOfMeasure No
UnitPrice Unit price Money Yes

SupplierPriceSettingLines — Prices

Used by: SupplierPriceSetting.

Field Caption Type Required
Item Item → Item Yes
Price Price Money Yes
Unit Unit → UnitOfMeasure No

VendorPaymentLines — Lines

Used by: VendorPayment.

Field Caption Type Required
Amount Amount Money Yes
Basis Basis Guid No
CarryingAmount Carrying amount Decimal(18,2) No
Contract Supplier contract → SupplierContract No
ExchangeRate Exchange rate Decimal(18,8) No
Supplier Supplier → Supplier Yes
Was this page helpful?