use decimal.Decimal instead of float to store amounts of money
This commit is contained in:
parent
32b87b47f5
commit
b157e92d5b
28 changed files with 111 additions and 69 deletions
|
|
@ -18,6 +18,7 @@
|
|||
# along with weboob. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
from decimal import Decimal
|
||||
import sys
|
||||
|
||||
from weboob.capabilities.bank import ICapBank, Account, Transaction
|
||||
|
|
@ -123,8 +124,8 @@ class AccountListFormatter(IFormatter):
|
|||
MANDATORY_FIELDS = ('id', 'label', 'balance', 'coming')
|
||||
|
||||
count = 0
|
||||
tot_balance = 0.0
|
||||
tot_coming = 0.0
|
||||
tot_balance = Decimal(0)
|
||||
tot_coming = Decimal(0)
|
||||
|
||||
def flush(self):
|
||||
if self.count < 1:
|
||||
|
|
@ -134,8 +135,8 @@ class AccountListFormatter(IFormatter):
|
|||
result += u'%s Total %8s %8s' % ((' ' * 15) if not self.interactive else '',
|
||||
'%.2f' % self.tot_balance, '%.2f' % self.tot_coming)
|
||||
self.after_format(result)
|
||||
self.tot_balance = 0.0
|
||||
self.tot_coming = 0.0
|
||||
self.tot_balance = Decimal(0)
|
||||
self.tot_coming = Decimal(0)
|
||||
self.count = 0
|
||||
|
||||
def format_dict(self, item):
|
||||
|
|
@ -152,7 +153,7 @@ class AccountListFormatter(IFormatter):
|
|||
result += '------------------------------------------%s+----------+----------\n' % (('-' * 15) if not self.interactive else '')
|
||||
result += (u' %s%-' + (u'15' if self.interactive else '30') + u's%s %-25s %8s %8s') % \
|
||||
(self.BOLD, id, self.NC,
|
||||
item['label'], '%.2f' % item['balance'], '%.2f' % (item['coming'] or 0.0))
|
||||
item['label'], '%.2f' % item['balance'], '%.2f' % (item['coming'] or Decimal(0.0)))
|
||||
|
||||
self.tot_balance += item['balance']
|
||||
if item['coming']:
|
||||
|
|
@ -281,7 +282,7 @@ class Boobank(ReplApplication):
|
|||
id_to, backend_name_to = self.parse_id(id_to)
|
||||
|
||||
try:
|
||||
amount = float(amount)
|
||||
amount = Decimal(amount)
|
||||
except (TypeError, ValueError):
|
||||
print >>sys.stderr, 'Error: please give a decimal amount to transfer'
|
||||
return 2
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@
|
|||
from PyQt4.QtGui import QListWidgetItem, QImage, QPixmap, QLabel, QIcon, QBrush, QColor
|
||||
from PyQt4.QtCore import SIGNAL, Qt
|
||||
|
||||
from decimal import Decimal
|
||||
|
||||
from weboob.tools.application.qt import QtMainWindow, QtDo, HTMLDelegate
|
||||
from weboob.tools.application.qt.backendcfg import BackendCfg
|
||||
from weboob.capabilities.housing import ICapHousing, Query, City
|
||||
|
|
@ -35,8 +37,8 @@ class HousingListWidgetItem(QListWidgetItem):
|
|||
self.read = True
|
||||
|
||||
def __lt__(self, other):
|
||||
return '%s%s' % (self.read, float(self.housing.cost or 0) / float(self.housing.area or 1)) < \
|
||||
'%s%s' % (other.read, float(other.housing.cost or 0) / float(other.housing.area or 1))
|
||||
return '%s%s' % (self.read, Decimal(self.housing.cost or 0) / Decimal(self.housing.area or 1)) < \
|
||||
'%s%s' % (other.read, Decimal(other.housing.cost or 0) / Decimal(other.housing.area or 1))
|
||||
|
||||
def setAttrs(self, storage):
|
||||
text = u'<h2>%s</h2>' % self.housing.title
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
from datetime import date, datetime
|
||||
|
||||
from .base import CapBaseObject, Field, StringField, DateField, FloatField, IntField
|
||||
from .base import CapBaseObject, Field, StringField, DateField, DecimalField, IntField
|
||||
from .collection import ICapCollection
|
||||
|
||||
|
||||
|
|
@ -66,8 +66,8 @@ class Account(Recipient):
|
|||
TYPE_JOINT = 6 # Joint account
|
||||
|
||||
type = IntField('Type of account', default=TYPE_UNKNOWN)
|
||||
balance = FloatField('Balance on this bank account')
|
||||
coming = FloatField('Coming balance')
|
||||
balance = DecimalField('Balance on this bank account')
|
||||
coming = DecimalField('Coming balance')
|
||||
|
||||
def __repr__(self):
|
||||
return u"<Account id=%r label=%r>" % (self.id, self.label)
|
||||
|
|
@ -94,7 +94,7 @@ class Transaction(CapBaseObject):
|
|||
raw = StringField('Raw label of the transaction')
|
||||
category = StringField('Category of transaction')
|
||||
label = StringField('Pretty label')
|
||||
amount = FloatField('Amount of transaction')
|
||||
amount = DecimalField('Amount of transaction')
|
||||
|
||||
def __repr__(self):
|
||||
return "<Transaction date='%s' label='%s' amount=%s>" % (self.date,
|
||||
|
|
@ -105,7 +105,7 @@ class Transfer(CapBaseObject):
|
|||
Transfer from an account to a recipient.
|
||||
"""
|
||||
|
||||
amount = FloatField('Amount to transfer')
|
||||
amount = DecimalField('Amount to transfer')
|
||||
date = Field('Date of transfer', basestring, date, datetime)
|
||||
origin = Field('Origin of transfer', int, long, basestring)
|
||||
recipient = Field('Recipient', int, long, basestring)
|
||||
|
|
@ -193,7 +193,7 @@ class ICapBank(ICapCollection):
|
|||
:param recipient: account to send money
|
||||
:type recipient: :class:`Recipient`
|
||||
:param amount: amount
|
||||
:type amount: :class:`float`
|
||||
:type amount: :class:`decimal.Decimal`
|
||||
:param reason: reason of transfer
|
||||
:type reason: :class:`unicode`
|
||||
:rtype: :class:`Transfer`
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
import warnings
|
||||
import datetime
|
||||
from decimal import Decimal
|
||||
from copy import deepcopy
|
||||
|
||||
from weboob.tools.misc import to_unicode
|
||||
|
|
@ -27,8 +28,8 @@ from weboob.tools.ordereddict import OrderedDict
|
|||
|
||||
|
||||
__all__ = ['FieldNotFound', 'NotAvailable', 'NotLoaded', 'IBaseCap',
|
||||
'Field', 'IntField', 'FloatField', 'StringField', 'BytesField',
|
||||
'DateField', 'DeltaField', 'CapBaseObject', 'empty']
|
||||
'Field', 'IntField', 'DecimalField', 'FloatField', 'StringField',
|
||||
'BytesField', 'DateField', 'DeltaField', 'CapBaseObject', 'empty']
|
||||
|
||||
|
||||
def empty(value):
|
||||
|
|
@ -154,6 +155,18 @@ class IntField(Field):
|
|||
def convert(self, value):
|
||||
return int(value)
|
||||
|
||||
class DecimalField(Field):
|
||||
"""
|
||||
A field which accepts only :class:`decimal` type.
|
||||
"""
|
||||
def __init__(self, doc, **kwargs):
|
||||
Field.__init__(self, doc, Decimal, **kwargs)
|
||||
|
||||
def convert(self, value):
|
||||
if isinstance(value, Decimal):
|
||||
return value
|
||||
return Decimal(value)
|
||||
|
||||
class FloatField(Field):
|
||||
"""
|
||||
A field which accepts only :class:`float` type.
|
||||
|
|
@ -244,7 +257,7 @@ class CapBaseObject(object):
|
|||
class Transfer(CapBaseObject):
|
||||
" Transfer from an account to a recipient. "
|
||||
|
||||
amount = FloatField('Amount to transfer')
|
||||
amount = DecimalField('Amount to transfer')
|
||||
date = Field('Date of transfer', basestring, date, datetime)
|
||||
origin = Field('Origin of transfer', int, long, basestring)
|
||||
recipient = Field('Recipient', int, long, basestring)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with weboob. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from .base import CapBaseObject, StringField, DateField, FloatField
|
||||
from .base import CapBaseObject, StringField, DateField, DecimalField
|
||||
from .collection import ICapCollection
|
||||
|
||||
|
||||
|
|
@ -47,7 +47,7 @@ class Detail(CapBaseObject):
|
|||
label = StringField('label of the detail line')
|
||||
infos = StringField('information')
|
||||
datetime = DateField('date information')
|
||||
price = FloatField('price')
|
||||
price = DecimalField('price')
|
||||
|
||||
def __init__(self):
|
||||
CapBaseObject.__init__(self, 0)
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
# along with weboob. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
from .base import IBaseCap, CapBaseObject, Field, IntField, FloatField, \
|
||||
from .base import IBaseCap, CapBaseObject, Field, IntField, DecimalField, \
|
||||
StringField, BytesField, DateField
|
||||
|
||||
|
||||
|
|
@ -50,8 +50,8 @@ class Housing(CapBaseObject):
|
|||
Content of a housing.
|
||||
"""
|
||||
title = StringField('Title of housing')
|
||||
area = FloatField('Area of housing, in m2')
|
||||
cost = FloatField('Cost of housing')
|
||||
area = DecimalField('Area of housing, in m2')
|
||||
cost = DecimalField('Cost of housing')
|
||||
currency = StringField('Currency of cost')
|
||||
date = DateField('Date when the housing has been published')
|
||||
location = StringField('Location of housing')
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
# along with weboob. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
from .base import IBaseCap, CapBaseObject, Field, FloatField, \
|
||||
from .base import IBaseCap, CapBaseObject, Field, DecimalField, \
|
||||
StringField, DateField
|
||||
|
||||
|
||||
|
|
@ -44,7 +44,7 @@ class Price(CapBaseObject):
|
|||
Price.
|
||||
"""
|
||||
date = DateField('Date when this price has been published')
|
||||
cost = FloatField('Cost of the product in this shop')
|
||||
cost = DecimalField('Cost of the product in this shop')
|
||||
currency = StringField('Currency of the price')
|
||||
message = StringField('Message related to this price')
|
||||
shop = Field('Shop information', Shop)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
# along with weboob. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
from decimal import Decimal
|
||||
import re
|
||||
import datetime
|
||||
|
||||
|
|
@ -53,9 +54,9 @@ class FrenchTransaction(Transaction):
|
|||
debit = self.clean_amount(debit)
|
||||
|
||||
if len(debit) > 0:
|
||||
self.amount = - float(debit)
|
||||
self.amount = - Decimal(debit)
|
||||
else:
|
||||
self.amount = float(credit)
|
||||
self.amount = Decimal(credit)
|
||||
|
||||
def parse(self, date, raw):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
from __future__ import with_statement
|
||||
|
||||
from ConfigParser import RawConfigParser, DEFAULTSECT
|
||||
from decimal import Decimal
|
||||
import logging
|
||||
import os
|
||||
|
||||
|
|
@ -70,7 +71,7 @@ class INIConfig(IConfig):
|
|||
def save(self):
|
||||
def save_section(values, root_section=self.ROOTSECT):
|
||||
for k, v in values.iteritems():
|
||||
if isinstance(v, (int, float, basestring)):
|
||||
if isinstance(v, (int, Decimal, float, basestring)):
|
||||
if not self.config.has_section(root_section):
|
||||
self.config.add_section(root_section)
|
||||
self.config.set(root_section, k, unicode(v))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue