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