http://www.youtube.com/watch?v=xW5xOdDk-BE
Here are the steps: # let us go into our web2py folder cd /Users/mdipierro/Desktop/demo/web2py # and we create a new app called pos (point of sale) cd applications mkdir pos rm -r pos/* # we make it a clone of the scaffolding application cp -r welcome/* pos/ cd pos open http://127.0.0.1:8000/admin/default/design/welcome # lets get janrain working! edit models/db.py # -*- coding: utf-8 -*- # this file is released under public domain and you can use without limitations ######################################################################### ## This scaffolding model makes your app work on Google App Engine too ######################################################################### if request.env.web2py_runtime_gae: # if running on Google App Engine db = DAL('gae') # connect to Google BigTable # optional DAL('gae:// namespace') session.connect(request, response, db = db) # and store sessions and tickets there ### or use the following lines to store sessions in Memcache # from gluon.contrib.memdb import MEMDB # from google.appengine.api.memcache import Client # session.connect(request, response, db = MEMDB(Client())) else: # else use a normal relational database db = DAL('sqlite://storage.sqlite') # if not, use SQLite or other DB ## if no need for session # session.forget() ######################################################################### ## Here is sample code if you need for ## - email capabilities ## - authentication (registration, login, logout, ... ) ## - authorization (role based authorization) ## - services (xml, csv, json, xmlrpc, jsonrpc, amf, rss) ## - crud actions ## (more options discussed in gluon/tools.py) ######################################################################### from gluon.tools import * mail = Mail() # mailer auth = Auth(globals(),db) # authentication/ authorization crud = Crud(globals(),db) # for CRUD helpers using auth service = Service(globals()) # for json, xml, jsonrpc, xmlrpc, amfrpc plugins = PluginManager() mail.settings.server = 'logging' or 'smtp.gmail.com:587' # your SMTP server mail.settings.sender = 'y...@gmail.com' # your email mail.settings.login = 'username:password' # your credentials or None auth.settings.hmac_key = '<your secret key>' # before define_tables() auth.define_tables() # creates all needed tables auth.settings.mailer = mail # for user email verification auth.settings.registration_requires_verification = False auth.settings.registration_requires_approval = False auth.messages.verify_email = 'Click on the link http://'+request.env.http_host+URL('default','user',args=['verify_email'])+'/%(key)s to verify your email' auth.settings.reset_password_requires_verification = True auth.messages.reset_password = 'Click on the link http://'+request.env.http_host+URL('default','user',args=['reset_password'])+'/%(key)s to reset your password' ######################################################################### ## If you need to use OpenID, Facebook, MySpace, Twitter, Linkedin, etc. ## register with janrain.com, uncomment and customize following from gluon.contrib.login_methods.rpx_account import RPXAccount auth.settings.actions_disabled=['register','change_password','request_reset_password'] api_key = open('/Users/mdipierro/ janrain_api_key.txt','r').read().strip() auth.settings.login_form = RPXAccount(request, api_key=api_key,domain='web2py', url = "http://localhost:8000/%s/default/user/login" % request.application) ## other login methods are in gluon/contrib/login_methods ######################################################################### crud.settings.auth = None # =auth to enforce authorization on crud @@END@@ open http://127.0.0.1:8000/admin/default/peek/welcome/models/db.py # then we create a custom model edit models/db_pos.py # we need a table to store products db.define_table('product', Field('name',notnull=True,unique=True), Field('price','double'), Field('description','text'), Field('image','upload'), Field('sortable','integer'), auth.signature, format='%(name)s') # and one table to store sales of products to users db.define_table('sale', Field('invoice'), Field('creditcard'), Field('buyer',db.auth_user), Field('product',db.product), Field('quantity','integer'), Field('price','double'), Field('shipped','boolean',default=False), auth.signature), # we also make a session cart, just in case session.cart = session.cart or {} @@END@@ # we can now already access the model via app-admin # try create some products open http://127.0.0.1:8000/pos/appadmin # we can also create prducts programmatically here is one way mkdir private cd private # let's get an image wget http://www.clker.com/cliparts/5/1/9/a/11954319101307220149molumen_cardboard_box.svg.med.png sh:convert 11954319101307220149molumen_cardboard_box.svg.med.png box.jpg open box.jpg cd .. edit private/script.py import os # find the box path = os.path.join(request.folder,'private','box.jpg') # insert it in a database record id = db.product.insert(name='Box',price=2.99,description='the best box', image=db.product.image.store(open(path,'rb'),path)) print 'record created, id=',id # and do not forget to commit db.commit() @@END@@ # now let's run it cd ../.. python web2py.py -S pos -M -N -R applications/pos/private/script.py cd applications/pos # let us write a controller with the actions we need rm controllers/default.py edit controllers/default.py # list of products def index(): products = db(db.product).select(orderby=db.product.sortable) return locals() # login, registration, etcetera def user(): return dict(form=auth()) # an action to download uploaded images def download(): return response.download(request,db) # an action to expose web services def call(): session.forget() return service() @@END@@ # let us try listing the products we created open http://127.0.0.1:8000/pos/default/index # let us make this better by creating a view rm views/default/index.html edit views/default/index.html {{extend 'layout.html'}} <h1>Products</h1> {{for p in products:}} <div> <h2>{{=p.name}} - ${{=p.price}}</h2> <img src="{{=URL('download',args=p.image)}}" align="right"/> {{=MARKMIN(p.description)}} </div> {{pass}} @@END@@ open http://127.0.0.1:8000/pos/default/index # and we make a simple menu edit models/menu.py response.menu=[ (T('Home'),False,URL('default','index')), (T('Cart'),False,URL('default','cart')), (T('Buy'),False,URL('default','buy')), ] @@END@@ open http://127.0.0.1:8000/pos/default/index # now we create some more logic for our app edit controllers/default.py # list of products def index(): products = db(db.product).select(orderby=db.product.sortable) return locals() # login, registration, etcetera def user(): return dict(form=auth()) # an action to download uploaded images def download(): return response.download(request,db) # an action to expose web services def call(): session.forget() return service() # an action to see and process a shopping cart @auth.requires_login() def cart(): return dict(cart=session.cart) # this is for paying @auth.requires_login() def pay(): form = SQLFORM.factory(Field('creditcard')) if form.accepts(request,session): for key, value in session.cart.items(): db.sale.insert(buyer=auth.user.id, product = key, quantity = value, price = db.product(key).price, creditcard = form.vars.creditcard) session.cart.clear() session.flash = 'Thank you for your order' redirect(URL('index')) return dict(cart=session.cart,form=form) # an action to add and remove items from the shopping cart def cart_callback(): id = int(request.vars.id) if request.vars.action == 'add': session.cart[id]=session.cart.get(id,0)+1 if request.vars.action == 'sub': session.cart[id]=max(0,session.cart.get(id,0)-1) return str(session.cart[id]) @@END@@ # we add a button from the index page edit views/default/index.html {{extend 'layout.html'}} <h1>Products</h1> {{for p in products:}} <div> <h2>{{=p.name}} - ${{=p.price}}</h2> <img src="{{=URL('download',args=p.image)}}" align="right"/> {{=MARKMIN(p.description)}} <span id="item{{=p.id}}">{{=session.cart.get(p.id,0)}}</span> in cart - <button onclick="ajax('{{=URL('cart_callback',vars=dict(id=p.id,action='add'))}}', [],'item{{=p.id}}')">add to cart</button> </div> {{pass}} @@END@@ # and a view for the cart so visitors can see their products edit views/default/cart.html {{extend 'layout.html'}} <h1>Your Shopping Cart</h1> <table width="100%"> {{for id, qty in cart.items():}}{{p=db.product(id)}} <tr> <td>{{=p.name}}</td> <td>${{=p.price}}</td> <td id="item{{=id}}">{{=qty}}</td> <td><button onclick="ajax('{{=URL('cart_callback',vars=dict(id=p.id,action='add'))}}', [],'item{{=id}}')">add</button></td> <td><button onclick="ajax('{{=URL('cart_callback',vars=dict(id=p.id,action='sub'))}}', [],'item{{=id}}')">sub</button></td> </tr> {{pass}} </table> <a href="{{=URL('pay')}}">checkout</a> @@END@@ # and a view for the buy action edit views/default/pay.html {{extend 'layout.html'}} <h1>Checkout</h1> {{=form}} @@END@@ # now try to add something to your cart and buy the products open http://127.0.0.1:8000/pos # Let's change the layout wget http://web2py.com/layouts/static/plugin_layouts/plugins/web2py.plugin.layout_Commission.w2p tar zxvf web2py.plugin.layout_Commission.w2p # time to accept real payments edit models/aim.py from gluon.contrib.AuthorizeNet import AIM def process(creditcard,expiration,total,cvv,tax,invoice): payment = AIM('cnpdev4289', 'SR2P8g4jdEn7vFLQ', True) payment.setTransaction(creditcard, expiration.replace('/',''), total, cvv, tax, invoice) payment.process() return payment.isApproved() @@END@@ # check out the new layout open http://127.0.0.1:8000/pos edit controllers/default.py # list of products def index(): products = db(db.product).select(orderby=db.product.sortable) return locals() # login, registration, etcetera def user(): return dict(form=auth()) # an action to download uploaded images def download(): return response.download(request,db) # an action to expose web services def call(): session.forget() return service() # an action to see and process a shopping cart @auth.requires_login() def cart(): return dict(cart=session.cart) # time to pay ... now for real @auth.requires_login() def pay(): import uuid invoice = str(uuid.uuid4()) total = sum(db.product(id).price*qty for id,qty in session.cart.items()) form = SQLFORM.factory(Field('creditcard',default='4427802641004797'), Field('expiration',default='12/2012'), Field('cvv',default='123'), Field('total','double',default=total,writable=False)) if form.accepts(request,session): if process(form.vars.creditcard,form.vars.expiration, total,form.vars.cvv,0.0,'invoice'): for key, value in session.cart.items(): db.sale.insert(invoice=invoice, buyer=auth.user.id, product = key, quantity = value, price = db.product(key).price, creditcard = form.vars.creditcard) session.cart.clear() session.flash = 'Thank you for your order' redirect(URL('index')) else: response.flash = "payment rejected (please call XXX)" return dict(cart=session.cart,form=form) # an action to add and remove items from the shopping cart def cart_callback(): id = int(request.vars.id) if request.vars.action == 'add': session.cart[id]=session.cart.get(id,0)+1 if request.vars.action == 'sub': session.cart[id]=max(0,session.cart.get(id,0)-1) return str(session.cart[id]) @@END@@ # done. now we have a functional web store