# 機能設計書 7-在庫ロケーション管理

## 概要

本ドキュメントは、InvenTreeシステムにおける在庫ロケーション管理機能の設計を記述する。在庫ロケーションは倉庫、棚、引き出しなどの物理的な保管場所を階層的に管理し、在庫アイテムの配置と追跡を可能にする。

### 本機能の処理概要

**業務上の目的・背景**：
製造業・物流業において、部品や製品の保管場所を正確に管理することは、ピッキング効率の向上、在庫の可視化、棚卸作業の効率化に不可欠である。在庫ロケーション管理機能は、倉庫→エリア→棚→段→箱のような多階層の保管場所をツリー構造で管理し、各ロケーションのオーナー設定、外部ロケーション区分、構造的ロケーション（直接配置不可）など、柔軟な設定を提供する。

**機能の利用シーン**：
- 倉庫レイアウトに合わせた保管場所の階層構造を定義する場面
- 部品のピッキング時に保管場所を特定する場面
- 棚卸作業でロケーション単位の在庫確認を行う場面
- ロケーション別の在庫レポートを出力する場面
- 外部倉庫（協力会社、保管サービス等）を区別して管理する場面

**主要な処理内容**：
1. ロケーションの作成・編集・削除（階層構造の維持）
2. ロケーション内の在庫アイテム一覧取得
3. オーナー（責任者）の設定と権限管理
4. 構造的ロケーション（部品を直接配置不可）の設定
5. 外部ロケーションフラグの管理
6. ロケーションタイプの分類

**関連システム・外部連携**：
- StockItem（在庫アイテム）との連携
- Part（部品）との連携（デフォルトロケーション）
- StockLocationType（ロケーションタイプ）との連携
- Owner（オーナー）との連携
- バーコード/QRコードシステムとの連携

**権限による制御**：
- ロケーションの閲覧は一般ユーザーでも可能
- ロケーションの作成・編集にはstock.change_stocklocation権限が必要
- オーナー設定時はSTOCK_OWNERSHIP_CONTROL設定による追加制御

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 15 | 在庫ロケーション一覧・詳細画面 | 主機能 | ロケーションの表示・編集・削除 |
| 16 | 在庫アイテム詳細画面 | 参照画面 | 在庫アイテムのロケーション参照 |

## 機能種別

CRUD操作 / 階層データ管理 / 権限管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| name | string | Yes | ロケーション名 | 最大100文字、空文字不可 |
| parent | integer | No | 親ロケーションID | 有効なStockLocationのID |
| description | string | No | ロケーション説明 | 最大250文字 |
| owner | integer | No | オーナーID | 有効なOwnerのID |
| structural | boolean | No | 構造的ロケーションフラグ | 既存在庫がある場合はtrue設定不可 |
| external | boolean | No | 外部ロケーションフラグ | |
| location_type | integer | No | ロケーションタイプID | 有効なStockLocationTypeのID |
| icon | string | No | アイコン | 最大100文字、バリデーション済みアイコン形式 |

### 入力データソース

- 画面入力（ロケーション作成・編集フォーム）
- REST API（api-location-list）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| pk | integer | ロケーションの主キー |
| name | string | ロケーション名 |
| pathstring | string | 階層パス文字列 |
| description | string | 説明 |
| parent | integer | 親ロケーションID |
| level | integer | 階層レベル |
| icon | string | アイコン（カスタムまたはタイプから継承） |
| structural | boolean | 構造的ロケーションフラグ |
| external | boolean | 外部ロケーションフラグ |
| location_type | integer | ロケーションタイプID |
| owner | integer | オーナーID |
| item_count | integer | 含まれる在庫アイテム数 |

### 出力先

- 画面表示（ロケーションツリー、ロケーション詳細）
- REST API レスポンス
- レポート・ラベル出力

## 処理フロー

### 処理シーケンス

