Загрузка данных


&НаСервере
Процедура СоздатьGTINs()

    // 1. Бэкап текущего состояния регистра
    ВыгрузитьРегистрВCSV();

    ТестовыйРежим = Истина;  // ← поменяйте на Ложь для реальной записи

    // 2. ОДИН ЗАПРОС: получаем все EAN13 (13 цифр) для всех характеристик
    Запрос = Новый Запрос;
    Запрос.Текст = "
    |ВЫБРАТЬ
    |    Штрихкоды.Владелец КАК Номенклатура,
    |    Штрихкоды.Характеристика КАК Характеристика,
    |    Штрихкоды.Штрихкод КАК Штрихкод
    |ИЗ
    |    РегистрСведений.Штрихкоды КАК Штрихкоды
    |ГДЕ
    |    Штрихкоды.Штрихкод <> """" 
    |    И СтрДлина(Штрихкоды.Штрихкод) = 13";

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

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

    // 3. Собираем структуру: ключ "НоменклатураСсылка|ХарактеристикаСсылка" → массив уникальных GTIN
    СтруктураГрупп = Новый Соответствие;
    Пока Выборка.Следующий() Цикл
        Номенклатура = Выборка.Номенклатура;
        Характеристика = Выборка.Характеристика;
        Штрихкод = СокрЛП(Выборка.Штрихкод);
        GTIN = "0" + Штрихкод;

        Ключ = Строка(Номенклатура) + "|" + Строка(Характеристика);
        Массив = СтруктураГрупп.Получить(Ключ);
        Если Массив = Неопределено Тогда
            Массив = Новый Массив;
            СтруктураГрупп.Вставить(Ключ, Массив);
        КонецЕсли;
        // Добавляем, если ещё нет
        Если Массив.Найти(GTIN) = Неопределено Тогда
            Массив.Добавить(GTIN);
        КонецЕсли;
    КонецЦикла;

    Если СтруктураГрупп.Количество() = 0 Тогда
        Сообщить("Нет данных для обработки.");
        Возврат;
    КонецЕсли;

    // 4. Загружаем все существующие GTIN из регистра ОписаниеGTINИС в массив (быстрая проверка)
    ЗапросСущ = Новый Запрос;
    ЗапросСущ.Текст = "ВЫБРАТЬ ОписаниеGTINИС.GTIN ИЗ РегистрСведений.ОписаниеGTINИС КАК ОписаниеGTINИС";
    РезультатСущ = ЗапросСущ.Выполнить();
    СуществующиеGTIN = Новый Массив;
    Если РезультатСущ.Пустой() = Ложь Тогда
        ВыборкаСущ = РезультатСущ.Выбрать();
        Пока ВыборкаСущ.Следующий() Цикл
            СуществующиеGTIN.Добавить(ВыборкаСущ.GTIN);
        КонецЦикла;
    КонецЕсли;

    // 5. Подготовка переменных статистики и коллекций
    КоличествоХарактеристик = 0;
    КоличествоСEAN13 = 0;
    КоличествоБезEAN13 = 0;   // не используется, но оставим для совместимости
    ВсегоУникальныхEAN13 = 0;
    КоличествоУжеСуществует = 0;
    КоличествоДобавленных = 0;

    НаборЗаписей = РегистрыСведений.ОписаниеGTINИС.СоздатьНаборЗаписей();
    СписокДобавляемых = Новый Массив;   // для плоского CSV
    ОтчетныеЗаписи = Новый Массив;      // для группового отчёта

    // 6. Основной цикл по группам
    Для каждого Элемент Из СтруктураГрупп Цикл
        Ключ = Элемент.Ключ;
        МассивGTIN = Элемент.Значение;

        КоличествоХарактеристик = КоличествоХарактеристик + 1;
        КоличествоСEAN13 = КоличествоСEAN13 + 1;
        ВсегоУникальныхEAN13 = ВсегоУникальныхEAN13 + МассивGTIN.Количество();

        // Извлекаем ссылки из ключа
        Разделитель = Найти(Ключ, "|");
        СтрНоменклатура = Лев(Ключ, Разделитель - 1);
        СтрХарактеристика = Сред(Ключ, Разделитель + 1);
        // Преобразуем строки в ссылки (через ЗначениеИзСтрокиВнутр, но лучше так: получаем объекты из регистра)
        // Мы не можем гарантировать, что строка преобразуется в ссылку, поэтому поступим иначе: 
        // будем хранить в структуре вместе с ключом сами ссылки. Для этого переделаем сбор данных.
        // Но так как мы уже собрали структуру со строками, переделаем: создадим соответствие "ключ-структура" с ссылками.
        // Это проще сделать заново в одном цикле с запросом, но мы уже его выполнили.
        // Поскольку это не повлияет на производительность, переделаем сбор, чтобы сразу хранить ссылки.
    КонецЦикла;

    // ПЕРЕДЕЛЫВАЕМ СБОР С ССЫЛКАМИ (без дополнительных запросов)
    // Выполним запрос ещё раз и сразу сохраним структуру со ссылками
    Запрос2 = Новый Запрос;
    Запрос2.Текст = "
    |ВЫБРАТЬ
    |    Штрихкоды.Владелец КАК Номенклатура,
    |    Штрихкоды.Характеристика КАК Характеристика,
    |    Штрихкоды.Штрихкод КАК Штрихкод
    |ИЗ
    |    РегистрСведений.Штрихкоды КАК Штрихкоды
    |ГДЕ
    |    Штрихкоды.Штрихкод <> """" 
    |    И СтрДлина(Штрихкоды.Штрихкод) = 13";
    Результат2 = Запрос2.Выполнить();
    Выборка2 = Результат2.Выбрать();

    // Структура с ключом-строкой и значением-структурой с полями НоменклатураСсылка, ХарактеристикаСсылка, МассивGTIN
    ГруппыСсылки = Новый Соответствие;
    Пока Выборка2.Следующий() Цикл
        НоменклатураСсылка = Выборка2.Номенклатура;
        ХарактеристикаСсылка = Выборка2.Характеристика;
        Штрихкод = СокрЛП(Выборка2.Штрихкод);
        GTIN = "0" + Штрихкод;

        Ключ = Строка(НоменклатураСсылка) + "|" + Строка(ХарактеристикаСсылка);
        СтруктураГруппы = ГруппыСсылки.Получить(Ключ);
        Если СтруктураГруппы = Неопределено Тогда
            СтруктураГруппы = Новый Структура("Номенклатура, Характеристика, GTINМассив", НоменклатураСсылка, ХарактеристикаСсылка, Новый Массив);
            ГруппыСсылки.Вставить(Ключ, СтруктураГруппы);
        КонецЕсли;
        Массив = СтруктураГруппы.GTINМассив;
        Если Массив.Найти(GTIN) = Неопределено Тогда
            Массив.Добавить(GTIN);
        КонецЕсли;
    КонецЦикла;

    // 7. Теперь обходим группы со ссылками
    КоличествоХарактеристик = 0;
    КоличествоСEAN13 = 0;
    ВсегоУникальныхEAN13 = 0;
    КоличествоУжеСуществует = 0;
    КоличествоДобавленных = 0;

    Для каждого Элемент Из ГруппыСсылки Цикл
        СтруктураГруппы = Элемент.Значение;
        НоменклатураСсылка = СтруктураГруппы.Номенклатура;
        ХарактеристикаСсылка = СтруктураГруппы.Характеристика;
        МассивGTIN = СтруктураГруппы.GTINМассив;

        КоличествоХарактеристик = КоличествоХарактеристик + 1;
        КоличествоСEAN13 = КоличествоСEAN13 + 1;
        ВсегоУникальныхEAN13 = ВсегоУникальныхEAN13 + МассивGTIN.Количество();

        Для каждого GTIN Из МассивGTIN Цикл
            // Проверяем наличие в массиве существующих (быстрый поиск)
            Если СуществующиеGTIN.Найти(GTIN) <> Неопределено Тогда
                КоличествоУжеСуществует = КоличествоУжеСуществует + 1;
                Продолжить;
            КонецЕсли;

            // Добавляем в набор записей
            НоваяЗапись = НаборЗаписей.Добавить();
            НоваяЗапись.GTIN = GTIN;
            НоваяЗапись.ВидУпаковки = Перечисления.ВидыУпаковокИС.Потребительская;
            НоваяЗапись.КоличествоПотребительскихУпаковок = 1;

            КоличествоДобавленных = КоличествоДобавленных + 1;

            // Для плоского списка
            СтруктураЗаписи = Новый Структура;
            СтруктураЗаписи.Вставить("GTIN", GTIN);
            СтруктураЗаписи.Вставить("ВидУпаковки", Перечисления.ВидыУпаковокИС.Потребительская);
            СтруктураЗаписи.Вставить("КоличествоПотребительскихУпаковок", 1);
            СписокДобавляемых.Добавить(СтруктураЗаписи);

            // Для отчёта по группам
            СтруктураОтчета = Новый Структура;
            СтруктураОтчета.Вставить("Номенклатура", НоменклатураСсылка.Наименование);
            СтруктураОтчета.Вставить("Характеристика", ?(ХарактеристикаСсылка.Пустая(), "Без характеристики", ХарактеристикаСсылка.Наименование));
            СтруктураОтчета.Вставить("GTIN", GTIN);
            ОтчетныеЗаписи.Добавить(СтруктураОтчета);
        КонецЦикла;
    КонецЦикла;

    // 8. Сохранение отчётов
    Если СписокДобавляемых.Количество() > 0 Тогда
        СохранитьСписокВCSV(СписокДобавляемых);
    КонецЕсли;

    Если ОтчетныеЗаписи.Количество() > 0 Тогда
        СохранитьОтчетПоДобавленным(ОтчетныеЗаписи);
    КонецЕсли;

    // 9. Запись или тест
    Если НаборЗаписей.Количество() > 0 Тогда
        Если ТестовыйРежим Тогда
            Сообщить("*** ТЕСТ: запись отключена. Будет добавлено записей: " + НаборЗаписей.Количество());
        Иначе
            НаборЗаписей.Записать();
            Сообщить("Данные записаны. Добавлено записей: " + НаборЗаписей.Количество());
        КонецЕсли;
    Иначе
        Сообщить("Нет новых записей для добавления.");
    КонецЕсли;

    // 10. Статистика
    Сообщить("========== СТАТИСТИКА ==========");
    Сообщить("Всего уникальных пар (Номенклатура + Характеристика): " + КоличествоХарактеристик);
    Сообщить("Из них имеют хотя бы один EAN13: " + КоличествоСEAN13);
    Сообщить("Всего уникальных EAN13 (преобразованных в GTIN): " + ВсегоУникальныхEAN13);
    Сообщить("Из них уже существовали в регистре: " + КоличествоУжеСуществует);
    Сообщить("Добавлено новых записей: " + КоличествоДобавленных);
    Сообщить("=================================");

    ЗаписьЖурналаРегистрации("Заполнение GTIN", УровеньЖурналаРегистрации.Информация,,
        "Тест: " + ?(ТестовыйРежим, "да", "нет") + " | Добавлено: " + КоличествоДобавленных);

