Остатки не сходятся с движениями: как найти месяц, где сломались итоги регистра

16.10.26

База данных - Инструменты администратора БД

Остатки по позиции не бьются, перепроведение не помогает, а полный пересчёт итогов - это ночь. Откуда взялся Чек-ап итогов: платформа не умеет пересчитывать итоги с отбором, зато запрос Остатки на первое число месяца читает одну сохранённую строку итогов, и по разнице с движениями видно, с какого месяца пошла ошибка. Почему строка 1 августа чинится пересчётом за июль и сколько это стоит по времени.

Остатки по одной позиции не бьются с движениями. Отчёт по движениям показывает одно число, запрос к остаткам другое. Документы перепровели, ничего не изменилось. Дальше звучит совет пересчитать итоги, а на большой базе полный пересчёт это ночное окно, и заранее никто не скажет, поможет ли он.

Ниже способ найти регистр, позицию и месяц, где итоги разошлись с движениями, одним запросом, и починить это пересчётом за один месяц вместо всей истории. Всё на встроенном языке, внешних обработок не нужно. Пример на типовом регистре ТоварыНаСкладах из УТ 11.5, проверен на тестовой копии с намеренно испорченной строкой итогов.

Почему перепроведение не лечит

Проверили на тестовой копии. При испорченной строке итогов за 1 августа прочитали и записали заново наборы записей всех трёх документов с движениями в июле, 1 800 записей:

Набор = РегистрыНакопления.ТоварыНаСкладах.СоздатьНаборЗаписей();
Набор.Отбор.Регистратор.Установить(ДокументСсылка);
Набор.Прочитать();

// Те же движения: итоги не изменились, испорченная строка осталась.
Набор.Записать();

При записи итоги меняются на разницу между старым и новым набором. Движения те же, разница нулевая, и ошибка, которая уже сидит в строке итогов, остаётся на месте. Отсюда знакомая картина: по каждому документу движения верные, а остаток всё равно не бьётся.

Что хранится в строке итогов

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

движения за месяц            строка итогов
июнь     +87 081             01.07   87 081
июль      -4 424             01.08   82 657
август      -819             01.09   81 838
                             текущие 81 838

Строка с периодом 1 августа хранит остаток на начало августа, то есть всё, что накопилось по конец июля. Запрос Остатки на первое число месяца берёт ровно эту строку и движения не читает. Испорченная строка вернётся из запроса как есть, и никакая проверка документов её не увидит.

Запрос: где итоги разошлись с движениями

Идея простая. Складываем активные движения раньше границы месяца: приход с плюсом, расход с минусом. Это остаток, который должен быть. Рядом ставим Остатки на ту же границу, это остаток, который хранится. Разница по позиции и есть ошибка строки итогов.

ВЫБРАТЬ
	Т.Номенклатура, Т.Характеристика, Т.Назначение, Т.Склад, Т.Помещение, Т.Серия,
	СУММА(ВЫБОР КОГДА Т.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход)
		ТОГДА Т.ВНаличии ИНАЧЕ -Т.ВНаличии КОНЕЦ) КАК ВНаличии
ПОМЕСТИТЬ ВТ_Движения
ИЗ
	РегистрНакопления.ТоварыНаСкладах КАК Т
ГДЕ
	Т.Активность
	И Т.Период < &ДвиженияДо
СГРУППИРОВАТЬ ПО
	Т.Номенклатура, Т.Характеристика, Т.Назначение, Т.Склад, Т.Помещение, Т.Серия
;
ВЫБРАТЬ
	О.Номенклатура, О.Характеристика, О.Назначение, О.Склад, О.Помещение, О.Серия,
	О.ВНаличииОстаток КАК ВНаличии
ПОМЕСТИТЬ ВТ_Итоги
ИЗ
	РегистрНакопления.ТоварыНаСкладах.Остатки(&Граница) КАК О
