@outbuild-company/schedule-core 1.14.0 → 1.14.2

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.js CHANGED
@@ -5367,13 +5367,14 @@ function buildCalendarPatch(activity, newCalendarId, ctx) {
5367
5367
  const newCalendar = ctx.calendars.getCalendar(newCalendarId);
5368
5368
  if (newCalendar) {
5369
5369
  const isMilestone = activity.durationHours === 0;
5370
- const snapFrom = isMilestone ? startOfUtcDay2(activity.startDate) : activity.startDate;
5370
+ const snapToShiftStart = isMilestone || activity.assignedDefaultCalendar;
5371
+ const snapFrom = snapToShiftStart ? startOfUtcDay2(activity.startDate) : activity.startDate;
5371
5372
  const calendarStart = newCalendar.getClosestWorkTime({
5372
5373
  date: snapFrom,
5373
5374
  direction: "future",
5374
5375
  unit: "hour"
5375
5376
  });
5376
- if (!activity.autoScheduling || isMilestone || newCalendar.getWorkHours(activity.startDate).length === 0) {
5377
+ if (!activity.autoScheduling || snapToShiftStart || newCalendar.getWorkHours(activity.startDate).length === 0) {
5377
5378
  fields.startDate = calendarStart;
5378
5379
  }
5379
5380
  if (!activity.autoScheduling) {
@@ -15085,6 +15086,9 @@ async function dispatchBulkEdit(action, options, deps) {
15085
15086
  const trackingEvents = [];
15086
15087
  const linkChanges = [];
15087
15088
  const warnings = [];
15089
+ const warningsBeforeExplicitConstraint = /* @__PURE__ */ new Set();
15090
+ const appliedDateColumnsByActivity = /* @__PURE__ */ new Map();
15091
+ const explicitConstraintsByActivity = /* @__PURE__ */ new Map();
15088
15092
  let needsAutoSchedule = false;
15089
15093
  for (const edit of action.edits) {
15090
15094
  const outcome = applyOneEdit2(edit, deps, action.eventSource);
@@ -15102,6 +15106,7 @@ async function dispatchBulkEdit(action, options, deps) {
15102
15106
  if (isExplicitConstraintDateEdit(edit.column)) {
15103
15107
  explicitDateEditActivities.add(String(edit.activityId));
15104
15108
  }
15109
+ recordAppliedDateColumn(appliedDateColumnsByActivity, edit);
15105
15110
  const beforeLinkLags = snapshotIncomingLinkLags(adapter, edit.activityId);
15106
15111
  const preEditSnapshot = snapshotSingleActivity(
15107
15112
  adapter,
@@ -15116,6 +15121,16 @@ async function dispatchBulkEdit(action, options, deps) {
15116
15121
  adapter,
15117
15122
  preEditSnapshot
15118
15123
  );
15124
+ recordWarningsBeforeExplicitConstraint(
15125
+ warningsBeforeExplicitConstraint,
15126
+ warnings,
15127
+ edit
15128
+ );
15129
+ recordExplicitConstraint(
15130
+ explicitConstraintsByActivity,
15131
+ edit,
15132
+ adapter.getActivity(edit.activityId)
15133
+ );
15119
15134
  syncCustomIdTracker(edit, customIdBeforeApply, deps);
15120
15135
  linkChanges.push(
15121
15136
  ...diffIncomingLinkLagChanges(beforeLinkLags, adapter, edit.activityId)
@@ -15135,6 +15150,14 @@ async function dispatchBulkEdit(action, options, deps) {
15135
15150
  now: deps.now,
15136
15151
  options
15137
15152
  };
15153
+ const reconciledWarnings = reconcileAtomicDateConstraints(
15154
+ appliedDateColumnsByActivity,
15155
+ explicitConstraintsByActivity,
15156
+ beforeSnap,
15157
+ warnings,
15158
+ warningsBeforeExplicitConstraint,
15159
+ deps
15160
+ );
15138
15161
  const batchHasConstraintEdits = constraintPriorsByActivity.size > 0;
15139
15162
  const { scheduledIds } = await (batchHasConstraintEdits ? settleConstraintEdits(
15140
15163
  {
@@ -15178,11 +15201,114 @@ async function dispatchBulkEdit(action, options, deps) {
15178
15201
  sirDetection: SIR_DETECTION_PHASE.BEFORE_DIFF,
15179
15202
  links: linkChanges,
15180
15203
  trackingEvents,
15181
- warnings,
15204
+ warnings: reconciledWarnings,
15182
15205
  hoursPerDay: sector.hoursPerDay
15183
15206
  })
15184
15207
  };
15185
15208
  }
15209
+ function recordWarningsBeforeExplicitConstraint(warningsBeforeExplicitConstraint, warnings, edit) {
15210
+ if (!isConstraintEditColumn(edit.column)) return;
15211
+ const activityId = String(edit.activityId);
15212
+ for (const warning of warnings) {
15213
+ if (String(warning.activityId) === activityId) {
15214
+ warningsBeforeExplicitConstraint.add(warning);
15215
+ }
15216
+ }
15217
+ }
15218
+ function recordExplicitConstraint(constraintsByActivity, edit, activity) {
15219
+ if (!isConstraintEditColumn(edit.column) || !activity) return;
15220
+ constraintsByActivity.set(String(edit.activityId), {
15221
+ constraintType: activity.constraintType,
15222
+ constraintDate: activity.constraintDate ? new Date(activity.constraintDate.getTime()) : null
15223
+ });
15224
+ }
15225
+ function recordAppliedDateColumn(columnsByActivity, edit) {
15226
+ if (edit.column !== COLUMN.START_DATE && edit.column !== COLUMN.END_DATE) {
15227
+ return;
15228
+ }
15229
+ const activityId = String(edit.activityId);
15230
+ const columns = columnsByActivity.get(activityId) ?? /* @__PURE__ */ new Set();
15231
+ columns.add(edit.column);
15232
+ columnsByActivity.set(activityId, columns);
15233
+ }
15234
+ function reconcileAtomicDateConstraints(columnsByActivity, explicitConstraintsByActivity, beforeSnap, warnings, warningsBeforeExplicitConstraint, deps) {
15235
+ const reconciledIds = /* @__PURE__ */ new Set();
15236
+ const reconciledWarnings = [];
15237
+ const discardedWarnings = /* @__PURE__ */ new Set();
15238
+ for (const [activityId, columns] of columnsByActivity) {
15239
+ if (!columns.has(COLUMN.START_DATE) || !columns.has(COLUMN.END_DATE)) {
15240
+ continue;
15241
+ }
15242
+ const explicitConstraint = explicitConstraintsByActivity.get(activityId);
15243
+ if (explicitConstraint) {
15244
+ deps.adapter.setActivityFields(activityId, explicitConstraint);
15245
+ for (const warning of warningsBeforeExplicitConstraint) {
15246
+ if (String(warning.activityId) === activityId) {
15247
+ discardedWarnings.add(warning);
15248
+ }
15249
+ }
15250
+ continue;
15251
+ }
15252
+ const before = beforeSnap.get(activityId);
15253
+ const after = deps.adapter.getActivity(activityId);
15254
+ if (!before?.constraintType || !before.constraintDate || !after) continue;
15255
+ const projectedDate = pickProjectedDateForConstraint(
15256
+ before.constraintType,
15257
+ after.startDate,
15258
+ after.endDate
15259
+ );
15260
+ const violatesConstraint = violatesAtomicDateConstraint(
15261
+ before.constraintType,
15262
+ before.constraintDate,
15263
+ projectedDate
15264
+ );
15265
+ reconciledIds.add(activityId);
15266
+ if (violatesConstraint) {
15267
+ deps.adapter.setActivityField(
15268
+ activityId,
15269
+ "constraintType",
15270
+ CONSTRAINT_TYPE.SNET
15271
+ );
15272
+ deps.adapter.setActivityField(
15273
+ activityId,
15274
+ "constraintDate",
15275
+ new Date(after.startDate.getTime())
15276
+ );
15277
+ const warning = toConstraintWarning(
15278
+ activityId,
15279
+ buildConstraintNotification(
15280
+ before.constraintType,
15281
+ before.constraintDate,
15282
+ projectedDate
15283
+ )
15284
+ );
15285
+ if (warning) reconciledWarnings.push(warning);
15286
+ continue;
15287
+ }
15288
+ deps.adapter.setActivityField(
15289
+ activityId,
15290
+ "constraintType",
15291
+ before.constraintType
15292
+ );
15293
+ deps.adapter.setActivityField(
15294
+ activityId,
15295
+ "constraintDate",
15296
+ before.constraintDate
15297
+ );
15298
+ }
15299
+ return [
15300
+ ...warnings.filter(
15301
+ (warning) => !discardedWarnings.has(warning) && !reconciledIds.has(String(warning.activityId))
15302
+ ),
15303
+ ...reconciledWarnings
15304
+ ];
15305
+ }
15306
+ function violatesAtomicDateConstraint(constraintType, constraintDate, projectedDate) {
15307
+ if (constraintType === CONSTRAINT_TYPE.MSO || constraintType === CONSTRAINT_TYPE.MFO) {
15308
+ return constraintDate.getTime() !== projectedDate.getTime();
15309
+ }
15310
+ return checkConstraintViolation(constraintType, constraintDate, projectedDate).violated;
15311
+ }
15186
15312
  function applyOneEdit2(edit, deps, eventSource) {
15187
15313
  const { ctx } = deps;
15188
15314
  const activityId = edit.activityId;