Как реализовать контроль пересечения периодов при планировании в 1С?

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

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

Выбор объекта метаданных: Регистр сведений против Регистра расчета

Первый вопрос, который возникает у разработчика: «Использовать ли специализированный РегистрРасчета, где контроль пересечений реализован на уровне платформы, или привычный РегистрСведений?». Проанализируем оба варианта.

Регистр расчета (РР) действительно обладает мощным механизмом вытеснения. Однако этот механизм создавался для задач расчета заработной платы (например, когда «Больничный» вытесняет «Явку»). В задачах планирования периоды обычно однотипные, и нам нужно не вытеснение (автоматическое сокращение старой записи), а жесткий запрет на создание пересекающейся записи. Использование РегистрРасчета для контроля выездов машин неоправданно усложнит структуру конфигурации: потребуется создание плана видов расчета и настройка сложных правил вытеснения. Кроме того, РР — это достаточно «тяжелый» объект, который может снизить общую производительность системы.

Регистр сведений (РС) является наиболее оптимальным выбором. Он прост в настройке, позволяет быстро извлекать данные и дает разработчику полный контроль над логикой проверки. Мы рекомендуем использовать непериодический регистр сведений. В качестве измерений укажем объект планирования (например, Автомобиль), а в качестве реквизитов или ресурсов — ДатаНачала и ДатаОкончания.

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

Разберем математическую логику проверки. Нам нужно понять, пересекается ли новый планируемый период (Период А) с уже существующим в базе (Период Б). Многие начинающие разработчики пытаются использовать сложные цепочки условий с И и ИЛИ, проверяя попадание каждой точки в интервал. На самом деле существует элегантное и универсальное условие пересечения:

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

Если это условие выполняется — периоды пересекаются. Рассмотрим подробнее, как это реализовать в запросе 1С. Предположим, мы передаем в запрос параметры &НовоеНачало и &НовыйКонец, а также &Автомобиль.


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

Важный момент: условие Заявка <> &ТекущаяЗаявка необходимо, чтобы при перепроведении существующей заявки система не находила «саму себя» как пересекающийся период.

Борьба с «гонкой данных» (Race Condition)

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

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


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

// Далее выполняем запрос на проверку пересечений...

Нюансы границ периодов

Выясним причину возможных логических ошибок при работе с границами. Считается ли пересечением ситуация, когда один выезд заканчивается ровно в то же время, когда начинается другой (например, в 12:00:00)?

  1. Если мы используем строгое сравнение (как в примере выше), то точка стыка не считается пересечением. Это удобно для плотного графика.
  2. Если специфика бизнеса требует технологического перерыва, стоит либо использовать нестрогое сравнение (<= и >=), либо прибавлять к ДатаОкончания определенный интервал времени.

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

Визуализация планирования

Посмотрим на задачу с точки зрения пользователя. Контроль при записи — это отлично, но диспетчеру удобнее видеть свободные «окна» визуально. Для этого в платформе 1С предусмотрен элемент управления формы «Планировщик».

Проанализируем шаги по его внедрению:

  1. Разместите элемент Планировщик на форме.
  2. Настройте его шкалу времени (например, с шагом в 30 минут).
  3. При открытии формы или изменении фильтров заполняйте его данными из нашего регистра сведений.
  4. Используйте событие ПриИзмененииСоставаДрагИДроп или ПриОкончанииРедактированияСоздания, чтобы программно вызывать тот же самый алгоритм проверки пересечений, который мы разработали для документа.

Альтернативное решение: Регистры накопления

Иногда, если задача подразумевает не просто «занят/свободен», а наличие некоторого количества ресурсов (например, в автопарке 5 одинаковых машин, и нам важно, чтобы в один период не выехало 6), лучше использовать РегистрНакопления. В этом случае мы контролируем не пересечение интервалов конкретных машин, а остаток доступных мощностей на шкале времени. Однако для индивидуального планирования конкретного транспортного средства связка Регистр Сведений + Запрос + Блокировка остается «золотым стандартом» разработки в 1С.

← На главную