1
0
forked from erp-dev/erp

test: before all tests

This commit is contained in:
2025-12-25 21:36:50 +08:00
parent 147b5804d2
commit c0277a8218
18 changed files with 310 additions and 89 deletions

View File

@@ -3,11 +3,12 @@ from rest_framework.mixins import ListModelMixin
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from rest_framework import serializers, status
from rest_framework.pagination import LimitOffsetPagination
import logging
from flower.viewsets import LimitedLimitOffsetPagination
from stock import models as stock_models
from basic_info import models as basic_models
from api_man.serializers import ProductSerializer
import logging
logger = logging.getLogger(__name__)
@@ -64,7 +65,7 @@ class InventoryAPIView(ListModelMixin, GenericAPIView):
- /api/v1/inventory/?limit=20&offset=40 - 跳过前40条获取接下来的20条
"""
serializer_class = InventorySerializer
pagination_class = LimitOffsetPagination
pagination_class = LimitedLimitOffsetPagination
permission_classes = [IsAuthenticated]
def get_queryset(self):

View File

@@ -16,9 +16,9 @@ from django.utils.decorators import method_decorator
from django.views.decorators.cache import cache_page
from django.db.models import F
from rest_framework import serializers, viewsets
from rest_framework.pagination import LimitOffsetPagination
from rest_framework.permissions import DjangoModelPermissions
from flower.viewsets import LimitedReadOnlyModelViewSet
from api_v1.models import MDYPlateOrderStaging
from flower.utils.mingdaoyun.mappings import plate_order_field_definitions
from flower.utils.mingdaoyun.relations import flatten_row_by_field_definitions, normalize_mdy_value
@@ -87,12 +87,11 @@ class MDYPlateOrderStagingSerializer(serializers.ModelSerializer):
@method_decorator(cache_page(10), name='list')
class MDYPlateOrderStagingViewSet(viewsets.ReadOnlyModelViewSet):
class MDYPlateOrderStagingViewSet(LimitedReadOnlyModelViewSet):
"""开版暂存数据查询(只读)。"""
serializer_class = MDYPlateOrderStagingSerializer
# permission_classes = [DjangoModelPermissions]
pagination_class = LimitOffsetPagination
def get_queryset(self):
qs = MDYPlateOrderStaging.objects.all()

View File

@@ -7,11 +7,13 @@ from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.decorators import action
from django.db.models import Q
from flower.viewsets import LimitedModelViewSet
from stateflow.models import StateParameter
from stateflow.serializers import StateParameterSerializer
class StateParameterViewSet(viewsets.ModelViewSet):
class StateParameterViewSet(LimitedModelViewSet):
"""
工艺参数 ViewSet

View File

