from rest_framework import status, views, serializers, pagination from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from django.utils import dateparse, timezone from api_v1.views.stock_change_views.mixins import StockChangeViewMixin from business import models as business_models from business import pre_order_services class PrePurchaseOrderItemSerializer(serializers.ModelSerializer): class Meta: model = business_models.PrePurchaseOrderItem fields = [ 'id', 'product_id', 'product_name', 'color', 'quantity', 'unit', 'spec', 'remarks', ] read_only_fields = ['id'] class PrePurchaseOrderSerializer(serializers.ModelSerializer): human_id = serializers.CharField(read_only=True) supplier_name = serializers.CharField(source='supplier.name', read_only=True) warehouse_name = serializers.CharField(source='warehouse.name', read_only=True) operator_name = serializers.CharField(source='operator.name', read_only=True) items = PrePurchaseOrderItemSerializer(many=True, read_only=True) class Meta: model = business_models.PrePurchaseOrder fields = [ 'id', 'human_id', 'merchant', 'supplier', 'supplier_name', 'warehouse', 'warehouse_name', 'operator', 'operator_name', 'kind', 'remarks', 'created_at', 'items', ] read_only_fields = [ 'id', 'human_id', 'created_at', 'supplier_name', 'warehouse_name', 'operator_name', 'items', ] class PrePurchaseOrderPagination(pagination.LimitOffsetPagination): default_limit = 20 max_limit = 100 class PrePurchaseOrderView(StockChangeViewMixin, views.APIView): """预采购单查询与创建""" permission_classes = [IsAuthenticated] pagination_class = PrePurchaseOrderPagination def get(self, request): if not self.check_employee_permission(request): return self.permission_error_response('无权限访问') merchant = request.user.employee.merchant queryset = pre_order_services.list_pre_purchase_orders(merchant=merchant) supplier_id = request.query_params.get('supplier') or request.query_params.get('supplier_id') warehouse_id = request.query_params.get('warehouse') or request.query_params.get('warehouse_id') kind = request.query_params.get('kind') human_id_contains = request.query_params.get('human_id__icontains') created_from = request.query_params.get('created_at_from') created_to = request.query_params.get('created_at_to') try: if supplier_id: queryset = queryset.filter(supplier_id=int(supplier_id)) if warehouse_id: queryset = queryset.filter(warehouse_id=int(warehouse_id)) if kind: queryset = queryset.filter(kind=int(kind)) except (TypeError, ValueError): return Response({'error': '筛选参数必须为整数'}, status=status.HTTP_400_BAD_REQUEST) if human_id_contains: queryset = queryset.filter(human_id__icontains=str(human_id_contains).strip()) def _parse_datetime(value: str): dt = dateparse.parse_datetime(value) if dt is None: d = dateparse.parse_date(value) if d is None: return None dt = timezone.datetime.combine(d, timezone.datetime.min.time()) if timezone.is_naive(dt): dt = timezone.make_aware(dt, timezone.get_current_timezone()) return dt if created_from: dt_from = _parse_datetime(created_from) if dt_from is None: return Response({'error': 'created_at_from 格式不正确'}, status=status.HTTP_400_BAD_REQUEST) queryset = queryset.filter(created_at__gte=dt_from) if created_to: dt_to = _parse_datetime(created_to) if dt_to is None: return Response({'error': 'created_at_to 格式不正确'}, status=status.HTTP_400_BAD_REQUEST) queryset = queryset.filter(created_at__lte=dt_to) paginator = self.pagination_class() page = paginator.paginate_queryset(queryset.order_by('-created_at'), request, view=self) serializer = PrePurchaseOrderSerializer(page, many=True) return paginator.get_paginated_response(serializer.data) def post(self, request): if not self.check_employee_permission(request): return self.permission_error_response('无权限访问') merchant = request.user.employee.merchant employee = request.user.employee data = request.data or {} try: pre_purchase_order = pre_order_services.create_pre_purchase_order( merchant=merchant, supplier_id=data.get('supplier') or data.get('supplier_id'), warehouse_id=data.get('warehouse') or data.get('warehouse_id'), operator=employee, created_by=request.user, kind=data.get('kind'), items=data.get('items'), remarks=data.get('remarks', ''), ) except ValueError as exc: return Response({'error': str(exc)}, status=status.HTTP_400_BAD_REQUEST) return Response(PrePurchaseOrderSerializer(pre_purchase_order).data, status=status.HTTP_201_CREATED) class PrePurchaseOrderDetailView(StockChangeViewMixin, views.APIView): permission_classes = [IsAuthenticated] def _get_order(self, request, pk: int): if not self.check_employee_permission(request): return None, self.permission_error_response('无权限访问') merchant = request.user.employee.merchant try: order = pre_order_services.get_pre_purchase_order( merchant=merchant, pre_purchase_order_id=pk, ) return order, None except ValueError: return None, self.not_found_response('预采购单不存在') def get(self, request, pk: int): order, error_response = self._get_order(request, pk) if error_response: return error_response return Response(PrePurchaseOrderSerializer(order).data, status=status.HTTP_200_OK) def put(self, request, pk: int): return self._update(request, pk) def patch(self, request, pk: int): return self._update(request, pk) def _update(self, request, pk: int): order, error_response = self._get_order(request, pk) if error_response: return error_response data = request.data or {} try: updated = pre_order_services.update_pre_purchase_order( pre_purchase_order=order, supplier_id=data.get('supplier') or data.get('supplier_id'), warehouse_id=data.get('warehouse') or data.get('warehouse_id'), kind=data.get('kind'), items=data.get('items'), remarks=data.get('remarks'), ) except ValueError as exc: return Response({'error': str(exc)}, status=status.HTTP_400_BAD_REQUEST) return Response(PrePurchaseOrderSerializer(updated).data, status=status.HTTP_200_OK) def delete(self, request, pk: int): order, error_response = self._get_order(request, pk) if error_response: return error_response pre_order_services.delete_pre_purchase_order(pre_purchase_order=order) return Response(status=status.HTTP_204_NO_CONTENT)