Skip to content

feat: refactor Deel app to OAuth integration with automatic time-off creation #22442

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 24 commits into
base: main
Choose a base branch
from

Conversation

devin-ai-integration[bot]
Copy link
Contributor

@devin-ai-integration devin-ai-integration bot commented Jul 12, 2025

Schema Refactoring for OutOfOfficeReason with Dynamic HRMS Integration

Summary

This PR implements schema refactoring for the OutOfOfficeReason model to support dynamic HRMS integration, specifically allowing OOO reasons to be fetched from external HRMS providers like Deel. The changes include:

  • Schema Changes: Made reason field non-unique and externalId field unique in OutOfOfficeReason model
  • Dynamic Reason Fetching: Modified outOfOfficeReasons.handler.ts to fetch and return HRMS policies when credentials are available
  • Modal Updates: Updated CreateOrEditOutOfOfficeModal to handle mixed ID types (numeric for static reasons, string for HRMS reasons)
  • Backend Integration: Modified createOOO/updateOOO handlers to use externalId directly as time_off_type_id instead of fetching from getTimeOffId
  • Type Safety: Updated interfaces and handlers to support union types for reason IDs

The implementation maintains backward compatibility - existing OOO functionality continues to work unchanged, while HRMS integration is activated when credentials are present.

Review & Testing Checklist for Human

  • Test schema migration locally - Verify the migration runs successfully and doesn't break existing OutOfOfficeReason data
  • End-to-end HRMS integration testing - Test the complete flow from Deel credential setup to OOO creation with dynamic reasons
  • Fallback behavior verification - Ensure the modal gracefully falls back to static reasons when HRMS credentials are missing or API calls fail
  • Backward compatibility testing - Verify existing OOO entries still work correctly and can be edited/deleted
  • Type safety validation - Test that the union type handling for reasonId works correctly in all scenarios (numeric IDs for static reasons, string IDs for HRMS reasons)

Recommended Test Plan:

  1. Test OOO creation/editing without HRMS credentials (should use static reasons)
  2. Set up Deel credentials and test OOO creation with dynamic reasons
  3. Test error scenarios (API failures, expired tokens)
  4. Verify existing OOO entries are not affected by the changes

Diagram

%%{ init : { "theme" : "default" }}%%
graph TD
    A["packages/prisma/schema.prisma<br/>OutOfOfficeReason model"]:::major-edit
    B["packages/trpc/server/routers/viewer/ooo/<br/>outOfOfficeReasons.handler.ts"]:::major-edit
    C["packages/features/settings/outOfOffice/<br/>CreateOrEditOutOfOfficeModal.tsx"]:::major-edit
    D["packages/trpc/server/routers/viewer/ooo/<br/>outOfOfficeCreateOrUpdate.handler.ts"]:::major-edit
    E["packages/app-store/deel/lib/<br/>HrmsService.ts"]:::minor-edit
    F["packages/lib/hrmsManager/<br/>hrmsManager.ts"]:::minor-edit
    G["packages/types/<br/>HrmsService.d.ts"]:::minor-edit
    H["Database Migration"]:::context

    A --> H
    B --> C
    B --> E
    D --> F
    F --> E
    C --> D
    G --> F

    A -.->|"Schema: reason non-unique,<br/>externalId unique"| B
    B -.->|"Dynamic reasons<br/>with fallback"| C
    C -.->|"Mixed ID types<br/>(string/number)"| D
    D -.->|"Uses externalId as<br/>time_off_type_id"| E

    subgraph Legend
        L1[Major Edit]:::major-edit
        L2[Minor Edit]:::minor-edit
        L3[Context/No Edit]:::context
    end

    classDef major-edit fill:#90EE90
    classDef minor-edit fill:#87CEEB
    classDef context fill:#FFFFFF
Loading

Notes

  • Session: Requested by anik@cal.com and amit@cal.com in Devin session
  • Migration: Created migration 20250715045153_make_reason_non_unique_and_external_id_unique
  • CI Status: All code-specific checks pass (Type check, Unit tests, Linting, Security). Only "required" meta check fails (GitHub configuration issue)
  • Risk Level: 🟡 Medium - Schema changes and complex type handling require careful testing
  • Backward Compatibility: Maintained - existing OOO functionality unaffected

