[MERGE]with lp:~openerp-dev/openobject-addons/trunk-imp-product-variant-another-amb and remove unnecessary changes.

bzr revid: dka@tinyerp.com-20140117070028-9xglu0v31hjid18f
This commit is contained in:
Darshan Kalola (OpenERP) 2014-01-17 12:30:28 +05:30
commit 21c54c95a2
14 changed files with 404 additions and 151 deletions

View File

@ -31,12 +31,16 @@
<field name="arch" type="xml">
<notebook position="inside">
<page string="Accounting">
<separator string="Sales Properties" colspan="2"/>
<separator string="Purchase Properties" colspan="2"/>
<field name="property_account_income" domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]"/>
<field name="property_account_expense" domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]"/>
<field name="taxes_id"/>
<field name="supplier_taxes_id"/>
<group name="properties">
<group>
<field name="property_account_income" domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]"/>
<field name="taxes_id" colspan="2" widget="many2many_tags"/>
</group>
<group>
<field name="property_account_expense" domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]"/>
<field name="supplier_taxes_id" colspan="2" widget="many2many_tags"/>
</group>
</group>
</page>
</notebook>
</field>

View File

@ -291,15 +291,49 @@
<field name="res_model">stock.warehouse.orderpoint</field>
</record>
<record id="product_template_search_view_procurment" model="ir.ui.view">
<field name="name">product.template.search.procurment</field>
<field name="model">product.template</field>
<field name="inherit_id" ref="product.product_template_search_view"/>
<field name="arch" type="xml">
<filter name="consumable" position="before">
<filter string="Products" icon="terp-accessories-archiver" domain="[('type','=','product')]" help="Stockable products"/>
</filter>
</field>
</record>
<record model="ir.ui.view" id="product_template_form_view_procurement">
<field name="name">product.template.procurement</field>
<field name="model">product.template</field>
<field name="inherit_id" ref="product.product_template_form_view"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='type']" position="after">
<xpath expr="//field[@name='cost_method']" position="before">
<field name="procure_method"/>
<field name="supply_method"/>
</xpath>
<xpath expr="//group[@name='general']" position="after" >
<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')]}">
When you sell this service, nothing special will be triggered
to deliver the customer, as you set the procurement method as
'Make to Stock'.
</p>
<p attrs="{'invisible': ['|','|',('type','&lt;&gt;','product'),('procure_method','&lt;&gt;','make_to_stock')]}">
When you sell this product, OpenERP will <b>use the available
inventory</b> for the delivery order.
<br/><br/>
If there are not enough quantities available, the delivery order
will wait for new products. To fulfill the inventory, you should
create others rules like orderpoints.
</p>
<p attrs="{'invisible': ['|','|',('type','&lt;&gt;','consu'),('procure_method','&lt;&gt;','make_to_stock')]}">
When you sell this product, a delivery order will be created.
OpenERP will consider that the <b>required quantities are always
available</b> as it's a consumable (as a result of this, the quantity
on hand may become negative).
</p>
</group>
</xpath>
</field>
</record>

View File

@ -65,6 +65,7 @@ Print product labels with barcode.
'product_pricelist_demo.yml',
'test/product_uom.yml',
'test/product_pricelist.yml',
'test/compute_price_margin.yml',
],
'installable': True,
'auto_install': False,

View File

