Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[12.0][IMP][WIP] - Contract: Add a new field to compute the next period end date #1

Open
wants to merge 2 commits into
base: 12.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion contract/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

{
'name': 'Recurring - Contracts Management',
'version': '12.0.4.2.5',
'version': '12.0.5.0.0',
'category': 'Contract Management',
'license': 'AGPL-3',
'author': "OpenERP SA, "
Expand Down
29 changes: 29 additions & 0 deletions contract/migrations/12.0.5.0.0/post-migration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Copyright 2019 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

import logging
from dateutil.relativedelta import relativedelta
from odoo import api, SUPERUSER_ID

_logger = logging.getLogger(__name__)


def migrate(cr, version):
_logger.info("Init next_period_end_date field")
with api.Environment.manage():
env = api.Environment(cr, SUPERUSER_ID, {})
cl_model = env['contract.line']
contract_lines = cl_model.search([])
for cl in contract_lines:
if cl.date_end and cl.last_date_invoiced == cl.date_end:
continue # Finished lines
next_period_start_date = (
cl.last_date_invoiced + relativedelta(days=1)
if cl.last_date_invoiced
else cl.date_start
)
cl.next_period_end_date = cl_model._get_next_period_end_date(
next_period_start_date,
cl.recurring_rule_type,
cl.recurring_interval,
)
169 changes: 128 additions & 41 deletions contract/models/contract_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,22 @@ class ContractLine(models.Model):
default=lambda self: fields.Date.context_today(self),
)
date_end = fields.Date(string='Date End', index=True)
recurring_next_date = fields.Date(string='Date of Next Invoice')
recurring_next_date = fields.Date(
string='Date of Next Invoice',
compute='_compute_recurring_next_date',
inverse='_inverse_recurring_next_date',
store=True,
)
last_date_invoiced = fields.Date(
string='Last Date Invoiced', readonly=True, copy=False
)
next_period_start_date = fields.Date(
string='Next Period Start Date',
compute='_compute_next_period_start_date',
)
next_period_end_date = fields.Date(
string='Next Period End Date'
)
termination_notice_date = fields.Date(
string='Termination notice date',
compute="_compute_termination_notice_date",
Expand Down Expand Up @@ -356,7 +368,7 @@ def _check_overlap_predecessor(self):
)

