Plank help · updated 2026-09-21

Загрузка входящих ЭСФ в 1С

Как входящая электронная счёт-фактура превращается в связанную пару «Счёт-фактура полученный» + «Поступление товаров и услуг» в 1С: обязательная тройная связь, товар или услуга (решает карточка, построчно), аналитика строк поступления, какой из двух номеров ЭСФ — «номер», выбор исторического шаблона, разрешение номенклатуры и единиц без выдумывания карточек, стоп-условия.

Agents: fetch the raw markdown of this page at /ru/help/1c-incoming-esf-import.md

Загрузка входящих ЭСФ в 1С

Входящая ЭСФ — это не документ. Это уведомление о том, что поставщик её выписал. Учёт появляется только тогда, когда в 1С есть полученный счёт-фактура и поступление товаров и услуг, связанные друг с другом и с самой ЭСФ.

Сначала: ЭСФ должна уже быть внутри 1С

Всё на этой странице начинается со строки в Document_ЭСФ. Как она туда попадает — отдельная задача, которую ни эта страница, ни скрипты здесь не выполняют. Три вещи легко перепутать:

Что делаетКладёт ЭСФ в Document_ЭСФ?
Собственный «Обмен с ИС ЭСФ» в 1СОбмен внутри 1С, настраивает бухгалтер своей ЭЦПДа — это предварительное условие
Подключение ЭСФПрямой клиент к esf.gov.kz: показывает выписанные и полученные счета-фактуры, выписывает новыеНет — отдаёт данные файлами
Эта страница / 1c-esf-import-kzПревращает ЭСФ, уже лежащую в 1С, в связанные счёт-фактуру и поступлениеЧитает их; никогда не создаёт

Ловушка — средняя строка. connecting-esf умеет видеть полученные счета-фактуры, поэтому пространство, подключившее ЭСФ, разумно ожидает, что загрузка сработает, — и не находит ничего, потому что то подключение идёт к порталу, а это читает 1С.

Если в базе нет ЭСФ, вопрос в том, настроен ли и запускался ли обмен на стороне 1С. Никакой скрипт его не заменит. check-access.py показывает Document_ЭСФ как опубликованный, но пустой, а загрузчик отличает «в этой базе вообще нет ЭСФ» от «этого регистрационного номера здесь нет» — это разные проблемы с разными следующими шагами.

Обратное направление — выписка своих счетов-фактур в портал — описано в Подключении ЭСФ. Эта страница только про пришедшие ЭСФ.

Для этого есть кит: 1c-esf-import-kz. Установите его (см. стартовый кит 1С), а не пишите новый скрипт:

python3 scripts/1c/esf/import-esf.py --first 5              # сухой прогон — посмотрите, какие даты он выбрал
python3 scripts/1c/esf/import-esf.py --registration 35318 --apply

--first N сортирует по возрастанию, то есть отдаёт самые старые неразнесённые ЭСФ. В базе, которая работает несколько лет, это почти никогда не те документы, о которых спрашивают, — см. ниже «Пакеты, и с каких ЭСФ начинается пакет». Прочитайте даты в сухом прогоне до --apply, и если это не тот период, ведите запись через --registration по каждому документу, а не полагайтесь на порядок сортировки.

Правила ниже — то, что он проверяет, и то, что нужно соблюсти, если вы его адаптируете.

Всё здесь предполагает, что вы уже прочитали Работу с 1С через OData. Правила оттуда — сопоставлять по идентификатору, не проводить, перечитывать после каждой записи, не хардкодить Ref_Key — действуют без изменений и не повторяются.

Цепочка, и почему двух документов недостаточно

Входящая ЭСФ ──▶ Счёт-фактура полученный ◀──▶ Поступление товаров и услуг

Три связи, все обязательны:

  1. поле СчетФактура у ЭСФ указывает на полученный счёт-фактуру;
  2. счёт-фактура указывает на поступление основной ссылкой и строкой в ДокументыОснования;
  3. поступление указывает обратно на счёт-фактуру.

ЭСФ не обработана только потому, что созданы два новых документа. Без первой связи интерфейс 1С по-прежнему показывает ЭСФ как необработанную, какими бы полными ни выглядели два документа, — и бухгалтер, открыв её, находит разорванную цепочку. Связь ЭСФ → счёт-фактура записывайте даже когда просили только черновик.

Базу выбирают по ЭСФ, а не по credentials

Целевую базу 1С определяет организация, указанная в ЭСФ. Находите её через реестр баз рабочего пространства. Нельзя брать адрес, который просто лежит в общем credentials.json: у практики с 17 клиентами 17 баз, и цена ошибки — документ в чужом учёте.

Шаблон берут из истории, но только структуру

Перед созданием прочитайте уже проведённые входящие ЭСФ этой же базы и связанные с ними документы. Приоритет:

  1. тот же поставщик по точному Ref_Key;
  2. тот же тип операции — товары или услуги;
  3. тот же признак НДС — есть налог в строках или нет;
  4. максимальное пересечение подтверждённой номенклатуры;
  5. при равенстве — самый свежий корректный документ.