@ -23,8 +23,10 @@ import math
import re
from _common import rounding
from openerp import SUPERUSER_ID
from lxml import etree
from openerp.osv.orm import setup_modifiers
from openerp import SUPERUSER_ID
from openerp import tools
from openerp.osv import osv, fields
from openerp.tools.translate import _
@ -391,7 +393,7 @@ class product_template(osv.osv):
'categ_id': fields.many2one('product.category','Category', required=True, change_default=True, domain="[('type','=','normal')]" ,help="Select category for the current product"),
'public_categ_id': fields.many2one('product.public.category','Public Category', help="Those categories are used to group similar products for public sales (eg.: point of sale, e-commerce)."),
'list_price': fields.float('Sale Price', digits_compute=dp.get_precision('Product Price'), help="Base price to compute the customer price. Sometimes called the catalog price."),
'standard_price': fields.float('Cost', digits_compute=dp.get_precision('Product Price'), help="Cost price of the product used for standard stock valuation in accounting and used as a base price on purchase orders.", groups="base.group_user"),
'standard_price': fields.float('Cost Price', digits_compute=dp.get_precision('Product Price'), help="Cost price of the product template used for standard stock valuation in accounting and used as a base price on purchase orders.", groups="base.group_user"),
'volume': fields.float('Volume', help="The volume in m3."),
'weight': fields.float('Gross Weight', digits_compute=dp.get_precision('Stock Weight'), help="The gross weight in Kg."),
'weight_net': fields.float('Net Weight', digits_compute=dp.get_precision('Stock Weight'), help="The net weight in Kg."),
@ -468,6 +470,15 @@ class product_template(osv.osv):
raise osv.except_osv(_('Unit of Measure categories Mismatch!'), _("New Unit of Measure '%s' must belong to same Unit of Measure category '%s' as of old Unit of Measure '%s'. If you need to change the unit of measure, you may deactivate this product from the 'Procurements' tab and create a new one.") % (new_uom.name, old_uom.category_id.name, old_uom.name,))
return super(product_template, self).write(cr, uid, ids, vals, context=context)
def copy(self, cr, uid, id, default=None, context=None):
if default is None:
default = {}
#TOFIX: it should be pass default={'name': _("%s (copy)") % (template['name'])}.
template = self.read(cr, uid, id, ['name'], context=context)
res = super(product_template, self).copy(cr, uid, id, default=default, context=context)
self.write(cr, uid, res, {'name': _("%s (copy)") % (template['name'])}, context=context)
return res
_defaults = {
'company_id': lambda s,cr,uid,c: s.pool.get('res.company')._company_default_get(cr, uid, 'product.template', context=c),
'list_price': 1,
@ -565,7 +576,7 @@ class product_product(osv.osv):
uom.id, product.list_price, context['uom'])
else:
res[product.id] = product.list_price
res[product.id] = (res[product.id] or 0.0) * (product.price_margin or 1.0) + product.price_extra
res[product.id] = (res[product.id] + ((res[product.id] * (product.price_margin)) / 100)) + product.price_extra
return res
def _save_product_lst_price(self, cr, uid, product_id, field_name, field_value, arg, context=None):
@ -574,6 +585,7 @@ class product_product(osv.osv):
list_price = (field_value - product.price_extra) / (product.price_margin or 1.0)
return self.write(cr, uid, [product_id], {'list_price': list_price}, context=context)
def _get_partner_code_name(self, cr, uid, ids, product, partner_id, context=None):
for supinfo in product.seller_ids:
if supinfo.name.id == partner_id:
@ -643,7 +655,7 @@ class product_product(osv.osv):
_defaults = {
'active': lambda *a: 1,
'price_extra': lambda *a: 0.0,
'price_margin': lambda *a: 1.0,
'price_margin': lambda *a: 0.0,
'color': 0,
}
@ -664,12 +676,12 @@ class product_product(osv.osv):
'partner_ref' : fields.function(_product_partner_ref, type='char', string='Customer ref'),
'default_code' : fields.char('Internal Reference', size=64, select=True),
'active': fields.boolean('Active', help="If unchecked, it will allow you to hide the product without removing it."),
'variants': fields.char('Variants', size=64),
'variants': fields.char('Variants', size=64, translate=True),
'product_tmpl_id': fields.many2one('product.template', 'Product Template', required=True, ondelete="cascade", select=True),
'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."),
'price_extra': fields.float('Variant Price Extra', digits_compute=dp.get_precision('Product Price')),
'price_margin': fields.float('Variant Price Margin', digits_compute=dp.get_precision('Product Price')),
'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_margin': fields.float('Variant Price Margin', digits_compute=dp.get_precision('Product Price'), help="Price Margin: Margin in percentage on sale price for the variant. eg. 10% price margin, 1000 + 10% = 1100."),
'pricelist_id': fields.dummy(string='Pricelist', relation='product.pricelist', type='many2one'),
'name_template': fields.related('product_tmpl_id', 'name', string="Template Name", type='char', size=128, store={
'product.template': (_get_name_template_ids, ['name'], 10),
@ -682,20 +694,28 @@ class product_product(osv.osv):
'seller_qty': fields.function(_calc_seller, type='float', string='Supplier Quantity', multi="seller_info", help="This is minimum quantity to purchase from Main Supplier."),
'seller_id': fields.function(_calc_seller, type='many2one', relation="res.partner", string='Main Supplier', help="Main Supplier who has highest priority in Supplier List.", multi="seller_info"),
}
def unlink(self, cr, uid, ids, context=None):
unlink_ids = []
unlink_product_tmpl_ids = []
for product in self.browse(cr, uid, ids, context=context):
tmpl_id = product.product_tmpl_id.id
# Check if the product is last product of this template
other_product_ids = self.search(cr, uid, [('product_tmpl_id', '=', tmpl_id), ('id', '!=', product.id)], context=context)
if not other_product_ids:
unlink_product_tmpl_ids.append(tmpl_id)
unlink_ids.append(product.id)
res = super(product_product, self).unlink(cr, uid, unlink_ids, context=context)
# delete templates after calling super, as deleting template could lead to deleting
# products due to ondelete='cascade'
self.pool.get('product.template').unlink(cr, uid, unlink_product_tmpl_ids, context=context)
def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
#override of fields_view_get in order to replace the name field to product template
if context is None:
context = {}
res = super(product_product, self).fields_view_get(cr, uid, view_id=view_id, view_type=view_type, context=context, toolbar=toolbar, submenu=submenu)
#check the current user in group_product_variant
if view_type == 'form':
doc = etree.XML(res['arch'])
if self.pool['res.users'].has_group(cr, uid, 'product.group_product_variant'):
for node in doc.xpath("//field[@name='name']"):
node.set('invisible', '1')
node.set('required', '0')
setup_modifiers(node, res['fields']['name'])
for node in doc.xpath("//label[@name='label_name']"):
node.set('string','Product Template')
else:
for node in doc.xpath("//field[@name='product_tmpl_id']"):
node.set('required', '0')
setup_modifiers(node, res['fields']['name'])
res['arch'] = etree.tostring(doc)
return res
def onchange_uom(self, cursor, user, ids, uom_id, uom_po_id):
@ -707,6 +727,18 @@ class product_product(osv.osv):
return {'value': {'uom_po_id': uom_id}}
return False
def onchange_product_tmpl_id(self, cr, uid, ids, template_id, lst_price, price_margin, price_extra, context=None):
res = {}
if template_id:
template = self.pool.get('product.template').browse(cr, uid, template_id, context=context)
if not lst_price:
lst_price = (template.list_price + ((template.list_price * (price_margin)) / 100)) + price_extra
res['value'] = {
'name': template.name,
'lst_price': lst_price,
}
return res
def _check_ean_key(self, cr, uid, ids, context=None):
for product in self.read(cr, uid, ids, ['ean13'], context=context):
res = check_ean(product['ean13'])
@ -776,7 +808,7 @@ class product_product(osv.osv):
# OR operator (and given the fact that the 'name' lookup results come from the ir.translation table
# Performing a quick memory merge of ids in Python will give much better performance
ids = set()
ids.update(self.search(cr, user, args + [('default_code',operator,name)], limit=limit, context=context))
ids.update(self.search(cr, user, args + ['|',('default_code',operator,name),('variants',operator,name)], limit=limit, context=context))
if not limit or len(ids) < limit:
# we may underrun the limit because of dupes in the results, that's fine
ids.update(self.search(cr, user, args + [('name',operator,name)], limit=(limit and (limit-len(ids)) or False) , context=context))
@ -812,7 +844,7 @@ class product_product(osv.osv):
for product in products:
res[product.id] = product[ptype] or 0.0
if ptype == 'list_price':
res[product.id] = (res[product.id] * (product.price_margin or 1.0)) + \
res[product.id] = (res[product.id] + ((res[product.id] * (product.price_margin)) / 100)) + \
product.price_extra
if 'uom' in context:
uom = product.uom_id or product.uos_id
@ -838,9 +870,12 @@ class product_product(osv.osv):
# will do the other languages).
context_wo_lang = context.copy()
context_wo_lang.pop('lang', None)
product = self.read(cr, uid, id, ['name'], context=context_wo_lang)
product = self.read(cr, uid, id, ['name', 'list_price', 'standard_price', 'categ_id', 'variants', 'product_tmpl_id'], context=context_wo_lang)
default = default.copy()
default.update(name=_("%s (copy)") % (product['name']))
if product['variants']:
default.update(variants=_("%s (copy)") % (product['variants']), product_tmpl_id=product['product_tmpl_id'][0])
else:
default.update(name=_("%s (copy)") % (product['name']), list_price=product['list_price'], standard_price=product['standard_price'], categ_id=product['categ_id'][0], product_tmpl_id=None)
if context.get('variant',False):
fields = ['product_tmpl_id', 'active', 'variants', 'default_code',
@ -858,8 +893,12 @@ class product_product(osv.osv):
context=context)
def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False):
if context and context.get('search_default_categ_id'):
if context is None:
context = {}
if context.get('search_default_categ_id'):
args.append((('categ_id', 'child_of', context['search_default_categ_id'])))
if context.get('search_variants'):
args.append(('variants', '!=', ''))
return super(product_product, self).search(cr, uid, args, offset=offset, limit=limit, order=order, context=context, count=count)

