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 @@ -
+