# 機能設計書 18-返品注文管理

## 概要

本ドキュメントは、InvenTreeシステムにおける返品注文管理機能の設計内容を記述した機能設計書である。顧客からの返品（RMA: Return Merchandise Authorization）の受付・管理・受領処理について詳細を定義する。

### 本機能の処理概要

**業務上の目的・背景**：
製品の不良、保証対応、顧客都合による返品など、販売後に商品が返送されてくるケースは少なくない。返品を適切に管理し、在庫への再登録や廃棄処理を行うことで、在庫の正確性を維持し、顧客対応の品質を向上させる。本機能は、返品注文のライフサイクル全体を管理する。

**機能の利用シーン**：
- 顧客から返品依頼を受け付ける場面
- 返品注文を発行して処理を開始する場面
- 返品商品を受領して在庫に戻す場面
- 返品商品の検品・処理結果を記録する場面
- 返品履歴を確認・分析する場面

**主要な処理内容**：
1. 返品注文の作成・編集・削除処理
2. 返品注文のステータス遷移管理（PENDING→IN_PROGRESS→COMPLETE/CANCELLED）
3. 返品注文の発行処理と通知
4. 返品商品の受領処理
5. 返品商品の処理結果記録
6. 返品合計金額の計算

**関連システム・外部連携**：
- 顧客管理との連携
- 在庫管理との連携（在庫への返却）
- 通知システムとの連携
- プラグインシステム（イベントトリガー）

**権限による制御**：
- 返品注文の作成・編集は販売担当者権限が必要
- 返品注文の発行・完了は承認権限が必要

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 21 | 販売インデックス画面 | 主機能 | 返品注文の一覧表示 |
| 23 | 返品注文詳細画面 | 主機能 | 返品注文の詳細表示・編集・発行・受領・完了処理 |
| 25 | 会社詳細画面 | 遷移先機能 | 顧客の返品注文一覧表示 |
| 16 | 在庫アイテム詳細画面 | 関連画面 | 返品された在庫アイテムの詳細 |

## 機能種別

CRUD操作 / ステータス管理 / 計算処理 / イベント通知

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| reference | CharField | Yes | 返品注文番号（最大64文字、一意） | パターン検証、重複チェック |
| customer | ForeignKey | Yes | 顧客（Company） | is_customer=Trueの会社のみ |
| description | CharField | No | 返品注文説明（最大250文字） | - |
| customer_reference | CharField | No | 顧客参照番号（最大64文字） | - |
| target_date | DateField | No | 処理予定日 | - |
| contact | ForeignKey | No | 担当連絡先 | 顧客に属するContact |
| address | ForeignKey | No | 返送元住所 | 顧客に属するAddress |
| responsible | ForeignKey | No | 責任者 | Owner（ユーザーまたはグループ） |
| project_code | ForeignKey | No | プロジェクトコード | ProjectCode |

### 入力データソース

- 画面入力（返品注文作成・編集フォーム）
- APIリクエスト

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| reference | str | 返品注文番号 |
| status | int | ステータスコード |
| total_price | Money | 返品合計金額 |
| is_received | bool | 全明細受領済みフラグ |
| is_overdue | bool | 期限超過フラグ |

### 出力先

- order_returnorderテーブル
- 通知システム（返品イベント）
- レポート・帳票出力

## 処理フロー

### 処理シーケンス

```
1. 返品注文の作成
   └─ reference自動採番
   └─ 顧客選択
   └─ バリデーション実行

2. 返品明細の追加
   └─ 返品対象在庫アイテムの選択
   └─ 数量の入力

3. 返品注文の発行（PENDING→IN_PROGRESS）
   └─ ステータス変更
   └─ 発行日の記録
   └─ 関係者への通知

4. 返品商品の受領
   └─ 明細ごとの受領処理
   └─ 在庫のロケーション移動
   └─ ステータス変更（隔離等）

5. 返品注文の完了（IN_PROGRESS→COMPLETE）
   └─ 全明細の受領完了チェック
   └─ ステータス変更
   └─ 完了日の記録
```

### フローチャート

