diff --git a/addons/account/account_invoice_view.xml b/addons/account/account_invoice_view.xml index 1be4ac7d2ba..93dd7bf2e41 100644 --- a/addons/account/account_invoice_view.xml +++ b/addons/account/account_invoice_view.xml @@ -61,7 +61,7 @@ - + @@ -95,7 +95,7 @@ - + @@ -201,7 +201,7 @@ domain="[('company_id', '=', parent.company_id), ('journal_id', '=', parent.journal_id), ('type', '=', 'other')]" on_change="onchange_account_id(product_id, parent.partner_id, parent.type, parent.fiscal_position,account_id)"/> + domain="[('type','!=','view'), ('company_id', '=', parent.company_id), ('state','not in',('close','cancelled'))]"/> @@ -358,7 +358,7 @@ domain="[('company_id', '=', parent.company_id), ('journal_id', '=', parent.journal_id), ('type', '=', 'other')]" on_change="onchange_account_id(product_id, parent.partner_id, parent.type, parent.fiscal_position,account_id)"/> + domain="[('type','!=','view'), ('company_id', '=', parent.company_id), ('state','not in',('close','cancelled'))]"/> diff --git a/addons/account/account_move_line.py b/addons/account/account_move_line.py index 2a9dd559fb4..c513261a9cf 100644 --- a/addons/account/account_move_line.py +++ b/addons/account/account_move_line.py @@ -583,7 +583,7 @@ class account_move_line(osv.osv): def _check_no_view(self, cr, uid, ids, context=None): lines = self.browse(cr, uid, ids, context=context) for l in lines: - if l.account_id.type == 'view': + if l.account_id.type in ('view', 'consolidation'): return False return True @@ -635,7 +635,7 @@ class account_move_line(osv.osv): return True _constraints = [ - (_check_no_view, 'You cannot create journal items on an account of type view.', ['account_id']), + (_check_no_view, 'You cannot create journal items on an account of type view or consolidation.', ['account_id']), (_check_no_closed, 'You cannot create journal items on closed account.', ['account_id']), (_check_company_id, 'Account and Period must belong to the same company.', ['company_id']), (_check_date, 'The date of your Journal Entry is not in the defined period! You should change the date or remove this constraint from the journal.', ['date']), diff --git a/addons/account_voucher/account_voucher.py b/addons/account_voucher/account_voucher.py index 275e002695e..6341c8b1e10 100644 --- a/addons/account_voucher/account_voucher.py +++ b/addons/account_voucher/account_voucher.py @@ -946,6 +946,8 @@ class account_voucher(osv.osv): # refresh to make sure you don't unlink an already removed move voucher.refresh() for line in voucher.move_ids: + # refresh to make sure you don't unreconcile an already unreconciled entry + line.refresh() if line.reconcile_id: move_lines = [move_line.id for move_line in line.reconcile_id.line_id] move_lines.remove(line.id) diff --git a/addons/base_vat/base_vat.py b/addons/base_vat/base_vat.py index b7ac9592dd3..38ad7a8fd24 100644 --- a/addons/base_vat/base_vat.py +++ b/addons/base_vat/base_vat.py @@ -63,6 +63,7 @@ _ref_vat = { 'mx': 'MXABC123456T1B', 'nl': 'NL123456782B90', 'no': 'NO123456785', + 'pe': 'PER10254824220 or PED10254824220', 'pl': 'PL1234567883', 'pt': 'PT123456789', 'ro': 'RO1234567897', @@ -144,10 +145,11 @@ class res_partner(osv.osv): return cn[0] in string.ascii_lowercase and cn[1] in string.ascii_lowercase vat_country, vat_number = self._split_vat(self.browse(cr, uid, ids)[0].vat) vat_no = "'CC##' (CC=Country Code, ##=VAT Number)" + error_partner = self.browse(cr, uid, ids, context=context) if default_vat_check(vat_country, vat_number): vat_no = _ref_vat[vat_country] if vat_country in _ref_vat else vat_no - #Retrieve the current partner for wich the VAT is not valid - error_partner = self.browse(cr, uid, ids, context=context) + if self.pool['res.users'].browse(cr, uid, uid).company_id.vat_check_vies: + return '\n' + _('The VAT number [%s] for partner [%s] either failed the VIES VAT validation check or did not respect the expected format %s.') % (error_partner[0].vat, error_partner[0].name, vat_no) return '\n' + _('The VAT number [%s] for partner [%s] does not seem to be valid. \nNote: the expected format is %s') % (error_partner[0].vat, error_partner[0].name, vat_no) _constraints = [(check_vat, _construct_constraint_msg, ["vat"])] @@ -218,7 +220,7 @@ class res_partner(osv.osv): return vat[7] == self._ie_check_char(vat[2:7] + vat[0] + vat[8]) return False - # Mexican VAT verification, contributed by + # Mexican VAT verification, contributed by Vauxoo # and Panos Christeas __check_vat_mx_re = re.compile(r"(?P[A-Za-z\xd1\xf1&]{3,4})" \ r"[ \-_]?" \ @@ -275,5 +277,39 @@ class res_partner(osv.osv): return False return check == int(vat[8]) + # Peruvian VAT validation, contributed by Vauxoo + def check_vat_pe(self, vat): + + vat_type,vat = vat and len(vat)>=2 and (vat[0], vat[1:]) or (False, False) + + if vat_type and vat_type.upper() == 'D': + #DNI + return True + elif vat_type and vat_type.upper() == 'R': + #verify RUC + factor = '5432765432' + sum = 0 + dig_check = False + if len(vat) != 11: + return False + try: + int(vat) + except ValueError: + return False + + for f in range(0,10): + sum += int(factor[f]) * int(vat[f]) + + subtraction = 11 - (sum % 11) + if subtraction == 10: + dig_check = 0 + elif subtraction == 11: + dig_check = 1 + else: + dig_check = subtraction + + return int(vat[10]) == dig_check + else: + return False # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/delivery/delivery.py b/addons/delivery/delivery.py index 0281c2787fb..a1afe087d28 100644 --- a/addons/delivery/delivery.py +++ b/addons/delivery/delivery.py @@ -211,7 +211,7 @@ class delivery_grid(osv.osv): for line in order.order_line: if not line.product_id or line.is_delivery: continue - q = product_uom_obj._compute_qty(cr, uid, line.product_uom.id, line.product_uos_qty, line.product_id.uom_id.id) + q = product_uom_obj._compute_qty(cr, uid, line.product_uom.id, line.product_uom_qty, line.product_id.uom_id.id) weight += (line.product_id.weight or 0.0) * q volume += (line.product_id.volume or 0.0) * q quantity += q diff --git a/addons/gamification/views/badge.xml b/addons/gamification/views/badge.xml index bdcb48240f8..302ad66caf0 100644 --- a/addons/gamification/views/badge.xml +++ b/addons/gamification/views/badge.xml @@ -40,7 +40,6 @@
diff --git a/addons/hr_holidays/hr_holidays.py b/addons/hr_holidays/hr_holidays.py index 414b45adf5b..80848941f87 100644 --- a/addons/hr_holidays/hr_holidays.py +++ b/addons/hr_holidays/hr_holidays.py @@ -500,7 +500,7 @@ class hr_employee(osv.osv): if diff > 0: leave_id = holiday_obj.create(cr, uid, {'name': _('Allocation for %s') % employee.name, 'employee_id': employee.id, 'holiday_status_id': status_id, 'type': 'add', 'holiday_type': 'employee', 'number_of_days_temp': diff}, context=context) elif diff < 0: - leave_id = holiday_obj.create(cr, uid, {'name': _('Leave Request for %s') % employee.name, 'employee_id': employee.id, 'holiday_status_id': status_id, 'type': 'remove', 'holiday_type': 'employee', 'number_of_days_temp': abs(diff)}, context=context) + raise osv.except_osv(_('Warning!'), _('You cannot reduce validated allocation requests')) else: return False for sig in ('confirm', 'validate', 'second_validate'): diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py index d11495289f7..b5457700145 100644 --- a/addons/mail/mail_message.py +++ b/addons/mail/mail_message.py @@ -76,7 +76,8 @@ class mail_message(osv.Model): def default_get(self, cr, uid, fields, context=None): # protection for `default_type` values leaking from menu action context (e.g. for invoices) - if context and context.get('default_type') and context.get('default_type') not in self._columns['type'].selection: + if context and context.get('default_type') and context.get('default_type') not in [ + val[0] for val in self._columns['type'].selection]: context = dict(context, default_type=None) return super(mail_message, self).default_get(cr, uid, fields, context=context) diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index c50e6d082e8..82b048b7e57 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -378,7 +378,10 @@ class mail_thread(osv.AbstractModel): # automatic logging unless asked not to (mainly for various testing purpose) if not context.get('mail_create_nolog'): - self.message_post(cr, uid, thread_id, body=_('%s created') % (self._description), context=context) + ir_model_pool = self.pool['ir.model'] + ids = ir_model_pool.search(cr, uid, [('model', '=', self._name)], context=context) + name = ir_model_pool.read(cr, uid, ids, ['name'], context=context)[0]['name'] + self.message_post(cr, uid, thread_id, body=_('%s created') % name, context=context) # auto_subscribe: take values and defaults into account create_values = dict(values) diff --git a/addons/project/report/project_report.py b/addons/project/report/project_report.py index 7dcccb13de1..1356a1ed007 100644 --- a/addons/project/report/project_report.py +++ b/addons/project/report/project_report.py @@ -51,7 +51,6 @@ class report_project_task_user(osv.osv): 'nbr': fields.integer('# of tasks', readonly=True), 'priority': fields.selection([('0','Low'), ('1','Normal'), ('2','High')], string='Priority', size=1, readonly=True), - 'state': fields.selection([('draft', 'Draft'), ('open', 'In Progress'), ('pending', 'Pending'), ('cancelled', 'Cancelled'), ('done', 'Done')],'Status', readonly=True), 'company_id': fields.many2one('res.company', 'Company', readonly=True), 'partner_id': fields.many2one('res.partner', 'Contact', readonly=True), 'stage_id': fields.many2one('project.task.type', 'Stage'), diff --git a/addons/sale/res_config.py b/addons/sale/res_config.py index f4892598332..e084d6494b2 100644 --- a/addons/sale/res_config.py +++ b/addons/sale/res_config.py @@ -93,6 +93,7 @@ Example: 10% for retailers, promotion of 5 EUR on this product, etc."""), product = ir_model_data.xmlid_to_object(cr, uid, 'product.product_product_consultant') if product and product.exists(): res['time_unit'] = product.uom_id.id + res['timesheet'] = res.get('module_account_analytic_analysis') return res def _get_default_time_unit(self, cr, uid, context=None): diff --git a/addons/sale/sale.py b/addons/sale/sale.py index 44f87b7ab03..0db6b9cd415 100644 --- a/addons/sale/sale.py +++ b/addons/sale/sale.py @@ -269,7 +269,7 @@ class sale_order(osv.osv): return osv.osv.unlink(self, cr, uid, unlink_ids, context=context) def copy_quotation(self, cr, uid, ids, context=None): - id = self.copy(cr, uid, ids[0], context=None) + id = self.copy(cr, uid, ids[0], context=context) view_ref = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'sale', 'view_order_form') view_id = view_ref and view_ref[1] or False, return { diff --git a/addons/sale/views/report_saleorder.xml b/addons/sale/views/report_saleorder.xml index a6771823f55..45ec4a77ac7 100644 --- a/addons/sale/views/report_saleorder.xml +++ b/addons/sale/views/report_saleorder.xml @@ -45,6 +45,10 @@ Salesperson:

+
+ Validity Date: +

+

Payment Term:

diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 68db426a4f9..4af91588a9d 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -928,8 +928,7 @@ class stock_picking(osv.osv): 'pack_operation_ids': [], 'backorder_id': picking.id, }) - back_order_name = self.browse(cr, uid, backorder_id, context=context).name - self.message_post(cr, uid, picking.id, body=_("Back order %s created.") % (back_order_name), context=context) + self.message_post(cr, uid, picking.id, body=_("Back order %s created.") % (picking.name), context=context) move_obj = self.pool.get("stock.move") move_obj.write(cr, uid, backorder_move_ids, {'picking_id': backorder_id}, context=context) @@ -1448,7 +1447,7 @@ class stock_production_lot(osv.osv): 'product_id': lambda x, y, z, c: c.get('product_id', False), } _sql_constraints = [ - ('name_ref_uniq', 'unique (name, ref)', 'The combination of Serial Number and internal reference must be unique !'), + ('name_ref_uniq', 'unique (name, ref, product_id, company_id)', 'The combination of Serial Number, internal reference, Product and Company must be unique !'), ] def action_traceability(self, cr, uid, ids, context=None): diff --git a/addons/survey/controllers/main.py b/addons/survey/controllers/main.py index 65152cdf8ce..901a7f3629a 100644 --- a/addons/survey/controllers/main.py +++ b/addons/survey/controllers/main.py @@ -299,7 +299,11 @@ class WebsiteSurvey(http.Controller): type='http', auth='user', website=True) def survey_reporting(self, survey, token=None, **post): '''Display survey Results & Statistics for given survey.''' - result_template, current_filters, filter_display_data, filter_finish = 'survey.result', [], [], False + result_template ='survey.result' + current_filters = [] + filter_display_data = [] + filter_finish = False + survey_obj = request.registry['survey.survey'] if not survey.user_input_ids or not [input_id.id for input_id in survey.user_input_ids if input_id.state != 'new']: result_template = 'survey.no_result' @@ -308,7 +312,7 @@ class WebsiteSurvey(http.Controller): filter_finish = True if post or filter_finish: filter_data = self.get_filter_data(post) - current_filters = survey_obj.filter_input_ids(request.cr, request.uid, filter_data, filter_finish, context=request.context) + current_filters = survey_obj.filter_input_ids(request.cr, request.uid, survey, filter_data, filter_finish, context=request.context) filter_display_data = survey_obj.get_filter_display_data(request.cr, request.uid, filter_data, context=request.context) return request.website.render(result_template, {'survey': survey, @@ -318,12 +322,49 @@ class WebsiteSurvey(http.Controller): 'filter_display_data': filter_display_data, 'filter_finish': filter_finish }) + # Quick retroengineering of what is injected into the template for now: + # (TODO: flatten and simplify this) + # + # survey: a browse record of the survey + # survey_dict: very messy dict containing all the info to display answers + # {'page_ids': [ + # + # ... + # + # {'page': browse record of the page, + # 'question_ids': [ + # + # ... + # + # {'graph_data': data to be displayed on the graph + # 'input_summary': number of answered, skipped... + # 'prepare_result': { + # answers displayed in the tables + # } + # 'question': browse record of the question_ids + # } + # + # ... + # + # ] + # } + # + # ... + # + # ] + # } + # + # page_range: pager helper function + # current_filters: a list of ids + # filter_display_data: [{'labels': ['a', 'b'], question_text} ... ] + # filter_finish: boolean => only finished surveys or not + # def prepare_result_dict(self,survey, current_filters=None): """Returns dictionary having values for rendering template""" current_filters = current_filters if current_filters else [] survey_obj = request.registry['survey.survey'] - result = {'survey':survey, 'page_ids': []} + result = {'page_ids': []} for page in survey.page_ids: page_dict = {'page': page, 'question_ids': []} for question in page.question_ids: @@ -357,9 +398,10 @@ class WebsiteSurvey(http.Controller): result = [] if question.type == 'multiple_choice': result.append({'key': str(question.question), - 'values': survey_obj.prepare_result(request.cr, request.uid, question, current_filters, context=request.context)}) + 'values': survey_obj.prepare_result(request.cr, request.uid, question, current_filters, context=request.context)['answers'] + }) if question.type == 'simple_choice': - result = survey_obj.prepare_result(request.cr, request.uid, question, current_filters, context=request.context) + result = survey_obj.prepare_result(request.cr, request.uid, question, current_filters, context=request.context)['answers'] if question.type == 'matrix': data = survey_obj.prepare_result(request.cr, request.uid, question, current_filters, context=request.context) for answer in data['answers']: diff --git a/addons/survey/survey.py b/addons/survey/survey.py index e87e24a41a0..5100b72f884 100644 --- a/addons/survey/survey.py +++ b/addons/survey/survey.py @@ -280,7 +280,7 @@ class survey_survey(osv.Model): else: return (pages[current_page_index + 1][1], current_page_index + 1, False) - def filter_input_ids(self, cr, uid, filters, finished=False, context=None): + def filter_input_ids(self, cr, uid, survey, filters, finished=False, context=None): '''If user applies any filters, then this function returns list of filtered user_input_id and label's strings for display data in web. :param filters: list of dictionary (having: row_id, ansewr_id) @@ -308,7 +308,7 @@ class survey_survey(osv.Model): if finished: user_input = self.pool.get('survey.user_input') if not filtered_input_ids: - current_filters = user_input.search(cr, uid, [], context=context) + current_filters = user_input.search(cr, uid, [('survey_id', '=', survey.id)], context=context) user_input_objs = user_input.browse(cr, uid, current_filters, context=context) else: user_input_objs = user_input.browse(cr, uid, filtered_input_ids, context=context) @@ -346,17 +346,22 @@ class survey_survey(osv.Model): result_summary = [] for label in question.labels_ids: count = 0 + comments = [] for input_line in question.user_input_line_ids: if input_line.answer_type == 'suggestion' and input_line.value_suggested.id == label.id and (not current_filters or input_line.user_input_id.id in current_filters): count = count + 1 - label_summary = {'text': label.value, 'count': count, 'answer_id': label.id} + if input_line.answer_type == 'text' and (not current_filters or input_line.user_input_id.id in current_filters): + comments.append(input_line) + label_summary = {'text': label.value, 'count': count, 'answer_id': label.id, 'comments': comments} result_summary = result_summary + [label_summary] + result_summary = {'answers': answers.values(), 'comments': comments} #Calculate and return statistics for matrix if question.type == 'matrix': rows = OrderedDict() answers = OrderedDict() res = dict() + comments = [] [rows.update({label.id: label.value}) for label in question.labels_ids_2] [answers.update({label.id: label.value}) for label in question.labels_ids] for cell in product(rows.keys(), answers.keys()): @@ -364,7 +369,9 @@ class survey_survey(osv.Model): for input_line in question.user_input_line_ids: if input_line.answer_type == 'suggestion' and (not(current_filters) or input_line.user_input_id.id in current_filters): res[(input_line.value_suggested_row.id, input_line.value_suggested.id)] += 1 - result_summary = {'answers': answers, 'rows': rows, 'result': res} + if input_line.answer_type == 'text' and (not(current_filters) or input_line.user_input_id.id in current_filters): + comments.append(input_line) + result_summary = {'answers': answers, 'rows': rows, 'result': res, 'comments': comments} #Calculate and return statistics for free_text, textbox, datetime if question.type in ['free_text', 'textbox', 'datetime']: @@ -1134,11 +1141,14 @@ class survey_user_input_line(osv.Model): vals.update({'answer_type': 'suggestion', 'value_suggested': post[answer_tag]}) else: vals.update({'answer_type': None, 'skipped': True}) - self.create(cr, uid, vals, context=context) + + # '-1' indicates 'comment count as an answer' so do not need to record it + if post.get(answer_tag) and post.get(answer_tag) != '-1': + self.create(cr, uid, vals, context=context) comment_answer = post.pop(("%s_%s" % (answer_tag, 'comment')), '').strip() if comment_answer: - vals.update({'answer_type': 'text', 'value_text': comment_answer, 'skipped': False}) + vals.update({'answer_type': 'text', 'value_text': comment_answer, 'skipped': False, 'value_suggested': False}) self.create(cr, uid, vals, context=context) return True @@ -1162,10 +1172,12 @@ class survey_user_input_line(osv.Model): comment_answer = ca.pop(("%s_%s" % (answer_tag, 'comment')), '').strip() if len(ca) > 0: for a in ca: - vals.update({'answer_type': 'suggestion', 'value_suggested': ca[a]}) - self.create(cr, uid, vals, context=context) + # '-1' indicates 'comment count as an answer' so do not need to record it + if a != ('%s_%s' % (answer_tag, '-1')): + vals.update({'answer_type': 'suggestion', 'value_suggested': ca[a]}) + self.create(cr, uid, vals, context=context) if comment_answer: - vals.update({'answer_type': 'text', 'value_text': comment_answer}) + vals.update({'answer_type': 'text', 'value_text': comment_answer, 'value_suggested': False}) self.create(cr, uid, vals, context=context) if not ca and not comment_answer: vals.update({'answer_type': None, 'skipped': True}) diff --git a/addons/survey/views/survey_result.xml b/addons/survey/views/survey_result.xml index 24c154d6bbc..79124efd812 100644 --- a/addons/survey/views/survey_result.xml +++ b/addons/survey/views/survey_result.xml @@ -13,7 +13,6 @@

