Making Salesforce and PayPal Work Together


A common question FormAssembly customers ask is ‘How can I make my organization’s PayPal account and Salesforce account interact more closely?’  With a little bit of Salesforce VisualForce code, you can make your PayPal Instant Payment Notifications (IPNs) update your Salesforce records, closing the loop from your forms to PayPal to Salesforce.

In the steps below we’ll use the example of a form set up to create a Salesforce Opportunity and receive a payment for participation in that Opportunity by the respondent.  The same procedure would work for any other Salesforce object type, but if you have any questions, just email us, we’re happy to help. Do note that the following instructions are geared towards advanced Salesforce users who are comfortable with Apex code and site setup.

Configuring your Salesforce object:

In Salesforce, go to “Setup->App Setup->Customize” and select the object you wish to contain PayPal information.  Let’s say ‘Opportunity’.  Add the following custom fields:

  1. FormAssemblyID: Properties: Text(255) (External ID) (Unique Case Insensitive) API Name: FormAssemblyID__c This is a unique key that FormAssembly adds to your object in order to reference it later.
  2. paid: Properties: Checkbox API Name: paid__c A checkbox for easy querying in Salesforce over your objects to see if the object’s PayPal payment has completed.
  3. PayPalInfo: Properties: Long Text Area(32768) API Name: PayPalInfo__c A large field to hold all data sent by PayPal about the transaction once complete.

Creating your Apex PayPal Notification Class:

In Salesforce, go to “Setup->App Setup->Develop->Apex Classes” and select  ”New”.  Give the class the name ‘IPNHandlerController’, and paste the following code into the interface:

public class IPNHandlerController {

    public PageReference myIPNupdate() {
     try{
        PageReference pageRef = ApexPages.currentPage();
        //Get the value of the 'custom' parameter from current page
        String paramCustom = pageRef.getParameters().get('custom');
        opportunity = [select Id,paid__c from Opportunity where FormAssemblyID__c = :paramCustom ];

        String content = '';
        for(String key : pageRef.getParameters().keySet()){
            //Note that there is no guarantee of order in the parameter key map.
            content += key + ' : ' + pageRef.getParameters().get(key) + '\n';
        }
        opportunity.PayPalInfo__c = content;
        opportunity.paid__c = True;
        update opportunity;

        PageReference newPage = new ApexPages.StandardController(opportunity).view();
        newPage.setRedirect(true);        

        return newPage;
     } catch (System.Exception e){
         //A failure occurred
         system.debug(e);
         return null;
     }
    }

    public Opportunity opportunity {get; set;}

    public IPNHandlerController() {
    }
}

Next, if testing / code coverage is a concern, create a new Apex Class called ‘IPNHandlerTestClass’ by pasting this code into a new Apex Class window:

@istest
private class IPNHandlerTestClass {
    public static testMethod void testMyIPNupdateSuccess(){
        IPNHandlerController ipn = new IPNHandlerController();

        Opportunity c = new Opportunity(Name='Test01',CloseDate=date.parse('1/1/2010'),StageName='Qualification',
FormAssemblyId__c='111111101111110z');
        insert c;
        ApexPages.currentPage().getParameters().put('custom', '111111101111110z');

        PageReference p = ipn.myIPNupdate();
        System.assertNotEquals(null,p);
    }

    public static testMethod void testMyIPNupdateFailure(){
        IPNHandlerController ipn = new IPNHandlerController();
        ApexPages.currentPage().getParameters().put('custom', '111111101111111z');
        PageReference p = ipn.myIPNupdate();
        System.assertEquals(null,p);
    }

    public static testMethod void testIPNHandlerController(){
        //You should customize this to fit your needs.
        System.assertEquals(true,true);
    }

}

Note that in the code above, we’re using the Opportunity type object in Salesforce as our targeted object type to update when PayPal information comes in.  You could just as easily use a Contact object or a Custom object, by substituting the object type name for Opportunity above.

Creating your Apex PayPal Notification Endpoint:

In Salesforce, go to “Setup->App Setup->Develop->Pages” and select  ”New”.  Give the page the name ‘IPNHandler’, and paste the following code into the interface:

<apex:page controller="IPNHandlerController" action="{!myIPNupdate}" />

Now go to “Setup->App Setup->Develop->Sites” and place the page into your Salesforce Site. For example, you could with a new site set the “Active Site Home Page” to ‘IPNHandler’, however this is not recommended for existing sites.  Make a note of where IPNHandler page is located.  It should be something that looks like: http://xxxxx.na3.force.com/yyyy/IPNHandler where ‘xxxxx.na3.force.com’ is your Salesforce sites domain, ‘yyyy’ is the path to where you are hosting the IPNHandler page and ‘IPNHandler’ is the name of the page we’ve created above.

Configuring your FormAssembly.com Form:

In FormAssembly, go to your Salesforce connector mapping.

  1. Map your usual Opportunity fields.
  2. Map the Salesforce field FormAssemblyID to a formula.
  3. Set that formula value to be: http://www.tfaforms.com/responses/view/%%RESPONSE_ID%%

Now go to your your FormAssembly PayPal connector mapping:

  1. Map your PayPal connector as usual.
  2. Change your IPN notification field to the location of your IPNHandler page, for example: http://xxxxx.na3.force.com/IPNHandler

Testing your Setup:

When properly configured, the process will work like so:

  1. Respondent completes the form.
  2. A new Opportunity record is created in Salesforce, with a value like “http://www.tfaforms.com/responses/view/1222222″ in the “FormAssemblyID” Salesforce field.
  3. Respondent completes PayPal section, starting the PayPal authorization and verification process.
  4. Whenever PayPal completes that transaction, PayPal will trigger an IPN to the location: http://xxxxx.na3.force.com/IPNHandler
  5. Once there, the Apex code we’ve created will lookup the Opportunity based on the ‘custom’ parameter included in the PayPal IPN notification which will match the ‘FormAssemblyID’ field, populate the field ‘paid’ to checked, and the field ‘PayPalInfo’ to a newline delimited list of the PayPal parameters passed from the IPN.