# 当面付代开通功能实现计划 ## Context 需要在 xjz-payment-platform 中新增"代商家开通当面付"功能。这是支付宝 ISV 服务商代商家开通当面付收单产品的标准流程,涉及 4 个 API 的顺序调用: 1. `alipay.open.agent.create` → 创建事务,获得 `batch_no` 2. `alipay.open.agent.facetoface.sign` → 提交当面付开通申请 3. `alipay.open.agent.confirm` → 确认提交事务 4. `alipay.open.agent.order.query` → 轮询申请单状态 SDK 验证:所有 Request/Response 类在 `alipay-sdk-python-all` 中可用。`FacetofaceSign` 无独立 Model 类,直接在 Request 上设置属性。 ## 实现方案 ### 1. 后端模块 `backend/app/plugin/module_payment/facetoface/` 完全复用现有 module_payment 的 model/crud/service/controller/schema 模式。 #### `enums.py` - 申请单状态枚举 ``` INIT - 初始化(本地状态,尚未提交) SUBMITTED - 已提交到支付宝 MERCHANT_AUDITING - 审核中 MERCHANT_CONFIRM - 审核通过,等待商家确认 SUCCESS - 商家已确认,开通成功 CLOSED - 已关闭(驳回/失败/取消) ``` #### `model.py` - FacetofaceOrderModel 表名 `pay_facetoface_order`,继承 `PaymentModelMixin + TenantMixin`。 关键字段: - `batch_no` (String64, unique) - 支付宝事务编号 - `order_no` (String64) - 支付宝申请单号 - `order_status` (String32) - 申请单状态(用枚举) - `merchant_name` (String128) - 商户名称 - `shop_name` (String128) - 店铺名称 - `shop_address` (String256) - 店铺地址 - `mcc_code` (String32) - 商户类别码 - `rate` (String16) - 费率 - `business_license_no` (String64) - 营业执照号 - `business_license_mobile` (String32) - 联系手机号 - `sign_and_auth` (Boolean) - 是否同时获取授权 - `confirm_url` (Text) - 商家确认链接 - `app_auth_token` (String128) - 商家授权 token - `reject_reason` (Text) - 驳回原因 - `remark` (Text) - 备注 - `last_query_time` (DateTime) - 最后查询时间 - `next_query_time` (DateTime) - 下次查询时间 - `query_count` (Integer) - 已查询次数 #### `schema.py` - `FacetofaceApplySchema` - 申请请求(shop_name, shop_address, mcc_code, rate, business_license_no, business_license_mobile, sign_and_auth 等) - `FacetofaceOrderOutSchema` - 详情响应 - `FacetofaceOrderListOutSchema` - 列表响应 #### `crud.py` - `FacetofaceCRUD` 继承 `CRUDBase` - `get_by_batch_no` - 按事务编号查询 - `get_pending_orders` - 获取待轮询的申请单 #### `service.py` - `apply_service` - 执行三步操作:create → sign → confirm,一次性完成提交 - `query_order_service` - 手动查询单个申请单状态 - `poll_pending_orders` - 定时任务调用,轮询所有待处理申请单 - 策略:提交后 5 分钟首查,之后每 4 小时查一次 - 如果 MERCHANT_AUDITING 超过 1 天,标记需关注 #### `controller.py` - `FacetofaceRouter = APIRouter(prefix="/facetoface", tags=["当面付开通"])` - `POST /facetoface/apply` - 提交开通申请 - `GET /facetoface` - 查询申请单列表(分页) - `POST /facetoface/{id}/query` - 手动刷新查询状态 - `GET /facetoface/{id}` - 查询申请单详情 #### `__init__.py` 导出 Router, CRUD, Model, Service 等。 ### 2. 模块注册 `backend/app/plugin/module_payment/__init__.py` 的 `_MODULES` 列表加入 `"facetoface"`。 路由自动发现:discover.py 会自动扫描 `module_payment/facetoface/controller.py` 并注册到 `/payment/facetoface`。 ### 3. 数据库迁移 创建 Alembic migration:`backend/app/alembic/versions/c1d2e3f4g5h6_add_facetoface_order.py` ### 4. 定时轮询任务 在应用启动时注册一个 interval 定时任务(通过现有的 APScheduler 系统),每 30 分钟检查一次是否有需要查询状态的申请单。具体轮询间隔由 `next_query_time` 字段控制: - 提交后 5 分钟 → 首查 - 之后每 4 小时查一次 - 达到终态(SUCCESS/CLOSED)后停止轮询 ### 5. 前端 #### `frontend/src/api/module_payment/facetoface.ts` API 接口定义 + 状态常量映射。 #### `frontend/src/views/module_payment/facetoface/index.vue` 管理页面,包含: - 搜索栏:商户名称、店铺名称、状态筛选 - 数据表格:batch_no、商户名、店铺名、状态、费率、确认链接、创建时间 - 新增按钮:打开申请表单弹窗 - 操作列:查询状态、查看详情 - 申请表单弹窗:填写商户信息后提交 复用现有 CRUD 组件:PageSearch, PageContent, CrudToolbarLeft, CrudToolbarRight, PageModal。 ### 6. 关键文件清单 **新建:** - `backend/app/plugin/module_payment/facetoface/__init__.py` - `backend/app/plugin/module_payment/facetoface/enums.py` - `backend/app/plugin/module_payment/facetoface/model.py` - `backend/app/plugin/module_payment/facetoface/schema.py` - `backend/app/plugin/module_payment/facetoface/crud.py` - `backend/app/plugin/module_payment/facetoface/service.py` - `backend/app/plugin/module_payment/facetoface/controller.py` - `backend/app/alembic/versions/c1d2e3f4g5h6_add_facetoface_order.py` - `frontend/src/api/module_payment/facetoface.ts` - `frontend/src/views/module_payment/facetoface/index.vue` **修改:** - `backend/app/plugin/module_payment/__init__.py` - 注册模块 ### 7. 复用的现有代码 - `AlipayClient.get_client()` from `app.core.alipay.client` - `PaymentModelMixin, TenantMixin` from `app.core.base_model` - `CRUDBase` from `app.core.base_crud` - `CustomException` from `app.core.exceptions` - `AuthPermission, redis_getter` from `app.core.dependencies` - `OperationLogRoute` from `app.core.router_class` - `ResponseSchema, SuccessResponse` from `app.common.response` - `scheduler` from `app.core.ap_scheduler` (注册轮询任务) - 前端: PageSearch, PageContent, CrudToolbarLeft/Right, PageModal 组件 ### 8. 验证 1. 后端:启动服务,检查 `/payment/facetoface` 路由是否注册 2. 数据库:运行 migration 创建表 3. 前端:访问当面付管理页面,测试列表、搜索、新增申请 4. 定时任务:检查 APScheduler 日志确认轮询任务注册成功