1
0
forked from erp-dev/erp

fix: merchant not required at customer create api

This commit is contained in:
2026-03-13 15:57:40 +08:00
parent a8e9801e15
commit 84dbb2ee10
6 changed files with 267 additions and 2 deletions

View File

@@ -7,6 +7,7 @@ from rest_framework.fields import empty
from api_v1.models import UploadedFile
from api_v1.utils.media import build_public_media_url
from api_v1.views.shipment.serializers import SalesItemSerializer
from printing import models
from .services import PrintingOrderService, PrintingJobService
from basic_info.models import Customer, Employee
@@ -332,6 +333,7 @@ class PrintingJobListSerializer(serializers.ModelSerializer):
last_completed_state = serializers.CharField(read_only=True)
business_object_id = serializers.SerializerMethodField()
batch_advance_records = serializers.SerializerMethodField()
saleitems = serializers.SerializerMethodField()
merchant_id = serializers.IntegerField(source='merchant.id', read_only=True, allow_null=True)
class Meta:
@@ -344,6 +346,7 @@ class PrintingJobListSerializer(serializers.ModelSerializer):
'status', 'is_completed', 'progress_percentage', 'last_completed_state',
'business_object_id',
'batch_advance_records',
'saleitems',
'created_at', 'updated_at'
]
read_only_fields = [
@@ -396,6 +399,17 @@ class PrintingJobListSerializer(serializers.ModelSerializer):
records = list(obj.batch_advance_records.all())
return PrintingJobBatchAdvanceRecordSerializer(records, many=True).data
def get_saleitems(self, obj):
items = getattr(obj, '_saleitems_cache', None)
if items is None:
from shipment.models import SalesItem
items = list(
SalesItem.objects.select_related('shipment', 'created_by')
.filter(printing_job_id=obj.id)
.order_by('id')
)
return SalesItemSerializer(items, many=True).data
class PrintingJobDetailSerializer(serializers.ModelSerializer):
"""印染款式明细详情序列化器"""
@@ -411,6 +425,7 @@ class PrintingJobDetailSerializer(serializers.ModelSerializer):
last_completed_state = serializers.CharField(read_only=True)
business_object_id = serializers.SerializerMethodField()
batch_advance_records = serializers.SerializerMethodField()
saleitems = serializers.SerializerMethodField()
merchant_id = serializers.IntegerField(source='merchant.id', read_only=True, allow_null=True)
class Meta:
@@ -423,6 +438,7 @@ class PrintingJobDetailSerializer(serializers.ModelSerializer):
'progress_percentage', 'last_completed_state',
'business_object_id',
'batch_advance_records',
'saleitems',
'created_at', 'updated_at'
]
read_only_fields = [
@@ -444,6 +460,17 @@ class PrintingJobDetailSerializer(serializers.ModelSerializer):
records = list(obj.batch_advance_records.all())
return PrintingJobBatchAdvanceRecordSerializer(records, many=True).data
def get_saleitems(self, obj):
items = getattr(obj, '_saleitems_cache', None)
if items is None:
from shipment.models import SalesItem
items = list(
SalesItem.objects.select_related('shipment', 'created_by')
.filter(printing_job_id=obj.id)
.order_by('id')
)
return SalesItemSerializer(items, many=True).data
class PrintingJobCreateUpdateSerializer(serializers.ModelSerializer):
"""印染款式明细创建/更新序列化器"""

View File

@@ -10,6 +10,7 @@ from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
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()
@@ -228,6 +229,91 @@ class PrintingJobAPITestCase(TestCase):
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertIn('batch_advance_records', response.data)
self.assertEqual(len(response.data['batch_advance_records']), 1)
def test_list_printing_jobs_includes_saleitems(self):
"""测试 list 返回包含关联的 shipment.SalesItem 数组"""
job1 = printing_models.PrintingJob.objects.create(
printing_order=self.printing_order,
product=self.product,
quantity=100,
unit='',
size='50*60',
pieces=10
)
job2 = printing_models.PrintingJob.objects.create(
printing_order=self.printing_order,
product=self.product,
quantity=200,
unit='',
size='60*70',
pieces=20
)
item1 = shipment_models.SalesItem.objects.create(
merchant=self.merchant,
name='销售品A',
quantity='88.50',
unit=shipment_models.UnitChoices.METER,
created_by=self.user,
printing_job_id=job1.id,
customer_id=self.customer.id,
position='A1-01',
remark='备注A',
)
item2 = shipment_models.SalesItem.objects.create(
merchant=self.merchant,
name='销售品B',
quantity='12.00',
unit=shipment_models.UnitChoices.PIECE,
created_by=self.user,
printing_job_id=job1.id,
customer_id=self.customer.id,
position='A1-02',
remark='备注B',
)
response = self.client.get(f'/api/v1/printing-jobs/?printing_order={self.printing_order.id}')
self.assertEqual(response.status_code, status.HTTP_200_OK)
data_by_id = {item['id']: item for item in response.data['results']}
self.assertIn('saleitems', data_by_id[job1.id])
self.assertEqual(len(data_by_id[job1.id]['saleitems']), 2)
self.assertEqual([item['id'] for item in data_by_id[job1.id]['saleitems']], [item1.id, item2.id])
self.assertEqual(data_by_id[job1.id]['saleitems'][0]['printing_job_id'], job1.id)
self.assertEqual(data_by_id[job1.id]['saleitems'][0]['name'], '销售品A')
self.assertIn('saleitems', data_by_id[job2.id])
self.assertEqual(data_by_id[job2.id]['saleitems'], [])
def test_retrieve_printing_job_includes_saleitems(self):
"""测试 detail 返回包含关联的 shipment.SalesItem 数组"""
job = printing_models.PrintingJob.objects.create(
printing_order=self.printing_order,
product=self.product,
quantity=100,
unit='',
size='50*60',
pieces=10
)
shipment_models.SalesItem.objects.create(
merchant=self.merchant,
name='详情销售品',
quantity='66.00',
unit=shipment_models.UnitChoices.METER,
created_by=self.user,
printing_job_id=job.id,
customer_id=self.customer.id,
position='B2-01',
remark='详情备注',
)
response = self.client.get(f'/api/v1/printing-jobs/{job.id}/')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertIn('saleitems', response.data)
self.assertEqual(len(response.data['saleitems']), 1)
self.assertEqual(response.data['saleitems'][0]['printing_job_id'], job.id)
self.assertEqual(response.data['saleitems'][0]['name'], '详情销售品')
def test_update_printing_job(self):
"""测试更新款式明细"""

View File

@@ -426,7 +426,48 @@ class PrintingJobViewSet(CustomerVisibilityFilterMixin, LimitedModelViewSet):
)
)
return queryset
@staticmethod
def _attach_saleitems_cache(jobs):
if not jobs:
return
from shipment.models import SalesItem
job_ids = [job.id for job in jobs]
saleitems = list(
SalesItem.objects.select_related('shipment', 'created_by')
.filter(printing_job_id__in=job_ids)
.order_by('id')
)
items_by_job_id = {job_id: [] for job_id in job_ids}
for item in saleitems:
items_by_job_id.setdefault(item.printing_job_id, []).append(item)
for job in jobs:
job._saleitems_cache = items_by_job_id.get(job.id, [])
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
self._attach_saleitems_cache(page)
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
jobs = list(queryset)
self._attach_saleitems_cache(jobs)
serializer = self.get_serializer(jobs, many=True)
return Response(serializer.data)
def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
self._attach_saleitems_cache([instance])
serializer = self.get_serializer(instance)
return Response(serializer.data)
def destroy(self, request, *args, **kwargs):
"""禁用删除操作"""
return Response(