@api.model
def _compute_first_recurring_next_date(
def _get_recurring_next_date(
self,
date_start,
recurring_invoicing_type,
Expand All @@ -373,8 +385,51 @@ def _compute_first_recurring_next_date(
recurring_rule_type, recurring_interval
)

@api.depends('last_date_invoiced')
def _compute_next_period_start_date(self):
for rec in self:
if rec.last_date_invoiced:
rec.next_period_start_date = (
rec.last_date_invoiced + relativedelta(days=1)
)
else:
rec.next_period_start_date = rec.date_start

@api.depends(
'recurring_invoicing_type',
'recurring_rule_type',
'next_period_end_date',
'date_start',
'date_end',
'last_date_invoiced',
)
def _compute_recurring_next_date(self):
for rec in self:
if rec.next_period_end_date:
if rec.recurring_rule_type == 'monthlylastday':
rec.recurring_next_date = rec.next_period_end_date
else:
if rec.recurring_invoicing_type == 'pre-paid':
rec.recurring_next_date = rec.next_period_start_date
else:
rec.recurring_next_date = rec.next_period_end_date + relativedelta(days=1)
if rec.date_end and rec.recurring_next_date > rec.date_end:
rec.recurring_next_date = False

@api.multi
def _inverse_recurring_next_date(self):
for rec in self:
# TODO: monthlylastday
if rec.recurring_next_date:
if rec.recurring_invoicing_type == 'pre-paid':
rec.next_period_end_date = rec.recurring_next_date + self.get_relative_delta(
rec.recurring_rule_type, rec.recurring_interval
) - relativedelta(days=1)
else:
rec.next_period_end_date = rec.recurring_next_date - relativedelta(days=1)

@api.model
def compute_first_date_end(
def _get_date_end(
self, date_start, auto_renew_rule_type, auto_renew_interval
):
return (
Expand All @@ -385,6 +440,20 @@ def compute_first_date_end(
- relativedelta(days=1)
)

@api.model
def _get_next_period_end_date(
self, next_period_start_date, recurring_rule_type, recurring_interval
):
if recurring_rule_type == 'monthlylastday':
return next_period_start_date + self.get_relative_delta(
recurring_rule_type, recurring_interval - 1
)
return (
next_period_start_date
+ self.get_relative_delta(recurring_rule_type, recurring_interval)
- relativedelta(days=1)
)

@api.onchange(
'date_start',
'is_auto_renew',
Expand All @@ -396,7 +465,7 @@ def _onchange_is_auto_renew(self):
auto_renew"""
for rec in self.filtered('is_auto_renew'):
if rec.date_start:
rec.date_end = self.compute_first_date_end(
rec.date_end = self._get_date_end(
rec.date_start,
rec.auto_renew_rule_type,
rec.auto_renew_interval,
Expand All @@ -407,15 +476,19 @@ def _onchange_is_auto_renew(self):
'recurring_invoicing_type',
'recurring_rule_type',
'recurring_interval',
'last_date_invoiced',
)
def _onchange_date_start(self):
for rec in self.filtered('date_start'):
rec.recurring_next_date = self._compute_first_recurring_next_date(
rec.recurring_next_date = self._get_recurring_next_date(
rec.date_start,
rec.recurring_invoicing_type,
rec.recurring_rule_type,
rec.recurring_interval,
)
rec.next_period_end_date = self._get_next_period_end_date(
rec.date_start, rec.recurring_rule_type, rec.recurring_interval
)

@api.constrains('is_canceled', 'is_auto_renew')
def _check_auto_renew_canceled_lines(self):
Expand Down Expand Up @@ -487,6 +560,20 @@ def _check_start_end_dates(self):
% line.name
)

@api.constrains('next_period_end_date', 'last_date_invoiced', 'date_end', 'date_start')
def _check_next_period_end_date(self):
for line in self.filtered('next_period_end_date'):
if line.next_period_end_date < line.date_start or (
line.date_end and line.next_period_end_date > line.date_end
):
raise ValidationError(
_(
"Next period end date must be between the "
"start and the end of the contract line: %s"
)
% line.name
)

@api.depends('recurring_next_date', 'date_start', 'date_end')
def _compute_create_invoice_visibility(self):
today = fields.Date.context_today(self)
Expand Down Expand Up @@ -542,23 +629,9 @@ def _get_period_to_invoice(
if last_date_invoiced
else self.date_start
)
if self.recurring_rule_type == 'monthlylastday':
last_date_invoiced = recurring_next_date
else:
if self.recurring_invoicing_type == 'pre-paid':
last_date_invoiced = (
recurring_next_date
+ self.get_relative_delta(
self.recurring_rule_type, self.recurring_interval
)
- relativedelta(days=1)
)
else:
last_date_invoiced = recurring_next_date - relativedelta(
days=1
)
last_date_invoiced = self.next_period_end_date
if stop_at_date_end:
if self.date_end and self.date_end < last_date_invoiced:
if not self.next_period_end_date and self.date_end:
last_date_invoiced = self.date_end
return first_date_invoiced, last_date_invoiced, recurring_next_date

Expand All @@ -580,23 +653,32 @@ def _insert_markers(self, first_date_invoiced, last_date_invoiced):
@api.multi
def _update_recurring_next_date(self):
for rec in self:
old_date = rec.recurring_next_date
new_date = old_date + self.get_relative_delta(
rec.recurring_rule_type, rec.recurring_interval
)
if rec.recurring_rule_type == 'monthlylastday':
last_date_invoiced = old_date
elif rec.recurring_invoicing_type == 'post-paid':
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
if rec.next_period_end_date:
last_date_invoiced = rec.next_period_end_date
next_period_start_date = last_date_invoiced + relativedelta(
days=1
)
next_period_end_date = self._get_next_period_end_date(
next_period_start_date,
rec.recurring_rule_type,
rec.recurring_interval,
)
recurring_next_date = self._get_recurring_next_date(
next_period_start_date,
rec.recurring_invoicing_type,
rec.recurring_rule_type,
rec.recurring_interval,
)
if rec.date_end and next_period_end_date > rec.date_end:
next_period_end_date = rec.date_end
if rec.date_end and last_date_invoiced >= rec.date_end:
rec.last_date_invoiced = rec.date_end
rec.recurring_next_date = False
rec.next_period_end_date = False
else:
rec.last_date_invoiced = last_date_invoiced
rec.recurring_next_date = recurring_next_date
rec.next_period_end_date = next_period_end_date

@api.multi
def _init_last_date_invoiced(self):
Expand Down Expand Up @@ -651,7 +733,7 @@ def _delay(self, delay_delta):
)
)
new_date_start = rec.date_start + delay_delta
rec.recurring_next_date = self._compute_first_recurring_next_date(
rec.recurring_next_date = self._get_recurring_next_date(
new_date_start,
rec.recurring_invoicing_type,
rec.recurring_rule_type,
Expand Down Expand Up @@ -684,6 +766,7 @@ def stop(self, date_end, manual_renew_needed=False, post_message=True):
}
if rec.last_date_invoiced == date_end:
values['recurring_next_date'] = False
values['next_period_end_date'] = False
rec.write(values)
if post_message:
msg = _(
Expand Down Expand Up @@ -712,19 +795,23 @@ def _prepare_value_for_plan_successor(
):
self.ensure_one()
if not recurring_next_date:
recurring_next_date = self._compute_first_recurring_next_date(
recurring_next_date = self._get_recurring_next_date(
date_start,
self.recurring_invoicing_type,
self.recurring_rule_type,
self.recurring_interval,
)
next_period_end_date = self._get_next_period_end_date(
date_start, self.recurring_rule_type, self.recurring_interval
)
new_vals = self.read()[0]
new_vals.pop("id", None)
new_vals.pop("last_date_invoiced", None)
values = self._convert_to_write(new_vals)
values['date_start'] = date_start
values['date_end'] = date_end
values['recurring_next_date'] = recurring_next_date
values['next_period_end_date'] = next_period_end_date
values['is_auto_renew'] = is_auto_renew
values['predecessor_contract_line_id'] = self.id
return values
Expand Down Expand Up @@ -1023,7 +1110,7 @@ def action_stop_plan_successor(self):
def _get_renewal_dates(self):
self.ensure_one()
date_start = self.date_end + relativedelta(days=1)
date_end = self.compute_first_date_end(
date_end = self._get_date_end(
date_start, self.auto_renew_rule_type, self.auto_renew_interval
)
return date_start, date_end
Expand Down
Loading