forked from erp-dev/erp
127 lines
4.2 KiB
Python
127 lines
4.2 KiB
Python
from decimal import Decimal
|
|
from django.db import models
|
|
from flower.common import ModelBase
|
|
from basic_info import models as basic_info_models
|
|
|
|
|
|
class PurchaseOrderKindEnum(models.IntegerChoices):
|
|
"""采购单类型"""
|
|
WHOLESALE = 1, '大货'
|
|
SAMPLE = 2, '样板'
|
|
|
|
|
|
class PurchaseOrderStatusEnum(models.IntegerChoices):
|
|
"""采购单状态"""
|
|
PENDING = 1, '审批中'
|
|
APPROVED = 2, '审批通过'
|
|
CANCELLED = 3, '作废'
|
|
|
|
|
|
class PurchaseOrder(ModelBase):
|
|
"""采购单模型(业务模块)"""
|
|
|
|
id = models.BigAutoField(primary_key=True)
|
|
merchant = models.ForeignKey(
|
|
basic_info_models.Merchant,
|
|
on_delete=models.PROTECT,
|
|
related_name='purchase_orders',
|
|
verbose_name='所属商户',
|
|
)
|
|
supplier = models.ForeignKey(
|
|
basic_info_models.Supplier,
|
|
on_delete=models.PROTECT,
|
|
related_name='purchase_orders',
|
|
verbose_name='供应商',
|
|
)
|
|
purchase_date = models.DateField(verbose_name='采购日期')
|
|
kind = models.IntegerField(
|
|
choices=PurchaseOrderKindEnum.choices,
|
|
default=PurchaseOrderKindEnum.WHOLESALE,
|
|
verbose_name='采购单类型',
|
|
)
|
|
operator = models.ForeignKey(
|
|
basic_info_models.Employee,
|
|
on_delete=models.PROTECT,
|
|
related_name='purchase_orders',
|
|
verbose_name='经办人',
|
|
)
|
|
warehouse = models.ForeignKey(
|
|
basic_info_models.WareHouse,
|
|
on_delete=models.PROTECT,
|
|
related_name='purchase_orders',
|
|
verbose_name='仓库',
|
|
)
|
|
status = models.IntegerField(
|
|
choices=PurchaseOrderStatusEnum.choices,
|
|
default=PurchaseOrderStatusEnum.PENDING,
|
|
verbose_name='状态',
|
|
)
|
|
remarks = models.TextField(blank=True, null=True, verbose_name='备注')
|
|
|
|
def __str__(self):
|
|
return f'采购订单 {self.id} - {self.supplier.name}'
|
|
|
|
class Meta:
|
|
verbose_name = '采购单'
|
|
verbose_name_plural = '采购单'
|
|
|
|
def get_total_amount(self) -> Decimal:
|
|
return sum(item.total_amount() for item in self.items.all())
|
|
|
|
def get_total_quantity(self) -> Decimal:
|
|
return sum(item.quantity for item in self.items.all())
|
|
|
|
def get_total_diff_quantity(self) -> Decimal:
|
|
return sum(item.diff_quantity() for item in self.items.all())
|
|
|
|
|
|
class PurchaseOrderItem(ModelBase):
|
|
"""采购单明细模型"""
|
|
|
|
id = models.BigAutoField(primary_key=True)
|
|
purchase_order = models.ForeignKey(
|
|
PurchaseOrder,
|
|
on_delete=models.CASCADE,
|
|
related_name='items',
|
|
verbose_name='采购单',
|
|
)
|
|
product = models.ForeignKey(
|
|
basic_info_models.Product,
|
|
on_delete=models.PROTECT,
|
|
related_name='purchase_order_items',
|
|
verbose_name='产品',
|
|
)
|
|
price = models.DecimalField(max_digits=15, decimal_places=2, verbose_name='单价')
|
|
color = models.CharField(max_length=50, null=True, blank=True, verbose_name='颜色')
|
|
quantity = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='数量')
|
|
unit = models.CharField(max_length=50, verbose_name='单位')
|
|
spec = models.CharField(max_length=100, null=True, blank=True, verbose_name='规格')
|
|
empty_diff_percent = models.DecimalField(
|
|
max_digits=15,
|
|
decimal_places=2,
|
|
verbose_name='空差百分比',
|
|
)
|
|
# if purchase_order.warehouse.mode != WarehouseModeEnum.UNRESTRICTED, then quantity_of_rolls is required
|
|
quantity_of_rolls = models.CharField(
|
|
max_length=255,
|
|
null=True,
|
|
blank=True,
|
|
verbose_name='各条数数量',
|
|
)
|
|
num_of_rolls = models.PositiveIntegerField(default=1, verbose_name='条数')
|
|
batch_number = models.CharField(null=True, blank=True, max_length=100, verbose_name='批次号')
|
|
remarks = models.TextField(blank=True, null=True, verbose_name='备注')
|
|
|
|
class Meta:
|
|
verbose_name = '采购单明细'
|
|
verbose_name_plural = '采购单明细'
|
|
|
|
def real_quantity(self):
|
|
return round(self.quantity * (1 - self.empty_diff_percent / 100), 2)
|
|
|
|
def diff_quantity(self):
|
|
return round(self.quantity * (self.empty_diff_percent / 100), 2)
|
|
|
|
def total_amount(self):
|
|
return round(self.price * self.real_quantity(), 2)
|