|
@@ -1,6 +1,8 @@
|
|
from django.db import models
|
|
from django.db import models
|
|
from bound.models import BoundBatchModel,BoundDetailModel,OutBatchModel,BoundListModel,BoundListModel
|
|
from bound.models import BoundBatchModel,BoundDetailModel,OutBatchModel,BoundListModel,BoundListModel
|
|
-
|
|
|
|
|
|
+from django.utils import timezone
|
|
|
|
+from django.db.models.signals import pre_save, post_save
|
|
|
|
+from django.dispatch import receiver
|
|
|
|
|
|
# Create your models here.
|
|
# Create your models here.
|
|
# 主表:托盘数据
|
|
# 主表:托盘数据
|
|
@@ -27,7 +29,6 @@ class ContainerListModel(models.Model):
|
|
verbose_name_plural = "ContainerList"
|
|
verbose_name_plural = "ContainerList"
|
|
ordering = ['-container_code']
|
|
ordering = ['-container_code']
|
|
|
|
|
|
-# 明细表:托盘详细数据记录当前组盘的 批次 数量 使用托盘码和状态来获取、托盘上的物料信息,
|
|
|
|
class ContainerDetailModel(models.Model):
|
|
class ContainerDetailModel(models.Model):
|
|
BATCH_STATUS=(
|
|
BATCH_STATUS=(
|
|
(0, '空盘'),
|
|
(0, '空盘'),
|
|
@@ -40,6 +41,7 @@ class ContainerDetailModel(models.Model):
|
|
(2, '空盘'),
|
|
(2, '空盘'),
|
|
(3, '散盘'),
|
|
(3, '散盘'),
|
|
)
|
|
)
|
|
|
|
+
|
|
month = models.IntegerField(verbose_name='月份')
|
|
month = models.IntegerField(verbose_name='月份')
|
|
container = models.ForeignKey(ContainerListModel, on_delete=models.CASCADE, related_name='details')
|
|
container = models.ForeignKey(ContainerListModel, on_delete=models.CASCADE, related_name='details')
|
|
batch = models.ForeignKey(BoundBatchModel, on_delete=models.CASCADE, verbose_name='批次',blank=True, null=True)
|
|
batch = models.ForeignKey(BoundBatchModel, on_delete=models.CASCADE, verbose_name='批次',blank=True, null=True)
|
|
@@ -60,9 +62,15 @@ class ContainerDetailModel(models.Model):
|
|
verbose_name = 'ContainerDetail'
|
|
verbose_name = 'ContainerDetail'
|
|
verbose_name_plural = "ContainerDetail"
|
|
verbose_name_plural = "ContainerDetail"
|
|
ordering = ['-id']
|
|
ordering = ['-id']
|
|
|
|
+ indexes = [
|
|
|
|
+ models.Index(fields=['container']),
|
|
|
|
+ models.Index(fields=['batch']),
|
|
|
|
+ models.Index(fields=['goods_code']),
|
|
|
|
+ models.Index(fields=['status']),
|
|
|
|
+ ]
|
|
|
|
|
|
def __str__(self):
|
|
def __str__(self):
|
|
- return f"{self.container_code} - {self.batch.bound_number} - {self.goods_code} - {self.goods_desc} - {self.goods_qty}"
|
|
|
|
|
|
+ return f"{self.container.container_code} - {self.batch.bound_number if self.batch else 'N/A'} - {self.goods_code}"
|
|
|
|
|
|
def save(self, *args, **kwargs):
|
|
def save(self, *args, **kwargs):
|
|
"""
|
|
"""
|
|
@@ -70,31 +78,176 @@ class ContainerDetailModel(models.Model):
|
|
goods_in_qty(组盘数目)
|
|
goods_in_qty(组盘数目)
|
|
,goods_in_location_qty(在库数目)
|
|
,goods_in_location_qty(在库数目)
|
|
,goods_out_qty(出库数目)
|
|
,goods_out_qty(出库数目)
|
|
-
|
|
|
|
"""
|
|
"""
|
|
|
|
+ # 在保存前调用信号处理器
|
|
|
|
+ if self.pk:
|
|
|
|
+ # 获取状态变化前的状态
|
|
|
|
+ original = ContainerDetailModel.objects.get(pk=self.pk)
|
|
|
|
+ original_status = original.status
|
|
|
|
+
|
|
|
|
+ super().save(*args, **kwargs)
|
|
|
|
+
|
|
|
|
+ # 更新批次数据
|
|
if self.batch:
|
|
if self.batch:
|
|
-
|
|
|
|
- super().save(*args, **kwargs)
|
|
|
|
-
|
|
|
|
- if self.goods_qty - self.goods_out_qty <= 0:
|
|
|
|
- self.status = 3
|
|
|
|
|
|
+ # 避免循环更新 - 仅在数量相关字段变更时才更新
|
|
|
|
+ if 'update_fields' not in kwargs or any(field in kwargs['update_fields'] for field in ['goods_qty', 'goods_out_qty']):
|
|
|
|
+ self.update_batch_stats()
|
|
|
|
+
|
|
|
|
+ # # 根据出库数量更新状态
|
|
|
|
+ # if self.goods_out_qty > self.goods_qty:
|
|
|
|
+ # # 出库数量不能大于总数量
|
|
|
|
+ # self.goods_out_qty = self.goods_qty
|
|
|
|
+ # self.save(update_fields=['goods_out_qty'])
|
|
|
|
+
|
|
|
|
+ # 根据当前数量状态更新状态
|
|
|
|
+ if self.goods_out_qty >= self.goods_qty:
|
|
|
|
+ self.status = 3 # 已出库
|
|
super().save(*args, **kwargs)
|
|
super().save(*args, **kwargs)
|
|
|
|
+
|
|
elif self.goods_qty - self.goods_out_qty > 0 and self.goods_out_qty > 0:
|
|
elif self.goods_qty - self.goods_out_qty > 0 and self.goods_out_qty > 0:
|
|
- self.status = 2
|
|
|
|
|
|
+ self.status = 2 # 在库
|
|
super().save(*args, **kwargs)
|
|
super().save(*args, **kwargs)
|
|
|
|
+
|
|
|
|
+
|
|
if self.status == 3 and self.goods_qty - self.goods_out_qty > 0 :
|
|
if self.status == 3 and self.goods_qty - self.goods_out_qty > 0 :
|
|
- self.status = 2
|
|
|
|
|
|
+ self.status = 2 # 在库
|
|
super().save(*args, **kwargs)
|
|
super().save(*args, **kwargs)
|
|
|
|
+
|
|
|
|
+ def update_batch_stats(self):
|
|
|
|
+ """更新批次的统计数据"""
|
|
|
|
+ if not self.batch:
|
|
|
|
+ return
|
|
|
|
+
|
|
|
|
+ # 聚合托盘明细数据
|
|
|
|
+ stats = ContainerDetailModel.objects.filter(
|
|
|
|
+ batch=self.batch,
|
|
|
|
+ is_delete=False
|
|
|
|
+ ).aggregate(
|
|
|
|
+ total_qty=models.Sum('goods_qty'),
|
|
|
|
+ total_out_qty=models.Sum('goods_out_qty')
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+ # 更新批次数据
|
|
|
|
+ self.batch.goods_in_qty = stats['total_qty'] or 0
|
|
|
|
+ self.batch.goods_in_location_qty = (stats['total_qty'] or 0) - (stats['total_out_qty'] or 0)
|
|
|
|
+ self.batch.goods_out_qty = stats['total_out_qty'] or 0
|
|
|
|
+ self.batch.save()
|
|
|
|
+
|
|
|
|
+
|
|
|
|
|
|
- container_all_qty = ContainerDetailModel.objects.filter(batch=self.batch,is_delete=False).aggregate(total_qty=models.Sum('goods_qty'))['total_qty']
|
|
|
|
- container_all_out_qty = ContainerDetailModel.objects.filter(batch=self.batch,is_delete=False).aggregate(total_out_qty=models.Sum('goods_out_qty'))['total_out_qty']
|
|
|
|
- self.batch.goods_in_qty = container_all_qty
|
|
|
|
- self.batch.goods_in_location_qty = container_all_qty - container_all_out_qty
|
|
|
|
- self.batch.goods_out_qty = container_all_out_qty
|
|
|
|
- self.batch.save()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+
|
|
|
|
+class ContainerDetailLogModel(models.Model):
|
|
|
|
+ """托盘明细变更日志模型"""
|
|
|
|
+ LOG_TYPES = (
|
|
|
|
+ ('create', '创建'),
|
|
|
|
+ ('update', '更新'),
|
|
|
|
+ ('delete', '删除'),
|
|
|
|
+ ('out', '出库'),
|
|
|
|
+ ('status_change', '状态变更'),
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+ # 关联的托盘明细
|
|
|
|
+ container_detail = models.ForeignKey(
|
|
|
|
+ ContainerDetailModel,
|
|
|
|
+ on_delete=models.CASCADE,
|
|
|
|
+ related_name='logs'
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+ # 日志类型
|
|
|
|
+ log_type = models.CharField(
|
|
|
|
+ max_length=20,
|
|
|
|
+ choices=LOG_TYPES,
|
|
|
|
+ verbose_name='日志类型'
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+ # 原值
|
|
|
|
+ old_goods_qty = models.IntegerField(verbose_name='原数量', null=True, blank=True)
|
|
|
|
+ old_goods_out_qty = models.IntegerField(verbose_name='原出库数量', null=True, blank=True)
|
|
|
|
+ old_status = models.IntegerField(
|
|
|
|
+ choices=ContainerDetailModel.BATCH_STATUS,
|
|
|
|
+ null=True,
|
|
|
|
+ blank=True,
|
|
|
|
+ verbose_name='原状态'
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+ # 新值
|
|
|
|
+ new_goods_qty = models.IntegerField(verbose_name='新数量', null=True, blank=True)
|
|
|
|
+ new_goods_out_qty = models.IntegerField(verbose_name='新出库数量', null=True, blank=True)
|
|
|
|
+ new_status = models.IntegerField(
|
|
|
|
+ choices=ContainerDetailModel.BATCH_STATUS,
|
|
|
|
+ null=True,
|
|
|
|
+ blank=True,
|
|
|
|
+ verbose_name='新状态'
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+ # 元信息
|
|
|
|
+ creater = models.CharField(max_length=50, verbose_name='操作人')
|
|
|
|
+ create_time = models.DateTimeField(auto_now_add=True, verbose_name='操作时间')
|
|
|
|
+
|
|
|
|
+ class Meta:
|
|
|
|
+ db_table = 'container_detail_log'
|
|
|
|
+ verbose_name = '托盘明细变更日志'
|
|
|
|
+ verbose_name_plural = "托盘明细变更日志"
|
|
|
|
+ ordering = ['-create_time']
|
|
|
|
+
|
|
|
|
+ def __str__(self):
|
|
|
|
+ return f"{self.container_detail} - {self.get_log_type_display()} - {self.create_time.strftime('%Y-%m-%d %H:%M:%S')}"
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+@receiver(pre_save, sender=ContainerDetailModel)
|
|
|
|
+def container_detail_pre_save(sender, instance, **kwargs):
|
|
|
|
+ """在托盘明细保存前记录变更"""
|
|
|
|
+ # 检查是否是新建对象
|
|
|
|
+ if instance.pk:
|
|
|
|
+ try:
|
|
|
|
+ # 获取数据库中的当前对象
|
|
|
|
+ old_instance = ContainerDetailModel.objects.get(pk=instance.pk)
|
|
|
|
+ except ContainerDetailModel.DoesNotExist:
|
|
|
|
+ return
|
|
|
|
+
|
|
|
|
+ # 创建日志记录
|
|
|
|
+ log = ContainerDetailLogModel(container_detail=instance, creater=instance.creater)
|
|
|
|
|
|
|
|
+ # 检查数量变化
|
|
|
|
+ if old_instance.goods_qty != instance.goods_qty:
|
|
|
|
+ log.old_goods_qty = old_instance.goods_qty
|
|
|
|
+ log.new_goods_qty = instance.goods_qty
|
|
|
|
+ log.log_type = 'update'
|
|
|
|
+ log.save()
|
|
|
|
+
|
|
|
|
+ # 检查出库数量变化
|
|
|
|
+ if old_instance.goods_out_qty != instance.goods_out_qty:
|
|
|
|
+ log.old_goods_out_qty = old_instance.goods_out_qty
|
|
|
|
+ log.new_goods_out_qty = instance.goods_out_qty
|
|
|
|
+ log.log_type = 'out'
|
|
|
|
+ log.save()
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ # # 检查状态变化
|
|
|
|
+ # if old_instance.status != instance.status:
|
|
|
|
+ # log.old_status = old_instance.status
|
|
|
|
+ # log.new_status = instance.status
|
|
|
|
+ # log.log_type = 'status_change'
|
|
|
|
+
|
|
|
|
+ # # 保存日志记录
|
|
|
|
+ # if hasattr(log, 'log_type'):
|
|
|
|
+ # log.save()
|
|
|
|
+
|
|
|
|
+@receiver(post_save, sender=ContainerDetailModel)
|
|
|
|
+def container_detail_post_save(sender, instance, created, **kwargs):
|
|
|
|
+ """在托盘明细保存后记录创建"""
|
|
|
|
+ if created:
|
|
|
|
+ # 为新建的对象创建日志
|
|
|
|
+ ContainerDetailLogModel.objects.create(
|
|
|
|
+ container_detail=instance,
|
|
|
|
+ log_type='create',
|
|
|
|
+ creater=instance.creater,
|
|
|
|
+ new_goods_qty=instance.goods_qty,
|
|
|
|
+ new_status=instance.status
|
|
|
|
+ )
|
|
|
|
|
|
|
|
|
|
|
|
|