Шаблоном никогда не берут документ, который «Проведён», но не сделал ни одного движения в регистрах: 1С так «проводит» документ, который молча отклонила. import-esf.py сам проверяет, какие проведённые документы действительно дали движения, остальные не использует ни как шаблон, ни как пример и перечисляет в отчёте (posted-without-movements) — их стоит открыть в 1С.

Пункт 3 стоит выше свежести не случайно. УчитыватьНДС и СуммаВключаетНДС — настройки базы, они переносятся из шаблона и определяют итог документа. В реальной базе самая свежая проведённая цепочка поставщика была без НДС, свежесть победила — и ЭСФ на 8 200,00 ₸ записалась как 7 068,97 ₸, то есть суммой без налога. Итог сверяется после записи, но документ к этому моменту уже существует, а 1С отказалась править его через OData.

Не берите шаблон с существенным расхождением сумм, ошибочным НДС или неполными ссылками.

Из шаблона берут только настройки. Склад, счета расчётов и авансов, автора и ответственного, валюту, счета и аналитику строк, вид операции, форму табличных частей.

Договор — не из шаблона. Он принадлежит одному контрагенту, поэтому шаблон другого поставщика назвал бы соглашение, которого у этого поставщика нет.

Если договор указан в самой ЭСФ, импорт пробует по порядку и в пробном запуске пишет, какой шаг сработал:

  1. выбор, который бухгалтер записал для этой ЭСФ (esf.contract_by_registration);
  2. тот же номер и та же дата;
  3. тот же договор, записанный иначе, — тот же номер с другой датой или те же слова («Договор оферты» и «Оферта»); только если подходит ровно одна карточка;
  4. договор, который стоит во всех последних проведённых документах этого поставщика, введённых бухгалтером;
  5. единственный договор поставщика — подставляется, но запись ждёт, пока его проверят (--accept-warning contract-substituted).

Если ничего не подошло, ЭСФ не записывается, а в отчёте перечислены все договоры поставщика с их ссылками — выбор записывают и запускают импорт снова.

Если в ЭСФ договор не указан и договор у контрагента один — берут его. Если несколько — считают, какой из них эта база уже использовала в проведённых документах этого контрагента, и берут его; если история молчит или расходится — самую свежую по дате карточку. Пустой договор не нейтрален: там, где счёт расчётов использует «Договоры» как субконто, 1С откажется проводить документ, а через OData откажет молча.

Никогда не берут содержание. Даты, суммы, номера, количество, цены, НДС и первичный документ — всё из текущей ЭСФ. Скопированная из шаблона сумма даёт достоверно выглядящий документ о поставке, которой не было.

Как выглядит «стабильность» на практике: в изученной базе каждая проведённая цепочка использовала один и тот же склад, один счёт расчётов, один счёт авансов и одного ответственного — при том что у каждого поставщика был свой договор, а одно поле (УчитыватьКПН) переключилось для всех ЭСФ начиная с определённого дня. То есть: настройки стабильны в пределах базы, договоры — в пределах поставщика, а у всего, что менялось в течение года, дату перехода нужно установить, а не угадать.

Что импорт заполняет по правилу, а не спрашивает

Поле, которое все проведённые документы заполняют, но по-разному, — иногда настоящий выбор, а иногда следствие того, что уже известно. Импорт заполняет только второе, и пробный запуск называет правило (derived-by-rule):

  • курс и кратность — из проведённых документов в той же валюте, если они все согласны;
  • копия другого поля — поле, которое во всех проведённых документах равно контрагенту, договору или дате того же документа («Поставщик_Key», «ДатаОборота» в строках), заполняется из этого поля; оно заменяет и значение, скопированное из истории, — в базе с историей одного поставщика это был бы прежний поставщик;
  • «УчитыватьНДС» для ЭСФ без НДС — включён, со ставкой «Без НДС» из этой базы, без вопроса: сумма документа от этого не меняется, а включённый флаг никогда не выводит документ из учёта НДС. Исключение одно — поставщик, у которого все его проведённые счета-фактуры без НДС (не меньше трёх) записаны с выключенным флагом: тогда как у поставщика. Ставка «Без НДС» не угадывается: она берётся из строки ЭСФ, esf.no_vat_rate_ref, таблицы vat_rates в mapping.json, единственного элемента справочника с таким названием или из проведённых строк без НДС; если ничего не отвечает — эта ЭСФ отклоняется с vat-rate-unresolved. Решается при создании, потому что потом 1С его не меняет;
  • поставщик без своих проведённых документов — счёт расчётов, счёт авансов и «СобытиеОС» из двадцати последних проведённых документов той же операции, только если все двадцать согласны.

То, что правило не решает, по-прежнему попадает в отчёт — со всеми значениями, которые встречались в базе, и их количеством, чтобы хватило одного ответа.

Образец — цепочка другого поставщика

