Как настроить печать двух цен на одном ценнике в 1С:Розница 2.2

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

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

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

Почему данные из таблицы товаров на форме не попадают напрямую в макет?

Когда мы открываем обработку Обработка.ПечатьЭтикетокИЦенников, мы видим на форме таблицу Товары. Логично предположить, что добавление новой колонки (например, ЦенаХХ) в эту таблицу позволит сразу вывести ее на печать. Однако при нажатии кнопки «Печать» система не передает эту таблицу напрямую в макет ценника.

Вместо этого обработка использует механизм Схемы компоновки данных (СКД). Макет ценника — это фактически отчет СКД, который берет из таблицы на форме только ссылки на номенклатуру, характеристики и склады, а затем выполняет собственный запрос к базе данных (в частности, к регистру сведений ЦеныНоменклатуры). Именно поэтому добавленная «на лету» в таблицу на форме колонка не появляется в макете — СКД просто ничего не знает о её существовании.

---

Способ №1: Метод автора темы (Использование расширения и доп. реквизитов)

Рассмотрим решение, к которому пришел автор темы. Его идея заключается в том, чтобы использовать предопределенный механизм дополнительных реквизитов 1С для временного хранения расчетной цены.

Алгоритм реализации автора:

  1. Создается общий дополнительный реквизит номенклатуры с наименованием ЦенаХХ.
  2. В макет ценника добавляется поле, выводящее значение этого дополнительного реквизита.
  3. Через механизм расширений в обработку ПечатьЭтикетокИЦенников добавляется колонка ЦенаХХ в таблицу товаров на форме, где рассчитывается нужное значение.
  4. При нажатии на кнопку печати перед выводом ценников запускается обработчик, который записывает рассчитанное значение ЦенаХХ непосредственно в карточку каждой номенклатуры в базе данных.

Автор применил следующий код на сервере для записи значений перед печатью:


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

В чем опасность данного метода (Критический анализ)

Хотя этот метод работоспособен и решает задачу «здесь и сейчас», внедрять его в реальные рабочие базы данных категорически не рекомендуется по следующим причинам:

Поэтому проанализируем более безопасные и архитектурно правильные альтернативы.

---

Способ №2: Использование динамических видов цен (Без программирования)

Если ваша вторая цена рассчитывается по какому-то математическому алгоритму (например, «минус 10% от розничной» или «розничная цена деленная на коэффициент»), этот функционал можно настроить полностью стандартными средствами программы.

Разберем этот процесс по шагам:

  1. Перейдем в раздел Маркетинг — Настройки и справочники — Виды цен.
  2. Создадим новый вид цен, назовем его, например, Цена со скидкой (расчетная).
  3. В поле Способ задания цены выберем значение Динамический (по формуле).
  4. В открывшемся конструкторе формул напишем простое выражение. Например: [Розничная] * 0.9 (что означает автоматическое вычисление цены со скидкой 10% от текущей розничной цены). Сохраним вид цены.
  5. При открытии обработки печати этикеток и ценников укажем наш основной вид цены (Розничная), а в качестве дополнительного (акционного) вида цен выберем только что созданную динамическую цену.
  6. В макете ценника разместим стандартный параметр [Цена] для базовой цены и параметр [СпецЦена] (или [СтараяЦена]) для вывода нашей расчетной динамической цены.

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

---

Способ №3: Редактирование СКД макета ценника (Для сложных расчетов)

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

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

  1. Запустим базу данных в режиме Толстого клиента (управляемое приложение). Это необходимо для того, чтобы у нас была возможность редактировать СКД интерактивно.
  2. Откроем справочник Шаблоны этикеток, ценников и чеков ККМ, выберем нужный шаблон ценника и нажмем кнопку Редактировать макет.
  3. В появившемся окне нажмем на кнопку Редактировать схему компоновки.
  4. Перейдем на вкладку Вычисляемые поля. Здесь мы можем добавить свое поле, например, ЦенаХХ.
  5. В колонке Выражение напишем алгоритм расчета на встроенном языке СКД. Например:
    Выбор Когда Цена > 500 Тогда Цена * 0.85 Иначе Цена * 0.95 Конец.
  6. Перейдем на вкладку Настройки и добавим созданное поле в Выбранные поля компоновщика.
  7. Сохраним схему. Теперь в визуальном конструкторе макета ценника в списке доступных полей появится наше новое поле ЦенаХХ, которое можно перетащить в любую ячейку ценника.

---

Способ №4: Перехват данных через расширение (Для продвинутых разработчиков)

Бывают ситуации, когда расчет второй цены зависит от ручного ввода пользователя непосредственно в ТЧ Товары на форме печати ценников. Чтобы вывести эти данные без записи в базу данных, мы можем использовать перехват таблицы данных перед отправкой в процессор компоновки.

Для реализации этого метода:

  1. Создадим расширение конфигурации.
  2. Найдем в обработке ПечатьЭтикетокИЦенников экспортный метод, отвечающий за подготовку таблицы значений для печати (в разных релизах это может быть функция ПодготовитьДанныеДляПечати в модуле объекта или менеджера обработки).
  3. Добавим этот метод в расширение с аннотацией &После или &Вместо.
  4. В коде метода программно модифицируем возвращаемую таблицу значений, добавив в нее колонку ЦенаХХ, и заполним её данными из реквизита формы:

&После("ПодготовитьДанныеДляПечати")
Функция Расш1_ПодготовитьДанныеДляПечати(СписокТоваров, ИсточникДанных)
    // Получаем результат стандартного выполнения функции
    ТаблицаРезультат = ПродолжитьВызов(СписокТоваров, ИсточникДанных);
    
    // Добавляем колонку для нашей специальной цены
    ТаблицаРезультат.Колонки.Добавить("ЦенаХХ", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2)));
    
    // Заполняем колонку данными, сопоставляя строки по Номенклатуре и Характеристике
    Для Каждого СтрокаТЗ Из ТаблицаРезультат Цикл
        ПараметрыОтбора = Новый Структура("Номенклатура, Характеристика", СтрокаТЗ.Номенклатура, СтрокаТЗ.Характеристика);
        НайденныеСтроки = Объект.Товары.НайтиСтроки(ПараметрыОтбора);
        Если НайденныеСтроки.Количество() > 0 Тогда
            СтрокаФормы = НайденныеСтроки[0];
            СтрокаТЗ.ЦенаХХ = СтрокаФормы.ЦенаХХ;
        КонецЕсли;
    КонецЦикла;
    
    Возврат ТаблицаРезультат;
КонецФункции

Используя этот подход, мы полностью сохраняем производительность системы, избегаем блокировок базы данных и обеспечиваем вывод абсолютно любых расчетных данных на ценник пользователя.

← На главную