from django.db import transaction from django.db.models import Q from django.utils import timezone from rest_framework import serializers from rest_framework.exceptions import PermissionDenied, ValidationError from rest_framework import filters from rest_framework.response import Response from flower.viewsets import LimitedModelViewSet from basic_info import models as basic_models from basic_info.services import CustomerVisibilityService def _parse_bool(value: str | None) -> bool | None: if value is None: return None normalized = value.strip().lower() if normalized in {"1", "true", "yes", "y"}: return True if normalized in {"0", "false", "no", "n"}: return False return None class CustomerAddressSerializer(serializers.ModelSerializer): merchant_name = serializers.CharField(source="merchant.name", read_only=True) customer_name = serializers.CharField(source="customer.name", read_only=True) created_by_name = serializers.CharField(source="created_by.name", read_only=True, allow_null=True) deleted_by_name = serializers.CharField(source="deleted_by.name", read_only=True, allow_null=True) class Meta: model = basic_models.CustomerAddress fields = [ "id", "merchant", "merchant_name", "customer", "customer_name", "address", "contact_name", "contact_phone", "area", "coordinates", "is_default", "remark", "extra", "created_by", "created_by_name", "deleted_at", "deleted_by", "deleted_by_name", "created_at", "updated_at", ] read_only_fields = [ "id", "merchant", "merchant_name", "customer_name", "created_by", "created_by_name", "deleted_at", "deleted_by", "deleted_by_name", "created_at", "updated_at", ] def validate_customer(self, customer): request = self.context["request"] view = self.context["view"] if self.instance is not None and customer.id != self.instance.customer_id: raise serializers.ValidationError("不允许修改客户") if not view.can_access_customer(customer, request.user): raise serializers.ValidationError("客户不存在或不可见") return customer class CustomerAddressViewSet(LimitedModelViewSet): """ 客户地址 CRUD。 查询参数: - customer: 客户ID - customer_name: 客户名称模糊查询 - address: 地址模糊查询 - contact_name: 联系人模糊查询 - contact_phone: 联系电话模糊查询 - area: 地区模糊查询 - is_default: 是否默认地址 true/false - include_deleted: 是否包含软删除记录 true/false - only_deleted: 是否仅查询软删除记录 true/false - search: 客户名/地址/联系人/电话/地区/备注模糊搜索 - ordering: id/-id/created_at/-created_at/updated_at/-updated_at/is_default/-is_default """ queryset = basic_models.CustomerAddress.objects.all() serializer_class = CustomerAddressSerializer filter_backends = [filters.OrderingFilter] ordering_fields = ["id", "created_at", "updated_at", "is_default"] ordering = ["-is_default", "-created_at", "-id"] def get_employee(self): return getattr(self.request.user, "employee", None) def can_view_all_customers(self, user) -> bool: return user.is_superuser or user.has_perm("basic_info.view_all_customers") def can_access_customer(self, customer, user) -> bool: if user.is_superuser: return True emp = getattr(user, "employee", None) if emp is None or emp.merchant_id != customer.merchant_id: return False if user.has_perm("basic_info.view_all_customers"): return True return CustomerVisibilityService.is_customer_visible_to_employee(customer, user) def get_queryset(self): queryset = ( super() .get_queryset() .select_related("merchant", "customer", "created_by", "deleted_by") ) user = self.request.user if not user.is_superuser: emp = self.get_employee() if emp is None or emp.merchant_id is None: return queryset.none() queryset = queryset.filter(merchant=emp.merchant) if not user.has_perm("basic_info.view_all_customers"): customer_queryset = CustomerVisibilityService.filter_customers_for_employee( basic_models.Customer.objects.filter(merchant=emp.merchant), user, ) queryset = queryset.filter(customer__in=customer_queryset) only_deleted = _parse_bool(self.request.query_params.get("only_deleted")) include_deleted = _parse_bool(self.request.query_params.get("include_deleted")) if only_deleted: queryset = queryset.filter(deleted_at__isnull=False) elif not include_deleted: queryset = queryset.filter(deleted_at__isnull=True) customer = self.request.query_params.get("customer") if customer: if not customer.strip().isdigit(): return queryset.none() queryset = queryset.filter(customer_id=customer) customer_name = (self.request.query_params.get("customer_name") or "").strip() if customer_name: queryset = queryset.filter(customer__name__icontains=customer_name) address = (self.request.query_params.get("address") or "").strip() if address: queryset = queryset.filter(address__icontains=address) contact_name = (self.request.query_params.get("contact_name") or "").strip() if contact_name: queryset = queryset.filter(contact_name__icontains=contact_name) contact_phone = (self.request.query_params.get("contact_phone") or "").strip() if contact_phone: queryset = queryset.filter(contact_phone__icontains=contact_phone) area = (self.request.query_params.get("area") or "").strip() if area: queryset = queryset.filter(area__icontains=area) is_default = _parse_bool(self.request.query_params.get("is_default")) if is_default is not None: queryset = queryset.filter(is_default=is_default) search = (self.request.query_params.get("search") or "").strip() if search: queryset = queryset.filter( Q(customer__name__icontains=search) | Q(address__icontains=search) | Q(contact_name__icontains=search) | Q(contact_phone__icontains=search) | Q(area__icontains=search) | Q(remark__icontains=search) ) return queryset.distinct() def _unset_other_default_addresses(self, address: basic_models.CustomerAddress): if not address.is_default or address.deleted_at is not None: return basic_models.CustomerAddress.objects.filter( merchant=address.merchant, customer=address.customer, deleted_at__isnull=True, is_default=True, ).exclude(id=address.id).update(is_default=False) @transaction.atomic def perform_create(self, serializer): customer = serializer.validated_data["customer"] emp = self.get_employee() if not self.request.user.is_superuser and emp is None: raise PermissionDenied("当前用户未绑定员工") address = serializer.save( merchant=customer.merchant, created_by=emp, ) self._unset_other_default_addresses(address) @transaction.atomic def perform_update(self, serializer): address = serializer.save() self._unset_other_default_addresses(address) @transaction.atomic def perform_destroy(self, instance): if instance.deleted_at is not None: return emp = self.get_employee() if not self.request.user.is_superuser and emp is None: raise PermissionDenied("当前用户未绑定员工") instance.deleted_at = timezone.now() instance.deleted_by = emp instance.is_default = False instance.save(update_fields=["deleted_at", "deleted_by", "is_default", "updated_at"]) @transaction.atomic def set_default(self, request, pk: int): address = self.get_object() if address.deleted_at is not None: raise ValidationError("已删除的客户地址不能设为默认地址") address.is_default = True address.save(update_fields=["is_default", "updated_at"]) self._unset_other_default_addresses(address) serializer = self.get_serializer(address) return Response(serializer.data)