```
1. ロケーション作成
   └─ 親ロケーション検証 → バリデーション実行 → MPTT構造更新 → DB保存

2. ロケーション編集
   └─ 構造的フラグ変更時の在庫存在チェック → バリデーション → 保存

3. ロケーション削除
   ├─ delete_sub_locations=True の場合
   │      └─ 子ロケーションも再帰的に削除
   └─ delete_stock_items=True の場合
          └─ 配下の在庫アイテムも削除

4. 在庫アイテム取得
   └─ cascade=True でサブロケーションを含む / False で直下のみ
```

### フローチャート

```mermaid
flowchart TD
    A[ロケーション操作開始] --> B{操作種別}
    B -->|作成| C[親ロケーション検証]
    C --> D[バリデーション実行]
    D --> E[MPTT構造更新]
    E --> F[DB保存]

    B -->|編集| G{structural変更?}
    G -->|Yes| H{配下に在庫あり?}
    H -->|Yes| I[ValidationError]
    H -->|No| D
    G -->|No| D

    B -->|削除| J{削除オプション確認}
    J --> K[子ロケーション処理]
    K --> L[配下在庫アイテム処理]
    L --> M[MPTT構造更新]
    M --> N[DB削除]

    F --> O[終了]
    N --> O
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | 構造的ロケーション制約 | 構造的ロケーションには在庫アイテムを直接配置不可 | structural=True |
| BR-002 | 既存在庫制約 | 在庫が既に配置されているロケーションはstructural=Trueに変更不可 | stock_item_count > 0 |
| BR-003 | オーナー継承 | オーナーは親ロケーションから継承可能 | 自身にownerが未設定の場合 |
| BR-004 | オーナー権限制御 | STOCK_OWNERSHIP_CONTROL有効時、オーナー以外は在庫操作不可 | 設定有効時 |
| BR-005 | アイコン継承 | アイコンはロケーションタイプから継承可能 | custom_iconが未設定の場合 |
| BR-006 | デフォルトアイコン | STOCK_LOCATION_DEFAULT_ICON設定から取得可能 | タイプもカスタムも未設定の場合 |

### 計算ロジック

```python
# 在庫アイテム数の取得（cascade=True の場合）
def stock_item_count(self, cascade=True):
    return self.get_stock_items(cascade).count()

# アイコン取得ロジック
@property
def icon(self) -> str:
    if self.custom_icon:
        return self.custom_icon
    if self.location_type:
        return self.location_type.icon
    if default_icon := get_global_setting('STOCK_LOCATION_DEFAULT_ICON', cache=True):
        return default_icon
    return ''

# オーナー取得（継承を考慮）
def get_location_owner(self):
    for loc in self.get_ancestors(include_self=True, ascending=True):
        if loc.owner is not None:
            return loc.owner
    return None
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| ロケーション作成 | stock_stocklocation | INSERT | 新規ロケーションレコード挿入 |
| ロケーション編集 | stock_stocklocation | UPDATE | ロケーション情報更新 |
| ロケーション削除 | stock_stocklocation | DELETE | ロケーションレコード削除 |
| タイプ作成 | stock_stocklocationtype | INSERT | ロケーションタイプ挿入 |

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

#### stock_stocklocation

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | name, description, parent_id, owner_id, structural, external, location_type_id, icon, lft, rght, tree_id, level | フォーム入力値、MPTT自動計算値 | MPTTによる階層管理 |
| UPDATE | 上記カラム | フォーム入力値 | structuralの変更は在庫存在チェック後 |
| DELETE | - | pk指定 | MPTT構造の再構築を伴う |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| ValidationError | バリデーションエラー | 構造的ロケーションに在庫が存在する状態でstructural=Trueに変更 | エラーメッセージ表示、変更を拒否 |
| ValidationError | バリデーションエラー | 親ロケーションに自身を指定（循環参照） | エラーメッセージ表示 |

### リトライ仕様

特になし（トランザクション管理による整合性確保）

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