;
ВЫБРАТЬ
	ЕСТЬNULL(Д.Номенклатура, Ит.Номенклатура) КАК Номенклатура,
	ЕСТЬNULL(Д.Склад, Ит.Склад) КАК Склад,
	ЕСТЬNULL(Д.ВНаличии, 0) КАК ПоДвижениям,
	ЕСТЬNULL(Ит.ВНаличии, 0) КАК ПоИтогам,
	ЕСТЬNULL(Д.ВНаличии, 0) - ЕСТЬNULL(Ит.ВНаличии, 0) КАК Разница
ИЗ
	ВТ_Движения КАК Д
		ПОЛНОЕ СОЕДИНЕНИЕ ВТ_Итоги КАК Ит
		ПО Д.Номенклатура = Ит.Номенклатура
			И Д.Характеристика = Ит.Характеристика
			И Д.Назначение = Ит.Назначение
			И Д.Склад = Ит.Склад
			И Д.Помещение = Ит.Помещение
			И Д.Серия = Ит.Серия
ГДЕ
	ЕСТЬNULL(Д.ВНаличии, 0) - ЕСТЬNULL(Ит.ВНаличии, 0) <> 0

Почему так, а не проще:

  • Полное соединение, потому что испорченная строка бывает у позиции, которой по движениям уже нет, и наоборот.
  • Только активные движения: неактивные в итоги не попадают, и сравнивать надо с тем же.
  • Строго меньше границы: Остатки(&Граница) возвращает остаток на начало этой даты, движения ровно в 00:00:00 первого числа в него не входят.
  • Все измерения регистра в группировке и соединении. Если какое-то пропустить, разница сложится по нему, и две встречные ошибки погасят друг друга.
  • Два параметра вместо одного: для месячной границы оба равны первому числу месяца, а для текущих итогов Граница пустая, и ДвиженияДо берёт все движения.

Для своего регистра меняется имя регистра (два раза в запросе и один в коде обхода ниже), список измерений в четырёх местах и ресурс. Ресурсов несколько - на каждый своя колонка суммы и своё условие в последнем ГДЕ через ИЛИ. На большом регистре первая часть читает всю историю движений, поэтому добавьте одинаковый отбор по складу или номенклатуре в обе части: в первую условием ГДЕ, в Остатки вторым параметром. В выборку для краткости выведены номенклатура и склад; если у вас расходится по характеристике или серии, выведите и их, иначе две строки на экране будут выглядеть одинаково.

Запрос проверяет одну границу. Обходим их от ранней к поздней:

Менеджер = РегистрыНакопления.ТоварыНаСкладах;
// Итоги рассчитаны по 31.08 - последняя хранимая строка месяца имеет период 01.09.
МаксПериод = Менеджер.ПолучитьМаксимальныйПериодРассчитанныхИтогов();
// Пустая дата: итоги по месяцам не рассчитаны, остаётся только полный ПересчитатьИтоги().
Последняя = КонецМесяца(МаксПериод) + 1;

Запрос = Новый Запрос(ТекстЗапроса);   // текст запроса выше
ПерваяСломанная = Неопределено;

Граница = ДобавитьМесяц(Последняя, -12);
МинПериод = Менеджер.ПолучитьМинимальныйПериодРассчитанныхИтогов();
Если ЗначениеЗаполнено(МинПериод) И Граница < НачалоМесяца(МинПериод) Тогда
	Граница = НачалоМесяца(МинПериод);   // раньше минимального периода строк итогов нет
КонецЕсли;
Пока Граница <= Последняя Цикл
	Запрос.УстановитьПараметр("Граница", Граница);
	Запрос.УстановитьПараметр("ДвиженияДо", Граница);
	Расхождения = Запрос.Выполнить().Выгрузить();
	Если Расхождения.Количество() > 0 И ПерваяСломанная = Неопределено Тогда
		ПерваяСломанная = Граница;
	КонецЕсли;
	Для Каждого Стр Из Расхождения Цикл
		Сообщить(Формат(Граница, "ДФ=dd.MM.yyyy") + " " + Стр.Номенклатура + ", " + Стр.Склад
			+ ": движения " + Стр.ПоДвижениям + ", итоги " + Стр.ПоИтогам + ", разница " + Стр.Разница);
	КонецЦикла;
	Граница = ДобавитьМесяц(Граница, 1);
