From 3622c0d12a879d8184b249c49ba2e24995d6a595 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Wed, 27 Jan 2016 13:58:13 +0100 Subject: [PATCH 01/16] [FIX] product: product price assumed currency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before this revision, with a configuration setup like this: - Company A - Currency EUR - Company B - Currency USD - Public Pricelist- Currency EUR - Product A - Company A - Price 100 (EUR) - Product B - No company - Price 100 When a user set in Company B browses the `/shop`, the pricelist applied is the public pricelist, and, therefore, the prices are shown in EUR (nothing wrong so far), but the currency of the price set on the products were assumed in USD, the user company currency, and, therefore, the rate conversion from USD to EUR was applied. The product A, configured with a sale price of 100€ in the company A, was therefore displayed to 92€ (100€ * the USD-EUR rate). The product B, without any company set, as well. Meaning, two users from two different companies using the same pricelist see two different prices in the same currency, because their companies do not use the same currency. This doesn't make any sense. With this revision, when setuping a sale price on a product, the currency of this price is assumed in the currency of the company set on the product. If there is no company set on the product (the company is not required), the currency assumed is then the currency of the main company. opw-666059 --- addons/product/pricelist.py | 3 +-- addons/product/product.py | 21 +++++++++++++-------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/addons/product/pricelist.py b/addons/product/pricelist.py index d1b01f15de0..28160e6b92c 100644 --- a/addons/product/pricelist.py +++ b/addons/product/pricelist.py @@ -242,8 +242,7 @@ class product_pricelist(osv.osv): break # Final price conversion into pricelist currency if suitable_rule and suitable_rule.compute_price != 'fixed' and suitable_rule.base != 'pricelist': - user_company = self.pool['res.users'].browse(cr, uid, uid, context=context).company_id - price = self.pool['res.currency'].compute(cr, uid, user_company.currency_id.id, pricelist.currency_id.id, price, context=context) + price = self.pool['res.currency'].compute(cr, uid, product.currency_id.id, pricelist.currency_id.id, price, context=context) results[product.id] = (price, suitable_rule and suitable_rule.id or False) return results diff --git a/addons/product/product.py b/addons/product/product.py index 0bc1ec3de85..3440b03ee41 100644 --- a/addons/product/product.py +++ b/addons/product/product.py @@ -421,6 +421,17 @@ class product_template(osv.osv): return product.write({'list_price': value}) + def _product_currency(self, cr, uid, ids, name, arg, context=None): + try: + main_company = self.pool['ir.model.data'].get_object(cr, uid, 'base', 'main_company') + except ValueError: + company_ids = self.pool['res.company'].search(cr, uid, [], limit=1, order="id", context=context) + main_company = self.pool['res.company'].browse(cr, uid, company_ids[0], context=context) + res = {} + for product in self.browse(cr, uid, ids, context=context): + res[product.id] = product.company_id.currency_id.id or main_company.currency_id.id + return res + def _get_product_variant_count(self, cr, uid, ids, name, arg, context=None): res = {} for product in self.browse(cr, uid, ids, context=context): @@ -477,11 +488,7 @@ class product_template(osv.osv): 'rental': fields.boolean('Can be Rent'), 'categ_id': fields.many2one('product.category','Internal Category', required=True, change_default=True, domain="[('type','=','normal')]" ,help="Select category for the current product"), 'price': fields.function(_product_template_price, fnct_inv=_set_product_template_price, type='float', string='Price', digits_compute=dp.get_precision('Product Price')), - 'currency_id': fields.related( - 'company_id', 'currency_id', - type='many2one', - relation='res.currency', - string='Currency'), + 'currency_id': fields.function(_product_currency, type='many2one', relation='res.currency', string='Currency'), 'list_price': fields.float('Sale Price', digits_compute=dp.get_precision('Product Price'), help="Base price to compute the customer price. Sometimes called the catalog price."), 'lst_price' : fields.related('list_price', type="float", string='Public Price', digits_compute=dp.get_precision('Product Price')), 'standard_price': fields.function(_compute_product_template_field, fnct_inv=_set_product_template_field, fnct_search=_search_by_standard_price, multi='_compute_product_template_field', type='float', string='Cost', digits_compute=dp.get_precision('Product Price'), @@ -556,8 +563,6 @@ class product_template(osv.osv): if context is None: context = {} - if 'currency_id' in context: - currency_id = self.pool['res.users'].browse(cr, uid, uid, context=context).company_id.currency_id.id res = {} product_uom_obj = self.pool.get('product.uom') for product in products: @@ -580,7 +585,7 @@ class product_template(osv.osv): if 'currency_id' in context: # Take current user company currency. # This is right cause a field cannot be in more than one currency - res[product.id] = self.pool.get('res.currency').compute(cr, uid, currency_id, + res[product.id] = self.pool.get('res.currency').compute(cr, uid, product.currency_id.id, context['currency_id'], res[product.id], context=context) return res From d2f848532399874eae7af3dc8b8983a058566f25 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Wed, 27 Jan 2016 15:56:56 +0100 Subject: [PATCH 02/16] [FIX] account: correct migration of tags and taxes --- addons/account/models/chart_template.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addons/account/models/chart_template.py b/addons/account/models/chart_template.py index 3b95fa9851b..24f39962cdb 100644 --- a/addons/account/models/chart_template.py +++ b/addons/account/models/chart_template.py @@ -19,7 +19,8 @@ def migrate_set_tags_and_taxes_updatable(cr, registry, module): that need migration (for example in case of VAT report improvements) ''' xml_record_ids = registry['ir.model.data'].search(cr, SUPERUSER_ID, [('model', 'in', ['account.tax.template', 'account.account.tag']), ('module', 'like', module)]) - cr.execute("update ir_model_data set noupdate = 'f' where id in %s", (tuple(xml_record_ids),)) + if xml_record_ids: + cr.execute("update ir_model_data set noupdate = 'f' where id in %s", (tuple(xml_record_ids),)) def migrate_tags_on_taxes(cr, registry): ''' This is a utiliy function to help migrate the tags of taxes when the localization has been modified on stable version. If From 36994a6616fae35b702c6bb9f1ed3779ece66fa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Tue, 26 Jan 2016 16:06:29 +0100 Subject: [PATCH 03/16] [FIX] web: load async js modules as soon as possible The module system allow modules to return a deferred. When that deferred resolves, the module is considered to have succesfully loaded, and the result value is its value. Then, the boot.js code used a setTimeout (via _.defer) to load all its dependencies. This is not wrong per se, but it empties the call stack, which give other code the opportunity to interfere. In particular, it is an issue in phantomjs tests, because it causes a window between the domcontentloaded event (which is a key event in website) and the actual loading of all dependent modules. This execution window can be used to start some tours, but the code of those tours is waiting the next tick to load, so horrible crashes happens. This commit calls immediately process_jobs to avoid those issues. --- addons/web/static/src/js/boot.js | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/addons/web/static/src/js/boot.js b/addons/web/static/src/js/boot.js index 77115499b46..34abca7ef03 100644 --- a/addons/web/static/src/js/boot.js +++ b/addons/web/static/src/js/boot.js @@ -203,24 +203,29 @@ function process_job (job) { var require = make_require(job); + + var job_exec; + var def = $.Deferred(); try { - var def = $.Deferred(); - $.when(job.factory.call(null, require)).then( - function (data) { - services[job.name] = data; - clearTimeout(time); - time = _.defer(odoo.process_jobs, jobs, services); - def.resolve(); - }, function (e) { - job.rejected = e || true; - jobs.push(job); - def.resolve(); - }); + job_exec = job.factory.call(null, require); jobs.splice(jobs.indexOf(job), 1); job_deferred.push(def); } catch (e) { job.error = e; } + if (!job.error) { + $.when(job_exec).then( + function (data) { + services[job.name] = data; + def.resolve(); + odoo.process_jobs(jobs, services); + }, function (e) { + job.rejected = e || true; + jobs.push(job); + def.resolve(); + } + ); + } } function is_ready (job) { From f19210ee08448aebbb5e378067aa5c903b8f45f6 Mon Sep 17 00:00:00 2001 From: Martin Geubelle Date: Tue, 26 Jan 2016 14:48:45 +0100 Subject: [PATCH 04/16] [FIX] web: properly remove nvd3 tooltips We fixed it for the graph view in 6bdf72bac5f6e8 but this needs to be fixed for every views. --- addons/web/static/src/js/action_manager.js | 3 +++ addons/web/static/src/js/views/graph_view.js | 4 ---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/addons/web/static/src/js/action_manager.js b/addons/web/static/src/js/action_manager.js index 2337583b7f9..5eb5aaa9891 100644 --- a/addons/web/static/src/js/action_manager.js +++ b/addons/web/static/src/js/action_manager.js @@ -180,6 +180,9 @@ var ViewManagerAction = WidgetAction.extend({ * @return {jQuery} the view_manager's $el */ detach: function() { + // Hack to remove badly inserted nvd3 tooltips ; should be removed when upgrading nvd3 lib + $('body > .nvtooltip').remove(); + return this.widget.$el.detach(); }, /** diff --git a/addons/web/static/src/js/views/graph_view.js b/addons/web/static/src/js/views/graph_view.js index f8f1bba909a..8a604640fc9 100644 --- a/addons/web/static/src/js/views/graph_view.js +++ b/addons/web/static/src/js/views/graph_view.js @@ -19,10 +19,6 @@ var GraphView = View.extend({ icon: 'fa-bar-chart', view_type: 'graph', - on_detach_callback: function () { - $('body > .nvtooltip').remove(); - }, - init: function(parent, dataset, view_id, options) { this._super(parent, dataset, view_id, options); From fb187b034b42153ddb6350179f1b7be1cbae33bb Mon Sep 17 00:00:00 2001 From: qdp-odoo Date: Wed, 27 Jan 2016 16:31:09 +0100 Subject: [PATCH 05/16] [FIX] account: aged partner balance was crashing because of access rights errors in multi company environment + error fixed in history building --- .../report/account_aged_partner_balance.py | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/addons/account/report/account_aged_partner_balance.py b/addons/account/report/account_aged_partner_balance.py index 6dfcd6a7e8b..ef922719c7f 100644 --- a/addons/account/report/account_aged_partner_balance.py +++ b/addons/account/report/account_aged_partner_balance.py @@ -12,6 +12,7 @@ class ReportAgedPartnerBalance(models.AbstractModel): res = [] self.total_account = [] cr = self.env.cr + user_company = self.env.user.company_id.id move_state = ['draft', 'posted'] if target_move == 'posted': move_state = ['posted'] @@ -25,7 +26,8 @@ class ReportAgedPartnerBalance(models.AbstractModel): AND l.reconciled IS FALSE\ AND (l.partner_id = res_partner.id)\ AND (l.date <= %s)\ - ORDER BY res_partner.name', (tuple(move_state), tuple(account_type), date_from)) + AND l.company_id = %s \ + ORDER BY res_partner.name', (tuple(move_state), tuple(account_type), date_from, user_company)) partners = cr.dictfetchall() # put a total of 0 @@ -46,7 +48,8 @@ class ReportAgedPartnerBalance(models.AbstractModel): AND (account_account.internal_type IN %s)\ AND (l.partner_id IN %s)\ AND (l.date <= %s)\ - GROUP BY l.partner_id ', (tuple(move_state), tuple(account_type), tuple(partner_ids), date_from,)) + AND l.company_id = %s \ + GROUP BY l.partner_id ', (tuple(move_state), tuple(account_type), tuple(partner_ids), date_from, user_company)) partner_totals = cr.fetchall() for partner_id, amount in partner_totals: totals[partner_id] = amount @@ -62,7 +65,8 @@ class ReportAgedPartnerBalance(models.AbstractModel): AND (l.partner_id IN %s)\ AND l.reconciled IS FALSE\ AND l.date <= %s \ - GROUP BY l.partner_id', (tuple(move_state), tuple(account_type), date_from, tuple(partner_ids), date_from)) + AND l.company_id = %s \ + GROUP BY l.partner_id', (tuple(move_state), tuple(account_type), date_from, tuple(partner_ids), date_from, user_company)) partner_totals = cr.fetchall() for partner_id, amount in partner_totals: future_past[partner_id] = amount @@ -83,7 +87,7 @@ class ReportAgedPartnerBalance(models.AbstractModel): else: dates_query += ' <= %s)' args_list += (form[str(i)]['stop'],) - args_list += (date_from,) + args_list += (date_from, user_company) query = '''SELECT l.id FROM account_move_line AS l, account_account, account_move am @@ -93,11 +97,11 @@ class ReportAgedPartnerBalance(models.AbstractModel): AND (l.partner_id IN %s) AND ''' + dates_query + ''' AND (l.date <= %s) - GROUP BY l.partner_id, l.id''' + AND l.company_id = %s''' cr.execute(query, args_list) partners_amount = {} aml_ids = cr.fetchall() - aml_ids = aml_ids and aml_ids[0] or [] + aml_ids = aml_ids and [x[0] for x in aml_ids] or [] for line in self.env['account.move.line'].browse(aml_ids): if line.partner_id.id not in partners_amount: partners_amount[line.partner_id.id] = 0.0 @@ -150,6 +154,7 @@ class ReportAgedPartnerBalance(models.AbstractModel): if target_move == 'posted': move_state = ['posted'] + user_company = self.env.user.company_id.id ## put a total of 0 for i in range(7): self.total_account.append(0) @@ -162,7 +167,8 @@ class ReportAgedPartnerBalance(models.AbstractModel): AND (account_account.internal_type IN %s)\ AND l.reconciled IS FALSE \ AND (l.date <= %s)\ - ',(tuple(move_state), tuple(account_type), date_from,)) + AND l.company_id = %s\ + ',(tuple(move_state), tuple(account_type), date_from, user_company)) total_amount = cr.fetchall() for amount in total_amount: totals['Unknown Partner'] = amount[0] @@ -175,7 +181,8 @@ class ReportAgedPartnerBalance(models.AbstractModel): AND (account_account.internal_type IN %s)\ AND (COALESCE(l.date_maturity,l.date) > %s)\ AND l.reconciled IS FALSE\ - ', (tuple(move_state), tuple(account_type), date_from,)) + AND l.company_id = %s\ + ', (tuple(move_state), tuple(account_type), date_from, user_company)) total_amount = cr.fetchall() for amount in total_amount: future_past['Unknown Partner'] = amount[0] @@ -193,7 +200,7 @@ class ReportAgedPartnerBalance(models.AbstractModel): else: dates_query += ' < %s)' args_list += (form[str(i)]['stop'],) - args_list += (date_from,) + args_list += (date_from, user_company) cr.execute('SELECT SUM(l.debit - l.credit)\ FROM account_move_line AS l, account_account, account_move am \ WHERE (l.account_id = account_account.id) AND (l.move_id = am.id)\ @@ -203,6 +210,7 @@ class ReportAgedPartnerBalance(models.AbstractModel): AND l.reconciled IS FALSE\ AND ' + dates_query + '\ AND (l.date <= %s)\ + AND l.company_id = %s\ GROUP BY l.partner_id', args_list) total_amount = cr.fetchall() history_data = {} From 3fcb70e3149546ccec7c9621a523841cef0c0ddb Mon Sep 17 00:00:00 2001 From: qdp-odoo Date: Wed, 27 Jan 2016 16:32:52 +0100 Subject: [PATCH 06/16] [FIX] account_extra_reports: sale/purchase journal fixed (tax summary was completly wrong and crashing) --- .../report/account_journal.py | 39 ++++++++++++------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/addons/account_extra_reports/report/account_journal.py b/addons/account_extra_reports/report/account_journal.py index 77d7d8222cf..90bfba7cba0 100644 --- a/addons/account_extra_reports/report/account_journal.py +++ b/addons/account_extra_reports/report/account_journal.py @@ -17,12 +17,12 @@ class ReportJournal(models.AbstractModel): query_get_clause = self._get_query_get_clause(data) params = [tuple(move_state), tuple(journal_ids)] + query_get_clause[2] - query = 'SELECT "account_move_line".id FROM ' + query_get_clause[0] + ', account_move am WHERE "account_move_line".move_id=am.id AND am.state IN %s AND "account_move_line".journal_id IN %s AND ' + query_get_clause[1] + ' ORDER BY ' + query = 'SELECT "account_move_line".id FROM ' + query_get_clause[0] + ', account_move am, account_account acc WHERE "account_move_line".account_id = acc.id AND "account_move_line".move_id=am.id AND am.state IN %s AND "account_move_line".journal_id IN %s AND ' + query_get_clause[1] + ' ORDER BY ' if sort_selection == 'date': query += '"account_move_line".date' else: query += 'am.name' - query += ', "account_move_line".move_id' + query += ', "account_move_line".move_id, acc.code' self.env.cr.execute(query, tuple(params)) ids = map(lambda x: x[0], self.env.cr.fetchall()) return self.env['account.move.line'].browse(ids) @@ -58,23 +58,32 @@ class ReportJournal(models.AbstractModel): query_get_clause = self._get_query_get_clause(data) params = [tuple(move_state), tuple(journal_id.ids)] + query_get_clause[2] - self.env.cr.execute('SELECT DISTINCT tax_line_id FROM ' + query_get_clause[0] + ', account_move am ' - 'WHERE "account_move_line".move_id=am.id AND am.state IN %s AND "account_move_line".journal_id IN %s AND ' + query_get_clause[1] + ' AND tax_line_id is not null', - tuple(params)) - ids = map(lambda x: x[0], self.env.cr.fetchall()) - taxes = self.env['account.tax'].browse(ids) + query = """ + SELECT rel.account_tax_id, SUM("account_move_line".balance) AS base_amount + FROM account_move_line_account_tax_rel rel, """ + query_get_clause[0] + """ + LEFT JOIN account_move am ON "account_move_line".move_id = am.id + WHERE "account_move_line".id = rel.account_move_line_id + AND am.state IN %s + AND "account_move_line".journal_id IN %s + AND """ + query_get_clause[1] + """ + GROUP BY rel.account_tax_id""" + self.env.cr.execute(query, tuple(params)) + ids = [] + base_amounts = {} + for row in self.env.cr.fetchall(): + ids.append(row[0]) + base_amounts[row[0]] = row[1] + + res = {} - for tax in taxes: - res[tax] = {} + for tax in self.env['account.tax'].browse(ids): self.env.cr.execute('SELECT sum(debit - credit) FROM ' + query_get_clause[0] + ', account_move am ' 'WHERE "account_move_line".move_id=am.id AND am.state IN %s AND "account_move_line".journal_id IN %s AND ' + query_get_clause[1] + ' AND tax_line_id = %s', tuple(params + [tax.id])) - res[tax]['tax_amount'] = self.env.cr.fetchone()[0] or 0.0 - amls = self.env['account.move.line'].search([('tax_ids', 'in', [tax.id])]) - self.env.cr.execute('SELECT sum(debit - credit) FROM ' + query_get_clause[0] + ', account_move am ' - 'WHERE "account_move_line".move_id=am.id AND am.state IN %s AND "account_move_line".journal_id IN %s AND ' + query_get_clause[1] + ' AND "account_move_line".id in %s', - tuple(params + [tuple(amls.ids)])) - res[tax]['base_amount'] = self.env.cr.fetchone()[0] or 0.0 + res[tax] = { + 'base_amount': base_amounts[tax.id], + 'tax_amount': self.env.cr.fetchone()[0] or 0.0, + } if journal_id.type == 'sale': #sales operation are credits res[tax]['base_amount'] = res[tax]['base_amount'] * -1 From a2d3d4d449acbd1c07d2a2ec1935193eabaaefcb Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Wed, 27 Jan 2016 18:25:08 +0100 Subject: [PATCH 07/16] [FIX] ir_sequence: `range_` actually uses the range start date In a sequence, `range_year` is supposed to be the year of the range beginning date: ``` When subsequences per date range are used, you can prefix variables with 'range_' to use the beginning of the range instead of the current date, e.g. %(range_year)s instead of %(year)s. ``` Therefore, for a sequence with ranges configured as: - 20150701 to 20160630 - 20160701 to 20170630 An invoice confirmed on 20160101 must have `2015` as year when using `range_year`, and not `2016`. If you would like the invoice effective date, you must then use `year`, instead. We add the `current_%` keys as well, in case some users absolutely want the `now` date instead of the effective date, but it doesn't make much sense in the context of accounting. Besides, outside the context of the accounting, `year`, `month`, `date` etc is the `now` date. opw-649487 --- openerp/addons/base/ir/ir_sequence.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/openerp/addons/base/ir/ir_sequence.py b/openerp/addons/base/ir/ir_sequence.py index ebd8ab0ee3e..2a0f3ab47b7 100644 --- a/openerp/addons/base/ir/ir_sequence.py +++ b/openerp/addons/base/ir/ir_sequence.py @@ -194,19 +194,21 @@ class ir_sequence(models.Model): return '' def _interpolation_dict(): - now = datetime.now(pytz.timezone(self.env.context.get('tz') or 'UTC')) + now = range_date = effective_date = datetime.now(pytz.timezone(self.env.context.get('tz') or 'UTC')) if self.env.context.get('ir_sequence_date'): - t = datetime.strptime(self.env.context.get('ir_sequence_date'), '%Y-%m-%d') - else: - t = now + effective_date = datetime.strptime(self.env.context.get('ir_sequence_date'), '%Y-%m-%d') + if self.env.context.get('ir_sequence_date_range'): + range_date = datetime.strptime(self.env.context.get('ir_sequence_date_range'), '%Y-%m-%d') + sequences = { 'year': '%Y', 'month': '%m', 'day': '%d', 'y': '%y', 'doy': '%j', 'woy': '%W', 'weekday': '%w', 'h24': '%H', 'h12': '%I', 'min': '%M', 'sec': '%S' } res = {} for key, sequence in sequences.iteritems(): - res[key] = now.strftime(sequence) - res['range_' + key] = t.strftime(sequence) + res[key] = effective_date.strftime(sequence) + res['range_' + key] = range_date.strftime(sequence) + res['current_' + key] = now.strftime(sequence) return res @@ -248,7 +250,7 @@ class ir_sequence(models.Model): seq_date = self.env['ir.sequence.date_range'].search([('sequence_id', '=', self.id), ('date_from', '<=', dt), ('date_to', '>=', dt)], limit=1) if not seq_date: seq_date = self._create_date_range_seq(dt) - return seq_date._next() + return seq_date.with_context(ir_sequence_date_range=seq_date.date_from)._next() @api.multi def next_by_id(self): From 51a192635375ea1ef56d3f548d02bdd62c20d65a Mon Sep 17 00:00:00 2001 From: Christophe Matthieu Date: Wed, 27 Jan 2016 17:05:14 +0100 Subject: [PATCH 08/16] [FIX] computed html field should not have "note-editable" class opw-660810 --- addons/web_editor/static/src/css/backend.css | 2 +- addons/web_editor/static/src/js/backend.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/web_editor/static/src/css/backend.css b/addons/web_editor/static/src/css/backend.css index 33a7155354c..2512b1de9c0 100644 --- a/addons/web_editor/static/src/css/backend.css +++ b/addons/web_editor/static/src/css/backend.css @@ -5,7 +5,7 @@ line-height: initial !important; color: initial !important; } -.oe_form_field_html_text iframe.o_readonly { +.oe_form_field_html_text .o_readonly { min-height: 1em; width: 100%; margin: 0; diff --git a/addons/web_editor/static/src/js/backend.js b/addons/web_editor/static/src/js/backend.js index becd0fe4769..7649d923f98 100644 --- a/addons/web_editor/static/src/js/backend.js +++ b/addons/web_editor/static/src/js/backend.js @@ -73,7 +73,7 @@ var FieldTextHtmlSimple = widget.extend({ self.resize(); }); } else { - this.$content = $('
'); + this.$content = $('
'); this.$textarea.hide().after(this.$content); } } else { From 3fab3a13471a499e7083e042bb477fb25a8619f1 Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Wed, 27 Jan 2016 16:41:48 +0100 Subject: [PATCH 09/16] [FIX] purchase: width in tree view In enterprise/web/static/src/xml/base.xml, the javascript template ListView uses on each column (field) column.width() where width is a javascript function. Then argument width cannot be use in tree view. opw:667465 --- addons/purchase/purchase_view.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/purchase/purchase_view.xml b/addons/purchase/purchase_view.xml index 41928b24db0..b4c21dc054e 100644 --- a/addons/purchase/purchase_view.xml +++ b/addons/purchase/purchase_view.xml @@ -414,7 +414,7 @@ - + From d35e75f7eb23e7274d306c57c30501bdf8a82906 Mon Sep 17 00:00:00 2001 From: qdp-odoo Date: Thu, 28 Jan 2016 10:58:08 +0100 Subject: [PATCH 10/16] [FIX] account: fixed computation of reconciled fields on account.move.line and account.invoice which were wrong due to bad usage of float_is_zero() --- addons/account/models/account_bank_statement.py | 2 +- addons/account/models/account_invoice.py | 2 +- addons/account/models/account_move.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/account/models/account_bank_statement.py b/addons/account/models/account_bank_statement.py index 4468d3e129a..b9ef598ff3e 100644 --- a/addons/account/models/account_bank_statement.py +++ b/addons/account/models/account_bank_statement.py @@ -81,7 +81,7 @@ class AccountBankStatement(models.Model): @api.multi def _is_difference_zero(self): for bank_stmt in self: - bank_stmt.is_difference_zero = float_is_zero(bank_stmt.difference, bank_stmt.currency_id.decimal_places) + bank_stmt.is_difference_zero = float_is_zero(bank_stmt.difference, precision_digits=bank_stmt.currency_id.decimal_places) @api.one @api.depends('journal_id') diff --git a/addons/account/models/account_invoice.py b/addons/account/models/account_invoice.py index ba922150f89..e354c44f2ca 100644 --- a/addons/account/models/account_invoice.py +++ b/addons/account/models/account_invoice.py @@ -97,7 +97,7 @@ class AccountInvoice(models.Model): self.residual_signed = abs(residual) * sign self.residual = abs(residual) digits_rounding_precision = self.currency_id.rounding - if float_is_zero(self.residual, digits_rounding_precision): + if float_is_zero(self.residual, precision_rounding=digits_rounding_precision): self.reconciled = True else: self.reconciled = False diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index 157c40ce542..ff03ccc2fe6 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -254,7 +254,7 @@ class AccountMoveLine(models.Model): #we can only check the amount in company currency reconciled = False digits_rounding_precision = line.company_id.currency_id.rounding - if float_is_zero(amount, digits_rounding_precision) and (line.debit or line.credit): + if float_is_zero(amount, precision_rounding=digits_rounding_precision) and (line.debit or line.credit): reconciled = True line.reconciled = reconciled From 5ff25215c7d453cabf067b939ef6721467e119b4 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Thu, 28 Jan 2016 11:05:25 +0100 Subject: [PATCH 11/16] [FIX] product_visible_discount: trigger property on overriden `product_uom_change` This revision is related to feb2ede0d6c48982209a5b18a20b58f69c70327c When overriding an onchange method, the `@api.change` property, that decides on which fields the onchange method must be triggered, should be the same on the overriding and the overriden method. Otherwise, the base onchange won't be triggered on the fields it expected to. opw-668049 --- addons/product_visible_discount/product_visible_discount.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/product_visible_discount/product_visible_discount.py b/addons/product_visible_discount/product_visible_discount.py index 426dea5a9ed..077ec1efa21 100644 --- a/addons/product_visible_discount/product_visible_discount.py +++ b/addons/product_visible_discount/product_visible_discount.py @@ -70,7 +70,7 @@ class sale_order_line(osv.osv): line.discount = 0.0 return res - @api.onchange('product_uom') + @api.onchange('product_uom', 'product_uom_qty') def product_uom_change(self): res = super(sale_order_line, self).product_uom_change() if not self.product_uom: From 261380250d639c6db7d2c00e5c2ce22d2f0ed392 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Thu, 3 Dec 2015 14:48:50 +0100 Subject: [PATCH 12/16] [IMP] base: do not warn about new application installation This warning is linked to SaaS pricing and should not be present in base has been moved to internal code. --- openerp/addons/base/i18n/base.pot | 7 ------- openerp/addons/base/res/res_config.py | 16 ---------------- 2 files changed, 23 deletions(-) diff --git a/openerp/addons/base/i18n/base.pot b/openerp/addons/base/i18n/base.pot index 00f745ab7c2..141575a5434 100644 --- a/openerp/addons/base/i18n/base.pot +++ b/openerp/addons/base/i18n/base.pot @@ -7987,13 +7987,6 @@ msgstr "" msgid "Enable Light Multi Company" msgstr "" -#. module: base -#: code:addons/base/res/res_config.py:479 -#, python-format -msgid "Enabling this feature will install the following paying application(s) : \n" -"%s" -msgstr "" - #. module: base #: selection:base.language.install,lang:0 msgid "English (AU)" diff --git a/openerp/addons/base/res/res_config.py b/openerp/addons/base/res/res_config.py index 9217cb22ac9..db01d2595fd 100644 --- a/openerp/addons/base/res/res_config.py +++ b/openerp/addons/base/res/res_config.py @@ -460,10 +460,6 @@ class res_config_settings(osv.osv_memory, res_config_module_installation_mixin): cr, SUPERUSER_ID, [('name', '=', module_name.replace("module_", '')), ('state','in', ['to install', 'installed', 'to upgrade'])], context=context) - installed_module_ids = module_pool.search( - cr, SUPERUSER_ID, [('name', '=', module_name.replace("module_", '')), - ('state', 'in', ['uninstalled'])], - context=context) if module_ids and not field_value: dep_ids = module_pool.downstream_dependencies(cr, SUPERUSER_ID, module_ids, context=context) @@ -476,18 +472,6 @@ class res_config_settings(osv.osv_memory, res_config_module_installation_mixin): 'message': _('Disabling this option will also uninstall the following modules \n%s') % message, } } - if installed_module_ids and field_value: - dep_ids = module_pool.upstream_dependencies(cr, SUPERUSER_ID, installed_module_ids, context=context) - dep_name = [x['display_name'] for x in module_pool.search_read( - cr, SUPERUSER_ID, ['|', ('id', 'in', installed_module_ids), ('id', 'in', dep_ids), ('application', '=', True)], context=context)] - if dep_name: - message = ''.join(["- %s \n" % name for name in dep_name]) - return { - 'warning': { - 'title': _('Warning!'), - 'message': _('Enabling this feature will install the following paying application(s) : \n%s') % message, - } - } return {} def _get_classified_fields(self, cr, uid, context=None): From c5923774a0fece4df6794cc2d377f4c7cb9b0744 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Thu, 28 Jan 2016 17:44:28 +0530 Subject: [PATCH 13/16] [FIX] web_settings_dashboard: missing terms in .pot Get more features with the Enterprise Edition! opw 666709 --- .../i18n/web_settings_dashboard.pot | 50 +++++++++++++++---- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/addons/web_settings_dashboard/i18n/web_settings_dashboard.pot b/addons/web_settings_dashboard/i18n/web_settings_dashboard.pot index be3b3986c74..6ddf7cee78b 100644 --- a/addons/web_settings_dashboard/i18n/web_settings_dashboard.pot +++ b/addons/web_settings_dashboard/i18n/web_settings_dashboard.pot @@ -4,10 +4,10 @@ # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 9.0\n" +"Project-Id-Version: Odoo Server 9.0c\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-09-07 14:41+0000\n" -"PO-Revision-Date: 2015-09-07 14:41+0000\n" +"POT-Creation-Date: 2016-01-28 12:13+0000\n" +"PO-Revision-Date: 2016-01-28 12:13+0000\n" "Last-Translator: <>\n" "Language-Team: \n" "MIME-Version: 1.0\n" @@ -59,21 +59,28 @@ msgstr "" #. module: web_settings_dashboard #. openerp-web -#: code:addons/web_settings_dashboard/static/src/xml/dashboard.xml:58 +#: code:addons/web_settings_dashboard/static/src/xml/dashboard.xml:64 #, python-format msgid "Enter e-mail addresses (one per line)" msgstr "" #. module: web_settings_dashboard #. openerp-web -#: code:addons/web_settings_dashboard/static/src/xml/dashboard.xml:82 +#: code:addons/web_settings_dashboard/static/src/xml/dashboard.xml:92 #, python-format msgid "Follow these implementation guides to get the most out of Odoo." msgstr "" #. module: web_settings_dashboard #. openerp-web -#: code:addons/web_settings_dashboard/static/src/xml/dashboard.xml:121 +#: code:addons/web_settings_dashboard/static/src/xml/dashboard.xml:149 +#, python-format +msgid "Get more features with the Enterprise Edition!" +msgstr "" + +#. module: web_settings_dashboard +#. openerp-web +#: code:addons/web_settings_dashboard/static/src/xml/dashboard.xml:131 #, python-format msgid "Help us spread the word: Share Odoo's awesomeness with your friends!" msgstr "" @@ -129,32 +136,46 @@ msgstr "" #. module: web_settings_dashboard #. openerp-web -#: code:addons/web_settings_dashboard/static/src/xml/dashboard.xml:65 +#: code:addons/web_settings_dashboard/static/src/xml/dashboard.xml:148 +#, python-format +msgid "Odoo Enterprise" +msgstr "" + +#. module: web_settings_dashboard +#. openerp-web +#: code:addons/web_settings_dashboard/static/src/xml/dashboard.xml:71 #, python-format msgid "Pending invitations:" msgstr "" #. module: web_settings_dashboard #. openerp-web -#: code:addons/web_settings_dashboard/static/src/js/dashboard.js:109 +#: code:addons/web_settings_dashboard/static/src/js/dashboard.js:107 #, python-format msgid "Please provide valid email addresses" msgstr "" #. module: web_settings_dashboard #. openerp-web -#: code:addons/web_settings_dashboard/static/src/xml/dashboard.xml:119 +#: code:addons/web_settings_dashboard/static/src/xml/dashboard.xml:129 #, python-format msgid "Social Share" msgstr "" #. module: web_settings_dashboard #. openerp-web -#: code:addons/web_settings_dashboard/static/src/xml/dashboard.xml:10 +#: code:addons/web_settings_dashboard/static/src/xml/dashboard.xml:43 #, python-format msgid "Theme store" msgstr "" +#. module: web_settings_dashboard +#. openerp-web +#: code:addons/web_settings_dashboard/static/src/xml/dashboard.xml:152 +#, python-format +msgid "Upgrade Now" +msgstr "" + #. module: web_settings_dashboard #: model:ir.model,name:web_settings_dashboard.model_res_users msgid "Users" @@ -162,8 +183,15 @@ msgstr "" #. module: web_settings_dashboard #. openerp-web -#: code:addons/web_settings_dashboard/static/src/xml/dashboard.xml:97 +#: code:addons/web_settings_dashboard/static/src/xml/dashboard.xml:107 #, python-format msgid "You need to install some apps first." msgstr "" +#. module: web_settings_dashboard +#. openerp-web +#: code:addons/web_settings_dashboard/static/src/xml/dashboard.xml:77 +#, python-format +msgid "more" +msgstr "" + From 9052bdc9cb14f9f7fe29d87373a31185806a18de Mon Sep 17 00:00:00 2001 From: Nicolas Martinelli Date: Wed, 27 Jan 2016 14:20:55 +0100 Subject: [PATCH 14/16] [FIX] account: calculation of amount residual When an account move line is reconciled with debits and credits, both are subtracted from the original amount. This is not logical, since if the line is a credit (debit) we should subtract (add) the debits and add (subtract) the credits. opw-667137 --- addons/account/models/account_move.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index ff03ccc2fe6..6fdcf5cc8b8 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -241,14 +241,20 @@ class AccountMoveLine(models.Model): sign = 1 if (line.debit - line.credit) > 0 else -1 for partial_line in (line.matched_debit_ids + line.matched_credit_ids): - amount -= partial_line.amount + # If line is a credit (sign = -1) we: + # - subtract matched_debit_ids (partial_line.credit_move_id == line) + # - add matched_credit_ids (partial_line.credit_move_id != line) + # If line is a debit (sign = 1), do the opposite. + sign_partial_line = sign if partial_line.credit_move_id == line else (-1 * sign) + + amount += sign_partial_line * partial_line.amount #getting the date of the matched item to compute the amount_residual in currency date = partial_line.credit_move_id.date if partial_line.debit_move_id == line else partial_line.debit_move_id.date if line.currency_id: if partial_line.currency_id and partial_line.currency_id == line.currency_id: - amount_residual_currency -= partial_line.amount_currency + amount_residual_currency += sign_partial_line * partial_line.amount_currency else: - amount_residual_currency -= line.company_id.currency_id.with_context(date=date).compute(partial_line.amount, line.currency_id) + amount_residual_currency += sign_partial_line * line.company_id.currency_id.with_context(date=date).compute(partial_line.amount, line.currency_id) #computing the `reconciled` field. As we book exchange rate difference on each partial matching, #we can only check the amount in company currency From ca343f7b041b6b8c7223748214392a77f3b7735f Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Thu, 28 Jan 2016 11:25:05 +0100 Subject: [PATCH 15/16] [FIX] purchase: currency_id in purchase report The field currency_id must be in the view to group by currency_id. opw:667869 --- addons/purchase/report/purchase_report.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/addons/purchase/report/purchase_report.py b/addons/purchase/report/purchase_report.py index 4cd3341b2b6..4786e46a7b9 100644 --- a/addons/purchase/report/purchase_report.py +++ b/addons/purchase/report/purchase_report.py @@ -72,6 +72,7 @@ class purchase_report(osv.osv): l.product_id, p.product_tmpl_id, t.categ_id as category_id, + s.currency_id, t.uom_id as product_uom, sum(l.product_qty/u.factor*u2.factor) as quantity, extract(epoch from age(s.date_approve,s.date_order))/(24*60*60)::decimal(16,2) as delay, @@ -102,6 +103,7 @@ class purchase_report(osv.osv): s.create_uid, s.partner_id, u.factor, + s.currency_id, l.price_unit, s.date_approve, l.date_planned, From 28e2dcf043dd853938b1bb385f81fa285b4df567 Mon Sep 17 00:00:00 2001 From: Jeremy Kersten Date: Thu, 28 Jan 2016 11:01:15 +0100 Subject: [PATCH 16/16] [FIX] website_payment, website_mail: fix route declaration typo Missing s of method for allowed methods. --- addons/website_mail/controllers/main.py | 2 +- addons/website_payment/controllers/main.py | 2 +- addons/website_sale/controllers/website_mail.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/website_mail/controllers/main.py b/addons/website_mail/controllers/main.py index a71d25dea51..64f11412aa1 100644 --- a/addons/website_mail/controllers/main.py +++ b/addons/website_mail/controllers/main.py @@ -163,7 +163,7 @@ class WebsiteMail(http.Controller): except Exception: return False - @http.route(['/website_mail/post/post'], type='http', method=['POST'], auth='public', website=True) + @http.route(['/website_mail/post/post'], type='http', methods=['POST'], auth='public', website=True) def chatter_post(self, res_model='', res_id=None, message='', redirect=None, **kw): res_id = int(res_id) url = request.httprequest.referrer diff --git a/addons/website_payment/controllers/main.py b/addons/website_payment/controllers/main.py index 13c84313dbd..c351e939578 100644 --- a/addons/website_payment/controllers/main.py +++ b/addons/website_payment/controllers/main.py @@ -18,7 +18,7 @@ class website_payment(http.Controller): acquirer.form = acquirer.sudo()._registration_render(request.env.user.partner_id.id, {'error': {}, 'error_message': [], 'return_url': '/my/payment_method', 'json': False, 'bootstrap_formatting': True})[0] return request.website.render("website_payment.pay_methods", values) - @http.route(['/website_payment/delete/'], method=['POST'], type='http', auth="user", website=True) + @http.route(['/website_payment/delete/'], methods=['POST'], type='http', auth="user", website=True) def delete(self, delete_pm_id=None): if delete_pm_id: pay_meth = request.env['payment.method'].browse(int(delete_pm_id)) diff --git a/addons/website_sale/controllers/website_mail.py b/addons/website_sale/controllers/website_mail.py index 937adbb3d0f..2fe6e5f5355 100644 --- a/addons/website_sale/controllers/website_mail.py +++ b/addons/website_sale/controllers/website_mail.py @@ -29,7 +29,7 @@ class WebsiteMailController(WebsiteMail): }) return message_data - @http.route(['/website_mail/post/post'], type='http', method=['POST'], auth='public', website=True) + @http.route(['/website_mail/post/post'], type='http', methods=['POST'], auth='public', website=True) def chatter_post(self, res_model='', res_id=None, message='', redirect=None, **kw): params = kw.copy() params.pop('rating')