@@ -146,10 +146,10 @@ class PrintingJobAPITestCase(TestCase):
response = self.client.get('/api/v1/printing-jobs/')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data), 2)
self.assertEqual(response.data['count'], 2)
# 新增字段:批量推进记录(稳定输出 key
for item in response.data:
for item in response.data['results']:
self.assertIn('batch_advance_records', item)
self.assertIsInstance(item['batch_advance_records'], list)
self.assertEqual(len(item['batch_advance_records']), 0)
@@ -202,7 +202,7 @@ class PrintingJobAPITestCase(TestCase):
# list: 应包含 batch_advance_records
response = self.client.get('/api/v1/printing-jobs/')
self.assertEqual(response.status_code, status.HTTP_200_OK)
target = next(item for item in response.data if item['id'] == job.id)
target = next(item for item in response.data['results'] if item['id'] == job.id)
self.assertIn('batch_advance_records', target)
self.assertEqual(len(target['batch_advance_records']), 1)
@@ -337,8 +337,8 @@ class PrintingJobAPITestCase(TestCase):
response = self.client.get(f'/api/v1/printing-jobs/?printing_order={self.printing_order.id}')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data), 1)
self.assertEqual(response.data[0]['printing_order'], self.printing_order.id)
self.assertEqual(response.data['count'], 1)
self.assertEqual(response.data['results'][0]['printing_order'], self.printing_order.id)
def test_filter_by_product(self):
"""测试按产品过滤"""
@@ -369,8 +369,8 @@ class PrintingJobAPITestCase(TestCase):
response = self.client.get(f'/api/v1/printing-jobs/?product={self.product.id}')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data), 1)
self.assertEqual(response.data[0]['product'], self.product.id)
self.assertEqual(response.data['count'], 1)
self.assertEqual(response.data['results'][0]['product'], self.product.id)
def test_filter_by_quantity_range(self):
"""测试按数量范围过滤"""
@@ -401,8 +401,8 @@ class PrintingJobAPITestCase(TestCase):
response = self.client.get('/api/v1/printing-jobs/?quantity_min=100&quantity_max=200')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data), 1)
self.assertEqual(response.data[0]['quantity'], 150)
self.assertEqual(response.data['count'], 1)
self.assertEqual(response.data['results'][0]['quantity'], 150)
def test_search_by_product_name(self):
"""测试按产品名称搜索"""
@@ -433,8 +433,8 @@ class PrintingJobAPITestCase(TestCase):
response = self.client.get('/api/v1/printing-jobs/?search=特殊')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data), 1)
self.assertIn('特殊', response.data[0]['product_name'])
self.assertEqual(response.data['count'], 1)
self.assertIn('特殊', response.data['results'][0]['product_name'])
def test_ordering(self):
"""测试排序"""
@@ -458,13 +458,13 @@ class PrintingJobAPITestCase(TestCase):
# 按数量升序
response = self.client.get('/api/v1/printing-jobs/?ordering=quantity')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data[0]['quantity'], 100)
self.assertEqual(response.data[1]['quantity'], 200)
self.assertEqual(response.data['results'][0]['quantity'], 100)
self.assertEqual(response.data['results'][1]['quantity'], 200)
# 按数量降序
response = self.client.get('/api/v1/printing-jobs/?ordering=-quantity')
self.assertEqual(response.data[0]['quantity'], 200)
self.assertEqual(response.data[1]['quantity'], 100)
self.assertEqual(response.data['results'][0]['quantity'], 200)
self.assertEqual(response.data['results'][1]['quantity'], 100)
def test_validate_quantity_positive(self):
"""测试数量必须大于0"""
@@ -570,8 +570,8 @@ class PrintingJobAPITestCase(TestCase):
self.assertEqual(response.status_code, status.HTTP_200_OK)
# 验证列表中的状态字段
self.assertIn('status', response.data[0])
self.assertIn('is_completed', response.data[0])
self.assertIn('status', response.data['results'][0])
self.assertIn('is_completed', response.data['results'][0])
def test_job_completion_status(self):
"""测试任务完成状态判断"""

View File

