セッション料金
HandyCafeはインターネットカフェやゲーミングセンターのセッション費用を計算するためにセグメントベースの料金エンジンを使用します。セッション全体に単一の定額料金を適用するのではなく、各セッションをセグメントに分割し、それぞれに固有の料金コンテキストを持たせます。このアプローチにより、セッションが複数の時間スロット、料金変更、一時停止、切断をまたぐ場合でも正確な課金が保証されます。
基本概念
詳細に入る前に、主要な用語を確認します。
| 用語 | 定義 |
|---|---|
| 基本時間単価 | 倍率適用前の1時間あたりの料金。設定 > 料金設定で設定します。 |
| 料金スロット | 特定の倍率を持つ名前付きの時間帯。8つのスロットがあり、それぞれ色分けされています。 |
| 倍率 | 基本料金に適用される係数。1.0 = 標準料金、0.5 = 半額、2.0 = 2倍。 |
| セグメント | 料金コンテキスト(スロット、倍率、基本料金)が変わらないセッション内の連続期間。 |
| 精算 | セッション終了時に顧客の支払い額を決定する最終計算。 |
基本時間単価
基本時間単価はすべての料金計算の基盤です。設定 > 料金設定で設定し、PC使用1時間あたりの標準料金を表します。
内部計算はすべて最小通貨単位で行われます(たとえばUSDではセント、JPYでは円)。基本料金が1時間あたり300円の場合、内部値は300です。これにより浮動小数点の丸め問題が解消されます。
デュアル通貨サポート
HandyCafeは基本通貨とローカル通貨を為替(FX)レートとともにサポートします。国際料金がローカル料金と異なる国で運営している場合:
- 基本通貨 内部の料金計算に使用される通貨。
- ローカル通貨 顧客に表示され、支払いに使用される通貨。
- FXレート 基本通貨とローカル通貨間の変換係数。
両方の通貨が同じ場合、FXレートは1.0として扱われ、影響しません。
料金スロット
8つの色分けされた料金スロットがあり、それぞれ異なる料金ティアを表します。
| スロット | 色 | 一般的な用途 |
|---|---|---|
| Blue | 青 | 標準料金 |
| Orange | オレンジ | 夜間・週末割増 |
| Red | 赤 | ピーク時間帯プレミアム |
| Green | 緑 | オフピーク割引 |
| Teal | ティール | 学生・メンバー料金 |
| Gray | グレー | 祝日・特別料金 |
| Cyan | シアン | 深夜料金 |
| Emerald | エメラルド | プロモーション料金 |
各スロットには3つのプロパティがあります。
- 名前 わかりやすいラベル(たとえば「ピーク時間帯」「深夜割引」)。
- 倍率 基本料金を変更する10進数値。一般的な値は1.0(標準)、0.5(半額)、1.5(50%割増)、2.0(2倍)です。倍率はゼロまたは正の値である必要があります。
- スケジュールデータ スロットが適用される曜日と時間帯を定義する内部表現。スケジュールグリッドを通じて自動的に管理されます。
スロットは個別に有効化・無効化できます。無効化されたスロットは料金エンジンに無視されます。
スケジュールグリッド
料金スケジュールは7日間 x 24時間のマトリクス(合計168の1時間ブロック)です。各ブロックは1つの料金スロットに割り当てられます。スケジュールにより、任意の時点でどの倍率が適用されるかが決定されます。
グリッドは設定 > 料金スケジュールで設定します。曜日は月曜日から日曜日、時間は00:00から23:00まで表示されます。時間ブロックにスロットを割り当てるには、グリッド上のブロックを選択して目的のスロットカラーを選びます。
エンジンのスケジュール読み取り方法
内部的には、各時間ブロックがスケジュールデータ内の位置にマッピングされます。エンジンは各有効なスロットのスケジュールデータを確認し、任意の曜日と時間帯にどのスロットがアクティブかを判定します。
指定された時間帯にどのスロットもビットが設定されていない場合、エンジンは倍率1.0の基本料金にフォールバックします。
料金スケジュール機能自体が無効化されている場合(設定 > 料金設定)、すべてのセッションは時間に関係なく基本料金と倍率1.0を使用します。
料金セグメント
セグメントは、料金コンテキストが変わらないセッション内の連続時間帯です。料金エンジンは以下の境界イベントのいずれかが発生するたびに新しいセグメントを作成します。
| 境界 | トリガー |
|---|---|
| session_start | 新しいセッションの開始 |
| session_stop | セッションの停止 |
| pause | キャッシャーがセッションを一時停止 |
| resume | キャッシャーがセッションを再開 |
| tick | 時計が異なる料金スロットの時間境界を越えた |
| disconnect | クライアントPCがネットワーク接続を失った |
| offline | クライアントPCがオフラインになった |
| load_recovery | サーバーが再起動し実行中のセッションを回復 |
各セグメントは以下を記録します。
| フィールド | 説明 |
|---|---|
| session_id | このセグメントが属するセッション |
| segment_start | セグメント開始のUnixタイムスタンプ |
| segment_end | セグメント終了のUnixタイムスタンプ(開いている場合はnull) |
| pricing_slot_id | アクティブな料金スロットのID(例: "blue"、"red"、"base") |
| multiplier | 料金スロットの倍率値 |
| base_price_snapshot | セグメント開始時点でキャプチャされた基本時間単価 |
| amount | このセグメントの計算費用(セグメント終了時に設定) |
| boundary_reason | このセグメントが作成された理由 |
基本料金のスナップショットが必要な理由
base_price_snapshotはセグメント開始の正確な時点での基本時間単価をキャプチャします。管理者がセッション中に基本料金を変更する可能性があるため、これは重要です。スナップショットにより、各セグメントは開始時点で有効だった料金を使用し、公正で監査可能な課金を保証します。
費用計算式
1つのセグメントの費用は以下のように計算されます。
amount = ceil( (base_price_snapshot * multiplier * duration_seconds) / 3600 )
より正確には、エンジンは浮動小数点エラーを回避するためにスケーリングされた整数演算を使用します。
- 倍率は固定小数点整数にスケーリングされます(1,000,000を乗算)。
- 計算は完全に128ビット整数で実行されます。
- 切り上げ除算が使用されます。結果は常に次の最小通貨単位に切り上げられます。
分単位計算
設定 > 料金設定で「分単位で計算」オプションが有効になっている場合、計算式が少し変わります。
amount = ceil( (base_price_snapshot * multiplier * used_minutes) / 60 )
ここでused_minutes = ceil(duration_seconds / 60)です。つまり、1分未満の端数は1分としてカウントされます。
セッション合計の計算
セッション合計費用は3つのステップで計算されます。
ステップ1: 全セグメントの合計
raw_total = すべての終了済みセグメント金額の合計 + 開いているセグメントの部分金額
ステップ2: 丸めの適用
rounded_total = round_up(raw_total, rounding_step)
丸めは常に切り上げ(天井値)で、売上を保護します。
ステップ3: 開始料金の最低額適用
final_total = max(rounded_total, startup_fee)
開始料金はセッションの長さに関係なく適用される最低料金です。
精算
精算はセッションの課金を確定するプロセスです。2つの精算段階があります。
開始精算(前払いのみ)
前払いセッションが開始されると、「開始」精算レコードが作成されます。
停止精算
セッション(前払いまたは後払い)が停止されると、「停止」精算レコードが作成され、計算費用、請求額、手動調整額、手数料、手数料固定費、料金セグメントのタイムラインスナップショットが記録されます。
消費税
消費税は設定 > 料金設定でパーセンテージ(0~100%)として設定されます。計算されたセッション金額に上乗せされます。
消費税 = 請求額 x (消費税率 / 100)
次のステップ
- セッション管理: セッションのライフサイクル全体を学ぶ
- 設定: 料金設定: 基本料金、丸め、開始料金の設定
- 設定: 料金スケジュール: 7 x 24スケジュールグリッドの設定
- 支払い方法: 手数料と費用付きの支払い方法を設定