При разработке внешних обработок, интеграций или механизмов автоматического заполнения документов в современных конфигурациях 1С (таких как 1С:ERP, 1С:Комплексная автоматизация 2 или 1С:Управление торговлей 11) разработчики часто сталкиваются с неприятной проблемой. При попытке программно заполнить реквизит СуммаПлатежа в табличной части ЭтапыГрафикаОплаты данные либо не выводятся на форму, либо бесследно исчезают сразу после записи или проведения документа.
В этой статье мы подробно разберем, почему так происходит, изучим внутренние механизмы платформы 1С, управляющие графиками платежей, и рассмотрим надежные программные способы решения этой задачи.
Простое присвоение значения реквизиту, например, через конструкцию СтрокаГрафика.СуммаПлатежа = СуммаВсего, не работает по нескольким важным причинам, заложенным в типовую архитектуру решений 1С:
ПроцентПлатежа. Сумма всех долей в табличной части должна строго составлять 100%. Если вы программно установили сумму, но оставили процент нулевым (или не пересчитали его пропорционально новой сумме), алгоритмы валидации документа посчитают строку некорректной и очистят ее.СуммаВзаиморасчетов. Без этого график также не пройдет проверку.Рассмотрим подробнее три основных варианта решения этой проблемы в зависимости от ваших задач.
Если вам не требуется вносить уникальные, не предусмотренные договором суммы, а нужно лишь заставить систему рассчитать график оплаты по правилам, установленным в самом документе (соглашении/договоре), лучше всего использовать встроенный API конфигурации. Это гарантирует, что при обновлении системы ваш код не сломается.
У объекта документа (например, ДокументОбъект.ЗаказПоставщику или ДокументОбъект.ПриобретениеТоваровУслуг) существует экспортный метод для заполнения этапов графика. Разберем пример кода для внешней обработки:
// Получаем объект документа для редактирования
ДокОбъект = СсылкаНаДокумент.ПолучитьОбъект();
// Вызываем типовой метод заполнения графика по правилам соглашения
ДокОбъект.ЗаполнитьЭтапыГрафикаОплаты();
// Записываем документ с проведением
ДокОбъект.Записать(РежимЗаписиДокумента.Проведение);
В некоторых случаях (например, при сложных расчетах скидок или динамическом изменении цен прямо в коде вашей обработки) может потребоваться принудительный пересчет этапов через специализированные общие модули. В ERP и УТ для этого используется процедура:
// Корректно рассчитывает и перезаполняет график на сервере
ВзаиморасчетыСервер.ПроверитьЗаполнитьЭтапыГрафикаОплаты(ДокОбъект);
ДокОбъект.Записать(РежимЗаписиДокумента.Запись);
Использование этого подхода полностью исключает ошибки округления и гарантирует корректность формирования движений по регистрам взаиморасчетов.
Проанализируем ситуацию, когда вам необходимо заполнить график уникальными суммами и датами, которые не привязаны ни к одному стандартному шаблону оплаты. Чтобы ваши данные не затерлись при записи, выполните следующие шаги:
Посмотрим на рабочий пример заполнения таблицы вручную:
ДокОбъект = СсылкаНаДокумент.ПолучитьОбъект();
// Полностью очищаем старый график перед ручным формированием
ДокОбъект.ЭтапыГрафикаОплаты.Очистить();
// Добавляем новую строку графика оплаты
НоваяСтрока = ДокОбъект.ЭтапыГрафикаОплаты.Добавить();
НоваяСтрока.ВариантОплаты = Перечисления.ВариантыОплатыПоставщику.КредитПослеОтгрузки;
НоваяСтрока.ДатаПлатежа = ТекущаяДата() + (24 * 3600 * 10); // Оплата через 10 дней
// Заполняем сумму платежа (тип ОпределяемыйТип.ДенежноеПолеНеотрицательное)
СуммаВсего = 150000.00;
НоваяСтрока.СуммаПлатежа = СуммаВсего;
// Рассчитываем процент платежа от общей суммы документа
// Это критически важно! Без корректного процента данные будут сброшены.
Если ДокОбъект.СуммаДокумента <> 0 Тогда
НоваяСтрока.ПроцентПлатежа = Округлить((СуммаВсего / ДокОбъект.СуммаДокумента) * 100, 2);
Иначе
НоваяСтрока.ПроцентПлатежа = 100;
КонецЕсли;
// Если валюты совпадают, дублируем сумму во взаиморасчеты
НоваяСтрока.СуммаВзаиморасчетов = СуммаВсего;
// Записываем документ
ДокОбъект.Записать(РежимЗаписиДокумента.Запись);
Обратите внимание на использование функции Округлить(). Так как реквизиты имеют строго определенную точность, любые копейки, превышающие 2 знака после запятой, могут привести к тому, что суммарный процент по всем строкам окажется равен, например, 99.99% вместо 100%, что вызовет отказ системы при проведении.
Если бизнес-логика документа настолько сложна, что расчет сумм и процентов жестко «зашит» в модуле управляемой формы документа (в обработчиках событий полей ввода ПриИзменении), и вы не хотите дублировать этот код у себя в обработке, можно прибегнуть к эмуляции работы пользователя.
Этот способ более ресурсоемок, но позволяет задействовать все визуальные алгоритмы формы без открытия самого окна на экране:
Пример схемы вызова функций формы:
// Получаем форму (не открывая ее интерактивно)
ПараметрыФормы = Новый Структура("Ключ", СсылкаНаДокумент);
ФормаДок = ПолучитьФорму("Документ.ПриобретениеТоваровУслуг.Форма.ФормаДокумента", ПараметрыФормы);
// Изменяем данные в ТЧ на форме
СтрокаТЧ = ФормаДок.Объект.ЭтапыГрафикаОплаты[0];
СтрокаТЧ.СуммаПлатежа = 25000;
// Вызываем обработчик изменения суммы платежа, который пересчитает проценты
ФормаДок.ЭтапыГрафикаОплатыСуммаПлатежаПриИзмененииНаСервере();
// Записываем форму программно
ФормаДок.Записать();
Важно помнить, что данный метод применим только в том случае, если разработчики конфигурации вынесли соответствующие процедуры изменения реквизитов в категорию экспортных в модуле формы.
Поскольку реквизит СуммаПлатежа имеет тип ОпределяемыйТип.ДенежноеПолеНеотрицательное, при работе с ним важно помнить следующее:
Число(15, 2) с установленным флагом «Неотрицательное».Мы подробно разобрали особенности работы с графиком оплат в 1С. При программной работе с табличной частью ЭтапыГрафикаОплаты всегда отдавайте приоритет типовому методу ЗаполнитьЭтапыГрафикаОплаты(). Если же вам необходимо полностью ручное распределение сумм — всегда рассчитывайте сопутствующий ПроцентПлатежа для каждой строки и следите, чтобы итоговый процент по всей табличной части был равен ровно 100.