diff --git a/addons/crm/static/description/crm_sc_05.png b/addons/crm/static/description/crm_sc_05.png
new file mode 100644
index 00000000000..b71ce805250
Binary files /dev/null and b/addons/crm/static/description/crm_sc_05.png differ
diff --git a/addons/product/product.py b/addons/product/product.py
index 3d4d2350d1a..f0a207a8064 100644
--- a/addons/product/product.py
+++ b/addons/product/product.py
@@ -364,7 +364,7 @@ class product_attribute_value(osv.osv):
_columns = {
'sequence': fields.integer('Sequence', help="Determine the display order"),
'name': fields.char('Value', translate=True, required=True),
- 'attribute_id': fields.many2one('product.attribute', 'Attribute', required=True),
+ 'attribute_id': fields.many2one('product.attribute', 'Attribute', required=True, ondelete='cascade'),
'product_ids': fields.many2many('product.product', id1='att_id', id2='prod_id', string='Variants', readonly=True),
'price_extra': fields.function(_get_price_extra, type='float', string='Attribute Price Extra',
fnct_inv=_set_price_extra,
@@ -378,20 +378,26 @@ class product_attribute_value(osv.osv):
_defaults = {
'price_extra': 0.0,
}
+ def unlink(self, cr, uid, ids, context=None):
+ ctx = dict(context or {}, active_test=False)
+ product_ids = self.pool['product.product'].search(cr, uid, [('attribute_value_ids', 'in', ids)], context=ctx)
+ if product_ids:
+ raise osv.except_osv(_('Integrity Error!'), _('The operation cannot be completed:\nYou trying to delete an attribute value with a reference on a product variant.'))
+ return super(product_attribute_value, self).unlink(cr, uid, ids, context=context)
class product_attribute_price(osv.osv):
_name = "product.attribute.price"
_columns = {
- 'product_tmpl_id': fields.many2one('product.template', 'Product Template', required=True),
- 'value_id': fields.many2one('product.attribute.value', 'Product Attribute Value', required=True),
+ 'product_tmpl_id': fields.many2one('product.template', 'Product Template', required=True, ondelete='cascade'),
+ 'value_id': fields.many2one('product.attribute.value', 'Product Attribute Value', required=True, ondelete='cascade'),
'price_extra': fields.float('Price Extra', digits_compute=dp.get_precision('Product Price')),
}
class product_attribute_line(osv.osv):
_name = "product.attribute.line"
_columns = {
- 'product_tmpl_id': fields.many2one('product.template', 'Product Template', required=True),
- 'attribute_id': fields.many2one('product.attribute', 'Attribute', required=True),
+ 'product_tmpl_id': fields.many2one('product.template', 'Product Template', required=True, ondelete='cascade'),
+ 'attribute_id': fields.many2one('product.attribute', 'Attribute', required=True, ondelete='restrict'),
'value_ids': fields.many2many('product.attribute.value', id1='line_id', id2='val_id', string='Product Attribute Value'),
}
@@ -898,7 +904,7 @@ class product_product(osv.osv):
'product.template': (_get_name_template_ids, ['name'], 10),
'product.product': (lambda self, cr, uid, ids, c=None: ids, [], 10),
}, select=True),
- 'attribute_value_ids': fields.many2many('product.attribute.value', id1='prod_id', id2='att_id', string='Attributes', readonly=True),
+ 'attribute_value_ids': fields.many2many('product.attribute.value', id1='prod_id', id2='att_id', string='Attributes', readonly=True, ondelete='restrict'),
# image: all image fields are base64 encoded and PIL-supported
'image_variant': fields.binary("Variant Image",
diff --git a/addons/product/product_view.xml b/addons/product/product_view.xml
index 963bdd0eea0..2e72d1aebf0 100644
--- a/addons/product/product_view.xml
+++ b/addons/product/product_view.xml
@@ -193,6 +193,7 @@
variants.template.tree
product.attribute.value
+
@@ -214,7 +215,7 @@
-
+
product.product.search
@@ -385,6 +386,54 @@
+
+ product.attribute.tree
+ product.attribute
+
+
+
+
+
+
+
+
+ Attributes
+ ir.actions.act_window
+ product.attribute
+ tree
+ form
+
+
+
+
+
+ product.attribute.value.tree
+ product.attribute.value
+
+
+
+
+
+
+
+
+
+
+ Attribute Values
+ ir.actions.act_window
+ product.attribute.value
+ tree
+ form
+
+
+
+
+
+
Product Variants
ir.actions.act_window
diff --git a/addons/stock/wizard/make_procurement_product.py b/addons/stock/wizard/make_procurement_product.py
index 5c6f4b618ee..dbc15ad81a7 100644
--- a/addons/stock/wizard/make_procurement_product.py
+++ b/addons/stock/wizard/make_procurement_product.py
@@ -20,7 +20,8 @@
##############################################################################
-from openerp.osv import fields, osv
+from openerp.osv import fields, osv, orm
+from openerp.tools.translate import _
class make_procurement(osv.osv_memory):
_name = 'make.procurement'
@@ -108,6 +109,13 @@ class make_procurement(osv.osv_memory):
context = {}
record_id = context.get('active_id')
+ if context.get('active_model') == 'product.template':
+ product_ids = self.pool.get('product.product').search(cr, uid, [('product_tmpl_id', '=', context.get('active_id'))], context=context)
+ if len(product_ids) == 1:
+ record_id = product_ids[0]
+ else:
+ raise orm.except_orm(_('Warning'), _('Please use the Product Variant vue to request a procurement.'))
+
res = super(make_procurement, self).default_get(cr, uid, fields, context=context)
if record_id and 'product_id' in fields:
diff --git a/addons/stock/wizard/stock_change_product_qty.py b/addons/stock/wizard/stock_change_product_qty.py
index 646a047d63c..62290e17572 100644
--- a/addons/stock/wizard/stock_change_product_qty.py
+++ b/addons/stock/wizard/stock_change_product_qty.py
@@ -50,6 +50,13 @@ class stock_change_product_qty(osv.osv_memory):
res = super(stock_change_product_qty, self).default_get(cr, uid, fields, context=context)
+ if context.get('active_model') == 'product.template':
+ product_ids = self.pool.get('product.product').search(cr, uid, [('product_tmpl_id', '=', context.get('active_id'))], context=context)
+ if len(product_ids) == 1:
+ res['product_id'] = product_ids[0]
+ else:
+ raise orm.except_orm(_('Warning'), _('Please use the Product Variant vue to update the product quantity.'))
+
if 'location_id' in fields:
location_id = res.get('location_id', False)
if not location_id:
@@ -77,12 +84,8 @@ class stock_change_product_qty(osv.osv_memory):
if context is None:
context = {}
- rec_id = context and context.get('active_id', False)
- assert rec_id, _('Active ID is not set in Context')
-
inventory_obj = self.pool.get('stock.inventory')
inventory_line_obj = self.pool.get('stock.inventory.line')
- prod_obj_pool = self.pool.get('product.product')
for data in self.browse(cr, uid, ids, context=context):
if data.new_quantity < 0:
@@ -90,15 +93,18 @@ class stock_change_product_qty(osv.osv_memory):
ctx = context.copy()
ctx['location'] = data.location_id.id
ctx['lot_id'] = data.lot_id.id
- res_original = prod_obj_pool.browse(cr, uid, rec_id, context=ctx)
- inventory_id = inventory_obj.create(cr, uid, {'name': _('INV: %s') % tools.ustr(res_original.name), 'product_id': rec_id, 'location_id': data.location_id.id, 'lot_id': data.lot_id.id}, context=context)
- th_qty = res_original.qty_available
+ inventory_id = inventory_obj.create(cr, uid, {
+ 'name': _('INV: %s') % tools.ustr(data.product_id.name),
+ 'product_id': data.product_id.id,
+ 'location_id': data.location_id.id,
+ 'lot_id': data.lot_id.id}, context=context)
+ th_qty = data.product_id.qty_available
line_data = {
'inventory_id': inventory_id,
'product_qty': data.new_quantity,
'location_id': data.location_id.id,
- 'product_id': rec_id,
- 'product_uom_id': res_original.uom_id.id,
+ 'product_id': data.product_id.id,
+ 'product_uom_id': data.product_id.uom_id.id,
'th_qty': th_qty,
'prod_lot_id': data.lot_id.id
}
diff --git a/addons/web_diagram/static/src/js/diagram.js b/addons/web_diagram/static/src/js/diagram.js
index 34dc5e084c7..77876c9dc52 100644
--- a/addons/web_diagram/static/src/js/diagram.js
+++ b/addons/web_diagram/static/src/js/diagram.js
@@ -24,15 +24,6 @@ instance.web.DiagramView = instance.web.View.extend({
this.ids = this.dataset.ids;
this.on('pager_action_executed', self, self.pager_action_trigger);
},
- start: function () {
- return this._super().then(function () {
- return $.when(
- openerp.webclient.session.load_js(['/web/js/web_diagram.assets_raphael'])
- );
- }).fail(function () {
- throw new Error("Could not load raphael.js");
- });
- },
view_loading: function(r) {
return this.load_diagram(r);
diff --git a/addons/web_kanban_gauge/static/lib/justgage/justgage.js b/addons/web_kanban_gauge/static/lib/justgage/justgage.js
index 3e23c12a29e..3e3437eeb5f 100644
--- a/addons/web_kanban_gauge/static/lib/justgage/justgage.js
+++ b/addons/web_kanban_gauge/static/lib/justgage/justgage.js
@@ -295,7 +295,7 @@
}
if (obj.config.relativeGaugeSize === true) {
- obj.canvas.setViewBox(0, 0, 200, 150, true);
+ obj.canvas.setViewBox(0, 0, 200, 150, false);
}
// canvas dimensions
@@ -306,7 +306,7 @@
canvasW = obj.config.width;
canvasH = obj.config.height;
} else if (obj.config.parentNode !== null) {
- obj.canvas.setViewBox(0, 0, 200, 150, true);
+ obj.canvas.setViewBox(0, 0, 200, 150, false);
canvasW = 200;
canvasH = 150;
} else {
diff --git a/addons/website_sale/views/views.xml b/addons/website_sale/views/views.xml
index fcc42502035..9971097a061 100644
--- a/addons/website_sale/views/views.xml
+++ b/addons/website_sale/views/views.xml
@@ -45,6 +45,16 @@
+
+ variants.template.tree
+ product.attribute.value
+
+
+
+
+
+
+