КонецЦикла;

// Текущие итоги: Остатки без даты против всех движений.
Запрос.УстановитьПараметр("Граница", Неопределено);
Запрос.УстановитьПараметр("ДвиженияДо", Дата(3999, 12, 31));
СломаныТекущие = Не Запрос.Выполнить().Пустой();

Дальше последней границы цикл не идёт: хранимых строк по месяцам там нет, проверять нечего. Глубина в 12 месяцев здесь для примера.

Какой месяц пересчитывать

Здесь мы сами ошиблись. Логика казалась очевидной: строка 1 августа хранит итог июля, значит, чинить её надо пересчётом за июль. Прогон на тестовой копии сказал другое:

Что пересчитали при испорченной строке 01.08 Время Строка 01.08
ПересчитатьИтогиЗаПериод за июнь 33 мс осталась испорченной
за июль 108 мс осталась испорченной
за август 116 и 85 мс (два раза) починилась оба раза

С последней строкой то же самое. Итоги рассчитаны по 31.08, но хранится и строка 01.09: это остаток на конец августа, а период у неё сентябрьский. Испорченную строку 01.09 не чинит ни пересчёт за август, ни за июнь-август. Чинит пересчёт за сентябрь, и максимальный период рассчитанных итогов от этого не сдвигается.

Правило получилось такое: ПересчитатьИтогиЗаПериод(Начало, Конец) перестраивает строки, чей период попадает в интервал. Строку на 1-е число месяца чинит пересчёт за этот же месяц. Если первая сломанная граница 01.08, пересчитываем с 01.08 по конец месяца последней границы: так заодно перестраиваются все более поздние строки, вдруг сломаны и они.

Второе, что показал тот же прогон: текущие итоги строятся от последней хранимой строки. При испорченной строке 01.09 вызов ПересчитатьТекущиеИтоги честно перенёс ту же ошибку и в текущие. Поэтому порядок жёсткий: сначала строки по месяцам, потом текущие.

Если ПерваяСломанная <> Неопределено Тогда
	// Строку 01.08 перестраивает пересчёт за август. Конец - месяц последней границы.
	Менеджер.ПересчитатьИтогиЗаПериод(ПерваяСломанная, КонецМесяца(Последняя));
КонецЕсли;
Если СломаныТекущие Тогда
	// Только после строк по месяцам: текущие считаются от последней из них.
	Менеджер.ПересчитатьТекущиеИтоги();
КонецЕсли;

// Контроль: тот же цикл по границам ещё раз. Расхождений быть не должно.

Пересчёт идёт по всему регистру за период, с отбором по складу или товару платформа его не умеет: ПересчитатьИтоги, ПересчитатьИтогиЗаПериод и ПересчитатьТекущиеИтоги отбора не принимают. Выигрыш метода только во времени: вместо всей истории перестраиваются один-два месяца. Запускать всё равно лучше вне рабочего времени. Права нужны "Управление итогами" на регистр.

Пример целиком

Тестовая копия УТ 11.5.22.67, платформа 8.3.27.1606, MS SQL 2022. Регистр ТоварыНаСкладах: 5 545 движений с июня по начало августа 2026, итоги рассчитаны по 31.08, разделения итогов нет, текущие итоги включены.

  1. На чистой базе цикл по четырём границам с 01.06 по 01.09 плюс текущие: расхождений ноль, весь проход 0,2 секунды.
  2. На тестовой копии изменили строку итогов 01.08 у одной позиции: плюс 7 к ВНаличии.
  3. Тот же цикл: 01.06 и 01.07 пусто, на 01.08 одна строка "движения 52, итоги 59, разница -7", 01.09 и текущие пусто. Первая сломанная граница 01.08, текущие целы.
  4. ПересчитатьИтогиЗаПериод(01.08.2026, 30.09.2026): 153, 152 и 230 мс в трёх повторах. Перед каждым повтором строку портили заново, и каждый раз после пересчёта она возвращалась к 82 657, как до порчи. В первом повторе это показал контрольный цикл: ни одного расхождения.
  5. Для сравнения при той же порче полный ПересчитатьИтоги(): 309, 306 и 308 мс. Строка тоже починилась.

Разница вдвое, и на таком маленьком регистре она ничего не доказывает: пять с половиной тысяч движений за три месяца пересчитываются целиком за треть секунды. Как соотносятся времена на регистре с годами истории и миллионами строк, наш полигон не показывает. Если у вас есть такой замер, пишите в комментариях.

Где метод не работает

  • Оборотные регистры. Таблицы Остатки у них нет. Сравнивать нужно виртуальную таблицу Обороты с периодичностью Месяц и движения, сгруппированные по началу месяца. Логика та же, запрос другой. В нашей УТ 11.5 из 32 оборотных регистров у 10 таблицы итогов нет совсем, им ломаться нечему.
  • Итоги выключены. Тогда Остатки сам считает по движениям, и разница всегда ноль. Проверять нечего, сначала надо разобраться, почему итоги выключены.
  • Регистры бухгалтерии. Принцип тот же, но запрос сильно сложнее: движения раскладываются на дебет и кредит, у Остатки отдельные параметры для счетов и измерений, небалансовые ресурсы учитываются только по счетам с признаком учёта. Здесь этого запроса нет.
  • Разделение итогов. Запрос не меняется. При разделении платформа хранит итог одной позиции несколькими строками, чтобы параллельные проведения не ждали друг друга, а Остатки складывает их сам. Порчу на регистре с разделением итогов мы не проверяли.
  • Ошибка в самих движениях. Если движения документа неправильные, итоги им честно соответствуют, и запрос покажет ноль. Это другой класс проблем, его ловят проверкой движений, а не итогов.

Вопрос к тем, кто видел порчу итогов на живой базе: откуда она взялась? Мы меняли строку сами на тестовой копии, а сценария, при котором итоги расходятся с движениями сами, у нас нет.

Этот же обход границ и контрольная сверка собраны в обработку Чек-ап итогов и остатков 1С.

Вступайте в нашу телеграмм-группу Инфостарт

итоги регистра накопления пересчет итогов 1С остатки не совпадают с движениями ПересчитатьИтогиЗаПериод период рассчитанных итогов текущие итоги перепроведение не помогает остатки не бьются управление итогами разделение итогов проверка итогов регистров

Вы можете заказать платную адаптацию этой статьи под ваши задачи на «Бирже заказов».

  • 0% комиссии — оплата напрямую исполнителю;
  • Исполнители любого масштаба — от отдельных специалистов до команд под проект;
  • Прямой обмен контактами между заказчиком и исполнителем;
  • Безопасная сделка — при необходимости;
  • Рейтинги, кейсы и прозрачная система откликов.

См. также

Инструментарий разработчика Чистка данных Свертка базы Инструменты администратора БД Системный администратор Разработчик Руководитель проекта 1С:Предприятие 8 1С:ERP Управление предприятием 2 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х 1С:Управление нашей фирмой 3.0 Россия Платные (руб)

Инструмент представляет собой обработку для проведения свёртки или обрезки баз данных. Работает на ЛЮБЫХ конфигурациях (УТ, БП, ERP, УНФ, КА и т.д.). Поддерживаются серверные и файловые базы, управляемые и обычные формы, интерфейс 8.5. Может выполнять свертку одновременно в несколько потоков, а также без непосредственного участия пользователя. Решение в Реестре отечественного ПО.

24900 руб.

20.08.2024    83294    432    171    

362

Инструменты администратора БД Роли и права Системный администратор Разработчик Пользователь 1С 8.3 1С:Розница 2 1С:Управление нашей фирмой 1.6 1С:Документооборот 1С:Зарплата и кадры государственного учреждения 3 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х 1С:Зарплата и Управление Персоналом 3.x 1С:Управление нашей фирмой 3.0 1С:Розница 3.0 Платные (руб)

Роли… Вы тратите много времени и сил на подбор ролей среди около 2400 в ERP или 1500 в Рознице 2, пытаясь понять какими правами они обладают? Вы все время смотрите права в конфигураторе или отчетах чтоб создать нормальные профили доступа? Вы хотите наглядно видеть какие права дает профиль и редактировать все в простом виде? А может хотите просто указать подсистему и дать права на просмотр и добавление на объекты и не лезть в дебри прав и чтоб обработка сама подобрала нужные роли? Все это теперь стало возможно! Обновление от 17.04.2026, версия 1.4.1, работает в 1С:ФРЕШ!

23180 руб.

06.12.2023    25087    85    14    

118

Инструменты администратора БД Инструментарий разработчика Роли и права Разработчик 1С:Предприятие 8 1C:Бухгалтерия Россия Платные (руб)

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

17000 руб.

10.11.2023    28767    103    46    

107

Информационная безопасность Инструменты администратора БД Инструментарий разработчика Учет документов Системный администратор Разработчик Аналитик Бухгалтер Пользователь Руководитель проекта 1С 8.3 1С 8.5 Розничная и сетевая торговля (FMCG) Платные (руб)

Контроль ввода данных в 1С: проверка заполнения реквизитов, обязательные поля, контроль перед записью и проведением, запрет проведения документа. Позволяет настраивать любые проверки данных в 1С 8.3/8.5 от обязательных полей до сложных условий – без открытия конфигуратора и написания кода. Готовое расширение, которое подключается и работает сразу.

6000 руб.

15.04.2026    4177    12    0    

25

Закрытие периода Инструменты администратора БД Корректировка данных Бухгалтер Пользователь 1С:Предприятие 8 1С:Бухгалтерия 3.0 Россия Бухгалтерский учет Платные (руб)

Расширение «Оперативное проведение» в 4 раза уменьшает время проведения документов и закрытия месяца. Является комплексным решением проблем 62 и 60 счетов. Оптимизирует проведение при включенной функциональной опции «Раздельный учет НДС». Используется в более 10 организациях уже 2 года. Совместимо с конфигурацией Бухгалтерия 3.0 (+КОРП).

14640 руб.

29.04.2020    52964    146    164    

98

Файловый обмен (TXT, XML, DBF), FTP Поиск данных Инструменты администратора БД Корректировка данных Системный администратор Разработчик 1С:Предприятие 8 1C:Бухгалтерия 1С:Розница 2 1С:Управление нашей фирмой 1.6 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Управление нашей фирмой 3.0 1С:Розница 3.0 Платные (руб)

Данная обработка позволит Вам легко и просто, а главное - быстро, выполнить сравнение данных между ЛЮБЫМИ базами (и РИБ, по правилам конвертаций) по контрольным суммам выбранных объектов баз 1С, работающих на платформах 8.3 и выше. Удобный и понятный интерфейс в виде "мастера". Высокая скорость сравнения достигается за счет специального алгоритма расчета контрольной суммы объекта/записи и сравнения по данным суммам объектов 2х баз через файл. Имеется возможность выбора реквизитов, по которым система будет сравнивать объекты. Сравнение количества записей в движениях документов, возможность сравнивать данные по правилам конвертации и не только! Выбор объектов конфигурации для КАЖДОГО узла в отдельности с индивидуальным отбором для каждого объекта конфигурации, работа с FTP, сохранение или загрузка настроек, сохранение или загрузка результата сравнения, регистрация на обмен объекта и его движений. (Обновление от 12.11.2024, версия 2.2-2.5)

24400 руб.

27.10.2017    47848    33    15    

51
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. YA_514896950 43 16.10.26 15:59 Сейчас в теме
Скажите, а вы знаете что такое нейрослоп?
2. aximo 2771 19.10.26 14:43 Сейчас в теме
(1) я не знаю, расскажите
3. YA_514896950 43 19.10.26 14:44 Сейчас в теме
(2) Нейрослоп — это контент, созданный с помощью ИИ без внимания к его качеству, достоверности и оригинальности. Он может быть текстовым, визуальным или звуковым. Иногда в одном материале сочетаются сразу несколько форматов, например: одна нейросеть пишет сценарий, другая генерирует картинку, а синтетический голос зачитывает текст.
Для отправки сообщения требуется регистрация/авторизация