采购管理

本页是一篇完整方案指南:以 procurement 插件(com.auraboot.procurement,命名空间 pr,依赖 product-catalog / crm / inventory / finance / quality)为例,从用户场景一路讲到开发实施和典型错误。它声明 23 个 model、95 条命令、42 个页面,绝大部分能力靠 DSL JSON 配置,另带一个小后端 jar 为 8 条命令挂自定义 handler(收货回写已收量、需求转订单等)。下面每个标识符你都能在插件里 grep 到、对运行实例调得通。

注意命名:模型与字段前缀是 pr_(不是 proc_),命令码是冒号格式 pr:动词_名词(不是点号)。本页所有标识符以 /Users/ghj/work/auraboot/plugins/procurement/ 下的真实配置为准。


1. 用户场景

一家制造企业的采购部,对接数十家供应商,日常覆盖:

  • 业务部门或 MRP 提采购需求 → 采购专员转为采购订单;
  • 采购订单提交审核 → 审批通过 → 收货 → 完成,大额订单需多级签字;
  • 供应商先发预发货通知(ASN),到货后做收货与验收;
  • 采购订单、收货单、供应商发票做三方匹配,差异要标记并解决;
  • 委外加工:外协订单 → 发料 → 加工 → 收货质检;
  • 框架合同管价目与变更,周期末按维度给供应商打评分卡

采购、生产、财务看到的数据视图和能做的操作各不相同。

采购管理(采购订单)—— 供应商解析为名称、总金额自动算,状态:草稿 → 待审核 → 已审核(中文电子元器件采购演示数据)

三方匹配 —— 采购订单 × 收货 × 发票按数量/价格核对,差异自动算,状态:待处理 / 有差异 / 已匹配

2. 需求痛点

  • 跨步骤契约靠人维护:"这张订单要先审批才能收货""收货数量要回写订单行""ASN 没到货不让收货"——这些规则散落在前端、脚本、人脑里。
  • 金额阈值与审批授权脱节:谁能审批多大金额的订单,没有统一闸门;改一次阈值要改好几处代码。
  • 操作无授权无审计:谁在什么时候把订单推到了下一状态、为什么,没有记录。
  • 集成困难:需求、收货、发票想自动触发下游动作(库存、财务),却只能人工二次录入。

这些都不是「再加一张表」能解决的,而是受控状态变更的问题。

3. 常规解法 vs AuraBoot 的设计哲学

3.1 常规解法是怎样的

如果让一个团队从零做采购到付款(P2P),通常是这条路:

  1. 领域建模:画实体和关系——供应商、采购需求、采购订单、收货单、发票、三方匹配、合同、外协单……
  2. 建表:把实体翻译成一堆 CREATE TABLE,加外键、状态字段、金额字段。
  3. 写 CRUD:每个实体一套 Repository / Service / Controller,增删改查全手写。
  4. 把业务规则 hard-code 进 service:「订单要先审批才能收货」「收货数量要回写订单行」「ASN 没到货不让收货」「订单×收货×发票三方核对」「按金额分多级审批」——全写死在 Java 里,审批阈值散落在 if-else 中。
  5. 各处补横切关注点:权限判断散落在每个 controller;审计靠手动插日志;想把收货、付款事件发给库存/财务,再搭一套集成。
  6. 前端:每个页面手写表单、列表、详情。
  7. 想接 AI / 自动化:对不起,得再包一层 API、再定义一遍权限和风险边界。

能跑,但审批规则写死在代码里,改一档金额阈值要改好几处;三方对账只能靠人逐张比对订单、收货、发票;供应商和价目主数据散落在各处;并发、审计、事件、AI 入口每一样都得自己扛。三个月起步,而且越改越脆。

3.2 AuraBoot 的设计哲学

