# 画面設計書 174-数量管理

## 概要

本ドキュメントは、Aureus ERPシステムにおける「数量管理」画面の設計書です。在庫モジュール（Inventories）のオペレーション機能の一部として、商品の在庫数量を管理・調整するための画面について詳述します。

### 本画面の処理概要

**業務上の目的・背景**：数量管理画面は、倉庫内の商品在庫数量を確認し、棚卸（実地棚卸）を行うための画面です。理論在庫と実際の在庫数量の差異を管理し、在庫調整を行うことで正確な在庫管理を実現します。

**画面へのアクセス方法**：サイドナビゲーションの「在庫」モジュール内の「オペレーション」クラスターから「数量」を選択してアクセスします。URLは `/inventories/operations/quantities` です。

**主要な操作・処理内容**：
1. 在庫数量の確認：ロケーション別、商品別の在庫数量を一覧表示
2. 棚卸数量の入力：counted_quantity列で実地棚卸数量を入力
3. 差異の確認：理論在庫と棚卸数量の差異を表示
4. 在庫調整の適用：Applyアクションで棚卸結果を反映
5. 棚卸のクリア：Clearアクションで棚卸入力をリセット
6. フィルタリング：PresetViewによる各種フィルタ表示

**画面遷移**：
- この画面から：各商品詳細、ロット詳細へのリンク
- この画面に：サイドナビゲーションから遷移

**権限による表示制御**：数量管理の権限を持つユーザーのみがアクセス可能です。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| FN-INV-010 | 数量管理 | 主機能 | 在庫数量の管理・棚卸 |

## 画面種別

管理画面（ManageRecords）

## URL/ルーティング

| 項目 | 値 |
|------|-----|
| URL | `/inventories/operations/quantities` |
| ルート名 | `filament.inventories.resources.quantities.index` |
| Resource | `QuantityResource` |
| Page | `ManageQuantities` |

## 画面構成

```
+----------------------------------------------------------+
| タイトル: 数量管理                                        |
+----------------------------------------------------------+
| [プリセットビュータブ]                                    |
| [内部ロケーション] [トランジット] [手持ち] [棚卸予定]    |
| [適用待ち]                                               |
+----------------------------------------------------------+
| [ヘッダーアクション] [新規作成]                           |
+----------------------------------------------------------+
| [フィルター] [検索] [列表示設定] [グループ化]             |
+----------------------------------------------------------+
| ┌─ テーブル ─────────────────────────────────────────┐    |
| │ ロケーション | 商品 | ロット | パッケージ |            │ |
| │ 利用可能数量 | 手持ち | 棚卸数量 | 差異 | 予定日 |     │ |
| │ ユーザー |                                            │ |
| │ [適用] [クリア]                                       │ |
| └──────────────────────────────────────────────────────┘  |
+----------------------------------------------------------+
```

## プリセットビュー

| No | ビュー名 | アイコン | フィルタ条件 | 説明 |
|----|---------|---------|-------------|------|
| 1 | 内部ロケーション | building-office | location.type = INTERNAL | 内部ロケーションの在庫のみ |
| 2 | トランジットロケーション | truck | location.type = TRANSIT | トランジットロケーションの在庫のみ |
| 3 | 手持ち | clipboard-document-list | quantity > 0 | 在庫がある商品のみ |
| 4 | 棚卸予定 | calculator | scheduled_at > now() | 棚卸予定日が未来の商品 |
| 5 | 適用待ち | check-circle | inventory_quantity_set = true | 棚卸入力済みで適用待ちの商品 |

## 入出力項目

### 新規作成フォーム

| No | 項目名 | 項目ID | 型 | 必須 | 入力/出力 | 説明 |
|----|--------|--------|-----|------|-----------|------|
| 1 | ロケーション | location_id | Select | ○ | 入力 | 内部ロケーションを選択（enable_locations有効時のみ表示） |
| 2 | 商品 | product_id | Select | ○ | 入力 | 保管可能な商品を選択 |
| 3 | ロット | lot_id | Select | - | 入力 | ロット/シリアル番号を選択（LOTトラッキング商品のみ） |
| 4 | パッケージ | package_id | Select | - | 入力 | パッケージを選択（enable_packages有効時のみ） |
| 5 | 棚卸数量 | counted_quantity | TextInput | ○ | 入力 | 棚卸で確認した数量 |
| 6 | 予定日 | scheduled_at | DatePicker | - | 入力 | 次回棚卸予定日 |

## テーブル表示項目

