Как рассчитать пройденное расстояние по дням и водителям в СКД при интеграции с внешней базой 1С:УАТ

Программист 1С v8.3 (Управляемые формы) Управленческий учет IT и автоматизация бизнеса
← На главную

При построении сложных аналитических отчетов в системе 1С:Предприятие часто возникает необходимость объединения данных из текущей информационной базы с показателями из внешних систем (например, специализированной конфигурации «1С:Управление автотранспортом» (УАТ)). Типичный сценарий: основной отчет формируется по документам логистики (маршрутным заданиям) в локальной базе, а данные о фактическом пробеге автомобилей и выработке водителей загружаются из базы УАТ через COM-соединение.

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

Выясняем причины проблем при связи наборов данных

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

  1. Несовместимость ссылочных типов (COM-объекты): Поле водителя, полученное из внешней базы через COM-соединение, на техническом уровне представляет собой COMОбъект. Локальная база ничего не знает об этом типе данных и не может напрямую сопоставить его со своим справочником ФизическиеЛица или Сотрудники. В результате связь наборов по полю водителя не срабатывает.
  2. Различие в составе дат: В локальном запросе дата документа приводится к началу дня (время 00:00:00), в то время как во внешней базе путевой лист содержит точное время выезда или возвращения. Даже если визуально даты совпадают, разница во времени на одну секунду делает их неравными для СКД.
  3. Декартово произведение (дублирование пробега): Если в настройках связи наборов данных в СКД указать связь только по водителю, проигнорировав дату, система выполнит декартово соединение. Пробег за все дни суммируется и будет выведен одинаковой (общей) цифрой на каждую строку отчета.

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

Шаг 1: Правильное получение и типизация данных из внешней базы

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

Разберем пример кода загрузки данных, исправляющий синтаксические и логические ошибки исходного кода:


// Создаем таблицу значений с явным указанием типов колонок для СКД
ТЗ_Пробег = Новый ТаблицаЗначений;
ТЗ_Пробег.Колонки.Добавить("Водитель", Новый ОписаниеТипов("СправочникСсылка.ФизическиеЛица"));
ТЗ_Пробег.Колонки.Добавить("Дата", Новый ОписаниеТипов("Дата", , , Новый КвалификаторыДаты(ЧастиДаты.Дата)));
ТЗ_Пробег.Колонки.Добавить("ПройденноеРасстояние", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2)));

// Настройка COM-соединения и выполнение запроса во внешней базе
ЗапросВнешний = Соединение.NewObject("Запрос");
ЗапросВнешний.Текст = 
    "ВЫБРАТЬ
    |    уатПутевойЛист.Водитель1 КАК ВодительСсылка,
    |    НАЧАЛОПЕРИОДА(уатПутевойЛист.ДатаВыезда, ДЕНЬ) КАК ДатаВыезда,
    |    СУММА(уатПутевойЛист.СпидометрВозвращения - уатПутевойЛист.СпидометрВыезда) КАК Пробег
    |ИЗ
    |    Документ.уатПутевойЛист КАК уатПутевойЛист
    |ГДЕ
    |    уатПутевойЛист.ДатаВыезда МЕЖДУ &НачалоПериода И &КонецПериода
    |    И уатПутевойЛист.Проведен = ИСТИНА
    |СГРУППИРОВАТЬ ПО
    |    уатПутевойЛист.Водитель1,
    |    НАЧАЛОПЕРИОДА(уатПутевойЛист.ДатаВыезда, ДЕНЬ)";

ЗапросВнешний.УстановитьПараметр("НачалоПериода", НачалоПериода);
ЗапросВнешний.УстановитьПараметр("КонецПериода", КонецПериода);

Выборка = ЗапросВнешний.Выполнить().Выбрать();

Пока Выборка.Следующий() Цикл
    НоваяСтрока = ТЗ_Пробег.Добавить();
    НоваяСтрока.ПройденноеРасстояние = Выборка.Пробег;
    НоваяСтрока.Дата = НачалоДня(Выборка.ДатаВыезда);
    
    // Сопоставляем водителя из внешней базы по UUID
    Попытка
        ВнешнийGUID = Соединение.String(Выборка.ВодительСсылка.УникальныйИдентификатор());
        НоваяСтрока.Водитель = Справочники.ФизическиеЛица.ПолучитьСсылку(Новый УникальныйИдентификатор(ВнешнийGUID));
    Исключение
        // Если сопоставить не удалось, оставляем пустую ссылку или ищем по наименованию
        НоваяСтрока.Водитель = Справочники.ФизическиеЛица.ПустаяСсылка();
    КонецПопытки;
