// WMS-Bridge — шаблон модуля объекта внешней обработки 1С:Предприятие 8.3 // Вставьте этот текст в модуль объекта новой внешней обработки и сохраните как .epf. // Либо перенесите процедуры в серверный общий модуль расширения .cfe. // // Идентификатор пространства ниже — пример. Замените его на слаг своего склада. // Каталог этого склада хранится отдельно и не смешивается с другими пространствами. Перем АдресСервера; Перем ПортСервера; Перем ИдентификаторСклада; Процедура ИнициализироватьПодключение() АдресСервера = "127.0.0.1"; ПортСервера = 8501; ИдентификаторСклада = "vash_sklad"; КонецПроцедуры // Заполняет номенклатуру документа «Поступление товаров и услуг». // Количество, цена и сумма строк не меняются. // // РежимПроверки = Истина — POST /api/preview-normalize (демо-каталог, до 10 строк). // РежимПроверки = Ложь — файл накладной .xls/.xlsx на POST /api/orders/upload. Функция ЗаполнитьПоступление(ДокументОбъект, РежимПроверки = Истина, ПутьКФайлуНакладной = "") Экспорт ИнициализироватьПодключение(); Если ДокументОбъект = Неопределено Тогда ВызватьИсключение "Передайте объект документа «Поступление товаров и услуг»."; КонецЕсли; Если РежимПроверки Тогда Ответ = ОтправитьСтрокиНаПроверку(ДокументОбъект.Товары); ПрименитьОтветПроверки(ДокументОбъект, Ответ); Иначе Если ПустаяСтрока(ПутьКФайлуНакладной) Тогда ВызватьИсключение "Для рабочего контура укажите путь к исходной накладной .xls или .xlsx."; КонецЕсли; ОтправитьФайлНакладной(ПутьКФайлуНакладной); СтрокиОтвета = ПрочитатьСтрокиЗаказа(); ПрименитьСтрокиЗаказа(ДокументОбъект, СтрокиОтвета); КонецЕсли; Возврат Истина; КонецФункции Функция ОтправитьСтрокиНаПроверку(Товары) Строки = Новый Массив; Для Каждого СтрокаТовара Из Товары Цикл Если Строки.Количество() >= 10 Тогда Прервать; КонецЕсли; Наименование = СокрЛП(Строка(СтрокаТовара.Номенклатура)); Если ПустаяСтрока(Наименование) И ЗначениеЗаполнено(СтрокаТовара.НоменклатураПоставщика) Тогда Наименование = СокрЛП(Строка(СтрокаТовара.НоменклатураПоставщика)); КонецЕсли; Если Не ПустаяСтрока(Наименование) Тогда Строки.Добавить(Наименование); КонецЕсли; КонецЦикла; Запись = Новый ЗаписьJSON; Запись.УстановитьСтроку(); Запись.ЗаписатьНачалоОбъекта(); Запись.ЗаписатьИмяСвойства("lines"); ЗаписатьJSON(Запись, Строки); Запись.ЗаписатьИмяСвойства("domain"); Запись.ЗаписатьЗначение("general"); Запись.ЗаписатьКонецОбъекта(); Тело = Запись.Закрыть(); Запрос = Новый HTTPЗапрос("/api/preview-normalize"); Запрос.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8"); Запрос.Заголовки.Вставить("X-Tenant-ID", ИдентификаторСклада); Запрос.УстановитьТелоИзСтроки(Тело, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать); Соединение = Новый HTTPСоединение(АдресСервера, ПортСервера, , , , 30); Ответ = Соединение.ВызватьHTTPМетод("POST", Запрос); Если Ответ.КодСостояния <> 200 Тогда ВызватьИсключение "WMS-Bridge вернул код " + Формат(Ответ.КодСостояния, "ЧГ=0") + ": " + Ответ.ПолучитьТелоКакСтроку(); КонецЕсли; Чтение = Новый ЧтениеJSON; Чтение.УстановитьСтроку(Ответ.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8)); Возврат ПрочитатьJSON(Чтение); КонецФункции Процедура ПрименитьОтветПроверки(ДокументОбъект, Ответ) ЭлементыОтвета = Неопределено; Если ТипЗнч(Ответ) = Тип("Соответствие") Тогда ЭлементыОтвета = Ответ.Получить("items"); ИначеЕсли ТипЗнч(Ответ) = Тип("Структура") Тогда ЭлементыОтвета = Ответ.items; КонецЕсли; Если ЭлементыОтвета = Неопределено Тогда Возврат; КонецЕсли; Индекс = 0; Для Каждого СтрокаТовара Из ДокументОбъект.Товары Цикл Если Индекс >= ЭлементыОтвета.Количество() Тогда Прервать; КонецЕсли; Элемент = ЭлементыОтвета[Индекс]; Индекс = Индекс + 1; Если ЭтоКарантин(Элемент) Тогда Продолжить; КонецЕсли; Номенклатура = НайтиНоменклатуру(ЗначениеПоля(Элемент, "barcode"), ЗначениеПоля(Элемент, "article")); Если ЗначениеЗаполнено(Номенклатура) Тогда СтрокаТовара.Номенклатура = Номенклатура; КонецЕсли; КонецЦикла; КонецПроцедуры Процедура ОтправитьФайлНакладной(ПутьКФайлу) Файл = Новый Файл(ПутьКФайлу); Если Не Файл.Существует() Тогда ВызватьИсключение "Файл накладной не найден: " + ПутьКФайлу; КонецЕсли; Расширение = НРег(Файл.Расширение); Если Расширение <> ".xls" И Расширение <> ".xlsx" Тогда ВызватьИсключение "Рабочий контур принимает только .xls и .xlsx."; КонецЕсли; Граница = "WmsBridge" + СтрЗаменить(Строка(Новый УникальныйИдентификатор), "-", ""); Двоичные = Новый ДвоичныеДанные(ПутьКФайлу); Тело = СобратьMultipart(Файл.Имя, Двоичные, Граница); Заголовки = Новый Соответствие; Заголовки.Вставить("Content-Type", "multipart/form-data; boundary=" + Граница); Заголовки.Вставить("X-Tenant-ID", ИдентификаторСклада); Запрос = Новый HTTPЗапрос("/api/orders/upload", Заголовки); Запрос.УстановитьТелоИзДвоичныхДанных(Тело); Соединение = Новый HTTPСоединение(АдресСервера, ПортСервера, , , , 120); Ответ = Соединение.ВызватьHTTPМетод("POST", Запрос); Если Ответ.КодСостояния <> 200 Тогда ВызватьИсключение "Не удалось обработать накладную, код " + Формат(Ответ.КодСостояния, "ЧГ=0") + ": " + Ответ.ПолучитьТелоКакСтроку(); КонецЕсли; КонецПроцедуры Функция ПрочитатьСтрокиЗаказа() Запрос = Новый HTTPЗапрос("/api/orders/items"); Запрос.Заголовки.Вставить("X-Tenant-ID", ИдентификаторСклада); Соединение = Новый HTTPСоединение(АдресСервера, ПортСервера, , , , 30); Ответ = Соединение.ВызватьHTTPМетод("GET", Запрос); Если Ответ.КодСостояния <> 200 Тогда ВызватьИсключение "Не удалось прочитать результат сверки, код " + Формат(Ответ.КодСостояния, "ЧГ=0"); КонецЕсли; Чтение = Новый ЧтениеJSON; Чтение.УстановитьСтроку(Ответ.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8)); Возврат ПрочитатьJSON(Чтение); КонецФункции Процедура ПрименитьСтрокиЗаказа(ДокументОбъект, СтрокиОтвета) Если ТипЗнч(СтрокиОтвета) <> Тип("Массив") Тогда Возврат; КонецЕсли; Индекс = 0; Для Каждого СтрокаТовара Из ДокументОбъект.Товары Цикл Если Индекс >= СтрокиОтвета.Количество() Тогда Прервать; КонецЕсли; Элемент = СтрокиОтвета[Индекс]; Индекс = Индекс + 1; Номенклатура = НайтиНоменклатуру( ЗначениеПоля(Элемент, "barcode"), ЗначениеПоля(Элемент, "nomenclature_code") ); Если ЗначениеЗаполнено(Номенклатура) Тогда СтрокаТовара.Номенклатура = Номенклатура; КонецЕсли; КонецЦикла; КонецПроцедуры Функция НайтиНоменклатуру(Штрихкод, Артикул) Если ЗначениеЗаполнено(Артикул) Тогда Найдено = Справочники.Номенклатура.НайтиПоРеквизиту("Артикул", Артикул); Если ЗначениеЗаполнено(Найдено) Тогда Возврат Найдено; КонецЕсли; КонецЕсли; // УТ / ERP / КА: штрихкод обычно в регистре сведений «ШтрихкодыНоменклатуры». // Раскомментируйте и поправьте имена под свою конфигурацию. // // Запрос = Новый Запрос; // Запрос.Текст = // "ВЫБРАТЬ ПЕРВЫЕ 1 // | Штрихкоды.Номенклатура КАК Номенклатура // |ИЗ // | РегистрСведений.ШтрихкодыНоменклатуры КАК Штрихкоды // |ГДЕ // | Штрихкоды.Штрихкод = &Штрихкод"; // Запрос.УстановитьПараметр("Штрихкод", Штрихкод); // Выборка = Запрос.Выполнить().Выбрать(); // Если Выборка.Следующий() Тогда // Возврат Выборка.Номенклатура; // КонецЕсли; Возврат Справочники.Номенклатура.ПустаяСсылка(); КонецФункции Функция ЭтоКарантин(Элемент) Признак = Неопределено; Если ТипЗнч(Элемент) = Тип("Соответствие") Тогда Признак = Элемент.Получить("quarantined"); ИначеЕсли ТипЗнч(Элемент) = Тип("Структура") Тогда Элемент.Свойство("quarantined", Признак); КонецЕсли; Возврат Признак = Истина; КонецФункции Функция ЗначениеПоля(Элемент, Имя) Если ТипЗнч(Элемент) = Тип("Соответствие") Тогда Значение = Элемент.Получить(Имя); ИначеЕсли ТипЗнч(Элемент) = Тип("Структура") Тогда Значение = Неопределено; Элемент.Свойство(Имя, Значение); Иначе Значение = Неопределено; КонецЕсли; Если Значение = Неопределено Тогда Возврат ""; КонецЕсли; Возврат СокрЛП(Строка(Значение)); КонецФункции Функция СобратьMultipart(ИмяФайла, ДвоичныеДанныеФайла, Граница) Поток = Новый ПотокВПамяти; Запись = Новый ЗаписьДанных(Поток); Заголовок = "--" + Граница + Символы.ВК + Символы.ПС + "Content-Disposition: form-data; name=""file""; filename=""" + ИмяФайла + """" + Символы.ВК + Символы.ПС + "Content-Type: application/octet-stream" + Символы.ВК + Символы.ПС + Символы.ВК + Символы.ПС; Запись.ЗаписатьСтроку(Заголовок); Запись.Закрыть(); Начало = Поток.ЗакрытьИПолучитьДвоичныеДанные(); ПотокКонца = Новый ПотокВПамяти; ЗаписьКонца = Новый ЗаписьДанных(ПотокКонца); ЗаписьКонца.ЗаписатьСтроку(Символы.ВК + Символы.ПС + "--" + Граница + "--" + Символы.ВК + Символы.ПС); ЗаписьКонца.Закрыть(); КонецТела = ПотокКонца.ЗакрытьИПолучитьДвоичныеДанные(); МассивЧастей = Новый Массив; МассивЧастей.Добавить(Начало); МассивЧастей.Добавить(ДвоичныеДанныеФайла); МассивЧастей.Добавить(КонецТела); Возврат СоединитьДвоичныеДанные(МассивЧастей); КонецФункции