mcpField
T
tres-invoice-bill-matching

tres-invoice-bill-matching

github.com/anthropics其他4.8k49 次安装2 周前更新
代码仓库

关于 tres-invoice-bill-matching

tres-invoice-bill-matching 是用于将 TRES 账本中的区块链交易与 ERP 发票或账单匹配,并可选同步到 ERP 的对话式技能。它通过候选项和用户确认来完成匹配与更新。

主要功能

  1. 01检查已连接的 ERP
  2. 02按交易或单据查找匹配项
  3. 03根据金额和日期筛选候选项
  4. 04配置付款账户与法币对齐
  5. 05确认后应用匹配并可选同步

适用场景

  1. 01将链上付款匹配到 ERP 账单
  2. 02将入账交易与 ERP 发票关联
  3. 03查找特定发票或账单对应的交易

MCP 相关

使用 TRES 的 GraphQL 操作查询 ERP 集成、发票、账单和交易,并在用户明确批准后执行匹配或同步变更。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/anthropics/claude-plugins-community --skill tres-invoice-bill-matching

安装后在 Claude Code 中输入/tres-invoice-bill-matching确认已加载。

详细介绍

TRES — 发票/账单匹配与 ERP 同步

端到端工作流:让用户在 TRES 账本中将未结清的 ERP 发票或账单与区块链交易进行匹配,然后可选择将匹配的条目推送到已连接的 ERP。

无论用户从哪一端开始(交易哈希或发票/账单 ID),流程都相同。该技能会逐步引导用户完成七个对话步骤(验证 ERP → 确认输入 → 获取并提供建议 → 用户选择 → 配置付款账户和法币 → 确认并应用 → 循环)。保持简洁——显示编号选项,记录用户的选择,然后继续。未经用户明确回答“是”,绝不执行任何变更。


基本原则

  1. 先确认组织。 从 get_viewer 开始,并告诉用户“您已连接到 {orgName}。”这样,如果有人使用了错误的令牌,也能及时发现并纠正。
  2. 先读取,再写入。 在显示变更摘要前,务必获取交易、发票/账单和付款账户的当前状态。出错比操作慢更糟。
  3. 变更需要明确批准。 显示摘要表(交易 · 发票/账单 · 付款账户 · 法币对齐 · 同步),并在任何变更前询问“应用这些变更吗?”。只有用户明确同意后才能继续。
  4. 不确定时,使用架构内省。 字段名、枚举值和参数结构可能会发生变化。如果查询/变更因“unknown field”或“invalid enum”报错,请调用 introspect(<TypeName>) 或 build_query(<operationName>) 并进行调整——不要猜测。下文特别标注为“运行时验证”的操作最可能需要这样处理。
  5. 此技能采用循环流程。 匹配成功后,询问“还要匹配其他项目吗?”,并从步骤 2 重新开始。不要重新检查 ERP——每个会话只需检查一次。

步骤 1 — 验证 ERP 是否已连接

运行:

query { integration(first: 50) { results { id integratedApp isErp connectionStatus companyName } } }

筛选出 isErp == true 且 connectionStatus == "ACTIVE" 的结果。应能识别的受支持 ERP 包括 Xero、QuickBooks Online (QBO) 和 NetSuite——integratedApp 的取值分别为 XERO、QUICKBOOKS 和 NETSUITE。(如果遇到未知值,introspect("IntegrationsQueryNode") 可以确认枚举。)忽略 integratedApp 为空的行——API 偶尔会返回空行。

  • 未连接 ERP: 告诉用户必须先连接 ERP 才能进行匹配,并引导他们访问 https://app.tres.finance/settings/integrations,然后停止。
  • 已连接一个 ERP: 默认使用该 ERP,只需说明“正在与 {companyName}({integratedApp})进行匹配。”
  • 已连接多个 ERP: 询问用户要使用哪一个——不同的 ERP 各自有独立的发票/账单存储。

