Skip to content

Commit

Permalink
[14.0]intrastat - improved brexit support
Browse files Browse the repository at this point in the history
  • Loading branch information
luc-demeyer committed May 2, 2022
1 parent a8cdd74 commit 2874b76
Show file tree
Hide file tree
Showing 9 changed files with 240 additions and 21 deletions.
1 change: 1 addition & 0 deletions intrastat_base/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
from . import account_fiscal_position
from . import account_fiscal_position_template
from . import account_move
from . import res_partner
67 changes: 67 additions & 0 deletions intrastat_base/models/res_partner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Copyright 2022 Noviat.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import _, api, models
from odoo.exceptions import UserError

XI_COUNTY_NAMES = [
"antrim",
"armagh",
"down",
"fermanagh",
"londonderry",
"tyrone",
"northern ireland",
]

XI_COUNTIES = [
"base.state_uk18", # County Antrim
"base.state_uk19", # County Armagh
"base.state_uk20", # County Down
"base.state_uk22", # County Fermanagh
"base.state_uk23", # County Londonderry
"base.state_uk24", # County Tyrone
"base.state_ie_27", # Antrim
"base.state_ie_28", # Armagh
"base.state_ie_29", # Down
"base.state_ie_30", # Fermanagh
"base.state_ie_31", # Londonderry
"base.state_ie_32", # Tyrone
]


class ResPartner(models.Model):
_inherit = "res.partner"

@api.model
def _get_xi_counties(self):
return [self.env.ref(x) for x in XI_COUNTIES]

@api.model
def _get_xu_counties(self):
uk_counties = self.env.ref("base.uk").state_ids
xu_counties = uk_counties.filtered(lambda r: r not in self._get_xi_counties())
return xu_counties

