From 94b7a8676a94a454e1b21eb46eac447f2b68d2ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 15 Jan 2015 23:40:42 +0100 Subject: [PATCH] Add reverse_compute on Tax issue4444 review6801002 --- CHANGELOG | 1 + tax.py | 52 +++++++++++++++++++++++++++++++++++++++++-- tests/test_account.py | 29 +++++++++++++++++++++++- 3 files changed, 79 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index b0d930b2b1..891a859e8d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* Add reverse_compute on Tax * Add fix_party script * Allow to display only the balance in the General Ledger * Add TaxableMixin diff --git a/tax.py b/tax.py index 5ccb44d163..438861d589 100644 --- a/tax.py +++ b/tax.py @@ -788,11 +788,47 @@ class Tax(ModelSQL, ModelView): return res @classmethod - def sort_taxes(cls, taxes): + def _reverse_rate_amount(cls, taxes, date): + rate = None + amount = 0 + for tax in taxes: + start_date = tax.start_date or datetime.date.min + end_date = tax.end_date or datetime.date.max + if not (start_date <= date <= end_date): + continue + + if tax.type == 'percentage': + if rate is None: + rate = tax.rate + else: + rate *= tax.rate + elif tax.type == 'fixed': + amount += tax.amount + + if tax.childs: + child_rate, child_amount = cls._reverse_rate_amount( + tax.childs, date) + if rate is None: + rate = child_rate + else: + rate *= child_rate + amount += child_amount + return rate, amount + + @classmethod + def _reverse_unit_compute(cls, price_unit, taxes, date): + rate, amount = cls._reverse_rate_amount(taxes, date) + price_unit -= amount + if rate is not None: + price_unit = price_unit / (1 + rate) + return price_unit + + @classmethod + def sort_taxes(cls, taxes, reverse=False): ''' Return a list of taxes sorted ''' - return sorted(taxes, key=lambda t: (t.sequence, t.id)) + return sorted(taxes, key=lambda t: (t.sequence, t.id), reverse=reverse) @classmethod def compute(cls, taxes, price_unit, quantity, date=None): @@ -815,6 +851,18 @@ class Tax(ModelSQL, ModelView): row['amount'] *= quantity return res + @classmethod + def reverse_compute(cls, price_unit, taxes, date=None): + ''' + Reverse compute the price_unit for taxes at the date. + ''' + pool = Pool() + Date = pool.get('ir.date') + if date is None: + date = Date.today() + taxes = cls.sort_taxes(taxes, reverse=True) + return cls._reverse_unit_compute(price_unit, taxes, date) + def update_tax(self, template2tax_code, template2account, template2tax=None): ''' diff --git a/tests/test_account.py b/tests/test_account.py index 1ce6224b60..997f9ae1bf 100644 --- a/tests/test_account.py +++ b/tests/test_account.py @@ -329,7 +329,7 @@ class AccountTestCase(unittest.TestCase): transaction.cursor.rollback() def test0040tax_compute(self): - 'Test tax compute' + 'Test tax compute/reverse_compute' with Transaction().start(DB_NAME, USER, context=CONTEXT): today = datetime.date.today() @@ -372,6 +372,10 @@ class AccountTestCase(unittest.TestCase): 'tax': child2, }]) + self.assertEqual( + self.tax.reverse_compute(Decimal('130'), [tax]), + Decimal('100')) + child1.end_date = today + relativedelta(days=5) child1.save() self.assertEqual(self.tax.compute([tax], Decimal('100'), 2, today), @@ -385,6 +389,10 @@ class AccountTestCase(unittest.TestCase): 'tax': child2, }]) + self.assertEqual( + self.tax.reverse_compute(Decimal('130'), [tax], today), + Decimal('100')) + child1.start_date = today + relativedelta(days=1) child1.save() self.assertEqual(self.tax.compute([tax], Decimal('100'), 2, today), @@ -393,6 +401,9 @@ class AccountTestCase(unittest.TestCase): 'amount': Decimal('20'), 'tax': child2, }]) + self.assertEqual( + self.tax.reverse_compute(Decimal('110'), [tax], today), + Decimal('100')) self.assertEqual(self.tax.compute([tax], Decimal('100'), 2, today + relativedelta(days=1)), [{ 'base': Decimal('200'), @@ -403,6 +414,10 @@ class AccountTestCase(unittest.TestCase): 'amount': Decimal('20'), 'tax': child2, }]) + self.assertEqual( + self.tax.reverse_compute( + Decimal('130'), [tax], today + relativedelta(days=1)), + Decimal('100')) self.assertEqual(self.tax.compute([tax], Decimal('100'), 2, today + relativedelta(days=5)), [{ 'base': Decimal('200'), @@ -413,12 +428,20 @@ class AccountTestCase(unittest.TestCase): 'amount': Decimal('20'), 'tax': child2, }]) + self.assertEqual( + self.tax.reverse_compute(Decimal('130'), [tax], + today + relativedelta(days=5)), + Decimal('100')) self.assertEqual(self.tax.compute([tax], Decimal('100'), 2, today + relativedelta(days=6)), [{ 'base': Decimal('200'), 'amount': Decimal('20'), 'tax': child2, }]) + self.assertEqual( + self.tax.reverse_compute(Decimal('110'), [tax], + today + relativedelta(days=6)), + Decimal('100')) child1.end_date = None child1.save() @@ -432,6 +455,10 @@ class AccountTestCase(unittest.TestCase): 'amount': Decimal('20'), 'tax': child2, }]) + self.assertEqual( + self.tax.reverse_compute(Decimal('130'), [tax], + today + relativedelta(days=6)), + Decimal('100')) def suite():