変更したドキュメント
ファイル 変更内容 14_マスタードキュメント_分配計画編.md 全面改訂: 旧「分配計画」→ 新「運搬計画」。データモデル5テーブル、API仕様、画面UI操作、PDFフォーマットを記載 CLAUDE.md データモデル概要(Distribution* → Delivery* に差し替え)、実装状況セクション、更新履歴を更新 13_マスタードキュメント_施肥計画編.md OUT スコープの「圃場への配置計画」を「運搬計画」への参照に修正 内容を確認して、問題なければ実装に進みます。
This commit is contained in:
@@ -64,7 +64,8 @@
|
|||||||
"Bash(TOKEN=\"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNzczNTY4MTAxLCJpYXQiOjE3NzM0ODE3MDEsImp0aSI6ImM1N2EyNzVjMzkyNTRmMjFiZmUxMzA4ZmU4ZjQ3ZWExIiwidXNlcl9pZCI6Mn0.LOZIpPOHN48YZuf7UBaDrPJfxb12hIm15QRnUPc9sYM\" __NEW_LINE_0b7fd53b80bd968a__ echo \"=== Stock summary \\(should show reserved\\) ===\" curl -s http://localhost:8000/api/materials/stock-summary/?material_type=fertilizer -H \"Authorization: Bearer $TOKEN\")",
|
"Bash(TOKEN=\"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNzczNTY4MTAxLCJpYXQiOjE3NzM0ODE3MDEsImp0aSI6ImM1N2EyNzVjMzkyNTRmMjFiZmUxMzA4ZmU4ZjQ3ZWExIiwidXNlcl9pZCI6Mn0.LOZIpPOHN48YZuf7UBaDrPJfxb12hIm15QRnUPc9sYM\" __NEW_LINE_0b7fd53b80bd968a__ echo \"=== Stock summary \\(should show reserved\\) ===\" curl -s http://localhost:8000/api/materials/stock-summary/?material_type=fertilizer -H \"Authorization: Bearer $TOKEN\")",
|
||||||
"Read(//c/Users/akira/Develop/keinasystem_t02/**)",
|
"Read(//c/Users/akira/Develop/keinasystem_t02/**)",
|
||||||
"Bash(TOKEN=\"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNzczNTY4MTAxLCJpYXQiOjE3NzM0ODE3MDEsImp0aSI6ImM1N2EyNzVjMzkyNTRmMjFiZmUxMzA4ZmU4ZjQ3ZWExIiwidXNlcl9pZCI6Mn0.LOZIpPOHN48YZuf7UBaDrPJfxb12hIm15QRnUPc9sYM\" __NEW_LINE_74a785697e4cd919__ echo \"=== After confirm: stock summary ===\" curl -s http://localhost:8000/api/materials/stock-summary/?material_type=fertilizer -H \"Authorization: Bearer $TOKEN\")",
|
"Bash(TOKEN=\"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNzczNTY4MTAxLCJpYXQiOjE3NzM0ODE3MDEsImp0aSI6ImM1N2EyNzVjMzkyNTRmMjFiZmUxMzA4ZmU4ZjQ3ZWExIiwidXNlcl9pZCI6Mn0.LOZIpPOHN48YZuf7UBaDrPJfxb12hIm15QRnUPc9sYM\" __NEW_LINE_74a785697e4cd919__ echo \"=== After confirm: stock summary ===\" curl -s http://localhost:8000/api/materials/stock-summary/?material_type=fertilizer -H \"Authorization: Bearer $TOKEN\")",
|
||||||
"Bash(git diff:*)"
|
"Bash(git diff:*)",
|
||||||
|
"mcp__serena__find_symbol"
|
||||||
],
|
],
|
||||||
"additionalDirectories": [
|
"additionalDirectories": [
|
||||||
"C:\\Users\\akira\\AppData\\Local\\Temp",
|
"C:\\Users\\akira\\AppData\\Local\\Temp",
|
||||||
|
|||||||
52
CLAUDE.md
52
CLAUDE.md
@@ -191,22 +191,37 @@ FertilizationEntry (施肥エントリ・中間テーブル)
|
|||||||
├── bags(袋数、Decimal)
|
├── bags(袋数、Decimal)
|
||||||
└── unique_together = ['plan', 'field', 'fertilizer']
|
└── unique_together = ['plan', 'field', 'fertilizer']
|
||||||
|
|
||||||
DistributionPlan (分配計画)
|
DeliveryPlan (運搬計画) ← 旧 DistributionPlan を置き換え(2026-03-16 再設計)
|
||||||
├── fertilization_plan (FK to FertilizationPlan, CASCADE)
|
├── year(年度)← 施肥計画へのFK廃止、年度ベースで全施肥計画を横断
|
||||||
├── name(計画名)
|
├── name(計画名)
|
||||||
└── groups → DistributionGroup
|
├── groups → DeliveryGroup
|
||||||
|
└── trips → DeliveryTrip
|
||||||
|
|
||||||
DistributionGroup (分配グループ)
|
DeliveryGroup (配送先グループ)
|
||||||
├── distribution_plan (FK to DistributionPlan, CASCADE)
|
├── delivery_plan (FK to DeliveryPlan, CASCADE)
|
||||||
├── name(グループ名)
|
├── name(グループ名)
|
||||||
├── order(表示順)
|
├── order(表示順)
|
||||||
└── unique_together = ['distribution_plan', 'name']
|
└── unique_together = ['delivery_plan', 'name']
|
||||||
|
|
||||||
DistributionGroupField (グループ圃場割り当て)
|
DeliveryGroupField (グループ圃場割り当て)
|
||||||
├── distribution_plan (FK to DistributionPlan, CASCADE) ← 一意制約用
|
├── delivery_plan (FK to DeliveryPlan, CASCADE) ← 一意制約用
|
||||||
├── group (FK to DistributionGroup, CASCADE)
|
├── group (FK to DeliveryGroup, CASCADE)
|
||||||
├── field (FK to fields.Field, PROTECT)
|
├── field (FK to fields.Field, PROTECT)
|
||||||
└── unique_together = ['distribution_plan', 'field'] ← 1圃場=1グループ/1計画
|
└── unique_together = ['delivery_plan', 'field'] ← 1圃場=1グループ/1計画
|
||||||
|
|
||||||
|
DeliveryTrip (運搬回)
|
||||||
|
├── delivery_plan (FK to DeliveryPlan, CASCADE)
|
||||||
|
├── order(何回目)
|
||||||
|
├── name(任意の名前)
|
||||||
|
├── date(運搬日、nullable、デフォルト=1回目の日付)
|
||||||
|
└── items → DeliveryTripItem
|
||||||
|
|
||||||
|
DeliveryTripItem (運搬明細)
|
||||||
|
├── trip (FK to DeliveryTrip, CASCADE)
|
||||||
|
├── field (FK to fields.Field, PROTECT)
|
||||||
|
├── fertilizer (FK to Fertilizer, PROTECT)
|
||||||
|
├── bags(袋数、Decimal)
|
||||||
|
└── unique_together = ['trip', 'field', 'fertilizer']
|
||||||
```
|
```
|
||||||
|
|
||||||
### 重要な設計判断
|
### 重要な設計判断
|
||||||
@@ -343,12 +358,15 @@ DistributionGroupField (グループ圃場割り当て)
|
|||||||
- 自動計算3方式: 反当袋数(per_tan)、均等配分(even)、反当チッソ(nitrogen)
|
- 自動計算3方式: 反当袋数(per_tan)、均等配分(even)、反当チッソ(nitrogen)
|
||||||
- フロントエンド: `/fertilizer/`(一覧), `/fertilizer/new`・`/fertilizer/[id]/edit`(編集・マトリクス表), `/fertilizer/masters/`(肥料マスタ)
|
- フロントエンド: `/fertilizer/`(一覧), `/fertilizer/new`・`/fertilizer/[id]/edit`(編集・マトリクス表), `/fertilizer/masters/`(肥料マスタ)
|
||||||
- スコープ外(将来): 購入管理
|
- スコープ外(将来): 購入管理
|
||||||
11. **分配計画機能**(2026-03-02 実装):
|
11. **運搬計画機能**(旧・分配計画、2026-03-16 再設計中):
|
||||||
- Django `apps/fertilizer` アプリに3モデル追加(DistributionPlan, DistributionGroup, DistributionGroupField)
|
- 旧 DistributionPlan/Group/GroupField → 新 DeliveryPlan/Group/GroupField/Trip/TripItem に移行
|
||||||
- API(JWT認証): `GET/POST /api/fertilizer/distribution/?year=`, `GET/PUT/DELETE /api/fertilizer/distribution/{id}/`, `GET /api/fertilizer/distribution/{id}/pdf/`
|
- 施肥計画への直接FK廃止 → 年度ベースで全施肥計画を横断
|
||||||
- 施肥計画を元に圃場をカスタムグループに割り当て、グループ×肥料の集計表を生成
|
- 「軽トラ1回分」を基本単位とする運搬回(DeliveryTrip)を追加
|
||||||
- PDF出力(A4横向き・グループ合計行★+圃場サブ行)
|
- 運搬明細(DeliveryTripItem)で圃場×肥料単位の袋数を管理
|
||||||
- フロントエンド: `/distribution/`(一覧), `/distribution/new`・`/distribution/[id]/edit`(編集)
|
- 運搬回ごとの日付記録(作業記録としても機能)
|
||||||
|
- API(JWT認証): `/api/fertilizer/delivery/` 配下
|
||||||
|
- PDF出力(A4横向き・回ごとに1ページ)
|
||||||
|
- フロントエンド: `/distribution/`(一覧・編集)
|
||||||
- マスタードキュメント: `document/14_マスタードキュメント_分配計画編.md`
|
- マスタードキュメント: `document/14_マスタードキュメント_分配計画編.md`
|
||||||
|
|
||||||
### 🚧 既知の課題・技術的負債
|
### 🚧 既知の課題・技術的負債
|
||||||
@@ -503,6 +521,8 @@ docker-compose exec backend python manage.py migrate
|
|||||||
|
|
||||||
## 📝 更新履歴
|
## 📝 更新履歴
|
||||||
|
|
||||||
|
- 2026-03-16: 分配計画を「運搬計画」に再設計。実運用のワークフロー(軽トラ複数回・複数施肥計画混在・肥料指定)に合わせ、DeliveryPlan/Trip/TripItem モデルへ移行。施肥計画へのFK廃止→年度ベース。マスタードキュメント14を全面改訂
|
||||||
|
|
||||||
- 2026-03-05: メール通知機能を更新。MailEmail.account を xserver1〜xserver6 で識別可能に変更。Windmill mail_filter に To ヘッダー宛先補正を追加し、Gmail先行取り込みでも Xserver 宛先ラベルが崩れないよう修正。マスタードキュメント/仕様書を同期。
|
- 2026-03-05: メール通知機能を更新。MailEmail.account を xserver1〜xserver6 で識別可能に変更。Windmill mail_filter に To ヘッダー宛先補正を追加し、Gmail先行取り込みでも Xserver 宛先ラベルが崩れないよう修正。マスタードキュメント/仕様書を同期。
|
||||||
|
|
||||||
- 2026-02-28: Cursor連携を廃止。Claude Code 単独運用に変更。`document/20_Cursor_Claude連携ガイド.md` を削除
|
- 2026-02-28: Cursor連携を廃止。Claude Code 単独運用に変更。`document/20_Cursor_Claude連携ガイド.md` を削除
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
| IN(実装済み) | OUT(対象外) |
|
| IN(実装済み) | OUT(対象外) |
|
||||||
|---|---|
|
|---|---|
|
||||||
| 肥料マスタ管理 | 肥料購入管理 |
|
| 肥料マスタ管理 | 肥料購入管理 |
|
||||||
| 施肥計画の作成・編集・削除 | 圃場への配置計画(置き場所割り当て) |
|
| 施肥計画の作成・編集・削除 | 運搬計画(→ `14_マスタードキュメント_分配計画編.md` 参照) |
|
||||||
| 3方式の自動計算 | 個別作業日報の詳細管理 |
|
| 3方式の自動計算 | 個別作業日報の詳細管理 |
|
||||||
| 作付け計画からの圃場自動取得 | |
|
| 作付け計画からの圃場自動取得 | |
|
||||||
| PDF出力(圃場×肥料マトリクス表) | |
|
| PDF出力(圃場×肥料マトリクス表) | |
|
||||||
|
|||||||
@@ -1,65 +1,140 @@
|
|||||||
# マスタードキュメント:分配計画機能
|
# マスタードキュメント:運搬計画機能(旧・分配計画)
|
||||||
|
|
||||||
> **作成**: 2026-03-02
|
> **作成**: 2026-03-02
|
||||||
> **最終更新**: 2026-03-02
|
> **最終更新**: 2026-03-16
|
||||||
> **対象機能**: 分配計画(施肥計画の圃場をグループ化し配置場所単位で集計)
|
> **対象機能**: 運搬計画(施肥計画の肥料を軽トラで運ぶ単位で計画・記録する)
|
||||||
> **実装状況**: 実装完了
|
> **実装状況**: 再設計中(旧分配計画から運搬計画へ移行)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 概要
|
## 概要
|
||||||
|
|
||||||
施肥計画(FertilizationPlan)で決めた圃場ごとの袋数を、**実際に肥料を配置する場所の単位**でまとめる機能。
|
施肥計画で決めた圃場ごとの肥料袋数を、**軽トラ1回分の積載単位**で運搬計画にまとめる機能。
|
||||||
例:「田中エリアにはA肥料12袋・B肥料6袋を持っていく」という単位で計画・PDF出力できる。
|
実際の作業では一度に全部運べないため、「何回目にどのグループのどの肥料を何袋運ぶか」を計画・記録する。
|
||||||
|
|
||||||
|
### 旧設計(分配計画)からの変更理由
|
||||||
|
|
||||||
|
旧設計は「1つの施肥計画の圃場をグループ分けする」だけだった。
|
||||||
|
実運用で以下のギャップが判明(2026-03-16):
|
||||||
|
|
||||||
|
1. **複数の施肥計画が混在する** - 軽トラには品種をまたいで積む
|
||||||
|
2. **単一の施肥計画が分割される** - 1回で運びきれない
|
||||||
|
3. **全肥料を一度に運ぶわけではない** - 運ぶ肥料を指定する必要がある
|
||||||
|
4. **圃場単位の合計袋数は不要** - グループ×肥料の合計が重要
|
||||||
|
5. **同じグループの圃場を回ごとに分割する** - 載りきらないときは次の回に
|
||||||
|
6. **作業記録でもある** - 運搬した日付を記録したい
|
||||||
|
|
||||||
### 機能スコープ
|
### 機能スコープ
|
||||||
|
|
||||||
| IN(実装済み) | OUT(対象外) |
|
| IN(実装対象) | OUT(対象外) |
|
||||||
|---|---|
|
|---|---|
|
||||||
| 施肥計画を元に圃場をカスタムグループに割り当て | 購入管理 |
|
| 年度単位の運搬計画作成 | 購入管理 |
|
||||||
| グループ×肥料の集計表(画面表示) | 実施記録 |
|
| 配送先グループへの圃場割り当て | 肥料の在庫管理 |
|
||||||
| PDF出力(グループ合計行+圃場サブ行) | |
|
| 運搬回ごとの圃場×肥料割り当て | ルート最適化 |
|
||||||
| グループの順序変更・名前変更 | |
|
| 回ごとの積載合計リアルタイム表示 | |
|
||||||
|
| 圃場を回の間で移動する操作 | |
|
||||||
|
| 「残り全部」一括割り当て | |
|
||||||
|
| 回ごとの運搬日記録 | |
|
||||||
|
| PDF出力(回ごとに1ページ) | |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## データモデル
|
## データモデル
|
||||||
|
|
||||||
### DistributionPlan(分配計画)
|
### 旧モデルからの移行
|
||||||
|
|
||||||
|
| 旧(削除) | 新(追加) | 備考 |
|
||||||
|
|---|---|---|
|
||||||
|
| DistributionPlan | DeliveryPlan | FK(FertilizationPlan) 廃止 → year ベース |
|
||||||
|
| DistributionGroup | DeliveryGroup | ほぼ同等 |
|
||||||
|
| DistributionGroupField | DeliveryGroupField | ほぼ同等 |
|
||||||
|
| (なし) | DeliveryTrip | 新規:運搬回 |
|
||||||
|
| (なし) | DeliveryTripItem | 新規:運搬明細(圃場×肥料単位) |
|
||||||
|
|
||||||
|
### DeliveryPlan(運搬計画)
|
||||||
|
|
||||||
| フィールド | 型 | 制約 | 説明 |
|
| フィールド | 型 | 制約 | 説明 |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| id | int | PK | |
|
| id | int | PK | |
|
||||||
| fertilization_plan | FK(FertilizationPlan) | CASCADE | |
|
| year | int | required | 年度 |
|
||||||
| name | varchar(200) | required | 計画名 |
|
| name | varchar(200) | required | 計画名 |
|
||||||
| created_at / updated_at | datetime | auto | |
|
| created_at / updated_at | datetime | auto | |
|
||||||
|
|
||||||
- `ordering = ['-fertilization_plan__year', 'name']`
|
- `ordering = ['-year', 'name']`
|
||||||
- 1つの施肥計画に対して複数の分配計画を作れる(OneToOneではなくFK)
|
- 施肥計画への直接FK なし(年度ベースで全施肥計画を横断)
|
||||||
|
|
||||||
### DistributionGroup(分配グループ)
|
### DeliveryGroup(配送先グループ)
|
||||||
|
|
||||||
| フィールド | 型 | 制約 | 説明 |
|
| フィールド | 型 | 制約 | 説明 |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| id | int | PK | |
|
| id | int | PK | |
|
||||||
| distribution_plan | FK(DistributionPlan) | CASCADE | |
|
| delivery_plan | FK(DeliveryPlan) | CASCADE | |
|
||||||
| name | varchar(100) | required | グループ名 |
|
| name | varchar(100) | required | グループ名(例: キウイ, 足川北) |
|
||||||
| order | PositiveIntegerField | default=0 | 表示順 |
|
| order | PositiveIntegerField | default=0 | 表示順 |
|
||||||
|
|
||||||
- `unique_together = [['distribution_plan', 'name']]` → 同一計画内でグループ名重複不可
|
- `unique_together = [['delivery_plan', 'name']]`
|
||||||
- `ordering = ['order', 'id']`
|
- `ordering = ['order', 'id']`
|
||||||
|
|
||||||
### DistributionGroupField(グループ圃場割り当て)
|
### DeliveryGroupField(グループ圃場割り当て)
|
||||||
|
|
||||||
| フィールド | 型 | 制約 | 説明 |
|
| フィールド | 型 | 制約 | 説明 |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| id | int | PK | |
|
| id | int | PK | |
|
||||||
| distribution_plan | FK(DistributionPlan) | CASCADE | 一意制約のために冗長保持 |
|
| delivery_plan | FK(DeliveryPlan) | CASCADE | 一意制約用 |
|
||||||
| group | FK(DistributionGroup) | CASCADE | |
|
| group | FK(DeliveryGroup) | CASCADE | |
|
||||||
| field | FK(fields.Field) | PROTECT | 圃場 |
|
| field | FK(fields.Field) | PROTECT | |
|
||||||
|
|
||||||
- `unique_together = [['distribution_plan', 'field']]` → 1圃場=1グループ/1計画
|
- `unique_together = [['delivery_plan', 'field']]` → 1圃場=1グループ/1計画
|
||||||
- `ordering = ['field__display_order', 'field__id']`
|
|
||||||
|
### DeliveryTrip(運搬回)
|
||||||
|
|
||||||
|
| フィールド | 型 | 制約 | 説明 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| id | int | PK | |
|
||||||
|
| delivery_plan | FK(DeliveryPlan) | CASCADE | |
|
||||||
|
| order | PositiveIntegerField | default=0 | 何回目(表示順) |
|
||||||
|
| name | varchar(100) | blank | 任意の名前(例: "たちはるか電気炉さい") |
|
||||||
|
| date | DateField | nullable | 運搬日(デフォルト: 1回目の日付を引き継ぎ) |
|
||||||
|
|
||||||
|
- `ordering = ['order', 'id']`
|
||||||
|
|
||||||
|
### DeliveryTripItem(運搬明細)
|
||||||
|
|
||||||
|
| フィールド | 型 | 制約 | 説明 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| id | int | PK | |
|
||||||
|
| trip | FK(DeliveryTrip) | CASCADE | |
|
||||||
|
| field | FK(fields.Field) | PROTECT | |
|
||||||
|
| fertilizer | FK(Fertilizer) | PROTECT | |
|
||||||
|
| bags | Decimal(10,4) | required | 袋数 |
|
||||||
|
|
||||||
|
- `unique_together = [['trip', 'field', 'fertilizer']]`
|
||||||
|
- bags は施肥計画の FertilizationEntry から自動計算で初期値を設定するが、手動上書きも可能
|
||||||
|
|
||||||
|
### ER図(概念)
|
||||||
|
|
||||||
|
```
|
||||||
|
DeliveryPlan (運搬計画)
|
||||||
|
├── year, name
|
||||||
|
│
|
||||||
|
├── groups → DeliveryGroup (配送先グループ)
|
||||||
|
│ ├── name, order
|
||||||
|
│ └── fields → DeliveryGroupField → Field
|
||||||
|
│
|
||||||
|
└── trips → DeliveryTrip (運搬回)
|
||||||
|
├── order, name, date
|
||||||
|
└── items → DeliveryTripItem
|
||||||
|
├── field → Field
|
||||||
|
├── fertilizer → Fertilizer
|
||||||
|
└── bags
|
||||||
|
```
|
||||||
|
|
||||||
|
### 袋数の算出ルール
|
||||||
|
|
||||||
|
1. 運搬計画作成時、年度の全 FertilizationEntry を参照して「グループ×肥料→圃場×袋数」を自動算出
|
||||||
|
2. ユーザーが運搬回に圃場を割り当てると、該当する FertilizationEntry の bags が DeliveryTripItem.bags にコピーされる
|
||||||
|
3. 手動で bags を上書きすることも可能(施肥計画との差異は許容)
|
||||||
|
4. 「残り全部」操作: 施肥計画の合計 − 既に割り当て済みの回の合計 = 残り
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -69,143 +144,209 @@
|
|||||||
|
|
||||||
| メソッド | URL | 説明 |
|
| メソッド | URL | 説明 |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| GET | `/api/fertilizer/distribution/?year={year}` | 一覧(年度フィルタ) |
|
| GET | `/api/fertilizer/delivery/?year={year}` | 一覧(年度フィルタ) |
|
||||||
| POST | `/api/fertilizer/distribution/` | 新規作成 |
|
| POST | `/api/fertilizer/delivery/` | 新規作成 |
|
||||||
| GET | `/api/fertilizer/distribution/{id}/` | 詳細(groups/entries/unassigned込み) |
|
| GET | `/api/fertilizer/delivery/{id}/` | 詳細(groups/trips/items 込み) |
|
||||||
| PUT | `/api/fertilizer/distribution/{id}/` | 更新(groups全置換) |
|
| PUT | `/api/fertilizer/delivery/{id}/` | 更新(groups・trips 全置換) |
|
||||||
| DELETE | `/api/fertilizer/distribution/{id}/` | 削除 |
|
| DELETE | `/api/fertilizer/delivery/{id}/` | 削除 |
|
||||||
| GET | `/api/fertilizer/distribution/{id}/pdf/` | PDF出力(application/pdf) |
|
| GET | `/api/fertilizer/delivery/{id}/pdf/` | PDF出力 |
|
||||||
|
|
||||||
### 一覧レスポンス(DistributionPlanListSerializer)
|
### 一覧レスポンス
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"name": "2025年コシヒカリ 分配計画",
|
"year": 2026,
|
||||||
"fertilization_plan_id": 3,
|
"name": "2026春 肥料運搬",
|
||||||
"fertilization_plan_name": "2025年コシヒカリ施肥計画",
|
"group_count": 5,
|
||||||
"year": 2025,
|
"trip_count": 3,
|
||||||
"variety_name": "コシヒカリ",
|
|
||||||
"crop_name": "米",
|
|
||||||
"group_count": 3,
|
|
||||||
"field_count": 12,
|
|
||||||
"created_at": "...",
|
"created_at": "...",
|
||||||
"updated_at": "..."
|
"updated_at": "..."
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 詳細レスポンス(DistributionPlanReadSerializer)
|
### 詳細レスポンス
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"name": "2025年コシヒカリ 分配計画",
|
"year": 2026,
|
||||||
"fertilization_plan": {
|
"name": "2026春 肥料運搬",
|
||||||
"id": 3,
|
|
||||||
"name": "2025年コシヒカリ施肥計画",
|
|
||||||
"year": 2025,
|
|
||||||
"variety_name": "コシヒカリ",
|
|
||||||
"crop_name": "米",
|
|
||||||
"fertilizers": [{"id": 1, "name": "一発肥料"}],
|
|
||||||
"entries": [{"field": 5, "fertilizer": 1, "bags": "2.40"}]
|
|
||||||
},
|
|
||||||
"groups": [
|
"groups": [
|
||||||
{
|
{
|
||||||
"id": 10,
|
"id": 10,
|
||||||
"name": "田中エリア",
|
"name": "キウイ",
|
||||||
"order": 0,
|
"order": 0,
|
||||||
"fields": [{"id": 5, "name": "田中上", "area_tan": "1.2000"}]
|
"fields": [
|
||||||
|
{"id": 5, "name": "キウイ畑1", "area_tan": "1.2000"}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"unassigned_fields": [{"id": 7, "name": "未割り当て圃場", "area_tan": "0.5000"}]
|
"trips": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"order": 0,
|
||||||
|
"name": "1回目 たちはるか電気炉さい",
|
||||||
|
"date": "2026-03-16",
|
||||||
|
"items": [
|
||||||
|
{"field": 5, "fertilizer": 1, "bags": "4.00"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"unassigned_fields": [],
|
||||||
|
"available_fertilizers": [
|
||||||
|
{"id": 1, "name": "電気炉さい"},
|
||||||
|
{"id": 2, "name": "ミネラルホウ素"}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
- `available_fertilizers`: 該当年度の全施肥計画で使われている肥料の一覧
|
||||||
|
- `unassigned_fields`: グループに割り当てられていない圃場
|
||||||
|
|
||||||
### 書き込みリクエスト(POST/PUT)
|
### 書き込みリクエスト(POST/PUT)
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"name": "2025年コシヒカリ 分配計画",
|
"year": 2026,
|
||||||
"fertilization_plan_id": 3,
|
"name": "2026春 肥料運搬",
|
||||||
"groups": [
|
"groups": [
|
||||||
{"name": "田中エリア", "order": 0, "field_ids": [5, 6]},
|
{"name": "キウイ", "order": 0, "field_ids": [5, 6]}
|
||||||
{"name": "奥地エリア", "order": 1, "field_ids": [7]}
|
],
|
||||||
|
"trips": [
|
||||||
|
{
|
||||||
|
"order": 0,
|
||||||
|
"name": "1回目",
|
||||||
|
"date": "2026-03-16",
|
||||||
|
"items": [
|
||||||
|
{"field_id": 5, "fertilizer_id": 1, "bags": "4.00"}
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
PUT は groups を全削除→再作成する全置換方式。
|
PUT は groups・trips を全削除→再作成する全置換方式。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## フロントエンド画面
|
## フロントエンド画面
|
||||||
|
|
||||||
### 分配計画一覧 `/distribution`
|
### 運搬計画一覧 `/distribution`
|
||||||
|
|
||||||
- 年度セレクタ(`localStorage distributionYear` で保持)
|
- 年度セレクタ(`localStorage distributionYear` で保持)
|
||||||
- テーブル: 計画名・施肥計画・作物/品種・グループ数・圃場数
|
- テーブル: 計画名・グループ数・回数
|
||||||
- アクション: PDF・編集・削除
|
- アクション: PDF・編集・削除
|
||||||
- 削除エラー: インラインバナー(確認なし・失敗したらバナー表示)
|
|
||||||
|
|
||||||
### 分配計画編集 `/distribution/new` / `/distribution/[id]/edit`
|
### 運搬計画編集 `/distribution/new` / `/distribution/[id]/edit`
|
||||||
|
|
||||||
**共通コンポーネント**: `frontend/src/app/distribution/_components/DistributionEditPage.tsx`
|
#### 画面レイアウト
|
||||||
|
|
||||||
#### State構成
|
```
|
||||||
|
[計画名: ________________] [年度: 2026]
|
||||||
|
|
||||||
```typescript
|
━━━ グループ定義 ━━━━━━━━━━━━━━━━━━━
|
||||||
// 基本情報
|
(既存の方式: グループ追加・圃場割り当て・並び替え)
|
||||||
const [name, setName] = useState('')
|
|
||||||
const [fertilizationPlanId, setFertilizationPlanId] = useState<number|''>('')
|
|
||||||
|
|
||||||
// 施肥計画詳細(施肥計画選択後に取得)
|
━━━ 対象肥料 ━━━━━━━━━━━━━━━━━━━━━
|
||||||
const [fertPlanDetail, setFertPlanDetail] = useState<DistributionPlan['fertilization_plan'] | null>(null)
|
☑電気炉さい ☑ミネラルホウ素 ☐有機100号 ...
|
||||||
|
(年度の施肥計画に含まれる肥料をチェックボックスで選択)
|
||||||
|
|
||||||
// ローカルグループ(tempId で管理、保存時にサーバーへ送信)
|
━━━ 未割り当て ━━━━━━━━━━━━━━━━━━━━
|
||||||
const [groups, setGroups] = useState<LocalGroup[]>([])
|
★ キウイ (小計: 電気炉さい 4, ミネラルホウ素 5)
|
||||||
// LocalGroup = { tempId: string, name: string, order: number, fieldIds: number[], isRenamingName?: string }
|
圃場A 電気炉さい:2 ミネラルホウ素:3 [→1回目 ▼]
|
||||||
|
圃場B 電気炉さい:2 ミネラルホウ素:2 [→1回目 ▼]
|
||||||
|
★ 足川北 (小計: 電気炉さい 12, ミネラルホウ素 6)
|
||||||
|
圃場D ...
|
||||||
|
|
||||||
|
━━━ 1回目 (2026-03-16) ━━━ 積載: 46袋 ━━━
|
||||||
|
日付: [2026-03-16] 名前: [たちはるか電気炉さい]
|
||||||
|
★ たちはるか (小計: 電気炉さい 46)
|
||||||
|
圃場X 電気炉さい:10 [←戻す]
|
||||||
|
圃場Y 電気炉さい:12 [←戻す]
|
||||||
|
...
|
||||||
|
|
||||||
|
━━━ 2回目 (2026-03-16) ━━━ 積載: 39袋 ━━━
|
||||||
|
日付: [2026-03-16] 名前: [____________]
|
||||||
|
★ キウイ (小計: 電気炉さい 4, ミネラルホウ素 5)
|
||||||
|
...
|
||||||
|
|
||||||
|
[+回を追加] [残り全部→新しい回] [保存]
|
||||||
```
|
```
|
||||||
|
|
||||||
#### UI構成
|
#### 主要な操作
|
||||||
|
|
||||||
1. **計画基本情報**: 計画名テキスト + 施肥計画セレクタ
|
| 操作 | 方法 | 説明 |
|
||||||
2. **グループ割り当て**:
|
|---|---|---|
|
||||||
- 新規グループ追加(名前入力 + 追加ボタン)
|
| 圃場を回に割り当て | 圃場行の「→N回目」ドロップダウン | 未割り当て→指定回に移動 |
|
||||||
- グループカード(↑↓順序変更・鉛筆名前変更・×削除)
|
| 圃場を回から戻す | 圃場行の「←戻す」ボタン | 回→未割り当てに移動 |
|
||||||
- グループ内圃場(×解除)+ 肥料別袋数をインライン表示
|
| 圃場を別の回に移動 | 戻す→再割り当て、または直接ドロップダウン | 回の間で移動 |
|
||||||
- 未割り当て圃場セクション(グループ選択ドロップダウンで割り当て)
|
| 残り全部を一括割り当て | 「残り全部→新しい回」ボタン | 未割り当て全圃場を新しい回に追加 |
|
||||||
3. **集計プレビュー**: グループ×肥料マトリクス(リアルタイム・サーバー通信なし)
|
| 回の追加 | 「+回を追加」ボタン | 空の回を追加 |
|
||||||
|
| 回の削除 | 回ヘッダーの「×」ボタン | 回を削除、中の圃場は未割り当てに戻る |
|
||||||
|
| 回の日付設定 | 日付入力フィールド | デフォルトは1回目の日付 |
|
||||||
|
| 対象肥料の絞り込み | チェックボックス | 選択した肥料だけ表示 |
|
||||||
|
|
||||||
|
#### 積載合計のリアルタイム表示
|
||||||
|
|
||||||
|
各回のヘッダーに、その回の肥料ごとの合計袋数と総袋数を表示。
|
||||||
|
圃場を追加・削除するたびに即時再計算(サーバー通信なし)。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## PDF 出力
|
## PDF 出力
|
||||||
|
|
||||||
`GET /api/fertilizer/distribution/{id}/pdf/`
|
`GET /api/fertilizer/delivery/{id}/pdf/`
|
||||||
|
|
||||||
- WeasyPrint(既存施肥計画PDFと同じ仕組み)
|
### フォーマット
|
||||||
- テンプレート: `backend/apps/fertilizer/templates/fertilizer/distribution_pdf.html`
|
|
||||||
- フォーマット: A4横向き
|
- WeasyPrint、A4横向き
|
||||||
- 内容:
|
- **回ごとに1ページ**(1回目=1ページ目、2回目=2ページ目...)
|
||||||
- ★グループ合計行(太字・緑背景)
|
|
||||||
- 圃場サブ行(小フォント・灰色背景)
|
### 各ページの内容
|
||||||
- 肥料列合計・総合計
|
|
||||||
- ファイル名: `distribution_{year}_{plan_id}.pdf`
|
```
|
||||||
|
━━━ 2回目 2026-03-16 ━━━━━━━━━━━━━━━
|
||||||
|
電気炉さい ミネラルホウ素
|
||||||
|
★ キウイ 4 5
|
||||||
|
圃場A 2 3
|
||||||
|
圃場B 2 2
|
||||||
|
★ 池田さんちの前 2 2
|
||||||
|
圃場C 2 2
|
||||||
|
★ 足川北 12 6
|
||||||
|
圃場D 4 2
|
||||||
|
圃場E 4 2
|
||||||
|
圃場F 4 2
|
||||||
|
★ 出祥邸 - 8
|
||||||
|
圃場G - 4
|
||||||
|
圃場H - 4
|
||||||
|
─────────────────────────────────────
|
||||||
|
合計 18 21
|
||||||
|
```
|
||||||
|
|
||||||
|
- ★行: グループ小計(肥料ごと)、太字・緑背景
|
||||||
|
- 圃場行: 各圃場の肥料ごとの袋数(**合計列なし**)
|
||||||
|
- 最下行: 回全体の肥料ごと合計
|
||||||
|
- 日付を各ページのヘッダーに記載
|
||||||
|
- ファイル名: `delivery_{year}_{plan_id}.pdf`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ファイル構成
|
## ファイル構成(予定)
|
||||||
|
|
||||||
### Backend
|
### Backend
|
||||||
|
|
||||||
```
|
```
|
||||||
backend/apps/fertilizer/
|
backend/apps/fertilizer/
|
||||||
├── models.py # DistributionPlan/Group/GroupField 追加(migration 0003)
|
├── models.py # DeliveryPlan/Group/GroupField/Trip/TripItem
|
||||||
├── serializers.py # Distribution* シリアライザ追加
|
├── serializers.py # Delivery* シリアライザ
|
||||||
├── views.py # DistributionPlanViewSet 追加
|
├── views.py # DeliveryPlanViewSet
|
||||||
├── urls.py # router.register('distribution', ...) 追加
|
├── urls.py # router.register('delivery', ...)
|
||||||
├── admin.py # DistributionPlan/Group の admin 登録
|
├── admin.py # DeliveryPlan 等の admin 登録
|
||||||
|
├── migrations/
|
||||||
|
│ └── 000X_delivery_*.py # 旧Distribution → 新Delivery マイグレーション
|
||||||
└── templates/fertilizer/
|
└── templates/fertilizer/
|
||||||
└── distribution_pdf.html # A4横 PDF テンプレート
|
└── delivery_pdf.html # 回ごと1ページ PDF テンプレート
|
||||||
```
|
```
|
||||||
|
|
||||||
### Frontend
|
### Frontend
|
||||||
@@ -215,27 +356,40 @@ frontend/src/app/distribution/
|
|||||||
├── page.tsx # 一覧ページ
|
├── page.tsx # 一覧ページ
|
||||||
├── new/page.tsx # 新規作成(ラッパー)
|
├── new/page.tsx # 新規作成(ラッパー)
|
||||||
├── [id]/edit/page.tsx # 編集(ラッパー)
|
├── [id]/edit/page.tsx # 編集(ラッパー)
|
||||||
└── _components/DistributionEditPage.tsx # 編集共通コンポーネント
|
└── _components/DeliveryEditPage.tsx # 編集共通コンポーネント
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## マイグレーション方針
|
||||||
|
|
||||||
|
### 旧モデル(Distribution*)の扱い
|
||||||
|
|
||||||
|
1. 新モデル(Delivery*)を追加するマイグレーションを作成
|
||||||
|
2. 旧モデル(Distribution*)は削除マイグレーションで除去
|
||||||
|
3. 旧データは少量のため、データ移行は行わない(手動で再作成)
|
||||||
|
|
||||||
|
### マイグレーション順序
|
||||||
|
|
||||||
|
1. `000X_add_delivery_models.py` - DeliveryPlan, DeliveryGroup, DeliveryGroupField, DeliveryTrip, DeliveryTripItem を追加
|
||||||
|
2. `000Y_remove_distribution_models.py` - DistributionPlan, DistributionGroup, DistributionGroupField を削除
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 注意点
|
## 注意点
|
||||||
|
|
||||||
### 集計は全クライアントサイド計算
|
### 施肥計画との関係
|
||||||
|
|
||||||
集計プレビューは API を呼ばず、`fertPlanDetail.entries` と `groups.fieldIds` からクライアントで計算する。
|
- 運搬計画は施肥計画への直接FKを持たない
|
||||||
|
- 年度ベースで、その年度の全 FertilizationEntry を参照して圃場×肥料の袋数を取得する
|
||||||
|
- 施肥計画を変更すると、未割り当ての圃場の袋数は自動で反映される
|
||||||
|
- 既に運搬回に割り当て済みの DeliveryTripItem.bags は変わらない(コピー済み)
|
||||||
|
|
||||||
|
### 集計はクライアントサイド計算
|
||||||
|
|
||||||
|
画面上の集計(グループ小計・回の積載合計)は API を呼ばずクライアントで計算。
|
||||||
PDF生成時のみサーバーサイドで同じ計算を実施。
|
PDF生成時のみサーバーサイドで同じ計算を実施。
|
||||||
|
|
||||||
### PUT の全置換方式
|
|
||||||
|
|
||||||
PUT 時は `groups.all().delete()` → 再作成。部分更新は非対応。
|
|
||||||
|
|
||||||
### 未割り当て圃場の扱い
|
|
||||||
|
|
||||||
- 施肥計画に含まれる圃場のうちグループに割り当てられていないものは「未割り当て」として表示
|
|
||||||
- PDF にも「未割り当て」グループとして出力される(ゼロの場合は出力なし)
|
|
||||||
|
|
||||||
### エラー表示方針
|
### エラー表示方針
|
||||||
|
|
||||||
施肥計画機能と同じく alert/confirm 廃止・インラインバナーに統一。
|
施肥計画機能と同じく alert/confirm 廃止・インラインバナーに統一。
|
||||||
|
|||||||
Reference in New Issue
Block a user