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