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