Skip to content

iDempiere 割引スキーマの使い方|在庫管理 操作マニュアル・技術仕様

This content is not available in your language yet.

📖 在庫管理の全体像: 在庫管理の業務フロー全体図 も合わせてご覧ください。

割引スキーマは、取引割引率(Trade Discount)の計算方法を定義するマスタです。単純な定率割引のほか、数量や金額の分岐点(Break)ごとに割引率を変える段階割引を設定でき、価格表や取引先マスタから参照されて伝票明細の価格計算に使われます。

📌 ポイント: 割引タイプは「定率(Flat Percent)」と「分岐(Breaks)」が実装されており、「数式(Formula)」「価格表(Pricelist)」は iDempiere 13 のコードでも未サポート(割引 0 を返却)です。

  • 定率割引(Flat Percent)の設定
  • 数量ベースまたは金額ベースの段階割引(分岐条件)の設定
  • 品目単位・品目カテゴリ単位での分岐条件の指定
  • 取引先マスタに設定された割引率の優先適用
  • 分岐ごとの固定価格(Fixed Price)の指定
  • 累積レベル(Accumulation Level)による集計単位の指定
  • 「再計算」ボタンによる分岐のシーケンス番号の振り直し
  • 適用開始日(Valid from)による有効期間の管理

割引スキーマは 2 タブ構成です。

タブ名テーブル項目数役割
割引スキーマM_DiscountSchema12項目割引タイプ・定率割引・累積レベル
割引条件設定M_DiscountSchemaBreak11項目分岐値ごとの割引率・固定価格

💡 ヒント: 割引タイプが「定率」の場合、割引条件設定タブは使用しません。段階割引を使う場合のみ分岐を登録してください。

graph TD
    A["🚀 メニューから開く<br/>在庫管理 > 品目マスタ管理 > 割引スキーマ"] --> B["➕ 新規で名称を入力"]
    B --> C{割引タイプ}
    C -->|定率割引| D["💯 割引率を入力<br/>(FlatDiscount)"]
    C -->|段階割引| E["📊 数量ベースか金額ベースかを選択"]
    D --> F{取引先の割引率を<br/>優先する?}
    E --> G["📋 割引条件設定タブで<br/>分岐値・分岐割引率を登録"]
    G --> H["🎯 必要なら品目 or 品目カテゴリで<br/>適用範囲を絞る"]
    H --> I["🔁 再計算ボタンで<br/>シーケンスNoを振り直し"]
    F -->|する| J["☑ 取引先割引率優先にチェック"]
    F -->|しない| K["💾 保存"]
    I --> K
    J --> K
    K --> L["🔗 価格表・取引先マスタから参照<br/>→ 伝票明細の割引に反映"]

メニューから開く 在庫管理 > 品目マスタ管理 > 割引スキーマ 新規で名称を入力 割引率を入力 (FlatDiscount) 数量ベースか金額ベースかを選択 割引条件設定タブで 分岐値・分岐割引率を登録 必要なら品目 or 品目カテゴリで 適用範囲を絞る 再計算ボタンで シーケンスNoを振り直し 取引先割引率優先にチェック 保存 価格表・取引先マスタから参照 → 伝票明細の割引に反映 割引タイプ 取引先の割引率を 優先する? 定率割引 段階割引 する しない

アクセス方法(メニューパス)

Section titled “アクセス方法(メニューパス)”

メニューから「在庫管理 > 品目マスタ管理 > 割引スキーマ」を開きます。

  1. ツールバーの「新規」ボタンをクリック
  2. 必須項目を入力:
    • 名称: 割引スキーマ名(60文字以内)
    • 割引タイプ: 定率(Flat Percent) を選択
    • 数量ベース: 定率の場合は判定に使用されません(既定値 Y)
    • 適用開始日: 空欄で保存すると当日日付が自動セットされます
  3. 割引率 に定率の割引パーセントを入力
  4. 取引先マスタ側の割引率を優先する場合は「取引先割引率優先」にチェック
  5. 保存」をクリック
  1. 割引スキーマタブで 割引タイプ を分岐(Breaks)系に設定し、判定軸を選択:
    • 数量ベース にチェック → 数量で分岐
    • チェックを外す → 金額(単価 × 数量)で分岐
  2. 割引条件設定」タブに移動
  3. 各分岐を登録:
    • 分岐値: この値以上で当該行が適用される下限値
    • 分岐割引率: 適用する割引率(%)
    • 品目 または 品目カテゴリ: 適用範囲を絞る場合に指定
    • Fixed Price: 固定価格を適用する場合に入力(既定値 0)
  4. 保存」をクリック
  5. 割引スキーマタブに戻り「再計算」ボタンでシーケンス番号を 10 刻みに整列

