From df451582fc638b7eb574d32d589469d700d83258 Mon Sep 17 00:00:00 2001 From: sbejaoui Date: Mon, 21 Jan 2019 19:02:48 +0100 Subject: [PATCH] [IMP] - Simplify sale order line creation for contract product --- product_contract/__manifest__.py | 4 +- product_contract/models/contract_line.py | 6 +- product_contract/models/product_template.py | 20 +---- product_contract/models/sale_order_line.py | 82 ++++++++++----------- product_contract/tests/test_sale_order.py | 19 ++--- product_contract/views/product_template.xml | 18 +---- product_contract/views/sale_order.xml | 14 +--- 7 files changed, 59 insertions(+), 104 deletions(-) diff --git a/product_contract/__manifest__.py b/product_contract/__manifest__.py index aa0f3b74..5f112894 100644 --- a/product_contract/__manifest__.py +++ b/product_contract/__manifest__.py @@ -7,7 +7,9 @@ 'version': '12.0.1.0.0', 'category': 'Contract Management', 'license': 'AGPL-3', - 'author': "LasLabs, " "ACSONE SA/NV, " "Odoo Community Association (OCA)", + 'author': "LasLabs, " + "ACSONE SA/NV, " + "Odoo Community Association (OCA)", 'website': 'https://github.com/oca/contract', 'depends': ['product', 'contract_sale'], 'data': [ diff --git a/product_contract/models/contract_line.py b/product_contract/models/contract_line.py index ca5cd9a5..1e0cd4fe 100644 --- a/product_contract/models/contract_line.py +++ b/product_contract/models/contract_line.py @@ -33,10 +33,10 @@ class AccountAnalyticInvoiceLine(models.Model): rec.recurring_invoicing_type = ( rec.product_id.recurring_invoicing_type ) - rec.recurring_interval = rec.product_id.recurring_interval + rec.recurring_interval = 1 rec.is_auto_renew = rec.product_id.is_auto_renew - rec.auto_renew_interval = rec.product_id.auto_renew_interval - rec.auto_renew_rule_type = rec.product_id.auto_renew_rule_type + rec.auto_renew_interval = rec.product_id.default_qty + rec.auto_renew_rule_type = rec.product_id.recurring_rule_type rec.termination_notice_interval = ( rec.product_id.termination_notice_interval ) diff --git a/product_contract/models/product_template.py b/product_contract/models/product_template.py index d3fd0b55..f73cc3af 100644 --- a/product_contract/models/product_template.py +++ b/product_contract/models/product_template.py @@ -13,7 +13,7 @@ class ProductTemplate(models.Model): contract_template_id = fields.Many2one( comodel_name='account.analytic.contract', string='Contract Template' ) - + default_qty = fields.Integer(string="Default Quantity") recurring_rule_type = fields.Selection( [ ('daily', 'Day(s)'), @@ -23,7 +23,7 @@ class ProductTemplate(models.Model): ('yearly', 'Year(s)'), ], default='monthly', - string='Recurrence', + string='Invoice Every', help="Specify Interval for automatic invoice generation.", ) recurring_invoicing_type = fields.Selection( @@ -32,23 +32,7 @@ class ProductTemplate(models.Model): string='Invoicing type', help="Specify if process date is 'from' or 'to' invoicing date", ) - recurring_interval = fields.Integer( - default=1, - 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' ) diff --git a/product_contract/models/sale_order_line.py b/product_contract/models/sale_order_line.py index a99f96d3..049f778c 100644 --- a/product_contract/models/sale_order_line.py +++ b/product_contract/models/sale_order_line.py @@ -31,8 +31,7 @@ class SaleOrderLine(models.Model): ('yearly', 'Year(s)'), ], default='monthly', - string='Recurrence', - help="Specify Interval for automatic invoice generation.", + string='Invoice Every', copy=False, ) recurring_invoicing_type = fields.Selection( @@ -42,12 +41,6 @@ class SaleOrderLine(models.Model): help="Specify if process date is 'from' or 'to' invoicing date", copy=False, ) - recurring_interval = fields.Integer( - default=1, - string='Repeat Every', - help="Repeat every (Days/Week/Month/Year)", - copy=False, - ) date_start = fields.Date(string='Date Start') date_end = fields.Date(string='Date End') @@ -57,48 +50,42 @@ 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): contract_line_env = self.env['account.analytic.invoice.line'] for rec in self: if rec.product_id.is_contract: + rec.product_uom_qty = rec.product_id.default_qty rec.recurring_rule_type = rec.product_id.recurring_rule_type rec.recurring_invoicing_type = ( rec.product_id.recurring_invoicing_type ) - rec.recurring_interval = rec.product_id.recurring_interval rec.date_start = rec.date_start or fields.Date.today() - if rec.product_id.is_auto_renew: - rec.date_end = ( - rec.date_start - + contract_line_env.get_relative_delta( - rec.product_id.auto_renew_rule_type, - rec.product_id.auto_renew_interval, - ) - - relativedelta(days=1) + rec.date_end = ( + rec.date_start + + contract_line_env.get_relative_delta( + rec.product_id.recurring_rule_type, + int(rec.product_uom_qty), ) + - relativedelta(days=1) + ) - @api.onchange('date_start') + @api.onchange('date_start', 'product_uom_qty', 'recurring_rule_type') def onchange_date_start(self): for rec in self: - if rec.product_id.is_auto_renew: - if not rec.date_start: - rec.date_end = False - else: - rec.date_end = ( - rec.date_start - + self.env[ - 'account.analytic.invoice.line' - ].get_relative_delta( - rec.product_id.auto_renew_rule_type, - rec.product_id.auto_renew_interval, - ) - - relativedelta(days=1) + if not rec.date_start: + rec.date_end = False + else: + rec.date_end = ( + rec.date_start + + self.env[ + 'account.analytic.invoice.line' + ].get_relative_delta( + rec.recurring_rule_type, int(rec.product_uom_qty) ) + - relativedelta(days=1) + ) @api.multi def _prepare_contract_line_values( @@ -111,7 +98,7 @@ class SaleOrderLine(models.Model): self.date_start or fields.Date.today(), self.recurring_invoicing_type, self.recurring_rule_type, - self.recurring_interval, + int(self.product_uom_qty), ) termination_notice_interval = ( self.product_id.termination_notice_interval @@ -123,19 +110,31 @@ class SaleOrderLine(models.Model): 'sequence': self.sequence, 'product_id': self.product_id.id, 'name': self.name, - 'quantity': self.product_uom_qty, + # The quantity on the generated contract line is 1, as it + # correspond to the most common use cases: + # - quantity on the SO line = number of periods sold and unit + # price the price of one period, so the + # total amount of the SO corresponds to the planned value + # of the contract; in this case the quantity on the contract + # line must be 1 + # - quantity on the SO line = number of hours sold, + # automatic invoicing of the actual hours through a variable + # quantity formula, in which case the quantity on the contract + # line is not used + # Other use cases are easy to implement by overriding this method. + 'quantity': 1.0, 'uom_id': self.product_uom.id, 'price_unit': self.price_unit, 'discount': self.discount, 'date_end': self.date_end, 'date_start': self.date_start or fields.Date.today(), 'recurring_next_date': recurring_next_date, - 'recurring_interval': self.recurring_interval, + 'recurring_interval': 1, '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, + 'auto_renew_interval': self.product_uom_qty, + 'auto_renew_rule_type': self.product_id.recurring_rule_type, 'termination_notice_interval': termination_notice_interval, 'termination_notice_rule_type': termination_notice_rule_type, 'contract_id': contract.id, @@ -153,8 +152,9 @@ class SaleOrderLine(models.Model): rec.date_start - relativedelta(days=1) ) new_contract_line = contract_line_env.create( - rec._prepare_contract_line_values(contract, - rec.contract_line_id) + rec._prepare_contract_line_values( + contract, rec.contract_line_id + ) ) if rec.contract_line_id: rec.contract_line_id.successor_contract_line_id = ( diff --git a/product_contract/tests/test_sale_order.py b/product_contract/tests/test_sale_order.py index a13aa121..33180659 100644 --- a/product_contract/tests/test_sale_order.py +++ b/product_contract/tests/test_sale_order.py @@ -41,7 +41,7 @@ class TestSaleOrder(TransactionCase): self.product1.write( { 'is_contract': True, - 'is_auto_renew': True, + 'default_qty': 12, 'contract_template_id': self.contract_template1.id, } ) @@ -55,6 +55,7 @@ class TestSaleOrder(TransactionCase): lambda l: l.product_id == self.product1 ) self.order_line1.date_start = '2018-01-01' + self.order_line1.product_uom_qty = 12 pricelist = self.sale.partner_id.property_product_pricelist.id self.contract = self.env["account.analytic.account"].create( { @@ -91,10 +92,6 @@ 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 """ @@ -122,10 +119,6 @@ class TestSaleOrder(TransactionCase): self.order_line1.recurring_rule_type, self.product1.recurring_rule_type, ) - self.assertEqual( - self.order_line1.recurring_interval, - self.product1.recurring_interval, - ) self.assertEqual( self.order_line1.recurring_invoicing_type, self.product1.recurring_invoicing_type, @@ -228,10 +221,8 @@ class TestSaleOrder(TransactionCase): { 'recurring_rule_type': 'monthly', 'recurring_invoicing_type': 'pre-paid', - 'recurring_interval': '2', 'is_auto_renew': True, - 'auto_renew_interval': '6', - 'auto_renew_rule_type': 'monthly', + 'default_qty': 12, 'termination_notice_interval': '6', 'termination_notice_rule_type': 'weekly', } @@ -249,9 +240,9 @@ class TestSaleOrder(TransactionCase): self.assertEqual( self.contract_line.recurring_invoicing_type, 'pre-paid' ) - self.assertEqual(self.contract_line.recurring_interval, 2) + self.assertEqual(self.contract_line.recurring_interval, 1) self.assertEqual(self.contract_line.is_auto_renew, True) - self.assertEqual(self.contract_line.auto_renew_interval, 6) + self.assertEqual(self.contract_line.auto_renew_interval, 12) self.assertEqual(self.contract_line.auto_renew_rule_type, 'monthly') self.assertEqual(self.contract_line.termination_notice_interval, 6) self.assertEqual( diff --git a/product_contract/views/product_template.xml b/product_contract/views/product_template.xml index dcc54cae..fd26d555 100644 --- a/product_contract/views/product_template.xml +++ b/product_contract/views/product_template.xml @@ -29,30 +29,16 @@ - + -