Загрузка данных
/ Остатки складов поставщиков (FBS со склада Берга).
//
// Остатки Берга не проходят через документы и регистры УТ: регламентное задание
// кор_ЗагрузкаОстатковБерга спрашивает их по API и перезаписывает регистр
// кор_ОстаткиПоставщиков, а БИТ.УМ при выгрузке остатков на маркетплейсы берёт их оттуда
// (вставка BSLR в топ_ОбщийМодульСервер.ОстаткиFBS_ПолучитьТекстЗапроса_ВТ_Остатки
// вызывает ДополнитьЗапросОстатковFBS). Какие склады УТ считаются складами поставщика и
// каким складам Берга они соответствуют, задаёт регистр кор_СкладыПоставщиков.
//
// ВОССТАНОВЛЕНО из текста с вырезанными символами. Операторы сравнения, которые
// пришлось угадывать по смыслу, помечены комментарием "// [восст.]".
#Область ПрограммныйИнтерфейс
// Обработчик регламентного задания кор_ЗагрузкаОстатковБерга.
//
Процедура ЗагрузитьОстаткиБерга() Экспорт
ОбщегоНазначения.ПриНачалеВыполненияРегламентногоЗадания(
Метаданные.РегламентныеЗадания.кор_ЗагрузкаОстатковБерга);
ЗагрузитьОстаткиБергаВРегистр();
КонецПроцедуры
// Спрашивает у Берга остатки по номенклатуре, выставленной на маркетплейсы со складов
// поставщика, и перезаписывает по этим складам регистр кор_ОстаткиПоставщиков.
// Можно вызывать и вне регламентного задания - например, для отладки.
//
// Возвращаемое значение:
// Структура:
// * Позиций - Число - сколько позиций спрошено у Берга.
// * Найдено - Число - позиций, по которым Берг вернул ровно один товар.
// * Неоднозначно - Число - позиций, по которым вернулось несколько товаров; остаток по ним не пишется.
// * ПачекСОшибкой - Число
// * Текст - Строка - итог для журнала регистрации.
//
Функция ЗагрузитьОстаткиБергаВРегистр() Экспорт
Итоги = Новый Структура("Позиций, Найдено, Неоднозначно, ПачекСОшибкой, Текст", 0, 0, 0, 0, "");
ПараметрыПодключения = кор_HTTPКоннектор.НовыеПараметрыПодключения();
ПараметрыПодключения.Ключ = кор_HTTPКоннектор.СохраненныйКлючAPI();
Если ПустаяСтрока(ПараметрыПодключения.Ключ) Тогда
Итоги.Текст = НСтр("ru = 'Загрузка остатков Берга пропущена: API-ключ не сохранён.'");
ЗаписатьВЖурнал(УровеньЖурналаРегистрации.Предупреждение, Итоги.Текст);
Возврат Итоги;
КонецЕсли;
УстановитьПривилегированныйРежим(Истина);
СкладыПоставщика = СкладыПоставщика();
НашиСклады = Новый Массив;
Для Каждого КлючИЗначение Из СкладыПоставщика Цикл
Если НашиСклады.Найти(КлючИЗначение.Значение) = Неопределено Тогда
НашиСклады.Добавить(КлючИЗначение.Значение);
КонецЕсли;
КонецЦикла;
Если НашиСклады.Количество() = 0 Тогда
Итоги.Текст = НСтр("ru = 'Загрузка остатков Берга пропущена: не заполнен регистр «Склады поставщиков».'");
ЗаписатьВЖурнал(УровеньЖурналаРегистрации.Предупреждение, Итоги.Текст);
Возврат Итоги;
КонецЕсли;
Позиции = ПозицииДляЗапроса(НашиСклады);
Итоги.Позиций = Позиции.Количество();
Если Позиции.Количество() = 0 Тогда
Итоги.Текст = НСтр("ru = 'Загрузка остатков Берга: нет товаров маркетплейсов, выставленных со складов поставщика.'");
ЗаписатьВЖурнал(УровеньЖурналаРегистрации.Информация, Итоги.Текст);
Возврат Итоги;
КонецЕсли;
ПозицииAPI = Новый Массив;
Для Индекс = 0 По Позиции.Количество() - 1 Цикл
Позиция = Позиции[Индекс];
ПозицииAPI.Добавить(Новый Структура("Индекс, ResourceID, Артикул, BrandID, Бренд",
Индекс + 1, Позиция.ИдентификаторТовара, Позиция.Артикул, 0, Позиция.Бренд));
КонецЦикла;
// Момент берётся до запроса: заказы, созданные, пока идёт опрос, Берг ещё не видит,
// и запрос выгрузки на МП вычтет их из остатка (см. ТекстЗапросаОстатковПоставщиков).
МоментЗагрузки = ТекущаяДатаСеанса();
Ответ = кор_HTTPКоннектор.ПолучитьОстатки(ПараметрыПодключения, ПозицииAPI);
Итоги.ПачекСОшибкой = Ответ.Ошибки.Количество();
Для Каждого ТекстОшибки Из Ответ.Ошибки Цикл
ЗаписатьВЖурнал(УровеньЖурналаРегистрации.Ошибка, ТекстОшибки);
КонецЦикла;
Если Ответ.КоличествоПачек > 0 И Ответ.Ошибки.Количество() = Ответ.КоличествоПачек Тогда // [восст.]
Итоги.Текст = СтрШаблон(
НСтр("ru = 'Загрузка остатков Берга: ни одна из %1 пачек не загрузилась, регистр не изменён.'"),
Ответ.КоличествоПачек);
ЗаписатьВЖурнал(УровеньЖурналаРегистрации.Ошибка, Итоги.Текст);
Возврат Итоги;
КонецЕсли;
Записи = НоваяТаблицаЗаписей();
СтрокиЗаписей = СтрокиЗаписейПоПозициям(Ответ.Предложения, Позиции, НашиСклады, МоментЗагрузки, Записи, Итоги);
ЗаполнитьЗаписиПоПредложениям(СтрокиЗаписей, Ответ.Предложения, СкладыПоставщика);
// По позициям из пачек с ошибкой ответа нет: оставляем прежние записи с прежней датой,
// чтобы товар не обнулился на маркетплейсе из-за одного сбойного запроса.
Если Ответ.ИндексыСОшибкой.Количество() > 0 Тогда // [восст.]
ДобавитьПрежниеЗаписи(Записи, Позиции, Ответ.ИндексыСОшибкой, НашиСклады);
КонецЕсли;
ЗаписатьОстатки(Записи, НашиСклады);
Итоги.Текст = СтрШаблон(
НСтр("ru = 'Загрузка остатков Берга: позиций %1, найдено %2, неоднозначно %3, пачек с ошибкой %4 из %5.'"),
Итоги.Позиций, Итоги.Найдено, Итоги.Неоднозначно, Итоги.ПачекСОшибкой, Ответ.КоличествоПачек);
ЗаписатьВЖурнал(УровеньЖурналаРегистрации.Информация, Итоги.Текст);
Возврат Итоги;
КонецФункции
// Подменяет в запросе остатков FBS БИТ.УМ остатки складов поставщиков: для них вместо
// РаспределениеЗапасов берётся регистр кор_ОстаткиПоставщиков за вычетом наших заказов,
// о которых поставщик ещё не знает. Вызывается из вставки BSLR в
// топ_ОбщийМодульСервер.ОстаткиFBS_ПолучитьТекстЗапроса_ВТ_Остатки.
//
// Параметры:
// ТекстыЗапроса - Массив из Строка - пакет запроса БИТ.УМ; последний элемент - запрос,
// помещающий остатки во временную таблицу ВТ_ОстаткиПредварительная
// (Номенклатура, Характеристика, Склад, Остаток). Массив меняется на месте.
//
Процедура ДополнитьЗапросОстатковFBS(ТекстыЗапроса) Экспорт
// Без права чтения запрос упал бы у пользователя целиком; лучше показать ему
// остатки без поставщиков. Право даёт роль кор_ЧтениеОстатковПоставщиков.
Если Не ПравоДоступа("Чтение", Метаданные.РегистрыСведений.кор_СкладыПоставщиков)
Или Не ПравоДоступа("Чтение", Метаданные.РегистрыСведений.кор_ОстаткиПоставщиков) Тогда
Возврат;
КонецЕсли;
Запрос = Новый Запрос(
"ВЫБРАТЬ ПЕРВЫЕ 1
| ИСТИНА КАК ЕстьСклады
|ИЗ
| РегистрСведений.кор_СкладыПоставщиков КАК СкладыПоставщиков");
Если Запрос.Выполнить().Пустой() Тогда
Возврат;
КонецЕсли;
ИмяТиповойТаблицы = "ВТ_ОстаткиПредварительнаяБезПоставщиков";
Индекс = ТекстыЗапроса.ВГраница();
ТекстыЗапроса[Индекс] = СтрЗаменить(ТекстыЗапроса[Индекс],
"ПОМЕСТИТЬ ВТ_ОстаткиПредварительная", "ПОМЕСТИТЬ " + ИмяТиповойТаблицы);
ТекстыЗапроса.Добавить(ТекстЗапросаОстатковПоставщиков(ИмяТиповойТаблицы));
ТекстыЗапроса.Добавить("УНИЧТОЖИТЬ " + ИмяТиповойТаблицы);
КонецПроцедуры
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
#Область ЗапросВыгрузкиНаМП
Функция ТекстЗапросаОстатковПоставщиков(ИмяТиповойТаблицы)
// Наши заказы вычитаются, только если созданы после загрузки остатка: более ранние
// поставщик уже учёл (после place_order) - иначе они вычитались бы дважды.
// Остаток старше срока актуальности склада не выгружается (товар уйдёт в 0), чтобы
// при остановившейся загрузке не продавать по давно устаревшим цифрам.
Текст =
"ВЫБРАТЬ
| Т.Номенклатура КАК Номенклатура,
| Т.Характеристика КАК Характеристика,
| Т.Склад КАК Склад,
| Т.Остаток КАК Остаток
|ПОМЕСТИТЬ ВТ_ОстаткиПредварительная
|ИЗ
| &ИмяТиповойТаблицы КАК Т
|ГДЕ
| НЕ Т.Склад В
| (ВЫБРАТЬ РАЗЛИЧНЫЕ
| СкладыПоставщиков.Склад
| ИЗ
| РегистрСведений.кор_СкладыПоставщиков КАК СкладыПоставщиков)
|
|ОБЪЕДИНИТЬ ВСЕ
|
|ВЫБРАТЬ
| Остатки.Номенклатура,
| Остатки.Характеристика,
| Остатки.Склад,
| ВЫБОР
| КОГДА Остатки.Количество - ЕСТЬNULL(Заказы.Количество, 0) > 0
| ТОГДА Остатки.Количество - ЕСТЬNULL(Заказы.Количество, 0)
| ИНАЧЕ 0
| КОНЕЦ
|ИЗ
| РегистрСведений.кор_ОстаткиПоставщиков КАК Остатки
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ (ВЫБРАТЬ
| СкладыПоставщиков.Склад КАК Склад,
| МАКСИМУМ(СкладыПоставщиков.СрокАктуальностиЧасов) КАК СрокАктуальностиЧасов
| ИЗ
| РегистрСведений.кор_СкладыПоставщиков КАК СкладыПоставщиков
|
| СГРУППИРОВАТЬ ПО
| СкладыПоставщиков.Склад) КАК Склады
| ПО Остатки.Склад = Склады.Склад
| ЛЕВОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ
| ОстаткиПоЗаказам.Склад КАК Склад,
| ОстаткиПоЗаказам.Номенклатура КАК Номенклатура,
| ОстаткиПоЗаказам.Характеристика КАК Характеристика,
| СУММА(ТоварыЗаказов.Количество) КАК Количество
| ИЗ
| РегистрСведений.кор_ОстаткиПоставщиков КАК ОстаткиПоЗаказам
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.ЗаказКлиента.Товары КАК ТоварыЗаказов
| ПО ОстаткиПоЗаказам.Склад = ТоварыЗаказов.Склад
| И ОстаткиПоЗаказам.Номенклатура = ТоварыЗаказов.Номенклатура
| И ОстаткиПоЗаказам.Характеристика = ТоварыЗаказов.Характеристика
| И (ТоварыЗаказов.Ссылка.Дата >= ОстаткиПоЗаказам.ДатаОбновления)
| И (ТоварыЗаказов.Ссылка.Проведен)
| И (НЕ ТоварыЗаказов.Отменено)
| И (ТоварыЗаказов.Ссылка.Статус <> ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказовКлиентов.Закрыт))
|
| СГРУППИРОВАТЬ ПО
| ОстаткиПоЗаказам.Склад,
| ОстаткиПоЗаказам.Номенклатура,
| ОстаткиПоЗаказам.Характеристика) КАК Заказы
| ПО Остатки.Склад = Заказы.Склад
| И Остатки.Номенклатура = Заказы.Номенклатура
| И Остатки.Характеристика = Заказы.Характеристика
|ГДЕ
| Остатки.Склад В
| (ВЫБРАТЬ
| Т.Склад
| ИЗ
| ВТ_Склады КАК Т)
| И Остатки.Номенклатура В
| (ВЫБРАТЬ
| Т.НоменклатураОстатков
| ИЗ
| ВТ_Номенклатура КАК Т)
| И (Склады.СрокАктуальностиЧасов = 0
| ИЛИ Остатки.ДатаОбновления >= ДОБАВИТЬКДАТЕ(&ТекущаяДата, ЧАС, -Склады.СрокАктуальностиЧасов))";
// [восст.] "Дата >= ДатаОбновления": заказ, созданный ровно в момент загрузки, вычитается
// (момент берётся до запроса к Бергу). Если в оригинале было ">" - вернуть.
// [восст.] "ДатаОбновления >= ДОБАВИТЬКДАТЕ(...)" - однозначно по смыслу комментария.
// Параметры в этот пакет не передать: запрос собирает и выполняет БИТ.УМ.
Текст = СтрЗаменить(Текст, "&ИмяТиповойТаблицы", ИмяТиповойТаблицы);
Текст = СтрЗаменить(Текст, "&ТекущаяДата", ЛитералДаты(ТекущаяДатаСеанса()));
Возврат Текст;
КонецФункции
Функция ЛитералДаты(Дата)
Возврат СтрШаблон("ДАТАВРЕМЯ(%1, %2, %3, %4, %5, %6)",
XMLСтрока(Год(Дата)), XMLСтрока(Месяц(Дата)), XMLСтрока(День(Дата)),
XMLСтрока(Час(Дата)), XMLСтрока(Минута(Дата)), XMLСтрока(Секунда(Дата)));
КонецФункции
#КонецОбласти
#Область ЗагрузкаОстатков
// Возвращаемое значение:
// Соответствие - ключ: идентификатор склада Берга (Строка), значение: СправочникСсылка.Склады.
//
Функция СкладыПоставщика()
Запрос = Новый Запрос(
"ВЫБРАТЬ
| СкладыПоставщиков.Склад КАК Склад,
| СкладыПоставщиков.ИдентификаторСкладаПоставщика КАК ИдентификаторСкладаПоставщика
|ИЗ
| РегистрСведений.кор_СкладыПоставщиков КАК СкладыПоставщиков
|ГДЕ
| СкладыПоставщиков.Склад <> ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка)");
Результат = Новый Соответствие;
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Результат.Вставить(СокрЛП(Выборка.ИдентификаторСкладаПоставщика), Выборка.Склад);
КонецЦикла;
Возврат Результат;
КонецФункции
// Номенклатура, сопоставленная с товарами маркетплейсов в тех личных кабинетах,
// где склад поставщика указан среди складов FBS. Только её и имеет смысл спрашивать
// у Берга: целого прайса API не отдаёт, а каждая позиция - это часть запроса.
//
// Возвращаемое значение:
// ТаблицаЗначений - Номенклатура, Характеристика, Артикул, Бренд, ИдентификаторТовара.
//
Функция ПозицииДляЗапроса(НашиСклады)
Запрос = Новый Запрос(
"ВЫБРАТЬ
| Соответствие.Номенклатура КАК Номенклатура,
| Соответствие.Характеристика КАК Характеристика
|ПОМЕСТИТЬ ВТ_Позиции
|ИЗ
| РегистрСведений.топ_СоответствиеТоваров КАК Соответствие
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.топ_ЛичныеКабинеты.СписокСкладовFBS КАК СкладыFBS
| ПО Соответствие.Товар.ЛичныйКабинет = СкладыFBS.Ссылка
| И (СкладыFBS.Склад В (&Склады))
|ГДЕ
| Соответствие.Товар.Показывается
| И НЕ Соответствие.Товар.ПометкаУдаления
| И НЕ Соответствие.Номенклатура.ПометкаУдаления
|
|СГРУППИРОВАТЬ ПО
| Соответствие.Номенклатура,
| Соответствие.Характеристика
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| Позиции.Номенклатура КАК Номенклатура,
| Позиции.Характеристика КАК Характеристика,
| Позиции.Номенклатура.Артикул КАК Артикул,
| ЕСТЬNULL(Позиции.Номенклатура.Производитель.Наименование, """") КАК Производитель,
| ЕСТЬNULL(Позиции.Номенклатура.Марка.Наименование, """") КАК Марка,
| ЕСТЬNULL(МАКСИМУМ(Остатки.ИдентификаторТовараПоставщика), 0) КАК ИдентификаторТовара
|ИЗ
| ВТ_Позиции КАК Позиции
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.кор_ОстаткиПоставщиков КАК Остатки
| ПО Позиции.Номенклатура = Остатки.Номенклатура
| И Позиции.Характеристика = Остатки.Характеристика
| И (Остатки.Склад В (&Склады))
|
|СГРУППИРОВАТЬ ПО
| Позиции.Номенклатура,
| Позиции.Характеристика,
| Позиции.Номенклатура.Артикул,
| ЕСТЬNULL(Позиции.Номенклатура.Производитель.Наименование, """"),
| ЕСТЬNULL(Позиции.Номенклатура.Марка.Наименование, """")");
Запрос.УстановитьПараметр("Склады", НашиСклады);
Результат = Новый ТаблицаЗначений;
Результат.Колонки.Добавить("Номенклатура");
Результат.Колонки.Добавить("Характеристика");
Результат.Колонки.Добавить("Артикул", Новый ОписаниеТипов("Строка"));
Результат.Колонки.Добавить("Бренд", Новый ОписаниеТипов("Строка"));
Результат.Колонки.Добавить("ИдентификаторТовара", Новый ОписаниеТипов("Число"));
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Если ПустаяСтрока(Выборка.Артикул) И Выборка.ИдентификаторТовара = 0 Тогда
Продолжить;
КонецЕсли;
Строка = Результат.Добавить();
ЗаполнитьЗначенияСвойств(Строка, Выборка, "Номенклатура, Характеристика, ИдентификаторТовара");
Строка.Артикул = СокрЛП(Выборка.Артикул);
// Как во внешней обработке: бренд Берга - наш производитель, если его нет - марка.
Строка.Бренд = ?(ЗначениеЗаполнено(Выборка.Производитель), Выборка.Производитель, Выборка.Марка);
КонецЦикла;
Возврат Результат;
КонецФункции
Функция НоваяТаблицаЗаписей()
Таблица = Новый ТаблицаЗначений;
Таблица.Колонки.Добавить("Склад");
Таблица.Колонки.Добавить("Номенклатура");
Таблица.Колонки.Добавить("Характеристика");
Таблица.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число"));
Таблица.Колонки.Добавить("Цена", Новый ОписаниеТипов("Число"));
Таблица.Колонки.Добавить("ДоступноБольше", Новый ОписаниеТипов("Булево"));
Таблица.Колонки.Добавить("ИдентификаторТовараПоставщика", Новый ОписаниеТипов("Число"));
Таблица.Колонки.Добавить("ИдентификаторыСкладовПоставщика", Новый ОписаниеТипов("Строка"));
Таблица.Колонки.Добавить("ДатаОбновления", Новый ОписаниеТипов("Дата"));
Возврат Таблица;
КонецФункции
// Заводит по строке записи на каждый наш склад для каждой позиции, по которой Берг вернул
// ровно один товар, - с нулевым остатком. Нулевая запись нужна: она хранит id товара Берга
// для следующих запросов и явно обнуляет товар на маркетплейсе.
// Позиции, по которым товаров несколько, пропускаются: чей остаток брать, непонятно.
//
// Возвращаемое значение:
// Соответствие - ключ: Индекс позиции, значение: Соответствие (Склад - СтрокаТаблицыЗначений).
//
Функция СтрокиЗаписейПоПозициям(Предложения, Позиции, НашиСклады, МоментЗагрузки, Записи, Итоги)
ТоварыПозиций = Новый Соответствие;
Для Каждого Предложение Из Предложения Цикл
Если Предложение.ИндексПозиции = 0 Или Предложение.ResourceID = 0 Тогда
Продолжить;
КонецЕсли;
Товары = ТоварыПозиций.Получить(Предложение.ИндексПозиции);
Если Товары = Неопределено Тогда
Товары = Новый Массив;
ТоварыПозиций.Вставить(Предложение.ИндексПозиции, Товары);
КонецЕсли;
Если Товары.Найти(Предложение.ResourceID) = Неопределено Тогда
Товары.Добавить(Предложение.ResourceID);
КонецЕсли;
КонецЦикла;
СтрокиЗаписей = Новый Соответствие;
Для Каждого КлючИЗначение Из ТоварыПозиций Цикл
Позиция = Позиции[КлючИЗначение.Ключ - 1];
Товары = КлючИЗначение.Значение;
Если Товары.Количество() > 1 Тогда // [восст.]
Итоги.Неоднозначно = Итоги.Неоднозначно + 1;
ЗаписатьВЖурнал(УровеньЖурналаРегистрации.Предупреждение, СтрШаблон(
НСтр("ru = 'Берг вернул несколько товаров по позиции %1 (артикул %2, бренд %3): %4. Остаток не загружен - уточните бренд.'"),
Позиция.Номенклатура, Позиция.Артикул, Позиция.Бренд, СтрСоединить(Товары, ", ")));
Продолжить;
КонецЕсли;
Итоги.Найдено = Итоги.Найдено + 1;
СтрокиПоСкладам = Новый Соответствие;
Для Каждого Склад Из НашиСклады Цикл
Запись = Записи.Добавить();
Запись.Склад = Склад;
Запись.Номенклатура = Позиция.Номенклатура;
Запись.Характеристика = Позиция.Характеристика;
Запись.ИдентификаторТовараПоставщика = Товары[0];
Запись.ДатаОбновления = МоментЗагрузки;
СтрокиПоСкладам.Вставить(Склад, Запись);
КонецЦикла;
СтрокиЗаписей.Вставить(КлючИЗначение.Ключ, СтрокиПоСкладам);
КонецЦикла;
Возврат СтрокиЗаписей;
КонецФункции
// Складывает предложения складов Берга в записи наших складов по регистру кор_СкладыПоставщиков.
// Если одному нашему складу соответствует несколько складов Берга, количество суммируется,
// а цена берётся минимальная.
//
Процедура ЗаполнитьЗаписиПоПредложениям(СтрокиЗаписей, Предложения, СкладыПоставщика)
Для Каждого Предложение Из Предложения Цикл
СтрокиПоСкладам = СтрокиЗаписей.Получить(Предложение.ИндексПозиции);
Если СтрокиПоСкладам = Неопределено Тогда
Продолжить;
КонецЕсли;
ИдентификаторСклада = XMLСтрока(Предложение.СкладID);
Склад = СкладыПоставщика.Получить(ИдентификаторСклада);
Если Склад = Неопределено Тогда
Продолжить;
КонецЕсли;
Запись = СтрокиПоСкладам.Получить(Склад);
Запись.Количество = Запись.Количество + Предложение.Количество;
Если Предложение.Цена > 0 И (Запись.Цена = 0 Или Предложение.Цена < Запись.Цена) Тогда // [восст.]
Запись.Цена = Предложение.Цена;
КонецЕсли;
Запись.ДоступноБольше = Запись.ДоступноБольше Или Предложение.БольшеДоступно;
Если СтрНайти("," + Запись.ИдентификаторыСкладовПоставщика + ",", "," + ИдентификаторСклада + ",") = 0 Тогда
Запись.ИдентификаторыСкладовПоставщика = ?(ПустаяСтрока(Запись.ИдентификаторыСкладовПоставщика),
ИдентификаторСклада, Запись.ИдентификаторыСкладовПоставщика + "," + ИдентификаторСклада);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Процедура ДобавитьПрежниеЗаписи(Записи, Позиции, ИндексыСОшибкой, НашиСклады)
ПозицииСОшибкой = Новый ТаблицаЗначений;
ПозицииСОшибкой.Колонки.Добавить("Номенклатура", Метаданные.РегистрыСведений.кор_ОстаткиПоставщиков.Измерения.Номенклатура.Тип);
ПозицииСОшибкой.Колонки.Добавить("Характеристика", Метаданные.РегистрыСведений.кор_ОстаткиПоставщиков.Измерения.Характеристика.Тип);
Для Каждого Индекс Из ИндексыСОшибкой Цикл
ЗаполнитьЗначенияСвойств(ПозицииСОшибкой.Добавить(), Позиции[Индекс - 1]);
КонецЦикла;
Запрос = Новый Запрос(
"ВЫБРАТЬ
| Т.Номенклатура КАК Номенклатура,
| Т.Характеристика КАК Характеристика
|ПОМЕСТИТЬ ВТ_Позиции
|ИЗ
| &Позиции КАК Т
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| Остатки.Склад КАК Склад,
| Остатки.Номенклатура КАК Номенклатура,
| Остатки.Характеристика КАК Характеристика,
| Остатки.Количество КАК Количество,
| Остатки.Цена КАК Цена,
| Остатки.ДоступноБольше КАК ДоступноБольше,
| Остатки.ИдентификаторТовараПоставщика КАК ИдентификаторТовараПоставщика,
| Остатки.ИдентификаторыСкладовПоставщика КАК ИдентификаторыСкладовПоставщика,
| Остатки.ДатаОбновления КАК ДатаОбновления
|ИЗ
| РегистрСведений.кор_ОстаткиПоставщиков КАК Остатки
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Позиции КАК Позиции
| ПО Остатки.Номенклатура = Позиции.Номенклатура
| И Остатки.Характеристика = Позиции.Характеристика
|ГДЕ
| Остатки.Склад В (&Склады)");
Запрос.УстановитьПараметр("Позиции", ПозицииСОшибкой);
Запрос.УстановитьПараметр("Склады", НашиСклады);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
ЗаполнитьЗначенияСвойств(Записи.Добавить(), Выборка);
КонецЦикла;
КонецПроцедуры
// Перезаписывает регистр по каждому нашему складу целиком: позиции, которых больше нет
// в ответе Берга (или на маркетплейсах), уходят из регистра, и остаток по ним становится 0.
//
Процедура ЗаписатьОстатки(Записи, НашиСклады)
Для Каждого Склад Из НашиСклады Цикл
Набор = РегистрыСведений.кор_ОстаткиПоставщиков.СоздатьНаборЗаписей();
Набор.Отбор.Склад.Установить(Склад);
Для Каждого Строка Из Записи.НайтиСтроки(Новый Структура("Склад", Склад)) Цикл
ЗаполнитьЗначенияСвойств(Набор.Добавить(), Строка);
КонецЦикла;
Попытка
Набор.Записать();
Исключение
ЗаписатьВЖурнал(УровеньЖурналаРегистрации.Ошибка, СтрШаблон(
НСтр("ru = 'Не удалось записать остатки Берга по складу %1: %2'"),
Склад, ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())));
КонецПопытки;
КонецЦикла;
КонецПроцедуры
Процедура ЗаписатьВЖурнал(Уровень, Текст)
ЗаписьЖурналаРегистрации(кор_HTTPКоннектор.ИмяСобытияЖурнала(), Уровень,
Метаданные.РегистрыСведений.кор_ОстаткиПоставщиков,, Текст);
КонецПроцедуры
#КонецОбласти
#КонецОбласти