Поставщик без своей проведённой цепочки берёт настройки из цепочки другого поставщика. Запись останавливается (template-other-supplier) только если поле, от которого зависит проведение, пришло из этой цепочки и больше ниоткуда. Импорт собирает документы второй раз без образца и сравнивает: счета расчётов и авансов, «СобытиеОС», «УчитыватьНДС», «СуммаВключаетНДС», договор, счета, аналитику и НДС в строках. Если всё это задано правилом, историей базы или записанным решением, отчёт только отмечает чужой образец и называет источник каждого поля — --accept-warning не нужен. Иначе предупреждение называет поля, взятые только у другого поставщика; сверьте их с документами этого поставщика до записи.

До 18.09.2026 «СуммаВключаетНДС» (пишет база суммы с налогом или без) не могло пройти эту проверку само по себе, даже когда вся организация была единогласна: самый обычный ответ, False (без налога), читался так же, как «база вообще не заполняет это поле», и поэтому не учитывался ни в одном выводе настроек из истории. Исправлено — теперь поле измеряется так же, как любая другая настройка базы.

Даты и номера берут из конкретных мест

ПолеИсточник
Дата полученного счёта-фактурыдата ЭСФ
Номер входящего счёта-фактурыНомер ЭСФ — см. ниже
Дата поступлениядата оборота ЭСФ, а не дата ЭСФ
Номер и дата первичного документа поступлениянакладная или акт, не ЭСФ

У ЭСФ два номера, и «номер ЭСФ» — только один из них. Номер — тот, под которым поставщик выписал счёт-фактуру, и именно его сверяет бухгалтер. РегистрационныйНомер — идентификатор документа в портале, длинный машинный ключ для поиска и защиты от дублей. В «Номер входящего документа» полученного счёта-фактуры идёт Номер.

Оба — непустые строки, похожие на номер счёта-фактуры, поэтому подстановка не того даёт документ, который не сходится ни с чем на бумаге и который изнутри 1С не опровергнуть. Перечитывайте и сравнивайте именно с Номер.

Ни один из них не подставляйте вместо номера накладной и не заменяйте техническую пустую дату (0001-01-01) догадкой. В реальной базе это значение законно несёт большинство поступлений: дата накладной просто не была известна.

Товар или услуга: решает карточка номенклатуры, построчно

1С держит покупки в двух табличных частях — «Товары» и «Услуги», — потому что они проводятся по-разному: товарная строка двигает склад, строка услуги идёт сразу на затраты. В какую часть попадает строка, определяется флагом Услуга в карточке разрешённой номенклатуры, по каждой строке отдельно.

Это никогда не настройка базы и никогда не наследуется от шаблона. Однажды её выставили — для клиента, чья база продаёт только услуги, — и за несколько часов товары всех остальных клиентов начали разноситься как услуги, притом что бухгалтер совершенно верно писала об этом в чат и ничего не менялось: указание было в чате, а ошибка в конфигурационном файле. Настройка не может знать, что за строка перед ней. Карточка — может. Тем же правилом определяется всё остальное: счета и то, означает ли количество 0 услугу «за всё» или возврат, который нужно показать человеку.

ЭСФ, где есть и товары, и услуги, становится двумя поступлениями под одним счётом-фактурой. «ВидОперации» — одно значение в шапке документа, поэтому одно поступление не может содержать и то, и другое. Импорт создаёт поступление товаров и поступление услуг и один полученный счёт-фактуру, в «ДокументыОснования» которого указаны оба (ссылка «СчетФактура» в ЭСФ одна, поэтому и счёт-фактура один). Отчёт сообщает об этом предупреждением esf-split; перед проведением сверьте оба поступления с ЭСФ. Проверка после записи сверяет каждое поступление с его собственными строками, а счёт-фактуру — со всей ЭСФ.

Деление происходит, только если у каждой строки известен вид: она нашла карточку номенклатуры, либо этому прогону разрешено её создать (см. «Карточка, которую создаст этот прогон, — не "нерешённое поле"» выше). Вид строки читается из карточки, и строка без карточки и без разрешения — это неизвестный вид, тогда ЭСФ отклоняется. База, которая хочет отклонять любую смешанную ЭСФ и делить её вручную, указывает "split_mixed": false в разделе esf файла mapping.json. До версии кита 1.18.2 верно разделённая цепочка получала «verification FAILED»: первое поступление сверялось со всеми строками ЭСФ.

Собственный вид операции базы сохраняется. Если esf.copy_from_template содержит «ВидОперации», поступление получает вид операции цепочки-образца — некоторые базы оформляют любую закупку как «ПокупкаКомиссия», — и проверка после записи ожидает именно его. Не наследуется только вид, который mapping объявляет для другого рода строк («Услуги» на товарах, «Товары» на услугах): тогда вид определяется по строкам, как описано выше. До версии кита 1.18.1 такая цепочка записывалась верно и всё равно получала отметку «verification FAILED».

Если товарная строка уже уехала в услуги: 1С не даёт сменить вид уже созданного документа через PATCH. Лечится только удалением всей непроведённой цепочки и повторным созданием — и это безопасно, только пока ничего не проведено.

Аналитика строк поступления: что 1С не выведет сама и о чём не предупредит

Это те поля, которые бухгалтер проверяет первыми и которые скрипт чаще всего оставляет пустыми. Каждое из них спокойно сохраняется пустым или неверным — документ сходится по сумме и в списке выглядит готовым, — поэтому проверить их можно только перечитыванием строки.

ПолеЧто этоОткуда берётся
НДСВидОборотавид оборота, напр. «Общий»правило базы, на всю базу
НДСВидПоступления«Товары, приобретенные с НДС» / «…без НДС»по строке — по наличию НДС в ней
СчетЗатратБУ / СчетЗатратНУсчёт затрат, напр. 7210правило базы, на всю базу
СубконтоЗатратБУ1 / НУ1статья затратпо строке — по проведённым поступлениям того же поставщика
СубконтоЗатратБУ2подразделениеправило базы, на всю базу
СчетУчетаНДСсчёт учёта НДСправило базы, на всю базу

Три вещи стоит сказать отдельно — каждая уже уходила в базу неверно:

  • НДСВидПоступления определяется по строке, по НДС. Строка с НДС — «приобретенные с НДС», без НДС — соответственно. Перепутанные местами дают неверную декларацию по НДС при верной сумме документа, поэтому дальше по цепочке этого никто не поймает.
  • Статья затрат — на услугу, а не на базу. Одна и та же база относит исследование и аренду на разные статьи. Берите её из проведённых поступлений того же поставщика по тому же товару, а если база так и не решала — оставьте бухгалтеру. Выдуманная статья хуже пустой.
  • Субконто* — полиморфные ссылки, им нужен спутник _Type (StandardODATA.Catalog_СтатьиЗатрат, …Catalog_ПодразделенияОрганизаций). Запишете одно значение — 1С сохранит Undefined: поле выглядит заполненным везде, кроме экрана бухгалтера, где оно пустое.

Берите это из строки проверенной проведённой цепочки, а не из её шапки. Это реквизиты табличной части; в документе 1С их нет, и код, который ищет их там, ничего не находит и молча пишет нулевой GUID.

Арифметика — построчно, до записи

Проверять до копейки: по каждой строке сумму без налогов, НДС и с НДС; итоги документа; равенство «без НДС + НДС = с НДС»; равенство суммы строк сумме документа.

Ставка НДС определяется по строке текущей ЭСФ. Не по поставщику и никогда копированием из старого документа. Поставщики меняют ставки посреди отношений, и расхождение суммы НДС между счётом-фактурой и поступлением — ровно признак того, что где-то построчное разрешение пропустили. Необъяснимое расхождение — стоп-условие, а не примечание об округлении.

Затем — сумма, которую 1С действительно сохранит, и до записи. 1С пересчитывает «СуммаДокумента» по строкам и двум флагам шапки: при выключенном «УчитыватьНДС» НДС отбрасывается, при выключенном «СуммаВключаетНДС» НДС добавляется сверх строк. ЭСФ с НДС, записанная по образцу без учёта НДС, сохраняется как сумма без НДС, и когда документ уже в 1С, этот флаг не исправить. С версии кита 1.19.0 импорт считает эту сумму для каждого документа, который собирается отправить, — и в пробном запуске тоже — и отклоняет ЭСФ с esf-total-mismatch, если она не равна сумме с НДС; в сообщении названы образец, оба флага, сумма без НДС, НДС и ожидаемая сумма. Не обходите это: исправьте выбор образца или mapping, повторите пробный запуск и только потом --apply.

Номенклатура: разрешать, а не выдумывать

По каждой строке, строго по порядку:

  1. непустая ссылка номенклатуры в самой ЭСФ, если карточка существует и активна;
  2. точный внешний идентификатор (GTIN, код нацкаталога), ведущий ровно на одну активную карточку;
  3. однозначное точное историческое соответствие исходного наименования у того же поставщика;
  4. однозначное точное соответствие действующей карточке справочника;
  5. создание новой карточки — только с явного разрешения пользователя.

Похожее название не идентификатор. Доза, концентрация, объём, количество в упаковке, лекарственная форма, бренд и производитель должны совпадать. Две карточки с одним идентификатором или одинаковым точным названием — остановиться и спросить, если в ЭСФ нет подтверждённой ссылки.

Если карточку всё-таки создаёте, с разрешения: сначала ещё раз проверьте дубли по внешнему идентификатору и точному названию, используйте точное исходное наименование, сохраните GTIN / ТН ВЭД / полное наименование, определите базовую единицу по коду ЭСФ, поставьте ставку НДС из текущей строки, клонируйте только учётные поля подходящей карточки той же базы, уберите серверные поля, укажите в комментарии регистрационный номер исходной ЭСФ и перечитайте карточку, проверив имя, единицу, НДС и активность.

Один и тот же GTIN под слегка разными названиями — один товар. Используйте существующую карточку.

Карточка, которую создаст этот прогон, — не «нерешённое поле»

При запуске с --create-nomenclature строка, дошедшая до шага 5, получает не созданную сразу карточку, а запланированную: сама запись в справочник происходит позже в этом же прогоне, когда решены все остальные вопросы по ЭСФ, поэтому сухой прогон всегда только планирует и ничего не пишет. До 2026-09-18 проверка готовности (см. «"Не проведутся как есть"» ниже) этого не знала и предлагала выбрать одну из уже существующих карточек базы — то есть заново отвечать на вопрос, который --create-nomenclature уже решил. Это исправлено: строка, для которой этот прогон разрешено и запланировано создать карточку, отмечается как решённая — «карточка будет создана в этом прогоне» — и только эта строка. Без флага, или для строки, для которой ничего не запланировано, поле по-прежнему держит цепочку так же, как и раньше.

