diff --git a/CHANGELOG.md b/CHANGELOG.md
index e88ce25..3a9eec1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,20 @@
# История изменений crm3-26.rhana
-Формат версии: `1.3.0.NNN` (синхронизируется с `VERSION` и `Configuration.xml`).
+Формат версии: `1.3.0.NNN` / `1.3.1.NNN` (синхронизируется с `VERSION` и `Configuration.xml`).
+
+---
+
+## 1.3.1.49 (2026-08-10)
+
+### Обработка РК_ЗагрузкаОстатков — подбор складов и предварительные остатки
+
+- Общий модуль `РК_ОбменСВнешнейБазой`: HTTP-клиент Transfer API по `РК_НастройкиПодключенияКВнешнейБазе`.
+- Подбор складов исходной ИБ (`POST /v1/stock/warehouses`) в отбор на форме.
+- Загрузка остатков (`POST /v1/stock/balances`, mode=`combined`) в ТЧ `ВходящиеДанные` с детализацией (кол-во, артикул, код, характеристика, серия/ГТД GUID, вид, политика, организация).
+- Шаг «Сопоставить»: поиск НСИ + создание серий-заглушек `Перенос_<склад>_<дата>` по логике BSL-переноса остатков (тест / запись).
+- Создание документов ввода остатков — следующий шаг (пока не реализовано).
+
+Пара: `ws-rhana` 0.0.0.30 (endpoint складов + `nomenclature_article`).
---
diff --git a/VERSION b/VERSION
index f8edff9..e77903a 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.3.1.48
+1.3.1.49
diff --git a/src/CommonModules/РК_ОбменСВнешнейБазой.xml b/src/CommonModules/РК_ОбменСВнешнейБазой.xml
new file mode 100644
index 0000000..198163e
--- /dev/null
+++ b/src/CommonModules/РК_ОбменСВнешнейБазой.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ РК_ОбменСВнешнейБазой
+
+
+ ru
+ Обмен с внешней базой
+
+
+ HTTP-клиент Transfer API по настройкам РК_НастройкиПодключенияКВнешнейБазе
+ false
+ false
+ true
+ false
+ false
+ true
+ false
+ DontUse
+
+
+
diff --git a/src/CommonModules/РК_ОбменСВнешнейБазой/Ext/Module.bsl b/src/CommonModules/РК_ОбменСВнешнейБазой/Ext/Module.bsl
new file mode 100644
index 0000000..0065ae1
--- /dev/null
+++ b/src/CommonModules/РК_ОбменСВнешнейБазой/Ext/Module.bsl
@@ -0,0 +1,190 @@
+
+#Область ПрограммныйИнтерфейс
+
+// Настройки подключения из элемента справочника РК_НастройкиПодключенияКВнешнейБазе.
+//
+Функция НастройкиПодключения(Подключение) Экспорт
+
+ Если Не ЗначениеЗаполнено(Подключение) Тогда
+ ВызватьИсключение "Не указано подключение к сторонней базе";
+ КонецЕсли;
+
+ Реквизиты = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(Подключение,
+ "АдресПодключения, Токен, Таймаут, Логин, Пароль, Активно, ИмяТекущейБазы");
+
+ Если Реквизиты.Активно = Ложь Тогда
+ ВызватьИсключение "Подключение к сторонней базе отключено (Активно = Ложь)";
+ КонецЕсли;
+
+ Адрес = СокрЛП(Строка(Реквизиты.АдресПодключения));
+ Если ПустаяСтрока(Адрес) Тогда
+ ВызватьИсключение "В настройке подключения не заполнен АдресПодключения";
+ КонецЕсли;
+
+ Таймаут = 120;
+ Попытка
+ Таймаут = Число(Реквизиты.Таймаут);
+ Исключение
+ Таймаут = 120;
+ КонецПопытки;
+ Если Таймаут <= 0 Тогда
+ Таймаут = 120;
+ КонецЕсли;
+
+ Настройки = Новый Структура;
+ Настройки.Вставить("Адрес", Адрес);
+ Настройки.Вставить("Токен", СокрЛП(Строка(Реквизиты.Токен)));
+ Настройки.Вставить("Таймаут", Таймаут);
+ Настройки.Вставить("Логин", СокрЛП(Строка(Реквизиты.Логин)));
+ Настройки.Вставить("Пароль", Строка(Реквизиты.Пароль));
+ Настройки.Вставить("ИмяТекущейБазы", СокрЛП(Строка(Реквизиты.ИмяТекущейБазы)));
+ Возврат Настройки;
+
+КонецФункции
+
+// POST /v1/stock/warehouses на исходной ИБ.
+//
+Функция СписокСкладовВнешнейБазы(Подключение, ПараметрыЗапроса = Неопределено) Экспорт
+
+ Если ПараметрыЗапроса = Неопределено Тогда
+ ПараметрыЗапроса = Новый Структура;
+ КонецЕсли;
+ Настройки = НастройкиПодключения(Подключение);
+ Возврат ВыполнитьPOST(Настройки, "v1/stock/warehouses", ПараметрыЗапроса);
+
+КонецФункции
+
+// POST /v1/stock/balances на исходной ИБ.
+//
+Функция ОстаткиВнешнейБазы(Подключение, ПараметрыЗапроса) Экспорт
+
+ Если ПараметрыЗапроса = Неопределено Тогда
+ ПараметрыЗапроса = Новый Структура;
+ КонецЕсли;
+ Настройки = НастройкиПодключения(Подключение);
+ Возврат ВыполнитьPOST(Настройки, "v1/stock/balances", ПараметрыЗапроса);
+
+КонецФункции
+
+// Универсальный POST к Transfer API.
+//
+Функция ВыполнитьPOST(НастройкиПодключения, ОтносительныйПуть, Тело) Экспорт
+
+ Возврат ВыполнитьHTTPЗапросЛокально(НастройкиПодключения, ОтносительныйПуть, Тело);
+
+КонецФункции
+
+#КонецОбласти
+
+#Область СлужебныеПроцедурыИФункции
+
+Функция ВыполнитьHTTPЗапросЛокально(НастройкиПодключения, ОтносительныйПуть, Тело)
+
+ АдресБазы = СокрЛП(Строка(НастройкиПодключения.Адрес));
+ Ключ = СокрЛП(Строка(НастройкиПодключения.Токен));
+ Таймаут = 120;
+ Попытка
+ Таймаут = Число(НастройкиПодключения.Таймаут);
+ Исключение
+ Таймаут = 120;
+ КонецПопытки;
+ Если Таймаут <= 0 Тогда
+ Таймаут = 120;
+ КонецЕсли;
+
+ Логин = "";
+ Пароль = "";
+ Если НастройкиПодключения.Свойство("Логин") Тогда
+ Логин = СокрЛП(Строка(НастройкиПодключения.Логин));
+ КонецЕсли;
+ Если НастройкиПодключения.Свойство("Пароль") Тогда
+ Пароль = Строка(НастройкиПодключения.Пароль);
+ КонецЕсли;
+
+ Если Тело = Неопределено Тогда
+ Тело = Новый Структура;
+ КонецЕсли;
+
+ Запись = Новый ЗаписьJSON;
+ Запись.УстановитьСтроку(Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Нет));
+ ЗаписатьJSON(Запись, Тело);
+ ТекстТела = Запись.Закрыть();
+
+ Разбор = РазобратьURL(АдресБазы);
+ ПутьЗапроса = Разбор.Путь;
+ Если Не СтрЗаканчиваетсяНа(ПутьЗапроса, "/") Тогда
+ ПутьЗапроса = ПутьЗапроса + "/";
+ КонецЕсли;
+ Относительный = СокрЛП(ОтносительныйПуть);
+ Если СтрНачинаетсяС(Относительный, "/") Тогда
+ Относительный = Сред(Относительный, 2);
+ КонецЕсли;
+ ПутьЗапроса = ПутьЗапроса + Относительный;
+
+ ПользовательHTTP = ?(ПустаяСтрока(Логин), Разбор.Пользователь, Логин);
+ ПарольHTTP = ?(ПустаяСтрока(Логин), Разбор.Пароль, Пароль);
+
+ Соединение = Новый HTTPСоединение(
+ Разбор.Хост,
+ Разбор.Порт,
+ ПользовательHTTP,
+ ПарольHTTP,
+ ,
+ Таймаут,
+ ?(Разбор.HTTPS, Новый ЗащищенноеСоединениеOpenSSL(), Неопределено));
+
+ ЗапросHTTP = Новый HTTPЗапрос(ПутьЗапроса);
+ Если Не ПустаяСтрока(Ключ) Тогда
+ ЗапросHTTP.Заголовки.Вставить("Authorization", "Bearer " + Ключ);
+ КонецЕсли;
+ ЗапросHTTP.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
+ ЗапросHTTP.УстановитьТелоИзСтроки(ТекстТела, КодировкаТекста.UTF8);
+
+ ОтветHTTP = Соединение.ОтправитьДляОбработки(ЗапросHTTP);
+ ТекстОтвета = ОтветHTTP.ПолучитьТелоКакСтроку();
+
+ Если ОтветHTTP.КодСостояния < 200 Или ОтветHTTP.КодСостояния >= 300 Тогда
+ ЗаписьЖурналаРегистрации("РК_ОбменСВнешнейБазой", УровеньЖурналаРегистрации.Ошибка, , ,
+ "HTTP " + ОтветHTTP.КодСостояния + " " + Относительный + ": " + ТекстОтвета);
+ ВызватьИсключение "Ошибка HTTP " + ОтветHTTP.КодСостояния + ": " + ТекстОтвета;
+ КонецЕсли;
+
+ Чтение = Новый ЧтениеJSON;
+ Чтение.УстановитьСтроку(ТекстОтвета);
+ Результат = ПрочитатьJSON(Чтение);
+ Чтение.Закрыть();
+ Возврат Результат;
+
+КонецФункции
+
+Функция РазобратьURL(Адрес)
+
+ Результат = Новый Структура("Хост, Порт, Путь, HTTPS, Пользователь, Пароль", "", 0, "", Ложь, "", "");
+
+ СтрокаURL = СокрЛП(Адрес);
+ HTTPS = СтрНачинаетсяС(НРег(СтрокаURL), "https://");
+ Если СтрНачинаетсяС(НРег(СтрокаURL), "http://") Тогда
+ СтрокаURL = Сред(СтрокаURL, 8);
+ ИначеЕсли HTTPS Тогда
+ СтрокаURL = Сред(СтрокаURL, 9);
+ КонецЕсли;
+ Результат.HTTPS = HTTPS;
+
+ ПозицияПути = СтрНайти(СтрокаURL, "/");
+ ХостПорт = ?(ПозицияПути > 0, Лев(СтрокаURL, ПозицияПути - 1), СтрокаURL);
+ Результат.Путь = ?(ПозицияПути > 0, Сред(СтрокаURL, ПозицияПути), "/");
+
+ ПозицияПорта = СтрНайти(ХостПорт, ":");
+ Если ПозицияПорта > 0 Тогда
+ Результат.Хост = Лев(ХостПорт, ПозицияПорта - 1);
+ Результат.Порт = Число(Сред(ХостПорт, ПозицияПорта + 1));
+ Иначе
+ Результат.Хост = ХостПорт;
+ Результат.Порт = ?(HTTPS, 443, 80);
+ КонецЕсли;
+
+ Возврат Результат;
+
+КонецФункции
+
+#КонецОбласти
diff --git a/src/Configuration.xml b/src/Configuration.xml
index f524a20..14c1bb2 100644
--- a/src/Configuration.xml
+++ b/src/Configuration.xml
@@ -62,7 +62,7 @@
Role.РК_ОсновнаяРоль
- 1.3.1.48
+ 1.3.1.49
Language.Русский
@@ -95,6 +95,7 @@
РК_ОбщегоНазначения
РК_ОбщегоНазначенияКлиентСервер
РК_ОбщегоНазначенияВызовСервера
+ РК_ОбменСВнешнейБазой
ОбщегоНазначенияКлиентСервер
МенеджерОбменаЧерезУниверсальныйФормат
ОбменДаннымиXDTOСервер
diff --git a/src/DataProcessors/РК_ЗагрузкаОстатков.xml b/src/DataProcessors/РК_ЗагрузкаОстатков.xml
index 98be217..bffd6c2 100644
--- a/src/DataProcessors/РК_ЗагрузкаОстатков.xml
+++ b/src/DataProcessors/РК_ЗагрузкаОстатков.xml
@@ -468,6 +468,867 @@
Auto
+
+
+ Количество
+
+
+ ru
+ Количество
+
+
+
+
+ xs:decimal
+
+ 15
+ 3
+ Any
+
+
+ false
+
+
+
+ false
+
+ false
+ false
+
+
+ false
+ 0
+ DontCheck
+ Items
+
+
+ Auto
+ Auto
+
+
+ Auto
+
+
+
+
+
+ КоличествоКОтгрузке
+
+
+ ru
+ К отгрузке
+
+
+
+
+ xs:decimal
+
+ 15
+ 3
+ Any
+
+
+ false
+
+
+
+ false
+
+ false
+ false
+
+
+ false
+ 0
+ DontCheck
+ Items
+
+
+ Auto
+ Auto
+
+
+ Auto
+
+
+
+
+
+ КоличествоОрганизации
+
+
+ ru
+ Кол. организации
+
+
+
+
+ xs:decimal
+
+ 15
+ 3
+ Any
+
+
+ false
+
+
+
+ false
+
+ false
+ false
+
+
+ false
+ 0
+ DontCheck
+ Items
+
+
+ Auto
+ Auto
+
+
+ Auto
+
+
+
+
+
+ Артикул
+
+
+ ru
+ Артикул
+
+
+
+
+ xs:string
+
+ 50
+ Variable
+
+
+ false
+
+
+
+ false
+
+ false
+ false
+
+
+ false
+
+ DontCheck
+ Items
+
+
+ Auto
+ Auto
+
+
+ Auto
+
+
+
+
+
+ НоменклатураКод
+
+
+ ru
+ Код
+
+
+
+
+ xs:string
+
+ 50
+ Variable
+
+
+ false
+
+
+
+ false
+
+ false
+ false
+
+
+ false
+
+ DontCheck
+ Items
+
+
+ Auto
+ Auto
+
+
+ Auto
+
+
+
+
+
+ ХарактеристикаНаименование
+
+
+ ru
+ Характеристика
+
+
+
+
+ xs:string
+
+ 150
+ Variable
+
+
+ false
+
+
+
+ false
+
+ false
+ false
+
+
+ false
+
+ DontCheck
+ Items
+
+
+ Auto
+ Auto
+
+
+ Auto
+
+
+
+
+
+ ХарактеристикаИдентификатор
+
+
+ ru
+ Характеристика идентификатор
+
+
+
+
+ v8:UUID
+
+ false
+
+
+
+ false
+
+ false
+ false
+
+
+ false
+
+ DontCheck
+ Items
+
+
+ Auto
+ Auto
+
+
+ Auto
+
+
+
+
+
+ СерияИдентификатор
+
+
+ ru
+ Серия идентификатор
+
+
+
+
+ v8:UUID
+
+ false
+
+
+
+ false
+
+ false
+ false
+
+
+ false
+
+ DontCheck
+ Items
+
+
+ Auto
+ Auto
+
+
+ Auto
+
+
+
+
+
+ ГТДИдентификатор
+
+
+ ru
+ ГТД идентификатор
+
+
+
+
+ v8:UUID
+
+ false
+
+
+
+ false
+
+ false
+ false
+
+
+ false
+
+ DontCheck
+ Items
+
+
+ Auto
+ Auto
+
+
+ Auto
+
+
+
+
+
+ ВидНоменклатурыНаименование
+
+
+ ru
+ Вид номенклатуры
+
+
+
+
+ xs:string
+
+ 150
+ Variable
+
+
+ false
+
+
+
+ false
+
+ false
+ false
+
+
+ false
+
+ DontCheck
+ Items
+
+
+ Auto
+ Auto
+
+
+ Auto
+
+
+
+
+
+ ВидНоменклатурыИдентификатор
+
+
+ ru
+ Вид номенклатуры идентификатор
+
+
+
+
+ v8:UUID
+
+ false
+
+
+
+ false
+
+ false
+ false
+
+
+ false
+
+ DontCheck
+ Items
+
+
+ Auto
+ Auto
+
+
+ Auto
+
+
+
+
+
+ ПолитикаСерии
+
+
+ ru
+ Политика серии
+
+
+
+
+ xs:string
+
+ 100
+ Variable
+
+
+ false
+
+
+
+ false
+
+ false
+ false
+
+
+ false
+
+ DontCheck
+ Items
+
+
+ Auto
+ Auto
+
+
+ Auto
+
+
+
+
+
+ ПолитикаХарактеристик
+
+
+ ru
+ Политика характеристик
+
+
+
+
+ xs:string
+
+ 100
+ Variable
+
+
+ false
+
+
+
+ false
+
+ false
+ false
+
+
+ false
+
+ DontCheck
+ Items
+
+
+ Auto
+ Auto
+
+
+ Auto
+
+
+
+
+
+ ОрганизацияНаименование
+
+
+ ru
+ Организация
+
+
+
+
+ xs:string
+
+ 150
+ Variable
+
+
+ false
+
+
+
+ false
+
+ false
+ false
+
+
+ false
+
+ DontCheck
+ Items
+
+
+ Auto
+ Auto
+
+
+ Auto
+
+
+
+
+
+ ОрганизацияИдентификатор
+
+
+ ru
+ Организация идентификатор
+
+
+
+
+ v8:UUID
+
+ false
+
+
+
+ false
+
+ false
+ false
+
+
+ false
+
+ DontCheck
+ Items
+
+
+ Auto
+ Auto
+
+
+ Auto
+
+
+
+
+
+ Номенклатура
+
+
+ ru
+ Номенклатура
+
+
+
+
+ cfg:CatalogRef.Номенклатура
+
+ false
+
+
+
+ false
+
+ false
+ false
+
+
+ false
+
+ DontCheck
+ Items
+
+
+ Auto
+ Auto
+
+
+ Auto
+
+
+
+
+
+ Склад
+
+
+ ru
+ Склад
+
+
+
+
+ cfg:CatalogRef.Склады
+
+ false
+
+
+
+ false
+
+ false
+ false
+
+
+ false
+
+ DontCheck
+ Items
+
+
+ Auto
+ Auto
+
+
+ Auto
+
+
+
+
+
+ Характеристика
+
+
+ ru
+ Характеристика (цель)
+
+
+
+
+ cfg:CatalogRef.ХарактеристикиНоменклатуры
+
+ false
+
+
+
+ false
+
+ false
+ false
+
+
+ false
+
+ DontCheck
+ Items
+
+
+ Auto
+ Auto
+
+
+ Auto
+
+
+
+
+
+ СерияСсылка
+
+
+ ru
+ Серия (цель)
+
+
+
+
+ cfg:CatalogRef.СерииНоменклатуры
+
+ false
+
+
+
+ false
+
+ false
+ false
+
+
+ false
+
+ DontCheck
+ Items
+
+
+ Auto
+ Auto
+
+
+ Auto
+
+
+
+
+
+ НомерГТДСсылка
+
+
+ ru
+ Номер ГТД (цель)
+
+
+
+
+ cfg:CatalogRef.НомераГТД
+
+ false
+
+
+
+ false
+
+ false
+ false
+
+
+ false
+
+ DontCheck
+ Items
+
+
+ Auto
+ Auto
+
+
+ Auto
+
+
+
+
+
+ Сопоставлено
+
+
+ ru
+ Сопоставлено
+
+
+
+
+ xs:boolean
+
+ false
+
+
+
+ false
+
+ false
+ false
+
+
+ false
+ false
+ DontCheck
+ Items
+
+
+ Auto
+ Auto
+
+
+ Auto
+
+
+
+
+
+ КомментарийСопоставления
+
+
+ ru
+ Комментарий сопоставления
+
+
+
+
+ xs:string
+
+ 500
+ Variable
+
+
+ false
+
+
+
+ false
+
+ false
+ false
+
+
+ false
+
+ DontCheck
+ Items
+
+
+ Auto
+ Auto
+
+
+ Auto
+
+
+
diff --git a/src/DataProcessors/РК_ЗагрузкаОстатков/Ext/ObjectModule.bsl b/src/DataProcessors/РК_ЗагрузкаОстатков/Ext/ObjectModule.bsl
new file mode 100644
index 0000000..cbc5d36
--- /dev/null
+++ b/src/DataProcessors/РК_ЗагрузкаОстатков/Ext/ObjectModule.bsl
@@ -0,0 +1,439 @@
+
+#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
+
+#Область ПрограммныйИнтерфейс
+
+// Заполняет ТЧ ВходящиеДанные строками остатков Transfer API (mode=combined по умолчанию).
+//
+Процедура ЗаполнитьВходящиеДанныеИзОтветаОстатков(ОтветAPI, ОчищатьПередЗаполнением = Истина) Экспорт
+
+ Если ОчищатьПередЗаполнением Тогда
+ ВходящиеДанные.Очистить();
+ КонецЕсли;
+
+ СтрокиОтвета = Неопределено;
+ Если ТипЗнч(ОтветAPI) = Тип("Структура") Или ТипЗнч(ОтветAPI) = Тип("Соответствие") Тогда
+ СтрокиОтвета = ЗначениеСвойства(ОтветAPI, "rows", Неопределено);
+ КонецЕсли;
+ Если ТипЗнч(СтрокиОтвета) <> Тип("Массив") Тогда
+ Возврат;
+ КонецЕсли;
+
+ Для Каждого СтрокаAPI Из СтрокиОтвета Цикл
+ НовСтр = ВходящиеДанные.Добавить();
+ ЗаполнитьСтрокуВходящихДанныхИзAPI(НовСтр, СтрокаAPI);
+ КонецЦикла;
+
+КонецПроцедуры
+
+// Сопоставление строк ТЧ с НСИ целевой ИБ + создание серий-заглушек при необходимости.
+// Алгоритм — по логике scripts/generate_balances_apply_bsl.py (артикул/GUID/код/имя; серии Перенос_*).
+//
+// Параметры:
+// РежимТест - Булево - Истина: только поиск, без создания серий/характеристик
+//
+// Возвращаемое значение:
+// Структура - Сопоставлено, НеСопоставлено, СозданоСерий, СозданоХарактеристик
+//
+Функция СопоставитьВходящиеДанные(РежимТест = Истина) Экспорт
+
+ Результат = Новый Структура;
+ Результат.Вставить("Сопоставлено", 0);
+ Результат.Вставить("НеСопоставлено", 0);
+ Результат.Вставить("СозданоСерий", 0);
+ Результат.Вставить("СозданоХарактеристик", 0);
+
+ СуффиксДатыСер = Формат(?(ЗначениеЗаполнено(ДатаДокументовВвода), ДатаДокументовВвода, ДатаОстатков), "ДФ=yyyyMMdd");
+ Если ПустаяСтрока(СуффиксДатыСер) Тогда
+ СуффиксДатыСер = Формат(ТекущаяДатаСеанса(), "ДФ=yyyyMMdd");
+ КонецЕсли;
+
+ КэшТребуетсяСерия = Новый Соответствие;
+ КэшСерий = Новый Соответствие;
+
+ Для Каждого СтрТ Из ВходящиеДанные Цикл
+
+ СтрТ.Сопоставлено = Ложь;
+ СтрТ.КомментарийСопоставления = "";
+ СтрТ.Номенклатура = Справочники.Номенклатура.ПустаяСсылка();
+ СтрТ.Склад = Справочники.Склады.ПустаяСсылка();
+ СтрТ.Характеристика = Справочники.ХарактеристикиНоменклатуры.ПустаяСсылка();
+ СтрТ.СерияСсылка = Справочники.СерииНоменклатуры.ПустаяСсылка();
+ СтрТ.НомерГТДСсылка = Справочники.НомераГТД.ПустаяСсылка();
+
+ Ном = НайтиНоменклатуруСтроки(СтрТ);
+ Если Не ЗначениеЗаполнено(Ном) Тогда
+ СтрТ.КомментарийСопоставления = "Номенклатура не найдена";
+ Результат.НеСопоставлено = Результат.НеСопоставлено + 1;
+ Продолжить;
+ КонецЕсли;
+ СтрТ.Номенклатура = Ном;
+
+ СкладЦель = НайтиСкладСтроки(СтрТ);
+ Если Не ЗначениеЗаполнено(СкладЦель) Тогда
+ СтрТ.КомментарийСопоставления = "Склад не найден";
+ Результат.НеСопоставлено = Результат.НеСопоставлено + 1;
+ Продолжить;
+ КонецЕсли;
+ СтрТ.Склад = СкладЦель;
+
+ Хар = НайтиИлиСоздатьХарактеристику(СтрТ, Ном, РежимТест, Результат);
+ СтрТ.Характеристика = Хар;
+
+ Сер = НайтиИлиСоздатьСерию(СтрТ, Ном, СкладЦель, СуффиксДатыСер, РежимТест,
+ КэшТребуетсяСерия, КэшСерий, Результат);
+ СтрТ.СерияСсылка = Сер;
+
+ Если ЗначениеЗаполнено(СтрТ.ГТД) Тогда
+ КодГТД = СокрЛП(СтрТ.ГТД);
+ СтрТ.НомерГТДСсылка = Справочники.НомераГТД.НайтиПоКоду(КодГТД);
+ Если Не ЗначениеЗаполнено(СтрТ.НомерГТДСсылка) Тогда
+ СтрТ.НомерГТДСсылка = Справочники.НомераГТД.НайтиПоРеквизиту("РегистрационныйНомер", КодГТД);
+ КонецЕсли;
+ Если Не ЗначениеЗаполнено(СтрТ.НомерГТДСсылка) Тогда
+ СтрТ.НомерГТДСсылка = Справочники.НомераГТД.НайтиПоНаименованию(КодГТД, Истина);
+ КонецЕсли;
+ Если Не ЗначениеЗаполнено(СтрТ.НомерГТДСсылка) Тогда
+ СсылкаГТД = СсылкаПоUUID(Справочники.НомераГТД, СтрТ.ГТДИдентификатор);
+ Если ЗначениеЗаполнено(СсылкаГТД) И ОбщегоНазначения.СсылкаСуществует(СсылкаГТД) Тогда
+ СтрТ.НомерГТДСсылка = СсылкаГТД;
+ КонецЕсли;
+ КонецЕсли;
+ КонецЕсли;
+
+ СтрТ.Сопоставлено = Истина;
+ Если ПустаяСтрока(СтрТ.КомментарийСопоставления) Тогда
+ СтрТ.КомментарийСопоставления = "OK";
+ КонецЕсли;
+ Результат.Сопоставлено = Результат.Сопоставлено + 1;
+
+ КонецЦикла;
+
+ Возврат Результат;
+
+КонецФункции
+
+#КонецОбласти
+
+#Область СлужебныеПроцедурыИФункции
+
+Процедура ЗаполнитьСтрокуВходящихДанныхИзAPI(НовСтр, СтрокаAPI)
+
+ НовСтр.НоменклатураИдентификатор = UUIDИзСтроки(ЗначениеСвойства(СтрокаAPI, "nomenclature_guid", ""));
+ НовСтр.НоменклатураНаименование = СокрЛП(Строка(ЗначениеСвойства(СтрокаAPI, "nomenclature_name", "")));
+ НовСтр.НоменклатураКод = СокрЛП(Строка(ЗначениеСвойства(СтрокаAPI, "nomenclature_code", "")));
+ НовСтр.Артикул = СокрЛП(Строка(ЗначениеСвойства(СтрокаAPI, "nomenclature_article", "")));
+
+ НовСтр.СкладИдентификатор = UUIDИзСтроки(ЗначениеСвойства(СтрокаAPI, "warehouse_guid", ""));
+ НовСтр.СкладНаименование = СокрЛП(Строка(ЗначениеСвойства(СтрокаAPI, "warehouse_name", "")));
+
+ НовСтр.ЕдИзмИдентификатор = UUIDИзСтроки(ЗначениеСвойства(СтрокаAPI, "unit_guid", ""));
+ НовСтр.ЕдИзм = СокрЛП(Строка(ЗначениеСвойства(СтрокаAPI, "unit_name", "")));
+ Если ПустаяСтрока(НовСтр.ЕдИзм) Тогда
+ НовСтр.ЕдИзм = СокрЛП(Строка(ЗначениеСвойства(СтрокаAPI, "unit_code", "")));
+ КонецЕсли;
+
+ НовСтр.ХарактеристикаИдентификатор = UUIDИзСтроки(ЗначениеСвойства(СтрокаAPI, "characteristic_guid", ""));
+ НовСтр.ХарактеристикаНаименование = СокрЛП(Строка(ЗначениеСвойства(СтрокаAPI, "characteristic_name", "")));
+
+ НовСтр.СерияИдентификатор = UUIDИзСтроки(ЗначениеСвойства(СтрокаAPI, "series_guid", ""));
+ НовСтр.Серия = СокрЛП(Строка(ЗначениеСвойства(СтрокаAPI, "series_name", "")));
+
+ НовСтр.ГТДИдентификатор = UUIDИзСтроки(ЗначениеСвойства(СтрокаAPI, "gtd_guid", ""));
+ НовСтр.ГТД = СокрЛП(Строка(ЗначениеСвойства(СтрокаAPI, "gtd_name", "")));
+
+ НовСтр.ОрганизацияИдентификатор = UUIDИзСтроки(ЗначениеСвойства(СтрокаAPI, "organization_guid", ""));
+ НовСтр.ОрганизацияНаименование = СокрЛП(Строка(ЗначениеСвойства(СтрокаAPI, "organization_name", "")));
+
+ НовСтр.Количество = ЧислоИзЗначения(ЗначениеСвойства(СтрокаAPI, "qty_warehouse",
+ ЗначениеСвойства(СтрокаAPI, "qty_org", 0)), 0);
+ НовСтр.КоличествоКОтгрузке = ЧислоИзЗначения(ЗначениеСвойства(СтрокаAPI, "qty_to_ship", 0), 0);
+ НовСтр.КоличествоОрганизации = ЧислоИзЗначения(ЗначениеСвойства(СтрокаAPI, "qty_org", 0), 0);
+
+ НовСтр.ВидНоменклатурыИдентификатор = UUIDИзСтроки(ЗначениеСвойства(СтрокаAPI, "policy_kind_guid", ""));
+ НовСтр.ВидНоменклатурыНаименование = СокрЛП(Строка(ЗначениеСвойства(СтрокаAPI, "policy_kind_name", "")));
+ НовСтр.ПолитикаСерии = СокрЛП(Строка(ЗначениеСвойства(СтрокаAPI, "policy_use_series", "")));
+ НовСтр.ПолитикаХарактеристик = СокрЛП(Строка(ЗначениеСвойства(СтрокаAPI, "policy_use_characteristics", "")));
+
+ НовСтр.Сопоставлено = Ложь;
+ НовСтр.КомментарийСопоставления = "";
+
+КонецПроцедуры
+
+Функция НайтиНоменклатуруСтроки(СтрТ)
+
+ Ном = Справочники.Номенклатура.ПустаяСсылка();
+ Арт = СокрЛП(СтрТ.Артикул);
+ ИмяНом = СокрЛП(СтрТ.НоменклатураНаименование);
+ КодНом = СокрЛП(СтрТ.НоменклатураКод);
+
+ Если ЗначениеЗаполнено(Арт) Тогда
+ Ном = Справочники.Номенклатура.НайтиПоРеквизиту("Артикул", Арт);
+ КонецЕсли;
+
+ Если Не ЗначениеЗаполнено(Ном) Тогда
+ СсылкаПоГуид = СсылкаПоUUID(Справочники.Номенклатура, СтрТ.НоменклатураИдентификатор);
+ Если ЗначениеЗаполнено(СсылкаПоГуид) И ОбщегоНазначения.СсылкаСуществует(СсылкаПоГуид) Тогда
+ Ном = СсылкаПоГуид;
+ КонецЕсли;
+ КонецЕсли;
+
+ Если Не ЗначениеЗаполнено(Ном) И ЗначениеЗаполнено(КодНом) Тогда
+ Ном = Справочники.Номенклатура.НайтиПоКоду(КодНом);
+ КонецЕсли;
+
+ Если Не ЗначениеЗаполнено(Ном) И ЗначениеЗаполнено(ИмяНом) Тогда
+ Ном = Справочники.Номенклатура.НайтиПоНаименованию(ИмяНом, Истина);
+ КонецЕсли;
+
+ Если ЗначениеЗаполнено(Ном) И ЗначениеЗаполнено(ИмяНом) Тогда
+ Если СокрЛП(Ном.Наименование) <> ИмяНом Тогда
+ СтрТ.КомментарийСопоставления = "Номенклатура не совпала по имени: " + ИмяНом + " → " + Ном.Наименование;
+ Возврат Справочники.Номенклатура.ПустаяСсылка();
+ КонецЕсли;
+ КонецЕсли;
+
+ Возврат Ном;
+
+КонецФункции
+
+Функция НайтиСкладСтроки(СтрТ)
+
+ СкладЦель = СсылкаПоUUID(Справочники.Склады, СтрТ.СкладИдентификатор);
+ Если ЗначениеЗаполнено(СкладЦель) И ОбщегоНазначения.СсылкаСуществует(СкладЦель) Тогда
+ Возврат СкладЦель;
+ КонецЕсли;
+
+ ИмяСкл = СокрЛП(СтрТ.СкладНаименование);
+ Если ЗначениеЗаполнено(ИмяСкл) Тогда
+ Возврат Справочники.Склады.НайтиПоНаименованию(ИмяСкл, Истина);
+ КонецЕсли;
+ Возврат Справочники.Склады.ПустаяСсылка();
+
+КонецФункции
+
+Функция НайтиИлиСоздатьХарактеристику(СтрТ, Ном, РежимТест, Результат)
+
+ Хар = Справочники.ХарактеристикиНоменклатуры.ПустаяСсылка();
+ ИмяХар = СокрЛП(СтрТ.ХарактеристикаНаименование);
+ ВидНом = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ном, "ВидНоменклатуры");
+
+ ИспХар = Ложь;
+ Попытка
+ ИспХар = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ном, "ВидНоменклатуры.ИспользоватьХарактеристики") = Истина;
+ Исключение
+ Попытка
+ ИспХар = ВидНом.ИспользоватьХарактеристики;
+ Исключение
+ КонецПопытки;
+ КонецПопытки;
+
+ Если ЗначениеЗаполнено(ИмяХар) Тогда
+ Хар = Справочники.ХарактеристикиНоменклатуры.НайтиПоНаименованию(ИмяХар, Истина, , Ном);
+ Если Не ЗначениеЗаполнено(Хар) Тогда
+ Хар = Справочники.ХарактеристикиНоменклатуры.НайтиПоНаименованию(ИмяХар, Истина, , ВидНом);
+ КонецЕсли;
+ КонецЕсли;
+
+ Если Не ЗначениеЗаполнено(Хар) Тогда
+ СсылкаПоГуид = СсылкаПоUUID(Справочники.ХарактеристикиНоменклатуры, СтрТ.ХарактеристикаИдентификатор);
+ Если ЗначениеЗаполнено(СсылкаПоГуид) И ОбщегоНазначения.СсылкаСуществует(СсылкаПоГуид) Тогда
+ ВладХар = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(СсылкаПоГуид, "Владелец");
+ Если ВладХар = Ном Или ВладХар = ВидНом Тогда
+ Хар = СсылкаПоГуид;
+ КонецЕсли;
+ КонецЕсли;
+ КонецЕсли;
+
+ Если Не ЗначениеЗаполнено(Хар) И ИспХар И ЗначениеЗаполнено(ИмяХар) И Не РежимТест Тогда
+ Попытка
+ НовХар = Справочники.ХарактеристикиНоменклатуры.СоздатьЭлемент();
+ НовХар.Владелец = ВидНом;
+ НовХар.Наименование = ИмяХар;
+ НовХар.Записать();
+ Хар = НовХар.Ссылка;
+ Результат.СозданоХарактеристик = Результат.СозданоХарактеристик + 1;
+ Исключение
+ СтрТ.КомментарийСопоставления = "Ошибка создания характеристики: " + ИмяХар;
+ КонецПопытки;
+ КонецЕсли;
+
+ Если Не ИспХар Тогда
+ Хар = Справочники.ХарактеристикиНоменклатуры.ПустаяСсылка();
+ КонецЕсли;
+
+ Возврат Хар;
+
+КонецФункции
+
+Функция НайтиИлиСоздатьСерию(СтрТ, Ном, СкладЦель, СуффиксДатыСер, РежимТест,
+ КэшТребуетсяСерия, КэшСерий, Результат)
+
+ Сер = Справочники.СерииНоменклатуры.ПустаяСсылка();
+ ВидНом = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ном, "ВидНоменклатуры");
+
+ КлючТребСер = Строка(Ном.УникальныйИдентификатор());
+ ТребуетсяСерия = КэшТребуетсяСерия.Получить(КлючТребСер);
+ Если ТребуетсяСерия = Неопределено Тогда
+ ТребуетсяСерия = Ложь;
+ Попытка
+ ТребуетсяСерия = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ном, "ВидНоменклатуры.ИспользоватьСерии") = Истина;
+ Исключение
+ Попытка
+ ТребуетсяСерия = ВидНом.ИспользоватьСерии;
+ Исключение
+ КонецПопытки;
+ КонецПопытки;
+ КэшТребуетсяСерия.Вставить(КлючТребСер, ТребуетсяСерия);
+ КонецЕсли;
+
+ ИмяСерии = СокрЛП(СтрТ.Серия);
+ Если Не ЗначениеЗаполнено(ИмяСерии) И ТребуетсяСерия Тогда
+ КодСклЗагл = "";
+ Попытка
+ КодСклЗагл = СокрЛП(Строка(ОбщегоНазначения.ЗначениеРеквизитаОбъекта(СкладЦель, "Код")));
+ Исключение
+ КодСклЗагл = "";
+ КонецПопытки;
+ Если ПустаяСтрока(КодСклЗагл) Тогда
+ КодСклЗагл = Лев(СтрЗаменить(Строка(СкладЦель.УникальныйИдентификатор()), "-", ""), 8);
+ КонецЕсли;
+ ИмяСерии = "Перенос_" + КодСклЗагл + "_" + СуффиксДатыСер;
+ СтрТ.Серия = ИмяСерии;
+ КонецЕсли;
+
+ Если Не ТребуетсяСерия И Не ЗначениеЗаполнено(ИмяСерии) Тогда
+ Возврат Сер;
+ КонецЕсли;
+
+ СсылкаПоГуид = СсылкаПоUUID(Справочники.СерииНоменклатуры, СтрТ.СерияИдентификатор);
+ Если ЗначениеЗаполнено(СсылкаПоГуид) И ОбщегоНазначения.СсылкаСуществует(СсылкаПоГуид) Тогда
+ Возврат СсылкаПоГуид;
+ КонецЕсли;
+
+ ВидСер = Неопределено;
+ ИспНомерСерии = Истина;
+ Попытка
+ НастрСер = Справочники.ВидыНоменклатуры.НастройкиИспользованияСерий(ВидНом, СкладЦель);
+ ВидСер = НастрСер.ВладелецСерий;
+ ИспНомерСерии = НастрСер.ИспользоватьНомерСерии;
+ Исключение
+ ВидСер = ВидНом;
+ КонецПопытки;
+ Если Не ЗначениеЗаполнено(ВидСер) Тогда
+ ВидСер = ВидНом;
+ КонецЕсли;
+
+ КлючКэшСер = Строка(ВидСер.УникальныйИдентификатор()) + "|" + ИмяСерии;
+ СерИзКэш = КэшСерий.Получить(КлючКэшСер);
+ Если СерИзКэш <> Неопределено Тогда
+ Возврат СерИзКэш;
+ КонецЕсли;
+
+ Если ИспНомерСерии Тогда
+ Сер = Справочники.СерииНоменклатуры.НайтиПоРеквизиту("Номер", ИмяСерии, , ВидСер);
+ КонецЕсли;
+ Если Не ЗначениеЗаполнено(Сер) Тогда
+ Сер = Справочники.СерииНоменклатуры.НайтиПоНаименованию(ИмяСерии, Истина, , ВидСер);
+ КонецЕсли;
+
+ Если Не ЗначениеЗаполнено(Сер) И Не РежимТест И (ТребуетсяСерия Или ЗначениеЗаполнено(ИмяСерии)) Тогда
+ Попытка
+ ОбСер = Справочники.СерииНоменклатуры.ПустойОбъект(ВидСер);
+ Если ИспНомерСерии Тогда
+ НомерСер = ИмяСерии;
+ Если СтрНачинаетсяС(ИмяСерии, "Перенос_") Тогда
+ НомерСер = Сред(ИмяСерии, СтрДлина("Перенос_") + 1);
+ КонецЕсли;
+ ОбСер.Номер = НомерСер;
+ Иначе
+ Попытка
+ ОбСер.Наименование = ИмяСерии;
+ Исключение
+ КонецПопытки;
+ КонецЕсли;
+ ОбСер.Записать();
+ Сер = ОбСер.Ссылка;
+ Результат.СозданоСерий = Результат.СозданоСерий + 1;
+ Исключение
+ СтрТ.КомментарийСопоставления = "Ошибка создания серии: " + ИмяСерии;
+ КонецПопытки;
+ КонецЕсли;
+
+ Если ЗначениеЗаполнено(Сер) Тогда
+ КэшСерий.Вставить(КлючКэшСер, Сер);
+ ИначеЕсли ТребуетсяСерия Тогда
+ Если ПустаяСтрока(СтрТ.КомментарийСопоставления) Или СтрТ.КомментарийСопоставления = "OK" Тогда
+ СтрТ.КомментарийСопоставления = "Серия не найдена" + ?(РежимТест, " (тест)", "");
+ КонецЕсли;
+ КонецЕсли;
+
+ Возврат Сер;
+
+КонецФункции
+
+Функция СсылкаПоUUID(Менеджер, Идентификатор)
+
+ Если Не ЗначениеЗаполнено(Идентификатор) Тогда
+ Возврат Менеджер.ПустаяСсылка();
+ КонецЕсли;
+ Попытка
+ Возврат Менеджер.ПолучитьСсылку(Идентификатор);
+ Исключение
+ Возврат Менеджер.ПустаяСсылка();
+ КонецПопытки;
+
+КонецФункции
+
+Функция UUIDИзСтроки(Значение)
+
+ Текст = НРег(СокрЛП(Строка(Значение)));
+ Если ПустаяСтрока(Текст) Или Текст = "00000000-0000-0000-0000-000000000000" Тогда
+ Возврат Новый УникальныйИдентификатор("00000000-0000-0000-0000-000000000000");
+ КонецЕсли;
+ Попытка
+ Возврат Новый УникальныйИдентификатор(Текст);
+ Исключение
+ Возврат Новый УникальныйИдентификатор("00000000-0000-0000-0000-000000000000");
+ КонецПопытки;
+
+КонецФункции
+
+Функция ЗначениеСвойства(Источник, Имя, ПоУмолчанию)
+
+ Если Источник = Неопределено Тогда
+ Возврат ПоУмолчанию;
+ КонецЕсли;
+ Если ТипЗнч(Источник) = Тип("Структура") Или ТипЗнч(Источник) = Тип("ФиксированнаяСтруктура") Тогда
+ Если Источник.Свойство(Имя) Тогда
+ Возврат Источник[Имя];
+ КонецЕсли;
+ Возврат ПоУмолчанию;
+ КонецЕсли;
+ Если ТипЗнч(Источник) = Тип("Соответствие") Или ТипЗнч(Источник) = Тип("ФиксированноеСоответствие") Тогда
+ Значение = Источник.Получить(Имя);
+ Если Значение = Неопределено Тогда
+ Возврат ПоУмолчанию;
+ КонецЕсли;
+ Возврат Значение;
+ КонецЕсли;
+ Возврат ПоУмолчанию;
+
+КонецФункции
+
+Функция ЧислоИзЗначения(Значение, ПоУмолчанию)
+
+ Если Значение = Неопределено Или Значение = Null Тогда
+ Возврат ПоУмолчанию;
+ КонецЕсли;
+ Попытка
+ Возврат Число(Значение);
+ Исключение
+ Возврат ПоУмолчанию;
+ КонецПопытки;
+
+КонецФункции
+
+#КонецОбласти
+
+#КонецЕсли
diff --git a/src/DataProcessors/РК_ЗагрузкаОстатков/Forms/ПодборСкладов/Ext/Form.xml b/src/DataProcessors/РК_ЗагрузкаОстатков/Forms/ПодборСкладов/Ext/Form.xml
index aae365c..8a35d5b 100644
--- a/src/DataProcessors/РК_ЗагрузкаОстатков/Forms/ПодборСкладов/Ext/Form.xml
+++ b/src/DataProcessors/РК_ЗагрузкаОстатков/Forms/ПодборСкладов/Ext/Form.xml
@@ -1,6 +1,18 @@
\ No newline at end of file
diff --git a/src/DataProcessors/РК_ЗагрузкаОстатков/Forms/ПодборСкладов/Ext/Form/Module.bsl b/src/DataProcessors/РК_ЗагрузкаОстатков/Forms/ПодборСкладов/Ext/Form/Module.bsl
new file mode 100644
index 0000000..33ed57c
--- /dev/null
+++ b/src/DataProcessors/РК_ЗагрузкаОстатков/Forms/ПодборСкладов/Ext/Form/Module.bsl
@@ -0,0 +1,78 @@
+
+&НаСервере
+Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
+
+ Добавление = Истина;
+ Подключение = Неопределено;
+ Если Параметры.Свойство("ПодключениеКСтороннейБазе", Подключение) Тогда
+ Объект.ПодключениеКСтороннейБазе = Подключение;
+ КонецЕсли;
+ ЗаполнитьСписокСкладовНаСервере();
+
+КонецПроцедуры
+
+&НаКлиенте
+Процедура ПеренестиВОтбор(Команда)
+
+ Выбранные = Новый Массив;
+ Для Каждого Стр Из СписокСкладовВнешнейБазы Цикл
+ Если Стр.Отметка Тогда
+ Выбранные.Добавить(Новый Структура("Наименование, Идентификатор, Отметка",
+ Стр.Наименование, Стр.Идентификатор, Истина));
+ КонецЕсли;
+ КонецЦикла;
+ Закрыть(Новый Структура("Добавление, Склады", Добавление, Выбранные));
+
+КонецПроцедуры
+
+&НаСервере
+Процедура ЗаполнитьСписокСкладовНаСервере()
+
+ Если Не ЗначениеЗаполнено(Объект.ПодключениеКСтороннейБазе) Тогда
+ Возврат;
+ КонецЕсли;
+
+ Ответ = РК_ОбменСВнешнейБазой.СписокСкладовВнешнейБазы(Объект.ПодключениеКСтороннейБазе);
+ Строки = Неопределено;
+ Если ТипЗнч(Ответ) = Тип("Структура") Или ТипЗнч(Ответ) = Тип("Соответствие") Тогда
+ Если ТипЗнч(Ответ) = Тип("Структура") Тогда
+ Если Ответ.Свойство("rows") Тогда
+ Строки = Ответ.rows;
+ КонецЕсли;
+ Иначе
+ Строки = Ответ.Получить("rows");
+ КонецЕсли;
+ КонецЕсли;
+ Если ТипЗнч(Строки) <> Тип("Массив") Тогда
+ Возврат;
+ КонецЕсли;
+
+ СписокСкладовВнешнейБазы.Очистить();
+ Для Каждого СтрокаAPI Из Строки Цикл
+ ГуидТекст = "";
+ Имя = "";
+ Если ТипЗнч(СтрокаAPI) = Тип("Структура") Тогда
+ Если СтрокаAPI.Свойство("guid") Тогда
+ ГуидТекст = СокрЛП(Строка(СтрокаAPI.guid));
+ КонецЕсли;
+ Если СтрокаAPI.Свойство("name") Тогда
+ Имя = СокрЛП(Строка(СтрокаAPI.name));
+ КонецЕсли;
+ ИначеЕсли ТипЗнч(СтрокаAPI) = Тип("Соответствие") Тогда
+ ГуидТекст = СокрЛП(Строка(СтрокаAPI.Получить("guid")));
+ Имя = СокрЛП(Строка(СтрокаAPI.Получить("name")));
+ КонецЕсли;
+ Если ПустаяСтрока(ГуидТекст) Тогда
+ Продолжить;
+ КонецЕсли;
+ НовСтр = СписокСкладовВнешнейБазы.Добавить();
+ НовСтр.Наименование = Имя;
+ Попытка
+ НовСтр.Идентификатор = Новый УникальныйИдентификатор(ГуидТекст);
+ Исключение
+ Продолжить;
+ КонецПопытки;
+ НовСтр.Отметка = Ложь;
+ КонецЦикла;
+
+КонецПроцедуры
diff --git a/src/DataProcessors/РК_ЗагрузкаОстатков/Forms/Форма/Ext/Form.xml b/src/DataProcessors/РК_ЗагрузкаОстатков/Forms/Форма/Ext/Form.xml
index d8bf30f..d014aef 100644
--- a/src/DataProcessors/РК_ЗагрузкаОстатков/Forms/Форма/Ext/Form.xml
+++ b/src/DataProcessors/РК_ЗагрузкаОстатков/Forms/Форма/Ext/Form.xml
@@ -6,7 +6,24 @@
Загрузка остатков из внешней базы
-
+
+
+
+
+
+
+
+ ПриСозданииНаСервере
+
Объект.ПодключениеКСтороннейБазе
@@ -45,7 +62,7 @@
ru
- Водящие данные
+ Входящие данные
@@ -143,6 +160,74 @@
+
+
+ Объект.ВходящиеДанные.Количество
+ EnterOnInput
+
+
+
+
+ Объект.ВходящиеДанные.Артикул
+ EnterOnInput
+
+
+
+
+ Объект.ВходящиеДанные.НоменклатураКод
+ EnterOnInput
+
+
+
+
+ Объект.ВходящиеДанные.ХарактеристикаНаименование
+ EnterOnInput
+
+
+
+
+ Объект.ВходящиеДанные.ВидНоменклатурыНаименование
+ EnterOnInput
+
+
+
+
+ Объект.ВходящиеДанные.ОрганизацияНаименование
+ EnterOnInput
+
+
+
+
+ Объект.ВходящиеДанные.Номенклатура
+ EnterOnInput
+
+
+
+
+ Объект.ВходящиеДанные.Склад
+ EnterOnInput
+
+
+
+
+ Объект.ВходящиеДанные.СерияСсылка
+ EnterOnInput
+
+
+
+
+ Объект.ВходящиеДанные.Сопоставлено
+ EnterOnInput
+ Auto
+
+
+
+
+ Объект.ВходящиеДанные.КомментарийСопоставления
+ EnterOnInput
+
+
+
@@ -325,5 +410,35 @@
ПодобратьСклады
+
+
+
+ ru
+ Загрузить остатки
+
+
+
+
+ ru
+ Загрузить остатки из исходной базы
+
+
+ ЗагрузитьОстатки
+
+
+
+
+ ru
+ Сопоставить
+
+
+
+
+ ru
+ Сопоставить НСИ и серии
+
+
+ Сопоставить
+
\ No newline at end of file
diff --git a/src/DataProcessors/РК_ЗагрузкаОстатков/Forms/Форма/Ext/Form/Module.bsl b/src/DataProcessors/РК_ЗагрузкаОстатков/Forms/Форма/Ext/Form/Module.bsl
index 37bd1ef..a59c694 100644
--- a/src/DataProcessors/РК_ЗагрузкаОстатков/Forms/Форма/Ext/Form/Module.bsl
+++ b/src/DataProcessors/РК_ЗагрузкаОстатков/Forms/Форма/Ext/Form/Module.bsl
@@ -1,10 +1,232 @@
+#Область ОбработчикиСобытийФормы
+
&НаСервере
-Процедура ПодобратьСкладыНаСервере()
- // Вставить содержимое обработчика.
+Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
+
+ Если Не ЗначениеЗаполнено(Объект.ПодключениеКСтороннейБазе) Тогда
+ Попытка
+ Объект.ПодключениеКСтороннейБазе = Константы.РК_РабочееПодключениеЧерезАПИ.Получить();
+ Исключение
+ КонецПопытки;
+ КонецЕсли;
+
+ Если Не ЗначениеЗаполнено(Объект.ДатаОстатков) Тогда
+ Объект.ДатаОстатков = КонецДня(НачалоМесяца(ТекущаяДатаСеанса()) - 1);
+ КонецЕсли;
+ Если Не ЗначениеЗаполнено(Объект.ДатаДокументовВвода) Тогда
+ Объект.ДатаДокументовВвода = Объект.ДатаОстатков;
+ КонецЕсли;
+
КонецПроцедуры
+#КонецОбласти
+
+#Область ОбработчикиКомандФормы
+
&НаКлиенте
Процедура ПодобратьСклады(Команда)
+
+ Если Не ЗначениеЗаполнено(Объект.ПодключениеКСтороннейБазе) Тогда
+ ПоказатьПредупреждение(, "Укажите подключение к сторонней базе");
+ Возврат;
+ КонецЕсли;
+
ПодобратьСкладыНаСервере();
+ Элементы.ГруппаСтраницы.ТекущаяСтраница = Элементы.ГруппаОтбор;
+
КонецПроцедуры
+
+&НаКлиенте
+Процедура ЗагрузитьОстатки(Команда)
+
+ Если Не ЗначениеЗаполнено(Объект.ПодключениеКСтороннейБазе) Тогда
+ ПоказатьПредупреждение(, "Укажите подключение к сторонней базе");
+ Возврат;
+ КонецЕсли;
+ Если Не ЗначениеЗаполнено(Объект.ДатаОстатков) Тогда
+ ПоказатьПредупреждение(, "Укажите дату остатков");
+ Возврат;
+ КонецЕсли;
+
+ Количество = ЗагрузитьОстаткиНаСервере();
+ Элементы.ГруппаСтраницы.ТекущаяСтраница = Элементы.ГруппаВходящиеДанные;
+ ПоказатьОповещениеПользователя("Загрузка остатков", , "Загружено строк: " + Формат(Количество, "ЧГ=0"));
+
+КонецПроцедуры
+
+&НаКлиенте
+Процедура Сопоставить(Команда)
+
+ Если Объект.ВходящиеДанные.Количество() = 0 Тогда
+ ПоказатьПредупреждение(, "Сначала загрузите остатки");
+ Возврат;
+ КонецЕсли;
+
+ ДопПараметры = Новый Структура("РежимТест", Истина);
+ Описание = Новый ОписаниеОповещения("СопоставитьПослеВопроса", ЭтотОбъект, ДопПараметры);
+ ПоказатьВопрос(Описание,
+ "Создавать отсутствующие серии и характеристики?" + Символы.ПС
+ + "Да — запись; Нет — только поиск (тест); Отмена — прервать.",
+ РежимДиалогаВопрос.ДаНетОтмена);
+
+КонецПроцедуры
+
+&НаКлиенте
+Процедура СопоставитьПослеВопроса(РезультатВопроса, ДопПараметры) Экспорт
+
+ Если РезультатВопроса = КодВозвратаДиалога.Отмена Тогда
+ Возврат;
+ КонецЕсли;
+ РежимТест = (РезультатВопроса <> КодВозвратаДиалога.Да);
+ Текст = СопоставитьНаСервере(РежимТест);
+ ПоказатьОповещениеПользователя("Сопоставление", , Текст);
+
+КонецПроцедуры
+
+#КонецОбласти
+
+#Область СлужебныеПроцедурыИФункции
+
+&НаСервере
+Процедура ПодобратьСкладыНаСервере()
+
+ Ответ = РК_ОбменСВнешнейБазой.СписокСкладовВнешнейБазы(Объект.ПодключениеКСтороннейБазе);
+ Строки = Неопределено;
+ Если ТипЗнч(Ответ) = Тип("Структура") Или ТипЗнч(Ответ) = Тип("Соответствие") Тогда
+ Строки = ЗначениеСвойстваОтвета(Ответ, "rows");
+ КонецЕсли;
+ Если ТипЗнч(Строки) <> Тип("Массив") Тогда
+ ВызватьИсключение "Некорректный ответ /v1/stock/warehouses";
+ КонецЕсли;
+
+ БылиОтметки = Новый Соответствие;
+ Для Каждого Стр Из ОтборСкладовВнешнейБазы Цикл
+ БылиОтметки.Вставить(Строка(Стр.Идентификатор), Стр.Отметка);
+ КонецЦикла;
+
+ ОтборСкладовВнешнейБазы.Очистить();
+ Для Каждого СтрокаAPI Из Строки Цикл
+ ГуидТекст = СокрЛП(Строка(ЗначениеСвойстваОтвета(СтрокаAPI, "guid")));
+ Если ПустаяСтрока(ГуидТекст) Тогда
+ Продолжить;
+ КонецЕсли;
+ НовСтр = ОтборСкладовВнешнейБазы.Добавить();
+ НовСтр.Наименование = СокрЛП(Строка(ЗначениеСвойстваОтвета(СтрокаAPI, "name")));
+ Попытка
+ НовСтр.Идентификатор = Новый УникальныйИдентификатор(ГуидТекст);
+ Исключение
+ Продолжить;
+ КонецПопытки;
+ СтараяОтметка = БылиОтметки.Получить(Строка(НовСтр.Идентификатор));
+ НовСтр.Отметка = ?(СтараяОтметка = Неопределено, Ложь, СтараяОтметка = Истина);
+ КонецЦикла;
+
+КонецПроцедуры
+
+&НаСервере
+Функция ЗагрузитьОстаткиНаСервере()
+
+ СкладыGUID = Новый Массив;
+ Для Каждого Стр Из ОтборСкладовВнешнейБазы Цикл
+ Если Стр.Отметка Тогда
+ СкладыGUID.Добавить(Строка(Стр.Идентификатор));
+ КонецЕсли;
+ КонецЦикла;
+ Если СкладыGUID.Количество() = 0 Тогда
+ ВызватьИсключение "Отметьте хотя бы один склад на закладке «Отбор»";
+ КонецЕсли;
+
+ Фильтры = Новый Структура;
+ Фильтры.Вставить("warehouses", СкладыGUID);
+ Фильтры.Вставить("only_nonzero", Истина);
+
+ ВсеСтроки = Новый Массив;
+ Курсор = "";
+ Лимит = 2000;
+ МаксСтраниц = 200;
+
+ Для НомерСтраницы = 1 По МаксСтраниц Цикл
+
+ ПараметрыЗапроса = Новый Структура;
+ ПараметрыЗапроса.Вставить("mode", "combined");
+ ПараметрыЗапроса.Вставить("as_of", Формат(Объект.ДатаОстатков, "ДФ=yyyy-MM-ddTHH:mm:ss"));
+ ПараметрыЗапроса.Вставить("limit", Лимит);
+ ПараметрыЗапроса.Вставить("include_policy", Истина);
+ ПараметрыЗапроса.Вставить("filters", Фильтры);
+ Если Не ПустаяСтрока(Курсор) Тогда
+ ПараметрыЗапроса.Вставить("cursor", Курсор);
+ КонецЕсли;
+
+ Ответ = РК_ОбменСВнешнейБазой.ОстаткиВнешнейБазы(Объект.ПодключениеКСтороннейБазе, ПараметрыЗапроса);
+ Строки = ЗначениеСвойстваОтвета(Ответ, "rows");
+ Если ТипЗнч(Строки) <> Тип("Массив") Тогда
+ ВызватьИсключение "Некорректный ответ /v1/stock/balances";
+ КонецЕсли;
+ Для Каждого СтрAPI Из Строки Цикл
+ ВсеСтроки.Добавить(СтрAPI);
+ КонецЦикла;
+
+ Мета = ЗначениеСвойстваОтвета(Ответ, "meta");
+ ЕстьЕще = Ложь;
+ Если ТипЗнч(Мета) = Тип("Структура") Или ТипЗнч(Мета) = Тип("Соответствие") Тогда
+ ЗначениеЕстьЕще = ЗначениеСвойстваОтвета(Мета, "has_more");
+ Если ТипЗнч(ЗначениеЕстьЕще) = Тип("Булево") Тогда
+ ЕстьЕще = ЗначениеЕстьЕще;
+ ИначеЕсли ЗначениеЕстьЕще <> Неопределено Тогда
+ ЕстьЕще = (НРег(СокрЛП(Строка(ЗначениеЕстьЕще))) = "true" Или Строка(ЗначениеЕстьЕще) = "1");
+ КонецЕсли;
+ КонецЕсли;
+ Курсор = СокрЛП(Строка(ЗначениеСвойстваОтвета(Ответ, "cursor")));
+ Если Не ЕстьЕще Или ПустаяСтрока(Курсор) Или Строки.Количество() = 0 Тогда
+ Прервать;
+ КонецЕсли;
+
+ КонецЦикла;
+
+ Пакет = Новый Структура("rows", ВсеСтроки);
+ ОбъектОбработки = РеквизитФормыВЗначение("Объект");
+ ОбъектОбработки.ЗаполнитьВходящиеДанныеИзОтветаОстатков(Пакет, Истина);
+ ЗначениеВРеквизитФормы(ОбъектОбработки, "Объект");
+
+ Возврат Объект.ВходящиеДанные.Количество();
+
+КонецФункции
+
+&НаСервере
+Функция СопоставитьНаСервере(РежимТест)
+
+ ОбъектОбработки = РеквизитФормыВЗначение("Объект");
+ Результат = ОбъектОбработки.СопоставитьВходящиеДанные(РежимТест);
+ ЗначениеВРеквизитФормы(ОбъектОбработки, "Объект");
+
+ Возврат СтрШаблон(
+ "Сопоставлено: %1; не сопоставлено: %2; создано серий: %3; создано характеристик: %4%5",
+ Формат(Результат.Сопоставлено, "ЧН=0; ЧГ=0"),
+ Формат(Результат.НеСопоставлено, "ЧН=0; ЧГ=0"),
+ Формат(Результат.СозданоСерий, "ЧН=0; ЧГ=0"),
+ Формат(Результат.СозданоХарактеристик, "ЧН=0; ЧГ=0"),
+ ?(РежимТест, " (тест)", ""));
+
+КонецФункции
+
+&НаСервере
+Функция ЗначениеСвойстваОтвета(Источник, Имя)
+
+ Если Источник = Неопределено Тогда
+ Возврат Неопределено;
+ КонецЕсли;
+ Если ТипЗнч(Источник) = Тип("Структура") Или ТипЗнч(Источник) = Тип("ФиксированнаяСтруктура") Тогда
+ Если Источник.Свойство(Имя) Тогда
+ Возврат Источник[Имя];
+ КонецЕсли;
+ Возврат Неопределено;
+ КонецЕсли;
+ Если ТипЗнч(Источник) = Тип("Соответствие") Или ТипЗнч(Источник) = Тип("ФиксированноеСоответствие") Тогда
+ Возврат Источник.Получить(Имя);
+ КонецЕсли;
+ Возврат Неопределено;
+
+КонецФункции
+
+#КонецОбласти
diff --git a/src/Subsystems/РК_РАНА/Subsystems/РК_ОбменСВнешнейБазой.xml b/src/Subsystems/РК_РАНА/Subsystems/РК_ОбменСВнешнейБазой.xml
index 8f5f021..0d61060 100644
--- a/src/Subsystems/РК_РАНА/Subsystems/РК_ОбменСВнешнейБазой.xml
+++ b/src/Subsystems/РК_РАНА/Subsystems/РК_ОбменСВнешнейБазой.xml
@@ -18,6 +18,7 @@
Catalog.РК_НастройкиПодключенияКВнешнейБазе
Constant.РК_РабочееПодключениеЧерезАПИ
+ CommonModule.РК_ОбменСВнешнейБазой
DataProcessor.РК_ЗагрузкаОстатков
DataProcessor.РК_ОбработкаПарнеровКонтрагентов