فهرست منبع

chore: 初始化项目

gatsby 1 ماه پیش
کامیت
0ad157b43c
10فایلهای تغییر یافته به همراه2420 افزوده شده و 0 حذف شده
  1. 1 0
      .gitignore
  2. 6 0
      .gitmodules
  3. 680 0
      Plugin模块规划.md
  4. 22 0
      deploy/.env
  5. 163 0
      deploy/docker-compose.yml
  6. 1 0
      payment-mini
  7. 1 0
      payment-platform
  8. 667 0
      因公付款服务系统架构设计.md
  9. 601 0
      技术集成指南.md
  10. 278 0
      支付宝SDK封装方案.md

+ 1 - 0
.gitignore

@@ -0,0 +1 @@
+*密钥*/

+ 6 - 0
.gitmodules

@@ -0,0 +1,6 @@
+[submodule "payment-platform"]
+	path = payment-platform
+	url = http://localhost:3000/gatsby/payment-platform.git
+[submodule "payment-mini"]
+	path = payment-mini
+	url = http://localhost:3000/gatsby/payment-mini.git

+ 680 - 0
Plugin模块规划.md

@@ -0,0 +1,680 @@
+# 因公付款服务系统 - Plugin 模块规划
+
+## 一、规划背景
+
+基于 [因公付款服务系统架构设计.md](../docs/因公付款服务系统架构设计.md) 文档,本规划旨在将因公付款服务的核心功能模块落地到 `app/plugin/` 目录下,采用 `module_payment` 作为一级模块,下设多个二级子模块。
+
+## 二、目录结构设计
+
+```
+app/plugin/
+├── module_payment/                          # 因公付款服务一级模块
+│   │
+│   ├── plugin.toml                          # 模块元数据
+│   │
+│   ├── enterprise/                         # 企业管理子模块
+│   │   ├── __init__.py
+│   │   ├── model.py                        # 企业实体定义
+│   │   ├── schema.py                       # Pydantic请求/响应模型
+│   │   ├── crud.py                         # 数据库CRUD操作
+│   │   ├── service.py                      # 业务逻辑层
+│   │   ├── controller.py                   # API路由控制器
+│   │   └── utils.py                        # 工具函数
+│   │
+│   ├── department/                         # 部门管理子模块
+│   │   ├── __init__.py
+│   │   ├── model.py
+│   │   ├── schema.py
+│   │   ├── crud.py
+│   │   ├── service.py
+│   │   └── controller.py
+│   │
+│   ├── employee/                           # 员工管理子模块
+│   │   ├── __init__.py
+│   │   ├── model.py
+│   │   ├── schema.py
+│   │   ├── crud.py
+│   │   ├── service.py
+│   │   ├── controller.py
+│   │   └── utils.py
+│   │
+│   ├── expense_institution/                # 费控制度子模块
+│   │   ├── __init__.py
+│   │   ├── model.py
+│   │   ├── schema.py
+│   │   ├── crud.py
+│   │   ├── service.py
+│   │   └── controller.py
+│   │
+│   ├── expense_rule/                       # 使用规则子模块
+│   │   ├── __init__.py
+│   │   ├── model.py
+│   │   ├── schema.py
+│   │   ├── crud.py
+│   │   ├── service.py
+│   │   └── controller.py
+│   │
+│   ├── quota/                              # 额度管理子模块
+│   │   ├── __init__.py
+│   │   ├── model.py
+│   │   ├── schema.py
+│   │   ├── crud.py
+│   │   ├── service.py
+│   │   └── controller.py
+│   │
+│   ├── bill/                               # 账单管理子模块
+│   │   ├── __init__.py
+│   │   ├── model.py
+│   │   ├── schema.py
+│   │   ├── crud.py
+│   │   ├── service.py
+│   │   ├── controller.py
+│   │   └── utils.py
+│   │
+│   ├── voucher/                            # 凭证管理子模块
+│   │   ├── __init__.py
+│   │   ├── model.py
+│   │   ├── schema.py
+│   │   ├── crud.py
+│   │   ├── service.py
+│   │   └── controller.py
+│   │
+│   ├── payment/                            # 支付跳转子模块
+│   │   ├── __init__.py
+│   │   ├── schema.py
+│   │   ├── service.py
+│   │   ├── controller.py
+│   │   └── utils.py                        # 支付宝跳转链接生成工具
+│   │
+│   └── notification/                       # 消息通知子模块
+│       ├── __init__.py
+│       ├── handlers/                       # 通知处理器
+│       │   ├── __init__.py
+│       │   ├── enterprise_handler.py       # 企业状态变更处理
+│       │   ├── employee_handler.py        # 员工变更处理
+│       │   ├── bill_handler.py            # 账单变动处理
+│       │   └── voucher_handler.py         # 凭证变动处理
+│       ├── service.py
+│       └── controller.py                   # WebSocket/HTTP回调入口
+│
+├── module_ai/                             # 现有AI模块(保留)
+├── module_example/                        # 现有示例模块(保留)
+├── module_generator/                      # 现有代码生成模块(保留)
+└── module_task/                          # 现有任务调度模块(保留)
+```
+
+## 三、模块职责划分
+
+### 3.1 module_payment/plugin.toml 配置
+
+```toml
+name = "payment"
+title = "因公付款服务"
+version = "1.0.0"
+description = "基于支付宝企业码的因公付款服务系统核心模块"
+optional = false
+tags = ["payment", "enterprise", "expense", "alipay"]
+```
+
+### 3.2 各子模块详细职责
+
+| 子模块 | 职责 | 对应支付宝API | 优先级 |
+|-------|------|--------------|-------|
+| enterprise | 企业入驻、签约、解约、注销 | alipay.commerce.ec.enterprise.* | P0 |
+| department | 部门创建、修改、删除、查询 | (本地管理,无支付宝API) | P1 |
+| employee | 员工添加、删除、激活、邀请链接 | alipay.commerce.ec.employee.* | P0 |
+| expense_institution | 费控制度CRUD、成员管理 | alipay.ebpp.invoice.institution.* | P0 |
+| expense_rule | 使用规则创建、编辑、删除 | alipay.ebpp.invoice.institution.expenserule.* | P1 |
+| quota | 额度创建、发放、查询、修改 | alipay.ebpp.invoice.expensecontrol.quota.* | P0 |
+| bill | 账单接收、查询、对账 | alipay.commerce.ec.consume.* | P0 |
+| voucher | 凭证存储、查询 | alipay.commerce.ec.voucher.* | P1 |
+| payment | 扫一扫/付款码跳转链接生成 | (本地生成,无支付宝API) | P0 |
+| notification | 支付宝消息接收、处理、分发 | (Webhook回调处理) | P0 |
+
+## 四、数据模型设计
+
+### 4.1 企业模块 (enterprise/model.py)
+
+```python
+import enum
+from sqlalchemy import String, DateTime
+from sqlalchemy.orm import Mapped, mapped_column
+
+from app.core.base_model import ModelMixin, UserMixin
+
+
+class EnterpriseStatusEnum(enum.Enum):
+    REGISTERED = "registered"       # 已注册
+    SIGNED = "signed"              # 已签约
+    UNSIGNED = "unsigned"           # 已解约
+    DELETED = "deleted"             # 已注销
+
+
+class EnterpriseModel(ModelMixin, UserMixin):
+    __tablename__ = "t_enterprise"
+    __table_args__ = {"comment": "企业表"}
+
+    enterprise_id: Mapped[str] = mapped_column(String(64), unique=True, index=True, comment="企业码企业ID")
+    account_id: Mapped[str | None] = mapped_column(String(64), comment="支付宝账号ID")
+    name: Mapped[str] = mapped_column(String(128), comment="企业名称")
+    status: Mapped[str] = mapped_column(String(32), default=EnterpriseStatusEnum.REGISTERED.value, comment="状态")
+```
+
+### 4.2 部门模块 (department/model.py)
+
+```python
+from sqlalchemy import String, ForeignKey
+from sqlalchemy.orm import Mapped, mapped_column
+
+from app.core.base_model import ModelMixin
+
+
+class DepartmentModel(ModelMixin):
+    __tablename__ = "t_department"
+    __table_args__ = {"comment": "部门表"}
+
+    department_id: Mapped[str] = mapped_column(String(64), unique=True, index=True, comment="部门ID")
+    enterprise_id: Mapped[str] = mapped_column(String(64), index=True, comment="所属企业ID")
+    name: Mapped[str] = mapped_column(String(128), comment="部门名称")
+    parent_id: Mapped[str | None] = mapped_column(String(64), comment="上级部门ID")
+```
+
+### 4.3 员工模块 (employee/model.py)
+
+```python
+import enum
+from sqlalchemy import String, DateTime, ForeignKey
+from sqlalchemy.orm import Mapped, mapped_column
+
+from app.core.base_model import ModelMixin, UserMixin
+
+
+class EmployeeStatusEnum(enum.Enum):
+    PENDING = "pending"     # 待激活
+    ACTIVE = "active"       # 已激活
+    DELETED = "deleted"     # 已删除
+
+
+class EmployeeModel(ModelMixin, UserMixin):
+    __tablename__ = "t_employee"
+    __table_args__ = {"comment": "员工表"}
+
+    employee_id: Mapped[str] = mapped_column(String(64), unique=True, index=True, comment="员工ID")
+    enterprise_id: Mapped[str] = mapped_column(String(64), index=True, comment="所属企业ID")
+    alipay_user_id: Mapped[str | None] = mapped_column(String(64), comment="支付宝用户ID")
+    name: Mapped[str] = mapped_column(String(64), comment="员工姓名")
+    phone: Mapped[str | None] = mapped_column(String(32), comment="手机号")
+    email: Mapped[str | None] = mapped_column(String(128), comment="邮箱")
+    department_id: Mapped[str | None] = mapped_column(String(64), comment="部门ID")
+    status: Mapped[str] = mapped_column(String(32), default=EmployeeStatusEnum.PENDING.value, comment="状态")
+    bind_time: Mapped[datetime | None] = mapped_column(DateTime, comment="绑定时间")
+```
+
+### 4.4 费控制度模块 (expense_institution/model.py)
+
+```python
+from sqlalchemy import String, DECIMAL, DateTime
+from sqlalchemy.orm import Mapped, mapped_column
+
+from app.core.base_model import ModelMixin, UserMixin
+
+
+class ExpenseInstitutionModel(ModelMixin, UserMixin):
+    __tablename__ = "t_expense_institution"
+    __table_args__ = {"comment": "费控制度表"}
+
+    institution_id: Mapped[str] = mapped_column(String(64), unique=True, index=True, comment="制度ID")
+    enterprise_id: Mapped[str] = mapped_column(String(64), index=True, comment="所属企业ID")
+    name: Mapped[str] = mapped_column(String(128), comment="制度名称")
+    expense_type: Mapped[str] = mapped_column(String(32), default="DEFAULT", comment="费用类型")
+    expense_sub_type: Mapped[str] = mapped_column(String(32), default="DEFAULT", comment="费用类型子类")
+    status: Mapped[str] = mapped_column(String(32), default="active", comment="状态")
+```
+
+### 4.5 使用规则模块 (expense_rule/model.py)
+
+```python
+from sqlalchemy import String, DECIMAL, DateTime, ForeignKey
+from sqlalchemy.orm import Mapped, mapped_column
+
+from app.core.base_model import ModelMixin
+
+
+class ExpenseRuleModel(ModelMixin):
+    __tablename__ = "t_expense_rule"
+    __table_args__ = {"comment": "使用规则表"}
+
+    rule_id: Mapped[str] = mapped_column(String(64), unique=True, index=True, comment="规则ID")
+    institution_id: Mapped[str] = mapped_column(String(64), index=True, comment="所属制度ID")
+    name: Mapped[str | None] = mapped_column(String(128), comment="规则名称")
+    max_amount: Mapped[float | None] = mapped_column(DECIMAL(12,2), comment="最大限额")
+    valid_from: Mapped[datetime | None] = mapped_column(DateTime, comment="有效期开始")
+    valid_to: Mapped[datetime | None] = mapped_column(DateTime, comment="有效期结束")
+    merchant_pid: Mapped[str | None] = mapped_column(String(64), comment="限定商户PID")
+```
+
+### 4.6 额度模块 (quota/model.py)
+
+```python
+import enum
+from sqlalchemy import String, DECIMAL, DateTime, ForeignKey
+from sqlalchemy.orm import Mapped, mapped_column
+
+from app.core.base_model import ModelMixin, UserMixin
+
+
+class QuotaStatusEnum(enum.Enum):
+    ACTIVE = "active"       # 正常
+    FROZEN = "frozen"        # 冻结
+    EXHAUSTED = "exhausted"  # 已用完
+    EXPIRED = "expired"      # 已过期
+
+
+class QuotaModel(ModelMixin, UserMixin):
+    __tablename__ = "t_quota"
+    __table_args__ = {"comment": "额度表"}
+
+    quota_id: Mapped[str] = mapped_column(String(64), unique=True, index=True, comment="额度ID")
+    employee_id: Mapped[str] = mapped_column(String(64), index=True, comment="员工ID")
+    institution_id: Mapped[str] = mapped_column(String(64), index=True, comment="制度ID")
+    outer_source_id: Mapped[str] = mapped_column(String(64), unique=True, comment="外部来源ID(幂等)")
+    total_amount: Mapped[float] = mapped_column(DECIMAL(12,2), comment="总金额")
+    available_amount: Mapped[float] = mapped_column(DECIMAL(12,2), comment="可用金额")
+    valid_from: Mapped[datetime] = mapped_column(DateTime, comment="有效期开始")
+    valid_to: Mapped[datetime] = mapped_column(DateTime, comment="有效期结束")
+    status: Mapped[str] = mapped_column(String(32), default=QuotaStatusEnum.ACTIVE.value, comment="状态")
+```
+
+### 4.7 账单模块 (bill/model.py)
+
+```python
+import enum
+from sqlalchemy import String, DECIMAL, DateTime, Text
+from sqlalchemy.orm import Mapped, mapped_column
+
+from app.core.base_model import ModelMixin
+
+
+class BillStatusEnum(enum.Enum):
+    PAID = "paid"       # 已支付
+    REFUNDED = "refunded"  # 已退款
+    CLOSED = "closed"      # 已关闭
+
+
+class BillModel(ModelMixin):
+    __tablename__ = "t_bill"
+    __table_args__ = {"comment": "账单表"}
+
+    bill_id: Mapped[str] = mapped_column(String(64), unique=True, index=True, comment="账单ID")
+    trade_no: Mapped[str] = mapped_column(String(64), index=True, comment="支付宝交易号")
+    enterprise_id: Mapped[str] = mapped_column(String(64), index=True, comment="企业ID")
+    employee_id: Mapped[str] = mapped_column(String(64), index=True, comment="员工ID")
+    institution_id: Mapped[str | None] = mapped_column(String(64), comment="制度ID")
+    quota_id: Mapped[str | None] = mapped_column(String(64), comment="额度ID")
+    total_amount: Mapped[float] = mapped_column(DECIMAL(12,2), comment="账单金额")
+    enterprise_pay_amount: Mapped[float] = mapped_column(DECIMAL(12,2), default=0, comment="企业付金额")
+    personal_pay_amount: Mapped[float] = mapped_column(DECIMAL(12,2), default=0, comment="个人付金额")
+    discount_amount: Mapped[float] = mapped_column(DECIMAL(12,2), default=0, comment="优惠金额")
+    trade_time: Mapped[datetime | None] = mapped_column(DateTime, comment="交易时间")
+    merchant_name: Mapped[str | None] = mapped_column(String(256), comment="商户名称")
+    status: Mapped[str] = mapped_column(String(32), default=BillStatusEnum.PAID.value, comment="状态")
+```
+
+### 4.8 凭证模块 (voucher/model.py)
+
+```python
+from sqlalchemy import String, JSON, ForeignKey
+from sqlalchemy.orm import Mapped, mapped_column
+
+from app.core.base_model import ModelMixin
+
+
+class VoucherModel(ModelMixin):
+    __tablename__ = "t_voucher"
+    __table_args__ = {"comment": "凭证表"}
+
+    voucher_id: Mapped[str] = mapped_column(String(64), unique=True, index=True, comment="凭证ID")
+    bill_id: Mapped[str] = mapped_column(String(64), index=True, comment="关联账单ID")
+    content: Mapped[dict | None] = mapped_column(JSON, comment="凭证内容")
+```
+
+### 4.9 消息通知模块 (notification/handlers)
+
+通知处理器采用策略模式,根据消息类型分发到不同的Handler处理:
+
+```python
+# notification/handlers/__init__.py
+from notification.handlers.enterprise_handler import EnterpriseChangeHandler
+from notification.handlers.employee_handler import EmployeeChangeHandler
+from notification.handlers.bill_handler import BillChangeHandler
+from notification.handlers.voucher_handler import VoucherChangeHandler
+
+HANDLER_MAP = {
+    "alipay.commerce.ec.enterprise.change.notify": EnterpriseChangeHandler,
+    "alipay.commerce.ec.employee.change.notify": EmployeeChangeHandler,
+    "alipay.commerce.ec.consume.change.notify": BillChangeHandler,
+    "alipay.commerce.ec.voucher.change.notify": VoucherChangeHandler,
+}
+```
+
+## 五、服务层设计
+
+### 5.1 企业签约服务 (enterprise/service.py)
+
+```python
+from typing import TYPE_CHECKING
+from alipaySdk import AlipaySDK
+
+if TYPE_CHECKING:
+    from enterprise.model import EnterpriseModel
+
+
+class EnterpriseService:
+
+    def __init__(self, alipay_sdk: AlipaySDK):
+        self._sdk = alipay_sdk
+
+    async def create_invite_url(self, enterprise: "EnterpriseModel") -> str:
+        """生成企业注册邀请链接"""
+        result = await self._sdk.execute(
+            "alipay.commerce.ec.enterprise.registerinvite.create",
+            {"enterprise_name": enterprise.name}
+        )
+        return result.get("invite_url")
+
+    async def handle_status_change(self, notify_data: dict) -> None:
+        """处理企业状态变更通知"""
+        # 更新企业状态
+        pass
+```
+
+### 5.2 员工服务 (employee/service.py)
+
+```python
+class EmployeeService:
+
+    async def add_employee(self, enterprise_id: str, name: str, phone: str) -> dict:
+        """添加企业员工"""
+        result = await self._sdk.execute(
+            "alipay.commerce.ec.employee.add",
+            {
+                "enterprise_id": enterprise_id,
+                "name": name,
+                "phone": phone,
+            }
+        )
+        return result
+
+    async def delete_employee(self, employee_id: str) -> dict:
+        """删除企业员工"""
+        result = await self._sdk.execute(
+            "alipay.commerce.ec.employee.delete",
+            {"employee_id": employee_id}
+        )
+        return result
+
+    async def get_invite_url(self, employee_id: str) -> str:
+        """获取员工邀请链接"""
+        result = await self._sdk.execute(
+            "alipay.commerce.ec.employee.invite.query",
+            {"employee_id": employee_id}
+        )
+        return result.get("sign_url")
+```
+
+### 5.3 费控服务 (expense_institution/service.py)
+
+```python
+class ExpenseInstitutionService:
+
+    async def create_institution(self, enterprise_id: str, name: str, **kwargs) -> dict:
+        """创建费控制度"""
+        result = await self._sdk.execute(
+            "alipay.ebpp.invoice.institution.create",
+            {
+                "enterprise_id": enterprise_id,
+                "name": name,
+                "expense_type": kwargs.get("expense_type", "DEFAULT"),
+                "expense_sub_type": kwargs.get("expense_sub_type", "DEFAULT"),
+            }
+        )
+        return result
+
+    async def modify_institution(self, institution_id: str, **kwargs) -> dict:
+        """编辑费控制度"""
+        result = await self._sdk.execute(
+            "alipay.ebpp.invoice.institution.modify",
+            {"institution_id": institution_id, **kwargs}
+        )
+        return result
+```
+
+### 5.4 额度服务 (quota/service.py)
+
+```python
+class QuotaService:
+
+    async def create_quota(self, employee_id: str, institution_id: str,
+                          total_amount: float, valid_from: datetime,
+                          valid_to: datetime, outer_source_id: str) -> dict:
+        """创建手工发放额度"""
+        result = await self._sdk.execute(
+            "alipay.ebpp.invoice.expensecontrol.quota.create",
+            {
+                "target_type": "INSTITUTION",
+                "target_id": institution_id,
+                "employee_id": employee_id,
+                "amount": total_amount,
+                "valid_from": valid_from.isoformat(),
+                "valid_to": valid_to.isoformat(),
+                "outer_source_id": outer_source_id,
+            }
+        )
+        return result
+
+    async def query_quota(self, employee_id: str, institution_id: str) -> dict:
+        """查询员工可用额度"""
+        result = await self._sdk.execute(
+            "alipay.ebpp.invoice.expensecontrol.quota.query",
+            {
+                "employee_id": employee_id,
+                "target_type": "INSTITUTION",
+                "target_id": institution_id,
+            }
+        )
+        return result
+```
+
+### 5.5 支付跳转服务 (payment/service.py)
+
+```python
+import json
+from urllib.parse import quote
+
+
+class PaymentService:
+
+    def generate_scan_params(self, account_id: str, rule_group_id: str,
+                            payment_id: str, isv_app_id: str) -> dict:
+        """生成扫一扫跳转参数"""
+        params = {
+            "pdSubBizScene": "enterprisePay",
+            "specifiedEnableChannelInfo": json.dumps({
+                "enableScene": "agreementpay",
+                "assetInfo": {
+                    "instId": "INST_ALIPAY",
+                    "assetId": account_id,
+                    "assetTypeCode": "ENTERPRISEPAY",
+                    "assetType": "ENTERPRISEPAYASSET"
+                }
+            }),
+            "assignJointAccountId": account_id,
+            "identityPayBizInfo": json.dumps({
+                "identityPaySubBizScene": "ISV_PAY",
+                "bizGroupId": account_id,
+                "groupId": account_id,
+                "identityPayBizScene": "ENTERPRISE_CODE"
+            }),
+            "CHANNEL_INDEX": "[\"ENTERPRISEPAYASSET_DC_ENTERPRISEPAY_DEFAULT\"]",
+            "enterprise_pay_info": json.dumps({
+                "paymentId": payment_id,
+                "ruleGroupId": rule_group_id
+            }),
+            "sourcePlatformInfo": json.dumps({
+                "paymentId": payment_id,
+                "ruleGroupId": rule_group_id,
+                "isvAppId": isv_app_id
+            })
+        }
+        return params
+
+    def generate_payment_code_url(self, account_id: str, rule_group_id: str,
+                                  payment_id: str, isv_app_id: str) -> str:
+        """生成付款码跳转链接"""
+        params = self.generate_scan_params(account_id, rule_group_id, payment_id, isv_app_id)
+        params["channelMode"] = "NONE_CHANNEL_MODE"
+
+        encoded_params = quote(json.dumps(params), safe='')
+        return f"alipays://platformapi/startapp?appId=20000056&customBizCode=enterprisePayForThirdPart&customBizParams={encoded_params}"
+```
+
+## 六、API路由设计
+
+### 6.1 企业管理路由 (enterprise/controller.py)
+
+```
+POST   /api/payment/enterprise/invite           # 创建企业邀请
+GET    /api/payment/enterprise/{enterprise_id}  # 查询企业详情
+PUT    /api/payment/enterprise/{enterprise_id}  # 修改企业信息
+POST   /api/payment/enterprise/{enterprise_id}/unsign  # 企业解约
+POST   /api/payment/enterprise/{enterprise_id}/delete  # 企业注销
+```
+
+### 6.2 员工管理路由 (employee/controller.py)
+
+```
+POST   /api/payment/employee                    # 添加员工
+DELETE /api/payment/employee/{employee_id}      # 删除员工
+GET    /api/payment/employee/{employee_id}      # 查询员工详情
+PUT    /api/payment/employee/{employee_id}      # 修改员工信息
+GET    /api/payment/employee/list               # 查询员工列表
+GET    /api/payment/employee/{employee_id}/invite-url  # 获取邀请链接
+```
+
+### 6.3 费控管理路由 (expense_institution/controller.py)
+
+```
+POST   /api/payment/institution                         # 创建费控制度
+PUT    /api/payment/institution/{institution_id}        # 编辑费控制度
+GET    /api/payment/institution/{institution_id}        # 查询制度详情
+GET    /api/payment/institution/list                   # 查询制度列表
+DELETE /api/payment/institution/{institution_id}       # 删除费控制度
+POST   /api/payment/institution/{institution_id}/members # 编辑制度成员
+```
+
+### 6.4 额度管理路由 (quota/controller.py)
+
+```
+POST   /api/payment/quota                      # 创建额度
+GET    /api/payment/quota/{quota_id}           # 查询额度详情
+GET    /api/payment/quota/employee/{employee_id}  # 查询员工可用额度
+PUT    /api/payment/quota/{quota_id}           # 修改额度
+DELETE /api/payment/quota/{quota_id}           # 删除额度
+```
+
+### 6.5 账单管理路由 (bill/controller.py)
+
+```
+GET    /api/payment/bill/{bill_id}            # 查询账单详情
+GET    /api/payment/bill/list                 # 查询账单列表
+GET    /api/payment/bill/download             # 下载对账单
+```
+
+### 6.6 支付跳转路由 (payment/controller.py)
+
+```
+POST   /api/payment/pay/scan-url               # 生成扫一扫跳转链接
+POST   /api/payment/pay/code-url               # 生成付款码跳转链接
+POST   /api/payment/pay/invoice-url            # 生成发票关联跳转链接
+```
+
+### 6.7 消息通知路由 (notification/controller.py)
+
+```
+POST   /api/payment/notification/enterprise     # 企业状态变更回调
+POST   /api/payment/notification/employee       # 员工变更回调
+POST   /api/payment/notification/bill          # 账单变动回调
+POST   /api/payment/notification/voucher       # 凭证变动回调
+WS     /ws/payment/notification                # WebSocket长连接
+```
+
+## 七、依赖关系
+
+```
+┌─────────────────────────────────────────────────────────────────┐
+│                      API Controller Layer                       │
+│  enterprise | employee | expense_institution | quota | bill    │
+│                      payment | notification                     │
+└─────────────────────────────────────────────────────────────────┘
+                              │
+                              ▼
+┌─────────────────────────────────────────────────────────────────┐
+│                       Service Layer                             │
+│  EnterpriseService | EmployeeService | ExpenseService | ...    │
+└─────────────────────────────────────────────────────────────────┘
+                              │
+                              ▼
+┌─────────────────────────────────────────────────────────────────┐
+│                    Alipay SDK Layer                             │
+│              (统一封装支付宝API调用)                              │
+└─────────────────────────────────────────────────────────────────┘
+                              │
+                              ▼
+┌─────────────────────────────────────────────────────────────────┐
+│                        CRUD Layer                               │
+│         Model | Schema | CRUD (与数据库交互)                      │
+└─────────────────────────────────────────────────────────────────┘
+                              │
+                              ▼
+┌─────────────────────────────────────────────────────────────────┐
+│                    PostgreSQL Database                          │
+└─────────────────────────────────────────────────────────────────┘
+```
+
+## 八、实施计划
+
+### 阶段一:基础框架(1周)
+
+1. 创建 `module_payment` 目录结构
+2. 定义 `plugin.toml` 元数据
+3. 创建各子模块的基础文件骨架
+4. 配置数据库连接和ORM模型
+
+### 阶段二:核心模块开发(3-4周)
+
+| 周次 | 开发内容 |
+|-----|---------|
+| 第2周 | enterprise + department 模块 |
+| 第3周 | employee + notification 基础 |
+| 第4周 | expense_institution + expense_rule |
+| 第5周 | quota + payment |
+
+### 阶段三:账单和凭证模块(1-2周)
+
+1. bill 模块开发
+2. voucher 模块开发
+3. 消息通知处理器完善
+
+### 阶段四:集成测试(1周)
+
+1. 模块间依赖测试
+2. 支付宝API联调
+3. 整体业务流程测试
+
+## 九、注意事项
+
+1. **命名规范**:遵循 `module_{一级模块}_{二级模块}` 的目录命名约定
+2. **ModelMixin**:所有模型类需继承 `ModelMixin`,支持通用CRUD
+3. **幂等性**:额度等关键操作需使用 `outer_source_id` 保证幂等
+4. **错误处理**:支付宝API调用需统一异常处理和日志记录
+5. **事务管理**:跨表操作需使用数据库事务保证一致性

