施肥計画の未散布Entry移動とRESERVE再生成を実装する #6

Closed
opened 2026-04-05 05:14:27 +00:00 by akira · 2 comments
Owner

概要

作付け計画の品種変更時に、未散布の施肥Entryのみを新品種側の新規施肥計画へ移動し、RESERVE を再生成する。

決定仕様

  • 散布済みEntryは旧計画に残す
  • 未散布Entryのみ移動する
  • 移動先施肥計画は既存計画へ集約せず、常に新規作成する
  • 新 plan 名: {year}年度 {品種名} 施肥計画(品種変更移動)
  • RESERVE は entry 単位ではなく create_reserves_for_plan(plan) により plan 単位で再生成する

未散布判定

  • actual_bags IS NULL → 未散布で移動対象
  • actual_bags IS NOT NULL and actual_bags < bags → 一部散布済みで移動不可
  • actual_bags >= bags → 散布完了で移動不可
  • actual_bags = 0 は移動不可側として扱う

実装内容

  • 品種変更サービスから施肥計画移動処理を呼び出す
  • 対象 Entry の plan FK を新品種側新規 plan へ付け替える
  • 旧 plan / 新 plan の RESERVE を再生成する
  • PlanVarietyChange.moved_entry_count に移動件数を記録する
  • actual_bags 再集計の前提となる invariant を守る

受け入れ条件

  • 未散布Entryのみが移動する
  • 散布済み・一部散布済みEntryは旧計画に残る
  • 旧 plan / 新 plan の RESERVE が正しく再生成される
  • 同一 year + field + fertilizer の Entry が複数 plan にまたがって共存しない
  • 新品種側の施肥計画から対象圃場を扱える

関連

## 概要 作付け計画の品種変更時に、未散布の施肥Entryのみを新品種側の新規施肥計画へ移動し、RESERVE を再生成する。 ## 決定仕様 - 散布済みEntryは旧計画に残す - 未散布Entryのみ移動する - 移動先施肥計画は既存計画へ集約せず、常に新規作成する - 新 plan 名: `{year}年度 {品種名} 施肥計画(品種変更移動)` - RESERVE は entry 単位ではなく `create_reserves_for_plan(plan)` により plan 単位で再生成する ## 未散布判定 - `actual_bags IS NULL` → 未散布で移動対象 - `actual_bags IS NOT NULL and actual_bags < bags` → 一部散布済みで移動不可 - `actual_bags >= bags` → 散布完了で移動不可 - `actual_bags = 0` は移動不可側として扱う ## 実装内容 - 品種変更サービスから施肥計画移動処理を呼び出す - 対象 Entry の `plan` FK を新品種側新規 plan へ付け替える - 旧 plan / 新 plan の RESERVE を再生成する - `PlanVarietyChange.moved_entry_count` に移動件数を記録する - `actual_bags` 再集計の前提となる invariant を守る ## 受け入れ条件 - [ ] 未散布Entryのみが移動する - [ ] 散布済み・一部散布済みEntryは旧計画に残る - [ ] 旧 plan / 新 plan の RESERVE が正しく再生成される - [ ] 同一 `year + field + fertilizer` の Entry が複数 plan にまたがって共存しない - [ ] 新品種側の施肥計画から対象圃場を扱える ## 関連 - 親: #3 - 実装全体: #4
Author
Owner
<html>

実装の評価

move_unspread_entries_for_variety_change の設計

仕様書の決定事項と照合:

仕様 | 実装 | 判定 -- | -- | -- actual_bags IS NULL のみ移動 | .filter(actual_bags__isnull=True) | actual_bags = 0 は移動不可 | NULL判定のみなので 0 は旧計画に残る | 移動先は常に新規作成 | FertilizationPlan.objects.create(...) | RESERVE は plan 単位で再生成 | create_reserves_for_plan(old_plan) / create_reserves_for_plan(new_plan) | moved_entry_count に件数記録 | plans/services.py で差分があれば save | calc_settings をコピー | calc_settings=old_plan.calc_settings | (自然な引き継ぎ)

process_plan_variety_change の更新

moved_count != change.moved_entry_count の差分チェックは無駄な DB 書き込みを避けるための配慮で適切です。


