| 
					
				 | 
			
			
				@@ -1,5 +1,5 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from wsgiref import headers 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-from rest_framework.views import APIView 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+from rest_framework.viewsets import ViewSet 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from rest_framework import viewsets 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from utils.page import MyPageNumberPagination 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from django.db.models import Prefetch  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -886,6 +886,13 @@ class ContainerWCSViewSet(viewsets.ModelViewSet): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 return Response({'code': '500', 'message': '出库状态更新失败', 'data': None}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                 status=status.HTTP_500_INTERNAL_SERVER_ERROR) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             OutboundService.process_next_task() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if task and task.tasktype == 'check' and task.status == 300: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            success = self.handle_outbound_completion(container_obj, task) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if not success: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return Response({'code': '500', 'message': '出库状态更新失败', 'data': None}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                status=status.HTTP_500_INTERNAL_SERVER_ERROR) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            OutboundService.process_next_task() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				          
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         return Response({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             'code': '200', 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1084,32 +1091,35 @@ class ContainerWCSViewSet(viewsets.ModelViewSet): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         try: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             allocator = LocationAllocation() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             location_task = task.current_location 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            location_row = location_task.split('-')[1] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            location_col = location_task.split('-')[2] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            location_layer = location_task.split('-')[3] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            location= LocationModel.objects.filter(row=location_row, col=location_col, layer=location_layer).first() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            location_code = location.location_code 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-   
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if location_task == '103' or location_task == '203': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return True 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            else: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                location_row = location_task.split('-')[1] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                location_col = location_task.split('-')[2] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                location_layer = location_task.split('-')[3] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                location= LocationModel.objects.filter(row=location_row, col=location_col, layer=location_layer).first() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                location_code = location.location_code 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            # 事务确保原子性 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            with transaction.atomic(): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                # 解除库位与托盘的关联 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if not allocator.release_location(location_code): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    raise Exception("解除库位关联失败") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                # 事务确保原子性 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                with transaction.atomic(): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    # 解除库位与托盘的关联 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if not allocator.release_location(location_code): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        raise Exception("解除库位关联失败") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                # 更新库位状态为可用 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if not allocator.update_location_status(location_code, 'available'): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    raise Exception("库位状态更新失败") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    # 更新库位状态为可用 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if not allocator.update_location_status(location_code, 'available'): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        raise Exception("库位状态更新失败") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                # 更新库位组的统计信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                self.handle_group_location_status(location_code, location.location_group) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    # 更新库位组的统计信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    self.handle_group_location_status(location_code, location.location_group) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                # 更新托盘状态为已出库(假设状态3表示已出库) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                container_obj.status = 3 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                container_obj.save() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    # 更新托盘状态为已出库(假设状态3表示已出库) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    container_obj.status = 3 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    container_obj.save() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            return True 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return True 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         except Exception as e: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             logger.error(f"出库完成处理失败: {str(e)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return False 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1680,6 +1690,50 @@ class OutboundService: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 container_obj.save() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             ContainerWCSModel.objects.bulk_create(tasks) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             logger.info(f"已创建 {len(tasks)} 个初始任务") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @staticmethod 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def create_initial_check_tasks(container_list,batch_id): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        """生成初始任务队列""" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        with transaction.atomic(): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            current_WCS = ContainerWCSModel.objects.filter(tasktype='check',batch_id = batch_id,is_delete=False,working=1).first() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if current_WCS: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                logger.error(f"当前{batch_id}已有检查任务") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return False 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            tasks = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            start_sequence = ContainerWCSModel.objects.filter(tasktype='check').count() + 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            tasknumber = ContainerWCSModel.objects.filter().count()  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            tasknumber_index = 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            for index, container in enumerate(container_list, start=start_sequence): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                container_obj = ContainerListModel.objects.filter(id =container['container_number']).first() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if container_obj.current_location != container_obj.target_location: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    logger.error(f"托盘 {container_obj.container_code} 未到达目的地,不生成任务") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    return False 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                batch_obj = BoundBatchModel.objects.filter(id =batch_id).first() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                month = int(timezone.now().strftime("%Y%m")) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                task = ContainerWCSModel( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    taskid=OutboundService.generate_task_id(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    batch = batch_obj, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    batch_out = None, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    bound_list = None, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    sequence=index, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    order_number = container['c_number'], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    priority=100, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    tasknumber = month*100000+tasknumber_index+tasknumber, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    container=container_obj.container_code, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    current_location=container_obj.current_location, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    target_location="103", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    tasktype="check", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    month=int(timezone.now().strftime("%Y%m")), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    message="等待出库", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    status=100, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                tasknumber_index += 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                tasks.append(task) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                container_obj = ContainerListModel.objects.filter(container_code=task.container).first() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                container_obj.target_location = task.target_location 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                container_obj.save() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            ContainerWCSModel.objects.bulk_create(tasks) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.info(f"已创建 {len(tasks)} 个初始任务") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     @staticmethod 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     def insert_new_tasks(new_tasks): 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1775,7 +1829,7 @@ class OutboundService: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 # 出库任务下发 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-class OutTaskViewSet(APIView): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+class OutTaskViewSet(ViewSet): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     """ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     # fun:get_out_task:下发出库任务 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1799,9 +1853,9 @@ class OutTaskViewSet(APIView): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 if current_WCS.working == 1: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     OutboundService.process_current_task(current_WCS.taskid) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    return Response({"code": "200", "msg": f"下发任务{ current_WCS.taskid }到WCS成功"}, status=200) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    return Response({"code": 200, "msg": f"下发任务{ current_WCS.taskid }到WCS成功"}, status=200) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 else : 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    return Response({"code": "200", "msg": f"当前任务{current_WCS.taskid}正在处理中"}, status=200) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    return Response({"code": 200, "msg": f"当前任务{current_WCS.taskid}正在处理中"}, status=200) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1812,7 +1866,7 @@ class OutTaskViewSet(APIView): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             ).select_related('batch_number') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				              
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             if not out_batches.exists(): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                return Response({"code": "404", "msg": "未找到相关出库批次"}, status=404) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return Response({"code": 404, "msg": "未找到相关出库批次"}, status=404) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             # 构建批次需求字典 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             batch_demand = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             for ob in out_batches: 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1846,14 +1900,43 @@ class OutTaskViewSet(APIView): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             # 3. 立即发送第一个任务 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             OutboundService.process_next_task() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				              
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            return Response({"code": "200", "msg": "Success"}, status=200) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return Response({"code": 200, "msg": "下发任务成功"}, status=200) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         except Exception as e: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             logger.error(f"任务生成失败: {str(e)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            return Response({"code": "200", "msg": str(e)}, status=200) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return Response({"code": 200, "msg": str(e)}, status=200) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    # 获取出库需求 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def post_check(self, request): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        try: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            data = self.request.data 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.info(f"收到 出库抽检 推送数据: {data}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # 从请求中获取 batch_id 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            batch_id = data.get('batch_id') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            container_demand = int(data.get('container_demand')) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if not batch_id or not container_demand: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return Response({"code": "400", "msg": "缺少抽检数目或批次号"}, status=200) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            current_WCS = ContainerWCSModel.objects.filter(batch=batch_id,tasktype='check',is_delete=False,working=1).first() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if current_WCS: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                logger.info(f"当前{batch_id}已有出库抽检任务{current_WCS.taskid}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if current_WCS.working == 1: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    OutboundService.process_current_task(current_WCS.taskid) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    return Response({"code": 200, "msg": f"下发任务{ current_WCS.taskid }到WCS成功"}, status=200) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                else : 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    return Response({"code": 200, "msg": f"当前任务{current_WCS.taskid}正在处理中"}, status=200) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # 获取批次号 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            generate_result = self.generate_location_by_check(batch_id,container_demand) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if generate_result['code'] != '200': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return Response(generate_result, status=200) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # 创建并处理出库任务 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            container_list = generate_result['data'] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # 3. 立即发送第一个任务 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            OutboundService.create_initial_check_tasks(container_list,batch_id) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            OutboundService.process_next_task() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return Response({"code": 200, "msg": "下发任务成功"}, status=200) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        except Exception as e: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.error(f"任务生成失败: {str(e)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return Response({"code": 200, "msg": str(e)}, status=200) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     def get_batch_count_by_boundlist(self,bound_list_id): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         try: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             bound_list_obj_all = OutBoundDetailModel.objects.filter(bound_list=bound_list_id).all() 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1946,7 +2029,75 @@ class OutTaskViewSet(APIView): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             .order_by('container_id', '-id') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-         
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def generate_location_by_check(self,batch_id,container_demand): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ''' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        根据抽检托盘数目,把相应的库位给到出库任务 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ''' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        try: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return_data = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # 获取已去重的托盘列表 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            container_qs = self.get_container_allocation(batch_id) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # 构建托盘信息字典(自动去重) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            container_map = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            for cd in container_qs: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if cd.container_id in container_map: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    continue 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                # 获取有效库位信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                active_location = next( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    (link.location for link in cd.container.active_location  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        if link.is_active), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        None 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                container_map[cd.container_id] = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    'detail': cd, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    'container': cd.container, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    'location': active_location 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                # 转换为排序列表 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            container_list = list(container_map.values()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            sorted_containers = sorted( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                container_list, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                key=lambda x: ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    self._get_goods_class_priority(x['detail'].goods_class), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    -(x['location'].c_number if x['location'] else 0), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    # -(x['location'].layer if x['location'] else 0), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    # x['location'].row if x['location'] else 0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    # x['location'].col if x['location'] else 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            for item in sorted_containers: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if container_demand <= 0: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                   break 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                # 获取可分配数量 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                # 记录分配信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                allocate_container = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    "container_number": item['container'].id, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    "batch_id": batch_id, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    "location_code": item['location'].location_code if item['location'] else 'N/A', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    "allocate_qty": 0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    "c_number": item['location'].c_number if item['location'] else 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return_data.append(allocate_container)   
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                container_demand -= 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # 降重 return_data,以container_number为key 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return_data = list({v['container_number']: v for v in return_data}.values()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # 排序 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return_data = sorted(return_data, key=lambda x: -x['c_number']) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return {"code": "200", "msg": "Success", "data": return_data} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        except Exception as e: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.error(f"出库任务生成失败: {str(e)}", exc_info=True) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return {"code": "500", "msg": str(e)} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     def generate_location_by_demand(self, batch_demand, bound_list_id): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         try: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return_data = [] 
			 |