Как оптимально организовать выборку и отслеживание необработанных документов для расчета?

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

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

Метод 1: Использование регистра сведений (подход «Реестр состояний»)

Рассмотрим вариант, предложенный автором темы. Для отслеживания связи создается непериодический (или периодический, если важна история) Регистр сведений. В качестве измерений выступает РассчитываемыйДокумент, а в качестве ресурса или реквизита — ДокументРасчета.

Разберем алгоритм работы этого механизма:

  1. При записи или проведении исходного документа создается запись в регистре с пустым значением ДокументРасчета.
  2. При заполнении документа расчета выполняется запрос к виртуальной таблице регистра с фильтром ДокументРасчета = ЗНАЧЕНИЕ(Документ.Расчет.ПустаяСсылка).
  3. При проведении документа расчета записи в регистре обновляются: в поле ДокументРасчета прописывается ссылка на текущий документ.

Проанализируем ситуацию: этот метод хорош тем, что позволяет хранить историю и быстро получать список «свободных» документов. Однако важно помнить об индексации. Чтобы запрос работал быстро, поле ДокументРасчета должно быть индексируемым, иначе при большом объеме данных СУБД будет выполнять полное сканирование таблицы (Full Scan).

Метод 2: Использование регистра накопления (метод «Очереди»)

Хотя в обсуждении на форуме это упоминалось вскользь, в крупных типовых решениях (например, в ERP) для таких задач чаще используют Регистры накопления вида «Остатки». Этот подход считается наиболее профессиональным для реализации очередей на обработку.

Рассмотрим подробнее реализацию:

  1. Создаем регистр накопления (остатки), например, ОчередьДокументовКРасчету. Измерение — ДокументОснование.
  2. Исходный документ при проведении делает движение Приход.
  3. Документ расчета при проведении делает движение Расход по тем документам, которые он включил в свой состав.

Почему это эффективно? Выясним причину: работа с виртуальной таблицей .Остатки() платформенно оптимизирована. Запрос к остаткам всегда вернет только те документы, которые еще не были рассчитаны (у которых «остаток» по измерению больше нуля). Это избавляет от необходимости проверять «пустые ссылки» в регистрах сведений.


// Пример запроса для получения нерассчитанных документов через Регистр Накопления
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ОчередьОстатки.ДокументОснование КАК Документ
    |ИЗ
    |	РегистрНакопления.ОчередьДокументовКРасчету.Остатки(&МоментВремени, ) КАК ОчередьОстатки";

Метод 3: Использование статусов и реквизитов в самом документе

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

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

  1. Программа должна программно открыть и перезаписать 300 объектов.
  2. При каждой записи будут срабатывать подписки на события, проверки в модулях объекта, пересчеты итогов и т.д.
  3. Это создает огромную нагрузку на транзакционную модель и может привести к блокировкам базы данных.

Важный вывод: использование реквизитов внутри документа оправдано только в том случае, если расчет физически меняет данные в этом документе (как в примере с кадровыми документами и начислением зарплаты в ЗУП). Если же нам нужно просто «пометить» документ, использование регистров (РС или РН) будет гораздо оптимальнее.

Метод 4: Табличные части и структура подчиненности

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

Это позволит решить проблему «красивого отображения», о которой шла речь в сообщении 14. Настроив критерий отбора по реквизиту табличной части, пользователь сможет прямо из карточки исходного документа по кнопке «Связанные документы» увидеть, каким документом расчета он был подхвачен. При этом нам не нужно писать сложные запросы к ТЧ всех документов в системе — платформа сама оптимизирует поиск через индексы табличных частей.

Проблема конкурентного заполнения и управляемые блокировки

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

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


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

// Далее выполняем запрос и заполняем ТЧ документа

Резюме и рекомендации

Подводя итог анализу, можно выделить следующие правила выбора архитектуры:

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

← На главную