Это же можно записать явно, построчно: {"source_name": "...", "unit_ref": "...", "create": {"description": "..."}} — «ни одна карточка этой строке не подходит, создайте новую» — вместо того чтобы дожидаться, пока автоматическая лестница выше сама не дойдёт до шага 5. description необязателен и, если указан, переопределяет название новой карточки (иначе берётся собственное имя строки ЭСФ). Создание по-прежнему требует --create-nomenclature и проходит ту же проверку дублей и то же контрольное чтение, что и любая другая создаваемая этим прогоном карточка — запись лишь говорит, что решение уже принято человеком, и прогону не нужно сначала неудачно пройти автоматическую лестницу, чтобы узнать это.

Запланированная карточка решает и то, можно ли разделить ЭСФ, смешивающую товары и услуги (см. ниже). До 2026-09-18 проверка деления задавала тот же вопрос, что и абзац выше уже чинил — «есть ли у строки карточка прямо сейчас» — но для другой цели, и строка, карточку которой этот прогон запланировал, но ещё не записал, по-прежнему читалась как нерешённая. Сухой прогон держал такую цепочку как неделимую, а следующий же --apply, где карточка создаётся раньше, чем эта проверка выполняется, делил её и записывал без единого предупреждения. Теперь оба прогона согласны: запланированная карточка — известный вид на обоих, а строка, для которой ничего не запланировано, держит деление одинаково на обоих.

До 2026-09-19 та же смешанная форма — запланированная карточка на ЭСФ, делящейся на поступление товаров и поступление услуг — всё ещё могла разойтись между сухим прогоном и --apply, по двум наложившимся друг на друга причинам. Разделение по товарам/услугам перенумеровывает позицию строки внутри её собственной секции (чтобы второй документ не начинал счёт со «строки 3»), а проверка, которая исключает запланированную карточку, всё ещё сверялась со СТАРОЙ позицией — и исключение молча переставало срабатывать в момент разделения цепочки. Отдельно, поставщик с очень короткой историей проведённых документов мог заставить базу выглядеть так, будто она всегда использует ОДИН и тот же товар для каждой строки — что никогда не верно для собственной номенклатуры строки — и это ложное «всегда одно и то же» на день скрыло первую ошибку. Обе исправлены, и теперь автоматическая проверка гоняет сухой прогон и --apply подряд, на одних и тех же данных, по нескольким таким формам, так что они больше не могут снова тихо разойтись.

Единицы измерения

  1. активная единица, указанная в ЭСФ;
  2. точное однозначное совпадение ЕдиницаИзмеренияКод со справочником единиц этой базы;
  3. однозначная единица подтверждённой номенклатуры или истории этого товара.

Текстовое название единицы регулярно пустое или ошибочное; код важнее, но только при точном однозначном совпадении. Один код на несколько активных единиц или отсутствие кода — остановиться и спросить. Это встречается часто: неполное распознавание единиц скорее норма, чем исключение.

Заполнение единиц в ЭСФ, которая уже лежит в базе

Правила выше — для цепочки, которую вы создаёте. ЭСФ, пришедшая с портала месяцы назад и лежащая с пустыми «Ед. изм.» и «Ед. изм. остатков», — другая задача: провести её так нельзя, а заполнять эти строки руками по всему месяцу счетов — работа, которую к сороковой строке никто не делает внимательно.

Это делает fill-esf-units.py. Правило ниже принадлежит той бухгалтерской практике, которая им пользуется — подтверждено их администратором 4 августа 2026 года, — поэтому целиком лежит в конфигурации mapping.json под esf.units_fill, а не в коде:

  1. Базовая единица из карточки номенклатуры важнее всего. Это то, что база уже решила про этот товар, и оно старше любой надписи на упаковке.
  2. Если карточка молчит — готовая фармацевтическая упаковка это шт: таблетки, капсулы, драже, ампулы, флаконы, тубы и всё с мг / мл / № в названии. Продаётся упаковка, а не её содержимое. Строка «Меновазин 40 мл» — это один флакон, а не сорок миллилитров.
  3. Весовой товар и продажу на розлив не трогать, даже если название подходит и под правило 2.
  4. Коэффициент пересчёта не 1 — строку не трогать. Единицы тогда разные меры, и связь между ними не вам выводить. При коэффициенте 1 они обязаны совпадать, и payload, где они разошлись, отклоняется.
  5. Больше ничего не угадывать. Строка, о которой молчит карточка и которую не определяет название, уходит в список ручной проверки с причиной.

Правило 5 — главное, и поэтому отчёт всегда состоит из трёх списков: заполнено (с источником каждой единицы), уже было заполнено, требует человека. Прогон, который заполнил всё и не отметил ничего, либо угадал, либо ему повезло, и по результату это не различить. Записанная единица неотличима от проверенной, а меняет она смысл каждого количества в строке.

