feat(discounts): добавлено комбинирование скидок по режимам

Добавлено поле combine_mode с тремя режимами:
- stack - складывать с другими скидками
- max_only - применять только максимальную
- exclusive - отменяет все остальные скидки

Изменения:
- Модель Discount: добавлено поле combine_mode
- Calculator: новый класс DiscountCombiner, методы возвращают списки скидок
- Applier: создание нескольких DiscountApplication записей
- Admin: отображение combine_mode с иконками
- POS API: возвращает списки применённых скидок
- POS UI: отображение нескольких скидок с иконками режимов

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-11 12:56:38 +03:00
parent 293f3b58cb
commit f57e639dbe
9 changed files with 715 additions and 223 deletions

View File

@@ -349,12 +349,17 @@
<div class="mb-2 pb-2 border-bottom">
<small class="text-muted d-block mb-1">Скидки</small>
<!-- Автоматические скидки (read-only) -->
<!-- Автоматические скидки -->
<div id="autoDiscountsContainer" class="mb-2" style="display: none;">
<div class="alert alert-success py-1 px-2 mb-1" style="font-size: 0.85rem;">
<i class="bi bi-magic me-1"></i>
<strong>Автоматически:</strong>
<div id="autoDiscountsList"></div>
<div class="d-flex justify-content-between align-items-center">
<div class="alert alert-success py-1 px-2 mb-0" style="font-size: 0.85rem; flex: 1;">
<i class="bi bi-magic me-1"></i>
<strong>Автоматически:</strong>
<div id="autoDiscountsList"></div>
</div>
<button type="button" class="btn btn-sm btn-link text-danger p-1 ms-2" id="skipAutoDiscountBtn" style="display: none; width: 32px; height: 32px;" title="Отменить скидку">
<i class="bi bi-x-lg fs-5"></i>
</button>
</div>
</div>
@@ -383,6 +388,26 @@
</ul>
</div>
<!-- Произвольная скидка -->
<div class="input-group input-group-sm mb-2">
<span class="input-group-text"><i class="bi bi-percent"></i></span>
<input type="number" class="form-control" id="customDiscountInput"
placeholder="Сумма или %" min="0" step="0.01">
<button class="btn btn-outline-secondary" type="button" id="applyCustomDiscountBtn">
<i class="bi bi-check-lg"></i>
</button>
<button class="btn btn-outline-danger" type="button" id="removeCustomDiscountBtn" style="display: none;">
<i class="bi bi-x-lg"></i>
</button>
</div>
<div class="form-check form-check-sm mb-2">
<input class="form-check-input" type="checkbox" id="customDiscountIsPercent" checked>
<label class="form-check-label small" for="customDiscountIsPercent">
Процент (снимите галочку для фиксированной суммы в рублях)
</label>
</div>
<div id="customDiscountError" class="text-danger small mb-2" style="display: none;"></div>
<!-- Промокод -->
<div class="input-group input-group-sm">
<span class="input-group-text"><i class="bi bi-ticket-perforated"></i></span>