При выполнении регламентной операции «Закрытие месяца» в программе «1С:Управление нашей фирмой» (УНФ) пользователи часто сталкиваются с критической ошибкой выполнения обработчика ОбработкаПроведения. Сообщение об ошибке обычно выглядит следующим образом: 22003: ERROR: numeric field overflow. DETAIL: A field with precision 23, scale 10 must round to an absolute value less than 10^13. Эта проблема особенно характерна для систем, работающих под управлением СУБД PostgreSQL.
В данной статье мы подробно разберем, почему возникает эта ошибка, проанализируем программный код, вызывающий сбой, и определим пошаговый алгоритм локализации и устранения причины в учетных данных.
Для начала проанализируем техническую суть сообщения. Ошибка numeric field overflow означает, что в процессе математических вычислений внутри запроса получилось число, которое не помещается в отведенный для него формат. В 1С:УНФ для хранения и расчета сумм часто используется тип ЧИСЛО(23, 10). Это означает, что число может иметь всего 23 знака, из которых 10 отведено под дробную часть. Следовательно, на целую часть остается 13 знаков (максимальное значение чуть меньше 10 в 13-й степени).
Почему же обычные суммы себестоимости внезапно превращаются в гигантские числа? Причина кроется в алгоритме расчета себестоимости. В УНФ применяется итерационный метод решения системы линейных алгебраических уравнений (СЛАУ). Программа пытается распределить затраты между номенклатурными позициями, учитывая встречные выпуски и перемещения. Рассмотрим ситуацию подробнее: если в данных есть логическая петля или отрицательные остатки, математическая модель теряет устойчивость. Вместо того чтобы на каждой итерации уменьшать погрешность, алгоритм начинает «раскачиваться», и значения сумм увеличиваются в геометрической прогрессии, пока не достигают предела точности СУБД.
Ошибка проявляется в модуле объекта документа ЗакрытиеМесяца при вызове метода ВыполнитьПакет. Рассмотрим фрагмент запроса, на котором происходит сбой:
// Фрагмент итерационного расчета себестоимости
ВЫБРАТЬ
УзлыКорректировкиСтоимостиСписания.НомерУзла КАК НомерУзла,
Сумма(ВЫРАЗИТЬ(ВЫБОР
КОГДА УзлыКорректировкиСтоимостиСписания.Количество <> 0
ТОГДА ВЫРАЗИТЬ(ТаблицаРешений.СуммаБезНДС КАК ЧИСЛО(23, 10)) * ВЫБОР
КОГДА УчетЗатрат.Количество = 0
ТОГДА ВЫРАЗИТЬ(УчетЗатрат.СуммаБезНДС КАК ЧИСЛО(23, 10))
ИНАЧЕ ВЫРАЗИТЬ(УчетЗатрат.Количество КАК ЧИСЛО(23, 10))
КОНЕЦ / ВЫРАЗИТЬ(УзлыКорректировкиСтоимостиСписания.Количество КАК ЧИСЛО(23, 10))
ИНАЧЕ 0
КОНЕЦ КАК ЧИСЛО(23, 10))) КАК СуммаБезНДС,
// ... аналогичный расчет для Сумма ...
ПОМЕСТИТЬ ВременнаяТаблицаРешений
ИЗ
РегистрСведений.УзлыКорректировкиСтоимостиСписания КАК УзлыКорректировкиСтоимостиСписания
ЛЕВОЕ СОЕДИНЕНИЕ УчетЗатрат КАК УчетЗатрат
// ... соединения по аналитике ...
Обратим внимание на операцию деления: / ВЫРАЗИТЬ(УзлыКорректировкиСтоимостиСписания.Количество КАК ЧИСЛО(23, 10)). Если значение количества в знаменателе крайне мало (близко к нулю, но не равно ему из-за погрешностей округления) или отрицательно, результат умножения на ТаблицаРешений.Сумма может мгновенно вырасти. В следующей части пакета запросов программа вычисляет СуммуКвадратовОтклонений:
ВЫБРАТЬ
СУММА((ЕСТЬNULL(ТаблицаРешений.Сумма, 0) - (УзлыКорректировкиСтоимостиСписания.Сумма + ЕСТЬNULL(ВременнаяТаблицаРешений.Сумма, 0)))
* (ЕСТЬNULL(ТаблицаРешений.Сумма, 0) - (УзлыКорректировкиСтоимостиСписания.Сумма + ЕСТЬNULL(ВременнаяТаблицаРешений.Сумма, 0))))
КАК СуммаКвадратовОтклонений
Когда алгоритм расходится, разница между итерациями (отклонение) становится огромной. Возведение этой разницы в квадрат окончательно «добивает» точность переменной, что и приводит к ошибке numeric field overflow.
Поскольку мы выяснили, что причина ошибки — некорректные данные, мешающие расчету СЛАУ, нам необходимо их локализовать. Воспользуемся следующей методикой:
Остатки товаров или Запасы на дату закрытия месяца. Обязательно установите детализацию до Партий, Характеристик и Заказов. Даже если общий остаток по номенклатуре положительный, минус по конкретной партии может привести к краху алгоритма.ЗапасыИЗатраты. Ищите записи, где при наличии суммового остатка отсутствует количественный, или наоборот.Приходная накладная и Отчет о переработке. Если в течение месяца было списание ТМЦ, которые не имели входящей стоимости (нулевая цена), это может вызвать нестабильность итераций.После того как проблемные позиции найдены, проанализируем способы устранения ошибки:
Способ 1: Исправление первичных документов. Если обнаружены отрицательные остатки, необходимо выяснить причину их появления — для их автоматической ликвидации есть расширение для исправления отрицательных остатков в 1С:УНФ. Возможно, документ поступления введен позже документа реализации, или нарушена последовательность проведения. Воспользуйтесь обработкой Поиск и установка дублей, если причина в пересортице по характеристикам или партиям. После исправления документов перепроведите месяц.
Способ 2: Ввод корректировок. Если найти причину оперативно невозможно, а закрыть месяц нужно срочно, создайте документ Корректировка регистров — для его быстрого заполнения подойдёт обработка автоматического заполнения корректировки регистров в УНФ. Внесите исправления в регистр Запасы и затраты, чтобы обнулить отрицательные остатки (как количественные, так и стоимостные) на начало закрываемого периода.
Способ 3: Проверка технологического анализа. В современных версиях УНФ встроен инструмент автоматической проверки данных. Перейдите в раздел Компания — Обслуживание — Анализ логических ошибок в данных. Программа сама может указать на наличие отрицательных остатков и некорректных движений, которые блокируют закрытие месяца — для этого можно использовать автоматический экспресс-анализ учета для 1С:УНФ.
Стоит отметить, что на MS SQL Server данная ошибка может не приводить к немедленному аборту транзакции, а возвращать NULL или Infinity, что все равно закончится ошибкой 1С, но с менее понятным описанием. PostgreSQL в этом плане более строг к типам данных. Если вы планируете увеличивать разрядность числа в конфигураторе (например, до ЧИСЛО(25, 10)), помните, что это лишь отодвинет порог ошибки, но не решит коренную проблему «разлетающегося» алгоритма. Единственный верный путь — поддержание чистоты учетных данных и отсутствие «минусов» по регистрам запасов.
Подводя итог, проанализируем ситуацию: ошибка 22003 — это лишь симптом математической нестабильности. Решая проблему с отрицательными остатками, мы не только устраняем технический сбой СУБД, но и обеспечиваем корректность расчета финансового результата вашего предприятия. Если закрыть месяц оперативно не получается, используйте отчет валовая прибыль без закрытия месяца — для этого есть альтернативный отчет по валовой прибыли без закрытия месяца для 1С:УНФ.