CForms to MethodCRM: Getting dirty with SOAP.

MethodCRM integrated with GMailOne of our clients recently began using MethodCRM to handle their sales/coordination process. It’s a pretty slick web based CRM tool which comes with some nifty plugins like their GMail integration (shown here). The challenge was to redirect our CForms data gathering form (which previously posted to Google Docs) to now post to MethodCRM. There were a few obstacles here:

  • Method is a dotNet based system, so the structural requirements of the SOAP package were a little different than what PHP’s SoapClient produced (leading to a lot of frustrating login fail responses).
  • The structure of the MethodCRM API only allows posting to a single table simultaneously, and cascades data through a hierarchy with each new post; populating the Customer table first prepopulates contact data in subsidiary views, and specific fields are used to link Customers with Opportunities, which have to be created after the Customer record. Thus, to generate both the Customer record, and spawn a new sales opportunity was going to require multiple posts.

I fought with their system and generic error responses for several days before discovering the very awesome SoapUI. If you ever have to work with SOAP, get that tool, as it is invaluable at tracking down issues. I sniffed the available methods through their API, and figured out the issue: dotNet and PHP, using standard SOAP call functions, generate slightly different XML packages. The strict interpretation of the Method API system meant if my packages didn’t exactly meet their spec, then no dice.

Let's do this.Challenge accepted. Some digging through StackOverflow found a fair number of folks with similar issues, and one solution for just posting whole XML packages via cURL as a variable. While not as ideal programmatically as iterating the nodes at run time, it looked to be a fix for my issue. With a little tweaking (and using the SOAP syntax as created by SoapUI), I was successfully able to post a few test messages, and then rewrote my cforms/myfunctions.php as follows:

 

