From ae886a24f9d0beb2f4322fb133ce2057045f9a19 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Thu, 2 Aug 2018 15:34:27 +0300 Subject: Fix: VAT computetions when count > 1 --- lasku.py | 129 ++++++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 87 insertions(+), 42 deletions(-) (limited to 'lasku.py') diff --git a/lasku.py b/lasku.py index 6ee3b6f..110c636 100755 --- a/lasku.py +++ b/lasku.py @@ -9,6 +9,9 @@ import yaml def debug(*args): sys.stderr.write('{}\n'.format(' '.join(str(x) for x in args))) +def round(f): + return int(f + 0.5) + def euros(cents): return '%.02f' % (cents / 100.0) @@ -18,51 +21,93 @@ class Item: def __init__(self, itemdict): self.dict = dict(itemdict) - count = itemdict['count'] - if count == "": - return + bignum = 99999999 + self.dict.update({ + 'unit_net_cents': bignum, + 'unit_vat_cents': bignum, + 'unit_cents': bignum, + 'total_net_cents': bignum, + 'total_vat_cents': bignum, + 'total_cents': bignum, + }) + + self.compute() + self.check() + + self.dict.update({ + 'unit_net_euros': euros(self['unit_net_cents']), + 'unit_vat_euros': euros(self['unit_vat_cents']), + 'unit_euros': euros(self['unit_cents']), + 'total_net_euros': euros(self['total_net_cents']), + 'total_vat_euros': euros(self['total_vat_cents']), + 'total_euros': euros(self['total_cents']), + }) + + def __getitem__(self, key): + return self.dict[key] + + def __setitem__(self, key, value): + self.dict[key] = value - unit_cents = int(itemdict['unit'] * 100.0) - vatpc = float(itemdict['vatpc']) / 100.0 + def items(self): + return self.dict.items() - self.total_cents = count * unit_cents + def check(self): + count = self['count'] + vatpc = int(self['vatpc'] / 100.0) + unit_net_cents = self['unit_net_cents'] + unit_vat_cents = self['unit_vat_cents'] + unit_cents = self['unit_cents'] + total_net_cents = self['total_net_cents'] + total_vat_cents = self['total_vat_cents'] + total_cents = self['total_cents'] + + debug(self.dict) + + assert unit_net_cents * count == total_net_cents, \ + '{} * {} != {}'.format(unit_net_cents, count, total_net_cents) + + assert unit_net_cents + unit_vat_cents == unit_cents, \ + '{} + {} != {}'.format(unit_net_cents, unit_vat_cents, unit_cents) + + assert total_cents == count * (unit_net_cents + unit_vat_cents), \ + '{} != {} * ({} + {})'.format( + total_net_cents, count, unit_net_cents, unit_vat_cents) - self.vat_cents = 0 if vatpc > 0: - unit_cents_with_vat = int(unit_cents / (1.0 - vatpc)) - unit_vat_cents = unit_cents_with_vat - unit_cents - debug('dict', self.dict) - debug('total_cents', self.total_cents) - debug('vatpc', vatpc) - debug('unit_cents_with_vat', unit_cents_with_vat) - debug('unit_vat_cents', unit_vat_cents) - debug('calc', int(vatpc * unit_cents_with_vat)) - assert int(unit_cents_with_vat * vatpc) == unit_vat_cents - assert unit_cents_with_vat == unit_cents + unit_vat_cents - self.vat_cents = unit_vat_cents * count + assert unit_cents == unit_net_cents + unit_vat_cents, \ + '{} != {} + {}'.format(unit_cents, unit_net_cents, unit_vat_cents) - self.dict.update({ - 'unit_euros': euros(unit_cents), - 'total_cents': self.total_cents, - 'total': euros(self.total_cents), - 'unitwithvat': euros(unit_cents + self.vat_cents), - 'vat_cents': self.vat_cents, - 'vat': euros(self.vat_cents), - 'vatsum': euros(self.vat_cents * count), - 'totalwithvat': euros(count * (unit_cents + self.vat_cents)), - }) + assert total_vat_cents == count * unit_vat_cents, \ + '{} != {} * {}'.format(total_vat_cents, count, unit_net_cents) + + assert round(total_cents * vatpc) == total_vat_cents, \ + '{} * {} != {}'.format( + total_cents, vatpc, total_vat_cents) + + def compute(self): + count = self['count'] + vatpc = float(self['vatpc']) / 100.0 + + unit_net_cents = self['unit_net_cents'] = round(self['unit'] * 100.0) + unit_vat_cents = self['unit_vat_cents'] = round( + unit_net_cents * vatpc / (1 - vatpc)) + unit_cents = self['unit_cents'] = unit_net_cents + unit_vat_cents + self['total_net_cents'] = unit_net_cents * count + self['total_vat_cents'] = unit_vat_cents * count + self['total_cents'] = count * unit_cents item_template = ( r'\raggedbottom #number# & ' r'\parbox[t]{5.5cm}{#desc#\\#date#} & ' r'\raggedbottom #count# & ' + r'\raggedbottom #unit_net_euros# & ' r'\raggedbottom #unit_euros# & ' - r'\raggedbottom #unitwithvat# & ' r'\raggedbottom #vatpc#\% & ' - r'\raggedbottom #total# & ' - r'\raggedbottom #vatsum# & ' - r'\raggedbottom #totalwithvat# \\[2.2ex]' + r'\raggedbottom #total_net_euros# & ' + r'\raggedbottom #total_vat_euros# & ' + r'\raggedbottom #total_euros# \\[2.2ex]' ) @@ -90,21 +135,21 @@ values = dict(company) values.update(invoice) itemtext = '' -total_cents = 0 -total_vat = 0 -total_sum = 0 +sum_net_cents = 0 +sum_vat_cents = 0 +sum_cents = 0 for item in items: it = Item(item) - itemtext += substitute_all(item_template, it.dict) - total_cents += it.total_cents - total_vat += it.vat_cents - total_sum += it.total_cents + it.vat_cents + itemtext += substitute_all(item_template, it) + sum_net_cents += it['total_net_cents'] + sum_vat_cents += it['total_vat_cents'] + sum_cents += it['total_cents'] values['itemtext'] = itemtext -values['totalraw'] = euros(total_cents) -values['totalvat'] = euros(total_vat) -values['totalsum'] = euros(total_sum) +values['totalraw'] = euros(sum_net_cents) +values['totalvat'] = euros(sum_vat_cents) +values['totalsum'] = euros(sum_cents) values['amount'] = values['totalsum'] -- cgit v1.2.1