mirror of
https://github.com/OCA/contract.git
synced 2025-02-13 17:57:24 +02:00
[FIX] contract: Select the correct sections/notes to be invoiced
This commit is contained in:
committed by
Pedro M. Baeza
parent
6b7576f37f
commit
b66e388378
@@ -125,9 +125,27 @@ class ContractAbstractContractLine(models.AbstractModel):
|
|||||||
required=True,
|
required=True,
|
||||||
ondelete='cascade',
|
ondelete='cascade',
|
||||||
)
|
)
|
||||||
display_type = fields.Selection([
|
display_type = fields.Selection(
|
||||||
|
selection=[
|
||||||
('line_section', "Section"),
|
('line_section', "Section"),
|
||||||
('line_note', "Note")], default=False, help="Technical field for UX purpose.")
|
('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
|
@api.model
|
||||||
def _get_default_recurring_invoicing_offset(
|
def _get_default_recurring_invoicing_offset(
|
||||||
@@ -141,6 +159,13 @@ class ContractAbstractContractLine(models.AbstractModel):
|
|||||||
else:
|
else:
|
||||||
return 1
|
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')
|
@api.depends('recurring_invoicing_type', 'recurring_rule_type')
|
||||||
def _compute_recurring_invoicing_offset(self):
|
def _compute_recurring_invoicing_offset(self):
|
||||||
for rec in self:
|
for rec in self:
|
||||||
|
|||||||
@@ -194,7 +194,8 @@ class ContractContract(models.Model):
|
|||||||
def _compute_recurring_next_date(self):
|
def _compute_recurring_next_date(self):
|
||||||
for contract in self:
|
for contract in self:
|
||||||
recurring_next_date = contract.contract_line_ids.filtered(
|
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')
|
).mapped('recurring_next_date')
|
||||||
if recurring_next_date:
|
if recurring_next_date:
|
||||||
contract.recurring_next_date = min(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)
|
:return: contract lines (contract.line recordset)
|
||||||
"""
|
"""
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
return self.contract_line_ids.filtered(
|
|
||||||
lambda l: not l.is_canceled
|
def can_be_invoiced(l):
|
||||||
and l.recurring_next_date
|
return (not l.is_canceled and l.recurring_next_date
|
||||||
and l.recurring_next_date <= date_ref
|
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
|
@api.multi
|
||||||
def _prepare_recurring_invoices_values(self, date_ref=False):
|
def _prepare_recurring_invoices_values(self, date_ref=False):
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ class ContractLine(models.Model):
|
|||||||
_name = 'contract.line'
|
_name = 'contract.line'
|
||||||
_description = "Contract Line"
|
_description = "Contract Line"
|
||||||
_inherit = 'contract.abstract.contract.line'
|
_inherit = 'contract.abstract.contract.line'
|
||||||
|
_order = 'sequence,id'
|
||||||
|
|
||||||
sequence = fields.Integer(
|
sequence = fields.Integer(
|
||||||
string="Sequence",
|
string="Sequence",
|
||||||
@@ -654,8 +655,8 @@ class ContractLine(models.Model):
|
|||||||
# have no meaning in certain invoices
|
# have no meaning in certain invoices
|
||||||
today = fields.Date.context_today(self)
|
today = fields.Date.context_today(self)
|
||||||
for rec in self:
|
for rec in self:
|
||||||
if (not rec.display_type and
|
if ((not rec.display_type or rec.is_recurring_note)
|
||||||
rec.date_start and today >= rec.date_start):
|
and rec.date_start and today >= rec.date_start):
|
||||||
rec.create_invoice_visibility = bool(rec.recurring_next_date)
|
rec.create_invoice_visibility = bool(rec.recurring_next_date)
|
||||||
else:
|
else:
|
||||||
rec.create_invoice_visibility = False
|
rec.create_invoice_visibility = False
|
||||||
@@ -691,6 +692,7 @@ class ContractLine(models.Model):
|
|||||||
name = self._insert_markers(dates[0], dates[1])
|
name = self._insert_markers(dates[0], dates[1])
|
||||||
invoice_line_vals.update(
|
invoice_line_vals.update(
|
||||||
{
|
{
|
||||||
|
'sequence': self.sequence,
|
||||||
'name': name,
|
'name': name,
|
||||||
'account_analytic_id': self.analytic_account_id.id,
|
'account_analytic_id': self.analytic_account_id.id,
|
||||||
'analytic_tag_ids': [(6, 0, self.analytic_tag_ids.ids)],
|
'analytic_tag_ids': [(6, 0, self.analytic_tag_ids.ids)],
|
||||||
|
|||||||
@@ -34,6 +34,10 @@
|
|||||||
<label for="name" string="Note" attrs="{'invisible': [('display_type', '!=', 'line_note')]}"/>
|
<label for="name" string="Note" attrs="{'invisible': [('display_type', '!=', 'line_note')]}"/>
|
||||||
<field name="name" nolabel="1"/>
|
<field name="name" nolabel="1"/>
|
||||||
|
|
||||||
|
<group name="note_invoicing_mode" attrs="{'invisible': [('display_type', '!=', 'line_note')]}">
|
||||||
|
<field name="note_invoicing_mode" widget="radio"/>
|
||||||
|
</group>
|
||||||
|
|
||||||
<group col="4" attrs="{'invisible': [('display_type', '!=', False)]}">
|
<group col="4" attrs="{'invisible': [('display_type', '!=', False)]}">
|
||||||
<field colspan="2" name="is_auto_renew"/>
|
<field colspan="2" name="is_auto_renew"/>
|
||||||
<field colspan="2" name="is_canceled" invisible="1"/>
|
<field colspan="2" name="is_canceled" invisible="1"/>
|
||||||
@@ -62,7 +66,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
<group name="recurrence_info" attrs="{'invisible': [('display_type', '!=', False)]}">
|
<group name="recurrence_info" attrs="{'invisible': ['|', ('display_type', '=', 'line_section'), '&', ('display_type', '=', 'line_note'), ('note_invoicing_mode', '!=', 'custom')]}">
|
||||||
<group>
|
<group>
|
||||||
<label for="recurring_interval"/>
|
<label for="recurring_interval"/>
|
||||||
<div class="o_row">
|
<div class="o_row">
|
||||||
|
|||||||
Reference in New Issue
Block a user