def _get_intrastat_country_code(self, country=None, state=None):
if self:
self.ensure_one()
country = self.country_id
state = self.state_id
else:
state = state or self.env["res.country.state"]
country = country or state.country_id
if not country:
raise UserError(
_("Programming Error when calling '_get_intrastat_country_code()")
)
cc = country.code
if cc == "GB":
cc = "XU"
if state and cc in ["XU", "IE"]:
if (
state in self._get_xi_counties()
or state.name.lower().strip() in XI_COUNTY_NAMES
):
cc = "XI"
return cc
63 changes: 49 additions & 14 deletions intrastat_product/models/intrastat_product_declaration.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Copyright 2011-2020 Akretion France (http://www.akretion.com)
# Copyright 2009-2021 Noviat (http://www.noviat.com)
# Copyright 2009-2022 Noviat (http://www.noviat.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# @author Luc de Meyer <info@noviat.com>

Expand Down Expand Up @@ -492,21 +492,20 @@ def _get_incoterm(self, inv_line, notedict):
def _get_product_origin_country_code(
self, inv_line, product_origin_country, notedict
):
product_origin_country_code = "QU"
cc = "QU"
if product_origin_country.code:
product_origin_country_code = product_origin_country.code
cc = product_origin_country.code
year = self.year or str(inv_line.move_id.date.year)
if year >= "2021":
if (
hasattr(inv_line.product_id, "origin_state_id")
and inv_line.product_id.origin_state_id
and inv_line.product_id.origin_state_id.name.lower()
== "northern ireland"
):
product_origin_country_code = "XI"
elif inv_line.product_id.origin_country_id.code == "GB":
product_origin_country_code = "XU"
return product_origin_country_code
product_origin_state = getattr(
inv_line.product_id,
"origin_state_id",
self.env["res.country.state"],
)
cc = self.env["res.partner"]._get_intrastat_country_code(
product_origin_country, product_origin_state
)
return cc

def _get_vat(self, inv_line, notedict):
vat = False
Expand Down Expand Up @@ -683,6 +682,9 @@ def _gather_invoices(self, notedict):
partner_country = self._get_partner_country(
inv_line, notedict, eu_countries
)
partner_country_code = (
invoice.commercial_partner_id._get_intrastat_country_code()
)

if inv_intrastat_line:
hs_code = inv_intrastat_line.hs_code_id
Expand Down Expand Up @@ -741,6 +743,7 @@ def _gather_invoices(self, notedict):
"parent_id": self.id,
"invoice_line_id": inv_line.id,
"src_dest_country_id": partner_country.id,
"src_dest_country_code": partner_country_code,
"product_id": inv_line.product_id.id,
"hs_code_id": hs_code.id,
"weight": weight,
Expand Down Expand Up @@ -847,7 +850,7 @@ def action_gather(self):
@api.model
def _group_line_hashcode_fields(self, computation_line):
return {
"country": computation_line.src_dest_country_id.id or False,
"country": computation_line.src_dest_country_code,
"hs_code_id": computation_line.hs_code_id.id or False,
"intrastat_unit": computation_line.intrastat_unit_id.id or False,
"transaction": computation_line.transaction_id.id or False,
Expand All @@ -866,6 +869,7 @@ def group_line_hashcode(self, computation_line):
def _prepare_grouped_fields(self, computation_line, fields_to_sum):
vals = {
"src_dest_country_id": computation_line.src_dest_country_id.id,
"src_dest_country_code": computation_line.src_dest_country_code,
"intrastat_unit_id": computation_line.intrastat_unit_id.id,
"hs_code_id": computation_line.hs_code_id.id,
"transaction_id": computation_line.transaction_id.id,
Expand Down Expand Up @@ -1070,6 +1074,15 @@ class IntrastatProductComputationLine(models.Model):
string="Country",
help="Country of Origin/Destination",
)
src_dest_country_code = fields.Char(
string="Country Code",
compute="_compute_src_dest_country_code",
store=True,
required=True,
readonly=False,
help="2 digit code of country of origin/destination.\n"
"Specify 'XI' for UK Northern Ireland and 'XU' for rest of the UK.",
)
product_id = fields.Many2one(
"product.product", related="invoice_line_id.product_id"
)
Expand Down Expand Up @@ -1129,6 +1142,14 @@ class IntrastatProductComputationLine(models.Model):
incoterm_id = fields.Many2one("account.incoterms", string="Incoterm")
transport_id = fields.Many2one("intrastat.transport_mode", string="Transport Mode")

@api.onchange("src_dest_country_id")
def _onchange_src_dest_country_id(self):
self.src_dest_country_code = self.src_dest_country_id.code
if self.parent_id.year >= "2021":
self.src_dest_country_code = self.env[
"res.partner"
]._get_intrastat_country_code(country=self.src_dest_country_id)

@api.depends("transport_id")
def _compute_check_validity(self):
"""TO DO: logic based upon fields"""
Expand Down Expand Up @@ -1184,6 +1205,12 @@ class IntrastatProductDeclarationLine(models.Model):
string="Country",
help="Country of Origin/Destination",
)
src_dest_country_code = fields.Char(
string="Country Code",
required=True,
help="2 digit code of country of origin/destination.\n"
"Specify 'XI' for UK Northern Ireland and 'XU' for rest of the UK.",
)
hs_code_id = fields.Many2one("hs.code", string="Intrastat Code")
intrastat_unit_id = fields.Many2one(
"intrastat.unit",
Expand Down Expand Up @@ -1226,6 +1253,14 @@ class IntrastatProductDeclarationLine(models.Model):
incoterm_id = fields.Many2one("account.incoterms", string="Incoterm")
transport_id = fields.Many2one("intrastat.transport_mode", string="Transport Mode")

@api.onchange("src_dest_country_id")
def _onchange_src_dest_country_id(self):
self.src_dest_country_code = self.src_dest_country_id.code
if self.parent_id.year >= "2021":
self.src_dest_country_code = self.env[
"res.partner"
]._get_intrastat_country_code(country=self.src_dest_country_id)

@api.constrains("vat")
def _check_vat(self):
for this in self:
Expand Down
4 changes: 2 additions & 2 deletions intrastat_product/report/intrastat_product_report_xls.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2009-2020 Noviat
# Copyright 2009-2022 Noviat
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

import logging
Expand Down Expand Up @@ -60,7 +60,7 @@ def _get_template(self, declaration):
},
"line": {
"type": "string",
"value": self._render("line.src_dest_country_id.name"),
"value": self._render("line.src_dest_country_code"),
},
"width": 28,
},
Expand Down
1 change: 1 addition & 0 deletions intrastat_product/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from . import common_purchase
from . import common_sale
from . import test_intrastat_product
from . import test_brexit
from . import test_company
from . import test_purchase_order
from . import test_sale_order
4 changes: 2 additions & 2 deletions intrastat_product/tests/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def _init_fiscal_position(cls):

@classmethod
def _init_regions(cls):
# Create Belgium Region
# Create Region
cls._create_region()

