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