# 機能設計書 16-在庫アイテム作成

## 概要

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

### 本機能の処理概要

本機能は、新規在庫アイテムを作成する機能である。パーツ、ロケーション、数量、シリアル番号等を指定して、新しい在庫レコードを作成する。

**業務上の目的・背景**：在庫管理業務において、入荷処理や製造完了後の在庫登録は基本的な業務である。モバイルアプリから直接在庫を作成できることで、倉庫現場での迅速な在庫登録が可能となり、データ入力のタイムラグを削減できる。また、バーコードスキャンと連携することで、パーツの特定やロケーションの指定を効率化できる。

**機能の利用シーン**：
- 発注品が入荷した際に在庫として登録する場合
- 製造が完了した製品を在庫として登録する場合
- 棚卸し時に新たに発見した在庫を登録する場合
- 特定のロケーションに在庫を追加する場合

**主要な処理内容**：
1. 在庫作成フォームの表示（パーツ、ロケーション、数量等）
2. 入力値のバリデーション
3. APIリクエストによる在庫アイテムの作成
4. 作成成功時の在庫詳細画面への遷移

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

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 22 | 部品詳細画面 | 関連機能 | 在庫作成ボタン押下時に在庫作成フォーム表示 |
| 23 | 在庫ロケーション画面 | 関連機能 | 在庫作成ボタン押下時に在庫作成フォーム表示 |

## 機能種別

データ作成（CREATE）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| part | int | Yes | パーツID | 正の整数、存在確認 |
| location | int | No | ロケーションID | 正の整数、存在確認 |
| quantity | double | Yes | 在庫数量 | 正の数値 |
| serial_numbers | String | No | シリアル番号（複数可） | - |
| status | int | No | 在庫ステータス | ステータスコード |
| batch | String | No | バッチコード | - |
| purchase_price | double | No | 購入価格 | 正の数値 |
| purchase_price_currency | String | No | 購入価格通貨 | 通貨コード |
| packaging | String | No | 梱包情報 | - |
| link | String | No | 外部リンク | URL形式 |

### 入力データソース

- ユーザーによるフォーム入力
- パーツ詳細画面から渡されるパーツID
- ロケーション画面から渡されるロケーションID

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| pk | int | 作成された在庫アイテムの主キー |
| 全入力項目 | - | 入力された値がそのまま保存 |

### 出力先

- InvenTreeデータベース（StockItemテーブル）
- 作成成功時は在庫詳細画面に遷移

## 処理フロー

### 処理シーケンス

```
1. 在庫作成フォームの起動
   └─ InvenTreeStockItem().createForm()を呼び出し
2. フォームフィールドの構築
   └─ formFields()から使用するフィールドを取得
3. 初期値の設定
   ├─ パーツID（呼び出し元から渡された場合）
   └─ ロケーションID（呼び出し元から渡された場合）
4. ユーザーによる入力
   └─ 各フィールドの値を入力
5. APIリクエストの実行
   └─ POST stock/ エンドポイントにデータを送信
6. レスポンスの処理
   ├─ 成功：作成された在庫アイテムの詳細画面へ遷移
   └─ 失敗：エラーメッセージを表示
```

### フローチャート

