flower_mr před 5 dny
rodič
revize
a130385d20

+ 1 - 1
bin/migrations/0006_alter_locationcontainerlink_container_and_more.py

@@ -15,7 +15,7 @@ class Migration(migrations.Migration):
         migrations.AlterField(
             model_name='locationcontainerlink',
             name='container',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='location_links', to='container.containerlistmodel', verbose_name='关联容器'),
+            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='location_links', to='container.containerlistmodel', verbose_name='关联托盘'),
         ),
         migrations.AlterField(
             model_name='locationcontainerlink',

+ 3 - 3
bin/models.py

@@ -73,13 +73,13 @@ class LocationModel(models.Model):
         )
 
     def get_active_containers(self):
-        """获取当前有效的容器列表"""
+        """获取当前有效的托盘列表"""
         from .models import LocationContainerLink
         active_links = LocationContainerLink.objects.filter(
             location=self,
             is_active=True
         ).select_related('container')  # 优化查询
-        return [link.container for link in active_links]  # 返回容器列表
+        return [link.container for link in active_links]  # 返回托盘列表
 
     @classmethod
     def generate_locations(cls, warehouse_code):
@@ -882,7 +882,7 @@ class LocationContainerLink(models.Model):
         ContainerListModel,
         on_delete=models.CASCADE,
         related_name='location_links',  
-        verbose_name='关联容器'
+        verbose_name='关联托盘'
     )
 
     task_wcs = models.ForeignKey(ContainerWCSModel, on_delete=models.CASCADE, null=True, blank=True)

+ 2 - 2
bin/queries.py

@@ -122,7 +122,7 @@ class LocationQueries:
         :param container_code: 要查询的托盘码
         :return: 所属批次下的托盘总数
         """
-        # 1. 通过托盘码获取容器详情
+        # 1. 通过托盘码获取托盘详情
         container = ContainerListModel.objects.filter(
             container_code=container_code
         ).first()
@@ -145,7 +145,7 @@ class LocationQueries:
         :param container_code: 要查询的托盘码
         :return: 所属批次下的托盘总数
         """
-        # 1. 通过托盘码获取容器详情
+        # 1. 通过托盘码获取托盘详情
         container = ContainerListModel.objects.filter(
             container_code=container_code
         ).first()

+ 9 - 9
bin/services.py

@@ -20,7 +20,7 @@ class AllocationService:
 
         batch_info = LocationQueries.get_batch_info(container_code)
         if not batch_info :
-            raise ValueError("无效的容器或批次信息")
+            raise ValueError("无效的托盘或批次信息")
         if not batch_info['number']:
             if batch_info['class'] == 2:
                 return cls._container_group_allocation(container_code,batch_info, start_point)
@@ -39,7 +39,7 @@ class AllocationService:
         total , scatter_total = LocationQueries.get_pallet_count_by_batch(container_code)
         current_total = LocationQueries.get_pallet_count(container_code)
         if not total:
-                raise ValueError("无效的容器或批次信息")
+                raise ValueError("无效的托盘或批次信息")
         LocationUpdates.update_pallet_count(total, batch_info['number'])
         if current_total == 0:
             
@@ -82,7 +82,7 @@ class AllocationService:
         total = 1
         batch_info['number'] = 'ContainerGroup'+str(container_code)+str(timezone.now().strftime('%Y%m%d'))
         if not total:
-            raise ValueError("无效的容器或批次信息")
+            raise ValueError("无效的托盘或批次信息")
        
         layer_cap = LocationQueries.get_group_capacity()
         pressure = LocationQueries.get_current_pressure()
@@ -139,8 +139,8 @@ class AllocationService:
 
         update_location_container_link = LocationUpdates.link_container(location_min_value.location_code, container_code)
         if not update_location_container_link:
-            raise ValueError("[6] 容器与库位关联失败")
-        print(f"[6] 容器与库位关联成功!")
+            raise ValueError("[6] 托盘与库位关联失败")
+        print(f"[6] 托盘与库位关联成功!")
  
         update_location_container_detail = LocationUpdates.update_container_detail_status(container_code, 2)
         if not update_location_container_detail:
@@ -182,8 +182,8 @@ class AllocationService:
 
         update_location_container_link = LocationUpdates.link_container(location_min_value.location_code, container_code)
         if not update_location_container_link:
