work in progress: orders and order items
git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@3110 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
2eba0d27a3
commit
e7fb4cd238
7 changed files with 266 additions and 38 deletions
|
@ -4,6 +4,8 @@ Commerce: Shope, Products, Customers, Orders, ...
|
|||
|
||||
($Id$)
|
||||
|
||||
>>> from zope import component
|
||||
|
||||
>>> from cybertools.commerce.manager import Manager
|
||||
>>> manager = Manager()
|
||||
|
||||
|
@ -42,6 +44,13 @@ it belongs to.
|
|||
>>> sorted((s.name, s.title) for s in p003.shops)
|
||||
[(u'shop1', u'PC up Ltd'), (u'shop2', u'Video up Ltd')]
|
||||
|
||||
We can also create a manufacturer and set it for a product.
|
||||
|
||||
>>> mf001 = manager.manufacturers.create(u'001', title=u'Global Electronics')
|
||||
>>> p001.manufacturer = mf001
|
||||
>>> [p.title for p in mf001.products]
|
||||
[u'Silent Case']
|
||||
|
||||
|
||||
Customers
|
||||
=========
|
||||
|
@ -66,6 +75,18 @@ Customers
|
|||
[(u'shop1', u'PC up Ltd'), (u'shop2', u'Video up Ltd')]
|
||||
|
||||
|
||||
Orders
|
||||
======
|
||||
Carts and Orders
|
||||
================
|
||||
|
||||
>>> from cybertools.commerce.order import OrderItems
|
||||
>>> component.provideAdapter(OrderItems)
|
||||
|
||||
>>> orderItems = manager.orderItems
|
||||
|
||||
>>> orderItems.add(p001, c001, quantity=3)
|
||||
<Track [..., 1, ..., '... ...']: {'quantity': 3}>
|
||||
|
||||
Orders
|
||||
------
|
||||
|
||||
>>> ord001 = manager.orders.create(u'001', shop=shop1, customer=c001)
|
||||
|
|
|
@ -51,22 +51,62 @@ class ContainerAttribute(object):
|
|||
|
||||
class RelationSet(object):
|
||||
|
||||
def __init__(self, parent, attributeName):
|
||||
def __init__(self, parent, attributeName=None):
|
||||
self.parent = parent
|
||||
self.attributeName = attributeName
|
||||
self.data = {}
|
||||
|
||||
def add(self, related):
|
||||
self.data[related.name] = related
|
||||
relatedData = getattr(related, self.attributeName).data
|
||||
if self.attributeName:
|
||||
value = getattr(related, self.attributeName)
|
||||
if isinstance(value, RelationSet):
|
||||
relatedData = value.data
|
||||
relatedData[self.parent.name] = self.parent
|
||||
else:
|
||||
setattr(related, self.attributeName, self.parent)
|
||||
|
||||
def remove(self, related):
|
||||
name = related.name
|
||||
del self.data[name]
|
||||
relatedData = getattr(related, self.attributeName).data
|
||||
if self.attributeName:
|
||||
value = getattr(related, self.attributeName)
|
||||
if isinstance(value, RelationSet):
|
||||
relatedData = value.data
|
||||
del relatedData[self.parent.name]
|
||||
else:
|
||||
setattr(related, self.attributeName, None)
|
||||
|
||||
def __iter__(self):
|
||||
for obj in self.data.values():
|
||||
yield obj
|
||||
|
||||
|
||||
class Relation(object):
|
||||
|
||||
def __init__(self, name, otherName):
|
||||
self.name = name
|
||||
self.otherName = otherName
|
||||
|
||||
def __get__(self, inst, class_=None):
|
||||
if inst is None:
|
||||
return self
|
||||
return getattr(inst, self.name)
|
||||
|
||||
def __set__(self, inst, value):
|
||||
existing = getattr(inst, self.name, None)
|
||||
if existing is not None:
|
||||
other = getattr(existing, self.otherName).data
|
||||
for k, v in other.items():
|
||||
if v != inst:
|
||||
del other[k]
|
||||
if value is not None:
|
||||
other = getattr(value, self.otherName).data
|
||||
other[inst.name] = inst
|
||||
setattr(inst, self.name, value)
|
||||
|
||||
|
||||
class BaseObject(object):
|
||||
|
||||
collection = RelationSet
|
||||
|
||||
|
|
|
@ -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
|
||||
|
@ -24,21 +24,20 @@ $Id$
|
|||
|
||||
from zope.interface import implements, Interface
|
||||
|
||||
from cybertools.commerce.common import RelationSet
|
||||
from cybertools.commerce.common import RelationSet, BaseObject
|
||||
from cybertools.commerce.interfaces import ICustomer, IAddress
|
||||
|
||||
|
||||
class Customer(object):
|
||||
class Customer(BaseObject):
|
||||
|
||||
implements(ICustomer)
|
||||
|
||||
collection = RelationSet
|
||||
|
||||
def __init__(self, customerId, title=None, client=None):
|
||||
self.name = self.customerId = customerId
|
||||
self.title = title or u'unknown'
|
||||
self.client = client
|
||||
self.shops = self.collection(self, 'customers')
|
||||
self.orders = self.collection(self, 'customer')
|
||||
|
||||
|
||||
class Address(object):
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#-*- coding: UTF-8 -*-
|
||||
#
|
||||
# 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
|
||||
|
@ -29,6 +30,7 @@ from zope.i18nmessageid import MessageFactory
|
|||
|
||||
from cybertools.util.jeep import Jeep, Term
|
||||
from cybertools.organize.interfaces import IAddress as IBaseAddress
|
||||
from cybertools.organize.interfaces import IPerson as IBasePerson
|
||||
from loops import util
|
||||
|
||||
_ = MessageFactory('cybertools.commerce')
|
||||
|
@ -41,12 +43,15 @@ class IManager(Interface):
|
|||
all components of a commerce site.
|
||||
"""
|
||||
|
||||
shops = Attribute('All shops in this commerce manager.')
|
||||
products = Attribute('All products in this commerce manager.')
|
||||
categories = Attribute('All product categories in this commerce manager.')
|
||||
manufacturers = Attribute('All manufacturers in this commerce manager.')
|
||||
suppliers = Attribute('All suppliers in this commerce manager.')
|
||||
customers = Attribute('All customers in this commerce manager.')
|
||||
shops = Attribute(u'All shops in this commerce manager.')
|
||||
products = Attribute(u'All products in this commerce manager.')
|
||||
categories = Attribute(u'All product categories in this commerce manager.')
|
||||
manufacturers = Attribute(u'All manufacturers in this commerce manager.')
|
||||
suppliers = Attribute(u'All suppliers in this commerce manager.')
|
||||
customers = Attribute(u'All customers in this commerce manager.')
|
||||
orders = Attribute(u'All orders in this commerce manager.')
|
||||
orderItems = Attribute(u'All order items; may also be cart items without '
|
||||
u'relation to an existing order.')
|
||||
|
||||
|
||||
# shops
|
||||
|
@ -179,6 +184,11 @@ class ICategory(Interface):
|
|||
""" A product category.
|
||||
"""
|
||||
|
||||
name = schema.ASCIILine(
|
||||
title=_(u'Category Identifier'),
|
||||
description=_(u'An internal name uniquely identifying the category.'),
|
||||
default='',
|
||||
required=True)
|
||||
title = schema.TextLine(
|
||||
title=_(u'Title'),
|
||||
description=_(u'Short title of the category.'),
|
||||
|
@ -203,6 +213,7 @@ class ICategory(Interface):
|
|||
|
||||
products = Attribute(u'The products belonging to this category.')
|
||||
subcategories = Attribute(u'The sub-categories belonging to this category.')
|
||||
parentCategories = Attribute(u'The parent categories belonging to this category.')
|
||||
shops = Attribute(u'The shops providing this category.')
|
||||
accessories = Attribute(u'Accessories for this category.')
|
||||
|
||||
|
@ -210,8 +221,8 @@ class ICategory(Interface):
|
|||
# customers
|
||||
|
||||
class ICustomer(Interface):
|
||||
""" Typically a role of - for example - a person or institution (the ``client``)
|
||||
representing a customer of one or more shops.
|
||||
""" Typically a role instance of - for example - a person or institution
|
||||
(the ``client``) representing a customer of one or more shops.
|
||||
|
||||
The client may be None in which case the customer is an object on
|
||||
its own.
|
||||
|
@ -229,16 +240,23 @@ class ICustomer(Interface):
|
|||
required=True)
|
||||
description = schema.Text(
|
||||
title=_(u'Description'),
|
||||
description=_(u'A medium-length description of the category.'),
|
||||
description=_(u'A medium-length description of the customer.'),
|
||||
default=u'',
|
||||
missing_value=u'',
|
||||
required=False)
|
||||
|
||||
shops = Attribute(u'The shops the client object is a customer of.')
|
||||
paymentTypes = Attribute(u'A collection of payment types supported.')
|
||||
orders = Attribute(u'A collection of the customer\'s orders.')
|
||||
|
||||
client = Attribute(u'An optional (real) client object of the customer role.')
|
||||
|
||||
|
||||
class IPerson(IBasePerson):
|
||||
|
||||
customer = Attribute(u'The customer the person belongs to.')
|
||||
|
||||
|
||||
addressTypesVoc = util.KeywordVocabulary((
|
||||
('standard', _(u'Standard Address')),
|
||||
('invoice', _(u'Invoice Address')),
|
||||
|
@ -256,9 +274,42 @@ class IAddress(IBaseAddress):
|
|||
default='standard',
|
||||
required=False)
|
||||
|
||||
clients = Attribute(u'A collection of objects that this address belongs to.')
|
||||
|
||||
# orders
|
||||
|
||||
valueTypesVoc = util.KeywordVocabulary((
|
||||
('product', _(u'Product Prices')),
|
||||
('shipping', _(u'Shipping Cost')),
|
||||
))
|
||||
|
||||
vatRatesVoc = util.KeywordVocabulary((
|
||||
('product', 0),
|
||||
('reduced', 7),
|
||||
('standard', 19),
|
||||
))
|
||||
|
||||
|
||||
currencyVoc = util.KeywordVocabulary((
|
||||
('EUR', u'€'),
|
||||
('USD', u'$'),
|
||||
))
|
||||
|
||||
|
||||
class IValue(Interface):
|
||||
""" An order or item value with additional information about the type of
|
||||
the value and e.g. the VAT rate.
|
||||
"""
|
||||
|
||||
type = Attribute(u'The type of the value; see valueTypesVoc.')
|
||||
value = Attribute(u'The value in the standard currency (EUR), '
|
||||
u'stored as a Decimal value.')
|
||||
currency = Attribute(u'The currency of the value.')
|
||||
currencyRate = Attribute(u'The rate for converting the value to the '
|
||||
u'standard currency, default is 1.')
|
||||
vat = Attribute(u'The id of the VAT rate; see vatRatesVoc.')
|
||||
|
||||
|
||||
class IOrder(Interface):
|
||||
"""
|
||||
"""
|
||||
|
@ -266,10 +317,16 @@ class IOrder(Interface):
|
|||
orderId = Attribute(u'Order Identifier')
|
||||
shop = Attribute(u'The shop this order belongs to.')
|
||||
customer = Attribute(u'The customer issuing this order.')
|
||||
invoiceAddress = Attribute(u'The address the invoice should be sent to.')
|
||||
shippingAddress = Attribute(u'The address the products should be sent to.')
|
||||
paymentType = Attribute(u'The payment type to be used for the order.')
|
||||
netValues = Attribute(u'A collection of net total values (IValue objects)'
|
||||
u'of the order.')
|
||||
total = Attribute(u'The total gross value (Decimal) of the order.')
|
||||
|
||||
|
||||
class IOrderItem(Interface):
|
||||
"""
|
||||
""" An individual order or cart item.
|
||||
"""
|
||||
|
||||
quantity = schema.Int(
|
||||
|
@ -278,7 +335,14 @@ class IOrderItem(Interface):
|
|||
default=1,
|
||||
required=True)
|
||||
|
||||
order = Attribute(u'Order this order item belongs to.')
|
||||
order = Attribute(u'The order this order item belongs to.')
|
||||
product = Attribute(u'The product represented by this order item.')
|
||||
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.')
|
||||
|
||||
|
||||
class IOrderItems(Interface):
|
||||
""" A collection of order items.
|
||||
"""
|
||||
|
||||
|
|
|
@ -26,9 +26,11 @@ from zope.interface import implements
|
|||
|
||||
from cybertools.commerce.common import ContainerAttribute
|
||||
from cybertools.commerce.customer import Customer
|
||||
from cybertools.commerce.interfaces import IManager
|
||||
from cybertools.commerce.product import Product
|
||||
from cybertools.commerce.interfaces import IManager, IOrderItems
|
||||
from cybertools.commerce.product import Product, Category, Manufacturer, Supplier
|
||||
from cybertools.commerce.order import Order, OrderItem
|
||||
from cybertools.commerce.shop import Shop
|
||||
from cybertools.tracking.btree import TrackingStorage
|
||||
|
||||
|
||||
class Manager(object):
|
||||
|
@ -38,4 +40,15 @@ class Manager(object):
|
|||
def __init__(self):
|
||||
self.shops = ContainerAttribute(Shop)
|
||||
self.products = ContainerAttribute(Product, 'productId')
|
||||
self.categories = ContainerAttribute(Category, 'name')
|
||||
self.manufacturers = ContainerAttribute(Manufacturer, 'name')
|
||||
self.suppliers = ContainerAttribute(Supplier, 'name')
|
||||
self.customers = ContainerAttribute(Customer, 'customerId')
|
||||
self.orders = ContainerAttribute(Order, 'orderId')
|
||||
self._orderItems = TrackingStorage(trackFactory=OrderItem)
|
||||
|
||||
@property
|
||||
def orderItems(self):
|
||||
return IOrderItems(self._orderItems)
|
||||
|
||||
|
||||
|
|
84
commerce/order.py
Normal file
84
commerce/order.py
Normal file
|
@ -0,0 +1,84 @@
|
|||
#
|
||||
# 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
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
"""
|
||||
Order and order item classes.
|
||||
|
||||
$Id$
|
||||
"""
|
||||
|
||||
from zope.component import adapts
|
||||
from zope.interface import implements, Interface
|
||||
|
||||
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):
|
||||
|
||||
implements(IOrder)
|
||||
|
||||
customer = Relation('_customer', 'orders')
|
||||
|
||||
def __init__(self, orderId, shop=None, customer=None):
|
||||
self.name = self.orderId = orderId
|
||||
self.shop = shop
|
||||
self.customer = customer
|
||||
|
||||
|
||||
class OrderItem(Track):
|
||||
|
||||
implements(IOrderItem)
|
||||
|
||||
def __getattr__(self, attr):
|
||||
if attr not in IOrderItem:
|
||||
raise AttributeError(attr)
|
||||
return self.data.get(attr)
|
||||
|
||||
|
||||
class OrderItems(object):
|
||||
""" A tracking storage adapter managing order items.
|
||||
"""
|
||||
|
||||
implements(IOrderItems)
|
||||
adapts(ITrackingStorage)
|
||||
|
||||
def __init__(self, context):
|
||||
self.context = context
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self.context[key]
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self.context.values())
|
||||
|
||||
def query(self, **criteria):
|
||||
if 'product' in criteria:
|
||||
criteria['taskId'] = criteria.pop('product')
|
||||
if 'person' in criteria:
|
||||
criteria['userName'] = criteria.pop('person')
|
||||
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)
|
||||
track = self[trackId]
|
||||
return track
|
|
@ -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
|
||||
|
@ -24,46 +24,53 @@ $Id$
|
|||
|
||||
from zope.interface import implements, Interface
|
||||
|
||||
from cybertools.commerce.common import RelationSet
|
||||
from cybertools.commerce.common import Relation, RelationSet, BaseObject
|
||||
from cybertools.commerce.interfaces import IProduct, ICategory
|
||||
from cybertools.commerce.interfaces import IManufacturer, ISupplier
|
||||
|
||||
|
||||
class Product(object):
|
||||
class Product(BaseObject):
|
||||
|
||||
implements(IProduct)
|
||||
|
||||
collection = RelationSet
|
||||
manufacturer = Relation('_manufacturer', 'products')
|
||||
|
||||
def __init__(self, productId, title=None):
|
||||
self.name = self.productId = productId
|
||||
self.title = title or u'unknown'
|
||||
self.shops = self.collection(self, 'products')
|
||||
self.categories = self.collection(self, 'products')
|
||||
self.suppliers = self.collection(self, 'products')
|
||||
|
||||
|
||||
class Category(object):
|
||||
class Category(BaseObject):
|
||||
|
||||
implements(ICategory)
|
||||
|
||||
collection = RelationSet
|
||||
|
||||
def __init__(self, title=None):
|
||||
def __init__(self, name, title=None):
|
||||
self.name = name
|
||||
self.title = title or u'unknown'
|
||||
self.shops = self.collection(self, 'categories')
|
||||
self.products = self.collection(self, 'categories')
|
||||
self.subcategories = self.collection(self, 'parentCategories')
|
||||
self.parentCategories = self.collection(self, 'subCategories')
|
||||
|
||||
|
||||
class Manufacturer(object):
|
||||
class Manufacturer(BaseObject):
|
||||
|
||||
implements(IManufacturer)
|
||||
|
||||
def __init__(self, title=None):
|
||||
def __init__(self, name, title=None):
|
||||
self.name = name
|
||||
self.title = title or u'unknown'
|
||||
self.products = self.collection(self, 'manufacturer')
|
||||
|
||||
|
||||
class Supplier(object):
|
||||
class Supplier(BaseObject):
|
||||
|
||||
implements(ISupplier)
|
||||
|
||||
def __init__(self, title=None):
|
||||
def __init__(self, name, title=None):
|
||||
self.name = name
|
||||
self.title = title or u'unknown'
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue