Selaa lähdekoodia

批次出库取消

flower_bs 4 kuukautta sitten
vanhempi
commit
f55ac5e5cd
2 muutettua tiedostoa jossa 204 lisäystä ja 29 poistoa
  1. 2 2
      container/urls.py
  2. 202 27
      container/views.py

+ 2 - 2
container/urls.py

@@ -24,8 +24,8 @@ path(r'locationdetail/', views.ContainerDetailViewSet.as_view( {"get": "location
 path(r'pdadetail/', views.ContainerDetailViewSet.as_view( {"get": "pdadetail_list"}), name="pdadetail_list"),
 path(r'pda/outdetail/', views.OutDetailViewSet.as_view( {"get": "get_out_batch_detail"}), name="get_out_batch_detail"),
 path(r'pda/containerdetail/', views.OutDetailViewSet.as_view( {"get": "get_contianer_detail"}), name="get_out_batch_detail"),
-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'pda/confirmdetail/', views.OutDetailViewSet.as_view( {"post": "confirm_out_batch_detail"}), name="confirm_out_batch_detail"),
+path(r'pda/canceldetail/', views.OutDetailViewSet.as_view( {"post": "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"),
 

+ 202 - 27
container/views.py

@@ -2572,54 +2572,229 @@ class OutDetailViewSet(viewsets.ModelViewSet):
             return Response({"code": "500", "message": str(e)}, status=status.HTTP_200_OK)
         
     def confirm_out_batch_detail(self, request):
-        """确认出库"""
+        """确认出库 - 支持按批次和数量部分确认"""
         try:
-
-            container_code = request.query_params.get('container_code')
+            container_code = request.data.get('container_code')
+            confirm_items = request.data.get('confirm_items', [])  # 格式: [{"detail_id": 1, "confirm_qty": 10}, ...]
+            
+            if not container_code:
+                return Response({"code": "500", "message": "缺少托盘编码参数"}, status=status.HTTP_200_OK)
+                
             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)
-            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)
-            for obj in out_batch_detail_all:
-                obj.working = 0
-                obj.save()
+            
+            # 如果没有指定确认项,则确认所有出库明细(保持向后兼容)
+            if not confirm_items:
+                out_batch_detail_all = out_batch_detail.objects.filter(container=container_obj,working=1,is_delete=False).order_by('-id').all()
+                if not out_batch_detail_all:
+                    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()
+                    BatchOperateLogModel.objects.create(
+                        batch_id = obj.container_detail.batch,
+                        log_type = 1,
+                        log_date = timezone.now(),
+                        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}",
+                        creater = "WMS",
+                        openid = "WMS"
+                    )
+                return Response({"code": "200", "message": "出库成功"}, status=status.HTTP_200_OK)
+            
+            # 按批次和数量部分确认
+            from decimal import Decimal
+            
+            for item in confirm_items:
+                out_detail_id = item.get('detail_id')  # 这是 out_batch_detail 的 ID
+                confirm_qty = Decimal(str(item.get('confirm_qty', 0)))
+                
+                if not out_detail_id or confirm_qty <= 0:
+                    continue
+                
+                # 确保 out_detail_id 是整数类型
+                try:
+                    out_detail_id = int(out_detail_id)
+                except (ValueError, TypeError):
+                    logger.error(f"无效的 out_detail_id: {out_detail_id}")
+                    continue
+                
+                # 添加调试日志
+                logger.info(f"查询出库明细: container={container_obj.container_code}, out_batch_detail_id={out_detail_id}")
+                
+                # 直接通过 out_batch_detail 的 ID 查找记录
+                out_detail = out_batch_detail.objects.filter(
+                    id=out_detail_id,
+                    container_id=container_obj.id,
+                    working=1,
+                    is_delete=False
+                ).first()
+                
+                if not out_detail:
+                    # 尝试不限制 working 状态查找
+                    out_detail_any = out_batch_detail.objects.filter(
+                        id=out_detail_id,
+                        container_id=container_obj.id,
+                        is_delete=False
+                    ).first()
+                    
+                    if out_detail_any:
+                        if out_detail_any.working == 0:
+                            logger.warning(f"出库明细 {out_detail_id} 的 working 状态为 0,可能已经被处理过了")
+                        else:
+                            logger.warning(f"出库明细 {out_detail_id} 的 working 状态为 {out_detail_any.working},不是 1")
+                    else:
+                        logger.error(f"未找到出库明细: out_batch_detail_id={out_detail_id}, container={container_obj.container_code}")
+                    continue
+                
+                # 计算本次要确认的数量(不能超过该出库明细的数量)
+                out_qty_to_confirm = min(confirm_qty, out_detail.out_goods_qty)
+                
+                # 如果确认数量等于或大于出库数量,则标记为已完成
+                if out_qty_to_confirm >= out_detail.out_goods_qty:
+                    out_detail.working = 0
+                    out_detail.save()
+                else:
+                    # 部分确认,创建新的确认记录并减少剩余数量
+                    # 创建一个新的 out_batch_detail 记录用于剩余数量
+                    remaining_qty = out_detail.out_goods_qty - out_qty_to_confirm
+                    out_detail.out_goods_qty = out_qty_to_confirm
+                    out_detail.working = 0
+                    out_detail.save()
+                    
+                    # 创建剩余数量的记录(如果需要)
+                    if remaining_qty > 0:
+                        out_batch_detail.objects.create(
+                            out_bound_id=out_detail.out_bound_id,
+                            container_id=out_detail.container_id,
+                            container_detail_id=out_detail.container_detail_id,
+                            out_goods_qty=remaining_qty,
+                            last_out_goods_qty=out_detail.last_out_goods_qty,
+                            working=1,
+                            is_delete=False
+                        )
+                
+                # 创建操作日志
                 BatchOperateLogModel.objects.create(
-                    batch_id = obj.container_detail.batch,
+                    batch_id = out_detail.container_detail.batch,
                     log_type = 1,
                     log_date = timezone.now(),
-                    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}",
+                    goods_code = out_detail.container_detail.batch.goods_code,
+                    goods_desc = out_detail.container_detail.batch.goods_desc,
+                    goods_qty = out_qty_to_confirm,
+                    log_content = f"出库托盘 {container_code} 批次 {out_detail.container_detail.batch.id} 数量 {out_qty_to_confirm}",
                     creater = "WMS",
                     openid = "WMS"
-
                 )
