feat(pos): enhance product kit price handling and UI interaction

- Updated price aggregation logic in update_product_kit to include unit prices.
- Improved terminal.js to allow inline editing of product prices in the kit.
- Added parsePrice function for consistent price parsing across the application.
- Ensured that the correct price is saved when creating or updating product kits.
This commit is contained in:
2026-01-27 11:31:22 +03:00
parent 2dc397b3ce
commit 2aed6f60e5
3 changed files with 93 additions and 22 deletions

View File

@@ -2165,11 +2165,63 @@ function renderTempKitItems() {
// Левая часть: название и цена
const leftDiv = document.createElement('div');
leftDiv.className = 'flex-grow-1';
leftDiv.innerHTML = `
<strong class="small">${item.name}</strong>
<br>
<small class="text-muted">${formatMoney(item.price)} руб. / шт.</small>
`;
// Название товара
const nameSpan = document.createElement('strong');
nameSpan.className = 'small';
nameSpan.textContent = item.name;
leftDiv.appendChild(nameSpan);
leftDiv.appendChild(document.createElement('br'));
// Цена с возможностью редактирования
const priceContainer = document.createElement('div');
priceContainer.className = 'd-inline-flex align-items-center gap-1';
// Отображение цены (кликабельное)
const priceDisplay = document.createElement('small');
priceDisplay.className = 'text-muted price-display';
priceDisplay.style.cursor = 'pointer';
priceDisplay.innerHTML = `<u>${formatMoney(item.price)}</u> руб. / шт.`;
priceDisplay.title = 'Кликните для изменения цены';
// Поле ввода (скрыто по умолчанию)
const priceInput = document.createElement('input');
priceInput.type = 'number';
priceInput.step = '0.01';
priceInput.className = 'form-control form-control-sm';
priceInput.style.width = '80px';
priceInput.style.display = 'none';
priceInput.value = item.price;
// Клик на цену — показать input
priceDisplay.onclick = () => {
priceDisplay.style.display = 'none';
priceInput.style.display = 'inline-block';
priceInput.focus();
priceInput.select();
};
// Потеря фокуса или Enter — сохранить и скрыть input
const savePrice = () => {
const newPrice = parseFloat(priceInput.value) || 0;
item.price = newPrice;
priceDisplay.innerHTML = `<u>${formatMoney(newPrice)}</u> руб. / шт.`;
priceInput.style.display = 'none';
priceDisplay.style.display = 'inline';
renderTempKitItems(); // Пересчёт итогов
};
priceInput.onblur = savePrice;
priceInput.onkeydown = (e) => {
if (e.key === 'Enter') {
e.preventDefault();
savePrice();
}
};
priceContainer.appendChild(priceInput);
priceContainer.appendChild(priceDisplay);
leftDiv.appendChild(priceContainer);
// Правая часть: контролы количества и удаление
const rightDiv = document.createElement('div');

View File

@@ -1371,12 +1371,19 @@ def update_product_kit(request, kit_id):
if len(products) != len(product_ids):
return JsonResponse({'success': False, 'error': 'Некоторые товары не найдены'}, status=400)
# Агрегируем количества
# Агрегируем количества и цены
aggregated_items = {}
for item in items:
product_id = item['product_id']
quantity = Decimal(str(item['quantity']))
aggregated_items[product_id] = aggregated_items.get(product_id, Decimal('0')) + quantity
unit_price = item.get('unit_price')
if product_id in aggregated_items:
aggregated_items[product_id]['quantity'] += quantity
else:
aggregated_items[product_id] = {
'quantity': quantity,
'unit_price': Decimal(str(unit_price)) if unit_price is not None else None
}
with transaction.atomic():
# Получаем старый состав для сравнения
@@ -1397,7 +1404,7 @@ def update_product_kit(request, kit_id):
for product_id in all_product_ids:
old_qty = old_items.get(product_id, Decimal('0'))
new_qty = aggregated_items.get(product_id, Decimal('0'))
new_qty = aggregated_items.get(product_id, {}).get('quantity', Decimal('0'))
diff = new_qty - old_qty
if diff > 0 and showcase:
@@ -1436,13 +1443,15 @@ def update_product_kit(request, kit_id):
# Обновляем состав
kit.kit_items.all().delete()
for product_id, quantity in aggregated_items.items():
for product_id, item_data in aggregated_items.items():
product = products[product_id]
# Используем переданную цену, если есть, иначе актуальную из каталога
final_price = item_data['unit_price'] if item_data['unit_price'] is not None else product.actual_price
KitItem.objects.create(
kit=kit,
product=product,
quantity=quantity,
unit_price=product.actual_price # Фиксируем актуальную цену
quantity=item_data['quantity'],
unit_price=final_price
)
kit.recalculate_base_price()