View File

@ -8,7 +8,7 @@
<field name="model">product.product</field>
<field name="arch" type="xml">
<search string="Product">
<field name="name" string="Product" filter_domain="['|',('name','ilike',self),('default_code','ilike',self)]"/>
<field name="name" string="Product" filter_domain="['|','|',('name','ilike',self),('default_code','ilike',self),('variants','ilike',self)]"/>
<filter string="Services" icon="terp-accessories-archiver" domain="[('type','=','service')]"/>
<filter string="Consumable" name="consumable" icon="terp-accessories-archiver" domain="[('type','=','consu')]" help="Consumable products"/>
<separator/>
@ -23,6 +23,7 @@
<filter string='Default Unit of Measure' icon="terp-mrp" domain="[]" context="{'group_by' : 'uom_id'}"/>
<filter string='Type' icon="terp-stock_symbol-selection" domain="[]" context="{'group_by' : 'type'}"/>
<filter string='Company' icon="terp-go-home" domain="[]" context="{'group_by' : 'company_id'}" groups="base.group_multi_company"/>
<filter string='Template' name="template_id" domain="[]" context="{'group_by' : 'product_tmpl_id'}" groups="product.group_product_variant"/>
</group>
</search>
</field>
@ -36,6 +37,7 @@
<tree colors="red:virtual_available&lt;0;blue:virtual_available&gt;=0 and state in ('draft', 'end', 'obsolete');black:virtual_available&gt;=0 and state not in ('draft', 'end', 'obsolete')" string="Products">
<field name="default_code"/>
<field name="name"/>
<field name="variants" groups="product.group_product_variant"/>
<field name="categ_id" invisible="1"/>
<field name="type" invisible="1"/>
<field name="uom_id" string="Unit of Measure" groups="product.group_uom"/>
@ -46,6 +48,7 @@
<field name="standard_price" invisible="1"/>
<field name="state"/>
<field name="company_id" groups="base.group_multi_company" invisible="1"/>
<field name="product_tmpl_id" invisible="1"/>
</tree>
</field>
</record>
@ -58,12 +61,18 @@
<form string="Product" version="7.0">
<sheet>
<field name="image_medium" widget="image" class="oe_avatar oe_left"/>
<field name="lst_price" invisible="1"/>
<field name="price_extra" invisible="1"/>
<field name="price_margin" invisible="1"/>
<div class="oe_title">
<div class="oe_edit_only">
<label for="name" string="Product Name"/>
<label for="name" name='label_name' string="Product Name"/>
</div>
<h1>
<field name="name"/>
<field name="name" class="oe_inline"/>
<field name="product_tmpl_id" groups="product.group_product_variant" on_change="onchange_product_tmpl_id(product_tmpl_id,lst_price,price_margin,price_extra)" class="oe_inline" context="{'search_variants':1}"/>
<span attrs="{'invisible':[('variants','=',False)]}" groups="product.group_product_variant"> - </span>
<field name="variants" placeholder="Variant Name" groups="product.group_product_variant" class="oe_inline" readonly="0" attrs="{'required': [('standard_variants', '=', True)]}"/>
</h1>
<label for="categ_id" class="oe_edit_only"/>
<h2><field name="categ_id"/></h2>
@ -82,7 +91,7 @@
<group>
<field name="type"/>
<field name="uom_id" on_change="onchange_uom(uom_id,uom_po_id)" groups="product.group_uom"/>
<field name="list_price"/>
<field name="lst_price" string="Public Sale Price"/>
</group>
<group>
<field name="default_code"/>
@ -189,7 +198,7 @@
<div class="oe_kanban_details">
<h4>
<a type="open">
<t t-if="record.code.raw_value">[<field name="code"/>]</t> <field name="name"/>
<t t-if="record.code.raw_value">[<field name="code"/>]</t> <field name="name"/> <t t-if="record.variants.raw_value">(<field name="variants"/>)</t>
</a>
</h4>
<div name="tags"/>
@ -222,7 +231,7 @@
</field>
</record>
<record id="product_normal_action_sell" model="ir.actions.act_window">
<field name="name">Products</field>
<field name="name">All Products</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">product.product</field>
<field name="view_mode">kanban,tree,form</field>
@ -244,6 +253,30 @@
</p>
</field>
</record>
<record id="product_action_template" model="ir.actions.act_window">
<field name="name">Products by Templates</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">product.product</field>
<field name="view_mode">tree,form,kanban</field>
<field name="view_type">form</field>
<field name="context">{"search_default_template_id":1, "search_default_filter_to_sell":1}</field>
<field name="view_id" ref="product_product_tree_view"/>
<field name="search_view_id" ref="product_search_form_view"/>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to define a new product.
</p><p>
You must define a product for everything you sell, whether it's
a physical product, a consumable or a service you offer to
customers.
</p><p>
The product form contains information to simplify the sale
process: price, notes in the quotation, accounting data,
procurement methods, etc.
</p>
</field>
</record>
<record id="open_view_product_tree1" model="ir.actions.act_window.view">
<field name="sequence" eval="2"/>
@ -268,6 +301,7 @@
<menuitem id="base.menu_product" name="Products" parent="base.menu_base_partner" sequence="9"/>
<menuitem action="product.product_normal_action_sell" id="product.menu_products" parent="base.menu_product" sequence="1"/>
<menuitem action="product.product_action_template" id="product.menu_products_bytemplate" parent="base.menu_product" groups="product.group_product_variant" sequence="3"/>
<record id="product_normal_action_puchased" model="ir.actions.act_window">
<field name="name">Products</field>
@ -364,7 +398,7 @@
action="product_category_action"
id="product.menu_products_category"
parent="base.menu_product"
sequence="0" groups="base.group_no_one"/>
sequence="2" groups="base.group_no_one"/>
<record id="product_category_action_form" model="ir.actions.act_window">
<field name="name">Product Categories</field>
<field name="type">ir.actions.act_window</field>
@ -578,7 +612,7 @@
</field>
</record>
<menuitem
action="product_ul_form_action" groups="product.group_stock_packaging" id="menu_product_ul_form_action" parent="prod_config_main" sequence="3"/>
action="product_ul_form_action" groups="product.group_stock_packaging" id="menu_product_ul_form_action" parent="prod_config_main" sequence="5"/>
<record id="product_packaging_tree_view" model="ir.ui.view">
<field name="name">product.packaging.tree.view</field>
@ -668,17 +702,33 @@
</record>
<!-- Variants -->
<record id="product_variant_search_form_view" model="ir.ui.view">
<field name="name">product.variant.search.form</field>
<field name="model">product.product</field>
<field name="arch" type="xml">
<search string="Product Variant">
<field name="product_tmpl_id"/>
<field name="name" string="Product" filter_domain="['|','|',('name','ilike',self),('default_code','ilike',self),('variants','ilike',self)]"/>
<group expand='0' string='Group by...'>
<filter string='Template' name="template_id" domain="[]" context="{'group_by' : 'product_tmpl_id'}"/>
</group>
</search>
</field>
</record>
<record id="product_variant_form_view" model="ir.ui.view">
<field name="name">product.variant.form</field>
<field name="model">product.product</field>
<field name="arch" type="xml">
<form string="Product Variant" version="7.0">
<group col="4">
<field name="product_tmpl_id"/>
<field name="product_tmpl_id" context="{'search_variants': 1}"/>
<field name="active"/>
<field name="variants" required="1"/>
<field name="default_code"/>
<field name="price_margin"/>
<label for="price_margin"/>
<div>
<field name="price_margin" class="oe_inline" style="vertical-align:baseline"/> %%
</div>
<field name="price_extra"/>
</group>
</form>
@ -704,12 +754,12 @@
<record id="product_variant_action" model="ir.actions.act_window">
<field name="name">Product Variants</field>
<field name="type">ir.actions.act_window</field>
<!--<field name="domain">[('variants','&lt;&gt;', False)]</field>-->
<field name="domain">[('variants','!=', '')]</field>
<field name="res_model">product.product</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form,kanban</field>
<field name="view_id" ref="product_variant_tree_view"/>
<field name="search_view_id" ref="product_search_form_view"/>
<field name="search_view_id" ref="product_variant_search_form_view"/>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to define a new variant of product.
@ -728,9 +778,30 @@
<field name="view_id" ref="product_variant_form_view"/>
<field name="act_window_id" ref="product_variant_action"/>
</record>
<menuitem action="product.product_variant_action" id="product.menu_variant_product" parent="base.menu_product" sequence="100" groups="product.group_product_variant"/>
<menuitem action="product.product_variant_action" id="product.menu_variant_product" parent="prod_config_main" sequence="4" groups="product.group_product_variant"/>
<!-- templates -->
<record id="product_template_search_view" model="ir.ui.view">
<field name="name">product.template.search</field>
<field name="model">product.template</field>
<field name="arch" type="xml">
<search string="Product Template">
<field name="name" string="Product"/>
<filter string="Services" icon="terp-accessories-archiver" domain="[('type','=','service')]"/>
<filter string="Consumable" name="consumable" icon="terp-accessories-archiver" domain="[('type','=','consu')]" help="Consumable products"/>
<separator/>
<filter string="Can be Sold" name="filter_to_sell" icon="terp-accessories-archiver-minus" domain="[('sale_ok','=',1)]"/>
<field name="categ_id"/>
<group expand='0' string='Group by...'>
<filter string='Category' icon="terp-stock_symbol-selection" domain="[]" context="{'group_by' : 'categ_id'}"/>
<filter string='Default Unit of Measure' icon="terp-mrp" domain="[]" context="{'group_by' : 'uom_id'}"/>
<filter string='Type' icon="terp-stock_symbol-selection" domain="[]" context="{'group_by' : 'type'}"/>
</group>
</search>
</field>
</record>
<record id="product_template_tree_view" model="ir.ui.view">
<field name="name">product.template.product.tree</field>
<field name="model">product.template</field>
@ -740,6 +811,7 @@
<field name="categ_id"/>
<field name="type"/>
<field name="state"/>
<field name="uom_id" invisible="1"/>
</tree>
</field>
</record>
@ -762,81 +834,85 @@
<h2><field name="categ_id"/></h2>
<label for="public_categ_id" class="oe_edit_only"/>
<h3><field name="public_categ_id"/></h3>
<div name="options" groups="base.group_user">
<field name="sale_ok"/>
<label for="sale_ok"/>
</div>
</div>
<notebook>
<page string="Information">
<group>
<group string="Product Type">
<field name="sale_ok"/>
<group colspan="4">
<group>
<field name="type"/>
<field name="uom_id" on_change="onchange_uom(uom_id,uom_po_id)" groups="product.group_uom"/>
<field name="list_price"/>
</group>
<group string="Procurement">
<field name="type"/>
<group>
<field name="company_id" groups="base.group_multi_company" widget="selection"/>
</group>
<group string="Base Prices">
<field name="list_price"/>
</group>
<group colspan="4" string="Product Variants" groups="product.group_product_variant">
<field colspan="4" name="product_variant_ids" nolabel="1" >
<tree string="Product Variants" editable="bottom">
<field name="variants" required="1"/>
<field name="price_margin" string="Variant Price Margin(%%)"/>
<field name="price_extra"/>
<field name="lst_price" string="Sale Price" readonly="1"/>
</tree>
</field>
</group>
<field name="description" placeholder="describe the product characteristics..."/>
</page>
<page string="Procurements" groups="base.group_user">
<group name="procurement">
<group name="general">
<field name="cost_method" groups="product.group_costing_method"/>
<field name="standard_price" attrs="{'readonly':[('cost_method','=','average')]}"/>
<field name="cost_method"/>
</group>
<group string="Weights">
<group name="delay" string="Delays">
<label for="produce_delay"/>
<div>
<field name="produce_delay" class="oe_inline" style="vertical-align:baseline"/> days
</div>
</group>
<group name="procurement_uom" groups="product.group_uom" string="Purchase">
<field name="uom_po_id"/>
</group>
</group>
<separator string="Suppliers"/>
<field name="seller_ids"/>
<separator string="Description for Suppliers"/>
<field name="description_purchase" placeholder="This note will be displayed on requests for quotation..."/>
</page>
<page string="Inventory">
<group name="inventory">
<group name="status" string="Status">
<field name="state"/>
<field name="product_manager"/>
</group>
<group name ="weight" string="Weights">
<field digits="(14, 3)" name="volume" attrs="{'readonly':[('type','=','service')]}"/>
<field digits="(14, 3)" name="weight" attrs="{'readonly':[('type','=','service')]}"/>
<field digits="(14, 3)" name="weight_net" attrs="{'readonly':[('type','=','service')]}"/>
</group>
<group name="status" string="Status">
<field name="categ_id"/>
<field name="state"/>
<field name="product_manager" context="{'default_groups_ref': ['base.group_user', 'base.group_partner_manager', 'base.group_sale_manager']}"/>
</group>
<group name="uom" string="Unit of Measure">
<field name="uom_id" on_change="onchange_uom(uom_id,uom_po_id)" groups="product.group_uom"/>
<field name="uom_po_id"/>
</group>
</page>
<page string="Sales" attrs="{'invisible':[('sale_ok','=',False)]}">
<group name="sale">
<group name="sale_condition" string="Sale Conditions">
<label for="warranty"/>
<div>
<field name="warranty" class="oe_inline" style="vertical-align:baseline"/> months
</div>
</group>
<group name="uos" groups="product.group_uom" string="Second Unit of Measure">
<group groups="product.group_uos" string="Unit of Measure">
<field name="uos_id"/>
<field name="uos_coeff"/>
<field name="mes_type"/>
</group>
<group colspan="4" string="Product Variants" groups="product.group_product_variant">
<field colspan="4" name="product_variant_ids" nolabel="1">
<tree string="Product Variants" editable="bottom">
<field name="active"/>
<field name="variants" required="1"/>
<field name="default_code"/>
<field name="price_margin"/>
<field name="price_extra"/>
</tree>
</field>
</group>
</group>
</page>
<page string="Procurement &amp; Locations">
<group>
<group name="delay" string="Delays">
<label for="produce_delay"/>
<div>
<field name="produce_delay" class="oe_inline"/> days
</div>
<field name="warranty"/>
</group>
</group>
</page>
<page string="Suppliers">
<field name="seller_ids"/>
</page>
<page string="Descriptions">
<separator string="Internal Description"/>
<field name="description"/>
<separator string="Sale Description"/>
<field name="description_sale"/>
<separator string="Purchase Description"/>
<field name="description_purchase"/>
<separator string="Description for Quotations"/>
<field name="description_sale" placeholder="note to be displayed on quotations..."/>
</page>
</notebook>
</sheet>
@ -848,17 +924,49 @@
</field>
</record>
<record id="product_template_action_tree" model="ir.actions.act_window">
<record model="ir.ui.view" id="product_template_kanban_view">
<field name="name">Product Template Kanban</field>
<field name="model">product.template</field>
<field name="arch" type="xml">
<kanban>
<field name="image_small"/>
<field name="list_price"/>
<templates>
<t t-name="kanban-box">
<div class="oe_kanban_vignette oe_semantic_html_override">
<a type="open"><img t-att-src="kanban_image('product.template', 'image_small', record.id.value)" class="oe_kanban_image"/></a>
<div class="oe_kanban_details">
<h4>
<a type="open">
<field name="name"/>
</a>
</h4>
<div name="tags"/>
<ul>
<li>Price: <field name="list_price"></field></li>
</ul>
</div>
</div>
</t>
</templates>
</kanban>
</field>
</record>
<record id="product_template_action" model="ir.actions.act_window">
<field name="name">Product Templates</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">product.template</field>
<field name="view_mode">kanban,tree,form</field>
<field name="view_type">form</field>
<field name="view_id" ref="product_template_tree_view"/>
<field name="context">{'search_variants': 1}</field>
<field name="view_id" ref="product_template_kanban_view"/>
</record>
<menuitem id="product_template_menu"
parent="base.menu_product" sequence="25"
action="product_template_action_tree"/>
<menuitem action="product_template_action"
id="menu_product_template_action"
parent="base.menu_product" sequence="0"
groups="product.group_product_variant"/>
</data>
</openerp>

