diff --git a/myproject/pos/static/pos/js/terminal.js b/myproject/pos/static/pos/js/terminal.js index 8aa5ed0..87ced6c 100644 --- a/myproject/pos/static/pos/js/terminal.js +++ b/myproject/pos/static/pos/js/terminal.js @@ -2292,11 +2292,22 @@ function renderCheckoutModal() { let paymentWidget = null; +// Переменные состояния скидок +let appliedPromoCode = null; // примененный промокод +let cartDiscounts = { + orderDiscount: null, // скидка на заказ + itemDiscounts: [], // скидки на позиции + totalDiscount: 0 // общая сумма скидки +}; + // При открытии модалки checkout -document.getElementById('checkoutModal').addEventListener('show.bs.modal', () => { +document.getElementById('checkoutModal').addEventListener('show.bs.modal', async () => { const customer = selectedCustomer || SYSTEM_CUSTOMER; const walletBalance = customer.wallet_balance || 0; + // Сбрасываем скидки + resetDiscounts(); + // Показываем баланс кошелька const walletDiv = document.getElementById('checkoutWalletBalance'); if (customer.id !== SYSTEM_CUSTOMER.id) { @@ -2312,11 +2323,16 @@ document.getElementById('checkoutModal').addEventListener('show.bs.modal', () => totalAmount += item.qty * item.price; }); - document.getElementById('checkoutFinalPrice').textContent = formatMoney(totalAmount) + ' руб.'; + // Проверяем автоматические скидки + await checkAutoDiscounts(); + + // Применяем скидки к итоговой сумме + const finalTotal = Math.max(0, totalAmount - cartDiscounts.totalDiscount); + document.getElementById('checkoutFinalPrice').textContent = formatMoney(finalTotal) + ' руб.'; // Инициализируем виджет в single mode initPaymentWidget('single', { - order: { total: totalAmount, amount_due: totalAmount, amount_paid: 0 }, + order: { total: finalTotal, amount_due: finalTotal, amount_paid: 0 }, customer: { id: customer.id, name: customer.name, wallet_balance: walletBalance } }); }); @@ -2345,6 +2361,205 @@ function reinitPaymentWidget(mode) { }); } +// ===== ФУНКЦИИ ДЛЯ РАБОТЫ СО СКИДКАМИ ===== + +// Сброс скидок +function resetDiscounts() { + appliedPromoCode = null; + cartDiscounts = { + orderDiscount: null, + itemDiscounts: [], + totalDiscount: 0 + }; + + // Сбрасываем UI + document.getElementById('promoCodeInput').value = ''; + document.getElementById('promoCodeError').style.display = 'none'; + document.getElementById('promoCodeError').textContent = ''; + document.getElementById('promoCodeSuccess').style.display = 'none'; + document.getElementById('promoCodeSuccess').textContent = ''; + document.getElementById('removePromoBtn').style.display = 'none'; + document.getElementById('autoDiscounts').style.display = 'none'; + document.getElementById('autoDiscountsText').textContent = ''; +} + +// Проверить автоматические скидки +async function checkAutoDiscounts() { + try { + const items = Array.from(cart.values()).map(item => ({ + type: item.type, + id: item.id, + quantity: item.qty, + price: item.price + })); + + const customer = selectedCustomer || SYSTEM_CUSTOMER; + + const response = await fetch('/pos/api/discounts/calculate/', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-CSRFToken': getCookie('csrftoken') + }, + body: JSON.stringify({ + items: items, + customer_id: customer.id !== SYSTEM_CUSTOMER.id ? customer.id : null + }) + }); + + const result = await response.json(); + + if (result.success) { + // Сохраняем скидки + cartDiscounts.totalDiscount = result.total_discount || 0; + cartDiscounts.orderDiscount = result.order_discount; + + // Показываем автоматические скидки + if (result.order_discount && result.order_discount.discount_id) { + document.getElementById('autoDiscounts').style.display = 'block'; + document.getElementById('autoDiscountsText').textContent = + `${result.order_discount.discount_name}: -${result.order_discount.discount_amount.toFixed(2)} руб.`; + } + } + } catch (error) { + console.error('Ошибка при проверке автоматических скидок:', error); + } +} + +// Применить промокод +async function applyPromoCode() { + const code = document.getElementById('promoCodeInput').value.trim().toUpperCase(); + if (!code) return; + + // Вычисляем сумму корзины + let cartTotal = 0; + cart.forEach((item) => { + cartTotal += item.qty * item.price; + }); + + try { + const response = await fetch('/pos/api/discounts/validate-promo/', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-CSRFToken': getCookie('csrftoken') + }, + body: JSON.stringify({ + promo_code: code, + cart_total: cartTotal + }) + }); + + const result = await response.json(); + + if (result.success) { + appliedPromoCode = result.promo_code; + + // Пересчитываем скидки с промокодом + await recalculateDiscountsWithPromo(code); + + // Показываем успех + document.getElementById('promoCodeSuccess').textContent = + `Скидка: ${result.promo_code.discount_name} (${result.promo_code.discount_type === 'percentage' ? result.promo_code.discount_value + '%' : result.promo_code.discount_value + ' руб.'})`; + document.getElementById('promoCodeSuccess').style.display = 'block'; + document.getElementById('promoCodeError').style.display = 'none'; + document.getElementById('removePromoBtn').style.display = 'inline-block'; + + // Обновляем итоговую сумму + updateCheckoutTotalWithDiscounts(); + } else { + // Показываем ошибку + document.getElementById('promoCodeError').textContent = result.error || 'Неверный промокод'; + document.getElementById('promoCodeError').style.display = 'block'; + document.getElementById('promoCodeSuccess').style.display = 'none'; + } + } catch (error) { + console.error('Ошибка при применении промокода:', error); + document.getElementById('promoCodeError').textContent = 'Ошибка при проверке промокода'; + document.getElementById('promoCodeError').style.display = 'block'; + } +} + +// Пересчитать скидки с промокодом +async function recalculateDiscountsWithPromo(promoCode) { + try { + const items = Array.from(cart.values()).map(item => ({ + type: item.type, + id: item.id, + quantity: item.qty, + price: item.price + })); + + const customer = selectedCustomer || SYSTEM_CUSTOMER; + + const response = await fetch('/pos/api/discounts/calculate/', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-CSRFToken': getCookie('csrftoken') + }, + body: JSON.stringify({ + items: items, + promo_code: promoCode, + customer_id: customer.id !== SYSTEM_CUSTOMER.id ? customer.id : null + }) + }); + + const result = await response.json(); + + if (result.success) { + cartDiscounts.totalDiscount = result.total_discount || 0; + cartDiscounts.orderDiscount = result.order_discount; + cartDiscounts.itemDiscounts = result.item_discounts || []; + } + } catch (error) { + console.error('Ошибка при пересчёте скидок:', error); + } +} + +// Обновить итоговую сумму с учётом скидок +function updateCheckoutTotalWithDiscounts() { + let cartTotal = 0; + cart.forEach((item) => { + cartTotal += item.qty * item.price; + }); + + const finalTotal = Math.max(0, cartTotal - cartDiscounts.totalDiscount); + document.getElementById('checkoutFinalPrice').textContent = formatMoney(finalTotal) + ' руб.'; + + // Пересоздаём платёжный виджет с новой суммой + const customer = selectedCustomer || SYSTEM_CUSTOMER; + initPaymentWidget('single', { + order: { total: finalTotal, amount_due: finalTotal, amount_paid: 0 }, + customer: { id: customer.id, name: customer.name, wallet_balance: customer.wallet_balance || 0 } + }); +} + +// Удалить промокод +function removePromoCode() { + appliedPromoCode = null; + + // Пересчитываем без промокода + recalculateDiscountsWithPromo(null).then(() => { + document.getElementById('promoCodeInput').value = ''; + document.getElementById('removePromoBtn').style.display = 'none'; + document.getElementById('promoCodeSuccess').style.display = 'none'; + updateCheckoutTotalWithDiscounts(); + }); +} + +// Обработчики кнопок промокода +document.getElementById('applyPromoBtn').addEventListener('click', applyPromoCode); + +document.getElementById('removePromoBtn').addEventListener('click', removePromoCode); + +document.getElementById('promoCodeInput').addEventListener('keypress', (e) => { + if (e.key === 'Enter') { + e.preventDefault(); + applyPromoCode(); + } +}); + async function initPaymentWidget(mode, data) { const paymentMethods = [ { id: 1, code: 'account_balance', name: 'С баланса счёта' }, @@ -2413,7 +2628,8 @@ async function handleCheckoutSubmit(paymentsData) { return itemData; }), payments: paymentsData, - notes: document.getElementById('orderNote').value.trim() + notes: document.getElementById('orderNote').value.trim(), + promo_code: appliedPromoCode || null }; // Отправляем на сервер diff --git a/myproject/pos/templates/pos/terminal.html b/myproject/pos/templates/pos/terminal.html index cb70d7a..909f6e5 100644 --- a/myproject/pos/templates/pos/terminal.html +++ b/myproject/pos/templates/pos/terminal.html @@ -345,6 +345,29 @@