AuraBoot 把这件事反过来:业务的「是什么」用声明描述,「怎么执行」由运行时统一兜底。三条核心理念:

  • 元数据驱动:model / field / command / page / permission 都是声明(DSL JSON),不是手写代码。平台据此自动建表、生成接口、渲染页面——供应商主数据、合同价目、订单明细都是声明出来的模型,上面第 2、3、6 步基本消失。
  • 单一命令管道:每个采购动作都是一条命令,走同一条 命令管道。鉴权、校验、状态机守卫、事务、审计、发事件这些横切关注点由管道统一处理,不写进每个业务里——你声明 pr:approve_purchase_order 时只关心「pending→approved + 权限」,「草稿不能直接收货」「没有明细不能提交」由 fromStates/toStatehas_children 校验白送(第 4、5 步从「自己扛」变成「平台默认」)。
  • 命令即契约:同一条命令同时服务 UI 按钮、自动化规则(按金额路由审批)、BPM 节点、AI agent(靠 cmd_risk_level + agent_hint 分级)。改审批闸门是改规则与权限,不是改命令代码;AI 原生不是事后包 API,而是天生的(第 7 步免了)。

3.3 同一个功能,两种活法

于是普通做法里那些「自己扛」的事,在 AuraBoot 变成平台契约的默认能力。每一格的 AuraBoot 列都是上面能 grep 到的真实命令/模型,不是宣传话术:

能力自己写(手写后端)打包 ERP / 典型低代码AuraBoot(本插件)
多级审批 / 金额阈值阈值与审批授权写进 if-else,改一档要动代码审批流现成,但规则写死,改阈值/加层级要二开pr:submit_purchase_order(draft→pending)+ pr:approve_purchase_order(pending→approved),阈值路由由自动化规则 + 权限决定,命令不改
三单匹配(PR→PO→收货→发票)自己写比对脚本,人逐张核三单多数有匹配模块,但差异规则常要定制pr_three_way_matchpr:match_three_way(→matched)/ pr:flag_variance(→variance,L2)/ pr:resolve_three_way_match(→resolved),状态机内建
收货回写订单 / 跨步骤契约手写「收货数量回写订单行」,易漏易错闭源,想 hook 收货回写很难pr:receive_purchase_order(approved→receiving,带 handler)由后端按行回写已收量、自动建入库单
合同 / 价目主数据自建合同表 + 手写生效/变更/到期逻辑有合同,框架价目/变更常要加购模块pr_contractpr:activate_contract / pr:add_amendment / pr:terminate_contract,生命周期声明化
被自动化 / AI 调用还要再包一层 API,且无风险分级基本无原生 AI 入口同一条命令带 cmd_risk_level + agent_hint,UI / 自动化 / BPM / AI agent 同一条路径,安全可控
权限 + 审计散落在各 controller,易漏角色粗粒度,字段级常缺14 个权限码 + 审计内建在命令管道,每次状态变更自动留痕

一句话:手写要三个月、还得自己扛审批阈值和三单对账;打包 ERP 快但改不动;AuraBoot 用声明式配置就拿到一套 production 级的采购到付内核,而且每个能力都能被 AI 安全驱动、被你自由扩展。 下面看它具体怎么搭。

4. 功能设计

4.1 数据模型(23 个)

Model用途关键状态字典
pr_supplier_common供应商主数据(分类 / 等级 / 联系方式)pe_enable_status:enabled / disabled
pr_purchase_request采购需求pe_request_status:pending / processing / completed / cancelled
pr_purchase_order / pr_purchase_order_line采购订单 + 明细pe_order_status:draft / pending / approved / delivering / receiving / completed / cancelled
pr_purchase_receipt / pr_purchase_receipt_line收货记录 + 明细
pr_asn_common预发货通知(ASN)pr_asn_status:draft / sent / in_transit / received / cancelled
pr_purchase_order_confirmation_common供应商订单确认pr_oc_status:pending / confirmed / partial / rejected / deviation_proposed / deviation_accepted / deviation_rejected
pr_purchase_return / pr_purchase_return_line采购退货单 + 明细pe_return_status:draft / pending / approved / confirmed / cancelled
pr_purchase_payment付款记录pe_payment_status:not_paid / partial / fully_paid
pr_three_way_match三方匹配结果(订单×收货×发票)pr_match_status:pending / matched / variance / resolved
pr_contract / pr_contract_line / pr_contract_amendment采购合同 / 明细 / 变更pr_contract_status:draft / under_review / active / expiring / expired / terminated
pr_supplier_scorecard / pr_scoring_criteria / pr_scorecard_detail供应商评分卡 / 评分标准 / 评分明细pr_scorecard_status:draft / submitted / approved
pr_outsource_order / pr_outsource_order_line外协订单 + 物料明细pr_oso_status:draft / submitted / approved / materials_sent / in_progress / received / completed / cancelled
pr_outsource_receipt / pr_outsource_receipt_line外协收货单 + 明细pr_osr_status:draft / pending_qc / qc_passed / qc_failed / completed
pr_spend_category费用分类