+ 22 - 0
deploy/.env

@@ -0,0 +1,22 @@
+# PostgreSQL 配置
+POSTGRES_USER=admin
+POSTGRES_PASSWORD=123456xjz
+POSTGRES_VERSION=18.3
+
+# PgAdmin 配置(已注释)
+PGADMIN_DEFAULT_EMAIL=admin@example.com
+PGADMIN_DEFAULT_PASSWORD=123456xjz
+PGADMIN_VERSION=latest
+
+# Nginx 配置
+NGINX_VERSION=1.28.3-alpine
+
+# Nginx Proxy Manager 配置
+NGINX_PROXY_MANAGER_VERSION=latest
+
+# Gogs 配置
+GOGS_VERSION=latest
+
+# Redis 配置
+REDIS_VERSION=8.6.2-alpine
+REDIS_PASSWORD=123456xjz

+ 163 - 0
deploy/docker-compose.yml

@@ -0,0 +1,163 @@
+version: '3.9'
+
+x-common-environment:
+  &common-environment
+  TZ: Asia/Shanghai
+
+x-common-config:
+  &common-config
+  restart: unless-stopped
+  networks:
+    - app-tier
+  environment:
+    <<: *common-environment
+  deploy:
+    resources:
+      limits:
+        cpus: '2'
+        memory: '1G'
+
+services:
+  postgres:
+    image: postgres:${POSTGRES_VERSION}
+    container_name: postgres
+    <<: *common-config
+    environment:
+      <<: *common-environment
+      POSTGRES_USER: ${POSTGRES_USER}
+      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
+      PGDATA: /var/lib/postgresql/data/pgdata
+      POSTGRES_INITDB_ARGS: "--data-checksums"
+      POSTGRES_POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
+    command: >
+      postgres
+      -c shared_buffers=1GB
+      -c work_mem=16MB
+      -c maintenance_work_mem=128MB
+      -c effective_cache_size=768MB
+      -c random_page_cost=1.1
+      -c synchronous_commit=off
+      -c wal_buffers=16MB
+      -c max_connections=200
+      -c checkpoint_completion_target=0.9
+      -c min_wal_size=80MB
+      -c max_wal_size=1GB
+    volumes:
+      - ./postgresql/data:/var/lib/postgresql/data
+    ports:
+      - "5432:5432"
+    healthcheck:
+      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"]
+      interval: 30s
+      timeout: 10s
+      retries: 5
+
+  redis:
+    image: redis:${REDIS_VERSION}
+    container_name: redis
+    <<: *common-config
+    environment:
+      <<: *common-environment
+      REDIS_PASSWORD: ${REDIS_PASSWORD}
+    command: >
+      redis-server
+      --requirepass ${REDIS_PASSWORD}
+      --appendonly yes
+      --appendfsync everysec
+      --save 900 1
+      --save 300 10
+      --save 60 10000
+      --maxmemory 512mb
+      --maxmemory-policy allkeys-lru
+      --tcp-keepalive 300
+      --timeout 0
+      --loglevel notice
+    volumes:
+      - ./redis/data:/data
+    ports:
+      - "6379:6379"
+    healthcheck:
+      test: ["CMD", "redis-cli", "ping"]
+      interval: 30s
+      timeout: 10s
+      retries: 5
+
+#  pgadmin:
+#    image: dpage/pgadmin4:${PGADMIN_VERSION}
+#    container_name: pgadmin
+#    <<: *common-config
+#    environment:
+#      <<: *common-environment
+#      PGADMIN_DEFAULT_EMAIL: ${PGADMIN_DEFAULT_EMAIL}
+#      PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_DEFAULT_PASSWORD}
+#    volumes:
+#      - ./pgadmin/data:/var/lib/pgadmin
+#    ports:
+#      - "8080:80"
+#    depends_on:
+#      - postgres
+#    healthcheck:
+#      test: ["CMD", "wget", "--spider", "http://localhost:80/login"]
+#      interval: 30s
+#      timeout: 10s
+#      retries: 5
+
+#  nginx:
+#    image: nginx:${NGINX_VERSION}
+#    container_name: nginx
+#    <<: *common-config
+#    environment:
+#      <<: *common-environment
+#    volumes:
+#      - ./nginx/conf.d:/etc/nginx/conf.d
+#      - ./nginx/html:/usr/share/nginx/html
+#    ports:
+#      - "80:80"
+#      - "443:443"
+#    healthcheck:
+#      test: ["CMD", "wget", "--spider", "http://localhost:80"]
+#      interval: 30s
+#      timeout: 10s
+#      retries: 5
+
+  nginx-proxy-manager:
+    image: jc21/nginx-proxy-manager:${NGINX_PROXY_MANAGER_VERSION}
+    container_name: nginx-proxy-manager
+    <<: *common-config
+    environment:
+      <<: *common-environment
+    volumes:
+      - ./nginx-proxy-manager/data:/data
+      - ./nginx-proxy-manager/letsencrypt:/etc/letsencrypt
+    ports:
+      - "80:80"
+      - "81:81"
+      - "443:443"
+    healthcheck:
+      test: ["CMD", "wget", "--spider", "http://localhost:81"]
+      interval: 30s
+      timeout: 10s
+      retries: 5
+
+  gogs:
+    image: gogs/gogs:${GOGS_VERSION}
+    container_name: gogs
+    <<: *common-config
+    environment:
+      <<: *common-environment
+    volumes:
+      - ./gogs/data:/data
+    ports:
+      - "3000:3000"
+      - "2222:22"
+    depends_on:
+      - postgres
+    healthcheck:
+      test: ["CMD", "wget", "--spider", "http://localhost:3000"]
+      interval: 30s
+      timeout: 10s
+      retries: 5
+
+networks:
+  app-tier:
+    driver: bridge

