gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] [taler-bank] branch master updated (c04007b -> fc6a56f)


From: gnunet
Subject: [GNUnet-SVN] [taler-bank] branch master updated (c04007b -> fc6a56f)
Date: Tue, 31 Oct 2017 15:05:07 +0100

This is an automated email from the git hooks/post-receive script.

marcello pushed a change to branch master
in repository bank.

    from c04007b  fix #5108
     new 034d177  define db custom type
     new f051ed2  glue new db column to models abstraction
     new 3738190  fix column type
     new fc6a56f  porting the bank to use the new Amount object

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 bank-check.conf                                    |   5 +-
 talerbank/app/Makefile.am                          |   2 +-
 talerbank/app/amount.py                            | 131 +++++++++++++++
 talerbank/app/amounts.py                           | 101 ------------
 talerbank/app/management/commands/dump_talerdb.py  |   2 +-
 .../app/migrations/0002_bankaccount_amount.py      |  21 +++
 .../app/migrations/0003_auto_20171030_1346.py      |  21 +++
 .../app/migrations/0004_auto_20171030_1428.py      |  34 ++++
 .../0005_remove_banktransaction_currency.py        |  19 +++
 .../app/migrations/0006_auto_20171031_0823.py      |  21 +++
 .../app/migrations/0007_auto_20171031_0906.py      |  21 +++
 .../app/migrations/0008_auto_20171031_0938.py      |  31 ++++
 talerbank/app/models.py                            |  75 +++++----
 talerbank/app/static/web-common                    |   2 +-
 talerbank/app/templates/pin_tan.html               |   2 +-
 talerbank/app/templates/profile_page.html          |   2 +-
 talerbank/app/templates/public_accounts.html       |   2 +-
 talerbank/app/tests.py                             | 142 ++++++++--------
 talerbank/app/tests_alt.py                         |  10 +-
 talerbank/app/views.py                             | 178 +++++++++------------
 talerbank/settings.py                              |   6 +-
 21 files changed, 512 insertions(+), 316 deletions(-)
 create mode 100644 talerbank/app/amount.py
 delete mode 100644 talerbank/app/amounts.py
 create mode 100644 talerbank/app/migrations/0002_bankaccount_amount.py
 create mode 100644 talerbank/app/migrations/0003_auto_20171030_1346.py
 create mode 100644 talerbank/app/migrations/0004_auto_20171030_1428.py
 create mode 100644 
talerbank/app/migrations/0005_remove_banktransaction_currency.py
 create mode 100644 talerbank/app/migrations/0006_auto_20171031_0823.py
 create mode 100644 talerbank/app/migrations/0007_auto_20171031_0906.py
 create mode 100644 talerbank/app/migrations/0008_auto_20171031_0938.py

diff --git a/bank-check.conf b/bank-check.conf
index 547dce0..46658e2 100644
--- a/bank-check.conf
+++ b/bank-check.conf
@@ -7,9 +7,10 @@ CURRENCY = KUDOS
 
 # Which database should we use?
 DATABASE = postgres:///talercheck
+NDIGITS = 2
 
 # FIXME
-MAX_DEBT = KUDOS:50
+MAX_DEBT = KUDOS:50.0
 
 # FIXME
-MAX_DEBT_BANK = KUDOS:0
+MAX_DEBT_BANK = KUDOS:0.0
diff --git a/talerbank/app/Makefile.am b/talerbank/app/Makefile.am
index 6376a68..b3efdd7 100644
--- a/talerbank/app/Makefile.am
+++ b/talerbank/app/Makefile.am
@@ -5,7 +5,7 @@ EXTRA_DIST = \
   schemas.py \
   urls.py \
   views.py \
-  amounts.py \
+  amount.py \
   checks.py  \
   __init__.py \
   models.py \
