flower_mr 1 hónapja
szülő
commit
577109e2d2

BIN
bin/__pycache__/views.cpython-38.pyc


+ 40 - 19
bin/views.py

@@ -233,9 +233,8 @@ class LocationAllocation:
             return None
         # 2. 获取关联的批次明细
         container_detail = ContainerDetailModel.objects.filter(
-            container=container.id,
-            status=1
-        ).first()
+            container=container.id
+        ).exclude(status = 3).first()
         if not container_detail:
             logger.error(f"托盘 {container_code} 未组盘")
             return None
@@ -330,7 +329,32 @@ class LocationAllocation:
         except Exception as e:       
             logger.error(f"更新库位和托盘的关联关系失败:{str(e)}")
             print(f"更新库位和托盘的关联关系失败:{str(e)}")
-            return False    
+            return False 
+    def update_container_detail_status(self,container_code,status):
+        try:
+            # 1. 获取托盘
+            container = ContainerListModel.objects.filter(
+                container_code=container_code
+            ).first()
+            if not container:
+                print(f"托盘 {container_code} 不存在")
+                return False
+            # 2. 更新托盘状态
+            container_detail = ContainerDetailModel.objects.filter(
+                container=container.id
+            ).exclude(status=3).first()
+            if not container_detail:
+                print(f"托盘 {container_code} 未组盘_from update_container_detail_status")
+                return False
+            container_detail.status = status
+            container_detail.save()
+            print(f"更新托盘状态成功!")
+            return True
+        except Exception as e:       
+            logger.error(f"更新托盘状态失败:{str(e)}")
+            print(f"更新托盘状态失败:{str(e)}")
+            return False 
+
     def update_location_group_batch(self,location,container_code):
         """
         :param location: 库位对象
@@ -467,7 +491,7 @@ class LocationAllocation:
         :return:
         """
         try:
-            # 1. 通过托盘码获取容器详情
+            # 1. 通过托盘码获取托盘详情
             container = ContainerListModel.objects.filter(
                 container_code=container_code
             ).first()
@@ -478,12 +502,11 @@ class LocationAllocation:
                 return None
             # 2. 获取关联的批次明细
             container_detail = ContainerDetailModel.objects.filter(
-                container=container.id,
-                status=1
-            ).first()
+                container=container.id
+            ).exclude(status=3).first()
             if not container_detail:
                 print (f"托盘 {container_code} 未组盘")
-                logger.error(f"托盘 {container_code} 未组盘")
+                logger.error(f"托盘 {container_code} 未组盘_from update_batch_status")
                 return None
         
             # 3. 更新批次状态
@@ -513,12 +536,11 @@ class LocationAllocation:
             return None
         # 2. 获取关联的批次明细
         container_detail = ContainerDetailModel.objects.filter(
-            container=container.id,
-            status=1
-        ).first()
+            container=container.id
+        ).exclude(status=3).first()
         if not container_detail:
             print (f"托盘 {container_code} 未组盘")
-            logger.error(f"托盘 {container_code} 未组盘")
+            logger.error(f"托盘 {container_code} 未组盘_from get_batch_status")
             return None
 
         batch_status = container_detail.batch.status
@@ -540,12 +562,11 @@ class LocationAllocation:
             return None
         # 2. 获取关联的批次明细
         container_detail = ContainerDetailModel.objects.filter(
-            container=container.id,
-            status=1
-        ).first()
+            container=container.id
+        ).exclude(status=3).first()
         if not container_detail:
             print (f"托盘 {container_code} 未组盘")
-            logger.error(f"托盘 {container_code} 未组盘")
+            logger.error(f"托盘 {container_code} 未组盘_from get_batch")
             return None
 
         batch = container_detail.batch.bound_number
@@ -834,9 +855,9 @@ class LocationAllocation:
             if not location_groups:
                 print(f"层{layer} 无库位")
             # 根据起始位置选择排序字段