-

@@ -34,6 +33,7 @@

+

@@ -56,7 +56,7 @@ -
+
@@ -115,6 +115,28 @@ + + + + @@ -217,6 +247,13 @@
+ +
+ + + + +
@@ -275,10 +312,7 @@ - -
- +
diff --git a/addons/survey/views/survey_templates.xml b/addons/survey/views/survey_templates.xml index de186b85b92..b49a48d2a53 100644 --- a/addons/survey/views/survey_templates.xml +++ b/addons/survey/views/survey_templates.xml @@ -8,7 +8,7 @@

Thank you!

-
+
You scored points.
If you wish, you can review your answers.
diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js index ef3aedb7cf3..b0e22f918c8 100644 --- a/addons/web/static/src/js/chrome.js +++ b/addons/web/static/src/js/chrome.js @@ -185,12 +185,12 @@ instance.web.Dialog = instance.web.Widget.extend({ close: function(reason) { if (this.dialog_inited && !this.__tmp_dialog_hiding) { $('.tooltip').remove(); //remove open tooltip if any to prevent them staying when modal has disappeared - this.trigger("closing", reason); if (this.$el.is(":data(bs.modal)")) { // may have been destroyed by closing signal this.__tmp_dialog_hiding = true; this.$dialog_box.modal('hide'); this.__tmp_dialog_hiding = undefined; } + this.trigger("closing", reason); } }, _closing: function() { diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js index 8a6c8def9ca..ac51a3445f2 100644 --- a/addons/web/static/src/js/views.js +++ b/addons/web/static/src/js/views.js @@ -691,8 +691,8 @@ instance.web.ViewManager = instance.web.Widget.extend({ var container = this.$el.find("> div > div > .oe_view_manager_body > .oe_view_manager_view_" + view_type); var view_promise = controller.appendTo(container); this.views[view_type].controller = controller; - this.views[view_type].deferred.resolve(view_type); return $.when(view_promise).done(function() { + self.views[view_type].deferred.resolve(view_type); if (self.searchview && self.flags.auto_search && view.controller.searchable !== false) { @@ -1122,7 +1122,7 @@ instance.web.ViewManagerAction = instance.web.ViewManager.extend({ ); } - $.when(defs).done(function() { + $.when(this.views[this.active_view] ? this.views[this.active_view].deferred : $.when(), defs).done(function() { self.views[self.active_view].controller.do_load_state(state, warm); }); }, diff --git a/addons/website/controllers/main.py b/addons/website/controllers/main.py index 5d1dbe04bec..22ec7f1fd02 100644 --- a/addons/website/controllers/main.py +++ b/addons/website/controllers/main.py @@ -191,14 +191,19 @@ class Website(openerp.addons.web.controllers.main.Home): modules_to_update = [] for temp_id in templates: view = request.registry['ir.ui.view'].browse(request.cr, request.uid, int(temp_id), context=request.context) + if view.page: + continue view.model_data_id.write({ 'noupdate': False }) if view.model_data_id.module not in modules_to_update: modules_to_update.append(view.model_data_id.module) - module_obj = request.registry['ir.module.module'] - module_ids = module_obj.search(request.cr, request.uid, [('name', 'in', modules_to_update)], context=request.context) - module_obj.button_immediate_upgrade(request.cr, request.uid, module_ids, context=request.context) + + if modules_to_update: + module_obj = request.registry['ir.module.module'] + module_ids = module_obj.search(request.cr, request.uid, [('name', 'in', modules_to_update)], context=request.context) + if module_ids: + module_obj.button_immediate_upgrade(request.cr, request.uid, module_ids, context=request.context) return request.redirect(redirect) @http.route('/website/customize_template_get', type='json', auth='user', website=True) diff --git a/addons/website/models/ir_http.py b/addons/website/models/ir_http.py index 8521d83630b..8c09c998bd1 100644 --- a/addons/website/models/ir_http.py +++ b/addons/website/models/ir_http.py @@ -210,7 +210,7 @@ class ir_http(orm.AbstractModel): 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) - to_reset = [v for v in views if v.model_data_id.noupdate is True] + 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: logger.warn("403 Forbidden:\n\n%s", values['traceback']) diff --git a/addons/website/static/src/js/website.editor.js b/addons/website/static/src/js/website.editor.js index f15278ee49f..60076b9664b 100644 --- a/addons/website/static/src/js/website.editor.js +++ b/addons/website/static/src/js/website.editor.js @@ -356,7 +356,13 @@ observer.disconnect(); var editor = this.rte.editor; var root = editor.element && editor.element.$; - editor.destroy(); + try { + editor.destroy(); + } + catch(err) { + // Hack to avoid the lost of all changes because ckeditor fails in destroy + console.log("Error in editor.destroy() : " + err.toString() + "\n " + err.stack); + } // FIXME: select editables then filter by dirty? var defs = this.rte.fetch_editables(root) .filter('.oe_dirty') diff --git a/addons/website_blog/models/website_blog.py b/addons/website_blog/models/website_blog.py index 9953b5f1ac8..5cb6f82e610 100644 --- a/addons/website_blog/models/website_blog.py +++ b/addons/website_blog/models/website_blog.py @@ -58,7 +58,7 @@ class BlogPost(osv.Model): 'tag_ids': fields.many2many( 'blog.tag', string='Tags', ), - 'content': fields.html('Content', translate=True), + 'content': fields.html('Content', translate=True, sanitize=False), # website control 'website_published': fields.boolean( 'Publish', help="Publish on the website", copy=False, diff --git a/addons/website_crm/controllers/main.py b/addons/website_crm/controllers/main.py index 5e2d8e75866..d8d437bc045 100644 --- a/addons/website_crm/controllers/main.py +++ b/addons/website_crm/controllers/main.py @@ -25,10 +25,19 @@ class contactus(http.Controller): values.update(kwargs=kwargs.items()) return request.website.render("website.contactus", values) - def create_lead(self, request, values): + def create_lead(self, request, values, kwargs): """ Allow to be overrided """ return request.registry['crm.lead'].create(request.cr, SUPERUSER_ID, values, request.context) + def preRenderThanks(self, request, values, kwargs): + """ Allow to be overrided """ + company = request.website.company_id + return { + 'google_map_url': self.generate_google_map_url(company.street, company.city, company.zip, company.country_id and company.country_id.name_get()[0][1] or ''), + '_values': values, + '_kwargs': kwargs, + } + @http.route(['/crm/contactus'], type='http', auth="public", website=True) def contactus(self, **kwargs): def dict_to_str(title, dictvar): @@ -37,7 +46,7 @@ class contactus(http.Controller): ret += "\n%s" % field return ret - _TECHNICAL = ['show_info'] # Only use for behavior, don't stock it + _TECHNICAL = ['show_info', 'view_from', 'view_callback'] # Only use for behavior, don't stock it _BLACKLIST = ['id', 'create_uid', 'create_date', 'write_uid', 'write_date', 'user_id', 'active'] # Allow in description _REQUIRED = ['name', 'contact_name', 'email_from', 'description'] # Could be improved including required from model @@ -56,12 +65,12 @@ class contactus(http.Controller): if "name" not in kwargs and values.get("contact_name"): # if kwarg.name is empty, it's an error, we cannot copy the contact_name values["name"] = values.get("contact_name") # fields validation : Check that required field from model crm_lead exists - error = set(field for field in _REQUIRED if not kwargs.get(field)) + error = set(field for field in _REQUIRED if not values.get(field)) values = dict(values, error=error) if error: values.update(kwargs=kwargs.items()) - return request.website.render("website.contactus", values) + return request.website.render(kwargs.get("view_from", "website.contactus"), values) try: values['medium_id'] = request.registry['ir.model.data'].get_object_reference(request.cr, SUPERUSER_ID, 'crm', 'crm_tracking_medium_website')[1] @@ -82,7 +91,7 @@ class contactus(http.Controller): post_description.append("%s: %s" % ("REFERER", environ.get("HTTP_REFERER"))) values['description'] += dict_to_str(_("Environ Fields: "), post_description) - lead_id = self.create_lead(request, dict(values, user_id=False)) + lead_id = self.create_lead(request, dict(values, user_id=False), kwargs) if lead_id: for field_value in post_file: attachment_value = { @@ -95,8 +104,5 @@ class contactus(http.Controller): } request.registry['ir.attachment'].create(request.cr, SUPERUSER_ID, attachment_value, context=request.context) - company = request.website.company_id - values = { - 'google_map_url': self.generate_google_map_url(company.street, company.city, company.zip, company.country_id and company.country_id.name_get()[0][1] or ''), - } - return request.website.render("website_crm.contactus_thanks", values) + values = self.preRenderThanks(request, values, kwargs) + return request.website.render(kwargs.get("view_callback", "website_crm.contactus_thanks"), values) diff --git a/addons/website_membership/controllers/main.py b/addons/website_membership/controllers/main.py index 9947eab4d98..c88fb43da9d 100644 --- a/addons/website_membership/controllers/main.py +++ b/addons/website_membership/controllers/main.py @@ -48,7 +48,7 @@ class WebsiteMembership(http.Controller): ('partner.website_description', 'ilike', post_name)] # group by country, based on all customers (base domain) - membership_line_ids = membership_line_obj.search(cr, uid, base_line_domain, context=context) + membership_line_ids = membership_line_obj.search(cr, SUPERUSER_ID, base_line_domain, context=context) countries = partner_obj.read_group( cr, uid, [('member_lines', 'in', membership_line_ids), ("website_published", "=", True)], ["id", "country_id"], groupby="country_id", orderby="country_id", context=request.context) @@ -70,8 +70,14 @@ class WebsiteMembership(http.Controller): 'country_id': (0, _("All Countries")) }) + # format domain for group_by and memberships + membership_ids = product_obj.search(cr, uid, [('membership', '=', True)], order="website_sequence", context=context) + memberships = product_obj.browse(cr, uid, membership_ids, context=context) + # make sure we don't access to lines with unpublished membershipts + line_domain.append(('membership_id', 'in', membership_ids)) + # displayed membership lines - membership_line_ids = membership_line_obj.search(cr, uid, line_domain, context=context) + membership_line_ids = membership_line_obj.search(cr, SUPERUSER_ID, line_domain, context=context) membership_lines = membership_line_obj.browse(cr, uid, membership_line_ids, context=context) membership_lines = sorted(membership_lines, key=lambda x: x.membership_id.website_sequence) partner_ids = [m.partner.id for m in membership_lines] @@ -79,10 +85,6 @@ class WebsiteMembership(http.Controller): partners = dict((p.id, p) for p in partner_obj.browse(request.cr, SUPERUSER_ID, partner_ids, request.context)) - # format domain for group_by and memberships - membership_ids = product_obj.search(cr, uid, [('membership', '=', True)], order="website_sequence", context=context) - memberships = product_obj.browse(cr, uid, membership_ids, context=context) - # request pager for lines pager = request.website.pager(url="/members", total=len(membership_line_ids), page=page, step=self._references_per_page, scope=7, url_args=post) diff --git a/openerp/addons/base/ir/ir_fields.py b/openerp/addons/base/ir/ir_fields.py index 79ede18e4ed..494111d812c 100644 --- a/openerp/addons/base/ir/ir_fields.py +++ b/openerp/addons/base/ir/ir_fields.py @@ -11,7 +11,8 @@ import pytz from openerp.osv import orm from openerp.tools.translate import _ from openerp.tools.misc import DEFAULT_SERVER_DATE_FORMAT,\ - DEFAULT_SERVER_DATETIME_FORMAT + DEFAULT_SERVER_DATETIME_FORMAT,\ + ustr from openerp.tools import html_sanitize REFERENCING_FIELDS = set([None, 'id', '.id']) @@ -263,6 +264,7 @@ class ir_fields_converter(orm.Model): # Or just copy context & remove lang? selection = selection(model, cr, uid, context=None) for item, label in selection: + label = ustr(label) labels = self._get_translations( cr, uid, ('selection', 'model', 'code'), label, context=context) labels.append(label) @@ -271,8 +273,8 @@ class ir_fields_converter(orm.Model): raise ValueError( _(u"Value '%s' not found in selection field '%%(field)s'") % ( value), { - 'moreinfo': [label or unicode(item) for item, label in selection - if label or item] + 'moreinfo': [_label or unicode(item) for item, _label in selection + if _label or item] }) diff --git a/openerp/addons/base/ir/ir_values.py b/openerp/addons/base/ir/ir_values.py index f34f02a8aec..4720f601f49 100644 --- a/openerp/addons/base/ir/ir_values.py +++ b/openerp/addons/base/ir/ir_values.py @@ -319,10 +319,10 @@ class ir_values(osv.osv): (SELECT company_id from res_users where id = %%s) ) %s - ORDER BY v.user_id, u.company_id, v.key2""" + ORDER BY v.user_id, u.company_id""" params = ('default', model, uid, uid) if condition: - query %= 'AND (v.key2 = %s OR v.key2 IS NULL)' + query %= 'AND v.key2 = %s' params += (condition[:200],) else: query %= 'AND v.key2 is NULL' diff --git a/openerp/tools/safe_eval.py b/openerp/tools/safe_eval.py index 94d417c9e84..2d548fff406 100644 --- a/openerp/tools/safe_eval.py +++ b/openerp/tools/safe_eval.py @@ -72,7 +72,7 @@ _SAFE_OPCODES = _EXPR_OPCODES.union(set(opmap[x] for x in [ # New in Python 2.7 - http://bugs.python.org/issue4715 : 'JUMP_IF_FALSE_OR_POP', 'JUMP_IF_TRUE_OR_POP', 'POP_JUMP_IF_FALSE', 'POP_JUMP_IF_TRUE', 'SETUP_EXCEPT', 'END_FINALLY', - 'LOAD_FAST', 'STORE_FAST', 'DELETE_FAST', + 'LOAD_FAST', 'STORE_FAST', 'DELETE_FAST', 'UNPACK_SEQUENCE', 'LOAD_GLOBAL', # Only allows access to restricted globals ] if x in opmap)) @@ -300,6 +300,7 @@ def safe_eval(expr, globals_dict=None, locals_dict=None, mode="eval", nocopy=Fal 'range': range, 'xrange': xrange, 'zip': zip, + 'Exception': Exception, } ) if locals_builtins: diff --git a/openerp/tools/translate.py b/openerp/tools/translate.py index 25ee4218d0f..a487b3dd9e3 100644 --- a/openerp/tools/translate.py +++ b/openerp/tools/translate.py @@ -796,7 +796,7 @@ def trans_generate(lang, modules, cr): for bin_path in ['osv', 'report' ]: path_list.append(os.path.join(config.config['root_path'], bin_path)) - _logger.debug("Scanning modules at paths: ", path_list) + _logger.debug("Scanning modules at paths: %s", path_list) mod_paths = list(path_list)