Как правильно сравнить код бухгалтерского счета по диапазону в 1С на управляемой форме?

Программист 1С v8.3 (Управляемые формы) Бухгалтерский учет
← На главную

Мы сталкиваемся с типичной задачей в 1С: необходимо выполнить определенные действия в форме, если выбранный пользователем бухгалтерский счет (например, в табличной части документа) попадает в заданный диапазон кодов. Допустим, нам нужно проверить, находится ли код счета в диапазоне от "1311" до "1330". На первый взгляд, это кажется простой операцией сравнения, но в 1С она таит в себе несколько нюансов, связанных с типами данных и обработкой ошибок. Рассмотрим подробнее проблему и шаги к её решению, проанализируем ошибки, которые могут возникнуть, и покажем, как их избежать.

Понимание типа данных и ошибки "Значение не является значением объектного типа"

Первая попытка решения задачи часто выглядит примерно так:


СтрокаТаблицы = Элементы.Товары.ТекущиеДанные;
Если СтрокаТаблицы.СчетУчетаБУ >= "1311" И СтрокаТаблицы.СчетУчетаБУ <= "1330" Тогда
    // Выполняем действия
КонецЕсли;

Однако такой подход приводит к ошибкам. Самая распространенная из них – "Значение не является значением объектного типа (СчетУчетаБУ)". Давайте выясним причину. Переменная СтрокаТаблицы.СчетУчетаБУ в 1С не содержит напрямую число или строку, представляющую код счета. Вместо этого она хранит ссылку на элемент плана счетов (тип ПланСчетовСсылка.Типовой, как мы выяснили в ходе обсуждения). Прямое сравнение ссылки со строкой ("1311") или числом невозможно, так как это совершенно разные типы данных. Кроме того, ошибка "Значение не является значением объектного типа" может возникнуть, если переменная СтрокаТаблицы или её свойство СчетУчетаБУ на момент выполнения кода окажется Неопределено. Это часто происходит, когда строка табличной части еще не выбрана, или в поле счета не заполнено значение. Для предотвращения таких ошибок необходимо всегда выполнять проверку на Неопределено перед попыткой доступа к свойствам объекта.


&НаКлиенте
Процедура ОбновитьДоступностьКнопкиИРеквизита(Команда)
    СтрокаТаблицы = Элементы.Товары.ТекущиеДанные;
    
    // 1. Обязательная проверка на Неопределено для СтрокаТаблицы
    Если СтрокаТаблицы = Неопределено Тогда
        // Скрываем элементы по умолчанию, если строка не выбрана
        Элементы.ЗаполнитьМОЛ.Видимость = Ложь;
        Элементы.ТоварыМОЛ.Видимость = Ложь;
        Возврат;
    КонецЕсли;
    
    // 2. Обязательная проверка на Неопределено для СчетУчетаБУ
    Если СтрокаТаблицы.СчетУчетаБУ = Неопределено Тогда
        // Скрываем элементы, если счет не выбран
        Элементы.ЗаполнитьМОЛ.Видимость = Ложь;
        Элементы.ТоварыМОЛ.Видимость = Ложь;
        Возврат;
    КонецЕсли;
    
    // ... дальнейший код для получения и сравнения кода счета
    // ...
КонецПроцедуры

Мы располагаем эти проверки в начале процедуры, чтобы избежать дальнейших ошибок и обеспечить корректное поведение формы. Если одна из проверок сработает, процедура завершит свою работу, не пытаясь обратиться к несуществующим данным.

Получение кода счета из ссылки

Как мы уже отметили, СтрокаТаблицы.СчетУчетаБУ — это ссылка. Чтобы получить код счета, который мы видим в интерфейсе (например, "1311"), нам необходимо обратиться к свойству .Код этого объекта-ссылки.


// ... предыдущие проверки на Неопределено
    
// Получаем код счета как строку
КодСчетаСтрока = СтрокаТаблицы.СчетУчетаБУ.Код;
    
// ... дальнейший код для обработки и сравнения

Теперь переменная КодСчетаСтрока будет содержать строковое представление кода счета, например, "1311".

Обработка кода счета: удаление лишних символов

Даже после получения кода счета как строки, мы можем столкнуться с новой проблемой при попытке преобразовать его в число или сравнить. В 1С коды счетов часто могут содержать различные символы, такие как точки или пробелы, например, "13.11", "1311 " или " 1311". Если эти символы присутствуют, прямое преобразование в число с помощью функции Число() вызовет ошибку "Преобразование значения к типу Число не может быть выполнено". Чтобы обеспечить корректное числовое сравнение, необходимо предварительно очистить строку кода счета от всех нежелательных символов. Мы используем для этого функции СтрЗаменить() для удаления точек и СокрЛП() для удаления начальных и конечных пробелов.


