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