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:
helmutm 2009-01-03 14:29:48 +00:00
parent e7fb4cd238
commit 1f72392904
7 changed files with 173 additions and 16 deletions

View file

@ -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}>]

View file

@ -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)

View file

@ -40,7 +40,7 @@ class Customer(BaseObject):
self.orders = self.collection(self, 'customer')
class Address(object):
class Address(BaseObject):
implements(IAddress)

View file

@ -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.
"""

View file

@ -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

View file

@ -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)

View file

@ -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__':