[IMP] contract_variable_quantity: black, isort, prettier

This commit is contained in:
Carlos Roca
2020-10-27 13:35:26 +01:00
committed by Víctor Martínez
parent fc1955b554
commit 8b7e3b4213
12 changed files with 190 additions and 166 deletions

View File

@@ -4,21 +4,20 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{ {
'name': 'Variable quantity in contract recurrent invoicing', "name": "Variable quantity in contract recurrent invoicing",
'version': '12.0.3.0.0', "version": "12.0.3.0.0",
'category': 'Contract Management', "category": "Contract Management",
'license': 'AGPL-3', "license": "AGPL-3",
'author': "Tecnativa," "author": "Tecnativa," "Odoo Community Association (OCA)",
"Odoo Community Association (OCA)", "website": "https://www.tecnativa.com",
'website': 'https://www.tecnativa.com', "depends": ["contract"],
'depends': ['contract'], "data": [
'data': [ "security/ir.model.access.csv",
'security/ir.model.access.csv', "views/abstract_contract_line.xml",
'views/abstract_contract_line.xml', "views/contract_line_formula.xml",
'views/contract_line_formula.xml', "views/contract_line_views.xml",
'views/contract_line_views.xml', "views/contract_template.xml",
'views/contract_template.xml', "views/contract.xml",
'views/contract.xml',
], ],
'installable': True, "installable": True,
} }

View File

@@ -10,23 +10,41 @@ _logger = logging.getLogger(__name__)
def migrate(cr, version): def migrate(cr, version):
xmlids_to_rename = [ xmlids_to_rename = [
('contract_sale.account_analytic_account_own_salesman', (
'contract_sale.contract_contract_own_salesman'), "contract_sale.account_analytic_account_own_salesman",
('contract_sale.account_analytic_account_see_all', "contract_sale.contract_contract_own_salesman",
'contract_sale.contract_contract_see_all'), ),
('contract_sale.account_analytic_contract_salesman', (
'contract_sale.contract_template_salesman'), "contract_sale.account_analytic_account_see_all",
('contract_sale.account_analytic_contract_sale_manager', "contract_sale.contract_contract_see_all",
'contract_sale.contract_template_sale_manager'), ),
('contract_sale.account_analytic_invoice_line_saleman', (
'contract_sale.contract_line_saleman'), "contract_sale.account_analytic_contract_salesman",
('contract_sale.account_analytic_invoice_line_manager', "contract_sale.contract_template_salesman",
'contract_sale.contract_line_manager'), ),
('contract_sale.account_analytic_contract_line_salesman', (
'contract_sale.contract_template_line_salesman'), "contract_sale.account_analytic_contract_sale_manager",
('contract_sale.account_analytic_contract_line_manager', "contract_sale.contract_template_sale_manager",
'contract_sale.contract_template_line_manager'), ),
('contract_sale.account_analytic_account_contract_salesman', (
'contract_sale.contract_contract_salesman'), "contract_sale.account_analytic_invoice_line_saleman",
"contract_sale.contract_line_saleman",
),
(
"contract_sale.account_analytic_invoice_line_manager",
"contract_sale.contract_line_manager",
),
(
"contract_sale.account_analytic_contract_line_salesman",
"contract_sale.contract_template_line_salesman",
),
(
"contract_sale.account_analytic_contract_line_manager",
"contract_sale.contract_template_line_manager",
),
(
"contract_sale.account_analytic_account_contract_salesman",
"contract_sale.contract_contract_salesman",
),
] ]
openupgrade.rename_xmlids(cr, xmlids_to_rename) openupgrade.rename_xmlids(cr, xmlids_to_rename)

View File

