# 機能設計書 14-発注受領処理

## 概要

本ドキュメントは、InvenTreeシステムにおける発注受領処理機能の設計内容を記述した機能設計書である。サプライヤーからの納品を受領し、在庫として登録する処理について詳細を定義する。

### 本機能の処理概要

**業務上の目的・背景**：
発注した部品や原材料がサプライヤーから納品された際、正確に在庫として登録することは在庫管理の基本である。受領処理では、発注明細に対して受領数量を記録し、対応する在庫アイテムを自動生成する。これにより、発注から在庫登録までのワークフローをシームレスに連携し、在庫の正確性を確保する。

**機能の利用シーン**：
- サプライヤーからの納品を受け入れる場面
- 部分納品を受領して残りを待つ場面
- 受領時にロケーション・バッチ・シリアル番号を指定する場面
- 外部製造オーダーの完成品を受領する場面
- 受領時に在庫ステータスを設定する場面

**主要な処理内容**：
1. 受領情報の入力・バリデーション
2. 在庫アイテム（StockItem）の自動生成
3. 受領数量の記録と発注明細の更新
4. 追跡履歴の記録
5. 発注書の自動完了判定
6. 通知の送信

**関連システム・外部連携**：
- 発注書管理機能（親機能）
- 在庫管理機能（在庫アイテム生成）
- シリアル番号管理機能（シリアル化受領）
- 製造オーダー管理機能（外部製造）
- 通知システム

**権限による制御**：
- 受領処理は購買担当者権限が必要
- 受領完了者情報が記録される

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 20 | 発注書詳細画面 | 主機能 | 受領アクションの実行・受領履歴の確認 |
| 16 | 在庫アイテム詳細画面 | 結果表示画面 | 受領で生成された在庫アイテムの詳細 |
| 18 | 製造オーダー詳細画面 | 関連画面 | 外部発注の受領状況表示 |

## 機能種別

データ登録 / トランザクション処理 / イベント通知

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| location | ForeignKey | Yes | 受入先ロケーション | StockLocation |
| items | List[dict] | Yes | 受領明細リスト | 各要素に必須項目あり |
| items[].line_item | ForeignKey | Yes | 発注明細 | PurchaseOrderLineItem |
| items[].quantity | Decimal | Yes | 受領数量 | 正の数値 |
| items[].location | ForeignKey | No | 個別受入先 | StockLocation（省略時はデフォルト） |
| items[].status | int | No | 在庫ステータス | StockStatus（デフォルト: OK） |
| items[].barcode | str | No | バーコード | - |
| items[].batch_code | str | No | バッチコード | - |
| items[].expiry_date | Date | No | 有効期限 | - |
| items[].serials | List[str] | No | シリアル番号リスト | シリアル化時必須 |
| items[].notes | str | No | メモ | - |
| items[].packaging | str | No | 梱包形態 | - |

### 入力データソース

- 画面入力（受領フォーム）
- APIリクエスト
- バーコードスキャン

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| stock_items | QuerySet[StockItem] | 生成された在庫アイテム |
| line_item.received | Decimal | 更新後の受領済み数量 |
| order.status | int | 発注書ステータス（自動完了時に更新） |

### 出力先

- stock_stockitemテーブル（新規在庫アイテム）
- stock_stockitemtrackingテーブル（受領履歴）
- order_purchaseorderlineitemテーブル（received更新）
- order_purchaseorderテーブル（自動完了時）
- 通知システム

## 処理フロー

### 処理シーケンス

```
1. 受領処理の開始
   └─ 発注書ステータス確認（PLACEDのみ許可）
   └─ 受領情報のバリデーション

2. 在庫アイテムの生成
   └─ シリアル化の判定
   └─ StockItemインスタンス生成
   └─ バーコード・バッチ情報の設定
   └─ bulk_createによる一括登録

3. 追跡履歴の記録
   └─ RECEIVED_AGAINST_PURCHASE_ORDER履歴
   └─ 追跡情報の一括登録

4. 発注明細の更新
   └─ received数量の加算
   └─ bulk_updateによる一括更新

5. 自動完了判定
   └─ 全明細完了チェック
   └─ PURCHASEORDER_AUTO_COMPLETE設定確認
   └─ 発注書のcomplete_order()呼び出し

6. 通知の送信
   └─ 責任者への通知
   └─ 部品購読者への通知
```

### フローチャート

