В практике разработки на платформе 1С:Предприятие часто возникает задача: необходимо связать группу исходных документов с одним итоговым документом расчета. При этом основной вызов заключается в том, чтобы механизм заполнения документа расчета работал максимально быстро, корректно обрабатывал ситуацию отмены проведения и позволял легко отследить, какие документы еще «не закрыты» расчетом. Проанализируем различные архитектурные подходы, их преимущества и недостатки.
Рассмотрим вариант, предложенный автором темы. Для отслеживания связи создается непериодический (или периодический, если важна история) Регистр сведений. В качестве измерений выступает РассчитываемыйДокумент, а в качестве ресурса или реквизита — ДокументРасчета.
Разберем алгоритм работы этого механизма:
ДокументРасчета.ДокументРасчета = ЗНАЧЕНИЕ(Документ.Расчет.ПустаяСсылка).ДокументРасчета прописывается ссылка на текущий документ.Проанализируем ситуацию: этот метод хорош тем, что позволяет хранить историю и быстро получать список «свободных» документов. Однако важно помнить об индексации. Чтобы запрос работал быстро, поле ДокументРасчета должно быть индексируемым, иначе при большом объеме данных СУБД будет выполнять полное сканирование таблицы (Full Scan).
Хотя в обсуждении на форуме это упоминалось вскользь, в крупных типовых решениях (например, в ERP) для таких задач чаще используют Регистры накопления вида «Остатки». Этот подход считается наиболее профессиональным для реализации очередей на обработку.
Рассмотрим подробнее реализацию:
ОчередьДокументовКРасчету. Измерение — ДокументОснование.Почему это эффективно? Выясним причину: работа с виртуальной таблицей .Остатки() платформенно оптимизирована. Запрос к остаткам всегда вернет только те документы, которые еще не были рассчитаны (у которых «остаток» по измерению больше нуля). Это избавляет от необходимости проверять «пустые ссылки» в регистрах сведений.
// Пример запроса для получения нерассчитанных документов через Регистр Накопления
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ОчередьОстатки.ДокументОснование КАК Документ
|ИЗ
| РегистрНакопления.ОчередьДокументовКРасчету.Остатки(&МоментВремени, ) КАК ОчередьОстатки";
Проанализируем ситуацию, когда мы добавляем реквизит СтатусРасчета или ДокументРасчета непосредственно в исходный документ. Как отмечалось в сообщениях форума, это решение имеет право на жизнь, но оно сопряжено с серьезными накладными расходами.
Разберем по шагам, что происходит, если документ расчета обрабатывает сразу 300 документов:
Важный вывод: использование реквизитов внутри документа оправдано только в том случае, если расчет физически меняет данные в этом документе (как в примере с кадровыми документами и начислением зарплаты в ЗУП). Если же нам нужно просто «пометить» документ, использование регистров (РС или РН) будет гораздо оптимальнее.
Посмотрим на пример типовых конфигураций, где связь между накладной и счет-фактурой отслеживается через структуру подчиненности. Если в документе расчета есть табличная часть ДокументыОснования, мы можем настроить объект метаданных Критерий отбора.
Это позволит решить проблему «красивого отображения», о которой шла речь в сообщении 14. Настроив критерий отбора по реквизиту табличной части, пользователь сможет прямо из карточки исходного документа по кнопке «Связанные документы» увидеть, каким документом расчета он был подхвачен. При этом нам не нужно писать сложные запросы к ТЧ всех документов в системе — платформа сама оптимизирует поиск через индексы табличных частей.
Разберем критический момент, который часто упускают разработчики. Что произойдет, если два бухгалтера одновременно нажмут кнопку «Заполнить» в разных экземплярах документов расчета?
Без использования механизмов блокировок оба документа могут «увидеть» одни и те же нерассчитанные документы. Чтобы этого избежать, в процедуре заполнения необходимо использовать объект БлокировкаДанных.
// Пример установки блокировки перед получением данных для заполнения
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.СостоянияДокументов"); // или РегистрНакопления
ЭлементБлокировки.УстановитьЗначение("ДокументРасчета", Справочники.ДокументыРасчета.ПустаяСсылка());
Блокировка.Заблокировать();
// Далее выполняем запрос и заполняем ТЧ документа
Подводя итог анализу, можно выделить следующие правила выбора архитектуры:
Рассмотренные подходы позволяют создать гибкую и отказоустойчивую систему, которая будет корректно работать как при проведении, так и при отмене проведения документов, обеспечивая целостность данных в вашей информационной базе.