В процессе импорта прайс-листов или первоначальной настройки базы данных «1С:Управление торговлей 11» (на платформе 1С:Предприятие 8.3) пользователи часто сталкиваются с ситуацией, когда для одной и той же номенклатурной позиции регистрируется несколько цен в разных валютах. Например, базовая цена товара установлена в USD или EUR, но система также импортировала для него цену в национальной валюте (грн/руб). При формировании прайс-листа или подборе товаров это создает путаницу.
В этой статье мы подробно разберем, как решить эту проблему. Мы рассмотрим архитектуру хранения цен в 1С:УТ 11, изучим альтернативные варианты настройки ценообразования без программирования, а также напишем готовую обработку для автоматической очистки лишних цен из базы данных.
Перед тем как приступать к написанию обработок, нам необходимо четко понимать, где именно в системе хранятся эти данные. В конфигурации «1С:Управление торговлей 11» архитектура хранения цен жестко разделена по назначению:
ЦеныНоменклатурыПоставщиков. Записи в этот регистр вносятся документами «Регистрация цен поставщика» или автоматически создаются при проведении документов «Приобретение товаров и услуг».ЦеныНоменклатуры. Они регистрируются исключительно документом УстановкаЦенНоменклатуры.Важное правило разработки в 1С: Регистр сведений ЦеныНоменклатуры является подчиненным регистратору (документу). Это означает, что мы не имеем права напрямую удалять или изменять записи в самом регистре сведений с помощью набора записей. Если мы сделаем это напрямую в регистре, то при первом же перепроведении документов-регистраторов (например, документов «Установка цен номенклатуры») все удаленные цены вернутся обратно. Корректировать данные нужно строго в самих документах-источниках.
Давайте проанализируем бизнес-логику. Если цены импортируются от поставщиков в валюте (USD/EUR), а продавать товары необходимо в национальной валюте с определенной наценкой, то физически хранить и постоянно очищать цены в национальной валюте вообще не требуется. Мы можем настроить автоматический пересчет.
Рассмотрим, как это сделать по шагам:
Выбор
Когда [ЦенаПоставщикаUSD] > 0 Тогда [ЦенаПоставщикаUSD] * [КурсUSD] * 1.15
Иначе [ЦенаПоставщикаUAH] * 1.15
Конец
При таком подходе система будет автоматически «на лету» пересчитывать актуальную продажную цену в нужной валюте при выписке документов или формировании прайс-листа. Лишние импортированные цены не будут мешать работе, так как формулы обращаются только к актуальным базовым значениям.
Если на вашем предприятии используется современная версия конфигурации (начиная с 11.5), то разработчики 1С добавили в систему встроенный инструмент очистки неактуальных цен. Чтобы им воспользоваться, выполните следующие действия:
Тем не менее, этот механизм не всегда позволяет гибко сопоставить цены в разных валютах для конкретных позиций номенклатуры. Для решения специфической задачи автора нам потребуется написать собственную обработку.
Рассмотрим технический алгоритм работы нашей будущей внешней обработки. Нам необходимо решить три последовательные задачи:
Для поиска дублирующихся позиций мы напишем запрос к регистру сведений ЦеныНоменклатуры.СрезПоследних. Мы сделаем внутреннее соединение таблицы валютных цен с таблицей цен в национальной валюте по полю Номенклатура. Это позволит нам гарантированно отобрать только те товары, у которых заполнены оба вида цен.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЦеныВалюта.Номенклатура КАК Номенклатура,
| ЦеныГрн.Регистратор КАК РегистраторГрн
|ИЗ
| РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, ВидЦены.Валюта В (&ВалютыИсключения)) КАК ЦеныВалюта
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, ВидЦены.Валюта = &ВалютаГрн) КАК ЦеныГрн
| ПО ЦеныВалюта.Номенклатура = ЦеныГрн.Номенклатура";
После выполнения запроса мы получим выборку, содержащую номенклатуру и ссылку на документ-регистратор, установивший ненужную цену. Нам необходимо сгруппировать данные по регистраторам, чтобы не открывать и не записывать один и тот же документ многократно.
Ниже представлен пример программного кода для реализации этой логики в модуле обработки:
// Подготовим параметры запроса
Запрос.УстановитьПараметр("Период", ТекущаяДата());
ВалютыИсключения = Новый Массив;
ВалютыИсключения.Добавить(Справочники.Валюты.НайтиПоКоду("840")); // USD
ВалютыИсключения.Добавить(Справочники.Валюты.НайтиПоКоду("978")); // EUR
Запрос.УстановитьПараметр("ВалютыИсключения", ВалютыИсключения);
// Предположим, что базовая лишняя валюта имеет код 980 (UAH)
ВалютаГрн = Справочники.Валюты.НайтиПоКоду("980");
Запрос.УстановитьПараметр("ВалютаГрн", ВалютаГрн);
РезультатЗапроса = Запрос.Выполнить();
Если РезультатЗапроса.Пустой() Тогда
Сообщить("Дублирующиеся цены не найдены.");
Возврат;
КонецЕсли;
Выборка = РезультатЗапроса.Выбрать();
// Сгруппируем номенклатуру по документам-регистраторам
ДокументыДляОбработки = Новый Соответствие;
Пока Выборка.Следующий() Цикл
Если ДокументыДляОбработки[Выборка.РегистраторГрн] = Неопределено Тогда
ДокументыДляОбработки.Вставить(Выборка.РегистраторГрн, Новый Массив);
КонецЕсли;
ДокументыДляОбработки[Выборка.РегистраторГрн].Добавить(Выборка.Номенклатура);
КонецЦикла;
// Начнем транзакционную обработку документов
Для Каждого ЗаписьИзСоответствия Из ДокументыДляОбработки Цикл
ДокументСсылка = ЗаписьИзСоответствия.Ключ;
МассивТоваров = ЗаписьИзСоответствия.Значение;
// Получаем объект документа для изменения
ДокОбъект = ДокументСсылка.ПолучитьОбъект();
Если ДокОбъект = Неопределено Тогда
Сообщить("Не удалось получить объект документа: " + ДокументСсылка, СтатусСообщения.Важное);
Продолжить;
КонецЕсли;
Модифицирован = Ложь;
// Обходим табличную часть "Товары" с конца, чтобы избежать смещения индексов при удалении строк
Индекс = ДокОбъект.Товары.Количество() - 1;
Пока Индекс >= 0 Цикл
СтрокаТовара = ДокОбъект.Товары[Индекс];
// Если номенклатура из строки есть в списке лишних - удаляем ее
Если МассивТоваров.Найти(СтрокаТовара.Номенклатура) <> Неопределено Тогда
ДокОбъект.Товары.Удалить(СтрокаТовара);
Модифицирован = Истина;
КонецЕсли;
Индекс = Индекс - 1;
КонецЦикла;
// Записываем и проводим документ только в случае реальных изменений
Если Модифицирован Тогда
Попытка
ДокОбъект.Записать(РежимЗаписиДокумента.Проведение);
Сообщить("Успешно обработан документ: " + ДокументСсылка);
Исключение
Сообщить("Ошибка проведения документа " + ДокументСсылка + ": " + ОписаниеОшибки(), СтатусСообщения.Внимание);
КонецПопытки;
КонецЕсли;
КонецЦикла;
Поскольку программное удаление строк из документов «Установка цен номенклатуры» напрямую влияет на историю цен компании, перед запуском алгоритма обязательно выполните следующие правила предосторожности:
Используя предложенные методики, вы сможете навести порядок в ценообразовании вашей компании, оптимизировать хранение прайс-листов и исключить ошибки при расчете цен.