[MERGE] Merged DKA's branch about product variants in the CMS. Review is coming.
bzr revid: tde@openerp.com-20140121093832-yp3jl36nsuho74vk
This commit is contained in:
commit
28eaa636f0
|
@ -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','<>','view'),('type','<>','consolidation')]"/>
|
||||
<field name="property_account_expense" domain="[('type','<>','view'),('type','<>','consolidation')]"/>
|
||||
<field name="taxes_id"/>
|
||||
<field name="supplier_taxes_id"/>
|
||||
<group name="properties">
|
||||
<group>
|
||||
<field name="property_account_income" domain="[('type','<>','view'),('type','<>','consolidation')]"/>
|
||||
<field name="taxes_id" colspan="2" widget="many2many_tags"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="property_account_expense" domain="[('type','<>','view'),('type','<>','consolidation')]"/>
|
||||
<field name="supplier_taxes_id" colspan="2" widget="many2many_tags"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
</field>
|
||||
|
|
|
@ -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','<>','service'),('procure_method','<>','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','<>','product'),('procure_method','<>','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','<>','consu'),('procure_method','<>','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>
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
@ -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:
|
||||
|
@ -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 amount on sale price for the variant. eg. 10 price margin, 1000 * 1.1 = 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,16 @@ 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, context=None):
|
||||
res = {}
|
||||
if template_id:
|
||||
template = self.pool.get('product.template').browse(cr, uid, template_id, context=context)
|
||||
res['value'] = {
|
||||
'name': template.name,
|
||||
'lst_price': template.list_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 +806,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))
|
||||
|
@ -838,9 +868,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,7 +891,9 @@ 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'])))
|
||||
return super(product_product, self).search(cr, uid, args, offset=offset, limit=limit, order=order, context=context, count=count)
|
||||
|
||||
|
|
|
@ -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<0;blue:virtual_available>=0 and state in ('draft', 'end', 'obsolete');black:virtual_available>=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>
|
||||
|
@ -60,10 +63,13 @@
|
|||
<field name="image_medium" widget="image" class="oe_avatar oe_left"/>
|
||||
<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)" class="oe_inline"/>
|
||||
<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"/>
|
||||
</h1>
|
||||
<label for="categ_id" class="oe_edit_only"/>
|
||||
<h2><field name="categ_id"/></h2>
|
||||
|
@ -82,7 +88,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 +195,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 +228,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>
|
||||
|
@ -364,7 +370,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 +584,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,6 +674,19 @@
|
|||
</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>
|
||||
|
@ -704,12 +723,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','<>', 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 +747,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 +780,7 @@
|
|||
<field name="categ_id"/>
|
||||
<field name="type"/>
|
||||
<field name="state"/>
|
||||
<field name="uom_id" invisible="1"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
@ -762,81 +803,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>
|
||||
<group string="Procurement">
|
||||
<group colspan="4">
|
||||
<group>
|
||||
<field name="type"/>
|
||||
</group>
|
||||
|
||||
<group string="Base Prices">
|
||||
<field name="uom_id" on_change="onchange_uom(uom_id,uom_po_id)" groups="product.group_uom"/>
|
||||
<field name="list_price"/>
|
||||
<field name="standard_price" attrs="{'readonly':[('cost_method','=','average')]}"/>
|
||||
<field name="cost_method"/>
|
||||
</group>
|
||||
|
||||
<group string="Weights">
|
||||
<group>
|
||||
<field name="company_id" groups="base.group_multi_company" widget="selection"/>
|
||||
</group>
|
||||
</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')]}"/>
|
||||
</group>
|
||||
<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 & 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 +893,48 @@
|
|||
</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="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>
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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','<>','view'),('type','<>','consolidation')]"/>
|
||||
<field name="property_stock_account_output" domain="[('type','<>','view'),('type','<>','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','<>','view'),('type','<>','consolidation')]"/>
|
||||
<field name="property_stock_account_output" domain="[('type','<>','view'),('type','<>','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"
|
||||
|
|
|
@ -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"/>
|
||||
|
|
|
@ -138,8 +138,8 @@ class product_product(osv.Model):
|
|||
def _website_url(self, cr, uid, ids, field_name, arg, context=None):
|
||||
res = {}
|
||||
base_url = self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url')
|
||||
for id in ids:
|
||||
res[id] = "%s/shop/product/%s/" % (base_url, id)
|
||||
for product in self.browse(cr, uid, ids, context=context):
|
||||
res[product.id] = "%s/shop/product/%s/" % (base_url, product.product_tmpl_id.id)
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
|
|
|
@ -211,4 +211,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)]
|
||||
|
|
|
@ -65,13 +65,19 @@ $(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"));
|
||||
});
|
||||
|
||||
|
||||
//Trigger mouseup event of the checked radio button.
|
||||
$('form.js_add_cart_json label input.variant_radio').each(function() {
|
||||
if (this.checked) {
|
||||
$(this).parent().trigger('mouseup');
|
||||
}
|
||||
});
|
||||
|
||||
$(".js_slider").each(function() {
|
||||
var $slide = $(this);
|
||||
var $slider = $('<div>'+
|
||||
|
|
|
@ -302,26 +302,41 @@
|
|||
<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) > 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 class="variant_radio" 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>
|
||||
</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">
|
||||
<span class="text-danger" style="text-decoration: line-through;"
|
||||
t-field="product.product_variant_ids[0].lst_price"
|
||||
<span t-if = "variant_id.lst_price != variant_id.price">
|
||||
<span class="oe_variant_lst_price text-danger" style="text-decoration: line-through;"
|
||||
t-esc="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"
|
||||
}'/><br/>
|
||||
}'/>
|
||||
</label>
|
||||
</t>
|
||||
<div class="product_price mt16" t-if="product.product_variant_ids">
|
||||
<h4>
|
||||
<t t-if="len(product.product_variant_ids) < 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>
|
||||
<b class="oe_price"
|
||||
t-field="product.product_variant_ids[0].price"
|
||||
|
|
|
@ -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"/>
|
||||
|
|
Loading…
Reference in New Issue