コンテンツにスキップ

ValueOS 業務フロー

位置づけ: クライアントERP(ValueOS)

ValueOSは案件(cases)に対して1つの決済区分(case_settlements.settlement_type)を紐付け、決済区分ごとに宣言された条件(SETTLEMENT_RULES)をWorkflowEngineが解釈して発注可否(canOrder)・請求可否(canInvoice)・現在の状態(currentState)・次アクション(nextAction)・担当(assignee)を機械的に導出する。判定ロジックはすべてlib/workflow配下の純関数に集約し、画面はこの判定結果を表示するレイヤーに徹する。if/elseの分岐をUIや各フォームに直接書かず、決済区分を追加・変更する場合はSETTLEMENT_RULESという設定オブジェクトを増やすことで対応する設計である。

決済区分が「3社間決済」の案件は、発注・請求とは別に、信販会社からの入金(finance_receipts)・販売店への仕切精算(dealer_settlements)・仕入先への支払(supplier_payments)という3つの金銭実体を持つ。これらはexecute_three_party_moneyという冪等なRPC経路を通じてのみ書き込まれ、three_party_money_requestsテーブルが実行結果を記録する。販売店発注フォーム(app/dealer/orders/new)による案件起票は、この金銭フローとは別の独立した登録経路であり、本ページで両者を区別して扱う。

項目内容
対象WorkflowEngine(canOrder/canInvoice/現在状態の判定)、決済区分別の工程進行、三社間金銭フロー(信販入金・仕切精算・仕入先支払)、販売店発注フォームの登録経路
対象外ダッシュボード集計基準(valueos/overviewを参照)、テーブル定義の網羅(valueos/data-modelを参照)
情報源ValueOS正本(github.com/stanaka-blip/valueos)のlib/workflowlib/threePartyapp/dealer/orders/newsupabase/migrations
関連ページfeatures/wholesale-settlementredesign/valueos-gapglossary
エンティティ主なフィールド役割
casescase_no, dealer_id, status, construction_completed_date案件本体。construction_completed_dateが3社間決済の請求可否判定に使われる
case_settlementscase_id(1:1), settlement_type, fee_rate/fee_amount, deposit_rate/deposit_amount, payment_terms, card_brand/card_status/card_status_updated_at, finance_company/approval_number, loan_status/loan_status_updated_at決済区分と、区分ごとの詳細項目を1レコードに集約
orders + order_itemssupplier_id, status, delivered_date, order_amount発注実体。全発注の納品状況が売掛の請求可否を決める
invoices / paymentsstatus, invoice_amount / payment_amount請求・入金実体。前金の入金確認判定にpaymentsの確認済み合計を使う
three_party_money_requestsrequest_id(PK), action, case_id, resource_id, status, payload_hash, response3社間金銭アクションの冪等リクエスト表。同一request_idの再送を安全に処理する
finance_receiptscase_id, finance_company, scheduled_date/scheduled_amount, actual_date/actual_amount, status, corrects_id信販会社からの入金予定・実績
dealer_settlements + dealer_settlement_linesdealer_id, finance_receipt_id, invoice_id, credit_received_amount, ve_share_amount, adjustment_total_amount, payout_amount, scheduled_payout_date/actual_payout_date/actual_payout_amount, status販売店への仕切清算書兼支払。明細(line_kind)で調整額を積み上げる
supplier_paymentscase_id, supplier_id, order_id, due_date/scheduled_amount, paid_date/paid_amount, status仕入先への支払予定・実績。発注(orders)に対して1:N
case_registration_requestsrequest_id(PK), case_id, status, payload_hash, responsecreate_case_registrationRPC(service_role専用)の冪等リクエスト表。現行の販売店発注フォームからは未接続(後述)

case_settlements.settlement_typeの正式値は4つ。旧値は読み取り互換のエイリアスとしてresolveSettlementRuleが吸収する。

正式値エイリアス(読取互換の旧値)
前金前金
売掛売掛、掛売
3社間決済3社間決済、ローン、三社間決済、3社間、三社間
カードカード