…creation

- Convert Deel app from redirect-only to full OAuth integration
- Add OAuth authorization flow with Deel API
- Implement DeelService for time-off request creation
- Integrate with OOO system to automatically create Deel time-off requests
- Follow existing Cal.com OAuth patterns (similar to HubSpot integration)
- Add proper credential storage and token management
- Update app metadata and configuration for OAuth template

Co-Authored-By: anik@cal.com <anik@cal.com>
Copy link
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

Copy link

vercel bot commented Jul 12, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

2 Skipped Deployments
Name Status Preview Comments Updated (UTC)
cal ⬜️ Ignored (Inspect) Visit Preview Jul 25, 2025 4:35pm
cal-eu ⬜️ Ignored (Inspect) Visit Preview Jul 25, 2025 4:35pm

Copy link

delve-auditor bot commented Jul 12, 2025

No security or compliance issues detected. Reviewed everything up to e58c2c6.

Security Overview
  • 🔎 Scanned files: 55 changed file(s)
Detected Code Changes

The diff is too large to display a summary of code changes.

Reply to this PR with @delve-auditor followed by a description of what change you want and we'll auto-submit a change to this PR to implement it.

Copy link
Contributor

github-actions bot commented Jul 12, 2025

E2E results are ready!

@anikdhabal anikdhabal self-assigned this Jul 12, 2025
@anikdhabal anikdhabal marked this pull request as ready for review July 12, 2025 09:43
@graphite-app graphite-app bot requested a review from a team July 12, 2025 09:43
@dosubot dosubot bot added app-store area: app store, apps, calendar integrations, google calendar, outlook, lark, apple calendar authentication area: authentication, auth, google sign in, password, SAML, password reset, can't log in ✨ feature New feature or request labels Jul 12, 2025
Copy link

graphite-app bot commented Jul 12, 2025

Graphite Automations

"Add consumer team as reviewer" took an action on this PR • (07/12/25)

1 reviewer was added to this PR based on Keith Williams's automation.

@anikdhabal
Copy link
Contributor

@cubic-dev-ai pls review

Copy link
Contributor

cubic-dev-ai bot commented Jul 12, 2025

@anikdhabal I've started the AI code review. It'll take a few minutes to complete.

import type { DeelToken } from "../api/callback";

