diff --git a/product_contract/__manifest__.py b/product_contract/__manifest__.py index 970265ff..f369b825 100644 --- a/product_contract/__manifest__.py +++ b/product_contract/__manifest__.py @@ -17,7 +17,8 @@ 'contract_sale', ], 'data': [ - 'views/product_template_view.xml', + 'views/product_template.xml', + 'views/sale_order.xml', ], 'installable': True, 'application': False, diff --git a/product_contract/models/product_template.py b/product_contract/models/product_template.py index 1016c60c..1d256201 100644 --- a/product_contract/models/product_template.py +++ b/product_contract/models/product_template.py @@ -15,6 +15,30 @@ class ProductTemplate(models.Model): comodel_name='account.analytic.contract', string='Contract Template' ) + recurring_rule_type = fields.Selection( + [ + ('daily', 'Day(s)'), + ('weekly', 'Week(s)'), + ('monthly', 'Month(s)'), + ('monthlylastday', 'Month(s) last day'), + ('yearly', 'Year(s)'), + ], + default='monthly', + string='Recurrence', + help="Specify Interval for automatic invoice generation.", + ) + recurring_invoicing_type = fields.Selection( + [('pre-paid', 'Pre-paid'), ('post-paid', 'Post-paid')], + default='pre-paid', + 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)", + ) + @api.onchange('is_contract') def _change_is_contract(self): """ Clear the relation to contract_template_id when downgrading diff --git a/product_contract/models/sale_order.py b/product_contract/models/sale_order.py index 45f2eec7..443eaaff 100644 --- a/product_contract/models/sale_order.py +++ b/product_contract/models/sale_order.py @@ -2,12 +2,22 @@ # Copyright 2017 LasLabs Inc. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from odoo import api, models +from odoo import fields, api, models class SaleOrder(models.Model): _inherit = 'sale.order' + is_contract = fields.Boolean( + string='Is a contract', compute="_compute_is_contract" + ) + + @api.depends('order_line') + def _compute_is_contract(self): + self.is_contract = any( + self.order_line.mapped('is_contract') + ) + @api.multi def action_confirm(self): """ If we have a contract in the order, set it up """ diff --git a/product_contract/models/sale_order_line.py b/product_contract/models/sale_order_line.py index c76c1059..23da9c1c 100644 --- a/product_contract/models/sale_order_line.py +++ b/product_contract/models/sale_order_line.py @@ -1,14 +1,57 @@ # -*- coding: utf-8 -*- # Copyright 2017 LasLabs Inc. +# Copyright 2017 ACSONE SA/NV. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from odoo import fields, models +from odoo import api, fields, models class SaleOrderLine(models.Model): _inherit = 'sale.order.line' + is_contract = fields.Boolean( + string='Is a contract', related="product_id.is_contract" + ) contract_id = fields.Many2one( - comodel_name='account.analytic.account', - string='Contract' + comodel_name='account.analytic.account', string='Contract' + ) + recurring_rule_type = fields.Selection( + [ + ('daily', 'Day(s)'), + ('weekly', 'Week(s)'), + ('monthly', 'Month(s)'), + ('monthlylastday', 'Month(s) last day'), + ('yearly', 'Year(s)'), + ], + default='monthly', + string='Recurrence', + help="Specify Interval for automatic invoice generation.", + copy=False, + ) + recurring_invoicing_type = fields.Selection( + [('pre-paid', 'Pre-paid'), ('post-paid', 'Post-paid')], + default='pre-paid', + string='Invoicing type', + 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', default=fields.Date.today()) + date_end = fields.Date(string='Date End', index=True) + recurring_next_date = fields.Date( + default=fields.Date.today(), copy=False, string='Date of Next Invoice' + ) + + @api.onchange('product_id') + def onchange_product(self): + if self.product_id.is_contract: + self.recurring_rule_type = self.product_id.recurring_rule_type + self.recurring_invoicing_type = ( + self.product_id.recurring_invoicing_type + ) + self.recurring_interval = self.product_id.recurring_interval diff --git a/product_contract/tests/__init__.py b/product_contract/tests/__init__.py index b4af49c0..4766d5ea 100644 --- a/product_contract/tests/__init__.py +++ b/product_contract/tests/__init__.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- # Copyright 2017 LasLabs Inc. +# Copyright 2018 ACSONE SA/NV. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from . import test_product from . import test_sale_order +from . import test_sale_order_line diff --git a/product_contract/tests/test_sale_order.py b/product_contract/tests/test_sale_order.py index f8a90e34..e8f66602 100644 --- a/product_contract/tests/test_sale_order.py +++ b/product_contract/tests/test_sale_order.py @@ -27,6 +27,8 @@ class TestSaleOrder(TransactionCase): def test_action_done(self): """ It should create a contract when the sale for a contract is set to done for the first time """ + + self.assertTrue(self.sale.is_contract) self.env['account.analytic.account']._patch_method( 'create', MagicMock() ) diff --git a/product_contract/tests/test_sale_order_line.py b/product_contract/tests/test_sale_order_line.py new file mode 100644 index 00000000..1f109059 --- /dev/null +++ b/product_contract/tests/test_sale_order_line.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 ACSONE SA/NV. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from mock import MagicMock +from odoo.tests.common import TransactionCase + + +class TestSaleOrder(TransactionCase): + + def setUp(self): + super(TestSaleOrder, self).setUp() + self.product = self.env.ref('product.product_product_1') + self.sale = self.env.ref('sale.sale_order_2') + self.contract = self.env['account.analytic.contract'].create({ + 'name': 'Test', + }) + self.product.product_tmpl_id.is_contract = True + self.sale_order_line = self.sale.order_line.filtered( + lambda l: l.product_id == self.product + ) + + def test_onchange_product(self): + """ It should get recurrence invoicing info to the sale line from + its product """ + self.assertEqual( + self.sale_order_line.recurring_rule_type, + self.product.recurring_rule_type + ) + self.assertEqual( + self.sale_order_line.recurring_interval, + self.product.recurring_interval + ) + self.assertEqual( + self.sale_order_line.recurring_invoicing_type, + self.product.recurring_invoicing_type + ) diff --git a/product_contract/views/product_template.xml b/product_contract/views/product_template.xml new file mode 100644 index 00000000..9eb3b38f --- /dev/null +++ b/product_contract/views/product_template.xml @@ -0,0 +1,44 @@ + + + + + + + + account.invoice.select.contract + product.template + + + +
+ +
+
+ + + + + +
+
+ +
diff --git a/product_contract/views/product_template_view.xml b/product_contract/views/product_template_view.xml deleted file mode 100644 index 46c2e05c..00000000 --- a/product_contract/views/product_template_view.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - account.invoice.select.contract - product.template - - - -
- -
-
- - - -
-
- -
diff --git a/product_contract/views/sale_order.xml b/product_contract/views/sale_order.xml new file mode 100644 index 00000000..f27c4025 --- /dev/null +++ b/product_contract/views/sale_order.xml @@ -0,0 +1,63 @@ + + + + + + + + sale.order.form (in product_contract) + sale.order + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +