1
0
forked from erp-dev/erp

feat: auto complete stock change

This commit is contained in:
2025-11-10 09:01:25 +08:00
parent 37c2e7d723
commit b2078dfa46
82 changed files with 1071 additions and 1336 deletions

View File

@@ -8,6 +8,13 @@ import decimal
# ==================== 枚举类定义 ====================
class StockFreezeStatusEnum(models.IntegerChoices):
"""库存冻结状态类型"""
FROZEN = 1, '冻结中'
CANCELLED = 2, '已取消'
COMPLETED = 3, '已成单'
class StockChangeSourceEnum(models.IntegerChoices):
"""库存变动来源类型"""
@@ -35,6 +42,12 @@ 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='供应商')
order_date = models.DateField(verbose_name='订单日期')
total_amount = models.DecimalField(max_digits=15, decimal_places=2, verbose_name='总金额')
@@ -52,6 +65,12 @@ class StockChangeRecord(ModelBase):
"""库存变动记录模型"""
id = models.BigAutoField(primary_key=True)
merchant = models.ForeignKey(
basic_info_models.Merchant,
on_delete=models.PROTECT,
related_name='stock_change_records',
verbose_name='所属商户'
)
type = models.IntegerField(choices=StockChangeTypeEnum.choices, verbose_name='变动类型')
warehouse = models.ForeignKey(
basic_info_models.WareHouse,
@@ -127,6 +146,12 @@ class StockChangeDetail(ModelBase):
"""库存变动明细模型"""
id = models.BigAutoField(primary_key=True)
merchant = models.ForeignKey(
basic_info_models.Merchant,
on_delete=models.PROTECT,
related_name='stock_change_details',
verbose_name='所属商户'
)
product = models.ForeignKey(
basic_info_models.Product,
on_delete=models.PROTECT,
@@ -161,6 +186,12 @@ class Inventory(ModelBase):
"""库存模型"""
id = models.BigAutoField(primary_key=True)
merchant = models.ForeignKey(
basic_info_models.Merchant,
on_delete=models.PROTECT,
related_name='inventories',
verbose_name='所属商户'
)
product = models.ForeignKey(
basic_info_models.Product,
on_delete=models.PROTECT,
@@ -192,6 +223,12 @@ class StockSnapshot(ModelBase):
"""库存变动快照模型"""
id = models.BigAutoField(primary_key=True)
merchant = models.ForeignKey(
basic_info_models.Merchant,
on_delete=models.PROTECT,
related_name='stock_snapshots',
verbose_name='所属商户'
)
product = models.ForeignKey(
basic_info_models.Product,
on_delete=models.PROTECT,
@@ -252,3 +289,76 @@ class StockSnapshot(ModelBase):
class Meta:
verbose_name = '库存快照'
verbose_name_plural = '库存快照'
class StockFreeze(ModelBase):
"""库存冻结模型"""
id = models.BigAutoField(primary_key=True)
merchant = models.ForeignKey(
basic_info_models.Merchant,
on_delete=models.PROTECT,
related_name='stock_freezes',
verbose_name='所属商户'
)
product = models.ForeignKey(
basic_info_models.Product,
on_delete=models.PROTECT,
related_name='stock_freezes',
verbose_name='产品',
)
warehouse = models.ForeignKey(
basic_info_models.WareHouse,
on_delete=models.PROTECT,
related_name='stock_freezes',
verbose_name='仓库',
)
stock_detail = models.ForeignKey(
StockChangeDetail,
on_delete=models.PROTECT,
related_name='stock_freezes',
verbose_name='关联的库存变动明细',
)
quantity = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='冻结数量')
unit = models.IntegerField(
verbose_name='单位',
choices=basic_info_models.ProductUnitEnum.choices,
)
status = models.IntegerField(
choices=StockFreezeStatusEnum.choices,
default=StockFreezeStatusEnum.FROZEN,
verbose_name='冻结状态',
)
frozen_by = models.ForeignKey(
'auth.User',
on_delete=models.PROTECT,
verbose_name='冻结操作人',
)
frozen_with = models.BigIntegerField(null=True, blank=True, verbose_name='冻结关联ID')
cancelled_by = models.ForeignKey(
'auth.User',
on_delete=models.PROTECT,
null=True,
blank=True,
related_name='cancelled_stock_freezes',
verbose_name='取消操作人',
)
completed_by = models.ForeignKey(
'auth.User',
on_delete=models.PROTECT,
null=True,
blank=True,
related_name='completed_stock_freezes',
verbose_name='成单操作人',
)
completed_at = models.DateTimeField(null=True, blank=True, verbose_name='成单时间')
completed_with = models.BigIntegerField(null=True, blank=True, verbose_name='成单关联ID')
cancelled_at = models.DateTimeField(null=True, blank=True, verbose_name='取消时间')
reason = models.TextField(blank=True, null=True, verbose_name='冻结原因')
def __str__(self):
return f'库存冻结 {self.id} - 产品: {self.product.name}'
class Meta:
verbose_name = '库存冻结'
verbose_name_plural = '库存冻结'