-            raise ValueError("[6] 容器与库位关联失败")
-        print(f"[6] 容器与库位关联成功!")
+            raise ValueError("[6] 托盘与库位关联失败")
+        print(f"[6] 托盘与库位关联成功!")
  
         update_location_container_detail = LocationUpdates.update_container_detail_status(container_code, 2)
         if not update_location_container_detail:
@@ -233,8 +233,8 @@ class AllocationService:
 
         update_location_container_link = LocationUpdates.link_container(location_min_value.location_code, container_code)
         if not update_location_container_link:
-            raise ValueError("[6] 容器与库位关联失败")
-        print(f"[6] 容器与库位关联成功!")
+            raise ValueError("[6] 托盘与库位关联失败")
+        print(f"[6] 托盘与库位关联成功!")
  
         update_location_container_detail = LocationUpdates.update_container_detail_status(container_code, 2)
         if not update_location_container_detail:

+ 5 - 5
bin/views.py

@@ -65,7 +65,7 @@ class locationViewSet(viewsets.ModelViewSet):
         'container_links', 
         queryset=LocationContainerLink.objects.filter(
             is_active=True
-        ).select_related('container'),  # 加载关联的容器对象
+        ).select_related('container'),  # 加载关联的托盘对象
         to_attr='active_links'  # 新的属性名称
         )
 
@@ -232,7 +232,7 @@ class LocationAllocation:
         :param container_code: 要查询的托盘码
         :return: 所属批次下的托盘总数
         """
-        # 1. 通过托盘码获取容器详情
+        # 1. 通过托盘码获取托盘详情
         container = ContainerListModel.objects.filter(
             container_code=container_code
         ).first()
@@ -577,7 +577,7 @@ class LocationAllocation:
         :param container_code: 托盘码
         :return: 批次状态
         """
-        # 1. 通过托盘码获取容器详情
+        # 1. 通过托盘码获取托盘详情
         container = ContainerListModel.objects.filter(
             container_code=container_code
         ).first()
