ZuloOne
English
Sign in
Menu

22 · Ukraine — VAT (ПДВ) by first event, regimes, and the Unified Register of Tax Invoices (ЄРПН)

Updated

Customization(3) layer. Depends on Organization, HR, Inventory, Purchasing, Sales, and Tax — six models, the widest coverage among the country packages.

← General specification · country package template — 20-Localization-Overview

Purpose#

The second country package after Saudi Arabia. It follows the same rule: the core knows nothing about Ukraine, and Ukraine does not rewrite the core. Tax is data — codes, rates, and rules in the Tax model — and the package adds only what the universal engine does not and should not have.

Ukraine has four things that KSA does not have:

  1. First event (Articles 187.1 and 198.2 of the Tax Code of Ukraine, ПКУ) — the tax liability arises on whichever happens earlier: shipment or payment. The universal engine calculates tax from a document; here tax is calculated from counterparty accumulation.
  2. Taxation regimes — one database can hold LLCs (ТОВ) on the general system and several individual entrepreneurs (ФОП) on the simplified system, with different rates and different bases.
  3. Payroll withholdings and three own documents — personal income tax (ПДФО), military levy (військовий збір), remittance of withheld tax to the budget, single social contribution (ЄСВ) for a FOP "for self", and the VAT refund claim (бюджетне відшкодування ПДВ) are handled by package objects, not by the common tax document.
  4. Unified Register of Tax Invoices (ЄРПН) through an operator — signatures and XML stay outside the platform. The package sends a flat JSON of facts, not a State Tax Service form.

Contour fact. 6 dictionaries, 4 dictionary extensions, 3 own documents (not zero — an important correction to the early understanding of the package), 8 registers, 5 services, 3 jobs, 13 commands, 9 extensions of other documents (one of them, TaxReturn.LocalizationUkraine, is declared but empty), 4 outbound channels, 3 reporting views, and 17 integration tests.

Process description for analysts — Ukraine; this page is the object-level reference.

What is created (object map)#

