From 2e276e2b1f05d13e946f6d1e86f5d5bf2293a03b Mon Sep 17 00:00:00 2001 From: laurentbarontini Date: Tue, 28 Apr 2026 11:09:37 +0200 Subject: [PATCH] Move line manual --- modules/account/move.py | 92 +++++++++++++------- modules/account/tests/test_module.py | 50 ++++++++++- modules/account/view/move_line_form_move.xml | 2 + modules/account_invoice/invoice.py | 8 +- 4 files changed, 115 insertions(+), 37 deletions(-) diff --git a/modules/account/move.py b/modules/account/move.py index 16fb786..c123e62 100755 --- a/modules/account/move.py +++ b/modules/account/move.py @@ -1013,7 +1013,9 @@ class Line(DescriptionOriginMixin, MoveLineMixin, ModelSQL, ModelView): journal = fields.Function(fields.Many2One('account.journal',"Journal"),'get_journal') - rate = fields.Function(fields.Numeric("Rate",digits=(1,6)),'get_rate') + rate = fields.Numeric("Rate", digits=(10, 6), states={ + 'readonly': _states['readonly'], + }) del _states @@ -1119,44 +1121,58 @@ class Line(DescriptionOriginMixin, MoveLineMixin, ModelSQL, ModelView): def get_rate(self,name=None): if self.amount_second_currency: return round((self.credit if self.credit else self.debit) / abs(self.amount_second_currency),6) - - @fields.depends( - 'debit', 'credit', - 'date','second_currency','amount_second_currency') - def on_change_amount_second_currency(self): - Currency = Pool().get('currency.currency') - Date = Pool().get('ir.date') - if self.second_currency != None and self.amount_second_currency != None and (not self.credit and not self.debit): - tdate = Date.today() - if self.date: - tdate = self.date - rate = Currency._get_rate([self.second_currency],tdate) - if rate: - rate = rate[self.second_currency.id] - if self.amount_second_currency > 0: - self.debit = round(rate * self.amount_second_currency,2) - elif self.amount_second_currency > 0: - self.credit = round(rate * abs(self.amount_second_currency),2) - self.rate = self.get_rate() @fields.depends( 'debit', 'credit', - 'date','second_currency','amount_second_currency') + 'date','second_currency','amount_second_currency', 'rate', + 'origin', 'move_origin', 'move', '_parent_move.origin') def on_change_second_currency(self): + if self._manual_rate_mode(): + self.rate = self._get_second_currency_rate() + self._compute_amount_from_second_currency() + + @fields.depends( + 'debit', 'credit', + 'date','second_currency','amount_second_currency', 'rate', + 'origin', 'move_origin', 'move', '_parent_move.origin') + def on_change_rate(self): + if self._manual_rate_mode() and not self.debit and not self.credit: + self._compute_amount_from_second_currency() + + def _manual_rate_mode(self): + if getattr(self, 'origin', None) or getattr(self, 'move_origin', None): + return False + move = getattr(self, 'move', None) + if move and getattr(move, 'origin', None): + return False + return True + + def _get_second_currency_rate(self): Currency = Pool().get('currency.currency') Date = Pool().get('ir.date') - if self.second_currency != None and self.amount_second_currency != None and (not self.credit and not self.debit): - tdate = Date.today() - if self.date: - tdate = self.date - rate = Currency._get_rate([self.second_currency],tdate) - if rate: - rate = rate[self.second_currency.id] + if self.second_currency is None: + return None + tdate = Date.today() + if self.date: + tdate = self.date + rates = Currency._get_rate([self.second_currency], tdate) + return rates.get(self.second_currency.id) if rates else None + + def _compute_amount_from_second_currency(self): + if self.second_currency is not None and self.amount_second_currency is not None: + if not self.rate: + self.rate = self._get_second_currency_rate() + if self.rate: + amount = round(self.rate * abs(self.amount_second_currency), 2) if self.amount_second_currency > 0: - self.debit = round(rate * self.amount_second_currency,2) - elif self.amount_second_currency > 0: - self.credit = round(rate * abs(self.amount_second_currency),2) - self.rate = self.get_rate() + self.debit = amount + self.credit = Decimal(0) + elif self.amount_second_currency < 0: + self.debit = Decimal(0) + self.credit = amount + else: + self.debit = Decimal(0) + self.credit = Decimal(0) @fields.depends( 'move', 'debit', 'credit', @@ -1223,15 +1239,25 @@ class Line(DescriptionOriginMixin, MoveLineMixin, ModelSQL, ModelView): if self.debit: self.credit = Decimal(0) self._amount_second_currency_sign() + self.rate = self.get_rate() @fields.depends('debit', 'credit', 'amount_second_currency') def on_change_credit(self): if self.credit: self.debit = Decimal(0) self._amount_second_currency_sign() + self.rate = self.get_rate() - @fields.depends('amount_second_currency', 'debit', 'credit') + @fields.depends( + 'amount_second_currency', 'debit', 'credit', 'date', 'second_currency', + 'rate', 'origin', 'move_origin', 'move', '_parent_move.origin') def on_change_amount_second_currency(self): + if self._manual_rate_mode(): + if not self.rate: + self.rate = self._get_second_currency_rate() + self._compute_amount_from_second_currency() + elif not self.rate: + self.rate = self.get_rate() self._amount_second_currency_sign() def _amount_second_currency_sign(self): diff --git a/modules/account/tests/test_module.py b/modules/account/tests/test_module.py index 0373751..15e0d4b 100755 --- a/modules/account/tests/test_module.py +++ b/modules/account/tests/test_module.py @@ -12,7 +12,7 @@ from trytond.modules.account.exceptions import ( from trytond.modules.account.tax import TaxableMixin from trytond.modules.company.tests import ( CompanyTestMixin, PartyCompanyCheckEraseMixin, create_company, set_company) -from trytond.modules.currency.tests import create_currency +from trytond.modules.currency.tests import add_currency_rate, create_currency from trytond.pool import Pool from trytond.tests.test_tryton import ModuleTestCase, with_transaction from trytond.transaction import Transaction, inactive_records @@ -576,6 +576,54 @@ class AccountTestCase( self.assertEqual( cash_cur.amount_second_currency, Decimal(50)) + @with_transaction() + def test_move_line_second_currency_amount_on_change(self): + 'Test account move line computes amount from second currency' + pool = Pool() + Account = pool.get('account.account') + Line = pool.get('account.move.line') + + company = create_company() + with set_company(company): + create_chart(company) + second_currency = create_currency('sec') + add_currency_rate(second_currency, Decimal('0.939506')) + + expense, = Account.search([ + ('type.expense', '=', True), + ]) + + line = Line( + account=expense, + second_currency=second_currency, + amount_second_currency=Decimal('100.00')) + line.on_change_amount_second_currency() + + self.assertEqual(line.debit, Decimal('93.95')) + self.assertEqual(line.credit, Decimal(0)) + self.assertEqual(line.rate, Decimal('0.939506')) + self.assertEqual(line.get_rate(), Decimal('0.939500')) + + line = Line( + account=expense, + credit=Decimal('7.61'), + second_currency=second_currency, + amount_second_currency=Decimal('-108.10')) + line.on_change_amount_second_currency() + + self.assertEqual(line.debit, Decimal(0)) + self.assertEqual(line.credit, Decimal('101.56')) + self.assertEqual(line.rate, Decimal('0.939506')) + self.assertEqual(line.get_rate(), Decimal('0.939500')) + + line.debit = line.credit = Decimal(0) + line.rate = Decimal('1.100000') + line.on_change_rate() + + self.assertEqual(line.debit, Decimal(0)) + self.assertEqual(line.credit, Decimal('118.91')) + self.assertEqual(line.rate, Decimal('1.100000')) + @with_transaction() def test_account_type_amount(self): "Test account type amount" diff --git a/modules/account/view/move_line_form_move.xml b/modules/account/view/move_line_form_move.xml index 77fff6b..5fa381f 100755 --- a/modules/account/view/move_line_form_move.xml +++ b/modules/account/view/move_line_form_move.xml @@ -26,6 +26,8 @@ this repository contains the full copyright notices and license terms. -->