В процессе разработки на платформе 1С:Предприятие мы часто сталкиваемся с необходимостью передачи данных между реквизитами, имеющими разные Определяемые типы. Несмотря на то, что базовым типом для них может выступать обычное Число, каждый такой тип может обладать специфическими квалификаторами: ограничением на неотрицательность, определенной длиной или точностью (количеством знаков после запятой). В этой статье мы подробно разберем, как правильно приводить значения к нужным типам, какие методы платформы использовать и на какие нюансы стоит обратить внимание.
Для начала проанализируем, как 1С работает с примитивными типами данных в программном коде. В языке 1С:Предприятие реализована достаточно свободная типизация для переменных. Если мы просто присваиваем одно числовое значение другому, например: Объект.Реквизит1 = Объект.Реквизит2;, система выполнит прямое копирование значения. Даже если Реквизит1 имеет ограничение «неотрицательное», а мы присваиваем ему «-100», в оперативной памяти переменная может временно хранить это отрицательное число.
Однако реальные проблемы начинаются в двух случаях:
Чтобы избежать логических ошибок, нам необходимо использовать механизмы явного приведения типов.
Самый правильный и надежный способ — это использование метода ПривестиЗначение() объекта ОписаниеТипов. Рассмотрим ситуацию, когда нам нужно привести число к типу ОпределяемыйТип.ДенежнаяСуммаНеотрицательная. Разберем по шагам, как это реализовать через метаданные.
Посмотрим на пример кода, который удобно проверять через встраиваемую консоль кода, позволяющую получить описание типа напрямую из конфигурации и применить его к числу:
// Получаем описание типа из метаданных конфигурации
ОписаниеЦелевогоТипа = Метаданные.ОпределяемыеТипы.ДенежнаяСуммаНеотрицательная.Тип;
// Приводим произвольное число к этому типу
НужноеЧисло = ОписаниеЦелевогоТипа.ПривестиЗначение(ИсходнаяСумма);
Рассмотрим подробнее, что происходит в этот момент. Метод ПривестиЗначение() не просто копирует число, он «просеивает» его через фильтры, заданные в метаданных (квалификаторы числа). Если в определяемом типе стоит флаг Неотрицательное, а исходное число было меньше нуля, то результатом выполнения функции будет 0.
Часто в коде удобнее обращаться не к конкретному имени определяемого типа, а к описанию типа того реквизита, в который мы записываем данные. Это делает код более устойчивым к изменениям в конфигураторе. Проанализируем пример, где мы берем описание типа прямо из метаданных реквизита объекта:
// Универсальное приведение к типу конкретного реквизита документа
ОписаниеТипаРеквизита = Объект.Метаданные().Реквизиты.СуммаВзаиморасчетов.Тип;
Объект.СуммаВзаиморасчетов = ОписаниеТипаРеквизита.ПривестиЗначение(СуммаДокумента);
Этот подход гарантирует, что если разработчик завтра изменит ОпределяемыйТип у реквизита СуммаВзаиморасчетов на какой-то другой, что легко отследить через веб-инструмент для анализа зависимостей, ваш программный код продолжит работать корректно без необходимости внесения правок.
Важно различать бизнес-логику и техническое приведение типов. Выясним причину, почему иногда метод ПривестиЗначение() может не подойти. Если ваша задача — превратить отрицательную сумму в положительную (например, при зачете аванса), то использование ПривестиЗначение() превратит «-500» в «0», что может быть ошибкой. В таком случае следует использовать функцию Abs() (Модуль) или условие:
// Вариант 1: Использование модуля
Объект.СуммаВзаиморасчетов = Abs(СуммаДокумента);
// Вариант 2: Условная логика
Если СуммаДокумента < 0 Тогда
Объект.СуммаВзаиморасчетов = -1 * СуммаДокумента;
Иначе
Объект.СуммаВзаиморасчетов = СуммаДокумента;
КонецЕсли;
Важный нюанс: Даже после взятия модуля, мы рекомендуем дополнительно использовать ПривестиЗначение(), чтобы число было округлено до нужного количества знаков после запятой, которое определено в типе (например, до 2 знаков для валюты).
Определяемые типы для денежных сумм часто имеют разную разрядность. Например, один тип может поддерживать 2 знака после запятой, а другой — 4 знака (для сложных расчетов себестоимости). Если вы просто присвоите значение 10.5566 реквизиту с точностью 2 знака, в памяти документа может остаться исходное число, но в базе данных оно будет округлено до 10.56.
Чтобы избежать расхождений между тем, что программа «видит» в расчетах в данный момент, и тем, что будет записано в базу, всегда используйте приведение типа. Это принудительно выполнит округление по правилам платформы немедленно.
Иногда программисты сталкиваются с тем, что после выполнения корректного присваивания в коде, значение в реквизите формы всё равно становится нулевым. Разберем, почему это происходит:
КопироватьДанныеФормыВОбъект и обратный ему).Подводя итог, можно сказать, что работа с определяемыми типами требует не только знания операторов присваивания, но и активного использования объекта ОписаниеТипов. Это залог стабильной работы системы и отсутствия ошибок при записи данных в базу.