source: main/waeup.ikoba/branches/uli-payments/src/waeup/ikoba/customers/vocabularies.py @ 12098

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

Add components for customer management. Some tests are still missing.

File size: 4.2 KB
Line 
1## $Id: vocabularies.py 9778 2012-12-06 15:45:03Z 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"""
20from zope.component import getUtility, queryUtility
21from zope.catalog.interfaces import ICatalog
22from zope.interface import implements, directlyProvides
23from zope.schema.interfaces import ISource, IContextSourceBinder
24from zope.schema.interfaces import ValidationError
25from zc.sourcefactory.basic import BasicSourceFactory
26from zc.sourcefactory.contextual import BasicContextualSourceFactory
27from waeup.ikoba.interfaces import SimpleIkobaVocabulary
28from waeup.ikoba.interfaces import MessageFactory as _
29from waeup.ikoba.utils.helpers import get_sorted_preferred
30from waeup.ikoba.utils.countries import COUNTRIES
31
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
58class RegNumNotInSource(ValidationError):
59    """Registration number exists already
60    """
61    # The docstring of ValidationErrors is used as error description
62    # by zope.formlib.
63    pass
64
65class RegNumberSource(object):
66    """A source that accepts any entry for a certain field if not used
67    already.
68
69    Using this kind of source means a way of setting an invariant.
70
71    We accept a value iff:
72    - the value cannot be found in catalog or
73    - the value can be found as part of some item but the bound item
74      is the context object itself.
75    """
76    implements(ISource)
77    cat_name = 'customers_catalog'
78    field_name = 'reg_number'
79    validation_error = RegNumNotInSource
80    comp_field = 'customer_id'
81    def __init__(self, context):
82        self.context = context
83        return
84
85    def __contains__(self, value):
86        """We accept all values not already given to other customers.
87        """
88        cat = queryUtility(ICatalog, self.cat_name)
89        if cat is None:
90            return True
91        kw = {self.field_name: (value, value)}
92        results = cat.searchResults(**kw)
93        for entry in results:
94            if not hasattr(self.context, self.comp_field):
95                # we have no context with comp_field (most probably
96                # while adding a new object, where the container is
97                # the context) which means that the value was given
98                # already to another object (as _something_ was found in
99                # the catalog with that value). Fail on first round.
100                raise self.validation_error(value)
101            if getattr(entry, self.comp_field) != getattr(
102                self.context, self.comp_field):
103                # An entry already given to another customer is not in our
104                # range of acceptable values.
105                raise self.validation_error(value)
106                #return False
107        return True
108
109def contextual_reg_num_source(context):
110    source = RegNumberSource(context)
111    return source
112directlyProvides(contextual_reg_num_source, IContextSourceBinder)
Note: See TracBrowser for help on using the repository browser.