# 機能設計書 19-在庫アイテム編集

## 概要

本ドキュメントは、InvenTreeモバイルアプリにおける在庫アイテム編集機能の設計仕様を定義する。

### 本機能の処理概要

本機能は、既存の在庫アイテムの属性を編集する機能である。シリアル番号、ステータス、バッチコード、価格情報、梱包情報、リンク等の属性を変更できる。

**業務上の目的・背景**：在庫管理業務において、在庫アイテムの属性変更は必要に応じて発生する。シリアル番号の修正、ステータスの変更、バッチコードの更新など、様々な理由で在庫情報を更新する必要がある。モバイルアプリから直接編集できることで、現場での迅速な情報更新が可能となる。

**機能の利用シーン**：
- シリアル番号を修正する場合
- 在庫ステータスを変更する場合（良品→不良品等）
- バッチコード情報を更新する場合
- 購入価格情報を追加・修正する場合
- 梱包情報を変更する場合

**主要な処理内容**：
1. 編集フォームの表示（現在値をデフォルト表示）
2. 入力値のバリデーション
3. APIリクエストによる在庫アイテムの更新
4. 更新成功時の画面リフレッシュ

**関連システム・外部連携**：InvenTree APIの `stock/{pk}/` エンドポイント（PATCH）を使用して在庫アイテムを更新する。

**権限による制御**：`stock` ロールの `change` 権限が必要である。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 25 | 在庫アイテム詳細画面 | 主画面 | 編集メニュー選択時に編集フォーム表示 |

## 機能種別

データ更新（UPDATE）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| serial | String | No | シリアル番号 | trackableパーツのみ |
| status | int | No | 在庫ステータス | ステータスコード |
| batch | String | No | バッチコード | - |
| purchase_price | double | No | 購入価格 | 正の数値 |
| purchase_price_currency | String | No | 購入価格通貨 | 通貨コード |
| packaging | String | No | 梱包情報 | - |
| link | String | No | 外部リンク | URL形式 |

### 入力データソース

- 在庫詳細画面に表示されている在庫アイテムの現在値
- ユーザーによるフォーム入力

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 更新後属性 | - | 入力された各フィールドの更新後の値 |

### 出力先

- InvenTreeデータベース（StockItemテーブル）
- 在庫詳細画面の表示更新

## 処理フロー

### 処理シーケンス

```
1. 編集フォームの起動
   └─ _editStockItem()を呼び出し
2. フォームフィールドの構築
   └─ formFields()から使用するフィールドを取得
3. 編集不可フィールドの除外
   └─ part, quantity, location, serial_numbersを除外
4. trackableチェック
   └─ 非trackableパーツの場合はserialフィールドも除外
5. ユーザーによる入力
   └─ 各フィールドの値を編集
6. APIリクエストの実行
   └─ PATCH stock/{pk}/ エンドポイントにデータを送信
7. レスポンスの処理
   ├─ 成功：画面をリフレッシュして更新後の値を表示
   └─ 失敗：エラーメッセージを表示
```

### フローチャート