缓存所选 ERP 的 id、integratedApp 和 companyName,供后续步骤及循环使用。


步骤 2 — 确认用户掌握的信息

询问用户是否有:

  • 交易哈希(例如 0x…)——最佳情况,可立即锁定匹配项;
  • 发票/账单 ID 或编号(数字格式的内部 ID,或面向用户的 invoiceNumber/billNumber);
  • 或者两者都有。

如果两者都没有,要求用户至少提供一项。如果他们不确定该标识符对应的是发票还是账单,也可以接受,并在步骤 3 中尝试两种查询。

也接受较宽松的描述形式——“INV-123”、“账单 9988”、“上周给 Acme 的账单”。erpInvoices / erpBills 上的 freeText 筛选器可以处理这些描述。

继续之前,如果用户尚未提供交易哈希,务必询问交易日期(或大致的日期范围)。 账本交易量很大——日期是缩小候选范围最有用的单一筛选条件。同时也可以补充:“如果您刚好有交易哈希,请现在粘贴——这样就能精确锁定匹配项。” 无论从交易查账单,还是从账单查交易,日期都很重要。


步骤 3 — 获取已知对象并生成排序后的匹配建议

分为两个分支。根据用户提供的信息选择相应分支。如果用户同时提供了交易哈希和发票/账单 ID,请直接跳到步骤 5(匹配项已确定)。

分支 A — 用户有交易哈希
  1. 获取交易及其子交易:
    query GetTx($hash: String!) {
      transaction(identifier: $hash, currency: "usd", limit: 1) {
        results {
          id identifier timestamp platform
          children {
            id amount balanceFactor isInternalTransfer
            fiatValue
            sender    { identifier displayName isInternal }
            recipient { identifier displayName isInternal }
            asset { symbol identifier }
          }
        }
      }
    }
    
  2. 选出相关子交易。跳过 Gas 和内部转账,优先选择一方是用户钱包、另一方是外部交易对手的交易。判断方向:
    • balanceFactor 为负 → 资金流出 → 查找要结清的账单。
    • balanceFactor 为正 → 资金流入 → 查找要结清的发票。 如果有多个符合条件的子交易(例如包含多个交易环节的兑换),请列出并让用户选择一项。
  3. 对于发票(资金流入),先尝试后端匹配建议——这些建议已预先计算并排序:
    query Suggest($subTxIds: [String]!) {
      subTransactionToInvoiceMatchSuggestions(
        subTransactionId_In: $subTxIds, minScore: 0.3, ordering: "-score", first: 10
      ) {
        results {
          id score confidenceTier
          scoreBreakdown { txHashMatch primaryMatchFactors }
          invoice {
            id invoiceId invoiceNumber customerName origAmount balance dueDate billingStatus
            integration { integratedApp companyName }
          }
        }
      }
    }
    
    重要提示:此端点仅适用于发票。对于账单(资金流出),请直接跳到下面的备用方案——架构中没有公开后端账单建议查询。
  4. **备用方案(没有发票建议时,或始终适用于账单):**查询 erpInvoices(资金流入)或 erpBills (资金流出),并按以下条件筛选:
    • 金额范围:子交易法币金额的 ±20%。
    • 日期范围:dateCreated_Range = [tx.timestamp − 60d, tx.timestamp] — 账单/发票的开具时间应在付款当天或之前,绝不会在付款之后。无需考虑日期晚于付款日期的发票/账单。
    • 联系人:如果用户提供了供应商/客户的名称,请将其作为 freeText 传入。切勿尝试将链上收款地址与 ERP 联系人匹配——ERP 联系人标识符(来自 QBO/Xero/NetSuite)是内部 ID,绝不是钱包地址。有些联系人标签的文本碰巧类似供应商名称,但架构没有“类似”筛选条件,因此请使用 freeText 搜索 vendor/customer 字段。 在客户端按以下顺序对备用结果集排序:金额接近程度 → 日期接近程度(优先选择交易前最近的账单/发票)→ freeText 输出中的名称匹配项。
  5. 按编号列出排名靠前的至多 5 项(绝不能更多——选项太多不如太少)。每项显示:置信度等级、金额($)、客户/供应商名称、invoiceNumber/billNumber、到期日,以及 primaryMatchFactors(例如 amount_exact、contact_match)。最匹配的排在最前。
