Как установить флаг оплаты в документе реализации при проведении ПКО в 1С?

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

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

Причина ошибки «Значение не является значением объектного типа (ПолучитьОбъект)»

Проанализируем исходный фрагмент кода, вызвавший исключение при проведении кассового ордера:


ОплаченоСсылка = ЭтотОбъект.ДокументОснование.Оплачено;
ОплаченоОбъект = ОплаченоСсылка.ПолучитьОбъект();
ОплаченоОбъект = Истина;
ОплаченоОбъект.Записать();

Выясним причину падения программы. В первой строке выражение ЭтотОбъект.ДокументОснование.Оплачено обращается через точку к реквизиту документа реализации. Так как реквизит Оплачено имеет примитивный тип Булево, переменная ОплаченоСсылка получает значение Истина или Ложь.

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

Исправление ошибки: прямое изменение документа-основания

Чтобы корректно изменить реквизит в документе-основании, необходимо вызывать метод ПолучитьОбъект() непосредственно у ссылки на документ, а не у его отдельного реквизита. Кроме того, обязательно нужно проверить, заполнено ли основание и соответствует ли оно ожидаемому типу документа.

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


Если ЗначениеЗаполнено(ЭтотОбъект.ДокументОснование) 
	И ТипЗнч(ЭтотОбъект.ДокументОснование) = Тип("ДокументСсылка.РеализацияТоваровИУслуг") Тогда

	// Получаем объект документа реализации по ссылке
	ОбъектОснование = ЭтотОбъект.ДокументОснование.ПолучитьОбъект();
	
	// Устанавливаем признак оплаты
	ОбъектОснование.Оплачено = Истина;
	
	// Записываем документ без повторного проведения
	ОбъектОснование.Записать(РежимЗаписиДокумента.Запись);

КонецЕсли;

Разберем важные детали этого алгоритма:

  1. Проверка заполненности и типа: с помощью ЗначениеЗаполнено() и ТипЗнч() мы исключаем попытку получения объекта из пустой ссылки или из документа другого вида (например, если основанием кассового ордера станет СчетНаОплату).
  2. Режим записи: метод Записать() следует вызывать с параметром РежимЗаписиДокумента.Запись, чтобы не инициировать повторное проведение реализации и не вызывать лишнюю нагрузку на систему.
  3. Обработка отмены проведения: если мы модифицируем документ при проведении, аналогичный код с установкой ОбъектОснование.Оплачено = Ложь; необходимо продублировать в процедуре ОбработкаУдаленияПроведения модуля кассового ордера.

Технические риски прямой перезаписи документов в транзакции

Хотя приведенный выше код решает задачу синтаксически, изменение стороннего документа внутри процедуры ОбработкаПроведения несет в себе существенные технические риски:

  1. Взаимные блокировки (Deadlocks): во время проведения кассового ордера накладывается транзакционная блокировка на сам ордер и на документ реализации. Если в этот момент другой пользователь или фоновое задание попытается провести реализацию или сформировать по ней отчет, возникнет ожидание блокировки или откат транзакции.
  2. Конфликты версий у пользователей: если менеджер держит открытой форму реализации, а бухгалтер в это время проводит ПКО, менеджер при попытке сохранить свои изменения получит ошибку несовпадения версий данных («Данные были изменены или удалены другим пользователем»).
  3. Неполноценная бизнес-логика: простой флаг Оплачено не отражает частичную оплату, предоплату, переплату или оплату несколькими платежными документами (например, часть суммы внесена наличными в кассу, а часть перечислена на расчетный счет).
  4. Избыточный трафик в планах обмена: каждый вызов Записать() меняет номер версии документа и регистрирует изменения для всех узлов РИБ и интеграций.

Рекомендуемые альтернативы: правильный учет оплаты в 1С

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

Рассмотрим два надежных способа реализации такого функционала:

  1. Использование регистра накопления взаиморасчетов:

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

  2. Использование независимого регистра сведений:

    Если конфигурация простая и регистр накопления избыточен, создают непериодический регистр сведений (например, СтатусыОплатыДокументов) с измерением Документ (тип ДокументСсылка.РеализацияТоваровИУслуг) и ресурсом Оплачено (тип Булево). При проведении ПКО формируется запись в этот регистр сведений. Это исключает перезапись самого документа реализации, предотвращает блокировки таблиц и не вызывает конфликтов версий у пользователей.

← На главную