diff --git a/addons/account_voucher/account_voucher.py b/addons/account_voucher/account_voucher.py index b0bca634bd2..c8be5c0925c 100644 --- a/addons/account_voucher/account_voucher.py +++ b/addons/account_voucher/account_voucher.py @@ -878,7 +878,7 @@ class account_voucher(osv.osv): currency_id = journal.currency.id else: currency_id = journal.company_id.currency_id.id - vals['value'].update({'currency_id': currency_id}) + vals['value'].update({'currency_id': currency_id, 'payment_rate_currency_id': currency_id}) #in case we want to register the payment directly from an invoice, it's confusing to allow to switch the journal #without seeing that the amount is expressed in the journal currency, and not in the invoice currency. So to avoid #this common mistake, we simply reset the amount to 0 if the currency is not the invoice currency. diff --git a/addons/account_voucher/voucher_sales_purchase_view.xml b/addons/account_voucher/voucher_sales_purchase_view.xml index f8c2d65f63b..3686cf2aab0 100644 --- a/addons/account_voucher/voucher_sales_purchase_view.xml +++ b/addons/account_voucher/voucher_sales_purchase_view.xml @@ -222,6 +222,7 @@ + diff --git a/addons/auth_ldap/users_ldap.py b/addons/auth_ldap/users_ldap.py index 92d723af3d9..876337a7b54 100644 --- a/addons/auth_ldap/users_ldap.py +++ b/addons/auth_ldap/users_ldap.py @@ -249,7 +249,7 @@ class users(osv.osv): return user_id registry = RegistryManager.get(db) with registry.cursor() as cr: - cr.execute("SELECT id, active FROM res_users WHERE lower(login)=%s", (login,)) + cr.execute("SELECT id FROM res_users WHERE lower(login)=%s", (login,)) res = cr.fetchone() if res: return False diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py index 30b3d750978..86d6333d7b1 100644 --- a/addons/crm/crm_lead.py +++ b/addons/crm/crm_lead.py @@ -160,6 +160,10 @@ class crm_lead(format_address, osv.osv): return result, fold def fields_view_get(self, cr, user, view_id=None, view_type='form', context=None, toolbar=False, submenu=False): + if context and context.get('opportunity_id'): + action = self._get_formview_action(cr, user, context['opportunity_id'], context=context) + if action.get('views') and any(view_id for view_id in action['views'] if view_id[1] == view_type): + view_id = next(view_id[0] for view_id in action['views'] if view_id[1] == view_type) res = super(crm_lead, self).fields_view_get(cr, user, view_id, view_type, context, toolbar=toolbar, submenu=submenu) if view_type == 'form': res['arch'] = self.fields_view_get_address(cr, user, res['arch'], context=context) @@ -586,6 +590,13 @@ class crm_lead(format_address, osv.osv): attachment.write(values) return True + def _merge_opportunity_phonecalls(self, cr, uid, opportunity_id, opportunities, context=None): + phonecall_obj = self.pool['crm.phonecall'] + for opportunity in opportunities: + for phonecall_id in phonecall_obj.search(cr, uid, [('opportunity_id', '=', opportunity.id)], context=context): + phonecall_obj.write(cr, uid, phonecall_id, {'opportunity_id': opportunity_id}, context=context) + return True + def get_duplicated_leads(self, cr, uid, ids, partner_id, include_lost=False, context=None): """ Search for opportunities that have the same partner and that arent done or cancelled @@ -616,6 +627,7 @@ class crm_lead(format_address, osv.osv): self._merge_notify(cr, uid, highest, opportunities, context=context) self._merge_opportunity_history(cr, uid, highest, opportunities, context=context) self._merge_opportunity_attachments(cr, uid, highest, opportunities, context=context) + self._merge_opportunity_phonecalls(cr, uid, highest, opportunities, context=context) def merge_opportunity(self, cr, uid, ids, user_id=False, section_id=False, context=None): """ diff --git a/addons/crm/crm_phonecall_view.xml b/addons/crm/crm_phonecall_view.xml index 47825a5d30c..619fc7cadd6 100644 --- a/addons/crm/crm_phonecall_view.xml +++ b/addons/crm/crm_phonecall_view.xml @@ -104,7 +104,7 @@ domain="[('object_id.model', '=', 'crm.phonecall')]"/> - + diff --git a/addons/payment/views/payment_acquirer.xml b/addons/payment/views/payment_acquirer.xml index 6840aa03274..8ff6ed57ace 100644 --- a/addons/payment/views/payment_acquirer.xml +++ b/addons/payment/views/payment_acquirer.xml @@ -108,7 +108,7 @@
- + diff --git a/addons/portal_sale/portal_sale_view.xml b/addons/portal_sale/portal_sale_view.xml index 2c5b05b7abf..1dd8db4e51c 100644 --- a/addons/portal_sale/portal_sale_view.xml +++ b/addons/portal_sale/portal_sale_view.xml @@ -74,7 +74,7 @@ account.invoice tree,form [('type','in',['out_invoice','out_refund'])] - {'type':['out_invoice','out_refund'], 'journal_type': 'sale'} + {} We haven't sent you any invoice. diff --git a/addons/product/_common.py b/addons/product/_common.py index c05dcee66a2..f44f6b11a4c 100644 --- a/addons/product/_common.py +++ b/addons/product/_common.py @@ -20,9 +20,6 @@ ############################################################################## from openerp import tools -import math - - def rounding(f, r): # TODO for trunk: log deprecation warning # _logger.warning("Deprecated rounding method, please use tools.float_round to round floats.") @@ -32,4 +29,4 @@ def rounding(f, r): def ceiling(f, r): if not r: return f - return math.ceil(f / r) * r + return tools.float_round(f, precision_rounding=r, rounding_method='UP') diff --git a/addons/product/product.py b/addons/product/product.py index 820cc231c90..763d139e7c5 100644 --- a/addons/product/product.py +++ b/addons/product/product.py @@ -32,6 +32,7 @@ from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT import psycopg2 import openerp.addons.decimal_precision as dp +from openerp.tools.float_utils import float_round def ean_checksum(eancode): """returns the checksum of an ean string of length 13, returns -1 if the string has the wrong length""" @@ -178,7 +179,10 @@ class product_uom(osv.osv): raise osv.except_osv(_('Error!'), _('Conversion from Product UoM %s to Default UoM %s is not possible as they both belong to different Category!.') % (from_unit.name,to_unit.name,)) else: return qty - amount = qty / from_unit.factor + # First round to the precision of the original unit, so that + # float representation errors do not bias the following ceil() + # e.g. with 1 / (1/12) we could get 12.0000048, ceiling to 13! + amount = float_round(qty/from_unit.factor, precision_rounding=from_unit.rounding) if to_unit: amount = amount * to_unit.factor if round: diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 5ab75cd0607..ee15592c924 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -2903,7 +2903,7 @@ instance.web.form.FieldTextHtml = instance.web.form.AbstractField.extend(instanc if (! this.get("effective_readonly")) { self._updating_editor = false; this.$textarea = this.$el.find('textarea'); - var width = ((this.node.attrs || {}).editor_width || 'auto'); + var width = ((this.node.attrs || {}).editor_width || 'calc(100% - 4px)'); var height = ((this.node.attrs || {}).editor_height || 250); this.$textarea.cleditor({ width: width, // width not including margins, borders or padding diff --git a/addons/web_calendar/static/src/js/web_calendar.js b/addons/web_calendar/static/src/js/web_calendar.js index acaf3ba5db8..b4aefc610a4 100644 --- a/addons/web_calendar/static/src/js/web_calendar.js +++ b/addons/web_calendar/static/src/js/web_calendar.js @@ -664,6 +664,13 @@ openerp.web_calendar = function(instance) { domain: self.get_range_domain(domain, start, end), context: context, }).done(function(events) { + if (self.dataset.index === null) { + if (events.length) { + self.dataset.index = 0; + } + } else if (self.dataset.index >= events.length) { + self.dataset.index = events.length ? 0 : null; + } if (self.event_source !== current_event_source) { console.log("Consecutive ``do_search`` called. Cancelling."); diff --git a/addons/web_graph/static/src/js/graph_view.js b/addons/web_graph/static/src/js/graph_view.js index 8ae99849bab..646a730b51b 100644 --- a/addons/web_graph/static/src/js/graph_view.js +++ b/addons/web_graph/static/src/js/graph_view.js @@ -85,6 +85,8 @@ instance.web_graph.GraphView = instance.web.View.extend({ measures = groupbys.measures; if (!this.graph_widget) { + this.widget_config.context = _.clone(context); + this.widget_config.context.group_by_no_leaf = true; if (group_by.length) { this.widget_config.row_groupby = group_by; } diff --git a/addons/web_graph/static/src/js/pivot_table.js b/addons/web_graph/static/src/js/pivot_table.js index b66bc41e98c..a46203faff5 100644 --- a/addons/web_graph/static/src/js/pivot_table.js +++ b/addons/web_graph/static/src/js/pivot_table.js @@ -13,6 +13,7 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ init: function (model, domain, fields, options) { this.cells = []; this.domain = domain; + this.context = options.context; this.no_data = true; this.updating = false; this.model = model; @@ -412,6 +413,7 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ var self = this; return this.model.query(_.without(fields, '__count')) .filter(domain) + .context(this.context) .lazy(false) .group_by(groupbys) .then(function (groups) { diff --git a/addons/website_blog/security/website_blog.xml b/addons/website_blog/security/website_blog.xml index 97efcb82eab..76653607faf 100644 --- a/addons/website_blog/security/website_blog.xml +++ b/addons/website_blog/security/website_blog.xml @@ -6,7 +6,7 @@ Blog Post: public: published only [('website_published', '=', True)] - + diff --git a/openerp/addons/base/ir/ir_cron.py b/openerp/addons/base/ir/ir_cron.py index b16ac822f51..eaeecdbeb35 100644 --- a/openerp/addons/base/ir/ir_cron.py +++ b/openerp/addons/base/ir/ir_cron.py @@ -85,7 +85,6 @@ class ir_cron(osv.osv): 'interval_type' : 'months', 'numbercall' : 1, 'active' : 1, - 'doall' : 1 } def _check_args(self, cr, uid, ids, context=None): diff --git a/openerp/addons/base/res/res_users.py b/openerp/addons/base/res/res_users.py index eeca380b96d..e3d65f21073 100644 --- a/openerp/addons/base/res/res_users.py +++ b/openerp/addons/base/res/res_users.py @@ -373,6 +373,12 @@ class res_users(osv.osv): default['login'] = _("%s (copy)") % user2copy['login'] return super(res_users, self).copy(cr, uid, id, default, context) + def copy_data(self, cr, uid, ids, default=None, context=None): + if default is None: + default = {} + default.update({'login_date': False}) + return super(res_users, self).copy_data(cr, uid, ids, default, context=context) + @tools.ormcache(skiparg=2) def context_get(self, cr, uid, context=None): user = self.browse(cr, SUPERUSER_ID, uid, context) diff --git a/openerp/addons/base/tests/base_test.yml b/openerp/addons/base/tests/base_test.yml index 5590e735135..6b3768e8e08 100644 --- a/openerp/addons/base/tests/base_test.yml +++ b/openerp/addons/base/tests/base_test.yml @@ -203,8 +203,8 @@ - !python {model: res.currency}: | from openerp.tools import float_compare, float_is_zero, float_round, float_repr - def try_round(amount, expected, precision_digits=3, float_round=float_round, float_repr=float_repr): - result = float_repr(float_round(amount, precision_digits=precision_digits), + def try_round(amount, expected, precision_digits=3, float_round=float_round, float_repr=float_repr, rounding_method='HALF-UP'): + result = float_repr(float_round(amount, precision_digits=precision_digits, rounding_method=rounding_method), precision_digits=precision_digits) assert result == expected, 'Rounding error: got %s, expected %s' % (result, expected) try_round(2.6745, '2.675') @@ -218,6 +218,15 @@ try_round(457.4554, '457.455') try_round(-457.4554, '-457.455') + # Try some rounding value with rounding method UP instead of HALF-UP + # We use 8.175 because when normalizing 8.175 with precision_digits=3 it gives + # us 8175,0000000001234 as value, and if not handle correctly the rounding UP + # value will be incorrect (should be 8,175 and not 8,176) + try_round(8.175, '8.175', rounding_method='UP') + try_round(8.1751, '8.176', rounding_method='UP') + try_round(-8.175, '-8.175', rounding_method='UP') + try_round(-8.1751, '-8.175', rounding_method='UP') + # Extended float range test, inspired by Cloves Almeida's test on bug #882036. fractions = [.0, .015, .01499, .675, .67499, .4555, .4555, .45555] expecteds = ['.00', '.02', '.01', '.68', '.67', '.46', '.456', '.4556'] diff --git a/openerp/tools/float_utils.py b/openerp/tools/float_utils.py index 5c934114e3c..79f5a34c7f6 100644 --- a/openerp/tools/float_utils.py +++ b/openerp/tools/float_utils.py @@ -29,10 +29,11 @@ def _float_check_precision(precision_digits=None, precision_rounding=None): return 10 ** -precision_digits return precision_rounding -def float_round(value, precision_digits=None, precision_rounding=None): - """Return ``value`` rounded to ``precision_digits`` - decimal digits, minimizing IEEE-754 floating point representation - errors, and applying HALF-UP (away from zero) tie-breaking rule. +def float_round(value, precision_digits=None, precision_rounding=None, rounding_method='HALF-UP'): + """Return ``value`` rounded to ``precision_digits`` decimal digits, + minimizing IEEE-754 floating point representation errors, and applying + the tie-breaking rule selected with ``rounding_method``, by default + HALF-UP (away from zero). Precision must be given by ``precision_digits`` or ``precision_rounding``, not both! @@ -41,6 +42,9 @@ def float_round(value, precision_digits=None, precision_rounding=None): :param float precision_rounding: decimal number representing the minimum non-zero value at the desired precision (for example, 0.01 for a 2-digit precision). + :param rounding_method: the rounding method used: 'HALF-UP' or 'UP', the first + one rounding up to the closest number with the rule that number>=0.5 is + rounded up to 1, and the latest one always rounding up. :return: rounded float """ rounding_factor = _float_check_precision(precision_digits=precision_digits, @@ -52,7 +56,7 @@ def float_round(value, precision_digits=None, precision_rounding=None): # we normalize the value before rounding it as an integer, and de-normalize # after rounding: e.g. float_round(1.3, precision_rounding=.5) == 1.5 - # TIE-BREAKING: HALF-UP + # TIE-BREAKING: HALF-UP (for normal rounding) # We want to apply HALF-UP tie-breaking rules, i.e. 0.5 rounds away from 0. # Due to IEE754 float/double representation limits, the approximation of the # real value may be slightly below the tie limit, resulting in an error of @@ -66,8 +70,19 @@ def float_round(value, precision_digits=None, precision_rounding=None): normalized_value = value / rounding_factor # normalize epsilon_magnitude = math.log(abs(normalized_value), 2) epsilon = 2**(epsilon_magnitude-53) - normalized_value += cmp(normalized_value,0) * epsilon - rounded_value = round(normalized_value) # round to integer + if rounding_method == 'HALF-UP': + normalized_value += cmp(normalized_value,0) * epsilon + rounded_value = round(normalized_value) # round to integer + + # TIE-BREAKING: UP (for ceiling operations) + # When rounding the value up, we instead subtract the epsilon value + # as the the approximation of the real value may be slightly *above* the + # tie limit, this would result in incorrectly rounding up to the next number + + elif rounding_method == 'UP': + normalized_value -= cmp(normalized_value,0) * epsilon + rounded_value = math.ceil(normalized_value) # ceil to integer + result = rounded_value * rounding_factor # de-normalize return result