```mermaid
flowchart TD
    A[在庫作成開始] --> B[createForm呼び出し]
    B --> C[formFields取得]
    C --> D[フォーム表示]
    D --> E[ユーザー入力]
    E --> F{入力検証}
    F -->|不正| G[エラー表示]
    G --> E
    F -->|正常| H[API POST stock/]
    H --> I{作成成功?}
    I -->|No| J[エラー表示]
    J --> E
    I -->|Yes| K[レスポンスからpk取得]
    K --> L[在庫詳細画面へ遷移]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-16-01 | パーツ必須 | 在庫アイテムには必ずパーツを指定する | 常時 |
| BR-16-02 | 数量必須 | 在庫数量は必須（シリアル番号指定時は自動計算） | 常時 |
| BR-16-03 | シリアル番号フォーマット | シリアル番号は範囲指定（1-10）やカンマ区切りが可能 | serial_numbers入力時 |
| BR-16-04 | ロケーション任意 | ロケーションは任意だが、在庫追跡には推奨 | - |
| BR-16-05 | シリアルフィールド除外 | serialフィールドは作成時に除外（serial_numbersを使用） | createForm()呼び出し時 |

### 計算ロジック

- シリアル番号から数量を自動計算（例: "1-10" → 数量10）

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 在庫作成 | StockItem | INSERT | 新規在庫アイテムを作成 |

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

#### StockItem（InvenTree API経由）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | part | ユーザー指定のパーツID | 必須 |
| INSERT | location | ユーザー指定のロケーションID | 任意 |
| INSERT | quantity | ユーザー指定の数量 | 必須 |
| INSERT | serial_numbers | ユーザー指定のシリアル番号 | 任意 |
| INSERT | status | ユーザー指定のステータス | デフォルトあり |
| INSERT | batch | ユーザー指定のバッチコード | 任意 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 400 | バリデーションエラー | 必須項目未入力、形式不正 | エラーメッセージを表示して再入力を促す |
| 401 | 認証エラー | トークン無効または期限切れ | 再ログインを促す |
| 403 | 権限エラー | add権限がない | 権限確認メッセージを表示 |
| 500 | サーバーエラー | サーバー内部エラー | リトライまたはエラー表示 |

### リトライ仕様

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

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

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

## パフォーマンス要件

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

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

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

## 備考

- シリアル番号入力は単一フィールドで複数シリアルを指定可能
- ロケーション画面から呼び出した場合はロケーションIDが自動設定
- パーツ詳細画面から呼び出した場合はパーツIDが自動設定

---

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

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

### 推奨読解順序

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

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

**読解のコツ**:
- **193-209行目**: formFields()で作成時に使用可能なフィールドを定義
- **197-199行目**: part, location, quantityフィールド
- **200行目**: serialフィールド（編集時用）
- **201行目**: serial_numbersフィールド（作成時用）
- **202-206行目**: status, batch, purchase_price等

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | location_display.dart | `lib/widget/stock/location_display.dart` | _newStockItem()メソッドによる在庫作成フォーム呼び出し |
| 2-2 | part_detail.dart | `lib/widget/part/part_detail.dart` | パーツ詳細画面からの在庫作成呼び出し |

**主要処理フロー（location_display.dart）**:
- **262-288行目**: _newStockItem()の実装
- **263行目**: formFields()を取得
- **266行目**: serialフィールドを除外
- **268-271行目**: ロケーションIDが存在する場合は初期値として設定
- **274-287行目**: createForm()を呼び出し、成功時に詳細画面へ遷移

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

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

**主要処理フロー**:
- **274-296行目**: createForm()の実装
- **286-295行目**: launchApiForm()を呼び出し、POSTメソッドで送信

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

```
LocationDisplayWidget._newStockItem() / PartDetailWidget
    │
    ├─ InvenTreeStockItem().formFields()
    │      └─ フィールド定義取得
    │
    ├─ fields.remove("serial")
    │      └─ シリアルフィールド除外
    │
    └─ InvenTreeStockItem().createForm()
           │
           └─ launchApiForm()
                  │
                  ├─ フォーム表示
                  │
                  ├─ POST stock/
                  │      └─ InvenTreeAPI.post()
                  │
                  └─ onSuccess callback
                         └─ InvenTreeStockItem.fromJson()
                                └─ goToDetailPage()
```

### データフロー図

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

ユーザー入力 ───▶ launchApiForm() ───▶ StockItem作成
(part, location,        │                     │
 quantity等)            ▼                     ▼
                 POST stock/ ───▶ StockItemレコード
                        │                     │
                        ▼                     ▼
                 JSON Response ───▶ 在庫詳細画面表示
                 (pk含む)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| stock.dart | `lib/inventree/stock.dart` | ソース | InvenTreeStockItemモデル、formFields()定義 |
| location_display.dart | `lib/widget/stock/location_display.dart` | ソース | ロケーション画面からの在庫作成呼び出し |
| part_detail.dart | `lib/widget/part/part_detail.dart` | ソース | パーツ詳細画面からの在庫作成呼び出し |
| model.dart | `lib/inventree/model.dart` | ソース | createForm()基底実装 |
| api_form.dart | `lib/api_form.dart` | ソース | launchApiForm()関数 |
| api.dart | `lib/api.dart` | ソース | InvenTree API通信クラス |
