ValueOS 差分・項目突合
7/29 定例会で「ValueAuth(案件・受注・請求・入金・タスクの5本柱)のイメージに寄せたい」との要望が出た。「ValueAuth」という別リポは存在せず、同じ5本柱を持つ ValueOS(正本 = github.com/stanaka-blip/valueos)がその実体(茗荷さん確認済み・2026-08-05)。以降 ValueOS を唯一の基準とする。
スタックの前提
Section titled “スタックの前提”| ValueOS | 現行 CRM モック | |
|---|---|---|
| 構成 | Next.js App Router + Supabase(実DB) | TanStack Start + Zustand(モック・ローカル永続化) |
| 主眼 | 単一 cases 軸で 受発注→請求→入金 | 販売店目線 deals + 商社別軸 wholesale(7/29 新設) |
| 明細 | case_products(案件配下・発注/請求共通) | 案件の items(卸案件)/見積の明細 |
| 決済区分 | case_settlements.settlement_type(正式4値=前金/売掛/3社間決済/カード・2026-08-01正規化。レガシー「その他」は保持のみで正式区分外)+card_brand/approval_number/card_status | WholesaleCase.settlement(前金/掛売/三社間/カード/その他)+承認番号 |
| ワークフロー | lib/workflow/WorkflowEngine.ts が SETTLEMENT_RULES(決済区分別)から canOrder/canInvoice・現在フェーズを判定 | wholesaleFlow=決済区分別に canOrder/canInvoice・次アクションを機械判定(同等) |
差分表(機能領域別・実装状況を更新)
Section titled “差分表(機能領域別・実装状況を更新)”| 領域 | ValueOS | 現行 CRM | 状況 |
|---|---|---|---|
| 決済区分 | case_settlements.settlement_type(正式4値=前金/売掛/3社間決済/カード。レガシー「その他」は保持のみ)+card_brand/approval_number/card_status | settlement(5値・カード/承認番号含む) | 実装済(同等) |
| 発注/請求ワークフロー | WorkflowEngine.ts(canOrder/canInvoice/現在フェーズを決済区分別ルールで判定) | wholesaleFlow(canOrder/canInvoice/次アクション/担当) | 実装済(同等・当方は FLOW+バケツ表示を拡張) |
| 販売店発注フォーム | app/cases/new 等(内部入力) | /dealer-order(販売店入力→受付番号→案件化) | 実装済 |
| 卸価格 | dealer_sales_prices(dealer×product×期間) | /master-wholesale-price(仕入先×商品/パッケージ×反映日)+WholesalePrice.dealer?(販売店軸・本セッション追加) | 実装済(仕入先軸に加え販売店(dealer)軸を追加。currentWholesalePriceForDealer()が販売店指定価格を優先→無ければ標準価格にフォールバック。下記突合参照) |
| 商社別軸案件 | 単一 cases | /wholesale(別軸・4ビュー切替) | 実装済 |
| タスク | tasks(case_id/status/due/assignee/priority) | WholesaleTask(同項目・案件紐付) | 実装済(本セッション) |
| 経営ダッシュボード | 売上/粗利/未入金+業務アラート | /wholesale サマリー(5本柱+バケツ/決済区分別) | 実装済(受発注KPIあり) |
| パッケージ商品マスタ | packages(package_code/manufacturer_id/series_id/system_type/warranty_years) | Package{code/name/maker?/series?/capacity?/systemType?/warrantyYears?/spec?/note?}+/master-packages | 実装済(本セッション) |
| 受注時価格スナップショット | case_products(purchase_price/sales_price/gross_profit/is_manual_price/price_fetched_at) | WItem.purchasePriceSnapshot?/wholesalePriceSnapshot?/isManualPrice?/priceFetchedAt?+snapshotWItem()。明細作成時にcurrentWholesalePriceForDealer()で卸価格を自動引き当て(⑩) | 実装済(本セッション) |
| 仕入先支払予定 | suppliers の closing_day/payment_site から支払予定を算出 | lib/supplierPayment.ts の supplierPaymentDueDate(supplierName, orderDate) | 実装済(本セッション) |
| 買掛(支払予定)の横断一覧 | supplier_payments(VE→仕入先支払)を案件横断で参照 | /wholesale-payables(WholesalePayables)が全案件のsupplierPaymentsを横断集計。dueDate未設定行は⑨で自動補完 | 実装済(本セッション⑪) |
| 発注(order)エンティティ | orders(order_no/date/amount/status) 独立 | WOrder{orderNo/orderDate/amount/status/deliveredDate?}+registerOrder()・発注書出力 | 実装済:残るは納期回答日・中間ステータス |
| 請求(invoice)エンティティ | invoices(invoice_no/date/due/amount/status) 独立 | WInvoice{invoiceNo/invoiceDate/dueDate/amount/status}+registerInvoice()・請求書出力 | 実装済:残るは作成済/入金待ちの中間ステータス |
| 入金(payment)エンティティ | payments(date/amount/status・一部入金) 独立 | WPayment{paymentDate/amount}(配列・分割入金対応)+請求単位の残高表示 | 実装済:残るは入金ごとの確認待ち/取消ステータス |
| マスタ経理項目 | supplier: 締め日/支払サイト/発注方法、products/packages: 既定仕入先(default_supplier_id)、dealer: 与信枠 | Supplier.closingDay?/paymentSite?/creditLimit?(本セッション追加)+supplierPaymentDueDate()(締日/支払サイトから支払予定を自動算出・本セッション追加)、EventCompany.paymentType?/defaultProfitAmount?(本セッション追加) | 一部実装済:残るは発注方法・既定仕入先(default_supplier_id)・dealer与信枠 |
項目突合(フィールド対応・ValueOS → 現行 CRM)
Section titled “項目突合(フィールド対応・ValueOS → 現行 CRM)”出典は ValueOS のアプリコード(insert/型定義。DBスキーマ生成物は同リポに無いため enum は「アプリが送出/表示する値」)。
① 案件 cases ↔ WholesaleCase(商社別軸)/ deals
Section titled “① 案件 cases ↔ WholesaleCase(商社別軸)/ deals”ValueOS cases | 現行 CRM | 突合 |
|---|---|---|
case_no(VE-…自動採番) | id(W-0001…) | 一致 |
| dealer_id → dealers | dealer(販売店名文字列) | 概ね一致(当方は名称直持ち) |
| order_type(材料のみ/材工/工事のみ/見積相談) | なし | 要検討:発注種別 |
| status(20値の一気通貫) | settlement+工程フラグ→wholesaleFlow.bucket | 表現差(当方は決済別ワークフローで導出) |
| assigned_user | wholesaleFlow.assignee(工程から導出) | 当方は工程担当を自動割当 |
| priority | なし(案件優先度) | 要検討 |
| customer_name/phone/site_address/construction_* | なし(卸案件は施主情報を持たない) | 別軸ゆえ意図的に非保持 |
| department | なし | 要検討(マネフォ部門連携で使う可能性) |
② 発注 orders ↔ WOrder(個別エンティティ・実装済み)
Section titled “② 発注 orders ↔ WOrder(個別エンティティ・実装済み)”ValueOS orders | 現行 CRM | 突合 |
|---|---|---|
| order_no / order_date / delivered_date | WOrder.orderNo(PO-xxxx)/ orderDate / deliveredDate? | 一致:registerOrder()で発番・発注書出力(/wholesale-order-print)まで対応 |
| expected_delivery_date(納期回答日) | なし | 差:納期回答日は個別保持なし |
| order_amount | WOrder.amount | 一致 |
| status(未発注/発注済/納期回答待ち/納期確定/一部納品/納品済) | WOrder.status(発注済/納品済の2値) | 差:納期回答・一部納品の中間状態なし |
③ 請求 invoices ↔ WInvoice(個別エンティティ・実装済み)
Section titled “③ 請求 invoices ↔ WInvoice(個別エンティティ・実装済み)”ValueOS invoices | 現行 CRM | 突合 |
|---|---|---|
| invoice_no / invoice_date / due_date | WInvoice.invoiceNo(INV-xxxx)/ invoiceDate / dueDate | 一致:registerInvoice()で発番・請求書出力(/wholesale-invoice-print)まで対応 |
| invoice_amount | WInvoice.amount | 一致 |
| status(未請求/作成済/請求済/入金待ち/一部入金/入金済) | WInvoice.status(請求済/一部入金/入金済の3値。入金額との突合で自動遷移) | 差:作成済・入金待ちの中間状態なし |
④ 入金 payments ↔ WPayment(個別エンティティ・実装済み)
Section titled “④ 入金 payments ↔ WPayment(個別エンティティ・実装済み)”ValueOS payments | 現行 CRM | 突合 |
|---|---|---|
| payment_date / payment_amount | WPayment.paymentDate / amount(配列で複数保持) | 一致:分割入金・案件ごとの残高(請求合計−入金合計)表示に対応 |
| status(確認待ち/入金確認済/取消) | なし(登録=確認済み扱い) | 差:入金ごとの確認待ち/取消ステータスなし |
⑤ タスク tasks ↔ WholesaleTask(本セッション実装)
Section titled “⑤ タスク tasks ↔ WholesaleTask(本セッション実装)”ValueOS tasks | 現行 CRM WholesaleTask | 突合 |
|---|---|---|
| case_id(null可) | caseId(W-XXXX/null) | 一致 |
| title | title | 一致 |
| status(未対応/対応中/完了) | status(同) | 一致 |
| due_date | dueDate | 一致 |
| assigned_user | assignee | 一致 |
| priority(高/中/低) | priority(同) | 一致 |
| memo | memo | 一致 |
→ タスクは ValueOS とフィールド完全一致。将来 Supabase 移行時もそのまま対応可能。
⑥ マスタ(当方に無い経理項目=要検討)
Section titled “⑥ マスタ(当方に無い経理項目=要検討)”| ValueOS | 現行 CRM | 突合 |
|---|---|---|
| suppliers: supplier_type/order_method/closing_day/payment_site/credit_limit | Supplier{name/type/closingDay?/paymentSite?/creditLimit?}(締め日・支払サイト・与信枠を本セッション追加)+supplierPaymentDueDate()で締日/支払サイトから支払予定日を自動算出(本セッション追加) | 実装済(残る差:発注方法(order_method)のみ) |
| dealers: payment_type/credit_limit/default_profit_amount | EventCompany{name/paymentType?/defaultProfitAmount?}(本セッション追加。ValueOS dealers 相当) | 一部実装済:支払区分・既定利益額は対応済み。残る差は与信枠(credit_limit) |
| products/packages: default_supplier_id(案件登録時の仕入先自動解決用。dealers の列ではない) | 明細ごとに仕入先を指定(既定値なし) | 要検討:既定仕入先の自動解決(Packageマスタ自体は本セッションで新設済み。残るのは既定仕入先の列) |
| dealer_sales_prices: dealer×product×期間 | WholesalePrice{仕入先×商品/パッケージ×期間}+dealer?(販売店軸・本セッション追加)。currentWholesalePriceForDealer()で販売店指定価格→標準価格の順に解決 | 実装済:仕入先軸に加え販売店(dealer)軸を追加。ValueOS は仕入(purchase_prices)と販売(sales_prices)を別テーブルに分離、当方は単一WholesalePriceに両軸を同居させる構造差は残る |
| supplier_purchase_prices: product×supplier×期間(is_active/日付で有効1件) | 価格表(部材の仕切)/仕切原価 | 概念一致。発注原価との接続は今後 |
⑦ アイテム系(商品・価格・施工店)マスタ突合
Section titled “⑦ アイテム系(商品・価格・施工店)マスタ突合”商品・アイテムマスタ の Product/周辺マスタと、ValueOS のアイテム系テーブルの突合。ValueOS 側は products を頂点に manufacturers(メーカー)→ product_series(シリーズ)→ products(商品)という、現行 CRM と同型の階層を持つ。
| ValueOS | 現行 CRM | 突合 |
|---|---|---|
products(id uuid 主キー。model_no は NULL 可の属性列) | Product(model 型番=主キー) | 軸差:ValueOS は uuid 主キー+型番は属性、当方は型番自体が主キー |
category/product_type | kind(PV/BT/EQ/IH/AC/付帯) | 概ね一致(区分の持ち方は別) |
manufacturer_id → manufacturers(FK・NULL可) | maker(メーカー名を文字列で直持ち・必須) | 概ね一致(当方は正規化なし・必須) |
series_id → product_series | series(シリーズ名) | 一致 |
name | name | 一致 |
specification + capacity + unit | spec | 概ね一致(当方は自由記述1項目に集約) |
memo | note | 一致 |
default_supplier_id → suppliers(既定仕入先) | なし | 差:既定仕入先の自動解決なし(次アクション②と同一課題) |
| なし | leadTimeDays(納期目安)・stock(潤沢/少/欠品) | 当方のみ保持。ValueOS に対応列なし |
product_series{id, name, description, manufacturer_id, is_active} | Series{name, maker} | 概ね一致。description/is_active は当方に無し |
manufacturers{id, name, …} | Manufacturer{name} | ほぼ1:1。メーカー→シリーズ→商品の階層は同型 |
suppliers{name, supplier_type, contact_name, phone, email, order_method, closing_day, payment_site, credit_limit, memo} | Supplier{name, type(商社/メーカー直送), closingDay?, paymentSite?, creditLimit?}(本セッション追加) | name↔name、supplier_type↔type、closing_day↔closingDay、payment_site↔paymentSite、credit_limit↔creditLimit は一致。contact_name/phone/email/order_method は当方に無し |
contractors{name, postal_code, address, phone, delivery_*, receiver_name, is_active} | Vendor(施工店){type(自社/他社), tool(CRMチャット/ANDPAD/LINE), area} | 概念は一致(施工店)だが属性が非対称:ValueOS は納品先住所・受取人など物流属性中心、当方は連絡手段・対応エリアなど運用属性中心。相互に無い列がある |
purchase_prices{price_target_type, product_id/package_id, supplier_id, purchase_price, start_date, end_date, is_active} | WholesalePrice の仕入側{itemKind, itemName, productModel, supplier, purchasePrice, startDate, endDate} | 概ね一致。適用ルール(is_active+期間内・start_date 降順先頭1件)も同じ発想 |
sales_prices{dealer_id, product_id/package_id, sales_price, start_date, end_date} | WholesalePrice の卸売側{wholesalePrice, dealer?}(dealer?は本セッション追加。ValueOS dealer_id 軸に相当) | 構造差は縮小:ValueOS は仕入(purchase_prices=仕入先軸)と販売(sales_prices=販売店 dealer_id 軸)を別テーブルに分離するのに対し、当方はWholesalePrice1レコードに仕入先軸と販売店軸を同居させる構造。販売店(dealers)マスタ自体はEventCompany(代理店=販売店マスタ)として保持済み |
packages{package_code, manufacturer_id, series_id, system_type, warranty_years, pricing_method, default_supplier_id} | Package{code, name, maker?, series?, capacity?, systemType?, warrantyYears?, spec?, note?}(本セッション新設。useMasters の packages スライス+PackagesMasterPage+/master-packages) | 実装済み:package_code↔code、manufacturer_id↔maker、series_id↔series、system_type↔systemType、warranty_years↔warrantyYears は一致。pricing_method・default_supplier_idは当方に無し |
dealers{name, payment_type, credit_limit, default_profit_amount, supplier_id} | EventCompany{name, paymentType?, defaultProfitAmount?}(本セッション追加。ValueOS dealers 相当) | name↔name、payment_type↔paymentType、default_profit_amount↔defaultProfitAmount は一致。credit_limit・supplier_id(既定仕入先)は当方に無し |
→ 商品階層(メーカー→シリーズ→商品)と仕入価格の適用ルールは ValueOS・当方でほぼ同型。販売店(dealer)マスタと dealer 軸の卸価格は本セッションで実装済み(EventCompany=dealers 相当、WholesalePrice.dealer?=sales_prices の dealer_id 軸相当)。パッケージ商品マスタ(packages)も本セッションで実装済み(Package=packages 相当・複数商品のセット販売マスタとして新設)。ValueOS の packages にある pricing_method は、当方が別に持つ「パッケージ(部材×必須/選択/オプション区分)」(下表「現行 CRM のみが持つ機能」参照・価格表 PackageSet の部材構成)と重なる概念だが、本節の Package(商品マスタとしてのパッケージ)とは別軸である点に注意。残るギャップは 既定仕入先(default_supplier_id)・発注方法・dealers の与信枠(次アクション②と同一)。
⑧ 明細 case_products ↔ WItem(価格スナップショット・自動引き当て⑩含む・実装済み)
Section titled “⑧ 明細 case_products ↔ WItem(価格スナップショット・自動引き当て⑩含む・実装済み)”ValueOS の case_products は案件配下の明細(発注/請求共通)で、受注時点の仕入・販売価格をレコードに固定して保持する。当方の WItem(app/src/lib/wholesale.ts)にも同等のスナップショット項目を追加済みで、snapshotWItem() で受注時に価格表から値を写し取る。
⑩ 明細への卸金額スナップショット自動引き当て(実装済み):明細作成画面(NewWholesaleSheet=WholesalePages.tsx 内/DealerIntakeForm.tsx=販売店発注フォーム)で品名を選択すると、app/src/lib/wholesalePricing.ts の currentWholesalePriceForDealer(prices, { itemName, kind, dealer }) が現在有効な卸価格を自動引き当てる。販売店指定価格があれば優先し、無ければ標準価格(dealer未設定)にフォールバックする(⑥のdealer?軸をそのまま利用)。引き当てた値、または手入力で上書きした値のいずれも snapshotWItem() で明細に固定し、単価がマスタ卸価と一致する明細には「マスタ卸価」バッジ(一致・販売店別価格の場合はその旨を併記)、手入力で上書きした明細には「手入力」バッジを表示して、単価の出所を明細単位で可視化する。ValueOS case_products は価格を明細に固定する運用までは実装済みだが、価格そのものをマスタから自動引き当てる導線は当方が独自に付加した拡張。
ValueOS case_products | 現行 CRM WItem | 突合 |
|---|---|---|
| purchase_price(受注時点の仕入価スナップ) | purchasePriceSnapshot?(本セッション追加) | 一致 |
| sales_price(受注時点の販売価スナップ) | wholesalePriceSnapshot?(本セッション追加。unitPrice の取得元) | 一致 |
| gross_profit(sales_price − purchase_price、導出値) | 保持なし(wholesalePriceSnapshot − purchasePriceSnapshot で都度算出可能) | 概ね一致(当方は列を持たず算出式で代替) |
| is_manual_price(価格表を使わず手入力したか) | isManualPrice?(本セッション追加) | 一致 |
| price_fetched_at(価格取得時点) | priceFetchedAt?(本セッション追加・YYYY-MM-DD) | 一致 |
→ 受注後にマスタ(価格表・卸価格)が改定されても、既存明細の unitPrice はスナップショットされた値のまま変わらない点が ValueOS・当方で共通の設計思想。粗利(gross_profit)は当方は列として持たず都度算出する点のみ差分。
⑪ 買掛 supplier_payments ↔ WSupplierPayment(発注→支払予定の横断一覧・実装済み)
Section titled “⑪ 買掛 supplier_payments ↔ WSupplierPayment(発注→支払予定の横断一覧・実装済み)”ValueOS は三社間(親決済)の金銭移動を finance_receipts(信販→VE入金)/supplier_payments(VE→仕入先支払)/dealer_settlements(VE→販売店精算)の3テーブルに実体化する。当方の WSupplierPayment(app/src/lib/wholesale.ts)はこのうち supplier_payments に対応する型で、案件(WholesaleCase.supplierPayments)配下に仕入先・紐づく発注番号・支払予定日・支払予定額・実支払日・実支払額・状態(予定/支払済)を個別に保持する。
ValueOS supplier_payments | 現行 CRM WSupplierPayment | 突合 |
|---|---|---|
| supplier(仕入先) | supplier | 一致 |
| 紐づく発注(order_no 相当) | orderNo?(発注番号 PO-xxxx) | 一致 |
| due_date(支払予定日) | dueDate | 一致 |
| scheduled_amount(支払予定額) | scheduledAmount | 一致 |
| paid_date / paid_amount(実支払) | paidDate?/paidAmount? | 一致 |
| status(予定/支払済 等) | status(予定/支払済) | 一致 |
新画面 /wholesale-payables(WholesalePayables.tsx)は、この WSupplierPayment を全案件横断でフラット化し、仕入先・発注番号・支払予定日・金額・状態で一覧表示する。支払予定日は明細(WSupplierPayment.dueDate)が未設定の場合、該当発注(WholesaleCase.orders の orderNo 一致)の発注日、無ければ受注日を起点に supplierPaymentDueDate()(⑨)で自動算出し「(自動)」表示で補完する。支払予定総額・支払済・未払残・期限超過(件数付き)をサマリー表示し、未払/支払済/すべてでフィルタできる。
既存の「請求・入金(未収管理)」一覧(WholesaleReceivables・売掛=ValueOSのfinance_receipts側に相当)に対して、本画面は買掛(仕入先への支払)側の対にあたる。ValueOS 側でも三社間決済の金銭移動が3テーブルに分かれているのと同様、当方も売掛(未収)・買掛(支払予定)を別画面で横断管理する構成に揃った。
卸案件ドメインの詳細設計仕様(実装 app/src/lib/wholesale.ts 準拠)
Section titled “卸案件ドメインの詳細設計仕様(実装 app/src/lib/wholesale.ts 準拠)”商社/卸(別軸)ドメインの実装本体は app/src/lib/wholesale.ts。決済区分(WSettlement)別に発注/請求/入金の可否と次アクションを機械判定する wholesaleFlow() が中核で、ValueOS lib/workflow/WorkflowEngine.ts(SETTLEMENT_RULES を解釈する evaluateWorkflow())と同じ設計思想(決済区分別ルールをデータで持ち、エンジンは解釈するだけ)を採る。以降、この節では実装コードに基づき、フィールド・状態遷移・業務ルール・画面挙動・権限・異常系を確定する。
フィールド定義(全型)
Section titled “フィールド定義(全型)”決済区分・決済条件詳細
Section titled “決済区分・決済条件詳細”| フィールド | 型 / enum | 必須 | 既定値 | 制約・備考 |
|---|---|---|---|---|
WholesaleCase.settlement | WSettlement = "前金" | "掛売" | "三社間" | "カード" | "その他" | 必須 | 新規作成時 "前金" | WHOLESALE_SETTLEMENTS の5値。ValueOS 正式値は 前金/売掛/3社間決済/カード の4値(aliases に旧称 掛売/三社間/ローン 等を読取互換で持つ)。当方の "その他" は ValueOS SETTLEMENT_RULES に対応ルールが無く、ValueOS 側に投入すると resolveSettlementRule() が null を返し「未対応の決済区分です」警告・canOrder=false/canInvoice=false になる |
WholesaleCase.settlementDetail | WSettlementDetail(任意) | 任意 | なし | 決済区分ごとに SETTLEMENT_FIELDS で表示項目を出し分け(下表) |
WSettlementDetail.feeRate | number(%) | 任意 | なし | 全区分共通で表示対象 |
WSettlementDetail.feeAmount | number(円) | 任意 | なし | 全区分共通で表示対象 |
WSettlementDetail.depositRate | number(%) | 任意 | なし | 前金のみ表示。registerPayment() の入金額算出には反映されない(下記「業務ルール」参照) |
WSettlementDetail.depositAmount | number(円) | 任意 | なし | 前金のみ表示。同上 |
WSettlementDetail.paymentTerms | string | 任意 | なし | 掛売/その他で表示(締め/サイトの自由記述) |
WSettlementDetail.cardBrand | string | 任意 | なし | カードのみ表示 |
WSettlementDetail.cardStatus | WCardStatus = "未処理" | "承認済" | "決済済" | 任意 | なし | カードのみ表示。ValueOS card_status の実カタログは 未決済/処理中/決済成功/決済失敗/取消 で値の語彙が一致しない(概念のみ対応。決済成功=当方決済済相当と推定) |
WSettlementDetail.financeCompany | string | 任意 | なし | 三社間のみ表示 |
WSettlementDetail.loanStatus | WLoanStatus = "審査中" | "承認済" | "実行済" | 任意 | なし | 三社間のみ表示。ValueOS loan_status の実カタログは 未申請/申請中/承認済/否認 で語彙が一致しない(承認済のみ字面一致。当方の実行済はValueOS側に対応値なし) |
WSettlementDetail.approvalNo | string | 任意 | なし | 三社間/カードで表示。WholesaleCase.approvalNo と同義で後方互換のため残置(重複保持) |
明細(WItem)
Section titled “明細(WItem)”| フィールド | 型 | 必須 | 既定値 | 制約・備考 |
|---|---|---|---|---|
name | string | 必須 | なし | マスタ選択 or 自由入力(ComboboxCreate) |
kind | WItemKind = "商品" | "パッケージ" | 必須 | 品名選択時はマスタの区分を自動セット | 手動変更可 |
qty | number | 必須 | 1 | UI入力は Math.max(1, Number(qty) || 1) で1未満を1に補正(0・負数・非数値を許さない) |
unitPrice | number(税抜) | 必須 | マスタ卸価格 or 手入力 | 販売店向け卸単価(税抜)。0以下は明細として採用されない(enteredPrice <= 0 は行ごと破棄) |
purchasePriceSnapshot | number(任意) | 任意 | マスタpurchasePrice(ヒット時) | 受注時点の仕入価スナップ(ValueOS case_products.purchase_price 相当) |
wholesalePriceSnapshot | number(任意) | 任意 | unitPriceと同値 | 受注時点の卸価スナップ(ValueOS sales_price 相当)。マスタ改定の影響を受けない |
isManualPrice | boolean(任意) | 任意 | !hit || hit.wholesalePrice !== enteredPrice で自動判定 | マスタ卸価と一致しない(マスタ未ヒット含む)場合に true |
priceFetchedAt | string(YYYY-MM-DD、任意) | 任意 | 明細確定日(当日) | 価格取得時点 |
発注 WOrder /請求 WInvoice /入金 WPayment
Section titled “発注 WOrder /請求 WInvoice /入金 WPayment”| フィールド | 型 | 必須 | 既定値(registerOrder/registerInvoice/registerPayment) | 制約・備考 |
|---|---|---|---|---|
WOrder.id | string | 必須 | O-${Date.now()} | 案件内一意(タイムスタンプ採番。同一ミリ秒での連打は衝突しうる) |
WOrder.orderNo | string(PO-0001形式) | 必須 | newOrderNo(cases) | 全案件横断の連番(nextSeq():既存 PO- 番号の最大値+1、4桁ゼロ詰め) |
WOrder.orderDate | string(YYYY-MM-DD) | 必須 | 当日 | |
WOrder.supplier | string(任意) | 任意 | 未設定(registerOrder()は仕入先を聞かない) | 印刷画面では未設定時「(仕入先未定)」表示 |
WOrder.amount | number | 必須 | wholesaleTotal(c)(=案件の卸金額合計) | コード注釈「発注金額(=原価。無ければ卸金額を仮置き)」の通り、画面の「発注を登録」操作は原価入力欄を持たず、卸金額(販売価格)をそのまま原価としてセットする。案件明細の purchasePriceSnapshot 合計とは別ソースで、両者は自動連動しない |
WOrder.status | WOrderStatus = "発注済" | "納品済" | 必須 | "発注済" | markDelivered()で"納品済"へ一方向遷移(差し戻しなし) |
WOrder.deliveredDate | string(任意) | 任意 | markDelivered()実行日 | |
WInvoice.id | string | 必須 | I-${Date.now()} | |
WInvoice.invoiceNo | string(INV-0001形式) | 必須 | newInvoiceNo(cases) | 全案件横断の連番(WOrderと同方式) |
WInvoice.invoiceDate | string | 必須 | 当日 | |
WInvoice.dueDate | string | 必須 | 請求日 + 固定30日(inDays(30)) | 支払サイトの個別設定は無く一律30日 |
WInvoice.amount | number | 必須 | wholesaleTotal(c)(税抜) | 印刷画面でのみ税10%を加算表示(下記「業務ルール」) |
WInvoice.status | WInvoiceStatus = "請求済" | "一部入金" | "入金済" | 必須 | "請求済" | addPayment()後にreconcile()が入金合計と請求合計を突合し自動遷移(下記状態遷移図) |
WPayment.id | string | 必須 | P-${Date.now()} | |
WPayment.paymentDate | string | 必須 | 当日 | |
WPayment.amount | number | 必須 | 入力額 or 残高(下記) | 0以下はregisterPayment()内で無視(登録されない) |
WPayment.method | string(任意) | 任意 | 未設定 | 案件詳細画面の入金登録フォームには入力欄なし(シードデータのみ"振込"等を保持) |
三社間マネー(WFinanceReceipt / WSupplierPayment / WDealerSettlement)
Section titled “三社間マネー(WFinanceReceipt / WSupplierPayment / WDealerSettlement)”| フィールド | 型 | 必須 | 制約・備考 |
|---|---|---|---|
WFinanceReceipt.financeCompany / scheduledDate / scheduledAmount / status("予定"|"入金済") | — | 必須 | 信販→VE入金 |
WFinanceReceipt.actualDate / actualAmount | — | 任意 | 実入金 |
WSupplierPayment.supplier / dueDate / scheduledAmount / status("予定"|"支払済") | — | 必須 | VE→仕入先支払 |
WSupplierPayment.orderNo / paidDate / paidAmount | — | 任意 | orderNoでWOrderと紐付け(発注日の起点に使用) |
WDealerSettlement.statementNo / issueDate / creditReceived / veShare / adjustment / payout / status("予定"|"精算済") | — | 必須 | VE→販売店精算。payout = creditReceived − veShare + adjustment (算出式はコード上の関係。ストア側で自動計算はされず、値は都度手入力を前提) |
WDealerSettlement.scheduledPayoutDate / actualPayoutDate / memo | — | 任意 |
この3型は useWholesale ストアに専用の追加・更新アクションが無い(addOrder/markDelivered/addInvoice/addPaymentのみ実装)。案件詳細画面(WholesaleDetail)は既存値の表示のみで、登録・編集フォームは実装されていない(シードデータの WHOLESALE_SEED にのみ実データがある)。
案件本体(WholesaleCase)
Section titled “案件本体(WholesaleCase)”| フィールド | 型 | 必須 | 既定値(新規作成時) | 備考 |
|---|---|---|---|---|
id | string(W-0001形式) | 必須 | newWholesaleId(existing)(既存IDの文字列配列を渡す。呼び出し側は newWholesaleId(cases.map((c) => c.id))。全案件横断・4桁ゼロ詰め連番) | |
createdAt | string | 必須 | 当日 | 起票日 |
orderReceivedDate | string(任意) | 任意 | 未設定(orderReceivedDateOf()がcreatedAtにフォールバック) | ValueOS order_received_date 相当 |
dealer | string | 必須 | フォーム選択必須(未選択は送信エラー) | EventCompany.name 由来 |
settlement / approvalNo? / settlementDetail? / items | 前掲 | itemsのみ必須(1件以上、品名かつ単価>0) | ||
settlementConfirmed | boolean | 必須 | false | 決済条件確定フラグ |
paymentReceived | boolean | 必須 | false | 入金完了(残高0)。reconcile()で自動更新 |
ordered | boolean | 必須 | false | addOrder()実行でtrue固定(差し戻しなし) |
delivered | boolean | 必須 | false | 全WOrder.statusが"納品済"になった時点でtrue |
invoiced | boolean | 必須 | false | addInvoice()実行でtrue固定(差し戻しなし) |
orders? / invoices? / payments? / financeReceipts? / supplierPayments? / dealerSettlement? | 配列/任意 | 任意 | undefined(?? []で空扱い) | |
cancelled | boolean(任意) | 任意 | 未設定 | wholesaleMetrics()の集計対象外に使うのみ。この値を立てるUI操作は実装されていない(updateCase()経由の直接パッチのみ理論上可能) |
memo | string(任意) | 任意 | 未設定 |
タスク(WholesaleTask)
Section titled “タスク(WholesaleTask)”| フィールド | 型 | 必須 | 備考 |
|---|---|---|---|
id | string(WT-0001形式) | 必須 | 全件横断連番 |
caseId | string | null | 必須(null許容) | 未紐付けタスクはnull |
title / assignee / dueDate / createdAt | string | 必須 | dueDateは空文字可 |
status | "未対応" | "対応中" | "完了" | 必須 | |
priority | "高" | "中" | "低" | 必須 | |
memo | string(任意) | 任意 |
ValueOS tasks(case_id/title/status/due_date/assigned_user/priority/memo)とフィールド完全一致(既存記述のとおり)。
状態遷移・ワークフロー
Section titled “状態遷移・ワークフロー”決済区分ごとに FLOW(ステップ順)が異なる。ステップの完了判定(stepDone())は案件のフラグ/settlementApproved()を参照する。
flowchart LR
subgraph SG1["前金"]
direction LR
A1["決済条件の確定"] --> A2["前金の請求・入金確認"] --> A3["商社/メーカーへ発注"] --> A4["納品確認"]
end
subgraph SG2["掛売"]
direction LR
B1["決済条件の確定"] --> B2["商社/メーカーへ発注"] --> B3["納品確認"] --> B4["販売店へ請求"] --> B5["入金の消込"]
end
subgraph SG3["三社間"]
direction LR
C1["審査OK(承認番号)の確認"] --> C2["商社/メーカーへ発注"] --> C3["納品確認"] --> C4["入金の消込"]
end
subgraph SG4["カード"]
direction LR
D1["審査OK(承認番号)の確認"] --> D2["商社/メーカーへ発注"] --> D3["納品確認"] --> D4["入金の消込"]
end
subgraph SG5["その他"]
direction LR
E1["決済条件の確定"] --> E2["商社/メーカーへ発注"] --> E3["納品確認"] --> E4["販売店へ請求"] --> E5["入金の消込"]
end
三社間・カードには「請求」ステップが無い点に注意(納品確認の次は直接「入金の消込」)。ValueOS SETTLEMENT_RULES.3社間決済/カードはcanInvoiceWhenにcompletion_date_set/card_status条件を持ち請求フェーズが存在するのに対し、当方はこの2区分について販売店への請求という概念を持たず、信販会社からの入金(WFinanceReceipt)で直接消込む設計(差分として明示)。
業務ボード(一覧のバケツ表示)の遷移は次の通り(BUCKET_BY_STEP+flow.doneから導出)。
stateDiagram-v2 [*] --> 決済待ち 決済待ち --> 入金待ち : 前金(prepayステップへ) 決済待ち --> 発注待ち : 掛売/その他(決済条件確定で発注可) 決済待ち --> 発注待ち : 三社間/カード(承認番号・審査OKで発注可) 入金待ち --> 発注待ち : 前金の入金確認完了(paymentReceived=true) 発注待ち --> 納品待ち : 発注登録(ordered=true) 納品待ち --> 完了 : 前金(納品確認で完了。請求ステップなし) 納品待ち --> 請求待ち : 掛売/その他(全発注が納品済) 納品待ち --> 入金待ち : 三社間/カード(請求ステップなし・直接入金消込へ) 請求待ち --> 入金待ち : 請求登録(invoiced=true) 入金待ち --> 完了 : 入金完了(paymentReceived=true・残高0) 完了 --> [*]
WInvoice.status は登録後、後戻りしない一方向の状態機械(reconcile()が入金合計のみを見て毎回再計算するため、入金取消の概念が無ければ請求済に戻ることも無い)。
stateDiagram-v2 [*] --> 請求済 : addInvoice() 請求済 --> 一部入金 : 入金合計 > 0 かつ < 請求合計 一部入金 --> 入金済 : 入金合計 >= 請求合計 請求済 --> 入金済 : 一括入金(入金合計 >= 請求合計) 入金済 --> [*]
WOrder.status は "発注済"→"納品済" の一方向のみ(差し戻し・部分納品の概念なし)。
主要フローのシーケンス
Section titled “主要フローのシーケンス”掛売(標準:発注→納品→請求→入金)
Section titled “掛売(標準:発注→納品→請求→入金)”sequenceDiagram participant 販売店 participant VE as VE担当者 participant 商社 as 仕入先(商社/メーカー) 販売店->>VE: 発注書提出(/dealer-order もしくは内部起票 NewWholesaleSheet) VE->>VE: 決済条件を確定(settlementConfirmed=true) VE->>商社: 発注を登録(registerOrder・PO-番号を全案件横断で採番) 商社-->>VE: 納品 VE->>VE: 納品確認(markDelivered・全発注が納品済で delivered=true) VE->>販売店: 請求を登録(registerInvoice・INV-番号採番・支払期日=請求日+30日固定) 販売店-->>VE: 入金 VE->>VE: 入金を登録(addPayment→reconcile:入金合計と請求合計を突合し請求ステータスを自動遷移)
三社間(資金の三者移動:信販会社→VE→仕入先/VE→販売店)
Section titled “三社間(資金の三者移動:信販会社→VE→仕入先/VE→販売店)”sequenceDiagram participant 販売店 participant VE as VE担当者 participant 信販 as 信販会社 participant 商社 as 仕入先(商社/メーカー) 販売店->>VE: 発注書提出+承認番号(審査OK) VE->>VE: settlementApproved() 判定(approvalNo/loanStatus/cardStatus) VE->>商社: 発注を登録(registerOrder) 商社-->>VE: 納品 VE->>VE: 納品確認(delivered=true) 信販->>VE: 信販入金(WFinanceReceipt・工事後) VE->>商社: 仕入先支払(WSupplierPayment・締日+支払サイトで支払予定日を自動算出) VE->>販売店: 販売店精算(WDealerSettlement・payout=creditReceived-veShare+adjustment)
※ 図中の「信販入金」「仕入先支払」「販売店精算」の3ステップは、前掲のとおり登録・更新するUI操作が未実装(シードデータの表示のみ)。実運用に載せる場合はこの3操作の入力導線(フォーム or ストアアクション)が別途必要。
業務ルール(判定条件・端数・反映日・フォールバック・算出式)
Section titled “業務ルール(判定条件・端数・反映日・フォールバック・算出式)”- 発注可能判定(
canOrder):FLOW上「order」より前の全ステップが完了 かつ 未発注(!c.ordered)。前金は入金確認(paymentReceived)、三社間/カードはsettlementApproved()、掛売/その他は決済条件確定(settlementConfirmed)が前提。 - 請求可能判定(
canInvoice):FLOWに「invoice」ステップが存在し(=掛売/その他のみ)、その手前まで全完了 かつ 未請求(!c.invoiced)。三社間/カードはinvoiceステップ自体が無いためcanInvoiceは常にfalse。 - 審査OK判定(
settlementApproved()):approvalNo(案件直下 orsettlementDetail.approvalNo)に非空文字がある、またはloanStatusが"承認済"/"実行済"、またはcardStatusが"承認済"/"決済済"のいずれか一つでも真なら承認済み扱い(OR条件)。 - 価格の自動引き当てとフォールバック(
currentWholesalePriceForDealer()):明細の品名選択時、まずdealer(選択中の販売店)を条件に卸価格マスタを検索し、ヒットすればそれを採用。ヒットしなければdealer未設定(標準価格)で再検索。両方ヒットしない場合は単価欄が空のまま手入力に委ねる。同一dealer条件内で複数候補がある場合は「反映日(startDate)が新しい順→同日なら卸価格が安い順」で1件に絞る。 - 手入力判定(
isManualPrice):確定した単価がマスタのヒット結果と一致しない(またはマスタ未ヒット)場合にtrue。品名選択直後にマスタ卸価を上書き入力した場合もtrueになる。 - 受注時価格スナップショット:
snapshotWItem()でwholesalePriceSnapshot(=unitPriceの取得元)・purchasePriceSnapshot・priceFetchedAt・isManualPriceを明細に固定。以降マスタ(WholesalePrice)が改定されても、既存明細のunitPriceは変化しない。 - 実粗利の算出式(
wholesaleGrossProfit):wholesaleTotal(c)(明細のunitPrice×qty合計=卸金額)からwholesaleCost(c)(c.ordersのamount合計)を引いた差。明細ごとのpurchasePriceSnapshot合計は使われない(表示専用)。加えてWOrder.amountは発注登録時に卸金額をそのまま仮置きするため(前掲フィールド表参照)、発注登録直後の実粗利は0になり、実際の原価を反映するにはWOrder.amountを別途手当てする必要がある。 - 残高・入金消込(
wholesaleBalance/reconcile()):残高=max(0, 請求ベース金額 − 入金合計)(マイナスにはならない=過入金があっても残高表示は0で頭打ち)。請求ベース金額はc.invoicesがあればその合計、無ければwholesaleTotal(c)。addPayment()のたびにreconcile()が入金合計と請求合計を再比較し、全WInvoiceのステータスを一括で上書き(個々の請求書ごとの消込ではなく案件単位で判定)。 - 請求書の支払期日:
registerInvoice()は請求日から固定30日後をdueDateにセット(決済条件のpaymentTermsや仕入先ごとのサイト設定は反映されない)。 - 仕入先支払予定日の算出(
supplierPaymentDueDate()):仕入先マスタのclosingDay(締日:"末"("月末"含む)/"◯日")とpaymentSite(支払サイト:接頭辞"翌"=+1ヶ月/"翌々"=+2ヶ月/接頭辞なし=当月(+0ヶ月)に、日指定"末"または"◯日"を組み合わせた表記)を解析し、①発注日が当月の締日以前ならその月で締め・超過なら翌月へ繰り越し、②締め月から支払サイトの月数だけ加算した月の指定日を支払予定日とする。仕入先が見つからない、締日/支払サイトが未設定、または表記を解析できない場合はundefined(呼び出し側で「未定」表示 or 手入力にフォールバック)。 - 消費税の扱い:システム内部の金額(
unitPrice/WOrder.amount/WInvoice.amount/WPayment.amount/残高計算)はすべて税抜。消費税10%は請求書印刷画面(/wholesale-invoice-print/:caseId)でのみMath.round(小計 × 0.1)として算出・表示され、保存はされない(表示専用の都度計算)。発注書印刷画面(/wholesale-order-print/:caseId)は税計算を行わない(税抜のまま)。 - 請求書印刷の「残高(未収)」表示に関する注意:印刷画面の「御請求金額(税込)」は税込合計だが、同画面の「残高(未収)」行は
wholesaleBalance()(税抜ベース)をそのまま表示しており、税込表示と税抜ベースの残高が並記される(税込・税抜の基準が画面内で混在する点に留意)。 - 前金の入金額:
前金区分の「入金の消込」操作(advance()→registerPayment(balance > 0 ? balance : billed))は残高(=卸金額全額)をそのまま入金額の既定値にする。settlementDetail.depositRate/depositAmount(頭金率・頭金額)は決済条件の表示欄があるのみで、一部前受金としての按分計算には使われない(全額精算が前提)。 - 番号採番(
newWholesaleId/newOrderNo/newInvoiceNo/newWholesaleTaskId):いずれも「既存の同一プレフィックス番号から数値部分を抽出し最大値+1、4桁ゼロ詰め」という同方式(newOrderNo/newInvoiceNoは共通ヘルパnextSeq()を使用、newWholesaleId/newWholesaleTaskId(lib/wholesaleTask.ts)は同等ロジックを個別実装)。WOrder.id/WInvoice.id/WPayment.id自体は`${prefix}-${Date.now()}`のタイムスタンプ採番(全案件横断の連番ではない)。 - 卸案件のバケツ集計対象:
wholesaleMetrics()はc.cancelled === trueの案件を集計から除外する(ValueOS の active レコード除外相当)。売上・実粗利はorderReceivedDateOf(c)(受注日、未設定時はcreatedAt)が指定期間内のものだけを集計し、未入金額は期間非連動(全期間の残高合計)。
画面・操作の挙動
Section titled “画面・操作の挙動”| 画面 | パス | 主な挙動 |
|---|---|---|
| 卸案件一覧 | /wholesale | 5つの見せ方をタブ切替(業務ボード/決済フロー/カレンダー/サマリー/タスク)。検索は販売店名/ID/決済区分の部分一致(サマリー・タスクタブでは検索欄非表示)。ヘッダーの「+新規」(NewWholesaleSheet)で案件を起票 |
| 卸案件詳細 | /wholesale/$caseId | 明細・発注/請求/入金の登録操作・ワークフローステップ表示・決済区分の変更・決済条件詳細・三社間マネー(表示のみ)を1画面に集約。「次に進める」ボタン(advance())は現在ステップに応じてconfirmSettlement/registerOrder/deliverAll/registerInvoice/registerPaymentのいずれかを自動的に呼ぶ(承認待ちステップのみボタンを出さず「承認番号を入力すると次の工程(発注)に進めます。」と案内) |
| 販売店発注フォーム(受付) | /dealer-order | 販売店が自ら入力するフルページフォーム(DealerIntakeForm)。送信で受付番号(W-XXXX)を即時発行しaddCase()。認証・ロールチェックは実装されていない(フォーム自体はサイドバー非表示だが、URLを直接開けば誰でも到達・送信できる) |
| 請求・入金(未収管理) | /wholesale-billing(WholesaleReceivables) | 実請求(invoices.length > 0)がある案件のみ対象。既定フィルタは「未収」。案件ごとに入金額を個別入力し登録可能 |
| 支払予定(買掛管理) | /wholesale-payables(WholesalePayables) | 全案件のsupplierPaymentsを横断フラット化。dueDate未設定行は起点日(該当発注のorderDate、無ければ受注日)からsupplierPaymentDueDate()で自動算出し「(自動)」表示。既定フィルタは「未払」 |
| 発注書 / 請求書印刷 | /wholesale-order-print/$caseId / /wholesale-invoice-print/$caseId | WOrder/WInvoiceが未登録でも閲覧可能(「未発注・仮」「未請求・仮」表示で明細合計を仮の金額として表示) |
| 卸金額マスタ | /master-wholesale-price | 仕入先軸・販売店(dealer)軸の卸価格を管理(WholesalePriceMaster) |
権限(根拠:lib/permissions.ts)
Section titled “権限(根拠:lib/permissions.ts)”卸/商社モジュールに対する専用の権限関数は実装されていない。ロールごとの制御はサイドバー/モバイルタブの表示可否(canSeeNav())のみで、ルート単位のアクセスガード(beforeLoad等)はアプリ全体を通じて実装されていない(grepでbeforeLoad使用箇所なし)。したがって以下は「見えるか」の一覧であり、「URLを直接開けば非表示ロールでも到達できる」点に注意。
| ロール | /wholesale | /wholesale-payables | /wholesale-billing | /dealer-order | /master-wholesale-price |
|---|---|---|---|---|---|
| 管理者 | ○ | ○ | ○ | ○ | ○ |
| 事務(BO) | ○ | ✕(NAV_ALLOW未掲載) | ✕(NAV_ALLOW未掲載) | ✕(NAV_ALLOW未掲載) | ✕(NAV_ALLOW未掲載) |
| 営業 | ✕ | ✕ | ✕ | ✕ | ✕ |
| 発注・申請担当 | ✕ | ✕ | ✕ | ✕ | ✕ |
| 代理店/代理店(メンバー) | ✕ | ✕ | ✕ | ✕ | ✕ |
| 施工店 | ✕ | ✕ | ✕ | ✕ | ✕ |
○=ナビに表示、✕=非表示(未実装ガードのためURL直打ちでの閲覧は妨げられない)。事務(BO)のNAV_ALLOW配列には/wholesaleは含まれるが、/wholesale-payables・/wholesale-billing・/dealer-order・/master-wholesale-priceは含まれていない(サイドバーの「商社/卸」グループ内リンクとして遷移するのみで、直接のナビ項目としては管理者専用)。代理店(販売店)ロールから/wholesale系画面が一切見えないため、販売店自身が自社の卸案件の進捗(発注状況・入金状況)を確認する導線は/dealer-order(発注の新規提出のみ・自社の既存案件一覧は見られない)に限られる。
エッジケース・異常系
Section titled “エッジケース・異常系”- 決済区分「その他」:ValueOS
SETTLEMENT_RULESに対応キーが無いため、ValueOS へ同期・連携する場合はresolveSettlementRule()がnullを返し発注・請求とも不可判定になる。当方内部ではFLOW.その他が定義済みで動作する(掛売と同型のステップ順)。 - カード/三社間の
loanStatus/cardStatus語彙不一致:当方WLoanStatus(審査中/承認済/実行済)・WCardStatus(未処理/承認済/決済済)は、ValueOS実カタログ(loan_status=未申請/申請中/承認済/否認、card_status=未決済/処理中/決済成功/決済失敗/取消)と字面が一致しない。将来 Supabase 移行時は値のマッピング表が別途必要。 WOrder.amountの仮置き:前述の通り、画面操作(registerOrder)で新規登録した発注は原価入力欄が無く卸金額を仮置きするため、登録直後の実粗利は常に0になる。シードデータ(WHOLESALE_SEED)は原価と卸金額を意図的に分けて手作りしているため、シードのみ正しい粗利が表示される。- 前金の頭金按分:
depositRate/depositAmountは表示のみで、実際の入金登録額(registerPaymentの既定値)は常に全額(残高)。一部前受金の管理はUI上できない。 - 三社間マネー3型(
WFinanceReceipt/WSupplierPayment/WDealerSettlement)の登録手段欠如:ストアに追加・更新アクションが無く、画面は表示のみ。新規の三社間案件で信販入金・仕入先支払・販売店精算を記録する運用上の手段が実装されていない。 cancelledフラグを立てる操作が無い:型と集計除外ロジック(wholesaleMetrics)は実装済みだが、UIからcancelled: trueにする手段が無い。WSupplierPaymentの支払予定日フォールバックが失敗するケース:仕入先マスタにclosingDay/paymentSiteが未設定、または表記から日指定("末"/"◯日")を読み取れない場合(月接頭辞は"翌"/"翌々"/なし=当月をすべて許容)、supplierPaymentDueDate()はundefinedを返し、/wholesale-payables・案件詳細の両方で「未定」表示になる(自動算出の完全なフォールバックにはならない)。- 入金取消・部分取消の概念が無い:
reconcile()は入金合計のみで請求ステータスを再計算する一方向ロジックで、誤登録したWPaymentを取り消す・訂正するUI操作が無い(配列に追加されたレコードは削除できない)。 - 明細の自由入力品名(マスタ未登録):
ComboboxCreateでマスタに無い品名を入力した場合、purchasePriceSnapshotはundefinedのまま(仕入価不明)。案件の実粗利算出自体はWOrder.amountベースのため直接影響しないが、明細単位の仕入価表示は欠落する。 - 同一ミリ秒での連続登録:
WOrder.id/WInvoice.id/WPayment.idはDate.now()採番のため、同一ミリ秒内で複数登録すると理論上ID衝突しうる(orderNo/invoiceNoはnextSeq()のため衝突しない)。
確認事項(未決のみ)
Section titled “確認事項(未決のみ)”- 三社間マネー(信販入金・仕入先支払・販売店精算)の登録フォームを別途実装するか、
updateCase()の直接パッチ運用のまま据え置くか。 WOrder.amount(発注金額=原価)を発注登録時に個別入力できるようにするか(現状は卸金額の仮置きで実粗利が正しく出ない)。- 前金の頭金率・頭金額を実際の入金額計算(一部前受金)に反映するか、それとも全額前金の運用に統一して
depositRate/depositAmountを表示専用のまま残すか。 事務(BO)ロールから/wholesale-payables・/wholesale-billing・/dealer-order・/master-wholesale-priceをナビ表示すべきか(現状管理者のみNAV_ALLOWに含まれる)。- 代理店(販売店)ロールに自社の卸案件の進捗閲覧を許可するか(現状は
/wholesale系画面が一切見えない)。 - ルート単位のアクセスガード(
beforeLoad)を卸/商社モジュールに導入するか、現状のナビ非表示のみで運用するか。
催事(店頭イベント運営)は ValueOS 非該当
Section titled “催事(店頭イベント運営)は ValueOS 非該当”催事運営(EventStore/EventCompany/EventShift/StartReport/EndReport)は ValueOS のスキーマ・画面のどこにも対応が無い。ValueOS は受注(案件登録)→発注→納品→請求→回収/支払→3社間決済という契約後(後段)の商社ERPであり、催事は契約前の集客・現場運営というドメインそのものが異なるため、対応関係を持たない(構造的に対象外であり、実装漏れではない)。催事モジュールは CRM 固有機能として現状のまま維持し、ValueOS 準拠の対象から除外する。詳細は 店舗催事フロー を参照。
現行 CRM のみが持つ機能(ValueOS に無い/薄い)
Section titled “現行 CRM のみが持つ機能(ValueOS に無い/薄い)”催事運営(shifts)/顧客CRM(households)/架電(前確)/チャット/活動/見積(quotes)/手数料条件/価格照合/パッケージ(部材×必須/選択/オプション区分)/決済区分別ワークフローの FLOW(STEP順)+バケツ表示/店舗・施工店・ローン会社マスタ/申請。→ ValueOS は施主情報を持つ単一案件軸、当方は前段CRM+別軸の商社/卸。統合すれば 前段(CRM)+後段(ERP) の一本化。
次アクション(残差の埋め方・優先度)
Section titled “次アクション(残差の埋め方・優先度)”- 【小】発注/請求/入金の中間ステータス:発注(
WOrder)・請求(WInvoice)・入金(WPayment)は番号・日付・金額とも個別エンティティとして実装済み、案件横断の未収一覧(WholesaleReceivables)・買掛一覧(WholesalePayables=⑪)も揃った。残るは各書類の中間ステータス(納期回答待ち・一部納品・作成済/入金待ちの請求状態・入金ごとの確認待ち/取消)の粒度のみ。 - 【中】マスタの経理項目(残り):suppliers の締め日/支払サイト/与信枠、dealers の支払区分/既定利益額、パッケージ商品マスタ、支払予定日の自動算出は実装済み(本セッション)。残るは dealers の与信枠、products/packages の既定仕入先(default_supplier_id 相当)。→ 発注タイミング・与信チェックの自動化に効く。
- 【低】案件の付帯項目:order_type・priority・department(マネフォ部門連携の布石)。
- 【将来】 Supabase 移行(ValueOS と同スキーマ方向)、マネフォ連携(PL/CF)、SaaS化。
※ ValueOS も WorkflowEngine.ts(SETTLEMENT_RULES)で決済区分別に canOrder/canInvoice を機械判定している。当方 wholesaleFlow の方針(決済区分別に canOrder/canInvoice を機械判定・FLOW+バケツ表示で拡張)は維持・発展させる。