-            if start_location == 'in1':
+            if start_location == '203':
                 ordered_groups = location_groups.order_by('left_priority')
-            elif start_location == 'in2':
+            elif start_location == '103':
                 ordered_groups = location_groups.order_by('right_priority')
             else:
                 ordered_groups = location_groups.none()

BIN
bound/__pycache__/models.cpython-38.pyc


+ 23 - 0
bound/migrations/0002_boundbatchmodel_goods_in_location_qty_and_more.py

@@ -0,0 +1,23 @@
+# Generated by Django 4.1.2 on 2025-04-28 13:56
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('bound', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='boundbatchmodel',
+            name='goods_in_location_qty',
+            field=models.BigIntegerField(default=0, verbose_name='库位上入库数量'),
+        ),
+        migrations.AddField(
+            model_name='boundbatchmodel',
+            name='goods_out_location_qty',
+            field=models.BigIntegerField(default=0, verbose_name='库位上出库数量'),
+        ),
+    ]

BIN
bound/migrations/__pycache__/0002_boundbatchmodel_goods_in_location_qty_and_more.cpython-38.pyc


+ 2 - 0
bound/models.py

@@ -55,7 +55,9 @@ class BoundBatchModel(models.Model):
     goods_unit = models.CharField(default='待填写', max_length=255, verbose_name="商品单位")
     goods_qty = models.BigIntegerField(default=0, verbose_name="商品数量")
     goods_in_qty = models.BigIntegerField(default=0, verbose_name="入库数量")
+    goods_in_location_qty = models.BigIntegerField(default=0, verbose_name="库位上入库数量")
     goods_out_qty = models.BigIntegerField(default=0, verbose_name="出库数量")
+    goods_out_location_qty = models.BigIntegerField(default=0, verbose_name="库位上出库数量")
 
     status = models.IntegerField(choices=CONTAINER_STATUS, default=0, verbose_name='批次状态')
     container_number = models.IntegerField( default=0, verbose_name="托盘数目")

BIN
container/__pycache__/models.cpython-38.pyc


BIN
container/__pycache__/views.cpython-38.pyc


+ 23 - 0
container/migrations/0009_containerwcsmodel_working_and_more.py

@@ -0,0 +1,23 @@
+# Generated by Django 4.1.2 on 2025-04-27 08:55
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('container', '0008_containerwcsmodel_order_number'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='containerwcsmodel',
+            name='working',
+            field=models.IntegerField(default=1, verbose_name='工作状态'),
+        ),
+        migrations.AlterField(
+            model_name='containerdetailmodel',
+            name='status',
+            field=models.IntegerField(choices=[(0, '空盘'), (1, '组盘'), (2, '在库'), (3, '已出库')], default=0, verbose_name='状态'),
+        ),
+    ]

BIN
container/migrations/__pycache__/0009_containerwcsmodel_working_and_more.cpython-38.pyc


+ 1 - 1
container/models.py

@@ -128,7 +128,7 @@ class ContainerWCSModel(models.Model):
             'target_location': self.target_location,
             'tasktype': self.tasktype,
             'taskid': self.taskid,
-            'taskNumber': self.tasknumber,
+            'taskNumber': self.tasknumber-20000000000,
             'message': self.message,
             'container': self.container,
             'status': self.status

+ 290 - 170
container/views.py

@@ -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 

BIN
db.sqlite3


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 117 - 4491
logs/error.log


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 132 - 6641
logs/server.log


+ 9 - 0
templates/src/layouts/MainLayout.vue

@@ -111,6 +111,7 @@
             <q-item-section avatar><q-icon name="stay_current_landscape" /></q-item-section>
             <q-item-section>托盘管理</q-item-section>
           </q-item>
+
           <q-item clickable :to="{ name: 'dn' }" @click="linkChange('outbound')" v-ripple exact
             :active="link === 'outbound' && link !== ''"
             :class="{ 'my-menu-link': link === 'outbound' && link !== '' }">