テストの妥当性評価

テスト test_serializer_update_moves_only_unspread_fertilizer_entries の検証内容を確認します:

テストが検証していること

  • 未散布エントリ(actual_bags=None)が新計画へ移動する
  • 一部散布済みエントリ(actual_bags=1.0)が旧計画に残る
  • 別圃場other_field)の未散布エントリが旧計画に残る(他圃場の誤移動がない)
  • 新計画の名前が仕様通り
  • calc_settings が引き継がれる
  • 旧計画の RESERVE が partial + other_field の2件になる
  • 新計画の RESERVE が unspread_entry の1件になる
  • moved_entry_count = 1 が記録される

不足している観点(軽微)

actual_bags = 0 のケース — 仕様書で「0 は移動不可」と明示しているが、そのケースのテストがない。実装が isnull=True のみなので 0 は自動的に移動しませんが、テストで担保されていません。

old_variety または new_variety が NULL のケースmove_unspread_entries_for_variety_change は冒頭で None チェックして 0 を返していますが、テストがない。

施肥計画が存在しないケース — 作付け品種を変更しても施肥計画がない場合(moved_count = 0)のテストがない。

これら3点は現状の実装が正しく動くケースですが、将来の改修時に壊れても検知できません。今回のスコープとしては許容範囲ですが、必要であれば追加できます。


気になる点(1件・要確認)

同一旧品種計画に同一圃場のエントリが複数肥料分ある場合の new_plan の数

現在の実装では「旧計画1件 → 新計画1件」を作ります。ただし、同じ old_plan の中に actual_bags=None のエントリが複数肥料分あっても、新計画は1件しか作りません(同じ new_plan にまとめて移動される)。これは正しい動作ですか?

コードを追うと:

for old_plan in old_plans:
    entries_to_move = list(old_plan.entries.filter(field_id=..., actual_bags__isnull=True))
    # → entries_to_move に複数肥料分が入る
    new_plan = FertilizationPlan.objects.create(...)  # 1件作成
    FertilizationEntry.objects.filter(id__in=[...]).update(plan=new_plan)  # 全部まとめて移動

仕様書(9-2)の記述「{year}年度 {品種名} 施肥計画(品種変更移動)」という命名から、1つの移動イベントに対して1計画を作る意図と読めるので、これは正しいと思いますが念のため確認させてください。