+ 1 - 0
payment-mini

@@ -0,0 +1 @@
+Subproject commit e9c322f636ea5d529ce025367e4e816cc1d55e76

+ 1 - 0
payment-platform

@@ -0,0 +1 @@
+Subproject commit 6d733b8fbda047b306620d2c3098daa7568df897

+ 667 - 0
因公付款服务系统架构设计.md

@@ -0,0 +1,667 @@
+# 因公付款服务系统 - 架构设计计划
+
+## 一、系统概述
+
+### 1.1 项目定位
+
+基于支付宝企业码能力,构建企业级因公付款服务系统。系统核心目标是帮助企业实现员工因公消费的额度管控、费用控制和账单管理,区别于原文档的旅行社场景,本系统面向各类企业客户提供通用的因公付款解决方案。
+
+### 1.2 核心业务流程
+
+```
+企业入驻 → 部门管理 → 员工管理 → 费控制度创建 → 额度发放 → 员工消费 → 账单通知 → 对账结算
+```
+
+1. **企业入驻**:企业完成支付宝企业码服务签约开通
+2. **组织架构**:创建企业部门,添加/管理企业员工
+3. **员工激活**:员工通过二维码/链接完成支付宝协议确认,绑定企业
+4. **费控制度**:创建通用场景费控制度,设置使用规则和发放规则
+5. **额度管理**:为员工创建点券/额度,设定有效期和金额
+6. **因公消费**:员工出示企业码付款或扫码进行因公支付
+7. **账单同步**:消费记录实时通过账单变动通知同步给企业
+8. **对账结算**:企业查询账单详情,进行费用核销和对账
+
+***
+
+## 二、系统架构设计
+
+### 2.1 整体架构图
+
+```
+┌─────────────────────────────────────────────────────────────────┐
+│                         前端应用层                                │
+│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐             │
+│  │  Web管理后台 │  │  企业Portal │  │ 支付宝小程序 │             │
+│  └─────────────┘  └─────────────┘  └─────────────┘             │
+└─────────────────────────────────────────────────────────────────┘
+                              │
+                              ▼
+┌─────────────────────────────────────────────────────────────────┐
+│                         接口服务层                                │
+│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐             │
+│  │ 企业管理API  │  │ 员工管理API  │  │ 费控管理API  │             │
+│  └─────────────┘  └─────────────┘  └─────────────┘             │
+│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐             │
+│  │ 额度管理API  │  │ 账单查询API  │  │ 支付跳转API  │             │
+│  └─────────────┘  └─────────────┘  └─────────────┘             │
+└─────────────────────────────────────────────────────────────────┘
+                              │
+                              ▼
+┌─────────────────────────────────────────────────────────────────┐
+│                        业务服务层                                 │
+│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐             │
+│  │ 企业签约服务  │  │ 员工管理服务  │  │ 费控规则服务  │             │
+│  └─────────────┘  └─────────────┘  └─────────────┘             │
+│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐             │
+│  │ 额度发放服务  │  │ 账单处理服务  │  │ 消息通知服务  │             │
+│  └─────────────┘  └─────────────┘  └─────────────┘             │
+└─────────────────────────────────────────────────────────────────┘
+                              │
+                              ▼
+┌─────────────────────────────────────────────────────────────────┐
+│                      支付宝集成层                                 │
+│  ┌─────────────────────────────────────────────────────────────┐│
+│  │                    Alipay SDK                               ││
+│  │   企业码API │ 费控API │ 账单API │ 消息订阅(websocket/http)  ││
+│  └─────────────────────────────────────────────────────────────┘│
+└─────────────────────────────────────────────────────────────────┘
+                              │
+                              ▼
+┌─────────────────────────────────────────────────────────────────┐
+│                         数据存储层                               │
+│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐             │
+│  │ PostgreSQL  │  │  Redis      │  │ 文件存储     │             │
+│  │ 企业/员工/制度│  │ 额度/会话缓存 │  │ 账单凭证    │             │
+│  └─────────────┘  └─────────────┘  └─────────────┘             │
+└─────────────────────────────────────────────────────────────────┘
+```
+
+### 2.2 技术栈选型
+
+| 层级     | 技术选型                  | 说明              |
+| ------ | --------------------- | --------------- |
+| 后端框架   | Spring Boot / FastAPI | 根据团队技术栈选择       |
+| 数据库    | PostgreSQL 14+            | 存储企业、员工、费控等核心数据 |
+| 缓存     | Redis                 | 额度缓存、会话管理、幂等控制  |
+| 消息订阅   | WebSocket / HTTP      | 接收支付宝账单变动通知     |
+| 支付宝SDK | Alipay SDK            | 调用支付宝企业码相关接口    |
+| API文档  | Swagger/OpenAPI       | 接口文档化           |
+
+***
+
+## 三、核心模块设计
+
+### 3.1 企业管理模块
+
+**功能职责**:完成企业码服务的开通和入驻
+
+**核心接口**:
+
+| 接口名                                                 | 功能       | 优先级 |
+| --------------------------------------------------- | -------- | --- |
+| alipay.commerce.ec.enterprise.registerinvite.create | 邀请企业注册   | P0  |
+| alipay.commerce.ec.enterprise.change.notify         | 企业状态变更通知 | P0  |
+| alipay.commerce.ec.enterprise.info.query            | 查询企业详情   | P1  |
+| alipay.commerce.ec.enterprise.info.modify           | 修改企业信息   | P1  |
+| alipay.commerce.ec.enterprise.unsign                | 企业解约     | P2  |
+| alipay.commerce.ec.enterprise.delete                | 企业注销     | P2  |
+
+**数据结构**:
+
+```
+Enterprise {
+    enterprise_id: string      # 企业码企业ID
+    account_id: string         # 支付宝账号ID
+    name: string               # 企业名称
+    status: enum               # 注册/签约/解约/注销
+    created_at: datetime
+    updated_at: datetime
+}
+```
+
+### 3.2 员工管理模块
+
+**功能职责**:管理企业内部可使用因公付款的员工账号
+
+**核心接口**:
+
+| 接口名                                       | 功能       | 优先级 |
+| ----------------------------------------- | -------- | --- |
+| alipay.commerce.ec.employee.add           | 添加企业员工   | P0  |
+| alipay.commerce.ec.employee.delete        | 删除企业员工   | P0  |
+| alipay.commerce.ec.employee.change.notify | 员工变更通知   | P0  |
+| alipay.commerce.ec.employee.invite.query  | 获取员工邀请链接 | P1  |
+| alipay.commerce.ec.employee.info.modify   | 修改员工信息   | P1  |
+| alipay.commerce.ec.employee.info.query    | 查询员工详情   | P1  |
+| alipay.commerce.ec.employee.idlist.query  | 查询员工ID列表 | P1  |
+
+**数据结构**:
+
+```
+Employee {
+    employee_id: string        # 员工ID
+    enterprise_id: string     # 所属企业ID
+    alipay_user_id: string     # 支付宝用户ID
+    name: string               # 员工姓名
+    phone: string              # 手机号
+    department_id: string     # 部门ID
+    status: enum              # 待激活/已激活/已删除
+    bind_time: datetime       # 绑定时间
+}
+
+Department {
+    department_id: string     # 部门ID
+    enterprise_id: string     # 所属企业ID
+    name: string              # 部门名称
+    parent_id: string         # 上级部门ID
+}
+```
+
+### 3.3 费控制度模块
+
+**功能职责**:创建和管理企业的费用控制规则
+
+**核心接口**:
+
+| 接口名                                                 | 功能       | 优先级 |
+| --------------------------------------------------- | -------- | --- |
+| alipay.ebpp.invoice.institution.create              | 创建费控制度   | P0  |
+| alipay.ebpp.invoice.institution.modify              | 编辑费控制度   | P0  |
+| alipay.ebpp.invoice.institution.scopepageinfo.query | 查询制度适用成员 | P0  |
+| alipay.ebpp.invoice.institution.pageinfo.query      | 查询费控制度列表 | P1  |
+| alipay.ebpp.invoice.institution.detailinfo.query    | 查询制度详情   | P1  |
+| alipay.ebpp.invoice.institution.delete              | 删除费控制度   | P2  |
+
+**数据结构**:
+
+```
+ExpenseControl {
+    institution_id: string    # 费控制度ID
+    enterprise_id: string     # 所属企业ID
+    name: string              # 制度名称
+    expense_type: string      # 费用类型
+    expense_sub_type: string  # 费用类型子类
+    status: enum              # 生效/失效
+    created_at: datetime
+}
+
+ExpenseRule {
+    rule_id: string           # 规则ID
+    institution_id: string    # 所属制度ID
+    name: string              # 规则名称
+    max_amount: decimal       # 最大限额
+    valid_from: datetime      # 有效期开始
+    valid_to: datetime         # 有效期结束
+    merchant_pid: string       # 限定商户(可选)
+}
+```
+
+### 3.4 额度管理模块
+
+**功能职责**:管理员工的因公消费额度
+
+**核心接口**:
+
+| 接口名                                             | 功能       | 优先级 |
+| ----------------------------------------------- | -------- | --- |
+| alipay.ebpp.invoice.expensecontrol.quota.create | 创建手工发放额度 | P0  |
+| alipay.ebpp.invoice.expensecontrol.quota.query  | 查询员工可用额度 | P0  |
+| alipay.ebpp.invoice.expensecontrol.quota.modify | 修改手工发放额度 | P0  |
+| alipay.ebpp.invoice.expensecontrol.quota.delete | 删除额度     | P2  |
+
+**数据结构**:
+
+```
+Quota {
+    quota_id: string           # 额度ID
+    employee_id: string        # 员工ID
+    institution_id: string    # 费控制度ID
+    outer_source_id: string   # 外部来源ID(幂等)
+    total_amount: decimal      # 总金额
+    available_amount: decimal # 可用金额
+    valid_from: datetime       # 有效期开始
+    valid_to: datetime         # 有效期结束
+    status: enum              # 正常/冻结/已用完/已过期
+}
+```
+
+### 3.5 账单管理模块
+
+**功能职责**:接收和处理消费账单数据
+
+**核心接口**:
+
+| 接口名                                          | 功能       | 优先级 |
+| -------------------------------------------- | -------- | --- |
+| alipay.commerce.ec.consume.change.notify     | 账单变动通知   | P0  |
+| alipay.commerce.ec.consume.detail.query      | 账单详情查询   | P0  |
+| alipay.commerce.ec.consume.detail.batchquery | 账单批量分页查询 | P1  |
+| alipay.commerce.ec.balance.downloadurl.query | 对账单文件下载  | P2  |
+| alipay.commerce.ec.voucher.change.notify     | 凭证变动通知   | P1  |
+
+**数据结构**:
+
+```
+Bill {
+    bill_id: string            # 账单ID
+    trade_no: string           # 支付宝交易号
+    enterprise_id: string     # 企业ID
+    employee_id: string       # 员工ID
+    institution_id: string    # 费控制度ID
+    quota_id: string           # 额度ID
+    total_amount: decimal     # 账单金额
+    enterprise_pay_amount: decimal  # 企业付金额
+    personal_pay_amount: decimal    # 个人付金额
+    discount_amount: decimal   # 优惠金额
+    trade_time: datetime       # 交易时间
+    merchant_name: string      # 商户名称
+    status: enum              # 已支付/退款/关闭
+}
+
+Voucher {
+    voucher_id: string         # 凭证ID
+    bill_id: string            # 关联账单ID
+    content: json              # 凭证内容
+}
+```
+
+### 3.6 支付跳转模块
+
+**功能职责**:生成跳转链接,拉起支付宝扫一扫或付款码
+
+**核心接口**:
+
+| 功能     | 说明                     | 优先级 |
+| ------ | ---------------------- | --- |
+| 跳转扫一扫  | 生成openAlipayApp拉起扫一扫参数 | P0  |
+| 跳转付款码  | 生成schema拉起付款码参数        | P0  |
+| 跳转发票关联 | 生成发票关联页面跳转链接           | P1  |
+
+***
+
+## 四、消息通知机制
+
+### 4.1 通知类型
+
+| 通知类型   | 接口名                                         | 处理方式    |
+| ------ | ------------------------------------------- | ------- |
+| 企业状态变更 | alipay.commerce.ec.enterprise.change.notify | 更新企业状态  |
+| 员工变更   | alipay.commerce.ec.employee.change.notify   | 更新员工状态  |
+| 账单变动   | alipay.commerce.ec.consume.change.notify    | 创建/更新账单 |
+| 凭证变动   | alipay.commerce.ec.voucher.change.notify    | 更新凭证信息  |
+
+### 4.2 接入方式
+
+* **WebSocket长连接**:实时推送,延迟低
+
+* **HTTP回调**:简单实现,需要暴露公网接口
+
+***
+
+## 五、数据库表设计
+
+### 5.1 核心表结构
+
+```sql
+-- 企业表
+CREATE TABLE t_enterprise (
+    id BIGSERIAL PRIMARY KEY,
+    enterprise_id VARCHAR(64) NOT NULL UNIQUE,
+    account_id VARCHAR(64),
+    name VARCHAR(128) NOT NULL,
+    status VARCHAR(32) DEFAULT 'registered',
+    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+);
+
+-- 部门表
+CREATE TABLE t_department (
+    id BIGSERIAL PRIMARY KEY,
+    department_id VARCHAR(64) NOT NULL UNIQUE,
+    enterprise_id VARCHAR(64) NOT NULL,
+    name VARCHAR(128) NOT NULL,
+    parent_id VARCHAR(64),
+    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+);
+
+-- 员工表
+CREATE TABLE t_employee (
+    id BIGSERIAL PRIMARY KEY,
+    employee_id VARCHAR(64) NOT NULL UNIQUE,
+    enterprise_id VARCHAR(64) NOT NULL,
+    alipay_user_id VARCHAR(64),
+    name VARCHAR(64) NOT NULL,
+    phone VARCHAR(32),
+    email VARCHAR(128),
+    department_id VARCHAR(64),
+    status VARCHAR(32) DEFAULT 'pending',
+    bind_time TIMESTAMP,
+    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+);
+
+-- 费控制度表
+CREATE TABLE t_expense_institution (
+    id BIGSERIAL PRIMARY KEY,
+    institution_id VARCHAR(64) NOT NULL UNIQUE,
+    enterprise_id VARCHAR(64) NOT NULL,
+    name VARCHAR(128) NOT NULL,
+    expense_type VARCHAR(32) DEFAULT 'DEFAULT',
+    expense_sub_type VARCHAR(32) DEFAULT 'DEFAULT',
+    status VARCHAR(32) DEFAULT 'active',
+    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+);
+
+-- 使用规则表
+CREATE TABLE t_expense_rule (
+    id BIGSERIAL PRIMARY KEY,
+    rule_id VARCHAR(64) NOT NULL UNIQUE,
+    institution_id VARCHAR(64) NOT NULL,
+    name VARCHAR(128),
+    max_amount DECIMAL(12,2),
+    valid_from TIMESTAMP,
+    valid_to TIMESTAMP,
+    merchant_pid VARCHAR(64),
+    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+);
+
+-- 额度表
+CREATE TABLE t_quota (
+    id BIGSERIAL PRIMARY KEY,
+    quota_id VARCHAR(64) NOT NULL UNIQUE,
+    employee_id VARCHAR(64) NOT NULL,
+    institution_id VARCHAR(64) NOT NULL,
+    outer_source_id VARCHAR(64) NOT NULL,
+    total_amount DECIMAL(12,2) NOT NULL,
+    available_amount DECIMAL(12,2) NOT NULL,
+    valid_from TIMESTAMP NOT NULL,
+    valid_to TIMESTAMP NOT NULL,
+    status VARCHAR(32) DEFAULT 'active',
+    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+);
+
+-- 账单表
+CREATE TABLE t_bill (
+    id BIGSERIAL PRIMARY KEY,
+    bill_id VARCHAR(64) NOT NULL UNIQUE,
+    trade_no VARCHAR(64) NOT NULL,
+    enterprise_id VARCHAR(64) NOT NULL,
+    employee_id VARCHAR(64) NOT NULL,
+    institution_id VARCHAR(64),
+    quota_id VARCHAR(64),
+    total_amount DECIMAL(12,2) NOT NULL,
+    enterprise_pay_amount DECIMAL(12,2) DEFAULT 0,
+    personal_pay_amount DECIMAL(12,2) DEFAULT 0,
+    discount_amount DECIMAL(12,2) DEFAULT 0,
+    trade_time TIMESTAMP,
+    merchant_name VARCHAR(256),
+    status VARCHAR(32) DEFAULT 'paid',
+    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+);
+
+-- 凭证表
+CREATE TABLE t_voucher (
+    id BIGSERIAL PRIMARY KEY,
+    voucher_id VARCHAR(64) NOT NULL UNIQUE,
+    bill_id VARCHAR(64) NOT NULL,
+    content JSONB,
+    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+);
+
+-- 操作日志表
+CREATE TABLE t_operation_log (
+    id BIGSERIAL PRIMARY KEY,
+    operation_type VARCHAR(64) NOT NULL,
+    enterprise_id VARCHAR(64),
+    employee_id VARCHAR(64),
+    request_data JSONB,
+    response_data JSONB,
+    status VARCHAR(32),
+    error_message TEXT,
+    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+);
+
+-- 添加更新触发器函数
+CREATE OR REPLACE FUNCTION update_updated_at_column()
+RETURNS TRIGGER AS $$
+BEGIN
+    NEW.updated_at = CURRENT_TIMESTAMP;
+    RETURN NEW;
+END;
+$$ language 'plpgsql';
+
+-- 为需要自动更新updated_at的表创建触发器
+CREATE TRIGGER update_t_enterprise_updated_at
+    BEFORE UPDATE ON t_enterprise
+    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
+
+CREATE TRIGGER update_t_employee_updated_at
+    BEFORE UPDATE ON t_employee
+    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
+
+CREATE TRIGGER update_t_expense_institution_updated_at
+    BEFORE UPDATE ON t_expense_institution
+    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
+
+CREATE TRIGGER update_t_quota_updated_at
+    BEFORE UPDATE ON t_quota
+    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
+
+CREATE TRIGGER update_t_bill_updated_at
+    BEFORE UPDATE ON t_bill
+    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
+```
+
+***
+
+## 六、接口设计
+
+### 6.1 企业管理接口
+
+| 接口                                         | 方法     | 说明     |
+| ------------------------------------------ | ------ | ------ |
+| POST /api/enterprise/invite                | 创建企业邀请 | 获取注册链接 |
+| GET /api/enterprise/{enterpriseId}         | 查询企业详情 | <br /> |
+| PUT /api/enterprise/{enterpriseId}         | 修改企业信息 | <br /> |
+| POST /api/enterprise/{enterpriseId}/unsign | 企业解约   | <br /> |
+| POST /api/enterprise/{enterpriseId}/delete | 企业注销   | <br /> |
+
+### 6.2 员工管理接口
+
+| 接口                                        | 方法     | 说明     |
+| ----------------------------------------- | ------ | ------ |
+| POST /api/employee                        | 添加员工   | <br /> |
+| DELETE /api/employee/{employeeId}         | 删除员工   | <br /> |
+| GET /api/employee/{employeeId}            | 查询员工详情 | <br /> |
+| PUT /api/employee/{employeeId}            | 修改员工信息 | <br /> |
+| GET /api/employee/list                    | 查询员工列表 | <br /> |
+| GET /api/employee/{employeeId}/invite-url | 获取邀请链接 | <br /> |
+
+### 6.3 费控管理接口
+
+| 接口                                            | 方法     | 说明     |
+| --------------------------------------------- | ------ | ------ |
+| POST /api/institution                         | 创建费控制度 | <br /> |
+| PUT /api/institution/{institutionId}          | 编辑费控制度 | <br /> |
+| GET /api/institution/{institutionId}          | 查询制度详情 | <br /> |
+| GET /api/institution/list                     | 查询制度列表 | <br /> |
+| DELETE /api/institution/{institutionId}       | 删除费控制度 | <br /> |
+| POST /api/institution/{institutionId}/members | 编辑制度成员 | <br /> |
+
+### 6.4 额度管理接口
+
+| 接口                                   | 方法       | 说明     |
+| ------------------------------------ | -------- | ------ |
+| POST /api/quota                      | 创建额度     | <br /> |
+| GET /api/quota/{quotaId}             | 查询额度详情   | <br /> |
+| GET /api/quota/employee/{employeeId} | 查询员工可用额度 | <br /> |
+| PUT /api/quota/{quotaId}             | 修改额度     | <br /> |
+| DELETE /api/quota/{quotaId}          | 删除额度     | <br /> |
+
+### 6.5 账单管理接口
+
+| 接口                     | 方法     | 说明     |
+| ---------------------- | ------ | ------ |
+| GET /api/bill/{billId} | 查询账单详情 | <br /> |
+| GET /api/bill/list     | 查询账单列表 | <br /> |
+| GET /api/bill/download | 下载对账单  | <br /> |
+
+### 6.6 支付跳转接口
+
+| 接口                        | 方法         | 说明     |
+| ------------------------- | ---------- | ------ |
+| POST /api/pay/scan-url    | 生成扫一扫跳转链接  | <br /> |
+| POST /api/pay/code-url    | 生成付款码跳转链接  | <br /> |
+| POST /api/pay/invoice-url | 生成发票关联跳转链接 | <br /> |
+
+***
+
+## 七、实施计划
+
+### 阶段一:基础能力建设(2-3周)
+
+1. **环境准备**
+
+   * 完成支付宝开放平台账号注册和认证
+
+   * 创建自研应用(小程序或网页应用)
+
+   * 配置密钥,完成应用上线
+
+2. **框架搭建**
+
+   * 项目工程创建,依赖配置
+
+   * 数据库设计和初始化
+
+   * 支付宝SDK集成和配置
+
+3. **核心功能开发**
+
+   * 企业管理模块(入驻、签约)
+
+   * 员工管理模块(增删改查)
+
+   * 消息订阅机制实现
+
+**交付物**:
+
+* 基础项目框架
+
+* 数据库表结构脚本
+
+* 企业管理、员工管理API
+
+### 阶段二:费控和额度模块(2-3周)
+
+1. **费控制度管理**
+
+   * 费控制度CRUD
+
+   * 使用规则管理
+
+   * 成员范围管理
+
+2. **额度管理**
+
+   * 额度创建和发放
+
+   * 额度查询和修改
+
+   * 有效期管理
+
+**交付物**:
+
+* 费控管理API
+
+* 额度管理API
+
+* 管理后台界面原型
+
+### 阶段三:账单和支付模块(2-3周)
+
+1. **账单管理**
+
+   * 账单通知接收和处理
+
+   * 账单查询和对账
+
+   * 凭证管理
+
+2. **支付跳转**
+
+   * 扫一扫跳转链接生成
+
+   * 付款码跳转链接生成
+
+   * H5/小程序端集成
+
+**交付物**:
+
+* 账单管理API
+
+* 支付跳转功能
+
+* 完整业务流程联调
+
+### 阶段四:测试和上线(1-2周)
+
+1. **测试**
+
+   * 单元测试编写
+
+   * 接口联调测试
+
+   * 场景测试
+
+2. **上线**
+
+   * 生产环境部署
+
+   * 支付宝产品包挂载
+
+   * 消息订阅配置
+
+   * 正式环境联调
+
+**交付物**:
+
+* 测试报告
+
+* 部署文档
+
+* 用户手册
+
+***
+
+## 八、风险点和注意事项
+
+### 8.1 关键风险
+
+| 风险点     | 影响    | 应对措施        |
+| ------- | ----- | ----------- |
+| 支付宝接口限流 | 业务中断  | 添加限流保护,本地缓存 |
+| 消息通知丢失  | 账单不一致 | 定期对账,主动查询补全 |
+| 额度超用    | 资金损失  | 额度预冻结机制     |
+| 员工删除后消费 | 纠纷    | 删除前检查待生效额度  |
+
+### 8.2 注意事项
+
+1. **幂等性**:所有写操作接口需保证幂等,使用outer\_source\_id控制
+2. **安全性**:敏感数据加密存储,接口权限校验
+3. **日志**:完整记录所有操作,便于问题排查
+4. **监控**:接口调用监控,异常告警
+
+***
+
+## 九、参考文档
+
+* 支付宝开放平台文档:<https://opendocs.alipay.com/>
+
+* 企业码产品文档:<https://opendocs.alipay.com/open/01qX5z>
+
+* 消息订阅接入:<https://opendocs.alipay.com/open/10381/gh4emp>
+

