forked from erp-dev/erp
feat: app verion && some field modify (printing & shipment)
This commit is contained in:
247
api_v1/views/basic_info.py
Normal file
247
api_v1/views/basic_info.py
Normal file
@@ -0,0 +1,247 @@
|
||||
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)
|
||||
Reference in New Issue
Block a user