ZuloOne
English
Sign in
Menu

ZuloOne — reference business layer

Updated

This is the specification of the reference business layer on the ZuloOne platform: supply, production, stores, sales, accounting, taxes, HR, customer relations, and cost for any industry and any jurisdiction. The business layer is described with metadata and scripts. From them the platform generates database tables, entity classes, REST API, and the user interface.

"Reference" means "this is what other documentation checks against," not "this is a sample you may copy loosely." The wiki cites this block as the source of truth for objects, and CI checks the workspace against it: tools/check-doc-names.mjs fails if the specification promises a document, register, or service that is not in the delivery. While this block lived under docs/samples/ and was called an example, it rotted unnoticed for a month: it promised SalesInvoice, long since renamed to SalesRealization, five Tax services that never existed, and a register/driver/service trio in Costing that does not exist. A sample may get away with that. A source of truth may not.

How each contour runs is in the wiki, not here: process map.

1. Principles#

  • Industry neutrality. Objects are not tied to a specific industry: arbitrary items are produced and sold, and a specification (BOM) describes any product composition.
  • Multi-country support. Country-specific parts — tax rates, e-invoices, statutory reporting — live in separate country packages (localizations). The core is country-independent; law is data, not code.
  • Metadata, not code. The developer describes objects (dictionaries, documents, registers, menus) and writes business logic in scripts. The platform generates SQL, migrations, controllers, EF mappings, and UI.
  • Layering. Models are arranged by layer: Base → Solution → Customization. A higher layer extends lower layers additively (new fields, event-chain links, script inheritance, menu items) without editing them.
  • Separation of responsibility. Each module owns its objects and exposes typed services to the others. Operational modules provide data to specialized modules (tax, cost), but do not duplicate their logic.

2. Modules and layers#

Module Layer Purpose Depends on
Common Base Countries, currencies, units of measure, geography (shared foundation) —
Organization Base Legal entities, org structure, sites; legal-entity country/currency come from Common Common
Accounting Base Chart of accounts, journal, general ledger (double entry), fiscal periods Organization, Common
Tax Base Tax engine: determination, calculation, tax ledger, reporting, tax documents, integration abstraction Organization, Accounting
Inventory Solution Items (units from Common), counterparties, stores, cells, balance register, store logistics Organization, Common
Purchasing Solution Supplier orders, receipts, accounts payable Inventory, Tax, Accounting
Production Solution Specifications (BOM), production orders Inventory
Sales Solution Sales, invoice (main tax document), retail (POS), accounts receivable Inventory, Tax, Accounting
HR Solution Employees, positions, time sheets, payroll Organization
CRM Solution Customers, loyalty program, leads and quotations Inventory, Sales
Costing Solution FIFO layers and stock cost Inventory, Purchasing
Localization.<Country> Customization Country taxes, e-invoices, statutory reporting Inventory, Organization, Sales, Tax

Development order is topological: first the foundation (Organization, Accounting, Tax), then operational modules, then country localizations. Country packages live in the top layer and extend the core additively, so adding a new country does not affect modules and documents that already work.

The same table by layer System(0) → Base(1) → Solution(2) → Customization(3) (including Core, which has no row above because it is a system model, not a business module) is in Metadata → By layers and models.

3. The platform's kinds of metadata#

