diff --git a/product_contract/models/abstract_contract_line.py b/product_contract/models/abstract_contract_line.py index 1bfe4c8c..2013cc15 100644 --- a/product_contract/models/abstract_contract_line.py +++ b/product_contract/models/abstract_contract_line.py @@ -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 + ) diff --git a/product_contract/models/product_template.py b/product_contract/models/product_template.py index b10ef3de..d3fd0b55 100644 --- a/product_contract/models/product_template.py +++ b/product_contract/models/product_template.py @@ -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): diff --git a/product_contract/models/sale_order_line.py b/product_contract/models/sale_order_line.py index b0434540..7caaf7a3 100644 --- a/product_contract/models/sale_order_line.py +++ b/product_contract/models/sale_order_line.py @@ -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, } diff --git a/product_contract/tests/test_sale_order.py b/product_contract/tests/test_sale_order.py index 37feb78b..09f9d9a9 100644 --- a/product_contract/tests/test_sale_order.py +++ b/product_contract/tests/test_sale_order.py @@ -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 ) diff --git a/product_contract/views/product_template.xml b/product_contract/views/product_template.xml index 9eb3b38f..0ff9f33f 100644 --- a/product_contract/views/product_template.xml +++ b/product_contract/views/product_template.xml @@ -19,24 +19,45 @@