diff --git a/myproject/pos/static/pos/js/terminal.js b/myproject/pos/static/pos/js/terminal.js index 255ed0a..6c95ff7 100644 --- a/myproject/pos/static/pos/js/terminal.js +++ b/myproject/pos/static/pos/js/terminal.js @@ -2,7 +2,7 @@ const CATEGORIES = JSON.parse(document.getElementById('categoriesData').textContent); const ITEMS = JSON.parse(document.getElementById('itemsData').textContent); // Единый массив товаров и комплектов -const SHOWCASE_KITS = JSON.parse(document.getElementById('showcaseKitsData').textContent); // Витринные комплекты +let showcaseKits = JSON.parse(document.getElementById('showcaseKitsData').textContent); // Витринные комплекты (изменяемый) let currentCategoryId = null; let isShowcaseView = false; // Флаг режима просмотра витринных букетов @@ -23,9 +23,10 @@ function renderCategories() { showcaseCard.className = 'card category-card showcase-card' + (isShowcaseView ? ' active' : ''); showcaseCard.style.backgroundColor = '#fff3cd'; showcaseCard.style.borderColor = '#ffc107'; - showcaseCard.onclick = () => { + showcaseCard.onclick = async () => { isShowcaseView = true; currentCategoryId = null; + await refreshShowcaseKits(); // Загружаем свежие данные renderCategories(); renderProducts(); }; @@ -97,7 +98,7 @@ function renderProducts() { // Если выбран режим витрины - показываем витринные комплекты if (isShowcaseView) { - filtered = SHOWCASE_KITS; + filtered = showcaseKits; // Используем изменяемую переменную } else { // Обычный режим - показываем товары и комплекты filtered = currentCategoryId @@ -334,6 +335,22 @@ async function openCreateTempKitModal() { modal.show(); } +// Обновление списка витринных комплектов +async function refreshShowcaseKits() { + try { + const response = await fetch('/pos/api/showcase-kits/'); + const data = await response.json(); + + if (data.success) { + showcaseKits = data.items; + } else { + console.error('Failed to refresh showcase kits:', data); + } + } catch (error) { + console.error('Error refreshing showcase kits:', error); + } +} + // Загрузка списка витрин async function loadShowcases() { try { @@ -344,12 +361,24 @@ async function loadShowcases() { select.innerHTML = ''; if (data.success && data.showcases.length > 0) { + let defaultShowcaseId = null; + data.showcases.forEach(showcase => { const option = document.createElement('option'); option.value = showcase.id; option.textContent = `${showcase.name} (${showcase.warehouse_name})`; select.appendChild(option); + + // Запоминаем витрину склада по умолчанию + if (showcase.is_default_warehouse) { + defaultShowcaseId = showcase.id; + } }); + + // Автовыбор витрины склада по умолчанию + if (defaultShowcaseId) { + select.value = defaultShowcaseId; + } } else { select.innerHTML = ''; } @@ -371,15 +400,15 @@ function renderTempKitItems() { if (item.type !== 'product') return; const itemDiv = document.createElement('div'); - itemDiv.className = 'd-flex justify-content-between align-items-center mb-2 pb-2 border-bottom'; + itemDiv.className = 'd-flex justify-content-between align-items-center mb-1 pb-1 border-bottom'; itemDiv.innerHTML = `
- ${item.name} + ${item.name}
${item.qty} шт × ${formatMoney(item.price)} руб.
- ${formatMoney(item.qty * item.price)} руб. + ${formatMoney(item.qty * item.price)} руб.
`; container.appendChild(itemDiv); @@ -387,13 +416,120 @@ function renderTempKitItems() { estimatedTotal += item.qty * item.price; }); - document.getElementById('tempKitEstimatedPrice').textContent = formatMoney(estimatedTotal); + // Обновляем все расчеты цен + updatePriceCalculations(estimatedTotal); } +// Расчет и обновление всех цен +function updatePriceCalculations(basePrice = null) { + // Если basePrice не передан, пересчитываем из корзины + if (basePrice === null) { + basePrice = 0; + cart.forEach((item, cartKey) => { + if (item.type === 'product') { + basePrice += item.qty * item.price; + } + }); + } + + // Базовая цена + document.getElementById('tempKitBasePrice').textContent = formatMoney(basePrice) + ' руб.'; + + // Корректировка + const adjustmentType = document.getElementById('priceAdjustmentType').value; + const adjustmentValue = parseFloat(document.getElementById('priceAdjustmentValue').value) || 0; + + let calculatedPrice = basePrice; + if (adjustmentType !== 'none' && adjustmentValue > 0) { + if (adjustmentType === 'increase_percent') { + calculatedPrice = basePrice + (basePrice * adjustmentValue / 100); + } else if (adjustmentType === 'increase_amount') { + calculatedPrice = basePrice + adjustmentValue; + } else if (adjustmentType === 'decrease_percent') { + calculatedPrice = Math.max(0, basePrice - (basePrice * adjustmentValue / 100)); + } else if (adjustmentType === 'decrease_amount') { + calculatedPrice = Math.max(0, basePrice - adjustmentValue); + } + } + + document.getElementById('tempKitCalculatedPrice').textContent = formatMoney(calculatedPrice) + ' руб.'; + + // Финальная цена (с учетом sale_price если задана) + const useSalePrice = document.getElementById('useSalePrice').checked; + const salePrice = parseFloat(document.getElementById('salePrice').value) || 0; + + let finalPrice = calculatedPrice; + if (useSalePrice && salePrice > 0) { + finalPrice = salePrice; + } + + document.getElementById('tempKitFinalPrice').textContent = formatMoney(finalPrice); +} + +// Обработчики для полей цены +document.getElementById('priceAdjustmentType').addEventListener('change', function() { + const adjustmentBlock = document.getElementById('adjustmentValueBlock'); + if (this.value === 'none') { + adjustmentBlock.style.display = 'none'; + document.getElementById('priceAdjustmentValue').value = '0'; + } else { + adjustmentBlock.style.display = 'block'; + } + updatePriceCalculations(); +}); + +document.getElementById('priceAdjustmentValue').addEventListener('input', function() { + updatePriceCalculations(); +}); + +document.getElementById('useSalePrice').addEventListener('change', function() { + const salePriceBlock = document.getElementById('salePriceBlock'); + if (this.checked) { + salePriceBlock.style.display = 'block'; + } else { + salePriceBlock.style.display = 'none'; + document.getElementById('salePrice').value = ''; + } + updatePriceCalculations(); +}); + +document.getElementById('salePrice').addEventListener('input', function() { + updatePriceCalculations(); +}); + +// Обработчик загрузки фото +document.getElementById('tempKitPhoto').addEventListener('change', function(e) { + const file = e.target.files[0]; + if (file) { + if (!file.type.startsWith('image/')) { + alert('Пожалуйста, выберите файл изображения'); + this.value = ''; + return; + } + + // Превью + const reader = new FileReader(); + reader.onload = function(event) { + document.getElementById('photoPreviewImg').src = event.target.result; + document.getElementById('photoPreview').style.display = 'block'; + }; + reader.readAsDataURL(file); + } +}); + +// Удаление фото +document.getElementById('removePhoto').addEventListener('click', function() { + document.getElementById('tempKitPhoto').value = ''; + document.getElementById('photoPreview').style.display = 'none'; + document.getElementById('photoPreviewImg').src = ''; +}); + // Подтверждение создания временного комплекта document.getElementById('confirmCreateTempKit').onclick = async () => { const kitName = document.getElementById('tempKitName').value.trim(); const showcaseId = document.getElementById('showcaseSelect').value; + const description = document.getElementById('tempKitDescription').value.trim(); + const photoFile = document.getElementById('tempKitPhoto').files[0]; // Валидация if (!kitName) { @@ -422,6 +558,27 @@ document.getElementById('confirmCreateTempKit').onclick = async () => { return; } + // Получаем данные о ценах + const priceAdjustmentType = document.getElementById('priceAdjustmentType').value; + const priceAdjustmentValue = parseFloat(document.getElementById('priceAdjustmentValue').value) || 0; + const useSalePrice = document.getElementById('useSalePrice').checked; + const salePrice = useSalePrice ? (parseFloat(document.getElementById('salePrice').value) || 0) : 0; + + // Формируем FormData для отправки с файлом + const formData = new FormData(); + formData.append('kit_name', kitName); + formData.append('showcase_id', showcaseId); + formData.append('description', description); + formData.append('items', JSON.stringify(items)); + formData.append('price_adjustment_type', priceAdjustmentType); + formData.append('price_adjustment_value', priceAdjustmentValue); + if (useSalePrice && salePrice > 0) { + formData.append('sale_price', salePrice); + } + if (photoFile) { + formData.append('photo', photoFile); + } + // Отправляем запрос на сервер const confirmBtn = document.getElementById('confirmCreateTempKit'); confirmBtn.disabled = true; @@ -431,16 +588,10 @@ document.getElementById('confirmCreateTempKit').onclick = async () => { const response = await fetch('/pos/api/create-temp-kit/', { method: 'POST', headers: { - 'Content-Type': 'application/json', 'X-CSRFToken': getCookie('csrftoken') + // Не указываем Content-Type - браузер сам установит multipart/form-data }, - body: JSON.stringify({ - kit_name: kitName, - showcase_id: parseInt(showcaseId), - items: items, - price_adjustment_type: 'none', - price_adjustment_value: 0 - }) + body: formData }); const data = await response.json(); @@ -456,9 +607,27 @@ document.getElementById('confirmCreateTempKit').onclick = async () => { // Очищаем корзину clearCart(); + // Сбрасываем поля формы + document.getElementById('tempKitDescription').value = ''; + document.getElementById('tempKitPhoto').value = ''; + document.getElementById('photoPreview').style.display = 'none'; + document.getElementById('priceAdjustmentType').value = 'none'; + document.getElementById('priceAdjustmentValue').value = '0'; + document.getElementById('adjustmentValueBlock').style.display = 'none'; + document.getElementById('useSalePrice').checked = false; + document.getElementById('salePrice').value = ''; + document.getElementById('salePriceBlock').style.display = 'none'; + // Закрываем модальное окно const modal = bootstrap.Modal.getInstance(document.getElementById('createTempKitModal')); modal.hide(); + + // Обновляем витринные комплекты и переключаемся на вид витрины + isShowcaseView = true; + currentCategoryId = null; + await refreshShowcaseKits(); + renderCategories(); + renderProducts(); } else { alert(`Ошибка: ${data.error}`); } diff --git a/myproject/pos/templates/pos/terminal.html b/myproject/pos/templates/pos/terminal.html index 27a259e..1b1efe6 100644 --- a/myproject/pos/templates/pos/terminal.html +++ b/myproject/pos/templates/pos/terminal.html @@ -107,7 +107,7 @@