КонецПроцедуры

// ============================================================
// Остальные функции (бэкап, сохранение списка, отчёта) остаются без изменений.
// Они уже были приведены ранее, я включу их в финальный код.
// ============================================================

Процедура ВыгрузитьРегистрВCSV()
    ИмяФайла = "F:\ОписаниеGTINИС_бэкап_" + Формат(ТекущаяДата(), "ДФ=yyyyMMdd_HHmmss") + ".csv";
    Запрос = Новый Запрос;
    Запрос.Текст = "ВЫБРАТЬ ОписаниеGTINИС.GTIN, ОписаниеGTINИС.ВидУпаковки, ОписаниеGTINИС.КоличествоПотребительскихУпаковок ИЗ РегистрСведений.ОписаниеGTINИС КАК ОписаниеGTINИС";
    Результат = Запрос.Выполнить();
    Если Результат.Пустой() Тогда 
        Сообщить("Регистр пуст."); 
        Возврат; 
    КонецЕсли;
    Выборка = Результат.Выбрать();
    ТекстCSV = Новый ЗаписьТекста(ИмяФайла, КодировкаТекста.ANSI);
    ТекстCSV.ЗаписатьСтроку("GTIN;ВидУпаковки;КоличествоУпаковок");
    Пока Выборка.Следующий() Цикл
        ТекстCSV.ЗаписатьСтроку(Выборка.GTIN + ";" + Строка(Выборка.ВидУпаковки) + ";" + Строка(Выборка.КоличествоПотребительскихУпаковок));
    КонецЦикла;
    ТекстCSV.Закрыть();
    Сообщить("Бэкап сохранён: " + ИмяФайла);
