Grails Cookbook - A collection of tutorials and examples

Grails PayPal Plugin Tutorial

This tutorial will show how to integrate payment processing with your Grails application using the Grails Paypal plugin. This plugin provides integration with Paypal's Instant Payment Notfication (IPN) system. Very useful for selling products and services.

How It Works

The most important thing is to understand how it works when the plugin is used. I studied the code together with experimentation and here is a sample flow to help you:
  • Display a link for a user to buy a specific product. This is done using the <paypal:button> tag.
  • When user clicks to buy the product:
    • org.grails.paypal.PaypalController's buy action is invoked
    • A org.grails.paypal.Payment record is created in pending state
    • The user's browser is redirected to Paypal Website for payment processing
  • When the user paid the item:
    • org.grails.paypal.PaypalController's success or notifyPaypal action is invoked. This is called automatically even without the user being redirected back to your website.
    • The relevant org.grails.paypal.Payment record is updated to completed state
  • You need to create 2 filters to intercept calls to org.grails.paypal.PaypalController and insert your own business logic.
    • Filter to intercept buy. This is where to create your own transaction record in pending state
    • Filter to intercept successful payment. This is where to update your transaction record to completed state

Install Paypal Plugin

The first step is to install the plugin by editing grails-app/conf/BuildConfig.groovy. Add entry similar to below in the plugins section:

grails.project.dependency.resolution = {
    ...
    plugins {
        ...
        compile ":paypal:0.6.8"
    }
}

Configure Paypal Plugin

In case you are not familiar with paypal, an account is associated with an email address. I.e. the information needed for someone to send a payment is just the email address of the merchant account.
Aside from live payment gateway for production use, Paypal also have a sandbox environment for testing purposes. When you are in sandbox, you can test the whole flow of your application without transferring real money. You can sign up for sandbox account to get test merchant and test buyer accounts.

From the sample configuration below, we can use the sandbox account for development purposes and use live account for production. To configure, just edit grails-app/conf/Config.groovy.

environments {
    production {
        grails.paypal.server = "https://www.paypal.com/cgi-bin/webscr"
        grails.paypal.email = "merchant@grails.asia"
        grails.serverURL = "http://store.grails.asia"
    }
    development {
        grails.paypal.server = "https://www.sandbox.paypal.com/cgi-bin/webscr"
        grails.paypal.email = "merchant_test_grails@paypal.com"
        grails.serverURL = "http://localhost:8080/sample"
    }
}

Note that the serverURL parameter is the URL to your application. It should be http://localhost:8080/<context> when using grails run-app and the real domain name when deployed to production.

Create Domain Class

Here is an example domain class that represents a product:

class ProductItem {
    String name
    BigDecimal price
    static constraints = {
        name(blank:false, nullable:false, unique: true)
        price(blank:false, nullable:false)
    }
}

Here is a sample domain class that represents a transaction. The completed field is for the status of the transaction. Pending state uses false value while completed uses true value.

import org.grails.paypal.Payment
class ProductPurchase {
    SystemUser user
    ProductItem item
    Payment payment
    boolean completed = false
}

Note that we need a user to identify which person is buying a product. I recommend the Grails Spring Security Core Plugin.

Display Buy Button

Assuming you have a list of items for sale and the currently logged user, here is an example GSP to display the list with Buy button for each:

<g:each in="${productItemList}" var="productItem">
    <h3>${productItem.name}</h3>
    <div>Price: ${productItem.price}</div>
    <paypal:button
        itemName="${item.name}"
        itemNumber="${item.name}"
        discountAmount="${0}"
        amount="${item.price}"
        buyerId="${user.id}"/>
</g:each>

Note that I used the same value (item.name) for both itemName and itemNumber because we declared name to be unique above. The two values could be different depending on how you designed it.

Purchase Filter

Create a Buy/Purchase Filter. For example, create the filter grails-app/conf/myfilters/PurchaseFilters.groovy with this code:
class PurchaseFilters {
    def filters = {
        all(controller:'paypal', action:'buy') {
            before = {
            }
            after = { Map model ->
                def user = SystemUser.get(request.payment.buyerId)
                def item = ProductItem.findByName(request.payment.paymentItems[0].itemName)
                new ProductPurchase( user:user, payment:request.payment, item:item).save()
            }
            afterView = { Exception e ->
            }
        }
    }
}
This will create a record of what item the user clicked to buy. Before this filter is called, the payment record is already created by the plugin based on the values used in the tag above. The payment instance can then be used to compose the ProductPurchase object.

Purchase Completed Filter

Create a Purchase Completed Filter. For example, create the filter grails-app/conf/myfilters/PurchaseCompletedFilters.groovy with this code:
class PurchaseCompletedFilters {
    def filters = {
        all(controller: 'paypal', action: '(success|notifyPaypal)') {
            before = {
            }
            after = { Map model ->
                def payment = request.payment
                if(payment && payment.status == org.grails.paypal.Payment.COMPLETE) {
                    def purchase = ProductPurchase.findByPayment(payment)
                    if ( !purchase.completed ) {
                        purchase.completed = true
                    }
                }
            }
            afterView = { Exception e ->
            }
        }
    }
}
When the user paid the item, this filter will be invoked. The payment record is retrieved and can be used in your custom business logic. For example, we can update the completed flag in our own transaction domain model.
And that's it! You then just need to check ProductPurchase records to determine which items are pending or paid to perform additional business logic.

Warning


Af of the time of this writing (Sept 24, 2014) the latest plugin version (0.6.8) was last updated on July 17, 2012. It is a bit out dated. It will have problems with Grails version 2.3 and above.

To use this particular Paypal plugin version with Grails 2.3 and above, create a converter class. E.g. grails-app/src/groovy/asia/grails/sample/CurrencyValueConverter.groovy

package asia.grails.sample
import org.grails.databinding.converters.ValueConverter
class CurrencyValueConverter implements ValueConverter  {
    boolean canConvert(value) {
        value instanceof String
    }
    def convert(value) {
        Currency.getInstance(value)
    }
    Class<?> getTargetType() {
        java.util.Currency
    }
}

And update grails-app/conf/spring/resources.groovy

beans = {
    currencyConverter asia.grails.sample.CurrencyValueConverter
}

Your app should now work.

Other Grails Plugins Tutorials


Tags: paypal, Plugin