From 4299c6eb4be460bbf82cf6cbe1c4cabce944d226 Mon Sep 17 00:00:00 2001 From: akira Date: Sun, 5 Apr 2026 14:00:50 +0900 Subject: [PATCH] =?UTF-8?q?=E6=94=B9=E5=96=84=E6=A1=88No2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .claude/settings.json | 3 +- 改善案/issue_3_計画始動後の作付け変更_調査.md | 409 ++++++++++++++++++ 2 files changed, 411 insertions(+), 1 deletion(-) create mode 100644 改善案/issue_3_計画始動後の作付け変更_調査.md diff --git a/.claude/settings.json b/.claude/settings.json index 3615e67..df60a8a 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -73,7 +73,8 @@ "mcp__butler__butler__get_skill_usage", "mcp__butler__inspect_runtime_config", "mcp__butler__execute_task", - "Bash(git -C /home/akira/develop/keinasystem remote -v)" + "Bash(git -C /home/akira/develop/keinasystem remote -v)", + "Bash(cat butler/skills/read_from_gitea*)" ], "additionalDirectories": [ "C:\\Users\\akira\\AppData\\Local\\Temp", diff --git a/改善案/issue_3_計画始動後の作付け変更_調査.md b/改善案/issue_3_計画始動後の作付け変更_調査.md new file mode 100644 index 0000000..ada70b0 --- /dev/null +++ b/改善案/issue_3_計画始動後の作付け変更_調査.md @@ -0,0 +1,409 @@ +# Issue #3 調査メモ: 計画始動後の作付け変更について + +## 対象 issue + +- Gitea Issue `#3` +- タイトル: `計画始動後の作付け変更について` +- 登録日: 2026-04-05 + +## 1. まず明らかになっている必要があること + +この課題は「作付け計画を変更したい」ではなく、 +「すでに計画・運搬・散布の一部が動き始めた後で、将来分だけを安全に組み替えたい」が本質。 +そのため、以下を仕様として先に決めないと実装を始めると破綻しやすい。 + +### 1-1. どこまでを履歴として固定し、どこから先を変更対象にするか + +- すでに散布実績がある `圃場 × 肥料` は履歴として固定するのか +- 固定する場合、固定対象は以下のどこまで含むのか + - 散布実績 + - 実績に対応する施肥計画エントリ + - 実績に対応する運搬明細 + - 在庫 USE / RESERVE + - 作業記録 +- 「まだ散布していない残計画」だけを別レコードへ移すのか +- 既存計画を上書きするのではなく、履歴保持のために分割するのか + +### 1-2. 品種変更を何の単位で許可するか + +- 圃場単位での変更を許可するのか +- 同じ年度中に圃場の品種変更履歴を残す必要があるのか +- 変更後の圃場は新しい品種の施肥計画へ付け替えるのか +- 変更前に散布済みの肥料は「旧品種の計画に残す」のか「圃場履歴として残す」のか + +### 1-3. グループ変更の意味 + +ユーザー確認により、issue 本文の「グループ変更」は主に圃場管理の `group_name` を指す。 + +- 圃場マスタの `group_name` は後から変更されうる +- 運搬計画の配送グループも散布前なら変更されうる +- ただし散布後は、運搬計画グループは基本的に変更しない前提 + +このため、少なくとも以下を分けて考える必要がある。 + +- 圃場マスタ上の現在属性としてのグループ +- 履歴として固定すべき運搬計画上のグループ + +### 1-4. 不整合をどこまで許容するか + +- 旧品種の施肥実績が残ったまま、新品種の作付け計画へ変更してよいか +- 「今年のその圃場は最終的に何を作ったか」と「途中で何を前提に散布したか」がズレてもよいか +- PDF や一覧画面で、旧計画分と新計画分を同時に見せる必要があるか + +### 1-5. ユーザー操作として必要な単位 + +- 圃場 1 筆だけ切り替えたいのか +- 複数圃場をまとめて切り替えたいのか +- 施肥済み分を残しつつ、未散布分を新計画へ一括移動したいのか +- 変更理由や変更日などの監査情報が必要か + +## 2. 現行実装で起きていること + +### 2-1. 候補圃場は「現在の作付け計画」から再計算される + +施肥計画の圃場候補は、現在の `plans.Plan(year, variety)` を見て作られている。 + +- [backend/apps/fertilizer/views.py](/home/akira/develop/keinasystem/backend/apps/fertilizer/views.py#L126) +- [frontend/src/app/fertilizer/_components/FertilizerEditPage.tsx](/home/akira/develop/keinasystem/frontend/src/app/fertilizer/_components/FertilizerEditPage.tsx#L180) + +そのため、作付け計画で圃場の品種を変更すると、 +変更前の品種に紐づく施肥計画画面では、その圃場が追加候補に出なくなる。 +issue にある「足川北上が圃場追加候補に出てこない」はこの挙動と一致する。 + +### 2-2. 施肥計画の実績集計は `year + field + fertilizer` 単位 + +散布実績から `actual_bags` を再集計するとき、対象は `plan__year + field_id + fertilizer_id` で更新される。 + +- [backend/apps/fertilizer/services.py](/home/akira/develop/keinasystem/backend/apps/fertilizer/services.py#L11) + +つまり現行実装では、 +「どの施肥計画に対する実績か」ではなく、 +「同年度のその圃場・その肥料の実績か」で紐づいている。 + +このため、同じ年度に圃場を別計画へ移したり、計画を分割したりすると、 +実績が複数計画へ二重反映または意図しない再配分になる余地がある。 + +### 2-3. 施肥計画更新はエントリ全削除・全再作成 + +施肥計画更新時は、既存エントリを全削除して新しいエントリを作り直す。 + +- [backend/apps/fertilizer/serializers.py](/home/akira/develop/keinasystem/backend/apps/fertilizer/serializers.py#L152) + +この方式だと、「散布済みの行だけ残して、未散布分だけ移す」という操作単位を持てない。 +履歴保持と将来計画の分離を実現するには、今の更新方式は不足している。 + +### 2-4. 運搬計画は年度内の全施肥エントリを前提に集計する + +運搬計画詳細の未割当圃場・利用可能肥料・全明細は、`plan__year=obj.year` の全施肥エントリから作られている。 + +- [backend/apps/fertilizer/serializers.py](/home/akira/develop/keinasystem/backend/apps/fertilizer/serializers.py#L291) + +そのため、作付け変更に伴って施肥計画を分割・移管したい場合、 +年度全体集計ベースの画面は旧計画と新計画を自然に区別できない。 + +### 2-5. 散布実績自体はスナップショットを保持している + +散布実績明細は以下を保存している。 + +- 実散布袋数 +- 計画袋数スナップショット +- 運搬済み袋数スナップショット + +- [backend/apps/fertilizer/models.py](/home/akira/develop/keinasystem/backend/apps/fertilizer/models.py#L211) +- [backend/apps/fertilizer/serializers.py](/home/akira/develop/keinasystem/backend/apps/fertilizer/serializers.py#L437) + +これは履歴保持の観点では良いが、 +「どの施肥計画のどの行から発生した散布か」という計画レベルの参照は保持していない。 + +## 3. 影響を受ける仕様 + +### 3-1. 作付け計画 + +- 現在は `field + year` が 1 件で、その年度の最新状態のみを表す +- 途中変更の履歴を持たない +- 変更前後を区別したいなら、履歴テーブルか有効期間の考え方が必要 + +### 3-2. 施肥計画 + +- 候補圃場抽出ロジック +- 編集画面での圃場追加可否 +- 既散布行と未散布行の扱い +- `actual_bags` の再集計単位 +- 在庫引当の再作成ロジック + +### 3-3. 圃場グループ + +- 圃場マスタの `group_name` は現在値しか持っていない +- 後日変更されると、過去時点でどのグループだったかは追えない +- ただし現時点では、散布実績や施肥実績が `group_name` に直接依存している箇所は薄い +- よって圃場グループ変更は、主に表示・集計・将来計画側の問題として扱える + +### 3-4. 運搬計画 + +- グループ割当の維持方法 +- 年度全体施肥エントリを前提にした未割当圃場計算 +- すでに運搬済みの明細を履歴として残しつつ、未運搬分だけ別グループへ再編できるか + +### 3-5. 散布実績 + +- 既存実績の参照元計画が曖昧 +- 変更後の計画へ実績が再集計されるかどうか +- 候補一覧生成時に、旧計画分と新計画分をどう見せ分けるか + +### 3-6. 在庫管理 + +- 施肥計画更新時、RESERVE が全置換される +- 実績 USE は散布実績ベースで残る +- 途中変更時に「旧計画の引当を解除し、新計画へ再引当」が必要 +- ただし散布済み分の USE は動かしてはいけない + +### 3-7. 作業記録 + +- 作業記録は運搬回 / 散布実績への 1:1 参照で成立しており、履歴としては比較的安定 +- 一方でタイトル等は計画名変更の影響を受けうる + +## 4. この issue に対する現時点の結論 + +この問題は単なる「候補圃場の表示漏れ」ではない。 + +本質は以下の 2 点。 + +1. 現行システムは「現在の作付け計画」と「履歴として固定すべき施肥・運搬・散布」を分離していない +2. 施肥・運搬・散布の一部が `年度 + 圃場 + 肥料` 集計でつながっており、計画の再編単位を持っていない + +したがって、候補圃場 API だけ直しても不十分で、 +少なくとも「履歴固定」と「未実施分の再計画」の仕様分離が必要。 + +## 5. 実装前に必要な仕様決定 + +最低限、次の 4 点を決める必要がある。 + +1. 変更後も残すべき履歴の最小単位は何か +2. 未散布分をどの単位で旧計画から切り離すか +3. 品種変更後、既散布分を旧品種の施肥計画に残すのか、新品種側に見せ替えるのか +4. 圃場マスタの `group_name` 変更を履歴管理対象にするか、現在値扱いに留めるか +5. 散布前の運搬計画変更をどこまで許容するか + +## 6. 推奨する実装方針の方向性 + +現時点では、次の方向が最も安全に見える。 + +### 方針A: 履歴固定 + 未実施分の再計画 + +- 散布実績がある `圃場 × 肥料` は旧施肥計画側に固定する +- 未散布分だけ新施肥計画へ移す +- 運搬済み明細も履歴として残し、未運搬分のみ再編対象にする +- 作付け計画の最新状態とは別に、施肥計画側で「履歴としての対象圃場集合」を保持する +- 圃場マスタの `group_name` は変更可能な現在属性として扱い、必要なら帳票側でスナップショット化を検討する + +### 方針B: 候補圃場と実績参照を分離する + +- 候補圃場表示は「現在の作付け計画」 +- 既存計画の保持対象は「その計画に保存済みの圃場」 +- 実績集計は `plan_id` またはそれに準ずる固定キーに寄せる + +方針A/B を組み合わせないと、issue の A/B/C を同時には満たしにくい。 + +## 6-1. ユーザー確認を踏まえた補足結論 + +ユーザー確認により、優先順位は次のように見える。 + +1. 散布後の履歴固定が最優先 +2. 散布前の運搬計画は変更可能 +3. 圃場マスタのグループは現在値として後から変わりうる + +したがって、構造上もっとも重要なのは +`作付け変更後も散布済みデータが崩れないこと` +であり、`group_name` 自体は二次的な論点。 +ただし帳票や一覧で「当時のグループ」を見たい要求が出るなら、別途スナップショットが必要になる。 + +## 7. 次の調査・設計タスク案 + +1. 「既散布・未散布」「既運搬・未運搬」で分けた業務フローを図にする +2. 施肥計画エントリに履歴固定用の状態を持たせるか検討する +3. 散布実績の参照先を `year + field + fertilizer` から計画単位へ寄せる案を比較する +4. 圃場マスタ `group_name` を履歴化する必要があるかを判断する +5. UI 上で必要な操作を列挙する +6. その後に issue を「暫定対処」と「構造対応」に分割する + +## 8. 追加提案に対する評価 + +ユーザーからの追加提案: + +- 変更履歴は必要 +- 散布済み Entry も新品種計画へ移動する案を第一候補 +- 未散布 Entry は新品種計画へ移動し、RESERVE も付け替える +- 圃場グループは対応不要 +- 田植え計画も同様に移動 + +この提案には良い点が多い一方で、現行実装のまま採ると危険な点もある。 + +### 8-1. 採用しやすい点 + +#### a. 変更履歴モデルの新設 + +`PlanVarietyChange` のような履歴モデル追加は妥当。 +少なくとも「いつ・どの圃場の品種が・何から何に変わったか」は残すべき。 + +補足: + +- `plan FK` だけでなく `field_id` と `year` を冗長保持した方が将来参照しやすい +- 変更理由 `reason` があると運用上かなり有用 +- 自動移動結果の件数も履歴に残せると監査しやすい + +#### b. 未散布 Entry の移動 + +これは方向性としてかなり自然。 +「まだ実施していない将来計画」は新品種側へ寄せ、引当も付け替えるのは業務的に納得感が高い。 + +#### c. 田植え計画も同様に扱う + +田植え計画も、候補圃場を現在の作付け計画から取っている以上、同種の問題を持つ。 +施肥だけ直して田植えを放置すると整合しないため、同時に見るべきという指摘は正しい。 + +### 8-2. そのまま採ると危険な点 + +#### a. 散布済み Entry を新品種計画へ移動する案 + +これはもっとも議論が必要。 + +現行では散布実績は `SpreadingSessionItem(field, fertilizer)` にあり、 +施肥計画との関係は `actual_bags` の再集計で後付けされている。 + +- [backend/apps/fertilizer/services.py](/home/akira/develop/keinasystem/backend/apps/fertilizer/services.py#L11) + +この構造で散布済み Entry を新品種計画へ移すと、画面上は +「新品種の施肥計画に、旧品種前提で行った散布実績が載る」 +ことになる。 + +業務的にそれを許容するなら成立するが、次の違和感が出る。 + +- 散布時点では旧品種前提だった履歴が、新品種計画の一部として見える +- 施肥計画 PDF や一覧で、後から見る人が経緯を誤解しやすい +- 「なぜこの新品種計画に既散布分が入っているのか」を履歴表示なしでは理解できない + +したがって、散布済み Entry を移動するなら、少なくとも +`変更前品種で発生した実績である` +ことが UI で明示される必要がある。 + +現時点では、実装の安全性だけで見ると +`散布済み Entry は旧計画に残す` +方が素直。 + +#### b. Entry の plan FK 付け替えだけでは履歴の意味が弱い + +提案では `FertilizationEntry.plan` / `RiceTransplantEntry.plan` を付け替えるが、 +それだけでは「なぜそこへ移ったか」が DB 上から分からない。 + +最低でも次が欲しい。 + +- どの変更イベントで移動したか +- 移動前 plan +- 移動後 plan +- 自動移動日時 + +つまり、履歴は `PlanVarietyChange` だけでなく、 +Entry 移動の監査ログも別に持つ方が安全。 + +#### c. 施肥計画が複数ある場合の自動集約 + +「最新 1 件に集約」は実装は簡単だが、業務意味が崩れやすい。 +issue 本文にもあるように、同年度・同品種で複数計画がありうる。 + +そこへ無条件に寄せると、 + +- 元肥用と追肥用 +- 第1回散布分と第2回散布分 +- ロット違い + +のような意味を壊す可能性がある。 + +自動選択(最新)は暫定対応としてはあり得るが、本命仕様にはしにくい。 + +### 8-3. 私の現時点の推奨 + +#### 変更履歴 + +採用推奨。 + +ただしモデルは次の方が使いやすい。 + +```python +PlanVarietyChange + field FK(Field, PROTECT) + year int + plan FK(Plan, CASCADE) + changed_at datetime + old_variety FK(Variety, SET_NULL, null=True) + new_variety FK(Variety, SET_NULL, null=True) + reason text blank +``` + +#### 散布済み Entry の扱い + +現時点の推奨は `(A) 旧計画に残す`。 + +理由: + +- 履歴解釈が明確 +- PDF/一覧での意味が崩れにくい +- 将来「既散布分も移したい」へ広げる余地を残せる + +もし `(B) 新品種計画へ移動` を採るなら、 +変更履歴表示と監査ログ表示を先に入れた方が安全。 + +#### 未散布 Entry の扱い + +採用推奨。 +RESERVE 付け替えもこの方針と整合する。 + +#### 圃場グループ + +現時点では対応不要でよさそう。 +少なくとも今回のコア問題ではない。 + +#### 田植え計画 + +採用推奨。 +ただし施肥より軽いので、実装順は施肥の後でよい。 + +### 8-4. 移動先計画の選び方への見解 + +3案の中では、私は次を推す。 + +1. 本命仕様: `b. 新規作成(常に)` +2. 暫定実装: `a. 自動選択(最新)` +3. 初期段階では避けたい: `c. ユーザー選択` + +理由: + +- `b` は履歴が最も明確で、既存計画の意味を壊しにくい +- `a` は早く実装できるが、複数計画の意味を壊しうる +- `c` は柔軟だが、allocation 画面の操作が一気に複雑になる + +実務上は、 +「品種変更に伴って自動移動された分」は専用計画として分けた方が後から説明しやすい。 + +たとえば: + +- `2026年度 たちはるか特栽 施肥計画(品種変更移動)` +- `2026年度 たちはるか特栽 田植え計画(品種変更移動)` + +のような命名。 + +### 8-5. 実装ステップ案への見解 + +提案の段階実装は良い。 +ただし Step 2 の前に「散布済みを残すか移すか」を固定した方がよい。 + +推奨順は次の通り。 + +1. `PlanVarietyChange` 追加 +2. 品種変更トリガーのサービス追加 +3. まずは `未散布 Entry のみ移動` を施肥計画で実装 +4. RESERVE 付け替えと `actual_bags` 再集計を確認 +5. 田植え計画へ横展開 +6. allocation 画面の履歴インジケータ追加 +7. 必要なら散布済み Entry 移動案を再検討 + +この順だと、もっとも危険な「履歴の意味が壊れる変更」を後ろ倒しにできる。