> ## Documentation Index
> Fetch the complete documentation index at: https://docs-docflow.textin.com/llms.txt
> Use this file to discover all available pages before exploring further.

# AP 审单场景（无工作空间）

> 在财务部门 AP（应付账款）审单业务场景中，调用 DocFlow API 完成发票、采购订单、收货单等单据的自动化交叉审核。

<Tip>
  本文以 **AP 审单**（应付账款审核）为业务场景，演示如何通过 API 完成从创建空间、配置类别、上传文件、获取抽取结果到智能审核的完整流程。
  如果您刚刚接触 DocFlow，建议先在 [Web 页面](https://docflow.textin.com/) 体验一下产品的基本功能，再阅读本文。
</Tip>

## 01 场景说明

在 AP（应付账款）审单业务中，财务人员每次付款前需要对一组采购单据进行交叉核验。典型的单据组合包括：

* 发票（含数电票、纸质增值税专用发票/普通发票等）：记录销售方/购买方信息、开票金额和税率
* 采购订单（PDF/Word）：约定供应商信息、合同金额、税率和产品明细
* 收货单（PDF）：记录实际收货数量、物料信息及关联的采购订单号

通过 DocFlow，您只需配置一次分类和字段，后续上传的单据即可自动完成**分类识别**和**结构化信息抽取**；配置好审核规则库后，还可对多份单据进行**跨文档智能审核**，自动发现供应商不一致、金额超标、数量异常等问题。

## 02 业务流程

<img src="https://mintcdn.com/docflow/NHmfC3xyBtH2bZya/docflow/cn/images/expense_reimbursement_flow.png?fit=max&auto=format&n=NHmfC3xyBtH2bZya&q=85&s=f294139c4cf2119d8d430dfb67107809" alt="AP 审单业务流程" width="842" height="301" data-path="docflow/cn/images/expense_reimbursement_flow.png" />

<Note>
  **工作空间、文件类别和审核规则库只需配置一次**，后续可持续复用——直接上传新的待处理文件并创建新的审核任务即可。本示例为演示完整流程，将配置步骤和处理步骤放在同一段代码中运行。
</Note>

## 03 先决条件

1. 登录 [TextIn 控制台](https://www.textin.com/console/dashboard/setting)，获取 `x-ti-app-id` 和 `x-ti-secret-code`
2. 下载[示例样本文件](https://github.com/intsig-textin/docflow-docs/tree/master/examples/sample_files/ap_review)，或使用自己的单据文件

## 04 类别与字段配置

本示例配置四个文件类别，均通过 `category/create` 接口创建并配置字段。

<AccordionGroup>
  <Accordion defaultOpen title="国内票-数电票（样本：sample_invoice.pdf）">
    增值税电子发票（数电票），包含发票号码、开票日期、购买方/销售方名称及税号、价税合计等基本信息字段，以及商品明细表格字段：

    <Tip>
      示例样本文件，可点击查看或下载：[sample\_invoice.pdf](https://dllf.intsig.net/download/2026/CustomService/sample_invoice.pdf)

      <iframe src="https://dllf.intsig.net/download/2026/CustomService/sample_invoice.pdf" width="100%" height="500px" />
    </Tip>

    | 字段名                                               | 类型     |
    | ------------------------------------------------- | ------ |
    | <span style={{color: "#3b82f6"}}>发票号码</span>      | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>开票日期</span>      | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>价税合计</span>      | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>税前金额</span>      | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>税额</span>        | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>销售方名称</span>     | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>销售方纳税人识别号</span> | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>购买方名称</span>     | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>购买方纳税人识别号</span> | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>发票备注</span>      | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>商品名称</span>      | 表格字段   |
    | <span style={{color: "#3b82f6"}}>规格型号</span>      | 表格字段   |
    | <span style={{color: "#3b82f6"}}>单位</span>        | 表格字段   |
    | <span style={{color: "#3b82f6"}}>数量</span>        | 表格字段   |
    | <span style={{color: "#3b82f6"}}>单价</span>        | 表格字段   |
    | <span style={{color: "#3b82f6"}}>金额</span>        | 表格字段   |
    | <span style={{color: "#3b82f6"}}>税率</span>        | 表格字段   |
    | <span style={{color: "#3b82f6"}}>税额</span>        | 表格字段   |
  </Accordion>

  <Accordion defaultOpen title="采购合同（样本：sample_contract.pdf）">
    采购合同是约定交易条款的核心文件，包含合同编号、甲乙方信息、金额、税率和产品明细。字段配置同时使用**基本信息字段**和**表格字段**：

    <Tip>
      示例样本文件，可点击查看或下载：[sample\_contract.pdf](https://dllf.intsig.net/download/2026/CustomService/sample_contract.pdf)

      <iframe src="https://dllf.intsig.net/download/2026/CustomService/sample_contract.pdf" width="100%" height="500px" />
    </Tip>

    | 字段名                                               | 类型     |
    | ------------------------------------------------- | ------ |
    | <span style={{color: "#3b82f6"}}>编号</span>        | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>甲方</span>        | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>乙方</span>        | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>签订日期</span>      | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>合作期间</span>      | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>支付条款</span>      | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>乙方银行账户信息</span>  | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>开票信息</span>      | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>违约金条款</span>     | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>采购物料/服务数量</span> | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>合同类型</span>      | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>采购金额</span>      | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>采购单价</span>      | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>税率</span>        | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>乙方税号</span>      | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>采购物料/服务</span>   | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>产品型号</span>      | 表格字段   |
    | <span style={{color: "#3b82f6"}}>产品说明</span>      | 表格字段   |
    | <span style={{color: "#3b82f6"}}>单价</span>        | 表格字段   |
    | <span style={{color: "#3b82f6"}}>数量</span>        | 表格字段   |
    | <span style={{color: "#3b82f6"}}>金额</span>        | 表格字段   |
  </Accordion>

  <Accordion defaultOpen title="入库单（样本：sample_inbound.pdf）">
    入库单是仓库收货的凭证，记录实收数量、物料信息和供应商信息。字段配置同时使用**基本信息字段**和**表格字段**：

    <Tip>
      示例样本文件，可点击查看或下载：[sample\_inbound.pdf](https://dllf.intsig.net/download/2026/CustomService/sample_inbound.pdf)

      <iframe src="https://dllf.intsig.net/download/2026/CustomService/sample_inbound.pdf" width="100%" height="500px" />
    </Tip>

    | 字段名                                                 | 类型     |
    | --------------------------------------------------- | ------ |
    | <span style={{color: "#3b82f6"}}>收货单编号</span>       | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>收货日期</span>        | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>对应合同号</span>       | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>供应商名称</span>       | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>仓库／库位</span>       | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>物流单号</span>        | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>入库总金额</span>       | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>收货结论</span>        | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>备注</span>          | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>仓库收货人</span>       | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>仓库收货人日期</span>     | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>质检确认</span>        | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>质检确认日期</span>      | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>供应商送货人</span>      | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>供应商送货人日期</span>    | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>供应商税号</span>       | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>收货入库明细-物料编码</span> | 表格字段   |
    | <span style={{color: "#3b82f6"}}>收货入库明细-物料描述</span> | 表格字段   |
    | <span style={{color: "#3b82f6"}}>收货入库明细-单位</span>   | 表格字段   |
    | <span style={{color: "#3b82f6"}}>收货入库明细-应收</span>   | 表格字段   |
    | <span style={{color: "#3b82f6"}}>收货入库明细-实收</span>   | 表格字段   |
    | <span style={{color: "#3b82f6"}}>收货入库明细-差异</span>   | 表格字段   |
    | <span style={{color: "#3b82f6"}}>收货入库明细-质检</span>   | 表格字段   |
    | <span style={{color: "#3b82f6"}}>收货入库明细-签收人</span>  | 表格字段   |
  </Accordion>

  <Accordion defaultOpen title="验收单（样本：sample_acceptance.pdf）">
    验收单是确认货物/服务交付质量的凭证，仅包含基本信息字段：

    <Tip>
      示例样本文件，可点击查看或下载：[sample\_acceptance.pdf](https://dllf.intsig.net/download/2026/CustomService/sample_acceptance.pdf)

      <iframe src="https://dllf.intsig.net/download/2026/CustomService/sample_acceptance.pdf" width="100%" height="500px" />
    </Tip>

    | 字段名                                            | 类型     |
    | ---------------------------------------------- | ------ |
    | <span style={{color: "#3b82f6"}}>项目名称</span>   | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>合同编号</span>   | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>甲方单位名称</span> | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>乙方单位名称</span> | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>甲方验收人</span>  | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>乙方施工人</span>  | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>交付内容</span>   | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>验收说明</span>   | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>验收结论</span>   | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>验收数量</span>   | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>验收日期</span>   | 基本信息字段 |
    | <span style={{color: "#3b82f6"}}>乙方税号</span>   | 基本信息字段 |
  </Accordion>
</AccordionGroup>

## 05 审核规则配置

本示例的审核规则库包含 **2 个规则组、12 条审核规则**，覆盖跨单据业务一致性核验和文档完整性预检两个维度：

<AccordionGroup>
  <Accordion defaultOpen title="规则组 1：业务一致性审核（跨单据交叉核验）">
    | 规则名称                                                 | 风险等级                                          | 审核逻辑                                              |
    | ---------------------------------------------------- | --------------------------------------------- | ------------------------------------------------- |
    | <span style={{color: "#3b82f6"}}>供应商一致性</span>       | <span style={{color: "#ef4444"}}>●</span> 高风险 | 若均存在税号，则发票销售方税号 = 合同乙方税号 = 入库单供应商税号；否则比对名称        |
    | <span style={{color: "#3b82f6"}}>金额匹配</span>         | <span style={{color: "#ef4444"}}>●</span> 高风险 | 发票价税合计金额 ≤ 采购合同总金额；框架协议（金额为空或 0）时不校验              |
    | <span style={{color: "#3b82f6"}}>数量一致性（入库单维度）</span> | <span style={{color: "#eab308"}}>●</span> 中风险 | 若发票含商品明细，则发票数量合计 ≤ 入库单实收数量合计                      |
    | <span style={{color: "#3b82f6"}}>标的一致性</span>        | <span style={{color: "#22c55e"}}>●</span> 低风险 | 合同约定的规格型号须与入库单、发票中的规格型号一致；未约定规格型号时校验标的物描述是否指向同一商品 |
    | <span style={{color: "#3b82f6"}}>税率一致性</span>        | <span style={{color: "#eab308"}}>●</span> 中风险 | 发票各行税率须与合同约定税率一致；合同未约定税率时跳过                       |
    | <span style={{color: "#3b82f6"}}>验收结论校验</span>       | <span style={{color: "#eab308"}}>●</span> 中风险 | 验收单的验收结论须为合格/通过/验收通过/同意验收或类似认可状态                  |
    | <span style={{color: "#3b82f6"}}>数量一致性（验收单维度）</span> | <span style={{color: "#eab308"}}>●</span> 中风险 | 若发票含商品明细且验收单有合格数量，则发票数量合计 ≤ 验收单合格数量               |
    | <span style={{color: "#3b82f6"}}>合同关联性</span>        | <span style={{color: "#eab308"}}>●</span> 中风险 | 入库单合同编号 = 采购合同编号；验收单合同编号 = 采购合同编号                 |

    <Tip>
      跨文档规则的 `category_ids` 包含多个分类 ID，只有当审核任务覆盖所有关联分类时，该规则才会被触发执行。
    </Tip>
  </Accordion>

  <Accordion defaultOpen title="规则组 2：文档采集与预处理审核">
    | 规则名称                                            | 风险等级                                          | 审核逻辑                                                |
    | ----------------------------------------------- | --------------------------------------------- | --------------------------------------------------- |
    | <span style={{color: "#3b82f6"}}>信息完整性校验</span> | <span style={{color: "#eab308"}}>●</span> 中风险 | 检查四类文档齐全性并核验各文档必填字段非空（详见审核点说明）                      |
    | <span style={{color: "#3b82f6"}}>发票日期合规性</span> | <span style={{color: "#eab308"}}>●</span> 中风险 | 发票开票日期 ≥ 合同签订日期                                     |
    | <span style={{color: "#3b82f6"}}>购买方信息匹配</span> | <span style={{color: "#ef4444"}}>●</span> 高风险 | 发票购买方名称 = 上海合合信息科技股份有限公司；购买方税号 = 91310110791485269J |
    | <span style={{color: "#3b82f6"}}>税率合规性校验</span> | <span style={{color: "#eab308"}}>●</span> 中风险 | 货物类税率应为 13%，服务类应为 6%，小规模纳税人应为 1% 或 3%               |
  </Accordion>
</AccordionGroup>

## 06 代码结构说明

示例代码将完整的七步流程放在一起运行，便于理解端到端的调用链路。在实际生产中，**步骤 1、2、5（创建工作空间、配置文件类别、配置审核规则库）只需执行一次**；后续处理新单据时，只需重复**步骤 3、4、6、7（上传文件 → 获取抽取结果 → 提交审核任务 → 获取审核结果）**，直接复用已有的配置即可。参见 [AP 审单场景（已完成配置）](./ap_review_already_configured)。

示例代码中的函数分为两类，理解这一点有助于对照 API 文档进行调试和扩展。

### 两类函数

**REST API 调用函数** — 每个函数直接封装一个 API 端点，函数参数与接口文档一一对应：

| 函数（Python）                  | 方法（Java）                 | 对应 API 端点                         | 说明                              |
| --------------------------- | ------------------------ | --------------------------------- | ------------------------------- |
| `create_workspace`          | `createWorkspace`        | `POST /workspace/create`          | 创建工作空间，返回 workspace\_id         |
| `create_category`           | `createCategory`         | `POST /category/create`           | 创建文件类别并上传样本，返回 category\_id     |
| `batch_add_category_fields` | `batchAddCategoryFields` | `POST /category/fields/batch_add` | 为已有类别追加字段（用于添加表格字段）             |
| `upload_file`               | `uploadFile`             | `POST /file/upload`               | 异步上传文件，返回 batch\_number，需轮询获取结果 |
| `upload_file_sync`          | `uploadFileSync`         | `POST /file/upload/sync`          | 同步上传文件，直接返回抽取结果，无需轮询            |
| `create_rule_repo`          | `createRuleRepo`         | `POST /review/rule_repo/create`   | 创建审核规则库，返回 repo\_id             |
| `create_rule_group`         | `createRuleGroup`        | `POST /review/rule_group/create`  | 在规则库内创建规则组，返回 group\_id         |
| `create_rule`               | `createRule`             | `POST /review/rule/create`        | 在规则组内创建审核规则，绑定适用分类              |
| `submit_review_task`        | `submitReviewTask`       | `POST /review/task/submit`        | 提交审核任务，返回审核 task\_id            |

**工具辅助函数** — 不直接对应 API 端点，提供公共基础能力或封装轮询/展示逻辑：

| 函数（Python）              | 方法（Java）              | 作用                               |
| ----------------------- | --------------------- | -------------------------------- |
| `_headers`              | `authHeaders`         | 构造鉴权请求头                          |
| `_check`                | `checkResponse`       | 校验响应 code，统一异常处理                 |
| `_mime`                 | `mimeType`            | 根据扩展名推断 MIME 类型                  |
| `wait_for_result`       | `waitForResult`       | 循环轮询 `file/fetch`，等待抽取完成         |
| `display_result`        | `displayResult`       | 格式化打印抽取结果                        |
| `wait_for_review`       | `waitForReview`       | 循环轮询 `review/task/result`，等待审核完成 |
| `display_review_result` | `displayReviewResult` | 格式化打印审核结果                        |

### 逐步代码说明

<AccordionGroup>
  <Accordion defaultOpen title="步骤 2：创建含表格字段的文件类别">
    国内票-数电票、采购合同和入库单均包含表格字段，需先创建类别（配置基本信息字段），再通过 `batch_add_category_fields` 追加表格字段。`table_id=-1` 表示挂载到默认表格。

    <Tabs>
      <Tab title="Python">
        ```python theme={null}
        # 国内票-数电票（基本信息字段 + 明细表格字段）
        invoice_id = create_category(
            workspace_id=workspace_id,
            name="国内票-数电票",
            sample_file_path="sample_invoice.pdf",
            fields=[
                {"name": "发票号码"}, {"name": "开票日期"}, {"name": "价税合计"},
                # ... 其余基本信息字段
            ],
        )
        batch_add_category_fields(workspace_id, invoice_id, table_id=-1, fields=[
            {"name": "商品名称"}, {"name": "规格型号"}, {"name": "单位"},
            {"name": "数量"}, {"name": "单价"}, {"name": "金额"}, {"name": "税率"}, {"name": "税额"}
        ])

        # 采购合同（基本信息字段 + 表格字段）
        contract_id = create_category(
            workspace_id=workspace_id,
            name="采购合同",
            sample_file_path="sample_contract.pdf",
            fields=[{"name": "编号"}, {"name": "甲方"}, {"name": "乙方"}, ...],
        )
        batch_add_category_fields(workspace_id, contract_id, table_id=-1, fields=[
            {"name": "产品型号"}, {"name": "产品说明"}, {"name": "单价"}, {"name": "数量"}, {"name": "金额"}
        ])
        ```
      </Tab>

      <Tab title="Java">
        ```java theme={null}
        // 国内票-数电票
        String invoiceId = createCategory(workspaceId, "国内票-数电票",
                SAMPLE_DIR + "/sample_invoice.pdf", invoiceFields, "增值税电子发票（数电票）...");
        batchAddCategoryFields(workspaceId, invoiceId, "-1",
                List.of("商品名称", "规格型号", "单位", "数量", "单价", "金额", "税率", "税额"));
        // 采购合同
        String contractId = createCategory(workspaceId, "采购合同",
                SAMPLE_DIR + "/sample_contract.pdf", contractFields, "");
        batchAddCategoryFields(workspaceId, contractId, "-1",
                List.of("产品型号", "产品说明", "单价", "数量", "金额"));
        ```
      </Tab>
    </Tabs>
  </Accordion>

  <Accordion defaultOpen title="步骤 3：上传待处理文件">
    文件上传支持两种模式，可根据业务场景选择：

    * **异步上传**（`file/upload`）：上传后立即返回 `batch_number`，需配合步骤 4 轮询 `file/fetch` 获取抽取结果。适合大批量文件并发处理。
    * **同步上传**（`file/upload/sync`）：上传后等待处理完成，直接返回抽取结果，无需轮询。适合单文件或少量文件的实时场景。

    **方式一：异步上传（需配合步骤 4 轮询）**

    <Tabs>
      <Tab title="Python">
        ```python theme={null}
        batch_numbers = []
        for file_path in [
            os.path.join(SAMPLE_DIR, "sample_invoice.pdf"),
            os.path.join(SAMPLE_DIR, "sample_contract.pdf"),
            os.path.join(SAMPLE_DIR, "sample_inbound.pdf"),
            os.path.join(SAMPLE_DIR, "sample_acceptance.pdf"),
        ]:
            batch_number = upload_file(workspace_id, file_path)
            batch_numbers.append(batch_number)
        ```
      </Tab>

      <Tab title="Java">
        ```java theme={null}
        List<String> batchNumbers = new ArrayList<>();
        for (String path : new String[]{
                SAMPLE_DIR + "/sample_invoice.pdf",
                SAMPLE_DIR + "/sample_contract.pdf",
                SAMPLE_DIR + "/sample_inbound.pdf",
                SAMPLE_DIR + "/sample_acceptance.pdf"}) {
            batchNumbers.add(uploadFile(workspaceId, path));
        }
        ```
      </Tab>
    </Tabs>

    **方式二：同步上传（直接返回抽取结果，跳过步骤 4）**

    <Tabs>
      <Tab title="Python">
        ```python theme={null}
        def upload_file_sync(workspace_id: str, file_path: str) -> dict:
            """同步上传：直接返回抽取结果，无需轮询。"""
            url = f"{BASE_URL}/api/app-api/sip/platform/v2/file/upload/sync"
            with open(file_path, "rb") as f:
                resp = requests.post(url,
                    params={"workspace_id": workspace_id},
                    files={"file": (os.path.basename(file_path), f, _mime(file_path))},
                    headers=_headers(), timeout=300)
            data = _check(resp, "同步上传文件")
            return data["result"]["files"][0]   # 返回结构与 file/fetch 一致

        # 调用示例：上传即得到抽取结果，可直接用于审核
        raw_results = [upload_file_sync(workspace_id, p) for p in [
            os.path.join(SAMPLE_DIR, "sample_invoice.pdf"),
            os.path.join(SAMPLE_DIR, "sample_contract.pdf"),
            os.path.join(SAMPLE_DIR, "sample_inbound.pdf"),
            os.path.join(SAMPLE_DIR, "sample_acceptance.pdf"),
        ]]
        ```
      </Tab>

      <Tab title="Java">
        ```java theme={null}
        public static JsonObject uploadFileSync(String workspaceId, String filePath) throws IOException {
            File file = new File(filePath);
            HttpUrl url = HttpUrl.parse(BASE_URL + "/api/app-api/sip/platform/v2/file/upload/sync")
                    .newBuilder().addQueryParameter("workspace_id", workspaceId).build();
            MultipartBody body = new MultipartBody.Builder().setType(MultipartBody.FORM)
                    .addFormDataPart("file", file.getName(),
                            RequestBody.create(file, MediaType.get(mimeType(file.getName()))))
                    .build();
            Request req = new Request.Builder().url(url).headers(authHeaders()).post(body).build();
            try (Response resp = HTTP.newCall(req).execute()) {
                return checkResponse(resp.body().string(), "同步上传文件")
                        .getAsJsonObject("result").getAsJsonArray("files")
                        .get(0).getAsJsonObject();
            }
        }

        // 调用示例
        List<JsonObject> rawResults = new ArrayList<>();
        for (String path : new String[]{
                SAMPLE_DIR + "/sample_invoice.pdf",
                SAMPLE_DIR + "/sample_contract.pdf",
                SAMPLE_DIR + "/sample_inbound.pdf",
                SAMPLE_DIR + "/sample_acceptance.pdf"}) {
            rawResults.add(uploadFileSync(workspaceId, path));
        }
        ```
      </Tab>
    </Tabs>
  </Accordion>

  <Accordion defaultOpen title="步骤 4：获取抽取结果（使用同步上传时可跳过）">
    <Note>若步骤 3 使用了同步上传 `file/upload/sync`，则已直接获得抽取结果，可跳过本步骤。</Note>

    异步上传后，需轮询 `file/fetch` 接口等待处理完成：

    <Tabs>
      <Tab title="Python">
        ```python theme={null}
        raw_results = []
        for batch_number in batch_numbers:
            result = wait_for_result(workspace_id, batch_number)
            raw_results.append(result)
            display_result(result)
        ```
      </Tab>

      <Tab title="Java">
        ```java theme={null}
        List<JsonObject> rawResults = new ArrayList<>();
        for (String batchNumber : batchNumbers) {
            JsonObject result = waitForResult(workspaceId, batchNumber);
            rawResults.add(result);
            displayResult(result);
        }
        ```
      </Tab>
    </Tabs>
  </Accordion>

  <Accordion defaultOpen title="步骤 5：配置跨文档审核规则">
    跨文档规则在 `category_ids` 中传入多个分类 ID。DocFlow 会从各分类已抽取的结果中提取规则关联字段，交由 AI 统一判断。

    <Tabs>
      <Tab title="Python">
        ```python theme={null}
        # 供应商一致性——关联发票、合同、入库单三个分类
        create_rule(workspace_id, repo_id, group1_id,
            "供应商一致性",
            "若均存在税号字段，则发票【销售方纳税人识别号】= 合同【乙方纳税人识别号】"
            "= 入库单【供应商税号】；否则比对名称",
            [invoice_id, contract_id, inbound_id], 10)
        ```
      </Tab>

      <Tab title="Java">
        ```java theme={null}
        createRule(workspaceId, repoId, group1Id, "供应商一致性",
                "若均存在税号字段，则发票【销售方纳税人识别号】= 合同【乙方纳税人识别号】"
                + "= 入库单【供应商税号】；否则比对名称",
                Arrays.asList(invoiceId, contractId, inboundId), 10);
        ```
      </Tab>
    </Tabs>
  </Accordion>
</AccordionGroup>

### 抽取结果示例

<img src="https://mintcdn.com/docflow/NHmfC3xyBtH2bZya/docflow/cn/images/senario_extract_result.png?fit=max&auto=format&n=NHmfC3xyBtH2bZya&q=85&s=7a2f79ed743421aca3dcf92df0653d9a" alt="抽取结果示例" width="2282" height="1594" data-path="docflow/cn/images/senario_extract_result.png" />

### 审核结果示例

<img src="https://mintcdn.com/docflow/NHmfC3xyBtH2bZya/docflow/cn/images/senario_review_result.png?fit=max&auto=format&n=NHmfC3xyBtH2bZya&q=85&s=2a52846ea3b8711b8e78706fd0c6e9e9" alt="审核结果示例" width="2298" height="1558" data-path="docflow/cn/images/senario_review_result.png" />

## 07 完整示例代码下载

完整可运行代码（含 Python、Java 两个版本）已内置在文档仓库的 `examples/` 目录下：

```
examples/
├── python/
│   ├── ap_review.py               # Python 完整示例
│   ├── requirements.txt
│   └── README.md
├── java/
│   ├── src/main/java/com/docflow/ApReview.java
│   ├── pom.xml
│   └── README.md
└── sample_files/
    └── ap_review/
        ├── sample_invoice.pdf
        ├── sample_contract.pdf
        ├── sample_inbound.pdf
        └── sample_acceptance.pdf
```

<CardGroup cols={2}>
  <Card title="Python 示例" icon="python" href="https://github.com/ichaozai/docflow-docs/tree/master/examples/python">
    查看 Python 完整示例代码
  </Card>

  <Card title="Java 示例" icon="java" href="https://github.com/ichaozai/docflow-docs/tree/master/examples/java">
    查看 Java 完整示例代码
  </Card>
</CardGroup>

## 08 运行示例

<Tabs>
  <Tab title="Python">
    **环境要求**：Python 3.8+

    **1. 安装依赖**

    ```bash theme={null}
    cd examples/python
    pip install -r requirements.txt
    ```

    **2. 填写配置**

    打开 `ap_review.py`，填写文件顶部的配置项：

    ```python theme={null}
    APP_ID        = "your-app-id"      # x-ti-app-id
    SECRET_CODE   = "your-secret-code" # x-ti-secret-code
    ```

    **3. 运行**

    ```bash theme={null}
    python ap_review.py
    ```
  </Tab>

  <Tab title="Java">
    **环境要求**：JDK 11+，Maven 3.6+

    **1. 填写配置**

    打开 `src/main/java/com/docflow/ApReview.java`，填写文件顶部的配置项：

    ```java theme={null}
    private static final String APP_ID        = "your-app-id";
    private static final String SECRET_CODE   = "your-secret-code";
    ```

    **2. 编译并运行**

    ```bash theme={null}
    cd examples/java
    mvn compile -q
    mvn exec:java -Dexec.mainClass="com.docflow.ApReview"
    ```
  </Tab>
</Tabs>

<Tip>
  运行成功后，可登录 [DocFlow Web 页面](https://docflow.textin.com/)，在对应工作空间下直观查看每份文件的分类、字段抽取结果和智能审核结果，便于与代码输出对照验证。
</Tip>

### 预期控制台输出

成功运行后，控制台将输出如下内容（workspace\_id、category\_id 等 ID 因运行环境不同而变化）：

```
============================================================
  DocFlow AP 审单场景示例
============================================================
[步骤1] 工作空间创建成功  workspace_id=<workspace_id>
[步骤2] 文件类别创建成功  name=国内票-数电票  category_id=<category_id>
  追加字段成功  name=商品名称  field_id=<field_id>
  追加字段成功  name=规格型号  field_id=<field_id>
  追加字段成功  name=单位  field_id=<field_id>
  追加字段成功  name=数量  field_id=<field_id>
  追加字段成功  name=单价  field_id=<field_id>
  追加字段成功  name=金额  field_id=<field_id>
  追加字段成功  name=税率  field_id=<field_id>
  追加字段成功  name=税额  field_id=<field_id>
[步骤2] 文件类别创建成功  name=采购合同  category_id=<category_id>
  追加字段成功  name=产品型号  field_id=<field_id>
  追加字段成功  name=产品说明  field_id=<field_id>
  追加字段成功  name=单价  field_id=<field_id>
  追加字段成功  name=数量  field_id=<field_id>
  追加字段成功  name=金额  field_id=<field_id>
[步骤2] 文件类别创建成功  name=入库单  category_id=<category_id>
  追加字段成功  name=收货入库明细-物料编码  field_id=<field_id>
  追加字段成功  name=收货入库明细-物料描述  field_id=<field_id>
  追加字段成功  name=收货入库明细-单位  field_id=<field_id>
  追加字段成功  name=收货入库明细-应收  field_id=<field_id>
  追加字段成功  name=收货入库明细-实收  field_id=<field_id>
  追加字段成功  name=收货入库明细-差异  field_id=<field_id>
  追加字段成功  name=收货入库明细-质检  field_id=<field_id>
  追加字段成功  name=收货入库明细-签收人  field_id=<field_id>
[步骤2] 文件类别创建成功  name=验收单  category_id=<category_id>

配置完成  workspace_id=<workspace_id>
  国内票-数电票: category_id=<category_id>
  采购合同:      category_id=<category_id>
  入库单:        category_id=<category_id>
  验收单:        category_id=<category_id>

开始上传待处理文件...
[步骤3] 文件上传成功  name=sample_invoice.pdf  batch_number=<batch_number>
[步骤3] 文件上传成功  name=sample_contract.pdf  batch_number=<batch_number>
[步骤3] 文件上传成功  name=sample_inbound.pdf  batch_number=<batch_number>
[步骤3] 文件上传成功  name=sample_acceptance.pdf  batch_number=<batch_number>

开始获取处理结果...
[步骤4] 等待处理结果（batch_number=<batch_number>）..... 完成

============================================================
文件名   : sample_invoice.pdf
分类结果 : 国内票-数电票

── 普通字段 ──────────────────────────
  发票号码                : 25442000000012345678
  开票日期                : 2025-01-15
  价税合计                : 50,900.00
  税前金额                : 48,000.00
  税额                   : 2,900.00
  销售方名称               : 上海某某科技有限公司
  销售方纳税人识别号         : 91310000XXXXXXXXXX
  购买方名称               : 合合信息科技（上海）有限公司
  购买方纳税人识别号         : 91310000YYYYYYYYYY

── 表格行数据 ────────────────────────
  第1行: 商品名称=智能硬件设备  |  规格型号=XH-2000  |  单位=台  |  数量=10  |  单价=4,800.00  |  金额=48,000.00  |  税率=6%  |  税额=2,880.00

[步骤4] 等待处理结果（batch_number=<batch_number>）......... 完成

============================================================
文件名   : sample_contract.pdf
分类结果 : 采购合同

── 普通字段 ──────────────────────────
  编号                   : HT-2025-001
  甲方                   : 合合信息科技（上海）有限公司
  乙方                   : 上海某某科技有限公司
  签订日期                : 2025-01-10
  采购金额                : 50,900.00
  税率                   : 6%
  乙方税号                : 91310000XXXXXXXXXX

[步骤4] 等待处理结果（batch_number=<batch_number>）...... 完成

============================================================
文件名   : sample_inbound.pdf
分类结果 : 入库单

── 普通字段 ──────────────────────────
  收货单编号               : RK-2025-0115
  收货日期                : 2025-01-20
  对应合同号               : HT-2025-001
  供应商名称               : 上海某某科技有限公司
  入库总金额               : 50,900.00
  供应商税号               : 91310000XXXXXXXXXX

[步骤4] 等待处理结果（batch_number=<batch_number>）.... 完成

============================================================
文件名   : sample_acceptance.pdf
分类结果 : 验收单

── 普通字段 ──────────────────────────
  合同编号                : HT-2025-001
  甲方单位名称              : 合合信息科技（上海）有限公司
  乙方单位名称              : 上海某某科技有限公司
  验收结论                : 验收合格

开始配置审核规则库...
[步骤5] 规则库创建成功  name=AP审单场景审核规则库  repo_id=<repo_id>
  规则组创建成功  name=供应商一致性校验  group_id=<group_id>
    规则创建成功  name=供应商一致性  rule_id=<rule_id>
    规则创建成功  name=发票与合同金额匹配  rule_id=<rule_id>
    规则创建成功  name=发票购买方与合同甲方一致  rule_id=<rule_id>
  规则组创建成功  name=入库与合同一致性  group_id=<group_id>
    规则创建成功  name=入库数量与合同数量匹配  rule_id=<rule_id>
    规则创建成功  name=入库单号关联合同号  rule_id=<rule_id>
  规则组创建成功  name=验收合规性  group_id=<group_id>
    规则创建成功  name=验收单与入库单物料一致  rule_id=<rule_id>
[步骤6] 审核任务提交成功  task_id=<task_id>
[步骤7] 等待审核结果（task_id=<task_id>）................. 完成

============================================================
审核任务状态  : 审核通过
规则通过数    : 6
规则不通过数  : 0

── 规则组：供应商一致性校验 ───────────────────
  ✓ [高风险] 供应商一致性: 审核通过
    依据: 发票销售方纳税人识别号与采购合同乙方税号均为 91310000XXXXXXXXXX，一致。
  ✓ [高风险] 发票与合同金额匹配: 审核通过
    依据: 发票价税合计 50,900.00 与采购合同采购金额 50,900.00 完全一致。
  ✓ [中风险] 发票购买方与合同甲方一致: 审核通过
    依据: 发票购买方"合合信息科技（上海）有限公司"与合同甲方一致。

── 规则组：入库与合同一致性 ───────────────────
  ✓ [高风险] 入库数量与合同数量匹配: 审核通过
    依据: 入库单实收数量 10 台与采购合同约定数量 10 台一致。
  ✓ [中风险] 入库单号关联合同号: 审核通过
    依据: 入库单对应合同号 HT-2025-001 与采购合同编号一致。

── 规则组：验收合规性 ───────────────────
  ✓ [中风险] 验收单与入库单物料一致: 审核通过
    依据: 验收单合同编号与入库单对应合同号均为 HT-2025-001，物料关联一致。

============================================================
  示例运行完成
============================================================
```

## 09 结果说明

### 抽取结果

处理完成后，每份文件将返回分类结果和字段抽取结果。字段抽取结果位于 `data.fields[]`，表格字段位于 `data.items[][]`，每个字段包含 `key`、`value` 及坐标 `position`（可用于原文高亮回显）。

以下为发票样本文件的实际接口返回（来自 `file/fetch`，省略了部分 `position` 坐标）：

<AccordionGroup>
  <Accordion defaultOpen title="sample_invoice.pdf">
    ```json theme={null}
    {
      "id": "2029124607672344576",
      "name": "sample_invoice.pdf",
      "format": "pdf",
      "category": "国内票-数电票",
      "recognition_status": 1,
      "duration_ms": 4832,
      "data": {
        "fields": [
          { "key": "发票号码",           "value": "25442000000012345678" },
          { "key": "开票日期",           "value": "2025-01-15" },
          { "key": "价税合计",           "value": "50900.00" },
          { "key": "税前金额",           "value": "48000.00" },
          { "key": "税额",              "value": "2900.00" },
          { "key": "销售方名称",          "value": "上海某某科技有限公司" },
          { "key": "销售方纳税人识别号",   "value": "91310000XXXXXXXXXX" },
          { "key": "购买方名称",          "value": "合合信息科技（上海）有限公司" },
          { "key": "购买方纳税人识别号",   "value": "91310000YYYYYYYYYY" },
          { "key": "发票备注",           "value": "" }
        ],
        "items": [
          [
            { "key": "商品名称", "value": "智能硬件设备" },
            { "key": "规格型号", "value": "XH-2000" },
            { "key": "单位",    "value": "台" },
            { "key": "数量",    "value": "10" },
            { "key": "单价",    "value": "4800.00" },
            { "key": "金额",    "value": "48000.00" },
            { "key": "税率",    "value": "6%" },
            { "key": "税额",    "value": "2880.00" }
          ]
        ],
        "stamps": [],
        "handwritings": []
      }
    }
    ```
  </Accordion>
</AccordionGroup>

### 审核结果

审核完成后，可从 `review/task/result` 接口获取以下信息：

* **`status`**：任务整体状态（`1`=审核通过，`4`=审核不通过，`2`=审核失败）
* **`statistics`**：规则通过数、不通过数汇总
* **`groups[].review_tasks[]`**：每条规则的详细审核结果，包含：
  * `review_result`：该规则的审核结论（`1`=通过，`4`=不通过）
  * `reasoning`：AI 给出的审核依据说明
  * `anchors`：依据在原文中的坐标位置（可用于高亮回显）

```json theme={null}
{
  "task_id": "31415926",
  "task_name": "AP审核",
  "status": 1,
  "statistics": { "pass_count": 6, "failure_count": 0, "error_count": 0 },
  "groups": [
    {
      "group_name": "供应商一致性校验",
      "review_tasks": [
        {
          "rule_name": "供应商一致性",
          "risk_level": 10,
          "review_result": 1,
          "reasoning": "发票销售方纳税人识别号与采购合同乙方税号均为 91310000XXXXXXXXXX，一致，审核通过。"
        },
        {
          "rule_name": "发票与合同金额匹配",
          "risk_level": 10,
          "review_result": 1,
          "reasoning": "发票价税合计 50900.00 与采购合同采购金额 50900.00 完全一致，审核通过。"
        },
        {
          "rule_name": "发票购买方与合同甲方一致",
          "risk_level": 20,
          "review_result": 1,
          "reasoning": "发票购买方"合合信息科技（上海）有限公司"与采购合同甲方一致，审核通过。"
        }
      ]
    },
    {
      "group_name": "入库与合同一致性",
      "review_tasks": [
        {
          "rule_name": "入库数量与合同数量匹配",
          "risk_level": 10,
          "review_result": 1,
          "reasoning": "入库单实收数量 10 台与采购合同约定数量 10 台一致，审核通过。"
        },
        {
          "rule_name": "入库单号关联合同号",
          "risk_level": 20,
          "review_result": 1,
          "reasoning": "入库单对应合同号 HT-2025-001 与采购合同编号一致，审核通过。"
        }
      ]
    },
    {
      "group_name": "验收合规性",
      "review_tasks": [
        {
          "rule_name": "验收单与入库单物料一致",
          "risk_level": 20,
          "review_result": 1,
          "reasoning": "验收单合同编号与入库单对应合同号均为 HT-2025-001，物料关联一致，审核通过。"
        }
      ]
    }
  ]
}
```