@@ -133,6 +134,14 @@
 
 
           <q-separator />
+          <q-item clickable :to="{ name: 'task' }" @click="linkChange('taskpage')" v-ripple exact
+            :active="link === 'taskpage' && link !== ''" :class="{
+              'my-menu-link': link === 'taskpage' && link !== '',
+            }">
+ 
+            <q-item-section avatar><q-icon name="img:statics/outbound/picked.png" /></q-item-section>
+            <q-item-section>任务管理</q-item-section>
+          </q-item>
 
           <q-item clickable :to="{ name: 'warehouseset' }" @click="linkChange('warehouse')" v-ripple exact
             :active="link === 'warehouse' && link !== ''"

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1218 - 0
templates/src/pages/task/task.vue


+ 54 - 0
templates/src/pages/task/taskpage.vue

@@ -0,0 +1,54 @@
+<template>
+  <q-page class="flex flex-top">
+<template>
+  <div class="q-pa-md">
+    <div class="q-gutter-y-md" style="max-width: 100%">
+      <q-tabs
+        v-model="detaillink"
+      >
+        <transition appear enter-active-class="animated zoomIn">
+          <q-route-tab name="asn" :label="$t('inbound.asn')" icon="img:statics/inbound/asn.png" :to="{ name: 'asn' }" exact/>
+        </transition>
+        <!-- <transition appear enter-active-class="animated zoomIn">
+          <q-route-tab name="predeliverystock" :label="$t('inbound.predeliverystock')"  icon="img:statics/inbound/polist.png" :to="{ name: 'predeliverystock' }" exact/>
+        </transition>
+        <transition appear enter-active-class="animated zoomIn">
+          <q-route-tab name="preloadstock" :label="$t('inbound.preloadstock')" icon="img:statics/inbound/preloadstock.png" :to="{ name: 'preloadstock' }" exact/>
+        </transition>
+        <transition appear enter-active-class="animated zoomIn">
+          <q-route-tab name="presortstock" :label="$t('inbound.presortstock')" icon="img:statics/inbound/presortstock.png" :to="{ name: 'presortstock' }" exact/>
+        </transition> -->
+        <transition appear enter-active-class="animated zoomIn">
+          <q-route-tab name="sortstock" :label="$t('inbound.sortstock')" icon="img:statics/inbound/sortstock.png" :to="{ name: 'sortstock' }" exact/>
+        </transition>
+        <!-- <transition appear enter-active-class="animated zoomIn">
+          <q-route-tab name="shortage" :label="$t('inbound.shortage')" icon="img:statics/inbound/shortage.png" :to="{ name: 'shortage' }" exact/>
+        </transition>
+        <transition appear enter-active-class="animated zoomIn">
+          <q-route-tab name="more" :label="$t('inbound.more')" icon="img:statics/inbound/more.png" :to="{ name: 'more' }" exact/>
+        </transition>
+        <transition appear enter-active-class="animated zoomIn">
+          <q-route-tab name="asnfinish" :label="$t('inbound.asnfinish')" icon="img:statics/inbound/asnfinish.png" :to="{ name: 'asnfinish' }" exact/>
+        </transition> -->
+      </q-tabs>
+    </div>
+  </div>
+</template>
+    <div class="main-table">
+      <router-view />
+    </div>
+  </q-page>
+</template>
+
+<script>
+export default {
+  name: 'Pageinbound',
+  data () {
+    return {
+      detaillink: 'asn'
+    }
+  },
+  methods: {
+  }
+}
+</script>

+ 11 - 0
templates/src/router/routes.js

@@ -264,6 +264,17 @@ const routes = [{
       }
       ]
     },
+    {
+      path: 'taskpage',
+      name: 'taskpage',
+      component: () => import('pages/task/taskpage.vue'),
+      children: [{
+        path: 'task',
+        name: 'task',
+        component: () => import('pages/task/task.vue')
+      }
+    ]
+    },
     {
       path: 'warehouse',
       name: 'warehouse',