feat(pos): добавлен полноценный интерфейс скидок в модальное окно продажи

- Добавлен API endpoint /pos/api/discounts/available/ для получения списка доступных скидок
- Добавлен метод DiscountApplier.apply_manual_discount() для применения ручных скидок
- Обновлен POS checkout для обработки manual_discount_id
- Расширена секция скидок в модальном окне:
  * Отображение автоматических скидок (read-only)
  * Dropdown для выбора скидки вручную
  * Подробная детализация: подитог, общая скидка, скидки на позиции
  * Поле промокода с иконкой
- Увеличен размер модального окна и изменено соотношение колонок (5/7)
- Убрана вертикальная прокрутка из модального окна

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-11 01:59:43 +03:00
parent 6313b8f6e7
commit 42d8c34e8c
5 changed files with 389 additions and 30 deletions

View File

@@ -282,18 +282,18 @@
<!-- Модалка: Продажа -->
<div class="modal fade" id="checkoutModal" tabindex="-1" aria-labelledby="checkoutModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-lg" style="max-width: 70vw;">
<div class="modal-content" style="max-height: 90vh; overflow: hidden;">
<div class="modal-dialog modal-dialog-centered modal-xl" style="max-width: 85vw;">
<div class="modal-content">
<div class="modal-header py-2">
<h5 class="modal-title" id="checkoutModalLabel">
<i class="bi bi-cash-stack"></i> Продажа
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body py-2" style="overflow-y: auto;">
<div class="modal-body py-2">
<div class="row g-3">
<!-- Левая колонка: состав заказа -->
<div class="col-md-7">
<div class="col-md-5">
<!-- Информация о клиенте и баланс в одной строке -->
<div class="row g-2 mb-2">
<div class="col-auto">
@@ -320,7 +320,7 @@
<!-- Состав заказа -->
<div class="mb-2">
<strong class="small">Состав заказа</strong>
<div class="border rounded p-2 mt-1" id="checkoutItems" style="max-height: 180px; overflow-y: auto; background: #f8f9fa; font-size: 0.9rem;">
<div class="border rounded p-2 mt-1" id="checkoutItems" style="background: #f8f9fa; font-size: 0.9rem;">
<!-- Заполняется из JS -->
</div>
</div>
@@ -333,7 +333,7 @@
</div>
<!-- Правая колонка: оплата -->
<div class="col-md-5">
<div class="col-md-7">
<div class="card mb-0">
<div class="card-header bg-light py-2">
<strong class="small">Оплата</strong>
@@ -347,14 +347,45 @@
<!-- Скидки -->
<div class="mb-2 pb-2 border-bottom">
<small class="text-muted">Скидки:</small>
<!-- Автоматические скидки -->
<div id="autoDiscounts" class="small text-success mb-1" style="display: none;">
<i class="bi bi-tag-fill"></i>
<span id="autoDiscountsText"></span>
<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>
</div>
<!-- Выбранная скидка вручную -->
<div id="manualDiscountContainer" class="mb-2" style="display: none;">
<div class="d-flex justify-content-between align-items-center">
<span class="badge bg-info text-dark">
<i class="bi bi-tag me-1"></i>
<span id="manualDiscountName"></span>
<span id="manualDiscountAmount" class="ms-1"></span>
</span>
<button type="button" class="btn btn-sm btn-link text-danger p-0" id="removeManualDiscountBtn">
<i class="bi bi-x-lg"></i>
</button>
</div>
</div>
<!-- Dropdown для выбора скидки -->
<div class="dropdown mb-2">
<button class="btn btn-sm btn-outline-primary w-100 dropdown-toggle" type="button"
id="selectDiscountBtn" data-bs-toggle="dropdown">
<i class="bi bi-plus-circle me-1"></i> Добавить скидку
</button>
<ul class="dropdown-menu w-100" id="discountsDropdownList">
<li><span class="dropdown-item-text small text-muted">Загрузка...</span></li>
</ul>
</div>
<!-- Промокод -->
<div class="input-group input-group-sm mt-1">
<div class="input-group input-group-sm">
<span class="input-group-text"><i class="bi bi-ticket-perforated"></i></span>
<input type="text" class="form-control" id="promoCodeInput"
placeholder="Промокод" style="text-transform: uppercase;">
<button class="btn btn-outline-secondary" type="button" id="applyPromoBtn">
@@ -366,6 +397,21 @@
</div>
<div id="promoCodeError" class="text-danger small mt-1" style="display: none;"></div>
<div id="promoCodeSuccess" class="text-success small mt-1" style="display: none;"></div>
<!-- Итоговая информация по скидкам -->
<div id="discountsSummary" class="mt-2 pt-2 border-top" style="display: none;">
<div class="d-flex justify-content-between small text-muted">
<span>Подитог:</span>
<span id="discountsSubtotal">0.00 руб.</span>
</div>
<div class="d-flex justify-content-between small text-success">
<span>Общая скидка:</span>
<span id="discountsTotalDiscount">-0.00 руб.</span>
</div>
<div id="itemDiscountsBreakdown" class="mt-1 small text-muted">
<!-- Скидки на позиции -->
</div>
</div>
</div>
<!-- Переключатель режима -->