mirror of
https://github.com/OCA/contract.git
synced 2025-02-13 17:57:24 +02:00
[IMP] - Link invoice line to contract lines
[IMP] - Add index on contract line [IMP] - Add is_suspended flag and _search_state [IMP] - Add is_suspended flag to stop contract line
This commit is contained in:
@@ -33,7 +33,6 @@
|
|||||||
'views/contract.xml',
|
'views/contract.xml',
|
||||||
'views/contract_template_line.xml',
|
'views/contract_template_line.xml',
|
||||||
'views/contract_template.xml',
|
'views/contract_template.xml',
|
||||||
'views/account_invoice_view.xml',
|
|
||||||
'views/contract_line.xml',
|
'views/contract_line.xml',
|
||||||
'views/res_partner_view.xml',
|
'views/res_partner_view.xml',
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -20,6 +20,5 @@ def migrate(cr, version):
|
|||||||
)
|
)
|
||||||
cr.execute(
|
cr.execute(
|
||||||
"UPDATE account_analytic_account set recurring_next_date=null "
|
"UPDATE account_analytic_account set recurring_next_date=null "
|
||||||
"where id in (%)"
|
"where id in (%)" % ','.join(finished_contract.ids)
|
||||||
% ','.join(finished_contract.ids)
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -7,4 +7,5 @@ from . import contract
|
|||||||
from . import contract_template_line
|
from . import contract_template_line
|
||||||
from . import contract_line
|
from . import contract_line
|
||||||
from . import account_invoice
|
from . import account_invoice
|
||||||
|
from . import account_invoice_line
|
||||||
from . import res_partner
|
from . import res_partner
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ from odoo import fields, models
|
|||||||
class AccountInvoice(models.Model):
|
class AccountInvoice(models.Model):
|
||||||
_inherit = 'account.invoice'
|
_inherit = 'account.invoice'
|
||||||
|
|
||||||
contract_id = fields.Many2one(
|
# We keep this field for migration purpose
|
||||||
'account.analytic.account', string='Contract'
|
old_contract_id = fields.Many2one(
|
||||||
|
'account.analytic.account', oldname="contract_id"
|
||||||
)
|
)
|
||||||
|
|||||||
12
contract/models/account_invoice_line.py
Normal file
12
contract/models/account_invoice_line.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# Copyright 2018 ACSONE SA/NV.
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
|
from odoo import fields, models
|
||||||
|
|
||||||
|
|
||||||
|
class AccountInvoiceLine(models.Model):
|
||||||
|
_inherit = 'account.invoice.line'
|
||||||
|
|
||||||
|
contract_line_id = fields.Many2one(
|
||||||
|
'account.analytic.invoice.line', string='Contract Line', index=True
|
||||||
|
)
|
||||||
@@ -50,6 +50,46 @@ class AccountAnalyticAccount(models.Model):
|
|||||||
payment_term_id = fields.Many2one(
|
payment_term_id = fields.Many2one(
|
||||||
comodel_name='account.payment.term', string='Payment Terms'
|
comodel_name='account.payment.term', string='Payment Terms'
|
||||||
)
|
)
|
||||||
|
invoice_count = fields.Integer(compute="_compute_invoice_count")
|
||||||
|
|
||||||
|
@api.multi
|
||||||
|
def _get_related_invoices(self):
|
||||||
|
self.ensure_one()
|
||||||
|
|
||||||
|
invoices = (
|
||||||
|
self.env['account.invoice.line']
|
||||||
|
.search(
|
||||||
|
[
|
||||||
|
(
|
||||||
|
'contract_line_id',
|
||||||
|
'in',
|
||||||
|
self.recurring_invoice_line_ids.ids,
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
.mapped('invoice_id')
|
||||||
|
)
|
||||||
|
invoices |= self.env['account.invoice'].search(
|
||||||
|
[('old_contract_id', '=', self.id)]
|
||||||
|
)
|
||||||
|
return invoices
|
||||||
|
|
||||||
|
@api.multi
|
||||||
|
def _compute_invoice_count(self):
|
||||||
|
for rec in self:
|
||||||
|
rec.invoice_count = len(rec._get_related_invoices())
|
||||||
|
|
||||||
|
@api.multi
|
||||||
|
def action_show_invoices(self):
|
||||||
|
self.ensure_one()
|
||||||
|
return {
|
||||||
|
'type': 'ir.actions.act_window',
|
||||||
|
'name': 'Invoices',
|
||||||
|
'res_model': 'account.invoice',
|
||||||
|
'view_type': 'form',
|
||||||
|
'view_mode': 'tree,kanban,form,calendar,pivot,graph,activity',
|
||||||
|
'domain': [('id', 'in', self._get_related_invoices().ids)],
|
||||||
|
}
|
||||||
|
|
||||||
@api.depends('recurring_invoice_line_ids.date_end')
|
@api.depends('recurring_invoice_line_ids.date_end')
|
||||||
def _compute_date_end(self):
|
def _compute_date_end(self):
|
||||||
@@ -185,7 +225,6 @@ class AccountAnalyticAccount(models.Model):
|
|||||||
'journal_id': journal.id,
|
'journal_id': journal.id,
|
||||||
'origin': self.name,
|
'origin': self.name,
|
||||||
'company_id': self.company_id.id,
|
'company_id': self.company_id.id,
|
||||||
'contract_id': self.id,
|
|
||||||
'user_id': self.partner_id.user_id.id,
|
'user_id': self.partner_id.user_id.id,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
# Copyright 2017 LasLabs Inc.
|
# Copyright 2017 LasLabs Inc.
|
||||||
|
# Copyright 2018 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).
|
||||||
|
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
@@ -40,6 +41,7 @@ class AccountAnalyticInvoiceLine(models.Model):
|
|||||||
string="Successor Contract Line",
|
string="Successor Contract Line",
|
||||||
required=False,
|
required=False,
|
||||||
readonly=True,
|
readonly=True,
|
||||||
|
index=True,
|
||||||
copy=False,
|
copy=False,
|
||||||
help="In case of restart after suspension, this field contain the new "
|
help="In case of restart after suspension, this field contain the new "
|
||||||
"contract line created.",
|
"contract line created.",
|
||||||
@@ -49,9 +51,11 @@ class AccountAnalyticInvoiceLine(models.Model):
|
|||||||
string="Predecessor Contract Line",
|
string="Predecessor Contract Line",
|
||||||
required=False,
|
required=False,
|
||||||
readonly=True,
|
readonly=True,
|
||||||
|
index=True,
|
||||||
copy=False,
|
copy=False,
|
||||||
help="Contract Line origin of this one.",
|
help="Contract Line origin of this one.",
|
||||||
)
|
)
|
||||||
|
is_suspended = fields.Boolean(string="Suspended", default=False)
|
||||||
is_plan_successor_allowed = fields.Boolean(
|
is_plan_successor_allowed = fields.Boolean(
|
||||||
string="Plan successor allowed?", compute='_compute_allowed'
|
string="Plan successor allowed?", compute='_compute_allowed'
|
||||||
)
|
)
|
||||||
@@ -72,11 +76,14 @@ class AccountAnalyticInvoiceLine(models.Model):
|
|||||||
selection=[
|
selection=[
|
||||||
('upcoming', 'Upcoming'),
|
('upcoming', 'Upcoming'),
|
||||||
('in-progress', 'In-progress'),
|
('in-progress', 'In-progress'),
|
||||||
|
('suspension-planed', 'Suspension Planed'),
|
||||||
|
('suspended', 'Suspended'),
|
||||||
('upcoming-close', 'Upcoming Close'),
|
('upcoming-close', 'Upcoming Close'),
|
||||||
('closed', 'Closed'),
|
('closed', 'Closed'),
|
||||||
('canceled', 'Canceled'),
|
('canceled', 'Canceled'),
|
||||||
],
|
],
|
||||||
compute="_compute_state",
|
compute="_compute_state",
|
||||||
|
search='_search_state',
|
||||||
)
|
)
|
||||||
active = fields.Boolean(
|
active = fields.Boolean(
|
||||||
string="Active",
|
string="Active",
|
||||||
@@ -90,20 +97,135 @@ class AccountAnalyticInvoiceLine(models.Model):
|
|||||||
def _compute_state(self):
|
def _compute_state(self):
|
||||||
today = fields.Date.context_today(self)
|
today = fields.Date.context_today(self)
|
||||||
for rec in self:
|
for rec in self:
|
||||||
if rec.date_start:
|
|
||||||
if rec.is_canceled:
|
if rec.is_canceled:
|
||||||
rec.state = 'canceled'
|
rec.state = 'canceled'
|
||||||
elif today < rec.date_start:
|
continue
|
||||||
|
|
||||||
|
if rec.date_start and rec.date_start > today:
|
||||||
|
# Before period
|
||||||
rec.state = 'upcoming'
|
rec.state = 'upcoming'
|
||||||
elif not rec.date_end or (
|
continue
|
||||||
today <= rec.date_end and rec.is_auto_renew
|
if (
|
||||||
|
rec.date_start
|
||||||
|
and rec.date_start <= today
|
||||||
|
and (not rec.date_end or rec.date_end >= today)
|
||||||
):
|
):
|
||||||
rec.state = 'in-progress'
|
# In period
|
||||||
elif today <= rec.date_end and not rec.is_auto_renew:
|
if rec.is_suspended:
|
||||||
|
rec.state = 'suspension-planed'
|
||||||
|
continue
|
||||||
|
if rec.date_end and not rec.is_auto_renew:
|
||||||
rec.state = 'upcoming-close'
|
rec.state = 'upcoming-close'
|
||||||
|
else:
|
||||||
|
rec.state = 'in-progress'
|
||||||
|
continue
|
||||||
|
if rec.date_end and rec.date_end < today:
|
||||||
|
if rec.is_suspended and not rec.successor_contract_line_id:
|
||||||
|
rec.state = 'suspended'
|
||||||
else:
|
else:
|
||||||
rec.state = 'closed'
|
rec.state = 'closed'
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def _get_state_domain(self, state):
|
||||||
|
today = fields.Date.context_today(self)
|
||||||
|
if state == 'upcoming':
|
||||||
|
return [
|
||||||
|
"&",
|
||||||
|
('date_start', '>', today),
|
||||||
|
('is_canceled', '=', False),
|
||||||
|
]
|
||||||
|
if state == 'in-progress':
|
||||||
|
return [
|
||||||
|
"&",
|
||||||
|
"&",
|
||||||
|
"&",
|
||||||
|
"&",
|
||||||
|
('date_start', '<=', today),
|
||||||
|
('is_auto_renew', '=', True),
|
||||||
|
('is_suspended', '=', False),
|
||||||
|
('is_canceled', '=', False),
|
||||||
|
"|",
|
||||||
|
('date_end', '>=', today),
|
||||||
|
('date_end', '=', False),
|
||||||
|
]
|
||||||
|
if state == 'suspension-planed':
|
||||||
|
return [
|
||||||
|
"&",
|
||||||
|
"&",
|
||||||
|
"&",
|
||||||
|
('date_start', '<=', today),
|
||||||
|
('is_suspended', '=', True),
|
||||||
|
('is_canceled', '=', False),
|
||||||
|
'|',
|
||||||
|
('date_end', '>=', today),
|
||||||
|
('date_end', '=', False),
|
||||||
|
]
|
||||||
|
if state == 'suspended':
|
||||||
|
return [
|
||||||
|
"&",
|
||||||
|
"&",
|
||||||
|
"&",
|
||||||
|
('date_end', '<', today),
|
||||||
|
('successor_contract_line_id', '=', False),
|
||||||
|
('is_suspended', '=', True),
|
||||||
|
('is_canceled', '=', False),
|
||||||
|
]
|
||||||
|
if state == 'upcoming-close':
|
||||||
|
return [
|
||||||
|
"&",
|
||||||
|
"&",
|
||||||
|
"&",
|
||||||
|
"&",
|
||||||
|
('date_start', '<=', today),
|
||||||
|
('is_auto_renew', '=', False),
|
||||||
|
('is_suspended', '=', False),
|
||||||
|
('is_canceled', '=', False),
|
||||||
|
'|',
|
||||||
|
('date_end', '>=', today),
|
||||||
|
('date_end', '=', False),
|
||||||
|
]
|
||||||
|
if state == 'closed':
|
||||||
|
return [
|
||||||
|
"&",
|
||||||
|
"&",
|
||||||
|
('is_canceled', '=', False),
|
||||||
|
('date_end', '<', today),
|
||||||
|
"|",
|
||||||
|
"&",
|
||||||
|
('is_suspended', '=', True),
|
||||||
|
('successor_contract_line_id', '!=', False),
|
||||||
|
('is_suspended', '=', False),
|
||||||
|
]
|
||||||
|
|
||||||
|
if state == 'canceled':
|
||||||
|
return [('is_canceled', '=', True)]
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def _search_state(self, operator, value):
|
||||||
|
if operator == '!=' and not value:
|
||||||
|
return []
|
||||||
|
if operator == '=' and not value:
|
||||||
|
return [('id', '=', False)]
|
||||||
|
if operator == '=':
|
||||||
|
return self._get_state_domain(value)
|
||||||
|
if operator == '!=':
|
||||||
|
states = [
|
||||||
|
'upcoming',
|
||||||
|
'in-progress',
|
||||||
|
'suspension-planed',
|
||||||
|
'suspended',
|
||||||
|
'upcoming-close',
|
||||||
|
'closed',
|
||||||
|
'canceled',
|
||||||
|
]
|
||||||
|
domain = []
|
||||||
|
for state in states:
|
||||||
|
if state != value:
|
||||||
|
if domain:
|
||||||
|
domain.insert(0, '|')
|
||||||
|
domain.extend(self._get_state_domain(state))
|
||||||
|
return domain
|
||||||
|
|
||||||
@api.depends(
|
@api.depends(
|
||||||
'date_start',
|
'date_start',
|
||||||
'date_end',
|
'date_end',
|
||||||
@@ -316,6 +438,7 @@ class AccountAnalyticInvoiceLine(models.Model):
|
|||||||
'quantity': self.quantity,
|
'quantity': self.quantity,
|
||||||
'uom_id': self.uom_id.id,
|
'uom_id': self.uom_id.id,
|
||||||
'discount': self.discount,
|
'discount': self.discount,
|
||||||
|
'contract_line_id': self.id,
|
||||||
}
|
}
|
||||||
if invoice_id:
|
if invoice_id:
|
||||||
invoice_line_vals['invoice_id'] = invoice_id.id
|
invoice_line_vals['invoice_id'] = invoice_id.id
|
||||||
@@ -460,7 +583,7 @@ class AccountAnalyticInvoiceLine(models.Model):
|
|||||||
rec.date_start = new_date_start
|
rec.date_start = new_date_start
|
||||||
|
|
||||||
@api.multi
|
@api.multi
|
||||||
def stop(self, date_end, post_message=True):
|
def stop(self, date_end, is_suspended=False, post_message=True):
|
||||||
"""
|
"""
|
||||||
Put date_end on contract line
|
Put date_end on contract line
|
||||||
We don't consider contract lines that end's before the new end date
|
We don't consider contract lines that end's before the new end date
|
||||||
@@ -487,9 +610,17 @@ class AccountAnalyticInvoiceLine(models.Model):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
rec.contract_id.message_post(body=msg)
|
rec.contract_id.message_post(body=msg)
|
||||||
rec.write({'date_end': date_end, 'is_auto_renew': False})
|
rec.write(
|
||||||
|
{
|
||||||
|
'date_end': date_end,
|
||||||
|
'is_auto_renew': False,
|
||||||
|
"is_suspended": is_suspended,
|
||||||
|
}
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
rec.write({'is_auto_renew': False})
|
rec.write(
|
||||||
|
{'is_auto_renew': False, "is_suspended": is_suspended}
|
||||||
|
)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@api.multi
|
@api.multi
|
||||||
@@ -624,7 +755,9 @@ class AccountAnalyticInvoiceLine(models.Model):
|
|||||||
+ relativedelta(days=1)
|
+ relativedelta(days=1)
|
||||||
)
|
)
|
||||||
rec.stop(
|
rec.stop(
|
||||||
date_start - relativedelta(days=1), post_message=False
|
date_start - relativedelta(days=1),
|
||||||
|
is_suspended=True,
|
||||||
|
post_message=False,
|
||||||
)
|
)
|
||||||
contract_line |= rec.plan_successor(
|
contract_line |= rec.plan_successor(
|
||||||
new_date_start,
|
new_date_start,
|
||||||
@@ -644,7 +777,9 @@ class AccountAnalyticInvoiceLine(models.Model):
|
|||||||
new_date_end = rec.date_end
|
new_date_end = rec.date_end
|
||||||
|
|
||||||
rec.stop(
|
rec.stop(
|
||||||
date_start - relativedelta(days=1), post_message=False
|
date_start - relativedelta(days=1),
|
||||||
|
is_suspended=True,
|
||||||
|
post_message=False,
|
||||||
)
|
)
|
||||||
contract_line |= rec.plan_successor(
|
contract_line |= rec.plan_successor(
|
||||||
new_date_start,
|
new_date_start,
|
||||||
|
|||||||
@@ -143,9 +143,7 @@ class TestContract(TestContractBase):
|
|||||||
self.contract.partner_id = False
|
self.contract.partner_id = False
|
||||||
self.contract.partner_id = self.partner.id
|
self.contract.partner_id = self.partner.id
|
||||||
self.contract.recurring_create_invoice()
|
self.contract.recurring_create_invoice()
|
||||||
self.invoice_monthly = self.env['account.invoice'].search(
|
self.invoice_monthly = self.contract._get_related_invoices()
|
||||||
[('contract_id', '=', self.contract.id)]
|
|
||||||
)
|
|
||||||
self.assertTrue(self.invoice_monthly)
|
self.assertTrue(self.invoice_monthly)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.acct_line.recurring_next_date, recurring_next_date
|
self.acct_line.recurring_next_date, recurring_next_date
|
||||||
@@ -182,9 +180,7 @@ class TestContract(TestContractBase):
|
|||||||
self.acct_line.recurring_rule_type = 'daily'
|
self.acct_line.recurring_rule_type = 'daily'
|
||||||
self.contract.pricelist_id = False
|
self.contract.pricelist_id = False
|
||||||
self.contract.recurring_create_invoice()
|
self.contract.recurring_create_invoice()
|
||||||
invoice_daily = self.env['account.invoice'].search(
|
invoice_daily = self.contract._get_related_invoices()
|
||||||
[('contract_id', '=', self.contract.id)]
|
|
||||||
)
|
|
||||||
self.assertTrue(invoice_daily)
|
self.assertTrue(invoice_daily)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.acct_line.recurring_next_date, recurring_next_date
|
self.acct_line.recurring_next_date, recurring_next_date
|
||||||
@@ -198,9 +194,7 @@ class TestContract(TestContractBase):
|
|||||||
self.acct_line.recurring_rule_type = 'weekly'
|
self.acct_line.recurring_rule_type = 'weekly'
|
||||||
self.acct_line.recurring_invoicing_type = 'post-paid'
|
self.acct_line.recurring_invoicing_type = 'post-paid'
|
||||||
self.contract.recurring_create_invoice()
|
self.contract.recurring_create_invoice()
|
||||||
invoices_weekly = self.env['account.invoice'].search(
|
invoices_weekly = self.contract._get_related_invoices()
|
||||||
[('contract_id', '=', self.contract.id)]
|
|
||||||
)
|
|
||||||
self.assertTrue(invoices_weekly)
|
self.assertTrue(invoices_weekly)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.acct_line.recurring_next_date, recurring_next_date
|
self.acct_line.recurring_next_date, recurring_next_date
|
||||||
@@ -214,9 +208,7 @@ class TestContract(TestContractBase):
|
|||||||
self.acct_line.recurring_rule_type = 'weekly'
|
self.acct_line.recurring_rule_type = 'weekly'
|
||||||
self.acct_line.recurring_invoicing_type = 'pre-paid'
|
self.acct_line.recurring_invoicing_type = 'pre-paid'
|
||||||
self.contract.recurring_create_invoice()
|
self.contract.recurring_create_invoice()
|
||||||
invoices_weekly = self.env['account.invoice'].search(
|
invoices_weekly = self.contract._get_related_invoices()
|
||||||
[('contract_id', '=', self.contract.id)]
|
|
||||||
)
|
|
||||||
self.assertTrue(invoices_weekly)
|
self.assertTrue(invoices_weekly)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.acct_line.recurring_next_date, recurring_next_date
|
self.acct_line.recurring_next_date, recurring_next_date
|
||||||
@@ -230,9 +222,7 @@ class TestContract(TestContractBase):
|
|||||||
self.acct_line.recurring_rule_type = 'yearly'
|
self.acct_line.recurring_rule_type = 'yearly'
|
||||||
self.acct_line.recurring_invoicing_type = 'post-paid'
|
self.acct_line.recurring_invoicing_type = 'post-paid'
|
||||||
self.contract.recurring_create_invoice()
|
self.contract.recurring_create_invoice()
|
||||||
invoices_weekly = self.env['account.invoice'].search(
|
invoices_weekly = self.contract._get_related_invoices()
|
||||||
[('contract_id', '=', self.contract.id)]
|
|
||||||
)
|
|
||||||
self.assertTrue(invoices_weekly)
|
self.assertTrue(invoices_weekly)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.acct_line.recurring_next_date, recurring_next_date
|
self.acct_line.recurring_next_date, recurring_next_date
|
||||||
@@ -247,9 +237,7 @@ class TestContract(TestContractBase):
|
|||||||
self.acct_line.recurring_rule_type = 'yearly'
|
self.acct_line.recurring_rule_type = 'yearly'
|
||||||
self.acct_line.recurring_invoicing_type = 'pre-paid'
|
self.acct_line.recurring_invoicing_type = 'pre-paid'
|
||||||
self.contract.recurring_create_invoice()
|
self.contract.recurring_create_invoice()
|
||||||
invoices_weekly = self.env['account.invoice'].search(
|
invoices_weekly = self.contract._get_related_invoices()
|
||||||
[('contract_id', '=', self.contract.id)]
|
|
||||||
)
|
|
||||||
self.assertTrue(invoices_weekly)
|
self.assertTrue(invoices_weekly)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.acct_line.recurring_next_date, recurring_next_date
|
self.acct_line.recurring_next_date, recurring_next_date
|
||||||
@@ -263,9 +251,7 @@ class TestContract(TestContractBase):
|
|||||||
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'
|
||||||
self.contract.recurring_create_invoice()
|
self.contract.recurring_create_invoice()
|
||||||
invoices_monthly_lastday = self.env['account.invoice'].search(
|
invoices_monthly_lastday = self.contract._get_related_invoices()
|
||||||
[('contract_id', '=', self.contract.id)]
|
|
||||||
)
|
|
||||||
self.assertTrue(invoices_monthly_lastday)
|
self.assertTrue(invoices_monthly_lastday)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.acct_line.recurring_next_date, recurring_next_date
|
self.acct_line.recurring_next_date, recurring_next_date
|
||||||
@@ -302,13 +288,9 @@ class TestContract(TestContractBase):
|
|||||||
)
|
)
|
||||||
self.assertFalse(self.acct_line.recurring_next_date)
|
self.assertFalse(self.acct_line.recurring_next_date)
|
||||||
self.assertFalse(self.acct_line.create_invoice_visibility)
|
self.assertFalse(self.acct_line.create_invoice_visibility)
|
||||||
invoices = self.env['account.invoice'].search(
|
invoices = self.contract._get_related_invoices()
|
||||||
[('contract_id', '=', self.contract.id)]
|
|
||||||
)
|
|
||||||
self.contract.recurring_create_invoice()
|
self.contract.recurring_create_invoice()
|
||||||
new_invoices = self.env['account.invoice'].search(
|
new_invoices = self.contract._get_related_invoices()
|
||||||
[('contract_id', '=', self.contract.id)]
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
invoices,
|
invoices,
|
||||||
new_invoices,
|
new_invoices,
|
||||||
@@ -345,13 +327,9 @@ class TestContract(TestContractBase):
|
|||||||
)
|
)
|
||||||
self.assertFalse(self.acct_line.recurring_next_date)
|
self.assertFalse(self.acct_line.recurring_next_date)
|
||||||
self.assertFalse(self.acct_line.create_invoice_visibility)
|
self.assertFalse(self.acct_line.create_invoice_visibility)
|
||||||
invoices = self.env['account.invoice'].search(
|
invoices = self.contract._get_related_invoices()
|
||||||
[('contract_id', '=', self.contract.id)]
|
|
||||||
)
|
|
||||||
self.contract.recurring_create_invoice()
|
self.contract.recurring_create_invoice()
|
||||||
new_invoices = self.env['account.invoice'].search(
|
new_invoices = self.contract._get_related_invoices()
|
||||||
[('contract_id', '=', self.contract.id)]
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
invoices,
|
invoices,
|
||||||
new_invoices,
|
new_invoices,
|
||||||
@@ -522,7 +500,6 @@ class TestContract(TestContractBase):
|
|||||||
|
|
||||||
def test_same_date_start_and_date_end(self):
|
def test_same_date_start_and_date_end(self):
|
||||||
"""It should create one invoice with same start and end date."""
|
"""It should create one invoice with same start and end date."""
|
||||||
account_invoice_model = self.env['account.invoice']
|
|
||||||
self.acct_line.write(
|
self.acct_line.write(
|
||||||
{
|
{
|
||||||
'date_start': fields.Date.today(),
|
'date_start': fields.Date.today(),
|
||||||
@@ -531,18 +508,12 @@ class TestContract(TestContractBase):
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
self.contract._compute_recurring_next_date()
|
self.contract._compute_recurring_next_date()
|
||||||
init_count = account_invoice_model.search_count(
|
init_count = len(self.contract._get_related_invoices())
|
||||||
[('contract_id', '=', self.contract.id)]
|
|
||||||
)
|
|
||||||
self.contract.recurring_create_invoice()
|
self.contract.recurring_create_invoice()
|
||||||
last_count = account_invoice_model.search_count(
|
last_count = len(self.contract._get_related_invoices())
|
||||||
[('contract_id', '=', self.contract.id)]
|
|
||||||
)
|
|
||||||
self.assertEqual(last_count, init_count + 1)
|
self.assertEqual(last_count, init_count + 1)
|
||||||
self.contract.recurring_create_invoice()
|
self.contract.recurring_create_invoice()
|
||||||
last_count = account_invoice_model.search_count(
|
last_count = len(self.contract._get_related_invoices())
|
||||||
[('contract_id', '=', self.contract.id)]
|
|
||||||
)
|
|
||||||
self.assertEqual(last_count, init_count + 1)
|
self.assertEqual(last_count, init_count + 1)
|
||||||
|
|
||||||
def test_act_show_contract(self):
|
def test_act_show_contract(self):
|
||||||
@@ -798,6 +769,7 @@ class TestContract(TestContractBase):
|
|||||||
new_line.date_start, suspension_end + relativedelta(days=1)
|
new_line.date_start, suspension_end + relativedelta(days=1)
|
||||||
)
|
)
|
||||||
self.assertEqual(new_line.date_end, new_date_end)
|
self.assertEqual(new_line.date_end, new_date_end)
|
||||||
|
self.assertTrue(self.acct_line.is_suspended)
|
||||||
|
|
||||||
def test_stop_plan_successor_contract_line_3(self):
|
def test_stop_plan_successor_contract_line_3(self):
|
||||||
"""
|
"""
|
||||||
@@ -838,6 +810,7 @@ class TestContract(TestContractBase):
|
|||||||
new_line.date_start, suspension_end + relativedelta(days=1)
|
new_line.date_start, suspension_end + relativedelta(days=1)
|
||||||
)
|
)
|
||||||
self.assertEqual(new_line.date_end, new_date_end)
|
self.assertEqual(new_line.date_end, new_date_end)
|
||||||
|
self.assertTrue(self.acct_line.is_suspended)
|
||||||
|
|
||||||
def test_stop_plan_successor_contract_line_3_without_end_date(self):
|
def test_stop_plan_successor_contract_line_3_without_end_date(self):
|
||||||
"""
|
"""
|
||||||
@@ -874,6 +847,7 @@ class TestContract(TestContractBase):
|
|||||||
new_line.date_start, suspension_end + relativedelta(days=1)
|
new_line.date_start, suspension_end + relativedelta(days=1)
|
||||||
)
|
)
|
||||||
self.assertFalse(new_line.date_end)
|
self.assertFalse(new_line.date_end)
|
||||||
|
self.assertTrue(self.acct_line.is_suspended)
|
||||||
|
|
||||||
def test_stop_plan_successor_contract_line_4(self):
|
def test_stop_plan_successor_contract_line_4(self):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<odoo>
|
|
||||||
|
|
||||||
<record id="view_account_invoice_filter_contract" model="ir.ui.view">
|
|
||||||
<field name="name">account.invoice.select.contract</field>
|
|
||||||
<field name="model">account.invoice</field>
|
|
||||||
<field name="inherit_id" ref="account.view_account_invoice_filter"/>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<field name="date" position="after">
|
|
||||||
<separator/>
|
|
||||||
<field name="contract_id"/>
|
|
||||||
</field>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="act_recurring_invoices" model="ir.actions.act_window">
|
|
||||||
<field name="name">Invoices</field>
|
|
||||||
<field name="res_model">account.invoice</field>
|
|
||||||
<field name="view_ids"
|
|
||||||
eval="[(5, 0, 0),
|
|
||||||
(0, 0, {'view_mode': 'tree', 'view_id': ref('account.invoice_tree')}),
|
|
||||||
(0, 0, {'view_mode': 'form', 'view_id': ref('account.invoice_form')})]"/>
|
|
||||||
<field name="context">{
|
|
||||||
'search_default_contract_id': [active_id],
|
|
||||||
'default_contract_id': active_id}
|
|
||||||
</field>
|
|
||||||
<field name="domain">[('type','in', ['out_invoice', 'out_refund'])]</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="act_purchase_recurring_invoices" model="ir.actions.act_window">
|
|
||||||
<field name="name">Vendor Bills</field>
|
|
||||||
<field name="res_model">account.invoice</field>
|
|
||||||
<field name="view_ids"
|
|
||||||
eval="[(5, 0, 0),
|
|
||||||
(0, 0, {'view_mode': 'tree', 'view_id': ref('account.invoice_supplier_tree')}),
|
|
||||||
(0, 0, {'view_mode': 'form', 'view_id': ref('account.invoice_supplier_form')})]"/>
|
|
||||||
<field name="context">{
|
|
||||||
'search_default_contract_id': [active_id],
|
|
||||||
'default_contract_id': active_id}
|
|
||||||
</field>
|
|
||||||
<field name="domain">[('type','in', ['in_invoice', 'in_refund'])]</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
</odoo>
|
|
||||||
|
|||||||
@@ -25,12 +25,13 @@
|
|||||||
<field name="active" widget="boolean_button"
|
<field name="active" widget="boolean_button"
|
||||||
options="{"terminology": "archive"}"/>
|
options="{"terminology": "archive"}"/>
|
||||||
</button>
|
</button>
|
||||||
|
<button name="action_show_invoices"
|
||||||
<button name="contract.act_recurring_invoices"
|
type="object" icon="fa-list"
|
||||||
type="action"
|
class="oe_stat_button">
|
||||||
string="Invoices"
|
<field string="Invoices"
|
||||||
icon="fa-list"
|
name="invoice_count"
|
||||||
class="oe_stat_button"/>
|
widget="statinfo"/>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="oe_title">
|
<div class="oe_title">
|
||||||
<label for="name" string="Contract Name"
|
<label for="name" string="Contract Name"
|
||||||
@@ -68,7 +69,8 @@
|
|||||||
<notebook>
|
<notebook>
|
||||||
<page name="recurring_invoice_line"
|
<page name="recurring_invoice_line"
|
||||||
string="Recurring Invoices">
|
string="Recurring Invoices">
|
||||||
<field name="recurring_invoice_line_ids" context="{'default_contract_type': contract_type}"/>
|
<field name="recurring_invoice_line_ids"
|
||||||
|
context="{'default_contract_type': contract_type}"/>
|
||||||
</page>
|
</page>
|
||||||
<page name="info" string="Other Information">
|
<page name="info" string="Other Information">
|
||||||
<div invisible="1">
|
<div invisible="1">
|
||||||
|
|||||||
@@ -13,16 +13,20 @@ class AccountAnalyticInvoiceLineWizard(models.TransientModel):
|
|||||||
date_end = fields.Date(string='Date End')
|
date_end = fields.Date(string='Date End')
|
||||||
recurring_next_date = fields.Date(string='Next Invoice Date')
|
recurring_next_date = fields.Date(string='Next Invoice Date')
|
||||||
is_auto_renew = fields.Boolean(string="Auto Renew", default=False)
|
is_auto_renew = fields.Boolean(string="Auto Renew", default=False)
|
||||||
|
is_suspended = fields.Boolean(string="Is a suspension", default=False)
|
||||||
contract_line_id = fields.Many2one(
|
contract_line_id = fields.Many2one(
|
||||||
comodel_name="account.analytic.invoice.line",
|
comodel_name="account.analytic.invoice.line",
|
||||||
string="Contract Line",
|
string="Contract Line",
|
||||||
required=True,
|
required=True,
|
||||||
|
index=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
@api.multi
|
@api.multi
|
||||||
def stop(self):
|
def stop(self):
|
||||||
for wizard in self:
|
for wizard in self:
|
||||||
wizard.contract_line_id.stop(wizard.date_end)
|
wizard.contract_line_id.stop(
|
||||||
|
wizard.date_end, is_suspended=wizard.is_suspended
|
||||||
|
)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@api.multi
|
@api.multi
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
<group>
|
<group>
|
||||||
<field name="contract_line_id" invisible="True"/>
|
<field name="contract_line_id" invisible="True"/>
|
||||||
<field string="Stop Date" name="date_end" required="True"/>
|
<field string="Stop Date" name="date_end" required="True"/>
|
||||||
|
<field string="Is a suspension" name="is_suspended"/>
|
||||||
</group>
|
</group>
|
||||||
<footer>
|
<footer>
|
||||||
<button name="stop"
|
<button name="stop"
|
||||||
|
|||||||
Reference in New Issue
Block a user