from rest_framework import viewsets from utils.page import MyPageNumberPagination from utils.datasolve import sumOfList, transportation_calculate from utils.md5 import Md5 from rest_framework.filters import OrderingFilter from django_filters.rest_framework import DjangoFilterBackend from rest_framework.response import Response from rest_framework.exceptions import APIException from django.utils import timezone from django.db import transaction import logging from rest_framework import status from .models import ContainerListModel,ContainerDetailModel,ContainerOperationModel,ContainerWCSModel,TaskModel from bound.models import BoundBatchModel,BoundDetailModel,BoundListModel # from .files import FileListRenderCN, FileDetailRenderCN from .serializers import ContainerDetailGetSerializer,ContainerDetailPostSerializer from .serializers import ContainerListGetSerializer,ContainerListPostSerializer from .serializers import ContainerOperationGetSerializer,ContainerOperationPostSerializer from .serializers import TaskGetSerializer,TaskPostSerializer from .filter import ContainerDetailFilter,ContainerListFilter,ContainerOperationFilter,TaskFilter # 以后添加模 from warehouse.models import ListModel as warehouse from staff.models import ListModel as staff from rest_framework.permissions import AllowAny logger = logging.getLogger(__name__) class ContainerListViewSet(viewsets.ModelViewSet): """ retrieve: Response a data list(get) list: Response a data list(all) create: Create a data line(post) delete: Delete a data line(delete) """ # authentication_classes = [] # 禁用所有认证类 # permission_classes = [AllowAny] # 允许任意访问 pagination_class = MyPageNumberPagination filter_backends = [DjangoFilterBackend, OrderingFilter, ] ordering_fields = ['id', "create_time", "update_time", ] filter_class = ContainerListFilter def get_project(self): try: id = self.kwargs.get('pk') return id except: return None def get_queryset(self): id = self.get_project() if self.request.user: if id is None: return ContainerListModel.objects.filter() else: return ContainerListModel.objects.filter( id=id) else: return ContainerListModel.objects.none() def get_serializer_class(self): if self.action in ['list', 'destroy','retrieve']: return ContainerListGetSerializer elif self.action in ['create', 'update']: return ContainerListPostSerializer else: return self.http_method_not_allowed(request=self.request) def create(self, request, *args, **kwargs): data = self.request.data order_month = str(timezone.now().strftime('%Y%m')) data['month'] = order_month data['last_operate'] = str(timezone.now()) serializer = self.get_serializer(data=data) serializer.is_valid(raise_exception=True) serializer.save() headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=200, headers=headers) def update(self, request, pk): qs = self.get_object() data = self.request.data serializer = self.get_serializer(qs, data=data) serializer.is_valid(raise_exception=True) serializer.save() headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=200, headers=headers) class TaskViewSet(viewsets.ModelViewSet): """ retrieve: Response a data list(get) list: Response a data list(all) create: Create a data line(post) delete: Delete a data line(delete) """ pagination_class = MyPageNumberPagination filter_backends = [DjangoFilterBackend, OrderingFilter, ] ordering_fields = ['id', "create_time", "update_time", ] filter_class = TaskFilter def get_project(self): try: id = self.kwargs.get('pk') return id except: return None def get_queryset(self): id = self.get_project() if self.request.user: if id is None: return TaskModel.objects.filter() else: return TaskModel.objects.filter( id=id) else: return TaskModel.objects.none() def get_serializer_class(self): if self.action in ['list', 'destroy','retrieve']: return TaskGetSerializer elif self.action in ['create', 'update']: return TaskPostSerializer else: return self.http_method_not_allowed(request=self.request) def create(self, request, *args, **kwargs): data = self.request.data return Response(data, status=200, headers=headers) def update(self, request, pk): qs = self.get_object() data = self.request.data serializer = self.get_serializer(qs, data=data) serializer.is_valid(raise_exception=True) serializer.save() headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=200, headers=headers) class ContainerWCSViewSet(viewsets.ModelViewSet): """ retrieve: Response a data list(get) list: Response a data list(all) create: Create a data line(post) delete: Delete a data line(delete) """ authentication_classes = [] # 禁用所有认证类 permission_classes = [AllowAny] # 允许任意访问 def get_container_wcs(self, request, *args, **kwargs): data = self.request.data container = data.get('container_number') current_location = data.get('current_location') data_return = {} 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 } else: current_task = ContainerWCSModel.objects.filter( container=container, tasktype='inbound' ).first() if current_task: data_return = { 'code': '200', 'message': '任务已存在,重新下发', 'data': current_task.to_dict() } else: self.generate_task(container, current_location, container_obj.target_location) current_task = ContainerWCSModel.objects.get( container=container, tasktype='inbound' ) data_return = { 'code': '200', 'message': '任务下发成功', 'data': current_task.to_dict() } self.inport_update_task(current_task.id, container_obj.id) http_status = status.HTTP_200_OK if data_return['code'] == '200' else status.HTTP_400_BAD_REQUEST return Response(data_return, status=http_status) 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 ) @transaction.atomic def generate_task(self, container, current_location, target_location): data_tosave = { 'container': container, 'current_location': current_location, 'month': timezone.now().strftime('%Y%m'), 'target_location': target_location, 'tasktype': 'inbound', 'status': 103, 'is_delete': False } # 生成唯一递增的 taskid last_task = ContainerWCSModel.objects.filter( month=data_tosave['month'], tasktype='inbound' ).order_by('-taskid').first() if last_task: last_id = int(last_task.taskid.split('-')[-1]) new_id = f"{last_id + 1:04}" else: new_id = "0001" data_tosave['taskid'] = f"inbound-{data_tosave['month']}-{new_id}" logger.info(f"生成入库任务: {data_tosave['taskid']}") # 每月生成唯一递增的 taskNumber data_tosave['tasknumber'] = f"{data_tosave['month']}{new_id}" ContainerWCSModel.objects.create(**data_tosave) @transaction.atomic def inport_update_task(self, wcs_id,container_id): try: task_obj = ContainerWCSModel.objects.filter(id=wcs_id).first() if task_obj: container_detail_obj = ContainerDetailModel.objects.filter(container=container_id).all() if container_detail_obj: for detail in container_detail_obj: # 保存到数据库 batch = BoundDetailModel.objects.filter(bound_batch_id=detail.batch.id).first() TaskModel.objects.create( task_wcs = task_obj, container_detail = detail, batch_detail = batch ) logger.info(f"入库任务 {wcs_id} 已更新") else: logger.info(f"入库任务 {container_id} 批次不存在") else: logger.info(f"入库任务 {wcs_id} 不存在") 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 ) # PDA组盘入库 将扫描到的托盘编码和批次信息保存到数据库 # 1. 先查询托盘对象,如果不存在,则创建托盘对象 # 2. 循环处理每个批次,查询批次对象, # 3. 更新批次数据(根据业务规则) # 4. 保存到数据库 # 5. 保存操作记录到数据库 class ContainerDetailViewSet(viewsets.ModelViewSet): """ retrieve: Response a data list(get) list: Response a data list(all) create: Create a data line(post) delete: Delete a data line(delete) """ # authentication_classes = [] # 禁用所有认证类 # permission_classes = [AllowAny] # 允许任意访问 pagination_class = MyPageNumberPagination filter_backends = [DjangoFilterBackend, OrderingFilter, ] ordering_fields = ['id', "create_time", "update_time", ] filter_class = ContainerDetailFilter def get_project(self): try: id = self.kwargs.get('pk') return id except: return None def get_queryset(self): id = self.get_project() if self.request.user: if id is None: return ContainerDetailModel.objects.filter( is_delete=False) else: return ContainerDetailModel.objects.filter( id=id, is_delete=False) else: return ContainerDetailModel.objects.none() def get_serializer_class(self): if self.action in ['list', 'destroy','retrieve']: return ContainerDetailGetSerializer elif self.action in ['create', 'update']: return ContainerDetailPostSerializer else: return self.http_method_not_allowed(request=self.request) def create(self, request, *args, **kwargs): data = self.request.data order_month = str(timezone.now().strftime('%Y%m')) data['month'] = order_month container_code = data.get('container') batches = data.get('batches', []) # 确保有默认空列表 print('扫描到的托盘编码', container_code) # 处理托盘对象 container_obj = ContainerListModel.objects.filter(container_code=container_code).first() if container_obj: data['container'] = container_obj.id logger.info(f"托盘 {container_code} 已存在") else: logger.info(f"托盘 {container_code} 不存在,创建托盘对象") serializer_list = ContainerListPostSerializer(data={'container_code': container_code}) serializer_list.is_valid(raise_exception=True) serializer_list.save() data['container'] = serializer_list.data.get('id') # 循环处理每个批次 for batch in batches: bound_number = batch.get('goods_code') goods_qty = batch.get('goods_qty') # 查询商品对象 bound_obj = BoundBatchModel.objects.filter(bound_number=bound_number).first() if not bound_obj: # 如果商品不存在,返回错误,这里暂时在程序中进行提醒,后续需要改为前端弹窗提醒 logger.error(f"批次 {bound_number} 不存在") # 跳出此次循环 continue # return Response({"error": f"商品编码 {bound_number} 不存在"}, status=400) # 3. 更新批次数据(根据业务规则) try: last_qty = bound_obj.goods_in_qty bound_obj.goods_in_qty += batch.get("goods_qty", 0) if bound_obj.goods_in_qty >= bound_obj.goods_qty: bound_obj.goods_in_qty = bound_obj.goods_qty bound_obj.status = 1 # 批次状态为组盘完成 print('批次id',bound_obj.id) bound_detail_obj = BoundDetailModel.objects.filter(bound_batch=bound_obj.id).first() if bound_detail_obj: bound_detail_obj.status = 1 bound_detail_obj.save() print('入库申请id',bound_detail_obj.bound_list_id) # 入库申请全部批次入库完成 bound_batch_all = BoundDetailModel.objects.filter(bound_list=bound_detail_obj.bound_list_id).all() if bound_batch_all.count() == bound_batch_all.filter(status=1).count(): bound_list_obj = BoundListModel.objects.filter(id=bound_detail_obj.bound_list_id).first() print('当前状态',bound_list_obj.bound_status) bound_list_obj.bound_status = 102 print('更新状态',bound_list_obj.bound_status) bound_list_obj.save() print('入库申请全部批次组盘完成') else: print('入库申请部分批次组盘完成') else: bound_obj.status = 0 bound_obj.save() # 保存到数据库 # 创建托盘详情记录(每个批次独立) print('新增个数',bound_obj.goods_in_qty-last_qty) if bound_obj.goods_in_qty-last_qty == goods_qty: detail_data = { "container": data['container'], # 托盘ID "batch": bound_obj.id, # 外键关联批次 "goods_code": bound_obj.goods_code, "goods_desc": bound_obj.goods_desc, "goods_qty": goods_qty, "goods_weight": bound_obj.goods_weight, "status": 1, "month": data['month'], "creater": data.get('creater', 'zl') # 默认值兜底 } serializer = self.get_serializer(data=detail_data) serializer.is_valid(raise_exception=True) serializer.save() # 必须保存到数据库 operate_data = { "month" : data['month'], "container": data['container'], # 托盘ID "operation_type" : 'container', "batch" : bound_obj.id, # 外键关联批次 "goods_code": bound_obj.goods_code, "goods_desc": bound_obj.goods_desc, "goods_qty": goods_qty, "goods_weight": bound_obj.goods_weight, "operator": data.get('creater', 'zl'), # 默认值兜底 "timestamp": timezone.now(), "from_location": "container", "to_location": "container", "memo": "入库PDA组盘,pda入库"+str(bound_obj.goods_code)+"数量"+str(goods_qty) } serializer_operate = ContainerOperationPostSerializer(data=operate_data) serializer_operate.is_valid(raise_exception=True) serializer_operate.save() # 必须保存到数据库 elif bound_obj.goods_in_qty-last_qty > 0: print('批次数量不一致') detail_data = { "container": data['container'], # 托盘ID "batch": bound_obj.id, # 外键关联批次 "goods_code": bound_obj.goods_code, "goods_desc": bound_obj.goods_desc, "goods_qty": bound_obj.goods_in_qty-last_qty, "goods_weight": bound_obj.goods_weight, "status": 1, "month": data['month'], "creater": data.get('creater', 'zl') # 默认值兜底 } serializer = self.get_serializer(data=detail_data) serializer.is_valid(raise_exception=True) serializer.save() # 必须保存到数据库 operate_data = { "month" : data['month'], "container": data['container'], # 托盘ID "operation_type" : 'container', "batch" : bound_obj.id, # 外键关联批次 "goods_code": bound_obj.goods_code, "goods_desc": bound_obj.goods_desc, "goods_qty": bound_obj.goods_in_qty-last_qty, "goods_weight": bound_obj.goods_weight, "operator": data.get('creater', 'zl'), # 默认值兜底 "timestamp": timezone.now(), "from_location": "container", "to_location": "container", "memo": "入库PDA组盘,(数量不一致)pda入库"+str(bound_obj.goods_code)+"数量"+str(goods_qty) } serializer_operate = ContainerOperationPostSerializer(data=operate_data) serializer_operate.is_valid(raise_exception=True) serializer_operate.save() # 必须保存到数据库 else : print('重复组盘') except Exception as e: print(f"更新批次 {bound_number} 失败: {str(e)}") continue # 将处理后的数据返回(或根据业务需求保存到数据库) res_data={ "code": "200", "msg": "Success Create", "data": data } return Response(res_data, status=200) def update(self, request, pk): qs = self.get_object() data = self.request.data serializer = self.get_serializer(qs, data=data) serializer.is_valid(raise_exception=True) serializer.save() headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=200, headers=headers) class ContainerOperateViewSet(viewsets.ModelViewSet): """ retrieve: Response a data list(get) list: Response a data list(all) create: Create a data line(post) delete: Delete a data line(delete) """ # authentication_classes = [] # 禁用所有认证类 # permission_classes = [AllowAny] # 允许任意访问 pagination_class = MyPageNumberPagination filter_backends = [DjangoFilterBackend, OrderingFilter, ] ordering_fields = ['id', "timestamp" ] filter_class = ContainerOperationFilter def get_project(self): try: id = self.kwargs.get('pk') return id except: return None def get_queryset(self): id = self.get_project() if self.request.user: if id is None: return ContainerOperationModel.objects.filter( is_delete=False) else: return ContainerOperationModel.objects.filter( id=id, is_delete=False) else: return ContainerOperationModel.objects.none() def get_serializer_class(self): if self.action in ['list', 'destroy','retrieve']: return ContainerOperationGetSerializer elif self.action in ['create', 'update']: return ContainerOperationPostSerializer else: return self.http_method_not_allowed(request=self.request) def create(self, request, *args, **kwargs): data = self.request.data serializer = self.get_serializer(data=data) serializer.is_valid(raise_exception=True) serializer.save() headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=200, headers=headers) def update(self, request, pk): qs = self.get_object() data = self.request.data serializer = self.get_serializer(qs, data=data) serializer.is_valid(raise_exception=True) serializer.save() headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=200, headers=headers)