```mermaid
flowchart TD
    A[在庫詳細画面] --> B{canEdit?}
    B -->|No| C[編集メニュー非表示]
    B -->|Yes| D[編集メニュー表示]
    D --> E[ユーザーが編集を選択]
    E --> F[_editStockItem]
    F --> G[formFields取得]
    G --> H[不要フィールド除外]
    H --> I{trackable?}
    I -->|No| J[serialフィールド除外]
    I -->|Yes| K[serialフィールド保持]
    J --> L[editForm呼び出し]
    K --> L
    L --> M[編集フォーム表示]
    M --> N[ユーザー入力]
    N --> O{入力検証}
    O -->|不正| P[エラー表示]
    P --> N
    O -->|正常| Q[PATCH stock/pk/]
    Q --> R{成功?}
    R -->|No| S[エラー表示]
    R -->|Yes| T[画面リフレッシュ]
    T --> U[更新完了メッセージ]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-19-01 | 編集除外フィールド | part, quantity, location, serial_numbersは編集不可 | 常時 |
| BR-19-02 | シリアル番号編集 | trackableパーツの場合のみシリアル番号を編集可能 | part.isTrackable == true |
| BR-19-03 | 現在値表示 | 編集フォームには現在の値がデフォルト表示される | 常時 |
| BR-19-04 | 部分更新 | 変更のあったフィールドのみPATCHで送信 | 常時 |

### 計算ロジック

- 特になし（単純な属性更新）

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 編集 | StockItem | UPDATE | 在庫アイテムの属性を更新 |

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

#### StockItem（InvenTree API経由）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | serial | ユーザー指定のシリアル番号 | trackableパーツのみ |
| UPDATE | status | ユーザー指定のステータス | 任意 |
| UPDATE | batch | ユーザー指定のバッチコード | 任意 |
| UPDATE | purchase_price | ユーザー指定の購入価格 | 任意 |
| UPDATE | purchase_price_currency | ユーザー指定の通貨コード | 任意 |
| UPDATE | packaging | ユーザー指定の梱包情報 | 任意 |
| UPDATE | link | ユーザー指定の外部リンク | 任意 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 400 | バリデーションエラー | 形式不正、シリアル番号重複 | エラーメッセージを表示して再入力を促す |
| 401 | 認証エラー | トークン無効または期限切れ | 再ログインを促す |
| 403 | 権限エラー | change権限がない | 権限確認メッセージを表示 |
| 404 | Not Found | 在庫アイテムが存在しない | エラーメッセージを表示 |
| 500 | サーバーエラー | サーバー内部エラー | リトライまたはエラー表示 |

### リトライ仕様

サーバーエラー時は手動でフォームを再送信可能。

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

単一レコードの更新のため、明示的なトランザクション管理は不要。

## パフォーマンス要件

- フォーム表示は即座に行う
- API応答は通常数秒以内

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

- API認証トークンによるアクセス制御
- `stock` ロールの `change` 権限チェック
- HTTPS通信によるデータ保護

## 備考

- 数量の変更は本機能では行わない（数量調整機能を使用）
- ロケーションの変更は本機能では行わない（在庫移動機能を使用）
- パーツの変更は不可（別パーツへの変更は新規作成が必要）

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | stock.dart | `lib/inventree/stock.dart` | InvenTreeStockItemのformFields()を理解する |

**読解のコツ**:
- **193-209行目**: formFields()で編集可能なフィールドを定義
- **197行目**: partフィールド（編集時は除外）
- **198行目**: serialフィールド（trackableパーツのみ）
- **200-206行目**: status, batch, purchase_price, packaging, link等

#### Step 2: 編集フォーム呼び出しを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | stock_detail.dart | `lib/widget/stock/stock_detail.dart` | _editStockItem()メソッドの実装 |

**主要処理フロー**:
- **340-362行目**: _editStockItem()の実装
- **341行目**: formFields()を取得
- **344-347行目**: 編集不可フィールドを除外（part, quantity, location, serial_numbers）
- **349-351行目**: 非trackableパーツの場合はserialフィールドも除外
- **353-361行目**: editForm()を呼び出し、成功時にrefresh()

#### Step 3: editFormメソッドを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | model.dart | `lib/inventree/model.dart` | editForm()の基底実装 |

**主要処理フロー**:
- **301-320行目**: editForm()の実装
- **311-319行目**: launchApiForm()を呼び出し、PATCHメソッドで送信
- **316行目**: modelDataにjsondataを設定（現在値を渡す）

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

```
StockDetailWidget.actionMenuItems()
    │
    └─ _editStockItem()
           │
           ├─ InvenTreeStockItem().formFields()
           │      └─ フィールド定義取得
           │
           ├─ fields.remove("part")
           ├─ fields.remove("quantity")
           ├─ fields.remove("location")
           ├─ fields.remove("serial_numbers")
           │
           ├─ if (!part.isTrackable)
           │      └─ fields.remove("serial")
           │
           └─ widget.item.editForm()
                  │
                  └─ launchApiForm()
                         │
                         ├─ フォーム表示（現在値をデフォルト）
                         │
                         ├─ PATCH stock/{pk}/
                         │      └─ InvenTreeAPI.patch()
                         │
                         └─ onSuccess callback
                                └─ refresh()
                                       └─ showSnackIcon()
```

### データフロー図

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

現在値(jsondata) ───▶ launchApiForm() ───▶ 属性更新
+ ユーザー編集           │                     │
                        ▼                     ▼
               PATCH stock/{pk}/ ───▶ StockItemレコード
                        │                     │
                        ▼                     ▼
               JSON Response ───▶ refresh()
                                       │
                                       ▼
                                画面表示更新
                               (更新後の値を表示)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| stock_detail.dart | `lib/widget/stock/stock_detail.dart` | ソース | 編集フォーム呼び出しの実装 |
| stock.dart | `lib/inventree/stock.dart` | ソース | InvenTreeStockItemモデル、formFields()定義 |
| model.dart | `lib/inventree/model.dart` | ソース | editForm()基底実装 |
| api_form.dart | `lib/api_form.dart` | ソース | launchApiForm()関数 |
| api.dart | `lib/api.dart` | ソース | InvenTree API通信クラス |
| snacks.dart | `lib/widget/snacks.dart` | ソース | 成功/失敗メッセージ表示 |
