From 58e923e2e935ab511709b0b18cfcacefd4d42807 Mon Sep 17 00:00:00 2001 From: Noah-Drew Date: Wed, 8 Oct 2025 19:03:43 -0400 Subject: [PATCH 1/4] Create Explain Project EAC (Estimate At Completion) Value The Estimate At Completion value (EAC) for Projects can be hard to visualize. This script will print out messages to explain the calculation and how the value is getting calculated. Run this in the [System Defintion > Scripts - Background] module. Set the "projectId" variable on line 1 with the Sys ID of your pm_project record --- ...Project EAC (Estimate At Completion) Value | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 Specialized Areas/Project Management/Explain Project EAC (Estimate At Completion) Value/Explain Project EAC (Estimate At Completion) Value diff --git a/Specialized Areas/Project Management/Explain Project EAC (Estimate At Completion) Value/Explain Project EAC (Estimate At Completion) Value b/Specialized Areas/Project Management/Explain Project EAC (Estimate At Completion) Value/Explain Project EAC (Estimate At Completion) Value new file mode 100644 index 0000000000..212c6ceafc --- /dev/null +++ b/Specialized Areas/Project Management/Explain Project EAC (Estimate At Completion) Value/Explain Project EAC (Estimate At Completion) Value @@ -0,0 +1,90 @@ +var projectId = ''; + +var instanceName = gs.getProperty('instance_name'); + +gs.info('Ensure you have clicked the "Calculate Completion Estimates" related link on the Project form to sync up the EAC with the latest data.'); +gs.info(''); +var fiscalCal = new ITFM_FiscalCalendar(); +var fiscalObject = fiscalCal.validatePeriods(); +var parsedFiscalObject = JSON.parse(fiscalObject); + +if (parsedFiscalObject.type == "Error") { +gs.info('Fiscal Calendar is not valid which may cause issues with the expected EAC calculation:'); +gs.info(parsedFiscalObject.msg); +} + +var currentFiscalPeriod = new FinancialsForPPM().getCurrentFiscalPeriod(); +var currentFiscalPeriodId = JSON.parse(currentFiscalPeriod).fiscal_period; +var grFP = new GlideRecord('fiscal_period'); +grFP.get(currentFiscalPeriodId); + +var startDate = grFP.getValue('start_date_time'); +var year = startDate.substring(0,4); +var month = startDate.substring(4,6); +var day = startDate.substring(6,8); +var date = year + "-" + month + "-" + day; + +gs.info(''); +gs.info('The current Fiscal Period is named "' + grFP.getDisplayValue() + '" and the Sys ID is ' + currentFiscalPeriodId); + +gs.info(''); +gs.info('EAC calculation: Total actual costs from previous months + Total planned cost from the current and future months'); + +var capexFuture = 0; +var opexFuture = 0; +var capexActual = 0; +var opexActual = 0; + +var aggCapexFuture = new GlideAggregate('cost_plan_breakdown'); +aggCapexFuture.addAggregate('SUM', 'cost_default_currency'); +aggCapexFuture.addEncodedQuery("breakdown_type=task^task=" + projectId + "^expense_type=capex^fiscal_period.fiscal_start_date_time>=javascript:gs.dateGenerate('" + date + "','00:00:00')"); +aggCapexFuture.setGroup(false); +aggCapexFuture.query(); +if (aggCapexFuture.next()) { +capexFuture = aggCapexFuture.getAggregate('SUM', 'cost_default_currency'); +gs.info(''); +gs.info('Capex Future Costs: ' + aggCapexFuture.getAggregate('SUM', 'cost_default_currency')); +gs.info("https://" + instanceName + ".service-now.com/" + "cost_plan_breakdown_list.do?sysparm_query=breakdown_type%3Dtask%5Etask%3D" + projectId + "%5Eexpense_type%3Dcapex%5Efiscal_period.fiscal_start_date_time%3E%3Djavascript%3Ags.dateGenerate('" + date + "'%2C'00%3A00%3A00')&sysparm_view="); +} + +var aggOpexFuture = new GlideAggregate('cost_plan_breakdown'); +aggOpexFuture.addAggregate('SUM', 'cost_default_currency'); +aggOpexFuture.addEncodedQuery("breakdown_type=task^task=" + projectId + "^expense_type=opex^fiscal_period.fiscal_start_date_time>=javascript:gs.dateGenerate('" + date + "','00:00:00')"); +aggOpexFuture.setGroup(false); +aggOpexFuture.query(); +if (aggOpexFuture.next()) { +opexFuture = aggOpexFuture.getAggregate('SUM', 'cost_default_currency'); +gs.info(''); +gs.info('Opex Future Costs: ' + aggOpexFuture.getAggregate('SUM', 'cost_default_currency')); +gs.info("https://" + instanceName + ".service-now.com/" + "cost_plan_breakdown_list.do?sysparm_query=breakdown_type%3Dtask%5Etask%3D" + projectId + "%5Eexpense_type%3Dopex%5Efiscal_period.fiscal_start_date_time%3E%3Djavascript%3Ags.dateGenerate('" + date + "'%2C'00%3A00%3A00')&sysparm_view="); +} + +var aggCapexActual = new GlideAggregate('cost_plan_breakdown'); +aggCapexActual.addAggregate('SUM', 'actual'); +aggCapexActual.addEncodedQuery("breakdown_type=task^task=" + projectId + "^expense_type=capex^fiscal_period.fiscal_start_date_time=javascript:gs.dateGenerate('" + date + "','00:00:00')"); -aggCapexFuture.setGroup(false); -aggCapexFuture.query(); -if (aggCapexFuture.next()) { -capexFuture = aggCapexFuture.getAggregate('SUM', 'cost_default_currency'); -gs.info(''); -gs.info('Capex Future Costs: ' + aggCapexFuture.getAggregate('SUM', 'cost_default_currency')); -gs.info("https://" + instanceName + ".service-now.com/" + "cost_plan_breakdown_list.do?sysparm_query=breakdown_type%3Dtask%5Etask%3D" + projectId + "%5Eexpense_type%3Dcapex%5Efiscal_period.fiscal_start_date_time%3E%3Djavascript%3Ags.dateGenerate('" + date + "'%2C'00%3A00%3A00')&sysparm_view="); -} - -var aggOpexFuture = new GlideAggregate('cost_plan_breakdown'); -aggOpexFuture.addAggregate('SUM', 'cost_default_currency'); -aggOpexFuture.addEncodedQuery("breakdown_type=task^task=" + projectId + "^expense_type=opex^fiscal_period.fiscal_start_date_time>=javascript:gs.dateGenerate('" + date + "','00:00:00')"); -aggOpexFuture.setGroup(false); -aggOpexFuture.query(); -if (aggOpexFuture.next()) { -opexFuture = aggOpexFuture.getAggregate('SUM', 'cost_default_currency'); -gs.info(''); -gs.info('Opex Future Costs: ' + aggOpexFuture.getAggregate('SUM', 'cost_default_currency')); -gs.info("https://" + instanceName + ".service-now.com/" + "cost_plan_breakdown_list.do?sysparm_query=breakdown_type%3Dtask%5Etask%3D" + projectId + "%5Eexpense_type%3Dopex%5Efiscal_period.fiscal_start_date_time%3E%3Djavascript%3Ags.dateGenerate('" + date + "'%2C'00%3A00%3A00')&sysparm_view="); -} - -var aggCapexActual = new GlideAggregate('cost_plan_breakdown'); -aggCapexActual.addAggregate('SUM', 'actual'); -aggCapexActual.addEncodedQuery("breakdown_type=task^task=" + projectId + "^expense_type=capex^fiscal_period.fiscal_start_date_time=javascript:gs.dateGenerate('" + date + "','00:00:00')"); +aggCapexFuture.setGroup(false); +aggCapexFuture.query(); +if (aggCapexFuture.next()) { +capexFuture = aggCapexFuture.getAggregate('SUM', 'cost_default_currency'); +gs.info(''); +gs.info('Capex Future Costs: ' + aggCapexFuture.getAggregate('SUM', 'cost_default_currency')); +gs.info("https://" + instanceName + ".service-now.com/" + "cost_plan_breakdown_list.do?sysparm_query=breakdown_type%3Dtask%5Etask%3D" + projectId + "%5Eexpense_type%3Dcapex%5Efiscal_period.fiscal_start_date_time%3E%3Djavascript%3Ags.dateGenerate('" + date + "'%2C'00%3A00%3A00')&sysparm_view="); +} + +var aggOpexFuture = new GlideAggregate('cost_plan_breakdown'); +aggOpexFuture.addAggregate('SUM', 'cost_default_currency'); +aggOpexFuture.addEncodedQuery("breakdown_type=task^task=" + projectId + "^expense_type=opex^fiscal_period.fiscal_start_date_time>=javascript:gs.dateGenerate('" + date + "','00:00:00')"); +aggOpexFuture.setGroup(false); +aggOpexFuture.query(); +if (aggOpexFuture.next()) { +opexFuture = aggOpexFuture.getAggregate('SUM', 'cost_default_currency'); +gs.info(''); +gs.info('Opex Future Costs: ' + aggOpexFuture.getAggregate('SUM', 'cost_default_currency')); +gs.info("https://" + instanceName + ".service-now.com/" + "cost_plan_breakdown_list.do?sysparm_query=breakdown_type%3Dtask%5Etask%3D" + projectId + "%5Eexpense_type%3Dopex%5Efiscal_period.fiscal_start_date_time%3E%3Djavascript%3Ags.dateGenerate('" + date + "'%2C'00%3A00%3A00')&sysparm_view="); +} + +var aggCapexActual = new GlideAggregate('cost_plan_breakdown'); +aggCapexActual.addAggregate('SUM', 'actual'); +aggCapexActual.addEncodedQuery("breakdown_type=task^task=" + projectId + "^expense_type=capex^fiscal_period.fiscal_start_date_time