// ... предыдущий код для получения КодСчетаСтрока
    
// Очищаем код счета от пробелов и точек
// Сначала удаляем точки, затем удаляем пробелы, а СокрЛП() убирает начальные/конечные пробелы.
ОчищенныйКодСчетаСтрока = СтрЗаменить(КодСчетаСтрока, ".", "");
ОчищенныйКодСчетаСтрока = СтрЗаменить(ОчищенныйКодСчетаСтрока, " ", "");
ОчищенныйКодСчетаСтрока = СокрЛП(ОчищенныйКодСчетаСтрока); // На всякий случай, если пробелы остались
    
// ... дальнейший код для преобразования и сравнения

Обратите внимание, что порядок применения функций важен. Сначала мы удаляем точки, затем пробелы внутри строки (если они есть), а затем СокрЛП() "подчищает" лишние пробелы по краям.

Преобразование кода счета в число и сравнение

После того как мы получили чистую строковую версию кода счета, следующим шагом будет преобразование её в числовой тип. Это необходимо, потому что операторы сравнения (>=, <=) в 1С могут корректно работать только с примитивными типами данных одного вида, такими как числа, строки или даты. Попытка сравнить строку "1311" с числом 1311 или две строки "1311" и "1330" без понимания их числового значения может привести к некорректным результатам (например, "2" > "10" будет истина, если сравнивать как строки). Для преобразования используем функцию Число():


// ... предыдущий код для получения ОчищенныйКодСчетаСтрока
    
// Преобразуем очищенный код счета в число
КодСчетаЧисло = Число(ОчищенныйКодСчетаСтрока);
    
// Теперь можем выполнять числовое сравнение
Если КодСчетаЧисло >= 1311 И КодСчетаЧисло <= 1330 Тогда
    // Выполняем нужные действия
    Элементы.ЗаполнитьМОЛ.Видимость = Истина;
    Элементы.ТоварыМОЛ.Видимость = Истина;
Иначе
    // Если счет не попадает в диапазон
    Элементы.ЗаполнитьМОЛ.Видимость = Ложь;
    Элементы.ТоварыМОЛ.Видимость = Ложь;
КонецЕсли;

Теперь сравнение КодСчетаЧисло >= 1311 И КодСчетаЧисло <= 1330 будет работать абсолютно корректно, поскольку мы сравниваем два числа.

Полный пример кода для решения задачи

Собрав все рассмотренные шаги воедино, мы получаем надежную и корректно работающую процедуру:


&НаКлиенте
Процедура ОбновитьДоступностьКнопкиИРеквизита(Команда)
    
    // Начальные установки видимости элементов
    Элементы.ЗаполнитьМОЛ.Видимость = Ложь;
    Элементы.ТоварыМОЛ.Видимость = Ложь;

    // Получаем текущие данные выбранной строки табличной части
    СтрокаТаблицы = Элементы.Товары.ТекущиеДанные;
    
    // Шаг 1: Обязательная проверка на Неопределено для всей строки табличной части.
    // Если строка не выбрана (т.е. СтрокаТаблицы = Неопределено), то возвращаемся,
    // так как нет данных для анализа. Элементы останутся невидимыми, как установлено выше.
    Если СтрокаТаблицы = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Шаг 2: Обязательная проверка на Неопределено для реквизита СчетУчетаБУ.
    // Если в текущей строке табличной части счет не выбран (т.е. пустой),
    // то возвращаемся. Элементы останутся невидимыми.
    Если СтрокаТаблицы.СчетУчетаБУ = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Шаг 3: Получаем код счета из ссылки как строку.
    // СтрокаТаблицы.СчетУчетаБУ является ссылкой на элемент Плана счетов.
    // Для получения самого кода счета используем свойство .Код.
    Перем КодСчетаСтрока;
    Попытка
        КодСчетаСтрока = СтрокаТаблицы.СчетУчетаБУ.Код;
    Исключение
        // На случай, если по какой-то причине свойство .Код недоступно (хотя это маловероятно для ссылок)
        Возврат;
    КонецПопытки;

    // Шаг 4: Очищаем строковый код счета от нежелательных символов (точек, пробелов).
    // Это предотвратит ошибки при преобразовании в число, если код счета имеет формат,
    // например, "13.11" или " 1311 ".
    Перем ОчищенныйКодСчетаСтрока;
    ОчищенныйКодСчетаСтрока = СтрЗаменить(КодСчетаСтрока, ".", "");
    ОчищенныйКодСчетаСтрока = СтрЗаменить(ОчищенныйКодСчетаСтрока, " ", "");
    ОчищенныйКодСчетаСтрока = СокрЛП(ОчищенныйКодСчетаСтрока); // Удаляем начальные/конечные пробелы
    
    // Шаг 5: Преобразуем очищенную строку кода счета в число.
    // Это ключевой шаг для выполнения корректного числового сравнения по диапазону.
    Перем КодСчетаЧисло;
    Попытка
        КодСчетаЧисло = Число(ОчищенныйКодСчетаСтрока);
    Исключение
        // Если преобразование в число не удалось (например, если после очистки остался нечисловой символ),
        // то считаем, что счет не попадает в нужный диапазон.
        Элементы.ЗаполнитьМОЛ.Видимость = Ложь;
        Элементы.ТоварыМОЛ.Видимость = Ложь;
        Возврат;
    КонецПопытки;
    
    // Шаг 6: Выполняем числовое сравнение кода счета с заданным диапазоном.
    // Если код счета находится в диапазоне от 1311 до 1330 (включительно),
    // то делаем элементы видимыми. В противном случае они остаются скрытыми.
    Если КодСчетаЧисло >= 1311 И КодСчетаЧисло <= 1330 Тогда
        Элементы.ЗаполнитьМОЛ.Видимость = Истина;
        Элементы.ТоварыМОЛ.Видимость = Истина;
    Иначе
        Элементы.ЗаполнитьМОЛ.Видимость = Ложь;
        Элементы.ТоварыМОЛ.Видимость = Ложь;
    КонецЕсли;

