Files
octopus/myproject/pos/static/pos/js/terminal.js

1016 lines
36 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// POS Terminal JavaScript
const CATEGORIES = JSON.parse(document.getElementById('categoriesData').textContent);
let ITEMS = []; // Будем загружать через API
let showcaseKits = JSON.parse(document.getElementById('showcaseKitsData').textContent);
let currentCategoryId = null;
let isShowcaseView = false;
const cart = new Map();
// Переменные для пагинации
let currentPage = 1;
let hasMoreItems = false;
let isLoadingItems = false;
// Переменные для режима редактирования
let isEditMode = false;
let editingKitId = null;
// Временная корзина для модального окна создания/редактирования комплекта
const tempCart = new Map();
function formatMoney(v) {
return (Number(v)).toFixed(2);
}
function renderCategories() {
const grid = document.getElementById('categoryGrid');
grid.innerHTML = '';
// Кнопка "Витрина" - первая в ряду
const showcaseCol = document.createElement('div');
showcaseCol.className = 'col-6 col-sm-4 col-md-3 col-lg-2';
const showcaseCard = document.createElement('div');
showcaseCard.className = 'card category-card showcase-card' + (isShowcaseView ? ' active' : '');
showcaseCard.style.backgroundColor = '#fff3cd';
showcaseCard.style.borderColor = '#ffc107';
showcaseCard.onclick = async () => {
isShowcaseView = true;
currentCategoryId = null;
await refreshShowcaseKits(); // Загружаем свежие данные
renderCategories();
renderProducts();
};
const showcaseBody = document.createElement('div');
showcaseBody.className = 'card-body';
const showcaseName = document.createElement('div');
showcaseName.className = 'category-name';
showcaseName.innerHTML = '<i class="bi bi-flower1"></i> <strong>ВИТРИНА</strong>';
showcaseBody.appendChild(showcaseName);
showcaseCard.appendChild(showcaseBody);
showcaseCol.appendChild(showcaseCard);
grid.appendChild(showcaseCol);
// Кнопка "Все"
const allCol = document.createElement('div');
allCol.className = 'col-6 col-sm-4 col-md-3 col-lg-2';
const allCard = document.createElement('div');
allCard.className = 'card category-card' + (currentCategoryId === null && !isShowcaseView ? ' active' : '');
allCard.onclick = async () => {
currentCategoryId = null;
isShowcaseView = false;
renderCategories();
await loadItems(); // Загрузка через API
};
const allBody = document.createElement('div');
allBody.className = 'card-body';
const allName = document.createElement('div');
allName.className = 'category-name';
allName.textContent = 'Все товары';
allBody.appendChild(allName);
allCard.appendChild(allBody);
allCol.appendChild(allCard);
grid.appendChild(allCol);
// Категории
CATEGORIES.forEach(cat => {
const col = document.createElement('div');
col.className = 'col-6 col-sm-4 col-md-3 col-lg-2';
const card = document.createElement('div');
card.className = 'card category-card' + (currentCategoryId === cat.id && !isShowcaseView ? ' active' : '');
card.onclick = async () => {
currentCategoryId = cat.id;
isShowcaseView = false;
renderCategories();
await loadItems(); // Загрузка через API
};
const body = document.createElement('div');
body.className = 'card-body';
const name = document.createElement('div');
name.className = 'category-name';
name.textContent = cat.name;
body.appendChild(name);
card.appendChild(body);
col.appendChild(card);
grid.appendChild(col);
});
}
function renderProducts() {
const grid = document.getElementById('productGrid');
grid.innerHTML = '';
const searchTerm = document.getElementById('searchInput').value.toLowerCase();
let filtered;
// Если выбран режим витрины - показываем витринные комплекты
if (isShowcaseView) {
filtered = showcaseKits;
} else {
// Обычный режим - ITEMS уже отфильтрованы по категории на сервере
filtered = ITEMS;
}
// Поиск — по названию или артикулу, по любой части, без регистра
if (searchTerm) {
const term = searchTerm.trim();
filtered = filtered.filter(item => {
const name = (item.name || '').toLowerCase();
const sku = (item.sku || '').toLowerCase();
return name.includes(term) || sku.includes(term);
});
}
filtered.forEach(item => {
const col = document.createElement('div');
col.className = 'col-6 col-sm-4 col-md-3 col-lg-2';
const card = document.createElement('div');
card.className = 'card product-card';
card.style.position = 'relative';
card.onclick = () => addToCart(item);
// Если это витринный комплект - добавляем кнопку редактирования
if (item.type === 'showcase_kit') {
const editBtn = document.createElement('button');
editBtn.className = 'btn btn-sm btn-outline-primary';
editBtn.style.position = 'absolute';
editBtn.style.top = '5px';
editBtn.style.right = '5px';
editBtn.style.zIndex = '10';
editBtn.innerHTML = '<i class="bi bi-pencil"></i>';
editBtn.onclick = (e) => {
e.stopPropagation();
openEditKitModal(item.id);
};
card.appendChild(editBtn);
}
const body = document.createElement('div');
body.className = 'card-body';
// Изображение товара/комплекта
const imageDiv = document.createElement('div');
imageDiv.className = 'product-image';
if (item.image) {
const img = document.createElement('img');
img.src = item.image;
img.alt = item.name;
img.loading = 'lazy'; // Lazy loading
imageDiv.appendChild(img);
} else {
imageDiv.innerHTML = '<i class="bi bi-image"></i>';
}
// Информация о товаре/комплекте
const info = document.createElement('div');
info.className = 'product-info';
const name = document.createElement('div');
name.className = 'product-name';
name.textContent = item.name;
const stock = document.createElement('div');
stock.className = 'product-stock';
// Для витринных комплектов показываем название витрины
if (item.type === 'showcase_kit') {
stock.textContent = `🌺 ${item.showcase_name}`;
stock.style.color = '#856404';
stock.style.fontWeight = 'bold';
} else if (item.type === 'product' && item.available_qty !== undefined && item.reserved_qty !== undefined) {
// Для обычных товаров показываем остатки: X(-Y)
const available = parseFloat(item.available_qty) || 0;
const reserved = parseFloat(item.reserved_qty) || 0;
const free = available - reserved;
// Создаём элементы для стилизации разных размеров
const availableSpan = document.createElement('span');
availableSpan.textContent = available;
availableSpan.style.fontSize = '1.1em';
availableSpan.style.fontWeight = 'bold';
availableSpan.style.fontStyle = 'normal';
// Отображаем резерв только если он есть
if (reserved > 0) {
const reservedSpan = document.createElement('span');
reservedSpan.textContent = `(${reserved})`;
reservedSpan.style.fontSize = '0.85em';
reservedSpan.style.marginLeft = '3px';
reservedSpan.style.fontStyle = 'normal';
stock.appendChild(availableSpan);
stock.appendChild(reservedSpan);
} else {
stock.appendChild(availableSpan);
}
// Цветовая индикация: красный если свободных остатков нет или отрицательные
if (free <= 0) {
stock.style.color = '#dc3545'; // Красный
} else if (free < 5) {
stock.style.color = '#ffc107'; // Жёлтый (мало остатков)
} else {
stock.style.color = '#28a745'; // Зелёный (достаточно)
}
} else {
// Fallback для старых данных или комплектов
stock.textContent = item.in_stock ? 'В наличии' : 'Под заказ';
if (!item.in_stock) {
stock.style.color = '#dc3545';
}
}
const sku = document.createElement('div');
sku.className = 'product-sku';
const skuText = document.createElement('span');
skuText.textContent = item.sku || 'н/д';
const priceSpan = document.createElement('span');
priceSpan.className = 'product-price';
priceSpan.textContent = `${formatMoney(item.price)}`;
sku.appendChild(skuText);
sku.appendChild(priceSpan);
info.appendChild(name);
info.appendChild(stock);
info.appendChild(sku);
body.appendChild(imageDiv);
body.appendChild(info);
card.appendChild(body);
col.appendChild(card);
grid.appendChild(col);
});
}
// Загрузка товаров через API
async function loadItems(append = false) {
if (isLoadingItems) return;
isLoadingItems = true;
if (!append) {
currentPage = 1;
ITEMS = [];
}
try {
const params = new URLSearchParams({
page: currentPage,
page_size: 60
});
if (currentCategoryId) {
params.append('category_id', currentCategoryId);
}
const response = await fetch(`/pos/api/items/?${params}`);
const data = await response.json();
if (data.success) {
if (append) {
ITEMS = ITEMS.concat(data.items);
} else {
ITEMS = data.items;
}
hasMoreItems = data.has_more;
if (data.has_more) {
currentPage = data.next_page;
}
renderProducts();
}
} catch (error) {
console.error('Ошибка загрузки товаров:', error);
} finally {
isLoadingItems = false;
}
}
// Infinite scroll
function setupInfiniteScroll() {
const grid = document.getElementById('productGrid');
const observer = new IntersectionObserver(
(entries) => {
entries.forEach(entry => {
if (entry.isIntersecting && hasMoreItems && !isLoadingItems && !isShowcaseView) {
loadItems(true); // Догрузка
}
});
},
{
rootMargin: '200px'
}
);
// Наблюдаем за концом грида
const sentinel = document.createElement('div');
sentinel.id = 'scroll-sentinel';
sentinel.style.height = '1px';
grid.parentElement.appendChild(sentinel);
observer.observe(sentinel);
}
function addToCart(item) {
const cartKey = `${item.type}-${item.id}`; // Уникальный ключ: "product-1" или "kit-1"
if (!cart.has(cartKey)) {
cart.set(cartKey, { id: item.id, name: item.name, price: Number(item.price), qty: 1, type: item.type });
} else {
cart.get(cartKey).qty += 1;
}
renderCart();
// Автоматический фокус на поле количества
setTimeout(() => {
const qtyInputs = document.querySelectorAll('.qty-input');
const itemIndex = Array.from(cart.keys()).indexOf(cartKey);
if (itemIndex !== -1 && qtyInputs[itemIndex]) {
qtyInputs[itemIndex].focus();
qtyInputs[itemIndex].select(); // Выделяем весь текст
}
}, 50);
}
function renderCart() {
const list = document.getElementById('cartList');
list.innerHTML = '';
let total = 0;
if (cart.size === 0) {
list.innerHTML = '<p class="text-muted text-center py-4 small">Корзина пуста</p>';
document.getElementById('cartTotal').textContent = '0.00';
return;
}
cart.forEach((item, cartKey) => {
const row = document.createElement('div');
row.className = 'cart-item mb-2';
// Левая часть: Название и цена единицы
const namePrice = document.createElement('div');
namePrice.className = 'item-name-price';
// Иконка только для комплектов
let typeIcon = '';
if (item.type === 'kit' || item.type === 'showcase_kit') {
typeIcon = '<i class="bi bi-box-seam text-info" title="Комплект"></i> ';
}
namePrice.innerHTML = `
<div class="fw-semibold small">${typeIcon}${item.name}</div>
<div class="text-muted" style="font-size: 0.75rem;">${formatMoney(item.price)} / шт</div>
`;
// Знак умножения
const multiplySign = document.createElement('span');
multiplySign.className = 'multiply-sign';
multiplySign.textContent = 'x';
// Поле ввода количества
const qtyInput = document.createElement('input');
qtyInput.type = 'number';
qtyInput.className = 'qty-input';
qtyInput.value = item.qty;
qtyInput.min = 1;
qtyInput.onchange = (e) => {
const newQty = parseInt(e.target.value) || 1;
if (newQty <= 0) {
removeFromCart(cartKey);
} else {
cart.get(cartKey).qty = newQty;
renderCart();
}
};
// Сумма за позицию
const itemTotal = document.createElement('div');
itemTotal.className = 'item-total';
itemTotal.textContent = formatMoney(item.price * item.qty);
// Кнопка удаления
const deleteBtn = document.createElement('button');
deleteBtn.className = 'btn btn-sm btn-link text-danger p-0';
deleteBtn.innerHTML = '<i class="bi bi-x"></i>';
deleteBtn.onclick = () => removeFromCart(cartKey);
row.appendChild(namePrice);
row.appendChild(multiplySign);
row.appendChild(qtyInput);
row.appendChild(itemTotal);
row.appendChild(deleteBtn);
list.appendChild(row);
total += item.qty * item.price;
});
document.getElementById('cartTotal').textContent = formatMoney(total);
}
function removeFromCart(cartKey) {
cart.delete(cartKey);
renderCart();
}
function clearCart() {
cart.clear();
renderCart();
}
document.getElementById('clearCart').onclick = clearCart;
// Кнопка "На витрину" - функционал будет добавлен позже
document.getElementById('addToShowcaseBtn').onclick = () => {
openCreateTempKitModal();
};
// Функция открытия модального окна для создания временного комплекта
async function openCreateTempKitModal() {
// Проверяем что корзина не пуста
if (cart.size === 0) {
alert('Корзина пуста. Добавьте товары перед созданием комплекта.');
return;
}
// Проверяем что в корзине только товары (не комплекты)
let hasKits = false;
for (const [cartKey, item] of cart) {
if (item.type === 'kit') {
hasKits = true;
break;
}
}
if (hasKits) {
alert('В корзине есть комплекты. Для витрины добавляйте только отдельные товары.');
return;
}
// Копируем содержимое cart в tempCart (изолированное состояние модалки)
tempCart.clear();
cart.forEach((item, key) => {
tempCart.set(key, {...item}); // Глубокая копия объекта
});
// Генерируем название по умолчанию
const now = new Date();
const defaultName = `Витрина — ${now.toLocaleDateString('ru-RU')} ${now.toLocaleTimeString('ru-RU', {hour: '2-digit', minute: '2-digit'})}`;
document.getElementById('tempKitName').value = defaultName;
// Загружаем список витрин
await loadShowcases();
// Заполняем список товаров из tempCart
renderTempKitItems();
// Открываем модальное окно
const modal = new bootstrap.Modal(document.getElementById('createTempKitModal'));
modal.show();
}
// Открытие модального окна для редактирования комплекта
async function openEditKitModal(kitId) {
try {
// Загружаем данные комплекта
const response = await fetch(`/pos/api/product-kits/${kitId}/`);
const data = await response.json();
if (!data.success) {
alert(`Ошибка: ${data.error}`);
return;
}
const kit = data.kit;
// Устанавливаем режим редактирования
isEditMode = true;
editingKitId = kitId;
// Загружаем список витрин
await loadShowcases();
// Очищаем tempCart и заполняем составом комплекта
tempCart.clear();
kit.items.forEach(item => {
const cartKey = `product-${item.product_id}`;
tempCart.set(cartKey, {
id: item.product_id,
name: item.name,
price: Number(item.price),
qty: Number(item.qty),
type: 'product'
});
});
renderTempKitItems(); // Отображаем товары в модальном окне
// Заполняем поля формы
document.getElementById('tempKitName').value = kit.name;
document.getElementById('tempKitDescription').value = kit.description;
document.getElementById('priceAdjustmentType').value = kit.price_adjustment_type;
document.getElementById('priceAdjustmentValue').value = kit.price_adjustment_value;
if (kit.sale_price) {
document.getElementById('useSalePrice').checked = true;
document.getElementById('salePrice').value = kit.sale_price;
document.getElementById('salePriceBlock').style.display = 'block';
} else {
document.getElementById('useSalePrice').checked = false;
document.getElementById('salePrice').value = '';
document.getElementById('salePriceBlock').style.display = 'none';
}
// Выбираем витрину
if (kit.showcase_id) {
document.getElementById('showcaseSelect').value = kit.showcase_id;
}
// Отображаем фото, если есть
if (kit.photo_url) {
document.getElementById('photoPreviewImg').src = kit.photo_url;
document.getElementById('photoPreview').style.display = 'block';
} else {
document.getElementById('photoPreview').style.display = 'none';
}
// Обновляем цены
updatePriceCalculations();
// Меняем заголовок и кнопку
document.getElementById('createTempKitModalLabel').textContent = 'Редактирование витринного букета';
document.getElementById('confirmCreateTempKit').textContent = 'Сохранить изменения';
// Открываем модальное окно
const modal = new bootstrap.Modal(document.getElementById('createTempKitModal'));
modal.show();
} catch (error) {
console.error('Error loading kit for edit:', error);
alert('Ошибка при загрузке комплекта');
}
}
// Обновление списка витринных комплектов
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 {
const response = await fetch('/pos/api/get-showcases/');
const data = await response.json();
const select = document.getElementById('showcaseSelect');
select.innerHTML = '<option value="">Выберите витрину...</option>';
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 = '<option value="">Нет доступных витрин</option>';
}
} catch (error) {
console.error('Error loading showcases:', error);
alert('Ошибка загрузки витрин');
}
}
// Отображение товаров из tempCart в модальном окне
function renderTempKitItems() {
const container = document.getElementById('tempKitItemsList');
container.innerHTML = '';
let estimatedTotal = 0;
tempCart.forEach((item, cartKey) => {
// Только товары (не комплекты)
if (item.type !== 'product') return;
const itemDiv = document.createElement('div');
itemDiv.className = 'd-flex justify-content-between align-items-center mb-1 pb-1 border-bottom';
itemDiv.innerHTML = `
<div>
<strong class="small">${item.name}</strong>
<br>
<small class="text-muted">${item.qty} шт × ${formatMoney(item.price)} руб.</small>
</div>
<div class="text-end">
<strong class="small">${formatMoney(item.qty * item.price)} руб.</strong>
</div>
`;
container.appendChild(itemDiv);
estimatedTotal += item.qty * item.price;
});
// Обновляем все расчеты цен
updatePriceCalculations(estimatedTotal);
}
// Расчет и обновление всех цен
function updatePriceCalculations(basePrice = null) {
// Если basePrice не передан, пересчитываем из tempCart
if (basePrice === null) {
basePrice = 0;
tempCart.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) {
alert('Введите название комплекта');
return;
}
if (!showcaseId && !isEditMode) {
alert('Выберите витрину');
return;
}
// Собираем товары из tempCart (изолированное состояние модалки)
const items = [];
tempCart.forEach((item, cartKey) => {
if (item.type === 'product') {
items.push({
product_id: item.id,
quantity: item.qty
});
}
});
if (items.length === 0) {
alert('Нет товаров для создания комплекта');
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);
if (showcaseId) {
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);
} else if (isEditMode && document.getElementById('photoPreview').style.display === 'none') {
// Если фото было удалено
formData.append('remove_photo', '1');
}
// Отправляем запрос на сервер
const confirmBtn = document.getElementById('confirmCreateTempKit');
confirmBtn.disabled = true;
const url = isEditMode
? `/pos/api/product-kits/${editingKitId}/update/`
: '/pos/api/create-temp-kit/';
const actionText = isEditMode ? 'Сохранение...' : 'Создание...';
confirmBtn.innerHTML = `<span class="spinner-border spinner-border-sm me-2"></span>${actionText}`;
try {
const response = await fetch(url, {
method: 'POST',
headers: {
'X-CSRFToken': getCookie('csrftoken')
// Не указываем Content-Type - браузер сам установит multipart/form-data
},
body: formData
});
const data = await response.json();
if (data.success) {
// Успех!
const successMessage = isEditMode
? `${data.message}\n\nКомплект: ${data.kit_name}\nЦена: ${data.kit_price} руб.`
: `${data.message}
Комплект: ${data.kit_name}
Цена: ${data.kit_price} руб.
Зарезервировано компонентов: ${data.reservations_count}`;
alert(successMessage);
// Очищаем tempCart (изолированное состояние модалки)
tempCart.clear();
// Сбрасываем поля формы
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';
// Сбрасываем режим редактирования
isEditMode = false;
editingKitId = null;
// Закрываем модальное окно
const modal = bootstrap.Modal.getInstance(document.getElementById('createTempKitModal'));
modal.hide();
// Обновляем витринные комплекты и переключаемся на вид витрины
isShowcaseView = true;
currentCategoryId = null;
await refreshShowcaseKits();
renderCategories();
renderProducts();
} else {
alert(`Ошибка: ${data.error}`);
}
} catch (error) {
console.error('Error saving kit:', error);
alert('Ошибка при сохранении комплекта');
} finally {
confirmBtn.disabled = false;
const btnText = isEditMode
? '<i class="bi bi-check-circle"></i> Сохранить изменения'
: '<i class="bi bi-check-circle"></i> Создать и зарезервировать';
confirmBtn.innerHTML = btnText;
}
};
// Вспомогательная функция для получения CSRF токена
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
// Сброс режима редактирования при закрытии модального окна
document.getElementById('createTempKitModal').addEventListener('hidden.bs.modal', function() {
// Очищаем tempCart (изолированное состояние модалки)
tempCart.clear();
if (isEditMode) {
// Сбрасываем режим редактирования
isEditMode = false;
editingKitId = null;
// Восстанавливаем заголовок и текст кнопки
document.getElementById('createTempKitModalLabel').textContent = 'Создать витринный букет из корзины';
document.getElementById('confirmCreateTempKit').innerHTML = '<i class="bi bi-check-circle"></i> Создать и зарезервировать';
}
});
// Заглушки для функционала (будет реализовано позже)
document.getElementById('checkoutNow').onclick = async () => {
alert('Функционал будет подключен позже: создание заказа и списание со склада.');
};
document.getElementById('scheduleLater').onclick = async () => {
alert('Функционал будет подключен позже: создание заказа на доставку/самовывоз.');
};
// Search functionality - клиентская фильтрация
document.getElementById('searchInput').addEventListener('input', () => {
renderProducts(); // Просто перерисовываем с фильтрацией
});
// Customer selection
document.getElementById('customerSelectBtn').addEventListener('click', () => {
alert('Функция выбора клиента будет реализована позже');
});
// Смена склада
const changeWarehouseBtn = document.getElementById('changeWarehouseBtn');
if (changeWarehouseBtn) {
changeWarehouseBtn.addEventListener('click', () => {
const modal = new bootstrap.Modal(document.getElementById('selectWarehouseModal'));
modal.show();
});
}
// Обработка выбора склада из списка
document.addEventListener('click', async (e) => {
const warehouseItem = e.target.closest('.warehouse-item');
if (!warehouseItem) return;
const warehouseId = warehouseItem.dataset.warehouseId;
const warehouseName = warehouseItem.dataset.warehouseName;
// Проверяем, есть ли товары в корзине
if (cart.size > 0) {
const confirmed = confirm(`При смене склада корзина будет очищена.\n\nПереключиться на склад "${warehouseName}"?`);
if (!confirmed) return;
}
try {
// Отправляем запрос на смену склада
const response = await fetch(`/pos/api/set-warehouse/${warehouseId}/`, {
method: 'POST',
headers: {
'X-CSRFToken': getCsrfToken()
}
});
const data = await response.json();
if (data.success) {
// Перезагружаем страницу для обновления данных
location.reload();
} else {
alert(`Ошибка: ${data.error}`);
}
} catch (error) {
console.error('Ошибка при смене склада:', error);
alert('Произошла ошибка при смене склада');
}
});
// Вспомогательная функция для получения CSRF токена
function getCsrfToken() {
const name = 'csrftoken';
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
// Инициализация
renderCategories();
renderProducts(); // Сначала пустая сетка
renderCart();
setupInfiniteScroll(); // Установка infinite scroll
// Установить фокус на строку поиска
document.getElementById('searchInput').focus();