@@ -5,7 +5,6 @@ from rest_framework import viewsets, filters, status
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.permissions import BasePermission
from rest_framework.pagination import LimitOffsetPagination
from rest_framework.permissions import DjangoModelPermissions
from rest_framework.parsers import MultiPartParser, FormParser, JSONParser
from django.db.models import CharField, Prefetch
@@ -15,6 +14,8 @@ from django.utils.decorators import method_decorator
from django_filters.rest_framework import DjangoFilterBackend
from django_filters import rest_framework as django_filters
from django_filters import IsoDateTimeFilter
from flower.viewsets import LimitedModelViewSet
from printing import models
from basic_info.models import MerchantTypeEnum
@@ -83,7 +84,7 @@ class PrintingOrderFilterSet(django_filters.FilterSet):
@method_decorator(cache_page(20), name='list')
class PrintingOrderViewSet(viewsets.ModelViewSet):
class PrintingOrderViewSet(LimitedModelViewSet):
"""
印染订单 ViewSet
@@ -113,7 +114,6 @@ class PrintingOrderViewSet(viewsets.ModelViewSet):
"""
queryset = models.PrintingOrder.objects.all()
permission_classes = [DjangoModelPermissions]
pagination_class = LimitOffsetPagination
filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
filterset_class = PrintingOrderFilterSet
search_fields = ['customer__name', 'fabric', 'area', 'craft', 'description']
@@ -253,7 +253,7 @@ class PrintingJobFilterSet(django_filters.FilterSet):
fields = ['printing_order', 'product']
class PrintingJobViewSet(viewsets.ModelViewSet):
class PrintingJobViewSet(LimitedModelViewSet):
"""
印染款式明细 ViewSet
@@ -288,7 +288,6 @@ class PrintingJobViewSet(viewsets.ModelViewSet):
"""
queryset = models.PrintingJob.objects.all()
permission_classes = [DjangoModelPermissions, IsPrintingFactory]
pagination_class = LimitOffsetPagination
filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
filterset_class = PrintingJobFilterSet
search_fields = ['product__name', 'unit', 'size', 'description']
@@ -558,7 +557,7 @@ class PlateOrderFilterSet(django_filters.FilterSet):
@method_decorator(cache_page(20), name='list')
class PlateOrderViewSet(viewsets.ModelViewSet):
class PlateOrderViewSet(LimitedModelViewSet):
"""
开版订单 ViewSet
@@ -607,7 +606,6 @@ class PlateOrderViewSet(viewsets.ModelViewSet):
queryset = models.PlateOrder.objects.all()
permission_classes = [DjangoModelPermissions]
parser_classes = [MultiPartParser, FormParser, JSONParser] # 支持文件上传
pagination_class = LimitOffsetPagination
filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
filterset_class = PlateOrderFilterSet
# design_code_normalized: 当 design_code 为空时用 id 兜底,便于搜索数字编号

View File

@@ -5,13 +5,14 @@ Products API Views
from rest_framework import viewsets, status
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from rest_framework.pagination import LimitOffsetPagination
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import filters
from flower.viewsets import LimitedGenericViewSet
from basic_info.models import Product
class ProductQuickViewSet(viewsets.GenericViewSet):
class ProductQuickViewSet(LimitedGenericViewSet):
"""
产品快速查询接口
@@ -25,7 +26,6 @@ class ProductQuickViewSet(viewsets.GenericViewSet):
"""
queryset = Product.objects.only('id', 'name', 'image') # 性能优化:只查询需要的字段
permission_classes = [IsAuthenticated]
pagination_class = LimitOffsetPagination
filter_backends = [DjangoFilterBackend, filters.SearchFilter]
search_fields = ['name']

View File

@@ -4,9 +4,10 @@ BusinessObject API ViewSet
from rest_framework import viewsets, filters, status
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.pagination import LimitOffsetPagination
from django_filters.rest_framework import DjangoFilterBackend
from django_filters import rest_framework as django_filters
from flower.viewsets import LimitedModelViewSet
from stateflow import models, services
from stateflow.serializers import (
BusinessObjectListSerializer,
@@ -61,7 +62,7 @@ class BusinessObjectFilterSet(django_filters.FilterSet):
'content_type_str', 'has_content_object']
class BusinessObjectViewSet(viewsets.ModelViewSet):
class BusinessObjectViewSet(LimitedModelViewSet):
"""
业务对象 CRUD 接口
@@ -85,7 +86,6 @@ class BusinessObjectViewSet(viewsets.ModelViewSet):
- ordering: 排序字段
"""
queryset = models.BusinessObject.objects.all()
pagination_class = LimitOffsetPagination
filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
filterset_class = BusinessObjectFilterSet
search_fields = ['name', 'description']

View File

@@ -4,9 +4,10 @@ Process API ViewSet
from rest_framework import viewsets, filters
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.pagination import LimitOffsetPagination
from django_filters.rest_framework import DjangoFilterBackend
from django.db.models import Count
from flower.viewsets import LimitedModelViewSet
from stateflow import models
from stateflow.serializers import (
ProcessListSerializer,
@@ -16,7 +17,7 @@ from stateflow.serializers import (
)
class ProcessViewSet(viewsets.ModelViewSet):
class ProcessViewSet(LimitedModelViewSet):
"""
流程 CRUD 接口
@@ -32,7 +33,6 @@ class ProcessViewSet(viewsets.ModelViewSet):
- search: 全文搜索(名称和描述)
- ordering: 排序字段,支持 id, name, node_count, created_at, updated_at
"""
pagination_class = LimitOffsetPagination
filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
filterset_fields = ['name']
search_fields = ['name', 'description']

View File

@@ -4,8 +4,9 @@ State API ViewSet
from rest_framework import viewsets, filters
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.pagination import LimitOffsetPagination
from django_filters.rest_framework import DjangoFilterBackend
from flower.viewsets import LimitedModelViewSet
from stateflow import models, services
from stateflow.serializers import (
StateListSerializer,
@@ -15,7 +16,7 @@ from stateflow.serializers import (
)
class StateViewSet(viewsets.ModelViewSet):
class StateViewSet(LimitedModelViewSet):
"""
状态节点 CRUD 接口
@@ -32,7 +33,6 @@ class StateViewSet(viewsets.ModelViewSet):
- ordering: 排序字段,支持 id, name, created_at, updated_at
"""
queryset = models.State.objects.all()
pagination_class = LimitOffsetPagination
filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
filterset_fields = ['name']
search_fields = ['name', 'description']

View File

@@ -1,8 +1,9 @@
from rest_framework.generics import ListAPIView
from rest_framework.pagination import LimitOffsetPagination
from rest_framework import filters, serializers
from django_filters.rest_framework import DjangoFilterBackend
from django_filters import rest_framework as django_filters
from flower.viewsets import LimitedLimitOffsetPagination
from stock import models
@@ -81,7 +82,7 @@ class StockSnapshotListView(ListAPIView):
- ordering: 排序字段
"""
serializer_class = StockSnapshotSerializer
pagination_class = LimitOffsetPagination
pagination_class = LimitedLimitOffsetPagination
filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
filterset_class = StockSnapshotFilterSet
search_fields = ['product__name', 'product__code', 'warehouse__name']

