Ticket sales (PayPal, Jasper Reports, Barcodes) with Grails
Please see Part 1 for the start of this series and links to all parts.
For the SupaJam ticket outlet, we didn't need anything too fancy, just enough to present people with a couple of ticket types to choose from and a way to pay for them. Of course we still had the extra requirement of collecting a real name for each and every ticket as well though.
We kept the structure online pretty simple, sticking to a single web page, either re-displaying with errors or sending the user straight to PayPal (our chosen payment processor purely for reasons of technical experience).
So far this was all fairly basic coding, a command object, controller, a couple of views and a few new domain objects to keep it all. This is where Grails really shines, making all of this simple and quick.
There is already a PayPal plugin for grails, but in this case I didn't feel it fitted, so the PayPal integration was custom coded. This included building and passing a cart, based on user selections as well as an IPN endpoint to make sure all the purchases were dealt with automatically.
Once a user has visited one of our ticket pages and decided to take up an offer, been to PayPal and paid, it's generally useful to then provide a ticket. This was the part that presented the first interesting challenge.
We hadn't finalised how we were going to run our festival entrance yet but it seemed like a fast method to check unique ticket codes might be handy. The quick and simple answer to this seemed like a barcode. So each person would need a physical ticket to bring along that we could scan and quickly check validity. We didn't want to add postage costs to what we charged, so email was the simplest solution. As for the most controllable and widely readable document format to send people - PDF of course!
So we needed to make PDFs that would contain some useful instructions to the owner, a few critical ticket details plus the essential unique code and its barcode representation. To make them look nicer and also to better fill an A4 page we also decided to add an image about the festival.
I had read about Jasper Reports before and knew there was a Grails plugin for it, so I decided it would be a good place to start. I soon had iReport downloaded, running and a simple ticket report designed.
While the basics of the ticket looked simple enough, there were two elements that proved slightly tougher. The most critical was the barcode. When adding a barcode in iReport you first get a choice of barcode library. So I researched each and picked the one I preferred.
This worked fine in iReport, but it soon became apparent that the Grails Jasper Reports plugin deliberately excludes most of the optional components and dependencies of Jasper. This included both of the barcode libraries. So off I went trying to add Barcode4J to my grails project.
After an hour or so of fighting to include one layer of dependencies while desperately excluding the next layer (mostly to avoid XML parser conflicts), I admitted defeat and had a crack at the Barbecue barcode library instead. Thankfully this turned out to be trivial in comparison and just needed:
compile('net.sourceforge.barbecue:barbecue:1.5-beta1') {
excludes 'portlet-api', 'servlet-api', 'junit'
}
The only downside was that I couldn't get the code to be automatically included under the barcode (even in iReport). Just including the code in a text field was a simple work around though.
Next up was the included images - for branding, page filling and information. I wanted to change these for different events and fetching each image from an event configured URL seemed like a good way to go. At least I thought that until I tried it!
For quite some time Jasper Reports stubbornly refused to load the images into the report. Test images from another site would work, but not those from my development grails server.
After much debugging and eventually resorting to tcpdump(!), I tracked this down to the zipped-resources plugin which currently does two bad things (as documented). It doesn't check to see if a client actually supports gzip and it gzip's images! So this meant that Jasper was being given gzipped images which it couldn't deal with.
Once I realised this, simply removing the zipped-resources plugin solved the problem. Although in the end I actually re-instated the zipped-resources plugin and decided to host the images on one of our external (ie not Grails) web servers.
My final little niggle with Jasper was font based. I could not seem to find a font that both Jasper could measure (for alignment purposes) and clients could find when rendering the PDF. I ended up solving this by using the Jasper-fonts package and choosing to embed the fonts within the PDF. This needed another line in my grails-app/conf/BuildConfig.groovy file:
compile('net.sf.jasperreports:jasperreports-fonts:4.0.0')
And that was it.
In less than a (short, due to bank holidays) week I built an e-commerce ticket agent system that created pretty, barcoded e-tickets. This promptly went live on SupaJam and sold several hundred (up to thousands by now) festival tickets.