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