After a bit of searching for a quick and dirty on Paypal and Grails my search came up blank. After making sure I wasn’t going to reinvent the wheel. I prodded off to fine the default jsp and servlet version which I did and it was very straight forward. Some of the code below is still used from that version.
Domain Object for paypal ipn:
class Ipn {
String last_name
String address_name
String txn_type
String receiver_email
String address_city
String residence_country
String payment_gross
String payment_date
String address_zip
String payment_status
String address_street
String first_name
String payer_email
String payer_id
String verify_sign
String payment_type
String business
String address_country_code
String mc_fee
String address_status
String quantity
String notify_version
String mc_currency
String custom
String address_state
String payment_fee
String payer_status
String shipping
String item_name
String tax
String charset
String item_number
String invoice
String mc_gross
String txn_id
String receiver_id
String address_country
}
SenderController ....
def paypal = {
String amount = params.paymentOptions
String itemType
if("400.00".equals(amount)){
itemType = "Whatever Order"
}
def now = new Date()
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddmm")
String invoice = "P"+params.userid+params.year+params.make+sdf.format(now)
String postString = "?"+"cmd=_xclick"+"&"
postString += "business=yourbuis@foo.com“+”&”
postString += “item_name=”+itemType+”&”
postString += “amount=”+params.paymentOptions+”&”
postString += “custom=”+params.custom+”&”
postString += “invoice=”+invoice+”&”
postString += “notify_url=http://foo.com/ipn” + “&”
postString += "return=http://foo.com/user/payloop/“+params.userid
redirect(url:”https://www.paypal.com/cgi-bin/webscr“+postString)
}
class IpnController {
def allowedMethods = [delete:'POST', save:'POST', update:'POST']
EmailerService emailerService
def index = {
def ipn = new Ipn(params)
ipn.parmscustom=params.custom
ipn.save()
Enumeration en = request.getParameterNames();
String str = "cmd=_notify-validate";
while(en.hasMoreElements()){
String paramName = (String)en.nextElement();
String paramValue = request.getParameter(paramName);
str = str + "&" + paramName + "=" + URLEncoder.encode(paramValue);
}
URL u = new URL("https://www.paypal.com/cgi-bin/webscr“);
URLConnection uc = u.openConnection();
uc.setDoOutput(true);
uc.setRequestProperty(”Content-Type”,”application/x-www-form-urlencoded”);
PrintWriter pw = new PrintWriter(uc.getOutputStream());
pw.close();
BufferedReader br = new BufferedReader(new InputStreamReader(uc.getInputStream()));
String res = br.readLine();
br.close();
def foo = MyDomainFoo.get( params.custom )
// check notification validation
if(res.equals(”VERIFIED”)) {
foo.verifiedPayment=”VALIDATED”
foo.save()
//send email
def email = [
to: [ ‘peeps@whocare.com‘ ],
subject: ‘Yadada duh’ + ipn.invoice ,
text: Information’
+ ‘nOrder Payment Status: VERIFIED’
]
// sendEmails expects a List
emailerService.sendEmails([email])
//update estimate to Validated
}
else if(res.equals(”INVALID”)) {
foo.verifiedPayment=”INVALID”
foo.save()
//send email bad here
}
else {
println(”LOG:: Something bad happened with” + ipn.custom)
}
redirect(uri:”/terminated.html”)
}
There it is in a nut-shell. It's not the cleanest but it works and works well.
What I would recommend if you are doing some paypal stuff with grails would be to do the following.
In your Config.groovy class use the following:
paypalurl = "http://localhost:8080/local-pay/foo"
analytics = "off"
environments {
test {
paypalurl = "https://www.sandbox.paypal.com/cgi-bin/webscr"
}
production {
analytics = "on"
paypalurl = "https://www.paypal.com/cgi-bin/webscr”
}
}
and use the grailsApplication.config.paypalurl convention so you can seperate the test from the production.
For Dev I used a mix of stuff with a selenium test for checking the call from paypal. below is one I use in my test calls.
?shipping=0.00&txn_id=573053526782394N&mc_fee=0.39&charset=windows-1252&address_country=United States&item_name=Stuff they bought&payment_status=Completed&address_state=FL&address_street=payer address&verify_sign=A2Aln3iC.testuffthatsunreadablegx2Elkzx&address_status=confirmed&payment_fee=0.39&payment_gross=233.99&quantity=1&first_name=payername&address_city=payercity&address_country_code=US&item_number=&mc_currency=USD&residence_country=US&payer_email=payer@foopayer.com&address_name=Brian Doyle&controller=ipn&txn_type=web_accept&payer_status=unverified&last_name=Doyle&payment_type=instant&invoice=W2008041358&payer_id=V636&receiver_id=6VX7YJ&payment_date=20:59:18 Apr 13, 2008 PDT&mc_gross=2.99&tax=0.00¬ify_version=2.4&address_zip=12345&receiver_email=paypal@foomydomaintest.com&custom=27&business=paypal@foomydomaintest.com
Also fix the business from test to production.
Need to make this a plugin....
Questions, Comments, and Improvements Accepted below...
update nice guide on how olaf descripes IPN IPN Diagram From the Dzone Dzone Link