Как загрузить данные из XML в документ Отчет о розничных продажах

Программист 1C:Бухгалтерия Бухгалтерский учет Торговля и дистрибуция
← На главную

Загрузка данных из внешних файлов (XML, JSON) в документ Отчет о розничных продажах (ОРП) — это классическая задача при интеграции 1С со сторонними кассовыми аппаратами или фронт-офисными системами. Сложность заключается в том, что ОРП имеет разветвленную структуру табличных частей: Товары, Услуги, Возвраты и Оплата. В этой статье мы подробно разберем, как правильно спроектировать алгоритм загрузки, избежать дублирования документов и корректно распределить товары по разделам.

Анализ структуры входящих данных и выбор способа чтения

Прежде чем приступать к созданию документов, необходимо прочитать данные из файла. В 1С для работы с XML чаще всего используются ЧтениеXML совместно с ПостроительDOM или объектная модель XDTO. Рассмотрим пример с использованием DOM, который позволяет обходить узлы файла как дерево объектов. Проанализируем типичную структуру, где один файл содержит данные по нескольким магазинам и сменам.

Для начала создадим вспомогательную таблицу значений (ТЗ), в которую выгрузим все "сырые" данные из файла. Это позволит нам сгруппировать информацию и уменьшить количество обращений к базе данных.


&НаСервере
Процедура ПрочитатьФайлXML(ПутьКФайлу)
    ТЗ_Данные = Новый ТаблицаЗначений;
    ТЗ_Данные.Колонки.Добавить("МагазинКод");
    ТЗ_Данные.Колонки.Добавить("НомерСмены");
    ТЗ_Данные.Колонки.Добавить("Дата");
    ТЗ_Данные.Колонки.Добавить("КодНоменклатуры");
    ТЗ_Данные.Колонки.Добавить("Количество");
    ТЗ_Данные.Колонки.Добавить("Цена");
    ТЗ_Данные.Колонки.Добавить("Сумма");
    ТЗ_Данные.Колонки.Добавить("ЭтоВозврат", Новый ОписаниеТипов("Булево"));
    ТЗ_Данные.Колонки.Добавить("ОплатаБезналом", Новый ОписаниеТипов("Булево"));

    Чтение = Новый ЧтениеXML;
    Чтение.ОткрытьФайл(ПутьКФайлу);
    
    Построитель = Новый ПостроительDOM;
    ДокументDOM = Построитель.Прочитать(Чтение);
    
    // Обход узлов и заполнение ТЗ_Данные (логика зависит от структуры вашего XML)
    // ...
    
    Чтение.Закрыть();
КонецПроцедуры

Группировка данных по документам

Одной из главных ошибок начинающих разработчиков является создание документа на каждую строку файла. Это приводит к хаосу в базе. Выясним причину: документ Отчет о розничных продажах в 1С создается один на одну кассовую смену для конкретной кассы (склада).

Следовательно, перед созданием документов нам нужно "свернуть" нашу таблицу данных, чтобы получить уникальные пары Магазин + НомерСмены. Именно столько документов и должно быть создано в итоге.


ТаблицаДокументов = ТЗ_Данные.Скопировать();
ТаблицаДокументов.Свернуть("МагазинКод, НомерСмены, Дата");

Для Каждого СтрокаДок Из ТаблицаДокументов Цикл
    // Здесь начинается логика создания одного документа ОРП
    СоздатьДокументОРП(СтрокаДок, ТЗ_Данные);
КонецЦикла;

Оптимизация поиска номенклатуры

Использование методов НайтиПоКоду() или НайтиПоНаименованию() внутри цикла загрузки — это прямой путь к низкой производительности. Если в файле 1000 строк, система выполнит 1000 запросов к БД. Рассмотрим более эффективный метод: заранее соберем все коды номенклатуры из файла и одним запросом получим ссылки на объекты.

Рекомендуемый алгоритм:

  1. Выгрузить колонку КодНоменклатуры в массив.
  2. Запустить запрос к справочнику Номенклатура с фильтром ГДЕ Код В (&МассивКодов).
  3. Результат запроса выгрузить в Соответствие, где ключом будет код, а значением — ссылка на номенклатуру.

Распределение товаров по табличным частям

Проанализируем ситуацию распределения позиций. В документе ОРП логика должна быть следующей:

Важный нюанс: при добавлении строки в ТЧ Товары или Возвраты необходимо также заполнять счета учета. В типовых конфигурациях для этого используются специализированные процедуры.


Процедура ЗаполнитьСтрокуДокумента(НовыйДокумент, ДанныеСтроки, СсылкаНоменклатура)
    
    // Проверяем, услуга это или товар
    ЭтоУслуга = (СсылкаНоменклатура.ТипНоменклатуры = Перечисления.ТипыНоменклатуры.Услуга);
    
    Если ДанныеСтроки.ЭтоВозврат Тогда
        Если ЭтоУслуга Тогда
            НоваяСтрока = НовыйДокумент.ВозвратУслуг.Добавить();
        Иначе
            НоваяСтрока = НовыйДокумент.Возвраты.Добавить();
        КонецЕсли;
    Иначе
        Если ЭтоУслуга Тогда
            НоваяСтрока = НовыйДокумент.Услуги.Добавить();
        Иначе
            НоваяСтрока = НовыйДокумент.Товары.Добавить();
        КонецЕсли;
    КонецЕсли;

    ЗаполнитьЗначенияСвойств(НоваяСтрока, ДанныеСтроки);
    НоваяСтрока.Номенклатура = СсылкаНоменклатура;

    // Автоматическое заполнение счетов учета (пример для БП 3.0)
    ЗаполнитьСчетаУчетаДляСтроки(НовыйДокумент, НоваяСтрока, ЭтоУслуга);
    
КонецПроцедуры

Обработка оплат (Безналичный расчет)

Сумма по ТЧ Товары и Услуги за вычетом Возвратов должна совпадать с итогом по ТЧ Оплата. Если в XML указано, что чек оплачен картой, необходимо добавить строку в таблицу оплат. Рассмотрим, как это реализовать:

Проанализируем пример: если в рамках одной смены было 10 чеков безналом, в документе ОРП в таблице "Оплата" достаточно создать одну строку с общим итогом по данному виду оплаты (например, "Эквайринг"), либо распределить их по видам карт.


// Внутри цикла создания документа
СуммаБезнала = ТЗ_Данные.Итог("Сумма", "ОплатаБезналом = Истина");
Если СуммаБезнала > 0 Тогда
    СтрокаОплаты = НовыйДокумент.Оплата.Добавить();
    СтрокаОплаты.ВидОплаты = Справочники.ВидыОплатЧековККМ.НайтиПоНаименованию("Карта");
    СтрокаОплаты.СуммаОплаты = СуммаБезнала;
КонецЕсли;

Итоговый алгоритм создания документа

Соберем всё воедино. Главное правило: метод Записать() вызывается один раз для каждого документа после того, как заполнены все его части. Посмотрим на итоговую структуру функции создания документа на сервере:


Функция СоздатьДокументНаСервере(ПараметрыШапки, ТЗ_ВсеДанные)
    
    НовыйДокумент = Документы.ОтчетОРозничныхПродажах.СоздатьДокумент();
    НовыйДокумент.Дата = ПараметрыШапки.Дата;
    НовыйДокумент.Организация = Справочники.Организации.ОрганизацияПоУмолчанию();
    // Поиск кассы по коду магазина из файла
    НовыйДокумент.Касса = Справочники.Кассы.НайтиПоРеквизиту("КодМагазина", ПараметрыШапки.МагазинКод);
    
    // Получаем строки именно для этой смены и магазина
    Отбор = Новый Структура("МагазинКод, НомерСмены", ПараметрыШапки.МагазинКод, ПараметрыШапки.НомерСмены);
    СтрокиСмены = ТЗ_ВсеДанные.НайтиСтроки(Отбор);
    
    Для Каждого Стр Из СтрокиСмены Цикл
        СсылкаНомен = ПолучитьНоменклатуруИзКэша(Стр.КодНоменклатуры); 
        ЗаполнитьСтрокуДокумента(НовыйДокумент, Стр, СсылкаНомен);
    КонецЦикла;
    
    // Заполнение итогов по оплате
    ЗаполнитьТаблицуОплат(НовыйДокумент, СтрокиСмены);
    
    Попытка
        НовыйДокумент.Записать(РежимЗаписиДокумента.Запись);
        Возврат НовыйДокумент.Ссылка;
    Исключение
        Сообщить("Ошибка при записи: " + ОписаниеОшибки());
        Возврат Неопределено;
    КонецПопытки;
    
КонецФункции

Типичные ошибки, которых следует избегать

1. Дублирование товаров в Товарах и Возвратах. Проверьте условия Если...ИначеЕсли. Если вы сначала добавляете строку в ТЧ "Товары", а потом проверяете "Если ЭтоВозврат" и добавляете её же в "Возвраты" — вы удваиваете оборот. Строка должна попадать строго в одну из таблиц.

2. Пустые документы при открытии формы. Если вы создали документ программно, записали его, а при открытии через ОткрытьФорму он пустой — убедитесь, что вы передаете ссылку на уже существующий документ в параметре Ключ, а не пытаетесь создать "Новый" через параметры формы.

3. Отсутствие группировки. Если в файле 500 чеков за одну смену, а вы создали 500 документов ОРП — это грубая методическая ошибка. В 1С один ОРП соответствует одному Z-отчету (одной смене).

Соблюдение этих правил позволит вам создать надежный и быстрый механизм загрузки, который будет корректно отражать розничные продажи в бухгалтерском и управленческом учете.

← На главную