Как найти и заполнить недостающие PLU-коды для номенклатуры в «1С:Розница 1.0»?

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

При импорте больших объемов данных из внешних файлов (например, таблиц Excel) в конфигурацию «1С:Розница 1.0» (работающую на обычных формах) нередко возникает неприятная ситуация. Новые карточки товаров успешно создаются в справочнике Номенклатура, однако сопутствующий регистр сведений КодыТоваровPLU остается незаполненным. В результате эти товары становится невозможно выгрузить в кассы offline или электронные весы с печатью этикеток, поскольку торговое оборудование идентифицирует весовой и штучный товар именно по кодам PLU (Price Look-Up).

В рамках данной статьи мы подробно разберем, как решить эту задачу за два этапа. Сначала мы спроектируем оптимальный поисковый запрос к базе данных, чтобы быстро локализовать все проблемные позиции, а затем напишем эффективный алгоритм на встроенном языке 1С для автоматического присвоения и записи недостающих PLU-кодов.

Этап 1. Оптимизация запроса для поиска товаров без PLU-кодов

Для начала проанализируем структуру хранения данных. Связь между справочником товаров и их кодами PLU в «1С:Розница 1.0» реализована через независимый непериодический регистр сведений КодыТоваровPLU. На форумах часто предлагают использовать конструкции с подзапросами и отрицанием связи, например, через оператор НЕ ... В. Рассмотрим типичный пример такого запроса:


ВЫБРАТЬ
    Номенклатура.Ссылка КАК Ссылка
ИЗ
    Справочник.Номенклатура КАК Номенклатура
ГДЕ
    НЕ Номенклатура.Ссылка В
                (ВЫБРАТЬ
                КодыТоваровPLU.Номенклатура    
                ИЗ
                    РегистрСведений.КодыТоваровPLU КАК КодыТоваровPLU)

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

  1. Низкая производительность. Конструкция НЕ ... В заставляет СУБД выполнять ресурсоемкую операцию сканирования таблиц, что приводит к долгому выполнению запроса и избыточной нагрузке на дисковую подсистему сервера.
  2. Отсутствие фильтрации иерархии. Справочник Номенклатура является иерархическим. Запрос в примере выше вернет не только конкретные товары, но и папки (группы справочника). Попытка программно присвоить PLU-код группе приведет к ошибкам в логике работы программы.

Чтобы избежать этих проблем, применим более элегантное и быстрое решение — связь таблиц через ЛЕВОЕ СОЕДИНЕНИЕ с последующей фильтрацией по значению NULL в правой таблице, а также исключим группы справочника с помощью обращения к реквизиту ЭтоГруппа.

Рассмотрим оптимальный вариант поискового запроса:


ВЫБРАТЬ
    Номенклатура.Ссылка КАК Номенклатура,
    Номенклатура.ЕдиницаХраненияОстатков КАК ЕдиницаИзмерения
ИЗ
    Справочник.Номенклатура КАК Номенклатура
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КодыТоваровPLU КАК КодыТоваровPLU
        ПО Номенклатура.Ссылка = КодыТоваровPLU.Номенклатура
ГДЕ
    Номенклатура.ЭтоГруппа = ЛОЖЬ
    И КодыТоваровPLU.Номенклатура ЕСТЬ NULL

Выясним причину высокой скорости работы такого решения. Использование ЛЕВОЕ СОЕДИНЕНИЕ позволяет СУБД эффективно использовать индексы таблиц. Мы соединяем справочник товаров с регистром сведений по полю Ссылка. Проверка КодыТоваровPLU.Номенклатура ЕСТЬ NULL позволяет отобрать только те записи из левой таблицы (справочника), для которых не нашлось соответствия в правой (регистре сведений). Фильтр ЭтоГруппа = ЛОЖЬ гарантирует, что в выборку попадут только конечные элементы (карточки товаров), готовые к продаже.

Этап 2. Проектирование структуры регистра и подготовка к записи

Прежде чем приступать к написанию исполняемого кода заполнения, важно четко понимать структуру регистра сведений КодыТоваровPLU в конфигурации «1С:Розница 1.0». Этот регистр содержит следующие измерения и ресурсы:

Для создания новых записей нам понадобится механизм генерации уникальных кодов. Чтобы не затереть уже существующие коды PLU в базе данных, мы должны сначала определить максимальный занятый код, а затем последовательно наращивать его значение (использовать инкремент) для каждой новой записи.

Этап 3. Реализация алгоритма автоматического заполнения PLU-кодов

Ниже представлен готовый программный код, предназначенный для использования во внешней обработке. Разберем его по шагам.


// Шаг 1. Вычисляем текущий максимальный PLU-код в информационной базе
ЗапросМакс = Новый Запрос;
ЗапросМакс.Текст = 
    "ВЫБРАТЬ
    |    ЕСТЬNULL(МАКСИМУМ(КодыТоваровPLU.Код), 0) КАК МаксКод
    |ИЗ
    |    РегистрСведений.КодыТоваровPLU КАК КодыТоваровPLU";
    
ВыборкаМакс = ЗапросМакс.Выполнить().Выбрать();
ТекущийКод = 1;

Если ВыборкаМакс.Следующий() Тогда
    // Начинаем нумерацию со следующего свободного числа
    ТекущийКод = ВыборкаМакс.МаксКод + 1;
КонецЕсли;

// Шаг 2. Выгружаем список номенклатуры, у которой отсутствуют PLU-коды
ЗапросБезPLU = Новый Запрос;
ЗапросБезPLU.Текст = 
    "ВЫБРАТЬ
    |    Номенклатура.Ссылка КАК Номенклатура,
    |    Номенклатура.ЕдиницаХраненияОстатков КАК ЕдиницаИзмерения
    |ИЗ
    |    Справочник.Номенклатура КАК Номенклатура
    |    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КодыТоваровPLU КАК КодыТоваровPLU
    |        ПО Номенклатура.Ссылка = КодыТоваровPLU.Номенклатура
    |ГДЕ
    |    Номенклатура.ЭтоГруппа = ЛОЖЬ
    |    И КодыТоваровPLU.Номенклатура ЕСТЬ NULL";

Выборка = ЗапросБезPLU.Выполнить().Выбрать();

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

Рассмотрим подробнее важные технологические особенности этого алгоритма:

  1. Использование транзакции (НачатьТранзакцию() / ЗафиксироватьТранзакцию()). При обработке больших массивов данных (тысячи позиций) запись каждой строки по отдельности напрямую в базу данных может занять много времени из-за постоянных обращений к диску. Обертывание цикла в единую транзакцию значительно ускоряет процесс записи (в десятки раз) и защищает базу данных от частичного заполнения в случае сбоя.
  2. Менеджер записи (СоздатьМенеджерЗаписи()). Так как регистр сведений является независимым, мы работаем с каждой записью индивидуально через специальный объект метаданных 1С. Метод Записать(Истина) гарантирует, что даже если в системе возникнут дублирующие ключи, запись перезапишет старые некорректные данные, исключая зависание транзакции по причине конфликта блокировок.

Этап 4. Важные нюансы работы с PLU-кодами

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

Таким образом, комбинируя оптимизированный запрос и безопасную транзакционную запись через менеджер записи, мы можем быстро восстановить целостность данных в «1С:Розница 1.0» и обеспечить бесперебойную выгрузку товаров на кассы и весовое оборудование.

← На главную