diff --git a/addons/account_analytic_default/security/ir.model.access.csv b/addons/account_analytic_default/security/ir.model.access.csv
index cdfebbbb156..dc2ecfdb076 100644
--- a/addons/account_analytic_default/security/ir.model.access.csv
+++ b/addons/account_analytic_default/security/ir.model.access.csv
@@ -1,4 +1,5 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_account_analytic_default,account.analytic.default,model_account_analytic_default,account.group_account_user,1,0,0,0
+access_account_analytic_default_analytic,account.analytic.default analytic,model_account_analytic_default,analytic.group_analytic_accounting,1,0,0,0
access_account_analytic_default_invoice,account.analytic.default invoice,model_account_analytic_default,account.group_account_invoice,1,1,1,1
access_account_analytic_default_salesman,account.analytic.default.salesman,model_account_analytic_default,base.group_sale_salesman,1,1,1,1
diff --git a/addons/account_check_writing/report/check_print.py b/addons/account_check_writing/report/check_print.py
index e67d334ae34..f5c304a90b7 100644
--- a/addons/account_check_writing/report/check_print.py
+++ b/addons/account_check_writing/report/check_print.py
@@ -36,7 +36,7 @@ class report_print_check(report_sxw.rml_parse):
})
def fill_stars(self, amount):
- if len(amount) < 100:
+ if amount and len(amount) < 100:
stars = 100 - len(amount)
return ' '.join([amount,'*'*stars])
diff --git a/addons/account_voucher/account_voucher.py b/addons/account_voucher/account_voucher.py
index 32baf5b302a..344bf902d11 100644
--- a/addons/account_voucher/account_voucher.py
+++ b/addons/account_voucher/account_voucher.py
@@ -1290,7 +1290,7 @@ class account_voucher(osv.osv):
'move_id': move_id,
'partner_id': line.voucher_id.partner_id.id,
'currency_id': line.move_line_id.currency_id.id,
- 'amount_currency': -1 * foreign_currency_diff,
+ 'amount_currency': (-1 if line.type == 'cr' else 1) * foreign_currency_diff,
'quantity': 1,
'credit': 0.0,
'debit': 0.0,
diff --git a/addons/base_import_module/models/ir_module.py b/addons/base_import_module/models/ir_module.py
index cbaaa77bd38..05ccdc384d1 100644
--- a/addons/base_import_module/models/ir_module.py
+++ b/addons/base_import_module/models/ir_module.py
@@ -102,6 +102,7 @@ class view(osv.osv):
self.import_module(cr, uid, mod_name, path, force=force, context=context)
success.append(mod_name)
except Exception, e:
+ _logger.exception('Error while importing module')
errors[mod_name] = exception_to_unicode(e)
r = ["Successfully imported module '%s'" % mod for mod in success]
for mod, error in errors.items():
diff --git a/addons/hr_contract/security/ir.model.access.csv b/addons/hr_contract/security/ir.model.access.csv
index 5e35e147230..820935111f0 100644
--- a/addons/hr_contract/security/ir.model.access.csv
+++ b/addons/hr_contract/security/ir.model.access.csv
@@ -1,5 +1,6 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_hr_resource_manager,hr.employee.resource.manager,resource.model_resource_resource,base.group_hr_manager,1,1,1,1
access_hr_resource_calendar_user,hr.employee.resource.calendar.user,resource.model_resource_calendar,base.group_hr_user,1,1,1,1
+access_hr_resource_calendar_attendance_user,hr.employee.resource.calendar.attendance.user,resource.model_resource_calendar_attendance,base.group_hr_user,1,1,1,1
access_hr_contract_type_manager,hr.contract.type.manager,model_hr_contract_type,base.group_hr_manager,1,1,1,1
access_hr_contract_manager,hr.contract.manager,model_hr_contract,base.group_hr_manager,1,1,1,1
diff --git a/addons/hr_timesheet_sheet/hr_timesheet_sheet.py b/addons/hr_timesheet_sheet/hr_timesheet_sheet.py
index 6be3ba3b885..90265a055fd 100644
--- a/addons/hr_timesheet_sheet/hr_timesheet_sheet.py
+++ b/addons/hr_timesheet_sheet/hr_timesheet_sheet.py
@@ -48,18 +48,24 @@ class hr_timesheet_sheet(osv.osv):
""" Compute the attendances, analytic lines timesheets and differences between them
for all the days of a timesheet and the current day
"""
+ res = dict.fromkeys(ids, {
+ 'total_attendance': 0.0,
+ 'total_timesheet': 0.0,
+ 'total_difference': 0.0,
+ })
+
+ cr.execute("""
+ SELECT sheet_id as id,
+ sum(total_attendance) as total_attendance,
+ sum(total_timesheet) as total_timesheet,
+ sum(total_difference) as total_difference
+ FROM hr_timesheet_sheet_sheet_day
+ WHERE sheet_id IN %s
+ GROUP BY sheet_id
+ """, (tuple(ids),))
+
+ res.update(dict((x.pop('id'), x) for x in cr.dictfetchall()))
- res = {}
- for sheet in self.browse(cr, uid, ids, context=context or {}):
- res.setdefault(sheet.id, {
- 'total_attendance': 0.0,
- 'total_timesheet': 0.0,
- 'total_difference': 0.0,
- })
- for period in sheet.period_ids:
- res[sheet.id]['total_attendance'] += period.total_attendance
- res[sheet.id]['total_timesheet'] += period.total_timesheet
- res[sheet.id]['total_difference'] += period.total_attendance - period.total_timesheet
return res
def check_employee_attendance_state(self, cr, uid, sheet_id, context=None):
diff --git a/addons/mrp/report/price.py b/addons/mrp/report/price.py
index 87387280c95..1b0f7f589f2 100644
--- a/addons/mrp/report/price.py
+++ b/addons/mrp/report/price.py
@@ -42,6 +42,8 @@ class report_custom(report_rml):
rml_obj.localcontext.update({'lang':context.get('lang',False)})
company_currency = user_pool.browse(cr, uid, uid).company_id.currency_id
company_currency_symbol = company_currency.symbol or company_currency.name
+ product_uom_digits = rml_obj.get_digits(dp='Product Unit of Measure')
+ purchase_price_digits = rml_obj.get_digits(dp='Product Price')
def process_bom(bom, currency_id, factor=1):
xml = '
You can access this document and pay online via our Customer Portal: @@ -128,7 +128,7 @@ % endif
- <% set signup_url = object.get_signup_url() %> + % set signup_url = object.get_signup_url() % if signup_url:
You can access the invoice document and pay online via our Customer Portal:
diff --git a/addons/product/product.py b/addons/product/product.py
index 874eb872a79..e68df7014a3 100644
--- a/addons/product/product.py
+++ b/addons/product/product.py
@@ -424,6 +424,14 @@ class product_attribute_line(osv.osv):
'value_ids': fields.many2many('product.attribute.value', id1='line_id', id2='val_id', string='Product Attribute Value(s)'),
}
+ def _check_valid_attribute(self, cr, uid, ids, context=None):
+ obj_pal = self.browse(cr, uid, ids[0], context=context)
+ return obj_pal.value_ids <= obj_pal.attribute_id.value_ids
+
+ _constraints = [
+ (_check_valid_attribute, 'Error ! You cannot use this attribute with the following value.', ['attribute_id'])
+ ]
+
#----------------------------------------------------------
# Products
diff --git a/addons/sale_service/models/sale_service.py b/addons/sale_service/models/sale_service.py
index 74540d43547..02d86af6a81 100644
--- a/addons/sale_service/models/sale_service.py
+++ b/addons/sale_service/models/sale_service.py
@@ -19,6 +19,7 @@
#
##############################################################################
+from openerp import SUPERUSER_ID
from openerp.osv import fields, osv
from openerp.tools.translate import _
@@ -127,7 +128,7 @@ class project_task(osv.osv):
proc_obj = self.pool.get("procurement.order")
for task in self.browse(cr, uid, ids, context=context):
if task.procurement_id:
- proc_obj.check(cr, uid, [task.procurement_id.id], context=context)
+ proc_obj.check(cr, SUPERUSER_ID, [task.procurement_id.id], context=context)
def write(self, cr, uid, ids, values, context=None):
""" When closing tasks, validate subflows. """
diff --git a/addons/sale_stock/sale_stock.py b/addons/sale_stock/sale_stock.py
index 872ebce9a9d..8f2c32a2cb5 100644
--- a/addons/sale_stock/sale_stock.py
+++ b/addons/sale_stock/sale_stock.py
@@ -488,7 +488,7 @@ class stock_picking(osv.osv):
def _get_invoice_vals(self, cr, uid, key, inv_type, journal_id, move, context=None):
inv_vals = super(stock_picking, self)._get_invoice_vals(cr, uid, key, inv_type, journal_id, move, context=context)
sale = move.picking_id.sale_id
- if sale:
+ if sale and inv_type in ('out_invoice', 'out_refund'):
inv_vals.update({
'fiscal_position': sale.fiscal_position.id,
'payment_term': sale.payment_term.id,
diff --git a/addons/stock/stock.py b/addons/stock/stock.py
index 4aafa8abfe6..701494ac3ae 100644
--- a/addons/stock/stock.py
+++ b/addons/stock/stock.py
@@ -1400,7 +1400,8 @@ class stock_picking(osv.osv):
This can be used to provide a button that rereserves taking into account the existing pack operations
"""
for pick in self.browse(cr, uid, ids, context=context):
- self.rereserve_quants(cr, uid, pick, move_ids = [x.id for x in pick.move_lines], context=context)
+ self.rereserve_quants(cr, uid, pick, move_ids = [x.id for x in pick.move_lines
+ if x.state not in ('done', 'cancel')], context=context)
def rereserve_quants(self, cr, uid, picking, move_ids=[], context=None):
""" Unreserve quants then try to reassign quants."""
diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js
index c00cedc620b..b15780d252a 100644
--- a/addons/web/static/src/js/data.js
+++ b/addons/web/static/src/js/data.js
@@ -1047,8 +1047,11 @@ instance.web.BufferedDataSet = instance.web.DataSetStatic.extend({
return this._super(id, signal);
},
alter_ids: function(n_ids) {
+ var dirty = !_.isEqual(this.ids, n_ids);
this._super(n_ids);
- this.trigger("dataset_changed", n_ids);
+ if(dirty) {
+ this.trigger("dataset_changed", n_ids);
+ }
},
});
instance.web.BufferedDataSet.virtual_id_regex = /^one2many_v_id_.*$/;
diff --git a/addons/web/static/src/js/formats.js b/addons/web/static/src/js/formats.js
index b716f0f0ef3..3461134d725 100644
--- a/addons/web/static/src/js/formats.js
+++ b/addons/web/static/src/js/formats.js
@@ -312,7 +312,16 @@ instance.web.round_precision = function(value, precision){
var epsilon_magnitude = Math.log(Math.abs(normalized_value))/Math.log(2);
var epsilon = Math.pow(2, epsilon_magnitude - 53);
normalized_value += normalized_value >= 0 ? epsilon : -epsilon;
- var rounded_value = Math.round(normalized_value);
+
+ /**
+ * Javascript performs strictly the round half up method, which is asymmetric. However, in
+ * Python, the method is symmetric. For example:
+ * - In JS, Math.round(-0.5) is equal to -0.
+ * - In Python, round(-0.5) is equal to -1.
+ * We want to keep the Python behavior for consistency.
+ */
+ var sign = normalized_value < 0 ? -1.0 : 1.0;
+ var rounded_value = sign * Math.round(Math.abs(normalized_value));
return rounded_value * precision;
};
diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js
index 929db311e30..04f6511a1de 100644
--- a/addons/web/static/src/js/view_form.js
+++ b/addons/web/static/src/js/view_form.js
@@ -4413,10 +4413,6 @@ instance.web.form.One2ManyListView = instance.web.ListView.extend({
}));
this.on('edit:after', this, this.proxy('_after_edit'));
this.on('save:before cancel:before', this, this.proxy('_before_unedit'));
-
- this.records
- .bind('add', this.proxy("changed_records"))
- .bind('remove', this.proxy("changed_records"));
this.on('save:after', this, this.proxy("changed_records"));
},
start: function () {
diff --git a/addons/web_calendar/static/src/js/web_calendar.js b/addons/web_calendar/static/src/js/web_calendar.js
index 4da7e37a2fe..dd91ca775ac 100644
--- a/addons/web_calendar/static/src/js/web_calendar.js
+++ b/addons/web_calendar/static/src/js/web_calendar.js
@@ -532,6 +532,9 @@ openerp.web_calendar = function(instance) {
throw new Error("Incomplete data received from dataset for record " + evt.id);
}
}
+ else if (_.contains(["date", "datetime"], self.fields[fieldname].type)) {
+ temp_ret[fieldname] = instance.web.format_value(value, self.fields[fieldname]);
+ }
else {
temp_ret[fieldname] = value;
}
diff --git a/addons/website/models/ir_http.py b/addons/website/models/ir_http.py
index 11db1070ea2..9af3f55df3c 100644
--- a/addons/website/models/ir_http.py
+++ b/addons/website/models/ir_http.py
@@ -274,7 +274,8 @@ class ir_http(orm.AbstractModel):
logger.error("500 Internal Server Error:\n\n%s", values['traceback'])
if 'qweb_exception' in values:
view = request.registry.get("ir.ui.view")
- views = view._views_get(request.cr, request.uid, exception.qweb['template'], request.context)
+ views = view._views_get(request.cr, request.uid, exception.qweb['template'],
+ context=request.context)
to_reset = [v for v in views if v.model_data_id.noupdate is True and not v.page]
values['views'] = to_reset
elif code == 403:
diff --git a/addons/website_mail_group/views/website_mail_group.xml b/addons/website_mail_group/views/website_mail_group.xml
index 6617e3d7895..28ab10b4ea9 100644
--- a/addons/website_mail_group/views/website_mail_group.xml
+++ b/addons/website_mail_group/views/website_mail_group.xml
@@ -190,7 +190,7 @@
}'/>
diff --git a/addons/website_quote/data/website_quotation_data.xml b/addons/website_quote/data/website_quotation_data.xml index 56a8810e76b..9466aebee95 100644 --- a/addons/website_quote/data/website_quotation_data.xml +++ b/addons/website_quote/data/website_quotation_data.xml @@ -201,7 +201,7 @@ % endif
- <% set signup_url = object.get_signup_url() %> + % set signup_url = object.get_signup_url() % if signup_url and object.amount_total > 0 :
You can access this document and pay online via our Customer Portal:
diff --git a/addons/website_sale/static/src/js/website_sale.js b/addons/website_sale/static/src/js/website_sale.js
index 03b913fff1c..67c17e86fec 100644
--- a/addons/website_sale/static/src/js/website_sale.js
+++ b/addons/website_sale/static/src/js/website_sale.js
@@ -1,4 +1,12 @@
$(document).ready(function () {
+
+function update_product_image(event_source, product_id) {
+ var $img = $(event_source).closest('tr.js_product, .oe_website_sale').find('span[data-oe-model^="product."][data-oe-type="image"] img:first, img.product_detail_img');
+ $img.attr("src", "/website/image/product.product/" + product_id + "/image");
+ $img.parent().attr('data-oe-model', 'product.product').attr('data-oe-id', product_id)
+ .data('oe-model', 'product.product').data('oe-id', product_id);
+}
+
$('.oe_website_sale').each(function () {
var oe_website_sale = this;
@@ -157,9 +165,7 @@ $('.oe_website_sale').each(function () {
var $parent = $(this).closest('.js_product');
$parent.find(".oe_default_price:first .oe_currency_value").html( price_to_str(+$(this).data('lst_price')) );
$parent.find(".oe_price:first .oe_currency_value").html(price_to_str(+$(this).data('price')) );
-
- var $img = $(this).closest('tr.js_product, .oe_website_sale').find('span[data-oe-model^="product."][data-oe-type="image"] img:first, img.product_detail_img');
- $img.attr("src", "/website/image/product.product/" + $(this).val() + "/image");
+ update_product_image(this, +$(this).val());
});
$(oe_website_sale).on('change', 'input.js_variant_change, select.js_variant_change, ul[data-attribute_value_ids]', function (ev) {
@@ -195,10 +201,7 @@ $('.oe_website_sale').each(function () {
}
if (product_id) {
- var $img = $(this).closest('tr.js_product, .oe_website_sale').find('span[data-oe-model^="product."][data-oe-type="image"] img:first, img.product_detail_img');
- $img.attr("src", "/website/image/product.product/" + product_id + "/image");
- $img.parent().attr('data-oe-model', 'product.product').attr('data-oe-id', product_id)
- .data('oe-model', 'product.product').data('oe-id', product_id);
+ update_product_image(this, product_id);
}
$parent.find("input.js_variant_change:radio, select.js_variant_change").each(function () {
diff --git a/addons/website_sale_options/views/templates.xml b/addons/website_sale_options/views/templates.xml
index 411ce05942b..f3e8b7f7a1a 100644
--- a/addons/website_sale_options/views/templates.xml
+++ b/addons/website_sale_options/views/templates.xml
@@ -141,5 +141,14 @@
+
+