From 2b2ec0743599260d1d3215dd273a6665ab5871d3 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Wed, 29 Oct 2014 19:49:26 +0100 Subject: [PATCH 01/16] [IMP] .gitignore maintenance migration scripts --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 7828a605ef0..68382f297f6 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,9 @@ _build/ status # odoo filestore openerp/filestore +# maintenance migration scripts +openerp/addons/base/maintenance + # generated for windows installer? install/win32/*.bat install/win32/meta.py From 1661cf53e9b30dabaa5658906b68b3a1d25599b7 Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Thu, 23 Oct 2014 17:45:55 -0400 Subject: [PATCH 02/16] [FIX] base_action_rule: Make sure model exists before trying to wrap hooks In certain cases, before running an update unregistered models will try to register hooks. Trying to wrap create and write on these will cause AttributeError on model_obj which would be None Signed-off-by: Sandy Carter --- addons/base_action_rule/base_action_rule.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/base_action_rule/base_action_rule.py b/addons/base_action_rule/base_action_rule.py index 98d533b3b6d..398bf00286a 100644 --- a/addons/base_action_rule/base_action_rule.py +++ b/addons/base_action_rule/base_action_rule.py @@ -199,7 +199,7 @@ class base_action_rule(osv.osv): for action_rule in self.browse(cr, SUPERUSER_ID, ids): model = action_rule.model_id.model model_obj = self.pool.get(model) - if not hasattr(model_obj, 'base_action_ruled'): + if model_obj and not hasattr(model_obj, 'base_action_ruled'): model_obj.create = self._wrap_create(model_obj.create, model) model_obj.write = self._wrap_write(model_obj.write, model) model_obj.base_action_ruled = True From 6a95c9cf3e3f7acc534e9ef7440a30730db2033f Mon Sep 17 00:00:00 2001 From: Julien Legros Date: Thu, 30 Oct 2014 17:58:29 +0100 Subject: [PATCH 03/16] [FIX] project_issue: explicit store attribute for the progress function field This is a workaround for an ORM limitation. A stored function field is not updated when it should if the "source" field is also a stored function field --- addons/project_issue/project_issue.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/project_issue/project_issue.py b/addons/project_issue/project_issue.py index 20a61657e20..efb4e4eff2b 100644 --- a/addons/project_issue/project_issue.py +++ b/addons/project_issue/project_issue.py @@ -306,7 +306,7 @@ class project_issue(base_stage, osv.osv): 'progress': fields.function(_hours_get, string='Progress (%)', multi='hours', group_operator="avg", help="Computed as: Time Spent / Total Time.", store = { 'project.issue': (lambda self, cr, uid, ids, c={}: ids, ['task_id'], 10), - 'project.task': (_get_issue_task, ['progress'], 10), + 'project.task': (_get_issue_task, ['work_ids', 'remaining_hours', 'planned_hours', 'state', 'stage_id'], 10), 'project.task.work': (_get_issue_work, ['hours'], 10), }), } From aed71f396284e8e5e948baa28be8d5d706b1e030 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Fri, 31 Oct 2014 12:20:56 +0100 Subject: [PATCH 04/16] [IMP] stock: avoid errors with picking without quantity When a line is not present in the partial delivery wizard, computation variables are initialized with generic values (zero quantity, zero price,...). Instead of setting the uom to False, keep the quantity of the move. This makes a difference only when the quantity of the move is 0. That means that the move will be marked as complete and can be processed. This avoids trying to update the stock.move with a uom at False. opw 616844 --- addons/stock/stock.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 644dae4ddf9..3b6bb70e457 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -1248,7 +1248,7 @@ class stock_picking(osv.osv): partial_data = partial_datas.get('move%s'%(move.id), {}) product_qty = partial_data.get('product_qty',0.0) move_product_qty[move.id] = product_qty - product_uom = partial_data.get('product_uom',False) + product_uom = partial_data.get('product_uom', move.product_uom.id) product_price = partial_data.get('product_price',0.0) product_currency = partial_data.get('product_currency',False) prodlot_id = partial_data.get('prodlot_id') From 8af9fdfa0635f6a9f78320d59d5cfb7ff1b89df2 Mon Sep 17 00:00:00 2001 From: Mohammad Alhashash Date: Fri, 31 Oct 2014 14:47:18 +0200 Subject: [PATCH 05/16] [FIX] stock: more tolerant copy method Allow setting origin/backorder when copying new stock.picking Fixes #379, lp:1098557 --- addons/stock/stock.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 3b6bb70e457..16565871de3 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -721,8 +721,8 @@ class stock_picking(osv.osv): if ('name' not in default) or (picking_obj.name == '/'): seq_obj_name = 'stock.picking.' + picking_obj.type default['name'] = self.pool.get('ir.sequence').get(cr, uid, seq_obj_name) - default['origin'] = '' - default['backorder_id'] = False + default.setdefault('origin', False) + default.setdefault('backorder_id', False) if 'invoice_state' not in default and picking_obj.invoice_state == 'invoiced': default['invoice_state'] = '2binvoiced' res = super(stock_picking, self).copy(cr, uid, id, default, context) From df845940ed52040ef92b1b5759306c556fa38e66 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Fri, 31 Oct 2014 17:40:56 +0100 Subject: [PATCH 06/16] [FIX] web: on editable list save, valid all records opw-617036: In my current timesheet, if you add a a required field on the timesheet ids lines, and add data in the summary tab, it was possible to validate the timesheet lines while requried fields were missing. --- addons/web/static/src/js/view_form.js | 33 ++++++++++++--------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index d140a9adb62..40a895f6c90 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -3881,28 +3881,23 @@ instance.web.form.One2ManyListView = instance.web.ListView.extend({ this.o2m.trigger_on_change(); }, is_valid: function () { - var editor = this.editor; - var form = editor.form; - // If no edition is pending, the listview can not be invalid (?) - if (!editor.record) { - return true - } - // If the form has not been modified, the view can only be valid - // NB: is_dirty will also be set on defaults/onchanges/whatever? - // oe_form_dirty seems to only be set on actual user actions - if (!form.$el.is('.oe_form_dirty')) { + var self = this; + if (!this.editable()){ return true; } this.o2m._dirty_flag = true; - - // Otherwise validate internal form - return _(form.fields).chain() - .invoke(function () { - this._check_css_flags(); - return this.is_valid(); - }) - .all(_.identity) - .value(); + var r; + return _.every(this.records.records, function(record){ + r = record; + _.each(self.editor.form.fields, function(field){ + field.set_value(r.attributes[field.name]); + }); + return _.every(self.editor.form.fields, function(field){ + field.process_modifiers(); + field._check_css_flags(); + return field.is_valid(); + }); + }); }, do_add_record: function () { if (this.editable()) { From 37fe61412655e68cd64e6fe8d472c4e01170280d Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Mon, 3 Nov 2014 11:41:03 +0100 Subject: [PATCH 07/16] [IMP] account: remove duplicated field in view Partial backport of 5f06129. Fixes #2837 --- addons/account/account_view.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/addons/account/account_view.xml b/addons/account/account_view.xml index de51be0ddad..2716e39cd80 100644 --- a/addons/account/account_view.xml +++ b/addons/account/account_view.xml @@ -2268,7 +2268,6 @@ - From 8852ab03e7af0135eb9e3dda92a164300d49a823 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Mon, 3 Nov 2014 15:13:38 +0100 Subject: [PATCH 08/16] [FIX] payment_paypal: add company name in paypal item name So the company name is displayed in the paypal payment form --- addons/payment_paypal/models/paypal.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/payment_paypal/models/paypal.py b/addons/payment_paypal/models/paypal.py index bade2343fa9..73db2e7a9f0 100644 --- a/addons/payment_paypal/models/paypal.py +++ b/addons/payment_paypal/models/paypal.py @@ -107,7 +107,7 @@ class AcquirerPaypal(osv.Model): paypal_tx_values.update({ 'cmd': '_xclick', 'business': acquirer.paypal_email_account, - 'item_name': tx_values['reference'], + 'item_name': '%s: %s' % (acquirer.company_id.name, tx_values['reference']), 'item_number': tx_values['reference'], 'amount': tx_values['amount'], 'currency_code': tx_values['currency'] and tx_values['currency'].name or '', From aea9c968cd6d1e5e26d6a10c408989695006a05c Mon Sep 17 00:00:00 2001 From: Paramjit Singh Sahota Date: Tue, 4 Mar 2014 18:55:34 +0530 Subject: [PATCH 09/16] [FIX] web: backport of 2331b14 Update the cleditor lib from v1.3.0 to v1.4.4 fixing IE11 issue, opw 614826 --- .../static/lib/cleditor/jquery.cleditor.css | 2 +- .../static/lib/cleditor/jquery.cleditor.js | 232 ++++++++++-------- .../lib/cleditor/jquery.cleditor.min.js | 31 +-- 3 files changed, 138 insertions(+), 127 deletions(-) diff --git a/addons/web/static/lib/cleditor/jquery.cleditor.css b/addons/web/static/lib/cleditor/jquery.cleditor.css index 6ac490bcfc4..19669406947 100644 --- a/addons/web/static/lib/cleditor/jquery.cleditor.css +++ b/addons/web/static/lib/cleditor/jquery.cleditor.css @@ -6,7 +6,7 @@ .cleditorButton {float:left; width:24px; height:24px; margin:1px 0 1px 0; background: url('images/buttons.gif')} .cleditorDisabled {opacity:0.3; filter:alpha(opacity=30)} .cleditorDivider {float:left; width:1px; height:23px; margin:1px 0 1px 0; background:#CCC} -.cleditorPopup {border:solid 1px #999; background-color:white; position:absolute; font:10pt Arial,Verdana; cursor:default; z-index:10000} +.cleditorPopup {border:solid 1px #999; background-color:white; color:#333333; position:absolute; font:10pt Arial,Verdana; cursor:default; z-index:10000} .cleditorList div {padding:2px 4px 2px 4px} .cleditorList p, .cleditorList h1, diff --git a/addons/web/static/lib/cleditor/jquery.cleditor.js b/addons/web/static/lib/cleditor/jquery.cleditor.js index 3de9089443d..7852037de58 100644 --- a/addons/web/static/lib/cleditor/jquery.cleditor.js +++ b/addons/web/static/lib/cleditor/jquery.cleditor.js @@ -1,18 +1,13 @@ -/** - @preserve CLEditor WYSIWYG HTML Editor v1.3.0 - http://premiumsoftware.net/cleditor +/*! + CLEditor WYSIWYG HTML Editor v1.4.4 + http://premiumsoftware.net/CLEditor requires jQuery v1.4.2 or later Copyright 2010, Chris Landowski, Premium Software, LLC Dual licensed under the MIT or GPL Version 2 licenses. */ -// ==ClosureCompiler== -// @compilation_level SIMPLE_OPTIMIZATIONS -// @output_file_name jquery.cleditor.min.js -// ==/ClosureCompiler== - -(function($) { +(function ($) { //============== // jQuery Plugin @@ -22,7 +17,7 @@ // Define the defaults used for all new cleditor instances defaultOptions: { - width: 500, // width not including margins, borders or padding + width: 'auto', // width not including margins, borders or padding height: 250, // height not including margins, borders or padding controls: // controls to add to the toolbar "bold italic underline strikethrough subscript superscript | font size " + @@ -46,18 +41,18 @@ [["Paragraph", "