@@ -7,15 +7,12 @@ from odoo import fields, models
class ContractAbstractContractLine(models.AbstractModel): class ContractAbstractContractLine(models.AbstractModel):
_inherit = 'contract.abstract.contract.line' _inherit = "contract.abstract.contract.line"
qty_type = fields.Selection( qty_type = fields.Selection(
selection=[ selection=[("fixed", "Fixed quantity"), ("variable", "Variable quantity")],
('fixed', 'Fixed quantity'),
('variable', 'Variable quantity'),
],
required=True, required=True,
default='fixed', default="fixed",
string="Qty. type", string="Qty. type",
) )
qty_formula_id = fields.Many2one( qty_formula_id = fields.Many2one(

View File

@@ -10,6 +10,6 @@ class ContractContract(models.Model):
_inherit = "contract.contract" _inherit = "contract.contract"
skip_zero_qty = fields.Boolean( skip_zero_qty = fields.Boolean(
string='Skip Zero Qty Lines', string="Skip Zero Qty Lines",
help="If checked, contract lines with 0 qty don't create invoice line", help="If checked, contract lines with 0 qty don't create invoice line",
) )

View File

@@ -9,30 +9,28 @@ from odoo.tools.safe_eval import safe_eval
class AccountAnalyticInvoiceLine(models.Model): class AccountAnalyticInvoiceLine(models.Model):
_inherit = 'contract.line' _inherit = "contract.line"
@api.multi @api.multi
def _get_quantity_to_invoice( def _get_quantity_to_invoice(
self, period_first_date, period_last_date, invoice_date self, period_first_date, period_last_date, invoice_date
): ):
quantity = super( quantity = super(AccountAnalyticInvoiceLine, self)._get_quantity_to_invoice(
AccountAnalyticInvoiceLine, self
)._get_quantity_to_invoice(
period_first_date, period_last_date, invoice_date period_first_date, period_last_date, invoice_date
) )
if not period_first_date or not period_last_date or not invoice_date: if not period_first_date or not period_last_date or not invoice_date:
return quantity return quantity
if self.qty_type == 'variable': if self.qty_type == "variable":
eval_context = { eval_context = {
'env': self.env, "env": self.env,
'context': self.env.context, "context": self.env.context,
'user': self.env.user, "user": self.env.user,
'line': self, "line": self,
'quantity': quantity, "quantity": quantity,
'period_first_date': period_first_date, "period_first_date": period_first_date,
'period_last_date': period_last_date, "period_last_date": period_last_date,
'invoice_date': invoice_date, "invoice_date": invoice_date,
'contract': self.contract_id, "contract": self.contract_id,
} }
safe_eval( safe_eval(
self.qty_formula_id.code.strip(), self.qty_formula_id.code.strip(),
@@ -40,7 +38,7 @@ class AccountAnalyticInvoiceLine(models.Model):
mode="exec", mode="exec",
nocopy=True, nocopy=True,
) # nocopy for returning result ) # nocopy for returning result
quantity = eval_context.get('result', 0) quantity = eval_context.get("result", 0)
return quantity return quantity
@api.multi @api.multi
@@ -49,13 +47,11 @@ class AccountAnalyticInvoiceLine(models.Model):
invoice_id=invoice_id, invoice_values=invoice_values, invoice_id=invoice_id, invoice_values=invoice_values,
) )
if ( if (
'quantity' in vals "quantity" in vals
and self.contract_id.skip_zero_qty and self.contract_id.skip_zero_qty
and float_is_zero( and float_is_zero(
vals['quantity'], vals["quantity"],
self.env['decimal.precision'].precision_get( self.env["decimal.precision"].precision_get("Product Unit of Measure"),
'Product Unit of Measure'
),
) )
): ):
vals = {} vals = {}

View File

@@ -3,38 +3,36 @@
# Copyright 2018 ACSONE SA/NV # Copyright 2018 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import _, api, fields, models, exceptions from odoo import _, api, exceptions, fields, models
from odoo.tools.safe_eval import safe_eval from odoo.tools.safe_eval import safe_eval
class ContractLineFormula(models.Model): class ContractLineFormula(models.Model):
_name = 'contract.line.qty.formula' _name = "contract.line.qty.formula"
_description = 'Contract Line Formula' _description = "Contract Line Formula"
name = fields.Char(required=True, translate=True) name = fields.Char(required=True, translate=True)
code = fields.Text(required=True, default="result = 0") code = fields.Text(required=True, default="result = 0")
@api.constrains('code') @api.constrains("code")
def _check_code(self): def _check_code(self):
eval_context = { eval_context = {
'env': self.env, "env": self.env,
'context': self.env.context, "context": self.env.context,
'user': self.env.user, "user": self.env.user,
'line': self.env['contract.line'], "line": self.env["contract.line"],
'contract': self.env['contract.contract'], "contract": self.env["contract.contract"],
'invoice': self.env['account.invoice'], "invoice": self.env["account.invoice"],
'quantity': 0, "quantity": 0,
'period_first_date': False, "period_first_date": False,
'period_last_date': False, "period_last_date": False,
'invoice_date': False, "invoice_date": False,
} }
try: try:
safe_eval( safe_eval(self.code.strip(), eval_context, mode="exec", nocopy=True)
self.code.strip(), eval_context, mode="exec", nocopy=True
)
except Exception as e: except Exception as e:
raise exceptions.ValidationError( raise exceptions.ValidationError(
_('Error evaluating code.\nDetails: %s') % e _("Error evaluating code.\nDetails: %s") % e
) )
if 'result' not in eval_context: if "result" not in eval_context:
raise exceptions.ValidationError(_('No valid result returned.')) raise exceptions.ValidationError(_("No valid result returned."))

View File

@@ -12,48 +12,46 @@ from odoo import exceptions
class TestContractVariableQuantity(odoo.tests.HttpCase): class TestContractVariableQuantity(odoo.tests.HttpCase):
def setUp(self): def setUp(self):
super(TestContractVariableQuantity, self).setUp() super(TestContractVariableQuantity, self).setUp()
self.partner = self.env['res.partner'].create({'name': 'Test partner'}) self.partner = self.env["res.partner"].create({"name": "Test partner"})
self.product = self.env['product.product'].create( self.product = self.env["product.product"].create({"name": "Test product"})
{'name': 'Test product'} self.contract = self.env["contract.contract"].create(
)
self.contract = self.env['contract.contract'].create(
{ {
'name': 'Test Contract', "name": "Test Contract",
'partner_id': self.partner.id, "partner_id": self.partner.id,
'pricelist_id': self.partner.property_product_pricelist.id, "pricelist_id": self.partner.property_product_pricelist.id,
} }
) )
self.formula = self.env['contract.line.qty.formula'].create( self.formula = self.env["contract.line.qty.formula"].create(
{ {
'name': 'Test formula', "name": "Test formula",
# For testing each of the possible variables # For testing each of the possible variables
'code': 'env["res.users"]\n' "code": 'env["res.users"]\n'
'context.get("lang")\n' 'context.get("lang")\n'
'user.id\n' "user.id\n"
'line.qty_type\n' "line.qty_type\n"
'contract.id\n' "contract.id\n"
'quantity\n' "quantity\n"
'period_first_date\n' "period_first_date\n"
'period_last_date\n' "period_last_date\n"
'invoice_date\n' "invoice_date\n"
'result = 12', "result = 12",
} }
) )
self.contract_line = self.env['contract.line'].create( self.contract_line = self.env["contract.line"].create(
{ {
'contract_id': self.contract.id, "contract_id": self.contract.id,
'product_id': self.product.id, "product_id": self.product.id,
'name': 'Test', "name": "Test",
'qty_type': 'variable', "qty_type": "variable",
'qty_formula_id': self.formula.id, "qty_formula_id": self.formula.id,
'quantity': 1, "quantity": 1,
'uom_id': self.product.uom_id.id, "uom_id": self.product.uom_id.id,
'price_unit': 100, "price_unit": 100,
'discount': 50, "discount": 50,
'recurring_rule_type': 'monthly', "recurring_rule_type": "monthly",
'recurring_interval': 1, "recurring_interval": 1,
'date_start': '2016-02-15', "date_start": "2016-02-15",
'recurring_next_date': '2016-02-29', "recurring_next_date": "2016-02-29",
} }
) )
@@ -71,7 +69,7 @@ class TestContractVariableQuantity(odoo.tests.HttpCase):
self.assertEqual(invoice.invoice_line_ids[0].quantity, 12) self.assertEqual(invoice.invoice_line_ids[0].quantity, 12)
def test_check_skip_zero_qty(self): def test_check_skip_zero_qty(self):
self.formula.code = 'result=0' self.formula.code = "result=0"
self.contract.skip_zero_qty = True self.contract.skip_zero_qty = True
invoice = self.contract.recurring_create_invoice() invoice = self.contract.recurring_create_invoice()
self.assertFalse(invoice.invoice_line_ids) self.assertFalse(invoice.invoice_line_ids)

View File

@@ -1,17 +1,19 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<odoo> <odoo>
<record id="contract_abstract_contract_line_form_view" model="ir.ui.view">
<record id="contract_abstract_contract_line_form_view"
model="ir.ui.view">
<field name="name">Abstract Contract Line Form View</field> <field name="name">Abstract Contract Line Form View</field>
<field name="model">contract.abstract.contract.line</field> <field name="model">contract.abstract.contract.line</field>
<field name="inherit_id" ref="contract.contract_abstract_contract_line_form_view"/> <field
name="inherit_id"
ref="contract.contract_abstract_contract_line_form_view"
/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//label[@for='quantity']" position="before"> <xpath expr="//label[@for='quantity']" position="before">
<field name="qty_type" /> <field name="qty_type" />
</xpath> </xpath>
<xpath expr="//field[@name='quantity']" position="after"> <xpath expr="//field[@name='quantity']" position="after">
<field name="qty_formula_id" <field
name="qty_formula_id"
attrs="{'required': [('qty_type', '=', 'variable')], 'invisible': [('qty_type', '!=', 'variable')]}" attrs="{'required': [('qty_type', '=', 'variable')], 'invisible': [('qty_type', '!=', 'variable')]}"
/> />
</xpath> </xpath>
@@ -22,5 +24,4 @@
</xpath> </xpath>
</field> </field>
</record> </record>
</odoo> </odoo>

View File

@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<odoo> <odoo>
<record id="contract_contract_form_view" model="ir.ui.view"> <record id="contract_contract_form_view" model="ir.ui.view">
<field name="model">contract.contract</field> <field name="model">contract.contract</field>
<field name="inherit_id" ref="contract.contract_contract_form_view" /> <field name="inherit_id" ref="contract.contract_contract_form_view" />
@@ -8,17 +7,24 @@
<xpath expr="//field[@name='code']" position="after"> <xpath expr="//field[@name='code']" position="after">
<field name="skip_zero_qty" /> <field name="skip_zero_qty" />
</xpath> </xpath>
<xpath expr="//field[@name='contract_line_ids']/tree/field[@name='quantity']" position="before"> <xpath
expr="//field[@name='contract_line_ids']/tree/field[@name='quantity']"
position="before"
>
<field name="qty_type" /> <field name="qty_type" />
<field <field
name="qty_formula_id" name="qty_formula_id"
attrs="{'invisible': [('qty_type', '!=', 'variable')]}" attrs="{'invisible': [('qty_type', '!=', 'variable')]}"
/> />
</xpath> </xpath>
<xpath expr="//field[@name='contract_line_ids']/tree/field[@name='quantity']" position="attributes"> <xpath
<attribute name="attrs">{'invisible': [('qty_type', '!=', 'fixed')]}</attribute> expr="//field[@name='contract_line_ids']/tree/field[@name='quantity']"
position="attributes"
>
<attribute
name="attrs"
>{'invisible': [('qty_type', '!=', 'fixed')]}</attribute>
</xpath> </xpath>
</field> </field>
</record> </record>
</odoo> </odoo>

View File

@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<odoo> <odoo>
<record id="view_contract_line_qty_formula_tree" model="ir.ui.view"> <record id="view_contract_line_qty_formula_tree" model="ir.ui.view">
<field name="model">contract.line.qty.formula</field> <field name="model">contract.line.qty.formula</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
@@ -9,7 +8,6 @@
</tree> </tree>
</field> </field>
</record> </record>
<record id="view_contract_line_qty_formula_form" model="ir.ui.view"> <record id="view_contract_line_qty_formula_form" model="ir.ui.view">
<field name="model">contract.line.qty.formula</field> <field name="model">contract.line.qty.formula</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
@@ -22,8 +20,12 @@
</div> </div>
<group string="Code"> <group string="Code">
<div style="margin-top: 4px;"> <div style="margin-top: 4px;">
<field name="code" nolabel="1" widget="ace" <field
options="{'mode': 'python'}"/> name="code"
nolabel="1"
widget="ace"
options="{'mode': 'python'}"
/>
<h3>Help with Python expressions.</h3> <h3>Help with Python expressions.</h3>
<p>You have to insert valid Python code block that <p>You have to insert valid Python code block that
stores at some moment a float/integer value of stores at some moment a float/integer value of
@@ -65,9 +67,7 @@
</form> </form>
</field> </field>
</record> </record>
<record id="action_contract_quantity_formula" model="ir.actions.act_window">
<record id="action_contract_quantity_formula"
model="ir.actions.act_window">
<field name="name">Formulas (quantity)</field> <field name="name">Formulas (quantity)</field>
<field name="res_model">contract.line.qty.formula</field> <field name="res_model">contract.line.qty.formula</field>
<field name="view_type">form</field> <field name="view_type">form</field>
@@ -78,10 +78,9 @@
</p> </p>
</field> </field>
</record> </record>
<menuitem
<menuitem id="menu_contract_quantity_formula" id="menu_contract_quantity_formula"
action="action_contract_quantity_formula" action="action_contract_quantity_formula"
parent="contract.menu_config_contract" parent="contract.menu_config_contract"
/> />
</odoo> </odoo>

View File

@@ -2,9 +2,10 @@
<!-- Copyright 2019 Tecnativa - Pedro M. Baeza <!-- Copyright 2019 Tecnativa - Pedro M. Baeza
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). --> License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
<odoo> <odoo>
<record id="contract_line_tree_view" model="ir.ui.view"> <record id="contract_line_tree_view" model="ir.ui.view">
<field name="name">contract.line tree view (in contract) - Add variable qty fields</field> <field
name="name"
>contract.line tree view (in contract) - Add variable qty fields</field>
<field name="model">contract.line</field> <field name="model">contract.line</field>
<field name="inherit_id" ref="contract.contract_line_tree_view" /> <field name="inherit_id" ref="contract.contract_line_tree_view" />
<field name="arch" type="xml"> <field name="arch" type="xml">
@@ -16,9 +17,10 @@
/> />
</field> </field>
<field name="quantity" position="attributes"> <field name="quantity" position="attributes">
<attribute name="attrs">{'invisible': [('qty_type', '!=', 'fixed')]}</attribute> <attribute
name="attrs"
>{'invisible': [('qty_type', '!=', 'fixed')]}</attribute>
</field> </field>
</field> </field>
</record> </record>
</odoo> </odoo>

