Plank help · updated 2026-08-04
Sales realizations from customer invoices in 1C
How to turn a «Счет на оплату покупателю» into a «Реализация товаров и услуг» draft over OData: the basis link is the identity, deal facts come from the invoice while accounting attributes come from a verified local document, and what ЭАВР actually is — a separate document that may be invisible until someone publishes it.
Agents: fetch the raw markdown of this page at /en/help/1c-sales-realizations.md
Sales realizations from customer invoices in 1C
A «Счет на оплату покупателю» is an offer. A «Реализация товаров и услуг» is the sale. Turning the first into the second is mostly copying — and the parts that are not copying are the parts that go wrong.
There is a kit for this: install 1c-sales-realization-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 basis link is the identity
A realization created from an invoice carries ДокументОснование — the invoice's
Ref_Key — together with ДокументОснование_Type
(StandardODATA.Document_СчетНаОплатуПокупателю). That pair is the duplicate
key. Not the number, not the amount, not the counterparty and date.
Check it immediately before each POST, not once at the top of a batch. A run over nine invoices that checks once and writes nine times has a nine-document window in which somebody else's session can create the same realization.
ДокументОснование_Type is half of the key and it is easy to drop. Two different
document types can hold the same Ref_Key value in the same field; matching on
the reference alone will eventually match the wrong basis.
Two sources, and they are not interchangeable
| From the invoice | From a verified realization in this base |
|---|---|
| organisation, counterparty, contract | operation type (ВидОперации) |
| currency | subdivision (Подразделение) |
| the service lines: nomenclature, quantity, price, amount | accounting accounts |
| VAT rate and VAT amount | nomenclature group |
| the document total | anything else the configuration requires and the invoice does not carry |
The right-hand column is accounting policy. It is not in the invoice, it is not guessable from the name of anything, and it differs per organisation. Take it from a posted realization of the same organisation in the same base — the most recent comparable one — and take nothing else from that template.
Do not select a reference because its name resembles what you want. Every reference you write must exist in this base and belong to this document's organisation. See OData rules §5 and §11.
Building the payload
Start from the template, then remove what 1C owns and what belongs to the template rather than to your document:
Ref_Key,DataVersion,Number— server-owned. 1C assigns them.- every key ending
@navigationLinkUrlor@associationLinkUrl, and the metadata keys. They are read artefacts; posting them back is at best ignored and at worst a 400.
Then:
- Send the empty tabular sections the object requires — typically
Товары,НомераГТД,УчастникиСовместнойДеятельности— as[]. Omitting a required section is not the same as sending it empty. - Number the
Услугиrows with a sequentialLineNumberstarting at 1. Rows without it can be stored in an order you did not choose. - Every tabular section travels inside the parent document's POST. Rows cannot be created through their own entity set.
- Re-check per row: quantity × price = amount, the VAT rate, the VAT amount, and the sum of rows against the header total.
Posted = false, DeletionMark = false, and a comment saying where the draft
came from — as with everything else this kit writes.
Posting is a separate, explicit decision
Only on a direct instruction from the user, and then through the OData action
Post(). Setting the Posted field is not posting; it is writing a flag onto a
document whose registers never moved. See
OData rules §7.
A posting failure is a stop-and-report, not a retry. On 2026-08-04 Post() on
one realization returned
Не удалось провести "Реализация ТМЗ и услуг 00000000269 …" and the document was
unchanged. That is 1C's accounting logic refusing, and the remedy is in 1C — an
accountant reading the event log — not in a differently-shaped payload.
Verify by reading
Re-read each created document by Ref_Key and compare against what you computed:
the basis reference and its type, the organisation, the counterparty, the
contract, the row count, each row's nomenclature, quantity, price, amount and VAT,
the header total, and Posted = false.
Then do the reconciliation the per-document check cannot do: exactly one realization per source invoice, and no invoice left without one. Report the count you skipped because a realization already existed, separately from the count you created. A 2xx is not evidence — see OData rules §9.
ЭАВР — the electronic act of work performed
An ЭАВР is a separate 1C document: Document_ЭлектронныйАктВыполненныхРабот,
linked to its realization through ДокументОснование and
ДокументОснование_Type. Not a printed form, not a view of the realization.
An object 1C did not publish is indistinguishable from an object nobody uses
Before you conclude that a base does not use some document type, establish that the
type is published to OData. 1C publishes objects to its OData interface one
checkbox at a time, and an unpublished object is simply absent from $metadata —
no error, no empty collection, nothing to notice.
On 2026-08-04 that cost a morning. The base reported 687 entity sets and no ЭАВР object, which read as "this configuration does not do ЭАВР". Someone ticked the publication checkbox in 1C; the count became 692, and 1,106 ЭАВР were readable that had existed all along.
So when a document type you expect is missing:
python3 scripts/1c/realization/check-eavr.py
It reports whether the object is published, how many ЭАВР the base holds, and what the local numbering convention is — or tells you the checkbox is the next step. "Not published" and "not used" need different answers, and only one of them is yours to give.
СпособВыпискиАктовВыполненныхРабот is a method, not an act
The realization field СпособВыпискиАктовВыполненныхРабот chooses how acts are
to be issued: on paper, through the state-procurement portal, or
НаПорталеИСЭСФ. Setting it to НаПорталеИСЭСФ creates nothing.
This is worth stating flatly because the evidence points the other way. In that
base 849 of 1,013 comparable posted realizations carried НаПорталеИСЭСФ, and the
realizations that had a visible ЭАВР all carried it too. The field correlates with
the act because the same accountants set both — it does not produce it.
A realization is not "done with ЭАВР" because the field is set. Confirm the act
by finding the ЭАВР record whose ДокументОснование is that realization, and read
its Статус and Состояние.
The number comes from the basis
In that base 99% of outgoing ЭАВР carry the same number as their realization: 212 of 214 confirmed acts, 5 of 5 drafts, 37 of 37 erroneous ones. Take the number from the basis realization and verify it after the write.
Do not accept OData's next sequential number. It will be plausible, it will be unique, and it will break the one convention that lets an accountant match an act to its sale by eye.
A draft's initial state, and what never comes from the template
Confirmed against five existing drafts in that base:
| Field | Value for a new draft |
|---|---|
Статус | Черновик |
Состояние | Сформирован |
Направление | Исходящий |
| registration number | empty |
| portal identifier | empty |
Never copy from a confirmed template: the registration number, the portal
identifier, the signatures, the status or the state. A local draft carrying
AKT-… and ПодтвержденПолучателем claims a portal registration that never
happened, on a document nobody signed.
The contract, the counterparty's accounting attributes and the line templates are what a template is for — and only from a template of the same counterparty.
Line amounts follow the base's VAT flags
Compute each line with УчитыватьНДС and СуммаВключаетНДС in hand; the two
combine into four different arithmetics and only one of them is right for a given
document. The document total must equal the basis realization's
СуммаДокумента exactly. If it does not, stop — a mismatch here is a wrong act,
not a rounding preference.
OData gives you no "create on the basis of"
For ЭАВР, 1C publishes only the Post and Unpost actions. There is no
server-side "fill from realization", so the payload is assembled by hand — which is
exactly why the field-by-field rules above are not optional.
Known blocker: ОбработкаЗаполнения rejects the create
Creating an ЭАВР over OData is not currently working, and the kit's
create-eavr.py is a dry run with no --apply.
A POST against a fully validated payload — nine acts, dry run clean, amounts matching, duplicates excluded — returned:
HTTP 500: Ошибка при выполнении обработчика «ОбработкаЗаполнения»
What is established: the document was not created (a re-read found nothing); nothing partial was written; it is not a rights error. The most likely untested cause is that the basis realizations were unposted — that configuration handler may require a posted basis.
The next step is the 1C event log (журнал регистрации), which holds the internal error text the OData response omits. Get that text before retrying. Varying the payload blind against a handler you cannot read produces, at best, a document that posts and is wrong.
Until then: build ЭАВР in 1C, or ask the accountant to.