diff --git a/addons/account/account.py b/addons/account/account.py index d4d3d5b42eb..aad42be0ba4 100644 --- a/addons/account/account.py +++ b/addons/account/account.py @@ -3046,6 +3046,20 @@ class wizard_multi_charts_accounts(osv.osv_memory): 'complete_tax_set': fields.boolean('Complete Set of Taxes', help='This boolean helps you to choose if you want to propose to the user to encode the sales and purchase rates or use the usual m2o fields. This last choice assumes that the set of tax defined for the chosen template is complete'), } + + def _get_chart_parent_ids(self, cr, uid, chart_template, context=None): + """ Returns the IDs of all ancestor charts, including the chart itself. + (inverse of child_of operator) + + :param browse_record chart_template: the account.chart.template record + :return: the IDS of all ancestor charts, including the chart itself. + """ + result = [chart_template.id] + while chart_template.parent_id: + chart_template = chart_template.parent_id + result.append(chart_template.id) + return result + def onchange_tax_rate(self, cr, uid, ids, rate=False, context=None): return {'value': {'purchase_tax_rate': rate or False}} @@ -3065,12 +3079,17 @@ class wizard_multi_charts_accounts(osv.osv_memory): res['value'].update({'complete_tax_set': data.complete_tax_set, 'currency_id': currency_id}) if data.complete_tax_set: # default tax is given by the lowest sequence. For same sequence we will take the latest created as it will be the case for tax created while isntalling the generic chart of account - sale_tax_ids = tax_templ_obj.search(cr, uid, [("chart_template_id" - , "=", chart_template_id), ('type_tax_use', 'in', ('sale','all'))], order="sequence, id desc") - purchase_tax_ids = tax_templ_obj.search(cr, uid, [("chart_template_id" - , "=", chart_template_id), ('type_tax_use', 'in', ('purchase','all'))], order="sequence, id desc") - res['value'].update({'sale_tax': sale_tax_ids and sale_tax_ids[0] or False, 'purchase_tax': purchase_tax_ids and purchase_tax_ids[0] or False}) - + chart_ids = self._get_chart_parent_ids(cr, uid, data, context=context) + base_tax_domain = [("chart_template_id", "in", chart_ids), ('parent_id', '=', False)] + sale_tax_domain = base_tax_domain + [('type_tax_use', 'in', ('sale','all'))] + purchase_tax_domain = base_tax_domain + [('type_tax_use', 'in', ('purchase','all'))] + sale_tax_ids = tax_templ_obj.search(cr, uid, sale_tax_domain, order="sequence, id desc") + purchase_tax_ids = tax_templ_obj.search(cr, uid, purchase_tax_domain, order="sequence, id desc") + res['value'].update({'sale_tax': sale_tax_ids and sale_tax_ids[0] or False, + 'purchase_tax': purchase_tax_ids and purchase_tax_ids[0] or False}) + res.setdefault('domain', {}) + res['domain']['sale_tax'] = repr(sale_tax_domain) + res['domain']['purchase_tax'] = repr(purchase_tax_domain) if data.code_digits: res['value'].update({'code_digits': data.code_digits}) return res @@ -3078,6 +3097,7 @@ class wizard_multi_charts_accounts(osv.osv_memory): def default_get(self, cr, uid, fields, context=None): res = super(wizard_multi_charts_accounts, self).default_get(cr, uid, fields, context=context) tax_templ_obj = self.pool.get('account.tax.template') + account_chart_template = self.pool['account.chart.template'] data_obj = self.pool.get('ir.model.data') if 'bank_accounts_id' in fields: @@ -3092,23 +3112,28 @@ class wizard_multi_charts_accounts(osv.osv_memory): currency_id = company_obj.on_change_country(cr, uid, company_id, country_id, context=context)['value']['currency_id'] res.update({'currency_id': currency_id}) - ids = self.pool.get('account.chart.template').search(cr, uid, [('visible', '=', True)], context=context) + ids = account_chart_template.search(cr, uid, [('visible', '=', True)], context=context) if ids: + #in order to set default chart which was last created set max of ids. + chart_id = max(ids) + if context.get("default_charts"): + data_ids = data_obj.search(cr, uid, [('model', '=', 'account.chart.template'), ('module', '=', context.get("default_charts"))], limit=1, context=context) + if data_ids: + chart_id = data_obj.browse(cr, uid, data_ids[0], context=context).res_id + chart = account_chart_template.browse(cr, uid, chart_id, context=context) + chart_hierarchy_ids = self._get_chart_parent_ids(cr, uid, chart, context=context) if 'chart_template_id' in fields: - #in order to set default chart which was last created set max of ids. - chart_id = max(ids) - if context.get("default_charts"): - data_ids = data_obj.search(cr, uid, [('model', '=', 'account.chart.template'), ('module', '=', context.get("default_charts"))], limit=1, context=context) - if data_ids: - chart_id = data_obj.browse(cr, uid, data_ids[0], context=context).res_id - res.update({'only_one_chart_template': len(ids) == 1, 'chart_template_id': chart_id}) + res.update({'only_one_chart_template': len(ids) == 1, + 'chart_template_id': chart_id}) if 'sale_tax' in fields: - sale_tax_ids = tax_templ_obj.search(cr, uid, [("chart_template_id" - , "=", ids[0]), ('type_tax_use', 'in', ('sale','all'))], order="sequence") + sale_tax_ids = tax_templ_obj.search(cr, uid, [("chart_template_id", "in", chart_hierarchy_ids), + ('type_tax_use', 'in', ('sale','all'))], + order="sequence") res.update({'sale_tax': sale_tax_ids and sale_tax_ids[0] or False}) if 'purchase_tax' in fields: - purchase_tax_ids = tax_templ_obj.search(cr, uid, [("chart_template_id" - , "=", ids[0]), ('type_tax_use', 'in', ('purchase','all'))], order="sequence") + purchase_tax_ids = tax_templ_obj.search(cr, uid, [("chart_template_id", "in", chart_hierarchy_ids), + ('type_tax_use', 'in', ('purchase','all'))], + order="sequence") res.update({'purchase_tax': purchase_tax_ids and purchase_tax_ids[0] or False}) res.update({ 'purchase_tax_rate': 15.0, @@ -3376,12 +3401,7 @@ class wizard_multi_charts_accounts(osv.osv_memory): obj_tax_temp = self.pool.get('account.tax.template') chart_template = obj_wizard.chart_template_id vals = {} - # get the ids of all the parents of the selected account chart template - current_chart_template = chart_template - all_parents = [current_chart_template.id] - while current_chart_template.parent_id: - current_chart_template = current_chart_template.parent_id - all_parents.append(current_chart_template.id) + all_parents = self._get_chart_parent_ids(cr, uid, chart_template, context=context) # create tax templates and tax code templates from purchase_tax_rate and sale_tax_rate fields if not chart_template.complete_tax_set: value = obj_wizard.sale_tax_rate diff --git a/addons/account/static/src/js/account_move_line_quickadd.js b/addons/account/static/src/js/account_move_line_quickadd.js index 0b904e19da6..997b2b03bb6 100644 --- a/addons/account/static/src/js/account_move_line_quickadd.js +++ b/addons/account/static/src/js/account_move_line_quickadd.js @@ -84,7 +84,7 @@ openerp.account.quickadd = function (instance) { }, search_by_journal_period: function() { var self = this; - var domain = ['|',['debit', '!=', 0], ['credit', '!=', 0]]; + var domain = []; if (self.current_journal !== null) domain.push(["journal_id", "=", self.current_journal]); if (self.current_period !== null) domain.push(["period_id", "=", self.current_period]); self.last_context["journal_id"] = self.current_journal === null ? false : self.current_journal; diff --git a/addons/account_voucher/account_voucher_view.xml b/addons/account_voucher/account_voucher_view.xml index 4674d62b6a0..41d3c6fc1f6 100644 --- a/addons/account_voucher/account_voucher_view.xml +++ b/addons/account_voucher/account_voucher_view.xml @@ -130,7 +130,7 @@ - + diff --git a/addons/account_voucher/voucher_payment_receipt_view.xml b/addons/account_voucher/voucher_payment_receipt_view.xml index 5d259772363..1169d5ef7c3 100644 --- a/addons/account_voucher/voucher_payment_receipt_view.xml +++ b/addons/account_voucher/voucher_payment_receipt_view.xml @@ -12,7 +12,7 @@ - + @@ -35,7 +35,7 @@ - + diff --git a/addons/account_voucher/voucher_sales_purchase_view.xml b/addons/account_voucher/voucher_sales_purchase_view.xml index dc732129803..e35061e1836 100644 --- a/addons/account_voucher/voucher_sales_purchase_view.xml +++ b/addons/account_voucher/voucher_sales_purchase_view.xml @@ -11,7 +11,7 @@ - + @@ -33,7 +33,7 @@ - + diff --git a/addons/auth_signup/auth_signup_data.xml b/addons/auth_signup/auth_signup_data.xml index 31e3b61a9f6..1b4e3e05502 100644 --- a/addons/auth_signup/auth_signup_data.xml +++ b/addons/auth_signup/auth_signup_data.xml @@ -22,7 +22,7 @@ Reset Password - ]]> + ]]> ${object.email} Password reset OpenERP Enterprise Connection - ]]> + ]]> ${object.email} diff --git a/addons/hr_timesheet_invoice/test/test_hr_timesheet_invoice.yml b/addons/hr_timesheet_invoice/test/test_hr_timesheet_invoice.yml index 05326bb19c1..49243e501f2 100644 --- a/addons/hr_timesheet_invoice/test/test_hr_timesheet_invoice.yml +++ b/addons/hr_timesheet_invoice/test/test_hr_timesheet_invoice.yml @@ -79,7 +79,15 @@ I click on "Create Invoice" button of "Invoice analytic Line" wizard to create invoice. - !python {model: hr.timesheet.invoice.create}: | - self.do_create(cr, uid, [ref("hr_timesheet_invoice_create_0")], {"active_ids": [ref("hr_timesheet_invoice.account_analytic_line_developyamlforhrmodule0")]}) + action_result = self.do_create(cr, uid, [ref("hr_timesheet_invoice_create_0")], { + "active_ids": [ref("hr_timesheet_invoice.account_analytic_line_developyamlforhrmodule0")] + }) + invoice_pool = self.pool.get('account.invoice') + invoice_domain = action_result['domain'] + invoice_ids = invoice_pool.search(cr, uid, invoice_domain) + invoice_pool.write(cr, uid, invoice_ids, {'origin': 'test-hrtsic0_id_'+str( ref("hr_timesheet_invoice_create_0")) \ + + '_aaldyfhrm0_id_'+str( ref("hr_timesheet_invoice.account_analytic_line_developyamlforhrmodule0") ) }) + - I check that Invoice is created for this timesheet. - @@ -90,7 +98,9 @@ partner = aline.account_id.partner_id.id invoice_obj = self.pool.get('account.invoice') - invoice_ids = invoice_obj.search(cr, uid, [('partner_id', '=', partner)]) + invoice_ids = invoice_obj.search(cr, uid, [('partner_id', '=', partner), + ('origin', '=', 'test-hrtsic0_id_'+str( ref("hr_timesheet_invoice_create_0")) + '_aaldyfhrm0_id_'+str( ref("hr_timesheet_invoice.account_analytic_line_developyamlforhrmodule0") )) + ]) invoice_id = invoice_obj.browse(cr, uid, invoice_ids)[0] for invoice in invoice_id.invoice_line: @@ -102,4 +112,4 @@ assert aline.invoice_id, "Invoice created, but analytic line wasn't updated." assert aline.invoice_id == invoice_id, "Invoice doesn't match the one at analytic line" assert invoice_id.amount_untaxed == 187.5, "Invoice amount mismatch: %s" % invoice_id.amount_untaxed - assert invoice_id.amount_tax == 50, "Invoice tax mismatch: %s" % invoice_id.amount_tax \ No newline at end of file + assert invoice_id.amount_tax == 50, "Invoice tax mismatch: %s" % invoice_id.amount_tax diff --git a/addons/hr_timesheet_invoice/test/test_hr_timesheet_invoice_no_prod_tax.yml b/addons/hr_timesheet_invoice/test/test_hr_timesheet_invoice_no_prod_tax.yml index 88675f3042f..c3a5fae866c 100644 --- a/addons/hr_timesheet_invoice/test/test_hr_timesheet_invoice_no_prod_tax.yml +++ b/addons/hr_timesheet_invoice/test/test_hr_timesheet_invoice_no_prod_tax.yml @@ -78,7 +78,14 @@ I click on "Create Invoice" button of "Invoice analytic Line" wizard to create invoice. - !python {model: hr.timesheet.invoice.create}: | - self.do_create(cr, uid, [ref("hr_timesheet_invoice_create_0")], {"active_ids": [ref("hr_timesheet_invoice.account_analytic_line_developyamlforhrmodule1")]}) + action_result = self.do_create(cr, uid, [ref("hr_timesheet_invoice_create_0")], { + "active_ids": [ref("hr_timesheet_invoice.account_analytic_line_developyamlforhrmodule1")] + }) + invoice_pool = self.pool.get('account.invoice') + invoice_domain = action_result['domain'] + invoice_ids = invoice_pool.search(cr, uid, invoice_domain) + invoice_pool.write(cr, uid, invoice_ids, {'origin': 'test-hrtsic0_id_'+str( ref("hr_timesheet_invoice_create_0"))\ + + '_aaldyfhrm1_id_'+str( ref("hr_timesheet_invoice.account_analytic_line_developyamlforhrmodule1") ) }) - I check that Invoice is created for this timesheet. - @@ -89,7 +96,10 @@ partner = aline.account_id.partner_id.id invoice_obj = self.pool.get('account.invoice') - invoice_ids = invoice_obj.search(cr, uid, [('partner_id', '=', partner)]) + invoice_ids = invoice_obj.search(cr, uid, [('partner_id', '=', partner), + ('origin', '=', 'test-hrtsic0_id_'+str( ref("hr_timesheet_invoice_create_0")) + '_aaldyfhrm1_id_'+str( ref("hr_timesheet_invoice.account_analytic_line_developyamlforhrmodule1") )) + ]) + invoice_id = invoice_obj.browse(cr, uid, invoice_ids)[0] for invoice in invoice_id.invoice_line: @@ -101,4 +111,4 @@ assert aline.invoice_id, "Invoice created, but analytic line wasn't updated." assert aline.invoice_id == invoice_id, "Invoice doesn't match the one at analytic line" assert invoice_id.amount_untaxed == 187.5, "Invoice amount mismatch: %s" % invoice_id.amount_untaxed - assert invoice_id.amount_tax == 40, "Invoice tax mismatch: %s" % invoice_id.amount_tax \ No newline at end of file + assert invoice_id.amount_tax == 40, "Invoice tax mismatch: %s" % invoice_id.amount_tax diff --git a/addons/l10n_br/data/account_tax_template.xml b/addons/l10n_br/data/account_tax_template.xml index 1e6efd5c616..c3ecf449838 100644 --- a/addons/l10n_br/data/account_tax_template.xml +++ b/addons/l10n_br/data/account_tax_template.xml @@ -242,6 +242,22 @@ + + IPI 24% + IPI Saída 24% + 0.24 + sale + + + + + + + + + + + IPI 25% IPI Saída 25% @@ -386,6 +402,22 @@ + + IPI 300% + IPI Saída 300% + 3.00 + sale + + + + + + + + + + + IPI 330% IPI Saída 330% @@ -642,6 +674,22 @@ + + IPI 24% + IPI Entrada 24% + 0.24 + purchase + + + + + + + + + + + IPI 25% IPI Entrada 25% @@ -786,6 +834,22 @@ + + IPI 300% + IPI Entrada 300% + 3.00 + purchase + + + + + + + + + + + IPI 330% IPI Entrada 330% diff --git a/addons/l10n_it/data/account.tax.code.template.csv b/addons/l10n_it/data/account.tax.code.template.csv index e5435945556..18c00b12777 100644 --- a/addons/l10n_it/data/account.tax.code.template.csv +++ b/addons/l10n_it/data/account.tax.code.template.csv @@ -75,3 +75,21 @@ IVC21Idet40,template_impcode_pagata_21det40,IVA a credito 21% detraibile 40% (im IVC21det50,template_ivacode_pagata_21det50,IVA a credito 21% detraibile 50%,template_ivacode_pagata IVC21Ndet50,template_ivacode_pagata_21det50ind,IVA a credito 21% detraibile 50% (indetraibile),template_ivacode_pagata_ind IVC21Idet50,template_impcode_pagata_21det50,IVA a credito 21% detraibile 50% (imponibile),template_impcode_pagata +IVC22,template_ivacode_pagata_22,IVA a credito 22%,template_ivacode_pagata +IVC22I,template_impcode_pagata_22,IVA a credito 22% (imponibile),template_impcode_pagata +IVD22,template_ivacode_riscossa_22,IVA a debito 22%,template_ivacode_riscossa +IVD22I,template_impcode_riscossa_22,IVA a debito 22% (imponibile),template_impcode_riscossa +IVC22ind,template_ivacode_pagata_22ind,IVA a credito 22% indetraibile,template_ivacode_pagata_ind +IVC22Iind,template_impcode_pagata_22ind,IVA a credito 22% indetraibile (imponibile),template_impcode_pagata +IVC22det10,template_ivacode_pagata_22det10,IVA a credito 22% detraibile 10%,template_ivacode_pagata +IVC22Ndet10,template_ivacode_pagata_22det10ind,IVA a credito 22% detraibile 10% (indetraibile),template_ivacode_pagata_ind +IVC22Idet10,template_impcode_pagata_22det10,IVA a credito 22% detraibile 10% (imponibile),template_impcode_pagata +IVC22det15,template_ivacode_pagata_22det15,IVA a credito 22% detraibile 15%,template_ivacode_pagata +IVC22Ndet15,template_ivacode_pagata_22det15ind,IVA a credito 22% detraibile 15% (indetraibile),template_ivacode_pagata_ind +IVC22Idet15,template_impcode_pagata_22det15,IVA a credito 22% detraibile 15% (imponibile),template_impcode_pagata +IVC22det40,template_ivacode_pagata_22det40,IVA a credito 22% detraibile 40%,template_ivacode_pagata +IVC22Ndet40,template_ivacode_pagata_22det40ind,IVA a credito 22% detraibile 40% (indetraibile),template_ivacode_pagata_ind +IVC22Idet40,template_impcode_pagata_22det40,IVA a credito 22% detraibile 40% (imponibile),template_impcode_pagata +IVC22det50,template_ivacode_pagata_22det50,IVA a credito 22% detraibile 50%,template_ivacode_pagata +IVC22Ndet50,template_ivacode_pagata_22det50ind,IVA a credito 22% detraibile 50% (indetraibile),template_ivacode_pagata_ind +IVC22Idet50,template_impcode_pagata_22det50,IVA a credito 22% detraibile 50% (imponibile),template_impcode_pagata diff --git a/addons/l10n_it/data/account.tax.template.csv b/addons/l10n_it/data/account.tax.template.csv index 5654b32e5e9..67daee0eeef 100644 --- a/addons/l10n_it/data/account.tax.template.csv +++ b/addons/l10n_it/data/account.tax.template.csv @@ -1,6 +1,8 @@ id,description,chart_template_id:id,name,sequence,amount,parent_id:id,child_depend,type,account_collected_id:id,account_paid_id:id,type_tax_use,base_code_id:id,tax_code_id:id,ref_base_code_id:id,ref_tax_code_id:id,ref_base_sign,ref_tax_sign,price_include,base_sign,tax_sign -21v,21v,l10n_it_chart_template_generic,Iva al 21% (debito),1,0.21,,False,percent,2601,2601,sale,template_impcode_riscossa_21,template_ivacode_riscossa_21,template_impcode_riscossa_21,template_ivacode_riscossa_21,-1,-1,False,1,1 -21a,21a,l10n_it_chart_template_generic,Iva al 21% (credito),2,0.21,,False,percent,1601,1601,purchase,template_impcode_pagata_21,template_ivacode_pagata_21,template_impcode_pagata_21,template_ivacode_pagata_21,1,1,False,-1,-1 +22v,22v,l10n_it_chart_template_generic,Iva al 22% (debito),1,0.22,,False,percent,2601,2601,sale,template_impcode_riscossa_22,template_ivacode_riscossa_22,template_impcode_riscossa_22,template_ivacode_riscossa_22,-1,-1,False,1,1 +22a,22a,l10n_it_chart_template_generic,Iva al 22% (credito),2,0.22,,False,percent,1601,1601,purchase,template_impcode_pagata_22,template_ivacode_pagata_22,template_impcode_pagata_22,template_ivacode_pagata_22,1,1,False,-1,-1 +21v,21v,l10n_it_chart_template_generic,Iva al 21% (debito),3,0.21,,False,percent,2601,2601,sale,template_impcode_riscossa_21,template_ivacode_riscossa_21,template_impcode_riscossa_21,template_ivacode_riscossa_21,-1,-1,False,1,1 +21a,21a,l10n_it_chart_template_generic,Iva al 21% (credito),4,0.21,,False,percent,1601,1601,purchase,template_impcode_pagata_21,template_ivacode_pagata_21,template_impcode_pagata_21,template_ivacode_pagata_21,1,1,False,-1,-1 20v,20v,l10n_it_chart_template_generic,Iva al 20% (debito),3,0.2,,False,percent,2601,2601,sale,template_impcode_riscossa_20,template_ivacode_riscossa_20,template_impcode_riscossa_20,template_ivacode_riscossa_20,-1,-1,False,1,1 20a,20a,l10n_it_chart_template_generic,Iva al 20% (credito),4,0.2,,False,percent,1601,1601,purchase,template_impcode_pagata_20,template_ivacode_pagata_20,template_impcode_pagata_20,template_ivacode_pagata_20,1,1,False,-1,-1 10v,10v,l10n_it_chart_template_generic,Iva al 10% (debito),5,0.1,,False,percent,2601,2601,sale,template_impcode_riscossa_10,template_ivacode_riscossa_10,template_impcode_riscossa_10,template_ivacode_riscossa_10,-1,-1,False,1,1 @@ -25,8 +27,8 @@ id,description,chart_template_id:id,name,sequence,amount,parent_id:id,child_depe 20I5,20I5,l10n_it_chart_template_generic,IVA al 20% detraibile al 50%,14,0.2,,True,percent,,,purchase,template_impcode_pagata_20det50,,template_impcode_pagata_20det50,,1,1,False,-1,-1 20I5b,20I5b,l10n_it_chart_template_generic,IVA al 20% detraibile al 50% (D),200,0,20I5,False,balance,1601,1601,purchase,,template_ivacode_pagata_20det50,,template_ivacode_pagata_20det50,1,1,False,-1,-1 20I5a,20I5a,l10n_it_chart_template_generic,IVA al 20% detraibile al 50% (I),100,0.5,20I5,False,percent,,,purchase,,template_ivacode_pagata_20det50ind,,template_ivacode_pagata_20det50ind,1,1,False,-1,-1 -22v,22v,l10n_it_chart_template_generic,Iva 2% (debito),15,0.02,,False,percent,2601,2601,sale,template_impcode_riscossa_2,template_ivacode_riscossa_2,template_impcode_riscossa_2,template_ivacode_riscossa_2,-1,-1,False,1,1 -22a,22a,l10n_it_chart_template_generic,Iva 2% (credito),16,0.02,,False,percent,1601,1601,purchase,template_impcode_pagata_2,template_ivacode_pagata_2,template_impcode_pagata_2,template_ivacode_pagata_2,1,1,False,-1,-1 +2v,2v,l10n_it_chart_template_generic,Iva 2% (debito),15,0.02,,False,percent,2601,2601,sale,template_impcode_riscossa_2,template_ivacode_riscossa_2,template_impcode_riscossa_2,template_ivacode_riscossa_2,-1,-1,False,1,1 +2a,2a,l10n_it_chart_template_generic,Iva 2% (credito),16,0.02,,False,percent,1601,1601,purchase,template_impcode_pagata_2,template_ivacode_pagata_2,template_impcode_pagata_2,template_ivacode_pagata_2,1,1,False,-1,-1 4v,4v,l10n_it_chart_template_generic,Iva 4% (debito),17,0.04,,False,percent,2601,2601,sale,template_impcode_riscossa_4,template_ivacode_riscossa_4,template_impcode_riscossa_4,template_ivacode_riscossa_4,-1,-1,False,1,1 4a,4a,l10n_it_chart_template_generic,Iva 4% (credito),18,0.04,,False,percent,1601,1601,purchase,template_impcode_pagata_4,template_ivacode_pagata_4,template_impcode_pagata_4,template_ivacode_pagata_4,1,1,False,-1,-1 4AO,4AO,l10n_it_chart_template_generic,Iva al 4% indetraibile,19,0.04,,True,percent,,,purchase,template_impcode_pagata_4ind,,template_impcode_pagata_4ind,,1,1,False,-1,-1 @@ -42,11 +44,12 @@ id,description,chart_template_id:id,name,sequence,amount,parent_id:id,child_depe 00a,00a,l10n_it_chart_template_generic,Fuori Campo IVA (credito),23,0,,False,percent,1601,1601,purchase,template_impcode_pagata_0,template_ivacode_pagata_0,template_impcode_pagata_0,template_ivacode_pagata_0,1,1,False,-1,-1 00art15v,00art15v,l10n_it_chart_template_generic,Imponibile Escluso Art.15 (debito),22,0,,False,percent,2601,2601,sale,template_impcode_riscossa_art15,template_ivacode_riscossa_art15,template_impcode_riscossa_art15,template_ivacode_riscossa_art15,-1,-1,False,1,1 00art15a,00art15a,l10n_it_chart_template_generic,Imponibile Escluso Art.15 (credito),23,0,,False,percent,1601,1601,purchase,template_impcode_pagata_art15,template_ivacode_pagata_art15,template_impcode_pagata_art15,template_ivacode_pagata_art15,1,1,False,-1,-1 -21v INC,21v INC,l10n_it_chart_template_generic,Iva al 21% (debito) INC,24,0.21,,False,percent,l10n_it.2601,l10n_it.2601,sale,l10n_it.template_impcode_riscossa_21,l10n_it.template_ivacode_riscossa_21,l10n_it.template_impcode_riscossa_21,l10n_it.template_ivacode_riscossa_21,-1,-1,True,1,1 +22v INC,22v INC,l10n_it_chart_template_generic,Iva al 22% (debito) INC,24,0.22,,False,percent,l10n_it.2601,l10n_it.2601,sale,l10n_it.template_impcode_riscossa_22,l10n_it.template_ivacode_riscossa_22,l10n_it.template_impcode_riscossa_22,l10n_it.template_ivacode_riscossa_22,-1,-1,True,1,1 +21v INC,21v INC,l10n_it_chart_template_generic,Iva al 21% (debito) INC,25,0.21,,False,percent,l10n_it.2601,l10n_it.2601,sale,l10n_it.template_impcode_riscossa_21,l10n_it.template_ivacode_riscossa_21,l10n_it.template_impcode_riscossa_21,l10n_it.template_ivacode_riscossa_21,-1,-1,True,1,1 20v INC,20v INC,l10n_it_chart_template_generic,Iva al 20% (debito) INC,25,0.2,,False,percent,l10n_it.2601,l10n_it.2601,sale,l10n_it.template_impcode_riscossa_20,l10n_it.template_ivacode_riscossa_20,l10n_it.template_impcode_riscossa_20,l10n_it.template_ivacode_riscossa_20,-1,-1,True,1,1 10v INC,10v INC,l10n_it_chart_template_generic,Iva al 10% (debito) INC,26,0.1,,False,percent,l10n_it.2601,l10n_it.2601,sale,l10n_it.template_impcode_riscossa_10,l10n_it.template_ivacode_riscossa_10,l10n_it.template_impcode_riscossa_10,l10n_it.template_ivacode_riscossa_10,-1,-1,True,1,1 12v INC,12v INC,l10n_it_chart_template_generic,Iva 12% (debito) INC,27,0.12,,False,percent,l10n_it.2601,l10n_it.2601,sale,l10n_it.template_impcode_riscossa_12,l10n_it.template_ivacode_riscossa_12,l10n_it.template_impcode_riscossa_12,l10n_it.template_ivacode_riscossa_12,-1,-1,True,1,1 -22v INC,22v INC,l10n_it_chart_template_generic,Iva 2% (debito) INC,28,0.02,,False,percent,l10n_it.2601,l10n_it.2601,sale,l10n_it.template_impcode_riscossa_2,l10n_it.template_ivacode_riscossa_2,l10n_it.template_impcode_riscossa_2,l10n_it.template_ivacode_riscossa_2,-1,-1,True,1,1 +2v INC,2v INC,l10n_it_chart_template_generic,Iva 2% (debito) INC,28,0.02,,False,percent,l10n_it.2601,l10n_it.2601,sale,l10n_it.template_impcode_riscossa_2,l10n_it.template_ivacode_riscossa_2,l10n_it.template_impcode_riscossa_2,l10n_it.template_ivacode_riscossa_2,-1,-1,True,1,1 4v INC,4v INC,l10n_it_chart_template_generic,Iva 4% (debito) INC,29,0.04,,False,percent,l10n_it.2601,l10n_it.2601,sale,l10n_it.template_impcode_riscossa_4,l10n_it.template_ivacode_riscossa_4,l10n_it.template_impcode_riscossa_4,l10n_it.template_ivacode_riscossa_4,-1,-1,True,1,1 00v INC,00v INC,l10n_it_chart_template_generic,Fuori Campo IVA (debito) INC,30,0,,False,percent,l10n_it.2601,l10n_it.2601,sale,l10n_it.template_impcode_riscossa_0,l10n_it.template_ivacode_riscossa_0,l10n_it.template_impcode_riscossa_0,l10n_it.template_ivacode_riscossa_0,-1,-1,True,1,1 2110,2110,l10n_it_chart_template_generic,Iva al 21% detraibile 10%,31,0.21,,True,percent,,,purchase,template_impcode_pagata_21det10,,template_impcode_pagata_21det10,,1,1,False,-1,-1 @@ -64,3 +67,18 @@ id,description,chart_template_id:id,name,sequence,amount,parent_id:id,child_depe 21I5,21I5,l10n_it_chart_template_generic,IVA al 21% detraibile al 50%,35,0.21,,True,percent,,,purchase,template_impcode_pagata_21det50,,template_impcode_pagata_21det50,,1,1,False,-1,-1 21I5b,21I5b,l10n_it_chart_template_generic,IVA al 21% detraibile al 50% (D),200,0,21I5,False,balance,1601,1601,purchase,,template_ivacode_pagata_21det50,,template_ivacode_pagata_21det50,1,1,False,-1,-1 21I5a,21I5a,l10n_it_chart_template_generic,IVA al 21% detraibile al 50% (I),100,0.5,21I5,False,percent,,,purchase,,template_ivacode_pagata_21det50ind,,template_ivacode_pagata_21det50ind,1,1,False,-1,-1 +2210,2210,l10n_it_chart_template_generic,Iva al 22% detraibile 10%,31,0.22,,True,percent,,,purchase,template_impcode_pagata_22det10,,template_impcode_pagata_22det10,,1,1,False,-1,-1 +2210b,2210b,l10n_it_chart_template_generic,Iva al 22% detraibile 10% (D),200,0,2210,False,balance,1601,1601,purchase,,template_ivacode_pagata_22det10,,template_ivacode_pagata_22det10,1,1,False,-1,-1 +2210a,2210a,l10n_it_chart_template_generic,Iva al 22% detraibile 10% (I),100,0.9,2210,False,percent,,,purchase,,template_ivacode_pagata_22det10ind,,template_ivacode_pagata_22det10ind,1,1,False,-1,-1 +2215,2215,l10n_it_chart_template_generic,Iva al 22% detraibile 15%,32,0.22,,True,percent,,,purchase,template_impcode_pagata_22det15,,template_impcode_pagata_22det15,,1,1,False,-1,-1 +2215b,2215b,l10n_it_chart_template_generic,Iva al 22% detraibile 15% (D),200,0,2215,False,balance,1601,1601,purchase,,template_ivacode_pagata_22det15,,template_ivacode_pagata_22det15,1,1,False,-1,-1 +2215a,2215a,l10n_it_chart_template_generic,Iva al 22% detraibile 15% (I),100,0.85,2215,False,percent,,,purchase,,template_ivacode_pagata_22det15ind,,template_ivacode_pagata_22det15ind,1,1,False,-1,-1 +2240,2240,l10n_it_chart_template_generic,Iva al 22% detraibile 40%,33,0.22,,True,percent,,,purchase,template_impcode_pagata_22det40,,template_impcode_pagata_22det40,,1,1,False,-1,-1 +2240b,2240b,l10n_it_chart_template_generic,Iva al 22% detraibile 40% (D),200,0,2240,False,balance,1601,1601,purchase,,template_ivacode_pagata_22det40,,template_ivacode_pagata_22det40,1,1,False,-1,-1 +2240a,2240a,l10n_it_chart_template_generic,Iva al 22% detraibile 40% (I),100,0.6,2240,False,percent,,,purchase,,template_ivacode_pagata_22det40ind,,template_ivacode_pagata_22det40ind,1,1,False,-1,-1 +22AO,22AO,l10n_it_chart_template_generic,Iva al 22% indetraibile,34,0.22,,True,percent,,,purchase,template_impcode_pagata_22ind,,template_impcode_pagata_22ind,,1,1,False,-1,-1 +22AOb,22AOb,l10n_it_chart_template_generic,Iva al 22% indetraibile (D),200,0,22AO,False,balance,1601,1601,purchase,,template_ivacode_pagata_22ind,,template_ivacode_pagata_22ind,1,1,False,-1,-1 +22AOa,22AOa,l10n_it_chart_template_generic,Iva al 22% indetraibile (I),100,1,22AO,False,percent,,,purchase,,template_ivacode_pagata_22ind,,template_ivacode_pagata_22ind,1,1,False,-1,-1 +22I5,22I5,l10n_it_chart_template_generic,IVA al 22% detraibile al 50%,35,0.22,,True,percent,,,purchase,template_impcode_pagata_22det50,,template_impcode_pagata_22det50,,1,1,False,-1,-1 +22I5b,22I5b,l10n_it_chart_template_generic,IVA al 22% detraibile al 50% (D),200,0,22I5,False,balance,1601,1601,purchase,,template_ivacode_pagata_22det50,,template_ivacode_pagata_22det50,1,1,False,-1,-1 +22I5a,22I5a,l10n_it_chart_template_generic,IVA al 22% detraibile al 50% (I),100,0.5,22I5,False,percent,,,purchase,,template_ivacode_pagata_22det50ind,,template_ivacode_pagata_22det50ind,1,1,False,-1,-1 diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 0f3158dfc20..263c01ec6d4 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -952,9 +952,9 @@ class mail_thread(osv.AbstractModel): partner_id, partner_name or partner_name, reason """ if email and not partner: # get partner info from email - partner_info = self.message_get_partner_info_from_emails(cr, uid, [email], context=context, res_id=obj.id)[0] - if partner_info.get('partner_id'): - partner = self.pool.get('res.partner').browse(cr, SUPERUSER_ID, [partner_info.get('partner_id')], context=context)[0] + partner_info = self.message_get_partner_info_from_emails(cr, uid, [email], context=context, res_id=obj.id) + if partner_info and partner_info[0].get('partner_id'): + partner = self.pool.get('res.partner').browse(cr, SUPERUSER_ID, [partner_info[0]['partner_id']], context=context)[0] if email and email in [val[1] for val in result[obj.id]]: # already existing email -> skip return result if partner and partner in obj.message_follower_ids: # recipient already in the followers -> skip diff --git a/addons/mail/update.py b/addons/mail/update.py index 94416aeb356..bcf9bb8c7c9 100644 --- a/addons/mail/update.py +++ b/addons/mail/update.py @@ -6,8 +6,8 @@ import urllib import urllib2 import openerp -from openerp import release -from openerp.osv import fields, osv +from openerp import release, SUPERUSER_ID +from openerp.osv import osv from openerp.tools.translate import _ from openerp.tools.safe_eval import safe_eval from openerp.tools.config import config @@ -86,25 +86,26 @@ class publisher_warranty_contract(osv.osv): try: try: result = get_sys_logs(self, cr, uid) - except Exception, ex: + except Exception: if cron_mode: # we don't want to see any stack trace in cron return False _logger.debug("Exception while sending a get logs messages", exc_info=1) raise osv.except_osv(_("Error"), _("Error during communication with the publisher warranty server.")) - limit_date = (datetime.datetime.now() - _PREVIOUS_LOG_CHECK).strftime(misc.DEFAULT_SERVER_DATETIME_FORMAT) # old behavior based on res.log; now on mail.message, that is not necessarily installed - proxy = self.pool.get('mail.message') - - model, res_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'mail', 'group_all_employees') - + IMD = self.pool['ir.model.data'] + user = self.pool['res.users'].browse(cr, SUPERUSER_ID, SUPERUSER_ID) + try: + poster = IMD.get_object(cr, SUPERUSER_ID, 'mail', 'group_all_employees') + except ValueError: + # Cannot found group, post the message on the wall of the admin + poster = user + if not poster.exists(): + return True for message in result["messages"]: - values = { - 'body' : message, - 'model' : 'mail.group', - 'res_id' : res_id, - 'user_id' : False, - } - proxy.create(cr, uid, values, context=context) + try: + poster.message_post(body=message, subtype='mt_comment', partner_ids=[user.partner_id.id]) + except Exception: + _logger.warning('Cannot send ping message', exc_info=True) except Exception: if cron_mode: return False # we don't want to see any stack trace in cron diff --git a/addons/note/note.py b/addons/note/note.py index eb9a6397d18..95fe8f97cdf 100644 --- a/addons/note/note.py +++ b/addons/note/note.py @@ -19,6 +19,7 @@ # ############################################################################## +from openerp import SUPERUSER_ID from openerp.osv import osv, fields from openerp.tools import html2plaintext @@ -188,18 +189,15 @@ class res_users(osv.Model): _inherit = ['res.users'] def create(self, cr, uid, data, context=None): user_id = super(res_users, self).create(cr, uid, data, context=context) - user = self.browse(cr, uid, uid, context=context) - note_obj = self.pool.get('note.stage') - data_obj = self.pool.get('ir.model.data') - model_id = data_obj.get_object_reference(cr, uid, 'base', 'group_user') #Employee Group - group_id = model_id and model_id[1] or False - if group_id in [x.id for x in user.groups_id]: - for note_xml_id in ['note_stage_00','note_stage_01','note_stage_02','note_stage_03','note_stage_04']: + note_obj = self.pool['note.stage'] + data_obj = self.pool['ir.model.data'] + is_employee = self.has_group(cr, user_id, 'base.group_user') + if is_employee: + for n in range(5): + xmlid = 'note_stage_%02d' % (n,) try: - data_id = data_obj._get_id(cr, uid, 'note', note_xml_id) + _model, stage_id = data_obj.get_object_reference(cr, SUPERUSER_ID, 'note', xmlid) except ValueError: continue - stage_id = data_obj.browse(cr, uid, data_id, context=context).res_id - note_obj.copy(cr, uid, stage_id, default = { - 'user_id': user_id}, context=context) + note_obj.copy(cr, SUPERUSER_ID, stage_id, default={'user_id': user_id}, context=context) return user_id diff --git a/addons/note/tests/__init__.py b/addons/note/tests/__init__.py new file mode 100644 index 00000000000..4a9f12c80b2 --- /dev/null +++ b/addons/note/tests/__init__.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Business Applications +# Copyright (c) 2013-TODAY OpenERP S.A. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## +from . import test_note + +checks = [ + test_note, +] + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/note/tests/test_note.py b/addons/note/tests/test_note.py new file mode 100644 index 00000000000..4300009981e --- /dev/null +++ b/addons/note/tests/test_note.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Business Applications +# Copyright (c) 2013-TODAY OpenERP S.A. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp.tests import common + +class TestNote(common.TransactionCase): + + def test_bug_lp_1156215(self): + """ensure any users can create new users""" + cr, uid = self.cr, self.uid + IMD = self.registry('ir.model.data') + Users = self.registry('res.users') + + _, demo_user = IMD.get_object_reference(cr, uid, 'base', 'user_demo') + _, group_id = IMD.get_object_reference(cr, uid, 'base', 'group_erp_manager') + + Users.write(cr, uid, [demo_user], { + 'groups_id': [(4, group_id)], + }) + + # must not fail + Users.create(cr, demo_user, { + 'name': 'test bug lp:1156215', + 'login': 'lp_1156215', + }) diff --git a/addons/procurement/procurement.py b/addons/procurement/procurement.py index 93b9417bded..f3c49c03900 100644 --- a/addons/procurement/procurement.py +++ b/addons/procurement/procurement.py @@ -371,7 +371,6 @@ class procurement_order(osv.osv): ctx_wkf = dict(context or {}) ctx_wkf['workflow.trg_write.%s' % self._name] = False self.write(cr, uid, [procurement.id], {'message': message},context=ctx_wkf) - self.message_post(cr, uid, [procurement.id], body=message, context=context) return ok def step_workflow(self, cr, uid, ids, context=None): diff --git a/addons/product/product_view.xml b/addons/product/product_view.xml index 2eefb3a2384..3fa9891ca9a 100644 --- a/addons/product/product_view.xml +++ b/addons/product/product_view.xml @@ -15,7 +15,7 @@ - + diff --git a/addons/purchase/purchase.py b/addons/purchase/purchase.py index 402292759bc..73f7edcde3b 100644 --- a/addons/purchase/purchase.py +++ b/addons/purchase/purchase.py @@ -1038,28 +1038,25 @@ class procurement_order(osv.osv): partner_obj = self.pool.get('res.partner') user = self.pool.get('res.users').browse(cr, uid, uid, context=context) for procurement in self.browse(cr, uid, ids, context=context): - if not procurement.product_id.seller_ids: - message = _('No supplier defined for this product !') - self.message_post(cr, uid, [procurement.id], body=message) - cr.execute('update procurement_order set message=%s where id=%s', (message, procurement.id)) - return False + message = '' partner = procurement.product_id.seller_id #Taken Main Supplier of Product of Procurement. - if not partner: + if not procurement.product_id.seller_ids: + message = _('No supplier defined for this product !') + elif not partner: message = _('No default supplier defined for this product') - self.message_post(cr, uid, [procurement.id], body=message) - cr.execute('update procurement_order set message=%s where id=%s', (message, procurement.id)) + elif not partner_obj.address_get(cr, uid, [partner.id], ['delivery'])['delivery']: + message = _('No address defined for the supplier') + + if message: + if procurement.message != message: + cr.execute('update procurement_order set message=%s where id=%s', (message, procurement.id)) return False + if user.company_id and user.company_id.partner_id: if partner.id == user.company_id.partner_id.id: raise osv.except_osv(_('Configuration Error!'), _('The product "%s" has been defined with your company as reseller which seems to be a configuration error!' % procurement.product_id.name)) - address_id = partner_obj.address_get(cr, uid, [partner.id], ['delivery'])['delivery'] - if not address_id: - message = _('No address defined for the supplier') - self.message_post(cr, uid, [procurement.id], body=message) - cr.execute('update procurement_order set message=%s where id=%s', (message, procurement.id)) - return False return True diff --git a/addons/sale/security/sale_security.xml b/addons/sale/security/sale_security.xml index c025cd6c6cf..49bd0e8716b 100644 --- a/addons/sale/security/sale_security.xml +++ b/addons/sale/security/sale_security.xml @@ -36,7 +36,6 @@ Properties on lines - diff --git a/addons/stock/product_view.xml b/addons/stock/product_view.xml index dc80c0f950a..b5af071a86d 100644 --- a/addons/stock/product_view.xml +++ b/addons/stock/product_view.xml @@ -8,8 +8,8 @@ - - + + diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 1e032626194..ec33456e501 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -73,6 +73,8 @@ class stock_location(osv.osv): _parent_order = 'posz,name' _order = 'parent_left' + # TODO: implement name_search() in a way that matches the results of name_get! + def name_get(self, cr, uid, ids, context=None): # always return the full hierarchical name res = self._complete_name(cr, uid, ids, 'complete_name', None, context=context) diff --git a/openerp/addons/base/ir/ir_fields.py b/openerp/addons/base/ir/ir_fields.py index 302b11eb526..09622dadd17 100644 --- a/openerp/addons/base/ir/ir_fields.py +++ b/openerp/addons/base/ir/ir_fields.py @@ -184,7 +184,7 @@ class ir_fields_converter(orm.Model): def _str_id(self, cr, uid, model, column, value, context=None): return value, [] - _str_to_char = _str_to_text = _str_to_binary = _str_id + _str_to_reference = _str_to_char = _str_to_text = _str_to_binary = _str_id def _str_to_date(self, cr, uid, model, column, value, context=None): try: diff --git a/openerp/addons/base/ir/ir_mail_server.py b/openerp/addons/base/ir/ir_mail_server.py index da04308e68b..9e2123f859b 100644 --- a/openerp/addons/base/ir/ir_mail_server.py +++ b/openerp/addons/base/ir/ir_mail_server.py @@ -404,9 +404,10 @@ class ir_mail_server(osv.osv): # The email's "Envelope From" (Return-Path), and all recipient addresses must only contain ASCII characters. from_rfc2822 = extract_rfc2822_addresses(smtp_from) - assert len(set(from_rfc2822)) == 1, ("Malformed 'Return-Path' or 'From' address: %r - " - "It should contain one plain ASCII email") % smtp_from - smtp_from = from_rfc2822[0] + assert from_rfc2822, ("Malformed 'Return-Path' or 'From' address: %r - " + "It should contain one valid plain ASCII email") % smtp_from + # use last extracted email, to support rarities like 'Support@MyComp ' + smtp_from = from_rfc2822[-1] email_to = message['To'] email_cc = message['Cc'] email_bcc = message['Bcc'] diff --git a/openerp/addons/base/ir/ir_model.py b/openerp/addons/base/ir/ir_model.py index 437095e5455..2d7bec331ff 100644 --- a/openerp/addons/base/ir/ir_model.py +++ b/openerp/addons/base/ir/ir_model.py @@ -198,6 +198,7 @@ class ir_model(osv.osv): select=vals.get('select_level', '0'), update_custom_fields=True) self.pool[vals['model']]._auto_init(cr, ctx) + self.pool[vals['model']]._auto_end(cr, ctx) # actually create FKs! openerp.modules.registry.RegistryManager.signal_registry_change(cr.dbname) return res @@ -356,6 +357,7 @@ class ir_model_fields(osv.osv): select=vals.get('select_level', '0'), update_custom_fields=True) self.pool[vals['model']]._auto_init(cr, ctx) + self.pool[vals['model']]._auto_end(cr, ctx) # actually create FKs! openerp.modules.registry.RegistryManager.signal_registry_change(cr.dbname) return res @@ -471,6 +473,7 @@ class ir_model_fields(osv.osv): for col_name, col_prop, val in patch_struct[1]: setattr(obj._columns[col_name], col_prop, val) obj._auto_init(cr, ctx) + obj._auto_end(cr, ctx) # actually create FKs! openerp.modules.registry.RegistryManager.signal_registry_change(cr.dbname) return res diff --git a/openerp/addons/base/ir/ir_translation.py b/openerp/addons/base/ir/ir_translation.py index 0f9b6ea3886..3306d95fce1 100644 --- a/openerp/addons/base/ir/ir_translation.py +++ b/openerp/addons/base/ir/ir_translation.py @@ -161,18 +161,20 @@ class ir_translation(osv.osv): ''' if context is None: context = {} - res = {} + res = dict.fromkeys(ids, False) for record in self.browse(cr, uid, ids, context=context): if record.type != 'model': res[record.id] = record.src else: model_name, field = record.name.split(',') model = self.pool.get(model_name) - #We need to take the context without the language information, because we want to read the - #value store in db and not on the one associate with current language. - context_wo_lang = context.copy() - context_wo_lang.pop('lang', None) - res[record.id] = model.read(cr, uid, record.res_id, [field], context=context_wo_lang)[field] + if model and model.exists(cr, uid, record.res_id, context=context): + #We need to take the context without the language information, because we want to read the + #value store in db and not on the one associate with current language. + context_wo_lang = context.copy() + context_wo_lang.pop('lang', None) + result = model.read(cr, uid, record.res_id, [field], context=context_wo_lang) + res[record.id] = result and result[field] or False return res def _set_src(self, cr, uid, id, name, value, args, context=None): diff --git a/openerp/modules/registry.py b/openerp/modules/registry.py index 2569bf47aad..98a4260be23 100644 --- a/openerp/modules/registry.py +++ b/openerp/modules/registry.py @@ -297,16 +297,14 @@ class RegistryManager(object): r, c = cr.fetchone() # Check if the model registry must be reloaded (e.g. after the # database has been updated by another process). - if registry.base_registry_signaling_sequence != r: + if registry.base_registry_signaling_sequence > 1 and registry.base_registry_signaling_sequence != r: _logger.info("Reloading the model registry after database signaling.") registry = cls.new(db_name) - registry.base_registry_signaling_sequence = r # Check if the model caches must be invalidated (e.g. after a write # occured on another process). Don't clear right after a registry # has been reload. - elif registry.base_cache_signaling_sequence != c: + elif registry.base_cache_signaling_sequence > 1 and registry.base_cache_signaling_sequence != c: _logger.info("Invalidating all model caches after database signaling.") - registry.base_cache_signaling_sequence = c registry.clear_caches() registry.reset_any_cache_cleared() # One possible reason caches have been invalidated is the @@ -316,6 +314,8 @@ class RegistryManager(object): for column in model._columns.values(): if hasattr(column, 'digits_change'): column.digits_change(cr) + registry.base_registry_signaling_sequence = r + registry.base_cache_signaling_sequence = c finally: cr.close() diff --git a/openerp/osv/fields.py b/openerp/osv/fields.py index 669b313db15..b60933cbf1d 100644 --- a/openerp/osv/fields.py +++ b/openerp/osv/fields.py @@ -208,27 +208,29 @@ class reference(_column): return model.name_get(cr, uid, [int(res_id)], context=context)[0][1] return tools.ustr(value) +# takes a string (encoded in utf8) and returns a string (encoded in utf8) +def _symbol_set_char(self, symb): + + #TODO: + # * we need to remove the "symb==False" from the next line BUT + # for now too many things rely on this broken behavior + # * the symb==None test should be common to all data types + if symb is None or symb == False: + return None + + # we need to convert the string to a unicode object to be able + # to evaluate its length (and possibly truncate it) reliably + u_symb = tools.ustr(symb) + return u_symb[:self.size].encode('utf8') + class char(_column): _type = 'char' def __init__(self, string="unknown", size=None, **args): _column.__init__(self, string=string, size=size or None, **args) - self._symbol_set = (self._symbol_c, self._symbol_set_char) - - # takes a string (encoded in utf8) and returns a string (encoded in utf8) - def _symbol_set_char(self, symb): - #TODO: - # * we need to remove the "symb==False" from the next line BUT - # for now too many things rely on this broken behavior - # * the symb==None test should be common to all data types - if symb is None or symb == False: - return None - - # we need to convert the string to a unicode object to be able - # to evaluate its length (and possibly truncate it) reliably - u_symb = tools.ustr(symb) - - return u_symb[:self.size].encode('utf8') + # self._symbol_set_char defined to keep the backward compatibility + self._symbol_f = self._symbol_set_char = lambda x: _symbol_set_char(self, x) + self._symbol_set = (self._symbol_c, self._symbol_f) class text(_column): @@ -1086,6 +1088,11 @@ class function(_column): self._symbol_f = integer._symbol_f self._symbol_set = integer._symbol_set + if type == 'char': + self._symbol_c = char._symbol_c + self._symbol_f = lambda x: _symbol_set_char(self, x) + self._symbol_set = (self._symbol_c, self._symbol_f) + def digits_change(self, cr): if self._type == 'float': if self.digits_compute: diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 8858b51e0f9..fea065c27ac 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -1007,8 +1007,10 @@ class BaseModel(object): raise except_orm('Error', ('Invalid function definition %s in object %s !\nYou must use the definition: store={object:(fnct, fields, priority, time length)}.' % (store_field, self._name))) self.pool._store_function.setdefault(object, []) - self.pool._store_function[object].append((self._name, store_field, fnct, tuple(fields2) if fields2 else None, order, length)) - self.pool._store_function[object].sort(lambda x, y: cmp(x[4], y[4])) + t = (self._name, store_field, fnct, tuple(fields2) if fields2 else None, order, length) + if not t in self.pool._store_function[object]: + self.pool._store_function[object].append((self._name, store_field, fnct, tuple(fields2) if fields2 else None, order, length)) + self.pool._store_function[object].sort(lambda x, y: cmp(x[4], y[4])) for (key, _, msg) in self._sql_constraints: self.pool._sql_error[self._table+'_'+key] = msg @@ -2844,8 +2846,12 @@ class BaseModel(object): """ Record the creation of a constraint for this model, to make it possible to delete it later when the module is uninstalled. Type can be either - 'f' or 'u' depending on the constraing being a foreign key or not. + 'f' or 'u' depending on the constraint being a foreign key or not. """ + if not self._module: + # no need to save constraints for custom models as they're not part + # of any module + return assert type in ('f', 'u') cr.execute(""" SELECT 1 FROM ir_model_constraint, ir_module_module @@ -4558,9 +4564,13 @@ class BaseModel(object): if ((not f[trigger_fields_]) or set(fields).intersection(f[trigger_fields_]))] mapping = {} + fresults = {} for function in to_compute: - # use admin user for accessing objects having rules defined on store fields - target_ids = [id for id in function[id_mapping_fnct_](self, cr, SUPERUSER_ID, ids, context) if id] + fid = id(function[id_mapping_fnct_]) + if not fid in fresults: + # use admin user for accessing objects having rules defined on store fields + fresults[fid] = [id2 for id2 in function[id_mapping_fnct_](self, cr, SUPERUSER_ID, ids, context) if id2] + target_ids = fresults[fid] # the compound key must consider the priority and model name key = (function[priority_], function[model_name_]) @@ -4581,8 +4591,8 @@ class BaseModel(object): functions_ids_maps = {} # function_ids_maps = # { (function_1_tuple, function_2_tuple) : [target_id1, target_id2, ..] } - for id, functions in id_map.iteritems(): - functions_ids_maps.setdefault(tuple(functions), []).append(id) + for fid, functions in id_map.iteritems(): + functions_ids_maps.setdefault(tuple(functions), []).append(fid) for functions, ids in functions_ids_maps.iteritems(): call_map.setdefault((priority,model),[]).append((priority, model, ids, [f[func_field_to_compute_] for f in functions])) diff --git a/openerp/tools/translate.py b/openerp/tools/translate.py index 3c51fa5f3b5..4a055950c46 100644 --- a/openerp/tools/translate.py +++ b/openerp/tools/translate.py @@ -832,8 +832,11 @@ def trans_generate(lang, modules, cr): if module: src_file = open(fabsolutepath, 'r') try: - for lineno, message, comments in extract.extract(extract_method, src_file, - keywords=extract_keywords): + for extracted in extract.extract(extract_method, src_file, + keywords=extract_keywords): + # Babel 0.9.6 yields lineno, message, comments + # Babel 1.3 yields lineno, message, comments, context + lineno, message, comments = extracted[:3] push_translation(module, trans_type, display_path, lineno, encode(message), comments + extra_comments) except Exception: