Почему не записываются дополнительные реквизиты в 1С:Управление торговлей 11.5 при использовании УправлениеСвойствами.ЗаписатьСвойстваУОбъекта?

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

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

Наш читатель столкнулся именно с такой ситуацией. Задача заключалась в программном заполнении дополнительного реквизита для элементов справочника "Контрагенты" в УТ 11.5.17.155. Требовалось сформировать значение, комбинируя ИНН и КПП контрагента, и записать его в дополнительный реквизит с заголовком "УИДК".

Исходный код, демонстрирующий проблему

Представим исходный фрагмент кода, который был предложен автором для решения его задачи:


&НаСервере
Процедура Команда12()

    // 1. Создаем запрос для получения контрагентов
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |    Контрагенты.Ссылка КАК Объект
        |ИЗ
        |    Справочник.Контрагенты КАК Контрагенты
        |ГДЕ
        |    Контрагенты.ПометкаУдаления = &ПометкаУдаления";
    Запрос.УстановитьПараметр("ПометкаУдаления", Ложь);
    
    РезультатЗапроса = Запрос.Выполнить();
    ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
    
    Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
        об = ВыборкаДетальныеЗаписи.Объект; // Получаем ссылку на текущего контрагента
        
        // 2. Находим дополнительный реквизит по заголовку
        // Здесь предполагается, что реквизит с заголовком "УИДК" существует
        // и привязан к справочнику "Контрагенты"
        ДопРеквизитУИДК = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоРеквизиту("Заголовок", "УИДК");
        
        // 3. Подготавливаем таблицу значений для записи свойств
        ТаблицаДопРеквизитов = Новый ТаблицаЗначений;
        ТаблицаДопРеквизитов.Колонки.Добавить("Свойство", Новый ОписаниеТипов("ПланВидовХарактеристикСсылка.ДополнительныеРеквизитыИСведения"));
        ТаблицаДопРеквизитов.Колонки.Добавить("Значение", Новый ОписаниеТипов("Строка"));
        
        // 4. Добавляем новый реквизит и его значение в таблицу
        НовыйРекизит = ТаблицаДопРеквизитов.Добавить();
        НовыйРекизит.Свойство = ДопРеквизитУИДК;
        НовыйРекизит.Значение = Строка(об.ИНН) + "-" + Строка(об.КПП);
        
        // 5. Вызываем функцию БСП для записи свойств
        УправлениеСвойствами.ЗаписатьСвойстваУОбъекта(об.Ссылка, ТаблицаДопРеквизитов);
        
    КонецЦикла;
    
КонецПроцедуры

Автор кода подтвердил, что реквизит "УИДК" был найден, значение для него формировалось корректно, и даже в отладчике все выглядело правильно, но в итоге запись в базу данных не происходила. В чем же может быть причина такого поведения?

Анализ возможных причин и методы диагностики

