При автоматизации процессов в конфигурациях, работающих на обычных формах (таких как Управление торговлей 10.3, Управление производственным предприятием 1.3 или Комплексная автоматизация 1.1), программисты часто сталкиваются с задачей программного создания документа УстановкаЦенНоменклатуры. Основная сложность заключается в том, что в экранной форме документа мы видим одну строку с товаром и несколько колонок с ценами, а в структуре базы данных это хранится совершенно иначе. Рассмотрим подробно, как правильно связать данные, чтобы документ корректно отображался и проводился.
Прежде чем приступать к написанию кода, проанализируем внутреннее устройство документа. Он состоит из двух ключевых табличных частей, которые работают в связке:
Для того чтобы система «понимала», какие строки из таблицы Товары относятся к одной позиции номенклатуры и должны быть показаны в одной строке на форме, используется служебный реквизит ИндексСтрокиТаблицыЦен. Именно в нем кроется решение проблемы «размножения» строк на форме.
На этой механике строится и загрузка номенклатуры из прайс-листа с иерархией и установка цен.
Рассмотрим процесс создания документа с нуля. Предположим, у нас есть массив товаров (например, если выполняется загрузка номенклатуры из прайс-листа Excel), и для каждого нужно установить базовую и розничную цену. Выясним, как правильно организовать циклы и заполнить индексы.
// Создаем новый объект документа
ДокУЦ = Документы.УстановкаЦенНоменклатуры.СоздатьДокумент();
ДокУЦ.Дата = ТекущаяДата();
ДокУЦ.Ответственный = Пользователи.ТекущийПользователь;
// 1. Заполняем табличную часть "ТипыЦен"
// Это определит, какие колонки будут видны в документе
ВидЦенаБазовая = Справочники.ТипыЦенНоменклатуры.НайтиПоНаименованию("Базовая");
ВидЦенаРозничная = Справочники.ТипыЦенНоменклатуры.НайтиПоНаименованию("Розничная");
НоваяСтрокаТипа = ДокУЦ.ТипыЦен.Добавить();
НоваяСтрокаТипа.ТипЦен = ВидЦенаБазовая;
НоваяСтрокаТипа = ДокУЦ.ТипыЦен.Добавить();
НоваяСтрокаТипа.ТипЦен = ВидЦенаРозничная;
// 2. Заполняем таблицу "Товары"
// Допустим, данные мы берем из некой ТЗ "ТаблицаДанных"
ИндексТовара = 0; // Начинаем индексацию с нуля
Для Каждого СтрДанные Из ТаблицаДанных Цикл
// Устанавливаем Базовую цену для текущего товара
НоваяСтрока = ДокУЦ.Товары.Добавить();
НоваяСтрока.Номенклатура = СтрДанные.Номенклатура;
НоваяСтрока.ТипЦен = ВидЦенаБазовая;
НоваяСтрока.Цена = СтрДанные.ЦенаБазовая;
НоваяСтрока.Валюта = СтрДанные.Валюта; // Обязательно к заполнению
НоваяСтрока.ЕдиницаИзмерения = СтрДанные.Номенклатура.ЕдиницаХраненияОстатков;
НоваяСтрока.ИндексСтрокиТаблицыЦен = ИндексТовара; // Общий индекс для этого товара
// Устанавливаем Розничную цену для этого же товара
НоваяСтрока = ДокУЦ.Товары.Добавить();
НоваяСтрока.Номенклатура = СтрДанные.Номенклатура;
НоваяСтрока.ТипЦен = ВидЦенаРозничная;
НоваяСтрока.Цена = СтрДанные.ЦенаРозничная;
НоваяСтрока.Валюта = СтрДанные.Валюта;
НоваяСтрока.ЕдиницаИзмерения = СтрДанные.Номенклатура.ЕдиницаХраненияОстатков;
НоваяСтрока.ИндексСтрокиТаблицыЦен = ИндексТовара; // Тот же индекс!
// Увеличиваем индекс для следующего товара в списке
ИндексТовара = ИндексТовара + 1;
КонецЦикла;
ДокУЦ.Записать(РежимЗаписиДокумента.Запись);
Если вы присвоите каждой строке в таблице Товары уникальный ИндексСтрокиТаблицыЦен (например, просто используя НомерСтроки), то при открытии документа 1С отобразит каждую цену как отдельную позицию номенклатуры. Это крайне неудобно для пользователя. В таких случаях часто помогает загрузка из Эксель справочника номенклатуры и цен.
Запомните правило: все цены, которые должны находиться в одной горизонтальной строке в интерфейсе, должны иметь одинаковое значение в поле ИндексСтрокиТаблицыЦен. При этом значения ТипЦен внутри этой группы должны различаться. Такая логика необходима, когда строится конвейер прайс-листов для установки цен на основе цен поставщика.
Иногда требуется не создать новый документ, а программно изменить цены в уже существующих. Рассмотрим ситуацию, когда нужно установить фиксированную цену (например, 5000) для конкретного товара во всех документах за период.
В таких случаях мы рекомендуем использовать следующий подход:
Запроса или Выборки.Товары и ищем нужную номенклатуру.
Выборка = Документы.УстановкаЦенНоменклатуры.Выбрать(ДатаНачала, ДатаОкончания);
Пока Выборка.Следующий() Цикл
ДокОбъект = Выборка.ПолучитьОбъект();
Модифицирован = Ложь;
Для Каждого СтрокаТовара Из ДокОбъект.Товары Цикл
Если СтрокаТовара.Номенклатура = ИскомыйТовар Тогда
СтрокаТовара.Цена = 5000;
Модифицирован = Истина;
КонецЕсли;
КонецЦикла;
Если Модифицирован Тогда
// Записываем с проведением, чтобы обновились записи в регистрах сведений
ДокОбъект.Записать(РежимЗаписиДокумента.Проведение);
КонецЕсли;
КонецЦикла;
Проанализируем несколько технических моментов, которые часто упускают начинающие разработчики:
УстановкаЦенНоменклатуры эти реквизиты являются обязательными для каждой строки. Если их не заполнить, цена может быть корректно записана в документ, но «не подхватится» в заказах или реализациях, так как в регистре сведений ЦеныНоменклатуры образуются пустые измерения.ХарактеристикаНоменклатуры. Если цена общая для всех характеристик — оставляйте поле пустым (Справочники.ХарактеристикиНоменклатуры.ПустаяСсылка()).ЗаполнитьПоУстановленнымСпособамФормированияЦен().ОбменДанными.Загрузка = Истина, чтобы ускорить процесс. Однако помните, что при этом не сработают стандартные проверки и автоматические расчеты в модуле документа.Таким образом, мы выяснили, что ключ к правильному заполнению установки цен — это строгое соблюдение индексации строк и синхронизация двух табличных частей. Используя предложенные шаблоны кода, вы сможете автоматизировать установку цен любой сложности.