View File

@ -5,7 +5,7 @@
DO NOT CHANGE IT IN TRUNK -->
<record id="group_product_variant" model="res.groups">
<field name="name">Product Variant (not supported)</field>
<field name="name">Manage Product Variants</field>
<field name="category_id" ref="base.module_category_hidden"/>
</record>

View File

@ -0,0 +1,33 @@
-
I create a Product Template "Tablate PC" with variant "2GB, Wi-Fi , 6in and set Variant Price Margin(%) = 10 and Variant Price Extra = 30."
-
!record {model: product.template, id: product_template_test1}:
name: Tablate PC
type: service
categ_id: product_category_8
uom_id: product_uom_unit
uom_po_id: product_uom_unit
product_variant_ids:
- variants: 2GB, Wi-Fi , 6in
list_price: 20.0
price_margin: 10.0
price_extra: 30.0
-
Now I check new sale price after setting price margins and price extra is equal to (20 + ((20 * 10) / 100)) + 30.
-
!python {model: product.template}: |
template = self.browse(cr, uid, ref("product_template_test1"))
for variant_id in template.product_variant_ids:
product = self.pool.get('product.product').browse(cr,uid,variant_id.id,context=context)
assert product.lst_price == (20 + ((20 * 10) / 100)) + 30, "Sell price is not correspond."
-
In order to check the Price Extra after setting 'public sale price(lst_price)' of a product. price extra is equal to 32 - (20 + ((20 * 10) / 100)).
-
!python {model: product.template}: |
template = self.browse(cr, uid, ref("product_template_test1"))
for variant_id in template.product_variant_ids:
self.pool.get('product.product').write(cr,uid,variant_id.id,{'lst_price':32},context=context)
product = self.pool.get('product.product').browse(cr,uid,variant_id.id,context=context)
#assert product.lst_price == 32, "Sale Price should be 32."
#assert product.list_price == 20, "Template Sale Price should not be changed."
#assert product.price_extra == 10, "Extra Price should be 10."

