Thanks for the replies guys. I started off with pbreit's snippet:
http://groups.google.com/group/web2py/browse_thread/thread/6cc84d9fb609e74/cdb0d848ed691e40?q=paypal+pbreit#cdb0d848ed691e40
First I ran into a problem in which paypal is saying I'm not
authorized to make the api call. Some googling and found a suggestion
to remove the 'subject' from the call, and it worked, at least on the
part where the api credentials are being verified.
Now when I test on sandbox it redirects fine. However, it displays the
'regular' login screen. When I try to login using a test personal
account, it goes to the user's My Account panel.
I know it should be showing a confirmation page for the purchase,
amirite? And afterwards it has to go back to my return url for
further processing on my end.
Is that behavior limited to IPN? I know this approach does not make
use of the IPN.
Here's the modified/simplified version of pbreit's code that I use:
############################################
# models
############################################
paypal_config = {
'user': 'my_api_username',
'pwd': 'my_api_pwd',
'signature': 'my_api_sig',
'version': '66.0',
'button_source': 'https://www.paypal.com/en_US/i/btn/
btn_buynowCC_LG.gif' ,
'return_url' : 'http://localhost:8000/controller/default/
paypal_return',
'cancel_url' : 'http://localhost:8000/controller/default/
paypal_cancel',
'notify_url' : 'http://localhost:8000/controller/default/
paypal_ipn',
}
db.define_table('purchase',
Field('owner', 'reference auth_user', readable=False,
writable=False, default=auth.user_id),
Field('amount'),
Field('item'),
Field('invoice', unique=True),
Field('status', readable=False, writable=False,
default='pending'),
Field('transaction_id'),
Field('date', 'datetime', default=request.now))
############################################
#module
############################################
import urllib
import cgi
def setec(config, purchase):
values = {'USER': config['user'],
'PWD': config['pwd'],
'SIGNATURE': config['signature'],
'VERSION': config['version'],
'METHOD': 'SetExpressCheckout',
'PAYMENTREQUEST_0_AMT': purchase.amount,
'PAYMENTREQUEST_0_CURRENCYCODE': 'USD',
'RETURNURL': config['return_url'],
'CANCELURL': config['cancel_url'],
'PAYMENTREQUEST_0_PAYMENTACTION': 'Sale',
'PAYMENTREQUEST_0_INVNUM': purchase.invoice,
'PAYMENTREQUEST_0_NOTIFYURL': config['notify_url']}
return cgi.parse_qs(urllib.urlopen('https://api-3t.paypal.com/
nvp', urllib.urlencode(values)).read())
def getec(config, token, recipient_id):
values = {'USER': config['user'],
'PWD': config['pwd'],
'SIGNATURE': config['signature'],
'VERSION': config['version'],
'METHOD': 'GetExpressCheckoutDetails',
'TOKEN': token}
return cgi.parse_qs(urllib.urlopen('https://api-3t.paypal.com/
nvp', urllib.urlencode(values)).read())
def doec(config, token, purchase, payerid):
values = {'USER': config['user'],
'PWD': config['pwd'],
'SIGNATURE': config['signature'],
'VERSION': config['version'],
'METHOD': 'DoExpressCheckoutPayment',
'BUTTONSOURCE': config['button_source'],
'TOKEN': token,
'PAYMENTREQUEST_0_PAYMENTACTION': 'Sale',
'PAYMENTREQUEST_0_DESC': 'Order #%s' % (purchase.id),
'PAYMENTREQUEST_0_AMT': purchase.amount,
'PAYMENTREQUEST_0_CURRENCYCODE': 'USD',
'PAYERID': payerid}
return cgi.parse_qs(urllib.urlopen('https://api-3t.paypal.com/
nvp', urllib.urlencode(values)).read())
############################################
# controller
############################################
import random, string
def paypal():
session.recipient_id = ''
item = request.args(0)
invoice = ''.join(random.choice(string.ascii_uppercase +
string.digits) for x in range(9)) + item.upper()
purchase = db.purchase.insert(
owner=auth.user.id,
status = 'pending',
item = item,
amount = TEMPLATE_PRICE,
invoice = invoice)
paypal = local_import('paypal', reload=True)
row = db(db.purchase.id==purchase).select().first()
res = paypal.setec(paypal_config, row)
if res['ACK'][0]=='Success':
session.recipient_id = auth.user.email
token = res['TOKEN'][0]
print 'token:', token
url = 'https://www.sandbox.paypal.com/cgi-bin/webscr%3Fcmd
%3D_express-checkout%26useraction%3Dcommit%26token%3D%27'
redirect('%s%s' % (url, token))
return locals()
else:
session.flash = 'Error: Purchase failure'
return locals()
def paypal_return():
token = request.vars.token
recipient_id = session.recipient_id
paypal = local_import('paypal', reload=True)
payment = paypal.getec(paypal_config, token, recipient_id)
if payment['ACK'][0]=='Success':
invoice = payment['PAYMENTREQUEST_0_INVNUM'][0]
purchase = db(db.purchase.invoice==invoice).select().first()
if purchase.amount != payment['PAYMENTREQUEST_0_AMT'][0]:
session.flash = 'Error: Template price was not paid in
full'
return locals()
purchase.update_record(
amount=payment['PAYMENTREQUEST_0_AMT']
[0])
payerid = request.vars.PayerID
res = paypal.doec(paypal_config, token, purchase, payerid)
if res['ACK'][0]=='Success':
purchase.update_record(status='completed',
date=request.now,
payment_id=res['PAYMENTINFO_0_TRANSACTIONID'][0])
session.flash = 'Template purchase success'
return locals()
else:
session.flash = 'Error: Payment not verified by Paypal'
return locals()
else:
session.flash = 'Error: Unsuccessful purchase'
return locals()
return locals()
def paypal_cancel():
return locals()
def paypal_ipn():
return locals()
******************************
Any feedback is greatly appreciated.
Thanks,
Arbie
On May 29, 8:12 am, pbreit <[email protected]> wrote:
> Express Checkout doesn't need the crypto stuff.
>
> And the crypto stuff is actually optional on PayPal "_cart" and "_xclick".
> Just make sure to review your payments visually or with IPN to make sure
> there was no tampering.