A detailed description of each kind (JSON envelope, C# base, event support) is in Metadata → By metadata kind.

Kind Role Details
Model Delivery unit (module/localization); carries the layer and dependencies model.md
Dictionary Dictionary (master data); may be hierarchical dictionary.md
Document Document; subtypes are finite-state-machine states, and transitions post movements document.md
Register Accumulation register (balances/turnovers); analytic breakdowns; double entry is optional register.md
TablePart Table part of a document/aggregate tablepart.md
EDT Data type: scalar or reference (reference to a dictionary) edt.md
DataEntity Public OData resource — a projection of a dictionary/document dataentity.md
NumberSequence Number sequence for numbering records and documents numbersequence.md
Analytic Reusable register breakdown from the global catalog analytic.md
LinkTable Link table (many-to-many, document ancestry) linktable.md
GlobalConstants Configuration values (thresholds, modes) outside code globalconstants.md
Service Class of business functions; contract I<Name> is generated from public methods service.md
Script Code: events, transactional postings, commands script.md
Menu Module menu items menu.md
Job Background job (scheduler) job.md

4. Modules#

Organization#

Legal entities (with country and currency — the basis for multi-country support and tax-jurisdiction determination), plus the hierarchy of divisions and sites. Feeds the context for all modules: who owns the operation and where it happens.

Accounting#

General ledger and accounting: chart of accounts (hierarchical), fiscal years and periods, the JournalEntry document, and the double-entry GL register. All subledgers — tax ledger, receivables/payables, store — are posted into GL. Period closing is aligned with tax periods.

Tax#

The universal tax engine is a mechanism that can be applied to any country:

  • Master data: tax authorities, tax types, taxes, jurisdictions (hierarchical), rates (with effective dates), categories, exemption codes, tax codes, registrations, profiles, mappings.
  • Rule engine: declarative rules (conditions/actions), selection by tax-event date; the result includes the reason for the choice.
  • Calculation: tax calculation (immutable after finalization), several taxes per line, input/output tax, recoverability.
  • Ledger and reporting: tax register as the source for returns; periods, returns, mapping to report lines.
  • Documents and integration: tax document, submission log, abstraction for integration with a government system.

Tax law (rates, codes, rules, reporting codes) is data in country packages, not core logic. The detailed metadata architecture is in 03-Tax.md.

Integration in operations. Tax is calculated while operational documents are posted, not separately. Sales (invoice) and Purchasing (receipt) build a tax context from their lines and call the engine — the end-to-end flow is:

Document (Issue / Receive)
  → TaxTransactionContext (seller, buyer, item, supply type, tax date)
  → ITaxRuleEngine.DetermineTax           → TaxCode (+ reason for choice)
  → ITaxCalculationService.Calculate      → TaxCalculation (OUTPUT on sale / INPUT on purchase)
  → TaxLedger                             → posting into GL (VAT + receivable/payable)
  → [sale] TaxDocument                    → e-invoice (localization → government system)

Internal movements (production, store transfers) do not carry tax. The engine is decoupled from any specific document: any module can supply a context, including a future payroll tax in HR.

Inventory#

Catalog of arbitrary items (raw materials, semi-finished products, finished goods, resale goods), units of measure, counterparties, stores and cells, the balance register, and store logistics (mandatory movements: receipt → storage → picking).

Purchasing#

Supplier order and receipt: balance movements, recognition of payables, and tax context for the input-tax engine.

Production#

A specification (BOM) describes the composition of any product; a production order consumes components and receives output, moving cost to the output.

Sales#

Sale: invoice as the main tax document (basis for an e-invoice), with retail receipt as a simplified variant. Recognition of revenue and receivables, and tax context for the output-tax engine.

HR#

Employees, positions, time sheets, payroll accrual and payment; payroll participates in cost as overhead.

CRM#

Customers, loyalty program, purchase history; extends the sales document without creating a reverse dependency.

Costing#

Cost registers and calculation drivers (average, FIFO), analytical accounting: stock valuation, production cost, gross profit, labor allocation.

5. Multi-country support and localization#

A country localization is a Customization-layer model connected to any country by a single template: its own taxes/rates/categories/codes, tax-determination rules, declaration-line mapping, invoice extension, integration-contract implementation, statutory registers and reports. Installation is tied to the legal entity's country; a package update introduces new rules with new dates without touching historical calculations.

The first reference package is Saudi Arabia: VAT, codes and categories, rules, return, and ZATCA/FATOORA e-invoice (clearing for B2B, reporting for B2C). All country codes live only in the country package.

6. Integration with government systems#

Tax calculation is separate from integration: the engine does not know about a specific government system, and integration does not calculate tax. The business layer builds a structured document, hash chain, and QR code, then puts it into an outbox queue. A platform connector (background job) signs it and sends it to the government API. Every submission attempt is written to an immutable log; sending is idempotent, errors are classified, and only retryable errors are retried. After government acceptance, the tax document does not change; corrections go through a credit/debit note.

7. Documentation structure#

Document Contents
README.md (this document) General specification: principles, modules, layers, metadata kinds
metadata/README.md Metadata section: the same material in two sections — by kind and by layer/model
00-Common.md Shared foundation: countries, currencies, units, geography
01-Organization.md Legal entity, organizational structure, sites
02-Accounting.md Chart of accounts, journal, general ledger (GL, double entry)
03-Tax.md Tax engine — detailed metadata architecture
04-Inventory.md Items, stores, cells, balance register
05-Purchasing.md Purchases, receipts, input tax
06-Production.md Specifications (BOM), production orders
07-Sales.md Sales, invoice, output tax
08-HR.md Employees, positions, payroll
09-CRM.md Customers, loyalty program
10-Costing.md FIFO layers and stock cost
20-Localization-Overview.md Country package template (for any country)
21-SaudiArabia.md First reference country package: VAT and ZATCA/FATOORA
22-Ukraine.md Second package: VAT by first event, regimes, ERPN through the operator

Each module document describes objects in ZuloOne metadata terms: dictionaries — fields (name, type, length, references), requiredness, and events; documents — header, table parts, states, and postings; registers — resources and analytics. Reference types, number sequences, link tables, global constants, and menus are listed explicitly.

8. The shared building blocks#

Common dictionaries used by all module documents.

8.1 Scalar data types (EDT)#

One EDT is one point where precision is corrected. It is declared by the owner module and reused through declared dependencies.

EDT Type Owner Reused by
Money Decimal(18,2) Accounting Tax, Purchasing, Sales, HR, Costing
Qty Decimal(18,4) Inventory Purchasing, Production, Sales
TaxRateValue Decimal(9,6) Tax localization
Percent Decimal(9,4) Accounting Tax
Points Decimal(18,2) CRM —

A reference type Ref<Dictionary> is declared by the module that owns the dictionary.

8.2 The global catalogue of analytics#

Register breakdowns come from the global catalog. An analytic is declared once and attached to any number of registers.

Analytic Ref → dictionary Owner Registers
LegalEntity → Organization.LegalEntity Organization GL, TaxLedger, Payroll
Division → Organization.Division Organization Payroll
Account → Accounting.ChartOfAccounts Accounting GL
FiscalPeriod → Accounting.FiscalPeriod Accounting GL
Store → Inventory.Store Inventory Cost, Revenue
Cell → Inventory.StoreCell Inventory Stock
Item → Inventory.Item Inventory Stock, Cost, Revenue
Customer → Inventory.Customer Inventory LoyaltyPoints
Tax, TaxCode, Jurisdiction, Direction, Recoverability → Tax.* Tax TaxLedger
Employee → HR.Employee HR Payroll, PayrollLiability

8.3 Conventions#

  • GUID placeholders. <GUID …> is a symbolic placeholder. A real metaId (uuid v4) is generated when an object is created. Links between files must use the same symbol; names are cross-cutting (for example, <GUID Dict.Item> is the same dictionary in all files).
  • Cross-link anchors. Standard headings create predictable anchors: dictionary/document/register — heading ### <Name> (Latin) → link <Name>. This lets module files refer to each other without seeing the final text.
  • Script names. <Object>EventHandler (owner events), <Object>Ext<Model>EventHandler (extension link), <Doc><Subtype><Target>Tx (transaction posting), <Name>Command, <Name>Service → contract I<Name>Service.

8.4 Module document skeleton#

Each NN-Module.md file uses one frame. Missing sections are omitted:

Purpose → model.json (layer, dependencies) → Number sequences → EDT →
Global constants → Dictionaries → Link tables → Documents → Registers →
Services → Menu → Links with other modules

9. UI and forms#

The basic UI is generated from metadata — individual forms are not written. From an object description, the platform builds:

  • Dictionary → list + card form; fields by displayOrder/isVisible, labels from caption, search by defaultSearchProperty.
  • Document → form with header, table parts, and a state panel (subtypes); transition buttons are document commands.
  • Register → balance/turnover view by analytics.
  • Navigation → from Menu (Dictionaries / Documents / Registers / Reports).

Therefore, tax packages do not require React forms to enter or view all master data. The generated UI is enough; custom UI appears only for narrow cases (for example, a dashboard or a specialized wizard).

Was this page helpful?