Changeset 12306


Ignore:
Timestamp:
24 Dec 2014, 07:38:53 (10 years ago)
Author:
Henrik Bettermann
Message:

Turn ResultEntry? (school grades) components into ProductOptionEntry? components.

Location:
main/waeup.ikoba/trunk/src/waeup/ikoba
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • main/waeup.ikoba/trunk/src/waeup/ikoba/interfaces.py

    r12260 r12306  
    8686            SimpleTerm(value, value, title) for title, value in terms])
    8787
     88currencies = SimpleIkobaVocabulary(
     89    (_('Naira'),'naira'),
     90    (_('USD'),'usd'),
     91    (_('EUR'),'eur'),
     92    )
    8893
    8994class ContextualDictSourceFactoryBase(SmartBasicContextualSourceFactory):
     
    105110        utils = getUtility(IIkobaUtils)
    106111        return getattr(utils, self.DICT_NAME)[value]
    107 
    108 class SubjectSource(BasicSourceFactory):
    109     """A source for school subjects used in exam documentation.
    110     """
    111     def getValues(self):
    112         subjects_dict = getUtility(IIkobaUtils).EXAM_SUBJECTS_DICT
    113         return sorted(subjects_dict.keys())
    114 
    115     def getTitle(self, value):
    116         subjects_dict = getUtility(IIkobaUtils).EXAM_SUBJECTS_DICT
    117         return "%s:" % subjects_dict[value]
    118 
    119 class GradeSource(BasicSourceFactory):
    120     """A source for exam grades.
    121     """
    122     def getValues(self):
    123         for entry in getUtility(IIkobaUtils).EXAM_GRADES:
    124             yield entry[0]
    125 
    126     def getTitle(self, value):
    127         return dict(getUtility(IIkobaUtils).EXAM_GRADES)[value]
    128112
    129113# Define a validation method for email addresses
     
    227211        return value
    228212
    229 class IResultEntry(Interface):
     213class IProductOptionEntry(Interface):
    230214    """A school grade entry.
    231215    """
    232     subject = schema.Choice(
    233         title = _(u'Subject'),
    234         source = SubjectSource(),
    235         )
    236     grade = schema.Choice(
    237         title = _(u'Grade'),
    238         source = GradeSource(),
    239         )
    240 
    241 class IResultEntryField(IObject):
     216    title = schema.TextLine(
     217        title = _(u'Title'),
     218        required = True,
     219        )
     220    fee = schema.Decimal(
     221        title = _(u'Fee'),
     222        required = False,
     223        )
     224    currency = schema.Choice(
     225        title = _(u'Currency'),
     226        vocabulary = currencies,
     227        required = False,
     228        )
     229
     230class IProductOptionEntryField(IObject):
    242231    """A zope.schema-like field for usage in interfaces.
    243232
    244     Marker interface to distuingish result entries from ordinary
     233    Marker interface to distuingish product option entries from ordinary
    245234    object fields. Needed for registration of widgets.
    246235    """
     
    252241    PORTAL_LANGUAGE = Attribute("Dict of global language setting")
    253242    PREFERRED_LANGUAGES_DICT = Attribute("Dict of preferred languages")
    254     EXAM_SUBJECTS_DICT = Attribute("Dict of examination subjects")
    255     EXAM_GRADES = Attribute("Dict of examination grades")
    256243    SYSTEM_MAX_LOAD = Attribute("Dict of maximum system loads.")
    257244
  • main/waeup.ikoba/trunk/src/waeup/ikoba/schoolgrades.py

    r11949 r12306  
    1616## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    1717##
    18 """Components representing and aggregating school grades.
     18"""Components representing and aggregating product options.
    1919"""
    2020import grok
     21from decimal import Decimal
    2122from zope.formlib.interfaces import IInputWidget, IDisplayWidget
    2223from zope.publisher.interfaces.browser import IBrowserRequest
    2324from zope.schema.fieldproperty import FieldProperty
    2425from zope.schema import Object
    25 from waeup.ikoba.interfaces import IResultEntry, IResultEntryField
     26from waeup.ikoba.interfaces import IProductOptionEntry, IProductOptionEntryField
    2627from waeup.ikoba.widgets.objectwidget import (
    2728    IkobaObjectWidget, IkobaObjectDisplayWidget
    2829    )
    2930
    30 class ResultEntry(grok.Model):
    31     """A result entry contains a subject and a grade.
     31class ProductOptionEntry(grok.Model):
     32    """A product option entry contains a title, fee and currency.
    3233    """
    33     grok.implements(IResultEntry)
    34     subject = FieldProperty(IResultEntry['subject'])
    35     grade = FieldProperty(IResultEntry['grade'])
     34    grok.implements(IProductOptionEntry)
     35    title = FieldProperty(IProductOptionEntry['title'])
     36    fee = FieldProperty(IProductOptionEntry['fee'])
     37    currency = FieldProperty(IProductOptionEntry['currency'])
    3638
    37     def __init__(self, subject=None, grade=None):
    38         super(ResultEntry, self).__init__()
    39         if subject is not None:
    40             self.subject = subject
    41         if grade is not None:
    42             self.grade = grade
     39    def __init__(self, title=None, fee=None, currency=None):
     40        super(ProductOptionEntry, self).__init__()
     41        if title is not None:
     42            self.title = title
     43        if fee is not None:
     44            self.fee = fee
     45        if currency is not None:
     46            self.currency = currency
    4347        return
    4448
     
    4650        """A string representation that can be used in exports.
    4751
    48         Returned is a unicode string of format ``(u'<SUBJ>',u'<GRADE>')``.
     52        Returned is a unicode string of format ``(u'<TITLE>',u'<FEE>',u'<CURR>')``.
    4953        """
    50         return unicode((self.subject, self.grade))
     54        string = u"(u'%s', u'%s', u'%s')" % (self.title, self.fee, self.currency)
     55        string = string.replace("u'None'", "None")
     56        return string
    5157
    5258    @classmethod
    5359    def from_string(cls, string):
    54         """Create new ResultEntry instance based on `string`.
     60        """Create new ProductOptionEntry instance based on `string`.
    5561
    5662        The string is expected to be in format as delivered by
     
    5965        This is a classmethod. This means, you normally will call::
    6066
    61           ResultEntry.from_string(mystring)
     67          ProductOptionEntry.from_string(mystring)
    6268
    63         i.e. use the `ResultEntry` class, not an instance thereof.
     69        i.e. use the `ProductOptionEntry` class, not an instance thereof.
    6470        """
    6571        string = string.replace("u''", "None")
    66         subject, grade = eval(string)
    67         return cls(subject, grade)
     72        title, fee, currency = eval(string)
     73        try:
     74            fee = Decimal(fee)
     75        except TypeError:
     76            pass
     77        return cls(title, fee, currency)
    6878
    69 class ResultEntryField(Object):
     79class ProductOptionEntryField(Object):
    7080    """A zope.schema-like field for usage in interfaces.
    7181
     
    7484
    7585      class IMyInterface(Interface):
    76           my_result_entry = ResultEntryField()
     86          my_option_entry = ProductOptionEntryField()
    7787
    7888    Default widgets are registered to render result entry fields.
    7989    """
    80     grok.implements(IResultEntryField)
     90    grok.implements(IProductOptionEntryField)
    8191
    8292    def __init__(self, **kw):
    83         super(ResultEntryField, self).__init__(IResultEntry, **kw)
     93        super(ProductOptionEntryField, self).__init__(IProductOptionEntry, **kw)
    8494        return
    8595
    86 # register IkobaObjectWidgets as default widgets for IResultEntryFields
    87 @grok.adapter(IResultEntryField, IBrowserRequest)
     96# register IkobaObjectWidgets as default widgets for IProductOptionEntryFields
     97@grok.adapter(IProductOptionEntryField, IBrowserRequest)
    8898@grok.implementer(IInputWidget)
    8999def result_entry_input_widget(obj, req):
    90     return IkobaObjectWidget(obj, req, ResultEntry)
     100    return IkobaObjectWidget(obj, req, ProductOptionEntry)
    91101
    92 # register a display widget for IResultEntryFields
    93 @grok.adapter(IResultEntryField, IBrowserRequest)
     102# register a display widget for IProductOptionEntryFields
     103@grok.adapter(IProductOptionEntryField, IBrowserRequest)
    94104@grok.implementer(IDisplayWidget)
    95105def result_entry_display_widget(obj, req):
    96     return IkobaObjectDisplayWidget(obj, req, ResultEntry)
     106    return IkobaObjectDisplayWidget(obj, req, ProductOptionEntry)
  • main/waeup.ikoba/trunk/src/waeup/ikoba/tests/test_schoolgrades.py

    r11949 r12306  
    11# Tests for schoolgrades module.
    22import unittest
     3from decimal import Decimal
    34from zope.component import getGlobalSiteManager
    45from zope.interface.verify import verifyObject, verifyClass
    5 from zope.schema.interfaces import ConstraintNotSatisfied
    6 from waeup.ikoba.interfaces import IResultEntry, IResultEntryField, IIkobaUtils
    7 from waeup.ikoba.schoolgrades import ResultEntry, ResultEntryField
     6from zope.schema.interfaces import ConstraintNotSatisfied, WrongType
     7from waeup.ikoba.interfaces import IProductOptionEntry, IProductOptionEntryField, IIkobaUtils
     8from waeup.ikoba.schoolgrades import ProductOptionEntry, ProductOptionEntryField
    89from waeup.ikoba.utils.utils import IkobaUtils
    910
    10 class ResultEntryTests(unittest.TestCase):
     11class ProductOptionEntryTests(unittest.TestCase):
    1112
    1213    def setUp(self):
     
    1415        self.gsm = getGlobalSiteManager()
    1516        self.gsm.registerUtility(self.utils, IIkobaUtils)
    16         self.valid_subj = self.utils.EXAM_SUBJECTS_DICT.keys()[0]
    17         self.valid_grade = self.utils.EXAM_GRADES[0][0]
     17        self.valid_title = u'Option 1'
     18        self.valid_fee = Decimal(55.5)
     19        self.valid_currency = 'usd'
    1820        return
    1921
     
    2426    def test_ifaces(self):
    2527        # make sure we implement the promised interfaces.
    26         obj = ResultEntry()
    27         verifyObject(IResultEntry, obj)
    28         verifyClass(IResultEntry, ResultEntry)
     28        obj = ProductOptionEntry()
     29        verifyObject(IProductOptionEntry, obj)
     30        verifyClass(IProductOptionEntry, ProductOptionEntry)
    2931        return
    3032
    3133    def test_init(self):
    3234        # we can pass initial values
    33         item1 = ResultEntry()
    34         item2 = ResultEntry(self.valid_subj, self.valid_grade)
    35         self.assertTrue(item1.subject is None)
    36         self.assertTrue(item1.grade is None)
    37         self.assertEqual(item2.subject, self.valid_subj)
    38         self.assertEqual(item2.grade, self.valid_grade)
     35        item1 = ProductOptionEntry()
     36        item2 = ProductOptionEntry(
     37            self.valid_title, self.valid_fee, self.valid_currency)
     38        self.assertTrue(item1.title is None)
     39        self.assertTrue(item1.fee is None)
     40        self.assertTrue(item1.currency is None)
     41        self.assertEqual(item2.title, self.valid_title)
     42        self.assertEqual(item2.fee, self.valid_fee)
     43        self.assertEqual(item2.currency, self.valid_currency)
    3944        return
    4045
    4146    def test_illegal_value(self):
    42         # we do not accept values not stored in IkobaUtils
    43         item = ResultEntry()
     47        # we do not accept values which do not meet the interface
     48        item = ProductOptionEntry()
    4449        self.assertRaises(
    45             ConstraintNotSatisfied, ResultEntry, 'invalid', 'invalid')
    46         self.assertRaises(
    47             ConstraintNotSatisfied, ResultEntry, 'invalid')
    48         self.assertRaises(
    49             ConstraintNotSatisfied, setattr, item, 'subject', 'blah')
    50         self.assertRaises(
    51             ConstraintNotSatisfied, setattr, item, 'grade', 'blah')
     50            WrongType, ProductOptionEntry, 6, 500, 'invalid')
    5251        return
    5352
    5453    def test_to_string(self):
    5554        # the string representation is handy for export
    56         item1 = ResultEntry()
    57         item2 = ResultEntry(self.valid_subj, self.valid_grade)
    58         self.assertEqual(item1.to_string(), u"(None, None)")
    59         self.assertEqual(item2.to_string(), u"('%s', '%s')" % (
    60             self.valid_subj, self.valid_grade))
     55        item1 = ProductOptionEntry()
     56        item2 = ProductOptionEntry(
     57            self.valid_title, self.valid_fee, self.valid_currency)
     58        self.assertEqual(item1.to_string(), u"(None, None, None)")
     59        self.assertEqual(item2.to_string(), u"(u'%s', u'%s', u'%s')" % (
     60            self.valid_title, self.valid_fee, self.valid_currency))
    6161        return
    6262
    6363    def test_from_string(self):
    6464        # we can create new result entries based on strings
    65         myinput = u"(u'%s',u'%s')" % (
    66             self.valid_subj, self.valid_grade)
    67         item1 = ResultEntry.from_string(myinput)
    68         item2 = ResultEntry.from_string(u"(u'',u'')")
    69         item3 = ResultEntry.from_string(u"(None, None)")
    70         self.assertEqual(item1.subject, self.valid_subj)
    71         self.assertEqual(item1.grade, self.valid_grade)
    72         self.assertTrue(item2.subject is None)
    73         self.assertTrue(item2.grade is None)
    74         self.assertTrue(item3.subject is None)
    75         self.assertTrue(item3.grade is None)
     65        myinput = u"(u'%s',u'%s',u'%s')" % (
     66            self.valid_title, self.valid_fee, self.valid_currency)
     67        item1 = ProductOptionEntry.from_string(myinput)
     68        item2 = ProductOptionEntry.from_string(u"(u'', u'', u'')")
     69        item3 = ProductOptionEntry.from_string(u"(None, None, None)")
     70        self.assertEqual(item1.title, self.valid_title)
     71        self.assertEqual(item1.fee, self.valid_fee)
     72        self.assertEqual(item1.currency, self.valid_currency)
     73        self.assertTrue(item2.title is None)
     74        self.assertTrue(item2.fee is None)
     75        self.assertEqual(item2.currency, None)
     76        self.assertTrue(item3.title is None)
     77        self.assertTrue(item3.fee is None)
     78        self.assertEqual(item3.currency, None)
    7679        return
    7780
    78 class ResultEntryFieldTests(unittest.TestCase):
     81class ProductOptionEntryFieldTests(unittest.TestCase):
    7982
    8083    def test_ifaces(self):
    8184        # make sure we implement the promised interfaces.
    82         obj = ResultEntryField()
    83         verifyObject(IResultEntryField, obj)
    84         verifyClass(IResultEntryField, ResultEntryField)
     85        obj = ProductOptionEntryField()
     86        verifyObject(IProductOptionEntryField, obj)
     87        verifyClass(IProductOptionEntryField, ProductOptionEntryField)
    8588        return
    8689
  • main/waeup.ikoba/trunk/src/waeup/ikoba/utils/converters.py

    r12261 r12306  
    3030from zope.schema.interfaces import IList
    3131from waeup.ikoba.interfaces import (
    32     IObjectConverter, IResultEntryField, IFieldConverter, SubjectSource,
    33     GradeSource, DELETION_MARKER, IGNORE_MARKER)
     32    IObjectConverter, IProductOptionEntryField, IFieldConverter,
     33    DELETION_MARKER, IGNORE_MARKER)
    3434from waeup.ikoba.schema.interfaces import IPhoneNumber
    35 from waeup.ikoba.schoolgrades import ResultEntry
     35from waeup.ikoba.schoolgrades import ProductOptionEntry
    3636
    3737class ExtendedCheckBoxWidget(CheckBoxWidget):
     
    175175        return result
    176176
    177 class ResultEntryConverter(grok.Adapter):
    178     grok.context(IResultEntryField)
     177class ProductOptionEntryConverter(grok.Adapter):
     178    grok.context(IProductOptionEntryField)
    179179    grok.implements(IFieldConverter)
    180180
    181181    def request_data(self, name, value, schema_field, prefix='',
    182182                     mode='create'):
    183         """Turn CSV values into ResultEntry-compatible form data.
    184 
    185         Expects as `value` a _string_ like ``(u'mysubject',
    186         u'mygrade')`` and turns it into some dict like::
     183        """Turn CSV values into ProductOptionEntry-compatible form data.
     184
     185        Expects as `value` a _string_ like ``(u'mytitle',
     186        u'myfee')`` and turns it into some dict like::
    187187
    188188          {
    189             'form.grade.subject': u'9234896395...',
    190             'form.grade.grade': u'7e67e9e777..'
     189            'form.option.title': u'9234896395...',
     190            'form.option.fee': 7698769
     191            'form.option.currency': u'7e67e9e777..'
    191192            }
    192193
    193194        where the values are tokens from appropriate sources.
    194195
    195         Such dicts can be transformed into real ResultEntry objects by
     196        Such dicts can be transformed into real ProductOptionEntry objects by
    196197        input widgets used in converters.
    197198        """
    198199        try:
    199             entry = ResultEntry.from_string(value)
    200             subj, grade = entry.subject, entry.grade
     200            entry = ProductOptionEntry.from_string(value)
     201            title, fee, currency = entry.title, entry.fee, entry.currency
    201202        except:
    202203            return {prefix: value}
    203         # web forms send tokens instead of real values
    204         s_token = SubjectSource().factory.getToken(subj)
    205         g_token = GradeSource().factory.getToken(grade)
    206204        result = {
    207             "%ssubject" % (prefix): s_token,
    208             "%sgrade" % (prefix): g_token,
     205            "%stitle" % (prefix): title,
     206            "%sfee" % (prefix): fee,
     207            "%scurrency" % (prefix): currency,
    209208            }
    210209        return result
  • main/waeup.ikoba/trunk/src/waeup/ikoba/utils/tests/test_converters.py

    r11954 r12306  
    2323import tempfile
    2424import unittest
     25from decimal import Decimal
    2526from zope import schema
    2627from zope.component import provideUtility
     
    3536from waeup.ikoba.testing import FunctionalLayer, FunctionalTestCase
    3637from waeup.ikoba.interfaces import (
    37     SimpleIkobaVocabulary, SubjectSource, GradeSource, IFieldConverter,
     38    SimpleIkobaVocabulary, IFieldConverter,
    3839    DELETION_MARKER, IGNORE_MARKER)
    39 from waeup.ikoba.schoolgrades import ResultEntryField
     40from waeup.ikoba.schoolgrades import ProductOptionEntryField
    4041from waeup.ikoba.utils.converters import (
    4142    IObjectConverter, IFieldConverter, DefaultFieldConverter,
    42     ListFieldConverter, PhoneNumberFieldConverter, ResultEntryConverter,
     43    ListFieldConverter, PhoneNumberFieldConverter, ProductOptionEntryConverter,
    4344    DefaultObjectConverter)
    4445from waeup.ikoba.utils.helpers import attrs_to_fields
     
    9192        vocabulary = car_nums,
    9293        )
    93     grades = schema.List(
    94         title = u'School Grades',
    95         value_type = ResultEntryField(),
     94    options = schema.List(
     95        title = u'Options',
     96        value_type = ProductOptionEntryField(),
    9697        required = True,
    9798        default = [],
     
    136137        obj2 = ListFieldConverter(None)
    137138        obj3 = PhoneNumberFieldConverter(None)
    138         obj4 = ResultEntryConverter(None)
     139        obj4 = ProductOptionEntryConverter(None)
    139140        verify.verifyObject(IFieldConverter, obj1)
    140141        verify.verifyObject(IFieldConverter, obj2)
     
    144145        verify.verifyClass(IFieldConverter, ListFieldConverter)
    145146        verify.verifyClass(IFieldConverter, PhoneNumberFieldConverter)
    146         verify.verifyClass(IFieldConverter, ResultEntryConverter)
     147        verify.verifyClass(IFieldConverter, ProductOptionEntryConverter)
    147148        return
    148149
     
    384385        return
    385386
    386     def test_list_of_resultentries(self):
     387    def test_list_of_optionentries(self):
    387388        # We can handle lists of result entries
    388389        converter = IObjectConverter(IContact)
    389390        # get currently valid values
    390         s_src, g_src = SubjectSource(), GradeSource()
    391         s_val1, s_val2 = list(s_src.factory.getValues())[0:2]
    392         g_val1, g_val2 = list(g_src.factory.getValues())[0:2]
    393         req_string = u"[('%s', '%s'), ('%s', '%s')]" % (
    394                 s_val1, g_val1, s_val2, g_val2)
    395         err, inv_err, data = converter.fromStringDict(
    396             {"grades": req_string,
    397              },
    398             'contact')
    399         result_grades = data['grades']
    400         self.assertTrue(isinstance(result_grades, list))
    401         self.assertEqual(len(result_grades), 2)
    402         self.assertEqual(result_grades[0].subject, s_val1)
    403         self.assertEqual(result_grades[0].grade, g_val1)
     391        req_string = u"[(u'T1', u'55.6', u'usd'), (u'T2', u'66.6', u'eur')]"
     392        err, inv_err, data = converter.fromStringDict(
     393            {"options": req_string,}, 'contact')
     394        result_options = data['options']
     395        self.assertTrue(isinstance(result_options, list))
     396        self.assertEqual(len(result_options), 2)
     397        self.assertEqual(result_options[0].title, 'T1')
     398        self.assertEqual(result_options[0].fee, Decimal('55.6'))
     399        self.assertEqual(result_options[0].currency, 'usd')
     400        self.assertEqual(result_options[1].title, 'T2')
     401        self.assertEqual(result_options[1].fee, Decimal('66.6'))
     402        self.assertEqual(result_options[1].currency, 'eur')
    404403        return
    405404
     
    420419        converter = IObjectConverter(IContact)
    421420        err, inv_err, data = converter.fromStringDict(
    422             {"grades": DELETION_MARKER,
     421            {"options": DELETION_MARKER,
    423422             "friends": DELETION_MARKER},
    424423            'contact', mode='update')
    425424        # grades are about to be set to default, friends to None
    426         self.assertEqual(data, {'grades': [], 'friends': None})
    427         return
     425        self.assertEqual(data, {'options': [], 'friends': None})
     426        return
  • main/waeup.ikoba/trunk/src/waeup/ikoba/utils/utils.py

    r12297 r12306  
    107107        'no': 'no contract',
    108108        }
    109 
    110     EXAM_SUBJECTS_DICT = {
    111         'math': 'Mathematics',
    112         'computer_science': 'Computer Science',
    113         }
    114 
    115     #: Exam grades. The tuple is sorted as it should be displayed in
    116     #: select boxes.
    117     EXAM_GRADES = (
    118         ('A', 'Best'),
    119         ('B', 'Better'),
    120         ('C', 'Good'),
    121         )
    122109
    123110    PAYMENT_CATEGORIES = {
Note: See TracChangeset for help on using the changeset viewer.