diff --git a/account_reconcile_oca/models/account_bank_statement_line.py b/account_reconcile_oca/models/account_bank_statement_line.py index f153d1a6..db0a3731 100644 --- a/account_reconcile_oca/models/account_bank_statement_line.py +++ b/account_reconcile_oca/models/account_bank_statement_line.py @@ -60,6 +60,19 @@ class AccountBankStatementLine(models.Model): "Percentage Analytic" ), ) + manual_in_currency = fields.Boolean(readonly=True, store=False, prefetch=False) + manual_in_currency_id = fields.Many2one( + "res.currency", readonly=True, store=False, prefetch=False + ) + manual_amount_in_currency = fields.Monetary( + store=False, + default=False, + prefetch=False, + currency_field="manual_in_currency_id", + ) + manual_exchange_counterpart = fields.Boolean( + store=False, + ) manual_model_id = fields.Many2one( "account.reconcile.model", check_company=True, @@ -268,15 +281,29 @@ class AccountBankStatementLine(models.Model): self.ensure_one() data = self.reconcile_data_info.get("data", []) new_data = [] + related_move_line_id = False for line in data: + if line.get("reference") == self.manual_reference: + related_move_line_id = line.get("id") + break + for line in data: + if ( + self.manual_delete + and related_move_line_id + and line.get("original_exchange_line_id") == related_move_line_id + ): + # We should remove the related exchange rate line + continue if line["reference"] == self.manual_reference: if self.manual_delete: self.update( { - "manual_delete": False, "manual_reference": False, "manual_account_id": False, "manual_amount": False, + "manual_exchange_counterpart": False, + "manual_in_currency_id": False, + "manual_in_currency": False, "manual_name": False, "manual_partner_id": False, "manual_line_id": False, @@ -286,6 +313,7 @@ class AccountBankStatementLine(models.Model): "manual_original_amount": False, "manual_currency_id": False, "analytic_distribution": False, + "manual_amount_in_currency": False, } ) continue @@ -293,11 +321,22 @@ class AccountBankStatementLine(models.Model): self.manual_account_id = line["account_id"][0] self.manual_amount = line["amount"] self.manual_currency_id = line["currency_id"] + self.manual_in_currency_id = line.get("line_currency_id") + self.manual_in_currency = line.get("line_currency_id") and line[ + "currency_id" + ] != line.get("line_currency_id") + self.manual_amount_in_currency = line.get("currency_amount") self.manual_name = line["name"] + self.manual_exchange_counterpart = line.get( + "is_exchange_counterpart", False + ) self.manual_partner_id = ( line.get("partner_id") and line["partner_id"][0] ) - self.manual_line_id = line["id"] + manual_line = ( + self.env["account.move.line"].browse(line["id"]).exists() + ) + self.manual_line_id = manual_line self.analytic_distribution = line.get("analytic_distribution", {}) if self.manual_line_id: self.manual_move_id = self.manual_line_id.move_id @@ -305,6 +344,7 @@ class AccountBankStatementLine(models.Model): self.manual_kind = line["kind"] self.manual_original_amount = line.get("original_amount", 0.0) new_data.append(line) + self.update({"manual_delete": False}) self.reconcile_data_info = self._recompute_suspense_line( new_data, self.reconcile_data_info["reconcile_auxiliary_id"], @@ -312,6 +352,17 @@ class AccountBankStatementLine(models.Model): ) self.can_reconcile = self.reconcile_data_info.get("can_reconcile", False) + @api.onchange("manual_amount_in_currency") + def _onchange_manual_amount_in_currency(self): + if self.manual_line_id.exists() and self.manual_line_id: + self.manual_amount = self.manual_in_currency_id._convert( + self.manual_amount_in_currency, + self.company_id.currency_id, + self.company_id, + self.manual_line_id.date, + ) + self._onchange_manual_reconcile_vals() + @api.onchange( "manual_account_id", "manual_partner_id", @@ -357,6 +408,23 @@ class AccountBankStatementLine(models.Model): ) if line["kind"] == "liquidity": self._update_move_partner() + if self.manual_line_id and self.manual_line_id.id == line.get( + "original_exchange_line_id" + ): + # Now, we should edit the amount of the exchange rate + amount = self._get_exchange_rate_amount( + self.manual_amount, + self.manual_amount_in_currency, + self.manual_line_id.currency_id, + self.manual_line_id, + ) + line.update( + { + "amount": amount, + "credit": -amount if amount < 0 else 0.0, + "debit": amount if amount > 0 else 0.0, + } + ) new_data.append(line) self.reconcile_data_info = self._recompute_suspense_line( new_data, @@ -485,6 +553,11 @@ class AccountBankStatementLine(models.Model): reconcile_auxiliary_id, self.manual_reference, ) + else: + other_lines = ( + other_lines.matched_credit_ids.credit_move_id + | other_lines.matched_debit_ids.debit_move_id + ) for line in other_lines: reconcile_auxiliary_id, lines = self._get_reconcile_line( line, "other", from_unreconcile=from_unreconcile @@ -504,7 +577,7 @@ class AccountBankStatementLine(models.Model): self.ensure_one() self.reconcile_mode = self.journal_id.reconcile_mode result = getattr(self, "_reconcile_bank_line_%s" % self.reconcile_mode)( - self.reconcile_data_info["data"] + self._prepare_reconcile_line_data(self.reconcile_data_info["data"]) ) self.reconcile_data_info = False return result @@ -713,9 +786,37 @@ class AccountBankStatementLine(models.Model): continue getattr( record, "_reconcile_bank_line_%s" % record.journal_id.reconcile_mode - )(data["data"]) + )(self._prepare_reconcile_line_data(data["data"])) return result + def _prepare_reconcile_line_data(self, lines): + new_lines = [] + reverse_lines = {} + for line in lines: + if not line.get("id") and not line.get("original_exchange_line_id"): + new_lines.append(line) + elif not line.get("original_exchange_line_id"): + reverse_lines[line["id"]] = line + for line in lines: + if line.get("original_exchange_line_id"): + reverse_lines[line["original_exchange_line_id"]].update( + { + "amount": reverse_lines[line["original_exchange_line_id"]][ + "amount" + ] + + line["amount"], + "credit": reverse_lines[line["original_exchange_line_id"]][ + "credit" + ] + + line["credit"], + "debit": reverse_lines[line["original_exchange_line_id"]][ + "debit" + ] + + line["debit"], + } + ) + return new_lines + list(reverse_lines.values()) + def button_manual_reference_full_paid(self): self.ensure_one() if not self.reconcile_data_info["manual_reference"]: @@ -801,6 +902,17 @@ class AccountBankStatementLine(models.Model): new_vals += rates return reconcile_auxiliary_id, new_vals + def _get_exchange_rate_amount(self, amount, currency_amount, currency, line): + return ( + currency._convert( + currency_amount, + self.company_id.currency_id, + self.company_id, + self.date, + ) + - amount + ) + def _compute_exchange_rate( self, vals, @@ -815,18 +927,17 @@ class AccountBankStatementLine(models.Model): if not foreign_currency or self.is_reconciled: return reconcile_auxiliary_id, False currency = self.env["res.currency"].browse(vals["line_currency_id"]) - amount = currency._convert( - vals["currency_amount"], - self.company_id.currency_id, - self.company_id, - self.date, - ) - vals.get("amount", 0) + amount = self._get_exchange_rate_amount( + vals.get("amount", 0), vals.get("currency_amount", 0), currency, line + ) if currency.is_zero(amount): return reconcile_auxiliary_id, False account = self.company_id.expense_currency_exchange_account_id if amount < 0: account = self.company_id.income_currency_exchange_account_id data = { + "is_exchange_counterpart": True, + "original_exchange_line_id": line.id, "reference": "reconcile_auxiliary;%s" % reconcile_auxiliary_id, "id": False, "account_id": account.name_get()[0], diff --git a/account_reconcile_oca/tests/test_bank_account_reconcile.py b/account_reconcile_oca/tests/test_bank_account_reconcile.py index ed68d9d2..bead9237 100644 --- a/account_reconcile_oca/tests/test_bank_account_reconcile.py +++ b/account_reconcile_oca/tests/test_bank_account_reconcile.py @@ -1020,6 +1020,11 @@ class TestReconciliationWidget(TestAccountReconciliationCommon): self.assertTrue(bank_stmt_line.can_reconcile) bank_stmt_line.reconcile_bank_line() self.assertEqual(0, inv1.amount_residual) + self.assertTrue( + inv1.line_ids.filtered( + lambda line: line.account_id.account_type == "asset_receivable" + ).full_reconcile_id + ) def test_journal_foreign_currency_change(self): self.env["res.currency.rate"].create( diff --git a/account_reconcile_oca/views/account_bank_statement_line.xml b/account_reconcile_oca/views/account_bank_statement_line.xml index 4f4e5ab2..b98d056c 100644 --- a/account_reconcile_oca/views/account_bank_statement_line.xml +++ b/account_reconcile_oca/views/account_bank_statement_line.xml @@ -258,16 +258,22 @@ + + + +