# 機能設計書 35-ロケーション管理

## 概要

本ドキュメントは、在庫管理モジュールにおけるロケーション管理機能の設計仕様を定義するものです。倉庫内の保管場所（ロケーション）を階層的に管理し、在庫の正確な位置把握と効率的なピッキングを支援します。

### 本機能の処理概要

ロケーション管理機能は、倉庫内の保管場所を定義・管理する機能です。ロケーションは階層構造（親子関係）を持ち、倉庫 > エリア > 棚 > 段などの論理的な位置を表現できます。また、内部ロケーションだけでなく、仕入先、顧客、中継、製造などの仮想的なロケーションタイプも管理できます。

**業務上の目的・背景**：倉庫内の在庫管理において、商品がどこに保管されているかを正確に把握することは非常に重要です。効率的なピッキングや在庫棚卸を実現するため、保管場所を体系的に定義・管理する必要があります。本機能は、物理的な保管場所だけでなく、仕入先や顧客との取引時の仮想的なロケーションも含めた包括的な位置管理を提供します。

**機能の利用シーン**：
- 新規倉庫のレイアウト設定時にロケーションを登録する場面
- 棚卸計画のために棚卸頻度を設定する場面
- スクラップ用ロケーションを定義する場面
- ロケーションのバーコードラベルを印刷する場面

**主要な処理内容**：
1. ロケーション情報の登録・編集・削除
2. 階層構造（親子関係）の管理
3. ロケーションタイプの設定
4. 棚卸頻度と棚卸予定の管理
5. ストレージカテゴリとの関連付け
6. バーコードラベル印刷

**関連システム・外部連携**：倉庫管理機能と連携し、倉庫に紐づくロケーションを管理します。在庫移動管理機能と連携して入出庫時の移動元・移動先ロケーションを指定します。ストレージカテゴリ管理機能と連携して保管ルールを適用します。

**権限による制御**：在庫設定権限を持つユーザーのみがロケーションの登録・編集・削除を行えます。WarehouseSettings設定でenable_locationsがtrueの場合のみ本機能が有効化されます。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| SCR-INV-002 | LocationResource | 主画面 | ロケーション一覧表示・検索・フィルタ |
| SCR-INV-002 | LocationResource/Create | 参照画面 | 新規ロケーションの作成 |
| SCR-INV-002 | LocationResource/Edit | 参照画面 | 既存ロケーションの編集 |
| SCR-INV-002 | LocationResource/View | 参照画面 | ロケーション詳細の表示 |

## 機能種別

CRUD操作 / マスタ管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| name | string | Yes | ロケーション名 | 最大255文字 |
| parent_id | integer | No | 親ロケーションID | 存在するロケーションであること |
| type | enum | Yes | ロケーションタイプ | LocationType列挙型 |
| company_id | integer | No | 会社ID | 存在する会社であること |
| storage_category_id | integer | No | ストレージカテゴリID | typeがINTERNALの場合のみ、存在するカテゴリ |
| description | text | No | 説明 | リッチテキスト |
| is_scrap | boolean | No | スクラップロケーションフラグ | typeがINTERNALまたはINVENTORYの場合のみ |
| is_dock | boolean | No | ドックロケーションフラグ | - |
| is_replenish | boolean | No | 補充対象フラグ | typeがINTERNALの場合のみ |
| cyclic_inventory_frequency | integer | No | 棚卸頻度（日数） | 0以上の整数 |

### 入力データソース

- 画面入力：ロケーション登録・編集フォームからのユーザー入力
- DBテーブル：inventories_locations（親ロケーション）、supports_companies（会社）、inventories_storage_categories（ストレージカテゴリ）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | integer | ロケーションID |
| name | string | ロケーション名 |
| full_name | string | フルパス名（親/子/孫...） |
| parent.full_name | string | 親ロケーションのフルパス名 |
| type | enum | ロケーションタイプ |
| company.name | string | 会社名 |
| storageCategory.name | string | ストレージカテゴリ名 |
| description | text | 説明 |
| is_scrap | boolean | スクラップロケーションフラグ |
| is_dock | boolean | ドックロケーションフラグ |
| is_replenish | boolean | 補充対象フラグ |
| cyclic_inventory_frequency | integer | 棚卸頻度（日数） |
| last_inventory_date | date | 最終棚卸日 |
| next_inventory_date | date | 次回棚卸予定日 |
| created_at | datetime | 作成日時 |
| updated_at | datetime | 更新日時 |
| deleted_at | datetime | 削除日時 |

