diff --git a/addons/account/__openerp__.py b/addons/account/__openerp__.py index a380a69dc03..17c0a77c30f 100644 --- a/addons/account/__openerp__.py +++ b/addons/account/__openerp__.py @@ -146,6 +146,7 @@ for a particular financial year and for preparation of vouchers there is a modul 'account_unit_test.xml', ], 'test': [ + 'test/account_test_users.yml', 'test/account_customer_invoice.yml', 'test/account_supplier_invoice.yml', 'test/account_change_currency.yml', @@ -153,12 +154,11 @@ for a particular financial year and for preparation of vouchers there is a modul 'test/account_period_close.yml', 'test/account_use_model.yml', 'test/account_validate_account_move.yml', - 'test/account_fiscalyear_close.yml', #'test/account_bank_statement.yml', #'test/account_cash_statement.yml', 'test/test_edi_invoice.yml', 'test/account_report.yml', - 'test/account_fiscalyear_close_state.yml', #last test, as it will definitively close the demo fiscalyear + 'test/account_fiscalyear_close.yml', #last test, as it will definitively close the demo fiscalyear ], 'installable': True, 'auto_install': False, diff --git a/addons/account/account.py b/addons/account/account.py index 3e101b89528..0dc7c00a716 100644 --- a/addons/account/account.py +++ b/addons/account/account.py @@ -137,16 +137,27 @@ class account_account_type(osv.osv): _name = "account.account.type" _description = "Account Type" - def _get_current_report_type(self, cr, uid, ids, name, arg, context=None): + def _get_financial_report_ref(self, cr, uid, context=None): obj_data = self.pool.get('ir.model.data') obj_financial_report = self.pool.get('account.financial.report') + financial_report_ref = {} + for key, financial_report in [ + ('asset','account_financial_report_assets0'), + ('liability','account_financial_report_liability0'), + ('income','account_financial_report_income0'), + ('expense','account_financial_report_expense0'), + ]: + try: + financial_report_ref[key] = obj_financial_report.browse(cr, uid, + obj_data.get_object_reference(cr, uid, 'account', financial_report)[1], + context=context) + except ValueError: + pass + return financial_report_ref + + def _get_current_report_type(self, cr, uid, ids, name, arg, context=None): res = {} - financial_report_ref = { - 'asset': obj_financial_report.browse(cr, uid, obj_data.get_object_reference(cr, uid, 'account','account_financial_report_assets0')[1], context=context), - 'liability': obj_financial_report.browse(cr, uid, obj_data.get_object_reference(cr, uid, 'account','account_financial_report_liability0')[1], context=context), - 'income': obj_financial_report.browse(cr, uid, obj_data.get_object_reference(cr, uid, 'account','account_financial_report_income0')[1], context=context), - 'expense': obj_financial_report.browse(cr, uid, obj_data.get_object_reference(cr, uid, 'account','account_financial_report_expense0')[1], context=context), - } + financial_report_ref = self._get_financial_report_ref(cr, uid, context=context) for record in self.browse(cr, uid, ids, context=context): res[record.id] = 'none' for key, financial_report in financial_report_ref.items(): @@ -157,15 +168,9 @@ class account_account_type(osv.osv): def _save_report_type(self, cr, uid, account_type_id, field_name, field_value, arg, context=None): field_value = field_value or 'none' - obj_data = self.pool.get('ir.model.data') obj_financial_report = self.pool.get('account.financial.report') #unlink if it exists somewhere in the financial reports related to BS or PL - financial_report_ref = { - 'asset': obj_financial_report.browse(cr, uid, obj_data.get_object_reference(cr, uid, 'account','account_financial_report_assets0')[1], context=context), - 'liability': obj_financial_report.browse(cr, uid, obj_data.get_object_reference(cr, uid, 'account','account_financial_report_liability0')[1], context=context), - 'income': obj_financial_report.browse(cr, uid, obj_data.get_object_reference(cr, uid, 'account','account_financial_report_income0')[1], context=context), - 'expense': obj_financial_report.browse(cr, uid, obj_data.get_object_reference(cr, uid, 'account','account_financial_report_expense0')[1], context=context), - } + financial_report_ref = self._get_financial_report_ref(cr, uid, context=context) for key, financial_report in financial_report_ref.items(): list_ids = [x.id for x in financial_report.account_type_ids] if account_type_id in list_ids: @@ -1257,6 +1262,10 @@ class account_move(osv.osv): return [('id', 'in', tuple(ids))] return [('id', '=', '0')] + def _get_move_from_lines(self, cr, uid, ids, context=None): + line_obj = self.pool.get('account.move.line') + return [line.move_id.id for line in line_obj.browse(cr, uid, ids, context=context)] + _columns = { 'name': fields.char('Number', size=64, required=True), 'ref': fields.char('Reference', size=64), @@ -1266,7 +1275,10 @@ class account_move(osv.osv): help='All manually created new journal entries are usually in the status \'Unposted\', but you can set the option to skip that status on the related journal. In that case, they will behave as journal entries automatically created by the system on document validation (invoices, bank statements...) and will be created in \'Posted\' status.'), 'line_id': fields.one2many('account.move.line', 'move_id', 'Entries', states={'posted':[('readonly',True)]}), 'to_check': fields.boolean('To Review', help='Check this box if you are unsure of that journal entry and if you want to note it as \'to be reviewed\' by an accounting expert.'), - 'partner_id': fields.related('line_id', 'partner_id', type="many2one", relation="res.partner", string="Partner", store=True), + 'partner_id': fields.related('line_id', 'partner_id', type="many2one", relation="res.partner", string="Partner", store={ + _name: (lambda self, cr,uid,ids,c: ids, ['line_id'], 10), + 'account.move.line': (_get_move_from_lines, ['partner_id'],10) + }), 'amount': fields.function(_amount_compute, string='Amount', digits_compute=dp.get_precision('Account'), type='float', fnct_search=_search_amount), 'date': fields.date('Date', required=True, states={'posted':[('readonly',True)]}, select=True), 'narration':fields.text('Internal Note'), @@ -1403,14 +1415,17 @@ class account_move(osv.osv): l[2]['period_id'] = default_period context['period_id'] = default_period - if 'line_id' in vals: + if vals.get('line_id', False): c = context.copy() c['novalidate'] = True c['period_id'] = vals['period_id'] if 'period_id' in vals else self._get_period(cr, uid, context) c['journal_id'] = vals['journal_id'] if 'date' in vals: c['date'] = vals['date'] result = super(account_move, self).create(cr, uid, vals, c) - self.validate(cr, uid, [result], context) + tmp = self.validate(cr, uid, [result], context) + journal = self.pool.get('account.journal').browse(cr, uid, vals['journal_id'], context) + if journal.entry_posted and tmp: + self.button_validate(cr,uid, [result], context) else: result = super(account_move, self).create(cr, uid, vals, context) return result @@ -1632,9 +1647,11 @@ class account_move(osv.osv): else: # We can't validate it (it's unbalanced) # Setting the lines as draft - obj_move_line.write(cr, uid, line_ids, { - 'state': 'draft' - }, context, check=False) + not_draft_line_ids = list(set(line_ids) - set(line_draft_ids)) + if not_draft_line_ids: + obj_move_line.write(cr, uid, not_draft_line_ids, { + 'state': 'draft' + }, context, check=False) # Create analytic lines for the valid moves for record in valid_moves: obj_move_line.create_analytic_lines(cr, uid, [line.id for line in record.line_id], context) @@ -2773,6 +2790,7 @@ class account_chart_template(osv.osv): 'parent_id': fields.many2one('account.chart.template', 'Parent Chart Template'), 'code_digits': fields.integer('# of Digits', required=True, help="No. of Digits to use for account code"), 'visible': fields.boolean('Can be Visible?', help="Set this to False if you don't want this template to be used actively in the wizard that generate Chart of Accounts from templates, this is useful when you want to generate accounts of this template only when loading its child template."), + 'currency_id': fields.many2one('res.currency', 'Currency'), '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 sale and purchase rates or choose from list of taxes. This last choice assumes that the set of tax defined on this template is complete'), 'account_root_id': fields.many2one('account.account.template', 'Root Account', domain=[('parent_id','=',False)]), 'tax_code_root_id': fields.many2one('account.tax.code.template', 'Root Tax Code', domain=[('parent_id','=',False)]), @@ -3028,11 +3046,19 @@ 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 onchange_company_id(self, cr, uid, ids, company_id, context=None): - currency_id = False - if company_id: - currency_id = self.pool.get('res.company').browse(cr, uid, company_id, context=context).currency_id.id - return {'value': {'currency_id': currency_id}} + + 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}} @@ -3043,15 +3069,21 @@ class wizard_multi_charts_accounts(osv.osv_memory): res['value'] = {'complete_tax_set': False, 'sale_tax': False, 'purchase_tax': False} if chart_template_id: data = self.pool.get('account.chart.template').browse(cr, uid, chart_template_id, context=context) - res['value'].update({'complete_tax_set': data.complete_tax_set}) + currency_id = data.currency_id and data.currency_id.id or self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.currency_id.id + 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 @@ -3059,6 +3091,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'] if 'bank_accounts_id' in fields: res.update({'bank_accounts_id': [{'acc_name': _('Cash'), 'account_type': 'cash'},{'acc_name': _('Bank'), 'account_type': 'bank'}]}) @@ -3072,17 +3105,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"): + model_data = self.pool.get('ir.model.data').search_read(cr, uid, [('model','=','account.chart.template'),('module','=',context.get("default_charts"))], ['res_id'], context=context) + if model_data: + chart_id = model_data[0]['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: - res.update({'only_one_chart_template': len(ids) == 1, 'chart_template_id': ids[0]}) + 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, @@ -3350,12 +3394,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/account_installer.xml b/addons/account/account_installer.xml index b03babc63ac..8d1b25b299f 100644 --- a/addons/account/account_installer.xml +++ b/addons/account/account_installer.xml @@ -10,7 +10,7 @@ diff --git a/addons/account/account_invoice.py b/addons/account/account_invoice.py index bf1da5cb71b..42f3effd6f9 100644 --- a/addons/account/account_invoice.py +++ b/addons/account/account_invoice.py @@ -1431,6 +1431,7 @@ class account_invoice_line(osv.osv): _name = "account.invoice.line" _description = "Invoice Line" + _order = "invoice_id,sequence,id" _columns = { 'name': fields.text('Description', required=True), 'origin': fields.char('Source Document', size=256, help="Reference of the document that produced this invoice."), @@ -1467,6 +1468,7 @@ class account_invoice_line(osv.osv): 'discount': 0.0, 'price_unit': _price_unit_default, 'account_id': _default_account_id, + 'sequence': 10, } def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False): diff --git a/addons/account/account_invoice_view.xml b/addons/account/account_invoice_view.xml index 364a6ad45b3..faa2aaee3be 100644 --- a/addons/account/account_invoice_view.xml +++ b/addons/account/account_invoice_view.xml @@ -192,6 +192,7 @@ + @@ -250,7 +251,7 @@ - + @@ -348,6 +349,7 @@ + @@ -392,7 +394,7 @@ - + - + - - + + diff --git a/addons/account/account_move_line.py b/addons/account/account_move_line.py index 7f5fa9707c1..0fc9d9e2227 100644 --- a/addons/account/account_move_line.py +++ b/addons/account/account_move_line.py @@ -1283,7 +1283,7 @@ class account_move_line(osv.osv): self.create(cr, uid, data, context) del vals['account_tax_id'] - if check and ((not context.get('no_store_function')) or journal.entry_posted): + if check and not context.get('novalidate') and ((not context.get('no_store_function')) or journal.entry_posted): tmp = move_obj.validate(cr, uid, [vals['move_id']], context) if journal.entry_posted and tmp: move_obj.button_validate(cr,uid, [vals['move_id']], context) diff --git a/addons/account/account_view.xml b/addons/account/account_view.xml index 5b5215af827..7d350fdd2e1 100644 --- a/addons/account/account_view.xml +++ b/addons/account/account_view.xml @@ -413,7 +413,7 @@ - + @@ -1404,7 +1404,7 @@ - + @@ -2118,7 +2118,7 @@ - +