1
0
forked from erp-dev/erp

fix: added permission for plate_order and printing_order api

This commit is contained in:
2026-01-14 18:14:22 +08:00
parent fae667c965
commit cae0f8434e
17 changed files with 867 additions and 15 deletions

View File

@@ -3,6 +3,6 @@ Shipment API 模块
提供出货单和销售品相关的 API 接口
"""
from .views import SalesItemByPrintingOrderView
from .views import SalesItemByPrintingOrderView, ShipmentCreateView
__all__ = ['SalesItemByPrintingOrderView']
__all__ = ['SalesItemByPrintingOrderView', 'ShipmentCreateView']

View File

@@ -3,6 +3,57 @@ Shipment API 序列化器
"""
from rest_framework import serializers
from shipment.models import Shipment
class ShipmentSerializer(serializers.ModelSerializer):
"""
出货单序列化器(只读,用于返回数据)
"""
customer_name = serializers.CharField(source='customer.name', read_only=True)
created_by_id = serializers.IntegerField(source='created_by.id', read_only=True, allow_null=True)
created_by_name = serializers.SerializerMethodField()
items_count = serializers.SerializerMethodField()
class Meta:
model = Shipment
fields = [
'id', 'customer', 'customer_name', 'shipment_date', 'remark',
'items_count', 'created_by_id', 'created_by_name',
'created_at', 'updated_at'
]
read_only_fields = ['id', 'created_at', 'updated_at']
def get_created_by_name(self, obj):
if obj.created_by:
employee = getattr(obj.created_by, 'employee', None)
if employee:
return employee.name
return obj.created_by.username
return None
def get_items_count(self, obj):
return obj.items.count()
class ShipmentCreateSerializer(serializers.Serializer):
"""
出货单创建序列化器
"""
customer = serializers.IntegerField(help_text='客户ID')
shipment_date = serializers.DateField(help_text='出货日期')
remark = serializers.CharField(required=False, default='', allow_blank=True, help_text='备注')
sales_items = serializers.ListField(
child=serializers.IntegerField(),
required=False,
default=list,
help_text='要关联的销售品ID列表'
)
def validate_sales_items(self, value):
# 去重
return list(set(value)) if value else []
class SalesItemSerializer(serializers.Serializer):
"""

View File

@@ -264,3 +264,165 @@ class SalesItemByPrintingOrderAPITestCase(TestCase):
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
class ShipmentCreateAPITestCase(TestCase):
"""测试创建出货单 API"""
def setUp(self):
self.client = APIClient()
# 创建商户
self.merchant = basic_models.Merchant.objects.create(
name='测试印花厂',
type=basic_models.MerchantTypeEnum.FACTORY
)
# 创建用户
self.user = User.objects.create_user(
username='testuser',
password='testpass123',
email='test@example.com'
)
# 创建员工并关联商户
self.employee = basic_models.Employee.objects.create(
sys_user=self.user,
merchant=self.merchant,
name='测试员工',
mobile='13800138000',
status=basic_models.EmployeeStatusEnum.ACTIVE
)
# 创建客户
self.customer = basic_models.Customer.objects.create(
merchant=self.merchant,
name='测试客户',
mobile='13900139000',
area='测试地区'
)
# 创建销售品(未关联出货单)
self.sales_item1 = shipment_models.SalesItem.objects.create(
name='销售品1',
quantity=Decimal('50.00'),
unit=shipment_models.UnitChoices.METER,
created_by=self.user,
)
self.sales_item2 = shipment_models.SalesItem.objects.create(
name='销售品2',
quantity=Decimal('30.00'),
unit=shipment_models.UnitChoices.METER,
created_by=self.user,
)
# 创建已关联出货单的销售品
self.existing_shipment = shipment_models.Shipment.objects.create(
customer=self.customer,
shipment_date='2026-01-13',
created_by=self.user,
)
self.sales_item_shipped = shipment_models.SalesItem.objects.create(
name='销售品3已出货',
quantity=Decimal('100.00'),
unit=shipment_models.UnitChoices.METER,
shipment=self.existing_shipment,
created_by=self.user,
)
# 认证用户
self.client.force_authenticate(user=self.user)
def test_create_shipment_success(self):
"""测试成功创建出货单"""
data = {
'customer': self.customer.id,
'shipment_date': '2026-01-14',
'remark': '测试备注',
'sales_items': [self.sales_item1.id, self.sales_item2.id]
}
response = self.client.post('/api/v1/shipment/shipments/', data, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
result = response.json()
# 验证返回数据
self.assertIn('id', result)
self.assertEqual(result['customer'], self.customer.id)
self.assertEqual(result['customer_name'], self.customer.name)
self.assertEqual(result['shipment_date'], '2026-01-14')
self.assertEqual(result['remark'], '测试备注')
self.assertEqual(result['items_count'], 2)
self.assertEqual(result['created_by_id'], self.user.id)
# 验证销售品已关联到出货单
self.sales_item1.refresh_from_db()
self.sales_item2.refresh_from_db()
self.assertEqual(self.sales_item1.shipment_id, result['id'])
self.assertEqual(self.sales_item2.shipment_id, result['id'])
def test_create_shipment_without_sales_items(self):
"""测试创建出货单但不关联销售品"""
data = {
'customer': self.customer.id,
'shipment_date': '2026-01-14',
}
response = self.client.post('/api/v1/shipment/shipments/', data, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
result = response.json()
self.assertEqual(result['items_count'], 0)
def test_create_shipment_customer_not_found(self):
"""测试客户不存在"""
data = {
'customer': 99999,
'shipment_date': '2026-01-14',
}
response = self.client.post('/api/v1/shipment/shipments/', data, format='json')
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertIn('不存在', response.json()['detail'])
def test_create_shipment_sales_item_not_found(self):
"""测试销售品不存在"""
data = {
'customer': self.customer.id,
'shipment_date': '2026-01-14',
'sales_items': [99999]
}
response = self.client.post('/api/v1/shipment/shipments/', data, format='json')
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertIn('不存在', response.json()['detail'])
def test_create_shipment_sales_item_already_shipped(self):
"""测试销售品已关联到其他出货单"""
data = {
'customer': self.customer.id,
'shipment_date': '2026-01-14',
'sales_items': [self.sales_item_shipped.id]
}
response = self.client.post('/api/v1/shipment/shipments/', data, format='json')
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertIn('已关联', response.json()['detail'])
def test_create_shipment_unauthenticated(self):
"""测试未认证用户"""
self.client.logout()
data = {
'customer': self.customer.id,
'shipment_date': '2026-01-14',
}
response = self.client.post('/api/v1/shipment/shipments/', data, format='json')
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)

View File

@@ -6,7 +6,63 @@ from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from .serializers import SalesItemSerializer
from .serializers import SalesItemSerializer, ShipmentSerializer, ShipmentCreateSerializer
class ShipmentCreateView(APIView):
"""
创建出货单
POST /api/v1/shipment/shipments/
请求体:
{
"customer": 1,
"shipment_date": "2026-01-14",
"remark": "备注信息(可选)",
"sales_items": [1, 2, 3]
}
返回:
{
"id": 1,
"customer": 1,
"customer_name": "客户A",
"shipment_date": "2026-01-14",
"remark": "备注信息",
"items_count": 3,
"created_by_id": 1,
"created_by_name": "张三",
"created_at": "2026-01-14T10:00:00Z",
"updated_at": "2026-01-14T10:00:00Z"
}
"""
permission_classes = [IsAuthenticated]
def post(self, request):
# 验证请求数据
serializer = ShipmentCreateSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
data = serializer.validated_data
# 调用业务逻辑
from shipment.services import create_shipment
try:
shipment = create_shipment(
customer_id=data['customer'],
shipment_date=data['shipment_date'],
sales_item_ids=data['sales_items'],
created_by=request.user,
remark=data.get('remark', ''),
)
except ValueError as e:
return Response({'detail': str(e)}, status=status.HTTP_400_BAD_REQUEST)
# 返回创建的出货单
response_serializer = ShipmentSerializer(shipment)
return Response(response_serializer.data, status=status.HTTP_201_CREATED)
class SalesItemByPrintingOrderView(APIView):