Grails PayPal IPN How I did it ….

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&notify_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

Leave a Reply