4.2 命令与状态机

命令命名 pr:<动词>_<名词>(冒号 + 下划线)。以采购订单为例,状态机由几条命令组成:

命令流转
pr:submit_purchase_orderdraft → pending(提交审核)
pr:approve_purchase_orderpending → approved(审核通过)
pr:receive_purchase_orderapproved → receiving(收货,带 handler)
pr:complete_purchase_orderreceiving → completed(完成)
pr:cancel_purchase_orderdraft / pending / approved → cancelled(取消)

其他主链路命令:pr:convert_request_to_po(需求转订单,带 handler)、pr:create_purchase_receipt / pr:confirm_purchase_receipt(创建 / 确认收货)、pr:match_three_way / pr:flag_variance / pr:resolve_three_way_match(三方匹配 / 标记差异 / 解决)、pr:activate_contract / pr:add_amendment / pr:terminate_contract(合同启用 / 变更 / 终止)、pr:submit_scorecard / pr:approve_scorecard(评分卡提交 / 审批)、pr:create_outsource_order / pr:send_materials / pr:receive_outsource(外协下单 / 发料 / 收货)。

每条命令都是一段声明。例如 pr:submit_purchase_order(config/commands/pr_submit_purchase_order.json)的真实定义:

{
  "code": "pr:submit_purchase_order",
  "displayName:zh-CN": "提交审核",
  "displayName:en": "Submit Order",
  "description": "Submit purchase order for approval: draft -> pending; requires at least one line item.",
  "type": "state_transition",
  "modelCode": "pr_purchase_order",
  "stateField": "pr_po_status",
  "fromStates": ["draft"],
  "toState": "pending",
  "validation": {
    "rules": [
      { "type": "has_children", "childModel": "pr_purchase_order_line",
        "parentField": "pr_pol_order_id", "minCount": 1,
        "message:zh-CN": "请至少添加一条采购订单明细后再提交" }
    ]
  },
  "permissions": ["pr.purchase.manage"],
  "agent_hint": "Transition pr purchase order status from draft to pending.",
  "cmd_risk_level": "L1"
}

读出来的设计信息:这是一条 state_transition(draft → pending),带 has_children 校验(没有明细行不让提交),要求 pr.purchase.manage 权限,风险级 L1,并通过 agent_hint 告诉 agent 它能做什么。状态字段是 pr_po_status,值约束来自字典 pe_order_status

需要写代码的命令多一个 handler 字段,例如 pr:receive_purchase_order 声明 "handler": "pr:receive_purchase_order",由插件后端的 ReceivePurchaseOrderHandler 按行回写采购订单行的已收数量——纯状态流转(如 submit / approve)不需要 handler。

4.3 权限与角色

14 个权限码(<模块>.<资源>.<动作>,每资源 manage + read):

pr.supplier.read           pr.supplier.manage
pr.purchase.read           pr.purchase.manage
pr.outsource.read          pr.outsource.manage
pr.three_way_match.read    pr.three_way_match.manage
pr.scorecard.read          pr.scorecard.manage
pr.contract.read           pr.contract.manage
pr.spend.read              pr.spend.manage

4 个角色:pr_admin(ERP 管理员,全部权限)、pr_purchaser(采购专员)、pr_production(生产主管,只管外协)、pr_finance(财务专员,采购只读)。命令 permissions 里绑的就是这些权限码——pr:approve_purchase_orderpr.purchase.manage,只有 pr_adminpr_purchaser 持有。

4.4 页面

42 个页面:各 model 的 list / form / detail 三件套(采购订单、收货、ASN、退货、付款、合同、评分卡、外协、供应商、三方匹配、费用分类等),另有 2 个 dashboard(pr_procurement_dashboard 采购总览、pr_spend_analysis_dashboard 费用分析)。

5. 具体开发与实施

先掌握基础。本插件主体是配置,只为少数命令挂后端 handler。动手前请先读:Model 与 Field · Command · 命令管道 · Permission · 插件清单 · 纯配置 Plugin · Page Designer

