mirror of
https://github.com/OCA/intrastat-extrastat.git
synced 2025-02-16 17:13:41 +02:00
@@ -3,3 +3,4 @@ from . import res_company
|
|||||||
from . import account_fiscal_position
|
from . import account_fiscal_position
|
||||||
from . import account_fiscal_position_template
|
from . import account_fiscal_position_template
|
||||||
from . import account_move
|
from . import account_move
|
||||||
|
from . import res_partner
|
||||||
|
|||||||
67
intrastat_base/models/res_partner.py
Normal file
67
intrastat_base/models/res_partner.py
Normal file
@@ -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
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# Copyright 2011-2020 Akretion France (http://www.akretion.com)
|
# Copyright 2011-2020 Akretion France (http://www.akretion.com)
|
||||||
# Copyright 2009-2020 Noviat (http://www.noviat.com)
|
# Copyright 2009-2022 Noviat (http://www.noviat.com)
|
||||||
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||||
# @author Luc de Meyer <info@noviat.com>
|
# @author Luc de Meyer <info@noviat.com>
|
||||||
|
|
||||||
@@ -93,6 +93,14 @@ class AccountMove(models.Model):
|
|||||||
if not hs_code:
|
if not hs_code:
|
||||||
return vals
|
return vals
|
||||||
weight, qty = decl_model._get_weight_and_supplunits(line, hs_code, notedict)
|
weight, qty = decl_model._get_weight_and_supplunits(line, hs_code, notedict)
|
||||||
|
product_country = line.product_id.origin_country_id
|
||||||
|
product_state = line.product_id.origin_state_id
|
||||||
|
country = product_country or product_state.country_id
|
||||||
|
product_origin_country_code = "QU"
|
||||||
|
if country:
|
||||||
|
product_origin_country_code = self.env[
|
||||||
|
"res.partner"
|
||||||
|
]._get_intrastat_country_code(product_country, product_state)
|
||||||
vals.update(
|
vals.update(
|
||||||
{
|
{
|
||||||
"invoice_line_id": line.id,
|
"invoice_line_id": line.id,
|
||||||
@@ -100,6 +108,7 @@ class AccountMove(models.Model):
|
|||||||
"transaction_weight": int(weight),
|
"transaction_weight": int(weight),
|
||||||
"transaction_suppl_unit_qty": qty,
|
"transaction_suppl_unit_qty": qty,
|
||||||
"product_origin_country_id": line.product_id.origin_country_id.id,
|
"product_origin_country_id": line.product_id.origin_country_id.id,
|
||||||
|
"product_origin_country_code": product_origin_country_code,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
return vals
|
return vals
|
||||||
@@ -160,11 +169,23 @@ class AccountMoveIntrastatLine(models.Model):
|
|||||||
transaction_weight = fields.Integer(
|
transaction_weight = fields.Integer(
|
||||||
help="Transaction weight in Kg: Quantity x Product Weight"
|
help="Transaction weight in Kg: Quantity x Product Weight"
|
||||||
)
|
)
|
||||||
|
# product_origin_country_id is replaced by product_origin_country_code
|
||||||
|
# this field should be dropped once the localisation modules have been
|
||||||
|
# adapted accordingly
|
||||||
product_origin_country_id = fields.Many2one(
|
product_origin_country_id = fields.Many2one(
|
||||||
comodel_name="res.country",
|
comodel_name="res.country",
|
||||||
string="Country of Origin",
|
string="Country of Origin",
|
||||||
help="Country of origin of the product i.e. product " "'made in ____'.",
|
help="Country of origin of the product i.e. product " "'made in ____'.",
|
||||||
)
|
)
|
||||||
|
product_origin_country_code = fields.Char(
|
||||||
|
string="Country of Origin of the Product",
|
||||||
|
size=2,
|
||||||
|
required=True,
|
||||||
|
default="QU",
|
||||||
|
help="2 digit code of country of origin of the product except for the UK.\n"
|
||||||
|
"Specify 'XI' for UK Northern Ireland and 'XU' for rest of the UK.\n"
|
||||||
|
"Specify 'QU' when the country is unknown.\n",
|
||||||
|
)
|
||||||
|
|
||||||
@api.onchange("invoice_line_id")
|
@api.onchange("invoice_line_id")
|
||||||
def _onchange_move_id(self):
|
def _onchange_move_id(self):
|
||||||
@@ -176,3 +197,18 @@ class AccountMoveIntrastatLine(models.Model):
|
|||||||
("id", "not in", moves.mapped("intrastat_line_ids.invoice_line_id").ids),
|
("id", "not in", moves.mapped("intrastat_line_ids.invoice_line_id").ids),
|
||||||
]
|
]
|
||||||
return {"domain": {"invoice_line_id": dom}}
|
return {"domain": {"invoice_line_id": dom}}
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def create(self, vals):
|
||||||
|
self._format_vals(vals)
|
||||||
|
return super().create(vals)
|
||||||
|
|
||||||
|
def write(self, vals):
|
||||||
|
self._format_vals(vals)
|
||||||
|
return super().write(vals)
|
||||||
|
|
||||||
|
def _format_vals(self, vals):
|
||||||
|
if "product_origin_country_code" in vals:
|
||||||
|
vals["product_origin_country_code"] = (
|
||||||
|
vals["product_origin_country_code"].upper().strip()
|
||||||
|
)
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
# Copyright 2011-2020 Akretion France (http://www.akretion.com)
|
# Copyright 2011-2020 Akretion France (http://www.akretion.com)
|
||||||
# Copyright 2009-2020 Noviat (http://www.noviat.com)
|
# Copyright 2009-2022 Noviat (http://www.noviat.com)
|
||||||
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||||
# @author Luc de Meyer <info@noviat.com>
|
# @author Luc de Meyer <info@noviat.com>
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import warnings
|
||||||
from datetime import date
|
from datetime import date
|
||||||
|
|
||||||
from dateutil.relativedelta import relativedelta
|
from dateutil.relativedelta import relativedelta
|
||||||
@@ -490,8 +491,31 @@ class IntrastatProductDeclaration(models.Model):
|
|||||||
return incoterm
|
return incoterm
|
||||||
|
|
||||||
def _get_product_origin_country(self, inv_line, notedict):
|
def _get_product_origin_country(self, inv_line, notedict):
|
||||||
|
warnings.warn(
|
||||||
|
"Method '_get_product_origin_country' is deprecated, "
|
||||||
|
"please use '_get_product_origin_country_code'.",
|
||||||
|
DeprecationWarning,
|
||||||
|
)
|
||||||
return inv_line.product_id.origin_country_id
|
return inv_line.product_id.origin_country_id
|
||||||
|
|
||||||
|
def _get_product_origin_country_code(
|
||||||
|
self, inv_line, product_origin_country, notedict
|
||||||
|
):
|
||||||
|
cc = "QU"
|
||||||
|
if product_origin_country.code:
|
||||||
|
cc = product_origin_country.code
|
||||||
|
year = self.year or str(inv_line.move_id.date.year)
|
||||||
|
if year >= "2021":
|
||||||
|
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):
|
def _get_vat(self, inv_line, notedict):
|
||||||
vat = False
|
vat = False
|
||||||
inv = inv_line.move_id
|
inv = inv_line.move_id
|
||||||
@@ -667,6 +691,9 @@ class IntrastatProductDeclaration(models.Model):
|
|||||||
partner_country = self._get_partner_country(
|
partner_country = self._get_partner_country(
|
||||||
inv_line, notedict, eu_countries
|
inv_line, notedict, eu_countries
|
||||||
)
|
)
|
||||||
|
partner_country_code = (
|
||||||
|
invoice.commercial_partner_id._get_intrastat_country_code()
|
||||||
|
)
|
||||||
|
|
||||||
if inv_intrastat_line:
|
if inv_intrastat_line:
|
||||||
hs_code = inv_intrastat_line.hs_code_id
|
hs_code = inv_intrastat_line.hs_code_id
|
||||||
@@ -708,9 +735,13 @@ class IntrastatProductDeclaration(models.Model):
|
|||||||
product_origin_country = (
|
product_origin_country = (
|
||||||
inv_intrastat_line.product_origin_country_id
|
inv_intrastat_line.product_origin_country_id
|
||||||
)
|
)
|
||||||
|
product_origin_country_code = (
|
||||||
|
inv_intrastat_line.product_origin_country_code
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
product_origin_country = self._get_product_origin_country(
|
product_origin_country = inv_line.product_id.origin_country_id
|
||||||
inv_line, notedict
|
product_origin_country_code = self._get_product_origin_country_code(
|
||||||
|
inv_line, product_origin_country, notedict
|
||||||
)
|
)
|
||||||
|
|
||||||
region = self._get_region(inv_line, notedict)
|
region = self._get_region(inv_line, notedict)
|
||||||
@@ -721,6 +752,7 @@ class IntrastatProductDeclaration(models.Model):
|
|||||||
"parent_id": self.id,
|
"parent_id": self.id,
|
||||||
"invoice_line_id": inv_line.id,
|
"invoice_line_id": inv_line.id,
|
||||||
"src_dest_country_id": partner_country.id,
|
"src_dest_country_id": partner_country.id,
|
||||||
|
"src_dest_country_code": partner_country_code,
|
||||||
"product_id": inv_line.product_id.id,
|
"product_id": inv_line.product_id.id,
|
||||||
"hs_code_id": hs_code.id,
|
"hs_code_id": hs_code.id,
|
||||||
"weight": weight,
|
"weight": weight,
|
||||||
@@ -729,6 +761,7 @@ class IntrastatProductDeclaration(models.Model):
|
|||||||
"amount_accessory_cost_company_currency": 0.0,
|
"amount_accessory_cost_company_currency": 0.0,
|
||||||
"transaction_id": intrastat_transaction.id,
|
"transaction_id": intrastat_transaction.id,
|
||||||
"product_origin_country_id": product_origin_country.id or False,
|
"product_origin_country_id": product_origin_country.id or False,
|
||||||
|
"product_origin_country_code": product_origin_country_code,
|
||||||
"region_id": region and region.id or False,
|
"region_id": region and region.id or False,
|
||||||
"vat": vat,
|
"vat": vat,
|
||||||
}
|
}
|
||||||
@@ -826,14 +859,13 @@ class IntrastatProductDeclaration(models.Model):
|
|||||||
@api.model
|
@api.model
|
||||||
def _group_line_hashcode_fields(self, computation_line):
|
def _group_line_hashcode_fields(self, computation_line):
|
||||||
return {
|
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,
|
"hs_code_id": computation_line.hs_code_id.id or False,
|
||||||
"intrastat_unit": computation_line.intrastat_unit_id.id or False,
|
"intrastat_unit": computation_line.intrastat_unit_id.id or False,
|
||||||
"transaction": computation_line.transaction_id.id or False,
|
"transaction": computation_line.transaction_id.id or False,
|
||||||
"transport": computation_line.transport_id.id or False,
|
"transport": computation_line.transport_id.id or False,
|
||||||
"region": computation_line.region_id.id or False,
|
"region": computation_line.region_id.id or False,
|
||||||
"product_origin_country": computation_line.product_origin_country_id.id
|
"product_origin_country": computation_line.product_origin_country_code,
|
||||||
or False,
|
|
||||||
"vat": computation_line.vat or False,
|
"vat": computation_line.vat or False,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -846,6 +878,7 @@ class IntrastatProductDeclaration(models.Model):
|
|||||||
def _prepare_grouped_fields(self, computation_line, fields_to_sum):
|
def _prepare_grouped_fields(self, computation_line, fields_to_sum):
|
||||||
vals = {
|
vals = {
|
||||||
"src_dest_country_id": computation_line.src_dest_country_id.id,
|
"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,
|
"intrastat_unit_id": computation_line.intrastat_unit_id.id,
|
||||||
"hs_code_id": computation_line.hs_code_id.id,
|
"hs_code_id": computation_line.hs_code_id.id,
|
||||||
"transaction_id": computation_line.transaction_id.id,
|
"transaction_id": computation_line.transaction_id.id,
|
||||||
@@ -853,6 +886,7 @@ class IntrastatProductDeclaration(models.Model):
|
|||||||
"region_id": computation_line.region_id.id,
|
"region_id": computation_line.region_id.id,
|
||||||
"parent_id": computation_line.parent_id.id,
|
"parent_id": computation_line.parent_id.id,
|
||||||
"product_origin_country_id": computation_line.product_origin_country_id.id,
|
"product_origin_country_id": computation_line.product_origin_country_id.id,
|
||||||
|
"product_origin_country_code": computation_line.product_origin_country_code,
|
||||||
"amount_company_currency": 0.0,
|
"amount_company_currency": 0.0,
|
||||||
"vat": computation_line.vat,
|
"vat": computation_line.vat,
|
||||||
}
|
}
|
||||||
@@ -1049,6 +1083,15 @@ class IntrastatProductComputationLine(models.Model):
|
|||||||
string="Country",
|
string="Country",
|
||||||
help="Country of Origin/Destination",
|
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_id = fields.Many2one(
|
||||||
"product.product", related="invoice_line_id.product_id"
|
"product.product", related="invoice_line_id.product_id"
|
||||||
)
|
)
|
||||||
@@ -1086,16 +1129,37 @@ class IntrastatProductComputationLine(models.Model):
|
|||||||
"intrastat.transaction", string="Intrastat Transaction"
|
"intrastat.transaction", string="Intrastat Transaction"
|
||||||
)
|
)
|
||||||
region_id = fields.Many2one("intrastat.region", string="Intrastat Region")
|
region_id = fields.Many2one("intrastat.region", string="Intrastat Region")
|
||||||
# extended declaration
|
# product_origin_country_id is replaced by product_origin_country_code
|
||||||
incoterm_id = fields.Many2one("account.incoterms", string="Incoterm")
|
# this field should be dropped once the localisation modules have been
|
||||||
transport_id = fields.Many2one("intrastat.transport_mode", string="Transport Mode")
|
# adapted accordingly
|
||||||
product_origin_country_id = fields.Many2one(
|
product_origin_country_id = fields.Many2one(
|
||||||
"res.country",
|
"res.country",
|
||||||
string="Country of Origin of the Product",
|
string="Country of Origin of the Product",
|
||||||
help="Country of origin of the product i.e. product 'made in ____'",
|
help="Country of origin of the product i.e. product 'made in ____'",
|
||||||
)
|
)
|
||||||
|
product_origin_country_code = fields.Char(
|
||||||
|
string="Country of Origin of the Product",
|
||||||
|
size=2,
|
||||||
|
required=True,
|
||||||
|
default="QU",
|
||||||
|
help="2 digit code of country of origin of the product except for the UK.\n"
|
||||||
|
"Specify 'XI' for UK Northern Ireland and 'XU' for rest of the UK.\n"
|
||||||
|
"Specify 'QU' when the country is unknown.\n",
|
||||||
|
)
|
||||||
vat = fields.Char(string="VAT Number")
|
vat = fields.Char(string="VAT Number")
|
||||||
|
|
||||||
|
# extended declaration
|
||||||
|
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")
|
@api.depends("transport_id")
|
||||||
def _compute_check_validity(self):
|
def _compute_check_validity(self):
|
||||||
"""TO DO: logic based upon fields"""
|
"""TO DO: logic based upon fields"""
|
||||||
@@ -1151,6 +1215,12 @@ class IntrastatProductDeclarationLine(models.Model):
|
|||||||
string="Country",
|
string="Country",
|
||||||
help="Country of Origin/Destination",
|
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")
|
hs_code_id = fields.Many2one("hs.code", string="Intrastat Code")
|
||||||
intrastat_unit_id = fields.Many2one(
|
intrastat_unit_id = fields.Many2one(
|
||||||
"intrastat.unit",
|
"intrastat.unit",
|
||||||
@@ -1172,15 +1242,35 @@ class IntrastatProductDeclarationLine(models.Model):
|
|||||||
"intrastat.transaction", string="Intrastat Transaction"
|
"intrastat.transaction", string="Intrastat Transaction"
|
||||||
)
|
)
|
||||||
region_id = fields.Many2one("intrastat.region", string="Intrastat Region")
|
region_id = fields.Many2one("intrastat.region", string="Intrastat Region")
|
||||||
# extended declaration
|
# product_origin_country_id is replaced by product_origin_country_code
|
||||||
incoterm_id = fields.Many2one("account.incoterms", string="Incoterm")
|
# this field should be dropped once the localisation modules have been
|
||||||
transport_id = fields.Many2one("intrastat.transport_mode", string="Transport Mode")
|
# adapted accordingly
|
||||||
product_origin_country_id = fields.Many2one(
|
product_origin_country_id = fields.Many2one(
|
||||||
"res.country",
|
"res.country",
|
||||||
string="Country of Origin of the Product",
|
string="Country of Origin of the Product",
|
||||||
help="Country of origin of the product i.e. product 'made in ____'",
|
help="Country of origin of the product i.e. product 'made in ____'",
|
||||||
)
|
)
|
||||||
|
product_origin_country_code = fields.Char(
|
||||||
|
string="Country of Origin of the Product",
|
||||||
|
size=2,
|
||||||
|
required=True,
|
||||||
|
default="QU",
|
||||||
|
help="2 digit code of country of origin of the product except for the UK.\n"
|
||||||
|
"Specify 'XI' for UK Northern Ireland and 'XU' for rest of the UK.\n"
|
||||||
|
"Specify 'QU' when the country is unknown.\n",
|
||||||
|
)
|
||||||
vat = fields.Char(string="VAT Number")
|
vat = fields.Char(string="VAT Number")
|
||||||
|
# extended declaration
|
||||||
|
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")
|
@api.constrains("vat")
|
||||||
def _check_vat(self):
|
def _check_vat(self):
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Copyright 2009-2020 Noviat
|
# Copyright 2009-2022 Noviat
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
@@ -60,7 +60,7 @@ class IntrastatProductDeclarationXlsx(models.AbstractModel):
|
|||||||
},
|
},
|
||||||
"line": {
|
"line": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"value": self._render("line.src_dest_country_id.name"),
|
"value": self._render("line.src_dest_country_code"),
|
||||||
},
|
},
|
||||||
"width": 28,
|
"width": 28,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ from . import common
|
|||||||
from . import common_purchase
|
from . import common_purchase
|
||||||
from . import common_sale
|
from . import common_sale
|
||||||
from . import test_intrastat_product
|
from . import test_intrastat_product
|
||||||
|
from . import test_brexit
|
||||||
from . import test_company
|
from . import test_company
|
||||||
from . import test_purchase_order
|
from . import test_purchase_order
|
||||||
from . import test_sale_order
|
from . import test_sale_order
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ class IntrastatProductCommon(IntrastatCommon):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _init_regions(cls):
|
def _init_regions(cls):
|
||||||
# Create Belgium Region
|
# Create Region
|
||||||
cls._create_region()
|
cls._create_region()
|
||||||
|
|
||||||
vals = {
|
vals = {
|
||||||
@@ -75,7 +75,7 @@ class IntrastatProductCommon(IntrastatCommon):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def _create_region(cls, vals=None):
|
def _create_region(cls, vals=None):
|
||||||
values = {
|
values = {
|
||||||
"code": "BE_w",
|
"code": "2",
|
||||||
"country_id": cls.env.ref("base.be").id,
|
"country_id": cls.env.ref("base.be").id,
|
||||||
"company_id": cls.env.company.id,
|
"company_id": cls.env.company.id,
|
||||||
"description": "Belgium Walloon Region",
|
"description": "Belgium Walloon Region",
|
||||||
|
|||||||
126
intrastat_product/tests/test_brexit.py
Normal file
126
intrastat_product/tests/test_brexit.py
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
# 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")
|
||||||
|
|
||||||
|
def test_brexit_invoice_intrastat_details(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
|
||||||
|
inv_in_xi.invoice_date = inv_in_xi.date
|
||||||
|
inv_in_xi.compute_intrastat_lines()
|
||||||
|
ilines = inv_in_xi.intrastat_line_ids
|
||||||
|
self.assertEqual(ilines.product_origin_country_code, "XI")
|
||||||
@@ -47,10 +47,7 @@
|
|||||||
<field name="transaction_suppl_unit_qty" />
|
<field name="transaction_suppl_unit_qty" />
|
||||||
<field name="hs_code_id" />
|
<field name="hs_code_id" />
|
||||||
<field name="transaction_weight" />
|
<field name="transaction_weight" />
|
||||||
<field
|
<field name="product_origin_country_code" />
|
||||||
name="product_origin_country_id"
|
|
||||||
options="{'no_create': True, 'no_open': True}"
|
|
||||||
/>
|
|
||||||
</tree>
|
</tree>
|
||||||
</field>
|
</field>
|
||||||
</page>
|
</page>
|
||||||
|
|||||||
@@ -224,6 +224,7 @@
|
|||||||
<field name="product_id" />
|
<field name="product_id" />
|
||||||
<field name="hs_code_id" />
|
<field name="hs_code_id" />
|
||||||
<field name="src_dest_country_id" />
|
<field name="src_dest_country_id" />
|
||||||
|
<field name="src_dest_country_code" />
|
||||||
<field
|
<field
|
||||||
name="amount_company_currency"
|
name="amount_company_currency"
|
||||||
widget="monetary"
|
widget="monetary"
|
||||||
@@ -250,7 +251,12 @@
|
|||||||
/>
|
/>
|
||||||
<field name="incoterm_id" invisible="1" />
|
<field name="incoterm_id" invisible="1" />
|
||||||
<field name="region_id" invisible="1" />
|
<field name="region_id" invisible="1" />
|
||||||
|
<!-- TODO: remove product_origin_country_id after update of localization modules -->
|
||||||
<field name="product_origin_country_id" invisible="1" />
|
<field name="product_origin_country_id" invisible="1" />
|
||||||
|
<field
|
||||||
|
name="product_origin_country_code"
|
||||||
|
attrs="{'invisible': [('declaration_type', '!=', 'arrivals')]}"
|
||||||
|
/>
|
||||||
<field name="vat" />
|
<field name="vat" />
|
||||||
<field name="partner_id" />
|
<field name="partner_id" />
|
||||||
<field name="invoice_id" />
|
<field name="invoice_id" />
|
||||||
@@ -273,6 +279,7 @@
|
|||||||
<field name="product_id" />
|
<field name="product_id" />
|
||||||
<field name="hs_code_id" />
|
<field name="hs_code_id" />
|
||||||
<field name="src_dest_country_id" />
|
<field name="src_dest_country_id" />
|
||||||
|
<field name="src_dest_country_code" />
|
||||||
<field name="amount_company_currency" />
|
<field name="amount_company_currency" />
|
||||||
<field name="amount_accessory_cost_company_currency" />
|
<field name="amount_accessory_cost_company_currency" />
|
||||||
<field name="transaction_id" />
|
<field name="transaction_id" />
|
||||||
@@ -287,11 +294,17 @@
|
|||||||
attrs="{'required': [('reporting_level', '=', 'extended')], 'invisible': [('reporting_level', '!=', 'extended')]}"
|
attrs="{'required': [('reporting_level', '=', 'extended')], 'invisible': [('reporting_level', '!=', 'extended')]}"
|
||||||
/>
|
/>
|
||||||
<field name="region_id" invisible="1" />
|
<field name="region_id" invisible="1" />
|
||||||
|
<!-- TODO: remove product_origin_country_id after update of localization modules -->
|
||||||
<field
|
<field
|
||||||
name="product_origin_country_id"
|
name="product_origin_country_id"
|
||||||
invisible="1"
|
invisible="1"
|
||||||
string="Product C/O"
|
string="Product C/O"
|
||||||
/>
|
/>
|
||||||
|
<field
|
||||||
|
name="product_origin_country_code"
|
||||||
|
attrs="{'column_invisible': [('parent.declaration_type', '=', 'arrivals')]}"
|
||||||
|
string="Product C/O"
|
||||||
|
/>
|
||||||
<field name="vat" />
|
<field name="vat" />
|
||||||
<field name="invoice_id" />
|
<field name="invoice_id" />
|
||||||
<field name="declaration_type" invisible="1" />
|
<field name="declaration_type" invisible="1" />
|
||||||
@@ -311,6 +324,7 @@
|
|||||||
/>
|
/>
|
||||||
<field name="hs_code_id" />
|
<field name="hs_code_id" />
|
||||||
<field name="src_dest_country_id" />
|
<field name="src_dest_country_id" />
|
||||||
|
<field name="src_dest_country_code" />
|
||||||
<field
|
<field
|
||||||
name="amount_company_currency"
|
name="amount_company_currency"
|
||||||
widget="monetary"
|
widget="monetary"
|
||||||
@@ -332,7 +346,12 @@
|
|||||||
/>
|
/>
|
||||||
<field name="region_id" invisible="1" />
|
<field name="region_id" invisible="1" />
|
||||||
<field name="incoterm_id" invisible="1" />
|
<field name="incoterm_id" invisible="1" />
|
||||||
|
<!-- TODO: remove product_origin_country_id after update of localization modules -->
|
||||||
<field name="product_origin_country_id" invisible="1" />
|
<field name="product_origin_country_id" invisible="1" />
|
||||||
|
<field
|
||||||
|
name="product_origin_country_code"
|
||||||
|
attrs="{'invisible': [('declaration_type', '!=', 'arrivals')]}"
|
||||||
|
/>
|
||||||
<field name="vat" />
|
<field name="vat" />
|
||||||
</group>
|
</group>
|
||||||
<group name="computation" string="Related Transactions">
|
<group name="computation" string="Related Transactions">
|
||||||
@@ -351,7 +370,8 @@
|
|||||||
invisible="not context.get('intrastat_product_declaration_line_main_view')"
|
invisible="not context.get('intrastat_product_declaration_line_main_view')"
|
||||||
/>
|
/>
|
||||||
<field name="hs_code_id" />
|
<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="amount_company_currency" />
|
||||||
<field name="transaction_id" />
|
<field name="transaction_id" />
|
||||||
<field name="weight" />
|
<field name="weight" />
|
||||||
@@ -365,11 +385,17 @@
|
|||||||
/>
|
/>
|
||||||
<field name="region_id" invisible="1" />
|
<field name="region_id" invisible="1" />
|
||||||
<field name="incoterm_id" invisible="1" />
|
<field name="incoterm_id" invisible="1" />
|
||||||
|
<!-- TODO: remove product_origin_country_id after update of localization modules -->
|
||||||
<field
|
<field
|
||||||
name="product_origin_country_id"
|
name="product_origin_country_id"
|
||||||
invisible="1"
|
invisible="1"
|
||||||
string="Product C/O"
|
string="Product C/O"
|
||||||
/>
|
/>
|
||||||
|
<field
|
||||||
|
name="product_origin_country_code"
|
||||||
|
attrs="{'column_invisible': [('parent.declaration_type', '=', 'arrivals')]}"
|
||||||
|
string="Product C/O"
|
||||||
|
/>
|
||||||
<field name="vat" />
|
<field name="vat" />
|
||||||
</tree>
|
</tree>
|
||||||
</field>
|
</field>
|
||||||
|
|||||||
@@ -23,10 +23,20 @@ class ProductTemplate(models.Model):
|
|||||||
"and configure the H.S. code on the product category.",
|
"and configure the H.S. code on the product category.",
|
||||||
)
|
)
|
||||||
origin_country_id = fields.Many2one(
|
origin_country_id = fields.Many2one(
|
||||||
"res.country",
|
comodel_name="res.country",
|
||||||
string="Country of Origin",
|
string="Country of Origin",
|
||||||
help="Country of origin of the product i.e. product " "'made in ____'.",
|
help="Country of origin of the product i.e. product " "'made in ____'.",
|
||||||
)
|
)
|
||||||
|
origin_state_id = fields.Many2one(
|
||||||
|
comodel_name="res.country.state",
|
||||||
|
string="Country State of Origin",
|
||||||
|
domain="[('country_id', '=?', origin_country_id)]",
|
||||||
|
help="Country State of origin of the product.\n"
|
||||||
|
"This field is used for the Intrastat declaration, "
|
||||||
|
"selecting one of the Northern Ireland counties will set the code 'XI' "
|
||||||
|
"for products from the United Kingdom whereas code 'XU' "
|
||||||
|
"will be used for the other UK counties.",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ProductProduct(models.Model):
|
class ProductProduct(models.Model):
|
||||||
|
|||||||
@@ -20,6 +20,10 @@
|
|||||||
name="origin_country_id"
|
name="origin_country_id"
|
||||||
attrs="{'invisible': [('type', '=', 'service')]}"
|
attrs="{'invisible': [('type', '=', 'service')]}"
|
||||||
/>
|
/>
|
||||||
|
<field
|
||||||
|
name="origin_state_id"
|
||||||
|
attrs="{'invisible': [('type', '=', 'service')]}"
|
||||||
|
/>
|
||||||
</field>
|
</field>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|||||||
Reference in New Issue
Block a user