| No | 項目名 | 項目ID | 型 | ソート | 検索 | 説明 |
|----|--------|--------|-----|--------|------|------|
| 1 | ロケーション | location.full_name | TextColumn | ○ | ○ | ロケーション名（enable_locations有効時のみ） |
| 2 | ストレージカテゴリ | storageCategory.name | TextColumn | ○ | ○ | ストレージカテゴリ（デフォルト非表示） |
| 3 | 商品 | product.name | TextColumn | ○ | ○ | 商品名 |
| 4 | 商品カテゴリ | product.category.name | TextColumn | ○ | ○ | 商品カテゴリ（デフォルト非表示） |
| 5 | ロット | lot.name | TextColumn | ○ | ○ | ロット名（enable_lots_serial_numbers有効時のみ） |
| 6 | パッケージ | package.name | TextColumn | ○ | ○ | パッケージ名（enable_packages有効時のみ） |
| 7 | 利用可能数量 | available_quantity | TextColumn | ○ | - | 利用可能な数量（デフォルト非表示） |
| 8 | 手持ち数量 | quantity | TextColumn | ○ | - | 現在の在庫数量 |
| 9 | 棚卸数量 | counted_quantity | TextInputColumn | ○ | - | 棚卸で入力した数量（インライン編集可能） |
| 10 | 差異 | inventory_diff_quantity | TextColumn | ○ | - | 差異（棚卸数量 - 手持ち数量）、プラスは緑、マイナスは赤 |
| 11 | 予定日 | scheduled_at | TextColumn | ○ | - | 次回棚卸予定日 |
| 12 | ユーザー | user.name | TextColumn | ○ | - | 担当ユーザー |
| 13 | 会社 | company.name | TextColumn | ○ | - | 会社（デフォルト非表示） |

## グループ化オプション

| No | グループ名 | グループID | 説明 |
|----|----------|----------|------|
| 1 | 商品 | product.name | 商品別にグループ化 |
| 2 | 商品カテゴリ | product.category.full_name | 商品カテゴリ別にグループ化 |
| 3 | ロケーション | location.full_name | ロケーション別にグループ化（enable_locations有効時） |
| 4 | ストレージカテゴリ | storageCategory.name | ストレージカテゴリ別にグループ化（enable_locations有効時） |
| 5 | ロット | lot.name | ロット別にグループ化（enable_lots_serial_numbers有効時） |
| 6 | パッケージ | package.name | パッケージ別にグループ化（enable_packages有効時） |
| 7 | 会社 | company.name | 会社別にグループ化 |

## フィルター

QueryBuilderによる高度なフィルタリングが可能です。

| No | フィルタ名 | タイプ | 説明 |
|----|----------|--------|------|
| 1 | ロケーション | RelationshipConstraint | ロケーションで絞り込み |
| 2 | ストレージカテゴリ | RelationshipConstraint | ストレージカテゴリで絞り込み |
| 3 | 商品 | RelationshipConstraint | 商品で絞り込み |
| 4 | 単位 | RelationshipConstraint | 単位で絞り込み（enable_uom有効時） |
| 5 | 商品カテゴリ | RelationshipConstraint | 商品カテゴリで絞り込み |
| 6 | ロット | RelationshipConstraint | ロットで絞り込み |
| 7 | パッケージ | RelationshipConstraint | パッケージで絞り込み |
| 8 | 手持ち数量 | NumberConstraint | 手持ち数量で絞り込み |
| 9 | 差異数量 | NumberConstraint | 差異数量で絞り込み |
| 10 | ユーザー | RelationshipConstraint | ユーザーで絞り込み |
| 11 | 入庫日 | DateConstraint | 入庫日で絞り込み |
| 12 | 予定日 | DateConstraint | 予定日で絞り込み |
| 13 | 作成日 | DateConstraint | 作成日で絞り込み |
| 14 | 更新日 | DateConstraint | 更新日で絞り込み |
| 15 | 会社 | RelationshipConstraint | 会社で絞り込み |
| 16 | 作成者 | RelationshipConstraint | 作成者で絞り込み |

## イベント仕様

### 1-棚卸数量入力（counted_quantity変更）

棚卸数量を入力すると、差異が自動計算されます。

**処理フロー**：
1. counted_quantityの値を検証（数値、0以上）
2. inventory_quantity_setをtrueに設定
3. inventory_diff_quantity（差異）を計算（counted_quantity - quantity）
4. レコードを更新
5. 成功通知を表示

### 2-適用アクション（Apply）

棚卸結果を在庫に反映します。inventory_quantity_setがtrueの場合のみ表示されます。

**処理フロー**：
1. 調整ロケーション（INVENTORY/非スクラップ）を取得
2. 棚卸数量と差異を取得
3. レコードを更新：
   - quantity = counted_quantity
   - counted_quantity = 0
   - inventory_diff_quantity = 0
   - inventory_quantity_set = false
