source: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/vocabularies.py @ 12115

Last change on this file since 12115 was 12101, checked in by Henrik Bettermann, 10 years ago

Add tests for ConCatProductSource? and CustomerDocumentSource?.

  • Property svn:keywords set to Id
File size: 5.5 KB
Line 
1## $Id: vocabularies.py 12101 2014-12-01 06:41:32Z henrik $
2##
3## Copyright (C) 2014 Uli Fouquet & Henrik Bettermann
4## This program is free software; you can redistribute it and/or modify
5## it under the terms of the GNU General Public License as published by
6## the Free Software Foundation; either version 2 of the License, or
7## (at your option) any later version.
8##
9## This program is distributed in the hope that it will be useful,
10## but WITHOUT ANY WARRANTY; without even the implied warranty of
11## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12## GNU General Public License for more details.
13##
14## You should have received a copy of the GNU General Public License
15## along with this program; if not, write to the Free Software
16## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17##
18"""Vocabularies and sources for the customer section.
19"""
20import grok
21from zope.component import getUtility, queryUtility
22from zope.catalog.interfaces import ICatalog
23from zope.interface import implements, directlyProvides
24from zope.schema.interfaces import ISource, IContextSourceBinder
25from zope.schema.interfaces import ValidationError
26from zc.sourcefactory.basic import BasicSourceFactory
27from zc.sourcefactory.contextual import BasicContextualSourceFactory
28from waeup.ikoba.interfaces import SimpleIkobaVocabulary, SUBMITTED, VERIFIED
29from waeup.ikoba.interfaces import MessageFactory as _
30from waeup.ikoba.utils.helpers import get_sorted_preferred
31from waeup.ikoba.utils.countries import COUNTRIES
32
33#: a tuple of tuples (<COUNTRY-NAME>, <ISO-CODE>) with Nigeria first.
34COUNTRIES = get_sorted_preferred(COUNTRIES, ['NG'])
35nats_vocab = SimpleIkobaVocabulary(*COUNTRIES)
36
37
38class GenderSource(BasicSourceFactory):
39    """A gender source delivers basically a mapping
40       ``{'m': 'Male', 'f': 'Female'}``
41
42       Using a source, we make sure that the tokens (which are
43       stored/expected for instance from CSV files) are something one
44       can expect and not cryptic IntIDs.
45    """
46    def getValues(self):
47        return ['m', 'f']
48
49    def getToken(self, value):
50        return value[0].lower()
51
52    def getTitle(self, value):
53        if value == 'm':
54            return _('male')
55        if value == 'f':
56            return _('female')
57
58
59class RegNumNotInSource(ValidationError):
60    """Registration number exists already
61    """
62    # The docstring of ValidationErrors is used as error description
63    # by zope.formlib.
64    pass
65
66
67class RegNumberSource(object):
68    """A source that accepts any entry for a certain field if not used
69    already.
70
71    Using this kind of source means a way of setting an invariant.
72
73    We accept a value iff:
74    - the value cannot be found in catalog or
75    - the value can be found as part of some item but the bound item
76      is the context object itself.
77    """
78    implements(ISource)
79    cat_name = 'customers_catalog'
80    field_name = 'reg_number'
81    validation_error = RegNumNotInSource
82    comp_field = 'customer_id'
83
84    def __init__(self, context):
85        self.context = context
86        return
87
88    def __contains__(self, value):
89        """We accept all values not already given to other customers.
90        """
91        cat = queryUtility(ICatalog, self.cat_name)
92        if cat is None:
93            return True
94        kw = {self.field_name: (value, value)}
95        results = cat.searchResults(**kw)
96        for entry in results:
97            if not hasattr(self.context, self.comp_field):
98                # we have no context with comp_field (most probably
99                # while adding a new object, where the container is
100                # the context) which means that the value was given
101                # already to another object (as _something_ was found in
102                # the catalog with that value). Fail on first round.
103                raise self.validation_error(value)
104            if getattr(entry, self.comp_field) != getattr(
105                self.context, self.comp_field):
106                # An entry already given to another customer is not in our
107                # range of acceptable values.
108                raise self.validation_error(value)
109                #return False
110        return True
111
112
113def contextual_reg_num_source(context):
114    source = RegNumberSource(context)
115    return source
116
117directlyProvides(contextual_reg_num_source, IContextSourceBinder)
118
119
120class ConCatProductSource(BasicContextualSourceFactory):
121    """A contract category product source delivers all products
122    which belong to a certain contract_category.
123    """
124
125    def getValues(self, context):
126        concat = getattr(context, 'contract_category', None)
127        products = grok.getSite()['products'].values()
128        if not concat:
129            return products
130        resultlist = [
131            value for value in products if value.contract_category == concat]
132        return resultlist
133
134    def getToken(self, context, value):
135        return value.product_id
136
137    def getTitle(self, context, value):
138        return "%s - %s" % (value.product_id, value.title)
139
140
141class CustomerDocumentSource(BasicContextualSourceFactory):
142    """A customer document source delivers all submitted and verified documents
143    of the context customer.
144    """
145
146    def getValues(self, context):
147        documents = context.customer['documents'].values()
148        resultlist = [
149            value for value in documents if value.state in (SUBMITTED, VERIFIED)]
150        return resultlist
151
152    def getToken(self, context, value):
153        return value.document_id
154
155    def getTitle(self, context, value):
156        return "%s - %s" % (value.document_id, value.title)
Note: See TracBrowser for help on using the repository browser.