コンテンツにスキップ

旧システム価格処理アルゴリズム

概要

このドキュメントは、リツビBtoB ECサイトの旧システムにおける価格処理アルゴリズム(price_chk()関数)の詳細な仕様を記録したものです。新システム(Vendure + Next.js)への移行において、既存の価格計算ロジックを正確に再現するための参考資料として使用されます。

関数仕様

1. メイン価格計算関数

関数名

price_chk()

目的

商品の最終価格を計算するメイン関数

引数

  • $item_num: 商品番号(8桁ゼロパディング文字列としてDBに格納)
  • $CompanyID: 顧客ID(6桁ゼロパディング文字列としてDBに格納)
  • $tmp_cnt: 商品数量
  • $set_cnt: 複数商品を1つの商品として扱う際の価格計算用数量
  • $special_price_OK: 価格制御フラグ

2. セット商品価格計算関数

関数名

price_chk_campain()

目的

BtoB発注システム内で作成された独自のセット商品の価格を取得するためのラッパー関数

引数

price_chk()関数と同じ引数を使用

処理概要

  • BtoB発注システム内の仮の商品番号毎に分岐
  • セットに含まれている各商品毎の価格を取得し合計した値を返す
  • セット商品は複数の個別商品を組み合わせた仮想的な商品

実装例(C25062B2セット)

case "C25062B2":
    // 商品番号80451の価格を取得
    $tmp = price_chk(80451, $conn, $CompanyID, $tmp_cnt, $set_cnt, $special_price_OK);

    // 商品番号80453の価格を取得して加算
    $tmp += price_chk(80453, $conn, $CompanyID, $tmp_cnt, $set_cnt, $special_price_OK);

    // 商品番号80438の価格を取得して加算
    $tmp += price_chk(80438, $conn, $CompanyID, $tmp_cnt, $set_cnt, $special_price_OK);

    return $tmp; // 合計金額を返す
    break;

セット商品の特徴

  • 仮想商品: BtoBシステム内でのみ使用される独自のセット識別子
  • 複数商品構成: 1つのセットに複数の実際の商品が含まれる
  • 価格合計: 各構成商品の価格をprice_chk()で取得し、合計値を返す
  • 動的計算: セット構成商品の価格が変更されても自動的に反映される

3. カート表示前価格調整ロジック

処理概要

カート表示処理実行時に、対象商品の価格を調整する前処理ロジック

対象顧客・商品

  • 対象顧客: ユーザー直送モード以外の顧客
  • 対象商品: Mesosutical小売商品、Rcodeライン商品

ビジネスルール

Mesosutical小売商品の価格ルール
  • 対象顧客: 「Mesosutical Premium A~E」グループ、または個別設定でPremiumグループに近い価格帯の顧客
  • 条件: 12個単位での購入時のみ特別価格を適用
  • 例外: 12個未満の場合は商品マスタの定価で販売
  • 実装: price_chk関数内で処理
Rcodeライン商品の例外ルール
  • 例外条件: Rcodeライン商品は上記ルールの例外
  • 24個条件: 24個以上の注文時は特別価格を適用(12個条件を満たさなくても)
  • 単一数量条件の詳細:
  • 24個未満でも、price_chk関数で計算された価格が商品マスタの定価より安い場合は特別価格を適用
  • これは、顧客別価格設定や数量別価格設定により、少数注文でも特別価格が適用される場合を考慮
  • 例: Premium顧客で1個から特別価格設定がされている場合
SMILEシステム連携
  • 制約: SMILEシステムでは上記価格ルールを制御できない
  • 設定: SMILEシステムでは各顧客に対して1個から特別価格を反映するよう設定

チェック変数設定フロー

flowchart TD
    A[対象顧客かつユーザー直送モードでない場合] --> B[対象商品の注文個数合計を算出]
    B --> C{合計数が1以上?}

    C -->|No| D[Premiumだけど1個から特別価格の顧客?]
    C -->|Yes| E{商品カテゴリは?}

    E -->|Mesosutical小売商品| F{合計数が12以上?}
    E -->|Rcodeライン商品| G{合計数が24以上?}
    E -->|その他| D

    F -->|Yes| H[チェック変数$line_206_chkに2を入力<br/>特別価格適用]
    F -->|No| I[チェック変数$line_206_chkに1を入力<br/>定価適用]

    G -->|Yes| H
    G -->|No| J{Premium顧客で<br/>1個から特別価格?}

    J -->|Yes| H
    J -->|No| I

    D -->|Yes| H
    D -->|No| K[チェック変数$line_206_chkに0を入力<br/>デフォルト処理]

    H --> L[カート表示処理へ]
    I --> L
    K --> L

カート表示時の価格決定