```mermaid
flowchart TD
    A[返品注文作成] --> B{バリデーションOK?}
    B -->|No| C[エラー表示]
    B -->|Yes| D[PENDING状態で保存]
    D --> E[明細追加]
    E --> F{発行可能?}
    F -->|No| E
    F -->|Yes| G[発行処理]
    G --> H[IN_PROGRESS状態]
    H --> I[受領処理]
    I --> J{全明細受領?}
    J -->|No| I
    J -->|Yes| K[COMPLETE状態]

    H --> L[キャンセル]
    L --> M[CANCELLED状態]
    D --> L
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-18-01 | 参照番号一意性 | 返品注文番号（reference）はシステム全体で一意 | 返品注文作成・編集時 |
| BR-18-02 | 顧客制約 | 顧客はis_customer=Trueの会社のみ | 顧客選択時 |
| BR-18-03 | ステータス遷移 | PENDING→IN_PROGRESS→COMPLETE、またはOPEN状態からCANCELLED | ステータス変更時 |
| BR-18-04 | 発行要件 | PENDINGまたはON_HOLD状態からのみ発行可能 | 発行処理時 |
| BR-18-05 | 完了要件 | IN_PROGRESS状態からのみ完了可能 | 完了処理時 |
| BR-18-06 | 受領ステータス | 受領時はデフォルトでQUARANTINED（隔離）ステータス | 受領処理時 |
| BR-18-07 | 責任者必須 | 設定により責任者を必須化可能 | RETURNORDER_REQUIRE_RESPONSIBLE設定時 |
| BR-18-08 | ロック制御 | 完了済み返品注文の編集可否は設定で制御 | RETURNORDER_EDIT_COMPLETED_ORDERS設定 |

### 計算ロジック

**返品合計金額（total_price）**:
```python
def calculate_total_price(target_currency):
    total = Money(0, target_currency)
    for line in self.lines.all():
        if line.price:
            total += line.quantity * convert_money(line.price, target_currency)
    for line in self.extra_lines.all():
        if line.price:
            total += line.quantity * convert_money(line.price, target_currency)
    return total
```

## データベース操作仕様

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 返品注文作成 | order_returnorder | INSERT | 新規返品注文レコードの作成 |
| 返品注文編集 | order_returnorder | UPDATE | 返品注文情報の更新 |
| 返品注文発行 | order_returnorder | UPDATE | status→IN_PROGRESS、issue_date設定 |
| 返品注文完了 | order_returnorder | UPDATE | status→COMPLETE、complete_date設定 |
| 返品注文キャンセル | order_returnorder | UPDATE | status→CANCELLED |
| 合計金額更新 | order_returnorder | UPDATE | total_priceフィールドの更新 |

### テーブル別操作詳細

#### order_returnorder

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT/UPDATE | reference | 返品注文番号 | UNIQUE制約 |
| INSERT/UPDATE | customer_id | 顧客ID | FK: company_company |
| UPDATE | status | ステータスコード | 10:PENDING, 20:IN_PROGRESS, 25:ON_HOLD, 30:COMPLETE, 40:CANCELLED |
| UPDATE | issue_date | 発行日 | 発行処理時に設定 |
| UPDATE | complete_date | 完了日 | 完了処理時に設定 |
| UPDATE | total_price | 合計金額 | 保存時に再計算 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| reference_duplicate | ValidationError | 返品注文番号が重複 | 別の番号を指定 |
| customer_invalid | ValidationError | 顧客がis_customer=False | 正しい顧客を選択 |
| contact_mismatch | ValidationError | 連絡先が顧客に属さない | 顧客の連絡先を選択 |
| status_transition_invalid | ValidationError | 不正なステータス遷移 | 正しい遷移パスを確認 |
| order_locked | ValidationError | 完了済み返品注文の編集試行 | 設定を確認するか新規作成 |

### リトライ仕様

- データベース一時エラー：トランザクション単位でリトライ
- 通知送信エラー：バックグラウンドタスクで自動リトライ

## トランザクション仕様

- 返品注文の作成・編集はトランザクション内で実行
- ステータス遷移処理はトランザクション内で完結
- 受領処理は@transaction.atomicで保護
- 合計金額の再計算は保存時に自動実行

## パフォーマンス要件

- 返品注文一覧表示：1秒以内（100件まで）
- 返品注文詳細表示：500ms以内
- ステータス変更：500ms以内

## セキュリティ考慮事項

- 返品注文の変更は監査ログに記録
- ステータス遷移はイベントトリガーで追跡
- 完了済み返品注文のロック機能で改ざん防止
- 受領時の在庫ステータス変更は追跡履歴に記録

## 備考

- 返品注文番号のパターンはRETURNORDER_REFERENCE_PATTERN設定でカスタマイズ可能
- 受領時のデフォルトステータスはQUARANTINED（隔離）で検品待ち状態

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | models.py | `src/backend/InvenTree/order/models.py` | ReturnOrderクラスの定義 |
| 1-2 | status_codes.py | `src/backend/InvenTree/order/status_codes.py` | ReturnOrderStatusの定義 |

**読解のコツ**:
- **2633-2955行目**: ReturnOrderクラスの定義
- **2709-2717行目**: referenceフィールドの定義
- **2734-2740行目**: statusフィールドの定義
- **2719-2727行目**: customerフィールドの定義

#### Step 2: ステータス遷移を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | models.py | `src/backend/InvenTree/order/models.py` | issue_order(), complete_order()メソッド |
| 2-2 | models.py | `src/backend/InvenTree/order/models.py` | _action_place(), _action_complete()メソッド |

**主要処理フロー**:
1. **2856-2861行目**: issue_order()でhandle_transitionを呼び出し
2. **2831-2847行目**: _action_place()でステータス変更と通知処理
3. **2863-2868行目**: complete_order()でhandle_transitionを呼び出し
4. **2810-2817行目**: _action_complete()でステータス変更

#### Step 3: 受領処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | models.py | `src/backend/InvenTree/order/models.py` | receive_line_item()メソッド |

**主要処理フロー**:
- **2879-2955行目**: receive_line_item()メソッド
- **2903-2907行目**: 部分返品時の在庫分割
- **2913-2916行目**: デフォルトステータス（QUARANTINED）設定
- **2923-2928行目**: 在庫アイテムの更新

### プログラム呼び出し階層図

```
ReturnOrder.issue_order()
    │
    └─ handle_transition()
           └─ _action_place()
                  ├─ status = IN_PROGRESS
                  ├─ issue_date = current_date()
                  ├─ trigger_event(ISSUED)
                  └─ notify_responsible()

