mirror of
https://github.com/OCA/contract.git
synced 2025-02-13 17:57:24 +02:00
[ADD] - Add renewal process with termination notice
This commit is contained in:
@@ -16,3 +16,12 @@ class AccountAbstractAnalyticContractLine(models.AbstractModel):
|
||||
)
|
||||
self.recurring_interval = self.product_id.recurring_interval
|
||||
self.date_start = fields.Date.today()
|
||||
self.is_auto_renew = self.product_id.is_auto_renew
|
||||
self.auto_renew_interval = self.product_id.auto_renew_interval
|
||||
self.auto_renew_rule_type = self.product_id.auto_renew_rule_type
|
||||
self.termination_notice_interval = (
|
||||
self.product_id.termination_notice_interval
|
||||
)
|
||||
self.termination_notice_rule_type = (
|
||||
self.product_id.termination_notice_rule_type
|
||||
)
|
||||
|
||||
@@ -37,6 +37,26 @@ class ProductTemplate(models.Model):
|
||||
string='Repeat Every',
|
||||
help="Repeat every (Days/Week/Month/Year)",
|
||||
)
|
||||
is_auto_renew = fields.Boolean(string="Auto Renew", default=False)
|
||||
auto_renew_interval = fields.Integer(
|
||||
default=1,
|
||||
string='Renew Every',
|
||||
help="Renew every (Days/Week/Month/Year)",
|
||||
)
|
||||
auto_renew_rule_type = fields.Selection(
|
||||
[('monthly', 'Month(s)'), ('yearly', 'Year(s)')],
|
||||
default='yearly',
|
||||
string='Renewal type',
|
||||
help="Specify Interval for automatic renewal.",
|
||||
)
|
||||
termination_notice_interval = fields.Integer(
|
||||
default=1, string='Termination Notice Before'
|
||||
)
|
||||
termination_notice_rule_type = fields.Selection(
|
||||
[('daily', 'Day(s)'), ('weekly', 'Week(s)'), ('monthly', 'Month(s)')],
|
||||
default='monthly',
|
||||
string='Termination Notice type',
|
||||
)
|
||||
|
||||
@api.onchange('is_contract')
|
||||
def _change_is_contract(self):
|
||||
|
||||
@@ -47,8 +47,8 @@ class SaleOrderLine(models.Model):
|
||||
help="Repeat every (Days/Week/Month/Year)",
|
||||
copy=False,
|
||||
)
|
||||
date_start = fields.Date(string='Date Start')
|
||||
date_end = fields.Date(string='Date End', index=True)
|
||||
date_start = fields.Date(string='Date Start',)
|
||||
date_end = fields.Date(string='Date End',)
|
||||
|
||||
contract_line_id = fields.Many2one(
|
||||
comodel_name="account.analytic.invoice.line",
|
||||
@@ -56,6 +56,11 @@ class SaleOrderLine(models.Model):
|
||||
required=False,
|
||||
copy=False,
|
||||
)
|
||||
is_auto_renew = fields.Boolean(
|
||||
string="Auto Renew",
|
||||
related="product_id.is_auto_renew",
|
||||
readonly=True,
|
||||
)
|
||||
|
||||
@api.onchange('product_id')
|
||||
def onchange_product(self):
|
||||
@@ -65,7 +70,14 @@ class SaleOrderLine(models.Model):
|
||||
self.product_id.recurring_invoicing_type
|
||||
)
|
||||
self.recurring_interval = self.product_id.recurring_interval
|
||||
self.date_start = fields.Date.today()
|
||||
self.date_start = self.date_start or fields.Date.today()
|
||||
if self.product_id.is_auto_renew:
|
||||
self.date_end = self.date_start + self.env[
|
||||
'account.analytic.invoice.line'
|
||||
].get_relative_delta(
|
||||
self.product_id.auto_renew_rule_type,
|
||||
self.product_id.auto_renew_interval,
|
||||
)
|
||||
|
||||
@api.multi
|
||||
def _prepare_contract_line_values(self, contract):
|
||||
@@ -91,6 +103,13 @@ class SaleOrderLine(models.Model):
|
||||
'recurring_interval': self.recurring_interval,
|
||||
'recurring_invoicing_type': self.recurring_invoicing_type,
|
||||
'recurring_rule_type': self.recurring_rule_type,
|
||||
'is_auto_renew': self.product_id.is_auto_renew,
|
||||
'auto_renew_interval': self.product_id.auto_renew_interval,
|
||||
'auto_renew_rule_type': self.product_id.auto_renew_rule_type,
|
||||
'termination_notice_interval':
|
||||
self.product_id.termination_notice_interval,
|
||||
'termination_notice_rule_type':
|
||||
self.product_id.termination_notice_rule_type,
|
||||
'contract_id': contract.id,
|
||||
'sale_order_line_id': self.id,
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ class TestSaleOrder(TransactionCase):
|
||||
self.product1.write(
|
||||
{
|
||||
'is_contract': True,
|
||||
'is_auto_renew': True,
|
||||
'contract_template_id': self.contract_template1.id,
|
||||
}
|
||||
)
|
||||
@@ -52,6 +53,7 @@ class TestSaleOrder(TransactionCase):
|
||||
self.order_line1 = self.sale.order_line.filtered(
|
||||
lambda l: l.product_id == self.product1
|
||||
)
|
||||
self.order_line1.date_start = '2018-01-01'
|
||||
self.contract = self.env["account.analytic.account"].create(
|
||||
{
|
||||
"name": "Test Contract 2",
|
||||
@@ -88,9 +90,14 @@ class TestSaleOrder(TransactionCase):
|
||||
contract"""
|
||||
self.assertTrue(self.sale.is_contract)
|
||||
|
||||
def test_action_confirm_auto_renew_without_date_end(self):
|
||||
with self.assertRaises(ValidationError):
|
||||
self.sale.action_confirm()
|
||||
|
||||
def test_action_confirm(self):
|
||||
""" It should create a contract for each contract template used in
|
||||
order_line """
|
||||
self.order_line1.onchange_product()
|
||||
self.sale.action_confirm()
|
||||
contracts = self.sale.order_line.mapped('contract_id')
|
||||
self.assertEqual(len(contracts), 2)
|
||||
@@ -102,12 +109,14 @@ class TestSaleOrder(TransactionCase):
|
||||
def test_sale_contract_count(self):
|
||||
"""It should count contracts as many different contract template used
|
||||
in order_line"""
|
||||
self.order_line1.onchange_product()
|
||||
self.sale.action_confirm()
|
||||
self.assertEqual(self.sale.contract_count, 2)
|
||||
|
||||
def test_onchange_product(self):
|
||||
""" It should get recurrence invoicing info to the sale line from
|
||||
its product """
|
||||
self.order_line1.onchange_product()
|
||||
self.assertEqual(
|
||||
self.order_line1.recurring_rule_type,
|
||||
self.product1.recurring_rule_type,
|
||||
@@ -120,6 +129,10 @@ class TestSaleOrder(TransactionCase):
|
||||
self.order_line1.recurring_invoicing_type,
|
||||
self.product1.recurring_invoicing_type,
|
||||
)
|
||||
self.assertEqual(
|
||||
self.order_line1.date_end,
|
||||
Date.to_date('2019-01-01'),
|
||||
)
|
||||
|
||||
def test_check_contract_sale_partner(self):
|
||||
"""Can't link order line to a partner contract different then the
|
||||
@@ -155,6 +168,7 @@ class TestSaleOrder(TransactionCase):
|
||||
def test_sale_order_line_invoice_status(self):
|
||||
"""Sale order line for contract product should have nothing to
|
||||
invoice as status"""
|
||||
self.order_line1.onchange_product()
|
||||
self.sale.action_confirm()
|
||||
self.assertEqual(self.order_line1.invoice_status, 'no')
|
||||
|
||||
@@ -164,6 +178,7 @@ class TestSaleOrder(TransactionCase):
|
||||
self.sale.order_line.filtered(
|
||||
lambda line: not line.product_id.is_contract
|
||||
).unlink()
|
||||
self.order_line1.onchange_product()
|
||||
self.sale.action_confirm()
|
||||
self.assertEqual(self.sale.invoice_status, 'no')
|
||||
|
||||
@@ -171,6 +186,7 @@ class TestSaleOrder(TransactionCase):
|
||||
"""Should not invoice contract product on sale order create invoice"""
|
||||
self.product2.is_contract = False
|
||||
self.product2.invoice_policy = 'order'
|
||||
self.order_line1.onchange_product()
|
||||
self.sale.action_confirm()
|
||||
self.sale.action_invoice_create()
|
||||
self.assertEqual(len(self.sale.invoice_ids), 1)
|
||||
@@ -181,6 +197,7 @@ class TestSaleOrder(TransactionCase):
|
||||
|
||||
def test_link_contract_invoice_to_sale_order(self):
|
||||
"""It should link contract invoice to sale order"""
|
||||
self.order_line1.onchange_product()
|
||||
self.sale.action_confirm()
|
||||
invoice = self.order_line1.contract_id.recurring_create_invoice()
|
||||
self.assertTrue(invoice in self.sale.invoice_ids)
|
||||
@@ -189,8 +206,14 @@ class TestSaleOrder(TransactionCase):
|
||||
"""Should stop contract line at sale order line start date"""
|
||||
self.order_line1.contract_id = self.contract
|
||||
self.order_line1.contract_line_id = self.contract_line
|
||||
self.order_line1.date_start = "2018-01-01"
|
||||
self.contract_line.date_end = "2019-01-01"
|
||||
self.contract_line.is_auto_renew = "2019-01-01"
|
||||
self.order_line1.date_start = "2018-06-01"
|
||||
self.order_line1.onchange_product()
|
||||
self.sale.action_confirm()
|
||||
self.assertEqual(
|
||||
self.contract_line.date_end, Date.to_date("2018-01-01")
|
||||
self.contract_line.date_end, Date.to_date("2018-06-01")
|
||||
)
|
||||
self.assertFalse(
|
||||
self.contract_line.is_auto_renew
|
||||
)
|
||||
|
||||
@@ -19,24 +19,45 @@
|
||||
<label for="is_contract"/>
|
||||
</div>
|
||||
</xpath>
|
||||
<xpath expr="//group[@name='group_standard_price']"
|
||||
position="inside">
|
||||
<field name="contract_template_id"
|
||||
attrs="{'invisible': [('is_contract', '=', False)],
|
||||
'required':[('is_contract', '=', True)]}"/>
|
||||
<field name="recurring_invoicing_type"
|
||||
attrs="{'invisible': [('is_contract', '=', False)],
|
||||
'required':[('is_contract', '=', True)]}"/>
|
||||
<xpath expr="//notebook" position="inside">
|
||||
<page string="Contract"
|
||||
attrs="{'invisible': [('is_contract', '=', False)],}">
|
||||
<group>
|
||||
<field name="contract_template_id"
|
||||
attrs="{'required':[('is_contract', '=', True)]}"/>
|
||||
<field name="recurring_invoicing_type"
|
||||
attrs="{'required':[('is_contract', '=', True)]}"/>
|
||||
|
||||
<label for="recurring_interval" attrs="{'invisible': [('is_contract', '=', False)],
|
||||
<label for="recurring_interval" attrs="{'required':[('is_contract', '=', True)]}"/>
|
||||
<div attrs="{'required':[('is_contract', '=', True)]}">
|
||||
<field name="recurring_interval"
|
||||
class="oe_inline" nolabel="1"/>
|
||||
<field name="recurring_rule_type"
|
||||
class="oe_inline" nolabel="1"/>
|
||||
</div>
|
||||
</group>
|
||||
<group>
|
||||
<field name="is_auto_renew"/>
|
||||
<label for="auto_renew_interval" attrs="{'invisible': [('is_auto_renew', '=', False)],
|
||||
'required':[('is_contract', '=', True)]}"/>
|
||||
<div attrs="{'invisible': [('is_contract', '=', False)],
|
||||
'required':[('is_contract', '=', True)]}">
|
||||
<field name="recurring_interval"
|
||||
class="oe_inline" nolabel="1"/>
|
||||
<field name="recurring_rule_type"
|
||||
class="oe_inline" nolabel="1"/>
|
||||
</div>
|
||||
<div attrs="{'invisible': [('is_auto_renew', '=', False)],
|
||||
'required':[('is_auto_renew', '=', True)]}">
|
||||
<field name="auto_renew_interval"
|
||||
class="oe_inline" nolabel="1"/>
|
||||
<field name="auto_renew_rule_type"
|
||||
class="oe_inline" nolabel="1"/>
|
||||
</div>
|
||||
<label for="termination_notice_interval" attrs="{'invisible': [('is_auto_renew', '=', False)],
|
||||
'required':[('is_contract', '=', True)]}"/>
|
||||
<div attrs="{'invisible': [('is_auto_renew', '=', False)],
|
||||
'required':[('is_auto_renew', '=', True)]}">
|
||||
<field name="termination_notice_interval"
|
||||
class="oe_inline" nolabel="1"/>
|
||||
<field name="termination_notice_rule_type"
|
||||
class="oe_inline" nolabel="1"/>
|
||||
</div>
|
||||
</group>
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -34,6 +34,8 @@
|
||||
<field name="contract_line_id"
|
||||
attrs="{'invisible': [('is_contract', '=', False)]}"
|
||||
domain="[('contract_id','=',contract_id)]"/>
|
||||
<field name="is_auto_renew"
|
||||
invisible="1"/>
|
||||
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='order_line']/form//field[@name='tax_id']/parent::group"
|
||||
@@ -58,10 +60,10 @@
|
||||
</div>
|
||||
</group>
|
||||
<group attrs="{'invisible': [('is_contract', '=', False)]}">
|
||||
<field name="date_start"/>
|
||||
<field name="date_start" attrs="{'required': [('is_contract', '=', True)]}"/>
|
||||
</group>
|
||||
<group attrs="{'invisible': [('is_contract', '=', False)]}">
|
||||
<field name="date_end"/>
|
||||
<field name="date_end" attrs="{'required': [('is_auto_renew', '=', True)]}"/>
|
||||
</group>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='order_line']/tree//field[@name='price_total']"
|
||||
|
||||
Reference in New Issue
Block a user