"""Документы ERP WaterSurf.""" from decimal import Decimal from django.db import models from django.db.models import Sum from references.models import Currency, OrderKind, Client, Organization, Supplier, Employee, CashAccount, Product class CustomerOrder(models.Model): date = models.DateField("Дата") number = models.CharField("Номер", max_length=50) order_kind = models.ForeignKey(OrderKind, on_delete=models.PROTECT, verbose_name="Вид заказа") organization = models.ForeignKey(Organization, on_delete=models.PROTECT, verbose_name="Организация") client = models.ForeignKey(Client, on_delete=models.PROTECT, verbose_name="Клиент") total_amount = models.DecimalField("Стоимость заказа", max_digits=18, decimal_places=2, default=Decimal("0"), editable=False) author = models.ForeignKey(Employee, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="Автор", related_name="customer_orders") class Meta: verbose_name = "Заказ клиента" verbose_name_plural = "Заказы клиентов" def __str__(self): return f"{self.number} от {self.date}" def recalc_total(self): self.total_amount = sum((i.price * i.quantity for i in self.items.all()), Decimal("0")) def get_economics(self): """Сводка по поступлениям и расходам по заказу: поступления, расходы (через заказы поставщику + прямые), маржа, маржинальность, рентабельность.""" total_inflows = self.cash_inflows.aggregate(s=Sum("amount"))["s"] or Decimal("0") expenses_via_supplier = CashExpense.objects.filter(supplier_order__customer_order=self).aggregate(s=Sum("amount"))["s"] or Decimal("0") expenses_direct = self.cash_expenses.aggregate(s=Sum("amount"))["s"] or Decimal("0") total_expenses = expenses_via_supplier + expenses_direct margin = total_inflows - total_expenses margin_pct = (margin / total_inflows * 100) if total_inflows else None profitability_pct = (margin / total_expenses * 100) if total_expenses else None return { "total_inflows": total_inflows, "expenses_via_supplier": expenses_via_supplier, "expenses_direct": expenses_direct, "total_expenses": total_expenses, "margin": margin, "margin_pct": margin_pct, "profitability_pct": profitability_pct, } class CustomerOrderItem(models.Model): document = models.ForeignKey(CustomerOrder, on_delete=models.CASCADE, related_name="items", verbose_name="Заказ") product = models.ForeignKey(Product, on_delete=models.PROTECT, verbose_name="Товар") price = models.DecimalField("Цена", max_digits=18, decimal_places=2, default=Decimal("0")) currency = models.ForeignKey(Currency, on_delete=models.PROTECT, verbose_name="Валюта", null=True, blank=True) quantity = models.DecimalField("Количество", max_digits=18, decimal_places=4, default=Decimal("1")) amount = models.DecimalField("Стоимость", max_digits=18, decimal_places=2, default=Decimal("0"), editable=False) class Meta: verbose_name = "Строка заказа клиента" verbose_name_plural = "Строки заказа клиента" def save(self, *args, **kwargs): self.amount = self.price * self.quantity super().save(*args, **kwargs) class SupplierOrder(models.Model): date = models.DateField("Дата") number = models.CharField("Номер", max_length=50) organization = models.ForeignKey(Organization, on_delete=models.PROTECT, verbose_name="Организация") supplier = models.ForeignKey(Supplier, on_delete=models.PROTECT, verbose_name="Поставщик") customer_order = models.ForeignKey(CustomerOrder, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="Заказ клиента", related_name="supplier_orders") currency = models.ForeignKey(Currency, on_delete=models.PROTECT, verbose_name="Валюта") rate = models.DecimalField("Курс валюты", max_digits=18, decimal_places=6, default=Decimal("1")) total_in_currency = models.DecimalField("Стоимость в валюте", max_digits=18, decimal_places=2, default=Decimal("0"), editable=False) total_amount = models.DecimalField("Стоимость заказа", max_digits=18, decimal_places=2, default=Decimal("0"), editable=False) author = models.ForeignKey(Employee, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="Автор", related_name="supplier_orders") class Meta: verbose_name = "Заказ поставщику" verbose_name_plural = "Заказы поставщику" def __str__(self): return f"{self.number} от {self.date}" def recalc_totals(self): self.total_in_currency = sum((i.price * i.quantity for i in self.items.all()), Decimal("0")) self.total_amount = self.total_in_currency * self.rate class SupplierOrderItem(models.Model): document = models.ForeignKey(SupplierOrder, on_delete=models.CASCADE, related_name="items", verbose_name="Заказ поставщику") product = models.ForeignKey(Product, on_delete=models.PROTECT, verbose_name="Товар") price = models.DecimalField("Цена", max_digits=18, decimal_places=2, default=Decimal("0")) currency = models.ForeignKey(Currency, on_delete=models.PROTECT, verbose_name="Валюта", null=True, blank=True) quantity = models.DecimalField("Количество", max_digits=18, decimal_places=4, default=Decimal("1")) amount = models.DecimalField("Стоимость", max_digits=18, decimal_places=2, default=Decimal("0"), editable=False) class Meta: verbose_name = "Строка заказа поставщику" verbose_name_plural = "Строки заказа поставщику" def save(self, *args, **kwargs): self.amount = self.price * self.quantity super().save(*args, **kwargs) class CashInflow(models.Model): date = models.DateField("Дата") number = models.CharField("Номер", max_length=50) recipient = models.ForeignKey(CashAccount, on_delete=models.PROTECT, verbose_name="Получатель", related_name="inflows") amount = models.DecimalField("Сумма", max_digits=18, decimal_places=2, default=Decimal("0")) customer_order = models.ForeignKey(CustomerOrder, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="Заказ клиента", related_name="cash_inflows") comment = models.CharField("Комментарий", max_length=500, blank=True) author = models.ForeignKey(Employee, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="Автор", related_name="cash_inflows") class Meta: verbose_name = "Поступление денежных средств" verbose_name_plural = "Поступления денежных средств" def __str__(self): return f"{self.number} от {self.date}" class CashTransfer(models.Model): date = models.DateField("Дата") number = models.CharField("Номер", max_length=50) sender = models.ForeignKey(CashAccount, on_delete=models.PROTECT, verbose_name="Отправитель", related_name="transfers_sent") recipient = models.ForeignKey(CashAccount, on_delete=models.PROTECT, verbose_name="Получатель", related_name="transfers_received") amount = models.DecimalField("Сумма", max_digits=18, decimal_places=2, default=Decimal("0")) comment = models.CharField("Комментарий", max_length=500, blank=True) author = models.ForeignKey(Employee, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="Автор", related_name="cash_transfers") class Meta: verbose_name = "Перемещение денежных средств" verbose_name_plural = "Перемещения денежных средств" def __str__(self): return f"{self.number} от {self.date}" class CashExpense(models.Model): date = models.DateField("Дата") number = models.CharField("Номер", max_length=50) sender = models.ForeignKey(CashAccount, on_delete=models.PROTECT, verbose_name="Отправитель", related_name="expenses") amount = models.DecimalField("Сумма", max_digits=18, decimal_places=2, default=Decimal("0")) supplier_order = models.ForeignKey(SupplierOrder, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="Заказ поставщику", related_name="cash_expenses") customer_order = models.ForeignKey(CustomerOrder, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="Заказ клиента", related_name="cash_expenses") comment = models.CharField("Комментарий", max_length=500, blank=True) author = models.ForeignKey(Employee, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="Автор", related_name="cash_expenses") class Meta: verbose_name = "Расход денежных средств" verbose_name_plural = "Расходы денежных средств" def __str__(self): return f"{self.number} от {self.date}"