В процессе работы с конфигурацией 1С:Управление нашей фирмой (УНФ) часто возникает необходимость сформировать историю цен поставщиков на основании ранее введенных документов поступления. Если при первичном проведении документов флаг регистрации цен не был установлен, регистр сведений ЦеныКонтрагентов остается пустым. Ручное перепроведение сотен накладных требует времени и может повлиять на оперативные данные. Разберем, как решить эту задачу как штатно, так и с помощью программных методов.
Проанализируем структуру хранения данных о ценах поставщиков в платформе 1С. Регистр сведений ЦеныКонтрагентов является периодическим и подчинен регистратору (документам ПриходнаяНакладная, УстановкаЦен и др.). Это накладывает определенные ограничения:
Прежде чем приступать к написанию собственного кода, рассмотрим стандартные механизмы программы, которые позволяют зафиксировать цены поставщиков:
УстановкаЦен. Это позволяет зарегистрировать цены без модификации проведенных первичных документов.ГрупповоеИзменениеРеквизитов можно проставить флаг РегистрироватьЦеныПоставщика во всех накладных за выбранный период с последующим групповым перепроведением документов.Если требуется написать обработку, которая заносит данные в регистр только при условии, что цена изменилась или отсутствует, рассмотрим эффективный алгоритм решения.
Частая ошибка разработчиков — чтение и перебор наборов записей (НаборЗаписей) в цикле по каждому документу. Это приводит к высокой нагрузке на систему. Правильный подход заключается в проверке существующих цен единым запросом к срезу последних.
Посмотрим на пример структуры запроса для проверки актуальных цен на дату документа:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТаблицаДокумента.Номенклатура КАК Номенклатура,
| ТаблицаДокумента.Характеристика КАК Характеристика,
| ТаблицаДокумента.Цена КАК НоваяЦена,
| ЕСТЬНУЛЛ(ЦеныСрез.Цена, 0) КАК ТекущаяЦена
|ИЗ
| Документ.ПриходнаяНакладная.Запасы КАК ТаблицаДокумента
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныКонтрагентов.СрезПоследних(&Период, ВидЦенКонтрагента = &ВидЦен) КАК ЦеныСрез
| ПО ТаблицаДокумента.Номенклатура = ЦеныСрез.Номенклатура
| И ТаблицаДокумента.Характеристика = ЦеныСрез.Характеристика
|ГДЕ
| ТаблицаДокумента.Ссылка = &СсылкаНаДокумент
| И (ЦеныСрез.Цена ИЗГОТОВИТЕЛЬ ИЛИ ЦеныСрез.Цена <> ТаблицаДокумента.Цена)";
Выясним, как правильно записать полученные данные в регистр сведений без выполнения полного цикла проведения документа. Для этого используется запись набора с включенным режимом загрузки данных.
Рассмотрим пример кода для записи движений по регистру:
// Создаем набор записей регистра по документу-регистратору
НаборЗаписей = РегистрыСведений.ЦеныКонтрагентов.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(СсылкаНаНакладную);
// Включаем режим обмена данными, чтобы отключить лишние проверки и обработчики
НаборЗаписей.ОбменДанными.Загрузка = Истина;
// Заполняем движения на основе подготовленных данных
Записи = НаборЗаписей.Добавить();
Записи.Период = СсылкаНаНакладную.Дата;
Записи.Регистратор = СсылкаНаНакладную;
Записи.ВидЦенКонтрагента = ВидЦен;
Записи.Номенклатура = СтрокаДанных.Номенклатура;
Записи.Характеристика = СтрокаДанных.Характеристика;
Записи.Цена = СтрокаДанных.НоваяЦена;
// Записываем набор в базу данных
НаборЗаписей.Записать();
Использование свойства ОбменДанными.Загрузка = Истина позволяет существенно ускорить процесс обработки исторических документов, избегая повторного вызова подписок на события и проверки остатков при перепроведении.