[IMP] product: only template child / multiple template childs form view improvements

- added a is_only_child field on product.product, telling whether the
product is the only child of the product.template
- improved the product form view, to set readonly all fields coming fgrom
the template when the product is not the only child. This way, the user
is more aware that changing a value in the template changes the value
for all child products. He will have to do those changes on the template
form. A link to the template has been added in the product form view.

bzr revid: tde@openerp.com-20140122095826-8k0wl7af57iiyify
This commit is contained in:
Thibault Delavallée 2014-01-22 10:58:26 +01:00
parent 14bdf21b17
commit 38d64147d5
8 changed files with 92 additions and 46 deletions

View File

@ -11,12 +11,16 @@
<page string="Accounting" groups="account.group_account_invoice"> <page string="Accounting" groups="account.group_account_invoice">
<group name="properties"> <group name="properties">
<group> <group>
<field name="property_account_income" domain="[('type','=','other')]" groups="account.group_account_user"/> <field name="property_account_income" domain="[('type','=','other')]" groups="account.group_account_user"
<field name="taxes_id" colspan="2" attrs="{'readonly':[('sale_ok','=',0)]}" widget="many2many_tags"/> attrs="{'readonly': [('is_only_child', '=', False)]}"/>
<field name="taxes_id" colspan="2" widget="many2many_tags"
attrs="{'readonly':[ '|', ('sale_ok','=',0), ('is_only_child', '=', False)]}"/>
</group> </group>
<group> <group>
<field name="property_account_expense" domain="[('type','=','other')]" groups="account.group_account_user"/> <field name="property_account_expense" domain="[('type','=','other')]" groups="account.group_account_user"
<field name="supplier_taxes_id" colspan="2" widget="many2many_tags"/> attrs="{'readonly': [('is_only_child', '=', False)]}"/>
<field name="supplier_taxes_id" colspan="2" widget="many2many_tags"
attrs="{'readonly': [('is_only_child', '=', False)]}"/>
</group> </group>
</group> </group>
</page> </page>

View File

@ -8,10 +8,11 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<div name="options" position="inside"> <div name="options" position="inside">
<field name="event_ok" on_change="onchange_event_ok(type, event_ok, context)"/> <field name="event_ok" on_change="onchange_event_ok(type, event_ok, context)"/>
<label for="event_ok"/> <label for="event_ok"
attrs="{'readonly': [('is_only_child', '=', False)]}"/>
</div> </div>
<div name='ean' position="after"> <div name='ean' position="after">
<field name="event_type_id" attrs="{'readonly': [('event_ok', '=', False)]}"/> <field name="event_type_id" attrs="{'readonly': ['|', ('event_ok', '=', False), ('is_only_child', '=', False)]}"/>
</div> </div>
</field> </field>
</record> </record>

View File