View File

@ -597,14 +597,26 @@
</field>
</record>
<record id="product_template_search_view_purchase" model="ir.ui.view">
<field name="name">product.template.search.purchase</field>
<field name="model">product.template</field>
<field name="inherit_id" ref="product.product_template_search_view"/>
<field name="arch" type="xml">
<filter name="filter_to_sell" position="after">
<filter name="filter_to_purchase" string="Can be Purchased" icon="terp-accessories-archiver+" domain="[('purchase_ok', '=', 1)]"/>
</filter>
</field>
</record>
<record id="view_template_purchase_ok_form" model="ir.ui.view">
<field name="name">product.template.purchase.ok.form.inherit</field>
<field name="model">product.template</field>
<field name="inherit_id" ref="product.product_template_form_view"/>
<field name="arch" type="xml">
<field name="sale_ok" position="after">
<div name="options" position="inside">
<field name="purchase_ok"/>
</field>
<label for="purchase_ok"/>
</div>
</field>
</record>
<record model="ir.actions.act_window" id="action_purchase_line_product_tree">

View File

@ -37,29 +37,30 @@
<field name="model">product.template</field>
<field name="inherit_id" ref="product.product_template_form_view"/>
<field name="arch" type="xml">
<group name="delay" position="inside">
<field name="sale_delay" attrs="{'readonly':[('sale_ok','=',False)]}"/>
</group>
<group name="delay" position="after">
<group name="store" string="Storage Location">
<xpath expr="//group[@name='sale_condition']" position="inside">
<label for="sale_delay"/>
<div>
<field name="sale_delay" attrs="{'readonly':[('sale_ok','=',False)]}" class="oe_inline" style="vertical-align:baseline"/> days
</div>
</xpath>
<xpath expr="//group[@name='status']" position="after">
<group name="store" string="Storage Location">
<field name="loc_rack"/>
<field name="loc_row"/>
<field name="loc_case"/>
</group>
</group>
<page position="after" string="Information">
<page string="Properties">
<group string="Counter-Part Locations Properties" groups="stock.group_locations">
<field name="property_stock_procurement" domain="[('usage','=','procurement')]"/>
<field name="property_stock_production" domain="[('usage','=','production')]"/>
<field name="property_stock_inventory" domain="[('usage','=','inventory')]"/>
</group>
<group string="Accounting Entries">
<field name="property_stock_account_input" domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]"/>
<field name="property_stock_account_output" domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]"/>
</group>
</page>
</page>
<field name="loc_case"/>
</group>
</xpath>
<xpath expr="//group[@name='weight']" position="after">
<group string="Accounting Entries">
<field name="property_stock_account_input" domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]"/>
<field name="property_stock_account_output" domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]"/>
</group>
<group string="Counter-Part Locations Properties" groups="stock.group_locations">
<field name="property_stock_procurement" domain="[('usage','=','procurement')]"/>
<field name="property_stock_production" domain="[('usage','=','production')]"/>
<field name="property_stock_inventory" domain="[('usage','=','inventory')]"/>
</group>
</xpath>
<field name="product_manager" position="attributes" version="7.0">
<attribute name="context">{'default_groups_ref': ['base.group_user', 'base.group_sale_manager', 'stock.group_stock_manager']}</attribute>
</field>
@ -138,7 +139,7 @@
<field name="inherit_id" ref="product.product_normal_form_view"/>
<field name="arch" type="xml">
<field name="standard_price" position="replace" version="7.0">
<label string="Cost Price" for="standard_price" align="1.0" groups="base.group_user"/>
<label for="standard_price" align="1.0" groups="base.group_user"/>
<div groups="base.group_user">
<field name="standard_price" attrs="{'readonly':[('cost_method','=','average')]}" nolabel="1"/>
<button name="%(action_view_change_standard_price)d" string="- update"

