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 <pbreitenb...@gmail.com> 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.

Reply via email to