@@ -16,42 +16,47 @@ const permissions = tcMiddleware.permissions;
1616
1717/**
1818 * 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
2121 * @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>
2424 */
25- function updateComingMilestones ( originalMilestone , updatedMilestone ) {
25+ function updateComingMilestones ( origMilestone , updMilestone ) {
2626 // 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 ) ;
2828 const today = moment . utc ( ) . hours ( 0 ) . minutes ( 0 ) . seconds ( 0 )
2929 . 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 ;
3036 return models . Milestone . findAll ( {
3137 where : {
32- timelineId : updatedMilestone . timelineId ,
33- order : { $gt : updatedMilestone . order } ,
38+ timelineId : updMilestone . timelineId ,
39+ order : { $gt : updMilestone . order } ,
3440 } ,
3541 } ) . then ( ( affectedMilestones ) => {
3642 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 ( ) ;
4045 let firstMilestoneFound = false ;
4146 const promises = _ . map ( comingMilestones , ( _milestone ) => {
4247 const milestone = _milestone ;
4348
4449 // Update the milestone startDate if different than the iterated startDate
4550 if ( ! _ . isEqual ( milestone . startDate , startDate ) ) {
4651 milestone . startDate = startDate ;
47- milestone . updatedBy = updatedMilestone . updatedBy ;
52+ milestone . updatedBy = updMilestone . updatedBy ;
4853 }
4954
5055 // Calculate the endDate, and update it if different
5156 const endDate = moment . utc ( startDate ) . add ( milestone . duration - 1 , 'days' ) . toDate ( ) ;
5257 if ( ! _ . isEqual ( milestone . endDate , endDate ) ) {
5358 milestone . endDate = endDate ;
54- milestone . updatedBy = updatedMilestone . updatedBy ;
59+ milestone . updatedBy = updMilestone . updatedBy ;
5560 }
5661
5762 // if completionDate is alerted, update status of the first non hidden milestone after the current one
@@ -160,10 +165,7 @@ module.exports = [
160165 // Merge JSON fields
161166 entityToUpdate . details = util . mergeJsonObjects ( milestone . details , entityToUpdate . details ) ;
162167
163- if ( durationChanged ) {
164- entityToUpdate . endDate = moment . utc ( milestone . startDate ) . add ( entityToUpdate . duration - 1 , 'days' ) . toDate ( ) ;
165- }
166-
168+ let actualStartDateCanged = false ;
167169 // if status has changed
168170 if ( statusChanged ) {
169171 // if status has changed to be completed, set the compeltionDate if not provided
@@ -176,9 +178,21 @@ module.exports = [
176178 // entityToUpdate.startDate = today;
177179 // should update actual start date
178180 entityToUpdate . actualStartDate = today ;
181+ actualStartDateCanged = true ;
179182 }
180183 }
181184
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+
182196 // if completionDate has changed
183197 if ( ! statusChanged && completionDateChanged ) {
184198 entityToUpdate . status = MILESTONE_STATUS . COMPLETED ;
0 commit comments