@@ -603,7 +603,7 @@ class LocationAllocation:
         :param container_code: 托盘码
         :return: 批次
         """
-        # 1. 通过托盘码获取容器详情
+        # 1. 通过托盘码获取托盘详情
         container = ContainerListModel.objects.filter(
             container_code=container_code
         ).first()
@@ -977,7 +977,7 @@ class LocationAllocation:
             try:
                 location = LocationModel.objects.get(location_code=location_code)
                 links = LocationContainerLink.objects.get(location=location, is_active=True)
-                print(f"释放库位: {location_code}, 关联容器: {links.container_id}")
+                print(f"释放库位: {location_code}, 关联托盘: {links.container_id}")
                 # 解除关联并标记为非活跃
                 links.is_active = False
                 links.save()

+ 2 - 2
container/container_operate.py

@@ -20,7 +20,7 @@ class ContainerService:
         # 初始化基础数据
         data['month'] = timezone.now().strftime('%Y%m')
         
-        # 处理容器
+        # 处理托盘
         container = ContainerManager.get_or_create_container(
             container_code=data.get('container'),
             logger=logger
@@ -37,7 +37,7 @@ class ContainerService:
 class ContainerManager:
     @staticmethod
     def get_or_create_container(container_code, logger):
-        """统一管理容器对象"""
+        """统一管理托盘对象"""
         if container := ContainerListModel.objects.filter(container_code=container_code).first():
             logger.info(f"托盘 {container_code} 已存在")
             return container

+ 1 - 0
container/urls.py

@@ -24,6 +24,7 @@ path(r'pda/containerdetail/', views.OutDetailViewSet.as_view( {"get": "get_conti
 path(r'pda/confirmdetail/', views.OutDetailViewSet.as_view( {"get": "confirm_out_batch_detail"}), name="confirm_out_batch_detail"),
 path(r'pda/canceldetail/', views.OutDetailViewSet.as_view( {"get": "cancel_out_batch_detail"}), name="cancel_out_batch_detail"),
 path(r'containerdetail/', views.ContainerDetailViewSet.as_view( {"get": "containerdetail_list"}), name="containerdetail_list"),
+path(r'pda/change_container_out_qty/', views.OutDetailViewSet.as_view( {"post": "change_container_out_qty"}), name="change_container_out_qty"),
 
 path(r'operate/', views.ContainerOperateViewSet.as_view( {"get": "list","post": "create"}), name="ContainerDetail"),
 re_path(r'^operate/(?P<pk>\d+)/$', views.ContainerOperateViewSet.as_view({

+ 50 - 33
container/views.py

@@ -263,13 +263,13 @@ class TaskRollbackMixin:
                 # 将批次状态恢复为未处理状态(假设原状态为1)
                 allocator.update_batch_status(batch.bound_number, '1')
 
-            # ==================== 容器状态回滚 ====================
+            # ==================== 托盘状态回滚 ====================
             container_obj = ContainerListModel.objects.get(container_code=container_code)
             
-            # 恢复容器详细状态为初始状态(假设原状态为1)
+            # 恢复托盘详细状态为初始状态(假设原状态为1)
             allocator.update_container_detail_status(container_code, 1)
         
-            # 恢复容器的目标位置为当前所在位置
+            # 恢复托盘的目标位置为当前所在位置
             container_obj.target_location = task.current_location
             container_obj.save()
             # ==================== 删除任务记录 ====================
@@ -330,7 +330,7 @@ class ContainerWCSViewSet(viewsets.ModelViewSet):
                 }
                 return Response(data_return, status=status.HTTP_400_BAD_REQUEST)
 
-            # 更新容器数据(部分更新)
+            # 更新托盘数据(部分更新)
             serializer = ContainerListPostSerializer(
                 container_obj, 
                 data=data, 
@@ -530,7 +530,7 @@ class ContainerWCSViewSet(viewsets.ModelViewSet):
             if error_response:
                 return error_response
 
-            # 更新容器数据
+            # 更新托盘数据
             if not self.update_container_data(container_obj, data):
                 return Response(
                     {'code': '400', 'message': '数据更新失败', 'data': data},
@@ -561,7 +561,7 @@ class ContainerWCSViewSet(viewsets.ModelViewSet):
 
     # ---------- 辅助函数 ----------
     def validate_container(self, data):
-        """验证容器是否存在"""
+        """验证托盘是否存在"""
         container = data.get('container_number')
         container_obj = ContainerListModel.objects.filter(container_code=container).first()
         if not container_obj:
@@ -573,7 +573,7 @@ class ContainerWCSViewSet(viewsets.ModelViewSet):
         return container_obj, None
 
     def update_container_data(self, container_obj, data):
-        """更新容器数据"""
+        """更新托盘数据"""
         serializer = ContainerListPostSerializer(
             container_obj, 
             data=data, 
@@ -686,7 +686,7 @@ class ContainerWCSViewSet(viewsets.ModelViewSet):
             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()
@@ -792,7 +792,7 @@ class ContainerWCSViewSet(viewsets.ModelViewSet):
                 # 更新库位组的统计信息
                 self.handle_group_location_status(location_code, location.location_group)
 
-                # 更新容器状态为已出库(假设状态3表示已出库)
+                # 更新托盘状态为已出库(假设状态3表示已出库)
                 container_obj.status = 3
                 container_obj.save()
 
@@ -922,21 +922,21 @@ class ContainerDetailViewSet(viewsets.ModelViewSet):
 
     def containerdetail_list(self, request):
         """
-        获取容器详情列表
+        获取托盘详情列表
         """
         try:
             container_id = request.query_params.get('container')
             if not container_id:
                 return Response(
-                    {'code': 400, 'message': '缺少容器ID参数', 'data': None},
+                    {'code': 400, 'message': '缺少托盘ID参数', 'data': None},
                     status=status.HTTP_400_BAD_REQUEST
                 )
-            # 获取容器对象
+            # 获取托盘对象
             try:
                 container = ContainerListModel.objects.get(id=container_id)
             except ContainerListModel.DoesNotExist:
                 return Response(
-                    {'code': 404, 'message': '指定容器不存在', 'data': None},
+                    {'code': 404, 'message': '指定托盘不存在', 'data': None},
                     status=status.HTTP_404_NOT_FOUND
                 )
 
@@ -969,16 +969,16 @@ class ContainerDetailViewSet(viewsets.ModelViewSet):
             container_id = request.query_params.get('container')
             if not container_id:
                 return Response(
-                    {'code': 400, 'message': '缺少容器ID参数', 'data': None},
+                    {'code': 400, 'message': '缺少托盘ID参数', 'data': None},
                     status=status.HTTP_400_BAD_REQUEST
                 )
 
-            # 获取容器对象
+            # 获取托盘对象
             try:
                 container = ContainerListModel.objects.get(id=container_id)
             except ContainerListModel.DoesNotExist:
                 return Response(
-                    {'code': 404, 'message': '指定容器不存在', 'data': None},
+                    {'code': 404, 'message': '指定托盘不存在', 'data': None},
                     status=status.HTTP_404_NOT_FOUND
                 )
 
@@ -1069,7 +1069,7 @@ class ContainerDetailViewSet(viewsets.ModelViewSet):
 
     def pdadetail_list(self, request):
         """
