123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579 |
- 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)
-
|