272 lines
14 KiB
Python
272 lines
14 KiB
Python
from openerp.tests.common import TransactionCase
|
|
import time
|
|
|
|
class TestReconciliation(TransactionCase):
|
|
"""Tests for reconciliation (account.tax)
|
|
|
|
Test used to check that when doing a sale or purchase invoice in a different currency,
|
|
the result will be balanced.
|
|
"""
|
|
|
|
def setUp(self):
|
|
super(TestReconciliation, self).setUp()
|
|
self.account_invoice_model = self.registry('account.invoice')
|
|
self.account_invoice_line_model = self.registry('account.invoice.line')
|
|
self.acc_bank_stmt_model = self.registry('account.bank.statement')
|
|
self.acc_bank_stmt_line_model = self.registry('account.bank.statement.line')
|
|
self.res_currency_model = self.registry('res.currency')
|
|
self.res_currency_rate_model = self.registry('res.currency.rate')
|
|
|
|
self.partner_agrolait_id = self.registry("ir.model.data").get_object_reference(self.cr, self.uid, "base", "res_partner_2")[1]
|
|
self.currency_swiss_id = self.registry("ir.model.data").get_object_reference(self.cr, self.uid, "base", "CHF")[1]
|
|
self.currency_usd_id = self.registry("ir.model.data").get_object_reference(self.cr, self.uid, "base", "USD")[1]
|
|
self.account_rcv_id = self.registry("ir.model.data").get_object_reference(self.cr, self.uid, "account", "a_recv")[1]
|
|
self.account_fx_income_id = self.registry("ir.model.data").get_object_reference(self.cr, self.uid, "account", "income_fx_income")[1]
|
|
self.account_fx_expense_id = self.registry("ir.model.data").get_object_reference(self.cr, self.uid, "account", "income_fx_expense")[1]
|
|
|
|
self.product_id = self.registry("ir.model.data").get_object_reference(self.cr, self.uid, "product", "product_product_4")[1]
|
|
|
|
self.bank_journal_usd_id = self.registry("ir.model.data").get_object_reference(self.cr, self.uid, "account", "bank_journal_usd")[1]
|
|
self.account_usd_id = self.registry("ir.model.data").get_object_reference(self.cr, self.uid, "account", "usd_bnk")[1]
|
|
|
|
self.company_id = self.registry("ir.model.data").get_object_reference(self.cr, self.uid, "base", "main_company")[1]
|
|
|
|
#set expense_currency_exchange_account_id and income_currency_exchange_account_id to the according accounts
|
|
self.registry("res.company").write(self.cr, self.uid, [self.company_id], {'expense_currency_exchange_account_id': self.account_fx_expense_id, 'income_currency_exchange_account_id':self.account_fx_income_id})
|
|
|
|
def test_balanced_customer_invoice(self):
|
|
cr, uid = self.cr, self.uid
|
|
#we create an invoice in CHF
|
|
invoice_id = self.account_invoice_model.create(cr, uid, {'partner_id': self.partner_agrolait_id,
|
|
'reference_type': 'none',
|
|
'currency_id': self.currency_swiss_id,
|
|
'name': 'invoice to client',
|
|
'account_id': self.account_rcv_id,
|
|
'type': 'out_invoice',
|
|
'date_invoice': time.strftime('%Y')+'-07-01', # to use USD rate rateUSDbis
|
|
})
|
|
self.account_invoice_line_model.create(cr, uid, {'product_id': self.product_id,
|
|
'quantity': 1,
|
|
'price_unit': 100,
|
|
'invoice_id': invoice_id,
|
|
'name': 'product that cost 100',})
|
|
|
|
#validate purchase
|
|
self.registry('account.invoice').signal_workflow(cr, uid, [invoice_id], 'invoice_open')
|
|
invoice_record = self.account_invoice_model.browse(cr, uid, [invoice_id])
|
|
|
|
#we pay half of it on a journal with currency in dollar (bank statement)
|
|
bank_stmt_id = self.acc_bank_stmt_model.create(cr, uid, {
|
|
'journal_id': self.bank_journal_usd_id,
|
|
'date': time.strftime('%Y')+'-07-15',
|
|
})
|
|
|
|
bank_stmt_line_id = self.acc_bank_stmt_line_model.create(cr, uid, {'name': 'half payment',
|
|
'statement_id': bank_stmt_id,
|
|
'partner_id': self.partner_agrolait_id,
|
|
'amount': 42,
|
|
'amount_currency': 50,
|
|
'currency_id': self.currency_swiss_id,
|
|
'date': time.strftime('%Y')+'-07-15',})
|
|
|
|
#reconcile the payment with the invoice
|
|
for l in invoice_record.move_id.line_id:
|
|
if l.account_id.id == self.account_rcv_id:
|
|
line_id = l
|
|
break
|
|
self.acc_bank_stmt_line_model.process_reconciliation(cr, uid, bank_stmt_line_id, [
|
|
{'counterpart_move_line_id': line_id.id, 'credit':50, 'debit':0, 'name': line_id.name,}])
|
|
|
|
#we check that the line is balanced (bank statement line)
|
|
move_line_ids = self.acc_bank_stmt_model.browse(cr,uid,bank_stmt_id).move_line_ids
|
|
|
|
self.assertEquals(len(move_line_ids), 3)
|
|
checked_line = 0
|
|
for move_line in move_line_ids:
|
|
if move_line.account_id.id == self.account_usd_id:
|
|
self.assertEquals(move_line.debit, 27.47)
|
|
self.assertEquals(move_line.credit, 0.0)
|
|
self.assertEquals(move_line.amount_currency, 42)
|
|
self.assertEquals(move_line.currency_id.id, self.currency_usd_id)
|
|
checked_line += 1
|
|
continue
|
|
if move_line.account_id.id == self.account_rcv_id:
|
|
self.assertEquals(move_line.debit, 0.0)
|
|
self.assertEquals(move_line.credit, 38.21)
|
|
self.assertEquals(move_line.amount_currency, -50)
|
|
self.assertEquals(move_line.currency_id.id, self.currency_swiss_id)
|
|
checked_line += 1
|
|
continue
|
|
if move_line.account_id.id == self.account_fx_expense_id:
|
|
self.assertEquals(move_line.debit, 10.74)
|
|
self.assertEquals(move_line.credit, 0.0)
|
|
checked_line += 1
|
|
continue
|
|
self.assertEquals(checked_line, 3)
|
|
|
|
|
|
|
|
def test_balanced_supplier_invoice(self):
|
|
cr, uid = self.cr, self.uid
|
|
#we create a supplier invoice in CHF
|
|
invoice_id = self.account_invoice_model.create(cr, uid, {'partner_id': self.partner_agrolait_id,
|
|
'reference_type': 'none',
|
|
'currency_id': self.currency_swiss_id,
|
|
'name': 'invoice to client',
|
|
'account_id': self.account_rcv_id,
|
|
'type': 'in_invoice',
|
|
'date_invoice': time.strftime('%Y')+'-07-01',
|
|
})
|
|
self.account_invoice_line_model.create(cr, uid, {'product_id': self.product_id,
|
|
'quantity': 1,
|
|
'price_unit': 100,
|
|
'invoice_id': invoice_id,
|
|
'name': 'product that cost 100',})
|
|
|
|
#validate purchase
|
|
self.registry('account.invoice').signal_workflow(cr, uid, [invoice_id], 'invoice_open')
|
|
invoice_record = self.account_invoice_model.browse(cr, uid, [invoice_id])
|
|
|
|
#we pay half of it on a journal with currency in dollar (bank statement)
|
|
bank_stmt_id = self.acc_bank_stmt_model.create(cr, uid, {
|
|
'journal_id': self.bank_journal_usd_id,
|
|
'date': time.strftime('%Y')+'-07-15',
|
|
})
|
|
|
|
bank_stmt_line_id = self.acc_bank_stmt_line_model.create(cr, uid, {'name': 'half payment',
|
|
'statement_id': bank_stmt_id,
|
|
'partner_id': self.partner_agrolait_id,
|
|
'amount': -42,
|
|
'amount_currency': -50,
|
|
'currency_id': self.currency_swiss_id,
|
|
'date': time.strftime('%Y')+'-07-15',})
|
|
|
|
#reconcile the payment with the invoice
|
|
for l in invoice_record.move_id.line_id:
|
|
if l.account_id.id == self.account_rcv_id:
|
|
line_id = l
|
|
break
|
|
self.acc_bank_stmt_line_model.process_reconciliation(cr, uid, bank_stmt_line_id, [
|
|
{'counterpart_move_line_id': line_id.id, 'credit':0, 'debit':50, 'name': line_id.name,}])
|
|
|
|
#we check that the line is balanced (bank statement line)
|
|
move_line_ids = self.acc_bank_stmt_model.browse(cr,uid,bank_stmt_id).move_line_ids
|
|
|
|
self.assertEquals(len(move_line_ids), 3)
|
|
checked_line = 0
|
|
for move_line in move_line_ids:
|
|
if move_line.account_id.id == self.account_usd_id:
|
|
self.assertEquals(move_line.debit, 0.0)
|
|
self.assertEquals(move_line.credit, 27.47)
|
|
self.assertEquals(move_line.amount_currency, -42)
|
|
self.assertEquals(move_line.currency_id.id, self.currency_usd_id)
|
|
checked_line += 1
|
|
continue
|
|
if move_line.account_id.id == self.account_rcv_id:
|
|
self.assertEquals(move_line.debit, 38.21)
|
|
self.assertEquals(move_line.credit, 0.0)
|
|
self.assertEquals(move_line.amount_currency, 50)
|
|
self.assertEquals(move_line.currency_id.id, self.currency_swiss_id)
|
|
checked_line += 1
|
|
continue
|
|
if move_line.account_id.id == self.account_fx_income_id:
|
|
self.assertEquals(move_line.debit, 0.0)
|
|
self.assertEquals(move_line.credit, 10.74)
|
|
checked_line += 1
|
|
continue
|
|
self.assertEquals(checked_line, 3)
|
|
|
|
def test_balanced_exchanges_gain_loss(self):
|
|
# The point of this test is to show that we handle correctly the gain/loss exchanges during reconciliations in foreign currencies.
|
|
# For instance, with a company set in EUR, and a USD rate set to 0.033,
|
|
# the reconciliation of an invoice of 2.00 USD (60.61 EUR) and a bank statement of two lines of 1.00 USD (30.30 EUR)
|
|
# will lead to an exchange loss, that should be handled correctly within the journal items.
|
|
cr, uid = self.cr, self.uid
|
|
# We update the currency rate of the currency USD in order to force the gain/loss exchanges in next steps
|
|
rateUSDbis_id = self.registry("ir.model.data").get_object_reference(self.cr, self.uid, "base", "rateUSDbis")[1]
|
|
self.res_currency_rate_model.write(cr, uid, rateUSDbis_id, {
|
|
'name': time.strftime('%Y-%m-%d') + ' 00:00:00',
|
|
'rate': 0.033,
|
|
})
|
|
# We create a customer invoice of 2.00 USD
|
|
invoice_id = self.account_invoice_model.create(cr, uid, {
|
|
'partner_id': self.partner_agrolait_id,
|
|
'currency_id': self.currency_usd_id,
|
|
'name': 'Foreign invoice with exchange gain',
|
|
'account_id': self.account_rcv_id,
|
|
'type': 'out_invoice',
|
|
'date_invoice': time.strftime('%Y-%m-%d'),
|
|
'journal_id': self.bank_journal_usd_id,
|
|
'invoice_line': [
|
|
(0, 0, {
|
|
'name': 'line that will lead to an exchange gain',
|
|
'quantity': 1,
|
|
'price_unit': 2,
|
|
})
|
|
]
|
|
})
|
|
self.registry('account.invoice').signal_workflow(cr, uid, [invoice_id], 'invoice_open')
|
|
invoice = self.account_invoice_model.browse(cr, uid, invoice_id)
|
|
# We create a bank statement with two lines of 1.00 USD each.
|
|
bank_stmt_id = self.acc_bank_stmt_model.create(cr, uid, {
|
|
'journal_id': self.bank_journal_usd_id,
|
|
'date': time.strftime('%Y-%m-%d'),
|
|
'line_ids': [
|
|
(0, 0, {
|
|
'name': 'half payment',
|
|
'partner_id': self.partner_agrolait_id,
|
|
'amount': 1.0,
|
|
'date': time.strftime('%Y-%m-%d')
|
|
}),
|
|
(0, 0, {
|
|
'name': 'second half payment',
|
|
'partner_id': self.partner_agrolait_id,
|
|
'amount': 1.0,
|
|
'date': time.strftime('%Y-%m-%d')
|
|
})
|
|
]
|
|
})
|
|
|
|
statement = self.acc_bank_stmt_model.browse(cr, uid, bank_stmt_id)
|
|
|
|
# We process the reconciliation of the invoice line with the two bank statement lines
|
|
line_id = None
|
|
for l in invoice.move_id.line_id:
|
|
if l.account_id.id == self.account_rcv_id:
|
|
line_id = l
|
|
break
|
|
for statement_line in statement.line_ids:
|
|
self.acc_bank_stmt_line_model.process_reconciliation(cr, uid, statement_line.id, [
|
|
{'counterpart_move_line_id': line_id.id, 'credit': 1.0, 'debit': 0.0, 'name': line_id.name}
|
|
])
|
|
|
|
# The invoice should be paid, as the payments totally cover its total
|
|
self.assertEquals(invoice.state, 'paid', 'The invoice should be paid by now')
|
|
reconcile = None
|
|
for payment in invoice.payment_ids:
|
|
reconcile = payment.reconcile_id
|
|
break
|
|
# The invoice should be reconciled (entirely, not a partial reconciliation)
|
|
self.assertTrue(reconcile, 'The invoice should be totally reconciled')
|
|
result = {}
|
|
exchange_loss_line = None
|
|
for line in reconcile.line_id:
|
|
res_account = result.setdefault(line.account_id, {'debit': 0.0, 'credit': 0.0, 'count': 0})
|
|
res_account['debit'] = res_account['debit'] + line.debit
|
|
res_account['credit'] = res_account['credit'] + line.credit
|
|
res_account['count'] += 1
|
|
if line.credit == 0.01:
|
|
exchange_loss_line = line
|
|
# We should be able to find a move line of 0.01 EUR on the Debtors account, being the cent we lost during the currency exchange
|
|
self.assertTrue(exchange_loss_line, 'There should be one move line of 0.01 EUR in credit')
|
|
# The journal items of the reconciliation should have their debit and credit total equal
|
|
# Besides, the total debit and total credit should be 60.61 EUR (2.00 USD)
|
|
self.assertEquals(sum([res['debit'] for res in result.values()]), 60.61)
|
|
self.assertEquals(sum([res['credit'] for res in result.values()]), 60.61)
|
|
counterpart_exchange_loss_line = None
|
|
for line in exchange_loss_line.move_id.line_id:
|
|
if line.account_id.id == self.account_fx_expense_id:
|
|
counterpart_exchange_loss_line = line
|
|
# We should be able to find a move line of 0.01 EUR on the Foreign Exchange Loss account
|
|
self.assertTrue(counterpart_exchange_loss_line, 'There should be one move line of 0.01 EUR on account "Foreign Exchange Loss"')
|