Files
octopus/myproject/inventory/migrations/0009_fix_showcase_items_status.py
Andrey Smakotin cfc6ce451e ShowcaseItem: защита от двойной продажи витринных букетов
Новая архитектура:
- ShowcaseItem модель - физический экземпляр букета на витрине
- OneToOneField(sold_order_item) - БД-уровневая защита от двойной продажи
- Поддержка создания нескольких экземпляров одного букета
- Возможность продавать N из M доступных (например 2 из 5)

Изменения:
- inventory/models.py: добавлена модель ShowcaseItem с методами lock/unlock/mark_sold
- inventory/services/showcase_manager.py: переработан для работы с ShowcaseItem
- pos/views.py: API поддерживает quantity и showcase_item_ids
- pos/templates/pos/terminal.html: поле "Сколько букетов создать"
- pos/static/pos/js/terminal.js: выбор количества, передача showcase_item_ids

Миграции:
- 0007: создание модели ShowcaseItem
- 0008: data migration существующих букетов
- 0009: очистка ShowcaseItem для уже проданных букетов

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 23:51:37 +03:00

66 lines
2.3 KiB
Python
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.
# Generated manually - Fix ShowcaseItem status for already sold kits
from django.db import migrations
def fix_showcase_items_status(apps, schema_editor):
"""
Исправляем статус ShowcaseItem для уже проданных комплектов.
Логика:
- Если у ShowcaseItem нет активных резервов (status='reserved') →
это уже проданный/разобранный букет → удаляем ShowcaseItem
"""
ShowcaseItem = apps.get_model('inventory', 'ShowcaseItem')
Reservation = apps.get_model('inventory', 'Reservation')
# Находим все ShowcaseItem в статусе 'available'
available_items = ShowcaseItem.objects.filter(status='available')
items_to_delete = []
for item in available_items:
# Проверяем есть ли активные резервы для этого экземпляра
has_active_reservations = Reservation.objects.filter(
showcase_item=item,
status='reserved'
).exists()
# Если резервы не привязаны к showcase_item, проверяем старым способом
if not has_active_reservations:
has_active_reservations = Reservation.objects.filter(
product_kit=item.product_kit,
showcase=item.showcase,
status='reserved'
).exists()
if not has_active_reservations:
# Нет активных резервов - этот букет уже продан/разобран
items_to_delete.append(item.id)
# Удаляем ShowcaseItem без активных резервов
if items_to_delete:
ShowcaseItem.objects.filter(id__in=items_to_delete).delete()
def reverse_migration(apps, schema_editor):
"""
Откат невозможен - удалённые ShowcaseItem не восстановить.
Но это безопасно - они относились к уже проданным букетам.
"""
pass
class Migration(migrations.Migration):
dependencies = [
('inventory', '0008_migrate_showcase_kits_to_items'),
]
operations = [
migrations.RunPython(
fix_showcase_items_status,
reverse_code=reverse_migration
),
]