Давайте пошагово рассмотрим основные причины, по которым УправлениеСвойствами.ЗаписатьСвойстваУОбъекта может не сохранять значения, и как их диагностировать.

  1. Некорректная привязка дополнительного реквизита к объекту метаданных

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

    Как мы можем проверить эту привязку?

    1. В пользовательском режиме:

      Перейдем в раздел "НСИ и администрирование" -> "Общие настройки" -> "Дополнительные реквизиты и сведения". Найдем наш реквизит "УИДК". Откроем его карточку и перейдем на закладку "Применение". Здесь мы увидим список объектов, к которым привязан данный дополнительный реквизит. Если в списке присутствует только "Контрагенты", но на самом деле в системе ожидается привязка к "Партнерам", то записи не произойдет. Нам нужно убедиться, что реквизит привязан к соответствующему типу объекта, в данном случае, вероятнее всего, к "Партнеры".

      Типовой объект, к которому привязываются дополнительные реквизиты, используемые для детализации контрагентов, часто является "Партнер". Это связано с логикой учета: Партнер представляет собой юридическое лицо или физическое лицо, с которым мы строим отношения, а Контрагент - это детализация этих отношений для конкретной организации, которая может быть одним из наших юридических лиц. Таким образом, общие реквизиты, такие как ИНН и КПП, которые, по сути, характеризуют юридическое лицо, логичнее привязывать к "Партнеру".

    2. Программная проверка (в отладчике):

      Во время отладки, после выполнения строки ДопРеквизитУИДК = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоРеквизиту("Заголовок", "УИДК");, мы можем посмотреть свойства объекта ДопРеквизитУИДК. В частности, нас будет интересовать свойство ВидВладельца или ВидыОбъектов, чтобы убедиться, что оно соответствует типу объекта, который мы пытаемся передать в УправлениеСвойствами.ЗаписатьСвойстваУОбъекта.

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

  2. Ошибка в поиске реквизита: "Заголовок" против "Имя"

    При использовании ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоРеквизиту("Заголовок", "УИДК") мы ищем реквизит по его представлению для пользователя. Хотя это часто работает, более надежным способом является поиск по "Имени". "Имя" — это уникальный идентификатор реквизита, который не меняется при переименовании "Заголовка". Если в системе случайно окажется несколько реквизитов с одинаковым "Заголовком", поиск может вернуть не тот, который мы ожидаем.

    Чтобы найти "Имя" реквизита, мы можем открыть его в пользовательском режиме, затем нажать "Еще" -> "Изменить" и посмотреть его программное имя. Или же получить его программно, выполнив запрос к плану видов характеристик.

    Пример поиска по имени:

    
    // Предполагаем, что имя реквизита "УИДК"
    ДопРеквизитУИДК = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("УИДК");
    // Или, если это Заголовок, но есть риск совпадений, можно так:
    ДопРеквизитУИДК = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоРеквизиту("Заголовок", "УИДК");
    // Затем, для верности, можно проверить его Имя
    // Если ДопРеквизитУИДК.Имя <> "УИДК" Тогда Сообщить("Найден не тот реквизит!"); КонецЕсли;
    
  3. Несоответствие типа значения дополнительного реквизита

    Убедимся, что тип значения, которое мы пытаемся записать, соответствует типу, указанному для дополнительного реквизита при его создании. В нашем случае реквизит "УИДК" явно предназначен для хранения строки, и мы формируем строку из ИНН и КПП. Однако, если бы реквизит был, например, "Дата", а мы пытались записать строку, это могло бы привести к ошибке или неявной конвертации, которая не всегда корректно отрабатывает.

    Тип данных для колонки "Значение" в ТаблицаДопРеквизитов должен быть достаточно широким, чтобы вместить любой допустимый тип значения, который может быть присвоен дополнительному реквизиту. Обычно используется Новый ОписаниеТипов("Произвольный") или Новый ОписаниеТипов("Строка"), если мы точно знаем, что реквизит строковый.

  4. Проверка параметров функции УправлениеСвойствами.ЗаписатьСвойстваУОбъекта

    Функция ожидает два основных параметра:

    • ВладелецСвойств: ссылка на объект, для которого записываются свойства. Важно передавать именно ссылку на объект, а не сам объект (например, СправочникСсылка.Контрагенты, а не СправочникОбъект.Контрагенты). В нашем коде передается об.Ссылка, что является корректным.
    • ТаблицаСвойствИЗначений: таблица значений, которая должна содержать две колонки: "Свойство" (тип ПланВидовХарактеристикСсылка.ДополнительныеРеквизитыИСведения) и "Значение" (произвольный тип, допустимый для свойства). Структура таблицы в коде также соответствует требованиям.

    Если один из этих параметров неверен, функция может отработать некорректно.

  5. Глубокая отладка процедуры БСП

    Если все предыдущие шаги не помогли выявить причину, необходимо использовать отладчик и углубиться в саму процедуру УправлениеСвойствами.ЗаписатьСвойстваУОбъекта. Поставим точку останова на вызове этой процедуры и шаг за шагом пройдемся по ее внутреннему коду. Это позволит нам увидеть, на каком именно этапе происходит "Отказ" или почему значение не записывается в регистр сведений, где хранятся дополнительные реквизиты (обычно это РегистрСведений.ЗначенияСвойствОбъектов).

Решение проблемы: Правильная привязка к "Партнерам"

Как выяснилось, корень проблемы заключался в некорректной привязке дополнительного реквизита. В УТ 11.5 дополнительные реквизиты, относящиеся к юридическим аспектам контрагента (такие как ИНН, КПП и, соответственно, их комбинации), чаще всего должны быть привязаны к справочнику "Партнеры", а не напрямую к "Контрагенты".

Для того чтобы решить эту проблему, нам необходимо:

  1. Убедиться, что дополнительный реквизит "УИДК" привязан к объекту "Партнеры" в настройках конфигурации (НСИ и администрирование -> Общие настройки -> Дополнительные реквизиты и сведения).
  2. Изменить код таким образом, чтобы мы получали не ссылку на "Контрагента", а ссылку на соответствующего "Партнера" и передавали ее в функцию УправлениеСвойствами.ЗаписатьСвойстваУОбъекта.

Давайте посмотрим, как можно модифицировать исходный код, чтобы он корректно работал с привязкой к "Партнерам".

Оптимизация запроса и кода для решения проблемы

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

Вот оптимизированный и исправленный код:


&НаСервере
Процедура Команда12()

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

    Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
        // 3. Получаем ссылку на Партнера (владельца свойств) из выборки
        ПартнерОбъект = ВыборкаДетальныеЗаписи.Партнер;
        
        // 4. Проверяем, что Партнер найден и не пустой (для случаев, когда контрагент может быть без партнера)
        Если ПартнерОбъект = Неопределено Или ПартнерОбъект = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.ПустаяСсылка() Тогда
            Сообщить("Для контрагента " + Строка(ВыборкаДетальныеЗаписи.Объект) + " не указан Партнер. Пропускаем.");
            Продолжить;
        КонецЕсли;

        // 5. Формируем значение для дополнительного реквизита
        ЗначениеУИДК = Строка(ВыборкаДетальныеЗаписи.ИНН) + "-" + Строка(ВыборкаДетальныеЗаписи.КПП);
        
        // 6. Подготавливаем таблицу значений для записи свойств
        ТаблицаДопРеквизитов = Новый ТаблицаЗначений;
        ТаблицаДопРеквизитов.Колонки.Добавить("Свойство", Новый ОписаниеТипов("ПланВидовХарактеристикСсылка.ДополнительныеРеквизитыИСведения"));
        ТаблицаДопРеквизитов.Колонки.Добавить("Значение", Новый ОписаниеТипов("Строка")); // Тип данных "Строка" для "УИДК"

        // 7. Добавляем новый реквизит и его значение в таблицу
        НовыйРекизит = ТаблицаДопРеквизитов.Добавить();
        НовыйРекизит.Свойство = ДопРеквизитУИДК;
        НовыйРекизит.Значение = ЗначениеУИДК;
        
        // 8. Вызываем функцию БСП для записи свойств, передавая ссылку на Партнера
        Попытка
            УправлениеСвойствами.ЗаписатьСвойстваУОбъекта(ПартнерОбъект, ТаблицаДопРеквизитов);
        Исключение
            Сообщить("Не удалось записать УИДК для Партнера " + Строка(ПартнерОбъект) + ". Ошибка: " + ОписаниеОшибки());
        КонецПопытки;
        
    КонецЦикла;
    
КонецПроцедуры

Подробное объяснение изменений

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

    
    Запрос.Текст = 
        "ВЫБРАТЬ
        |    Контрагенты.Ссылка КАК Объект,
        |    Контрагенты.Партнер КАК Партнер,
        |    Контрагенты.ИНН КАК ИНН,
        |    Контрагенты.КПП КАК КПП
        |ИЗ
        |    Справочник.Контрагенты КАК Контрагенты
        |ГДЕ
        |    Контрагенты.ПометкаУдаления = &ПометкаУдаления";
    
  2. Получение ссылки на Партнера: Вместо использования об.Ссылка (ссылка на контрагента), мы теперь используем ПартнерОбъект = ВыборкаДетальныеЗаписи.Партнер;. Именно эта ссылка передается в качестве первого параметра в функцию УправлениеСвойствами.ЗаписатьСвойстваУОбъекта.

    
    ПартнерОбъект = ВыборкаДетальныеЗаписи.Партнер;
    ...
    УправлениеСвойствами.ЗаписатьСвойстваУОбъекта(ПартнерОбъект, ТаблицаДопРеквизитов);
    

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

  3. Обработка случаев отсутствия Партнера: Мы добавили проверку на случай, если для какого-либо контрагента не указан партнер. Это повышает отказоустойчивость обработки, предотвращая возможные ошибки при попытке записи свойств для неопределенного объекта.

    
    Если ПартнерОбъект = Неопределено Или ПартнерОбъект = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.ПустаяСсылка() Тогда
        Сообщить("Для контрагента " + Строка(ВыборкаДетальныеЗаписи.Объект) + " не указан Партнер. Пропускаем.");
        Продолжить;
    КонецЕсли;
    
  4. Обработка ошибок записи: Добавили блок Попытка...Исключение вокруг вызова функции записи. Это позволит в случае возникновения непредвиденных ошибок при записи свойства для конкретного партнера не прерывать выполнение всей обработки, а лишь зафиксировать проблему и продолжить работу с остальными элементами.

    
    Попытка
        УправлениеСвойствами.ЗаписатьСвойстваУОбъекта(ПартнерОбъект, ТаблицаДопРеквизитов);
    Исключение
        Сообщить("Не удалось записать УИДК для Партнера " + Строка(ПартнерОбъект) + ". Ошибка: " + ОписаниеОшибки());
    КонецПопытки;
    

Заключение

Проблема с незаписывающимися дополнительными реквизитами в 1С:Управление торговлей 11.5, использующими функцию УправлениеСвойствами.ЗаписатьСвойстваУОбъекта, чаще всего кроется в несоответствии типа объекта, к которому программно пытаются привязать реквизит, и типа объекта, к которому реквизит фактически привязан в настройках конфигурации. В случае с "Контрагентами" в УТ 11.5 часто бывает необходимо работать через основной справочник "Партнеры".

Помните о важности следующих моментов при работе с дополнительными реквизитами:

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

← На главную