@outbuild-company/schedule-core 1.23.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/cdn/schedule-core.global.js +1 -1
- package/dist/cdn/schedule-core.global.js.map +1 -1
- package/dist/index.cjs +168 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +168 -25
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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",
|
|
@@ -11977,14 +11979,65 @@ function createOutbuildP6ActivityDraft(activity) {
|
|
|
11977
11979
|
if (state === void 0) return void 0;
|
|
11978
11980
|
return {
|
|
11979
11981
|
...state,
|
|
11980
|
-
|
|
11982
|
+
...outbuildProgressExecution(activity, activity.durationHours)
|
|
11981
11983
|
};
|
|
11982
11984
|
}
|
|
11983
|
-
|
|
11985
|
+
var COMPLETED_PHYSICAL_PERCENT = 100;
|
|
11986
|
+
var NOT_STARTED_PHYSICAL_PERCENT = 0;
|
|
11987
|
+
function outbuildProgressExecution(activity, originalDurationHours) {
|
|
11984
11988
|
if (activity.progress === NOT_STARTED_PROGRESS) {
|
|
11985
|
-
return
|
|
11989
|
+
return {
|
|
11990
|
+
executionStatus: P6_EXECUTION_STATUS.NOT_STARTED,
|
|
11991
|
+
actualStart: null,
|
|
11992
|
+
actualFinish: null,
|
|
11993
|
+
remainingDurationHours: originalDurationHours,
|
|
11994
|
+
physicalPercentComplete: NOT_STARTED_PHYSICAL_PERCENT,
|
|
11995
|
+
actualDurationHours: 0,
|
|
11996
|
+
atCompletionDurationHours: originalDurationHours,
|
|
11997
|
+
durationPercentComplete: 0
|
|
11998
|
+
};
|
|
11986
11999
|
}
|
|
11987
|
-
|
|
12000
|
+
const actualStart = cloneValidDate(activity.startDate, "actualStart");
|
|
12001
|
+
if (isCompletedProgress(activity.progress)) {
|
|
12002
|
+
const hasMeasurableDuration = originalDurationHours > 0;
|
|
12003
|
+
return {
|
|
12004
|
+
executionStatus: P6_EXECUTION_STATUS.COMPLETED,
|
|
12005
|
+
actualStart,
|
|
12006
|
+
actualFinish: cloneValidDate(activity.endDate, "actualFinish"),
|
|
12007
|
+
remainingDurationHours: 0,
|
|
12008
|
+
physicalPercentComplete: COMPLETED_PHYSICAL_PERCENT,
|
|
12009
|
+
actualDurationHours: originalDurationHours,
|
|
12010
|
+
atCompletionDurationHours: originalDurationHours,
|
|
12011
|
+
durationPercentComplete: hasMeasurableDuration ? COMPLETED_PHYSICAL_PERCENT : NOT_STARTED_PHYSICAL_PERCENT
|
|
12012
|
+
};
|
|
12013
|
+
}
|
|
12014
|
+
return {
|
|
12015
|
+
executionStatus: P6_EXECUTION_STATUS.IN_PROGRESS,
|
|
12016
|
+
actualStart,
|
|
12017
|
+
actualFinish: null,
|
|
12018
|
+
remainingDurationHours: originalDurationHours,
|
|
12019
|
+
physicalPercentComplete: activity.progress,
|
|
12020
|
+
actualDurationHours: 0,
|
|
12021
|
+
atCompletionDurationHours: originalDurationHours,
|
|
12022
|
+
durationPercentComplete: 0
|
|
12023
|
+
};
|
|
12024
|
+
}
|
|
12025
|
+
function awaitsOutbuildExecution(draft) {
|
|
12026
|
+
return draft.executionStatus === P6_EXECUTION_STATUS.NOT_STARTED && draft.actualStart === null;
|
|
12027
|
+
}
|
|
12028
|
+
function reconcileOutbuildProgress(activity, draft) {
|
|
12029
|
+
const isProgressed = activity.progress !== NOT_STARTED_PROGRESS;
|
|
12030
|
+
if (!isProgressed || !awaitsOutbuildExecution(draft)) return draft;
|
|
12031
|
+
const inferred = outbuildProgressExecution(
|
|
12032
|
+
activity,
|
|
12033
|
+
draft.originalDurationHours
|
|
12034
|
+
);
|
|
12035
|
+
const keepsRecordedRemaining = inferred.executionStatus === P6_EXECUTION_STATUS.IN_PROGRESS && draft.remainingDurationHours !== null;
|
|
12036
|
+
return {
|
|
12037
|
+
...draft,
|
|
12038
|
+
...inferred,
|
|
12039
|
+
...keepsRecordedRemaining ? { remainingDurationHours: draft.remainingDurationHours } : {}
|
|
12040
|
+
};
|
|
11988
12041
|
}
|
|
11989
12042
|
|
|
11990
12043
|
// src/p6/inactive-drafts.ts
|
|
@@ -12037,17 +12090,41 @@ function ordinaryInputChanges(before, activity) {
|
|
|
12037
12090
|
...before.startDate.getTime() !== activity.startDate.getTime() ? { plannedStart: new Date(activity.startDate) } : {},
|
|
12038
12091
|
...before.endDate.getTime() !== activity.endDate.getTime() ? { plannedFinish: new Date(activity.endDate) } : {},
|
|
12039
12092
|
...durationChanged ? { originalDurationHours: activity.durationHours } : {},
|
|
12040
|
-
...durationChanged || before.progress !== activity.progress ?
|
|
12093
|
+
...durationChanged || before.progress !== activity.progress ? executionInputChanges(before, activity, durationChanged) : {}
|
|
12041
12094
|
};
|
|
12042
12095
|
}
|
|
12043
|
-
function
|
|
12096
|
+
function executionInputChanges(before, activity, durationChanged) {
|
|
12044
12097
|
const current = activity.p6;
|
|
12045
|
-
|
|
12046
|
-
|
|
12047
|
-
const
|
|
12098
|
+
const hasExplicitRemainingCorrection = current.remainingDurationHours !== before.p6.remainingDurationHours;
|
|
12099
|
+
if (hasExplicitRemainingCorrection) return {};
|
|
12100
|
+
const progressChanged = before.progress !== activity.progress;
|
|
12101
|
+
const resetsToNotStarted = progressChanged && activity.progress === NOT_STARTED_PROGRESS;
|
|
12102
|
+
if (awaitsOutbuildExecution(current) || resetsToNotStarted) {
|
|
12103
|
+
const originalDurationHours = durationChanged ? activity.durationHours : current.originalDurationHours;
|
|
12104
|
+
return outbuildProgressExecution(activity, originalDurationHours);
|
|
12105
|
+
}
|
|
12106
|
+
const isStarted = current.actualStart !== null;
|
|
12107
|
+
if (!isStarted || !progressChanged) return {};
|
|
12108
|
+
return startedProgressChanges(current, activity);
|
|
12109
|
+
}
|
|
12110
|
+
function startedProgressChanges(current, activity) {
|
|
12111
|
+
const mirrorsPhysicalPercent = current.percentCompleteType === P6_PERCENT_COMPLETE_TYPE.PHYSICAL;
|
|
12112
|
+
if (!isCompletedProgress(activity.progress)) {
|
|
12113
|
+
return {
|
|
12114
|
+
...current.actualFinish === null ? {} : {
|
|
12115
|
+
executionStatus: P6_EXECUTION_STATUS.IN_PROGRESS,
|
|
12116
|
+
actualFinish: null
|
|
12117
|
+
},
|
|
12118
|
+
...mirrorsPhysicalPercent ? { physicalPercentComplete: activity.progress } : {}
|
|
12119
|
+
};
|
|
12120
|
+
}
|
|
12121
|
+
const finishesAfterActualStart = current.actualStart !== null && activity.endDate.getTime() >= current.actualStart.getTime();
|
|
12122
|
+
if (current.actualFinish !== null || !finishesAfterActualStart) return {};
|
|
12048
12123
|
return {
|
|
12049
|
-
|
|
12050
|
-
|
|
12124
|
+
executionStatus: P6_EXECUTION_STATUS.COMPLETED,
|
|
12125
|
+
actualFinish: new Date(activity.endDate),
|
|
12126
|
+
remainingDurationHours: 0,
|
|
12127
|
+
physicalPercentComplete: COMPLETED_PROGRESS
|
|
12051
12128
|
};
|
|
12052
12129
|
}
|
|
12053
12130
|
|
|
@@ -17939,6 +18016,7 @@ var LOAD_DIAGNOSTIC_SAMPLE_LIMIT = 10;
|
|
|
17939
18016
|
var LOAD_DIAGNOSTIC_CODE = {
|
|
17940
18017
|
INVALID_BASELINE_POINT: "invalid_baseline_point",
|
|
17941
18018
|
UNKNOWN_CONSTRAINT: "unknown_constraint",
|
|
18019
|
+
PROGRESS_OUT_OF_RANGE: "progress_out_of_range",
|
|
17942
18020
|
ORPHAN_ACTIVITY: "orphan_activity",
|
|
17943
18021
|
INVALID_LINK: "invalid_link",
|
|
17944
18022
|
DUPLICATE_LINK: "duplicate_link"
|
|
@@ -17946,6 +18024,7 @@ var LOAD_DIAGNOSTIC_CODE = {
|
|
|
17946
18024
|
var LOAD_DIAGNOSTIC_CODE_ORDER = [
|
|
17947
18025
|
LOAD_DIAGNOSTIC_CODE.INVALID_BASELINE_POINT,
|
|
17948
18026
|
LOAD_DIAGNOSTIC_CODE.UNKNOWN_CONSTRAINT,
|
|
18027
|
+
LOAD_DIAGNOSTIC_CODE.PROGRESS_OUT_OF_RANGE,
|
|
17949
18028
|
LOAD_DIAGNOSTIC_CODE.ORPHAN_ACTIVITY,
|
|
17950
18029
|
LOAD_DIAGNOSTIC_CODE.INVALID_LINK,
|
|
17951
18030
|
LOAD_DIAGNOSTIC_CODE.DUPLICATE_LINK
|
|
@@ -24751,12 +24830,21 @@ function normalizePersistedActivityId(rawId) {
|
|
|
24751
24830
|
}
|
|
24752
24831
|
return rawId;
|
|
24753
24832
|
}
|
|
24754
|
-
function parseProgress(raw) {
|
|
24833
|
+
function parseProgress(raw, reporter, recordDiagnostic, activityId) {
|
|
24755
24834
|
const progress = Number(raw);
|
|
24756
|
-
if (!Number.isFinite(progress)
|
|
24835
|
+
if (!Number.isFinite(progress)) {
|
|
24757
24836
|
throw new TypeError(`invalid activity progress ${String(raw)}`);
|
|
24758
24837
|
}
|
|
24759
|
-
|
|
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;
|
|
24760
24848
|
}
|
|
24761
24849
|
function parseCriticality(raw, reporter) {
|
|
24762
24850
|
if (typeof raw.is_critical === "boolean") return raw.is_critical;
|
|
@@ -24789,7 +24877,12 @@ function parseActivity(raw, context) {
|
|
|
24789
24877
|
context.defaultCalendarId
|
|
24790
24878
|
);
|
|
24791
24879
|
const inheritedDefaultCalendar = raw.calendarId == null || !context.knownCalendarIds.has(String(raw.calendarId));
|
|
24792
|
-
const progress = parseProgress(
|
|
24880
|
+
const progress = parseProgress(
|
|
24881
|
+
raw.progress,
|
|
24882
|
+
context.reporter,
|
|
24883
|
+
context.recordDiagnostic,
|
|
24884
|
+
String(raw.unique_id)
|
|
24885
|
+
);
|
|
24793
24886
|
const { constraintType, constraintDate } = resolveConstraint(
|
|
24794
24887
|
raw,
|
|
24795
24888
|
context.reporter,
|
|
@@ -26243,8 +26336,8 @@ var P6ActivityStatusError = class extends Error {
|
|
|
26243
26336
|
}
|
|
26244
26337
|
code;
|
|
26245
26338
|
};
|
|
26246
|
-
var
|
|
26247
|
-
var
|
|
26339
|
+
var COMPLETED_PHYSICAL_PERCENT2 = 100;
|
|
26340
|
+
var NOT_STARTED_PHYSICAL_PERCENT2 = 0;
|
|
26248
26341
|
function validateP6ActivityStatus(activity) {
|
|
26249
26342
|
validateRemainingDuration(activity.remainingDurationHours);
|
|
26250
26343
|
validateDates(activity);
|
|
@@ -26270,11 +26363,11 @@ function normalizeP6ActualDatePatch(current, patch) {
|
|
|
26270
26363
|
executionStatus,
|
|
26271
26364
|
...actualFinish !== null ? {
|
|
26272
26365
|
remainingDurationHours: 0,
|
|
26273
|
-
physicalPercentComplete:
|
|
26366
|
+
physicalPercentComplete: COMPLETED_PHYSICAL_PERCENT2
|
|
26274
26367
|
} : {},
|
|
26275
26368
|
...unStarting ? {
|
|
26276
26369
|
remainingDurationHours: current.originalDurationHours,
|
|
26277
|
-
physicalPercentComplete:
|
|
26370
|
+
physicalPercentComplete: NOT_STARTED_PHYSICAL_PERCENT2
|
|
26278
26371
|
} : {}
|
|
26279
26372
|
};
|
|
26280
26373
|
validateP6ActivityDraftStatus({ ...current, ...normalized2 });
|
|
@@ -30018,6 +30111,39 @@ function blockedActivities(code, message, activityIds, missingInputs = []) {
|
|
|
30018
30111
|
};
|
|
30019
30112
|
}
|
|
30020
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
|
+
|
|
30021
30147
|
// src/p6/commands.ts
|
|
30022
30148
|
function dataDateScheduleReadiness(input) {
|
|
30023
30149
|
const preflight = getP6SchedulePreflight({
|
|
@@ -30131,8 +30257,17 @@ function prepareDataDateSchedule(input) {
|
|
|
30131
30257
|
preflight.settings,
|
|
30132
30258
|
beforeProjectState
|
|
30133
30259
|
);
|
|
30260
|
+
const rolledExpectedFinishes = planRolledExpectedFinishes({
|
|
30261
|
+
previousSettings: preflight.previousSettings,
|
|
30262
|
+
settings: preflight.settings,
|
|
30263
|
+
activities: preflight.activities
|
|
30264
|
+
});
|
|
30134
30265
|
const calculated = calculateP6Schedule({
|
|
30135
|
-
adapter: calculationState(
|
|
30266
|
+
adapter: calculationState(
|
|
30267
|
+
input.state,
|
|
30268
|
+
preflight.activities,
|
|
30269
|
+
rolledExpectedFinishes
|
|
30270
|
+
),
|
|
30136
30271
|
settings: preflight.settings,
|
|
30137
30272
|
project: {
|
|
30138
30273
|
projectId: String(input.sector.projectId),
|
|
@@ -30178,11 +30313,19 @@ function requireProjectState(projectState) {
|
|
|
30178
30313
|
"P6 capability is not enabled for this Schedule"
|
|
30179
30314
|
);
|
|
30180
30315
|
}
|
|
30181
|
-
function calculationState(current, schedulableActivities) {
|
|
30316
|
+
function calculationState(current, schedulableActivities, rolledExpectedFinishes) {
|
|
30182
30317
|
const state = current.fork();
|
|
30183
30318
|
state.forEachActivity((activity) => {
|
|
30184
|
-
if (schedulableActivities.has(activity.id))
|
|
30185
|
-
|
|
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
|
+
});
|
|
30186
30329
|
});
|
|
30187
30330
|
return state;
|
|
30188
30331
|
}
|
|
@@ -30307,7 +30450,7 @@ function initializeDataDate(input, activities) {
|
|
|
30307
30450
|
function attachImportedDataDate(activities, imported, settings) {
|
|
30308
30451
|
for (const activity of activities) {
|
|
30309
30452
|
const importedP6 = Object.hasOwn(imported, activity.id) ? imported[activity.id] : void 0;
|
|
30310
|
-
const p6 = importedP6
|
|
30453
|
+
const p6 = importedP6 === void 0 ? createOutbuildP6ActivityDraft(activity) : reconcileOutbuildProgress(activity, importedP6);
|
|
30311
30454
|
if (p6 === void 0) continue;
|
|
30312
30455
|
activity.p6 = p6;
|
|
30313
30456
|
if (!hasActiveDataDate(settings)) continue;
|