flowchart TD
    A[カート表示処理中] --> B{該当商品?}
    B -->|Yes| C{$line_206_chk == 1?}
    B -->|No| D[通常処理]

    C -->|Yes| E[商品マスタから定価を取得してカート内価格を上書き]
    C -->|No| F{$line_206_chk == 2?}

    F -->|Yes| G[price_chk関数で価格を取得しカート内価格を上書き]
    F -->|No| H[デフォルト価格処理]

    E --> I[カート表示完了]
    G --> I
    H --> I

チェック変数の意味

  • $line_206_chk = 0: デフォルト価格(特別価格なし)
  • $line_206_chk = 1: 商品マスタ定価を適用(特別価格条件を満たさない)
  • $line_206_chk = 2: price_chk関数による特別価格を適用(特別価格条件を満たす)

価格計算フロー

フローチャート

flowchart TD
    A[price_chk関数開始] --> B[基本商品数量計算<br/>$price_cnt = $tmp_cnt * $set_cnt]
    B --> C[基本価格取得<br/>$item_price, $item_end_price]
    C --> D{$special_price_ok == 0?}

    D -->|Yes| E[ユーザー直送モード判定1]
    D -->|No| F[数量の一時調整<br/>ボーナス商品対応]

    F --> G[数量別価格適用<br/>一般]
    G --> H[顧客マスタ検索<br/>$CompanyID]
    H --> I{顧客グループ存在?}

    I -->|Yes| J[グループ価格適用<br/>価格マスタ]
    I -->|No| K[顧客個別価格適用<br/>価格マスタ]

    J --> L[グループ価格適用<br/>数量別価格マスタ]
    K --> M[顧客個別価格適用<br/>数量別価格マスタ]

    L --> N[数量の復元]
    M --> N
    N --> E

    E --> O{ユーザー直送モード?}
    O -->|Yes| P[システム利用料追加<br/>$item_price += $item_end_price / 10]
    O -->|No| Q[ユーザー直送モード判定2]

    P --> R[最終価格計算<br/>$final_price = $item_price * $price_cnt]

    Q --> S{ユーザー直送モード?}
    S -->|Yes| T{RCODE配分対象<br/>AND 12個未満?}
    S -->|No| R

    T -->|Yes| U[商品マスタ価格で上書き]
    T -->|No| V[システム利用料追加<br/>$item_price += $item_end_price / 10]

    U --> R
    V --> R
    R --> W[価格返却]

1. 基本商品数量の計算

$price_cnt = $tmp_cnt * $set_cnt

説明: BtoBシステムにおける商品バンドル(例:「11+1」「3+1」)を処理するための基本数量を計算します。

2. 基本価格の取得

商品マスタから以下の価格を取得:

  • $item_price: 標準販売価格(単品)
  • $item_end_price: エンドユーザー販売価格(単品)

3. 特別価格制御フラグの判定

$special_price_ok == 0 の場合:

  • 顧客別価格を使用しない
  • 直接「ユーザー直送モード」判定に進む

$special_price_ok != 0 の場合:

  • 顧客別・数量別価格調整を実行

3.1 数量の一時調整

ボーナス商品(「11+1」「23+1」等)の場合、数量を一時的に調整:

  • 12個または24個に調整($special_price_okの値に基づく)

3.2 数量別価格の適用(一般)

数量別価格マスタに該当商品の価格が設定されている場合:

  • $item_priceを数量別価格で上書き

3.3 顧客マスタの検索

$CompanyIDを使用して顧客マスタを検索

3.4 顧客グループの判定

顧客が顧客グループに属している場合:

グループ価格の適用:

  • 価格マスタ: 商品×顧客グループの価格で$item_priceを上書き
  • 数量別価格マスタ: 商品×顧客グループの価格で$item_priceを上書き

顧客が顧客グループに属していない場合:

顧客個別価格の適用:

  • 価格マスタ: 商品×顧客個別の価格で$item_priceを上書き
  • 数量別価格マスタ: 商品×顧客個別の価格で$item_priceを上書き

3.5 数量の復元

ボーナス商品の場合、一時的に調整した数量を元に戻す

4. ユーザー直送モードの判定(第1回目)

現在の取引が「ユーザー直送モード」の場合:

  • システム利用料を追加: $item_price += $item_end_price / 10
  • 最終価格計算に進む

5. ユーザー直送モードの判定(第2回目)

現在の取引が「ユーザー直送モード」の場合:

5.1 RCODE配分対象商品の判定

  • RCODE配分対象商品 AND 購入数量が12個未満の場合:
  • $item_priceを商品マスタの価格で上書き
  • それ以外の場合:
  • システム利用料を追加: $item_price += $item_end_price / 10

6. 最終価格の計算

$final_price = $item_price * $price_cnt

重要なビジネスルール

顧客別価格制御

  • 顧客グループ優先: 個別顧客価格よりグループ価格が優先される
  • 数量別価格: 一般数量別価格 → グループ数量別価格 → 個別数量別価格の順で適用

