Files
calendar/packages/app-store/salesforce
Joe Au-YeungGitHubjoe@cal.com <j.auyeung419@gmail.com>Devin 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: joe@cal.com <j.auyeung419@gmail.com>

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

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

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

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

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

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

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

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* 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: joe@cal.com <j.auyeung419@gmail.com>

* chore: reformat getAttributes.ts

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* 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 <noreply@anthropic.com>

* 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 <noreply@anthropic.com>

* 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 <noreply@anthropic.com>

* 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 <noreply@anthropic.com>

* 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 <noreply@anthropic.com>

* 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: joe@cal.com <j.auyeung419@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 23:03:19 -05:00
..

Creating a Salesforce test org

You must have the Salesforce CLI installed to create a test org. Once installed, you can create a test org using the following command yarn scratch-org:create

This will create a scratch org with the configuration specified in the project-scratch-def.json file.

To open a browser tab to the org, run yarn scratch-org:start

Working With GraphQL

This package utilizes GraphQL Codegen to generate types and queries from the Salesforce schema.

Generating GraphQL Schema

Currently v63 of the Salesforce graphql endpoint throws an error when trying to generate files. This is due to the Setup__JoinInput type not generating any fields. To work around this, the schema.json file comes from the Salesforce graphql introspection query. This file is then converted to a SDL file using the graphql-introspection-json-to-sdl package. You can generate the SDL file by running yarn generate:schema.

Generating Queries

When working with graphql files ensure that yarn codegen:watch is running in the background. This will generate the types and queries from the SDL file.

Developing the SFDC package

The SFDC package is written using Apex. To develop this package, you need to have the Salesforce CLI installed. Then you can run yarn sfdc:deploy:preview to see what changes will be deployed to the scratch org. Running yarn sfdc:deploy will deploy the changes to the scratch org.

Note that if you want to call your local development instances you need to change the "Named Credential" on the scratch org settings to point the CalCom_Development credential to the local instance.

Publishing the SFDC Package

All commands should be run from the sfdc-package directory:

cd packages/app-store/salesforce/sfdc-package

Initial Setup (One-time)

If the package doesn't exist yet in the Dev Hub, create it:

sf package create \
  --name "calcom-sfdc-package" \
  --package-type Unlocked \
  --path force-app \
  --target-dev-hub team@cal.com

This registers the package and updates sfdx-project.json with the package ID.

Creating a New Package Version

Each time you want to release changes, create a new version:

sf package version create \
  --package "calcom-sfdc-package" \
  --installation-key-bypass \
  --wait 20 \
  --target-dev-hub team@cal.com

Options:

  • --installation-key-bypass: Allows installation without a password
  • --wait 20: Waits up to 20 minutes for completion
  • --code-coverage: Add this flag when ready to promote (requires 75% Apex test coverage)

Viewing Packages and Installation URLs

List all package versions:

sf package version list --target-dev-hub team@cal.com

The installation URL format is:

https://login.salesforce.com/packaging/installPackage.apexp?p0=<04t_SUBSCRIBER_PACKAGE_VERSION_ID>

Promoting for Production

Beta versions can only be installed in sandboxes/scratch orgs. To allow installation in production orgs, promote the version:

sf package version promote \
  --package "calcom-sfdc-package@X.X.X-X" \
  --target-dev-hub team@cal.com

Replace X.X.X-X with the version number (e.g., 0.1.0-1).

Running Tests

To run Apex tests and check code coverage:

sf project deploy start --target-org <org-alias>
sf apex run test --test-level RunLocalTests --wait 10 --target-org <org-alias>