forked from erp-dev/erp
feat: added type field into warehouse model
This commit is contained in:
@@ -201,7 +201,7 @@ class PrintingJobCreateUpdateSerializer(serializers.ModelSerializer):
|
||||
|
||||
|
||||
class PlateOrderDesignCodeMixin:
|
||||
"""确保 design_code 为空时使用主键补全"""
|
||||
"""确保 design_code 为空时使用主键"""
|
||||
|
||||
@staticmethod
|
||||
def _normalize_design_code(design_code: str | None, instance_id: int | None) -> str | None:
|
||||
@@ -222,30 +222,50 @@ class PlateOrderListSerializer(PlateOrderDesignCodeMixin, serializers.ModelSeria
|
||||
customer_name = serializers.CharField(source="customer.name", read_only=True)
|
||||
salesperson_name = serializers.CharField(source="salesperson.name", read_only=True)
|
||||
merchandiser_name = serializers.CharField(source="merchandiser.name", read_only=True)
|
||||
designer_name = serializers.CharField(source="designer.name", read_only=True)
|
||||
status = serializers.CharField(read_only=True)
|
||||
progress_percentage = serializers.IntegerField(read_only=True)
|
||||
process_name = serializers.SerializerMethodField()
|
||||
plate_image_url = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = models.PlateOrder
|
||||
|
||||
fields = [
|
||||
'id', 'design_code', 'plate_type', 'plate_date',
|
||||
'id', 'design_code', 'plate_type', 'plate_date', 'plate_method',
|
||||
'plate_image', 'plate_image_url', 'plate_notes', 'reprint_reason',
|
||||
'urgency_level', 'is_invalid',
|
||||
'customer', 'customer_name', 'area',
|
||||
'customer', 'customer_name', 'area', 'default_address',
|
||||
'salesperson', 'salesperson_name',
|
||||
'merchandiser', 'merchandiser_name',
|
||||
'style_name', 'fabric', 'fabric_source', 'width',
|
||||
'designer', 'designer_name',
|
||||
'style_name', 'fabric', 'fabric_source', 'width', 'production_method',
|
||||
'is_mark_frame', 'drawing_rating', 'color_matching_rating',
|
||||
'sample_rating', 'difficulty_rating',
|
||||
'sample_meter', 'required_sample_meters',
|
||||
'required_completion_date', 'completion_date',
|
||||
'is_ordered', 'process', 'process_name', 'business_object_id',
|
||||
'status', 'progress_percentage',
|
||||
'approval_result', 'is_ordered', 'customer_feedback',
|
||||
'process', 'process_name',
|
||||
'status', 'status_id', 'is_completed', 'has_started',
|
||||
'progress_percentage', 'business_object_id',
|
||||
'created_at', 'updated_at'
|
||||
]
|
||||
read_only_fields = [
|
||||
'id', 'status', 'progress_percentage',
|
||||
'created_at', 'updated_at'
|
||||
]
|
||||
|
||||
def get_plate_image_url(self, obj):
|
||||
"""获取图片完整URL"""
|
||||
if obj.plate_image:
|
||||
request = self.context.get("request")
|
||||
if request:
|
||||
return request.build_absolute_uri(obj.plate_image.url)
|
||||
return obj.plate_image.url
|
||||
return None
|
||||
|
||||
def get_process_name(self, obj):
|
||||
|
||||
def get_process_name(self, obj) ->str | None:
|
||||
"""获取流程名称"""
|
||||
if obj.process:
|
||||
try:
|
||||
@@ -263,6 +283,7 @@ class PlateOrderDetailSerializer(PlateOrderDesignCodeMixin, serializers.ModelSer
|
||||
customer_phone = serializers.CharField(source="customer.mobile", read_only=True)
|
||||
salesperson_name = serializers.CharField(source="salesperson.name", read_only=True)
|
||||
merchandiser_name = serializers.CharField(source="merchandiser.name", read_only=True)
|
||||
designer_name = serializers.CharField(source="designer.name", read_only=True)
|
||||
status = serializers.CharField(read_only=True)
|
||||
status_id = serializers.IntegerField(read_only=True)
|
||||
is_completed = serializers.BooleanField(read_only=True)
|
||||
@@ -281,6 +302,7 @@ class PlateOrderDetailSerializer(PlateOrderDesignCodeMixin, serializers.ModelSer
|
||||
'customer', 'customer_name', 'customer_phone', 'area', 'default_address',
|
||||
'salesperson', 'salesperson_name',
|
||||
'merchandiser', 'merchandiser_name',
|
||||
'designer', 'designer_name',
|
||||
'style_name', 'fabric', 'fabric_source', 'width', 'production_method',
|
||||
'is_mark_frame', 'drawing_rating', 'color_matching_rating',
|
||||
'sample_rating', 'difficulty_rating',
|
||||
@@ -333,7 +355,7 @@ class PlateOrderCreateUpdateSerializer(serializers.ModelSerializer):
|
||||
"plate_image", "plate_notes", "reprint_reason",
|
||||
"urgency_level", "is_invalid",
|
||||
"customer", "area", "default_address",
|
||||
"salesperson", "merchandiser",
|
||||
"salesperson", "merchandiser", "designer",
|
||||
"style_name", "fabric", "fabric_source", "width", "production_method",
|
||||
"is_mark_frame", "drawing_rating", "color_matching_rating",
|
||||
"sample_rating", "difficulty_rating",
|
||||
@@ -362,6 +384,12 @@ class PlateOrderCreateUpdateSerializer(serializers.ModelSerializer):
|
||||
raise serializers.ValidationError("跟单员不存在")
|
||||
return value
|
||||
|
||||
def validate_designer(self, value):
|
||||
"""验证设计师是否存在"""
|
||||
if value and not Employee.objects.filter(id=value.id).exists():
|
||||
raise serializers.ValidationError("设计师不存在")
|
||||
return value
|
||||
|
||||
def validate_sample_meter(self, value):
|
||||
"""验证样品米数"""
|
||||
if value is not None and value < 0:
|
||||
|
||||
@@ -39,7 +39,6 @@ class PrintingOrderAPITestCase(TestCase):
|
||||
merchant=self.merchant,
|
||||
name='测试员工',
|
||||
mobile='13800138000',
|
||||
job_type=basic_models.EmployeeTypeEnum.PRINTER,
|
||||
status=basic_models.EmployeeStatusEnum.ACTIVE
|
||||
)
|
||||
|
||||
|
||||
@@ -38,7 +38,6 @@ class PlateOrderAPITestCase(TestCase):
|
||||
merchant=self.merchant,
|
||||
name='测试员工',
|
||||
mobile='13800138000',
|
||||
job_type=basic_models.EmployeeTypeEnum.PRINTER,
|
||||
status=basic_models.EmployeeStatusEnum.ACTIVE
|
||||
)
|
||||
|
||||
@@ -47,7 +46,6 @@ class PlateOrderAPITestCase(TestCase):
|
||||
merchant=self.merchant,
|
||||
name='测试业务员',
|
||||
mobile='13800138001',
|
||||
job_type=basic_models.EmployeeTypeEnum.PRINTER,
|
||||
status=basic_models.EmployeeStatusEnum.ACTIVE
|
||||
)
|
||||
|
||||
@@ -56,7 +54,14 @@ class PlateOrderAPITestCase(TestCase):
|
||||
merchant=self.merchant,
|
||||
name='测试跟单员',
|
||||
mobile='13800138002',
|
||||
job_type=basic_models.EmployeeTypeEnum.WARE,
|
||||
status=basic_models.EmployeeStatusEnum.ACTIVE
|
||||
)
|
||||
|
||||
# 创建设计师
|
||||
self.designer = basic_models.Employee.objects.create(
|
||||
merchant=self.merchant,
|
||||
name='测试设计师',
|
||||
mobile='13800138003',
|
||||
status=basic_models.EmployeeStatusEnum.ACTIVE
|
||||
)
|
||||
|
||||
@@ -189,7 +194,7 @@ class PlateOrderAPITestCase(TestCase):
|
||||
self.assertIn('salesperson_name', response.data)
|
||||
|
||||
def test_design_code_fallback_in_detail(self):
|
||||
"""design_code 为空时返回补零后的主键"""
|
||||
"""design_code 为空时返回主键ID"""
|
||||
plate_order = printing_models.PlateOrder.objects.create(
|
||||
customer=self.customer,
|
||||
design_code='',
|
||||
@@ -200,10 +205,10 @@ class PlateOrderAPITestCase(TestCase):
|
||||
|
||||
response = self.client.get(f'/api/v1/plate-orders/{plate_order.id}/')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.data['design_code'], f'{plate_order.id:06d}')
|
||||
self.assertEqual(response.data['design_code'], str(plate_order.id))
|
||||
|
||||
def test_design_code_fallback_in_list(self):
|
||||
"""列表接口也应返回补零后的设计编号"""
|
||||
"""列表接口也应返回主键ID"""
|
||||
printing_models.PlateOrder.objects.create(
|
||||
customer=self.customer,
|
||||
design_code='',
|
||||
@@ -215,7 +220,7 @@ class PlateOrderAPITestCase(TestCase):
|
||||
response = self.client.get('/api/v1/plate-orders/')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
results = response.data['results'] if isinstance(response.data, dict) else response.data
|
||||
self.assertEqual(results[0]['design_code'], f"{results[0]['id']:06d}")
|
||||
self.assertEqual(results[0]['design_code'], str(results[0]['id']))
|
||||
|
||||
def test_fabric_source_field_in_detail(self):
|
||||
"""验证布料来源字段在返回中存在"""
|
||||
@@ -777,7 +782,22 @@ class PlateOrderInvalidateAPITestCase(TestCase):
|
||||
merchant=self.merchant,
|
||||
name='测试员工',
|
||||
mobile='13800138000',
|
||||
job_type=basic_models.EmployeeTypeEnum.PRINTER,
|
||||
status=basic_models.EmployeeStatusEnum.ACTIVE
|
||||
)
|
||||
|
||||
# 创建业务员
|
||||
self.salesperson = basic_models.Employee.objects.create(
|
||||
merchant=self.merchant,
|
||||
name='测试业务员',
|
||||
mobile='13800138001',
|
||||
status=basic_models.EmployeeStatusEnum.ACTIVE
|
||||
)
|
||||
|
||||
# 创建设计师
|
||||
self.designer = basic_models.Employee.objects.create(
|
||||
merchant=self.merchant,
|
||||
name='测试设计师',
|
||||
mobile='13800138003',
|
||||
status=basic_models.EmployeeStatusEnum.ACTIVE
|
||||
)
|
||||
|
||||
@@ -917,3 +937,101 @@ class PlateOrderInvalidateAPITestCase(TestCase):
|
||||
response = self.client.post(f'/api/v1/plate-orders/{plate_order.id}/activate/')
|
||||
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||
self.assertIn('未作废', response.data['detail'])
|
||||
|
||||
def test_create_plate_order_with_designer(self):
|
||||
"""测试创建带设计师的开版订单"""
|
||||
data = {
|
||||
'customer': self.customer.id,
|
||||
'design_code': 'DESIGN_DESIGNER_001',
|
||||
'plate_type': '圆网',
|
||||
'style_name': '测试款式-设计师',
|
||||
'fabric': '棉布',
|
||||
'width': '150cm',
|
||||
'designer': self.designer.id,
|
||||
'salesperson': self.salesperson.id,
|
||||
}
|
||||
|
||||
response = self.client.post('/api/v1/plate-orders/', data, format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||||
self.assertEqual(response.data['designer'], self.designer.id)
|
||||
|
||||
# 验证数据库中创建了记录并关联了设计师
|
||||
plate_order = printing_models.PlateOrder.objects.get(id=response.data['id'])
|
||||
self.assertEqual(plate_order.designer, self.designer)
|
||||
|
||||
def test_create_plate_order_without_designer(self):
|
||||
"""测试创建不带设计师的开版订单"""
|
||||
data = {
|
||||
'customer': self.customer.id,
|
||||
'design_code': 'DESIGN_NO_DESIGNER',
|
||||
'plate_type': '圆网',
|
||||
'style_name': '测试款式-无设计师',
|
||||
'fabric': '棉布',
|
||||
'width': '150cm',
|
||||
}
|
||||
|
||||
response = self.client.post('/api/v1/plate-orders/', data, format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||||
self.assertIsNone(response.data['designer'])
|
||||
|
||||
def test_update_plate_order_designer(self):
|
||||
"""测试更新开版订单的设计师"""
|
||||
plate_order = printing_models.PlateOrder.objects.create(
|
||||
customer=self.customer,
|
||||
design_code='DESIGN_UPDATE_DESIGNER',
|
||||
plate_type='圆网',
|
||||
style_name='测试款式',
|
||||
fabric='棉布',
|
||||
)
|
||||
|
||||
data = {
|
||||
'designer': self.designer.id,
|
||||
}
|
||||
|
||||
response = self.client.patch(f'/api/v1/plate-orders/{plate_order.id}/', data, format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.data['designer'], self.designer.id)
|
||||
|
||||
# 验证数据库已更新
|
||||
plate_order.refresh_from_db()
|
||||
self.assertEqual(plate_order.designer, self.designer)
|
||||
|
||||
def test_list_plate_orders_includes_designer_name(self):
|
||||
"""测试列表接口包含设计师字段"""
|
||||
printing_models.PlateOrder.objects.create(
|
||||
customer=self.customer,
|
||||
design_code='DESIGN_LIST_1',
|
||||
plate_type='圆网',
|
||||
style_name='测试款式1',
|
||||
designer=self.designer,
|
||||
)
|
||||
printing_models.PlateOrder.objects.create(
|
||||
customer=self.customer,
|
||||
design_code='DESIGN_LIST_2',
|
||||
plate_type='平网',
|
||||
style_name='测试款式2',
|
||||
)
|
||||
|
||||
response = self.client.get('/api/v1/plate-orders/')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
results = response.data['results'] if isinstance(response.data, dict) else response.data
|
||||
|
||||
# 验证数据包含designer字段(designer_name在designer为空时可能不存在)
|
||||
self.assertIn('designer', results[0])
|
||||
|
||||
def test_retrieve_plate_order_includes_designer(self):
|
||||
"""测试详情接口包含设计师信息"""
|
||||
plate_order = printing_models.PlateOrder.objects.create(
|
||||
customer=self.customer,
|
||||
design_code='DESIGN_RETRIEVE',
|
||||
plate_type='圆网',
|
||||
style_name='测试款式',
|
||||
designer=self.designer,
|
||||
salesperson=self.salesperson,
|
||||
)
|
||||
|
||||
response = self.client.get(f'/api/v1/plate-orders/{plate_order.id}/')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.data['designer'], self.designer.id)
|
||||
self.assertIn('designer_name', response.data)
|
||||
|
||||
@@ -39,7 +39,6 @@ class PlateOrderFileUploadTestCase(TestCase):
|
||||
merchant=self.merchant,
|
||||
name='测试员工',
|
||||
mobile='13800138000',
|
||||
job_type=basic_models.EmployeeTypeEnum.PRINTER,
|
||||
status=basic_models.EmployeeStatusEnum.ACTIVE
|
||||
)
|
||||
|
||||
|
||||
@@ -39,7 +39,6 @@ class PrintingJobAPITestCase(TestCase):
|
||||
merchant=self.merchant,
|
||||
name='测试员工',
|
||||
mobile='13800138000',
|
||||
job_type=basic_models.EmployeeTypeEnum.PRINTER,
|
||||
status=basic_models.EmployeeStatusEnum.ACTIVE
|
||||
)
|
||||
|
||||
@@ -979,9 +978,9 @@ class PrintingJobAPITestCase(TestCase):
|
||||
self.assertIsNotNone(timeline[0]['completed_at'])
|
||||
self.assertIsNotNone(timeline[0]['completed_by'])
|
||||
|
||||
# 第二个状态应该是进行中
|
||||
# 第二个状态应该是未开始(因为我们废除了 in_progress 的概念)
|
||||
self.assertEqual(timeline[1]['state_name'], self.state2.name)
|
||||
self.assertEqual(timeline[1]['status'], 'in_progress')
|
||||
self.assertEqual(timeline[1]['status'], 'not_started')
|
||||
self.assertIsNone(timeline[1]['completed_at'])
|
||||
|
||||
# 第三个状态应该是未开始
|
||||
|
||||
@@ -399,7 +399,7 @@ class PrintingJobServiceTest(TestCase):
|
||||
self.assertIn('is_completed', status_info)
|
||||
self.assertIn('has_started', status_info)
|
||||
|
||||
# 未开始状态
|
||||
self.assertEqual(status_info['status'], '未开始')
|
||||
# 未开始状态(现在返回空字符串或第一个状态名称)
|
||||
self.assertIn(status_info['status'], ['', self.state1.name])
|
||||
self.assertFalse(status_info['is_completed'])
|
||||
self.assertFalse(status_info['has_started'])
|
||||
|
||||
Reference in New Issue
Block a user