+                logger.info(f"确认出库明细 {out_detail_id}: 确认数量={out_qty_to_confirm}, 剩余数量={out_detail.out_goods_qty}")
+            
             return Response({"code": "200", "message": "出库成功"}, status=status.HTTP_200_OK)
+                
         except Exception as e:
+            logger.error(f"确认出库失败: {str(e)}", exc_info=True)
             return Response({"code": "500", "message": str(e)}, status=status.HTTP_200_OK)
         
     def cancel_out_batch_detail(self, request):
-        """取消出库"""
+        """取消出库 - 支持按批次和数量部分取消"""
         try:
-            container_code = request.query_params.get('container_code')
+            container_code = request.data.get('container_code')
+            cancel_items = request.data.get('cancel_items', [])  # 格式: [{"detail_id": 1, "cancel_qty": 10}, ...]
+            
+            if not container_code:
+                return Response({"code": "500", "message": "缺少托盘编码参数"}, status=status.HTTP_200_OK)
+                
             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)
-            out_batch_detail_all = out_batch_detail.objects.filter(container=container_obj,working=1,is_delete=False).order_by('-id').all()
-            if not out_batch_detail_all:
-                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
-                # print(f"取消出库托盘 {container_code} 批次 {obj.container_detail.batch.id},详情 {obj.container_detail.id} 变化前数量 {obj.container_detail.goods_out_qty} 变化后数量 {obj.last_out_goods_qty}")
-                obj.container_detail.save()
-                obj.is_delete = True
-                obj.working = 0
-                obj.save()
+            
+            # 如果没有指定取消项,则取消所有出库明细(保持向后兼容)
+            if not cancel_items:
+                out_batch_detail_all = out_batch_detail.objects.filter(container=container_obj,working=1,is_delete=False).order_by('-id').all()
+                if not out_batch_detail_all:
+                    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()
+                    obj.is_delete = True
+                    obj.working = 0
+                    obj.save()
+                return Response({"code": "200", "message": "出库取消成功"}, status=status.HTTP_200_OK)
+            
+            # 按批次和数量部分取消
+            from decimal import Decimal
+            
+            for item in cancel_items:
+                out_detail_id = item.get('detail_id')  # 这是 out_batch_detail 的 ID
+                cancel_qty = Decimal(str(item.get('cancel_qty', 0)))
+                
+                if not out_detail_id or cancel_qty <= 0:
+                    continue
+                
+                # 确保 out_detail_id 是整数类型
+                try:
+                    out_detail_id = int(out_detail_id)
+                except (ValueError, TypeError):
+                    logger.error(f"无效的 out_detail_id: {out_detail_id}")
+                    continue
+                
+                # 添加调试日志
+                logger.info(f"查询出库明细: container={container_obj.container_code}, out_batch_detail_id={out_detail_id}")
+                
+                # 直接通过 out_batch_detail 的 ID 查找记录
+                out_detail = out_batch_detail.objects.filter(
+                    id=out_detail_id,
+                    container_id=container_obj.id,
+                    working=1,
+                    is_delete=False
+                ).first()
+                
+                if not out_detail:
+                    # 尝试不限制 working 状态查找
+                    out_detail_any = out_batch_detail.objects.filter(
+                        id=out_detail_id,
+                        container_id=container_obj.id,
+                        is_delete=False
+                    ).first()
+                    
+                    if out_detail_any:
+                        if out_detail_any.working == 0:
+                            logger.warning(f"出库明细 {out_detail_id} 的 working 状态为 0,可能已经被处理过了")
+                        else:
+                            logger.warning(f"出库明细 {out_detail_id} 的 working 状态为 {out_detail_any.working},不是 1")
+                    else:
+                        logger.error(f"未找到出库明细: out_batch_detail_id={out_detail_id}, container={container_obj.container_code}")
+                    continue
+                
+                # 计算本次要取消的数量(不能超过该出库明细的数量)
+                out_qty_to_cancel = min(cancel_qty, out_detail.out_goods_qty)
+                
+                # 更新容器明细的出库数量
+                out_detail.container_detail.goods_out_qty -= out_qty_to_cancel
+                out_detail.container_detail.goods_out_qty = max(
+                    out_detail.container_detail.goods_out_qty, 
+                    out_detail.last_out_goods_qty
+                )
+                out_detail.container_detail.save()
+                
+                # 如果全部取消,则删除或标记该出库明细
+                if out_detail.out_goods_qty <= out_qty_to_cancel:
+                    out_detail.is_delete = True
+                    out_detail.working = 0
+                    out_detail.out_goods_qty = Decimal('0')  # 清零
+                else:
+                    # 部分取消,减少出库数量
+                    out_detail.out_goods_qty -= out_qty_to_cancel
+                
+                out_detail.save()
+                logger.info(f"取消出库明细 {out_detail_id}: 取消数量={out_qty_to_cancel}, 剩余数量={out_detail.out_goods_qty}")
+            
             return Response({"code": "200", "message": "出库取消成功"}, status=status.HTTP_200_OK)
+                
         except Exception as e:
+            logger.error(f"取消出库失败: {str(e)}", exc_info=True)
             return Response({"code": "500", "message": str(e)}, status=status.HTTP_200_OK)
         
     def get_contianer_detail(self, request):