@@ -16,42 +16,47 @@ const permissions = tcMiddleware.permissions;
16
16
17
17
/**
18
18
* Cascades endDate/completionDate changes to all milestones with a greater order than the given one.
19
- * @param {Object } originalMilestone the original milestone that was updated
20
- * @param {Object } updatedMilestone the milestone that was updated
19
+ * @param {Object } origMilestone the original milestone that was updated
20
+ * @param {Object } updMilestone the milestone that was updated
21
21
* @returns {Promise<void> } a promise that resolves to the last found milestone. If no milestone exists with an
22
- * order greater than the passed <b>updatedMilestone </b>, the promise will resolve to the passed
23
- * <b>updatedMilestone </b>
22
+ * order greater than the passed <b>updMilestone </b>, the promise will resolve to the passed
23
+ * <b>updMilestone </b>
24
24
*/
25
- function updateComingMilestones ( originalMilestone , updatedMilestone ) {
25
+ function updateComingMilestones ( origMilestone , updMilestone ) {
26
26
// flag to indicate if the milestone in picture, is updated for completionDate field or not
27
- const completionDateChanged = ! _ . isEqual ( originalMilestone . completionDate , updatedMilestone . completionDate ) ;
27
+ const completionDateChanged = ! _ . isEqual ( origMilestone . completionDate , updMilestone . completionDate ) ;
28
28
const today = moment . utc ( ) . hours ( 0 ) . minutes ( 0 ) . seconds ( 0 )
29
29
. milliseconds ( 0 ) ;
30
+ // updated milestone's start date, pefers actual start date over scheduled start date
31
+ const updMSStartDate = updMilestone . actualStartDate ? updMilestone . actualStartDate : updMilestone . startDate ;
32
+ // calculates schedule end date for the milestone based on start date and duration
33
+ let updMilestoneEndDate = moment . utc ( updMSStartDate ) . add ( updMilestone . duration - 1 , 'days' ) . toDate ( ) ;
34
+ // if the milestone, in context, is completed, overrides the end date to the completion date
35
+ updMilestoneEndDate = updMilestone . completionDate ? updMilestone . completionDate : updMilestoneEndDate ;
30
36
return models . Milestone . findAll ( {
31
37
where : {
32
- timelineId : updatedMilestone . timelineId ,
33
- order : { $gt : updatedMilestone . order } ,
38
+ timelineId : updMilestone . timelineId ,
39
+ order : { $gt : updMilestone . order } ,
34
40
} ,
35
41
} ) . then ( ( affectedMilestones ) => {
36
42
const comingMilestones = _ . sortBy ( affectedMilestones , 'order' ) ;
37
- let startDate = moment . utc ( updatedMilestone . completionDate
38
- ? updatedMilestone . completionDate
39
- : updatedMilestone . endDate ) . add ( 1 , 'days' ) . toDate ( ) ;
43
+ // calculates the schedule start date for the next milestone
44
+ let startDate = moment . utc ( updMilestoneEndDate ) . add ( 1 , 'days' ) . toDate ( ) ;
40
45
let firstMilestoneFound = false ;
41
46
const promises = _ . map ( comingMilestones , ( _milestone ) => {
42
47
const milestone = _milestone ;
43
48
44
49
// Update the milestone startDate if different than the iterated startDate
45
50
if ( ! _ . isEqual ( milestone . startDate , startDate ) ) {
46
51
milestone . startDate = startDate ;
47
- milestone . updatedBy = updatedMilestone . updatedBy ;
52
+ milestone . updatedBy = updMilestone . updatedBy ;
48
53
}
49
54
50
55
// Calculate the endDate, and update it if different
51
56
const endDate = moment . utc ( startDate ) . add ( milestone . duration - 1 , 'days' ) . toDate ( ) ;
52
57
if ( ! _ . isEqual ( milestone . endDate , endDate ) ) {
53
58
milestone . endDate = endDate ;
54
- milestone . updatedBy = updatedMilestone . updatedBy ;
59
+ milestone . updatedBy = updMilestone . updatedBy ;
55
60
}
56
61
57
62
// if completionDate is alerted, update status of the first non hidden milestone after the current one
@@ -160,10 +165,7 @@ module.exports = [
160
165
// Merge JSON fields
161
166
entityToUpdate . details = util . mergeJsonObjects ( milestone . details , entityToUpdate . details ) ;
162
167
163
- if ( durationChanged ) {
164
- entityToUpdate . endDate = moment . utc ( milestone . startDate ) . add ( entityToUpdate . duration - 1 , 'days' ) . toDate ( ) ;
165
- }
166
-
168
+ let actualStartDateCanged = false ;
167
169
// if status has changed
168
170
if ( statusChanged ) {
169
171
// if status has changed to be completed, set the compeltionDate if not provided
@@ -176,9 +178,21 @@ module.exports = [
176
178
// entityToUpdate.startDate = today;
177
179
// should update actual start date
178
180
entityToUpdate . actualStartDate = today ;
181
+ actualStartDateCanged = true ;
179
182
}
180
183
}
181
184
185
+ // Updates the end date of the milestone if:
186
+ // 1. if duration of the milestone is udpated, update its end date
187
+ // OR
188
+ // 2. if actual start date is updated, updating the end date of the activated milestone because
189
+ // early or late start of milestone, we are essentially changing the end schedule of the milestone
190
+ if ( durationChanged || actualStartDateCanged ) {
191
+ const updatedStartDate = actualStartDateCanged ? entityToUpdate . actualStartDate : milestone . startDate ;
192
+ const updatedDuration = _ . get ( entityToUpdate , 'duration' , milestone . duration ) ;
193
+ entityToUpdate . endDate = moment . utc ( updatedStartDate ) . add ( updatedDuration - 1 , 'days' ) . toDate ( ) ;
194
+ }
195
+
182
196
// if completionDate has changed
183
197
if ( ! statusChanged && completionDateChanged ) {
184
198
entityToUpdate . status = MILESTONE_STATUS . COMPLETED ;
0 commit comments