チャーター料金の計算を 自前の料金エンジンとして作り直す ための設計資料。作るものは ①パラメータ設定ページ ②料金シミュレーションページ の2つで、置き場所は当面 mcj-companyapps の /pricing。将来は刷新後のHP・予約管理・代理店ポータル・オーナーポータルから叩かれる 社内外まとめて1本の料金API にする。
第1版で挙げた論点10件はすべて方針が決まった。いちばん大きいのは「HPとの金額一致を条件にしない」こと。料金改定を前提にするので、エンジンは HPの再現装置ではなく、これからの料金の正 になる。飛行時間も 空中ETEを5分切り上げ という自前の定義で持つ。
細部6件も決着し、未決はゼロ。端数はHPの実挙動を実測して確認したうえで 1,000円未満切り捨て・丸めてから貸切料金を充当 に決めた(4章)。この版をそのまま実装仕様として使える状態。次は12章 Phase1。
- 課金する飛行時間=空中ETE(風補正・空港ファクター込み)を LEGごとに5分切り上げ。ブロックタイムは使わない。往復で時間が違うのはそのまま出す。
- テクランは料金計算に持ち込まない。燃料を度外視して直行したときの空中ETEで計算する。運航上テクランが要るかどうかは別の判断(配置エンジンの仕事)。
- 連続5日以上も計算する。HPの4日上限が外れる。むしろ長期の受注を伸ばしたいので、そこで見積が出ないのは機会損失。
- エンジンは定価のみを返す。代理店割引・キックバックは代理店ポータル側で管理する。
- 通貨は当面JPYのみ。USDは将来やるので、データモデルには通貨の軸だけ入れておく。
- 遠域ゾーンは空港ごとに選ぶ。海外運航が始まり空港もゾーンも増えていく前提で、地理条件のハードコードにはしない。
- 版(プライスブック)+有効化フラグを持つ。見積時点の額がそのまま請求額なので、見積を出した瞬間の版と明細を焼き付ける。
- 編集権限は最初は不要。ただし後から挟むので、誰がいつ何を変えたかの記録は最初から取る。
- 置き場所=いまは companyapps、本格運用時に切り離す。パラメータのD1は mcj-master に相乗り。(9章)
- HPとの金額一致は条件にしない。companyapps 内で十分検証してから公開へ進む。現行料金からの変更を予定している。
- 飛行料金は1,000円未満を切り捨て、その丸め後の値で貸切料金を充当する(HPの実挙動と同じ順序)。
- 型式ごとに「社内で使える/公開してよい」の2フラグを持つ。事業機化が未定の機体を公開しないための栓。
- 最初の投入は現行のままのパラメータ。改定は次の版で。
① パラメータ設定ページ /pricing/params
- 型式ごとに 基本料金・貸切料金/日・飛行単価①②・海外運航料金・早朝/深夜料金 を設定
- 遠域ゾーンを自由に追加。ゾーンごと × 型式ごとに 遠域料金・施設料
- 空港ごとに 空港内送迎料金・所属遠域ゾーン を割当(マスタの空港一覧から検索)
- 税率・丸め規則・版の作成と有効化
- 変更は 保存の前に差分プレビュー、保存後は版として残る
② 料金シミュレーションページ /pricing/sim
- 型式・日程・区間(複数日・複数LEG)・早朝深夜を入れると内訳つきで金額が出る
- 飛行時間は
flight-calc.jsが算出(直行・空中ETE・5分切り上げ) - 内訳の各行が どのパラメータから来たかを表示(値付けを説明できる状態にする)
- 版どうしの比較モード — 現行料金と改定案で代表ケースがいくら変わるかを一覧(13章)
/rc/ を触ると全部止まる。自前化の一番の理由は、HP刷新でこの依存が切れること。HP側は同僚が担当する予定で、/rc/ を残すか引っ越すかも未決。料金エンジンを自前で持てば、HPは「料金APIを叩くだけの画面」になり、/rc/ のCGIごと廃止できる。
副次的に、4日上限が外れる(連続5日以上を営業部へ回している運用が不要になる)・失敗が静かに0円にならない・料金改定をこちらの都合でできるようになる。
mcj-quote/workers/src/pricing.ts にも自前実装があるが、C510定数のみ・遠域を全LEGの発着地で加算しており料金表とズレている。流用しない。新エンジン完成時に撤去対象。これは 移行の出発点であって、目標ではない。現行から料金を変更する予定なので、この値は「最初に投入する版(2026-04)」として入れておき、改定は新しい版で行う。
| 項目 | Mustang(C510) | CJ4(C25C) | 課金単位 | 適用条件 |
|---|---|---|---|---|
| 基本料金 | 700,000 | 1,050,000 | 円 / 件 | 1件につき1回 |
| チャーター(貸切)料金 | 600,000 | 750,000 | 円 / 日 | 飛行料金に充当される(4章) |
| 飛行単価① | 400,000 | 600,000 | 円 / 時間 | 国内離発着 |
| 飛行単価② | 500,000 | 700,000 | 円 / 時間 | 出発地または到着地が海外 |
| 海外運航料金 | 250,000 | 250,000 | 円 / 件 | 国際運航時(HPの表は両型式で結合セル=同額。2026-08-13 確認) |
| 早朝出発料金 | 280,000 | 280,000 | 円 / 件 | 初日の出発が 8:59 まで |
| 深夜到着料金 | 280,000 | 280,000 | 円 / 件 | 最終日の到着が 21:00 以降 |
| 遠域発着料金(対象地域) | C510 | CJ4 |
|---|---|---|
| 北海道 | 120,000 | 200,000 |
| 奄美以南 | 200,000 | 320,000 |
| 那覇以南 | 350,000 | 520,000 |
| 台湾 | 500,000 | 750,000 |
| 韓国 | 250,000 | 350,000 |
| グアム・サイパン | — | 750,000 |
| 香港・マカオ | — | 1,300,000 |
| 空港内送迎料金 | 金額 |
|---|---|
| 千歳・成田・羽田・関西・福岡・鹿児島・那覇 | 120,000 |
| 中部 | 150,000 |
| 海外空港施設利用料金・送迎料金 | 金額 |
|---|---|
| 台湾 | 650,000 |
| 韓国 | 500,000 |
| グアム・サイパン | 500,000 |
| 香港 | 1,500,000 |
| マカオ | 550,000 |
C510 / C25C。エンジンのキーは マスタ側の type_code に統一し、表示名だけHP表記に寄せる。G550(N679MS)・HA420 は料金表にないので当面 料金未設定=見積不可(→ 11章の確認5)。// 1件(=連続して飛ぶ日の塊 ひとかたまり)あたり・税抜 合計税抜 = 基本料金 // 件に1回 + Σ日 [ 飛行料金(その日) + max(0, 貸切料金/日 − 飛行料金(その日)) ] // ← 明細の「貸切料金」 + Σ使用空港(重複排除) 空港内送迎料金 + 遠域発着料金(発地) + 遠域発着料金(最終着陸地) // 実質フェリー料金。同じ空港でも重複排除しない + 海外運航料金(国際運航なら件に1回) + Σ海外空港(重複排除) 海外空港施設利用料金 + 早朝出発料金 + 深夜到着料金 // その日の飛行料金(★丸めてから貸切に充当する。順序が金額に効く) 飛行料金(日) = floorN( Σその日のLEG ( 課金時間(LEG)[分] ÷ 60 × 飛行単価 ) ) 飛行単価 = 出発地か到着地が海外なら hourly_intl(単価2) / それ以外は hourly_domestic(単価1) // 判定はLEG単位(羽田→那覇は単価1・那覇→台北は単価2) floorN = 1,000円未満切り捨て(HPの実挙動に合わせる。単位はパラメータで変更可) // 課金時間の定義(第2版で確定) 課金時間(LEG) = ceil5( 空中ETE(直行・風補正込み) ) 空中ETE = 大圏距離 ÷ 巡航速度 × 60 + 固定分 + 風補正 固定分 = 20分(羽田・成田の発着は30分) 風補正 = α(季節,型式) × 東西成分 ÷ 100 // 東向きは短縮・西向きは延長 ceil5(x) = 5分単位で切り上げ // 1:02 → 1:05 / 0:58 → 1:00 // taxi は含めない(ブロックタイムは使わない) // テクランは考慮しない(燃料度外視で直行したときの値) // 早朝・深夜は時刻が入力されているときだけ判定する(未入力なら加算しない) // 風補正の季節αは各LEGの運航日の月。運航日未定の問い合わせでは当月を使う 合計税込 = 合計税抜 × (1 + 税率)
いちばん間違えやすいのは貸切料金の充当。「総額に対して」ではなく「日ごとに」充当する。飛ぶ日は飛行料金で吸収され、吸収しきれない差額だけ貸切料金が乗る。飛ばない中日は満額が乗る。
そしてもう一段、順序の罠がある。HPは飛行料金を丸めてからその値で貸切料金を充当している(下表)。先に充当してから丸めると金額が変わるので、この順序を守る。
| 区間(C510・単価400,000/時) | HPの飛行時間 | 理論値(丸め前) | HPの飛行料金 | HPの貸切料金 | 検算 |
|---|---|---|---|---|---|
| 羽田 → 大島 | 0:25 | 166,666.67 | 166,000 | 434,000 | 600,000 − 166,000 |
| 羽田 → 松本 | 0:35 | 233,333.33 | 233,000 | 367,000 | 600,000 − 233,000 |
| 羽田 → 八丈島 | 0:45 | 300,000.00 | 300,000 | 300,000 | 端数なし |
| 羽田 → 南紀白浜 | 1:05 | 433,333.33 | 433,000 | 167,000 | 600,000 − 433,000 |
| 名古屋 → 仙台 | 1:10 | 466,666.67 | 466,000 | 134,000 | 600,000 − 466,000 |
| 羽田 → 稚内 | 2:25 | 966,666.67 | 966,000 | 0 | 飛行料金が60万超 |
| 羽田 → 石垣 | 4:10 | 1,666,666.67 | 1,666,000 | 0 | 同上 |
なお CJ4 は単価600,000/時=1分あたり10,000円ちょうどなので、そもそも端数が出ない。端数が問題になるのは C510(単価①400,000=6,666.67/分)と海外発着の単価②(500,000=8,333.33/分)。
小計は各項目が1,000円単位に揃うので、消費税は必ず100円単位になる(例 1,906,000 × 0.1 = 190,600)。
- 「件」の定義=連続して飛ぶ日の塊。連続する日は機材を通しで確保する=1件なので割らない。日ごとに割ると基本料金が件数ぶん乗る。
- エンジンの責務は「1件を正しく計算すること」まで。塊が複数あるときの「まとめるか分けるか」の最適化は、エンジンを何度か呼ぶ上位レイヤの仕事として分離する。
- 遠域は 発地と最終着陸地のみ=実質フェリー料金。羽田→下地島→羽田は起終点が羽田なので該当なし、下地島→羽田→下地島は起終点が下地島なので下地島の遠域料金×2。羽田→新千歳の片道は着地ぶんの1回で、往復を1件にまとめると0回・片道2件に割ると各1回。この非線形があるので、まとめ/分けの損得は静的ルールで決め打ちせず必ず両方計算して比べる。
- 5日以上の制約はなくす。式はそのまま日数ぶん延びる(貸切料金/日が積み上がる)。長期案件で見積が出せるようになる。
使うもの = FlightCalc.ete() 一本
- 入力は 発地・着地・型式・運航月 だけ。返る
eteMin(空中ETE)を5分切り上げて使う block(taxi込)は使わない- 諸元は
cfgFromMaster()、空港はairportsFromMaster()=mcj-master が単一情報源 - 座標さえマスタにあれば、新規空港も海外空港もそのまま計算できる
使わないもの = assessItinerary()
- テクラン計画・燃料・滑走路長・代替空港の判定は料金には持ち込まない
- おかげでエンジンの入力が激減し、燃料モデルの精度が料金に影響しなくなる
- 「運航できるか」は配置エンジン、「いくらか」は料金エンジン、と責務が割れる
- 結果として、テクランが要る区間でも料金は直行相当=差分は会社が飲む
コピーを増やさないこと。flight-calc.js はいまリポジトリ内に中身が完全に同一のコピーが3つある(mcj-reservation/frontend/=原本・Workerが直接 import、mcj-sales/frontend/、mcj-companyapps/frontend/flight-calc/)。
<script src="/flight-calc/flight-calc.js"> で既存ファイルをそのまま参照する。コピーは増えないし、今日から動く。shared/flight-calc/ に1つ置き、各プロジェクトはそこを import。そのPRで既存3コピーもまとめて解消する。GET /api/feasibility を実行時に叩く案は採らない。将来は逆に予約管理が料金エンジンを呼ぶので相互依存になる。設計の芯は 「遠域ゾーン」を実体として持ち、空港をそこに割り当てること。海外運航が始まって空港もゾーンも増えていく前提なので、地理条件のハードコードにはしない。ゾーンを足す → 空港を割り当てる の2操作だけで対応できる状態にする。
もうひとつは 版(プライスブック)+有効化フラグ。見積時点の額がそのまま請求額になるので、見積を作った瞬間に「どの版で出したか」と明細を焼き付ける。改定は「新しい版を作る → 内容を詰める → 有効化する」の3手。
| テーブル | 列 | 役割 |
|---|---|---|
price_books | id / name / currency / effective_from / is_active / status(draft·active·archived) / note / created_by / created_at | 版。currency は当面 JPY 固定だが列は持つ(将来USD) |
price_type_rates | book_id / type_code / base_fee / charter_per_day / hourly_domestic / hourly_intl / overseas_ops_fee / early_fee / late_fee / is_internal / is_public | 型式ごとの単価。型式を足す=1行足す。2つの公開フラグで「社内では見積れるが外には出さない」を作れる |
price_zones | book_id / zone_code / name / sort | 遠域ゾーンの定義。ここを増やすのが「適宜追加」の実体 |
price_zone_rates | book_id / zone_code / type_code / remote_fee / facility_fee | ゾーン × 型式の金額。CJ4のみ設定(C510は「—」)も表現できる |
price_airport_fees | book_id / icao / transfer_fee / zone_code | 空港ごとの送迎料金と所属ゾーン。未登録の空港は 0円・ゾーンなしで落ちる(=警告対象) |
price_rules | book_id / tax_rate / time_basis / rounding_unit_min / rounding_scope / rounding_mode / amount_round_unit / amount_round_mode / early_before / late_after | 税率・課金時間・金額の丸め。確定値は air / 5 / leg / ceil + 金額は floor / 単位 1000 |
price_audit | id / book_id / actor / action / diff_json / at | 誰がいつ何を変えたか。権限は後回しでも記録は最初から |
仮フェーズは D1 を作らず KV の JSON 1本で始める
- companyapps には既に KV バインド(
COMPARISON_CACHE)があり、航空路マップの手動経路が同じパターンで既に乗っている(/api/routes-local)。同じ形で/api/pricing-paramsを足せば、新しいリソースを一切作らずにページから編集・保存ができる。 - JSON の構造は上の7テーブルと1対1にしておく。本体化のとき流し込むだけになる。
// KV: key = pricing-params (本体化後は上のテーブルに1:1で写る) { "book": { "id": "2026-04", "name": "2026年度 標準", "currency": "JPY", "effective_from": "2026-04-01", "is_active": true, "status": "active" }, "rules": { "tax_rate": 0.10, "time_basis": "air", // 空中ETE(ブロックではない) "rounding_unit_min": 5, // 5分 "rounding_scope": "leg", // LEGごと "rounding_mode": "ceil", // 切り上げ "techran": "ignore", // 燃料度外視の直行で計算 "amount_round_unit": 1000, // 飛行料金の丸め単位=1,000円(HP準拠) "amount_round_mode": "floor", // 切り捨て。丸めてから貸切に充当する "early_before": "08:59", "late_after": "21:00" }, "types": { "C510": { "label": "Mustang", "base_fee": 700000, "charter_per_day": 600000, "hourly_domestic": 400000, "hourly_intl": 500000, "overseas_ops_fee": 250000, "early_fee": 280000, "late_fee": 280000, "is_internal": true, "is_public": true }, "C25C": { "label": "CJ4", "base_fee": 1050000, "charter_per_day": 750000, "hourly_domestic": 600000, "hourly_intl": 700000, "overseas_ops_fee": null, "early_fee": 280000, "late_fee": 280000, "is_internal": true, "is_public": true } // 事業機化が未定の型式を足すときは is_internal:true / is_public:false で入れる }, "zones": [ { "code": "HKD", "name": "北海道", "rates": { "C510": {"remote":120000}, "C25C": {"remote":200000} } }, { "code": "AMAMI","name": "奄美以南", "rates": { "C510": {"remote":200000}, "C25C": {"remote":320000} } }, { "code": "OKA_S","name": "那覇以南", "rates": { "C510": {"remote":350000}, "C25C": {"remote":520000} } }, { "code": "TW", "name": "台湾", "rates": { "C510": {"remote":500000,"facility":650000}, "C25C": {"remote":750000,"facility":650000} } }, { "code": "KR", "name": "韓国", "rates": { "C510": {"remote":250000,"facility":500000}, "C25C": {"remote":350000,"facility":500000} } }, { "code": "GUM", "name": "グアム・サイパン","rates": { "C25C": {"remote":750000,"facility":500000} } }, { "code": "HKG", "name": "香港", "rates": { "C25C": {"remote":1300000,"facility":1500000} } }, { "code": "MFM", "name": "マカオ", "rates": { "C25C": {"remote":1300000,"facility":550000} } } ], "airports": { "RJCC": { "transfer": 120000, "zone": "HKD" }, "RJTT": { "transfer": 120000 }, "RJGG": { "transfer": 150000 }, "ROAH": { "transfer": 120000, "zone": "OKA_S" } } }
ゾーン割当の漏れ対策。空港が増えるほど「ゾーンを割り当て忘れて静かに安くなる」事故が起きやすい。対策を2つ入れる。
① 設定ページに 「マスタにあるがゾーン未割当の空港」一覧 を常設する。
② 見積時、国内でない空港(country_code <> 'JP')にゾーンが無い場合は警告を返す。海外は必ずどこかのゾーンに属するはずなので、これで取りこぼしを拾える。
型式ごとの公開フラグ(2つ持つ)
is_internal… 社内見積・予約管理・各ポータルで計算してよいかis_public… HPの公開APIに出してよいか- 新しい型式は internal のみ ON で投入し、値付けを検証してから public を立てる。事業機化が未定の機体を外に出さない栓になる
- 版とは独立。改定の版を切っても公開状態はその版の設定に従う
master の「事実」とは分ける
- 就航開始日
aircraft.service_start、機体の有効aircraft.is_active、国際運航の認可type_intl_rulesは master が持つ事実。料金側では持たない(二重管理になる) - 料金側のフラグは 「料金を出してよいか」という意思だけを表す
- 見積が通る条件は master の事実 AND 料金側のフラグ。どちらで弾かれたかを理由として返す
// 見積(本体。将来HP・予約管理・各ポータルが叩く) POST /api/pricing/quote { "type_code": "C510", "legs": [ { "date": "2026-08-20", "from": "RJTT", "to": "RJOO", "dep_time": "09:00" }, { "date": "2026-08-22", "from": "RJOO", "to": "RJTT", "arr_time": "17:00" } ], "days": ["2026-08-20","2026-08-21","2026-08-22"], // 省略時はLEGの初日〜最終日 "options": { "early_departure": null, "late_arrival": null }, // null=時刻から自動判定 "price_book": null, // null=いま有効な版 "flight_minutes": null // 指定すればコアを呼ばずその値で計算(版比較・実績精算用) } → { "price_book": "2026-04", "currency": "JPY", "lines": [ { "code":"base", "label":"基本料金", "qty":1, "unit":700000, "amount":700000, "src":"types.C510.base_fee" }, { "code":"flight", "label":"飛行料金", "qty":2.083, "unit":400000, "amount":833000, "src":"types.C510.hourly_domestic" }, { "code":"charter", "label":"貸切料金", "qty":3, "unit":600000, "amount":967000, "src":"types.C510.charter_per_day" }, { "code":"transfer", "label":"空港内送迎", "qty":1, "unit":120000, "amount":120000, "src":"airports.RJTT.transfer" } ], "subtotal": 2620000, "tax": 262000, "total": 2882000, "meta": { "legs":[{"from":"RJTT","to":"RJOO","air_min":62,"billed_min":65}], "warnings": [] } } // パラメータ(設定ページが使う。書き込みは将来 社内認証必須) GET /api/pricing/params // いま有効な版 GET /api/pricing/params?book=2025-04 PUT /api/pricing/params // 版ごと差し替え(版を切らずに上書きはさせない) POST /api/pricing/books/:id/activate // 有効化(他の版の is_active を落とす) GET /api/pricing/books
設計上の約束
- エンジンは定価だけを返す。代理店割引・キックバックは代理店ポータル側の管理。割引率がエンジンに入ると社外公開できなくなる
- 1件=1リクエスト。まとめ/分けの比較は呼び出し側がN回叩いて比べる
- 飛行時間は差し込める。
flight_minutesを渡せる形にしておくと、版どうしの比較も実績時間での再計算もできる - 合計0は必ずエラー。いまのHPスクレイプの「静かに0円」を繰り返さない
- 見積を保存する側が
price_bookとlinesを丸ごと持つ。あとで料金が改定されても請求額が動かない
公開(HP)向けの追加
- APIキー + レート制限(未認証の公開口になるため)
- CORS を刷新後HPのオリジンに限定
- 公開版では
src(パラメータの出所)を落とす - 問い合わせ導線に使うので、計算不能でも理由を返す(運航不可空港・型式未設定・国際運航の認可制約など)
ここは 「Worker(API)をどこに置くか」と「D1(パラメータ)をどこに置くか」を別々に決められるのが要点。D1 は Service Binding を挟まなくても複数の Worker から直接バインドできるので、「APIは独立・データはmasterのDBに同居」という組み合わせが取れる。
D1 は mcj-master-prod に相乗り(price_* テーブル群)
- パラメータの半分(空港ごとの送迎料金・遠域ゾーン所属)は事実上「空港の属性」。
airportsと同じDBにある方が素直で、ゾーン割当漏れの検出が1クエリで書ける - master には既に
aircraft_types(型式諸元)という商売寄りの値も入っている。料金だけ別DBにする強い理由がない - 新規D1がゼロ。Free プランはアカウント全体で10個上限で、既に到達した経緯がある
- 守るルール:テーブル接頭辞
price_で所有を明示し、書き込みは料金Workerだけ。master worker は price_* を触らない
Worker は独立(mcj-pricing-api)
- 公開トラフィックを master に流したくない。master は社内の単一情報源で、落ちると全社が止まる。HPからの未認証アクセスは別Workerで受けてレート制限をかける
- 社外公開(HP)と社内利用で必要な保護が違うのを、1か所で設計しきれる
/rc/のCGI廃止の受け皿になる- 予約管理に置かない理由:あそこは 「/api/* 既定拒否+公開許可リスト」 の認証設計で、未認証の公開口と相性が悪い
price_* テーブルへ流し込むだけになるよう、構造を1対1に保っておく。| # | 論点 | 決定 | 効いてくるところ |
|---|---|---|---|
| 1 | 課金する飛行時間の定義と丸め | 空中ETE(風・空港ファクター込み)を LEGごとに5分切り上げ。ブロックは使わない。往復非対称はそのまま出す | 4章の式。rules.time_basis=air / unit=5 / scope=leg / mode=ceil |
| 2 | テクランの扱い | 考慮しない。燃料度外視で直行したときの空中ETEで計算 | コアは ete() だけ呼ぶ。assessItinerary() は使わない(5章) |
| 3 | 連続5日以上の値付け | 問題ない。むしろ伸ばしたい | HPの4日上限に由来する hp_days ブロックを撤廃(12章 Phase4) |
| 4 | 割引をエンジンに入れるか | 入れない。代理店ポータル等で別管理。エンジンは基本の計算のみ | 8章「定価だけを返す」。公開APIにそのまま出せる |
| 5 | 多通貨 | いまはJPYのみ。将来USDを実装する | price_books.currency 列だけ先に持つ(6章) |
| 6 | 遠域ゾーンの帰属 | 空港ごとに選ぶ。海外運航開始で空港もゾーンも増える前提 | ゾーン追加+割当のUI、割当漏れの検出2種(6章) |
| 7 | 版と再現性 | 見積時点の額がそのまま請求額。版管理+有効化フラグを持つ | price_books.is_active、見積側に price_book と明細を焼き付け(8章) |
| 8 | 編集権限・監査 | 最初は権限不要。いずれ挟む(管理方法は別途) | price_audit は最初から記録。認証は後付けできる形にしておく |
| 9 | 本体の置き場所 | いまは companyapps。本格運用時に切り離す。パラメータD1は master に相乗り | 9章。mcj-pricing-api Worker + mcj-master-prod の price_* |
| 10 | 切替の合格基準 | HPとの合致は問わない(料金変更を予定)。companyapps 内で十分検証してから公開へ | 13章。検証は「HP再現」から「版どうしの差分確認」へ |
| A | 金額の端数 | 1,000円未満切り捨て。丸めてから貸切に充当(HP実挙動と同じ順序) | 4章の floorN。rules.amount_round_unit=1000 / mode=floor |
| B | 時刻未定のときの早朝・深夜 | 時刻が入力されていなければ加算しない | 内訳に「時刻未定のため未計上」と出す |
| C | 風補正に使う月 | 各LEGの運航日の月。運航日未定なら当月 | コア呼び出し時の month |
| D | 飛行単価②の判定範囲 | LEG単位。旅程全体のどこかが海外なら②、という判定にするなら再検討 | 4章の式に明記 |
| E | 料金表にない型式 | 型式ごとに is_internal / is_public の2フラグを持つ。事業機化が未定なら公開しない | 6章。master の事実(就航開始・認可)とは分けて管理 |
| F | 改定の中身 | まずは現行のままのパラメータで作る。改定は次の版で | 12章 Phase2。エンジンは値を持たないので改定を待たずに実装できる |
| G | 遠域の数え方 | 実質フェリー料金なので一連の発地と最終着陸地のみ。同じ空港でも重複排除しない(2026-08-13 確定) | 4章の式。切替パラメータは持たない(誤設定で請求が狂うため) |
| H | CJ4の海外運航料金 | Mustangと同額 250,000円/件。HPの表が結合セルだった(2026-08-13 確定) | 3章の表。types.C25C.overseas_ops_fee |
HP準拠の1,000円未満切り捨てとする。丸めてから貸切料金に充当する順序も同じ(4章の実測表)。いまの見積書と桁の見え方が変わらない。羽田→大島なら 166,666.67 → 166,000。
単位は rules.amount_round_unit のパラメータなので、あとから100円に変えることもできる(版を切れば過去の見積は動かない)。
- B 時刻未定の早朝・深夜 … 加算しない。内訳に「時刻未定のため未計上」と出す。
- C 風補正の月 … 各LEGの運航日の月。運航日未定なら当月。
- D 飛行単価②の判定 … LEG単位。旅程全体で判定する運用になったら再検討。
- E 型式の公開 …
is_internal/is_publicの2フラグ(6章)。事業機化が未定なら公開しない。 - F 改定の中身 … まずは現行のままのパラメータで作る。改定は次の版で。
companyapps で作る
パラメータ設定(KVのJSON)+シミュレーション。飛行時間は同一Pages内の /flight-calc/flight-calc.js を読む(コピーを増やさない)。
本番影響ゼロ・既存経路に触らない
現行料金を版として投入
現行のままのパラメータを「2026-04 標準」として入れ、代表ケースを回して内訳の妥当性を確認。HPと突き合わせるのは参考まで。
ここで料金改定の議論の土台ができる
mcj-pricing へ切り出す
Worker化+パラメータを mcj-master-prod の price_* へ。同PRで flight-calc を shared/ に集約し3コピーを解消。
要 高橋相談(新Worker・masterへのmigration)
社内の見積を載せ替える
予約管理の charterQuoteHandler を mcj-shift のHPスクレイプから mcj-pricing の Service Binding へ差し替え。4日上限のブロックを外す。
本番影響あり・段階切替+差分監視
HPに公開APIを出す
刷新後HPが叩く公開口(APIキー・レート制限・CORS)。ここまで来ると /rc/ のCGIが不要になる。
HP側の進行と歩調を合わせる
後片付け
mcj-shift/hp-calculator.ts・mcj-quote/pricing.ts・空き確認画面の概算モデルを撤去。料金の実装を1本にする。
残していると必ず食い違う
HPとの一致を条件にしないので、検証の軸は2つになる。①内訳が式どおりに積み上がっているか(回帰)と、②版を変えたときに金額がどう動くか(差分)。②はそのまま 料金改定の検討ツール になる。
① 回帰 — 代表ケースを固定
- 飛行時間を固定値で差し込み(
flight_minutes)、パラメータを変えていないのに金額が動いたら落ちる、という形にする - ケースは「単発 / 連続2日 / 中日1日 / 中日2日 × 近距離・遠距離・遠域あり」+連続7日(HPでは作れなかった形)+海外発着
- 非線形の確認:羽田発着の往復1件なら遠域0回、片道2件に割ると各1回。遠域が起終点なら往復ぶん2回
② 差分 — 版どうしの比較
- 同じケース集合を「現行 2026-04」と「改定案」で流し、1件ずついくら変わるかの一覧を出す
- 影響の大きい順に並べれば、改定の議論がそのまま数字でできる
- 飛行時間の定義変更(空中ETE・5分切り上げ)による増減も、この形で1回だけ測っておく
C510 羽田⇄伊丹 単発×2件 3,124,000 / 連続2日 2,222,000 / 中日1日 2,882,000 ・・・ CJ4 羽田⇄新千歳 単発×2件 5,148,000 / 連続2日 3,289,000 / 中日1日 4,114,000。中日1日ぶんの増分は C510 660,000・CJ4 825,000(=貸切料金/日 ×1.1)で一定。