From 071144b0acccae94ecc7dc818a1a9f75cc3f9ed2 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Tue, 8 Dec 2015 14:59:20 +0100 Subject: [PATCH 01/96] [FIX] mass_mailing,crm_mass_mailing: exclude opt-out By default, when changing the recipients type of a mass-mailing to partners or leads, the selected records included the opt-out records. To be consistent, as: - `opt-out` records are excluded by default for mass mailing contacts - the filter excluding the opt-out records `Available for mass-mailing` is loaded by default when changing the selection in the selection list dialog The domain for partners and leads should exclude opt-out records by default. opw-658391 --- addons/crm_mass_mailing/mass_mailing.py | 8 ++++++++ addons/mass_mailing/models/mass_mailing.py | 2 ++ 2 files changed, 10 insertions(+) diff --git a/addons/crm_mass_mailing/mass_mailing.py b/addons/crm_mass_mailing/mass_mailing.py index 6a2e1322136..20b7b4db86d 100644 --- a/addons/crm_mass_mailing/mass_mailing.py +++ b/addons/crm_mass_mailing/mass_mailing.py @@ -4,3 +4,11 @@ from openerp.osv import osv class MassMailing(osv.Model): _name = 'mail.mass_mailing' _inherit = ['mail.mass_mailing', 'crm.tracking.mixin'] + + def on_change_model_and_list(self, cr, uid, ids, mailing_model, list_ids, context=None): + res = super(MassMailing, self).on_change_model_and_list(cr, uid, ids, mailing_model, list_ids, context=context) + if mailing_model == 'crm.lead': + res = res or {} + values = {'mailing_domain': "[('opt_out', '=', False)]"} + res = dict(res, value=dict(res.get('value', {}), **values)) + return res diff --git a/addons/mass_mailing/models/mass_mailing.py b/addons/mass_mailing/models/mass_mailing.py index 4e42f335b1b..f496736eb22 100644 --- a/addons/mass_mailing/models/mass_mailing.py +++ b/addons/mass_mailing/models/mass_mailing.py @@ -517,6 +517,8 @@ class MassMailing(osv.Model): value['mailing_domain'] = "[('list_id', 'in', %s), ('opt_out', '=', False)]" % list(mailing_list_ids) else: value['mailing_domain'] = "[('list_id', '=', False)]" + elif mailing_model in ['res.partner']: + value['mailing_domain'] = "[('opt_out', '=', False)]" else: value['mailing_domain'] = [] return {'value': value} From 2939800ed438505be9c919d4edca0ce624e6bf8e Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Tue, 8 Dec 2015 15:04:35 +0100 Subject: [PATCH 02/96] [FIX] web: char_domain widget re-renders on model change Before this revision, the `char_domain` re-rendered its display only when its domain value was changed. It must re-render as well when the model on which this domain is applied is changed, as the number of records can obviously be different. e.g., in mass-mailing, when changing the recipients type from partners to leads, the domain doesn't change, it stays `['opt_out', '=', False]`, but the model on which this domain is applied does change, as well as the number of selected records. opw-658391 --- addons/web/static/src/js/view_form.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index e660d31292e..2766b9bb5e6 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -2566,6 +2566,15 @@ instance.web.form.FieldCharDomain = instance.web.form.AbstractField.extend(insta this.on("change:effective_readonly", this, function () { this.display_field(); }); + if (this.options.model_field){ + this.field_manager.fields[this.options.model_field].on("change:value", this, function(){ + if (self.view && self.view.onchanges_mutex){ + self.view.onchanges_mutex.def.then(function(){ + self.display_field(); + }); + } + }); + } this.display_field(); return this._super(); }, From 7f20b791881dc79d8ee99479b30a529cea59811c Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Tue, 8 Dec 2015 15:08:36 +0100 Subject: [PATCH 03/96] [FIX] web: char_domain display translation The `records selected` could not be translated. --- addons/web/static/src/js/view_form.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 2766b9bb5e6..ae2cac633ff 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -2591,7 +2591,7 @@ instance.web.form.FieldCharDomain = instance.web.form.AbstractField.extend(insta var domain = instance.web.pyeval.eval('domain', this.get('value')); var ds = new instance.web.DataSetStatic(self, model, self.build_context()); ds.call('search_count', [domain, self.build_context()]).then(function (results) { - $('.oe_domain_count', self.$el).text(results + ' records selected'); + $('.oe_domain_count', self.$el).text(results + _t(' records selected')); if (self.get('effective_readonly')) { $('button span', self.$el).text(' See selection'); } From a148e2a47a347e61004f21c1daf8db55c8fc1eb1 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Tue, 8 Dec 2015 16:13:55 +0100 Subject: [PATCH 04/96] [FIX] sale: team bar values for sent quotations The "Quotation" bar in the sales team dashboard excluded sent quotation, it only included draft quotation. A `sale.order` in the state `sent` must be considered as a quotation, the only different is that it has been sent by mail to the customer, that's all. opw-658861 --- addons/sale/sales_team.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/sale/sales_team.py b/addons/sale/sales_team.py index a9f8fa6b482..d80fe387300 100644 --- a/addons/sale/sales_team.py +++ b/addons/sale/sales_team.py @@ -21,7 +21,7 @@ class crm_case_section(osv.osv): res = {} for id in ids: res[id] = {} - created_domain = [('section_id', '=', id), ('state', '=', 'draft'), ('date_order', '>=', date_begin), ('date_order', '<=', date_end)] + created_domain = [('section_id', '=', id), ('state', 'in', ['draft', 'sent']), ('date_order', '>=', date_begin), ('date_order', '<=', date_end)] validated_domain = [('section_id', '=', id), ('state', 'not in', ['draft', 'sent', 'cancel']), ('date_order', '>=', date_begin), ('date_order', '<=', date_end)] res[id]['monthly_quoted'] = json.dumps(self.__get_bar_values(cr, uid, obj, created_domain, ['amount_total', 'date_order'], 'amount_total', 'date_order', context=context)) res[id]['monthly_confirmed'] = json.dumps(self.__get_bar_values(cr, uid, obj, validated_domain, ['amount_untaxed', 'date_order'], 'amount_untaxed', 'date_order', context=context)) From 6cdcdb872424a2ae47d12ee4d4917169dfd5856f Mon Sep 17 00:00:00 2001 From: Antonio Espinosa Date: Fri, 4 Dec 2015 03:02:11 +0100 Subject: [PATCH 05/96] [FIX] web: datejs Spanish long format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From: miércoles, 04' 4e 'noviembre' 4e '2015 10:48:19 To: miércoles, 04 de noviembre de 2015 10:48:19 Closes #9910 --- addons/web/static/lib/datejs/globalization/es-AR.js | 6 +++--- addons/web/static/lib/datejs/globalization/es-BO.js | 6 +++--- addons/web/static/lib/datejs/globalization/es-CL.js | 6 +++--- addons/web/static/lib/datejs/globalization/es-CO.js | 6 +++--- addons/web/static/lib/datejs/globalization/es-CR.js | 6 +++--- addons/web/static/lib/datejs/globalization/es-DO.js | 6 +++--- addons/web/static/lib/datejs/globalization/es-EC.js | 6 +++--- addons/web/static/lib/datejs/globalization/es-ES.js | 6 +++--- addons/web/static/lib/datejs/globalization/es-GT.js | 6 +++--- addons/web/static/lib/datejs/globalization/es-HN.js | 6 +++--- addons/web/static/lib/datejs/globalization/es-MX.js | 6 +++--- addons/web/static/lib/datejs/globalization/es-NI.js | 6 +++--- addons/web/static/lib/datejs/globalization/es-PA.js | 6 +++--- addons/web/static/lib/datejs/globalization/es-PE.js | 6 +++--- addons/web/static/lib/datejs/globalization/es-PR.js | 6 +++--- addons/web/static/lib/datejs/globalization/es-PY.js | 6 +++--- addons/web/static/lib/datejs/globalization/es-SV.js | 6 +++--- addons/web/static/lib/datejs/globalization/es-UY.js | 6 +++--- addons/web/static/lib/datejs/globalization/es-VE.js | 6 +++--- addons/web/static/lib/datejs/globalization/gl-ES.js | 6 +++--- addons/web/static/lib/datejs/globalization/pt-BR.js | 8 ++++---- addons/web/static/lib/datejs/globalization/pt-PT.js | 6 +++--- addons/web/static/lib/datejs/globalization/quz-BO.js | 6 +++--- addons/web/static/lib/datejs/globalization/quz-EC.js | 6 +++--- addons/web/static/lib/datejs/globalization/quz-PE.js | 6 +++--- 25 files changed, 76 insertions(+), 76 deletions(-) diff --git a/addons/web/static/lib/datejs/globalization/es-AR.js b/addons/web/static/lib/datejs/globalization/es-AR.js index 6fb5e6b0e02..06272f116e0 100644 --- a/addons/web/static/lib/datejs/globalization/es-AR.js +++ b/addons/web/static/lib/datejs/globalization/es-AR.js @@ -43,15 +43,15 @@ Date.CultureInfo = { /* Standard date and time format patterns */ formatPatterns: { shortDate: "dd/MM/yyyy", - longDate: "dddd, dd' de 'MMMM' de 'yyyy", + longDate: "dddd, dd \\de MMMM \\de yyyy", shortTime: "hh:mm tt", longTime: "hh:mm:ss tt", - fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", + fullDateTime: "dddd, dd \\de MMMM \\de yyyy hh:mm:ss tt", sortableDateTime: "yyyy-MM-ddTHH:mm:ss", universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ", rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT", monthDay: "dd MMMM", - yearMonth: "MMMM' de 'yyyy" + yearMonth: "MMMM \\de yyyy" }, /** diff --git a/addons/web/static/lib/datejs/globalization/es-BO.js b/addons/web/static/lib/datejs/globalization/es-BO.js index c2d422919b2..6d075fde1be 100644 --- a/addons/web/static/lib/datejs/globalization/es-BO.js +++ b/addons/web/static/lib/datejs/globalization/es-BO.js @@ -43,15 +43,15 @@ Date.CultureInfo = { /* Standard date and time format patterns */ formatPatterns: { shortDate: "dd/MM/yyyy", - longDate: "dddd, dd' de 'MMMM' de 'yyyy", + longDate: "dddd, dd \\de MMMM \\de yyyy", shortTime: "hh:mm tt", longTime: "hh:mm:ss tt", - fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", + fullDateTime: "dddd, dd \\de MMMM \\de yyyy hh:mm:ss tt", sortableDateTime: "yyyy-MM-ddTHH:mm:ss", universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ", rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT", monthDay: "dd MMMM", - yearMonth: "MMMM' de 'yyyy" + yearMonth: "MMMM \\de yyyy" }, /** diff --git a/addons/web/static/lib/datejs/globalization/es-CL.js b/addons/web/static/lib/datejs/globalization/es-CL.js index 8cf18922932..2aad3d99986 100644 --- a/addons/web/static/lib/datejs/globalization/es-CL.js +++ b/addons/web/static/lib/datejs/globalization/es-CL.js @@ -43,15 +43,15 @@ Date.CultureInfo = { /* Standard date and time format patterns */ formatPatterns: { shortDate: "dd-MM-yyyy", - longDate: "dddd, dd' de 'MMMM' de 'yyyy", + longDate: "dddd, dd \\de MMMM \\de yyyy", shortTime: "H:mm", longTime: "H:mm:ss", - fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy H:mm:ss", + fullDateTime: "dddd, dd \\de MMMM \\de yyyy H:mm:ss", sortableDateTime: "yyyy-MM-ddTHH:mm:ss", universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ", rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT", monthDay: "dd MMMM", - yearMonth: "MMMM' de 'yyyy" + yearMonth: "MMMM \\de yyyy" }, /** diff --git a/addons/web/static/lib/datejs/globalization/es-CO.js b/addons/web/static/lib/datejs/globalization/es-CO.js index 7d4cbfa5bf3..423c3098116 100644 --- a/addons/web/static/lib/datejs/globalization/es-CO.js +++ b/addons/web/static/lib/datejs/globalization/es-CO.js @@ -43,15 +43,15 @@ Date.CultureInfo = { /* Standard date and time format patterns */ formatPatterns: { shortDate: "dd/MM/yyyy", - longDate: "dddd, dd' de 'MMMM' de 'yyyy", + longDate: "dddd, dd \\de MMMM \\de yyyy", shortTime: "hh:mm tt", longTime: "hh:mm:ss tt", - fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", + fullDateTime: "dddd, dd \\de MMMM \\de yyyy hh:mm:ss tt", sortableDateTime: "yyyy-MM-ddTHH:mm:ss", universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ", rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT", monthDay: "dd MMMM", - yearMonth: "MMMM' de 'yyyy" + yearMonth: "MMMM \\de yyyy" }, /** diff --git a/addons/web/static/lib/datejs/globalization/es-CR.js b/addons/web/static/lib/datejs/globalization/es-CR.js index 1a5012c14e7..b39ff0d0409 100644 --- a/addons/web/static/lib/datejs/globalization/es-CR.js +++ b/addons/web/static/lib/datejs/globalization/es-CR.js @@ -43,15 +43,15 @@ Date.CultureInfo = { /* Standard date and time format patterns */ formatPatterns: { shortDate: "dd/MM/yyyy", - longDate: "dddd, dd' de 'MMMM' de 'yyyy", + longDate: "dddd, dd \\de MMMM \\de yyyy", shortTime: "hh:mm tt", longTime: "hh:mm:ss tt", - fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", + fullDateTime: "dddd, dd \\de MMMM \\de yyyy hh:mm:ss tt", sortableDateTime: "yyyy-MM-ddTHH:mm:ss", universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ", rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT", monthDay: "dd MMMM", - yearMonth: "MMMM' de 'yyyy" + yearMonth: "MMMM \\de yyyy" }, /** diff --git a/addons/web/static/lib/datejs/globalization/es-DO.js b/addons/web/static/lib/datejs/globalization/es-DO.js index 2ff8a2ea531..e7bd89d0f33 100644 --- a/addons/web/static/lib/datejs/globalization/es-DO.js +++ b/addons/web/static/lib/datejs/globalization/es-DO.js @@ -43,15 +43,15 @@ Date.CultureInfo = { /* Standard date and time format patterns */ formatPatterns: { shortDate: "dd/MM/yyyy", - longDate: "dddd, dd' de 'MMMM' de 'yyyy", + longDate: "dddd, dd \\de MMMM \\de yyyy", shortTime: "hh:mm tt", longTime: "hh:mm:ss tt", - fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", + fullDateTime: "dddd, dd \\de MMMM \\de yyyy hh:mm:ss tt", sortableDateTime: "yyyy-MM-ddTHH:mm:ss", universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ", rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT", monthDay: "dd MMMM", - yearMonth: "MMMM' de 'yyyy" + yearMonth: "MMMM \\de yyyy" }, /** diff --git a/addons/web/static/lib/datejs/globalization/es-EC.js b/addons/web/static/lib/datejs/globalization/es-EC.js index 9847d0c6d35..fa51ec5f14f 100644 --- a/addons/web/static/lib/datejs/globalization/es-EC.js +++ b/addons/web/static/lib/datejs/globalization/es-EC.js @@ -43,15 +43,15 @@ Date.CultureInfo = { /* Standard date and time format patterns */ formatPatterns: { shortDate: "dd/MM/yyyy", - longDate: "dddd, dd' de 'MMMM' de 'yyyy", + longDate: "dddd, dd \\de MMMM \\de yyyy", shortTime: "H:mm", longTime: "H:mm:ss", - fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy H:mm:ss", + fullDateTime: "dddd, dd \\de MMMM \\de yyyy H:mm:ss", sortableDateTime: "yyyy-MM-ddTHH:mm:ss", universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ", rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT", monthDay: "dd MMMM", - yearMonth: "MMMM' de 'yyyy" + yearMonth: "MMMM \\de yyyy" }, /** diff --git a/addons/web/static/lib/datejs/globalization/es-ES.js b/addons/web/static/lib/datejs/globalization/es-ES.js index 91e7183dd8d..94094c7558f 100644 --- a/addons/web/static/lib/datejs/globalization/es-ES.js +++ b/addons/web/static/lib/datejs/globalization/es-ES.js @@ -43,15 +43,15 @@ Date.CultureInfo = { /* Standard date and time format patterns */ formatPatterns: { shortDate: "dd/MM/yyyy", - longDate: "dddd, dd' de 'MMMM' de 'yyyy", + longDate: "dddd, dd \\de MMMM \\de yyyy", shortTime: "H:mm", longTime: "H:mm:ss", - fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy H:mm:ss", + fullDateTime: "dddd, dd \\de MMMM \\de yyyy H:mm:ss", sortableDateTime: "yyyy-MM-ddTHH:mm:ss", universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ", rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT", monthDay: "dd MMMM", - yearMonth: "MMMM' de 'yyyy" + yearMonth: "MMMM \\de yyyy" }, /** diff --git a/addons/web/static/lib/datejs/globalization/es-GT.js b/addons/web/static/lib/datejs/globalization/es-GT.js index 7a7edaf863f..7cebc570470 100644 --- a/addons/web/static/lib/datejs/globalization/es-GT.js +++ b/addons/web/static/lib/datejs/globalization/es-GT.js @@ -43,15 +43,15 @@ Date.CultureInfo = { /* Standard date and time format patterns */ formatPatterns: { shortDate: "dd/MM/yyyy", - longDate: "dddd, dd' de 'MMMM' de 'yyyy", + longDate: "dddd, dd \\de MMMM \\de yyyy", shortTime: "hh:mm tt", longTime: "hh:mm:ss tt", - fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", + fullDateTime: "dddd, dd \\de MMMM \\de yyyy hh:mm:ss tt", sortableDateTime: "yyyy-MM-ddTHH:mm:ss", universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ", rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT", monthDay: "dd MMMM", - yearMonth: "MMMM' de 'yyyy" + yearMonth: "MMMM \\de yyyy" }, /** diff --git a/addons/web/static/lib/datejs/globalization/es-HN.js b/addons/web/static/lib/datejs/globalization/es-HN.js index c1dc596ee87..267b56ec4f3 100644 --- a/addons/web/static/lib/datejs/globalization/es-HN.js +++ b/addons/web/static/lib/datejs/globalization/es-HN.js @@ -43,15 +43,15 @@ Date.CultureInfo = { /* Standard date and time format patterns */ formatPatterns: { shortDate: "dd/MM/yyyy", - longDate: "dddd, dd' de 'MMMM' de 'yyyy", + longDate: "dddd, dd \\de MMMM \\de yyyy", shortTime: "hh:mm tt", longTime: "hh:mm:ss tt", - fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", + fullDateTime: "dddd, dd \\de MMMM \\de yyyy hh:mm:ss tt", sortableDateTime: "yyyy-MM-ddTHH:mm:ss", universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ", rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT", monthDay: "dd MMMM", - yearMonth: "MMMM' de 'yyyy" + yearMonth: "MMMM \\de yyyy" }, /** diff --git a/addons/web/static/lib/datejs/globalization/es-MX.js b/addons/web/static/lib/datejs/globalization/es-MX.js index 52ef0ab2b12..677c34ee0dc 100644 --- a/addons/web/static/lib/datejs/globalization/es-MX.js +++ b/addons/web/static/lib/datejs/globalization/es-MX.js @@ -43,15 +43,15 @@ Date.CultureInfo = { /* Standard date and time format patterns */ formatPatterns: { shortDate: "dd/MM/yyyy", - longDate: "dddd, dd' de 'MMMM' de 'yyyy", + longDate: "dddd, dd \\de MMMM \\de yyyy", shortTime: "hh:mm tt", longTime: "hh:mm:ss tt", - fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", + fullDateTime: "dddd, dd \\de MMMM \\de yyyy hh:mm:ss tt", sortableDateTime: "yyyy-MM-ddTHH:mm:ss", universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ", rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT", monthDay: "dd MMMM", - yearMonth: "MMMM' de 'yyyy" + yearMonth: "MMMM \\de yyyy" }, /** diff --git a/addons/web/static/lib/datejs/globalization/es-NI.js b/addons/web/static/lib/datejs/globalization/es-NI.js index 850dbcb6abb..74cf8ef6e9d 100644 --- a/addons/web/static/lib/datejs/globalization/es-NI.js +++ b/addons/web/static/lib/datejs/globalization/es-NI.js @@ -43,15 +43,15 @@ Date.CultureInfo = { /* Standard date and time format patterns */ formatPatterns: { shortDate: "dd/MM/yyyy", - longDate: "dddd, dd' de 'MMMM' de 'yyyy", + longDate: "dddd, dd \\de MMMM \\de yyyy", shortTime: "hh:mm tt", longTime: "hh:mm:ss tt", - fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", + fullDateTime: "dddd, dd \\de MMMM \\de yyyy hh:mm:ss tt", sortableDateTime: "yyyy-MM-ddTHH:mm:ss", universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ", rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT", monthDay: "dd MMMM", - yearMonth: "MMMM' de 'yyyy" + yearMonth: "MMMM \\de yyyy" }, /** diff --git a/addons/web/static/lib/datejs/globalization/es-PA.js b/addons/web/static/lib/datejs/globalization/es-PA.js index 85351d74dc2..b7d0e95f3d4 100644 --- a/addons/web/static/lib/datejs/globalization/es-PA.js +++ b/addons/web/static/lib/datejs/globalization/es-PA.js @@ -43,15 +43,15 @@ Date.CultureInfo = { /* Standard date and time format patterns */ formatPatterns: { shortDate: "MM/dd/yyyy", - longDate: "dddd, dd' de 'MMMM' de 'yyyy", + longDate: "dddd, dd \\de MMMM \\de yyyy", shortTime: "hh:mm tt", longTime: "hh:mm:ss tt", - fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", + fullDateTime: "dddd, dd \\de MMMM \\de yyyy hh:mm:ss tt", sortableDateTime: "yyyy-MM-ddTHH:mm:ss", universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ", rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT", monthDay: "dd MMMM", - yearMonth: "MMMM' de 'yyyy" + yearMonth: "MMMM \\de yyyy" }, /** diff --git a/addons/web/static/lib/datejs/globalization/es-PE.js b/addons/web/static/lib/datejs/globalization/es-PE.js index 3084ad4c120..9bbb5b54115 100644 --- a/addons/web/static/lib/datejs/globalization/es-PE.js +++ b/addons/web/static/lib/datejs/globalization/es-PE.js @@ -43,15 +43,15 @@ Date.CultureInfo = { /* Standard date and time format patterns */ formatPatterns: { shortDate: "dd/MM/yyyy", - longDate: "dddd, dd' de 'MMMM' de 'yyyy", + longDate: "dddd, dd \\de MMMM \\de yyyy", shortTime: "hh:mm tt", longTime: "hh:mm:ss tt", - fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", + fullDateTime: "dddd, dd \\de MMMM \\de yyyy hh:mm:ss tt", sortableDateTime: "yyyy-MM-ddTHH:mm:ss", universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ", rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT", monthDay: "dd MMMM", - yearMonth: "MMMM' de 'yyyy" + yearMonth: "MMMM \\de yyyy" }, /** diff --git a/addons/web/static/lib/datejs/globalization/es-PR.js b/addons/web/static/lib/datejs/globalization/es-PR.js index a1c86c413c9..689721df732 100644 --- a/addons/web/static/lib/datejs/globalization/es-PR.js +++ b/addons/web/static/lib/datejs/globalization/es-PR.js @@ -43,15 +43,15 @@ Date.CultureInfo = { /* Standard date and time format patterns */ formatPatterns: { shortDate: "dd/MM/yyyy", - longDate: "dddd, dd' de 'MMMM' de 'yyyy", + longDate: "dddd, dd \\de MMMM \\de yyyy", shortTime: "hh:mm tt", longTime: "hh:mm:ss tt", - fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", + fullDateTime: "dddd, dd \\de MMMM \\de yyyy hh:mm:ss tt", sortableDateTime: "yyyy-MM-ddTHH:mm:ss", universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ", rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT", monthDay: "dd MMMM", - yearMonth: "MMMM' de 'yyyy" + yearMonth: "MMMM \\de yyyy" }, /** diff --git a/addons/web/static/lib/datejs/globalization/es-PY.js b/addons/web/static/lib/datejs/globalization/es-PY.js index 96f61aeeced..d44215d801b 100644 --- a/addons/web/static/lib/datejs/globalization/es-PY.js +++ b/addons/web/static/lib/datejs/globalization/es-PY.js @@ -43,15 +43,15 @@ Date.CultureInfo = { /* Standard date and time format patterns */ formatPatterns: { shortDate: "dd/MM/yyyy", - longDate: "dddd, dd' de 'MMMM' de 'yyyy", + longDate: "dddd, dd \\de MMMM \\de yyyy", shortTime: "hh:mm tt", longTime: "hh:mm:ss tt", - fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", + fullDateTime: "dddd, dd \\de MMMM \\de yyyy hh:mm:ss tt", sortableDateTime: "yyyy-MM-ddTHH:mm:ss", universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ", rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT", monthDay: "dd MMMM", - yearMonth: "MMMM' de 'yyyy" + yearMonth: "MMMM \\de yyyy" }, /** diff --git a/addons/web/static/lib/datejs/globalization/es-SV.js b/addons/web/static/lib/datejs/globalization/es-SV.js index f92011935e4..e124c2f4017 100644 --- a/addons/web/static/lib/datejs/globalization/es-SV.js +++ b/addons/web/static/lib/datejs/globalization/es-SV.js @@ -43,15 +43,15 @@ Date.CultureInfo = { /* Standard date and time format patterns */ formatPatterns: { shortDate: "dd/MM/yyyy", - longDate: "dddd, dd' de 'MMMM' de 'yyyy", + longDate: "dddd, dd \\de MMMM \\de yyyy", shortTime: "hh:mm tt", longTime: "hh:mm:ss tt", - fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", + fullDateTime: "dddd, dd \\de MMMM \\de yyyy hh:mm:ss tt", sortableDateTime: "yyyy-MM-ddTHH:mm:ss", universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ", rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT", monthDay: "dd MMMM", - yearMonth: "MMMM' de 'yyyy" + yearMonth: "MMMM \\de yyyy" }, /** diff --git a/addons/web/static/lib/datejs/globalization/es-UY.js b/addons/web/static/lib/datejs/globalization/es-UY.js index dc8ae404a53..a9f7ee51da4 100644 --- a/addons/web/static/lib/datejs/globalization/es-UY.js +++ b/addons/web/static/lib/datejs/globalization/es-UY.js @@ -43,15 +43,15 @@ Date.CultureInfo = { /* Standard date and time format patterns */ formatPatterns: { shortDate: "dd/MM/yyyy", - longDate: "dddd, dd' de 'MMMM' de 'yyyy", + longDate: "dddd, dd \\de MMMM \\de yyyy", shortTime: "hh:mm tt", longTime: "hh:mm:ss tt", - fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", + fullDateTime: "dddd, dd \\de MMMM \\de yyyy hh:mm:ss tt", sortableDateTime: "yyyy-MM-ddTHH:mm:ss", universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ", rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT", monthDay: "dd MMMM", - yearMonth: "MMMM' de 'yyyy" + yearMonth: "MMMM \\de yyyy" }, /** diff --git a/addons/web/static/lib/datejs/globalization/es-VE.js b/addons/web/static/lib/datejs/globalization/es-VE.js index 087110fb229..cfd2601d2bd 100644 --- a/addons/web/static/lib/datejs/globalization/es-VE.js +++ b/addons/web/static/lib/datejs/globalization/es-VE.js @@ -43,15 +43,15 @@ Date.CultureInfo = { /* Standard date and time format patterns */ formatPatterns: { shortDate: "dd/MM/yyyy", - longDate: "dddd, dd' de 'MMMM' de 'yyyy", + longDate: "dddd, dd \\de MMMM \\de yyyy", shortTime: "hh:mm tt", longTime: "hh:mm:ss tt", - fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", + fullDateTime: "dddd, dd \\de MMMM \\de yyyy hh:mm:ss tt", sortableDateTime: "yyyy-MM-ddTHH:mm:ss", universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ", rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT", monthDay: "dd MMMM", - yearMonth: "MMMM' de 'yyyy" + yearMonth: "MMMM \\de yyyy" }, /** diff --git a/addons/web/static/lib/datejs/globalization/gl-ES.js b/addons/web/static/lib/datejs/globalization/gl-ES.js index edadc90b9d0..429f1755ab8 100644 --- a/addons/web/static/lib/datejs/globalization/gl-ES.js +++ b/addons/web/static/lib/datejs/globalization/gl-ES.js @@ -43,15 +43,15 @@ Date.CultureInfo = { /* Standard date and time format patterns */ formatPatterns: { shortDate: "dd/MM/yy", - longDate: "dddd, dd' de 'MMMM' de 'yyyy", + longDate: "dddd, dd \\de MMMM \\de yyyy", shortTime: "H:mm", longTime: "H:mm:ss", - fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy H:mm:ss", + fullDateTime: "dddd, dd \\de MMMM \\de yyyy H:mm:ss", sortableDateTime: "yyyy-MM-ddTHH:mm:ss", universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ", rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT", monthDay: "dd MMMM", - yearMonth: "MMMM' de 'yyyy" + yearMonth: "MMMM \\de yyyy" }, /** diff --git a/addons/web/static/lib/datejs/globalization/pt-BR.js b/addons/web/static/lib/datejs/globalization/pt-BR.js index 6313c581d8d..5cc5304a53c 100644 --- a/addons/web/static/lib/datejs/globalization/pt-BR.js +++ b/addons/web/static/lib/datejs/globalization/pt-BR.js @@ -43,15 +43,15 @@ Date.CultureInfo = { /* Standard date and time format patterns */ formatPatterns: { shortDate: "d/M/yyyy", - longDate: "dddd, d' de 'MMMM' de 'yyyy", + longDate: "dddd, d \\de MMMM \\de yyyy", shortTime: "H:mm", longTime: "H:mm:ss", - fullDateTime: "dddd, d' de 'MMMM' de 'yyyy H:mm:ss", + fullDateTime: "dddd, d \\de MMMM \\de yyyy H:mm:ss", sortableDateTime: "yyyy-MM-ddTHH:mm:ss", universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ", rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT", - monthDay: "dd' de 'MMMM", - yearMonth: "MMMM' de 'yyyy" + monthDay: "dd \\de MMMM", + yearMonth: "MMMM \\de yyyy" }, /** diff --git a/addons/web/static/lib/datejs/globalization/pt-PT.js b/addons/web/static/lib/datejs/globalization/pt-PT.js index 6c19c28f5bf..4b11df3b4fd 100644 --- a/addons/web/static/lib/datejs/globalization/pt-PT.js +++ b/addons/web/static/lib/datejs/globalization/pt-PT.js @@ -43,15 +43,15 @@ Date.CultureInfo = { /* Standard date and time format patterns */ formatPatterns: { shortDate: "dd-MM-yyyy", - longDate: "dddd, d' de 'MMMM' de 'yyyy", + longDate: "dddd, d \\de MMMM \\de yyyy", shortTime: "H:mm", longTime: "H:mm:ss", - fullDateTime: "dddd, d' de 'MMMM' de 'yyyy H:mm:ss", + fullDateTime: "dddd, d \\de MMMM \\de yyyy H:mm:ss", sortableDateTime: "yyyy-MM-ddTHH:mm:ss", universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ", rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT", monthDay: "d/M", - yearMonth: "MMMM' de 'yyyy" + yearMonth: "MMMM \\de yyyy" }, /** diff --git a/addons/web/static/lib/datejs/globalization/quz-BO.js b/addons/web/static/lib/datejs/globalization/quz-BO.js index 86f0a4f74d9..61d1127121c 100644 --- a/addons/web/static/lib/datejs/globalization/quz-BO.js +++ b/addons/web/static/lib/datejs/globalization/quz-BO.js @@ -43,15 +43,15 @@ Date.CultureInfo = { /* Standard date and time format patterns */ formatPatterns: { shortDate: "dd/MM/yyyy", - longDate: "dddd, dd' de 'MMMM' de 'yyyy", + longDate: "dddd, dd \\de MMMM \\de yyyy", shortTime: "hh:mm:ss tt", longTime: "hh:mm:ss tt", - fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", + fullDateTime: "dddd, dd \\de MMMM \\de yyyy hh:mm:ss tt", sortableDateTime: "yyyy-MM-ddTHH:mm:ss", universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ", rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT", monthDay: "MMMM dd", - yearMonth: "MMMM' de 'yyyy" + yearMonth: "MMMM \\de yyyy" }, /** diff --git a/addons/web/static/lib/datejs/globalization/quz-EC.js b/addons/web/static/lib/datejs/globalization/quz-EC.js index e72514dd09f..b4185f77c4f 100644 --- a/addons/web/static/lib/datejs/globalization/quz-EC.js +++ b/addons/web/static/lib/datejs/globalization/quz-EC.js @@ -43,15 +43,15 @@ Date.CultureInfo = { /* Standard date and time format patterns */ formatPatterns: { shortDate: "dd/MM/yyyy", - longDate: "dddd, dd' de 'MMMM' de 'yyyy", + longDate: "dddd, dd \\de MMMM \\de yyyy", shortTime: "H:mm:ss", longTime: "H:mm:ss", - fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy H:mm:ss", + fullDateTime: "dddd, dd \\de MMMM \\de yyyy H:mm:ss", sortableDateTime: "yyyy-MM-ddTHH:mm:ss", universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ", rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT", monthDay: "MMMM dd", - yearMonth: "MMMM' de 'yyyy" + yearMonth: "MMMM \\de yyyy" }, /** diff --git a/addons/web/static/lib/datejs/globalization/quz-PE.js b/addons/web/static/lib/datejs/globalization/quz-PE.js index 42c1e5c0c83..2e401827f37 100644 --- a/addons/web/static/lib/datejs/globalization/quz-PE.js +++ b/addons/web/static/lib/datejs/globalization/quz-PE.js @@ -43,15 +43,15 @@ Date.CultureInfo = { /* Standard date and time format patterns */ formatPatterns: { shortDate: "dd/MM/yyyy", - longDate: "dddd, dd' de 'MMMM' de 'yyyy", + longDate: "dddd, dd \\de MMMM \\de yyyy", shortTime: "hh:mm:ss tt", longTime: "hh:mm:ss tt", - fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", + fullDateTime: "dddd, dd \\de MMMM \\de yyyy hh:mm:ss tt", sortableDateTime: "yyyy-MM-ddTHH:mm:ss", universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ", rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT", monthDay: "MMMM dd", - yearMonth: "MMMM' de 'yyyy" + yearMonth: "MMMM \\de yyyy" }, /** From c4fb2c2efc8f9c97eb80e616f508476a75eaa109 Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Tue, 8 Dec 2015 15:57:38 +0100 Subject: [PATCH 06/96] [FIX] account: Test product_id_change Test that when an included tax is mapped by a fiscal position, the included tax must be subtracted to the price of the product. Inspired from 503820acb6d82a85c0c49ac26f7e7f8cd73851dd --- addons/account/tests/__init__.py | 1 + .../account/tests/test_product_id_change.py | 50 +++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 addons/account/tests/test_product_id_change.py diff --git a/addons/account/tests/__init__.py b/addons/account/tests/__init__.py index 75f03b9a8be..d941d95cc53 100644 --- a/addons/account/tests/__init__.py +++ b/addons/account/tests/__init__.py @@ -3,3 +3,4 @@ from . import test_search from . import test_reconciliation from . import test_account_move_closed_period from . import test_fiscal_position +from . import test_product_id_change diff --git a/addons/account/tests/test_product_id_change.py b/addons/account/tests/test_product_id_change.py new file mode 100644 index 00000000000..1bd5154f4ba --- /dev/null +++ b/addons/account/tests/test_product_id_change.py @@ -0,0 +1,50 @@ +from openerp.tests.common import TransactionCase + +class TestProductIdChange(TransactionCase): + """Test that when an included tax is mapped by a fiscal position, the included tax must be + subtracted to the price of the product. + """ + + def setUp(self): + super(TestProductIdChange, self).setUp() + self.fiscal_position_model = self.registry('account.fiscal.position') + self.fiscal_position_tax_model = self.registry('account.fiscal.position.tax') + self.tax_model = self.registry('account.tax') + self.pricelist_model = self.registry('product.pricelist') + self.res_partner_model = self.registry('res.partner') + self.product_tmpl_model = self.registry('product.template') + self.product_model = self.registry('product.product') + self.invoice_line_model = self.registry('account.invoice.line') + + def test_product_id_change(self): + cr, uid = self.cr, self.uid + partner_id = self.res_partner_model.create(cr, uid, dict(name="George")) + tax_include_id = self.tax_model.create(cr, uid, dict(name="Include tax", + type='percent', + amount='0.21', + price_include=True)) + tax_exclude_id = self.tax_model.create(cr, uid, dict(name="Exclude tax", + type='percent', + amount='0.00')) + product_tmpl_id = self.product_tmpl_model.create(cr, uid, dict(name="Voiture", + list_price='121', + standard_price='121', + taxes_id=[(6, 0, [tax_include_id])], + supplier_taxes_id=[(6, 0, [tax_include_id])])) + product_id = self.product_model.create(cr, uid, dict(product_tmpl_id=product_tmpl_id)) + product = self.product_model.browse(cr, uid, [product_id]) + fp_id = self.fiscal_position_model.create(cr, uid, dict(name="fiscal position", + sequence=1)) + fp_tax_id = self.fiscal_position_tax_model.create(cr, uid, dict(position_id=fp_id, + tax_src_id=tax_include_id, + tax_dest_id=tax_exclude_id)) + + res = self.invoice_line_model.product_id_change(cr, uid, [], product.id, product.uom_id.id, + qty=1, type='out_invoice', partner_id=partner_id, + fposition_id=fp_id) + self.assertEquals(100, res['value']['price_unit'], "The included tax must be subtracted to the price") + + res = self.invoice_line_model.product_id_change(cr, uid, [], product.id, product.uom_id.id, + qty=1, type='in_invoice', partner_id=partner_id, + fposition_id=fp_id) + self.assertEquals(100, res['value']['price_unit'], "The included tax must be subtracted to the price") From 6e945de681452d6753f58a749352bfbe099bac1d Mon Sep 17 00:00:00 2001 From: Joren Van Onder Date: Wed, 9 Dec 2015 10:33:15 +0100 Subject: [PATCH 07/96] [FIX] point_of_sale: don't error when splitting an order 4b003afd0ab125b0296de8939626ae889ccdab47 made it so that the constructor of an orderline calls set_quantity(). The issue is that this function first asserts that the order is editable. pos_restaurant uses the clone() of orderline when splitting an order, and this method did not set order, leading to an error. This fixes the issue by temporarily cloning the order reference, and then setting it back to null. It's not the cleanest fix, but seeing as how the clone() method is only used in one place this will have to do for now. --- addons/point_of_sale/static/src/js/models.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addons/point_of_sale/static/src/js/models.js b/addons/point_of_sale/static/src/js/models.js index 4f49f070194..71592e9f7d4 100644 --- a/addons/point_of_sale/static/src/js/models.js +++ b/addons/point_of_sale/static/src/js/models.js @@ -885,10 +885,11 @@ openerp.point_of_sale.load_models = function load_models(instance, module){ //mo clone: function(){ var orderline = new module.Orderline({},{ pos: this.pos, - order: null, + order: this.order, product: this.product, price: this.price, }); + orderline.order = null; orderline.quantity = this.quantity; orderline.quantityStr = this.quantityStr; orderline.discount = this.discount; From 2bc5d8b32e297154a1f76baebfd28d0e8ef502c2 Mon Sep 17 00:00:00 2001 From: Joren Van Onder Date: Tue, 1 Dec 2015 13:04:53 +0100 Subject: [PATCH 08/96] [ADD] hw_blackbox_be: implements the Belgian blackbox protocol To be used together with the pos_blackbox_be module. The protocol specification is available in: http://www.minfin.fgov.be/portail2/fr/current/spokesperson-12-06-05.htm --- addons/hw_blackbox_be/__init__.py | 4 + addons/hw_blackbox_be/__openerp__.py | 24 +++ addons/hw_blackbox_be/controllers/__init__.py | 4 + addons/hw_blackbox_be/controllers/main.py | 162 ++++++++++++++++++ 4 files changed, 194 insertions(+) create mode 100644 addons/hw_blackbox_be/__init__.py create mode 100644 addons/hw_blackbox_be/__openerp__.py create mode 100644 addons/hw_blackbox_be/controllers/__init__.py create mode 100644 addons/hw_blackbox_be/controllers/main.py diff --git a/addons/hw_blackbox_be/__init__.py b/addons/hw_blackbox_be/__init__.py new file mode 100644 index 00000000000..bf7fb7b45c1 --- /dev/null +++ b/addons/hw_blackbox_be/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import controllers diff --git a/addons/hw_blackbox_be/__openerp__.py b/addons/hw_blackbox_be/__openerp__.py new file mode 100644 index 00000000000..d33930e2143 --- /dev/null +++ b/addons/hw_blackbox_be/__openerp__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. +{ + 'name': 'Blackbox Hardware Driver', + 'version': '1.0', + 'category': 'Hardware Drivers', + 'sequence': 6, + 'summary': 'Hardware Driver for Belgian Fiscal Data Modules', + 'website': 'https://www.odoo.com/page/point-of-sale', + 'description': """ +Fiscal Data Module Hardware Driver +================================== + +This module allows a Point Of Sale client to communicate with a +connected Belgian Fiscal Data Module. +""", + 'author': 'OpenERP SA', + 'depends': ['hw_proxy'], + 'external_dependencies': {'python': ['serial']}, + 'test': [ + ], + 'installable': True, + 'auto_install': False, +} diff --git a/addons/hw_blackbox_be/controllers/__init__.py b/addons/hw_blackbox_be/controllers/__init__.py new file mode 100644 index 00000000000..f48716d3a69 --- /dev/null +++ b/addons/hw_blackbox_be/controllers/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import main diff --git a/addons/hw_blackbox_be/controllers/main.py b/addons/hw_blackbox_be/controllers/main.py new file mode 100644 index 00000000000..fbc7664cbc0 --- /dev/null +++ b/addons/hw_blackbox_be/controllers/main.py @@ -0,0 +1,162 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import logging +import serial +from os import listdir +from threading import Thread, Lock + +from openerp import http + +import openerp.addons.hw_proxy.controllers.main as hw_proxy + +_logger = logging.getLogger(__name__) + +class Blackbox(Thread): + def __init__(self): + Thread.__init__(self) + self.blackbox_lock = Lock() + self.set_status('connecting') + self.device_path = self._find_device_path_by_probing() + + def set_status(self, status, messages=[]): + self.status = { + 'status': status, + 'messages': messages + } + + def get_status(self): + return self.status + + # There is no real way to find a serial device, all you can really + # find is the name of the serial to usb interface, which in the + # case of the blackbox is not defined because it doesn't always + # come with it's own interface (eg. Retail Cleancash SC-B). So, in + # order to differentiate between other devices like this, what + # we'll do is probe every serial device with an FDM status + # request. The first device to give an answer that makes sense + # wins. + def _find_device_path_by_probing(self): + path = "/dev/serial/by-id/" + probe_message = self._wrap_low_level_message_around("S000") + + try: + devices = listdir(path) + except OSError: + _logger.warning(path + " doesn't exist") + else: + for device in listdir(path): + path_to_device = path + device + _logger.debug("Probing " + device) + + if self._send_to_blackbox(probe_message, 21, path_to_device, just_wait_for_ack=True): + _logger.info(device + " will be used as the blackbox") + self.set_status("connected", [device]) + return path_to_device + + _logger.warning("Blackbox could not be found") + self.set_status("error", ["Couldn't find the Fiscal Data Module"]) + return "" + + def _lrc(self, msg): + lrc = 0 + + for character in msg: + byte = ord(character) + lrc = (lrc + byte) & 0xFF + + lrc = ((lrc ^ 0xFF) + 1) & 0xFF + + return lrc + + def _wrap_low_level_message_around(self, high_level_message): + bcc = self._lrc(high_level_message) + high_level_message_bytes = map(ord, high_level_message) + + low_level_message = bytearray() + low_level_message.append(0x02) + low_level_message.extend(high_level_message_bytes) + low_level_message.append(0x03) + low_level_message.append(bcc) + + return low_level_message + + def _send_and_wait_for_ack(self, packet, serial): + ack = 0 + MAX_RETRIES = 1 + + while ack != 0x06 and int(chr(packet[4])) < MAX_RETRIES: + serial.write(packet) + ack = serial.read(1) + + # This violates the principle that we do high level + # client-side and low level posbox-side but the retry + # counter is always in a fixed position in the high level + # message so it's safe to do it. Also it would be a pain + # to have to throw this all the way back to js just so it + # can increment the retry counter and then try again. + packet = packet[:4] + str(int(packet[4]) + 1) + packet[5:] + + if ack: + ack = ord(ack) + else: + _logger.warning("did not get ACK, retrying...") + ack = 0 + + if ack == 0x06: + return True + else: + _logger.error("retried " + str(MAX_RETRIES) + " times without receiving ACK, is blackbox properly connected?") + return False + + def _send_to_blackbox(self, packet, response_size, device_path, just_wait_for_ack=False): + if not device_path: + return "" + + ser = serial.Serial(port=device_path, + baudrate=19200, + timeout=3) + MAX_NACKS = 1 + got_response = False + sent_nacks = 0 + + if self._send_and_wait_for_ack(packet, ser): + if just_wait_for_ack: + return True + + while not got_response and sent_nacks < MAX_NACKS: + stx = ser.read(1) + response = ser.read(response_size) + etx = ser.read(1) + bcc = ser.read(1) + + if stx == chr(0x02) and etx == chr(0x03) and bcc and self._lrc(response) == ord(bcc): + got_response = True + ser.write(chr(0x06)) + else: + _logger.warning("received ACK but not a valid response, sending NACK...") + sent_nacks += 1 + ser.write(chr(0x15)) + + if not got_response: + _logger.error("sent " + str(MAX_NACKS) + " NACKS without receiving response, giving up.") + return "" + + ser.close() + return response + else: + ser.close() + return "" + +blackbox_thread = Blackbox() +hw_proxy.drivers['fiscal_data_module'] = blackbox_thread + +class BlackboxDriver(hw_proxy.Proxy): + @http.route('/hw_proxy/request_blackbox/', type='json', auth='none', cors='*') + def request_blackbox(self, high_level_message, response_size): + to_send = blackbox_thread._wrap_low_level_message_around(high_level_message) + + with blackbox_thread.blackbox_lock: + response = blackbox_thread._send_to_blackbox(to_send, response_size, blackbox_thread.device_path) + + return response From 184471dbf1022b03a957a7d51ea32b2c80599956 Mon Sep 17 00:00:00 2001 From: Joren Van Onder Date: Tue, 1 Dec 2015 14:39:15 +0100 Subject: [PATCH 09/96] [IMP] point_of_sale: add hw_blackbox_be to posbox image This removes server_wide_modules from odoo.conf entirely because it wasn't actually used. --- addons/point_of_sale/tools/posbox/configuration/odoo.conf | 1 - .../tools/posbox/overwrite_before_init/etc/init.d/odoo | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/addons/point_of_sale/tools/posbox/configuration/odoo.conf b/addons/point_of_sale/tools/posbox/configuration/odoo.conf index 1bc0a0d3ba5..bbe21f44c3e 100644 --- a/addons/point_of_sale/tools/posbox/configuration/odoo.conf +++ b/addons/point_of_sale/tools/posbox/configuration/odoo.conf @@ -3,4 +3,3 @@ data_dir = /var/run/odoo log_level = error logfile = /var/log/odoo/odoo-server.log pidfile = /var/run/odoo/odoo.pid -server_wide_modules = web,hw_proxy,hw_posbox_homepage,hw_posbox_upgrade,hw_scale,hw_scanner,hw_escpos \ No newline at end of file diff --git a/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/init.d/odoo b/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/init.d/odoo index f9bc0400abc..30be4bd26d3 100755 --- a/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/init.d/odoo +++ b/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/init.d/odoo @@ -26,7 +26,7 @@ test -x $DAEMON || exit 0 set -e function _start() { - start-stop-daemon --start --quiet --pidfile $PIDFILE --chuid $USER:$USER --background --make-pidfile --exec $DAEMON -- --config $CONFIG --logfile $LOGFILE --load=web,hw_proxy,hw_posbox_homepage,hw_posbox_upgrade,hw_scale,hw_scanner,hw_escpos + start-stop-daemon --start --quiet --pidfile $PIDFILE --chuid $USER:$USER --background --make-pidfile --exec $DAEMON -- --config $CONFIG --logfile $LOGFILE --load=web,hw_proxy,hw_posbox_homepage,hw_posbox_upgrade,hw_scale,hw_scanner,hw_escpos,hw_blackbox_be } function _stop() { From 22d0592c9aea3264c7b9c1b7d9566d1aa145d117 Mon Sep 17 00:00:00 2001 From: Pascal Zenklusen Date: Mon, 9 Nov 2015 13:20:21 +0100 Subject: [PATCH 10/96] [CLA] add corporate signature for brain-tec --- doc/cla/corporate/brain-tec.md | 40 ++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 doc/cla/corporate/brain-tec.md diff --git a/doc/cla/corporate/brain-tec.md b/doc/cla/corporate/brain-tec.md new file mode 100644 index 00000000000..f598f64eb1b --- /dev/null +++ b/doc/cla/corporate/brain-tec.md @@ -0,0 +1,40 @@ +Switzerland, 2015-11-09 + +brain-tec AG agrees to the terms of the Odoo Corporate Contributor License +Agreement v1.0. + +I declare that I am authorized and able to make this agreement and sign this +declaration. + +Signed, + +Pascal Zenklusen pascal.zenklusen@braintec-group.com https://github.com/BT-pzenklusen + +List of contributors: + +Álvaro Estébanez López alvaro.estebanez@braintec-group.com https://github.com/BT-aestebanez +Andreas Stauder andreas.stauder@braintec-group.com https://github.com/BT-astauder +Carlos Millán de Silva carlos.millan@braintec-group.com https://github.com/BT-cmillan +Cesar Andres Sanchez cesar-andres.sanchez@braintec-group.com https://github.com/BT-csanchez +Carlos Serra Toro carlos.serra@braintec-group.com https://github.com/BT-cserra +Dominik Schleich dominik.schleich@braintec-group.com https://github.com/BT-dschleich +Frédéric Aebi frederic.aebi@braintec-group.com https://github.com/BT-faebi +Fréderic Garbely frederic.garbely@braintec-group.com https://github.com/BT-fgarbely +Florian Wonneberger florian.wonneberger@braintec-group.com https://github.com/BT-fwonneberger +Jorge Asensio jorge.asensio@braintec-group.com https://github.com/BT-jasensio +Jose J. Duran-Martin jose-javier.duran@braintec-group.com https://github.com/BT-jduran +Federico Javier Mesa Hidalgo javier.mesa@braintec-group.com https://github.com/BT-jmesa +Joël Michaud joel.michaud@braintec-group.com https://github.com/BT-jmichaud +Jose Montero jose.montero@braintec-group.com https://github.com/BT-jmontero +José Luis Vallejo Diaz jose.vallejo@braintec-group.com https://github.com/BT-jvallejo +Kumar Aberer kumar.aberer@braintec-group.com https://github.com/BT-kaberer +Matt Fasola matt.fasola@braintec-group.com https://github.com/BT-mfasola +Miguel Tallon Benitez miguel.tallon@braintec-group.com https://github.com/BT-mtallon +Nicolas Frei nicolas.frei@braintec-group.com https://github.com/BT-nfrei +Nathanael Leutenegger nathanael.leutenegger@braintec-group.com https://github.com/BT-nleutenegger +Olivier Jossen olivier.jossen@braintec-group.com https://github.com/BT-ojossen +Philipp Fux philipp.fux@braintec-group.com https://github.com/BT-pfux +Raúl Martín raul.martin@braintec-group.com https://github.com/BT-rmartin +Silvan Wyden silvan.wyden@braintec-group.com https://github.com/BT-swyden +Timka Piric Muratovic timka.piric@braintec-group.com https://github.com/BT-tpiric +Pascal Zenklusen pascal.zenklusen@braintec-group.com https://github.com/BT-pzenklusen From ff2910f8f247225dbd882190d5ac2dc706e5ac85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Garbely?= Date: Wed, 9 Dec 2015 17:15:43 +0100 Subject: [PATCH 11/96] [FIX] ir_translation: prevent `overwrite` propagation Once set for the loading of terms for a lang, the flag `overwrite` was propagated to all other following languages, even if not actually needed. Use case: - Installed languages: en_US, de, fr_CH, it - Update of the `sale` module - In `load_module_terms`, the system iterates through the languages: 1. en_US: No problem 2. de: No problem 3. fr_CH: The flag `overwrite` is set to `True`, because the sub-language `fr_CH` should overwrite the `fr` terms 4. it: The flag is still set to `True`, because of the previous iteration, while it must not. opw-654042 --- openerp/addons/base/ir/ir_translation.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openerp/addons/base/ir/ir_translation.py b/openerp/addons/base/ir/ir_translation.py index da3a3556a5f..6e2dc73b019 100644 --- a/openerp/addons/base/ir/ir_translation.py +++ b/openerp/addons/base/ir/ir_translation.py @@ -468,12 +468,13 @@ class ir_translation(osv.osv): return ir_translation_import_cursor(cr, uid, self, context=context) def load_module_terms(self, cr, modules, langs, context=None): - context = dict(context or {}) # local copy + context_template = dict(context or {}) # local copy for module_name in modules: modpath = openerp.modules.get_module_path(module_name) if not modpath: continue for lang in langs: + context = dict(context_template) lang_code = tools.get_iso_codes(lang) base_lang_code = None if '_' in lang_code: From 3184925bf88c267d9173ce643fc4f54d7617c238 Mon Sep 17 00:00:00 2001 From: Luis Felipe Mileo Date: Fri, 4 Dec 2015 18:29:05 -0200 Subject: [PATCH 12/96] [CLA] KMEE signs the coprporate CLA Closes #9933 --- doc/cla/corporate/kmee.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 doc/cla/corporate/kmee.md diff --git a/doc/cla/corporate/kmee.md b/doc/cla/corporate/kmee.md new file mode 100644 index 00000000000..e29245abf56 --- /dev/null +++ b/doc/cla/corporate/kmee.md @@ -0,0 +1,21 @@ +KMEE, Brazil, 2015-12-04 + +KMEE INFORMATICA LTDA agrees to the terms of the Odoo Corporate +Contributor License Agreement v1.0. + +I declare that I am authorized and able to make this agreement and sign this +declaration. + +Signed, + +Luis Felipe Miléo mileo@kmee.com.br https://github.com/kmee + +List of contributors: + +Luis Felipe Miléo mileo@kmee.com.br https://github.com/mileo +Ananias Pereira Batista Filho ananias@kmee.com.br https://github.com/ananiasfilho +Michell Stuttigart michell.stuttigart@kmee.com.br https://github.com/mstuttgart +Fernando Marcato Rodrigues fernando.marcato@kmee.com.br https://github.com/fernandomr +Daniel Sadamo daniel.sadamo@kmee.com.br https://github.com/sadamo +Bianca Tella bianca.tella@kmee.com.br https://github.com/biancatella +Luiz Felipe do Divino luiz.divino@kmee.com.br https://github.com/lfdivino \ No newline at end of file From eb7477989d9572876a298657ebcfa1828af2b580 Mon Sep 17 00:00:00 2001 From: Davide Corio Date: Thu, 5 Nov 2015 14:34:15 +0100 Subject: [PATCH 13/96] [CLA] Abstract signs the corporate CLA Closes #9435 --- doc/cla/corporate/abstract.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 doc/cla/corporate/abstract.md diff --git a/doc/cla/corporate/abstract.md b/doc/cla/corporate/abstract.md new file mode 100644 index 00000000000..7c1f520bfd8 --- /dev/null +++ b/doc/cla/corporate/abstract.md @@ -0,0 +1,18 @@ +Italy, 2015-11-05 + +Abstract Srl agrees to the terms of the Odoo Corporate Contributor License +Agreement v1.0. + +I declare that I am authorized and able to make this agreement and sign this +declaration. + +Signed, + +Davide Corio davide.corio@abstract.it https://github.com/dcorio + + +List of contributors: + +Davide Corio davide.corio@abstract.it https://github.com/dcorio +Simone Orsi simone.orsi@abstract.it https://github.com/simahawk +Giacomo Spettoli giacomo.spettoli@abstract.it https://github.com/giacomos From 25b56671c135387ac213d19a7bb959a06d66ac55 Mon Sep 17 00:00:00 2001 From: Atchuthan Date: Wed, 18 Nov 2015 10:51:55 +0530 Subject: [PATCH 14/96] [CLA] update Sodexis corporate cla Closes #9614 --- doc/cla/corporate/sodexis.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/cla/corporate/sodexis.md b/doc/cla/corporate/sodexis.md index 2a642474497..3b7544acd9c 100644 --- a/doc/cla/corporate/sodexis.md +++ b/doc/cla/corporate/sodexis.md @@ -17,3 +17,4 @@ Suganthi Karunanithi ksuganthi@sodexis.com https://github.com/suganthikarunanith Xavier Dass xavier@sodexis.com https://github.com/xavier-dass Atchuthan atchuthan@sodexis.com https://github.com/atchuthan Dhinesh dhinesh@sodexis.com https://github.com/dvdhinesh +SodexisTeam dev@sodexis.com https://github.com/SodexisTeam From 8a0b4ca39fce06b95025e1a4978ef32cf8389420 Mon Sep 17 00:00:00 2001 From: Christophe Matthieu Date: Thu, 10 Dec 2015 10:02:37 +0100 Subject: [PATCH 15/96] [FIX] website: display website_published image without access to the model Issue: if the user don't have any access to the model, _image method raise an exception instead of display the website_published images. --- addons/website/models/website.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/addons/website/models/website.py b/addons/website/models/website.py index e82d09b0502..dcffeb0baf3 100644 --- a/addons/website/models/website.py +++ b/addons/website/models/website.py @@ -535,8 +535,10 @@ class website(osv.osv): Model = self.pool[model] id = int(id) - ids = Model.search(cr, uid, - [('id', '=', id)], context=context) + ids = None + if Model.check_access_rights(cr, uid, 'read', raise_exception=False): + ids = Model.search(cr, uid, + [('id', '=', id)], context=context) if not ids and 'website_published' in Model._fields: ids = Model.search(cr, openerp.SUPERUSER_ID, [('id', '=', id), ('website_published', '=', True)], context=context) From 35a390daf1c8fa7aa0ffe548d0986e8e0a41f4e6 Mon Sep 17 00:00:00 2001 From: Nicolas Martinelli Date: Thu, 10 Dec 2015 10:05:06 +0100 Subject: [PATCH 16/96] [FIX] sale: change qty updates weight The method `product_id_change` has become quite a mess with time as it gathers a lot of onchanges. Therefore, previous commits were made in order to prevent unwanted side effects, such as af07b2a0, 1cedcf6a and 136bd723. This revision fixes the weight which was lost with commit af07b2a0. opw-658712 --- addons/sale/sale.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/addons/sale/sale.py b/addons/sale/sale.py index 49652efb234..7e1c28577a4 100644 --- a/addons/sale/sale.py +++ b/addons/sale/sale.py @@ -1173,10 +1173,10 @@ class sale_order_line(osv.osv): price = Product.price_get(cr, uid, [product], ptype='list_price', context=ctx_product)[product] or False price = self.pool['account.tax']._fix_tax_included_price(cr, uid, price, taxes, result['tax_id']) if context.get('uom_qty_change', False): - product_uos_qty = result.get('product_uos_qty') - result, domain = {}, {} - if product_uos_qty: - result['product_uos_qty'] = product_uos_qty + # Remove unnecessary changes + domain = {} + for key in ["name", "product_uom", "product_uos", "tax_id"]: + result.pop(key, None) result.update({'price_unit': price}) return {'value': result, 'domain': domain} From 9f65dad250127fe2699a27e1e3b6325bd0838885 Mon Sep 17 00:00:00 2001 From: Alexandre Fayolle Date: Wed, 2 Dec 2015 14:03:08 +0100 Subject: [PATCH 17/96] [FIX] stock: mutation of the context If the method do_enter_transfer_details is called form the new API, the context is a frozendict and can not be updated and the previous code would crash. Copying it before updating. Closes #9872 --- addons/stock/stock.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 2e372b7ae58..98a15b5ab7c 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -1406,7 +1406,8 @@ class stock_picking(osv.osv): def do_enter_transfer_details(self, cr, uid, picking, context=None): if not context: context = {} - + else: + context = context.copy() context.update({ 'active_model': self._name, 'active_ids': picking, From feef50adae072fc71ac0edfb8b3d9727fa2f5bf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Maillard?= Date: Thu, 10 Dec 2015 19:35:34 +0800 Subject: [PATCH 18/96] [CLA] Corporate CLA for Elico Corporation Closes #10010 --- doc/cla/corporate/elico-corporation.md | 30 ++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 doc/cla/corporate/elico-corporation.md diff --git a/doc/cla/corporate/elico-corporation.md b/doc/cla/corporate/elico-corporation.md new file mode 100644 index 00000000000..aa5e28564bc --- /dev/null +++ b/doc/cla/corporate/elico-corporation.md @@ -0,0 +1,30 @@ +China, 2015-12-10 + +Elico Corporation agrees to the terms of the Odoo Corporate Contributor License +Agreement v1.0. + +I declare that I am authorized and able to make this agreement and sign this +declaration. + +Signed, + +Eric Caudal eric.caudal@elico-corp.com https://github.com/elicoidal + +List of contributors: +Eric Caudal eric.caudal@elico-corp.com https://github.com/elicoidal +Sébastien Maillard sebastien.maillard@elico-corp.com https://github.com/seb-elico +Siyuan Gu siyuancn@hotmail.com https://github.com/siyuancn +Wang Liping lynn.config@gmail.com https://github.com/lynndotconfig +Luke Zheng cialuo@126.com https://github.com/cialuo +Gary Wei gary.wei@elico-corp.com https://github.com/Garywei1314 +Yaxi Zheng zheng.yaxi@elico-corp.com https://github.com/Elico-Yaxi +Faust Huang faust_huang@hotmail.com https://github.com/fausthuang +Yu Lin yu_lin@me.com https://github.com/uynil +Xie Xiaopeng hellomyjob@163.com https://github.com/xie8899 +Connie Xiao connie.xiao@elico-corp.com https://github.com/ConnieXiao +Alex Duan alex.duan@elico-corp.com https://github.com/duanyp1991 +Liu Lixia liulixia19901988@163.com https://github.com/liulixia1990 +Liliane Li liliane.li@elico-corp.com http://github.com/lilianeandbrody +Rona Lin ssauapw@qq.com https://github.com/Rona111 +Bob Luo luo.yumeng0831@gmail.com https://github.com/m6519578 +Waller Zhang waller.zhang@elico-corp.com https://github.com/wallerzhang From 267ab22d000f4c8ed829042c89e4bd6cd0c0b446 Mon Sep 17 00:00:00 2001 From: Christophe Matthieu Date: Thu, 10 Dec 2015 10:26:13 +0100 Subject: [PATCH 19/96] [FIX] website_sale: variable reference 'message' variable was not always defined. Set a default value. Closes #10006 --- addons/website_sale/controllers/main.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/addons/website_sale/controllers/main.py b/addons/website_sale/controllers/main.py index 1e9d9d52f37..81a4743eb3f 100644 --- a/addons/website_sale/controllers/main.py +++ b/addons/website_sale/controllers/main.py @@ -780,16 +780,14 @@ class website_sale(http.Controller): '|', ('sale_order_id', '=', order.id), ('reference', '=', order.name) ], context=context) + state = 'done' + message = "" + validation = None + if not tx_ids: if order.amount_total: - return { - 'state': 'error', - 'message': '

