При работе в распределенных информационных базах (РИБ) на базе современных конфигураций 1С (таких как 1С:Управление торговлей 11, 1С:Комплексная автоматизация 2 или 1С:ERP Управление предприятием) администраторы и программисты часто сталкиваются со специфической ошибкой при попытке удалить помеченные объекты. Система прерывает транзакцию и выдает сообщение вида: «Не удалось записать: Задания к формированию записей книги покупок/продаж» или «Не удалось записать: Задания к распределению расчетов с клиентами».
В этой статье мы подробно разберем, почему возникает данная ошибка, как устроен механизм контроля ссылочной целостности платформы 1С:Предприятие и какими способами можно решить эту проблему как на стороне разработчика, так и на стороне администратора системы.
---
Для начала проанализируем архитектурную логику, заложенную разработчиками фирмы «1С» в механизмы распределенных баз. Регистры сведений, на которые ругается система при удалении документов, — это так называемые регистры заданий. К ним относятся:
РегистрСведений.ЗаданияКРаспределениюРасчетовСКлиентамиРегистрСведений.ЗаданияКРаспределениюРасчетовСПоставщикамиРегистрСведений.ЗаданияКРасчетуСебестоимостиРегистрСведений.ЗаданияКФормированиюЗаписейКнигиПокупокПродажЭти регистры служат «сигналами» для регламентных заданий (например, для закрытия месяца, распределения взаиморасчетов или расчета себестоимости). Согласно методологии 1С, все тяжелые финансовые расчеты должны выполняться строго в центральном (главном) узле РИБ. Подчиненные узлы предназначены только для оперативного ввода первичных документов.
Чтобы исключить случайный запуск или формирование этих заданий на периферии, разработчики жестко заблокировали возможность записи в эти регистры на стороне подчиненных узлов. В модулях набора записей этих регистров в обработчике ПередЗаписью прописан следующий код:
Если ПланыОбмена.ГлавныйУзел() <> Неопределено Тогда
Отказ = Истина;
Возврат;
КонецЕсли;
Если текущая база является подчиненным узлом (то есть метод ПланыОбмена.ГлавныйУзел() возвращает ссылку на главный узел, а не значение Неопределено), то любая попытка записи в регистр вызывает отказ и отмену транзакции.
---
Часто при анализе этой ошибки через консоль запросов выясняется, что указанные регистры сведений абсолютно пустые и не содержат никаких записей, связанных с удаляемым документом. Возникает логичный вопрос: почему же система пытается туда что-то записать?
Дело в особенностях работы платформы при удалении объектов и механизмов очистки движений Библиотеки Стандартных Подсистем (БСП):
УдалитьОбъекты().Расходный кассовый ордер) во всех таблицах базы данных.Записать().ПередЗаписью в модуле набора записей соответствующего регистра.Отказ устанавливается в значение Истина, и транзакция удаления аварийно завершается.Рассмотрим четыре практических способа решения этой проблемы: от простых административных обходов до программных правок.
---
Если вам нужно оперативно удалить объекты непосредственно в подчиненном узле и вы не хотите менять код конфигурации, можно временно «обмануть» систему, заставив ее думать, что база является автономной.
Разберем по шагам, как это сделать:
// Отключаем признак подчиненного узла РИБ
ПланыОбмена.УстановитьГлавныйУзел(Неопределено);
Отказ = Истина.
// Восстанавливаем связь с главным узлом.
// СсылкаНаУзел - это ссылка на элемент плана обмена, соответствующий головной базе.
СсылкаНаУзел = ПланыОбмена.НайтиПоКоду("КодГлавногоУзла"); // Укажите реальный код вашего узла
Если ЗначениеЗаполнено(СсылкаНаУзел) Тогда
ПланыОбмена.УстановитьГлавныйУзел(СсылкаНаУзел);
КонецЕсли;
Важно: во время отключенного состояния узла не рекомендуется вводить новые документы во избежание рассинхронизации кодов и номеров документов.
---
Если удаление помеченных объектов в подчиненных базах требуется выполнять регулярно, постоянное отключение и подключение главного узла становится неудобным. В этом случае лучшим решением будет создание небольшого расширения конфигурации.
Мы можем перехватить событие ПередЗаписью в проблемных регистрах сведений с помощью аннотации &Вместо или &Перед. Наша задача — разрешить запись набора, если он пустой (то есть происходит попытка очистки движений при удалении).
Рассмотрим пример кода для расширения модуля набора записей регистра сведений:
&Вместо("ПередЗаписью")
Процедура Ист_ПередЗаписью(Отказ, Замещение)
// Если набор записей пустой, то разрешаем запись даже в подчиненном узле РИБ
Если ЭтотОбъект.Количество() = 0 Тогда
Возврат;
КонецЕсли;
// Если в наборе есть записи, то выполняем стандартную проверку конфигурации
ПродолжитьВызов(Отказ, Замещение);
КонецПроцедуры
При таком подходе основная конфигурация остается на полной поддержке, а проблема с удалением объектов в периферийных базах исчезает навсегда.
---
С точки зрения методологии разработчиков 1С, удаление любых объектов должно происходить централизованно. Рассмотрим правильный жизненный цикл удаления данных в распределенной системе:
ОбменДанными.Загрузка установлено в значение Истина, что заставляет систему игнорировать любые прикладные проверки в модулях объектов и регистров.---
Если база уже снята с поддержки или находится на доработке, вы можете внести изменения непосредственно в код модулей наборов записей проблемных регистров сведений. Для этого найдите процедуру ПередЗаписью в модулях следующих регистров:
РегистрСведений.ЗаданияКРаспределениюРасчетовСКлиентамиРегистрСведений.ЗаданияКРаспределениюРасчетовСПоставщикамиРегистрСведений.ЗаданияКРасчетуСебестоимостиРегистрСведений.ЗаданияКФормированиюЗаписейКнигиПокупокПродажПроанализируем код проверки и закомментируем строки, вызывающие отказ при записи:
// Процедура ПередЗаписью в модуле набора записей
Процедура ПередЗаписью(Отказ, Замещение)
// Блокируем стандартный отказ для обхода ошибки удаления
// Если ПланыОбмена.ГлавныйУзел() <> Неопределено Тогда
// Отказ = Истина;
// Возврат;
// КонецЕсли;
КонецПроцедуры
Обратите внимание: данный способ крайне не рекомендуется использовать на типовых конфигурациях, так как при последующем обновлении программы эти изменения могут быть затерты, либо вам придется вручную объединять код модулей при каждом обновлении.
---
Мы подробно разобрали природу ошибки «Не удалось записать...» при очистке регистров заданий в РИБ. Для разового решения проблемы оптимально использовать Способ 1 (временное отключение связи с главным узлом), а для системного и автоматизированного решения в активно развивающихся базах лучше всего применить Способ 2 с созданием расширения конфигурации.