Отчёт в хранилище не сходится с 1С: какие правки теряет выгрузка и как сверять по дням
Иван Недомолков · Жарияланды:
Типичная жалоба звучит так: выгрузка из 1С в хранилище каждую ночь проходит без ошибок, в журнале пусто, а бухгалтер приносит отчёт за март, где остаток не совпадает с 1С. Ошибок нет, потому что выгрузка сделала ровно то, что умеет: перечитала последние две недели. Документ, который поправили в марте, в эти две недели не попал.
Ниже разбор по типам правок. Для каждой правки сказано, что с ней делает обычная выгрузка “окном”, какая проверка её ловит и сколько эта проверка стоит. Все числа сняты на тестовых базах Управления торговлей 11.5 и Бухгалтерии для Казахстана 3.0, платформа 8.3.27.
Короткий ответ
| Что сделали в 1С | Окно 14 дней | Сравнение числа строк | Паспорт дня | Версии документов |
|---|---|---|---|---|
| Перепровели вчерашний документ | видит | видит, если строк стало другое число | видит | видит |
| Перенесли документ на полгода назад | удаляет строку в старой дате, новую не видит | видит только в итоге за всё время | видит обе даты | видит обе даты |
| Поменяли сумму в старом документе | не видит | не видит | видит | видит |
| Поменяли товар или склад, сумма та же | не видит | не видит | не видит | видит |
| Записали набор записей кодом мимо документа | видит, только если день в окне | видит, если поменялось число строк | видит, если поменялись строки или суммы | не видит |
Последняя строка таблицы и есть настоящая дыра, к ней вернёмся в конце. Всё остальное закрывается двумя дешёвыми проверками поверх окна: паспортом дня и версиями документов. И отдельно стоит вопрос, на который не отвечает ни одна из них: дошло ли выгруженное до приёмника целиком.
Как выглядит пойманная правка
На тестовой Бухгалтерии для Казахстана поступление на 180 000 перенесли с 3 августа на 15 марта. Выгрузка с окном в 14 дней этого не увидела бы вовсе: ни август, ни март в окно не попадают. Проверка по дням нашла обе даты: в августе было две проводки на 194 000, стала одна на 14 000, в марте не было ничего, появилась проводка на 180 000. Версии документа подтвердили то же самое с другой стороны: дата документа 03.08.2026 стала 15.03.2026.

