forked from erp-dev/erp
feat: added print_count api, added merchant setting model, added manual mode setting for purchase order
This commit is contained in:
@@ -2,9 +2,99 @@
|
||||
Printing API 序列化器
|
||||
"""
|
||||
from rest_framework import serializers
|
||||
|
||||
from api_v1.models import UploadedFile
|
||||
from printing import models
|
||||
from .services import PrintingOrderService, PrintingJobService
|
||||
from basic_info.models import Customer, Employee
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
def _build_absolute_media_url(url: str | None, request):
|
||||
if not url:
|
||||
return None
|
||||
if isinstance(url, str) and url.startswith(('http://', 'https://')):
|
||||
return url
|
||||
if not isinstance(url, str):
|
||||
return None
|
||||
if request:
|
||||
if url.startswith('/'):
|
||||
return request.build_absolute_uri(url)
|
||||
media_prefix = (settings.MEDIA_URL or '/media/').rstrip('/')
|
||||
return request.build_absolute_uri(f'{media_prefix}/{url.lstrip("/")}')
|
||||
return url
|
||||
|
||||
|
||||
def _serialize_plate_images(raw_value, request):
|
||||
if not raw_value:
|
||||
return []
|
||||
serialized = []
|
||||
if isinstance(raw_value, list):
|
||||
iterable = raw_value
|
||||
elif isinstance(raw_value, dict):
|
||||
iterable = [raw_value]
|
||||
elif isinstance(raw_value, str):
|
||||
iterable = [{'url': raw_value}]
|
||||
else:
|
||||
iterable = []
|
||||
|
||||
for entry in iterable:
|
||||
if isinstance(entry, str):
|
||||
data = {'url': entry}
|
||||
elif isinstance(entry, dict):
|
||||
data = dict(entry)
|
||||
else:
|
||||
continue
|
||||
url = data.get('url') or data.get('path')
|
||||
data['url'] = _build_absolute_media_url(url, request)
|
||||
if 'path' not in data and isinstance(url, str):
|
||||
data['path'] = url
|
||||
serialized.append(data)
|
||||
return serialized
|
||||
|
||||
|
||||
def _build_plate_image_payload(items, request_user):
|
||||
if items is None:
|
||||
return None
|
||||
if not items:
|
||||
return []
|
||||
file_ids = [item['file_id'] for item in items if item.get('file_id') is not None]
|
||||
if not file_ids:
|
||||
return []
|
||||
|
||||
queryset = UploadedFile.objects.filter(id__in=file_ids, is_deleted=False)
|
||||
if request_user and request_user.is_authenticated:
|
||||
queryset = queryset.filter(owner=request_user)
|
||||
|
||||
files_map = {file.id: file for file in queryset}
|
||||
missing = [str(fid) for fid in file_ids if fid not in files_map]
|
||||
if missing:
|
||||
raise serializers.ValidationError({'plate_image': f'以下文件不存在或已删除: {", ".join(missing)}'})
|
||||
|
||||
payload = []
|
||||
for item in items:
|
||||
file = files_map[item['file_id']]
|
||||
name = item.get('name') or file.original_filename or file.path.name
|
||||
payload.append({
|
||||
'file_id': file.id,
|
||||
'name': name,
|
||||
'path': file.path.name,
|
||||
'url': file.file_url,
|
||||
'size': file.file_size,
|
||||
'content_type': file.content_type,
|
||||
'uploaded_at': file.created_at.isoformat(),
|
||||
})
|
||||
return payload
|
||||
|
||||
|
||||
class PlateImageInputSerializer(serializers.Serializer):
|
||||
file_id = serializers.IntegerField(min_value=1, help_text='上传文件的 ID')
|
||||
name = serializers.CharField(
|
||||
required=False,
|
||||
allow_blank=True,
|
||||
allow_null=True,
|
||||
help_text='可选的图片名称,默认使用文件原始名称'
|
||||
)
|
||||
|
||||
|
||||
class PrintingOrderListSerializer(serializers.ModelSerializer):
|
||||
@@ -20,10 +110,10 @@ class PrintingOrderListSerializer(serializers.ModelSerializer):
|
||||
'id', 'human_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',
|
||||
'process', 'process_name', 'progress', 'position', 'print_count',
|
||||
'created_at', 'updated_at',
|
||||
]
|
||||
read_only_fields = ['id', 'human_id', 'created_at', 'updated_at', 'progress']
|
||||
read_only_fields = ['id', 'human_id', 'created_at', 'updated_at', 'progress', 'print_count']
|
||||
|
||||
|
||||
class PrintingOrderDetailSerializer(serializers.ModelSerializer):
|
||||
@@ -42,10 +132,10 @@ class PrintingOrderDetailSerializer(serializers.ModelSerializer):
|
||||
'is_fabric_received', 'craft', 'description', 'outgoing_date',
|
||||
'curve', 'new_curve', 'position',
|
||||
'printing_warn', 'rolling_warn', 'production_warn',
|
||||
'is_invalid', 'process', 'process_name', 'progress',
|
||||
'is_invalid', 'process', 'process_name', 'progress', 'print_count',
|
||||
'created_at', 'updated_at'
|
||||
]
|
||||
read_only_fields = ['id', 'human_id', 'created_at', 'updated_at', 'progress']
|
||||
read_only_fields = ['id', 'human_id', 'created_at', 'updated_at', 'progress', 'print_count']
|
||||
|
||||
|
||||
class PrintingOrderCreateUpdateSerializer(serializers.ModelSerializer):
|
||||
@@ -214,6 +304,7 @@ class PlateOrderDesignCodeMixin:
|
||||
def to_representation(self, instance):
|
||||
data = super().to_representation(instance)
|
||||
data['design_code'] = self._normalize_design_code(data.get('design_code'), instance.id)
|
||||
data['plate_image'] = _serialize_plate_images(getattr(instance, 'plate_image', None), self.context.get('request'))
|
||||
return data
|
||||
|
||||
|
||||
@@ -244,7 +335,7 @@ class PlateOrderListSerializer(PlateOrderDesignCodeMixin, serializers.ModelSeria
|
||||
'sample_rating', 'difficulty_rating',
|
||||
'sample_meter', 'required_sample_meters',
|
||||
'required_completion_date', 'completion_date',
|
||||
'approval_result', 'is_ordered', 'customer_feedback',
|
||||
'approval_result', 'is_ordered', 'customer_feedback', 'print_count',
|
||||
'process', 'process_name',
|
||||
'status', 'status_id', 'is_completed', 'has_started',
|
||||
'progress_percentage', 'business_object_id',
|
||||
@@ -252,17 +343,12 @@ class PlateOrderListSerializer(PlateOrderDesignCodeMixin, serializers.ModelSeria
|
||||
]
|
||||
read_only_fields = [
|
||||
'id', 'status', 'progress_percentage',
|
||||
'created_at', 'updated_at'
|
||||
'created_at', 'updated_at', 'print_count'
|
||||
]
|
||||
|
||||
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
|
||||
images = _serialize_plate_images(getattr(obj, 'plate_image', None), self.context.get('request'))
|
||||
return [entry.get('url') for entry in images if entry.get('url')]
|
||||
|
||||
|
||||
def get_process_name(self, obj) ->str | None:
|
||||
@@ -308,7 +394,7 @@ class PlateOrderDetailSerializer(PlateOrderDesignCodeMixin, serializers.ModelSer
|
||||
'sample_rating', 'difficulty_rating',
|
||||
'sample_meter', 'required_sample_meters',
|
||||
'required_completion_date', 'completion_date',
|
||||
'approval_result', 'is_ordered', 'customer_feedback',
|
||||
'approval_result', 'is_ordered', 'customer_feedback', 'print_count',
|
||||
'process', 'process_name',
|
||||
'status', 'status_id', 'is_completed', 'has_started',
|
||||
'progress_percentage', 'business_object_id',
|
||||
@@ -317,7 +403,7 @@ class PlateOrderDetailSerializer(PlateOrderDesignCodeMixin, serializers.ModelSer
|
||||
read_only_fields = [
|
||||
'id', 'status', 'status_id', 'is_completed', 'has_started',
|
||||
'progress_percentage', 'business_object_id',
|
||||
'created_at', 'updated_at'
|
||||
'created_at', 'updated_at', 'print_count'
|
||||
]
|
||||
|
||||
def get_business_object_id(self, obj):
|
||||
@@ -325,13 +411,8 @@ class PlateOrderDetailSerializer(PlateOrderDesignCodeMixin, serializers.ModelSer
|
||||
return obj.business_object.id if obj.business_object else None
|
||||
|
||||
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
|
||||
images = _serialize_plate_images(getattr(obj, 'plate_image', None), self.context.get('request'))
|
||||
return [entry.get('url') for entry in images if entry.get('url')]
|
||||
|
||||
def get_process_name(self, obj):
|
||||
"""获取流程名称"""
|
||||
@@ -347,7 +428,13 @@ class PlateOrderDetailSerializer(PlateOrderDesignCodeMixin, serializers.ModelSer
|
||||
|
||||
class PlateOrderCreateUpdateSerializer(serializers.ModelSerializer):
|
||||
"""开版订单创建/更新序列化器"""
|
||||
|
||||
plate_image = PlateImageInputSerializer(
|
||||
many=True,
|
||||
required=False,
|
||||
allow_null=True,
|
||||
help_text="开版图片列表,需提供已上传的 file_id,可选 name 字段"
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = models.PlateOrder
|
||||
fields = [
|
||||
@@ -365,7 +452,10 @@ class PlateOrderCreateUpdateSerializer(serializers.ModelSerializer):
|
||||
"process"
|
||||
]
|
||||
read_only_fields = ["id"]
|
||||
|
||||
|
||||
def validate_plate_image(self, value):
|
||||
return value or []
|
||||
|
||||
def validate_customer(self, value):
|
||||
"""验证客户是否存在"""
|
||||
if not value:
|
||||
@@ -415,18 +505,18 @@ class PlateOrderCreateUpdateSerializer(serializers.ModelSerializer):
|
||||
return attrs
|
||||
|
||||
def create(self, validated_data):
|
||||
"""创建开版订单"""
|
||||
user = self.context["request"].user
|
||||
|
||||
# 创建 PlateOrder,save 方法会自动创建 BusinessObject
|
||||
plate_order = models.PlateOrder.objects.create(**validated_data)
|
||||
|
||||
return plate_order
|
||||
plate_images = validated_data.pop('plate_image', None)
|
||||
if plate_images is not None:
|
||||
validated_data['plate_image'] = _build_plate_image_payload(plate_images, self._request_user)
|
||||
return super().create(validated_data)
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
"""更新开版订单"""
|
||||
# 直接更新字段,save 方法会自动处理 BusinessObject 的创建
|
||||
for attr, value in validated_data.items():
|
||||
setattr(instance, attr, value)
|
||||
instance.save()
|
||||
return instance
|
||||
plate_images = validated_data.pop('plate_image', None)
|
||||
if plate_images is not None:
|
||||
validated_data['plate_image'] = _build_plate_image_payload(plate_images, self._request_user)
|
||||
return super().update(instance, validated_data)
|
||||
|
||||
@property
|
||||
def _request_user(self):
|
||||
request = self.context.get('request')
|
||||
return getattr(request, 'user', None)
|
||||
|
||||
Reference in New Issue
Block a user