%s

' % _('There seems to be an error with your request.'), - } - else: - state = 'done' - message = "" - validation = None + state = 'error' + message = '

%s

' % _('There seems to be an error with your request.') else: tx = request.registry['payment.transaction'].browse(cr, SUPERUSER_ID, tx_ids[0], context=context) state = tx.state From 43482d2d1ecac0b8000f2ea971b7fdd3a438f1bc Mon Sep 17 00:00:00 2001 From: "Jonathan Nemry (ACSONE)" Date: Wed, 9 Dec 2015 17:17:39 +0100 Subject: [PATCH 20/96] [FIX] mass_mailing: translatable unsubscribe link Display the unsubscribe link in the language of the user Closes #9995, opw 659075 --- addons/mass_mailing/i18n/mass_mailing.pot | 6 ++++++ addons/mass_mailing/models/mail_mail.py | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/addons/mass_mailing/i18n/mass_mailing.pot b/addons/mass_mailing/i18n/mass_mailing.pot index ad39d58edc2..0355182e24a 100644 --- a/addons/mass_mailing/i18n/mass_mailing.pot +++ b/addons/mass_mailing/i18n/mass_mailing.pot @@ -1088,3 +1088,9 @@ msgstr "" msgid "your email..." msgstr "" +#. module: mass_mailing +#: code:addons/mass_mailing/models/mail_mail.py:72 +#, python-format +msgid "Click to unsubscribe" +msgstr "" + diff --git a/addons/mass_mailing/models/mail_mail.py b/addons/mass_mailing/models/mail_mail.py index bd5224ca2ba..651d8f07729 100644 --- a/addons/mass_mailing/models/mail_mail.py +++ b/addons/mass_mailing/models/mail_mail.py @@ -22,6 +22,7 @@ import urlparse import werkzeug.urls +from openerp.tools.translate import _ from openerp import tools from openerp import SUPERUSER_ID from openerp.osv import osv, fields @@ -68,7 +69,7 @@ class MailMail(osv.Model): 'params': werkzeug.url_encode({'db': cr.dbname, 'res_id': mail.res_id, 'email': email_to}) } ) - return '%s' % (url, msg or 'Click to unsubscribe') + return '%s' % (url, msg or _('Click to unsubscribe')) def send_get_mail_body(self, cr, uid, mail, partner=None, context=None): """ Override to add the tracking URL to the body. """ From b139c5819dff7eb89762d50e561fe472a4d6f6e8 Mon Sep 17 00:00:00 2001 From: Stefan Rijnhart Date: Fri, 4 Dec 2015 09:59:09 +0100 Subject: [PATCH 21/96] [FIX] email_template: allow override of in new API If context is passed as a non-keyword argument to a new-API override of this method, it ends up as the positional fields argument. Closes #9911 --- addons/email_template/email_template.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/email_template/email_template.py b/addons/email_template/email_template.py index a4f8370d00a..f395fdfc503 100644 --- a/addons/email_template/email_template.py +++ b/addons/email_template/email_template.py @@ -583,6 +583,6 @@ class email_template(osv.osv): return self.get_email_template_batch(cr, uid, template_id, [record_id], context)[record_id] def generate_email(self, cr, uid, template_id, res_id, context=None): - return self.generate_email_batch(cr, uid, template_id, [res_id], context)[res_id] + return self.generate_email_batch(cr, uid, template_id, [res_id], context=context)[res_id] # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From 73d5f62acd20dc2bda212e06ec84b774ced77707 Mon Sep 17 00:00:00 2001 From: Nicolas Lempereur Date: Tue, 1 Dec 2015 12:38:57 +0100 Subject: [PATCH 22/96] [IMP] web_calendar: refresh event after fail If an event is moved at another time, its appearance would only be refreshed if it was successful. But in this particular instance, the refresh may even be more useful when the change failed. part of #9837 second half of: opw-657863 --- addons/web_calendar/static/src/js/web_calendar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/web_calendar/static/src/js/web_calendar.js b/addons/web_calendar/static/src/js/web_calendar.js index 63066f7a861..c054a0148b0 100644 --- a/addons/web_calendar/static/src/js/web_calendar.js +++ b/addons/web_calendar/static/src/js/web_calendar.js @@ -806,7 +806,7 @@ openerp.web_calendar = function(instance) { var index = this.dataset.get_id_index(id); if (index !== null) { event_id = this.dataset.ids[index]; - this.dataset.write(event_id, data, {}).done(function() { + this.dataset.write(event_id, data, {}).always(function() { if (is_virtual_id(event_id)) { // this is a virtual ID and so this will create a new event // with an unknown id for us. From d0ccd87e79206b4f071fcc7360e065b382f8921b Mon Sep 17 00:00:00 2001 From: Antonio Espinosa Date: Sat, 28 Nov 2015 00:01:04 +0100 Subject: [PATCH 23/96] [FIX] mass_mailing: Confirmation when sending a mass mailing When a user clicks on the `Send to all` button in a mass mailing form, then all emails (sometime thousands) are sent inmediatly. With this fix, a confirmation dialog appears and the user is asked to confirm this operation. This simple fix prevents common human errors. opw-659117 Closes #9796 --- addons/mass_mailing/views/mass_mailing.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/mass_mailing/views/mass_mailing.xml b/addons/mass_mailing/views/mass_mailing.xml index e441f78190f..fdede2f38d6 100644 --- a/addons/mass_mailing/views/mass_mailing.xml +++ b/addons/mass_mailing/views/mass_mailing.xml @@ -281,10 +281,10 @@ string="Test Mailing"/> - + From 631d6b19d4c38910620e1d22a4d0bce936a17a7c Mon Sep 17 00:00:00 2001 From: Joren Van Onder Date: Thu, 17 Dec 2015 12:15:16 +0100 Subject: [PATCH 56/96] [FIX] point_of_sale: make tipping adhere to correct number formatting The number popup uses gui.numpad_input() which now only allows the correct decimal separator (before this it was hardcoded as '.'). So we now have to use the correct decimal separator in that particular popup. Because of that we also have to correctly format the default tipping amount AND also parse whatever value we get back from the popup through web.parse_value(). Although you could do this formatting directly in the NumberPopupWidget constructor, this would not be ideal because this widget is also used for numbers that shouldn't adhere to the formatting (eg. PIN numbers). --- addons/point_of_sale/static/src/js/popups.js | 1 + addons/point_of_sale/static/src/js/screens.js | 4 ++-- addons/point_of_sale/static/src/xml/pos.xml | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/addons/point_of_sale/static/src/js/popups.js b/addons/point_of_sale/static/src/js/popups.js index febeab06d8e..d0294e74bb8 100644 --- a/addons/point_of_sale/static/src/js/popups.js +++ b/addons/point_of_sale/static/src/js/popups.js @@ -188,6 +188,7 @@ openerp.point_of_sale.load_popups = function load_popups(instance, module) { this._super(options); this.inputbuffer = '' + (options.value || ''); + this.decimal_separator = instance.web._t.database.parameters.decimal_point; this.renderElement(); this.firstinput = true; }, diff --git a/addons/point_of_sale/static/src/js/screens.js b/addons/point_of_sale/static/src/js/screens.js index 24de92cd923..b93b426b7ab 100644 --- a/addons/point_of_sale/static/src/js/screens.js +++ b/addons/point_of_sale/static/src/js/screens.js @@ -1654,9 +1654,9 @@ openerp.point_of_sale.load_screens = function load_screens(instance, module){ // this.gui.show_popup('number',{ 'title': tip ? _t('Change Tip') : _t('Add Tip'), - 'value': value, + 'value': self.format_currency_no_symbol(value), 'confirm': function(value) { - order.set_tip(Number(value)); + order.set_tip(instance.web.parse_value(value, {type: "float"}, 0)); self.order_changes(); self.render_paymentlines(); } diff --git a/addons/point_of_sale/static/src/xml/pos.xml b/addons/point_of_sale/static/src/xml/pos.xml index b2314424144..6616a3de2fc 100644 --- a/addons/point_of_sale/static/src/xml/pos.xml +++ b/addons/point_of_sale/static/src/xml/pos.xml @@ -1023,7 +1023,7 @@
- + From 682e66043ffe744752587906467c15d90b07203f Mon Sep 17 00:00:00 2001 From: Joren Van Onder Date: Thu, 17 Dec 2015 13:28:58 +0100 Subject: [PATCH 57/96] [FIX] point_of_sale: fix the +10, +20 and +50 buttons Because we now correctly format numbers, we have to parse the number strings with web.parse_value(), then calculate the new amount and then convert them back to a correctly formatted number string. --- addons/point_of_sale/static/src/js/gui.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addons/point_of_sale/static/src/js/gui.js b/addons/point_of_sale/static/src/js/gui.js index 1557c2af230..cd296b6dd4a 100644 --- a/addons/point_of_sale/static/src/js/gui.js +++ b/addons/point_of_sale/static/src/js/gui.js @@ -314,6 +314,7 @@ openerp.point_of_sale.load_gui = function load_gui(instance, module) { numpad_input: function(buffer, input, options) { var options = options || {}; var newbuf = buffer.slice(0); + var newbuf_float = instance.web.parse_value(newbuf, {type: "float"}, 0); var decimal_point = instance.web._t.database.parameters.decimal_point; if (input === decimal_point) { @@ -339,7 +340,7 @@ openerp.point_of_sale.load_gui = function load_gui(instance, module) { newbuf = '-' + newbuf; } } else if (input[0] === '+' && !isNaN(parseFloat(input))) { - newbuf = '' + ((parseFloat(newbuf) || 0) + parseFloat(input)); + newbuf = this.chrome.format_currency_no_symbol(newbuf_float + parseFloat(input)); } else if (!isNaN(parseInt(input))) { if (options.firstinput) { newbuf = '' + input; From 43aaf30b157638947b5add07839eb8c65f986b84 Mon Sep 17 00:00:00 2001 From: Richard Mathot Date: Tue, 8 Dec 2015 13:42:25 +0100 Subject: [PATCH 58/96] [IMP] delivery: re-enable the ability to display delivery price in name_get Was available before 3098ab7fd101b1bc5caa7ad8fd3200c0b5e66310. This time, a special key in the context is required as this behaviour is quite slow. (This commit could have been named "Dirty Hacking") --- addons/delivery/delivery.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/addons/delivery/delivery.py b/addons/delivery/delivery.py index 4ac88771d3b..1398b061ed9 100644 --- a/addons/delivery/delivery.py +++ b/addons/delivery/delivery.py @@ -25,7 +25,7 @@ from openerp.osv import fields,osv from openerp.tools.translate import _ import openerp.addons.decimal_precision as dp from openerp.tools.safe_eval import safe_eval as eval -from openerp.exceptions import UserError +from openerp.exceptions import UserError, ValidationError _logger = logging.getLogger(__name__) @@ -33,6 +33,29 @@ class delivery_carrier(osv.osv): _name = "delivery.carrier" _description = "Carrier" + def name_get(self, cr, uid, ids, context=None): + if not len(ids): + return [] + if context is None: + context = {} + display_delivery = context.get('display_delivery', False) + order_id = context.get('order_id', False) + if display_delivery and order_id: + order = self.pool.get('sale.order').browse(cr, uid, order_id, context=context) + currency = order.pricelist_id.currency_id.name or '' + res = [] + for carrier_id in ids: + try: + r = self.read(cr, uid, [carrier_id], ['name', 'price'], context)[0] + res.append((r['id'], r['name'] + ' (' + (str(r['price'])) + ' ' + currency + ')')) + except ValidationError: + r = self.read(cr, uid, [carrier_id], ['name'], context)[0] + res.append((r['id'], r['name'])) + + else: + res = super(delivery_carrier, self).name_get(cr, uid, ids, context=context) + return res + def get_price(self, cr, uid, ids, field_name, arg=None, context=None): res={} if context is None: From ca40236ddc75424be0e361f33adc55e8663ca399 Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Thu, 17 Dec 2015 14:26:06 +0100 Subject: [PATCH 59/96] [FIX] sale: onchange_product_uom The function "product_uom_change" was built to reset the price unit of a SO line when the uom was changed. Before this fix 503820a, the price unit of the SO line only depended on the price list then it was not needed to pass the fiscal position to this function. After this fix 503820a, the price unit of a SO line also depends on the taxes set on the SO line(e.g.:if an included tax is deleted, the price unit must be recomputed without this tax). Then to recompute the unit price, the function "product_id_change" must take into account the fiscal position set on the SO to consider the right taxes to recompute the unit price. The fiscal position set on a SO must be passed to onchange_product_uom each time it will be called because the price unit will be recomputed. --- addons/sale/sale.py | 12 ++++++++++++ addons/sale/sale_view.xml | 4 ++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/addons/sale/sale.py b/addons/sale/sale.py index d172c7bdb2c..119bee779aa 100644 --- a/addons/sale/sale.py +++ b/addons/sale/sale.py @@ -1232,6 +1232,18 @@ class sale_order_line(osv.osv): partner_id=partner_id, lang=lang, update_tax=update_tax, date_order=date_order, context=context) + def onchange_product_uom(self, cursor, user, ids, pricelist, product, qty=0, + uom=False, qty_uos=0, uos=False, name='', partner_id=False, + lang=False, update_tax=True, date_order=False, fiscal_position=False, context=None): + context = context or {} + lang = lang or ('lang' in context and context['lang']) + if not uom: + return {'value': {'price_unit': 0.0, 'product_uom' : uom or False}} + return self.product_id_change(cursor, user, ids, pricelist, product, + qty=qty, uom=uom, qty_uos=qty_uos, uos=uos, name=name, + partner_id=partner_id, lang=lang, update_tax=update_tax, + date_order=date_order, fiscal_position=fiscal_position, context=context) + def unlink(self, cr, uid, ids, context=None): if context is None: context = {} diff --git a/addons/sale/sale_view.xml b/addons/sale/sale_view.xml index be3ad08b6ee..675a621071f 100644 --- a/addons/sale/sale_view.xml +++ b/addons/sale/sale_view.xml @@ -134,7 +134,7 @@ on_change="product_id_change(parent.pricelist_id,product_id,product_uom_qty,product_uom,product_uos_qty,product_uos,name,parent.partner_id, False, False, parent.date_order, False, parent.fiscal_position, True, context)"/> + on_change="onchange_product_uom(parent.pricelist_id,product_id,product_uom_qty,product_uom,product_uos_qty,product_uos,name,parent.partner_id, False, False, parent.date_order, parent.fiscal_position, context)"/>