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