Plank help · updated 2026-07-31
Reconciliation acts in 1C
How to build an «Акт сверки взаиморасчетов» in 1C without asserting things you do not know: whose figures go in which column, the contract rule, debit/credit direction, opening balance versus discrepancy, one currency, and verifying the amounts you wrote.
Agents: fetch the raw markdown of this page at /en/help/1c-reconciliation-acts.md
Reconciliation acts in 1C
An «Акт сверки взаиморасчетов» states, for one counterparty and one period, what each side thinks the other owes. It has two tabular sections because it holds two opinions — and the second one is not yours to write.
Everything on this page exists because a wrong act is not obviously wrong. It reads perfectly, it gets signed, and it goes to a counterparty.
There is a kit for this: install 1c-reconciliation-act-kz (see
the 1C starter kit) rather than writing a fresh script.
The rules below are what it enforces, and what you have to honour if you adapt it.
The counterparty's side is theirs, and you do not know it
ПоДаннымОрганизации is your books. ПоДаннымКонтрагента is theirs — and
nothing in a script knows what theirs say.
There are three honest states, and the default is the third:
- You have their act. Fill the second table from it and report the discrepancies explicitly. That is the entire point of the document.
- A person has established they recorded the same operations. Mirror the rows —
same dates, same documents, same types, same contracts, with debit and credit
swapped — and mark the act agreed.
create-act.py --counterparty-confirmed. - You know nothing. Leave their table empty and «Сверка согласована» false.
Do not mirror by default. An act whose counterparty column was derived from your own books, stamped «Сверка согласована», asserts that they confirmed figures they never saw — on a document you are about to send them. The kit refuses, and warns when you write an unagreed act, so the empty column is a decision rather than an oversight.
The contract rule
Count the counterparty's contracts in Catalog_ДоговорыКонтрагентов, filtered by
Owner_Key, the right Организация_Key, DeletionMark=false and
IsFolder=false. Then:
| Contracts found | What to do |
|---|---|
| none | leave the contract empty |
| exactly one | put it in the header and in the rows of both tables |
| more than one | leave the header empty — do not pick one |
Picking one of several at random is worse than leaving it blank: a blank field reads as "across all contracts", which is true, while a guessed one asserts something about which debt is being reconciled.
Debit and credit direction
For customer settlements, in ПоДаннымОрганизации:
- a sale (
РеализацияТоваровУслуг) is a debit; - an incoming payment (
ПлатежноеПоручениеВходящее,ПлатежныйОрдерПоступлениеДенежныхСредств) is a credit.
Do not take this on faith across configurations — and do not read the acts by hand either. Run:
python3 scripts/1c/reconciliation-act/check-direction.py
python3 scripts/1c/reconciliation-act/check-direction.py --since 2025-01-01
It reports which side each settlement type lands on in this base's own posted acts,
with row counts, act counts, counterparty counts and date ranges, and prints the
document_sides block to paste — or says why the evidence is not conclusive.
It needs at least 3 rows across at least 2 acts per document type. Below that it reports "not enough to call the convention" and prints nothing to paste. One row is an anecdote, and what gets pasted here signs every future act balance: three rows of one act can be the same operation repeated, and two acts of one row each is a coincidence away from being two documents of the same kind. Acts the kit wrote are excluded, because taking our own output as proof of the convention is how a first wrong guess becomes permanent.
Two things make it local rather than universal, and both surface as "BOTH — mixed
evidence": the direction inverts by settlement kind (a customer receivable rises
with a sale, a supplier payable falls with one), and it changes over time — a base's
acts from three years ago can use the reverse of this year's. --since is how you ask
what the base does now. The direction is the one thing here that a wrong answer makes
silently, plausibly wrong.
Opening balance and discrepancy are different numbers
ОстатокНаНачало is the net of all settlement documents dated before the
period — not zero, not the first row. Compute it from the same documents you filter
for the body, using the same rules.
Расхождение is the gap between the two sides: your closing balance minus
theirs. It is NOT your closing balance. Writing the closing balance there produces
an act that declares a disagreement equal to the whole outstanding amount while its
two tables agree by construction — and, if you also stamped «Сверка согласована», one
that contradicts itself in two fields at once. With their table empty the discrepancy
is your whole closing balance, which is the correct reading of "we have no figures
from them".
Only posted, not-marked-for-deletion documents count. An unposted draft has moved no registers, so including it states a balance the accounting does not have. Count the ones you excluded and say how many: it is usually the answer to "why is this total not what I expected".
Every settlement type in the base, not only the ones you configured
The types you read must be discovered from the base — from what the deployment's
entity_sets knows about — and then checked against document_sides. Doing it the
other way round is a guard that cannot fire: if you only read the types you already
declared, a type you forgot is never read, never reported, and silently missing from
the balance — and the act reads as complete, with exit code 0 and nothing in the
report to suggest a number is missing.
A type present in the base with no declared direction stops the run. So does a type that could not be read — an unreadable table is not an empty one.
One currency
Do not sum documents in different currencies into one balance, and do not take the currency from the template act. Take it from the documents; refuse when they disagree. A number that is right in one currency and labelled with another is wrong in the way that is hardest to see.
The contract on a row is that document's contract
The header contract follows the rule above. Each row carries its own document's
ДоговорКонтрагента_Key, falling back to the header's only when the document names
none. Relabelling a historical document with the counterparty's currently active
contract misstates which debt is being reconciled.
Fields the kit sets for you
Posted = false,DeletionMark = false— a draft like everything else this kit writes. Posting stays the accountant's decision, made in 1C.СверкаСогласована— follows the confirmation, not the clock. See above.- Author, responsible and
СписокСчетовcome from a recent correct act of the same organisation in the same base. They are per-base settings, and aRef_Keyfrom another base means nothing. Currency does not — that comes from the documents.
Both tabular sections travel inside the parent document's own POST — rows cannot be created through their own entity set.
Duplicate guard
Before creating, look for an active act with the same organisation, the same counterparty and the same period. One period reconciled twice is two documents that disagree with each other by construction.
Resolve the counterparty by exact БИН/ИИН. Zero matches or several matches is stop-and-ask, never a guess by name.
Verify by reading — the amounts
After the write, re-read the document by Ref_Key and compare against what you
computed: the period, the counterparty, the contract, the currency, the opening
balance, the discrepancy, Posted=false, «Сверка согласована», and for both
tables the row count and each row's «Дебет», «Кредит» and document reference.
Checking flags, dates and row counts is not verification. A configuration that recomputes or zeroes every monetary cell passes all of those — and the report then prints the numbers you calculated as though 1C had returned them. Build the report from what was stored, not from what was computed.
A 2xx is not evidence. See Working with 1C over OData §9.
Known limits
- The duplicate check is not atomic. It lists existing acts, then POSTs. 1C's OData offers no uniqueness constraint to lean on, so two concurrent runs for the same counterparty and period can both pass and both write. Run one at a time.
- No closing-balance field is written. Which attribute a configuration keeps it in is not established, and writing a field name nobody verified is worse than leaving the configuration to compute it from the rows.
Posting
Only on a separate, explicit instruction from the user.