100 Commits
Author SHA1 Message Date
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Udit Takkar
b539adf47b perf: add paginated host endpoints and repository methods for large teams (#28156)
* perf: add paginated host endpoints and delta-based host updates for event type editor

- New cursor-paginated tRPC endpoints: getHostsForAssignment, getHostsForAvailability, searchTeamMembers, getChildrenForAssignment, exportHostsForWeights, getHostsWithLocationOptions
- Delta-based host update support in update.handler.ts (pendingHostChanges, pendingChildrenChanges)
- Repository additions: EventTypeRepository.findChildrenByParentId, HostRepository pagination, MembershipRepository.searchMembers, UserRepository.findByIdsWithPagination
- Remove teamMembers from getEventTypeById initial load
- Shared types: PendingHostChangesInput, PendingChildrenChangesInput, HostUpdateInput

Co-Authored-By: unknown <>

* fix: revert getTranslation import path to @calcom/i18n/server

Co-Authored-By: unknown <>

* fix: guard findChildrenByParentId to only run when pendingChildrenChanges exists

Co-Authored-By: unknown <>

* refactor: remove delta-based saving logic from backend PR

Move pendingHostChanges/pendingChildrenChanges processing out of backend PR.
These changes belong in the frontend PR since they are tightly coupled
to the new frontend delta tracking components.

Backend PR now contains only read-side optimizations:
- Paginated host/children/member endpoints
- Repository methods
- getEventTypeById optimizations

Co-Authored-By: unknown <>

* refactor: move getEventTypeById changes to frontend PR for type safety

Reverts getEventTypeById.ts, eventTypeRepository.ts, API v2 atom service,
and platform libraries to main. The backend PR now only adds new
infrastructure (paginated endpoints, repository methods, findChildrenByParentId)
without changing existing return types. The getEventTypeById optimizations
will be in the frontend PR instead.

Co-Authored-By: unknown <>

* refactor: move findTeamMembersMatchingAttributeLogic pagination to frontend PR

The handler's return type change (adding nextCursor/total) breaks frontend
files on main that expect the old shape. Moving these changes to the
frontend PR keeps the backend PR purely additive.

Co-Authored-By: unknown <>

* fix: address Cubic review comments - empty array filter, stable total count, Set lookup

Co-Authored-By: [email protected] <[email protected]>

* Fix inifnite pagination loop

Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix: derive teamId from event type to prevent cross-team enumeration in exportHostsForWeights

Co-Authored-By: [email protected] <[email protected]>

* fix: restore doc comment to correct method hasAnyTeamMembershipByUserId

Co-Authored-By: [email protected] <[email protected]>

* fix: use memberUserIds?.length to handle empty array filter in findHostsForAssignmentPaginated

Co-Authored-By: [email protected] <[email protected]>

* fix: use explicit undefined check for memberUserIds to preserve empty array semantics

Co-Authored-By: [email protected] <[email protected]>

* refactor: rename findChildrenByParentId to findChildrenByParentIdIncludeOwner

The method selects owner with user profile data, so the name should
reflect the included relation per Cal.com repository naming conventions.

Co-Authored-By: [email protected] <[email protected]>

* refactor: rename host repository methods to follow naming conventions

- findHostsForAvailabilityPaginated -> findHostsPaginatedIncludeUser
- findHostsForAssignmentPaginated -> findHostsPaginatedIncludeUserForAssignment

Repository methods should not be named after use-cases (Availability/Assignment)
but should describe what data they include, per Cal.com conventions.

Co-Authored-By: [email protected] <[email protected]>

* refactor: standardize slice(0, limit) across all pagination methods

Replace slice(0, -1) with slice(0, limit) in all HostRepository
pagination methods for consistency. slice(0, limit) is clearer about
intent since it directly references the limit parameter.

Co-Authored-By: [email protected] <[email protected]>

* perf: only run total count query on first page in findByIdsWithPagination

Wrap the count query in a !cursor guard so it only runs on the first
page request, avoiding an extra database query on every scroll.
Consistent with the hasFixedHosts optimization in HostRepository.

Co-Authored-By: [email protected] <[email protected]>

* test: add integration tests for paginated host endpoints

Tests cover getHostsForAvailability and getHostsForAssignment handlers:
- Basic host retrieval
- Cursor-based pagination across multiple pages
- Host data fields (isFixed, priority, weight, name, email)
- Search filtering by name
- memberUserIds filtering (including empty array returning zero results)
- hasFixedHosts only present on first page

Co-Authored-By: [email protected] <[email protected]>

* refactor: extract EventTypeHostService and make TRPC handlers thin

- Create EventTypeHostService at packages/features/host/services/ with all
  DTO types and business logic for 5 event-type-host endpoints
- Refactor all 5 handlers to delegate to the service (thin handlers)
- Add 17 unit tests covering DTO mapping, authorization, segment filtering,
  default values, and pagination pass-through

Co-Authored-By: [email protected] <[email protected]>

* docs: add PR review context comments to EventTypeHostService

Reference key review decisions from PR #28156 as code comments:
- searchTeamMembers: membership check + repository delegation per @eunjae-lee
- exportHostsForWeights: cross-team enumeration security fix per @hariombalhara
- exportHostsForWeights: repository method instead of direct Prisma per @hariombalhara

Co-Authored-By: [email protected] <[email protected]>

* Revert "docs: add PR review context comments to EventTypeHostService"

This reverts commit 1a1596e012.

* fix: use explicit undefined/null check for memberUserIds in searchMembers

Fixes empty array semantics so memberUserIds: [] correctly returns zero
results instead of all members. Now consistent with HostRepository pattern
which uses 'memberUserIds !== undefined' instead of 'memberUserIds?.length'.

Co-Authored-By: [email protected] <[email protected]>

* refactor: replace TRPCError with ErrorWithCode in EventTypeHostService

Per AGENTS.md rules, services in packages/features/ should use
ErrorWithCode instead of TRPCError. The errorConversionMiddleware
will automatically convert it to the appropriate TRPCError at the
router layer.

Co-Authored-By: [email protected] <[email protected]>

* Remove comment

Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix: remove unused teamId from exportHostsForWeights schema

teamId was originally accepted by the schema when the handler used it
directly. After the security fix to derive teamId server-side from the
event type, the field became dead code. Removing it to keep the API
contract accurate.

Co-Authored-By: [email protected] <[email protected]>

* Abstract types

* Update imports

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Udit Takkar <[email protected]>
2026-03-09 11:28:33 -04:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Claude Opus 4.5
48cbb94af2 feat: add webhook trigger when routing form fallback route is hit (#27588)
* feat: add no users found fallback action for routing forms

- Add NoUsersFoundFallbackActionType enum with CustomPageMessage and ExternalRedirectUrl options
- Add noUsersFoundFallbackAction field to zodNonRouterRoute schema
- Add NoUsersFoundFallback UI component in RouteBuilder for configuring fallback action
- Update handleResponse to return noUsersFoundFallbackAction when no team members match
- Add i18n translation keys for new UI strings

Co-Authored-By: [email protected] <[email protected]>

* refactor: change fallback to use same action options as main route

- Replace noUsersFoundFallbackAction with fallbackAction that has same structure as main action
- Add action dropdown and input fields to fallback attributes query builder section
- Support Event redirect, External URL, and Custom page options in fallback
- Remove separate NoUsersFoundFallback toggle component
- Update handleResponse to return fallbackAction

Co-Authored-By: [email protected] <[email protected]>

* fix: ensure fallbackAction type is always defined in onChange handlers

Co-Authored-By: [email protected] <[email protected]>

* fix: add guards for route.fallbackAction in onChange handlers

Co-Authored-By: [email protected] <[email protected]>

* fix: only return fallbackAction when no users are found

Co-Authored-By: [email protected] <[email protected]>

* refactor: restructure fallback section to mirror main route structure

Co-Authored-By: [email protected] <[email protected]>

* fix: ensure backwards compatibility for existing routes with fallbackAttributesQueryValue

Co-Authored-By: [email protected] <[email protected]>

* fix: initialize fallbackAction with main event type for backwards compatibility

Co-Authored-By: [email protected] <[email protected]>

* fix: include fallbackAction in getRoutesToSave to persist changes

Co-Authored-By: [email protected] <[email protected]>

* fix: use fallbackAction in getRoutedUrl when no team members found

Co-Authored-By: [email protected] <[email protected]>

* fix: use i18n for fallback label and add tests for fallback action

Co-Authored-By: [email protected] <[email protected]>

* fix: do not trigger fallback action when CRM contact owner is found

Co-Authored-By: [email protected] <[email protected]>

* fix: prioritize fallbackAction over fallbackAttributesQueryValue

When a route has a fallbackAction configured, skip the
fallbackAttributesQueryValue to ensure the fallbackAction is triggered
when no team members are found. This maintains backwards compatibility
by only using fallbackAttributesQueryValue when fallbackAction is not set.

Also treats teamMemberIdsMatchingAttributeLogic being null (routing couldn't
run, e.g., missing orgId) the same as an empty array for the purpose of
triggering the fallbackAction.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* refactor: extract RouteActionSelector shared component for action selection UI

Co-Authored-By: [email protected] <[email protected]>

* fix: add i18n string for default custom page message

Co-Authored-By: [email protected] <[email protected]>

* feat: add webhook trigger when routing form fallback route is hit

- Add ROUTING_FORM_FALLBACK_HIT to WebhookTriggerEvents enum in Prisma schema
- Add new trigger to routing-forms webhook triggers in constants
- Add translation string for the new webhook trigger
- Implement triggerFallbackWebhook function in formSubmissionUtils.ts
- Call webhook trigger from handleResponse.ts when fallback action is used

Co-Authored-By: [email protected] <[email protected]>

* fix: remove webhook object from error log to avoid exposing secrets

Co-Authored-By: [email protected] <[email protected]>

* revert: remove webhook trigger changes (to be moved to separate PR)

Co-Authored-By: [email protected] <[email protected]>

* feat: add webhook trigger when routing form fallback route is hit

- Add ROUTING_FORM_FALLBACK_HIT to WebhookTriggerEvents enum in Prisma schema
- Add new trigger to routing-forms webhook triggers in constants
- Add translation string for the new webhook trigger
- Implement triggerFallbackWebhook function in formSubmissionUtils.ts
- Call webhook trigger from handleResponse.ts when fallback action is used

Co-Authored-By: [email protected] <[email protected]>

* fix: remove webhook object from error log to avoid exposing secrets

Co-Authored-By: [email protected] <[email protected]>

* fix: add ROUTING_FORM_FALLBACK_HIT to PayloadBuilderFactory trigger mapping

Co-Authored-By: [email protected] <[email protected]>

* style: apply biome formatting fixes

Co-Authored-By: [email protected] <[email protected]>

* fix: restore removed comments in RouteBuilder

Co-Authored-By: [email protected] <[email protected]>

* chore: add prisma migration for ROUTING_FORM_FALLBACK_HIT enum value

Co-Authored-By: [email protected] <[email protected]>

* fix: add ROUTING_FORM_FALLBACK_HIT to FormTriggerEvents type union

Co-Authored-By: [email protected] <[email protected]>

* test: add test coverage for triggerFallbackWebhook function

Co-Authored-By: [email protected] <[email protected]>

* refactor: consolidate fallback webhook firing with form submission webhooks

Move ROUTING_FORM_FALLBACK_HIT webhooks into the same Promise.all() batch
as FORM_SUBMITTED / FORM_SUBMITTED_NO_EVENT, eliminating redundant
getWebhooks/getWebhookTargetEntity/getOrgIdFromMemberOrTeamId calls.

- Add fallbackAction parameter to _onFormSubmission and onSubmissionOfFormResponse
- Remove triggerFallbackWebhook function and all its usages/imports
- Move getFallbackAction() earlier in handleResponse.ts and pass result through
- Update all tests to verify batched webhook behavior

Co-Authored-By: [email protected] <[email protected]>

* Add UI option for trigger

* feat: persist fallbackAction on queued form responses

When a routing form response is queued, the fallbackAction determined
during routing is now stored on the QueuedFormResponse record. When
the queued response is later converted to a real FormResponse, the
stored fallbackAction is passed to onSubmissionOfFormResponse so the
ROUTING_FORM_FALLBACK_HIT webhook fires correctly.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* test: add coverage for fallbackAction in queued form response flow

Verify that fallbackAction is persisted when queuing and passed through
to onSubmissionOfFormResponse when the queued response is converted.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <[email protected]>
2026-02-23 16:44:41 -05:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
9d29055808 feat: replace admin API settings page with link to API docs (#28046)
* feat: replace admin API settings page with link to API docs

Co-Authored-By: [email protected] <[email protected]>

* chore: remove unused AdminAPIView component

Co-Authored-By: [email protected] <[email protected]>

* feat: rename admin API tab to API Docs

Co-Authored-By: [email protected] <[email protected]>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-02-18 17:12:24 -05:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Claude Opus 4.5[email protected] <[email protected]>cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>[email protected] <[email protected]>
7cfb053026 feat: add wrong routing tab under Insights for reviewing assignment reports (#27423)
* Add DB table for wrong assignment reports

* When report is submitted write to the db

* Prevent duplicate reportings

* test: add migration and tests for WrongAssignmentReport table

Co-Authored-By: [email protected] <[email protected]>

* fix: add unique constraint on bookingUid and booking access check for hasWrongAssignmentReport

- Add @unique constraint on bookingUid in WrongAssignmentReport model to prevent duplicate reports at DB level
- Add booking ownership check using BookingAccessService in hasWrongAssignmentReport endpoint
- Refactor hasWrongAssignmentReport into separate handler and schema files

Addresses Cubic AI review feedback on PR #27405

Co-Authored-By: unknown <>

* feat: add routingFormId to WrongAssignmentReport and fix Select clearing

- Add routingFormId field to WrongAssignmentReport model in schema.prisma
- Add relation to App_RoutingForms_Form with SetNull on delete
- Update WrongAssignmentReportRepository.createReport to accept routingFormId
- Update BookingRepository.findByUidIncludeEventTypeAndTeamAndAssignmentReason to include routedFromRoutingFormReponse
- Extract routingFormId from booking in reportWrongAssignment handler
- Fix Select clearing issue: handle null case when user clears team member selection
- Update tests to include routingFormId field

Co-Authored-By: [email protected] <[email protected]>

* chore: add migration for routingFormId in WrongAssignmentReport

Co-Authored-By: [email protected] <[email protected]>

* feat: add wrong assignment reports dashboard under routing tab

- Add reviewedById and reviewedAt fields to WrongAssignmentReport model
- Add repository methods for listing reports by status and updating status
- Create tRPC endpoints for fetching reports and updating status
- Create dashboard UI with pending/reviewed tabs showing routing form name
- Add translation keys for dashboard UI
- Integrate dashboard into routing insights page

Co-Authored-By: [email protected] <[email protected]>

* fix: move hooks before early return and fix indentation

Co-Authored-By: [email protected] <[email protected]>

* fix: address Udit's review comments

- hasWrongAssignmentReport: throw UNAUTHORIZED error instead of returning false
- reportWrongAssignment: add try-catch for Prisma P2002 unique constraint error
- WrongAssignmentReport: add Team relation to teamId field
- WrongAssignmentReportRepository: use findUnique instead of findFirst
- reportWrongAssignment: use i18n for error messages

Co-Authored-By: [email protected] <[email protected]>

* fix: revert hasWrongAssignmentReport to return false when user lacks access

Per PR checklist, hasWrongAssignmentReport should return { hasReport: false }
when user lacks access to booking, not throw an error. This allows the UI
to gracefully treat 'no access' as 'no report exists'.

Co-Authored-By: [email protected] <[email protected]>

* test: update mocks for findUnique and i18n in unit tests

Co-Authored-By: [email protected] <[email protected]>

* fix: throw UNAUTHORIZED in hasWrongAssignmentReport and squash migrations

Co-Authored-By: [email protected] <[email protected]>

* feat: move wrong assignment reports to its own tab under Insights

Co-Authored-By: [email protected] <[email protected]>

* Use data table for wrong reports

* Add option to view routing trace

* feat: add view routing form submission action to wrong assignment reports

Co-Authored-By: [email protected] <[email protected]>

* feat: add RoutingFormResponseSheet component for viewing form submissions

- Create slide-out sheet to display routing form responses
- Map option IDs to display labels for select/multiselect fields
- Handle both legacy and modern option formats
- Add i18n strings: form_submission, no_responses_found

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* feat: improve wrong assignment reports UX

- Integrate RoutingFormResponseSheet as slide-out panel instead of new tab
- Fix dropdown padding by using StartIcon prop instead of manual Icon
- Allow direct status changes for reviewed reports (no need to reopen first)
- Remove unused Icon import

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: change User relation onDelete from Cascade to SetNull in WrongAssignmentReport

Address Hariom's review feedback:
- Changed reportedById from Int to Int? (nullable)
- Changed reportedBy relation from onDelete: Cascade to onDelete: SetNull
- Updated migration SQL to reflect these changes

This preserves wrong assignment reports even when the reporting user is deleted,
as the data is still useful for analysis.

Co-Authored-By: [email protected] <[email protected]>

* feat: add missing i18n strings for wrong assignment reports dashboard

Co-Authored-By: [email protected] <[email protected]>

* refactor: move form response display value resolution server-side

Replace client-side option ID to label resolution in
RoutingFormResponseSheet with a new lean tRPC endpoint
(getFormResponseDisplay) that resolves values server-side using
the existing getHumanReadableFieldResponseValue utility. This
enforces DTO boundaries by returning a clean pre-resolved payload
instead of leaking internal option format details to the client.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* feat: add report wrong assignment button to routing trace sheet

Wire up the WrongAssignmentDialog from the routing trace sheet header
so users can flag wrong assignments directly while viewing the trace.
The report button is disabled with a tooltip when a report already
exists.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* refactor: reuse existing WrongAssignmentDialog from parent

Replace the duplicate WrongAssignmentDialog in RoutingTraceSheet with
a callback to the existing instance in BookingActionsDropdown. This
reduces the prop surface from a 6-field reportContext object to an
onReport callback and hasExistingReport boolean.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* refactor: use repository instead of direct Prisma in getFormResponseDisplay

Replace direct Prisma query with PrismaRoutingFormResponseRepository's
findByIdIncludeForm method. Extend the method to also select form name,
description, userId, and teamId needed for display and auth checks.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* refactor: replace direct Prisma calls with repository methods

Use MembershipRepository.hasMembership() for auth checks and
TeamRepository.findAllByParentId() for child team queries instead
of direct Prisma calls. Replace direct user query with
UserRepository.getTimeZoneAndDefaultScheduleId(). Remove unused
seed script.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* refactor: use PBAC services for wrong assignment report auth

Replace manual MembershipRepository.hasMembership() checks with
PBAC-aware permission checking. getWrongAssignmentReports uses
createTeamPbacProcedure middleware since teamId is in input.
updateWrongAssignmentReportStatus uses PermissionCheckService
directly since teamId is discovered from the report entity.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix: resolve type errors in RoutingFormResponseSheet and wrong-routing view

Co-Authored-By: [email protected] <[email protected]>

* feat: add seed script for wrong assignment reports test data

Co-Authored-By: [email protected] <[email protected]>

* Revert "feat: add seed script for wrong assignment reports test data"

This reverts commit 0bd60e9661858a59aab1573d14d57d81733b7991.

* Only update reviewed fields when not pending

Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* refactor: wrap handleStatusChange in useCallback to fix useMemo recalculation

Co-Authored-By: [email protected] <[email protected]>

* Fix routing sheet UI

* fix: use appropriate error message in getFormResponseDisplay handler

Co-Authored-By: [email protected] <[email protected]>

* refactor: extract WrongAssignmentReportService from tRPC handlers

Move business logic (booking lookup, duplicate check, report creation,
webhook dispatch, org-level team resolution) into a dedicated service
in packages/features. Handlers become thin controllers that only handle
auth checks and delegate to the service.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix: restrict report status updates to admin/owner roles

Remove MembershipRole.MEMBER from fallbackRoles in
updateWrongAssignmentReportStatus permission check. Updating report
status is an administrative action that should be limited to team
admins and owners.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix: localize hard-coded success message in WrongAssignmentReportService

Co-Authored-By: [email protected] <[email protected]>

* fix: rename reviewed tab to handled and add missing translations

Rename the "Reviewed" tab to "Handled" since it groups three distinct
statuses (Reviewed, Resolved, Dismissed). Also add missing translation
keys for "resolved" and "dismissed" status badges.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* merge: resolve conflicts with main branch

Merge main into devin/1769747741-wrong-assignment-dashboard, resolving conflicts in:
- BookingActionsDropdown.tsx: use main's booking prop with PR's fragment structure
- reportWrongAssignment.handler.ts: keep PR's service-based approach
- reportWrongAssignment.handler.test.ts: use main's class-based mocks with PR's additions
- WrongAssignmentReportService.ts: align with main's repo method and field names

Co-Authored-By: [email protected] <[email protected]>

* Add guard when accessing assignmentReasonSortedByCreatedAt

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>

* fix: address Cubic AI review feedback - select projection and useLocale refactor

Co-Authored-By: [email protected] <[email protected]>

* fix: remove stale TRPCError assertion in test (service throws ErrorWithCode)

Co-Authored-By: [email protected] <[email protected]>

* refactor: remove unused findByTeamIdAndStatus and findByTeamIdAndStatuses methods

Co-Authored-By: [email protected] <[email protected]>

* perf: add composite index on WrongAssignmentReport and narrow findByIdIncludeForm select

Co-Authored-By: [email protected] <[email protected]>

* perf: use lightweight findTeamIdById in update-status handler instead of findById

Co-Authored-By: [email protected] <[email protected]>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: [email protected] <[email protected]>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Co-authored-by: [email protected] <[email protected]>
2026-02-12 13:02:33 +00:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
06bb994145 fix: Improve wrong assignment report (#27162)
* Pass already fetched booking

* Fetch the assignment reason

* Update tests

* Label as first assignment reason

* Pass single booking object

* Remove unused repository method

* Only pass bookingUid to handler

* Rename booking `assignmentReason` to `assignmentReasonSortedByCreatedAt`

* fix: use renamed assignmentReasonSortedByCreatedAt property

Co-Authored-By: [email protected] <[email protected]>

* Remove take statement

* fix: address Udit's review comments

- Restore BookingAccessService for access control checks
- Rename repository method from findByUidForWrongAssignmentReport to findByUidIncludeUserAndEventTypeTeamAndAttendeesAndAssignmentReason

Co-Authored-By: [email protected] <[email protected]>

* test: update tests to use BookingAccessService mock

Co-Authored-By: [email protected] <[email protected]>

* fix: use latest assignment reason in BookingDetailsSheet for consistency

Co-Authored-By: [email protected] <[email protected]>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-02-11 13:12:21 -05:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Claude Opus 4.5Hariom Balhara
6089f47d24 feat: add fallback action options to routing form fallback section (#27449)
* feat: add no users found fallback action for routing forms

- Add NoUsersFoundFallbackActionType enum with CustomPageMessage and ExternalRedirectUrl options
- Add noUsersFoundFallbackAction field to zodNonRouterRoute schema
- Add NoUsersFoundFallback UI component in RouteBuilder for configuring fallback action
- Update handleResponse to return noUsersFoundFallbackAction when no team members match
- Add i18n translation keys for new UI strings

Co-Authored-By: [email protected] <[email protected]>

* refactor: change fallback to use same action options as main route

- Replace noUsersFoundFallbackAction with fallbackAction that has same structure as main action
- Add action dropdown and input fields to fallback attributes query builder section
- Support Event redirect, External URL, and Custom page options in fallback
- Remove separate NoUsersFoundFallback toggle component
- Update handleResponse to return fallbackAction

Co-Authored-By: [email protected] <[email protected]>

* fix: ensure fallbackAction type is always defined in onChange handlers

Co-Authored-By: [email protected] <[email protected]>

* fix: add guards for route.fallbackAction in onChange handlers

Co-Authored-By: [email protected] <[email protected]>

* fix: only return fallbackAction when no users are found

Co-Authored-By: [email protected] <[email protected]>

* refactor: restructure fallback section to mirror main route structure

Co-Authored-By: [email protected] <[email protected]>

* fix: ensure backwards compatibility for existing routes with fallbackAttributesQueryValue

Co-Authored-By: [email protected] <[email protected]>

* fix: initialize fallbackAction with main event type for backwards compatibility

Co-Authored-By: [email protected] <[email protected]>

* fix: include fallbackAction in getRoutesToSave to persist changes

Co-Authored-By: [email protected] <[email protected]>

* fix: use fallbackAction in getRoutedUrl when no team members found

Co-Authored-By: [email protected] <[email protected]>

* fix: use i18n for fallback label and add tests for fallback action

Co-Authored-By: [email protected] <[email protected]>

* fix: do not trigger fallback action when CRM contact owner is found

Co-Authored-By: [email protected] <[email protected]>

* fix: prioritize fallbackAction over fallbackAttributesQueryValue

When a route has a fallbackAction configured, skip the
fallbackAttributesQueryValue to ensure the fallbackAction is triggered
when no team members are found. This maintains backwards compatibility
by only using fallbackAttributesQueryValue when fallbackAction is not set.

Also treats teamMemberIdsMatchingAttributeLogic being null (routing couldn't
run, e.g., missing orgId) the same as an empty array for the purpose of
triggering the fallbackAction.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* refactor: extract RouteActionSelector shared component for action selection UI

Co-Authored-By: [email protected] <[email protected]>

* fix: add i18n string for default custom page message

Co-Authored-By: [email protected] <[email protected]>

* feat: add webhook trigger when routing form fallback route is hit

- Add ROUTING_FORM_FALLBACK_HIT to WebhookTriggerEvents enum in Prisma schema
- Add new trigger to routing-forms webhook triggers in constants
- Add translation string for the new webhook trigger
- Implement triggerFallbackWebhook function in formSubmissionUtils.ts
- Call webhook trigger from handleResponse.ts when fallback action is used

Co-Authored-By: [email protected] <[email protected]>

* fix: remove webhook object from error log to avoid exposing secrets

Co-Authored-By: [email protected] <[email protected]>

* revert: remove webhook trigger changes (to be moved to separate PR)

Co-Authored-By: [email protected] <[email protected]>

* fix: only show fallback query builder when fallbackAction is explicitly set

The fallback attributes query builder was being shown for new routes
when fallbackAction was not set, causing an extra 'Add rule' button
to appear. This broke e2e tests that relied on the button index.

Now the fallback query builder is only shown when fallbackAction is
explicitly set to EventTypeRedirectUrl, which happens after the route
is saved and reloaded (via auto-initialization in useRoutes).

Co-Authored-By: [email protected] <[email protected]>

* fix: use data-testid for attribute query builder selectors in e2e tests

- Add data-testid='attributes-query-builder' to the main attributes query builder div
- Update addAttributeRoutingRule and addAttributeRoutingRuleWithOperator to use the data-testid selector instead of nth() indices
- This makes the tests more robust and independent of DOM structure changes

Co-Authored-By: [email protected] <[email protected]>

* fix: initialize fallbackAction for new routes in useCreateRoute hook

- New routes created via useCreateRoute now initialize fallbackAction
- This ensures new routes have a valid fallbackAction when saved
- Matches the initialization logic for existing routes in useRoutes

Co-Authored-By: [email protected] <[email protected]>

* fix: initialize fallbackAction at save time when action is EventTypeRedirectUrl

- When saving routes, if fallbackAction is undefined but action is EventTypeRedirectUrl,
  initialize fallbackAction from the main action
- This handles the case where user creates a new route and changes action to an event type
- Fixes e2e test failures where form save was failing due to undefined fallbackAction

Co-Authored-By: [email protected] <[email protected]>

* fix: initialize fallbackAction when main action changes to EventTypeRedirectUrl

Co-Authored-By: [email protected] <[email protected]>

* fix: only show fallback section when main action has valid event type selected

Co-Authored-By: [email protected] <[email protected]>

* fix: check for valid fallbackAction event type before preserving existing value

Co-Authored-By: [email protected] <[email protected]>

* Give more structure to main and fallback routes

* Update comment

* Rename fallbackAttributesQueryBuilder to matchingMembersFallbackRoute

* Display custom event redirect input

* fix: address Cubic AI review feedback for routing form fallback

- Simplify getFallbackAction logic to use checkedFallback flag instead of
  manually parsing attributesQueryValue (confidence 9/10)
- Add i18n translation for 'And connect with specific team members' string
  using t('connect_with_specific_team_members') (confidence 9/10)

Co-Authored-By: unknown <>

* fix: update getFallbackAction to use checkedFallback and handle missing orgId case

- Use checkedFallback flag as primary indicator for triggering fallback action
- Also handle edge case where attribute routing was configured but couldn't run
  due to missing orgId (teamMemberIdsMatchingAttributeLogic is null)
- Update test to mock checkedFallback: true when expecting fallback action

Co-Authored-By: unknown <>

* Address UI comment

* fix: Use fallbackAttributesQueryValue when fallback action is event redirect

Only use fallbackAttributesQueryValue when:
1. fallbackAction is EventTypeRedirectUrl (attribute routing applies)
2. fallbackAction is not set (backwards compatibility)

Skip it for CustomPageMessage and ExternalRedirectUrl fallback actions
since attribute routing doesn't apply to those action types.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: correct JSX syntax error in matchingMembersFallbackRoute

Co-Authored-By: [email protected] <[email protected]>

* refactor: extract getCustomSlug helper to deduplicate custom event type slug logic

Co-Authored-By: [email protected] <[email protected]>

* fix: only show fallback attribute filtering for teams under orgs

Co-Authored-By: [email protected] <[email protected]>

* fix: show fallback action for all team forms, gate attribute filtering on isOrganization

Co-Authored-By: [email protected] <[email protected]>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Hariom Balhara <[email protected]>
2026-02-11 09:15:16 -05:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
c0504993a6 feat: Write wrong assignment reports to the database (#27405)
* Add DB table for wrong assignment reports

* When report is submitted write to the db

* Prevent duplicate reportings

* test: add migration and tests for WrongAssignmentReport table

Co-Authored-By: [email protected] <[email protected]>

* fix: add unique constraint on bookingUid and booking access check for hasWrongAssignmentReport

- Add @unique constraint on bookingUid in WrongAssignmentReport model to prevent duplicate reports at DB level
- Add booking ownership check using BookingAccessService in hasWrongAssignmentReport endpoint
- Refactor hasWrongAssignmentReport into separate handler and schema files

Addresses Cubic AI review feedback on PR #27405

Co-Authored-By: unknown <>

* feat: add routingFormId to WrongAssignmentReport and fix Select clearing

- Add routingFormId field to WrongAssignmentReport model in schema.prisma
- Add relation to App_RoutingForms_Form with SetNull on delete
- Update WrongAssignmentReportRepository.createReport to accept routingFormId
- Update BookingRepository.findByUidIncludeEventTypeAndTeamAndAssignmentReason to include routedFromRoutingFormReponse
- Extract routingFormId from booking in reportWrongAssignment handler
- Fix Select clearing issue: handle null case when user clears team member selection
- Update tests to include routingFormId field

Co-Authored-By: [email protected] <[email protected]>

* chore: add migration for routingFormId in WrongAssignmentReport

Co-Authored-By: [email protected] <[email protected]>

* fix: address Udit's review comments

- hasWrongAssignmentReport: throw UNAUTHORIZED error instead of returning false
- reportWrongAssignment: add try-catch for Prisma P2002 unique constraint error
- WrongAssignmentReport: add Team relation to teamId field
- WrongAssignmentReportRepository: use findUnique instead of findFirst
- reportWrongAssignment: use i18n for error messages

Co-Authored-By: [email protected] <[email protected]>

* fix: revert hasWrongAssignmentReport to return false when user lacks access

Per PR checklist, hasWrongAssignmentReport should return { hasReport: false }
when user lacks access to booking, not throw an error. This allows the UI
to gracefully treat 'no access' as 'no report exists'.

Co-Authored-By: [email protected] <[email protected]>

* test: update mocks for findUnique and i18n in unit tests

Co-Authored-By: [email protected] <[email protected]>

* fix: throw UNAUTHORIZED in hasWrongAssignmentReport and squash migrations

Co-Authored-By: [email protected] <[email protected]>

* fix: change User relation onDelete from Cascade to SetNull in WrongAssignmentReport

Address Hariom's review feedback:
- Changed reportedById from Int to Int? (nullable)
- Changed reportedBy relation from onDelete: Cascade to onDelete: SetNull
- Updated migration SQL to reflect these changes

This preserves wrong assignment reports even when the reporting user is deleted,
as the data is still useful for analysis.

Co-Authored-By: [email protected] <[email protected]>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-02-10 08:00:01 -03:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
82a4780145 feat: show routing trace dialog on assignment reason badge click (#27629)
* feat: show routing trace dialog on assignment reason badge click

Co-Authored-By: [email protected] <[email protected]>

* fix: remove duplicate RoutingTraceSheet rendering

- Remove RoutingTraceSheet from BookingListItem.tsx to avoid duplicate rendering
- Move RoutingTraceSheet in BookingActionsDropdown.tsx outside of isBookingFromRoutingForm condition
- Use booking.assignmentReason.length > 0 condition for RoutingTraceSheet rendering
- Remove unused isOpenRoutingTraceSheet getter and RoutingTraceSheet import from BookingListItem.tsx

Co-Authored-By: [email protected] <[email protected]>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-02-09 10:39:34 -05:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
b6916df671 test: add E2E tests for assignAllTeamMembers with attribute segment filters (#27680)
* test: add E2E tests for assignAllTeamMembers with attribute segment filters

Cover all 4 attribute types (SINGLE_SELECT, MULTI_SELECT, TEXT, NUMBER)
with booking flow verification plus edge cases (no match, all match).

Co-Authored-By: [email protected] <[email protected]>

* fix: use auto-retrying assertion for no-match edge case test

Replace flaky waitForTimeout(2000) + count check with Playwright's
toHaveCount(0, { timeout: 15000 }) which retries until availability
settles, preventing CI timing issues.

Co-Authored-By: [email protected] <[email protected]>

* test: add exclusion tests for members without attribute assigned

Add 4 new E2E tests covering the case where team members have no
attribute assigned at all (not just a different value). Each attribute
type (SINGLE_SELECT, MULTI_SELECT, TEXT, NUMBER) is tested to verify
that members without the attribute are excluded from the booking pool.

Co-Authored-By: [email protected] <[email protected]>

* test: add negation operator tests and restructure exclusion tests

- Restructure 'Members without attribute assigned' tests: assign
  matching attribute to teammate-1 (not owner) so round-robin can't
  coincidentally pass when the bug exists
- Add 4 negation operator tests (select_not_any_in, multiselect_not_some_in,
  not_equal for TEXT and NUMBER) that verify unassigned members should
  match negation filters. Marked with test.fail() as they confirm a
  known bug where getLogicResultForAllMembers skips members without
  attribute assignments entirely.
- Add edge case: no members have attribute assigned -> no available slots

Co-Authored-By: [email protected] <[email protected]>

* test: remove test.fail() markers from negation tests after bug fix

Co-Authored-By: [email protected] <[email protected]>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-02-09 14:07:49 +05:30
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
f819f6488e test: add E2E tests for routing form attribute conditions (#27681)
* feat: add comprehensive E2E tests for routing form attribute conditions

Co-Authored-By: [email protected] <[email protected]>

* refactor: assert routedTeamMemberIds in URL instead of email in results

Co-Authored-By: [email protected] <[email protected]>

* refactor: assert both routedTeamMemberIds in URL and email in results

Co-Authored-By: [email protected] <[email protected]>

* fix: include users without attribute assignments in exclusion condition evaluation

Users with no attribute assigned were excluded from the team members list
entirely, causing exclusion operators (not_equals, not_some_in, not_like,
not_between, etc.) to never match them. Now getAttributesAssignmentData
includes all team members, even those without attribute assignments.

Also adds unit tests and E2E tests for this scenario.

Co-Authored-By: [email protected] <[email protected]>

* fix: update getAttributes test to reflect new behavior for empty attributes

Users without attribute assignments are now included with empty attributes
so exclusion operators can match them. Updated test expectation accordingly.

Co-Authored-By: [email protected] <[email protected]>

* refactor: remove redundant usersWithAssignments code (fix already in _prepareAssignmentData from main)

Co-Authored-By: [email protected] <[email protected]>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-02-09 14:02:22 +05:30
Joe Au-YeungandGitHub bc0ff0da8e fix: Exclusion attribute filter (#27669)
* Fix exclusion filter - include all team members

* Fix display when members aren't saved in the DB

* Update tests

* Undo change to member switch
2026-02-06 14:06:31 +00:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
9de621eb23 perf: replace O(n*m) array lookups with O(1) Map lookups in attribute routing (#27599)
* Replace n x m array functions with maps

* test: add tests and benchmark for Map-based attribute lookup optimization

Co-Authored-By: [email protected] <[email protected]>

* test: add real-world enterprise scenario (14 attrs x 6,530 opts) to benchmark

Co-Authored-By: [email protected] <[email protected]>

* chore: remove benchmark file

Co-Authored-By: [email protected] <[email protected]>

* Rename function

* Pass built maps to functions

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-02-04 12:43:16 -05:00
Joe Au-YeungGitHubClaude Opus 4.5Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
8d79209e74 perf: Optmize DB queries around attribute routing (#27600)
* Replace n x m array functions with maps

* feat: add attributeIds filter to findManyByOrgMembershipIds

Allow filtering attribute-to-user assignments by specific attribute IDs.
This enables querying only the attributes needed for a routing rule
instead of fetching all attributes for all team members.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* feat: extract attribute IDs from routing rules and filter queries

Add extractAttributeIdsFromQueryValue helper to parse routing rules
and identify which attributes are referenced. Pass these IDs through
getAttributesAssignmentData to _queryAllData to only fetch the
attribute assignments that are actually needed for evaluation.

For a team with 785 members and 14 attributes, if a routing rule
only references 2-3 attributes, this reduces the query from ~3500
rows to ~500 rows.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* feat: use attribute filtering in findTeamMembersMatchingAttributeLogic

Extract attribute IDs from the routing rules (main + fallback) and
pass them to getAttributesForLogic to only fetch necessary data.

This completes the optimization to reduce database load when
evaluating routing rules that only reference a subset of attributes.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* feat: filter attributes query by attribute IDs

Also filter the attributes query (not just attributeToUser assignments)
by the attribute IDs referenced in routing rules.

For a routing rule that references 2 out of 14 attributes with 6524
total options, this reduces:
- Attributes fetched: 14 → 2
- Options fetched: 6524 → ~930 (proportional reduction)
- Fewer regex replacements in replaceAttributeOptionIdsWithOptionLabel

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* test: add comprehensive test coverage for attribute routing query optimization

Co-Authored-By: [email protected] <[email protected]>

* Revert "Replace n x m array functions with maps"

This reverts commit 312eeb03bd1aba19760f093c798861a23b5fc66f.

* fix: re-establish extractAttributeIdsFromQueryValue mock after resetAllMocks

Co-Authored-By: [email protected] <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-02-04 11:28:46 -05:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
f7381d1b6d Parallelize calls (#27486)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-02-03 17:31:22 +05:30
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
c0f6a1b088 feat: add redirect option for non-routed visits to event types (#27468)
* feat: add redirect option for non-routing form bookings

Add a new event type option that redirects to a custom URL when the booking
was not made through a routing form (no cal.routingFormResponseId or
cal.queuedFormResponseId query parameters).

Changes:
- Add redirectUrlOnNoRoutingFormResponse field to EventType schema
- Add UI toggle in Advanced tab to configure the redirect URL
- Implement redirect logic in bookingSuccessRedirect hook
- Add translations for new UI strings

Co-Authored-By: [email protected] <[email protected]>

* fix: add redirectUrlOnNoRoutingFormResponse to test builder

Co-Authored-By: [email protected] <[email protected]>

* fix: add redirectUrlOnNoRoutingFormResponse to BookerEvent type

Co-Authored-By: [email protected] <[email protected]>

* fix: add redirectUrlOnNoRoutingFormResponse to getPublicEventSelect

Co-Authored-By: [email protected] <[email protected]>

* fix: add redirect logic to getServerSideProps for non-routing form bookings

Co-Authored-By: [email protected] <[email protected]>

* fix: remove redirectUrlOnNoRoutingFormResponse from booking success flow

Co-Authored-By: [email protected] <[email protected]>

* fix: use 'in' operator for type narrowing on redirectUrlOnNoRoutingFormResponse

Co-Authored-By: [email protected] <[email protected]>

* fix: exclude redirectUrlOnNoRoutingFormResponse from test assertions

Co-Authored-By: [email protected] <[email protected]>

* fix: include redirectUrlOnNoRoutingFormResponse in test assertions and update description

Co-Authored-By: [email protected] <[email protected]>

* fix: add redirectUrlOnNoRoutingFormResponse to mockUpdatedEventType

Co-Authored-By: [email protected] <[email protected]>

* fix: remove redirect logic from instant meetings

Co-Authored-By: [email protected] <[email protected]>

* fix: add redirectUrlOnNoRoutingFormResponse to EventTypeRepository select

Co-Authored-By: [email protected] <[email protected]>

* fix: add redirectUrlOnNoRoutingFormResponse to form default values

Co-Authored-By: [email protected] <[email protected]>

* Reword string

* fix: bust tRPC cache for redirectUrlOnNoRoutingFormResponse

Co-Authored-By: [email protected] <[email protected]>

* fix: guard redirect when rescheduleUid or bookingUid is present

Co-Authored-By: [email protected] <[email protected]>

* fix: add redirectUrlOnNoRoutingFormResponse to dynamicEvent defaults

Co-Authored-By: [email protected] <[email protected]>

* fix: add bookingUid guard to team getServerSideProps redirect

Co-Authored-By: [email protected] <[email protected]>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-02-02 15:48:23 -03:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
1d5228ef38 fix: skip duplicate CRM lookup when router already performed it (#27487)
When the routing form redirects to an event type, it now passes
cal.crmLookupDone=true to indicate that the CRM contact owner lookup
was already performed. The event type SSR checks for this flag and
skips the duplicate CRM lookup, improving performance.

This fixes the scenario where no CRM contact owner exists - previously
the lookup would be performed twice (once in the router, once in SSR),
but now it's only performed once.

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-02-02 14:28:34 +00:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Claude Opus 4.5
f91511b927 feat(salesforce): add field rules for round robin routing (#27402)
* feat(salesforce): add field rules for round robin skip

- Add rrSkipFieldRules schema to appDataSchema in zod.ts
- Implement applyFieldRules method in CrmService.ts for post-query filtering
- Integrate field rules into getContacts method when forRoundRobinSkip=true
- Add UI component for configuring field rules in EventTypeAppCardInterface
- Add translations for new UI strings
- Add comprehensive tests for field rules functionality

Field rules allow users to specify conditions based on Salesforce record fields
with 'ignore' or 'must_include' actions. Rules are evaluated with AND logic
and gracefully handle missing fields by skipping those rules.

Co-Authored-By: [email protected] <[email protected]>

* fix: add children prop to Section.SubSectionHeader for field rules

Co-Authored-By: [email protected] <[email protected]>

* feat(salesforce): add edit button for field rules

Co-Authored-By: [email protected] <[email protected]>

* feat(salesforce): apply field rules to GraphQL results

Co-Authored-By: [email protected] <[email protected]>

* feat(salesforce): add Redis caching for field validation

Co-Authored-By: [email protected] <[email protected]>

* fix(salesforce): remove Redis caching to fix ERR_INVALID_THIS error

- Removed Redis caching for field validation that was causing ERR_INVALID_THIS errors
- Simplified field rules filtering to try query directly and skip filtering if it fails
- Restored ensureFieldsExistOnObject method for other uses (write to record)
- Field rules now gracefully handle invalid fields by skipping filtering

Co-Authored-By: [email protected] <[email protected]>

* chore: reformat getAttributes.ts

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* feat(salesforce): dynamically build GraphQL query for field rules with multi-edge iteration

- Add buildDynamicAccountQuery to inject field rule fields into GraphQL query
- Add passesFieldRules to evaluate ignore/must_include rules against UIAPI nodes
- Validate field rules via getObjectFieldNames (in-memory + Redis cache) before branching
- Remove applyFieldRulesToGraphQLRecords (used jsforce conn in GraphQL path)
- Iterate all edges in Tiers 1 and 2 instead of only the first result
- Rank Tier 3 accounts by contact count and fallback to next on field rule failure

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* feat(salesforce): add field rule routing trace steps

Add trace calls alongside field rule info logs for routing visibility:
- fieldRulesValidated: records validation result in CrmService
- fieldRuleFilteredRecord: records when account is filtered at each tier
- fieldRuleEvaluated: records individual rule evaluation details
- allRecordsFilteredByFieldRules: records when SOQL records are all filtered

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(salesforce): remove duplicate field validation and fix disabled Select options

applyFieldRules now receives pre-validated rules from the early
validation block instead of re-validating internally. Also adds
the missing options prop to the disabled Select in the field rules UI.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* feat(salesforce): include failed rule details in field rule trace steps

Rename passesFieldRules to getFailingFieldRule so the caller receives
the specific rule that caused filtering. The fieldRuleFilteredRecord
trace step now includes failedRule with field, value, and action.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* test(salesforce): add GraphQL path tests for field rules

Cover field rule filtering across all three GraphQL resolution tiers
(contact, account, related contacts) with ignore and must_include
actions, multi-edge fallback, case-insensitivity, and dynamic query
selection.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* Abstract new field rules settings

* Reduce extra SOQL call

* fix(salesforce): fix type errors in CrmService and GraphQL client

- Add missing import for getRedisService from @calcom/features/di/containers/Redis
- Fix ensureFieldsExistOnObject to properly return Field[] instead of incomplete function
- Use Array.from() instead of spread operator for Set and Map iterators to fix downlevelIteration errors

Co-Authored-By: [email protected] <[email protected]>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <[email protected]>
2026-02-01 23:03:19 -05:00
Joe Au-YeungGitHubClaude Opus 4.5Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
7abbc8c22c feat: Routing trace presenter (#27372)
* feat: Add routing trace presenters

Add domain-specific presenters (SalesforceRoutingTracePresenter,
RoutingFormTracePresenter) that format trace steps into human-readable
strings, and a core RoutingTracePresenter that delegates to them based
on step domain. Includes unit tests for all presenters.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* feat: Add findByBookingUid to RoutingTraceRepository

Add method to look up a routing trace by booking UID, needed by the
routing trace presenter tRPC endpoint.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* feat: Add getRoutingTrace tRPC endpoint

Expose routing trace data for a booking via viewer.bookings.getRoutingTrace.
Tries the permanent RoutingTrace first (round robin bookings), then falls
back to PendingRoutingTrace via the booking's form response relation.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* feat: Add routing trace side sheet to booking list item

Add a route icon button on booking list items that came from routing
forms. Clicking it opens a side sheet displaying the full routing trace
as human-readable steps. Adds RoutingTraceSheet component, store state,
and translation key.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* refactor: Move routing trace action to dropdown menu

Move the routing trace button from a standalone icon on the booking list
item into the actions dropdown menu alongside "Report wrong assignment".
The RoutingTraceSheet is now rendered from BookingActionsDropdown.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: Improve routing trace UI and handle unnamed routes

- Redesign RoutingTraceSheet with vertical timeline layout, domain badges,
  skeleton loading state, and millisecond timestamps
- Use Salesforce app-store icon for Salesforce steps
- Fall back to "Unnamed route" when route name is missing or matches route ID
- Fix dropdown menu icon to git-merge (valid icon, unique in menu)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* test: Add tests for getRoutingTrace handler and findByBookingUid repository method

Co-Authored-By: [email protected] <[email protected]>

* Abstract functions

* Fix build error

* Add permission check

* fix: Update getRoutingTrace tests to include ctx and mock BookingAccessService

Co-Authored-By: [email protected] <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-29 15:26:44 -03:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Hariom Balhara
ca5d931165 fix: preserve UI config across iframe resets for element-click embeds (#27363)
* fix: preserve UI config across iframe resets for element-click embeds

For element-click embeds, ui() is called before the iframe exists, and
iframeReset() clears the queue when the modal is opened. This causes UI
config like hideEventTypeDetails, cssVarsPerTheme, and styles to be lost.

This fix stores UI config in a persistent property that survives iframe
resets and applies it when the iframe becomes ready.

Co-Authored-By: [email protected] <[email protected]>

* test: add assertion to verify hideEventTypeDetails config is applied in element-click embed

Co-Authored-By: [email protected] <[email protected]>

* Add mergeUiConfig function and related tests for UI configuration merging

- Introduced mergeUiConfig function to handle merging of UI configuration, specifically for cssVarsPerTheme at theme level.
- Added comprehensive tests for mergeUiConfig covering various scenarios including merging themes, handling missing properties, and preserving existing configuration values.
- Updated utils.test.ts to include tests for the new function and ensure correct behavior in different merging situations.

* Fixes

* Remove process import as it breaks embed.js

* Simplify

* fix name

* fix name

* fix: use forEach instead of for...of for URLSearchParams iteration

Co-Authored-By: [email protected] <[email protected]>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Hariom Balhara <[email protected]>
2026-01-29 08:18:53 -03:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Claude Opus 4.5Volnei Munhoz
034fbd63f1 feat: Add CrmRoutingTraceService and SalesforceRoutingTraceService (#27318)
* Add DB schema

* Init zod schema

* Init RoutingTrace and PendingRoutingTrace repository interfaces

* Create PrismaPendingRoutingTraceRepository

* Init RoutingTraceService

* Create RoutingTraceService container

* User routing trace service in routing

* Create RoutingTraceRepository and PrismaRoutingTraceRepoistory

* Add findByFormResponseId and findByQueuedFormResponseId to PendingRoutingTraceRepository

* Update DI containers

* RoutingTraceService create process booking method

* Use pending routing trace rather than URL params

* Fix schema

* Fix writing assignment reason for routed booking

* Remove  from  service

* Refactor RoutingTraceService to not rely on async local storage

* Pass RoutingTraceService through routing call

* Add attribute-logic-evaluated to routing trace step

* Add routing trace to trpc endpoint

* Add CRM routing trace step

* Fix extracting routing trace to assignment reason

* Add back CRM params to prevent refetching

* test: Add unit tests for RoutingTraceService and repositories

Co-Authored-By: [email protected] <[email protected]>

* test: Add missing mock for RoutingTraceService in getRoutedUrl tests

Also fix pre-existing lint issues in the test file:
- Add explicit types to mockForm and mockSerializableForm variables
- Add explicit type to url parameter in mockContext
- Replace 'as any' with 'as unknown as InstanceType<typeof UserRepository>'

Co-Authored-By: [email protected] <[email protected]>

* Link pending form submission to routing trace

* Clean up

* Add lookup field assignment reasons

* Rename to PendingRoutingTrace

* Add migration file

* fix: Update RoutingTraceService tests to use assignmentReasonRepository mock

- Add getStepsCount() method back to RoutingTraceService
- Add queuedFormResponseId support to processForBooking method
- Update tests to use mockAssignmentReasonRepository instead of prisma mock
- Remove test for missing routingTraceRepository (all deps now required)

Co-Authored-By: [email protected] <[email protected]>

* fix: Remove PII (organizer email) from log payload in RoutingTraceService

Addresses Cubic AI review feedback with confidence 9/10.
Logging PII violates sensitive information logging rules.

Co-Authored-By: unknown <>

* Write field values at the time of routing

* Write attributes used to route

* feat: add CRM routing trace service

Add CrmRoutingTraceService as a reusable wrapper around RoutingTraceService
for CRM-specific tracing. Also adds CrmRoutingTraceServiceInterface type
to support passing trace services through the CRM call chain.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* feat: add Salesforce routing trace infrastructure

Add SalesforceRoutingTrace static class with 19 trace methods covering:
- Account resolution (SOQL path): searching by website, contact domain
- Lookup field queries
- Owner lookups (contact, lead, account)
- Validation and skip scenarios
- GraphQL three-tier resolution

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* feat: wire CRM trace service through call chain

Pass crmTrace parameter through the CRM call chain:
- routerGetCrmContactOwnerEmail creates CrmRoutingTraceService
- Passes to app booking form handlers and CRM round robin skip
- CrmManager.getContacts accepts and forwards crmTrace
- All handlers accept optional crmTrace parameter

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* feat: add trace instrumentation to Salesforce CRM service

Instrument Salesforce CRM methods with routing trace steps:
- getContacts: trace owner lookups for contact/lead/account
- getAccountIdBasedOnEmailDomainOfContacts: trace website and domain searches
- findUserEmailFromLookupField: trace lookup field queries
- GetAccountRecordsForRRSkip (GraphQL): trace three-tier resolution

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* refactor: rename SalesforceRoutingTrace to SalesforceRoutingTraceService

Consistent naming with CrmRoutingTraceService.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* test: add unit tests for CrmRoutingTraceService and SalesforceRoutingTraceService

Co-Authored-By: [email protected] <[email protected]>

* refactor: use AsyncLocalStorage for CRM routing trace

Replace explicit crmTrace parameter passing with AsyncLocalStorage:

- Add AsyncLocalStorage to RoutingTraceService with getCurrent() and runAsync()
- Update SalesforceRoutingTraceService to auto-resolve trace from AsyncLocalStorage
- Remove CrmRoutingTraceService wrapper (no longer needed)
- Remove crmTrace parameter from all CRM method signatures
- Wrap CRM operations in routingTraceService.runAsync() context

This is cleaner than threading crmTrace through 5+ function layers.
The trace context is available within the withReporting wrapper.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* Use async local storage for `CrmRoutingTraceService`

* fix: correct template literal syntax in RoutingTraceService

Co-Authored-By: [email protected] <[email protected]>

* fix: use narrowed eventTypeId variable in nested async function

Co-Authored-By: [email protected] <[email protected]>

* fix: update SalesforceRoutingTraceService tests to use AsyncLocalStorage API

Co-Authored-By: [email protected] <[email protected]>

* refactor: rename crmTrace to crmRoutingTraceService for consistency

Co-Authored-By: [email protected] <[email protected]>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: Volnei Munhoz <[email protected]>
2026-01-28 17:28:35 -03:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Claude Opus 4.5
f536100224 feat: Add RoutingFormTrace (#27316)
* Add DB schema

* Init zod schema

* Init RoutingTrace and PendingRoutingTrace repository interfaces

* Create PrismaPendingRoutingTraceRepository

* Init RoutingTraceService

* Create RoutingTraceService container

* User routing trace service in routing

* Create RoutingTraceRepository and PrismaRoutingTraceRepoistory

* Add findByFormResponseId and findByQueuedFormResponseId to PendingRoutingTraceRepository

* Update DI containers

* RoutingTraceService create process booking method

* Use pending routing trace rather than URL params

* Fix schema

* Fix writing assignment reason for routed booking

* Remove  from  service

* Refactor RoutingTraceService to not rely on async local storage

* Pass RoutingTraceService through routing call

* Add attribute-logic-evaluated to routing trace step

* Add routing trace to trpc endpoint

* Add CRM routing trace step

* Fix extracting routing trace to assignment reason

* Add back CRM params to prevent refetching

* test: Add unit tests for RoutingTraceService and repositories

Co-Authored-By: [email protected] <[email protected]>

* test: Add missing mock for RoutingTraceService in getRoutedUrl tests

Also fix pre-existing lint issues in the test file:
- Add explicit types to mockForm and mockSerializableForm variables
- Add explicit type to url parameter in mockContext
- Replace 'as any' with 'as unknown as InstanceType<typeof UserRepository>'

Co-Authored-By: [email protected] <[email protected]>

* Link pending form submission to routing trace

* Clean up

* Add lookup field assignment reasons

* Rename to PendingRoutingTrace

* Add migration file

* fix: Update RoutingTraceService tests to use assignmentReasonRepository mock

- Add getStepsCount() method back to RoutingTraceService
- Add queuedFormResponseId support to processForBooking method
- Update tests to use mockAssignmentReasonRepository instead of prisma mock
- Remove test for missing routingTraceRepository (all deps now required)

Co-Authored-By: [email protected] <[email protected]>

* fix: Remove PII (organizer email) from log payload in RoutingTraceService

Addresses Cubic AI review feedback with confidence 9/10.
Logging PII violates sensitive information logging rules.

Co-Authored-By: unknown <>

* Write field values at the time of routing

* Write attributes used to route

* fix: Add CHECK constraint to ensure at least one response ID is set in routing trace tables

Co-Authored-By: [email protected] <[email protected]>

* fix: Address PR review comments for routing trace feature

- Add checkedFallback to routing trace step data (Comment 11)
- Extract hardcoded domain/step strings to constants (Comment 13)
- Use @default(now()) for createdAt in PendingRoutingTrace and RoutingTrace (Comment 15)
- Add DEFAULT CURRENT_TIMESTAMP to migration for createdAt fields

Co-Authored-By: [email protected] <[email protected]>

* fix: Use UTC-safe timezone expression for createdAt defaults in routing trace tables

Addresses Cubic AI review feedback (confidence 9/10) to prevent timezone
issues by using dbgenerated("timezone('UTC', now())") instead of bare now()
for the createdAt fields in PendingRoutingTrace and RoutingTrace models.

Co-Authored-By: unknown <>

* fix: Align migration SQL with Prisma's expected timezone syntax

Use 'UTC'::text cast in timezone() function to match Prisma's generated SQL.

Co-Authored-By: unknown <>

* fix: Revert migration SQL to match Prisma schema timezone syntax

Remove ::text cast from timezone() function to match what Prisma generates
from the schema definition.

Co-Authored-By: unknown <>

* fix: Use explicit ::text cast in timezone() for PostgreSQL compatibility

PostgreSQL normalizes timezone('UTC', now()) to timezone('UTC'::text, now())
internally. Update both schema and migration to use the explicit cast to
ensure they match and pass the migration check.

Co-Authored-By: unknown <>

* feat: Add RoutingFormTraceService domain class for type-safe routing traces

- Create RoutingFormTraceService class with routeMatched, fallbackRouteUsed,
  attributeLogicEvaluated, and attributeFallbackUsed methods
- Add ROUTING_FORM_STEPS constants
- Add unit tests

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* feat: Integrate RoutingFormTraceService for routing form tracing

- Add routingFormTraceService parameter to findMatchingRoute
- Record route_matched or fallback_route_used step when route is selected
- Use "Default Route" as name for form-level fallback routes
- Refactor findTeamMembersMatchingAttributeLogic to use RoutingFormTraceService
- Update handleResponse to accept and pass routingFormTraceService
- Create RoutingFormTraceService in getRoutedUrl and pass through the flow

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* test: Add test coverage for RoutingFormTraceService integration

Co-Authored-By: [email protected] <[email protected]>

* feat: Integrate RoutingFormTraceService for routing form tracing

- Add routingFormTraceService parameter to findMatchingRoute
- Record route_matched or fallback_route_used step when route is selected
- Use "Default Route" as name for form-level fallback routes
- Refactor findTeamMembersMatchingAttributeLogic to use RoutingFormTraceService
- Update handleResponse to accept and pass routingFormTraceService
- Create RoutingFormTraceService in getRoutedUrl and pass through the flow

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: Restore schema and migration from main branch

Co-Authored-By: [email protected] <[email protected]>

* fix: Use correct parameter name routingFormTraceService in tests

Co-Authored-By: [email protected] <[email protected]>

* fix: Use 'default_route' instead of 'Default Route' for fallback route name

Co-Authored-By: [email protected] <[email protected]>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <[email protected]>
2026-01-28 17:15:22 -03:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Pedro Castro
620445d85f feat: Use RoutingTraceService to write assignment reasons (#27225)
* Add DB schema

* Init zod schema

* Init RoutingTrace and PendingRoutingTrace repository interfaces

* Create PrismaPendingRoutingTraceRepository

* Init RoutingTraceService

* Create RoutingTraceService container

* User routing trace service in routing

* Create RoutingTraceRepository and PrismaRoutingTraceRepoistory

* Add findByFormResponseId and findByQueuedFormResponseId to PendingRoutingTraceRepository

* Update DI containers

* RoutingTraceService create process booking method

* Use pending routing trace rather than URL params

* Fix schema

* Fix writing assignment reason for routed booking

* Remove  from  service

* Refactor RoutingTraceService to not rely on async local storage

* Pass RoutingTraceService through routing call

* Add attribute-logic-evaluated to routing trace step

* Add routing trace to trpc endpoint

* Add CRM routing trace step

* Fix extracting routing trace to assignment reason

* Add back CRM params to prevent refetching

* test: Add unit tests for RoutingTraceService and repositories

Co-Authored-By: [email protected] <[email protected]>

* test: Add missing mock for RoutingTraceService in getRoutedUrl tests

Also fix pre-existing lint issues in the test file:
- Add explicit types to mockForm and mockSerializableForm variables
- Add explicit type to url parameter in mockContext
- Replace 'as any' with 'as unknown as InstanceType<typeof UserRepository>'

Co-Authored-By: [email protected] <[email protected]>

* Link pending form submission to routing trace

* Clean up

* Add lookup field assignment reasons

* Rename to PendingRoutingTrace

* Add migration file

* fix: Update RoutingTraceService tests to use assignmentReasonRepository mock

- Add getStepsCount() method back to RoutingTraceService
- Add queuedFormResponseId support to processForBooking method
- Update tests to use mockAssignmentReasonRepository instead of prisma mock
- Remove test for missing routingTraceRepository (all deps now required)

Co-Authored-By: [email protected] <[email protected]>

* fix: Remove PII (organizer email) from log payload in RoutingTraceService

Addresses Cubic AI review feedback with confidence 9/10.
Logging PII violates sensitive information logging rules.

Co-Authored-By: unknown <>

* Write field values at the time of routing

* Write attributes used to route

* fix: Add CHECK constraint to ensure at least one response ID is set in routing trace tables

Co-Authored-By: [email protected] <[email protected]>

* fix: Address PR review comments for routing trace feature

- Add checkedFallback to routing trace step data (Comment 11)
- Extract hardcoded domain/step strings to constants (Comment 13)
- Use @default(now()) for createdAt in PendingRoutingTrace and RoutingTrace (Comment 15)
- Add DEFAULT CURRENT_TIMESTAMP to migration for createdAt fields

Co-Authored-By: [email protected] <[email protected]>

* fix: Use UTC-safe timezone expression for createdAt defaults in routing trace tables

Addresses Cubic AI review feedback (confidence 9/10) to prevent timezone
issues by using dbgenerated("timezone('UTC', now())") instead of bare now()
for the createdAt fields in PendingRoutingTrace and RoutingTrace models.

Co-Authored-By: unknown <>

* fix: Align migration SQL with Prisma's expected timezone syntax

Use 'UTC'::text cast in timezone() function to match Prisma's generated SQL.

Co-Authored-By: unknown <>

* fix: Revert migration SQL to match Prisma schema timezone syntax

Remove ::text cast from timezone() function to match what Prisma generates
from the schema definition.

Co-Authored-By: unknown <>

* fix: Use explicit ::text cast in timezone() for PostgreSQL compatibility

PostgreSQL normalizes timezone('UTC', now()) to timezone('UTC'::text, now())
internally. Update both schema and migration to use the explicit cast to
ensure they match and pass the migration check.

Co-Authored-By: unknown <>

* fix: Use CURRENT_TIMESTAMP for createdAt defaults (standard Cal.com pattern)

Co-Authored-By: [email protected] <[email protected]>

* fix: Use @default(now()) for createdAt in routing trace tables to match migration

Co-Authored-By: [email protected] <[email protected]>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Pedro Castro <[email protected]>
2026-01-28 12:45:15 -05:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
01ae6f1b9e fix: Salesforce tokens add token_lifetime (#27264)
* Create `getSalesforceTokenLifetime`

* When connecting salesforce, add token_lifetime

* Migrate token_lifetime and refetch if token expiry doesn't match

* Add tests for Salesforce token lifetime feature

- Add unit tests for getSalesforceTokenLifetime function
- Add integration tests for token lifecycle management in CrmService
- Fix type error in CrmService.ts by extracting refreshToken variable

Co-Authored-By: [email protected] <[email protected]>

* chore: re-trigger CI

Co-Authored-By: [email protected] <[email protected]>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-27 10:00:48 -03:00
Joe Au-YeungandGitHub b02af9ae53 Update config with new id (#27197) 2026-01-23 21:06:12 -03:00
Joe Au-YeungandGitHub 3355fab4fb feat: display assignment reason in organizer emails and booking single view (#27192) 2026-01-23 20:50:07 -03:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Volnei Munhoz
ec951cacad perf: getUserAvailability if dateRange is empty, early return (#26000)
* Early return if date range is empty

* test: add tests for empty workingHours early return optimization

Co-Authored-By: [email protected] <[email protected]>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Volnei Munhoz <[email protected]>
2026-01-21 02:51:01 -03:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2608e136cb fix: use appropriate error codes in chargeCard handler (#27013)
- Change 'Booking not found' to throw NOT_FOUND (404) instead of plain Error
- Preserve ErrorWithCode for ChargeCardFailure to properly map to BAD_REQUEST (400)
- Add specific error handling for 'User is not a member of the team' -> FORBIDDEN (403)
- Add specific error handling for 'User ID is required' and 'No payment credential found' -> BAD_REQUEST (400)
- Keep INTERNAL_SERVER_ERROR (500) only for actual server errors like 'Payment app not implemented'
- Update test to expect ErrorWithCode to be re-thrown instead of wrapped in translated Error

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-19 18:14:13 +00:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
463987c02d feat: add GitHub Action to check Prisma migrations match schema (#26897)
* feat: add GitHub Action to check Prisma migrations match schema

Co-Authored-By: [email protected] <[email protected]>

* refactor: use CI_DATABASE_URL secret instead of hardcoded URL

Co-Authored-By: [email protected] <[email protected]>

* test: add test field to verify prisma migration check workflow

Co-Authored-By: [email protected] <[email protected]>

* fix: use git-based check for prisma changes to bypass paths-filter issue

Co-Authored-By: [email protected] <[email protected]>

* feat: add migration for test field to verify prisma migration check workflow

Co-Authored-By: [email protected] <[email protected]>

* chore: revert test field and migration after verifying workflow

Co-Authored-By: [email protected] <[email protected]>

* fix: split paths-filter into two actions to fix predicate-quantifier issue

Co-Authored-By: [email protected] <[email protected]>

* fix: rename has_companion to has-companion for consistent naming

Co-Authored-By: [email protected] <[email protected]>

* fix: update steps.filter references to steps.filter-exclusions

Co-Authored-By: [email protected] <[email protected]>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-16 15:50:20 +00:00
Joe Au-YeungandGitHub 40a7f53d1f Add IF NOT EXISTS (#26893) 2026-01-15 16:46:09 +00:00
Joe Au-YeungandGitHub adb7509d96 Rename migration file (#26889) 2026-01-16 01:06:19 +09:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Hariom Balharacubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
6501743e5e feat: Add attribute sync logic from Salesforce (#26517)
* Add db schema

* Add `CredentialRepository.findByTeamIdAndSlugs`

* Add enabled app slugs for attribute syncing

* Create repository for `IntegrationAttributeSync`

* Create zod schemas

* Create `AttributeSyncUserRuleOutputMapper`

* Create `IntegrationAttributeSyncService`

* Create DI contianer

* Create trpc endpoints

* Create page

* Include team name in `CredentialRepository.findByTeamIdAndSlugs`

* Update schema and relations

* Update types and schemas

* Add more methods to IntegrationAttributeSyncRepository

* Add more services to `IntegrationAttributeSyncService`
- getById
- Init updateIncludeRulesAndMappings

* Refactor `getTeams.handler` to use repository

* Create `createAttributeSync` trpc endpoint

* Create `updateAttributeSync` trpc endpoint

* Add router to trpc

* Create attribute sync child components

* Pass custom actions to `FormCard`

* Create `IntegrationAttributeSyncCard`

* Pass inital props via server side

* Fix prop

* Only refetch on mutation

* Fixes

* Add form error when duplicate field and attribute combo

* Add `updateTransactionWithRUleAndMappings` logic

* Adjust zod schemas

* Service add `updateIncludeRulesAndMappings`

* Pass orgId from server to component

* Rename types

* Add deleteById method to repository

* Add name to integrationAttributeSync

* Add deleteById method to service

* Rename method

* Add deleteAttributeSync trpc endpoint

* Make the IntegrationAttributeSyncCard a dummy component

* test: add tests for IntegrationAttributeSync feature

Co-Authored-By: [email protected] <[email protected]>

* Move creating a attribute sync record to the service

* Add i18n strings

* Safe select credential in find by id and team

* Fix default credentialId value in form

* Update repository return types

* Add i18n string

* Make credentialId optional for form schema

* Fix label

* Add cascade deletes

* Add verification that syncs belong to org

* Create mapper for repository output

* Type fixes

* Remove old test file

* Pass `attributeOptions` from parent to children

* Infer types from zod schema

* Type fixes

* Type fix

* Clean up

* Add i18n strings

* Remove unused file

* Address feedback

* Add migration file

* Address feedback

* Add validation for new integration values

* Remove unused router

* Move away from z.infer to z.ZodType

* Clean up comments

* Type fix

* Type fixes

* Type fix

* fix: add passthrough to syncFormDataSchema to preserve extra fields

Co-Authored-By: [email protected] <[email protected]>

* fix: remove incorrect test that expected extra fields to pass through syncFormDataSchema

Co-Authored-By: [email protected] <[email protected]>

* Add endpoint for SF to call

* Create scratch org config

* Create sf cli scripts

* Create package logic

* Update README

* Remove unused file

* Add indexes

* Add aria label

* Address feedback - consistent validation

* Fix import paths for attribute types

* Add `CredentialRepository.findByAppIdAndKeyValue`

* Get credential by instance URL

* Verify incoming sfdc orgId matches credential sfdc orgId

* Rename method

* Get user name integration syncs

* refactor: change attributeSyncRules array to singular attributeSyncRule

The database schema enforces a one-to-one relationship between
IntegrationAttributeSync and AttributeSyncRule (via @unique constraint),
and the UI only supports a single rule. This change makes the TypeScript
type match the database schema and UI behavior.

Changes:
- Update IntegrationAttributeSync interface to use attributeSyncRule: AttributeSyncRule | null
- Update mapper to return singular rule instead of wrapping in array
- Update UI component to access sync.attributeSyncRule directly
- Update IIntegrationAttributeSyncUpdateParams Omit type
- Update tests to use attributeSyncRule: null instead of attributeSyncRules: []

Co-Authored-By: [email protected] <[email protected]>

* Convert `membershipRepository.findAllByUserId` to a normal method

* Add temp files to git ignore

* Init  and process team conditions

* Biome formatting

* Add `AttributeService` to get user attributes

* Add DI container for AttributeService

* AttributeSyncService evaluate attribute conditions

* Create DI container for attributeSyncService

* Return result for full condition

* Evaluate if attribute sync should apply to user

* Add  method

* Change PrismaAttributeOptionRepository to instance methods

* Init AttributeSyncFieldMappingsService and process attribute syncs

* Add AttributeSyncFieldMappingService DI container

* Refactor orgId to organizationId

* Add membership validation to sync field service

* AttributeSYncFieldMappingService use repository methods

* AttributeSyncFieldMappingService.processMappings add mapping logic

* Add DI tokens

* user-sync endpoint to implement attribute syncing

* Validate team belongs to org for rule

* test: add tests for AttributeSyncRuleService, AttributeSyncFieldMappingService, and AttributeService

Co-Authored-By: [email protected] <[email protected]>

* Remove duplicate migration file

* Fix merge conflict

* fix: resolve type errors in attribute sync feature (#26814)

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* Rename  variable

* Fix log typo

* Fix file name

* Add error logging

* Use credential teamId

* fix: add missing mockTeamRepository and team validation to tests

Co-Authored-By: [email protected] <[email protected]>

* Fix naming

* Fix file import

* Type fix

* Pass MembershipRepository as a dep in AttributeSyncFieldMappingService

* Type fix

* fix: add mockMembershipRepository to AttributeSyncFieldMappingService tests

Co-Authored-By: [email protected] <[email protected]>

* Update packages/app-store/salesforce/api/user-sync.ts

Add error handling when getting orgId from stored salesforce id

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>

* fix: address Cubic code review comments

- PrismaAttributeRepository: use nested select instead of include: true for options
- CredentialRepository: use this.primaClient instead of global prisma, use select instead of include for relations
- AttributeSyncFieldMappingService: optimize O(n*m) complexity with Map lookup for O(1) access

Co-Authored-By: [email protected] <[email protected]>

* Fix typo in CredentialRepository

* Update README

* Update sfdx-project

* Add SFDC package tests

* fix: improve Salesforce Apex test assertions to verify actual behavior

- Enhanced CalComHttpMock to track HTTP callout invocations and capture requests
- Updated UserUpdateHandlerTest to verify HTTP callouts are made with correct data
- Updated CalComCalloutQueueableTest to verify HTTP callouts are made correctly
- Replaced System.assert(true, ...) with meaningful assertions that verify:
  - Correct number of HTTP callouts
  - Request body contains expected fields
  - Request method is POST

Addresses Cubic AI review feedback (confidence 9/10 issues only)

Co-Authored-By: unknown <>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Hariom Balhara <[email protected]>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-01-15 09:19:57 -05:00
Joe Au-YeungandGitHub d04bc970e0 Add missing migration (#26799) 2026-01-15 13:49:40 +02:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Eunjae LeeHariom Balhara
2664eb459b feat: Init Cal.com Salesforce package (#26330)
* Add db schema

* Add `CredentialRepository.findByTeamIdAndSlugs`

* Add enabled app slugs for attribute syncing

* Create repository for `IntegrationAttributeSync`

* Create zod schemas

* Create `AttributeSyncUserRuleOutputMapper`

* Create `IntegrationAttributeSyncService`

* Create DI contianer

* Create trpc endpoints

* Create page

* Include team name in `CredentialRepository.findByTeamIdAndSlugs`

* Update schema and relations

* Update types and schemas

* Add more methods to IntegrationAttributeSyncRepository

* Add more services to `IntegrationAttributeSyncService`
- getById
- Init updateIncludeRulesAndMappings

* Refactor `getTeams.handler` to use repository

* Create `createAttributeSync` trpc endpoint

* Create `updateAttributeSync` trpc endpoint

* Add router to trpc

* Create attribute sync child components

* Pass custom actions to `FormCard`

* Create `IntegrationAttributeSyncCard`

* Pass inital props via server side

* Fix prop

* Only refetch on mutation

* Fixes

* Add form error when duplicate field and attribute combo

* Add `updateTransactionWithRUleAndMappings` logic

* Adjust zod schemas

* Service add `updateIncludeRulesAndMappings`

* Pass orgId from server to component

* Rename types

* Add deleteById method to repository

* Add name to integrationAttributeSync

* Add deleteById method to service

* Rename method

* Add deleteAttributeSync trpc endpoint

* Make the IntegrationAttributeSyncCard a dummy component

* test: add tests for IntegrationAttributeSync feature

Co-Authored-By: [email protected] <[email protected]>

* Move creating a attribute sync record to the service

* Add i18n strings

* Safe select credential in find by id and team

* Fix default credentialId value in form

* Update repository return types

* Add i18n string

* Make credentialId optional for form schema

* Fix label

* Add cascade deletes

* Add verification that syncs belong to org

* Create mapper for repository output

* Type fixes

* Remove old test file

* Pass `attributeOptions` from parent to children

* Infer types from zod schema

* Type fixes

* Type fix

* Clean up

* Add i18n strings

* Remove unused file

* Address feedback

* Add migration file

* Address feedback

* Add validation for new integration values

* Remove unused router

* Move away from z.infer to z.ZodType

* Clean up comments

* Type fix

* Type fixes

* Type fix

* fix: add passthrough to syncFormDataSchema to preserve extra fields

Co-Authored-By: [email protected] <[email protected]>

* fix: remove incorrect test that expected extra fields to pass through syncFormDataSchema

Co-Authored-By: [email protected] <[email protected]>

* Add endpoint for SF to call

* Create scratch org config

* Create sf cli scripts

* Create package logic

* Update README

* Remove unused file

* Add indexes

* Add aria label

* Address feedback - consistent validation

* Fix import paths for attribute types

* refactor: change attributeSyncRules array to singular attributeSyncRule

The database schema enforces a one-to-one relationship between
IntegrationAttributeSync and AttributeSyncRule (via @unique constraint),
and the UI only supports a single rule. This change makes the TypeScript
type match the database schema and UI behavior.

Changes:
- Update IntegrationAttributeSync interface to use attributeSyncRule: AttributeSyncRule | null
- Update mapper to return singular rule instead of wrapping in array
- Update UI component to access sync.attributeSyncRule directly
- Update IIntegrationAttributeSyncUpdateParams Omit type
- Update tests to use attributeSyncRule: null instead of attributeSyncRules: []

Co-Authored-By: [email protected] <[email protected]>

* feat: implement FeatureOptInService (#25805)

* feat: implement FeatureOptInService WIP

* clean up

* feat: consolidate feature repositories and add updateFeatureForUser

- Implement updateFeatureForUser in FeaturesRepository (similar to updateFeatureForTeam)
- Move getUserFeatureState and getTeamFeatureState from PrismaFeatureOptInRepository to FeaturesRepository
- Update FeatureOptInService to use only FeaturesRepository
- Add setUserFeatureState and setTeamFeatureState methods to FeatureOptInService
- Update _router.ts to remove PrismaFeatureOptInRepository usage
- Remove PrismaFeatureOptInRepository.ts and FeatureOptInRepositoryInterface.ts
- Update features.repository.interface.ts and features.repository.mock.ts
- Add integration tests for updateFeatureForUser, getUserFeatureState, getTeamFeatureState
- Update service.integration-test.ts to use FeaturesRepository

Co-Authored-By: [email protected] <[email protected]>

* refactor: rename updateFeatureForUser to setUserFeatureState

Rename to match the convention used for setTeamFeatureState

Co-Authored-By: [email protected] <[email protected]>

* refactor: return FeatureState type from getUserFeatureState and getTeamFeatureState

* fix integration tests

* clean up logics

* update services and router

* refactor: change getUserFeatureState and getTeamFeatureState to accept featureIds array

- Renamed getUserFeatureState to getUserFeatureStates
- Renamed getTeamFeatureState to getTeamFeatureStates
- Changed parameter from featureId: string to featureIds: string[]
- Changed return type from FeatureState to Record<string, FeatureState>
- Updated FeatureOptInService to use the new batch methods
- Added tests for querying multiple features in a single call
- Optimized listFeaturesForTeam to fetch all feature states in one query

Co-Authored-By: [email protected] <[email protected]>

* feat: add getFeatureStateForTeams for batch querying multiple teams

- Added getFeatureStateForTeams method to query a single feature across multiple teams in one call
- Updated FeatureOptInService.resolveFeatureStateAcrossTeams to use the new batch method
- Replaces N+1 queries with a single database query for team states
- Added comprehensive integration tests for the new method

Co-Authored-By: [email protected] <[email protected]>

* refactor: combine org and team state queries into single call

- Include orgId in the teamIds array passed to getFeatureStateForTeams
- Extract org state and team states from the combined result
- Reduces database queries from 3 to 2 in resolveFeatureStateAcrossTeams

Co-Authored-By: [email protected] <[email protected]>

* refactor: use team.isOrganization and clarify computeEffectiveState comment

Co-Authored-By: [email protected] <[email protected]>

* refactor: use MembershipRepository.findAllByUserId with isOrganization

Co-Authored-By: [email protected] <[email protected]>

* feat: add featureId validation using isOptInFeature type guard

Co-Authored-By: [email protected] <[email protected]>

* less queries

* add fallback value

* fix type error

* move files

* add autoOptInFeatures column

* use autoOptInFeatures flag within FeatureOptInService

* add setUserAutoOptIn and setTeamAutoOptIn

* fix computeEffectiveState logic

* rewrite computeEffectiveState

* clean up integration tests

* clean up in afterEach

* fix type error

* refactor: use FeaturesRepository methods instead of direct Prisma calls

Replace all manual userFeatures and teamFeatures Prisma operations with
the new setUserFeatureState and setTeamFeatureState repository methods.

Changes include:
- Admin handlers (assignFeatureToTeam, unassignFeatureFromTeam)
- Test fixtures and integration tests
- Playwright fixtures
- Development scripts

This ensures consistent feature flag management through the repository
pattern and supports the new tri-state semantics (enabled/disabled/inherit).

Co-Authored-By: [email protected] <[email protected]>

* clean up

* fix the logic

* extract some logic into applyAutoOptIn()

* remove wrong code

* refactor: convert setUserFeatureState and setTeamFeatureState to object params with discriminated union

- Convert multiple positional parameters to single object parameter
- Use discriminated union types: assignedBy required for enabled/disabled, omitted for inherit
- Update all callers across repository, service, handlers, fixtures, and tests

* fix type error

* use Promise.all

* fix

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* Prevent duplicate field and attribute mappings

* Add validation that attribute belongs to the org

* fix: address Cubic AI review feedback

- Add @@index([credentialId]) to IntegrationAttributeSync model for efficient cascade deletes and credential-based queries (confidence: 9/10)
- Fix translation key from 'credential_required' to 'attribute_sync_credential_required' to match existing locale definition (confidence: 10/10)

Co-Authored-By: [email protected] <[email protected]>

* fix: address remaining cubic review feedback

- RuleBuilder.tsx: Use unique IDs for React keys instead of array index to prevent reconciliation bugs when removing conditions
- updateAttributeSync.handler.ts: Add early organization check before service calls for consistency
- createAttributeSync.handler.ts: Add CredentialNotFoundError class for type-safe error handling instead of string matching
- IntegrationAttributeSyncService.test.ts: Replace expect.fail() with proper Vitest rejects.toSatisfy() pattern

Co-Authored-By: [email protected] <[email protected]>

* Pull test file from main

* fix: address Cubic AI review feedback (confidence >= 9/10)

- Remove sensitive fields (email, changedFields) from logging in user-sync.ts
- Rename scratch-org:open to scratch-org:start in package.json to match README

Co-Authored-By: unknown <>

* Update README

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Eunjae Lee <[email protected]>
Co-authored-by: Hariom Balhara <[email protected]>
2026-01-13 20:01:21 -03:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Eunjae Lee
8dbe3848e7 feat: Create Integration Attribute Sync records (#26007)
* Add db schema

* Add `CredentialRepository.findByTeamIdAndSlugs`

* Add enabled app slugs for attribute syncing

* Create repository for `IntegrationAttributeSync`

* Create zod schemas

* Create `AttributeSyncUserRuleOutputMapper`

* Create `IntegrationAttributeSyncService`

* Create DI contianer

* Create trpc endpoints

* Create page

* Include team name in `CredentialRepository.findByTeamIdAndSlugs`

* Update schema and relations

* Update types and schemas

* Add more methods to IntegrationAttributeSyncRepository

* Add more services to `IntegrationAttributeSyncService`
- getById
- Init updateIncludeRulesAndMappings

* Refactor `getTeams.handler` to use repository

* Create `createAttributeSync` trpc endpoint

* Create `updateAttributeSync` trpc endpoint

* Add router to trpc

* Create attribute sync child components

* Pass custom actions to `FormCard`

* Create `IntegrationAttributeSyncCard`

* Pass inital props via server side

* Fix prop

* Only refetch on mutation

* Fixes

* Add form error when duplicate field and attribute combo

* Add `updateTransactionWithRUleAndMappings` logic

* Adjust zod schemas

* Service add `updateIncludeRulesAndMappings`

* Pass orgId from server to component

* Rename types

* Add deleteById method to repository

* Add name to integrationAttributeSync

* Add deleteById method to service

* Rename method

* Add deleteAttributeSync trpc endpoint

* Make the IntegrationAttributeSyncCard a dummy component

* test: add tests for IntegrationAttributeSync feature

Co-Authored-By: [email protected] <[email protected]>

* Move creating a attribute sync record to the service

* Add i18n strings

* Safe select credential in find by id and team

* Fix default credentialId value in form

* Update repository return types

* Add i18n string

* Make credentialId optional for form schema

* Fix label

* Add cascade deletes

* Add verification that syncs belong to org

* Create mapper for repository output

* Type fixes

* Remove old test file

* Pass `attributeOptions` from parent to children

* Infer types from zod schema

* Type fixes

* Type fix

* Clean up

* Add i18n strings

* Remove unused file

* Address feedback

* Add migration file

* Address feedback

* Add validation for new integration values

* Remove unused router

* Move away from z.infer to z.ZodType

* Clean up comments

* Type fix

* Type fixes

* Type fix

* fix: add passthrough to syncFormDataSchema to preserve extra fields

Co-Authored-By: [email protected] <[email protected]>

* fix: remove incorrect test that expected extra fields to pass through syncFormDataSchema

Co-Authored-By: [email protected] <[email protected]>

* Add indexes

* Add aria label

* Address feedback - consistent validation

* Fix import paths for attribute types

* refactor: change attributeSyncRules array to singular attributeSyncRule

The database schema enforces a one-to-one relationship between
IntegrationAttributeSync and AttributeSyncRule (via @unique constraint),
and the UI only supports a single rule. This change makes the TypeScript
type match the database schema and UI behavior.

Changes:
- Update IntegrationAttributeSync interface to use attributeSyncRule: AttributeSyncRule | null
- Update mapper to return singular rule instead of wrapping in array
- Update UI component to access sync.attributeSyncRule directly
- Update IIntegrationAttributeSyncUpdateParams Omit type
- Update tests to use attributeSyncRule: null instead of attributeSyncRules: []

Co-Authored-By: [email protected] <[email protected]>

* feat: implement FeatureOptInService (#25805)

* feat: implement FeatureOptInService WIP

* clean up

* feat: consolidate feature repositories and add updateFeatureForUser

- Implement updateFeatureForUser in FeaturesRepository (similar to updateFeatureForTeam)
- Move getUserFeatureState and getTeamFeatureState from PrismaFeatureOptInRepository to FeaturesRepository
- Update FeatureOptInService to use only FeaturesRepository
- Add setUserFeatureState and setTeamFeatureState methods to FeatureOptInService
- Update _router.ts to remove PrismaFeatureOptInRepository usage
- Remove PrismaFeatureOptInRepository.ts and FeatureOptInRepositoryInterface.ts
- Update features.repository.interface.ts and features.repository.mock.ts
- Add integration tests for updateFeatureForUser, getUserFeatureState, getTeamFeatureState
- Update service.integration-test.ts to use FeaturesRepository

Co-Authored-By: [email protected] <[email protected]>

* refactor: rename updateFeatureForUser to setUserFeatureState

Rename to match the convention used for setTeamFeatureState

Co-Authored-By: [email protected] <[email protected]>

* refactor: return FeatureState type from getUserFeatureState and getTeamFeatureState

* fix integration tests

* clean up logics

* update services and router

* refactor: change getUserFeatureState and getTeamFeatureState to accept featureIds array

- Renamed getUserFeatureState to getUserFeatureStates
- Renamed getTeamFeatureState to getTeamFeatureStates
- Changed parameter from featureId: string to featureIds: string[]
- Changed return type from FeatureState to Record<string, FeatureState>
- Updated FeatureOptInService to use the new batch methods
- Added tests for querying multiple features in a single call
- Optimized listFeaturesForTeam to fetch all feature states in one query

Co-Authored-By: [email protected] <[email protected]>

* feat: add getFeatureStateForTeams for batch querying multiple teams

- Added getFeatureStateForTeams method to query a single feature across multiple teams in one call
- Updated FeatureOptInService.resolveFeatureStateAcrossTeams to use the new batch method
- Replaces N+1 queries with a single database query for team states
- Added comprehensive integration tests for the new method

Co-Authored-By: [email protected] <[email protected]>

* refactor: combine org and team state queries into single call

- Include orgId in the teamIds array passed to getFeatureStateForTeams
- Extract org state and team states from the combined result
- Reduces database queries from 3 to 2 in resolveFeatureStateAcrossTeams

Co-Authored-By: [email protected] <[email protected]>

* refactor: use team.isOrganization and clarify computeEffectiveState comment

Co-Authored-By: [email protected] <[email protected]>

* refactor: use MembershipRepository.findAllByUserId with isOrganization

Co-Authored-By: [email protected] <[email protected]>

* feat: add featureId validation using isOptInFeature type guard

Co-Authored-By: [email protected] <[email protected]>

* less queries

* add fallback value

* fix type error

* move files

* add autoOptInFeatures column

* use autoOptInFeatures flag within FeatureOptInService

* add setUserAutoOptIn and setTeamAutoOptIn

* fix computeEffectiveState logic

* rewrite computeEffectiveState

* clean up integration tests

* clean up in afterEach

* fix type error

* refactor: use FeaturesRepository methods instead of direct Prisma calls

Replace all manual userFeatures and teamFeatures Prisma operations with
the new setUserFeatureState and setTeamFeatureState repository methods.

Changes include:
- Admin handlers (assignFeatureToTeam, unassignFeatureFromTeam)
- Test fixtures and integration tests
- Playwright fixtures
- Development scripts

This ensures consistent feature flag management through the repository
pattern and supports the new tri-state semantics (enabled/disabled/inherit).

Co-Authored-By: [email protected] <[email protected]>

* clean up

* fix the logic

* extract some logic into applyAutoOptIn()

* remove wrong code

* refactor: convert setUserFeatureState and setTeamFeatureState to object params with discriminated union

- Convert multiple positional parameters to single object parameter
- Use discriminated union types: assignedBy required for enabled/disabled, omitted for inherit
- Update all callers across repository, service, handlers, fixtures, and tests

* fix type error

* use Promise.all

* fix

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* Prevent duplicate field and attribute mappings

* Add validation that attribute belongs to the org

* fix: address Cubic AI review feedback

- Add @@index([credentialId]) to IntegrationAttributeSync model for efficient cascade deletes and credential-based queries (confidence: 9/10)
- Fix translation key from 'credential_required' to 'attribute_sync_credential_required' to match existing locale definition (confidence: 10/10)

Co-Authored-By: [email protected] <[email protected]>

* fix: address remaining cubic review feedback

- RuleBuilder.tsx: Use unique IDs for React keys instead of array index to prevent reconciliation bugs when removing conditions
- updateAttributeSync.handler.ts: Add early organization check before service calls for consistency
- createAttributeSync.handler.ts: Add CredentialNotFoundError class for type-safe error handling instead of string matching
- IntegrationAttributeSyncService.test.ts: Replace expect.fail() with proper Vitest rejects.toSatisfy() pattern

Co-Authored-By: [email protected] <[email protected]>

* Pull test file from main

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Eunjae Lee <[email protected]>
2026-01-12 22:57:28 +00:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
d5c2212c41 chore: Add logging eventId from Stripe webhook (#26623)
* Add loggin

* fix: use established logger instead of console.log for Stripe webhook eventId

Co-Authored-By: unknown <>

* fix: remove sensitive stripe-signature header from error logs

Co-Authored-By: unknown <>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-12 14:02:35 +00:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Udit TakkarAnik Dhabal Babu
08edd4f361 chore: Add logging to msteams (#23684)
* Add logging

* fix: Add response status checking to MS Teams adapter error handling

- Add response.ok checks before parsing JSON in createMeeting and updateMeeting
- Remove console.log statements that could leak credential information
- Ensure error handling matches original handleErrorsRaw behavior for tests

Co-Authored-By: [email protected] <[email protected]>

* Fix logs

* Revert "fix: Add response status checking to MS Teams adapter error handling"

This reverts commit 35820d21e1a54d9e04d83fd5f53584d64a5459b6.

* fix: Add response status checking to MS Teams adapter error handling

- Check response.ok before parsing JSON in createMeeting and updateMeeting
- Re-throw HttpError instances instead of wrapping them in catch blocks
- This ensures HTTP errors (like 500) are properly propagated

Co-Authored-By: unknown <>

* fix: Correct log message in updateMeeting to say 'updating' instead of 'creating'

Co-Authored-By: unknown <>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Udit Takkar <[email protected]>
Co-authored-by: Anik Dhabal Babu <[email protected]>
2026-01-11 10:34:02 +05:30
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
f6d3b11582 refactor: Membership.findByUserIdAndTeamId to instance method (#26628)
* Make  and instance method

* Refactor files

* fix: update MembershipRepository mocks to use vi.hoisted() for proper hoisting

Co-Authored-By: [email protected] <[email protected]>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-09 22:37:42 -03:00
Joe Au-YeungandGitHub 04e447058c fix: Add copy-app-store-static to docker file (#26565)
* Add `copy-app-store-static` step

* Biome formatting
2026-01-08 04:30:02 -03:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
0cf5de5ef8 fix: log Zoom token refresh errors at ERROR level (#26547)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-07 21:49:11 +00:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
8b5d9202db refactor: convert PrismaAttributeToUserRepository to accept Prisma as dependency (#26515)
* refactor: convert PrismaAttributeToUserRepository to accept Prisma as dependency

Co-Authored-By: [email protected] <[email protected]>

* fix: use Prisma types from generated client instead of custom types

Co-Authored-By: [email protected] <[email protected]>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-06 18:09:07 +00:00
Joe Au-YeungandGitHub 048a9b04fa chore: add logging in next-auth (#26404)
* Add logging in next-auth
* Add logging at other return
2026-01-02 20:30:09 -03:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Udit TakkarSyed Ali Shahbaz
2b61bddf7b feat: add completed onboarding column to organization members table (#25582)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Udit Takkar <[email protected]>
Co-authored-by: Syed Ali Shahbaz <[email protected]>
2025-12-30 10:57:49 -03:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
8ac3d423cb fix: When checking email domains to block replace includes with endsWith (#26166)
* Lint fixes

* Replace `includes` with `endsWith`

* Fix typo

* test: add tests for email domain blocking fix

Co-Authored-By: [email protected] <[email protected]>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-23 19:56:43 -03:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
3a59cd41cc feat: add toggle to opt out of booking title translation in instant meetings (#25547)
* feat: add toggle to opt out of booking title translation in instant meetings

Co-Authored-By: [email protected] <[email protected]>

* fix: add autoTranslateTitleEnabled to test builder

Co-Authored-By: [email protected] <[email protected]>

* fix: respect autoTranslateTitleEnabled toggle in InstantBookingCreateService

Co-Authored-By: [email protected] <[email protected]>

* fix: fetch autoTranslateTitleEnabled directly in InstantBookingCreateService

Co-Authored-By: [email protected] <[email protected]>

* refactor: rename autoTranslateTitleEnabled to autoTranslateInstantMeetingTitleEnabled

- Renamed field to clarify it only applies to instant meeting title translation
- Moved Prisma query to EventTypeRepository.findInstantMeetingConfigById()
- Removed title translation logic from update.handler.ts (flag only controls instant meeting title)
- Updated all references across the codebase
- Added new i18n translation keys for the renamed field

Co-Authored-By: [email protected] <[email protected]>

* fix: add autoTranslateInstantMeetingTitleEnabled to test destructuring patterns

Co-Authored-By: [email protected] <[email protected]>

* fix: use Prisma.TeamCreateInput type for metadata in test helper

Co-Authored-By: [email protected] <[email protected]>

* fix: add autoTranslateInstantMeetingTitleEnabled to mockUpdatedEventType in test

Co-Authored-By: [email protected] <[email protected]>

* refactor: use generic findByIdMinimal instead of business-specific method

- Add autoTranslateInstantMeetingTitleEnabled to eventTypeSelect constant
- Remove findInstantMeetingConfigById from EventTypeRepository
- Update InstantBookingCreateService to use findByIdMinimal

Co-Authored-By: [email protected] <[email protected]>

* refactor: remove autoTranslateInstantMeetingTitleEnabled from eventTypeSelect (not needed for findByIdMinimal)

Co-Authored-By: [email protected] <[email protected]>

* feat: add autoTranslateInstantMeetingTitleEnabled to event type form defaults

- Rename shouldTranslateTitle to shouldAutoTranslateInstantMeetingTitle for clarity
- Add autoTranslateInstantMeetingTitleEnabled to findById and findByIdForOrgAdmin selects
- Add autoTranslateInstantMeetingTitleEnabled to useEventTypeForm defaultValues

Co-Authored-By: [email protected] <[email protected]>

* fix: only update autoTranslateInstantMeetingTitleEnabled when explicitly provided

Fixes issue where omitting the field in update requests would overwrite
the saved opt-out setting with the default value (true). Now the field
is only included in the update payload when explicitly provided.

Co-Authored-By: [email protected] <[email protected]>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-09 13:51:51 +00:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
dc44825ce5 fix: prevent overwriting existing event type values with undefined (#25624)
When updating an event type, fields like autoTranslateDescriptionEnabled
and disableGuests were being overwritten with false/default values even
when they weren't explicitly provided in the update request.

Changes:
- autoTranslateDescriptionEnabled: Only set when explicitly provided
  (not undefined) to avoid overwriting existing true values with false
- disableGuests: Only set when bookingFields is explicitly provided,
  since it's derived from the guests field in bookingFields

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-12-04 19:18:45 +00:00
0605572969 fix: Log detailed error in getConnectedCalendar (#25338)
* Log error

* Reverse sent error message changes

---------

Co-authored-by: Anik Dhabal Babu <[email protected]>
2025-12-03 19:51:51 +00:00
Joe Au-YeungGitHubcal.comMorganhbjORbjDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Alex van Andel
f33edb2b99 feat: Generate email workflow payload at time of sending (#25446)
* wip

* wip

* feature: Booking Tasker without DI yet

* feature: Booking Tasker with DI

* fix type check 1

* fix type check 2

* fix

* comment booking tasker for now

* fix: DI regularBookingService api v2

* fix: convert trigger.dev SDK imports to dynamic imports to fix unit tests

The unit tests were failing because BookingEmailAndSmsTriggerTasker.ts had static imports of trigger files that depend on @trigger.dev/sdk. This caused Vitest to try to resolve the SDK at module load time, even though it should be optional.

Changed all imports in BookingEmailAndSmsTriggerTasker.ts from static to dynamic (using await import()) so the trigger files are only loaded when the tasker methods are actually called, not at module load time during tests.

This fixes the 'Failed to load url @trigger.dev/sdk' errors that were causing 28+ test failures.

Co-Authored-By: [email protected] <[email protected]>

* fix unit tests

* keep inline smsAndEmailHandler.send calls

* chore: add team feature flag

* add satisfies ModuleLoader

* fix type check app flags

* move trigger in feature

* fix: add trigger.dev prisma  generator

* fix: email app statuses

* fix: CalEvtBuilder unit test

* chore: improvements, schema, config, retry

* fixup! chore: improvements, schema, config, retry

* chore: cleanup code

* chore: cleanup code

* chore: clean code and give full payload

* remove log

* add booking notifications queue

* add attendee phone number for sms

* bump trigger to 4.1.0

* add missing booking seat data in attendee

* update config

* fix logger regular booking service

* fix: prisma as external deps of trigger

* fix yarn.lock

* revert change to example app booking page

* fix: resolve circular dependencies and improve cold start performance in trigger tasks

- Convert BookingRepository import to type-only in CalendarEventBuilder.ts to eliminate circular dependency risk
- Convert EventNameObjectType, CalendarEvent, and JsonObject imports to type-only in BookingEmailAndSmsTaskService.ts
- Use dynamic imports in all trigger notification tasks (confirm, request, reschedule, rr-reschedule) to reduce cold start time
- Move heavy imports (BookingEmailSmsHandler, BookingRepository, prisma, TriggerDevLogger, BookingEmailAndSmsTaskService) inside run functions
- Eliminates module-level prisma import which violates repo guidelines and adds cold start overhead
- Reduces initial module dependency graph by deferring heavy imports (email templates, workflows, large repositories) until task execution

Co-Authored-By: [email protected] <[email protected]>

* fix: improve cold start performance in reminderScheduler with dynamic imports

- Remove module-level prisma import (violates 'No prisma outside repositories' guideline)
- Use dynamic imports for UserRepository (1,168 lines) - only loaded when needed in EMAIL_ATTENDEE action
- Use dynamic imports for twilio provider (386 lines) - only loaded in cancelScheduledMessagesAndScheduleEmails
- Use dynamic imports for all manager functions by action type:
  - scheduleSMSReminder (387 lines) - loaded only for SMS actions
  - scheduleEmailReminder (459 lines) - loaded only for Email actions
  - scheduleWhatsappReminder (266 lines) - loaded only for WhatsApp actions
  - scheduleAIPhoneCall (478 lines) - loaded only for AI phone call actions
- Use dynamic imports for sendOrScheduleWorkflowEmails in cancelScheduledMessagesAndScheduleEmails
- Significantly reduces cold start time by deferring heavy module loading until execution paths need them
- Eliminates module-level prisma import that violated repository pattern guidelines

Co-Authored-By: [email protected] <[email protected]>

* fix: improve cold start performance in BookingEmailSmsHandler with dynamic imports

- Remove module-level imports of all email-manager functions (653 LOC + 30+ email templates)
- Add dynamic imports in each method (_handleRescheduled, _handleRoundRobinRescheduled, _handleConfirmed, _handleRequested, handleAddGuests)
- Defer heavy email-manager loading until method execution
- Verified no circular dependencies between email-manager and bookings
- Significantly reduces cold start time for RegularBookingService and BookingEmailAndSmsTaskService

Co-Authored-By: [email protected] <[email protected]>

* fix: use dynamic imports

* update yarn lock

* code review

* trigger config project ref in env

* update yarn lock

* add .env.example trigger variables

* add .env.example trigger variables

* fix: cleanup error handling and loggin

* fix: trigger config from env

* fix: small typo fix

* fix: ai review comments

* fix: ai review comments

* ai review

* Add `create` on `WorkflowReminderRepository`

* `sendWorkflowEmails` tasker to accept lazy payload

* Add `scheduleLazyEmailWorkflow` to `WorkflowService

* Process scheduled date in `scheduleLazyEmailWorkflow`

* Type fixes

* Use `WorkflowService` to schedule

* Refactor `scheduleEmailReminderForEvt` to use
`WorkflowService.processWorkflowScheduledDate`

* Pass seat reference to lazy scheduled workflow reminder

* Refactor `WorkflowReminderRepository` to accept prisma as constructor

* Abstract `FormSubmissionData` type

* Abstract select statement and add get by uid to `BookingRepository`

* Add `FormSubmissionData` type

* Add `findByIdIncludeStepAndWorkflow` to `WorkflowReminderRepository`

* Tasker payload to accept `workflowReminderId`

* Create `BookingSeatRepository`

* Write `workflowReminderId` to tasker payload

* Add `generateCommonScheduleFunctionParams` to `WorkflowService`

* Init

* Use services in tasker

* Abstract types

* In reminderScheduler use workflowService to generate common params

* Type fix

* Return params from emailWorkflowService.generateParametersToBuildEmailWorkflowContent

* Use emailWorkflowService to generate params

* Abstract types

* Generate email content and send in EmailWorkflowService

* Move check to caller

* Use EmailWorkflowService to generate email payload in
emailReminderManager

* Fix initalizing repository

* Use evt.videoCallData first before the booking metadata

* Only get non-deleted references to build calendar event

* Remove check for videoCallData.id

* Dynamic import credit service

* BookingRepository.getByUid to only return what we need from attendee

* Type fixes

* test: Add comprehensive tests for lazy email workflow generation and fix broken tests

- Fix prisma mocks in sms-manager.test.ts and outOfOfficeCreateOrUpdate.handler.test.ts
  to export both 'default' and named 'prisma' exports
- Add EmailWorkflowService.test.ts with 4 tests for error handling paths
- Add sendWorkflowEmails.test.ts with 7 tests for schema validation and email sending
- Add tests to WorkflowService.test.ts for scheduleLazyEmailWorkflow,
  processWorkflowScheduledDate, and generateCommonScheduleFunctionParams methods

Co-Authored-By: [email protected] <[email protected]>

* Write `seatReferenceUid`

* Return promise

* Fix log

* Change to `Promise.allSettled`

* Type fix

* Fix failing test

* fix: reorder workflow step checks to fix test failure

The test 'should throw error if workflow step not found on reminder' was failing because the code checked workflowStep.verifiedAt before checking if workflowStep exists. When workflowStep is null, this caused the error message to include 'undefined' instead of the expected workflow step id.

Fixed by reordering the checks:
1. First check if workflowStep exists
2. Then check if workflowStep.verifiedAt exists

Also updated the test expectation to match the correct error message.

Co-Authored-By: [email protected] <[email protected]>

---------

Co-authored-by: cal.com <[email protected]>
Co-authored-by: Morgan <[email protected]>
Co-authored-by: hbjORbj <[email protected]>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Alex van Andel <[email protected]>
2025-12-02 02:25:07 +00:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2b2bf36703 fix: Grab booking organizer credentials when team admins request reschedule (#24645)
* Change arg name from `bookingUId` to `bookingUid`

* Lint fix

* Use `BookingRepository` to find booking to reschedule

* Move early return further up if no booking is found

* Use `PermissionCheckService` if request rescheduling a team booking

* Remove redundent check

* Remove redundent eventType query

* Using `BookingRepository` to update the booking to rescheduled

* Update type in `getUsersCredentialsIncludeServiceAccountKey` to only
require params that are required

* Get booking organizer credentials

* Type fixes

* test: Add tests for team admin request reschedule with organizer credentials

- Add test for team admin requesting reschedule with proper permissions
- Add test verifying organizer's credentials are used (not requester's)
- Add test for team member without permissions (should fail)

These tests cover the fix in PR #24645 which ensures that when a team admin
requests a reschedule, the booking organizer's credentials are used to delete
calendar events instead of the requester's credentials.

Co-Authored-By: [email protected] <[email protected]>

* fix: Address code review comments for request reschedule

- Change user: true to user: { select: { id, email } } to only fetch required fields
- Change eventType include to select with explicit fields including teamId
- Remove sensitive information (user object, cancellationReason) from debug log
- All integration tests passing locally

Co-Authored-By: [email protected] <[email protected]>

* Type fix

* Remove businesss logic references from repository methods.

* Move business logic to handler

* Type fix

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-11-25 07:27:07 +00:00
Joe Au-YeungandGitHub e5ebf7feb4 fix: signup (#25334)
* Handle Stripe logic in `paymentCallback`

* Remove endpoint

* Do not send email verification email if premium username

* Remove logic from verify-view

* Callback send verification email

* Add `create` method to `VerificationToken` repository

* Create `VerificationTokenService`

* Early return if payment failed

* Refactor token generation

* Add tests

* Type fixes

* Type fixes
2025-11-21 19:51:19 +00:00
Joe Au-YeungandGitHub dd7c553cc3 fix: Remove hosts - verify event type belongs to event type (#25321)
* Add check that event type belongs to team

* Add `findAcceptedMembershipsByUserIdsInTeam` to `MembershipRepository`

* Validate that passed `userIds` belong to a team

* Add tests

* Typo fix
2025-11-21 10:26:22 -05:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Udit Takkar
dc3df122e2 feat: Add configurable trial days to org subscriptions + wizard warning (#25229)
* feat: Add trial days to organization subscriptions and workspace warning

- Add ORGANIZATION_TRIAL_DAYS environment variable for configurable trial periods
- Implement trial days in Stripe checkout session (only when env var is set)
- Add warning message to organization setup page about workspace structure
- Add translation string for organization trial workspace warning
- Add ORGANIZATION_TRIAL_DAYS to turbo.json env vars
- Fix pre-existing linting warnings in CreateANewOrganizationForm.tsx
- Add ESLint disable comments for turbo/no-undeclared-env-vars warnings

Co-Authored-By: [email protected] <[email protected]>

* Rename variable

* Add trial days to `purchaseTeamOrOrgSubscription`

* fix: Move organization trial warning to spot 3 below form card

- Add optional footer prop to WizardLayout component
- Use footer prop in create-new-view.tsx to render warning at spot 3
- Remove warning from inside CreateANewOrganizationForm component
- Warning now appears below the form card as requested

Co-Authored-By: [email protected] <[email protected]>

* feat: Add organization trial warning to all wizard steps

- Add warning footer to step 2 (about-view.tsx)
- Add warning footer to step 3 (add-teams-view.tsx)
- Add warning footer to step 4 (onboard-members-view.tsx)
- Add warning footer to step 5 (payment-status-view.tsx)
- Add warning footer to resume-view.tsx (step 1 resume page)
- Warning now appears on all steps of the organization creation wizard

Co-Authored-By: [email protected] <[email protected]>

* fix: Correct environment variable name to STRIPE_ORG_TRIAL_DAYS

- Changed ORGANIZATION_TRIAL_DAYS to STRIPE_ORG_TRIAL_DAYS in turbo.json
- This matches the actual usage in OrganizationPaymentService.ts and payments.ts
- Ensures the environment variable is properly recognized by the build system

Co-Authored-By: [email protected] <[email protected]>

* refactor: Create shared OrganizationWizardLayout component

- Create OrganizationWizardLayout component that wraps WizardLayout
- Centralizes the trial warning footer logic in one place
- Update all 6 wizard pages to use the shared component:
  - create-new-view.tsx
  - about-view.tsx
  - add-teams-view.tsx
  - onboard-members-view.tsx
  - payment-status-view.tsx
  - resume-view.tsx
- Remove duplicate useLocale/Alert imports and footer props from pages
- Simplifies maintenance by having warning logic in a single location

Co-Authored-By: [email protected] <[email protected]>

* Fix lint error

* Add `ORG_TRIAL_DAYS` as constant

* Add comment

* Ensure no negative number is passed

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Udit Takkar <[email protected]>
2025-11-20 15:02:01 -03:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
717a26f223 fix: prevent bulk update of locked locations in child managed event types (#24978)
* fix: prevent bulk update of locked locations in child managed event types

- Filter out child managed event types with locked locations in getBulkUserEventTypes
- Add validation in bulkUpdateEventsToDefaultLocation to prevent updating locked fields
- Implements defense in depth with validation at multiple layers

Co-Authored-By: [email protected] <[email protected]>

* Abstract filtering logic

* test: add comprehensive tests for bulk location update filtering

- Add unit tests for filterEventTypesWhereLocationUpdateIsAllowed
- Add unit tests for bulkUpdateEventsToDefaultLocation
- Add integration tests for getBulkUserEventTypes
- Fix bug: change unlockedFields?.locations check from !== undefined to === true
  This ensures that locations: false is properly treated as locked, addressing
  the security issue identified in PR review comments

Co-Authored-By: [email protected] <[email protected]>

* fix: filter locked managed event types on app installation page

- Add parentId to eventTypeSelect in getEventTypes function
- Apply filterEventTypesWhereLocationUpdateIsAllowed to both team and user event types
- Only filter when isConferencing is true to avoid affecting other app types
- Fixes issue where locked managed event types were showing in the event type selection list on /apps/installation/event-types page

Co-Authored-By: [email protected] <[email protected]>

* fix(embed-react): remove obsolete availabilityLoaded event listener

The availabilityLoaded event does not exist in the EventDataMap type system
in embed-core. This code was causing 5 TypeScript errors in CI:
- Type 'availabilityLoaded' does not satisfy constraint 'keyof EventDataMap'
- 'data' is of type 'unknown' (2 occurrences)
- Type 'availabilityLoaded' is not assignable to action union (2 occurrences)

Since this is an example file and the event is not defined in the type system,
removing this obsolete code resolves the type errors.

Co-Authored-By: [email protected] <[email protected]>

* fix: correct Prisma type for metadata in test helper function

Co-Authored-By: [email protected] <[email protected]>

* fix: use flexible PrismaLike type for better test compatibility

Co-Authored-By: [email protected] <[email protected]>

* fix: properly type mock Prisma objects in test files

Co-Authored-By: [email protected] <[email protected]>

* fix: properly mock Prisma methods in test file

Co-Authored-By: [email protected] <[email protected]>

* Filter out metadata

* Undo change in embed file

* Address feedback

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-11-19 15:46:05 -05:00
Joe Au-YeungGitHubcubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Syed Ali Shahbaz
7e4d9e26c6 refactor: implement DI in team billing service and team billing data repository factory (#24803)
* Move TeamBillingRepositories

* WIP refactor team internal billing service

* Remove duplicate billing repository files

* Remove logic check in repository for billing is enabled

* Rename repository to `TeamBillingData`

* Use repository factory in main service

* Fix new import paths

* Rename  to

* Ensure `IS_TEAM_BILLING_ENABLED` is of type boolean

* Rename classes to TeamBillingService and TeamBillingServiceFactory

* Implement DI in `BookingServiceFactory`

* `TeamBillingService` use repository in `getOrgIfNeeded`

* DI `isTeamBillingEnabled` to `TeamBillingServiceFactory`

* Rename files for consistency

* Return stub BillingRepository if billing is not enabled

* Move Stripe billing service to service folder

* Rename file

* `StripeBillingService.getSubscriptionStatus` return `SubscriptionStatus`

* Type fices in StripeBillingService

* Type fix in `stubTeamBillingService`

* DI the `BillingProviderService` into the `TeamBillingService`

* Implement DI in `skipTeamTrials.handler`

* Implement DI for team billing in `inviteMember.handler`

* `skipTeamTrials.handler` use `team.isOrganization`

* Implement DI for billing in `hasActiveTeamPlan.handler`

* Type fixes

* Implement DI in `bulkDeleteUsers.handler`

* Implement `BillingProviderServiceFactory` in `updateProfile.handler`

* Implment `BillingProviderServiceFactory` in `buyCredits.handler`

* Fix import in `stripeCustomer.handler`

* Add a constructor to `teamBillingServiceFactory`

* Add DI to `PrismaTeamBillingRepository`

* Add DI to `StripeBillingService`

* Implement singleton in `BillingProviderServiceFactory`

* Add DI folder and contents to billing folder

* Use `getTeamBillingServiceFactory` in `inviteMember.handler`

* Add `saveTeamBilling` method to `ITeamBillingService`

* Implement DI in new team route

* Implement DI in `teamService`

* Implement DI in `OrganizationPaymentService`

* Implement DI in `credit-service`

* In `StripeBillingService` remove `static` from status methods

* Implemnt DI in `_invoice.paid.org`

* Refactor `hasActiveTeamPlan` to use `getTeamBillingFactory`

* Refactor `skipTeamTrials` to use `getTeamBillingFactory`

* Refactor `skipTeamTrials` to use `getTeamBillingServiceFactory`

* `stripeCustomer.handler` to use `getBillingProviderService`

* Remove old factories

* Type fix

* Remove unused factory

* Refactor `updateProfile.handler` to use `getBillingProviderService`

* Change name to `TeamBillingDataRepositoryFactory`

* Type Prisma return in `prisma.module`

* Type fix

* Refactor `buyCredits.handler` to use `getBillingProviderService`

* Refactor `credit-service` to use billing DI containers

* Type fix

* Add `getTeamBillingDataRepository`

* Refactor `_invoice.paid.org` to use DI container

* Refactor `_customer.subscription.deleted.team-plan` to use DI container

* Refactor `calcomHandler` to use DI container

* Refactor `getCustomerAndCheckoutSession` to use DI container

* Refactor `verify-email` to use DI containers

* Refactor `api/create/route` to use DI container

* Refactor downgradeUsers to use DI container

* Type fix

* Clean up console.logs

* Add await to `this.billingRepository.create` in `saveTeamBilling`

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>

* Fix type errors

* Address comments

* fix: update tests to work with new DI pattern

- Update teamBillingService.test.ts to properly inject DI dependencies
- Remove unused billingModule import and mock
- Fix import naming in teamService.integration-test.ts (remove unused rename)
- Fix import path for TeamBillingPublishResponseStatus

All tests now properly mock IBillingProviderService, ITeamBillingDataRepository,
and IBillingRepository instead of using the old BillingRepositoryFactory pattern.

Co-Authored-By: [email protected] <[email protected]>

* fix: add compatibility layer and env setup for unit tests

- Add STRIPE_PRIVATE_KEY dummy value to vitest.config.ts to prevent DI module errors
- Fix import paths in credit-service.test.ts (StripeBillingService, TeamBillingService)
- Create compatibility barrel at packages/features/ee/billing/teams/index.ts for test mocking

Co-Authored-By: [email protected] <[email protected]>

* fix: update unit tests to mock DI container properly

- Update teamService.test.ts to mock getTeamBillingServiceFactory() instead of TeamBilling.findAndInit
- Update teamService.alternative.test.ts to mock DI container
- Update credit-service.test.ts to mock getBillingProviderService() and use SubscriptionStatus enum values
- Update OrganizationPaymentService.test.ts to mock DI container instead of direct StripeBillingService import
- Remove all 'as any' type casting to comply with Cal.com coding standards
- Fix unused variable warnings by prefixing with underscore

All 53 tests now passing (16 + 1 + 30 + 6)

Co-Authored-By: [email protected] <[email protected]>

* fix: update remaining unit tests to use DI pattern

- Fix StripeBillingService.test.ts to inject mock Stripe client directly
- Fix teamBillingFactory.test.ts to mock getTeamBillingServiceFactory() from DI container
- Fix skipTeamTrials.test.ts to mock DI container and use SubscriptionStatus enum

All 11 previously failing tests now pass (5 + 5 + 1)

Co-Authored-By: [email protected] <[email protected]>

* Undo changes made to Prisma module

* fix: address test-related PR comments

- Fix OrganizationPaymentService.test.ts mock path from @calcom/ee to @calcom/features/ee
- Refactor teamBillingFactory.test.ts to test real factory logic instead of mocking container
- Remove duplicate teamBillingService.test..ts file with incorrect double-dot filename

All three test files now pass successfully with proper DI patterns.

Co-Authored-By: [email protected] <[email protected]>

* Address feedback

* fix: update teamService integration test to mock new DI factory pattern

Co-Authored-By: [email protected] <[email protected]>

* refactor: remove duplicate imports in credit-service.test.ts

Co-Authored-By: [email protected] <[email protected]>

* Remove unused index file

* `getBySubscriptionId` to return team or null

* Address feedback

* Merge fix

* Refactor file names

* fix: correct mockStripe variable name to stripeMock in StripeBillingService.test.ts

Co-Authored-By: [email protected] <[email protected]>

* refactor: update internal-team-billing.test.ts to use new DI structure with TeamBillingService

- Replace InternalTeamBilling with TeamBillingService
- Use constructor injection with mock dependencies instead of factory pattern
- Remove BillingRepositoryFactory mock and import
- Update all test cases to use mockBillingProviderService, mockTeamBillingDataRepository, and mockBillingRepository
- Simplify saveTeamBilling tests to focus on repository.create calls
- All 11 tests now pass with the new DI structure

Co-Authored-By: [email protected] <[email protected]>

* fix: update createWithPaymentIntent.handler.test.ts to mock DI container's getBillingProviderService

- OrganizationPaymentService now uses getBillingProviderService() from DI container
- Test was mocking @calcom/features/ee/payments/server/stripe directly, which no longer works
- Added mock for @calcom/features/ee/billing/di/containers/Billing module
- Mock returns fake billing provider that delegates to mockSharedStripe
- Preserves all existing test assertions and helpers
- Fixed lint error by prefixing unused lastCreatedSessionId with underscore
- All 11 tests now pass (1 skipped as expected)

Co-Authored-By: [email protected] <[email protected]>

---------

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Syed Ali Shahbaz <[email protected]>
2025-11-19 10:21:22 -05:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Hariom Balhara
21411b8f93 docs: update embed-events.mdx with all currently emitted embed events (#25099)
* docs: update embed-events.mdx with all currently emitted embed events

Co-Authored-By: [email protected] <[email protected]>

* docs: remove V2 suffix from event names in documentation

Per feedback, the documentation should not expose internal versioning details.
Event names are now presented as clean, non-versioned names:
- bookingSuccessful (instead of bookingSuccessfulV2)
- rescheduleBookingSuccessful (instead of rescheduleBookingSuccessfulV2)
- dryRunBookingSuccessful (instead of dryRunBookingSuccessfulV2)
- dryRunRescheduleBookingSuccessful (instead of dryRunRescheduleBookingSuccessfulV2)

Added note about using wildcard listener for future-proofing.

Co-Authored-By: [email protected] <[email protected]>

* docs: use V2 suffix for embed event names to match code (#25263)

* docs: update embed events to use V2 event names

- Document bookingSuccessfulV2 instead of deprecated bookingSuccessful
- Document rescheduleBookingSuccessfulV2 instead of deprecated rescheduleBookingSuccessful
- Keep dryRunBookingSuccessful and dryRunRescheduleBookingSuccessful without V2 suffix (only V2 versions exist)
- Add comprehensive event documentation with all public and internal events
- Organize events into Public Events and Internal Events sections

Co-Authored-By: [email protected] <[email protected]>

* fix: use V2 suffix for dry-run event names

- Change dryRunBookingSuccessful to dryRunBookingSuccessfulV2
- Change dryRunRescheduleBookingSuccessful to dryRunRescheduleBookingSuccessfulV2
- These match the actual event names emitted in the code (only V2 versions exist)

Co-Authored-By: [email protected] <[email protected]>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Hariom Balhara <[email protected]>
2025-11-19 08:54:12 +00:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
7635d338c0 fix: increase dropdown z-index to appear above logo (#24057)
- Change dropdown z-index from z-10 to z-50 to ensure dropdowns appear above navigation elements
- TopNav uses z-40, so dropdowns need higher z-index to be properly visible
- Fixes issue where Cal.com logo was appearing above dropdown menus

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-11-18 20:36:03 +00:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
5ceda11a0b fix: add 'use client' to routing-forms components to resolve React error 185 (#25107)
Adds 'use client' directive to FormInputFields.tsx and widgets.tsx in the
routing-forms package. These components use React hooks (useLocale, setState)
but were missing the client directive, causing React error 185 (invalid hook
call) in production builds due to Next.js App Router bundling differences.

The error only occurred in production, not local dev, because production
builds optimize and bundle packages differently. The widgets.tsx file uses
the useLocale hook in the Button component, and FormInputFields.tsx passes
state setters to child components.

Fixes the reroute dialog error reported in production.

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-11-13 18:36:46 +00:00
Joe Au-YeungGitHubAlex van AndelAnik Dhabal BabuDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
787828d0ca feat: Toggle auto adding users to an org if they signup without an invite (#25051)
* Remove auto adding users to an org

* Update tests

* Fix tests

* fix: Update organization invitation E2E tests to not expect auto-accept before signup

- Changed isMemberShipAccepted expectations from true to false before signup
- Users with emails matching orgAutoAcceptEmail are no longer auto-accepted
- They must explicitly accept the invitation after signup
- Fixed lint warnings for unused parameters

Co-Authored-By: [email protected] <[email protected]>

* fix: Update E2E tests to expect pending membership after signup without auto-accept

Since auto-accept functionality was removed, users with emails matching
orgAutoAcceptEmail are no longer automatically accepted into organizations
after signup. They remain in pending state until explicitly accepted.

Updated assertions in:
- 'nonexisting user is invited to Org' test
- 'nonexisting user is invited to a team inside organization' test

Both tests now correctly expect isMemberShipAccepted: false after signup.

Co-Authored-By: [email protected] <[email protected]>

* Restore `verify-email` and tests from `main`

* Add `orgAutoJoinOnSignup` to `organizationSettings`

* Update
`OrganizationRepository.findUniqueNonPlatformOrgsByMatchingAutoAcceptEmail`
to find orgs where `orgAutoJoinOnSignup` is true

* `organization.update` lint fix

* `organization.update` to handle `orgAutoJoinOnSignup`

* Create toggle for `orgAutoJoinOnSignup`

* test: Add comprehensive tests for orgAutoJoinOnSignup functionality

- Update existing test to expect null instead of error when multiple orgs match
- Add test for when orgAutoJoinOnSignup is false (should return null)
- Add test for when orgAutoJoinOnSignup is true (should return org)
- Add test for default behavior (orgAutoJoinOnSignup defaults to true)

These tests verify that the new orgAutoJoinOnSignup setting correctly controls
whether users are automatically added to organizations during email verification.

Co-Authored-By: [email protected] <[email protected]>

* Type fix

* e2e: invited users should be accepted after signup (address cubic r2511916791)

Reverted post-signup isMemberShipAccepted assertions from false to true for
explicit invite scenarios. When users are explicitly invited to an org/team
and complete signup via invite link, their membership should be accepted.

This is distinct from auto-join by domain (controlled by orgAutoJoinOnSignup),
which only affects users who sign up without an invite but match the org's
email domain.

Backend sets membership.accepted = true on invite completion in:
packages/features/auth/signup/utils/createOrUpdateMemberships.ts:61,67,77,83

Co-Authored-By: [email protected] <[email protected]>

* Fix API V2 build

---------

Co-authored-by: Alex van Andel <[email protected]>
Co-authored-by: Anik Dhabal Babu <[email protected]>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-11-13 15:13:10 -03:00
Joe Au-YeungandGitHub 5267f8c3c1 Escape special characters in email query (#25079) 2025-11-11 23:56:51 +00:00
Joe Au-YeungandGitHub 7d17b443cf chore: Add cache log (#24954)
* Add log

* Update getCalendar.ts
2025-11-06 08:24:52 +00:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2dc0e2a6f2 fix: use highest role for org admins accessing sub team event types (#24748)
* fix: use highest role for org admins accessing sub team event types

When an org admin who is also a member of a sub team (but only as MEMBER role) tries to update a sub team event type, they were being denied access. This was because the permission check logic was using the team MEMBER role instead of checking both team and org roles and using the highest one.

This fix updates PermissionCheckService.checkPermission() and checkPermissions() to use the highest role between team membership and org membership, similar to how getEventTypePermissions() already works.

Changes:
- Added getHighestRole() helper method to determine the highest role between two roles
- Updated checkPermission() to check both team and org membership and use the highest role
- Updated checkPermissions() to use the same logic
- Added test case for org admin who is team member updating sub team event type

Fixes the issue where org admins get 'permission required eventType.update' errors when updating sub team event types.

Co-Authored-By: [email protected] <[email protected]>

* test: add PBAC-enabled test case for org admin accessing sub team event types

Adds a test case to verify that when PBAC is enabled, org admins who are also members of a sub team (but only with MEMBER role) can still access sub team event types through their org-level ADMIN permissions.

This complements the existing fallback (PBAC disabled) test case and ensures both code paths handle org admin permissions correctly.

Co-Authored-By: [email protected] <[email protected]>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-10-30 13:59:48 +00:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Udit Takkar
d7df154059 fix: Add critical logger for booking created log to prevent stdout buffering issues (#24570)
* Add critical logger for booking created log to prevent stdout buffering issues

Co-Authored-By: [email protected] <[email protected]>

* Add comment

* Separate critialLogger into it's own file

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Udit Takkar <[email protected]>
2025-10-28 12:59:44 -03:00
Joe Au-YeungandGitHub 4d3727db12 Default fetchCrm to true for getRoutedUrl (#24635) 2025-10-22 14:44:42 +00:00
Joe Au-YeungandGitHub 78c2a69389 Script to reassign attributes (#24496) 2025-10-16 07:06:53 +00:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
bb9c4bb8f3 feat: Update HubSpot meetings to CANCELLED status instead of archiving on booking cancellation (#24478)
* feat: Update HubSpot meetings to CANCELLED status instead of archiving

When a booking is cancelled in Cal.com, preserve the meeting record
in HubSpot by updating it to a CANCELLED status rather than archiving
it. This maintains the meeting history for better tracking and reporting.

Changes:
- Renamed hubspotDeleteMeeting to hubspotCancelMeeting
- Updated the method to set hs_meeting_outcome to CANCELLED
- Changed from archive() to update() API call
- Removed unused CustomPublicObjectInput interface

Co-Authored-By: [email protected] <[email protected]>

* fix: Remove return statement to match void return type in deleteEvent

Co-Authored-By: [email protected] <[email protected]>

* refactor: Remove hs_timestamp from cancel meeting to keep it minimal

Only update the meeting outcome status when cancelling,
without modifying the timestamp field.

Co-Authored-By: [email protected] <[email protected]>

* fix: Use correct HubSpot API value for canceled meetings

Changed hs_meeting_outcome from "CANCELLED" to "CANCELED" to match
HubSpot API specification. HubSpot uses lowercase American spelling
"CANCELED" as the valid enum value for canceled meeting outcomes.

Co-Authored-By: [email protected] <[email protected]>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-10-16 03:38:10 +00:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Alex van Andel
17ab088af8 fix: Faulty logic around shouldServeCache (#24465)
* Should return `false` if no `teamId` is passed to `getShouldServeCache`

* Change  to falsey check

* test: Add comprehensive tests for shouldServeCache fix

- Add tests for CacheService.getShouldServeCache to verify it returns false when no teamId is provided (instead of undefined)
- Add tests for GoogleCalendarService.getFreeBusyResult to verify the falsey check properly handles undefined, null, 0, empty string, and false values
- All tests verify the fix in PR #24465 which changes undefined return to false and changes === false check to !shouldServeCache

Co-Authored-By: [email protected] <[email protected]>

* fix: Resolve type errors in test files

- Fix private credential property access by using type assertion
- Add missing IFeaturesRepository methods to mock

Co-Authored-By: [email protected] <[email protected]>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Alex van Andel <[email protected]>
2025-10-15 11:20:25 +00:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
b312955838 feat: Add subscription start, trial end, and dates to billing tables (#24408)
* Add subscription start, trial end, and end dates to db

* Add subscription start, trial end, and end date to db

* Write subscription start date on new team subscriptions

* Write subscription start date for new orgs

* Fix typo in stripe billing service file (billling -> billing)

* Use `StripeBillingService.extractSubscriptionDates`

* Remove comments

* Address comment

* Fix typo in file import

* Fix typo in file import

* Add missing SubscriptionStatus enum values

- Add INCOMPLETE, INCOMPLETE_EXPIRED, UNPAID, PAUSED enum values
- These values are referenced in stripe-billing-service.ts status mapping
- Fixes type errors in billing-related code

Co-Authored-By: [email protected] <[email protected]>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-10-14 21:12:31 -04:00
Joe Au-YeungandGitHub 4303fb8726 feat: Salesforce - add urql/retry-exchange (#24302)
* Add .env variables

* Add `urql/exchange-retry`

* Add retry mechanic to graphql client

* Only add retries if .env variables are set

* Remove console.log
2025-10-08 14:03:40 +00:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
c702da0334 feat: Add team billing tables (#24148)
* Init billing tables

* Create `IBillingRepository` types

* Create billing repositories

* Create billingRepositoryFactory

* Eslint fix - remove unused organizationOnboarding

* internal-team-billing create saveTeamBilling method using repositories

* On new teams write to team billing table

* On new org write to org billing table

* Change fields to organizationId

* Add todo comment

* Revert "Change fields to organizationId"

This reverts commit bbb2e5dfa6b4c20a8a395f5730848a492cd70d68.

* test: add comprehensive tests for team billing tables

- Fix credit-service.test.ts Prisma mock to export prisma object
- Replace any types with proper TypeScript types in credit-service.test.ts
- Add unit tests for PrismaTeamBillingRepository covering record creation, enum casting, and error handling
- Add unit tests for PrismaOrganizationBillingRepository with same coverage
- Add unit tests for BillingRepositoryFactory to verify correct repository selection
- Add unit tests for InternalTeamBilling.saveTeamBilling() method testing delegation to correct repositories
- All 53 tests pass with TZ=UTC yarn test
- Type checking passes with yarn type-check:ci --force

Co-Authored-By: [email protected] <[email protected]>

* refactor: update saveTeamBilling tests to mock repository interface

- Replace prismaMock usage with BillingRepositoryFactory mock
- Mock IBillingRepository interface instead of Prisma directly
- Follow repository mocking pattern from handleResponse.test.ts
- All tests passing (53 total)

Co-Authored-By: [email protected] <[email protected]>

* Remove log statement

* Remove repository tests

* Address feedback

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-10-07 14:25:31 -04:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
654a865007 refactor: Salesforce getContacts (#24235)
* lint fixes

* Create getContactOrLeadFromEmail method

* Use getContactOrLeadFromEmail in getContacts

* Move normal getContact query

* fix: correct return type in getContactOrLeadFromEmail and add search mock

- Fix getContactOrLeadFromEmail to return single ContactRecord instead of array
- Add conn.search() implementation to salesforceMock for integration tests
- Ensure id field is always string with proper fallbacks for AccountId and Id
- Fix Owner.Email to use undefined instead of null in mock

Co-Authored-By: [email protected] <[email protected]>

* test: add comprehensive tests for getContactOrLeadFromEmail method

- Add 6 new unit tests covering all key scenarios
- Test contact lookup, lead fallback, and preference logic
- Test both roundRobinSkipFallbackToLeadOwner and createEventOnLeadCheckForContact code paths
- Add search mock support to mockConnection in beforeEach
- All 34 tests passing, type-check clean

Co-Authored-By: [email protected] <[email protected]>

* Implement change to error from #24090

* Address feedback

* Type fix

* test: update SOQL query expectations to include Account.OwnerId

Co-Authored-By: [email protected] <[email protected]>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-10-03 14:53:00 -04:00
Joe Au-YeungandGitHub f003ef935b Remove safeStringify from graphql errors (#24188) 2025-10-01 09:50:15 +05:30
b2239374bc fix: Remove team members as org admin (#24020)
* Fallback to org admin

* Prevent accidental privilege escalation as code changes in the future

* When org admin, we don't actually need to do the db query

* Use findMany and Map to drill down permission adjustments

* Exclude .MEMBER from overriding role, we likely don't want to demote

* refactor logic

* Add tests for services/factories + removeHandler

* fix type check

---------

Co-authored-by: Alex van Andel <[email protected]>
Co-authored-by: Sean Brydon <[email protected]>
2025-09-24 09:33:31 +01:00
88391c7942 fix: Handle account user lookup fields for queued form responses (#23811)
* Add constants for queued response id query string

* Ignore eslint - app store imports

* Return `routingFormResponseId` or `queuedFormResponseId` from URL params

* Pass routingForm params to `getTeamMemberEmailForResponseOrContact`

* Handle getting form responses for queued form responses

* Type fix

* add test

* Add tests

---------

Co-authored-by: Hariom Balhara <[email protected]>
Co-authored-by: Udit Takkar <[email protected]>
2025-09-15 11:16:50 +00:00
31270ca86b feat: Write same metadata to Stripe for booking payment and no show fee payment (#23634)
* Add `findBookingById` to `BookingRepository`

* Create `generateMetadata` to Stripe `PaymentService`

* `create` method to use `generateMetadata`

* Remove unused trpc endpoint

* Pass booking id to chargeCard method

* Use generateMetadata in chargeCard method

* Remove unused stripeAppKeys

* Add error handling if booking doesn't contain attendee

* Rename  to

* Return attendees in a consistent order

---------

Co-authored-by: Hariom Balhara <[email protected]>
2025-09-15 14:20:05 +05:30
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
d7397d4563 fix: managed event types inherit team hideBranding setting (#23562)
* fix: managed event types inherit team hideBranding setting

- Add getParentTeamForBranding helper to query parent team data
- Update shouldHideBrandingForEvent to use parent team when eventType.team is null
- Ensures CTA 'create your own booking link with Cal' respects team branding settings
- Follows existing pattern used by eventType.team?.id ?? eventType.parent?.teamId

Co-Authored-By: [email protected] <[email protected]>

* chore: update yarn.lock dependencies

Co-Authored-By: [email protected] <[email protected]>

* Get parent event type team branding

* Use data from getEventTypeFromDB

* Undo yarn.lock changes

* Undo yarn.lock changes from latest main

* Address code commit

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-09-13 08:35:23 +01:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Syed Ali ShahbazAlex van Andel
d6b17b76db test: add comprehensive unit tests for no-show fee payment functions (#23626)
* feat: add time-based cancellation fees for no-show fee events

- Add configurable time threshold (minutes/hours/days) for cancellation fees
- Show warnings during booking submission and cancellation
- Automatically charge fees when bookings cancelled within threshold
- Exempt organizer/admin cancellations from fees
- Extend existing no-show fee infrastructure

Co-Authored-By: [email protected] <[email protected]>

* fix: replace any type with proper type guards for metadata

- Use Record<string, unknown> instead of any for metadata type
- Add proper type assertions for nested metadata properties
- Maintain type safety while avoiding ESLint no-explicit-any warning

Co-Authored-By: [email protected] <[email protected]>

* fix: handle JsonValue type compatibility in shouldChargeCancellationFee

- Add proper type guard for metadata JsonValue from Prisma
- Ensure metadata is object before casting to Record<string, unknown>
- Fixes TypeScript error on line 390 in handleCancelBooking.ts

Co-Authored-By: [email protected] <[email protected]>

* Refactor Devin changes to Stripe options

* Undo Devin changes to advanced tab

* Add translations

* Pass props to CancelBooking

* Display no show fee charge for attendee

* WIP

* Anstract shouldChargeNoSHowCancellationFee

* Abstract `handleNoShowFee`

* Add  to

* Refactor `chargeCard.handler`

* Remove Devin code

* Type fix in `shouldChargeNoShowCancellationFee`

* Create `processNoSHowFeeOnCancellation`

* Process no show fee on cancellation

* Type fix

* Skip processing no show fee if organizer or admin is cancelling

* Add translation

* Dynamically get  and  in

* Remove unused translations

* Undo dev change

* Refactor logic

* Type fix

* remove any

* revert WEBAPP_URL_FOR_OAUTH

* Clean up console.log remnants

* test: add comprehensive tests for time-based cancellation fees

- Add unit tests for shouldChargeCancellationFee function with time thresholds and role exemptions
- Add handleCancelBooking integration tests for organizer/team admin exemptions
- Add handleCancelBooking test for attendee fee charging within time threshold
- Add UI component tests for cancellation fee warning display
- Add E2E test for cancellation fee warning during booking flow

All 23 new tests pass successfully, covering:
- Time-based logic with different units (minutes, hours, days)
- Role-based exemptions (organizer, team admin vs regular attendee)
- Payment charging integration with HOLD payment option
- UI warning display during booking submission and cancellation
- Edge cases like invalid metadata and past bookings

Fixed lint issues:
- Replaced 'any' types with proper Record<string, unknown>
- Fixed Playwright test.skip() usage with ESLint disable comments

Co-Authored-By: [email protected] <[email protected]>

* test: add comprehensive tests for time-based cancellation fees

- Add unit tests for shouldChargeCancellationFee function with time thresholds and role exemptions
- Add handleCancelBooking integration tests for organizer/team admin exemptions
- Add handleCancelBooking test for attendee fee charging within time threshold
- Add UI component tests for cancellation fee warning display
- Add E2E test for cancellation fee warning during booking flow

All unit and integration tests pass successfully. E2E test implementation complete.

Co-Authored-By: [email protected] <[email protected]>

* test: add comprehensive tests for time-based cancellation fees

- Add unit tests for shouldChargeCancellationFee function with time thresholds and role exemptions
- Add handleCancelBooking integration tests for organizer/team admin exemptions
- Add handleCancelBooking test for attendee fee charging within time threshold
- Add UI component tests for cancellation fee warning display
- Add E2E test for cancellation fee warning during booking flow
- Fix TypeScript issues and prettier formatting
- All tests follow existing Cal.com patterns and pass locally

Co-Authored-By: [email protected] <[email protected]>

* test: add comprehensive unit and E2E tests for time-based cancellation fees

- Add unit tests for shouldChargeCancellationFee function with time thresholds and role exemptions
- Add handleCancelBooking integration tests for organizer/team admin exemptions and attendee fee charging
- Add UI component tests for cancellation fee warning display in CancelBooking component
- Add E2E test for cancellation fee warning during booking flow
- Fix TypeScript errors in CancelBooking.tsx with proper type annotations
- All tests follow existing Cal.com patterns and use proper mocking/test utilities

Co-Authored-By: [email protected] <[email protected]>

* Revert dev change

* Add missing translation

* Remove Devin code

* Revert Devin changes

* test: fix attendee cancellation test logic and ensure comprehensive test coverage

- Fix userId in attendee cancellation test to properly test fee charging
- Ensure all test files follow Cal.com patterns with proper mocking
- Add comprehensive coverage for time thresholds, role exemptions, and UI warnings
- All tests pass locally with proper timezone handling

Co-Authored-By: [email protected] <[email protected]>

* Fix tests

* test: add comprehensive unit tests for no-show fee payment functions

- Add unit tests for handleNoShowFee.ts covering successful scenarios, error handling, and edge cases
- Add unit tests for processNoShowFeeOnCancellation.ts covering cancellation logic and payment conditions
- Tests include proper mocking of dependencies and comprehensive coverage of all code paths
- All tests pass with TZ=UTC yarn test and type checking passes

Co-Authored-By: [email protected] <[email protected]>

* Don't block cancel flow for failed payment processing

* Await single attendee getTranslation in `handleNoShowFee`

* Add missing data

* Undo old strings

* Type fix

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Syed Ali Shahbaz <[email protected]>
Co-authored-by: Alex van Andel <[email protected]>
2025-09-05 23:01:52 +01:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Syed Ali Shahbaz
083a162d0e feat: add time-based cancellation fees for no-show fee events (#23595)
* feat: add time-based cancellation fees for no-show fee events

- Add configurable time threshold (minutes/hours/days) for cancellation fees
- Show warnings during booking submission and cancellation
- Automatically charge fees when bookings cancelled within threshold
- Exempt organizer/admin cancellations from fees
- Extend existing no-show fee infrastructure

Co-Authored-By: [email protected] <[email protected]>

* fix: replace any type with proper type guards for metadata

- Use Record<string, unknown> instead of any for metadata type
- Add proper type assertions for nested metadata properties
- Maintain type safety while avoiding ESLint no-explicit-any warning

Co-Authored-By: [email protected] <[email protected]>

* fix: handle JsonValue type compatibility in shouldChargeCancellationFee

- Add proper type guard for metadata JsonValue from Prisma
- Ensure metadata is object before casting to Record<string, unknown>
- Fixes TypeScript error on line 390 in handleCancelBooking.ts

Co-Authored-By: [email protected] <[email protected]>

* Refactor Devin changes to Stripe options

* Undo Devin changes to advanced tab

* Add translations

* Pass props to CancelBooking

* Display no show fee charge for attendee

* WIP

* Anstract shouldChargeNoSHowCancellationFee

* Abstract `handleNoShowFee`

* Add  to

* Refactor `chargeCard.handler`

* Remove Devin code

* Type fix in `shouldChargeNoShowCancellationFee`

* Create `processNoSHowFeeOnCancellation`

* Process no show fee on cancellation

* Type fix

* Skip processing no show fee if organizer or admin is cancelling

* Add translation

* Dynamically get  and  in

* Remove unused translations

* Undo dev change

* Refactor logic

* Type fix

* remove any

* revert WEBAPP_URL_FOR_OAUTH

* Clean up console.log remnants

* test: add comprehensive tests for time-based cancellation fees

- Add unit tests for shouldChargeCancellationFee function with time thresholds and role exemptions
- Add handleCancelBooking integration tests for organizer/team admin exemptions
- Add handleCancelBooking test for attendee fee charging within time threshold
- Add UI component tests for cancellation fee warning display
- Add E2E test for cancellation fee warning during booking flow

All 23 new tests pass successfully, covering:
- Time-based logic with different units (minutes, hours, days)
- Role-based exemptions (organizer, team admin vs regular attendee)
- Payment charging integration with HOLD payment option
- UI warning display during booking submission and cancellation
- Edge cases like invalid metadata and past bookings

Fixed lint issues:
- Replaced 'any' types with proper Record<string, unknown>
- Fixed Playwright test.skip() usage with ESLint disable comments

Co-Authored-By: [email protected] <[email protected]>

* test: add comprehensive tests for time-based cancellation fees

- Add unit tests for shouldChargeCancellationFee function with time thresholds and role exemptions
- Add handleCancelBooking integration tests for organizer/team admin exemptions
- Add handleCancelBooking test for attendee fee charging within time threshold
- Add UI component tests for cancellation fee warning display
- Add E2E test for cancellation fee warning during booking flow

All unit and integration tests pass successfully. E2E test implementation complete.

Co-Authored-By: [email protected] <[email protected]>

* test: add comprehensive tests for time-based cancellation fees

- Add unit tests for shouldChargeCancellationFee function with time thresholds and role exemptions
- Add handleCancelBooking integration tests for organizer/team admin exemptions
- Add handleCancelBooking test for attendee fee charging within time threshold
- Add UI component tests for cancellation fee warning display
- Add E2E test for cancellation fee warning during booking flow
- Fix TypeScript issues and prettier formatting
- All tests follow existing Cal.com patterns and pass locally

Co-Authored-By: [email protected] <[email protected]>

* test: add comprehensive unit and E2E tests for time-based cancellation fees

- Add unit tests for shouldChargeCancellationFee function with time thresholds and role exemptions
- Add handleCancelBooking integration tests for organizer/team admin exemptions and attendee fee charging
- Add UI component tests for cancellation fee warning display in CancelBooking component
- Add E2E test for cancellation fee warning during booking flow
- Fix TypeScript errors in CancelBooking.tsx with proper type annotations
- All tests follow existing Cal.com patterns and use proper mocking/test utilities

Co-Authored-By: [email protected] <[email protected]>

* Revert dev change

* Add missing translation

* Remove Devin code

* Revert Devin changes

* test: fix attendee cancellation test logic and ensure comprehensive test coverage

- Fix userId in attendee cancellation test to properly test fee charging
- Ensure all test files follow Cal.com patterns with proper mocking
- Add comprehensive coverage for time thresholds, role exemptions, and UI warnings
- All tests pass locally with proper timezone handling

Co-Authored-By: [email protected] <[email protected]>

* Fix tests

* Remove reverted PR translations

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Syed Ali Shahbaz <[email protected]>
2025-09-05 21:46:54 +04:00
Joe Au-YeungandGitHub 25c20e5093 fix: Handle personal billing portal on backend (#23521) 2025-09-02 13:08:04 -04:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
f1d1674693 feat: allow organization owners access to shared billing portal (#23451)
* feat: allow organization owners access to shared billing portal

- Modify stripepayment portal endpoint to accept teamId parameter
- Use team's subscription ID to get customer ID from Stripe subscription
- Validate user permissions before allowing team billing access
- Update platform and regular billing views to pass teamId
- Maintain backward compatibility with individual user billing

Co-Authored-By: [email protected] <[email protected]>

* Add `getTeamByIdIfUserIsAdmin` to `TeamRepository`

* Add `getSubscriptionFromId` function

* Generate portal URL via the team's subscription not the requesting
user's customerId

* Pass teamId to `/portal` endpoint

* Undo Devin change to platform billing

* Address coderabbit comments

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-09-01 08:07:36 +05:30
Joe Au-YeungandGitHub bfa23ddb80 refactor: Remove app store index (#23449)
* Remove app store index

* Remove reliance on app-store mock

* Remove app store mock
2025-08-29 18:41:07 +00:00
Joe Au-YeungandGitHub 1fd1202373 fix: Allow install on teams for concurrent meeting apps (#23429) 2025-08-29 09:59:47 -04:00
Joe Au-YeungandGitHub 84bd4d3d38 Remove payment fee from chargeCard (#23411) 2025-08-28 08:07:52 +00:00
b2244503b1 fix: Missing jose module in saml-jackson package (#23291)
* Ensure packages are bundled with code

* Update dependencies

---------

Co-authored-by: Alex van Andel <[email protected]>
2025-08-25 15:36:31 +01:00
2d90d11e9e feat: Add custom label for organizer default app and link meeting (#23114)
* Create `CalVideoSettings` type

* Create `LocationOptionContainer`

* Extract cal video settings to `CalVideoSettings`

* Refactor `<Locations />` component to use `<CalVideoSettings />`

* Unify naming

* Move location folder back under components

* Type fixes

* Extract types

* Add custom label prop to default app types

* Extract `LocationInput` component

* Create `DefaultLocationSettings` component

* Move `locations` folder

* Add custom label field for link and organizer default locations

* Type fixes

* Save the custom label in db

* Include location custom label when querying db

* Display custom label on booking page

* Add translations

* Type fixes

* Change `customLabel` to `supportsCustomLabel`

* Remove unused code

* Show the customLabel on booking page

* Fix hover tooltip text as well

* Fix displaying exact value on booking page

* Add missing translation

* Remove default label of "Value"

* Replace nullish collescing with OR

* Replace nullish collescing with OR

---------

Co-authored-by: Hariom Balhara <[email protected]>
Co-authored-by: Udit Takkar <[email protected]>
2025-08-22 16:34:14 +00:00
Joe Au-YeungandGitHub b9aee3b18c fix: Add guests via URL param even if field is hidden (#23229)
* Add guests via URL param even if field is hidden

* Clean up
2025-08-21 02:27:52 +00:00
Joe Au-YeungGitHubAlex van Andelcoderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
cf13c06c57 chore: Upgrade boxyhq/saml-jackson to 1.52.2 (#23231)
* Upgrade jackson to 1.52.2

* Update apps/web/package.json

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Remove unused option prop

---------

Co-authored-by: Alex van Andel <[email protected]>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-20 23:13:36 +01:00
Joe Au-YeungandGitHub f9e24f51a7 refactor: Extract <CalVideoSettings /> from `<Locations /> (#23113)
* Create `CalVideoSettings` type

* Create `LocationOptionContainer`

* Extract cal video settings to `CalVideoSettings`

* Refactor `<Locations />` component to use `<CalVideoSettings />`

* Unify naming

* Move location folder back under components

* Type fixes

* Delete console.log
2025-08-19 10:24:28 +00:00
ff79064ca7 fix: Managed event types - children inherit team's appearance settings (#23116)
* Get parent event type team's appearance settings

* Use style profile to get brand colours

* Update packages/features/eventtypes/lib/getPublicEvent.ts

---------

Co-authored-by: Hariom Balhara <[email protected]>
2025-08-19 05:52:27 +00:00
Joe Au-YeungandGitHub ed6f9d8252 fix: Add cal.eu to IS_CALCOM (#23111)
* Add cal.eu to `IS_CALCOM`

* Create `getCalcomUrl` function

* Use `getCalcomURl` in generate metadata

* Use `getCalcomURl` in `buildCanonical`

* Linting fix
2025-08-18 16:04:48 +05:30
Joe Au-YeungandGitHub ab703a4346 Add and to (#23020) 2025-08-12 16:44:02 +01:00
Joe Au-YeungandGitHub 4baa9b6bc1 wrap samlResponse in try/catch (#22984) 2025-08-08 16:06:18 +00:00
bf8f966811 chore: Add logging to SAML endpoints (#22968)
* Add logging to SAML endpoints

* Update packages/features/auth/lib/next-auth-options.ts

---------

Co-authored-by: Hariom Balhara <[email protected]>
2025-08-08 11:50:46 +01:00
Joe Au-YeungandGitHub cfefba6d4d Revert "perf: use repository for webhooks list query & caching in /settings/developer/webhooks/... RSC (#21781)" (#22963) 2025-08-07 11:55:13 -07:00
Joe Au-YeungandGitHub 815e13303b Compare membership with teamId (#22957) 2025-08-07 15:07:21 +00:00
Joe Au-YeungGitHubcoderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>Alex van Andel
b7e11dc112 chore: Add logging to handleNewBooking (#22868)
* Add logging

* Apply suggestion from @coderabbitai[bot]

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Update logger config, fix Create booking log

* Added oooExcludedDateRanges + type error fix

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Alex van Andel <[email protected]>
2025-08-02 17:15:30 +01:00
Joe Au-YeungandGitHub 91932212e3 fix: Cal Video sidebar not showing meeting time in timezone (#22821)
* Pass params as object to `formatToLocalizedTime`

* Refactor videos-single-view

* Refactor bookings-single-view
2025-07-31 16:34:02 -04:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
f81bb92beb fix: increment iCalSequence when changing booking location (#22847)
* fix: increment iCalSequence when changing booking location

- Add iCalSequence parameter to buildCalEventFromBooking function
- Update editLocation handler to increment sequence by 1 in CalendarEvent
- Update database with incremented iCalSequence when location changes
- Update buildCalEventFromBooking test to include new fields
- Ensures ICS files properly update existing calendar events instead of creating duplicates

Co-Authored-By: [email protected] <[email protected]>

* `BookingRepository.updateLocationById` to accept responses and iCalSequence

* `editLocation.handler` use `BookingRepository`

* Update iCalSequence

* Use iCalSequence from booking param

* Add iCalUID to evt object

* Clean up

* Fix test

* Fix test

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-07-31 20:58:48 +01:00
f7b201b0b5 fix: Return empty available days if error querying calendar (#22828)
* Return a busy block placeholder if calendar throws an error

* Refactor `getCalendarsEvents` to return an object with a success prop

* Throw error in `getBusyTimes` if failed to fetch calendar availability

* Return empty available days if error getting busy times

* yeet.

* Type fix

* Fix type error in getLuckyUsers

* Type fixes

* Type fix

* Type fix

* Fix test

* Fix test mocks

* Refactor calendars.service to use new calendarBusyTimesQuery

---------

Co-authored-by: Alex van Andel <[email protected]>
2025-07-31 02:09:09 +01:00
Joe Au-YeungandGitHub 704bbf2757 chore: Refactor logs (#22824)
* Refactor logs

* Add specific info to log
2025-07-31 01:47:38 +01:00
Joe Au-YeungandGitHub 4e92b6edeb chore: Log availability snapshot when booking is created (#22782)
* Add userAvailability type

* Add user availability to return value of getUsersAvailability

* Log availabilitySnapshot when booking is created

* Type fix
2025-07-29 12:10:21 -04:00
Joe Au-YeungGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
6c936472d2 feat: add cancelledBy and rescheduledBy parameters to workflow links (#22438)
* feat: add cancelledBy and rescheduledBy parameters to workflow links

- Extended workflow reminder selection to include user and team data
- Added getWorkflowAssigneeEmail helper function to resolve assignee email
- Updated email and SMS workflow templates to include assignee in cancel/reschedule links
- For user workflows, uses user email; for team workflows, uses team owner email
- Maintains backward compatibility when assignee data is unavailable

Co-Authored-By: [email protected] <[email protected]>

* fix: use workflow recipient email instead of assignee email for link parameters

- Updated getWorkflowRecipientEmail to determine recipient based on workflow action type
- EMAIL_ADDRESS uses sendTo email, EMAIL_HOST uses organizer, EMAIL_ATTENDEE uses attendee
- SMS_ATTENDEE/WHATSAPP_ATTENDEE use attendee email for cancelledBy/rescheduledBy params
- Maintains backward compatibility when recipient data unavailable

Co-Authored-By: [email protected] <[email protected]>

* fix: use emailReminderManager for email workflows with recipient parameters

- Updated emailReminderManager to include recipient email in cancel/reschedule links
- Added getEmailWorkflowRecipientEmail function for proper recipient determination
- Removed changes from deprecated scheduleEmailReminders.ts
- SMS_ATTENDEE correctly uses attendee email like EMAIL_ATTENDEE

Co-Authored-By: [email protected] <[email protected]>

* Get attendee's email when sending SMS

* Remove unused query

* feat: add cancelledBy and rescheduledBy parameters to getSMSMessageWithVariables

Co-Authored-By: [email protected] <[email protected]>

* Clean up Devin

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-07-28 16:43:23 +00:00