diff --git a/CHANGELOG b/CHANGELOG
index 15bbc9e546..2d8d04fa4b 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,4 @@
+* Add start/end date to tax
* Use account of write-off journal as default
* Add write-off journal type
* Add description on write-off move
diff --git a/tax.py b/tax.py
index ede99e3eed..9c27e9f32d 100644
--- a/tax.py
+++ b/tax.py
@@ -1,5 +1,6 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
+import datetime
from decimal import Decimal
from sql.aggregate import Sum
@@ -347,6 +348,8 @@ class TaxTemplate(ModelSQL, ModelView):
description = fields.Char('Description', required=True, translate=True)
group = fields.Many2One('account.tax.group', 'Group')
sequence = fields.Integer('Sequence')
+ start_date = fields.Date('Starting Date')
+ end_date = fields.Date('Ending Date')
amount = fields.Numeric('Amount', digits=(16, 8),
states={
'required': Eval('type') == 'fixed',
@@ -449,7 +452,8 @@ class TaxTemplate(ModelSQL, ModelView):
res = {}
for field in ('name', 'description', 'sequence', 'amount',
'rate', 'type', 'invoice_base_sign', 'invoice_tax_sign',
- 'credit_note_base_sign', 'credit_note_tax_sign'):
+ 'credit_note_base_sign', 'credit_note_tax_sign',
+ 'start_date', 'end_date'):
if not tax or getattr(tax, field) != getattr(self, field):
res[field] = getattr(self, field)
for field in ('group',):
@@ -571,6 +575,8 @@ class Tax(ModelSQL, ModelView):
}, depends=['parent'])
active = fields.Boolean('Active')
sequence = fields.Integer('Sequence', help='Use to order the taxes')
+ start_date = fields.Date('Starting Date')
+ end_date = fields.Date('Ending Date')
currency_digits = fields.Function(fields.Integer('Currency Digits'),
'on_change_with_currency_digits')
amount = fields.Numeric('Amount', digits=(16, Eval('currency_digits', 2)),
@@ -749,13 +755,17 @@ class Tax(ModelSQL, ModelView):
}
@classmethod
- def _unit_compute(cls, taxes, price_unit):
+ def _unit_compute(cls, taxes, price_unit, date):
res = []
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 != 'none':
res.append(tax._process_tax(price_unit))
if len(tax.childs):
- res.extend(cls._unit_compute(tax.childs, price_unit))
+ res.extend(cls._unit_compute(tax.childs, price_unit, date))
return res
@classmethod
@@ -766,16 +776,20 @@ class Tax(ModelSQL, ModelView):
return sorted(taxes, key=lambda t: (t.sequence, t.id))
@classmethod
- def compute(cls, taxes, price_unit, quantity):
+ def compute(cls, taxes, price_unit, quantity, date=None):
'''
- Compute taxes for price_unit and quantity.
+ Compute taxes for price_unit and quantity at the date.
Return list of dict for each taxes and their childs with:
base
amount
tax
'''
+ pool = Pool()
+ Date = pool.get('ir.date')
+ if date is None:
+ date = Date.today()
taxes = cls.sort_taxes(taxes)
- res = cls._unit_compute(taxes, price_unit)
+ res = cls._unit_compute(taxes, price_unit, date)
quantity = Decimal(str(quantity or 0.0))
for row in res:
row['base'] *= quantity
diff --git a/tests/test_account.py b/tests/test_account.py
index da8ea40ea6..b7a9b9eae8 100644
--- a/tests/test_account.py
+++ b/tests/test_account.py
@@ -4,6 +4,7 @@ import unittest
import doctest
import datetime
from decimal import Decimal
+from dateutil.relativedelta import relativedelta
import trytond.tests.test_tryton
from trytond.tests.test_tryton import test_view, test_depends, doctest_dropdb
from trytond.tests.test_tryton import POOL, DB_NAME, USER, CONTEXT
@@ -31,6 +32,7 @@ class AccountTestCase(unittest.TestCase):
self.period = POOL.get('account.period')
self.balance_non_deferral = POOL.get(
'account.fiscalyear.balance_non_deferral', type='wizard')
+ self.tax = POOL.get('account.tax')
def test0005views(self):
'Test views'
@@ -316,6 +318,111 @@ class AccountTestCase(unittest.TestCase):
transaction.cursor.rollback()
+ def test0040tax_compute(self):
+ 'Test tax compute'
+ with Transaction().start(DB_NAME, USER, context=CONTEXT):
+ today = datetime.date.today()
+
+ tax_account, = self.account.search([
+ ('name', '=', 'Main Tax'),
+ ])
+ tax = self.tax()
+ tax.name = tax.description = 'Test'
+ tax.type = 'none'
+ tax.invoice_account = tax_account
+ tax.credit_note_account = tax_account
+
+ child1 = self.tax()
+ child1.name = child1.description = 'Child 1'
+ child1.type = 'percentage'
+ child1.rate = Decimal('0.2')
+ child1.invoice_account = tax_account
+ child1.credit_note_account = tax_account
+ child1.save()
+
+ child2 = self.tax()
+ child2.name = child2.description = 'Child 1'
+ child2.type = 'fixed'
+ child2.amount = Decimal('10')
+ child2.invoice_account = tax_account
+ child2.credit_note_account = tax_account
+ child2.save()
+
+ tax.childs = [child1, child2]
+ tax.save()
+
+ self.assertEqual(self.tax.compute([tax], Decimal('100'), 2),
+ [{
+ 'base': Decimal('200'),
+ 'amount': Decimal('40.0'),
+ 'tax': child1,
+ }, {
+ 'base': Decimal('200'),
+ 'amount': Decimal('20'),
+ 'tax': child2,
+ }])
+
+ child1.end_date = today + relativedelta(days=5)
+ child1.save()
+ self.assertEqual(self.tax.compute([tax], Decimal('100'), 2, today),
+ [{
+ 'base': Decimal('200'),
+ 'amount': Decimal('40.0'),
+ 'tax': child1,
+ }, {
+ 'base': Decimal('200'),
+ 'amount': Decimal('20'),
+ 'tax': child2,
+ }])
+
+ child1.start_date = today + relativedelta(days=1)
+ child1.save()
+ self.assertEqual(self.tax.compute([tax], Decimal('100'), 2, today),
+ [{
+ 'base': Decimal('200'),
+ 'amount': Decimal('20'),
+ 'tax': child2,
+ }])
+ self.assertEqual(self.tax.compute([tax], Decimal('100'), 2,
+ today + relativedelta(days=1)), [{
+ 'base': Decimal('200'),
+ 'amount': Decimal('40.0'),
+ 'tax': child1,
+ }, {
+ 'base': Decimal('200'),
+ 'amount': Decimal('20'),
+ 'tax': child2,
+ }])
+ self.assertEqual(self.tax.compute([tax], Decimal('100'), 2,
+ today + relativedelta(days=5)), [{
+ 'base': Decimal('200'),
+ 'amount': Decimal('40.0'),
+ 'tax': child1,
+ }, {
+ 'base': Decimal('200'),
+ 'amount': Decimal('20'),
+ 'tax': child2,
+ }])
+ self.assertEqual(self.tax.compute([tax], Decimal('100'), 2,
+ today + relativedelta(days=6)), [{
+ 'base': Decimal('200'),
+ 'amount': Decimal('20'),
+ 'tax': child2,
+ }])
+
+ child1.end_date = None
+ child1.save()
+ self.assertEqual(self.tax.compute([tax], Decimal('100'), 2,
+ today + relativedelta(days=6)), [{
+ 'base': Decimal('200'),
+ 'amount': Decimal('40.0'),
+ 'tax': child1,
+ }, {
+ 'base': Decimal('200'),
+ 'amount': Decimal('20'),
+ 'tax': child2,
+ }])
+
def suite():
suite = trytond.tests.test_tryton.suite()
diff --git a/view/tax_form.xml b/view/tax_form.xml
index 6c4985462d..dc1fb2e40c 100644
--- a/view/tax_form.xml
+++ b/view/tax_form.xml
@@ -14,6 +14,10 @@ this repository contains the full copyright notices and license terms. -->
+
+
+
+
diff --git a/view/tax_template_form.xml b/view/tax_template_form.xml
index 28acd4da6c..93ab0ba6b2 100644
--- a/view/tax_template_form.xml
+++ b/view/tax_template_form.xml
@@ -14,6 +14,10 @@ this repository contains the full copyright notices and license terms. -->
+
+
+
+