「その他」はレガシー値として保持されるが正式区分には含まれない。settlementTypeがいずれの正式値・エイリアスにも一致しない場合、WorkflowEngineruleKey: nullcurrentState: "決済条件未設定"canOrder: falsecanInvoice: falseを返し、警告に「未対応の決済区分です」または「決済区分が未設定です」を積む。

当方のWholesaleCaseは決済区分を前金/掛売/三社間/カード/その他の5値で管理しており、ValueOSの正式値(前金/売掛/3社間決済/カード)とは表記が異なる。対応は本ページ末尾の対応表を参照。

evaluateWorkflow(ctx: WorkflowContext)は決済区分ごとの設定(SETTLEMENT_RULES)から次を導出し、WorkflowResultとして返す。

フィールド内容
canOrder発注可否。canOrderWhen条件配列がすべて真のとき真
canInvoice請求可否。canInvoiceWhen条件配列がすべて真のとき真
currentState / assignee / nextAction現在の工程表示。phases配列を先頭から走査し、completeWhenが未達成の最初のフェーズを返す(canOrder/canInvoiceとは別ロジック)
warnings発注・請求がブロックされている理由の文言(複数可、重複排除)
billingClosingDate / paymentDueDate売掛のみ算出する請求締め日・支払期日

canOrder/canInvoicecurrentStateは同じ条件セットを参照するが、評価の入口が異なる独立したロジックである。settlement_confirmed条件は決済区分が正式値に解決できた時点で常に真になる(別途「確定」操作を要しない)。

決済区分別の発注可否・請求可否条件

