2 Define special types used in BlueChips
5 import sqlalchemy as sa
6 from bluechips.lib.subclass import SmartSubclass
8 from weakref import WeakValueDictionary
10 class Currency(object):
12 Store currency values as an integral number of cents
14 __metaclass__ = SmartSubclass(int)
15 __old_values__ = WeakValueDictionary()
16 def __new__(cls, value):
19 elif isinstance(value, str):
20 value = int(float(value) * 100)
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
30 return cls.__old_values__[value]
34 If I don't define this, SmartSubclass will return
35 Currency(int(self.value))
40 If I don't define this, SmartSubclass will return
41 Currency(float(self.value))
43 return float(self.value)
46 If I don't define this, SmartSubclass will return
47 Currency(long(self.value))
49 return long(self.value)
51 def __cmp__(self, other):
53 This is overridden for when validators compare a Currency to
59 return self.value.__cmp__(int(other))
61 def __mul__(self, other):
63 If I don't define this, SmartSubclass will convert the other
66 return Currency(self.value * other)
67 def __rmul__(self, other):
69 If I don't define this, SmartSubclass will convert the other
72 return self.__mul__(other)
74 def __str_no_dollar__(self):
76 Get to the formatted string without the dollar sign
78 return str(self).replace('$', '')
81 return '%s("%s")' % (self.__class__.__name__, 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)
88 class DBCurrency(sa.types.TypeDecorator):
90 A type which represents monetary amounts internally as integers.
92 This avoids binary/decimal float conversion issues
95 impl = sa.types.Integer
97 def process_bind_param(self, value, engine):
100 def convert_result_value(self, value, engine):
101 return Currency(value)
102 process_result_value = convert_result_value