Две механические ловушки, обе удаляют данные молча:

  • Передавайте табличную часть целиком. Частичная часть заменяет часть — строки, которых нет в payload, удаляются. «Отправим только изменённое» уничтожает остаток счёта.
  • Двигаться могут только ссылка на товар и две единицы. Количество, цена, сумма и НДС — цифры поставщика. Скрипт доказывает это построчным сравнением полей до записи, а не намерением: payload, собранный из перечитанной строки, несёт все поля.

Это запись в документ, который кит не создавал, поэтому у неё та же защита, что у link_esf_to_invoice: ЭСФ должна принадлежать закреплённой организации, а суммы и связь со счётом-фактурой перечитываются после записи, чтобы доказать, что правка не задела ничего другого. Ничего не проводится.

Защита от дублей

ЭСФ опознаётся по совокупности: Ref_Key, регистрационный номер, поставщик, организация, номер и дата, дата оборота, сумма, состав строк. Перед созданием убедитесь: ЭСФ входящая, активная, относится к целевой организации; поле СчетФактура пустое; регистрационный номер встречается один раз; нет счёта-фактуры с тем же поставщиком, входящим номером, датой и суммой; нет поступления по той же накладной, поставщику, дате и сумме; нет цепочки с маркером этой ЭСФ.

Одинаковый номер поставщика не всегда дубль. Если старый и новый документы почти совпадают, но регистрационные номера различаются, это повторная или исправленная ЭСФ — отдельное решение, а не пропуск.

Запись цепочки

  1. создать полностью заполненное непроведённое поступление;
  2. перечитать его и взять Ref_Key;
  3. создать непроведённый полученный счёт-фактуру с основной ссылкой и строкой ДокументыОснования на поступление;
  4. перечитать счёт-фактуру;
  5. записать обратную ссылку поступления на счёт-фактуру;
  6. записать ссылку ЭСФ на счёт-фактуру;
  7. перечитать все три документа.

Все три остаются Posted=false. Каждый черновик несёт технический комментарий с регистрационным номером исходной ЭСФ, а скрипт идемпотентен: повторный запуск находит уже созданные карточки и документы, а не создаёт новые.

Этот комментарий обязателен. В нём лежит якорь, по которому следующий запуск узнаёт цепочку, прерванную после шага 1, поэтому пустой комментарий отклоняется ещё до чтения ЭСФ (no-import-anchor). Текст берётся из esf.comment в mapping.json и касается только документов ЭСФ. Если в базе комментарии для банковских документов выключены (documents.write_comment: false), а esf.comment не задан, задайте его, например «Создано из входящей ЭСФ. Требует проверки бухгалтером.». Не включайте комментарии для всей базы ради этого.

Проверять — чтением, отдельно

Успешный POST не доказательство. Отдельным чтением подтвердите: одна ЭСФ, один счёт-фактура, одно поступление; все три на одной организации и одном поставщике; одинаковый договор у счёта-фактуры и поступления; ЭСФ ссылается на нужный счёт-фактуру; счёт-фактура и поступление связаны в обе стороны; число строк совпадает с ЭСФ; в каждой строке заполнены номенклатура и единица; количество, цена, сумма, ставка и НДС совпадают с источником; итоги документов совпадают с ЭСФ; даты и номера взяты из правильных источников; ничего не проведено и не помечено на удаление.

Проведение

Только по отдельной прямой команде пользователя. Сначала перечитайте всю цепочку, затем проводите поступление → счёт-фактуру → ЭСФ штатным действием OData Post(), пропуская уже проведённое. После — независимо подтвердите, что все три Posted=true, все связи сохранились, суммы и число строк не изменились, дублей и пометок удаления не появилось.

Сам по себе Posted=true ничего не доказывает — проводите через scripts/1c/odata/post-documents.py: он считает документ проведённым, только если в регистрах появилось движение, а если движения нет — снимает флаг.

Документ «проведён», а движений нет — его чинят, а не перепроводят: повторное проведение с теми же пустыми полями ничего не меняет. Запустите python3 scripts/1c/esf/repair-esf-posting.py <набор> <Ref_Key> --mapping … --credentials … (только чтение) и покажите пользователю, что он заполнит; с его согласия — ещё раз с --apply --confirm <дайджест>. Скрипт снимает ложный флаг, заполняет поля, которые есть во всех недавних работающих документах той же операции (по тем же правилам, что и импорт), проводит и доказывает движение — по одному документу за запуск. Если он отказал — передайте причину: поле с несколькими вариантами решает бухгалтер, а поле, которое 1С принимает только при создании, — это замена цепочки (ниже).

Замена цепочки, которую нельзя исправить

