はじめに
Odooでは「モデル」がデータの設計図です。顧客情報や見積、請求書といった業務データはすべてモデルを通じてデータベースに保存されます。
モデルの理解は開発者だけでなく、設定を担当するコンサルタントにも不可欠です。モデルはフィールドや関連、業務ルールを定義するため、システム全体の土台になります。
本稿ではセールス(Sales)モジュールの中核モデルの一つである sale.order.line に焦点を当てます。カスタム開発、外部連携、価格設定や請求フローの構築など、さまざまな場面で扱う重要モデルです。
sale.order.line モデルとは何か
sale.order.line は見積や受注の各行(行アイテム)を表すモデルです。一般的に一行が一商品に対応し、数量、単価、税などの情報を持ちます。
このモデルは sale モジュールで使われ、analytic.mixin を継承してプロジェクトごとの原価管理やタイムシート連携を可能にします。見積へ商品を追加すると sale.order.line レコードが作成されます。
モデル本体は sale モジュールで定義され、他モジュールが継承して拡張します。たとえば sale_stock は配送/出荷に関するフィールドを追加し、sale_margin は粗利計算を加える。コア構造を保ちつつ必要機能だけを追加する形です。
モデルの主要フィールド
以下は sale.order.line で特に重要なフィールド群です。これらを把握しておくと見積・受注の設定やカスタマイズがスムーズになります。
1. order_id(注文参照)
タイプ: Many2one(sale.order)。必須。各行を親の受注に紐づけます。受注削除時は行も削除される(カスケード)仕様です。
2. sequence(表示順)
タイプ: Integer。デフォルト10。見積書上での行の並び順を制御します。セクションや注釈、商品行の表示優先度に使われます。
3. company_id(会社)
タイプ: Many2one(res.company)。order_id から関連付けられる値で、マルチカンパニー運用やアクセス制御に用いられます。
4. currency_id(通貨)
タイプ: Many2one(res.currency)。order_id から関連。行の金額に適用される通貨を決めます。価格計算の整合性に重要です。
5. order_partner_id(顧客)
タイプ: Many2one(res.partner)。order_id から関連。プライスリストや課税ルールの判定に使われます。
6. salesman_id(営業担当)
タイプ: Many2one(res.users)。order_id から関連。コミッションや営業別レポートで利用されます。
7. state(受注状態)
タイプ: Selection。order_id から関連。draft、sent、sale、done、cancel などの状態により編集可能な項目が変わります。
8. display_type(表示タイプ)
タイプ: Selection。line_section または line_note。設定するとその行は見出しや注釈扱いになり、商品関連フィールドは空になります。
9. is_downpayment(頭金フラグ)
タイプ: Boolean。行が前受けや頭金である場合に true。頭金は別請求扱いになります。
10. is_expense(経費由来フラグ)
タイプ: Boolean。経費や仕入伝票由来の行で true。プロジェクト原価管理で識別に使われます。
11. product_id(製品)
タイプ: Many2one(product.product)。販売対象の商品。ドメインで販売可能な製品に限定され、商品行では必須です。
12. product_template_id(製品テンプレート)
タイプ: Many2one(product.template)。product_id から計算される値で、バリアント選択やコンフィグレータで利用されます。
13. name(行説明)
タイプ: Text。商品や属性から計算される行の説明文。バリアント詳細などを含めて表示されます。
14. product_uom_qty(数量)
タイプ: Float。必須。注文数量。デフォルトは1.0。パッケージ設定で駆動される場合があります。
15. product_uom(単位)
タイプ: Many2one(uom.uom)。単位。商品からのデフォルト値を使い、数量・価格計算に影響します。
16. tax_id(税金)
タイプ: Many2many(account.tax)。行に適用される税。商品や会計上の税ポジションから計算されます。
17. price_unit(単価)
タイプ: Float。必須。単位あたりの価格。プライスリストや商品から計算され、手動で上書き可能です。
18. discount(割引)
タイプ: Float。割引率(%)。税計算の前に price_unit に適用されます。
19. price_subtotal(税抜小計)
タイプ: Monetary。税抜きの小計。数量・単価・割引から計算されます。
20. price_tax(税額)
タイプ: Float。税額合計。price_subtotal と tax_id を基に計算されます。
21. price_total(税込合計)
タイプ: Monetary。税を含んだ合計金額。請求金額の基礎となる金額です。
22. product_packaging_id(梱包)
タイプ: Many2one(product.packaging)。オプションの梱包(例:12個入り箱)。設定すると数量が梱包数に合わせて変動することがあります。
23. customer_lead(納期リード)
タイプ: Float。注文確定から出荷までの日数。納品日の算出に利用されます。
24. qty_delivered(出荷数量)
タイプ: Float。出荷済み数量。出庫処理や手動更新で変わり、部分請求の判定に使われます。
25. qty_invoiced(請求済数量)
タイプ: Float。既に請求された数量。請求書ラインから計算されます。
26. qty_to_invoice(未請求数量)
タイプ: Float。請求残の数量。qty_delivered と qty_invoiced を元に算出されます。
27. invoice_status(請求状況)
タイプ: Selection。upselling、invoiced、to invoice、no など。行ごとの請求ステータスを示します。
28. invoice_lines(関連請求行)
タイプ: Many2many(account.move.line)。この売上行から作成された請求書行への参照。トレーサビリティに用います。
29. create_date(作成日時)
タイプ: Datetime。レコード作成日時。Odooが自動管理します。
30. write_date(更新日時)
タイプ: Datetime。最終更新日時。監査や同期の判断に使います。
業務フローでの利用シーン
1. 見積・受注作成の基本フロー
営業担当が見積を作る際、商品を追加すると各商品が sale.order.line として登録されます。各行には数量、単価、割引、小計が表示され、顧客が承認すると受注確定となります。
2. プライスリストと割引の適用
行単位でプライスリストが適用され、price_unit や discount が計算されます。数量割引や顧客別価格はここで反映されます。
3. 出荷と請求の連携
出荷が行われると qty_delivered が更新されます。請求は出荷ごとに行う方式と一括請求の方式があり、invoice_status が残りの請求対象を示してくれます。
4. サービス/プロジェクト連携
サービス商品では行がプロジェクトのタスクやタイムシートと紐づきます。analytic.mixin によってプロジェクト別の原価管理が可能です。
5. ECサイトとポータル利用時の扱い
ウェブのカートに商品を追加すると、注文作成時に各カート行が sale.order.line になります。コンフィグレータは product_template_id とカスタム属性を使ってバリアントを決定します。
開発者による拡張方法
開発者はモデル継承などのパターンで sale.order.line を拡張します。Odoo の継承メカニズムが基本手段です。
モデル継承の考え方
モデルを拡張するには _inherit = 'sale.order.line' を使います。新フィールドの追加、既存メソッドのオーバーライド、制約の追加などが可能で、変更は別モジュールに分離して保守性を高めます。
フィールド追加のポイント
継承モデルに新しい Odoo フィールドを定義します。Char、Many2one、Boolean、Integer、Text、Selection など適切な型を選び、マルチカンパニー対応が必要なら company-dependent を検討します。
Python 側の拡張
_compute_price_unit や _compute_price_subtotal をオーバーライドしたり、create/write にロジックを加えます。super() を使って元処理を呼び出すこと、計算フィールドの依存関係に注意することが重要です。
Odoo Studio の活用
コードを書かずにフィールド追加できる Odoo Studio は迅速なカスタマイズに便利です。ただし複雑な業務ロジックや将来のアップグレードを考えると、拡張モジュールでの実装が保守上望ましい場合が多いです。
推奨される実務上の作法
- 見出しや注釈は display_type を使う
- セクションやメモを表す行には display_type を設定しましょう。偽の製品行を使うより帳票や集計が整然と保たれます。
- API連携時の行作成
- 外部APIで行を作る場合は order_id を通じて作成するか、sale.order の order_line_ids フィールドに適切なコマンド形式で追加します。
- SQL制約や必須条件を守る
よくある間違いと注意点
- 商品行には product_id と product_uom が必須、注釈行には display_type が必要といった制約を守りましょう。違反するとDBレベルやバリデーションでエラーになります。
- 製品IDとテンプレートIDを混同しない
- 商品行では product_id を設定し、バリアント選択や構成フローでは product_template_id を使ってから適切なバリアントを確定するのが正しい流れです。
- 請求済み後の価格変更に注意
- qty_invoiced が0より大きい行で price_unit や discount を変更すると請求データとの不整合や会計上の問題を招く恐れがあります。
まとめ
super() を呼ばないオーバーライドは危険
コアメソッドを上書きして super() を呼ばないと、他モジュールとの互換性や将来のアップグレードで不具合を招くことがあります。
Odoo導入でお困りですか?
セクション/注釈に display_type を付け忘れない
display_type を設定しないと注釈が商品行扱いになり、必須バリデーションで失敗します。意図した用途に合わせて必ず設定してください。 sale.order.line は Odoo セールスの核です。見積や受注の各行を保持することで、設定、カスタマイズ、外部連携の基盤になります。 業務設計をするコンサルタントも、拡張開発を行うエンジニアも、sale.order.line を理解しておくことで手戻りを減らしミスを防げます。