</html>
<html> <body> <!--StartFragment--><h3 style="color: rgb(41, 41, 41); font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">実装の評価</h3><p style="white-space: pre-wrap; margin-top: 0.1em; margin-bottom: 0.2em; color: rgb(41, 41, 41); font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, sans-serif; font-size: 13px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><strong><code style="font-family: monospace; color: rgb(255, 255, 255); background-color: rgb(9, 52, 95); padding: 2px 4px; border-radius: 3px; word-break: break-word; font-size: 0.9em;">move_unspread_entries_for_variety_change</code> の設計</strong></p><p style="white-space: pre-wrap; margin-top: 0.1em; margin-bottom: 0.2em; color: rgb(41, 41, 41); font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, sans-serif; font-size: 13px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">仕様書の決定事項と照合:</p> 仕様 | 実装 | 判定 -- | -- | -- actual_bags IS NULL のみ移動 | .filter(actual_bags__isnull=True) | ✅ actual_bags = 0 は移動不可 | NULL判定のみなので 0 は旧計画に残る | ✅ 移動先は常に新規作成 | FertilizationPlan.objects.create(...) | ✅ RESERVE は plan 単位で再生成 | create_reserves_for_plan(old_plan) / create_reserves_for_plan(new_plan) | ✅ moved_entry_count に件数記録 | plans/services.py で差分があれば save | ✅ calc_settings をコピー | calc_settings=old_plan.calc_settings | ✅(自然な引き継ぎ) <p style="white-space: pre-wrap; margin-top: 0.1em; margin-bottom: 0.2em; color: rgb(41, 41, 41); font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, sans-serif; font-size: 13px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><strong><code style="font-family: monospace; color: rgb(255, 255, 255); background-color: rgb(9, 52, 95); padding: 2px 4px; border-radius: 3px; word-break: break-word; font-size: 0.9em;">process_plan_variety_change</code> の更新</strong></p><p style="white-space: pre-wrap; margin-top: 0.1em; margin-bottom: 0.2em; color: rgb(41, 41, 41); font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, sans-serif; font-size: 13px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><code style="font-family: monospace; color: rgb(255, 255, 255); background-color: rgb(9, 52, 95); padding: 2px 4px; border-radius: 3px; word-break: break-word; font-size: 0.9em;">moved_count != change.moved_entry_count</code> の差分チェックは無駄な DB 書き込みを避けるための配慮で適切です。</p><hr style="font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, sans-serif; font-size: 13px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><h3 style="color: rgb(41, 41, 41); font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">テストの妥当性評価</h3><p style="white-space: pre-wrap; margin-top: 0.1em; margin-bottom: 0.2em; color: rgb(41, 41, 41); font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, sans-serif; font-size: 13px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">テスト <code style="font-family: monospace; color: rgb(255, 255, 255); background-color: rgb(9, 52, 95); padding: 2px 4px; border-radius: 3px; word-break: break-word; font-size: 0.9em;">test_serializer_update_moves_only_unspread_fertilizer_entries</code> の検証内容を確認します:</p><p style="white-space: pre-wrap; margin-top: 0.1em; margin-bottom: 0.2em; color: rgb(41, 41, 41); font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, sans-serif; font-size: 13px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><strong>テストが検証していること ✅</strong></p><ul style="padding-inline-start: 2em; color: rgb(41, 41, 41); font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, sans-serif; font-size: 13px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><li>未散布エントリ(<code style="font-family: monospace; color: rgb(255, 255, 255); background-color: rgb(9, 52, 95); padding: 2px 4px; border-radius: 3px; word-break: break-word; font-size: 0.9em;">actual_bags=None</code>)が新計画へ移動する</li><li>一部散布済みエントリ(<code style="font-family: monospace; color: rgb(255, 255, 255); background-color: rgb(9, 52, 95); padding: 2px 4px; border-radius: 3px; word-break: break-word; font-size: 0.9em;">actual_bags=1.0</code>)が旧計画に残る</li><li><strong>別圃場</strong>(<code style="font-family: monospace; color: rgb(255, 255, 255); background-color: rgb(9, 52, 95); padding: 2px 4px; border-radius: 3px; word-break: break-word; font-size: 0.9em;">other_field</code>)の未散布エントリが旧計画に残る(他圃場の誤移動がない)</li><li>新計画の名前が仕様通り</li><li><code style="font-family: monospace; color: rgb(255, 255, 255); background-color: rgb(9, 52, 95); padding: 2px 4px; border-radius: 3px; word-break: break-word; font-size: 0.9em;">calc_settings</code><span> </span>が引き継がれる</li><li>旧計画の RESERVE が partial + other_field の2件になる</li><li>新計画の RESERVE が unspread_entry の1件になる</li><li><code style="font-family: monospace; color: rgb(255, 255, 255); background-color: rgb(9, 52, 95); padding: 2px 4px; border-radius: 3px; word-break: break-word; font-size: 0.9em;">moved_entry_count = 1</code><span> </span>が記録される</li></ul><p style="white-space: pre-wrap; margin-top: 0.1em; margin-bottom: 0.2em; color: rgb(41, 41, 41); font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, sans-serif; font-size: 13px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><strong>不足している観点(軽微)</strong></p><p style="white-space: pre-wrap; margin-top: 0.1em; margin-bottom: 0.2em; color: rgb(41, 41, 41); font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, sans-serif; font-size: 13px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">① <strong><code style="font-family: monospace; color: rgb(255, 255, 255); background-color: rgb(9, 52, 95); padding: 2px 4px; border-radius: 3px; word-break: break-word; font-size: 0.9em;">actual_bags = 0</code> のケース</strong> — 仕様書で「0 は移動不可」と明示しているが、そのケースのテストがない。実装が <code style="font-family: monospace; color: rgb(255, 255, 255); background-color: rgb(9, 52, 95); padding: 2px 4px; border-radius: 3px; word-break: break-word; font-size: 0.9em;">isnull=True</code> のみなので 0 は自動的に移動しませんが、テストで担保されていません。</p><p style="white-space: pre-wrap; margin-top: 0.1em; margin-bottom: 0.2em; color: rgb(41, 41, 41); font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, sans-serif; font-size: 13px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">② <strong><code style="font-family: monospace; color: rgb(255, 255, 255); background-color: rgb(9, 52, 95); padding: 2px 4px; border-radius: 3px; word-break: break-word; font-size: 0.9em;">old_variety</code> または <code style="font-family: monospace; color: rgb(255, 255, 255); background-color: rgb(9, 52, 95); padding: 2px 4px; border-radius: 3px; word-break: break-word; font-size: 0.9em;">new_variety</code> が NULL のケース</strong> — <code style="font-family: monospace; color: rgb(255, 255, 255); background-color: rgb(9, 52, 95); padding: 2px 4px; border-radius: 3px; word-break: break-word; font-size: 0.9em;">move_unspread_entries_for_variety_change</code> は冒頭で <code style="font-family: monospace; color: rgb(255, 255, 255); background-color: rgb(9, 52, 95); padding: 2px 4px; border-radius: 3px; word-break: break-word; font-size: 0.9em;">None</code> チェックして 0 を返していますが、テストがない。</p><p style="white-space: pre-wrap; margin-top: 0.1em; margin-bottom: 0.2em; color: rgb(41, 41, 41); font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, sans-serif; font-size: 13px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">③ <strong>施肥計画が存在しないケース</strong> — 作付け品種を変更しても施肥計画がない場合(<code style="font-family: monospace; color: rgb(255, 255, 255); background-color: rgb(9, 52, 95); padding: 2px 4px; border-radius: 3px; word-break: break-word; font-size: 0.9em;">moved_count = 0</code>)のテストがない。</p><p style="white-space: pre-wrap; margin-top: 0.1em; margin-bottom: 0.2em; color: rgb(41, 41, 41); font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, sans-serif; font-size: 13px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">これら3点は現状の実装が正しく動くケースですが、将来の改修時に壊れても検知できません。<strong>今回のスコープとしては許容範囲</strong>ですが、必要であれば追加できます。</p><hr style="font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, sans-serif; font-size: 13px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><h3 style="color: rgb(41, 41, 41); font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">気になる点(1件・要確認)</h3><p style="white-space: pre-wrap; margin-top: 0.1em; margin-bottom: 0.2em; color: rgb(41, 41, 41); font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, sans-serif; font-size: 13px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><strong>同一旧品種計画に同一圃場のエントリが複数肥料分ある場合の new_plan の数</strong></p><p style="white-space: pre-wrap; margin-top: 0.1em; margin-bottom: 0.2em; color: rgb(41, 41, 41); font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, sans-serif; font-size: 13px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">現在の実装では「旧計画1件 → 新計画1件」を作ります。ただし、同じ <code style="font-family: monospace; color: rgb(255, 255, 255); background-color: rgb(9, 52, 95); padding: 2px 4px; border-radius: 3px; word-break: break-word; font-size: 0.9em;">old_plan</code> の中に <code style="font-family: monospace; color: rgb(255, 255, 255); background-color: rgb(9, 52, 95); padding: 2px 4px; border-radius: 3px; word-break: break-word; font-size: 0.9em;">actual_bags=None</code> のエントリが複数肥料分あっても、新計画は1件しか作りません(同じ <code style="font-family: monospace; color: rgb(255, 255, 255); background-color: rgb(9, 52, 95); padding: 2px 4px; border-radius: 3px; word-break: break-word; font-size: 0.9em;">new_plan</code> にまとめて移動される)。これは正しい動作ですか?</p><p style="white-space: pre-wrap; margin-top: 0.1em; margin-bottom: 0.2em; color: rgb(41, 41, 41); font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, sans-serif; font-size: 13px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">コードを追うと:</p><div class="codeBlockWrapper_-a7MRw" style="position: relative; margin: 8px 0px; color: rgb(41, 41, 41); font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, sans-serif; font-size: 13px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><button class="copyButton_CEmTFw copyButton_-a7MRw" title="Copy code" aria-label="Copy code to clipboard" style="color: rgb(41, 41, 41); font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, sans-serif; font-size: 13px; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255); border-color: rgb(15, 74, 133); border-style: solid; border-width: 1px; border-image: none 100% / 1 / 0 stretch; cursor: pointer; opacity: 0; display: flex; border-radius: 4px; justify-content: center; align-items: center; padding: 4px; transition: opacity 0.15s, background 0.15s; position: absolute; top: 4px; right: 4px;"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" data-slot="icon" class="copyIcon_CEmTFw"><path fill-rule="evenodd" d="M15.988 3.012A2.25 2.25 0 0 1 18 5.25v6.5A2.25 2.25 0 0 1 15.75 14H13.5v-3.379a3 3 0 0 0-.879-2.121l-3.12-3.121a3 3 0 0 0-1.402-.791 2.252 2.252 0 0 1 1.913-1.576A2.25 2.25 0 0 1 12.25 1h1.5a2.25 2.25 0 0 1 2.238 2.012ZM11.5 3.25a.75.75 0 0 1 .75-.75h1.5a.75.75 0 0 1 .75.75v.25h-3v-.25Z" clip-rule="evenodd"></path><path d="M3.5 6A1.5 1.5 0 0 0 2 7.5v9A1.5 1.5 0 0 0 3.5 18h7a1.5 1.5 0 0 0 1.5-1.5v-5.879a1.5 1.5 0 0 0-.44-1.06L8.44 6.439A1.5 1.5 0 0 0 7.378 6H3.5Z"></path></svg></button><pre style="overflow-x: auto; white-space: pre; box-sizing: border-box; border-radius: 4px; max-width: 100%; margin: 0px; padding: 8px;"><code class="language-python" style="font-family: monospace; color: rgb(255, 255, 255); background-color: rgb(9, 52, 95); padding: 0px; border-radius: 3px; word-break: break-word; font-size: 0.9em;">for old_plan in old_plans: entries_to_move = list(old_plan.entries.filter(field_id=..., actual_bags__isnull=True)) # → entries_to_move に複数肥料分が入る new_plan = FertilizationPlan.objects.create(...) # 1件作成 FertilizationEntry.objects.filter(id__in=[...]).update(plan=new_plan) # 全部まとめて移動 </code></pre></div><p style="white-space: pre-wrap; margin-top: 0.1em; margin-bottom: 0.2em; color: rgb(41, 41, 41); font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, sans-serif; font-size: 13px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">仕様書(9-2)の記述「<code style="font-family: monospace; color: rgb(255, 255, 255); background-color: rgb(9, 52, 95); padding: 2px 4px; border-radius: 3px; word-break: break-word; font-size: 0.9em;">{year}年度 {品種名} 施肥計画(品種変更移動)</code>」という命名から、1つの移動イベントに対して1計画を作る意図と読めるので、これは正しいと思いますが念のため確認させてください。</p><!--EndFragment--> </body> </html>
Author
Owner

完了

#11 の議論で仕様がB案(全entry移動)に変更され、実装済みです。

確定仕様(B案)

  • 散布済・未散布を問わず、対象圖場のentryを全件新品種計画へ移動
  • RESERVEはplan単位で再生成

対応コミット

  • c675b7b Move all fertilization entries on variety change(未散布のみ移動→全entry移動に変更)
  • c90c621 Add fertilization plan merge workflow(既存計画へのマージ機能追加)

元の受け入れ条件はA案前提で書かれていましたが、B案への変更とマージ機能の追加をもって実装完了とします。

## 完了 #11 の議論で仕様がB案(全entry移動)に変更され、実装済みです。 ### 確定仕様(B案) - 散布済・未散布を問わず、対象圖場のentryを全件新品種計画へ移動 - RESERVEはplan単位で再生成 ### 対応コミット - `c675b7b` Move all fertilization entries on variety change(未散布のみ移動→全entry移動に変更) - `c90c621` Add fertilization plan merge workflow(既存計画へのマージ機能追加) 元の受け入れ条件はA案前提で書かれていましたが、B案への変更とマージ機能の追加をもって実装完了とします。
akira closed this issue 2026-04-07 01:24:03 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: akira/keinasystem#6