TSDZakazScladVasilek/CommonModules/СинхронизацияУТ/Ext/Module.bsl

1913 lines
98 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
//
// Параметры:
// Номер - Строка - номер документа или штрихкод.
// ТипДокумента - Строка - "ЗаказКлиента" | "ПоступлениеТоваровУслуг".
// Тип обязателен: номера заказа и поступления могут совпадать.
//
Функция GetDoc(Номер, ТипДокумента = "ЗаказКлиента") Экспорт
СтрокаURI = "https://vasvas.itinalog.ru/utip_curent/ws/tsdsync";
Пользователь = "admin1c";
Пароль = "A400943@!";
HTTPСоединение = Новый HTTPСоединение("vasvas.itinalog.ru",443,Пользователь,Пароль,,,Новый ЗащищенноеСоединениеOpenSSL());
Заголовки = Новый Соответствие();
Заголовки.Вставить("Content-Type","application/xml_request");
Штрихкод = НормализоватьШтрихкодДокумента(Номер);
ТипДокументаНорм = НормализоватьТипДокументаЗагрузки(ТипДокумента);
ИмяМакетаGetDoc = ?(ТипДокументаНорм = "ПоступлениеТоваровУслуг",
аблонGetDocПоступление", "ШаблонGetDoc");
ТелоЗапроса = ТекстОбщегоМакета(ИмяМакетаGetDoc);
ТелоЗапроса = СтрЗаменить(ТелоЗапроса, "$Штрихкод", Штрихкод);
ТелоЗапроса = СтрЗаменить(ТелоЗапроса, "$ТипДокумента", ТипДокументаНорм);
HTTPЗапрос = Новый HTTPЗапрос("/utip_curent/ws/tsdsync", Заголовки);
HTTPЗапрос.УстановитьТелоИзСтроки(ТелоЗапроса);
РезультатЗапроса = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
ТекстОтвета = РезультатЗапроса.ПолучитьТелоКакСтроку();
Возврат НормализоватьXMLОтветСервиса(ТекстОтвета);
КонецФункции
Функция SetDoc(Док) Экспорт
Пользователь = "admin1c";
Пароль = "A400943@!";
HTTPСоединение = Новый HTTPСоединение("vasvas.itinalog.ru", 443, Пользователь, Пароль,,,
Новый ЗащищенноеСоединениеOpenSSL());
Заголовки = Новый Соответствие;
Заголовки.Вставить("Content-Type", "application/xml_request");
ТелоЗапроса = ТекстОбщегоМакета("ШаблонSetDoc");
ТелоЗапроса = СтрЗаменить(ТелоЗапроса, "$ДокСсылка", Строка(Док.Ссылка.УникальныйИдентификатор()));
ТелоЗапроса = СтрЗаменить(ТелоЗапроса, "$Дата", Формат(Док.Дата, "ДФ=""гггг-ММ-дд'T'ЧЧ:мм:сс"""));
ТелоЗапроса = СтрЗаменить(ТелоЗапроса, "$Номер", XMLЗначениеДляШаблона(Док.Номер));
Если ЗначениеЗаполнено(Док.Партнер) Тогда
ТелоЗапроса = СтрЗаменить(ТелоЗапроса, "$КонтрагентСсылка",
Строка(Док.Партнер.УникальныйИдентификатор()));
Иначе
ТелоЗапроса = СтрЗаменить(ТелоЗапроса, "$КонтрагентСсылка", "");
КонецЕсли;
// Партии/серии — как в поступлении; марки из партий + оставшиеся КодыМаркировки.
ТелоЗапроса = СтрЗаменить(ТелоЗапроса, "$Серии", СформироватьПартииSetDocПоступление(Док));
ТелоЗапроса = СтрЗаменить(ТелоЗапроса, "$Марки", СформироватьМаркиSetDocЗаказ(Док));
ТелоЗапроса = ОчиститьПлейсхолдерыШаблона(ТелоЗапроса);
HTTPЗапрос = Новый HTTPЗапрос("/utip_curent/ws/tsdsync", Заголовки);
HTTPЗапрос.УстановитьТелоИзСтроки(ТелоЗапроса);
РезультатЗапроса = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
Возврат РезультатЗапроса.ПолучитьТелоКакСтроку();
КонецФункции
// Марки заказа: ШК из ТЧ Партии + КодыМаркировки без дублей по коду.
//
Функция СформироватьМаркиSetDocЗаказ(Док)
СтрокиЗапроса = СформироватьМаркиИзПартийSetDocПоступление(Док);
ШаблонСтроки = ТекстОбщегоМакета("ШаблонSetDocМарка");
КодыИзПартий = Новый Соответствие;
Попытка
Для Каждого СтрокаПартии Из Док.Партии Цикл
Если ЗначениеЗаполнено(СтрокаПартии.ШК) Тогда
КодыИзПартий.Вставить(СокрЛП(СтрокаПартии.ШК), Истина);
КодыИзПартий.Вставить(НормализоватьКодМаркировки(СтрокаПартии.ПредставлениеШК), Истина);
КодыИзПартий.Вставить(НормализоватьКодМаркировки(ИсходныйКодМаркировкиИзШК(СтрокаПартии.ШК)), Истина);
КонецЕсли;
КонецЦикла;
Исключение
// ТЧ Партии может отсутствовать в старых данных
КонецПопытки;
Для Каждого СтрокаКМ Из Док.КодыМаркировки Цикл
Код = СокрЛП(Строка(СтрокаКМ.Код));
Если Не ЗначениеЗаполнено(Код) Тогда
Продолжить;
КонецЕсли;
Если КодыИзПартий.Получить(Код) <> Неопределено
Или КодыИзПартий.Получить(НормализоватьКодМаркировки(Код)) <> Неопределено
Или КодыИзПартий.Получить(КодМаркировкиДляSOAP(Код)) <> Неопределено Тогда
Продолжить;
КонецЕсли;
ТелоСтроки = ШаблонСтроки;
ТелоСтроки = СтрЗаменить(ТелоСтроки, "$Строка", XMLЗначениеДляШаблона(СтрокаКМ.Строка));
ТелоСтроки = СтрЗаменить(ТелоСтроки, "$Код", КодироватьСтрокуВBase64(Код));
Если ЗначениеЗаполнено(СтрокаКМ.Номенклатура) Тогда
ТелоСтроки = СтрЗаменить(ТелоСтроки, "$НоменклатураСсылка",
Строка(СтрокаКМ.Номенклатура.УникальныйИдентификатор()));
Иначе
ТелоСтроки = СтрЗаменить(ТелоСтроки, "$НоменклатураСсылка", "");
КонецЕсли;
ТелоСтроки = СтрЗаменить(ТелоСтроки, "$Упаковка", XMLЧислоДляШаблона(СтрокаКМ.Упаковка));
ТелоСтроки = СтрЗаменить(ТелоСтроки, "$ТоварнаяКатегория",
XMLЗначениеДляШаблона(ТоварнаяКатегорияНоменклатуры(СтрокаКМ.Номенклатура)));
СтрокиЗапроса = СтрокиЗапроса + ТелоСтроки;
КонецЦикла;
Возврат СтрокиЗапроса;
КонецФункции
// Выгрузка поступления в УТ11 (SOAP setDoc).
// В пакет включаются ТЧ Товары и ТЧ Партии (Серии + Марки по ШК партий).
//
Функция SetDocПоступление(Док) Экспорт
Пользователь = "admin1c";
Пароль = "A400943@!";
HTTPСоединение = Новый HTTPСоединение("vasvas.itinalog.ru", 443, Пользователь, Пароль,,,
Новый ЗащищенноеСоединениеOpenSSL());
Заголовки = Новый Соответствие;
Заголовки.Вставить("Content-Type", "application/xml_request");
ТелоЗапроса = ТекстОбщегоМакета("ШаблонSetDocПоступление");
ТелоЗапроса = СтрЗаменить(ТелоЗапроса, "$ДокСсылка", Строка(Док.Ссылка.УникальныйИдентификатор()));
ТелоЗапроса = СтрЗаменить(ТелоЗапроса, "$Дата", Формат(Док.Дата, "ДФ=""гггг-ММ-дд'T'ЧЧ:мм:сс"""));
ТелоЗапроса = СтрЗаменить(ТелоЗапроса, "$Номер", XMLЗначениеДляШаблона(Док.Номер));
ТелоЗапроса = СтрЗаменить(ТелоЗапроса, "$Комментарий", XMLЗначениеДляШаблона(Док.Комментарий));
ТелоЗапроса = СтрЗаменить(ТелоЗапроса, "$Товары", СформироватьТоварыSetDocПоступление(Док));
ТелоЗапроса = СтрЗаменить(ТелоЗапроса, "$Серии", СформироватьПартииSetDocПоступление(Док));
ТелоЗапроса = СтрЗаменить(ТелоЗапроса, "$Марки", СформироватьМаркиИзПартийSetDocПоступление(Док));
ТелоЗапроса = ОчиститьПлейсхолдерыШаблона(ТелоЗапроса);
HTTPЗапрос = Новый HTTPЗапрос("/utip_curent/ws/tsdsync", Заголовки);
HTTPЗапрос.УстановитьТелоИзСтроки(ТелоЗапроса);
РезультатЗапроса = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
Возврат РезультатЗапроса.ПолучитьТелоКакСтроку();
КонецФункции
// Выгрузка всех проведённых поступлений со статусом Котправке.
// Возвращает текст протокола (успех/ошибка по каждому документу).
//
Функция ВыгрузитьПоступленияКОтправке() Экспорт
Протокол = "";
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ПоступлениеТоваровИУслуг.Ссылка КАК Ссылка
|ИЗ
| Документ.ПоступлениеТоваровИУслуг КАК ПоступлениеТоваровИУслуг
|ГДЕ
| НЕ ПоступлениеТоваровИУслуг.ПометкаУдаления
| И ПоступлениеТоваровИУслуг.Проведен
| И ПоступлениеТоваровИУслуг.Статус = &Статус
|
|УПОРЯДОЧИТЬ ПО
| ПоступлениеТоваровИУслуг.Дата,
| ПоступлениеТоваровИУслуг.Номер";
Запрос.УстановитьПараметр("Статус", Перечисления.Статус.Котправке);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
ДокОбъект = Выборка.Ссылка.ПолучитьОбъект();
Если ДокОбъект = Неопределено Тогда
Протокол = Протокол + "Ошибка: объект не найден " + Выборка.Ссылка + Символы.ПС;
Продолжить;
КонецЕсли;
Попытка
xmlответ = SetDocПоступление(ДокОбъект);
Если ОтветSetDocУспешен(xmlответ) Тогда
ДокОбъект.Статус = Перечисления.Статус.Отправлен;
ДокОбъект.Записать();
Протокол = Протокол + "Успешно отправлено поступление " + Выборка.Ссылка
+ " (партий: " + ДокОбъект.Партии.Количество() + ")" + Символы.ПС;
Иначе
Протокол = Протокол + "Ошибка отправки поступления " + Выборка.Ссылка
+ ": " + КраткийТекстОшибкиSetDoc(xmlответ) + Символы.ПС;
КонецЕсли;
Исключение
Протокол = Протокол + "Ошибка отправки поступления " + Выборка.Ссылка
+ ": " + ОписаниеОшибки() + Символы.ПС;
КонецПопытки;
КонецЦикла;
Возврат Протокол;
КонецФункции
Функция СформироватьТоварыSetDocПоступление(Док)
СтрокиЗапроса = "";
ШаблонСтроки = ТекстОбщегоМакета("ШаблонSetDocПоступлениеТовар");
Для Каждого СтрокаТовара Из Док.Товары Цикл
ТелоСтроки = ШаблонСтроки;
ТелоСтроки = СтрЗаменить(ТелоСтроки, "$НомерСтроки", Формат(СтрокаТовара.НомерСтроки, "ЧГ=0"));
ТелоСтроки = СтрЗаменить(ТелоСтроки, "$КодСтроки", Формат(СтрокаТовара.НомерСтроки, "ЧГ=0"));
ТелоСтроки = СтрЗаменить(ТелоСтроки, "$ИдентификаторСтроки", Формат(СтрокаТовара.НомерСтроки, "ЧГ=0"));
ТелоСтроки = СтрЗаменить(ТелоСтроки, "$КлючСвязи", Формат(СтрокаТовара.НомерСтроки, "ЧГ=0"));
Если ЗначениеЗаполнено(СтрокаТовара.Номенклатура) Тогда
ТелоСтроки = СтрЗаменить(ТелоСтроки, "$НоменклатураСсылка",
Строка(СтрокаТовара.Номенклатура.УникальныйИдентификатор()));
ТелоСтроки = СтрЗаменить(ТелоСтроки, "$НоменклатураНаименование",
XMLЗначениеДляШаблона(Строка(СтрокаТовара.Номенклатура)));
ТелоСтроки = СтрЗаменить(ТелоСтроки, "$НоменклатураНаименованиеПолное",
XMLЗначениеДляШаблона(Строка(СтрокаТовара.Номенклатура)));
ТелоСтроки = СтрЗаменить(ТелоСтроки, "$ТоварнаяКатегория",
XMLЗначениеДляШаблона(ТоварнаяКатегорияНоменклатуры(СтрокаТовара.Номенклатура)));
КонецЕсли;
ТелоСтроки = СтрЗаменить(ТелоСтроки, "$Количество", XMLЧислоДляШаблона(СтрокаТовара.Количество));
ТелоСтроки = СтрЗаменить(ТелоСтроки, "$КоличествоУпаковок", XMLЧислоДляШаблона(СтрокаТовара.Количество));
ТелоСтроки = СтрЗаменить(ТелоСтроки, "$Отсканировано", XMLЧислоДляШаблона(СтрокаТовара.Отсканировано));
ТелоСтроки = СтрЗаменить(ТелоСтроки, "$Партия",
XMLЗначениеДляШаблона(НомераПартийНоменклатурыСтрокой(Док, СтрокаТовара.Номенклатура)));
ТелоСтроки = ОчиститьПлейсхолдерыШаблона(ТелоСтроки);
СтрокиЗапроса = СтрокиЗапроса + ТелоСтроки;
КонецЦикла;
Возврат СтрокиЗапроса;
КонецФункции
Функция ТекстОбщегоМакета(ИмяМакета)
// Без Тип("ТекстовыйДокумент") / Тип("ТабличныйДокумент") —
// на мобильной платформе эти типы не определены.
Макет = ПолучитьОбщийМакет(ИмяМакета);
Текст = "";
// Сначала ячейка R1C1 (как у рабочих SOAP-макетов ШаблонSetDoc / GetDoc)
Попытка
Текст = Макет.Область(1, 1, 1, 1).Текст;
Исключение
КонецПопытки;
Если Не ЗначениеЗаполнено(Текст) Тогда
Попытка
Текст = Макет.ТекущаяОбласть.Текст;
Исключение
КонецПопытки;
КонецЕсли;
Если Не ЗначениеЗаполнено(Текст) Тогда
Попытка
Текст = Макет.ПолучитьТекст();
Исключение
КонецПопытки;
КонецЕсли;
Если Не ЗначениеЗаполнено(Текст) Тогда
ВызватьИсключение "Пустой макет " + ИмяМакета
+ ". Загрузите конфигурацию из файлов (Ext\Template.xml).";
КонецЕсли;
Возврат Текст;
КонецФункции
Функция СформироватьПартииSetDocПоступление(Док)
СтрокиЗапроса = "";
ШаблонСтроки = ТекстОбщегоМакета("ШаблонSetDocПоступлениеПартия");
Для Каждого СтрокаПартии Из Док.Партии Цикл
ТелоСтроки = ШаблонСтроки;
ТелоСтроки = СтрЗаменить(ТелоСтроки, "$НомерСтроки", Формат(СтрокаПартии.НомерСтроки, "ЧГ=0"));
Если ЗначениеЗаполнено(СтрокаПартии.Номенклатура) Тогда
ТелоСтроки = СтрЗаменить(ТелоСтроки, "$НоменклатураСсылка",
Строка(СтрокаПартии.Номенклатура.УникальныйИдентификатор()));
ТелоСтроки = СтрЗаменить(ТелоСтроки, "$НоменклатураНаименование",
XMLЗначениеДляШаблона(Строка(СтрокаПартии.Номенклатура)));
КонецЕсли;
ТелоСтроки = СтрЗаменить(ТелоСтроки, "$Количество", XMLЧислоДляШаблона(СтрокаПартии.КоличествоВПартии));
ТелоСтроки = СтрЗаменить(ТелоСтроки, "$Партия", XMLЗначениеДляШаблона(СтрокаПартии.НомерПартии));
ТелоСтроки = СтрЗаменить(ТелоСтроки, "$СерияПартии", XMLЗначениеДляШаблона(СтрокаПартии.СерияПартии));
ТелоСтроки = СтрЗаменить(ТелоСтроки, "$СерияНомер",
XMLЗначениеДляШаблона(?(ЗначениеЗаполнено(СтрокаПартии.СерияПартии),
СтрокаПартии.СерияПартии, СтрокаПартии.НомерПартии)));
Если ЗначениеЗаполнено(СтрокаПартии.ДатаПартии) Тогда
ТелоСтроки = СтрЗаменить(ТелоСтроки, "$СерияДатаПроизводства",
Формат(СтрокаПартии.ДатаПартии, "ДФ=гггг-ММ-дд"));
Иначе
ТелоСтроки = СтрЗаменить(ТелоСтроки, "<ДатаПроизводства>$СерияДатаПроизводства</ДатаПроизводства>", "");
КонецЕсли;
ДатаГоденДо = СтрокаПартии.ГоденДо;
Если ЗначениеЗаполнено(ДатаГоденДо) Тогда
ТелоСтроки = СтрЗаменить(ТелоСтроки, "$СерияГоденДо",
Формат(ДатаГоденДо, "ДФ=гггг-ММ-дд"));
Иначе
ТелоСтроки = СтрЗаменить(ТелоСтроки, "<ГоденДо>$СерияГоденДо</ГоденДо>", "");
КонецЕсли;
ТелоСтроки = СтрЗаменить(ТелоСтроки, "$Штрихкод",
XMLЗначениеДляШаблона(КодМаркировкиДляSOAP(СтрокаПартии.ШК)));
ТелоСтроки = ОчиститьПлейсхолдерыШаблона(ТелоСтроки);
СтрокиЗапроса = СтрокиЗапроса + ТелоСтроки;
КонецЦикла;
Возврат СтрокиЗапроса;
КонецФункции
Функция СформироватьМаркиИзПартийSetDocПоступление(Док)
СтрокиЗапроса = "";
ШаблонСтроки = ТекстОбщегоМакета("ШаблонSetDocМарка");
Для Каждого СтрокаПартии Из Док.Партии Цикл
Если Не ЗначениеЗаполнено(СтрокаПартии.ШК) Тогда
Продолжить;
КонецЕсли;
ТелоСтроки = ШаблонСтроки;
ТелоСтроки = СтрЗаменить(ТелоСтроки, "$Строка", Формат(СтрокаПартии.НомерСтроки, "ЧГ=0"));
ТелоСтроки = СтрЗаменить(ТелоСтроки, "$Код", КодМаркировкиДляSOAP(СтрокаПартии.ШК));
Если ЗначениеЗаполнено(СтрокаПартии.Номенклатура) Тогда
ТелоСтроки = СтрЗаменить(ТелоСтроки, "$НоменклатураСсылка",
Строка(СтрокаПартии.Номенклатура.УникальныйИдентификатор()));
Иначе
ТелоСтроки = СтрЗаменить(ТелоСтроки, "$НоменклатураСсылка", "");
КонецЕсли;
ТелоСтроки = СтрЗаменить(ТелоСтроки, "$Упаковка", XMLЧислоДляШаблона(СтрокаПартии.КоличествоВПартии));
ТелоСтроки = СтрЗаменить(ТелоСтроки, "$ТоварнаяКатегория",
XMLЗначениеДляШаблона(ТоварнаяКатегорияНоменклатуры(СтрокаПартии.Номенклатура)));
СтрокиЗапроса = СтрокиЗапроса + ТелоСтроки;
КонецЦикла;
Возврат СтрокиЗапроса;
КонецФункции
Функция НомераПартийНоменклатурыСтрокой(Док, Номенклатура)
Если Не ЗначениеЗаполнено(Номенклатура) Тогда
Возврат "";
КонецЕсли;
Части = Новый Массив;
Для Каждого СтрокаПартии Из Док.Партии.НайтиСтроки(Новый Структура("Номенклатура", Номенклатура)) Цикл
Если ЗначениеЗаполнено(СтрокаПартии.НомерПартии)
И Части.Найти(СтрокаПартии.НомерПартии) = Неопределено Тогда
Части.Добавить(СтрокаПартии.НомерПартии);
КонецЕсли;
КонецЦикла;
Возврат СтрСоединить(Части, ", ");
КонецФункции
Функция НормализоватьXMLОтветСервиса(Знач ТекстОтвета)
Если Не ЗначениеЗаполнено(ТекстОтвета) Тогда
Возврат "";
КонецЕсли;
ТекстОтвета = СокрЛП(ТекстОтвета);
// Убираем мусор / BOM до первого тега
ПозНачало = СтрНайти(ТекстОтвета, "<");
Если ПозНачало = 0 Тогда
Возврат "";
КонецЕсли;
Если ПозНачало > 1 Тогда
ТекстОтвета = Сред(ТекстОтвета, ПозНачало);
КонецЕсли;
ТекстВерх = ВРег(ТекстОтвета);
// Обрезаем по закрывающему </...:Envelope> (последнее вхождение)
МаркерКонца = ":ENVELOPE>";
ПозПоиска = 1;
ПозМаркера = 0;
Пока Истина Цикл
Поз = СтрНайти(Сред(ТекстВерх, ПозПоиска), МаркерКонца);
Если Поз = 0 Тогда
Прервать;
КонецЕсли;
ПозМаркера = ПозПоиска + Поз - 1;
ПозПоиска = ПозМаркера + 1;
КонецЦикла;
Если ПозМаркера > 0 Тогда
ПозОтворота = ПозМаркера;
Пока ПозОтворота > 1 И Сред(ТекстОтвета, ПозОтворота, 1) <> "<" Цикл
ПозОтворота = ПозОтворота - 1;
КонецЦикла;
Если Сред(ТекстОтвета, ПозОтворота, 2) = "</" Тогда
ТекстОтвета = Лев(ТекстОтвета, ПозМаркера + СтрДлина(МаркерКонца) - 1);
КонецЕсли;
Иначе
// Без Envelope — отрезаем второй <?xml, если есть
ПозПервого = СтрНайти(ТекстОтвета, "<?xml");
Если ПозПервого > 0 Тогда
ПозВторого = СтрНайти(Сред(ТекстОтвета, ПозПервого + 5), "<?xml");
Если ПозВторого > 0 Тогда
ТекстОтвета = СокрЛП(Лев(ТекстОтвета, ПозПервого + 5 + ПозВторого - 2));
КонецЕсли;
КонецЕсли;
КонецЕсли;
Возврат СокрЛП(ТекстОтвета);
КонецФункции
Функция КраткийТекстОшибкиSetDoc(xmlответ)
Если Не ЗначениеЗаполнено(xmlответ) Тогда
Возврат "пустой ответ УТ11";
КонецЕсли;
Текст = НормализоватьXMLОтветСервиса(xmlответ);
Если Не ЗначениеЗаполнено(Текст) Тогда
Возврат "некорректный ответ УТ11";
КонецЕсли;
ИменаТегов = Новый Массив;
ИменаТегов.Добавить("faultstring");
ИменаТегов.Добавить("Text");
ИменаТегов.Добавить("Reason");
Для Каждого ИмяТега Из ИменаТегов Цикл
Фрагмент = ТекстМеждуXMLТегами(Текст, ИмяТега);
Если ЗначениеЗаполнено(Фрагмент)
И ВРег(Фрагмент) <> "FALSE"
И ВРег(Фрагмент) <> "0" Тогда
Возврат Лев(Фрагмент, 500);
КонецЕсли;
КонецЦикла;
Возврат Лев(СтрЗаменить(Текст, Символы.ПС, " "), 300);
КонецФункции
Функция ТекстМеждуXMLТегами(Текст, ИмяТега)
Открывающий = "<" + ИмяТега;
Поз = СтрНайти(ВРег(Текст), ВРег(Открывающий));
Если Поз = 0 Тогда
Возврат "";
КонецЕсли;
Хвост = Сред(Текст, Поз);
ПозКонцаОткр = СтрНайти(Хвост, ">");
Если ПозКонцаОткр = 0 Тогда
Возврат "";
КонецЕсли;
ПослеОткр = Сред(Хвост, ПозКонцаОткр + 1);
ПозЗакр = СтрНайти(ВРег(ПослеОткр), ВРег("</" + ИмяТега + ">"));
Если ПозЗакр = 0 Тогда
Возврат "";
КонецЕсли;
Фрагмент = СокрЛП(Лев(ПослеОткр, ПозЗакр - 1));
Фрагмент = СтрЗаменить(Фрагмент, "&lt;", "<");
Фрагмент = СтрЗаменить(Фрагмент, "&gt;", ">");
Фрагмент = СтрЗаменить(Фрагмент, "&amp;", "&");
Возврат Фрагмент;
КонецФункции
Функция ОтветSetDocУспешен(xmlответ)
Если Не ЗначениеЗаполнено(xmlответ) Тогда
Возврат Ложь;
КонецЕсли;
Попытка
Чтение = Новый ЧтениеXML;
xmlответ = НормализоватьXMLОтветСервиса(xmlответ);
Если Не ЗначениеЗаполнено(xmlответ) Тогда
Возврат Ложь;
КонецЕсли;
Чтение.УстановитьСтроку(xmlответ);
Фабрика = Новый ФабрикаXDTO;
Конверт = Фабрика.ПрочитатьXML(Чтение);
Возврат Булево(Конверт.Body.setDocResponse.return);
Исключение
Возврат Ложь;
КонецПопытки;
КонецФункции
Функция XMLЗначениеДляШаблона(Значение)
Если Значение = Неопределено Тогда
Возврат "";
КонецЕсли;
Текст = Строка(Значение);
Текст = СтрЗаменить(Текст, "&", "&amp;");
Текст = СтрЗаменить(Текст, "<", "&lt;");
Текст = СтрЗаменить(Текст, ">", "&gt;");
Текст = СтрЗаменить(Текст, """", "&quot;");
Возврат Текст;
КонецФункции
Функция XMLЧислоДляШаблона(Значение)
Если Значение = Неопределено Тогда
Возврат "0";
КонецЕсли;
Возврат Формат(Значение, "ЧРД=.; ЧДЦ=3; ЧН=0; ЧГ=0");
КонецФункции
Функция ТоварнаяКатегорияНоменклатуры(Номенклатура)
Если Не ЗначениеЗаполнено(Номенклатура) Тогда
Возврат "";
КонецЕсли;
Возврат СокрЛП(Строка(Номенклатура.ТоварнаяКатегория));
КонецФункции
Функция ТоварнаяКатегорияИзXDTO(ДанныеНоменклатуры, НоменклатураXDTO = Неопределено)
Результат = ТоварнаяКатегорияИзОбъектаXDTO(ДанныеНоменклатуры);
Если Результат <> "" Тогда
Возврат Результат;
КонецЕсли;
Возврат ТоварнаяКатегорияИзОбъектаXDTO(НоменклатураXDTO);
КонецФункции
Функция ТоварнаяКатегорияИзОбъектаXDTO(ОбъектXDTO)
Если ОбъектXDTO = Неопределено Тогда
Возврат "";
КонецЕсли;
Результат = СтрокаИзЗначенияXDTO(СвойствоXDTO(ОбъектXDTO, "ТоварнаяКатегория"));
Если Результат <> "" Тогда
Возврат Результат;
КонецЕсли;
Возврат СтрокаИзЗначенияXDTO(СвойствоXDTO(ОбъектXDTO, "ОсобенностьУчета"));
КонецФункции
Функция СтрокаИзЗначенияXDTO(Значение)
Если Значение = Неопределено Тогда
Возврат "";
КонецЕсли;
ТипЗнач = ТипЗнч(Значение);
Если ТипЗнач = Тип("Строка")
Или ТипЗнач = Тип("Число")
Или ТипЗнач = Тип("Дата")
Или ТипЗнач = Тип("Булево") Тогда
Возврат СокрЛП(Строка(Значение));
КонецЕсли;
ИменаСвойств = Новый Массив;
ИменаСвойств.Добавить("Наименование");
ИменаСвойств.Добавить("НаименованиеПолное");
ИменаСвойств.Добавить("Description");
ИменаСвойств.Добавить("Представление");
ИменаСвойств.Добавить("Name");
Для Каждого ИмяСвойства Из ИменаСвойств Цикл
Текст = ТекстСвойстваXDTO(Значение, ИмяСвойства);
Если Текст <> "" Тогда
Возврат Текст;
КонецЕсли;
КонецЦикла;
// Не вызываем Строка(XDTO) — на мобильной платформе это даёт «ОбъектXDTO».
Возврат "";
КонецФункции
Функция ТекстСвойстваXDTO(Объект, ИмяСвойства)
ЗначениеСвойства = СвойствоXDTO(Объект, ИмяСвойства);
Если ЗначениеСвойства = Неопределено Тогда
Возврат "";
КонецЕсли;
ТипЗнач = ТипЗнч(ЗначениеСвойства);
Если ТипЗнач = Тип("Строка")
Или ТипЗнач = Тип("Число")
Или ТипЗнач = Тип("Дата")
Или ТипЗнач = Тип("Булево") Тогда
Возврат СокрЛП(Строка(ЗначениеСвойства));
КонецЕсли;
Возврат СтрокаИзЗначенияXDTO(ЗначениеСвойства);
КонецФункции
Функция ОчиститьПлейсхолдерыШаблона(Знач Текст)
Пока Истина Цикл
Поз = СтрНайти(Текст, "$");
Если Поз = 0 Тогда
Прервать;
КонецЕсли;
КонецИмени = Поз + 1;
Пока КонецИмени <= СтрДлина(Текст) Цикл
Если Не ЭтоСимволИмениПлейсхолдера(Сред(Текст, КонецИмени, 1)) Тогда
Прервать;
КонецЕсли;
КонецИмени = КонецИмени + 1;
КонецЦикла;
Текст = Лев(Текст, Поз - 1) + Сред(Текст, КонецИмени);
КонецЦикла;
Возврат Текст;
КонецФункции
Функция ЭтоСимволИмениПлейсхолдера(Символ)
Код = КодСимвола(Символ);
Возврат (Код >= 65 И Код <= 90)
Или (Код >= 97 И Код <= 122)
Или (Код >= 48 И Код <= 57)
Или (Код >= 1040 И Код <= 1103)
Или Код = 1025
Или Код = 1105
Или Символ = "_";
КонецФункции
Функция КодироватьСтрокуВBase64(Знач Строка,
Знач Кодировка = Неопределено,
Знач ЗаписатьBOM = Ложь) Экспорт
// Устанавливаем кодировку по умолчанию, если не указана
Если Не ЗначениеЗаполнено(Кодировка) Тогда
Кодировка = КодировкаТекста.UTF8;
КонецЕсли;
// Преобразуем строку в двоичные данные
ДвоичныеДанные = ПолучитьДвоичныеДанныеИзСтроки(Строка, Кодировка, ЗаписатьBOM);
// Кодируем двоичные данные в Base64
Результат = Base64Строка(ДвоичныеДанные);
Результат = СтрЗаменить(Результат, Символы.ПС, "");
Результат = СтрЗаменить(Результат, Символы.ВК, "");
Возврат Результат;
КонецФункции
Функция НормализоватьКодМаркировки(Знач Код) Экспорт
Результат = СокрЛП(Строка(Код));
Результат = СтрЗаменить(Результат, Символ(29), "");
Результат = СтрЗаменить(Результат, Символ(232), "");
Результат = СтрЗаменить(Результат, " ", "");
Возврат Результат;
КонецФункции
Функция КодМаркировкиВBase64(Знач Код) Экспорт
Возврат КодироватьСтрокуВBase64(Строка(Код));
КонецФункции
// Для SOAP: если в ШК уже Base64 — не кодируем повторно.
//
Функция КодМаркировкиДляSOAP(Знач ШК) Экспорт
Текст = СокрЛП(Строка(ШК));
Если Не ЗначениеЗаполнено(Текст) Тогда
Возврат "";
КонецЕсли;
Если ЭтоСыройКодМаркировки(Текст) Тогда
Возврат КодироватьСтрокуВBase64(Текст);
КонецЕсли;
Очищенный = СтрЗаменить(СтрЗаменить(Текст, Символы.ПС, ""), Символы.ВК, "");
Если ЭтоСтрокаBase64(Очищенный) Тогда
Возврат Очищенный;
КонецЕсли;
Возврат КодироватьСтрокуВBase64(Текст);
КонецФункции
Функция ИсходныйКодМаркировкиИзШК(Знач ШК) Экспорт
Текст = СокрЛП(Строка(ШК));
Если Не ЗначениеЗаполнено(Текст) Тогда
Возврат "";
КонецЕсли;
Если ЭтоСыройКодМаркировки(Текст) Тогда
Возврат Текст;
КонецЕсли;
Очищенный = СтрЗаменить(СтрЗаменить(Текст, Символы.ПС, ""), Символы.ВК, "");
Если Не ЭтоСтрокаBase64(Очищенный) Тогда
Возврат Текст;
КонецЕсли;
Попытка
ДвоичныеДанные = Base64Значение(Очищенный);
Если ДвоичныеДанные = Неопределено Тогда
Возврат Текст;
КонецЕсли;
Чтение = Новый ЧтениеДанных(ДвоичныеДанные);
Декодированная = СокрЛП(Чтение.ПрочитатьСимволы());
Чтение.Закрыть();
Если ЗначениеЗаполнено(Декодированная) Тогда
Возврат Декодированная;
КонецЕсли;
Исключение
КонецПопытки;
Возврат Текст;
КонецФункции
Функция ЭтоСыройКодМаркировки(Текст)
Если СтрНайти(Текст, Символ(29)) > 0 Или СтрНайти(Текст, Символ(232)) > 0 Тогда
Возврат Истина;
КонецЕсли;
Префикс = Лев(Текст, 2);
Возврат Префикс = "01" Или Префикс = "00";
КонецФункции
Функция ЭтоСтрокаBase64(Текст)
Если СтрДлина(Текст) < 8 Или СтрДлина(Текст) % 4 <> 0 Тогда
Возврат Ложь;
КонецЕсли;
Для Номер = 1 По СтрДлина(Текст) Цикл
Символ = Сред(Текст, Номер, 1);
Код = КодСимвола(Символ);
ЭтоЛатиница = (Код >= 65 И Код <= 90) Или (Код >= 97 И Код <= 122);
ЭтоЦифра = (Код >= 48 И Код <= 57);
Если Не ЭтоЛатиница И Не ЭтоЦифра И Символ <> "+" И Символ <> "/" И Символ <> "=" Тогда
Возврат Ложь;
КонецЕсли;
КонецЦикла;
Возврат Истина;
КонецФункции
Функция GetMarkCND(марка, инн) Экспорт
СтрокаURI = "https://vasvas.itinalog.ru/utip_curent/ws/tsdsync";
Пользователь = "admin1c";
Пароль = "A400943@!";
HTTPСоединение = Новый HTTPСоединение("vasvas.itinalog.ru",443,Пользователь,Пароль,,,Новый ЗащищенноеСоединениеOpenSSL());
Заголовки = Новый Соответствие();
Заголовки.Вставить("Content-Type","application/xml_request");
ТелоЗапроса = ПолучитьОбщийМакет("ШаблонGetMarkCND").ТекущаяОбласть.Текст;
ТелоЗапроса=СтрЗаменить(ТелоЗапроса,"$марка", КодироватьСтрокуВBase64(марка));
ТелоЗапроса=СтрЗаменить(ТелоЗапроса,"$инн", инн);
HTTPЗапрос = Новый HTTPЗапрос("/utip_curent/ws/tsdsync", Заголовки);
HTTPЗапрос.УстановитьТелоИзСтроки(ТелоЗапроса);
РезультатЗапроса = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
ТекстОтвета = РезультатЗапроса.ПолучитьТелоКакСтроку();
Возврат ТекстОтвета;
КонецФункции
// Загрузка документа из УТ11. Тип обязателен: номера заказа и поступления могут совпадать.
//
// Параметры:
// НомерИлиШтрихкод - Строка;
// ТипДокумента - Строка - "ЗаказКлиента" | "ПоступлениеТоваровУслуг".
//
Функция ЗагрузитьДокумент(НомерИлиШтрихкод, ТипДокумента = "ЗаказКлиента") Экспорт
Результат = Новый Структура("Успех, Ссылка, Сообщение, ЭтоНовый, ТипДокумента",
Ложь, Неопределено, "", Ложь, "");
Штрихкод = НормализоватьШтрихкодДокумента(НомерИлиШтрихкод);
Если Не ЗначениеЗаполнено(Штрихкод) Тогда
Результат.Сообщение = "Не указан номер или штрихкод документа.";
Возврат Результат;
КонецЕсли;
ТипДокументаНорм = НормализоватьТипДокументаЗагрузки(ТипДокумента);
Результат.ТипДокумента = ТипДокументаНорм;
ЭтоПоступление = (ТипДокументаНорм = "ПоступлениеТоваровУслуг");
МенеджерДокументов = ?(ЭтоПоступление,
Документы.ПоступлениеТоваровИУслуг,
Документы.ЗаказКлиента);
ПредставлениеТипа = ?(ЭтоПоступление, "поступление", "заказ");
ЛокальнаяСсылка = НайтиДокументПоНомеруИлиШК(Штрихкод, ТипДокументаНорм);
Попытка
XmlОтвет = GetDoc(Штрихкод, ТипДокументаНорм);
Исключение
Если ДокументСсылкаСуществует(ЛокальнаяСсылка) Тогда
Результат.Успех = Истина;
Результат.Ссылка = ЛокальнаяСсылка;
Результат.Сообщение = "Открыт локальный " + ПредставлениеТипа
+ " (УТ11 недоступна): " + ПредставлениеДокументаКратко(ЛокальнаяСсылка);
Возврат Результат;
КонецЕсли;
Результат.Сообщение = "Ошибка обращения к УТ11: " + ОписаниеОшибки();
Возврат Результат;
КонецПопытки;
XmlОтвет = НормализоватьXMLОтветСервиса(XmlОтвет);
Если Не ЗначениеЗаполнено(XmlОтвет) Тогда
Если ДокументСсылкаСуществует(ЛокальнаяСсылка) Тогда
Результат.Успех = Истина;
Результат.Ссылка = ЛокальнаяСсылка;
Результат.Сообщение = "Открыт локальный " + ПредставлениеТипа
+ " (пустой ответ УТ11): " + ПредставлениеДокументаКратко(ЛокальнаяСсылка);
Возврат Результат;
КонецЕсли;
Результат.Сообщение = "Пустой или некорректный XML-ответ УТ11.";
Возврат Результат;
КонецЕсли;
Чтение = Новый ЧтениеXML;
Чтение.УстановитьСтроку(XmlОтвет);
Фабрика = Новый ФабрикаXDTO;
Попытка
ОбXDTO = Фабрика.ПрочитатьXML(Чтение).Body.getDocResponse.return;
Исключение
Если ДокументСсылкаСуществует(ЛокальнаяСсылка) Тогда
Результат.Успех = Истина;
Результат.Ссылка = ЛокальнаяСсылка;
Результат.Сообщение = "Открыт локальный " + ПредставлениеТипа
+ " (ошибка ответа УТ11): " + ПредставлениеДокументаКратко(ЛокальнаяСсылка);
Возврат Результат;
КонецЕсли;
Фрагмент = Лев(СтрЗаменить(XmlОтвет, Символы.ПС, " "), 300);
Результат.Сообщение = "Ошибка разбора ответа УТ11: " + ОписаниеОшибки()
+ Символы.ПС + "Фрагмент ответа: " + Фрагмент;
Возврат Результат;
КонецПопытки;
ОбXDTOИсходный = ОбXDTO;
ТипИзОтвета = ОпределитьТипДокументаИзОтветаXDTO(ОбXDTOИсходный);
ОбXDTO = ИзвлечьДокументXDTO(ОбXDTO, ТипДокументаНорм);
Если Не ЗначениеЗаполнено(ТипИзОтвета) Тогда
ТипИзОтвета = ОпределитьТипДокументаИзОтветаXDTO(ОбXDTO);
КонецЕсли;
Если ЗначениеЗаполнено(ТипИзОтвета) И ТипИзОтвета <> ТипДокументаНорм Тогда
Ожидали = ?(ЭтоПоступление, "поступление товаров", "заказ клиента");
Получили = ?(ТипИзОтвета = "ПоступлениеТоваровУслуг", "поступление товаров", "заказ клиента");
Результат.Сообщение = "Тип документа не совпадает: ожидался "
+ Ожидали + ", а в УТ11 найден " + Получили + ".";
Возврат Результат;
КонецЕсли;
КлючевыеСвойства = СвойствоXDTO(ОбXDTO, "КлючевыеСвойства");
Если КлючевыеСвойства = Неопределено Тогда
Если ДокументСсылкаСуществует(ЛокальнаяСсылка) Тогда
Результат.Успех = Истина;
Результат.Ссылка = ЛокальнаяСсылка;
Результат.Сообщение = "Открыт локальный " + ПредставлениеТипа + ": "
+ ПредставлениеДокументаКратко(ЛокальнаяСсылка);
Возврат Результат;
КонецЕсли;
Результат.Сообщение = "В ответе УТ11 отсутствуют ключевые свойства документа.";
Возврат Результат;
КонецЕсли;
СсылкаСтрока = НормализоватьИдентификаторСсылкиXDTO(СвойствоXDTO(КлючевыеСвойства, "Ссылка", ""));
НомерИзУТ = СокрЛП(Строка(СвойствоXDTO(КлючевыеСвойства, "Номер", "")));
ДатаИзУТ = ДатаИзСтрокиXDTO(СвойствоXDTO(КлючевыеСвойства, "Дата"));
// Доп. защита: GUID/номер уже есть в ТСД как документ другого типа
ТипКонфликта = НайтиКонфликтТипаДокумента(СсылкаСтрока, НомерИзУТ, ТипДокументаНорм);
Если ЗначениеЗаполнено(ТипКонфликта) Тогда
Ожидали = ?(ЭтоПоступление, "поступление товаров", "заказ клиента");
Получили = ?(ТипКонфликта = "ПоступлениеТоваровУслуг", "поступление товаров", "заказ клиента");
Результат.Сообщение = "Тип документа не совпадает: ожидался "
+ Ожидали + ", а найден " + Получили + ".";
Возврат Результат;
КонецЕсли;
Если Не ЗначениеЗаполнено(СсылкаСтрока) Тогда
Если ДокументСсылкаСуществует(ЛокальнаяСсылка) Тогда
Результат.Успех = Истина;
Результат.Ссылка = ЛокальнаяСсылка;
Результат.Сообщение = "Открыт локальный " + ПредставлениеТипа + ": "
+ ПредставлениеДокументаКратко(ЛокальнаяСсылка);
Возврат Результат;
КонецЕсли;
Результат.Сообщение = "Документ не найден в УТ11 по штрихкоду/номеру: " + Штрихкод;
Возврат Результат;
КонецЕсли;
// Сначала ищем уже загруженный документ по номеру УТ
// иначе при другом GUID открывается «новый» с идентификатором ссылки.
ДокОбъект = Неопределено;
Если ЗначениеЗаполнено(НомерИзУТ) Тогда
СсылкаПоНомеру = НайтиДокументПоТочномуНомеру(НомерИзУТ, ТипДокументаНорм);
Если ДокументСсылкаСуществует(СсылкаПоНомеру) Тогда
ДокОбъект = СсылкаПоНомеру.ПолучитьОбъект();
КонецЕсли;
КонецЕсли;
Если ДокОбъект = Неопределено И ДокументСсылкаСуществует(ЛокальнаяСсылка) Тогда
ДокОбъект = ЛокальнаяСсылка.ПолучитьОбъект();
КонецЕсли;
Если ДокОбъект = Неопределено Тогда
Попытка
ДокСсылка = МенеджерДокументов.ПолучитьСсылку(Новый УникальныйИдентификатор(СсылкаСтрока));
ДокОбъект = ДокСсылка.ПолучитьОбъект();
Если ДокОбъект = Неопределено Тогда
ДокОбъект = МенеджерДокументов.СоздатьДокумент();
ДокОбъект.УстановитьСсылкуНового(ДокСсылка);
Результат.ЭтоНовый = Истина;
КонецЕсли;
Исключение
Результат.Сообщение = "Некорректный идентификатор документа из УТ11.";
Возврат Результат;
КонецПопытки;
КонецЕсли;
Если ЗначениеЗаполнено(НомерИзУТ) Тогда
ДокОбъект.Номер = НомерИзУТ;
КонецЕсли;
Если ЗначениеЗаполнено(ДатаИзУТ) Тогда
ДокОбъект.Дата = ДатаИзУТ;
ИначеЕсли Не ЗначениеЗаполнено(ДокОбъект.Дата) Тогда
ДокОбъект.Дата = ТекущаяДата();
КонецЕсли;
ДокОбъект.Партнер = НайтиСоздатьПартнерИзXDTO(ОбXDTO);
ДокОбъект.Статус = Перечисления.Статус.Вработе;
ЭтоОбновлениеЗаказа = (Не ЭтоПоступление) И (Не Результат.ЭтоНовый);
ЗаполнитьТабличныеЧастиДокументаИзXDTO(ДокОбъект, ОбXDTO, ЭтоПоступление, ЭтоОбновлениеЗаказа);
Попытка
ДокОбъект.Записать();
Исключение
Если ЗначениеЗаполнено(НомерИзУТ) Тогда
СсылкаКонфликт = НайтиДокументПоТочномуНомеру(НомерИзУТ, ТипДокументаНорм);
Если ДокументСсылкаСуществует(СсылкаКонфликт) Тогда
ДокОбъект = СсылкаКонфликт.ПолучитьОбъект();
ДокОбъект.Номер = НомерИзУТ;
Если ЗначениеЗаполнено(ДатаИзУТ) Тогда
ДокОбъект.Дата = ДатаИзУТ;
КонецЕсли;
ДокОбъект.Партнер = НайтиСоздатьПартнерИзXDTO(ОбXDTO);
ДокОбъект.Статус = Перечисления.Статус.Вработе;
ЗаполнитьТабличныеЧастиДокументаИзXDTO(ДокОбъект, ОбXDTO, ЭтоПоступление, Не ЭтоПоступление);
Попытка
ДокОбъект.Записать();
Результат.ЭтоНовый = Ложь;
Исключение
Результат.Сообщение = "Ошибка записи документа: " + ОписаниеОшибки();
Возврат Результат;
КонецПопытки;
Иначе
Результат.Сообщение = "Ошибка записи документа: " + ОписаниеОшибки();
Возврат Результат;
КонецЕсли;
Иначе
Результат.Сообщение = "Ошибка записи документа: " + ОписаниеОшибки();
Возврат Результат;
КонецЕсли;
КонецПопытки;
Если Не ДокументСсылкаСуществует(ДокОбъект.Ссылка) Тогда
Результат.Сообщение = "Документ не записан в базу ТСД.";
Возврат Результат;
КонецЕсли;
Результат.Успех = Истина;
Результат.Ссылка = ДокОбъект.Ссылка;
Действие = ?(Результат.ЭтоНовый, "Загружен", "Обновлен");
Результат.Сообщение = Действие + " " + ПредставлениеТипа + " № " + ДокОбъект.Номер
+ " от " + Формат(ДокОбъект.Дата, "ДФ=дд.ММ.гггг");
Возврат Результат;
КонецФункции
Функция НормализоватьИдентификаторСсылкиXDTO(Знач СсылкаЗначение)
СсылкаСтрока = СокрЛП(Строка(СсылкаЗначение));
Если Не ЗначениеЗаполнено(СсылкаСтрока) Тогда
Возврат "";
КонецЕсли;
СсылкаСтрока = СтрЗаменить(СсылкаСтрока, "{", "");
СсылкаСтрока = СтрЗаменить(СсылкаСтрока, "}", "");
СсылкаСтрока = СокрЛП(СсылкаСтрока);
Если СсылкаСтрока = "00000000-0000-0000-0000-000000000000" Тогда
Возврат "";
КонецЕсли;
Если СтрДлина(СсылкаСтрока) > 36 Тогда
Поз = СтрНайти(СсылкаСтрока, "-");
Если Поз > 8 Тогда
Фрагмент = Сред(СсылкаСтрока, Поз - 8, 36);
Если СтрДлина(Фрагмент) = 36 Тогда
СсылкаСтрока = Фрагмент;
КонецЕсли;
КонецЕсли;
КонецЕсли;
Попытка
Уид = Новый УникальныйИдентификатор(СсылкаСтрока);
Возврат Строка(Уид);
Исключение
Возврат "";
КонецПопытки;
КонецФункции
Функция ДокументСсылкаСуществует(Ссылка)
Если Не ЗначениеЗаполнено(Ссылка) Тогда
Возврат Ложь;
КонецЕсли;
Попытка
Возврат Ссылка.ПолучитьОбъект() <> Неопределено;
Исключение
Возврат Ложь;
КонецПопытки;
КонецФункции
Функция ПредставлениеДокументаКратко(Ссылка)
Если Не ЗначениеЗаполнено(Ссылка) Тогда
Возврат "";
КонецЕсли;
Попытка
Возврат "№ " + Ссылка.Номер + " от " + Формат(Ссылка.Дата, "ДФ=дд.ММ.гггг");
Исключение
Возврат "";
КонецПопытки;
КонецФункции
Функция НайтиДокументПоТочномуНомеру(Номер, ТипДокумента)
ТипДокументаНорм = НормализоватьТипДокументаЗагрузки(ТипДокумента);
ЭтоПоступление = (ТипДокументаНорм = "ПоступлениеТоваровУслуг");
ИмяТаблицы = ?(ЭтоПоступление, "Документ.ПоступлениеТоваровИУслуг", "Документ.ЗаказКлиента");
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| Док.Ссылка КАК Ссылка
|ИЗ
| " + ИмяТаблицы + " КАК Док
|ГДЕ
| НЕ Док.ПометкаУдаления
| И Док.Номер = &Номер
|
|УПОРЯДОЧИТЬ ПО
| Док.Дата УБЫВ";
Запрос.УстановитьПараметр("Номер", СокрЛП(Строка(Номер)));
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
Возврат Выборка.Ссылка;
КонецЕсли;
Если ЭтоПоступление Тогда
Возврат Документы.ПоступлениеТоваровИУслуг.ПустаяСсылка();
КонецЕсли;
Возврат Документы.ЗаказКлиента.ПустаяСсылка();
КонецФункции
Функция ЗагрузитьЗаказКлиента(НомерИлиШтрихкод) Экспорт
Возврат ЗагрузитьДокумент(НомерИлиШтрихкод, "ЗаказКлиента");
КонецФункции
Функция ЗагрузитьПоступлениеТоваровИУслуг(НомерИлиШтрихкод) Экспорт
Возврат ЗагрузитьДокумент(НомерИлиШтрихкод, "ПоступлениеТоваровУслуг");
КонецФункции
Функция НормализоватьТипДокументаЗагрузки(ТипДокумента)
ТипСтрока = ВРег(СокрЛП(Строка(ТипДокумента)));
Если ТипСтрока = ВРег("ПоступлениеТоваровУслуг")
Или ТипСтрока = ВРег("ПоступлениеТоваровИУслуг")
Или ТипСтрока = ВРег("ПриобретениеТоваровУслуг")
Или ТипСтрока = ВРег("ПриобретениеТоваровИУслуг") Тогда
Возврат "ПоступлениеТоваровУслуг";
КонецЕсли;
// По умолчанию и при неизвестном значении — заказ клиента
Возврат "ЗаказКлиента";
КонецФункции
// Единый локальный поиск документа по номеру/ШК.
// - длина < 7 → по номеру (ПОДОБНО %ШК);
// - иначе → GUID или точный номер.
//
Функция НайтиСсылкиДокументаПоНомеруИлиШК(НомерИлиШтрихкод, ТипДокумента = "ЗаказКлиента") Экспорт
Ссылки = Новый Массив;
Штрихкод = НормализоватьШтрихкодДокумента(НомерИлиШтрихкод);
Если Не ЗначениеЗаполнено(Штрихкод) Тогда
Возврат Ссылки;
КонецЕсли;
ТипДокументаНорм = НормализоватьТипДокументаЗагрузки(ТипДокумента);
ЭтоПоступление = (ТипДокументаНорм = "ПоступлениеТоваровУслуг");
ИмяТаблицы = ?(ЭтоПоступление, "Документ.ПоступлениеТоваровИУслуг", "Документ.ЗаказКлиента");
МенеджерДокументов = ?(ЭтоПоступление, Документы.ПоступлениеТоваровИУслуг, Документы.ЗаказКлиента);
Если СтрДлина(Штрихкод) < 7 Тогда
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| Док.Ссылка КАК Ссылка
|ИЗ
| " + ИмяТаблицы + " КАК Док
|ГДЕ
| НЕ Док.ПометкаУдаления
| И Док.Номер ПОДОБНО &Номер
|
|УПОРЯДОЧИТЬ ПО
| Док.Дата УБЫВ";
Запрос.УстановитьПараметр("Номер", "%" + Штрихкод);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Ссылки.Добавить(Выборка.Ссылка);
КонецЦикла;
Иначе
Если СтрДлина(Штрихкод) = 36 Тогда
Попытка
СсылкаПоGUID = МенеджерДокументов.ПолучитьСсылку(Новый УникальныйИдентификатор(Штрихкод));
Если ОбщегоНазначенияСсылкаСуществует(СсылкаПоGUID) Тогда
Ссылки.Добавить(СсылкаПоGUID);
Возврат Ссылки;
КонецЕсли;
Исключение
// Не GUID
КонецПопытки;
КонецЕсли;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| Док.Ссылка КАК Ссылка
|ИЗ
| " + ИмяТаблицы + " КАК Док
|ГДЕ
| НЕ Док.ПометкаУдаления
| И Док.Номер = &Номер
|
|УПОРЯДОЧИТЬ ПО
| Док.Дата УБЫВ";
Запрос.УстановитьПараметр("Номер", Штрихкод);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Ссылки.Добавить(Выборка.Ссылка);
КонецЦикла;
КонецЕсли;
Возврат Ссылки;
КонецФункции
Функция НайтиДокументПоНомеруИлиШК(НомерИлиШтрихкод, ТипДокумента = "ЗаказКлиента") Экспорт
Ссылки = НайтиСсылкиДокументаПоНомеруИлиШК(НомерИлиШтрихкод, ТипДокумента);
Если Ссылки.Количество() > 0 Тогда
Возврат Ссылки[0];
КонецЕсли;
ТипДокументаНорм = НормализоватьТипДокументаЗагрузки(ТипДокумента);
Если ТипДокументаНорм = "ПоступлениеТоваровУслуг" Тогда
Возврат Документы.ПоступлениеТоваровИУслуг.ПустаяСсылка();
КонецЕсли;
Возврат Документы.ЗаказКлиента.ПустаяСсылка();
КонецФункции
Функция НайтиСсылкиПоступленияПоНомеруИлиШК(НомерИлиШтрихкод) Экспорт
Возврат НайтиСсылкиДокументаПоНомеруИлиШК(НомерИлиШтрихкод, "ПоступлениеТоваровУслуг");
КонецФункции
Функция НайтиПоступлениеПоШтрихкоду(НомерИлиШтрихкод) Экспорт
Возврат НайтиДокументПоНомеруИлиШК(НомерИлиШтрихкод, "ПоступлениеТоваровУслуг");
КонецФункции
Функция НормализоватьШтрихкодДокумента(Знач Штрихкод)
Если Штрихкод = Неопределено Тогда
Возврат "";
КонецЕсли;
Результат = СокрЛП(Строка(Штрихкод));
Результат = СтрЗаменить(Результат, Символы.НПП, "");
Результат = СтрЗаменить(Результат, " ", "");
Результат = СтрЗаменить(Результат, Символы.ПС, "");
Результат = СтрЗаменить(Результат, Символы.ВК, "");
Результат = СтрЗаменить(Результат, Символы.Таб, "");
Возврат Результат;
КонецФункции
Функция ОбщегоНазначенияСсылкаСуществует(Ссылка)
Если Не ЗначениеЗаполнено(Ссылка) Тогда
Возврат Ложь;
КонецЕсли;
Возврат Ссылка.ПолучитьОбъект() <> Неопределено;
КонецФункции
Функция ИзвлечьДокументXDTO(ОбXDTO, ТипДокумента = "")
Если ОбXDTO = Неопределено Тогда
Возврат ОбXDTO;
КонецЕсли;
Если СвойствоXDTO(ОбXDTO, "КлючевыеСвойства") <> Неопределено Тогда
Возврат ОбXDTO;
КонецЕсли;
ИменаУзлов = Новый Массив;
ТипДокументаНорм = НормализоватьТипДокументаЗагрузки(ТипДокумента);
Если ТипДокументаНорм = "ПоступлениеТоваровУслуг" Тогда
ИменаУзлов.Добавить("Документ.ПоступлениеТоваровУслуг");
ИменаУзлов.Добавить("Документ.ПоступлениеТоваровИУслуг");
ИменаУзлов.Добавить("ПоступлениеТоваровУслуг");
ИменаУзлов.Добавить("ПоступлениеТоваровИУслуг");
ИначеЕсли ТипДокументаНорм = "ЗаказКлиента" Тогда
ИменаУзлов.Добавить("Документ.ЗаказКлиента");
ИменаУзлов.Добавить("ЗаказКлиента");
Иначе
// Авто: сначала поступление, затем заказ (чтобы не перепутать вложенный узел)
ИменаУзлов.Добавить("Документ.ПоступлениеТоваровУслуг");
ИменаУзлов.Добавить("Документ.ПоступлениеТоваровИУслуг");
ИменаУзлов.Добавить("ПоступлениеТоваровУслуг");
ИменаУзлов.Добавить("ПоступлениеТоваровИУслуг");
ИменаУзлов.Добавить("Документ.ЗаказКлиента");
ИменаУзлов.Добавить("ЗаказКлиента");
КонецЕсли;
Для Каждого ИмяУзла Из ИменаУзлов Цикл
Вложенный = СвойствоXDTO(ОбXDTO, ИмяУзла);
Если Вложенный <> Неопределено Тогда
Возврат Вложенный;
КонецЕсли;
КонецЦикла;
Возврат ОбXDTO;
КонецФункции
// Определяет фактический тип документа в ответе getDoc (по имени узла / типу XDTO).
// Серии/марки для определения типа не используем.
//
Функция ОпределитьТипДокументаИзОтветаXDTO(ОбXDTO)
Если ОбXDTO = Неопределено Тогда
Возврат "";
КонецЕсли;
// 1) Вложенный узел явного типа
УзлыПоступления = Новый Массив;
УзлыПоступления.Добавить("Документ.ПоступлениеТоваровУслуг");
УзлыПоступления.Добавить("Документ.ПоступлениеТоваровИУслуг");
УзлыПоступления.Добавить("ПоступлениеТоваровУслуг");
УзлыПоступления.Добавить("ПоступлениеТоваровИУслуг");
Для Каждого ИмяУзла Из УзлыПоступления Цикл
Если СвойствоXDTO(ОбXDTO, ИмяУзла) <> Неопределено Тогда
Возврат "ПоступлениеТоваровУслуг";
КонецЕсли;
КонецЦикла;
УзлыЗаказа = Новый Массив;
УзлыЗаказа.Добавить("Документ.ЗаказКлиента");
УзлыЗаказа.Добавить("ЗаказКлиента");
Для Каждого ИмяУзла Из УзлыЗаказа Цикл
Если СвойствоXDTO(ОбXDTO, ИмяУзла) <> Неопределено Тогда
Возврат "ЗаказКлиента";
КонецЕсли;
КонецЦикла;
// 2) Имя типа самого XDTO-объекта
ТипПоИмени = ТипДокументаПоИмениXDTO(ОбXDTO);
Если ЗначениеЗаполнено(ТипПоИмени) Тогда
Возврат ТипПоИмени;
КонецЕсли;
// 3) Тип узла КлючевыеСвойства (КлючевыеСвойстваЗаказКлиента / ...Поступление...)
КлючевыеСвойства = СвойствоXDTO(ОбXDTO, "КлючевыеСвойства");
Если КлючевыеСвойства <> Неопределено Тогда
ТипПоКС = ТипДокументаПоИмениXDTO(КлючевыеСвойства);
Если ЗначениеЗаполнено(ТипПоКС) Тогда
Возврат ТипПоКС;
КонецЕсли;
// 4) GUID уже есть локально как заказ или поступление
СсылкаСтрока = НормализоватьИдентификаторСсылкиXDTO(СвойствоXDTO(КлючевыеСвойства, "Ссылка", ""));
Если ЗначениеЗаполнено(СсылкаСтрока) Тогда
Попытка
СсылкаЗаказа = Документы.ЗаказКлиента.ПолучитьСсылку(Новый УникальныйИдентификатор(СсылкаСтрока));
Если ДокументСсылкаСуществует(СсылкаЗаказа) Тогда
Возврат "ЗаказКлиента";
КонецЕсли;
Исключение
КонецПопытки;
Попытка
СсылкаПоступления = Документы.ПоступлениеТоваровИУслуг.ПолучитьСсылку(
Новый УникальныйИдентификатор(СсылкаСтрока));
Если ДокументСсылкаСуществует(СсылкаПоступления) Тогда
Возврат "ПоступлениеТоваровУслуг";
КонецЕсли;
Исключение
КонецПопытки;
КонецЕсли;
КонецЕсли;
Возврат "";
КонецФункции
Функция ТипДокументаПоИмениXDTO(ОбъектXDTO)
ИмяТипа = "";
Попытка
ИмяТипа = Строка(ОбъектXDTO.Тип().Имя);
Исключение
Возврат "";
КонецПопытки;
ИмяВРег = ВРег(ИмяТипа);
Если СтрНайти(ИмяВРег, "ПОСТУПЛЕНИЕ") > 0
Или СтрНайти(ИмяВРег, "ПРИОБРЕТЕНИЕ") > 0 Тогда
Возврат "ПоступлениеТоваровУслуг";
ИначеЕсли СтрНайти(ИмяВРег, "ЗАКАЗКЛИЕНТА") > 0 Тогда
Возврат "ЗаказКлиента";
КонецЕсли;
Возврат "";
КонецФункции
// Если в ТСД уже есть документ другого типа с тем же GUID — вернуть его тип.
// Номер не сравниваем: у заказа и поступления номера могут совпадать.
//
Функция НайтиКонфликтТипаДокумента(СсылкаСтрока, НомерДокумента, ОжидаемыйТип)
Если Не ЗначениеЗаполнено(СсылкаСтрока) Тогда
Возврат "";
КонецЕсли;
ОжидаемыйТипНорм = НормализоватьТипДокументаЗагрузки(ОжидаемыйТип);
ДругойТип = ?(ОжидаемыйТипНорм = "ПоступлениеТоваровУслуг",
"ЗаказКлиента", "ПоступлениеТоваровУслуг");
МенеджерДругого = ?(ДругойТип = "ПоступлениеТоваровУслуг",
Документы.ПоступлениеТоваровИУслуг, Документы.ЗаказКлиента);
Попытка
СсылкаДругого = МенеджерДругого.ПолучитьСсылку(Новый УникальныйИдентификатор(СсылкаСтрока));
Если ДокументСсылкаСуществует(СсылкаДругого) Тогда
Возврат ДругойТип;
КонецЕсли;
Исключение
КонецПопытки;
Возврат "";
КонецФункции
Функция ИзвлечьДокументПоступленияXDTO(ОбXDTO)
Возврат ИзвлечьДокументXDTO(ОбXDTO, "ПоступлениеТоваровУслуг");
КонецФункции
Процедура ЗаполнитьТабличныеЧастиДокументаИзXDTO(ДокОбъект, ОбXDTO, ЭтоПоступление, ЭтоОбновлениеЗаказа)
СохраненноеОтсканировано = Неопределено;
Если ЭтоОбновлениеЗаказа Тогда
СохраненноеОтсканировано = СохранитьОтсканированоТоваров(ДокОбъект);
КонецЕсли;
ДокОбъект.Товары.Очистить();
ЗаполнитьТоварыДокументаИзXDTO(ДокОбъект, ОбXDTO, ЭтоПоступление);
Если ЭтоОбновлениеЗаказа Тогда
// При обновлении заказа из УТ11 не трогаем локальные КМ и партии.
ВосстановитьОтсканированоТоваров(ДокОбъект, СохраненноеОтсканировано);
Возврат;
КонецЕсли;
Если ДокОбъект.Метаданные().ТабличныеЧасти.Найти("Партии") <> Неопределено Тогда
ДокОбъект.Партии.Очистить();
КонецЕсли;
Если ДокОбъект.Метаданные().ТабличныеЧасти.Найти("КодыМаркировки") <> Неопределено Тогда
ДокОбъект.КодыМаркировки.Очистить();
ЗаполнитьМаркиДокументаИзXDTO(ДокОбъект, ОбXDTO);
КонецЕсли;
КонецПроцедуры
Функция СохранитьОтсканированоТоваров(ДокОбъект)
Результат = Новый Соответствие;
Если ДокОбъект.Метаданные().ТабличныеЧасти.Товары.Реквизиты.Найти("Отсканировано") = Неопределено Тогда
Возврат Результат;
КонецЕсли;
Для Каждого СтрокаТовара Из ДокОбъект.Товары Цикл
Текущее = Результат.Получить(СтрокаТовара.Номенклатура);
Если Текущее = Неопределено Тогда
Текущее = 0;
КонецЕсли;
Результат.Вставить(СтрокаТовара.Номенклатура, Текущее + СтрокаТовара.Отсканировано);
КонецЦикла;
Возврат Результат;
КонецФункции
Процедура ВосстановитьОтсканированоТоваров(ДокОбъект, СохраненноеОтсканировано)
Если СохраненноеОтсканировано = Неопределено Тогда
Возврат;
КонецЕсли;
Если ДокОбъект.Метаданные().ТабличныеЧасти.Товары.Реквизиты.Найти("Отсканировано") = Неопределено Тогда
Возврат;
КонецЕсли;
Обработанные = Новый Соответствие;
Для Каждого СтрокаТовара Из ДокОбъект.Товары Цикл
Если Обработанные.Получить(СтрокаТовара.Номенклатура) = Истина Тогда
Продолжить;
КонецЕсли;
Обработанные.Вставить(СтрокаТовара.Номенклатура, Истина);
Остаток = СохраненноеОтсканировано.Получить(СтрокаТовара.Номенклатура);
Если Остаток = Неопределено Тогда
Остаток = 0;
КонецЕсли;
Для Каждого СтрокаНоменклатуры Из ДокОбъект.Товары.НайтиСтроки(Новый Структура("Номенклатура", СтрокаТовара.Номенклатура)) Цикл
Если Остаток <= 0 Тогда
СтрокаНоменклатуры.Отсканировано = 0;
Продолжить;
КонецЕсли;
ВСтроку = Мин(СтрокаНоменклатуры.Количество, Остаток);
СтрокаНоменклатуры.Отсканировано = ВСтроку;
Остаток = Остаток - ВСтроку;
КонецЦикла;
КонецЦикла;
КонецПроцедуры
Процедура ЗаполнитьТоварыДокументаИзXDTO(ДокОбъект, ОбXDTO, ЭтоПоступление = Ложь)
ТоварыXDTO = СвойствоXDTO(ОбXDTO, "Товары");
Если ТоварыXDTO = Неопределено Тогда
Возврат;
КонецЕсли;
ЕстьОтсканировано = (ДокОбъект.Метаданные().ТабличныеЧасти.Товары.Реквизиты.Найти("Отсканировано") <> Неопределено);
Для Каждого СтрокаXDTO Из СтрокиТаблицыXDTO(ТоварыXDTO) Цикл
СтрокаТовара = ДокОбъект.Товары.Добавить();
СтрокаТовара.Номенклатура = НайтиСоздатьНоменклатуруИзXDTO(СтрокаXDTO);
СтрокаТовара.Количество = ЧислоИзXDTO(СвойствоXDTO(СтрокаXDTO, "Количество", 0));
Если ЕстьОтсканировано Тогда
СтрокаТовара.Отсканировано = ЧислоИзXDTO(СвойствоXDTO(СтрокаXDTO, "Отсканировано", 0));
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Процедура ЗаполнитьТоварыПоступленияИзXDTO(ДокОбъект, ОбXDTO)
ЗаполнитьТоварыДокументаИзXDTO(ДокОбъект, ОбXDTO, Истина);
КонецПроцедуры
Процедура ЗаполнитьМаркиДокументаИзXDTO(ДокОбъект, ОбXDTO)
МаркиXDTO = СвойствоXDTO(ОбXDTO, "Марки");
Если МаркиXDTO = Неопределено Тогда
Возврат;
КонецЕсли;
Для Каждого СтрокаXDTO Из СтрокиТаблицыXDTO(МаркиXDTO) Цикл
СтрокаМарки = ДокОбъект.КодыМаркировки.Добавить();
СтрокаМарки.Номенклатура = НайтиСоздатьНоменклатуруИзXDTO(СтрокаXDTO, Ложь);
КодМарки = СвойствоXDTO(СтрокаXDTO, "Код", "");
Попытка
СтрокаМарки.Код = ДекодироватьСтрокуВBase64(Строка(КодМарки));
Исключение
СтрокаМарки.Код = Строка(КодМарки);
КонецПопытки;
НомерСтроки = СвойствоXDTO(СтрокаXDTO, "НомерСтрокиДокумента");
Если ЗначениеЗаполнено(НомерСтроки) Тогда
СтрокаМарки.Строка = ЧислоИзXDTO(НомерСтроки);
Иначе
НайденныеСтроки = ДокОбъект.Товары.НайтиСтроки(Новый Структура("Номенклатура", СтрокаМарки.Номенклатура));
Если НайденныеСтроки.Количество() > 0 Тогда
СтрокаМарки.Строка = НайденныеСтроки[0].НомерСтроки;
КонецЕсли;
КонецЕсли;
Если ДокОбъект.Метаданные().ТабличныеЧасти.КодыМаркировки.Реквизиты.Найти("Упаковка") <> Неопределено Тогда
СтрокаМарки.Упаковка = ЧислоИзXDTO(СвойствоXDTO(СтрокаXDTO, "ВУпаковке",
СвойствоXDTO(СтрокаXDTO, "Упаковка", 0)));
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Функция ДекодироватьСтрокуВBase64(Знач Строка64) Экспорт
ДвоичныеДанные = Base64Значение(Строка64);
ВременныйФайл = ПолучитьИмяВременногоФайла();
ДвоичныеДанные.Записать(ВременныйФайл);
ЧтениеТекста = Новый ЧтениеТекста(ВременныйФайл, "UTF8");
Результат = ЧтениеТекста.Прочитать();
ЧтениеТекста.Закрыть();
Возврат Результат;
КонецФункции
Функция НайтиСоздатьПартнерИзXDTO(ОбXDTO)
Контрагент = СвойствоXDTO(ОбXDTO, "Контрагент");
Если Контрагент = Неопределено Тогда
Контрагент = СвойствоXDTO(ОбXDTO, "Партнер");
КонецЕсли;
Если Контрагент = Неопределено Тогда
Возврат Справочники.Партнеры.ПустаяСсылка();
КонецЕсли;
СсылкаСтрока = Строка(СвойствоXDTO(Контрагент, "Ссылка", ""));
Если Не ЗначениеЗаполнено(СсылкаСтрока) Тогда
Возврат Справочники.Партнеры.ПустаяСсылка();
КонецЕсли;
ПартнерСсылка = Справочники.Партнеры.ПолучитьСсылку(Новый УникальныйИдентификатор(СсылкаСтрока));
ПартнерОбъект = ПартнерСсылка.ПолучитьОбъект();
Если ПартнерОбъект = Неопределено Тогда
ПартнерОбъект = Справочники.Партнеры.СоздатьЭлемент();
ПартнерОбъект.УстановитьСсылкуНового(ПартнерСсылка);
КонецЕсли;
Наименование = СвойствоXDTO(Контрагент, "Наименование");
Если ЗначениеЗаполнено(Наименование) Тогда
ПартнерОбъект.Наименование = Строка(Наименование);
КонецЕсли;
ПартнерОбъект.Записать();
Возврат ПартнерОбъект.Ссылка;
КонецФункции
Функция НайтиСоздатьНоменклатуруИзXDTO(СтрокаXDTO, Создавать = Истина)
ДанныеНоменклатуры = СвойствоXDTO(СтрокаXDTO, "ДанныеНоменклатуры");
НоменклатураXDTO = Неопределено;
Если ДанныеНоменклатуры <> Неопределено Тогда
НоменклатураXDTO = СвойствоXDTO(ДанныеНоменклатуры, "Номенклатура");
КонецЕсли;
Если НоменклатураXDTO = Неопределено Тогда
НоменклатураXDTO = СвойствоXDTO(СтрокаXDTO, "Номенклатура");
КонецЕсли;
Если НоменклатураXDTO = Неопределено Тогда
Возврат Справочники.Номенклатура.ПустаяСсылка();
КонецЕсли;
СсылкаСтрока = Строка(СвойствоXDTO(НоменклатураXDTO, "Ссылка", ""));
Если Не ЗначениеЗаполнено(СсылкаСтрока) Тогда
Возврат Справочники.Номенклатура.ПустаяСсылка();
КонецЕсли;
НоменклатураСсылка = Справочники.Номенклатура.ПолучитьСсылку(Новый УникальныйИдентификатор(СсылкаСтрока));
НоменклатураОбъект = НоменклатураСсылка.ПолучитьОбъект();
Если НоменклатураОбъект = Неопределено Тогда
Если Не Создавать Тогда
Возврат Справочники.Номенклатура.ПустаяСсылка();
КонецЕсли;
НоменклатураОбъект = Справочники.Номенклатура.СоздатьЭлемент();
НоменклатураОбъект.УстановитьСсылкуНового(НоменклатураСсылка);
ИначеЕсли Не Создавать Тогда
Возврат НоменклатураОбъект.Ссылка;
КонецЕсли;
Наименование = СвойствоXDTO(НоменклатураXDTO, "Наименование");
Если ЗначениеЗаполнено(Наименование) Тогда
НоменклатураОбъект.Наименование = Строка(Наименование);
КонецЕсли;
Код = Неопределено;
Если ДанныеНоменклатуры <> Неопределено Тогда
Код = СвойствоXDTO(ДанныеНоменклатуры, "Код");
КонецЕсли;
Если Не ЗначениеЗаполнено(Код) Тогда
Код = СвойствоXDTO(НоменклатураXDTO, "КодВПрограмме",
СвойствоXDTO(НоменклатураXDTO, "Код"));
КонецЕсли;
Если ЗначениеЗаполнено(Код) Тогда
НоменклатураОбъект.Код = Строка(Код);
КонецЕсли;
Если ДанныеНоменклатуры <> Неопределено Тогда
ТоварнаяКатегория = ТоварнаяКатегорияИзXDTO(ДанныеНоменклатуры, НоменклатураXDTO);
Если ТоварнаяКатегория = "" Тогда
ТоварнаяКатегория = "Не используется";
КонецЕсли;
НоменклатураОбъект.ТоварнаяКатегория = ТоварнаяКатегория;
Штрихкод = СвойствоXDTO(ДанныеНоменклатуры, "Штрихкод");
Если Не ЗначениеЗаполнено(Штрихкод) Тогда
Штрихкод = СвойствоXDTO(ДанныеНоменклатуры, "ШтрихКод");
КонецЕсли;
Если ЗначениеЗаполнено(Штрихкод) Тогда
НоменклатураОбъект.Штрихкод = Лев(Строка(Штрихкод), 20);
КонецЕсли;
SKU = СвойствоXDTO(ДанныеНоменклатуры, "SKU");
Если SKU <> Неопределено Тогда
НоменклатураОбъект.ИспользуетСерии = БулевоИзXDTO(SKU);
КонецЕсли;
КонецЕсли;
НоменклатураОбъект.Записать();
Если ДанныеНоменклатуры <> Неопределено Тогда
ЗаписатьШтрихкодыУпаковокИзXDTO(НоменклатураОбъект.Ссылка, ДанныеНоменклатуры);
КонецЕсли;
Возврат НоменклатураОбъект.Ссылка;
КонецФункции
Процедура ЗаписатьШтрихкодыУпаковокИзXDTO(НоменклатураСсылка, ДанныеНоменклатуры)
УдалитьШтрихкодыУпаковокНоменклатуры(НоменклатураСсылка);
ЗаписанныеШтрихкоды = Новый Соответствие;
Штрихкод = СвойствоXDTO(ДанныеНоменклатуры, "Штрихкод");
Если Не ЗначениеЗаполнено(Штрихкод) Тогда
Штрихкод = СвойствоXDTO(ДанныеНоменклатуры, "ШтрихКод");
КонецЕсли;
Если ЗначениеЗаполнено(Штрихкод) И Строка(Штрихкод) <> "не установлен" Тогда
ЗаписатьШтрихкодУпаковкиНоменклатуры(НоменклатураСсылка, Строка(Штрихкод), 1, ЗаписанныеШтрихкоды);
КонецЕсли;
Упаковки = СвойствоXDTO(ДанныеНоменклатуры, "Упаковки");
Если Упаковки = Неопределено Тогда
Возврат;
КонецЕсли;
Для Каждого СтрокаУпаковки Из СтрокиТаблицыXDTO(Упаковки) Цикл
Штрихкод = СвойствоXDTO(СтрокаУпаковки, "Штрихкод");
Если Не ЗначениеЗаполнено(Штрихкод) Тогда
Штрихкод = СвойствоXDTO(СтрокаУпаковки, "ШтрихКод");
КонецЕсли;
Если Не ЗначениеЗаполнено(Штрихкод) Тогда
Продолжить;
КонецЕсли;
Количество = ЧислоИзXDTO(СвойствоXDTO(СтрокаУпаковки, "Количество", 0));
Если Количество <= 0 Тогда
Количество = 1;
КонецЕсли;
ЗаписатьШтрихкодУпаковкиНоменклатуры(НоменклатураСсылка, Строка(Штрихкод), Количество, ЗаписанныеШтрихкоды);
КонецЦикла;
КонецПроцедуры
Процедура УдалитьШтрихкодыУпаковокНоменклатуры(НоменклатураСсылка)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ШтрихкодыУпаковок.Штрихкод КАК Штрихкод
|ИЗ
| РегистрСведений.ШтрихкодыУпаковок КАК ШтрихкодыУпаковок
|ГДЕ
| ШтрихкодыУпаковок.Номенклатура = &Номенклатура";
Запрос.УстановитьПараметр("Номенклатура", НоменклатураСсылка);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
НаборШК = РегистрыСведений.ШтрихкодыУпаковок.СоздатьМенеджерЗаписи();
НаборШК.Штрихкод = Выборка.Штрихкод;
НаборШК.Удалить();
КонецЦикла;
КонецПроцедуры
Процедура ЗаписатьШтрихкодУпаковкиНоменклатуры(НоменклатураСсылка, Штрихкод, Количество, ЗаписанныеШтрихкоды)
Если ЗаписанныеШтрихкоды.Получить(Штрихкод) <> Неопределено Тогда
Возврат;
КонецЕсли;
НаборШК = РегистрыСведений.ШтрихкодыУпаковок.СоздатьМенеджерЗаписи();
НаборШК.Номенклатура = НоменклатураСсылка;
НаборШК.Штрихкод = Штрихкод;
НаборШК.Количество = Количество;
НаборШК.Записать(Истина);
ЗаписанныеШтрихкоды.Вставить(Штрихкод, Истина);
КонецПроцедуры
Функция СтрокиТаблицыXDTO(ТаблицаXDTO)
Результат = Новый Массив;
Если ТаблицаXDTO = Неопределено Тогда
Возврат Результат;
КонецЕсли;
СтрокаXDTO = СвойствоXDTO(ТаблицаXDTO, "Строка");
Если СтрокаXDTO = Неопределено Тогда
Возврат Результат;
КонецЕсли;
Если ТипЗнч(СтрокаXDTO) = Тип("СписокXDTO") Тогда
Для Каждого Элемент Из СтрокаXDTO Цикл
Результат.Добавить(Элемент);
КонецЦикла;
Иначе
Результат.Добавить(СтрокаXDTO);
КонецЕсли;
Возврат Результат;
КонецФункции
Функция СвойствоXDTO(ОбъектXDTO, ИмяСвойства, ЗначениеПоУмолчанию = Неопределено)
Если ОбъектXDTO = Неопределено Тогда
Возврат ЗначениеПоУмолчанию;
КонецЕсли;
Попытка
Если ОбъектXDTO.Свойства().Получить(ИмяСвойства) = Неопределено Тогда
Возврат ЗначениеПоУмолчанию;
КонецЕсли;
Значение = ОбъектXDTO[ИмяСвойства];
Исключение
Возврат ЗначениеПоУмолчанию;
КонецПопытки;
Если Значение = Неопределено Тогда
Возврат ЗначениеПоУмолчанию;
КонецЕсли;
Возврат Значение;
КонецФункции
Функция ДатаИзСтрокиXDTO(ЗначениеДаты)
Если Не ЗначениеЗаполнено(ЗначениеДаты) Тогда
Возврат '00010101';
КонецЕсли;
Если ТипЗнч(ЗначениеДаты) = Тип("Дата") Тогда
Возврат ЗначениеДаты;
КонецЕсли;
СтрокаДаты = Строка(ЗначениеДаты);
СтрокаДаты = СтрЗаменить(СтрокаДаты, "T", "");
СтрокаДаты = СтрЗаменить(СтрокаДаты, "-", "");
СтрокаДаты = СтрЗаменить(СтрокаДаты, ":", "");
СтрокаДаты = СтрЗаменить(СтрокаДаты, " ", "");
Попытка
Возврат Дата(СтрокаДаты);
Исключение
Возврат '00010101';
КонецПопытки;
КонецФункции
Функция ЧислоИзXDTO(Значение)
Если Значение = Неопределено Или Значение = Null Тогда
Возврат 0;
КонецЕсли;
Попытка
Возврат Число(Значение);
Исключение
Возврат 0;
КонецПопытки;
КонецФункции
Функция БулевоИзXDTO(Значение)
Если ТипЗнч(Значение) = Тип("Булево") Тогда
Возврат Значение;
КонецЕсли;
СтрокаЗначения = НРег(СокрЛП(Строка(Значение)));
Возврат СтрокаЗначения = "true"
Или СтрокаЗначения = "истина"
Или СтрокаЗначения = "1"
Или СтрокаЗначения = "yes";
КонецФункции