@outbuild-company/schedule-core 1.24.0 → 1.25.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
@@ -6287,7 +6287,9 @@ var P6_PERCENT_COMPLETE_TYPE = {
6287
6287
  var P6_ACTIVITY_TYPE = {
6288
6288
  TASK: "task",
6289
6289
  LEVEL_OF_EFFORT: "level_of_effort",
6290
- START_MILESTONE: "start_milestone"};
6290
+ START_MILESTONE: "start_milestone",
6291
+ RESOURCE_DEPENDENT: "resource_dependent"
6292
+ };
6291
6293
  var P6_EXECUTION_STATUS = {
6292
6294
  NOT_STARTED: "not_started",
6293
6295
  IN_PROGRESS: "in_progress",
@@ -18016,6 +18018,7 @@ var LOAD_DIAGNOSTIC_SAMPLE_LIMIT = 10;
18016
18018
  var LOAD_DIAGNOSTIC_CODE = {
18017
18019
  INVALID_BASELINE_POINT: "invalid_baseline_point",
18018
18020
  UNKNOWN_CONSTRAINT: "unknown_constraint",
18021
+ PROGRESS_OUT_OF_RANGE: "progress_out_of_range",
18019
18022
  ORPHAN_ACTIVITY: "orphan_activity",
18020
18023
  INVALID_LINK: "invalid_link",
18021
18024
  DUPLICATE_LINK: "duplicate_link"
@@ -18023,6 +18026,7 @@ var LOAD_DIAGNOSTIC_CODE = {
18023
18026
  var LOAD_DIAGNOSTIC_CODE_ORDER = [
18024
18027
  LOAD_DIAGNOSTIC_CODE.INVALID_BASELINE_POINT,
18025
18028
  LOAD_DIAGNOSTIC_CODE.UNKNOWN_CONSTRAINT,
18029
+ LOAD_DIAGNOSTIC_CODE.PROGRESS_OUT_OF_RANGE,
18026
18030
  LOAD_DIAGNOSTIC_CODE.ORPHAN_ACTIVITY,
18027
18031
  LOAD_DIAGNOSTIC_CODE.INVALID_LINK,
18028
18032
  LOAD_DIAGNOSTIC_CODE.DUPLICATE_LINK
@@ -24828,12 +24832,21 @@ function normalizePersistedActivityId(rawId) {
24828
24832
  }
24829
24833
  return rawId;
24830
24834
  }
24831
- function parseProgress(raw) {
24835
+ function parseProgress(raw, reporter, recordDiagnostic, activityId) {
24832
24836
  const progress = Number(raw);
24833
- if (!Number.isFinite(progress) || progress < NOT_STARTED_PROGRESS || progress > MAX_TOLERATED_PROGRESS) {
24837
+ if (!Number.isFinite(progress)) {
24834
24838
  throw new TypeError(`invalid activity progress ${String(raw)}`);
24835
24839
  }
24836
- return progress;
24840
+ const isBelowNotStarted = progress < NOT_STARTED_PROGRESS;
24841
+ const isAboveCompleted = progress > MAX_TOLERATED_PROGRESS;
24842
+ const isWithinRange = !isBelowNotStarted && !isAboveCompleted;
24843
+ if (isWithinRange) return progress;
24844
+ const clamped = isBelowNotStarted ? NOT_STARTED_PROGRESS : COMPLETED_PROGRESS;
24845
+ recordDiagnostic(LOAD_DIAGNOSTIC_CODE.PROGRESS_OUT_OF_RANGE, activityId);
24846
+ reporter.warn(
24847
+ `[parseFromBackend] activity "${activityId}" progress ${String(raw)} is out of range \u2014 clamping to ${clamped}`
24848
+ );
24849
+ return clamped;
24837
24850
  }
24838
24851
  function parseCriticality(raw, reporter) {
24839
24852
  if (typeof raw.is_critical === "boolean") return raw.is_critical;
@@ -24866,7 +24879,12 @@ function parseActivity(raw, context) {
24866
24879
  context.defaultCalendarId
24867
24880
  );
24868
24881
  const inheritedDefaultCalendar = raw.calendarId == null || !context.knownCalendarIds.has(String(raw.calendarId));
24869
- const progress = parseProgress(raw.progress);
24882
+ const progress = parseProgress(
24883
+ raw.progress,
24884
+ context.reporter,
24885
+ context.recordDiagnostic,
24886
+ String(raw.unique_id)
24887
+ );
24870
24888
  const { constraintType, constraintDate } = resolveConstraint(
24871
24889
  raw,
24872
24890
  context.reporter,
@@ -30095,6 +30113,39 @@ function blockedActivities(code, message, activityIds, missingInputs = []) {
30095
30113
  };
30096
30114
  }
30097
30115
 
30116
+ // src/p6/rolled-expected-finish.ts
30117
+ var PINNABLE_ACTIVITY_TYPES = /* @__PURE__ */ new Set([
30118
+ P6_ACTIVITY_TYPE.TASK,
30119
+ P6_ACTIVITY_TYPE.RESOURCE_DEPENDENT
30120
+ ]);
30121
+ var NO_ROLLED_EXPECTED_FINISHES = /* @__PURE__ */ new Map();
30122
+ function planRolledExpectedFinishes(input) {
30123
+ const adoptsShownFinishes = input.settings.useExpectedFinishDates && rollsDataDateForward(input.previousSettings, input.settings);
30124
+ if (!adoptsShownFinishes) return NO_ROLLED_EXPECTED_FINISHES;
30125
+ const pinned = /* @__PURE__ */ new Map();
30126
+ for (const [activityId, state] of input.activities) {
30127
+ const shownFinish = state.remainingEarlyFinish;
30128
+ if (shownFinish === null) continue;
30129
+ if (!needsExpectedFinishPin(state)) continue;
30130
+ pinned.set(activityId, new Date(shownFinish));
30131
+ }
30132
+ return pinned;
30133
+ }
30134
+ function rollsDataDateForward(previous, next) {
30135
+ const previousDataDate = previous.dataDate;
30136
+ const nextDataDate = next.dataDate;
30137
+ if (previousDataDate === null || nextDataDate === null) return false;
30138
+ return nextDataDate.getTime() > previousDataDate.getTime();
30139
+ }
30140
+ function needsExpectedFinishPin(state) {
30141
+ return state.executionStatus === P6_EXECUTION_STATUS.IN_PROGRESS && state.expectedFinish === null && hasPinnableActivityType(state);
30142
+ }
30143
+ function hasPinnableActivityType(state) {
30144
+ const { activityType } = state;
30145
+ if (activityType === void 0) return true;
30146
+ return PINNABLE_ACTIVITY_TYPES.has(activityType);
30147
+ }
30148
+
30098
30149
  // src/p6/commands.ts
30099
30150
  function dataDateScheduleReadiness(input) {
30100
30151
  const preflight = getP6SchedulePreflight({
@@ -30208,8 +30259,17 @@ function prepareDataDateSchedule(input) {
30208
30259
  preflight.settings,
30209
30260
  beforeProjectState
30210
30261
  );
30262
+ const rolledExpectedFinishes = planRolledExpectedFinishes({
30263
+ previousSettings: preflight.previousSettings,
30264
+ settings: preflight.settings,
30265
+ activities: preflight.activities
30266
+ });
30211
30267
  const calculated = calculateP6Schedule({
30212
- adapter: calculationState(input.state, preflight.activities),
30268
+ adapter: calculationState(
30269
+ input.state,
30270
+ preflight.activities,
30271
+ rolledExpectedFinishes
30272
+ ),
30213
30273
  settings: preflight.settings,
30214
30274
  project: {
30215
30275
  projectId: String(input.sector.projectId),
@@ -30255,11 +30315,19 @@ function requireProjectState(projectState) {
30255
30315
  "P6 capability is not enabled for this Schedule"
30256
30316
  );
30257
30317
  }
30258
- function calculationState(current, schedulableActivities) {
30318
+ function calculationState(current, schedulableActivities, rolledExpectedFinishes) {
30259
30319
  const state = current.fork();
30260
30320
  state.forEachActivity((activity) => {
30261
- if (schedulableActivities.has(activity.id)) return;
30262
- state.setActivityField(activity.id, "p6", void 0);
30321
+ if (!schedulableActivities.has(activity.id)) {
30322
+ state.setActivityField(activity.id, "p6", void 0);
30323
+ return;
30324
+ }
30325
+ const rolledExpectedFinish = rolledExpectedFinishes.get(activity.id);
30326
+ if (rolledExpectedFinish === void 0 || activity.p6 === void 0) return;
30327
+ state.setActivityField(activity.id, "p6", {
30328
+ ...activity.p6,
30329
+ expectedFinish: rolledExpectedFinish
30330
+ });
30263
30331
  });
30264
30332
  return state;
30265
30333
  }