Как программно применить ручную скидку к заказу клиента, создаваемому без формы?

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

Понимание архитектурной проблемы

При работе с типовыми конфигурациями, такими как 1С:Управление торговлей или 1С:ERP, многие разработчики сталкиваются с тем, что штатные механизмы расчета скидок (например, функции модуля СкидкиНаценкиЗаполнениеСервер) требуют наличия контекста формы. Это связано с тем, что при интерактивной работе пользователя данные о скидках проходят через временное хранилище (АдресВоВременномХранилище), которое инициализируется при открытии формы документа.

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

Решение 1: Прямое заполнение данных в объекте

Наиболее надежный и рекомендуемый способ программного изменения скидок без использования форм — прямое воздействие на табличную часть объекта. Вместо попыток «обмануть» серверные методы, давайте воспользуемся логикой прямого расчета.

Для того чтобы применить общую сумму скидки ко всем строкам заказа, выполним следующие действия:

  1. Рассчитаем общую сумму документа без учета скидок.
  2. Определим долю каждой строки в итоговой сумме документа.
  3. Рассчитаем сумму скидки для каждой строки, распределив общую сумму ручной скидки пропорционально весу строки.
  4. Запишем полученные значения в реквизиты СуммаРучнойСкидки или ПроцентРучнойСкидки табличной части Товары.

Пример программного распределения скидки:


// Предположим, что ЗаказОбъект уже создан и заполнен
ОбщаяСуммаЗаказа = ЗаказОбъект.Товары.Итог("Сумма");
СуммаРучнойСкидкиНаВесьЗаказ = 1000; // Целевая сумма скидки

Для Каждого СтрокаТовара Из ЗаказОбъект.Товары Цикл
    Доля = СтрокаТовара.Сумма / ОбщаяСуммаЗаказа;
    СуммаСкидкиСтроки = СуммаРучнойСкидкиНаВесьЗаказ * Доля;
    
    // Записываем сумму в колонку табличной части
    СтрокаТовара.СуммаРучнойСкидки = СуммаСкидкиСтроки;
КонецЦикла;

// После изменения данных обязательно вызываем пересчет итогов
// Если в конфигурации предусмотрена процедура пересчета, вызываем её
ЗаказОбъект.ЗаполнитьИтоги();

Решение 2: Имитация серверных данных

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

Разберем, что нам необходимо для инициализации процесса:

  1. Подготовка структуры ПараметрыСкидки, которая определяет режим использования автоматических и ручных скидок.
  2. Использование методов СкидкиНаценкиЗаполнениеСервер для регистрации данных в сессии, если это возможно без вызова ПолучитьФорму.

Важное замечание: Метод СкидкиНаценкиЗаполнениеСервер.АдресДанныхДляРасчетаРучныхСкидокВоВременномХранилище критически зависит от идентификатора формы. Если вы используете этот подход, убедитесь, что вы передаете актуальный УникальныйИдентификатор создаваемого объекта, а не объекта формы. Однако, учитывая высокую сложность поддержки такого кода при обновлениях конфигурации, мы рекомендуем использовать его только при крайней необходимости.

Рекомендации по реализации

При внедрении любого из этих подходов, следуйте правилам хорошего тона при разработке на 1С:

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

← На главную