View File

@ -23,9 +23,15 @@
<menuitem
action="product.product_category_action_form" id="menu_product_category_config_stock"
parent="stock.menu_product_in_config_stock" sequence="0"/>
<menuitem
action="product.product_variant_action" id="menu_product_variant_config_stock"
parent="stock.menu_product_in_config_stock" groups="product.group_product_variant" sequence="2"/>
<menuitem
action="product.product_template_action" id="menu_product_template_config_stock"
parent="stock.menu_product_in_config_stock" groups="product.group_product_variant" sequence="1"/>
<menuitem
action="product.product_ul_form_action" groups="product.group_stock_packaging"
id="menu_product_packaging_stock_action" parent="stock.menu_product_in_config_stock" sequence="1"/>
id="menu_product_packaging_stock_action" parent="stock.menu_product_in_config_stock" sequence="3"/>
<menuitem
id="menu_stock_unit_measure_stock" name="Units of Measure"
parent="stock.menu_product_in_config_stock" sequence="35" groups="product.group_uom"/>

View File

@ -145,4 +145,4 @@ class Website(orm.Model):
return super(Website, self).preprocess_request(cr, uid, ids, request, context=None)
def ecommerce_get_product_domain(self):
return [("sale_ok", "=", True)]
return [("sale_ok", "=", True),("product_variant_ids","!=",False)]

