@dv4resi/dvss-backend-module-calendar-im 0.0.4 → 0.0.6

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
@@ -978,6 +978,13 @@ var GET_PAYMENTS_SORTING_ENUM = /* @__PURE__ */ (function(GET_PAYMENTS_SORTING_E
978
978
  GET_PAYMENTS_SORTING_ENUM2["PAYMENT_MODE"] = "PAYMENT_MODE";
979
979
  return GET_PAYMENTS_SORTING_ENUM2;
980
980
  })({});
981
+ var EVENT_INSTANCE_KIND = /* @__PURE__ */ (function(EVENT_INSTANCE_KIND2) {
982
+ EVENT_INSTANCE_KIND2["SINGLE"] = "SINGLE";
983
+ EVENT_INSTANCE_KIND2["SERIES_MASTER"] = "SERIES_MASTER";
984
+ EVENT_INSTANCE_KIND2["OCCURRENCE"] = "OCCURRENCE";
985
+ EVENT_INSTANCE_KIND2["EXCEPTION"] = "EXCEPTION";
986
+ return EVENT_INSTANCE_KIND2;
987
+ })({});
981
988
 
982
989
  // ../../packages/dvss-integration-libs/src/integration-operation-skeletons/capabilities/wellness/wellness-management.base.ts
983
990
  var BaseWellnessManagement = class {
@@ -3834,184 +3841,215 @@ exports.MicrosoftApiClientService = _ts_decorate27([
3834
3841
  typeof exports.TrafficGatewayService === "undefined" ? Object : exports.TrafficGatewayService
3835
3842
  ])
3836
3843
  ], exports.MicrosoftApiClientService);
3837
-
3838
- // ../../packages/dvss-integration-microsoft/src/capabilities/booking-management/booking-management.mapper.ts
3839
- var GRAPH_EVENT_KNOWN_KEYS = /* @__PURE__ */ new Set([
3840
- "id",
3841
- "subject",
3842
- "body",
3843
- "start",
3844
- "end",
3845
- "location",
3846
- "showAs",
3847
- "isCancelled",
3848
- "recurrence",
3849
- "attendees",
3850
- "organizer"
3851
- ]);
3852
3844
  var GRAPH_RESOURCE_ATTENDEE_TYPE = "resource";
