При работе с конфигурацией 1С:Зарплата и Управление Персоналом 3.1 многие разработчики и опытные пользователи замечают странное, на первый взгляд, поведение: при обычном формировании отчета ОстаткиОтпусков система инициирует движения (запись) в базе данных. Согласно классической методологии 1С, отчеты должны предназначаться исключительно для чтения и визуализации данных. Однако в данном случае мы сталкиваемся с тем, что в процедуре ПриКомпоновкеРезультата происходит активная запись в регистры. Разберем подробно, почему так происходит, насколько это оправдано и какие механизмы за этим стоят.
Выясним причину такого поведения системы. Расчет остатков отпусков в ЗУП 3.1 — это одна из самых ресурсоемких операций. Системе необходимо проанализировать огромное количество кадровых документов: приказы о приеме, переводы, прогулы, фактически использованные отпуска и корректировки. Если выполнять этот расчет «на лету» (в режиме реального времени) для каждого сотрудника при каждом формировании отчета, время ожидания результата станет неприемлемым для пользователя.
Для оптимизации производительности разработчики 1С применили механизм кэширования. Данные о правах на отпуска хранятся в специализированном регистре сведений ЗаработанныеПраваНаОтпуска. Рассмотрим, что происходит в момент нажатия кнопки «Сформировать»:
ЗаработанныеПраваНаОтпуска на дату формирования отчета.ПриКомпоновкеРезультата отчет понимает, что выводить устаревшие цифры нельзя, и инициирует процедуру актуализации (пересчета) данных именно по тем сотрудникам, которые попадают в отчет.Проанализируем ситуацию с точки зрения методологии. Действительно, стандартные правила разработки 1С гласят, что отчет не должен менять состояние базы. Однако в случае с ЗУП мы имеем дело с «Расчетом по требованию». Разработчики 1С выбрали этот путь как компромисс (Trade-off) между чистотой архитектуры и скоростью работы программы.
В системе существует регламентное задание Обновление данных о правах на отпуска. В идеальной ситуации оно должно отрабатывать в фоновом режиме, незаметно для пользователя обновляя кэш. Но если регламентное задание не успело сработать или выключено, отчет берет на себя роль «двигателя», который актуализирует данные перед показом. Таким образом, отчет здесь выступает не просто как визуализатор, а как часть системы оперативной подготовки данных.
Посмотрим на пример того, как можно управлять этим поведением через интерфейс. В настройках производительности (раздел «Настройка» — «Сервис» — «Настройки расчета зарплаты») существует опция «Выполнять расчет остатков отпусков в фоновом режиме». Рассмотрим влияние этой настройки:
Если настройка включена, система старается делегировать запись данных фоновому заданию. Однако, если пользователь формирует отчет «здесь и сейчас», а данные еще не готовы, отчет может форсировать запись в привилегированном режиме, чтобы избежать вывода некорректных остатков. Если же данных крайне много, пользователь может увидеть сообщение о том, что данные готовятся.
Рассмотрим упрощенный пример того, как может выглядеть вызов актуализации данных в модуле объекта отчета. Хотя основной код скрыт в общих модулях, логика процедуры ПриКомпоновкеРезультата сводится к следующему алгоритму:
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
// 1. Проверяем, нужно ли обновлять данные
Если НужноОбновитьОстаткиОтпусков() Тогда
// 2. Вызываем метод, который произведет расчет и запись в регистр
ОстаткиОтпусков.АктуализироватьДанныеПоСотрудникам(ПараметрыОтчета);
КонецЕсли;
// 3. Продолжаем стандартное формирование отчета,
// который теперь возьмет готовые данные из регистра
...
КонецПроцедуры
Именно использование метода АктуализироватьДанныеПоСотрудникам и приводит к возникновению транзакций записи при открытии или формировании отчета.
Разберем, к чему может привести такое архитектурное решение в реальной эксплуатации:
ЗаработанныеПраваНаОтпуска. Это приводит к ошибкам «Конфликт блокировок при выполнении транзакции».УстановитьПривилегированныйРежим(Истина)), но в кастомизированных базах это может вызвать ошибки прав доступа, если доработки сделаны некорректно.Выясним, является ли этот случай уникальным. На самом деле, подобная логика встречается и в других блоках ЗУП 3.1:
Резюме: Запись данных в отчете «Остатки отпусков» — это не ошибка и не нарушение методологии со стороны разработчиков 1С, а осознанное архитектурное решение. Оно позволяет обеспечить актуальность данных при сохранении высокой скорости работы системы за счет использования кэширующего регистра ЗаработанныеПраваНаОтпуска.