Загрузка данных
//++Варнин А.А. Задача №72300 - 27.07.26
#Область РегламентноеЗадание_кор_ВыгрузкаЗакупочныхЦен
Процедура ВыполнитьВыгрузкуЗакупочныхЦен() Экспорт
ИмяСобытия = "Выгрузка закупочных цен";
НачалоРаботы = ТекущаяУниверсальнаяДатаВМиллисекундах();
ЗаписьЖурналаРегистрации(ИмяСобытия, УровеньЖурналаРегистрации.Информация, , , "Старт выгрузки.");
ЦеныТЗ = СформироватьТаблицуЦен();
Если ЦеныТЗ.Количество() = 0 Тогда
ТекстОшибки = "Запрос не вернул ни одной строки. Выгрузка не выполнена.";
ЗаписьЖурналаРегистрации(ИмяСобытия, УровеньЖурналаРегистрации.Ошибка, , , ТекстОшибки);
ВызватьИсключение ТекстОшибки;
КонецЕсли;
ЗаписьЖурналаРегистрации(ИмяСобытия, УровеньЖурналаРегистрации.Информация, , ,
СтрШаблон("Сформировано строк: %1. Время запроса: %2 мс.",
ЦеныТЗ.Количество(), ТекущаяУниверсальнаяДатаВМиллисекундах() - НачалоРаботы));
РезультатОтправки = СформироватьОтправитьВKafka(ЦеныТЗ);
ВыгрузитьВExcel(ЦеныТЗ);
ЗаписьЖурналаРегистрации(ИмяСобытия,
?(РезультатОтправки.Успех, УровеньЖурналаРегистрации.Информация, УровеньЖурналаРегистрации.Ошибка),
, , СтрШаблон("Финиш. %1 Общее время: %2 мс.",
РезультатОтправки.Текст, ТекущаяУниверсальнаяДатаВМиллисекундах() - НачалоРаботы));
Если НЕ РезультатОтправки.Успех Тогда
ВызватьИсключение РезультатОтправки.Текст;
КонецЕсли;
КонецПроцедуры
Функция СформироватьТаблицуЦен()
ВидЦены = Справочники.ВидыЦен.НайтиПоРеквизиту("Идентификатор", "ЗакупочнаяЦена");
Если НЕ ЗначениеЗаполнено(ВидЦены) Тогда
ВызватьИсключение "Не найден вид цены с идентификатором ""ЗакупочнаяЦена"".";
КонецЕсли;
СвойствоOEM = НайтиДополнительныйРеквизит("OEMНомер");
СвойствоАртикулМП = НайтиДополнительныйРеквизит("АртикулМаркетплейсов");
Запрос = Новый Запрос(ТекстЗапросаЦены());
Запрос.УстановитьПараметр("ВидЦены", ВидЦены);
Запрос.УстановитьПараметр("КонецПериода", ТекущаяДатаСеанса());
Запрос.УстановитьПараметр("СвойствоOEM", СвойствоOEM);
Запрос.УстановитьПараметр("СвойствоАртикулМП", СвойствоАртикулМП);
Запрос.УстановитьПараметр("МаскаНоменклатуры", "%не использовать%");
Результаты = Запрос.ВыполнитьПакет();
ЦеныТЗ = Результаты[Результаты.Количество() - 2].Выгрузить();
СоставТЗ = Результаты[Результаты.Количество() - 1].Выгрузить();
Колонки = ЦеновыеКолонки();
Для Каждого СтрЦена Из ЦеныТЗ Цикл
Для Каждого ИмяКолонки Из Колонки Цикл
СтрЦена[ИмяКолонки] = Окр(СтрЦена[ИмяКолонки], 2, РежимОкругления.Окр15как20);
КонецЦикла;
КонецЦикла;
ДополнитьЦенамиНаборов(ЦеныТЗ, СоставТЗ);
ЦеныТЗ.Сортировать("Код");
Возврат ЦеныТЗ;
КонецФункции
Процедура ДополнитьЦенамиНаборов(ЦеныТЗ, СоставТЗ)
Если СоставТЗ.Количество() = 0 Тогда
Возврат;
КонецЕсли;
ИзвестныеЦены = Новый Соответствие;
Для Каждого СтрЦена Из ЦеныТЗ Цикл
ИзвестныеЦены.Вставить(СтрЦена.Номенклатура,
Новый Структура("СредняяЦена, Цена, СредняяЦенаБезНДС, ЦенаБезНДС",
СтрЦена.СредняяЦена, СтрЦена.Цена, СтрЦена.СредняяЦенаБезНДС, СтрЦена.ЦенаБезНДС));
КонецЦикла;
РеквизитыНаборов = Новый Соответствие;
СоставНабора = Новый Соответствие;
Для Каждого СтрСостав Из СоставТЗ Цикл
Если РеквизитыНаборов[СтрСостав.Набор] = Неопределено Тогда
Реквизиты = Новый Структура("Наименование, Код, Артикул, Марка, OEMНомер, АртикулМаркетплейса");
ЗаполнитьЗначенияСвойств(Реквизиты, СтрСостав);
РеквизитыНаборов.Вставить(СтрСостав.Набор, Реквизиты);
СоставНабора.Вставить(СтрСостав.Набор, Новый Массив);
КонецЕсли;
СоставНабора[СтрСостав.Набор].Добавить(
Новый Структура("Компонент, Количество", СтрСостав.Компонент, СтрСостав.Количество));
КонецЦикла;
МассивНаборов = Новый Массив;
Для Каждого КлючЗначение Из СоставНабора Цикл
МассивНаборов.Добавить(КлючЗначение.Ключ);
КонецЦикла;
Для Каждого Набор Из МассивНаборов Цикл
СредняяИтог = 0;
ЦенаИтог = 0;
СредняяБезНДСИтог = 0;
ЦенаБезНДСИтог = 0;
Для Каждого Строка Из СоставНабора[Набор] Цикл
ЦеныКомпонента = ИзвестныеЦены[Строка.Компонент];
Если ЦеныКомпонента <> Неопределено Тогда
Цена = ЦеныКомпонента.Цена;
ЦенаБезНДС = ЦеныКомпонента.ЦенаБезНДС;
СредняяЦена = ЦеныКомпонента.СредняяЦена;
СредняяЦенаБезНДС = ЦеныКомпонента.СредняяЦенаБезНДС;
Количество = Строка.Количество;
Иначе
СредняяИтог = 0;
ЦенаИтог = 0;
СредняяБезНДСИтог = 0;
ЦенаБезНДСИтог = 0;
Прервать;
КонецЕсли;
СредняяИтог = СредняяИтог + СредняяЦена * Количество;
ЦенаИтог = ЦенаИтог + Цена * Количество;
СредняяБезНДСИтог = СредняяБезНДСИтог + СредняяЦенаБезНДС * Количество;
ЦенаБезНДСИтог = ЦенаБезНДСИтог + ЦенаБезНДС * Количество;
КонецЦикла;
СредняяИтог = Окр(СредняяИтог, 2, РежимОкругления.Окр15как20);
ЦенаИтог = Окр(ЦенаИтог, 2, РежимОкругления.Окр15как20);
СредняяБезНДСИтог = Окр(СредняяБезНДСИтог, 2, РежимОкругления.Окр15как20);
ЦенаБезНДСИтог = Окр(ЦенаБезНДСИтог, 2, РежимОкругления.Окр15как20);
НоваяСтрока = ЦеныТЗ.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, РеквизитыНаборов[Набор]);
НоваяСтрока.Номенклатура = Набор;
НоваяСтрока.СредняяЦена = СредняяИтог;
НоваяСтрока.Цена = ЦенаИтог;
НоваяСтрока.СредняяЦенаБезНДС = СредняяБезНДСИтог;
НоваяСтрока.ЦенаБезНДС = ЦенаБезНДСИтог;
НоваяСтрока.КоличествоДокументов = 0;
ИзвестныеЦены.Вставить(Набор, Новый Структура("СредняяЦена, Цена, СредняяЦенаБезНДС, ЦенаБезНДС",
СредняяИтог, ЦенаИтог, СредняяБезНДСИтог, ЦенаБезНДСИтог));
КонецЦикла;
КонецПроцедуры
Функция НайтиДополнительныйРеквизит(ИдентификаторДляФормул)
Свойство = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоРеквизиту(
"ИдентификаторДляФормул", ИдентификаторДляФормул);
Если НЕ ЗначениеЗаполнено(Свойство) Тогда
ЗаписьЖурналаРегистрации("Выгрузка закупочных цен",
УровеньЖурналаРегистрации.Предупреждение, , ,
"Не найден дополнительный реквизит с идентификатором """ + ИдентификаторДляФормул + """.");
КонецЕсли;
Возврат Свойство;
КонецФункции
Функция ЦеновыеКолонки()
Возврат СтрРазделить("СредняяЦена,Цена,СредняяЦенаБезНДС,ЦенаБезНДС", ",");
КонецФункции
Функция ТекстЗапросаЦены()
Возврат
"ВЫБРАТЬ
| Вариант.Владелец КАК Набор,
| Вариант.Ссылка КАК Вариант,
| Вариант.Наименование КАК ВариантНаименование,
| СоставТЧ.НомерСтроки КАК НомерСтроки,
| СоставТЧ.Номенклатура КАК Компонент,
| СоставТЧ.Количество КАК Количество
|ПОМЕСТИТЬ ВТ_СоставНаборов
|ИЗ
| Справочник.ВариантыКомплектацииНоменклатуры.Товары КАК СоставТЧ
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ВариантыКомплектацииНоменклатуры КАК Вариант
| ПО СоставТЧ.Ссылка = Вариант.Ссылка
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Наборы
| ПО (Вариант.Владелец = Наборы.Ссылка)
|ГДЕ
| НЕ Вариант.ПометкаУдаления
| И НЕ Наборы.ПометкаУдаления
| И Наборы.ТипНоменклатуры = ЗНАЧЕНИЕ(Перечисление.ТипыНоменклатуры.Набор)
| И СоставТЧ.Количество > 0
|
|ИНДЕКСИРОВАТЬ ПО
| Набор,
| Компонент
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ РАЗЛИЧНЫЕ
| ВсяНоменклатура.Номенклатура КАК Номенклатура
|ПОМЕСТИТЬ ВТ_НоменклатураКРасчету
|ИЗ
| (ВЫБРАТЬ
| ОстаткиТоваров.Номенклатура КАК Номенклатура
| ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки(&КонецПериода, ) КАК ОстаткиТоваров
| ГДЕ
| ОстаткиТоваров.ВНаличииОстаток > 0
|
| ОБЪЕДИНИТЬ ВСЕ
|
| ВЫБРАТЬ
| ВТ_СоставНаборов.Компонент
| ИЗ
| ВТ_СоставНаборов КАК ВТ_СоставНаборов
|
| ОБЪЕДИНИТЬ ВСЕ
|
| ВЫБРАТЬ
| ВТ_СоставНаборов.Набор
| ИЗ
| ВТ_СоставНаборов КАК ВТ_СоставНаборов) КАК ВсяНоменклатура
|
|ИНДЕКСИРОВАТЬ ПО
| Номенклатура
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| УстановкаЦен.ДокументОснование КАК Основание,
| ЦеныНоменклатуры25.Номенклатура КАК Номенклатура,
| МАКСИМУМ(ЦеныНоменклатуры25.Период) КАК ПериодУстановки
|ПОМЕСТИТЬ ВТ_ДокУстановкаЦен
|ИЗ
| РегистрСведений.ЦеныНоменклатуры25 КАК ЦеныНоменклатуры25
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.УстановкаЦенНоменклатуры КАК УстановкаЦен
| ПО ЦеныНоменклатуры25.Регистратор = УстановкаЦен.Ссылка
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_НоменклатураКРасчету КАК ВТ_Номенклатура
| ПО ЦеныНоменклатуры25.Номенклатура = ВТ_Номенклатура.Номенклатура
|ГДЕ
| УстановкаЦен.Проведен
| И УстановкаЦен.ДокументОснование ССЫЛКА Документ.ПриобретениеТоваровУслуг
| И ЦеныНоменклатуры25.ВидЦены = &ВидЦены
| И ЦеныНоменклатуры25.Цена > 0
|
|СГРУППИРОВАТЬ ПО
| УстановкаЦен.ДокументОснование,
| ЦеныНоменклатуры25.Номенклатура
|
|ИНДЕКСИРОВАТЬ ПО
| Номенклатура,
| Основание
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ДокТовары.Номенклатура КАК Номенклатура,
| Док.Ссылка КАК Ссылка,
| ВТ_ДокУстановкаЦен.ПериодУстановки КАК ПериодУстановки,
| СУММА(ВЫБОР
| КОГДА Док.ЦенаВключаетНДС
| ТОГДА ДокТовары.Сумма - ДокТовары.СуммаНДС
| ИНАЧЕ ДокТовары.Сумма
| КОНЕЦ) КАК СуммаБезНДС,
| СУММА(ВЫБОР
| КОГДА Док.ЦенаВключаетНДС
| ТОГДА ДокТовары.Сумма
| ИНАЧЕ ДокТовары.Сумма + ДокТовары.СуммаНДС
| КОНЕЦ) КАК СуммаСНДС,
| СУММА(ДокТовары.Количество) КАК Количество
|ПОМЕСТИТЬ ВТ_ПоДокументам
|ИЗ
| Документ.ПриобретениеТоваровУслуг.Товары КАК ДокТовары
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.ПриобретениеТоваровУслуг КАК Док
| ПО ДокТовары.Ссылка = Док.Ссылка
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_ДокУстановкаЦен КАК ВТ_ДокУстановкаЦен
| ПО (Док.Ссылка = ВТ_ДокУстановкаЦен.Основание)
| И ДокТовары.Номенклатура = ВТ_ДокУстановкаЦен.Номенклатура
|ГДЕ
| Док.Проведен
| И ДокТовары.Количество > 0
| И ДокТовары.Сумма > 0
|
|СГРУППИРОВАТЬ ПО
| ДокТовары.Номенклатура,
| Док.Ссылка,
| ВТ_ДокУстановкаЦен.ПериодУстановки
|
|ИНДЕКСИРОВАТЬ ПО
| Номенклатура
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТ_ПоДокументам.Номенклатура КАК Номенклатура,
| ВТ_ПоДокументам.Ссылка КАК Ссылка,
| ВТ_ПоДокументам.ПериодУстановки КАК ПериодУстановки,
| ВТ_ПоДокументам.СуммаБезНДС / ВТ_ПоДокументам.Количество КАК ЦенаДокумента,
| ВТ_ПоДокументам.СуммаСНДС / ВТ_ПоДокументам.Количество КАК ЦенаДокументаСНДС
|ПОМЕСТИТЬ ВТ_ЦеныДокументов
|ИЗ
| ВТ_ПоДокументам КАК ВТ_ПоДокументам
|
|ИНДЕКСИРОВАТЬ ПО
| Номенклатура,
| ПериодУстановки
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТ_ЦеныДокументов.Номенклатура КАК Номенклатура,
| СРЕДНЕЕ(ВТ_ЦеныДокументов.ЦенаДокумента) КАК СредняяЦена,
| СРЕДНЕЕ(ВТ_ЦеныДокументов.ЦенаДокументаСНДС) КАК СредняяЦенаСНДС,
| КОЛИЧЕСТВО(ВТ_ЦеныДокументов.Ссылка) КАК КоличествоДокументов,
| МАКСИМУМ(ВТ_ЦеныДокументов.ПериодУстановки) КАК ПериодУстановки
|ПОМЕСТИТЬ ВТ_СредняяЦена
|ИЗ
| ВТ_ЦеныДокументов КАК ВТ_ЦеныДокументов
|
|СГРУППИРОВАТЬ ПО
| ВТ_ЦеныДокументов.Номенклатура
|
|ИНДЕКСИРОВАТЬ ПО
| Номенклатура,
| ПериодУстановки
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТ_ЦеныДокументов.Номенклатура КАК Номенклатура,
| СРЕДНЕЕ(ВТ_ЦеныДокументов.ЦенаДокумента) КАК ТекущаяЦенаБезНДС,
| СРЕДНЕЕ(ВТ_ЦеныДокументов.ЦенаДокументаСНДС) КАК ТекущаяЦенаСНДС
|ПОМЕСТИТЬ ВТ_ПоследняяЦена
|ИЗ
| ВТ_ЦеныДокументов КАК ВТ_ЦеныДокументов
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_СредняяЦена КАК ВТ_СредняяЦена
| ПО ВТ_ЦеныДокументов.Номенклатура = ВТ_СредняяЦена.Номенклатура
| И ВТ_ЦеныДокументов.ПериодУстановки = ВТ_СредняяЦена.ПериодУстановки
|
|СГРУППИРОВАТЬ ПО
| ВТ_ЦеныДокументов.Номенклатура
|
|ИНДЕКСИРОВАТЬ ПО
| Номенклатура
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ДопРеквизиты.Ссылка КАК Номенклатура,
| МАКСИМУМ(ВЫБОР
| КОГДА ДопРеквизиты.Свойство = &СвойствоOEM
| ТОГДА ВЫРАЗИТЬ(ДопРеквизиты.Значение КАК СТРОКА(150))
| ИНАЧЕ """"
| КОНЕЦ) КАК OEMНомер,
| МАКСИМУМ(ВЫБОР
| КОГДА ДопРеквизиты.Свойство = &СвойствоАртикулМП
| ТОГДА ВЫРАЗИТЬ(ДопРеквизиты.Значение КАК СТРОКА(150))
| ИНАЧЕ """"
| КОНЕЦ) КАК АртикулМаркетплейса
|ПОМЕСТИТЬ ВТ_ДопРеквизиты
|ИЗ
| Справочник.Номенклатура.ДополнительныеРеквизиты КАК ДопРеквизиты
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_НоменклатураКРасчету КАК ВТ_Номенклатура
| ПО ДопРеквизиты.Ссылка = ВТ_Номенклатура.Номенклатура
|ГДЕ
| ДопРеквизиты.Свойство В (&СвойствоOEM, &СвойствоАртикулМП)
|
|СГРУППИРОВАТЬ ПО
| ДопРеквизиты.Ссылка
|
|ИНДЕКСИРОВАТЬ ПО
| Номенклатура
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ПРЕДСТАВЛЕНИЕ(Ном.Марка) КАК Марка,
| Ном.Артикул КАК Артикул,
| ЕСТЬNULL(ВТ_ДопРеквизиты.АртикулМаркетплейса, """") КАК АртикулМаркетплейса,
| Ном.Код КАК Код,
| ЕСТЬNULL(ВТ_ДопРеквизиты.OEMНомер, """") КАК OEMНомер,
| Ном.Ссылка КАК Номенклатура,
| ПРЕДСТАВЛЕНИЕ(Ном.Ссылка) КАК Наименование,
| ВТ_ПоследняяЦена.ТекущаяЦенаБезНДС КАК ЦенаБезНДС,
| ВТ_СредняяЦена.СредняяЦена КАК СредняяЦенаБезНДС,
| ВТ_ПоследняяЦена.ТекущаяЦенаСНДС КАК Цена,
| ВТ_СредняяЦена.СредняяЦенаСНДС КАК СредняяЦена,
| ВТ_СредняяЦена.КоличествоДокументов КАК КоличествоДокументов
|ИЗ
| ВТ_СредняяЦена КАК ВТ_СредняяЦена
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_ПоследняяЦена КАК ВТ_ПоследняяЦена
| ПО ВТ_СредняяЦена.Номенклатура = ВТ_ПоследняяЦена.Номенклатура
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Ном
| ПО ВТ_СредняяЦена.Номенклатура = Ном.Ссылка
| ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ДопРеквизиты КАК ВТ_ДопРеквизиты
| ПО ВТ_СредняяЦена.Номенклатура = ВТ_ДопРеквизиты.Номенклатура
|ГДЕ
| НЕ Ном.ПометкаУдаления
| И ВТ_СредняяЦена.СредняяЦена > 0
| И НЕ Ном.Наименование ПОДОБНО &МаскаНоменклатуры
| И НЕ Ном.Артикул ПОДОБНО &МаскаНоменклатуры
| И Ном.ТипНоменклатуры <> ЗНАЧЕНИЕ(Перечисление.ТипыНоменклатуры.Набор)
|
|УПОРЯДОЧИТЬ ПО
| Код
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТ_СоставНаборов.Набор КАК Набор,
| ПРЕДСТАВЛЕНИЕ(Ном.Ссылка) КАК Наименование,
| Ном.Код КАК Код,
| Ном.Артикул КАК Артикул,
| ПРЕДСТАВЛЕНИЕ(Ном.Марка) КАК Марка,
| ЕСТЬNULL(ВТ_ДопРеквизиты.OEMНомер, """") КАК OEMНомер,
| ЕСТЬNULL(ВТ_ДопРеквизиты.АртикулМаркетплейса, """") КАК АртикулМаркетплейса,
| ВТ_СоставНаборов.Вариант КАК Вариант,
| ВТ_СоставНаборов.ВариантНаименование КАК ВариантНаименование,
| ВТ_СоставНаборов.НомерСтроки КАК НомерСтроки,
| ВТ_СоставНаборов.Компонент КАК Компонент,
| ВТ_СоставНаборов.Количество КАК Количество
|ИЗ
| ВТ_СоставНаборов КАК ВТ_СоставНаборов
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Ном
| ПО ВТ_СоставНаборов.Набор = Ном.Ссылка
| ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ДопРеквизиты КАК ВТ_ДопРеквизиты
| ПО ВТ_СоставНаборов.Набор = ВТ_ДопРеквизиты.Номенклатура
|
|УПОРЯДОЧИТЬ ПО
| Набор,
| ВариантНаименование,
| НомерСтроки";
КонецФункции
Функция СформироватьОтправитьВKafka(ЦеныТЗ)
Сообщения = Новый Массив;
Для Каждого СтрЦена Из ЦеныТЗ Цикл
Элемент = Новый Структура;
Элемент.Вставить("name", СокрЛП(СтрЦена.Наименование));
Элемент.Вставить("code", СокрЛП(СтрЦена.Код));
Элемент.Вставить("brand", СокрЛП(СтрЦена.Марка));
Элемент.Вставить("article", СокрЛП(СтрЦена.Артикул));
Элемент.Вставить("article_mp", СокрЛП(СтрЦена.АртикулМаркетплейса));
Элемент.Вставить("oem", СокрЛП(СтрЦена.OEMНомер));
Элемент.Вставить("last_price", СтрЦена.Цена);
Элемент.Вставить("avg_price", СтрЦена.СредняяЦена);
Сообщение = Новый Структура("Ключ, Тело",
Строка(СтрЦена.Номенклатура.УникальныйИдентификатор()),
ОбщегоНазначения.ЗначениеВJSON(Элемент));
Сообщения.Добавить(Сообщение);
КонецЦикла;
Возврат ОтправитьВKafka(Сообщения);
КонецФункции
Процедура ВыгрузитьВExcel(ЦеныТЗ)
Каталог = "C:\Выгрузка закупочных цен";
// Каталог = "C:\Тестовая Папка";
КолонкиФайла = "Марка,Артикул,АртикулМаркетплейса,Код,OEMНомер,Номенклатура,Цена,СредняяЦена";
Ключи = "Имя, Заголовок, Ширина, Формат, Переносить";
Колонки = Новый Массив;
Колонки.Добавить(Новый Структура(Ключи, "Марка", "Марка", 14, "", Ложь));
Колонки.Добавить(Новый Структура(Ключи, "Артикул", "Артикул", 18, "", Истина));
Колонки.Добавить(Новый Структура(Ключи, "АртикулМаркетплейса", "Артикул МП", 18, "", Истина));
Колонки.Добавить(Новый Структура(Ключи, "Код", "Код", 12, "", Ложь));
Колонки.Добавить(Новый Структура(Ключи, "OEMНомер", "OEM номер", 22, "", Истина));
Колонки.Добавить(Новый Структура(Ключи, "Номенклатура", "Номенклатура", 50, "", Истина));
Колонки.Добавить(Новый Структура(Ключи, "СредняяЦена", "Средняя цена с НДС", 16, "ЧДЦ=2; ЧН=0; ЧРГ=", Ложь));
Колонки.Добавить(Новый Структура(Ключи, "Цена", "Последняя цена с НДС", 16, "ЧДЦ=2; ЧН=0; ЧРГ=", Ложь));
Колонки.Добавить(Новый Структура(Ключи, "СредняяЦенаБезНДС", "Средняя цена без НДС", 16, "ЧДЦ=2; ЧН=0; ЧРГ=", Ложь));
Колонки.Добавить(Новый Структура(Ключи, "ЦенаБезНДС", "Последняя цена без НДС",16, "ЧДЦ=2; ЧН=0; ЧРГ=", Ложь));
Попытка
ТабДок = Новый ТабличныйДокумент;
Для НомерКолонки = 1 По Колонки.Количество() Цикл
Описание = Колонки[НомерКолонки - 1];
Ячейка = ТабДок.Область(1, НомерКолонки, 1, НомерКолонки);
Ячейка.Текст = Описание.Заголовок;
Ячейка.Шрифт = Новый Шрифт(, , Истина);
Ячейка.РазмещениеТекста = ТипРазмещенияТекстаТабличногоДокумента.Переносить;
Ячейка.ВертикальноеПоложение = ВертикальноеПоложение.Центр;
Ячейка.ГоризонтальноеПоложение = ГоризонтальноеПоложение.Центр;
Ячейка.ЦветФона = Новый Цвет(230, 230, 230);
ТабДок.Область(, НомерКолонки, , НомерКолонки).ШиринаКолонки = Описание.Ширина;
КонецЦикла;
НомерСтроки = 1;
Для Каждого СтрокаТЗ Из ЦеныТЗ Цикл
НомерСтроки = НомерСтроки + 1;
Для НомерКолонки = 1 По Колонки.Количество() Цикл
Описание = Колонки[НомерКолонки - 1];
Значение = СтрокаТЗ[Описание.Имя];
Ячейка = ТабДок.Область(НомерСтроки, НомерКолонки, НомерСтроки, НомерКолонки);
Если ЗначениеЗаполнено(Описание.Формат) Тогда
Ячейка.Текст = Формат(Значение, Описание.Формат);
Ячейка.ГоризонтальноеПоложение = ГоризонтальноеПоложение.Право;
Иначе
Ячейка.Текст = СокрЛП(Строка(Значение));
КонецЕсли;
КонецЦикла;
КонецЦикла;
ПоследняяСтрока = ЦеныТЗ.Количество() + 1;
Для НомерКолонки = 1 По Колонки.Количество() Цикл
Описание = Колонки[НомерКолонки - 1];
Если Описание.Свойство("Переносить") И Описание.Переносить Тогда
ОбластьКолонки = ТабДок.Область(2, НомерКолонки, ПоследняяСтрока, НомерКолонки);
ОбластьКолонки.РазмещениеТекста = ТипРазмещенияТекстаТабличногоДокумента.Переносить;
ОбластьКолонки.ВертикальноеПоложение = ВертикальноеПоложение.Верх;
КонецЕсли;
КонецЦикла;
ТабДок.Область(2, , ПоследняяСтрока, ).АвтоВысотаСтроки = Истина;
ТабДок.ФиксацияСверху = 1;
ИмяФайла = Каталог
+ ?(Прав(Каталог, 1) = ПолучитьРазделительПути(), "", ПолучитьРазделительПути())
+ "Цены_" + Формат(ТекущаяДатаСеанса(), "ДФ=yyyyMMdd_HHmmss") + ".xlsx";
ТабДок.Записать(ИмяФайла, ТипФайлаТабличногоДокумента.XLSX);
Исключение
ЗаписьЖурналаРегистрации("Выгрузка закупочных цен",
УровеньЖурналаРегистрации.Предупреждение, , ,
"Не удалось сохранить файл: " + ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
КонецПопытки;
КонецПроцедуры
#КонецОбласти
// https://github.com/NuclearAPK/Simple-Kafka_Adapter
// Общий модуль: кор_HTTPКоннектор
//
// Настройки хранятся в константах:
// кор_KafkaБрокеры (Строка) - "host:port,host:port,..."
// кор_KafkaТопик (Строка) - имя топика
// кор_KafkaКаталогЛогов (Строка) - каталог логов компоненты
//
#Область Кафка
#Область ПрограммныйИнтерфейс
Функция ПолучитьСтруктуруПодключения() Экспорт
СтруктураПодключения = Новый Структура;
СтруктураПодключения.Вставить("Брокеры", СокрЛП(Константы.кор_KafkaБрокеры.Получить()));
СтруктураПодключения.Вставить("ИмяТопика", СокрЛП(Константы.кор_KafkaТопик.Получить()));
СтруктураПодключения.Вставить("КаталогЛогов", СокрЛП(Константы.кор_KafkaКаталогЛогов.Получить()));
Возврат СтруктураПодключения;
КонецФункции
// Отправляет поток сообщений в Kafka.
//
// Параметры:
// Сообщения - Массив структур - каждый элемент: Ключ (Строка), Тело (Строка JSON)
//
// Возвращаемое значение:
// Структура - Отправлено (Число), Ошибок (Число), Успех (Булево), Текст (Строка)
//
Функция ОтправитьВKafka(Сообщения) Экспорт
ИмяСобытия = "Kafka. Отправка цен";
Результат = Новый Структура("Отправлено, Ошибок, Успех, Текст", 0, 0, Ложь, "");
Если ТипЗнч(Сообщения) <> Тип("Массив") ИЛИ Сообщения.Количество() = 0 Тогда
Результат.Текст = "Нет данных для отправки.";
Возврат Результат;
КонецЕсли;
Подключение = ПолучитьСтруктуруПодключения();
Если НЕ ЗначениеЗаполнено(Подключение.Брокеры) Тогда
Результат.Текст = "Не заполнена константа кор_KafkaБрокеры.";
ЗаписьЖурналаРегистрации(ИмяСобытия, УровеньЖурналаРегистрации.Ошибка, , , Результат.Текст);
Возврат Результат;
КонецЕсли;
Если НЕ ЗначениеЗаполнено(Подключение.ИмяТопика) Тогда
Результат.Текст = "Не заполнена константа кор_KafkaТопик.";
ЗаписьЖурналаРегистрации(ИмяСобытия, УровеньЖурналаРегистрации.Ошибка, , , Результат.Текст);
Возврат Результат;
КонецЕсли;
Компонента = СоздатьКомпонентуКафкаКлиент();
Если Компонента = Неопределено Тогда
Результат.Текст = "Не удалось создать компоненту Kafka.";
Возврат Результат;
КонецЕсли;
Попытка
Компонента.УстановитьТаймаутОчисткиПродюсера(60000);
Исключение
КонецПопытки;
Если НЕ Компонента.ИнициализироватьПродюсера(Подключение.Брокеры) Тогда
Результат.Текст = "Не удалось инициализировать продюсера. Брокеры: " + Подключение.Брокеры
+ ". " + Компонента.ПолучитьСообщениеОбОшибке();
ЗаписьЖурналаРегистрации(ИмяСобытия, УровеньЖурналаРегистрации.Ошибка, , , Результат.Текст);
Компонента = Неопределено;
Возврат Результат;
КонецЕсли;
Всего = Сообщения.Количество();
Попытка
ОтправитьПакетами(Компонента, Сообщения, Подключение.ИмяТопика, Результат, ИмяСобытия);
Исключение
Результат.Текст = "Прервано на " + (Результат.Отправлено + Результат.Ошибок) + " из " + Всего
+ ". " + ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
ЗаписьЖурналаРегистрации(ИмяСобытия, УровеньЖурналаРегистрации.Ошибка, , , Результат.Текст);
Попытка Компонента.ОстановитьПродюсера(); Исключение КонецПопытки;
Компонента = Неопределено;
Возврат Результат;
КонецПопытки;
ОчередьОчищена = ОстановитьПродюсераБезопасно(Компонента, ИмяСобытия);
Компонента = Неопределено;
Результат.Успех = (Результат.Ошибок = 0) И ОчередьОчищена;
Результат.Текст = СтрШаблон("Отправлено: %1, ошибок: %2, всего: %3.",
Результат.Отправлено, Результат.Ошибок, Всего);
ЗаписьЖурналаРегистрации(ИмяСобытия,
?(Результат.Успех, УровеньЖурналаРегистрации.Информация, УровеньЖурналаРегистрации.Предупреждение),
, , Результат.Текст);
Возврат Результат;
КонецФункции
Функция ОстановитьПродюсераБезопасно(Компонента, ИмяСобытия)
Попытка
Возврат Компонента.ОстановитьПродюсера();
Исключение
КонецПопытки;
Попытка
Компонента.ОстановитьПродюсера();
Возврат Истина;
Исключение
ЗаписьЖурналаРегистрации(ИмяСобытия, УровеньЖурналаРегистрации.Ошибка, , ,
"Ошибка остановки продюсера: " + ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
Возврат Ложь;
КонецПопытки;
КонецФункции
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
Процедура ОтправитьПакетами(Компонента, Сообщения, Топик, Результат, ИмяСобытия)
РазмерПачки = 1000;
Пачка = Новый Массив;
Для Каждого ЭлементСообщения Из Сообщения Цикл
Ключ = ?(ЭлементСообщения.Свойство("Ключ"), Строка(ЭлементСообщения.Ключ), "");
Тело = ?(ЭлементСообщения.Свойство("Тело"), Строка(ЭлементСообщения.Тело), "");
Если НЕ ЗначениеЗаполнено(Тело) Тогда
Результат.Ошибок = Результат.Ошибок + 1;
Продолжить;
КонецЕсли;
СообщениеКомпоненты = Новый Структура;
СообщениеКомпоненты.Вставить("message", Тело);
Если ЗначениеЗаполнено(Ключ) Тогда
СообщениеКомпоненты.Вставить("key", Ключ);
КонецЕсли;
Пачка.Добавить(СообщениеКомпоненты);
Если Пачка.Количество() >= РазмерПачки Тогда
ОтправитьОднуПачку(Компонента, Пачка, Топик, Результат, ИмяСобытия);
Пачка = Новый Массив;
КонецЕсли;
КонецЦикла;
Если Пачка.Количество() > 0 Тогда
ОтправитьОднуПачку(Компонента, Пачка, Топик, Результат, ИмяСобытия);
КонецЕсли;
КонецПроцедуры
Процедура ОтправитьОднуПачку(Компонента, Пачка, Топик, Результат, ИмяСобытия)
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, Пачка);
ПачкаJSON = ЗаписьJSON.Закрыть();
ОтветJSON = "";
ЕстьПакетныйМетод = Истина;
Попытка
ОтветJSON = Компонента.ОтправитьПакетСРезультатом(ПачкаJSON, Топик, 60000);
Исключение
ЕстьПакетныйМетод = Ложь;
КонецПопытки;
Если НЕ ЕстьПакетныйМетод Тогда
ОтправитьПоштучно(Компонента, Пачка, Топик, Результат, ИмяСобытия);
Возврат;
КонецЕсли;
Если ПустаяСтрока(ОтветJSON) Тогда
Результат.Ошибок = Результат.Ошибок + Пачка.Количество();
ЗаписьЖурналаРегистрации(ИмяСобытия, УровеньЖурналаРегистрации.Ошибка, , ,
"Пакет не отправлен: " + Компонента.ПолучитьСообщениеОбОшибке());
Возврат;
КонецЕсли;
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(ОтветJSON);
ОтветПакета = ПрочитатьJSON(ЧтениеJSON);
ЧтениеJSON.Закрыть();
Доставлено = Число(ОтветПакета["success_count"]);
НеДоставлено = Число(ОтветПакета["failed_count"]);
Результат.Отправлено = Результат.Отправлено + Доставлено;
Результат.Ошибок = Результат.Ошибок + НеДоставлено;
Если НеДоставлено > 0 Тогда
ЗаписатьОшибкиПакета(ОтветПакета, ИмяСобытия);
КонецЕсли;
КонецПроцедуры
Процедура ЗаписатьОшибкиПакета(ОтветПакета, ИмяСобытия)
СтрокиОшибок = Новый Массив;
Для Каждого СтрокаРезультата Из ОтветПакета["results"] Цикл
Если СтрокаРезультата["delivered"] = "true" Тогда
Продолжить;
КонецЕсли;
СтрокиОшибок.Добавить(СтрШаблон("Ключ: %1. %2",
СтрокаРезультата["key"], СтрокаРезультата["error"]));
Если СтрокиОшибок.Количество() >= 50 Тогда
Прервать;
КонецЕсли;
КонецЦикла;
ЗаписьЖурналаРегистрации(ИмяСобытия, УровеньЖурналаРегистрации.Ошибка, , ,
"Недоставленные сообщения:" + Символы.ПС + СтрСоединить(СтрокиОшибок, Символы.ПС));
КонецПроцедуры
Процедура ОтправитьПоштучно(Компонента, Пачка, Топик, Результат, ИмяСобытия)
Для Каждого СообщениеКомпоненты Из Пачка Цикл
Ключ = "";
СообщениеКомпоненты.Свойство("key", Ключ);
Тело = СообщениеКомпоненты["message"];
РезультатОтправки = Компонента.ОтправитьСообщение(Тело, Топик, -1, Ключ);
Если РезультатОтправки = -1 Тогда
Результат.Ошибок = Результат.Ошибок + 1;
ЗаписьЖурналаРегистрации(ИмяСобытия, УровеньЖурналаРегистрации.Ошибка, , ,
"Не поставлено в очередь. Ключ: " + Ключ + ". " + Компонента.ПолучитьСообщениеОбОшибке());
Иначе
Результат.Отправлено = Результат.Отправлено + 1;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Функция СоздатьКомпонентуКафкаКлиент() Экспорт
ИмяСобытия = "Kafka. Подключение компоненты";
Попытка
Подключено = ПодключитьВнешнююКомпоненту(
"ОбщийМакет.SimpleKafkaAdapter64",
"KafkaClient",
ТипВнешнейКомпоненты.Native,
ТипПодключенияВнешнейКомпоненты.Изолированно);
Исключение
ЗаписьЖурналаРегистрации(ИмяСобытия, УровеньЖурналаРегистрации.Ошибка, , ,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
Возврат Неопределено;
КонецПопытки;
Если НЕ Подключено Тогда
ЗаписьЖурналаРегистрации(ИмяСобытия, УровеньЖурналаРегистрации.Ошибка, , ,
"Не удалось подключить компоненту из общего макета SimpleKafkaAdapter64.");
Возврат Неопределено;
КонецЕсли;
Попытка
Компонента = Новый("AddIn.KafkaClient.simpleKafka1C");
Исключение
ЗаписьЖурналаРегистрации(ИмяСобытия, УровеньЖурналаРегистрации.Ошибка, , ,
"Компонента подключилась, но объект не создался: "
+ ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
Возврат Неопределено;
КонецПопытки;
Возврат Компонента;
КонецФункции
#КонецОбласти
#КонецОбласти