При доработке инвентаризационных описей (в частности, формы ИНВ-8а по учету драгоценных металлов в основных средствах) разработчики часто сталкиваются с двумя проблемами: попаданием списанных объектов в отчет и аварийным завершением работы программы с ошибкой «Операции сравнения на больше-меньше допустимы только для значений совпадающих примитивных типов».
В этой статье мы подробно проанализируем причины возникновения данных ошибок, разберем исправление логики работы с типами данных и рассмотрим правильные варианты исключения списанных основных средств из выборки запроса.
Рассмотрим ситуацию: при обходе результатов запроса в модуле внешней обработки выполняется проверка числовых значений (например, амортизации или количества драгметаллов):
Если ОС.Амортизация > 0 Тогда
// Заполнение секции макета
КонецЕсли;
Если в запросе применяется ЛЕВОЕ СОЕДИНЕНИЕ с виртуальными таблицами (например, с таблицей оборотов регистра накопителя или сведений), а для основного средства соответствующие записи отсутствуют, запрос возвращает значение типа NULL. В языке BSL значение NULL не является числовым типом, поэтому операция вида ОС.Амортизация > 0 приводит к выполнению ошибки сравнения несравнимых типов.
Для решения этой проблемы разберем два подхода.
Подход 1. Преобразование NULL в ноль на уровне запроса
Самый надежный способ — обернуть все соединяемые числовые поля в функцию ЕСТЬNULL() прямо в тексте запроса. В этом случае вместо отсутствующего значения NULL запрос гарантированно вернет число 0:
// В тексте запроса изменяем выборку амортизации и показателей свойств:
ЕСТЬNULL(СтоимостьОСБухгалтерскийУчетОстаткиИОбороты.АмортизацияОборот, 0) КАК Амортизация
Подход 2. Проверка значения на NULL в коде BSL
Если изменить текст запроса нет возможности, следует выполнять проверку заполнености поля перед сравнением с числом в цикле обхода выборки:
Для Каждого ОС Из ВыборкаЗапроса Цикл
Если ОС.Амортизация <> NULL И ОС.Амортизация > 0 Тогда
// Обработка данных
КонецЕсли;
КонецЦикла;
Также для проверки можно использовать встроенную функцию ЗначениеЗаполнено(ОС.Амортизация).
Проанализируем фрагмент кода, используемый для фильтрации строк перед выводом на печать:
Если ОС.Амортизация > 0 и ОС.КолЗолото <> 0 ИЛИ ОС.КолСеребро <> 0 ИЛИ ОС.КолПлатина <> 0 Тогда
// Вывод строки
КонецЕсли;
В языке BSL оператор И имеет более высокий приоритет, чем ИЛИ. Из-за отсутствия скобок данное условие вычисляется как (ОС.Амортизация > 0 И ОС.КолЗолото <> 0) ИЛИ ОС.КолСеребро <> 0.... В результате, если у списанного основного средства заполнен хотя бы один драгметалл (например, ОС.КолСеребро <> 0), вся конструкция принимается как ИСТИНА, и проверка амортизации полностью игнорируется.
Правильная группировка логических условий должна выглядеть следующим образом:
Если ОС.Амортизация > 0 И (ОС.КолЗолото <> 0 ИЛИ ОС.КолСеребро <> 0 ИЛИ ОС.КолПлатина <> 0) Тогда
// Вывод строки в печатную форму
КонецЕсли;
Определение факта списания ОС по наличию амортизации (Амортизация > 0) является методологической ошибкой по следующим причинам:
Рассмотрим правильные способы исключения списанных объектов на уровне запроса.
Способ 1. Использование регистра сведений «Состояния ОС организаций»
Для получения актуального состояния основного средства выполним соединение с срезом последних регистра сведений СостоянияОСОрганизаций на дату проведения инвентаризации:
ВЫБРАТЬ
МестонахождениеОС.ОсновноеСредство КАК ОсновноеСредство,
СостоянияОССрезПоследних.Состояние КАК Состояние
ИЗ
РегистрСведений.МестонахождениеОСБухгалтерскийУчет.СрезПоследних(&КонецПериода, Организация = &Организация) КАК МестонахождениеОС
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СостоянияОСОрганизаций.СрезПоследних(&КонецПериода, Организация = &Организация) КАК СостоянияОССрезПоследних
ПО МестонахождениеОС.ОсновноеСредство = СостоянияОССрезПоследних.ОсновноеСредство
ГДЕ
СостоянияОССрезПоследних.Состояние <> ЗНАЧЕНИЕ(Перечисление.СостоянияОС.СнятоСУчета)
Способ 2. Проверка балансовых остатков по счетам учета ОС
Чтобы убедиться, что объект числится на балансе организации, присоединим виртуальную таблицу остатков регистра бухгалтерии (например, по счету 01.01):
ВЫБРАТЬ
МестонахождениеОС.ОсновноеСредство КАК ОсновноеСредство,
ЕСТЬNULL(ХозрасчетныйОстатки.СуммаОстатокДт, 0) КАК ОстаточнаяСтоимость
ИЗ
РегистрСведений.МестонахождениеОСБухгалтерскийУчет.СрезПоследних(&КонецПериода, Организация = &Организация) КАК МестонахождениеОС
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрБухгалтерии.Хозрасчетный.Остатки(
&КонецПериода,
Счет = ЗНАЧЕНИЕ(ПланСчетов.Хозрасчетный.ОсновныеСредстваНаСкладе),
,
Организация = &Организация
) КАК ХозрасчетныйОстатки
ПО МестонахождениеОС.ОсновноеСредство = ХозрасчетныйОстатки.Субконто1
Применение внутреннего соединения (ВНУТРЕННЕЕ СОЕДИНЕНИЕ) с остатками счета автоматически отсечет все объекты, не имеющие остатка на балансе на указанную дату, исключая списанные основные средства из формируемого отчета.