Добавлена функциональность витрин для POS: модели, сервисы, UI
- Создана модель Showcase (витрина) привязанная к складу - Расширена Reservation для поддержки витринных резервов - Добавлены поля в OrderItem для маркировки витринных продаж - Реализован ShowcaseManager с методами резервирования, продажи и разбора - Обновлён админ-интерфейс для управления витринами - Добавлена кнопка Витрина в POS (категории) и API для просмотра - Добавлена кнопка На витрину в панели действий POS - Миграции готовы к применению
This commit is contained in:
@@ -359,10 +359,36 @@ class InventoryLine(models.Model):
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
|
||||
class Showcase(models.Model):
|
||||
"""
|
||||
Витрина - место выкладки собранных букетов/комплектов.
|
||||
Привязана к конкретному складу для учёта резервов.
|
||||
"""
|
||||
name = models.CharField(max_length=200, verbose_name="Название")
|
||||
warehouse = models.ForeignKey(Warehouse, on_delete=models.CASCADE,
|
||||
related_name='showcases', verbose_name="Склад")
|
||||
description = models.TextField(blank=True, null=True, verbose_name="Описание")
|
||||
is_active = models.BooleanField(default=True, verbose_name="Активна")
|
||||
created_at = models.DateTimeField(auto_now_add=True, verbose_name="Дата создания")
|
||||
updated_at = models.DateTimeField(auto_now=True, verbose_name="Дата обновления")
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Витрина"
|
||||
verbose_name_plural = "Витрины"
|
||||
ordering = ['warehouse', 'name']
|
||||
indexes = [
|
||||
models.Index(fields=['warehouse']),
|
||||
models.Index(fields=['is_active']),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.name} ({self.warehouse.name})"
|
||||
|
||||
|
||||
class Reservation(models.Model):
|
||||
"""
|
||||
Резервирование товара для заказа.
|
||||
Отслеживает, какой товар зарезервирован за каким заказом.
|
||||
Резервирование товара для заказа или витрины.
|
||||
Отслеживает, какой товар зарезервирован за каким заказом или витриной.
|
||||
"""
|
||||
STATUS_CHOICES = [
|
||||
('reserved', 'Зарезервирован'),
|
||||
@@ -373,6 +399,10 @@ class Reservation(models.Model):
|
||||
order_item = models.ForeignKey('orders.OrderItem', on_delete=models.CASCADE,
|
||||
related_name='reservations', verbose_name="Позиция заказа",
|
||||
null=True, blank=True)
|
||||
showcase = models.ForeignKey(Showcase, on_delete=models.CASCADE,
|
||||
related_name='reservations', verbose_name="Витрина",
|
||||
null=True, blank=True,
|
||||
help_text="Витрина, на которой выложен букет")
|
||||
product = models.ForeignKey(Product, on_delete=models.CASCADE,
|
||||
related_name='reservations', verbose_name="Товар")
|
||||
warehouse = models.ForeignKey(Warehouse, on_delete=models.CASCADE,
|
||||
@@ -393,11 +423,17 @@ class Reservation(models.Model):
|
||||
models.Index(fields=['product', 'warehouse']),
|
||||
models.Index(fields=['status']),
|
||||
models.Index(fields=['order_item']),
|
||||
models.Index(fields=['showcase']),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
order_info = f" (заказ {self.order_item.order.order_number})" if self.order_item else ""
|
||||
return f"Резерв {self.product.name}: {self.quantity} шт{order_info} [{self.get_status_display()}]"
|
||||
if self.order_item:
|
||||
context = f" (заказ {self.order_item.order.order_number})"
|
||||
elif self.showcase:
|
||||
context = f" (витрина {self.showcase.name})"
|
||||
else:
|
||||
context = ""
|
||||
return f"Резерв {self.product.name}: {self.quantity} шт{context} [{self.get_status_display()}]"
|
||||
|
||||
|
||||
class Stock(models.Model):
|
||||
|
||||
Reference in New Issue
Block a user