Skip to content

Защита total от ухода в минус + UX-маркер для скидок в настройках доставки/оплаты #265

@biz87

Description

@biz87

Проблема

После #211 / #246 поле price у способов доставки и оплаты поддерживает отрицательные значения и проценты — это позволяет настраивать скидки за способ оплаты/доставки (например, «−5% за оплату наличными», «−200₽ за самовывоз»).

Текущая реализация оставляет два открытых вопроса:

  1. Нет защиты от отрицательного total заказа. isAllowedPercent ограничивает только проценты диапазоном -100..100, а фиксированная скидка вроде -99999 сохранится без вопросов. При накоплении скидок из нескольких источников (доставка + оплата) total может уйти в минус. Потенциальный фрод-вектор.

  2. UX в админке не различает наценку и скидку. Поле одно, plain textfield, подсказка в lexicon говорит «может быть отрицательной». Оператор легко теряет знак при копи-пасте или вводе с клавиатуры и продаёт в минус.

Предложение

1. Защита total в OrderService::recalculate()

Финальная проверка после применения всех слагаемых:

if ($total < 0) {
    $this->modx->log(
        modX::LOG_LEVEL_WARN,
        "[Order] Negative total for order #{$order->id}: "
        . "subtotal={$subtotal}, delivery={$deliveryCost}, payment={$paymentCost}. "
        . "Clamping to 0."
    );
    $total = 0;
}

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

2. UX-маркер «Скидка / Наценка» в админке

В Vue-формах способов доставки и оплаты рядом с полем price:

  • Значение начинается с - → зелёный бейдж «Скидка».
  • Положительное → серый бейдж «Наценка».
  • 0 или пусто → без бейджа.

Реактивная подсказка по v-model поля, без серверной валидации. Помогает оператору сразу видеть знак.

Из scope намеренно вынесено

  • Размазывание скидки по позициям заказа для чеков 54-ФЗ — это задача компонентов-провайдеров фискализации, которые работают со своим API эквайринга и знают его требования. MS3 отдаёт им итоговые цифры заказа, дальше их зона ответственности.
  • Отдельное поле discount на моделях — не нужно. Знак числа в price — естественный способ выразить наценку/скидку, ломать его смысла нет.
  • Событие для расширения источников скидок — пока нет реального запроса, добавим, если появится.

Связанные

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions