diff --git a/CHANGELOG b/CHANGELOG
index 43755c0e17..3479d880c1 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,4 @@
+* Allow to define many relativedelta on payment term
* Add test wizard for payment term
* Use TaxableMixin
diff --git a/__init__.py b/__init__.py
index 4e64cab9a8..aa65f3a9c0 100644
--- a/__init__.py
+++ b/__init__.py
@@ -12,6 +12,7 @@ def register():
Pool.register(
PaymentTerm,
PaymentTermLine,
+ PaymentTermLineRelativeDelta,
TestPaymentTermView,
TestPaymentTermViewResult,
Invoice,
diff --git a/payment_term.py b/payment_term.py
index 383993bf74..55a9c0cf55 100644
--- a/payment_term.py
+++ b/payment_term.py
@@ -3,7 +3,7 @@
from decimal import Decimal
from dateutil.relativedelta import relativedelta
-from sql import Null
+from sql import Null, Column
from trytond.model import ModelView, ModelSQL, fields
from trytond import backend
@@ -12,7 +12,7 @@ from trytond.transaction import Transaction
from trytond.pool import Pool
from trytond.wizard import Wizard, StateView, Button
-__all__ = ['PaymentTerm', 'PaymentTermLine',
+__all__ = ['PaymentTerm', 'PaymentTermLine', 'PaymentTermLineRelativeDelta',
'TestPaymentTerm', 'TestPaymentTermView', 'TestPaymentTermViewResult']
@@ -126,44 +126,13 @@ class PaymentTermLine(ModelSQL, ModelView):
}, depends=['type'])
currency_digits = fields.Function(fields.Integer('Currency Digits'),
'on_change_with_currency_digits')
- day = fields.Integer('Day of Month')
- month = fields.Selection([
- (None, ''),
- ('1', 'January'),
- ('2', 'February'),
- ('3', 'March'),
- ('4', 'April'),
- ('5', 'May'),
- ('6', 'June'),
- ('7', 'July'),
- ('8', 'August'),
- ('9', 'September'),
- ('10', 'October'),
- ('11', 'November'),
- ('12', 'December'),
- ], 'Month', sort=False)
- weekday = fields.Selection([
- (None, ''),
- ('0', 'Monday'),
- ('1', 'Tuesday'),
- ('2', 'Wednesday'),
- ('3', 'Thursday'),
- ('4', 'Friday'),
- ('5', 'Saturday'),
- ('6', 'Sunday'),
- ], 'Day of Week', sort=False)
- months = fields.Integer('Number of Months', required=True)
- weeks = fields.Integer('Number of Weeks', required=True)
- days = fields.Integer('Number of Days', required=True)
+ relativedeltas = fields.One2Many(
+ 'account.invoice.payment_term.line.relativedelta', 'line', 'Deltas')
@classmethod
def __setup__(cls):
super(PaymentTermLine, cls).__setup__()
cls._order.insert(0, ('sequence', 'ASC'))
- cls._sql_constraints += [
- ('day', 'CHECK(day BETWEEN 1 AND 31)',
- 'Day of month must be between 1 and 31.'),
- ]
cls._error_messages.update({
'invalid_percentage_and_divisor': ('Percentage and '
'Divisor values are not consistent in line "%(line)s" '
@@ -216,18 +185,6 @@ class PaymentTermLine(ModelSQL, ModelView):
def default_type():
return 'remainder'
- @staticmethod
- def default_months():
- return 0
-
- @staticmethod
- def default_weeks():
- return 0
-
- @staticmethod
- def default_days():
- return 0
-
@fields.depends('type')
def on_change_type(self):
if self.type != 'fixed':
@@ -270,7 +227,9 @@ class PaymentTermLine(ModelSQL, ModelView):
}
def get_date(self, date):
- return date + relativedelta(**self.get_delta())
+ for relativedelta_ in self.relativedeltas:
+ date += relativedelta_.get()
+ return date
def get_value(self, remainder, amount, currency):
Currency = Pool().get('currency.currency')
@@ -326,6 +285,105 @@ class PaymentTermLine(ModelSQL, ModelView):
})
+class PaymentTermLineRelativeDelta(ModelSQL, ModelView):
+ 'Payment Term Line Relative Delta'
+ __name__ = 'account.invoice.payment_term.line.relativedelta'
+ sequence = fields.Integer('Sequence')
+ line = fields.Many2One('account.invoice.payment_term.line',
+ 'Payment Term Line', required=True, ondelete='CASCADE')
+ day = fields.Integer('Day of Month',
+ domain=['OR',
+ ('day', '=', None),
+ [('day', '>=', 1), ('day', '<=', 31)],
+ ])
+ month = fields.Selection([
+ (None, ''),
+ ('1', 'January'),
+ ('2', 'February'),
+ ('3', 'March'),
+ ('4', 'April'),
+ ('5', 'May'),
+ ('6', 'June'),
+ ('7', 'July'),
+ ('8', 'August'),
+ ('9', 'September'),
+ ('10', 'October'),
+ ('11', 'November'),
+ ('12', 'December'),
+ ], 'Month', sort=False)
+ weekday = fields.Selection([
+ (None, ''),
+ ('0', 'Monday'),
+ ('1', 'Tuesday'),
+ ('2', 'Wednesday'),
+ ('3', 'Thursday'),
+ ('4', 'Friday'),
+ ('5', 'Saturday'),
+ ('6', 'Sunday'),
+ ], 'Day of Week', sort=False)
+ months = fields.Integer('Number of Months', required=True)
+ weeks = fields.Integer('Number of Weeks', required=True)
+ days = fields.Integer('Number of Days', required=True)
+
+ @classmethod
+ def __setup__(cls):
+ super(PaymentTermLineRelativeDelta, cls).__setup__()
+ cls._order.insert(0, ('sequence', 'ASC'))
+
+ @classmethod
+ def __register__(cls, module_name):
+ TableHandler = backend.get('TableHandler')
+ cursor = Transaction().cursor
+ pool = Pool()
+ Line = pool.get('account.invoice.payment_term.line')
+ sql_table = cls.__table__()
+ line = Line.__table__()
+
+ super(PaymentTermLineRelativeDelta, cls).__register__(module_name)
+
+ line_table = TableHandler(cursor, Line, module_name)
+
+ # Migration from 3.4
+ fields = ['day', 'month', 'weekday', 'months', 'weeks', 'days']
+ if any(line_table.column_exist(f) for f in fields):
+ columns = ([line.id.as_('line')]
+ + [Column(line, f) for f in fields])
+ cursor.execute(*sql_table.insert(
+ columns=[sql_table.line]
+ + [Column(sql_table, f) for f in fields],
+ values=line.select(*columns)))
+ for field in fields:
+ line_table.drop_column(field, exception=True)
+
+ @staticmethod
+ def order_sequence(tables):
+ table, _ = tables[None]
+ return [table.sequence == Null, table.sequence]
+
+ @staticmethod
+ def default_months():
+ return 0
+
+ @staticmethod
+ def default_weeks():
+ return 0
+
+ @staticmethod
+ def default_days():
+ return 0
+
+ def get(self):
+ "Return the relativedelta"
+ return relativedelta(
+ day=self.day,
+ month=int(self.month) if self.month else None,
+ days=self.days,
+ weeks=self.weeks,
+ months=self.months,
+ weekday=int(self.weekday) if self.weekday else None,
+ )
+
+
class TestPaymentTerm(Wizard):
'Test Payment Term'
__name__ = 'account.invoice.payment_term.test'
diff --git a/payment_term.xml b/payment_term.xml
index 1e5083fda1..948ac76e92 100644
--- a/payment_term.xml
+++ b/payment_term.xml
@@ -85,6 +85,46 @@ this repository contains the full copyright notices and license terms. -->
+
+ account.invoice.payment_term.line.relativedelta
+ tree
+
+ payment_term_line_relativedelta_list
+
+
+ account.invoice.payment_term.line.relativedelta
+ tree
+
+ payment_term_line_relativedelta_list_sequence
+
+
+
+ account.invoice.payment_term.line.relativedelta
+ form
+ payment_term_line_relativedelta_form
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Test Payment Term
account.invoice.payment_term.test
diff --git a/tests/scenario_invoice.rst b/tests/scenario_invoice.rst
index e8433fbbf2..1f56443820 100644
--- a/tests/scenario_invoice.rst
+++ b/tests/scenario_invoice.rst
@@ -88,13 +88,11 @@ Create product::
Create payment term::
>>> PaymentTerm = Model.get('account.invoice.payment_term')
- >>> PaymentTermLine = Model.get('account.invoice.payment_term.line')
>>> payment_term = PaymentTerm(name='Term')
- >>> payment_term_line = PaymentTermLine(type='percent', days=20,
- ... percentage=Decimal(50))
- >>> payment_term.lines.append(payment_term_line)
- >>> payment_term_line = PaymentTermLine(type='remainder', days=40)
- >>> payment_term.lines.append(payment_term_line)
+ >>> line = payment_term.lines.new(type='percent', percentage=Decimal(50))
+ >>> delta = line.relativedeltas.new(days=20)
+ >>> line = payment_term.lines.new(type='remainder')
+ >>> delta = line.relativedeltas.new(days=40)
>>> payment_term.save()
Create invoice::
diff --git a/tests/scenario_invoice_alternate_currency.rst b/tests/scenario_invoice_alternate_currency.rst
index 24f7507d7f..0a9d849475 100644
--- a/tests/scenario_invoice_alternate_currency.rst
+++ b/tests/scenario_invoice_alternate_currency.rst
@@ -90,13 +90,11 @@ Create product::
Create payment term::
>>> PaymentTerm = Model.get('account.invoice.payment_term')
- >>> PaymentTermLine = Model.get('account.invoice.payment_term.line')
>>> payment_term = PaymentTerm(name='Term')
- >>> payment_term_line = PaymentTermLine(type='percent', days=20,
- ... percentage=Decimal(50))
- >>> payment_term.lines.append(payment_term_line)
- >>> payment_term_line = PaymentTermLine(type='remainder', days=40)
- >>> payment_term.lines.append(payment_term_line)
+ >>> line = payment_term.lines.new(type='percent', percentage=Decimal(50))
+ >>> delta = line.relativedeltas.new(days=20)
+ >>> line = payment_term.lines.new(type='remainder')
+ >>> delta = line.relativedeltas.new(days=40)
>>> payment_term.save()
Create invoice with alternate currency::
diff --git a/tests/scenario_invoice_supplier.rst b/tests/scenario_invoice_supplier.rst
index 864d960dcf..ed2192d79f 100644
--- a/tests/scenario_invoice_supplier.rst
+++ b/tests/scenario_invoice_supplier.rst
@@ -87,10 +87,8 @@ Create product::
Create payment term::
>>> PaymentTerm = Model.get('account.invoice.payment_term')
- >>> PaymentTermLine = Model.get('account.invoice.payment_term.line')
>>> payment_term = PaymentTerm(name='Term')
- >>> payment_term_line = PaymentTermLine(type='remainder')
- >>> payment_term.lines.append(payment_term_line)
+ >>> line = payment_term.lines.new(type='remainder')
>>> payment_term.save()
Create invoice::
diff --git a/tests/test_account_invoice.py b/tests/test_account_invoice.py
index 085bd4e76b..a9cc6863dc 100644
--- a/tests/test_account_invoice.py
+++ b/tests/test_account_invoice.py
@@ -37,26 +37,42 @@ class AccountInvoiceTestCase(ModuleTestCase):
'type': 'percent',
'divisor': 4,
'percentage': 25,
- 'days': 30,
+ 'relativedeltas': [('create', [{
+ 'days': 30,
+ },
+ ]),
+ ],
}, {
'sequence': 1,
'type': 'percent_on_total',
'divisor': 4,
'percentage': 25,
- 'months': 1,
+ 'relativedeltas': [('create', [{
+ 'months': 1,
+ },
+ ]),
+ ],
}, {
'sequence': 2,
'type': 'fixed',
- 'months': 1,
- 'days': 30,
'amount': Decimal('396.84'),
'currency': cu1.id,
+ 'relativedeltas': [('create', [{
+ 'months': 1,
+ 'days': 30,
+ },
+ ]),
+ ],
}, {
'sequence': 3,
'type': 'remainder',
- 'months': 2,
- 'days': 30,
- 'day': 15,
+ 'relativedeltas': [('create', [{
+ 'months': 2,
+ 'days': 30,
+ 'day': 15,
+ },
+ ]),
+ ],
}])]
}])
terms = term.compute(Decimal('1587.35'), cu1,
diff --git a/tests/tools.py b/tests/tools.py
index a0b2dde75a..10fceb22f0 100644
--- a/tests/tools.py
+++ b/tests/tools.py
@@ -24,5 +24,5 @@ def create_payment_term(config=None):
PaymentTerm = Model.get('account.invoice.payment_term')
payment_term = PaymentTerm(name='Direct')
- payment_term.lines.new(type='remainder', days=0)
+ payment_term.lines.new(type='remainder')
return payment_term
diff --git a/view/payment_term_line_form.xml b/view/payment_term_line_form.xml
index 232d57983a..ccdf1123b6 100644
--- a/view/payment_term_line_form.xml
+++ b/view/payment_term_line_form.xml
@@ -1,29 +1,19 @@
-
diff --git a/view/payment_term_line_list.xml b/view/payment_term_line_list.xml
index 04e09b66dd..7d91ed6e43 100644
--- a/view/payment_term_line_list.xml
+++ b/view/payment_term_line_list.xml
@@ -7,12 +7,4 @@ this repository contains the full copyright notices and license terms. -->
-
-
-
-
-
-
-
-
diff --git a/view/payment_term_line_list_sequence.xml b/view/payment_term_line_list_sequence.xml
index 8f2b00f134..8499bdd4f0 100644
--- a/view/payment_term_line_list_sequence.xml
+++ b/view/payment_term_line_list_sequence.xml
@@ -6,12 +6,4 @@ this repository contains the full copyright notices and license terms. -->
-
-
-
-
-
-
-
-
diff --git a/view/payment_term_line_relativedelta_form.xml b/view/payment_term_line_relativedelta_form.xml
new file mode 100644
index 0000000000..5344d939ef
--- /dev/null
+++ b/view/payment_term_line_relativedelta_form.xml
@@ -0,0 +1,21 @@
+
+
+
diff --git a/view/payment_term_line_relativedelta_list.xml b/view/payment_term_line_relativedelta_list.xml
new file mode 100644
index 0000000000..60e6a4c9df
--- /dev/null
+++ b/view/payment_term_line_relativedelta_list.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/view/payment_term_line_relativedelta_list_sequence.xml b/view/payment_term_line_relativedelta_list_sequence.xml
new file mode 100644
index 0000000000..4199526ec0
--- /dev/null
+++ b/view/payment_term_line_relativedelta_list_sequence.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+