При интеграции 1С со сторонними сервисами или внешними аналитическими системами часто возникает задача регулярного экспорта документов (например, ЧекККМ) в формате XML. Главная сложность заключается в организации инкрементальной выгрузки: система должна отбирать исключительно новые или измененные с момента прошлой выгрузки документы, не дублируя данные и не пропуская чеки при интенсивных продажах.
Разберем по шагам, какие механизмы платформы 1С лучше всего подходят для решения этой задачи, как отслеживать изменения и как технически сформировать XML-файл по расписанию.
Механизм планов обмена — это штатный и наиболее надежный инструмент платформы «1С:Предприятие» для фиксации изменений данных. Он обеспечивает транзакционную безопасность: если документ проводится прямо в момент выгрузки, он гарантированно попадет в следующую итерацию без риска потери данных.
Рассмотрим порядок реализации через план обмена:
ПланОбмена (например, ОбменСВнешнейСистемой). В составе плана обмена указываем документ ЧекККМ с авторегистрацией Разрешить.ПланыОбмена.ВыбратьИзменения(), формируем XML и удаляем регистрацию только после успешного сохранения файла.Посмотрим на пример кода выборки изменений и сериализации в XML:
Процедура ВыгрузитьНовыеЧекиВXML(УзелОбмена, ПутьКФайлу) Экспорт
Выборка = ПланыОбмена.ВыбратьИзменения(УзелОбмена, УзелОбмена.НомерОтправленного + 1);
// Если изменений нет, прерываем выполнение
Если Выборка.Количество() = 0 Тогда
Возврат;
КонецЕсли;
ВременныйФайл = ПутьКФайлу + ".tmp";
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл(ВременныйФайл, "UTF-8");
ЗаписьXML.ЗаписатьНачалоЭлемента("ЧекиККМ");
Пока Выборка.Следующий() Цикл
ДанныеОбъекта = Выборка.Получить();
Если ТипЗнч(ДанныеОбъекта) = Тип("ДокументСсылка.ЧекККМ") Тогда
ОбъектДокумент = ДанныеОбъекта.ПолучитьОбъект();
Если ОбъектДокумент <> Неопределено Тогда
// Сериализация стандартными средствами платформы
СериализаторXDTO.ЗаписатьXML(ЗаписьXML, ОбъектДокумент);
КонецЕсли;
КонецЕсли;
КонецЦикла;
ЗаписьXML.ЗаписатьКонецЭлемента();
ЗаписьXML.Закрыть();
// Удаляем регистрацию изменений только после успешной записи файла
ПланыОбмена.УдалитьРегистрациюИзменений(УзелОбмена, УзелОбмена.НомерОтправленного + 1);
// Атомарное перемещение во избежание чтения недописанного файла внешней системой
ПереместитьФайл(ВременныйФайл, ПутьКФайлу);
КонецПроцедуры
Если внесение изменений в структуру планов обмена нежелательно или конфигурация находится на поддержке без возможности редактирования метаданных плана обмена, можно использовать непериодический независимый РегистрСведений (например, ВыгруженныеДокументы).
Важное архитектурное правило: Не следует добавлять признак (флаг) «Выгружен» в сам документ ЧекККМ. Запись признака в документ при выгрузке приведет к повторной перезаписи объекта, изменению версии данных, блокировкам таблиц и лишним коллизиям в кассовой смене. Всегда выносите статус выгрузки в отдельный регистр сведений.
Структура регистра сведений:
Документ (Тип: ДокументСсылка.ЧекККМ).ДатаВыгрузки (Тип: Дата).Разберем логику выборки невыгруженных документов с помощью запроса:
Функция ПолучитьНевыгруженныеЧеки(ПериодОтбора) Экспорт
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Чек.Ссылка КАК Ссылка
|ИЗ
| Документ.ЧекККМ КАК Чек
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ВыгруженныеДокументы КАК РегВыгрузка
| ПО Чек.Ссылка = РегВыгрузка.Документ
|ГДЕ
| РегВыгрузка.Документ ЕСТЬ NULL
| И Чек.Проведен = ИСТИНА
| И Чек.Дата >= &ПериодОтбора";
Запрос.УстановитьПараметр("ПериодОтбора", ПериодОтбора);
Возврат Запрос.Выполнить().Выгрузить();
КонецФункции
После успешной записи документов в XML выполняется пакетная запись ссылок в регистр сведений с помощью объекта РегистрСведенийНаборЗаписей.
В зависимости от требований внешней системы к структуре XML-файла применяются два подхода:
СериализаторXDTO: Если принимающая система способна обрабатывать XML произвольной структуры или схему 1С, сериализация всего объекта (включая шапку и табличные части Товары, Оплата) одной строкой через СериализаторXDTO.ЗаписатьXML() является самой производительной.ЗаписьXML: Если принимающая сторона ожидает строго определенный формат тегов, используется объект ЗаписьXML с методами ЗаписатьНачалоЭлемента, ЗаписатьАтрибут, ЗаписатьТекст и ЗаписатьКонецЭлемента. Потоковая запись в отличие от ДокументDOM не перегружает оперативную память сервера при больших объемах данных.Посмотрим на пример ручной потоковой выгрузки необходимых реквизитов чека:
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл(ПутьКФайлу, "UTF-8");
ЗаписьXML.ЗаписатьОбъявлениеXML();
ЗаписьXML.ЗаписатьНачалоЭлемента("Receipts");
Для Каждого Стр Из ТаблицаЧеков Цикл
ЧекОбъект = Стр.Ссылка.ПолучитьОбъект();
ЗаписьXML.ЗаписатьНачалоЭлемента("Receipt");
ЗаписьXML.ЗаписатьАтрибут("Number", Строка(ЧекОбъект.Номер));
ЗаписьXML.ЗаписатьАтрибут("Date", Формат(ЧекОбъект.Дата, "ДФ=yyyy-MM-ddTHH:mm:ss"));
ЗаписьXML.ЗаписатьАтрибут("Sum", Строка(ЧекОбъект.СуммаДокумента));
ЗаписьXML.ЗаписатьНачалоЭлемента("Items");
Для Каждого СтрТовар Из ЧекОбъект.Товары Цикл
ЗаписьXML.ЗаписатьНачалоЭлемента("Item");
ЗаписьXML.ЗаписатьАтрибут("Code", Строка(СтрТовар.Номенклатура.Код));
ЗаписьXML.ЗаписатьАтрибут("Name", Строка(СтрТовар.Номенклатура.Наименование));
ЗаписьXML.ЗаписатьАтрибут("Quantity", Строка(СтрТовар.Количество));
ЗаписьXML.ЗаписатьАтрибут("Price", Строка(СтрТовар.Цена));
ЗаписьXML.ЗаписатьКонецЭлемента(); // Item
КонецЦикла;
ЗаписьXML.ЗаписатьКонецЭлемента(); // Items
ЗаписьXML.ЗаписатьКонецЭлемента(); // Receipt
КонецЦикла;
ЗаписьXML.ЗаписатьКонецЭлемента(); // Receipts
ЗаписьXML.Закрыть();
Для выполнения экспорта по расписанию используется объект конфигурации РегламентноеЗадание:
ВыгрузкаЧековККМ).900 секунд (15 минут)..tmp), а после завершения метода ЗаписьXML.Закрыть() переименовывайте его в целевой .xml.ОтчетОРозничныхПродажах. Если внешняя система должна получать детализацию по позициям чека, выгрузка должна отрабатывать оперативно в течение смены до выполнения архивации.Артикул, Штрихкод или Код.