View File

@@ -1,23 +1,33 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<odoo> <odoo>
<record id="contract_template_form_view" model="ir.ui.view"> <record id="contract_template_form_view" model="ir.ui.view">
<field name="name">Contract Template Variable Qty</field> <field name="name">Contract Template Variable Qty</field>
<field name="model">contract.template</field> <field name="model">contract.template</field>
<field name="inherit_id" ref="contract.contract_template_form_view" /> <field name="inherit_id" ref="contract.contract_template_form_view" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//field[@name='contract_line_ids']//field[@name='quantity']" position="before"> <xpath
expr="//field[@name='contract_line_ids']//field[@name='quantity']"
position="before"
>
<field name="qty_type" /> <field name="qty_type" />
</xpath> </xpath>
<xpath expr="//field[@name='contract_line_ids']//field[@name='quantity']" position="after"> <xpath
<field name="qty_formula_id" expr="//field[@name='contract_line_ids']//field[@name='quantity']"
position="after"
>
<field
name="qty_formula_id"
attrs="{'required': [('qty_type', '=', 'variable')], 'invisible': [('qty_type', '!=', 'variable')]}" attrs="{'required': [('qty_type', '=', 'variable')], 'invisible': [('qty_type', '!=', 'variable')]}"
/> />
</xpath> </xpath>
<xpath expr="//field[@name='contract_line_ids']//field[@name='quantity']" position="attributes"> <xpath
<attribute name="attrs">{'required': [('qty_type', '=', 'fixed')], 'invisible': [('qty_type', '!=', 'fixed')]}</attribute> expr="//field[@name='contract_line_ids']//field[@name='quantity']"
position="attributes"
>
<attribute
name="attrs"
>{'required': [('qty_type', '=', 'fixed')], 'invisible': [('qty_type', '!=', 'fixed')]}</attribute>
</xpath> </xpath>
</field> </field>
</record> </record>
</odoo> </odoo>