mirror of
https://github.com/OCA/contract.git
synced 2025-02-13 17:57:24 +02:00
@@ -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).
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
10
contract/migrations/12.0.5.0.0/pre-migration.py
Normal file
10
contract/migrations/12.0.5.0.0/pre-migration.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
def migrate(cr, version):
|
||||||
|
# pre-paid/post-paid becomes significant for monthlylastday too,
|
||||||
|
# make sure it has the value that was implied for previous versions.
|
||||||
|
cr.execute(
|
||||||
|
"""\
|
||||||
|
UPDATE contract_line
|
||||||
|
SET recurring_invoicing_type = 'post-paid'
|
||||||
|
WHERE recurring_rule_type = 'monthlylastday'
|
||||||
|
"""
|
||||||
|
)
|
||||||
@@ -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 start 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',
|
||||||
|
|||||||
@@ -41,6 +41,14 @@ class ContractLine(models.Model):
|
|||||||
last_date_invoiced = fields.Date(
|
last_date_invoiced = fields.Date(
|
||||||
string='Last Date Invoiced', readonly=True, copy=False
|
string='Last Date Invoiced', readonly=True, copy=False
|
||||||
)
|
)
|
||||||
|
next_period_date_start = fields.Date(
|
||||||
|
string='Next Period Start',
|
||||||
|
compute='_compute_next_period_date_start',
|
||||||
|
)
|
||||||
|
next_period_date_end = fields.Date(
|
||||||
|
string='Next Period End',
|
||||||
|
compute='_compute_next_period_date_end',
|
||||||
|
)
|
||||||
termination_notice_date = fields.Date(
|
termination_notice_date = fields.Date(
|
||||||
string='Termination notice date',
|
string='Termination notice date',
|
||||||
compute="_compute_termination_notice_date",
|
compute="_compute_termination_notice_date",
|
||||||
@@ -361,20 +369,140 @@ class ContractLine(models.Model):
|
|||||||
date_start,
|
date_start,
|
||||||
recurring_invoicing_type,
|
recurring_invoicing_type,
|
||||||
recurring_rule_type,
|
recurring_rule_type,
|
||||||
recurring_interval,
|
recurring_interval
|
||||||
):
|
):
|
||||||
if recurring_rule_type == 'monthlylastday':
|
# deprecated method for backward compatibility
|
||||||
return date_start + self.get_relative_delta(
|
return self.get_next_invoice_date(
|
||||||
recurring_rule_type, recurring_interval - 1
|
date_start,
|
||||||
)
|
recurring_invoicing_type,
|
||||||
if recurring_invoicing_type == 'pre-paid':
|
self._get_default_recurring_invoicing_offset(
|
||||||
return date_start
|
recurring_invoicing_type, recurring_rule_type
|
||||||
return date_start + self.get_relative_delta(
|
),
|
||||||
recurring_rule_type, recurring_interval
|
recurring_rule_type,
|
||||||
|
recurring_interval,
|
||||||
|
max_date_end=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def compute_first_date_end(
|
def get_next_invoice_date(
|
||||||
|
self,
|
||||||
|
next_period_date_start,
|
||||||
|
recurring_invoicing_type,
|
||||||
|
recurring_invoicing_offset,
|
||||||
|
recurring_rule_type,
|
||||||
|
recurring_interval,
|
||||||
|
max_date_end,
|
||||||
|
):
|
||||||
|
next_period_date_end = self.get_next_period_date_end(
|
||||||
|
next_period_date_start,
|
||||||
|
recurring_rule_type,
|
||||||
|
recurring_interval,
|
||||||
|
max_date_end=max_date_end,
|
||||||
|
)
|
||||||
|
if not next_period_date_end:
|
||||||
|
return False
|
||||||
|
if recurring_invoicing_type == 'pre-paid':
|
||||||
|
recurring_next_date = (
|
||||||
|
next_period_date_start
|
||||||
|
+ relativedelta(days=recurring_invoicing_offset)
|
||||||
|
)
|
||||||
|
else: # post-paid
|
||||||
|
recurring_next_date = (
|
||||||
|
next_period_date_end
|
||||||
|
+ relativedelta(days=recurring_invoicing_offset)
|
||||||
|
)
|
||||||
|
return recurring_next_date
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def get_next_period_date_end(
|
||||||
|
self,
|
||||||
|
next_period_date_start,
|
||||||
|
recurring_rule_type,
|
||||||
|
recurring_interval,
|
||||||
|
max_date_end,
|
||||||
|
next_invoice_date=False,
|
||||||
|
recurring_invoicing_type=False,
|
||||||
|
recurring_invoicing_offset=False,
|
||||||
|
):
|
||||||
|
"""Compute the end date for the next period.
|
||||||
|
|
||||||
|
The next period normally depends on recurrence options only.
|
||||||
|
It is however possible to provide it a next invoice date, in
|
||||||
|
which case this method can adjust the next period based on that
|
||||||
|
too. In that scenario it required the invoicing type and offset
|
||||||
|
arguments.
|
||||||
|
"""
|
||||||
|
if not next_period_date_start:
|
||||||
|
return False
|
||||||
|
if max_date_end and next_period_date_start > max_date_end:
|
||||||
|
# start is past max date end: there is no next period
|
||||||
|
return False
|
||||||
|
if not next_invoice_date:
|
||||||
|
# regular algorithm
|
||||||
|
next_period_date_end = (
|
||||||
|
next_period_date_start
|
||||||
|
+ self.get_relative_delta(
|
||||||
|
recurring_rule_type, recurring_interval
|
||||||
|
)
|
||||||
|
- relativedelta(days=1)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# special algorithm when the next invoice date is forced
|
||||||
|
if recurring_invoicing_type == 'pre-paid':
|
||||||
|
next_period_date_end = (
|
||||||
|
next_invoice_date
|
||||||
|
- relativedelta(days=recurring_invoicing_offset)
|
||||||
|
+ self.get_relative_delta(
|
||||||
|
recurring_rule_type, recurring_interval
|
||||||
|
)
|
||||||
|
- relativedelta(days=1)
|
||||||
|
)
|
||||||
|
else: # post-paid
|
||||||
|
next_period_date_end = (
|
||||||
|
next_invoice_date
|
||||||
|
- relativedelta(days=recurring_invoicing_offset)
|
||||||
|
)
|
||||||
|
if max_date_end and next_period_date_end > max_date_end:
|
||||||
|
# end date is past max_date_end: trim it
|
||||||
|
next_period_date_end = max_date_end
|
||||||
|
return next_period_date_end
|
||||||
|
|
||||||
|
@api.depends('last_date_invoiced', 'date_start', 'date_end')
|
||||||
|
def _compute_next_period_date_start(self):
|
||||||
|
for rec in self:
|
||||||
|
if rec.last_date_invoiced:
|
||||||
|
next_period_date_start = (
|
||||||
|
rec.last_date_invoiced + relativedelta(days=1)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
next_period_date_start = rec.date_start
|
||||||
|
if rec.date_end and next_period_date_start > rec.date_end:
|
||||||
|
next_period_date_start = False
|
||||||
|
rec.next_period_date_start = next_period_date_start
|
||||||
|
|
||||||
|
@api.depends(
|
||||||
|
'next_period_date_start',
|
||||||
|
'recurring_invoicing_type',
|
||||||
|
'recurring_invoicing_offset',
|
||||||
|
'recurring_rule_type',
|
||||||
|
'recurring_interval',
|
||||||
|
'date_end',
|
||||||
|
'recurring_next_date',
|
||||||
|
)
|
||||||
|
def _compute_next_period_date_end(self):
|
||||||
|
for rec in self:
|
||||||
|
rec.next_period_date_end = self.get_next_period_date_end(
|
||||||
|
rec.next_period_date_start,
|
||||||
|
rec.recurring_rule_type,
|
||||||
|
rec.recurring_interval,
|
||||||
|
max_date_end=rec.date_end,
|
||||||
|
next_invoice_date=rec.recurring_next_date,
|
||||||
|
recurring_invoicing_type=rec.recurring_invoicing_type,
|
||||||
|
recurring_invoicing_offset=rec.recurring_invoicing_offset,
|
||||||
|
)
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def _get_first_date_end(
|
||||||
self, date_start, auto_renew_rule_type, auto_renew_interval
|
self, date_start, auto_renew_rule_type, auto_renew_interval
|
||||||
):
|
):
|
||||||
return (
|
return (
|
||||||
@@ -396,7 +524,7 @@ class ContractLine(models.Model):
|
|||||||
auto_renew"""
|
auto_renew"""
|
||||||
for rec in self.filtered('is_auto_renew'):
|
for rec in self.filtered('is_auto_renew'):
|
||||||
if rec.date_start:
|
if rec.date_start:
|
||||||
rec.date_end = self.compute_first_date_end(
|
rec.date_end = self._get_first_date_end(
|
||||||
rec.date_start,
|
rec.date_start,
|
||||||
rec.auto_renew_rule_type,
|
rec.auto_renew_rule_type,
|
||||||
rec.auto_renew_interval,
|
rec.auto_renew_interval,
|
||||||
@@ -404,17 +532,20 @@ class ContractLine(models.Model):
|
|||||||
|
|
||||||
@api.onchange(
|
@api.onchange(
|
||||||
'date_start',
|
'date_start',
|
||||||
|
'date_end',
|
||||||
'recurring_invoicing_type',
|
'recurring_invoicing_type',
|
||||||
'recurring_rule_type',
|
'recurring_rule_type',
|
||||||
'recurring_interval',
|
'recurring_interval',
|
||||||
)
|
)
|
||||||
def _onchange_date_start(self):
|
def _onchange_date_start(self):
|
||||||
for rec in self.filtered('date_start'):
|
for rec in self.filtered('date_start'):
|
||||||
rec.recurring_next_date = self._compute_first_recurring_next_date(
|
rec.recurring_next_date = self.get_next_invoice_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,
|
||||||
)
|
)
|
||||||
|
|
||||||
@api.constrains('is_canceled', 'is_auto_renew')
|
@api.constrains('is_canceled', 'is_auto_renew')
|
||||||
@@ -533,33 +664,25 @@ class ContractLine(models.Model):
|
|||||||
def _get_period_to_invoice(
|
def _get_period_to_invoice(
|
||||||
self, last_date_invoiced, recurring_next_date, stop_at_date_end=True
|
self, last_date_invoiced, recurring_next_date, stop_at_date_end=True
|
||||||
):
|
):
|
||||||
|
# TODO this method can now be removed, since
|
||||||
|
# TODO self.next_period_date_start/end have the same values
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
first_date_invoiced = False
|
|
||||||
if not recurring_next_date:
|
if not recurring_next_date:
|
||||||
return first_date_invoiced, last_date_invoiced, recurring_next_date
|
return False, False, False
|
||||||
first_date_invoiced = (
|
first_date_invoiced = (
|
||||||
last_date_invoiced + relativedelta(days=1)
|
last_date_invoiced + relativedelta(days=1)
|
||||||
if last_date_invoiced
|
if last_date_invoiced
|
||||||
else self.date_start
|
else self.date_start
|
||||||
)
|
)
|
||||||
if self.recurring_rule_type == 'monthlylastday':
|
last_date_invoiced = self.get_next_period_date_end(
|
||||||
last_date_invoiced = recurring_next_date
|
first_date_invoiced,
|
||||||
else:
|
self.recurring_rule_type,
|
||||||
if self.recurring_invoicing_type == 'pre-paid':
|
self.recurring_interval,
|
||||||
last_date_invoiced = (
|
max_date_end=(self.date_end if stop_at_date_end else False),
|
||||||
recurring_next_date
|
next_invoice_date=recurring_next_date,
|
||||||
+ self.get_relative_delta(
|
recurring_invoicing_type=self.recurring_invoicing_type,
|
||||||
self.recurring_rule_type, self.recurring_interval
|
recurring_invoicing_offset=self.recurring_invoicing_offset,
|
||||||
)
|
)
|
||||||
- relativedelta(days=1)
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
last_date_invoiced = recurring_next_date - relativedelta(
|
|
||||||
days=1
|
|
||||||
)
|
|
||||||
if stop_at_date_end:
|
|
||||||
if self.date_end and self.date_end < last_date_invoiced:
|
|
||||||
last_date_invoiced = self.date_end
|
|
||||||
return first_date_invoiced, last_date_invoiced, recurring_next_date
|
return first_date_invoiced, last_date_invoiced, recurring_next_date
|
||||||
|
|
||||||
@api.multi
|
@api.multi
|
||||||
@@ -580,23 +703,19 @@ class ContractLine(models.Model):
|
|||||||
@api.multi
|
@api.multi
|
||||||
def _update_recurring_next_date(self):
|
def _update_recurring_next_date(self):
|
||||||
for rec in self:
|
for rec in self:
|
||||||
old_date = rec.recurring_next_date
|
last_date_invoiced = rec.next_period_date_end
|
||||||
new_date = old_date + self.get_relative_delta(
|
recurring_next_date = rec.get_next_invoice_date(
|
||||||
rec.recurring_rule_type, rec.recurring_interval
|
last_date_invoiced + relativedelta(days=1),
|
||||||
|
rec.recurring_invoicing_type,
|
||||||
|
rec.recurring_invoicing_offset,
|
||||||
|
rec.recurring_rule_type,
|
||||||
|
rec.recurring_interval,
|
||||||
|
max_date_end=rec.date_end,
|
||||||
)
|
)
|
||||||
if rec.recurring_rule_type == 'monthlylastday':
|
rec.write({
|
||||||
last_date_invoiced = old_date
|
"recurring_next_date": recurring_next_date,
|
||||||
elif rec.recurring_invoicing_type == 'post-paid':
|
"last_date_invoiced": last_date_invoiced,
|
||||||
last_date_invoiced = old_date - relativedelta(days=1)
|
})
|
||||||
elif rec.recurring_invoicing_type == 'pre-paid':
|
|
||||||
last_date_invoiced = new_date - relativedelta(days=1)
|
|
||||||
|
|
||||||
if rec.date_end and last_date_invoiced >= rec.date_end:
|
|
||||||
rec.last_date_invoiced = rec.date_end
|
|
||||||
rec.recurring_next_date = False
|
|
||||||
else:
|
|
||||||
rec.last_date_invoiced = last_date_invoiced
|
|
||||||
rec.recurring_next_date = new_date
|
|
||||||
|
|
||||||
@api.multi
|
@api.multi
|
||||||
def _init_last_date_invoiced(self):
|
def _init_last_date_invoiced(self):
|
||||||
@@ -609,8 +728,9 @@ class ContractLine(models.Model):
|
|||||||
last_date_invoiced = (
|
last_date_invoiced = (
|
||||||
rec.recurring_next_date
|
rec.recurring_next_date
|
||||||
- self.get_relative_delta(
|
- self.get_relative_delta(
|
||||||
rec.recurring_rule_type, rec.recurring_interval
|
rec.recurring_rule_type, rec.recurring_interval - 1
|
||||||
)
|
)
|
||||||
|
- relativedelta(days=1)
|
||||||
)
|
)
|
||||||
elif rec.recurring_invoicing_type == 'post-paid':
|
elif rec.recurring_invoicing_type == 'post-paid':
|
||||||
last_date_invoiced = (
|
last_date_invoiced = (
|
||||||
@@ -618,12 +738,18 @@ class ContractLine(models.Model):
|
|||||||
- self.get_relative_delta(
|
- self.get_relative_delta(
|
||||||
rec.recurring_rule_type, rec.recurring_interval
|
rec.recurring_rule_type, rec.recurring_interval
|
||||||
)
|
)
|
||||||
) - relativedelta(days=1)
|
- relativedelta(days=1)
|
||||||
|
)
|
||||||
if last_date_invoiced > rec.date_start:
|
if last_date_invoiced > rec.date_start:
|
||||||
rec.last_date_invoiced = last_date_invoiced
|
rec.last_date_invoiced = last_date_invoiced
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def get_relative_delta(self, recurring_rule_type, interval):
|
def get_relative_delta(self, recurring_rule_type, interval):
|
||||||
|
"""Return a relativedelta for one period.
|
||||||
|
|
||||||
|
When added to the first day of the period,
|
||||||
|
it gives the first day of the next period.
|
||||||
|
"""
|
||||||
if recurring_rule_type == 'daily':
|
if recurring_rule_type == 'daily':
|
||||||
return relativedelta(days=interval)
|
return relativedelta(days=interval)
|
||||||
elif recurring_rule_type == 'weekly':
|
elif recurring_rule_type == 'weekly':
|
||||||
@@ -631,7 +757,7 @@ class ContractLine(models.Model):
|
|||||||
elif recurring_rule_type == 'monthly':
|
elif recurring_rule_type == 'monthly':
|
||||||
return relativedelta(months=interval)
|
return relativedelta(months=interval)
|
||||||
elif recurring_rule_type == 'monthlylastday':
|
elif recurring_rule_type == 'monthlylastday':
|
||||||
return relativedelta(months=interval, day=31)
|
return relativedelta(months=interval, day=1)
|
||||||
else:
|
else:
|
||||||
return relativedelta(years=interval)
|
return relativedelta(years=interval)
|
||||||
|
|
||||||
@@ -651,15 +777,23 @@ class ContractLine(models.Model):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
new_date_start = rec.date_start + delay_delta
|
new_date_start = rec.date_start + delay_delta
|
||||||
rec.recurring_next_date = self._compute_first_recurring_next_date(
|
if rec.date_end:
|
||||||
|
new_date_end = rec.date_end + delay_delta
|
||||||
|
else:
|
||||||
|
new_date_end = False
|
||||||
|
new_recurring_next_date = self.get_next_invoice_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
|
||||||
)
|
)
|
||||||
if rec.date_end:
|
rec.write({
|
||||||
rec.date_end += delay_delta
|
"date_start": new_date_start,
|
||||||
rec.date_start = new_date_start
|
"date_end": new_date_end,
|
||||||
|
"recurring_next_date": new_recurring_next_date,
|
||||||
|
})
|
||||||
|
|
||||||
@api.multi
|
@api.multi
|
||||||
def stop(self, date_end, manual_renew_needed=False, post_message=True):
|
def stop(self, date_end, manual_renew_needed=False, post_message=True):
|
||||||
@@ -712,11 +846,13 @@ class ContractLine(models.Model):
|
|||||||
):
|
):
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
if not recurring_next_date:
|
if not recurring_next_date:
|
||||||
recurring_next_date = self._compute_first_recurring_next_date(
|
recurring_next_date = self.get_next_invoice_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,
|
||||||
)
|
)
|
||||||
new_vals = self.read()[0]
|
new_vals = self.read()[0]
|
||||||
new_vals.pop("id", None)
|
new_vals.pop("id", None)
|
||||||
@@ -1023,7 +1159,7 @@ class ContractLine(models.Model):
|
|||||||
def _get_renewal_dates(self):
|
def _get_renewal_dates(self):
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
date_start = self.date_end + relativedelta(days=1)
|
date_start = self.date_end + relativedelta(days=1)
|
||||||
date_end = self.compute_first_date_end(
|
date_end = self._get_first_date_end(
|
||||||
date_start, self.auto_renew_rule_type, self.auto_renew_interval
|
date_start, self.auto_renew_rule_type, self.auto_renew_interval
|
||||||
)
|
)
|
||||||
return date_start, date_end
|
return date_start, date_end
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
# Copyright 2018 Tecnativa - Pedro M. Baeza
|
# Copyright 2018 Tecnativa - Pedro M. Baeza
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
|
from collections import namedtuple
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from dateutil.relativedelta import relativedelta
|
from dateutil.relativedelta import relativedelta
|
||||||
from odoo import fields
|
from odoo import fields
|
||||||
@@ -247,7 +248,7 @@ class TestContract(TestContractBase):
|
|||||||
self.assertEqual(self.acct_line.last_date_invoiced, last_date_invoiced)
|
self.assertEqual(self.acct_line.last_date_invoiced, last_date_invoiced)
|
||||||
|
|
||||||
def test_contract_monthly_lastday(self):
|
def test_contract_monthly_lastday(self):
|
||||||
recurring_next_date = to_date('2018-03-31')
|
recurring_next_date = to_date('2018-02-28')
|
||||||
last_date_invoiced = to_date('2018-02-22')
|
last_date_invoiced = to_date('2018-02-22')
|
||||||
self.acct_line.recurring_next_date = '2018-02-22'
|
self.acct_line.recurring_next_date = '2018-02-22'
|
||||||
self.acct_line.recurring_invoicing_type = 'post-paid'
|
self.acct_line.recurring_invoicing_type = 'post-paid'
|
||||||
@@ -279,7 +280,7 @@ class TestContract(TestContractBase):
|
|||||||
)
|
)
|
||||||
self.contract.recurring_create_invoice()
|
self.contract.recurring_create_invoice()
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.acct_line.recurring_next_date, to_date('2018-04-01')
|
self.acct_line.recurring_next_date, to_date('2018-3-16')
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.acct_line.last_date_invoiced, to_date('2018-02-28')
|
self.acct_line.last_date_invoiced, to_date('2018-02-28')
|
||||||
@@ -537,7 +538,34 @@ 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_compute_first_recurring_next_date(self):
|
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_next_invoice_date(self):
|
||||||
"""Test different combination to compute recurring_next_date
|
"""Test different combination to compute recurring_next_date
|
||||||
Combination format
|
Combination format
|
||||||
{
|
{
|
||||||
@@ -547,6 +575,7 @@ class TestContract(TestContractBase):
|
|||||||
recurring_rule_type, # ('daily', 'weekly', 'monthly',
|
recurring_rule_type, # ('daily', 'weekly', 'monthly',
|
||||||
# 'monthlylastday', 'yearly'),
|
# 'monthlylastday', 'yearly'),
|
||||||
recurring_interval, # integer
|
recurring_interval, # integer
|
||||||
|
max_date_end, # date
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
@@ -554,64 +583,415 @@ 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,
|
||||||
):
|
):
|
||||||
return "Error in %s every %d %s case, start with %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,
|
||||||
|
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),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
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', 1,
|
||||||
|
to_date('2018-01-15')),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
False,
|
||||||
|
(to_date('2018-01-16'), 'pre-paid', 0, 'monthly', 1,
|
||||||
|
to_date('2018-01-15')),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
to_date('2018-01-01'),
|
||||||
|
(to_date('2018-01-01'), 'pre-paid', 0, 'monthly', 2,
|
||||||
|
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),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
to_date('2018-01-16'),
|
||||||
|
(to_date('2018-01-01'), 'post-paid', 1, 'monthly', 1,
|
||||||
|
to_date('2018-01-15')),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
False,
|
||||||
|
(to_date('2018-01-16'), 'post-paid', 1, 'monthly', 1,
|
||||||
|
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),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
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),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
to_date('2018-01-31'),
|
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),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
to_date('2018-02-28'),
|
to_date('2018-02-28'),
|
||||||
(to_date('2018-01-05'), 'pre-paid', 'monthlylastday', 2),
|
(to_date('2018-01-05'), 'post-paid', 0, 'monthlylastday', 2,
|
||||||
|
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, 'monthlylastday', 2,
|
||||||
|
False),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
to_date('2018-01-05'),
|
||||||
|
(to_date('2018-01-05'), 'pre-paid', 0, 'yearly', 1,
|
||||||
|
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),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
contract_line_env = self.env['contract.line']
|
contract_line_env = self.env['contract.line']
|
||||||
for recurring_next_date, combination in combinations:
|
for recurring_next_date, combination in combinations:
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
recurring_next_date,
|
recurring_next_date,
|
||||||
contract_line_env._compute_first_recurring_next_date(
|
contract_line_env.get_next_invoice_date(
|
||||||
*combination
|
*combination
|
||||||
),
|
),
|
||||||
error_message(*combination),
|
error_message(*combination),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_next_invoicing_period(self):
|
||||||
|
"""Test different combination for next invoicing period
|
||||||
|
{
|
||||||
|
(
|
||||||
|
'recurring_next_date', # date
|
||||||
|
'next_period_date_start', # date
|
||||||
|
'next_period_date_end' # date
|
||||||
|
): (
|
||||||
|
date_start, # date
|
||||||
|
date_end, # date
|
||||||
|
last_date_invoiced, # date
|
||||||
|
recurring_next_date, # date
|
||||||
|
recurring_invoicing_type, # ('pre-paid','post-paid',)
|
||||||
|
recurring_rule_type, # ('daily', 'weekly', 'monthly',
|
||||||
|
# 'monthlylastday', 'yearly'),
|
||||||
|
recurring_interval, # integer
|
||||||
|
max_date_end, # date
|
||||||
|
),
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
def _update_contract_line(
|
||||||
|
case,
|
||||||
|
date_start,
|
||||||
|
date_end,
|
||||||
|
last_date_invoiced,
|
||||||
|
recurring_next_date,
|
||||||
|
recurring_invoicing_type,
|
||||||
|
recurring_rule_type,
|
||||||
|
recurring_interval,
|
||||||
|
max_date_end,
|
||||||
|
):
|
||||||
|
self.acct_line.write(
|
||||||
|
{
|
||||||
|
'date_start': date_start,
|
||||||
|
'date_end': date_end,
|
||||||
|
'last_date_invoiced': last_date_invoiced,
|
||||||
|
'recurring_next_date': recurring_next_date,
|
||||||
|
'recurring_invoicing_type': recurring_invoicing_type,
|
||||||
|
'recurring_rule_type': recurring_rule_type,
|
||||||
|
'recurring_interval': recurring_interval,
|
||||||
|
'max_date_end': max_date_end,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
def _get_result():
|
||||||
|
return Result(
|
||||||
|
recurring_next_date=self.acct_line.recurring_next_date,
|
||||||
|
next_period_date_start=self.acct_line.next_period_date_start,
|
||||||
|
next_period_date_end=self.acct_line.next_period_date_end,
|
||||||
|
)
|
||||||
|
|
||||||
|
def _error_message(
|
||||||
|
case,
|
||||||
|
date_start,
|
||||||
|
date_end,
|
||||||
|
last_date_invoiced,
|
||||||
|
recurring_next_date,
|
||||||
|
recurring_invoicing_type,
|
||||||
|
recurring_rule_type,
|
||||||
|
recurring_interval,
|
||||||
|
max_date_end,
|
||||||
|
):
|
||||||
|
return (
|
||||||
|
"Error in case %s:"
|
||||||
|
"date_start: %s, "
|
||||||
|
"date_end: %s, "
|
||||||
|
"last_date_invoiced: %s, "
|
||||||
|
"recurring_next_date: %s, "
|
||||||
|
"recurring_invoicing_type: %s, "
|
||||||
|
"recurring_rule_type: %s, "
|
||||||
|
"recurring_interval: %s, "
|
||||||
|
"max_date_end: %s, "
|
||||||
|
) % (
|
||||||
|
case,
|
||||||
|
date_start,
|
||||||
|
date_end,
|
||||||
|
last_date_invoiced,
|
||||||
|
recurring_next_date,
|
||||||
|
recurring_invoicing_type,
|
||||||
|
recurring_rule_type,
|
||||||
|
recurring_interval,
|
||||||
|
max_date_end,
|
||||||
|
)
|
||||||
|
|
||||||
|
Result = namedtuple(
|
||||||
|
'Result',
|
||||||
|
[
|
||||||
|
'recurring_next_date',
|
||||||
|
'next_period_date_start',
|
||||||
|
'next_period_date_end',
|
||||||
|
],
|
||||||
|
)
|
||||||
|
Combination = namedtuple(
|
||||||
|
'Combination',
|
||||||
|
[
|
||||||
|
'case',
|
||||||
|
'date_start',
|
||||||
|
'date_end',
|
||||||
|
'last_date_invoiced',
|
||||||
|
'recurring_next_date',
|
||||||
|
'recurring_invoicing_type',
|
||||||
|
'recurring_rule_type',
|
||||||
|
'recurring_interval',
|
||||||
|
'max_date_end',
|
||||||
|
],
|
||||||
|
)
|
||||||
|
combinations = {
|
||||||
|
Result(
|
||||||
|
recurring_next_date=to_date('2019-01-01'),
|
||||||
|
next_period_date_start=to_date('2019-01-01'),
|
||||||
|
next_period_date_end=to_date('2019-01-31'),
|
||||||
|
): Combination(
|
||||||
|
case="1",
|
||||||
|
date_start='2019-01-01',
|
||||||
|
date_end=False,
|
||||||
|
last_date_invoiced=False,
|
||||||
|
recurring_next_date='2019-01-01',
|
||||||
|
recurring_invoicing_type='pre-paid',
|
||||||
|
recurring_rule_type='monthly',
|
||||||
|
recurring_interval=1,
|
||||||
|
max_date_end=False,
|
||||||
|
),
|
||||||
|
Result(
|
||||||
|
recurring_next_date=to_date('2019-01-01'),
|
||||||
|
next_period_date_start=to_date('2019-01-01'),
|
||||||
|
next_period_date_end=to_date('2019-01-15'),
|
||||||
|
): Combination(
|
||||||
|
case="2",
|
||||||
|
date_start='2019-01-01',
|
||||||
|
date_end='2019-01-15',
|
||||||
|
last_date_invoiced=False,
|
||||||
|
recurring_next_date='2019-01-01',
|
||||||
|
recurring_invoicing_type='pre-paid',
|
||||||
|
recurring_rule_type='monthly',
|
||||||
|
recurring_interval=1,
|
||||||
|
max_date_end=False,
|
||||||
|
),
|
||||||
|
Result(
|
||||||
|
recurring_next_date=to_date('2019-01-05'),
|
||||||
|
next_period_date_start=to_date('2019-01-05'),
|
||||||
|
next_period_date_end=to_date('2019-01-15'),
|
||||||
|
): Combination(
|
||||||
|
case="3",
|
||||||
|
date_start='2019-01-05',
|
||||||
|
date_end='2019-01-15',
|
||||||
|
last_date_invoiced=False,
|
||||||
|
recurring_next_date='2019-01-05',
|
||||||
|
recurring_invoicing_type='pre-paid',
|
||||||
|
recurring_rule_type='monthly',
|
||||||
|
recurring_interval=1,
|
||||||
|
max_date_end=False,
|
||||||
|
),
|
||||||
|
Result(
|
||||||
|
recurring_next_date=to_date('2019-01-05'),
|
||||||
|
next_period_date_start=to_date('2019-01-01'),
|
||||||
|
next_period_date_end=to_date('2019-01-15'),
|
||||||
|
): Combination(
|
||||||
|
case="4",
|
||||||
|
date_start='2019-01-01',
|
||||||
|
date_end='2019-01-15',
|
||||||
|
last_date_invoiced=False,
|
||||||
|
recurring_next_date='2019-01-05',
|
||||||
|
recurring_invoicing_type='pre-paid',
|
||||||
|
recurring_rule_type='monthly',
|
||||||
|
recurring_interval=1,
|
||||||
|
max_date_end=False,
|
||||||
|
),
|
||||||
|
Result(
|
||||||
|
recurring_next_date=to_date('2019-02-01'),
|
||||||
|
next_period_date_start=to_date('2019-01-01'),
|
||||||
|
next_period_date_end=to_date('2019-01-31'),
|
||||||
|
): Combination(
|
||||||
|
case="5",
|
||||||
|
date_start='2019-01-01',
|
||||||
|
date_end=False,
|
||||||
|
last_date_invoiced=False,
|
||||||
|
recurring_next_date='2019-02-01',
|
||||||
|
recurring_invoicing_type='post-paid',
|
||||||
|
recurring_rule_type='monthly',
|
||||||
|
recurring_interval=1,
|
||||||
|
max_date_end=False,
|
||||||
|
),
|
||||||
|
Result(
|
||||||
|
recurring_next_date=to_date('2019-02-01'),
|
||||||
|
next_period_date_start=to_date('2019-01-01'),
|
||||||
|
next_period_date_end=to_date('2019-01-15'),
|
||||||
|
): Combination(
|
||||||
|
case="6",
|
||||||
|
date_start='2019-01-01',
|
||||||
|
date_end='2019-01-15',
|
||||||
|
last_date_invoiced=False,
|
||||||
|
recurring_next_date='2019-02-01',
|
||||||
|
recurring_invoicing_type='post-paid',
|
||||||
|
recurring_rule_type='monthly',
|
||||||
|
recurring_interval=1,
|
||||||
|
max_date_end=False,
|
||||||
|
),
|
||||||
|
Result(
|
||||||
|
recurring_next_date=to_date('2019-02-01'),
|
||||||
|
next_period_date_start=to_date('2019-01-05'),
|
||||||
|
next_period_date_end=to_date('2019-01-31'),
|
||||||
|
): Combination(
|
||||||
|
case="7",
|
||||||
|
date_start='2019-01-05',
|
||||||
|
date_end=False,
|
||||||
|
last_date_invoiced=False,
|
||||||
|
recurring_next_date='2019-02-01',
|
||||||
|
recurring_invoicing_type='post-paid',
|
||||||
|
recurring_rule_type='monthly',
|
||||||
|
recurring_interval=1,
|
||||||
|
max_date_end=False,
|
||||||
|
),
|
||||||
|
Result(
|
||||||
|
recurring_next_date=to_date('2019-01-05'),
|
||||||
|
next_period_date_start=to_date('2019-01-01'),
|
||||||
|
next_period_date_end=to_date('2019-01-15'),
|
||||||
|
): Combination(
|
||||||
|
case="8",
|
||||||
|
date_start='2019-01-01',
|
||||||
|
date_end='2019-01-15',
|
||||||
|
last_date_invoiced=False,
|
||||||
|
recurring_next_date='2019-01-05',
|
||||||
|
recurring_invoicing_type='pre-paid',
|
||||||
|
recurring_rule_type='monthly',
|
||||||
|
recurring_interval=1,
|
||||||
|
max_date_end=False,
|
||||||
|
),
|
||||||
|
Result(
|
||||||
|
recurring_next_date=to_date('2019-01-01'),
|
||||||
|
next_period_date_start=to_date('2018-12-16'),
|
||||||
|
next_period_date_end=to_date('2019-01-31'),
|
||||||
|
): Combination(
|
||||||
|
case="9",
|
||||||
|
date_start='2018-01-01',
|
||||||
|
date_end='2020-01-15',
|
||||||
|
last_date_invoiced='2018-12-15',
|
||||||
|
recurring_next_date='2019-01-01',
|
||||||
|
recurring_invoicing_type='pre-paid',
|
||||||
|
recurring_rule_type='monthly',
|
||||||
|
recurring_interval=1,
|
||||||
|
max_date_end=False,
|
||||||
|
),
|
||||||
|
Result(
|
||||||
|
recurring_next_date=to_date('2019-01-01'),
|
||||||
|
next_period_date_start=to_date('2018-12-16'),
|
||||||
|
next_period_date_end=to_date('2018-12-31'),
|
||||||
|
): Combination(
|
||||||
|
case="10",
|
||||||
|
date_start='2018-01-01',
|
||||||
|
date_end='2020-01-15',
|
||||||
|
last_date_invoiced='2018-12-15',
|
||||||
|
recurring_next_date='2019-01-01',
|
||||||
|
recurring_invoicing_type='post-paid',
|
||||||
|
recurring_rule_type='monthly',
|
||||||
|
recurring_interval=1,
|
||||||
|
max_date_end=False,
|
||||||
|
),
|
||||||
|
Result(
|
||||||
|
recurring_next_date=to_date('2018-12-31'),
|
||||||
|
next_period_date_start=to_date('2018-12-16'),
|
||||||
|
next_period_date_end=to_date('2018-12-31'),
|
||||||
|
): Combination(
|
||||||
|
case="11",
|
||||||
|
date_start='2018-01-01',
|
||||||
|
date_end='2020-01-15',
|
||||||
|
last_date_invoiced='2018-12-15',
|
||||||
|
recurring_next_date='2018-12-31',
|
||||||
|
recurring_invoicing_type='post-paid',
|
||||||
|
recurring_rule_type='monthlylastday',
|
||||||
|
recurring_interval=1,
|
||||||
|
max_date_end=False,
|
||||||
|
),
|
||||||
|
Result(
|
||||||
|
recurring_next_date=to_date('2018-12-16'),
|
||||||
|
next_period_date_start=to_date('2018-12-16'),
|
||||||
|
next_period_date_end=to_date('2018-12-31'),
|
||||||
|
): Combination(
|
||||||
|
case="12",
|
||||||
|
date_start='2018-01-01',
|
||||||
|
date_end='2020-01-15',
|
||||||
|
last_date_invoiced='2018-12-15',
|
||||||
|
recurring_next_date='2018-12-16',
|
||||||
|
recurring_invoicing_type='pre-paid',
|
||||||
|
recurring_rule_type='monthlylastday',
|
||||||
|
recurring_interval=1,
|
||||||
|
max_date_end=False,
|
||||||
|
),
|
||||||
|
Result(
|
||||||
|
recurring_next_date=to_date('2018-01-05'),
|
||||||
|
next_period_date_start=to_date('2018-01-05'),
|
||||||
|
next_period_date_end=to_date('2018-03-31'),
|
||||||
|
): Combination(
|
||||||
|
case="12",
|
||||||
|
date_start='2018-01-05',
|
||||||
|
date_end='2020-01-15',
|
||||||
|
last_date_invoiced=False,
|
||||||
|
recurring_next_date='2018-01-05',
|
||||||
|
recurring_invoicing_type='pre-paid',
|
||||||
|
recurring_rule_type='monthlylastday',
|
||||||
|
recurring_interval=3,
|
||||||
|
max_date_end=False,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
for result, combination in combinations.items():
|
||||||
|
_update_contract_line(*combination)
|
||||||
|
self.assertEqual(
|
||||||
|
result, _get_result(), _error_message(*combination)
|
||||||
|
)
|
||||||
|
|
||||||
def test_recurring_next_date(self):
|
def test_recurring_next_date(self):
|
||||||
"""recurring next date for a contract is the min for all lines"""
|
"""recurring next date for a contract is the min for all lines"""
|
||||||
self.contract.recurring_create_invoice()
|
self.contract.recurring_create_invoice()
|
||||||
@@ -1331,7 +1711,7 @@ class TestContract(TestContractBase):
|
|||||||
len(invoice_lines),
|
len(invoice_lines),
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_get_period_to_invoice_monthlylastday(self):
|
def test_get_period_to_invoice_monthlylastday_postpaid(self):
|
||||||
self.acct_line.date_start = '2018-01-05'
|
self.acct_line.date_start = '2018-01-05'
|
||||||
self.acct_line.recurring_invoicing_type = 'post-paid'
|
self.acct_line.recurring_invoicing_type = 'post-paid'
|
||||||
self.acct_line.recurring_rule_type = 'monthlylastday'
|
self.acct_line.recurring_rule_type = 'monthlylastday'
|
||||||
@@ -1362,6 +1742,67 @@ class TestContract(TestContractBase):
|
|||||||
self.assertEqual(last, to_date('2018-03-15'))
|
self.assertEqual(last, to_date('2018-03-15'))
|
||||||
self.acct_line.manual_renew_needed = True
|
self.acct_line.manual_renew_needed = True
|
||||||
|
|
||||||
|
def test_get_period_to_invoice_monthlylastday_prepaid(self):
|
||||||
|
self.acct_line.date_start = '2018-01-05'
|
||||||
|
self.acct_line.recurring_invoicing_type = 'pre-paid'
|
||||||
|
self.acct_line.recurring_rule_type = 'monthlylastday'
|
||||||
|
self.acct_line.date_end = '2018-03-15'
|
||||||
|
self.acct_line._onchange_date_start()
|
||||||
|
first, last, recurring_next_date = \
|
||||||
|
self.acct_line._get_period_to_invoice(
|
||||||
|
self.acct_line.last_date_invoiced,
|
||||||
|
self.acct_line.recurring_next_date,
|
||||||
|
)
|
||||||
|
self.assertEqual(first, to_date('2018-01-05'))
|
||||||
|
self.assertEqual(last, to_date('2018-01-31'))
|
||||||
|
self.assertEqual(recurring_next_date, to_date('2018-01-05'))
|
||||||
|
self.assertEqual(
|
||||||
|
self.acct_line.recurring_next_date, to_date('2018-01-05')
|
||||||
|
)
|
||||||
|
self.contract.recurring_create_invoice()
|
||||||
|
first, last, recurring_next_date = \
|
||||||
|
self.acct_line._get_period_to_invoice(
|
||||||
|
self.acct_line.last_date_invoiced,
|
||||||
|
self.acct_line.recurring_next_date,
|
||||||
|
)
|
||||||
|
self.assertEqual(first, to_date('2018-02-01'))
|
||||||
|
self.assertEqual(last, to_date('2018-02-28'))
|
||||||
|
self.assertEqual(recurring_next_date, to_date('2018-02-01'))
|
||||||
|
self.assertEqual(
|
||||||
|
self.acct_line.recurring_next_date, to_date('2018-02-01')
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
self.acct_line.last_date_invoiced, to_date('2018-01-31')
|
||||||
|
)
|
||||||
|
self.contract.recurring_create_invoice()
|
||||||
|
first, last, recurring_next_date = \
|
||||||
|
self.acct_line._get_period_to_invoice(
|
||||||
|
self.acct_line.last_date_invoiced,
|
||||||
|
self.acct_line.recurring_next_date,
|
||||||
|
)
|
||||||
|
self.assertEqual(first, to_date('2018-03-01'))
|
||||||
|
self.assertEqual(last, to_date('2018-03-15'))
|
||||||
|
self.assertEqual(recurring_next_date, to_date('2018-03-01'))
|
||||||
|
self.assertEqual(
|
||||||
|
self.acct_line.recurring_next_date, to_date('2018-03-01')
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
self.acct_line.last_date_invoiced, to_date('2018-02-28')
|
||||||
|
)
|
||||||
|
self.contract.recurring_create_invoice()
|
||||||
|
first, last, recurring_next_date = \
|
||||||
|
self.acct_line._get_period_to_invoice(
|
||||||
|
self.acct_line.last_date_invoiced,
|
||||||
|
self.acct_line.recurring_next_date,
|
||||||
|
)
|
||||||
|
self.assertFalse(first)
|
||||||
|
self.assertFalse(last)
|
||||||
|
self.assertFalse(recurring_next_date)
|
||||||
|
self.assertFalse(self.acct_line.recurring_next_date)
|
||||||
|
self.assertEqual(
|
||||||
|
self.acct_line.last_date_invoiced, to_date('2018-03-15')
|
||||||
|
)
|
||||||
|
|
||||||
def test_get_period_to_invoice_monthly_pre_paid_2(self):
|
def test_get_period_to_invoice_monthly_pre_paid_2(self):
|
||||||
self.acct_line.date_start = '2018-01-05'
|
self.acct_line.date_start = '2018-01-05'
|
||||||
self.acct_line.recurring_invoicing_type = 'pre-paid'
|
self.acct_line.recurring_invoicing_type = 'pre-paid'
|
||||||
|
|||||||
@@ -59,8 +59,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<field name="recurring_invoicing_type"
|
<field name="recurring_invoicing_type"/>
|
||||||
attrs="{'invisible': [('recurring_rule_type', '=', 'monthlylastday')]}"/>
|
<field name="recurring_invoicing_offset"/>
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
</sheet>
|
</sheet>
|
||||||
|
|||||||
@@ -15,11 +15,13 @@
|
|||||||
<group>
|
<group>
|
||||||
<field name="create_invoice_visibility" invisible="1"/>
|
<field name="create_invoice_visibility" invisible="1"/>
|
||||||
<field name="date_start" required="1"/>
|
<field name="date_start" required="1"/>
|
||||||
|
<field name="next_period_date_start"/>
|
||||||
<field name="recurring_next_date"/>
|
<field name="recurring_next_date"/>
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<field name="date_end"
|
<field name="date_end"
|
||||||
attrs="{'required': [('is_auto_renew', '=', True)]}"/>
|
attrs="{'required': [('is_auto_renew', '=', True)]}"/>
|
||||||
|
<field name="next_period_date_end"/>
|
||||||
</group>
|
</group>
|
||||||
<group groups="base.group_no_one">
|
<group groups="base.group_no_one">
|
||||||
<field name="last_date_invoiced" readonly="True"/>
|
<field name="last_date_invoiced" readonly="True"/>
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ class TestContractSaleMandate(TestContractBase):
|
|||||||
'is_contract': True,
|
'is_contract': True,
|
||||||
'default_qty': 12,
|
'default_qty': 12,
|
||||||
'recurring_rule_type': "monthlylastday",
|
'recurring_rule_type': "monthlylastday",
|
||||||
|
'recurring_invoicing_type': "post-paid",
|
||||||
'contract_template_id': cls.contract_template1.id,
|
'contract_template_id': cls.contract_template1.id,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
10
product_contract/migrations/12.0.3.0.0/pre-migration.py
Normal file
10
product_contract/migrations/12.0.3.0.0/pre-migration.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
def migrate(cr, version):
|
||||||
|
# pre-paid/post-paid becomes significant for monthlylastday too,
|
||||||
|
# make sure it has the value that was implied for previous versions.
|
||||||
|
cr.execute(
|
||||||
|
"""\
|
||||||
|
UPDATE product_template
|
||||||
|
SET recurring_invoicing_type = 'post-paid'
|
||||||
|
WHERE recurring_rule_type = 'monthlylastday'
|
||||||
|
"""
|
||||||
|
)
|
||||||
@@ -43,6 +43,7 @@ class TestSaleOrder(TransactionCase):
|
|||||||
'is_contract': True,
|
'is_contract': True,
|
||||||
'default_qty': 12,
|
'default_qty': 12,
|
||||||
'recurring_rule_type': "monthlylastday",
|
'recurring_rule_type': "monthlylastday",
|
||||||
|
'recurring_invoicing_type': "post-paid",
|
||||||
'contract_template_id': self.contract_template1.id,
|
'contract_template_id': self.contract_template1.id,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -33,8 +33,7 @@
|
|||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<field name="default_qty"/>
|
<field name="default_qty"/>
|
||||||
<field name="recurring_invoicing_type"
|
<field name="recurring_invoicing_type"/>
|
||||||
attrs="{'invisible': [('recurring_rule_type', '=', 'monthlylastday')]}"/>
|
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
|
|||||||
@@ -58,8 +58,7 @@
|
|||||||
<field name="recurring_rule_type"/>
|
<field name="recurring_rule_type"/>
|
||||||
</group>
|
</group>
|
||||||
<group attrs="{'invisible': [('is_contract', '=', False)]}">
|
<group attrs="{'invisible': [('is_contract', '=', False)]}">
|
||||||
<field name="recurring_invoicing_type"
|
<field name="recurring_invoicing_type"/>
|
||||||
attrs="{'invisible': [('recurring_rule_type', '=', 'monthlylastday')]}"/>
|
|
||||||
</group>
|
</group>
|
||||||
<group attrs="{'invisible': [('is_contract', '=', False)]}">
|
<group attrs="{'invisible': [('is_contract', '=', False)]}">
|
||||||
<field name="date_start"
|
<field name="date_start"
|
||||||
|
|||||||
Reference in New Issue
Block a user