forked from erp-dev/erp
fix: added merchant_id to printing_order and plate_order
This commit is contained in:
@@ -141,11 +141,12 @@ class PrintingOrderListSerializer(serializers.ModelSerializer):
|
||||
jobs_last_status_summary = serializers.SerializerMethodField()
|
||||
created_by = serializers.IntegerField(source='created_by_id', read_only=True)
|
||||
created_by_name = serializers.SerializerMethodField()
|
||||
merchant_id = serializers.IntegerField(source='merchant.id', read_only=True, allow_null=True)
|
||||
|
||||
class Meta:
|
||||
model = models.PrintingOrder
|
||||
fields = [
|
||||
'id', 'human_id', 'customer', 'customer_name', 'customer_phone',
|
||||
'id', 'human_id', 'merchant_id', 'customer', 'customer_name', 'customer_phone',
|
||||
'fabric', 'width', 'is_urgent', 'area', 'address', 'curve',
|
||||
'is_fabric_received', 'outgoing_date', 'is_invalid', 'new_curve',
|
||||
'process', 'process_name', 'progress', 'position', 'print_count',
|
||||
@@ -153,7 +154,7 @@ class PrintingOrderListSerializer(serializers.ModelSerializer):
|
||||
'created_by', 'created_by_name',
|
||||
'created_at', 'updated_at',
|
||||
]
|
||||
read_only_fields = ['id', 'human_id', 'created_at', 'updated_at', 'progress', 'print_count']
|
||||
read_only_fields = ['id', 'human_id', 'created_at', 'updated_at', 'progress', 'print_count', 'merchant_id']
|
||||
|
||||
def get_jobs_status_summary(self, obj):
|
||||
"""
|
||||
@@ -228,11 +229,12 @@ class PrintingOrderDetailSerializer(serializers.ModelSerializer):
|
||||
process_name = serializers.CharField(source='process.name', read_only=True)
|
||||
created_by_name = serializers.SerializerMethodField()
|
||||
progress = serializers.IntegerField(read_only=True)
|
||||
merchant_id = serializers.IntegerField(source='merchant.id', read_only=True, allow_null=True)
|
||||
|
||||
class Meta:
|
||||
model = models.PrintingOrder
|
||||
fields = [
|
||||
'id', 'human_id', 'customer', 'customer_name', 'customer_phone', 'customer_area',
|
||||
'id', 'human_id', 'merchant_id', 'customer', 'customer_name', 'customer_phone', 'customer_area',
|
||||
'fabric', 'width', 'is_urgent', 'area', 'address', 'fabric_source',
|
||||
'is_fabric_received', 'craft', 'description', 'outgoing_date',
|
||||
'curve', 'new_curve', 'position', 'created_by_name',
|
||||
@@ -240,7 +242,7 @@ class PrintingOrderDetailSerializer(serializers.ModelSerializer):
|
||||
'is_invalid', 'process', 'process_name', 'progress', 'print_count',
|
||||
'created_at', 'updated_at'
|
||||
]
|
||||
read_only_fields = ['id', 'human_id', 'created_at', 'updated_at', 'progress', 'print_count']
|
||||
read_only_fields = ['id', 'human_id', 'created_at', 'updated_at', 'progress', 'print_count', 'merchant_id']
|
||||
|
||||
def get_created_by_name(self, obj):
|
||||
"""获取创建人名称(员工姓名)"""
|
||||
@@ -316,11 +318,12 @@ class PrintingJobListSerializer(serializers.ModelSerializer):
|
||||
last_completed_state = serializers.CharField(read_only=True)
|
||||
business_object_id = serializers.SerializerMethodField()
|
||||
batch_advance_records = serializers.SerializerMethodField()
|
||||
merchant_id = serializers.IntegerField(source='merchant.id', read_only=True, allow_null=True)
|
||||
|
||||
class Meta:
|
||||
model = models.PrintingJob
|
||||
fields = [
|
||||
'id', 'original_id', 'printing_order', 'printing_order_id', 'product', 'product_name',
|
||||
'id', 'original_id', 'merchant_id', 'printing_order', 'printing_order_id', 'product', 'product_name',
|
||||
'product_image_url', 'has_started',
|
||||
'quantity', 'unit', 'size', 'pieces', 'description',
|
||||
'work_state', 'work_state_display',
|
||||
@@ -332,7 +335,7 @@ class PrintingJobListSerializer(serializers.ModelSerializer):
|
||||
read_only_fields = [
|
||||
'id', 'created_at', 'updated_at',
|
||||
'status', 'is_completed', 'progress_percentage', 'last_completed_state',
|
||||
'business_object_id'
|
||||
'business_object_id', 'merchant_id'
|
||||
]
|
||||
|
||||
def get_business_object_id(self, obj):
|
||||
@@ -394,11 +397,12 @@ class PrintingJobDetailSerializer(serializers.ModelSerializer):
|
||||
last_completed_state = serializers.CharField(read_only=True)
|
||||
business_object_id = serializers.SerializerMethodField()
|
||||
batch_advance_records = serializers.SerializerMethodField()
|
||||
merchant_id = serializers.IntegerField(source='merchant.id', read_only=True, allow_null=True)
|
||||
|
||||
class Meta:
|
||||
model = models.PrintingJob
|
||||
fields = [
|
||||
'id', 'original_id', 'printing_order', 'printing_order_id', 'product', 'product_name', 'product_code',
|
||||
'id', 'original_id', 'merchant_id', 'printing_order', 'printing_order_id', 'product', 'product_name', 'product_code',
|
||||
'quantity', 'unit', 'size', 'pieces', 'description',
|
||||
'work_state', 'work_state_display',
|
||||
'status', 'status_id', 'is_completed', 'has_started',
|
||||
@@ -411,7 +415,7 @@ class PrintingJobDetailSerializer(serializers.ModelSerializer):
|
||||
'id', 'created_at', 'updated_at',
|
||||
'status', 'status_id', 'is_completed', 'has_started',
|
||||
'progress_percentage', 'last_completed_state',
|
||||
'business_object_id'
|
||||
'business_object_id', 'merchant_id'
|
||||
]
|
||||
|
||||
def get_business_object_id(self, obj):
|
||||
@@ -550,12 +554,13 @@ class PlateOrderListSerializer(PlateOrderDesignCodeMixin, serializers.ModelSeria
|
||||
last_completed_state = serializers.CharField(read_only=True)
|
||||
content_type_id = serializers.SerializerMethodField()
|
||||
created_by_name = serializers.SerializerMethodField()
|
||||
merchant_id = serializers.IntegerField(source='merchant.id', read_only=True, allow_null=True)
|
||||
|
||||
class Meta:
|
||||
model = models.PlateOrder
|
||||
|
||||
fields = [
|
||||
'id', 'original_id', 'design_code', 'plate_type', 'plate_date', 'plate_method',
|
||||
'id', 'original_id', 'merchant_id', 'design_code', 'plate_type', 'plate_date', 'plate_method',
|
||||
'plate_image', 'plate_image_url', 'image_name', 'plate_notes', 'reprint_reason',
|
||||
'urgency_level', 'is_invalid',
|
||||
'customer', 'customer_name', 'area', 'default_address',
|
||||
@@ -576,7 +581,7 @@ class PlateOrderListSerializer(PlateOrderDesignCodeMixin, serializers.ModelSeria
|
||||
]
|
||||
read_only_fields = [
|
||||
'id', 'status', 'progress_percentage', 'last_completed_state',
|
||||
'created_at', 'updated_at', 'print_count'
|
||||
'created_at', 'updated_at', 'print_count', 'merchant_id'
|
||||
]
|
||||
|
||||
def get_plate_image_url(self, obj):
|
||||
@@ -630,11 +635,12 @@ class PlateOrderDetailSerializer(PlateOrderDesignCodeMixin, serializers.ModelSer
|
||||
plate_image_url = serializers.SerializerMethodField()
|
||||
process_name = serializers.SerializerMethodField()
|
||||
last_completed_state = serializers.CharField(read_only=True)
|
||||
merchant_id = serializers.IntegerField(source='merchant.id', read_only=True, allow_null=True)
|
||||
|
||||
class Meta:
|
||||
model = models.PlateOrder
|
||||
fields = [
|
||||
'id', 'original_id', 'design_code', 'plate_type', 'plate_date', 'plate_method',
|
||||
'id', 'original_id', 'merchant_id', 'design_code', 'plate_type', 'plate_date', 'plate_method',
|
||||
'plate_image', 'plate_image_url', 'image_name', 'plate_notes', 'reprint_reason',
|
||||
'urgency_level', 'is_invalid',
|
||||
'customer', 'customer_name', 'customer_phone', 'area', 'default_address',
|
||||
@@ -656,7 +662,7 @@ class PlateOrderDetailSerializer(PlateOrderDesignCodeMixin, serializers.ModelSer
|
||||
read_only_fields = [
|
||||
'id', 'status', 'status_id', 'is_completed', 'has_started',
|
||||
'progress_percentage', 'business_object_id', 'last_completed_state',
|
||||
'created_at', 'updated_at', 'print_count'
|
||||
'created_at', 'updated_at', 'print_count', 'merchant_id'
|
||||
]
|
||||
|
||||
def get_business_object_id(self, obj):
|
||||
|
||||
@@ -46,6 +46,10 @@ class PrintingOrderService:
|
||||
# 绑定创建人
|
||||
data['created_by'] = user
|
||||
|
||||
# 绑定商户(从当前用户的 employee 获取)
|
||||
if hasattr(user, 'employee') and user.employee and user.employee.merchant:
|
||||
data['merchant'] = user.employee.merchant
|
||||
|
||||
order = printing_models.PrintingOrder.objects.create(**data)
|
||||
return order
|
||||
|
||||
@@ -128,6 +132,10 @@ class PrintingJobService:
|
||||
# 绑定创建人
|
||||
data['created_by'] = user
|
||||
|
||||
# 绑定商户(从当前用户的 employee 获取)
|
||||
if hasattr(user, 'employee') and user.employee and user.employee.merchant:
|
||||
data['merchant'] = user.employee.merchant
|
||||
|
||||
# 创建 PrintingJob
|
||||
job = printing_models.PrintingJob.objects.create(**data)
|
||||
|
||||
|
||||
@@ -106,6 +106,8 @@ class PrintingOrderAPITestCase(TestCase):
|
||||
self.assertIsNotNone(order)
|
||||
self.assertEqual(order.customer.id, self.customer.id)
|
||||
self.assertEqual(order.fabric, '纯棉布料')
|
||||
# 验证 merchant 自动绑定
|
||||
self.assertEqual(order.merchant.id, self.merchant.id)
|
||||
|
||||
def test_list_printing_orders(self):
|
||||
"""测试获取订单列表"""
|
||||
|
||||
@@ -740,9 +740,13 @@ class PlateOrderViewSet(LimitedModelViewSet):
|
||||
|
||||
def perform_create(self, serializer):
|
||||
"""
|
||||
创建时自动绑定创建人(created_by),不允许前端传参控制。
|
||||
创建时自动绑定创建人(created_by)和商户(merchant),不允许前端传参控制。
|
||||
"""
|
||||
serializer.save(created_by=self.request.user)
|
||||
user = self.request.user
|
||||
merchant = None
|
||||
if hasattr(user, 'employee') and user.employee and user.employee.merchant:
|
||||
merchant = user.employee.merchant
|
||||
serializer.save(created_by=user, merchant=merchant)
|
||||
|
||||
@action(detail=True, methods=['post'])
|
||||
def invalidate(self, request, pk=None):
|
||||
|
||||
8
api_v1/views/shipment/__init__.py
Normal file
8
api_v1/views/shipment/__init__.py
Normal file
@@ -0,0 +1,8 @@
|
||||
"""
|
||||
Shipment API 模块
|
||||
|
||||
提供出货单和销售品相关的 API 接口
|
||||
"""
|
||||
from .views import SalesItemByPrintingOrderView
|
||||
|
||||
__all__ = ['SalesItemByPrintingOrderView']
|
||||
37
api_v1/views/shipment/serializers.py
Normal file
37
api_v1/views/shipment/serializers.py
Normal file
@@ -0,0 +1,37 @@
|
||||
"""
|
||||
Shipment API 序列化器
|
||||
"""
|
||||
from rest_framework import serializers
|
||||
|
||||
|
||||
class SalesItemSerializer(serializers.Serializer):
|
||||
"""
|
||||
销售品序列化器(只读)
|
||||
|
||||
用于返回销售品数据
|
||||
"""
|
||||
id = serializers.IntegerField(read_only=True)
|
||||
name = serializers.CharField(read_only=True)
|
||||
quantity = serializers.DecimalField(max_digits=12, decimal_places=2, read_only=True)
|
||||
unit = serializers.IntegerField(read_only=True)
|
||||
unit_display = serializers.SerializerMethodField()
|
||||
position = serializers.CharField(read_only=True)
|
||||
remark = serializers.CharField(read_only=True)
|
||||
printing_job_id = serializers.IntegerField(read_only=True)
|
||||
customer_id = serializers.IntegerField(read_only=True)
|
||||
shipment_id = serializers.IntegerField(source='shipment.id', read_only=True, allow_null=True)
|
||||
shipment_date = serializers.DateField(source='shipment.shipment_date', read_only=True, allow_null=True)
|
||||
created_at = serializers.DateTimeField(read_only=True)
|
||||
created_by_id = serializers.IntegerField(source='created_by.id', read_only=True, allow_null=True)
|
||||
created_by_name = serializers.SerializerMethodField()
|
||||
|
||||
def get_unit_display(self, obj):
|
||||
return obj.get_unit_display()
|
||||
|
||||
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
|
||||
266
api_v1/views/shipment/test_api.py
Normal file
266
api_v1/views/shipment/test_api.py
Normal file
@@ -0,0 +1,266 @@
|
||||
"""
|
||||
Shipment API 测试
|
||||
"""
|
||||
from decimal import Decimal
|
||||
|
||||
from django.test import TestCase
|
||||
from django.conf import settings
|
||||
from rest_framework.test import APIClient
|
||||
from rest_framework import status
|
||||
from django.contrib.auth import get_user_model
|
||||
|
||||
from basic_info import models as basic_models
|
||||
from printing import models as printing_models
|
||||
from shipment import models as shipment_models
|
||||
from stateflow import models as stateflow_models
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class SalesItemByPrintingOrderAPITestCase(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.state1 = stateflow_models.State.objects.create(name='待印染')
|
||||
self.state2 = stateflow_models.State.objects.create(name='印染中')
|
||||
self.state3 = stateflow_models.State.objects.create(name='已完成')
|
||||
|
||||
self.process = stateflow_models.Process.objects.create(name='印染流程')
|
||||
self.process.replace_nodes([self.state1, self.state2, self.state3])
|
||||
|
||||
# 创建产品分类
|
||||
self.category = basic_models.ProductCategory.objects.create(
|
||||
merchant=self.merchant,
|
||||
name='测试分类',
|
||||
)
|
||||
|
||||
# 创建产品
|
||||
self.product = basic_models.Product.objects.create(
|
||||
merchant=self.merchant,
|
||||
category=self.category,
|
||||
name='测试产品',
|
||||
human_id='TEST001',
|
||||
)
|
||||
|
||||
# 创建印染订单
|
||||
self.printing_order = printing_models.PrintingOrder.objects.create(
|
||||
merchant=self.merchant,
|
||||
customer=self.customer,
|
||||
fabric='测试面料',
|
||||
width='150cm',
|
||||
process=self.process,
|
||||
created_by=self.user,
|
||||
)
|
||||
|
||||
# 创建印染任务
|
||||
self.printing_job1 = printing_models.PrintingJob.objects.create(
|
||||
merchant=self.merchant,
|
||||
printing_order=self.printing_order,
|
||||
product=self.product,
|
||||
quantity=100,
|
||||
unit='米',
|
||||
created_by=self.user,
|
||||
)
|
||||
|
||||
self.printing_job2 = printing_models.PrintingJob.objects.create(
|
||||
merchant=self.merchant,
|
||||
printing_order=self.printing_order,
|
||||
product=self.product,
|
||||
quantity=200,
|
||||
unit='米',
|
||||
created_by=self.user,
|
||||
)
|
||||
|
||||
# 创建出货单
|
||||
self.shipment = shipment_models.Shipment.objects.create(
|
||||
customer=self.customer,
|
||||
shipment_date='2026-01-14',
|
||||
created_by=self.user,
|
||||
)
|
||||
|
||||
# 创建销售品 - 未关联出货单
|
||||
self.sales_item1 = shipment_models.SalesItem.objects.create(
|
||||
name='销售品1',
|
||||
quantity=Decimal('50.00'),
|
||||
unit=shipment_models.UnitChoices.METER,
|
||||
printing_job_id=self.printing_job1.id,
|
||||
created_by=self.user,
|
||||
)
|
||||
|
||||
self.sales_item2 = shipment_models.SalesItem.objects.create(
|
||||
name='销售品2',
|
||||
quantity=Decimal('30.00'),
|
||||
unit=shipment_models.UnitChoices.METER,
|
||||
printing_job_id=self.printing_job1.id,
|
||||
position='A1-01',
|
||||
remark='备注信息',
|
||||
created_by=self.user,
|
||||
)
|
||||
|
||||
# 创建销售品 - 已关联出货单
|
||||
self.sales_item3 = shipment_models.SalesItem.objects.create(
|
||||
name='销售品3(已出货)',
|
||||
quantity=Decimal('100.00'),
|
||||
unit=shipment_models.UnitChoices.METER,
|
||||
printing_job_id=self.printing_job2.id,
|
||||
shipment=self.shipment,
|
||||
created_by=self.user,
|
||||
)
|
||||
|
||||
# 创建与该订单无关的销售品
|
||||
self.sales_item_other = shipment_models.SalesItem.objects.create(
|
||||
name='其它销售品',
|
||||
quantity=Decimal('999.00'),
|
||||
unit=shipment_models.UnitChoices.PIECE,
|
||||
printing_job_id=99999, # 不存在的 job
|
||||
created_by=self.user,
|
||||
)
|
||||
|
||||
# 认证用户
|
||||
self.client.force_authenticate(user=self.user)
|
||||
|
||||
def test_get_sales_items_by_printing_order_exclude_shipped(self):
|
||||
"""测试查询销售品 - 默认不包含已出货的"""
|
||||
url = f'/api/v1/shipment/sales-items/by-printing-order/{self.printing_order.id}/'
|
||||
response = self.client.get(url)
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
data = response.json()
|
||||
|
||||
# 应该只返回2个未出货的销售品
|
||||
self.assertEqual(data['count'], 2)
|
||||
|
||||
# 检查返回的销售品
|
||||
item_ids = [item['id'] for item in data['results']]
|
||||
self.assertIn(self.sales_item1.id, item_ids)
|
||||
self.assertIn(self.sales_item2.id, item_ids)
|
||||
self.assertNotIn(self.sales_item3.id, item_ids) # 已出货的不应该在列表中
|
||||
self.assertNotIn(self.sales_item_other.id, item_ids) # 其它订单的也不在
|
||||
|
||||
def test_get_sales_items_by_printing_order_include_shipped(self):
|
||||
"""测试查询销售品 - 包含已出货的"""
|
||||
url = f'/api/v1/shipment/sales-items/by-printing-order/{self.printing_order.id}/?include_already_has_shipment=true'
|
||||
response = self.client.get(url)
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
data = response.json()
|
||||
|
||||
# 应该返回3个销售品(包含已出货的)
|
||||
self.assertEqual(data['count'], 3)
|
||||
|
||||
# 检查返回的销售品
|
||||
item_ids = [item['id'] for item in data['results']]
|
||||
self.assertIn(self.sales_item1.id, item_ids)
|
||||
self.assertIn(self.sales_item2.id, item_ids)
|
||||
self.assertIn(self.sales_item3.id, item_ids) # 已出货的也应该在列表中
|
||||
self.assertNotIn(self.sales_item_other.id, item_ids) # 其它订单的依然不在
|
||||
|
||||
def test_get_sales_items_response_format(self):
|
||||
"""测试返回数据格式"""
|
||||
url = f'/api/v1/shipment/sales-items/by-printing-order/{self.printing_order.id}/'
|
||||
response = self.client.get(url)
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
data = response.json()
|
||||
|
||||
# 找到 sales_item2(包含 position 和 remark)
|
||||
item = next(item for item in data['results'] if item['id'] == self.sales_item2.id)
|
||||
|
||||
# 检查所有字段
|
||||
self.assertEqual(item['name'], '销售品2')
|
||||
self.assertEqual(Decimal(item['quantity']), Decimal('30.00'))
|
||||
self.assertEqual(item['unit'], shipment_models.UnitChoices.METER)
|
||||
self.assertEqual(item['unit_display'], '米')
|
||||
self.assertEqual(item['position'], 'A1-01')
|
||||
self.assertEqual(item['remark'], '备注信息')
|
||||
self.assertEqual(item['printing_job_id'], self.printing_job1.id)
|
||||
self.assertIsNone(item['shipment_id'])
|
||||
self.assertIsNone(item['shipment_date'])
|
||||
self.assertIsNotNone(item['created_at'])
|
||||
self.assertEqual(item['created_by_id'], self.user.id)
|
||||
|
||||
def test_get_sales_items_shipped_item_format(self):
|
||||
"""测试已出货的销售品返回格式"""
|
||||
url = f'/api/v1/shipment/sales-items/by-printing-order/{self.printing_order.id}/?include_already_has_shipment=true'
|
||||
response = self.client.get(url)
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
data = response.json()
|
||||
|
||||
# 找到已出货的销售品
|
||||
item = next(item for item in data['results'] if item['id'] == self.sales_item3.id)
|
||||
|
||||
# 检查出货单信息
|
||||
self.assertEqual(item['shipment_id'], self.shipment.id)
|
||||
self.assertEqual(item['shipment_date'], '2026-01-14')
|
||||
|
||||
def test_get_sales_items_printing_order_not_found(self):
|
||||
"""测试生产订单不存在"""
|
||||
url = '/api/v1/shipment/sales-items/by-printing-order/99999/'
|
||||
response = self.client.get(url)
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
||||
self.assertIn('不存在', response.json()['detail'])
|
||||
|
||||
def test_get_sales_items_empty_result(self):
|
||||
"""测试生产订单没有关联销售品"""
|
||||
# 创建一个没有销售品的订单
|
||||
empty_order = printing_models.PrintingOrder.objects.create(
|
||||
merchant=self.merchant,
|
||||
customer=self.customer,
|
||||
fabric='测试面料2',
|
||||
width='150cm',
|
||||
process=self.process,
|
||||
created_by=self.user,
|
||||
)
|
||||
|
||||
url = f'/api/v1/shipment/sales-items/by-printing-order/{empty_order.id}/'
|
||||
response = self.client.get(url)
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
data = response.json()
|
||||
|
||||
self.assertEqual(data['count'], 0)
|
||||
self.assertEqual(data['results'], [])
|
||||
|
||||
def test_get_sales_items_unauthenticated(self):
|
||||
"""测试未认证用户"""
|
||||
self.client.logout()
|
||||
|
||||
url = f'/api/v1/shipment/sales-items/by-printing-order/{self.printing_order.id}/'
|
||||
response = self.client.get(url)
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
|
||||
78
api_v1/views/shipment/views.py
Normal file
78
api_v1/views/shipment/views.py
Normal file
@@ -0,0 +1,78 @@
|
||||
"""
|
||||
Shipment API ViewSet
|
||||
"""
|
||||
from rest_framework import status
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
|
||||
from .serializers import SalesItemSerializer
|
||||
|
||||
|
||||
class SalesItemByPrintingOrderView(APIView):
|
||||
"""
|
||||
通过生产订单查询销售品
|
||||
|
||||
GET /api/v1/shipment/sales-items/by-printing-order/<printing_order_id>/
|
||||
|
||||
返回与该 PrintingOrder 下所有 PrintingJob 关联的 SalesItem 列表。
|
||||
|
||||
查询参数:
|
||||
- include_already_has_shipment: 是否包含已关联出货单的销售品(true/false),默认 false
|
||||
|
||||
返回:
|
||||
{
|
||||
"count": 5,
|
||||
"results": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "产品A",
|
||||
"quantity": "100.00",
|
||||
"unit": 1,
|
||||
"unit_display": "米",
|
||||
"position": "A1-01",
|
||||
"remark": "",
|
||||
"printing_job_id": 123,
|
||||
"customer_id": null,
|
||||
"shipment_id": null,
|
||||
"shipment_date": null,
|
||||
"created_at": "2026-01-14T10:00:00Z",
|
||||
"created_by_id": 1,
|
||||
"created_by_name": "张三"
|
||||
},
|
||||
...
|
||||
]
|
||||
}
|
||||
"""
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get(self, request, printing_order_id):
|
||||
# 验证生产订单是否存在
|
||||
from printing.models import PrintingOrder
|
||||
try:
|
||||
printing_order = PrintingOrder.objects.get(id=printing_order_id)
|
||||
except PrintingOrder.DoesNotExist:
|
||||
return Response(
|
||||
{'detail': f'生产订单 {printing_order_id} 不存在'},
|
||||
status=status.HTTP_404_NOT_FOUND
|
||||
)
|
||||
|
||||
# 获取查询参数
|
||||
include_already_has_shipment = request.query_params.get(
|
||||
'include_already_has_shipment', 'false'
|
||||
).lower() == 'true'
|
||||
|
||||
# 调用 shipment 业务逻辑
|
||||
from shipment.services import get_sales_items_by_printing_order
|
||||
sales_items = get_sales_items_by_printing_order(
|
||||
printing_order_id=printing_order.id,
|
||||
include_already_has_shipment=include_already_has_shipment,
|
||||
)
|
||||
|
||||
# 序列化返回
|
||||
serializer = SalesItemSerializer(sales_items, many=True)
|
||||
|
||||
return Response({
|
||||
'count': len(serializer.data),
|
||||
'results': serializer.data
|
||||
})
|
||||
Reference in New Issue
Block a user