Kind Name Purpose
Model LocalizationUkraine package model, Customization(3) layer
Dictionary LocalizationUkraineSettings package settings (singleton)
Dictionary UaSingleTaxLimit dated annual single-tax revenue limit (ПКУ 291.4)
Dictionary UaRegimeChange audit journal of forced moves to the general system
Dictionary UaBankConnection tenant half of the bank channel: address, environment, credential reference
Dictionary UaLandPlot land plots for minimum tax liability (мінімальне податкове зобов'язання, МПЗ)
Dictionary UaTaxFilingExport prepared return export (CSV/DECLAR XML)
Enum UaTaxRegime tax regime of the legal entity
EDT UaTaxRegimeEdt, UaBankRefEdt, UaBankTextEdt, UaBankTranTypeEdt regime field type; key, text, and posting type of an Autoclient bank statement
DictionaryExtension LegalEntity.LocalizationUkraine regime, DPS region/office codes, legal-person flag
DictionaryExtension Employee.LocalizationUkraine 12 DPS fields for forms 4ДФ/D1/D5/D6
DictionaryExtension Position.LocalizationUkraine DK 003 profession-classifier code for D5
DictionaryExtension TimeOff.LocalizationUkraine D5 person category and unpaid leave for D1
Document UaTaxRemittance remittance of withheld PIT/military levy to the budget
Document UaFopEsvAccrual accrual of ЄСВ for a FOP "for self"
Document UaVatRefund VAT refund claim
Register UaVatFirstEvent accumulation by contract for the output first event
Register UaVatPayable VAT liability
Register UaPurchaseFirstEvent supplier accumulation for the input first event
Register UaVatCredit tax credit
Register UaPayrollLevy PIT and military levy by employee
Register UaBankStatement imported Autoclient postings (information register)
Register UaFopEsv accrued ЄСВ for a FOP "for self", by legal entity
Register UaVatRefundClaim claimed VAT refund amount
Service UaFirstEvent first-event determination and accrual
Service UaPayrollLevies payroll withholdings
Service UaTaxFiling return-export assembly
Service UaEInvoice tax-invoice envelope for ЄРПН
Service UaBank Autoclient statement import and matching
Job ApplyUaRegimeChanges move to the general system after exceeding the limit
Job PullUaTaxInvoiceReceipts receive receipts from the ЄРПН operator
Job PullUaBankStatements periodic Autoclient statement import
Command ×13 UaExportTaxReturn, UaResolveTaxInvoice, UaExportPayrollLevy, UaExportQuarterlyReturn, UaExportDpsPayroll, UaExportSingleTax, UaExportFopSingleTax, UaPayTaxRemittance, UaVoidTaxRemittance, UaPostFopEsv, UaVoidFopEsv, UaPostVatRefund, UaVoidVatRefund declaration/DPS form exports and subtype transitions of the three own documents
DataPackage vat-UA codes, rates, categories, and mappings for Ukrainian VAT, single tax, PIT, and military levy
— reused — Tax, TaxCode, TaxRate, TaxReportMapping, TaxDocument, TaxLedger, TaxReturn (Tax); LegalEntity (Organization); PayrollLiability, PayrollAccrual, PayrollPayment (HR) not created here

Total: 6 dictionaries, 8 registers, 3 documents, 5 services, 3 jobs, 13 commands, 1 enum, 4 EDTs, 4 dictionary extensions, 9 extensions of other documents (1 of them empty), 4 outbound channels, 3 reporting views, and 17 integration tests.

model.json#

{
  "modelType": "Custom",
  "modelVersion": "1.44.0",
  "layerId": 3,
  "publisher": "ZuloOne",
  "name": "LocalizationUkraine"
}

Six dependencies (not an abstract template — the real minVersion values from model.json):

Model minVersion Why
HR ≥1.9.2 Employee/Position/TimeOff extensions, PayrollAccrual/PayrollPayment
Inventory ≥1.9.0 counterparties and item in the first event
Organization ≥1.4.1 LegalEntity — regime, DPS codes, legal-person flag
Purchasing ≥1.12.0 PurchaseOrder/VendorPayment/PurchaseCreditNote — input VAT
Sales ≥1.13.1 SalesRealization/SalesCreditNote/CustomerPayment — output VAT
Tax ≥1.11.0 codes, rates, TaxReportMapping, TaxLedger, TaxReturn

As with KSA, the core has no backlink to the package: the connection is extensions and data. There is no Accounting dependency because the package does not touch the chart of accounts directly.

Reference data (DataPackages/vat-UA.json)#

The vat-UA manifest (DataPackages/index.json: when: "country", country: "UA", sort: 26 — immediately after Saudi sort: 25) loads tax legislation as four kinds of objects:

Object How many What is inside
TaxAuthority 1 DPS — State Tax Service of Ukraine (Державна податкова служба України)
TaxJurisdiction 1 UA, level 0
Tax 4 VAT-UA (from 2011-01-01), EP-UA (single tax, from 2011-01-01), PDFO-UA (personal income tax, from 2011-01-01), VZ-UA (military levy, from 2014-08-03 — the actual introduction date of the levy)
TaxCategory 11 STANDARD/REDUCED/ZERO_RATED/EXEMPT on VAT-UA; EP3/EP5/EP15/EP6/EP10 on EP-UA (all Treatment: STANDARD — single tax has no zero/exempt category, only different rates); PDFO, VZ
TaxRate 10 VAT20 (0.20, from 2014-01-01), VAT7 (0.07, from 2014-04-01), EP3/EP5/EP15 (0.03/0.05/0.15), EP6/EP10 ("double" 0.06/0.10), PDFO18 (0.18, from 2016-01-01), VZ1_5 (0.015, 2014-08-03 → 2024-11-30), VZ5 (0.05, from 2024-12-01)
TaxCode 16 see below
TaxReportMapping 18 boxes of three declarations; see below

Example with numbers: military levy increase. Salary of 30,000 ₴ accrued on 2024-11-30 withholds military levy at 1.5% = 450 ₴. The same salary accrued on 2024-12-01 withholds 5% = 1,500 ₴ — more than three times more one day later. The rate is selected by accrual date, not by payment date (see Salary deductions).

16 tax codes — not only standard/reduced/zero/exempt. In addition to the obvious UA-S (20%), UA-7 (7%), UA-Z (zero), and UA-E (exempt), the package has UA-ZX — zero rate for export, separate from ordinary UA-Z: both map to category ZERO_RATED, but in declaration J0200126 they go to different lines (2.1 for export, 3 for other zero-rated supplies). Single tax has not only five "direct" codes (UA-EP3/5/15/6/10), but also double rates for special circumstances that are usually absent from a short single-tax description: UA-EPB3/UA-EPB5 for barter settlements (the non-cash form by itself raises the rate to 6%/10%, regardless of the income limit), and UA-EPF3/UA-EPF5 for income from activity forbidden for the simplified system (the same double tariff). UA-PDFO and UA-VZ cover payroll withholdings.

18 mappings cover THREE different ReturnType values, not one. J0200126 (VAT declaration) has 5 OUTPUT lines (UA-S→1.1, UA-7→1.2, UA-ZX→2.1, UA-Z→3, UA-E→5) and 2 INPUT lines (UA-S→10.1, UA-7→10.2), all with EffectiveFrom: 2024-10-01. J0103509 (single-tax declaration for a legal entity) has 8 OUTPUT lines: UA-EP3→1.3, UA-EP5→1.4, UA-EP6→2.3, UA-EP10→2.4, UA-EPB3→3.3, UA-EPB5→3.4, UA-EPF3→4.3, UA-EPF5→4.4 (EffectiveFrom: 2025-01-01). F0103309 (FOP declaration, a return code separate from J0103509) has 3 lines: UA-EP3→05, UA-EP5→06, UA-EP15→07 (EffectiveFrom: 2025-01-01). These three ReturnType values are what UaExportTaxReturn, UaExportSingleTax, and UaExportFopSingleTax export, respectively.

What the package does not create. ЄСВ (social insurance) rates are not here; they are in the common HR contour. vat-UA carries only VAT/ЄП/ПДФО/ВЗ. The package also does not create data for military-levy limits or a PIT base ceiling. The ceiling applies to ЄСВ, not to withholdings (see Salary deductions).

Settings#

LocalizationUkraineSettings is one record per tenant. Fields and the effect of each field:

Field What it sets If it is empty
SingleTaxCode3 single-tax code for 3% (with VAT) the 3% simplified regime will not accrue single tax
SingleTaxCode5 single-tax code for 5% (without VAT) the 5% simplified regime will not accrue single tax
SingleTaxCodeExcess 15% code for exceeding the limit the excess will not be taxed
ExemptVatCode VAT exemption code the regime change cannot set the mapping, and sales will use DefaultTaxCode
IncomeTaxCode PIT code the withholding will not reach the ledger
MilitaryLevyCode military-levy code same
VatReturnType VAT declaration type the export will not be assembled
TaxInvoiceFormCode tax-invoice form code the envelope leaves without the form code
TaxInvoiceAdjustmentFormCode adjustment-calculation form code same for an adjustment
EInvoiceEnabled enables sending to ЄРПН envelopes are assembled but not sent

The taxpayer identification number is not stored here. It lives in LegalEntity.TaxRegistrationNumber in Organization, because it is a legal-entity attribute, not a country setting.

Taxation regimes#

UaTaxRegime is a field on the legal entity through a dictionary extension (the Enum + EDT pair UaTaxRegimeEdt, because the field cannot reference the enum directly). It has four values:

Value Who it is VAT Single tax
VatPayer (default) VAT payer on the general system by first event no
SimplifiedWithVat simplified taxpayer, 3% with VAT by first event 3% of income excluding VAT
SimplifiedNoVat simplified taxpayer, 5% without VAT no 5% of income
General general system without VAT no no

Default is VatPayer: a tenant that does not know about regimes keeps accounting as a regular VAT payer.

Example with numbers. A FOP on 3% with VAT received 120 ₴:

  • VAT base = 120 / 1.20 = 100, liability 20 ₴;
  • single-tax base is also 100, not 120: single tax is charged on income excluding VAT.

The same amount for a FOP on 5% without VAT gives a single-tax base of 120 ₴ and zero VAT.

A regime change is not only a field change. Exceeding the limit from UaSingleTaxLimit writes a transition to UaRegimeChange, and job ApplyUaRegimeChanges moves the legal entity to the general system from the first day of the month after the quarter of the excess (ПКУ 293.8). The excess itself is taxed at 15% (ПКУ 293.4). At the same time, the regime change sets and removes TaxMapping for the exemption code; without that, sales after the transition would use the default code.

Dictionaries#

UaRegimeChange#

Audit trail, not a service table (isLogged: true). The line lives from excess detection until the transition date arrives, and remains after that.

Fields: see UaRegimeChange in Objects below.

Field Business note
LegalEntity Legal entity that exceeded the limit.
FromRegime / ToRegime A 3% simplified taxpayer was a VAT payer and remains one on the general system; a 5% simplified taxpayer was not a VAT payer and does not become one.
ExceededOn Date of the movement that crossed the income limit.
EffectiveFrom First day of the month AFTER the excess quarter (ПКУ 293.8), not the excess date.
AppliedOn Date when the job actually changed the regime. Empty means the transition is still waiting for its date; this makes application idempotent.

UaSingleTaxLimit#

Dated annual limit (ПКУ 291.4). It is data, not a code constant, because it changes every year with the minimum wage.

Fields: see UaSingleTaxLimit in Objects below.

Field Business note
Code Usually the year, for example 2024 or 2025.
Amount Revenue limit. Zero means the limit is not set and excess is not considered at all.
EffectiveFrom / EffectiveTo Validity window. Empty EffectiveTo means open-ended.

UaBankConnection#

Tenant half of the pb-statements channel: address, environment, account, and a reference to the credential. The token itself is not written here, because the dictionary is exported to the workspace and the workspace is in git. This is not TaxAuthorityConnection: the tax operator and the bank are different contours with different secrets.

Fields: see UaBankConnection in Objects below.

Field Meaning
Code What the channel uses as connectionRef (not ID, which comes from a number sequence and cannot be quoted in the channel).
LegalEntity, AccountNumber Which legal entity and which IBAN/account.
BaseUrl Autoclient API address for this client.
CredentialRef Credential name in Integration:Credentials (for example privatbank-merchant) — the token value lives in host configuration.
Environment Free label (test/prod), not the tax enum Sandbox/Simulation/Production.
TimeoutSeconds, MaxRetries Call parameters.
AgentTag Tag of the agent that dials the address from the client's LAN when the bank is not reachable directly from the host.
IsDisabled Optional Boolean is generated as false; an unchecked record participates.

UaLandPlot#

Land plots for MPZ (minimum tax liability, мінімальне податкове зобов'язання) = normative monetary valuation × rate from settings × months in the period / 12. If the dictionary is empty, declaration appendices J0135709/F0133209 remain empty.

Fields: see UaLandPlot in Objects below.

Field Meaning
LegalEntity, Name, CadastralNumber Whose plot and which plot it is.
NormativeValue Normative monetary valuation. MPZ is calculated as the sum of the legal entity's valuations.

UaTaxFilingExport#

Prepared return export for submission, created by the UaExport* commands.

Fields: see UaTaxFilingExport in Objects below.

Field Meaning
LegalEntity, ReturnType Whose return and which return code (the same code as TaxReportMapping.ReturnType).
PeriodFrom/PeriodTo, CreatedOn Window and assembly time.
Payload CSV content for manually transferring numbers to the cabinet.
DeclarXml Unsigned DECLAR (windows-1251 inside the declaration; the field stores Unicode) under Ministry of Revenue Order No. 729 — for import into M.E.Doc; not a signed cabinet container (DPA Order No. 499 / QES).

Dictionary extensions#

Dictionary Owner model Adds
LegalEntity.LocalizationUkraine Organization UaTaxRegime (regime); DpsRegionCode/DpsOfficeCode — C_REG/C_STI codes for DPS forms; IsLegalPerson — TOV vs FOP. Unset intentionally means FOP: the optional Boolean is generated non-nullable, and this decides which excess rate applies — 15% (FOP, ПКУ 293.4/F0103309 line 07) or doubled 6%/10% (legal entity, J0103509 line 2).
Employee.LocalizationUkraine HR 12 DPS fields for forms 4ДФ/D1/D5/D6: DpsIncomeSign (101 salary / 102 civil-law contract), TaxCardNumber (РНОКПП), FireDate/FireReason, DpsTenureGround (special service record D6), DpsInternalPartTime/DpsPartTimeHours (internal part-time vs incomplete hours — DIFFERENT columns, do not confuse them), DpsTransferDate, DpsLaborCategory (1 employees / 2 military personnel / 3 civil-law contract — not derived from DpsIncomeSign automatically except the default), DpsLastName/DpsFirstName/DpsPatronymic/DpsSex — empty if not filled; HR core does not split full names into words.
Position.LocalizationUkraine HR DkppCode — DK 003 profession-classifier code for the D5 column.
TimeOff.LocalizationUkraine HR DpsPersonCategory (D5, 4/5/6); DpsUnpaidLeave — calendar days in D1 G13 (not derived from Kind=Absence: absence is not the same as unpaid leave).

The HR personnel core knows nothing about DPS forms. All 13 fields above live in this package's extensions, not directly in Employee/Position/ TimeOff.

Documents#

The three own documents are thin and one-directional, with the same skeleton: OnBeforeCreateAsync: next → IRecordDefaults.SeedAsync → seed LegalEntity if empty; OnBeforePostAsync: validate only on the subtype being posted, and re-read the document through IDocumentManager.GetDocumentAsync.

UaTaxRemittance#

Remittance of withheld PIT/military levy to the budget. requiresPosting + postOnSave, clonable. Header: required LegalEntity, required TaxCode (PIT or military-levy code). This is the package's only document with a table part: Lines (Employee × Amount).

Draft → Paid → Voided (both endpoint subtypes are isReadOnly). Transaction script UaTaxRemittancePaidTx on Paid: for each line with non-empty Employee and non-zero Amount, writes RegisterMovementSpec("UaPayrollLevy").Dim("LegalEntity", …).Dim("Employee", …).Dim("TaxCode", …).Res("Transferred", …). It does not touch TaxLedger: remittance does not change the liability; it only closes it with money. Voided removes these movements itself (Mix). Manual compensation is not needed here, unlike payroll payment, where PaidBase is written by an event handler.

Pre-posting checks: LegalEntity and TaxCode are not empty, at least one line exists, no amount is negative, and the sum of all lines is greater than zero.

UaFopEsvAccrual#

Accrual of ЄСВ for a FOP "for self". The employment contour does not write here; that is SocialInsurance in HR. Header: required LegalEntity, required Amount. No table part.

Draft → Posted → Voided. Transaction script UaFopEsvAccrualPostedTx on Posted: when LegalEntity is non-empty and Amount != 0, writes RegisterMovementSpec("UaFopEsv").Dim("LegalEntity", …).Res("Amount", …). Checks: LegalEntity is not empty, Amount > 0.

UaVatRefund#

VAT refund claim (line 20.2 of declaration J0200126, not more than line 19). Header: required LegalEntity, required Amount. No table part.

Draft → Posted → Voided. Transaction script UaVatRefundPostedTx on Posted writes RegisterMovementSpec("UaVatRefundClaim").Dim("LegalEntity", …).Res("Amount", …). Checks: LegalEntity is not empty, Amount > 0.

Registers#

Register dimensions and resources: see UaVatFirstEvent, UaVatPayable, UaPurchaseFirstEvent, UaVatCredit, UaPayrollLevy, UaBankStatement, UaFopEsv, and UaVatRefundClaim in Objects below.

Register Business question
UaVatFirstEvent Has the output first event occurred?
UaVatPayable VAT liability.
UaPurchaseFirstEvent Input first event.
UaVatCredit Input VAT credit.
UaPayrollLevy PIT and military levy by person.
UaBankStatement What came in or went out in the statement. This is an information register, not a payment document: CustomerPayment/VendorPayment are not created from it automatically; without EDRPOU reconciliation, the line may be somebody else's money on somebody else's contract.
UaFopEsv Accrued ЄСВ for a FOP "for self"; read by application F0133109.
UaVatRefundClaim Claimed refund amount read by line 20.2.

Why the first event is keyed by dimensions, not analytics. The totals driver calculates the accrual, and the driver sees only register coordinates — analytics are unavailable to it. A register split by analytics would silently match zero lines, without an error. Therefore, UaVatFirstEvent carries legal entity, customer, and contract as dimensions. There are no duplicate analytics for them: customer and contract are already columns, and outlet moves to UaVatPayable.

Why payroll needed a separate register. TaxLedger (Tax) is split by direction, legal entity, and tax code. That is enough to pay the budget, but not enough to show withholding by a specific employee. Form 4ДФ needs the person, so UaPayrollLevy adds the Employee dimension.

UaBankStatement is the package's only registerEngineType: Information register. The other seven are registerEngineType: Standard with a balance table. The statement does not accumulate a balance; it stores posting facts, so useBalanceTable: false and allowNegativeBalance: true describe an import log, not a balance.

Salary deductions#

ЄСВ 22% did not require its own code. It is exactly the social-insurance contour in HR, and the package sets it through settings, not logic.

PIT 18% and military levy are withheld under separate codes and written to UaPayrollLevy and TaxLedger. The military-levy rate is taken on the accrual date: 1.5% until 2024-12-01, then 5% (see the example with numbers above). The ЄСВ base ceiling does not apply to withholdings; they have their own base.

Withholding reduces the debt to the employee through the PayrollLiability .Withheld resource in HR. This is the contract for any second withholder: without it, voiding the payroll fund would treat itself as the only one.

Remittance of the withheld amount to the budget is a separate document, UaTaxRemittance (above), not a subtype change on the payroll statement: only that document writes Transferred in UaPayrollLevy.

ЄРПН — electronic tax invoice#

The envelope is the common TaxDocument (Tax), with subtypes Draft → Issued → Cleared | Rejected; deduplication by source document and the submission journal already exist in the core. The package adds service UaEInvoice, two outbound channels (erpn-send and erpn-receipt), and job PullUaTaxInvoiceReceipts.

Why it is not like KSA. In Saudi Arabia, the host assembles XML and the signature, and Fatoora responds to the same submission. In Ukraine, XML and the qualified electronic signature (КЕП) stay with the operator: the script does not know DSTU 4145, and the key is in the operator's cabinet. Therefore the package sends a flat JSON of facts — contour, number, date, tax number (ІПН), lines — not a DPS form. A made-up form field name would pass our validation and fail in the cabinet when the registration deadline is already urgent.

Successful sending does not close the invoice. The operator has only accepted it for processing. The "sent, no response" state is resolved by a query (UaResolveTaxInvoice or the receipt job), not by resubmission: a repeat submission would create a second document for the same operation.

Channel erpn-gov is direct exchange with the state register for scenarios where the operator is not involved (status/reference request). erpn-send and erpn-receipt serve the regular operator route. Those three plus bank channel pb-statements make the package's four outbound channels.

The Ukraine sales extension folder is SalesRealization.LocalizationUkraine. Bindings inside point to SalesRealization; the handler is found by objectName in the script envelope, not by the folder name.

Extensions of other documents#

Document Owner model Adds
SalesRealization (SalesRealization.LocalizationUkraine folder) Sales UaVatTx — first-event accrual; UaEInvoiceEventHandler — invoice envelope
SalesCreditNote Sales UaCreditVatTx — base movement; UaEInvoiceCreditNoteEventHandler — adjustment calculation
CustomerPayment Sales UaPaymentFirstEventTx — payment as a possible first event; UaPaymentEntityGuardEventHandler — guard against a legal entity that conflicts with the line contract
PurchaseOrder Purchasing UaPurchaseReceiptTx — receipt as the input first event
VendorPayment Purchasing UaVendorPaymentTx — supplier advance as the first event
PurchaseCreditNote Purchasing UaPurchaseCreditTx — Received movement and credit removal
PayrollAccrual HR UaPayrollLevyEventHandler — PIT and military-levy withholdings on accrual
PayrollPayment HR UaPayrollPaymentLevyEventHandler — the same pattern on the payment side: writes PayrollLiability.Withheld and TaxLedger, without accruing again
TaxReturn Tax Only .extension.json, no scripts. The extension aggregate is declared and empty, confirmed by a glob over the directory. The extension point is reserved, possibly for future Ukrainian return fields, but currently carries no fields or behavior.

Direct package writes into other models' registers (PayrollLiability, TaxLedger from the two HR handlers above, next to package register UaPayrollLevy) are explained as a pattern in 20-Localization-Overview.

Services#

  • UaFirstEvent — determines whether the first event (shipment or payment) has occurred by the accumulation in UaVatFirstEvent/UaPurchaseFirstEvent, and calculates the accrual as the increase of max(Shipped, Paid), so that an advance and a later shipment for the same amount do not double-tax it. Called from transaction scripts such as UaVatTx, UaPaymentFirstEventTx, and UaPurchaseReceiptTx.
  • UaPayrollLevies — calculates PIT/military levy by the rate effective on the accrual date (see Salary deductions) and writes all three destinations in one call: UaPayrollLevy, PayrollLiability.Withheld (HR), and TaxLedger (Tax).
  • UaTaxFiling — assembles UaTaxFilingExport by return code: reads TaxLedger/TaxReportMapping for the period, creates CSV and, where applicable, unsigned DeclarXml. Common entry point for all seven UaExport* commands.
  • UaEInvoice — builds a flat JSON envelope for a tax invoice or adjustment calculation from the source document and queues channel erpn-send; parses receipts from inbound channels erpn-receipt/erpn-gov.
  • UaBank — parses the Autoclient statement (REF+REFN, TRANTYPE C/D) into UaBankStatement lines. It does not itself reconcile with CustomerPayment/ VendorPayment by EDRPOU; that is intentionally left to a person (see the register description above).

Outbound channels and jobs#

Channel Purpose
erpn-send submits the tax invoice/adjustment calculation to the operator
erpn-receipt receives receipts about the submitted invoice status
erpn-gov direct exchange with the state register, bypassing the operator (status/reference request)
pb-statements Autoclient bank statement import; connectionTable: UaBankConnection, not a tax dictionary
Job Does
ApplyUaRegimeChanges moves the legal entity to the general system from UaRegimeChange.EffectiveFrom, idempotently by AppliedOn
PullUaTaxInvoiceReceipts pulls receipts through erpn-receipt and updates TaxDocument status
PullUaBankStatements periodically pulls the statement through pb-statements and writes UaBankStatement lines

Root group Ukraine (displayOrder 12) with four subgroups:

  • Settings — LocalizationUkraineSettings, UaBankConnection.
  • Dictionaries — UaSingleTaxLimit, UaRegimeChange, UaTaxFilingExport, UaLandPlot.
  • Registers — UaVatPayable, UaVatFirstEvent, UaVatCredit, UaPurchaseFirstEvent, UaPayrollLevy, UaBankStatement, UaFopEsv, UaVatRefundClaim.
  • Documents — UaTaxRemittance, UaFopEsvAccrual, UaVatRefund.

Services, jobs, and reporting views are not shown in the menu because they are not menu-navigable object kinds on this platform.

Reporting views#

Three Custom Reports read package registers:

View Source Breakdown
UaPayrollLevyByEmployeeCode UaPayrollLevy by employee code
UaVatCreditBySupplier UaVatCredit by supplier
UaVatPayableByCustomerContract UaVatPayable by customer and contract

Printed declaration forms#

11 printed forms are physically located in directories of OTHER models. The form belongs to the host document, not to the package that fills it with data:

  • 10 forms under Tax/Documents/TaxReturn/PrintForms/: UaDps4DfZr, UaDpsCalculationZr, UaDpsD1Zr, UaDpsD5Zr, UaDpsD6Zr, UaFopSingleTaxDeclarationZr, UaLevyWorkpaperZr, UaQuarterlyWorkpaperZr, UaSingleTaxDeclarationZr, UaVatDeclarationZr.
  • 1 form under Sales/Documents/SalesRealization/PrintForms/: UaFiscalReceiptSample.

Business logic and invariants#

Prepayment is taxed before shipment; shipment does not accrue tax a second time. Accrual uses the increase of max(Shipped, Paid), not the sum: an advance of 120 ₴ closes the base, and a later shipment for the same amount adds nothing.

Partial prepayments together produce one full tax. Two half-events create exactly one full liability, not two and not one and a half.

A credit note moves the base, not only the tax, and does not release the liability until the prepayment is returned.

VAT from different outlets of one customer is not mixed because the contract is part of the register coordinates.

A payment whose legal entity conflicts with the line contract is rejected, and an empty legal entity is taken from the contract. Otherwise, Shipped and Paid would diverge by coordinates and tax would be accrued twice.

A non-VAT payer still writes events, but does not move credit: switching between regimes does not lose history.

Remittance and accrual of FOP ЄСВ / VAT refund do not accrue tax twice. All three own documents write a resource register without a second entry in TaxLedger: UaTaxRemittance closes a liability that is already accrued as debt and does not accrue it again; UaFopEsvAccrual/UaVatRefund are independent facts, not derivatives of sales or purchases.

Voided removes its own movements itself (Mix), except in one place. On payroll payment, PaidBase is written by an event handler and removal requires manual compensation. The package's own documents (UaTaxRemittance and others) do not need that, because only a transaction script writes their movements.

Package tests#

17 integration tests cover: end-to-end VAT flow by first event (UkraineVatFlowTest), seeded rates (UkraineSeededRatesTest), regimes and forced change (UkraineTaxRegimeTest, UkraineForcedRegimeChangeTest), input VAT on purchase (UkrainePurchaseVatTest), declaration exports (UkraineFilingExportTest, UkraineQuarterlyFilingTest, UkraineVatDeclarationFilingTest, UkraineFopSingleTaxDeclarationFilingTest, UkraineSingleTaxDeclarationFilingTest, UkraineDpsPayrollFilingTest, UkrainePayrollFilingTest), exemption mapping (UkraineExemptMappingTest), payroll withholdings (UkrainePayrollLevyTest), bank connection and statement (UkraineBankConnectionTest, UkraineBankStatementTest), and the single-tax limit (UkraineSingleTaxLimitTest).

What's not there yet#

  • No live exchange with M.E.Doc in CI: the MakeDoc/ToGov/GetDocInfo adapter is in the package, but REST is a service on the accountant's PC. Setup note: M.E.Doc on the client. The exchange itself is not covered by tests.
  • PrivatBank statement import is implemented, but without a live sandbox. Channel pb-statements, dictionary UaBankConnection, service UaBank, job PullUaBankStatements, and register UaBankStatement are all available in code and covered by tests (UkraineBankConnectionTest, UkraineBankStatementTest). What is missing: an Autoclient sandbox for checking against a live API and automatic creation of CustomerPayment/VendorPayment from a statement line. EDRPOU reconciliation is intentionally manual; see the register above. Setup note.
  • No Diia (Дія). Login is platform identity, not a package feature. Why it is separate.
  • No DPS cabinet container (Order No. 499 / QES). Unsigned DECLAR for the payroll J05 family is stored in field DeclarXml for import into M.E.Doc. Forms with official identifiers: payroll J0500111 / J0510411 / J0510111 / J0510511 / J0510611 (4ДФ R01011=income sign 101 / R01012=102, R0107=line 3; D1 G5 citizenship / G6S sex / G8=26 civil-law contract / G111–G113 full name / G12 Sick / G13 unpaid / G14 HireDate/FireDate / G15 maternity leave / G21–G22 part-time and incomplete hours / G24 new workplace from the flag, not HireDate; D5: HireDate/FireDate/DpsTransferDate/ DkppCode; ordinary employers do not file D2/D3), VAT J0200126 (form rows, not R00xG3; line 20.2 from UaVatRefund; UA-ZX→2.1, UA-Z→3), single tax for legal entities J0103509 (UA-EP6/UA-EP10 line 2, UA-EPB3/UA-EPB5 line 3, UA-EPF3/UA-EPF5 line 4, MPZ from UaLandPlot), and FOP F0103309 (F0133109 from UaFopEsvAccrual). Accrued amounts come from registers; paid amounts after PayrollPayment; ЄСВ paid from SocialInsurancePayment (D1 and R0107 are not reset); remitted from document UaTaxRemittance; C_REG/C_STI are legal-entity fields in the CSV header and in the DeclarXml head.
  • Workpapers UA-LEVY and UA-QPR remain for transfer without DPS column codes.
  • Outgoing: Tax — codes, rates, mappings, ledger, invoice envelope, TaxReturn declaration (empty extension); Sales and Purchasing — documents extended by the package; HR — accrual base, withholding resource, Employee/Position/ TimeOff fields; Organization — legal entity, its regime, and DPS codes; Inventory — counterparties and item in the first event.
  • Incoming: none. The package is the top layer; nothing references it.

Objects#

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

Dictionaries#

LocalizationUkraineSettings — Ukraine settings

Field Caption Type Required
EInvoiceEnabled E-invoice (tax invoice) enabled Boolean No
ExemptVat Exempt VAT (no-VAT regimes) → TaxCode No
ExemptVatCode Exempt VAT code (no-VAT regimes) String(64) No
ID ID String(50) Yes
IncomeTax Personal income tax (payroll) → TaxCode No
IncomeTaxCode Personal income tax code (payroll) String(64) No
MilitaryLevy Military levy (payroll) → TaxCode No
MilitaryLevyCode Military levy code (payroll) String(64) No
MpzRate MPZ rate Decimal(18,4) No
PayrollIncomeSign 4ДФ income sign (payroll) String(8) No
SingleTax3 Single tax 3% (with VAT) → TaxCode No
SingleTax5 Single tax 5% (without VAT) → TaxCode No
SingleTaxCode3 Single tax code, 3% (with VAT) String(64) No
SingleTaxCode5 Single tax code, 5% (without VAT) String(64) No
SingleTaxCodeDouble3 Double rate code 6% (legal person, 3%) String(64) No
SingleTaxCodeDouble5 Double rate code 10% (legal person, 5%) String(64) No
SingleTaxCodeExcess Single tax code, 15% (over the limit) String(64) No
SingleTaxDouble3 Double rate 6% (legal person, 3%) → TaxCode No
SingleTaxDouble5 Double rate 10% (legal person, 5%) → TaxCode No
SingleTaxExcess Single tax 15% (over the limit) → TaxCode No
TaxInvoiceAdjustmentFormCode Tax invoice adjustment form code String(32) No
TaxInvoiceFormCode Tax invoice form code String(32) No
VatReturnType Return type for export String(32) No

UaBankConnection — Bank connections

Field Caption Type Required
AccountNumber Account / IBAN String(34) No
AgentTag Agent tag String(100) No
BaseUrl Base URL String(256) Yes
Code Code String(128) Yes
CredentialRef Credential reference String(128) No
Environment Environment String(32) No
ID Code String(50) Yes
IsDisabled Disabled Boolean No
LegalEntity Legal entity → LegalEntity Yes
MaxRetries Max retries Integer No
Name Name String(256) Yes
TimeoutSeconds Timeout, s Integer No

UaLandPlot — Land plot (Ukraine MPZ)

Field Caption Type Required
CadastralNumber Cadastral number String(32) No
ID Code String(50) Yes
LegalEntity Legal entity → LegalEntity Yes
Name Name String(256) Yes
NormativeValue Normative value Money No

UaRegimeChange — Forced regime change

Field Caption Type Required
AppliedOn Applied on DateTime No
EffectiveFrom Effective from DateTime Yes
ExceededOn Exceeded on DateTime Yes
FromRegime From regime UaTaxRegimeEdt No
ID Code String(50) Yes
LegalEntity Legal entity → LegalEntity Yes
ToRegime To regime UaTaxRegimeEdt No

UaSingleTaxLimit — Single tax revenue limit

Field Caption Type Required
Amount Limit Money Yes
Code Code String(32) Yes
EffectiveFrom Effective from DateTime Yes
EffectiveTo Effective to DateTime No
ID Code String(50) Yes

UaTaxFilingExport — Tax filing export

Field Caption Type Required
CreatedOn Created on DateTime No
DeclarXml DECLAR XML (M.E.Doc import) LargeText No
ID ID String(50) Yes
LegalEntity Legal entity → LegalEntity Yes
Payload Payload LargeText No
PeriodFrom Period from DateTime Yes
PeriodTo Period to DateTime Yes
ReturnType Return type String(32) Yes

Documents#

UaFopEsvAccrual — FOP ESS for self (Ukraine)

Header fields:

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

Subtypes:

Subtype Caption
Draft Draft
Posted Posted
Voided Voided

Commands:

Command Caption Target subtype
UaPostFopEsv Post FOP ESS —
UaVoidFopEsv Void FOP ESS —

UaTaxRemittance — Tax remittance to budget (Ukraine)

Header fields:

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

Subtypes:

Subtype Caption
Draft Draft
Paid Paid
Voided Voided

Commands:

Command Caption Target subtype
UaPayTaxRemittance Remit to budget —
UaVoidTaxRemittance Void remittance —

UaVatRefund — VAT refund claim (Ukraine)

Header fields:

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

Subtypes:

Subtype Caption
Draft Draft
Posted Posted
Voided Voided

Commands:

Command Caption Target subtype
UaPostVatRefund Post VAT refund claim —
UaVoidVatRefund Void VAT refund claim —

Registers#

UaBankStatement — PrivatBank statement lines

Dimensions:

Dimension Caption Type Required
BankRef Bank ref (REF+REFN) UaBankRefEdt —
LegalEntity Legal entity → LegalEntity —

Resources:

Resource Caption Type Required
Amount Amount Money —
CounterpartyEdrpou Counterparty EDRPOU UaBankTextEdt —
CounterpartyName Counterparty name UaBankTextEdt —
Purpose Purpose UaBankTextEdt —
TranType C/D UaBankTranTypeEdt —

UaFopEsv — FOP ESS for self (Ukraine)

Dimensions:

Dimension Caption Type Required
LegalEntity Legal entity → LegalEntity —

Resources:

Resource Caption Type Required
Amount Amount Money —

UaPayrollLevy — Ukraine payroll levies withheld

Dimensions:

Dimension Caption Type Required
Employee Employee → Employee —
LegalEntity Legal entity → LegalEntity —
TaxCode Tax code → TaxCode —

Resources:

Resource Caption Type Required
Amount Amount Money —
Base Base Money —
PaidBase Paid income Money —
Transferred Transferred to budget Money —

UaPurchaseFirstEvent — Ukraine input VAT first event

Dimensions:

Dimension Caption Type Required
LegalEntity Legal entity → LegalEntity —
Supplier Supplier → Supplier —

Resources:

Resource Caption Type Required
Credited Base already credited Money —
PaidOut Paid out Money —
Received Received base Money —
ReceivedCoded Received base with line tax code Money —
ReceivedCodedVat VAT of coded received lines Money —

UaVatCredit — Ukraine input VAT credit

Dimensions:

Dimension Caption Type Required
LegalEntity Legal entity → LegalEntity —
Supplier Supplier → Supplier —

Resources:

Resource Caption Type Required
Amount Amount Money —

UaVatFirstEvent — Ukraine VAT first event

Dimensions:

Dimension Caption Type Required
Customer Customer → Customer —
LegalEntity Legal entity → LegalEntity —
SalesContract Sales contract → SalesContract —

Resources:

Resource Caption Type Required
Accrued Base already taxed Money —
EpAccrued Base already taxed (single tax) Money —
Paid Paid base Money —
Shipped Shipped base Money —
ShippedCoded Shipped base with line tax code Money —
ShippedCodedVat VAT of coded shipped lines Money —

UaVatPayable — Ukraine VAT payable

Resources:

Resource Caption Type Required
Amount Amount Money —

Analytics:

Analytic Caption Type Required
UaVatPayable-Customer UaVatPayable-Customer — Yes
UaVatPayable-CustomerOutlet UaVatPayable-CustomerOutlet — Yes
UaVatPayable-SalesContract UaVatPayable-SalesContract — Yes

UaVatRefundClaim — VAT refund claim (Ukraine)

Dimensions:

Dimension Caption Type Required
LegalEntity Legal entity → LegalEntity —

Resources:

Resource Caption Type Required
Amount Amount Money —

Table parts#

UaTaxRemittanceLines — Remittance lines

Used by: UaTaxRemittance.

Field Caption Type Required
Amount Amount Money Yes
Employee Employee → Employee Yes
Was this page helpful?