Section titled “決済区分別の発注可否・請求可否条件”
決済区分canOrder条件canInvoice条件
前金入金確認(payment_confirmed_from_billing決済区分の解決(実質常時true)
売掛決済区分の解決(実質常時true)案件内の全発注が納品済(all_orders_delivered
3社間決済loan_statusが「承認済」construction_completed_date(完工日)が設定済
カードcard_statusが「決済成功」card_statusが「決済成功」(発注と同一条件)

前金は請求可否が実質常時trueになる点、カードは発注と請求が同一条件で同時に解放される点が、区分間で構造が異なる箇所である。

入金確認(payment_confirmed_from_billing)は、案件に紐づく入金(payments)のうち確認済みステータスの金額を合算し、deposit_amount(頭金予定額)が設定されていれば合計がそれ以上か、未設定なら合計が0円超かで判定する。全発注納品済(all_orders_delivered)は、キャンセル等を除いたアクティブな発注(lib/status/activeRecords.tsと同一の判定)が1件以上あり、かつ全件のstatusが「納品済」かつdelivered_dateが入力済みであることを要求する。発注が0件の案件は未達とみなす。

決済区分STEP1STEP2STEP3STEP4
前金決済条件未設定(経理)入金確認待ち(経理)発注可能(発注担当)
売掛決済条件未設定(経理)発注可能(発注担当、全納品まで)請求可能(経理)
3社間決済決済条件未設定(経理)ローン承認待ち(経理)完工報告待ち(営業事務)請求可能(経理)
カード決済条件未設定(経理)カード決済待ち(経理)発注・請求可能(発注担当)

「決済条件未設定」フェーズはsettlement_confirmedが常時真であるため実質的に即時通過し、UI上で長く滞在することはない。

発注・請求ブロック時の警告文言

Section titled “発注・請求ブロック時の警告文言”
状況警告文言
前金・入金未確認で発注不可前金の入金確認前のため発注できません(請求・入金データで判定)
3社間決済・ローン未承認で発注不可ローン未承認のため発注できません
カード・決済未成立で発注不可カード決済前のため発注できません
カード・決済未成立で請求不可カード決済前のため請求できません
3社間決済・完工日未登録で請求不可完工日登録前のため請求できません
売掛・納品済だがdelivered_date欠損納品日が登録されていません
売掛・未納品の発注が残っている売掛の請求は、案件内の全発注が納品済になってから可能です

売掛の請求不可は上記の個別メッセージのみを出し、汎用メッセージ(「現在の決済区分ルールでは請求できません」)は出さない実装になっている。

売掛(datePolicy.trigger: all_orders_delivered)は、案件内の全発注が納品済となった時点の最終納品日(アクティブな発注のdelivered_dateの最大値)を起点に、月末締め・翌月末払いでbillingClosingDatepaymentDueDateを自動算出する。他の決済区分にはこの日付ポリシーはない。

販売店発注(app/dealer/orders/new)の登録経路

Section titled “販売店発注(app/dealer/orders/new)の登録経路”

販売店発注フォームは4ステップ(案件情報→商品選択→決済区分選択→確認)で入力を受け付け、送信時にsaveDealerOrder.tsが次の順でSupabaseへ直接INSERTする。

  1. casesへ案件本体を作成する。ステータスは常に「新規受付」固定、case_noVE-{timestamp}形式で発番する
  2. パッケージ発注ならcase_packagescase_package_items(パッケージ構成のスナップショット・仕入価格)、部材のみ発注ならcase_productsを作成する
  3. case_settlementsに選択された決済区分(settlement_type)を保存する
  4. いずれかのステップが失敗した場合はcleanupCaseが作成済みの行を逆順で削除し、中間状態の案件を残さない

この経路はブラウザから直接複数テーブルへ書き込む非トランザクションな実装であり、失敗時のクリーンアップで整合性を保っている。

STEP3(決済区分選択)の入力値とWorkflowEngine正式値の対応

Section titled “STEP3(決済区分選択)の入力値とWorkflowEngine正式値の対応”

STEP3で選択できる決済区分はDEALER_ORDER_SETTLEMENT_TYPES掛売/ローン/現金/カード/その他の5値)であり、WorkflowEngineの正式値(前金/売掛/3社間決済/カード)とは選択肢の構成そのものが異なる。入力値はそのままcase_settlements.settlement_typeにINSERTされ、以降resolveSettlementRuleが正式値へ解決する。

STEP3の選択肢resolveSettlementRuleでの解決
掛売売掛(エイリアス一致)
ローン3社間決済(エイリアス一致)
カードカード(正式値)
現金未対応(ruleKey: nullcanOrder/canInvoiceとも常時false)
その他未対応(ruleKey: nullcanOrder/canInvoiceとも常時false)

「前金」はSTEP3の選択肢に存在せず、この販売店発注フォームからは前金の案件を作成できない。「現金」「その他」を選択して作成した案件はresolveSettlementRuleがいずれの正式値・エイリアスにも一致せずruleKey: nullを返すため、発注・請求ともにブロックされた状態(警告「未対応の決済区分です: 現金」等)で登録される。案件詳細側で決済区分を正式値へ手動修正しない限りこの状態は解消しない。

これとは別に、DB側には冪等な案件登録用のcreate_case_registrationRPC(SECURITY INVOKERservice_role専用実行権限・request_idpayload_hashによる冪等性)と、その結果を記録するcase_registration_requestsテーブルが用意されている。この経路はservice_role経由のトランザクション登録用として設計されており、現行のapp/dealer/orders/new画面からは呼び出されていない。案件起票の正本は現時点で「フォーム→直接INSERT」であり、RPC経路は未接続のバックエンド機能として存在する。

三社間の金銭フロー(信販入金・仕切精算・仕入先支払)

Section titled “三社間の金銭フロー(信販入金・仕切精算・仕入先支払)”

3社間決済の案件は、発注・請求可否のワークフローとは独立に、次の3系統の金銭実体を持つ。いずれもexecute_three_party_moneyRPCへのアクションとして実行され、moneyActionsLogic.tsが入力検証・正規化を行う。

アクション対象テーブル主な操作
finance_receipt.*finance_receiptscreate(入金予定登録)→confirm(実入金確認:実績日・実績額)。cancel/correctで取消・訂正
dealer_settlement.*dealer_settlements + dealer_settlement_linescreate(仕切清算書作成)→confirm(確定)→pay(実績支払日・実績支払額)。cancel/correctで取消・訂正
supplier_payment.*supplier_paymentscreate(支払予定登録)→pay(実績支払日・実績支払額)。cancel/correctで取消・訂正

想定される進行順序は「ローン承認(loan_status=承認済)→発注→工事完了(construction_completed_date)→請求→信販会社からの入金(finance_receipt)→販売店への仕切精算(dealer_settlement)/仕入先への支払(supplier_payment)」である。信販入金・仕切精算・仕入先支払の3系統は互いに独立したアクション列であり、dealer_settlements.finance_receipt_idinvoice_idで該当する信販入金・請求と任意に紐付けられる。

dealer_settlement.create時、払戻額(payout_amount)は次の式で自動計算される。

payout_amount = credit_received_amount − ve_share_amount − Σ(調整明細のamount)

調整明細(dealer_settlement_lines.line_kind)はtransfer_fee(振込手数料)・discount(値引)・offset(相殺)・other(その他控除)の4種で、控除額を正数で保持する。credit_in(信販入金額行)・ve_share(当社取り分行)は明細に計上できるが調整合計には含めない。計算結果payout_amountが負になる登録・訂正はAPI側で拒否される。

DB上のステータスは最小集合とし、期限超過などの表示状態は登録時の日付から都度導出する。

エンティティDB値表示値
finance_receipts予定 / 入金済 / 取消未入金 / 入金予定 / 入金済 / 期限超過 / 取消
dealer_settlements下書き / 確定 / 支払済 / 取消下書き / 支払予定 / 支払済 / 期限超過 / 取消
supplier_payments予定 / 支払済 / 取消支払予定 / 支払済 / 期限超過 / 取消

期限超過は「予定日が当日より前」で判定し、当日中は超過扱いにしない。取消済み行は集計から除外する。

すべての3社間金銭アクションはrequest_id(クライアント発行のUUID)を伴い、three_party_money_requestspayload_hash(キー順正規化したJSONのハッシュ)とともに記録される。同一request_idの再送は冪等に処理される。確定済み金額の直接UPDATEは扱わず、訂正はcorrectアクション(新しい内容で作り直し、corrects_idで元レコードを参照)、取消はcancelアクション(cancel_reasonを記録)という形で、常に監査可能な履歴として残す設計である。

観点当方(WholesaleCase)ValueOS
決済区分の値前金 / 掛売 / 三社間 / カード / その他(5値)前金 / 売掛 / 3社間決済 / カード(正式4値、旧値はエイリアス吸収)
発注可否・請求可否の判定wholesaleFlow(工程配列上の位置関係から導出)WorkflowEngine.evaluateWorkflow(決済区分別の条件配列canOrderWhen/canInvoiceWhen
承認番号・審査情報WholesaleCase.approvalNo(単一・三社間とカードで共用)case_settlements.finance_company/approval_number(3社間決済)、card_brand/card_status(カード)に分離
入金消込案件のpayments[]を残高計算方式で合算前金はpayments確認済み合計とdeposit_amount比較、売掛は納品完了トリガーで締め日算出、3社間決済はfinance_receiptsが信販入金を個別管理
三社間の下流精算未実装(案件メモでの運用)dealer_settlements(販売店への仕切精算)・supplier_payments(仕入先への支払)として構造化
販売店発注の起票DealerIntakeForm送信→WholesaleCaseをクライアント側で生成app/dealer/orders/newsaveDealerOrder.tsが直接INSERT。冪等RPC(create_case_registration)はDB側に存在するが未接続

差分の全体像はredesign/valueos-gapを参照。

  • redesign/valueos-gapの「ValueOSには決済区分でフローを制御するロジックが無い」という記述は、本ページで確認したWorkflowEngineの実装内容(決済区分別のcanOrder/canInvoice宣言的判定)と齟齬がある。記述の更新要否を確認する
  • create_case_registrationRPC(冪等な案件登録経路)をapp/dealer/orders/newから呼び出す設計へ移行する要否。現行はsaveDealerOrder.tsによる直接INSERTで運用されている
  • 3社間金銭アクション(finance_receipt/dealer_settlement/supplier_payment)の呼び出し導線(社内のどの画面・どの担当者が実行するか)の確認
  • 販売店発注STEP3で「現金」「その他」を選択した案件が発注・請求ともに永続ブロックされる状態を仕様として許容するか、STEP3の選択肢自体をWorkflowEngine正式値(前金/売掛/3社間決済/カード)に合わせて見直すかの確認