Skip to content

Bug/64292 disabling an incomplete phase leads to inconsistencies #19058

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: release/16.1
Choose a base branch
from

Conversation

dombesz
Copy link
Contributor

@dombesz dombesz commented May 29, 2025

Ticket

https://community.openproject.org/wp/64292

What are you trying to accomplish?

Screenshots

What approach did you choose and why?

Merge checklist

  • Added/updated tests
  • Added/updated documentation in Lookbook (patterns, previews, etc)
  • Tested major browsers (Chrome, Firefox, Edge, ...)

@dombesz dombesz changed the base branch from dev to release/16.1 June 5, 2025 10:06
@dombesz dombesz force-pushed the bug/64292-disabling-an-incomplete-phase-leads-to-inconsistencies branch 4 times, most recently from 0d78305 to e84e1ea Compare June 6, 2025 06:28
dombesz added 4 commits June 6, 2025 09:55
https://community.openproject.org/work_packages/64292

Reschedule following phases to the closest active preceding phase when activating/deactivating a phase.

This is an important step, because otherwise unset phases' default dates
will be left behind during rescheduling.

Move default start date on phases during rescheduling on phases where no finish date is set.
This change is required because we do not refresh the form on every
keystroke to dynamically display the clear button, so it's better to
display it all the time as we do on the work package datepicker.
@dombesz dombesz force-pushed the bug/64292-disabling-an-incomplete-phase-leads-to-inconsistencies branch from e84e1ea to a9e18cc Compare June 6, 2025 06:55
@dombesz dombesz marked this pull request as ready for review June 6, 2025 08:53
@dombesz dombesz requested a review from Copilot June 6, 2025 08:54
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR ensures consistent rescheduling when disabling or updating phases without a complete date range, adds working‐day awareness, and updates related specs and UI behavior.

  • UpdateService now skips to the next working day after a finish date and supports rescheduling a following phase that only has a start date.
  • RescheduleService refactored to handle phases with only start dates and to separate date‐range updates into a helper.
  • ActivationService simplified preceding‐phase logic; form behavior for clear buttons was relaxed.
  • Tests and feature specs updated to cover the new scenarios and permission.

Reviewed Changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated no comments.

Show a summary per file
File Description
spec/services/project_life_cycle_steps/update_service_spec.rb Added test for following phase with only a start date.
spec/services/project_life_cycle_steps/reschedule_service_spec.rb Renamed example and adjusted expected dates for start‐date‐only phases.
spec/services/project_life_cycle_steps/activation_service_spec.rb Updated descriptions and expected dates to use closest preceding date range.
spec/features/projects/life_cycle/active_in_project_spec.rb Added edit_project_phases permission to feature spec.
app/services/project_life_cycle_steps/update_service.rb Use Day.next_working for initial reschedule date.
app/services/project_life_cycle_steps/reschedule_service.rb Refactored looping logic and extracted set_phase_dates_and_next_start.
app/services/project_life_cycle_steps/activation_service.rb Removed date‐range guard to always pick a preceding phase.
app/forms/projects/life_cycles/form.rb Simplified show_clear_button?, now ignores value presence.
Comments suppressed due to low confidence (2)

app/forms/projects/life_cycles/form.rb:106

  • Removing the presence check causes the clear button to appear even when no date is set, which can confuse users. Consider reintroducing value(field_name).present? to hide the button when there is nothing to clear.
when :start_date

app/services/project_life_cycle_steps/reschedule_service.rb:50

  • [nitpick] Mutating the method argument from inside the loop can be error‐prone. Introduce a separate local variable (e.g. next_from) for clarity and to avoid side effects on the original parameter.
def reschedule_phases(phases:, from:)

Copy link
Contributor

@toy toy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, what do you think about first two points?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is probably better to use RescheduleService instead of UpdateService after upsert in persist, unless it leads to much code duplication

@@ -48,7 +48,7 @@ def reschedule_following_phases
end

def initial_reschedule_date
model.active? ? model.finish_date + 1 : model.start_date
model.active? ? Day.next_working(from: model.finish_date).date : model.start_date
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is better to handle finding next working day in RescheduleService

Also looking at Day.next_working I have a feeling that it is easy for it to return nil - it is not rare to have even few weeks of non working days on organisation level (like CERN)

Comment on lines +53 to +54
next_start_date = set_phase_dates_and_next_start(phase, from)
from = next_start_date unless next_start_date.nil?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
next_start_date = set_phase_dates_and_next_start(phase, from)
from = next_start_date unless next_start_date.nil?
from = set_phase_dates_and_next_start(phase, from) || from

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe it reads a bit better to have the condition instead of having just the ||.

@@ -165,6 +165,17 @@
end
end

context "for following phase with a start date only" do
let!(:phase) { create(:project_phase, project:, start_date: date, finish_date: date) }
let!(:following) { create(:project_phase, project:, start_date: date + 1, finish_date: nil, duration: 3) }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

duration should be nil here, probably easier implicitly:

Suggested change
let!(:following) { create(:project_phase, project:, start_date: date + 1, finish_date: nil, duration: 3) }
let!(:following) { create(:project_phase, project:, start_date: date + 1, finish_date: nil) }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having an unrelated duration makes sure we do not accidentally clear or re-calculate the duration while rescheduling with a start date only.

it "reschedules by moving the start date only" do
expect(service.call(start_date: date, finish_date: date + 1)).to be_success

expect(following).to have_attributes(start_date: date + 2, finish_date: nil, duration: 3)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
expect(following).to have_attributes(start_date: date + 2, finish_date: nil, duration: 3)
expect(following).to have_attributes(start_date: date + 2, finish_date: nil, duration: nil)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging this pull request may close these issues.

2 participants