Загрузка данных
&НаСервере
Функция ФорматироватьДатуДляЭТРАН(ДатаЗнач)
// Формируем дату в формате dd.MM.yyyy HH:mm:ss
// Используем Формат с точным указанием разделителей
Возврат Формат(ДатаЗнач, "ДФ='dd.MM.yyyy HH:mm:ss'");
КонецФункции
&НаСервере
Функция ДекодироватьHTML(Текст)
Если ПустаяСтрока(Текст) Тогда
Возврат Текст;
КонецЕсли;
Текст = СтрЗаменить(Текст, """, Символ(34));
Текст = СтрЗаменить(Текст, "'", Символ(39));
Текст = СтрЗаменить(Текст, "&", "&");
Текст = СтрЗаменить(Текст, "<", "<");
Текст = СтрЗаменить(Текст, ">", ">");
Текст = СокрЛП(Текст);
Возврат Текст;
КонецФункции
&НаСервере
Функция ПолучитьСписокНакладныхВПути(ДатаС, ДатаПо) Экспорт
Результат = Новый Массив;
АдресСервера = "10.10.100.4";
Порт = 5055;
// Форматируем даты БЕЗ кодирования
СтрокаДатаС = ФорматироватьДатуДляЭТРАН(ДатаС);
СтрокаДатаПо = ФорматироватьДатуДляЭТРАН(ДатаПо);
// Формируем URL напрямую, без замены пробелов и двоеточий
//URL = "http://" + АдресСервера + ":" + Формат(Порт, "ЧГ=0") + "/getBlockInvoiceStatus";
URL = "/getBlockInvoiceStatus";
URL = URL + "?fromDate=" + СтрокаДатаС;
URL = URL + "&toDate=" + СтрокаДатаПо;
ЗаписьЖурналаРегистрации("ЗагрузкаЭтран", УровеньЖурналаРегистрации.Информация, , ,
"URL запроса: " + URL);
// HTTP-запрос
Попытка
HTTPСоединение = Новый HTTPСоединение(АдресСервера, Порт, , , , 60);
HTTPЗапрос = Новый HTTPЗапрос(URL);
HTTPОтвет = HTTPСоединение.Получить(HTTPЗапрос);
Если HTTPОтвет.КодСостояния = 200 Тогда
XMLСтрока = HTTPОтвет.ПолучитьТелоКакСтроку();
ЗаписьЖурналаРегистрации("ЗагрузкаЭтран", УровеньЖурналаРегистрации.Информация, , ,
"Получен ответ, длина: " + СтрДлина(XMLСтрока));
Результат = РаспарситьСписокНакладныхВПути(XMLСтрока);
Иначе
ЗаписьЖурналаРегистрации("ЗагрузкаЭтран", УровеньЖурналаРегистрации.Ошибка, , ,
"Ошибка HTTP: " + HTTPОтвет.КодСостояния);
КонецЕсли;
Исключение
ЗаписьЖурналаРегистрации("ЗагрузкаЭтран", УровеньЖурналаРегистрации.Ошибка, , ,
"Ошибка соединения: " + ОписаниеОшибки());
КонецПопытки;
Возврат Результат;
КонецФункции
&НаСервере
Функция РаспарситьСписокНакладныхВПути(XMLСтрока) Экспорт
Результат = Новый Массив;
Чтение = Новый ЧтениеXML;
Попытка
Чтение.УстановитьСтроку(XMLСтрока);
Пока Чтение.Прочитать() Цикл
ИмяУзла = ВРег(Чтение.Имя);
// Нашли начало блока накладной
Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента И ИмяУзла = "INVOICE" Тогда
Ид = "";
Ном = "";
// Читаем внутренние теги накладной
Пока Чтение.Прочитать() Цикл
ТекущееИмя = ВРег(Чтение.Имя);
// Выход из накладной
Если Чтение.ТипУзла = ТипУзлаXML.КонецЭлемента И ТекущееИмя = "INVOICE" Тогда
Прервать;
КонецЕсли;
// Нас интересуют только начала элементов (invoiceID, invNumber)
Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
// Ищем атрибут "value" у текущего тега
ЗначениеАтрибута = Чтение.ПолучитьАтрибут("value");
Если ТекущееИмя = "INVOICEID" Тогда
Ид = ЗначениеАтрибута;
// Убираем разделители тысяч (запятые)
Ид = СтрЗаменить(Ид, ",", "");
ИначеЕсли ТекущееИмя = "INVNUMBER" Тогда
Ном = ЗначениеАтрибута;
КонецЕсли;
КонецЕсли;
КонецЦикла;
Если ЗначениеЗаполнено(Ид) Тогда
Результат.Добавить(Новый Структура("InvoiceID, InvNumber", Ид, Ном));
КонецЕсли;
КонецЕсли;
КонецЦикла;
Исключение
ЗаписьЖурналаРегистрации("ЗагрузкаЭтран", УровеньЖурналаРегистрации.Ошибка, , ,
"Ошибка парсинга: " + ОписаниеОшибки());
КонецПопытки;
ЗаписьЖурналаРегистрации("ЗагрузкаЭтран", УровеньЖурналаРегистрации.Информация, , ,
"Парсинг завершен. Найдено: " + Результат.Количество());
Возврат Результат;
КонецФункции
&НаСервере
Функция ПолучитьСписокИспорченныхНакладных(ДатаС, ДатаПо) Экспорт
Результат = Новый Массив;
АдресСервера = "10.10.100.4";
Порт = 5055;
// Формируем даты
СтрокаДатаС = ФорматироватьДатуДляЭТРАН(ДатаС);
СтрокаДатаПо = ФорматироватьДатуДляЭТРАН(ДатаПо);
// Формируем URL для испорченных накладных
URL = "/getBlockInvoiceStatusSpoil";
URL = URL + "?fromDate=" + СтрокаДатаС;
URL = URL + "&toDate=" + СтрокаДатаПо;
//URL = "/getBlockInvoiceStatusSpent?fromDate=" + СтрокаДатаС + "&toDate=" + СтрокаДатаПо;
ЗаписьЖурналаРегистрации("ЗагрузкаЭтран", УровеньЖурналаРегистрации.Информация, , ,
"URL (испорченные): " + URL);
Попытка
HTTPСоединение = Новый HTTPСоединение(АдресСервера, Порт, , , , 60);
HTTPЗапрос = Новый HTTPЗапрос(URL);
HTTPОтвет = HTTPСоединение.Получить(HTTPЗапрос);
Если HTTPОтвет.КодСостояния = 200 Тогда
XMLСтрока = HTTPОтвет.ПолучитьТелоКакСтроку();
Если СтрДлина(XMLСтрока) > 150 Тогда
ЗаписьЖурналаРегистрации("ЗагрузкаЭтран", УровеньЖурналаРегистрации.Информация, , ,
"Получен ответ (испорченные), длина: " + СтрДлина(XMLСтрока) + " байт");
Результат = РаспарситьСписокИспорченныхНакладных(XMLСтрока);
КонецЕсли;
Иначе
ЗаписьЖурналаРегистрации("ЗагрузкаЭтран", УровеньЖурналаРегистрации.Ошибка, , ,
"Ошибка HTTP (испорченные): " + HTTPОтвет.КодСостояния);
КонецЕсли;
Исключение
ЗаписьЖурналаРегистрации("ЗагрузкаЭтран", УровеньЖурналаРегистрации.Ошибка, , ,
"Ошибка соединения (испорченные): " + ОписаниеОшибки());
КонецПопытки;
Возврат Результат;
КонецФункции
&НаСервере
Процедура РаспарситьПолнуюНакладнуюВДокумент(Документ, XMLСтрока) Экспорт
// 1. Очистка табличной части
Документ.ДанныеНакладной.Очистить();
Чтение = Новый ЧтениеXML;
Чтение.УстановитьСтроку(XMLСтрока);
ТекущийВагон = Неопределено;
Пока Чтение.Прочитать() Цикл
ТипУзла = Чтение.ТипУзла;
ИмяТега = ВРег(Чтение.Имя);
Если ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
// Получаем значение из атрибута value
Значение = Чтение.ПолучитьАтрибут("value");
// --- ШАПКА ДОКУМЕНТА ---
Если ИмяТега = "INVNUMBER" Тогда Документ.InvNumber = Значение;
ИначеЕсли ИмяТега = "INVOICESTATE" Тогда Документ.InvoiceState = Значение;
ИначеЕсли ИмяТега = "INVOICESTATEID" Тогда Документ.InvoiceStateID = Значение;
ИначеЕсли ИмяТега = "INVDATECREATE" Тогда Документ.InvDateCreate = ДатаИзЭтрана(Значение);
ИначеЕсли ИмяТега = "INVDATELOAD" Тогда Документ.InvDateLoad = ДатаИзЭтрана(Значение);
ИначеЕсли ИмяТега = "INVSENDERNAME" Тогда
Документ.InvSenderName = ?(ЗначениеЗаполнено(Значение), ДекодироватьHTML(Значение), "");
ИначеЕсли ИмяТега = "INVFROMSTATIONNAME" Тогда Документ.InvFromStationName = ДекодироватьHTML(Значение);
ИначеЕсли ИмяТега = "FREIGHTNAME" Тогда Документ.FreightName = ДекодироватьHTML(Значение);
ИначеЕсли ИмяТега = "INVFACTDATETOLOAD" Тогда Документ.InvFactDateToLoad = ДатаИзЭтрана (Значение);
ИначеЕсли ИмяТега = "INVDATEEXPIRE" Тогда Документ.InvDateExpire = ДатаИзЭтрана (Значение);
ИначеЕсли ИмяТега = "INVSENDERID" Тогда Документ.InvSenderID = Значение;
ИначеЕсли ИмяТега = "INVFROMSTATIONCODE" Тогда Документ.InvFromStationCode = Значение;
ИначеЕсли ИмяТега = "FREIGHTCODE" Тогда Документ.FreightCode = Значение;
ИначеЕсли ИмяТега = "FREIGHTEXACTNAME" Тогда Документ.FreightExactName = ДекодироватьHTML(Значение);
ИначеЕсли ИмяТега = "INVTYPEID" Тогда Документ.InvTypeID = Значение;
ИначеЕсли ИмяТега = "INVTYPENAME" Тогда Документ.InvTypeName = ДекодироватьHTML(Значение);
ИначеЕсли ИмяТега = "INVPARENTID" Тогда Документ.ParentInvoiceID = Значение;
ИначеЕсли ИмяТега = "INVPARENTNUMBER" Тогда Документ.ParentInvNumber = Значение;
// --- ОБРАБОТКА ВАГОНОВ ---
ИначеЕсли ИмяТега = "INVCAR" Тогда
ТекущийВагон = Документ.ДанныеНакладной.Добавить();
ТекущийВагон.КоличествоЗПУ = 0;
ТекущийВагон.НомераЗПУ = "";
ИначеЕсли ТекущийВагон <> Неопределено Тогда
// Мы внутри блока <invCar>, заполняем поля текущей строки
Если ИмяТега = "CARNUMBER" Тогда ТекущийВагон.CarNumber = Значение;
ИначеЕсли ИмяТега = "CARTYPECODE" Тогда ТекущийВагон.CarTypeCode = Значение;
ИначеЕсли ИмяТега = "CARTYPENAME" Тогда ТекущийВагон.CarTypeName = ДекодироватьHTML(Значение);
ИначеЕсли ИмяТега = "CAROWNERNAME" Тогда ТекущийВагон.CarOwnerName = ДекодироватьHTML(Значение);
// Весовые показатели
ИначеЕсли ИмяТега = "CARWEIGHTDEP" Тогда
ТекущийВагон.CarTareWeight = ЧислоИзСтрокиЭТРАН(Значение);
ИначеЕсли ИмяТега = "CARWEIGHTDEPREAL" Тогда
ТекущийВагон.CarWeightDepReal = ЧислоИзСтрокиЭТРАН(Значение);
ИначеЕсли ИмяТега = "CARTONNAGE" Тогда
ТекущийВагон.CarTonnage = ЧислоИзСтрокиЭТРАН(Значение);
ИначеЕсли ИмяТега = "CARWEIGHTNET" Тогда
ТекущийВагон.CarWeightNet = ЧислоИзСтрокиЭТРАН(Значение);
ИначеЕсли ИмяТега = "CARWEIGHTGROSS" Тогда
ТекущийВагон.CarWeightGross = ЧислоИзСтрокиЭТРАН(Значение);
// ЗПУ (внутри вагона)
ИначеЕсли ИмяТега = "SEALMARKS" И ЗначениеЗаполнено(Значение) Тогда
ТекущийВагон.КоличествоЗПУ = ТекущийВагон.КоличествоЗПУ + 1;
ТекущийВагон.НомераЗПУ = ТекущийВагон.НомераЗПУ + ?(ТекущийВагон.НомераЗПУ = "", "", ", ") + Значение;
КонецЕсли;
КонецЕсли;
ИначеЕсли ТипУзла = ТипУзлаXML.КонецЭлемента И ИмяТега = "INVCAR" Тогда
// Вышли из блока вагона
ТекущийВагон = Неопределено;
КонецЕсли;
КонецЦикла;
// Признак досылочной
Документ.ЯвляетсяДосылочной = ЗначениеЗаполнено(Документ.ParentInvNumber);
Документ.Иерархия = ?(ЗначениеЗаполнено(Документ.ParentInvNumber), "→ " + Документ.ParentInvNumber, "");
//Документ.Записать();
ЗаписьЖурналаРегистрации("ЗагрузкаЭтран.Отладка", , , ,
"Парсинг завершен. Вагонов загружено: " + Документ.ДанныеНакладной.Количество());
КонецПроцедуры
&НаСервере
Функция ЧислоИзСтрокиЭТРАН(СтрокаЗнач)
Если ПустаяСтрока(СтрокаЗнач) Тогда
Возврат 0;
КонецЕсли;
Возврат Число(СтрЗаменить(СтрокаЗнач, ",", "."));
КонецФункции
&НаСервере
Функция ДатаИзЭтрана(СтрДата)
// Преобразует строку "06.05.2026 23:49:17" в дату 1С
Попытка
// Разбиваем строку по всем возможным разделителям
Части = СтрРазделить(СтрДата, " .:");
Если Части.Количество() >= 3 Тогда
// Формируем дату: Год, Месяц, День, Час, Мин, Сек
Г = Число(Части[2]);
М = Число(Части[1]);
Д = Число(Части[0]);
час = ?(Части.Количество() > 3, Число(Части[3]), 0);
мин = ?(Части.Количество() > 4, Число(Части[4]), 0);
сек = ?(Части.Количество() > 5, Число(Части[5]), 0);
Возврат Дата(Г, М, Д, час, мин, сек);
КонецЕсли;
Исключение
Возврат '00010101'; // Если дата пустая или битая
КонецПопытки;
Возврат '00010101';
КонецФункции
&НаСервере
Процедура СоздатьДокументЭтранНакладная(InvoiceID, InvNumber) Экспорт
// Проверяем, существует ли документ
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| Документ.Ссылка
|ИЗ
| Документ.ЭтранНакладная КАК Документ
|ГДЕ
| Документ.InvoiceID = &InvoiceID
| И Документ.ПометкаУдаления = ЛОЖЬ";
Запрос.УстановитьПараметр("InvoiceID", InvoiceID);
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Если Выборка.Следующий() Тогда
ЗаписьЖурналаРегистрации("ЗагрузкаЭтран", УровеньЖурналаРегистрации.Информация, , ,
"Документ уже существует: " + InvNumber);
Возврат;
КонецЕсли;
// Создаем новый документ
НовыйДокумент = Документы.ЭтранНакладная.СоздатьДокумент();
НовыйДокумент.InvoiceID = InvoiceID;
НовыйДокумент.InvNumber = InvNumber;
НовыйДокумент.Дата = ТекущаяДата();
// Загружаем XML для ОДНОЙ конкретной накладной
IPАдрес = "10.10.100.4";
ПортЧислом = 5055;
ПутьРесурса = "/getBlockInvoiceID?invoiceID=" + InvoiceID;
ЗаписьЖурналаРегистрации("ЗагрузкаЭтран.Отладка", УровеньЖурналаРегистрации.Информация, , ,
"Запрашиваем полную накладную по InvoiceID: " + InvoiceID);
ЗаписьЖурналаРегистрации("ЗагрузкаЭтран.Отладка", УровеньЖурналаРегистрации.Информация, , ,
"URL для полной накладной: " + ПутьРесурса);
Попытка
HTTPСоединение = Новый HTTPСоединение(IPАдрес, ПортЧислом, , , , 60);
HTTPЗапрос = Новый HTTPЗапрос(ПутьРесурса);
HTTPОтвет = HTTPСоединение.Получить(HTTPЗапрос);
Если HTTPОтвет.КодСостояния = 200 Тогда
Попытка
XMLСтрока = HTTPОтвет.ПолучитьТелоКакСтроку();
Если Не ПустаяСтрока(XMLСтрока) И СтрДлина(XMLСтрока) > 150 Тогда
// Парсим XML напрямую
РаспарситьПолнуюНакладнуюВДокумент(НовыйДокумент, XMLСтрока);
КонецЕсли;
Исключение
ЗаписьЖурналаРегистрации("ЗагрузкаЭтран", УровеньЖурналаРегистрации.Ошибка, , ,
"Ошибка получения тела ответа для " + InvNumber + ": " + ОписаниеОшибки());
КонецПопытки;
Иначе
ЗаписьЖурналаРегистрации("ЗагрузкаЭтран", УровеньЖурналаРегистрации.Ошибка, , ,
"Ошибка HTTP для " + InvNumber + ": " + HTTPОтвет.КодСостояния);
КонецЕсли;
Исключение
ЗаписьЖурналаРегистрации("ЗагрузкаЭтран", УровеньЖурналаРегистрации.Ошибка, , ,
"Ошибка загрузки данных для " + InvNumber + ": " + ОписаниеОшибки());
КонецПопытки;
// Запись документа
Попытка
НовыйДокумент.Записать();
ЗаписьЖурналаРегистрации("ЗагрузкаЭтран", УровеньЖурналаРегистрации.Информация, , ,
"Создан документ: " + InvNumber + ", вагонов: " + НовыйДокумент.ДанныеНакладной.Количество());
Исключение
ЗаписьЖурналаРегистрации("ЗагрузкаЭтран", УровеньЖурналаРегистрации.Ошибка, , ,
"Ошибка записи документа " + InvNumber + ": " + ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры
&НаСервере
Процедура ПометитьДокументНаУдаление(InvoiceID)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| Документ.Ссылка
|ИЗ
| Документ.ЭтранНакладная КАК Документ
|ГДЕ
| Документ.InvoiceID = &InvoiceID
| И Документ.ПометкаУдаления = ЛОЖЬ";
Запрос.УстановитьПараметр("InvoiceID", InvoiceID);
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Если Выборка.Следующий() Тогда
ДокументОбъект = Выборка.Ссылка.ПолучитьОбъект();
ДокументОбъект.УстановитьПометкуУдаления(Истина);
ДокументОбъект.Записать();
ЗаписьЖурналаРегистрации("ЗагрузкаЭтран", УровеньЖурналаРегистрации.Информация, , ,
"Документ помечен на удаление: InvoiceID " + InvoiceID);
КонецЕсли;
КонецПроцедуры
&НаСервере
Функция СоздатьНовыйДокументСпискаНакладныхВПути(ДатаНачала, ДатаОкончания) Экспорт
// 1. Проверяем, не создавали ли мы уже документ за этот точный интервал
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1 Ссылка ИЗ Документ.ЭтранСписокНакладныхВПути
|ГДЕ ДатаС = &ДатаНачала И ДатаПо = &ДатаОкончания И Проведен";
Запрос.УстановитьПараметр("ДатаНачала", ДатаНачала);
Запрос.УстановитьПараметр("ДатаОкончания", ДатаОкончания);
Если Не Запрос.Выполнить().Пустой() Тогда
ЗаписьЖурналаРегистрации("ЗагрузкаЭтран", УровеньЖурналаРегистрации.Информация, , ,
"Документ за период " + ДатаНачала + " - " + ДатаОкончания + " уже существует. Пропуск.");
Возврат Неопределено;
КонецЕсли;
// 2. Получаем данные
Накладные = ПолучитьСписокНакладныхВПути(ДатаНачала, ДатаОкончания);
Если Накладные = Неопределено Или Накладные.Количество() = 0 Тогда
ЗаписьЖурналаРегистрации("ЗагрузкаЭтран", УровеньЖурналаРегистрации.Информация, , ,
"Нет данных для создания документа за час " + Формат(ДатаНачала, "ДФ=HH:00"));
Возврат Неопределено;
КонецЕсли;
// 3. Создаем документ
НовыйДокумент = Документы.ЭтранСписокНакладныхВПути.СоздатьДокумент();
НовыйДокумент.Дата = ТекущаяДата();
НовыйДокумент.ДатаС = ДатаНачала;
НовыйДокумент.ДатаПо = ДатаОкончания;
Для Каждого Накладная Из Накладные Цикл
// Проверка на дубли внутри массива (на случай, если ЭТРАН вернул одну накладную дважды)
ПараметрыПоиска = Новый Структура("InvoiceID", Накладная.InvoiceID);
Если НовыйДокумент.СтатусыНакладных.НайтиСтроки(ПараметрыПоиска).Количество() > 0 Тогда
Продолжить;
КонецЕсли;
НоваяСтрока = НовыйДокумент.СтатусыНакладных.Добавить();
НоваяСтрока.InvoiceID = Накладная.InvoiceID;
НоваяСтрока.НомерНакладной = Накладная.InvNumber;
НоваяСтрока.Статус = "В пути";
КонецЦикла;
Попытка
НовыйДокумент.Записать(РежимЗаписиДокумента.Запись);
ЗаписьЖурналаРегистрации("ЗагрузкаЭтран", УровеньЖурналаРегистрации.Информация, , ,
"Создан документ 'В пути' за час " + Формат(ДатаНачала, "ДФ=HH:00") +
", накладных: " + НовыйДокумент.СтатусыНакладных.Количество());
// 4. Создаем детальные накладные только после успешной записи основного документа
Для Каждого СтрокаТЧ Из НовыйДокумент.СтатусыНакладных Цикл
Попытка
// ✅ Очищаем ID от запятых и пробелов перед передачей
ЧистыйID = СтрЗаменить(СтрЗаменить(СтрокаТЧ.InvoiceID, ",", ""), " ", "");
СоздатьДокументЭтранНакладная(ЧистыйID, СтрокаТЧ.НомерНакладной);
Исключение
ЗаписьЖурналаРегистрации("ЗагрузкаЭтран", УровеньЖурналаРегистрации.Ошибка, , ,
"Ошибка создания детальной накладной ID " + СтрокаТЧ.InvoiceID + ": " + ОписаниеОшибки());
КонецПопытки;
КонецЦикла;
Исключение
ЗаписьЖурналаРегистрации("ЗагрузкаЭтран", УровеньЖурналаРегистрации.Ошибка, , ,
"Не удалось записать документ ЭтранСписокНакладныхВПути: " + ОписаниеОшибки());
Возврат Неопределено;
КонецПопытки;
Возврат НовыйДокумент.Ссылка;
КонецФункции
&НаСервере
Функция СоздатьНовыйДокументСпискаИспорченныхНакладных(ДатаНачала, ДатаОкончания)
Накладные = ПолучитьСписокИспорченныхНакладных(ДатаНачала, ДатаОкончания);
Если Накладные.Количество() = 0 Тогда
ЗаписьЖурналаРегистрации("ЗагрузкаЭтран", УровеньЖурналаРегистрации.Информация, , ,
"Нет испорченных накладных за час " + Формат(ДатаНачала, "ДФ=HH:00"));
Возврат Неопределено;
КонецЕсли;
НовыйДокумент = Документы.ЭтранСписокИспорченыхНакладных.СоздатьДокумент();
НовыйДокумент.ДатаС = ДатаНачала;
НовыйДокумент.ДатаПо = ДатаОкончания;
НовыйДокумент.Дата = ТекущаяДата();
Для Каждого Накладная Из Накладные Цикл
НоваяСтрока = НовыйДокумент.СтатусыНакладных.Добавить();
НоваяСтрока.InvoiceID = Накладная.InvoiceID;
НоваяСтрока.НомерНакладной = Накладная.InvNumber;
НоваяСтрока.Статус = "Испорчен";
КонецЦикла;
НовыйДокумент.Записать();
ЗаписьЖурналаРегистрации("ЗагрузкаЭтран", УровеньЖурналаРегистрации.Информация, , ,
"Создан документ 'Испорченные' за час " + Формат(ДатаНачала, "ДФ=HH:00") +
", накладных: " + Строка(Накладные.Количество()));
Для Каждого Накладная Из Накладные Цикл
Попытка
ПометитьДокументНаУдаление(Накладная.InvoiceID);
Исключение
ЗаписьЖурналаРегистрации("ЗагрузкаЭтран", УровеньЖурналаРегистрации.Ошибка, , ,
"Ошибка пометки на удаление " + Накладная.InvNumber);
КонецПопытки;
КонецЦикла;
Возврат НовыйДокумент;
КонецФункции
&НаСервере
Процедура АвтозагрузкаНакладныхЭТРАН() Экспорт
// Загружаем предыдущие полные сутки
Вчера = ТекущаяДата() - 86400; // 24 часа назад
НачалоСуток = Дата(Год(Вчера), Месяц(Вчера), День(Вчера), 0, 0, 0);
ЗаписьЖурналаРегистрации("ЗагрузкаЭтран", УровеньЖурналаРегистрации.Информация, , ,
"=== Начало загрузки за сутки: " + Формат(НачалоСуток, "ДФ=dd.MM.yyyy") + " ===");
ВсегоВПути = 0;
ВсегоИспорчено = 0;
ВсегоЧасовСДанными = 0;
Для Час = 0 По 23 Цикл
// Вычисляем начало и конец часа
НачалоЧаса = НачалоСуток + (Час * 3600);
КонецЧаса = НачалоЧаса + 3599; // 59 минут 59 секунд
ЗаписьЖурналаРегистрации("ЗагрузкаЭтран", УровеньЖурналаРегистрации.Информация, , ,
"Обработка часа: " + Формат(НачалоЧаса, "ДФ=HH:mm") + " - " + Формат(КонецЧаса, "ДФ=HH:mm"));
// 1. Накладные в пути за этот час
НакладныеВПути = ПолучитьСписокНакладныхВПути(НачалоЧаса, КонецЧаса);
Если НакладныеВПути.Количество() > 0 Тогда
СоздатьНовыйДокументСпискаНакладныхВПути(НачалоЧаса, КонецЧаса);
ВсегоВПути = ВсегоВПути + НакладныеВПути.Количество();
ВсегоЧасовСДанными = ВсегоЧасовСДанными + 1;
КонецЕсли;
// 2. Испорченные накладные за этот час
ИспорченныеНакладные = ПолучитьСписокИспорченныхНакладных(НачалоЧаса, КонецЧаса);
Если ИспорченныеНакладные.Количество() > 0 Тогда
СоздатьНовыйДокументСпискаИспорченныхНакладных(НачалоЧаса, КонецЧаса);
ВсегоИспорчено = ВсегоИспорчено + ИспорченныеНакладные.Количество();
Если НакладныеВПути.Количество() = 0 Тогда
ВсегоЧасовСДанными = ВсегоЧасовСДанными + 1;
КонецЕсли;
КонецЕсли;
КонецЦикла;
ЗаписьЖурналаРегистрации("ЗагрузкаЭтран", УровеньЖурналаРегистрации.Информация, , ,
"=== Загрузка завершена ===");
ЗаписьЖурналаРегистрации("ЗагрузкаЭтран", УровеньЖурналаРегистрации.Информация, , ,
"Всего часов с данными: " + ВсегоЧасовСДанными + " из 24");
ЗаписьЖурналаРегистрации("ЗагрузкаЭтран", УровеньЖурналаРегистрации.Информация, , ,
"Накладных в пути: " + ВсегоВПути + ", испорчено: " + ВсегоИспорчено);
КонецПроцедуры
&НаСервере
Функция РаспарситьСписокИспорченныхНакладных(XMLСтрока) Экспорт
Результат = Новый Массив;
Чтение = Новый ЧтениеXML;
Попытка
Чтение.УстановитьСтроку(XMLСтрока);
Пока Чтение.Прочитать() Цикл
// Приводим имя тега к верхнему регистру для надежности
ИмяУзла = ВРег(Чтение.Имя);
// Нашли начало блока накладной <invoice>
Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента И ИмяУзла = "INVOICE" Тогда
Ид = "";
Ном = "";
// Читаем всё внутри текущего блока <invoice>
Пока Чтение.Прочитать() Цикл
ТекущееИмя = ВРег(Чтение.Имя);
// Если дошли до конца </invoice>, выходим из внутреннего цикла
Если Чтение.ТипУзла = ТипУзлаXML.КонецЭлемента И ТекущееИмя = "INVOICE" Тогда
Прервать;
КонецЕсли;
// Ищем нужные поля в начале элементов
Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
// Получаем данные из атрибута value="..."
ЗначениеАтрибута = Чтение.ПолучитьАтрибут("value");
Если ТекущееИмя = "INVOICEID" Тогда
Ид = ЗначениеАтрибута;
// Убираем разделители тысяч (запятые)
Ид = СтрЗаменить(Ид, ",", "");
ИначеЕсли ТекущееИмя = "INVNUMBER" Тогда
Ном = ЗначениеАтрибута;
КонецЕсли;
КонецЕсли;
КонецЦикла;
// Если данные найдены, добавляем структуру в массив
Если ЗначениеЗаполнено(Ид) Тогда
Результат.Добавить(Новый Структура("InvoiceID, InvNumber", Ид, Ном));
КонецЕсли;
КонецЕсли;
КонецЦикла;
Исключение
ЗаписьЖурналаРегистрации("ЗагрузкаЭтран", УровеньЖурналаРегистрации.Ошибка, , ,
"Ошибка парсинга испорченных накладных: " + ОписаниеОшибки());
КонецПопытки;
Возврат Результат;
КонецФункции