Avoid updating issue with older changes Salesforce <> Jira

A continuity from: Avoid updating issue with older changes ADO <> Jira, Jira <> Jira, ServiceNow <> Jira, ZenDesk <> Jira

For the use case we will sync Salesforce Case “Assignee” <> Jira Assignee and Salesforce Status <> Jira Status fields.

Salesforce Outgoing Script:

replica.status = entity.Status
if (entity.Assignee__c)
    replica.assigneeUsername = nodeHelper.getReference('Case', 'Assignee__c', entity.Assignee__c)?.Username__c

request = "/services/data/v54.0/query?q=" +
"SELECT Field,OldValue,NewValue,CreatedDate FROM CaseHistory " +
"WHERE CaseId='${entity.Id}' " +
"ORDER BY CreatedDate DESC"

records = httpClient.get(request).records

def dateFormat = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")

def history = []

records.eachWithIndex { r, i ->
    if(r.Field && !(r.OldValue == null && r.NewValue == null)){
    def author = new com.exalate.basic.domain.hubobject.v1.BasicHubUser()
    author.key = "salesforce"
    author.displayName = "salesforce"
    author.active = true

    def date = dateFormat.parse(r.CreatedDate)
    def timestamp = new java.sql.Timestamp(date.time)

    def changeItem =
        new com.exalate.basic.domain.hubobject.v1.BasicHubChangeItem(
            r.OldValue as String,
            r.OldValue as String,
            r.NewValue as String,
            r.NewValue as String,
            r.Field,
            "system"
        )

    history << new com.exalate.basic.domain.hubobject.v1.BasicHubChangeHistory(
        i as Long,
        author,
        timestamp,
        [changeItem]
    )
  }
}
replica.changeHistory = history

Salesforce Incoming Script:

def fieldToLastUpdateDateFn = { exalateUserKey ->
        { history ->
            history
                .sort { c -> c.created.time }
                .reverse()
                .findAll { c -> c.author.key != exalateUserKey && c.author.key != "salesforce"}
                .inject([:]) { result, c ->
                    c.changeItems.inject(result) { r, i ->
                        if(r[i.field] == null){
                            r[i.field] = c.created
                        }
                        r
                    }
                }
        }
    }

    def remoteFieldToLastUpdateDate =
        fieldToLastUpdateDateFn("exalate")(replica.changeHistory)

    def localFieldToLastUpdateDate =
        fieldToLastUpdateDateFn("exalate")(entity.changeHistory)

    if(remoteFieldToLastUpdateDate."assignee" > localFieldToLastUpdateDate."Assignee" && replica.assignee){

        def rContact = httpClient.get("/services/data/v61.0/query?q=SELECT Id, Username__c FROM R_Contact__c where Username__c = '${replica.assignee.username}' and Active__c = true")?.records?[0]?.Id
    if (!rContact) rContact = httpClient.post("/services/data/v61.0/sobjects/R_Contact__c", """
        {
            "Name": "${replica.assignee.displayName}",
            "Username__c": "${replica.assignee.username}",
            "Email__c": "${replica.assignee.email}",
            "Active__c": ${replica.assignee.active}
        }
    """)?.id
    entity.Assignee__c = rContact
    }

    if(remoteFieldToLastUpdateDate."status" > localFieldToLastUpdateDate."Status"){

        entity.Status = (replica.status?.value != "Closed") ? replica.status?.value : 'Closed'
    }

Jira Outgoing Script:

replica.assignee = issue.assignee
replica.status = issue.status
replica.changeHistory = issue.changeHistory

Jira Incoming Script:

 def fieldToLastUpdateDateFn = { exalateUserKey ->
        { history ->
            history
                .sort { c -> c.created.time }
                .reverse()
                .findAll { c -> c.author.key != exalateUserKey }
                .inject([:]) { result, c ->
                    c.changeItems.inject(result) { r, i ->
                        if(r[i.field] == null){
                            r[i.field] = c.created
                        }
                        r
                    }
                }
        }
    }

    def remoteFieldToLastUpdateDate =
        fieldToLastUpdateDateFn("exalate")(replica.changeHistory ?: [])

    def localFieldToLastUpdateDate =
        fieldToLastUpdateDateFn("exalate")(issue.changeHistory ?: [])

    def remoteStatusTime = remoteFieldToLastUpdateDate["Status"]
    def localStatusTime  = localFieldToLastUpdateDate["status"]

    if(remoteStatusTime && (!localStatusTime || remoteStatusTime > localStatusTime)){
        issue.setStatus(replica.status?.name)
    }
    def remoteAssigneeTime = remoteFieldToLastUpdateDate["Assignee"]
    def localAssigneeTime  = localFieldToLastUpdateDate["assignee"]

    if(remoteAssigneeTime && (!localAssigneeTime || remoteAssigneeTime > localAssigneeTime)){
        if(replica.assigneeUsername){
            def jiraUser = nodeHelper.getUserByUsername(replica.assigneeUsername)
            if(jiraUser){
                issue.assignee = jiraUser
            }
        }
    }

Tested and working!

HI @Ariel_Aguilar

Could you update query to send the change history of only a select number of fields? From both Jira, and Salesforce.

Hi kibeh,

Sure, what fields are you interested to send in the change history for both sides?

Kind regards,

Ariel

For my usecase, only Assignee but you can include Description and Comment.

Hi kibeh,

Jira Outgoing

def allowedFields = ["assignee", "status", "description"]

replica.changeHistory = issue.changeHistory.collect { historyItem ->
    def filteredItems = historyItem.changeItems.findAll { change ->
        change.field in allowedFields
    }

    if (filteredItems) {
        historyItem.changeItems = filteredItems
        return historyItem
    }
    return null
}.findAll { it != null }

Salesforce Outgoing

def allowedFields = ["Status", "Assignee", "Description"]

request = "/services/data/v54.0/query?q=" +
"SELECT Field,OldValue,NewValue,CreatedDate FROM CaseHistory " +
"WHERE CaseId='${entity.Id}' " +
"ORDER BY CreatedDate DESC"

records = httpClient.get(request).records

def dateFormat = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")

def history = []

records.eachWithIndex { r, i ->

    if (
        r.Field &&
        allowedFields.contains(r.Field) &&
        !(r.OldValue == null && r.NewValue == null)
    ) {

        def author = new com.exalate.basic.domain.hubobject.v1.BasicHubUser()
        author.key = "salesforce"
        author.displayName = "salesforce"
        author.active = true

        def date = dateFormat.parse(r.CreatedDate)
        def timestamp = new java.sql.Timestamp(date.time)

        // Map Salesforce "Assignee" → Jira "assignee"
        def mappedField = (r.Field == "Assignee") ? "assignee" :
                          (r.Field == "Status") ? "status" :
                          (r.Field == "Description") ? "description" :
                          r.Field

        def changeItem =
            new com.exalate.basic.domain.hubobject.v1.BasicHubChangeItem(
                r.OldValue as String,
                r.OldValue as String,
                r.NewValue as String,
                r.NewValue as String,
                mappedField,
                "system"
            )

        history << new com.exalate.basic.domain.hubobject.v1.BasicHubChangeHistory(
            i as Long,
            author,
            timestamp,
            [changeItem]
        )
    }
}

replica.changeHistory = history

Comments are not trackable as the other fields for both systems.

Kind regards,

Ariel

1 Like