From 147b5804d23a86bab451c0175453f06a8bc33415 Mon Sep 17 00:00:00 2001 From: colaftc Date: Thu, 25 Dec 2025 20:38:17 +0800 Subject: [PATCH] feat: bind employee to customer (v2) --- api_v2/urls.py | 2 + api_v2/views/basic_info.py | 86 +++++++++++++++++++ docs/api_v2_customer_employee_binding.md | 105 +++++++++++++++++++++++ 3 files changed, 193 insertions(+) create mode 100644 api_v2/views/basic_info.py create mode 100644 docs/api_v2_customer_employee_binding.md diff --git a/api_v2/urls.py b/api_v2/urls.py index 351d9e7..cac2df5 100644 --- a/api_v2/urls.py +++ b/api_v2/urls.py @@ -11,9 +11,11 @@ from api_v2.views import ( PlateOrderBatchUpdateView, BusinessObjectCloneView, ) +from api_v2.views.basic_info import CustomerEmployeeBindingView urlpatterns = [ path('users/quick-create/', QuickCreateEmployeeUserView.as_view(), name='api_v2_user_quick_create'), + path('customers/bind-employee/', CustomerEmployeeBindingView.as_view(), name='api_v2_customer_bind_employee'), path('printing-jobs/by-customer/', PrintingJobByCustomerView.as_view(), name='api_v2_printing_job_by_customer'), path('printing-jobs/batch-advance/preview/', PrintingJobBatchAdvancePreviewView.as_view(), name='api_v2_printing_job_batch_advance_preview'), path('printing-jobs/batch-advance/', PrintingJobBatchAdvanceSubmitView.as_view(), name='api_v2_printing_job_batch_advance_submit'), diff --git a/api_v2/views/basic_info.py b/api_v2/views/basic_info.py new file mode 100644 index 0000000..25b2648 --- /dev/null +++ b/api_v2/views/basic_info.py @@ -0,0 +1,86 @@ +from rest_framework import serializers, status +from rest_framework.permissions import IsAuthenticated +from rest_framework.response import Response +from rest_framework.views import APIView + +from basic_info import models as basic_models + + +class CustomerEmployeeBindingSerializer(serializers.Serializer): + """客户员工绑定序列化器""" + customer_name = serializers.CharField(max_length=100, help_text='客户名称') + employee_name = serializers.CharField(max_length=100, help_text='员工姓名') + + +class CustomerEmployeeBindingView(APIView): + """ + 客户员工可见性绑定 API + + 将指定员工添加到指定客户的可见员工列表中。 + + POST /api/v2/customers/bind-employee/ + """ + + permission_classes = [IsAuthenticated] + + def post(self, request): + serializer = CustomerEmployeeBindingSerializer(data=request.data) + serializer.is_valid(raise_exception=True) + + employee_name = serializer.validated_data['employee_name'] + customer_name = serializer.validated_data['customer_name'] + + # 查询员工 + employees = basic_models.Employee.objects.filter(name=employee_name) + if employees.count() == 0: + return Response( + {'error': f'未找到名为 "{employee_name}" 的员工'}, + status=status.HTTP_400_BAD_REQUEST + ) + if employees.count() > 1: + return Response( + {'error': f'找到多个名为 "{employee_name}" 的员工({employees.count()} 个),请使用更精确的标识'}, + status=status.HTTP_403_FORBIDDEN + ) + + # 查询客户 + customers = basic_models.Customer.objects.filter(name=customer_name) + if customers.count() == 0: + return Response( + {'error': f'未找到名为 "{customer_name}" 的客户'}, + status=status.HTTP_400_BAD_REQUEST + ) + if customers.count() > 1: + return Response( + {'error': f'找到多个名为 "{customer_name}" 的客户({customers.count()} 个),请使用更精确的标识'}, + status=status.HTTP_403_FORBIDDEN + ) + + # 建立绑定关系 + employee = employees.first() + customer = customers.first() + + # 检查是否已经绑定 + if customer.visible_employees.filter(id=employee.id).exists(): + return Response( + { + 'message': f'员工 "{employee_name}" 已在客户 "{customer_name}" 的可见列表中', + 'customer_id': customer.id, + 'employee_id': employee.id, + }, + status=status.HTTP_200_OK + ) + + # 添加绑定 + customer.visible_employees.add(employee) + + return Response( + { + 'message': f'成功将员工 "{employee_name}" 添加到客户 "{customer_name}" 的可见列表', + 'customer_id': customer.id, + 'customer_name': customer.name, + 'employee_id': employee.id, + 'employee_name': employee.name, + }, + status=status.HTTP_201_CREATED + ) diff --git a/docs/api_v2_customer_employee_binding.md b/docs/api_v2_customer_employee_binding.md new file mode 100644 index 0000000..f96336f --- /dev/null +++ b/docs/api_v2_customer_employee_binding.md @@ -0,0 +1,105 @@ +# 客户员工绑定 API + +## 接口说明 + +将指定员工添加到指定客户的可见员工列表中(`Customer.visible_employees`)。 + +## 接口信息 + +- **URL**: `/api/v2/customers/bind-employee/` +- **方法**: `POST` +- **认证**: 需要登录(Bearer Token) + +## 请求参数 + +| 参数名 | 类型 | 必填 | 说明 | +|--------|------|------|------| +| customer_name | string | 是 | 客户名称 | +| employee_name | string | 是 | 员工姓名 | + +## 请求示例 + +```bash +curl -X POST "http://your-domain/api/v2/customers/bind-employee/" \ + -H "Authorization: Bearer YOUR_TOKEN" \ + -H "Content-Type: application/json" \ + -d '{ + "customer_name": "张三服装厂", + "employee_name": "李四" + }' +``` + +## 响应说明 + +### 成功响应(201 Created) + +```json +{ + "message": "成功将员工 \"李四\" 添加到客户 \"张三服装厂\" 的可见列表", + "customer_id": 123, + "customer_name": "张三服装厂", + "employee_id": 456, + "employee_name": "李四" +} +``` + +### 已存在响应(200 OK) + +如果该员工已经在客户的可见列表中: + +```json +{ + "message": "员工 \"李四\" 已在客户 \"张三服装厂\" 的可见列表中", + "customer_id": 123, + "employee_id": 456 +} +``` + +### 错误响应 + +#### 未找到数据(400 Bad Request) + +```json +{ + "error": "未找到名为 \"李四\" 的员工" +} +``` + +或 + +```json +{ + "error": "未找到名为 \"张三服装厂\" 的客户" +} +``` + +#### 找到多条数据(403 Forbidden) + +```json +{ + "error": "找到多个名为 \"李四\" 的员工(3 个),请使用更精确的标识" +} +``` + +或 + +```json +{ + "error": "找到多个名为 \"张三服装厂\" 的客户(2 个),请使用更精确的标识" +} +``` + +#### 参数验证失败(400 Bad Request) + +```json +{ + "customer_name": ["该字段是必填项。"], + "employee_name": ["该字段是必填项。"] +} +``` + +## 注意事项 + +1. 该操作是**幂等的**:重复绑定同一对客户和员工不会报错,会返回 200 状态码 +2. 如果客户或员工名称不唯一,系统会返回 403 错误,建议在数据库中确保名称唯一性 +3. 绑定关系为多对多,一个客户可以有多个可见员工,一个员工也可以被多个客户可见