@outbuild-company/schedule-core 1.17.2 → 1.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -291,6 +291,7 @@ var READ_ONLY = {
291
291
  DURATION_BASE: "duration_base",
292
292
  COST_BASE: "cost_base",
293
293
  WORK_BASE: "work_base",
294
+ BASELINE_VARIANCE: "baseline_variance",
294
295
  CALENDAR_DURATION: "calendarDuration",
295
296
  IS_CRITICAL: "is_critical",
296
297
  EARLY_START: "earlyStart",
@@ -1044,6 +1045,7 @@ var FILTER_FIELD = {
1044
1045
  TOTAL_SLACK_DAYS: "totalSlackDays",
1045
1046
  EXPECTED_PROGRESS_BASELINE: "expectedProgressBaseline",
1046
1047
  BASELINE_DURATION_DAYS: "baselineDurationDays",
1048
+ BASELINE_VARIANCE_DAYS: "baselineVarianceDays",
1047
1049
  BASELINE_COST: "baselineCost",
1048
1050
  BASELINE_WORK_HOURS: "baselineWorkHours",
1049
1051
  EXPECTED_PROGRESS: "expectedProgress",
@@ -1211,6 +1213,10 @@ var FIELD_REGISTRY = {
1211
1213
  valueKind: FILTER_VALUE_KIND.NUMBER,
1212
1214
  extract: (activity) => activity.baselineSnapshot?.durationDays ?? null
1213
1215
  },
1216
+ [FILTER_FIELD.BASELINE_VARIANCE_DAYS]: {
1217
+ valueKind: FILTER_VALUE_KIND.NUMBER,
1218
+ extract: (activity) => activity.baselineVarianceDays
1219
+ },
1214
1220
  [FILTER_FIELD.BASELINE_COST]: {
1215
1221
  valueKind: FILTER_VALUE_KIND.NUMBER,
1216
1222
  extract: (activity) => activity.baselineSnapshot?.cost ?? null
@@ -2356,7 +2362,8 @@ var ACTIVITY_PROPERTY = {
2356
2362
  CUSTOM_ID: "customId",
2357
2363
  NEW_ACTIVITIES_ARRAY: "newActivityIds",
2358
2364
  HAS_NEW_ACTIVITIES: "hasNewActivities",
2359
- CALENDAR_DURATION: "calendarDuration"};
2365
+ CALENDAR_DURATION: "calendarDuration",
2366
+ BASELINE_VARIANCE_DAYS: "baselineVarianceDays"};
2360
2367
  var LINK_PROPERTY = {
2361
2368
  SOURCE: "source",
2362
2369
  TARGET: "target",
@@ -6288,12 +6295,16 @@ function mergeCorrelativeShiftIntoDiff(diff, correlativeBefore, activityId, live
6288
6295
  after: liveActivity.correlativeId
6289
6296
  };
6290
6297
  }
6298
+ var DERIVED_DISPLAY_FIELDS = [
6299
+ ACTIVITY_PROPERTY.CALENDAR_DURATION,
6300
+ ACTIVITY_PROPERTY.BASELINE_VARIANCE_DAYS
6301
+ ];
6291
6302
  function diffActivity(before, after) {
6292
6303
  const fields = {};
6293
6304
  const beforeRec = before ?? {};
6294
6305
  const afterRec = after;
6295
6306
  const keys = /* @__PURE__ */ new Set([...Object.keys(beforeRec), ...Object.keys(afterRec)]);
6296
- keys.delete(ACTIVITY_PROPERTY.CALENDAR_DURATION);
6307
+ for (const derived of DERIVED_DISPLAY_FIELDS) keys.delete(derived);
6297
6308
  for (const k of keys) {
6298
6309
  if (Object.hasOwn(beforeRec, k) !== Object.hasOwn(afterRec, k) || !fieldValueEqual(beforeRec[k], afterRec[k])) {
6299
6310
  fields[k] = {
@@ -6543,6 +6554,43 @@ function applyStatusPass(state, criteria) {
6543
6554
  return changed;
6544
6555
  }
6545
6556
 
6557
+ // src/propagations/shared/get-visible-baseline.ts
6558
+ function getVisibleBaseline(activity) {
6559
+ const points = activity?.baselinePoints;
6560
+ if (!Array.isArray(points) || points.length === 0) return null;
6561
+ return points.find((point) => point.isVisibleVersion) ?? null;
6562
+ }
6563
+
6564
+ // src/columns/baseline-variance/compute.ts
6565
+ var VARIANCE_DECIMAL_SCALE = 100;
6566
+ var roundToVariancePrecision = (days) => Math.round(days * VARIANCE_DECIMAL_SCALE) / VARIANCE_DECIMAL_SCALE;
6567
+ function computeBaselineVarianceDays(activity, calendars, hoursPerDay) {
6568
+ if (hoursPerDay <= 0) return null;
6569
+ const baselineEnd = getVisibleBaseline(activity)?.endDate;
6570
+ const activityEnd = activity.endDate;
6571
+ if (!baselineEnd || !activityEnd) return null;
6572
+ const finishesLate = activityEnd.getTime() > baselineEnd.getTime();
6573
+ const finishesEarly = baselineEnd.getTime() > activityEnd.getTime();
6574
+ if (!finishesLate && !finishesEarly) return 0;
6575
+ const durationHours = calendars.calculateDuration({
6576
+ startDate: finishesLate ? baselineEnd : activityEnd,
6577
+ endDate: finishesLate ? activityEnd : baselineEnd,
6578
+ task: activity
6579
+ });
6580
+ const magnitude = roundToVariancePrecision(durationHours / hoursPerDay);
6581
+ return finishesLate ? magnitude : -magnitude;
6582
+ }
6583
+ function applyBaselineVariancePass(state, hoursPerDay) {
6584
+ const changed = [];
6585
+ state.forEachActivity((activity, id) => {
6586
+ const variance = computeBaselineVarianceDays(activity, state, hoursPerDay);
6587
+ if (activity.baselineVarianceDays === variance) return;
6588
+ activity.baselineVarianceDays = variance;
6589
+ changed.push(String(id));
6590
+ });
6591
+ return changed;
6592
+ }
6593
+
6546
6594
  // src/critical-path/legacy/shims/moment.js
6547
6595
  function moment(input) {
6548
6596
  const d = input instanceof Date ? new Date(input.getTime()) : input && typeof input === "object" && typeof input.valueOf === "function" ? new Date(input.valueOf()) : new Date(input);
@@ -11267,6 +11315,7 @@ var DERIVED_PASS = {
11267
11315
  REAL_WORK: "real-work",
11268
11316
  EXPECTED_PROGRESS: "expected-progress",
11269
11317
  REAL_COST: "real-cost",
11318
+ BASELINE_VARIANCE: "baseline-variance",
11270
11319
  CRITICAL_PATH: "critical-path"
11271
11320
  };
11272
11321
  function resolveDerivedPasses(action, autoSchedule, options) {
@@ -11284,6 +11333,9 @@ function resolveDerivedPasses(action, autoSchedule, options) {
11284
11333
  if (runsLoadRecomputes && resolveRunRealCost(action)) {
11285
11334
  passes.add(DERIVED_PASS.REAL_COST);
11286
11335
  }
11336
+ if (dispatchChangesSchedulingState(action)) {
11337
+ passes.add(DERIVED_PASS.BASELINE_VARIANCE);
11338
+ }
11287
11339
  const runsCriticalPath = runsLoadRecomputes && resolveRunCriticalPath(action) && !options.skipCriticalPath;
11288
11340
  if (runsCriticalPath) passes.add(DERIVED_PASS.CRITICAL_PATH);
11289
11341
  return passes;
@@ -11946,6 +11998,9 @@ async function runDerivedRecomputes(deps, passes, now) {
11946
11998
  if (passes.has(DERIVED_PASS.REAL_COST)) {
11947
11999
  emitRealCost(deps.adapter);
11948
12000
  }
12001
+ if (passes.has(DERIVED_PASS.BASELINE_VARIANCE)) {
12002
+ applyBaselineVariancePass(deps.adapter, deps.sector.hoursPerDay);
12003
+ }
11949
12004
  if (passes.has(DERIVED_PASS.CRITICAL_PATH)) {
11950
12005
  await applyCriticalPath(deps.adapter, deps.sector.hoursPerDay);
11951
12006
  }
@@ -12893,6 +12948,7 @@ var NEW_ACTIVITY_DEFAULTS = Object.freeze({
12893
12948
  tagIds: [],
12894
12949
  baselinePoints: [],
12895
12950
  baselineSnapshot: null,
12951
+ baselineVarianceDays: null,
12896
12952
  recursiveDurationHours: 0,
12897
12953
  isCritical: false,
12898
12954
  freeSlackHours: null,
@@ -16624,6 +16680,7 @@ async function dispatchBaselineApply(action, deps) {
16624
16680
  deps.reporter,
16625
16681
  deps.defaultBaseCalendarId ?? null
16626
16682
  );
16683
+ applyBaselineVariancePass(deps.adapter, deps.sector.hoursPerDay);
16627
16684
  if (activeBaselineSignature(deps) !== activeBaselineBefore) {
16628
16685
  recomputeBaselineWeightedFields(
16629
16686
  deps,
@@ -21711,6 +21768,7 @@ var ACTIVITY_SAVE_FIELD_POLICY = {
21711
21768
  isCritical: SAVE_FIELD_POLICY.IGNORED,
21712
21769
  freeSlackHours: SAVE_FIELD_POLICY.IGNORED,
21713
21770
  calendarDuration: SAVE_FIELD_POLICY.IGNORED,
21771
+ baselineVarianceDays: SAVE_FIELD_POLICY.IGNORED,
21714
21772
  expectedProgress: SAVE_FIELD_POLICY.IGNORED,
21715
21773
  expectedProgressBaseline: SAVE_FIELD_POLICY.IGNORED,
21716
21774
  status: SAVE_FIELD_POLICY.IGNORED,
@@ -22337,6 +22395,7 @@ function parseActivity(raw, context) {
22337
22395
  isMilestone
22338
22396
  ),
22339
22397
  baselineSnapshot: null,
22398
+ baselineVarianceDays: null,
22340
22399
  recursiveDurationHours: durationToHours(
22341
22400
  Number(raw.sumOfDurationRecursively ?? 0),
22342
22401
  context.hoursPerDay
@@ -23559,6 +23618,7 @@ async function runInitialPasses(deps) {
23559
23618
  applyExpectedProgressLive(state, now);
23560
23619
  applyStatusPass(state, sector.statusCriteria);
23561
23620
  }
23621
+ applyBaselineVariancePass(state, sector.hoursPerDay);
23562
23622
  return;
23563
23623
  }
23564
23624
  const result = await scheduler.schedule({});
@@ -23571,6 +23631,7 @@ async function runInitialPasses(deps) {
23571
23631
  applyExpectedProgressLive(state, now);
23572
23632
  applyStatusPass(state, sector.statusCriteria);
23573
23633
  }
23634
+ applyBaselineVariancePass(state, sector.hoursPerDay);
23574
23635
  }
23575
23636
  function recomputeSkippedLeafEnds(state) {
23576
23637
  state.forEachActivity((activity) => {