### 出力先

- 画面表示：ロケーション一覧画面、詳細画面
- PDF出力：バーコードラベル印刷
- DBテーブル：inventories_locations

## 処理フロー

### 処理シーケンス

```
1. ロケーション一覧表示
   └─ inventories_locationsテーブルからデータ取得
   └─ フィルター・ソート条件を適用
   └─ ページネーション処理
   └─ 一覧画面に表示

2. ロケーション登録
   └─ 入力フォームでデータ入力
   └─ タイプに応じた入力項目の制御
   └─ バリデーション実行
   └─ parent_pathを自動計算
   └─ full_nameを自動計算
   └─ inventories_locationsテーブルにINSERT
   └─ 成功通知表示

3. ロケーション編集
   └─ 既存データを取得してフォームに表示
   └─ データ編集
   └─ バリデーション実行
   └─ full_nameを再計算
   └─ 子ロケーションのfull_nameも連動更新
   └─ inventories_locationsテーブルをUPDATE
   └─ 成功通知表示

4. ロケーション削除
   └─ 削除確認ダイアログ表示
   └─ inventories_locationsテーブルをソフトデリート
   └─ 成功/エラー通知表示

5. バーコード印刷
   └─ 選択されたロケーションを取得
   └─ PDF生成（Location-Barcode.pdf）
   └─ ダウンロード
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{操作種別}
    B -->|一覧表示| C[データ取得]
    C --> D[フィルタ・ソート適用]
    D --> E[一覧表示]

    B -->|登録| F[入力フォーム表示]
    F --> G[ロケーション情報入力]
    G --> H[タイプ選択]
    H --> I{バリデーション}
    I -->|OK| J[parent_path計算]
    J --> K[full_name計算]
    K --> L[DBに保存]
    I -->|NG| G
    L --> M[成功通知]

    B -->|編集| N[既存データ取得]
    N --> O[編集フォーム表示]
    O --> P[データ編集]
    P --> Q{バリデーション}
    Q -->|OK| R[full_name再計算]
    R --> S[子ロケーションfull_name更新]
    S --> T[DBを更新]
    Q -->|NG| P
    T --> U[成功通知]

    B -->|削除| V[削除確認]
    V -->|確認| W{削除実行}
    W -->|成功| X[ソフトデリート]
    W -->|失敗| Y[エラー通知]
    V -->|キャンセル| E

    B -->|印刷| Z[選択レコード取得]
    Z --> AA[PDF生成]
    AA --> AB[ダウンロード]

    E --> AC[終了]
    M --> AC
    U --> AC
    X --> AC
    Y --> AC
    AB --> AC
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-035-001 | タイプデフォルト | ロケーションタイプのデフォルトはINTERNAL | 新規登録時 |
| BR-035-002 | 会社デフォルト | 会社はユーザーのデフォルト会社を設定 | 新規登録時 |
| BR-035-003 | ストレージカテゴリ表示条件 | typeがINTERNALの場合のみストレージカテゴリ選択を表示 | 画面表示時 |
| BR-035-004 | スクラップフラグ表示条件 | typeがINTERNALまたはINVENTORYの場合のみ表示 | 画面表示時 |
| BR-035-005 | 補充フラグ表示条件 | typeがINTERNALの場合のみ表示 | 画面表示時 |
| BR-035-006 | 棚卸設定表示条件 | typeがINTERNALまたはTRANSITの場合のみ表示 | 画面表示時 |
| BR-035-007 | full_name自動生成 | 親ロケーションのfull_name/自身のnameを連結 | 保存時 |
| BR-035-008 | parent_path自動生成 | 親ロケーションのparent_path + 自身のID/ | 保存時 |
| BR-035-009 | 子ロケーション連動更新 | full_name変更時、全子孫のfull_nameも更新 | 編集時 |
| BR-035-010 | VIEWタイプのfull_name | typeがVIEWの場合、full_name = name | 保存時 |
| BR-035-011 | 機能有効化条件 | enable_locations設定がtrueの場合のみ機能有効 | 画面表示時 |

### 計算ロジック

**full_nameの算出**：
```
if (type === VIEW) {
    full_name = name
} else if (parent_id) {
    full_name = parent.full_name + '/' + name
} else {
    full_name = name
}
```

**parent_pathの算出**：
```
if (type === VIEW) {
    parent_path = id + '/'
} else if (parent_id) {
    parent_path = parent.parent_path + id + '/'
} else {
    parent_path = id + '/'
}
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 一覧表示 | inventories_locations | SELECT | ロケーション一覧の取得 |
| 登録 | inventories_locations | INSERT | 新規ロケーションの登録 |
| 編集 | inventories_locations | UPDATE | 既存ロケーションの更新 |
| 編集 | inventories_locations | UPDATE | 子孫ロケーションのfull_name/parent_path更新 |
| 削除 | inventories_locations | UPDATE | ソフトデリート（deleted_at設定） |
| 復元 | inventories_locations | UPDATE | deleted_atをNULLに |
| 完全削除 | inventories_locations | DELETE | 物理削除 |

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

