Как автоматически заполнить цену из справочника в табличную часть документа в 1С 8.3

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

В процессе разработки конфигураций на платформе 1С:Предприятие 8 часто возникает классическая задача: необходимо сделать так, чтобы при выборе товара в документе (например, в «Расходной накладной») его цена автоматически подтягивалась из карточки этого товара. Это значительно упрощает работу пользователя и минимизирует количество ошибок при вводе данных. Рассмотрим детально, как реализовать этот механизм, разберем типичные ошибки новичков и обсудим лучшие практики проектирования подобных систем.

Разбор базовой логики задачи

Прежде всего, проанализируем структуру наших данных. Допустим, у нас есть документ с табличной частью. В этой табличной части есть реквизит Номенклатура (ссылка на справочник) и реквизит Цена (число). В самом справочнике Номенклатура также есть реквизит Цена. Наша цель — в момент интерактивного изменения поля номенклатуры в строке документа программно найти цену этого объекта в базе данных и перенести ее в строку документа.

Реализация через обработчик события «ПриИзменении»

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

Рассмотрим пошагово, как должен выглядеть код в модуле управляемой формы документа:


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

&НаСервереБезКонтекста
Функция ПолучитьЦенуНаСервере(СсылкаНаНоменклатуру)
    
    // Возвращаем значение реквизита "Цена" из объекта справочника
    Возврат СсылкаНаНоменклатуру.Цена;
    
КонецФункции

Разберем, почему мы используем именно такую структуру. Код разбит на две части: клиентскую и серверную. На клиенте мы работаем с интерфейсом (получаем текущую строку), а на сервере — с данными базы (обращаемся к реквизиту справочника через точку). Использование директивы &НаСервереБезКонтекста является наиболее эффективным, так как при вызове такой функции на сервер не передаются данные всей формы, что ускоряет работу программы.

Важность правильного именования объектов

Проанализируем частую проблему, с которой сталкиваются начинающие разработчики: несовпадение имен в коде и в дереве метаданных. Если ваша табличная часть называется Продукция, а в коде вы пишете Объект.Товары, система выдаст ошибку «Поле объекта не обнаружено».

Выясним причину одной из популярных ошибок: использование метода НайтиПоИдентификатору(). Хотя этот метод рабочий, для получения данных текущей строки в управляемом интерфейсе гораздо удобнее использовать свойство Элементы.ИмяВашейТаблицы.ТекущиеДанные. Это избавляет от лишних манипуляций с индексами и идентификаторами строк.

Расширение функционала: расчет суммы и налогов

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


&НаКлиенте
Процедура ПересчитатьСуммуСтроки(СтрокаТабличнойЧасти)
    
    СтрокаТабличнойЧасти.Сумма = СтрокаТабличнойЧасти.Количество * СтрокаТабличнойЧасти.Цена;
    
КонецПроцедуры

&НаКлиенте
Процедура ТоварыНоменклатураПриИзменении(Элемент)
    ТекущиеДанные = Элементы.Товары.ТекущиеДанные;
    
    Если ТекущиеДанные <> Неопределено Тогда
        ТекущиеДанные.Цена = ПолучитьЦенуНаСервере(ТекущиеДанные.Номенклатура);
        // Сразу пересчитываем сумму
        ПересчитатьСуммуСтроки(ТекущиеДанные);
    КонецЕсли;
КонецПроцедуры

Проанализируем ситуацию: что если цена в справочнике не заполнена? В таком случае в документ подставится 0. Хорошим тоном считается информирование пользователя о том, что цена для данного товара не задана, чтобы избежать отгрузки товара по нулевой стоимости.

Архитектурный вопрос: где хранить цены?

Хотя в учебных примерах цена часто хранится прямо в реквизите справочника Номенклатура, в профессиональной разработке это считается плохой практикой. Разберем почему:

  1. История цен: Если вы измените цену в справочнике сегодня, вы не сможете узнать, какой она была вчера.
  2. Виды цен: У одного товара может быть несколько цен (оптовая, розничная, закупочная).
  3. Периодичность: Цены могут зависеть от даты документа.

Поэтому в реальных конфигурациях (таких как Управление торговлей или Бухгалтерия предприятия) цены хранятся в Регистрах сведений. В этом случае серверная функция получения цены будет выполнять запрос к регистру сведений на дату документа с учетом типа цены, указанного в шапке.

Оптимизация и безопасность

Посмотрим на пример оптимизации. Если вам нужно получить из справочника не только цену, но и, например, ставку НДС или единицу измерения, не стоит делать несколько серверных вызовов. Правильнее будет вернуть с сервера структуру данных:


&НаСервереБезКонтекста
Функция ПолучитьПараметрыНоменклатуры(СсылкаНаНоменклатуру)
    
    Результат = Новый Структура;
    Результат.Вставить("Цена", СсылкаНаНоменклатуру.Цена);
    Результат.Вставить("СтавкаНДС", СсылкаНаНоменклатуру.СтавкаНДС);
    Результат.Вставить("ЕдиницаИзмерения", СсылкаНаНоменклатуру.ЕдиницаИзмерения);
    
    Возврат Результат;
    
КонецФункции

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

Важный момент: обращение к реквизитам через точку на клиенте (например, ТекущиеДанные.Номенклатура.Цена) технически возможно в некоторых случаях, но крайне не рекомендуется. Это приводит к неявным серверным вызовам, которые могут существенно замедлить работу интерфейса при низкой скорости интернета или большой нагрузке на сервер.

Резюме

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

← На главную