From 5bd5c7b9063cce5bff5c286c6f99ca42b8a0e02d Mon Sep 17 00:00:00 2001 From: git_admin Date: Tue, 28 Apr 2026 07:34:59 +0000 Subject: [PATCH] Tower: upload at_accounting 18.0.1.7 (via marketplace) --- .../models/account_reconcile_model_line.py | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 addons/at_accounting/models/account_reconcile_model_line.py diff --git a/addons/at_accounting/models/account_reconcile_model_line.py b/addons/at_accounting/models/account_reconcile_model_line.py new file mode 100644 index 0000000..4be6936 --- /dev/null +++ b/addons/at_accounting/models/account_reconcile_model_line.py @@ -0,0 +1,117 @@ +from odoo import models, Command, _ +from odoo.exceptions import UserError + +import re + +from math import copysign + + +class AccountReconcileModelLine(models.Model): + _inherit = 'account.reconcile.model.line' + + def _prepare_aml_vals(self, partner): + """ Prepare a dictionary that will be used later to create a new journal item (account.move.line) for the + given reconcile model line. + + :param partner: The partner to be linked to the journal item. + :return: A python dictionary. + """ + self.ensure_one() + + taxes = self.tax_ids + if taxes and partner: + fiscal_position = self.env['account.fiscal.position']._get_fiscal_position(partner) + if fiscal_position: + taxes = fiscal_position.map_tax(taxes) + + values = { + 'name': self.label, + 'partner_id': partner.id, + 'analytic_distribution': self.analytic_distribution, + 'tax_ids': [Command.set(taxes.ids)], + 'reconcile_model_id': self.model_id.id, + } + if self.account_id: + values['account_id'] = self.account_id.id + return values + + def _apply_in_manual_widget(self, residual_amount_currency, partner, currency): + """ Prepare a dictionary that will be used later to create a new journal item (account.move.line) for the + given reconcile model line used by the manual reconciliation widget. + + Note: 'journal_id' is added to the returned dictionary even if it is a related readonly field. + It's a hack for the manual reconciliation widget. Indeed, a single journal entry will be created for each + journal. + + :param residual_amount_currency: The current balance expressed in the account's currency. + :param partner: The partner to be linked to the journal item. + :param currency: The currency set on the account in the manual reconciliation widget. + :return: A python dictionary. + """ + self.ensure_one() + + if self.amount_type == 'percentage': + amount_currency = currency.round(residual_amount_currency * (self.amount / 100.0)) + elif self.amount_type == 'fixed': + sign = 1 if residual_amount_currency > 0.0 else -1 + amount_currency = currency.round(self.amount * sign) + else: + raise UserError(_("This reconciliation model can't be used in the manual reconciliation widget because its " + "configuration is not adapted")) + + return { + **self._prepare_aml_vals(partner), + 'currency_id': currency.id, + 'amount_currency': amount_currency, + 'journal_id': self.journal_id.id, + } + + def _apply_in_bank_widget(self, residual_amount_currency, partner, st_line): + """ Prepare a dictionary that will be used later to create a new journal item (account.move.line) for the + given reconcile model line used by the bank reconciliation widget. + + :param residual_amount_currency: The current balance expressed in the statement line's currency. + :param partner: The partner to be linked to the journal item. + :param st_line: The statement line mounted inside the bank reconciliation widget. + :return: A python dictionary. + """ + self.ensure_one() + currency = st_line.foreign_currency_id or st_line.journal_id.currency_id or st_line.company_currency_id + + aml_values = {'currency_id': currency.id} + + if self.amount_type == 'percentage_st_line': + transaction_amount, transaction_currency, journal_amount, journal_currency, _company_amount, _company_currency \ + = st_line._get_accounting_amounts_and_currencies() + if self.model_id.rule_type == 'writeoff_button' and self.model_id.counterpart_type in ('sale', 'purchase'): + # The invoice should be created using the transaction currency. + aml_values['amount_currency'] = currency.round(-transaction_amount * self.amount / 100.0) + aml_values['percentage_st_line'] = self.amount / 100.0 + aml_values['currency_id'] = transaction_currency.id + else: + # The additional journal items follow the journal currency. + aml_values['amount_currency'] = currency.round(-journal_amount * self.amount / 100.0) + aml_values['currency_id'] = journal_currency.id + elif self.amount_type == 'regex': + match = re.search(self.amount_string, st_line.payment_ref) + if match: + sign = 1 if residual_amount_currency > 0.0 else -1 + decimal_separator = self.model_id.decimal_separator + try: + extracted_match_group = re.sub(r'[^\d' + decimal_separator + ']', '', match.group(1)) + extracted_balance = float(extracted_match_group.replace(decimal_separator, '.')) + aml_values['amount_currency'] = copysign(extracted_balance * sign, residual_amount_currency) + except ValueError: + aml_values['amount_currency'] = 0.0 + else: + aml_values['amount_currency'] = 0.0 + + if 'amount_currency' not in aml_values: + aml_values.update(self._apply_in_manual_widget(residual_amount_currency, partner, currency)) + else: + aml_values.update(self._prepare_aml_vals(partner)) + + if not aml_values.get('name', False): + aml_values['name'] = st_line.payment_ref + + return aml_values