```mermaid
flowchart TD
    A[受領処理開始] --> B{発注書=PLACED?}
    B -->|No| C[ValidationError]
    B -->|Yes| D[受領情報バリデーション]
    D --> E{バリデーションOK?}
    E -->|No| F[ValidationError]
    E -->|Yes| G{シリアル化?}
    G -->|Yes| H[_create_serial_numbers]
    G -->|No| I[StockItem作成]
    H --> J[bulk_create]
    I --> J
    J --> K[追跡履歴記録]
    K --> L[受領数量更新]
    L --> M[bulk_update]
    M --> N{全明細完了?}
    N -->|No| O[通知送信]
    N -->|Yes| P{自動完了設定?}
    P -->|Yes| Q[complete_order]
    P -->|No| O
    Q --> O
    O --> R[終了]
    C --> R
    F --> R
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-14-01 | 受領可能状態 | 発注書がPLACED状態の場合のみ受領可能 | 受領処理開始時 |
| BR-14-02 | 数量制約 | 受領数量は正の数値 | 受領情報入力時 |
| BR-14-03 | ロケーション決定 | 個別指定→発注明細→発注書→部品デフォルトの順で決定 | 在庫生成時 |
| BR-14-04 | 単価変換 | サプライヤー部品の基準数量で購入価格を変換 | 在庫生成時 |
| BR-14-05 | 通貨変換 | PURCHASEORDER_CONVERT_CURRENCY設定時に基準通貨へ変換 | 在庫生成時 |
| BR-14-06 | 自動完了 | PURCHASEORDER_AUTO_COMPLETE設定時、全明細完了で発注書を完了 | 受領完了時 |
| BR-14-07 | 外部製造連携 | 外部ビルドオーダー連携時は製造出力として処理 | 外部製造明細の受領時 |

### 計算ロジック

**単価計算（基準単位あたり）**:
```python
if line.purchase_price:
    purchase_price = line.purchase_price / supplier_part.base_quantity(1)
    if convert_purchase_price:
        purchase_price = convert_money(purchase_price, default_currency)
```

**在庫数量計算（基準単位変換）**:
```python
stock_quantity = supplier_part.base_quantity(quantity)
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 在庫生成 | stock_stockitem | INSERT | bulk_createによる一括登録 |
| 追跡記録 | stock_stockitemtracking | INSERT | bulk_createによる一括登録 |
| 受領更新 | order_purchaseorderlineitem | UPDATE | bulk_updateでreceived更新 |
| 自動完了 | order_purchaseorder | UPDATE | status→COMPLETE |

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

#### stock_stockitem（INSERT）

| 項目（カラム名） | 値 | 備考 |
|-----------------|-----|------|
| part_id | サプライヤー部品の基準部品 | FK: part_part |
| supplier_part_id | サプライヤー部品 | FK: company_supplierpart |
| purchase_order_id | 発注書 | FK: order_purchaseorder |
| location_id | 受入先ロケーション | FK: stock_stocklocation |
| quantity | 受領数量（基準単位） | DecimalField |
| purchase_price | 購入価格（基準単位あたり） | MoneyField |
| batch | バッチコード | CharField |
| expiry_date | 有効期限 | DateField |
| serial | シリアル番号 | CharField |
| status | 在庫ステータス | カスタムステータス対応 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| order_not_placed | ValidationError | 発注書がPLACED以外 | 発注書を発行してから受領 |
| quantity_invalid | ValidationError | 受領数量が負 | 正の数量を入力 |
| line_item_mismatch | ValidationError | 明細が発注書に属さない | 正しい明細を選択 |
| part_missing | ValidationError | 明細に部品が紐づいていない | 明細を確認 |
| build_order_not_external | ValidationError | 内部ビルドオーダーへの受領 | 外部ビルドオーダーを使用 |

### リトライ仕様

- 一括登録失敗時：トランザクション全体をロールバック
- 部分的な成功は許可しない

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

- receive_line_items()全体が@transaction.atomicで保護
- 在庫生成→追跡記録→受領更新→自動完了が一つのトランザクション
- エラー発生時は全てロールバック

## パフォーマンス要件

- 受領処理（10明細まで）：2秒以内
- bulk_createによる一括登録で個別INSERTを回避
- bulk_updateによる一括更新でN+1問題を回避
- prefetch_relatedによる関連データの先読み

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

