Browse Source

[IMP] - Add recurrence fields to product template and sale order line

pull/208/head
sbejaoui 6 years ago
committed by Thomas Binsfeld
parent
commit
280eca9819
  1. 3
      product_contract/__manifest__.py
  2. 24
      product_contract/models/product_template.py
  3. 12
      product_contract/models/sale_order.py
  4. 49
      product_contract/models/sale_order_line.py
  5. 2
      product_contract/tests/__init__.py
  6. 2
      product_contract/tests/test_sale_order.py
  7. 37
      product_contract/tests/test_sale_order_line.py
  8. 44
      product_contract/views/product_template.xml
  9. 29
      product_contract/views/product_template_view.xml
  10. 63
      product_contract/views/sale_order.xml

3
product_contract/__manifest__.py

@ -17,7 +17,8 @@
'contract_sale', 'contract_sale',
], ],
'data': [ 'data': [
'views/product_template_view.xml',
'views/product_template.xml',
'views/sale_order.xml',
], ],
'installable': True, 'installable': True,
'application': False, 'application': False,

24
product_contract/models/product_template.py

@ -15,6 +15,30 @@ class ProductTemplate(models.Model):
comodel_name='account.analytic.contract', string='Contract Template' 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') @api.onchange('is_contract')
def _change_is_contract(self): def _change_is_contract(self):
""" Clear the relation to contract_template_id when downgrading """ Clear the relation to contract_template_id when downgrading

12
product_contract/models/sale_order.py

@ -2,12 +2,22 @@
# Copyright 2017 LasLabs Inc. # Copyright 2017 LasLabs Inc.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # 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): class SaleOrder(models.Model):
_inherit = 'sale.order' _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 @api.multi
def action_confirm(self): def action_confirm(self):
""" If we have a contract in the order, set it up """ """ If we have a contract in the order, set it up """

49
product_contract/models/sale_order_line.py

@ -1,14 +1,57 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright 2017 LasLabs Inc. # Copyright 2017 LasLabs Inc.
# Copyright 2017 ACSONE SA/NV.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # 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): class SaleOrderLine(models.Model):
_inherit = 'sale.order.line' _inherit = 'sale.order.line'
is_contract = fields.Boolean(
string='Is a contract', related="product_id.is_contract"
)
contract_id = fields.Many2one( 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

2
product_contract/tests/__init__.py

@ -1,6 +1,8 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# 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.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import test_product from . import test_product
from . import test_sale_order from . import test_sale_order
from . import test_sale_order_line

2
product_contract/tests/test_sale_order.py

@ -27,6 +27,8 @@ class TestSaleOrder(TransactionCase):
def test_action_done(self): def test_action_done(self):
""" It should create a contract when the sale for a contract is set """ It should create a contract when the sale for a contract is set
to done for the first time """ to done for the first time """
self.assertTrue(self.sale.is_contract)
self.env['account.analytic.account']._patch_method( self.env['account.analytic.account']._patch_method(
'create', MagicMock() 'create', MagicMock()
) )

37
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
)

44
product_contract/views/product_template.xml

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2017 LasLabs Inc.
Copyright 2018 ACSONE SA/NV.
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-->
<odoo>
<record id="product_template_form_contract_view" model="ir.ui.view">
<field name="name">account.invoice.select.contract</field>
<field name="model">product.template</field>
<field name="inherit_id" ref="product.product_template_form_view"/>
<field name="arch" type="xml">
<xpath expr="//div[@name='options']" position="inside">
<div>
<field name="is_contract"/>
<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)]}"/>
<label for="recurring_interval" attrs="{'invisible': [('is_contract', '=', 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>
</xpath>
</field>
</record>
</odoo>

29
product_contract/views/product_template_view.xml

@ -1,29 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2017 LasLabs Inc.
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-->
<odoo>
<record id="product_template_form_contract_view" model="ir.ui.view">
<field name="name">account.invoice.select.contract</field>
<field name="model">product.template</field>
<field name="inherit_id" ref="product.product_template_form_view"/>
<field name="arch" type="xml">
<xpath expr="//div[@name='options']" position="inside">
<div>
<field name="is_contract" />
<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)]}" />
</xpath>
</field>
</record>
</odoo>

63
product_contract/views/sale_order.xml

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2018 ACSONE SA/NV.
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-->
<odoo>
<record id="view_order_form" model="ir.ui.view">
<field name="name">sale.order.form (in product_contract)</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='order_line']" position="before">
<field name="is_contract" invisible="1"/>
</xpath>
<xpath expr="//field[@name='order_line']/form//field[@name='tax_id']/parent::group"
position="after">
<separator colspan="4" string="Recurrence Invoicing"
attrs="{'invisible': [('is_contract', '=', False)]}"/>
<group attrs="{'invisible': [('is_contract', '=', False)]}">
<field name="is_contract" invisible="1"/>
<field name="recurring_invoicing_type"
attrs="{'invisible': [('is_contract', '=', False)],
'required':[('is_contract', '=', True)]}"/>
</group>
<group attrs="{'invisible': [('is_contract', '=', False)]}">
<label for="recurring_interval"/>
<div>
<field name="recurring_interval"
class="oe_inline" nolabel="1"
attrs="{'required':[('is_contract', '=', True)]}"/>
<field name="recurring_rule_type"
class="oe_inline" nolabel="1"
attrs="{'required':[('is_contract', '=', True)]}"/>
</div>
</group>
<group attrs="{'invisible': [('is_contract', '=', False)]}">
<field name="date_start"/>
<field name="recurring_next_date"/>
</group>
<group attrs="{'invisible': [('is_contract', '=', False)]}">
<field name="date_end"/>
</group>
</xpath>
<xpath expr="//field[@name='order_line']/tree//field[@name='price_total']"
position="after">
<field name="date_start"
attrs="{'column_invisible': [('parent.is_contract', '=', False)]}"/>
<field name="date_end"
attrs="{'column_invisible': [('parent.is_contract', '=', False)]}"/>
<field name="recurring_next_date"
attrs="{'column_invisible': [('parent.is_contract', '=', False)]}"/>
</xpath>
<xpath expr="//field[@name='order_line']/tree"
position="attributes">
<attribute name="editable"/>
</xpath>
</field>
</record>
</odoo>
Loading…
Cancel
Save