From 7586194e0ca68e7c25b6a1725d368eb8d5c62b3a Mon Sep 17 00:00:00 2001 From: Joren Van Onder Date: Wed, 27 Jan 2016 10:02:14 +0100 Subject: [PATCH 01/88] [IMP] account: create an index on account.move.statement_line_id account.bank.statement.line has a journal_entry_ids field which is a o2m to account.move. During confirmation of bank statements (button_confirm_bank()) this o2m field is heavily used. When a database has a lot of account.move records this lookup starts taking up quite a bit of time. As an example, on a locally duplicated customer database with ~700000 account.move records attempting to resolve journal_entry_ids of an account.bank.statement.line record was observed to take > 1 second. This index improves it to be < 5 milliseconds. This is especially important when big POS sessions have to be closed, because those will contain a lot of account.bank.statement.line records. opw-665309 --- addons/account/account.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/account/account.py b/addons/account/account.py index ac56c6891e2..1380a01d139 100644 --- a/addons/account/account.py +++ b/addons/account/account.py @@ -1295,7 +1295,7 @@ class account_move(osv.osv): 'narration':fields.text('Internal Note'), 'company_id': fields.related('journal_id','company_id',type='many2one',relation='res.company',string='Company', store=True, readonly=True), 'balance': fields.float('balance', digits_compute=dp.get_precision('Account'), help="This is a field only used for internal purpose and shouldn't be displayed"), - 'statement_line_id': fields.many2one('account.bank.statement.line', 'Bank statement line reconciled with this entry', copy=False, readonly=True) + 'statement_line_id': fields.many2one('account.bank.statement.line', 'Bank statement line reconciled with this entry', copy=False, readonly=True, select=True) } _defaults = { From 634c62610efc784b47206a700a796fdbb343ec30 Mon Sep 17 00:00:00 2001 From: Joren Van Onder Date: Wed, 27 Jan 2016 12:21:40 +0100 Subject: [PATCH 02/88] [FIX] purchase: only search in requested model Because otherwise a user who has access to a view displaying supplier_invoice_count will get an access error if he doesn't also have access to purchase.order, even if that wouldn't have been displayed. opw-666935 --- addons/purchase/partner.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/addons/purchase/partner.py b/addons/purchase/partner.py index bc2255cca03..b86471fafaa 100644 --- a/addons/purchase/partner.py +++ b/addons/purchase/partner.py @@ -28,13 +28,17 @@ class res_partner(osv.osv): def _purchase_invoice_count(self, cr, uid, ids, field_name, arg, context=None): PurchaseOrder = self.pool['purchase.order'] Invoice = self.pool['account.invoice'] - return { - partner_id: { - 'purchase_order_count': PurchaseOrder.search_count(cr,uid, [('partner_id', 'child_of', partner_id)], context=context), - 'supplier_invoice_count': Invoice.search_count(cr,uid, [('partner_id', 'child_of', partner_id), ('type','=','in_invoice')], context=context) - } - for partner_id in ids - } + res = {} + + for partner_id in ids: + res[partner_id] = {} + + if 'purchase_order_count' in field_name: + res[partner_id]['purchase_order_count'] = PurchaseOrder.search_count(cr,uid, [('partner_id', 'child_of', partner_id)], context=context) + if 'supplier_invoice_count' in field_name: + res[partner_id]['supplier_invoice_count'] = Invoice.search_count(cr,uid, [('partner_id', 'child_of', partner_id), ('type','=','in_invoice')], context=context) + + return res def _commercial_fields(self, cr, uid, context=None): return super(res_partner, self)._commercial_fields(cr, uid, context=context) + ['property_product_pricelist_purchase'] From 3622c0d12a879d8184b249c49ba2e24995d6a595 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Wed, 27 Jan 2016 13:58:13 +0100 Subject: [PATCH 03/88] [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 04/88] [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 05/88] [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 06/88] [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 07/88] [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 08/88] [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 e2d16ea04a2ae98800086619ff5dc94dfa6eb5d3 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Wed, 27 Jan 2016 16:28:49 +0100 Subject: [PATCH 09/88] [FIX] account_voucher: unreconcile with deleted journal items This is possible to unreconcile and then remove journal items associated to `account.voucher.line`. When it's done, the voucher is within a corrupted state, with debits and credits lines without journal item, which is required. Because the journal item of this line is empty, while required, this is no longer possible to use the "Unreconcile" button, because the form is invalid. In order to allow to unreconcile a posted customer/supplier payments with missing journal items, we set the journal items as required only when the payment is within the `draft` stage. opw-667232 --- addons/account_voucher/account_voucher.py | 1 + addons/account_voucher/voucher_payment_receipt_view.xml | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/addons/account_voucher/account_voucher.py b/addons/account_voucher/account_voucher.py index d942225d70b..949239f8124 100644 --- a/addons/account_voucher/account_voucher.py +++ b/addons/account_voucher/account_voucher.py @@ -1498,6 +1498,7 @@ class account_voucher_line(osv.osv): 'amount_unreconciled': fields.function(_compute_balance, multi='dc', type='float', string='Open Balance', store=True, digits_compute=dp.get_precision('Account')), 'company_id': fields.related('voucher_id','company_id', relation='res.company', type='many2one', string='Company', store=True, readonly=True), 'currency_id': fields.function(_currency_id, string='Currency', type='many2one', relation='res.currency', readonly=True), + 'state': fields.related('voucher_id', 'state', type='char', string='State', readonly=True), } _defaults = { 'name': '', diff --git a/addons/account_voucher/voucher_payment_receipt_view.xml b/addons/account_voucher/voucher_payment_receipt_view.xml index 073b1efed82..f70f47c54ef 100644 --- a/addons/account_voucher/voucher_payment_receipt_view.xml +++ b/addons/account_voucher/voucher_payment_receipt_view.xml @@ -163,10 +163,11 @@