- 受領実行者がreceived_byとして記録
- 受領履歴がStockItemTrackingに記録
- 発注書の受領イベントがトリガーで通知

## 備考

- シリアル化受領時は_create_serial_numbers()を使用
- 外部ビルドオーダー連携時はis_buildingフラグを設定
- カスタムステータス値の使用に対応

---

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

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

### 推奨読解順序

#### Step 1: エントリーポイントを理解する

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

**読解のコツ**:
- **933-1200行目**: receive_line_items()メソッドの全体構造
- **958-961行目**: PLACEDステータスのチェック
- **975-976行目**: 通貨変換設定の取得

#### Step 2: バリデーション処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | models.py | `src/backend/InvenTree/order/models.py` | 明細バリデーション処理 |

**主要処理フロー**:
- **984-989行目**: prefetch_relatedによる効率的なクエリ
- **994-999行目**: 各明細のバリデーション（発注書一致、部品存在）

#### Step 3: 在庫アイテム生成を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | models.py | `src/backend/InvenTree/order/models.py` | StockItem生成処理 |

**主要処理フロー**:
- **1052-1064行目**: stock_dataの構築
- **1066-1067行目**: ステータスの抽出
- **1107-1115行目**: シリアル化受領の処理
- **1117-1133行目**: 非シリアル化受領の処理

#### Step 4: 一括処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | models.py | `src/backend/InvenTree/order/models.py` | bulk_create/bulk_update処理 |

**主要処理フロー**:
- **1139-1150行目**: StockItemのbulk_create
- **1167-1168行目**: StockItemTrackingのbulk_create
- **1170-1171行目**: PurchaseOrderLineItemのbulk_update

#### Step 5: 自動完了・通知を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | models.py | `src/backend/InvenTree/order/models.py` | 自動完了判定と通知 |

**主要処理フロー**:
- **1180-1186行目**: 自動完了の判定と実行
- **1188-1195行目**: 通知の送信

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

```
PurchaseOrder.receive_line_items()
    │
    ├─ バリデーション
    │      ├─ status == PLACED チェック
    │      └─ 各明細のバリデーション
    │
    ├─ 在庫アイテム生成
    │      ├─ シリアル化判定
    │      │      ├─ _create_serial_numbers()
    │      │      └─ set_status()
    │      │
    │      └─ 非シリアル化
    │             ├─ StockItem()
    │             ├─ set_status()
    │             └─ assign_barcode()
    │
    ├─ bulk_create()
    │      └─ StockItem.objects.bulk_create()
    │
    ├─ 追跡履歴記録
    │      └─ StockItemTracking.objects.bulk_create()
    │
    ├─ 受領数量更新
    │      └─ PurchaseOrderLineItem.objects.bulk_update()
    │
    ├─ 自動完了判定
    │      └─ complete_order()
    │
    └─ 通知送信
           └─ notify_responsible()
```

### データフロー図

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

受領情報         ───▶ バリデーション          ───▶ ValidationError
  (items)               │                           (エラー時)
                        │
                        ▼
                  在庫データ構築
                        │
                        ├─ シリアル化
                        │      └─ _create_serial_numbers
                        │
                        └─ 非シリアル化
                               └─ StockItem構築
                        │
                        ▼
                  bulk_create            ───▶ stock_stockitem
                        │                       テーブル
                        │
                        ▼
                  追跡履歴記録           ───▶ stock_stockitemtracking
                        │                       テーブル
                        │
                        ▼
                  受領数量更新           ───▶ order_purchaseorderlineitem
                        │                       テーブル
                        │
                        ▼
                  自動完了判定           ───▶ order_purchaseorder
                        │                       テーブル
                        │
                        ▼
                  通知送信               ───▶ 通知システム
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| models.py | `src/backend/InvenTree/order/models.py` | ソース | receive_line_items()メソッド |
| models.py | `src/backend/InvenTree/stock/models.py` | ソース | StockItem、StockItemTrackingモデル |
| api.py | `src/backend/InvenTree/order/api.py` | ソース | 受領APIエンドポイント |
| serializers.py | `src/backend/InvenTree/order/serializers.py` | ソース | 受領シリアライザー |
| status_codes.py | `src/backend/InvenTree/stock/status_codes.py` | ソース | StockStatusの定義 |
| events.py | `src/backend/InvenTree/order/events.py` | ソース | ITEM_RECEIVEDイベント |
