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