В процессе разработки и сопровождения систем на базе 1С:ERP программисты часто сталкиваются с труднообъяснимыми на первый взгляд расхождениями в числовых данных. Типичная ситуация: в табличной части документа «Этап производства» пользователь видит одно число, а при выполнении программного кода или типового запроса значение отличается на незначительную величину, например, на 0,001. Рассмотрим детально, почему это происходит, как платформа 1С обрабатывает числа и какие механизмы в ERP провоцируют подобные коллизии.
Проанализируем конкретный пример. Допустим, у нас есть расчет: 24,555 * 10,69002 = 262,4934411. В конфигурации для реквизита Количество установлен тип Число(15, 3). Согласно правилам математического округления до трех знаков после запятой, мы должны получить 262,493. Именно это число пользователь видит в интерфейсе и именно оно записывается в физическую таблицу базы данных.
Однако при выполнении запроса, особенно сложного типового запроса из модуля менеджера документа ПроизводственнаяОперация2_2, система может вернуть 262,494. Выясним причину такого поведения. Она кроется в нескольких плоскостях: особенностях хранения коэффициентов упаковок, механизмах работы SQL-сервера и логике распределения количества между этапами и операциями.
В 1С:ERP для пересчета единиц измерения используются справочники упаковок. Рассмотрим важные моменты:
КоличествоУпаковок * Коэффициент, SQL-сервер производит вычисление с максимальной точностью, доступной для операндов. Если коэффициент имеет 5 знаков после запятой, промежуточный результат будет содержать все знаки, и только при финальном выводе или помещении во временную таблицу с типизированным полем произойдет округление.Если в одном месте запроса число округлилось «вниз», а в другом (после сложения с другими остатками) — «вверх», возникает та самая разница в 0,001.
Проанализируем структуру производственного учета. Документ Этап производства является распоряжением, а Производственная операция — детальным фактом выполнения. Часто запрос в функции ДанныеВыполненныхОпераций собирает данные не только из текущего документа, но и соединяет их с:
Разберем ситуацию: если документ «Этап производства» был изменен вручную, а связанные с ним операции пересчитывались автоматически, алгоритм распределения остатков мог добавить 0,001 к последней строке, чтобы итоговая сумма по всем операциям в точности соответствовала общему количеству по этапу. В результате в табличной части этапа мы видим одно значение, а запрос, анализирующий совокупность операций, получает скорректированное значение.
Платформа 1С на сервере приложений использует для вычислений тип данных с плавающей точкой. В то же время SQL-сервер работает с фиксированной точностью Numeric. При сложных соединениях (JOIN) и агрегатных функциях (SUM) внутри временных таблиц может происходить накопление погрешности. Рассмотрим, как это выглядит в запросе:
// Фрагмент кода, который может приводить к ошибке
ВЫБРАТЬ
ТЧ.КоличествоУпаковок * ТЧ.Упаковка.Числитель / ТЧ.Упаковка.Знаменатель КАК Количество
ПОМЕСТИТЬ ВТ_Данные
ИЗ
Документ.ЭтапПроизводства.ВыходныеИзделия КАК ТЧ
В этом примере поле Количество во временной таблице ВТ_Данные может получить тип с гораздо большей точностью, чем 3 знака. Если далее по тексту запроса это поле участвует в соединениях, SQL-сервер будет сравнивать или складывать полные значения, что приведет к результату 262,4935, который при выводе превратится в 262,494, хотя в исходной ТЧ было 262,493.
Чтобы исключить влияние «хвостов» после запятой и гарантировать, что запрос вернет в точности то же значение, что хранится в базе, необходимо использовать функцию ВЫРАЗИТЬ. Проанализируем правильный подход к написанию запроса:
ВЫБРАТЬ
ВЫРАЗИТЬ(ТЧ.КоличествоУпаковок * ТЧ.Коэффициент КАК ЧИСЛО(15, 3)) КАК Количество
ИЗ
Документ.ЭтапПроизводства.ВыходныеИзделия КАК ТЧ
Рассмотрим по шагам, что дает этот метод:
ЧИСЛО(15, 3) полностью соответствует метаданным реквизита, что исключает расхождения при программном сравнении результатов выборки с данными объекта 1С.JOIN по числовым полям (хотя это и редкость, иногда это необходимо), округленные значения будут сопоставляться корректно.Если вы столкнулись с подобной ошибкой, выполните следующие действия:
КоличествоУпаковок и Коэффициент. Часто выясняется, что именно коэффициент имеет избыточную точность.ПриЧтенииНаСервере. Если в ней данные объекта выглядят корректно, а в запросе — нет, значит, проблема именно в логике сборки данных внутри запроса (использование временных таблиц без явного указания точности).Помните, что в 1С:ERP производственный блок сильно завязан на автоматические корректировки. Система всегда старается «закрыть в ноль» потребности и выпуски, поэтому добавление или вычитание 0,001 в сложных цепочках документов — это штатное поведение алгоритмов распределения, которое нужно учитывать при написании собственных обработок и отчетов.