From f08bf5a08e67af086a26b51e67c69bd253155a38 Mon Sep 17 00:00:00 2001 From: Josse Colpaert Date: Mon, 4 Mar 2013 14:53:29 +0100 Subject: [PATCH 01/24] [FIX] Generates journal items immediately from expense bzr revid: jco@openerp.com-20130304135329-v1dfw564svd0zv7q --- addons/hr_expense/hr_expense.py | 301 ++++++++++++++++++++++ addons/hr_expense/hr_expense_workflow.xml | 2 +- 2 files changed, 302 insertions(+), 1 deletion(-) diff --git a/addons/hr_expense/hr_expense.py b/addons/hr_expense/hr_expense.py index f32479c2ae2..03475c90b04 100644 --- a/addons/hr_expense/hr_expense.py +++ b/addons/hr_expense/hr_expense.py @@ -145,6 +145,307 @@ class hr_expense_expense(osv.osv): def expense_canceled(self, cr, uid, ids, context=None): return self.write(cr, uid, ids, {'state': 'cancelled'}, context=context) + + def account_move_get(self, cr, uid, expense_id, journal_id, context=None): + ''' + This method prepare the creation of the account move related to the given expense. + + :param expense_id: Id of voucher for which we are creating account_move. + :return: mapping between fieldname and value of account move to create + :rtype: dict + ''' + + + #Search for the period corresponding with confirmation date + expense_brw = self.browse(cr,uid,expense_id,context) + period_obj = self.pool.get('account.period') + company_id = expense_brw.company_id.id + ctx = context + ctx.update({'company_id': company_id}) + date = expense_brw.date_confirm + pids = period_obj.find(cr, uid, date, context=ctx) + try: + period_id = pids[0] + except: + raise osv.except_osv(_('Error! '), + _('Please define periods!')) + period = period_obj.browse(cr, uid, period_id, context=context) + + seq_obj = self.pool.get('ir.sequence') + + journal = self.pool.get('account.journal').browse(cr, uid, journal_id, context=context) + if journal.sequence_id: + if not journal.sequence_id.active: + raise osv.except_osv(_('Configuration Error !'), + _('Please activate the sequence of selected journal !')) + c = dict(context) + c.update({'fiscalyear_id': period.fiscalyear_id.id}) + name = seq_obj.next_by_id(cr, uid, journal.sequence_id.id, context=c) + else: + raise osv.except_osv(_('Error!'), + _('Please define a sequence on the journal.')) + #Look for the next expense number + ref = seq_obj.get(cr, uid, 'hr.expense.invoice') + + move = { + 'name': name, + 'journal_id': journal_id, + 'narration': '', + 'date': expense_brw.date_confirm, + 'ref': ref, + 'period_id': period_id, + } + return move + + def line_get_convert(self, cr, uid, x, part, date, context=None): + return { + 'date_maturity': x.get('date_maturity', False), + 'partner_id': part.id, + 'name': x['name'][:64], + 'date': date, + 'debit': x['price']>0 and x['price'], + 'credit': x['price']<0 and -x['price'], + 'account_id': x['account_id'], + 'analytic_lines': x.get('analytic_lines', False), + 'amount_currency': x['price']>0 and abs(x.get('amount_currency', False)) or -abs(x.get('amount_currency', False)), + 'currency_id': x.get('currency_id', False), + 'tax_code_id': x.get('tax_code_id', False), + 'tax_amount': x.get('tax_amount', False), + 'ref': x.get('ref', False), + 'quantity': x.get('quantity',1.00), + 'product_id': x.get('product_id', False), + 'product_uom_id': x.get('uos_id', False), + 'analytic_account_id': x.get('account_analytic_id', False), + } + + def compute_expense_totals(self, cr, uid, inv, company_currency, ref, invoice_move_lines, context=None): + if context is None: + context={} + total = 0 + total_currency = 0 + cur_obj = self.pool.get('res.currency') + for i in invoice_move_lines: + if inv.currency_id.id != company_currency: + context.update({'date': inv.date_confirm or time.strftime('%Y-%m-%d')}) + i['currency_id'] = inv.currency_id.id + i['amount_currency'] = i['price'] + i['price'] = cur_obj.compute(cr, uid, inv.currency_id.id, + company_currency, i['price'], + context=context) + else: + i['amount_currency'] = False + i['currency_id'] = False + i['ref'] = ref + total -= i['price'] + total_currency -= i['amount_currency'] or i['price'] + return total, total_currency, invoice_move_lines + + + def action_move_create(self, cr, uid, ids, context=None): + property_obj = self.pool.get('ir.property') + sequence_obj = self.pool.get('ir.sequence') + analytic_journal_obj = self.pool.get('account.analytic.journal') + account_journal = self.pool.get('account.journal') + voucher_obj = self.pool.get('account.voucher') + currency_obj = self.pool.get('res.currency') + ait_obj = self.pool.get('account.invoice.tax') + move_obj = self.pool.get('account.move') + if context is None: + context = {} + for exp in self.browse(cr, uid, ids, context=context): + company_id = exp.company_id.id + lines = [] + total = 0.0 + ctx = context.copy() + ctx.update({'date': exp.date}) + journal = False + if exp.journal_id: + journal = exp.journal_id + else: + journal_id = voucher_obj._get_journal(cr, uid, context={'type': 'purchase', 'company_id': company_id}) + if journal_id: + journal = account_journal.browse(cr, uid, journal_id, context=context) + if not journal: + raise osv.except_osv(_('Error!'), _("No expense journal found. Please make sure you have a journal with type 'purchase' configured.")) + if not journal.sequence_id: + raise osv.except_osv(_('Error!'), _('Please define sequence on the journal related to this invoice.')) + company_currency = exp.company_id.currency_id.id + current_currency = exp.currency_id +# for line in exp.line_ids: +# if line.product_id: +# acc = line.product_id.property_account_expense +# if not acc: +# acc = line.product_id.categ_id.property_account_expense_categ +# else: +# acc = property_obj.get(cr, uid, 'property_account_expense_categ', 'product.category', context={'force_company': company_id}) +# if not acc: +# raise osv.except_osv(_('Error!'), _('Please configure Default Expense account for Product purchase: `property_account_expense_categ`.')) +# total_amount = line.total_amount +# if journal.currency: +# if exp.currency_id != journal.currency: +# total_amount = currency_obj.compute(cr, uid, exp.currency_id.id, journal.currency.id, total_amount, context=ctx) +# elif exp.currency_id != exp.company_id.currency_id: +# total_amount = currency_obj.compute(cr, uid, exp.currency_id.id, exp.company_id.currency_id.id, total_amount, context=ctx) +# lines.append((0, False, { +# 'name': line.name, +# 'account_id': acc.id, +# 'account_analytic_id': line.analytic_account.id, +# 'amount': total_amount, +# 'type': 'dr' +# })) +# total += total_amount + if not exp.employee_id.address_home_id: + raise osv.except_osv(_('Error!'), _('The employee must have a home address.')) + acc = exp.employee_id.address_home_id.property_account_payable.id + + #From action_move_line_create of voucher + move_id = move_obj.create(cr, uid, self.account_move_get(cr, uid, exp.id, journal.id, context=context), context=context) + move = move_obj.browse(cr, uid, move_id, context=context) + #iml = self._get_analytic_lines + + # within: iml = self.pool.get('account.invoice.line').move_line_get + iml = self.move_line_get(cr, uid, exp.id, context=context) + + #Write taxes on the lines which should automatically add the necessary extra lines upon creation + + + + diff_currency_p = exp.currency_id.id <> company_currency + # create one move line for the total + total = 0 + total_currency = 0 + total, total_currency, iml = self.compute_expense_totals(cr, uid, exp, company_currency, exp.name, iml, context=ctx) + + + #Need to have counterline: + + iml.append({ + 'type':'dest', + 'name':'/', + 'price':total, + 'account_id': acc, + 'date_maturity': exp.date_confirm, + 'amount_currency': diff_currency_p and total_currency or False, + 'currency_id': diff_currency_p and exp.currency_id.id or False, + 'ref': exp.name + }) + + line = map(lambda x:(0,0,self.line_get_convert(cr, uid, x, exp.user_id.partner_id, exp.date_confirm, context=ctx)),iml) + move_obj.write(cr, uid, [move_id], {'line_id':line}, context=ctx) + self.write(cr, uid, ids, {'account_move_id':move_id, 'state':'done'}, context=context) + + + #compute_taxes = ait_obj.compute(cr, uid, , context=context) + + + +# return { +# 'type':'src', +# 'name':line.name.split('\n')[0][:64], +# 'price_unit':line.price_unit, +# 'quantity':line.quantity, +# 'price':line.price_subtotal, +# 'account_id':line.account_id.id, +# 'product_id':line.product_id.id, +# 'uos_id':line.uos_id.id, +# 'account_analytic_id':line.account_analytic_id.id, +# 'taxes':line.invoice_line_tax_id} + + + def move_line_get(self, cr, uid, expense_id, context=None): + res = [] + tax_obj = self.pool.get('account.tax') + cur_obj = self.pool.get('res.currency') + if context is None: + context = {} + exp = self.browse(cr, uid, expense_id, context=context) + company_currency = exp.company_id.currency_id.id + + for line in exp.line_ids: + mres = self.move_line_get_item(cr, uid, line, context) + if not mres: + continue + res.append(mres) + tax_code_found= False + + #Calculate tax according to default tax on product + + #Taken from product_id_onchange in account.invoice + if line.product_id: + fposition_id = False + fpos_obj = self.pool.get('account.fiscal.position') + fpos = fposition_id and fpos_obj.browse(cr, uid, fposition_id, context=context) or False + product = line.product_id + taxes = product.supplier_taxes_id + #If taxes are not related to the product, maybe they are in the account + if not taxes: + a = product.property_account_expense.id #Why is not there a check here? + if not a: + a = product.categ_id.property_account_expense_categ.id + a = fpos_obj.map_account(cr, uid, fpos, a) + taxes = a and self.pool.get('account.account').browse(cr, uid, a, context=context).tax_ids or False + tax_id = fpos_obj.map_tax(cr, uid, fpos, taxes) + #Calculating tax on the line and creating move? + for tax in tax_obj.compute_all(cr, uid, taxes, + line.unit_amount , + line.unit_quantity, line.product_id, + exp.user_id.partner_id)['taxes']: + tax_code_id = tax['base_code_id'] + tax_amount = line.total_amount * tax['base_sign'] + if tax_code_found: + if not tax_code_id: + continue + res.append(self.move_line_get_item(cr, uid, line, context)) + res[-1]['price'] = 0.0 + res[-1]['account_analytic_id'] = False + elif not tax_code_id: + continue + tax_code_found = True + res[-1]['tax_code_id'] = tax_code_id + res[-1]['tax_amount'] = cur_obj.compute(cr, uid, exp.currency_id.id, company_currency, tax_amount, context={'date': exp.date_confirm}) + + #Will create the tax here as we don't have the access + assoc_tax = { + 'type':'tax', + 'name':tax['name'], + 'price_unit': tax['price_unit'], + 'quantity': 1, + 'price': tax['amount'] * tax['base_sign'] or 0.0, + 'account_id': tax['account_collected_id'], + 'tax_code_id': tax['tax_code_id'], + 'tax_amount': tax['amount'] * tax['base_sign'], + } + res.append(assoc_tax) + return res + + def move_line_get_item(self, cr, uid, line, context=None): + company = line.expense_id.company_id + property_obj = self.pool.get('ir.property') + if line.product_id: + acc = line.product_id.property_account_expense + if not acc: + acc = line.product_id.categ_id.property_account_expense_categ + else: + acc = property_obj.get(cr, uid, 'property_account_expense_categ', 'product.category', context={'force_company': company.id}) + if not acc: + raise osv.except_osv(_('Error!'), _('Please configure Default Expense account for Product purchase: `property_account_expense_categ`.')) + return { + 'type':'src', + 'name': line.name.split('\n')[0][:64], + 'price_unit':line.unit_amount, + 'quantity':line.unit_quantity, + 'price':line.total_amount, + 'account_id':acc.id, + 'product_id':line.product_id.id, + 'uos_id':line.uom_id.id, + 'account_analytic_id':line.analytic_account.id, + #'taxes':line.invoice_line_tax_id, + } + + + + + def action_receipt_create(self, cr, uid, ids, context=None): property_obj = self.pool.get('ir.property') sequence_obj = self.pool.get('ir.sequence') diff --git a/addons/hr_expense/hr_expense_workflow.xml b/addons/hr_expense/hr_expense_workflow.xml index 2e085071207..c01bb4cd14b 100644 --- a/addons/hr_expense/hr_expense_workflow.xml +++ b/addons/hr_expense/hr_expense_workflow.xml @@ -43,7 +43,7 @@ done function - action_receipt_create() + action_move_create() From 1e3725b9e6cc0f167dd3000844dc3d13e64dff98 Mon Sep 17 00:00:00 2001 From: Josse Colpaert Date: Mon, 4 Mar 2013 15:47:22 +0100 Subject: [PATCH 02/24] [FIX] adjust tests and no taxes when product not available bzr revid: jco@openerp.com-20130304144722-y30nkmmd8hyby7x0 --- addons/hr_expense/hr_expense.py | 2 ++ addons/hr_expense/test/expense_process.yml | 5 ----- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/addons/hr_expense/hr_expense.py b/addons/hr_expense/hr_expense.py index 03475c90b04..fb8af6649de 100644 --- a/addons/hr_expense/hr_expense.py +++ b/addons/hr_expense/hr_expense.py @@ -385,6 +385,8 @@ class hr_expense_expense(osv.osv): a = fpos_obj.map_account(cr, uid, fpos, a) taxes = a and self.pool.get('account.account').browse(cr, uid, a, context=context).tax_ids or False tax_id = fpos_obj.map_tax(cr, uid, fpos, taxes) + else: + taxes = [] #Calculating tax on the line and creating move? for tax in tax_obj.compute_all(cr, uid, taxes, line.unit_amount , diff --git a/addons/hr_expense/test/expense_process.yml b/addons/hr_expense/test/expense_process.yml index eae63c460fc..4b65c16e8ea 100644 --- a/addons/hr_expense/test/expense_process.yml +++ b/addons/hr_expense/test/expense_process.yml @@ -26,11 +26,6 @@ !python {model: hr.expense.expense}: | sep_expenses = self.browse(cr, uid, ref("sep_expenses"), context=context) assert sep_expenses.state == 'done', "Expense should be in 'Done' state." - assert sep_expenses.voucher_id, "Expense should have link of Purchase Receipt." - assert sep_expenses.voucher_id.type == 'purchase', "Receipt type is not purchase receipt." - assert sep_expenses.voucher_id.amount == sep_expenses.amount,"Receipt total amount is not correspond with expense total." - assert len(sep_expenses.voucher_id.line_dr_ids) == len(sep_expenses.line_ids),"Lines of Receipt and expense line are not correspond." - - I duplicate the expenses and cancel duplicated. - From 804bc3a916916eb5c32ef44e8bc5b5f37c89078d Mon Sep 17 00:00:00 2001 From: Josse Colpaert Date: Mon, 4 Mar 2013 16:55:50 +0100 Subject: [PATCH 03/24] [FIX] in case of no taxes bzr revid: jco@openerp.com-20130304155550-g5m12ryt6id0b3m3 --- addons/hr_expense/hr_expense.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/addons/hr_expense/hr_expense.py b/addons/hr_expense/hr_expense.py index fb8af6649de..f61f8923411 100644 --- a/addons/hr_expense/hr_expense.py +++ b/addons/hr_expense/hr_expense.py @@ -306,9 +306,6 @@ class hr_expense_expense(osv.osv): # within: iml = self.pool.get('account.invoice.line').move_line_get iml = self.move_line_get(cr, uid, exp.id, context=context) - #Write taxes on the lines which should automatically add the necessary extra lines upon creation - - diff_currency_p = exp.currency_id.id <> company_currency # create one move line for the total @@ -385,7 +382,7 @@ class hr_expense_expense(osv.osv): a = fpos_obj.map_account(cr, uid, fpos, a) taxes = a and self.pool.get('account.account').browse(cr, uid, a, context=context).tax_ids or False tax_id = fpos_obj.map_tax(cr, uid, fpos, taxes) - else: + if not taxes: taxes = [] #Calculating tax on the line and creating move? for tax in tax_obj.compute_all(cr, uid, taxes, From cdabf79cf27a08f8ecb63a0a94e7d13b9f05fc4e Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Wed, 6 Mar 2013 15:05:54 +0100 Subject: [PATCH 04/24] [REF] hr_expense, creation of accounting entries from hr.expense: a lot of code refactoring. Still a huge work to be done in order to factorize some code with other objects (like account.invoice, account.voucher, account.asset...) bzr revid: qdp-launchpad@openerp.com-20130306140554-fhs6fhkyb779t6re --- addons/account/account.py | 23 +++ addons/hr_expense/__openerp__.py | 2 +- addons/hr_expense/hr_expense.py | 264 ++++++-------------------- addons/hr_expense/hr_expense_view.xml | 1 + 4 files changed, 79 insertions(+), 211 deletions(-) diff --git a/addons/account/account.py b/addons/account/account.py index acf27c42392..2aab34ff8ba 100644 --- a/addons/account/account.py +++ b/addons/account/account.py @@ -1150,6 +1150,29 @@ class account_move(osv.osv): _description = "Account Entry" _order = 'id desc' + def account_move_prepare(self, cr, uid, journal_id, date=False, ref='', company_id=False, context=None): + ''' + Prepares and returns a dictionary of values, ready to be passed to create() based on the parameters received. + ''' + if not date: + date = fields.date.today() + period_obj = self.pool.get('account.period') + if not company_id: + user = self.pool.get('res.users').browse(cr, uid, uid, context=context) + company_id = user.company_id.id + if context is None: + context = {} + #put the company in context to find the good period + ctx = context.copy() + ctx.update({'company_id': company_id}) + return { + 'journal_id': journal_id, + 'date': date, + 'period_id': period_obj.find(cr, uid, date, context=ctx)[0], + 'ref': ref, + 'company_id': company_id, + } + def name_search(self, cr, user, name, args=None, operator='ilike', context=None, limit=80): """ Returns a list of tupples containing id, name, as internally it is called {def name_get} diff --git a/addons/hr_expense/__openerp__.py b/addons/hr_expense/__openerp__.py index 516af7f9d27..1f4e7b42209 100644 --- a/addons/hr_expense/__openerp__.py +++ b/addons/hr_expense/__openerp__.py @@ -46,7 +46,7 @@ This module also uses analytic accounting and is compatible with the invoice on 'author': 'OpenERP SA', 'website': 'http://www.openerp.com', 'images': ['images/hr_expenses_analysis.jpeg', 'images/hr_expenses.jpeg'], - 'depends': ['hr', 'account_voucher'], + 'depends': ['hr', 'account_voucher, account_accountant'], 'data': [ 'security/ir.model.access.csv', 'hr_expense_data.xml', diff --git a/addons/hr_expense/hr_expense.py b/addons/hr_expense/hr_expense.py index f61f8923411..29570559c65 100644 --- a/addons/hr_expense/hr_expense.py +++ b/addons/hr_expense/hr_expense.py @@ -145,8 +145,7 @@ class hr_expense_expense(osv.osv): def expense_canceled(self, cr, uid, ids, context=None): return self.write(cr, uid, ids, {'state': 'cancelled'}, context=context) - - def account_move_get(self, cr, uid, expense_id, journal_id, context=None): + def account_move_get(self, cr, uid, expense_id, context=None): ''' This method prepare the creation of the account move related to the given expense. @@ -154,53 +153,27 @@ class hr_expense_expense(osv.osv): :return: mapping between fieldname and value of account move to create :rtype: dict ''' - - - #Search for the period corresponding with confirmation date - expense_brw = self.browse(cr,uid,expense_id,context) - period_obj = self.pool.get('account.period') - company_id = expense_brw.company_id.id - ctx = context - ctx.update({'company_id': company_id}) - date = expense_brw.date_confirm - pids = period_obj.find(cr, uid, date, context=ctx) - try: - period_id = pids[0] - except: - raise osv.except_osv(_('Error! '), - _('Please define periods!')) - period = period_obj.browse(cr, uid, period_id, context=context) - - seq_obj = self.pool.get('ir.sequence') - - journal = self.pool.get('account.journal').browse(cr, uid, journal_id, context=context) - if journal.sequence_id: - if not journal.sequence_id.active: - raise osv.except_osv(_('Configuration Error !'), - _('Please activate the sequence of selected journal !')) - c = dict(context) - c.update({'fiscalyear_id': period.fiscalyear_id.id}) - name = seq_obj.next_by_id(cr, uid, journal.sequence_id.id, context=c) + journal_obj = self.pool.get('account.journal') + expense = self.browse(cr, uid, expense_id, context=context) + company_id = expense.company_id.id + date = expense.date_confirm + ref = expense.name + journal_id = False + if expense.journal_id: + journal_id = expense.journal_id.id else: - raise osv.except_osv(_('Error!'), - _('Please define a sequence on the journal.')) - #Look for the next expense number - ref = seq_obj.get(cr, uid, 'hr.expense.invoice') - - move = { - 'name': name, - 'journal_id': journal_id, - 'narration': '', - 'date': expense_brw.date_confirm, - 'ref': ref, - 'period_id': period_id, - } - return move + journal_id = journal_obj.search(cr, uid, [('type', '=', 'purchase'), ('company_id', '=', company_id)]) + if not journal_id: + raise osv.except_osv(_('Error!'), _("No expense journal found. Please make sure you have a journal with type 'purchase' configured.")) + journal_id = journal_id[0] + return self.pool.get('account_move').account_move_prepare(cr, uid, journal_id, date=date, ref=ref, company_id=company_id, context=context) def line_get_convert(self, cr, uid, x, part, date, context=None): + #partner_id = self.pool.get('res.partner')._find_partner(part) + partner_id = part.id return { 'date_maturity': x.get('date_maturity', False), - 'partner_id': part.id, + 'partner_id': partner_id, 'name': x['name'][:64], 'date': date, 'debit': x['price']>0 and x['price'], @@ -218,108 +191,65 @@ class hr_expense_expense(osv.osv): 'analytic_account_id': x.get('account_analytic_id', False), } - def compute_expense_totals(self, cr, uid, inv, company_currency, ref, invoice_move_lines, context=None): + def compute_expense_totals(self, cr, uid, exp, company_currency, ref, account_move_lines, context=None): + ''' + internal method used for computation of total amount of an expense in the company currency and + in the expense currency, given the account_move_lines that will be created. It also do some small + transformations at these account_move_lines (for multi-currency purposes) + + :param account_move_lines: list of dict + :rtype: tuple of 3 elements (a, b ,c) + a: total in company currency + b: total in hr.expense currency + c: account_move_lines potentially modified + ''' + cur_obj = self.pool.get('res.currency') if context is None: context={} - total = 0 - total_currency = 0 - cur_obj = self.pool.get('res.currency') - for i in invoice_move_lines: - if inv.currency_id.id != company_currency: - context.update({'date': inv.date_confirm or time.strftime('%Y-%m-%d')}) - i['currency_id'] = inv.currency_id.id + context.update({'date': exp.date_confirm or time.strftime('%Y-%m-%d')}) + total = 0.0 + total_currency = 0.0 + for i in account_move_lines: + if exp.currency_id.id != company_currency: + i['currency_id'] = exp.currency_id.id i['amount_currency'] = i['price'] - i['price'] = cur_obj.compute(cr, uid, inv.currency_id.id, + i['price'] = cur_obj.compute(cr, uid, exp.currency_id.id, company_currency, i['price'], context=context) else: i['amount_currency'] = False i['currency_id'] = False - i['ref'] = ref total -= i['price'] total_currency -= i['amount_currency'] or i['price'] - return total, total_currency, invoice_move_lines + return total, total_currency, account_move_lines def action_move_create(self, cr, uid, ids, context=None): - property_obj = self.pool.get('ir.property') - sequence_obj = self.pool.get('ir.sequence') - analytic_journal_obj = self.pool.get('account.analytic.journal') - account_journal = self.pool.get('account.journal') - voucher_obj = self.pool.get('account.voucher') - currency_obj = self.pool.get('res.currency') - ait_obj = self.pool.get('account.invoice.tax') move_obj = self.pool.get('account.move') if context is None: context = {} for exp in self.browse(cr, uid, ids, context=context): - company_id = exp.company_id.id - lines = [] - total = 0.0 - ctx = context.copy() - ctx.update({'date': exp.date}) - journal = False - if exp.journal_id: - journal = exp.journal_id - else: - journal_id = voucher_obj._get_journal(cr, uid, context={'type': 'purchase', 'company_id': company_id}) - if journal_id: - journal = account_journal.browse(cr, uid, journal_id, context=context) - if not journal: - raise osv.except_osv(_('Error!'), _("No expense journal found. Please make sure you have a journal with type 'purchase' configured.")) - if not journal.sequence_id: - raise osv.except_osv(_('Error!'), _('Please define sequence on the journal related to this invoice.')) - company_currency = exp.company_id.currency_id.id - current_currency = exp.currency_id -# for line in exp.line_ids: -# if line.product_id: -# acc = line.product_id.property_account_expense -# if not acc: -# acc = line.product_id.categ_id.property_account_expense_categ -# else: -# acc = property_obj.get(cr, uid, 'property_account_expense_categ', 'product.category', context={'force_company': company_id}) -# if not acc: -# raise osv.except_osv(_('Error!'), _('Please configure Default Expense account for Product purchase: `property_account_expense_categ`.')) -# total_amount = line.total_amount -# if journal.currency: -# if exp.currency_id != journal.currency: -# total_amount = currency_obj.compute(cr, uid, exp.currency_id.id, journal.currency.id, total_amount, context=ctx) -# elif exp.currency_id != exp.company_id.currency_id: -# total_amount = currency_obj.compute(cr, uid, exp.currency_id.id, exp.company_id.currency_id.id, total_amount, context=ctx) -# lines.append((0, False, { -# 'name': line.name, -# 'account_id': acc.id, -# 'account_analytic_id': line.analytic_account.id, -# 'amount': total_amount, -# 'type': 'dr' -# })) -# total += total_amount if not exp.employee_id.address_home_id: raise osv.except_osv(_('Error!'), _('The employee must have a home address.')) - acc = exp.employee_id.address_home_id.property_account_payable.id + company_currency = exp.company_id.currency_id.id + diff_currency_p = exp.currency_id.id <> company_currency - #From action_move_line_create of voucher - move_id = move_obj.create(cr, uid, self.account_move_get(cr, uid, exp.id, journal.id, context=context), context=context) - move = move_obj.browse(cr, uid, move_id, context=context) + #create the move that will contain the accounting entries + move_id = move_obj.create(cr, uid, self.account_move_get(cr, uid, exp.id, context=context), context=context) #iml = self._get_analytic_lines # within: iml = self.pool.get('account.invoice.line').move_line_get iml = self.move_line_get(cr, uid, exp.id, context=context) - - diff_currency_p = exp.currency_id.id <> company_currency # create one move line for the total - total = 0 - total_currency = 0 - total, total_currency, iml = self.compute_expense_totals(cr, uid, exp, company_currency, exp.name, iml, context=ctx) - - - #Need to have counterline: + total, total_currency, iml = self.compute_expense_totals(cr, uid, exp, company_currency, exp.name, iml, context=context) + #counterline with the total on payable account for the employee + acc = exp.employee_id.address_home_id.property_account_payable.id iml.append({ - 'type':'dest', - 'name':'/', - 'price':total, + 'type': 'dest', + 'name': '/', + 'price': total, 'account_id': acc, 'date_maturity': exp.date_confirm, 'amount_currency': diff_currency_p and total_currency or False, @@ -327,27 +257,10 @@ class hr_expense_expense(osv.osv): 'ref': exp.name }) - line = map(lambda x:(0,0,self.line_get_convert(cr, uid, x, exp.user_id.partner_id, exp.date_confirm, context=ctx)),iml) - move_obj.write(cr, uid, [move_id], {'line_id':line}, context=ctx) - self.write(cr, uid, ids, {'account_move_id':move_id, 'state':'done'}, context=context) - - - #compute_taxes = ait_obj.compute(cr, uid, , context=context) - - - -# return { -# 'type':'src', -# 'name':line.name.split('\n')[0][:64], -# 'price_unit':line.price_unit, -# 'quantity':line.quantity, -# 'price':line.price_subtotal, -# 'account_id':line.account_id.id, -# 'product_id':line.product_id.id, -# 'uos_id':line.uos_id.id, -# 'account_analytic_id':line.account_analytic_id.id, -# 'taxes':line.invoice_line_tax_id} - + lines = map(lambda x:(0,0,self.line_get_convert(cr, uid, x, exp.user_id.partner_id, exp.date_confirm, context=context)),iml) + move_obj.write(cr, uid, [move_id], {'line_id': lines}, context=context) + self.write(cr, uid, ids, {'account_move_id': move_id, 'state': 'done'}, context=context) + return True def move_line_get(self, cr, uid, expense_id, context=None): res = [] @@ -442,80 +355,11 @@ class hr_expense_expense(osv.osv): } - - - def action_receipt_create(self, cr, uid, ids, context=None): - property_obj = self.pool.get('ir.property') - sequence_obj = self.pool.get('ir.sequence') - analytic_journal_obj = self.pool.get('account.analytic.journal') - account_journal = self.pool.get('account.journal') - voucher_obj = self.pool.get('account.voucher') - currency_obj = self.pool.get('res.currency') - wkf_service = netsvc.LocalService("workflow") - if context is None: - context = {} - for exp in self.browse(cr, uid, ids, context=context): - company_id = exp.company_id.id - lines = [] - total = 0.0 - ctx = context.copy() - ctx.update({'date': exp.date}) - journal = False - if exp.journal_id: - journal = exp.journal_id - else: - journal_id = voucher_obj._get_journal(cr, uid, context={'type': 'purchase', 'company_id': company_id}) - if journal_id: - journal = account_journal.browse(cr, uid, journal_id, context=context) - if not journal: - raise osv.except_osv(_('Error!'), _("No expense journal found. Please make sure you have a journal with type 'purchase' configured.")) - for line in exp.line_ids: - if line.product_id: - acc = line.product_id.property_account_expense - if not acc: - acc = line.product_id.categ_id.property_account_expense_categ - else: - acc = property_obj.get(cr, uid, 'property_account_expense_categ', 'product.category', context={'force_company': company_id}) - if not acc: - raise osv.except_osv(_('Error!'), _('Please configure Default Expense account for Product purchase: `property_account_expense_categ`.')) - total_amount = line.total_amount - if journal.currency: - if exp.currency_id != journal.currency: - total_amount = currency_obj.compute(cr, uid, exp.currency_id.id, journal.currency.id, total_amount, context=ctx) - elif exp.currency_id != exp.company_id.currency_id: - total_amount = currency_obj.compute(cr, uid, exp.currency_id.id, exp.company_id.currency_id.id, total_amount, context=ctx) - lines.append((0, False, { - 'name': line.name, - 'account_id': acc.id, - 'account_analytic_id': line.analytic_account.id, - 'amount': total_amount, - 'type': 'dr' - })) - total += total_amount - if not exp.employee_id.address_home_id: - raise osv.except_osv(_('Error!'), _('The employee must have a home address.')) - acc = exp.employee_id.address_home_id.property_account_payable.id - voucher = { - 'name': exp.name or '/', - 'reference': sequence_obj.get(cr, uid, 'hr.expense.invoice'), - 'account_id': acc, - 'type': 'purchase', - 'partner_id': exp.employee_id.address_home_id.id, - 'company_id': company_id, - 'line_ids': lines, - 'amount': total, - 'journal_id': journal.id, - } - if journal and not journal.analytic_journal_id: - analytic_journal_ids = analytic_journal_obj.search(cr, uid, [('type','=','purchase')], context=context) - if analytic_journal_ids: - account_journal.write(cr, uid, [journal.id], {'analytic_journal_id': analytic_journal_ids[0]}, context=context) - voucher_id = voucher_obj.create(cr, uid, voucher, context=context) - self.write(cr, uid, [exp.id], {'voucher_id': voucher_id, 'state': 'done'}, context=context) - return True + raise osv.except_osv(_('Error!'), _('Deprecated function used')) def action_view_receipt(self, cr, uid, ids, context=None): + raise osv.except_osv(_('Error!'), _('Deprecated function used')) ''' This function returns an action that display existing receipt of given expense ids. ''' diff --git a/addons/hr_expense/hr_expense_view.xml b/addons/hr_expense/hr_expense_view.xml index 0324388786f..cb1a7408a29 100644 --- a/addons/hr_expense/hr_expense_view.xml +++ b/addons/hr_expense/hr_expense_view.xml @@ -133,6 +133,7 @@ + From d448390cafeeeadc470d1c84d77252e53483bf50 Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Wed, 6 Mar 2013 15:35:34 +0100 Subject: [PATCH 05/24] [FIX] hr_expense: mising coma in manifest bzr revid: qdp-launchpad@openerp.com-20130306143534-30vh1xl79eo6bf5c --- addons/hr_expense/__openerp__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/hr_expense/__openerp__.py b/addons/hr_expense/__openerp__.py index 1f4e7b42209..8eb7de957f8 100644 --- a/addons/hr_expense/__openerp__.py +++ b/addons/hr_expense/__openerp__.py @@ -46,7 +46,7 @@ This module also uses analytic accounting and is compatible with the invoice on 'author': 'OpenERP SA', 'website': 'http://www.openerp.com', 'images': ['images/hr_expenses_analysis.jpeg', 'images/hr_expenses.jpeg'], - 'depends': ['hr', 'account_voucher, account_accountant'], + 'depends': ['hr', 'account_voucher', 'account_accountant'], 'data': [ 'security/ir.model.access.csv', 'hr_expense_data.xml', From ee72f0953aec63c1f5f5444541a9075e0f3c9c43 Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Wed, 6 Mar 2013 15:38:37 +0100 Subject: [PATCH 06/24] [FIX] hr_expense: typo bzr revid: qdp-launchpad@openerp.com-20130306143837-gc7edztg71h5hi56 --- addons/hr_expense/hr_expense.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/hr_expense/hr_expense.py b/addons/hr_expense/hr_expense.py index 29570559c65..9196cba3d96 100644 --- a/addons/hr_expense/hr_expense.py +++ b/addons/hr_expense/hr_expense.py @@ -166,7 +166,7 @@ class hr_expense_expense(osv.osv): if not journal_id: raise osv.except_osv(_('Error!'), _("No expense journal found. Please make sure you have a journal with type 'purchase' configured.")) journal_id = journal_id[0] - return self.pool.get('account_move').account_move_prepare(cr, uid, journal_id, date=date, ref=ref, company_id=company_id, context=context) + return self.pool.get('account.move').account_move_prepare(cr, uid, journal_id, date=date, ref=ref, company_id=company_id, context=context) def line_get_convert(self, cr, uid, x, part, date, context=None): #partner_id = self.pool.get('res.partner')._find_partner(part) From fd54f58ccb7802af3aa8eff580affb29dceb9874 Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Wed, 6 Mar 2013 17:39:31 +0100 Subject: [PATCH 07/24] [IMP] hr_expense: now propose to open the account.move in form view thanks to a button in the expense form view bzr revid: qdp-launchpad@openerp.com-20130306163931-609cgn16xmcr0wot --- addons/hr_expense/hr_expense.py | 25 +++++++++++++------------ addons/hr_expense/hr_expense_view.xml | 2 +- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/addons/hr_expense/hr_expense.py b/addons/hr_expense/hr_expense.py index 9196cba3d96..cd11d19ff17 100644 --- a/addons/hr_expense/hr_expense.py +++ b/addons/hr_expense/hr_expense.py @@ -145,6 +145,9 @@ class hr_expense_expense(osv.osv): def expense_canceled(self, cr, uid, ids, context=None): return self.write(cr, uid, ids, {'state': 'cancelled'}, context=context) + def action_receipt_create(self, cr, uid, ids, context=None): + raise osv.except_osv(_('Error!'), _('Deprecated function used')) + def account_move_get(self, cr, uid, expense_id, context=None): ''' This method prepare the creation of the account move related to the given expense. @@ -354,28 +357,26 @@ class hr_expense_expense(osv.osv): #'taxes':line.invoice_line_tax_id, } - - def action_receipt_create(self, cr, uid, ids, context=None): - raise osv.except_osv(_('Error!'), _('Deprecated function used')) - - def action_view_receipt(self, cr, uid, ids, context=None): - raise osv.except_osv(_('Error!'), _('Deprecated function used')) + def action_view_move(self, cr, uid, ids, context=None): ''' - This function returns an action that display existing receipt of given expense ids. + This function returns an action that display existing account.move of given expense ids. ''' assert len(ids) == 1, 'This option should only be used for a single id at a time' voucher_id = self.browse(cr, uid, ids[0], context=context).voucher_id.id - res = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'account_voucher', 'view_purchase_receipt_form') + try: + dummy, view_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'account', 'view_move_form') + except: + view_id = False result = { - 'name': _('Expense Receipt'), + 'name': _('Expense Account Move'), 'view_type': 'form', 'view_mode': 'form', - 'view_id': res and res[1] or False, - 'res_model': 'account.voucher', + 'view_id': view_id, + 'res_model': 'account.move', 'type': 'ir.actions.act_window', 'nodestroy': True, 'target': 'current', - 'res_id': voucher_id, + 'res_id': account_move_id, } return result diff --git a/addons/hr_expense/hr_expense_view.xml b/addons/hr_expense/hr_expense_view.xml index cb1a7408a29..3ee97ba3a0e 100644 --- a/addons/hr_expense/hr_expense_view.xml +++ b/addons/hr_expense/hr_expense_view.xml @@ -67,7 +67,7 @@