function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
apexsutherlandapexsutherland 

How to get CTI adapter to pop a new Lead record if no match is found

REALLY hoping someone can provide a simple solution for this question - we have a client who needs to have their CTI Adapter show a new Lead record (with the Phone field populated with the ANI of the caller) if no match is found in their org. Also, they need to be able to access custom fields on the Call record while the call is in progress. Does anyone know if this is possible with the CTI Adapter?
werewolfwerewolf
Are you privy to the code of the CTI adapter or is this an out-of-the-box adapter?  There's something you can do in code, but not with a straight up adapter.
AlexCRMmanagerAlexCRMmanager
Well, our client will be using a third-party, out of the box adapter from Zeacom (for an NEC phone system). However, I am just testing using the CTI Demo Adapter from from the developer wiki. We might be able to get Zeacom to modify their CTI adapter to behave the way that we need. Can you share some more details about the changes required to do what we want?
werewolfwerewolf
Well, you'll have to get Zeacom to change the code a little.  The CTI adapter wasn't made to pop edit pages, but with a bit of doing you (or Zeacom anyway) can make it do so.  I think I'm going to make a blog entry out of this post, but I'll write the text here so that you're not left in suspense :).

For the CTI adapter to pop any page, it must have a search result of some sort.  Normally that search result is an actual object, but if you find no object, you can "fool" it into thinking it's found an object and pop that instead.

The trick to this is twofold.  First, you have to make sure that it actually finds something to pop.  Then you have to change the ID of the popped object such that it pops the page you're looking for.

Let's take your situation, where you want to pop a new lead page when the lead is not found.  There are a few options, but here's what I would do:

1.  Make a custom object called "New Lead."  This is sort of a throwaway custom object, but the adapter will need its existence in order to have something to pop.
2.  Make exactly one row of this custom object.
3.  Make a Visualforce page (let's call it GotoNewLead) that contains nothing but the following:

Code:
<apex:page standardController="New_Lead__c">
<meta http-equiv="refresh" content="0;url=/00Q/e"/>
</apex:page>

4.  Go to your New Lead custom object setup page.  In the Standard Buttons and Links section, override the View component to point to your GotoNewLead Visualforce page.
5.  Go to Setup->Customize->Call Center->Softphone Layout and add the New Lead custom object to your softphone layout.
6.  Here's where the CTI adapter vendor comes in (and this is where we get in the technical weeds).  Remember that ID you saved in step 2?  The adapter vendor needs to make a change to CCTIAppExchangeSearchThread::ThreadSearch.  This change would be on line 212, just before the     if (IsWindow(pInfo->m_hWnd)) stuff.  They'll want to add this:

Code:
if (listRelObjSets.empty()) {
//Still nothing from the logs and IVR -- try the ANI search
try
{
IQueryResultSet4Ptr pQueryResults = pSession->Search(L"Select Id,Name From New_Lead__c Limit 1",VARIANT_FALSE);
CCTIAppExchange::PopulateQueryResults(pSession,pQueryResults,pInfo->m_mapLayout,listRelObjSets,true);
}
catch(_com_error ce)
{
CCTILogger::Log(LOGLEVEL_LOW,L"CCTIAppExchangeSearchThread::ThreadSearch: Error running ANI query: %s.",(wchar_t*)pSession->GetErrorMessage());
}
}

7.  The adapter vendor needs to recompile the adapter with this code and give it to you.

So what are we doing here?  Well, we've created a custom object which just redirects itself at the new Lead page (a fact you can test for yourself just by trying to navigate to that one row of the New Lead custom object you made).  Then we hardcoded the adapter to say that if the IVR search returns nothing and the caller ID search returns nothing (that's the if (listRelObjSets.empty()) part) then we'll search on your new custom object instead, and because you created one row back in step 2 we know that it's going to come up, and because you overrode that page to redirect to a new lead page, then you're going to pop to a new lead!


werewolfwerewolf
By the way if you can't get Zeacom to change the adapter code for you, there's another way to do it which is a tad convoluted but which I wrote in the blog entry which I'll post in a couple of weeks.  The text of it is below.

What NEC telephony system are you integrating to here?  I've not heard of an NEC integration yet so this is interesting.

Here's the other way to do it:

But wait, you may say, I'm using an out-of-the-box adapter – I can't get it customized. 

Well, that doesn’t necessarily mean you're out of luck.  Many adapters support attached data.  If you can attach some data at the IVR or ACD level that will be sent on to the adapter, then you can use a modified version of this process to achieve the same result.

If you are in this situation, then steps 6 and 7 do not apply to you – you can't touch the adapter code.  What you need to do, then, is do a data dip into Salesforce.com to search on the ANI to see if you come up with anything (and remember, if you're doing an ANI search you almost always want to use the SOSL language, not the SOQL language).  If you don't find anything, then attach data to the call like (per my example above) "New_Lead__c.Id" = "<the ID of your one and only New Lead object that you created in step 2>".  The CTI Toolkit considers attached data in key-value pairs, and lots of phone systems do too, but if yours does not then contact your vendor on how to attach this data such that it will search properly.

Provided the data is attached to the call properly, the adapter will receive it and pop the object you specified rather than searching itself, and it will pop your Visualforce page.  How about that.