diff --git a/talerbank/app/amount.py b/talerbank/app/amount.py
new file mode 100644
index 0000000..c66691a
--- /dev/null
+++ b/talerbank/app/amount.py
@@ -0,0 +1,131 @@
+#  This file is part of TALER
+#  (C) 2017 TALER SYSTEMS
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License, or (at your option) any later version.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  
USA
+#
+#  @author Marcello Stanisci
+#  @version 0.0
+#  @repository https://git.taler.net/copylib.git/
+#  This code is "copylib", it is versioned under the Git repository
+#  mentioned above, and it is meant to be manually copied into any project
+#  which might need it.
+
+class CurrencyMismatch(Exception):
+    pass
+
+class BadFormatAmount(Exception):
+    def __init__(self, faulty_str):
+        self.faulty_str = faulty_str
+
+class Amount:
+    # How many "fraction" units make one "value" unit of currency
+    # (Taler requires 10^8).  Do not change this 'constant'.
+    @staticmethod
+    def FRACTION():
+        return 10 ** 8
+
+    @staticmethod
+    def MAX_VALUE():
+        return (2 ** 53) - 1
+
+    def __init__(self, currency, value=0, fraction=0):
+        # type: (str, int, int) -> Amount
+        assert(value >= 0 and fraction >= 0)
+        self.value = value
+        self.fraction = fraction
+        self.currency = currency
+        self.__normalize()
+        assert(self.value <= Amount.MAX_VALUE())
+
+    # Normalize amount
+    def __normalize(self):
+        if self.fraction >= Amount.FRACTION():
+            self.value += int(self.fraction / Amount.FRACTION())
+            self.fraction = self.fraction % Amount.FRACTION()
+
+    # Parse a string matching the format "A:B.C"
+    # instantiating an amount object.
+    @classmethod
+    def parse(cls, amount_str):
+        exp = '^\s*([-_*A-Za-z0-9]+):([0-9]+)\.([0-9]+)\s*$'
+        import re
+        parsed = re.search(exp, amount_str)
+        if not parsed:
+            raise BadFormatAmount(amount_str)
+        value = int(parsed.group(2))
+        fraction = 0
+        for i, digit in enumerate(parsed.group(3)):
+            fraction += int(int(digit) * (Amount.FRACTION() / 10 ** (i+1)))
+        return cls(parsed.group(1), value, fraction)
+
+    # Comare two amounts, return:
+    # -1 if a < b
+    # 0 if a == b
+    # 1 if a > b
+    @staticmethod
+    def cmp(a, b):
+        if a.currency != b.currency:
+            raise CurrencyMismatch()
+        if a.value == b.value:
+            if a.fraction < b.fraction:
+                return -1
+            if a.fraction > b.fraction:
+                return 1
+            return 0
+        if a.value < b.value:
+            return -1
+        return 1
+
+    def set(self, currency, value=0, fraction=0):
+        self.currency = currency
+        self.value = value
+        self.fraction = fraction
+
+    # Add the given amount to this one
+    def add(self, a):
+        if self.currency != a.currency:
+            raise CurrencyMismatch()
+        self.value += a.value
+        self.fraction += a.fraction
+        self.__normalize()
+
+    # Subtract passed amount from this one
+    def subtract(self, a):
+        if self.currency != a.currency:
+            raise CurrencyMismatch()
+        if self.fraction < a.fraction:
+            self.fraction += Amount.FRACTION()
+            self.value -= 1
+        if self.value < a.value:
+            raise ValueError('self is lesser than amount to be subtracted')
+        self.value -= a.value
+        self.fraction -= a.fraction
+
+    # Dump string from this amount, will put 'ndigits' numbers
+    # after the dot.
+    def stringify(self, ndigits):
+        assert ndigits > 0
+        ret = '%s:%s.' % (self.currency, str(self.value))
+        f = self.fraction
+        for i in range(0, ndigits):
+            ret += str(int(f / (Amount.FRACTION() / 10)))
+            f = (f * 10) % (Amount.FRACTION())
+        return ret
+
+    # Dump the Taler-compliant 'dict' amount
+    def dump(self):
+        return dict(value=self.value,
+                    fraction=self.fraction,
+                    currency=self.currency)
diff --git a/talerbank/app/amounts.py b/talerbank/app/amounts.py
deleted file mode 100644
index f9bdd02..0000000
--- a/talerbank/app/amounts.py
+++ /dev/null
@@ -1,101 +0,0 @@
-#  This file is part of TALER
-#  (C) 2016 INRIA
-#
-#  TALER is free software; you can redistribute it and/or modify it under the
-#  terms of the GNU Affero General Public License as published by the Free 
Software
-#  Foundation; either version 3, or (at your option) any later version.
-#
-#  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
-#  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
-#  A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License along with
-#  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
-#
-#  @author Marcello Stanisci
-#  @author Florian Dold
-
-
-import re
-import math
-import logging
-from django.conf import settings
-
-logger = logging.getLogger(__name__)
-
-FRACTION = 100000000
-
-class CurrencyMismatchException(Exception):
-    def __init__(self, msg=None, status_code=0):
-        self.msg = msg
-        # HTTP status code to be returned as response for
-        # this exception
-        self.status_code = status_code
-
-class BadFormatAmount(Exception):
-    def __init__(self, msg=None, status_code=0):
-        self.msg = msg
-        # HTTP status code to be returned as response for
-        # this exception
-        self.status_code = status_code
-
-
-def check_currency(a1, a2):
-    if a1["currency"] != a2["currency"]:
-        logger.error("Different currencies given: %s vs %s" % (a1["currency"], 
a2["currency"]))
-        raise CurrencyMismatchException
-
-def get_zero():
-    return dict(value=0, fraction=0, currency=settings.TALER_CURRENCY)
-
-def amount_add(a1, a2):
-    check_currency(a1, a2)
-    a1_float = floatify(a1)
-    a2_float = floatify(a2)
-    return parse_amount("%s:%s" % (a2["currency"], str(a1_float + a2_float)))
-
-def amount_sub(a1, a2):
-    check_currency(a1, a2)
-    a1_float = floatify(a1)
-    a2_float = floatify(a2)
-    sub = a1_float - a2_float
-    fmt = "%s:%s" % (a2["currency"], str(sub))
-    return parse_amount(fmt)
-
-# Return -1 if a1 < a2, 0 if a1 == a2, 1 if a1 > a2
-def amount_cmp(a1, a2):
-    check_currency(a1, a2)
-    a1_float = floatify(a1)
-    a2_float = floatify(a2)
-
-    if a1_float < a2_float:
-        return -1
-    elif a1_float == a2_float:
-        return 0
-
-    return 1
-
-
-def floatify(amount_dict):
-    return amount_dict['value'] + (float(amount_dict['fraction']) / 
float(FRACTION))
-
-def stringify(amount_float, digits=2):
-    o = "".join(["%.", "%sf" % digits])
-    return o % amount_float
-
-def parse_amount(amount_str):
-    """
-    Parse amount of return None if not a
-    valid amount string
-    """
-    parsed = re.search("^\s*([-_*A-Za-z0-9]+):([0-9]+)(\.[0-9]+)?\s*$", 
amount_str)
-    if not parsed:
-        raise BadFormatAmount
-    value = int(parsed.group(2))
-    fraction = 0
-    if parsed.group(3) is not None:
-        for i, digit in enumerate(parsed.group(3)[1:]):
-            fraction += int(int(digit) * (FRACTION / 10 ** (i+1)))
-    return {'value': value,
-            'fraction': fraction,
-            'currency': parsed.group(1)}
diff --git a/talerbank/app/management/commands/dump_talerdb.py 
b/talerbank/app/management/commands/dump_talerdb.py
index ab587d9..b4a93fc 100644
--- a/talerbank/app/management/commands/dump_talerdb.py
+++ b/talerbank/app/management/commands/dump_talerdb.py
@@ -50,7 +50,7 @@ def dump_history():
             # as the first/last character on a line makes flake8 complain
             msg.append("+%s, " % item.credit_account.account_no)
             msg.append("-%s, " % item.debit_account.account_no)
-            msg.append("%.2f, " % floatify(item.amount_obj))
+            msg.append(item.amount.stringify(2))
             msg.append(item.subject)
             print(''.join(msg))
     except (OperationalError, ProgrammingError):
