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