From 741fdc97a8f166aa5e9a6b24c6466abdd0c60416 Mon Sep 17 00:00:00 2001 From: Andrey Smakotin Date: Thu, 11 Dec 2025 22:10:06 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D1=8B=20=D0=BA=D0=BD=D0=BE=D0=BF=D0=BA=D0=B8=20+/-=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D1=83=D0=BF=D1=80=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F=20=D0=BA=D0=BE=D0=BB=D0=B8=D1=87=D0=B5=D1=81?= =?UTF-8?q?=D1=82=D0=B2=D0=BE=D0=BC=20=D0=B2=D0=B8=D1=82=D1=80=D0=B8=D0=BD?= =?UTF-8?q?=D0=BD=D1=8B=D1=85=20=D0=BA=D0=BE=D0=BC=D0=BF=D0=BB=D0=B5=D0=BA?= =?UTF-8?q?=D1=82=D0=BE=D0=B2=20=D0=B2=20=D0=BA=D0=BE=D1=80=D0=B7=D0=B8?= =?UTF-8?q?=D0=BD=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Теперь витринные букеты можно увеличивать и уменьшать по экземплярам: UI изменения: - Заменен badge на полноценные кнопки +/- как у обычных товаров - Поле количества readonly с желтым фоном для визуального отличия - Кнопки используют тот же дизайн что и для обычных товаров Функционал увеличения (increaseShowcaseKitQty): - Блокирует еще один доступный экземпляр через API - Проверяет наличие свободных букетов на витрине - Показывает сообщение если нет доступных - Обновляет showcase_item_ids и qty в корзине Функционал уменьшения (decreaseShowcaseKitQty): - Снимает блокировку с последнего экземпляра из списка - При qty=1 полностью удаляет из корзины - Обновляет список витрины после изменения Все операции синхронизируются с сервером и Redis. --- myproject/pos/static/pos/js/terminal.js | 145 ++++++++++++++++++++++-- 1 file changed, 138 insertions(+), 7 deletions(-) diff --git a/myproject/pos/static/pos/js/terminal.js b/myproject/pos/static/pos/js/terminal.js index d291412..a8ebf30 100644 --- a/myproject/pos/static/pos/js/terminal.js +++ b/myproject/pos/static/pos/js/terminal.js @@ -901,14 +901,42 @@ function renderCart() { qtyControl.className = 'd-flex align-items-center'; qtyControl.style.gap = '2px'; - // СПЕЦИАЛЬНАЯ ЛОГИКА для витринных комплектов (только badge, без кнопок) + // СПЕЦИАЛЬНАЯ ЛОГИКА для витринных комплектов if (isShowcaseKit) { - const badge = document.createElement('span'); - badge.className = 'badge bg-warning text-dark'; - badge.textContent = `${item.qty} шт (витрина)`; - badge.style.fontSize = '0.85rem'; - badge.style.padding = '0.5rem 0.75rem'; - qtyControl.appendChild(badge); + // Кнопка минус + const minusBtn = document.createElement('button'); + minusBtn.className = 'btn btn-outline-secondary btn-sm'; + minusBtn.innerHTML = ''; + minusBtn.onclick = async (e) => { + e.preventDefault(); + await decreaseShowcaseKitQty(cartKey); + }; + + // Поле количества (только для отображения, readonly) + const qtyInput = document.createElement('input'); + qtyInput.type = 'number'; + qtyInput.className = 'qty-input form-control form-control-sm'; + qtyInput.style.width = '60px'; + qtyInput.style.textAlign = 'center'; + qtyInput.style.padding = '0.375rem 0.25rem'; + qtyInput.value = item.qty; + qtyInput.min = 1; + qtyInput.readOnly = true; // Только чтение - изменяем только через +/- + qtyInput.style.backgroundColor = '#fff3cd'; // Желтый фон как у витринных + + // Кнопка плюс + const plusBtn = document.createElement('button'); + plusBtn.className = 'btn btn-outline-secondary btn-sm'; + plusBtn.innerHTML = ''; + plusBtn.onclick = async (e) => { + e.preventDefault(); + await increaseShowcaseKitQty(cartKey); + }; + + // Собираем контейнер + qtyControl.appendChild(minusBtn); + qtyControl.appendChild(qtyInput); + qtyControl.appendChild(plusBtn); } else { // ОБЫЧНАЯ ЛОГИКА для товаров и комплектов @@ -1029,6 +1057,109 @@ async function removeFromCart(cartKey) { } } +/** + * Увеличивает количество витринного комплекта в корзине + * Добавляет еще один экземпляр через API (если есть доступные) + */ +async function increaseShowcaseKitQty(cartKey) { + const item = cart.get(cartKey); + if (!item || item.type !== 'showcase_kit') return; + + try { + // Пытаемся заблокировать еще 1 экземпляр + const response = await fetch(`/pos/api/showcase-kits/${item.id}/add-to-cart/`, { + method: 'POST', + headers: { + 'X-CSRFToken': getCookie('csrftoken'), + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ quantity: 1 }) + }); + + const data = await response.json(); + + if (!response.ok || !data.success) { + // Нет доступных экземпляров + alert(data.error || 'Нет доступных экземпляров этого букета на витрине'); + return; + } + + // Успешно заблокировали - обновляем корзину + const lockedItemIds = data.locked_item_ids || []; + item.qty += lockedItemIds.length; + item.showcase_item_ids = [...(item.showcase_item_ids || []), ...lockedItemIds]; + + renderCart(); + saveCartToRedis(); + + // Обновляем список витрины + if (isShowcaseView) { + await loadShowcaseKits(); + } + } catch (error) { + console.error('Ошибка при увеличении количества витринного комплекта:', error); + alert('Ошибка сервера. Попробуйте еще раз.'); + } +} + +/** + * Уменьшает количество витринного комплекта в корзине + * Снимает блокировку с одного экземпляра (последнего в списке) + */ +async function decreaseShowcaseKitQty(cartKey) { + const item = cart.get(cartKey); + if (!item || item.type !== 'showcase_kit') return; + + // Если количество = 1, удаляем полностью + if (item.qty <= 1) { + await removeFromCart(cartKey); + return; + } + + try { + // Снимаем блокировку с последнего экземпляра + const showcaseItemIds = item.showcase_item_ids || []; + if (showcaseItemIds.length === 0) { + // Нет ID - просто удаляем + await removeFromCart(cartKey); + return; + } + + // Берем последний ID из списка + const itemIdToRelease = showcaseItemIds[showcaseItemIds.length - 1]; + + const response = await fetch(`/pos/api/showcase-kits/${item.id}/remove-from-cart/`, { + method: 'POST', + headers: { + 'X-CSRFToken': getCookie('csrftoken'), + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ showcase_item_ids: [itemIdToRelease] }) + }); + + const data = await response.json(); + + if (!response.ok) { + console.error('Ошибка при снятии блокировки:', data.error); + } + + // Обновляем корзину + item.qty -= 1; + item.showcase_item_ids = showcaseItemIds.filter(id => id !== itemIdToRelease); + + renderCart(); + saveCartToRedis(); + + // Обновляем список витрины + if (isShowcaseView) { + await loadShowcaseKits(); + } + } catch (error) { + console.error('Ошибка при уменьшении количества витринного комплекта:', error); + alert('Ошибка сервера. Попробуйте еще раз.'); + } +} + async function clearCart() { // Сбрасываем все свои блокировки витринных букетов try {