КонецПроцедуры

Альтернативный подход: Использование списка ссылок на счета

В обсуждении также прозвучала идея использовать коллекцию счетов. Этот подход может быть полезен, если вам нужен фиксированный, небольшой список конкретных счетов (например, 1311, 1315, 1320), а не непрерывный диапазон. Однако для диапазонов чисел, как в нашей задаче, прямой числовой подход более эффективен и понятен. Если же вам действительно нужен список, то это можно реализовать следующим образом (обычно на сервере, чтобы избежать повторного создания списка при каждом вызове):


// Пример серверной функции для получения списка счетов
// Эта функция может быть помещена в общий модуль с галочками "Сервер" и "Вызов сервера"
// и вызываться из клиентского кода.
&НаСервере
Функция ПолучитьСписокЦелевыхСчетов()
    СписокСчетов = Новый СписокЗначений();
    // Добавляем ссылки на конкретные счета
    СписокСчетов.Добавить(ПланыСчетов.Хозрасчетный.НайтиПоКоду("1311"));
    СписокСчетов.Добавить(ПланыСчетов.Хозрасчетный.НайтиПоКоду("1315"));
    СписокСчетов.Добавить(ПланыСчетов.Хозрасчетный.НайтиПоКоду("1320"));
    // ... и так далее для всех нужных счетов
    Возврат СписокСчетов;
КонецФункции

// Пример использования на клиенте
&НаКлиенте
Процедура ОбновитьДоступностьКнопкиИРеквизитаАльтернативно(Команда)
    СтрокаТаблицы = Элементы.Товары.ТекущиеДанные;
    Если СтрокаТаблицы = Неопределено Тогда Возврат; КонецЕсли;
    Если СтрокаТаблицы.СчетУчетаБУ = Неопределено Тогда Возврат; КонецЕсли;
    
    // Вызываем серверную функцию для получения списка
    СписокЦелевыхСчетов = ПолучитьСписокЦелевыхСчетов(); 
    
    // Проверяем, содержится ли текущий счет в списке
    ВидимостьЭлементовМОЛ = (СписокЦелевыхСчетов.НайтиПоЗначению(СтрокаТаблицы.СчетУчетаБУ) <> Неопределено);
    
    Элементы.ЗаполнитьМОЛ.Видимость = ВидимостьЭлементовМОЛ;
    Элементы.ТоварыМОЛ.Видимость = ВидимостьЭлементовМОЛ;
КонецПроцедуры

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

Мы разобрали комплексное решение задачи по проверке кода бухгалтерского счета в 1С. Основные выводы, которые мы можем сделать: всегда проверяйте на Неопределено, получайте код счета через свойство .Код, очищайте строковый код от лишних символов и только после этого преобразуйте его в число для корректного сравнения по диапазону. Такой подход обеспечит стабильную работу вашего кода и предотвратит множество распространенных ошибок.

← На главную