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

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

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

Почему стандартный отбор не работает

Рассмотрим типичную ошибку начинающего разработчика. При попытке программно отобрать данные напрямую через объект РегистрРасчетаНаборЗаписей, многие пытаются обратиться к полям периода в свойстве Отбор, например, так:


// Ошибочный код
ОВр = РегистрыРасчета.Начисления.СоздатьНаборЗаписей();
ОВр.Отбор.ПериодДействияКонец.Установить(НужнаяДата); // Вызовет ошибку

Проанализируем причину неудачи. В платформе 1С объект НаборЗаписей для регистров расчета имеет жестко ограниченный список доступных полей в свойстве Отбор. В большинстве случаев фильтрация возможна только по полю Регистратор. В некоторых конфигурациях могут быть доступны измерения, если для них в метаданных включено свойство «Индексировать». Поля ПериодДействия, ПериодРегистрации или их составляющие (начало/конец) никогда не входят в состав доступных полей отбора набора записей. Это системное ограничение платформы.

Различие периодов: что именно мы удаляем?

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

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

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

Алгоритм решения задачи

Единственный штатный и корректный способ очистить записи регистра за период — это действовать через регистраторы. Разберем этот процесс по шагам:

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

Реализация решения в коде

Посмотрим на пример кода, который реализует данный алгоритм. Предположим, нам нужно удалить все записи из регистра расчета Начисления за определенный период регистрации.


Процедура УдалитьЗаписиРегистраЗаПериод(ДатаНачала, ДатаКонца)
    
    // Шаг 1: Подготовка запроса для поиска регистраторов
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ РАЗЛИЧНЫЕ
        |   Начисления.Регистратор КАК Регистратор
        |ИЗ
        |   РегистрРасчета.Начисления КАК Начисления
        |ГДЕ
        |   Начисления.ПериодРегистрации МЕЖДУ &ДатаНачала И &ДатаКонца";
    
    Запрос.УстановитьПараметр("ДатаНачала", ДатаНачала);
    Запрос.УстановитьПараметр("ДатаКонца", ДатаКонца);
    
    Выборка = Запрос.Выполнить().Выбрать();
    
    // Шаг 2: Цикл по найденным документам
    Пока Выборка.Следующий() Цикл
        
        // Создаем набор записей для конкретного регистратора
        НаборЗаписей = РегистрыРасчета.Начисления.СоздатьНаборЗаписей();
        НаборЗаписей.Отбор.Регистратор.Установить(Выборка.Регистратор);
        
        // Шаг 3: Запись пустого набора (фактическое удаление)
        // Параметр Истина в методе Записать() означает, что существующие 
        // в базе данные будут замещены текущим (пустым) набором.
        Попытка
            НаборЗаписей.Записать(Истина);
        Исключение
            ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Не удалось очистить записи по документу: " + Выборка.Регистратор);
        КонецПопытки;
        
    КонецЦикла;
    
КонецПроцедуры

Оптимизация при работе с большими данными

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

Использование режима загрузки данных:
Чтобы платформа не выполняла лишние проверки в модуле набора записей и не инициировала сложные пересчеты (если это допустимо в вашей ситуации), можно использовать свойство ОбменДанными.Загрузка.


НаборЗаписей = РегистрыРасчета.Начисления.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(Выборка.Регистратор);
НаборЗаписей.ОбменДанными.Загрузка = Истина; 
НаборЗаписей.Записать(Истина);

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

Важные нюансы и механизм вытеснения

Выясним причину, почему нельзя просто «удалить строку» из регистра расчета. Регистры расчета часто используют механизм вытеснения (например, когда запись «Больничный» вытесняет «Оклад»). Когда мы удаляем запись через Записать(Истина), платформа автоматически пересчитывает фактический период действия у других записей, которые были связаны с удаляемой.

Если вы используете ручное удаление записей из таблицы (как пытался автор в Сообщении 0 через ОВР.Удалить(Запись)), вы рискуете нарушить целостность данных, если забудете вызвать финальный метод Записать(). Но даже в этом случае, метод Прочитать() загрузит в память все записи документа, что при миллионах строк приведет к критическому потреблению оперативной памяти. Именно поэтому очистка через пустой набор с отбором по регистратору является самым быстрым и безопасным методом.

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

← На главную