[MERGE] merged the branch with refactoring of method action_move_line_create on account voucher

bzr revid: qdp-launchpad@openerp.com-20111017101015-4h2m4ovaoo6z71mr
This commit is contained in:
Quentin (OpenERP) 2011-10-17 12:10:15 +02:00
commit 8b5e5f8b32
1 changed files with 323 additions and 188 deletions

View File

@ -651,13 +651,302 @@ class account_voucher(osv.osv):
res['account_id'] = account_id
return {'value':res}
def _sel_context(self, cr, uid, voucher_id,context=None):
"""
Select the context to use accordingly if it needs to be multicurrency or not.
:param voucher_id: Id of the actual voucher
:return: The returned context will be the same as given in parameter if the voucher currency is the same
than the company currency, otherwise it's a copy of the parameter with an extra key 'date' containing
the date of the voucher.
:rtype: dict
"""
company_currency = self._get_company_currency(cr, uid, voucher_id, context)
current_currency = self._get_current_currency(cr, uid, voucher_id, context)
if current_currency <> company_currency:
context_multi_currency = context.copy()
voucher_brw = self.pool.get('account.voucher').browse(cr, uid, voucher_id, context)
context_multi_currency.update({'date': voucher_brw.date})
return context_multi_currency
return context
def first_move_line_get(self, cr, uid, voucher_id, move_id, company_currency, current_currency, context=None):
'''
Return a dict to be use to create the first account move line of given voucher.
:param voucher_id: Id of voucher what we are creating account_move.
:param move_id: Id of account move where this line will be added.
:param company_currency: id of currency of the company to which the voucher belong
:param current_currency: id of currency of the voucher
:return: mapping between fieldname and value of account move line to create
:rtype: dict
'''
move_line_obj = self.pool.get('account.move.line')
currency_obj = self.pool.get('res.currency')
voucher_brw = self.pool.get('account.voucher').browse(cr,uid,voucher_id,context)
debit = credit = 0.0
# TODO: is there any other alternative then the voucher type ??
# ANSWER: We can have payment and receipt "In Advance".
# TODO: Make this logic available.
# -for sale, purchase we have but for the payment and receipt we do not have as based on the bank/cash journal we can not know its payment or receipt
if voucher_brw.type in ('purchase', 'payment'):
credit = currency_obj.compute(cr, uid, current_currency, company_currency, voucher_brw.amount, context=context)
elif voucher_brw.type in ('sale', 'receipt'):
debit = currency_obj.compute(cr, uid, current_currency, company_currency, voucher_brw.amount, context=context)
if debit < 0: credit = -debit; debit = 0.0
if credit < 0: debit = -credit; credit = 0.0
sign = debit - credit < 0 and -1 or 1
#set the first line of the voucher
move_line = {
'name': voucher_brw.name or '/',
'debit': debit,
'credit': credit,
'account_id': voucher_brw.account_id.id,
'move_id': move_id,
'journal_id': voucher_brw.journal_id.id,
'period_id': voucher_brw.period_id.id,
'partner_id': voucher_brw.partner_id.id,
'currency_id': company_currency <> current_currency and current_currency or False,
'amount_currency': company_currency <> current_currency and sign * voucher_brw.amount or 0.0,
'date': voucher_brw.date,
'date_maturity': voucher_brw.date_due
}
return move_line
def account_move_get(self, cr, uid, voucher_id, context=None):
'''
This method prepare the creation of the account move related to the given voucher.
:param voucher_id: Id of voucher for which we are creating account_move.
:return: mapping between fieldname and value of account move to create
:rtype: dict
'''
move_obj = self.pool.get('account.move')
seq_obj = self.pool.get('ir.sequence')
voucher_brw = self.pool.get('account.voucher').browse(cr,uid,voucher_id,context)
if voucher_brw.number:
name = voucher_brw.number
elif voucher_brw.journal_id.sequence_id:
name = seq_obj.next_by_id(cr, uid, voucher_brw.journal_id.sequence_id.id)
else:
raise osv.except_osv(_('Error !'),
_('Please define a sequence on the journal !'))
if not voucher_brw.reference:
ref = name.replace('/','')
else:
ref = voucher_brw.reference
move = {
'name': name,
'journal_id': voucher_brw.journal_id.id,
'narration': voucher_brw.narration,
'date': voucher_brw.date,
'ref': ref,
'period_id': voucher_brw.period_id and voucher_brw.period_id.id or False
}
return move
def _get_exchange_lines(self, cr, uid, line, move_id, amount_residual, company_currency, current_currency, context=None):
'''
Prepare the two lines due to currency rate difference.
:param line: browse record of the voucher.line for which we want to create currency rate difference accounting entries
:param move_id: Account move wher the move lines will be.
:param amount_residual: Amount to be posted.
:param company_currency: id of currency of the company to which the voucher belong
:param current_currency: id of currency of the voucher
:return: the account move line and its counterpart to create, depicted as mapping between fieldname and value
:rtype: tuple of dict
'''
if not line.voucher_id.exchange_acc_id.id:
raise osv.except_osv(_('Error!'), _('You must provide an account for the exchange difference.'))
move_line = {
'journal_id': line.voucher_id.journal_id.id,
'period_id': line.voucher_id.period_id.id,
'name': _('change')+': '+(line.name or '/'),
'account_id': line.account_id.id,
'move_id': move_id,
'partner_id': line.voucher_id.partner_id.id,
'currency_id': company_currency <> current_currency and current_currency or False,
'amount_currency': 0.0,
'quantity': 1,
'credit': amount_residual > 0 and amount_residual or 0.0,
'debit': amount_residual < 0 and -amount_residual or 0.0,
'date': line.voucher_id.date,
}
move_line_counterpart = {
'journal_id': line.voucher_id.journal_id.id,
'period_id': line.voucher_id.period_id.id,
'name': _('change')+': '+(line.name or '/'),
'account_id': line.voucher_id.exchange_acc_id.id,
'move_id': move_id,
'amount_currency': 0.0,
'partner_id': line.voucher_id.partner_id.id,
'currency_id': company_currency <> current_currency and current_currency or False,
'quantity': 1,
'debit': amount_residual > 0 and amount_residual or 0.0,
'credit': amount_residual < 0 and -amount_residual or 0.0,
'date': line.voucher_id.date,
}
return (move_line, move_line_counterpart)
def voucher_move_line_create(self, cr, uid, voucher_id, line_total, move_id, company_currency, current_currency, context=None):
'''
Create one account move line, on the given account move, per voucher line where amount is not 0.0.
It returns Tuple with tot_line what is total of difference between debit and credit and
a list of lists with ids to be reconciled with this format (total_deb_cred,list_of_lists).
:param voucher_id: Voucher id what we are working with
:param line_total: Amount of the first line, which correspond to the amount we should totally split among all voucher lines.
:param move_id: Account move wher those lines will be joined.
:param company_currency: id of currency of the company to which the voucher belong
:param current_currency: id of currency of the voucher
:return: Tuple build as (remaining amount not allocated on voucher lines, list of account_move_line created in this method)
:rtype: tuple(int, list of int)
'''
move_line_obj = self.pool.get('account.move.line')
currency_obj = self.pool.get('res.currency')
tot_line = line_total
rec_lst_ids = []
voucher_brw = self.pool.get('account.voucher').browse(cr,uid,voucher_id,context)
for line in voucher_brw.line_ids:
#create one move line per voucher line where amount is not 0.0
if not line.amount:
continue
#we check if the voucher line is fully paid or not and create a move line to balance the payment and initial invoice if needed
if line.amount == line.amount_unreconciled:
amount = currency_obj.compute(cr, uid, current_currency, company_currency, line.untax_amount or line.amount, context=context)
amount_residual = line.move_line_id.amount_residual - amount #residual amount in company currency
else:
amount = currency_obj.compute(cr, uid, current_currency, company_currency, line.untax_amount or line.amount, context=context)
amount_residual = 0.0
move_line = {
'journal_id': voucher_brw.journal_id.id,
'period_id': voucher_brw.period_id.id,
'name': line.name or '/',
'account_id': line.account_id.id,
'move_id': move_id,
'partner_id': voucher_brw.partner_id.id,
'currency_id': company_currency <> current_currency and current_currency or False,
'analytic_account_id': line.account_analytic_id and line.account_analytic_id.id or False,
'quantity': 1,
'credit': 0.0,
'debit': 0.0,
'date': voucher_brw.date
}
if amount < 0:
amount = -amount
if line.type == 'dr':
line.type = 'cr'
else:
line.type = 'dr'
if (line.type=='dr'):
tot_line += amount
move_line['debit'] = amount
else:
tot_line -= amount
move_line['credit'] = amount
if voucher_brw.tax_id and voucher_brw.type in ('sale', 'purchase'):
move_line.update({
'account_tax_id': voucher_brw.tax_id.id,
})
if move_line.get('account_tax_id', False):
tax_data = tax_obj.browse(cr, uid, [move_line['account_tax_id']], context=context)[0]
if not (tax_data.base_code_id and tax_data.tax_code_id):
raise osv.except_osv(_('No Account Base Code and Account Tax Code!'),_("You have to configure account base code and account tax code on the '%s' tax!") % (tax_data.name))
sign = (move_line['debit'] - move_line['credit']) < 0 and -1 or 1
move_line['amount_currency'] = company_currency <> current_currency and sign * line.amount or False
voucher_line = move_line_obj.create(cr, uid, move_line)
rec_ids = [voucher_line, line.move_line_id.id]
if amount_residual:
# Change difference entry
exch_lines = self._get_exchange_lines(cr, uid, line, move_id, amount_residual, company_currency, current_currency, context=context)
new_id = move_line_obj.create(cr, uid, exch_lines[0],context)
move_line_obj.create(cr, uid, exch_lines[1], context)
rec_ids.append(new_id)
if line.move_line_id.id:
rec_lst_ids.append(rec_ids)
return (tot_line, rec_lst_ids)
def writeoff_move_line_get(self, cr, uid, voucher_id, line_total, move_id, name, company_currency, current_currency, context=None):
'''
Set a dict to be use to create the writeoff move line.
:param voucher_id: Id of voucher what we are creating account_move.
:param line_total: Amount remaining to be allocated on lines.
:param move_id: Id of account move where this line will be added.
:param name: Description of account move line.
:param company_currency: id of currency of the company to which the voucher belong
:param current_currency: id of currency of the voucher
:return: mapping between fieldname and value of account move line to create
:rtype: dict
'''
move_line_obj = self.pool.get('account.move.line')
currency_obj = self.pool.get('res.currency')
move_line = {}
voucher_brw = self.pool.get('account.voucher').browse(cr,uid,voucher_id,context)
current_currency_obj = voucher_brw.currency_id or voucher_brw.journal_id.company_id.currency_id
if not currency_obj.is_zero(cr, uid, current_currency_obj, line_total):
diff = line_total
account_id = False
write_off_name = ''
if voucher_brw.payment_option == 'with_writeoff':
account_id = voucher_brw.writeoff_acc_id.id
write_off_name = voucher_brw.comment
elif voucher_brw.type in ('sale', 'receipt'):
account_id = voucher_brw.partner_id.property_account_receivable.id
else:
account_id = voucher_brw.partner_id.property_account_payable.id
move_line = {
'name': write_off_name or name,
'account_id': account_id,
'move_id': move_id,
'partner_id': voucher_brw.partner_id.id,
'date': voucher_brw.date,
'credit': diff > 0 and diff or 0.0,
'debit': diff < 0 and -diff or 0.0,
'amount_currency': company_currency <> current_currency and voucher_brw.writeoff_amount or False,
'currency_id': company_currency <> current_currency and current_currency or False,
}
return move_line
def _get_company_currency(self, cr, uid, voucher_id, context=None):
'''
Get the currency of the actual company.
:param voucher_id: Id of the voucher what i want to obtain company currency.
:return: currency id of the company of the voucher
:rtype: int
'''
return self.pool.get('account.voucher').browse(cr,uid,voucher_id,context).journal_id.company_id.currency_id.id
def _get_current_currency(self, cr, uid, voucher_id, context=None):
'''
Get the currency of the voucher.
:param voucher_id: Id of the voucher what i want to obtain current currency.
:return: currency id of the voucher
:rtype: int
'''
voucher = self.pool.get('account.voucher').browse(cr,uid,voucher_id,context)
return voucher.currency_id.id or self._get_company_currency(cr,uid,voucher.id,context)
def action_move_line_create(self, cr, uid, ids, context=None):
def _get_payment_term_lines(term_id, amount):
term_pool = self.pool.get('account.payment.term')
if term_id and amount:
terms = term_pool.compute(cr, uid, term_id, amount)
return terms
return False
'''
Confirm the vouchers given in ids and create the journal entries for each of them
'''
if context is None:
context = {}
move_pool = self.pool.get('account.move')
@ -665,198 +954,44 @@ class account_voucher(osv.osv):
currency_pool = self.pool.get('res.currency')
tax_obj = self.pool.get('account.tax')
seq_obj = self.pool.get('ir.sequence')
for inv in self.browse(cr, uid, ids, context=context):
if inv.move_id:
for voucher in self.browse(cr, uid, ids, context=context):
if voucher.move_id:
continue
context_multi_currency = context.copy()
context_multi_currency.update({'date': inv.date})
if inv.number:
name = inv.number
elif inv.journal_id.sequence_id:
name = seq_obj.next_by_id(cr, uid, inv.journal_id.sequence_id.id)
else:
raise osv.except_osv(_('Error !'), _('Please define a sequence on the journal !'))
if not inv.reference:
ref = name.replace('/','')
else:
ref = inv.reference
move = {
'name': name,
'journal_id': inv.journal_id.id,
'narration': inv.narration,
'date': inv.date,
'ref': ref,
'period_id': inv.period_id and inv.period_id.id or False
}
move_id = move_pool.create(cr, uid, move)
#create the first line manually
company_currency = inv.journal_id.company_id.currency_id.id
current_currency = inv.currency_id.id or company_currency
current_currency_obj = inv.currency_id or inv.journal_id.company_id.currency_id
debit = 0.0
credit = 0.0
# TODO: is there any other alternative then the voucher type ??
# -for sale, purchase we have but for the payment and receipt we do not have as based on the bank/cash journal we can not know its payment or receipt
if inv.type in ('purchase', 'payment'):
credit = currency_pool.compute(cr, uid, current_currency, company_currency, inv.amount, context=context_multi_currency)
elif inv.type in ('sale', 'receipt'):
debit = currency_pool.compute(cr, uid, current_currency, company_currency, inv.amount, context=context_multi_currency)
if debit < 0:
credit = -debit
debit = 0.0
if credit < 0:
debit = -credit
credit = 0.0
sign = debit - credit < 0 and -1 or 1
#create the first line of the voucher, the payment made
move_line = {
'name': inv.name or '/',
'debit': debit,
'credit': credit,
'account_id': inv.account_id.id,
'move_id': move_id,
'journal_id': inv.journal_id.id,
'period_id': inv.period_id.id,
'partner_id': inv.partner_id.id,
'currency_id': company_currency <> current_currency and current_currency or False,
'amount_currency': company_currency <> current_currency and sign * inv.amount or 0.0,
'date': inv.date,
'date_maturity': inv.date_due
}
move_line_pool.create(cr, uid, move_line)
company_currency = self._get_company_currency(cr, uid, voucher.id, context)
current_currency = self._get_current_currency(cr, uid, voucher.id, context)
context = self._sel_context(cr, uid, voucher.id, context)
#Create the account move record.
move_id = move_pool.create(cr, uid, self.account_move_get(cr, uid, voucher.id, context=context), context=context)
# Get the name of the account_move just created
name = move_pool.browse(cr, uid, move_id, context=context).name
#Create the first line of the voucher
move_line_id = move_line_pool.create(cr, uid, self.first_move_line_get(cr,uid,voucher.id, move_id, company_currency, current_currency, context), context)
move_line_brw = move_line_pool.browse(cr, uid, move_line_id, context=context)
line_total = move_line_brw.debit - move_line_brw.credit
rec_list_ids = []
line_total = debit - credit
if inv.type == 'sale':
line_total = line_total - currency_pool.compute(cr, uid, current_currency, company_currency, inv.tax_amount, context=context_multi_currency)
elif inv.type == 'purchase':
line_total = line_total + currency_pool.compute(cr, uid, current_currency, company_currency, inv.tax_amount, context=context_multi_currency)
if voucher.type == 'sale':
line_total = line_total - currency_pool.compute(cr, uid, current_currency, company_currency, voucher.tax_amount, context=context)
elif voucher.type == 'purchase':
line_total = line_total + currency_pool.compute(cr, uid, current_currency, company_currency, voucher.tax_amount, context=context)
#create one move line per voucher line where amount is not 0.0
line_total, rec_list_ids = self.voucher_move_line_create(cr, uid, voucher.id, line_total, move_id, company_currency, current_currency, context)
for line in inv.line_ids:
#create one move line per voucher line where amount is not 0.0
if not line.amount:
continue
#we check if the voucher line is fully paid or not and create a move line to balance the payment and initial invoice if needed
if line.amount == line.amount_unreconciled:
amount = currency_pool.compute(cr, uid, current_currency, company_currency, line.untax_amount or line.amount, context=context_multi_currency)
amount_residual = line.move_line_id.amount_residual - amount #residual amount in company currency
else:
amount = currency_pool.compute(cr, uid, current_currency, company_currency, line.untax_amount or line.amount, context=context_multi_currency)
amount_residual = 0.0
move_line = {
'journal_id': inv.journal_id.id,
'period_id': inv.period_id.id,
'name': line.name or '/',
'account_id': line.account_id.id,
'move_id': move_id,
'partner_id': inv.partner_id.id,
'currency_id': company_currency <> current_currency and current_currency or False,
'analytic_account_id': line.account_analytic_id and line.account_analytic_id.id or False,
'quantity': 1,
'credit': 0.0,
'debit': 0.0,
'date': inv.date
}
if amount < 0:
amount = -amount
if line.type == 'dr':
line.type = 'cr'
else:
line.type = 'dr'
if (line.type=='dr'):
line_total += amount
move_line['debit'] = amount
else:
line_total -= amount
move_line['credit'] = amount
if inv.tax_id and inv.type in ('sale', 'purchase'):
move_line.update({
'account_tax_id': inv.tax_id.id,
})
if move_line.get('account_tax_id', False):
tax_data = tax_obj.browse(cr, uid, [move_line['account_tax_id']], context=context)[0]
if not (tax_data.base_code_id and tax_data.tax_code_id):
raise osv.except_osv(_('No Account Base Code and Account Tax Code!'),_("You have to configure account base code and account tax code on the '%s' tax!") % (tax_data.name))
sign = (move_line['debit'] - move_line['credit']) < 0 and -1 or 1
move_line['amount_currency'] = company_currency <> current_currency and sign * line.amount or False
voucher_line = move_line_pool.create(cr, uid, move_line)
rec_ids = [voucher_line, line.move_line_id.id]
# Change difference entry
if amount_residual:
if not inv.exchange_acc_id.id:
raise osv.except_osv(_('Error!'), _('You must provide an account for the exchange difference.'))
move_line = {
'journal_id': inv.journal_id.id,
'period_id': inv.period_id.id,
'name': _('change')+': '+(line.name or '/'),
'account_id': line.account_id.id,
'move_id': move_id,
'partner_id': inv.partner_id.id,
'currency_id': company_currency <> current_currency and current_currency or False,
'amount_currency': 0.0,
'quantity': 1,
'credit': amount_residual > 0 and amount_residual or 0.0,
'debit': amount_residual < 0 and -amount_residual or 0.0,
'date': inv.date
}
new_id = move_line_pool.create(cr, uid, move_line)
move_line = {
'journal_id': inv.journal_id.id,
'period_id': inv.period_id.id,
'name': _('change')+': '+(line.name or '/'),
'account_id': inv.exchange_acc_id.id,
'move_id': move_id,
'amount_currency': 0.0,
'partner_id': inv.partner_id.id,
'currency_id': company_currency <> current_currency and current_currency or False,
'quantity': 1,
'debit': amount_residual > 0 and amount_residual or 0.0,
'credit': amount_residual < 0 and -amount_residual or 0.0,
'date': inv.date
}
move_line_pool.create(cr, uid, move_line)
rec_ids.append(new_id)
if line.move_line_id.id:
rec_list_ids.append(rec_ids)
if not currency_pool.is_zero(cr, uid, current_currency_obj, line_total):
diff = line_total
account_id = False
write_off_name = ''
if inv.payment_option == 'with_writeoff':
account_id = inv.writeoff_acc_id.id
write_off_name = inv.comment
elif inv.type in ('sale', 'receipt'):
account_id = inv.partner_id.property_account_receivable.id
else:
account_id = inv.partner_id.property_account_payable.id
move_line = {
'name': write_off_name or name,
'account_id': account_id,
'move_id': move_id,
'partner_id': inv.partner_id.id,
'date': inv.date,
'credit': diff > 0 and diff or 0.0,
'debit': diff < 0 and -diff or 0.0,
'amount_currency': company_currency <> current_currency and inv.writeoff_amount or False,
'currency_id': company_currency <> current_currency and current_currency or False,
}
move_line_pool.create(cr, uid, move_line)
self.write(cr, uid, [inv.id], {
#create the writeoff line if needed
ml_writeoff = self.writeoff_move_line_get(cr, uid, voucher.id, line_total, move_id, name, company_currency, current_currency, context)
if ml_writeoff:
ml_writeoff_id = move_line_pool.create(cr, uid, ml_writeoff, context)
#We post the voucher.
self.write(cr, uid, [voucher.id], {
'move_id': move_id,
'state': 'posted',
'number': name,
})
if inv.journal_id.entry_posted:
if voucher.journal_id.entry_posted:
move_pool.post(cr, uid, [move_id], context={})
#We automatically reconcile the account move lines.
for rec_ids in rec_list_ids:
if len(rec_ids) >= 2:
move_line_pool.reconcile_partial(cr, uid, rec_ids, writeoff_acc_id=inv.exchange_acc_id.id, writeoff_period_id=inv.period_id.id, writeoff_journal_id=inv.journal_id.id)
move_line_pool.reconcile_partial(cr, uid, rec_ids, writeoff_acc_id=voucher.exchange_acc_id.id, writeoff_period_id=voucher.period_id.id, writeoff_journal_id=voucher.journal_id.id)
return True
def copy(self, cr, uid, id, default={}, context=None):