@ -292,7 +292,7 @@
</record> </record>
<record id="product_template_search_view_procurment" model="ir.ui.view"> <record id="product_template_search_view_procurment" model="ir.ui.view">
<field name="name">product.template.search.procurment</field> <field name="name">product.template.search.procurement</field>
<field name="model">product.template</field> <field name="model">product.template</field>
<field name="inherit_id" ref="product.product_template_search_view"/> <field name="inherit_id" ref="product.product_template_search_view"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
@ -313,12 +313,12 @@
</xpath> </xpath>
<xpath expr="//group[@name='general']" position="after" > <xpath expr="//group[@name='general']" position="after" >
<group name="procurement_help" class="oe_grey" col="1" groups="base.group_user"> <group name="procurement_help" class="oe_grey" col="1" groups="base.group_user">
<p attrs="{'invisible': ['|','|',('type','&lt;&gt;','service'),('procure_method','&lt;&gt;','make_to_stock')]}"> <p attrs="{'invisible': ['|', '|', ('type', '!=', 'service'), ('procure_method', '!=', 'make_to_stock')]}">
When you sell this service, nothing special will be triggered When you sell this service, nothing special will be triggered
to deliver the customer, as you set the procurement method as to deliver the customer, as you set the procurement method as
'Make to Stock'. 'Make to Stock'.
</p> </p>
<p attrs="{'invisible': ['|','|',('type','&lt;&gt;','product'),('procure_method','&lt;&gt;','make_to_stock')]}"> <p attrs="{'invisible': ['|', '|', ('type', '!=', 'product'), ('procure_method', '!=', 'make_to_stock')]}">
When you sell this product, OpenERP will <b>use the available When you sell this product, OpenERP will <b>use the available
inventory</b> for the delivery order. inventory</b> for the delivery order.
<br/><br/> <br/><br/>
@ -326,7 +326,7 @@
will wait for new products. To fulfill the inventory, you should will wait for new products. To fulfill the inventory, you should
create others rules like orderpoints. create others rules like orderpoints.
</p> </p>
<p attrs="{'invisible': ['|','|',('type','&lt;&gt;','consu'),('procure_method','&lt;&gt;','make_to_stock')]}"> <p attrs="{'invisible': ['|', '|', ('type', '!=', 'consu'), ('procure_method', '!=', 'make_to_stock')]}">
When you sell this product, a delivery order will be created. When you sell this product, a delivery order will be created.
OpenERP will consider that the <b>required quantities are always OpenERP will consider that the <b>required quantities are always
available</b> as it's a consumable (as a result of this, the quantity available</b> as it's a consumable (as a result of this, the quantity
@ -360,8 +360,10 @@
<button string="Orderpoints" name="%(product_open_orderpoint)d" type="action" attrs="{'invisible':[('type', '=', 'service')]}"/> <button string="Orderpoints" name="%(product_open_orderpoint)d" type="action" attrs="{'invisible':[('type', '=', 'service')]}"/>
</xpath> </xpath>
<xpath expr="//field[@name='cost_method']" position="before"> <xpath expr="//field[@name='cost_method']" position="before">
<field name="procure_method" groups="base.group_user"/> <field name="procure_method" groups="base.group_user"
<field name="supply_method" groups="base.group_user"/> attrs="{'readonly': [('is_only_child', '=', False)]}"/>
<field name="supply_method" groups="base.group_user"
attrs="{'readonly': [('is_only_child', '=', False)]}"/>
</xpath> </xpath>
<xpath expr="//group[@name='general']" position="after" > <xpath expr="//group[@name='general']" position="after" >
<group name="procurement_help" class="oe_grey" col="1" groups="base.group_user"> <group name="procurement_help" class="oe_grey" col="1" groups="base.group_user">

View File

@ -615,6 +615,12 @@ class product_product(osv.osv):
(data['name'] or '') + (data['variants'] and (' - '+data['variants']) or '') (data['name'] or '') + (data['variants'] and (' - '+data['variants']) or '')
return res return res
def _is_only_child(self, cr, uid, ids, name, arg, context=None):
res = dict.fromkeys(ids, True)
for product in self.browse(cr, uid, ids, context=context):
if product.product_tmpl_id and len(product.product_tmpl_id.product_variant_ids) > 1:
res[product.id] = False
return res
def _get_main_product_supplier(self, cr, uid, product, context=None): def _get_main_product_supplier(self, cr, uid, product, context=None):
"""Determines the main (best) product supplier for ``product``, """Determines the main (best) product supplier for ``product``,
@ -676,6 +682,8 @@ class product_product(osv.osv):
'active': fields.boolean('Active', help="If unchecked, it will allow you to hide the product without removing it."), 'active': fields.boolean('Active', help="If unchecked, it will allow you to hide the product without removing it."),
'variants': fields.char('Variants', size=64, translate=True), 'variants': fields.char('Variants', size=64, translate=True),
'product_tmpl_id': fields.many2one('product.template', 'Product Template', required=True, ondelete="cascade", select=True), 'product_tmpl_id': fields.many2one('product.template', 'Product Template', required=True, ondelete="cascade", select=True),
'is_only_child': fields.function(
_is_only_child, type='boolean', string='Sole child of the parent template'),
'ean13': fields.char('EAN13 Barcode', size=13, help="International Article Number used for product identification."), 'ean13': fields.char('EAN13 Barcode', size=13, help="International Article Number used for product identification."),
'packaging' : fields.one2many('product.packaging', 'product_id', 'Logistical Units', help="Gives the different ways to package the same product. This has no impact on the picking order and is mainly used if you use the EDI module."), 'packaging' : fields.one2many('product.packaging', 'product_id', 'Logistical Units', help="Gives the different ways to package the same product. This has no impact on the picking order and is mainly used if you use the EDI module."),
'price_extra': fields.float('Variant Price Extra', digits_compute=dp.get_precision('Product Price'), help="Price Extra: Extra price for the variant on sale price. eg. 200 price extra, 1000 + 200 = 1200."), 'price_extra': fields.float('Variant Price Extra', digits_compute=dp.get_precision('Product Price'), help="Price Extra: Extra price for the variant on sale price. eg. 200 price extra, 1000 + 200 = 1200."),

View File

@ -60,30 +60,35 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Product" version="7.0"> <form string="Product" version="7.0">
<sheet> <sheet>
<field name="is_only_child" invisible="0"/>
<field name="image_medium" widget="image" class="oe_avatar oe_left"/> <field name="image_medium" widget="image" class="oe_avatar oe_left"/>
<div class="oe_title"> <div class="oe_title">
<div class="oe_edit_only"> <div class="oe_edit_only">
<label for="name" name='label_name' string="Product Name" <label for="name" name='label_name' string="Product Name"
groups="product.group_product_mono"/> attrs="{'invisible': [('is_only_child', '=', False)]}"/>
<label for="name" name='label_name' string="Product Template" <label for="name" name='label_name' string="Product Template"
groups="product.gorup_product_variant"/> attrs="{'invisible': [('is_only_child', '=', True)]}"/>
</div> </div>
<h1> <h1>
<field name="name" class="oe_inline" <field name="name" class="oe_inline"
required="0" attrs="{'required': [('is_only_child', '=', True)],
groups="product.group_product_mono"/> 'invisible': [('is_only_child', '=', False)]}"/>
<field name="product_tmpl_id" class="oe_inline" <field name="product_tmpl_id" class="oe_inline"
groups="product.group_product_variant" attrs="{'required': [('is_only_child', '=', False)],
'invisible': [('is_only_child', '=', True)]}"
on_change="onchange_product_tmpl_id(product_tmpl_id)"/> on_change="onchange_product_tmpl_id(product_tmpl_id)"/>
<span attrs="{'invisible':[('variants','=',False)]}" groups="product.group_product_variant"> - </span> <span attrs="{'invisible':[('variants','=',False)]}" groups="product.group_product_variant"> - </span>
<field name="variants" placeholder="Variant Name" <field name="variants" placeholder="Variant Name"
readonly="0"
groups="product.group_product_variant" class="oe_inline"/> groups="product.group_product_variant" class="oe_inline"/>
</h1> </h1>
<span attrs="{'invisible': [('is_only_child', '=', True)]}">
Manage some of the product attributes on the
<a>template form</a>
</span>
<label for="categ_id" class="oe_edit_only"/> <label for="categ_id" class="oe_edit_only"/>
<h2><field name="categ_id"/></h2> <h2><field name="categ_id" attrs="{'readonly': [('is_only_child', '=', False)]}"/></h2>
<label for="public_categ_id" class="oe_edit_only"/> <label for="public_categ_id" class="oe_edit_only"/>
<h3><field name="public_categ_id"/></h3> <h3><field name="public_categ_id" attrs="{'readonly': [('is_only_child', '=', False)]}"/></h3>
<div name="options" groups="base.group_user"> <div name="options" groups="base.group_user">
<field name="sale_ok"/> <field name="sale_ok"/>
<label for="sale_ok"/> <label for="sale_ok"/>
@ -95,9 +100,14 @@
<page string="Information"> <page string="Information">
<group> <group>
<group> <group>
<field name="type"/> <field name="type"
<field name="uom_id" on_change="onchange_uom(uom_id,uom_po_id)" groups="product.group_uom"/> attrs="{'invisible': [('is_only_child', '=', False)]}"/>
<field name="lst_price" string="Public Sale Price"/> <field name="uom_id" on_change="onchange_uom(uom_id,uom_po_id)" groups="product.group_uom"
attrs="{'invisible': [('is_only_child', '=', False)]}"/>
<field name="lst_price" string="Public Sale Price"
attrs="{'readonly': [('is_only_child', '=', False)]}"/>
<field name="price_extra"
attrs="{'invisible': [('is_only_child', '=', True)]}"/>
</group> </group>
<group> <group>
<field name="default_code"/> <field name="default_code"/>
@ -105,19 +115,24 @@
<div name="ean"> <div name="ean">
<field name="ean13" placeholder="e.g. 5901234123457"/> <field name="ean13" placeholder="e.g. 5901234123457"/>
</div> </div>
<field name="company_id" groups="base.group_multi_company" widget="selection"/> <field name="company_id" groups="base.group_multi_company" widget="selection"
attrs="{'invisible': [('is_only_child', '=', False)]}"/>
</group> </group>
</group> </group>
<field name="description" placeholder="describe the product characteristics..."/> <field name="description" placeholder="describe the product characteristics..."
attrs="{'readonly': [('is_only_child', '=', False)]}"/>
</page> </page>
<page string="Procurements" groups="base.group_user"> <page string="Procurements" groups="base.group_user">
<group name="procurement"> <group name="procurement">
<group name="general"> <group name="general">
<field name="cost_method" groups="product.group_costing_method"/> <field name="cost_method" groups="product.group_costing_method"
<field name="standard_price" attrs="{'readonly':[('cost_method','=','average')]}"/> attrs="{'readonly': [('is_only_child', '=', False)]}"/>
<field name="standard_price"
attrs="{'readonly': ['|', ('cost_method','=','average'), ('is_only_child', '=', False)]}"/>
</group> </group>
<group name="procurement_uom" groups="product.group_uom" string="Purchase"> <group name="procurement_uom" groups="product.group_uom" string="Purchase">
<field name="uom_po_id"/> <field name="uom_po_id"
attrs="{'readonly': [('is_only_child', '=', False)]}"/>
</group> </group>
</group> </group>
<separator string="Description for Suppliers"/> <separator string="Description for Suppliers"/>
@ -126,14 +141,19 @@
<page string="Inventory" groups="base.group_user"> <page string="Inventory" groups="base.group_user">
<group name="inventory"> <group name="inventory">
<group name="status" string="Status"> <group name="status" string="Status">
<field name="state"/> <field name="state"
attrs="{'readonly': [('is_only_child', '=', False)]}"/>
<field name="product_manager" <field name="product_manager"
context="{'default_groups_ref': ['base.group_user', 'base.group_partner_manager', 'base.group_sale_manager']}"/> attrs="{'readonly': [('is_only_child', '=', False)]}"
context="{'default_groups_ref': ['base.group_user', 'base.group_partner_manager', 'base.group_sale_manager']}"/>
</group> </group>
<group name="Weights" groups="product.group_stock_packaging" string="Weights"> <group name="Weights" groups="product.group_stock_packaging" string="Weights">
<field digits="(14, 3)" name="volume" attrs="{'readonly':[('type','=','service')]}"/> <field digits="(14, 3)" name="volume"
<field name="weight" attrs="{'readonly':[('type','=','service')]}"/> attrs="{'readonly': ['|', ('type','=','service'), ('is_only_child', '=', False)]}"/>
<field name="weight_net" attrs="{'readonly':[('type','=','service')]}"/> <field name="weight"
attrs="{'readonly': ['|', ('type','=','service'), ('is_only_child', '=', False)]}"/>
<field name="weight_net"
attrs="{'readonly': ['|', ('type','=','service'), ('is_only_child', '=', False)]}"/>
</group> </group>
</group> </group>
</page> </page>
@ -141,17 +161,21 @@
<group name="sale"> <group name="sale">
<group string="Sale Conditions"> <group string="Sale Conditions">
<label for="warranty"/> <label for="warranty"/>
<div> <div attrs="{'readonly': [('is_only_child', '=', False)]}">
<field name="warranty" class="oe_inline"/> months <field name="warranty" class="oe_inline"/> months
</div> </div>
</group> </group>
<group groups="product.group_uos" string="Unit of Measure"> <group groups="product.group_uos" string="Unit of Measure">
<field name="uos_id"/> <field name="uos_id"
<field name="uos_coeff"/> attrs="{'readonly': [('is_only_child', '=', False)]}"/>
<field name="mes_type"/> <field name="uos_coeff"
attrs="{'readonly': [('is_only_child', '=', False)]}"/>
<field name="mes_type"
attrs="{'readonly': [('is_only_child', '=', False)]}"/>
</group> </group>
</group> </group>
<field name="packaging" groups="product.group_stock_packaging"> <field name="packaging" groups="product.group_stock_packaging"
attrs="{'readonly': [('is_only_child', '=', False)]}">
<form string="Packaging" version="7.0"> <form string="Packaging" version="7.0">
<group col="4"> <group col="4">
<field name="ean"/> <field name="ean"/>
@ -174,7 +198,8 @@
</form> </form>
</field> </field>
<separator string="Description for Quotations"/> <separator string="Description for Quotations"/>
<field name="description_sale" placeholder="note to be displayed on quotations..."/> <field name="description_sale" placeholder="note to be displayed on quotations..."
attrs="{'readonly': [('is_only_child', '=', False)]}"/>
</page> </page>
</notebook> </notebook>
</sheet> </sheet>

