@outbuild-company/schedule-core 1.35.1 → 1.35.3
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/build-fingerprint.json +2 -2
- package/dist/cdn/schedule-core.global.js +1 -1
- package/dist/cdn/schedule-core.global.js.map +1 -1
- package/dist/index.cjs +361 -329
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +89 -87
- package/dist/index.d.ts +89 -87
- package/dist/index.js +361 -329
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -13000,11 +13000,6 @@ function rejectedGesture(editability) {
|
|
|
13000
13000
|
...editability.alertKey ? { alertKey: editability.alertKey } : {}
|
|
13001
13001
|
};
|
|
13002
13002
|
}
|
|
13003
|
-
var STATUS_ONLY_CHANGES = {
|
|
13004
|
-
patch: {},
|
|
13005
|
-
needsAutoSchedule: false,
|
|
13006
|
-
postProcessors: []
|
|
13007
|
-
};
|
|
13008
13003
|
function resolveDataDateProgressButton(activity, progress, progressChanges, deps, confirmations) {
|
|
13009
13004
|
const governsProgress = deps.dataDateCapability !== null && hasActiveDataDate(deps.dataDateSettings, deps.dataDateEnabled);
|
|
13010
13005
|
if (!governsProgress) return null;
|
|
@@ -13018,19 +13013,19 @@ function resolveDataDateProgressButton(activity, progress, progressChanges, deps
|
|
|
13018
13013
|
if (activity.p6 === void 0) return null;
|
|
13019
13014
|
return resolveDataDateFieldChanges(
|
|
13020
13015
|
activity,
|
|
13021
|
-
progressChanges
|
|
13016
|
+
progressChanges,
|
|
13022
13017
|
deps,
|
|
13023
13018
|
COLUMN.PROGRESS,
|
|
13024
13019
|
confirmations,
|
|
13025
13020
|
{
|
|
13026
13021
|
progress,
|
|
13027
13022
|
explicitCompletion: true,
|
|
13028
|
-
writesProgress:
|
|
13023
|
+
writesProgress: activity.p6.percentCompleteType !== P6_PERCENT_COMPLETE_TYPE.UNITS
|
|
13029
13024
|
}
|
|
13030
13025
|
);
|
|
13031
13026
|
}
|
|
13032
13027
|
function resolveDataDateFieldChanges(activity, changes, deps, column, confirmations, progressRouting, editedStart = null) {
|
|
13033
|
-
const
|
|
13028
|
+
const routed = routeGenericColumnEdit(
|
|
13034
13029
|
activity,
|
|
13035
13030
|
routeConstraintTypeEdit(activity, changes, column),
|
|
13036
13031
|
deps,
|
|
@@ -13039,9 +13034,8 @@ function resolveDataDateFieldChanges(activity, changes, deps, column, confirmati
|
|
|
13039
13034
|
progressRouting,
|
|
13040
13035
|
editedStart
|
|
13041
13036
|
);
|
|
13042
|
-
if (
|
|
13043
|
-
if ("accepted" in
|
|
13044
|
-
const routed = limitTransitionActuals(activity, generic, deps, column);
|
|
13037
|
+
if (routed === null) return rejected(REJECTION_REASON.INVALID_VALUE);
|
|
13038
|
+
if ("accepted" in routed) return routed;
|
|
13045
13039
|
if (routed.dataDatePatch === void 0) return accepted(routed);
|
|
13046
13040
|
if (activity.p6 === void 0 || deps.dataDateCapability === null) {
|
|
13047
13041
|
return rejected(REJECTION_REASON.INVALID_VALUE);
|
|
@@ -13101,32 +13095,6 @@ function withMirroredProgress(activity, changes, next, deps, column) {
|
|
|
13101
13095
|
}
|
|
13102
13096
|
return { ...changes, patch: { ...changes.patch, progress: percent } };
|
|
13103
13097
|
}
|
|
13104
|
-
var EXECUTION_TRANSITION_COLUMNS = /* @__PURE__ */ new Set([
|
|
13105
|
-
COLUMN.PROGRESS,
|
|
13106
|
-
COLUMN.EXECUTION_STATUS,
|
|
13107
|
-
COLUMN.PHYSICAL_PERCENT_COMPLETE
|
|
13108
|
-
]);
|
|
13109
|
-
function limitTransitionActuals(activity, changes, deps, column) {
|
|
13110
|
-
const dataDate = deps.dataDateSettings?.dataDate ?? null;
|
|
13111
|
-
if (!EXECUTION_TRANSITION_COLUMNS.has(column) || dataDate === null || changes.dataDatePatch === void 0 || !hasActiveDataDate(deps.dataDateSettings, deps.dataDateEnabled)) {
|
|
13112
|
-
return changes;
|
|
13113
|
-
}
|
|
13114
|
-
const calendar = deps.ctx.calendars.getCalendar(activity.calendarId);
|
|
13115
|
-
const limit = calendar === null ? { start: dataDate, finish: dataDate } : completionActualsLimit(dataDate, calendar);
|
|
13116
|
-
const recordedStart = activity.p6?.actualStart ?? null;
|
|
13117
|
-
const floor = recordedStart !== null && recordedStart <= dataDate ? recordedStart : null;
|
|
13118
|
-
const alternative = changes.confirmationAlternative;
|
|
13119
|
-
return {
|
|
13120
|
-
...changes,
|
|
13121
|
-
dataDatePatch: capActualDates(changes.dataDatePatch, floor, limit),
|
|
13122
|
-
...alternative === void 0 ? {} : {
|
|
13123
|
-
confirmationAlternative: {
|
|
13124
|
-
...alternative,
|
|
13125
|
-
effects: capActualDates(alternative.effects, floor, limit)
|
|
13126
|
-
}
|
|
13127
|
-
}
|
|
13128
|
-
};
|
|
13129
|
-
}
|
|
13130
13098
|
function accepted(changes) {
|
|
13131
13099
|
return { accepted: true, changes };
|
|
13132
13100
|
}
|
|
@@ -16115,6 +16083,315 @@ async function dispatchHistoryRevert(action, options, deps) {
|
|
|
16115
16083
|
};
|
|
16116
16084
|
}
|
|
16117
16085
|
|
|
16086
|
+
// src/p6/status.ts
|
|
16087
|
+
var INVALID_STATUS = "Invalid P6 activity status";
|
|
16088
|
+
var P6ActivityStatusError = class extends Error {
|
|
16089
|
+
constructor(code, reason) {
|
|
16090
|
+
super(`${INVALID_STATUS}: ${reason}`);
|
|
16091
|
+
this.code = code;
|
|
16092
|
+
this.name = "P6ActivityStatusError";
|
|
16093
|
+
}
|
|
16094
|
+
code;
|
|
16095
|
+
};
|
|
16096
|
+
var COMPLETED_PHYSICAL_PERCENT2 = 100;
|
|
16097
|
+
var NOT_STARTED_PHYSICAL_PERCENT2 = 0;
|
|
16098
|
+
function validateP6ActivityStatus(activity) {
|
|
16099
|
+
validateRemainingDuration(activity.remainingDurationHours);
|
|
16100
|
+
validateDates(activity);
|
|
16101
|
+
validateExecutionStatus(activity);
|
|
16102
|
+
validateDateOrder(activity);
|
|
16103
|
+
}
|
|
16104
|
+
function validateP6ActivityDraftStatus(activity) {
|
|
16105
|
+
validateDraftRemainingDuration(activity.remainingDurationHours);
|
|
16106
|
+
validateDates(activity);
|
|
16107
|
+
validateDraftExecutionStatus(activity);
|
|
16108
|
+
validateDateOrder(activity);
|
|
16109
|
+
}
|
|
16110
|
+
function normalizeP6ActualDatePatch(current, patch) {
|
|
16111
|
+
if (patch.actualStart === void 0 && patch.actualFinish === void 0) {
|
|
16112
|
+
return patch;
|
|
16113
|
+
}
|
|
16114
|
+
const actualStart = patch.actualStart !== void 0 ? patch.actualStart : current.actualStart;
|
|
16115
|
+
const actualFinish = patch.actualFinish !== void 0 ? patch.actualFinish : current.actualFinish;
|
|
16116
|
+
const executionStatus = actualFinish !== null ? "completed" : actualStart !== null ? "in_progress" : "not_started";
|
|
16117
|
+
const unStarting = actualStart === null && actualFinish === null && current.actualStart !== null;
|
|
16118
|
+
const normalized2 = {
|
|
16119
|
+
...patch,
|
|
16120
|
+
executionStatus,
|
|
16121
|
+
...actualFinish !== null ? {
|
|
16122
|
+
remainingDurationHours: 0,
|
|
16123
|
+
physicalPercentComplete: COMPLETED_PHYSICAL_PERCENT2
|
|
16124
|
+
} : {},
|
|
16125
|
+
...unStarting ? {
|
|
16126
|
+
remainingDurationHours: current.originalDurationHours,
|
|
16127
|
+
physicalPercentComplete: NOT_STARTED_PHYSICAL_PERCENT2
|
|
16128
|
+
} : {}
|
|
16129
|
+
};
|
|
16130
|
+
validateP6ActivityDraftStatus({ ...current, ...normalized2 });
|
|
16131
|
+
return normalized2;
|
|
16132
|
+
}
|
|
16133
|
+
function validateRemainingDuration(remainingDurationHours) {
|
|
16134
|
+
if (!Number.isFinite(remainingDurationHours) || remainingDurationHours < 0) {
|
|
16135
|
+
invalid2("Remaining Duration must be finite and non-negative");
|
|
16136
|
+
}
|
|
16137
|
+
}
|
|
16138
|
+
function validateDraftRemainingDuration(remainingDurationHours) {
|
|
16139
|
+
if (remainingDurationHours === null) return;
|
|
16140
|
+
validateRemainingDuration(remainingDurationHours);
|
|
16141
|
+
}
|
|
16142
|
+
function validateDates(activity) {
|
|
16143
|
+
const dates = [
|
|
16144
|
+
activity.actualStart,
|
|
16145
|
+
activity.actualFinish,
|
|
16146
|
+
activity.suspendDate,
|
|
16147
|
+
activity.resumeDate
|
|
16148
|
+
];
|
|
16149
|
+
if (dates.some((date2) => date2 !== null && Number.isNaN(date2.getTime()))) {
|
|
16150
|
+
invalid2("actual, suspend and resume dates must be valid");
|
|
16151
|
+
}
|
|
16152
|
+
}
|
|
16153
|
+
function validateExecutionStatus(activity) {
|
|
16154
|
+
const hasActualStart = activity.actualStart !== null;
|
|
16155
|
+
const hasActualFinish = activity.actualFinish !== null;
|
|
16156
|
+
if (activity.executionStatus === "not_started") {
|
|
16157
|
+
if (hasActualStart || hasActualFinish) {
|
|
16158
|
+
invalid2("not_started cannot have actual dates");
|
|
16159
|
+
}
|
|
16160
|
+
return;
|
|
16161
|
+
}
|
|
16162
|
+
if (activity.executionStatus === "in_progress") {
|
|
16163
|
+
if (!hasActualStart || hasActualFinish) {
|
|
16164
|
+
invalid2("in_progress requires Actual Start and no Actual Finish");
|
|
16165
|
+
}
|
|
16166
|
+
return;
|
|
16167
|
+
}
|
|
16168
|
+
if (!hasActualStart || !hasActualFinish || activity.remainingDurationHours !== 0) {
|
|
16169
|
+
invalid2(
|
|
16170
|
+
"completed requires Actual Start, Actual Finish and zero Remaining Duration"
|
|
16171
|
+
);
|
|
16172
|
+
}
|
|
16173
|
+
}
|
|
16174
|
+
function validateDraftExecutionStatus(activity) {
|
|
16175
|
+
const hasActualStart = activity.actualStart !== null;
|
|
16176
|
+
const hasActualFinish = activity.actualFinish !== null;
|
|
16177
|
+
if (hasActualFinish && !hasActualStart) {
|
|
16178
|
+
invalid2("Actual Finish requires Actual Start");
|
|
16179
|
+
}
|
|
16180
|
+
if (activity.executionStatus === "not_started" && hasActualStart) {
|
|
16181
|
+
invalid2("not_started cannot have actual dates");
|
|
16182
|
+
}
|
|
16183
|
+
if (activity.executionStatus === "in_progress" && hasActualFinish) {
|
|
16184
|
+
invalid2("in_progress cannot have Actual Finish");
|
|
16185
|
+
}
|
|
16186
|
+
if (activity.executionStatus === "completed" && activity.remainingDurationHours !== null && activity.remainingDurationHours !== 0) {
|
|
16187
|
+
invalid2("completed requires zero Remaining Duration");
|
|
16188
|
+
}
|
|
16189
|
+
}
|
|
16190
|
+
function validateDateOrder(activity) {
|
|
16191
|
+
const { actualStart, actualFinish, suspendDate, resumeDate } = activity;
|
|
16192
|
+
if (actualStart !== null && actualFinish !== null && actualStart.getTime() > actualFinish.getTime()) {
|
|
16193
|
+
throw new P6ActivityStatusError(
|
|
16194
|
+
"ACTUAL_FINISH_BEFORE_START",
|
|
16195
|
+
"Actual Start must not be after Actual Finish"
|
|
16196
|
+
);
|
|
16197
|
+
}
|
|
16198
|
+
if (suspendDate !== null) {
|
|
16199
|
+
if (actualStart === null) invalid2("Suspend requires Actual Start");
|
|
16200
|
+
if (actualStart.getTime() > suspendDate.getTime()) {
|
|
16201
|
+
invalid2("Suspend must not be before Actual Start");
|
|
16202
|
+
}
|
|
16203
|
+
if (actualFinish !== null && suspendDate.getTime() > actualFinish.getTime()) {
|
|
16204
|
+
invalid2("Suspend must not be after Actual Finish");
|
|
16205
|
+
}
|
|
16206
|
+
}
|
|
16207
|
+
if (resumeDate === null) return;
|
|
16208
|
+
if (suspendDate === null) invalid2("Resume requires Suspend");
|
|
16209
|
+
if (suspendDate.getTime() > resumeDate.getTime()) {
|
|
16210
|
+
invalid2("Suspend must not be after Resume");
|
|
16211
|
+
}
|
|
16212
|
+
if (actualFinish !== null && resumeDate.getTime() > actualFinish.getTime()) {
|
|
16213
|
+
invalid2("Resume must not be after Actual Finish");
|
|
16214
|
+
}
|
|
16215
|
+
}
|
|
16216
|
+
function invalid2(reason) {
|
|
16217
|
+
throw new Error(`${INVALID_STATUS}: ${reason}`);
|
|
16218
|
+
}
|
|
16219
|
+
|
|
16220
|
+
// src/p6/lookahead-progress-transition.ts
|
|
16221
|
+
var LookaheadActualTransitionError = class extends Error {
|
|
16222
|
+
constructor(code) {
|
|
16223
|
+
super(code);
|
|
16224
|
+
this.code = code;
|
|
16225
|
+
this.name = "LookaheadActualTransitionError";
|
|
16226
|
+
}
|
|
16227
|
+
code;
|
|
16228
|
+
};
|
|
16229
|
+
var ACTUAL_DAY_PATTERN = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
16230
|
+
function resolveLookaheadActualDateSelection(input) {
|
|
16231
|
+
if (!validDate(input.timeSource)) invalid3("INVALID_ACTUAL_TIME_SOURCE");
|
|
16232
|
+
const parts = actualDayParts(input.selectedDay);
|
|
16233
|
+
const [year, month, day] = parts;
|
|
16234
|
+
const result = new Date(input.timeSource);
|
|
16235
|
+
result.setUTCFullYear(year, month - 1, day);
|
|
16236
|
+
if (!sameUtcDay2(result, parts)) invalid3("INVALID_ACTUAL_DAY");
|
|
16237
|
+
return result;
|
|
16238
|
+
}
|
|
16239
|
+
function actualDayParts(value) {
|
|
16240
|
+
const match = ACTUAL_DAY_PATTERN.exec(value);
|
|
16241
|
+
if (!match) invalid3("INVALID_ACTUAL_DAY");
|
|
16242
|
+
return [Number(match[1]), Number(match[2]), Number(match[3])];
|
|
16243
|
+
}
|
|
16244
|
+
function planLookaheadProgressActuals(input) {
|
|
16245
|
+
validateInput(input);
|
|
16246
|
+
if (input.dataDate === null) {
|
|
16247
|
+
return { start: null, finish: null, uncomplete: null };
|
|
16248
|
+
}
|
|
16249
|
+
const start = input.activity.executionStatus === P6_EXECUTION_STATUS.NOT_STARTED && input.nextProgress > NOT_STARTED_PROGRESS ? { required: true, suggestedAt: new Date(input.dataDate) } : null;
|
|
16250
|
+
const finish = input.activity.executionStatus !== P6_EXECUTION_STATUS.COMPLETED && input.nextProgress === COMPLETED_PROGRESS ? {
|
|
16251
|
+
optional: true,
|
|
16252
|
+
suggestedAt: input.displayedFinish ? new Date(input.displayedFinish) : null
|
|
16253
|
+
} : null;
|
|
16254
|
+
const uncomplete = input.activity.executionStatus === P6_EXECUTION_STATUS.COMPLETED && input.activity.actualFinish !== null && input.nextProgress < COMPLETED_PROGRESS ? {
|
|
16255
|
+
required: true,
|
|
16256
|
+
removes: new Date(input.activity.actualFinish)
|
|
16257
|
+
} : null;
|
|
16258
|
+
return { start, finish, uncomplete };
|
|
16259
|
+
}
|
|
16260
|
+
function prepareLookaheadProgressActuals(input) {
|
|
16261
|
+
const plan = planLookaheadProgressActuals(input);
|
|
16262
|
+
if (input.dataDate === null && hasIntent(input.intent)) {
|
|
16263
|
+
invalid3("DATA_DATE_INACTIVE");
|
|
16264
|
+
}
|
|
16265
|
+
if (plan.start && input.intent?.actualStart === void 0) {
|
|
16266
|
+
invalid3("ACTUAL_START_REQUIRED");
|
|
16267
|
+
}
|
|
16268
|
+
if (input.intent?.actualFinish instanceof Date && input.nextProgress !== COMPLETED_PROGRESS) {
|
|
16269
|
+
invalid3("ACTUAL_FINISH_REQUIRES_100");
|
|
16270
|
+
}
|
|
16271
|
+
if (plan.uncomplete && input.intent?.actualFinish !== null) {
|
|
16272
|
+
invalid3("ACTUAL_FINISH_REMOVAL_REQUIRED");
|
|
16273
|
+
}
|
|
16274
|
+
if (!plan.uncomplete && input.intent?.actualFinish === null) {
|
|
16275
|
+
invalid3("ACTUAL_FINISH_REMOVAL_NOT_APPLICABLE");
|
|
16276
|
+
}
|
|
16277
|
+
const actuals = normalizeP6ActualDatePatch(
|
|
16278
|
+
input.activity,
|
|
16279
|
+
input.intent ?? {}
|
|
16280
|
+
);
|
|
16281
|
+
if (input.dataDate === null) return actuals;
|
|
16282
|
+
return withMirroredPercent(input.activity, actuals, input.nextProgress);
|
|
16283
|
+
}
|
|
16284
|
+
function prepareLookaheadProgressActualsForPersistence(input) {
|
|
16285
|
+
const { resolveCalendar, ...progressInput } = input;
|
|
16286
|
+
const preparedActuals = prepareLookaheadProgressActuals(progressInput);
|
|
16287
|
+
if (input.dataDate === null) {
|
|
16288
|
+
return preparedActuals;
|
|
16289
|
+
}
|
|
16290
|
+
const actualStart = input.intent?.actualStart;
|
|
16291
|
+
const needsActualStartNormalization = actualStart !== void 0 && isUtcMidnight(actualStart);
|
|
16292
|
+
if (!needsActualStartNormalization) return preparedActuals;
|
|
16293
|
+
const intent = normalizeActualStart(
|
|
16294
|
+
input.intent,
|
|
16295
|
+
input.activity.actualStart,
|
|
16296
|
+
resolveCalendar
|
|
16297
|
+
);
|
|
16298
|
+
if (intent === void 0) {
|
|
16299
|
+
return preparedActuals;
|
|
16300
|
+
}
|
|
16301
|
+
return prepareLookaheadProgressActuals({ ...progressInput, intent });
|
|
16302
|
+
}
|
|
16303
|
+
function normalizeActualStart(intent, existingActualStart, resolveCalendar) {
|
|
16304
|
+
if (intent?.actualStart === void 0) return intent;
|
|
16305
|
+
if (!isUtcMidnight(intent.actualStart)) return intent;
|
|
16306
|
+
if (existingActualStart !== null) {
|
|
16307
|
+
return {
|
|
16308
|
+
...intent,
|
|
16309
|
+
actualStart: resolveLookaheadActualDateSelection({
|
|
16310
|
+
selectedDay: intent.actualStart.toISOString().slice(0, 10),
|
|
16311
|
+
timeSource: existingActualStart
|
|
16312
|
+
})
|
|
16313
|
+
};
|
|
16314
|
+
}
|
|
16315
|
+
const calendar = resolveCalendar();
|
|
16316
|
+
if (calendar === null) {
|
|
16317
|
+
invalid3("ACTIVITY_CALENDAR_REQUIRED");
|
|
16318
|
+
}
|
|
16319
|
+
return {
|
|
16320
|
+
...intent,
|
|
16321
|
+
actualStart: defaultActualStartTime(intent.actualStart, calendar)
|
|
16322
|
+
};
|
|
16323
|
+
}
|
|
16324
|
+
function withMirroredPercent(activity, actuals, nextProgress) {
|
|
16325
|
+
const executionStatus = actuals.executionStatus ?? activity.executionStatus;
|
|
16326
|
+
if (executionStatus !== P6_EXECUTION_STATUS.IN_PROGRESS) return actuals;
|
|
16327
|
+
switch (activity.percentCompleteType) {
|
|
16328
|
+
case P6_PERCENT_COMPLETE_TYPE.PHYSICAL:
|
|
16329
|
+
return { ...actuals, physicalPercentComplete: nextProgress };
|
|
16330
|
+
case P6_PERCENT_COMPLETE_TYPE.DURATION:
|
|
16331
|
+
return {
|
|
16332
|
+
...actuals,
|
|
16333
|
+
remainingDurationHours: activity.originalDurationHours * (1 - nextProgress / COMPLETED_PROGRESS)
|
|
16334
|
+
};
|
|
16335
|
+
default:
|
|
16336
|
+
return actuals;
|
|
16337
|
+
}
|
|
16338
|
+
}
|
|
16339
|
+
function validateInput(input) {
|
|
16340
|
+
if (!Number.isFinite(input.nextProgress) || input.nextProgress < NOT_STARTED_PROGRESS || input.nextProgress > COMPLETED_PROGRESS) {
|
|
16341
|
+
invalid3("INVALID_PROGRESS");
|
|
16342
|
+
}
|
|
16343
|
+
if (input.dataDate !== null && !validDate(input.dataDate)) {
|
|
16344
|
+
invalid3("INVALID_DATA_DATE");
|
|
16345
|
+
}
|
|
16346
|
+
if (input.displayedFinish != null && !validDate(input.displayedFinish)) {
|
|
16347
|
+
invalid3("INVALID_DISPLAYED_FINISH");
|
|
16348
|
+
}
|
|
16349
|
+
}
|
|
16350
|
+
function validDate(value) {
|
|
16351
|
+
return value instanceof Date && Number.isFinite(value.getTime());
|
|
16352
|
+
}
|
|
16353
|
+
function sameUtcDay2(value, [year, month, day]) {
|
|
16354
|
+
return value.getUTCFullYear() === year && value.getUTCMonth() === month - 1 && value.getUTCDate() === day;
|
|
16355
|
+
}
|
|
16356
|
+
function hasIntent(intent) {
|
|
16357
|
+
return intent?.actualStart !== void 0 || intent?.actualFinish !== void 0;
|
|
16358
|
+
}
|
|
16359
|
+
function invalid3(code) {
|
|
16360
|
+
throw new LookaheadActualTransitionError(code);
|
|
16361
|
+
}
|
|
16362
|
+
|
|
16363
|
+
// src/p6/lookahead-reconciliation.ts
|
|
16364
|
+
function preparePersistedLookaheadDataDate(action, activity, deps) {
|
|
16365
|
+
const settings = deps.dataDateSettings;
|
|
16366
|
+
const capability = deps.dataDateCapability;
|
|
16367
|
+
if (action.persistedProgress === void 0 || activity?.p6 === void 0 || capability === null || !hasActiveDataDate(settings, deps.dataDateEnabled) || settings?.dataDate == null)
|
|
16368
|
+
return null;
|
|
16369
|
+
const patch = prepareLookaheadProgressActuals({
|
|
16370
|
+
dataDate: settings.dataDate,
|
|
16371
|
+
activity: activity.p6,
|
|
16372
|
+
nextProgress: action.persistedProgress,
|
|
16373
|
+
...action.persistedActualTransition === void 0 ? {} : { intent: action.persistedActualTransition }
|
|
16374
|
+
});
|
|
16375
|
+
const prepared = capability.prepareActivityUpdate(
|
|
16376
|
+
activity.p6,
|
|
16377
|
+
{
|
|
16378
|
+
originalDurationHours: activity.p6.originalDurationHours,
|
|
16379
|
+
...patch.actualStart === void 0 ? {} : { actualStart: patch.actualStart },
|
|
16380
|
+
...patch.actualFinish === void 0 ? {} : { actualFinish: patch.actualFinish },
|
|
16381
|
+
...patch.remainingDurationHours == null ? {} : { remainingDurationHours: patch.remainingDurationHours },
|
|
16382
|
+
...patch.physicalPercentComplete == null ? {} : { physicalPercentComplete: patch.physicalPercentComplete }
|
|
16383
|
+
},
|
|
16384
|
+
activity.constraintType
|
|
16385
|
+
);
|
|
16386
|
+
const calendar = deps.adapter.calendarReader.getCalendar(activity.calendarId);
|
|
16387
|
+
const projection = calendar === null ? { p6: prepared.next, startDate: void 0, endDate: void 0 } : capability.projectLocalActivity(activity.p6, prepared.next, {
|
|
16388
|
+
calendar,
|
|
16389
|
+
dataDate: settings.dataDate,
|
|
16390
|
+
totalFloatMethod: settings.totalFloatMethod
|
|
16391
|
+
});
|
|
16392
|
+
return { activityId: activity.id, ...projection };
|
|
16393
|
+
}
|
|
16394
|
+
|
|
16118
16395
|
// src/dispatch/handlers/persistence-acknowledge.ts
|
|
16119
16396
|
var EMPTY_OWNERS = /* @__PURE__ */ new Map();
|
|
16120
16397
|
function persistedOwnersOf(entities) {
|
|
@@ -16333,6 +16610,30 @@ async function dispatchActivityLookaheadSync(action, options, deps) {
|
|
|
16333
16610
|
if (snapshots.some((snapshot) => !snapshot)) {
|
|
16334
16611
|
return { ok: false, reason: REJECTION_REASON.ACTIVITY_NOT_FOUND };
|
|
16335
16612
|
}
|
|
16613
|
+
const persistedDataDate = preparePersistedLookaheadDataDate(
|
|
16614
|
+
action,
|
|
16615
|
+
snapshots[0],
|
|
16616
|
+
deps
|
|
16617
|
+
);
|
|
16618
|
+
if (persistedDataDate !== null) {
|
|
16619
|
+
deps.adapter.setActivityField(
|
|
16620
|
+
persistedDataDate.activityId,
|
|
16621
|
+
"p6",
|
|
16622
|
+
persistedDataDate.p6
|
|
16623
|
+
);
|
|
16624
|
+
if (persistedDataDate.startDate !== void 0)
|
|
16625
|
+
deps.adapter.setActivityField(
|
|
16626
|
+
persistedDataDate.activityId,
|
|
16627
|
+
"startDate",
|
|
16628
|
+
persistedDataDate.startDate
|
|
16629
|
+
);
|
|
16630
|
+
if (persistedDataDate.endDate !== void 0)
|
|
16631
|
+
deps.adapter.setActivityField(
|
|
16632
|
+
persistedDataDate.activityId,
|
|
16633
|
+
"endDate",
|
|
16634
|
+
persistedDataDate.endDate
|
|
16635
|
+
);
|
|
16636
|
+
}
|
|
16336
16637
|
const activities = [];
|
|
16337
16638
|
for (const [index, id] of ids.entries()) {
|
|
16338
16639
|
const snapshot = snapshots[index];
|
|
@@ -16373,7 +16674,7 @@ async function dispatchActivityLookaheadSync(action, options, deps) {
|
|
|
16373
16674
|
[{ activityId: ids[0], progress: action.persistedProgress }],
|
|
16374
16675
|
deps
|
|
16375
16676
|
);
|
|
16376
|
-
if (progressChanges.length > 0) {
|
|
16677
|
+
if (progressChanges.length > 0 || persistedDataDate !== null) {
|
|
16377
16678
|
await runPostMutation(
|
|
16378
16679
|
{
|
|
16379
16680
|
adapter: deps.adapter,
|
|
@@ -17615,7 +17916,7 @@ async function dispatchActivitySetProgress(action, options, deps) {
|
|
|
17615
17916
|
const statusRouting = resolveDataDateProgressButton(
|
|
17616
17917
|
activitySnap,
|
|
17617
17918
|
action.newValue,
|
|
17618
|
-
|
|
17919
|
+
progressChanges,
|
|
17619
17920
|
deps,
|
|
17620
17921
|
options.confirmations
|
|
17621
17922
|
);
|
|
@@ -17623,17 +17924,14 @@ async function dispatchActivitySetProgress(action, options, deps) {
|
|
|
17623
17924
|
return rejectedRouting(statusRouting);
|
|
17624
17925
|
}
|
|
17625
17926
|
const changes = statusRouting === null ? progressChanges : statusRouting.changes;
|
|
17626
|
-
const writesProgress = statusRouting === null || editGate.allowed;
|
|
17627
17927
|
const touchedIds = collectTouchedIds(action.activityId, changes);
|
|
17628
|
-
const beforeSnap = await snapshotActivities(adapter, touchedIds);
|
|
17629
|
-
applyFieldChanges(adapter, action.activityId, changes);
|
|
17630
|
-
|
|
17631
|
-
|
|
17632
|
-
|
|
17633
|
-
|
|
17634
|
-
|
|
17635
|
-
);
|
|
17636
|
-
}
|
|
17928
|
+
const beforeSnap = await snapshotActivities(adapter, touchedIds);
|
|
17929
|
+
applyFieldChanges(adapter, action.activityId, changes);
|
|
17930
|
+
setExplicitSummaryProgressFallbacks(
|
|
17931
|
+
action.activityId,
|
|
17932
|
+
action.newValue,
|
|
17933
|
+
adapter
|
|
17934
|
+
);
|
|
17637
17935
|
runPostProcessorsOnAdapter(
|
|
17638
17936
|
action.activityId,
|
|
17639
17937
|
changes.postProcessors ?? [],
|
|
@@ -26795,140 +27093,6 @@ function changed(before, after) {
|
|
|
26795
27093
|
return serializeCanonicalSchedule(before) !== serializeCanonicalSchedule(after);
|
|
26796
27094
|
}
|
|
26797
27095
|
|
|
26798
|
-
// src/p6/status.ts
|
|
26799
|
-
var INVALID_STATUS = "Invalid P6 activity status";
|
|
26800
|
-
var P6ActivityStatusError = class extends Error {
|
|
26801
|
-
constructor(code, reason) {
|
|
26802
|
-
super(`${INVALID_STATUS}: ${reason}`);
|
|
26803
|
-
this.code = code;
|
|
26804
|
-
this.name = "P6ActivityStatusError";
|
|
26805
|
-
}
|
|
26806
|
-
code;
|
|
26807
|
-
};
|
|
26808
|
-
var COMPLETED_PHYSICAL_PERCENT2 = 100;
|
|
26809
|
-
var NOT_STARTED_PHYSICAL_PERCENT2 = 0;
|
|
26810
|
-
function validateP6ActivityStatus(activity) {
|
|
26811
|
-
validateRemainingDuration(activity.remainingDurationHours);
|
|
26812
|
-
validateDates(activity);
|
|
26813
|
-
validateExecutionStatus(activity);
|
|
26814
|
-
validateDateOrder(activity);
|
|
26815
|
-
}
|
|
26816
|
-
function validateP6ActivityDraftStatus(activity) {
|
|
26817
|
-
validateDraftRemainingDuration(activity.remainingDurationHours);
|
|
26818
|
-
validateDates(activity);
|
|
26819
|
-
validateDraftExecutionStatus(activity);
|
|
26820
|
-
validateDateOrder(activity);
|
|
26821
|
-
}
|
|
26822
|
-
function normalizeP6ActualDatePatch(current, patch) {
|
|
26823
|
-
if (patch.actualStart === void 0 && patch.actualFinish === void 0) {
|
|
26824
|
-
return patch;
|
|
26825
|
-
}
|
|
26826
|
-
const actualStart = patch.actualStart !== void 0 ? patch.actualStart : current.actualStart;
|
|
26827
|
-
const actualFinish = patch.actualFinish !== void 0 ? patch.actualFinish : current.actualFinish;
|
|
26828
|
-
const executionStatus = actualFinish !== null ? "completed" : actualStart !== null ? "in_progress" : "not_started";
|
|
26829
|
-
const unStarting = actualStart === null && actualFinish === null && current.actualStart !== null;
|
|
26830
|
-
const normalized2 = {
|
|
26831
|
-
...patch,
|
|
26832
|
-
executionStatus,
|
|
26833
|
-
...actualFinish !== null ? {
|
|
26834
|
-
remainingDurationHours: 0,
|
|
26835
|
-
physicalPercentComplete: COMPLETED_PHYSICAL_PERCENT2
|
|
26836
|
-
} : {},
|
|
26837
|
-
...unStarting ? {
|
|
26838
|
-
remainingDurationHours: current.originalDurationHours,
|
|
26839
|
-
physicalPercentComplete: NOT_STARTED_PHYSICAL_PERCENT2
|
|
26840
|
-
} : {}
|
|
26841
|
-
};
|
|
26842
|
-
validateP6ActivityDraftStatus({ ...current, ...normalized2 });
|
|
26843
|
-
return normalized2;
|
|
26844
|
-
}
|
|
26845
|
-
function validateRemainingDuration(remainingDurationHours) {
|
|
26846
|
-
if (!Number.isFinite(remainingDurationHours) || remainingDurationHours < 0) {
|
|
26847
|
-
invalid2("Remaining Duration must be finite and non-negative");
|
|
26848
|
-
}
|
|
26849
|
-
}
|
|
26850
|
-
function validateDraftRemainingDuration(remainingDurationHours) {
|
|
26851
|
-
if (remainingDurationHours === null) return;
|
|
26852
|
-
validateRemainingDuration(remainingDurationHours);
|
|
26853
|
-
}
|
|
26854
|
-
function validateDates(activity) {
|
|
26855
|
-
const dates = [
|
|
26856
|
-
activity.actualStart,
|
|
26857
|
-
activity.actualFinish,
|
|
26858
|
-
activity.suspendDate,
|
|
26859
|
-
activity.resumeDate
|
|
26860
|
-
];
|
|
26861
|
-
if (dates.some((date2) => date2 !== null && Number.isNaN(date2.getTime()))) {
|
|
26862
|
-
invalid2("actual, suspend and resume dates must be valid");
|
|
26863
|
-
}
|
|
26864
|
-
}
|
|
26865
|
-
function validateExecutionStatus(activity) {
|
|
26866
|
-
const hasActualStart = activity.actualStart !== null;
|
|
26867
|
-
const hasActualFinish = activity.actualFinish !== null;
|
|
26868
|
-
if (activity.executionStatus === "not_started") {
|
|
26869
|
-
if (hasActualStart || hasActualFinish) {
|
|
26870
|
-
invalid2("not_started cannot have actual dates");
|
|
26871
|
-
}
|
|
26872
|
-
return;
|
|
26873
|
-
}
|
|
26874
|
-
if (activity.executionStatus === "in_progress") {
|
|
26875
|
-
if (!hasActualStart || hasActualFinish) {
|
|
26876
|
-
invalid2("in_progress requires Actual Start and no Actual Finish");
|
|
26877
|
-
}
|
|
26878
|
-
return;
|
|
26879
|
-
}
|
|
26880
|
-
if (!hasActualStart || !hasActualFinish || activity.remainingDurationHours !== 0) {
|
|
26881
|
-
invalid2(
|
|
26882
|
-
"completed requires Actual Start, Actual Finish and zero Remaining Duration"
|
|
26883
|
-
);
|
|
26884
|
-
}
|
|
26885
|
-
}
|
|
26886
|
-
function validateDraftExecutionStatus(activity) {
|
|
26887
|
-
const hasActualStart = activity.actualStart !== null;
|
|
26888
|
-
const hasActualFinish = activity.actualFinish !== null;
|
|
26889
|
-
if (hasActualFinish && !hasActualStart) {
|
|
26890
|
-
invalid2("Actual Finish requires Actual Start");
|
|
26891
|
-
}
|
|
26892
|
-
if (activity.executionStatus === "not_started" && hasActualStart) {
|
|
26893
|
-
invalid2("not_started cannot have actual dates");
|
|
26894
|
-
}
|
|
26895
|
-
if (activity.executionStatus === "in_progress" && hasActualFinish) {
|
|
26896
|
-
invalid2("in_progress cannot have Actual Finish");
|
|
26897
|
-
}
|
|
26898
|
-
if (activity.executionStatus === "completed" && activity.remainingDurationHours !== null && activity.remainingDurationHours !== 0) {
|
|
26899
|
-
invalid2("completed requires zero Remaining Duration");
|
|
26900
|
-
}
|
|
26901
|
-
}
|
|
26902
|
-
function validateDateOrder(activity) {
|
|
26903
|
-
const { actualStart, actualFinish, suspendDate, resumeDate } = activity;
|
|
26904
|
-
if (actualStart !== null && actualFinish !== null && actualStart.getTime() > actualFinish.getTime()) {
|
|
26905
|
-
throw new P6ActivityStatusError(
|
|
26906
|
-
"ACTUAL_FINISH_BEFORE_START",
|
|
26907
|
-
"Actual Start must not be after Actual Finish"
|
|
26908
|
-
);
|
|
26909
|
-
}
|
|
26910
|
-
if (suspendDate !== null) {
|
|
26911
|
-
if (actualStart === null) invalid2("Suspend requires Actual Start");
|
|
26912
|
-
if (actualStart.getTime() > suspendDate.getTime()) {
|
|
26913
|
-
invalid2("Suspend must not be before Actual Start");
|
|
26914
|
-
}
|
|
26915
|
-
if (actualFinish !== null && suspendDate.getTime() > actualFinish.getTime()) {
|
|
26916
|
-
invalid2("Suspend must not be after Actual Finish");
|
|
26917
|
-
}
|
|
26918
|
-
}
|
|
26919
|
-
if (resumeDate === null) return;
|
|
26920
|
-
if (suspendDate === null) invalid2("Resume requires Suspend");
|
|
26921
|
-
if (suspendDate.getTime() > resumeDate.getTime()) {
|
|
26922
|
-
invalid2("Suspend must not be after Resume");
|
|
26923
|
-
}
|
|
26924
|
-
if (actualFinish !== null && resumeDate.getTime() > actualFinish.getTime()) {
|
|
26925
|
-
invalid2("Resume must not be after Actual Finish");
|
|
26926
|
-
}
|
|
26927
|
-
}
|
|
26928
|
-
function invalid2(reason) {
|
|
26929
|
-
throw new Error(`${INVALID_STATUS}: ${reason}`);
|
|
26930
|
-
}
|
|
26931
|
-
|
|
26932
27096
|
// src/p6/derived.ts
|
|
26933
27097
|
var INVALID_INPUT = "Invalid P6 derived input";
|
|
26934
27098
|
var PERCENT_SCALE2 = 100;
|
|
@@ -30897,48 +31061,48 @@ function optionalP6Date(rawValue) {
|
|
|
30897
31061
|
function yesNo(rawValue) {
|
|
30898
31062
|
if (rawValue === "Y") return true;
|
|
30899
31063
|
if (rawValue === "N") return false;
|
|
30900
|
-
|
|
31064
|
+
invalid4(`expected Y/N, got "${rawValue}"`);
|
|
30901
31065
|
}
|
|
30902
31066
|
function enumValue(map, rawValue) {
|
|
30903
|
-
if (!Object.hasOwn(map, rawValue))
|
|
31067
|
+
if (!Object.hasOwn(map, rawValue)) invalid4(`unknown enum "${rawValue}"`);
|
|
30904
31068
|
return map[rawValue];
|
|
30905
31069
|
}
|
|
30906
31070
|
function outOfSequencePolicy(schedule) {
|
|
30907
31071
|
const retained = yesNo(schedule.sched_retained_logic);
|
|
30908
31072
|
const override = yesNo(schedule.sched_progress_override);
|
|
30909
31073
|
if (retained && override)
|
|
30910
|
-
|
|
31074
|
+
invalid4("retained logic and progress override conflict");
|
|
30911
31075
|
if (retained) return "retained_logic";
|
|
30912
31076
|
if (override) return "progress_override";
|
|
30913
31077
|
return "actual_dates";
|
|
30914
31078
|
}
|
|
30915
31079
|
function nonNegativeNumber(rawValue, field) {
|
|
30916
31080
|
const value = finiteNumber(rawValue, field);
|
|
30917
|
-
if (value < 0)
|
|
31081
|
+
if (value < 0) invalid4(`${field} must be a non-negative number`);
|
|
30918
31082
|
return value;
|
|
30919
31083
|
}
|
|
30920
31084
|
function finiteNumber(rawValue, field) {
|
|
30921
31085
|
const value = Number(rawValue);
|
|
30922
31086
|
if (rawValue === "" || !Number.isFinite(value)) {
|
|
30923
|
-
|
|
31087
|
+
invalid4(`${field} must be a finite number`);
|
|
30924
31088
|
}
|
|
30925
31089
|
return value;
|
|
30926
31090
|
}
|
|
30927
31091
|
function nonNegativeInteger(rawValue, field) {
|
|
30928
31092
|
const value = nonNegativeNumber(rawValue, field);
|
|
30929
|
-
if (!Number.isInteger(value))
|
|
31093
|
+
if (!Number.isInteger(value)) invalid4(`${field} must be an integer`);
|
|
30930
31094
|
return value;
|
|
30931
31095
|
}
|
|
30932
31096
|
function endingActivityId(rawValue, resolveActivityId) {
|
|
30933
31097
|
if (rawValue === "") return null;
|
|
30934
31098
|
if (resolveActivityId === void 0) {
|
|
30935
|
-
|
|
31099
|
+
invalid4("ending activity requires an ID resolver");
|
|
30936
31100
|
}
|
|
30937
31101
|
const resolved = resolveActivityId(rawValue);
|
|
30938
|
-
if (resolved === null)
|
|
31102
|
+
if (resolved === null) invalid4(`unknown ending activity "${rawValue}"`);
|
|
30939
31103
|
return resolved;
|
|
30940
31104
|
}
|
|
30941
|
-
function
|
|
31105
|
+
function invalid4(reason) {
|
|
30942
31106
|
throw new Error(`${INVALID_OPTIONS}: ${reason}`);
|
|
30943
31107
|
}
|
|
30944
31108
|
|
|
@@ -30969,13 +31133,11 @@ function prepareDataDateSettingsUpdate(current, patch) {
|
|
|
30969
31133
|
};
|
|
30970
31134
|
}
|
|
30971
31135
|
function prepareDataDateActivityUpdate(current, patch, primaryConstraint) {
|
|
30972
|
-
const
|
|
31136
|
+
const synchronized = synchronizeNotStartedDurations(current, patch);
|
|
31137
|
+
const percentRouted = routeActivityPercentComplete(current, synchronized);
|
|
30973
31138
|
validateActivityInputPatch(percentRouted);
|
|
30974
31139
|
validateSecondaryConstraint(percentRouted, primaryConstraint);
|
|
30975
|
-
const routed =
|
|
30976
|
-
current,
|
|
30977
|
-
gatePhysicalPercentInput(current, percentRouted)
|
|
30978
|
-
);
|
|
31140
|
+
const routed = gatePhysicalPercentInput(current, percentRouted);
|
|
30979
31141
|
const next = cloneDomainValue({
|
|
30980
31142
|
...current,
|
|
30981
31143
|
...routed,
|
|
@@ -30988,7 +31150,7 @@ function prepareDataDateActivityUpdate(current, patch, primaryConstraint) {
|
|
|
30988
31150
|
};
|
|
30989
31151
|
}
|
|
30990
31152
|
function synchronizeNotStartedDurations(current, patch) {
|
|
30991
|
-
if (current.executionStatus !== P6_EXECUTION_STATUS.NOT_STARTED || patch.remainingDurationHours === void 0 || patch.originalDurationHours !== void 0) {
|
|
31153
|
+
if (current.executionStatus !== P6_EXECUTION_STATUS.NOT_STARTED || patch.actualStart != null || patch.activityPercentComplete !== void 0 || patch.remainingDurationHours === void 0 || patch.originalDurationHours !== void 0) {
|
|
30992
31154
|
return patch;
|
|
30993
31155
|
}
|
|
30994
31156
|
return {
|
|
@@ -31033,7 +31195,7 @@ function routeActivityPercentComplete(current, patch) {
|
|
|
31033
31195
|
case P6_PERCENT_COMPLETE_TYPE.DURATION:
|
|
31034
31196
|
return {
|
|
31035
31197
|
...rest,
|
|
31036
|
-
remainingDurationHours: current.originalDurationHours * (1 - activityPercentComplete / FULL_PERCENT)
|
|
31198
|
+
remainingDurationHours: (rest.originalDurationHours ?? current.originalDurationHours) * (1 - activityPercentComplete / FULL_PERCENT)
|
|
31037
31199
|
};
|
|
31038
31200
|
case P6_PERCENT_COMPLETE_TYPE.UNITS:
|
|
31039
31201
|
throw new Error(
|
|
@@ -37208,136 +37370,6 @@ function serializeP6State(input) {
|
|
|
37208
37370
|
// src/boundary/save/unsaved.ts
|
|
37209
37371
|
var getUnsavedActivities = (activities = []) => (activities ?? []).filter((activity) => !activity.proplannerId);
|
|
37210
37372
|
|
|
37211
|
-
// src/p6/lookahead-progress-transition.ts
|
|
37212
|
-
var LookaheadActualTransitionError = class extends Error {
|
|
37213
|
-
constructor(code) {
|
|
37214
|
-
super(code);
|
|
37215
|
-
this.code = code;
|
|
37216
|
-
this.name = "LookaheadActualTransitionError";
|
|
37217
|
-
}
|
|
37218
|
-
code;
|
|
37219
|
-
};
|
|
37220
|
-
var ACTUAL_DAY_PATTERN = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
37221
|
-
function resolveLookaheadActualDateSelection(input) {
|
|
37222
|
-
if (!validDate(input.timeSource)) invalid4("INVALID_ACTUAL_TIME_SOURCE");
|
|
37223
|
-
const parts = actualDayParts(input.selectedDay);
|
|
37224
|
-
const [year, month, day] = parts;
|
|
37225
|
-
const result = new Date(input.timeSource);
|
|
37226
|
-
result.setUTCFullYear(year, month - 1, day);
|
|
37227
|
-
if (!sameUtcDay2(result, parts)) invalid4("INVALID_ACTUAL_DAY");
|
|
37228
|
-
return result;
|
|
37229
|
-
}
|
|
37230
|
-
function actualDayParts(value) {
|
|
37231
|
-
const match = ACTUAL_DAY_PATTERN.exec(value);
|
|
37232
|
-
if (!match) invalid4("INVALID_ACTUAL_DAY");
|
|
37233
|
-
return [Number(match[1]), Number(match[2]), Number(match[3])];
|
|
37234
|
-
}
|
|
37235
|
-
function planLookaheadProgressActuals(input) {
|
|
37236
|
-
validateInput(input);
|
|
37237
|
-
if (input.dataDate === null) {
|
|
37238
|
-
return { start: null, finish: null, uncomplete: null };
|
|
37239
|
-
}
|
|
37240
|
-
const start = input.activity.executionStatus === P6_EXECUTION_STATUS.NOT_STARTED && input.nextProgress > NOT_STARTED_PROGRESS ? { required: true, suggestedAt: new Date(input.dataDate) } : null;
|
|
37241
|
-
const finish = input.activity.executionStatus !== P6_EXECUTION_STATUS.COMPLETED && input.nextProgress === COMPLETED_PROGRESS ? {
|
|
37242
|
-
optional: true,
|
|
37243
|
-
suggestedAt: input.displayedFinish ? new Date(input.displayedFinish) : null
|
|
37244
|
-
} : null;
|
|
37245
|
-
const uncomplete = input.activity.executionStatus === P6_EXECUTION_STATUS.COMPLETED && input.activity.actualFinish !== null && input.nextProgress < COMPLETED_PROGRESS ? {
|
|
37246
|
-
required: true,
|
|
37247
|
-
removes: new Date(input.activity.actualFinish)
|
|
37248
|
-
} : null;
|
|
37249
|
-
return { start, finish, uncomplete };
|
|
37250
|
-
}
|
|
37251
|
-
function prepareLookaheadProgressActuals(input) {
|
|
37252
|
-
const plan = planLookaheadProgressActuals(input);
|
|
37253
|
-
if (input.dataDate === null && hasIntent(input.intent)) {
|
|
37254
|
-
invalid4("DATA_DATE_INACTIVE");
|
|
37255
|
-
}
|
|
37256
|
-
if (plan.start && input.intent?.actualStart === void 0) {
|
|
37257
|
-
invalid4("ACTUAL_START_REQUIRED");
|
|
37258
|
-
}
|
|
37259
|
-
if (input.intent?.actualFinish instanceof Date && input.nextProgress !== COMPLETED_PROGRESS) {
|
|
37260
|
-
invalid4("ACTUAL_FINISH_REQUIRES_100");
|
|
37261
|
-
}
|
|
37262
|
-
if (plan.uncomplete && input.intent?.actualFinish !== null) {
|
|
37263
|
-
invalid4("ACTUAL_FINISH_REMOVAL_REQUIRED");
|
|
37264
|
-
}
|
|
37265
|
-
if (!plan.uncomplete && input.intent?.actualFinish === null) {
|
|
37266
|
-
invalid4("ACTUAL_FINISH_REMOVAL_NOT_APPLICABLE");
|
|
37267
|
-
}
|
|
37268
|
-
const actuals = normalizeP6ActualDatePatch(
|
|
37269
|
-
input.activity,
|
|
37270
|
-
input.intent ?? {}
|
|
37271
|
-
);
|
|
37272
|
-
if (input.dataDate === null) return actuals;
|
|
37273
|
-
return withMirroredPercent(input.activity, actuals, input.nextProgress);
|
|
37274
|
-
}
|
|
37275
|
-
function prepareLookaheadProgressActualsForPersistence(input) {
|
|
37276
|
-
const { resolveCalendar, ...progressInput } = input;
|
|
37277
|
-
const preparedActuals = prepareLookaheadProgressActuals(progressInput);
|
|
37278
|
-
if (input.dataDate === null) {
|
|
37279
|
-
return preparedActuals;
|
|
37280
|
-
}
|
|
37281
|
-
const actualStart = input.intent?.actualStart;
|
|
37282
|
-
const needsActualStartNormalization = actualStart !== void 0 && isUtcMidnight(actualStart);
|
|
37283
|
-
if (!needsActualStartNormalization) return preparedActuals;
|
|
37284
|
-
const intent = normalizeActualStart(input.intent, resolveCalendar);
|
|
37285
|
-
if (intent === void 0) {
|
|
37286
|
-
return preparedActuals;
|
|
37287
|
-
}
|
|
37288
|
-
return prepareLookaheadProgressActuals({ ...progressInput, intent });
|
|
37289
|
-
}
|
|
37290
|
-
function normalizeActualStart(intent, resolveCalendar) {
|
|
37291
|
-
if (intent?.actualStart === void 0) return intent;
|
|
37292
|
-
if (!isUtcMidnight(intent.actualStart)) return intent;
|
|
37293
|
-
const calendar = resolveCalendar();
|
|
37294
|
-
if (calendar === null) {
|
|
37295
|
-
invalid4("ACTIVITY_CALENDAR_REQUIRED");
|
|
37296
|
-
}
|
|
37297
|
-
return {
|
|
37298
|
-
...intent,
|
|
37299
|
-
actualStart: defaultActualStartTime(intent.actualStart, calendar)
|
|
37300
|
-
};
|
|
37301
|
-
}
|
|
37302
|
-
function withMirroredPercent(activity, actuals, nextProgress) {
|
|
37303
|
-
const executionStatus = actuals.executionStatus ?? activity.executionStatus;
|
|
37304
|
-
if (executionStatus !== P6_EXECUTION_STATUS.IN_PROGRESS) return actuals;
|
|
37305
|
-
switch (activity.percentCompleteType) {
|
|
37306
|
-
case P6_PERCENT_COMPLETE_TYPE.PHYSICAL:
|
|
37307
|
-
return { ...actuals, physicalPercentComplete: nextProgress };
|
|
37308
|
-
case P6_PERCENT_COMPLETE_TYPE.DURATION:
|
|
37309
|
-
return {
|
|
37310
|
-
...actuals,
|
|
37311
|
-
remainingDurationHours: activity.originalDurationHours * (1 - nextProgress / COMPLETED_PROGRESS)
|
|
37312
|
-
};
|
|
37313
|
-
default:
|
|
37314
|
-
return actuals;
|
|
37315
|
-
}
|
|
37316
|
-
}
|
|
37317
|
-
function validateInput(input) {
|
|
37318
|
-
if (!Number.isFinite(input.nextProgress) || input.nextProgress < NOT_STARTED_PROGRESS || input.nextProgress > COMPLETED_PROGRESS) {
|
|
37319
|
-
invalid4("INVALID_PROGRESS");
|
|
37320
|
-
}
|
|
37321
|
-
if (input.dataDate !== null && !validDate(input.dataDate)) {
|
|
37322
|
-
invalid4("INVALID_DATA_DATE");
|
|
37323
|
-
}
|
|
37324
|
-
if (input.displayedFinish != null && !validDate(input.displayedFinish)) {
|
|
37325
|
-
invalid4("INVALID_DISPLAYED_FINISH");
|
|
37326
|
-
}
|
|
37327
|
-
}
|
|
37328
|
-
function validDate(value) {
|
|
37329
|
-
return value instanceof Date && Number.isFinite(value.getTime());
|
|
37330
|
-
}
|
|
37331
|
-
function sameUtcDay2(value, [year, month, day]) {
|
|
37332
|
-
return value.getUTCFullYear() === year && value.getUTCMonth() === month - 1 && value.getUTCDate() === day;
|
|
37333
|
-
}
|
|
37334
|
-
function hasIntent(intent) {
|
|
37335
|
-
return intent?.actualStart !== void 0 || intent?.actualFinish !== void 0;
|
|
37336
|
-
}
|
|
37337
|
-
function invalid4(code) {
|
|
37338
|
-
throw new LookaheadActualTransitionError(code);
|
|
37339
|
-
}
|
|
37340
|
-
|
|
37341
37373
|
// src/p6/expected-finish-selection.ts
|
|
37342
37374
|
function resolveExpectedFinishDateSelection(input) {
|
|
37343
37375
|
return resolveLookaheadActualDateSelection({
|