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
|
Carts and Orders
|
||||||
================
|
================
|
||||||
|
|
||||||
>>> from cybertools.commerce.order import OrderItems
|
A cart is just a collection of order items belonging to a certain customer
|
||||||
>>> component.provideAdapter(OrderItems)
|
(or some other kind of party).
|
||||||
|
|
||||||
>>> orderItems = manager.orderItems
|
>>> orderItems = manager.orderItems
|
||||||
|
|
||||||
>>> orderItems.add(p001, c001, quantity=3)
|
>>> orderItems.add(p001, c001, shop=shop1, quantity=3)
|
||||||
<Track [..., 1, ..., '... ...']: {'quantity': 3}>
|
<OrderItem [2, 1, 7, '... ...', '???']: {'shop': 0, 'quantity': 3}>
|
||||||
|
|
||||||
|
>>> orderItems.getCart(c001)
|
||||||
|
[<OrderItem [2, 1, 7, '... ...', '???']: {'shop': 0, 'quantity': 3}>]
|
||||||
|
|
||||||
Orders
|
Orders
|
||||||
------
|
------
|
||||||
|
|
||||||
|
The items in a shopping cart may be included in an order.
|
||||||
|
|
||||||
>>> ord001 = manager.orders.create(u'001', shop=shop1, customer=c001)
|
>>> 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
|
# 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
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
@ -22,6 +22,9 @@ Common functionality.
|
||||||
$Id$
|
$Id$
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from zope.app.intid.interfaces import IIntIds
|
||||||
|
from zope import component
|
||||||
|
|
||||||
|
|
||||||
class ContainerAttribute(object):
|
class ContainerAttribute(object):
|
||||||
|
|
||||||
|
@ -37,9 +40,11 @@ class ContainerAttribute(object):
|
||||||
for k, v in kw.items():
|
for k, v in kw.items():
|
||||||
setattr(obj, k, v)
|
setattr(obj, k, v)
|
||||||
self.data[id] = obj
|
self.data[id] = obj
|
||||||
|
component.getUtility(IIntIds).register(obj)
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
def remove(self, id):
|
def remove(self, id):
|
||||||
|
component.getUtility(IIntIds).unregister(self.data[id])
|
||||||
del self.data[id]
|
del self.data[id]
|
||||||
|
|
||||||
def get(self, id, default=None):
|
def get(self, id, default=None):
|
||||||
|
@ -110,3 +115,16 @@ class BaseObject(object):
|
||||||
|
|
||||||
collection = RelationSet
|
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')
|
self.orders = self.collection(self, 'customer')
|
||||||
|
|
||||||
|
|
||||||
class Address(object):
|
class Address(BaseObject):
|
||||||
|
|
||||||
implements(IAddress)
|
implements(IAddress)
|
||||||
|
|
||||||
|
|
|
@ -335,14 +335,42 @@ class IOrderItem(Interface):
|
||||||
default=1,
|
default=1,
|
||||||
required=True)
|
required=True)
|
||||||
|
|
||||||
order = Attribute(u'The order this order item belongs to.')
|
|
||||||
product = Attribute(u'The product represented by this order item.')
|
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 '
|
unitPrice = Attribute(u'The basic unit price for one of the product '
|
||||||
u'items ordered.')
|
u'items ordered.')
|
||||||
fullPrice = Attribute(u'The full price for the quantity 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):
|
class IOrderItems(Interface):
|
||||||
""" A collection of order items.
|
""" 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$
|
$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.component import adapts
|
||||||
from zope.interface import implements, Interface
|
from zope.interface import implements, Interface
|
||||||
|
|
||||||
|
from cybertools.commerce.common import getUidForObject, getObjectForUid
|
||||||
from cybertools.commerce.common import Relation, BaseObject
|
from cybertools.commerce.common import Relation, BaseObject
|
||||||
from cybertools.commerce.interfaces import IOrder, IOrderItem, IOrderItems
|
from cybertools.commerce.interfaces import IOrder, IOrderItem, IOrderItems
|
||||||
from cybertools.tracking.btree import Track
|
from cybertools.tracking.btree import Track
|
||||||
from cybertools.tracking.interfaces import ITrackingStorage
|
from cybertools.tracking.interfaces import ITrackingStorage
|
||||||
|
|
||||||
|
|
||||||
class Order(object):
|
class Order(BaseObject):
|
||||||
|
|
||||||
implements(IOrder)
|
implements(IOrder)
|
||||||
|
|
||||||
|
@ -47,11 +51,34 @@ class OrderItem(Track):
|
||||||
|
|
||||||
implements(IOrderItem)
|
implements(IOrderItem)
|
||||||
|
|
||||||
|
metadata_attributes = Track.metadata_attributes + ('order',)
|
||||||
|
index_attributes = metadata_attributes
|
||||||
|
typeName = 'OrderItem'
|
||||||
|
|
||||||
def __getattr__(self, attr):
|
def __getattr__(self, attr):
|
||||||
if attr not in IOrderItem:
|
if attr not in IOrderItem:
|
||||||
raise AttributeError(attr)
|
raise AttributeError(attr)
|
||||||
return self.data.get(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):
|
class OrderItems(object):
|
||||||
""" A tracking storage adapter managing order items.
|
""" A tracking storage adapter managing order items.
|
||||||
|
@ -71,14 +98,40 @@ class OrderItems(object):
|
||||||
|
|
||||||
def query(self, **criteria):
|
def query(self, **criteria):
|
||||||
if 'product' in criteria:
|
if 'product' in criteria:
|
||||||
criteria['taskId'] = criteria.pop('product')
|
criteria['taskId'] = self.getUid(criteria.pop('product'))
|
||||||
if 'person' in criteria:
|
if 'party' in criteria:
|
||||||
criteria['userName'] = criteria.pop('person')
|
criteria['userName'] = self.getUid(criteria.pop('party'))
|
||||||
|
if 'order' in criteria:
|
||||||
|
criteria['order'] = self.getUid(criteria.pop('order'))
|
||||||
if 'run' in criteria:
|
if 'run' in criteria:
|
||||||
criteria['runId'] = criteria.pop('run')
|
criteria['runId'] = criteria.pop('run')
|
||||||
return self.context.query(**criteria)
|
return self.context.query(**criteria)
|
||||||
|
|
||||||
def add(self, product, person, run=0, **kw):
|
def add(self, product, party, shop, order='???', run=0, **kw):
|
||||||
trackId = self.context.saveUserTrack(product, run, person, kw)
|
kw['shop'] = self.getUid(shop)
|
||||||
|
trackId = self.context.saveUserTrack(self.getUid(product), run,
|
||||||
|
self.getUid(party), kw)
|
||||||
track = self[trackId]
|
track = self[trackId]
|
||||||
|
track.order = self.getUid(order)
|
||||||
|
self.context.indexTrack(0, track, 'order')
|
||||||
return track
|
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 zope.interface import implements
|
||||||
|
|
||||||
from cybertools.commerce.common import RelationSet
|
from cybertools.commerce.common import RelationSet, BaseObject
|
||||||
from cybertools.commerce.interfaces import IShop
|
from cybertools.commerce.interfaces import IShop
|
||||||
|
|
||||||
|
|
||||||
class Shop(object):
|
class Shop(BaseObject):
|
||||||
|
|
||||||
implements(IShop)
|
implements(IShop)
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,49 @@ $Id$
|
||||||
|
|
||||||
import unittest, doctest
|
import unittest, doctest
|
||||||
from zope.testing.doctestunit import DocFileSuite
|
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
|
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):
|
class Test(unittest.TestCase):
|
||||||
"Basic tests."
|
"Basic tests."
|
||||||
|
|
||||||
|
@ -21,7 +62,8 @@ def test_suite():
|
||||||
flags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
|
flags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
|
||||||
return unittest.TestSuite((
|
return unittest.TestSuite((
|
||||||
unittest.makeSuite(Test),
|
unittest.makeSuite(Test),
|
||||||
DocFileSuite('README.txt', optionflags=flags),
|
DocFileSuite('README.txt', optionflags=flags,
|
||||||
|
setUp=setUp, tearDown=tearDown),
|
||||||
))
|
))
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
Loading…
Add table
Reference in a new issue