Как программно назначить ручную скидку в документах 1С

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

При разработке в современных конфигурациях на базе 1С:Предприятие 8.3 (таких как «Управление торговлей 11», «ERP Управление предприятием» или «Комплексная автоматизация 2») программисты часто сталкиваются с проблемой: при попытке программно изменить сумму ручной скидки в заказе или реализации данные «сбрасываются» сразу после записи документа или при любом интерактивном действии пользователя. Рассмотрим подробнее, почему это происходит и как правильно реализовать этот механизм.

Почему данные сбрасываются: анализируем механизмы пересчета

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

Проанализируем ситуацию: как только происходит изменение строки, срабатывает типовой обработчик, который заново вычисляет итоговую сумму строки. Если система «не видит», что ручная скидка была установлена корректно (согласно внутренним флагам), она считает её неактуальной и перезаписывает значением по умолчанию (обычно нулем) или пересчитывает на основании ПроцентРучнойСкидки. Если процент остался старым, то и сумма вернется к старому значению.

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

Для того чтобы наша скидка «прижилась» и не исчезла, мы должны действовать комплексно. Недостаточно заполнить один реквизит, нужно обновить целую группу связанных полей и вызвать процедуры актуализации. Разберем по шагам, что именно необходимо сделать.

1. Синхронизация суммы и процента

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

2. Использование служебного реквизита СтатусУказанияСкидок

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

3. Вызов типовых процедур пересчета

После изменения данных в коде необходимо инициировать пересчет всей строки, чтобы обновились итоги (сумма с НДС, сумма без НДС, итоговая сумма к оплате). Рассмотрим, как это выглядит на практике.

Пример реализации на стороне клиента (в форме документа)

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


// Предположим, мы работаем в контексте формы документа
&НаКлиенте
Процедура УстановитьСкидкуНаСтроку(ТекущаяСтрока, ВеличинаСкидки)
    
    // 1. Устанавливаем сумму
    ТекущаяСтрока.СуммаРучнойСкидки = ВеличинаСкидки;
    
    // 2. Рассчитываем процент, чтобы система не сбросила сумму
    Если ТекущаяСтрока.Цена * ТекущаяСтрока.Количество <> 0 Тогда
        ТекущаяСтрока.ПроцентРучнойСкидки = (ВеличинаСкидки / (ТекущаяСтрока.Цена * ТекущаяСтрока.Количество)) * 100;
    КонецЕсли;
    
    // 3. Вызываем типовой механизм пересчета строки
    // Структура действий имитирует выбор пользователя
    ПараметрыПересчета = Новый Структура("ИмяТабличнойЧасти, ИмяРеквизита", "Товары", "СуммаРучнойСкидки");
    ОбработкаТабличнойЧастиКлиент.РассчитатьСуммуСтрокиТЧ(ТекущаяСтрока, ПараметрыПересчета);
    
    // 4. Оповещаем форму об изменениях
    ЭтаФорма.Модифицированность = Истина;
    
КонецПроцедуры

Пример реализации на сервере (в объекте документа)

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


// В модуле обработки или в серверном контексте формы
Процедура ЗаполнитьСкидкуВОбъекте(ДокументОбъект, НомерСтроки, СуммаСкидки)
    
    СтрокаТЧ = ДокументОбъект.Товары[НомерСтроки - 1];
    
    // Устанавливаем сумму скидки
    СтрокаТЧ.СуммаРучнойСкидки = СуммаСкидки;
    
    // Рассчитываем итоговую сумму строки вручную
    // Сумма = (Цена * Количество) - СуммаРучнойСкидки - СуммаАвтоматическойСкидки
    ЧистаяСуммаПродажи = СтрокаТЧ.Цена * СтрокаТЧ.Количество;
    СтрокаТЧ.Сумма = ЧистаяСуммаПродажи - СтрокаТЧ.СуммаРучнойСкидки - СтрокаТЧ.СуммаАвтоматическойСкидки;
    
    // Важно: пересчитываем НДС, если он входит в сумму или начисляется сверху
    СтруктураПересчета = Новый Структура;
    СтруктураПересчета.Вставить("НалогообложениеНДС", ДокументОбъект.НалогообложениеНДС);
    СтруктураПересчета.Вставить("ЦенаВключаетНДС", ДокументОбъект.ЦенаВключаетНДС);
    
    // Вызываем метод из общего модуля (название может варьироваться от версии конфигурации)
    ОбработкаТабличнойЧастиСервер.РассчитатьСуммуНДССтроки(СтрокаТЧ, СтруктураПересчета);
    
КонецПроцедуры

Анализируем важные нюансы

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

  1. Приоритеты скидок: Если в системе настроены автоматические скидки, они могут конфликтовать с ручными. В некоторых случаях установка ручной скидки может блокировать автоматическую, или наоборот — автоматическая скидка может «вытеснить» ручную при проведении документа. Проанализируйте настройки в разделе CRM и маркетинг.
  2. Статус документа: Если документ уже проведен или имеет статус, запрещающий редактирование (например, «К отгрузке»), программное изменение реквизитов может не сработать или привести к ошибкам согласованности данных.
  3. Типовые модули: Обратите внимание на модуль СкидкиНаценкиСервер. В нем содержатся функции распределения скидок. Иногда проще вызвать функцию РассчитатьРучныеСкидки(), чем пытаться вручную высчитывать суммы для каждой строки.
  4. Округление: При расчете процента от суммы часто возникают погрешности округления. Всегда проверяйте, чтобы итоговая сумма Сумма + СуммаРучнойСкидки + СуммаАвтоматическойСкидки точно равнялась произведению цены на количество.

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

← На главную