Как автоматически удалить дублирующиеся цены в разных валютах в 1С:Управление торговлей 11?

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

В процессе импорта прайс-листов или первоначальной настройки базы данных «1С:Управление торговлей 11» (на платформе 1С:Предприятие 8.3) пользователи часто сталкиваются с ситуацией, когда для одной и той же номенклатурной позиции регистрируется несколько цен в разных валютах. Например, базовая цена товара установлена в USD или EUR, но система также импортировала для него цену в национальной валюте (грн/руб). При формировании прайс-листа или подборе товаров это создает путаницу.

В этой статье мы подробно разберем, как решить эту проблему. Мы рассмотрим архитектуру хранения цен в 1С:УТ 11, изучим альтернативные варианты настройки ценообразования без программирования, а также напишем готовую обработку для автоматической очистки лишних цен из базы данных.

Разбор архитектуры: Где хранятся цены в 1С:УТ 11?

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

  1. Цены поставщиков: Хранятся в периодическом регистре сведений ЦеныНоменклатурыПоставщиков. Записи в этот регистр вносятся документами «Регистрация цен поставщика» или автоматически создаются при проведении документов «Приобретение товаров и услуг».
  2. Собственные продажные цены: Хранятся в периодическом регистре сведений ЦеныНоменклатуры. Они регистрируются исключительно документом УстановкаЦенНоменклатуры.

Важное правило разработки в 1С: Регистр сведений ЦеныНоменклатуры является подчиненным регистратору (документу). Это означает, что мы не имеем права напрямую удалять или изменять записи в самом регистре сведений с помощью набора записей. Если мы сделаем это напрямую в регистре, то при первом же перепроведении документов-регистраторов (например, документов «Установка цен номенклатуры») все удаленные цены вернутся обратно. Корректировать данные нужно строго в самих документах-источниках.

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

Давайте проанализируем бизнес-логику. Если цены импортируются от поставщиков в валюте (USD/EUR), а продавать товары необходимо в национальной валюте с определенной наценкой, то физически хранить и постоянно очищать цены в национальной валюте вообще не требуется. Мы можем настроить автоматический пересчет.

Рассмотрим, как это сделать по шагам:

  1. Перейдем в раздел CRM и маркетинг — Настройки и справочники — Виды цен.
  2. Создадим базовый вид цены, например «Цена поставщика (USD)», с валютой USD. Настроим ее заполнение по данным импорта или документов поставки.
  3. Создадим подчиненный (расчетный) вид цены, например «Дистрибьюторская (грн)», с валютой UAH (или руб).
  4. Установим способ задания цены: Наценка на другой вид цен или Рассчитывать по формуле.
  5. В редакторе формул мы можем написать логическое условие. Например, использовать оператор выбора для определения валюты-источника:

Выбор
    Когда [ЦенаПоставщикаUSD] > 0 Тогда [ЦенаПоставщикаUSD] * [КурсUSD] * 1.15
    Иначе [ЦенаПоставщикаUAH] * 1.15
Конец

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

Решение 2. Использование типовой обработки «Очистка цен» (для версий УТ 11.5+)

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

  1. Откройте форму списка Виды цен.
  2. Найдите ссылку или кнопку Очистить цены (ее доступность зависит от прав пользователя).
  3. Этот инструмент позволяет удалить устаревшие, нулевые или дублирующиеся записи из регистра сведений, снижая общую нагрузку на базу данных.

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

Решение 3. Создание программной обработки для удаления лишних цен

Рассмотрим технический алгоритм работы нашей будущей внешней обработки. Нам необходимо решить три последовательные задачи:

  1. Найти номенклатуру, у которой одновременно установлены цены в валюте (USD/EUR) и в национальной валюте (UAH/RUB).
  2. Определить документы-регистраторы («Установка цен номенклатуры»), которые сделали записи по национальной валюте для этих позиций.
  3. Программно открыть эти документы, удалить из их табличных частей строки с целевой номенклатурой и перепровести документы.

Шаг 1. Написание поискового запроса