3845
+ var GRAPH_WEEKDAY = {
3846
+ [models.DAY_OF_WEEK.SUN]: "sunday",
3847
+ [models.DAY_OF_WEEK.MON]: "monday",
3848
+ [models.DAY_OF_WEEK.TUE]: "tuesday",
3849
+ [models.DAY_OF_WEEK.WED]: "wednesday",
3850
+ [models.DAY_OF_WEEK.THU]: "thursday",
3851
+ [models.DAY_OF_WEEK.FRI]: "friday",
3852
+ [models.DAY_OF_WEEK.SAT]: "saturday"
3853
+ };
3854
+ var GRAPH_MONTHLY_INDEX = {
3855
+ [models.SCHEDULE_MONTHLY_UNIT.FIRST]: "first",
3856
+ [models.SCHEDULE_MONTHLY_UNIT.SECOND]: "second",
3857
+ [models.SCHEDULE_MONTHLY_UNIT.THIRD]: "third",
3858
+ [models.SCHEDULE_MONTHLY_UNIT.FOURTH]: "fourth",
3859
+ [models.SCHEDULE_MONTHLY_UNIT.LAST]: "last"
3860
+ };
3861
+ var GRAPH_TYPE_TO_INSTANCE_KIND = {
3862
+ singleInstance: EVENT_INSTANCE_KIND.SINGLE,
3863
+ seriesMaster: EVENT_INSTANCE_KIND.SERIES_MASTER,
3864
+ occurrence: EVENT_INSTANCE_KIND.OCCURRENCE,
3865
+ exception: EVENT_INSTANCE_KIND.EXCEPTION
3866
+ };
3853
3867
  function toGraphEvent(event, options) {
3854
3868
  const graph = {};
3855
- if (event.subject !== void 0) {
3856
- graph.subject = event.subject;
3869
+ if (event.name !== void 0) {
3870
+ graph.subject = event.name;
3857
3871
  }
3858
- if (event.body !== void 0) {
3872
+ const body = event.description ?? event.notes ?? void 0;
3873
+ if (body !== void 0) {
3859
3874
  graph.body = {
3860
3875
  contentType: "text",
3861
- content: event.body
3876
+ content: body
3862
3877
  };
3863
3878
  }
3864
- if (event.start !== void 0) {
3879
+ if (event.bookingStartDateLabel !== void 0) {
3865
3880
  graph.start = {
3866
- dateTime: event.start.dateTime,
3867
- timeZone: event.start.timeZone
3881
+ dateTime: toGraphDateTime(event.bookingStartDateLabel, event.bookingStartTimeLabel, event.isFullDay),
3882
+ timeZone: event.timeZone ?? ""
3868
3883
  };
3869
3884
  }
3870
- if (event.end !== void 0) {
3885
+ if (event.bookingEndDateLabel !== void 0) {
3871
3886
  graph.end = {
3872
- dateTime: event.end.dateTime,
3873
- timeZone: event.end.timeZone
3887
+ dateTime: toGraphDateTime(event.bookingEndDateLabel, event.bookingEndTimeLabel, event.isFullDay),
3888
+ timeZone: event.timeZone ?? ""
3874
3889
  };
3875
3890
  }
3876
- if (event.location !== void 0) {
3877
- graph.location = {
3878
- displayName: event.location
3879
- };
3891
+ if (event.isFullDay !== void 0) {
3892
+ graph.isAllDay = event.isFullDay;
3880
3893
  }
3881
- if (event.showAs !== void 0) {
3882
- graph.showAs = event.showAs;
3894
+ if (event.isRecurring && event.schedule) {
3895
+ const recurrence = scheduleToGraphRecurrence(event.schedule, {
3896
+ startDate: event.bookingStartDateLabel,
3897
+ endDate: event.bookingEndDateLabel
3898
+ });
3899
+ if (recurrence) {
3900
+ graph.recurrence = recurrence;
3901
+ }
3883
3902
  }
3884
- if (event.isCancelled !== void 0) {
3885
- graph.isCancelled = event.isCancelled;
3903
+ const attendees = buildGraphAttendees(event, options?.targetMailbox);
3904
+ if (attendees.length > 0) {
3905
+ graph.attendees = attendees;
3886
3906
  }
3887
- if (event.recurrence !== void 0) {
3888
- graph.recurrence = toGraphRecurrence(event.recurrence);
3907
+ return graph;
3908
+ }
3909
+ __name(toGraphEvent, "toGraphEvent");
3910
+ function spaceMailboxesFromItems(items) {
3911
+ const out = [];
3912
+ const seen = /* @__PURE__ */ new Set();
3913
+ for (const item of items ?? []) {
3914
+ const isSpace = item.resources?.some((resource) => resource.resourceType === models.OFFERING_RESOURCE_TYPE.SPACE);
3915
+ const email = item.externalId?.trim();
3916
+ const key = email?.toLowerCase();
3917
+ if (isSpace && email && key && !seen.has(key)) {
3918
+ seen.add(key);
3919
+ out.push(email);
3920
+ }
3889
3921
  }
3890
- if (event.attendees !== void 0) {
3891
- graph.attendees = event.attendees.map((attendee) => {
3892
- const mapped = {
3893
- emailAddress: omitUndefined({
3894
- address: attendee.email,
3895
- name: attendee.name
3896
- })
3897
- };
3898
- if (attendee.type !== void 0) {
3899
- mapped.type = attendee.type;
3900
- }
3901
- return mapped;
3922
+ return out;
3923
+ }
3924
+ __name(spaceMailboxesFromItems, "spaceMailboxesFromItems");
3925
+ function buildGraphAttendees(event, targetMailbox) {
3926
+ const target = targetMailbox?.trim().toLowerCase();
3927
+ const seen = new Set(target ? [
3928
+ target
3929
+ ] : []);
3930
+ const attendees = [];
3931
+ const add = /* @__PURE__ */ __name((email, type) => {
3932
+ const key = email?.trim().toLowerCase();
3933
+ if (!key || seen.has(key)) {
3934
+ return;
3935
+ }
3936
+ seen.add(key);
3937
+ attendees.push({
3938
+ emailAddress: {
3939
+ address: email.trim()
3940
+ },
3941
+ type
3902
3942
  });
3943
+ }, "add");
3944
+ for (const email of [
3945
+ ...event.requestedForIds ?? [],
3946
+ ...event.recipientIds ?? []
3947
+ ]) {
3948
+ add(email, "required");
3903
3949
  }
3904
- const resourceId = options?.resourceId?.trim();
3905
- if (resourceId) {
3906
- const isAlreadyInvited = graph.attendees?.some((attendee) => attendee.emailAddress?.address?.toLowerCase() === resourceId.toLowerCase());
3907
- if (isAlreadyInvited !== true) {
3908
- graph.attendees = [
3909
- ...graph.attendees ?? [],
3910
- {
3911
- emailAddress: {
3912
- address: resourceId
3913
- },
3914
- type: GRAPH_RESOURCE_ATTENDEE_TYPE
3915
- }
3916
- ];
3917
- }
3950
+ for (const email of spaceMailboxesFromItems(event.items)) {
3951
+ add(email, GRAPH_RESOURCE_ATTENDEE_TYPE);
3918
3952
  }
3919
- return graph;
3953
+ return attendees;
3920
3954
  }
3921
- __name(toGraphEvent, "toGraphEvent");
3922
- function toGraphRecurrence(recurrence) {
3923
- return {
3924
- pattern: omitUndefined({
3925
- type: recurrence.pattern.type,
3926
- interval: recurrence.pattern.interval,
3927
- daysOfWeek: recurrence.pattern.daysOfWeek,
3928
- firstDayOfWeek: recurrence.pattern.firstDayOfWeek,
3929
- dayOfMonth: recurrence.pattern.dayOfMonth,
3930
- month: recurrence.pattern.month,
3931
- index: recurrence.pattern.index
3932
- }),
3933
- range: omitUndefined({
3934
- type: recurrence.range.type,
3935
- startDate: recurrence.range.startDate,
3936
- endDate: recurrence.range.endDate,
3937
- numberOfOccurrences: recurrence.range.numberOfOccurrences,
3938
- recurrenceTimeZone: recurrence.range.recurrenceTimeZone
3939
- })
3955
+ __name(buildGraphAttendees, "buildGraphAttendees");
3956
+ function scheduleToGraphRecurrence(schedule, window) {
3957
+ if (!window.startDate || !window.endDate) {
3958
+ return void 0;
3959
+ }
3960
+ const range = {
3961
+ type: "endDate",
3962
+ startDate: window.startDate,
3963
+ endDate: window.endDate
3940
3964
  };
3965
+ switch (schedule.repeat) {
3966
+ case models.SCHEDULE_REPEAT_TYPE.EVERY_DAY:
3967
+ return {
3968
+ pattern: {
3969
+ type: "daily",
3970
+ interval: 1
3971
+ },
3972
+ range
3973
+ };
3974
+ case models.SCHEDULE_REPEAT_TYPE.EVERY_WEEK:
3975
+ if (!schedule.daysOfWeek?.length) {
3976
+ return void 0;
3977
+ }
3978
+ return {
3979
+ pattern: {
3980
+ type: "weekly",
3981
+ interval: 1,
3982
+ daysOfWeek: schedule.daysOfWeek.map((day) => GRAPH_WEEKDAY[day])
3983
+ },
3984
+ range
3985
+ };
3986
+ case models.SCHEDULE_REPEAT_TYPE.EVERY_MONTH:
3987
+ if (schedule.datesOfMonth?.length === 1) {
3988
+ return {
3989
+ pattern: {
3990
+ type: "absoluteMonthly",
3991
+ interval: 1,
3992
+ dayOfMonth: schedule.datesOfMonth[0]
3993
+ },
3994
+ range
3995
+ };
3996
+ }
3997
+ if (schedule.monthlyUnit && schedule.daysOfWeek?.length) {
3998
+ return {
3999
+ pattern: {
4000
+ type: "relativeMonthly",
4001
+ interval: 1,
4002
+ daysOfWeek: schedule.daysOfWeek.map((day) => GRAPH_WEEKDAY[day]),
4003
+ index: GRAPH_MONTHLY_INDEX[schedule.monthlyUnit]
4004
+ },
4005
+ range
4006
+ };
4007
+ }
4008
+ return void 0;
4009
+ case models.SCHEDULE_REPEAT_TYPE.CUSTOM:
4010
+ default:
4011
+ return void 0;
4012
+ }
3941
4013
  }
3942
- __name(toGraphRecurrence, "toGraphRecurrence");
3943
- function fromGraphEvent(graph, options) {
3944
- const providerPayload = collectUnknownGraphFields(graph);
4014
+ __name(scheduleToGraphRecurrence, "scheduleToGraphRecurrence");
4015
+ function graphEventToRef(graph, options) {
3945
4016
  return {
3946
4017
  id: graph.id,
3947
- subject: graph.subject ?? "",
3948
- body: graph.body?.content,
3949
- start: graph.start ?? {
3950
- dateTime: "",
3951
- timeZone: ""
3952
- },
3953
- end: graph.end ?? {
3954
- dateTime: "",
3955
- timeZone: ""
3956
- },
3957
- location: graph.location?.displayName,
3958
- resourceId: options?.resourceId,
3959
- recurrence: graph.recurrence ? fromGraphRecurrence(graph.recurrence) : void 0,
3960
- attendees: graph.attendees?.filter((attendee) => Boolean(attendee.emailAddress?.address)).map((attendee) => ({
3961
- email: attendee.emailAddress?.address ?? "",
3962
- name: attendee.emailAddress?.name,
3963
- type: attendee.type
3964
- })),
3965
- organizerEmail: graph.organizer?.emailAddress?.address,
3966
- showAs: graph.showAs,
3967
- isCancelled: graph.isCancelled,
4018
+ seriesId: graph.seriesMasterId,
4019
+ instanceKind: graph.type ? GRAPH_TYPE_TO_INSTANCE_KIND[graph.type] : void 0,
3968
4020
  syncMetadata: omitUndefined({
3969
4021
  ...options?.syncMetadata,
3970
4022
  externalEventId: graph.id ?? options?.syncMetadata?.externalEventId,
3971
- // Event ids are mailbox-scoped — remember which mailbox can address this id.
3972
- // Left undefined when the room organizes; `resourceId` addresses the event then.
3973
4023
  organizerUserEmail: options?.organizerUserEmail ?? options?.syncMetadata?.organizerUserEmail,
3974
- resourceId: options?.resourceId ?? options?.syncMetadata?.resourceId
3975
- }),
3976
- providerPayload
3977
- };
3978
- }
3979
- __name(fromGraphEvent, "fromGraphEvent");
3980
- function fromGraphRecurrence(recurrence) {
3981
- return {
3982
- pattern: omitUndefined({
3983
- type: recurrence.pattern?.type ?? "",
3984
- interval: recurrence.pattern?.interval ?? 1,
3985
- daysOfWeek: recurrence.pattern?.daysOfWeek,
3986
- firstDayOfWeek: recurrence.pattern?.firstDayOfWeek,
3987
- dayOfMonth: recurrence.pattern?.dayOfMonth,
3988
- month: recurrence.pattern?.month,
3989
- index: recurrence.pattern?.index
3990
- }),
3991
- range: omitUndefined({
3992
- type: recurrence.range?.type ?? "",
3993
- startDate: recurrence.range?.startDate ?? "",
3994
- endDate: recurrence.range?.endDate,
3995
- numberOfOccurrences: recurrence.range?.numberOfOccurrences,
3996
- recurrenceTimeZone: recurrence.range?.recurrenceTimeZone
4024
+ resourceId: options?.resourceId ?? options?.syncMetadata?.resourceId,
4025
+ excludedDateResults: options?.excludedDateResults ?? options?.syncMetadata?.excludedDateResults
3997
4026
  })
3998
4027
  };
3999
4028
  }
4000
- __name(fromGraphRecurrence, "fromGraphRecurrence");
4029
+ __name(graphEventToRef, "graphEventToRef");
4030
+ function graphEventsToInstances(response) {
4031
+ return (response.value ?? []).filter((graph) => Boolean(graph.id && graph.start?.dateTime)).map((graph) => omitUndefined({
4032
+ id: graph.id,
4033
+ startDateLabel: graph.start.dateTime.slice(0, 10),
4034
+ seriesId: graph.seriesMasterId
4035
+ }));
4036
+ }
4037
+ __name(graphEventsToInstances, "graphEventsToInstances");
4038
+ function toGraphDateTime(dateLabel, timeLabel, isFullDay) {
4039
+ if (isFullDay || !timeLabel) {
4040
+ return `${dateLabel}T00:00:00`;
4041
+ }
4042
+ const parts = timeLabel.split(":");
4043
+ const hh = parts[0] ?? "00";
4044
+ const mm = parts[1] ?? "00";
4045
+ const ss = parts[2] ?? "00";
4046
+ return `${dateLabel}T${hh}:${mm}:${ss}`;
4047
+ }
4048
+ __name(toGraphDateTime, "toGraphDateTime");
4001
4049
  function omitUndefined(value) {
4002
4050
  return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== void 0));
4003
4051
  }
4004
4052
  __name(omitUndefined, "omitUndefined");
4005
- function collectUnknownGraphFields(graph) {
4006
- const extras = {};
4007
- for (const [key, value] of Object.entries(graph)) {
4008
- if (!GRAPH_EVENT_KNOWN_KEYS.has(key) && value !== void 0) {
4009
- extras[key] = value;
4010
- }
4011
- }
4012
- return Object.keys(extras).length > 0 ? extras : void 0;
4013
- }
4014
- __name(collectUnknownGraphFields, "collectUnknownGraphFields");
4015
4053
 
4016
4054
  // ../../packages/dvss-integration-microsoft/src/capabilities/booking-management/booking-management.service.ts
4017
4055
  function _ts_decorate28(decorators, target, key, desc2) {
@@ -4037,32 +4075,34 @@ exports.MicrosoftCalendarBookingService = class MicrosoftCalendarBookingService
4037
4075
  }
4038
4076
  async createEvent(request, integration, loggedInUserId) {
4039
4077
  try {
4040
- const mailboxEmail = this.resolveMailboxEmail(request);
4078
+ const organizerEmail = request.event.requestedForIds?.[0];
4079
+ const roomEmail = spaceMailboxesFromItems(request.event.items)[0];
4080
+ const mailboxEmail = this.pickMailbox(organizerEmail, roomEmail);
4081
+ this.assertMailbox(mailboxEmail);
4041
4082
  this.logger.info(loggedInUserId, this.createEvent.name, this.fileName, "Create Microsoft Graph calendar event", {
4042
4083
  mailboxEmail,
4043
- resourceId: request.resourceId,
4044
- subject: request.event.subject,
4084
+ subject: request.event.name,
4045
4085
  path: MICROSOFT_GRAPH_PATHS.userCalendarEvents(mailboxEmail)
4046
4086
  });
4047
- this.assertResourceId(request.resourceId);
4048
4087
  const graphEvent = await this.microsoftApiClient.apiCall({
4049
4088
  apiMethod: HTTP_METHOD.POST,
4050
4089
  url: MICROSOFT_GRAPH_PATHS.userCalendarEvents(mailboxEmail),
4051
4090
  body: toGraphEvent(request.event, {
4052
- resourceId: this.resourceAsAttendee(mailboxEmail, request.resourceId)
4091
+ targetMailbox: mailboxEmail
4053
4092
  })
4054
4093
  }, integration, loggedInUserId);
4055
- const mapped = fromGraphEvent(graphEvent, {
4056
- resourceId: request.resourceId,
4057
- organizerUserEmail: this.organizerUserMailbox(request),
4058
- syncMetadata: request.event.syncMetadata
4094
+ const excludedDateResults = await this.resolveSkipDatesIfAny(graphEvent.id, request.event.schedule?.skipDates, mailboxEmail, this.organizerUserMailbox(organizerEmail), integration, loggedInUserId);
4095
+ const ref = graphEventToRef(graphEvent, {
4096
+ organizerUserEmail: this.organizerUserMailbox(organizerEmail),
4097
+ resourceId: roomEmail,
4098
+ syncMetadata: request.event.syncMetadata,
4099
+ excludedDateResults
4059
4100
  });
4060
4101
  this.logger.info(loggedInUserId, this.createEvent.name, this.fileName, "Created Microsoft Graph calendar event", {
4061
- eventId: mapped.id,
4062
- mailboxEmail,
4063
- resourceId: request.resourceId
4102
+ eventId: ref.id,
4103
+ mailboxEmail
4064
4104
  });
4065
- return mapped;
4105
+ return ref;
4066
4106
  } catch (error) {
4067
4107
  this.logger.error(loggedInUserId, this.createEvent.name, this.fileName, "Error creating Microsoft Graph calendar event", error);
4068
4108
  throw error;
@@ -4070,31 +4110,33 @@ exports.MicrosoftCalendarBookingService = class MicrosoftCalendarBookingService
4070
4110
  }
4071
4111
  async updateEvent(request, integration, loggedInUserId) {
4072
4112
  try {
4073
- const mailboxEmail = this.resolveMailboxEmail(request);
4113
+ const mailboxEmail = this.pickMailbox(request.organizerUserEmail, request.resourceEmail);
4114
+ this.assertMailbox(mailboxEmail);
4115
+ this.assertEventId(request.eventId);
4074
4116
  this.logger.info(loggedInUserId, this.updateEvent.name, this.fileName, "Update Microsoft Graph calendar event", {
4075
4117
  mailboxEmail,
4076
- resourceId: request.resourceId,
4077
4118
  eventId: request.eventId,
4078
4119
  path: MICROSOFT_GRAPH_PATHS.userCalendarEvent(mailboxEmail, request.eventId)
4079
4120
  });
4080
- this.assertResourceId(request.resourceId);
4081
- this.assertEventId(request.eventId);
4082
4121
  const graphEvent = await this.microsoftApiClient.apiCall({
4083
4122
  apiMethod: HTTP_METHOD.PATCH,
4084
4123
  url: MICROSOFT_GRAPH_PATHS.userCalendarEvent(mailboxEmail, request.eventId),
4085
- body: toGraphEvent(request.event)
4124
+ body: toGraphEvent(request.event, {
4125
+ targetMailbox: mailboxEmail
4126
+ })
4086
4127
  }, integration, loggedInUserId);
4087
- const mapped = fromGraphEvent(graphEvent, {
4088
- resourceId: request.resourceId,
4089
- organizerUserEmail: this.organizerUserMailbox(request),
4090
- syncMetadata: request.event.syncMetadata
4128
+ const excludedDateResults = await this.resolveSkipDatesIfAny(graphEvent.id ?? request.eventId, request.event.schedule?.skipDates, mailboxEmail, this.organizerUserMailbox(request.organizerUserEmail), integration, loggedInUserId);
4129
+ const ref = graphEventToRef(graphEvent, {
4130
+ organizerUserEmail: this.organizerUserMailbox(request.organizerUserEmail),
4131
+ resourceId: request.resourceEmail,
4132
+ syncMetadata: request.event.syncMetadata,
4133
+ excludedDateResults
4091
4134
  });
4092
4135
  this.logger.info(loggedInUserId, this.updateEvent.name, this.fileName, "Updated Microsoft Graph calendar event", {
4093
- eventId: mapped.id,
4094
- mailboxEmail,
4095
- resourceId: request.resourceId
4136
+ eventId: ref.id,
4137
+ mailboxEmail
4096
4138
  });
4097
- return mapped;
4139
+ return ref;
4098
4140
  } catch (error) {
4099
4141
  this.logger.error(loggedInUserId, this.updateEvent.name, this.fileName, "Error updating Microsoft Graph calendar event", error);
4100
4142
  throw error;
@@ -4102,19 +4144,12 @@ exports.MicrosoftCalendarBookingService = class MicrosoftCalendarBookingService
4102
4144
  }
4103
4145
  async cancelEvent(request, integration, loggedInUserId) {
4104
4146
  try {
4105
- const mailboxEmail = this.resolveMailboxEmail(request);
4147
+ const mailboxEmail = this.pickMailbox(request.organizerUserEmail, request.resourceEmail);
4106
4148
  this.logger.info(loggedInUserId, this.cancelEvent.name, this.fileName, "Cancel Microsoft Graph calendar event", {
4107
4149
  mailboxEmail,
4108
- resourceId: request.resourceId,
4109
- eventId: request.eventId,
4110
- path: MICROSOFT_GRAPH_PATHS.userCalendarEvent(mailboxEmail, request.eventId)
4111
- });
4112
- await this.deleteGraphEvent(mailboxEmail, request.resourceId, request.eventId, integration, loggedInUserId);
4113
- this.logger.info(loggedInUserId, this.cancelEvent.name, this.fileName, "Cancelled Microsoft Graph calendar event", {
4114
- eventId: request.eventId,
4115
- mailboxEmail,
4116
- resourceId: request.resourceId
4150
+ eventId: request.eventId
4117
4151
  });
4152
+ await this.deleteGraphEvent(mailboxEmail, request.eventId, integration, loggedInUserId);
4118
4153
  } catch (error) {
4119
4154
  this.logger.error(loggedInUserId, this.cancelEvent.name, this.fileName, "Error cancelling Microsoft Graph calendar event", error);
4120
4155
  throw error;
@@ -4122,76 +4157,35 @@ exports.MicrosoftCalendarBookingService = class MicrosoftCalendarBookingService
4122
4157
  }
4123
4158
  async deleteEvent(request, integration, loggedInUserId) {
4124
4159
  try {
4125
- const mailboxEmail = this.resolveMailboxEmail(request);
4160
+ const mailboxEmail = this.pickMailbox(request.organizerUserEmail, request.resourceEmail);
4126
4161
  this.logger.info(loggedInUserId, this.deleteEvent.name, this.fileName, "Delete Microsoft Graph calendar event", {
4127
4162
  mailboxEmail,
4128
- resourceId: request.resourceId,
4129
- eventId: request.eventId,
4130
- path: MICROSOFT_GRAPH_PATHS.userCalendarEvent(mailboxEmail, request.eventId)
4131
- });
4132
- await this.deleteGraphEvent(mailboxEmail, request.resourceId, request.eventId, integration, loggedInUserId);
4133
- this.logger.info(loggedInUserId, this.deleteEvent.name, this.fileName, "Deleted Microsoft Graph calendar event", {
4134
- eventId: request.eventId,
4135
- mailboxEmail,
4136
- resourceId: request.resourceId
4163
+ eventId: request.eventId
4137
4164
  });
4165
+ await this.deleteGraphEvent(mailboxEmail, request.eventId, integration, loggedInUserId);
4138
4166
  } catch (error) {
4139
4167
  this.logger.error(loggedInUserId, this.deleteEvent.name, this.fileName, "Error deleting Microsoft Graph calendar event", error);
4140
4168
  throw error;
4141
4169
  }
4142
4170
  }
4143
- async getEvent(request, integration, loggedInUserId) {
4144
- try {
4145
- const mailboxEmail = this.resolveMailboxEmail(request);
4146
- this.logger.info(loggedInUserId, this.getEvent.name, this.fileName, "Get Microsoft Graph calendar event", {
4147
- mailboxEmail,
4148
- resourceId: request.resourceId,
4149
- eventId: request.eventId,
4150
- path: MICROSOFT_GRAPH_PATHS.userCalendarEvent(mailboxEmail, request.eventId)
4151
- });
4152
- this.assertResourceId(request.resourceId);
4153
- this.assertEventId(request.eventId);
4154
- const graphEvent = await this.microsoftApiClient.apiCall({
4155
- apiMethod: HTTP_METHOD.GET,
4156
- url: MICROSOFT_GRAPH_PATHS.userCalendarEvent(mailboxEmail, request.eventId)
4157
- }, integration, loggedInUserId);
4158
- const mapped = fromGraphEvent(graphEvent, {
4159
- resourceId: request.resourceId,
4160
- organizerUserEmail: this.organizerUserMailbox(request)
4161
- });
4162
- this.logger.info(loggedInUserId, this.getEvent.name, this.fileName, "Fetched Microsoft Graph calendar event", {
4163
- eventId: mapped.id,
4164
- mailboxEmail,
4165
- resourceId: request.resourceId
4166
- });
4167
- return mapped;
4168
- } catch (error) {
4169
- this.logger.error(loggedInUserId, this.getEvent.name, this.fileName, "Error fetching Microsoft Graph calendar event", error);
4170
- throw error;
4171
- }
4172
- }
4173
4171
  async getEvents(request, integration, loggedInUserId) {
4174
4172
  try {
4175
- this.assertResourceId(request.resourceId);
4176
- const mailboxEmail = this.resolveMailboxEmail(request);
4177
- const url = request.start && request.end ? MICROSOFT_GRAPH_PATHS.userCalendarView(mailboxEmail, request.start.dateTime, request.end.dateTime) : MICROSOFT_GRAPH_PATHS.userCalendarEvents(mailboxEmail);
4173
+ const mailboxEmail = this.pickMailbox(request.organizerUserEmail, request.resourceEmail);
4174
+ this.assertMailbox(mailboxEmail);
4175
+ const hasWindow = Boolean(request.startDateLabel && request.endDateLabel);
4176
+ const url = hasWindow ? MICROSOFT_GRAPH_PATHS.userCalendarView(mailboxEmail, `${request.startDateLabel}T00:00:00`, `${request.endDateLabel}T23:59:59`) : MICROSOFT_GRAPH_PATHS.userCalendarEvents(mailboxEmail);
4178
4177
  this.logger.info(loggedInUserId, this.getEvents.name, this.fileName, "List Microsoft Graph calendar events", {
4179
4178
  mailboxEmail,
4180
- resourceId: request.resourceId,
4181
4179
  path: url,
4182
- hasTimeWindow: Boolean(request.start && request.end)
4180
+ hasTimeWindow: hasWindow
4183
4181
  });
4184
4182
  const response = await this.microsoftApiClient.apiCall({
4185
4183
  apiMethod: HTTP_METHOD.GET,
4186
4184
  url
4187
4185
  }, integration, loggedInUserId);
4188
- const events = (response.value ?? []).map((graphEvent) => fromGraphEvent(graphEvent, {
4189
- resourceId: request.resourceId,
4190
- organizerUserEmail: this.organizerUserMailbox(request)
4191
- }));
4186
+ const events = graphEventsToInstances(response);
4192
4187
  this.logger.info(loggedInUserId, this.getEvents.name, this.fileName, "Listed Microsoft Graph calendar events", {
4193
4188
  mailboxEmail,
4194
- resourceId: request.resourceId,
4195
4189
  count: events.length
4196
4190
  });
4197
4191
  return {
@@ -4202,16 +4196,8 @@ exports.MicrosoftCalendarBookingService = class MicrosoftCalendarBookingService
4202
4196
  throw error;
4203
4197
  }
4204
4198
  }
4205
- syncEvents(request, integration, loggedInUserId) {
4206
- this.logger.info(loggedInUserId, this.syncEvents.name, this.fileName, "Sync Microsoft Graph calendar events (delta)", {
4207
- resourceId: request.resourceId,
4208
- hasSyncToken: Boolean(request.syncToken)
4209
- });
4210
- void this.microsoftApiClient;
4211
- return Promise.reject(new common.NotImplementedException("MicrosoftCalendarBookingService.syncEvents is not implemented yet"));
4212
- }
4213
- async deleteGraphEvent(mailboxEmail, resourceId, eventId, integration, loggedInUserId) {
4214
- this.assertResourceId(resourceId);
4199
+ async deleteGraphEvent(mailboxEmail, eventId, integration, loggedInUserId) {
4200
+ this.assertMailbox(mailboxEmail);
4215
4201
  this.assertEventId(eventId);
4216
4202
  await this.microsoftApiClient.apiCall({
4217
4203
  apiMethod: HTTP_METHOD.DELETE,
@@ -4219,30 +4205,74 @@ exports.MicrosoftCalendarBookingService = class MicrosoftCalendarBookingService
4219
4205
  }, integration, loggedInUserId);
4220
4206
  }
4221
4207
  /**
4222
- * Mailbox the Graph call targets: the organizing user when one is known, otherwise the
4223
- * resource mailbox, which keeps the room-organizes behaviour for callers that cannot
4224
- * resolve a user. The return value is therefore a user *or* a resource mailbox — never
4225
- * store it as `organizerUserEmail`; use `organizerUserMailbox` for that.
4208
+ * Graph always creates/updates a recurring series whole. For each date in
4209
+ * `schedule.skipDates` this finds the occurrence instance in the series just
4210
+ * created/updated and cancels it via the existing DELETE path. Best-effort per date — a
4211
+ * date that can't be resolved is reported `excluded: false`, not thrown.
4226
4212
  */
4227
- resolveMailboxEmail(request) {
4228
- return this.organizerUserMailbox(request) ?? request.resourceId;
4213
+ async resolveSkipDatesIfAny(seriesId, dates, mailboxEmail, organizerUserEmail, integration, loggedInUserId) {
4214
+ if (!dates?.length) {
4215
+ return void 0;
4216
+ }
4217
+ const results = [];
4218
+ for (const date of dates) {
4219
+ try {
4220
+ const instanceId = await this.findOccurrenceInstanceId(seriesId, date, mailboxEmail, integration, loggedInUserId);
4221
+ if (!instanceId) {
4222
+ this.logger.warn(loggedInUserId, this.resolveSkipDatesIfAny.name, this.fileName, "Could not resolve skip-date occurrence", {
4223
+ seriesId,
4224
+ date,
4225
+ mailboxEmail
4226
+ });
4227
+ results.push({
4228
+ date,
4229
+ excluded: false
4230
+ });
4231
+ continue;
4232
+ }
4233
+ await this.cancelEvent({
4234
+ eventId: instanceId,
4235
+ resourceEmail: mailboxEmail,
4236
+ organizerUserEmail
4237
+ }, integration, loggedInUserId);
4238
+ results.push({
4239
+ date,
4240
+ eventId: instanceId,
4241
+ excluded: true
4242
+ });
4243
+ } catch (error) {
4244
+ this.logger.warn(loggedInUserId, this.resolveSkipDatesIfAny.name, this.fileName, "Failed to cancel skip-date occurrence", {
4245
+ seriesId,
4246
+ date,
4247
+ mailboxEmail,
4248
+ error: error instanceof Error ? error.message : String(error)
4249
+ });
4250
+ results.push({
4251
+ date,
4252
+ excluded: false
4253
+ });
4254
+ }
4255
+ }
4256
+ return results;
4229
4257
  }
4230
- /**
4231
- * The organizing user's mailbox, or undefined when the room ends up organizing.
4232
- */
4233
- organizerUserMailbox(request) {
4234
- return request.organizerUserEmail?.trim() || void 0;
4258
+ async findOccurrenceInstanceId(seriesId, date, mailboxEmail, integration, loggedInUserId) {
4259
+ const response = await this.microsoftApiClient.apiCall({
4260
+ apiMethod: HTTP_METHOD.GET,
4261
+ url: MICROSOFT_GRAPH_PATHS.userCalendarView(mailboxEmail, `${date}T00:00:00`, `${date}T23:59:59`)
4262
+ }, integration, loggedInUserId);
4263
+ return (response.value ?? []).find((occurrence) => occurrence.seriesMasterId === seriesId)?.id;
4235
4264
  }
4236
- /**
4237
- * The room only needs to be invited as an attendee when the event lives in someone
4238
- * else's mailbox. Posting into the room's own calendar already books it.
4239
- */
4240
- resourceAsAttendee(mailboxEmail, resourceId) {
4241
- return mailboxEmail.trim().toLowerCase() === resourceId.trim().toLowerCase() ? void 0 : resourceId;
4265
+ /** Mailbox the Graph call targets: the organizing user if known, else the room. */
4266
+ pickMailbox(organizerEmail, roomEmail) {
4267
+ return this.organizerUserMailbox(organizerEmail) ?? roomEmail?.trim() ?? "";
4242
4268
  }
4243
- assertResourceId(resourceId) {
4244
- if (!resourceId?.trim()) {
4245
- throw new dvssBackendModuleUtility.CustomException("BAD_REQUEST", "resourceId is required");
4269
+ /** The organizing user's mailbox, or undefined when the room ends up organizing. */
4270
+ organizerUserMailbox(organizerEmail) {
4271
+ return organizerEmail?.trim() || void 0;
4272
+ }
4273
+ assertMailbox(mailboxEmail) {
4274
+ if (!mailboxEmail?.trim()) {
4275
+ throw new dvssBackendModuleUtility.CustomException("BAD_REQUEST", "a requested-for or resource mailbox is required");
4246
4276
  }
4247
4277
  }
4248
4278
  assertEventId(eventId) {
@@ -4788,15 +4818,9 @@ exports.MicrosoftCalendarBookingHandler = class MicrosoftCalendarBookingHandler
4788
4818
  async deleteCalendarBooking(request, integration, loggedInUserId) {
4789
4819
  return this.microsoftCalendarBookingService.deleteEvent(request, integration, loggedInUserId);
4790
4820
  }
4791
- async getCalendarBooking(request, integration, loggedInUserId) {
4792
- return this.microsoftCalendarBookingService.getEvent(request, integration, loggedInUserId);
4793
- }
4794
4821
  async getCalendarBookings(request, integration, loggedInUserId) {
4795
4822
  return this.microsoftCalendarBookingService.getEvents(request, integration, loggedInUserId);
4796
4823
  }
4797
- async syncCalendarBookings(request, integration, loggedInUserId) {
4798
- return this.microsoftCalendarBookingService.syncEvents(request, integration, loggedInUserId);
4799
- }
4800
4824
  };
4801
4825
  exports.MicrosoftCalendarBookingHandler = _ts_decorate36([
4802
4826
  common.Injectable(),
@@ -5112,6 +5136,30 @@ exports.CalendarIntegrationManager = _ts_decorate44([
5112
5136
  })
5113
5137
  ], exports.CalendarIntegrationManager);
5114
5138
 
5139
+ Object.defineProperty(exports, "BEHAVIOUR_TYPE_ENUM", {
5140
+ enumerable: true,
5141
+ get: function () { return models.BEHAVIOUR_TYPE_ENUM; }
5142
+ });
5143
+ Object.defineProperty(exports, "DAY_OF_WEEK", {
5144
+ enumerable: true,
5145
+ get: function () { return models.DAY_OF_WEEK; }
5146
+ });
5147
+ Object.defineProperty(exports, "OFFERING_BOOKING_TIME_TYPE", {
5148
+ enumerable: true,
5149
+ get: function () { return models.OFFERING_BOOKING_TIME_TYPE; }
5150
+ });
5151
+ Object.defineProperty(exports, "OFFERING_BOOKING_TYPE_ENUM", {
5152
+ enumerable: true,
5153
+ get: function () { return models.OFFERING_BOOKING_TYPE_ENUM; }
5154
+ });
5155
+ Object.defineProperty(exports, "SCHEDULE_MONTHLY_UNIT", {
5156
+ enumerable: true,
5157
+ get: function () { return models.SCHEDULE_MONTHLY_UNIT; }
5158
+ });
5159
+ Object.defineProperty(exports, "SCHEDULE_REPEAT_TYPE", {
5160
+ enumerable: true,
5161
+ get: function () { return models.SCHEDULE_REPEAT_TYPE; }
5162
+ });
5115
5163
  exports.BOOKABLE_ITEM_STATUS_ENUM = BOOKABLE_ITEM_STATUS_ENUM;
5116
5164
  exports.BOOKABLE_ITEM_TYPE_ENUM = BOOKABLE_ITEM_TYPE_ENUM;
5117
5165
  exports.BaseAccessManagement = BaseAccessManagement;
@@ -5144,6 +5192,7 @@ exports.CREDIT_STATUS_ENUM = CREDIT_STATUS_ENUM;
5144
5192
  exports.CREDIT_TYPE_ENUM = CREDIT_TYPE_ENUM;
5145
5193
  exports.DOWNLOAD_CUSTOMER_ACCOUNTING_STATEMENT_FILTER_BY_ENUM = DOWNLOAD_CUSTOMER_ACCOUNTING_STATEMENT_FILTER_BY_ENUM;
5146
5194
  exports.DOWNLOAD_CUSTOMER_ACCOUNTING_STATEMENT_STATUS_ENUM = DOWNLOAD_CUSTOMER_ACCOUNTING_STATEMENT_STATUS_ENUM;
5195
+ exports.EVENT_INSTANCE_KIND = EVENT_INSTANCE_KIND;
5147
5196
  exports.GET_CUSTOMER_CREDIT_NOTES_FILTER_BY = GET_CUSTOMER_CREDIT_NOTES_FILTER_BY;
5148
5197
  exports.GET_CUSTOMER_CREDIT_NOTES_SORT_BY = GET_CUSTOMER_CREDIT_NOTES_SORT_BY;
5149
5198
  exports.GET_INVOICES_FILTER_BY_ENUM = GET_INVOICES_FILTER_BY_ENUM;