Skip to content

feat: Implement Salesforce to DocuSign contract automation integration - #58

Open
iamvirul wants to merge 51 commits into
wso2:mainfrom
iamvirul:integration-sample-for-docusign-salesforce
Open

feat: Implement Salesforce to DocuSign contract automation integration#58
iamvirul wants to merge 51 commits into
wso2:mainfrom
iamvirul:integration-sample-for-docusign-salesforce

Conversation

@iamvirul

@iamvirul iamvirul commented Mar 12, 2026

Copy link
Copy Markdown
Member

Fixes: https://github.com/wso2-enterprise/integration-engineering/issues/71

  • Created README.md with setup instructions, prerequisites, and configuration details for Salesforce and DocuSign.
  • Developed agents.bal for future AI-powered features, including opportunity complexity analysis and intelligent template selection.
  • Implemented automation.bal for core logic to create and send DocuSign envelopes based on Salesforce opportunity updates.
  • Configured connections.bal for Salesforce and DocuSign client initialization.
  • Established data_mappings.bal for transforming Salesforce data to DocuSign format.
  • Added functions.bal for retrieving opportunity and contact details from Salesforce.
  • Created main.bal to handle Salesforce listener events for opportunity changes.
  • Defined types.bal for Salesforce and DocuSign data structures, including opportunity, contact, and template configurations.
  • Introduced error handling and logging throughout the integration for better observability.

Summary by CodeRabbit

  • New Features

    • Salesforce → DocuSign contract automation: real-time listener, end-to-end envelope creation/sending, template selection, signer/CC handling, field mapping, idempotency checks, and opportunity stage updates.
    • New configurable surface for credentials, templates, business rules, expiration and reminder settings.
    • Lightweight AI scaffold for future template recommendations.
  • Documentation

    • Added setup guide, configuration schema, process diagram, examples and troubleshooting for deployment and local runs.

- Added integration prompt detailing the functionality and requirements for automating contract dispatch from Salesforce to DocuSign.
- Created README.md with setup instructions, prerequisites, and configuration details for Salesforce and DocuSign.
- Developed agents.bal for future AI-powered features, including opportunity complexity analysis and intelligent template selection.
- Implemented automation.bal for core logic to create and send DocuSign envelopes based on Salesforce opportunity updates.
- Configured connections.bal for Salesforce and DocuSign client initialization.
- Established data_mappings.bal for transforming Salesforce data to DocuSign format.
- Added functions.bal for retrieving opportunity and contact details from Salesforce.
- Created main.bal to handle Salesforce listener events for opportunity changes.
- Defined types.bal for Salesforce and DocuSign data structures, including opportunity, contact, and template configurations.
- Introduced error handling and logging throughout the integration for better observability.
@coderabbitai

coderabbitai Bot commented Mar 12, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a Ballerina integration that listens for Salesforce Change Events and automates DocuSign envelope creation: types, configuration, client connections, listener service, orchestration and helpers, AI scaffolding, documentation, and Choreo metadata.

Changes

Cohort / File(s) Summary
Project manifests & ignore
ballerina-integrator/salesforce-closewon-contract-automation/Ballerina.toml, ballerina-integrator/salesforce-closewon-contract-automation/Dependencies.toml, ballerina-integrator/salesforce-closewon-contract-automation/.gitignore
Add Ballerina project manifest, dependency lock/resolution file, and .gitignore entries for build/generated/config artifacts.
Choreo metadata & docs
ballerina-integrator/salesforce-closewon-contract-automation/.choreo/config-schema.json, ballerina-integrator/salesforce-closewon-contract-automation/.choreo/diagram.md, ballerina-integrator/salesforce-closewon-contract-automation/.choreo/instructions.md
Add JSON Schema for runtime config, Mermaid workflow diagram, and Choreo deployment/setup instructions with examples.
Repository docs
ballerina-integrator/salesforce-closewon-contract-automation/README.md
New README describing integration flow, prerequisites, configuration, deployment, running, and troubleshooting.
Public types
ballerina-integrator/salesforce-closewon-contract-automation/types.bal
Introduce domain and DTO types: Opportunity, Contact, OpportunityContactRole, EnvelopeRequest, SignerInfo, CarbonCopy, TemplateConfig, CcRecipient, FieldMapping, and SignerRole enum.
Configuration
ballerina-integrator/salesforce-closewon-contract-automation/config.bal
Add public configurable declarations for Salesforce and DocuSign credentials, template configs, signer/CC defaults, field mappings, business rules, expiration and stage settings.
Connections & listener
ballerina-integrator/salesforce-closewon-contract-automation/connections.bal, ballerina-integrator/salesforce-closewon-contract-automation/main.bal
Instantiate Salesforce and DocuSign clients (OAuth refresh), define listener config and salesforce listener, and add Change Events service with handlers; onUpdate triggers processing.
Core orchestration & helpers
ballerina-integrator/salesforce-closewon-contract-automation/automation.bal, ballerina-integrator/salesforce-closewon-contract-automation/functions.bal, ballerina-integrator/salesforce-closewon-contract-automation/data_mappings.bal
Implement processOpportunityForContract orchestration, envelope creation/sending, template selection, field mapping, contact resolution, validation, Salesforce read/update helpers, and data mapping utilities.
AI scaffolding
ballerina-integrator/salesforce-closewon-contract-automation/agents.bal
Add placeholder AI helper functions for opportunity complexity analysis and template recommendation scaffold.

