Как реализовать проверку пересечения временных интервалов для водителей и транспорта в 1С

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

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

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

Математическая логика пересечения периодов

Прежде чем переходить к написанию кода, давайте определимся с логическим условием. Пусть у нас есть два интервала:

  1. Первый интервал: Начало1 — Конец1
  2. Второй интервал: Начало2 — Конец2

Многие начинающие программисты пытаются описать все возможные варианты пересечения (когда начало второго внутри первого, когда конец второго внутри первого, когда второй полностью поглощает первый и т.д.). Это приводит к громоздким конструкциям с множеством условий ИЛИ, как мы видим в сообщении №13 форума.

Однако существует изящная и короткая формула, которая описывает любое пересечение:

Начало1 < Конец2 И Конец1 > Начало2

Рассмотрим, почему это работает. Интервалы не пересекаются только в двух случаях:

  1. Первый интервал закончился раньше, чем начался второй (Конец1 <= Начало2).
  2. Первый интервал начался позже, чем закончился второй (Начало1 >= Конец2).

Отрицание этих двух условий (по закону де Моргана) дает нам универсальную формулу пересечения. Важно учитывать граничные условия. Как отмечено в сообщении №3, если один рейс заканчивается в 17:30, а другой начинается ровно в 17:30 — это нормально. В таком случае мы используем строгие знаки «меньше» и «больше». Если же даже «стыковка» в одну секунду запрещена, знаки следует заменить на нестрогие (<= и >=).

Реализация проверки внутри табличной части документа

Часто проверка требуется внутри одного документа, например, в «Разнарядке» или «Путевом листе», где в табличной части перечислено несколько ходок одного водителя. Проанализируем решение, предложенное в сообщении №13. Автор использует внутреннее соединение таблицы самой с собой.

Разберем по шагам, как построить такой запрос:

  1. Выбираем данные из табличной части документа.
  2. Соединяем эту таблицу с ней же самой по условию равенства водителя (Водитель = Водитель).
  3. Добавляем условие, что мы не сравниваем строку саму с собой (НомерСтроки <> НомерСтроки).
  4. Применяем нашу формулу пересечения периодов.

Пример оптимизированного запроса для проверки пересечений внутри табличной части:


ВЫБРАТЬ
    ТЧ1.НомерСтроки КАК НомерСтрокиА,
    ТЧ2.НомерСтроки КАК НомерСтрокиБ,
    ТЧ1.Водитель КАК Водитель
ИЗ
    Документ.Разнарядка.Разнарядка КАК ТЧ1
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.Разнарядка.Разнарядка КАК ТЧ2
        ПО ТЧ1.Ссылка = ТЧ2.Ссылка
        И ТЧ1.Водитель = ТЧ2.Водитель
        И ТЧ1.НомерСтроки < ТЧ2.НомерСтроки
ГДЕ
    ТЧ1.Ссылка = &СсылкаНаДокумент
    И ТЧ1.ДатаВыезда < ТЧ2.ДатаВозврата
    И ТЧ1.ДатаВозврата > ТЧ2.ДатаВыезда
    И ТЧ1.Водитель <> ЗНАЧЕНИЕ(Справочник.Сотрудники.ПустаяСсылка)

Обратите внимание на условие ТЧ1.НомерСтроки < ТЧ2.НомерСтроки. Использование знака «меньше» вместо «не равно» позволяет избежать дублирования результатов (система не будет выдавать две ошибки: «Строка 1 пересекается со строкой 2» и «Строка 2 пересекается со строкой 1»).

Проверка пересечений с данными в базе (другими документами)

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

Рассмотрим алгоритм комплексной проверки в модуле документа (процедура ПередЗаписью или ОбработкаПроверкиЗаполнения):

  1. Выгружаем временную таблицу с периодами из текущего документа.
  2. Выполняем запрос к физическим таблицам (или регистрам), ограничивая выборку периодом «от минимального начала» до «максимального конца» текущих строк для оптимизации.
  3. Соединяем временную таблицу с данными базы по сотруднику и условию пересечения.

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

Использование блокировок для целостности данных

Проанализируем критически важный аспект: многопользовательскую работу. Представим ситуацию: два диспетчера одновременно открыли разные документы «Разнарядка» и ставят Иванова на одно и то же время. Если оба нажмут «Провести» одновременно, запрос на проверку пересечений у обоих вернет пустой результат, так как данные еще не записаны в базу. В итоге мы получим два проведенных документа с ошибкой.

Чтобы этого избежать, выясним, как работают управляемые блокировки. Перед выполнением запроса проверки необходимо установить исключительную блокировку на объект «Водитель» в заданном интервале времени.


Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.уатЗанятостьВодителей");
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
ЭлементБлокировки.УстановитьПараметр("Водитель", ТекущийВодитель);
// Устанавливаем диапазон времени, который хотим заблокировать
ЭлементБлокировки.ИспользоватьИзДанных("Период", СписокПериодовДокумента); 
Блокировка.Заблокировать();

Только после вызова Блокировка.Заблокировать() можно выполнять запрос. Если другой пользователь уже начал проводить документ по этому водителю, текущий сеанс подождет завершения транзакции соседа и увидит актуальные данные.

Пользовательский интерфейс и удобство (UX)

Выдавать ошибку в момент записи — это надежно, но не всегда удобно для пользователя. Рассмотрим, как сделать интерфейс более дружелюбным:

  1. Диаграмма Ганта: Вместо сухого ввода цифр, используйте визуальное планирование. На диаграмме наложения будут видны сразу красным цветом или физическим наложением блоков.
  2. Проверка «на лету»: Реализуйте обработчик события ПриИзменении для полей даты и водителя. Программу можно настроить так, чтобы она сразу подсвечивала строку красным, если обнаружено пересечение, не дожидаясь попытки записи.
  3. Подбор свободных: При выборе водителя в форму подбора передавайте параметры начала и конца рейса, чтобы список сразу фильтровал только тех сотрудников, которые свободны в этот период.

Использование этих методов значительно сократит количество ошибок ввода и повысит общую эффективность работы транспортного отдела.

Заключение

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

← На главную