|  | @@ -16,7 +16,7 @@ import logging
 | 
	
		
			
				|  |  |  from rest_framework import status
 | 
	
		
			
				|  |  |  from .models import ContainerListModel,ContainerDetailModel,ContainerOperationModel,ContainerWCSModel,TaskModel
 | 
	
		
			
				|  |  |  from bound.models import BoundBatchModel,BoundDetailModel,BoundListModel,OutBoundDetailModel
 | 
	
		
			
				|  |  | -from bin.views import LocationAllocation
 | 
	
		
			
				|  |  | +from bin.views import LocationAllocation,base_location
 | 
	
		
			
				|  |  |  from bin.models import LocationModel,LocationContainerLink
 | 
	
		
			
				|  |  |  # from .files import FileListRenderCN, FileDetailRenderCN
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -159,6 +159,88 @@ class TaskViewSet(viewsets.ModelViewSet):
 | 
	
		
			
				|  |  |          headers = self.get_success_headers(serializer.data)
 | 
	
		
			
				|  |  |          return Response(serializer.data, status=200, headers=headers)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +class TaskRollbackMixin:
 | 
	
		
			
				|  |  | +    @transaction.atomic
 | 
	
		
			
				|  |  | +    def rollback_task(self, request, task_id, *args, **kwargs):
 | 
	
		
			
				|  |  | +        """
 | 
	
		
			
				|  |  | +        撤销入库任务并回滚相关状态
 | 
	
		
			
				|  |  | +        """
 | 
	
		
			
				|  |  | +        try:
 | 
	
		
			
				|  |  | +            # 获取任务实例并锁定数据库记录
 | 
	
		
			
				|  |  | +            task = ContainerWCSModel.objects.select_for_update().get(taskid=task_id)
 | 
	
		
			
				|  |  | +            container_code = task.container
 | 
	
		
			
				|  |  | +            target_location = task.target_location
 | 
	
		
			
				|  |  | +            batch = task.batch
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            # 初始化库位分配器
 | 
	
		
			
				|  |  | +            allocator = LocationAllocation()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            # ==================== 库位状态回滚 ====================
 | 
	
		
			
				|  |  | +            # 解析目标库位信息(格式:仓库代码-行-列-层)
 | 
	
		
			
				|  |  | +            try:
 | 
	
		
			
				|  |  | +                warehouse_code, row, col, layer = target_location.split('-')
 | 
	
		
			
				|  |  | +                location = LocationModel.objects.get(
 | 
	
		
			
				|  |  | +                    warehouse_code=warehouse_code,
 | 
	
		
			
				|  |  | +                    row=int(row),
 | 
	
		
			
				|  |  | +                    col=int(col),
 | 
	
		
			
				|  |  | +                    layer=int(layer)
 | 
	
		
			
				|  |  | +                )
 | 
	
		
			
				|  |  | +                
 | 
	
		
			
				|  |  | +                # 回滚库位状态到可用状态
 | 
	
		
			
				|  |  | +                allocator.update_location_status(location.location_code, 'available')
 | 
	
		
			
				|  |  | +                
 | 
	
		
			
				|  |  | +                # 更新库位组状态(需要根据实际逻辑实现)
 | 
	
		
			
				|  |  | +                allocator.update_location_group_status(location.location_code)
 | 
	
		
			
				|  |  | +                
 | 
	
		
			
				|  |  | +                # 解除库位与托盘的关联
 | 
	
		
			
				|  |  | +                allocator.update_location_container_link(location.location_code, None)
 | 
	
		
			
				|  |  | +                
 | 
	
		
			
				|  |  | +                # 清除库位组的批次关联
 | 
	
		
			
				|  |  | +                allocator.update_location_group_batch(location, None)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            except (ValueError, LocationModel.DoesNotExist) as e:
 | 
	
		
			
				|  |  | +                logger.error(f"库位解析失败: {str(e)}")
 | 
	
		
			
				|  |  | +                raise Exception("关联库位信息无效")
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            # ==================== 批次状态回滚 ====================
 | 
	
		
			
				|  |  | +            if batch:
 | 
	
		
			
				|  |  | +                # 将批次状态恢复为未处理状态(假设原状态为1)
 | 
	
		
			
				|  |  | +                allocator.update_batch_status(batch.bound_number, '1')
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            # ==================== 容器状态回滚 ====================
 | 
	
		
			
				|  |  | +            container_obj = ContainerListModel.objects.get(container_code=container_code)
 | 
	
		
			
				|  |  | +            
 | 
	
		
			
				|  |  | +            # 恢复容器详细状态为初始状态(假设原状态为1)
 | 
	
		
			
				|  |  | +            allocator.update_container_detail_status(container_code, 1)
 | 
	
		
			
				|  |  | +            
 | 
	
		
			
				|  |  | +            # 恢复容器的目标位置为当前所在位置
 | 
	
		
			
				|  |  | +            container_obj.target_location = task.current_location
 | 
	
		
			
				|  |  | +            container_obj.save()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            # ==================== 删除任务记录 ====================
 | 
	
		
			
				|  |  | +            task.delete()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            # ==================== 其他关联清理 ====================
 | 
	
		
			
				|  |  | +            # 如果有其他关联数据(如inport_update_task的操作),在此处添加清理逻辑
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            return Response(
 | 
	
		
			
				|  |  | +                {'code': '200', 'message': '任务回滚成功', 'data': None},
 | 
	
		
			
				|  |  | +                status=status.HTTP_200_OK
 | 
	
		
			
				|  |  | +            )
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        except ContainerWCSModel.DoesNotExist:
 | 
	
		
			
				|  |  | +            logger.warning(f"任务不存在: {task_id}")
 | 
	
		
			
				|  |  | +            return Response(
 | 
	
		
			
				|  |  | +                {'code': '404', 'message': '任务不存在', 'data': None},
 | 
	
		
			
				|  |  | +                status=status.HTTP_404_NOT_FOUND
 | 
	
		
			
				|  |  | +            )
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        except Exception as e:
 | 
	
		
			
				|  |  | +            logger.error(f"任务回滚失败: {str(e)}", exc_info=True)
 | 
	
		
			
				|  |  | +            return Response(
 | 
	
		
			
				|  |  | +                {'code': '500', 'message': '服务器内部错误', 'data': None},
 | 
	
		
			
				|  |  | +                status=status.HTTP_500_INTERNAL_SERVER_ERROR
 | 
	
		
			
				|  |  | +            )
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  class ContainerWCSViewSet(viewsets.ModelViewSet):
 | 
	
		
			
				|  |  |      """
 | 
	
	
		
			
				|  | @@ -181,11 +263,6 @@ class ContainerWCSViewSet(viewsets.ModelViewSet):
 | 
	
		
			
				|  |  |          container = data.get('container_number')
 | 
	
		
			
				|  |  |          current_location = data.get('current_location')
 | 
	
		
			
				|  |  |          logger.info(f"请求托盘:{container},请求位置:{current_location}")
 | 
	
		
			
				|  |  | -        if current_location =="203":
 | 
	
		
			
				|  |  | -            current_location ="in1"
 | 
	
		
			
				|  |  | -        elif current_location=="103":
 | 
	
		
			
				|  |  | -            current_location="in2"
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |          data_return = {}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          try:
 | 
	
	
		
			
				|  | @@ -268,6 +345,12 @@ class ContainerWCSViewSet(viewsets.ModelViewSet):
 | 
	
		
			
				|  |  |                          print("❌ 库位和托盘的关联关系更新失败,请检查托盘编码")
 | 
	
		
			
				|  |  |                          return
 | 
	
		
			
				|  |  |                      print(f"[7]库位和托盘的关联关系更新成功!")
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    update_location_container_detail = allocator.update_container_detail_status(container_code,2)  # 更新库位和托盘的关联关系
 | 
	
		
			
				|  |  | +                    if not update_location_container_detail:
 | 
	
		
			
				|  |  | +                        print("❌ 库位和托盘的关联关系更新失败,请检查托盘编码")
 | 
	
		
			
				|  |  | +                        return
 | 
	
		
			
				|  |  | +                    print(f"[8]托盘的关联关系更新成功!")
 | 
	
		
			
				|  |  |                      
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                      allocation_target_location = (
 | 
	
	
		
			
				|  | @@ -276,7 +359,7 @@ class ContainerWCSViewSet(viewsets.ModelViewSet):
 | 
	
		
			
				|  |  |                              + f"{int(location_list_cnumber.col):02d}" + '-' 
 | 
	
		
			
				|  |  |                              + f"{int(location_list_cnumber.layer):02d}" 
 | 
	
		
			
				|  |  |                          )
 | 
	
		
			
				|  |  | -                    batch_id = LocationAllocation.get_batch(container_code)
 | 
	
		
			
				|  |  | +                    batch_id = allocator.get_batch(container_code)
 | 
	
		
			
				|  |  |                      self.generate_task(container, current_location, allocation_target_location,batch_id,location_list_cnumber.c_number)  # 生成任务
 | 
	
		
			
				|  |  |                      current_task = ContainerWCSModel.objects.get(
 | 
	
		
			
				|  |  |                          container=container, 
 | 
	
	
		
			
				|  | @@ -328,15 +411,15 @@ class ContainerWCSViewSet(viewsets.ModelViewSet):
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          # 生成唯一递增的 taskid
 | 
	
		
			
				|  |  |          last_task = ContainerWCSModel.objects.filter(
 | 
	
		
			
				|  |  | -            month=data_tosave['month'], 
 | 
	
		
			
				|  |  | -            tasktype='inbound'
 | 
	
		
			
				|  |  | +            month=data_tosave['month'],
 | 
	
		
			
				|  |  | +          
 | 
	
		
			
				|  |  |          ).order_by('-taskid').first()
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          if last_task:
 | 
	
		
			
				|  |  |              last_id = int(last_task.taskid.split('-')[-1])
 | 
	
		
			
				|  |  | -            new_id = f"{last_id + 1:04}"
 | 
	
		
			
				|  |  | +            new_id = f"{last_id + 1:05}"
 | 
	
		
			
				|  |  |          else:
 | 
	
		
			
				|  |  | -            new_id = "0001"
 | 
	
		
			
				|  |  | +            new_id = "00001"
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          data_tosave['taskid'] = f"inbound-{data_tosave['month']}-{new_id}"
 | 
	
		
			
				|  |  |          logger.info(f"生成入库任务: {data_tosave['taskid']}")
 | 
	
	
		
			
				|  | @@ -346,166 +429,199 @@ class ContainerWCSViewSet(viewsets.ModelViewSet):
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      def update_container_wcs(self, request, *args, **kwargs):
 | 
	
		
			
				|  |  |          data = self.request.data
 | 
	
		
			
				|  |  | -        container = data.get('container_number')
 | 
	
		
			
				|  |  | -        current_location = data.get('current_location')
 | 
	
		
			
				|  |  | -        taskNumber = data.get('taskNumber')
 | 
	
		
			
				|  |  | -    
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        logger.info(f"请求托盘:{container},请求位置:{current_location}")
 | 
	
		
			
				|  |  | -        if current_location =="203":
 | 
	
		
			
				|  |  | -            current_location ="in1"
 | 
	
		
			
				|  |  | -        elif current_location=="103":
 | 
	
		
			
				|  |  | -            current_location="in2"
 | 
	
		
			
				|  |  | -        data_return = {}
 | 
	
		
			
				|  |  | +        logger.info(f"请求托盘:{data.get('container_number')}, 请求位置:{data.get('current_location')}, 任务号:{data.get('taskNumber')}")
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          try:
 | 
	
		
			
				|  |  | -            container_obj = ContainerListModel.objects.filter(container_code=container).first()
 | 
	
		
			
				|  |  | -            if not container_obj:
 | 
	
		
			
				|  |  | -                data_return = {
 | 
	
		
			
				|  |  | -                    'code': '400',
 | 
	
		
			
				|  |  | -                    'message': '托盘编码不存在',
 | 
	
		
			
				|  |  | -                    'data': data
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | -                return Response(data_return, status=status.HTTP_400_BAD_REQUEST)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            # 更新容器数据(部分更新)
 | 
	
		
			
				|  |  | -            serializer = ContainerListPostSerializer(
 | 
	
		
			
				|  |  | -                container_obj, 
 | 
	
		
			
				|  |  | -                data=data, 
 | 
	
		
			
				|  |  | -                partial=True  # 允许部分字段更新
 | 
	
		
			
				|  |  | -            )
 | 
	
		
			
				|  |  | -            serializer.is_valid(raise_exception=True)
 | 
	
		
			
				|  |  | -            serializer.save()
 | 
	
		
			
				|  |  | -             
 | 
	
		
			
				|  |  | -            # 检查是否已在目标位置
 | 
	
		
			
				|  |  | -            if current_location == str(container_obj.target_location):
 | 
	
		
			
				|  |  | -                logger.info(f"托盘 {container} 已在目标位置")
 | 
	
		
			
				|  |  | -                data_return = {
 | 
	
		
			
				|  |  | -                    'code': '200',
 | 
	
		
			
				|  |  | -                    'message': '当前位置已是目标位置',
 | 
	
		
			
				|  |  | -                    'data': data
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                allocator = LocationAllocation()  # 创建实例
 | 
	
		
			
				|  |  | -                location_row = int(container_obj.target_location.split('-')[1])
 | 
	
		
			
				|  |  | -                location_col = int(container_obj.target_location.split('-')[2])
 | 
	
		
			
				|  |  | -                location_layer = int(container_obj.target_location.split('-')[3])
 | 
	
		
			
				|  |  | -                coordinate = f"{location_row}-{location_col}-{location_layer}"
 | 
	
		
			
				|  |  | -                print(f"坐标:{coordinate}")
 | 
	
		
			
				|  |  | -                location_code = LocationModel.objects.filter(coordinate=coordinate).first().location_code
 | 
	
		
			
				|  |  | -                container_code = container
 | 
	
		
			
				|  |  | -                update_location_status = allocator.update_location_status(location_code, 'occupied')  # 更新库位状态
 | 
	
		
			
				|  |  | -                if not update_location_status:
 | 
	
		
			
				|  |  | -                    print("❌ 库位状态更新失败,请检查托盘编码")
 | 
	
		
			
				|  |  | -                    return
 | 
	
		
			
				|  |  | -                print(f"[6]WCS到位,库位状态更新成功!")
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                update_location_container_link = allocator.update_location_container_link(location_code, container_code)  # 更新库位和托盘的关联关系
 | 
	
		
			
				|  |  | -                if not update_location_container_link:
 | 
	
		
			
				|  |  | -                    print("❌ 库位和托盘的关联关系更新失败,请检查托盘编码")
 | 
	
		
			
				|  |  | -                    return
 | 
	
		
			
				|  |  | -                print(f"[7]库位和托盘的关联关系更新成功!")
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | +            # 前置校验
 | 
	
		
			
				|  |  | +            container_obj, error_response = self.validate_container(data)
 | 
	
		
			
				|  |  | +            if error_response:
 | 
	
		
			
				|  |  | +                return error_response
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            # 更新容器数据
 | 
	
		
			
				|  |  | +            if not self.update_container_data(container_obj, data):
 | 
	
		
			
				|  |  | +                return Response({'code': '400', 'message': '数据更新失败', 'data': data}, 
 | 
	
		
			
				|  |  | +                            status=status.HTTP_400_BAD_REQUEST)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            # 处理位置逻辑
 | 
	
		
			
				|  |  | +            if self.is_already_at_target(container_obj, data.get('current_location')):
 | 
	
		
			
				|  |  | +                return self.handle_target_reached(container_obj, data)
 | 
	
		
			
				|  |  |              else:
 | 
	
		
			
				|  |  | -                current_task = ContainerWCSModel.objects.filter(
 | 
	
		
			
				|  |  | -                    container=container, 
 | 
	
		
			
				|  |  | -                    tasktype='inbound'
 | 
	
		
			
				|  |  | -                ).first()
 | 
	
		
			
				|  |  | +                return self.handle_new_allocation(container_obj, data)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                if current_task:
 | 
	
		
			
				|  |  | -                    
 | 
	
		
			
				|  |  | -                    data_return = {
 | 
	
		
			
				|  |  | -                        'code': '200',
 | 
	
		
			
				|  |  | -                        'message': '任务已存在,重新下发',
 | 
	
		
			
				|  |  | -                        'data': current_task.to_dict()
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -                else:
 | 
	
		
			
				|  |  | -                    # 库位分配
 | 
	
		
			
				|  |  | -                    container_code = container
 | 
	
		
			
				|  |  | -                    print(f"开始生成库位,托盘编码:{container_code}")
 | 
	
		
			
				|  |  | -                    allocator = LocationAllocation()  # 创建实例
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    location_list_cnumber = allocator.get_location_by_status(container_code, current_location)  # 获取库位列表
 | 
	
		
			
				|  |  | -                    if not location_list_cnumber:
 | 
	
		
			
				|  |  | -                        print("❌ 通用库位获取失败,请检查托盘编码")
 | 
	
		
			
				|  |  | -                        return
 | 
	
		
			
				|  |  | -                    print(f"[1]库位:{location_list_cnumber}")
 | 
	
		
			
				|  |  | -                    
 | 
	
		
			
				|  |  | -                    update_location_status = allocator.update_location_status(location_list_cnumber.location_code, 'reserved')  # 更新库位状态
 | 
	
		
			
				|  |  | -                    if not update_location_status:
 | 
	
		
			
				|  |  | -                        print("❌ 库位状态更新失败,请检查托盘编码")
 | 
	
		
			
				|  |  | -                        return
 | 
	
		
			
				|  |  | -                    print(f"[2]发送任务,库位状态更新成功!")
 | 
	
		
			
				|  |  | -                    update_location_group_status = allocator.update_location_group_status(location_list_cnumber.location_code)  # 更新库位组状态
 | 
	
		
			
				|  |  | -                    if not update_location_group_status:
 | 
	
		
			
				|  |  | -                        print("❌ 库位组状态更新失败,请检查托盘编码")
 | 
	
		
			
				|  |  | -                        return
 | 
	
		
			
				|  |  | -                    print(f"[3]库位组状态更新成功!")
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    update_batch_status = allocator.update_batch_status(container_code, '2')  # 更新批次状态
 | 
	
		
			
				|  |  | -                    if not update_batch_status:
 | 
	
		
			
				|  |  | -                        print("❌ 批次状态更新失败,请检查批次号")
 | 
	
		
			
				|  |  | -                        return
 | 
	
		
			
				|  |  | -                    print(f"[4]批次状态更新成功!")
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    update_location_group_batch = allocator.update_location_group_batch(location_list_cnumber, container_code)  # 更新库位组的批次
 | 
	
		
			
				|  |  | -                    if not update_location_group_batch:
 | 
	
		
			
				|  |  | -                        print("❌ 库位组批次更新失败,请检查托盘编码")
 | 
	
		
			
				|  |  | -                        return
 | 
	
		
			
				|  |  | -                    print(f"[5]库位组批次更新成功!")
 | 
	
		
			
				|  |  | -                    
 | 
	
		
			
				|  |  | -                    
 | 
	
		
			
				|  |  | -                    update_location_container_link = allocator.update_location_container_link(location_list_cnumber.location_code, container_code)  # 更新库位和托盘的关联关系
 | 
	
		
			
				|  |  | -                    if not update_location_container_link:
 | 
	
		
			
				|  |  | -                        print("❌ 库位和托盘的关联关系更新失败,请检查托盘编码")
 | 
	
		
			
				|  |  | -                        return
 | 
	
		
			
				|  |  | -                    print(f"[7]库位和托盘的关联关系更新成功!")
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    # update_location_status = allocator.update_location_status(location_list_cnumber.location_code, 'occupied')  # 更新库位状态
 | 
	
		
			
				|  |  | -                    # if not update_location_status:
 | 
	
		
			
				|  |  | -                    #     print("❌ 库位状态更新失败,请检查托盘编码")  
 | 
	
		
			
				|  |  | -                    #     return
 | 
	
		
			
				|  |  | -                    # print(f"[6]WCS到位,库位状态更新成功!")
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    # update_location_container_link = allocator.update_location_container_link(location_list_cnumber.location_code, container_code)  # 更新库位和托盘的关联关系
 | 
	
		
			
				|  |  | -                    # if not update_location_container_link:
 | 
	
		
			
				|  |  | -                    #     print("❌ 库位和托盘的关联关系更新失败,请检查托盘编码")
 | 
	
		
			
				|  |  | -                    #     return
 | 
	
		
			
				|  |  | -                    # print(f"[7]库位和托盘的关联关系更新成功!")
 | 
	
		
			
				|  |  | -                    allocation_target_location = (
 | 
	
		
			
				|  |  | -                            location_list_cnumber.warehouse_code + '-' 
 | 
	
		
			
				|  |  | -                            + f"{int(location_list_cnumber.row):02d}" + '-'  # 关键修改点
 | 
	
		
			
				|  |  | -                            + f"{int(location_list_cnumber.col):02d}" + '-' 
 | 
	
		
			
				|  |  | -                            + f"{int(location_list_cnumber.layer):02d}" 
 | 
	
		
			
				|  |  | -                        )
 | 
	
		
			
				|  |  | -                    batch_id = allocator.get_batch(container_code)
 | 
	
		
			
				|  |  | -                    self.generate_task(container, current_location, allocation_target_location,batch_id,location_list_cnumber.c_number)  # 生成任务
 | 
	
		
			
				|  |  | -                    current_task = ContainerWCSModel.objects.get(
 | 
	
		
			
				|  |  | -                        container=container, 
 | 
	
		
			
				|  |  | -                        tasktype='inbound'
 | 
	
		
			
				|  |  | -                    )
 | 
	
		
			
				|  |  | -                  
 | 
	
		
			
				|  |  | -                    data_return = {
 | 
	
		
			
				|  |  | -                        'code': '200',
 | 
	
		
			
				|  |  | -                        'message': '任务下发成功',
 | 
	
		
			
				|  |  | -                        'data': current_task.to_dict()
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -                    container_obj.target_location = allocation_target_location
 | 
	
		
			
				|  |  | -                    container_obj.save()
 | 
	
		
			
				|  |  | -      
 | 
	
		
			
				|  |  | +        except Exception as e:
 | 
	
		
			
				|  |  | +            logger.error(f"处理请求时发生错误: {str(e)}", exc_info=True)
 | 
	
		
			
				|  |  | +            return Response({'code': '500', 'message': '服务器内部错误', 'data': None},
 | 
	
		
			
				|  |  | +                        status=status.HTTP_500_INTERNAL_SERVER_ERROR)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                    self.inport_update_task(current_task.id, container_obj.id)
 | 
	
		
			
				|  |  | +    # ---------- 辅助函数 ----------
 | 
	
		
			
				|  |  | +    def validate_container(self, data):
 | 
	
		
			
				|  |  | +        """验证容器是否存在"""
 | 
	
		
			
				|  |  | +        container = data.get('container_number')
 | 
	
		
			
				|  |  | +        container_obj = ContainerListModel.objects.filter(container_code=container).first()
 | 
	
		
			
				|  |  | +        if not container_obj:
 | 
	
		
			
				|  |  | +            return None, Response({
 | 
	
		
			
				|  |  | +                'code': '400',
 | 
	
		
			
				|  |  | +                'message': '托盘编码不存在',
 | 
	
		
			
				|  |  | +                'data': data
 | 
	
		
			
				|  |  | +            }, status=status.HTTP_400_BAD_REQUEST)
 | 
	
		
			
				|  |  | +        return container_obj, None
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def update_container_data(self, container_obj, data):
 | 
	
		
			
				|  |  | +        """更新容器数据"""
 | 
	
		
			
				|  |  | +        serializer = ContainerListPostSerializer(
 | 
	
		
			
				|  |  | +            container_obj, 
 | 
	
		
			
				|  |  | +            data=data, 
 | 
	
		
			
				|  |  | +            partial=True
 | 
	
		
			
				|  |  | +        )
 | 
	
		
			
				|  |  | +        if serializer.is_valid():
 | 
	
		
			
				|  |  | +            serializer.save()
 | 
	
		
			
				|  |  | +            return True
 | 
	
		
			
				|  |  | +        return False
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def is_already_at_target(self, container_obj, current_location):
 | 
	
		
			
				|  |  | +        """检查是否已在目标位置"""
 | 
	
		
			
				|  |  | +        return current_location == str(container_obj.target_location)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def handle_target_reached(self, container_obj, data):
 | 
	
		
			
				|  |  | +        """处理已到达目标位置的逻辑"""
 | 
	
		
			
				|  |  | +        logger.info(f"托盘 {container_obj.container_code} 已在目标位置")
 | 
	
		
			
				|  |  | +        task = self.get_task_by_tasknumber(data)
 | 
	
		
			
				|  |  | +        self.update_pressure_values(task, container_obj)
 | 
	
		
			
				|  |  | +        task = self.process_task_completion(data)
 | 
	
		
			
				|  |  | +        if not task:
 | 
	
		
			
				|  |  | +            return Response({'code': '400', 'message': '任务不存在', 'data': data},
 | 
	
		
			
				|  |  | +                        status=status.HTTP_400_BAD_REQUEST)
 | 
	
		
			
				|  |  | +        if task and task.tasktype == 'inbound':
 | 
	
		
			
				|  |  | +            self.update_storage_system(container_obj)
 | 
	
		
			
				|  |  | +        
 | 
	
		
			
				|  |  | +        if task and task.tasktype == 'outbound':
 | 
	
		
			
				|  |  | +            OutboundService.process_next_task()
 | 
	
		
			
				|  |  | +        
 | 
	
		
			
				|  |  | +        return Response({
 | 
	
		
			
				|  |  | +            'code': '200',
 | 
	
		
			
				|  |  | +            'message': '当前位置已是目标位置',
 | 
	
		
			
				|  |  | +            'data': data
 | 
	
		
			
				|  |  | +        }, status=status.HTTP_200_OK)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    def get_task_by_tasknumber(self, data):
 | 
	
		
			
				|  |  | +        
 | 
	
		
			
				|  |  | +        taskNumber = data.get('taskNumber') + 20000000000
 | 
	
		
			
				|  |  | +        task = ContainerWCSModel.objects.filter(tasknumber=taskNumber).first()
 | 
	
		
			
				|  |  | +        if task:
 | 
	
		
			
				|  |  | +            return task
 | 
	
		
			
				|  |  | +        else:
 | 
	
		
			
				|  |  | +            return None
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            http_status = status.HTTP_200_OK if data_return['code'] == '200' else status.HTTP_400_BAD_REQUEST
 | 
	
		
			
				|  |  | -            return Response(data_return, status=http_status)
 | 
	
		
			
				|  |  | +    def process_task_completion(self, data):
 | 
	
		
			
				|  |  | +        """处理任务完成状态"""
 | 
	
		
			
				|  |  | +        taskNumber = data.get('taskNumber') + 20000000000
 | 
	
		
			
				|  |  | +        task = ContainerWCSModel.objects.filter(tasknumber=taskNumber).first()
 | 
	
		
			
				|  |  | +        if task:
 | 
	
		
			
				|  |  | +            task.status = 300
 | 
	
		
			
				|  |  | +            task.working = 0
 | 
	
		
			
				|  |  | +            task.save()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        return task
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def update_pressure_values(self, task, container_obj):
 | 
	
		
			
				|  |  | +        """更新压力值计算"""
 | 
	
		
			
				|  |  | +        if task and task.tasktype in ['inbound']:
 | 
	
		
			
				|  |  | +            base_location_obj = base_location.objects.get(id=1)
 | 
	
		
			
				|  |  | +            layer = int(container_obj.target_location.split('-')[-1])
 | 
	
		
			
				|  |  | +            pressure_field = f"layer{layer}_pressure"
 | 
	
		
			
				|  |  | +            logger.info(f"更新压力值,压力字段:{pressure_field}")
 | 
	
		
			
				|  |  | +            current_pressure = getattr(base_location_obj, pressure_field, 0)
 | 
	
		
			
				|  |  | +            updated_pressure = max(current_pressure - task.working, 0)
 | 
	
		
			
				|  |  | +            setattr(base_location_obj, pressure_field, updated_pressure)
 | 
	
		
			
				|  |  | +            base_location_obj.save()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def update_storage_system(self, container_obj):
 | 
	
		
			
				|  |  | +        """更新仓储系统状态"""
 | 
	
		
			
				|  |  | +        allocator = LocationAllocation()
 | 
	
		
			
				|  |  | +        location_code = self.get_location_code(container_obj.target_location)
 | 
	
		
			
				|  |  | +        
 | 
	
		
			
				|  |  | +        # 链式更新操作
 | 
	
		
			
				|  |  | +        update_operations = [
 | 
	
		
			
				|  |  | +            (allocator.update_location_status, location_code, 'occupied'),
 | 
	
		
			
				|  |  | +            (allocator.update_location_container_link, location_code, container_obj.container_code),
 | 
	
		
			
				|  |  | +            (allocator.update_container_detail_status, container_obj.container_code, 2)
 | 
	
		
			
				|  |  | +        ]
 | 
	
		
			
				|  |  | +        
 | 
	
		
			
				|  |  | +        for func, *args in update_operations:
 | 
	
		
			
				|  |  | +            if not func(*args):
 | 
	
		
			
				|  |  | +                logger.error(f"操作失败: {func.__name__}")
 | 
	
		
			
				|  |  | +                return False
 | 
	
		
			
				|  |  | +        return True
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def get_location_code(self, target_location):
 | 
	
		
			
				|  |  | +        """从目标位置解析获取位置编码"""
 | 
	
		
			
				|  |  | +        parts = target_location.split('-')
 | 
	
		
			
				|  |  | +        coordinate = f"{int(parts[1])}-{int(parts[2])}-{int(parts[3])}"
 | 
	
		
			
				|  |  | +        return LocationModel.objects.filter(coordinate=coordinate).first().location_code
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def handle_new_allocation(self, container_obj, data):
 | 
	
		
			
				|  |  | +        """处理新库位分配逻辑"""
 | 
	
		
			
				|  |  | +        allocator = LocationAllocation()
 | 
	
		
			
				|  |  | +        container_code = container_obj.container_code
 | 
	
		
			
				|  |  | +        
 | 
	
		
			
				|  |  | +        # 获取并验证库位分配
 | 
	
		
			
				|  |  | +        location = allocator.get_location_by_status(container_code, data.get('current_location'))
 | 
	
		
			
				|  |  | +        if not location or not self.perform_initial_allocation(allocator, location, container_code):
 | 
	
		
			
				|  |  | +            return Response({'code': '400', 'message': '库位分配失败', 'data': data},
 | 
	
		
			
				|  |  | +                        status=status.HTTP_400_BAD_REQUEST)
 | 
	
		
			
				|  |  | +        
 | 
	
		
			
				|  |  | +        # 生成目标位置并更新容器
 | 
	
		
			
				|  |  | +        target_location = self.generate_target_location(location)
 | 
	
		
			
				|  |  | +        container_obj.target_location = target_location
 | 
	
		
			
				|  |  | +        container_obj.save()
 | 
	
		
			
				|  |  | +        
 | 
	
		
			
				|  |  | +        # 创建任务并返回响应
 | 
	
		
			
				|  |  | +        task = self.create_inbound_task(container_code, data, target_location, location)
 | 
	
		
			
				|  |  | +        return Response({
 | 
	
		
			
				|  |  | +            'code': '200',
 | 
	
		
			
				|  |  | +            'message': '任务下发成功',
 | 
	
		
			
				|  |  | +            'data': task.to_dict()
 | 
	
		
			
				|  |  | +        }, status=status.HTTP_200_OK)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def perform_initial_allocation(self, allocator, location, container_code):
 | 
	
		
			
				|  |  | +        """执行初始库位分配操作"""
 | 
	
		
			
				|  |  | +        operations = [
 | 
	
		
			
				|  |  | +            (allocator.update_location_status, location.location_code, 'reserved'),
 | 
	
		
			
				|  |  | +            (allocator.update_location_group_status, location.location_code),
 | 
	
		
			
				|  |  | +            (allocator.update_batch_status, container_code, '2'),
 | 
	
		
			
				|  |  | +            (allocator.update_location_group_batch, location, container_code),
 | 
	
		
			
				|  |  | +            (allocator.update_location_container_link, location.location_code, container_code),
 | 
	
		
			
				|  |  | +            (allocator.update_container_detail_status, container_code, 2)
 | 
	
		
			
				|  |  | +        ]
 | 
	
		
			
				|  |  | +        
 | 
	
		
			
				|  |  | +        for func, *args in operations:
 | 
	
		
			
				|  |  | +            if not func(*args):
 | 
	
		
			
				|  |  | +                logger.error(f"分配操作失败: {func.__name__}")
 | 
	
		
			
				|  |  | +                return False
 | 
	
		
			
				|  |  | +        return True
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def generate_target_location(self, location):
 | 
	
		
			
				|  |  | +        """生成目标位置字符串"""
 | 
	
		
			
				|  |  | +        return (
 | 
	
		
			
				|  |  | +            f"{location.warehouse_code}-"
 | 
	
		
			
				|  |  | +            f"{int(location.row):02d}-"
 | 
	
		
			
				|  |  | +            f"{int(location.col):02d}-"
 | 
	
		
			
				|  |  | +            f"{int(location.layer):02d}"
 | 
	
		
			
				|  |  | +        )
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        except Exception as e:
 | 
	
		
			
				|  |  | -            logger.error(f"处理请求时发生错误: {str(e)}", exc_info=True)
 | 
	
		
			
				|  |  | -            return Response(
 | 
	
		
			
				|  |  | -                {'code': '500', 'message': '服务器内部错误', 'data': None},
 | 
	
		
			
				|  |  | -                status=status.HTTP_500_INTERNAL_SERVER_ERROR
 | 
	
		
			
				|  |  | -            )
 | 
	
		
			
				|  |  | +    def create_inbound_task(self, container_code, data, target_location, location):
 | 
	
		
			
				|  |  | +        """创建入库任务"""
 | 
	
		
			
				|  |  | +        batch_id = LocationAllocation().get_batch(container_code)
 | 
	
		
			
				|  |  | +        self.generate_task(
 | 
	
		
			
				|  |  | +            container_code,
 | 
	
		
			
				|  |  | +            data.get('current_location'),
 | 
	
		
			
				|  |  | +            target_location,
 | 
	
		
			
				|  |  | +            batch_id,
 | 
	
		
			
				|  |  | +            location.c_number
 | 
	
		
			
				|  |  | +        )
 | 
	
		
			
				|  |  | +        task = ContainerWCSModel.objects.get(container=container_code, tasktype='inbound')
 | 
	
		
			
				|  |  | +        self.inport_update_task(task.id, container_code)
 | 
	
		
			
				|  |  | +        return task
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      @transaction.atomic
 | 
	
		
			
				|  |  |      def inport_update_task(self, wcs_id,container_id):
 | 
	
	
		
			
				|  | @@ -821,7 +937,7 @@ class OutboundService:
 | 
	
		
			
				|  |  |              month=int(month)
 | 
	
		
			
				|  |  |          ).order_by('-sequence').first()
 | 
	
		
			
				|  |  |          sequence = last_task.sequence + 1 if last_task else 1
 | 
	
		
			
				|  |  | -        return f"outbound-{month}-{sequence:04d}"
 | 
	
		
			
				|  |  | +        return f"outbound-{month}-{sequence:05d}"
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      # @staticmethod
 | 
	
		
			
				|  |  |      # def send_task_to_wcs(task):
 | 
	
	
		
			
				|  | @@ -874,13 +990,15 @@ class OutboundService:
 | 
	
		
			
				|  |  |                  "month": task.month,
 | 
	
		
			
				|  |  |                  "message": task.message,
 | 
	
		
			
				|  |  |                  "status": task.status,
 | 
	
		
			
				|  |  | -                "taskNumber": task.tasknumber,
 | 
	
		
			
				|  |  | +                "taskNumber": task.tasknumber-20000000000,
 | 
	
		
			
				|  |  |                  "order_number":task.order_number,
 | 
	
		
			
				|  |  |                  "sequence":task.sequence
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | -        
 | 
	
		
			
				|  |  | +        container_obj = ContainerListModel.objects.filter(container_code=task.container).first()
 | 
	
		
			
				|  |  | +        container_obj.target_location = task.target_location
 | 
	
		
			
				|  |  | +        container_obj.save()
 | 
	
		
			
				|  |  |          # 创建并启动线程
 | 
	
		
			
				|  |  |          thread = threading.Thread(
 | 
	
		
			
				|  |  |              target=OutboundService._async_send_handler,
 | 
	
	
		
			
				|  | @@ -960,10 +1078,10 @@ class OutboundService:
 | 
	
		
			
				|  |  |                      sequence=index,
 | 
	
		
			
				|  |  |                      order_number = container['location_c_number'],
 | 
	
		
			
				|  |  |                      priority=100,
 | 
	
		
			
				|  |  | -                    tasknumber = month*10000+tasknumber_index+tasknumber,
 | 
	
		
			
				|  |  | +                    tasknumber = month*100000+tasknumber_index+tasknumber,
 | 
	
		
			
				|  |  |                      container=container_obj.container_code,
 | 
	
		
			
				|  |  |                      current_location=container_obj.current_location,
 | 
	
		
			
				|  |  | -                    target_location="103",
 | 
	
		
			
				|  |  | +                    target_location="203",
 | 
	
		
			
				|  |  |                      tasktype="outbound",
 | 
	
		
			
				|  |  |                      month=int(timezone.now().strftime("%Y%m")),
 | 
	
		
			
				|  |  |                      message="等待出库",
 | 
	
	
		
			
				|  | @@ -1028,6 +1146,7 @@ class OutTaskViewSet(viewsets.ModelViewSet):
 | 
	
		
			
				|  |  |      """
 | 
	
		
			
				|  |  |      # fun:get_out_task:下发出库任务
 | 
	
		
			
				|  |  |      # fun:get_batch_count_by_boundlist:获取出库申请下的批次数量
 | 
	
		
			
				|  |  | +    # fun:generate_location_by_demand:根据出库需求生成出库任务
 | 
	
		
			
				|  |  |      """
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      # authentication_classes = []  # 禁用所有认证类
 | 
	
	
		
			
				|  | @@ -1061,6 +1180,7 @@ class OutTaskViewSet(viewsets.ModelViewSet):
 | 
	
		
			
				|  |  |              logger.error(f"任务生成失败: {str(e)}")
 | 
	
		
			
				|  |  |              return Response({"code": "500", "msg": str(e)}, status=500)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    # 获取出库需求
 | 
	
		
			
				|  |  |      def get_batch_count_by_boundlist(self,bound_list_id):
 | 
	
		
			
				|  |  |          try:
 | 
	
		
			
				|  |  |              bound_list_obj_all = OutBoundDetailModel.objects.filter(bound_list=bound_list_id).all()
 | 
	
	
		
			
				|  | @@ -1136,7 +1256,7 @@ class OutTaskViewSet(viewsets.ModelViewSet):
 | 
	
		
			
				|  |  |          try:
 | 
	
		
			
				|  |  |              return_location =[]
 | 
	
		
			
				|  |  |              for demand_id, demand_qty in demand_list.items():
 | 
	
		
			
				|  |  | -                container_list = self.get_location_by_status_and_batch(1, demand_id)
 | 
	
		
			
				|  |  | +                container_list = self.get_location_by_status_and_batch(2, demand_id)
 | 
	
		
			
				|  |  |                  if not container_list:
 | 
	
		
			
				|  |  |                      return {"code": "500", "msg": f"批次 {demand_id} 不存在"}
 | 
	
		
			
				|  |  |                  container_id_list = container_list.keys()
 | 
	
	
		
			
				|  | @@ -1152,7 +1272,7 @@ class OutTaskViewSet(viewsets.ModelViewSet):
 | 
	
		
			
				|  |  |                      )
 | 
	
		
			
				|  |  |                  current_qty = 0
 | 
	
		
			
				|  |  |                  for container in order:
 | 
	
		
			
				|  |  | -                    container_detail_obj = ContainerDetailModel.objects.filter(container_id=container['container_number'],batch_id=demand_id,status=1).all()
 | 
	
		
			
				|  |  | +                    container_detail_obj = ContainerDetailModel.objects.filter(container_id=container['container_number'],batch_id=demand_id,status=2).all()
 | 
	
		
			
				|  |  |                      if not container_detail_obj:
 | 
	
		
			
				|  |  |                          return {"code": "500", "msg": f"托盘上无该批次,请检查{container['container_number']} 不存在"}
 | 
	
		
			
				|  |  |                      goods_qty = 0 
 |