]> asedeno.scripts.mit.edu Git - bluechips.git/blob - bluechips/model/types.py
d4454813bd7e5463fc513518359b755b53abd25f
[bluechips.git] / bluechips / model / types.py
1 """
2 Define special types used in BlueChips
3 """
4
5 import sqlalchemy as sa
6 from bluechips.lib.subclass import SmartSubclass
7
8 from weakref import WeakValueDictionary
9
10 class Currency(object):
11     """
12     Store currency values as an integral number of cents
13     """
14     __metaclass__ = SmartSubclass(int)
15     __old_values__ = WeakValueDictionary()
16     def __new__(cls, value):
17         if value is None:
18             value = 0
19         elif isinstance(value, str):
20             value = int(float(value) * 100)
21         else:
22             value = int(value)
23         
24         if value not in cls.__old_values__:
25             new_object = super(cls, cls).__new__(cls)
26             new_object.value = value
27             cls.__old_values__[value] = new_object
28             return new_object
29         else:
30             return cls.__old_values__[value]
31     
32     def __int__(self):
33         """
34         If I don't define this, SmartSubclass will return
35         Currency(int(self.value))
36         """
37         return self.value
38     def __float__(self):
39         """
40         If I don't define this, SmartSubclass will return
41         Currency(float(self.value))
42         """
43         return float(self.value)
44     def __long__(self):
45         """
46         If I don't define this, SmartSubclass will return
47         Currency(long(self.value))
48         """
49         return long(self.value)
50     
51     def __cmp__(self, other):
52         """
53         This is overridden for when validators compare a Currency to
54         ''
55         """
56         if other == '':
57             return 1
58         else:
59             return self.value.__cmp__(int(other))
60     
61     def __mul__(self, other):
62         """
63         If I don't define this, SmartSubclass will convert the other
64         argument to an int
65         """
66         return Currency(self.value * other)
67     def __rmul__(self, other):
68         """
69         If I don't define this, SmartSubclass will convert the other
70         argument to an int
71         """
72         return self.__mul__(other)
73     
74     def __str_no_dollar__(self):
75         """
76         Get to the formatted string without the dollar sign
77         """
78         return str(self).replace('$', '')
79     
80     def __repr__(self):
81         return '%s("%s")' % (self.__class__.__name__, str(self))
82     def __str__(self):
83         sign = '-' if self.value < 0 else ''
84         cents = abs(self.value) % 100
85         dollars = (abs(self.value) - cents) / 100
86         return '%s$%s.%.02d' % (sign, dollars, cents)
87
88 class DBCurrency(sa.types.TypeDecorator):
89     """
90     A type which represents monetary amounts internally as integers.
91     
92     This avoids binary/decimal float conversion issues
93     """
94     
95     impl = sa.types.Integer
96     
97     def process_bind_param(self, value, engine):
98         return int(value)
99     
100     def convert_result_value(self, value, engine):
101         return Currency(value)
102     process_result_value = convert_result_value