fix(pos): исправлены проблемы с ценами витринных комплектов
- Исправлена логика установки useSalePrice при загрузке данных комплекта - Исправлено сохранение sale_price при снятии чекбокса 'Установить свою цену' - Исправлено сохранение измененных цен товаров в составе комплекта (unit_price) - Добавлен блок предупреждения о неактуальных ценах с функцией пересчета - Улучшена логика агрегации товаров при сохранении комплекта
This commit is contained in:
@@ -519,14 +519,74 @@ export class ProductManager {
|
||||
_renderShowcaseKitBadges(card, item, cart) {
|
||||
// Кнопка редактирования (только если не заблокирован другим)
|
||||
if (!item.is_locked || item.locked_by_me) {
|
||||
// Индикатор неактуальной цены (показываем первым, если есть)
|
||||
if (item.price_outdated) {
|
||||
const outdatedBadge = document.createElement('button');
|
||||
outdatedBadge.className = 'btn btn-sm p-0';
|
||||
outdatedBadge.style.position = 'absolute';
|
||||
outdatedBadge.style.top = '8px';
|
||||
outdatedBadge.style.right = '45px';
|
||||
outdatedBadge.style.zIndex = '10';
|
||||
outdatedBadge.style.width = '28px';
|
||||
outdatedBadge.style.height = '28px';
|
||||
outdatedBadge.style.borderRadius = '50%';
|
||||
outdatedBadge.style.display = 'flex';
|
||||
outdatedBadge.style.alignItems = 'center';
|
||||
outdatedBadge.style.justifyContent = 'center';
|
||||
outdatedBadge.style.backgroundColor = '#ff6b6b';
|
||||
outdatedBadge.style.border = '2px solid #fff';
|
||||
outdatedBadge.style.boxShadow = '0 2px 4px rgba(0,0,0,0.2)';
|
||||
outdatedBadge.style.cursor = 'pointer';
|
||||
outdatedBadge.style.transition = 'all 0.2s ease';
|
||||
outdatedBadge.title = 'Цена неактуальна - требуется обновление';
|
||||
outdatedBadge.innerHTML = '<i class="bi bi-exclamation-triangle-fill text-white" style="font-size: 14px;"></i>';
|
||||
outdatedBadge.onmouseenter = function() {
|
||||
this.style.transform = 'scale(1.1)';
|
||||
this.style.boxShadow = '0 3px 6px rgba(0,0,0,0.3)';
|
||||
};
|
||||
outdatedBadge.onmouseleave = function() {
|
||||
this.style.transform = 'scale(1)';
|
||||
this.style.boxShadow = '0 2px 4px rgba(0,0,0,0.2)';
|
||||
};
|
||||
outdatedBadge.onclick = (e) => {
|
||||
e.stopPropagation();
|
||||
if (window.showcaseManager) {
|
||||
window.showcaseManager.openEditModal(item.id);
|
||||
}
|
||||
};
|
||||
card.appendChild(outdatedBadge);
|
||||
}
|
||||
|
||||
// Кнопка редактирования (карандаш)
|
||||
const editBtn = document.createElement('button');
|
||||
editBtn.className = 'btn btn-sm btn-outline-primary';
|
||||
editBtn.className = 'btn btn-sm p-0';
|
||||
editBtn.style.position = 'absolute';
|
||||
editBtn.style.top = '5px';
|
||||
editBtn.style.right = '5px';
|
||||
editBtn.style.top = '8px';
|
||||
editBtn.style.right = '8px';
|
||||
editBtn.style.zIndex = '10';
|
||||
editBtn.innerHTML = '<i class="bi bi-pencil"></i>';
|
||||
editBtn.style.width = '32px';
|
||||
editBtn.style.height = '32px';
|
||||
editBtn.style.borderRadius = '6px';
|
||||
editBtn.style.display = 'flex';
|
||||
editBtn.style.alignItems = 'center';
|
||||
editBtn.style.justifyContent = 'center';
|
||||
editBtn.style.backgroundColor = '#4dabf7';
|
||||
editBtn.style.border = '2px solid #fff';
|
||||
editBtn.style.boxShadow = '0 2px 4px rgba(0,0,0,0.2)';
|
||||
editBtn.style.cursor = 'pointer';
|
||||
editBtn.style.transition = 'all 0.2s ease';
|
||||
editBtn.title = 'Редактировать комплект';
|
||||
editBtn.innerHTML = '<i class="bi bi-pencil-fill text-white" style="font-size: 14px;"></i>';
|
||||
editBtn.onmouseenter = function() {
|
||||
this.style.backgroundColor = '#339af0';
|
||||
this.style.transform = 'scale(1.05)';
|
||||
this.style.boxShadow = '0 3px 6px rgba(0,0,0,0.3)';
|
||||
};
|
||||
editBtn.onmouseleave = function() {
|
||||
this.style.backgroundColor = '#4dabf7';
|
||||
this.style.transform = 'scale(1)';
|
||||
this.style.boxShadow = '0 2px 4px rgba(0,0,0,0.2)';
|
||||
};
|
||||
editBtn.onclick = (e) => {
|
||||
e.stopPropagation();
|
||||
if (window.showcaseManager) {
|
||||
@@ -534,28 +594,6 @@ export class ProductManager {
|
||||
}
|
||||
};
|
||||
card.appendChild(editBtn);
|
||||
|
||||
// Индикатор неактуальной цены (красный кружок)
|
||||
if (item.price_outdated) {
|
||||
const outdatedBadge = document.createElement('div');
|
||||
outdatedBadge.className = 'badge bg-danger';
|
||||
outdatedBadge.style.position = 'absolute';
|
||||
outdatedBadge.style.top = '5px';
|
||||
outdatedBadge.style.right = '45px';
|
||||
outdatedBadge.style.zIndex = '10';
|
||||
outdatedBadge.style.width = '18px';
|
||||
outdatedBadge.style.height = '18px';
|
||||
outdatedBadge.style.padding = '0';
|
||||
outdatedBadge.style.borderRadius = '50%';
|
||||
outdatedBadge.style.display = 'flex';
|
||||
outdatedBadge.style.alignItems = 'center';
|
||||
outdatedBadge.style.justifyContent = 'center';
|
||||
outdatedBadge.style.fontSize = '10px';
|
||||
outdatedBadge.style.minWidth = '18px';
|
||||
outdatedBadge.title = 'Цена неактуальна';
|
||||
outdatedBadge.innerHTML = '!';
|
||||
card.appendChild(outdatedBadge);
|
||||
}
|
||||
}
|
||||
|
||||
// Индикация блокировки
|
||||
|
||||
@@ -85,6 +85,9 @@ export class ShowcaseManager {
|
||||
document.getElementById('priceAdjustmentValue')?.addEventListener('input', () => this.updatePriceCalculation());
|
||||
document.getElementById('useSalePrice')?.addEventListener('change', () => this.updatePriceCalculation());
|
||||
document.getElementById('salePrice')?.addEventListener('input', () => this.updatePriceCalculation());
|
||||
|
||||
// Кнопка пересчета цен
|
||||
document.getElementById('recalculatePricesBtn')?.addEventListener('click', () => this.recalculatePrices());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -157,26 +160,44 @@ export class ShowcaseManager {
|
||||
|
||||
// Заполняем временную корзину
|
||||
this.tempCart.clear();
|
||||
let hasOutdatedPrices = false;
|
||||
if (kit.items) {
|
||||
kit.items.forEach(item => {
|
||||
const key = `product-${item.product_id}-${item.sales_unit_id || 'base'}`;
|
||||
const actualPrice = item.actual_catalog_price ? parseFloat(item.actual_catalog_price) : null;
|
||||
const currentPrice = parseFloat(item.price) || 0;
|
||||
const isOutdated = item.price_outdated || (actualPrice !== null && Math.abs(currentPrice - actualPrice) > 0.01);
|
||||
|
||||
if (isOutdated) {
|
||||
hasOutdatedPrices = true;
|
||||
}
|
||||
|
||||
this.tempCart.set(key, {
|
||||
id: item.product_id,
|
||||
name: item.name || item.product_name, // Сервер отдаёт name
|
||||
price: parseFloat(item.price) || 0,
|
||||
price: currentPrice,
|
||||
qty: parseFloat(item.qty || item.quantity) || 1, // Сервер отдаёт qty
|
||||
type: 'product',
|
||||
sales_unit_id: item.sales_unit_id,
|
||||
unit_name: item.unit_name
|
||||
unit_name: item.unit_name,
|
||||
actual_catalog_price: actualPrice, // Сохраняем актуальную цену для пересчета
|
||||
price_outdated: isOutdated
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Показываем блок предупреждения о неактуальных ценах
|
||||
this.updatePriceOutdatedWarning(hasOutdatedPrices);
|
||||
|
||||
// Заполняем цены
|
||||
document.getElementById('priceAdjustmentType').value = kit.price_adjustment_type || 'none';
|
||||
document.getElementById('priceAdjustmentValue').value = kit.price_adjustment_value || 0;
|
||||
document.getElementById('useSalePrice').checked = kit.use_sale_price || false;
|
||||
document.getElementById('salePrice').value = kit.sale_price || '';
|
||||
|
||||
// Если sale_price установлен, автоматически включаем useSalePrice
|
||||
const salePriceValue = kit.sale_price || '';
|
||||
const hasSalePrice = salePriceValue && parseFloat(salePriceValue) > 0;
|
||||
document.getElementById('useSalePrice').checked = hasSalePrice;
|
||||
document.getElementById('salePrice').value = salePriceValue;
|
||||
|
||||
this.renderTempKitItems();
|
||||
this.updatePriceCalculation();
|
||||
@@ -363,6 +384,15 @@ export class ShowcaseManager {
|
||||
|
||||
// Обновляем базовую цену
|
||||
document.getElementById('tempKitBasePrice').textContent = formatMoney(totalBasePrice) + ' руб.';
|
||||
|
||||
// Проверяем наличие неактуальных цен и обновляем предупреждение
|
||||
let hasOutdatedPrices = false;
|
||||
this.tempCart.forEach((item) => {
|
||||
if (item.price_outdated || (item.actual_catalog_price !== null && item.actual_catalog_price !== undefined && Math.abs(item.price - item.actual_catalog_price) > 0.01)) {
|
||||
hasOutdatedPrices = true;
|
||||
}
|
||||
});
|
||||
this.updatePriceOutdatedWarning(hasOutdatedPrices);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -416,6 +446,50 @@ export class ShowcaseManager {
|
||||
document.getElementById('tempKitFinalPrice').textContent = formatMoney(finalPrice);
|
||||
}
|
||||
|
||||
/**
|
||||
* Обновляет отображение предупреждения о неактуальных ценах
|
||||
* @param {boolean} hasOutdated - Есть ли неактуальные цены
|
||||
*/
|
||||
updatePriceOutdatedWarning(hasOutdated) {
|
||||
const warningBlock = document.getElementById('priceOutdatedWarning');
|
||||
if (warningBlock) {
|
||||
warningBlock.style.display = hasOutdated ? 'block' : 'none';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Пересчитывает цены товаров на актуальные из каталога
|
||||
*/
|
||||
recalculatePrices() {
|
||||
let updated = false;
|
||||
|
||||
this.tempCart.forEach((item, key) => {
|
||||
if (item.actual_catalog_price !== null && item.actual_catalog_price !== undefined) {
|
||||
const oldPrice = item.price;
|
||||
const newPrice = item.actual_catalog_price;
|
||||
|
||||
if (Math.abs(oldPrice - newPrice) > 0.01) {
|
||||
item.price = newPrice;
|
||||
item.price_outdated = false;
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (updated) {
|
||||
// Перерисовываем список товаров и пересчитываем цены
|
||||
this.renderTempKitItems();
|
||||
this.updatePriceCalculation();
|
||||
|
||||
// Скрываем предупреждение
|
||||
this.updatePriceOutdatedWarning(false);
|
||||
|
||||
showToast('success', 'Цены обновлены на актуальные из каталога');
|
||||
} else {
|
||||
showToast('info', 'Все цены уже актуальны');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Обрабатывает загрузку фото
|
||||
*/
|
||||
@@ -462,6 +536,8 @@ export class ShowcaseManager {
|
||||
document.getElementById('useSalePrice').checked = false;
|
||||
document.getElementById('salePrice').value = '';
|
||||
this.removePhoto();
|
||||
// Скрываем предупреждение о неактуальных ценах
|
||||
this.updatePriceOutdatedWarning(false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -537,8 +613,9 @@ export class ShowcaseManager {
|
||||
formData.append('showcase_created_at', data.createdAt || '');
|
||||
formData.append('price_adjustment_type', data.adjustmentType);
|
||||
formData.append('price_adjustment_value', data.adjustmentValue);
|
||||
formData.append('use_sale_price', data.useSalePrice);
|
||||
formData.append('sale_price', data.salePrice || 0);
|
||||
formData.append('use_sale_price', data.useSalePrice ? '1' : '0');
|
||||
// Если useSalePrice выключен, отправляем пустую строку для явной очистки sale_price на сервере
|
||||
formData.append('sale_price', data.useSalePrice ? (data.salePrice || '') : '');
|
||||
|
||||
if (!this.isEditMode) {
|
||||
formData.append('quantity', data.quantity);
|
||||
@@ -550,7 +627,7 @@ export class ShowcaseManager {
|
||||
items.push({
|
||||
product_id: item.id,
|
||||
quantity: item.qty,
|
||||
price: item.price,
|
||||
unit_price: item.price, // Используем unit_price для сохранения измененной цены товара
|
||||
sales_unit_id: item.sales_unit_id || null
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user