diff --git a/myproject/inventory/services/showcase_manager.py b/myproject/inventory/services/showcase_manager.py
index 201c916..6e09493 100644
--- a/myproject/inventory/services/showcase_manager.py
+++ b/myproject/inventory/services/showcase_manager.py
@@ -666,6 +666,113 @@ class ShowcaseManager:
'message': f'Ошибка разбора: {str(e)}'
}
+ @staticmethod
+ def write_off_from_showcase(showcase_item, reason='spoilage', notes=None, created_by=None):
+ """
+ Списывает экземпляр витринного комплекта:
+ 1. Создаёт документ списания с компонентами комплекта
+ 2. Преобразует резервы комплекта в позиции документа списания
+ 3. Помечает экземпляр как разобранный
+
+ Args:
+ showcase_item: ShowcaseItem - экземпляр для списания
+ reason: str - причина списания (spoilage по умолчанию)
+ notes: str - примечания
+ created_by: User - пользователь
+
+ Returns:
+ dict: {
+ 'success': bool,
+ 'document_id': int,
+ 'document_number': str,
+ 'items_count': int,
+ 'message': str,
+ 'error': str (при ошибке)
+ }
+ """
+ from inventory.services.writeoff_document_service import WriteOffDocumentService
+
+ # Проверка статуса
+ if showcase_item.status == 'sold':
+ return {
+ 'success': False,
+ 'document_id': None,
+ 'message': 'Нельзя списать проданный экземпляр'
+ }
+
+ if showcase_item.status == 'dismantled':
+ return {
+ 'success': False,
+ 'document_id': None,
+ 'message': 'Экземпляр уже разобран'
+ }
+
+ try:
+ with transaction.atomic():
+ warehouse = showcase_item.showcase.warehouse
+ product_kit = showcase_item.product_kit
+
+ # Создаём документ списания (черновик)
+ document = WriteOffDocumentService.create_document(
+ warehouse=warehouse,
+ date=timezone.now().date(),
+ notes=f'Списание витринного комплекта: {product_kit.name}',
+ created_by=created_by
+ )
+
+ # Получаем резервы этого экземпляра
+ reservations = Reservation.objects.filter(
+ showcase_item=showcase_item,
+ status='reserved'
+ ).select_related('product')
+
+ items_count = 0
+
+ for reservation in reservations:
+ # Добавляем позицию в документ списания
+ # Используем add_item без создания резерва (меняем статус существующего)
+ from inventory.models import WriteOffDocumentItem
+
+ item = WriteOffDocumentItem.objects.create(
+ document=document,
+ product=reservation.product,
+ quantity=reservation.quantity,
+ reason=reason,
+ notes=notes
+ )
+
+ # Привязываем существующий резерв к позиции документа
+ reservation.writeoff_document_item = item
+ reservation.status = 'converted_to_writeoff'
+ reservation.converted_at = timezone.now()
+ reservation.save(update_fields=['writeoff_document_item', 'status', 'converted_at'])
+
+ items_count += 1
+
+ # Помечаем экземпляр как разобранный
+ showcase_item.status = 'dismantled'
+ showcase_item.save(update_fields=['status'])
+
+ # Помечаем шаблон комплекта как снятый
+ if product_kit.status != 'discontinued':
+ product_kit.status = 'discontinued'
+ product_kit.save(update_fields=['status'])
+
+ return {
+ 'success': True,
+ 'document_id': document.id,
+ 'document_number': document.document_number,
+ 'items_count': items_count,
+ 'message': f'Создан документ {document.document_number} с {items_count} позициями'
+ }
+
+ except Exception as e:
+ return {
+ 'success': False,
+ 'document_id': None,
+ 'message': f'Ошибка списания: {str(e)}'
+ }
+
@staticmethod
def get_showcase_items_for_pos(showcase=None):
"""
diff --git a/myproject/pos/static/pos/js/terminal.js b/myproject/pos/static/pos/js/terminal.js
index 2512642..0665b26 100644
--- a/myproject/pos/static/pos/js/terminal.js
+++ b/myproject/pos/static/pos/js/terminal.js
@@ -1923,6 +1923,7 @@ async function openEditKitModal(kitId) {
// По��азываем кнопку "Разобрать" и блок добавления товаров
document.getElementById('disassembleKitBtn').style.display = 'block';
+ document.getElementById('writeOffKitBtn').style.display = 'block';
document.getElementById('showcaseKitQuantityBlock').style.display = 'none';
document.getElementById('addProductBlock').style.display = 'block';
@@ -2554,6 +2555,53 @@ document.getElementById('disassembleKitBtn').addEventListener('click', async ()
}
});
+// Обработчик кнопки "Списать букет"
+document.getElementById('writeOffKitBtn').addEventListener('click', async () => {
+ if (!isEditMode || !editingKitId) {
+ alert('Ошибка: режим редактирования не активен');
+ return;
+ }
+
+ // Запрос подтверждения
+ const confirmed = confirm(
+ 'Вы уверены?\n\n' +
+ 'Букет будет списан:\n' +
+ '• Будет создан документ списания с компонентами букета\n' +
+ '• Комплект будет помечен как "Снят"\n' +
+ '• Будет открыта страница документа для редактирования\n\n' +
+ 'Продолжить?'
+ );
+
+ if (!confirmed) {
+ return;
+ }
+
+ try {
+ const response = await fetch(`/pos/api/product-kits/${editingKitId}/write-off/`, {
+ method: 'POST',
+ headers: {
+ 'X-CSRFToken': getCsrfToken()
+ }
+ });
+
+ const data = await response.json();
+
+ if (data.success) {
+ // Закрываем модальное окно
+ const modal = bootstrap.Modal.getInstance(document.getElementById('createTempKitModal'));
+ modal.hide();
+
+ // Перенаправляем на страницу документа
+ window.location.href = data.redirect_url;
+ } else {
+ alert(`❌ Ошибка: ${data.error}`);
+ }
+ } catch (error) {
+ console.error('Error writing off kit:', error);
+ alert('Произошла ошибка при списании букета');
+ }
+});
+
// Вспомогательная функция для определения мобильного устройства
function isMobileDevice() {
// Проверяем по юзер-агенту и размеру экрана
@@ -2616,8 +2664,9 @@ document.getElementById('createTempKitModal').addEventListener('hidden.bs.modal'
document.getElementById('createTempKitModalLabel').textContent = 'Создать витринный букет из корзины';
document.getElementById('confirmCreateTempKit').innerHTML = ' Создать и зарезервировать';
- // Скрываем кнопку "Разобрать" и блок добавления товаров
+ // Скрываем кнопки "Разобрать" и "Списать" и блок добавления товаров
document.getElementById('disassembleKitBtn').style.display = 'none';
+ document.getElementById('writeOffKitBtn').style.display = 'none';
document.getElementById('showcaseKitQuantityBlock').style.display = 'block';
document.getElementById('addProductBlock').style.display = 'none';
}
diff --git a/myproject/pos/templates/pos/terminal.html b/myproject/pos/templates/pos/terminal.html
index 05682d4..a1ba5f9 100644
--- a/myproject/pos/templates/pos/terminal.html
+++ b/myproject/pos/templates/pos/terminal.html
@@ -330,6 +330,11 @@
Разобрать букет
+
+
+