From 905617b53002a0052bade2359b713f369faefdba Mon Sep 17 00:00:00 2001 From: Laetitia Gangloff Date: Fri, 6 Jun 2014 12:55:22 +0200 Subject: [PATCH 01/19] hr_timesheet_sheet: for attendance, set default value for employee_id in the context --- addons/hr_timesheet_sheet/hr_timesheet_sheet_view.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/hr_timesheet_sheet/hr_timesheet_sheet_view.xml b/addons/hr_timesheet_sheet/hr_timesheet_sheet_view.xml index 644586ec502..1b4f733eb8a 100644 --- a/addons/hr_timesheet_sheet/hr_timesheet_sheet_view.xml +++ b/addons/hr_timesheet_sheet/hr_timesheet_sheet_view.xml @@ -134,7 +134,7 @@ - + From ac117ac2200a250de9be44cebe172bd512a8afbd Mon Sep 17 00:00:00 2001 From: Alexandre Fayolle Date: Fri, 6 Jun 2014 14:18:37 +0200 Subject: [PATCH 02/19] [FIX] delivery: propagate additional fields in chained pickings closes #367 --- addons/delivery/__openerp__.py | 4 +- addons/delivery/stock.py | 11 ++++ .../test/delivery_chained_pickings.yml | 50 +++++++++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 addons/delivery/test/delivery_chained_pickings.yml diff --git a/addons/delivery/__openerp__.py b/addons/delivery/__openerp__.py index 0ea891bb6ae..dffc156e104 100644 --- a/addons/delivery/__openerp__.py +++ b/addons/delivery/__openerp__.py @@ -41,7 +41,9 @@ invoices from picking, OpenERP is able to add and compute the shipping line. 'delivery_data.xml' ], 'demo': ['delivery_demo.xml'], - 'test': ['test/delivery_cost.yml'], + 'test': ['test/delivery_cost.yml', + 'test/delivery_chained_pickings.yml', + ], 'installable': True, 'auto_install': False, 'images': ['images/1_delivery_method.jpeg','images/2_delivery_pricelist.jpeg'], diff --git a/addons/delivery/stock.py b/addons/delivery/stock.py index e96daea63d2..263a47696a5 100644 --- a/addons/delivery/stock.py +++ b/addons/delivery/stock.py @@ -167,6 +167,17 @@ class stock_move(osv.osv): } return res + def _prepare_chained_picking(self, cr, uid, picking_name, picking, picking_type, moves_todo, context=None): + values = super(stock_move, self)._prepare_chained_picking(cr, uid, picking_name, picking, picking_type, moves_todo, context=context) + if picking.carrier_id: + values['carrier_id'] = picking.carrier_id.id + values['volume'] = picking.volume + values['weight'] = picking.weight + values['weight_net'] = picking.weight_net + values['carrier_tracking_ref'] = picking.carrier_tracking_ref + values['number_of_packages'] = picking.number_of_packages + return values + _columns = { 'weight': fields.function(_cal_move_weight, type='float', string='Weight', digits_compute= dp.get_precision('Stock Weight'), multi='_cal_move_weight', store={ diff --git a/addons/delivery/test/delivery_chained_pickings.yml b/addons/delivery/test/delivery_chained_pickings.yml new file mode 100644 index 00000000000..1d368e51d86 --- /dev/null +++ b/addons/delivery/test/delivery_chained_pickings.yml @@ -0,0 +1,50 @@ +- + I setup product and locations +- + !record {model: stock.location, id: dest_chained_location}: + name: DestChainedLocation + usage: internal +- + !record {model: stock.location, id: source_chained_location}: + name: Source Chained Location + chained_auto_packing: auto + chained_location_type: fixed + usage: internal + chained_location_id: dest_chained_location +- + I create a picking to location_convenience_shop, which is chained with location_refrigerator +- + !record {model: stock.picking, id: shipment_with_delivery}: + type: internal + carrier_id: delivery.delivery_carrier + volume: 42 + carrier_tracking_ref: FDX123 + number_of_packages: 7 +- + I add a move in the picking +- + !record {model: stock.move, id: icecream_move}: + picking_id: shipment_with_delivery + product_id: product_product_delivery + product_uom: product.product_uom_kgm + product_qty: 130.0 + location_id: stock.stock_location_suppliers + location_dest_id: source_chained_location +- + I confirm the picking +- + !workflow {model: stock.picking, action: button_confirm, ref: shipment_with_delivery} +- + I check that the delivery fields have been propagated to the chained picking +- + !python {model: stock.move}: | + original_move = self.browse(cr, uid, ref('icecream_move'), context=context) + original_picking = original_move.picking_id + chained_move = original_move.move_dest_id + chained_picking = chained_move.picking_id + assert chained_picking.carrier_tracking_ref == original_picking.carrier_tracking_ref, 'no propagation of carrier_tracking_ref' + assert chained_picking.carrier_id == original_picking.carrier_id, 'no propagation of carrier_id' + assert chained_picking.volume == original_picking.volume, 'no propagation of volume' + assert chained_picking.weight == original_picking.weight, 'no propagation of weight' + assert chained_picking.weight_net == original_picking.weight_net, 'no propagation of weight' + From 81a3a4fcbb1d6aa74ca06db8e98df11324403827 Mon Sep 17 00:00:00 2001 From: "Somesh Khare(OpenERP)" Date: Wed, 24 Jul 2013 14:37:27 +0530 Subject: [PATCH 03/19] [FIX]Delivery: carrier information not propagated from sale order to pickings (Case: ref 595240) closes lp:1192115 --- addons/delivery/sale.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/addons/delivery/sale.py b/addons/delivery/sale.py index d2916eb2085..c5ae43a4546 100644 --- a/addons/delivery/sale.py +++ b/addons/delivery/sale.py @@ -72,8 +72,7 @@ class sale_order(osv.osv): 'tax_id': [(6,0,taxes_ids)], 'type': 'make_to_stock' }) - #remove the value of the carrier_id field on the sale order - return self.write(cr, uid, ids, {'carrier_id': False}, context=context) + return True #return {'type': 'ir.actions.act_window_close'} action reload? sale_order() From 0ceee2a1209b789c9cfcd9f6c8b9da50be425dca Mon Sep 17 00:00:00 2001 From: Alexandre Fayolle Date: Fri, 6 Jun 2014 14:47:33 +0200 Subject: [PATCH 04/19] [IMP] add an index on account_move_line(date, id) fixes https://launchpad.net/bugs/1311004 --- addons/account/account_move_line.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/addons/account/account_move_line.py b/addons/account/account_move_line.py index 4da965167ba..a7fd2adf33e 100644 --- a/addons/account/account_move_line.py +++ b/addons/account/account_move_line.py @@ -566,6 +566,9 @@ class account_move_line(osv.osv): cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = \'account_move_line_journal_id_period_id_index\'') if not cr.fetchone(): cr.execute('CREATE INDEX account_move_line_journal_id_period_id_index ON account_move_line (journal_id, period_id)') + cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = %s', ('account_move_line_date_id_index',)) + if not cr.fetchone(): + cr.execute('CREATE INDEX account_move_line_date_id_index ON account_move_line (date DESC, id desc)') return res def _check_no_view(self, cr, uid, ids, context=None): From 387093a34a172afad33e20c2808f09a1b541e958 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Tue, 10 Jun 2014 10:59:59 +0200 Subject: [PATCH 05/19] gamification: when changing the domain on a goal definition give a simple check to avoid getting a traceback when the challenge is reloaded --- addons/gamification/models/goal.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/addons/gamification/models/goal.py b/addons/gamification/models/goal.py index 8e79c43c8a6..44071a526b4 100644 --- a/addons/gamification/models/goal.py +++ b/addons/gamification/models/goal.py @@ -121,6 +121,36 @@ class gamification_goal_definition(osv.Model): user = self.pool.get('res.users').browse(cr, uid, uid, context=context) return self.pool.get('mail.followers').search(cr, uid, [('res_model', '=', model_name), ('partner_id', '=', user.partner_id.id)], count=True, context=context) + def _check_domain_validity(self, cr, uid, ids, context=None): + # take admin as should always be present + superuser = self.pool['res.users'].browse(cr, uid, SUPERUSER_ID, context=context) + for definition in self.browse(cr, uid, ids, context=context): + if definition.computation_mode not in ('count', 'sum'): + continue + + obj = self.pool[definition.model_id.model] + try: + domain = safe_eval(definition.domain, {'user': superuser}) + # demmy search to make sure the domain is valid + obj.search(cr, uid, domain, context=context, count=True) + except (ValueError, SyntaxError), e: + msg = e.message or (e.msg + '\n' + e.text) + raise osv.except_osv(_('Error!'),_("The domain for the definition %s seems incorrect, please check it.\n\n%s" % (definition.name, msg))) + return True + + def create(self, cr, uid, vals, context=None): + res_id = super(gamification_goal_definition, self).create(cr, uid, vals, context=context) + if vals.get('computation_mode') in ('count', 'sum'): + self._check_domain_validity(cr, uid, [res_id], context=context) + + return res_id + + def write(self, cr, uid, ids, vals, context=None): + res = super(gamification_goal_definition, self).write(cr, uid, ids, vals, context=context) + if vals.get('computation_mode', 'count') in ('count', 'sum') and (vals.get('domain') or vals.get('model_id')): + self._check_domain_validity(cr, uid, ids, context=context) + + return res class gamification_goal(osv.Model): From fdd00fe635a9666d337a4ef420e08d49973ff307 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Tue, 10 Jun 2014 12:26:46 +0200 Subject: [PATCH 06/19] [FIX] account_voucher: better pay invoice wizard If the writeoff_amount is above 0, the fields writeoff_acc_id can be displayed and is required depending of the payment option. If the writeoff_amount is reset to 0, this field should no longer be required. --- addons/account_voucher/voucher_payment_receipt_view.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/account_voucher/voucher_payment_receipt_view.xml b/addons/account_voucher/voucher_payment_receipt_view.xml index 1169d5ef7c3..b4578c9b035 100644 --- a/addons/account_voucher/voucher_payment_receipt_view.xml +++ b/addons/account_voucher/voucher_payment_receipt_view.xml @@ -334,7 +334,7 @@ From 6b85d80f2349a26e8eb6b68a8368d58dce3b2eb6 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Tue, 10 Jun 2014 18:46:40 +0200 Subject: [PATCH 07/19] [FIX] Wrap werkzeug.utils.escape() to accomodate signature change in 0.9 We always want to escape quotes (") as part of the process of generating HTML output. This option (quote=True) turned into an implicit flag with a DeprecationWarning in werkzeug 0.9.0 It is likely to disappear in a future release of werkzeug too. A wrapper avoids this warning without loss of compatibility --- addons/website/models/ir_qweb.py | 3 ++- addons/website/models/website.py | 3 ++- .../website_event_track/controllers/event.py | 4 ++-- openerp/addons/base/ir/ir_qweb.py | 20 +++++++++---------- .../addons/test_converter/tests/test_html.py | 3 +-- openerp/tools/misc.py | 10 +++++++++- 6 files changed, 26 insertions(+), 17 deletions(-) diff --git a/addons/website/models/ir_qweb.py b/addons/website/models/ir_qweb.py index 0e1fe2beb89..6c466355d07 100644 --- a/addons/website/models/ir_qweb.py +++ b/addons/website/models/ir_qweb.py @@ -25,6 +25,7 @@ import openerp.modules import openerp from openerp.osv import orm, fields from openerp.tools import ustr, DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT +from openerp.tools import html_escape as escape from openerp.addons.web.http import request from openerp.addons.base.ir import ir_qweb @@ -276,7 +277,7 @@ class Image(orm.AbstractModel): url_params[options_key] = options[options_key] return ir_qweb.HTMLSafe('' % ( - ' '.join(itertools.imap(werkzeug.utils.escape, classes)), + ' '.join(itertools.imap(escape, classes)), werkzeug.urls.url_encode(url_params) )) diff --git a/addons/website/models/website.py b/addons/website/models/website.py index 9828e9aa39d..434712933f0 100644 --- a/addons/website/models/website.py +++ b/addons/website/models/website.py @@ -27,6 +27,7 @@ except ImportError: import openerp from openerp.osv import orm, osv, fields +from openerp.tools import html_escape as escape from openerp.tools.safe_eval import safe_eval from openerp.addons.web.http import request @@ -728,7 +729,7 @@ class ir_attachment(osv.osv): for attachment in self.browse(cr, uid, ids, context=context): # in-document URLs are html-escaped, a straight search will not # find them - url = werkzeug.utils.escape(attachment.website_url) + url = escape(attachment.website_url) ids = Views.search(cr, uid, ["|", ('arch', 'like', '"%s"' % url), ('arch', 'like', "'%s'" % url)], context=context) if ids: diff --git a/addons/website_event_track/controllers/event.py b/addons/website_event_track/controllers/event.py index e24aee7e62d..c2bcb3f2e4b 100644 --- a/addons/website_event_track/controllers/event.py +++ b/addons/website_event_track/controllers/event.py @@ -24,9 +24,9 @@ import datetime import re import pytz -import werkzeug.utils import openerp +import openerp.tools from openerp.addons.web import http from openerp.addons.web.http import request @@ -150,7 +150,7 @@ class website_event(http.Controller): if post.get('tag_'+str(tag.id)): tags.append(tag.id) - e = werkzeug.utils.escape + e = openerp.tools.escape track_description = '''
diff --git a/openerp/addons/base/ir/ir_qweb.py b/openerp/addons/base/ir/ir_qweb.py index 940c7844628..48cb8afbae2 100644 --- a/openerp/addons/base/ir/ir_qweb.py +++ b/openerp/addons/base/ir/ir_qweb.py @@ -11,12 +11,12 @@ import xml # FIXME use lxml and etree import babel import babel.dates -import werkzeug.utils from PIL import Image import openerp.tools -from openerp.tools.safe_eval import safe_eval as eval from openerp.osv import osv, orm, fields +from openerp.tools import html_escape as escape +from openerp.tools.safe_eval import safe_eval as eval from openerp.tools.translate import _ _logger = logging.getLogger(__name__) @@ -259,14 +259,14 @@ class QWeb(orm.AbstractModel): for attribute in self._render_att: if attribute_name[2:].startswith(attribute): att, val = self._render_att[attribute](self, element, attribute_name, attribute_value, qwebcontext) - generated_attributes += val and ' %s="%s"' % (att, werkzeug.utils.escape(val)) or " " + generated_attributes += val and ' %s="%s"' % (att, escape(val)) or " " break else: if attribute_name[2:] in self._render_tag: t_render = attribute_name[2:] template_attributes[attribute_name[2:]] = attribute_value else: - generated_attributes += ' %s="%s"' % (attribute_name, werkzeug.utils.escape(attribute_value)) + generated_attributes += ' %s="%s"' % (attribute_name, escape(attribute_value)) if 'debug' in template_attributes: debugger = template_attributes.get('debug', 'pdb') @@ -454,7 +454,7 @@ class FieldConverter(osv.AbstractModel): """ Generates the metadata attributes (prefixed by ``data-oe-`` for the root node of the field conversion. Attribute values are escaped by the - parent using ``werkzeug.utils.escape``. + parent. The default attributes are: @@ -507,7 +507,7 @@ class FieldConverter(osv.AbstractModel): record._model._all_columns[field_name].column, options, context=context) if options.get('html-escape', True): - content = werkzeug.utils.escape(content) + content = escape(content) elif hasattr(content, '__html__'): content = content.__html__() except Exception: @@ -518,7 +518,7 @@ class FieldConverter(osv.AbstractModel): if context and context.get('inherit_branding'): # add branding attributes g_att += ''.join( - ' %s="%s"' % (name, werkzeug.utils.escape(value)) + ' %s="%s"' % (name, escape(value)) for name, value in self.attributes( cr, uid, field_name, record, options, source_element, g_att, t_att, qweb_context) @@ -841,7 +841,7 @@ class Contact(orm.AbstractModel): val = { 'name': value.split("\n")[0], - 'address': werkzeug.utils.escape("\n".join(value.split("\n")[1:])), + 'address': escape("\n".join(value.split("\n")[1:])), 'phone': field_browse.phone, 'mobile': field_browse.mobile, 'fax': field_browse.fax, @@ -885,7 +885,7 @@ class QwebWidget(osv.AbstractModel): return self.pool['ir.qweb'].eval_str(inner, qwebcontext) def format(self, inner, options, qwebcontext): - return werkzeug.utils.escape(self._format(inner, options, qwebcontext)) + return escape(self._format(inner, options, qwebcontext)) class QwebWidgetMonetary(osv.AbstractModel): _name = 'ir.qweb.widget.monetary' @@ -945,7 +945,7 @@ def nl2br(string, options=None): if options is None: options = {} if options.get('html-escape', True): - string = werkzeug.utils.escape(string) + string = escape(string) return HTMLSafe(string.replace('\n', '
\n')) def get_field_type(column, options): diff --git a/openerp/addons/test_converter/tests/test_html.py b/openerp/addons/test_converter/tests/test_html.py index 3ef6566e829..c3fbca1b982 100644 --- a/openerp/addons/test_converter/tests/test_html.py +++ b/openerp/addons/test_converter/tests/test_html.py @@ -4,9 +4,8 @@ import os import xml.dom.minidom import datetime -from werkzeug.utils import escape as e - from openerp.tests import common +from openerp.tools import html_escape as e from openerp.addons.base.ir import ir_qweb directory = os.path.dirname(__file__) diff --git a/openerp/tools/misc.py b/openerp/tools/misc.py index b9fdef9b421..8829e15dca7 100644 --- a/openerp/tools/misc.py +++ b/openerp/tools/misc.py @@ -34,6 +34,7 @@ import socket import sys import threading import time +import werkzeug.utils import zipfile from collections import defaultdict, Mapping from datetime import datetime @@ -50,6 +51,7 @@ except ImportError: from config import config from cache import * +from .parse_version import parse_version import openerp # get_encodings, ustr and exception_to_unicode were originally from tools.misc. @@ -1208,6 +1210,12 @@ def dumpstacks(sig=None, frame=None): _logger.info("\n".join(code)) - +# Avoid DeprecationWarning while still remaining compatible with werkzeug pre-0.9 +if parse_version(getattr(werkzeug, '__version__', '0.0')) < parse_version('0.9.0'): + def html_escape(text): + return werkzeug.utils.escape(text, quote=True) +else: + def html_escape(text): + return werkzeug.utils.escape(text) # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From 100eba8eaf478fc1d6cb71ab7ca7d021aa7eca40 Mon Sep 17 00:00:00 2001 From: Jeremy Kersten Date: Wed, 11 Jun 2014 10:30:00 +0200 Subject: [PATCH 08/19] [FIX] fields.py - avoid dict comprehension inside a dict comprehension --- openerp/osv/fields.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/osv/fields.py b/openerp/osv/fields.py index 529f0563f8d..18aa3aad8c2 100644 --- a/openerp/osv/fields.py +++ b/openerp/osv/fields.py @@ -1148,7 +1148,7 @@ class function(_column): if values and not multi and name in values[0]: result = {v['id']: v[name] for v in values} elif values and multi and all(n in values[0] for n in name): - result = {v['id']: dict({n: v[n]} for n in name) for v in values} + result = {v['id']: dict((n, v[n]) for n in name) for v in values} else: result = self._fnct(obj, cr, uid, ids, name, self._arg, context) for id in ids: From 194049df99ab2ccd413c94d60aa873a29d5b9ade Mon Sep 17 00:00:00 2001 From: Richard Mathot Date: Wed, 11 Jun 2014 10:57:03 +0200 Subject: [PATCH 09/19] [FIX] survey: user-friendly message when login is required --- addons/survey/controllers/main.py | 2 +- addons/survey/views/survey_templates.xml | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/addons/survey/controllers/main.py b/addons/survey/controllers/main.py index 2f65d92cd4c..ea9af115712 100644 --- a/addons/survey/controllers/main.py +++ b/addons/survey/controllers/main.py @@ -46,7 +46,7 @@ class WebsiteSurvey(http.Controller): # In case of auth required, block public user if survey.auth_required and uid == request.registry['website'].get_public_user(cr, uid, context): - return request.website.render("website.403") + return request.website.render("survey.auth_required", {'survey': survey}) # In case of non open surveys if survey.stage_id.closed: diff --git a/addons/survey/views/survey_templates.xml b/addons/survey/views/survey_templates.xml index 9a342fa128d..9ae973b9345 100644 --- a/addons/survey/views/survey_templates.xml +++ b/addons/survey/views/survey_templates.xml @@ -31,6 +31,20 @@ + + +