export interface DeelTimeOffRequest {
employee_id: string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is wrong. As per thier docs we need to pass recipient_profile_id (The hris profile id of the recipient) instead of it. So pls fix it

devin-ai-integration bot and others added 2 commits July 12, 2025 14:37
…and time_off_type_id

- Replace employee_id with recipient_profile_id in DeelTimeOffRequest interface
- Replace time_off_type with time_off_type_id in DeelTimeOffRequest interface
- Add new interfaces for DeelTimeOffType, DeelPolicy, and DeelPoliciesResponse
- Rename getEmployeeId to getRecipientProfileId method
- Add getTimeOffTypeId method to fetch time-off types from List Policies endpoint
- Update OOO handler to use new method names and correct API field structure
- Implement logic to select appropriate time-off type (prioritizing vacation/PTO)

Co-Authored-By: anik@cal.com <anik@cal.com>
…pient_profile_id and policies array from List Policies response

Co-Authored-By: anik@cal.com <anik@cal.com>
- Add deelTimeOffId field to OutOfOfficeEntry schema for storing Deel time-off IDs
- Implement updateTimeOff and deleteTimeOff methods in DeelService
- Integrate update operations in outOfOfficeCreateOrUpdate handler
- Integrate delete operations in outOfOfficeEntryDelete handler
- Support complete lifecycle: create → update → delete for Deel time-off requests

Co-Authored-By: anik@cal.com <anik@cal.com>
@devin-ai-integration devin-ai-integration bot requested a review from a team as a code owner July 12, 2025 15:16
- Create HrmsService interface similar to CrmService for HRMS operations
- Implement HrmsManager class following CrmManager pattern for service instantiation
- Add getHrms utility function for mapping credential types to HRMS services
- Generate HrmsServiceMap for auto-mapping HRMS apps to their services
- Refactor Deel integration to implement HrmsService interface instead of direct imports
- Update OOO handlers to use HrmsManager instead of direct Deel service imports
- Add HRMS service generation to app-store-cli build process
- Update Deel app config to include 'hrms' category
- Maintain full CRUD operations (create, update, delete) for time-off requests
- Architecture supports multiple HRMS providers for future extensibility

Co-Authored-By: anik@cal.com <anik@cal.com>
@github-actions github-actions bot added the High priority Created by Linear-GitHub Sync label Jul 14, 2025
Co-Authored-By: anik@cal.com <anik@cal.com>
- Make reason field non-unique and externalId field unique in OutOfOfficeReason schema
- Add externalId to HRMS mapped response in outOfOfficeReasons.handler.ts
- Update CreateOrEditOOOModal to use policy.name/policy.id as label/value when externalId is present
- Modify createOOO/updateOOO to use externalId as time_off_type_id instead of fetching from getTimeOffId
- Add proper type safety for union types in modal dropdown
- Update HrmsManager and HrmsService interfaces to support externalId parameter
- Ensure backward compatibility for regular OOO without HRMS integration

Co-Authored-By: anik@cal.com <anik@cal.com>
type: "deel_other",
title: "Deel Time Off",
variant: "other",
categories: ["other"],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
categories: ["other"],
categories: ["other", "hrms"],

await createOAuthAppCredential({ appId: metadata.slug, type: metadata.type }, deelToken, req);

res.redirect(
getSafeRedirectUrl(state?.returnTo) ?? getInstalledAppPath({ variant: "other", slug: "deel" })
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
getSafeRedirectUrl(state?.returnTo) ?? getInstalledAppPath({ variant: "other", slug: "deel" })
getSafeRedirectUrl(state?.returnTo) ?? getInstalledAppPath({ variant: "hrms", slug: "deel" })

"isTemplate": false,
"__createdUsingCli": true,
"__template": "link-as-an-app",
"__template": "oauth",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"__template": "oauth",
"__template": "link-as-an-app",

use cli to change this

}
}
} catch (error) {
console.error("Failed to create/update HRMS time-off request:", error);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use the logger in @lib/logger for loggin failures for debugging in prod

…or credentialId_externalId

Co-Authored-By: anik@cal.com <anik@cal.com>
…tialsByUserIdAndCategory method

- Rename findHrmsCredentialsByUserId to findCredentialsByUserIdAndCategory for reusability
- Add category parameter to support future CRM, calendar, and other app integrations
- Update all OOO handlers to use the new centralized method
- Eliminate ~30+ lines of repetitive credential fetching code
- Maintain existing functionality while improving maintainability

Co-Authored-By: anik@cal.com <anik@cal.com>
devin-ai-integration bot and others added 2 commits July 17, 2025 07:34
- Add webhook endpoint with signature verification using x-deel-signature header
- Handle time-off.created events with status APPROVED only
- Fetch user details from Deel API using requester.id and match by email
- Create OOO entries with proper policy mapping using externalId
- Add webhook_signing_key to Deel app configuration schema
- Export webhook endpoint from Deel API index
- Fix HRMS service import to use named export pattern

Co-Authored-By: anik@cal.com <anik@cal.com>
devin-ai-integration bot and others added 2 commits July 17, 2025 11:28
… pattern

- Add createOOOEntry and upsertOOOReason methods to PrismaOOORepository
- Add findByEmailCaseInsensitive method to UserRepository
- Add findManyByCategoryAndAppSlug method to CredentialRepository
- Refactor webhook handlers to use repository methods instead of direct Prisma calls

Co-Authored-By: anik@cal.com <anik@cal.com>
… DeelHrmsService from imported module

Co-Authored-By: anik@cal.com <anik@cal.com>
Copy link
Contributor Author

Closing due to inactivity for more than 7 days. Configure here.

Copy link
Contributor

github-actions bot commented Aug 9, 2025

This PR is being marked as stale due to inactivity.

@github-actions github-actions bot added the Stale label Aug 9, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
app-store area: app store, apps, calendar integrations, google calendar, outlook, lark, apple calendar authentication area: authentication, auth, google sign in, password, SAML, password reset, can't log in ✨ feature New feature or request High priority Created by Linear-GitHub Sync ❗️ migrations contains migration files ready-for-e2e Stale
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants