Merry Christmas!
Monday 17 December 2012
Merry Christmas from Desynit
I'm devastated to tell you that I wasn't in the office the day that this little productive gem was filmed, but all the same, Merry Christmas from Desynit and the Simon Lawrence Application Development Blog...
Don't forget to like Desynit on Facebook to make us feel all loved and popular, and if you so wish to know more about what I do (typically outside of programming) dig me up on twitter too.
Merry Christmas!
Merry Christmas!
Wednesday 26 September 2012
Outputting the Salesforce 18 character ID
Those familiar with Salesforce record IDs, and more specifically their use within the Salesforce API will probably know that they come in both 15 and 18 character variations.
The 15 digit ID, as seen in the URL of any record within Salesforce, is a case sensitive ID, and can be confidently used internally within your org for managing objects.
If you intend to use, load or manipulate records with an external program, for example, exporting data via reports or the API, you will probably need to use the 18 digit ID, which includes three extra "check digits" and is not case sensitive. It is important to remember, that functions like Excel's VLOOKUP are not case sensitive, nor, by default are MySQL queries.
There are a number of functions and tools available to manually calculate the last three characters, and a really brilliant explainantion of how the digits are calculated, and their use can be found on the Astadia blog post 15 or 18 Character IDs in Salesforce.com.
This isn't an ideal solution though, which leaves you thinking that there must be a simpler way to get the 18 digit ID out of the front end of your organisation. And of course, you can, and once you know how, it's actually incredibly simple!
All you need to do is create a new custom formula field on your object, give it a relevant name, set it's type to "text" and in the formula box enter:
CASESAFEID(Id)
and that's it! If you're feeling particularly lazy, it's even in the righthand box of "Functions" and you can just double click it to enter.
Save the field, alter your field level security settings, and add it to the relevant page layouts and this field will display the 18 digit ID on your Salesforce record.
Now when you want to test, or work, with your Salesforce records, as they will have been saved in external applications and data exports, you can grab the 18 character ID straight off your page layout.
The 15 digit ID, as seen in the URL of any record within Salesforce, is a case sensitive ID, and can be confidently used internally within your org for managing objects.
If you intend to use, load or manipulate records with an external program, for example, exporting data via reports or the API, you will probably need to use the 18 digit ID, which includes three extra "check digits" and is not case sensitive. It is important to remember, that functions like Excel's VLOOKUP are not case sensitive, nor, by default are MySQL queries.
There are a number of functions and tools available to manually calculate the last three characters, and a really brilliant explainantion of how the digits are calculated, and their use can be found on the Astadia blog post 15 or 18 Character IDs in Salesforce.com.
This isn't an ideal solution though, which leaves you thinking that there must be a simpler way to get the 18 digit ID out of the front end of your organisation. And of course, you can, and once you know how, it's actually incredibly simple!
All you need to do is create a new custom formula field on your object, give it a relevant name, set it's type to "text" and in the formula box enter:
CASESAFEID(Id)
and that's it! If you're feeling particularly lazy, it's even in the righthand box of "Functions" and you can just double click it to enter.
Save the field, alter your field level security settings, and add it to the relevant page layouts and this field will display the 18 digit ID on your Salesforce record.
Now when you want to test, or work, with your Salesforce records, as they will have been saved in external applications and data exports, you can grab the 18 character ID straight off your page layout.
Monday 10 September 2012
Dreamforce 2012: Integrating PayPal Mass Payments with Force.com
"Welcome to Dreamforce 2012"
Everywhere you look at the moment in the Salesforce.com world, there are banners, blogs and news articles hailing the largest ever Enterprise IT conference.
It used to be held at the worlds biggest conference centre, the Moscone West in San Francisco; but now, it's held at the worlds biggest conference centre AND ten surrounding hotels and facilities. Not to mention closing off a few streets and booking out every hotel in the west of the city. With 70,000 attendees, and a gala headlined by the Red Hot Chilli Peppers, this is the CRM industry's flagship event.
So who wouldn't want to give a presentation there? Especially on such an awesome topic as combining one of the worlds most popular and accessible payment gateways with the worlds coolest CRM
(ok, it's just the inner-nerd in me that's getting so excited about those bits).
Welcome then to the supporting blog post to this Dreamforce 2012 developer track session:
Integrating PayPal Mass Payments with Force.com
If you are attending Dreamforce, you'll have access to the Chatter (touch!) session page here.
So what can you expect from this session? Well, having found this post, I can promise you will be well placed to take the most away from this presentation (and if you are here after the session, you will find this blog, along with what I presented an incredibly valuable combination towards understanding the process).
Firstly, let me link you up with the GitHub repository containing the integration code and demo files:
https://github.com/srlawr/PaypalSFDC
Once I have clearance from Salesforce.com I will post the slides from the presentation up here too, but really, what you'll want is these two blog posts on the topic, which are the original works that landed me the Dreamforce presentation in the first place:
1) Salesforce - Paypal Masspay Integration
2) Salesforce - Paypal IPN integration
Working through these two blog posts should empower a talented developer to perform their own complete PayPal Mass Payments integration in a couple of days. If you don't have this kind of resource, or want to tap into my expert knowledge on the topic.. please get in touch with my employers Desynit, and I'm sure they will be more than happy to talk to you.
Everywhere you look at the moment in the Salesforce.com world, there are banners, blogs and news articles hailing the largest ever Enterprise IT conference.
It used to be held at the worlds biggest conference centre, the Moscone West in San Francisco; but now, it's held at the worlds biggest conference centre AND ten surrounding hotels and facilities. Not to mention closing off a few streets and booking out every hotel in the west of the city. With 70,000 attendees, and a gala headlined by the Red Hot Chilli Peppers, this is the CRM industry's flagship event.
So who wouldn't want to give a presentation there? Especially on such an awesome topic as combining one of the worlds most popular and accessible payment gateways with the worlds coolest CRM
(ok, it's just the inner-nerd in me that's getting so excited about those bits).
Welcome then to the supporting blog post to this Dreamforce 2012 developer track session:
Integrating PayPal Mass Payments with Force.com
If you are attending Dreamforce, you'll have access to the Chatter (touch!) session page here.
So what can you expect from this session? Well, having found this post, I can promise you will be well placed to take the most away from this presentation (and if you are here after the session, you will find this blog, along with what I presented an incredibly valuable combination towards understanding the process).
Firstly, let me link you up with the GitHub repository containing the integration code and demo files:
https://github.com/srlawr/PaypalSFDC
Once I have clearance from Salesforce.com I will post the slides from the presentation up here too, but really, what you'll want is these two blog posts on the topic, which are the original works that landed me the Dreamforce presentation in the first place:
1) Salesforce - Paypal Masspay Integration
2) Salesforce - Paypal IPN integration
Working through these two blog posts should empower a talented developer to perform their own complete PayPal Mass Payments integration in a couple of days. If you don't have this kind of resource, or want to tap into my expert knowledge on the topic.. please get in touch with my employers Desynit, and I'm sure they will be more than happy to talk to you.
Thursday 30 August 2012
Certified Force.com Developer
I remember a time when I blogged about coding and solving technical problems with intelligent solutions, but now I seem to write more and more about qualifications and user-meetups.
Maybe I am becoming a consultant after all?
Well asides, because it's time for a new badge, and about time too. I have just taken and passed my Salesforce.com Certified Force.com developers exam. I have huge thanks to pass on to Christopher Lewis, a colleague with the qualification who helped me prepare, through conversations, debates and a wicked revision guide, and also to the boss himself who took the exam minutes before me (and passed) which boosted my confidence nicely.
So here's to DREAMFORCE 2012, and my Developer Session "Integrating PayPal Mass Payments with Force.com" - presented Friday September 21st 11:00 San Francisco time (7:00pm UK time) in the Developer Theatre.
Maybe I am becoming a consultant after all?
Well asides, because it's time for a new badge, and about time too. I have just taken and passed my Salesforce.com Certified Force.com developers exam. I have huge thanks to pass on to Christopher Lewis, a colleague with the qualification who helped me prepare, through conversations, debates and a wicked revision guide, and also to the boss himself who took the exam minutes before me (and passed) which boosted my confidence nicely.
So here's to DREAMFORCE 2012, and my Developer Session "Integrating PayPal Mass Payments with Force.com" - presented Friday September 21st 11:00 San Francisco time (7:00pm UK time) in the Developer Theatre.
Monday 25 June 2012
Now Cross Browser Compatible!
I recently attended The Learning Tree's "CSS for Web Page Development" course, at their Euston House education center, London.
I have just received my certificate for completing the 3 day qualification, having passed the final exam with a super respectable 87.5%.
I have just received my certificate for completing the 3 day qualification, having passed the final exam with a super respectable 87.5%.
Thursday 17 May 2012
Force by Forcewest: Salesforce Developer meetup
Thursday May 31st @ 6pm in The Elephant, Bristol
It's that time again, time for me to sell my soul and advertise another group meet-up in the South West of England.This time, the group is Force by Forcewest, it's an-off shoot of the original Salesforce user group, Forcewest, and it's really intended just for the technically minded. No old admins in battered ties, or accountants talking about licence costs, just developers, coders and hackers (ethical, of course) talking about Apex, Workflow and Visualforce.
So if you live anywhere near Bristol and you know how important semi-colons are, then write "May 31st - FxFw" on a post-it note and stick it to your monitor. We'll be meeting in The Elephant pub, in St. Nicks market, please come on down and join us for a couple of beers, and to meet like minded people.
Sign up for more info on the usual channels:
http://www.facebook.com/ForceByForceWest
http://twitter.com/fxfwbarman
and actually sign up (for free!)
http://fxfw1.eventbrite.com/
but more importantly just head to this pub:
Thursday 10 May 2012
Drupal cron stopped working after site migration
Have you recently moved your Drupal website to a new server, and all
of a sudden Cron has stopped working, and all your jobs
are timing out, or locking up?
That has recently happened to me.
First of all, I will point out that I am using Drupal 7, and we are managing a number of jobs using the Ultimate Cron module, which as you may know, is dependant on the Background Process (and Progress) module(s). We migrated our site from a test server to a live server, with identical setup, and all of a sudden, our cron jobs packed in. I couldn't run them automatically, manually, externally, with drush or even from the root shell.
For a day I struggled. With every CRON setting I could imagine.
Then, whilst manually trawling through the system and variable tables in the database I discovered the following setting:
http://test.desynit.com is the name server of test site (obviously). This is not the path of the live server.
So I leapt into the admin config for the BACKGROUND PROCESS module, and lo and behold, there it was..
I clicked "Determine default service host" and this was instantly updated to the new correct base_url for the live server, and away you go!
Full cron ahead.
I hope this helps someone out.
That has recently happened to me.
First of all, I will point out that I am using Drupal 7, and we are managing a number of jobs using the Ultimate Cron module, which as you may know, is dependant on the Background Process (and Progress) module(s). We migrated our site from a test server to a live server, with identical setup, and all of a sudden, our cron jobs packed in. I couldn't run them automatically, manually, externally, with drush or even from the root shell.
For a day I struggled. With every CRON setting I could imagine.
Then, whilst manually trawling through the system and variable tables in the database I discovered the following setting:
background_process_derived_default_host | a:1:{s:7:"default";a:1:{s:8:"base_url";s:20:"http://test.desynit.com";}}
http://test.desynit.com is the name server of test site (obviously). This is not the path of the live server.
So I leapt into the admin config for the BACKGROUND PROCESS module, and lo and behold, there it was..
I clicked "Determine default service host" and this was instantly updated to the new correct base_url for the live server, and away you go!
Full cron ahead.
I hope this helps someone out.
Tuesday 10 April 2012
Forcewest - UK Salesforce user group
Where will you be on April 17th 2012? If you'll be anywhere near the south west of England, can I recommend you make your evening plans to be attending Forcewest?
There's a presentation from Simon Parker who is presenting his Surf Life Saving Salesforce.com implementation case study, followed by an open Q&A. The night then normally evolves into an eruption of conversation and debate about almost all technologies.
I'll also point out that there is a fair tab behind the bar, courtesy of Desynit, so if you're in good time you can enjoy a free pint to help break the ice with your fellow Salesforce.com users.
Thursday 2 February 2012
Salesforce Paypal IPN integration
In my previous post Salesforce Paypal Integration I went through sending payment details to the Paypal Mass Payments API. By the end of that post, your application should be receiving "Success" messages from Paypal, and seeing payments move between two accounts. This is really only half the story though.
The "Success" message is Paypal confirming it has received the SOAP request, and it was correctly structured. You don't actually know what has happened to each payment row in your request. What, for example, happens to payments issued to e-mail addresses not registered to a Paypal account? Or if a transaction is cancelled or reversed? These are things you need to know, and that is where the Paypal IPN system comes into play.
The IPN messages are documented quite well here on the PayPal website, and indeed if you were developing in ASP or Java, that's probably all you'd need to get going with them, but this is Salesforce.com, and so things are a little different.
IPN messages are the second half of our payment process diagram:
They originate from PayPal, and are delivered to a URL in your application.
Your first action is to send the whole message back to PayPal, which will verify it originated there, and that it is intact.
You can then examine the message, extract the referenced payments, and execute update actions on their status/pay dates and so forth.
IPN messages for a transaction can appear any time up to 30 days after it was requested, and IPN messages can update a single transaction many times, depending on how complicated it proves to be.
So how do we deal with IPN messages in Salesforce? In short, we are going to do the following:
So go to Your name -> Setup -> Develop -> Apex classes and select to make a new class. Then copy the file PaypalIPNController.cls from the GitHub repository:
https://github.com/srlawr/PaypalSFDC/blob/master/PaypalIPNController.cls
Have a read through it so you know what's going on, and you'll probably notice that because this controller has to send the message back to PayPal we will need to add the verification URL to our Remote Site Settings so your application can communicate with the outside world.
Go to Your name -> Setup -> Security Controls -> Remote Site Settings and add a new Paypal URL for:
With the Apex controller in place, we need to create the page to front it. There isn't actually anything on this page, because it's never going to be served out to a browser, it is simply acting as as URL for web-service calls. We do need to point it at this controller though,
Navigate your way to Your name -> Setup -> Develop -> Pages and create a new page. Call it Paypal_IPN, for clarity. This Visualforce page only has one real line to it, which you can see in paypal_ipn.page on GitHub:
https://github.com/srlawr/PaypalSFDC/blob/master/paypal_ipn.page
This is all the code you really need. When the page is loaded, the controller is constructed, and you can see the Apex page "Action" attribute to call the function "digestMessage", this is because you cannot make DML calls in a controller's constructor, or any method calls direct from it.
The final action on the Salesforce side of things is to expose this page via Salesforce sites. Click Your name -> Setup -> Develop -> Sites and click to create a new Site. I simply set the label, name and default web address all to "Paypal" and then in the Active Site Home Page selected the new page we just created.
The sites detail page should list a number of attributes of this new object, one of which is "Secure Web Address" - copy the value of this to your clipboard, because we're going to need it in a minute.
Next then, back in your Paypal sandbox, we need to tell it what URL to send the messages too, so log into your Payments Pro account and click on "Profile" -> "Instant Payment Notification preferences". On this page, you will need to enter the Secure Web Address of the Salesforce.com page, and Enable IPN messages. From the confirmation page, head over to the "IPN History Page", this page could become your best friend during development/testing.
Ready to roll!
It feels like we've done enough work now. Lets see if it's all come together.
If you return to your Payments List page, and make sure you have a handful of payment records with a status of "Unpaid", you should find yourself looking at something like this:
Just like in the last stage, if you click the "Pay out" button, the page should reload, with a success message and, having updated all the PayPal Status values to "Sent".
What has happened now is PayPal has received the request and is whipping through each of your transfers. Typically, (typically!!) this takes a few seconds in the first instance, and after each row has been considered, your first IPN message will be sent over by PayPal.
Twiddle your thumbs for just a few seconds (or if you wish to use this time constructively, check your PayPal sandbox, and make sure your transaction has been recorded on their side) and then reload the Payment List page in Salesforce.
You should see the status column has been updated, to something similar to this:
In this case, three of my transactions (those associated with my PayPal Sandbox email addresses) have completed entirely, and instantly, but one transaction is currently sitting unclaimed, because that e-mail address isn't associated with a PayPal account. You can read up more on IPN status codes over on the PayPal website.
In Paypal you can view your IPN messages, like the one below, from your IPN history page, which you'll find linked from the configuration page you put your IPN endpoint in above.
That really is it though, for a basic demonstration of Integrating the PayPal Mass Payments API with Force.com.
It should be absolutely noted that this is a purely educational blog post, and no-one should ever attempt to implement payment gateways or infrastructures without the appropriate knowledge and testing.
If you would like to talk to Desynit about applying this knowledge to your business or organisation, please get in touch via the details on our website. Otherwise, any questions or discussions are always more than welcome in the comments section below.
The "Success" message is Paypal confirming it has received the SOAP request, and it was correctly structured. You don't actually know what has happened to each payment row in your request. What, for example, happens to payments issued to e-mail addresses not registered to a Paypal account? Or if a transaction is cancelled or reversed? These are things you need to know, and that is where the Paypal IPN system comes into play.
The IPN messages are documented quite well here on the PayPal website, and indeed if you were developing in ASP or Java, that's probably all you'd need to get going with them, but this is Salesforce.com, and so things are a little different.
IPN messages are the second half of our payment process diagram:
They originate from PayPal, and are delivered to a URL in your application.
Your first action is to send the whole message back to PayPal, which will verify it originated there, and that it is intact.
You can then examine the message, extract the referenced payments, and execute update actions on their status/pay dates and so forth.
IPN messages for a transaction can appear any time up to 30 days after it was requested, and IPN messages can update a single transaction many times, depending on how complicated it proves to be.
So how do we deal with IPN messages in Salesforce? In short, we are going to do the following:
- Establish a publically visible end point, using a visualforce page, and Salesforce sites
- Implement a custom controller to execute the behaviour described above
So go to Your name -> Setup -> Develop -> Apex classes and select to make a new class. Then copy the file PaypalIPNController.cls from the GitHub repository:
https://github.com/srlawr/PaypalSFDC/blob/master/PaypalIPNController.cls
Have a read through it so you know what's going on, and you'll probably notice that because this controller has to send the message back to PayPal we will need to add the verification URL to our Remote Site Settings so your application can communicate with the outside world.
Go to Your name -> Setup -> Security Controls -> Remote Site Settings and add a new Paypal URL for:
PayPal Sandbox IPN: https://www.sandbox.paypal.com/cgi-bin/webscr
With the Apex controller in place, we need to create the page to front it. There isn't actually anything on this page, because it's never going to be served out to a browser, it is simply acting as as URL for web-service calls. We do need to point it at this controller though,
Navigate your way to Your name -> Setup -> Develop -> Pages and create a new page. Call it Paypal_IPN, for clarity. This Visualforce page only has one real line to it, which you can see in paypal_ipn.page on GitHub:
https://github.com/srlawr/PaypalSFDC/blob/master/paypal_ipn.page
This is all the code you really need. When the page is loaded, the controller is constructed, and you can see the Apex page "Action" attribute to call the function "digestMessage", this is because you cannot make DML calls in a controller's constructor, or any method calls direct from it.
The final action on the Salesforce side of things is to expose this page via Salesforce sites. Click Your name -> Setup -> Develop -> Sites and click to create a new Site. I simply set the label, name and default web address all to "Paypal" and then in the Active Site Home Page selected the new page we just created.
The sites detail page should list a number of attributes of this new object, one of which is "Secure Web Address" - copy the value of this to your clipboard, because we're going to need it in a minute.
Next then, back in your Paypal sandbox, we need to tell it what URL to send the messages too, so log into your Payments Pro account and click on "Profile" -> "Instant Payment Notification preferences". On this page, you will need to enter the Secure Web Address of the Salesforce.com page, and Enable IPN messages. From the confirmation page, head over to the "IPN History Page", this page could become your best friend during development/testing.
Ready to roll!
It feels like we've done enough work now. Lets see if it's all come together.
If you return to your Payments List page, and make sure you have a handful of payment records with a status of "Unpaid", you should find yourself looking at something like this:
Just like in the last stage, if you click the "Pay out" button, the page should reload, with a success message and, having updated all the PayPal Status values to "Sent".
What has happened now is PayPal has received the request and is whipping through each of your transfers. Typically, (typically!!) this takes a few seconds in the first instance, and after each row has been considered, your first IPN message will be sent over by PayPal.
Twiddle your thumbs for just a few seconds (or if you wish to use this time constructively, check your PayPal sandbox, and make sure your transaction has been recorded on their side) and then reload the Payment List page in Salesforce.
You should see the status column has been updated, to something similar to this:
In this case, three of my transactions (those associated with my PayPal Sandbox email addresses) have completed entirely, and instantly, but one transaction is currently sitting unclaimed, because that e-mail address isn't associated with a PayPal account. You can read up more on IPN status codes over on the PayPal website.
In Paypal you can view your IPN messages, like the one below, from your IPN history page, which you'll find linked from the configuration page you put your IPN endpoint in above.
That really is it though, for a basic demonstration of Integrating the PayPal Mass Payments API with Force.com.
It should be absolutely noted that this is a purely educational blog post, and no-one should ever attempt to implement payment gateways or infrastructures without the appropriate knowledge and testing.
If you would like to talk to Desynit about applying this knowledge to your business or organisation, please get in touch via the details on our website. Otherwise, any questions or discussions are always more than welcome in the comments section below.
Tuesday 10 January 2012
Salesforce - Paypal Masspay Integration
It took me less than two hours to get processing test transactions with the PayPal Sandbox and Salesforce.com. This blog will cover how I setup the MassPay API, to allow my Salesforce application to send money to customer accounts, on demand.
Very quickly, first of all, MassPay is the Paypal API for transacting money from one Paypal account to many others, it is called MassPay because it can handle up to 250 accounts and transaction amounts in one go. If you want to integrate a "customers paying for stuff" shopping experience, maybe give this blog a read as well, http://techsahre.blogspot.com/2011/01/simple-paypal-integration-with.html
The basic process of integrating with the PayPal API involves dispatching an XML request to their web-service endpoint, interpreting the response, and then listening out yourself for incoming IPN messages from PayPal, which deliver status updates and information on your transactions as they are processed. This UML model roughly outlines the experience.
In this blog post, I will discuss the first half of the process. If you'd like to skip off and discover more about the IPN update messages, there is a second blog post by myself called Salesforce Paypal IPN Integration.
So first of all let's head over to the Paypal sandbox at https://developer.paypal.com/ and first register ourselves a PayPal developer account. Once you're in, create yourself two preconfigured accounts, make sure one is described a PayPal Payments Pro account - which will become the source of your money (so give it a chunky balance). The other can be a Buyer or Seller account, and this will be the test account that will receive the money. You can create as many of these as you like, depending on how thoroughly you like to test!
Now, we need to activate API access to the Pro account. So from the PayPal accounts list, select the Pro account and click "Enter Sandbox Test Site" and log in. Follow these steps:
We're now done on the PayPal side of things. So log in to your Salesforce.com account. As this blog is just about integration, I will talk you through a fairly simple demo, and you can then deploy the knowledge it gives you as you see fit.
For this demo, we are going to work with one simple custom object, called Paypal_obj. The MetaData for this is on the GitHub repository for this project, in the folder demo/pages
https://github.com/srlawr/PaypalSFDC/tree/master/demo/objects
But for ease of click-development, here it is in UML for you to work through.
I set the label to "Paypal Payment" and the Record name to "Payment number" - as an Auto-numbering field, format:
PP-{0000}
and starting at "1".
Once you have this custom object set up, you can go ahead and create a few records. Make sure your Paypal_status field is defaulting correctly to "Unpaid" and in the Paypal_email field, put (mostly) the e-mail addresses associated with the test buyer and seller accounts you created in PayPal above. Any e-mail addresses that arn't in that list, will be your test cases for failure, because they won't work!
With a bunch of unpaid PayPal payments in our app though, we'd best create the payment processing class to deal with them...
Click on Your Name > Setup > Develop > Apex Classes and select "New" (or, if you use an IDE, create a new class file). Now, head over the the GitHub repository for this integration and get hold of a copy of the PaypalProcessor.cls.
https://github.com/srlawr/PaypalSFDC
Copy all this this code into the file, and give it a good read. It is explained through the comments. Most importantly, copy your API user details and signature (collected above) into the relevant fields in the generateRequest function. (Note: For production, please move these out to at least a Custom Setting Object!).
Before we can interact with the PayPal servers, you need to grant your organisation access to the Paypal web services. Click Your name -> Setup -> Security Controls -> Remote Site Settings, now add the following site to the list:
At this point, we basically have a functioning back end integration with PayPal. But.. it'd probably be nice to have a little UI for executing payments, not least for testing. So before we start firing SOAP requests all over the place, lets set up a page and controller to give us something to look at.
First, lets add the custom controller class to our application. Create a new Apex class and copy the contents of the approvedPaypalController.cls into it from GitHub
https://github.com/srlawr/PaypalSFDC/tree/master/demo/classes
Once that is saved, click through Your name -> Setup -> Develop -> Pages and set up a new page called Payment_List. Copy the contents of the Payment_List.page file on GitHub into the body of the page:
https://github.com/srlawr/PaypalSFDC/tree/master/demo/pages
I personally then like to create a new custom Visualforce Tab to access this page, which is a lot easier than having to navigate to the URL over and over again.
With this page, controller, and tab, and a handful of test records, you should find yourself with a setup not a million miles away from this:
Now, I would imagine you are very excited right now about that custom action button "Pay out"... and so long as you have everything appropriately set up (in Sandbox) you should be able to click it. Go ahead!
The result should be a green success message at the top of the page, and all of your payment objects will have been updated to status "Sent".. much like below:
If you now log into your PayPal Payments pro account and have a look (click on "All account activity" or "Payments sent"), you should see a transaction appear for the total amount of your payments, and also the PayPal Fees amount the request would have cost.
If you only paid out to e-mail addresses in your list of sandbox accounts, I would expect the transaction Payment Status to be "Completed" - but if (like in the screenshots above) you had other accounts involved in the mix, it will be "Processed" - because technically, PayPal will still be waiting for those accounts to collect their money - which in Sandbox they can actually never do.
So that's it! We're kind of there. The PayPal Mass Payments API has been invoked, and we have sent potentially thousands of pounds (or dollars) out into the Internet.
Of course, when we send money out on to the internet, most people want to know what has happened to it, and that is the second half of the process, which I will cover in a subsequent post, called Salesforce Paypal IPN Integration.
(by the way, if you have clicked "Pay Out" reverting the processing is as easy as editing the records and setting their status back to "Unpaid" - a testing loop you're probably going to become very familiar with.)
Very quickly, first of all, MassPay is the Paypal API for transacting money from one Paypal account to many others, it is called MassPay because it can handle up to 250 accounts and transaction amounts in one go. If you want to integrate a "customers paying for stuff" shopping experience, maybe give this blog a read as well, http://techsahre.blogspot.com/2011/01/simple-paypal-integration-with.html
The basic process of integrating with the PayPal API involves dispatching an XML request to their web-service endpoint, interpreting the response, and then listening out yourself for incoming IPN messages from PayPal, which deliver status updates and information on your transactions as they are processed. This UML model roughly outlines the experience.
In this blog post, I will discuss the first half of the process. If you'd like to skip off and discover more about the IPN update messages, there is a second blog post by myself called Salesforce Paypal IPN Integration.
So first of all let's head over to the Paypal sandbox at https://developer.paypal.com/ and first register ourselves a PayPal developer account. Once you're in, create yourself two preconfigured accounts, make sure one is described a PayPal Payments Pro account - which will become the source of your money (so give it a chunky balance). The other can be a Buyer or Seller account, and this will be the test account that will receive the money. You can create as many of these as you like, depending on how thoroughly you like to test!
Now, we need to activate API access to the Pro account. So from the PayPal accounts list, select the Pro account and click "Enter Sandbox Test Site" and log in. Follow these steps:
- Click "Profile" (the last item on the second menu under "My Account")
- Click "Request API Credentials" underneath "Account Information"
- In Option 1 click "Setup PayPal API credentials and permissions"
- In Option 2 click "View API Signature"
- Copy out your API Username, API Password and Signature.
We're now done on the PayPal side of things. So log in to your Salesforce.com account. As this blog is just about integration, I will talk you through a fairly simple demo, and you can then deploy the knowledge it gives you as you see fit.
For this demo, we are going to work with one simple custom object, called Paypal_obj. The MetaData for this is on the GitHub repository for this project, in the folder demo/pages
https://github.com/srlawr/PaypalSFDC/tree/master/demo/objects
But for ease of click-development, here it is in UML for you to work through.
I set the label to "Paypal Payment" and the Record name to "Payment number" - as an Auto-numbering field, format:
PP-{0000}
and starting at "1".
Once you have this custom object set up, you can go ahead and create a few records. Make sure your Paypal_status field is defaulting correctly to "Unpaid" and in the Paypal_email field, put (mostly) the e-mail addresses associated with the test buyer and seller accounts you created in PayPal above. Any e-mail addresses that arn't in that list, will be your test cases for failure, because they won't work!
With a bunch of unpaid PayPal payments in our app though, we'd best create the payment processing class to deal with them...
Click on Your Name > Setup > Develop > Apex Classes and select "New" (or, if you use an IDE, create a new class file). Now, head over the the GitHub repository for this integration and get hold of a copy of the PaypalProcessor.cls.
Copy all this this code into the file, and give it a good read. It is explained through the comments. Most importantly, copy your API user details and signature (collected above) into the relevant fields in the generateRequest function. (Note: For production, please move these out to at least a Custom Setting Object!).
Before we can interact with the PayPal servers, you need to grant your organisation access to the Paypal web services. Click Your name -> Setup -> Security Controls -> Remote Site Settings, now add the following site to the list:
Paypal_SOAP: https://api-3t.sandbox.paypal.com/2.0/
At this point, we basically have a functioning back end integration with PayPal. But.. it'd probably be nice to have a little UI for executing payments, not least for testing. So before we start firing SOAP requests all over the place, lets set up a page and controller to give us something to look at.
First, lets add the custom controller class to our application. Create a new Apex class and copy the contents of the approvedPaypalController.cls into it from GitHub
https://github.com/srlawr/PaypalSFDC/tree/master/demo/classes
Once that is saved, click through Your name -> Setup -> Develop -> Pages and set up a new page called Payment_List. Copy the contents of the Payment_List.page file on GitHub into the body of the page:
https://github.com/srlawr/PaypalSFDC/tree/master/demo/pages
I personally then like to create a new custom Visualforce Tab to access this page, which is a lot easier than having to navigate to the URL over and over again.
With this page, controller, and tab, and a handful of test records, you should find yourself with a setup not a million miles away from this:
Now, I would imagine you are very excited right now about that custom action button "Pay out"... and so long as you have everything appropriately set up (in Sandbox) you should be able to click it. Go ahead!
The result should be a green success message at the top of the page, and all of your payment objects will have been updated to status "Sent".. much like below:
If you now log into your PayPal Payments pro account and have a look (click on "All account activity" or "Payments sent"), you should see a transaction appear for the total amount of your payments, and also the PayPal Fees amount the request would have cost.
If you only paid out to e-mail addresses in your list of sandbox accounts, I would expect the transaction Payment Status to be "Completed" - but if (like in the screenshots above) you had other accounts involved in the mix, it will be "Processed" - because technically, PayPal will still be waiting for those accounts to collect their money - which in Sandbox they can actually never do.
So that's it! We're kind of there. The PayPal Mass Payments API has been invoked, and we have sent potentially thousands of pounds (or dollars) out into the Internet.
Of course, when we send money out on to the internet, most people want to know what has happened to it, and that is the second half of the process, which I will cover in a subsequent post, called Salesforce Paypal IPN Integration.
(by the way, if you have clicked "Pay Out" reverting the processing is as easy as editing the records and setting their status back to "Unpaid" - a testing loop you're probably going to become very familiar with.)
Friday 6 January 2012
Writing Drupal FieldMaps with Salesforce Suite
The real power of the Drupal Salesforce Suite module is in its ability to specifically connect Drupal objects and their individual fields, to their Salesforce counterparts. Out of the box, the module comes with a pre-configured "User" and "Page" FieldMap, which give you a good feel for the abilities of this functionality, but with a little creativity, all sorts of powerful data management can be achieved.
Examining the User FieldMapping
If you access the field maps list (admin/config/salesforce/fieldmap) and click to edit the "User" row, you can see that the Last name and Postcode of the Target (Salesforce) object are mapped to the Last name and Post code of the (Drupal) User object. That is how easy it is to tie standard fields together. My Drupal user object had a lot more fields to it though, and as you can see here, they have all been simply mapped over to Salesforce equivalents in the "Members" object.
Custom fields are listed at the bottom of the Salesforce fields select box, which, incidentally, is populated by the information provided by the WSDL file you uploaded.
I did note, during the process of adding multiple fields, that sometimes the Drupal overlay didn't refresh correctly. Occasionally I would have to "Save" and re-edit the mapping to get the rows to appear correctly. The easiest way I found to keep the table fresh was to re-click the "Edit" tab after each "Add" click, whether I'd seen the new row appear or not, as this refreshed the form, guaranteeing the new field would be visible.
Once you have completed this mapping, and made sure that you have ticked at least the "Create" checkbox at the top of the mapping page, if you register a new user on your Drupal website, it should appear in both your Drupal Users view AND in your Salesforce.com contacts list. Your first synchronisation is complete! If you then navigate to your Drupal user page for the user (logged in as admin) you will see a Salesforce tab, which will detail the connection between the two objects.
As you can see here, the data for my Drupal user has been mapped to the relevant fields in Salesforce, and also there is an extra section detailing the Salesforce ID associated with the account.
Synchronising a Drupal object with Salesforce
One of the key pieces of functionality I had to deal with was recording user comments on the Drupal site in Salesforce. Luckily, "Comment" is a Drupal object already tied into the Salesforce suite, so by clicking "add" and then selecting "Comment: Poll comment" from the Drupal Object list was as simple as that.
My specification for this prototype was to register Comments as an "Event" within Salesforce. So from the Salesforce object list, I chose Event, and then began making my mappings. I was then involved in using a wide plethora of techniques to squeeze the relevant info out of Drupal and into Salesforce, as you can see from this screenshot:
For the "Location", "Type" and "Show Time as" fields, I used a Fixed value, so these are the same for all Event Objects created. In order to tell Salesforce to set the Start and End times as that instant, I used the "Evaluate PHP" option, and told it to return a new date object, formatted as "c" - which from the PHP Date API, you can see is a Unix timestamp - exactly as Salesforce is expecting.
The next fields were the trickiest. Whenever a new object is created by the Salesforce suite, because the SOAP connection is authenticated by the user login you provided during set-up, all new objects are created BY this account. Which means no matter who is logged into Drupal, the content is being created by "the system" in Salesforce. In order to connect the new content with the current Drupal user, I had to insert the following PHP snippet into the Lead ID field:
(Obviously, because of the textfield, this was all entered on one line)
This snippet retrieves the logged in user, loads up their (expanded) user account, and then returns the SFID (Salesforce ID) from it. I was able to use a similar technique to include the Users e-mail address, using "global $user; return $user->mail;" - which is otherwise unavailable to you in the drop-down boxes.
In order to group the comments against specific polls, I passed the comment subject into the Event subject field. In a custom drupal module, I used a form_alter to ensure the subject was the title of the poll, and I used the Comment settings to then hide the title field from the user.
The body of the comment, obviously, was mapped to the description of the Event, and with that, all the information I collected in Drupal, was now also being stored in Salesforce.
Tracking custom Drupal events in Salesforce
What do you do though, if you want to track a "customised" event in Salesforce..? Believe it or not, when a Drupal user votes in a Poll, for example, it doesn't actually create a Drupal object, and thus cannot be "sent" to Salesforce. In order to do this, I had to get a little more funky.
What I ended up doing, in a number of cases, was finding a relevant hook to the event, and then using it to trigger the programmatic creation of a custom object, which in turn trigged an exchange with Salesforce.
In the case of polls, there is a poll_vote hook, which, alongside a custom content type called "cck_poll_vote" allowed me to send Drupal votes to Salesforce.
In a custom module I wrote this hooking function that generates a cck_poll_vote each time a vote is cast:
It was then a simple case of creating a normal fieldMapping for a Drupal object, in the Salesforce Suite. cck_poll_vote automatically appears in the list of Drupal objects, and the mapping can be set to trigger whenever one is created, just like any other object.
Examining the User FieldMapping
If you access the field maps list (admin/config/salesforce/fieldmap) and click to edit the "User" row, you can see that the Last name and Postcode of the Target (Salesforce) object are mapped to the Last name and Post code of the (Drupal) User object. That is how easy it is to tie standard fields together. My Drupal user object had a lot more fields to it though, and as you can see here, they have all been simply mapped over to Salesforce equivalents in the "Members" object.
Custom fields are listed at the bottom of the Salesforce fields select box, which, incidentally, is populated by the information provided by the WSDL file you uploaded.
I did note, during the process of adding multiple fields, that sometimes the Drupal overlay didn't refresh correctly. Occasionally I would have to "Save" and re-edit the mapping to get the rows to appear correctly. The easiest way I found to keep the table fresh was to re-click the "Edit" tab after each "Add" click, whether I'd seen the new row appear or not, as this refreshed the form, guaranteeing the new field would be visible.
Once you have completed this mapping, and made sure that you have ticked at least the "Create" checkbox at the top of the mapping page, if you register a new user on your Drupal website, it should appear in both your Drupal Users view AND in your Salesforce.com contacts list. Your first synchronisation is complete! If you then navigate to your Drupal user page for the user (logged in as admin) you will see a Salesforce tab, which will detail the connection between the two objects.
As you can see here, the data for my Drupal user has been mapped to the relevant fields in Salesforce, and also there is an extra section detailing the Salesforce ID associated with the account.
Synchronising a Drupal object with Salesforce
One of the key pieces of functionality I had to deal with was recording user comments on the Drupal site in Salesforce. Luckily, "Comment" is a Drupal object already tied into the Salesforce suite, so by clicking "add" and then selecting "Comment: Poll comment" from the Drupal Object list was as simple as that.
My specification for this prototype was to register Comments as an "Event" within Salesforce. So from the Salesforce object list, I chose Event, and then began making my mappings. I was then involved in using a wide plethora of techniques to squeeze the relevant info out of Drupal and into Salesforce, as you can see from this screenshot:
(click to enlarge further)
For the "Location", "Type" and "Show Time as" fields, I used a Fixed value, so these are the same for all Event Objects created. In order to tell Salesforce to set the Start and End times as that instant, I used the "Evaluate PHP" option, and told it to return a new date object, formatted as "c" - which from the PHP Date API, you can see is a Unix timestamp - exactly as Salesforce is expecting.
The next fields were the trickiest. Whenever a new object is created by the Salesforce suite, because the SOAP connection is authenticated by the user login you provided during set-up, all new objects are created BY this account. Which means no matter who is logged into Drupal, the content is being created by "the system" in Salesforce. In order to connect the new content with the current Drupal user, I had to insert the following PHP snippet into the Lead ID field:
global $user; $account = user_load($user->uid); return $account->salesforce->sfid;
(Obviously, because of the textfield, this was all entered on one line)
This snippet retrieves the logged in user, loads up their (expanded) user account, and then returns the SFID (Salesforce ID) from it. I was able to use a similar technique to include the Users e-mail address, using "global $user; return $user->mail;" - which is otherwise unavailable to you in the drop-down boxes.
In order to group the comments against specific polls, I passed the comment subject into the Event subject field. In a custom drupal module, I used a form_alter to ensure the subject was the title of the poll, and I used the Comment settings to then hide the title field from the user.
function mymodule_form_alter(&$form, &$form_state, $form_id) { if($form_id == "comment_node_poll_form") { $form['subject']['#default_value'] = $form['#node']->title; } }
The body of the comment, obviously, was mapped to the description of the Event, and with that, all the information I collected in Drupal, was now also being stored in Salesforce.
Tracking custom Drupal events in Salesforce
What do you do though, if you want to track a "customised" event in Salesforce..? Believe it or not, when a Drupal user votes in a Poll, for example, it doesn't actually create a Drupal object, and thus cannot be "sent" to Salesforce. In order to do this, I had to get a little more funky.
What I ended up doing, in a number of cases, was finding a relevant hook to the event, and then using it to trigger the programmatic creation of a custom object, which in turn trigged an exchange with Salesforce.
In the case of polls, there is a poll_vote hook, which, alongside a custom content type called "cck_poll_vote" allowed me to send Drupal votes to Salesforce.
In a custom module I wrote this hooking function that generates a cck_poll_vote each time a vote is cast:
function mymodule_vote($form_id, $form_values) { $poll = $form_values['complete form']['#node']->title; $choice = $form_values['complete form']['choice']['#options'][$form_values['complete form']['choice']['#value']]; $body_text = 'A CCK Drupal object representing a poll vote.'; $node = new stdClass(); $node->type = 'cck_poll_vote'; node_object_prepare($node); $node->title = 'Poll Vote'; $node->language = LANGUAGE_NONE; $node->field_poll_id[$node->language][0]['value'] = $poll; $node->field_choice[$node->language][0]['value'] = $choice; $node = node_submit($node); node_save($node); }
It was then a simple case of creating a normal fieldMapping for a Drupal object, in the Salesforce Suite. cck_poll_vote automatically appears in the list of Drupal objects, and the mapping can be set to trigger whenever one is created, just like any other object.
Wednesday 4 January 2012
Configuring the Drupal Salesforce Suite Module
Assuming you have successfully installed the Salesforce Suite module on Drupal (as per my previous post Integrating Salesforce.com and Drupal) and you have a Salesforce account (Developer or Enterprise), then the next logical step is to connect the two together.
Luckily doing so is fairly simple, and largely done through the Drupal front end.
First, in your Drupal Admin suite, you need to navigate to the Salesforce settings page (admin/config/salesforce/). This is where you will provide an account username and password, as well as a generated API security token. Security tokens can be generated in Salesforce (and e-mailed to the registered address) through: Your name > Setup > My Personal Information > Reset My Security Token.
Next, you must (optionally) supply the module with your Salesforce WSDL definition. This contains (among other things) the object structure of your Salesforce implementation, and the connection end point URL. You can obtain your WSDL by clicking through Your Name > Setup > Develop > API and selecting the relevant link to download the Enterprise WSDL. If you don't do this, you will only have access to the standard Salesforce.com objects, and you may also experience trouble connecting to Developer or Sandbox accounts, by virtue of their different EndPoint URLs for login.
The module provides a couple of mechanisms for uploading your WSDL to Drupal, via the WSDL tab in the module configuration (admin/config/salesforce/wsdl). You can either directly upload the file, or point the module to the system folder containing the XML file. I did find, during development at this point, that if I needed to update my WSDL definition, I had to go through a fairly trial-and-error combination of clearing caches and reloading pages to get the new details properly installed.
Once the WSDL definition is set though, you are basically ready to go! All you need to do now is click through to the Object Setup tab (admin/config/salesforce/object) to choose the objects you wish to synchronise with Salesforce.com, and then define the mappings between the fields in Salesforce.com and the fields in your Drupal installation. I will cover the complexities of field mappings in a later post, but for now, you should at least have an operational connection between Salesforce.com and Drupal.
Luckily doing so is fairly simple, and largely done through the Drupal front end.
First, in your Drupal Admin suite, you need to navigate to the Salesforce settings page (admin/config/salesforce/). This is where you will provide an account username and password, as well as a generated API security token. Security tokens can be generated in Salesforce (and e-mailed to the registered address) through: Your name > Setup > My Personal Information > Reset My Security Token.
Next, you must (optionally) supply the module with your Salesforce WSDL definition. This contains (among other things) the object structure of your Salesforce implementation, and the connection end point URL. You can obtain your WSDL by clicking through Your Name > Setup > Develop > API and selecting the relevant link to download the Enterprise WSDL. If you don't do this, you will only have access to the standard Salesforce.com objects, and you may also experience trouble connecting to Developer or Sandbox accounts, by virtue of their different EndPoint URLs for login.
The module provides a couple of mechanisms for uploading your WSDL to Drupal, via the WSDL tab in the module configuration (admin/config/salesforce/wsdl). You can either directly upload the file, or point the module to the system folder containing the XML file. I did find, during development at this point, that if I needed to update my WSDL definition, I had to go through a fairly trial-and-error combination of clearing caches and reloading pages to get the new details properly installed.
Once the WSDL definition is set though, you are basically ready to go! All you need to do now is click through to the Object Setup tab (admin/config/salesforce/object) to choose the objects you wish to synchronise with Salesforce.com, and then define the mappings between the fields in Salesforce.com and the fields in your Drupal installation. I will cover the complexities of field mappings in a later post, but for now, you should at least have an operational connection between Salesforce.com and Drupal.
Integrating Salesforce.com with Drupal
I was recently charged with producing a rich, modern consumer website, for
a client already heavily invested in the Salesforce.com CRM. My employers, Desynit, already have
a strong understanding of the Salesform.com platform, and alongside my
experience with rapid development CMS systems, we set ourselves the goal of
having a fully functional prototype system up and running within a week.
The core site functionality was to deliver polls, surveys and discussion forums to registered users, with a mechanism for rewarding customers for their participation and interaction; whilst at the same time, integrating all captured data with the existing Salesforce implementation.
Step up Drupal 7 and the Salesforce Suite module.
Anyone familiar with the Drupal platform will be aware of it's incredibly quick set-up. With the dawn of Drupal 7, its new and improved core modules, (Field, Poll, Comments) and site theming tools, by the end of the first day I already had a visually impressive website, with full functionality for user navigation, registration and interaction through forums, polls and article comments.
I was hoping that implementing the Salesforce suite module would prove equally smooth and efficent, and I must say, I was not disappointed. There is one additional step you have to take above and beyond the simple "paste the URL" process for installing contrib modules on Drupal 7, and that is to install the Salesforce.com PHP API. This can be downloaded from GitHub (ignore the "Sorry, there aren't any downloads for this repository" - and click on "Download as Zip/gz") and then extract it to \sites\all\libraries\salesforce. You can then rename the top level folder to "toolkit" (so that instructions.html resides in \sites\all\libraries\salesforce\toolkit).
Once this is in place, you can navigate back to your modules page and enable whichever relevant submodules you want to use. I only needed the Core API and Entity modules to achieve my goals, and you should note that at the time of writing not all the modules were production-ready for Drupal 7.
Having enabled the modules, Drupal immediately has a new set of administration pages available to you at admin/config/salesforce, and the module even comes pre-configured with a couple of default object mappings for the fundamental Drupal concepts, User and Page. The next step you must take is to connect your Drupal site to your specific Salesforce.com instance, and I will outline how I went about this, in my next post.
Please note, this is all fantastically documented in the Salesforce Suite Documentation on drupal.org, as well as here.
The core site functionality was to deliver polls, surveys and discussion forums to registered users, with a mechanism for rewarding customers for their participation and interaction; whilst at the same time, integrating all captured data with the existing Salesforce implementation.
Step up Drupal 7 and the Salesforce Suite module.
Anyone familiar with the Drupal platform will be aware of it's incredibly quick set-up. With the dawn of Drupal 7, its new and improved core modules, (Field, Poll, Comments) and site theming tools, by the end of the first day I already had a visually impressive website, with full functionality for user navigation, registration and interaction through forums, polls and article comments.
I was hoping that implementing the Salesforce suite module would prove equally smooth and efficent, and I must say, I was not disappointed. There is one additional step you have to take above and beyond the simple "paste the URL" process for installing contrib modules on Drupal 7, and that is to install the Salesforce.com PHP API. This can be downloaded from GitHub (ignore the "Sorry, there aren't any downloads for this repository" - and click on "Download as Zip/gz") and then extract it to \sites\all\libraries\salesforce. You can then rename the top level folder to "toolkit" (so that instructions.html resides in \sites\all\libraries\salesforce\toolkit).
Once this is in place, you can navigate back to your modules page and enable whichever relevant submodules you want to use. I only needed the Core API and Entity modules to achieve my goals, and you should note that at the time of writing not all the modules were production-ready for Drupal 7.
Having enabled the modules, Drupal immediately has a new set of administration pages available to you at admin/config/salesforce, and the module even comes pre-configured with a couple of default object mappings for the fundamental Drupal concepts, User and Page. The next step you must take is to connect your Drupal site to your specific Salesforce.com instance, and I will outline how I went about this, in my next post.
Please note, this is all fantastically documented in the Salesforce Suite Documentation on drupal.org, as well as here.
Subscribe to:
Posts (Atom)