function my_cforms_action($cformsdata) {

#Get form info
$formID = $cformsdata['id'];
$form   = $cformsdata['data'];

#Assign Address
$url = 'https://www.methodintegration.com/MethodAPI/service.asmx?wsdl';

#prepare post data

$FirstName = $form ['First Name'];
$LastName = $form ['Last Name'];
$Phone = $form ['Phone'];
$Email = $form ['Email'];
$EventType = $form ['Event Type'];
$GuestCount = $form ['Est. No. of Guests'];
$RequestDate = $form ['Select Date'];
$DateFlex = $form ['Is this date flexible?'];
$FlexDetail = $form ['If yes, please provide details:'];
$Budget = $form ['Estimate'];
$EventDetail = $form ['Special Instructions or Additional Details'];
$LeadSource = $form ['How did you hear about us?'];
$CustomerName = $FirstName . ' ' . $LastName . ' Web Lead';
$OpportunityName = $LastName . ' ' . $EventType . ' ' . $RequestDate;
$date = date('Y-M-d h:i:s A');
$CloseDate = date('Y-M-d h:i:s A', strtotime("+30 days"));

$post_string = '<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:tem="http://tempuri.org/">
   <soap:Header/>
   <soap:Body>
      <tem:MethodAPIInsertV2>
         <!--Optional:-->
         <tem:strCompanyAccount>mycompanyaccount</tem:strCompanyAccount>
         <!--Optional:-->
         <tem:strLogin>mylogin</tem:strLogin>
         <!--Optional:-->
         <tem:strPassword>mypassword</tem:strPassword>
         <!--Optional:-->
         <tem:strSessionID/>
         <!--Optional:-->
         <tem:strTable>Customer</tem:strTable>
         <!--Optional:-->
         <tem:arrInsertFieldsArray>
            <!--Zero or more repetitions:-->
            <tem:string>AssignedTo</tem:string>
            <tem:string>Email</tem:string>
            <tem:string>IsLeadStatusOnly</tem:string>
            <tem:string>FirstName</tem:string>
            <tem:string>LastName</tem:string>
            <tem:string>IsActive</tem:string>
            <tem:string>LeadRating</tem:string>
            <tem:string>LeadSource</tem:string>
            <tem:string>LeadStatus</tem:string>
            <tem:string>Name</tem:string>
            <tem:string>Phone</tem:string>
         </tem:arrInsertFieldsArray>
         <!--Optional:-->
         <tem:arrInsertValueArray>
            <!--Zero or more repetitions:-->
            <tem:string>Sales Rep</tem:string>
            <tem:string>'. $Email .'</tem:string>
            <tem:string>True</tem:string>
            <tem:string>'. $FirstName .'</tem:string>
            <tem:string>'. $LastName .'</tem:string>
            <tem:string>True</tem:string>
            <tem:string>Hot</tem:string>
            <tem:string>'. $LeadSource .'</tem:string>
            <tem:string>Open</tem:string>
            <tem:string>'. $CustomerName .'</tem:string>
            <tem:string>'. $Phone .'</tem:string>
         </tem:arrInsertValueArray>
      </tem:MethodAPIInsertV2>
   </soap:Body>
</soap:Envelope>';
$soap_do = curl_init(); 
curl_setopt($soap_do, CURLOPT_URL,            $url );   
curl_setopt($soap_do, CURLOPT_CONNECTTIMEOUT, 10); 
curl_setopt($soap_do, CURLOPT_TIMEOUT,        10); 
curl_setopt($soap_do, CURLOPT_RETURNTRANSFER, true );
curl_setopt($soap_do, CURLOPT_SSL_VERIFYPEER, false);  
curl_setopt($soap_do, CURLOPT_SSL_VERIFYHOST, false); 
curl_setopt($soap_do, CURLOPT_POST,           true ); 
curl_setopt($soap_do, CURLOPT_POSTFIELDS,    $post_string); 
curl_setopt($soap_do, CURLOPT_HTTPHEADER,     array('Content-Type: text/xml; charset=utf-8', 'SOAPAction: "http://tempuri.org/MethodAPIInsertV2"', 'Content-Length: '.strlen($post_string) )); 


$result = curl_exec($soap_do);
$err = curl_error($soap_do); 

if(curl_exec($soap_do) === false)
{
    echo 'Curl error: ' . curl_error($soap_do);
    // Dump the whole shizzle
		curl_close($soap_do);
		
}
else
{
// Close our first cURL session and start a new one
curl_close($soap_do);

// Clear our previous values
unset ($post_string, $soap_do, $result, $err);

// Prepare for our next cURL
$post_string = '<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:tem="http://tempuri.org/">
   <soap:Header/>
   <soap:Body>
      <tem:MethodAPIInsertV2>
         <!--Optional:-->
         <tem:strCompanyAccount>mycompanyaccount</tem:strCompanyAccount>
         <!--Optional:-->
         <tem:strLogin>my login</tem:strLogin>
         <!--Optional:-->
         <tem:strPassword>my password</tem:strPassword>
         <!--Optional:-->
         <tem:strSessionID/>
         <!--Optional:-->
         <tem:strTable>Opportunity</tem:strTable>
         <!--Optional:-->
         <tem:arrInsertFieldsArray>
            <!--Zero or more repetitions:-->
            <tem:string>AssignedTo</tem:string>
            <tem:string>BudgetEstimate</tem:string>
            <tem:string>Customer</tem:string>
            <tem:string>EventDate</tem:string>
            <tem:string>EventType</tem:string>
            <tem:string>FlexibleDate</tem:string>
            <tem:string>FlexibleDetails</tem:string>
            <tem:string>Guests</tem:string>
            <tem:string>Name</tem:string>
            <tem:string>Details</tem:string>
            <tem:string>CloseDate</tem:string>
            <tem:string>OpportunityStage</tem:string>
         </tem:arrInsertFieldsArray>
         <!--Optional:-->
         <tem:arrInsertValueArray>
            <!--Zero or more repetitions:-->
            <tem:string>Sales Rep</tem:string>
            <tem:string>'. $Budget .'</tem:string>
            <tem:string>'. $CustomerName .'</tem:string>
            <tem:string>'. $RequestDate .'</tem:string>
            <tem:string>'. $EventType .'</tem:string>
            <tem:string>'. $DateFlex .'</tem:string>
            <tem:string>'. $FlexDetail .'</tem:string>
            <tem:string>'. $GuestCount .'</tem:string>
            <tem:string>'. $OpportunityName .'</tem:string>
            <tem:string>'. $EventDetail .'</tem:string>
            <tem:string>'. $CloseDate .'</tem:string>
            <tem:string>My Opportunity Stage</tem:string>
         </tem:arrInsertValueArray>
      </tem:MethodAPIInsertV2>
   </soap:Body>
</soap:Envelope>';
$soap_do = curl_init(); 
curl_setopt($soap_do, CURLOPT_URL,            $url );   
curl_setopt($soap_do, CURLOPT_CONNECTTIMEOUT, 10); 
curl_setopt($soap_do, CURLOPT_TIMEOUT,        10); 
curl_setopt($soap_do, CURLOPT_RETURNTRANSFER, true );
curl_setopt($soap_do, CURLOPT_SSL_VERIFYPEER, false);  
curl_setopt($soap_do, CURLOPT_SSL_VERIFYHOST, false); 
curl_setopt($soap_do, CURLOPT_POST,           true ); 
curl_setopt($soap_do, CURLOPT_POSTFIELDS,    $post_string); 
curl_setopt($soap_do, CURLOPT_HTTPHEADER,     array('Content-Type: text/xml; charset=utf-8', 'SOAPAction: "http://tempuri.org/MethodAPIInsertV2"', 'Content-Length: '.strlen($post_string) )); 


$result = curl_exec($soap_do);
$err = curl_error($soap_do);

		
    // Dump the whole shizzle
		curl_close($soap_do);
}
}

While this isn’t the most graceful method of SOAP interaction, it gets the job done, and successfully creates a new customer lead and associated sales opportunity, assigned to the rep of your choice. Possible variations for the process include:

  • Using a drop down in CForms to allow the submitter to select who the submission is assigned to.
  • Additional fields/values of your choice.

I made a few arbitrary decisions here that fit our business process: I set the CloseDate value to be 30 days from the form submission, set up an arbitrary structure for the Customer Name and Opportunity Name, and included some custom fields in our post which likely won’t pertain to your need. Feel free to go wild with it, and post your uses in the comments.