Как предотвратить перезапись реквизитов при повторной синхронизации и почему изменения в 1С загружаются только со второго раза?

Программист 1С v8.3 (Управляемые формы) 1C:Бухгалтерия Бухгалтерский учет IT и автоматизация бизнеса
← На главную

При организации регулярного обмена данными между конфигурациями на платформе 1С:Предприятие (например, при переносе документов из управленческой базы в бухгалтерскую) разработчики часто сталкиваются с конфликтами совместного изменения данных. Типичный сценарий: документ загружается в базу-приемник, бухгалтеры вручную заполняют в нем счета учета и аналитику, но при повторной выгрузке из источника все ручные правки затираются. Еще более загадочной выглядит ситуация, когда изменения табличных частей применяются в приемнике только со второго раза.

В этой статье мы подробно разберем оба сценария, проанализируем архитектурные особенности механизмов обмена (как КД 2.1, так и КД 3.0) и предложим надежные программные решения для предотвращения перезаписи критически важных данных.

Часть 1. Предотвращение перезаписи документов и реквизитов в базе-приемнике

Рассмотрим ситуацию, когда нам необходимо защитить уже существующий и проверенный бухгалтером документ от изменений при повторной синхронизации. Существует несколько способов реализации этой логики в зависимости от используемой версии технологии «Конвертации данных».

Почему стандартный Отказ = Истина в обработчике «ПослеЗагрузки» — это плохая идея?

На форумах часто советуют использовать обработчик ПослеЗагрузки правила конвертации объекта (ПКО) и взводить флаг Отказ = Истина, если объект уже существует и помечен признаком «не обновлять». Проанализируем, почему этот подход использовать не рекомендуется:

Решение для КД 2.x: Использование параметра НеЗамещатьОбъект

Для корректного решения задачи в КД 2.1 воспользуемся обработчиком ПКО ПередЗагрузкой (или ПриЗагрузке). В этих обработчиках нам доступен параметр ОбъектНайден, указывающий на наличие объекта в информационной базе приемника, а также параметр НеЗамещатьОбъект.

Рассмотрим пример кода, который проверяет состояние флага «Загружать/пропустить» (например, реквизит документа ПроверенБухгалтером) непосредственно в базе-приемнике, не затирая данные:


// Обработчик ПКО "ПередЗагрузкой"
Если ОбъектНайден Тогда
    // Считываем значение признака напрямую из базы данных приемника без полной загрузки объекта
    НужноОбновлять = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ссылка, "ПроверенБухгалтером");
    
    // Если бухгалтер уже проверил и утвердил документ, запрещаем его перезапись
    Если НужноОбновлять = Истина Тогда
        НеЗамещатьОбъект = Истина;
    КонецЕсли;
КонецЕсли;

При таком подходе новые документы будут создаваться без препятствий, а уже существующие и проверенные — просто пропускаться при чтении файла обмена без генерации ошибок в журнале.

Частичное обновление: Защита конкретных реквизитов (счетов учета и субконто)

Зачастую пользователям нужно, чтобы ключевые реквизиты документа (например, количество или сумма) обновлялись при изменении в источнике, но заполненные вручную счета учета в бухгалтерии при этом сохранялись. Выясним, как решить эту задачу.

Способ А. Через настройки ПКС (Правила конвертации свойств):
В интерфейсе «Конвертации данных 2.1» выберите нужное свойство (например, СчетУчета) внутри ПКО и перейдите в его настройки. Установите флаг «Не замещать существующие значения в приемнике при загрузке». В этом случае свойство перенесется только для новых документов.

Способ Б. Программный в обработчике «ПослеЗагрузки» ПКО:
Если логика сохранения реквизитов более сложная, мы можем восстановить старые значения реквизитов из базы-приемника прямо перед записью объекта:


// Обработчик ПКО "ПослеЗагрузки"
Если ОбъектНайден Тогда
    // Запрашиваем структуру старых значений из БД
    СтарыеЗначения = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(Ссылка, "СчетУчета, Субконто1");
    
    // Если счета учета в приемнике были заполнены, возвращаем их в загруженный Объект
    Если ЗначениеЗаполнено(СтарыеЗначения.СчетУчета) Тогда
        Объект.СчетУчета = СтарыеЗначения.СчетУчета;
        Объект.Субконто1 = СтарыеЗначения.Субконто1;
    КонецЕсли;
КонецЕсли;

Решение для Конвертации данных 3.0 (EnterpriseData)

В КД 3.0 архитектура обмена базируется на менеджерах обмена через формат EnterpriseData. Здесь вся логика обработки полученных данных сосредоточена в обработчике ПередЗаписьюПолученныхДанных общего модуля менеджера обмена.

Нам доступны параметры ПолученныеДанные (то, что пришло в XML/JSON) и ДанныеИБ (версия объекта, уже хранящаяся в СУБД приемника). Если объект существует в приемнике, параметр ДанныеИБ будет заполнен. Нам достаточно выполнить следующую проверку:


// Обработчик ПередЗаписьюПолученныхДанных
Если ДанныеИБ <> Неопределено Тогда
    // Если в существующем документе приемника установлен флаг блокировки изменений
    Если ДанныеИБ.ПроверенБухгалтером Тогда
        // Приравниваем полученные данные к Неопределено. 
        // Это полностью отменит запись изменений в СУБД без вызова ошибок.
        ПолученныеДанные = Неопределено;
    КонецЕсли;
КонецЕсли;

---

Часть 2. Почему изменения загружаются только со второго раза?

Теперь проанализируем вторую, крайне специфическую проблему обмена: в источнике меняется количество в табличной части, объект регистрируется на узле обмена и уходит в файл. Но в приемнике при первой загрузке количество остается старым, а отчет об успешной загрузке не возвращается. При повторном изменении того же документа в источнике всё отрабатывает корректно.

Разберем по шагам пять основных технических причин этой аномалии:

1. Коллизия версий данных (ВерсияДанных / Optimistic Locking)

Каждая запись в таблицах 1С содержит скрытое системное поле ВерсияДанных. При первой синхронизации измененного документа в XML-пакет записывается его новая версия. Однако, если в приемнике параллельно выполнялись фоновые процессы (например, отложенное проведение или регламентное обновление регистров), версия документа в базе-приемнике могла обновиться.

При загрузке платформа сравнивает версию из файла и версию из БД. Если версия в БД приемника кажется «более новой» или конфликтует с алгоритмом БСП, система тихо игнорирует обновление полей, чтобы предотвратить потерю данных. При повторном изменении в источнике версия гарантированно увеличивается, преодолевая этот барьер.

2. Асинхронность работы регистра «Соответствие объектов информационных баз»

При первом обмене (создании документа) создается запись в регистре сведений СоответствиеОбъектовИнформационныхБаз для связки уникальных идентификаторов (GUID) источника и приемника. Если обмен идет в многопоточном режиме или через COM/Web-сервисы, транзакция записи этого соответствия может завершиться с микросекундной задержкой.

Во время первой попытки изменения документа механизм сопоставления БСП не находит соответствия по GUID и пытается сопоставить объект по полям поиска (которые могут отработать некорректно или вернуть пустую ссылку). Ко второму обмену транзакция записи соответствия точно зафиксирована в БД, и сопоставление проходит мгновенно.

3. Некорректная обработка признака ОбменДанными.Загрузка в приемнике

При загрузке данных через XML/EnterpriseData платформа устанавливает свойству записываемого объекта признак ОбменДанными.Загрузка = Истина. Это должно отключать прикладную бизнес-логику (проверки, заполнение реквизитов, проведение) в модуле документа.

Если в базе-приемнике написаны нетиповые подписки на события или кастомный код в процедурах ПередЗаписью / ПриЗаписи модуля документа, и там отсутствует проверка:


Если ОбменДанными.Загрузка Тогда
    Возврат;
КонецЕсли;

то при первой загрузке срабатывает тяжелый алгоритм (например, автоматический пересчет ТЧ по остаткам на складах). Он «тихо» перезаполняет табличную часть старыми значениями или блокирует запись нового количества. Во второй раз, из-за изменения кэша транзакций или статусов проведения, алгоритм выполняется иначе, и запись проходит успешно.

4. Логика ПВД (Правила выгрузки данных) и выгрузка по ссылке

Если в правилах выгрузки данных источника используется сложный алгоритм выгрузки сопутствующих объектов (например, через вызов ВыгрузитьПоПравилу), при первом изменении документ мог выгрузиться в «усеченном» виде (только ссылка и ключевые поля поиска для идентификации), так как ПВД посчитало его лишь сопутствующим справочным объектом для другой сущности. В приемнике он просто идентифицировался, но табличная часть не обновилась. При повторном ручном изменении документ регистрируется на узле обмена полноценно и выгружается со всей структурой данных.

5. Ошибки квитирования номеров сообщений в БСП

Если при первом обмене пакет с изменениями ушел, но подтверждение (квитанция) от приемника задержалось или «наложилось» на запуск новой сессии, БСП может посчитать, что данные из этого пакета уже были успешно применены, и пропустить повторную обработку данных из этого же пакета. При повторном изменении генерируется новый пакет с новым номером сообщения, который гарантированно обрабатывается СУБД приемника.

Рекомендации по отладке

Чтобы локализовать и устранить проблему «второго раза», выполните следующие действия:

  1. Откройте сформированный XML-файл выгрузки при первом изменении и проверьте, присутствует ли там узел с вашей табличной частью и новым количеством. Если данных в файле нет — проблему нужно искать на стороне источника (в ПВД/ПКО выгрузки).
  2. Если данные в файле есть, запустите базу-приемник в режиме отладки, установите точку останова в процедуре ПередЗаписью проблемного документа и проверьте, заходит ли выполнение в обработчики, игнорирующие флаг ОбменДанными.Загрузка.
  3. Убедитесь, что в регистре СоответствиеОбъектовИнформационныхБаз нет дублирующих записей для этого документа.
← На главную