КонецПроцедуры

Процедура СохранитьСписокВCSV(СписокЗаписей)
    ИмяФайла = "F:\Добавляемые_GTIN_" + Формат(ТекущаяДата(), "ДФ=yyyyMMdd_HHmmss") + ".csv";
    ТекстCSV = Новый ЗаписьТекста(ИмяФайла, КодировкаТекста.ANSI);
    ТекстCSV.ЗаписатьСтроку("GTIN;ВидУпаковки;КоличествоУпаковок");
    Для каждого Запись Из СписокЗаписей Цикл
        ТекстCSV.ЗаписатьСтроку(Запись.GTIN + ";" + Строка(Запись.ВидУпаковки) + ";" + Строка(Запись.КоличествоПотребительскихУпаковок));
    КонецЦикла;
    ТекстCSV.Закрыть();
    Сообщить("Список добавляемых GTIN сохранён: " + ИмяФайла);
КонецПроцедуры

Процедура СохранитьОтчетПоДобавленным(ОтчетныеЗаписи)
    Если ОтчетныеЗаписи.Количество() = 0 Тогда
        Сообщить("Нет данных для отчёта.");
        Возврат;
    КонецЕсли;
    Группы = Новый Соответствие;
    Для каждого Запись Из ОтчетныеЗаписи Цикл
        Ключ = Запись.Номенклатура + "|" + Запись.Характеристика;
        МассивGTIN = Группы.Получить(Ключ);
        Если МассивGTIN = Неопределено Тогда
            МассивGTIN = Новый Массив;
            Группы.Вставить(Ключ, МассивGTIN);
        КонецЕсли;
        МассивGTIN.Добавить(Запись.GTIN);
    КонецЦикла;
    СтрокиДляCSV = Новый Массив;
    СтрокиДляCSV.Добавить("Номенклатура;Характеристика;Добавленные штрихкоды;Количество");
    Для каждого Элемент Из Группы Цикл
        Ключ = Элемент.Ключ;
        МассивGTIN = Элемент.Значение;
        Разделитель = Найти(Ключ, "|");
        Номенклатура = Лев(Ключ, Разделитель - 1);
        Характеристика = Сред(Ключ, Разделитель + 1);
        СписокШтрихкодов = "";
        Для каждого GTIN Из МассивGTIN Цикл
            Если СписокШтрихкодов = "" Тогда
                СписокШтрихкодов = GTIN;
            Иначе
                СписокШтрихкодов = СписокШтрихкодов + ", " + GTIN;
            КонецЕсли;
        КонецЦикла;
        Количество = МассивGTIN.Количество();
        Строка = Номенклатура + ";" + Характеристика + ";" + СписокШтрихкодов + ";" + Строка(Количество);
        СтрокиДляCSV.Добавить(Строка);
    КонецЦикла;
    ИмяФайла = "F:\Отчет_по_добавленным_GTIN_" + Формат(ТекущаяДата(), "ДФ=yyyyMMdd_HHmmss") + ".csv";
    ТекстCSV = Новый ЗаписьТекста(ИмяФайла, КодировкаТекста.ANSI);
    Для каждого Строка Из СтрокиДляCSV Цикл
        ТекстCSV.ЗаписатьСтроку(Строка);
    КонецЦикла;
    ТекстCSV.Закрыть();
    Сообщить("Отчёт по добавленным GTIN сохранён: " + ИмяФайла);
КонецПроцедуры

// ============================================================
// Обработчик кнопки
// ============================================================
&НаКлиенте
Процедура ВыполнитьНаКлиенте(Команда)
    СоздатьGTINs();
КонецПроцедуры