分支 B — 用户有发票/账单 ID 或编号
  1. 解析实体。先尝试 erpInvoices,如果不是发票,再尝试 erpBills(如果用户说的是“账单”,则反过来)。对于发票,包含内嵌的建议:
    query GetInvoice($id: Float, $text: String) {
      erpInvoices(id: $id, freeText: $text, first: 1) {
        results {
          id invoiceNumber customerName origAmount balance dateCreated dueDate billingStatus
          integration { integratedApp companyName }
          suggestedSubTransactionMatches {
            id score confidenceTier
            subTransaction {
              id amount fiatValue
              asset { symbol identifier }
              tx { identifier timestamp platform }
            }
          }
        }
      }
    }
    
    对于账单,查询 erpBills——注意,账单不会公开 suggestedSubTransactionMatches,因此只获取账单元数据(id billNumber vendorName vendorId origAmount balance dateCreated dueDate billingStatus integration { integratedApp companyName }),然后直接进入后备步骤。如果 id 查询无结果,则使用 freeText: $userInput 重试。
  2. 对于发票,将内嵌的 suggestedSubTransactionMatches 用作排序后的列表。
  3. 后备方案(发票没有建议结果,或账单一律如此):
    • 首先,询问用户大致的付款日期(并提醒他们:“如果你有 tx hash,那是最快的方式”)。付款发生在账单/发票日期当天或之后,通常在几天内——不会在之前。 如果用户无法提供具体日期,默认使用 [dateCreated, dateCreated + 60 days] 作为时间范围。
    • 使用服务端筛选条件查询 transaction,避免拉取整个账本。使用:
      • platform: <configuredNetwork or user's network>(例如 "ethereum"),
      • timestamp_Gte / timestamp_Lte → 用户提供的日期范围,
      • children_Asset_Identifier_In: [<assetIdentifier>] → 账单的 configuredAsset.identifier(例如 USDC 合约),或发票的预期资产,
      • children_FiatValue_Between: "<low>,<high>" → origAmount 附近的法币金额范围(例如 ±20%)。这是由两个逗号分隔数字组成的字符串。例如,"0.4,0.6" 表示一笔 $0.50 的账单。
      • 可选的 children_BalanceFactor: -1(资金流出,适用于账单)或 1(资金流入,适用于发票)。
      • 仅当无法信任法币价格时,才将 children_Amount_Between 用作额外筛选条件(例如,经过预定价的历史资产等)。
    • 如果筛选结果仍然很多,在展示结果前,请用户缩小日期范围或进一步 уточ金额范围。
  4. 以编号列表形式展示最多 5 笔候选交易——每笔交易都显示: **tx hash(截短为 0xabcd…1234)、发送方 → 接收方地址(相同的缩短格式)、代币金额 + 符号、法币价值和时间戳。**tx hash 是用户能识别的面向用户标识;原始地址和代币金额可在仅凭法币金额过于模糊时帮助区分(许多交易的金额相近)。**绝不要向用户显示 subTxId 之类的内部 ID——这些对用户毫无意义。**将 subTxId 保留在内部供变更操作使用;所有面向用户的输出都应通过 tx hash 引用该交易。 如果没有合适的匹配项,请如实告知并询问 tx hash——不要猜测并倾倒一大串结果。

第 4 步 — 用户选择匹配项(或要求查看更多)

