""" Printing API Mixins 提供客户可见性过滤等通用功能 """ from django.db.models import Q class CustomerVisibilityFilterMixin: """ 基于客户可见性的查询过滤 Mixin 适用于关联了 Customer 的模型(PlateOrder, PrintingOrder, PrintingJob) 使用方式: 1. 在 ViewSet 中继承此 Mixin(放在 LimitedModelViewSet 之前) 2. 设置 customer_field 指定关联 customer 的字段路径 3. 设置 view_all_permission 指定突破限制的权限名 可见性规则: - superuser: 无限制 - 有 view_all_permission 权限: 无限制 - 订单.customer 为空: 全员可见(同 merchant) - 订单.customer 不为空: 按客户绑定关系判断 - customer.created_by == 当前员工 → 可见 - 当前员工 in customer.visible_employees → 可见 """ # 子类需要指定:通过哪个字段关联到 customer customer_field = 'customer' # PlateOrder/PrintingOrder 直接关联 # customer_field = 'printing_order__customer' # PrintingJob 间接关联 # 子类需要指定:突破限制的权限名(完整格式如 'printing.view_all_plateorders') view_all_permission = None def can_bypass_customer_visibility(self) -> bool: """ 是否可以突破客户可见性限制 注意:view_all_customers 权限不影响此判断 """ user = self.request.user if user.is_superuser: return True # 仅检查订单级别的专属权限 if self.view_all_permission and user.has_perm(self.view_all_permission): return True return False def filter_by_customer_visibility(self, queryset): """ 应用客户可见性过滤 Returns: 过滤后的 queryset """ if self.can_bypass_customer_visibility(): return queryset user = self.request.user emp = getattr(user, 'employee', None) if emp is None: return queryset.none() # 可见的客户条件: # 1. customer.created_by == 当前员工 # 2. 当前员工 in customer.visible_employees visible_customer_filter = ( Q(**{f'{self.customer_field}__created_by': emp}) | Q(**{f'{self.customer_field}__visible_employees': emp}) ) # customer 为空时全员可见(同 merchant 下) no_customer_filter = Q(**{f'{self.customer_field}__isnull': True}) return queryset.filter(visible_customer_filter | no_customer_filter).distinct() def filter_by_merchant(self, queryset): """ 应用 merchant 隔离过滤 Returns: 过滤后的 queryset,如果用户没有关联 merchant 则返回空 """ user = self.request.user if user.is_superuser: return queryset emp = getattr(user, 'employee', None) if emp is None or emp.merchant is None: return queryset.none() return queryset.filter(merchant=emp.merchant) def get_queryset(self): """ 重写 get_queryset,应用 merchant 隔离和客户可见性过滤 """ queryset = super().get_queryset() # 1. merchant 隔离(必须) queryset = self.filter_by_merchant(queryset) # 2. 客户可见性过滤 queryset = self.filter_by_customer_visibility(queryset) return queryset