Рефакторинг моделей заказов и добавление методов оплаты
This commit is contained in:
154
myproject/orders/models/order_item.py
Normal file
154
myproject/orders/models/order_item.py
Normal file
@@ -0,0 +1,154 @@
|
||||
from django.db import models
|
||||
from django.core.exceptions import ValidationError
|
||||
from products.models import Product, ProductKit
|
||||
from simple_history.models import HistoricalRecords
|
||||
from .order import Order
|
||||
|
||||
|
||||
class OrderItem(models.Model):
|
||||
"""
|
||||
Позиция (товар) в заказе.
|
||||
Хранит информацию о товаре или комплекте, количестве и цене на момент заказа.
|
||||
"""
|
||||
order = models.ForeignKey(
|
||||
Order,
|
||||
on_delete=models.CASCADE,
|
||||
related_name='items',
|
||||
verbose_name="Заказ"
|
||||
)
|
||||
|
||||
# Товар или комплект (один из двух должен быть заполнен)
|
||||
product = models.ForeignKey(
|
||||
Product,
|
||||
on_delete=models.PROTECT,
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name='order_items',
|
||||
verbose_name="Товар"
|
||||
)
|
||||
|
||||
product_kit = models.ForeignKey(
|
||||
ProductKit,
|
||||
on_delete=models.PROTECT,
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name='order_items',
|
||||
verbose_name="Комплект товаров"
|
||||
)
|
||||
|
||||
quantity = models.PositiveIntegerField(
|
||||
default=1,
|
||||
verbose_name="Количество"
|
||||
)
|
||||
|
||||
price = models.DecimalField(
|
||||
max_digits=10,
|
||||
decimal_places=2,
|
||||
verbose_name="Цена за единицу",
|
||||
help_text="Цена на момент создания заказа (фиксируется)"
|
||||
)
|
||||
|
||||
is_custom_price = models.BooleanField(
|
||||
default=False,
|
||||
verbose_name="Цена изменена вручную",
|
||||
help_text="True если цена была изменена вручную при создании заказа"
|
||||
)
|
||||
|
||||
# Витринные продажи
|
||||
is_from_showcase = models.BooleanField(
|
||||
default=False,
|
||||
verbose_name="С витрины",
|
||||
help_text="True если товар продан с витрины"
|
||||
)
|
||||
|
||||
showcase = models.ForeignKey(
|
||||
'inventory.Showcase',
|
||||
on_delete=models.SET_NULL,
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name='order_items',
|
||||
verbose_name="Витрина",
|
||||
help_text="Витрина, с которой был продан товар"
|
||||
)
|
||||
|
||||
# Временные метки
|
||||
created_at = models.DateTimeField(
|
||||
auto_now_add=True,
|
||||
verbose_name="Дата добавления"
|
||||
)
|
||||
|
||||
# История изменений
|
||||
history = HistoricalRecords()
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Позиция заказа"
|
||||
verbose_name_plural = "Позиции заказа"
|
||||
indexes = [
|
||||
models.Index(fields=['order']),
|
||||
models.Index(fields=['product']),
|
||||
models.Index(fields=['product_kit']),
|
||||
models.Index(fields=['is_from_showcase']),
|
||||
models.Index(fields=['showcase']),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
item_name = ""
|
||||
if self.product:
|
||||
item_name = self.product.name
|
||||
elif self.product_kit:
|
||||
item_name = self.product_kit.name
|
||||
return f"{item_name} x{self.quantity} в заказе #{self.order.order_number}"
|
||||
|
||||
def clean(self):
|
||||
"""Валидация модели"""
|
||||
super().clean()
|
||||
|
||||
# Проверка: должен быть заполнен либо product, либо product_kit
|
||||
if not self.product and not self.product_kit:
|
||||
raise ValidationError(
|
||||
'Необходимо указать либо товар, либо комплект товаров'
|
||||
)
|
||||
|
||||
# Проверка: не должны быть заполнены оба поля одновременно
|
||||
if self.product and self.product_kit:
|
||||
raise ValidationError(
|
||||
'Нельзя указать одновременно и товар, и комплект'
|
||||
)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
# Автоматически фиксируем цену при создании, если она не указана
|
||||
if not self.price:
|
||||
if self.product:
|
||||
self.price = self.product.price
|
||||
elif self.product_kit:
|
||||
self.price = self.product_kit.price
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
def get_total_price(self):
|
||||
"""Возвращает общую стоимость позиции"""
|
||||
return self.price * self.quantity
|
||||
|
||||
@property
|
||||
def item_name(self):
|
||||
"""Название товара/комплекта"""
|
||||
if self.product:
|
||||
return self.product.name
|
||||
elif self.product_kit:
|
||||
return self.product_kit.name
|
||||
return "Не указано"
|
||||
|
||||
@property
|
||||
def original_price(self):
|
||||
"""Оригинальная цена товара/комплекта из каталога"""
|
||||
if self.product:
|
||||
return self.product.actual_price
|
||||
elif self.product_kit:
|
||||
return self.product_kit.actual_price
|
||||
return None
|
||||
|
||||
@property
|
||||
def price_difference(self):
|
||||
"""Разница между установленной ценой и оригинальной"""
|
||||
if self.is_custom_price and self.original_price:
|
||||
return self.price - self.original_price
|
||||
return None
|
||||
Reference in New Issue
Block a user