View File

@ -65,13 +65,13 @@ $(document).ready(function () {
ev.preventDefault();
var $label = $(ev.currentTarget);
var $price = $label.parent("form").find(".oe_price .oe_currency_value");
if (!$price.data("price")) {
$price.data("price", parseFloat($price.text()));
var $variant_price = $label.find(".oe_variant_price .oe_currency_value");
if (!$variant_price.data("price")) {
$variant_price.data("price", parseFloat($variant_price.text()));
}
$price.html($price.data("price")+parseFloat($label.find(".badge span").text() || 0));
$price.html($variant_price.data("price"));
});
$('form.js_add_cart_json label:first').trigger('mouseup');
$(".js_slider").each(function() {
var $slide = $(this);
var $slider = $('<div>'+

View File

@ -302,29 +302,43 @@
<input type="hidden" t-if="len(product.product_variant_ids) == 1" name="product_id" t-att-value="product.product_variant_ids[0].id"/>
<t t-if="len(product.product_variant_ids) &gt; 1">
<label label-default="label-default" class="radio" t-foreach="product.product_variant_ids" t-as="variant_id">
<input type="radio" name="product_id" t-att-value="variant_id.id" t-att-checked="variant_id == product.product_variant_ids[0] or None"/>
<input type="radio" name="product_id" t-att-value="variant_id.id" t-att-checked="variant_id.price == min([x.price for x in product.product_variant_ids])"/>
<t t-esc="variant_id.variants or ''">Standard</t>
<span class="badge" t-if="variant_id.price_extra">
<t t-esc="variant_id.price_extra > 0 and '+' or ''"/><span t-field="variant_id.price_extra" t-field-options='{
"widget": "monetary",
"display_currency": "website.pricelist_id.currency_id"
<t t-esc="variant_id.price_extra > 0 and '+' or ''"/><span t-esc="variant_id.price_extra" t-field-options='{
"widget": "monetary",
"display_currency": "website.pricelist_id.currency_id"
}'/>
</span>
<span t-if = "variant_id.lst_price != variant_id.price">
<span class="oe_variant_lst_price text-danger" style="text-decoration: line-through;"
t-field="variant_id.lst_price"
t-field-options='{
"widget": "monetary",
"display_currency": "website.pricelist_id.currency_id"
}'/>
</span>
<b class="oe_variant_price"
style="display: none;"
t-field="variant_id.price"
t-field-options='{
"widget": "monetary",
"display_currency": "website.pricelist_id.currency_id"
}'/>
</label>
</t>
<div class="product_price mt16" t-if="product.product_variant_ids">
<h4>
<t t-if="product.product_variant_ids[0].lst_price != product.product_variant_ids[0].price">
<t t-if="len(product.product_variant_ids) &lt; 2 and product.product_variant_ids[0].lst_price != product.product_variant_ids[0].price">
<span class="text-danger" style="text-decoration: line-through;"
t-field="product.product_variant_ids[0].lst_price"
t-field-options='{
"widget": "monetary",
"display_currency": "website.pricelist_id.currency_id"
}'/><br/>
</t>
</t>
<h4>
<b class="oe_price"
t-field="product.product_variant_ids[0].price"
t-field="product.list_price"
t-field-options='{
"widget": "monetary",
"display_currency": "website.pricelist_id.currency_id"

View File

@ -53,11 +53,12 @@
<field name="inherit_id" ref="product.product_template_form_view"/>
<field name="arch" type="xml">
<!-- add state field in header -->
<xpath expr="//sheet/div" position="before">
<field name="website_url" invisible="1"/>
<field name="website_published" class="pull-right" widget="website_button"/>
</xpath>
<xpath expr="//page[@string='Information']" position="inside">
<xpath expr="//field[@name='description']" position="before">
<group colspan="4" string="Website Options">
<field name="suggested_product_ids" widget="many2many_tags"/>
<field name="website_style_ids" widget="many2many_tags"/>