The tags should be separated by a comma without any
- spacing. For example, if you want you customer to be
- lined to both tags 'Manufacturer' and 'Retailer'
- then you will encode it as follow "Manufacturer,
+ spacing. For example, if you want your customer to be
+ linked to both tags 'Manufacturer' and 'Retailer'
+ then you will encode "Manufacturer,
Retailer" in the same column of your CSV file.
CSV file for Manufacturer, Retailer
diff --git a/addons/google_calendar/google_calendar.py b/addons/google_calendar/google_calendar.py
index 70c6cceaed4..d4743f22bac 100644
--- a/addons/google_calendar/google_calendar.py
+++ b/addons/google_calendar/google_calendar.py
@@ -502,6 +502,7 @@ class google_calendar(osv.AbstractModel):
rrule = [rule for rule in single_event_dict["recurrence"] if rule.startswith("RRULE:")][0][6:]
result['rrule'] = rrule
+ context = dict(context or {}, no_mail_to_attendees=True)
if type == "write":
res = calendar_event.write(cr, uid, event['id'], result, context=context)
elif type == "copy":
diff --git a/addons/hr_timesheet_sheet/hr_timesheet_sheet.py b/addons/hr_timesheet_sheet/hr_timesheet_sheet.py
index e71514f1d32..9ac36bbc63c 100644
--- a/addons/hr_timesheet_sheet/hr_timesheet_sheet.py
+++ b/addons/hr_timesheet_sheet/hr_timesheet_sheet.py
@@ -265,6 +265,14 @@ class hr_timesheet_sheet(osv.osv):
raise UserError(_('You cannot delete a timesheet which is already confirmed.'))
elif sheet['total_attendance'] <> 0.00:
raise UserError(_('You cannot delete a timesheet which have attendance entries.'))
+
+ toremove = []
+ analytic_timesheet = self.pool.get('hr.analytic.timesheet')
+ for sheet in self.browse(cr, uid, ids, context=context):
+ for timesheet in sheet.timesheet_ids:
+ toremove.append(timesheet.id)
+ analytic_timesheet.unlink(cr, uid, toremove, context=context)
+
return super(hr_timesheet_sheet, self).unlink(cr, uid, ids, context=context)
def onchange_employee_id(self, cr, uid, ids, employee_id, context=None):
diff --git a/addons/product/product.py b/addons/product/product.py
index c2596b93e0c..72a7848fd8c 100644
--- a/addons/product/product.py
+++ b/addons/product/product.py
@@ -22,8 +22,10 @@
import math
import re
import time
+from collections import OrderedDict
from _common import ceiling
+
from openerp import SUPERUSER_ID
from openerp import tools
from openerp.osv import osv, fields, expression
@@ -796,9 +798,16 @@ class product_template(osv.osv):
pass
return super(product_template, self).name_get(cr, user, ids, context)
-
-
-
+ def name_search(self, cr, user, name='', args=None, operator='ilike', context=None, limit=100):
+ product_product = self.pool['product.product']
+ results = product_product.name_search(
+ cr, user, name, args, operator=operator, context=context, limit=limit)
+ product_ids = [p[0] for p in results]
+ template_ids = [p.product_tmpl_id.id
+ for p in product_product.browse(
+ cr, user, product_ids, context=context)]
+ uniq_ids = OrderedDict.fromkeys(template_ids).keys()
+ return self.name_get(cr, user, uniq_ids, context=context)
class product_product(osv.osv):
_name = "product.product"
@@ -1068,12 +1077,11 @@ class product_product(osv.osv):
# on a database with thousands of matching products, due to the huge merge+unique needed for the
# 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(self.search(cr, user, args + [('default_code', operator, name)], limit=limit, context=context))
+ ids = self.search(cr, user, args + [('default_code', 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
limit2 = (limit - len(ids)) if limit else False
- ids.update(self.search(cr, user, args + [('name', operator, name), ('id', 'not in', list(ids))], limit=limit2, context=context))
- ids = list(ids)
+ ids += self.search(cr, user, args + [('name', operator, name), ('id', 'not in', ids)], limit=limit2, context=context)
elif not ids and operator in expression.NEGATIVE_TERM_OPERATORS:
ids = self.search(cr, user, args + ['&', ('default_code', operator, name), ('name', operator, name)], limit=limit, context=context)
if not ids and operator in positive_operators:
diff --git a/addons/project_timesheet/project_timesheet.py b/addons/project_timesheet/project_timesheet.py
index dfa2ea0cad7..9ec821dfc9c 100644
--- a/addons/project_timesheet/project_timesheet.py
+++ b/addons/project_timesheet/project_timesheet.py
@@ -115,9 +115,12 @@ class project_work(osv.osv):
vals_line['user_id'] = vals['user_id']
vals_line['product_id'] = result['product_id']
if vals.get('date'):
- timestamp = datetime.datetime.strptime(vals['date'], tools.DEFAULT_SERVER_DATETIME_FORMAT)
- ts = fields.datetime.context_timestamp(cr, uid, timestamp, context)
- vals_line['date'] = ts.strftime(tools.DEFAULT_SERVER_DATE_FORMAT)
+ if len(vals['date']) > 10:
+ timestamp = datetime.datetime.strptime(vals['date'], tools.DEFAULT_SERVER_DATETIME_FORMAT)
+ ts = fields.datetime.context_timestamp(cr, uid, timestamp, context)
+ vals_line['date'] = ts.strftime(tools.DEFAULT_SERVER_DATE_FORMAT)
+ else:
+ vals_line['date'] = vals['date']
# Calculate quantity based on employee's product's uom
vals_line['unit_amount'] = vals['hours']
@@ -260,7 +263,7 @@ class task(osv.osv):
missing_analytic_entries[task_work.id] = {
'name' : task_work.name,
'user_id' : task_work.user_id.id,
- 'date' : task_work.date and task_work.date[:10] or False,
+ 'date' : task_work.date,
'account_id': acc_id,
'hours' : task_work.hours,
'task_id' : task_obj.id
diff --git a/addons/purchase/stock.py b/addons/purchase/stock.py
index 102ef73deea..00c69b4e86b 100644
--- a/addons/purchase/stock.py
+++ b/addons/purchase/stock.py
@@ -70,13 +70,33 @@ class stock_move(osv.osv):
self.pool.get('purchase.order').write(cr, uid, [purchase_line.order_id.id], {
'invoice_ids': [(4, invoice_line_vals['invoice_id'])],
})
+ purchase_line_obj = self.pool.get('purchase.order.line')
+ purchase_obj = self.pool.get('purchase.order')
+ invoice_line_obj = self.pool.get('account.invoice.line')
+ purchase_id = move.purchase_line_id.order_id.id
+ purchase_line_ids = purchase_line_obj.search(cr, uid, [('order_id', '=', purchase_id), ('product_id.type', '=', 'service'), ('invoice_lines', '=', False)], context=context)
+ if purchase_line_ids:
+ inv_lines = []
+ for po_line in purchase_line_obj.browse(cr, uid, purchase_line_ids, context=context):
+ acc_id = purchase_obj._choose_account_from_po_line(cr, uid, po_line, context=context)
+ inv_line_data = purchase_obj._prepare_inv_line(cr, uid, acc_id, po_line, context=context)
+ inv_line_id = invoice_line_obj.create(cr, uid, inv_line_data, context=context)
+ inv_lines.append(inv_line_id)
+ po_line.write({'invoice_lines': [(4, inv_line_id)]})
+ invoice_line_obj.write(cr, uid, inv_lines, {'invoice_id': invoice_line_vals['invoice_id']}, context=context)
return invoice_line_id
def _get_master_data(self, cr, uid, move, company, context=None):
if move.purchase_line_id:
purchase_order = move.purchase_line_id.order_id
return purchase_order.partner_id, purchase_order.create_uid.id, purchase_order.currency_id.id
- else:
+ elif move.picking_id:
+ # In case of an extra move, it is better to use the data from the original moves
+ for purchase_move in move.picking_id.move_lines:
+ if purchase_move.purchase_line_id:
+ purchase_order = purchase_move.purchase_line_id.order_id
+ return purchase_order.partner_id, purchase_order.create_uid.id, purchase_order.currency_id.id
+
partner = move.picking_id and move.picking_id.partner_id or False
code = self.get_code_from_locs(cr, uid, move, context=context)
if partner and partner.property_product_pricelist_purchase and code == 'incoming':
@@ -149,18 +169,6 @@ class stock_picking(osv.osv):
purchase_line_obj = self.pool.get('purchase.order.line')
invoice_line_obj = self.pool.get('account.invoice.line')
invoice_id = super(stock_picking, self)._create_invoice_from_picking(cr, uid, picking, vals, context=context)
- if picking.move_lines and picking.move_lines[0].purchase_line_id:
- purchase_id = picking.move_lines[0].purchase_line_id.order_id.id
- purchase_line_ids = purchase_line_obj.search(cr, uid, [('order_id', '=', purchase_id), ('product_id.type', '=', 'service'), ('invoiced', '=', False)], context=context)
- if purchase_line_ids:
- inv_lines = []
- for po_line in purchase_line_obj.browse(cr, uid, purchase_line_ids, context=context):
- acc_id = purchase_obj._choose_account_from_po_line(cr, uid, po_line, context=context)
- inv_line_data = purchase_obj._prepare_inv_line(cr, uid, acc_id, po_line, context=context)
- inv_line_id = invoice_line_obj.create(cr, uid, inv_line_data, context=context)
- inv_lines.append(inv_line_id)
- po_line.write({'invoice_lines': [(4, inv_line_id)]})
- invoice_line_obj.write(cr, uid, inv_lines, {'invoice_id': invoice_id}, context=context)
return invoice_id
def _get_invoice_vals(self, cr, uid, key, inv_type, journal_id, move, context=None):
diff --git a/addons/report/models/abstract_report.py b/addons/report/models/abstract_report.py
index 08d70e83e20..cccaa339b63 100644
--- a/addons/report/models/abstract_report.py
+++ b/addons/report/models/abstract_report.py
@@ -54,7 +54,9 @@ class AbstractReport(osv.AbstractModel):
# Rendering self._template with the wrapped report instance localcontext as
# rendering environment
- docargs = wrapped_report.localcontext
+ docargs = dict(wrapped_report.localcontext)
+ if not docargs.get('lang'):
+ docargs.pop('lang', False)
docargs['docs'] = docargs.get('objects')
# Used in template translation (see translate_doc method from report model)
diff --git a/addons/sale/sale_view.xml b/addons/sale/sale_view.xml
index 246356b42c2..1baa2448c8c 100644
--- a/addons/sale/sale_view.xml
+++ b/addons/sale/sale_view.xml
@@ -517,7 +517,7 @@
diff --git a/addons/sale_stock/sale_stock.py b/addons/sale_stock/sale_stock.py
index 683b2ff47db..60866b782c3 100644
--- a/addons/sale_stock/sale_stock.py
+++ b/addons/sale_stock/sale_stock.py
@@ -374,12 +374,23 @@ class stock_move(osv.osv):
self.pool.get('sale.order').write(cr, uid, [sale_line.order_id.id], {
'invoice_ids': [(4, invoice_line_vals['invoice_id'])],
})
+ sale_line_obj = self.pool.get('sale.order.line')
+ invoice_line_obj = self.pool.get('account.invoice.line')
+ sale_line_ids = sale_line_obj.search(cr, uid, [('order_id', '=', move.procurement_id.sale_line_id.order_id.id), ('product_id.type', '=', 'service'), ('invoiced', '=', False)], context=context)
+ if sale_line_ids:
+ created_lines = sale_line_obj.invoice_line_create(cr, uid, sale_line_ids, context=context)
+ invoice_line_obj.write(cr, uid, created_lines, {'invoice_id': invoice_line_vals['invoice_id']}, context=context)
+
return invoice_line_id
def _get_master_data(self, cr, uid, move, company, context=None):
if move.procurement_id and move.procurement_id.sale_line_id and move.procurement_id.sale_line_id.order_id.order_policy == 'picking':
sale_order = move.procurement_id.sale_line_id.order_id
return sale_order.partner_invoice_id, sale_order.user_id.id, sale_order.pricelist_id.currency_id.id
+ elif move.picking_id.sale_id:
+ # In case of extra move, it is better to use the same data as the original moves
+ sale_order = move.picking_id.sale_id
+ return sale_order.partner_invoice_id, sale_order.user_id.id, sale_order.pricelist_id.currency_id.id
return super(stock_move, self)._get_master_data(cr, uid, move, company, context=context)
def _get_invoice_line_vals(self, cr, uid, move, partner, inv_type, context=None):
@@ -442,13 +453,6 @@ class stock_picking(osv.osv):
sale_line_obj = self.pool.get('sale.order.line')
invoice_line_obj = self.pool.get('account.invoice.line')
invoice_id = super(stock_picking, self)._create_invoice_from_picking(cr, uid, picking, vals, context=context)
- if picking.group_id:
- sale_ids = sale_obj.search(cr, uid, [('procurement_group_id', '=', picking.group_id.id)], context=context)
- if sale_ids:
- sale_line_ids = sale_line_obj.search(cr, uid, [('order_id', 'in', sale_ids), ('product_id.type', '=', 'service'), ('invoiced', '=', False)], context=context)
- if sale_line_ids:
- created_lines = sale_line_obj.invoice_line_create(cr, uid, sale_line_ids, context=context)
- invoice_line_obj.write(cr, uid, created_lines, {'invoice_id': invoice_id}, context=context)
return invoice_id
def _get_invoice_vals(self, cr, uid, key, inv_type, journal_id, move, context=None):
diff --git a/addons/stock/stock.py b/addons/stock/stock.py
index 48c1eaec9bb..fa004c232d0 100644
--- a/addons/stock/stock.py
+++ b/addons/stock/stock.py
@@ -2530,6 +2530,7 @@ class stock_move(osv.osv):
'split_from': move.id,
'procurement_id': move.procurement_id.id,
'move_dest_id': move.move_dest_id.id,
+ 'origin_returned_move_id': move.origin_returned_move_id.id,
}
if context.get('source_location_id'):
defaults['location_id'] = context['source_location_id']
diff --git a/addons/stock/wizard/stock_return_picking.py b/addons/stock/wizard/stock_return_picking.py
index c72a4ccce86..24440192dde 100644
--- a/addons/stock/wizard/stock_return_picking.py
+++ b/addons/stock/wizard/stock_return_picking.py
@@ -133,6 +133,12 @@ class stock_return_picking(osv.osv_memory):
raise UserError(_("You have manually created product lines, please delete them to proceed"))
new_qty = data_get.quantity
if new_qty:
+ # The return of a return should be linked with the original's destination move if it was not cancelled
+ if move.origin_returned_move_id.move_dest_id.id and move.origin_returned_move_id.move_dest_id.state != 'cancel':
+ move_dest_id = move.origin_returned_move_id.move_dest_id.id
+ else:
+ move_dest_id = False
+
returned_lines += 1
move_obj.copy(cr, uid, move.id, {
'product_id': data_get.product_id.id,
@@ -145,6 +151,7 @@ class stock_return_picking(osv.osv_memory):
'origin_returned_move_id': move.id,
'procure_method': 'make_to_stock',
'restrict_lot_id': data_get.lot_id.id,
+ 'move_dest_id': move_dest_id,
})
if not returned_lines:
diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js
index bed0cefbd9e..ba7a689a8a4 100644
--- a/addons/web/static/src/js/view_form.js
+++ b/addons/web/static/src/js/view_form.js
@@ -2501,7 +2501,9 @@ instance.web.form.Priority = instance.web.form.FieldChar.extend({
this.record_id = this.view.datarecord.id;
this.priorities = this.prepare_priority();
this.$el.html(QWeb.render("Priority", {'widget': this}));
- this.$el.find('li').on('click', this.set_priority.bind(this));
+ if (!this.get('readonly')){
+ this.$el.find('li').on('click', this.set_priority.bind(this));
+ }
},
/* setting the value: in view mode, perform an asynchronous call and reload
the form view; in edit mode, use set_value to save the new value that will
diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml
index ab242df110b..bbf83d02b0e 100644
--- a/addons/web/static/src/xml/base.xml
+++ b/addons/web/static/src/xml/base.xml
@@ -1118,9 +1118,10 @@