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