SimonZeacomSimonZeacom

This approach does pop a blank New Lead, however, Salesforce doesn't like it and the Softphone immediately dies when the blank New Lead is popped.

Symptoms are as follows:
1. Call arrives and the Softphone interface displays the name of the "New Lead" record (it was found succesfully).

2. The "New Lead" Tab is briefly activated and the Softphone interface is replaced by a red error box with the following error:
     "Error connecting to the Salesforce.com AppExchange API: Only urls under the salesforce.com domain are allowed"

3. The "Leads" Tab is then quickly activated and the "Lead Edit" page for a new Lead is successfully popped.  The red error box now contains the following error:
    "Error: Unable to start the Softphone XML subsystem. Please contact your Salesforce.com administrator to rectify this issue"

Although the "Lead Edit" page for a new Lead was successfully popped in step 3, the Softphone interface is now gone for good (it disappeared in step 2).  The only way to get the softphone back up and running again is to shut down & restart SalesforceCTI.exe.

As per your suggestion, I'm using the following code just before the "if (IsWindow(pInfo->m_hWnd))":

Code:
if (listRelObjSets.empty())
{
    //Still nothing from the logs, IVR, and ANI -- try to pop a blank Lead
    if(pInfo->m_bPopLeadOnNoMatch)
    {
        CCTILogger::Log(LOGLEVEL_MED,L"CCTIAppExchangeSearchThread::ThreadSearch: bPopLeadOnNoMatch flag set.");
        try
        {
                IQueryResultSet4Ptr pQueryResults = pSession->Query(L"Select Id,Name From New_Lead__c Limit 1",VARIANT_FALSE);
                CCTIAppExchange::PopulateQueryResults(pSession,pQueryResults,pInfo->m_mapLayout,listRelObjSets,false);
        }
        catch(_com_error ce)
        {
            CCTILogger::Log(LOGLEVEL_LOW,L"CCTIAppExchangeSearchThread::ThreadSearch: Error running New_Lead query: %s.",(wchar_t*)pSession->GetErrorMessage());
        }
    }
    else
        CCTILogger::Log(LOGLEVEL_MED,L"CCTIAppExchangeSearchThread::ThreadSearch: bPopLeadOnNoMatch flag NOT set.");
}


...and here are the last few lines of the cti_connector.log:

11/24/2008 17:57:25: CCTIAppExchangeSearchThread::ThreadSearch: bPopLeadOnNoMatch flag set.
11/24/2008 17:57:25: CCTIAppExchange::PopulateQueryResults: ANI query found 1 results.
11/24/2008 17:57:25: CCTIAppExchangeSearchThread::ThreadSearch: Asynchronous search complete.
11/24/2008 17:57:25: CCTIUserInterface::GetLineByCallId: Call ID 1 is on line 1.
11/24/2008 17:57:26: CZeacomSfAdapterUI::UIHandleMessage(). Message: EXIT
11/24/2008 17:57:26: CCTIUserInterface::UIHandleMessage: Message received: EXIT.
11/24/2008 17:57:26: CZeacomSfAdapterUI::CTIDisonnect
11/24/2008 17:57:26: CZeacomSfAdapterUI::CTIDisonnect. Dropping call.
11/24/2008 17:57:26: CZeacomSfAdapterUI::CTIDisonnect: Calling QmCOM Hangup()
11/24/2008 17:57:26: CZeacomSfAdapterUI::CTIDisonnect: Drop call succeeded!
11/24/2008 17:57:26: CCTIAppExchange::Reset: Clearing all cached info.
11/24/2008 17:57:26: UserId set to .


By the way, it works fine if it finds a match to the query data (the normal way). Here is an example of the same part of the cti_connector.log where a match was found (and it did not attempt to pop a blank lead):

11/24/2008 19:09:54: CCTIAppExchange::PopulateQueryResults: ANI query found 1 results.
11/24/2008 19:09:54: CCTIAppExchangeSearchThread::ThreadSearch: Asynchronous search complete.
11/24/2008 19:09:54: CCTIUserInterface::GetLineByCallId: Call ID 1 is on line 1.
11/24/2008 19:09:55: CZeacomSfAdapterUI::UIHandleMessage(). Message: ADD_LOG_OBJECT
11/24/2008 19:09:55: CCTIUserInterface::UIHandleMessage: Message received: ADD_LOG_OBJECT.
11/24/2008 19:09:55: CCTIUserInterface::GetLineByCallId: Call ID 1 is on line 1.
11/24/2008 19:09:59: CZeacomSfAdapterUI::UIHandleMessage(). Message: RELEASE
11/24/2008 19:09:59: CCTIUserInterface::UIHandleMessage: Message received: RELEASE.
11/24/2008 19:09:59: CZeacomSfAdapterUI::CallRelease


...any help with this would be much appreciated :smileyhappy:

apexsutherlandapexsutherland
Is there a reason that the CTI adapter can't just redirect to the New Lead page:

URL:
https://[SFDC Instance].salesforce.com/00Q/e

and populate the Phone field on the page layout instead of quering for the custom object which redirects to the New Lead page through VisualForce?



Message Edited by apexsutherland on 11-24-2008 03:25 PM