Skip to content

Commit c941004

Browse files
KAAV-3492 adding logic fixes
1 parent b597cf8 commit c941004

1 file changed

Lines changed: 83 additions & 3 deletions

File tree

projects/models/project.py

Lines changed: 83 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,10 @@ def _set_calculated_deadline(self, deadline, date, user, preview, preview_attrib
536536
identifier = deadline.attribute.identifier
537537
if identifier in confirmed_fields:
538538
# Get the original confirmed value - don't let calculation overwrite it
539+
# KAAV-3492 FIX: If previewing, prefer the value from the request (preview_attribute_data)
540+
# because self.attribute_data might be stale (e.g. if user just edited it)
541+
if preview and preview_attribute_data and identifier in preview_attribute_data:
542+
return preview_attribute_data.get(identifier)
539543
return self.attribute_data.get(identifier)
540544

541545
# NOTE: Removed line that prioritized preview_attribute_data over calculated value
@@ -881,14 +885,80 @@ def get_preview_deadlines(self, updated_attributes, subtype, confirmed_fields=No
881885
log.info(f"[KAAV-3492 BACKEND] Visibility bool enabled: {key}")
882886

883887
# For each deadline, if its visibility bool was just enabled, mark its date as "changed"
884-
for dl in project_dls.keys():
888+
for dl in sorted(project_dls.keys(), key=lambda x: x.index):
885889
if not dl.deadlinegroup or not dl.attribute:
886890
continue
887891
vis_bool = get_dl_vis_bool_name(dl.deadlinegroup)
888892
if vis_bool and vis_bool in vis_bools_enabled:
893+
identifier = dl.attribute.identifier
894+
895+
# Check for stale date: Group enabled, but date matches stored value
896+
current_val = updated_attribute_data.get(identifier)
897+
stored_val = self.attribute_data.get(identifier)
898+
899+
current_date = self._coerce_date_value(current_val)
900+
stored_date = self._coerce_date_value(stored_val)
901+
902+
if current_date and current_date == stored_date:
903+
# Calculate target date based on predecessors
904+
max_target = None
905+
for distance in dl.distances_to_previous.all():
906+
combined = {**self.attribute_data, **updated_attribute_data}
907+
if not distance.check_conditions(combined):
908+
continue
909+
prev_date = self._resolve_deadline_date(distance.previous_deadline, updated_attribute_data)
910+
prev_date = self._coerce_date_value(prev_date)
911+
if not prev_date:
912+
continue
913+
target = self._min_distance_target_date(prev_date, distance, dl)
914+
if target and (not max_target or target > max_target):
915+
max_target = target
916+
917+
# SPECIAL CASE (AT1.5.3): Opinions deadline ("viimeistaan_mielipiteet")
918+
# defaults to matching "esillaolo_paattyy" if no distance rules exist
919+
if not max_target and "viimeistaan_mielipiteet" in identifier:
920+
# Find sibling "esillaolo_paattyy" in same group
921+
sibling = next((d for d in project_dls.keys() if d.deadlinegroup == dl.deadlinegroup and "esillaolo_paattyy" in (d.attribute.identifier if d.attribute else "")), None)
922+
if sibling and sibling.attribute:
923+
# Use updated_attribute_data if present (already snapped), else stored
924+
sib_id = sibling.attribute.identifier
925+
sib_val = updated_attribute_data.get(sib_id) or self.attribute_data.get(sib_id)
926+
if sib_val:
927+
max_target = self._coerce_date_value(sib_val)
928+
log.info(f"[KAAV-3492 BACKEND] Derived target for {identifier} from {sib_id}: {max_target}")
929+
930+
# If current date creates a gap (is later than target), snap it back
931+
if max_target and current_date > max_target:
932+
log.info(f"[KAAV-3492 BACKEND] Snapping stale date {identifier} from {current_date} to {max_target}")
933+
updated_attribute_data[identifier] = max_target
934+
935+
# UX80.4.2.3.7: When adding element row, update phase boundaries
936+
# so cascade calculates from the correct snapped position
937+
if "_paattyy" in identifier:
938+
# Map identifier patterns to phase boundary pairs
939+
PHASE_BOUNDARY_MAP = {
940+
"oas": ("oasvaihe_paattyy_pvm", "ehdotusvaihe_alkaa_pvm"),
941+
"periaatteet": ("periaatteetvaihe_paattyy_pvm", "oasvaihe_alkaa_pvm"),
942+
"luonnos": ("luonnosvaihe_paattyy_pvm", "ehdotusvaihe_alkaa_pvm"),
943+
}
944+
# Special case: ehdotus but not tarkistettu
945+
if "ehdotus" in identifier and "tarkistettu" not in identifier:
946+
boundaries = ("ehdotusvaihe_paattyy_pvm", "tarkistettuehdotusvaihe_alkaa_pvm")
947+
else:
948+
boundaries = next((v for k, v in PHASE_BOUNDARY_MAP.items() if k in identifier), None)
949+
950+
if boundaries:
951+
phase_end_id, next_phase_start_id = boundaries
952+
current_phase_end = self._coerce_date_value(updated_attribute_data.get(phase_end_id))
953+
if current_phase_end and max_target != current_phase_end:
954+
log.info(f"[KAAV-3492 BACKEND] Updating phase boundary {phase_end_id} to {max_target}")
955+
updated_attribute_data[phase_end_id] = max_target
956+
updated_attribute_data[next_phase_start_id] = max_target
957+
actually_changed.update([phase_end_id, next_phase_start_id])
958+
889959
# This deadline's group was just re-enabled - treat its date as changed
890-
actually_changed.add(dl.attribute.identifier)
891-
log.info(f"[KAAV-3492 BACKEND] Marking {dl.attribute.identifier} as changed due to vis_bool {vis_bool}")
960+
actually_changed.add(identifier)
961+
log.info(f"[KAAV-3492 BACKEND] Marking {identifier} as changed due to vis_bool {vis_bool}")
892962

893963
log.info(f"[KAAV-3492 BACKEND] actually_changed set: {actually_changed}")
894964

@@ -1159,6 +1229,10 @@ def get_preview_deadlines(self, updated_attributes, subtype, confirmed_fields=No
11591229
continue
11601230
min_target = self._min_distance_target_date(prev_date, distance, dl)
11611231
if min_target and current_date < min_target:
1232+
# KAAV-3492: Do not try to enforce confirmed fields
1233+
if confirmed_fields and identifier in confirmed_fields:
1234+
continue
1235+
11621236
log.info(f"[CONVERGENCE CHECK] {identifier} violates distance rule (prev={prev_date}, min={min_target})")
11631237
cascade_queue.add(identifier)
11641238
break
@@ -1189,6 +1263,9 @@ def get_preview_deadlines(self, updated_attributes, subtype, confirmed_fields=No
11891263
continue
11901264
min_target = self._min_distance_target_date(prev_date, distance, changed_dl)
11911265
if min_target and current_date < min_target:
1266+
if confirmed_fields and changed_id in confirmed_fields:
1267+
log.info(f"[CONVERGENCE ENFORCE] Skipping confirmed {changed_id}")
1268+
continue
11921269
log.info(f"[CONVERGENCE ENFORCE] {changed_id} from {current_date} to {min_target}")
11931270
enforced = self._enforce_distance_requirements(changed_dl, min_target, updated_attribute_data)
11941271
if enforced and enforced != current_date:
@@ -1223,6 +1300,9 @@ def get_preview_deadlines(self, updated_attributes, subtype, confirmed_fields=No
12231300

12241301
min_target = self._min_distance_target_date(current_date, distance, next_dl)
12251302
if min_target and next_date < min_target:
1303+
if confirmed_fields and next_id in confirmed_fields:
1304+
log.info(f"[CONVERGENCE PUSH] Skipping confirmed {next_id}")
1305+
continue
12261306
log.info(f"[CONVERGENCE PUSH] Pushing {next_id} from {next_date} to {min_target} (because {changed_id} moved)")
12271307
new_cascade_changes.add(next_id)
12281308
iteration_changes.add(next_id)

0 commit comments

Comments
 (0)