tres-invoice-bill-matching について
tres-invoice-bill-matchingは、TRES台帳のブロックチェーン取引をERPの請求書や仕入先請求書と照合し、任意でERPへ同期する対話型スキルです。候補を提示し、変更前に明示的な承認を求めます。
主な機能
- 01接続済みERPの確認
- 02取引または請求書から候補を検索
- 03金額と日付による候補の絞り込み
- 04支払口座と法定通貨の設定
- 05承認後の照合と任意の同期
活用シーン
- 01オンチェーンの支払いをERPの仕入先請求書と照合
- 02入金取引をERPの請求書に関連付け
- 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)から始めても、フローは同じです。このスキルでは、会話形式の 7 つのステップ(ERP を確認 → 入力を特定 → 取得して候補を提示 → ユーザーが選択 → 支払いアカウントと法定通貨を設定 → 確認して適用 → 繰り返し)を進めます。簡潔に対応してください。番号付きの選択肢を示し、ユーザーの選択を受け取って次に進みます。ユーザーから明示的な「はい」を得る前に、変更操作を実行してはいけません。
基本ルール
- まず組織を特定します。
get_viewerを実行し、ユーザーに「{orgName} に接続しています。」と伝えます。これにより、誤ったトークンを使っていた場合も修正できます。 - 書き込みの前に読み取ります。 変更内容の概要を示す前に、取引、請求書/買掛請求書、支払いアカウントの現在の状態を必ず取得します。時間がかかることより、予期しない結果になることのほうが問題です。
- 変更には明示的な承認が必要です。 概要テーブル(Transaction · Invoice/Bill · Payment Account · Fiat alignment · Sync)を表示し、変更操作を実行する前に「これらの変更を適用しますか?」と尋ねます。明確な肯定を得た場合にのみ進めます。
- 不明な点があればスキーマを調べます。 フィールド名、列挙値、引数の形式は変わることがあります。クエリ/変更操作で「unknown field」または「invalid enum」エラーが発生した場合は、
introspect(<TypeName>)またはbuild_query(<operationName>)を呼び出して調整します。推測してはいけません。以下で「実行時に確認」と明記されている操作は、特に確認が必要になる可能性が高いものです。 - このスキルはループします。 照合が成功したら「別のものも照合しますか?」と尋ね、ステップ 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 が null 行を返すことがあるためです。
- 接続済みの ERP がない場合: 照合には ERP の接続が必要であることをユーザーに伝え、
https://app.tres.finance/settings/integrationsを案内して終了します。 - 接続済みの ERP が 1 つの場合: それを暗黙的に使用し、「{companyName}({integratedApp})と照合します。」とだけ伝えます。
- 接続済みの ERP が複数ある場合: どれを使用するか尋ねます。ERP ごとに請求書/買掛請求書の保存先が異なります。
選択した ERP の id、integratedApp、companyName を後のステップおよびループで使えるように保持します。
ステップ 2 — ユーザーが持っている情報を特定する
次のどれを持っているか尋ねます。
- 取引ハッシュ(例:
0x…)— 照合対象をすぐに特定できるため、最も確実です。 - 請求書/買掛請求書の ID または番号(数値の内部 ID、またはユーザーに表示される
invoiceNumber/billNumber)。 - 両方。
どちらも持っていない場合は、少なくとも一方を求めます。識別子が請求書のものか買掛請求書のものか分からない場合は、そのまま受け取り、ステップ 3 で両方を検索します。
「INV-123」「Bill 9988」「先週の Acme の買掛請求書」など、曖昧な形式の入力も受け付けます。erpInvoices/erpBills の freeText フィルターで検索できます。
次に進む前に、tx ハッシュが提示されていない場合は、必ず取引日(またはおおよその日付範囲)を尋ねてください。 台帳の取引量は多いため、日付は候補を絞り込むうえで最も有用なフィルターです。また、「もし tx ハッシュがあれば、ここに貼り付けてください。照合対象を正確に特定できます。」と案内します。日付は、tx から買掛請求書を探す場合も、買掛請求書から tx を探す場合も重要です。
ステップ 3 — 既知のオブジェクトを取得し、照合候補を順位付けして提示する
分岐は 2 つあります。ユーザーが提示した情報に応じて選びます。tx ハッシュと請求書/買掛請求書 ID の両方が提示されている場合は、ステップ 5 に進みます(照合対象はすでに決まっています)。
ブランチ A — ユーザーがトランザクションハッシュを持っている場合
- サブトランザクションとともにトランザクションを取得します:
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 } } } } } - 関連するサブトランザクションを選びます。ガスと内部送金は除外し、一方がユーザーのウォレット、もう一方が外部の取引相手であるものを優先します。方向を判断します:
balanceFactorが負 → 流出 → 決済する請求書を探します。balanceFactorが正 → 流入 → 決済する売上請求書を探します。 条件に合うサブトランザクションが複数ある場合(複数のレッグを伴うスワップなど)は、それらを提示してユーザーに選んでもらいます。
- 売上請求書(流入)の場合は、まずバックエンドの照合候補を試します — あらかじめ計算され、順位付けされています:
重要:このエンドポイントは売上請求書専用です。請求書(流出)の場合は、以下のフォールバックに直接進んでください — スキーマにはバックエンドの請求書候補クエリが公開されていません。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 } } } } } - フォールバック(売上請求書の候補がゼロの場合、または請求書の場合は常に実行):
erpInvoices(流入)またはerpBills(流出)を、次の条件で絞り込んでクエリします:- 金額の範囲:サブトランザクションの法定通貨換算額の
±20%。 - 日付の範囲:
dateCreated_Range = [tx.timestamp − 60d, tx.timestamp]— 請求書/売上請求書は支払い日以前に発行されます。支払い後に発行されたものは対象外です。未来の日付の請求書/売上請求書は調べないでください。 - 取引先:ユーザーが仕入先/顧客名を指定している場合は、それを
freeTextとして渡します。オンチェーンの受取人アドレスと ERP の取引先を照合しようとしないでください — QBO/Xero/NetSuite の ERP 取引先識別子は内部 ID であり、ウォレットアドレスではありません。取引先のラベルがたまたまテキスト上の仕入先名に似ている場合もありますが、スキーマには「似ている」かどうかを絞り込む機能がないため、vendor/customerフィールドではなくfreeTextを利用してください。 フォールバック候補はクライアント側で、金額の近さ → 日付の近さ(トランザクション前の最も新しい請求書/売上請求書を優先) →freeTextの出力における名前の一致、の順に順位付けします。
- 金額の範囲:サブトランザクションの法定通貨換算額の
- 上位≤5件を番号付きリストで提示します(必ず5件以下にします。選択肢が多すぎるのは少なすぎるよりも望ましくありません)。各行に、信頼度区分、金額($)、顧客/仕入先名、
invoiceNumber/billNumber、支払期日、primaryMatchFactors(例:amount_exact、contact_match)を表示します。最適な候補を先頭にします。
ブランチ B — ユーザーが請求書/請求明細の ID または番号を持っている場合
- エンティティを解決します。まず
erpInvoicesを試し、請求書でなければerpBillsを試します(ユーザーが「bill」と言った場合はその逆)。 請求書の場合は、埋め込みの候補を含めます:
請求明細の場合は、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で再試行します。 - 請求書の場合は、埋め込みの
suggestedSubTransactionMatchesをランク付けされたリストとして使用します。 - フォールバック(請求書の候補がゼロの場合、または請求明細の場合は常に):
- まず、ユーザーにおおよその支払日を尋ねます(そして次のように念を押します:「tx ハッシュがあれば、それが最速です」)。支払いは請求明細/請求書の日付以降に行われ、通常は数日以内です — それより前には行われません。具体的な日付が分からない場合は、デフォルトで
[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%)。これはカンマ区切りの 2 つの数値からなる文字列です。例: $0.50 の請求明細に対して"0.4,0.6"。- オプションで
children_BalanceFactor: -1(請求明細の場合は流出)または1(請求書の場合は流入)。 - フィアット価格が信頼できない場合(事前に価格が設定された履歴アセットなど)にのみ、追加フィルターとして
children_Amount_Betweenを使用します。
- 結果のセットが依然として大きい場合は、提示する前に、より狭い日付または金額の絞り込みをユーザーに尋ねます。
- まず、ユーザーにおおよその支払日を尋ねます(そして次のように念を押します:「tx ハッシュがあれば、それが最速です」)。支払いは請求明細/請求書の日付以降に行われ、通常は数日以内です — それより前には行われません。具体的な日付が分からない場合は、デフォルトで
- 最大 5 件の候補トランザクションを番号付きリストとして提示します — それぞれについて次を表示します:
tx ハッシュ(切り詰めた
0xabcd…1234)、送信者 → 受信者のアドレス(同じ短縮形式)、トークン量 + シンボル、フィアット価値、タイムスタンプ。 tx ハッシュはユーザーが認識できるユーザー向けの識別子です。フィアットだけでは曖昧すぎる場合(多くの tx が同じ金額付近に集中します)、生のアドレスとトークン量が曖昧さを解消します。subTxIdのような内部 ID をユーザーに決して表示しないでください — ユーザーにとって無意味です。subTxIdはミューテーション用に内部的に保持し、ユーザーに表示されるすべての出力では tx をそのハッシュで参照します。 良い一致がない場合は、その旨を伝えて tx ハッシュを尋ねます — 当て推量で大きなリストを吐き出さないでください。
ステップ 4 — ユーザーが一致を選択する(またはさらに情報を求める)
プロンプト: 「番号を選ぶか、more と入力して検索を広げてください(絞り込むための連絡先名、日付、または金額を教えてください)。」
- 番号の場合: 選択された
(subTxId, invoiceOrBillId, entityType)を取得し、ステップ 5 に進みます。 moreの場合: より緩い範囲、またはユーザーが追加したヒント(連絡先フィルター、拡張した日付範囲、金額範囲)で再クエリし、新しいリストを提示して繰り返します。- 「これらはどれも違う」または同様の回答の場合: 穏当に停止します — 「了解しました、一致はありませんでした。さらに情報が得られたら教えてください。」
ステップ 5 — 支払いアカウントと(任意の)法定通貨の調整を設定する
マッチするペアを選んだら:
-
入金アカウント(
matchApAr.depositAccountId用)。 これは ERP 統合アカウント です (請求書の計上先となる Xero/QBO/NetSuite の GL アカウントです。例:「Crypto Wallet – ETH」、 「Cash and cash equivalents」)。tres の内部アカウント/ウォレットアカウントではありません。スキーマの外部キーはschema_integrationaccountを参照します。この値はErpBill.depositAccount/ErpInvoice.depositAccountにIntegrationAccountQuery { id name type value }として格納されます。解決の優先順位:
- 請求書/請求にあらかじめ設定されているものを使います。 ERP でエンティティが作成された際、ユーザーは通常、
入金アカウントをすでに選択しています。
erpBills.results[].depositAccount.id(またはerpInvoices.results[].depositAccount.id)を読み取ります。null 以外の場合は、その ID をdepositAccountIdとして使い、概要で伝えるだけで構いません。プロンプトは不要です。 - それ以外の場合はユーザーに尋ねます。
integrationAccount(integration: <erpId>, first: 100)を照会し、 ASSET タイプのアカウント(現金/ウォレット/暗号資産の GL アカウント)を番号付きリストでユーザーに提示します。 選択されたintegrationAccount.idを取得します。 paymentToInternalAccountsは tres 側で ウォレット → 資産 をマッピングするもので、支払いワークフローで役立ちますが、matchApArのdepositAccountIdの参照元ではありません。ここでは使用しないでください。
- 請求書/請求にあらかじめ設定されているものを使います。 ERP でエンティティが作成された際、ユーザーは通常、
入金アカウントをすでに選択しています。
-
法定通貨の調整。 サブトランザクションの
fiatValueと請求書/請求のorigAmountを比較します。次の 3 つのケースがあります。fiatValueが null または 0:"このトランザクションには法定通貨の値が設定されていません。{bill/invoice} が全額決済されるように ${origAmount} に合わせますか?(y/n)" と尋ねます — デフォルト値は設定せず、明示的な yes を求めます。fiatValueがorigAmountと異なる:"買掛金/売掛金が全額決済されるよう、トランザクションの法定通貨の値を $X から $Y に合わせますか?(y/n)" と尋ねます — デフォルト値は設定せず、明示的な yes を求めます。- 値が一致している:スキップします。
明確な yes がない限り、
setManualFiatValueを実行してはいけません — ユーザーの最初の依頼が「請求書を決済する」ことを示唆していた場合でも、法定通貨の調整は別個の書き込み操作であり、独立した同意が必要です。no と回答された場合でもマッチングは続行されますが、エンティティの支払いが一部のままになる可能性があります。
Step 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 に同期」と伝えていた場合でも、実際のマッチの詳細を確認する前に出された依頼であるため、ここで必ず確認してください。
次の順序で変更を実行し、それぞれの結果を報告します。
-
マッチ(必ず実行):
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 を参照)。
-
法定通貨額の調整(ユーザーが希望した場合のみ):
mutation AlignFiat($id: String!, $newFiatValue: String!, $currency: String) { setManualFiatValue(id: $id, newFiatValue: $newFiatValue, currency: $currency) { success } }サブトランザクション ID を
idとして、目標額を文字列でnewFiatValueに渡します(例:"123.45"。請求書/請求のorigAmountを指定)。また、currency: "usd"を指定します。応答で「locked period」に関するエラーが返された場合、tx を含む会計期間は締め済みです。その旨をユーザーに伝え、強制的に処理しようとしないでください。 -
ERP 同期(毎回、先に確認): 「このトランザクションを今すぐ {erpName} に同期しますか?(はい/いいえ)」。ユーザーの当初の依頼に「QBO に同期」も含まれていた場合でも、この時点で明示的な承認がない限り、決して同期しないでください。同期呼び出しは ERP 上で確認でき、マッチ自体よりも取り消しが難しいため、別途確認が必要です。はいの場合:
mutation Sync($txIds: [String]!, $entityType: String!) { syncSpecificTransactions(transactionIds: $txIds, entitySourceType: $entityType) { status } }entitySourceTypeはマッチ呼び出しのentityTypeと同じ値にします。
結果をユーザーに報告する際は、トランザクションを tx ハッシュ(省略形)で、入金口座を名前で示してください。subTxId や depositAccountId は決して使わないでください。これらの内部 ID はデバッグ用であり、ユーザー向けの出力には使いません。
いずれかの変更でエラーが発生した場合は、エラーメッセージをそのまま提示し、再試行するか尋ねてください。レコードを実際に関連付けるのはマッチです。マッチが失敗した場合、それ以降の処理は意味をなしません。
Step 7 — 繰り返し
次のように尋ねます:「別のトランザクションまたは請求書/請求をマッチしますか?(はい/いいえ)」
- はい → ステップ 2 から再開します(ステップ 1 はスキップし、このセッションでキャッシュした ERP を引き続き使用します)。
- いいえ → 終了します:「完了しました。このセッションでは {n} 件をクローズしました。」
使用することが確認済みの TRES MCP 操作
| 目的 | 操作 | 種類 |
|---|---|---|
| 組織の識別 | get_viewer | MCP ツール |
| スキーマの検出 | introspect, build_query | MCP ツール |
| ERP 接続の確認 | integration(フィルター isErp=true) | クエリ |
| ハッシュによるトランザクションの取得 | transaction(identifier:) | クエリ |
| 請求書の取得(埋め込みの候補を含む) | erpInvoices | クエリ |
| 仕入請求書の取得(埋め込みの候補を含む) | erpBills | クエリ |
| 事前計算済みのサブトランザクション → 請求書のマッチング候補 | subTransactionToInvoiceMatchSuggestions | クエリ |
| COA にマッピングされた支払いアカウント | paymentToInternalAccounts | クエリ |
| サブトランザクション ↔ 請求書/仕入請求書のマッチング | matchApAr | ミューテーション |
| 法定通貨の金額の調整 | setManualFiatValue(実行時に引数を確認) | ミューテーション |
| トランザクションの ERP への同期 | syncSpecificTransactions | ミューテーション |
| マッチングの取り消し(ユーザーから依頼があった場合) | manualUnmatchSubtransactions | ミューテーション |
対象外(依頼された場合は丁寧に案内してください)
- 一括マッチング(多対多)— このスキルではまだサポートされていません。
- 支払いの送信(
sendBillPayment、sendInvoicePayment)— 別のワークフローです。 - ERP 自体の接続または取り消し —
tres-settings-managementスキルを使用してください。 - トランザクションの説明文の作成 —
tres-tx-storyを使用してください。 - エクスプローラーのリンクの台帳へのインポート —
tres-explorer-tx-to-ledgerを使用してください。