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