"], ["Header 1", "

"], ["Header 2", "

"], ["Header 3", "

"], ["Header 4","

"], ["Header 5","

"], ["Header 6","
"]], - useCSS: false, // use CSS to style HTML when possible (not supported in ie) + useCSS: true, // use CSS to style HTML when possible (not supported in ie) docType: // Document type contained within the editor '', docCSSFile: // CSS file used to style the document contained within the editor "", bodyStyle: // style to assign to document body contained within the editor - "margin:4px; color:#4c4c4c; font-size:13px; font-family:\"Lucida Grande\",Helvetica,Verdana,Arial,sans-serif; cursor:text" + "margin:4px; font:10pt Arial,Verdana; cursor:text" }, // Define all usable toolbar buttons - the init string property is // expanded during initialization back into the buttons object and - // seperate object properties are created for each button. + // separate object properties are created for each button. // e.g. buttons.size.title = "Font Size" buttons: { // name,title,command,popupName (""=use name) @@ -109,7 +104,7 @@ // Loop through all matching textareas and create the editors this.each(function(idx, elem) { - if (elem.tagName == "TEXTAREA") { + if (elem.tagName.toUpperCase() === "TEXTAREA") { var data = $.data(elem, CLEDITOR); if (!data) data = new cleditor(elem, options); $result = $result.add(data); @@ -129,6 +124,7 @@ // Misc constants BACKGROUND_COLOR = "backgroundColor", + BLURRED = "blurred", BUTTON = "button", BUTTON_NAME = "buttonName", CHANGE = "change", @@ -136,6 +132,7 @@ CLICK = "click", DISABLED = "disabled", DIV_TAG = "
", + FOCUSED = "focused", TRANSPARENT = "transparent", UNSELECTABLE = "unselectable", @@ -152,12 +149,15 @@ PROMPT_CLASS = "cleditorPrompt", // prompt popup divs inside body MSG_CLASS = "cleditorMsg", // message popup div inside body - // Test for ie - ie = $.browser.msie, - ie6 = /msie\s6/i.test(navigator.userAgent), + // Browser detection + ua = navigator.userAgent.toLowerCase(), + ie = /msie/.test(ua), + ie6 = /msie\s6/.test(ua), + iege11 = /(trident)(?:.*rv:([\w.]+))?/.test(ua), + webkit = /webkit/.test(ua), // Test for iPhone/iTouch/iPad - iOS = /iphone|ipad|ipod/i.test(navigator.userAgent), + iOS = /iphone|ipad|ipod/i.test(ua), // Popups are created once as needed and shared by all editor instances popups = {}, @@ -223,19 +223,26 @@ var $group = $(DIV_TAG) .addClass(GROUP_CLASS) .appendTo($toolbar); + + // Initialize the group width + var groupWidth = 0; // Add the buttons to the toolbar $.each(options.controls.split(" "), function(idx, buttonName) { if (buttonName === "") return true; // Divider - if (buttonName == "|") { + if (buttonName === "|") { // Add a new divider to the group var $div = $(DIV_TAG) .addClass(DIVIDER_CLASS) .appendTo($group); + // Update the group width + $group.width(groupWidth + 1); + groupWidth = 0; + // Create a new group $group = $(DIV_TAG) .addClass(GROUP_CLASS) @@ -258,6 +265,10 @@ .appendTo($group) .hover(hoverEnter, hoverLeave); + // Update the group width + groupWidth += 24; + $group.width(groupWidth + 1); + // Prepare the button image var map = {}; if (button.css) map = button.css; @@ -295,17 +306,7 @@ // Bind the window resize event when the width or height is auto or % if (/auto|%/.test("" + options.width + options.height)) - $(window).resize(function() { - //Forcefully blurred iframe contentWindow, chrome, IE, safari doesn't trigger blur on window resize and due to which text disappears - var contentWindow = editor.$frame[0].contentWindow; - if(!$.browser.mozilla && contentWindow){ - $(contentWindow).trigger('blur'); - } - // CHM Note MonkeyPatch: if the DOM is not remove, refresh the cleditor - if(editor.$main.parent().parent().size()) { - refresh(editor); - } - }); + $(window).bind('resize.cleditor', function () { refresh(editor); }); // Create the iframe and resize the controls refresh(editor); @@ -347,13 +348,26 @@ return editor; }; }); + + // blurred - shortcut for .bind("blurred", handler) or .trigger("blurred") + fn.blurred = function(handler) { + var $this = $(this); + return handler ? $this.bind(BLURRED, handler) : $this.trigger(BLURRED); + }; // change - shortcut for .bind("change", handler) or .trigger("change") - fn.change = function(handler) { + fn.change = function change(handler) { + console.log('change test'); var $this = $(this); return handler ? $this.bind(CHANGE, handler) : $this.trigger(CHANGE); }; + // focused - shortcut for .bind("focused", handler) or .trigger("focused") + fn.focused = function(handler) { + var $this = $(this); + return handler ? $this.bind(FOCUSED, handler) : $this.trigger(FOCUSED); + }; + //=============== // Event Handlers //=============== @@ -369,7 +383,7 @@ popup = popups[popupName]; // Check if disabled - if (editor.disabled || $(buttonDiv).attr(DISABLED) == DISABLED) + if (editor.disabled || $(buttonDiv).attr(DISABLED) === DISABLED) return; // Fire the buttonClick event @@ -387,7 +401,7 @@ return false; // Toggle source - if (buttonName == "source") { + if (buttonName === "source") { // Show the iframe if (sourceMode(editor)) { @@ -418,10 +432,10 @@ var $popup = $(popup); // URL - if (popupName == "url") { + if (popupName === "url") { // Check for selection before showing the link url popup - if (buttonName == "link" && selectedText(editor) === "") { + if (buttonName === "link" && selectedText(editor) === "") { showMessage(editor, "A selection is required when inserting a link.", buttonDiv); return false; } @@ -447,7 +461,7 @@ } // Paste as Text - else if (popupName == "pastetext") { + else if (popupName === "pastetext") { // Wire up the submit button click event handler $popup.children(":button") @@ -475,13 +489,13 @@ return false; // stop propagination to document click } - // propaginate to documnt click + // propaginate to document click return; } // Print - else if (buttonName == "print") + else if (buttonName === "print") editor.$frame[0].contentWindow.print(); // All other buttons @@ -526,19 +540,19 @@ useCSS = editor.options.useCSS; // Get the command value - if (buttonName == "font") + if (buttonName === "font") // Opera returns the fontfamily wrapped in quotes value = target.style.fontFamily.replace(/"/g, ""); - else if (buttonName == "size") { - if (target.tagName == "DIV") + else if (buttonName === "size") { + if (target.tagName.toUpperCase() === "DIV") target = target.children[0]; value = target.innerHTML; } - else if (buttonName == "style") + else if (buttonName === "style") value = "<" + target.tagName + ">"; - else if (buttonName == "color") + else if (buttonName === "color") value = hex(target.style.backgroundColor); - else if (buttonName == "highlight") { + else if (buttonName === "highlight") { value = hex(target.style.backgroundColor); if (ie) command = 'backcolor'; else useCSS = true; @@ -572,7 +586,7 @@ //================== // Private Functions //================== - + // checksum - returns a checksum using the Adler-32 method function checksum(text) { @@ -610,7 +624,7 @@ $popup.html(popupContent); // Color - else if (popupName == "color") { + else if (popupName === "color") { var colors = options.colors.split(" "); if (colors.length < 10) $popup.width("auto"); @@ -622,7 +636,7 @@ } // Font - else if (popupName == "font") + else if (popupName === "font") $.each(options.fonts.split(","), function(idx, font) { $(DIV_TAG).appendTo($popup) .css("fontFamily", font) @@ -630,28 +644,28 @@ }); // Size - else if (popupName == "size") + else if (popupName === "size") $.each(options.sizes.split(","), function(idx, size) { $(DIV_TAG).appendTo($popup) - .html("" + size + ""); + .html('' + size + ''); }); // Style - else if (popupName == "style") + else if (popupName === "style") $.each(options.styles, function(idx, style) { $(DIV_TAG).appendTo($popup) .html(style[1] + style[0] + style[1].replace("<", "
'); + else if (popupName === "url") { + $popup.html('Enter URL:

'); popupTypeClass = PROMPT_CLASS; } // Paste as Text - else if (popupName == "pastetext") { - $popup.html('Paste your content here and click submit.

'); + else if (popupName === "pastetext") { + $popup.html('Paste your content here and click submit.

'); popupTypeClass = PROMPT_CLASS; } @@ -720,12 +734,12 @@ } // Execute the command and check for error - var success = true, description; - if (ie && command.toLowerCase() == "inserthtml") + var success = true, message; + if (ie && command.toLowerCase() === "inserthtml") getRange(editor).pasteHTML(value); else { try { success = editor.doc.execCommand(command, 0, value || null); } - catch (err) { description = err.description; success = false; } + catch (err) { message = err.message; success = false; } if (!success) { if ("cutcopypaste".indexOf(command) > -1) showMessage(editor, "For security reasons, your browser does not support the " + @@ -733,13 +747,14 @@ button); else showMessage(editor, - (description ? description : "Error executing the " + command + " command."), + (message ? message : "Error executing the " + command + " command."), button); } } - // Enable the buttons + // Enable the buttons and update the textarea refreshButtons(editor); + updateTextArea(editor, true); return success; } @@ -765,19 +780,26 @@ return editor.$frame[0].contentWindow.getSelection(); } - // Returns the hex value for the passed in string. - // hex("rgb(255, 0, 0)"); // #FF0000 - // hex("#FF0000"); // #FF0000 - // hex("#F00"); // #FF0000 + // hex - returns the hex value for the passed in color string function hex(s) { - var m = /rgba?\((\d+), (\d+), (\d+)/.exec(s), - c = s.split(""); + + // hex("rgb(255, 0, 0)") returns #FF0000 + var m = /rgba?\((\d+), (\d+), (\d+)/.exec(s); if (m) { - s = ( m[1] << 16 | m[2] << 8 | m[3] ).toString(16); + s = (m[1] << 16 | m[2] << 8 | m[3]).toString(16); while (s.length < 6) s = "0" + s; + return "#" + s; } - return "#" + (s.length == 6 ? s : c[1] + c[1] + c[2] + c[2] + c[3] + c[3]); + + // hex("#F00") returns #FF0000 + var c = s.split(""); + if (s.length === 4) + return "#" + c[1] + c[1] + c[2] + c[2] + c[3] + c[3]; + + // hex("#FF0000") returns #FF0000 + return s; + } // hidePopups - hides all popups @@ -792,9 +814,8 @@ // imagesPath - returns the path to the images folder function imagesPath() { - var cssFile = "jquery.cleditor.css", - href = $("link[href$='" + cssFile +"']").attr("href"); - return href.substr(0, href.length - cssFile.length) + "images/"; + var href = $("link[href*=cleditor]").attr("href"); + return href.replace(/^(.*\/)[^\/]+$/, '$1') + "images/"; } // imageUrl - Returns the css url string for a filemane @@ -813,7 +834,7 @@ editor.$frame.remove(); // Create a new iframe - var $frame = editor.$frame = $('