+ 601 - 0
技术集成指南.md

@@ -0,0 +1,601 @@
+# 技术集成指南
+
+## 集成交互说明
+
+![集成交互流程](https://cdn.nlark.com/yuque/0/2023/png/25758943/1692675283450-908be34c-4234-4f26-bc55-6b8eb39e9259.png)
+
+### 业务流程说明
+
+1. 旅行社通过"企业签约"接口完成企业码服务开通和入驻。
+2. 可以根据需要"创建部门"接口来管理旅行社不同门店。并通过"添加企业员工"接口来添加导游名单,员工离职后通过"删除企业员工"接口从企业码中删除该名员工。
+3. 员工名单添加后,通过二维码,或者链接跳转的方式,让员工通过自己的支付宝账户完成企业码协议确认,以完成员工与企业的激活和绑定。
+4. 先通过"创建费控制度"创建通用场景费控制度,通过"编辑费控制度成员"接口将旅行社的导游都添加到费控制度下。导游根据旅行社内部备用金审批流程完成备用金的申请,审批流程走完后,通过"创建手工发放额度"接口,为员工创建一个点券类型的额度,可消费时间范围、金额与备用金申请条件一致。
+5. 导游在带团过程中,需要使用备用金进行消费时,进入企业码小程序,出示企业码付款码,或者企业码的扫一扫,进行企业码因公消费。点券到期后,将不可使用企业因公资金进行消费,出示企业码,会使用个人账户资产完成消费支付。
+6. 导游消费后,消费记录会实时通过"账单变动通知"同步给到旅行社。
+
+> **注意**: 以上的应用只是个参考案例,我们是要做一个类似因公付款服务系统,但不是关于旅行社的。你只需要参考结构。
+
+***
+
+## 1. 集成工作流程说明
+
+### 1.1 集成步骤
+
+1. 企业支付宝账号注册,[点击查看指导手册](https://opendocs.alipay.com/open/200/qyzfbsmrz)。
+2. 联系合作BD签约支付宝销售方案。
+   - a. 甲方企业需要签署"企业报销码KA合作"销售方案。
+   - b. 企业码合作的服务商,需要签署"企业码服务商合作"销售方案。
+3. 销售方案签约后会自动生成Appid用于接口调用。也可以创建自研服务的应用"[小程序](https://opendocs.alipay.com/mini/)"或"[网页&移动应用](https://opendocs.alipay.com/open/200/105310)",并将应用的Appid提供给支付宝PD完成产品包挂载添加权限。
+   - 所使用的自研服务应用则需要完成:"配置密钥" 和 "[上线应用](https://opendocs.alipay.com/open/200/golive)"。
+   - 小程序应用:审核通过后自动上线。
+   - 网页/移动应用:需要手动上线。提交审核后,预计 1 个工作日的审核时间,需请耐心等待,详细步骤可查看 [上线应用](https://opendocs.alipay.com/open/200/golive/)。
+   - 订阅消息接入,待完成产品包挂载后即可订阅相关消息(说明:若未挂载相应产品包将无法订阅相关消息接口)。消息订阅路径:支付宝开放平台-控制台-开发设置-FROM平台。
+
+![消息接入](https://cdn.nlark.com/yuque/0/2022/png/232948/1670222689950-bba83581-a2d9-451c-9c20-618f279ba695.png)
+
+> **说明**: 消息接入方式支持 websocket长连接 和 http(s) 两种接入任选其一即可,详情可点击查看From蚂蚁消息服务使用。
+
+1. 协议签署,通过"企业签约"接口完成入驻。
+2. 按下面技术方案内容进行接口开发。
+3. 在生产环境进行联调测试。
+4. 上线。
+
+### 1.2 集成前准备
+
+#### 1.2.1 开发前准备
+
+查看[开放平台文档](https://opendocs.alipay.com/open/01csp3#%E9%9B%86%E6%88%90%E5%B9%B6%E9%85%8D%E7%BD%AE%20SDK),完成以下两步准备工作:
+
+1. 集成并配置SDK
+2. 接口调用配置
+
+#### 1.2.2 企业码接口通用参数说明
+
+- **charset**(字符集):`utf-8`
+- **企业ID**(企业入驻企业码生成的企业id)入参说明:
+  - `enterprise_id`,2.0版本接口生成的企业id
+
+***
+
+## 2. 企业码接口
+
+### 2.1 员企业关系管理
+
+#### 2.1.1 企业管理
+
+企业需要开通企业码服务,需要通过下面的接口完成企业码服务的开通。支持服务商引入企业开通,也支持每个企业进行单独开通。
+
+![企业管理流程](https://mdn.alipayobjects.com/afts/img/A*bGW3RpTJ6wkAAAAAR4AAAAgAeq8wAA/original?bz=openpt_doc\&t=jFA0EujoL2MttD0BJbYbGR1jGLNc3ef-hHBiRFUlbAQDAAAAZAAAMK8AAAAA)
+
+##### 2.1.1.1 邀请企业注册
+
+**接口名**: `alipay.commerce.ec.enterprise.registerinvite.create`
+
+**功能说明**: 获取企业码-企业注册/认证/签约三合一页面的链接地址,适用于邀请企业或代理企业开通企业码
+
+- 企业自研系统入驻,可以通过企业支付宝账号登录[企业码PC端](https://qiyema.alipay.com/) 完成企业签约开通。
+- 企业通过接口入驻或者服务商代入驻,可以使用接口创建企业
+- 如果是服务商代企业开通的情况,企业名称需要填写和企业营业执照一致的名字,企业才会成为认证状态使用更多能力,否则无法使用企业码。
+
+![企业注册流程](https://mdn.alipayobjects.com/afts/img/A*TXksTYF_nCMAAAAATxAAAAgAeq8wAA/original?bz=openpt_doc\&t=VwPGn0-Vw8oFeMbXhP40EGKnzHZl-89LR7cTOxmjww0DAAAAZAAAMK8AAAAA)
+
+**参数说明**: <https://opendocs.alipay.com/pre-open/59de3d66_alipay.commerce.ec.enterprise.registerinvite.create?pathHash=ad13ca47>
+
+![参数说明](https://cdn.nlark.com/yuque/0/2022/png/224831/1661180823534-a15d3790-2221-423a-a1c5-394c14c1a974.png)
+
+##### 2.1.1.2 企业状态变更通知
+
+**接口名**: `alipay.commerce.ec.enterprise.change.notify`
+
+**功能说明**: 企业相关状态变化产生的通知信息,包括企业签约成功,企业注销等状态通知。
+
+**参数说明**: <https://opendocs.alipay.com/apis/0477mu>
+
+**支付宝通知类消息接入说明**: <https://opendocs.alipay.com/open/10381/gh4emp>
+
+##### 2.1.1.3 其他可选接口
+
+**1. 企业解约【可选】**
+
+- **接口名**: `alipay.commerce.ec.enterprise.unsign`
+- **功能说明**: 企业解约,获取解约链接,点击链接跳转到解约页面,进行资金协议解约。
+- **参数说明**: <https://opendocs.alipay.com/apis/04j719>
+
+**2. 企业注销【可选】**
+
+- **接口名**: `alipay.commerce.ec.enterprise.delete`
+- **功能说明**: 企业注销,并清理企业数据,企业及员工不再能使用企业码服务。注销前,请先完成企业解约(alipay.commerce.ec.enterprise.unsign)。
+- **参数说明**: <https://opendocs.alipay.com/apis/04iyzd>
+
+**3. 查询企业详情【可选】**
+
+- **接口名**: `alipay.commerce.ec.enterprise.info.query`
+- **功能说明**: 查询企业详细信息
+- **参数说明**: <https://opendocs.alipay.com/apis/04jcz1>
+
+**4. 修改企业信息【可选】**
+
+- **接口名**: `alipay.commerce.ec.enterprise.info.modify`
+- **功能说明**: 目前主要支持修改企业简称。
+- **参数说明**: <https://opendocs.alipay.com/apis/04eukp>
+
+#### 2.1.2 员工管理
+
+用来管理可申请备用金的导游支付宝账户。
+
+##### 2.1.2.1 添加企业员工
+
+**接口名**: `alipay.commerce.ec.employee.add`
+
+**功能说明**: 通过接口同步企业员工信息,并获取员工加入企业码链接。员工绑定开通后,即建立企业账号与员工账号的关联关系。并将结果通知给到企业。
+
+**参数说明**: <https://opendocs.alipay.com/apis/047c5n>
+
+**重要参数说明**:
+
+- `department_ids`为部门列表,目前只支持员工在一个部门里,不支持跨多个部门。
+- `sign_url`每个企业返回的链接都是固定的,且永久有效
+
+**手机号/邮箱邀请员工加入交互逻辑说明**:
+
+![员工加入流程](https://cdn.nlark.com/yuque/0/2022/png/224831/1662385873146-edd4a786-f3a4-4c70-a76d-e0e6eb7bb3af.png)
+
+**手机号/邮箱邀请员工身份确认逻辑说明**: 员工开通服务时,入参传入员工在企业预留的手机号/邮箱和员工姓名,支付宝会唤起短信校验码页面让员工进行校验,校验一致,则完成员企业关系绑定。
+
+![身份确认流程](https://cdn.nlark.com/yuque/0/2022/png/224831/1662389849644-d543d812-8018-41b2-9531-9c964881a663.png)
+
+**员工加入企业的固定链接**:
+
+- 员工同意加入需要员工访问支付宝页面进行签约操作。
+- 将企业签约完成后获取到的 accountId 企业账号拼接到 `alipays://platformapi/startapp?appId=2021002128690179&page=pages%2Fopen%2Finvite%2Fsign%2Findex%3FaccountId%3D` 地址后面,生成二维码让员工扫码加入企业。
+- **注**: 该链接中`appId=2021002128690179`为固定值,不需要进行变更。
+- 该二维码是基于企业账号维度的,生成一次即可,员工加入可以重复使用。只有被邀请过的员工加入才会继续流程,没有被邀请过的扫码后无法加入企业。
+- 完整链接如下所示:
+  ```
+  alipays://platformapi/startapp?appId=2021002128690179&page=pages%2Fopen%2Finvite%2Fsign%2Findex%3FaccountId%3D2088000330796***.
+  ```
+
+**小程序跳转企业码签约页面方案**:
+
+小程序按下面代码示例调用,跳转企业码员工签约授权页,只需要替换掉enterpriseId后面的值为自己企业的enterpriseId。**不要改appId的值!不要改appId的值!不要改appId的值!**
+
+**旅行社场景按如下表格圈选字段及示意枚举值传参即可**:
+
+![字段说明](https://cdn.nlark.com/yuque/0/2024/png/25758943/1716187605316-d4b959fd-1bcd-4a6d-af79-f87e8af2c960.png)
+
+##### 2.1.2.2 删除企业员工
+
+**接口名**: `alipay.commerce.ec.employee.delete`
+
+**功能说明**: 通过接口删除企业码已离职员工。
+
+**参数说明**: <https://opendocs.alipay.com/apis/04763u>
+
+##### 2.1.2.3 员工变更通知
+
+**接口名**: `alipay.commerce.ec.employee.change.notify`
+
+**功能说明**: 员工变更通知,包括:员工新增、激活、信息修改、部门修改、角色修改和删除
+
+**参数说明**: <https://opendocs.alipay.com/apis/03s8k8>
+
+##### 2.1.2.4 其他可选接口
+
+**1. 获取员工邀请链接【可选】**
+
+- **接口名**: `alipay.commerce.ec.employee.invite.query`
+- **功能说明**: 获取员工邀请链接。返回的sign\_url与员工邀请接口返回的sign\_url一致,链接都是固定的,且永久有效。
+- **参数说明**: <https://opendocs.alipay.com/apis/04irne>
+
+**2. 修改员工信息【可选】**
+
+- **接口名**: `alipay.commerce.ec.employee.info.modify`
+- **功能说明**: 修改员工信息
+- **参数说明**: <https://opendocs.alipay.com/apis/04ipsd>
+
+**3. 查询员工详情【可选】**
+
+- **接口名**: `alipay.commerce.ec.employee.info.query`
+- **功能说明**: 通过员工id查询企业码中员工信息。
+- **参数说明**: <https://opendocs.alipay.com/apis/03s0gz>
+
+**4. 查询员工id列表【可选】**
+
+- **接口名**: `alipay.commerce.ec.employee.idlist.query`
+- **功能说明**: 批量查询加入企业的员工id。
+- **参数说明**: <https://opendocs.alipay.com/apis/03sb6y>
+
+**5. 企业升级高级认证【可选】**
+
+- **接口名**: `alipay.commerce.ec.enterprise.auth.apply`
+- **功能说明**: 已注册企业从初级认证升级高级认证。
+- **参数说明**: <https://opendocs.alipay.com/apis/06hmnw>
+
+### 2.2 费用控制管理
+
+**旅行社备用金场景费用控制建议交互逻辑**:
+
+![费用控制流程](https://cdn.nlark.com/yuque/0/2022/png/224831/1669617618685-410f1dd1-4ab4-44a1-9cca-43523ac40ca3.png)
+
+#### 2.2.1 费控制度管理
+
+##### 2.2.1.1 创建费控制度
+
+**接口名**: `alipay.ebpp.invoice.institution.create`
+
+**功能说明**: 创建费控制度。
+
+- 创建费控制度时的入参中至少同时要创建一条使用规则,发放规则不是必须同时创建。
+- 其中使用规则名称在企业码小程序端用户可见,费控制度名称不可见。
+- 创建制度后,再通过编辑费控制度成员接口进行制度下成员管理
+
+**参数说明**: <https://opendocs.alipay.com/apis/049l40>
+
+**费用类型及子类**:
+
+- 对于旅行社备用金来说,可以不限制可消费商户,费用类型和费用类型子类都用`DEFAULT`即可。
+- 旅行社使用 手工发放接口 进行额度管控即可,不要设置使用规则限额
+
+**旅行社场景按如下表格圈选字段及示意枚举值传参即可**:
+
+![字段说明1](https://cdn.nlark.com/yuque/0/2023/png/25758943/1695287030313-2e9512f5-0082-4a0a-bb6c-7e0d70fe62e5.png)
+
+![字段说明2](https://cdn.nlark.com/yuque/0/2023/png/25758943/1695287144351-c3edfd90-dff6-4e71-9a92-df3a3499e1b2.png)
+
+![字段说明3](https://cdn.nlark.com/yuque/0/2023/png/25758943/1695287215178-3fa81a74-90db-437e-8a94-5fc58b56d311.png)
+
+![字段说明4](https://cdn.nlark.com/yuque/0/2023/png/25758943/1695287319910-e3e1b3e3-edcc-4a41-a013-15a30431f15b.png)
+
+![字段说明5](https://cdn.nlark.com/yuque/0/2023/png/25758943/1695293610034-3394d00c-6a4b-43cd-b489-0f059c48606d.png)
+
+![字段说明6](https://cdn.nlark.com/yuque/0/2023/png/25758943/1699605009207-961d01ac-d601-4b55-8326-ebbe4b5dfba2.png)
+
+![字段说明7](https://cdn.nlark.com/yuque/0/2023/png/25758943/1699605044789-e8712b19-5f76-44e0-b865-f86187e61e66.png)
+
+**standard\_condition\_info\_list字段传值参考**:
+
+| 使用时间                 | 说明                     |
+| -------------------- | ---------------------- |
+| 【ALARM\_CLOCK\_TIME】 | 1、时间不限: `{"all":true}` |
+
+**定向支付,指定商户**:
+
+| 字段                         | 是否必填 | 枚举值               |
+| -------------------------- | ---- | ----------------- |
+| 费用类型【expense\_type】        | 是    | 餐饮【MEAL】          |
+| 费用类型子类【expense\_sub\_type】 | 是    | 中餐【CHINESE\_FOOD】 |
+| 商户PID【merchant\_pid】       | 是    | 商户PID,2088开头      |
+
+##### 2.2.1.2 编辑费控制度
+
+**接口名**: `alipay.ebpp.invoice.institution.modify`
+
+**功能说明**: 编辑费控制度完整信息。
+
+**参数说明**: <https://opendocs.alipay.com/apis/049zmk>
+
+##### 2.2.1.3 查询费控制度适用成员范围
+
+**接口名**: `alipay.ebpp.invoice.institution.scopepageinfo.query`
+
+**功能说明**: 查询制度下成员列表,支持分页查询。
+
+**参数说明**: <https://opendocs.alipay.com/apis/04a389>
+
+##### 2.2.1.4 其他可选接口
+
+**1. 查询费控制度列表【可选】**
+
+- **接口名**: `alipay.ebpp.invoice.institution.pageinfo.query`
+- **功能说明**: 查询企业下所有创建的费控制度,支持分页查询。
+- **参数说明**: <https://opendocs.alipay.com/apis/049hlt>
+
+**2. 查询单个费控制度详情【可选】**
+
+- **接口名**: `alipay.ebpp.invoice.institution.detailinfo.query`
+- **功能说明**: 查询单个费控制度详细信息,包含制度下使用规则列表和发放规则列表。
+- **参数说明**: <https://opendocs.alipay.com/apis/049zml>
+
+**3. 删除费控制度**
+
+- **接口名**: `alipay.ebpp.invoice.institution.delete`
+- **功能说明**: 删除制度,删除制度下使用规则和发放规则以及制度下人员关系。制度关联的发放规则和已发放的券或者额度都会被清除,不可再使用。
+- **参数说明**: <https://opendocs.alipay.com/apis/049vo9>
+
+#### 2.2.2 手工发放额度管理
+
+##### 2.2.2.1 创建手工发放额度
+
+**接口名**: `alipay.ebpp.invoice.expensecontrol.quota.create`
+
+**功能说明**: 创建用户可用额度。target\_type用INSTITUTION(费控制度)来创建,target\_id用前面创建的费控制度id(institution\_id)。
+
+- 为每个员工单独创建。
+- outer\_source\_id用来控制幂等。
+
+**关键入参**: <https://opendocs.alipay.com/apis/02f6m7>
+
+##### 2.2.2.2 查询员工可用额度
+
+**接口名**: `alipay.ebpp.invoice.expensecontrol.quota.query`
+
+**功能说明**: 查询员工可用额度值。
+
+**关键入参**: <https://opendocs.alipay.com/apis/02f6m8>
+
+##### 2.2.2.3 修改手工发放额度
+
+**接口名**: `alipay.ebpp.invoice.expensecontrol.quota.modify`
+
+**功能说明**: 可对额度进行增加、扣减等操作。
+
+**关键入参**: <https://opendocs.alipay.com/apis/02f7v9>
+
+**修改额度场景说明**:
+
+- **case1**: 修改金额不修改有效期日期时间,需要用4.2.2.3修改手工发放额度,将额度进行变更
+- **case2**: 额度修改涉及有效期时间,需要先用4.2.2.3将额度调整成0,再用4.2.2.1重新发放额度
+
+##### 2.2.2.4 其他可选接口
+
+**1. 删除额度**
+
+- **接口名**: `alipay.ebpp.invoice.expensecontrol.quota.delete`
+- **功能说明**: 可对余额/点券进行删除操作;已经有过使用记录的点券无法删除
+- **关键入参**: <https://opendocs.alipay.com/pre-open/3cf6a733_alipay.ebpp.invoice.expensecontrol.quota.delete?pathHash=a8c8bb78>
+
+#### 2.2.3 使用规则管理
+
+##### 2.2.3.1 编辑使用规则
+
+**接口名**: `alipay.ebpp.invoice.institution.expenserule.modify`
+
+**功能说明**: 编辑使用规则属性。
+
+**参数说明**: <https://opendocs.alipay.com/apis/049n7a>
+
+##### 2.2.3.1 其他可选接口
+
+**1. 创建使用规则**
+
+- **接口名**: `alipay.ebpp.invoice.institution.expenserule.create`
+
+**功能说明**: 创建使用规则,场景和费用类型需要和制度一致,有效期起始、结束时间、关联人员与制度保持一致。
+
+**参数说明**: <https://opendocs.alipay.com/apis/049e73>
+
+**2. 删除使用规则**
+
+- **接口名**: `alipay.ebpp.invoice.institution.expenserule.delete`
+
+**功能说明**: 删除使用规则。如果是制度下唯一使用规则,则使用规则不能被删除。
+
+**参数说明**: <https://opendocs.alipay.com/apis/049m7m>
+
+2.4 账单&订单信息获取
+
+![image.png](https://mdn.alipayobjects.com/afts/img/A*6de1QpMVxE4AAAAAZGAAAAgAeq8wAA/original?bz=openpt_doc\&t=qOIHDqiIi1PwpgQXCGrluWAKvKaBCCsO-Lib0mj8uu4DAAAAZAAAMK8AAAAA)
+
+### 2.4.1 支付账单信息获取
+
+#### 2.4.1.1 账单变动通知
+
+**接口名**: `alipay.commerce.ec.consume.change.notify`
+
+**功能说明**: 单笔交易信息账单关联凭证发生变化时通知。
+
+**参数说明**: <https://opendocs.alipay.com/apis/03t2yt>
+
+**支付宝通知类消息接入说明**: <https://opendocs.alipay.com/open/10381/gh4emp>
+
+#### 2.4.1.2 账单详情查询
+
+**接口名**: `alipay.commerce.ec.consume.detail.query`
+
+**功能说明**: 获取消费账单详情数据和相关凭证数据。
+
+**参数说明**: <https://opendocs.alipay.com/apis/03t1jw>
+
+- `voucher_content`字段结构介绍: <https://opendocs.alipay.com/pre-open/07d3dg>
+- 账单需区分企业付金额,相关字段处理逻辑如下:
+  - 企业付金额:直接用;
+  - 个人付金额:账单金额—企业付金额=个人付金额;
+  - 优惠:订单金额—账单金额=优惠金额
+
+#### 2.4.1.3 其他可选接口
+
+**1. 账单详情批量分页查询**
+
+- **接口名**: `alipay.commerce.ec.consume.detail.batchquery`
+- **功能说明**: 批量分页查询企业消费账单详情数据
+- **参数说明**: <https://opendocs.alipay.com/pre-open/542e9778_alipay.commerce.ec.consume.detail.batchquery?scene=common&pathHash=85f04459>
+
+> **注意**: 入参中的`start_date`和`end_date`为前闭后开,例如需要查询2021-01-01当天的所有账单,则`start_date`取"2021-01-01 00:00:00",`end_date`取"2021-01-02 00:00:00"
+
+**2. 对账单文件下载**
+
+- **接口名**: `alipay.commerce.ec.balance.downloadurl.query`
+- **功能说明**: 支持按日或者月获取账单文件下载链接,日期不能为当日或者当月。
+- **参数说明**: <https://opendocs.alipay.com/apis/03tmlu>
+
+### 2.4.2 账单关联凭证获取
+
+#### 2.4.2.1 凭证变动通知
+
+**接口名**: `alipay.commerce.ec.voucher.change.notify`
+
+**功能说明**: 单笔交易账单关联凭证发生变化时通知。
+
+**参数说明**: <https://opendocs.alipay.com/apis/04bl9s>
+
+**支付宝通知类消息接入说明**: <https://opendocs.alipay.com/open/10381/gh4emp>
+
+#### 2.4.2.2 账单及关联凭证详情查询
+
+**接口名**: `alipay.commerce.ec.consume.detail.query`
+
+**功能说明**: 获取消费账单详情数据和相关凭证数据。
+
+**参数说明**: <https://opendocs.alipay.com/apis/03t1jw>
+
+<br />
+
+<br />
+
+### 2.5 跳转扫一扫/付款码页面
+
+#### 2.5.1 跳转扫一扫
+
+通过 `openAlipayApp` 拉起扫一扫,调用方式如下:
+
+```javascript
+my.ap.openAlipayApp({
+  appCode: 'alipayScan',
+  appParams: {
+    externalThrough: {params}
+  }
+})
+```
+
+**参数说明**:
+
+其中标为黄色的区域,取值如下:
+
+- `{params}` 是需要携带的因公付拓展参数使用 Json 格式字符串
+
+**params参数说明**:
+
+- **pdSubBizScene**: 支付决策子场景
+  - 默认值: `enterprisePay`,适用: 收钱码,当面付,铁路线下支付
+- **specifiedEnableChannelInfo**
+  - 按照示例传参,仅需要替换`assetId`为共同账户id(accountId,从[企业签约状态变更消息通知](https://opendocs.alipay.com/apis/0477mu)里获取)
+- **assignJointAccountId**: 共同账户id(accountId,从[企业签约状态变更消息通知](https://opendocs.alipay.com/apis/0477mu)里获取)
+- **identityPayBizInfo**: 企业码身份付业务字段
+  - `identityPayBizScene`: `ENTERPRISE_CODE`
+  - `identityPaySubBizScene`: `ISV_PAY`
+  - `groupId`: 共同账户id(accountId,从[企业签约状态变更消息通知](https://opendocs.alipay.com/apis/0477mu)里获取)
+  - `bizGroupId`: 共同账户id(accountId,从[企业签约状态变更消息通知](https://opendocs.alipay.com/apis/0477mu)里获取)
+  - `expenseGroupId`: 费控规则id(当需要指定费控规则id消费时可传入此字段,可从创建[费控制度接口](https://opendocs.alipay.com/apis/049l40)出参获取)
+- **CHANNEL_INDEX**: 渠道
+  - 传入固定值: `ENTERPRISEPAYASSET_DC_ENTERPRISEPAY_DEFAULT`
+- **sourcePlatformInfo**: 企业码因公付大字段
+  - `ruleGroupId`: 费控规则id(当需要指定费控规则id消费时可传入此字段,可从创建[费控制度接口](https://opendocs.alipay.com/apis/049l40)出参获取)
+  - `paymentId`: 付款事由(paymentId为服务商付款事由ID,通过此字段服务商可做到精确对账)
+  - `isvAppId`: 三方小程序appId(必传,涉及到后面服务商政策)
+
+**接入示例**:
+
+1. 准备所需要的参数,将参数转换为 JSON 结构并压缩(注意 key-value 都是字符串):
+
+```json
+{
+  "pdSubBizScene": "enterprisePay",
+  "specifiedEnableChannelInfo": "{\"enableScene\":\"agreementpay\",\"assetInfo\":{\"instId\":\"INST_ALIPAY\",\"assetId\":\"2088610***68075\",\"assetTypeCode\":\"ENTERPRISEPAY\",\"assetType\":\"ENTERPRISEPAYASSET\"}}",
+  "assignJointAccountId": "208861***868075",
+  "identityPayBizInfo": "{\"identityPaySubBizScene\":\"ISV_PAY\",\"bizGroupId\":\"208861***868075\",\"groupId\":\"20886***68075\",\"identityPayBizScene\":\"ENTERPRISE_CODE\"}",
+  "CHANNEL_INDEX": "[\"ENTERPRISEPAYASSET_DC_ENTERPRISEPAY_DEFAULT\"]",
+  "enterprise_pay_info": "{\"paymentId\":\"test001\",\"ruleGroupId\":\"2023121200152608840000615146\"}",
+  "sourcePlatformInfo": "{\"paymentId\":\"test001\",\"ruleGroupId\":\"2023121200152608840000615146\",\"isvAppId\":\"2021004130649307\"}"
+}
+```
+
+2. 通过 `openAlipayPage` 拉起扫一扫
+
+#### 2.5.2 跳转付款码
+
+**集成前准备**:
+
+通过 **开放平台控制台 > 对应小程序详情页 > 开发设置 > openURL配置** 中添加地址自助申请,添加地址填写:
+
+```
+alipays://platformapi/startapp?appId=20000056
+```
+
+若openURL配置没有,需要更改小程序经营类目, [理财金融](https://opendocs.alipay.com/b/03al2m#%E7%90%86%E8%B4%A2%E9%87%91%E8%9E%8D) 、工具 之外的全部小程序经营类目才开放openURL配置。
+
+![](https://cdn.nlark.com/yuque/0/2023/png/25758943/1703043937438-70150553-ec58-4de6-9783-a350464b019d.png)
+
+**schema 跳转付款码 2.0 的跳转链接**,格式如下:
+
+```
+alipays://platformapi/startapp?appId=20000056&customBizCode={bizCode}&customBizParams=encode({params})
+```
+
+其中标为黄色的区域,取值如下:
+
+- **bizCode** 是付款码分配的固定业务身份,旅行社场景为 `enterprisePayForThirdPart`
+- **encode({params})** 是将需要携带的拓展参数用 Json 格式字符串表示后,进行 URL-Encode 后得到的字符串(如果没有拓展参数需要传递,可以不传)
+
+**params参数说明**:
+
+- **pdSubBizScene**: 支付决策子场景
+  - 默认值: `enterprisePay`,适用: 收钱码,当面付,铁路线下支付
+- **specifiedEnableChannelInfo**
+  - 按照示例传参,仅需要替换`assetId`为共同账户id(accountId,从[企业签约状态变更消息通知](https://opendocs.alipay.com/apis/0477mu)里获取)
+- **assignJointAccountId**: 共同账户id(accountId,从[企业签约状态变更消息通知](https://opendocs.alipay.com/apis/0477mu)里获取)
+- **identityPayBizInfo**: 企业码身份付业务字段
+  - `identityPayBizScene`: `ENTERPRISE_CODE`
+  - `identityPaySubBizScene`: `ISV_PAY`
+  - `groupId`: 共同账户id(accountId,从[企业签约状态变更消息通知](https://opendocs.alipay.com/apis/0477mu)里获取)
+  - `bizGroupId`: 共同账户id(accountId,从[企业签约状态变更消息通知](https://opendocs.alipay.com/apis/0477mu)里获取)
+  - `expenseGroupId`: 费控规则id(当需要指定费控规则id消费时可传入此字段,可从创建[费控制度接口](https://opendocs.alipay.com/apis/049l40)出参获取)
+- **CHANNEL_INDEX**: 渠道
+  - 传入固定值: `ENTERPRISEPAYASSET_DC_ENTERPRISEPAY_DEFAULT`
+- **CHANNEL_MODE**: 渠道展示模式
+  - 默认值: `NONE_CHANNEL_MODE`
+- **enterprise_pay_info**: 企业码因公付大字段
+  - `ruleGroupId`: 费控规则id(当需要指定费控规则id消费时可传入此字段,可从创建[费控制度接口](https://opendocs.alipay.com/apis/049l40)出参获取)
+  - `paymentId`: 付款事由(paymentId为服务商付款事由ID,通过此字段服务商可做到精确对账)
+  - `isvAppId`: 三方小程序appId(必传,涉及到后面服务商政策)
+
+**接入示例**:
+
+1. 准备所需要的参数,将参数转换为 JSON 结构并压缩(注意 key-value 都是字符串):
+
+```json
+{
+  "pdSubBizScene": "enterprisePay",
+  "CHANNEL_INDEX": "[\"ENTERPRISEPAYASSET_DC_ENTERPRISEPAY_DEFAULT\"]",
+  "channelMode": "NONE_CHANNEL_MODE",
+  "specifiedEnableChannelInfo": "{\"enableScene\":\"agreementpay\",\"assetInfo\":{\"instId\":\"INST_ALIPAY\",\"assetId\":\"20883107**473\",\"assetTypeCode\":\"ENTERPRISEPAY\",\"assetType\":\"ENTERPRISEPAYASSET\"}}",
+  "assignJointAccountId": "208831****3473",
+  "identityPayBizInfo": "{\"identityPaySubBizScene\":\"ISV_PAY\",\"bizGroupId\":\"2088310****213473\",\"groupId\":\"2088310****3473\",\"identityPayBizScene\":\"ENTERPRISE_CODE\"}",
+  "enterprise_pay_info": "{\"paymentId\":\"test001\",\"ruleGroupId\":\"2023120400152608470000419071\",\"isvAppId\":\"2021004130649307\"}"
+}
+```
+
+2. URL encode 后拼接可得到链接(红色部分是固定前缀):
+
+```
+最终链接 = 链接主体 + &customBizParams= + encode(params)
+```
+
+完整示例:
+
+```
+alipays://platformapi/startapp?appId=20000056&customBizCode=enterprisePayForThirdPart&customBizParams=%7B%22pdSubBizScene%22%3A%22enterprisePay%22%2C%22CHANNEL_INDEX%22%3A%22%5B%5C%5C%5C%22ENTERPRISEPAYASSET_DC_ENTERPRISEPAY_DEFAULT%5C%5C%5C%22%5D%22%2C%22channelMode%22%3A%22NONE_CHANNEL_MODE%22%2C%22specifiedEnableChannelInfo%22%3A%22%7B%5C%5C%5C%22enableScene%5C%5C%5C%22%3A%5C%5C%5C%22agreementpay%5C%5C%5C%22%2C%5C%5C%5C%22assetInfo%5C%5C%5C%22%3A%7B%5C%5C%5C%22instId%5C%5C%5C%22%3A%5C%5C%5C%22INST_ALIPAY%5C%5C%5C%22%2C%5C%5C%5C%22assetId%5C%5C%5C%22%3A%5C%5C%5C%22208831***213473%5C%5C%5C%22%2C%5C%5C%5C%22assetTypeCode%5C%5C%5C%22%3A%5C%5C%5C%22ENTERPRISEPAY%5C%5C%5C%22%2C%5C%5C%5C%22assetType%5C%5C%5C%22%3A%5C%5C%5C%22ENTERPRISEPAYASSET%5C%5C%5C%22%7D%7D%22%2C%22assignJointAccountId%22%3A%22208831***61213473%22%2C%22identityPayBizInfo%22%3A%22%7B%5C%5C%5C%22identityPaySubBizScene%5C%5C%5C%22%3A%5C%5C%5C%22ISV_PAY%5C%5C%5C%22%2C%5C%5C%5C%22bizGroupId%5C%5C%5C%22%3A%5C%5C%5C%222088***1213473%5C%5C%5C%22%2C%5C%5C%5C%22groupId%5C%5C%5C%22%3A%5C%5C%5C%22208831***13473%5C%5C%5C%22%2C%5C%5C%5C%22identityPayBizScene%5C%5C%5C%22%3A%5C%5C%5C%22ENTERPRISE_CODE%5C%5C%5C%22%7D%22%2C%22enterprise_pay_info%22%3A%22%7B%5C%5C%5C%22paymentId%5C%5C%5C%22%3A%5C%5C%5C%22test001%5C%5C%5C%22%2C%5C%5C%5C%22ruleGroupId%5C%5C%5C%22%3A%5C%5C%5C%222023120400152608470000419071%5C%5C%5C%22%2C%5C%5C%5C%22isvAppId%5C%5C%5C%22%3A%5C%5C%5C%222021004130649307%5C%5C%5C%22%7D%22%7D
+```
+
+3. 通过jsapi拉起付款码
+
+#### 2.5.3 跳转发票关联
+
+通过 `my.navigateToMiniProgram` 拉起扫一扫(通过支付宝小程序跳转方式),调用方式如下:
+
+```javascript
+// 代码示例
+```
+
+通过 scheme 拉起扫一扫(通过H5跳转方式),调用方式如下:
+
+```
+// scheme示例
+```
+
+**参数说明**:
+
+| 参数名称 | 含义 | 值说明 |
+|---------|------|--------|
+| enterpriseId | 企业码企业ID(非因公账户ID) | 208831***473 |
+| pageType | 页面类型,发票关联使用固定值: invoice-folder | invoice-folder |
+| payNo | 发票关联页面类型对应的查询参数,支付宝交易号 | 2024042522001453811441399756 |

+ 278 - 0
支付宝SDK封装方案.md

@@ -0,0 +1,278 @@
+# 支付宝 SDK 封装方案
+
+## 一、现状分析
+
+### 1.1 项目技术栈
+
+| 组件 | 技术选型 |
+|-----|---------|
+| 后端框架 | FastAPI 0.115.2 |
+| 数据库 | PostgreSQL 14+ (asyncpg) / MySQL (asyncmy) |
+| ORM | SQLAlchemy 2.0.45 |
+| 支付宝SDK | alipay-sdk-python >= 3.7.1018 |
+| 异步框架 | uvicorn + asyncio |
+
+### 1.2 官方 SDK 结构
+
+```
+alipay-sdk-python >= 3.7.1018
+├── alipay.aop.api.AlipayClientConfig          # 配置类
+├── alipay.aop.api.DefaultAlipayClient         # 客户端类
+├── alipay.aop.api.domain.*                     # 业务模型类
+├── alipay.aop.api.request.*                    # 请求类
+└── alipay.aop.api.response.*                   # 响应类
+```
+
+---
+
+## 二、目录结构
+
+```
+app/core/alipay/                              # 支付宝 SDK 封装
+├── __init__.py                               # 导出接口
+├── config.py                                 # SDK 配置类
+├── client.py                                 # 统一客户端
+├── schema.py                                  # 响应模型定义
+└── services/                                 # 服务层(规划中)
+```
+
+---
+
+## 三、核心组件
+
+### 3.1 配置类 `config.py`
+
+```python
+from pydantic_settings import BaseSettings, SettingsConfigDict
+
+class AlipayConfig(BaseSettings):
+    """支付宝 SDK 配置"""
+
+    app_id: str = Field(default="", validation_alias=AliasChoices("ALIPAY_APPID", "ALIPAY_APP_ID"))
+    app_private_key: str = Field(default="")
+    alipay_public_key: str = Field(default="")
+    format: str = Field(default="json")
+    charset: str = Field(default="UTF-8")
+    sign_type: str = Field(default="RSA2")
+    sandbox: bool = Field(default=False)
+    notify_url: str = Field(default="")
+    return_url: str = Field(default="")
+
+    @property
+    def is_valid(self) -> bool:
+        """检查配置是否有效"""
+        return bool(self.app_id and self.app_private_key and self.alipay_public_key)
+
+    def to_alipay_client_config(self) -> "AlipayClientConfig":
+        """转换为官方 AlipayClientConfig"""
+        config = AlipayClientConfig(sandbox_debug=self.sandbox)
+        config.app_id = self.app_id
+        config.app_private_key = self.app_private_key
+        config.alipay_public_key = self.alipay_public_key
+        config.format = self.format
+        config.charset = self.charset
+        config.sign_type = self.sign_type
+        return config
+```
+
+### 3.2 客户端类 `client.py`
+
+```python
+from alipay.aop.api.DefaultAlipayClient import DefaultAlipayClient
+
+class AlipayClient:
+    """支付宝客户端工具类"""
+
+    _client: DefaultAlipayClient | None = None
+
+    @classmethod
+    def get_client(cls) -> DefaultAlipayClient:
+        """获取支付宝客户端实例"""
+        if cls._client is None:
+            cls._client = DefaultAlipayClient(
+                alipay_client_config=get_alipay_config().to_alipay_client_config(),
+                logger=logger,
+            )
+        return cls._client
+```
+
+### 3.3 响应模型 `schema.py`
+
+#### 基础响应模型
+
+```python
+class AlipayResponse(BaseModel):
+    """支付宝响应基础模型"""
+
+    code: str = Field(..., description="网关返回码,10000表示成功")
+    msg: str = Field(..., description="网关返回码描述")
+    sub_code: Optional[str] = Field(None, description="业务错误码")
+    sub_msg: Optional[str] = Field(None, description="业务错误描述")
+
+    @property
+    def success(self) -> bool:
+        return self.code == AlipayResponseCodeEnum.SUCCESS.value.code
+```
+
+#### 响应码枚举
+
+```python
+AlipayResponseCode = NamedTuple("AlipayResponseCode", [("code", str), ("msg", str)])
+
+
+class AlipayResponseCodeEnum(Enum):
+    """支付宝响应码枚举"""
+
+    SUCCESS = AlipayResponseCode("10000", "接口调用成功")
+    SERVICE_UNAVAILABLE = AlipayResponseCode("20000", "服务不可用")
+    AUTH_INSUFFICIENT = AlipayResponseCode("20001", "授权权限不足")
+    MISSING_REQUIRED_PARAM = AlipayResponseCode("40001", "缺少必选参数")
+    INVALID_PARAM = AlipayResponseCode("40002", "非法的参数")
+    CONDITION_ABNORMAL = AlipayResponseCode("40003", "条件异常")
+    SERVICE_NOT_EXIST = AlipayResponseCode("40004", "服务不存在")
+    METHOD_NOT_SUPPORTED = AlipayResponseCode("40005", "不支持请求方式")
+    PERMISSION_DENIED = AlipayResponseCode("40006", "权限不足")
+
+    @classmethod
+    def from_code(cls, code: str) -> AlipayResponseCode:
+        """根据 code 获取对应的 AlipayResponseCode"""
+        for item in cls:
+            if item.value.code == code:
+                return item.value
+        return AlipayResponseCode(code, "未知错误")
+```
+
+#### 业务响应模型示例
+
+```python
+class AlipayCommerceEcEnterpriseRegisterInviteCreateResponse(AlipayResponse):
+    """邀请企业注册响应"""
+
+    pc_invite_url: Optional[str] = Field(None, description="企业注册/认证/签约三合一页面的链接地址")
+    expire_time: Optional[datetime] = Field(None, description="链接过期时间")
+
+    @field_validator("expire_time", mode="before")
+    @classmethod
+    def parse_expire_time(cls, v: Optional[str]) -> Optional[datetime]:
+        if v is None:
+            return None
+        return datetime.strptime(v, "%Y-%m-%d %H:%M:%S")
+```
+
+---
+
+## 四、使用示例
+
+### 4.1 基础调用
+
+```python
+from app.core.alipay import AlipayClient, get_alipay_config
+
+# 获取客户端
+client = AlipayClient.get_client()
+
+# 构建请求
+model = AlipayCommerceEcEnterpriseRegisterInviteCreateModel()
+model.out_biz_no = "2024051000000001"
+model.identity_type = "ALIPAY_USER_ID"
+model.identity = "2088051553855663"
+model.register_mode = "NORMAL"
+model.sign_fund_way = "BALANCE"
+
+request = AlipayCommerceEcEnterpriseRegisterInviteCreateRequest()
+request.biz_model = model
+
+# 执行调用
+response = client.execute(request)
+
+# 使用 Pydantic 模型验证响应
+result = AlipayCommerceEcEnterpriseRegisterInviteCreateResponse.model_validate_json(response)
+if result.success:
+    print(result.pc_invite_url)
+    print(result.expire_time)
+```
+
+### 4.2 响应码使用
+
+```python
+from app.core.alipay.schema import AlipayResponseCodeEnum
+
+# 获取成功码信息
+success_code = AlipayResponseCodeEnum.SUCCESS.value
+print(success_code.code)  # "10000"
+print(success_code.msg)   # "接口调用成功"
+
+# 根据 code 反查
+result = AlipayResponseCodeEnum.from_code("40001")
+print(result.code)  # "40001"
+print(result.msg)   # "缺少必选参数"
+```
+
+---
+
+## 五、接口导出
+
+```python
+# app/core/alipay/__init__.py
+
+from app.core.alipay.client import AlipayClient
+from app.core.alipay.config import AlipayConfig, get_alipay_config
+
+__all__ = [
+    "AlipayConfig",
+    "get_alipay_config",
+    "AlipayClient",
+]
+```
+
+---
+
+## 六、规划中功能
+
+### 6.1 服务层封装
+
+```
+services/
+├── base.py                             # 基础服务类
+├── enterprise_service.py               # 企业服务
+├── employee_service.py                  # 员工服务
+├── expense_service.py                  # 费控服务
+├── quota_service.py                    # 额度服务
+└── bill_service.py                     # 账单服务
+```
+
+### 6.2 异常体系
+
+```python
+class AlipayError(Exception):
+    """支付宝基础异常"""
+    code: str = "500"
+    msg: str = "Unknown error"
+
+
+class AlipayApiError(AlipayError):
+    """API 调用错误"""
+    code = "40000"
+
+
+class AlipayNetworkError(AlipayError):
+    """网络错误(可重试)"""
+    code = "20000"
+```
+
+### 6.3 重试机制
+
+基于指数退避的重试策略,支持的错误码:
+- `20000` - 服务不可用
+- `20001` - 授权权限不足
+- `ACQ.SystemError` - 银行系统异常
+
+---
+
+## 七、注意事项
+
+1. **密钥安全**:私钥通过环境变量注入,严禁硬编码
+2. **沙箱环境**:开发时设置 `sandbox=True`
+3. **响应验证**:使用 Pydantic 模型验证响应数据
+4. **错误处理**:根据 `code` 和 `sub_code` 进行分类处理
+5. **超时控制**:默认超时 30 秒