docs: refine pesticide management spec
This commit is contained in:
@@ -59,7 +59,7 @@
|
||||
|
||||
### 特別栽培向け成分数集計
|
||||
|
||||
「節減対象農薬(`is_non_target=False`)の有効成分が何種類使われたか」を年度×作物単位でカウントする。
|
||||
「節減対象農薬(`is_non_target=False`)の有効成分(`is_active=True`)が何種類使われたか」を年度×作物単位でカウントする。
|
||||
上限はなく、報告用の集計値として表示する。
|
||||
|
||||
---
|
||||
@@ -102,10 +102,25 @@
|
||||
| name | CharField(200) | required | 成分名称(例: MEP) |
|
||||
| concentration | CharField(100) | blank | 含有濃度(例: 50.0%) |
|
||||
| is_active | BooleanField | default=True | 有効成分かどうか(False = その他成分) |
|
||||
|
||||
- `unique_together = ['pesticide', 'name']`
|
||||
|
||||
### PesticideIngredientLimit(有効成分の総使用回数上限:作物別)
|
||||
|
||||
**テーブル名**: `pesticide_pesticideingredientlimit`
|
||||
|
||||
農水省の「○○を含む農薬の総使用回数」は作物ごとに異なりうるため、有効成分本体とは分離して作物別に保持する。
|
||||
|
||||
| フィールド | 型 | 制約 | 説明 |
|
||||
|---|---|---|---|
|
||||
| id | BigAutoField | PK | |
|
||||
| pesticide | FK(Pesticide) | CASCADE | 取得元農薬 |
|
||||
| ingredient_name | CharField(200) | required | 成分名称(例: MEP) |
|
||||
| crop_name | CharField(200) | required | 作物名(農水省登録情報の表記、例: 稲) |
|
||||
| max_total_uses | IntegerField | null=True | この成分を含む農薬の総使用回数上限 |
|
||||
| use_timing_note | TextField | blank | 使用時期別制限のテキスト(例: 種もみへの処理は1回以内、…) |
|
||||
|
||||
- `unique_together = ['pesticide', 'name']`
|
||||
- `unique_together = ['pesticide', 'ingredient_name', 'crop_name']`
|
||||
|
||||
### PesticideProductLimit(製品の使用回数上限:作物別)
|
||||
|
||||
@@ -123,6 +138,22 @@
|
||||
|
||||
- `unique_together = ['pesticide', 'crop_name']`
|
||||
|
||||
### PesticideCropAlias(農水省作物名と内部作物の対応)
|
||||
|
||||
**テーブル名**: `pesticide_pesticidecropalias`
|
||||
|
||||
農水省の適用表上の作物名と、内部 `plans.Crop` の作物を対応付けるための正規化テーブル。
|
||||
|
||||
| フィールド | 型 | 制約 | 説明 |
|
||||
|---|---|---|---|
|
||||
| id | BigAutoField | PK | |
|
||||
| crop | FK(plans.Crop) | PROTECT | 内部作物 |
|
||||
| alias_name | CharField(200) | required, unique | 農水省登録情報の作物名(例: 稲, 水稲) |
|
||||
| is_primary | BooleanField | default=False | 代表表記かどうか |
|
||||
|
||||
- 使用回数チェック時は `crop_id` から本テーブルを逆引きし、`PesticideProductLimit.crop_name` / `PesticideIngredientLimit.crop_name` と照合する
|
||||
- 初期データ例: `Crop=水稲` に対し `alias_name=稲`, `alias_name=水稲` を登録
|
||||
|
||||
### SprayEvent(散布イベント)
|
||||
|
||||
**テーブル名**: `pesticide_sprayevent`
|
||||
@@ -139,6 +170,8 @@
|
||||
| target_group | CharField(50) | blank | 対象が圃場グループの場合(group_name) |
|
||||
| target_crop | FK(plans.Crop) | null=True, PROTECT | 対象が作物の場合 |
|
||||
| target_variety | FK(plans.Variety) | null=True, PROTECT | 対象が品種の場合 |
|
||||
| crop_snapshot | CharField(100) | blank | 保存時点の集計対象作物名 |
|
||||
| variety_snapshot | CharField(100) | blank | 保存時点の対象品種名 |
|
||||
| notes | TextField | blank | 備考 |
|
||||
| created_at | DateTimeField | auto | |
|
||||
| updated_at | DateTimeField | auto | |
|
||||
@@ -152,6 +185,27 @@
|
||||
| `crop` | target_crop | 特定の作物に対して散布(作付け計画と照合) |
|
||||
| `variety` | target_variety | 特定の品種に対して散布(作付け計画と照合) |
|
||||
|
||||
- 保存時に `crop_snapshot` / `variety_snapshot` を自動設定し、後日の作付け変更やグループ名変更があっても過去実績の集計結果が変わらないようにする
|
||||
|
||||
### SprayEventResolvedField(散布イベント対象圃場スナップショット)
|
||||
|
||||
**テーブル名**: `pesticide_sprayeventresolvedfield`
|
||||
|
||||
`target_type=group` / `crop` / `variety` のように複数圃場へ展開される散布について、保存時点で対象圃場を確定保存する。
|
||||
|
||||
| フィールド | 型 | 制約 | 説明 |
|
||||
|---|---|---|---|
|
||||
| id | BigAutoField | PK | |
|
||||
| event | FK(SprayEvent) | CASCADE | |
|
||||
| field | FK(fields.Field) | PROTECT | 対象圃場 |
|
||||
| field_name_snapshot | CharField(100) | required | 保存時点の圃場名 |
|
||||
| group_name_snapshot | CharField(50) | blank | 保存時点のグループ名 |
|
||||
| crop_name_snapshot | CharField(100) | required | 保存時点の作物名 |
|
||||
| variety_name_snapshot | CharField(100) | blank | 保存時点の品種名 |
|
||||
|
||||
- `unique_together = ['event', 'field']`
|
||||
- `target_type=field` の場合も 1 行作成しておくと、集計ロジックを統一しやすい
|
||||
|
||||
### SprayEventPesticide(散布農薬明細)
|
||||
|
||||
**テーブル名**: `pesticide_sprayeventpesticide`
|
||||
@@ -177,9 +231,9 @@
|
||||
|
||||
**年度 × 作物** を基本単位とする。
|
||||
|
||||
- `target_type=field`/`group` の場合: そのイベントの年度の作付け計画(Plan)から作物を特定
|
||||
- `target_type=crop` の場合: target_crop が直接作物
|
||||
- `target_type=variety` の場合: target_variety の crop が作物
|
||||
- 集計対象作物は `SprayEvent.crop_snapshot` と `SprayEventResolvedField.crop_name_snapshot` を正とする
|
||||
- `target_type=field`/`group`/`crop`/`variety` の違いにかかわらず、保存時に解決済み対象圃場と作物スナップショットを作成する
|
||||
- 使用回数上限の照合は、内部 `Crop` から `PesticideCropAlias` を介して農水省表記へ変換して行う
|
||||
|
||||
### 製品使用回数の集計
|
||||
|
||||
@@ -194,6 +248,7 @@
|
||||
有効成分総使用回数 = COUNT(SprayEventPesticide)
|
||||
where SprayEventPesticide.pesticide に
|
||||
当該有効成分(PesticideIngredient.name)が含まれる
|
||||
かつ PesticideIngredient.is_active=True
|
||||
かつ is_non_target=False
|
||||
で year × 作物 でフィルタしたもの
|
||||
```
|
||||
@@ -203,6 +258,7 @@
|
||||
```
|
||||
使用成分数 = COUNT(DISTINCT PesticideIngredient.name)
|
||||
where 当該年度×作物の散布イベントで使用された農薬の有効成分
|
||||
かつ PesticideIngredient.is_active=True
|
||||
かつ pesticide.is_non_target=False
|
||||
```
|
||||
|
||||
@@ -243,9 +299,7 @@
|
||||
"id": 1,
|
||||
"name": "MEP",
|
||||
"concentration": "50.0%",
|
||||
"is_active": true,
|
||||
"max_total_uses": 3,
|
||||
"use_timing_note": "種もみへの処理は1回以内、育苗箱散布は1回以内、本田では2回以内"
|
||||
"is_active": true
|
||||
}
|
||||
],
|
||||
"product_limits": [
|
||||
@@ -255,6 +309,23 @@
|
||||
"max_uses": 2,
|
||||
"use_timing_note": "収穫21日前まで"
|
||||
}
|
||||
],
|
||||
"ingredient_limits": [
|
||||
{
|
||||
"id": 1,
|
||||
"ingredient_name": "MEP",
|
||||
"crop_name": "稲",
|
||||
"max_total_uses": 3,
|
||||
"use_timing_note": "種もみへの処理は1回以内、育苗箱散布は1回以内、本田では2回以内"
|
||||
}
|
||||
],
|
||||
"crop_aliases": [
|
||||
{
|
||||
"crop": 1,
|
||||
"crop_name": "水稲",
|
||||
"alias_name": "稲",
|
||||
"is_primary": true
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
@@ -347,6 +418,17 @@
|
||||
"target_type": "group",
|
||||
"target_group": "田中エリア",
|
||||
"target_display": "田中エリア(グループ)",
|
||||
"crop_snapshot": "水稲",
|
||||
"variety_snapshot": "",
|
||||
"resolved_fields": [
|
||||
{
|
||||
"field": 5,
|
||||
"field_name_snapshot": "田中上",
|
||||
"group_name_snapshot": "田中エリア",
|
||||
"crop_name_snapshot": "水稲",
|
||||
"variety_name_snapshot": "コシヒカリ"
|
||||
}
|
||||
],
|
||||
"notes": "曇り、風弱し",
|
||||
"pesticides": [
|
||||
{
|
||||
@@ -373,7 +455,8 @@
|
||||
{
|
||||
"year": 2026,
|
||||
"crop_id": 1,
|
||||
"crop_name": "稲",
|
||||
"crop_name": "水稲",
|
||||
"crop_aliases": ["稲", "水稲"],
|
||||
"product_usage": [
|
||||
{
|
||||
"pesticide_id": 1,
|
||||
@@ -454,7 +537,7 @@ URL: `https://pesticide.maff.go.jp/`
|
||||
| 作物名 | 作物名 | `PesticideProductLimit.crop_name` |
|
||||
| 本剤の使用回数 | 「N回以内」から N を抽出 | `PesticideProductLimit.max_uses` |
|
||||
| 使用時期 | テキストそのまま | `PesticideProductLimit.use_timing_note` |
|
||||
| `{成分名}を含む農薬の総使用回数` | 「N回以内(...)」から N と補足を抽出 | `PesticideIngredient.max_total_uses` / `use_timing_note` |
|
||||
| `{成分名}を含む農薬の総使用回数` | 「N回以内(...)」から N と補足を抽出 | `PesticideIngredientLimit.max_total_uses` / `use_timing_note` |
|
||||
|
||||
**「総使用回数」テキストのパース規則:**
|
||||
|
||||
@@ -477,6 +560,7 @@ Django management command として実装。APIエンドポイントから呼び
|
||||
- アクセスは農薬マスタ登録時の1件ずつに限定(バルク取得は行わない)
|
||||
- 農水省サイトの内部ID(`system_id`)と農薬の公式登録番号は別物
|
||||
- タイムアウト: 10秒
|
||||
- 適用表の作物名は `PesticideCropAlias` で内部 `Crop` と対応付ける前提で保存する
|
||||
|
||||
---
|
||||
|
||||
@@ -508,11 +592,14 @@ Django management command として実装。APIエンドポイントから呼び
|
||||
## 設計判断と制約
|
||||
|
||||
1. **散布対象の特定**: `target_type` + 対象FK/文字列で柔軟に対応。作物ごとの集計は作付け計画(Plan)と照合。
|
||||
2. **使用回数上限は作物別に保持**: 同一農薬でも稲と野菜で上限が異なるため `PesticideProductLimit` を作物別に複数行保持。
|
||||
3. **総使用回数はテキストパース**: 農水省サイトの「○○を含む農薬の総使用回数」カラムから正規表現で数値を抽出。
|
||||
4. **保存はブロックしない**: 使用回数超過は警告表示のみ。農薬散布の記録は法的義務があるため、超過でも保存できるようにする。
|
||||
5. **`SprayEventPesticide.pesticide` は PROTECT**: 散布記録に使用中の農薬は削除不可。
|
||||
6. **`is_spreader=True` は `is_non_target` 扱い**: 展着剤はカウント除外のため、展着剤フラグをセットすれば節減対象外フラグも自動的に True 扱い(DB保存は別フィールド)。
|
||||
2. **使用回数上限は作物別に保持**: 同一農薬でも作物ごとに上限が異なるため `PesticideProductLimit` と `PesticideIngredientLimit` を作物別に複数行保持する。
|
||||
3. **作物名の照合は別名テーブルで吸収**: 農水省表記の「稲」と内部の「水稲」のような差異を吸収するため、`PesticideCropAlias` を必須とする。
|
||||
4. **散布対象は保存時に確定保存する**: 後日のグループ名変更や作付け変更で過去実績の集計結果が変わらないよう、`SprayEventResolvedField` と `crop_snapshot` / `variety_snapshot` を保持する。
|
||||
5. **総使用回数はテキストパース**: 農水省サイトの「○○を含む農薬の総使用回数」カラムから正規表現で数値を抽出する。
|
||||
6. **保存はブロックしない**: 使用回数超過は警告表示のみ。農薬散布の記録は法的義務があるため、超過でも保存できるようにする。
|
||||
7. **`SprayEventPesticide.pesticide` は PROTECT**: 散布記録に使用中の農薬は削除不可。
|
||||
8. **成分集計は `is_active=True` のみ対象**: 「その他成分」は総使用回数・特別栽培の成分数集計に含めない。
|
||||
9. **`is_spreader=True` は `is_non_target` 扱い**: 展着剤はカウント除外のため、展着剤フラグをセットすれば節減対象外フラグも自動的に True 扱い(DB保存は別フィールド)。
|
||||
|
||||
---
|
||||
|
||||
@@ -520,7 +607,7 @@ Django management command として実装。APIエンドポイントから呼び
|
||||
|
||||
| ファイル | 説明 |
|
||||
|---|---|
|
||||
| `backend/apps/pesticide/models.py` | Pesticide, PesticideIngredient, PesticideProductLimit, SprayEvent, SprayEventPesticide |
|
||||
| `backend/apps/pesticide/models.py` | Pesticide, PesticideIngredient, PesticideIngredientLimit, PesticideProductLimit, PesticideCropAlias, SprayEvent, SprayEventResolvedField, SprayEventPesticide |
|
||||
| `backend/apps/pesticide/serializers.py` | DRF シリアライザ |
|
||||
| `backend/apps/pesticide/views.py` | ViewSet |
|
||||
| `backend/apps/pesticide/urls.py` | URL ルーティング |
|
||||
|
||||
Reference in New Issue
Block a user