ユーザー直送モード

  • システム利用料: エンドユーザー販売価格の10%を追加
  • RCODE配分対象商品の特別処理: 12個未満の場合はシステム利用料を適用しない

商品バンドル処理

  • 「11+1」「23+1」等のボーナス商品に対応
  • 数量計算時の一時調整により正確な価格計算を実現

データベーステーブル構造(推測)

商品マスタ

  • item_num: 商品番号(8桁)
  • item_price: 標準販売価格
  • item_end_price: エンドユーザー販売価格

顧客マスタ

  • CompanyID: 顧客ID(6桁)
  • customer_group: 顧客グループ

価格マスタ

  • item_num: 商品番号
  • CompanyID: 顧客ID(個別価格用)
  • customer_group: 顧客グループ(グループ価格用)
  • price: 設定価格

数量別価格マスタ

  • item_num: 商品番号
  • CompanyID: 顧客ID(個別価格用)
  • customer_group: 顧客グループ(グループ価格用)
  • quantity: 数量
  • price: 設定価格

新システム移行時の考慮事項

Vendureプラグイン実装

  1. 価格計算プラグイン: 既存の価格計算ロジックをVendureプラグインとして実装
  2. 顧客グループ管理: VendureのCustomerGroup機能を活用
  3. 数量別価格: VendureのPromotion機能またはカスタムプラグインで実装
  4. ユーザー直送モード: カスタムフィールドと価格計算ロジックの組み合わせ
  5. セット商品管理: VendureのProductVariant機能とカスタムフィールドで実装
  6. セット商品をProductVariantとして定義
  7. 構成商品をカスタムフィールドで管理
  8. 価格計算時に構成商品の価格を動的に合計
  9. カート表示前価格調整: VendureのPromotion機能とカスタムプラグインで実装
  10. 顧客グループ別の価格ルールをPromotionで管理
  11. 数量条件に基づく価格切り替えロジック
  12. 商品カテゴリ別の特別価格ルール(Mesosutical、Rcode)

データ移行

  • 既存の価格マスタデータをVendureのProductVariantPriceに移行
  • 顧客グループ情報をVendureのCustomerGroupに移行
  • 数量別価格をカスタムテーブルまたはVendureのPromotion機能で管理
  • セット商品情報をVendureのProductVariantとカスタムフィールドに移行
  • セット識別子(C25062B2等)をProductVariantのSKUとして設定
  • 構成商品リストをカスタムフィールドで管理
  • カート表示前価格調整ルールをVendureのPromotion機能に移行
  • 顧客グループ別価格ルールをPromotionとして設定
  • 商品カテゴリ別の特別価格条件をPromotion条件で管理
  • 数量条件に基づく価格切り替えロジックを実装

テストケース

  • 各価格計算パターンのテストケース作成
  • 顧客グループ別価格の動作確認
  • ユーザー直送モードの料金計算確認
  • 商品バンドルの価格計算確認
  • セット商品の価格計算確認
  • セット構成商品の個別価格計算
  • セット合計価格の正確性
  • セット商品の数量計算
  • カート表示前価格調整の動作確認
  • 顧客グループ別価格ルールの適用確認
  • 数量条件に基づく価格切り替えの動作確認
  • 商品カテゴリ別特別価格ルールの適用確認
  • チェック変数($line_206_chk)の設定確認

価格計算例

例1: 通常の顧客別価格計算

商品番号: 12345678
顧客ID: 000001
数量: 10個
$set_cnt: 1
$special_price_ok: 1

処理フロー:
1. $price_cnt = 10 * 1 = 10
2. 基本価格取得: $item_price = 1000円, $item_end_price = 1200円
3. 顧客個別価格適用: $item_price = 900円(顧客別価格)
4. ユーザー直送モード: なし
5. 最終価格 = 900円 * 10 = 9,000円

例2: ユーザー直送モード(システム利用料追加)

商品番号: 12345678
顧客ID: 000001
数量: 5個
$set_cnt: 1
$special_price_ok: 1
ユーザー直送モード: 有効

処理フロー:
1. $price_cnt = 5 * 1 = 5
2. 基本価格取得: $item_price = 1000円, $item_end_price = 1200円
3. 顧客個別価格適用: $item_price = 900円
4. ユーザー直送モード: システム利用料追加
   $item_price = 900円 + (1200円 / 10) = 900円 + 120円 = 1020円
5. 最終価格 = 1020円 * 5 = 5,100円

例3: 商品バンドル(11+1)の価格計算

商品番号: 87654321(11+1商品)
顧客ID: 000002
数量: 12個
$set_cnt: 11
$special_price_ok: 12

