Как реализовать документ установки цен номенклатуры с типами цен в колонках?

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

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

Архитектура данных: Хранение vs Отображение

Прежде всего, проанализируем важный архитектурный аспект: структура хранения данных в базе должна отличаться от структуры их представления на форме. В системе 1С данные о ценах хранятся в «плоском» виде в регистре сведений ЦеныНоменклатуры (измерения: Номенклатура, ТипЦен; ресурс: Цена). Пытаться создать документ с 20-ю жестко заданными колонками в табличной части — это ошибка, так как количество типов цен может меняться.

Рассмотрим правильный подход: в документе создается одна табличная часть Товары со следующими реквизитами:

  1. Номенклатура (СправочникСсылка.Номенклатура)
  2. ТипЦен (СправочникСсылка.ТипыЦенНоменклатуры)
  3. Цена (Число)
  4. КлючСтроки (Число) — для связи экранной таблицы с данными документа.

На форме же мы будем использовать вспомогательную ТаблицаЗначений, которую назовем ДеревоЦен или МатрицаЦен, и будем формировать её колонки программно.

Шаг 1: Программное создание динамических колонок

Выясним, как добавить колонки на форму в режиме «1С:Предприятие». Для этого используется метод ИзменитьРеквизиты. Разберем алгоритм действий в процедуре ПриСозданииНаСервере:


// Массив для новых реквизитов
ДобавляемыеРеквизиты = Новый Массив;
ВыбранныеТипыЦен = ПолучитьСписокТиповЦен(); // Ваша функция получения типов цен

Для Каждого ТипЦен Из ВыбранныеТипыЦен Цикл
    ИмяРеквизита = "Цена_" + СтрЗаменить(Строка(ТипЦен.УникальныйИдентификатор()), "-", "_");
    ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы(ИмяРеквизита, Новый ОписаниеТипов("Число", 15, 2), "Объект.Товары"));
КонецЦикла;

ИзменитьРеквизиты(ДобавляемыеРеквизиты);

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


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

Шаг 2: Заполнение данных и трансформация таблицы

Рассмотрим ситуацию, когда данные уже есть в табличной части документа, и их нужно «развернуть» в матрицу. Процесс трансформации данных из строк в колонки называется «пивот» (Pivot). Посмотрим на пример логики:

  1. Выгружаем табличную часть Товары в промежуточную таблицу значений.
  2. Сворачиваем её по колонке Номенклатура, чтобы получить уникальный список товаров.
  3. Для каждой строки номенклатуры обходим все созданные динамические колонки и ищем соответствующую цену в исходной табличной части.

Важный момент: чтобы при прокрутке больших списков (более 1000 позиций) интерфейс не «тормозил», рекомендуется фиксировать левые колонки с названием товара. Для этого используем свойство ФиксацияСлева у элемента таблицы формы.

Шаг 3: Синхронизация изменений

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

Во-первых, определим, в какой колонке произошло изменение. Имя элемента формы даст нам понять, какой это ТипЦен. Во-вторых, найдем строку в табличной части документа по идентификатору текущей строки формы. Проанализируем пример обработчика:


&НаКлиенте
Процедура Подключаемое_ПриИзмененииЦены(Элемент)
    ТекущиеДанные = Элементы.ТаблицаТовары.ТекущиеДанные;
    ИмяКолонки = Элемент.Имя;
    НоваяЦена = ТекущиеДанные[ИмяКолонки];
    
    // Вызываем серверную процедуру для обновления реальной ТЧ объекта
    ОбновитьЦенуВОбъекте(ТекущиеДанные.НомерСтроки, ИмяКолонки, НоваяЦена);
КонецПроцедуры

Дополнительные возможности в типовых решениях

Посмотрим, как аналогичные задачи решаются в конфигурациях Управление торговлей 11 или ERP 2. Там часто используется механизм «зависимых цен». Например, если «Розничная» цена рассчитывается как «Закупочная + 20%», то при изменении колонки с закупочной ценой код должен автоматически пересчитать значения во всех зависимых динамических колонках этой строки.

Для реализации такой логики рекомендуем:

В заключение отметим, что хотя визуально документ выглядит как широкая таблица, для системы 1С он остается набором строк. Главное — правильно настроить связь между экранными полями и данными объекта через КлючСтроки или Идентификатор. Это позволит сохранить целостность данных при записи документа в РегистрСведений.ЦеныНоменклатуры.

← На главную