Salesforce associate activity (task) to object (Case, etc.) and tab sync

Hey all -
Let's do a thread so other people can learn how to do this.

I'm working with someone who uses Salesforce in a little different way than a lot of our customers. They have a few different types of cases with mild customization but they don't use Tasks ("Activities") - so I added the Interaction ID to sync over to Task as InteractionID__c and they're adding it to the Case at Call_GUID__c.

The following code does match up the related fields well and right away. However, the tab sync (changing which case is shown based on which interaction you select) doesn't work unless we manually add a note to the activity through the embedded client.

The ask here is (and should be) simple - and ideally would be documented (or easier to find if it is because I've looked quite a bit).

What calls or other code do we need to execute beyond associating the auto-created task to the case?

It would be nice to get this answered here so other people don't waste as much time as I have digging around. From a case record standpoint in the developer debugger (in SF) I'm not seeing any difference in the tasks, cases, or even over in the call details on Genesys based on the two different methods.

Sorry if I'm missing something obvious, I'm not an expert in Salesforce. Thanks in advance!

--

trigger associateTask on Case (after insert) {
    List<Task> taskUpdates = new List<Task>();
    
    For (Case myCase : trigger.new)
    if (myCase.Call_GUID__c != null) {
        List<Task> matchingTasks = [SELECT Id, WhatId FROM Task WHERE InteractionID__c = :myCase.Call_GUID__c];
        if(matchingTasks.size() > 0) {
            Task task = matchingTasks[0];
            if(task.WhatId == null) {
                task.WhatId = myCase.Id;
                update task;
            }
        }
    }
}

--

bump :eyes: (anyone?)

bump! I'd also like to know

1 Like

Trying to keep this open - hopefully someone wants to share (support hasn't been able to help other than pointing here).

I will post how to do this once we have it. Basic functionality shouldn't be hobbled or prevented via incomplete documentation and then exploiting that for profit from anyone. It would be nice to get the community a win here.

Additional details:
"Checking callLogs for associated interaction" gets logged from app.js in the embedded client code where it's running:

oe.$on("ExternalViewChanged", e=>{
                const {objectId: n} = e
                  , r = e.id;
                if (w(this, xee, lMe).call(this, {
                    objectId: n
                })) {
                    let i = !1;
                    const s = id.getCallLogs();
                    if (Object.keys(s).forEach(a=>{
                        if (s.hasOwnProperty(a)) {
                            const o = s[a];
                            x.logInfo("Checking callLogs for associated interaction"),
                            o.selectedContact && o.selectedContact.id === n ? (x.logInfo("Found associated interaction by contact id: " + n),
                            v(this, _k).call(this, a),
                            v(this, uy)[a] = {
                                tabId: r,
                                objectId: n
                            },
                            i = !0) : o.selectedRelated && o.selectedRelated.id === n && (x.logInfo("Found associated interaction by related to id: " + n),
                            v(this, _k).call(this, a),
                            v(this, uy)[a] = {
                                tabId: r,
                                objectId: n
                            },
                            i = !0)
                        }
                    }
                    ),
                    !i) {
                        const o = w(this, hT, Sk).call(this)[n];
                        if (o) {
                            const c = id.getCallLogByInteractionId(o);
                            w(this, gW, $ee).call(this) && (c.selectedContact && c.selectedContact.id || c.selectedRelated && c.selectedRelated.id) || (x.logDebug("Found associated external routing interaction by object id: " + n),
                            v(this, _k).call(this, o),
                            v(this, uy)[o] = {
                                tabId: r,
                                objectId: n
                            })
                        }
                    }
                }
            }

So we need to get into the callLog the related Id - the structure of the CallLog is

{
    "subject": "Chat 1/18/2024, 10:15:37 AM",
    "externalId": "00THs0000DHpECPMQ3"
}

when related via the code above (nothing about the relation)
and

{
    "subject": "Chat 1/18/2024, 10:16:17 AM",
    "externalId": "00THs0000DHpECBMQ3",
    "selectedRelated": {
        "text": "00001073 - Case",
        "id": "500Hs000022HFruIAG"
    }
}

when related via the embedded client UI.

So I'm looking for the Genesys approved way of updating the "selectedRelated" object via Salesforce.

@Richard.Schott - any thoughts on this?

The tab synchronization logic relies on the call log relationship within the client, so the client "knows" which tab is associated with which conversation; this is outlined in the Call Center Settings doc: https://help.mypurecloud.com/articles/configure-call-center-settings/. Typically this is set via the screenpop, which occurs at roughly the same time the call log is created (screen pop occurs on alerting, call log occurs on connected, but there is an internal cache that notes the screenpop is related to the conversation so it can be added to the call log). Honestly, I'm not entirely sure what it is that you're trying to accomplish with the code above, but it appears that you're creating task record outside of the client's native call logging feature, which is certainly awkward, as the client has some pretty sophisticated logic to keep track of those activities it's creating, save attempts, etc.

There are some alternatives that could be explored if you absolutely need to avoid the usage of activity records. they would center around listening to client events for the selected conversation and updating the Salesforce view to corresponding record. You might also be able to use the client extension point to interrupt the saving of the call log while still retaining the relationship for tab sync purposes, although I haven't tried that, so please test thoroughly to validate there aren't other unintended consequences of doing this.

Thanks - I think we've followed that to a T, but while we pop we hit a custom Apex class that creates the right kind of case for the interaction (they're different if they come in as a digital - chat/messaging/whatsapp vs. a phone call).

I tested this in a Salesforce sandbox configuring the interaction ID to be written to the Task (see below) and using the standard SF_URLPop with "lightning/o/Case/new?&defaultFieldValues=Call_GUID__c=" + Message.ConversationId for the value. - I set up a custom field Call_GUID__c on the case to store the interaction.

Have I done something overcomplicated or nonstandard here? Doing a code association in this case (see Apex code at top) it still doesn't work.

(to clarify, my goal here is auto-linking the case to the activity in a way that will work for the Embedded Client to work with tab synching - we're trying to save them manually adding a note or linking the tasks by hand through the call log UI) (And I'm totally open to having done something off here and failing to RTM - I've used the integration on and off at different customers for almost a decade but haven't run into this scenario oddly.)

Also - in the code above we're not creating the Task - you (Genesys Cloud) are already doing that - I'm simply trying to relate the two objects.

@Richard.Schott - here's pseudocode of the above salesforce apex:

if myCase has a Call ID in it, then:
        Find all the tasks that have that same call ID in them - it should be 1 at this point;
        if we found more than 0, lets get the 0th (or "first" if you prefer 1 based counting) then
            set the case ID on that Task related to field so they are related.

Obviously I'm missing something here. Are you leveraging the client extension point to modify the screenpop, creating the appropriate case type, then returning that newly created object as the screenpop value/object that gets popped?

so what I believe is happening here is that the association is happening outside of the client, so the client is not aware of it until there is another save that the client is trying to implement (which is what happens when you type a note). At the point of that second save, the relationship is returned as part of the saveLog function being used by the client, so it's now aware that the task is related, which allows the tab sync to operate correctly.

What needs to happen is that the client handles the association in the first place, which typically occurs as part of the screenpop process. Moving the case creation into the client extension point should resolve this; alternatively, the case could be created in the inbound flow via a data action, and the object ID returned as the sf_urlPop attribute to allow the client to manage the screenpop to this new case object, which will trigger the association and everything should be happy.

@Richard.Schott we're calling a custom salesforce / visualforce page that sorts out what kind of case it should create, but the task is getting created correctly.

More importantly if I do this in a "sandbox" (basically a vanilla install of Salesforce to play with) and I pop to new case using the SF_URLPop and passing in the call ID -- "lightning/o/Case/new?&defaultFieldValues=Call_GUID__c=" + Message.ConversationId -- it still doesn't work, until I manually assign the case and the task together by using the UI in the embedded client (creating a call log and selecting the appropriate case number).

We're simply trying to automate that last part. We don't want our counselors ("agents") to have to do those extra steps for each chat to keep them straight.

update - saw your other note. So it should work in my sandbox simply popping to lightning/o/Case/new ? I'm doing that and the task gets created but not associated. In the default SF instance you're at a create case page and need to save it before you get a case id, etc.

not exactly. Popping to the lightning/o/case/new page still doesn't present the object ID until after the call log is already created, so the association doesn't happen (in part because auto associate based on navigation has to be disabled in order to have tab sync).

Again, the best tools you have at your disposal are those in the flow, or the client extension points (which provide a place to run your custom apex to handle case creation and pass in the object ID as part of the screenpop process). See Configure extension points - Genesys Cloud Resource Center and Extension points in Genesys Cloud for Salesforce - Genesys Cloud Resource Center. You're going to want to leverage the screenPop extension, outputting the object ID of your newly created case as the URL parameter described here: Use the extension points to customize screen pop - Genesys Cloud Resource Center

Basically, you're duplicating some capabilities that are part of client, but doing so out of band from the client's normal operation. Because of this, the client isn't aware of what you're doing until later in the process, which is what's causing the issues you're seeing. Doing the same thing within the native capabilities of the client should cause everything to work together happily while still providing you the end result you're going for.

Thanks - my hope was to find a way to play nicely with the client and leverage the work our salesforce team has already done but it sounds like we're not able to do that easily. I'll check out the Apex extension point and see if I can make that work. If I get it all to work well, I'll post another HOWTO on here because I've seen plenty of other people ask similar questions and not really find a solution.

I appreciate all your time and help. Thanks again and I'll come back and update this if we get it working without pre-creating the case in the flow. We want to avoid that so we don't have cases for abandoned interactions but we may have to work around that another way down the road.

Hopefully all of that helps. There's just a lot going on within the client in order to make certain features operate, so sometimes there's just a narrow path to success. Ideally the apex that is running within the Visualforce page can be reused, which should make your implementation a little easier (and preserve some of the time investment you've already got into this project).

When you get it sorted, please tag me so I'll get an update.

Well, we got it to work with using extension points and keeping our linking code and other items in place. When we get some time after go-live I'll rework the pieces into a clean HOWTO.

Been following this thread and will be looking forward to your How To @ottoflux so I can show our Salesforce admins.

Out of curiosity, does your approach also work with Salesforce External Routing of Chats/Messages (i.e. Genesys Cloud open messaging)?

I ask because when the Genesys Cloud open messaging (chat) object enters Salesforce, our Salesforce admins are able to see the Salesforce Task and any custom [participant] attributes we had them map in the managed package call center settings. However, they want those same custom attributes to be associated with/passed to custom fields on their Messaging work item/chat transcript/Case. I'm no Salesforce guru, but it sounds like they need to create some sort of relationship between the Task Genesys creates in Salesforce and the corresponding Salesforce objects they're interested in referencing said fields.

I'll keep doing research for them, but do appreciate the discussion here.

Hey there Brian - I'll try to get to it soon - it may be after our current go-live depending on work I have going on.

I haven't played with it routing in open messaging with Salesforce yet but it may be tricky depending on how the embedded client works with them. As long as they're displayed/operated on through the client I think it would be fine but if they're only interfaced through Salesforce it may be a bit more complicated.

I'll see if I can get "anonymized/base working copy" ready for the How To. :slight_smile:

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.