cyberapps.commerce: Python3 fixes
This commit is contained in:
parent
3524df21a1
commit
c6c4fd56f2
27 changed files with 1554 additions and 0 deletions
7
cyberapps/bsm/README.txt
Normal file
7
cyberapps/bsm/README.txt
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
========================
|
||||||
|
Berlin School Management
|
||||||
|
========================
|
||||||
|
|
||||||
|
School Information
|
||||||
|
==================
|
||||||
|
|
3
cyberapps/bsm/__init__.py
Normal file
3
cyberapps/bsm/__init__.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
"""
|
||||||
|
$Id$
|
||||||
|
"""
|
138
cyberapps/bsm/browser.py
Normal file
138
cyberapps/bsm/browser.py
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
#
|
||||||
|
# Copyright (c) 2007 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
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
View classes for the BSM (Berlin School Management) project.
|
||||||
|
|
||||||
|
$Id$
|
||||||
|
"""
|
||||||
|
|
||||||
|
from zope import interface, component
|
||||||
|
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||||
|
from zope.cachedescriptors.property import Lazy
|
||||||
|
|
||||||
|
from cybertools.composer.schema import Schema
|
||||||
|
from cybertools.composer.schema import Field
|
||||||
|
from cybertools.reporter.browser.report import DetailView, ListingView
|
||||||
|
from cybertools.reporter.resultset import ResultSet, Cell
|
||||||
|
from loops.browser.concept import ConceptView
|
||||||
|
from loops.browser.node import NodeView
|
||||||
|
from loops.common import adapted
|
||||||
|
from loops.browser.common import conceptMacrosTemplate
|
||||||
|
from loops import util
|
||||||
|
|
||||||
|
|
||||||
|
bsmTemplate = ViewPageTemplateFile('macros.pt')
|
||||||
|
|
||||||
|
|
||||||
|
class TitleCell(Cell):
|
||||||
|
|
||||||
|
@property
|
||||||
|
def url(self):
|
||||||
|
view = self.row.resultSet.view
|
||||||
|
if view is None:
|
||||||
|
return u''
|
||||||
|
return ('%s/.target%s' %
|
||||||
|
(view.url, util.getUidForObject(self.row.context.context)))
|
||||||
|
|
||||||
|
|
||||||
|
class UrlCell(Cell):
|
||||||
|
|
||||||
|
limit = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def url(self):
|
||||||
|
value = self.value
|
||||||
|
if not value:
|
||||||
|
return ''
|
||||||
|
if self.field.name == 'email':
|
||||||
|
return 'mailto:' + value
|
||||||
|
if value.startswith('http'):
|
||||||
|
return value
|
||||||
|
return 'http://' + value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def text(self):
|
||||||
|
text = super(UrlCell, self).text
|
||||||
|
if self.limit and len(text) > self.limit:
|
||||||
|
text = text[:self.limit-1] + '...'
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
class UrlCellWithLimit(UrlCell):
|
||||||
|
|
||||||
|
limit = 20
|
||||||
|
|
||||||
|
|
||||||
|
class SchoolDetails(DetailView):
|
||||||
|
|
||||||
|
conceptMacros = conceptMacrosTemplate
|
||||||
|
|
||||||
|
@property
|
||||||
|
def macro(self):
|
||||||
|
return bsmTemplate.macros['detail']
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def nodeView(self):
|
||||||
|
return NodeView(self.context, self.request)
|
||||||
|
|
||||||
|
def resources(self):
|
||||||
|
for obj in self.context.getResources():
|
||||||
|
yield ConceptView(obj, self.request)
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def resultSet(self):
|
||||||
|
result = ResultSet([adapted(self.context)])
|
||||||
|
result.schema = Schema(
|
||||||
|
Field(u'title', u'Name'),
|
||||||
|
Field(u'address', u'Anschrift'),
|
||||||
|
Field(u'headMaster', u'Rektor'),
|
||||||
|
Field(u'telephone', u'Telefon'),
|
||||||
|
Field(u'telefax', u'Telefax'),
|
||||||
|
Field(u'email', u'E-Mail', renderFactory=UrlCell),
|
||||||
|
Field(u'website', u'Web', renderFactory=UrlCell),
|
||||||
|
)
|
||||||
|
result.view = self.nodeView
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
class SchoolListing(ListingView):
|
||||||
|
|
||||||
|
@property
|
||||||
|
def children(self):
|
||||||
|
for obj in self.nodeView.virtualTargetObject.getChildren():
|
||||||
|
yield adapted(obj)
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def nodeView(self):
|
||||||
|
return NodeView(self.context, self.request)
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def resultSet(self):
|
||||||
|
result = ResultSet(self.children)
|
||||||
|
result.schema = Schema(
|
||||||
|
Field(u'title', u'Name', renderFactory=TitleCell),
|
||||||
|
Field(u'address', u'Anschrift'),
|
||||||
|
Field(u'headMaster', u'Rektor'),
|
||||||
|
Field(u'telephone', u'Telefon'),
|
||||||
|
Field(u'telefax', u'Telefax'),
|
||||||
|
Field(u'email', u'E-Mail', renderFactory=UrlCellWithLimit),
|
||||||
|
Field(u'website', u'Web', renderFactory=UrlCellWithLimit),
|
||||||
|
)
|
||||||
|
result.view = self.nodeView
|
||||||
|
return result
|
32
cyberapps/bsm/configure.zcml
Normal file
32
cyberapps/bsm/configure.zcml
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<!-- $Id$ -->
|
||||||
|
|
||||||
|
<configure
|
||||||
|
xmlns:zope="http://namespaces.zope.org/zope"
|
||||||
|
xmlns:browser="http://namespaces.zope.org/browser"
|
||||||
|
i18n_domain="zope">
|
||||||
|
|
||||||
|
<zope:adapter factory="cyberapps.bsm.data.SchoolInfoAdapter"
|
||||||
|
trusted="True" />
|
||||||
|
|
||||||
|
<zope:class class="cyberapps.bsm.data.SchoolInfoAdapter">
|
||||||
|
<require permission="zope.View"
|
||||||
|
interface="cyberapps.bsm.interfaces.ISchoolInfo" />
|
||||||
|
<require permission="zope.ManageContent"
|
||||||
|
set_schema="cyberapps.bsm.interfaces.ISchoolInfo" />
|
||||||
|
</zope:class>
|
||||||
|
|
||||||
|
<browser:page
|
||||||
|
for="loops.interfaces.IConcept"
|
||||||
|
name="bsm_school_detail.html"
|
||||||
|
class="cyberapps.bsm.browser.SchoolDetails"
|
||||||
|
permission="zope.View"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<browser:page
|
||||||
|
for="loops.interfaces.INode"
|
||||||
|
name="bsm_schools.html"
|
||||||
|
class="cyberapps.bsm.browser.SchoolListing"
|
||||||
|
permission="zope.View"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</configure>
|
42
cyberapps/bsm/data.py
Normal file
42
cyberapps/bsm/data.py
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#
|
||||||
|
# Copyright (c) 2007 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
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
Classes for BSM School Informations.
|
||||||
|
|
||||||
|
$Id$
|
||||||
|
"""
|
||||||
|
|
||||||
|
from zope.component import adapts
|
||||||
|
from zope.interface import implements
|
||||||
|
|
||||||
|
from cyberapps.bsm.interfaces import ISchoolInfo
|
||||||
|
from loops.common import AdapterBase
|
||||||
|
from loops.interfaces import IConcept
|
||||||
|
from loops.type import TypeInterfaceSourceList
|
||||||
|
|
||||||
|
|
||||||
|
TypeInterfaceSourceList.typeInterfaces += (ISchoolInfo,)
|
||||||
|
|
||||||
|
|
||||||
|
class SchoolInfoAdapter(AdapterBase):
|
||||||
|
|
||||||
|
implements(ISchoolInfo)
|
||||||
|
|
||||||
|
_contextAttributes = list(ISchoolInfo) + list(IConcept)
|
||||||
|
|
62
cyberapps/bsm/interfaces.py
Normal file
62
cyberapps/bsm/interfaces.py
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
#
|
||||||
|
# Copyright (c) 2007 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
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
Interfaces for BSM (Berlin School Managment).
|
||||||
|
|
||||||
|
$Id$
|
||||||
|
"""
|
||||||
|
|
||||||
|
from zope.interface import Interface, Attribute
|
||||||
|
from zope import schema
|
||||||
|
|
||||||
|
from loops.util import _
|
||||||
|
|
||||||
|
|
||||||
|
class ISchoolInfo(Interface):
|
||||||
|
""" Information about schools taking part in the Berlin School Management
|
||||||
|
(BSM) project.
|
||||||
|
|
||||||
|
The name of the school is in the ``title`` attribute.
|
||||||
|
"""
|
||||||
|
|
||||||
|
address = schema.TextLine(
|
||||||
|
title=_(u'Address'),
|
||||||
|
description=_(u'Postal address of the school'),
|
||||||
|
required=False,)
|
||||||
|
headMaster = schema.TextLine(
|
||||||
|
title=_(u'Headmaster'),
|
||||||
|
description=_(u'Name of the head master of the school'),
|
||||||
|
required=False,)
|
||||||
|
telephone = schema.TextLine(
|
||||||
|
title=_(u'Telephone'),
|
||||||
|
description=_(u'Telephone number of the headmaster'),
|
||||||
|
required=False,)
|
||||||
|
telefax = schema.TextLine(
|
||||||
|
title=_(u'Telefax'),
|
||||||
|
description=_(u'Telefax number of the headmaster'),
|
||||||
|
required=False,)
|
||||||
|
email = schema.TextLine(
|
||||||
|
title=_(u'Email'),
|
||||||
|
description=_(u'Email address of the headmaster'),
|
||||||
|
required=False,)
|
||||||
|
website = schema.TextLine(
|
||||||
|
title=_(u'Website'),
|
||||||
|
description=_(u'URL of the website of the school'),
|
||||||
|
required=False,)
|
||||||
|
|
30
cyberapps/bsm/macros.pt
Normal file
30
cyberapps/bsm/macros.pt
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
<!-- $Id$ -->
|
||||||
|
|
||||||
|
<metal:detail define-macro="detail"
|
||||||
|
tal:define="result item/resultSet">
|
||||||
|
|
||||||
|
<h2 tal:content="item/title"
|
||||||
|
tal:attributes="ondblclick item/openEditWindow">
|
||||||
|
Something</h2><br />
|
||||||
|
<table>
|
||||||
|
<tr tal:repeat="cell item/cells">
|
||||||
|
<td width="20%">
|
||||||
|
<span tal:content="cell/field/title"
|
||||||
|
i18n:translate="">Fieldname</span>:
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="#"
|
||||||
|
tal:omit-tag="not:cell/url"
|
||||||
|
tal:attributes="href cell/url;
|
||||||
|
title cell/urlTitle">
|
||||||
|
<span tal:content="cell/text">Value</span>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table><br />
|
||||||
|
|
||||||
|
<div tal:attributes="class string:content-$level;">
|
||||||
|
<metal:fields use-macro="item/conceptMacros/macros/conceptresources" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</metal:detail>
|
187
cyberapps/commerce/README.txt
Normal file
187
cyberapps/commerce/README.txt
Normal file
|
@ -0,0 +1,187 @@
|
||||||
|
====================
|
||||||
|
eCommerce with loops
|
||||||
|
====================
|
||||||
|
|
||||||
|
Note: This package depends on loops.
|
||||||
|
|
||||||
|
Let's do some basic set up
|
||||||
|
|
||||||
|
>>> from zope.app.testing.setup import placefulSetUp, placefulTearDown
|
||||||
|
>>> site = placefulSetUp(True)
|
||||||
|
|
||||||
|
>>> from zope import component, interface
|
||||||
|
|
||||||
|
and setup a simple loops site with a concept manager and some concepts
|
||||||
|
(with all the type machinery, what in real life is done via standard
|
||||||
|
ZCML setup):
|
||||||
|
|
||||||
|
>>> from cyberapps.commerce.tests import TestSite
|
||||||
|
>>> t = TestSite(site)
|
||||||
|
>>> concepts, resources, views = t.setup()
|
||||||
|
|
||||||
|
We also collect here some basic imports we'll need later.
|
||||||
|
|
||||||
|
>>> from loops.concept import Concept
|
||||||
|
>>> from loops.common import adapted
|
||||||
|
>>> from loops.setup import addAndConfigureObject
|
||||||
|
|
||||||
|
We also use an adapter to the concept manager for accessing the commerce
|
||||||
|
objects.
|
||||||
|
|
||||||
|
>>> from cyberapps.commerce.manager import Manager
|
||||||
|
>>> manager = Manager(concepts)
|
||||||
|
|
||||||
|
|
||||||
|
Shops and Products
|
||||||
|
==================
|
||||||
|
|
||||||
|
Let's start with two shops:
|
||||||
|
|
||||||
|
>>> shop1 = manager.shops.create('shop1', title='PC up Ltd')
|
||||||
|
>>> shop2 = manager.shops.create('shop2', title='Video up Ltd')
|
||||||
|
|
||||||
|
>>> len(list(manager.shops))
|
||||||
|
2
|
||||||
|
|
||||||
|
>>> shop1.title
|
||||||
|
'PC up Ltd'
|
||||||
|
|
||||||
|
Now we create a few products ...
|
||||||
|
|
||||||
|
>>> p001 = manager.products.create('001', title='Silent Case')
|
||||||
|
>>> p002 = manager.products.create('002', title='Portable Projector')
|
||||||
|
>>> p003 = manager.products.create('003', title='HD Flatscreen Monitor')
|
||||||
|
>>> p004 = manager.products.create('004', title='Giga Mainboard')
|
||||||
|
|
||||||
|
>>> p001.title
|
||||||
|
'Silent Case'
|
||||||
|
>>> p001.fullDescription
|
||||||
|
|
||||||
|
... and add them to the shops.
|
||||||
|
|
||||||
|
>>> shop1.products.add(p001)
|
||||||
|
>>> shop1.products.add(p003)
|
||||||
|
>>> shop1.products.add(p004)
|
||||||
|
>>> shop2.products.add(p002)
|
||||||
|
>>> shop2.products.add(p003)
|
||||||
|
|
||||||
|
We can now list the products in a shop.
|
||||||
|
|
||||||
|
>>> sorted((p.productId, p.title) for p in shop1.products)
|
||||||
|
[('001', 'Silent Case'), ('003', 'HD Flatscreen Monitor'),
|
||||||
|
('004', 'Giga Mainboard')]
|
||||||
|
|
||||||
|
>>> sorted((s.name, s.title) for s in p003.shops)
|
||||||
|
[('shop1', 'PC up Ltd'), ('shop2', 'Video up Ltd')]
|
||||||
|
|
||||||
|
Categories
|
||||||
|
----------
|
||||||
|
|
||||||
|
>>> cat001 = manager.categories.create('001', title='Cases')
|
||||||
|
>>> p001.categories.add(cat001)
|
||||||
|
|
||||||
|
|
||||||
|
Customers
|
||||||
|
=========
|
||||||
|
|
||||||
|
Now let's add a few customers.
|
||||||
|
|
||||||
|
>>> c001 = manager.customers.create('001', title='Your Local Computer Store')
|
||||||
|
>>> c002 = manager.customers.create('002', title='Speedy Gonzales')
|
||||||
|
>>> c003 = manager.customers.create('003', title='TeeVee')
|
||||||
|
>>> c004 = manager.customers.create('004', title='MacVideo')
|
||||||
|
|
||||||
|
These are stored in a separate ConceptManager object.
|
||||||
|
|
||||||
|
>>> customers = concepts.getLoopsRoot()['customers']
|
||||||
|
>>> len(customers)
|
||||||
|
4
|
||||||
|
|
||||||
|
In the testing scenario we have to index all the customer objects.
|
||||||
|
|
||||||
|
>>> from zope.app.catalog.interfaces import ICatalog
|
||||||
|
>>> catalog = component.getUtility(ICatalog)
|
||||||
|
>>> from loops import util
|
||||||
|
>>> for r in customers.values():
|
||||||
|
... catalog.index_doc(int(util.getUidForObject(r)), r)
|
||||||
|
|
||||||
|
Now the customers can be accessed via the standard concept manager adapter.
|
||||||
|
|
||||||
|
>>> manager.customers.get('004')
|
||||||
|
<cyberapps.commerce.customer.Customer object ...>
|
||||||
|
|
||||||
|
>>> shop1.customers.add(c001)
|
||||||
|
>>> shop1.customers.add(c002)
|
||||||
|
>>> shop1.customers.add(c004)
|
||||||
|
>>> shop2.customers.add(c002)
|
||||||
|
>>> shop2.customers.add(c003)
|
||||||
|
>>> shop2.customers.add(c004)
|
||||||
|
|
||||||
|
>>> sorted((c.customerId, c.title) for c in shop1.customers)
|
||||||
|
[('001', 'Your Local Computer Store'), ('002', 'Speedy Gonzales'),
|
||||||
|
('004', 'MacVideo')]
|
||||||
|
|
||||||
|
>>> sorted((s.name, s.title) for s in c002.shops)
|
||||||
|
[('shop1', 'PC up Ltd'), ('shop2', 'Video up Ltd')]
|
||||||
|
|
||||||
|
|
||||||
|
Carts and Orders
|
||||||
|
================
|
||||||
|
|
||||||
|
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, shop=shop1, quantity=3)
|
||||||
|
<OrderItem ['44', 1, '60', '... ...', '???']: {'quantity': 3, 'shop': '40'}>
|
||||||
|
|
||||||
|
>>> orderItems.getCart(c001)
|
||||||
|
[<OrderItem ['44', 1, '60', '... ...', '???']: {'quantity': 3, 'shop': '40'}>]
|
||||||
|
|
||||||
|
Orders
|
||||||
|
------
|
||||||
|
|
||||||
|
The items in a shopping cart may be included in an order.
|
||||||
|
|
||||||
|
>>> ord001 = manager.orders.create('001', shop=shop1, customer=c001)
|
||||||
|
|
||||||
|
>>> for item in orderItems.getCart(c001):
|
||||||
|
... item.setOrder(ord001)
|
||||||
|
|
||||||
|
Now the default cart is empty; we have to supply the order for
|
||||||
|
retrieving the order items. But now we can omit the customer from the query.
|
||||||
|
|
||||||
|
>>> orderItems.getCart(c001)
|
||||||
|
[]
|
||||||
|
>>> orderItems.getCart(c001, ord001)
|
||||||
|
[<OrderItem ['44', 1, '60', '... ...', '74']: {'quantity': 3, 'shop': '40'}>]
|
||||||
|
>>> orderItems.getCart(order=ord001)
|
||||||
|
[<OrderItem ['44', 1, '60', '... ...', '74']: {'quantity': 3, 'shop': '40'}>]
|
||||||
|
|
||||||
|
|
||||||
|
Administrative Views and Forms
|
||||||
|
==============================
|
||||||
|
|
||||||
|
>>> from zope.publisher.browser import TestRequest
|
||||||
|
|
||||||
|
Listings
|
||||||
|
--------
|
||||||
|
|
||||||
|
>>> from cyberapps.commerce.browser.base import SimpleListing
|
||||||
|
|
||||||
|
Forms
|
||||||
|
-----
|
||||||
|
|
||||||
|
>>> from loops.view import Node
|
||||||
|
>>> from cyberapps.commerce.browser.product import CreateProductPage
|
||||||
|
|
||||||
|
>>> home = addAndConfigureObject(views, Node, 'home', target=cat001.context)
|
||||||
|
|
||||||
|
>>> form = CreateProductPage(home, TestRequest())
|
||||||
|
|
||||||
|
|
||||||
|
Fin de partie
|
||||||
|
=============
|
||||||
|
|
||||||
|
>>> placefulTearDown()
|
3
cyberapps/commerce/__init__.py
Normal file
3
cyberapps/commerce/__init__.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
"""
|
||||||
|
$Id$
|
||||||
|
"""
|
3
cyberapps/commerce/browser/__init__.py
Normal file
3
cyberapps/commerce/browser/__init__.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
"""
|
||||||
|
$Id$
|
||||||
|
"""
|
58
cyberapps/commerce/browser/action.py
Normal file
58
cyberapps/commerce/browser/action.py
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
#
|
||||||
|
# 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
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
Action definitions for loops-based eCommerce applications.
|
||||||
|
|
||||||
|
$Id$
|
||||||
|
"""
|
||||||
|
|
||||||
|
from cyberapps.commerce.util import _
|
||||||
|
from cybertools.browser.action import actions
|
||||||
|
from loops.browser.action import DialogAction, TargetAction
|
||||||
|
|
||||||
|
|
||||||
|
actions.register('create_product', 'portlet', TargetAction,
|
||||||
|
title=_(u'Create Product...'),
|
||||||
|
description=_(u'Create a new product.'),
|
||||||
|
viewName='create_product_page.html',
|
||||||
|
)
|
||||||
|
|
||||||
|
actions.register('edit_product', 'portlet', TargetAction,
|
||||||
|
title=_(u'Edit Product...'),
|
||||||
|
description=_(u'Modify product data.'),
|
||||||
|
viewName='edit_product_page.html',
|
||||||
|
)
|
||||||
|
|
||||||
|
actions.register('create_category', 'portlet', TargetAction,
|
||||||
|
title=_(u'Create Catgory...'),
|
||||||
|
description=_(u'Create a new category.'),
|
||||||
|
viewName='create_category_page.html',
|
||||||
|
)
|
||||||
|
|
||||||
|
actions.register('edit_category', 'portlet', TargetAction,
|
||||||
|
title=_(u'Edit Category...'),
|
||||||
|
description=_(u'Modify category data.'),
|
||||||
|
viewName='edit_category_page.html',
|
||||||
|
)
|
||||||
|
|
||||||
|
actions.register('edit_customer', 'portlet', TargetAction,
|
||||||
|
title=_(u'Edit Customer...'),
|
||||||
|
description=_(u'Modify customer data.'),
|
||||||
|
viewName='edit_concept_page.html',
|
||||||
|
)
|
22
cyberapps/commerce/browser/base.pt
Normal file
22
cyberapps/commerce/browser/base.pt
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<!-- $Id$ -->
|
||||||
|
|
||||||
|
|
||||||
|
<metal:block define-macro="simple_listing">
|
||||||
|
<div>
|
||||||
|
<metal:title use-macro="item/conceptMacros/concepttitle" />
|
||||||
|
</div>
|
||||||
|
<metal:listing define-macro="base_listing">
|
||||||
|
<dl tal:repeat="related item/children">
|
||||||
|
<dt>
|
||||||
|
<a tal:content="related/title"
|
||||||
|
tal:attributes="href python: view.getUrlForTarget(related);">Something</a>
|
||||||
|
</dt>
|
||||||
|
<dd class="description"
|
||||||
|
tal:define="description related/description"
|
||||||
|
tal:condition="description">
|
||||||
|
<span tal:content="structure related/renderedDescription">Description</span>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
</metal:listing>
|
||||||
|
</metal:block>
|
||||||
|
|
41
cyberapps/commerce/browser/base.py
Normal file
41
cyberapps/commerce/browser/base.py
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#
|
||||||
|
# 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
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
Common base/common view classes for loops-based eCommerce applications.
|
||||||
|
|
||||||
|
$Id$
|
||||||
|
"""
|
||||||
|
|
||||||
|
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||||
|
from zope.cachedescriptors.property import Lazy
|
||||||
|
from zope import component
|
||||||
|
|
||||||
|
from loops.browser.concept import ConceptView
|
||||||
|
from loops.common import adapted
|
||||||
|
from loops import util
|
||||||
|
|
||||||
|
|
||||||
|
base_macros = ViewPageTemplateFile('base.pt')
|
||||||
|
|
||||||
|
|
||||||
|
class SimpleListing(ConceptView):
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def macro(self):
|
||||||
|
return base_macros.macros['simple_listing']
|
84
cyberapps/commerce/browser/configure.zcml
Normal file
84
cyberapps/commerce/browser/configure.zcml
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
<!-- $Id$ -->
|
||||||
|
|
||||||
|
<configure
|
||||||
|
xmlns:zope="http://namespaces.zope.org/zope"
|
||||||
|
xmlns:browser="http://namespaces.zope.org/browser"
|
||||||
|
i18n_domain="cyberapps.commerce">
|
||||||
|
|
||||||
|
<zope:module module="cyberapps.commerce.browser.action" />
|
||||||
|
|
||||||
|
<!-- products, categories, ... -->
|
||||||
|
|
||||||
|
<zope:adapter
|
||||||
|
name="commerce_simple_listing.html"
|
||||||
|
for="loops.interfaces.IConcept
|
||||||
|
zope.publisher.interfaces.browser.IBrowserRequest"
|
||||||
|
provides="zope.interface.Interface"
|
||||||
|
factory="cyberapps.commerce.browser.base.SimpleListing"
|
||||||
|
permission="zope.View" />
|
||||||
|
|
||||||
|
<zope:adapter
|
||||||
|
name="commerce_product.html"
|
||||||
|
for="loops.interfaces.IConcept
|
||||||
|
zope.publisher.interfaces.browser.IBrowserRequest"
|
||||||
|
provides="zope.interface.Interface"
|
||||||
|
factory="cyberapps.commerce.browser.product.ProductView"
|
||||||
|
permission="zope.View" />
|
||||||
|
|
||||||
|
<zope:adapter
|
||||||
|
name="commerce_category.html"
|
||||||
|
for="loops.interfaces.IConcept
|
||||||
|
zope.publisher.interfaces.browser.IBrowserRequest"
|
||||||
|
provides="zope.interface.Interface"
|
||||||
|
factory="cyberapps.commerce.browser.product.CategoryView"
|
||||||
|
permission="zope.View" />
|
||||||
|
|
||||||
|
<browser:page
|
||||||
|
name="create_product_page.html"
|
||||||
|
for="loops.interfaces.INode"
|
||||||
|
class="cyberapps.commerce.browser.product.CreateProductPage"
|
||||||
|
permission="zope.ManageContent" />
|
||||||
|
|
||||||
|
<browser:page
|
||||||
|
name="edit_product_page.html"
|
||||||
|
for="loops.interfaces.INode"
|
||||||
|
class="cyberapps.commerce.browser.product.EditProductPage"
|
||||||
|
permission="zope.ManageContent" />
|
||||||
|
|
||||||
|
<zope:adapter
|
||||||
|
name="create_product"
|
||||||
|
for="loops.browser.node.NodeView
|
||||||
|
zope.publisher.interfaces.browser.IBrowserRequest"
|
||||||
|
factory="cyberapps.commerce.browser.product.CreateProduct"
|
||||||
|
permission="zope.ManageContent" />
|
||||||
|
|
||||||
|
<browser:page
|
||||||
|
name="create_category_page.html"
|
||||||
|
for="loops.interfaces.INode"
|
||||||
|
class="cyberapps.commerce.browser.product.CreateCategoryPage"
|
||||||
|
permission="zope.ManageContent" />
|
||||||
|
|
||||||
|
<browser:page
|
||||||
|
name="edit_category_page.html"
|
||||||
|
for="loops.interfaces.INode"
|
||||||
|
class="cyberapps.commerce.browser.product.EditCategoryPage"
|
||||||
|
permission="zope.ManageContent" />
|
||||||
|
|
||||||
|
<zope:adapter
|
||||||
|
name="create_category"
|
||||||
|
for="loops.browser.node.NodeView
|
||||||
|
zope.publisher.interfaces.browser.IBrowserRequest"
|
||||||
|
factory="cyberapps.commerce.browser.product.CreateCategory"
|
||||||
|
permission="zope.ManageContent" />
|
||||||
|
|
||||||
|
<!-- customers, ... -->
|
||||||
|
|
||||||
|
<zope:adapter
|
||||||
|
name="commerce_customer.html"
|
||||||
|
for="loops.interfaces.IConcept
|
||||||
|
zope.publisher.interfaces.browser.IBrowserRequest"
|
||||||
|
provides="zope.interface.Interface"
|
||||||
|
factory="cyberapps.commerce.browser.customer.CustomerView"
|
||||||
|
permission="zope.View" />
|
||||||
|
|
||||||
|
</configure>
|
37
cyberapps/commerce/browser/customer.py
Normal file
37
cyberapps/commerce/browser/customer.py
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
#
|
||||||
|
# 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
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
View classes for customers and related objects.
|
||||||
|
|
||||||
|
$Id$
|
||||||
|
"""
|
||||||
|
|
||||||
|
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||||
|
from zope.cachedescriptors.property import Lazy
|
||||||
|
|
||||||
|
from loops.browser.concept import ConceptView
|
||||||
|
from loops.common import adapted
|
||||||
|
from loops import util
|
||||||
|
|
||||||
|
|
||||||
|
# customers
|
||||||
|
|
||||||
|
class CustomerView(ConceptView):
|
||||||
|
|
||||||
|
pass
|
43
cyberapps/commerce/browser/product.pt
Normal file
43
cyberapps/commerce/browser/product.pt
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
<!-- $Id$ -->
|
||||||
|
|
||||||
|
|
||||||
|
<metal:block define-macro="category">
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<metal:title use-macro="item/conceptMacros/concepttitle" />
|
||||||
|
</div>
|
||||||
|
<h2 i18n:translate="">Subcategories</h2>
|
||||||
|
<dl tal:repeat="related item/subcategories">
|
||||||
|
<tal:item define="data related/data">
|
||||||
|
<dt>
|
||||||
|
<a tal:content="related/title"
|
||||||
|
tal:attributes="href python: view.getUrlForTarget(related);">Category</a>
|
||||||
|
</dt>
|
||||||
|
<dd class="description"
|
||||||
|
tal:define="description related/description"
|
||||||
|
tal:condition="description">
|
||||||
|
<span tal:content="structure related/renderedDescription">Description</span>
|
||||||
|
</dd>
|
||||||
|
</tal:item>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<h2 i18n:translate="">Products</h2>
|
||||||
|
<dl tal:repeat="related item/products">
|
||||||
|
<tal:item define="data related/data">
|
||||||
|
<dt>
|
||||||
|
<a tal:content="related/title"
|
||||||
|
tal:attributes="href python: view.getUrlForTarget(related);">Product</a>
|
||||||
|
</dt>
|
||||||
|
<dd class="description"
|
||||||
|
tal:define="description related/description"
|
||||||
|
tal:condition="description">
|
||||||
|
<span tal:content="structure related/renderedDescription">Description</span>
|
||||||
|
</dd>
|
||||||
|
</tal:item>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<metal:resources use-macro="view/concept_macros/conceptresources" />
|
||||||
|
|
||||||
|
</metal:block>
|
||||||
|
|
||||||
|
|
130
cyberapps/commerce/browser/product.py
Normal file
130
cyberapps/commerce/browser/product.py
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
#
|
||||||
|
# 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
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
View classes for loops-based eCommerce applications.
|
||||||
|
|
||||||
|
$Id$
|
||||||
|
"""
|
||||||
|
|
||||||
|
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||||
|
from zope.cachedescriptors.property import Lazy
|
||||||
|
from zope import component
|
||||||
|
|
||||||
|
from cybertools.browser.action import actions
|
||||||
|
from cybertools.composer.schema import Schema
|
||||||
|
from cybertools.composer.schema import Field
|
||||||
|
from loops.browser.action import DialogAction, TargetAction
|
||||||
|
from loops.browser.concept import ConceptView
|
||||||
|
from loops.browser.form import EditConceptPage, CreateConceptPage
|
||||||
|
from loops.browser.form import EditConcept, CreateConcept
|
||||||
|
from loops.browser.node import NodeView
|
||||||
|
from loops.common import adapted
|
||||||
|
from loops import util
|
||||||
|
|
||||||
|
|
||||||
|
product_macros = ViewPageTemplateFile('product.pt')
|
||||||
|
|
||||||
|
|
||||||
|
# products
|
||||||
|
|
||||||
|
class ProductView(ConceptView):
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class EditProductPage(EditConceptPage):
|
||||||
|
|
||||||
|
showAssignments = False
|
||||||
|
|
||||||
|
def setupController(self):
|
||||||
|
super(EditProductPage, self).setupController()
|
||||||
|
self.registerDojoFormAllGrid()
|
||||||
|
|
||||||
|
|
||||||
|
class CreateProductPage(CreateConceptPage):
|
||||||
|
|
||||||
|
showAssignments = False
|
||||||
|
typeToken = '.loops/concepts/product'
|
||||||
|
fixedType = True
|
||||||
|
form_action = 'create_product'
|
||||||
|
|
||||||
|
def setupController(self):
|
||||||
|
super(CreateProductPage, self).setupController()
|
||||||
|
self.registerDojoFormAllGrid()
|
||||||
|
|
||||||
|
|
||||||
|
class CreateProduct(CreateConcept):
|
||||||
|
|
||||||
|
def getNameFromData(self):
|
||||||
|
id = self.request.form.get('productId')
|
||||||
|
if id:
|
||||||
|
return 'p' + id
|
||||||
|
|
||||||
|
|
||||||
|
# categories
|
||||||
|
|
||||||
|
class CategoryView(ConceptView):
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def macro(self):
|
||||||
|
return product_macros.macros['category']
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def subcategories(self):
|
||||||
|
for c in self.adapted.subcategories:
|
||||||
|
view = ConceptView(c.context, self.request)
|
||||||
|
yield view
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def products(self):
|
||||||
|
for c in self.adapted.products:
|
||||||
|
view = ProductView(c.context, self.request)
|
||||||
|
yield view
|
||||||
|
|
||||||
|
|
||||||
|
class EditCategoryPage(EditConceptPage):
|
||||||
|
|
||||||
|
#showAssignments = False
|
||||||
|
|
||||||
|
def setupController(self):
|
||||||
|
super(EditCategoryPage, self).setupController()
|
||||||
|
self.registerDojoFormAllGrid()
|
||||||
|
|
||||||
|
|
||||||
|
class CreateCategoryPage(CreateConceptPage):
|
||||||
|
|
||||||
|
#showAssignments = False
|
||||||
|
typeToken = '.loops/concepts/category'
|
||||||
|
fixedType = True
|
||||||
|
form_action = 'create_category'
|
||||||
|
|
||||||
|
def setupController(self):
|
||||||
|
super(CreateCategoryPage, self).setupController()
|
||||||
|
self.registerDojoFormAllGrid()
|
||||||
|
|
||||||
|
|
||||||
|
class CreateCategory(CreateConcept):
|
||||||
|
|
||||||
|
def getNameFromData(self):
|
||||||
|
return super(CreateCategory, self).getNameFromData()
|
||||||
|
|
||||||
|
id = self.request.form.get('productId')
|
||||||
|
if id:
|
||||||
|
return 'p' + id
|
||||||
|
|
95
cyberapps/commerce/configure.zcml
Normal file
95
cyberapps/commerce/configure.zcml
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
<!-- $Id$ -->
|
||||||
|
|
||||||
|
<configure
|
||||||
|
xmlns:zope="http://namespaces.zope.org/zope"
|
||||||
|
xmlns:browser="http://namespaces.zope.org/browser"
|
||||||
|
i18n_domain="cyberapps.commerce">
|
||||||
|
|
||||||
|
<include package="cybertools.commerce" />
|
||||||
|
|
||||||
|
<zope:adapter factory="cyberapps.commerce.shop.Shop"
|
||||||
|
provides="cyberapps.commerce.interfaces.IShop"
|
||||||
|
trusted="True" />
|
||||||
|
<zope:class class="cyberapps.commerce.shop.Shop">
|
||||||
|
<require permission="zope.View"
|
||||||
|
interface="cyberapps.commerce.interfaces.IShop" />
|
||||||
|
<require permission="zope.ManageContent"
|
||||||
|
set_schema="cyberapps.commerce.interfaces.IShop" />
|
||||||
|
</zope:class>
|
||||||
|
|
||||||
|
<zope:adapter factory="cyberapps.commerce.product.Product"
|
||||||
|
provides="cyberapps.commerce.interfaces.IProduct"
|
||||||
|
trusted="True" />
|
||||||
|
<zope:class class="cyberapps.commerce.product.Product">
|
||||||
|
<require permission="zope.View"
|
||||||
|
interface="cyberapps.commerce.interfaces.IProduct" />
|
||||||
|
<require permission="zope.ManageContent"
|
||||||
|
set_schema="cyberapps.commerce.interfaces.IProduct" />
|
||||||
|
</zope:class>
|
||||||
|
|
||||||
|
<zope:adapter factory="cyberapps.commerce.product.Category"
|
||||||
|
provides="cyberapps.commerce.interfaces.ICategory"
|
||||||
|
trusted="True" />
|
||||||
|
<zope:class class="cyberapps.commerce.product.Category">
|
||||||
|
<require permission="zope.View"
|
||||||
|
interface="cyberapps.commerce.interfaces.ICategory" />
|
||||||
|
<require permission="zope.ManageContent"
|
||||||
|
set_schema="cyberapps.commerce.interfaces.ICategory" />
|
||||||
|
</zope:class>
|
||||||
|
|
||||||
|
<zope:adapter factory="cyberapps.commerce.product.Manufacturer"
|
||||||
|
trusted="True" />
|
||||||
|
<zope:class class="cyberapps.commerce.product.Manufacturer">
|
||||||
|
<require permission="zope.View"
|
||||||
|
interface="cybertools.commerce.interfaces.IManufacturer" />
|
||||||
|
<require permission="zope.ManageContent"
|
||||||
|
set_schema="cybertools.commerce.interfaces.IManufacturer" />
|
||||||
|
</zope:class>
|
||||||
|
|
||||||
|
<zope:adapter factory="cyberapps.commerce.customer.Customer"
|
||||||
|
provides="cyberapps.commerce.interfaces.ICustomer"
|
||||||
|
trusted="True" />
|
||||||
|
<zope:class class="cyberapps.commerce.customer.Customer">
|
||||||
|
<require permission="zope.View"
|
||||||
|
interface="cyberapps.commerce.interfaces.ICustomer" />
|
||||||
|
<require permission="zope.ManageContent"
|
||||||
|
set_schema="cyberapps.commerce.interfaces.ICustomer" />
|
||||||
|
</zope:class>
|
||||||
|
|
||||||
|
<zope:adapter factory="cyberapps.commerce.customer.Address"
|
||||||
|
provides="cyberapps.commerce.interfaces.IAddress"
|
||||||
|
trusted="True" />
|
||||||
|
<zope:class class="cyberapps.commerce.customer.Address">
|
||||||
|
<require permission="zope.View"
|
||||||
|
interface="cyberapps.commerce.interfaces.IAddress" />
|
||||||
|
<require permission="zope.ManageContent"
|
||||||
|
set_schema="cyberapps.commerce.interfaces.IAddress" />
|
||||||
|
</zope:class>
|
||||||
|
|
||||||
|
<zope:adapter factory="cyberapps.commerce.order.Order"
|
||||||
|
provides="cyberapps.commerce.interfaces.IOrder"
|
||||||
|
trusted="True" />
|
||||||
|
<zope:class class="cyberapps.commerce.order.Order">
|
||||||
|
<require permission="zope.View"
|
||||||
|
interface="cyberapps.commerce.interfaces.IOrder" />
|
||||||
|
<require permission="zope.ManageContent"
|
||||||
|
set_schema="cyberapps.commerce.interfaces.IOrder" />
|
||||||
|
</zope:class>
|
||||||
|
|
||||||
|
<!--<zope:adapter factory="cyberapps.commerce.order.OrderItems" />-->
|
||||||
|
|
||||||
|
<zope:class class="cyberapps.commerce.order.OrderItem">
|
||||||
|
<require permission="zope.View"
|
||||||
|
interface="cybertools.commerce.interfaces.IOrderItem" />
|
||||||
|
<require permission="zope.ManageContent"
|
||||||
|
set_schema="cybertools.commerce.interfaces.IOrderItem" />
|
||||||
|
</zope:class>
|
||||||
|
|
||||||
|
<!-- setup -->
|
||||||
|
|
||||||
|
<zope:adapter factory="cyberapps.commerce.setup.SetupManager"
|
||||||
|
name="cyberapps.commerce" />
|
||||||
|
|
||||||
|
<include package=".browser" />
|
||||||
|
|
||||||
|
</configure>
|
39
cyberapps/commerce/customer.py
Normal file
39
cyberapps/commerce/customer.py
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
# cyberapps.commerce.customer
|
||||||
|
|
||||||
|
""" Customer adapter and related classes.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from zope.interface import implementer
|
||||||
|
|
||||||
|
from cyberapps.commerce.interfaces import ICustomer, IAddress
|
||||||
|
from cybertools.commerce.customer import Customer as BaseCustomer
|
||||||
|
from cybertools.commerce.customer import Address as BaseAddress
|
||||||
|
from loops.common import AdapterBase
|
||||||
|
from loops.common import ChildRelationSetProperty, ParentRelationSetProperty
|
||||||
|
from loops.interfaces import IConceptSchema
|
||||||
|
from loops.type import TypeInterfaceSourceList
|
||||||
|
|
||||||
|
|
||||||
|
TypeInterfaceSourceList.typeInterfaces += (ICustomer, IAddress)
|
||||||
|
|
||||||
|
|
||||||
|
@implementer(ICustomer)
|
||||||
|
class Customer(AdapterBase, BaseCustomer):
|
||||||
|
|
||||||
|
_adapterAttributes = ('context', '__parent__', 'shops')
|
||||||
|
_contextAttributes = list(ICustomer)
|
||||||
|
_noexportAttributes = ('shops', 'orders')
|
||||||
|
|
||||||
|
shops = ParentRelationSetProperty('shop.customer', noSecurityCheck=True)
|
||||||
|
orders = ChildRelationSetProperty('customer.order')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def identifier(self):
|
||||||
|
return self.customerId
|
||||||
|
|
||||||
|
|
||||||
|
@implementer(IAddress)
|
||||||
|
class Address(AdapterBase, BaseAddress):
|
||||||
|
|
||||||
|
_contextAttributes = list(IAddress)
|
||||||
|
|
90
cyberapps/commerce/interfaces.py
Normal file
90
cyberapps/commerce/interfaces.py
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
#
|
||||||
|
# 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
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
Specific interfaces.
|
||||||
|
|
||||||
|
$Id$
|
||||||
|
"""
|
||||||
|
|
||||||
|
from cyberapps.commerce.util import _
|
||||||
|
from cybertools.commerce.interfaces import IShop, IProduct, ICategory, IManufacturer
|
||||||
|
from cybertools.commerce.interfaces import ICustomer, IAddress
|
||||||
|
from cybertools.commerce.interfaces import IOrder, IOrderItem
|
||||||
|
from loops.interfaces import ILoopsAdapter
|
||||||
|
from loops.schema.base import Relation, RelationSet
|
||||||
|
|
||||||
|
|
||||||
|
class IShop(ILoopsAdapter, IShop):
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ICategory(ILoopsAdapter, ICategory):
|
||||||
|
|
||||||
|
accessorySubcategories = RelationSet(
|
||||||
|
title=_(u'Accessory Subcategories'),
|
||||||
|
description=_(u'A collection of categories that contain products '
|
||||||
|
u'that may be used as accessories for this category.'),
|
||||||
|
target_types=('category',),
|
||||||
|
required=False)
|
||||||
|
selectedProducts = RelationSet(
|
||||||
|
title=_(u'Selected Products'),
|
||||||
|
description=_(u'Selected products for this category.'),
|
||||||
|
target_types=('product',),
|
||||||
|
required=False)
|
||||||
|
|
||||||
|
|
||||||
|
class IProduct(ILoopsAdapter, IProduct):
|
||||||
|
|
||||||
|
shops = RelationSet(
|
||||||
|
title=_(u'Shops'),
|
||||||
|
description=_(u'The shops providing this product..'),
|
||||||
|
target_types=('shop',),
|
||||||
|
required=False)
|
||||||
|
categories = RelationSet(
|
||||||
|
title=_(u'Categories'),
|
||||||
|
description=_(u'The product categories this product belongs to.'),
|
||||||
|
target_types=('category',),
|
||||||
|
required=False)
|
||||||
|
manufacturer = Relation(
|
||||||
|
title=_(u'Manufacturer'),
|
||||||
|
description=_(u'The manufacturer providing this product.'),
|
||||||
|
target_types=('manufacturer',),
|
||||||
|
required=False)
|
||||||
|
recommendedAccessories = RelationSet(
|
||||||
|
title=_(u'Recommended Accessories'),
|
||||||
|
description=_(u'Accessories for this product.'),
|
||||||
|
target_types=('product',),
|
||||||
|
required=False)
|
||||||
|
|
||||||
|
|
||||||
|
class ICustomer(ILoopsAdapter, ICustomer):
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class IAddress(ILoopsAdapter, IAddress):
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class IOrder(ILoopsAdapter, IOrder):
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
42
cyberapps/commerce/manager.py
Normal file
42
cyberapps/commerce/manager.py
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
# cyberapps.commerce.manager
|
||||||
|
|
||||||
|
""" The commerce manager (container, registry, ...).
|
||||||
|
"""
|
||||||
|
|
||||||
|
from zope.cachedescriptors.property import Lazy
|
||||||
|
from zope.component import adapts
|
||||||
|
from zope.interface import implementer
|
||||||
|
|
||||||
|
from cybertools.commerce.interfaces import IManager, IOrderItems
|
||||||
|
from loops.common import TypeInstancesProperty
|
||||||
|
from loops.concept import Concept
|
||||||
|
from loops.interfaces import IConceptManager
|
||||||
|
from loops.setup import addAndConfigureObject
|
||||||
|
|
||||||
|
|
||||||
|
@implementer(IManager)
|
||||||
|
class Manager(object):
|
||||||
|
|
||||||
|
adapts(IConceptManager)
|
||||||
|
|
||||||
|
langInfo = None
|
||||||
|
|
||||||
|
shops = TypeInstancesProperty('shop')
|
||||||
|
products = TypeInstancesProperty('product', 'productId', 'p')
|
||||||
|
categories = TypeInstancesProperty('category', 'name', 'cat')
|
||||||
|
customers = TypeInstancesProperty('customer', 'customerId', 'c',
|
||||||
|
container='customers')
|
||||||
|
orders = TypeInstancesProperty('order', 'orderId', '',
|
||||||
|
container='orders')
|
||||||
|
|
||||||
|
def __init__(self, context):
|
||||||
|
self.context = context
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def records(self):
|
||||||
|
return self.context.getLoopsRoot().getRecordManager()
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def orderItems(self):
|
||||||
|
return IOrderItems(self.records['orderitems'])
|
||||||
|
|
59
cyberapps/commerce/order.py
Normal file
59
cyberapps/commerce/order.py
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
# cyberapps.commerce.order
|
||||||
|
|
||||||
|
""" Order and order item classes.
|
||||||
|
"""
|
||||||
|
|
||||||
|
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 implementer, Interface
|
||||||
|
|
||||||
|
from cyberapps.commerce.interfaces import IOrder
|
||||||
|
from cybertools.commerce.order import Order as BaseOrder
|
||||||
|
from cybertools.commerce.order import OrderItem as BaseOrderItem
|
||||||
|
from cybertools.commerce.order import OrderItems as BaseOrderItems
|
||||||
|
from loops.common import AdapterBase, ParentRelation
|
||||||
|
from loops.interfaces import ILoopsObject
|
||||||
|
from loops import util
|
||||||
|
from loops.type import TypeInterfaceSourceList
|
||||||
|
|
||||||
|
|
||||||
|
TypeInterfaceSourceList.typeInterfaces += (IOrder,)
|
||||||
|
|
||||||
|
|
||||||
|
@implementer(IOrder)
|
||||||
|
class Order(AdapterBase, BaseOrder):
|
||||||
|
|
||||||
|
_adapterAttributes = ('context', '__parent__', 'customer')
|
||||||
|
_contextAttributes = list(IOrder)
|
||||||
|
|
||||||
|
#shop = ParentRelation('shop.order') # implemented as context attribute
|
||||||
|
customer = ParentRelation('customer.order')
|
||||||
|
|
||||||
|
|
||||||
|
class OrderItem(BaseOrderItem):
|
||||||
|
|
||||||
|
def getObject(self, ref):
|
||||||
|
if isinstance(ref, int):
|
||||||
|
return util.getObjectForUid(ref)
|
||||||
|
if isinstance(ref, basestring):
|
||||||
|
if ref.isdigit:
|
||||||
|
return util.getObjectForUid(ref)
|
||||||
|
if ':' in ref:
|
||||||
|
tp, id = ref.split(':', 1)
|
||||||
|
return (tp, id)
|
||||||
|
return ref
|
||||||
|
|
||||||
|
|
||||||
|
class OrderItems(BaseOrderItems):
|
||||||
|
|
||||||
|
# utility methods
|
||||||
|
|
||||||
|
def getUid(self, obj):
|
||||||
|
if ILoopsObject.providedBy(obj):
|
||||||
|
return util.getUidForObject(obj, self.intIds)
|
||||||
|
elif isinstance(obj, AdapterBase):
|
||||||
|
return util.getUidForObject(obj.context, self.intIds)
|
||||||
|
return obj
|
||||||
|
|
140
cyberapps/commerce/product.py
Normal file
140
cyberapps/commerce/product.py
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
# cyberapps.commerce.product
|
||||||
|
|
||||||
|
""" Product adapter.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from zope.app.intid.interfaces import IIntIds
|
||||||
|
from zope import component
|
||||||
|
from zope.interface import implementer
|
||||||
|
|
||||||
|
from cyberapps.commerce.interfaces import IProduct, ICategory
|
||||||
|
from cybertools.commerce.interfaces import IManufacturer, ISupplier
|
||||||
|
from cybertools.commerce.product import Product as BaseProduct, Category as BaseCategory
|
||||||
|
from cybertools.commerce.product import Manufacturer, Supplier
|
||||||
|
from cybertools.util.cache import cache
|
||||||
|
from loops.common import adapted, AdapterBase, baseObject, ParentRelation
|
||||||
|
from loops.common import ParentRelationSetProperty, ChildRelationSetProperty
|
||||||
|
from loops.interfaces import IConceptSchema
|
||||||
|
from loops.type import TypeInterfaceSourceList
|
||||||
|
from loops import util
|
||||||
|
|
||||||
|
|
||||||
|
TypeInterfaceSourceList.typeInterfaces += (
|
||||||
|
IProduct, ICategory, IManufacturer, ISupplier)
|
||||||
|
|
||||||
|
|
||||||
|
@implementer(IProduct)
|
||||||
|
class Product(AdapterBase, BaseProduct):
|
||||||
|
|
||||||
|
_adapterAttributes = ('context', '__parent__',
|
||||||
|
'shops', 'manufacturer', 'suppliers', 'categories',
|
||||||
|
'recommendedAccessories')
|
||||||
|
_contextAttributes = list(IProduct)
|
||||||
|
_noexportAttributes = ('shops', 'categories', 'manufacturer', 'suppliers',
|
||||||
|
'recommendedAccessories')
|
||||||
|
|
||||||
|
shops = ParentRelationSetProperty('shop.product')
|
||||||
|
categories = ParentRelationSetProperty('category.product')
|
||||||
|
manufacturer = ParentRelation('manufacturer.product')
|
||||||
|
suppliers = ParentRelationSetProperty('supplier.product')
|
||||||
|
recommendedAccessories = ChildRelationSetProperty('product.accessory')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def identifier(self):
|
||||||
|
return self.productId
|
||||||
|
|
||||||
|
|
||||||
|
@implementer(ICategory)
|
||||||
|
class Category(AdapterBase, BaseCategory):
|
||||||
|
|
||||||
|
_adapterAttributes = ('context', '__parent__',
|
||||||
|
'shops', 'subcategories', 'products',
|
||||||
|
'accessorySubcategories', 'selectedProducts')
|
||||||
|
_contextAttributes = list(ICategory)
|
||||||
|
_noexportAttributes = ('shops', 'products', 'parentCategories',
|
||||||
|
'subcategories', 'accessorySubcategories',
|
||||||
|
'selectedProducts')
|
||||||
|
|
||||||
|
shops = ParentRelationSetProperty('shop.category')
|
||||||
|
products = ChildRelationSetProperty('category.product')
|
||||||
|
parentCategories = ParentRelationSetProperty('standard', ICategory)
|
||||||
|
subcategories = ChildRelationSetProperty('standard')
|
||||||
|
accessorySubcategories = ChildRelationSetProperty('category.accessory')
|
||||||
|
selectedProducts = ChildRelationSetProperty('category.selected')
|
||||||
|
|
||||||
|
def getLongTitle(self):
|
||||||
|
parent = u''
|
||||||
|
defaultPredicate = self.getLoopsRoot().getConceptManager().getDefaultPredicate()
|
||||||
|
pr = self.context.getParentRelations([defaultPredicate])
|
||||||
|
for r in pr:
|
||||||
|
if r.relevance >= 0.8:
|
||||||
|
parent = r.first.title
|
||||||
|
if parent:
|
||||||
|
parent = u' - ' + parent
|
||||||
|
return self.title + parent
|
||||||
|
|
||||||
|
def getIsActiveCacheId(self, shop=None, *args, **kw):
|
||||||
|
shopId = shop is None and 'None' or shop.uid
|
||||||
|
filter = kw.get('filter') or ''
|
||||||
|
return 'commerce.category.isActive.%s.%s.%s' % (self.uid, shopId, filter)
|
||||||
|
|
||||||
|
@cache(getIsActiveCacheId, lifetime=93600)
|
||||||
|
def isActive(self, shop=None, filter=None):
|
||||||
|
depth = 0
|
||||||
|
for cat in self.subcategories:
|
||||||
|
if ICategory.providedBy(cat):
|
||||||
|
depth = max(depth, int(cat.isActive(shop, filter=filter)))
|
||||||
|
if depth:
|
||||||
|
return depth + 1
|
||||||
|
for prod in self.products:
|
||||||
|
if prod.isActive(shop, filter=filter):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def getAccessoryParents(self):
|
||||||
|
pred = self.getLoopsRoot().getConceptManager()['category.accessory']
|
||||||
|
for c in self.context.getParents([pred]):
|
||||||
|
yield adapted(c)
|
||||||
|
|
||||||
|
def getAllProductsCacheId(self, shop=None, *args, **kw):
|
||||||
|
shopId = shop is None and 'None' or shop.uid
|
||||||
|
filter = kw.get('filter') or ''
|
||||||
|
return 'commerce.category.allProducts.%s.%s.%s' % (self.uid, shopId, filter)
|
||||||
|
|
||||||
|
@cache(getAllProductsCacheId, lifetime=93600)
|
||||||
|
def getAllProductsUids(self, shop=None, filter=None):
|
||||||
|
intids = component.getUtility(IIntIds)
|
||||||
|
result = [util.getUidForObject(baseObject(p), intids)
|
||||||
|
for p in self.products
|
||||||
|
if p.isActive(shop, filter)]
|
||||||
|
for c in self.subcategories:
|
||||||
|
result.extend(c.getAllProductsUids())
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
class Manufacturer(AdapterBase, Manufacturer):
|
||||||
|
|
||||||
|
_contextAttributes = list(IManufacturer)
|
||||||
|
_noexportAttributes = ('products',)
|
||||||
|
|
||||||
|
products = ChildRelationSetProperty('manufacturer.product')
|
||||||
|
|
||||||
|
def getIsActiveCacheId(self, shop, *args, **kw):
|
||||||
|
shopId = shop is None and 'None' or shop.uid
|
||||||
|
filter = kw.get('filter') or ''
|
||||||
|
return 'commerce.manufacturer.isActive.%s.%s.%s' % (self.uid, shopId, filter)
|
||||||
|
|
||||||
|
@cache(getIsActiveCacheId, lifetime=72000)
|
||||||
|
def isActive(self, shop=None, filter=None):
|
||||||
|
for prod in self.products:
|
||||||
|
if prod.isActive(shop, filter=filter):
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class Supplier(AdapterBase, Supplier):
|
||||||
|
|
||||||
|
_contextAttributes = list(ISupplier)
|
||||||
|
_noexportAttributes = ('products',)
|
||||||
|
|
||||||
|
products = ChildRelationSetProperty('supplier.product')
|
||||||
|
|
58
cyberapps/commerce/setup.py
Normal file
58
cyberapps/commerce/setup.py
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
# cyberapps.commerce.setup
|
||||||
|
|
||||||
|
""" Automatic setup of a loops site for the commerce package.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from zope.component import adapts
|
||||||
|
|
||||||
|
from cyberapps.commerce.order import OrderItem
|
||||||
|
from cybertools.commerce.interfaces import IShop, IProduct, ICategory
|
||||||
|
from cybertools.commerce.interfaces import ICustomer, IOrder
|
||||||
|
from cybertools.tracking.btree import TrackingStorage
|
||||||
|
from loops.concept import Concept, ConceptManager
|
||||||
|
from loops.interfaces import ITypeConcept
|
||||||
|
from loops.setup import SetupManager as BaseSetupManager
|
||||||
|
|
||||||
|
|
||||||
|
class SetupManager(BaseSetupManager):
|
||||||
|
|
||||||
|
def setup(self):
|
||||||
|
concepts = self.context.getConceptManager()
|
||||||
|
type = concepts.getTypeConcept()
|
||||||
|
predicate = concepts.getPredicateType()
|
||||||
|
customers = self.addObject(self.context, ConceptManager, 'customers')
|
||||||
|
orders = self.addObject(self.context, ConceptManager, 'orders')
|
||||||
|
# type concepts:
|
||||||
|
tShop = self.addAndConfigureObject(concepts, Concept, 'shop',
|
||||||
|
title=u'Shop', conceptType=type, typeInterface=IShop)
|
||||||
|
tProduct = self.addAndConfigureObject(concepts, Concept, 'product',
|
||||||
|
title=u'Product', conceptType=type, typeInterface=IProduct)
|
||||||
|
tCategory = self.addAndConfigureObject(concepts, Concept, 'category',
|
||||||
|
title=u'Category', conceptType=type, typeInterface=ICategory)
|
||||||
|
tCustomer = self.addAndConfigureObject(concepts, Concept, 'customer',
|
||||||
|
title=u'Customer', conceptType=type, typeInterface=ICustomer)
|
||||||
|
tOrder = self.addAndConfigureObject(concepts, Concept, 'order',
|
||||||
|
title=u'Order', conceptType=type, typeInterface=IOrder)
|
||||||
|
# predicates:
|
||||||
|
category_product = self.addObject(concepts, Concept, 'category.product',
|
||||||
|
title=u'category <- product', conceptType=predicate)
|
||||||
|
category_accessory = self.addObject(concepts, Concept, 'category.accessory',
|
||||||
|
title=u'category <- accessory subcategory', conceptType=predicate)
|
||||||
|
#category_selected = self.addObject(concepts, Concept, 'category.selected',
|
||||||
|
# title=u'category <- selected product', conceptType=predicate)
|
||||||
|
product_accessory = self.addObject(concepts, Concept, 'product.accessory',
|
||||||
|
title=u'product <- accessory', conceptType=predicate)
|
||||||
|
shop_product = self.addObject(concepts, Concept, 'shop.product',
|
||||||
|
title=u'shop <- product', conceptType=predicate)
|
||||||
|
shop_customer = self.addObject(concepts, Concept, 'shop.customer',
|
||||||
|
title=u'shop <- customer', conceptType=predicate)
|
||||||
|
#shop_order = self.addObject(concepts, Concept, 'shop.order',
|
||||||
|
# title=u'shop <- order', conceptType=predicate)
|
||||||
|
manufacturer_product = self.addObject(concepts, Concept, 'manufacturer.product',
|
||||||
|
title=u'manufacturer <- product', conceptType=predicate)
|
||||||
|
customer_order = self.addObject(concepts, Concept, 'customer.order',
|
||||||
|
title=u'customer <- order', conceptType=predicate)
|
||||||
|
# records:
|
||||||
|
records = self.context.getRecordManager()
|
||||||
|
if 'orderitems' not in records:
|
||||||
|
records['orderitems'] = TrackingStorage(trackFactory=OrderItem)
|
31
cyberapps/commerce/shop.py
Normal file
31
cyberapps/commerce/shop.py
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
# cyberapps.commerce.shop
|
||||||
|
|
||||||
|
""" Shop adapter.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from zope.interface import implementer
|
||||||
|
from zope.traversing.api import getName
|
||||||
|
|
||||||
|
from cyberapps.commerce.interfaces import IShop
|
||||||
|
from cybertools.commerce.shop import Shop as BaseShop
|
||||||
|
from loops.common import AdapterBase, ChildRelationSetProperty
|
||||||
|
from loops.type import TypeInterfaceSourceList
|
||||||
|
|
||||||
|
|
||||||
|
TypeInterfaceSourceList.typeInterfaces += (IShop,)
|
||||||
|
|
||||||
|
|
||||||
|
@implementer(IShop)
|
||||||
|
class Shop(AdapterBase, BaseShop):
|
||||||
|
|
||||||
|
_adapterAttributes = ('context', '__parent__',
|
||||||
|
'products', 'categories', 'suppliers', 'customers')
|
||||||
|
_contextAttributes = list(IShop)
|
||||||
|
_noexportAttributes = ('products', 'customers')
|
||||||
|
|
||||||
|
products = ChildRelationSetProperty('shop.product')
|
||||||
|
customers = ChildRelationSetProperty('shop.customer')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
return getName(self.context)
|
55
cyberapps/commerce/tests.py
Executable file
55
cyberapps/commerce/tests.py
Executable file
|
@ -0,0 +1,55 @@
|
||||||
|
# $Id$
|
||||||
|
|
||||||
|
import unittest, doctest
|
||||||
|
from zope.testing.doctestunit import DocFileSuite
|
||||||
|
from zope import component
|
||||||
|
from zope.interface.verify import verifyClass
|
||||||
|
|
||||||
|
from cyberapps.commerce.customer import Customer, Address
|
||||||
|
from cyberapps.commerce.interfaces import IShop, IProduct, ICategory
|
||||||
|
from cyberapps.commerce.interfaces import ICustomer, IAddress, IOrder
|
||||||
|
from cyberapps.commerce.order import Order, OrderItems
|
||||||
|
from cyberapps.commerce.product import Product, Category
|
||||||
|
from cyberapps.commerce.shop import Shop
|
||||||
|
from cyberapps.commerce.setup import SetupManager
|
||||||
|
from cybertools.commerce.interfaces import IProduct
|
||||||
|
from loops.interfaces import ILoops
|
||||||
|
from loops.setup import ISetupManager
|
||||||
|
from loops.tests.setup import TestSite as BaseTestSite
|
||||||
|
|
||||||
|
|
||||||
|
class TestSite(BaseTestSite):
|
||||||
|
|
||||||
|
def __init__(self, site):
|
||||||
|
self.site = site
|
||||||
|
|
||||||
|
def setup(self):
|
||||||
|
component.provideAdapter(SetupManager, (ILoops,), ISetupManager,
|
||||||
|
name='cyberapps.commerce')
|
||||||
|
component.provideAdapter(Shop, provides=IShop)
|
||||||
|
component.provideAdapter(Product, provides=IProduct)
|
||||||
|
component.provideAdapter(Category, provides=ICategory)
|
||||||
|
component.provideAdapter(Customer, provides=ICustomer)
|
||||||
|
component.provideAdapter(Address, provides=IAddress)
|
||||||
|
component.provideAdapter(Order, provides=IOrder)
|
||||||
|
component.provideAdapter(OrderItems)
|
||||||
|
concepts, resources, views = self.baseSetup()
|
||||||
|
return concepts, resources, views
|
||||||
|
|
||||||
|
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
"Basic tests for the cyberapps.commerce package."
|
||||||
|
|
||||||
|
def testSomething(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def test_suite():
|
||||||
|
flags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
|
||||||
|
return unittest.TestSuite((
|
||||||
|
unittest.makeSuite(Test),
|
||||||
|
DocFileSuite('README.txt', optionflags=flags),
|
||||||
|
))
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main(defaultTest='test_suite')
|
23
cyberapps/commerce/util.py
Normal file
23
cyberapps/commerce/util.py
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
# cyberapps.commerce.util
|
||||||
|
|
||||||
|
""" Utility functions.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from email.mime.text import MIMEText
|
||||||
|
from zope import component
|
||||||
|
from zope.i18nmessageid import MessageFactory
|
||||||
|
from zope.sendmail.interfaces import IMailDelivery
|
||||||
|
|
||||||
|
|
||||||
|
_ = MessageFactory('cyberapps.commerce')
|
||||||
|
|
||||||
|
|
||||||
|
def sendEMail(subject, message, sender, recipients):
|
||||||
|
if isinstance(message, unicode):
|
||||||
|
message = message.encode('UTF-8')
|
||||||
|
msg = MIMEText(message, 'plain', 'utf-8')
|
||||||
|
msg['Subject'] = subject
|
||||||
|
msg['From'] = sender
|
||||||
|
msg['To'] = ', '.join(recipients)
|
||||||
|
mailhost = component.getUtility(IMailDelivery, 'Mail')
|
||||||
|
mailhost.send(sender, recipients, msg.as_string())
|
Loading…
Add table
Reference in a new issue