Весь прогон занял 0,2 секунды на базе с 1 627 проводками за 53 дня. Число строк первой выгрузки сверили с таблицей проводок самой базы в SQL Server, мимо 1С: 1 627 и там, и там.
Почему окно теряет правку в старом периоде
Окно это самая частая схема инкрементальной выгрузки: каждый прогон заново читает последние N дней, вставляет новое, обновляет изменённое, удаляет пропавшее. Всё, что старше N дней, выгрузка считает неизменным.
С переносом документа окно поступает хуже, чем кажется. Сентябрьскую половину правки оно отрабатывает честно: строки в сентябре больше нет, значит её надо удалить в приёмнике. Мартовскую половину не видит. В итоге строки нет ни в сентябре, ни в марте, и журнал выгрузки при этом чистый. На тестовой УТ это воспроизводится одним документом: перенос с 25.09 на 25.03 при окне в 14 дней.
Расширить окно до полугода можно, но это лечит только длину. Правка на семь месяцев назад опять пройдёт мимо, а перечитывать каждую ночь всю историю дорого.
Число строк не ловит правку внутри строки
Первое, что обычно ставят после окна, это сравнение количества строк: сколько в 1С, столько в приёмнике. Проверка полезная, но ловит только потерю или дубль строки.
Пример с тестовой УТ: в приёмнике испортили одну строку за 20 июня, количество 2 стало 3. Документы там крупные, за этот день в регистре “Товары на складах” 500 строк. В 1С 500 и в приёмнике 500. А сумма движений за день разная: в 1С -1 210, в приёмнике -1 211 (расход идёт с минусом, отсюда знак).
Паспорт дня: проверка всей истории за секунды
Паспорт дня это несколько чисел на каждую дату: сколько строк движений и какая сумма каждого ресурса. После выгрузки паспорт сохраняется. Следующий прогон строит его заново по всей истории и сравнивает. Разошёлся день, значит этот день целиком уходит в приёмник заново, даже если это март.
Строится паспорт одним запросом с группировкой по дню. Для регистра остатков приход берётся плюсом, расход минусом, иначе строка, переехавшая из прихода в расход, сумму дня не изменит:
ВЫБРАТЬ
НАЧАЛОПЕРИОДА(Т.Период, ДЕНЬ) КАК День,
КОЛИЧЕСТВО(*) КАК Строк,
СУММА(ВЫБОР
КОГДА Т.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход)
ТОГДА Т.ВНаличии
ИНАЧЕ -Т.ВНаличии
КОНЕЦ) КАК ВНаличии
ИЗ
РегистрНакопления.ТоварыНаСкладах КАК Т
ГДЕ
Т.Период >= &НачалоИстории
И Т.Активность
СГРУППИРОВАТЬ ПО
НАЧАЛОПЕРИОДА(Т.Период, ДЕНЬ)
Правило знака зависит от вида регистра:
| Регистр | Как суммировать ресурсы |
|---|---|
| накопления, остатки | приход плюсом, расход минусом |
| накопления, обороты | как есть, вида движения нет |
| бухгалтерии с корреспонденцией | без знака: балансовый ресурс один на проводку, небалансовые раздельно по дебету и кредиту |
| бухгалтерии без корреспонденции | дебет плюсом, кредит минусом |
Для регистра бухгалтерии паспорт берётся из основной таблицы, а не из виртуальной ДвиженияССубконто: субконто для сумм не нужны, а соединение лишнее. Если выгружаются только деньги, в запрос добавляется отбор по счетам.
Сколько это стоит. Замер на синтетике в регистре “Движения денежных средств”, три прогона подряд, восемь серий в разные дни:
| Строк в регистре | Паспорт всей истории | Версии документов |
|---|---|---|
| 300 000 | 0,25-0,37 с | 0,55-0,66 с (3 000 документов) |
| 10 000 000 | 4,0-8,6 с | 4,8-8,5 с (12 700 документов) |
Машина тестовая: 16 ГБ памяти, сервер 1С и SQL Server вместе, свободно 0,6-4 ГБ. Первый проход после простоя, пока таблица не в кэше СУБД, шёл 35 секунд. Когда машину грузили соседние процессы, паспорт занимал 20-22 секунды. Индекс паспорту не помогает: это полный проход по таблице регистра, и время растёт с объёмом. Для ночного прогона даже 35 секунд не деньги, поэтому паспорт имеет смысл считать по всей истории каждый раз.
Версии документов: правка, которая не меняет сумм
Против паспорта есть простой контрпример. В старой строке меняют товар на другой, количество и дату оставляют. Число строк дня то же, сумма та же, паспорт зелёный, а в приёмнике лежит не тот товар, и отчёт по номенклатуре врёт.
Такую правку видно по самому документу. Платформа меняет ВерсияДанных при каждой записи объекта, и прочитать её можно обычным запросом:
ВЫБРАТЬ
Д.Ссылка КАК Ссылка,
Д.ВерсияДанных КАК Версия,
Д.Дата КАК Дата,
Д.Проведен КАК Проведен,
Д.ПометкаУдаления КАК Пометка
ИЗ
Документ.ОприходованиеИзлишковТоваров КАК Д
ГДЕ
Д.Ссылка В (&РегистраторыЭтогоВида)
Порядок важен. Сначала один проход по регистру собирает регистраторы и дни их движений, потом версии читаются только по тем видам документов, которые реально встретились. Если делать подзапрос к регистру на каждый вид документа, который вообще может писать в регистр, то у регистра бухгалтерии это десятки проходов вместо одного.
Вместе с версией сохраняются дни, где у документа были движения. Разошлись версия, дата, проведение или пометка, и документ отправляет в пакет все свои дни, старые из сохранённого списка, новые из текущего прохода. Поэтому перенос даты и снятие с проведения закрываются полностью, а помеченный на удаление документ без движений не теряется: его старые дни известны.
У версий есть цена. ВерсияДанных меняется при любой перезаписи, даже если движения остались прежними. Групповое перепроведение за квартал отправит в приёмник весь квартал, и пакет после такой ночи будет большим. Ошибки это не создаёт, только объём.
Есть и платформенная альтернатива: план обмена с авторегистрацией документов и самого регистра. Он ловит любую запись в любом периоде, включая набор записей мимо документа. Но в типовой конфигурации плана обмена под такую выгрузку нет, а добавить его можно только правкой конфигурации или расширением со своей структурой данных. Это согласование с владельцем базы и сопровождение на каждом обновлении. Если менять базу можно, план обмена надёжнее версий. Как в нём устроена регистрация и почему изменение иногда не встаёт в очередь, разобрано в статье про регистрацию изменений в плане обмена.
Чем чинить: заменой дня целиком
Когда проверки нашли разошедшиеся дни, приёмнику нужно правило ремонта. Самое простое и самое надёжное: удалить у себя все строки этих дней и залить строки из 1С, в одной транзакции.
Построчная загрузка по ключу “регистратор плюс номер строки” тоже работает, но спотыкается на удалениях. Документ перепровели, строк стало три вместо пяти, и приёмнику нужны ключи двух пропавших строк, которых в 1С уже нет. Замена дня решает это без хранения старых ключей: день стирается и заливается тем, что в нём есть сейчас.
Второе правило жёсткое: пакеты грузятся строго по порядку номеров. Если старый пакет загрузить после нового, старое состояние дня ляжет поверх свежего. Нумеровать пакеты временем создания не стоит: два прогона в одну секунду дадут одно имя, а ремонтный пакет встанет в очередь не туда. Нужен сквозной номер. Если пакеты едут в приёмник по слабому каналу, добавляется третья беда, обрезанный файл: почему пакет на FTP после обрыва не докачивается и как везти его частями, разобрано в статье про обрыв обмена 1С через FTP.
Вот как это выглядит на стороне приёмника на MS SQL. Пакет состоит из двух файлов: dni.csv со списком дат к замене и stroki.csv со всеми строками этих дат:
-- Фрагмент процедуры загрузки пакета, @katalog - путь к папке пакета.
-- Удалить строки дней из dni.csv и вставить stroki.csv.
-- Промежуточные таблицы stg_dni и stg_stroki уже заполнены через BULK INSERT.
SET XACT_ABORT ON;
BEGIN TRAN;
DELETE t FROM dbo.tovary t
WHERE CAST(t.period AS date) IN (SELECT den FROM dbo.stg_dni);
INSERT dbo.tovary SELECT * FROM dbo.stg_stroki;
-- журнал помнит, какие пакеты уже загружены
INSERT dbo.zhurnal (paket, dnej) SELECT @katalog, COUNT(*) FROM dbo.stg_dni;
COMMIT;
Повтор того же пакета ничего не портит: дни заменятся ещё раз. Индекс по периоду в таблице приёмника нужен, иначе удаление дня станет полным проходом.
Сверка самого приёмника
Всё выше отвечает на вопрос “изменилась ли 1С после выгрузки”. Второй вопрос задают реже: дошло ли выгруженное до приёмника. Пакет мог не загрузиться, загрузиться наполовину, а кто-то мог поправить строку прямо в хранилище.
Ответ тот же паспорт, только посчитанный в приёмнике по тем же правилам знака:
-- Паспорт приёмника: число строк и суммы ресурсов по дню.
-- Регистр остатков: приход плюсом, расход минусом, как в паспорте 1С.
CREATE OR ALTER VIEW dbo.pasport AS
SELECT CAST(period AS date) AS den,
COUNT(*) AS strok,
SUM(CASE WHEN vid_dvizheniya = 'Receipt' THEN v_nalichii ELSE -v_nalichii END) AS v_nalichii,
SUM(CASE WHEN vid_dvizheniya = 'Receipt' THEN k_otgruzke ELSE -k_otgruzke END) AS k_otgruzke
FROM dbo.tovary
GROUP BY CAST(period AS date);
Сравнивать его с паспортом 1С можно где угодно. Если паспорт выгрузки лежит в приёмнике таблицей, расхождение находится одним запросом:
-- stg_pasport_1c: паспорт выгруженного состояния, загруженный из файла 1С
SELECT COALESCE(a.den, b.den) AS den,
a.strok AS strok_1c, b.strok AS strok_priemnik,
a.v_nalichii AS summa_1c, b.v_nalichii AS summa_priemnik
FROM dbo.stg_pasport_1c a
FULL JOIN dbo.pasport b ON b.den = a.den
WHERE a.den IS NULL OR b.den IS NULL
OR a.strok <> b.strok
OR a.v_nalichii <> b.v_nalichii
OR a.k_otgruzke <> b.k_otgruzke
ORDER BY 1;
Что эта сверка нашла на тестовом приёмнике под “Товары на складах” (5 545 строк):
| Что сломали в приёмнике | Сверка паспортом | Разбор дня по строкам |
|---|---|---|
| плюс 1 к количеству в одной строке за 20.06 | красный день, строк 500 и 500 | документ, строка 1, поле ВНаличии: 2 и 3 |
| не загрузили пакет с новым документом за 25.09 | красный день; всего в 1С 5 546, в приёмнике 5 545 | не понадобился |
| подменили товар в строке за 05.07 | зелёный | документ, строка 1, поле Номенклатура |
Подмену товара паспорт приёмника не видит по той же причине, что и паспорт 1С: суммы не изменились. Её находит только разбор дня: строки приёмника за день сравниваются со строками 1С по ключу “регистратор плюс номер строки”, и в ответ получается адрес вида “Реализация товаров и услуг от 05.07.2026, строка 1, поле Номенклатура”. Разбор дорогой, его запускают точечно, на красный день или на дату, про которую спросил бухгалтер.
Ремонт после красной сверки делается тем же механизмом: пакет на красные дни из текущего состояния 1С, со следующим номером в общем ряду. В сценарии с порчей 20 июня ремонтный пакет заменил 500 строк дня, и следующая сверка стала зелёной.
Что остаётся непокрытым
Набор записей, записанный кодом мимо документа. Версия документа не меняется, версии молчат. Паспорт заметит правку, только если изменилось число строк или сумма. В доработанных базах обработки, правящие наборы записей напрямую, встречаются регулярно, и это самая большая дыра схемы. Без правки базы против неё работает только разбор дня по известной дате, с правкой базы её закрывает план обмена с регистром в составе.
Регистры сведений. Слой версий держится на документе-регистраторе, у независимого регистра сведений его нет. Схема рассчитана на регистры накопления и бухгалтерии.
Первая выгрузка. Она пишет всю историю в файл кодом 1С, около 600 строк в секунду. 300 000 строк это 481-521 секунда и файл на 156 МБ. По той же скорости 10 миллионов займут четыре-пять часов, а 50 миллионов около суток. Повторные прогоны быстрые: на 300 000 строк с окном 14 дней 5,7-5,8 секунды, из них около секунды на паспорт и версии.
Два прогона в один каталог. Если вызов, ждавший выгрузку, оборвался по таймауту, сервер 1С продолжает писать, и повторный запуск начнёт писать туда же. На стенде так два прогона почти четыре минуты писали в одну папку. Лечится замком в каталоге на время прогона.
Как проверить свою выгрузку за вечер
- Возьмите копию базы и выгрузку в тестовый приёмник.
- Перенесите один документ на полгода назад и прогоните выгрузку. Если строки нет ни в старой дате, ни в новой, окно у вас единственная проверка.
- В другом старом документе замените товар, не меняя количества. Посмотрите, заметит ли это хоть что-нибудь.
- Испортите одну строку прямо в приёмнике и посчитайте его паспорт запросом выше. Если расхождение видно только глазами в отчёте, сверки приёмника нет.
Готовая обработка, которая делает всё описанное на запросах 1С и файлах, называется Выгрузка регистров 1С во внешнюю базу со сверкой сходимости: окно, паспорт дня, версии, сверка приёмника, ремонтный пакет и разбор дня. К СУБД базы 1С она не обращается и в базу не пишет. Если выгрузку под отчёты нужно построить или починить целиком, вместе с приёмником и регламентом, это работа из раздела обмены данными и интеграции 1С.