⚠️ 注意: 分岐行で「品目」と「品目カテゴリ」の両方を指定して保存すると、MDiscountSchemaBreak.beforeSave()品目カテゴリを自動的に 0(クリア) します。品目指定が優先される仕様です。

項目名必須説明
名称必須文字列(60)割引スキーマ名
説明-文字列(255)補足説明
割引タイプ必須リスト(1)定率/分岐/数式/価格表
割引率-数値定率割引のパーセント
取引先割引率優先必須チェック取引先マスタの割引率を使用
数量ベース必須チェック分岐判定を数量で行う(既定値 Y)
累積レベル-リスト(1)集計単位(既定値 L
スクリプト-テキスト(2000)動的スクリプト(数式タイプ用)
適用開始日必須日付未入力時は保存日が自動セット
再計算-ボタン分岐のシーケンスNoを振り直す
有効-チェックレコードが有効か(既定値 Y)
項目名必須説明
割引スキーマ必須選択親レコードへの参照
シーケンスNo必須整数評価順(既定値は最大値+10)
分岐値必須数値適用の下限値(数量または金額)
分岐割引率必須数値当該分岐の割引率(%)
品目-検索適用対象の品目
品目カテゴリ-選択適用対象の品目カテゴリ
取引先割引率優先必須チェック取引先の割引率を使用(既定値 N)
Fixed Price-金額固定価格(既定値 0)
有効必須チェックレコードが有効か(既定値 Y)

全項目一覧はリファレンス参照

Q. 割引タイプに「数式」や「価格表」を選ぶとどうなりますか?

Section titled “Q. 割引タイプに「数式」や「価格表」を選ぶとどうなりますか?”

割引率 0 が返されます。MDiscountSchema.calculateDiscount()DISCOUNTTYPE_Formula および DISCOUNTTYPE_Pricelist に対して「Not supported (yet)」とログ出力し、Env.ZERO を返す実装です(iDempiere 13 時点)。実運用では「定率」または分岐(Breaks)を使用してください。

Q. 分岐はどの順番で評価されますか?

Section titled “Q. 分岐はどの順番で評価されますか?”

「割引条件設定」タブのシーケンスNo 順(昇順)です。getBreaks() で取得した配列を順に走査し、MDiscountSchemaBreak.applies() が真になる行を採用します。評価順を整理したい場合は割引スキーマタブの「再計算」ボタンを実行すると、reSeq() が 10 / 20 / 30 … と 10 刻みに振り直します。

Q. 分岐行の適用条件はどのように判定されますか?

Section titled “Q. 分岐行の適用条件はどのように判定されますか?”

MDiscountSchemaBreak.applies(Value, M_Product_ID, M_Product_Category_ID) が以下の順で判定します。

  1. 行が無効(IsActive=N)なら不適用
  2. 判定値が分岐値(BreakValue未満なら不適用
  3. 品目・品目カテゴリがどちらも未指定なら適用(全品目対象)
  4. 行の品目が対象品目と一致すれば適用
  5. 対象の品目カテゴリが指定されていれば、行の品目カテゴリと一致するかを判定
  6. それ以外は MProductCategory.isCategory() で品目のカテゴリを照会して判定

Q. 「数量ベース」のチェックを外すと何が変わりますか?

Section titled “Q. 「数量ベース」のチェックを外すと何が変わりますか?”

分岐の判定値が数量から金額(Price × Qty)に変わります。「10 個以上で 5% 引き」ではなく「10 万円以上で 5% 引き」といった金額帯での段階割引を設定できます。

Q. 「取引先割引率優先」にチェックすると何が起きますか?

Section titled “Q. 「取引先割引率優先」にチェックすると何が起きますか?”

割引タイプが定率の場合、calculateDiscount() はスキーマの FlatDiscount ではなく、引数で渡された取引先の割引率(BPartnerFlatDiscount)を返します。取引先マスタ側で個別の割引率を管理している場合に使用します。

Q. 適用開始日を入力し忘れました

Section titled “Q. 適用開始日を入力し忘れました”

保存時に自動補完されます。MDiscountSchema.beforeSave()ValidFrom の未設定を検出すると TimeUtil.getDay(null)(当日)をセットします。

🛠 技術仕様(開発者向け)

割引スキーマはマスタデータ型のウィンドウ(AD_Window_ID: 233)で、M_DiscountSchema テーブル(アクセスレベル 3)と子テーブル M_DiscountSchemaBreak で構成されます。MDiscountSchema クラス(488行)が価格・割引の計算エンジンを、MDiscountSchemaBreak(183行)が分岐の適用判定を担います。MDiscountSchemamarkImmutable() を実装し、キャッシュ経由の不変オブジェクト参照に対応しています。Document 型ではありません。

なお、価格表の割引に使われる M_DiscountSchemaLineMDiscountSchemaLine クラス)も同じ親テーブルに紐づきますが、このウィンドウのタブとしては公開されていません。

classDiagram
    class MDiscountSchema {
        +get(M_DiscountSchema_ID) MDiscountSchema
        +getBreaks(reload) MDiscountSchemaBreak[]
        +getLines(reload) MDiscountSchemaLine[]
        +calculatePrice(Qty, Price, ...) BigDecimal
        +calculateDiscount(Qty, Price, ...) BigDecimal
        +calculateDiscountedPrice(price, discount) BigDecimal
        +beforeSave(newRecord) boolean
        +reSeq() int
    }
    class MDiscountSchemaBreak {
        +applies(Value, M_Product_ID, M_Product_Category_ID) boolean
        +beforeSave(newRecord) boolean
    }
    class X_M_DiscountSchema {
        <<generated>>
    }
    class PO {
        <<abstract>>
    }
    MDiscountSchema --|> X_M_DiscountSchema
    X_M_DiscountSchema --|> PO
    MDiscountSchema --> MDiscountSchemaBreak : has many
    MDiscountSchema --> MDiscountSchemaLine : has many
    MDiscountSchemaBreak --> MProductCategory : category check

+get(M_DiscountSchema_ID) MDiscountSchema +getBreaks(reload) MDiscountSchemaBreak[] +getLines(reload) MDiscountSchemaLine[] +calculatePrice(Qty, Price, ...) BigDecimal +calculateDiscount(Qty, Price, ...) BigDecimal +calculateDiscountedPrice(price, discount) BigDecimal +beforeSave(newRecord) boolean +reSeq() int +applies(Value, M_Product_ID, M_Product_Category_ID) boolean +beforeSave(newRecord) boolean <> <> > X_M_DiscountSchema X_M_DiscountSchema --

パッケージ: org.compiere.model ソースファイル: org.adempiere.base/src/org/compiere/model/MDiscountSchema.javaMDiscountSchemaBreak.java

カラム名必須説明備考
M_DiscountSchema_IDIDPK割引スキーマID主キー
AD_Client_IDTable DirectYクライアント既定値 @#AD_Client_ID@
AD_Org_IDTable DirectY組織既定値 @#AD_Org_ID@
NameString(60)Y名称識別子カラム
DescriptionString(255)N説明
DiscountTypeList(1)Y割引タイプ定率/分岐/数式/価格表
FlatDiscountNumberN割引率定率割引用
IsBPartnerFlatDiscountYes-NoY取引先割引率優先
IsQuantityBasedYes-NoY数量ベース既定値 Y
CumulativeLevelList(1)N累積レベル既定値 L
ScriptText(2000)Nスクリプト数式タイプ用
ValidFromDateY適用開始日未設定時は beforeSave で当日補完
ProcessingButtonN再計算reSeq() を起動
IsActiveYes-NoY有効既定値 Y

M_DiscountSchemaBreak(割引条件設定)

Section titled “M_DiscountSchemaBreak(割引条件設定)”
カラム名必須説明備考
M_DiscountSchemaBreak_IDIDPK分岐ID主キー
M_DiscountSchema_IDTable DirectY割引スキーマIsParent=Y
SeqNoIntegerYシーケンスNo既定値 MAX(SeqNo)+10・識別子
BreakValueNumberY分岐値適用の下限値
BreakDiscountNumberY分岐割引率
M_Product_IDSearchN品目指定時はカテゴリをクリア
M_Product_Category_IDTable DirectN品目カテゴリ
IsBPartnerFlatDiscountYes-NoY取引先割引率優先既定値 N
FixedPriceCosts+PricesN固定価格既定値 0
IsActiveYes-NoY有効既定値 Y
erDiagram
    M_DiscountSchema ||--o{ M_DiscountSchemaBreak : "breaks"
    M_DiscountSchema ||--o{ M_DiscountSchemaLine : "price list lines"
    M_DiscountSchemaBreak }o--o| M_Product : "product filter"
    M_DiscountSchemaBreak }o--o| M_Product_Category : "category filter"
    M_PriceList }o--o| M_DiscountSchema : "price list schema"
    C_BPartner }o--o| M_DiscountSchema : "partner schema"