処理フロー:
1. $price_cnt = 12 * 11 = 132
2. 基本価格取得: $item_price = 500円, $item_end_price = 600円
3. 数量の一時調整: 12個 → 12個($special_price_ok = 12)
4. 数量別価格適用: $item_price = 450円(12個用価格)
5. 顧客グループ価格適用: $item_price = 400円(グループ価格)
6. 数量の復元: 12個のまま
7. ユーザー直送モード: なし
8. 最終価格 = 400円 * 132 = 52,800円

例4: RCODE配分対象商品の特別処理

商品番号: 11111111(RCODE配分対象)
顧客ID: 000003
数量: 10個(12個未満)
$set_cnt: 1
$special_price_ok: 1
ユーザー直送モード: 有効

処理フロー:
1. $price_cnt = 10 * 1 = 10
2. 基本価格取得: $item_price = 800円, $item_end_price = 1000円
3. 顧客個別価格適用: $item_price = 750円
4. ユーザー直送モード判定1: システム利用料追加
   $item_price = 750円 + (1000円 / 10) = 850円
5. ユーザー直送モード判定2: RCODE配分対象かつ12個未満
   $item_price = 800円(商品マスタ価格で上書き)
6. 最終価格 = 800円 * 10 = 8,000円

例5: セット商品(C25062B2)の価格計算

セットID: C25062B2
顧客ID: 000004
数量: 2セット
$set_cnt: 1
$special_price_ok: 1

処理フロー:
1. セット構成商品の価格を個別に計算:
   - 商品80451: price_chk() → 1,500円
   - 商品80453: price_chk() → 2,000円
   - 商品80438: price_chk() → 1,200円
2. セット単価 = 1,500円 + 2,000円 + 1,200円 = 4,700円
3. 最終価格 = 4,700円 * 2セット = 9,400円

例6: カート表示前価格調整(Mesosutical小売商品)

商品: Mesosutical小売商品
顧客: Premium Aグループ
注文数量: 15個
ユーザー直送モード: なし

処理フロー:
1. 対象顧客かつユーザー直送モードでない → 対象
2. 注文個数合計 = 15個(1以上)
3. 商品カテゴリ: Mesosutical小売商品
4. 合計数12以上 → $line_206_chk = 2
5. カート表示時: $line_206_chk == 2
   → price_chk関数で価格を取得しカート内価格を上書き
6. 結果: 特別価格で表示

例7: カート表示前価格調整(Rcodeライン商品)

商品: Rcodeライン商品
顧客: Premium Bグループ
注文数量: 25個
ユーザー直送モード: なし

処理フロー:
1. 対象顧客かつユーザー直送モードでない → 対象
2. 注文個数合計 = 25個(1以上)
3. 商品カテゴリ: Rcodeライン商品
4. 合計数24以上 → $line_206_chk = 2
5. カート表示時: $line_206_chk == 2
   → price_chk関数で価格を取得しカート内価格を上書き
6. 結果: 特別価格で表示

例8: カート表示前価格調整(条件未満の場合)

商品: Mesosutical小売商品
顧客: Premium Aグループ
注文数量: 8個
ユーザー直送モード: なし

処理フロー:
1. 対象顧客かつユーザー直送モードでない → 対象
2. 注文個数合計 = 8個(1以上)
3. 商品カテゴリ: Mesosutical小売商品
4. 合計数12未満 → $line_206_chk = 1
5. カート表示時: $line_206_chk == 1
   → 商品マスタから定価を取得してカート内価格を上書き
6. 結果: 定価で表示(特別価格条件を満たさない)

例9: カート表示前価格調整(Rcode商品・Premium顧客特例)

商品: Rcodeライン商品
顧客: Premium Cグループ(1個から特別価格設定あり)
注文数量: 10個
ユーザー直送モード: なし

処理フロー:
1. 対象顧客かつユーザー直送モードでない → 対象
2. 注文個数合計 = 10個(1以上)
3. 商品カテゴリ: Rcodeライン商品
4. 合計数24未満 → Premium顧客で1個から特別価格? → Yes
5. $line_206_chk = 2
6. カート表示時: $line_206_chk == 2
   → price_chk関数で価格を取得しカート内価格を上書き
7. 結果: 特別価格で表示(Premium顧客特例適用)

実装時の注意点

データ整合性

  • 顧客グループと個別顧客の価格設定の優先順位
  • 数量別価格の適用順序(一般 → グループ → 個別)
  • ユーザー直送モードの判定タイミング
  • カート表示前価格調整の適用条件
  • Mesosutical小売商品の12個以上条件
  • Rcodeライン商品の24個以上条件
  • Premium顧客の1個から特別価格例外処理

パフォーマンス考慮

  • 価格マスタの検索最適化
  • 顧客グループの階層構造対応
  • 大量商品の価格計算処理

エラーハンドリング

  • 価格データが存在しない場合のフォールバック
  • 顧客情報が不正な場合の処理
  • 数量計算エラーの対応