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 django.db import transaction from rest_framework.response import Response from rest_framework.exceptions import APIException from django.utils import timezone from django.db.models import Sum from .models import BoundListModel, BoundDetailModel,BoundBatchModel, BatchLogModel, OutBatchModel,OutBoundDetailModel,MaterialStatistics,OutBoundDemandModel # from .files import FileListRenderCN, FileDetailRenderCN from .serializers import BoundListGetSerializer,BoundListPostSerializer,BoundBatchGetSerializer,BoundBatchPostSerializer,BoundDetailGetSerializer,BoundDetailPostSerializer from .serializers import OutBoundDetailGetSerializer,OutBoundDetailPostSerializer,OutBatchGetSerializer,OutBatchPostSerializer,BatchLogGetSerializer from .serializers import MaterialStatisticsSerializer,MaterialStatisticsSerializer_items from .serializers import OutBoundDemandModelSerializer from .filter import BoundListFilter, BoundDetailFilter,BoundBatchFilter from .filter import OutBatchFilter,OutBoundDetailFilter,BatchlogFilter from .filter import MaterialStatisticsFilter from .filter import OutBoundDemandFilter # 以后添加模块检验 from warehouse.models import ListModel as warehouse from staff.models import ListModel as staff from rest_framework.permissions import AllowAny from rest_framework.views import APIView class OutBoundDemandViewSet(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 = OutBoundDemandFilter 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 OutBoundDemandModel.objects.filter( is_delete=False) else: return OutBoundDemandModel.objects.filter( id=id, is_delete=False) else: return OutBoundDemandModel.objects.none() def get_serializer_class(self): if self.action in ['list' ]: return OutBoundDemandModelSerializer else: return OutBoundDemandModelSerializer def batch_list(self, request): data =self.request.data OutBoundDemand_all = OutBoundDemandModel.objects.filter(bound_list_id=data['bound_list_id'], is_delete=False).all() data = OutBoundDemandModelSerializer(OutBoundDemand_all, many=True).data return_data ={ "code": 200, "msg": "Success Create", "data": data } return Response(return_data,status=200,headers={}) def create(self, request, *args, **kwargs): data = self.request.data data['openid'] = self.request.auth.openid data['create_time'] = str(timezone.now().strftime('%Y-%m-%d %H:%M:%S')) data['update_time'] = str(timezone.now().strftime('%Y-%m-%d %H:%M:%S')) data['working'] = True bound_list_obj = BoundListModel.objects.get(id=data['bound_list_id']) OutBoundDemand_obj =OutBoundDemandModel.objects.create( bound_list=bound_list_obj, goods_code=data['goods_code'], goods_desc=data['goods_desc'], goods_std=data['goods_std'], goods_unit=data['goods_unit'], goods_qty=data['goods_out_qty'], out_type = data['out_type'], creater=data['creater'], create_time=data['create_time'], update_time=data['update_time'], working=data['working'] ) return_data = OutBoundDemandModelSerializer(OutBoundDemand_obj).data headers = self.get_success_headers(return_data) return Response(return_data, status=200, headers=headers) def batch_demanded_list(self, request): data =self.request.data OutBoundDemand_all = OutBatchModel.objects.filter(bound_list_id=data['bound_list_id'], is_delete=False).all() data = OutBatchGetSerializer(OutBoundDemand_all, many=True).data return_data = { "code": 200, "msg": "Success Create", "data": data } return Response(return_data,status=200,headers={}) def distribute(self, request): """主分配入口""" try: with transaction.atomic(): bound_list_id, demands,out_type, creater= self.validate_distribute_request(request) if OutBatchModel.objects.filter(bound_list_id=bound_list_id, is_delete=False).exists(): return_data = { "code": 200, "msg": "Success Create", "data": { "msg": "该订单已分配,请勿重复分配" } } return Response(return_data, status=200, headers={}) aggregated_demands = self.aggregate_demands(demands) result = self.process_all_goods(aggregated_demands, request, out_type, creater,bound_list_id) return self.build_success_response(result) except APIException as e: return self.build_error_response(e.detail, 200) except Exception as e: return self.build_error_response(str(e), 200) # 验证层方法 def validate_distribute_request(self, request): """验证请求参数""" bound_list_id = request.data.get('bound_list_id') if not bound_list_id: raise APIException({"detail": "Missing bound_list_id"}) demands = OutBoundDemandModel.objects.filter( bound_list_id=bound_list_id, is_delete=False ) if not demands.exists(): raise APIException({"detail": "No demands found"}) base_info = OutBoundDemandModel.objects.filter( bound_list_id=bound_list_id, is_delete=False ).first() out_type = base_info.out_type creater = base_info.creater return bound_list_id, demands, out_type, creater # 数据处理层方法 def aggregate_demands(self, demands): """合并相同物料需求""" return demands.values('goods_code').annotate( total_demand=Sum('goods_qty') ) # 核心分配逻辑 def process_all_goods(self, aggregated_demands, request, out_type, creater,bound_list_id): """处理所有物料分配""" return [ self.process_single_goods( goods_code=item['goods_code'], total_demand=item['total_demand'], request=request, out_type=out_type, creater=creater, bound_list_id=bound_list_id ) for item in aggregated_demands ] def process_single_goods(self, goods_code, total_demand, request,out_type, creater,bound_list_id): """处理单个物料分配""" batches = self.get_available_batches(goods_code) remaining, allocations = self.allocate_batches(total_demand, batches, request,out_type, creater,bound_list_id) if remaining > 0: raise APIException({ "detail": f"Insufficient stock for {goods_code}", "required": total_demand, "allocated": total_demand - remaining }) return { "goods_code": goods_code, "total_demand": total_demand, "allocations": allocations } def get_available_batches(self, goods_code): """获取可用入库批次""" return BoundBatchModel.objects.filter( goods_code=goods_code, is_delete=False ).order_by('bound_batch_order') # 批次分配逻辑 def allocate_batches(self, total_demand, batches, request,out_type, creater,bound_list_id): """分配具体批次""" remaining = total_demand allocations = [] for batch in batches: if remaining <= 0: break allocated = self.allocate_single_batch( batch=batch, remaining=remaining, request=request, out_type=out_type, creater=creater, bound_list_id=bound_list_id ) if allocated == 0: continue allocations.append(allocated) remaining -= allocated['allocated'] return remaining, allocations def allocate_single_batch(self, batch, remaining, request,out_type, creater,bound_list_id): """单个批次分配逻辑""" available = batch.goods_in_location_qty - batch.goods_out_qty if available <= 0: return 0 allocate_qty = min(remaining, available) self.update_batch_status(batch, allocate_qty) out_batch = self.create_out_batch(batch, allocate_qty, request,out_type, creater,bound_list_id) return { "batch": batch.bound_number, "allocated": allocate_qty, "out_batch": out_batch.out_number } # 数据操作层方法 def update_batch_status(self, batch, allocate_qty): """更新批次状态和数量""" batch.goods_out_qty += allocate_qty if batch.goods_out_qty == batch.goods_in_location_qty: batch.status = 6 # 已出库 elif batch.goods_out_qty > 0: batch.status = 5 # 部分出库 batch.save() def create_out_batch(self, batch, allocate_qty, request,out_type, creater,bound_list_id): """创建出库记录""" out_data = { 'bound_list': bound_list_id, 'out_number': self.generate_out_number(batch.goods_code), 'batch_number': batch.id, 'out_date': timezone.now(), 'warehouse_code': batch.warehouse_code, 'warehouse_name': batch.warehouse_name, 'goods_code': batch.goods_code, 'goods_desc': batch.goods_desc, 'goods_out_qty': allocate_qty, 'status': 0, 'openid': request.auth.openid, 'out_type': out_type, 'creater': creater, } serializer = OutBatchPostSerializer(data=out_data) if not serializer.is_valid(): raise APIException({ "detail": f"Serialization error for {batch.goods_code}", "errors": serializer.errors }) return serializer.save() # 工具方法 def generate_out_number(self, goods_code): """生成唯一出库单号""" timestamp = timezone.now().strftime("%Y%m%d%H%M%S") import uuid return f"OUT-{goods_code}-{timestamp}-{uuid.uuid4().hex[:6]}" def build_success_response(self, data): """构建成功响应""" return Response({ "code": 200, "msg": "Distribution completed", "data": data }) def build_error_response(self, error, status_code): """构建错误响应""" return Response({ "code": status_code, "msg": "Distribution failed" if status_code == 400 else "Server error", "error": error }, status=status_code) class MaterialStatisticsViewSet(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 = MaterialStatisticsFilter 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 MaterialStatistics.objects.filter() else: return MaterialStatistics.objects.filter(id=id) else: return MaterialStatistics.objects.none() def get_serializer_class(self): if self.action in ['list' ]: return MaterialStatisticsSerializer elif self.action in ['retrieve']: return MaterialStatisticsSerializer_items else: return self.http_method_not_allowed(request=self.request) class BoundListViewSet(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 = BoundListFilter 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 BoundListModel.objects.filter( is_delete=False) else: return BoundListModel.objects.filter( id=id, is_delete=False) else: return BoundListModel.objects.none() def get_serializer_class(self): if self.action in ['list', 'destroy','retrieve']: return BoundListGetSerializer elif self.action in ['create', 'update']: return BoundListPostSerializer else: return self.http_method_not_allowed(request=self.request) def create(self, request, *args, **kwargs): data = self.request.data # if BoundListModel.objects.filter(code=data['code'], is_delete=False).exists(): # raise APIException({"detail": "Data exists"}) # else: data['openid'] = self.request.auth.openid data['bound_date'] =str(timezone.now().strftime('%Y-%m-%d')) order_day=str(timezone.now().strftime('%Y-%m-')) data['bound_month'] =str(timezone.now().strftime('%Y%m')) if data['bound_type'] == 'in': data['bound_status'] = '100' else: data['bound_status'] = '200' qs_set = BoundListModel.objects.filter(bound_month=data['bound_month'], bound_code_type=data['bound_code_type'], is_delete=False) print('qs_set是:', len(qs_set)) if len(qs_set) > 0: bound_last_code = qs_set.order_by('-id').first().bound_code data['bound_code'] = data['bound_code_type'] +'-'+ order_day + str(int(bound_last_code.split('-')[-1])+1).zfill(4) else: data['bound_code'] = data['bound_code_type'] +'-'+ order_day + '0001' 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) def destroy(self, request, pk): qs = self.get_object() if qs.openid != self.request.auth.openid: raise APIException({"detail": "该入库非您所属,禁止删除,您可以进行编辑"}) else: qs.is_delete = True qs.bound_code =qs.bound_code+'-delete'+str(timezone.now().strftime('%Y%m%d%H%M%S')) qs.save() serializer = self.get_serializer(qs, many=False) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=200, headers=headers) class BoundBatchViewSet(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 = BoundBatchFilter 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 BoundBatchModel.objects.filter( is_delete=False) else: return BoundBatchModel.objects.filter( id=id, is_delete=False) else: return BoundBatchModel.objects.none() def get_serializer_class(self): if self.action in ['list', 'destroy','retrieve']: return BoundBatchGetSerializer elif self.action in ['create', 'update']: return BoundBatchPostSerializer else: return self.http_method_not_allowed(request=self.request) def create(self, request, *args, **kwargs): data = self.request.data try: data['openid'] = self.request.auth.openid data['goods_total_weight'] = data['goods_weight']*data['goods_qty'] order_day=str(timezone.now().strftime('-%Y%m')) order_month=str(timezone.now().strftime('%Y%m')) data['bound_month'] =str(timezone.now().strftime('%Y%m')) print(data['order']) if data['order'] == 'true': qs_set = BoundBatchModel.objects.filter( goods_code=data['goods_code'], bound_month=order_month, is_delete=False) print('qs_set是:', len(qs_set)) if len(qs_set) > 0: bound_last_code = qs_set.order_by('-bound_batch_order').first().bound_number data['bound_batch_order'] = int(bound_last_code.split('-')[-1])+1 data['bound_number'] = data['goods_code'] + '-' + str(int(bound_last_code.split('-')[-1])+1) else: data['bound_batch_order'] = int(order_day.split('-')[-1])*1000 +1 data['bound_number'] = data['goods_code'] + order_day + '001' else: data['bound_number'] = data['goods_code'] + '-' + str(data['bound_batch_order']) serializer = self.get_serializer(data=data) serializer.is_valid(raise_exception=True) serializer.save() headers = self.get_success_headers(serializer.data) self.add_batch_log(serializer.data, 0, data['goods_qty']) return Response(serializer.data, status=200, headers=headers) except Exception as e: print(e) raise APIException({"detail": "{}".format(e)}) def add_batch_log(self, data, log_type, goods_qty): choices_dict = dict(BatchLogModel.BATCH_LOG_TYPE) log_type_name = choices_dict.get(log_type, "未知类型") try: # 获取 BoundBatchModel 实例 batch_obj = BoundBatchModel.objects.get(id=data['id']) except BoundBatchModel.DoesNotExist: return False log_data = { 'batch_id': batch_obj, 'log_type': log_type, 'log_date': timezone.now().strftime('%Y-%m-%d-%H:%M'), # 直接格式化时间,无需转字符串 'goods_code': data['goods_code'], 'goods_desc': data['goods_desc'], 'goods_qty': data['goods_qty'], 'log_content': f"{log_type_name} {data['goods_qty']}件", 'creater': data['creater'], 'openid': data['openid'], 'is_delete': False, } # 创建日志记录 BatchLogModel.objects.create(**log_data) return True 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) def destroy(self, request, pk): qs = self.get_object() if qs.openid != self.request.auth.openid: raise APIException({"detail": "该入库非您所属,禁止删除,您可以进行编辑"}) else: qs.is_delete = True qs.save() serializer = self.get_serializer(qs, many=False) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=200, headers=headers) class BoundDetailViewSet(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 = BoundDetailFilter 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 BoundDetailModel.objects.filter( is_delete=False) else: return BoundDetailModel.objects.filter( id=id, is_delete=False) else: return BoundDetailModel.objects.none() def get_serializer_class(self): if self.action in ['list', 'destroy','retrieve']: return BoundDetailGetSerializer elif self.action in ['create', 'update']: return BoundDetailPostSerializer else: return self.http_method_not_allowed(request=self.request) def create(self, request, *args, **kwargs): data = self.request.data data['openid'] = self.request.auth.openid data.setdefault('is_delete', False) # 验证并保存数据 data['detail_code'] = f"DC-{data['bound_list']:02}{data['bound_batch']:02}" print(data['detail_code']) if BoundDetailModel.objects.filter(detail_code=data['detail_code'], is_delete=False).exists(): raise APIException({"detail": "Data exists"}) else: 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) def destroy(self, request, pk): qs = self.get_object() if qs.openid != self.request.auth.openid: raise APIException({"detail": "该入库非您所属,禁止删除,您可以进行编辑"}) else: qs.is_delete = True qs.save() serializer = self.get_serializer(qs, many=False) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=200, headers=headers) class OutBoundDetailViewSet(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 = OutBoundDetailFilter 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 OutBoundDetailModel.objects.filter( is_delete=False) else: return OutBoundDetailModel.objects.filter( id=id, is_delete=False) else: return OutBoundDetailModel.objects.none() def get_serializer_class(self): if self.action in ['list', 'destroy','retrieve']: return OutBoundDetailGetSerializer elif self.action in ['create', 'update']: return OutBoundDetailPostSerializer else: return self.http_method_not_allowed(request=self.request) def create(self, request, *args, **kwargs): data = self.request.data data['openid'] = self.request.auth.openid data.setdefault('is_delete', False) data['bound_batch_number'] = OutBatchModel.objects.get(id=data['bound_batch']).batch_number.id # 验证并保存数据 data['detail_code'] = f"DC-{data['bound_list']:02}{data['bound_batch']:02}" print(data['detail_code']) if OutBoundDetailModel.objects.filter(detail_code=data['detail_code'], is_delete=False).exists(): raise APIException({"detail": "Data exists"}) else: 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) def destroy(self, request, pk): qs = self.get_object() if qs.openid != self.request.auth.openid: raise APIException({"detail": "该入库非您所属,禁止删除,您可以进行编辑"}) else: qs.is_delete = True qs.save() serializer = self.get_serializer(qs, many=False) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=200, headers=headers) class OutBoundBatchViewSet(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 = OutBatchFilter 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 OutBatchModel.objects.filter( is_delete=False) else: return OutBatchModel.objects.filter( id=id, is_delete=False) else: return OutBatchModel.objects.none() def get_serializer_class(self): if self.action in ['list', 'destroy','retrieve']: return OutBatchGetSerializer elif self.action in ['create', 'update']: return OutBatchPostSerializer else: return self.http_method_not_allowed(request=self.request) def create(self, request, *args, **kwargs): data = self.request.data batch_obj = BoundBatchModel.objects.get(bound_number=data['out_number']) if batch_obj is None: raise APIException({"detail": "批次不存在"}) data['batch_number'] = batch_obj.id data['out_date'] = str(timezone.now().strftime('%Y-%m-%d %H:%M:%S')) data['openid'] = self.request.auth.openid data.setdefault('is_delete', False) data['goods_total_weight'] = data['goods_weight']*data['goods_out_qty'] data['goods_qty'] = batch_obj.goods_qty -batch_obj.goods_out_qty - data['goods_out_qty'] batch_obj.goods_out_qty += data['goods_out_qty'] if batch_obj.goods_out_qty > batch_obj.goods_in_qty: raise APIException({"detail": "出库数量大于批次数量"}) batch_obj.goods_qty -= data['goods_out_qty'] batch_obj.save() data['status'] = 0 #现在处于出库申请状态 serializer = self.get_serializer(data=data) serializer.is_valid(raise_exception=True) serializer.save() headers = self.get_success_headers(serializer.data) self.add_batch_log(serializer.data, 1, data['goods_out_qty']) return Response(serializer.data, status=200, headers=headers) def update(self, request, pk): qs = self.get_object() data = self.request.data data['openid'] = self.request.auth.openid data.setdefault('is_delete', False) data['goods_total_weight'] = data['goods_weight']*data['goods_qty'] serializer = self.get_serializer(qs, data=data) serializer.is_valid(raise_exception=True) serializer.save() headers = self.get_success_headers(serializer.data) self.add_batch_log(serializer.data, 1, data['goods_qty']) return Response(serializer.data, status=200, headers=headers) def destroy(self, request, pk): qs = self.get_object() if qs.openid != self.request.auth.openid: raise APIException({"detail": "该出库非您所属,禁止删除,您可以进行编辑"}) else: qs.is_delete = True qs.save() serializer = self.get_serializer(qs, many=False) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=200, headers=headers) def add_batch_log(self, data, log_type, goods_qty): choices_dict = dict(BatchLogModel.BATCH_LOG_TYPE) log_type_name = choices_dict.get(log_type, "未知类型") try: # 获取 BoundBatchModel 实例 batch_obj = BoundBatchModel.objects.get(id=data['batch_number']) except BoundBatchModel.DoesNotExist: # 处理批次不存在的情况(如记录日志或抛出异常) return False log_data = { 'batch_id': batch_obj, # 关键修复:传入实例对象,而不是 batch_obj.id 'log_type': log_type, 'log_date': timezone.now().strftime('%Y-%m-%d-%H:%M'), # 直接格式化时间,无需转字符串 'goods_code': data['goods_code'], 'goods_desc': data['goods_desc'], 'goods_qty': data['goods_qty'], 'log_content': f"{log_type_name} {goods_qty}件", 'creater': data['creater'], 'openid': data['openid'], 'is_delete': False, # 注意:create_time 和 update_time 由模型的 auto_now_add 和 auto_now 自动处理,无需手动赋值 } # 创建日志记录 BatchLogModel.objects.create(**log_data) return True class BoundBatchLogViewSet(viewsets.ModelViewSet): """ retrieve: Response a data list(get) list: Response a data list(all) 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 = BatchlogFilter def get_queryset(self): return BatchLogModel.objects.filter( is_delete=False) def get_serializer_class(self): if self.action in ['list', 'destroy','retrieve']: return BatchLogGetSerializer else: return self.http_method_not_allowed(request=self.request) def destroy(self, request, pk): qs = self.get_object() qs.is_delete = True qs.save() serializer = self.get_serializer(qs, many=False) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=200, headers=headers) class BatchContainerAPIView(APIView): """ post: 返回批次对应的container列表 """ # authentication_classes = [] # 禁用所有认证类 # permission_classes = [AllowAny] # 允许任意访问 def post(self, request): data = request.data batch_id = data.get('batch_id') from container.models import ContainerDetailModel container_detail_all = ContainerDetailModel.objects.filter(batch_id=batch_id, is_delete=False).exclude(status=3).all() container_dict = {} for container_detail in container_detail_all: container_id = container_detail.container_id if container_id not in container_dict: container_dict[container_id] = { 'id': container_id, 'goods_code': container_detail.goods_code, 'goods_desc': container_detail.goods_desc, 'container_code': container_detail.container.container_code, 'current_location': container_detail.container.current_location, 'goods_qty': container_detail.goods_qty-container_detail.goods_out_qty, 'class':container_detail.goods_class } else: container_dict[container_id]['goods_qty'] += container_detail.goods_qty-container_detail.goods_out_qty container_dict = list(container_dict.values()) return_data = {'code': 200,'msg': 'Success Create', 'data': container_dict} return Response(return_data)