提示:“选择一个编号,或输入 more 以扩大搜索范围(告诉我一个联系人姓名、日期或金额,方便我缩小范围)。”

  • 输入编号时:捕获选定的 (subTxId, invoiceOrBillId, entityType),然后继续第 5 步。
  • 输入 more 时:使用更宽松的范围或用户补充的线索(联系人筛选条件、扩展后的日期范围、金额范围)重新查询,展示新的列表并重复此步骤。
  • 用户说“这些都不是”或类似内容时:妥善结束——“好的,没有匹配项。等你有更多信息时再告诉我。”

第 5 步 — 配置付款账户和(可选)法币对齐

选定一对匹配项后:

  1. 存款账户(用于 matchApAr.depositAccountId)。 这是一个 ERP 集成账户 (账单将记入的 Xero/QBO/NetSuite 总账账户,例如“Crypto Wallet – ETH”、 “Cash and cash equivalents”)。它不是 tres 内部账户或钱包账户。Schema 外键指向 schema_integrationaccount;该值位于 ErpBill.depositAccount / ErpInvoice.depositAccount 中,类型为 IntegrationAccountQuery { id name type value }。

    解析顺序:

    1. 使用账单/发票上预设的账户。 在 ERP 中创建实体时,用户通常已选择存款账户。读取 erpBills.results[].depositAccount.id(或 erpInvoices.results[].depositAccount.id)。如果该值 非 null,则将该 id 用作 depositAccountId,并在摘要中提及即可——无需询问。
    2. 否则询问用户。 查询 integrationAccount(integration: <erpId>, first: 100),并以编号列表向用户 展示 ASSET 类型的账户(现金/钱包/加密货币总账账户);记录用户选择的 integrationAccount.id。
    3. paymentToInternalAccounts 在 tres 端将 钱包 → 资产 映射起来,适用于出款 工作流——它不是 matchApAr 的 depositAccountId 来源。此处不要使用它。
  2. 法币对齐。 比较子交易的 fiatValue 与发票/账单的 origAmount。分三种情况:

    • fiatValue 为 null 或 0:询问 “此交易尚未设置法币价值。是否将其对齐为 ${origAmount}, 以便该 {bill/invoice} 全额结清?(y/n)” — 不设默认选项,必须明确答复是。
    • fiatValue 与 origAmount 不同:询问 “是否将交易法币价值从 $X 对齐为 $Y,以便 AP/AR 全额结清?(y/n)” — 不设默认选项,必须明确答复是。
    • 数值匹配:跳过。 未经明确同意,绝不要运行 setManualFiatValue——即使用户最初的请求暗示要“结清发票”, 法币对齐也是单独的写入操作,需要单独征得同意。如果用户回答否,匹配仍会继续,但该实体可能无法全额付款。

步骤 6 — 确认并应用

显示以下汇总表——仅使用人类可读的值:tx 哈希(截断)、付款账户名称 (绝不使用其 ID)、发票/账单编号或客户/供应商名称。内部 ID(subTxId、depositAccountId、 DB entityId)仅用于变更载荷,绝不向用户展示。

交易0xabcd…1234 · {asset.symbol} {amount} · ${fiatValue}
发票/账单{invoiceNumber or billNumber} · {customer/vendor} · ${origAmount} {currency}
付款账户{depositAccount.name}
对齐法币金额是 → ${origAmount} / 否
匹配后同步到 ERP是 / 否

询问:"将这些变更应用到 {orgName}?(是/否)"——只有用户回答是才继续。将此视为仅批准 匹配操作。法币金额对齐和 ERP 同步都需要各自单独的明确肯定答复(法币金额在步骤 5 确认, 同步在下方提问)——即使用户最初的请求中说了“同步到 QBO”,也仍要在此确认,因为用户是在看到 实际匹配详情之前提出的请求。