落地一个像 procurement 这样的插件,步骤是:

  1. 定义 model 与字段 —— config/models.json + config/fields/,字段类型用平台 dataType(string / integer / enum / decimal / date…),枚举字段用 dictCode 指向 config/dicts.json 里的字典(如 pr_po_statuspe_order_status)。详见 Model 与 Field
  2. 声明命令 —— 每个状态流转一个 config/commands/<动词>_<名词>.json,用 type: state_transition + fromStates / toState,并在 permissions 绑权限码;需要写业务逻辑的命令多加 handler 字段并在后端实现对应 handler。详见 Command
  3. 配 binding 与 bindingRules —— model-field binding 放 config/bindings/;命令级钩子(如 currencyConversionHandler 汇率换算)放独立 config/bindingRules.json,并在 plugin.jsonresourceDirs 注册(见「典型错误」)。
  4. 设计页面 —— config/pages/,list / form / detail 用 Page Designer 出 DSL。
  5. 权限、角色、字典、菜单 —— config/permissions.json / roles.json / dicts.json / menus.json
  6. 打包导入 —— 用 aura CLI 的 import-directory-sync(参数是目录 path)或平台导入接口;校验返回 success:true 才算导入成功。带后端 jar 的插件还要把 backend/build/libs/procurement-plugin-1.0.0.jar 编出来、装进插件目录后重启 backend,否则 handler 命令报 [S-EXT-HANDLER] references unregistered handler。详见 插件清单

6. 常见配置

  • 审批阈值:用自动化规则在 pr:submit_purchase_order 之后按金额路由——小额由 pr:approve_purchase_order 自动审批,大额挂人工任务;命令本身只管 pending → approved 的合法性,审批授权由权限 + 规则决定。
  • 三方匹配差异:pr_three_way_matchpr:match_three_way(pending → matched)→ 发现差异 pr:flag_variance(→ variance)→ 处理后 pr:resolve_three_way_match(→ resolved),全程在 pr_match_status 上。
  • 合同生命周期:pr_contract_status 从 draft 经 pr:submit_contract / pr:activate_contract 到 active,pr:add_amendment 记变更,到期 pr:expire_contract / 终止 pr:terminate_contract
  • 外协闭环:pr_oso_status 走 draft → submitted →(pr:approve_outsource_order)approved →(pr:send_materials)materials_sent →(pr:start_outsource)in_progress →(pr:receive_outsource)received → completed。
  • 汇率换算:多币种订单在 config/bindingRules.json 里给 pr:create_purchase_ordercurrencyConversionHandler,把外币金额按汇率折算到本位币字段,无需改命令定义。

7. 典型错误

  • 命令码用点号:写成 proc.po.approve 跑不通——真实是冒号 + 动词_名词:pr:approve_purchase_order
  • 模型前缀用 proc_:模型是 pr_ 前缀,且供应商是 pr_supplier_common、采购订单是 pr_purchase_order、收货是 pr_purchase_receipt(不存在 proc_supplier / proc_po / proc_grn / proc_rfq 这类名字)。
  • 绕过命令直接改订单表:直接 UPDATE pr_purchase_order 会跳过状态机、权限校验、has_children 校验和 handler 的下游回写(如收货回写已收量),导致数据失真。一切状态变更都走命令
  • 提交时没有明细行:pr:submit_purchase_orderhas_children 校验会拒绝(「请至少添加一条采购订单明细」)——这是设计,不是 bug。
  • bindingRules 写进 commands.json 内联:不会被导入;必须独立 config/bindingRules.json 并在 resourceDirs 注册,否则命令钩子(如汇率换算)静默不生效。
  • handler 命令只导配置不打 jar:pr:receive_purchase_order 等 8 条命令带后端 handler,光导 config 不够;jar 没编、没装、没重启会报 [S-EXT-HANDLER] references unregistered handler
  • 命令执行 payload 结构:字段放在 { "payload": { ... }, "operationType": ... },目标记录用 targetRecordId(不是 recordId)——放错位会出现「执行成功却字段为空」的迷惑性报错。

下一步

  • 系统总览 —— 插件、命令与运行时如何拼到一起
  • 命令管道 —— 上面每条命令都走的执行契约
  • 权限 —— 上面角色背后的五层模型
  • 各版本能力差异见 Pricing