diff --git a/talerbank/app/migrations/0002_bankaccount_amount.py 
b/talerbank/app/migrations/0002_bankaccount_amount.py
new file mode 100644
index 0000000..beaa1d8
--- /dev/null
+++ b/talerbank/app/migrations/0002_bankaccount_amount.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-10-30 13:23
+from __future__ import unicode_literals
+
+from django.db import migrations
+import talerbank.app.models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('app', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='bankaccount',
+            name='amount',
+            field=talerbank.app.models.AmountField(default=False),
+        ),
+    ]
diff --git a/talerbank/app/migrations/0003_auto_20171030_1346.py 
b/talerbank/app/migrations/0003_auto_20171030_1346.py
new file mode 100644
index 0000000..91c6cb9
--- /dev/null
+++ b/talerbank/app/migrations/0003_auto_20171030_1346.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-10-30 13:46
+from __future__ import unicode_literals
+
+from django.db import migrations
+import talerbank.app.models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('app', '0002_bankaccount_amount'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='bankaccount',
+            name='amount',
+            field=talerbank.app.models.AmountField(),
+        ),
+    ]
diff --git a/talerbank/app/migrations/0004_auto_20171030_1428.py 
b/talerbank/app/migrations/0004_auto_20171030_1428.py
new file mode 100644
index 0000000..b93ebd4
--- /dev/null
+++ b/talerbank/app/migrations/0004_auto_20171030_1428.py
@@ -0,0 +1,34 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-10-30 14:28
+from __future__ import unicode_literals
+
+from django.db import migrations
+import talerbank.app.models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('app', '0003_auto_20171030_1346'),
+    ]
+
+    operations = [
+        migrations.RemoveField(
+            model_name='banktransaction',
+            name='amount_fraction',
+        ),
+        migrations.RemoveField(
+            model_name='banktransaction',
+            name='amount_value',
+        ),
+        migrations.AddField(
+            model_name='banktransaction',
+            name='amount',
+            field=talerbank.app.models.AmountField(default=False),
+        ),
+        migrations.AlterField(
+            model_name='bankaccount',
+            name='amount',
+            field=talerbank.app.models.AmountField(default=False),
+        ),
+    ]
diff --git a/talerbank/app/migrations/0005_remove_banktransaction_currency.py 
b/talerbank/app/migrations/0005_remove_banktransaction_currency.py
new file mode 100644
index 0000000..9cd781f
--- /dev/null
+++ b/talerbank/app/migrations/0005_remove_banktransaction_currency.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-10-30 14:37
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('app', '0004_auto_20171030_1428'),
+    ]
+
+    operations = [
+        migrations.RemoveField(
+            model_name='banktransaction',
+            name='currency',
+        ),
+    ]
diff --git a/talerbank/app/migrations/0006_auto_20171031_0823.py 
b/talerbank/app/migrations/0006_auto_20171031_0823.py
new file mode 100644
index 0000000..67c1a70
--- /dev/null
+++ b/talerbank/app/migrations/0006_auto_20171031_0823.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-10-31 08:23
+from __future__ import unicode_literals
+
+from django.db import migrations
+import talerbank.app.models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('app', '0005_remove_banktransaction_currency'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='bankaccount',
+            name='amount',
+            field=talerbank.app.models.AmountField(default=None),
+        ),
+    ]
diff --git a/talerbank/app/migrations/0007_auto_20171031_0906.py 
b/talerbank/app/migrations/0007_auto_20171031_0906.py
new file mode 100644
index 0000000..923cff2
--- /dev/null
+++ b/talerbank/app/migrations/0007_auto_20171031_0906.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-10-31 09:06
+from __future__ import unicode_literals
+
+from django.db import migrations
+import talerbank.app.models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('app', '0006_auto_20171031_0823'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='bankaccount',
+            name='amount',
+            
field=talerbank.app.models.AmountField(default=talerbank.app.models.get_zero_amount),
+        ),
+    ]
diff --git a/talerbank/app/migrations/0008_auto_20171031_0938.py 
b/talerbank/app/migrations/0008_auto_20171031_0938.py
new file mode 100644
index 0000000..3b97829
--- /dev/null
+++ b/talerbank/app/migrations/0008_auto_20171031_0938.py
@@ -0,0 +1,31 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-10-31 09:38
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('app', '0007_auto_20171031_0906'),
+    ]
+
+    operations = [
+        migrations.RemoveField(
+            model_name='bankaccount',
+            name='balance',
+        ),
+        migrations.RemoveField(
+            model_name='bankaccount',
+            name='balance_fraction',
+        ),
+        migrations.RemoveField(
+            model_name='bankaccount',
+            name='balance_value',
+        ),
+        migrations.RemoveField(
+            model_name='bankaccount',
+            name='currency',
+        ),
+    ]
diff --git a/talerbank/app/models.py b/talerbank/app/models.py
index 868b0d6..ebbb9f0 100644
--- a/talerbank/app/models.py
+++ b/talerbank/app/models.py
@@ -18,40 +18,56 @@
 from __future__ import unicode_literals
 from django.contrib.auth.models import User
 from django.db import models
+from django.conf import settings
+from . import amount
 
+class AmountField(models.Field):
+    
+    description = 'Amount object in Taler style'
+    
+    def __init__(self, *args, **kwargs):
+        super(AmountField, self).__init__(*args, **kwargs)
+
+    def deconstruct(self):
+        name, path, args, kwargs = super(AmountField, self).deconstruct()
+        return name, path, args, kwargs
+
+    def db_type(self, connection):
+        return "varchar"
+
+    # Pass stringified object to db connector
+    def get_prep_value(self, value):
+        if not value:
+            return "%s:0.0" % settings.TALER_CURRENCY
+        return value.stringify(settings.TALER_DIGITS)
+
+    def from_db_value(self, value, expression, connection, context):
+        if None is value:
+            return amount.Amount.parse(settings.TALER_CURRENCY)
+        return amount.Amount.parse(value)
+
+    def to_python(self, value):
+        if isinstance(value, amount.Amount):
+            return value
+        try:
+            if None is value:
+                return amount.Amount.parse(settings.TALER_CURRENCY)
+            return amount.Amount.parse(value)
+        except amount.BadAmount:
+            raise models.ValidationError()
+
+def get_zero_amount():
+    return amount.Amount(settings.TALER_CURRENCY)
 
 class BankAccount(models.Model):
     is_public = models.BooleanField(default=False)
-    # Handier than keeping the amount signed, for two reasons:
-    # (1) checking if someone is in debt is less verbose: with signed
-    # amounts we have to check if the amount is less than zero; this
-    # way we only check if a boolean is true. (2) The bank logic is
-    # ready to welcome a data type for amounts which doesn't have any
-    # sign notion, like Taler amounts do.
     debit = models.BooleanField(default=False)
-    balance_value = models.IntegerField(default=0)
-    balance_fraction = models.IntegerField(default=0)
-    # From today's (16/10/2017) Mumble talk, it emerged that bank shouldn't
-    # store amounts as floats, but: normal banks should not care about
-    # Taler when representing values around in their databases..
-    balance = models.FloatField(default=0)
-    currency = models.CharField(max_length=12, default="")
     account_no = models.AutoField(primary_key=True)
     user = models.OneToOneField(User, on_delete=models.CASCADE)