ReturnOrder.receive_line_item()
    │
    ├─ 受領済みチェック
    │
    ├─ 部分返品処理
    │      └─ splitStock() [数量 < 在庫数量の場合]
    │
    ├─ 在庫ステータス変更
    │      └─ set_status(QUARANTINED)
    │
    ├─ 在庫情報更新
    │      ├─ location 変更
    │      ├─ customer = None
    │      └─ sales_order = None
    │
    ├─ 追跡履歴記録
    │      └─ add_tracking_entry(RETURNED_AGAINST_RETURN_ORDER)
    │
    ├─ 明細更新
    │      └─ received_date = current_date()
    │
    └─ 通知送信
           └─ notify_responsible()
```

### データフロー図

```
[入力]               [処理]                    [出力]

返品注文情報     ───▶ バリデーション          ───▶ order_returnorder
  (フォーム)            │                           テーブル
                        │
                        ▼
在庫アイテム     ───▶ 明細追加               ───▶ order_returnorderlineitem
  (選択)                │                           テーブル
                        │
                        ▼
発行コマンド     ───▶ ステータス遷移          ───▶ status = IN_PROGRESS
                        │
                        ▼
                  通知処理                 ───▶ 通知システム
                        │
                        ▼
受領情報         ───▶ 受領処理               ───▶ stock_stockitem
  (ロケーション等)      │                           (location, status更新)
                        │
                        ▼
                  追跡履歴記録             ───▶ stock_stockitemtracking
                        │
                        ▼
                  完了判定                 ───▶ status = COMPLETE
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| models.py | `src/backend/InvenTree/order/models.py` | ソース | ReturnOrderモデル定義 |
| status_codes.py | `src/backend/InvenTree/order/status_codes.py` | ソース | ReturnOrderStatus、ReturnOrderLineStatusの定義 |
| api.py | `src/backend/InvenTree/order/api.py` | ソース | 返品注文APIエンドポイント |
| serializers.py | `src/backend/InvenTree/order/serializers.py` | ソース | 返品注文シリアライザー |
| validators.py | `src/backend/InvenTree/order/validators.py` | ソース | 参照番号のバリデーション・生成 |
| events.py | `src/backend/InvenTree/order/events.py` | ソース | ReturnOrderEventsの定義 |
