В современных конфигурациях 1С, таких как 1С:ERP Управление предприятием, 1С:Комплексная автоматизация (КА) 2 и 1С:Управление торговлей (УТ) 11, разработчики применили механизм отложенного проведения расчетов с клиентами и поставщиками. Этот механизм позволяет не перегружать систему тяжелыми вычислениями (такими как распределение авансов по FIFO, зачет оплат и расчет сроков долга) непосредственно в момент проведения первичных документов. Вместо этого система делает быструю запись в специальный регистр заданий, а само распределение выполняется позже в фоновом режиме.
Однако на практике многие администраторы и программисты 1С сталкиваются с ситуацией, когда в регистре сведений ЗаданияКРаспределениюРасчетовСКлиентами годами висят старые необработанные записи. Проанализируем, почему это происходит, чем это грозит системе и как решить эту проблему раз и навсегда.
Регистр сведений ЗаданияКРаспределениюРасчетовСКлиентами — это технический буфер (очередь задач). При проведении накладной, платежного поручения или корректировки долга в этот регистр записывается информация о том, что по конкретному партнеру, организации и соглашению за определенный месяц требуется пересчитать взаиморасчеты.
Регламентное задание «Выполнение отложенных движений по расчетам с клиентами» регулярно запускается по расписанию, считывает накопленные задания из регистра, выполняет детальный расчет и удаляет отработанные записи из очереди. В идеальном состоянии этот регистр должен быть пустым (или содержать записи только за самый последний период, по которому еще ведется оперативная работа).
Если в регистре «зависли» старые записи (например, за прошлые годы), это серьезная техническая проблема. Она приводит к следующим последствиям:
МИНИМУМ(Задания.Месяц)). Если у вас «висит» забытая запись за 2019 год, система при каждом новом расчете или проведении текущих документов будет пытаться анализировать и пересчитывать цепочки расчетов начиная с 2019 года по сегодняшний день. Это создает колоссальную и бесполезную нагрузку на СУБД.---
Разберем детально программный баг в логике работы механизма распределения расчетов, с которым столкнулись разработчики на форуме. Обратим внимание на функцию НачалоРасчета в модуле закрытия месяца:
Функция НачалоРасчета(ИмяРегистраЗаданий, ОкончаниеРасчета, АналитикиРасчета, НомерЗадания = 0)
ТекстЗапроса =
"ВЫБРАТЬ
| МИНИМУМ(Задания.Месяц) КАК НачалоПериодаРасчета
|ИЗ
| ИмяРегистраЗаданий КАК Задания
|ГДЕ
| Задания.Месяц <= &ОкончаниеРасчета
| И (Задания.АналитикаУчетаПоПартнерам В (&АналитикиУчетаПоПартнерам)
| ИЛИ &ПоВсемАналитикам)
| И (Задания.Организация В (&Организации)
| ИЛИ &ПоВсемОрганизациям)
| И (Задания.НомерЗадания <= &НомерЗадания
| ИЛИ &ПоВсемНомерамЗаданий)
|ИМЕЮЩИЕ
| НЕ (МИНИМУМ(Задания.Месяц) ЕСТЬ NULL)";
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ИмяРегистраЗаданий", "РегистрСведений." + ИмяРегистраЗаданий);
Запрос = Новый Запрос(ТекстЗапроса);
Запрос.УстановитьПараметр("ОкончаниеРасчета", ОкончаниеРасчета);
// ... Установка остальных параметров ...
Запрос.УстановитьПараметр("НомерЗадания", НомерЗадания);
Запрос.УстановитьПараметр("ПоВсемНомерамЗаданий", НомерЗадания = 0);
Выборка = Запрос.Выполнить.Выбрать;
Возврат ?(Выборка.Следующий, Выборка.НачалоПериодаРасчета, КонецМесяца(ОкончаниеРасчета) + 1);
КонецФункции
В чем заключается проблема?
При запуске автоматического распределения через фоновое регламентное задание параметр НомерЗадания по умолчанию передается равным 0. В этом случае срабатывает условие отбора по всем номерам заданий. Однако при определенных условиях вычисление минимального периода расчета дает сбой, возвращая дату, равную ОкончаниеРасчета (например, 01.05.2019), в то время как в регистре реально есть более старые записи.
Затем в основном коде распределения запускается цикл по обработке периодов:
ПервыйПроход = Истина;
Пока НачалоПериода < ОкончаниеПериодаРасчета Цикл
// Выполнение расчетов за месяц...
// ...
КонецЦикла;
Если функция НачалоРасчета из-за некорректных параметров или логических коллизий вернула дату НачалоПериода, равную ОкончаниеПериодаРасчета, то условие цикла НачалоПериода < ОкончаниеПериодаРасчета возвращает ложь при первом же сравнении. Цикл распределения не отрабатывает ни разу! Из-за этого старые задания так и остаются лежать мертвым грузом в регистре сведений, а новые документы продолжают накапливаться.
Для исправления этой проблемы в коде (если вы используете старые релизы конфигураций до перехода на новые версии взаиморасчетов) можно принудительно инициализировать НомерЗадания, если он пришел равным нулю. Для этого перед вызовом основного запроса функции НачалоРасчета определим максимальный существующий номер задания в регистре:
// Доработка механизма определения номера задания
Если НомерЗадания = 0 И ИмяРегистраЗаданий = "ЗаданияКРаспределениюРасчетовСКлиентами" Тогда
ЗапросНЗ = Новый Запрос;
ЗапросНЗ.Текст =
"ВЫБРАТЬ
| МАКСИМУМ(Задания.НомерЗадания) КАК НомерЗадания
|ИЗ
| РегистрСведений.ЗаданияКРаспределениюРасчетовСКлиентами КАК Задания";
РезультатЗапроса = ЗапросНЗ.Выполнить();
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
Если ВыборкаДетальныеЗаписи.Следующий() Тогда
Если ЗначениеЗаполнено(ВыборкаДетальныеЗаписи.НомерЗадания) Тогда
НомерЗадания = ВыборкаДетальныеЗаписи.НомерЗадания;
КонецЕсли;
КонецЕсли;
КонецЕсли;
Этот нехитрый прием позволяет корректно обойти ошибку инициализации параметров при запуске распределения из фонового режима и запустить цикл перерасчета по всем зависшим старым записям.
---
Даже при полностью исправном коде задания могут зависнуть по более банальным «эксплуатационным» причинам:
---
Рассмотрим, как вернуть систему в рабочее состояние и очистить зависший регистр без вреда для сданной отчетности.
Если причиной зависания стали битые ссылки, необходимо выполнить логическую проверку базы данных. Перед процедурой обязательно создайте резервную копию базы!
Если прошлые годы (например, 2018–2022 гг.) уже полностью закрыты, проверены, декларации сданы, и вы не планируете ничего там пересчитывать, лучшим и самым безопасным решением будет полная ручная очистка регистра заданий за эти закрытые периоды. Это уберет «якорь», который заставлял фоновое задание при каждом запуске тратить ресурсы сервера на анализ старых периодов.
Для этого можно написать простую внешнюю обработку со следующим кодом удаления записей старше определенной даты:
ГраницаОчистки = '20230101000000'; // Все задания до 1 января 2023 года удаляем
НаборЗаписей = РегистрыСведений.ЗаданияКРаспределениюРасчетовСКлиентами.СоздатьНаборЗаписей();
// Выбираем только старые записи, чтобы удалить их
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗЛИЧНЫЕ
| Задания.Месяц КАК Месяц,
| Задания.Организация КАК Организация,
| Задания.АналитикаУчетаПоПартнерам КАК АналитикаУчетаПоПартнерам
|ИЗ
| РегистрСведений.ЗаданияКРаспределениюРасчетовСКлиентами КАК Задания
|ГДЕ
| Задания.Месяц < &ГраницаОчистки";
Запрос.УстановитьПараметр("ГраницаОчистки", ГраницаОчистки);
ТаблицаСтарыхЗаписей = Запрос.Выполнить().Выгрузить();
Для Каждого СтрокаЗаписи Из ТаблицаСтарыхЗаписей Цикл
НаборЗаписей.Отбор.Месяц.Установить(СтрокаЗаписи.Месяц);
НаборЗаписей.Отбор.Организация.Установить(СтрокаЗаписи.Организация);
НаборЗаписей.Отбор.АналитикаУчетаПоПартнерам.Установить(СтрокаЗаписи.АналитикаУчетаПоПартнерам);
// Записываем пустой набор, тем самым удаляя конкретную запись
НаборЗаписей.Записать(Истина);
КонецЦикла;
После удаления старых «хвостов» регламентное задание начнет выполняться мгновенно, так как ему больше не придется лопатить гигабайты старых исторических данных.
В конфигурациях 1С последних версий встроен специальный инструмент для борьбы со сбоями распределения. При закрытии месяца обязательно обратите внимание на регламентную операцию «Контроль и устранение разрывов расчетов с партнерами». Эта операция сравнивает оперативные регистры расчетов с детализированными и автоматически генерирует исправления, устраняя «подвисшие» остатки и распределения.
В версиях ERP / КА / УТ линеек 2.4 / 11.4 и старше механизмы расчетов с клиентами и поставщиками были разделены на разные регистры (ЗаданияКРаспределениюРасчетовСКлиентами и ЗаданияКРаспределениюРасчетовСПоставщиками).
В новых линейках решений (начиная с 2.5 / 11.5) фирма «1С» полностью переработала архитектуру. Теперь используется единый регистр сведений «Задания к распределению расчетов», а алгоритмы онлайн-распределения стали гораздо более отказоустойчивыми и оптимизированными по скорости. При обновлении конфигурации на современные релизы система автоматически перенесет данные, исправив большинство застарелых ошибок распределения прошлых периодов.