- ロケーション削除時はtransaction.atomic()内で実行
- MPTT構造の更新は自動的にトランザクション管理される
- 子ロケーション・在庫アイテムの一括削除は単一トランザクション内で実行

## パフォーマンス要件

- ロケーションツリーの取得: 1000ロケーションで1秒以内
- 在庫アイテム数集計: cascade=True でも2秒以内
- MPTTによる効率的な階層クエリを活用

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

- アイコンフィールドはvalidate_iconバリデータで検証
- オーナー権限制御（STOCK_OWNERSHIP_CONTROL）
- APIエンドポイントは認証必須

## 備考

- MPTTライブラリ（django-mptt）を使用した階層構造管理
- パス文字列（pathstring）はInvenTreeTreeモデルで自動生成
- バーコード型コードは'SL'

---

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

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

### 推奨読解順序

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

StockLocationモデルとStockLocationTypeモデルの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | models.py | `src/backend/InvenTree/stock/models.py` | StockLocationTypeクラス（59-100行目） |
| 1-2 | models.py | `src/backend/InvenTree/stock/models.py` | StockLocationクラス（121-334行目） |

**読解のコツ**:
- StockLocationはInvenTreeTreeを継承しており、MPTTによる階層管理機能を持つ
- `ITEM_PARENT_KEY = 'location'` は在庫アイテムとの関連を定義
- custom_iconフィールドとiconプロパティでアイコン継承を実現

**主要処理フロー**:
- **121-134行目**: クラス定義とMixin継承
- **150-158行目**: deleteメソッドのオーバーライド（子ロケーション・在庫アイテムの処理オプション）
- **180-188行目**: custom_iconフィールド（db_column='icon'で既存互換）
- **225-242行目**: iconプロパティ（継承ロジック）
- **254-263行目**: get_location_ownerメソッド（オーナー継承）
- **265-284行目**: check_ownershipメソッド（オーナー権限チェック）
- **286-297行目**: cleanメソッド（構造的ロケーションの在庫存在チェック）
- **304-317行目**: get_stock_itemsメソッド（配下在庫取得、cascade対応）

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

APIエンドポイントとシリアライザを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | api.py | `src/backend/InvenTree/stock/api.py` | StockLocationListとStockLocationDetailビュー |
| 2-2 | serializers.py | `src/backend/InvenTree/stock/serializers.py` | StockLocationSerializerの定義 |

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

```
REST API Request
    │
    ├─ StockLocationList (api.py)
    │      ├─ StockLocationSerializer
    │      │      └─ StockLocation.save()
    │      │             ├─ clean()
    │      │             │      └─ stock_item_count() - 在庫存在チェック
    │      │             └─ super().save() - MPTT更新
    │      │
    │      └─ StockLocation.delete()
    │             └─ super().delete() - 子ロケーション・在庫処理
    │
    └─ StockLocationDetail (api.py)
           └─ 同上
```

### データフロー図

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

フォーム入力 ───▶ StockLocationSerializer ───▶ JSONレスポンス
                        │
                        ▼
                 StockLocation.clean()
                        │
                        ▼
                 StockLocation.save()
                        │
                        ▼
                 stock_stocklocation テーブル
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| models.py | `src/backend/InvenTree/stock/models.py` | ソース | StockLocation, StockLocationTypeモデル定義 |
| api.py | `src/backend/InvenTree/stock/api.py` | ソース | REST APIビュー定義 |
| serializers.py | `src/backend/InvenTree/stock/serializers.py` | ソース | シリアライザ定義 |
| models.py | `src/backend/InvenTree/InvenTree/models.py` | ソース | InvenTreeTreeベースクラス |
| LocationDetail.tsx | `src/frontend/src/pages/stock/LocationDetail.tsx` | ソース | フロントエンド詳細画面 |
| admin.py | `src/backend/InvenTree/stock/admin.py` | ソース | 管理画面設定 |
