X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=bluechips%2Fmodel%2Ftypes.py;h=d4454813bd7e5463fc513518359b755b53abd25f;hb=ac41cefa3569ceca9ebee894d2c333360b4158fc;hp=d4ff40142e4cc0724a1b0d39c7037c425d8f7f50;hpb=040562cf56afa0d29449efea4e5a3ad60b6f1338;p=bluechips.git diff --git a/bluechips/model/types.py b/bluechips/model/types.py index d4ff401..d445481 100644 --- a/bluechips/model/types.py +++ b/bluechips/model/types.py @@ -3,10 +3,89 @@ Define special types used in BlueChips """ import sqlalchemy as sa -from bluechips.lib.helpers import round_currency -import locale +from bluechips.lib.subclass import SmartSubclass -class Currency(sa.types.TypeDecorator): +from weakref import WeakValueDictionary + +class Currency(object): + """ + Store currency values as an integral number of cents + """ + __metaclass__ = SmartSubclass(int) + __old_values__ = WeakValueDictionary() + def __new__(cls, value): + if value is None: + value = 0 + elif isinstance(value, str): + value = int(float(value) * 100) + else: + value = int(value) + + if value not in cls.__old_values__: + new_object = super(cls, cls).__new__(cls) + new_object.value = value + cls.__old_values__[value] = new_object + return new_object + else: + return cls.__old_values__[value] + + def __int__(self): + """ + If I don't define this, SmartSubclass will return + Currency(int(self.value)) + """ + return self.value + def __float__(self): + """ + If I don't define this, SmartSubclass will return + Currency(float(self.value)) + """ + return float(self.value) + def __long__(self): + """ + If I don't define this, SmartSubclass will return + Currency(long(self.value)) + """ + return long(self.value) + + def __cmp__(self, other): + """ + This is overridden for when validators compare a Currency to + '' + """ + if other == '': + return 1 + else: + return self.value.__cmp__(int(other)) + + def __mul__(self, other): + """ + If I don't define this, SmartSubclass will convert the other + argument to an int + """ + return Currency(self.value * other) + def __rmul__(self, other): + """ + If I don't define this, SmartSubclass will convert the other + argument to an int + """ + return self.__mul__(other) + + def __str_no_dollar__(self): + """ + Get to the formatted string without the dollar sign + """ + return str(self).replace('$', '') + + def __repr__(self): + return '%s("%s")' % (self.__class__.__name__, str(self)) + def __str__(self): + sign = '-' if self.value < 0 else '' + cents = abs(self.value) % 100 + dollars = (abs(self.value) - cents) / 100 + return '%s$%s.%.02d' % (sign, dollars, cents) + +class DBCurrency(sa.types.TypeDecorator): """ A type which represents monetary amounts internally as integers. @@ -16,7 +95,8 @@ class Currency(sa.types.TypeDecorator): impl = sa.types.Integer def process_bind_param(self, value, engine): - return int(value * 100) + return int(value) def convert_result_value(self, value, engine): - return round_currency(Decimal(value) / 100) + return Currency(value) + process_result_value = convert_result_value