Часть полей счёта-фактуры принимается только при создании документа — «КурсВзаиморасчетов», «КратностьВзаиморасчетов», «УчитыватьНДС», — и цепочку с таким неверным полем или с неверной суммой не правят, а заменяют. Не пишите для этого разовый скрипт. Самодельная замена, которая при каждой неудачной попытке создавала новый счёт-фактуру, оставила у одной ЭСФ пять живых счетов-фактур, после чего 1С отказывала в любой записи в эту цепочку. Используйте supersede-esf.py:

  1. python3 scripts/1c/esf/supersede-esf.py --registration <ЭСФ> --replace-invoice <№ счёта-фактуры> — сухой прогон. Он называет цепочку, на которой стоит ЭСФ, и, пока она живая, говорит бухгалтеру, что сделать в 1С: отменить проведение, если документ проведён, и пометить на удаление счёт-фактуру и её поступление (или поступления). Набор этого сам не делает.
  2. Когда бухгалтер это сделала, запустите тот же сухой прогон ещё раз. Теперь он показывает новую цепочку и печатает --apply --confirm <дайджест>. Дайджест покрывает ЭСФ, заменяемую цепочку и все данные для записи, поэтому годится только для того, что она прочитала.
  3. Запустите с --apply --confirm <дайджест>. Скрипт создаёт новую непроведённую цепочку тем же кодом, что и импорт, переносит ссылку ЭСФ с помеченного счёта-фактуры на новый и перечитывает все три документа.
  4. Бухгалтер проверяет и проводит новую цепочку, а помеченные документы удаляет, когда сочтёт нужным.

Старая цепочка помечается до того, как появится новая, поэтому не бывает момента, когда у одной ЭСФ две живые цепочки. Прерванный запуск завершают, запустив его ещё раз: ничего существующего второй раз не создаётся, а две живые копии одной роли — отказ, а не выбор. За один запуск заменяется одна цепочка и только та, на которую ЭСФ действительно ссылается. Код выхода: 0 — готово или делать нечего, 1 — отказ, ожидание бухгалтера или нет подтверждения.

Пакеты, и с каких ЭСФ начинается пакет

По умолчанию — текущий период, начиная с самых свежих. Бухгалтер, который просит «первые три», имеет в виду те три, что мешают ему сегодня, а не три самые старые строки реестра, уходящего на годы назад. Сортировка неразнесённых по возрастанию и взятие начала списка — это ровно тот способ, которым запрос про этот год превращается в документы, записанные в период, закрытый и проверенный два года назад; потом их приходится искать и удалять по одному.

Определите выборку до того, как что-либо запишете:

  • берите текущий год, если пользователь не назвал период;
  • внутри него сортируйте по дате оборота от свежих к старым, затем по дате ЭСФ и номеру;
  • назовите диапазон дат в том же сообщении, где предлагаете пакет — «3 ЭСФ, 12.07.2026–04.08.2026». Неверный период виден бухгалтеру с одного взгляда и совершенно незаметен внутри регистрационного номера;
  • всё, что вне текущего периода, включается только по явному запросу. Спросите до того, как включить, и никогда не позволяйте голому «первые N» дотянуться до закрытого года.

Старые неразнесённые ЭСФ — это отдельный вопрос, а не очередь, которую разбирают с головы. ЭСФ, оставшаяся несвязанной в базе, которая нормально закрывала периоды, гораздо вероятнее заброшена, заменена или исправлена другим документом, чем ждёт разноски, — и её тихая запись заново открывает уже сданный период.

Дальше по самому пакету: исключить уже связанное; отложить старые аномальные ЭСФ и вероятные повторные выгрузки; взять N уникальных документов; проанализировать всю партию и сделать один сухой прогон; создавать номенклатуру с общей защитой по GTIN, чтобы один товар не создался дважды по двум ЭСФ партии; создавать и проверять каждую цепочку отдельно; проводить только после отдельного подтверждения.

Один неверный флаг НДС — три разных симптома

УчитыватьНДС решает, учитывает ли документ НДС вообще. Ошибка в нём не вызывает жалоб 1С — она даёт одно из трёх, и выглядят они как три несвязанные проблемы:

что виднокогда
документ сохранён на сумму без НДС вместо суммы с НДСпри импорте
Posted=true при нуле движений регистровпри проведении, часами позже
пересозданный документ повторяет ту же неверную суммупри исправлении

Третий симптом и выдаёт, что дело никогда не было в проведении: писать в налоговые регистры нечего, поэтому 1С ставит флаг и не формирует ничего.

Отсюда три правила:

  • Решает исходная ЭСФ, а не шаблон. Если в ЭСФ есть НДС, УчитыватьНДС ставится true независимо от шаблона. Совпадение профиля НДС у шаблона предпочтительно, но это предпочтение, а не гарантия: у поставщика может не быть в базе ни одной цепочки с НДС.
  • Признак читается в ШАПКЕ, а не в строках. Проведённая цепочка может нести СуммаНДС в строках, а в шапке «Не учитывать НДС» — 1С хранит и то и другое. Выбор шаблона по строкам приводит именно к такому шаблону.
  • СуммаВключаетНДС — другой вопрос. Он говорит, пишет ли база суммы с налогом или без. Оба варианта верны, суммы строк считаются под него, и он остаётся от шаблона. Не форсируйте его.

Часть полей пишется только при создании

