Как исправить ошибки «Переменная не определена» и «Элемент не выбран!» при изменении проводок в 1С

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

При разработке внешних обработок для корректировки бухгалтерских проводок начинающие разработчики часто сталкиваются с типовыми ошибками синтаксического контроля и времени выполнения. В этой статье подробно разберем, почему возникают ошибки «Переменная не определена» и «Элемент не выбран!», а также рассмотрим правильную работу с набором записей регистра бухгалтерии и субконто.

Анализ исходного кода и причин ошибок

Посмотрим на исходный пример процедуры, в котором возникли трудности:


&НаСервере
Процедура Команда1НаСервере()
    Операция = Объект.ОперацияБух.ПолучитьОбъект();
    Проводки = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();
    Проводки.Отбор.Регистратор.Установить(СсылкаНаДокумент);
    Проводки.Прочитать();
    Для каждого Проводка из НаборЗаписей Цикл
        Если Проводка.СчетКт = ПланыСчетов.Хозрасчетный.ПрочиеРасчетыСРазнымиДебиторамиИКредиторами Тогда 
            Проводка.СубконтоКт[Проводка.СчетКт.ВидыСубконто] = Объект.ДоговорКонтрагента;
            НаборЗаписей.СубконтоКт.Договоры = Объект.ДоговорКонтрагента;
        КонецЕсли;
    КонецЦикла;
    Проводки.Записать(); 
КонецПроцедуры

Выясним причину возникновения сообщений об ошибках:

  1. Неопределенная переменная СсылкаНаДокумент: в коде происходит попытка установить отбор по значению, которое нигде ранее не было объявлено и не было получено из реквизитов формы или объекта.
  2. Неопределенная переменная НаборЗаписей: при инициализации набору записей было присвоено имя Проводки, однако в цикле Для каждого разработчик обращается к переменной с другим именем — НаборЗаписей.
  3. Обращение к набору вместо строки: конструкция НаборЗаписей.СубконтоКт... ошибочна, поскольку набор записей — это табличная коллекция. Обращаться к реквизитам и субконто необходимо у конкретной строки коллекции — переменной Проводка.
  4. Некорректная индексация субконто: выражение Проводка.СчетКт.ВидыСубконто возвращает табличную часть счета (коллекцию строк видов субконто), а не конкретный вид субконто. Передача коллекции в квадратные скобки приводит к ошибке «Несоответствие типов».
  5. Ошибка времени выполнения «Элемент не выбран!»: метод ПолучитьОбъект() вызывается у пустой ссылки, когда пользователь на форме еще не выбрал документ в поле ОперацияБух.

Шаг 1. Исправление отбора и исключение лишних вызовов

Проанализируем первую строку: Операция = Объект.ОперацияБух.ПолучитьОбъект();. Если задача обработки заключается исключительно в чтении и перезаписи движений через регистр бухгалтерии, получать объект документа из базы данных не требуется. Получение объекта документа в память создает лишнюю нагрузку и приводит к падению программы, если реквизит не заполнен.

Для установки отбора в наборе записей достаточно обычной ссылки на документ, которая хранится в Объект.ОперацияБух. Перед установкой отбора обязательно добавим проверку на заполненность:


Если Не ЗначениеЗаполнено(Объект.ОперацияБух) Тогда
    ВызватьИсключение "Не выбран документ операции!";
КонецЕсли;

Проводки = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();
Проводки.Отбор.Регистратор.Установить(Объект.ОперацияБух);
Проводки.Прочитать();

Шаг 2. Корректный обход коллекции проводок и заполнение субконто

Разберем цикл по проводкам. Перебирать необходимо ту переменную, в которую был прочитан набор, то есть Проводки:


Для каждого Проводка Из Проводки Цикл
    // Работа с полями текущей строки проводки
КонецЦикла;

