Как программно отменить проведение документа в 1С и избежать ошибки при записи движений?

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

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

Анализ проблемы: почему стандартный метод выдает ошибку?

Проанализируем ситуацию. У нас есть следующий код для программной отмены проведения:

ОбъектЗаполнения.Записать(РежимЗаписиДокумента.ОтменаПроведения);

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

Когда мы программно отменяем проведение, платформа автоматически пытается очистить записи (движения), созданные этим документом-регистратором. Ошибка означает, что внутри модуля набора записей этого регистра сработало условие, установившее флаг Отказ = Истина. Выясним причину этого отказа. Чаще всего это происходит из-за:

  1. Проверки на закрытый период (попытка удалить движения в периоде, который уже закрыт для изменений).
  2. Нехватки прав доступа у пользователя на изменение конкретного регистра.
  3. Пользовательских или типовых проверок целостности (например, запрет на удаление движений, если товар уже списан следующими документами).

Также в современных конфигурациях (таких как ERP, УТ 11, Комплексная автоматизация) при проведении и его отмене активно используется менеджер временных таблиц, передаваемый через коллекцию ДополнительныеСвойства. Если мы вызываем отмену проведения из внешней обработки или произвольного серверного контекста без инициализации нужных параметров, типовой код может "упасть" с ошибкой, так как ожидает подготовленную среду.

Варианты решения: типовой механизм и "обходной" путь

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

Разберем по шагам обходной путь (ручное снятие с проведения). Этот метод предполагает прямую работу с наборами записей и флагом проведения:


// 1. Очистка движений документа по всем регистрам
// Программно перебираем все регистры, где документ является регистратором,
// читаем пустой набор записей и записываем его.

// 2. Снятие флага проведения и запись
ОбъектЗаполнения.Проведен = Ложь;
ОбъектЗаполнения.Записать(РежимЗаписиДокумента.Запись);

Важное предупреждение: В профессиональном сообществе такой метод считается "костылем". При таком подходе не отрабатывают стандартные алгоритмы платформы (в частности, ОбработкаУдаленияПроведения). Это может привести к нарушению логики работы конфигурации, некорректным связям в базе данных или "зависшим" записям во вспомогательных регистрах. Использовать этот подход стоит только в крайнем случае для разовых исправлений данных.

Программный расчет зависимых цен в документе Установка цен номенклатуры

Теперь посмотрим на вторую задачу. На основании поступления товаров программно создается документ УстановкаЦенНоменклатуры, но как рассчитать зависимые (вычисляемые) цены согласно настроенному правилу ценообразования?

В типовых конфигурациях кнопка расчета на форме активно использует клиент-серверные вызовы. При создании документа на сервере использовать методы формы невозможно. Решать эту задачу нужно через серверные общие модули ценообразования.

Посмотрим на примерный алгоритм действий:

  1. Добавляем в документ базовые виды цен (например, цену поступления) и зависимые виды цен (например, розничную).
  2. Заполняем табличную часть номенклатурой и базовыми ценами из документа-основания.
  3. Формируем структуру параметров (в зависимости от релиза это может быть массив строк или структура с настройками).
  4. Вызываем экспортный метод общего модуля. Обычно это функции вроде ЦенообразованиеСервер.РассчитатьЦеныПоФормулам() или УстановкаЦенСервер.ЗаполнитьЦены(). Эти методы самостоятельно распарсят формулы из справочника ВидыЦен и выполнят пересчет.
  5. Переносим полученные результаты обратно в табличную часть создаваемого документа и вызываем ОбъектЦена.Записать().

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

Используя эти методы, мы сможем корректно управлять состоянием проведения документов и автоматически формировать цены, не нарушая логику современных конфигураций 1С.

← На главную