#### inventories_locations

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | name | フォーム入力値 | ロケーション名 |
| INSERT | full_name | 自動計算 | フルパス名 |
| INSERT | parent_id | フォーム入力値 | 親ロケーションID |
| INSERT | parent_path | 自動計算 | パスID連結 |
| INSERT | type | フォーム入力値（デフォルトINTERNAL） | タイプ |
| INSERT | company_id | フォーム入力値 | 会社ID |
| INSERT | storage_category_id | フォーム入力値 | ストレージカテゴリID |
| INSERT | description | フォーム入力値 | 説明 |
| INSERT | is_scrap | フォーム入力値 | スクラップフラグ |
| INSERT | is_dock | フォーム入力値 | ドックフラグ |
| INSERT | is_replenish | フォーム入力値 | 補充対象フラグ |
| INSERT | cyclic_inventory_frequency | フォーム入力値（デフォルト0） | 棚卸頻度 |
| INSERT | creator_id | 認証ユーザーID | 作成者ID |
| UPDATE | 上記項目 | フォーム入力値 | 更新対象項目 |
| UPDATE | deleted_at | 現在日時 | ソフトデリート時 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| ERR-035-001 | バリデーションエラー | 必須項目未入力 | エラーメッセージ表示、入力画面に戻る |
| ERR-035-002 | 外部キー制約エラー | 存在しない親ロケーション/会社/カテゴリを指定 | エラーメッセージ表示、正しい値を選択 |
| ERR-035-003 | 削除エラー | 他テーブルから参照されている | エラー通知表示、完全削除をキャンセル |
| ERR-035-004 | 権限エラー | 操作権限がない | アクセス拒否メッセージ表示 |
| ERR-035-005 | 機能無効エラー | enable_locationsがfalse | 画面非表示・ナビゲーション非表示 |

### リトライ仕様

通常のCRUD操作のため、リトライ処理は不要です。DBエラー発生時はエラーメッセージを表示し、ユーザーに再操作を促します。

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

- 登録・更新・削除操作は単一レコードへの操作のため、デフォルトのトランザクション管理を使用
- full_name変更時の子孫更新はsaveQuietlyで再帰処理
- 一括削除時は全レコードの削除を1トランザクションで処理

## パフォーマンス要件

- 一覧表示：1秒以内にレスポンス
- 登録・更新・削除：2秒以内に完了
- 子孫更新（深い階層）：5秒以内に完了
- PDF生成（バーコード印刷）：5秒以内に完了

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

- 在庫設定権限による操作制限
- SQLインジェクション対策（Eloquent ORMによるパラメータバインディング）
- CSRF対策（Laravelのトークン検証）
- XSS対策（Bladeテンプレートによるエスケープ）

## 備考

- Locationモデルは`Webkul\Inventory\Models\Location`を使用
- SoftDeletesトレイトによる論理削除対応
- LocationType列挙型（SUPPLIER/VIEW/INTERNAL/CUSTOMER/INVENTORY/PRODUCTION/TRANSIT）
- ストレージカテゴリはStorageCategoryResourceから直接作成可能
- Barryvdh\DomPDF\Facade\Pdfを使用したバーコード印刷機能
