"""Exchange-difference calculation helper. Pure-Python FX gain/loss computation. The engine uses this for rapid pre-checks; Odoo's account.move._create_exchange_difference_move() is invoked separately for the actual GL posting. """ from dataclasses import dataclass @dataclass class ExchangeDiffResult: needs_diff_move: bool diff_amount: float # in company currency; positive = gain, negative = loss line_company_amount: float against_company_amount: float def compute_exchange_diff(*, line_amount, line_currency_code, against_amount, against_currency_code, line_rate, against_rate) -> ExchangeDiffResult: """Compute whether an exchange-diff move is needed and its magnitude. Args: line_amount: Bank line amount in its currency line_currency_code: e.g. 'USD' against_amount: Matched journal item amount in its currency against_currency_code: e.g. 'USD' (or different) line_rate: FX rate (foreign per company currency) at line date against_rate: FX rate at journal item posting date Returns: ExchangeDiffResult with needs_diff_move flag and computed diff in company currency (positive = gain, negative = loss). """ line_company = line_amount * line_rate against_company = against_amount * against_rate diff = line_company - against_company needs_diff = abs(diff) > 0.005 # rounding tolerance return ExchangeDiffResult( needs_diff_move=needs_diff, diff_amount=round(diff, 2), line_company_amount=round(line_company, 2), against_company_amount=round(against_company, 2), )