details:   https://code.tryton.org/tryton/commit/9b9ff0dd3074
branch:    7.6
user:      Maxime Richez <[email protected]>
date:      Fri Jan 30 17:32:18 2026 +0100
description:
        Set incoterm required on extended intrastat for sale between EU 
countries

        Closes #14531
        (grafted from afe3d31157bf24243d1f2d3a0cb8d4b747ea5357)
diffstat:

 modules/account_stock_eu/sale.py              |    6 +-
 modules/account_stock_eu/tests/test_module.py |  116 +++++++++++++++++++++++++-
 modules/incoterm/tests/test_module.py         |   63 +++++++++++++-
 3 files changed, 180 insertions(+), 5 deletions(-)

diffs (224 lines):

diff -r 5bd75486bb5f -r 9b9ff0dd3074 modules/account_stock_eu/sale.py
--- a/modules/account_stock_eu/sale.py  Thu Jan 22 13:54:58 2026 +0100
+++ b/modules/account_stock_eu/sale.py  Fri Jan 30 17:32:18 2026 +0100
@@ -42,7 +42,7 @@
                                 self.sale_date)
                         else:
                             to_europe = None
-                    required = (
-                        (from_country != to_country)
-                        and not (from_europe and to_europe))
+                        if (from_country != to_country
+                                and from_europe and to_europe):
+                            required = True
         return required
diff -r 5bd75486bb5f -r 9b9ff0dd3074 
modules/account_stock_eu/tests/test_module.py
--- a/modules/account_stock_eu/tests/test_module.py     Thu Jan 22 13:54:58 
2026 +0100
+++ b/modules/account_stock_eu/tests/test_module.py     Fri Jan 30 17:32:18 
2026 +0100
@@ -1,6 +1,10 @@
 # This file is part of Tryton.  The COPYRIGHT file at the top level of
 # this repository contains the full copyright notices and license terms.
-from trytond.tests.test_tryton import ModuleTestCase
+from unittest.mock import Mock, patch
+
+from trytond.modules.account.exceptions import FiscalYearNotFoundError
+from trytond.pool import Pool
+from trytond.tests.test_tryton import ModuleTestCase, with_transaction
 
 
 class AccountStockEuTestCase(ModuleTestCase):
@@ -8,5 +12,115 @@
     module = 'account_stock_eu'
     extras = ['carrier', 'incoterm', 'production', 'stock_consignment']
 
+    @with_transaction()
+    def test_sale_incoterm_required(self):
+        "Test incoterm required on sale"
+        pool = Pool()
+        Sale = pool.get('sale.sale')
+        FiscalYear = pool.get('account.fiscalyear')
+        Country = pool.get('country.country')
+
+        from_country = Mock(spec=Country)
+        to_country = Mock(spec=Country)
+        sale = Mock(spec=Sale)
+        sale.warehouse.address.country = from_country
+        sale.shipment_address.country = to_country
+        type(sale)._incoterm_required = Sale._incoterm_required
+        fiscalyear = Mock(spec=FiscalYear)
+
+        with patch.object(FiscalYear, 'find') as fiscalyear_find:
+            fiscalyear_find.return_value = fiscalyear
+            for extended, from_europe, to_europe, result in [
+                    (False, False, False, True),
+                    (False, False, True, True),
+                    (False, True, False, True),
+                    (False, True, True, False),
+                    (True, False, False, True),
+                    (True, False, True, True),
+                    (True, True, False, True),
+                    (True, True, True, True),
+                    (None, False, False, True),
+                    (None, False, True, True),
+                    (None, True, False, True),
+                    (None, True, True, False),
+                    ]:
+                if extended is not None:
+                    fiscalyear_find.side_effect = None
+                    fiscalyear.intrastat_extended = extended
+                else:
+                    fiscalyear_find.side_effect = FiscalYearNotFoundError('')
+                from_country.is_member.return_value = from_europe
+                to_country.is_member.return_value = to_europe
+                with self.subTest(
+                        extended=extended,
+                        from_europe=from_europe,
+                        to_europe=to_europe):
+                    self.assertEqual(sale._incoterm_required, result)
+
+    @with_transaction()
+    def test_sale_incoterm_required_same_country(self):
+        "Test incoterm required on sale with same country"
+        pool = Pool()
+        Sale = pool.get('sale.sale')
+        FiscalYear = pool.get('account.fiscalyear')
+        Country = pool.get('country.country')
+
+        country = Mock(spec=Country)
+        sale = Mock(spec=Sale)
+        sale.warehouse.address.country = country
+        sale.shipment_address.country = country
+        type(sale)._incoterm_required = Sale._incoterm_required
+        fiscalyear = Mock(spec=FiscalYear)
+
+        with patch.object(FiscalYear, 'find') as fiscalyear_find:
+            fiscalyear_find.return_value = fiscalyear
+            for extended, europe, result in [
+                    (False, False, False),
+                    (False, True, False),
+                    (True, False, False),
+                    (True, True, False),
+                    (None, False, False),
+                    (None, True, False),
+                    ]:
+                if extended is not None:
+                    fiscalyear_find.side_effect = None
+                    fiscalyear.intrastat_extended = extended
+                else:
+                    fiscalyear_find.side_effect = FiscalYearNotFoundError('')
+                country.is_member.return_value = europe
+                with self.subTest(
+                        extended=extended,
+                        europe=europe):
+                    self.assertEqual(sale._incoterm_required, result)
+
+    @with_transaction()
+    def test_sale_incoterm_required_no_country(self):
+        "Test incoterm required on sale without country"
+        pool = Pool()
+        Sale = pool.get('sale.sale')
+        FiscalYear = pool.get('account.fiscalyear')
+
+        sale = Mock(spec=Sale)
+        sale.warehouse.address.country = None
+        sale.shipment_address.country = None
+        type(sale)._incoterm_required = Sale._incoterm_required
+        fiscalyear = Mock(spec=FiscalYear)
+
+        with patch.object(FiscalYear, 'find') as fiscalyear_find:
+            fiscalyear_find.return_value = fiscalyear
+
+            for extended, result in [
+                    (False, False),
+                    (True, False),
+                    (None, False),
+                    ]:
+                if extended is not None:
+                    fiscalyear_find.side_effect = None
+                    fiscalyear.intrastat_extended = extended
+                else:
+                    fiscalyear_find.side_effect = FiscalYearNotFoundError('')
+                with self.subTest(extended=extended):
+                    self.assertEqual(sale._incoterm_required, result)
+
 
 del ModuleTestCase
