Реализован функционал создания временных комплектов на витрину из POS
- Добавлен API endpoint для создания временного комплекта из корзины - Реализован endpoint получения списка активных витрин - Создано модальное окно для настройки комплекта и выбора витрины - JavaScript логика: валидация корзины, отправка данных, очистка после успеха - Автоматическая генерация названия комплекта с датой и временем - Агрегация дубликатов товаров в корзине перед созданием - Резервирование компонентов на витрину через ShowcaseManager - Расчёт и отображение итоговой цены комплекта
This commit is contained in:
@@ -285,9 +285,200 @@ document.getElementById('clearCart').onclick = clearCart;
|
||||
|
||||
// Кнопка "На витрину" - функционал будет добавлен позже
|
||||
document.getElementById('addToShowcaseBtn').onclick = () => {
|
||||
alert('Функционал "На витрину" будет реализован позже');
|
||||
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;
|
||||
}
|
||||
|
||||
// Генерируем название по умолчанию
|
||||
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();
|
||||
|
||||
// Заполняем список товаров из корзины
|
||||
renderTempKitItems();
|
||||
|
||||
// Открываем модальное окно
|
||||
const modal = new bootstrap.Modal(document.getElementById('createTempKitModal'));
|
||||
modal.show();
|
||||
}
|
||||
|
||||
// Загрузка списка витрин
|
||||
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) {
|
||||
data.showcases.forEach(showcase => {
|
||||
const option = document.createElement('option');
|
||||
option.value = showcase.id;
|
||||
option.textContent = `${showcase.name} (${showcase.warehouse_name})`;
|
||||
select.appendChild(option);
|
||||
});
|
||||
} else {
|
||||
select.innerHTML = '<option value="">Нет доступных витрин</option>';
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading showcases:', error);
|
||||
alert('Ошибка загрузки витрин');
|
||||
}
|
||||
}
|
||||
|
||||
// Отображение товаров из корзины в модальном окне
|
||||
function renderTempKitItems() {
|
||||
const container = document.getElementById('tempKitItemsList');
|
||||
container.innerHTML = '';
|
||||
|
||||
let estimatedTotal = 0;
|
||||
|
||||
cart.forEach((item, cartKey) => {
|
||||
// Только товары (не комплекты)
|
||||
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.innerHTML = `
|
||||
<div>
|
||||
<strong>${item.name}</strong>
|
||||
<br>
|
||||
<small class="text-muted">${item.qty} шт × ${formatMoney(item.price)} руб.</small>
|
||||
</div>
|
||||
<div class="text-end">
|
||||
<strong>${formatMoney(item.qty * item.price)} руб.</strong>
|
||||
</div>
|
||||
`;
|
||||
container.appendChild(itemDiv);
|
||||
|
||||
estimatedTotal += item.qty * item.price;
|
||||
});
|
||||
|
||||
document.getElementById('tempKitEstimatedPrice').textContent = formatMoney(estimatedTotal);
|
||||
}
|
||||
|
||||
// Подтверждение создания временного комплекта
|
||||
document.getElementById('confirmCreateTempKit').onclick = async () => {
|
||||
const kitName = document.getElementById('tempKitName').value.trim();
|
||||
const showcaseId = document.getElementById('showcaseSelect').value;
|
||||
|
||||
// Валидация
|
||||
if (!kitName) {
|
||||
alert('Введите название комплекта');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!showcaseId) {
|
||||
alert('Выберите витрину');
|
||||
return;
|
||||
}
|
||||
|
||||
// Собираем товары из корзины
|
||||
const items = [];
|
||||
cart.forEach((item, cartKey) => {
|
||||
if (item.type === 'product') {
|
||||
items.push({
|
||||
product_id: item.id,
|
||||
quantity: item.qty
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (items.length === 0) {
|
||||
alert('Нет товаров для создания комплекта');
|
||||
return;
|
||||
}
|
||||
|
||||
// Отправляем запрос на сервер
|
||||
const confirmBtn = document.getElementById('confirmCreateTempKit');
|
||||
confirmBtn.disabled = true;
|
||||
confirmBtn.innerHTML = '<span class="spinner-border spinner-border-sm me-2"></span>Создание...';
|
||||
|
||||
try {
|
||||
const response = await fetch('/pos/api/create-temp-kit/', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': getCookie('csrftoken')
|
||||
},
|
||||
body: JSON.stringify({
|
||||
kit_name: kitName,
|
||||
showcase_id: parseInt(showcaseId),
|
||||
items: items,
|
||||
price_adjustment_type: 'none',
|
||||
price_adjustment_value: 0
|
||||
})
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
// Успех!
|
||||
alert(`✅ ${data.message}
|
||||
|
||||
Комплект: ${data.kit_name}
|
||||
Цена: ${data.kit_price} руб.
|
||||
Зарезервировано компонентов: ${data.reservations_count}`);
|
||||
|
||||
// Очищаем корзину
|
||||
clearCart();
|
||||
|
||||
// Закрываем модальное окно
|
||||
const modal = bootstrap.Modal.getInstance(document.getElementById('createTempKitModal'));
|
||||
modal.hide();
|
||||
} else {
|
||||
alert(`Ошибка: ${data.error}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error creating temp kit:', error);
|
||||
alert('Ошибка при создании комплекта');
|
||||
} finally {
|
||||
confirmBtn.disabled = false;
|
||||
confirmBtn.innerHTML = '<i class="bi bi-check-circle"></i> Создать и зарезервировать';
|
||||
}
|
||||
};
|
||||
|
||||
// Вспомогательная функция для получения 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('checkoutNow').onclick = async () => {
|
||||
alert('Функционал будет подключен позже: создание заказа и списание со склада.');
|
||||
|
||||
Reference in New Issue
Block a user