Для поиска дублирующихся позиций мы напишем запрос к регистру сведений ЦеныНоменклатуры.СрезПоследних. Мы сделаем внутреннее соединение таблицы валютных цен с таблицей цен в национальной валюте по полю Номенклатура. Это позволит нам гарантированно отобрать только те товары, у которых заполнены оба вида цен.


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ЦеныВалюта.Номенклатура КАК Номенклатура,
    |	ЦеныГрн.Регистратор КАК РегистраторГрн
    |ИЗ
    |	РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, ВидЦены.Валюта В (&ВалютыИсключения)) КАК ЦеныВалюта
    |		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, ВидЦены.Валюта = &ВалютаГрн) КАК ЦеныГрн
    |		ПО ЦеныВалюта.Номенклатура = ЦеныГрн.Номенклатура";

Шаг 2. Программный обход документов и удаление строк

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

Ниже представлен пример программного кода для реализации этой логики в модуле обработки:


// Подготовим параметры запроса
Запрос.УстановитьПараметр("Период", ТекущаяДата());

ВалютыИсключения = Новый Массив;
ВалютыИсключения.Добавить(Справочники.Валюты.НайтиПоКоду("840")); // USD
ВалютыИсключения.Добавить(Справочники.Валюты.НайтиПоКоду("978")); // EUR
Запрос.УстановитьПараметр("ВалютыИсключения", ВалютыИсключения);

// Предположим, что базовая лишняя валюта имеет код 980 (UAH)
ВалютаГрн = Справочники.Валюты.НайтиПоКоду("980"); 
Запрос.УстановитьПараметр("ВалютаГрн", ВалютаГрн);

РезультатЗапроса = Запрос.Выполнить();
Если РезультатЗапроса.Пустой() Тогда
    Сообщить("Дублирующиеся цены не найдены.");
    Возврат;
КонецЕсли;

Выборка = РезультатЗапроса.Выбрать();

// Сгруппируем номенклатуру по документам-регистраторам
ДокументыДляОбработки = Новый Соответствие;
Пока Выборка.Следующий() Цикл
    Если ДокументыДляОбработки[Выборка.РегистраторГрн] = Неопределено Тогда
        ДокументыДляОбработки.Вставить(Выборка.РегистраторГрн, Новый Массив);
    КонецЕсли;
    ДокументыДляОбработки[Выборка.РегистраторГрн].Добавить(Выборка.Номенклатура);
КонецЦикла;

// Начнем транзакционную обработку документов
Для Каждого ЗаписьИзСоответствия Из ДокументыДляОбработки Цикл
    ДокументСсылка = ЗаписьИзСоответствия.Ключ;
    МассивТоваров = ЗаписьИзСоответствия.Значение;
    
    // Получаем объект документа для изменения
    ДокОбъект = ДокументСсылка.ПолучитьОбъект();
    Если ДокОбъект = Неопределено Тогда
        Сообщить("Не удалось получить объект документа: " + ДокументСсылка, СтатусСообщения.Важное);
        Продолжить;
    КонецЕсли;
    
    Модифицирован = Ложь;
    
    // Обходим табличную часть "Товары" с конца, чтобы избежать смещения индексов при удалении строк
    Индекс = ДокОбъект.Товары.Количество() - 1;
    Пока Индекс >= 0 Цикл
        СтрокаТовара = ДокОбъект.Товары[Индекс];
        
        // Если номенклатура из строки есть в списке лишних - удаляем ее
        Если МассивТоваров.Найти(СтрокаТовара.Номенклатура) <> Неопределено Тогда
            ДокОбъект.Товары.Удалить(СтрокаТовара);
            Модифицирован = Истина;
        КонецЕсли;
        
        Индекс = Индекс - 1;
    КонецЦикла;
    
    // Записываем и проводим документ только в случае реальных изменений
    Если Модифицирован Тогда
        Попытка
            ДокОбъект.Записать(РежимЗаписиДокумента.Проведение);
            Сообщить("Успешно обработан документ: " + ДокументСсылка);
        Исключение
            Сообщить("Ошибка проведения документа " + ДокументСсылка + ": " + ОписаниеОшибки(), СтатусСообщения.Внимание);
        КонецПопытки;
    КонецЕсли;
КонецЦикла;

Рекомендации по запуску обработки в рабочей базе

Поскольку программное удаление строк из документов «Установка цен номенклатуры» напрямую влияет на историю цен компании, перед запуском алгоритма обязательно выполните следующие правила предосторожности:

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

← На главную