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