+
+
+
Click to design your email.
diff --git a/addons/mass_mailing/views/snippets.xml b/addons/mass_mailing/views/snippets.xml
index cefe2e7bdfd..e05e680206f 100644
--- a/addons/mass_mailing/views/snippets.xml
+++ b/addons/mass_mailing/views/snippets.xml
@@ -20,6 +20,7 @@
placeholder="your email..."/>
Subscribe
+ Thanks
Thanks for your subscription!
diff --git a/addons/mass_mailing/wizard/mail_compose_message.py b/addons/mass_mailing/wizard/mail_compose_message.py
index 4aebff2d04d..ede3fe37803 100644
--- a/addons/mass_mailing/wizard/mail_compose_message.py
+++ b/addons/mass_mailing/wizard/mail_compose_message.py
@@ -43,10 +43,15 @@ class MailComposeMessage(osv.TransientModel):
}, context=context)
mass_mailing = self.pool['mail.mass_mailing'].browse(cr, uid, mass_mailing_id, context=context)
for res_id in res_ids:
- res[res_id]['mailing_id'] = mass_mailing.id
- res[res_id]['statistics_ids'] = [(0, 0, {
- 'model': wizard.model,
- 'res_id': res_id,
- 'mass_mailing_id': mass_mailing.id,
- })]
+ res[res_id].update({
+ 'mailing_id': mass_mailing.id,
+ 'statistics_ids': [(0, 0, {
+ 'model': wizard.model,
+ 'res_id': res_id,
+ 'mass_mailing_id': mass_mailing.id,
+ })],
+ # email-mode: keep original message for routing
+ 'notification': mass_mailing.reply_to_mode == 'thread',
+ 'auto_delete': True,
+ })
return res
diff --git a/addons/mrp/mrp.py b/addons/mrp/mrp.py
index 23033fa0af5..f5b6cf466a5 100644
--- a/addons/mrp/mrp.py
+++ b/addons/mrp/mrp.py
@@ -325,8 +325,8 @@ class mrp_bom(osv.osv):
})
else:
bom_id = self._bom_find(cr, uid, bom_line_id.product_uom.id, product_id=bom_line_id.product_id.id, properties=properties)
- bom2 = self.browse(cr, uid, bom_id)
- if bom2:
+ if bom_id:
+ bom2 = self.browse(cr, uid, bom_id)
res = self._bom_explode(cr, uid, bom2, bom_line_id.product_id, factor,
properties=properties, level=level + 10, previous_products=all_prod, master_bom=master_bom)
result = result + res[0]
diff --git a/addons/mrp_byproduct/mrp_byproduct.py b/addons/mrp_byproduct/mrp_byproduct.py
index 91ea997a2e4..fc6069fc8ad 100644
--- a/addons/mrp_byproduct/mrp_byproduct.py
+++ b/addons/mrp_byproduct/mrp_byproduct.py
@@ -35,7 +35,7 @@ class mrp_subproduct(osv.osv):
'Fixed' depicts a situation where the quantity of created byproduct is always equal to the quantity set on the BoM, regardless of how many are created in the production order.\
By opposition, 'Variable' means that the quantity will be computed as\
'(quantity of byproduct set on the BoM / quantity of manufactured product set on the BoM * quantity of manufactured product in the production order.)'"),
- 'bom_id': fields.many2one('mrp.bom', 'BoM'),
+ 'bom_id': fields.many2one('mrp.bom', 'BoM', ondelete='cascade'),
}
_defaults={
'subproduct_type': 'variable',
diff --git a/addons/point_of_sale/static/src/js/db.js b/addons/point_of_sale/static/src/js/db.js
index b8edc9dd472..1057d774806 100644
--- a/addons/point_of_sale/static/src/js/db.js
+++ b/addons/point_of_sale/static/src/js/db.js
@@ -29,7 +29,7 @@ function openerp_pos_db(instance, module){
this.category_parent = {};
this.category_search_string = {};
this.packagings_by_id = {};
- this.packagings_by_product_id = {};
+ this.packagings_by_product_tmpl_id = {};
this.packagings_by_ean13 = {};
},
/* returns the category object from its id. If you pass a list of id as parameters, you get
@@ -130,7 +130,7 @@ function openerp_pos_db(instance, module){
if(product.default_code){
str += '|' + product.default_code;
}
- var packagings = this.packagings_by_product_id[product.id] || [];
+ var packagings = this.packagings_by_product_tmpl_id[product.product_tmpl_id] || [];
for(var i = 0; i < packagings.length; i++){
str += '|' + packagings[i].ean;
}
@@ -149,6 +149,7 @@ function openerp_pos_db(instance, module){
if (product.variants){
product.name = product.name+" ("+product.variants+")";
}
+ product.product_tmpl_id = product.product_tmpl_id[0];
if(!stored_categories[categ_id]){
stored_categories[categ_id] = [];
}
@@ -186,10 +187,10 @@ function openerp_pos_db(instance, module){
for(var i = 0, len = packagings.length; i < len; i++){
var pack = packagings[i];
this.packagings_by_id[pack.id] = pack;
- if(!this.packagings_by_product_id[pack.product_id[0]]){
- this.packagings_by_product_id[pack.product_id[0]] = [];
+ if(!this.packagings_by_product_tmpl_id[pack.product_tmpl_id[0]]){
+ this.packagings_by_product_tmpl_id[pack.product_tmpl_id[0]] = [];
}
- this.packagings_by_product_id[pack.product_id[0]].push(pack);
+ this.packagings_by_product_tmpl_id[pack.product_tmpl_id[0]].push(pack);
if(pack.ean){
this.packagings_by_ean13[pack.ean] = pack;
}
diff --git a/addons/point_of_sale/static/src/js/models.js b/addons/point_of_sale/static/src/js/models.js
index 0c3c91f2a98..94a23042df6 100644
--- a/addons/point_of_sale/static/src/js/models.js
+++ b/addons/point_of_sale/static/src/js/models.js
@@ -204,18 +204,19 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
self.accounting_precision = precision;
console.log("PRECISION",precision);
*/
- return self.fetch('product.packaging',['ean','product_id']);
+ return self.fetch('product.packaging',['ean','product_tmpl_id']);
}).then(function(packagings){
self.db.add_packagings(packagings);
- return self.fetch('pos.category', ['id','name','parent_id','child_id','image'])
+ return self.fetch('pos.category', ['id','name','parent_id','child_id','image']);
}).then(function(categories){
self.db.add_categories(categories);
return self.fetch(
- 'product.product',
+ 'product.product',
['name', 'list_price','price','pos_categ_id', 'taxes_id', 'ean13', 'default_code', 'variants',
- 'to_weight', 'uom_id', 'uos_id', 'uos_coeff', 'mes_type', 'description_sale', 'description'],
+ 'to_weight', 'uom_id', 'uos_id', 'uos_coeff', 'mes_type', 'description_sale', 'description',
+ 'product_tmpl_id'],
[['sale_ok','=',true],['available_in_pos','=',true]],
{pricelist: self.pricelist.id} // context for price
);
@@ -230,7 +231,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
}).then(function(bankstatements){
var journals = [];
_.each(bankstatements,function(statement) {
- journals.push(statement.journal_id[0])
+ journals.push(statement.journal_id[0]);
});
self.bankstatements = bankstatements;
return self.fetch('account.journal', undefined, [['id','in', journals]]);
@@ -238,7 +239,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
self.journals = journals;
// associate the bank statements with their journals.
- var bankstatements = self.bankstatements
+ var bankstatements = self.bankstatements;
for(var i = 0, ilen = bankstatements.length; i < ilen; i++){
for(var j = 0, jlen = journals.length; j < jlen; j++){
if(bankstatements[i].journal_id[0] === journals[j].id){
diff --git a/addons/procurement/procurement.py b/addons/procurement/procurement.py
index d1ce6047e76..787178723ab 100644
--- a/addons/procurement/procurement.py
+++ b/addons/procurement/procurement.py
@@ -276,7 +276,8 @@ class procurement_order(osv.osv):
@param cr: The current row, from the database cursor,
@param uid: The current user ID for security checks
@param ids: List of selected IDs
- @param use_new_cursor: False or the dbname
+ @param use_new_cursor: if set, use a dedicated cursor and auto-commit after processing each procurement.
+ This is appropriate for batch jobs only.
@param context: A standard dictionary for contextual values
@return: Dictionary of values
'''
@@ -284,7 +285,7 @@ class procurement_order(osv.osv):
context = {}
try:
if use_new_cursor:
- cr = openerp.registry(use_new_cursor).cursor()
+ cr = openerp.registry(cr.dbname).cursor()
# Run confirmed procurements
while True:
diff --git a/addons/product/__openerp__.py b/addons/product/__openerp__.py
index 83ecea95886..469941620e1 100644
--- a/addons/product/__openerp__.py
+++ b/addons/product/__openerp__.py
@@ -25,7 +25,7 @@
'version': '1.1',
'author': 'OpenERP SA',
'category': 'Sales Management',
- 'depends': ['base', 'decimal_precision', 'mail'],
+ 'depends': ['base', 'decimal_precision', 'mail', 'report'],
'demo': [
'product_demo.xml',
'product_image_demo.xml',
diff --git a/addons/product/pricelist_view.xml b/addons/product/pricelist_view.xml
index 8d725b3beee..bb4b2b0129b 100644
--- a/addons/product/pricelist_view.xml
+++ b/addons/product/pricelist_view.xml
@@ -74,7 +74,7 @@
-
+
@@ -92,7 +92,7 @@
-
+
diff --git a/addons/product/product.py b/addons/product/product.py
index 2369db49d43..eaed55c0b41 100644
--- a/addons/product/product.py
+++ b/addons/product/product.py
@@ -202,6 +202,8 @@ class product_uom(osv.osv):
return {}
def write(self, cr, uid, ids, vals, context=None):
+ if isinstance(ids, (int, long)):
+ ids = [ids]
if 'category_id' in vals:
for uom in self.browse(cr, uid, ids, context=context):
if uom.category_id.id != vals['category_id']:
@@ -344,6 +346,8 @@ class product_attribute_value(osv.osv):
return result
def _set_price_extra(self, cr, uid, id, name, value, args, context=None):
+ if context is None:
+ context = {}
if 'active_id' not in context:
return None
p_obj = self.pool['product.attribute.price']
@@ -351,7 +355,7 @@ class product_attribute_value(osv.osv):
if p_ids:
p_obj.write(cr, uid, p_ids, {'price_extra': value}, context=context)
else:
- p_obj.create(cr, uid, p_ids, {
+ p_obj.create(cr, uid, {
'product_tmpl_id': context['active_id'],
'value_id': id,
'price_extra': value,
@@ -458,6 +462,8 @@ class product_template(osv.osv):
def _set_standard_price(self, cr, uid, product_tmpl_id, value, context=None):
''' Store the standard price change in order to be able to retrieve the cost of a product template for a given date'''
+ if context is None:
+ context = {}
price_history_obj = self.pool['product.price.history']
user_company = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.id
company_id = context.get('force_company', user_company)
@@ -532,10 +538,10 @@ class product_template(osv.osv):
help="Small-sized image of the product. It is automatically "\
"resized as a 64x64px image, with aspect ratio preserved. "\
"Use this field anywhere a small image is required."),
-
- 'packaging' : fields.one2many('product.packaging', 'product_id', 'Logistical Units',
- help="Gives the different ways to package the same product. This has no impact on the picking order and is mainly used if you use the EDI module."),
-
+ 'packaging_ids': fields.one2many(
+ 'product.packaging', 'product_tmpl_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."),
'seller_ids': fields.one2many('product.supplierinfo', 'product_tmpl_id', 'Supplier'),
'seller_delay': fields.related('seller_ids','delay', type='integer', string='Supplier Lead Time',
help="This is the average delay in days between the purchase order confirmation and the reception of goods for this product and for the default supplier. It is used by the scheduler to order requests based on reordering delays."),
@@ -676,7 +682,7 @@ class product_template(osv.osv):
def write(self, cr, uid, ids, vals, context=None):
''' Store the standard price change in order to be able to retrieve the cost of a product template for a given date'''
- if isinstance(id, (int, long)):
+ if isinstance(ids, (int, long)):
ids = [ids]
if 'uom_po_id' in vals:
new_uom = self.pool.get('product.uom').browse(cr, uid, vals['uom_po_id'], context=context)
@@ -879,7 +885,6 @@ class product_product(osv.osv):
'active': fields.boolean('Active', help="If unchecked, it will allow you to hide the product without removing it."),
'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', 'Packaging', 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."),
'name_template': fields.related('product_tmpl_id', 'name', string="Template Name", type='char', store={
'product.template': (_get_name_template_ids, ['name'], 10),
'product.product': (lambda self, cr, uid, ids, c=None: ids, [], 10),
@@ -1075,7 +1080,7 @@ class product_packaging(osv.osv):
'ul_container': fields.many2one('product.ul', 'Pallet Logistic Unit'),
'rows' : fields.integer('Number of Layers', required=True,
help='The number of layers on a pallet or box'),
- 'product_id' : fields.many2one('product.product', 'Product', select=1, ondelete='cascade', required=True),
+ 'product_tmpl_id' : fields.many2one('product.template', 'Product', select=1, ondelete='cascade', required=True),
'ean' : fields.char('EAN', size=14, help="The EAN code of the package unit."),
'code' : fields.char('Code', help="The code of the transport unit."),
'weight': fields.float('Total Package Weight',
@@ -1147,7 +1152,7 @@ class product_supplierinfo(osv.osv):
'company_id':fields.many2one('res.company','Company',select=1),
}
_defaults = {
- 'qty': 0.0,
+ 'min_qty': 0.0,
'sequence': 1,
'delay': 1,
'company_id': lambda self,cr,uid,c: self.pool.get('res.company')._company_default_get(cr, uid, 'product.supplierinfo', context=c),
diff --git a/addons/product/product_demo.xml b/addons/product/product_demo.xml
index 4f922f40629..112cb581a4b 100644
--- a/addons/product/product_demo.xml
+++ b/addons/product/product_demo.xml
@@ -213,6 +213,10 @@ FaceTime HD Camera, 1.2 MP Photos
+
+
+
+
diff --git a/addons/product/product_view.xml b/addons/product/product_view.xml
index 9b5770a565d..aff15867476 100644
--- a/addons/product/product_view.xml
+++ b/addons/product/product_view.xml
@@ -270,7 +270,7 @@
-
+
@@ -657,7 +657,7 @@
@@ -54,7 +54,7 @@
6
4
-
+
10
@@ -82,7 +82,7 @@
6
4
-
+
10
@@ -110,7 +110,7 @@
6
4
-
+
10
diff --git a/addons/purchase/purchase.py b/addons/purchase/purchase.py
index 08362899ccf..2f86d674d75 100644
--- a/addons/purchase/purchase.py
+++ b/addons/purchase/purchase.py
@@ -661,6 +661,8 @@ class purchase_order(osv.osv):
_('You must first cancel all invoices related to this purchase order.'))
self.pool.get('account.invoice') \
.signal_invoice_cancel(cr, uid, map(attrgetter('id'), purchase.invoice_ids))
+ self.pool['purchase.order.line'].write(cr, uid, [l.id for l in purchase.order_line],
+ {'state': 'cancel'})
self.write(cr, uid, ids, {'state': 'cancel'})
self.set_order_line_status(cr, uid, ids, 'cancel', context=context)
self.signal_purchase_cancel(cr, uid, ids)
@@ -982,6 +984,9 @@ class purchase_order_line(osv.osv):
return super(purchase_order_line, self).copy_data(cr, uid, id, default, context)
def unlink(self, cr, uid, ids, context=None):
+ for line in self.browse(cr, uid, ids, context=context):
+ if line.state not in ['draft', 'cancel']:
+ raise osv.except_osv(_('Invalid Action!'), _('Cannot delete a purchase order line which is in state \'%s\'.') %(line.state,))
procurement_obj = self.pool.get('procurement.order')
procurement_ids_to_cancel = procurement_obj.search(cr, uid, [('purchase_line_id', 'in', ids)], context=context)
if procurement_ids_to_cancel:
diff --git a/addons/sale/sale.py b/addons/sale/sale.py
index 70dece22651..45c32a33b22 100644
--- a/addons/sale/sale.py
+++ b/addons/sale/sale.py
@@ -538,14 +538,18 @@ class sale_order(osv.osv):
if grouped:
res = self._make_invoice(cr, uid, val[0][0], reduce(lambda x, y: x + y, [l for o, l in val], []), context=context)
invoice_ref = ''
+ origin_ref = ''
for o, l in val:
- invoice_ref += o.name + '|'
+ invoice_ref += (o.client_order_ref or o.name) + '|'
+ origin_ref += (o.origin or o.name) + '|'
self.write(cr, uid, [o.id], {'state': 'progress'})
cr.execute('insert into sale_order_invoice_rel (order_id,invoice_id) values (%s,%s)', (o.id, res))
#remove last '|' in invoice_ref
- if len(invoice_ref) >= 1:
+ if len(invoice_ref) >= 1:
invoice_ref = invoice_ref[:-1]
- invoice.write(cr, uid, [res], {'origin': invoice_ref, 'name': invoice_ref})
+ if len(origin_ref) >= 1:
+ origin_ref = origin_ref[:-1]
+ invoice.write(cr, uid, [res], {'origin': origin_ref, 'name': invoice_ref})
else:
for order, il in val:
res = self._make_invoice(cr, uid, order, il, context=context)
diff --git a/addons/sale_stock/sale_stock.py b/addons/sale_stock/sale_stock.py
index 65158582eb0..b3bbd253392 100644
--- a/addons/sale_stock/sale_stock.py
+++ b/addons/sale_stock/sale_stock.py
@@ -277,7 +277,7 @@ class sale_order_line(osv.osv):
warning_msgs = res.get('warning') and res['warning'].get('message', '') or ''
products = product_obj.browse(cr, uid, product, context=context)
- if not products.packaging:
+ if not products.packaging_ids:
packaging = result['product_packaging'] = False
if packaging:
diff --git a/addons/sales_team/sales_team.xml b/addons/sales_team/sales_team.xml
index 5ac8e24d8bb..647a9803914 100644
--- a/addons/sales_team/sales_team.xml
+++ b/addons/sales_team/sales_team.xml
@@ -126,7 +126,7 @@