forked from erp-dev/erp
193 lines
6.2 KiB
Python
193 lines
6.2 KiB
Python
from rest_framework import serializers
|
||
from basic_info import models as basic_models
|
||
from django.contrib.auth.models import User
|
||
import logging
|
||
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
|
||
class BaseSerializer(serializers.ModelSerializer):
|
||
merchant = serializers.PrimaryKeyRelatedField(
|
||
queryset=basic_models.Merchant.objects.all(),
|
||
required=False # 创建时由视图层设置
|
||
)
|
||
|
||
def to_representation(self, instance):
|
||
# 检查是否有 request context,以及是否需要进行权限验证
|
||
request = self.context.get('request')
|
||
|
||
if request and hasattr(request, 'user') and hasattr(request.user, 'employee'):
|
||
try:
|
||
merchant = request.user.employee.merchant
|
||
if instance.merchant != merchant:
|
||
# 数据保护手段
|
||
logger.warning(f"用户 {request.user.username} 无权限访问对象 {type(instance).__name__} {instance.id}")
|
||
raise PermissionError("无权限访问该对象")
|
||
except AttributeError as e:
|
||
# 用户没有 employee 属性
|
||
logger.warning(f"用户权限验证失败: {str(e)}")
|
||
raise PermissionError("无权限访问该对象")
|
||
|
||
result = super().to_representation(instance)
|
||
if self.context.get('expand_merchant', False):
|
||
result['merchant'] = {
|
||
'id': instance.merchant.id,
|
||
'name': instance.merchant.name
|
||
}
|
||
return result
|
||
|
||
|
||
class QuickInputSerializer(serializers.ModelSerializer):
|
||
class Meta:
|
||
model = basic_models.QuickInput
|
||
fields = ['id', 'name', 'value', 'group']
|
||
|
||
|
||
class ProductCategorySerializer(BaseSerializer):
|
||
class Meta:
|
||
model = basic_models.ProductCategory
|
||
fields = '__all__'
|
||
|
||
|
||
class ProductSerializer(BaseSerializer):
|
||
# 图片字段:读取时返回完整 URL,写入时接受文件上传或 URL
|
||
image = serializers.ImageField(required=False, allow_null=True)
|
||
image_url = serializers.SerializerMethodField(read_only=True)
|
||
|
||
class Meta:
|
||
model = basic_models.Product
|
||
fields = '__all__'
|
||
|
||
def get_image_url(self, obj):
|
||
"""
|
||
获取图片的完整 URL
|
||
|
||
返回:
|
||
- 如果有图片:返回完整 URL(七牛云 CDN 地址)
|
||
- 如果没有图片:返回 None
|
||
"""
|
||
primary_url_resolver = getattr(obj, 'get_primary_image_url', None)
|
||
if callable(primary_url_resolver):
|
||
resolved = primary_url_resolver()
|
||
if resolved:
|
||
return resolved
|
||
|
||
if obj.image:
|
||
request = self.context.get('request')
|
||
if request:
|
||
# 使用 request.build_absolute_uri 构建完整 URL
|
||
return request.build_absolute_uri(obj.image.url)
|
||
else:
|
||
# 没有 request context 时,返回相对 URL
|
||
# 七牛云存储会自动返回完整 URL
|
||
return obj.image.url
|
||
return None
|
||
|
||
def to_representation(self, instance):
|
||
result = super().to_representation(instance)
|
||
result['category'] = {
|
||
'id': instance.category.id,
|
||
'name': instance.category.name
|
||
}
|
||
|
||
# 如果使用七牛云,image 字段已经是完整 URL,添加额外的 image_url 方便前端使用
|
||
# 前端可以使用 image 或 image_url,两者内容相同
|
||
return result
|
||
|
||
|
||
class WareHouseSerializer(BaseSerializer):
|
||
class Meta:
|
||
model = basic_models.WareHouse
|
||
fields = '__all__'
|
||
|
||
|
||
class SupplierSerializer(BaseSerializer):
|
||
class Meta:
|
||
model = basic_models.Supplier
|
||
fields = '__all__'
|
||
|
||
|
||
class EmployeeSerializer(BaseSerializer):
|
||
job_type = serializers.CharField(read_only=True)
|
||
|
||
class Meta:
|
||
model = basic_models.Employee
|
||
fields = '__all__'
|
||
|
||
|
||
class EmployeeTypeSerializer(BaseSerializer):
|
||
def __init__(self, *args, **kwargs):
|
||
super().__init__(*args, **kwargs)
|
||
# 移除 unique_together 验证器中对 merchant 的要求
|
||
# 因为 merchant 会在 perform_create 中自动设置
|
||
for validator in self.validators:
|
||
if hasattr(validator, 'fields') and 'merchant' in validator.fields:
|
||
validator.fields = tuple(f for f in validator.fields if f != 'merchant')
|
||
|
||
class Meta:
|
||
model = basic_models.EmployeeType
|
||
fields = '__all__'
|
||
|
||
|
||
class CustomerSerializer(BaseSerializer):
|
||
created_by = serializers.PrimaryKeyRelatedField(
|
||
queryset=basic_models.Employee.objects.all(),
|
||
required=False,
|
||
)
|
||
|
||
class Meta:
|
||
model = basic_models.Customer
|
||
fields = '__all__'
|
||
|
||
|
||
class VehicleTypeSerializer(BaseSerializer):
|
||
class Meta:
|
||
model = basic_models.VehicleType
|
||
fields = '__all__'
|
||
|
||
|
||
class BankAccountSerializer(BaseSerializer):
|
||
class Meta:
|
||
model = basic_models.BankAccount
|
||
fields = '__all__'
|
||
|
||
|
||
class DeviceInfoSerializer(BaseSerializer):
|
||
class Meta:
|
||
model = basic_models.DeviceInfo
|
||
fields = '__all__'
|
||
|
||
|
||
class VehicleTransportRecordSerializer(BaseSerializer):
|
||
vehicle_type_name = serializers.CharField(source='vehicle_type.name', read_only=True)
|
||
# 显式定义 vehicle_type 字段,避免 depth=1 影响反序列化
|
||
vehicle_type = serializers.PrimaryKeyRelatedField(
|
||
queryset=basic_models.VehicleType.objects.all()
|
||
)
|
||
|
||
class Meta:
|
||
model = basic_models.VehicleTransportRecord
|
||
fields = '__all__'
|
||
depth = 1 # 展开外键关系(仅影响序列化输出)
|
||
|
||
|
||
class UserSerializerSimple(serializers.ModelSerializer):
|
||
class Meta:
|
||
model = basic_models.User
|
||
fields = ['id', 'username', 'email', 'is_active', 'is_superuser', 'last_login']
|
||
|
||
|
||
class UserProfileSerializer(BaseSerializer):
|
||
user = serializers.PrimaryKeyRelatedField(
|
||
queryset=User.objects.all()
|
||
)
|
||
user_detail = UserSerializerSimple(source='user', read_only=True)
|
||
|
||
class Meta:
|
||
model = basic_models.UserProfile
|
||
fields = ['id', 'user', 'user_detail', 'merchant', 'description', 'created_at', 'updated_at']
|
||
extra_kwargs = {
|
||
'merchant': {'required': False} # 创建时由视图层设置
|
||
}
|