Теперь рассмотрим правильное заполнение субконто. В типовых конфигурациях обращение к субконто по имени через точку (например, Проводка.СубконтоКт.Договоры) допускается, только если в плане видов характеристик есть соответствующее предопределенное значение. Однако наиболее надежным и платформенным способом является обращение по индексу с передачей ссылки на вид субконто:


ВидСубконтоДоговоры = ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.Договоры;
Проводка.СубконтоКт[ВидСубконтоДоговоры] = Объект.ДоговорКонтрагента;

Для предотвращения ошибок также рекомендуется проверить, настроен ли у данного счета выбранный вид субконто с помощью метода Найти() по табличной части ВидыСубконто счета.

Шаг 3. Итоговый вариант решения через набор записей регистра

Соберем все исправления вместе. Добавим явную транзакцию для безопасной записи данных:


&НаСервере
Процедура Команда1НаСервере()
    Если Не ЗначениеЗаполнено(Объект.ОперацияБух) Тогда
        ВызватьИсключение "Пожалуйста, выберите операцию для обработки.";
    КонецЕсли;

    Проводки = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();
    Проводки.Отбор.Регистратор.Установить(Объект.ОперацияБух);
    Проводки.Прочитать();

    СчетПрочиеРасчеты = ПланыСчетов.Хозрасчетный.ПрочиеРасчетыСРазнымиДебиторамиИКредиторами;
    ВидСубконтоДоговоры = ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.Договоры;

    Модифицировано = Ложь;

    Для каждого Проводка Из Проводки Цикл
        Если Проводка.СчетКт = СчетПрочиеРасчеты Тогда
            // Проверяем, поддерживает ли счет данный вид субконто
            Если Проводка.СчетКт.ВидыСубконто.Найти(ВидСубконтоДоговоры, "ВидСубконто") <> Неопределено Тогда
                Проводка.СубконтоКт[ВидСубконтоДоговоры] = Объект.ДоговорКонтрагента;
                Модифицировано = Истина;
            КонецЕсли;
        КонецЕсли;
    КонецЦикла;

    Если Модифицировано Тогда
        НачатьТранзакцию();
        Попытка
            Проводки.Записать();
            ЗафиксироватьТранзакцию();
        Исключение
            ОтменитьТранзакцию();
            ВызватьИсключение;
        КонецПопытки;
    КонецЕсли;
КонецПроцедуры

Альтернативное решение: изменение проводок через объект документа

Для ручных операций бухгалтерского учета (документ ОперацияБух) в 1С более безопасным подходом считается работа через движения самого объекта документа. Это предотвращает коллизии параллельного изменения и гарантирует целостность данных документа и регистра.

Рассмотрим, как выглядит изменение проводок через сам объект документа:


&НаСервере
Процедура ИзменитьЧерезОбъект()
    Если Не ЗначениеЗаполнено(Объект.ОперацияБух) Тогда
        Возврат;
    КонецЕсли;

    ОперацияОбъект = Объект.ОперацияБух.ПолучитьОбъект();
    ДвиженияХозрасчетный = ОперацияОбъект.Движения.Хозрасчетный;
    ДвиженияХозрасчетный.Прочитать();

    СчетПрочиеРасчеты = ПланыСчетов.Хозрасчетный.ПрочиеРасчетыСРазнымиДебиторамиИКредиторами;
    ВидСубконтоДоговоры = ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.Договоры;

    Для каждого Проводка Из ДвиженияХозрасчетный Цикл
        Если Проводка.СчетКт = СчетПрочиеРасчеты Тогда
            Проводка.СубконтоКт[ВидСубконтоДоговоры] = Объект.ДоговорКонтрагента;
        КонецЕсли;
    КонецЦикла;

    ОперацияОбъект.Записать();
КонецПроцедуры

Важное отличие: при записи объекта документа (ОперацияОбъект.Записать()) платформа автоматически блокирует документ от одновременного редактирования другими сеансами и перезаписывает связанные движения регистра бухгалтерии.

← На главную