From 04fdd9dc9e85aefc94330744f16fe6b02a8277a7 Mon Sep 17 00:00:00 2001 From: Frederik Jaeckel Date: Tue, 23 Aug 2022 15:34:36 +0200 Subject: [PATCH] line: valid handling of 2nd-currency + test --- line.py | 30 +++++- tests/test_config.py | 46 +++++++++ tests/test_line.py | 232 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 303 insertions(+), 5 deletions(-) diff --git a/line.py b/line.py index 59de07b..5b58c44 100644 --- a/line.py +++ b/line.py @@ -251,17 +251,17 @@ class Line(Workflow, ModelSQL, ModelView): )) # in case of 'mvin' or 'mvout' - create counterpart if (line.bookingtype in ['mvout', 'mvin']) and (line.reference is None): - to_create_line.append({ + values = { 'cashbook': line.booktransf.id, 'bookingtype': 'mvin' if line.bookingtype == 'mvout' else 'mvout', 'date': line.date, 'description': line.description, - 'amount': line.amount, - 'credit': line.debit, - 'debit': line.credit, 'booktransf': line.cashbook.id, 'reference': line.id, - }) + } + values.update(line.get_amount_by_second_currency(line.booktransf.currency)) + values.update(cls.get_debit_credit(values)) + to_create_line.append(values) # add number to line if line.cashbook.number_atcheck == True: @@ -342,6 +342,26 @@ class Line(Workflow, ModelSQL, ModelView): 'type': gettext('cashbook.msg_line_bookingtype_%s' % self.bookingtype), } + def get_amount_by_second_currency(self, to_currency): + """ get amount, calculate credit/debit from currency of current + cashbook to 'to_currency' + """ + Currency = Pool().get('currency.currency') + + values = { + 'amount': self.amount, + } + + if to_currency.id != self.cashbook.currency.id: + with Transaction().set_context({ + 'date': self.date, + }): + values['amount'] = Currency.compute( + self.cashbook.currency, + self.amount, + to_currency) + return values + @staticmethod def order_state(tables): """ edit = 0, check/done = 1 diff --git a/tests/test_config.py b/tests/test_config.py index 2523bdf..7932229 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -9,6 +9,7 @@ from trytond.transaction import Transaction from trytond.exceptions import UserError from trytond.modules.company.tests import create_company from datetime import date +from decimal import Decimal class ConfigTestCase(ModuleTestCase): @@ -53,6 +54,51 @@ class ConfigTestCase(ModuleTestCase): }]) return party + def prep_2nd_currency(self, company): + """ add EUR as 2nd currency + """ + pool = Pool() + Currency = pool.get('currency.currency') + CurrencyRate = pool.get('currency.currency.rate') + Company = pool.get('company.company') + + usd, = Currency.search([('name', '=', 'usd')]) + euros = Currency.search([('code', '=', 'EUR')]) + if len(euros) == 0: + euro, = Currency.create([{ + 'name': 'Euro', + 'symbol': '€', + 'code': 'EUR', + 'numeric_code': '978', + 'rounding': Decimal('0.01'), + 'digits': 2, + }]) + else : + euro = euros[0] + + # set company-currency to euro + self.assertEqual(company.currency.name, 'usd') + Company.write(*[ + [company], + { + 'currency': euro.id, + }]) + self.assertEqual(company.currency.name, 'Euro') + + # add rate for euro/usd @ 05/02/2022 + # EUR is base-currency + CurrencyRate.create([{ + 'date': date(2022, 5, 2), + 'currency': euro.id, + 'rate': Decimal('1.0'), + }, { + 'date': date(2022, 5, 2), + 'currency': usd.id, + 'rate': Decimal('1.05'), + }]) + + return (usd, euro) + @with_transaction() def test_config_create(self): """ create config diff --git a/tests/test_line.py b/tests/test_line.py index 7848d4e..e08d0b1 100644 --- a/tests/test_line.py +++ b/tests/test_line.py @@ -16,6 +16,238 @@ class LineTestCase(ModuleTestCase): 'Test cashbook line module' module = 'cashbook' + @with_transaction() + def test_line_check_transfer_2nd_currency_out(self): + """ create cashbook, lines, transfer amount between + accounts with different currencies + """ + pool = Pool() + Book = pool.get('cashbook.book') + Lines = pool.get('cashbook.line') + Reconciliation = pool.get('cashbook.recon') + + types = self.prep_type() + company = self.prep_company() + + # add EURO, set company-currency to EURO + (usd, euro) = self.prep_2nd_currency(company) + + books = Book.create([{ + 'name': 'Book USD', + 'btype': types.id, + 'company': company.id, + 'currency': usd.id, + 'number_sequ': self.prep_sequence().id, + 'start_date': date(2022, 5, 1), + }, { + 'name': 'Book EURO', + 'btype': types.id, + 'company': company.id, + 'currency': euro.id, + 'number_sequ': self.prep_sequence().id, + 'start_date': date(2022, 5, 1), + }]) + self.assertEqual(len(books), 2) + self.assertEqual(books[0].rec_name, 'Book USD | 0.00 usd | Open') + self.assertEqual(books[1].rec_name, 'Book EURO | 0.00 € | Open') + + Book.write(*[ + [books[0]], + { + 'lines': [('create', [{ + 'date': date(2022, 5, 5), + 'description': 'Transfer USD --> EUR', + 'bookingtype': 'mvout', + 'amount': Decimal('10.0'), + 'booktransf': books[1].id, + }])], + }]) + self.assertEqual(len(books[0].lines), 1) + self.assertEqual(len(books[1].lines), 0) + self.assertEqual(books[0].lines[0].rec_name, + '05/05/2022|to|-10.00 usd|Transfer USD --> EUR [Book EURO | 0.00 € | Open]') + self.assertEqual(books[0].lines[0].reference, None) + self.assertEqual(len(books[0].lines[0].references), 0) + self.assertEqual(books[0].lines[0].reconciliation, None) + + Lines.wfcheck([books[0].lines[0]]) + + self.assertEqual(len(books[0].lines), 1) + self.assertEqual(len(books[1].lines), 1) + self.assertEqual(books[0].lines[0].reference, None) + self.assertEqual(len(books[0].lines[0].references), 1) + + self.assertEqual(books[0].lines[0].rec_name, + '05/05/2022|to|-10.00 usd|Transfer USD --> EUR [Book EURO | 9.52 € | Open]') + self.assertEqual(books[1].lines[0].rec_name, + '05/05/2022|from|9.52 €|Transfer USD --> EUR [Book USD | -10.00 usd | Open]') + self.assertEqual(books[0].balance, Decimal('-10.0')) + self.assertEqual(books[0].currency.rec_name, 'usd') + self.assertEqual(books[1].balance, Decimal('9.52')) + self.assertEqual(books[1].currency.rec_name, 'Euro') + + @with_transaction() + def test_line_check_transfer_2nd_currency_in(self): + """ create cashbook, lines, transfer amount between + accounts with different currencies + """ + pool = Pool() + Book = pool.get('cashbook.book') + Lines = pool.get('cashbook.line') + Reconciliation = pool.get('cashbook.recon') + + types = self.prep_type() + company = self.prep_company() + + # add EURO, set company-currency to EURO + (usd, euro) = self.prep_2nd_currency(company) + + books = Book.create([{ + 'name': 'Book USD', + 'btype': types.id, + 'company': company.id, + 'currency': usd.id, + 'number_sequ': self.prep_sequence().id, + 'start_date': date(2022, 5, 1), + }, { + 'name': 'Book EURO', + 'btype': types.id, + 'company': company.id, + 'currency': euro.id, + 'number_sequ': self.prep_sequence().id, + 'start_date': date(2022, 5, 1), + }]) + self.assertEqual(len(books), 2) + self.assertEqual(books[0].rec_name, 'Book USD | 0.00 usd | Open') + self.assertEqual(books[1].rec_name, 'Book EURO | 0.00 € | Open') + + Book.write(*[ + [books[0]], + { + 'lines': [('create', [{ + 'date': date(2022, 5, 5), + 'description': 'Transfer USD <-- EUR', + 'bookingtype': 'mvin', + 'amount': Decimal('10.0'), + 'booktransf': books[1].id, + }])], + }]) + self.assertEqual(len(books[0].lines), 1) + self.assertEqual(len(books[1].lines), 0) + self.assertEqual(books[0].lines[0].rec_name, + '05/05/2022|from|10.00 usd|Transfer USD <-- EUR [Book EURO | 0.00 € | Open]') + self.assertEqual(books[0].lines[0].reference, None) + self.assertEqual(len(books[0].lines[0].references), 0) + self.assertEqual(books[0].lines[0].reconciliation, None) + + Lines.wfcheck([books[0].lines[0]]) + + self.assertEqual(len(books[0].lines), 1) + self.assertEqual(len(books[1].lines), 1) + self.assertEqual(books[0].lines[0].reference, None) + self.assertEqual(len(books[0].lines[0].references), 1) + + self.assertEqual(books[0].lines[0].rec_name, + '05/05/2022|from|10.00 usd|Transfer USD <-- EUR [Book EURO | -9.52 € | Open]') + self.assertEqual(books[1].lines[0].rec_name, + '05/05/2022|to|-9.52 €|Transfer USD <-- EUR [Book USD | 10.00 usd | Open]') + self.assertEqual(books[0].balance, Decimal('10.0')) + self.assertEqual(books[0].currency.rec_name, 'usd') + self.assertEqual(books[1].balance, Decimal('-9.52')) + self.assertEqual(books[1].currency.rec_name, 'Euro') + + @with_transaction() + def test_line_check_transfer_2nd_currency_nocompany(self): + """ create cashbook, lines, transfer amount between + accounts with different currencies, + both currencies are no company-currencies + """ + pool = Pool() + Book = pool.get('cashbook.book') + Lines = pool.get('cashbook.line') + Reconciliation = pool.get('cashbook.recon') + Currency = pool.get('currency.currency') + CurrencyRate = pool.get('currency.currency.rate') + + types = self.prep_type() + company = self.prep_company() + + # add EURO, set company-currency to EURO + (usd, euro) = self.prep_2nd_currency(company) + # add CHF + curr_chf, = Currency.create([{ + 'name': 'Swiss Franc', + 'symbol': 'CHF', + 'code': 'CHF', + 'numeric_code': '756', + 'rounding': Decimal('0.01'), + 'digits': 2, + }]) + CurrencyRate.create([{ + 'date': date(2022, 5, 2), + 'currency': curr_chf.id, + 'rate': Decimal('1.04'), # 1 € = 1.04 CHF @ 5/2/2022 + },]) + + books = Book.create([{ + 'name': 'Book CHF', + 'btype': types.id, + 'company': company.id, + 'currency': curr_chf.id, + 'number_sequ': self.prep_sequence().id, + 'start_date': date(2022, 5, 1), + }, { + 'name': 'Book USD', + 'btype': types.id, + 'company': company.id, + 'currency': usd.id, + 'number_sequ': self.prep_sequence().id, + 'start_date': date(2022, 5, 1), + }]) + self.assertEqual(len(books), 2) + self.assertEqual(books[0].rec_name, 'Book CHF | 0.00 CHF | Open') + self.assertEqual(books[1].rec_name, 'Book USD | 0.00 usd | Open') + + Book.write(*[ + [books[0]], + { + 'lines': [('create', [{ + 'date': date(2022, 5, 5), + 'description': 'Transfer CHF --> USD', + 'bookingtype': 'mvout', + 'amount': Decimal('10.0'), + 'booktransf': books[1].id, + }])], + }]) + self.assertEqual(len(books[0].lines), 1) + self.assertEqual(len(books[1].lines), 0) + self.assertEqual(books[0].lines[0].rec_name, + '05/05/2022|to|-10.00 CHF|Transfer CHF --> USD [Book USD | 0.00 usd | Open]') + self.assertEqual(books[0].lines[0].reference, None) + self.assertEqual(len(books[0].lines[0].references), 0) + self.assertEqual(books[0].lines[0].reconciliation, None) + + Lines.wfcheck([books[0].lines[0]]) + + self.assertEqual(len(books[0].lines), 1) + self.assertEqual(len(books[1].lines), 1) + self.assertEqual(books[0].lines[0].reference, None) + self.assertEqual(len(books[0].lines[0].references), 1) + + # 10 CHF --> USD: USD = CHF * 1.05 / 1.04 + # 10 CHF = 10.0961538 USD + # EUR | USD | CHF + # -----+-----+----- @ 05/02/2022 + # 1.00| 1.05| 1.04 + self.assertEqual(books[0].lines[0].rec_name, + '05/05/2022|to|-10.00 CHF|Transfer CHF --> USD [Book USD | 10.10 usd | Open]') + self.assertEqual(books[1].lines[0].rec_name, + '05/05/2022|from|10.10 usd|Transfer CHF --> USD [Book CHF | -10.00 CHF | Open]') + self.assertEqual(books[0].balance, Decimal('-10.0')) + self.assertEqual(books[0].currency.rec_name, 'Swiss Franc') + self.assertEqual(books[1].balance, Decimal('10.10')) + self.assertEqual(books[1].currency.rec_name, 'usd') + @with_transaction() def test_line_check_balance_by_line(self): """ create cashbook, lines, reconciliations,