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" } }
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.
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.
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.
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.
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.
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.