# 入札形式の大口取引の実務ガイド|小さく始めて継続運用へ移す実践手順を示す
大口入札を導入するとき、最初から全機種、全拠点、複数通貨、複雑な組合せ入札へ対応する必要はありません。一方、対象を小さくすることと、価格・数量・権限・締切を曖昧にすることは別です。一案件でも、0円、自己取引、過剰落札、同時承認、誤通知、古い金額の請求を止める必要があります。
安全な進め方は、均一な一ロットを選び、案件票、入札、落札、契約、請求、発送、検収を別状態として設計し、異常シナリオを実APIで確認してから範囲を広げることです。本稿では、初回500台案件を想定し、準備、実装、パイロット、継続運用を90日で進める手順を示します。
手順1:初回案件の範囲と成功条件を決める
初回は、一拠点、一通貨、一つの税区分、品質が比較的均一な一ロットに絞ります。品目別・組合せ・段階価格・越境・複数発送は後段に置きます。
対象例は次です。
- •同一モデル・同一容量を500台
- •税抜円建ての台単価
- •封印入札、締切後に売り手が選定
- •全量または100台単位の部分落札
- •国内一拠点から一括発送
- •検収差は対象個体と数量で精算
成功条件は「落札できた」ではなく、価格・数量の再現、競合防止、権限境界、請求一致まで含めます。重大な不変条件違反がゼロ、落札から請求へ品目・数量・金額が一致、一台の検収差を元入札まで追えることを条件にします。
手順2:関係者と職務分離を決める
案件作成、公開承認、入札、落札選定、請求、支払確認、検収を一人へ集中させません。少なくとも次の役割を定義します。
| 役割 | 主な操作 | 禁止する操作 |
|---|---|---|
| 売り手作成者 | 案件下書き・資料登録 | 自分の案件への入札 |
| 売り手承認者 | 公開・取消・落札承認 | 入札者の代理入力 |
| 買い手入札者 | 自社入札・変更・撤回 | 他社価格・非公開情報の閲覧 |
| 案件スタッフ | 条件確認・当事者支援 | 担当外案件の変更 |
| 経理 | 請求発行・入金照合 | 落札数量の直接変更 |
| 監査 | 履歴閲覧 | 業務データ更新 |
IPAのアクセス制御や認可制御の欠落に関する解説を参考に、画面表示だけでなくAPIで、role、organization_id、assignment、対象状態を確認します。推測困難なIDを認可の代わりにしません。
手順3:状態機械を先に図にする
画面を作る前に、許可する状態遷移を固定します。
案件は `DRAFT → SCHEDULED → OPEN → CLOSED → AWARDING → AWARDED → FULFILLING → COMPLETED` を基本とし、許可状態からだけ `CANCELLED` へ進めます。入札は `ACTIVE → WITHDRAWN | EXPIRED | AWARDED | REJECTED` とします。
落札選定と取引契約を分ける場合は、`SELECTED → PENDING_CONFIRMATION → CONTRACTED` を追加します。契約成立時点は利用規約・案件条件と一致させます。経済産業省の電子商取引及び情報財取引等に関する準則も参照し、自社取引への適用は必要に応じ専門家へ確認します。
各遷移に、実行役割、前提、更新内容、監査、通知イベントを定義します。管理者用の無条件更新を作らず、緊急操作にも理由と追加承認を必要にします。
手順4:案件票を版管理して凍結する
案件公開時に、対象、数量、品質、写真、価格条件、税、送料、締切、選定規則を一つの版として確定します。公開後の軽微な誤字と、価格判断へ影響する変更を分けます。
重大変更の例は次です。
- •機種・容量・状態・数量
- •写真・検査結果・データ消去状態
- •最低価格・最小数量・部分落札
- •税・送料・手数料・通貨
- •締切・自動延長
- •支払い・発送・検収
重大変更では既存入札をそのまま有効にせず、変更内容を全参加者へ示し、再確認または再入札を求めます。旧版を削除せず、各入札が見た案件版を保存します。
手順5:金額と数量を正確値で持つ
円建てなら金額を整数で保存し、JavaScriptの表示用小数や文字列から請求額を再計算しません。外貨へ広げる場合は通貨ごとの最小単位または十進精度を定義します。
初回の基本項目は次です。
- •unit_price_ex_tax:正の整数
- •bid_quantity:最小単位以上、希望上限以下
- •subtotal:単価×落札数量
- •shipping・fee:負担者と計算式
- •tax:税率、課税対象、端数規則
- •total:確定した内訳の合計
数量はlisted、bid、awarded、shipped、received、accepted、invoicedを分けます。案件の残数を表示用集計だけに頼らず、有効落札と取消戻入から検証します。
手順6:入札入力をサーバーで再検証する
クライアントの入力制限は操作補助です。APIで、認証、組織、案件状態、締切、案件版、単価、数量、最小単位、部分落札条件を再確認します。
拒否する代表値は次です。
- •未入力、0、負数、非数、無限大
- •最大桁・精度を超える値
- •希望上限を超える数量
- •案件の単位に合わない数量
- •非対応通貨・税区分
- •自社案件・利用停止中組織
- •締切後・未公開・取消済み案件
同じ送信の再試行には冪等キーを使い、同じキー・同じ内容は同じ結果、同じキー・違う内容は拒否します。入札変更は旧版を残し、現在有効な版を一つにします。
手順7:締切と自動延長を同時実行に耐えさせる
締切判定はデータベースまたはサーバーの共通時刻を使います。画面のカウントダウンは正式判定ではありません。
自動延長を使うなら、入札保存と締切更新を同じ確定処理にします。例えば「締切前5分以内の有効入札で5分延長、最大30分」とし、元締切、現在締切、延長回数を保存します。
期限処理は、読み取った古い期限だけで案件を終了させず、「状態がOPENで、現在のdeadlineが読み取った値と一致し、時刻を過ぎた」という条件付き更新にします。延長が先に確定した場合、終了処理は失敗して最新値を読み直します。
手順8:落札ルールをコード化する前に表で検証する
500台に対し、三者の入札を表計算またはテストデータで評価します。
| 入札者 | 単価 | 希望数量 | 最小数量 | 条件 |
|---|---|---|---|---|
| A | 41,000円 | 300台 | 300台 | 300台全量のみ |
| B | 40,800円 | 500台 | 100台 | 100台単位 |
| C | 40,500円 | 500台 | 500台 | 全量のみ |
単価順ならAへ300台、Bへ200台で総額20,460,000円です。Bが最小300台だった場合、この配分は無効です。Cへ500台全量なら20,250,000円です。単価だけでなく制約を満たす組合せを計算します。
期待結果、同額、辞退、資格失効、数量不足を表で確認し、その例を自動テストへ変えます。手動変更を許す場合、元の推奨配分、変更後、理由、承認者を保存します。
手順9:落札確定を一つの処理へ閉じ込める
落札確定時に、案件、入札、資格、残数、在庫、既存落札をロックまたはversion付き条件更新で確認します。
確定前の条件
- •案件がCLOSEDまたはAWARDING
- •入札版がACTIVEで未撤回
- •入札者が現在も適格
- •配分が最小・上限・単位を満たす
- •案件残数と実在庫を超えない
- •同じ入札・品目が未確定
確定する内容
- •awardとaward_line
- •品目、数量、単価、金額内訳
- •案件残数・状態・version
- •在庫の仮配分または確保
- •選定ルール・手動理由
- •監査イベント
- •通知送信待ちイベント
途中で競合したら全体を取り消し、部分的な落札や残数更新を残しません。自動再試行で別の配分を確定せず、担当者へ最新状態を再表示します。
手順10:通知を取引確定から分離する
落札DB更新と外部メール・通知の間には失敗が起きます。確定処理内で通知本文を送らず、送信待ち台帳へイベントを一度だけ登録します。
送信イベントにはevent_key、award_id、recipient_id、template_version、payload_version、status、attempt、next_retry_atを持たせます。本文にはaward_lineだけを渡し、一部落札で元入札の全品目を入れません。
送信担当は待ちイベントを取得し、受付結果を記録します。タイムアウト時に再試行してもevent_keyで重複を防ぎます。最終失敗は業務画面へ表示し、落札処理を再実行しません。
テスト環境では外部メール・LINEへ送らず、模擬受信箱へ保存し、宛先、品目、数量、金額、重複を確認します。
手順11:請求・支払いを落札版へ結ぶ
落札後に請求書を作る場合、元の入札ではなく確定したaward_lineを参照します。商談・契約状態、価格版、数量版、既存請求を生成処理内で確認します。
下書き、発行、送付、支払確認を分けます。自動生成する場合も自動送信とは分け、送付は権限者が内容を確認して実行できる設計にします。再生成は旧版を残し、番号、金額、理由、実行者を追跡します。
支払総額と取引計算値が一致しない場合、過去履歴を自動修正しません。請求、銀行記録、返金、調整を照合ケースへ集め、原因と承認を経て処理します。
手順12:発送・受領・検収差を実装する
落札500台でも、発送499台、受領498台、検収合格495台になる場合があります。数量を一つの列で上書きしません。
発送時に個体・箱を割り当て、受領時に箱と個体を照合します。検収差は、欠品、予定外、破損、品質、データ、安全へ分類し、対象asset_id、写真、基準版、当事者合意を結びます。
精算は、交換、追加発送、返品、減額、現状受入を選び、請求調整へ連動します。金額だけを合わせて差異原因を閉じず、再発防止を別に管理します。
手順13:隔離環境で実API結合テストを行う
コード内の文字列や単体関数だけでなく、隔離DB、テスト組織、模擬通知で全状態遷移を実行します。既存の本番取引・ユーザー・通知へ触れません。
必須シナリオは次です。
- •0・負数・桁超過・数量超過の拒否
- •自己取引・担当外閲覧・担当外再生成の拒否
- •締切直前入札と自動延長
- •締切更新と期限処理の競合
- •撤回と落札の同時実行
- •二人による残数への同時落札
- •部分落札と全量・最小数量条件
- •一部品目だけの通知・請求
- •通知タイムアウトと重複再試行
- •落札後変更と請求生成の競合
- •発送・受領・検収数量差
- •取消・戻入後の再落札
各テストでHTTP結果、DB状態、監査、送信待ち、請求件数を確認し、失敗後に中間状態が残らないことを証明します。
テストデータは、実在する取引先やメールアドレスを流用せず、seller-test、buyer-a-test、buyer-b-test、staff-test、account-testのように役割を分けます。外部送信先は模擬受信箱へ固定し、商品承認、落札、請求のどの処理からも実メール・LINEへ到達しないことを設定とテストの両方で確認します。
500台案件には、正常な499台だけでなく、別案件ID一台、消去失敗一台、電池異常一台、品質差一台を重ねず別ケースとして用意します。異常品が価格配分や落札件数へ混ざらず、落札後に発見した場合も対象個体と精算だけを訂正できるか確認します。
完走テストでは、案件作成から、二者入札、締切、部分落札、下書き請求、支払確認、発送、受領、検収差、精算、完了までを一つのテストIDで追います。各段階で次のAPIを直接呼べないことも確認し、状態遷移の飛び越しを防ぎます。
テスト終了後は、作成した案件、請求、送信待ち、監査記録をテスト用として識別できることを確認し、本番集計・価格統計・売買実績へ含めません。削除だけに頼らず、隔離環境の初期化手順と再実行時のデータ準備を自動化します。
手順14:パイロット後の監視を自動化する
初回案件後も、次の不変条件を定期検査します。
- •有効落札数量が販売可能数量を超えない
- •案件残数と落札・取消集計が一致する
- •有効入札単価・数量が許容範囲内
- •自己取引・停止組織の落札がない
- •award_lineと通知・請求の品目が一致する
- •同じ落札版の有効請求が重複しない
- •送信イベントの一意キーが重複しない
- •支払い・検収・完了状態が順序どおり
異常を検出したら自動で過去値を書き換えず、案件を保留し、対象、差、最終正常状態を担当へ通知します。監視自体の実行失敗も検知します。
90日ロードマップ
0〜30日
- •初回500台案件と成功条件を選ぶ
- •役割、状態機械、案件票、金額・数量モデルを承認する
- •正常・異常・同時実行の期待結果を表にする
- •模擬通知と隔離DBを準備する
31〜60日
- •入札、締切、落札、通知、請求を実装する
- •権限・0円・自己取引・競合テストを通す
- •売り手・買い手・スタッフ・経理が操作確認する
- •監査と不変条件チェックを作る
61〜90日
- •一案件を限定公開し、日次照合する
- •落札から検収・精算まで完走する
- •最悪ケースと手動変更をレビューする
- •合格条件を満たした形式・品目だけ広げる
実装チェックリスト
[販売相場を確認する](/market-search)際も、希望価格、入札価格、落札価格を分け、状態・数量・税送料・時点をそろえます。
- •[ ] 初回案件の形式と対象外を決めた
- •[ ] 案件作成・落札・請求を職務分離した
- •[ ] 案件と入札の状態機械がある
- •[ ] 公開後の重大変更を版管理する
- •[ ] 金額を正確値、数量を段階別に保存する
- •[ ] サーバーで0円・自己取引・締切を拒否する
- •[ ] 締切延長と終了処理の競合を防ぐ
- •[ ] 配分制約を表と自動テストで確認する
- •[ ] 落札確定を一つの処理で行う
- •[ ] 一部落札の品目だけを通知・請求へ渡す
- •[ ] 通知を送信待ち台帳で再試行する
- •[ ] 請求を確定した落札版へ結ぶ
- •[ ] 発送・受領・検収数量を分ける
- •[ ] 隔離DBで実API同時実行を試した
- •[ ] 本番で不変条件を定期監視する
- •[ ] 異常時に履歴を自動修正しない
まとめ:一案件でも、取引の境界は省略しない
大口入札を小さく始めるなら、対象機種、拠点、通貨、形式を限定します。ただし、案件票、金額、数量、締切、資格、落札、通知、請求、検収の境界は最初から明確にします。
状態機械と版を先に決め、入力をサーバーで検証し、落札確定時に入札版・残数・資格・在庫を同じ処理で確認します。通知は送信待ち台帳へ分離し、一部落札の確定品目だけを請求へ渡します。
90日間で、正常系より先に0円、自己取引、締切競合、同時落札、通知失敗、請求競合を隔離環境で再現します。初回500台を落札から検収・精算まで追い、不変条件と逆向き監査を満たした形式だけ広げることが、継続可能な入札運用への最短経路です。