УчитыватьНДС, ВидУчетаНУ_Key и УчитыватьКПН принимаются при создании документа и отклоняются при PATCH — и через OData, и через диалог «Цена и валюта» в самом веб-клиенте 1С.

Поэтому исправление неверного значения — это пересоздание цепочки, а не правка, и делается оно через supersede-esf.py (раздел «Замена цепочки, которую нельзя исправить»), а не вручную. Отказ корректора править проведённый документ — не препятствие, которое надо обойти: он сообщает, что правка всё равно не записалась бы.

И не делайте отсюда вывод «нужен клиент 1С». Он не помогает: штатная команда «Провести», нажатая руками на таком документе, даёт те же ноль движений.

«Не проведутся как есть» — это говорят при импорте, а не через неделю

Каждый прогон, в том числе сухой, сравнивает черновики, которые собирается создать, с проведёнными документами самого этого поставщика (и только если их меньше пяти — со всеми проведёнными документами организации). Всё, что база на своих документах заполняет, а мы оставляем пустым, попадает отдельной таблицей в начало отчёта: документ, поле, доказательство («17 из 20») и что с этим делать.

Таблица начинается там, где заканчивается подстановка по истории. То, что база заполняет на каждом проведённом документе, импорт уже подставил сам (см. выше). В таблицу попадает то, что заполняет большинство — и именно это подстановка сознательно не трогает: «почти всегда» — это вопрос о том, какой это документ, и база сама ответила на него по-разному.

Дальше вопрос делится надвое:

  • Заполнимо — когда база это поле заполняет, там всегда одно и то же значение; оно названо, и исправление занимает полминуты в 1С.
  • Решение — те документы, где поле заполнено, расходятся. Ничего не выдумывается: подставить частое значит подставить чужое.

И поперёк обоих — можно ли вообще записать поле после создания документа. Если нет (см. раздел выше), в отчёте написано «удалить цепочку и импортировать заново», а не «проставить»: никакой PATCH это поле не сдвинет.

Исключение — «Номенклатура_Key» строки, для которой этот прогон уже запланировал и получил разрешение создать карточку (--create-nomenclature, см. «Номенклатура: разрешать, а не выдумывать» выше): в таблицу оно не попадает, а в отчёте отмечено отдельно — «карточка будет создана в этом прогоне».

Предупреждение — не отказ. Черновики всё равно создаются: бухгалтер может как раз собираться заполнить поле руками, а прогон, останавливающий из-за этого месяц, просто приучает работать в обход. Сигнал — таблица в отчёте и код возврата: 0 — чисто, 1 — заблокировано и ничего не записано, 3 — записано, и часть как есть не проведётся.

Количество 0 в услуге — не аномалия

В ЭСФ на услугу количество сплошь и рядом равно нулю: считать нечего. 1С при этом нужно количество, чтобы вывести цену, поэтому для строки, карточка которой помечена как услуга, ноль читается как единица. На строке товара так делать нельзя: там ноль — это либо возврат, либо ошибка, и единица придумывает поставку, которой не было. Правило отключается настройкой zero_service_quantity_as_one в маппинге базы.

Стоп-условия

Остановиться до записи, если: не определена целевая база или организация; найден дубль регистрации или существующая цепочка; любая ЭСФ выбранного пакета выходит за текущий период, а пользователь этот период не называл; не определены поставщик, договор, склад, счета или вид операции; не сходится арифметика; неоднозначны номенклатура или единица; нужно создать элемент справочника без разрешения; ставка НДС не сопоставлена со справочником; документ по товарам собирают по шаблону услуг или наоборот; нельзя доказать все три связи.

Чистый сухой прогон, а затем удержанный --apply — это не баг

Первая ЭСФ от поставщика без собственной проведённой цепочки и без договора, уже известного этой базе, покажет предупреждения contract-unresolved и/или template-other-supplier. Обычный --apply (без --accept-warnings) удерживает запись именно по этой причине — прочитайте предупреждения, проверьте заимствованные счета и профиль НДС на соответствие тому, что должно быть у документов этого поставщика, и перезапустите с --accept-warnings (или конкретными --accept-warning <код> для каждого). Это не переодетый required-unresolved, и это не тот класс дефекта, для предотвращения которого существует флаг --create-nomenclature: строка, которую этот прогон разрешено и вот-вот создаст карточкой в справочнике, уже исключена из required-unresolved — одинаково на сухом прогоне и на --apply, сколько бы разных значений номенклатуры ни несла проведённая история этой базы (1c-esf-import-and-posting.md §0 #32).

Куда складывать знания об этом

Эта страница и есть регламент. Не копируйте её в рабочие пространства. Вписанная вручную в knowledge/ каждого пространства, она превращается в N копий, которые расходятся и которые нельзя исправить вместе. Ставьте ссылку; /help/1c-incoming-esf-import.md отдаёт исходный markdown.

Что действительно место в knowledge/local/ пространства: подтверждённые договоры и настройки поставщиков этой базы, её устойчивая структура документов, локальные исключения, решения пользователя о создании справочников и проведении, номера уже созданных документов. Никогда — названия компаний, GUID, БИН/ИИН, адреса баз и банковские реквизиты одной базы в общих заметках другого пространства.