diff -r 5bd75486bb5f -r 9b9ff0dd3074 modules/incoterm/tests/test_module.py
--- a/modules/incoterm/tests/test_module.py     Thu Jan 22 13:54:58 2026 +0100
+++ b/modules/incoterm/tests/test_module.py     Fri Jan 30 17:32:18 2026 +0100
@@ -1,7 +1,7 @@
 # This file is part of Tryton.  The COPYRIGHT file at the top level of
 # this repository contains the full copyright notices and license terms.
 
-from unittest.mock import MagicMock
+from unittest.mock import MagicMock, Mock
 
 from trytond.modules.company.tests import CompanyTestMixin
 from trytond.pool import Pool
@@ -32,5 +32,66 @@
         self.assertLessEqual({'incoterm', 'incoterm_location'}, fields)
         self.assertLessEqual(fields, ShipmentOut._fields.keys())
 
+    @with_transaction()
+    def test_sale_incoterm_required(self):
+        "Test incoterm required on sale"
+        pool = Pool()
+        Sale = pool.get('sale.sale')
+        Country = pool.get('country.country')
+
+        from_country = Mock(spec=Country)
+        to_country = Mock(spec=Country)
+        sale = Mock(spec=Sale)
+        sale.warehouse.address.country = from_country
+        sale.shipment_address.country = to_country
+        type(sale)._incoterm_required = Sale._incoterm_required
+
+        for from_europe, to_europe, result in [
+                (False, False, True),
+                (False, True, True),
+                (True, False, True),
+                (True, True, False),
+                ]:
+            from_country.is_member.return_value = from_europe
+            to_country.is_member.return_value = to_europe
+            with self.subTest(
+                    from_europe=from_europe,
+                    to_europe=to_europe):
+                self.assertEqual(sale._incoterm_required, result)
+
+    @with_transaction()
+    def test_sale_incoterm_required_same_country(self):
+        "Test incoterm required on sale with same country"
+        pool = Pool()
+        Sale = pool.get('sale.sale')
+        Country = pool.get('country.country')
+
+        country = Mock(spec=Country)
+        sale = Mock(spec=Sale)
+        sale.warehouse.address.country = country
+        sale.shipment_address.country = country
+        type(sale)._incoterm_required = Sale._incoterm_required
+
+        for europe, result in [
+                (False, False),
+                (True, False),
+                ]:
+            country.is_member.return_value = europe
+            with self.subTest(europe=europe):
+                self.assertEqual(sale._incoterm_required, result)
+
+    @with_transaction()
+    def test_sale_incoterm_required_no_country(self):
+        "Test incoterm required on sale without country"
+        pool = Pool()
+        Sale = pool.get('sale.sale')
+
+        sale = Mock(spec=Sale)
+        sale.warehouse.address.country = None
+        sale.shipment_address.country = None
+        type(sale)._incoterm_required = Sale._incoterm_required
+
+        self.assertFalse(sale._incoterm_required)
+
 
 del ModuleTestCase

Reply via email to