vals = {
Expand Down Expand Up @@ -75,7 +75,7 @@ def setUpClass(cls):
@classmethod
def _create_region(cls, vals=None):
values = {
"code": "BE_w",
"code": "2",
"country_id": cls.env.ref("base.be").id,
"company_id": cls.env.company.id,
"description": "Belgium Walloon Region",
Expand Down
111 changes: 111 additions & 0 deletions intrastat_product/tests/test_brexit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# Copyright 2022 Noviat.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo.tests import Form, SavepointCase

from .common import IntrastatProductCommon


class TestIntrastatBrexit(IntrastatProductCommon, SavepointCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.inv_obj = cls.env["account.move"]
cls.hs_code_whiskey = cls.env["hs.code"].create(
{
"description": "Whiskey",
"local_code": "22083000",
}
)
cls.product_xi = cls.env["product.product"].create(
{
"name": "Bushmills Original",
"weight": 1.4,
"list_price": 30.0,
"standard_price": 15.0,
"origin_country_id": cls.env.ref("base.uk").id,
"origin_state_id": cls.env.ref("base.state_uk18").id,
"hs_code_id": cls.hs_code_whiskey.id,
}
)
cls.product_xu = cls.env["product.product"].create(
{
"name": "Glenfiddich",
"weight": 1.4,
"list_price": 50.0,
"standard_price": 25.0,
"origin_country_id": cls.env.ref("base.uk").id,
"origin_state_id": cls.env.ref("base.state_uk6").id,
"hs_code_id": cls.hs_code_whiskey.id,
}
)
cls.partner_xi = cls.env["res.partner"].create(
{
"name": "Bushmills Distillery",
"country_id": cls.env.ref("base.uk").id,
"state_id": cls.env.ref("base.state_uk18").id,
"vat": "XI123456782",
"property_account_position_id": cls.position.id,
}
)

def test_brexit_sale(self):
inv_out_xi = self.inv_obj.with_context(default_move_type="out_invoice").create(
{
"partner_id": self.partner_xi.id,
"fiscal_position_id": self.position.id,
}
)
with Form(inv_out_xi) as inv_form:
with inv_form.invoice_line_ids.new() as ail:
ail.product_id = self.product_c3po.product_variant_ids[0]
inv_out_xi.action_post()

self._create_declaration(
{
"declaration_type": "dispatches",
"year": str(inv_out_xi.date.year),
"month": str(inv_out_xi.date.month).zfill(2),
}
)
self.declaration.action_gather()
self.declaration.generate_declaration()
cline = self.declaration.computation_line_ids
dline = self.declaration.declaration_line_ids
self.assertEqual(cline.src_dest_country_code, "XI")
self.assertEqual(dline.src_dest_country_code, "XI")

def test_brexit_purchase(self):
inv_in_xi = self.inv_obj.with_context(default_move_type="in_invoice").create(
{
"partner_id": self.partner_xi.id,
"fiscal_position_id": self.position.id,
}
)
with Form(inv_in_xi) as inv_form:
with inv_form.invoice_line_ids.new() as ail:
ail.product_id = self.product_xi
with inv_form.invoice_line_ids.new() as ail:
ail.product_id = self.product_xu
inv_in_xi.invoice_date = inv_in_xi.date
inv_in_xi.action_post()

self._create_declaration(
{
"declaration_type": "arrivals",
"year": str(inv_in_xi.date.year),
"month": str(inv_in_xi.date.month).zfill(2),
}
)
self.declaration.action_gather()
self.declaration.generate_declaration()
clines = self.declaration.computation_line_ids
cl_xi = clines.filtered(lambda r: r.product_id == self.product_xi)
cl_xu = clines.filtered(lambda r: r.product_id == self.product_xu)
dlines = self.declaration.declaration_line_ids
dl_xi = dlines.filtered(lambda r: r.computation_line_ids == cl_xi)
dl_xu = dlines.filtered(lambda r: r.computation_line_ids == cl_xu)
self.assertEqual(cl_xi.product_origin_country_code, "XI")
self.assertEqual(cl_xu.product_origin_country_code, "XU")
self.assertEqual(dl_xi.product_origin_country_code, "XI")
self.assertEqual(dl_xu.product_origin_country_code, "XU")
6 changes: 5 additions & 1 deletion intrastat_product/views/intrastat_product_declaration.xml
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@
<field name="product_id" />
<field name="hs_code_id" />
<field name="src_dest_country_id" />
<field name="src_dest_country_code" />
<field
name="amount_company_currency"
widget="monetary"
Expand Down Expand Up @@ -278,6 +279,7 @@
<field name="product_id" />
<field name="hs_code_id" />
<field name="src_dest_country_id" />
<field name="src_dest_country_code" />
<field name="amount_company_currency" />
<field name="amount_accessory_cost_company_currency" />
<field name="transaction_id" />
Expand Down Expand Up @@ -322,6 +324,7 @@
/>
<field name="hs_code_id" />
<field name="src_dest_country_id" />
<field name="src_dest_country_code" />
<field
name="amount_company_currency"
widget="monetary"
Expand Down Expand Up @@ -367,7 +370,8 @@
invisible="not context.get('intrastat_product_declaration_line_main_view')"
/>
<field name="hs_code_id" />
<field name="src_dest_country_id" />
<field name="src_dest_country_id" invisible="1" />
<field name="src_dest_country_code" />
<field name="amount_company_currency" />
<field name="transaction_id" />
<field name="weight" />
Expand Down
Loading

0 comments on commit 2874b76

Please sign in to comment.