Как проверить, что документ не был изменен перед отправкой на сервер в мобильном приложении 1С?

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

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

Метод 1. Проверка свойства Модифицированность и принудительная запись

Проанализируем самый простой и логичный сценарий. Перед тем как начать формирование пакета данных (JSON или XML) для отправки, нам необходимо убедиться, что данные в экранной форме соответствуют данным в базе. Для этого в управляемых формах существует свойство ЭтаФорма.Модифицированность.

Рассмотрим алгоритм действий в процедуре команды отправки:

  1. Проверяем, изменены ли данные в форме.
  2. Если Модифицированность равна Истина, вызываем принудительную запись объекта.
  3. Если запись прошла успешно, продолжаем процесс обмена.

Посмотрим на пример кода, который можно внедрить в обработчик нажатия кнопки:


&НаКлиенте
Процедура ОтправитьНаСервер(Команда)
    
    Если Модифицированность Тогда
        // Попытаемся записать объект перед отправкой
        РезультатЗаписи = Записать();
        Если Не РезультатЗаписи Тогда
            Возврат; // Если сработали проверки заполнения, отправку прерываем
        КонецЕсли;
    КонецЕсли;
    
    // Вызываем серверную процедуру для формирования JSON и отправки
    ВыполнитьОбменДаннымиНаСервере();
    
КонецПроцедуры

Метод 2. Использование системного механизма ВерсияДанных

Платформа 1С автоматически поддерживает свойство ВерсияДанных для каждого объекта. Это скрытое поле типа Base64String, которое меняется при каждой записи объекта. Мы можем использовать его для реализации механизма оптимистической блокировки.

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

В коде формирования HTTP-запроса это выглядит следующим образом:


Запрос = Новый HTTPЗапрос(АдресРесурса);
Запрос.Заголовки.Вставить("If-Match", Объект.ВерсияДанных);
// Далее тело запроса с данными документа

Метод 3. Статусная модель с транзакционной блокировкой

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

Логика работы должна быть следующей:

  1. В начале процедуры отправки меняем статус документа на БлокированОбменом и записываем его в транзакции.
  2. Устанавливаем для формы режим ТолькоПросмотр = Истина.
  3. Выполняем HTTP-вызов.
  4. В зависимости от ответа сервера (успех или ошибка) либо устанавливаем окончательный статус Отправлен, либо возвращаем статус Черновик и разрешаем редактирование.

Такой подход гарантирует, что пользователь не сможет нажать «Записать» в тот самый момент, пока идет ожидание ответа от сервера.

Метод 4. Хеширование данных (Контрольная сумма)

Если вы хотите быть на 100% уверены, что содержимое отправленного JSON-пакета в точности соответствует тому, что лежит в базе, можно использовать метод вычисления хеша (MD5 или SHA-256). Это особенно актуально при нестабильной связи.

Разберем по шагам:

  1. В объекте создается скрытый реквизит ХешДанных.
  2. При записи документа на мобильном устройстве вычисляется хеш по значимым полям и сохраняется в этот реквизит.
  3. В момент нажатия кнопки «Отправить» хеш вычисляется заново по текущим данным формы и сравнивается с тем, что записано в базе.
  4. Если хеши не совпадают — значит, форма была изменена, но не сохранена, и обмен запускать нельзя.

Пример функции для вычисления хеша (упрощенно):


Функция ПолучитьХешОбъекта(ТекущийОбъект)
    Хеширование = Новый ХешированиеДанных(АлгоритмХеширования.MD5);
    СтрокаДанных = "" + ТекущийОбъект.Номер + ТекущийОбъект.Дата + ТекущийОбъект.СуммаДокумента;
    Хеширование.Добавить(СтрокаДанных);
    Возврат НРег(СтрЗаменить(Строка(Хеширование.ХешСумма), " ", ""));
КонецФункции

Метод 5. Сравнение с объектом в базе данных

Иногда полезно выполнить проверку «в лоб». Перед отправкой мы можем прочитать состояние документа непосредственно из базы данных мобильного устройства и сравнить его с текущими данными в памяти (в реквизите Объект).

Посмотрим на пример такой проверки в коде:


&НаСервере
Функция ДанныеИзменены()
    ДокВБазе = Объект.Ссылка.ПолучитьОбъект();
    // Сравниваем ключевые реквизиты, например, сумму или табличную часть
    Если ДокВБазе.СуммаДокумента <> Объект.СуммаДокумента Тогда
        Возврат Истина;
    КонецЕсли;
    Возврат Ложь;
КонецФункции

Если функция возвращает Истина, мы сообщаем пользователю: «Данные документа были изменены. Пожалуйста, сохраните документ перед отправкой». Это исключает передачу в JSON-пакет значений, которые еще не зафиксированы в базе данных.

Резюме и рекомендации

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

Помните, что в мобильной платформе 1С выполнение HTTP-запросов лучше оборачивать в попытку-исключение, так как сетевое соединение может оборваться в любой момент, и документ не должен остаться в «зависшем» промежуточном статусе.

← На главную