My only real requirement is a convenient way to handle PayPal IPN (Instant Payment Notifications). IPN in a nutshell is PayPal POSTing all the details of a transaction to a pre-agreed URL on your server. To ensure its validity, you then post that back to a PayPal URL which either verifies or rejects it.
My code currently supports only buy now links, which are suitable for my purposes as I just want to charge a single calculated amount at a time.
Before I start committing this package to the CVS tree, I wanted to get a bit of feedback on my implementation approach. You can browse the (undocumented) code on my CVS server:
openacs/packages/
paypal-support is the PayPal package, pump-invoicing is a simple package using paypal-support.
The overall idea is this:
pump-invoicing uses an api-call from paypal-support to generate the PayPal "buy now" link (actually a form snippet):
db_multirow -extend { buy_now } invoice_list invoice_list {
select invoice_id, description, total, notes
from invoices
where organization_id = :organization
and deleted = 'f';
} {
set buy_now [paypal::buy_now \
-item_name $description \
-amount $total \
-no_shipping \
-invoice_id $invoice_id \
-return_url $return_url \
-callback_impl [invoicing::package_key]]
}
When the customer completes the paypal transaction, PayPal will post the IPN to /paypal-support/ipn-callback - see
openacs/packages/paypal-support/www/ipn-callback.tcl
(Prepare yourself for a confusion of the word callback - sorry about that, but PayPal does a callback on us, and we do a Tcl callback internally...)
After verifying the IPN, the paypal-support package (optionally) uses the callback mechanism to pass the IPN info back to the client package. In our example, pump-invoicing, here is the callback implementation:
ad_proc -callback paypal::ipn::callback -impl pump-invoicing {
-ipn_ns_set:required
} {
Implementation of the ipn callback provided by paypal-support
} {
ns_log Notice "pump-invoicing: received an ipn callback for invoice [ns_set get $ipn_ns_set invoice]"
return 1
}
I think that's nice and simple. There are a few nuances - some dealt with, some still to be - with how we need to interact with PayPal, but that's about it.
I'd appreciate it if anyone interested in PayPal could take a look at the code and give me some feedback.
The reason I am using an ns_set to pass in the IPN info is so if PayPal add extra info fields, the callback interface won't have to change.
I am planning to add some helper procs to paypal-support to interrogate the ns_set for standard pieces of information to provide abstraction for the common pieces of information - oh for method calls on ns_sets :)