КонецЦикла;

Важное примечание: Если ваши информационные базы не синхронизированы по уникальным идентификаторам (GUID), сопоставление по GUID вернет "битые" ссылки. В таком случае единственным надежным способом связать водителей будет сопоставление по строковому представлению (ФИО водителя) либо по его табельному номеру. Для этого в обеих базах в ТЗ нужно выгружать текстовые поля и производить связь в СКД по ним.

Шаг 2: Настройка связей наборов данных в СКД

После передачи полученной таблицы в СКД в качестве внешнего набора данных (например, под именем НаборДанныхВыработка), необходимо правильно связать его с основным набором данных запроса. Перейдем на вкладку «Связи наборов данных» в конструкторе схемы компоновки данных.

Для корректного сопоставления необходимо создать две связи (строки) в таблице настроек:

  1. Связь по водителю:
    • Источник связи: НаборДанныхЛокальный
    • Приемник связи: НаборДанныхВыработка
    • Выражение источника: Водитель
    • Выражение приемника: Водитель
  2. Связь по дате:
    • Источник связи: НаборДанныхЛокальный
    • Приемник связи: НаборДанныхВыработка
    • Выражение источника: НАЧАЛОПЕРИОДА(Дата, "ДЕНЬ")
    • Выражение приемника: Дата

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

Шаг 3: Борьба с задвоением итогов по ресурсам

Если у водителя за один рабочий день было несколько локальных документов (например, три «Маршрутных задания»), а путевой лист в УАТ на этот день один, СКД присоединит показатель пробега к каждому из трех документов. При расчете общих итогов по водителю стандартная функция Сумма(ПройденноеРасстояние) сложит эти показатели, и итоговый пробег за день увеличится в три раза.

Чтобы избежать этого, настроим расчет ресурсов СКД с использованием агрегатных функций языка выражений. На вкладке «Ресурсы» для поля ПройденноеРасстояние вместо простой суммы укажем следующее выражение:


Сумма(ВычислитьВыражениеСГруппировкойТаблицаЗначений("Максимум(ПройденноеРасстояние)", "Водитель, Дата"))

Как работает это выражение: Функция сначала группирует детальные строки отчета по уникальным парам "Водитель и Дата", находит для каждого дня максимальное значение пробега (что исключает дублирование при наличии нескольких маршрутных листов за день), а затем суммирует эти уникальные суточные показатели на уровне итогов по водителю или по всему отчету.

Шаг 4: Учет специфики многодневных рейсов в 1С:УАТ

При работе с путевыми листами в УАТ критически важно учитывать логику работы конфигурации. Если автомобиль уезжает в рейс на 3 дня, в документе уатПутевойЛист будут заполнены даты выезда и возвращения, например, с 21 по 23 мая. Прямой запрос к таблице документов запишет весь пробег рейса на одну дату (дату выезда или возвращения), а в остальные дни водитель по отчету "не работал".

Для решения этой проблемы рекомендуется отказаться от прямых запросов к документам и использовать виртуальные таблицы оборотов регистров накопления УАТ. В системе УАТ за это отвечает регистр уатВыработкаТСиВодителей (или уатВыработкаТС). Запрос к этому регистру с периодичностью "День" автоматически распределит выработку транспортного средства пропорционально дням нахождения в пути:


ВЫБРАТЬ
    ВыработкаОбороты.Водитель КАК ВодительСсылка,
    ВыработкаОбороты.Период КАК Дата,
    ВыработкаОбороты.КоличествоОборот КАК ПройденноеРасстояние
ИЗ
    РегистрНакопления.уатВыработкаТСиВодителей.Обороты(&НачалоПериода, &КонецПериода, День, ПараметрВыработки = ЗНАЧЕНИЕ(Справочник.уатПараметрыВыработки.ПробегОбщий)) КАК ВыработкаОбороты

Использование регистра накопления позволяет гарантировать, что данные о пробеге будут распределены по дням максимально корректно, в соответствии с алгоритмами, заложенными разработчиками отраслевого решения 1С:УАТ.

← На главную