From 34de85726f57d6b74bc7df83018c0a9938153cd8 Mon Sep 17 00:00:00 2001 From: Michael Tietz Date: Fri, 27 Feb 2026 11:58:20 +0100 Subject: [PATCH] [FIX] account_invoice_import: Apply fiscal position like Odoo does --- account_invoice_import/readme/CONTRIBUTORS.md | 1 + .../tests/test_invoice_import.py | 88 +++++++++++++++++++ .../wizard/account_invoice_import.py | 33 +++++-- 3 files changed, 114 insertions(+), 8 deletions(-) diff --git a/account_invoice_import/readme/CONTRIBUTORS.md b/account_invoice_import/readme/CONTRIBUTORS.md index f096d21025..779cd3578c 100644 --- a/account_invoice_import/readme/CONTRIBUTORS.md +++ b/account_invoice_import/readme/CONTRIBUTORS.md @@ -4,3 +4,4 @@ - Yannick Vaucher \<\> - Ronald Portier \<\> - Simone Orsi \<\> +- Michael Tietz (MT Software) \<\> diff --git a/account_invoice_import/tests/test_invoice_import.py b/account_invoice_import/tests/test_invoice_import.py index 245fbeb3f3..672b9cfbf6 100644 --- a/account_invoice_import/tests/test_invoice_import.py +++ b/account_invoice_import/tests/test_invoice_import.py @@ -2,6 +2,7 @@ # @author: Alexis de Lattre # Copyright 2022 Camptocamp SA # @author: Simone Orsi +# Copyright 2026 Michael Tietz (MT Software) # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). import unittest.mock @@ -420,3 +421,90 @@ def test_email_partner_invoice_config(self): price_prec = self.env["decimal.precision"].precision_get("Product Price") self.assertTrue(float_is_zero(iline.price_unit, precision_digits=price_prec)) self.assertTrue(self.company.currency_id.is_zero(iline.price_subtotal)) + + def test_import_in_invoice_fiscal_position(self): + """The auto-applied fiscal position of the partner maps account and taxes""" + partner = self.env["res.partner"].create( + { + "is_company": True, + "name": "AII Fiscal Position Supplier", + "country_id": self.env.ref("base.be").id, + } + ) + dest_account = self.env["account.account"].create( + { + "code": "613AII", + "name": "Fiscal position expense account invoice import", + "account_type": "expense", + "company_ids": [Command.set([self.company.id])], + } + ) + dest_tax = self.purchase_tax.copy( + {"name": "Test 0% VAT", "description": "ZZ-VAT-buy-0.0", "amount": 0} + ) + self.env["account.fiscal.position"].create( + { + "name": "AII Belgium", + "company_id": self.company.id, + "auto_apply": True, + "country_id": self.env.ref("base.be").id, + "sequence": 1, + "account_ids": [ + Command.create( + { + "account_src_id": self.expense_account.id, + "account_dest_id": dest_account.id, + } + ) + ], + "tax_ids": [ + Command.create( + { + "tax_src_id": self.purchase_tax.id, + "tax_dest_id": dest_tax.id, + } + ) + ], + } + ) + parsed_inv = { + "type": "in_invoice", + "amount_untaxed": 100.0, + "amount_total": 100.0, + "date": "2017-08-16", + "partner": {"name": partner.name}, + "lines": [ + { + "product": {"code": "AII-TEST-PRODUCT"}, + "name": "Super test product", + "qty": 2, + "price_unit": 50, + "taxes": [ + { + "amount_type": "percent", + "amount": 1.0, + "unece_type_code": "VAT", + "unece_categ_code": "S", + } + ], + } + ], + } + import_configs = [ + { + "single_line": True, + "account": self.expense_account, + "taxes": self.purchase_tax, + "company": self.company, + }, + {"single_line": False, "product": self.product, "company": self.company}, + ] + for import_config in import_configs: + parsed_inv["invoice_number"] = f"INV-{randint(100000, 999999)}" + inv = self.env["account.invoice.import"].create_invoice( + parsed_inv, import_config + ) + self.assertEqual(inv.partner_id, partner) + self.assertEqual(len(inv.invoice_line_ids), 1) + self.assertEqual(inv.invoice_line_ids.account_id, dest_account) + self.assertEqual(inv.invoice_line_ids.tax_ids, dest_tax) diff --git a/account_invoice_import/wizard/account_invoice_import.py b/account_invoice_import/wizard/account_invoice_import.py index 976e21d91c..e12d57656f 100644 --- a/account_invoice_import/wizard/account_invoice_import.py +++ b/account_invoice_import/wizard/account_invoice_import.py @@ -1,5 +1,6 @@ # Copyright 2015-2021 Akretion France (http://www.akretion.com/) # Copyright 2020-2021 Therp BV (https://therp.nl) +# Copyright 2026 Michael Tietz (MT Software) # @author: Alexis de Lattre # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). @@ -364,6 +365,24 @@ def _prepare_create_invoice_vals(self, parsed_inv, import_config): vals["check_total"] = parsed_inv["amount_total"] return vals + def _get_fiscal_position(self, import_config, partner, partner_shipping=None): + return ( + self.env["account.fiscal.position"] + .with_company(import_config["company"]) + ._get_fiscal_position(partner, partner_shipping) + ) + + def _map_account_and_taxes(self, import_config, partner, account, taxes): + res = account, taxes + if not partner: + return res + fiscal_position = self._get_fiscal_position(import_config, partner) + if not fiscal_position: + return res + new_account = fiscal_position.map_account(account) + new_taxes = fiscal_position.map_tax(taxes) + return new_account, new_taxes + @api.model def _prepare_line_vals_1line(self, parsed_inv, import_config, vals, partner): il_vals = { @@ -394,10 +413,9 @@ def _prepare_line_vals_1line(self, parsed_inv, import_config, vals, partner): account = import_config["account"] if import_config.get("taxes"): taxes = import_config["taxes"] - fp = partner and partner.property_account_position_id or False - if fp: - account = fp.map_account(account) - taxes = fp.map_tax(taxes) + account, taxes = self._map_account_and_taxes( + import_config, partner, account, taxes + ) il_vals.update( { "account_id": account.id, @@ -465,10 +483,9 @@ def _prepare_line_vals_nline(self, parsed_inv, import_config, vals, partner): if not taxes: taxes = import_config["taxes"] - fp = partner and partner.property_account_position_id or False - if fp: - account = fp.map_account(account) - taxes = fp.map_tax(taxes) + account, taxes = self._map_account_and_taxes( + import_config, partner, account, taxes + ) uom = bdio._match_uom( line.get("uom"), parsed_inv["chatter_msg"],