При разработке конфигураций в системе 1С:Предприятие одной из самых частых задач является автоматизация ввода данных. Пользователь не должен вводить цену вручную, если она уже определена для товара в справочнике. Рассмотрим подробно, как реализовать механизм, при котором при выборе номенклатуры в табличной части документа цена подставляется автоматически, а сумма пересчитывается мгновенно.
Прежде чем переходить к написанию кода, проанализируем, в какой момент система должна выполнить действие. В 1С работа с интерфейсом строится на событиях. Нам необходимо, чтобы действие произошло сразу после того, как пользователь выбрал товар в конкретной строке. Для этого идеально подходит обработчик события ПриИзменении. Это событие возникает в тот момент, когда значение в поле выбора было изменено и подтверждено пользователем.
Разберем по шагам, где именно создавать этот обработчик. Если наша табличная часть называется Товары, а колонка с товаром — Товар (или Номенклатура), то в свойствах этого поля на форме нужно найти событие «ПриИзменении» и создать процедуру в модуле формы.
Одной из главных проблем новичков является обращение к данным таблицы. Часто пытаются обращаться к реквизитам документа напрямую, что приводит к ошибкам, так как в таблице может быть множество строк. Выясним причину: программа должна точно знать, в какую именно строку «положить» цену. Для этого мы используем конструкцию Элементы.Товары.ТекущиеДанные.
ТекущиеДанные — это объект, который содержит данные именно той строки, в которой сейчас находится курсор пользователя или где происходит редактирование. Обращаясь к этому объекту, мы получаем доступ ко всем колонкам этой строки: Товар, Цена, Количество, Сумма.
Рассмотрим пример кода, который решает задачу переноса цены. Предположим, что в справочнике Товары у нас есть реквизит Цена, и в документе в табличной части Товары тоже есть реквизит Цена. Посмотрим на логику:
&НаКлиенте
Процедура ТоварыТоварПриИзменении(Элемент)
// Получаем строку, в которой пользователь изменил товар
СтрокаТаблицы = Элементы.Товары.ТекущиеДанные;
// Проверяем, что товар действительно выбран (не очищен)
Если ЗначениеЗаполнено(СтрокаТаблицы.Товар) Тогда
// Получаем цену из справочника через точку от ссылки на товар
// И записываем её в колонку "Цена" текущей строки
СтрокаТаблицы.Цена = СтрокаТаблицы.Товар.Цена;
// Сразу вызываем расчет суммы, чтобы данные были актуальны
РассчитатьСуммуСтроки(СтрокаТаблицы);
КонецЕсли;
КонецПроцедуры
В процессе обсуждения часто возникает вопрос: «Как программа поймет, к какой именно цене я обращаюсь, если они называются одинаково?». Проанализируем ситуацию. Когда мы пишем СтрокаТаблицы.Цена, мы обращаемся к реквизиту табличной части документа. Когда мы пишем СтрокаТаблицы.Товар.Цена, мы идем «через точку»: сначала получаем ссылку на объект в справочнике (Товар), а затем берем его свойство (Цена). 1С четко разделяет эти области видимости, поэтому конфликта имен не происходит.
Чтобы автоматизация была полной, нам необходимо реализовать пересчет суммы при изменении любого из параметров: цены или количества. Проанализируем ситуацию: логика пересчета одинакова для обоих случаев. Поэтому правильным подходом будет вынесение этой логики в отдельную процедуру. Это позволит избежать дублирования кода.
&НаКлиенте
Процедура РассчитатьСуммуСтроки(СтрокаТаблицы)
// Сумма = Цена * Количество
СтрокаТаблицы.Сумма = СтрокаТаблицы.Цена * СтрокаТаблицы.Количество;
КонецПроцедуры
&НаКлиенте
Процедура ТоварыКоличествоПриИзменении(Элемент)
СтрокаТаблицы = Элементы.Товары.ТекущиеДанные;
РассчитатьСуммуСтроки(СтрокаТаблицы);
КонецПроцедуры
&НаКлиенте
Процедура ТоварыЦенаПриИзменении(Элемент)
СтрокаТаблицы = Элементы.Товары.ТекущиеДанные;
РассчитатьСуммуСтроки(СтрокаТаблицы);
КонецПроцедуры
Рассмотрим подробнее архитектуру управляемого приложения. При работе в режиме «Тонкий клиент» прямое обращение через точку к реквизитам справочника (как в примере СтрокаТаблицы.Товар.Цена) может работать медленно или быть недоступным в зависимости от настроек платформы. Профессиональным подходом считается получение данных на стороне сервера.
Если простая подстановка не срабатывает, разберем более надежный способ с использованием серверной функции:
&НаКлиенте
Процедура ТоварыТоварПриИзменении(Элемент)
СтрокаТаблицы = Элементы.Товары.ТекущиеДанные;
Если ЗначениеЗаполнено(СтрокаТаблицы.Товар) Тогда
// Вызываем серверную функцию для получения цены
СтрокаТаблицы.Цена = ПолучитьЦенуТовараНаСервере(СтрокаТаблицы.Товар);
РассчитатьСуммуСтроки(СтрокаТаблицы);
КонецЕсли;
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПолучитьЦенуТовараНаСервере(СсылкаНаТовар)
// Возвращаем значение реквизита "Цена" из справочника "Товары"
Возврат СсылкаНаТовар.Цена;
КонецФункции
Использование директивы &НаСервереБезКонтекста позволяет максимально быстро получить данные, не передавая всю форму на сервер, что значительно ускоряет работу программы.
В процессе реализации начинающие разработчики часто сталкиваются со следующими проблемами:
ЗначениеЗаполнено().ТекущиеДанные в управляемых формах это обычно происходит автоматически.Разберем также вопрос хранения цен. Помните, что хранение цены непосредственно в справочнике Товары — это упрощенная модель, подходящая для учебных задач. В реальном бизнесе цены постоянно меняются. Посмотрим на перспективу: в будущем вам может потребоваться использовать Регистры сведений, чтобы хранить историю цен и подставлять ту цену, которая была актуальна на дату документа.
Подводя итог, можно сказать, что связка события ПриИзменении, объекта ТекущиеДанные и серверной функции для получения реквизитов — это стандарт «золотого сечения» при разработке интерфейсов в 1С. Реализовав эту логику один раз, вы сможете применять её для любых типов документов, будь то заказы, накладные или акты выполненных работ.