-        获取PDA组盘入库的容器详情列表
+        获取PDA组盘入库的托盘详情列表
         """
         try:
             container_code = request.query_params.get('container_code')
@@ -1080,7 +1080,7 @@ class ContainerDetailViewSet(viewsets.ModelViewSet):
                 )
  
 
-            # 获取容器对象
+            # 获取托盘对象
             try:
                 container = ContainerListModel.objects.get(container_code=container_code)
             except ContainerListModel.DoesNotExist:
@@ -1579,7 +1579,7 @@ class OutTaskViewSet(APIView):
 
     def get_container_allocation(self, batch_id):
         """兼容所有数据库的去重方案"""
-        # 获取唯一容器ID列表
+        # 获取唯一托盘ID列表
         container_ids = (
             ContainerDetailModel.objects
             .filter(batch_id=batch_id, status=2,is_delete=False)
@@ -1587,7 +1587,7 @@ class OutTaskViewSet(APIView):
             .distinct()
         )
 
-        # 获取每个容器的最新明细(按id倒序)
+        # 获取每个托盘的最新明细(按id倒序)
         return (
             ContainerDetailModel.objects
             .filter(container_id__in=container_ids,batch_id=batch_id, status=2,is_delete=False)
@@ -1605,10 +1605,10 @@ class OutTaskViewSet(APIView):
             return_data = []
             
             for batch_id, demand in batch_demand.items():
-                # 获取已去重的容器列表
+                # 获取已去重的托盘列表
                 container_qs = self.get_container_allocation(batch_id)
                 
-                # 构建容器信息字典(自动去重)
+                # 构建托盘信息字典(自动去重)
                 container_map = {}
                 for cd in container_qs:
                     if cd.container_id in container_map:
@@ -1692,7 +1692,7 @@ class OutTaskViewSet(APIView):
     def _update_allocation_status(self, allocate_container, allocate_qty,bound_list_id):
         """事务化更新分配状态"""
         try:
-            # 更新容器明细
+            # 更新托盘明细
             container_detail_all = ContainerDetailModel.objects.filter(
                 container_id=allocate_container['container_number'],
                 batch_id=allocate_container['batch_id'],
@@ -1852,15 +1852,15 @@ class OutDetailViewSet(viewsets.ModelViewSet):
         return super().get_serializer_class()
     
     def get_out_batch_detail(self, request):
-        """获取某个容器的出库明细"""
+        """获取某个托盘的出库明细"""
         try:
             container_code = request.query_params.get('container_code')
             container_obj = ContainerListModel.objects.filter(container_code=container_code).first()
             if not container_obj:
-                return Response({"code": "500", "message": f"容器 {container_code} 不存在"}, status=status.HTTP_200_OK)
+                return Response({"code": "500", "message": f"托盘 {container_code} 不存在"}, status=status.HTTP_200_OK)
             out_batch_detail_all = out_batch_detail.objects.filter(container=container_obj,working=1,is_delete=False).all()
             if not out_batch_detail_all:
-                return Response({"code": "500", "message": f"容器 {container_code} 无出库明细"}, status=status.HTTP_200_OK)
+                return Response({"code": "500", "message": f"托盘 {container_code} 无出库明细"}, status=status.HTTP_200_OK)
             serializer = OutBoundFullDetailSerializer(out_batch_detail_all, many=True)
             return Response({"code": "200", "message": "Success", "data": serializer.data}, status=status.HTTP_200_OK)
         except Exception as e:
@@ -1873,10 +1873,10 @@ class OutDetailViewSet(viewsets.ModelViewSet):
             container_code = request.query_params.get('container_code')
             container_obj = ContainerListModel.objects.filter(container_code=container_code).first()
             if not container_obj:
-                return Response({"code": "500", "message": f"容器 {container_code} 不存在"}, status=status.HTTP_200_OK)
+                return Response({"code": "500", "message": f"托盘 {container_code} 不存在"}, status=status.HTTP_200_OK)
             out_batch_detail_all = out_batch_detail.objects.filter(container=container_obj,working=1,is_delete=False).all()
             if not out_batch_detail_all:
-                return Response({"code": "500", "message": f"容器 {container_code} 无出库明细"}, status=status.HTTP_200_OK)
+                return Response({"code": "500", "message": f"托盘 {container_code} 无出库明细"}, status=status.HTTP_200_OK)
             for obj in out_batch_detail_all:
                 obj.working = 0
                 obj.save()
@@ -1887,7 +1887,7 @@ class OutDetailViewSet(viewsets.ModelViewSet):
                     goods_code = obj.container_detail.batch.goods_code,
                     goods_desc = obj.container_detail.batch.goods_desc,
                     goods_qty = obj.out_goods_qty,
-                    log_content = f"出库容器 {container_code} 批次 {obj.container_detail.batch.id} 数量 {obj.out_goods_qty} 重量 {obj.container_detail.batch.goods_weight} 到 {obj.to_location.location_code} 库位",
+                    log_content = f"出库托盘 {container_code} 批次 {obj.container_detail.batch.id} 数量 {obj.out_goods_qty}",
                     creater = "WMS",
                     openid = "WMS"
 
@@ -1902,10 +1902,10 @@ class OutDetailViewSet(viewsets.ModelViewSet):
             container_code = request.query_params.get('container_code')
             container_obj = ContainerListModel.objects.filter(container_code=container_code).first()
             if not container_obj:
-                return Response({"code": "500", "message": f"容器 {container_code} 不存在"}, status=status.HTTP_200_OK)
+                return Response({"code": "500", "message": f"托盘 {container_code} 不存在"}, status=status.HTTP_200_OK)
             out_batch_detail_all = out_batch_detail.objects.filter(container=container_obj,working=1,is_delete=False).all()
             if not out_batch_detail_all:
-                return Response({"code": "500", "message": f"容器 {container_code} 无出库明细"}, status=status.HTTP_200_OK)
+                return Response({"code": "500", "message": f"托盘 {container_code} 无出库明细"}, status=status.HTTP_200_OK)
             for obj in out_batch_detail_all:
                 obj.container_detail.goods_out_qty = obj.last_out_goods_qty
                 obj.container_detail.save()
@@ -1921,7 +1921,7 @@ class OutDetailViewSet(viewsets.ModelViewSet):
             container_code = request.query_params.get('container_code')
             container_obj = ContainerListModel.objects.filter(container_code=container_code).first()
             if not container_obj:
-                return Response({"code": "500", "message": f"容器 {container_code} 不存在"}, status=status.HTTP_200_OK)
+                return Response({"code": "500", "message": f"托盘 {container_code} 不存在"}, status=status.HTTP_200_OK)
             container_detail_all = ContainerDetailModel.objects.filter(container=container_obj,is_delete=False).all().exclude(status__in=[3])
             return_data=[]
             for obj in container_detail_all:
@@ -1935,4 +1935,21 @@ class OutDetailViewSet(viewsets.ModelViewSet):
                 })
             return Response({"code": "200", "message": "Success", "data": return_data}, status=status.HTTP_200_OK)
         except Exception as e:
-            return Response({"code": "500", "message": str(e)}, status=status.HTTP_200_OK)
+            return Response({"code": "500", "message": str(e)}, status=status.HTTP_200_OK)
+        
+    def change_container_out_qty(self, request):
+        try:
+            container_code = request.data.get('container_code')
+            container_obj = ContainerListModel.objects.filter(container_code=container_code).first()
+            if not container_obj:
+                return Response({"code": "500", "message": f"托盘 {container_code} 不存在"}, status=status.HTTP_200_OK)
+            for container_detail_id, out_qty in request.data.get('detail_list').items():
+                container_detail_obj = ContainerDetailModel.objects.filter(id=container_detail_id,is_delete=False).first()
+                if not container_detail_obj:
+                    continue
+                container_detail_obj.goods_out_qty += out_qty
+                container_detail_obj.save()
+            return Response({"code": "200", "message": "Success"}, status=status.HTTP_200_OK)
+        except Exception as e:
+            return Response({"code": "500", "message": str(e)}, status=status.HTTP_200_OK)
+                    

+ 70 - 0
logs/error.log

@@ -9342,3 +9342,73 @@ Traceback (most recent call last):
   File "d:\language\python38\lib\site-packages\rest_framework\views.py", line 423, in finalize_response
     assert isinstance(response, HttpResponseBase), (
 AssertionError: Expected a `Response`, `HttpResponse` or `HttpStreamingResponse` to be returned from the view, but received a `<class 'dict'>`
+[2025-05-30 15:34:51,091][django.request.log_response():241] [ERROR] Internal Server Error: /container/pda/outdetail/
+Traceback (most recent call last):
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\backends\utils.py", line 89, in _execute
+    return self.cursor.execute(sql, params)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\backends\sqlite3\base.py", line 357, in execute
+    return Database.Cursor.execute(self, query, params)
+sqlite3.OperationalError: no such table: user_profile
+
+The above exception was the direct cause of the following exception:
+
+Traceback (most recent call last):
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\asgiref\sync.py", line 472, in thread_handler
+    raise exc_info[1]
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\core\handlers\exception.py", line 42, in inner
+    response = await get_response(request)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\core\handlers\base.py", line 253, in _get_response_async
+    response = await wrapped_callback(
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\asgiref\sync.py", line 435, in __call__
+    ret = await asyncio.wait_for(future, timeout=None)
+  File "D:\language\python38\lib\asyncio\tasks.py", line 455, in wait_for
+    return await fut
+  File "D:\language\python38\lib\concurrent\futures\thread.py", line 57, in run
+    result = self.fn(*self.args, **self.kwargs)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\asgiref\sync.py", line 476, in thread_handler
+    return func(*args, **kwargs)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\views\decorators\csrf.py", line 54, in wrapped_view
+    return view_func(*args, **kwargs)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\viewsets.py", line 125, in view
+    return self.dispatch(request, *args, **kwargs)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\views.py", line 509, in dispatch
+    response = self.handle_exception(exc)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\views.py", line 469, in handle_exception
+    self.raise_uncaught_exception(exc)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\views.py", line 480, in raise_uncaught_exception
+    raise exc
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\views.py", line 497, in dispatch
+    self.initial(request, *args, **kwargs)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\views.py", line 414, in initial
+    self.perform_authentication(request)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\views.py", line 324, in perform_authentication
+    request.user
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\request.py", line 227, in user
+    self._authenticate()
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\request.py", line 380, in _authenticate
+    user_auth_tuple = authenticator.authenticate(self)
+  File "D:\Document\code\vue\greater_wms\.\utils\auth.py", line 9, in authenticate
+    if Users.objects.filter(openid__exact=str(token)).exists():
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\models\query.py", line 1225, in exists
+    return self.query.has_results(using=self.db)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\models\sql\query.py", line 592, in has_results
+    return compiler.has_results()
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\models\sql\compiler.py", line 1366, in has_results
+    return bool(self.execute_sql(SINGLE))
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\models\sql\compiler.py", line 1398, in execute_sql
+    cursor.execute(sql, params)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\backends\utils.py", line 103, in execute
+    return super().execute(sql, params)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\backends\utils.py", line 67, in execute
+    return self._execute_with_wrappers(
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\backends\utils.py", line 80, in _execute_with_wrappers
+    return executor(sql, params, many, context)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\backends\utils.py", line 89, in _execute
+    return self.cursor.execute(sql, params)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\utils.py", line 91, in __exit__
+    raise dj_exc_value.with_traceback(traceback) from exc_value
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\backends\utils.py", line 89, in _execute
+    return self.cursor.execute(sql, params)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\backends\sqlite3\base.py", line 357, in execute
+    return Database.Cursor.execute(self, query, params)
+django.db.utils.OperationalError: no such table: user_profile

+ 74 - 0
logs/server.log

@@ -27935,3 +27935,77 @@ AssertionError: Expected a `Response`, `HttpResponse` or `HttpStreamingResponse`
 [2025-05-29 23:01:23,197][django.request.log_response():241] [WARNING] Not Found: /containerpda/canceldetail/
 [2025-05-30 00:14:09,489][django.request.log_response():241] [WARNING] Bad Request: /container/container_wcs/
 [2025-05-30 00:14:23,714][django.request.log_response():241] [WARNING] Bad Request: /container/container_wcs/
+[2025-05-30 15:34:51,091][django.request.log_response():241] [ERROR] Internal Server Error: /container/pda/outdetail/
+Traceback (most recent call last):
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\backends\utils.py", line 89, in _execute
+    return self.cursor.execute(sql, params)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\backends\sqlite3\base.py", line 357, in execute
+    return Database.Cursor.execute(self, query, params)
+sqlite3.OperationalError: no such table: user_profile
+
+The above exception was the direct cause of the following exception:
+
+Traceback (most recent call last):
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\asgiref\sync.py", line 472, in thread_handler
+    raise exc_info[1]
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\core\handlers\exception.py", line 42, in inner
+    response = await get_response(request)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\core\handlers\base.py", line 253, in _get_response_async
+    response = await wrapped_callback(
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\asgiref\sync.py", line 435, in __call__
+    ret = await asyncio.wait_for(future, timeout=None)
+  File "D:\language\python38\lib\asyncio\tasks.py", line 455, in wait_for
+    return await fut
+  File "D:\language\python38\lib\concurrent\futures\thread.py", line 57, in run
+    result = self.fn(*self.args, **self.kwargs)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\asgiref\sync.py", line 476, in thread_handler
+    return func(*args, **kwargs)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\views\decorators\csrf.py", line 54, in wrapped_view
+    return view_func(*args, **kwargs)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\viewsets.py", line 125, in view
+    return self.dispatch(request, *args, **kwargs)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\views.py", line 509, in dispatch
+    response = self.handle_exception(exc)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\views.py", line 469, in handle_exception
+    self.raise_uncaught_exception(exc)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\views.py", line 480, in raise_uncaught_exception
+    raise exc
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\views.py", line 497, in dispatch
+    self.initial(request, *args, **kwargs)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\views.py", line 414, in initial
+    self.perform_authentication(request)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\views.py", line 324, in perform_authentication
+    request.user
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\request.py", line 227, in user
+    self._authenticate()
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\request.py", line 380, in _authenticate
+    user_auth_tuple = authenticator.authenticate(self)
+  File "D:\Document\code\vue\greater_wms\.\utils\auth.py", line 9, in authenticate
+    if Users.objects.filter(openid__exact=str(token)).exists():
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\models\query.py", line 1225, in exists
+    return self.query.has_results(using=self.db)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\models\sql\query.py", line 592, in has_results
+    return compiler.has_results()
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\models\sql\compiler.py", line 1366, in has_results
+    return bool(self.execute_sql(SINGLE))
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\models\sql\compiler.py", line 1398, in execute_sql
+    cursor.execute(sql, params)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\backends\utils.py", line 103, in execute
+    return super().execute(sql, params)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\backends\utils.py", line 67, in execute
+    return self._execute_with_wrappers(
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\backends\utils.py", line 80, in _execute_with_wrappers
+    return executor(sql, params, many, context)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\backends\utils.py", line 89, in _execute
+    return self.cursor.execute(sql, params)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\utils.py", line 91, in __exit__
+    raise dj_exc_value.with_traceback(traceback) from exc_value
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\backends\utils.py", line 89, in _execute
+    return self.cursor.execute(sql, params)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\backends\sqlite3\base.py", line 357, in execute
+    return Database.Cursor.execute(self, query, params)
+django.db.utils.OperationalError: no such table: user_profile
+[2025-05-31 16:47:26,163][django.server.log_message():187] [INFO] "GET /container/pda/confirmdetail/?container_code=10079 HTTP/1.1" 200 55
+[2025-05-31 16:48:06,455][django.server.log_message():187] [INFO] "GET /container/pda/confirmdetail/?container_code=10080 HTTP/1.1" 200 55
+[2025-05-31 16:48:57,577][django.server.log_message():187] [INFO] "GET /container/pda/confirmdetail/?container_code=10080 HTTP/1.1" 200 78
+[2025-05-31 16:49:13,628][django.server.log_message():187] [INFO] "GET /container/pda/confirmdetail/?container_code=10080 HTTP/1.1" 200 78