price list lines product filter category filter price list schema partner schema

flowchart TD
    A["calculateDiscount(Qty, Price,<br/>M_Product_ID, M_Product_Category_ID,<br/>BPartnerFlatDiscount)"] --> B["BPartnerFlatDiscount が null なら<br/>ZERO に補完"]
    B --> C{DiscountType}
    C -->|FlatPercent| D{IsBPartnerFlatDiscount?}
    D -->|Yes| E["取引先の割引率を返却"]
    D -->|No| F["FlatDiscount を返却"]
    C -->|Formula / Pricelist| G["未サポート<br/>ログ出力して ZERO を返却"]
    C -->|Breaks| H["getBreaks(false) で分岐を取得"]
    H --> I["判定値を決定<br/>数量ベース: Qty / それ以外: Price × Qty"]
    I --> J["分岐を順に走査し<br/>applies() が真の行を採用"]

calculateDiscount(Qty, Price, M_Product_ID, M_Product_Category_ID, BPartnerFlatDiscount) BPartnerFlatDiscount が null なら ZERO に補完 取引先の割引率を返却 FlatDiscount を返却 未サポート ログ出力して ZERO を返却 getBreaks(false) で分岐を取得 判定値を決定 数量ベース: Qty / それ以外: Price × Qty 分岐を順に走査し applies() が真の行を採用 IsBPartnerFlatDiscount? Formula / Pricelist

MDiscountSchemaBreak.applies(BigDecimal Value, int M_Product_ID, int M_Product_Category_ID):

条件結果
1!isActive()false
2Value < BreakValuefalse
3行の品目・品目カテゴリがどちらも 0true(全品目対象)
4行の品目 == 対象品目true
5対象の品目カテゴリ != 0行の品目カテゴリと一致するか
6上記以外MProductCategory.isCategory(行のカテゴリ, 対象品目) の結果
クラス処理
MDiscountSchemaValidFrom が null なら TimeUtil.getDay(null)(当日)をセット
MDiscountSchemaBreakM_Product_ID > 0 かつ M_Product_Category_ID > 0 の場合、M_Product_Category_ID を 0 にリセット

reSeq() — シーケンスの振り直し

Section titled “reSeq() — シーケンスの振り直し”

「再計算」ボタン(Processing カラム)から起動される reSeq() は次の処理を行います。

  1. getLines(true)M_DiscountSchemaLine を再取得し、(i+1) * 10 の値に SeqNo を更新
  2. getBreaks(true)M_DiscountSchemaBreak を再取得し、同様に 10 刻みへ更新
  3. 更新できた件数を返却し、内部キャッシュ(m_lines / m_breaks)をクリア

calculateDiscountedPrice(BigDecimal price, BigDecimal discount) は static メソッドとして提供され、価格と割引率から割引後価格を求めます。伝票明細の価格計算(calculatePrice())から利用されます。

拡張ポイント(カスタマイズ箇所)

Section titled “拡張ポイント(カスタマイズ箇所)”

M_DiscountSchema / M_DiscountSchemaBreak の各カラムには標準の Callout は定義されていません。SeqNo の既定値は AD の @SQL=SELECT NVL(MAX(SeqNo),0)+10 ... で解決されます。

public class CustomDiscountSchemaValidator implements ModelValidator {
@Override
public int modelChange(PO po, int type) throws Exception {
if (po instanceof MDiscountSchemaBreak && (type == TYPE_BEFORE_NEW || type == TYPE_BEFORE_CHANGE)) {
MDiscountSchemaBreak br = (MDiscountSchemaBreak) po;
// 例: 割引率の上限を 30% に制限
if (br.getBreakDiscount() != null
&& br.getBreakDiscount().compareTo(new BigDecimal("30")) > 0) {
throw new AdempiereException("分岐割引率は30%以内にしてください");
}
}
return null;
}
}

IPricingRule による価格計算の拡張

Section titled “IPricingRule による価格計算の拡張”

「数式(Formula)」タイプがコアで未実装であるため、複雑な割引ロジックが必要な場合は IPricingRule インターフェースを実装し、OSGi サービスとして登録する方式が推奨されます。コアの価格計算エンジンを改変せずに、得意先グループ別・期間限定・累積購入額連動などのルールを追加できます。

プロセス名起動場所説明
再計算(Renumber Discount entries)割引スキーマタブの Processing ボタンreSeq() により明細・分岐のシーケンスNoを 10 刻みに振り直す

数量帯別割引や得意先別価格は、売上と粗利に直結する重要な設定です。標準の割引スキーマで足りない部分は IPricingRule の追加実装で、コア改変なしに柔軟な価格戦略を実現できます。

As-Link株式会社では、OSGiプラグインによる安全なカスタマイズを提供しています。

OSS ERP導入・カスタマイズサービスの詳細はこちら