View File

@ -552,7 +552,8 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<div name="options" position="inside"> <div name="options" position="inside">
<field name="purchase_ok"/> <field name="purchase_ok"/>
<label for="purchase_ok"/> <label for="purchase_ok"
attrs="{'readonly': [('is_only_child', '=', False)]}"/>
</div> </div>
<group name="procurement" position="after"> <group name="procurement" position="after">
<separator string="Suppliers"/> <separator string="Suppliers"/>

View File

@ -31,7 +31,8 @@
<field name="inherit_id" ref="product.product_normal_form_view"/> <field name="inherit_id" ref="product.product_normal_form_view"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="product_manager" position="after"> <field name="product_manager" position="after">
<field name="intrastat_id"/> <field name="intrastat_id"
attrs="{'readonly': [('is_only_child', '=', False)]}"/>
</field> </field>
</field> </field>
</record> </record>

View File

@ -122,9 +122,9 @@
</group> </group>
<group name="Weights" position="after"> <group name="Weights" position="after">
<group name="store" groups="stock.group_locations" string="Counter-Part Locations Properties"> <group name="store" groups="stock.group_locations" string="Counter-Part Locations Properties">
<field name="property_stock_procurement" attrs="{'readonly':[('type','=','service')]}" domain="[('usage','=','procurement')]"/> <field name="property_stock_procurement" attrs="{'readonly':['|', '|', ('type','=','service'), ('is_only_child', '=', False), ('is_only_child', '=', False)]}" domain="[('usage','=','procurement')]"/>
<field name="property_stock_production" attrs="{'readonly':[('type','=','service')]}" domain="[('usage','=','production')]"/> <field name="property_stock_production" attrs="{'readonly':['|', '|', ('type','=','service'), ('is_only_child', '=', False), ('is_only_child', '=', False)]}" domain="[('usage','=','production')]"/>
<field name="property_stock_inventory" attrs="{'readonly':[('type','=','service')]}" domain="[('usage','=','inventory')]"/> <field name="property_stock_inventory" attrs="{'readonly':['|', '|', ('type','=','service'), ('is_only_child', '=', False), ('is_only_child', '=', False)]}" domain="[('usage','=','inventory')]"/>
</group> </group>
</group> </group>
<field name="product_manager" position="attributes" version="7.0"> <field name="product_manager" position="attributes" version="7.0">
@ -163,9 +163,13 @@
<field name="valuation" attrs="{'readonly':[('type', '=', 'service')]}"/> <field name="valuation" attrs="{'readonly':[('type', '=', 'service')]}"/>
</group> </group>
<group colspan="2" col="2"> <group colspan="2" col="2">
<field name="property_stock_account_input" attrs="{'invisible':[('valuation', '!=', 'real_time')]}" <field name="property_stock_account_input"
attrs="{'invisible':[('valuation', '!=', 'real_time')],
'readonly': [('is_only_child', '=', False)]}"
domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]"/> domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]"/>
<field name="property_stock_account_output" attrs="{'invisible':[('valuation', '!=', 'real_time')]}" <field name="property_stock_account_output"
attrs="{'invisible':[('valuation', '!=', 'real_time')],
'readonly': [('is_only_child', '=', False)]}"
domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]"/> domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]"/>
</group> </group>
</group> </group>