-    def _get_balance(self):
-        return dict(value=self.balance_value,
-                    fraction=self.balance_fraction,
-                    currency=self.currency)
-    def _set_balance(self, amount):
-        self.balance_value = amount["value"]
-        self.balance_fraction = amount["fraction"]
-        self.currency = amount["currency"]
-    balance_obj = property(_get_balance, _set_balance)
+    amount = AmountField(default=get_zero_amount)
 
 class BankTransaction(models.Model):
-    amount_value = models.IntegerField(default=0)
-    amount_fraction = models.IntegerField(default=0)
-    currency = models.CharField(max_length=12)
+    amount = AmountField(default=False)
     debit_account = models.ForeignKey(BankAccount,
                                       on_delete=models.CASCADE,
                                       related_name="debit_account")
@@ -60,12 +76,3 @@ class BankTransaction(models.Model):
                                        related_name="credit_account")
     subject = models.CharField(default="(no subject given)", max_length=200)
     date = models.DateTimeField(auto_now=True)
-    def _get_amount(self):
-        return dict(value=self.amount_value,
-                    fraction=self.amount_fraction,
-                    currency=self.currency)
-    def _set_amount(self, amount):
-        self.amount_value = amount["value"]
-        self.amount_fraction = amount["fraction"]
-        self.currency = amount["currency"]
-    amount_obj = property(_get_amount, _set_amount)
diff --git a/talerbank/app/static/web-common b/talerbank/app/static/web-common
index d7e0135..489a9e3 160000
--- a/talerbank/app/static/web-common
+++ b/talerbank/app/static/web-common
@@ -1 +1 @@
-Subproject commit d7e013594d15388b1a7342a44a0e9c8d4ecca82d
+Subproject commit 489a9e38e6960fdce309ab8cf5ff66d930ecb3bc
diff --git a/talerbank/app/templates/pin_tan.html 
b/talerbank/app/templates/pin_tan.html
index b545524..0855b3b 100644
--- a/talerbank/app/templates/pin_tan.html
+++ b/talerbank/app/templates/pin_tan.html
@@ -31,7 +31,7 @@
   {% endif %}
   <p>
     {{ settings_value("TALER_CURRENCY") }} Bank needs to verify that you
-    intend to withdraw <b>{{ amount }} {{ settings_value("TALER_CURRENCY") 
}}</b> from
+    intend to withdraw <b>{{ amount }}</b> from
     <b>{{ exchange }}</b>.
     To prove that you are the account owner, please answer the
     following &quot;security question&quot; (*):
diff --git a/talerbank/app/templates/profile_page.html 
b/talerbank/app/templates/profile_page.html
index c64f215..ad8345d 100644
--- a/talerbank/app/templates/profile_page.html
+++ b/talerbank/app/templates/profile_page.html
@@ -125,7 +125,7 @@
           <tr>
             <td style="text-align:right">{{ item.date }}</td>
            <td style="text-align:right">
-              {{ item.float_amount }} {{ item.float_currency }}
+              {{ item.sign }} {{ item.amount }}
             </td>
            <td class="text-align:left">{% if item.counterpart_username %} {{ 
item.counterpart_username }} {% endif %} (account #{{ item.counterpart }})</td>
            <td class="text-align:left">{{ item.subject }}</td>
diff --git a/talerbank/app/templates/public_accounts.html 
b/talerbank/app/templates/public_accounts.html
index 2f38489..3c5b53e 100644
--- a/talerbank/app/templates/public_accounts.html
+++ b/talerbank/app/templates/public_accounts.html
@@ -54,7 +54,7 @@
           <tr>
             <td>{{entry.date}}</td>
             <td>
-              {{ entry.float_amount }} {{ entry.float_currency }}
+              {{ sign }} {{ entry.amount }}
             </td>
             <td>{% if entry.counterpart_username %} {{ 
entry.counterpart_username }} {% endif %} (account #{{ entry.counterpart 
}})</td>
             <td>
diff --git a/talerbank/app/tests.py b/talerbank/app/tests.py
index feff213..435fd7d 100644
--- a/talerbank/app/tests.py
+++ b/talerbank/app/tests.py
@@ -20,9 +20,9 @@ from django.conf import settings
 from django.contrib.auth.models import User
 from .models import BankAccount, BankTransaction
 from . import urls
-from . import amounts
 from .views import wire_transfer
 import json
+from .amount import Amount, CurrencyMismatch, BadFormatAmount
 
 import logging
 
@@ -39,7 +39,7 @@ class RegisterTestCase(TestCase):
 
     def setUp(self):
         bank = User.objects.create_user(username='Bank')
-        ba = BankAccount(user=bank, currency=settings.TALER_CURRENCY)
+        ba = BankAccount(user=bank)
         ba.account_no = 1
         ba.save() 
 
@@ -62,8 +62,8 @@ class RegisterWrongCurrencyTestCase(TestCase):
 
     # Activating this user with a faulty currency.
     def setUp(self):
-        bank = User.objects.create_user(username='Bank')
-        ba = BankAccount(user=bank, currency="XYZ")
+        ba = BankAccount(user=User.objects.create_user(username='Bank'),
+            amount=Amount('WRONGCURRENCY'))
         ba.account_no = 1
         ba.save() 
 
@@ -88,8 +88,7 @@ class LoginTestCase(TestCase):
     def setUp(self):
         user = User.objects.create_user(username="test_user",
                                         password="test_password")
-        user_account = BankAccount(user=user,
-                                   currency=settings.TALER_CURRENCY)
+        user_account = BankAccount(user=user)
         user_account.save()
 
     def tearDown(self):
@@ -116,20 +115,21 @@ class LoginTestCase(TestCase):
 class AmountTestCase(TestCase):
     
     def test_cmp(self):
-        a1 = dict(value=1, fraction=0, currency="X")
-        _a1 = dict(value=1, fraction=0, currency="X")
-        a2 = dict(value=2, fraction=0, currency="X")
-        self.assertEqual(-1, amounts.amount_cmp(a1, a2))
-        self.assertEqual(1, amounts.amount_cmp(a2, a1))
-        self.assertEqual(0, amounts.amount_cmp(a1, _a1))
+        a1 = Amount("X", 1)
+        _a1 = Amount("X", 1)
+        a2 = Amount("X", 2)
+        
+        self.assertEqual(-1, Amount.cmp(a1, a2))
+        self.assertEqual(1, Amount.cmp(a2, a1))
+        self.assertEqual(0, Amount.cmp(a1, _a1))
 
     # Trying to compare amount of different currencies
     def test_cmp_diff_curr(self):
-        a1 = dict(value=1, fraction=0, currency="X")
-        a2 = dict(value=2, fraction=0, currency="Y")
+        a1 = Amount("X", 1)
+        a2 = Amount("Y", 2)
         try:
-            amounts.amount_cmp(a1, a2)
-        except amounts.CurrencyMismatchException:
+            Amount.cmp(a1, a2)
+        except CurrencyMismatch:
             self.assertTrue(True)
             return
         # Should never get here
@@ -140,14 +140,12 @@ class AddIncomingTestCase(TestCase):
     """Test money transfer's API"""
 
     def setUp(self):
-        bank = User.objects.create_user(username="bank_user",
-                                        password="bank_password")
-        bank_account = BankAccount(user=bank,
-                                   currency=settings.TALER_CURRENCY)
-        user = User.objects.create_user(username="user_user",
-                                        password="user_password")
-        user_account = BankAccount(user=user,
-                                   currency=settings.TALER_CURRENCY)
+        bank_account = BankAccount(user=User.objects.create_user(
+            username="bank_user",
+            password="bank_password"))
+        user_account = BankAccount(user=User.objects.create_user(
+            username="user_user",
+            password="user_password"))
         bank_account.save()
         user_account.save()
 
@@ -206,22 +204,22 @@ class HistoryTestCase(TestCase):
 
     def setUp(self):
         user = User.objects.create_user(username='User', password="Password")
-        ub = BankAccount(user=user, currency=settings.TALER_CURRENCY)
+        ub = BankAccount(user=user, amount=Amount(settings.TALER_CURRENCY, 
100))
         ub.account_no = 1
-        ub.balance_obj = dict(value=100, fraction=0, 
currency=settings.TALER_CURRENCY)
         ub.save() 
         user_passive = User.objects.create_user(username='UserP', 
password="PasswordP")
-        ub_p = BankAccount(user=user_passive, currency=settings.TALER_CURRENCY)
+        ub_p = BankAccount(user=user_passive)
         ub_p.account_no = 2
         ub_p.save() 
-        wire_transfer(dict(value=1, fraction=0, 
currency=settings.TALER_CURRENCY), ub, ub_p, subject="a")
-        wire_transfer(dict(value=1, fraction=0, 
currency=settings.TALER_CURRENCY), ub, ub_p, subject="b")
-        wire_transfer(dict(value=1, fraction=0, 
currency=settings.TALER_CURRENCY), ub, ub_p, subject="c")
-        wire_transfer(dict(value=1, fraction=0, 
currency=settings.TALER_CURRENCY), ub, ub_p, subject="d")
-        wire_transfer(dict(value=1, fraction=0, 
currency=settings.TALER_CURRENCY), ub, ub_p, subject="e")
-        wire_transfer(dict(value=1, fraction=0, 
currency=settings.TALER_CURRENCY), ub, ub_p, subject="f")
-        wire_transfer(dict(value=1, fraction=0, 
currency=settings.TALER_CURRENCY), ub, ub_p, subject="g")
-        wire_transfer(dict(value=1, fraction=0, 
currency=settings.TALER_CURRENCY), ub, ub_p, subject="h")
+        one = Amount(settings.TALER_CURRENCY, 1)
+        wire_transfer(one, ub, ub_p, subject="a")
+        wire_transfer(one, ub, ub_p, subject="b")
+        wire_transfer(one, ub, ub_p, subject="c")
+        wire_transfer(one, ub, ub_p, subject="d")
+        wire_transfer(one, ub, ub_p, subject="e")
+        wire_transfer(one, ub, ub_p, subject="f")
+        wire_transfer(one, ub, ub_p, subject="g")
+        wire_transfer(one, ub, ub_p, subject="h")
 
     def tearDown(self):
         clearDb()
@@ -267,16 +265,34 @@ class HistoryTestCase(TestCase):
                          **{"HTTP_X_TALER_BANK_USERNAME": "User", 
"HTTP_X_TALER_BANK_PASSWORD": "Password"})
         self.assertEqual(404, response.status_code)
 
+class DBAmountSubtraction(TestCase):
+    def setUp(self):
+        a = BankAccount(user=User.objects.create_user(username='U'),
+            amount=Amount(settings.TALER_CURRENCY, 3))
+        a.save()
+    
+    def test_subtraction(self):
+        a = BankAccount.objects.get(user=User.objects.get(username='U'))
+        a.amount.subtract(Amount(settings.TALER_CURRENCY, 2))
+        self.assertEqual(0, Amount.cmp(Amount(settings.TALER_CURRENCY, 1), 
a.amount))
+
+
+class DBCustomColumnTestCase(TestCase):
+
+    def setUp(TestCase):
+        a = BankAccount(user=User.objects.create_user(username='U'))
+        a.save()
+
+    def test_exists(self):
+        a = BankAccount.objects.get(user=User.objects.get(username='U'))
+        self.assertTrue(isinstance(a.amount, Amount))
 
 # This tests whether a bank account goes debit and then goes >=0  again
 class DebitTestCase(TestCase):
 
     def setUp(self):
-        u = User.objects.create_user(username='U')
-        u0 = User.objects.create_user(username='U0')
-        ua = BankAccount(user=u, currency=settings.TALER_CURRENCY)
-        u0a = BankAccount(user=u0, currency=settings.TALER_CURRENCY)
-
+        ua = BankAccount(user=User.objects.create_user(username='U'))
+        u0a = BankAccount(user=User.objects.create_user(username='U0'))
         ua.save()
         u0a.save()
 
@@ -286,46 +302,40 @@ class DebitTestCase(TestCase):
         self.assertEqual(False, ub.debit)
 
     def test_red(self):
-        u = User.objects.get(username='U')
-        u0 = User.objects.get(username='U0')
-
-        ub = BankAccount.objects.get(user=u)
-        ub0 = BankAccount.objects.get(user=u0)
+        ub = BankAccount.objects.get(user=User.objects.get(username='U'))
+        ub0 = BankAccount.objects.get(user=User.objects.get(username='U0'))
 
-        wire_transfer(dict(value=10, fraction=0, 
currency=settings.TALER_CURRENCY),
+        wire_transfer(Amount(settings.TALER_CURRENCY, 10, 0),
                       ub0,
                       ub,
                       "Go green")
-        tmp = amounts.get_zero()
-        tmp["value"] = 10
+        tmp = Amount(settings.TALER_CURRENCY, 10)
+        self.assertEqual(0, Amount.cmp(ub.amount, tmp))
+        self.assertEqual(0, Amount.cmp(ub0.amount, tmp))
+        self.assertFalse(ub.debit)
 
-        self.assertEqual(0, amounts.amount_cmp(ub.balance_obj, tmp))
-        self.assertEqual(False, ub.debit)
-        self.assertEqual(True, ub0.debit)
+        self.assertTrue(ub0.debit)
 
-        wire_transfer(dict(value=11, fraction=0, 
currency=settings.TALER_CURRENCY),
+        wire_transfer(Amount(settings.TALER_CURRENCY, 11),
                       ub,
                       ub0,
                       "Go red")
 
-        self.assertEqual(True, ub.debit)
-        self.assertEqual(False, ub0.debit)
-
-        tmp["value"] = 1
-
-        self.assertEqual(0, amounts.amount_cmp(ub0.balance_obj, tmp))
+        tmp.value = 1
+        self.assertTrue(ub.debit)
+        self.assertFalse(ub0.debit)
+        self.assertEqual(0, Amount.cmp(ub.amount, tmp))
+        self.assertEqual(0, Amount.cmp(ub0.amount, tmp))
 
 class ParseAmountTestCase(TestCase):
      def test_parse_amount(self):
-         ret = amounts.parse_amount("KUDOS:4")
-         self.assertJSONEqual('{"value": 4, "fraction": 0, "currency": 
"KUDOS"}', json.dumps(ret))
-         ret = amounts.parse_amount("KUDOS:4.00")
-         self.assertJSONEqual('{"value": 4, "fraction": 0, "currency": 
"KUDOS"}', json.dumps(ret))
-         ret = amounts.parse_amount("KUDOS:4.3")
-         self.assertJSONEqual('{"value": 4, "fraction": 30000000, "currency": 
"KUDOS"}', json.dumps(ret))
+         ret = Amount.parse("KUDOS:4.0")
+         self.assertJSONEqual('{"value": 4, "fraction": 0, "currency": 
"KUDOS"}', ret.dump())
+         ret = Amount.parse("KUDOS:4.3")
+         self.assertJSONEqual('{"value": 4, "fraction": 30000000, "currency": 
"KUDOS"}', ret.dump())
          try:
-             amounts.parse_amount("Buggy")
-         except amounts.BadFormatAmount:
+             Amount.parse("Buggy")
+         except BadFormatAmount:
              return
          # make sure the control doesn't get here
          self.assertEqual(True, False)
diff --git a/talerbank/app/tests_alt.py b/talerbank/app/tests_alt.py
index cf782d1..4ab9b65 100644
--- a/talerbank/app/tests_alt.py
+++ b/talerbank/app/tests_alt.py
@@ -20,7 +20,7 @@ from django.conf import settings
 from django.contrib.auth.models import User
 from .models import BankAccount, BankTransaction
 from . import urls
-from . import amounts
+from .amount import Amount, BadFormatAmount
 from .views import wire_transfer
 import json
 
@@ -35,13 +35,13 @@ class BadDatabaseStringTestCase(TestCase):
 class BadMaxDebtOptionTestCase(TestCase):
     def test_badmaxdebtoption(self):
         try:
-            amounts.parse_amount(settings.TALER_MAX_DEBT)
-        except amounts.BadFormatAmount:
+            Amount.parse(settings.TALER_MAX_DEBT)
+        except BadFormatAmount:
             self.assertTrue(True)
             return
         try:
-            amounts.parse_amount(settings.TALER_MAX_DEBT_BANK)
-        except amounts.BadFormatAmount:
+            Amount.parse(settings.TALER_MAX_DEBT_BANK)
+        except BadFormatAmount:
             self.assertTrue(True)
             return
         # Force to have at least one bad amount in config
diff --git a/talerbank/app/views.py b/talerbank/app/views.py
index 45328f8..fd6f570 100644
--- a/talerbank/app/views.py
+++ b/talerbank/app/views.py
@@ -37,9 +37,9 @@ import time
 import hashlib
 import requests
 from urllib.parse import urljoin
-from . import amounts
 from . import schemas
 from .models import BankAccount, BankTransaction
+from .amount import Amount, CurrencyMismatch, BadFormatAmount
 
 logger = logging.getLogger(__name__)
 
@@ -98,9 +98,9 @@ def profile_page(request):
 
     context = dict(
         name=user_account.user.username,
-        balance=amounts.stringify(amounts.floatify(user_account.balance_obj)),
+        balance=user_account.amount.stringify(settings.TALER_DIGITS),
         sign = "-" if user_account.debit else "",
-        currency=user_account.currency,
+        currency=user_account.amount.currency,
         precision=settings.TALER_DIGITS,
         account_no=user_account.account_no,
         history=history,
@@ -149,9 +149,9 @@ def pin_tan_question(request):
         currency = request.GET.get("amount_currency", None)
     except ValueError:
         return HttpResponseBadRequest("invalid parameters: \"amount_currency\" 
not given")
-    amount = {"value": value,
-              "fraction": fraction,
-              "currency": currency}
+    if currency != settings.TALER_CURRENCY:
+        return HttpResponse("Such currency (%s) is not accepted" % currency, 
status=422)
+    amount = Amount(currency, value, fraction)
     user_account = BankAccount.objects.get(user=request.user)
     wiredetails = json.loads(request.GET["wire_details"])
     if not isinstance(wiredetails, dict) or "test" not in wiredetails:
@@ -160,7 +160,6 @@ def pin_tan_question(request):
                 "The exchange does not seem to support it.")
     try:
         schemas.validate_wiredetails(wiredetails)
-        schemas.validate_amount(amount)
     except ValueError as error:
         return HttpResponseBadRequest("invalid parameters (%s)" % error)
     # parameters we store in the session are (more or less) validated
@@ -176,7 +175,7 @@ def pin_tan_question(request):
     previous_failed = get_session_flag(request, "captcha_failed")
     context = dict(
         form=Pin(auto_id=False),
-        amount=amounts.floatify(amount),
+        amount=amount.stringify(settings.TALER_DIGITS),
         previous_failed=previous_failed,
         exchange=request.GET["exchange"],
     )
@@ -223,7 +222,7 @@ def pin_tan_verify(request):
             sender_account_details=sender_wiredetails,
              # just something unique
             transfer_details=dict(timestamp=int(time.time() * 1000)),
-            amount=amount,
+            amount=amount.dump(),
     )
     user_account = BankAccount.objects.get(user=request.user)
     exchange_account = 
BankAccount.objects.get(account_no=exchange_account_number)
@@ -233,13 +232,16 @@ def pin_tan_verify(request):
         logger.warning("Withdrawal impossible due to debt limit exceeded")
         request.session["debt_limit"] = True
         return redirect("profile")
-    except amounts.BadFormatAmount as e:
-        return HttpResponse(e.msg, status=e.status_code) 
-    except amounts.CurrencyMismatchException as e:
-        return HttpResponse(e.msg, status=e.status_code) 
     except SameAccountException:
         logger.error("Odd situation: SameAccountException should NOT occur in 
this function")
-        return HttpResponse("internal server error", status=500)
+    except BadFormatAmount:
+        logger.error("parsing MAX_DEBT or MAX_BANK_DEBT failed")
+    except CurrencyMismatch:
+        # The only currency mismatch which can occur here is
+        # between the bank and credit/debit accounts', should
+        # never happen.
+        return HttpResponse("Internal server error", status=500) 
+
 
     request_url = urljoin(exchange_url, "admin/add/incoming")
     res = requests.post(request_url, json=json_body)
@@ -273,22 +275,25 @@ def register(request):
         return render(request, "register.html", dict(not_available=True))
     with transaction.atomic():
         user = User.objects.create_user(username=username, password=password)
-        user_account = BankAccount(user=user, currency=settings.TALER_CURRENCY)
+        user_account = BankAccount(user=user)
         user_account.save()
     bank_internal_account = BankAccount.objects.get(account_no=1)
-    amount = dict(value=100, fraction=0, currency=settings.TALER_CURRENCY)
+    print('bank_internal_account currency: ' + 
bank_internal_account.amount.currency)
     try:
-        wire_transfer(amount, bank_internal_account, user_account, "Joining 
bonus")
+        wire_transfer(Amount(settings.TALER_CURRENCY, 100, 0), 
bank_internal_account, user_account, "Joining bonus")
     except DebtLimitExceededException:
         logger.info("Debt situation encountered")
         request.session["no_initial_bonus"] = True
-    except amounts.CurrencyMismatchException as e:
-        return HttpResponse(e.msg, status=e.status_code)
-    except amounts.BadFormatAmount as e:
-        return HttpResponse(e.msg, status=e.status_code)
+        return HttpResponseServerError()
+    except CurrencyMismatch:
+        logger.error("Currency mismatch internal to the bank")
+        return HttpResponseServerError()
+    except BadFormatAmount:
+        logger.error("Could not parse MAX_DEBT|MAX_BANK_DEBT")
+        return HttpResponseServerError()
     except SameAccountException:
         logger.error("Odd situation: SameAccountException should NOT occur in 
this function")
-        return HttpResponse("internal server error", status=500)
+        return HttpResponseServerError()
         
     request.session["just_registered"] = True
     user = django.contrib.auth.authenticate(username=username, 
password=password)
@@ -312,13 +317,13 @@ def extract_history(account):
     for item in related_transactions:
         if item.credit_account == account:
             counterpart = item.debit_account
-            sign = 1
+            sign = ""
         else:
             counterpart = item.credit_account
-            sign = -1
+            sign = "-"
         entry = dict(
-            float_amount=amounts.stringify(amounts.floatify(item.amount_obj) * 
sign),
-            float_currency=item.currency,
+            sign = sign,
+            amount = item.amount.stringify(settings.TALER_DIGITS),
             counterpart=counterpart.account_no,
             counterpart_username=counterpart.user.username,
             subject=item.subject,
@@ -421,7 +426,7 @@ def history(request):
             counterpart = entry.debit_account.account_no
             sign_ = "+"
         history.append(dict(counterpart=counterpart,
-                            amount=entry.amount_obj,
+                            amount=entry.amount.dump(),
                             sign=sign_,
                             wt_subject=entry.subject,
                             row_id=entry.id,
@@ -484,29 +489,37 @@ def add_incoming(request):
     except BankAccount.DoesNotExist:
         return HttpResponse(status=404)
     try:
-        transaction = wire_transfer(data["amount"],
+        schemas.validate_amount(data["amount"])
+        if settings.TALER_CURRENCY != data["amount"]["currency"]:
+            logger.error("Currency differs from bank's")
+            return JsonResponse(dict(error="Currency differs from bank's"), 
status=406)
+        transaction = wire_transfer(Amount(**data["amount"]),
                                     user_account.bankaccount,
                                     credit_account,
                                     subject)
         return JsonResponse(dict(serial_id=transaction.id, 
timestamp="/Date(%s)/" % int(transaction.date.timestamp())))
-    except amounts.BadFormatAmount as e:
-        return JsonResponse(dict(error=e.msg), status=e.status_code)
+    except ValueError as e:
+        return JsonResponse(dict(error=e), status=400)
+
+    except BadFormatAmount:
+        logger("Bad MAX_DEBT|MAX_BANK_DEBT format")
+    except CurrencyMismatch:
+        logger.error("Internal currency inconsistency")
+        return JsonResponse(dict(error="Internal server error"), status=500)
     except SameAccountException:
         return JsonResponse(dict(error="debit and credit account are the 
same"), status=422)
     except DebtLimitExceededException:
         logger.info("Prevenetd transfer, debit account would go beyond debt 
threshold")
         return JsonResponse(dict(error="debit count has reached its debt 
limit", status=403 ),
                              status=403)
-    except amounts.CurrencyMismatchException as e:
-        return JsonResponse(dict(error=e.msg), status=e.status_code)
 
 @login_required
 @require_POST
 def withdraw_nojs(request):
 
     try:
-        amount = amounts.parse_amount(request.POST.get("kudos_amount", ""))
-    except amounts.BadFormatAmount:
+        amount = Amount.parse(request.POST.get("kudos_amount", ""))
+    except BadFormatAmount:
         logger.error("Amount did not pass parsing")
         return HttpResponseBadRequest()
 
@@ -516,7 +529,7 @@ def withdraw_nojs(request):
     response["X-Taler-Operation"] = "create-reserve"
     response["X-Taler-Callback-Url"] = reverse("pin-question")
     response["X-Taler-Wt-Types"] = '["test"]'
-    response["X-Taler-Amount"] = json.dumps(amount)
+    response["X-Taler-Amount"] = amount.stringify(settings.TALER_CURRENCY)
     response["X-Taler-Sender-Wire"] = json.dumps(dict(
         type="test",
         bank_uri=request.build_absolute_uri(reverse("index")),
@@ -527,81 +540,48 @@ def withdraw_nojs(request):
     return response
 
 
-def wire_transfer(amount,
-                  debit_account,
-                  credit_account,
-                  subject):
+def wire_transfer(amount, debit_account, credit_account, subject):
     if debit_account.pk == credit_account.pk:
         logger.error("Debit and credit account are the same!")
         raise SameAccountException()
 
-    transaction_item = BankTransaction(amount_value=amount["value"],
-                                       amount_fraction=amount["fraction"],
-                                       currency=amount["currency"],
+    transaction_item = BankTransaction(amount=amount,
                                        credit_account=credit_account,
                                        debit_account=debit_account,
                                        subject=subject)
-
-    try:
-        if debit_account.debit:
-            debit_account.balance_obj = 
amounts.amount_add(debit_account.balance_obj,
-                                                           amount)
-    
-        elif -1 == amounts.amount_cmp(debit_account.balance_obj, amount):
-            debit_account.debit = True
-            debit_account.balance_obj = amounts.amount_sub(amount,
-                                                           
debit_account.balance_obj)
-        else:
-            debit_account.balance_obj = 
amounts.amount_sub(debit_account.balance_obj,
-                                                           amount)
-
-        if False == credit_account.debit:
-            credit_account.balance_obj = 
amounts.amount_add(credit_account.balance_obj,
-                                                            amount)
-    
-        elif 1 == amounts.amount_cmp(amount, credit_account.balance_obj):
-            credit_account.debit = False
-            credit_account.balance_obj = amounts.amount_sub(amount,
-                                                            
credit_account.balance_obj)
-        else:
-            credit_account.balance_obj = 
amounts.amount_sub(credit_account.balance_obj,
-                                                            amount)
-    except amounts.CurrencyMismatchException:
-        msg = "The amount to be transferred (%s) doesn't match the bank's 
currency (%s)" % (amount["currency"], settings.TALER_CURRENCY)
-        status_code = 406
-        if settings.TALER_CURRENCY != credit_account.balance_obj["currency"]:
-            logger.error("Internal inconsistency: credit account's currency 
(%s) differs from bank's (%s)" % (credit_account.balance_obj["currency"], 
settings.TALER_CURRENCY))
-            msg = "Internal server error"
-            status_code = 500
-        elif settings.TALER_CURRENCY != debit_account.balance_obj["currency"]:
-            logger.error("Internal inconsistency: debit account's currency 
(%s) differs from bank's (%s)" % (debit_account.balance_obj["currency"], 
settings.TALER_CURRENCY))
-            msg = "Internal server error"
-            status_code = 500
-        logger.error(msg)
-        raise amounts.CurrencyMismatchException(msg=msg, 
status_code=status_code)
+    if debit_account.debit:
+        debit_account.amount.add(amount)
+   
+    elif -1 == Amount.cmp(debit_account.amount, amount):
+        debit_account.debit = True
+        tmp = Amount(**amount.dump())
+        tmp.subtract(debit_account.amount)
+        debit_account.amount.set(**tmp.dump())
+    else:
+        debit_account.amount.subtract(amount)
+
+    if not credit_account.debit:
+        credit_account.amount.add(amount)
+    elif 1 == Amount.cmp(amount, credit_account.amount):
+        credit_account.debit = False
+        tmp = Amount(**amount.dump())
+        tmp.subtract(credit_account.amount)
+        credit_account.amount.set(**tmp.dump())
+    else:
+        credit_account.amount.subtract(amount)
 
     # Check here if any account went beyond the allowed
     # debit threshold.
 
-    try:
-        threshold = amounts.parse_amount(settings.TALER_MAX_DEBT)
-
-        if debit_account.user.username == "Bank":
-            threshold = amounts.parse_amount(settings.TALER_MAX_DEBT_BANK)
-    except amounts.BadFormatAmount:
-        logger.error("MAX_DEBT|MAX_DEBT_BANK had the wrong format")
-        raise amounts.BadFormatAmount(msg="internal server error", 
status_code=500)
-
-    try:
-        if 1 == amounts.amount_cmp(debit_account.balance_obj, threshold) \
-           and 0 != amounts.amount_cmp(amounts.get_zero(), threshold) \
-           and debit_account.debit:
-            logger.info("Negative balance '%s' not allowed." % 
json.dumps(debit_account.balance_obj))
-            logger.info("%s's threshold is: '%s'." % 
(debit_account.user.username, json.dumps(threshold)))
-            raise DebtLimitExceededException()
-    except amounts.CurrencyMismatchException:
-        logger.error("(Internal) currency mismatch between debt threshold and 
debit account")
-        raise amounts.CurrencyMismatchException(msg="internal server error", 
status_code=500)
+    threshold = Amount.parse(settings.TALER_MAX_DEBT)
+    if debit_account.user.username == "Bank":
+        threshold = Amount.parse(settings.TALER_MAX_DEBT_BANK)
+    if 1 == Amount.cmp(debit_account.amount, threshold) \
+        and 0 != Amount.cmp(Amount(settings.TALER_CURRENCY), threshold) \
+        and debit_account.debit:
+        logger.info("Negative balance '%s' not allowed." % 
json.dumps(debit_account.amount.dump()))
+        logger.info("%s's threshold is: '%s'." % (debit_account.user.username, 
json.dumps(threshold.dump())))
+        raise DebtLimitExceededException()
 
     with transaction.atomic():
         debit_account.save()
diff --git a/talerbank/settings.py b/talerbank/settings.py
index b553a3b..3dad905 100644
--- a/talerbank/settings.py
+++ b/talerbank/settings.py
@@ -187,10 +187,10 @@ except ConfigurationError as e:
     logger.error(e)
     sys.exit(3)
 
-TALER_MAX_DEBT = tc.value_string("bank", "MAX_DEBT", default="%s:50" % 
TALER_CURRENCY)
-TALER_MAX_DEBT_BANK = tc.value_string("bank", "MAX_DEBT_BANK", default="%s:0" 
% TALER_CURRENCY)
+TALER_MAX_DEBT = tc.value_string("bank", "MAX_DEBT", default="%s:50.0" % 
TALER_CURRENCY)
+TALER_MAX_DEBT_BANK = tc.value_string("bank", "MAX_DEBT_BANK", 
default="%s:0.0" % TALER_CURRENCY)
 
-TALER_DIGITS = 2
+TALER_DIGITS = tc.value_int("bank", "NDIGITS", default=2)
 TALER_PREDEFINED_ACCOUNTS = ['Tor', 'GNUnet', 'Taler', 'FSF', 'Tutorial']
 TALER_EXPECTS_DONATIONS = ['Tor', 'GNUnet', 'Taler', 'FSF']
 TALER_SUGGESTED_EXCHANGE = tc.value_string("bank", "suggested_exchange")

-- 
To stop receiving notification emails like this one, please contact
address@hidden



reply via email to

[Prev in Thread] Current Thread [Next in Thread]