然后按以下顺序执行变更,并逐项报告结果:

  1. 匹配(始终执行):

    mutation Match($entityType: String!, $matches: [SubTxMatchInput]!) {
      matchApAr(entityType: $entityType, matches: $matches) {
        results { subTxId entityId depositAccountId }
      }
    }
    

    变量:

    • entityType:小写——"invoice" 或 "bill"。大写值会被拒绝,并返回 Invalid entity_type。
    • matches[].subTxId:字符串(例如 "4548595830")。
    • matches[].entityId:整数——发票/账单的 DB id(来自 erpInvoices.results[].id / erpBills.results[].id),而不是面向用户的 invoiceNumber/billNumber。传入字符串 会报错 "Int cannot represent non-integer value";传入账单编号则查无结果,并报错 "One or more Bill IDs not found"。
    • matches[].depositAccountId:整数——集成账户 ID(见步骤 5)。
  2. 法币金额对齐(仅当用户选择进行时):

    mutation AlignFiat($id: String!, $newFiatValue: String!, $currency: String) {
      setManualFiatValue(id: $id, newFiatValue: $newFiatValue, currency: $currency) { success }
    }
    

    将子交易 ID 作为 id,将目标值作为字符串传入 newFiatValue(例如发票/账单的 origAmount,如 "123.45"),并设置 currency: "usd"。如果响应返回与“locked period”(锁定期间)相关的错误,说明包含该交易的会计期间已关闭——向用户说明情况;不要尝试强制执行。

  3. ERP 同步(每次都先询问): "现在将此交易同步到 {erpName}?(是/否)"——此时未获得明确肯定答复, 绝不进行同步,即使用户最初的请求中包含“并同步到 QBO”也是如此。同步调用会在 ERP 中显示, 且比匹配操作更难撤销,因此需要单独确认。若回答是:

    mutation Sync($txIds: [String]!, $entityType: String!) {
      syncSpecificTransactions(transactionIds: $txIds, entitySourceType: $entityType) { status }
    }
    

    entitySourceType 与匹配调用中的 entityType 保持一致。

向用户报告结果时,请用tx 哈希(截断)来指代交易,并用付款账户的名称来指代账户——绝不使用 subTxId 或 depositAccountId。这些内部 ID 仅用于调试,不应出现在面向用户的输出中。

如果任何变更报错,请原样显示错误消息,并提出重试。真正将记录关联起来的是匹配操作——如果它失败, 后续操作都没有意义。


步骤 7 — 循环

询问:"再匹配一笔交易或一张发票/账单?(是/否)"

  • 是 → 从步骤 2 重新开始(跳过步骤 1——保留本次会话中缓存的 ERP)。
  • 否 → 结束:"完成。本次会话已处理 {n} 项。"

已验证使用的 TRES MCP 操作

用途操作类型
组织身份get_viewerMCP 工具
架构发现introspect, build_queryMCP 工具
检查 ERP 连接integration(筛选条件 isErp=true)查询
按哈希获取交易transaction(identifier:)查询
获取发票(包含嵌入的建议)erpInvoices查询
获取账单(包含嵌入的建议)erpBills查询
预计算的子交易 → 发票匹配建议subTransactionToInvoiceMatchSuggestions查询
映射至 COA 的付款账户paymentToInternalAccounts查询
匹配子交易 ↔ 发票/账单matchApAr变更
调整法币价值setManualFiatValue(在运行时验证参数)变更
将交易同步至 ERPsyncSpecificTransactions变更
撤销匹配(应用户要求)manualUnmatchSubtransactions变更

不在支持范围内(如有询问,请礼貌地引导)

  • 批量匹配(多对多)——此技能尚不支持。
  • 发送付款(sendBillPayment、sendInvoicePayment)——属于单独的工作流。
  • 连接或撤销连接 ERP 本身——请使用 tres-settings-management 技能。
  • 以叙述形式解释交易——请使用 tres-tx-story。
  • 将区块浏览器链接导入账本——请使用 tres-explorer-tx-to-ledger。

评论

支持 Markdown