Sequence Diagram

sequenceDiagram
    participant Salesforce as Salesforce (Change Event)
    participant Listener as SalesorceListener
    participant Processor as ContractProcessor
    participant SF_API as Salesforce API
    participant DS_API as DocuSign API

    Salesforce->>Listener: onUpdate(eventData)
    Listener->>Processor: processOpportunityForContract(opportunityId)
    Processor->>SF_API: getOpportunity(opportunityId)
    SF_API-->>Processor: Opportunity
    Processor->>Processor: validate & meetsDispatchCriteria
    Processor->>SF_API: getContactByRole / getPrimaryContact (fallback)
    SF_API-->>Processor: Contact
    Processor->>Processor: selectTemplate, buildTemplateFields, buildEnvelope
    Processor->>DS_API: createAndSendEnvelope(envelopeDefinition)
    DS_API-->>Processor: envelopeId / status
    Processor->>SF_API: updateOpportunityStage(opportunityId, "Contract Sent", envelopeId)
    SF_API-->>Processor: updateResult
    Processor-->>Listener: complete (log)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐇 I hop on change events with a twitch and a grin,
I stitch fields to templates and tuck signatures in,
Envelopes leap, reminders drum a soft tune,
Logs whisper secrets beneath the bright moon,
A rabbit applauds the contracts that soon swoon.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description provides a high-level overview of all implemented files and references the resolved issue (#71). However, it lacks coverage of most required template sections including Purpose, Goals, Approach, User stories, Release notes, Documentation, Training, Certification, Marketing, detailed test coverage, Security checks, Samples, and Test environment details. Complete the PR description by filling in all required template sections, particularly Purpose with linked issues, Goals, Approach, User stories, Release notes, Documentation links, Security checks (secure coding, FindSecurityBugs, secrets verification), and Test environment details.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main feature being added: a Salesforce to DocuSign contract automation integration. It is concise, avoids vague terms, and accurately reflects the primary change across the entire changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 10

🧹 Nitpick comments (2)
ballerina-integrator/salesforce-closewon-contract-automation/.choreo/instructions.md (1)

51-62: Consider differentiating heading names across sections.

Static analysis flagged duplicate headings ("Prerequisites" and "Setup Steps") appearing in both Salesforce and DocuSign setup guides. While they're in separate collapsible sections, unique headings (e.g., "DocuSign Prerequisites") would improve navigation and anchor-link uniqueness.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@ballerina-integrator/salesforce-closewon-contract-automation/.choreo/instructions.md`
around lines 51 - 62, The duplicate top-level headings "Prerequisites" and
"Setup Steps" cause ambiguous anchors; update the headings in instructions.md to
unique names (e.g., rename the DocuSign section headers from "Prerequisites" and
"Setup Steps" to "DocuSign Prerequisites" and "DocuSign Setup Steps") so anchors
and navigation are distinct; locate the headings that exactly match
"Prerequisites" and "Setup Steps" in the DocuSign collapsible section and rename
them consistently, keeping the content intact.
ballerina-integrator/salesforce-closewon-contract-automation/agents.bal (1)

12-36: Placeholder functions are not integrated into the workflow.

These functions are scaffolding as noted in the comments. However, recommendTemplate always returns () and neither function is called by the actual template selection flow (selectTemplate in functions.bal is used instead per automation.bal:156).

Consider either:

  1. Adding a TODO comment clarifying these are unused scaffolds pending AI integration
  2. Removing until actual AI features are implemented to avoid dead code
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ballerina-integrator/salesforce-closewon-contract-automation/agents.bal`
around lines 12 - 36, The two scaffold functions analyzeOpportunityComplexity
and recommendTemplate are dead code (recommendTemplate returns empty and neither
is called by selectTemplate), so either mark them clearly as unused or remove
them; update agents.bal by adding a TODO comment above both functions stating
they are unused scaffolds pending AI integration (including reference to
selectTemplate and automation.bal where the real flow lives) or delete the
functions entirely to avoid dead code—choose one approach and apply consistently
so reviewers know these are intentionally not part of the current template
selection flow.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ballerina-integrator/salesforce-closewon-contract-automation/automation.bal`:
- Around line 34-38: The envelopeDefinition currently only sets emailSubject,
templateId and status so templateConfig.expirationDays never gets sent; update
the code that builds envelopeDefinition (the variable envelopeDefinition) to
include the expiration configuration from templateConfig.expirationDays (attach
it under the DocuSign notification/expiration structure expected by the API) so
the value passed by selectTemplate() and stored on TemplateConfig is forwarded
in the outgoing envelope.
- Around line 170-180: The current getSignerContact implementation always falls
back to getPrimaryContact on any Contact|error from getContactByRole, which
hides real errors and also mis-handles when signerRole == PRIMARY_CONTACT;
change getSignerContact to first check if signerRole == PRIMARY_CONTACT and call
getPrimaryContact directly (use the existing getPrimaryContact), and when
calling getContactByRole(opportunityId, signerRole) only perform the fallback to
primary when the returned error is a typed “not found” error (e.g.,
ContactNotFound or a sentinel error type your code uses) — for all other errors
return the error immediately so auth/query/deserialization failures are
propagated rather than downgraded.
- Around line 159-164: The flow currently calls
createAndSendEnvelope(opportunity, signer, templateConfig) before any durable
marker is written, so retries can produce duplicate envelopes; make this
idempotent by persisting a marker or envelopeId before or atomically with the
send and skipping the send if the marker exists. Concretely: add or extend a
durable check function (e.g., hasEnvelopeOrStage(opportunityId) or
storeEnvelopeMarker(opportunityId, envelopeId)) and call it before
createAndSendEnvelope to short-circuit if an envelope was already recorded; if
you must write a marker before sending, write a “sending_started” marker (via
updateOpportunityStage or a new persistent store function) and only call
createAndSendEnvelope when no marker exists, then update the marker with the
real envelopeId after success; update updateOpportunityStage (or create a new
persistent helper) to perform the durable write/read so retries are safe.

In
`@ballerina-integrator/salesforce-closewon-contract-automation/connections.bal`:
- Around line 12-19: The docusignClient is being created with a static
docusignAccessToken which will expire; replace this with the OAuth2
refresh-token configuration supported by dsesign:Client: remove the static token
usage and initialize docusignClient using clientId, clientSecret, refreshToken
and refreshUrl (and keep serviceUrl = docusignBaseUrl) so the connector can
automatically renew tokens; follow the same pattern used for the Salesforce
client in this file to wire secrets and URLs into the dsesign:Client
constructor.

In
`@ballerina-integrator/salesforce-closewon-contract-automation/data_mappings.bal`:
- Line 70: The info log currently prints raw PII (contact.Email) in the call to
log:printInfo; change that to avoid exposing emails by logging a masked email or
a non-personal identifier instead (for example mask contact.Email before
logging, or log contact.Id or a hash/correlation id). Update the call that
contains log:printInfo(string `Validated contact ${contact.Id}:
${contact.Email}`) to use the masked/hashed value or contact.Id only so no raw
email is emitted.

In `@ballerina-integrator/salesforce-closewon-contract-automation/functions.bal`:
- Around line 122-128: The current updateOpportunityStage function only logs a
message but returns no value, so callers like processOpportunityForContract
treat it as a successful update while Salesforce is unchanged; either implement
the actual Salesforce REST call to patch the Opportunity StageName (and any
required fields) using your Salesforce HTTP client (e.g., perform a PATCH to
/sobjects/Opportunity/{opportunityId} setting StageName to stageName and handle
auth/response), or if you cannot implement it now, change updateOpportunityStage
to return a non-nil error when not implemented so processOpportunityForContract
does not assume success; update the function signature/return path accordingly
and ensure processOpportunityForContract checks and handles the returned error.
- Around line 87-118: The getOpportunityFieldValue function currently returns an
empty string for any fieldName it doesn't recognize, causing silent data loss in
buildTemplateFields; update handling so unknown opportunityField names surface
an error instead of returning "", either by changing getOpportunityFieldValue to
return an error type (e.g., returns string|error) and return a descriptive error
for unknown fieldName, or by adding a validation step in startup that iterates
configured opportunityField values (from config) and uses
getOpportunityFieldValue to verify each one exists, failing fast with a clear
message; reference getOpportunityFieldValue and buildTemplateFields when
implementing the change and include the unknown fieldName in the error text.
- Around line 12-17: Both SOQL queries that populate the OpportunityContactRole
record are missing required Id and OpportunityId fields; update the SELECT
clauses to include Id and OpportunityId so the Ballerina record maps correctly.
Specifically, modify the soqlQuery string used with salesforceClient->query (and
the other similar SOQL string later in the file) to include "Id, OpportunityId"
alongside ContactId and Role/IsPrimary before calling salesforceClient->query
that produces stream<OpportunityContactRole, error?> (or any other variable that
holds that query result).

In `@ballerina-integrator/salesforce-closewon-contract-automation/main.bal`:
- Line 5: The service path is using a custom name "OpportunityChangeListener" so
the salesforceListener never subscribes; change the service declaration to use
the configurable salesforceChannelName as the service path (i.e., declare
service salesforceChannelName on salesforceListener) and ensure the existing
remote methods (onCreate/onUpdate/onDelete or onEvent) remain on that service so
the connector subscribes to the correct CDC channel.

In `@ballerina-integrator/salesforce-closewon-contract-automation/README.md`:
- Around line 109-111: The README currently points to a non-existent Config.toml
which is gitignored; update the docs and repo so users have a usable sample: add
a new file named Config.toml.example (or Config.toml.sample) checked into the
repo containing the required TOML keys/structure, and update README.md (the
installation/run steps) to reference Config.toml.example (or include a short
inline TOML snippet) and instruct users to copy it to Config.toml and fill in
credentials; ensure references to "Config.toml" in README.md are replaced with
the example filename or explicit copy instructions to avoid confusion.

---

Nitpick comments:
In
`@ballerina-integrator/salesforce-closewon-contract-automation/.choreo/instructions.md`:
- Around line 51-62: The duplicate top-level headings "Prerequisites" and "Setup
Steps" cause ambiguous anchors; update the headings in instructions.md to unique
names (e.g., rename the DocuSign section headers from "Prerequisites" and "Setup
Steps" to "DocuSign Prerequisites" and "DocuSign Setup Steps") so anchors and
navigation are distinct; locate the headings that exactly match "Prerequisites"
and "Setup Steps" in the DocuSign collapsible section and rename them
consistently, keeping the content intact.

In `@ballerina-integrator/salesforce-closewon-contract-automation/agents.bal`:
- Around line 12-36: The two scaffold functions analyzeOpportunityComplexity and
recommendTemplate are dead code (recommendTemplate returns empty and neither is
called by selectTemplate), so either mark them clearly as unused or remove them;
update agents.bal by adding a TODO comment above both functions stating they are
unused scaffolds pending AI integration (including reference to selectTemplate
and automation.bal where the real flow lives) or delete the functions entirely
to avoid dead code—choose one approach and apply consistently so reviewers know
these are intentionally not part of the current template selection flow.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: df87ec85-6267-47ce-95d6-21966c356536

📥 Commits

Reviewing files that changed from the base of the PR and between c7cb295 and 8bc0d02.

📒 Files selected for processing (15)
  • ballerina-integrator/salesforce-closewon-contract-automation/.choreo/config-schema.json
  • ballerina-integrator/salesforce-closewon-contract-automation/.choreo/diagram.md
  • ballerina-integrator/salesforce-closewon-contract-automation/.choreo/instructions.md
  • ballerina-integrator/salesforce-closewon-contract-automation/.gitignore
  • ballerina-integrator/salesforce-closewon-contract-automation/Ballerina.toml
  • ballerina-integrator/salesforce-closewon-contract-automation/Dependencies.toml
  • ballerina-integrator/salesforce-closewon-contract-automation/README.md
  • ballerina-integrator/salesforce-closewon-contract-automation/agents.bal
  • ballerina-integrator/salesforce-closewon-contract-automation/automation.bal
  • ballerina-integrator/salesforce-closewon-contract-automation/config.bal
  • ballerina-integrator/salesforce-closewon-contract-automation/connections.bal
  • ballerina-integrator/salesforce-closewon-contract-automation/data_mappings.bal
  • ballerina-integrator/salesforce-closewon-contract-automation/functions.bal
  • ballerina-integrator/salesforce-closewon-contract-automation/main.bal
  • ballerina-integrator/salesforce-closewon-contract-automation/types.bal

Comment thread ballerina-integrator/salesforce-closewon-contract-automation/automation.bal Outdated
Comment thread ballerina-integrator/salesforce-closewon-contract-automation/automation.bal Outdated
Comment thread ballerina-integrator/salesforce-closewon-contract-automation/data_mappings.bal Outdated
Comment thread ballerina-integrator/salesforce-closewon-contract-automation/functions.bal Outdated
Comment thread ballerina-integrator/salesforce-closewon-contract-automation/main.bal Outdated
Comment thread ballerina-integrator/salesforce-closewon-contract-automation/README.md Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (2)
ballerina-integrator/salesforce-closewon-contract-automation/data_mappings.bal (1)

82-84: ⚠️ Potential issue | 🟠 Major

Avoid returning raw email in validation errors.

Line 83 includes contact.Email in the error message, which can leak PII through logs and traces. Return a generic message (or masked value) instead.

Proposed fix
-    if !contact.Email.includes("@") {
-        return error(string `Invalid email format: ${contact.Email}`);
-    }
+    if !contact.Email.includes("@") {
+        string maskedEmail = maskEmail(contact.Email);
+        return error(string `Invalid email format for contact ${contact.Id}: ${maskedEmail}`);
+    }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@ballerina-integrator/salesforce-closewon-contract-automation/data_mappings.bal`
around lines 82 - 84, The validation currently returns the raw contact.Email in
the error (the if !contact.Email.includes("@") branch); change the error return
to avoid leaking PII by returning a generic message like "Invalid email format"
or a masked email (e.g., replace the local-part with a single character and
asterisks) instead of embedding contact.Email; update the return error(...)
expression in that conditional so it emits the safe message while preserving the
same error type and flow.
ballerina-integrator/salesforce-closewon-contract-automation/automation.bal (1)

217-224: ⚠️ Potential issue | 🔴 Critical

DocuSign send is still not durably idempotent.

The irreversible send happens before a durable, retry-safe marker is guaranteed. If the post-send update path fails, retried events can create duplicate envelopes.

Suggested direction
-    // Create and send DocuSign envelope
-    string envelopeId = check createAndSendEnvelope(opportunity, signer, templateConfig);
+    // Persist a durable "in-flight" marker before send (or reserve an idempotency key)
+    check markDispatchStarted(opportunityId);
+    string envelopeId = check createAndSendEnvelope(opportunity, signer, templateConfig);
+    check markDispatchCompleted(opportunityId, envelopeId);

Also ensure hasEnvelopeAlreadySent() checks both markers.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ballerina-integrator/salesforce-closewon-contract-automation/automation.bal`
around lines 217 - 224, The createAndSendEnvelope call is performed before any
durable, retry-safe marker is persisted, so failures after send can cause
duplicate envelopes on retry; change the flow to (1) have hasEnvelopeAlreadySent
check both the final envelope marker and a durable "pending-send" marker, (2)
persist a durable pending marker (e.g., via updateOpportunityStage or a new
persistent flag) before calling createAndSendEnvelope, (3) call
createAndSendEnvelope, and (4) atomically replace the pending marker with the
final envelopeId (or updateOpportunityStage to the "Contract Sent" state with
envelopeId); ensure functions referenced—createAndSendEnvelope,
updateOpportunityStage, and hasEnvelopeAlreadySent—are updated accordingly to
implement the pending→final marker pattern so retries are idempotent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ballerina-integrator/salesforce-closewon-contract-automation/functions.bal`:
- Around line 12-15: The SOQL is constructed by interpolating opportunityId and
role directly into the soqlQuery string (see the soqlQuery variable and use of
opportunityId/role), which risks malformed queries or injection; instead
validate and whitelist Salesforce IDs (e.g., ensure opportunityId matches the
15/18-char SF ID pattern and role is from an allowed set) before constructing
the query, and build the query using a safe/parameterized approach or escaped
literals; apply the same validation and construction fix to the second
occurrence that interpolates opportunityId/role elsewhere in the file.
- Around line 167-172: The code currently writes the DocuSign envelope marker
into the standard Description field (see envelopeId, envelopeMarker,
updatePayload, opportunityId) which risks overwriting user CRM content; change
the assignment to use a dedicated custom field instead (for example replace
updatePayload["Description"] = envelopeMarker with
updatePayload["DocuSign_Envelope_Id__c"] = envelopeMarker or a configurable
custom-field key), keep the log line as-is, and update comments to reflect that
a custom integration field is used rather than Description.

In `@ballerina-integrator/salesforce-closewon-contract-automation/main.bal`:
- Around line 19-27: The code currently reads the Opportunity ID from
changedData["entityId"]; update it to read from eventData.metadata.recordId
instead (reference eventData and its metadata.recordId field) and change the
failure behavior to fail fast: if recordId is missing or empty log an error ("No
recordId found in Salesforce ChangeEvent metadata") and return an error (not
nil) so downstream logic using opportunityId is not executed; ensure you assign
the value to the existing opportunityId variable and use a non-empty check
before proceeding.

---

Duplicate comments:
In `@ballerina-integrator/salesforce-closewon-contract-automation/automation.bal`:
- Around line 217-224: The createAndSendEnvelope call is performed before any
durable, retry-safe marker is persisted, so failures after send can cause
duplicate envelopes on retry; change the flow to (1) have hasEnvelopeAlreadySent
check both the final envelope marker and a durable "pending-send" marker, (2)
persist a durable pending marker (e.g., via updateOpportunityStage or a new
persistent flag) before calling createAndSendEnvelope, (3) call
createAndSendEnvelope, and (4) atomically replace the pending marker with the
final envelopeId (or updateOpportunityStage to the "Contract Sent" state with
envelopeId); ensure functions referenced—createAndSendEnvelope,
updateOpportunityStage, and hasEnvelopeAlreadySent—are updated accordingly to
implement the pending→final marker pattern so retries are idempotent.

In
`@ballerina-integrator/salesforce-closewon-contract-automation/data_mappings.bal`:
- Around line 82-84: The validation currently returns the raw contact.Email in
the error (the if !contact.Email.includes("@") branch); change the error return
to avoid leaking PII by returning a generic message like "Invalid email format"
or a masked email (e.g., replace the local-part with a single character and
asterisks) instead of embedding contact.Email; update the return error(...)
expression in that conditional so it emits the safe message while preserving the
same error type and flow.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 07a1e717-b9be-4634-8a43-d2b0b7c9058a

📥 Commits

Reviewing files that changed from the base of the PR and between 8bc0d02 and 2edb11a.

📒 Files selected for processing (8)
  • ballerina-integrator/salesforce-closewon-contract-automation/Dependencies.toml
  • ballerina-integrator/salesforce-closewon-contract-automation/README.md
  • ballerina-integrator/salesforce-closewon-contract-automation/automation.bal
  • ballerina-integrator/salesforce-closewon-contract-automation/config.bal
  • ballerina-integrator/salesforce-closewon-contract-automation/connections.bal
  • ballerina-integrator/salesforce-closewon-contract-automation/data_mappings.bal
  • ballerina-integrator/salesforce-closewon-contract-automation/functions.bal
  • ballerina-integrator/salesforce-closewon-contract-automation/main.bal
🚧 Files skipped from review as they are similar to previous changes (3)
  • ballerina-integrator/salesforce-closewon-contract-automation/Dependencies.toml
  • ballerina-integrator/salesforce-closewon-contract-automation/README.md
  • ballerina-integrator/salesforce-closewon-contract-automation/config.bal

Comment thread ballerina-integrator/salesforce-closewon-contract-automation/functions.bal Outdated
Comment thread ballerina-integrator/salesforce-closewon-contract-automation/functions.bal Outdated
Comment thread ballerina-integrator/salesforce-closewon-contract-automation/main.bal Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
ballerina-integrator/salesforce-closewon-contract-automation/functions.bal (1)

203-208: ⚠️ Potential issue | 🟠 Major

Do not store integration metadata in Description.

At Line 207, writing envelope markers to Description can overwrite user CRM content. Keep envelope metadata in a dedicated custom field instead.

Proposed fix
-        string envelopeMarker = string `[DocuSign Envelope: ${envelopeId}]`;
-        updatePayload["Description"] = envelopeMarker;
+        updatePayload["DocuSign_Envelope_Id__c"] = envelopeId;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ballerina-integrator/salesforce-closewon-contract-automation/functions.bal`
around lines 203 - 208, The code is writing DocuSign metadata into the CRM
Description field (using updatePayload["Description"] and envelopeMarker), which
can overwrite user content; change the payload to set a dedicated custom field
(e.g., updatePayload["DocuSign_Envelope_Id__c"] = envelopeMarker) instead of
"Description", keep the log printInfo for envelopeId and opportunityId
unchanged, and remove or avoid writing to updatePayload["Description"] wherever
envelopeMarker is set (refer to the envelopeId, envelopeMarker, updatePayload
and opportunityId symbols to locate the change).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ballerina-integrator/salesforce-closewon-contract-automation/functions.bal`:
- Around line 214-220: The code currently returns updateResult (an error) from
updateOpportunityStage after the DocuSign envelope has already been sent, which
causes retries and duplicate sends; instead swallow and surface a non-fatal
outcome: in the function that contains the shown block (updateOpportunityStage),
remove the "return updateResult" error propagation and replace it with a
non-error return (e.g., return (); or return a success/partial-failure value) so
the function does not propagate a failure after the envelope dispatch; also
update the caller in automation.bal to stop using "check
updateOpportunityStage(...)" (use a plain call or handle the returned status) so
an update failure won't trigger retry of the send logic.

In `@ballerina-integrator/salesforce-closewon-contract-automation/main.bal`:
- Line 5: The service is subscribing too broadly to "/data/ChangeEvents" on
salesforceListener and should be limited to Opportunity change events; change
the service resource path from "/data/ChangeEvents" to the Opportunity-specific
channel (e.g., "/data/ChangeEvents/OpportunityChangeEvent") so only
OpportunityChangeEvent messages are received and processed by this service
declaration on salesforceListener.

---

Duplicate comments:
In `@ballerina-integrator/salesforce-closewon-contract-automation/functions.bal`:
- Around line 203-208: The code is writing DocuSign metadata into the CRM
Description field (using updatePayload["Description"] and envelopeMarker), which
can overwrite user content; change the payload to set a dedicated custom field
(e.g., updatePayload["DocuSign_Envelope_Id__c"] = envelopeMarker) instead of
"Description", keep the log printInfo for envelopeId and opportunityId
unchanged, and remove or avoid writing to updatePayload["Description"] wherever
envelopeMarker is set (refer to the envelopeId, envelopeMarker, updatePayload
and opportunityId symbols to locate the change).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0f5b5fdb-e0cc-415b-80d0-09579c18a21d

📥 Commits

Reviewing files that changed from the base of the PR and between 2edb11a and b857b8b.

📒 Files selected for processing (2)
  • ballerina-integrator/salesforce-closewon-contract-automation/functions.bal
  • ballerina-integrator/salesforce-closewon-contract-automation/main.bal

Comment thread ballerina-integrator/salesforce-closewon-contract-automation/functions.bal Outdated
Comment thread ballerina-integrator/salesforce-closewon-contract-automation/README.md Outdated
Comment thread ballerina-integrator/salesforce-closewon-contract-automation/README.md Outdated
Comment thread ballerina-integrator/salesforce-closewon-contract-automation/README.md Outdated
Comment thread ballerina-integrator/salesforce-closewon-contract-automation/README.md Outdated
Comment thread ballerina-integrator/salesforce-closewon-contract-automation/README.md Outdated
…EADME.md

Co-authored-by: Haritha Hasathcharu <42366642+hasathcharu@users.noreply.github.com>
Comment thread ballerina-integrator/salesforce-closewon-contract-automation/.choreo/diagram.md Outdated
Comment thread ballerina-integrator/salesforce-closewon-contract-automation/.choreo/diagram.md Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (1)
ballerina-integrator/salesforce-closewon-contract-automation/README.md (1)

114-127: 🛠️ Refactor suggestion | 🟠 Major

Remove local execution instructions per previous feedback.

The "Running Locally" section was flagged for removal in an earlier review. Additionally, line 117 references a gitignored Config.toml file that won't exist in cloned repositories, which was also flagged previously as misleading.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ballerina-integrator/salesforce-closewon-contract-automation/README.md`
around lines 114 - 127, Remove the entire "Running Locally" section (the "##
Running Locally" header and its numbered steps) and any references to a
gitignored Config.toml or the local command "bal run" from README.md so the file
no longer instructs users to run the integration locally or points to a
non-existent Config.toml; ensure you also remove the duplicate_comment marker
and any duplicated guidance elsewhere in the README to avoid reintroducing the
same content.
🧹 Nitpick comments (2)
ballerina-integrator/salesforce-closewon-contract-automation/README.md (2)

39-39: Fix brand name capitalization.

"Docusign" should be "DocuSign" (capital S). This inconsistency was noted in a previous review.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ballerina-integrator/salesforce-closewon-contract-automation/README.md` at
line 39, Update the heading "Docusign Setup" in the README to use the correct
brand capitalization "DocuSign Setup" and scan the README for any other
occurrences of "Docusign" to replace them with "DocuSign" to ensure consistent
branding throughout.

9-19: Consolidate bullet points to 3-5 as previously requested.

The list currently contains 10 bullet points. Based on previous feedback, this should be reduced to 3-5 high-level points. Consider grouping related items (e.g., "validates, retrieves, and selects" into one bullet; "creates envelope with signers, fields, and CCs" into another).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ballerina-integrator/salesforce-closewon-contract-automation/README.md`
around lines 9 - 19, Condense the README's detailed 10-item feature list into
3–5 high-level bullets by grouping related actions: one bullet for event
listening and business validation (Change Data Capture + "Closed Won" & deal
value checks), one for data retrieval and template selection (contact lookup by
signer role + DocuSign template choice), one for envelope creation (pre-filled
fields + configured signer(s) + CC recipients + custom subject/routing), and one
for post-send actions and robustness (update Opportunity stage to "Contract
Sent" + error handling/logging); update the existing bullet list under the
feature summary to replace the 10 bullets with these grouped items so the README
remains concise and focused.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ballerina-integrator/salesforce-closewon-contract-automation/README.md`:
- Line 102: The section heading currently reads "## Deploying on **Choreo**" and
must be updated to use the requested platform name; change that heading text to
"## Deploying on **WSO2 Integration Platform**" (update any other occurrences of
"Choreo" in the README to "WSO2 Integration Platform" to keep terminology
consistent).
- Line 134: The README's troubleshooting line "Check OAuth token validity and
refresh token" references OAuth credentials that don't exist in config.bal;
either add the missing OAuth keys (e.g., client_id, client_secret,
refresh_token, access_token) to config.bal or update the README.md
troubleshooting section to reference the actual authentication method and config
keys used by the project (modify the line in README.md or the section around
it), and ensure consistency between config.bal and README.md so the guidance is
actionable.
- Around line 104-112: The README's deployment steps currently reference
Choreo-specific concepts; replace that bulleted section with WSO2 Integration
Platform deployment instructions: describe signing in to WSO2 Integration Studio
or Management Console, importing this repository as an Integration Project,
configuring connectors (Salesforce/DocuSign) and required environment variables,
building and deploying to the WSO2 Micro Integrator or Integration Cloud
runtime, and monitoring logs/metrics via the Management Console; ensure the
updated steps mention where to set env vars for production and how to promote
the integration in the WSO2 platform (replace the Choreo terms "Integration",
"Technology", and "Type" with WSO2-specific workflow).

---

Duplicate comments:
In `@ballerina-integrator/salesforce-closewon-contract-automation/README.md`:
- Around line 114-127: Remove the entire "Running Locally" section (the "##
Running Locally" header and its numbered steps) and any references to a
gitignored Config.toml or the local command "bal run" from README.md so the file
no longer instructs users to run the integration locally or points to a
non-existent Config.toml; ensure you also remove the duplicate_comment marker
and any duplicated guidance elsewhere in the README to avoid reintroducing the
same content.

---

Nitpick comments:
In `@ballerina-integrator/salesforce-closewon-contract-automation/README.md`:
- Line 39: Update the heading "Docusign Setup" in the README to use the correct
brand capitalization "DocuSign Setup" and scan the README for any other
occurrences of "Docusign" to replace them with "DocuSign" to ensure consistent
branding throughout.
- Around line 9-19: Condense the README's detailed 10-item feature list into 3–5
high-level bullets by grouping related actions: one bullet for event listening
and business validation (Change Data Capture + "Closed Won" & deal value
checks), one for data retrieval and template selection (contact lookup by signer
role + DocuSign template choice), one for envelope creation (pre-filled fields +
configured signer(s) + CC recipients + custom subject/routing), and one for
post-send actions and robustness (update Opportunity stage to "Contract Sent" +
error handling/logging); update the existing bullet list under the feature
summary to replace the 10 bullets with these grouped items so the README remains
concise and focused.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 59c077dc-2460-4aa3-945b-82f125fdaedb

📥 Commits

Reviewing files that changed from the base of the PR and between b857b8b and f70b865.

📒 Files selected for processing (1)
  • ballerina-integrator/salesforce-closewon-contract-automation/README.md

Comment thread ballerina-integrator/salesforce-closewon-contract-automation/README.md Outdated
Comment thread ballerina-integrator/salesforce-closewon-contract-automation/README.md Outdated
@hasathcharu

hasathcharu commented Mar 13, 2026

Copy link
Copy Markdown
Contributor

Prebuilt Integration Checklist

  • .github/workflows/projects.json is updated with the new prebuilt integration path
  • Path in the .github/workflows/projects.json matches the project path exactly
  • Directory path is identical to the integration name in Ballerina.toml
  • README.MD is correctly structured
  • Configurations are organized by records based on vendor
  • choreo/config-schema.json exists and is up to date
  • choreo/instructions.md is correctly structured
  • choreo/diagram.md is correctly written and parsable by Mermaid
  • choreo/component.yaml exists for service type integrations

iamvirul added 12 commits March 16, 2026 12:56
…me/password to OAuth2 and update related configurations.
…er to use the service path for channel specification, with corresponding documentation updates.
…geEventHeader.recordIds` instead of `entityId`.
…fely extract `ContactId` via JSON conversion with explicit error handling.
…c, adding robust error handling and configuration validation, and updating README documentation with detailed setup and troubleshooting.
…ing for `ENVELOPE_IS_INCOMPLETE` by adding detailed README instructions and in-code logging.
@hasathcharu

Copy link
Copy Markdown
Contributor

Shall we use refresh token flow for docusign and salesforce

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds a new Ballerina integration package intended to automate DocuSign contract sending when Salesforce Opportunities transition to “Closed Won”, along with Choreo deployment assets and repository registration for CI/project discovery.

Changes:

  • Introduces a new salesforce-closewon-contract-automation integration package (listener + envelope creation flow + mappings/types/config).
  • Adds Choreo artifacts (config schema, instructions, diagram) and end-user documentation (README).
  • Registers the new integration path in .github/workflows/projects.json.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
ballerina-integrator/salesforce-closewon-contract-automation/types.bal Defines Salesforce/DocuSign-related record types and configuration records.
ballerina-integrator/salesforce-closewon-contract-automation/main.bal Salesforce CDC listener service entrypoint for change events.
ballerina-integrator/salesforce-closewon-contract-automation/functions.bal Salesforce query helpers, template selection, dispatch criteria, and stage update stub.
ballerina-integrator/salesforce-closewon-contract-automation/data_mappings.bal Mapping + validation utilities for envelope subject and signer details.
ballerina-integrator/salesforce-closewon-contract-automation/connections.bal Initializes Salesforce/DocuSign clients and Salesforce listener.
ballerina-integrator/salesforce-closewon-contract-automation/config.bal Declares configurable records for Salesforce/DocuSign/templates/business rules.
ballerina-integrator/salesforce-closewon-contract-automation/automation.bal Core orchestration: validate, select signer/template, create & send envelope.
ballerina-integrator/salesforce-closewon-contract-automation/agents.bal Placeholder scaffolding for future AI-powered logic.
ballerina-integrator/salesforce-closewon-contract-automation/README.md Setup, configuration, deployment and troubleshooting documentation.
ballerina-integrator/salesforce-closewon-contract-automation/Ballerina.toml Package metadata for the new integration.
ballerina-integrator/salesforce-closewon-contract-automation/.gitignore Ignores build artifacts and local config.
ballerina-integrator/salesforce-closewon-contract-automation/.choreo/instructions.md Choreo-facing deployment/setup instructions.
ballerina-integrator/salesforce-closewon-contract-automation/.choreo/diagram.md Process diagram for the integration flow.
ballerina-integrator/salesforce-closewon-contract-automation/.choreo/config-schema.json Choreo configuration schema for deployment-time config UI/validation.
.github/workflows/projects.json Adds the new integration path to the projects list.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread ballerina-integrator/salesforce-closewon-contract-automation/README.md Outdated
Comment thread ballerina-integrator/salesforce-closewon-contract-automation/functions.bal Outdated
iamvirul and others added 2 commits March 24, 2026 09:35
Co-authored-by: Haritha Hasathcharu <42366642+hasathcharu@users.noreply.github.com>
Co-authored-by: Haritha Hasathcharu <42366642+hasathcharu@users.noreply.github.com>
@hasathcharu

hasathcharu commented Mar 24, 2026

Copy link
Copy Markdown
Contributor

Prebuilt Integration Checklist

  • .github/workflows/projects.json is updated with the new prebuilt integration path
  • Path in the .github/workflows/projects.json matches the project path exactly
  • Directory path is identical to the integration name in Ballerina.toml
  • README.MD is correctly structured
  • Configurations are organized by records based on vendor
  • choreo/config-schema.json exists and is up to date
  • choreo/instructions.md is correctly structured
  • choreo/diagram.md is correctly written and parsable by Mermaid
  • choreo/component.yaml exists for service type integrations

Shall we fix these

@hasathcharu

hasathcharu commented Mar 25, 2026

Copy link
Copy Markdown
Contributor

Prebuilt Integration Checklist

  • .github/workflows/projects.json is updated with the new prebuilt integration path
  • Path in the .github/workflows/projects.json matches the project path exactly
  • Directory path is identical to the integration name in Ballerina.toml
  • README.MD is correctly structured
  • Configurations are organized by records based on vendor
  • choreo/config-schema.json exists and is up to date
  • choreo/instructions.md is correctly structured
  • choreo/diagram.md is correctly written and parsable by Mermaid
  • choreo/component.yaml exists for service type integrations

Shall we fix the unchecked
Please regenerate the config schema.json as well

@iamvirul

Copy link
Copy Markdown
Member Author

Prebuilt Integration Checklist

  • .github/workflows/projects.json is updated with the new prebuilt integration path
  • Path in the .github/workflows/projects.json matches the project path exactly
  • Directory path is identical to the integration name in Ballerina.toml
  • README.MD is correctly structured
  • Configurations are organized by records based on vendor
  • choreo/config-schema.json exists and is up to date
  • choreo/instructions.md is correctly structured
  • choreo/diagram.md is correctly written and parsable by Mermaid

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants