work in progress: orders and order items
git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@3111 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
e7fb4cd238
commit
1f72392904
7 changed files with 173 additions and 16 deletions
|
@ -78,15 +78,31 @@ Customers
|
|||
Carts and Orders
|
||||
================
|
||||
|
||||
>>> from cybertools.commerce.order import OrderItems
|
||||
>>> component.provideAdapter(OrderItems)
|
||||
A cart is just a collection of order items belonging to a certain customer
|
||||
(or some other kind of party).
|
||||
|
||||
>>> orderItems = manager.orderItems
|
||||
|
||||
>>> orderItems.add(p001, c001, quantity=3)
|
||||
<Track [..., 1, ..., '... ...']: {'quantity': 3}>
|
||||
>>> orderItems.add(p001, c001, shop=shop1, quantity=3)
|
||||
<OrderItem [2, 1, 7, '... ...', '???']: {'shop': 0, 'quantity': 3}>
|
||||
|
||||
>>> orderItems.getCart(c001)
|
||||
[<OrderItem [2, 1, 7, '... ...', '???']: {'shop': 0, 'quantity': 3}>]
|
||||
|
||||
Orders
|
||||
------
|
||||
|
||||
The items in a shopping cart may be included in an order.
|
||||
|
||||
>>> ord001 = manager.orders.create(u'001', shop=shop1, customer=c001)
|
||||
|
||||
>>> for item in orderItems.getCart(c001):
|
||||
... item.setOrder(ord001)
|
||||
|
||||
Now the default cart is empty; we now have to supply the order for
|
||||
retrieving the order items.
|
||||
|
||||
>>> orderItems.getCart(c001)
|
||||
[]
|
||||
>>> orderItems.getCart(c001, ord001)
|
||||
[<OrderItem [2, 1, 7, '... ...', 11]: {'shop': 0, 'quantity': 3}>]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2008 Helmut Merz helmutm@cy55.de
|
||||
# Copyright (c) 2009 Helmut Merz helmutm@cy55.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
@ -22,6 +22,9 @@ Common functionality.
|
|||
$Id$
|
||||
"""
|
||||
|
||||
from zope.app.intid.interfaces import IIntIds
|
||||
from zope import component
|
||||
|
||||
|
||||
class ContainerAttribute(object):
|
||||
|
||||
|
@ -37,9 +40,11 @@ class ContainerAttribute(object):
|
|||
for k, v in kw.items():
|
||||
setattr(obj, k, v)
|
||||
self.data[id] = obj
|
||||
component.getUtility(IIntIds).register(obj)
|
||||
return obj
|
||||
|
||||
def remove(self, id):
|
||||
component.getUtility(IIntIds).unregister(self.data[id])
|
||||
del self.data[id]
|
||||
|
||||
def get(self, id, default=None):
|
||||
|
@ -110,3 +115,16 @@ class BaseObject(object):
|
|||
|
||||
collection = RelationSet
|
||||
|
||||
|
||||
# utility functions
|
||||
|
||||
def getUidForObject(obj, intIds=None):
|
||||
if intIds is None:
|
||||
intIds = component.getUtility(IIntIds)
|
||||
return intIds.getId(obj)
|
||||
|
||||
def getObjectForUid(uid, intIds=None):
|
||||
if intIds is None:
|
||||
intIds = component.getUtility(IIntIds)
|
||||
return intIds.getObject(uid)
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ class Customer(BaseObject):
|
|||
self.orders = self.collection(self, 'customer')
|
||||
|
||||
|
||||
class Address(object):
|
||||
class Address(BaseObject):
|
||||
|
||||
implements(IAddress)
|
||||
|
||||
|
|
|
@ -335,14 +335,42 @@ class IOrderItem(Interface):
|
|||
default=1,
|
||||
required=True)
|
||||
|
||||
order = Attribute(u'The order this order item belongs to.')
|
||||
product = Attribute(u'The product represented by this order item.')
|
||||
party = Attribute(u'The party (person, customer, session, ...) '
|
||||
u'that is ordering the product.')
|
||||
shop = Attribute(u'The shop from which the product is ordered.')
|
||||
order = Attribute(u'The order this order item belongs to.')
|
||||
unitPrice = Attribute(u'The basic unit price for one of the product '
|
||||
u'items ordered.')
|
||||
fullPrice = Attribute(u'The full price for the quantity ordered.')
|
||||
|
||||
def setOrder(order):
|
||||
""" Assign the order given to the order item.
|
||||
"""
|
||||
|
||||
|
||||
class IOrderItems(Interface):
|
||||
""" A collection of order items.
|
||||
"""
|
||||
|
||||
def __getitem__(key):
|
||||
""" Return the order item identified by the key given.
|
||||
"""
|
||||
|
||||
def __iter__():
|
||||
""" Return an iterator of all order items.
|
||||
"""
|
||||
|
||||
def query(**criteria):
|
||||
""" Search for order items. Possible criteria are:
|
||||
product, party, order, run, timeFrom, timeTo.
|
||||
"""
|
||||
|
||||
def add(product, party, shop, order='???', run=0, **kw):
|
||||
""" Create and register an order item; return it. Additional properties
|
||||
may be specified via keyword arguments.
|
||||
"""
|
||||
|
||||
def getCart(party, order='???', shop=None, run=0, **kw):
|
||||
""" Return a collection of order items.
|
||||
"""
|
||||
|
|
|
@ -22,16 +22,20 @@ Order and order item classes.
|
|||
$Id$
|
||||
"""
|
||||
|
||||
from zope.app.intid.interfaces import IIntIds
|
||||
from zope.cachedescriptors.property import Lazy
|
||||
from zope import component
|
||||
from zope.component import adapts
|
||||
from zope.interface import implements, Interface
|
||||
|
||||
from cybertools.commerce.common import getUidForObject, getObjectForUid
|
||||
from cybertools.commerce.common import Relation, BaseObject
|
||||
from cybertools.commerce.interfaces import IOrder, IOrderItem, IOrderItems
|
||||
from cybertools.tracking.btree import Track
|
||||
from cybertools.tracking.interfaces import ITrackingStorage
|
||||
|
||||
|
||||
class Order(object):
|
||||
class Order(BaseObject):
|
||||
|
||||
implements(IOrder)
|
||||
|
||||
|
@ -47,11 +51,34 @@ class OrderItem(Track):
|
|||
|
||||
implements(IOrderItem)
|
||||
|
||||
metadata_attributes = Track.metadata_attributes + ('order',)
|
||||
index_attributes = metadata_attributes
|
||||
typeName = 'OrderItem'
|
||||
|
||||
def __getattr__(self, attr):
|
||||
if attr not in IOrderItem:
|
||||
raise AttributeError(attr)
|
||||
return self.data.get(attr)
|
||||
|
||||
def getParent(self):
|
||||
return IOrderItems(self.__parent__)
|
||||
|
||||
def getObject(self, ref):
|
||||
if isinstance(ref, int):
|
||||
return getObjectForUid(ref)
|
||||
if isinstance(ref, basestring):
|
||||
if ref.isdigit:
|
||||
return getObjectForUid(int(ref))
|
||||
if ':' in ref:
|
||||
tp, id = ref.split(':', 1)
|
||||
return (tp, id)
|
||||
return ref
|
||||
|
||||
def setOrder(self, order):
|
||||
parent = self.getParent()
|
||||
self.order = parent.getUid(order)
|
||||
parent.context.indexTrack(0, self, 'order')
|
||||
|
||||
|
||||
class OrderItems(object):
|
||||
""" A tracking storage adapter managing order items.
|
||||
|
@ -71,14 +98,40 @@ class OrderItems(object):
|
|||
|
||||
def query(self, **criteria):
|
||||
if 'product' in criteria:
|
||||
criteria['taskId'] = criteria.pop('product')
|
||||
if 'person' in criteria:
|
||||
criteria['userName'] = criteria.pop('person')
|
||||
criteria['taskId'] = self.getUid(criteria.pop('product'))
|
||||
if 'party' in criteria:
|
||||
criteria['userName'] = self.getUid(criteria.pop('party'))
|
||||
if 'order' in criteria:
|
||||
criteria['order'] = self.getUid(criteria.pop('order'))
|
||||
if 'run' in criteria:
|
||||
criteria['runId'] = criteria.pop('run')
|
||||
return self.context.query(**criteria)
|
||||
|
||||
def add(self, product, person, run=0, **kw):
|
||||
trackId = self.context.saveUserTrack(product, run, person, kw)
|
||||
def add(self, product, party, shop, order='???', run=0, **kw):
|
||||
kw['shop'] = self.getUid(shop)
|
||||
trackId = self.context.saveUserTrack(self.getUid(product), run,
|
||||
self.getUid(party), kw)
|
||||
track = self[trackId]
|
||||
track.order = self.getUid(order)
|
||||
self.context.indexTrack(0, track, 'order')
|
||||
return track
|
||||
|
||||
def getCart(self, party, order='???', shop=None, run=None, **kw):
|
||||
if run:
|
||||
kw['run'] = run
|
||||
result = self.query(party=party, order=order, **kw)
|
||||
if shop is None:
|
||||
return list(result)
|
||||
return [item for item in result if item.shop == shop]
|
||||
|
||||
# utility methods
|
||||
|
||||
@Lazy
|
||||
def intIds(self):
|
||||
return component.getUtility(IIntIds)
|
||||
|
||||
def getUid(self, obj):
|
||||
if isinstance(obj, BaseObject):
|
||||
return getUidForObject(obj, self.intIds)
|
||||
return obj
|
||||
|
||||
|
|
|
@ -24,11 +24,11 @@ $Id$
|
|||
|
||||
from zope.interface import implements
|
||||
|
||||
from cybertools.commerce.common import RelationSet
|
||||
from cybertools.commerce.common import RelationSet, BaseObject
|
||||
from cybertools.commerce.interfaces import IShop
|
||||
|
||||
|
||||
class Shop(object):
|
||||
class Shop(BaseObject):
|
||||
|
||||
implements(IShop)
|
||||
|
||||
|
|
|
@ -8,8 +8,49 @@ $Id$
|
|||
|
||||
import unittest, doctest
|
||||
from zope.testing.doctestunit import DocFileSuite
|
||||
|
||||
from zope.app.intid.interfaces import IIntIds
|
||||
from zope import component
|
||||
from zope.interface import implements
|
||||
|
||||
from cybertools.commerce.order import OrderItems
|
||||
from cybertools.commerce.product import Product
|
||||
|
||||
|
||||
class IntIdsStub(object):
|
||||
"""A testing stub (mock utility) for IntIds."""
|
||||
implements(IIntIds)
|
||||
|
||||
def __init__(self):
|
||||
self.objs = []
|
||||
|
||||
def getObject(self, uid):
|
||||
return self.objs[uid]
|
||||
|
||||
def register(self, ob):
|
||||
if ob not in self.objs:
|
||||
self.objs.append(ob)
|
||||
return self.objs.index(ob)
|
||||
|
||||
getId = register
|
||||
queryId = getId
|
||||
|
||||
def unregister(self, ob):
|
||||
id = self.getId(ob)
|
||||
self.objs[id] = None
|
||||
|
||||
def __iter__(self):
|
||||
return iter(xrange(len(self.objs)))
|
||||
|
||||
|
||||
def setUp(testCase):
|
||||
component.provideUtility(IntIdsStub())
|
||||
component.provideAdapter(OrderItems)
|
||||
|
||||
def tearDown(testCase):
|
||||
pass
|
||||
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
"Basic tests."
|
||||
|
||||
|
@ -21,7 +62,8 @@ def test_suite():
|
|||
flags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
|
||||
return unittest.TestSuite((
|
||||
unittest.makeSuite(Test),
|
||||
DocFileSuite('README.txt', optionflags=flags),
|
||||
DocFileSuite('README.txt', optionflags=flags,
|
||||
setUp=setUp, tearDown=tearDown),
|
||||
))
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
Loading…
Add table
Reference in a new issue