Не секрет, что создание процедуры перерасчета записей регистров расчета она из самых сложных задач по всей теме "Сложные периодические расчеты". Казалось бы, нет ничего сложного: получить набор записей того регистра расчета, записи которого следует пересчитать, сделать отбор по нужным регистраторам (их получить можно запросом к таблице перерасчета соответствующего регистра) и передать полученный набор записей в основную процедуру расчета. Но... При этом теряется основной смысл перерасчета: вместо того, чтобы пересчитать только те записи, которые действительно требуют перерасчета и которые записаны в таблицу перерасчета, будет произведен перерасчет по ВСЕМ записям документа. Конечно, можно пойти дальше и "доработать" обе процедуры (и расчета, и перерасчета) кодом, который будет производить "фильтрацию" только по нужным записям. Примеры таких процедур можно увидеть в различной литературе по 1С и на разных курсах по подготовке специалистов. Но такой код становится достаточно объемным и сложным для изучения.
Возникла мысль, а почему нельзя полностью сделать отбор в самой процедуре перерасчета и передавать для расчета только "нужный" набор. Но здесь можно столкнуться с трудностями: Набор записей - это единая сущность (объект системы), которая должна читаться и записываться только полностью. Это ограничение можно обойти, используя некоторый "искусственный" прием.
Мне удалось сделать процедуру перерасчета с сортировкой на уровне набора записей. В общий модуль (процедуру расчета) передается набор только тех записей, которые требуют перерасчета. Остальные записи (которые не надо перерассчитывать) впоследствии "дозаписываются" к перерассчитанным. Сама процедура расчета (в общем модуле) остается НЕИЗМЕННОЙ (совершенно одинаковой: используются перерасчеты или нет) и в ней ничего менять не нужно! Проверил - все работает. По-моему все красиво! И объем кода минимальный.
Привожу пример процедуры перерасчета для регистра расчета "ДополнительныеНачисления" (релиз платформы 8.3.18.1128):
&НаСервереБезКонтекста
Процедура ПерессчитатьНаСервере()
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Перерасчет.ОбъектПерерасчета КАК Регистратор,
| Перерасчет.ОбъектПерерасчета.Дата КАК Дата,
| ДополнительныеНачисления.НомерСтроки КАК НомерСтроки
|ИЗ
| РегистрРасчета.ДополнительныеНачисления.Перерасчет КАК Перерасчет
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрРасчета.ДополнительныеНачисления КАК ДополнительныеНачисления
| ПО Перерасчет.ОбъектПерерасчета = ДополнительныеНачисления.Регистратор
| И Перерасчет.ВидРасчета = ДополнительныеНачисления.ВидРасчета
| И Перерасчет.Сотрудник = ДополнительныеНачисления.Сотрудник
| И Перерасчет.Подразделение = ДополнительныеНачисления.Подразделение
|
|УПОРЯДОЧИТЬ ПО
| НомерСтроки
|ИТОГИ ПО
| Регистратор";
РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
ВыборкаРегистратор = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
НачатьТранзакцию();
Пока ВыборкаРегистратор.Следующий() Цикл
ДополнительныеНачисления = РегистрыРасчета.ДополнительныеНачисления.СоздатьНаборЗаписей();
ДополнительныеНачисления.Отбор.Регистратор.Установить(ВыборкаРегистратор.Регистратор);
ДополнительныеНачисления.Прочитать();
ТЗНеРассчитываемые = ДополнительныеНачисления.Выгрузить();
ТЗПерерасчет = Новый ТаблицаЗначений;
МассивСтрок = Новый Массив;
ВыборкаДетальныеЗаписи = ВыборкаРегистратор.Выбрать();
Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
НайденнаяСтрока = ТЗНеРассчитываемые.Найти(ВыборкаДетальныеЗаписи.НомерСтроки, "НомерСтроки");
МассивСтрок.Добавить(НайденнаяСтрока);
КонецЦикла;
ТЗПерерасчет = ТЗНеРассчитываемые.Скопировать(МассивСтрок);
ТЗПерерасчет.Сортировать("НомерСтроки");
ДополнительныеНачисления.Загрузить(ТЗПерерасчет);
ДополнительныеНачисления.Записать();
Расчеты.РассчитатьДополнительныеНачисления(ВыборкаРегистратор.Регистратор, ДополнительныеНачисления, НачалоМесяца(ВыборкаРегистратор.Дата));
Для каждого Строка Из МассивСтрок Цикл
ТЗНеРассчитываемые.Удалить(Строка);
КонецЦикла;
ДополнительныеНачисления.Загрузить(ТЗНеРассчитываемые);
ДополнительныеНачисления.Записать(Ложь);
КонецЦикла;
Если ТранзакцияАктивна() Тогда
ЗафиксироватьТранзакцию();
КонецЕсли;
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура Перессчитать(Команда)
ПерессчитатьНаСервере();
КонецПроцедуры