Custom Superfecta Source?

myitguy

Guru
Joined
Jan 8, 2011
Messages
97
Reaction score
4
Is anyone aware of any documentation regarding adding a custom Caller ID Superfecta source?

I.E. Is it as easy as copying an existing source_* file and modifying it to fit my needs or is there more involved to this?

I ask as we store all of our customer information in ConnectWise (Basically a CRM for Managed Service providers) and I would like to pull information straight from this database rather than updating AsteriDex or the Asterisk Phone Book.
 

myitguy

Guru
Joined
Jan 8, 2011
Messages
97
Reaction score
4
*edit* Reading a bit about CW, it looks like it is not based on MySQL. If you can give us a few more details, perhaps we can suggest a better existing source to start with.

ConnectWise is MS SQL Based, but they do provide an API that you can use to integrate with (The preferred method in case other ConnectWise users as Cloud/Hosted users don't get access to the database, while I'm an on-premise user I'm keeping others in mind in the event they wish to utilize this code as well).

I think I have a good understanding of the Superfecta source file...but I'm having trouble with generating the request via SOAP to the API.

Below is what I have so far based on the PHP Documentation I've seen (I know the basics of PHP...but this is definitely outside of my knowledge area). Anyone want to provide some insight into how I can make the code below work? If needed I can PM you the specs and the connection info for testing.

PHP:
<?php

// xml content
$xmlDocument = '<?xml version="1.0" encoding="utf-16"?>
<FindPartnerCompaniesAction xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <CompanyName>companyname</CompanyName>
    <IntegrationLoginId>ILID</IntegrationLoginId>
    <IntegrationPassword>ILP</IntegrationPassword>

    <Conditions>PhoneNumber like "XXXXXXXXXX"</Conditions>

    <!-- optional sort field -->
    <OrderBy>CompanyID</OrderBy>

    <!-- optional limit on the number of results returned -->
    <Limit>1</Limit>
</FindPartnerCompaniesAction>';

// Initiate SOAP Client
ini_set("soap.wsdl_cache_enabled", "0");
$client = new SoapClient(
            "https://psa.company.com/v4_6_release/services/system_io/integration_io.asmx?wsdl",
            array(
                'trace' => 1,
                'exceptions' => 1,
                'features' => SOAP_SINGLE_ELEMENT_ARRAYS
            )
);

// Prepare XML
// I debugged using $client->__getLastRequest() and
// then saw that the node around the XML was missing.
// So the trick here is to manually add the parameter
// (see the WSDL to catch the right parameter name of course).
$xmlvar = new SoapVar(
            $xmlDocument,
            XSD_ANYXML
);

// send xml
try {
    $params->xmlDocument = (object)$xmlDocument;
    $save_result = $client->ProcessClientAction($params);
    echo "<pre>\n\n";
    echo "Result :\n";
    var_dump($save_result);
    echo "</pre>";
} catch (SoapFault $e) {
    echo "<b>SOAP Fault:</b> <br />".$e->getMessage()."<br />\n";
}

//* DEBUG
echo "<pre>\n\n";
echo "Request :\n";
echo htmlspecialchars($client->__getLastRequest())."\n";
echo htmlspecialchars($xmlDocument)."\n";
echo "</pre>";
//*/
Once I'm able to get the results back from the server then I should be able to modify the SuperFecta sources pretty easily *Hopefully*
 

myitguy

Guru
Joined
Jan 8, 2011
Messages
97
Reaction score
4
I will start an issue on the dev site to direct some better qualified eyes to this thread.

Much appreciated!

Until we can get the SOAP version worked out, I created a source file using an HTTPS call...it's not the recommended method by the vendor (ConnectWise)...but it works:

PHP:
<?php
//this file is designed to be used as an include that is part of a loop.
//If a valid match is found, it should give $caller_id a value
//available variables for use are: $thenumber
//retreive website contents using get_url_contents($url);

/* BUG FIXES */
// v0.1.0: Initial Release Version


//configuration / display parameters
//The description cannot contain "a" tags, but can contain limited HTML. Some HTML (like the a tags) will break the UI.
$source_desc = "Look up data in your ConnectWise CRM, local or remote.<br>Fill in the appropriate ConnectWise configuration information to make the connection to the ConnectWise database.";
$source_param = array();
$source_param['DB_Site']['desc'] = 'ConnectWise Site URL';
$source_param['DB_Site']['type'] = 'text';

$source_param['DB_Company']['desc'] = 'ConnectWise Company ID';
$source_param['DB_Company']['type'] = 'text';

$source_param['DB_User']['desc'] = 'Integration Username to connect to ConnectWise';
$source_param['DB_User']['type'] = 'text';

$source_param['DB_Password']['desc'] = 'Integration Password to connect to ConnectWise';
$source_param['DB_Password']['type'] = 'password';

$source_param['Search_Type']['desc'] = 'The ConnectWise type of entries that should be used to match the number';
$source_param['Search_Type']['type'] = 'select';
$source_param['Search_Type']['option'][0] = 'Companies Only';
$source_param['Search_Type']['option'][1] = 'Contacts Only';
$source_param['Search_Type']['option'][2] = 'Companies --> Contacts';
$source_param['Search_Type']['default'] = 1;
$source_param['Filter_Length']['desc']='The number of rightmost digits to check for a match';
$source_param['Filter_Length']['type']='number';
$source_param['Filter_Length']['default']= 9;



//run this if the script is running in the "get caller id" usage mode.
if($usage_mode == 'get caller id')
{
$integration_site = $run_param['DB_Site'];
$integration_company = $run_param['DB_Company'];
$integration_user = $run_param['DB_User'];
$integration_password = $run_param['DB_Password'];
$varSearchType = $run_param['Search_Type'];

    if($debug)
    {
        print "Searching ConnectWise ... ";
    }
    
    $wquery_input = "";
    $wquery_string = "";
    $wquery_result = "";
    $wresult_caller_name = "";
        
    $wquery_input = preg_replace("/\D/","",$thenumber); // strip non-digits
    if (strlen($wquery_input) == 0) exit; // abandon search if no number is passed
    if (strlen($wquery_input) > $run_param['Filter_Length']) $wquery_input = substr($wquery_input, -$run_param['Filter_Length']); // keep only the filter_length rightmost digits

    // Search Companies
    if($run_param['Search_Type'] == 0 || $run_param['Search_Type'] = 2)
    {
        $integration_xml = <<<EOT
            <FindPartnerCompaniesAction xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
            <CompanyName>$integration_company</CompanyName>
            <IntegrationLoginId>$integration_user</IntegrationLoginId>
            <IntegrationPassword>$integration_password</IntegrationPassword>
            <Conditions>PhoneNumber like "$thenumber"</Conditions>
            <OrderBy>CompanyID</OrderBy>
            <Limit>1</Limit>
            </FindPartnerCompaniesAction>
EOT;

        // Order of replacement
        $order   = array("\r\n", "\n", "\r");
        $replace = '';
    
        // Processes \r\n's first so they aren't converted twice.
        $integration_xml = str_replace($order, $replace, $integration_xml);

        $url="https://$integration_site/v4_6_release/services/system_io/integration_io.asmx/ProcessClientAction?actionString=".urlencode($integration_xml);
        //$value = get_url_contents($url);
        $ch = curl_init();
        $timeout = 5; // set to zero for no timeout
        curl_setopt ($ch, CURLOPT_URL, $url);
        curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
        $value = htmlspecialchars_decode(curl_exec($ch));
        curl_close($ch);

        $pattern = "/<CompanyName>(.*?)<\/CompanyName>/";
        preg_match_all($pattern, $value, $matches);
        if (count($matches[0])>1) {
            $wresult_caller_name = $matches[0][1];
        }
    }
    
    // Search Contacts
    
    if($run_param['Search_Type'] == 1 || $run_param['Search_Type'] == 2 && $wresult_caller_name =="")
    {
        $integration_xml = <<<EOT
            <FindPartnerContactsAction xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
            <CompanyName>$integration_company</CompanyName>
            <IntegrationLoginId>$integration_user</IntegrationLoginId>
            <IntegrationPassword>$integration_password</IntegrationPassword>
            <Conditions>Phone like "$thenumber"</Conditions>
            <OrderBy>LastName</OrderBy>
            <Limit>10</Limit>
            </FindPartnerContactsAction>
EOT;

        // Order of replacement
        $order   = array("\r\n", "\n", "\r");
        $replace = '';
    
        // Processes \r\n's first so they aren't converted twice.
        $integration_xml = str_replace($order, $replace, $integration_xml);

        $url="https://$integration_site/v4_6_release/services/system_io/integration_io.asmx/ProcessClientAction?actionString=".urlencode($integration_xml);
        //$value = get_url_contents($url);
        $ch = curl_init();
        $timeout = 5; // set to zero for no timeout
        curl_setopt ($ch, CURLOPT_URL, $url);
        curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
        $value = htmlspecialchars_decode(curl_exec($ch));
        curl_close($ch);

        $pattern = "/<LastName>(.*?)<\/LastName>/";
        preg_match($pattern, $value, $match_LastName);
        
        $pattern = "/<FirstName>(.*?)<\/FirstName>/";
        preg_match($pattern, $value, $match_FirstName);
        if (count($match_LastName)>0 && count($match_FirstName)>0) {
            $wresult_caller_name = $match_FirstName[0]." ".$match_LastName[0];
        }
    }
    
    if(strlen($wresult_caller_name) > 0)
    {
        $caller_id = $wresult_caller_name;
    }
    else if($debug)
    {
        print "not found<br>\n";
    }
}
?>
 

myitguy

Guru
Joined
Jan 8, 2011
Messages
97
Reaction score
4
I haven't tried it but a couple of thing stick out to me. The "search type selector" should use numbers 1, 2 & 3 and not 0, 1 & 2. If you test it you will find that the first option doesn't stick. Remove the final "?>" from the code to prevent stray spaces and cr's.

You don't need these lines, they are a remnant of the superfecta dark ages:
PHP:
    $wquery_input = preg_replace("/\D/","",$thenumber); // strip non-digits
     if (strlen($wquery_input) == 0) exit; // abandon search if no number is passed
To allow some future user to disable the filter length, enclose it like this:
PHP:
$source_param['Filter_Length']['desc'] = 'The number of rightmost digits to check for a match. Enter false to disable this setting';
.
.
.
if ($run_param['Filter_Length'] != false)
        {
                 if (strlen($wquery_input) > $run_param['Filter_Length']) $wquery_input = ... etc;
        }

Thanks for the feedback, the changes have been made except for one. You mention removing the final "?>", isn't this needed for the PHP interpreter?
 

ukstevef

Guru
Joined
Sep 20, 2009
Messages
134
Reaction score
0
Thanks for the feedback, the changes have been made except for one. You mention removing the final "?>", isn't this needed for the PHP interpreter?
You need to remove this as all the superfecta modules are used as includes.

Do you still need help with your SOAP requests ?, I could probably find some time to debug/help if required.
 

myitguy

Guru
Joined
Jan 8, 2011
Messages
97
Reaction score
4
You need to remove this as all the superfecta modules are used as includes.

Never knew that the ending ?> wasn't needed on includes. Do I still need to include the <?php at the beginning then?

Do you still need help with your SOAP requests ?, I could probably find some time to debug/help if required.

I would be interested in pursuing the SOAP request method further in the event the vendor ever removes the HTTPS functionality in future updates.

If anything is needed just let me know (I can provide web space, API documentation from the vendor and access to my system for testing purposes).
 

ukstevef

Guru
Joined
Sep 20, 2009
Messages
134
Reaction score
0
Never knew that the ending ?> wasn't needed on includes. Do I still need to include the <?php at the beginning then?
Yes, this is still required.

I would be interested in pursuing the SOAP request method further in the event the vendor ever removes the HTTPS functionality in future updates.

If anything is needed just let me know (I can provide web space, API documentation from the vendor and access to my system for testing purposes).
I would tend to agree with you, if the preferred method is SOAP then that is the solution that time should be lavished upon :)
Having never used CW before, you are in a better position than me, but I am happy to help with code review and if time permits possibly remote testing.
 

tm1000

Schmoozecom INC/FreePBX
Joined
Dec 1, 2009
Messages
1,360
Reaction score
78
Clarification.

The ending ?> is never needed on any PHP files. Ever. regardless of if they are includes or not.

You'd use the ?> in situations where you are using HTML and PHP at the same time.
 

Members online

No members online now.

Forum statistics

Threads
25,812
Messages
167,761
Members
19,240
Latest member
nikko
Get 3CX - Absolutely Free!

Link up your team and customers Phone System Live Chat Video Conferencing

Hosted or Self-managed. Up to 10 users free forever. No credit card. Try risk free.

3CX
A 3CX Account with that email already exists. You will be redirected to the Customer Portal to sign in or reset your password if you've forgotten it.
Top