[REF] contract: make recurring_invoicing_offset a computed field

In preparation to making it user modifiable.
This commit is contained in:
Stéphane Bidoul (ACSONE)
2019-12-09 10:21:20 +01:00
committed by Francisco Ivan Anton Prieto
parent d74f65ff97
commit 198060511c
4 changed files with 112 additions and 44 deletions

View File

@@ -4,7 +4,7 @@
# Copyright 2016-2018 Tecnativa - Carlos Dauden # Copyright 2016-2018 Tecnativa - Carlos Dauden
# Copyright 2017 Tecnativa - Vicent Cubells # Copyright 2017 Tecnativa - Vicent Cubells
# Copyright 2016-2017 LasLabs Inc. # Copyright 2016-2017 LasLabs Inc.
# Copyright 2018 ACSONE SA/NV # Copyright 2018-2019 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{ {

View File

@@ -70,9 +70,20 @@ class ContractAbstractContractLine(models.AbstractModel):
[('pre-paid', 'Pre-paid'), ('post-paid', 'Post-paid')], [('pre-paid', 'Pre-paid'), ('post-paid', 'Post-paid')],
default='pre-paid', default='pre-paid',
string='Invoicing type', string='Invoicing type',
help="Specify if process date is 'from' or 'to' invoicing date", help=(
"Specify if the invoice must be generated at the beginning "
"(pre-paid) or end (post-paid) of the period."
),
required=True, required=True,
) )
recurring_invoicing_offset = fields.Integer(
compute="_compute_recurring_invoicing_offset",
string="Invoicing offset",
help=(
"Number of days to offset the invoice from the period end "
"date (in post-paid mode) or beginning date (in pre-paid mode)."
)
)
recurring_interval = fields.Integer( recurring_interval = fields.Integer(
default=1, default=1,
string='Invoice Every', string='Invoice Every',
@@ -115,6 +126,27 @@ class ContractAbstractContractLine(models.AbstractModel):
ondelete='cascade', ondelete='cascade',
) )
@api.model
def _get_default_recurring_invoicing_offset(
self, recurring_invoicing_type, recurring_rule_type
):
if (
recurring_invoicing_type == 'pre-paid'
or recurring_rule_type == 'monthlylastday'
):
return 0
else:
return 1
@api.depends('recurring_invoicing_type', 'recurring_rule_type')
def _compute_recurring_invoicing_offset(self):
for rec in self:
rec.recurring_invoicing_offset = (
self._get_default_recurring_invoicing_offset(
rec.recurring_invoicing_type, rec.recurring_rule_type
)
)
@api.depends( @api.depends(
'automatic_price', 'automatic_price',
'specific_price', 'specific_price',

View File

@@ -375,32 +375,20 @@ class ContractLine(models.Model):
return self._get_recurring_next_date( return self._get_recurring_next_date(
date_start, date_start,
recurring_invoicing_type, recurring_invoicing_type,
self._get_default_recurring_invoicing_offset(
recurring_invoicing_type, recurring_rule_type
),
recurring_rule_type, recurring_rule_type,
recurring_interval, recurring_interval,
max_date_end=False, max_date_end=False,
) )
@api.model
def _get_offset(self, recurring_invoicing_type, recurring_rule_type):
"""Return a relativedelta to offset the invoice date compared
to the period start or end date.
This method will disappear when the offset becomes user controlled.
"""
if (
recurring_invoicing_type == 'pre-paid'
or recurring_rule_type == 'monthlylastday'
):
offset = 0
else:
offset = 1
return relativedelta(days=offset)
@api.model @api.model
def _get_recurring_next_date( def _get_recurring_next_date(
self, self,
next_period_date_start, next_period_date_start,
recurring_invoicing_type, recurring_invoicing_type,
recurring_invoicing_offset,
recurring_rule_type, recurring_rule_type,
recurring_interval, recurring_interval,
max_date_end, max_date_end,
@@ -408,17 +396,23 @@ class ContractLine(models.Model):
next_period_date_end = self._get_next_period_date_end( next_period_date_end = self._get_next_period_date_end(
next_period_date_start, next_period_date_start,
recurring_invoicing_type, recurring_invoicing_type,
recurring_invoicing_offset,
recurring_rule_type, recurring_rule_type,
recurring_interval, recurring_interval,
max_date_end=max_date_end, max_date_end=max_date_end,
) )
if not next_period_date_end: if not next_period_date_end:
return False return False
offset = self._get_offset(recurring_invoicing_type, recurring_rule_type)
if recurring_invoicing_type == 'pre-paid': if recurring_invoicing_type == 'pre-paid':
recurring_next_date = next_period_date_start + offset recurring_next_date = (
next_period_date_start
+ relativedelta(days=recurring_invoicing_offset)
)
else: # post-paid else: # post-paid
recurring_next_date = next_period_date_end + offset recurring_next_date = (
next_period_date_end
+ relativedelta(days=recurring_invoicing_offset)
)
return recurring_next_date return recurring_next_date
@api.model @api.model
@@ -426,6 +420,7 @@ class ContractLine(models.Model):
self, self,
next_period_date_start, next_period_date_start,
recurring_invoicing_type, recurring_invoicing_type,
recurring_invoicing_offset,
recurring_rule_type, recurring_rule_type,
recurring_interval, recurring_interval,
max_date_end, max_date_end,
@@ -448,18 +443,20 @@ class ContractLine(models.Model):
) )
else: else:
# special algorithm when the next invoice date is forced # special algorithm when the next invoice date is forced
offset = self._get_offset(recurring_invoicing_type, recurring_rule_type)
if recurring_invoicing_type == 'pre-paid': if recurring_invoicing_type == 'pre-paid':
next_period_date_end = ( next_period_date_end = (
next_invoice_date next_invoice_date
- offset - relativedelta(days=recurring_invoicing_offset)
+ self.get_relative_delta( + self.get_relative_delta(
recurring_rule_type, recurring_interval recurring_rule_type, recurring_interval
) )
- relativedelta(days=1) - relativedelta(days=1)
) )
else: # post-paid else: # post-paid
next_period_date_end = next_invoice_date - offset next_period_date_end = (
next_invoice_date
- relativedelta(days=recurring_invoicing_offset)
)
if max_date_end and next_period_date_end > max_date_end: if max_date_end and next_period_date_end > max_date_end:
# end date is past max_date_end: trim it # end date is past max_date_end: trim it
next_period_date_end = max_date_end next_period_date_end = max_date_end
@@ -481,6 +478,7 @@ class ContractLine(models.Model):
@api.depends( @api.depends(
'next_period_date_start', 'next_period_date_start',
'recurring_invoicing_type', 'recurring_invoicing_type',
'recurring_invoicing_offset',
'recurring_rule_type', 'recurring_rule_type',
'recurring_interval', 'recurring_interval',
'date_end', 'date_end',
@@ -491,6 +489,7 @@ class ContractLine(models.Model):
rec.next_period_date_end = self._get_next_period_date_end( rec.next_period_date_end = self._get_next_period_date_end(
rec.next_period_date_start, rec.next_period_date_start,
rec.recurring_invoicing_type, rec.recurring_invoicing_type,
rec.recurring_invoicing_offset,
rec.recurring_rule_type, rec.recurring_rule_type,
rec.recurring_interval, rec.recurring_interval,
max_date_end=rec.date_end, max_date_end=rec.date_end,
@@ -538,6 +537,7 @@ class ContractLine(models.Model):
rec.recurring_next_date = self._get_recurring_next_date( rec.recurring_next_date = self._get_recurring_next_date(
rec.date_start, rec.date_start,
rec.recurring_invoicing_type, rec.recurring_invoicing_type,
rec.recurring_invoicing_offset,
rec.recurring_rule_type, rec.recurring_rule_type,
rec.recurring_interval, rec.recurring_interval,
max_date_end=rec.date_end, max_date_end=rec.date_end,
@@ -673,6 +673,7 @@ class ContractLine(models.Model):
last_date_invoiced = self._get_next_period_date_end( last_date_invoiced = self._get_next_period_date_end(
first_date_invoiced, first_date_invoiced,
self.recurring_invoicing_type, self.recurring_invoicing_type,
self.recurring_invoicing_offset,
self.recurring_rule_type, self.recurring_rule_type,
self.recurring_interval, self.recurring_interval,
max_date_end=(self.date_end if stop_at_date_end else False), max_date_end=(self.date_end if stop_at_date_end else False),
@@ -702,6 +703,7 @@ class ContractLine(models.Model):
recurring_next_date = rec._get_recurring_next_date( recurring_next_date = rec._get_recurring_next_date(
last_date_invoiced + relativedelta(days=1), last_date_invoiced + relativedelta(days=1),
rec.recurring_invoicing_type, rec.recurring_invoicing_type,
rec.recurring_invoicing_offset,
rec.recurring_rule_type, rec.recurring_rule_type,
rec.recurring_interval, rec.recurring_interval,
max_date_end=rec.date_end, max_date_end=rec.date_end,
@@ -778,6 +780,7 @@ class ContractLine(models.Model):
new_recurring_next_date = self._get_recurring_next_date( new_recurring_next_date = self._get_recurring_next_date(
new_date_start, new_date_start,
rec.recurring_invoicing_type, rec.recurring_invoicing_type,
rec.recurring_invoicing_offset,
rec.recurring_rule_type, rec.recurring_rule_type,
rec.recurring_interval, rec.recurring_interval,
max_date_end=new_date_end max_date_end=new_date_end
@@ -842,6 +845,7 @@ class ContractLine(models.Model):
recurring_next_date = self._get_recurring_next_date( recurring_next_date = self._get_recurring_next_date(
date_start, date_start,
self.recurring_invoicing_type, self.recurring_invoicing_type,
self.recurring_invoicing_offset,
self.recurring_rule_type, self.recurring_rule_type,
self.recurring_interval, self.recurring_interval,
max_date_end=date_end, max_date_end=date_end,

View File

@@ -537,6 +537,33 @@ class TestContract(TestContractBase):
'There was an error and the view couldn\'t be opened.', 'There was an error and the view couldn\'t be opened.',
) )
def test_get_default_recurring_invoicing_offset(self):
clm = self.env['contract.line']
self.assertEqual(
clm._get_default_recurring_invoicing_offset(
"pre-paid", "monthly"
),
0
)
self.assertEqual(
clm._get_default_recurring_invoicing_offset(
"post-paid", "monthly"
),
1
)
self.assertEqual(
clm._get_default_recurring_invoicing_offset(
"pre-paid", "monthlylastday"
),
0
)
self.assertEqual(
clm._get_default_recurring_invoicing_offset(
"post-paid", "monthlylastday"
),
0
)
def test_get_recurring_next_date(self): def test_get_recurring_next_date(self):
"""Test different combination to compute recurring_next_date """Test different combination to compute recurring_next_date
Combination format Combination format
@@ -555,87 +582,92 @@ class TestContract(TestContractBase):
def error_message( def error_message(
date_start, date_start,
recurring_invoicing_type, recurring_invoicing_type,
recurring_invoicing_offset,
recurring_rule_type, recurring_rule_type,
recurring_interval, recurring_interval,
max_date_end, max_date_end,
): ):
return "Error in %s every %d %s case, start with %s (max_date_end=%s)" % ( return (
recurring_invoicing_type, "Error in %s-%d every %d %s case, "
recurring_interval, "start with %s (max_date_end=%s)" % (
recurring_rule_type, recurring_invoicing_type,
date_start, recurring_invoicing_offset,
max_date_end, recurring_interval,
recurring_rule_type,
date_start,
max_date_end,
)
) )
combinations = [ combinations = [
( (
to_date('2018-01-01'), to_date('2018-01-01'),
(to_date('2018-01-01'), 'pre-paid', 'monthly', 1, (to_date('2018-01-01'), 'pre-paid', 0, 'monthly', 1,
False), False),
), ),
( (
to_date('2018-01-01'), to_date('2018-01-01'),
(to_date('2018-01-01'), 'pre-paid', 'monthly', 1, (to_date('2018-01-01'), 'pre-paid', 0, 'monthly', 1,
to_date('2018-01-15')), to_date('2018-01-15')),
), ),
( (
False, False,
(to_date('2018-01-16'), 'pre-paid', 'monthly', 1, (to_date('2018-01-16'), 'pre-paid', 0, 'monthly', 1,
to_date('2018-01-15')), to_date('2018-01-15')),
), ),
( (
to_date('2018-01-01'), to_date('2018-01-01'),
(to_date('2018-01-01'), 'pre-paid', 'monthly', 2, (to_date('2018-01-01'), 'pre-paid', 0, 'monthly', 2,
False), False),
), ),
( (
to_date('2018-02-01'), to_date('2018-02-01'),
(to_date('2018-01-01'), 'post-paid', 'monthly', 1, (to_date('2018-01-01'), 'post-paid', 1, 'monthly', 1,
False), False),
), ),
( (
to_date('2018-01-16'), to_date('2018-01-16'),
(to_date('2018-01-01'), 'post-paid', 'monthly', 1, (to_date('2018-01-01'), 'post-paid', 1, 'monthly', 1,
to_date('2018-01-15')), to_date('2018-01-15')),
), ),
( (
False, False,
(to_date('2018-01-16'), 'post-paid', 'monthly', 1, (to_date('2018-01-16'), 'post-paid', 1, 'monthly', 1,
to_date('2018-01-15')), to_date('2018-01-15')),
), ),
( (
to_date('2018-03-01'), to_date('2018-03-01'),
(to_date('2018-01-01'), 'post-paid', 'monthly', 2, (to_date('2018-01-01'), 'post-paid', 1, 'monthly', 2,
False), False),
), ),
( (
to_date('2018-01-31'), to_date('2018-01-31'),
(to_date('2018-01-05'), 'post-paid', 'monthlylastday', 1, (to_date('2018-01-05'), 'post-paid', 0, 'monthlylastday', 1,
False), False),
), ),
( (
to_date('2018-01-06'), to_date('2018-01-06'),
(to_date('2018-01-06'), 'pre-paid', 'monthlylastday', 1, (to_date('2018-01-06'), 'pre-paid', 0, 'monthlylastday', 1,
False), False),
), ),
( (
to_date('2018-02-28'), to_date('2018-02-28'),
(to_date('2018-01-05'), 'post-paid', 'monthlylastday', 2, (to_date('2018-01-05'), 'post-paid', 0, 'monthlylastday', 2,
False), False),
), ),
( (
to_date('2018-01-05'), to_date('2018-01-05'),
(to_date('2018-01-05'), 'pre-paid', 'monthlylastday', 2, (to_date('2018-01-05'), 'pre-paid', 0, 'monthlylastday', 2,
False), False),
), ),
( (
to_date('2018-01-05'), to_date('2018-01-05'),
(to_date('2018-01-05'), 'pre-paid', 'yearly', 1, (to_date('2018-01-05'), 'pre-paid', 0, 'yearly', 1,
False), False),
), ),
( (
to_date('2019-01-05'), to_date('2019-01-05'),
(to_date('2018-01-05'), 'post-paid', 'yearly', 1, (to_date('2018-01-05'), 'post-paid', 1, 'yearly', 1,
False), False),
), ),
] ]