Add rice transplant planning feature

This commit is contained in:
akira
2026-04-04 17:26:55 +09:00
parent f236fe2f90
commit 0c57dd7886
15 changed files with 1458 additions and 13 deletions

View File

@@ -0,0 +1,308 @@
# マスタードキュメント:田植え計画機能
> **作成**: 2026-04-04
> **最終更新**: 2026-04-04
> **対象機能**: 田植え計画(年度・品種を軸に複数回作成できる苗箱・種もみ使用量計画)
> **実装状況**: MVP実装完了
---
## 概要
農業生産者が「年度 × 品種」を軸に、田植え前の播種・育苗準備量を見積もる機能。
各圃場について「反当何枚の苗箱を使うか」「苗箱1枚あたり種もみを何g使うか」を記録し、圃場別・計画全体の苗箱枚数と種もみ使用量を自動集計する。
圃場候補は既存の作付け計画から自動取得し、種もみ在庫は作物単位、反当苗箱枚数の初期値は品種単位で管理する。
同じ年度・同じ品種でも、播種時期や育苗ロットを分けるために複数の田植え計画を作成できる。
### 機能スコープIN / OUT
| IN実装済み | OUT対象外 |
|---|---|
| 田植え計画の作成・編集・削除 | 育苗日程のカレンダー管理 |
| 作付け計画からの候補圃場自動取得 | 実播種実績の記録 |
| 圃場ごとの苗箱枚数/反の個別調整 | 種もみロット管理 |
| 圃場ごとの種もみg/箱の個別調整 | 在庫の自動引当 |
| 苗箱合計・種もみkg合計の自動集計 | PDF出力 |
| 作物ごとの種もみ在庫kg管理 | 品種ごとの播種日管理 |
| 品種ごとの反当苗箱枚数デフォルト管理 | |
---
## 業務ルール
1. 田植え計画は `年度 × 品種` を軸に作成する
2. 対象圃場は、その年度・品種の作付け計画が登録されている圃場から取得する
3. 種もみ在庫は作物単位で管理する
4. 反当苗箱枚数の初期値は品種単位で管理する
5. ただし実際の計画値は圃場単位で上書きできる
6. 種もみg/箱は計画全体のデフォルト値を持ちつつ、圃場単位で上書きできる
7. 在庫不足はエラーで保存停止せず、一覧・編集画面で残在庫見込みとして可視化する
8. 同じ年度・同じ品種で複数の計画を作成してよい
9. 複数回に分ける場合は、`計画名` で「第1回」「第2回」「4/10播種分」などを区別する
---
## 計算式
### 圃場ごとの苗箱合計
`苗箱合計 = 圃場面積(反) × 反当苗箱枚数`
### 圃場ごとの種もみ使用量
`種もみkg = 苗箱合計 × 苗箱1枚あたり種もみ(g) ÷ 1000`
### 計画全体の残在庫見込み
`残在庫見込み = 作物の種もみ在庫(kg) - 計画全体の種もみkg合計`
---
## データモデル
### Crop作物マスタ
既存 `plans.Crop` に以下を追加。
| フィールド | 型 | 制約 | 説明 |
|---|---|---|---|
| seed_inventory_kg | decimal(10,3) | default=0 | 作物単位の種もみ在庫(kg) |
### Variety品種マスタ
既存 `plans.Variety` に以下を追加。
| フィールド | 型 | 制約 | 説明 |
|---|---|---|---|
| default_seedling_boxes_per_tan | decimal(6,2) | default=0 | 反当苗箱枚数の初期値 |
### RiceTransplantPlan田植え計画
| フィールド | 型 | 制約 | 説明 |
|---|---|---|---|
| id | int | PK | |
| name | varchar(200) | required | 計画名 |
| year | int | required | 年度 |
| variety | FK(plans.Variety) | PROTECT | 品種 |
| default_seed_grams_per_box | decimal(8,2) | default=0 | 苗箱1枚あたり種もみ(g)の初期値 |
| notes | text | blank | 備考 |
| created_at | datetime | auto | |
| updated_at | datetime | auto | |
- `year + variety` の一意制約は持たない
- 同一年度・同一品種で複数レコード作成可能
#### 表示用計算項目APIレスポンスに含まれる
| 項目 | 型 | 説明 |
|---|---|---|
| field_count | int | 対象圃場数 |
| total_seedling_boxes | decimal | 苗箱枚数合計 |
| total_seed_kg | decimal | 種もみ使用量合計(kg) |
| crop_seed_inventory_kg | decimal | 作物在庫(kg) |
| remaining_seed_kg | decimal | 残在庫見込み(kg) |
### RiceTransplantEntry田植え計画エントリ
| フィールド | 型 | 制約 | 説明 |
|---|---|---|---|
| id | int | PK | |
| plan | FK(RiceTransplantPlan) | CASCADE | |
| field | FK(fields.Field) | CASCADE | |
| seedling_boxes_per_tan | decimal(6,2) | required | 反当苗箱枚数 |
| seed_grams_per_box | decimal(8,2) | required | 苗箱1枚あたり種もみ(g) |
- `unique_together = ['plan', 'field']`
- 順序: `field__display_order, field__id`
#### 表示用計算項目entryレスポンスに含まれる
| 項目 | 型 | 説明 |
|---|---|---|
| field_name | string | 圃場名 |
| field_area_tan | decimal | 圃場面積(反) |
| planned_boxes | decimal | 圃場ごとの苗箱合計 |
| planned_seed_kg | decimal | 圃場ごとの種もみkg |
---
## API エンドポイント
すべて JWT 認証(`Authorization: Bearer <token>`)が必要。
### 田植え計画
| メソッド | URL | 説明 |
|---|---|---|
| GET | `/api/plans/rice-transplant-plans/?year={year}` | 年度別一覧 |
| POST | `/api/plans/rice-transplant-plans/` | 新規作成 |
| GET | `/api/plans/rice-transplant-plans/{id}/` | 詳細取得 |
| PUT/PATCH | `/api/plans/rice-transplant-plans/{id}/` | 更新 |
| DELETE | `/api/plans/rice-transplant-plans/{id}/` | 削除 |
| GET | `/api/plans/rice-transplant-plans/candidate_fields/?year={year}&variety_id={id}` | 作付け計画から候補圃場取得 |
一覧レスポンス例:
```json
{
"id": 1,
"name": "2026年度 コシヒカリ 田植え計画",
"year": 2026,
"variety": 3,
"variety_name": "コシヒカリ",
"crop_name": "水稲",
"default_seed_grams_per_box": "200.00",
"notes": "",
"field_count": 8,
"total_seedling_boxes": "98.40",
"total_seed_kg": "19.680",
"crop_seed_inventory_kg": "25.000",
"remaining_seed_kg": "5.320",
"entries": [
{
"id": 10,
"field": 5,
"field_name": "田中上",
"field_area_tan": "1.2000",
"seedling_boxes_per_tan": "12.00",
"seed_grams_per_box": "200.00",
"planned_boxes": "14.40",
"planned_seed_kg": "2.880"
}
]
}
```
POST/PUT リクエスト例:
```json
{
"name": "2026年度 コシヒカリ 田植え計画",
"year": 2026,
"variety": 3,
"default_seed_grams_per_box": "200.00",
"notes": "",
"entries": [
{
"field_id": 5,
"seedling_boxes_per_tan": "12.00",
"seed_grams_per_box": "200.00"
},
{
"field_id": 6,
"seedling_boxes_per_tan": "11.50",
"seed_grams_per_box": "190.00"
}
]
}
```
更新時は `entries` を全置換する。
### 作物・品種マスタ更新
田植え計画に必要な既定値は既存 API で更新する。
| メソッド | URL | 更新項目 |
|---|---|---|
| PATCH | `/api/plans/crops/{id}/` | `seed_inventory_kg` |
| PATCH | `/api/plans/varieties/{id}/` | `default_seedling_boxes_per_tan` |
---
## 画面仕様
### 1. 田植え計画一覧 `/rice-transplant`
- 年度切替
- 田植え計画の一覧表示
- 同一年度・同一品種の計画が複数並ぶことを想定する
- 表示列:
- 計画名
- 作物 / 品種
- 圃場数
- 苗箱合計
- 種もみ計画kg
- 残在庫見込みkg
- 行アクション:
- 編集
- 削除
### 2. 田植え計画編集 `/rice-transplant/new`, `/rice-transplant/{id}/edit`
- 基本情報:
- 計画名
- 同一年度・同一品種の複数計画を区別できる名称を付ける
- 例: `2026年度 コシヒカリ 第1回`, `2026年度 コシヒカリ 4/15播種分`
- 年度
- 品種
- 苗箱1枚あたり種もみ(g) デフォルト
- 備考
- 対象圃場:
- 品種選択後に作付け計画から候補圃場を自動取得
- 新規作成時は候補圃場を初期選択
- 圃場の追加・除外が可能
- 初期値:
- `反当苗箱枚数` は品種マスタの `default_seedling_boxes_per_tan`
- `種もみg/箱` は計画ヘッダの `default_seed_grams_per_box`
- 圃場テーブル:
- 圃場
- 面積(反)
- 反当苗箱枚数
- 種もみg/箱
- 苗箱合計
- 種もみkg
- サマリー:
- 対象圃場数
- 苗箱合計
- 種もみ計画kg
- 作物在庫kg
- 残在庫見込みkg
- 補助操作:
- 初期値を一括反映
### 3. 品種管理モーダル `/allocation`
既存の作付け計画画面内の品種管理モーダルを拡張。
- 作物単位:
- 種もみ在庫(kg) を更新可能
- 品種単位:
- 反当苗箱枚数デフォルトを更新可能
---
## バリデーション・運用ルール
1. 計画名は必須
2. 品種は必須
3. 圃場は1件以上必要
4. `seedling_boxes_per_tan``seed_grams_per_box` は 0 以上の数値を想定
5. 在庫不足でも保存は許可し、UIで不足を可視化する
6. 候補圃場の抽出元は既存 `Plan`(作付け計画)であるため、先に作付け計画が必要
---
## 既知の制約
1. 種もみ在庫は作物単位のみで、品種別在庫には未対応
2. 田植え計画の PDF 出力は未実装
3. 在庫管理 `materials` app とは未連携で、引当・使用実績は持たない
4. 実播種や田植え実績との連携は未実装
---
## 関連ファイル
| 種別 | パス |
|---|---|
| モデル | `backend/apps/plans/models.py` |
| シリアライザ | `backend/apps/plans/serializers.py` |
| ViewSet | `backend/apps/plans/views.py` |
| URL | `backend/apps/plans/urls.py` |
| マイグレーション | `backend/apps/plans/migrations/0005_crop_seed_inventory_variety_seedling_boxes_and_rice_transplant.py` |
| 一覧画面 | `frontend/src/app/rice-transplant/page.tsx` |
| 編集画面 | `frontend/src/app/rice-transplant/_components/RiceTransplantEditPage.tsx` |
| ナビゲーション | `frontend/src/components/Navbar.tsx` |
| 品種管理モーダル | `frontend/src/app/allocation/page.tsx` |