4. 調整ロケーションのProductQuantityを更新/作成
5. 差異がマイナスの場合：
   - ソース = 現在のロケーション、出庫先 = 調整ロケーション
6. 差異がプラスの場合：
   - ソース = 調整ロケーション、出庫先 = 現在のロケーション
7. 在庫移動レコード（Move）を作成
8. 成功通知を表示

### 3-クリアアクション（Clear）

棚卸入力をリセットします。inventory_quantity_setがtrueの場合のみ表示されます。

**処理フロー**：
1. レコードを更新：
   - inventory_quantity_set = false
   - counted_quantity = 0
   - inventory_diff_quantity = 0
2. 成功通知を表示

### 4-新規作成

新しい在庫数量レコードを作成します。

**処理フロー**：
1. フォームバリデーションを実行
2. mutateDataUsingで以下を設定：
   - location_id（未設定の場合はWarehouseのlot_stock_location_id）
   - creator_id = Auth::id()
   - company_id = 商品の会社ID
   - inventory_quantity_set = true
   - inventory_diff_quantity = counted_quantity
   - incoming_at = now()
   - scheduled_at = 設定に基づく次回棚卸日
3. 既存レコードの重複チェック
4. 重複がある場合は警告通知を表示して処理中止
5. ProductQuantityを作成
6. 成功通知を表示

## データベース更新仕様

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 棚卸数量入力 | inventories_product_quantities | UPDATE | 棚卸関連フラグ・数量を更新 |
| 適用アクション | inventories_product_quantities | UPDATE | 在庫数量を確定 |
| 適用アクション | inventories_product_quantities | INSERT/UPDATE | 調整ロケーションの数量を更新 |
| 適用アクション | inventories_moves | INSERT | 在庫移動レコードを作成 |
| クリアアクション | inventories_product_quantities | UPDATE | 棚卸入力をリセット |
| 新規作成 | inventories_product_quantities | INSERT | 新規在庫数量レコードを作成 |

### テーブル別更新項目詳細

#### inventories_product_quantities（棚卸数量入力時）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | counted_quantity | 入力値 | - |
| UPDATE | inventory_quantity_set | true | - |
| UPDATE | inventory_diff_quantity | counted_quantity - quantity | 差異計算 |
| UPDATE | updated_at | now() | 自動 |

#### inventories_product_quantities（適用時）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | quantity | counted_quantity | 棚卸数量を反映 |
| UPDATE | counted_quantity | 0 | リセット |
| UPDATE | inventory_diff_quantity | 0 | リセット |
| UPDATE | inventory_quantity_set | false | リセット |
| UPDATE | updated_at | now() | 自動 |

## メッセージ仕様

| No | 種別 | タイミング | メッセージ内容 | 備考 |
|----|------|----------|---------------|------|
| 1 | 成功 | 棚卸数量更新時 | 棚卸数量が正常に更新されました | 通知で表示 |
| 2 | 成功 | 適用完了時 | 棚卸が正常に適用されました | 通知で表示 |
| 3 | 成功 | クリア完了時 | 棚卸がクリアされました | 通知で表示 |
| 4 | 成功 | 新規作成時 | 数量が正常に作成されました | 通知で表示 |
| 5 | 警告 | 重複時 | 同じ条件の在庫レコードが既に存在します | 通知で表示 |

## 例外処理

| No | 例外条件 | 処理内容 | 表示メッセージ |
|----|----------|----------|---------------|
| 1 | 必須項目未入力 | フォームバリデーションエラー | 各フィールドの必須エラーメッセージ |
| 2 | 数値バリデーションエラー | 入力値エラー | 0以上の数値を入力してください |
| 3 | 重複レコード | 処理中止 | 同じ条件の在庫レコードが既に存在します |
| 4 | 権限不足 | アクセス拒否 | この操作を行う権限がありません |

## 備考

- HasTableViewsトレイトを使用してプリセットビューを実装
- ロケーション機能（enable_locations）、ロット/シリアル番号機能（enable_lots_serial_numbers）、パッケージ機能（enable_packages）は設定により表示/非表示が切り替わる
- 単位機能（enable_uom）は設定により表示/非表示が切り替わる
- 棚卸数量列はTextInputColumnでインライン編集可能
- 差異列は正の値は緑（success）、負の値は赤（danger）で表示
- デフォルトで内部ロケーション（INTERNAL）とトランジットロケーション（TRANSIT）の在庫のみ表示
- 削除済みの商品は表示しない（whereNull('deleted_at')）
- 次回棚卸予定日はOperationSettingsの年次棚卸日設定から自動計算
