* feat: add 5 new workflow triggers for booking events
- Add BOOKING_REJECTED, BOOKING_REQUESTED, BOOKING_PAYMENT_INITIATED, BOOKING_PAID, BOOKING_NO_SHOW_UPDATED to WorkflowTriggerEvents enum
- Update workflow constants to include new trigger options
- Implement workflow trigger logic for booking rejected and requested events
- Add translations for new workflow triggers following {enum}_trigger format
- Generate updated Prisma types for new schema changes
Co-Authored-By: amit@cal.com <samit91848@gmail.com>
* fix: type check, remove as any
* feat: add workflow trigger for BOOKING_REQUESTED in handleNewBooking.ts
- Add WorkflowTriggerEvents import to handleNewBooking.ts
- Implement workflow trigger logic for BOOKING_REQUESTED in else block
- Filter workflows by BOOKING_REQUESTED trigger and call scheduleWorkflowReminders
- Use proper calendar event object construction without type casting
- Add error handling for workflow reminder scheduling
Co-Authored-By: amit@cal.com <samit91848@gmail.com>
* fix: resolve type errors in workflow trigger implementations
- Add proper database includes for user information in handleConfirmation.ts
- Fix ExtendedCalendarEvent type structure with correct hosts mapping
- Add missing properties to calendar event objects in handleMarkNoShow.ts
- Ensure all workflow triggers follow proper type patterns
Co-Authored-By: amit@cal.com <samit91848@gmail.com>
* feat: add workflow test configurations for new booking triggers
- Add workflow configurations for BOOKING_REQUESTED and BOOKING_PAYMENT_INITIATED in fresh-booking.test.ts
- Add workflow configuration for BOOKING_REJECTED in confirm.handler.test.ts
- Enable previously skipped confirm.handler.test.ts
- Remove workflow test assertions temporarily until triggers are fully functional
- Maintain webhook test coverage while adding workflow test infrastructure
Co-Authored-By: amit@cal.com <samit91848@gmail.com>
* fix: add missing mockSuccessfulVideoMeetingCreation import to confirm.handler.test.ts
- Import mockSuccessfulVideoMeetingCreation from bookingScenario utils
- Add mock call to BOOKING_REJECTED workflow test case
- Resolves ReferenceError that was causing unit test CI failure
Co-Authored-By: amit@cal.com <samit91848@gmail.com>
* refactor: improve _scheduleWorkflowReminders readability and add missing booking trigger events
- Extract complex conditional logic into helper functions (isImmediateTrigger, isTimeBased, shouldProcessWorkflow)
- Add missing workflow trigger events with immediate execution logic
- Update test workflows to use different actions (EMAIL_ATTENDEE, SMS_ATTENDEE) for better differentiation
- Fix translation function mock in confirm.handler.test.ts using mockNoTranslations utility
- Maintain existing functionality while improving code maintainability
Co-Authored-By: amit@cal.com <samit91848@gmail.com>
* filter outside scheduleWorkflowReminder
* fix type check
* chore: add more tests
* test: add comprehensive unit tests for handleMarkNoShow with webhook and workflow coverage
- Create handleMarkNoShow.test.ts following confirm.handler.test.ts pattern
- Add expectBookingNoShowUpdatedWebhookToHaveBeenFired utility function
- Test both webhook and workflow triggers for BOOKING_NO_SHOW_UPDATED
- Cover attendee/host no-show scenarios, multiple attendees, and error cases
- All 6 unit tests pass with proper mocking of external dependencies
Co-Authored-By: amit@cal.com <samit91848@gmail.com>
* Revert "test: add comprehensive unit tests for handleMarkNoShow with webhook and workflow coverage"
This reverts commit 764299220279f0c012392dec24d3150246bfc4ad.
* fix: add new workflow triggers to api/v2
* update swagger docs
* fix: e2e
* fix type check
* fix tests, add test for before after events
* fix unit tests
* revert confirm.handler.test
* fix: unit tests
* review fixes
* refactor WorkflowService
* remove logs
* remove unused
* fix: type check
* fix: missed before after events for recurring
* fix: calendarEvent handleMarkNoShow
* fix error message
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* review fixes
* add missing BOOKING_PAID workflow trigger
* fix pathname
* fix: test for BOOKING_REQUESTED
* review fixes
* Update packages/features/bookings/lib/handleSeats/handleSeats.ts
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com>
132 lines
4.0 KiB
TypeScript
132 lines
4.0 KiB
TypeScript
import type { ScheduleWorkflowRemindersArgs } from "@calcom/ee/workflows/lib/reminders/reminderScheduler";
|
|
import { scheduleWorkflowReminders } from "@calcom/ee/workflows/lib/reminders/reminderScheduler";
|
|
import type { Workflow } from "@calcom/ee/workflows/lib/types";
|
|
import { prisma } from "@calcom/prisma";
|
|
import { WorkflowTriggerEvents } from "@calcom/prisma/enums";
|
|
|
|
import { WorkflowRepository } from "../repository/workflow";
|
|
|
|
// TODO (Sean): Move most of the logic migrated in 16861 to this service
|
|
export class WorkflowService {
|
|
static _beforeAfterEventTriggers: WorkflowTriggerEvents[] = [
|
|
WorkflowTriggerEvents.AFTER_EVENT,
|
|
WorkflowTriggerEvents.BEFORE_EVENT,
|
|
];
|
|
static async deleteWorkflowRemindersOfRemovedTeam(teamId: number) {
|
|
const team = await prisma.team.findUnique({
|
|
where: {
|
|
id: teamId,
|
|
},
|
|
});
|
|
|
|
if (team?.parentId) {
|
|
const activeWorkflowsOnTeam = await prisma.workflow.findMany({
|
|
where: {
|
|
teamId: team.parentId,
|
|
OR: [
|
|
{
|
|
activeOnTeams: {
|
|
some: {
|
|
teamId: team.id,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
isActiveOnAll: true,
|
|
},
|
|
],
|
|
},
|
|
select: {
|
|
steps: true,
|
|
activeOnTeams: true,
|
|
isActiveOnAll: true,
|
|
},
|
|
});
|
|
|
|
for (const workflow of activeWorkflowsOnTeam) {
|
|
const workflowSteps = workflow.steps;
|
|
let remainingActiveOnIds = [];
|
|
|
|
if (workflow.isActiveOnAll) {
|
|
const allRemainingOrgTeams = await prisma.team.findMany({
|
|
where: {
|
|
parentId: team.parentId,
|
|
id: {
|
|
not: team.id,
|
|
},
|
|
},
|
|
});
|
|
remainingActiveOnIds = allRemainingOrgTeams.map((team) => team.id);
|
|
} else {
|
|
remainingActiveOnIds = workflow.activeOnTeams
|
|
.filter((activeOn) => activeOn.teamId !== team.id)
|
|
.map((activeOn) => activeOn.teamId);
|
|
}
|
|
const remindersToDelete = await WorkflowRepository.getRemindersFromRemovedTeams(
|
|
[team.id],
|
|
workflowSteps,
|
|
remainingActiveOnIds
|
|
);
|
|
await WorkflowRepository.deleteAllWorkflowReminders(remindersToDelete);
|
|
}
|
|
}
|
|
}
|
|
|
|
static async scheduleWorkflowsForNewBooking({
|
|
isNormalBookingOrFirstRecurringSlot,
|
|
isConfirmedByDefault,
|
|
isRescheduleEvent,
|
|
workflows,
|
|
...args
|
|
}: ScheduleWorkflowRemindersArgs & {
|
|
isConfirmedByDefault: boolean;
|
|
isRescheduleEvent: boolean;
|
|
isNormalBookingOrFirstRecurringSlot: boolean;
|
|
}) {
|
|
if (workflows.length <= 0) return;
|
|
|
|
const workflowsToTrigger: Workflow[] = [];
|
|
|
|
if (isRescheduleEvent) {
|
|
workflowsToTrigger.push(
|
|
...workflows.filter(
|
|
(workflow) =>
|
|
workflow.trigger === WorkflowTriggerEvents.RESCHEDULE_EVENT ||
|
|
this._beforeAfterEventTriggers.includes(workflow.trigger)
|
|
)
|
|
);
|
|
} else if (!isConfirmedByDefault) {
|
|
workflowsToTrigger.push(
|
|
...workflows.filter((workflow) => workflow.trigger === WorkflowTriggerEvents.BOOKING_REQUESTED)
|
|
);
|
|
} else if (isConfirmedByDefault) {
|
|
workflowsToTrigger.push(
|
|
...workflows.filter(
|
|
(workflow) =>
|
|
this._beforeAfterEventTriggers.includes(workflow.trigger) ||
|
|
(isNormalBookingOrFirstRecurringSlot && workflow.trigger === WorkflowTriggerEvents.NEW_EVENT)
|
|
)
|
|
);
|
|
}
|
|
|
|
if (workflowsToTrigger.length === 0) return;
|
|
|
|
await scheduleWorkflowReminders({
|
|
...args,
|
|
workflows: workflowsToTrigger,
|
|
});
|
|
}
|
|
|
|
static async scheduleWorkflowsFilteredByTriggerEvent({
|
|
workflows,
|
|
triggers,
|
|
...args
|
|
}: ScheduleWorkflowRemindersArgs & { triggers: WorkflowTriggerEvents[] }) {
|
|
if (workflows.length <= 0) return;
|
|
await scheduleWorkflowReminders({
|
|
...args,
|
|
workflows: workflows.filter((workflow) => triggers.includes(workflow.trigger)),
|
|
});
|
|
}
|
|
}
|