82 lines
2.9 KiB
Python
82 lines
2.9 KiB
Python
import uuid
|
|
from decimal import Decimal
|
|
|
|
from django.db import models
|
|
from django.db.models import Q
|
|
|
|
|
|
class CostType(models.TextChoices):
|
|
COMMISSION = "commission", "Комиссия"
|
|
DELIVERY = "delivery", "Доставка"
|
|
STORAGE = "storage", "Хранение"
|
|
ADVERTISING = "advertising", "Реклама"
|
|
ACQUIRING = "acquiring", "Эквайринг"
|
|
RETURN = "return", "Возврат"
|
|
OTHER = "other", "Прочее"
|
|
|
|
|
|
class Cost(models.Model):
|
|
"""Additional product- or sale-line-level expense."""
|
|
|
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
|
project = models.ForeignKey(
|
|
"commerce.ExternalProject", null=True, blank=True, on_delete=models.PROTECT
|
|
)
|
|
source = models.ForeignKey(
|
|
"commerce.SourceSystem",
|
|
on_delete=models.PROTECT,
|
|
related_name="costs",
|
|
verbose_name="Источник",
|
|
)
|
|
product = models.ForeignKey(
|
|
"commerce.Product",
|
|
on_delete=models.PROTECT,
|
|
null=True,
|
|
blank=True,
|
|
related_name="costs",
|
|
verbose_name="Товар",
|
|
)
|
|
sale_line = models.ForeignKey(
|
|
"commerce.SaleLine",
|
|
on_delete=models.CASCADE,
|
|
null=True,
|
|
blank=True,
|
|
related_name="costs",
|
|
verbose_name="Позиция продажи",
|
|
)
|
|
external_id = models.CharField("Внешний ID", max_length=255, blank=True)
|
|
channel = models.CharField("Канал продаж", max_length=64, blank=True, db_index=True)
|
|
cost_type = models.CharField("Тип расхода", max_length=32, choices=CostType.choices)
|
|
amount = models.DecimalField(
|
|
"Сумма", max_digits=18, decimal_places=2, default=Decimal("0")
|
|
)
|
|
currency = models.CharField("Валюта", max_length=3, default="RUB")
|
|
occurred_at = models.DateTimeField("Дата расхода", db_index=True)
|
|
metadata = models.JSONField("Дополнительные данные", default=dict, blank=True)
|
|
created_at = models.DateTimeField("Создано", auto_now_add=True)
|
|
|
|
class Meta:
|
|
verbose_name = "Расход"
|
|
verbose_name_plural = "Расходы"
|
|
constraints = [
|
|
models.CheckConstraint(
|
|
condition=Q(product__isnull=False)
|
|
| Q(sale_line__isnull=False)
|
|
| Q(project__isnull=False),
|
|
name="commerce_cost_has_target",
|
|
),
|
|
models.UniqueConstraint(
|
|
fields=["source", "external_id", "cost_type"],
|
|
condition=~Q(external_id=""),
|
|
name="commerce_cost_source_external_type",
|
|
),
|
|
]
|
|
indexes = [
|
|
models.Index(
|
|
fields=["product", "occurred_at"], name="commerce_cost_product_date"
|
|
)
|
|
]
|
|
|
|
def __str__(self):
|
|
return f"{self.get_cost_type_display()}: {self.amount} {self.currency}"
|