diff --git a/contract/models/abstract_contract_line.py b/contract/models/abstract_contract_line.py
index 6624f3371..a1ed154dc 100644
--- a/contract/models/abstract_contract_line.py
+++ b/contract/models/abstract_contract_line.py
@@ -125,9 +125,27 @@ class ContractAbstractContractLine(models.AbstractModel):
required=True,
ondelete='cascade',
)
- display_type = fields.Selection([
- ('line_section', "Section"),
- ('line_note', "Note")], default=False, help="Technical field for UX purpose.")
+ display_type = fields.Selection(
+ selection=[
+ ('line_section', "Section"),
+ ('line_note', "Note"),
+ ],
+ default=False,
+ help="Technical field for UX purpose."
+ )
+ note_invoicing_mode = fields.Selection(
+ selection=[
+ ('with_previous_line', 'With previous line'),
+ ('with_next_line', 'With next line'),
+ ('custom', 'Custom'),
+ ],
+ default='with_previous_line',
+ help="Defines when the Note is invoiced:\n"
+ "- With previous line: If the previous line can be invoiced.\n"
+ "- With next line: If the next line can be invoiced.\n"
+ "- Custom: Depending on the recurrence to be define."
+ )
+ is_recurring_note = fields.Boolean(compute="_compute_is_recurring_note")
@api.model
def _get_default_recurring_invoicing_offset(
@@ -141,6 +159,13 @@ class ContractAbstractContractLine(models.AbstractModel):
else:
return 1
+ def is_recurring_note(self):
+ for record in self:
+ record.is_recurring_note = (
+ record.display_type == 'line_note'
+ and record.note_invoicing_mode == 'custom'
+ )
+
@api.depends('recurring_invoicing_type', 'recurring_rule_type')
def _compute_recurring_invoicing_offset(self):
for rec in self:
diff --git a/contract/models/contract.py b/contract/models/contract.py
index ea007c2c0..a9199ba83 100644
--- a/contract/models/contract.py
+++ b/contract/models/contract.py
@@ -194,7 +194,8 @@ class ContractContract(models.Model):
def _compute_recurring_next_date(self):
for contract in self:
recurring_next_date = contract.contract_line_ids.filtered(
- lambda l: l.recurring_next_date and not l.is_canceled
+ lambda l: (l.recurring_next_date and not l.is_canceled
+ and (not l.display_type or l.is_recurring_note))
).mapped('recurring_next_date')
if recurring_next_date:
contract.recurring_next_date = min(recurring_next_date)
@@ -412,11 +413,35 @@ class ContractContract(models.Model):
:return: contract lines (contract.line recordset)
"""
self.ensure_one()
- return self.contract_line_ids.filtered(
- lambda l: not l.is_canceled
- and l.recurring_next_date
- and l.recurring_next_date <= date_ref
- )
+
+ def can_be_invoiced(l):
+ return (not l.is_canceled and l.recurring_next_date
+ and l.recurring_next_date <= date_ref)
+
+ lines2invoice = previous = self.env['contract.line']
+ current_section = current_note = False
+ for line in self.contract_line_ids:
+ if line.display_type == 'line_section':
+ current_section = line
+ elif (line.display_type == 'line_note' and
+ not line.is_recurring_note):
+ if line.note_invoicing_mode == "with_previous_line":
+ if previous in lines2invoice:
+ lines2invoice |= line
+ current_note = False
+ elif line.note_invoicing_mode == "with_next_line":
+ current_note = line
+ elif line.is_recurring_note or not line.display_type:
+ if can_be_invoiced(line):
+ if current_section:
+ lines2invoice |= current_section
+ current_section = False
+ if current_note:
+ lines2invoice |= current_note
+ lines2invoice |= line
+ current_note = False
+ previous = line
+ return lines2invoice.sorted()
@api.multi
def _prepare_recurring_invoices_values(self, date_ref=False):
diff --git a/contract/models/contract_line.py b/contract/models/contract_line.py
index 011cdc4bd..e5074d654 100644
--- a/contract/models/contract_line.py
+++ b/contract/models/contract_line.py
@@ -15,6 +15,7 @@ class ContractLine(models.Model):
_name = 'contract.line'
_description = "Contract Line"
_inherit = 'contract.abstract.contract.line'
+ _order = 'sequence,id'
sequence = fields.Integer(
string="Sequence",
@@ -654,8 +655,8 @@ class ContractLine(models.Model):
# have no meaning in certain invoices
today = fields.Date.context_today(self)
for rec in self:
- if (not rec.display_type and
- rec.date_start and today >= rec.date_start):
+ if ((not rec.display_type or rec.is_recurring_note)
+ and rec.date_start and today >= rec.date_start):
rec.create_invoice_visibility = bool(rec.recurring_next_date)
else:
rec.create_invoice_visibility = False
@@ -691,6 +692,7 @@ class ContractLine(models.Model):
name = self._insert_markers(dates[0], dates[1])
invoice_line_vals.update(
{
+ 'sequence': self.sequence,
'name': name,
'account_analytic_id': self.analytic_account_id.id,
'analytic_tag_ids': [(6, 0, self.analytic_tag_ids.ids)],
diff --git a/contract/views/abstract_contract_line.xml b/contract/views/abstract_contract_line.xml
index d4c7d3d02..44feec0a6 100644
--- a/contract/views/abstract_contract_line.xml
+++ b/contract/views/abstract_contract_line.xml
@@ -34,6 +34,10 @@
+
+
+
+
@@ -62,7 +66,7 @@
-
+