| 
															
																@@ -1,7 +1,7 @@ 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 from django.db import models 
															 | 
															
															 | 
															
																 from django.db import models 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 from erp.models import InboundBill, MaterialDetail, OutboundBill,OutMaterialDetail 
															 | 
															
															 | 
															
																 from erp.models import InboundBill, MaterialDetail, OutboundBill,OutMaterialDetail 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 from django.db.models import Sum 
															 | 
															
															 | 
															
																 from django.db.models import Sum 
															 | 
														
													
												
													
														
															| 
															 | 
															
																-from django.db.models.signals import post_save, post_delete 
															 | 
															
															 | 
															
																 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+from django.db.models.signals import post_save, post_delete, pre_save 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 from django.dispatch import receiver 
															 | 
															
															 | 
															
																 from django.dispatch import receiver 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 from decimal import Decimal 
															 | 
															
															 | 
															
																 from decimal import Decimal 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 class BoundListModel(models.Model): 
															 | 
															
															 | 
															
																 class BoundListModel(models.Model): 
															 | 
														
													
												
											
												
													
														
															 | 
															
																@@ -154,36 +154,74 @@ class MaterialStatistics(models.Model): 
															 | 
														
													
												
													
														
															| 
															 | 
															
																         verbose_name_plural = "物料统计" 
															 | 
															
															 | 
															
																         verbose_name_plural = "物料统计" 
															 | 
														
													
												
													
														
															| 
															 | 
															
																         ordering = ['goods_code'] 
															 | 
															
															 | 
															
																         ordering = ['goods_code'] 
															 | 
														
													
												
													
														
															| 
															 | 
															
																  
															 | 
															
															 | 
															
																  
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+ 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+ 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+ 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+@receiver(pre_save, sender=BoundBatchModel) 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+def store_original_goods_code(sender, instance, **kwargs): 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+    """保存前记录原始物料编码(仅更新时生效)""" 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+    if not instance.pk:  # 新建对象无原始值 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+        return 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+ 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+    try: 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+        original = BoundBatchModel.objects.get(pk=instance.pk) 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+        # 将原始值存储在实例属性中供post_save使用 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+        instance._original_goods_code = original.goods_code   
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+    except BoundBatchModel.DoesNotExist: 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+        pass 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+ 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 @receiver([post_save, post_delete], sender=BoundBatchModel) 
															 | 
															
															 | 
															
																 @receiver([post_save, post_delete], sender=BoundBatchModel) 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 def update_material_statistics(sender, instance, **kwargs): 
															 | 
															
															 | 
															
																 def update_material_statistics(sender, instance, **kwargs): 
															 | 
														
													
												
													
														
															| 
															 | 
															
																-    goods_code = instance.goods_code 
															 | 
															
															 | 
															
																 
															 | 
														
													
												
													
														
															| 
															 | 
															
																-    stats, created = MaterialStatistics.objects.get_or_create( 
															 | 
															
															 | 
															
																 
															 | 
														
													
												
													
														
															| 
															 | 
															
																-        goods_code=goods_code, 
															 | 
															
															 | 
															
																 
															 | 
														
													
												
													
														
															| 
															 | 
															
																-        defaults={ 
															 | 
															
															 | 
															
																 
															 | 
														
													
												
													
														
															| 
															 | 
															
																-            'goods_desc': instance.goods_desc, 
															 | 
															
															 | 
															
																 
															 | 
														
													
												
													
														
															| 
															 | 
															
																-            'goods_std': instance.goods_std or '待填写', 
															 | 
															
															 | 
															
																 
															 | 
														
													
												
													
														
															| 
															 | 
															
																-            'goods_unit': instance.goods_unit or '待填写', 
															 | 
															
															 | 
															
																 
															 | 
														
													
												
													
														
															| 
															 | 
															
																-        } 
															 | 
															
															 | 
															
																 
															 | 
														
													
												
													
														
															| 
															 | 
															
																-    ) 
															 | 
															
															 | 
															
																 
															 | 
														
													
												
													
														
															| 
															 | 
															
																-     
															 | 
															
															 | 
															
																 
															 | 
														
													
												
													
														
															| 
															 | 
															
																-    # 更新物料信息为最新批次的信息(可选) 
															 | 
															
															 | 
															
																 
															 | 
														
													
												
													
														
															| 
															 | 
															
																-    stats.goods_desc = instance.goods_desc 
															 | 
															
															 | 
															
																 
															 | 
														
													
												
													
														
															| 
															 | 
															
																-    if instance.goods_std and instance.goods_std != '待填写': 
															 | 
															
															 | 
															
																 
															 | 
														
													
												
													
														
															| 
															 | 
															
																-        stats.goods_std = instance.goods_std 
															 | 
															
															 | 
															
																 
															 | 
														
													
												
													
														
															| 
															 | 
															
																-    if instance.goods_unit and instance.goods_unit != '待填写': 
															 | 
															
															 | 
															
																 
															 | 
														
													
												
													
														
															| 
															 | 
															
																-        stats.goods_unit = instance.goods_unit 
															 | 
															
															 | 
															
																 
															 | 
														
													
												
													
														
															| 
															 | 
															
																-    stats.save() 
															 | 
															
															 | 
															
																 
															 | 
														
													
												
													
														
															| 
															 | 
															
																- 
															 | 
															
															 | 
															
																 
															 | 
														
													
												
													
														
															| 
															 | 
															
																-    # 计算总数量 
															 | 
															
															 | 
															
																 
															 | 
														
													
												
													
														
															| 
															 | 
															
																-    total = BoundBatchModel.objects.filter(goods_code=goods_code).aggregate( 
															 | 
															
															 | 
															
																 
															 | 
														
													
												
													
														
															| 
															 | 
															
																-        total=Sum('goods_in_location_qty') 
															 | 
															
															 | 
															
																 
															 | 
														
													
												
													
														
															| 
															 | 
															
																-    )['total'] or 0 
															 | 
															
															 | 
															
																 
															 | 
														
													
												
													
														
															| 
															 | 
															
																-    # 更新物料统计的出库数目 
															 | 
															
															 | 
															
																 
															 | 
														
													
												
													
														
															| 
															 | 
															
																-    total_out = BoundBatchModel.objects.filter(goods_code=goods_code).aggregate( 
															 | 
															
															 | 
															
																 
															 | 
														
													
												
													
														
															| 
															 | 
															
																-        total_out=Sum('goods_out_qty') 
															 | 
															
															 | 
															
																 
															 | 
														
													
												
													
														
															| 
															 | 
															
																-    )['total_out'] or 0 
															 | 
															
															 | 
															
																 
															 | 
														
													
												
													
														
															| 
															 | 
															
																-    stats.total_quantity = total 
															 | 
															
															 | 
															
																 
															 | 
														
													
												
													
														
															| 
															 | 
															
																-    stats.save() 
															 | 
															
															 | 
															
																 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+    # 处理删除/创建/更新操作的核心逻辑 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+    def refresh_stats(target_goods_code, force_desc=False): 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+        """刷新指定物料的统计数据""" 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+        stats, created = MaterialStatistics.objects.get_or_create( 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+            goods_code=target_goods_code, 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+            defaults={ 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+                'goods_desc': instance.goods_desc, 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+                'goods_std': instance.goods_std or '待填写', 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+                'goods_unit': instance.goods_unit or '待填写', 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+            } 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+        ) 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+         
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+        # 仅强制更新描述(用于当前物料)或新建时初始化 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+        if force_desc or created: 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+            stats.goods_desc = instance.goods_desc 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+            if instance.goods_std and instance.goods_std != '待填写': 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+                stats.goods_std = instance.goods_std 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+            if instance.goods_unit and instance.goods_unit != '待填写': 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+                stats.goods_unit = instance.goods_unit 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+         
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+        # 重新聚合统计数据(始终执行) 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+        agg = BoundBatchModel.objects.filter(goods_code=target_goods_code).aggregate( 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+            total=Sum('goods_in_location_qty'), 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+            total_out=Sum('goods_out_qty') 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+        ) 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+        stats.total_quantity = agg['total'] or 0 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+        # 如果有出库统计字段需更新,可在此添加 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+        stats.save() 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+ 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+    # 情况1:删除操作直接更新当前物料 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+    if kwargs.get('signal') == post_delete: 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+        refresh_stats(instance.goods_code) 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+        return 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+ 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+    # 情况2:创建操作直接更新新物料 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+    if kwargs.get('created'): 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+        refresh_stats(instance.goods_code, force_desc=True) 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+        return 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+ 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+    # 情况3:更新操作(检测物料编码变更) 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+    original_code = getattr(instance, '_original_goods_code', None) 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+    current_code = instance.goods_code 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+ 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+    # 物料编码未变化时仅更新当前物料 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+    if original_code == current_code: 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+        refresh_stats(current_code, force_desc=True) 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+    # 物料编码变化时更新新旧两个物料 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+    else: 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+        refresh_stats(original_code)      # 更新旧物料(仅刷新数量) 
															 | 
														
													
												
													
														
															| 
															 | 
															
																 
															 | 
															
															 | 
															
																+        refresh_stats(current_code, force_desc=True)  # 更新新物料(全量刷新) 
															 | 
														
													
												
													
														
															| 
															 | 
															
																  
															 | 
															
															 | 
															
																  
															 | 
														
													
												
													
														
															| 
															 | 
															
																  
															 | 
															
															 | 
															
																  
															 | 
														
													
												
													
														
															| 
															 | 
															
																  
															 | 
															
															 | 
															
																  
															 |