View File

@@ -70,10 +70,10 @@ class StateParameterAPITestCase(TestCase):
response = self.client.get('/api/v1/parameters/')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data), 4)
self.assertEqual(response.data['count'], 4)
# 验证返回的数据结构
for item in response.data:
for item in response.data['results']:
self.assertIn('id', item)
self.assertIn('key', item)
self.assertIn('value', item)
@@ -181,24 +181,24 @@ class StateParameterAPITestCase(TestCase):
response = self.client.get('/api/v1/parameters/?search=颜色')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data), 1)
self.assertEqual(response.data[0]['key'], 'color')
self.assertEqual(response.data['count'], 1)
self.assertEqual(response.data['results'][0]['key'], 'color')
def test_search_parameters_by_key(self):
"""测试按 key 搜索工艺参数"""
response = self.client.get('/api/v1/parameters/?search=size')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data), 1)
self.assertEqual(response.data[0]['key'], 'size')
self.assertEqual(response.data['count'], 1)
self.assertEqual(response.data['results'][0]['key'], 'size')
def test_filter_required_parameters(self):
"""测试筛选必填参数"""
response = self.client.get('/api/v1/parameters/?is_required=true')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data), 2) # color 和 logo_image
for item in response.data:
self.assertEqual(response.data['count'], 2) # color 和 logo_image
for item in response.data['results']:
self.assertTrue(item['is_required'])
def test_filter_optional_parameters(self):
@@ -206,8 +206,8 @@ class StateParameterAPITestCase(TestCase):
response = self.client.get('/api/v1/parameters/?is_required=false')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data), 2) # size 和 material
for item in response.data:
self.assertEqual(response.data['count'], 2) # size 和 material
for item in response.data['results']:
self.assertFalse(item['is_required'])
def test_filter_image_path_parameters(self):
@@ -215,9 +215,9 @@ class StateParameterAPITestCase(TestCase):
response = self.client.get('/api/v1/parameters/?is_image_path=true')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data), 1)
self.assertEqual(response.data[0]['key'], 'logo_image')
self.assertTrue(response.data[0]['is_image_path'])
self.assertEqual(response.data['count'], 1)
self.assertEqual(response.data['results'][0]['key'], 'logo_image')
self.assertTrue(response.data['results'][0]['is_image_path'])
def test_get_required_parameters_action(self):
"""测试获取所有必填参数的自定义 action"""

View File

@@ -7,11 +7,12 @@ from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from rest_framework.parsers import MultiPartParser, FormParser
from flower.viewsets import LimitedGenericViewSet
from api_v1.models import UploadedFile
from api_v1.serializers import UploadedFileSerializer, FileUploadSerializer
class UploadFileViewSet(viewsets.GenericViewSet,
class UploadFileViewSet(LimitedGenericViewSet,
viewsets.mixins.CreateModelMixin,
viewsets.mixins.RetrieveModelMixin,
viewsets.mixins.DestroyModelMixin):

View File

@@ -2,9 +2,10 @@ from django.contrib.auth.models import User
from rest_framework.decorators import permission_classes
from rest_framework.permissions import IsAuthenticated, DjangoModelPermissions
from rest_framework.response import Response
from rest_framework.pagination import LimitOffsetPagination
from rest_framework import status, serializers
from rest_framework.generics import GenericAPIView
from flower.viewsets import LimitedLimitOffsetPagination
from basic_info.models import UserProfile
@@ -51,7 +52,7 @@ class CreateUserWithProfileView(GenericAPIView):
"""创建用户和关联的用户资料信息视图"""
queryset = User.objects.all()
permission_classes = [IsAuthenticated, DjangoModelPermissions]
pagination_class = LimitOffsetPagination
pagination_class = LimitedLimitOffsetPagination
def post(self, request):
"""