Merge PR #214 into 16.0

Signed-off-by alexis-via
This commit is contained in:
OCA-git-bot
2023-06-09 14:34:34 +00:00
64 changed files with 10517 additions and 0 deletions

View File

@@ -0,0 +1,165 @@
=================
Intrastat Product
=================
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fintrastat--extrastat-lightgray.png?logo=github
:target: https://github.com/OCA/intrastat-extrastat/tree/14.0/intrastat_product
:alt: OCA/intrastat-extrastat
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/intrastat-extrastat-14-0/intrastat-extrastat-14-0-intrastat_product
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
:target: https://runbot.odoo-community.org/runbot/227/14.0
:alt: Try me on Runbot
|badge1| |badge2| |badge3| |badge4| |badge5|
This module contains common objects and fields for the Intrastat Product reporting.
It should be used in combination with country-specific Intrastat Product reporting modules
such as:
- *l10n_fr_intrastat_product*:
the module for the *Déclaration d'Echange de Biens* (DEB) for France
- *l10n_be_intrastat_product*:
the module for the Intrastat Product Declaration for Belgium
These country-specific modules can be found in the OCA localization for those countries.
**Table of contents**
.. contents::
:local:
Installation
============
This module is NOT compatible with the *account_intrastat* module from Odoo Enterprise.
Configuration
=============
By default the intrastat declaration is generated based upon the product record master data.
Hence unexpected results may occur in case this master data is not accurate,
e.g. wrong or missing weight, country of origin, ...
|
This can be corrected by changing the appropriate fields when analysing the intrastat declaration
but this can be challenging in case of large transaction volumes and especially in the specific use
case where the product weight cannot be encoded correctly on the product records (e.g. products with variable weight).
|
It is possible to allow encoding the intrastat transaction details on the purchase/sale invoice
via the "intrastat_product.group_invoice_intrastat_transaction_detail" usability group.
Usage
=====
This module is used in combination with the country-specific
localization module(s).
**Coding guidelines for localization module:**
We recommend to start by copying an existing module, e.g. l10n_be_intrastat_product
and adapt the code for the specific needs of your country.
* Declaration Object
Create a new class as follows:
.. code-block:: python
class L10nCcIntrastatProductDeclaration(models.Model):
_name = 'l10n.cc.intrastat.product.declaration'
_description = "Intrastat Product Declaration for YourCountry"
_inherit = ['intrastat.product.declaration', 'mail.thread']
whereby cc = your country code
* Computation & Declaration Lines
Create also new objects inheriting from the Computation and Declaration Line Objects
so that you can add methods or customise the methods from the base modules (make a PR when
the customization or new method is required for multiple countries).
Adapt also the parent_id fields of the newly created objects
(cf. l10n_be_intrastat_product as example).
* XML Files: Menu, Action, Views
Cf. l10n_be_istrastat_product as example, replace "be" by your Country Code.
**Other functionality added by this module:**
* Compute the Intrastat Lines in an invoice.
For this, your user needs to be in the "Technical / Invoice Intrastat Transaction Details" group.
Go to the "Intrastat transaction details" tab and press **Compute**
Known issues / Roadmap
======================
The declaration is based upon the invoices of the corresponding tax declaration period.
An option to generate the intrastat declaration based upon the dates of the physical movements of goods is currently not available.
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/intrastat-extrastat/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
`feedback <https://github.com/OCA/intrastat-extrastat/issues/new?body=module:%20intrastat_product%0Aversion:%2014.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Do not contact contributors directly about support or help with technical issues.
Credits
=======
Authors
~~~~~~~
* ACSONE SA/NV
* brain-tec AG
* Akretion
* Noviat
Contributors
~~~~~~~~~~~~
* Alexis de Lattre, Akretion <alexis.delattre@akretion.com>
* Luc De Meyer, Noviat <info@noviat.com>
* Denis Roussel <denis.roussel@acsone.eu>
* Tecnativa <www.tecnativa.com>:
* João Marques
* Víctor Martínez
Maintainers
~~~~~~~~~~~
This module is maintained by the OCA.
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
This module is part of the `OCA/intrastat-extrastat <https://github.com/OCA/intrastat-extrastat/tree/14.0/intrastat_product>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View File

@@ -0,0 +1,4 @@
from . import models
from . import report
from . import wizards
from .hooks import pre_init_hook

View File

@@ -0,0 +1,49 @@
# Copyright 2011-2020 Akretion (http://www.akretion.com)
# Copyright 2009-2020 Noviat (http://www.noviat.com)
# Copyright 2018-2020 brain-tec AG (http://www.braintec-group.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# @author Luc de Meyer <info@noviat.com>
# @author Kumar Aberer <kumar.aberer@braintec-group.com>
{
"name": "Intrastat Product",
"version": "16.0.1.0.0",
"category": "Intrastat",
"license": "AGPL-3",
"summary": "Base module for Intrastat Product",
"author": "ACSONE SA/NV, brain-tec AG, Akretion, Noviat, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/intrastat-extrastat",
"depends": [
"intrastat_base",
"product_harmonized_system",
"sale_stock",
"purchase_stock",
"report_xlsx_helper",
],
"excludes": ["account_intrastat"],
"external_dependencies": {"python": ["python-stdnum>=1.16"]},
"data": [
"security/intrastat_security.xml",
"security/ir.model.access.csv",
"report/report.xml",
"views/hs_code.xml",
"views/intrastat_region.xml",
"views/intrastat_unit.xml",
"views/intrastat_transaction.xml",
"views/intrastat_transport_mode.xml",
"views/intrastat_product_declaration.xml",
"views/res_config_settings.xml",
"views/res_partner_view.xml",
"views/account_move.xml",
"views/sale_order.xml",
"views/stock_warehouse.xml",
"views/report_invoice.xml",
"wizards/intrastat_result_view.xml",
"data/intrastat_transport_mode.xml",
"data/intrastat_unit.xml",
"data/intrastat_transaction.xml",
],
"demo": ["demo/intrastat_demo.xml"],
"installable": True,
"pre_init_hook": "pre_init_hook",
}

View File

@@ -0,0 +1,110 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo noupdate="1">
<!-- Source: https://eur-lex.europa.eu/legal-content/EN/TXT/HTML/?uri=CELEX:32020R1197&from=EN#d1e32-7-1
ANNEX I
Part C. Classifications
Table 1. Nature of transaction breakdown
-->
<record id="intrastat_transaction_11" model="intrastat.transaction">
<field name="code">11</field>
<field name="description">B2B sale/purchase</field>
</record>
<record id="intrastat_transaction_12" model="intrastat.transaction">
<field name="code">12</field>
<field name="description">B2C sale/purchase (incl. distance sale)</field>
</record>
<record id="intrastat_transaction_21" model="intrastat.transaction">
<field name="code">21</field>
<field name="description">Return of goods (free of charge)</field>
</record>
<record id="intrastat_transaction_22" model="intrastat.transaction">
<field name="code">22</field>
<field
name="description"
>Replacement for returned goods (free of charge)</field>
</record>
<record id="intrastat_transaction_23" model="intrastat.transaction">
<field name="code">23</field>
<field
name="description"
>Replacement (e.g. under warranty) for goods not being returned</field>
</record>
<record id="intrastat_transaction_31" model="intrastat.transaction">
<field name="code">31</field>
<field
name="description"
>Movements to/from a warehouse (excluding call-off and consignment stock)</field>
</record>
<record id="intrastat_transaction_32" model="intrastat.transaction">
<field name="code">32</field>
<field
name="description"
>Supply for sale on approval or after trial (including call-off and consignment stock)</field>
</record>
<record id="intrastat_transaction_33" model="intrastat.transaction">
<field name="code">33</field>
<field name="description">Financial leasing</field>
</record>
<record id="intrastat_transaction_34" model="intrastat.transaction">
<field name="code">34</field>
<field
name="description"
>Transactions involving transfer of ownership without financial compensation</field>
</record>
<record id="intrastat_transaction_41" model="intrastat.transaction">
<field name="code">41</field>
<field
name="description"
>Transactions with a view to processing under contract (no change of ownership). Goods expected to return to the initial Member State/country of export</field>
</record>
<record id="intrastat_transaction_42" model="intrastat.transaction">
<field name="code">42</field>
<field
name="description"
>Transactions with a view to processing under contract (no change of ownership). Goods not expected to return to the initial Member State/country of export</field>
</record>
<record id="intrastat_transaction_51" model="intrastat.transaction">
<field name="code">51</field>
<field
name="description"
>Transactions following processing under contract (not involving change of ownership). Goods returning to the initial Member State/country of export.</field>
</record>
<record id="intrastat_transaction_52" model="intrastat.transaction">
<field name="code">52</field>
<field
name="description"
>Transactions following processing under contract (not involving change of ownership). Goods not returning to the initial Member State/country of export.</field>
</record>
<!-- intrastat.transaction that start with "6" are
"Particular transactions recorded for national purposes"
so they should be supplied by coutry-specific modules -->
<record id="intrastat_transaction_71" model="intrastat.transaction">
<field name="code">71</field>
<field
name="description"
>Release of goods for free circulation in a Member State with a subsequent export to another Member State</field>
</record>
<record id="intrastat_transaction_72" model="intrastat.transaction">
<field name="code">72</field>
<field
name="description"
>Transportation of goods from one Member State to another Member State to place the goods under the export procedure</field>
</record>
<record id="intrastat_transaction_80" model="intrastat.transaction">
<field name="code">80</field>
<field
name="description"
>Transactions involving the supply of building materials and technical equipment under a general construction or civil engineering contract for which no separate invoicing of the goods is required and an invoice for the total contract is issued</field>
</record>
<record id="intrastat_transaction_91" model="intrastat.transaction">
<field name="code">91</field>
<field
name="description"
>Hire, loan, and operational leasing longer than 24 months</field>
</record>
<record id="intrastat_transaction_99" model="intrastat.transaction">
<field name="code">99</field>
<field name="description">Other</field>
</record>
</odoo>

View File

@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo noupdate="1">
<record id="intrastat_transport_1" model="intrastat.transport_mode">
<field name="code">1</field>
<field name="name">Sea</field>
<field
name="description"
>Sea Transport (including wagons, motor vehicles, trailers, semi-trailers and lighters on board of a ship)</field>
</record>
<record id="intrastat_transport_2" model="intrastat.transport_mode">
<field name="code">2</field>
<field name="name">Rail</field>
<field
name="description"
>Railway transport (including lorries on railway wagons)</field>
</record>
<record id="intrastat_transport_3" model="intrastat.transport_mode">
<field name="code">3</field>
<field name="name">Road</field>
<field name="description">Road Transport</field>
</record>
<record id="intrastat_transport_4" model="intrastat.transport_mode">
<field name="code">4</field>
<field name="name">Air</field>
<field name="description">Air Transport</field>
</record>
<record id="intrastat_transport_5" model="intrastat.transport_mode">
<field name="code">5</field>
<field name="name">Post</field>
<field name="description">Postal consignments</field>
</record>
<record id="intrastat_transport_7" model="intrastat.transport_mode">
<field name="code">7</field>
<field name="name">Fixed installations</field>
<field
name="description"
>Fixed transport installations (e.g. pipelines, high-tension cables)</field>
</record>
<record id="intrastat_transport_8" model="intrastat.transport_mode">
<field name="code">8</field>
<field name="name">Inland waterway</field>
<field name="description">Inland waterway transport</field>
</record>
<record id="intrastat_transport_9" model="intrastat.transport_mode">
<field name="code">9</field>
<field name="name">Own propulsion</field>
<field
name="description"
>Own propulsion (imported or exported means of transport crossing the border under their own power, e.g. aircraft, lorries, boats, etc.)</field>
</record>
<!-- Set default value to Road trp on main company -->
<record id="base.main_company" model="res.company">
<field name="intrastat_transport_id" ref="intrastat_transport_3" />
</record>
</odoo>

View File

@@ -0,0 +1,122 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo noupdate="1">
<!-- Extracted from the Official Journal of the European Union -->
<record id="intrastat_unit_c_k" model="intrastat.unit">
<field name="name">c/k</field>
<field name="description">Carats - 1 metric carat = 2 × 10exp(4) kg</field>
</record>
<record id="intrastat_unit_ce_el" model="intrastat.unit">
<field name="name">ce/el</field>
<field name="description">Number of cells</field>
</record>
<record id="intrastat_unit_ct_l" model="intrastat.unit">
<field name="name">ct/l</field>
<field name="description">Carrying capacity in tonnes</field>
</record>
<record id="intrastat_unit_g" model="intrastat.unit">
<field name="name">g</field>
<field name="description">Gram</field>
<field name="uom_id" ref="uom.product_uom_gram" />
</record>
<record id="intrastat_unit_gi_FS" model="intrastat.unit">
<field name="name">gi F/S</field>
<field name="description">Gram of fissile isotopes</field>
</record>
<record id="intrastat_unit_kg_H2O2" model="intrastat.unit">
<field name="name">kg H2O2</field>
<field name="description">Kilogram of hydrogen peroxide</field>
</record>
<record id="intrastat_unit_kg_K2O" model="intrastat.unit">
<field name="name">kg K2O</field>
<field name="description">Kilogram of potassium oxide</field>
</record>
<record id="intrastat_unit_kg_KOH" model="intrastat.unit">
<field name="name">kg KOH</field>
<field
name="description"
>Kilogram of potassium hydroxide (caustic potash)</field>
</record>
<record id="intrastat_unit_kg_ma" model="intrastat.unit">
<field name="name">kg met.am.</field>
<field name="description">Kilogram of methylamines</field>
</record>
<record id="intrastat_unit_kg_N" model="intrastat.unit">
<field name="name">kg N</field>
<field name="description">Kilogram of nitrogen</field>
</record>
<record id="intrastat_unit_kg_NaOH" model="intrastat.unit">
<field name="name">kg NaOH</field>
<field name="description">Kilogram of sodium hydroxide (caustic soda)</field>
</record>
<record id="intrastat_unit_kg_net_eda" model="intrastat.unit">
<field name="name">kg/net eda</field>
<field name="description">Kilogram drained net weight</field>
</record>
<record id="intrastat_unit_kg_P2O5" model="intrastat.unit">
<field name="name">kg P2O5</field>
<field name="description">Kilogram of diphosphorus pentaoxide</field>
</record>
<record id="intrastat_unit_kg_90_pct_sdt" model="intrastat.unit">
<field name="name">kg 90 pct sdt</field>
<field name="description">Kilogram of substance 90 % dry</field>
</record>
<record id="intrastat_unit_kg_U" model="intrastat.unit">
<field name="name">kg U</field>
<field name="description">Kilogram of uranium</field>
</record>
<record id="intrastat_unit_1000_kWh" model="intrastat.unit">
<field name="name">1000 kWh</field>
<field name="description">Thousand kilowatt hours</field>
</record>
<record id="intrastat_unit_l" model="intrastat.unit">
<field name="name">l</field>
<field name="description">Litre</field>
<field name="uom_id" ref="uom.product_uom_litre" />
</record>
<record id="intrastat_unit_1000l" model="intrastat.unit">
<field name="name">1000 l</field>
<field name="description">Thousand litres</field>
</record>
<record id="intrastat_unit_l_alc_100_pct" model="intrastat.unit">
<field name="name">l alc. 100 pct</field>
<field name="description">Litre pure (100 %) alcohol</field>
</record>
<record id="intrastat_unit_m" model="intrastat.unit">
<field name="name">m</field>
<field name="description">Metre</field>
<field name="uom_id" ref="uom.product_uom_meter" />
</record>
<record id="intrastat_unit_m2" model="intrastat.unit">
<field name="name">m2</field>
<field name="description">Square metre</field>
</record>
<record id="intrastat_unit_m3" model="intrastat.unit">
<field name="name">m3</field>
<field name="description">Cubic metre</field>
</record>
<record id="intrastat_unit_1000m3" model="intrastat.unit">
<field name="name">1000 m3</field>
<field name="description">Thousand cubic metres</field>
</record>
<record id="intrastat_unit_pa" model="intrastat.unit">
<field name="name">pa</field>
<field name="description">Number of pairs</field>
</record>
<record id="intrastat_unit_pce" model="intrastat.unit">
<field name="name">items</field>
<field name="description">Number of items</field>
<field name="uom_id" ref="uom.product_uom_unit" />
</record>
<record id="intrastat_unit_100pce" model="intrastat.unit">
<field name="name">100 items</field>
<field name="description">Hundred items</field>
</record>
<record id="intrastat_unit_1000pce" model="intrastat.unit">
<field name="name">1000 items</field>
<field name="description">Thousand items</field>
</record>
<record id="intrastat_unit_TJ" model="intrastat.unit">
<field name="name">TJ</field>
<field name="description">Terajoule (gross calorific value)</field>
</record>
</odoo>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
© 2011-2017 Akretion (http://www.akretion.com/)
@author Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo noupdate="1">
<record id="product_harmonized_system.84715000" model="hs.code">
<field name="intrastat_unit_id" ref="intrastat_unit_pce" />
</record>
<record id="product_harmonized_system.84717050" model="hs.code">
<field name="intrastat_unit_id" ref="intrastat_unit_pce" />
</record>
<record id="base.main_company" model="res.company">
<field name="intrastat_arrivals">extended</field>
<field name="intrastat_dispatches">extended</field>
<field name="incoterm_id" ref="account.incoterm_DAP" />
<field name="intrastat_transport_id" ref="intrastat_transport_3" />
</record>
</odoo>

View File

@@ -0,0 +1,35 @@
# Copyright 2022 Stefan Rijnhart <stefan@opener.amsterdam>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
import logging
def pre_init_hook(cr):
"""Prepopulate stored computed fields for faster installation"""
logger = logging.getLogger(__name__)
logger.info("Prepopulating stored computed fields")
cr.execute(
"""
alter table account_move
add column if not exists src_dest_country_id integer;
"""
)
cr.execute(
"""
with countries as (
select am.id as move_id,
coalesce(
rps.country_id,
rp.country_id,
rpc.country_id
) as country_id
from account_move am
left join res_partner rps on rps.id = am.partner_shipping_id
join res_partner rp on rp.id = am.partner_id
join res_company rc on rc.id = am.company_id
join res_partner rpc on rpc.id = rc.partner_id
)
update account_move am
set src_dest_country_id = countries.country_id
from countries where am.id = countries.move_id;
"""
)

1793
intrastat_product/i18n/es.po Normal file

File diff suppressed because it is too large Load Diff

1849
intrastat_product/i18n/fr.po Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,11 @@
from . import res_company
from . import res_partner
from . import account_move
from . import hs_code
from . import intrastat_product_declaration
from . import intrastat_region
from . import intrastat_transaction
from . import intrastat_transport_mode
from . import intrastat_unit
from . import sale_order
from . import stock_warehouse

View File

@@ -0,0 +1,213 @@
# Copyright 2011-2020 Akretion France (http://www.akretion.com)
# Copyright 2009-2022 Noviat (http://www.noviat.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# @author Luc de Meyer <info@noviat.com>
from odoo import api, fields, models
class AccountMove(models.Model):
_inherit = "account.move"
intrastat_transaction_id = fields.Many2one(
comodel_name="intrastat.transaction",
string="Intrastat Transaction Type",
ondelete="restrict",
tracking=True,
check_company=True,
help="Intrastat Nature of Transaction",
domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]",
)
intrastat_transport_id = fields.Many2one(
comodel_name="intrastat.transport_mode",
string="Intrastat Transport Mode",
ondelete="restrict",
)
src_dest_country_id = fields.Many2one(
comodel_name="res.country",
string="Origin/Destination Country",
compute="_compute_src_dest_country_id",
store=True,
help="Destination country for dispatches. Origin country for arrivals.",
)
src_dest_region_id = fields.Many2one(
comodel_name="intrastat.region",
string="Origin/Destination Region",
default=lambda self: self.env.company.intrastat_region_id,
help="Origin region for dispatches, destination region for "
"arrivals. This field is used for the Intrastat Declaration.",
ondelete="restrict",
)
intrastat = fields.Char(
string="Intrastat Declaration", related="company_id.intrastat"
)
intrastat_line_ids = fields.One2many(
comodel_name="account.move.intrastat.line",
inverse_name="move_id",
string="Intrastat Declaration Details",
)
@api.depends("partner_shipping_id.country_id", "partner_id.country_id")
def _compute_src_dest_country_id(self):
for inv in self:
country = inv.partner_shipping_id.country_id or inv.partner_id.country_id
if not country:
country = inv.company_id.country_id
inv.src_dest_country_id = country.id
def compute_intrastat_lines(self):
"""
Compute the Intrastat Lines so that they can be modified
when encoding the Customer/Supplier Invoice.
"""
self.mapped("intrastat_line_ids").unlink()
for inv in self:
if inv.move_type not in (
"out_invoice",
"out_refund",
"in_invoice",
"in_refund",
):
continue
line_vals = []
for line in inv.invoice_line_ids:
vals = self._get_intrastat_line_vals(line)
if vals:
line_vals.append(vals)
if line_vals:
inv.intrastat_line_ids = [(0, 0, x) for x in line_vals]
def _get_intrastat_line_vals(self, line):
vals = {}
notedict = {
"note": "",
"line_nbr": 0,
}
decl_model = self.env["intrastat.product.declaration"]
if decl_model._is_product(line):
hs_code = line.product_id.get_hs_code_recursively()
if not hs_code:
return vals
weight, qty = decl_model._get_weight_and_supplunits(line, hs_code, notedict)
vals.update(
{
"invoice_line_id": line.id,
"hs_code_id": hs_code.id,
"transaction_weight": weight,
"transaction_suppl_unit_qty": qty,
"product_origin_country_id": line.product_id.origin_country_id.id,
}
)
return vals
def _prepare_intrastat_line_info(self, line):
is_intrastat_line = bool(line._name == "account.move.intrastat.line")
product = line.product_id
return {
"product_id": product,
"hs_code_id": (
line.hs_code_id if is_intrastat_line else product.hs_code_id
),
"weight": (
line.transaction_weight
if is_intrastat_line
else self._get_intrastat_line_vals(line)["transaction_weight"]
),
"origin_country_id": (
line.product_origin_country_id
if is_intrastat_line
else product.origin_country_id
),
}
def _get_intrastat_lines_info(self):
"""We obtain a list of information that we will need to group at the end by
product and sum weight.
"""
res = {}
for line in (
self.invoice_line_ids.filtered(
lambda x: x.product_id.hs_code_id and x.product_id.origin_country_id
)
if not self.intrastat_line_ids
else self.intrastat_line_ids
):
res.setdefault(line.product_id.id, {"weight": 0})
vals = self._prepare_intrastat_line_info(line)
weight = vals.pop("weight")
res[line.product_id.id].update(vals)
res[line.product_id.id]["weight"] += weight
return res.values()
class AccountMoveLine(models.Model):
_inherit = "account.move.line"
hs_code_id = fields.Many2one(
comodel_name="hs.code",
compute="_compute_hs_code_id",
string="Intrastat Code",
)
def _compute_hs_code_id(self):
for rec in self:
intrastat_line = self.move_id.intrastat_line_ids.filtered(
lambda r: r.invoice_line_id == rec
)
rec.hs_code_id = (
intrastat_line.hs_code_id or rec.product_id.get_hs_code_recursively()
)
class AccountMoveIntrastatLine(models.Model):
_name = "account.move.intrastat.line"
_description = "Intrastat declaration details"
_order = "sequence"
move_id = fields.Many2one(
comodel_name="account.move",
string="Invoice",
ondelete="cascade",
required=True,
)
invoice_line_id = fields.Many2one(
comodel_name="account.move.line",
string="Invoice Line",
ondelete="cascade",
required=True,
)
sequence = fields.Integer(related="invoice_line_id.sequence", store=True)
product_id = fields.Many2one(
comodel_name="product.product",
string="Product",
related="invoice_line_id.product_id",
)
quantity = fields.Float(related="invoice_line_id.quantity")
transaction_suppl_unit_qty = fields.Float(
help="Transaction quantity in Intrastat Supplementary Unit"
)
hs_code_id = fields.Many2one(
comodel_name="hs.code",
string="Intrastat Code",
ondelete="restrict",
required=True,
)
transaction_weight = fields.Integer(
help="Transaction weight in Kg: Quantity x Product Weight"
)
product_origin_country_id = fields.Many2one(
comodel_name="res.country",
string="Country of Origin of the Product",
help="Country of origin of the product i.e. product " "'made in ____'.",
)
@api.onchange("invoice_line_id")
def _onchange_move_id(self):
moves = self.mapped("move_id")
dom = [
("exclude_from_invoice_tab", "=", False),
("display_type", "=", False),
("id", "in", moves.mapped("invoice_line_ids").ids),
("id", "not in", moves.mapped("intrastat_line_ids.invoice_line_id").ids),
]
return {"domain": {"invoice_line_id": dom}}

View File

@@ -0,0 +1,14 @@
# Copyright 2011-2020 Akretion (http://www.akretion.com)
# Copyright 2009-2020 Noviat (http://www.noviat.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# @author Luc de Meyer <info@noviat.com>
from odoo import fields, models
class HSCode(models.Model):
_inherit = "hs.code"
intrastat_unit_id = fields.Many2one(
comodel_name="intrastat.unit", string="Intrastat Supplementary Unit"
)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,22 @@
# Copyright 2009-2020 Noviat nv/sa (www.noviat.com).
# @author Luc de Meyer <info@noviat.com>
from odoo import fields, models
class IntrastatRegion(models.Model):
_name = "intrastat.region"
_description = "Intrastat Region"
_sql_constraints = [
(
"intrastat_region_code_unique",
"UNIQUE(code, country_id)", # TODO add company_id ?
"Code must be unique.",
)
]
code = fields.Char(required=True)
country_id = fields.Many2one(comodel_name="res.country", required=True)
name = fields.Char(translate=True)
description = fields.Char()
company_id = fields.Many2one("res.company", default=lambda self: self.env.company)

View File

@@ -0,0 +1,39 @@
# Copyright 2011-2020 Akretion France (http://www.akretion.com)
# Copyright 2009-2020 Noviat (http://www.noviat.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# @author Luc de Meyer <info@noviat.com>
from textwrap import shorten
from odoo import api, fields, models
class IntrastatTransaction(models.Model):
_name = "intrastat.transaction"
_description = "Intrastat Transaction"
_rec_name = "code"
_order = "code"
_sql_constraints = [
(
"intrastat_transaction_code_unique",
"UNIQUE(code, company_id)",
"Code must be unique.",
)
]
code = fields.Char(required=True)
description = fields.Text()
# intrastat.transaction are shared among companies by default
company_id = fields.Many2one("res.company")
active = fields.Boolean(default=True)
@api.depends("code", "description")
def name_get(self):
res = []
for this in self:
name = this.code
if this.description:
name += " " + this.description
name = shorten(name, 55)
res.append((this.id, name))
return res

View File

@@ -0,0 +1,27 @@
# Copyright 2011-2017 Akretion (http://www.akretion.com)
# Copyright 2009-2019 Noviat (http://www.noviat.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# @author Luc de Meyer <info@noviat.com>
from odoo import api, fields, models
class IntrastatTransportMode(models.Model):
_name = "intrastat.transport_mode"
_description = "Intrastat Transport Mode"
_order = "code"
_sql_constraints = [
("intrastat_transport_code_unique", "UNIQUE(code)", "Code must be unique.")
]
code = fields.Char(required=True)
name = fields.Char(required=True, translate=True)
description = fields.Char(translate=True)
@api.depends("name", "code")
def name_get(self):
res = []
for mode in self:
name = "{}. {}".format(mode.code, mode.name)
res.append((mode.id, name))
return res

View File

@@ -0,0 +1,21 @@
# Copyright 2011-2020 Akretion (http://www.akretion.com)
# Copyright 2009-2020 Noviat (http://www.noviat.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# @author Luc de Meyer <info@noviat.com>
from odoo import fields, models
class IntrastatUnit(models.Model):
_name = "intrastat.unit"
_description = "Intrastat Supplementary Units"
name = fields.Char(required=True)
description = fields.Char(required=True)
uom_id = fields.Many2one(
comodel_name="uom.uom",
string="Regular UoM",
help="Select the regular Unit of Measure of Odoo that corresponds "
"to this Intrastat Supplementary Unit.",
)
active = fields.Boolean(default=True)

View File

@@ -0,0 +1,72 @@
# Copyright 2011-2017 Akretion (http://www.akretion.com)
# Copyright 2009-2020 Noviat (http://www.noviat.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# @author Luc de Meyer <info@noviat.com>
from odoo import api, fields, models
class ResCompany(models.Model):
_inherit = "res.company"
intrastat_arrivals = fields.Selection(
selection="_intrastat_arrivals",
string="Arrivals",
default="extended",
required=True,
)
intrastat_dispatches = fields.Selection(
selection="_intrastat_dispatches",
string="Dispatches",
default="extended",
required=True,
)
intrastat_transport_id = fields.Many2one(
comodel_name="intrastat.transport_mode",
string="Default Transport Mode",
ondelete="restrict",
)
intrastat = fields.Char(
string="Intrastat Declaration",
store=True,
readonly=True,
compute="_compute_intrastat",
)
intrastat_region_id = fields.Many2one(
comodel_name="intrastat.region", string="Default Intrastat Region"
)
intrastat_accessory_costs = fields.Boolean(
string="Include Accessory Costs in Fiscal Value of Product"
)
@api.model
def _intrastat_arrivals(self):
return [
("exempt", "Exempt"),
("standard", "Standard"),
("extended", "Extended"),
]
@api.model
def _intrastat_dispatches(self):
return [
("exempt", "Exempt"),
("standard", "Standard"),
("extended", "Extended"),
]
@api.depends("intrastat_arrivals", "intrastat_dispatches")
def _compute_intrastat(self):
for this in self:
if (
this.intrastat_arrivals == "exempt"
and this.intrastat_dispatches == "exempt"
):
this.intrastat = "exempt"
elif (
this.intrastat_arrivals == "extended"
or this.intrastat_dispatches == "extended"
):
this.intrastat = "extended"
else:
this.intrastat = "standard"

View File

@@ -0,0 +1,16 @@
# Copyright 2022 Tecnativa - Víctor Martínez
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models
class ResParter(models.Model):
_inherit = "res.partner"
invoice_intrastat_detail = fields.Boolean(
string="Show intrastat details in invoice report"
)
@api.model
def _commercial_fields(self):
return super()._commercial_fields() + ["invoice_intrastat_detail"]

View File

@@ -0,0 +1,27 @@
# Copyright 2010-2020 Akretion France (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models
class SaleOrder(models.Model):
_inherit = "sale.order"
intrastat_transport_id = fields.Many2one(
comodel_name="intrastat.transport_mode",
string="Transport Mode",
help="This information is used in Intrastat reports",
)
intrastat = fields.Selection(
string="Intrastat Declaration", related="company_id.intrastat_dispatches"
)
def _prepare_invoice(self):
"""Copy destination country to invoice"""
vals = super()._prepare_invoice()
if self.intrastat_transport_id:
vals["intrastat_transport_id"] = self.intrastat_transport_id.id
if self.warehouse_id.region_id:
vals["src_dest_region_id"] = self.warehouse_id.region_id.id
return vals

View File

@@ -0,0 +1,27 @@
# Copyright 2009-2020 Noviat nv/sa (www.noviat.com).
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# @author Luc de Meyer <info@noviat.com>
from odoo import fields, models
class StockWarehouse(models.Model):
_inherit = "stock.warehouse"
region_id = fields.Many2one(
comodel_name="intrastat.region", string="Intrastat Region"
)
class StockLocation(models.Model):
_inherit = "stock.location"
def get_intrastat_region(self):
self.ensure_one()
warehouse = self.env["stock.warehouse"].search(
[("lot_stock_id", "parent_of", self.ids), ("region_id", "!=", False)],
limit=1,
)
if warehouse:
return warehouse.region_id
return None

View File

@@ -0,0 +1,14 @@
By default the intrastat declaration is generated based upon the product record master data.
Hence unexpected results may occur in case this master data is not accurate,
e.g. wrong or missing weight, country of origin, ...
|
This can be corrected by changing the appropriate fields when analysing the intrastat declaration
but this can be challenging in case of large transaction volumes and especially in the specific use
case where the product weight cannot be encoded correctly on the product records (e.g. products with variable weight).
|
It is possible to allow encoding the intrastat transaction details on the purchase/sale invoice
via the "intrastat_product.group_invoice_intrastat_transaction_detail" usability group.

View File

@@ -0,0 +1,7 @@
* Alexis de Lattre, Akretion <alexis.delattre@akretion.com>
* Luc De Meyer, Noviat <info@noviat.com>
* Denis Roussel <denis.roussel@acsone.eu>
* Tecnativa <www.tecnativa.com>:
* João Marques
* Víctor Martínez

View File

@@ -0,0 +1,11 @@
This module contains common objects and fields for the Intrastat Product reporting.
It should be used in combination with country-specific Intrastat Product reporting modules
such as:
- *l10n_fr_intrastat_product*:
the module for the *Déclaration d'Echange de Biens* (DEB) for France
- *l10n_be_intrastat_product*:
the module for the Intrastat Product Declaration for Belgium
These country-specific modules can be found in the OCA localization for those countries.

View File

@@ -0,0 +1 @@
This module is NOT compatible with the *account_intrastat* module from Odoo Enterprise.

View File

@@ -0,0 +1,3 @@
The declaration is based upon the invoices of the corresponding tax declaration period.
An option to generate the intrastat declaration based upon the dates of the physical movements of goods is currently not available.

View File

@@ -0,0 +1,39 @@
This module is used in combination with the country-specific
localization module(s).
**Coding guidelines for localization module:**
We recommend to start by copying an existing module, e.g. l10n_be_intrastat_product
and adapt the code for the specific needs of your country.
* Declaration Object
Create a new class as follows:
.. code-block:: python
class L10nCcIntrastatProductDeclaration(models.Model):
_name = 'l10n.cc.intrastat.product.declaration'
_description = "Intrastat Product Declaration for YourCountry"
_inherit = ['intrastat.product.declaration', 'mail.thread']
whereby cc = your country code
* Computation & Declaration Lines
Create also new objects inheriting from the Computation and Declaration Line Objects
so that you can add methods or customise the methods from the base modules (make a PR when
the customization or new method is required for multiple countries).
Adapt also the parent_id fields of the newly created objects
(cf. l10n_be_intrastat_product as example).
* XML Files: Menu, Action, Views
Cf. l10n_be_istrastat_product as example, replace "be" by your Country Code.
**Other functionality added by this module:**
* Compute the Intrastat Lines in an invoice.
For this, your user needs to be in the "Technical / Invoice Intrastat Transaction Details" group.
Go to the "Intrastat transaction details" tab and press **Compute**

View File

@@ -0,0 +1 @@
from . import intrastat_product_report_xls

View File

@@ -0,0 +1,289 @@
# Copyright 2009-2022 Noviat
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import logging
from odoo import _, models
from odoo.addons.report_xlsx_helper.report.report_xlsx_format import (
FORMATS,
XLS_HEADERS,
)
_logger = logging.getLogger(__name__)
IR_TRANSLATION_NAME = "intrastat.product.report"
class IntrastatProductDeclarationXlsx(models.AbstractModel):
_name = "report.intrastat_product.product_declaration_xls"
_inherit = "report.report_xlsx.abstract"
_description = "Intrastat declaration"
def _get_template(self, declaration):
"""
Return a dictionary that contains columns specifications
see: report_xlsx_helper / _write_line() method
"""
template = {
"product": {
"header": {"type": "string", "value": _("Product")},
"line": {
"value": self._render("line.product_id and line.product_id.name")
},
"width": 36,
},
"product_origin_country_code": {
"header": {"type": "string", "value": _("Product C/O Code")},
"line": {
"type": "string",
"value": self._render("line.product_origin_country_code or ''"),
},
"width": 10,
},
"product_origin_country": {
"header": {"type": "string", "value": _("Product C/O")},
"line": {
"type": "string",
"value": self._render("line.product_origin_country_id.name or ''"),
},
"width": 28,
},
"hs_code": {
"header": {"type": "string", "value": _("Intrastat Code")},
"line": {
"type": "string",
"value": self._render("line.hs_code_id.local_code"),
},
"width": 14,
},
"src_dest_country_code": {
"header": {
"type": "string",
"value": _("Country Code of Origin/Destination"),
},
"line": {
"type": "string",
"value": self._render("line.src_dest_country_code"),
},
"width": 10,
},
"src_dest_country": {
"header": {
"type": "string",
"value": _("Country of Origin/Destination"),
},
"line": {
"type": "string",
"value": self._render("line.src_dest_country_id.name"),
},
"width": 28,
},
"amount_company_currency": {
"header": {
"type": "string",
"value": _("Fiscal Value"),
"format": FORMATS["format_theader_yellow_right"],
},
"line": {
"type": "number",
"value": self._render("line.amount_company_currency"),
"format": FORMATS["format_tcell_amount_right"],
},
"width": 18,
},
"accessory_cost": {
"header": {
"type": "string",
"value": _("Accessory Costs"),
"format": FORMATS["format_theader_yellow_right"],
},
"line": {
"type": "number",
"value": self._render(
"line.amount_accessory_cost_company_currency"
),
"format": FORMATS["format_tcell_amount_right"],
},
"width": 18,
},
"transaction_code": {
"header": {
"type": "string",
"value": _("Intrastat Transaction code"),
},
"line": {"value": self._render("line.transaction_id.code")},
"width": 10,
},
"transaction": {
"header": {"type": "string", "value": _("Intrastat Transaction")},
"line": {"value": self._render("line.transaction_id.display_name")},
"width": 36,
},
"weight": {
"header": {
"type": "string",
"value": _("Weight"),
"format": FORMATS["format_theader_yellow_right"],
},
"line": {
"type": "number",
"value": self._render("line.weight"),
"format": FORMATS["format_tcell_amount_right"],
},
"width": 18,
},
"suppl_unit_qty": {
"header": {
"type": "string",
"value": _("Suppl. Unit Qty"),
"format": FORMATS["format_theader_yellow_right"],
},
"line": {
# we don't specify a type here and rely on the
# report_xlsx_helper type detection to use
# write_string when suppl_unit_qty is zero
"value": self._render("line.suppl_unit_qty or ''"),
"format": FORMATS["format_tcell_amount_right"],
},
"width": 18,
},
"suppl_unit": {
"header": {"type": "string", "value": _("Suppl. Unit")},
"line": {"value": self._render("line.intrastat_unit_id.name or ''")},
"width": 14,
},
"incoterm": {
"header": {"type": "string", "value": _("Incoterm")},
"line": {"value": self._render("line.incoterm_id.name or ''")},
"width": 14,
},
"transport_code": {
"header": {"type": "string", "value": _("Transport Mode Code")},
"line": {"value": self._render("line.transport_id.code or ''")},
"width": 10,
},
"transport": {
"header": {"type": "string", "value": _("Transport Mode")},
"line": {"value": self._render("line.transport_id.name or ''")},
"width": 14,
},
"region": {
"header": {"type": "string", "value": _("Intrastat Region")},
"line": {"value": self._render("line.region_id.name or ''")},
"width": 28,
},
"region_code": {
"header": {"type": "string", "value": _("Intrastat Region Code")},
"line": {"value": self._render("line.region_code or ''")},
"width": 10,
},
"vat": {
"header": {"type": "string", "value": _("VAT")},
"line": {"value": self._render("line.vat or ''")},
"width": 20,
},
"partner_id": {
"header": {"type": "string", "value": _("Partner")},
"line": {"value": self._render("line.partner_id.display_name or ''")},
"width": 28,
},
"invoice": {
"header": {"type": "string", "value": _("Invoice")},
"line": {"value": self._render("line.invoice_id.name")},
"width": 18,
},
}
template.update(declaration._xls_template())
return template
def _get_ws_params(self, wb, data, declarations):
template = self._get_template(declarations)
res = []
wanted_list_computation = declarations._xls_computation_line_fields()
wanted_list_declaration = declarations._xls_declaration_line_fields()
for declaration in declarations:
dname = declaration.display_name
res += [
{
"ws_name": "%s %s" % (dname, _("comput.")),
"generate_ws_method": "_intrastat_report_computation",
"title": "%s : %s" % (dname, _("Computation Lines")),
"wanted_list": wanted_list_computation,
"col_specs": template,
},
{
"ws_name": "%s %s" % (dname, _("decl.")),
"generate_ws_method": "_intrastat_report_declaration",
"title": "%s : %s" % (dname, _("Declaration Lines")),
"wanted_list": wanted_list_declaration,
"col_specs": template,
},
]
return res
def _report_title(self, ws, row_pos, ws_params, data, declaration):
return self._write_ws_title(ws, row_pos, ws_params)
def _empty_report(self, ws, row_pos, ws_params, data, declaration, report):
if report == "computation":
lines = _("Computation Lines")
else:
lines = _("Declaration Lines")
no_entries = (
_("No") + " " + lines + " " + _("for period %s") % declaration.year_month
)
ws.write_string(row_pos, 0, no_entries, FORMATS["format_left_bold"])
def _intrastat_report_computation(self, workbook, ws, ws_params, data, declaration):
report = "computation"
lines = declaration.computation_line_ids
self._intrastat_report(
workbook, ws, ws_params, data, declaration, lines, report
)
def _intrastat_report_declaration(self, workbook, ws, ws_params, data, declaration):
report = "declaration"
lines = declaration.declaration_line_ids
self._intrastat_report(
workbook, ws, ws_params, data, declaration, lines, report
)
def _intrastat_report(
self, workbook, ws, ws_params, data, declaration, lines, report
):
ws.set_landscape()
ws.fit_to_pages(1, 0)
ws.set_header(XLS_HEADERS["xls_headers"]["standard"])
ws.set_footer(XLS_HEADERS["xls_footers"]["standard"])
self._set_column_width(ws, ws_params)
row_pos = 0
row_pos = self._report_title(ws, row_pos, ws_params, data, declaration)
if not lines:
return self._empty_report(ws, row_pos, ws_params, data, declaration, report)
row_pos = self._write_line(
ws,
row_pos,
ws_params,
col_specs_section="header",
default_format=FORMATS["format_theader_yellow_left"],
)
ws.freeze_panes(row_pos, 0)
for line in lines:
row_pos = self._write_line(
ws,
row_pos,
ws_params,
col_specs_section="line",
render_space={"line": line},
default_format=FORMATS["format_tcell_left"],
)

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
Copyright 2023 Akretion France (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="intrastat_product_xlsx_report" model="ir.actions.report">
<field name="name">Excel Export</field>
<field name="model">intrastat.product.declaration</field>
<field name="report_type">xlsx</field>
<field name="report_name">intrastat_product.product_declaration_xls</field>
<field name="report_file">intrastat_product.product_declaration_xls</field>
<field
name="print_report_name"
>'intrastat-%s-%s%s' % (object.year_month, object.declaration_type, object.state == 'draft' and '-draft' or '')</field>
<field name="binding_model_id" ref="model_intrastat_product_declaration" />
</record>
</odoo>

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<data noupdate="0">
<record id="group_invoice_intrastat_transaction_details" model="res.groups">
<field name="name">Invoice Intrastat Transaction Details</field>
<field
name="comment"
>Allow to encode Intrastat Transaction Details on Invoices</field>
<field name="category_id" ref="base.module_category_hidden" />
</record>
</data>
<data noupdate="1">
<record id="intrastat_transaction_company_rule" model="ir.rule">
<field name="name">Intrastat Transaction Company rule</field>
<field name="model_id" ref="model_intrastat_transaction" />
<field
name="domain_force"
>['|', ('company_id', '=', False), ('company_id', 'in', company_ids)]</field>
</record>
<record id="intrastat_region_company_rule" model="ir.rule">
<field name="name">Intrastat Region Company rule</field>
<field name="model_id" ref="model_intrastat_region" />
<field
name="domain_force"
>['|', ('company_id', '=', False), ('company_id', 'in', company_ids)]</field>
</record>
<record id="intrastat_product_declaration_company_rule" model="ir.rule">
<field name="name">Intrastat Product Declaration Company rule</field>
<field name="model_id" ref="model_intrastat_product_declaration" />
<field
name="domain_force"
>['|', ('company_id', '=', False), ('company_id', 'in', company_ids)]</field>
</record>
</data>
</odoo>

View File

@@ -0,0 +1,18 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_intrastat_unit_read,Read access on Intrastat Supplementary Units to everybody,model_intrastat_unit,,1,0,0,0
access_intrastat_unit_full,Full access on Intrastat Supplementary Units to Finance manager,model_intrastat_unit,account.group_account_manager,1,1,1,1
access_intrastat_transaction_read,Read access on Intrastat Transaction Types to everybody,model_intrastat_transaction,,1,0,0,0
access_intrastat_transaction_full,Full access on Intrastat Transaction Types to Finance manager,model_intrastat_transaction,account.group_account_manager,1,1,1,1
access_intrastat_transport_mode_read,Read access on Intrastat Transport Modes to everybody,model_intrastat_transport_mode,,1,0,0,0
access_intrastat_transport_mode_full,Full access on Intrastat Transport Modes to Finance manager,model_intrastat_transport_mode,account.group_account_manager,1,1,1,1
access_intrastat_region_read,Read access on Intrastat Regions,model_intrastat_region,,1,0,0,0
access_intrastat_region_full,Full access on Intrastat Regions,model_intrastat_region,account.group_account_manager,1,1,1,1
access_hs_code_financial_mgr_full,Full access on H.S. Code to financial mgr,product_harmonized_system.model_hs_code,account.group_account_manager,1,1,1,1
access_read_sale_move_intrastat_line,Read access to Sale User on Invoice Intrastat Lines,model_account_move_intrastat_line,sales_team.group_sale_salesman,1,0,0,0
access_read_purchase_move_intrastat_line,Read access to Purchase User on Invoice Intrastat Lines,model_account_move_intrastat_line,purchase.group_purchase_user,1,0,0,0
access_read_account_move_intrastat_line,Read access on Invoice Intrastat Lines,model_account_move_intrastat_line,account.group_account_readonly,1,0,0,0
access_account_move_intrastat_line,Full access on Invoice Intrastat Lines,model_account_move_intrastat_line,account.group_account_invoice,1,1,1,1
access_intrastat_product_declaration,Full access on Intrastat Product Declarations to Accountant,model_intrastat_product_declaration,account.group_account_user,1,1,1,1
access_intrastat_product_computation_line,Full access on Intrastat Product Computation Lines to Accountant,model_intrastat_product_computation_line,account.group_account_user,1,1,1,1
access_intrastat_product_declaration_line,Full access on Intrastat Product Declaration Lines to Accountant,model_intrastat_product_declaration_line,account.group_account_user,1,1,1,1
access_intrastat_result_view,Access on intrastat.result.view,model_intrastat_result_view,account.group_account_user,1,1,1,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_intrastat_unit_read Read access on Intrastat Supplementary Units to everybody model_intrastat_unit 1 0 0 0
3 access_intrastat_unit_full Full access on Intrastat Supplementary Units to Finance manager model_intrastat_unit account.group_account_manager 1 1 1 1
4 access_intrastat_transaction_read Read access on Intrastat Transaction Types to everybody model_intrastat_transaction 1 0 0 0
5 access_intrastat_transaction_full Full access on Intrastat Transaction Types to Finance manager model_intrastat_transaction account.group_account_manager 1 1 1 1
6 access_intrastat_transport_mode_read Read access on Intrastat Transport Modes to everybody model_intrastat_transport_mode 1 0 0 0
7 access_intrastat_transport_mode_full Full access on Intrastat Transport Modes to Finance manager model_intrastat_transport_mode account.group_account_manager 1 1 1 1
8 access_intrastat_region_read Read access on Intrastat Regions model_intrastat_region 1 0 0 0
9 access_intrastat_region_full Full access on Intrastat Regions model_intrastat_region account.group_account_manager 1 1 1 1
10 access_hs_code_financial_mgr_full Full access on H.S. Code to financial mgr product_harmonized_system.model_hs_code account.group_account_manager 1 1 1 1
11 access_read_sale_move_intrastat_line Read access to Sale User on Invoice Intrastat Lines model_account_move_intrastat_line sales_team.group_sale_salesman 1 0 0 0
12 access_read_purchase_move_intrastat_line Read access to Purchase User on Invoice Intrastat Lines model_account_move_intrastat_line purchase.group_purchase_user 1 0 0 0
13 access_read_account_move_intrastat_line Read access on Invoice Intrastat Lines model_account_move_intrastat_line account.group_account_readonly 1 0 0 0
14 access_account_move_intrastat_line Full access on Invoice Intrastat Lines model_account_move_intrastat_line account.group_account_invoice 1 1 1 1
15 access_intrastat_product_declaration Full access on Intrastat Product Declarations to Accountant model_intrastat_product_declaration account.group_account_user 1 1 1 1
16 access_intrastat_product_computation_line Full access on Intrastat Product Computation Lines to Accountant model_intrastat_product_computation_line account.group_account_user 1 1 1 1
17 access_intrastat_product_declaration_line Full access on Intrastat Product Declaration Lines to Accountant model_intrastat_product_declaration_line account.group_account_user 1 1 1 1
18 access_intrastat_result_view Access on intrastat.result.view model_intrastat_result_view account.group_account_user 1 1 1 0

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

View File

@@ -0,0 +1,510 @@
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.15.1: http://docutils.sourceforge.net/" />
<title>Intrastat Product</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
border: 0 }
table.borderless td, table.borderless th {
/* Override padding for "table.docutils td" with "! important".
The right padding separates the table cells. */
padding: 0 0.5em 0 0 ! important }
.first {
/* Override more specific margin styles with "! important". */
margin-top: 0 ! important }
.last, .with-subtitle {
margin-bottom: 0 ! important }
.hidden {
display: none }
.subscript {
vertical-align: sub;
font-size: smaller }
.superscript {
vertical-align: super;
font-size: smaller }
a.toc-backref {
text-decoration: none ;
color: black }
blockquote.epigraph {
margin: 2em 5em ; }
dl.docutils dd {
margin-bottom: 0.5em }
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
overflow: hidden;
}
/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
font-weight: bold }
*/
div.abstract {
margin: 2em 5em }
div.abstract p.topic-title {
font-weight: bold ;
text-align: center }
div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
margin: 2em ;
border: medium outset ;
padding: 1em }
div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
font-weight: bold ;
font-family: sans-serif }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title, .code .error {
color: red ;
font-weight: bold ;
font-family: sans-serif }
/* Uncomment (and remove this text!) to get reduced vertical space in
compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
margin-bottom: 0.5em }
div.compound .compound-last, div.compound .compound-middle {
margin-top: 0.5em }
*/
div.dedication {
margin: 2em 5em ;
text-align: center ;
font-style: italic }
div.dedication p.topic-title {
font-weight: bold ;
font-style: normal }
div.figure {
margin-left: 2em ;
margin-right: 2em }
div.footer, div.header {
clear: both;
font-size: smaller }
div.line-block {
display: block ;
margin-top: 1em ;
margin-bottom: 1em }
div.line-block div.line-block {
margin-top: 0 ;
margin-bottom: 0 ;
margin-left: 1.5em }
div.sidebar {
margin: 0 0 0.5em 1em ;
border: medium outset ;
padding: 1em ;
background-color: #ffffee ;
width: 40% ;
float: right ;
clear: right }
div.sidebar p.rubric {
font-family: sans-serif ;
font-size: medium }
div.system-messages {
margin: 5em }
div.system-messages h1 {
color: red }
div.system-message {
border: medium outset ;
padding: 1em }
div.system-message p.system-message-title {
color: red ;
font-weight: bold }
div.topic {
margin: 2em }
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
margin-top: 0.4em }
h1.title {
text-align: center }
h2.subtitle {
text-align: center }
hr.docutils {
width: 75% }
img.align-left, .figure.align-left, object.align-left, table.align-left {
clear: left ;
float: left ;
margin-right: 1em }
img.align-right, .figure.align-right, object.align-right, table.align-right {
clear: right ;
float: right ;
margin-left: 1em }
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left }
.align-center {
clear: both ;
text-align: center }
.align-right {
text-align: right }
/* reset inner alignment in figures */
div.align-right {
text-align: inherit }
/* div.align-center * { */
/* text-align: left } */
.align-top {
vertical-align: top }
.align-middle {
vertical-align: middle }
.align-bottom {
vertical-align: bottom }
ol.simple, ul.simple {
margin-bottom: 1em }
ol.arabic {
list-style: decimal }
ol.loweralpha {
list-style: lower-alpha }
ol.upperalpha {
list-style: upper-alpha }
ol.lowerroman {
list-style: lower-roman }
ol.upperroman {
list-style: upper-roman }
p.attribution {
text-align: right ;
margin-left: 50% }
p.caption {
font-style: italic }
p.credits {
font-style: italic ;
font-size: smaller }
p.label {
white-space: nowrap }
p.rubric {
font-weight: bold ;
font-size: larger ;
color: maroon ;
text-align: center }
p.sidebar-title {
font-family: sans-serif ;
font-weight: bold ;
font-size: larger }
p.sidebar-subtitle {
font-family: sans-serif ;
font-weight: bold }
p.topic-title {
font-weight: bold }
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font: inherit }
pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
pre.code .ln { color: grey; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
pre.code .literal.string, code .literal.string { color: #0C5404 }
pre.code .name.builtin, code .name.builtin { color: #352B84 }
pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}
span.classifier {
font-family: sans-serif ;
font-style: oblique }
span.classifier-delimiter {
font-family: sans-serif ;
font-weight: bold }
span.interpreted {
font-family: sans-serif }
span.option {
white-space: nowrap }
span.pre {
white-space: pre }
span.problematic {
color: red }
span.section-subtitle {
/* font-size relative to parent (h1..h6 element) */
font-size: 80% }
table.citation {
border-left: solid 1px gray;
margin-left: 1px }
table.docinfo {
margin: 2em 4em }
table.docutils {
margin-top: 0.5em ;
margin-bottom: 0.5em }
table.footnote {
border-left: solid 1px black;
margin-left: 1px }
table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
padding-left: 0.5em ;
padding-right: 0.5em ;
vertical-align: top }
table.docutils th.field-name, table.docinfo th.docinfo-name {
font-weight: bold ;
text-align: left ;
white-space: nowrap ;
padding-left: 0 }
/* "booktabs" style (no vertical lines) */
table.docutils.booktabs {
border: 0px;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.docutils.booktabs * {
border: 0px;
}
table.docutils.booktabs th {
border-bottom: thin solid;
text-align: left;
}
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% }
ul.auto-toc {
list-style-type: none }
</style>
</head>
<body>
<div class="document" id="intrastat-product">
<h1 class="title">Intrastat Product</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/intrastat-extrastat/tree/14.0/intrastat_product"><img alt="OCA/intrastat-extrastat" src="https://img.shields.io/badge/github-OCA%2Fintrastat--extrastat-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/intrastat-extrastat-14-0/intrastat-extrastat-14-0-intrastat_product"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/227/14.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
<p>This module contains common objects and fields for the Intrastat Product reporting.</p>
<p>It should be used in combination with country-specific Intrastat Product reporting modules
such as:</p>
<ul class="simple">
<li><em>l10n_fr_intrastat_product</em>:
the module for the <em>Déclaration dEchange de Biens</em> (DEB) for France</li>
<li><em>l10n_be_intrastat_product</em>:
the module for the Intrastat Product Declaration for Belgium</li>
</ul>
<p>These country-specific modules can be found in the OCA localization for those countries.</p>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#installation" id="id1">Installation</a></li>
<li><a class="reference internal" href="#configuration" id="id2">Configuration</a></li>
<li><a class="reference internal" href="#usage" id="id3">Usage</a></li>
<li><a class="reference internal" href="#known-issues-roadmap" id="id4">Known issues / Roadmap</a></li>
<li><a class="reference internal" href="#bug-tracker" id="id5">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="id6">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="id7">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="id8">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="id9">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="installation">
<h1><a class="toc-backref" href="#id1">Installation</a></h1>
<p>This module is NOT compatible with the <em>account_intrastat</em> module from Odoo Enterprise.</p>
</div>
<div class="section" id="configuration">
<h1><a class="toc-backref" href="#id2">Configuration</a></h1>
<p>By default the intrastat declaration is generated based upon the product record master data.
Hence unexpected results may occur in case this master data is not accurate,
e.g. wrong or missing weight, country of origin, …</p>
<div class="line-block">
<div class="line"><br /></div>
</div>
<p>This can be corrected by changing the appropriate fields when analysing the intrastat declaration
but this can be challenging in case of large transaction volumes and especially in the specific use
case where the product weight cannot be encoded correctly on the product records (e.g. products with variable weight).</p>
<div class="line-block">
<div class="line"><br /></div>
</div>
<p>It is possible to allow encoding the intrastat transaction details on the purchase/sale invoice
via the “intrastat_product.group_invoice_intrastat_transaction_detail” usability group.</p>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#id3">Usage</a></h1>
<p>This module is used in combination with the country-specific
localization module(s).</p>
<p><strong>Coding guidelines for localization module:</strong></p>
<p>We recommend to start by copying an existing module, e.g. l10n_be_intrastat_product
and adapt the code for the specific needs of your country.</p>
<ul>
<li><p class="first">Declaration Object</p>
<p>Create a new class as follows:</p>
<pre class="code python literal-block">
<span class="k">class</span> <span class="nc">L10nCcIntrastatProductDeclaration</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
<span class="n">_name</span> <span class="o">=</span> <span class="s1">'l10n.cc.intrastat.product.declaration'</span>
<span class="n">_description</span> <span class="o">=</span> <span class="s2">&quot;Intrastat Product Declaration for YourCountry&quot;</span>
<span class="n">_inherit</span> <span class="o">=</span> <span class="p">[</span><span class="s1">'intrastat.product.declaration'</span><span class="p">,</span> <span class="s1">'mail.thread'</span><span class="p">]</span>
</pre>
<p>whereby cc = your country code</p>
</li>
<li><p class="first">Computation &amp; Declaration Lines</p>
<p>Create also new objects inheriting from the Computation and Declaration Line Objects
so that you can add methods or customise the methods from the base modules (make a PR when
the customization or new method is required for multiple countries).</p>
<p>Adapt also the parent_id fields of the newly created objects
(cf. l10n_be_intrastat_product as example).</p>
</li>
<li><p class="first">XML Files: Menu, Action, Views</p>
<p>Cf. l10n_be_istrastat_product as example, replace “be” by your Country Code.</p>
</li>
</ul>
<p><strong>Other functionality added by this module:</strong></p>
<ul class="simple">
<li>Compute the Intrastat Lines in an invoice.
For this, your user needs to be in the “Technical / Invoice Intrastat Transaction Details” group.
Go to the “Intrastat transaction details” tab and press <strong>Compute</strong></li>
</ul>
</div>
<div class="section" id="known-issues-roadmap">
<h1><a class="toc-backref" href="#id4">Known issues / Roadmap</a></h1>
<p>The declaration is based upon the invoices of the corresponding tax declaration period.</p>
<p>An option to generate the intrastat declaration based upon the dates of the physical movements of goods is currently not available.</p>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#id5">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/intrastat-extrastat/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/OCA/intrastat-extrastat/issues/new?body=module:%20intrastat_product%0Aversion:%2014.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h1><a class="toc-backref" href="#id6">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#id7">Authors</a></h2>
<ul class="simple">
<li>ACSONE SA/NV</li>
<li>brain-tec AG</li>
<li>Akretion</li>
<li>Noviat</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#id8">Contributors</a></h2>
<ul>
<li><p class="first">Alexis de Lattre, Akretion &lt;<a class="reference external" href="mailto:alexis.delattre&#64;akretion.com">alexis.delattre&#64;akretion.com</a>&gt;</p>
</li>
<li><p class="first">Luc De Meyer, Noviat &lt;<a class="reference external" href="mailto:info&#64;noviat.com">info&#64;noviat.com</a>&gt;</p>
</li>
<li><p class="first">Denis Roussel &lt;<a class="reference external" href="mailto:denis.roussel&#64;acsone.eu">denis.roussel&#64;acsone.eu</a>&gt;</p>
</li>
<li><p class="first">Tecnativa &lt;www.tecnativa.com&gt;:</p>
<blockquote>
<ul class="simple">
<li>João Marques</li>
<li>Víctor Martínez</li>
</ul>
</blockquote>
</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#id9">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.</p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/intrastat-extrastat/tree/14.0/intrastat_product">OCA/intrastat-extrastat</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,8 @@
from . import common
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

View File

@@ -0,0 +1,209 @@
# Copyright 2021 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import xlrd
from werkzeug.urls import url_encode
from odoo.addons.intrastat_base.tests.common import IntrastatCommon
class IntrastatProductCommon(IntrastatCommon):
@classmethod
def _init_products(cls):
# Create category - don't init intrastat values, do it in tests
vals = {
"name": "Robots",
"parent_id": cls.category_saleable.id,
}
cls.categ_robots = cls.category_obj.create(vals)
vals = {
"name": "C3PO",
"type": "consu",
"categ_id": cls.categ_robots.id,
"origin_country_id": cls.env.ref("base.us").id,
"weight": 300,
# Computer - C3PO is one of them
"hs_code_id": cls.hs_code_computer.id,
"list_price": 42,
}
cls.product_c3po = cls.product_template_obj.create(vals)
@classmethod
def _init_company(cls):
# Default transport for company is Road
cls.demo_company.intrastat_transport_id = cls.transport_road
@classmethod
def _init_fiscal_position(cls):
vals = {
"name": "Intrastat Fiscal Position",
"intrastat": "b2b",
"vat_required": True,
}
cls.position = cls.position_obj.create(vals)
@classmethod
def _init_regions(cls):
# Create Region
cls._create_region()
vals = {
"code": "DE",
"name": "Germany",
"country_id": cls.env.ref("base.de").id,
"description": "Germany",
}
cls._create_region(vals)
@classmethod
def _init_transaction(cls):
vals = {
"code": "9X",
"company_id": cls.env.company.id,
"description": "Test 9X",
}
cls._create_transaction(vals)
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.region_obj = cls.env["intrastat.region"]
cls.transaction_obj = cls.env["intrastat.transaction"]
cls.transport_mode_obj = cls.env["intrastat.transport_mode"]
cls.partner_obj = cls.env["res.partner"]
cls.category_saleable = cls.env.ref("product.product_category_1")
cls.category_obj = cls.env["product.category"]
cls.product_template_obj = cls.env["product.template"]
cls.declaration_obj = cls.env["intrastat.product.declaration"]
cls.position_obj = cls.env["account.fiscal.position"]
cls.hs_code_computer = cls.env.ref("product_harmonized_system.84715000")
cls.report_obj = cls.env["ir.actions.report"]
cls.xls_declaration = cls.env[
"report.intrastat_product.product_declaration_xls"
]
cls.transport_rail = cls.env.ref("intrastat_product.intrastat_transport_2")
cls.transport_road = cls.env.ref("intrastat_product.intrastat_transport_3")
cls._init_regions()
cls._init_company()
cls._init_fiscal_position()
cls._init_products()
cls._init_transaction()
@classmethod
def _create_xls(cls, declaration=False):
"""
Prepare the Excel report to be tested
:return: The Excel file
:rtype: bytes
"""
report = cls.env.ref(
"intrastat_product.intrastat_product_xlsx_report"
).with_context(active_ids=cls.declaration.ids)
report_name = report.report_name
cls.report = cls.report_obj._get_report_from_name(report_name)
datas = {
"context": {
"active_ids": [cls.declaration.id],
}
}
data = {}
encoded_data = "report/report_xlsx/" + report_name + "?" + url_encode(data)
datas["data"] = encoded_data
active_model = cls.declaration._name
if not declaration:
computation_lines = True
else:
computation_lines = False
file_data = cls.xls_declaration.with_context(
computation_lines=computation_lines, active_model=active_model
).create_xlsx_report(None, datas)
return file_data
def check_xls(self, xls):
"""
Check that the xls content correspond to computation/declaration
lines values
:param xls: the Excel file content
:type xls: bytes
:param declaration: By default, check computation lines, either declaration ones
:type declaration: bool, optional
"""
book = xlrd.open_workbook(file_contents=xls)
# Get the template used to build the Excel file lines
template = self.xls_declaration._get_template(self.declaration)
# Get the declaration lines or the computation ones
to_test = [
(
book.sheet_by_index(0),
self.declaration.computation_line_ids,
self.declaration._xls_computation_line_fields(),
),
(
book.sheet_by_index(1),
self.declaration.declaration_line_ids,
self.declaration._xls_declaration_line_fields(),
),
]
# Iterate on each row beginning on third one (two headers)
for (sheet, lines, line_fields) in to_test:
i = 0
for rx in range(3, sheet.nrows):
line = lines[i]
row = sheet.row(rx)
j = 0
dict_compare = dict()
for line_field in line_fields:
column_spec = template.get(line_field)
dict_compare.update(
{row[j].value: column_spec.get("line").get("value")}
)
j += 1
for key, value in dict_compare.items():
value_eval = self.xls_declaration._eval(value, {"line": line})
self.assertEqual(key, value_eval)
i += 1
@classmethod
def _create_region(cls, vals=None):
values = {
"code": "2",
"country_id": cls.env.ref("base.be").id,
"company_id": cls.env.company.id,
"description": "Belgium Walloon Region",
"name": "Walloon Region",
}
if vals is not None:
values.update(vals)
cls.region = cls.region_obj.create(values)
@classmethod
def _create_transaction(cls, vals=None):
values = {
"code": "11",
"company_id": cls.env.company.id,
"description": "Sale / Purchase",
}
if vals is not None:
values.update(vals)
cls.transaction = cls.transaction_obj.create(values)
@classmethod
def _create_transport_mode(cls, vals=None):
values = {}
if vals is not None:
values.update(vals)
cls.transport_mode = cls.transport_mode_obj.create(values)
@classmethod
def _create_declaration(cls, vals=None):
values = {
"company_id": cls.env.company.id,
"declaration_type": "dispatches",
}
if vals is not None:
values.update(vals)
cls.declaration = cls.declaration_obj.create(values)

View File

@@ -0,0 +1,81 @@
# Copyright 2021 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo.tests import Form
from .common import IntrastatProductCommon
class IntrastatPurchaseCommon(IntrastatProductCommon):
"""
We define common flow:
- Supplier in Germany
"""
def _get_expected_vals(self, line):
return {
"declaration_type": "arrivals",
"suppl_unit_qty": line.qty_received,
"hs_code_id": line.product_id.hs_code_id,
"product_origin_country_code": line.product_id.origin_country_id.code,
"amount_company_currency": line.price_subtotal,
"src_dest_country_code": line.partner_id.country_id.code,
}
def _check_line_values(self, final=False, declaration=None, purchase=None):
"""
This method allows to test computation lines and declaration
lines values from original sale order line
"""
if declaration is None:
declaration = self.declaration
if purchase is None:
purchase = self.purchase
for line in purchase.order_line:
expected_vals = self._get_expected_vals(line)
comp_line = declaration.computation_line_ids.filtered(
lambda cline: cline.product_id == line.product_id
)
self.assertTrue(
all(comp_line[key] == val for key, val in expected_vals.items())
)
if final:
decl_line = declaration.declaration_line_ids.filtered(
lambda dline: comp_line in dline.computation_line_ids
)
self.assertTrue(
all(decl_line[key] == val for key, val in expected_vals.items())
)
@classmethod
def _init_supplier(cls, vals=None):
values = {
"name": "DE Supplier",
"country_id": cls.env.ref("base.de").id,
"property_account_position_id": cls.position.id,
}
if vals is not None:
values.update(vals)
cls.supplier = cls.partner_obj.create(values)
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.purchase_obj = cls.env["purchase.order"]
cls.move_obj = cls.env["account.move"]
cls._init_supplier()
@classmethod
def _create_purchase_order(cls, vals=None):
vals = {
"partner_id": cls.supplier.id,
}
purchase_new = cls.purchase_obj.new(vals)
purchase_new.onchange_partner_id()
purchase_vals = purchase_new._convert_to_write(purchase_new._cache)
cls.purchase = cls.purchase_obj.create(purchase_vals)
with Form(cls.purchase) as purchase_form:
with purchase_form.order_line.new() as line:
line.product_id = cls.product_c3po.product_variant_ids[0]
line.product_qty = 3.0
# Price should not be void - if no purchase pricelist
line.price_unit = 150.0

View File

@@ -0,0 +1,76 @@
# Copyright 2021 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo.tests import Form
from .common import IntrastatProductCommon
class IntrastatSaleCommon(IntrastatProductCommon):
"""
We define common flow:
- Customer in Netherlands
"""
def _get_expected_vals(self, line):
return {
"declaration_type": "dispatches",
"suppl_unit_qty": line.qty_delivered,
"hs_code_id": line.product_id.hs_code_id,
"product_origin_country_code": line.product_id.origin_country_id.code,
}
def _check_line_values(self, final=False, declaration=None, sale=None):
"""
This method allows to test computation lines and declaration
lines values from original sale order line
"""
if declaration is None:
declaration = self.declaration
if sale is None:
sale = self.sale
for line in sale.order_line:
expected_vals = self._get_expected_vals(line)
comp_line = declaration.computation_line_ids.filtered(
lambda cline: cline.product_id == line.product_id
)
self.assertTrue(
all(comp_line[key] == val for key, val in expected_vals.items())
)
if final:
decl_line = declaration.declaration_line_ids.filtered(
lambda dline: comp_line in dline.computation_line_ids
)
self.assertTrue(
all(decl_line[key] == val for key, val in expected_vals.items())
)
@classmethod
def _init_customer(cls, vals=None):
values = {
"name": "Akretion France",
"country_id": cls.env.ref("base.fr").id,
"property_account_position_id": cls.position.id,
"vat": "FR86792377731",
}
if vals is not None:
values.update(vals)
cls.customer = cls.partner_obj.create(values)
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.sale_obj = cls.env["sale.order"]
cls._init_customer()
@classmethod
def _create_sale_order(cls, vals=None):
vals = {
"partner_id": cls.customer.id,
}
sale_new = cls.sale_obj.new(vals)
sale_vals = sale_new._convert_to_write(sale_new._cache)
cls.sale = cls.sale_obj.create(sale_vals)
with Form(cls.sale) as sale_form:
with sale_form.order_line.new() as line:
line.product_id = cls.product_c3po.product_variant_ids[0]
line.product_uom_qty = 3.0

View File

@@ -0,0 +1,108 @@
# Copyright 2022 Noviat.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo.tests import Form, TransactionCase
from .common import IntrastatProductCommon
class TestIntrastatBrexit(IntrastatProductCommon, TransactionCase):
@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_uk = 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,
"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.done()
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_uk
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.done()
clines = self.declaration.computation_line_ids
cl_uk = clines.filtered(lambda r: r.product_id == self.product_uk)
dlines = self.declaration.declaration_line_ids
dl_uk = dlines.filtered(lambda r: r.computation_line_ids == cl_uk)
self.assertEqual(cl_uk.product_origin_country_code, "XU")
self.assertEqual(dl_uk.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_uk
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_id, self.env.ref("base.uk"))

View File

@@ -0,0 +1,40 @@
# Copyright 2021 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo.tests.common import TransactionCase
from .common import IntrastatProductCommon
class TestIntrastatCompany(IntrastatProductCommon):
"""Tests for this module"""
def test_company_values(self):
# Exempt for arrivals and dispatches => exempt
self.demo_company.update(
{
"intrastat_arrivals": "exempt",
"intrastat_dispatches": "exempt",
}
)
self.assertEqual("exempt", self.demo_company.intrastat)
# Extended for arrivals or dispatches => extended
self.demo_company.update(
{
"intrastat_arrivals": "extended",
}
)
self.assertEqual("extended", self.demo_company.intrastat)
# standard for arrivals or dispatches => standard
self.demo_company.update(
{
"intrastat_arrivals": "exempt",
"intrastat_dispatches": "standard",
}
)
self.assertEqual("standard", self.demo_company.intrastat)
class TestIntrastatProductCase(TestIntrastatCompany, TransactionCase):
"""Test Intrastat Product"""

View File

@@ -0,0 +1,153 @@
# Copyright 2021 ACSONE SA/NV
# Copyright 2022 Tecnativa - Víctor Martínez
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from psycopg2 import IntegrityError
from odoo.exceptions import UserError, ValidationError
from odoo.tests import Form
from odoo.tests.common import TransactionCase
from odoo.tools import mute_logger
from .common import IntrastatProductCommon
class TestIntrastatProduct(IntrastatProductCommon):
"""Tests for this module"""
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.product = cls.env["product.product"].create(
{
"name": "Test product",
"hs_code_id": cls.env.ref("product_harmonized_system.84715000").id,
"origin_country_id": cls.env.ref("base.de").id,
"weight": 1.25,
}
)
cls.partner = cls.partner_obj.create(
{
"name": "Test partner",
"country_id": cls.env.ref("base.fr").id,
"invoice_intrastat_detail": True,
}
)
cls.env["account.journal"].create(
{"name": "Test sale journal", "type": "sale", "code": "TEST-sale"}
)
cls.report_obj = cls.env["ir.actions.report"]
cls.sale_order = cls._create_sale_order(cls)
cls.sale_order.action_confirm()
cls.sale_order.order_line.qty_delivered = 1
cls.invoice = cls.sale_order._create_invoices()
# Test duplicates
@mute_logger("odoo.sql_db")
def test_region(self):
with self.assertRaises(IntegrityError):
self._create_region()
@mute_logger("odoo.sql_db")
def test_transaction(self):
self._create_transaction()
with self.assertRaises(IntegrityError):
self._create_transaction()
@mute_logger("odoo.sql_db")
def test_transport_mode(self):
vals = {"code": 1, "name": "Sea"}
with self.assertRaises(IntegrityError):
self._create_transport_mode(vals)
def test_copy(self):
"""
When copying declaration, the new one has an incremented revision
value.
"""
vals = {"declaration_type": "dispatches"}
self._create_declaration(vals)
decl_copy = self.declaration.copy()
self.assertEqual(self.declaration.revision + 1, decl_copy.revision)
def test_declaration_manual_lines(self):
vals = {"declaration_type": "dispatches", "reporting_level": "extended"}
self._create_declaration(vals)
computation_line_form = Form(
self.env["intrastat.product.computation.line"].with_context(
default_parent_id=self.declaration.id
)
)
computation_line_form.src_dest_country_id = self.env.ref("base.fr")
computation_line_form.transaction_id = self.transaction
computation_line_form.hs_code_id = self.hs_code_computer
computation_line_form.region_code = "ZZ"
computation_line_form.product_origin_country_code = "BE"
computation_line_form.transport_id = self.env.ref(
"intrastat_product.intrastat_transport_3"
)
computation_line = computation_line_form.save()
self.assertEqual(computation_line.src_dest_country_code, "FR")
declaration_line_form = Form(
self.env["intrastat.product.declaration.line"].with_context(
default_parent_id=self.declaration.id
)
)
declaration_line_form.src_dest_country_code = "FR"
declaration_line = declaration_line_form.save()
self.assertEqual(declaration_line.src_dest_country_code, "FR")
def test_declaration_no_country(self):
self.demo_company.country_id = False
with self.assertRaises(ValidationError):
self._create_declaration()
self.declaration.flush()
def test_declaration_no_vat(self):
self.demo_company.partner_id.vat = False
with self.assertRaises(UserError):
self._create_declaration()
self.declaration._check_generate_xml()
def test_declaration_state(self):
self._create_declaration()
self.declaration.unlink()
self._create_declaration()
self.declaration.state = "done"
with self.assertRaises(UserError):
self.declaration.unlink()
def _create_sale_order(self):
order_form = Form(self.env["sale.order"])
order_form.partner_id = self.partner
with order_form.order_line.new() as line_form:
line_form.product_id = self.product
with order_form.order_line.new() as line_form:
line_form.product_id = self.product
return order_form.save()
def _test_invoice_report(self, weight):
"""We need to check weight because if intrastat_line_ids already exist
the weight will be different because weight field in model is integer."""
res = self.report_obj._render(
"account.report_invoice_with_payments", self.invoice.ids
)
self.assertRegex(str(res[0]), self.product.hs_code_id.hs_code)
self.assertRegex(str(res[0]), self.product.origin_country_id.name)
res = list(self.invoice._get_intrastat_lines_info())
self.assertEqual(len(res), 1)
self.assertEqual(res[0]["product_id"], self.product)
self.assertEqual(res[0]["hs_code_id"], self.product.hs_code_id)
self.assertEqual(res[0]["origin_country_id"], self.product.origin_country_id)
self.assertEqual(res[0]["weight"], weight)
def test_invoice_report_without_intrastat_lines(self):
self._test_invoice_report(2.5)
def test_invoice_report_with_intrastat_lines(self):
self.invoice.compute_intrastat_lines()
self._test_invoice_report(2)
class TestIntrastatProductCase(TestIntrastatProduct, TransactionCase):
"""Test Intrastat Product"""

View File

@@ -0,0 +1,57 @@
# Copyright 2021 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from freezegun import freeze_time
from odoo import fields
from odoo.tests.common import TransactionCase
from .common_purchase import IntrastatPurchaseCommon
class TestIntrastatProductPurchase(IntrastatPurchaseCommon):
"""Tests for this module"""
def test_purchase_to_invoice_default(self):
date_order = "2021-09-01"
declaration_date = "2021-10-01"
with freeze_time(date_order):
self._create_purchase_order()
self.purchase.button_confirm()
self.purchase.picking_ids.action_assign()
for line in self.purchase.picking_ids.move_line_ids:
line.qty_done = line.reserved_uom_qty
self.purchase.picking_ids._action_done()
self.assertEqual("done", self.purchase.picking_ids.state)
with freeze_time(date_order):
action = self.purchase.action_create_invoice()
invoice_id = action["res_id"]
invoice = self.move_obj.browse(invoice_id)
invoice.invoice_date = fields.Date.from_string(date_order)
invoice.action_post()
# Check if transport mode has been transmitted to invoice
# It should be None as not defined on sale order
self.assertFalse(
invoice.intrastat_transport_id,
)
vals = {
"declaration_type": "arrivals",
}
with freeze_time(declaration_date):
self._create_declaration(vals)
self.declaration.action_gather()
self._check_line_values()
self.declaration.done()
self._check_line_values(final=True)
# Check the Excel file
file_data = self._create_xls()
self.check_xls(file_data[0])
class TestIntrastatProductPurchaseCase(TestIntrastatProductPurchase, TransactionCase):
"""Test Intrastat Purchase"""

View File

@@ -0,0 +1,92 @@
# Copyright 2021 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from freezegun import freeze_time
from odoo.tests.common import TransactionCase
from .common_sale import IntrastatSaleCommon
class TestIntrastatProductSale(IntrastatSaleCommon):
"""Tests for this module"""
def test_sale_to_invoice_default(self):
self._create_sale_order()
self.sale.action_confirm()
self.sale.picking_ids.action_assign()
for line in self.sale.picking_ids.move_line_ids:
line.qty_done = line.reserved_uom_qty
self.sale.picking_ids._action_done()
self.assertEqual("done", self.sale.picking_ids.state)
invoice = self.sale._create_invoices()
invoice.action_post()
# Check if transport mode has been transmitted to invoice
# It should be None as not defined on sale order
self.assertFalse(
invoice.intrastat_transport_id,
)
# Test specific transport set on sale to invoice
def test_sale_to_invoice(self):
self._create_sale_order()
# Set intrastat transport mode to rail
self.sale.intrastat_transport_id = self.transport_rail
self.sale.action_confirm()
self.sale.picking_ids.action_assign()
for line in self.sale.picking_ids.move_line_ids:
line.qty_done = line.reserved_uom_qty
self.sale.picking_ids._action_done()
self.assertEqual("done", self.sale.picking_ids.state)
invoice = self.sale._create_invoices()
invoice.action_post()
# Check if transport mode has been transmitted to invoice
self.assertEqual(
self.transport_rail,
invoice.intrastat_transport_id,
)
def test_sale_declaration(self):
date_order = "2021-09-01"
declaration_date = "2021-10-01"
with freeze_time(date_order):
self._create_sale_order()
# Set intrastat transport mode to rail
self.sale.intrastat_transport_id = self.transport_rail
self.sale.action_confirm()
self.sale.picking_ids.action_assign()
for line in self.sale.picking_ids.move_line_ids:
line.qty_done = line.reserved_uom_qty
self.sale.picking_ids._action_done()
self.assertEqual("done", self.sale.picking_ids.state)
with freeze_time(date_order):
invoice = self.sale._create_invoices()
invoice.action_post()
# Check if transport mode has been transmitted to invoice
self.assertEqual(
self.transport_rail,
invoice.intrastat_transport_id,
)
vals = {
"declaration_type": "dispatches",
}
with freeze_time(declaration_date):
self._create_declaration(vals)
self.declaration.action_gather()
self._check_line_values()
self.declaration.done()
self._check_line_values(final=True)
# Check the Excel file
file_data = self._create_xls()
self.check_xls(file_data[0])
class TestIntrastatProductSaleCase(TestIntrastatProductSale, TransactionCase):
"""Test Intrastat Sale"""

View File

@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record id="view_move_form" model="ir.ui.view">
<field name="name">intrastat.invoice.form</field>
<field name="model">account.move</field>
<field name="inherit_id" ref="account.view_move_form" />
<field name="arch" type="xml">
<xpath
expr="//page[@name='other_info']//field[@name='invoice_incoterm_id']"
position="after"
>
<field name="intrastat_transaction_id" />
<field name="intrastat" invisible="1" />
<field
name="intrastat_transport_id"
attrs="{'invisible': [('intrastat', '!=', 'extended')]}"
widget="selection"
/>
<field name="src_dest_country_id" string="Destination Country" />
<field name="src_dest_region_id" string="Origin Region" invisible="1" />
</xpath>
<page id="invoice_tab" position="after">
<page
id="intrastat_lines"
string="Intrastat transaction details"
groups="intrastat_product.group_invoice_intrastat_transaction_details"
attrs="{'invisible': [('move_type', 'not in', ('out_invoice', 'out_refund', 'in_invoice', 'in_refund'))]}"
>
<div>
<button
type="object"
name="compute_intrastat_lines"
string="Compute"
help="(Re)compute the intrastat transaction details from the product master data."
icon="fa-gears"
/>
</div>
<field name="intrastat_line_ids">
<tree editable="bottom">
<field
name="invoice_line_id"
domain="[('move_id', '=', parent.id), ('display_type', '=', 'product')]"
options="{'no_create': True, 'no_open': True}"
/>
<field name="product_id" />
<field name="quantity" />
<field name="transaction_suppl_unit_qty" />
<field name="hs_code_id" />
<field name="transaction_weight" />
<field name="product_origin_country_id" />
</tree>
</field>
</page>
</page>
</field>
</record>
</odoo>

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
Copyright 2010-2020 Akretion (http://www.akretion.com/)
Copyright 2015-2020 Noviat (http://www.noviat.com/)
@author Alexis de Lattre <alexis.delattre@akretion.com>
@author Luc De Meyer <luc.demeyer@noviat.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<!-- Add the H.S. code menu under the Intrastat Config menu -->
<menuitem
id="intrastat_code_menu"
action="product_harmonized_system.hs_code_action"
parent="intrastat_base.menu_intrastat_config_root"
sequence="10"
/>
<!-- Inherit tree view of H.S. code -->
<record id="hs_code_tree" model="ir.ui.view">
<field name="name">intrastat.hs.code.tree</field>
<field name="model">hs.code</field>
<field name="inherit_id" ref="product_harmonized_system.hs_code_view_tree" />
<field name="arch" type="xml">
<field name="local_code" position="after">
<field name="intrastat_unit_id" optional="show" />
</field>
</field>
</record>
<!-- Inherit form view for H.S. code -->
<record id="hs_code_form" model="ir.ui.view">
<field name="name">intrastat.hs.code.form</field>
<field name="model">hs.code</field>
<field name="inherit_id" ref="product_harmonized_system.hs_code_view_form" />
<field name="arch" type="xml">
<field name="local_code" position="after">
<field name="intrastat_unit_id" />
</field>
</field>
</record>
</odoo>

View File

@@ -0,0 +1,488 @@
<?xml version="1.0" ?>
<odoo>
<record id="intrastat_product_declaration_view_form" model="ir.ui.view">
<field name="name">intrastat.product.declaration.form</field>
<field name="model">intrastat.product.declaration</field>
<field name="arch" type="xml">
<form>
<header>
<button
name="action_gather"
type="object"
attrs="{'invisible': ['|', ('state', '!=', 'draft'), ('action', '=', 'nihil')]}"
string="Generate Lines from Invoices"
class="btn-primary"
/>
<button
name="done"
string="Confirm"
type="object"
class="btn-primary"
states="draft"
help="Generate declaration lines, generate XML export and set declaration to 'Done'"
/>
<button
name="back2draft"
string="Back to Draft"
type="object"
states="done"
confirm="Are you sure you want to go back to draft?"
/>
<button
name="%(intrastat_product.intrastat_product_xlsx_report)d"
type="action"
string="Excel Export"
/>
<field name="state" widget="statusbar" />
</header>
<sheet>
<div class="oe_title">
<h1>
<span>Intrastat Product Declaration </span>
<field name="year_month" class="oe_inline" />
</h1>
</div>
<group name="top-block">
<group name="properties-1">
<field name="year" />
<field name="month" />
<field name="declaration_type" />
<field name="reporting_level" />
<field
name="xml_attachment_datas"
filename="xml_attachment_name"
invisible="context.get('generic_intrastat_product_declaration')"
/>
<field name="xml_attachment_name" invisible="1" />
<field name="xml_attachment_id" invisible="1" />
</group>
<group name="properties-2">
<field name="action" />
<field name="revision" />
<field
name="total_amount"
widget="monetary"
options="{'currency_field': 'currency_id'}"
/>
<field name="num_decl_lines" />
<field
name="company_id"
groups="base.group_multi_company"
/>
<field name="company_country_code" invisible="1" />
<field name="currency_id" invisible="1" />
</group>
</group>
<notebook>
<page string="Transactions" name="computation_lines">
<field
name="computation_line_ids"
context="{'declaration_type': declaration_type, 'reporting_level': reporting_level}"
nolabel="1"
/>
</page>
<page string="Declaration Lines" name="declaration_lines">
<field
name="declaration_line_ids"
context="{'declaration_type': declaration_type, 'reporting_level': reporting_level}"
nolabel="1"
/>
</page>
<page string="Notes" name="note">
<field name="note" />
</page>
</notebook>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers" />
<field name="activity_ids" widget="mail_activity" />
<field name="message_ids" widget="mail_thread" />
</div>
</form>
</field>
</record>
<record id="intrastat_product_declaration_view_tree" model="ir.ui.view">
<field name="name">intrastat.product.declaration.tree</field>
<field name="model">intrastat.product.declaration</field>
<field name="arch" type="xml">
<tree>
<field name="year_month" decoration-bf="1" />
<field
name="declaration_type"
widget="badge"
decoration-danger="declaration_type == 'arrivals'"
decoration-warning="declaration_type == 'dispatches'"
/>
<field name="reporting_level" optional="hide" />
<field name="action" optional="hide" />
<field name="revision" optional="hide" />
<field name="num_decl_lines" optional="show" />
<field name="total_amount" sum="1" optional="show" />
<field name="currency_id" optional="show" />
<field
name="state"
decoration-success="state == 'done'"
decoration-info="state == 'draft'"
widget="badge"
/>
</tree>
</field>
</record>
<record id="intrastat_product_declaration_view_search" model="ir.ui.view">
<field name="name">intrastat.product.declaration.search</field>
<field name="model">intrastat.product.declaration</field>
<field name="arch" type="xml">
<search>
<field name="year_month" />
<filter
name="arrivals"
string="Arrivals"
domain="[('declaration_type', '=', 'arrivals')]"
/>
<filter
name="dispatches"
string="Dispatches"
domain="[('declaration_type', '=', 'dispatches')]"
/>
<separator />
<filter
name="draft"
string="Draft"
domain="[('state', '=', 'draft')]"
/>
<filter name="done" string="Done" domain="[('state', '=', 'done')]" />
<group string="Group By" name="group_by">
<filter
name="date_group_by"
string="Date"
context="{'group_by': 'year_month'}"
/>
<filter
name="declaration_type_group_by"
string="Type"
context="{'group_by': 'declaration_type'}"
/>
</group>
</search>
</field>
</record>
<record id="intrastat_product_declaration_view_graph" model="ir.ui.view">
<field name="name">intrastat.product.declaration.graph</field>
<field name="model">intrastat.product.declaration</field>
<field name="arch" type="xml">
<graph type="bar" stacked="False">
<field name="year_month" type="row" />
<field name="declaration_type" type="row" />
<field name="total_amount" type="measure" />
</graph>
</field>
</record>
<record id="intrastat_product_declaration_view_pivot" model="ir.ui.view">
<field name="name">intrastat.product.declaration.pivot</field>
<field name="model">intrastat.product.declaration</field>
<field name="arch" type="xml">
<pivot>
<field name="year_month" type="row" />
<field name="declaration_type" type="col" />
<field name="total_amount" type="measure" />
</pivot>
</field>
</record>
<!-- No menuitem nor action since these are provided by the localization modules -->
<record id="intrastat_product_computation_line_view_form" model="ir.ui.view">
<field name="name">intrastat.product.computation.line.form</field>
<field name="model">intrastat.product.computation.line</field>
<field name="arch" type="xml">
<form>
<group string="Transaction" name="transaction">
<field
name="parent_id"
invisible="not context.get('intrastat_product_computation_line_main_view')"
/>
<field name="declaration_type" invisible="1" />
<field name="reporting_level" invisible="1" />
<field name="company_country_code" invisible="1" />
<field name="product_id" />
<field
name="hs_code_id"
attrs="{'required': [('reporting_level', '=', 'extended')], 'invisible': [('reporting_level', '!=', 'extended')]}"
/>
<field
name="src_dest_country_id"
attrs="{'invisible': [('reporting_level', '!=', 'extended')]}"
/>
<field
name="src_dest_country_code"
attrs="{'required': [('reporting_level', '=', 'extended')], 'invisible': [('reporting_level', '!=', 'extended')]}"
/>
<field
name="amount_company_currency"
widget="monetary"
options="{'currency_field': 'company_currency_id'}"
/>
<field
name="amount_accessory_cost_company_currency"
widget="monetary"
options="{'currency_field': 'company_currency_id'}"
/>
<field name="company_currency_id" invisible="1" />
<field name="transaction_id" required="1" />
<label
for="weight"
attrs="{'required': [('reporting_level', '=', 'extended')], 'invisible': [('reporting_level', '!=', 'extended')]}"
/>
<div
name="weight"
attrs="{'required': [('reporting_level', '=', 'extended')], 'invisible': [('reporting_level', '!=', 'extended')]}"
>
<field name="weight" class="oe_inline" /> Kg
</div>
<field
name="suppl_unit_qty"
attrs="{'required': [('reporting_level', '=', 'extended'), ('intrastat_unit_id', '!=', False)], 'invisible': ['|', ('reporting_level', '!=', 'extended'), ('intrastat_unit_id', '=', False)]}"
/>
<field
name="intrastat_unit_id"
attrs="{'invisible': ['|', ('reporting_level', '!=', 'extended'), ('intrastat_unit_id', '=', False)]}"
/>
<field
name="transport_id"
attrs="{'required': [('reporting_level', '=', 'extended')], 'invisible': [('reporting_level', '!=', 'extended')]}"
/>
<field name="incoterm_id" invisible="1" />
<field
name="region_id"
attrs="{'invisible': [('reporting_level', '!=', 'extended')]}"
/>
<field
name="region_code"
attrs="{'required': [('reporting_level', '=', 'extended')], 'invisible': [('reporting_level', '!=', 'extended')]}"
/>
<field
name="product_origin_country_id"
attrs="{'invisible': [('reporting_level', '!=', 'extended')]}"
/>
<field
name="product_origin_country_code"
attrs="{'invisible': [('reporting_level', '!=', 'extended')], 'required': [('reporting_level', '=', 'extended')]}"
/>
<field name="partner_id" />
<field name="vat" />
<field name="invoice_id" />
</group>
<group string="Declaration" name="declaration">
<field name="declaration_line_id" />
</group>
</form>
</field>
</record>
<record id="intrastat_product_computation_line_view_tree" model="ir.ui.view">
<field name="name">intrastat.product.computation.line.tree</field>
<field name="model">intrastat.product.computation.line</field>
<field name="arch" type="xml">
<tree>
<field
name="parent_id"
invisible="not context.get('intrastat_product_computation_line_main_view')"
/>
<field name="declaration_type" invisible="1" />
<field name="reporting_level" invisible="1" />
<field name="company_country_code" invisible="1" />
<field name="product_id" optional="show" />
<field
name="hs_code_id"
optional="show"
attrs="{'column_invisible': [('parent.reporting_level', '!=', 'extended')]}"
/>
<field
name="src_dest_country_id"
optional="hide"
attrs="{'column_invisible': [('parent.reporting_level', '!=', 'extended')]}"
/>
<field
name="src_dest_country_code"
optional="show"
attrs="{'column_invisible': [('parent.reporting_level', '!=', 'extended')]}"
/>
<field name="amount_company_currency" sum="1" />
<field
name="amount_accessory_cost_company_currency"
optional="show"
sum="1"
/>
<field name="transaction_code" />
<field
name="weight"
optional="show"
attrs="{'column_invisible': [('parent.reporting_level', '!=', 'extended')]}"
/>
<field
name="suppl_unit_qty"
optional="show"
attrs="{'column_invisible': [('parent.reporting_level', '!=', 'extended')], 'invisible': [('intrastat_unit_id', '=', False)]}"
/>
<field
name="intrastat_unit_id"
optional="show"
attrs="{'column_invisible': [('parent.reporting_level', '!=', 'extended')]}"
/>
<field
name="transport_id"
optional="show"
attrs="{'column_invisible': [('parent.reporting_level', '!=', 'extended')]}"
/>
<field
name="region_id"
optional="hide"
attrs="{'column_invisible': [('parent.reporting_level', '!=', 'extended')]}"
/>
<field
name="region_code"
optional="show"
attrs="{'column_invisible': [('parent.reporting_level', '!=', 'extended')]}"
/>
<field
name="product_origin_country_id"
optional="hide"
string="Product C/O"
attrs="{'column_invisible': [('parent.reporting_level', '!=', 'extended')]}"
/>
<field
name="product_origin_country_code"
optional="show"
string="Product C/O"
attrs="{'column_invisible': [('parent.reporting_level', '!=', 'extended')]}"
/>
<field name="vat" optional="show" />
<field name="invoice_id" optional="show" />
</tree>
</field>
</record>
<record id="intrastat_product_declaration_line_view_form" model="ir.ui.view">
<field name="name">intrastat.product.declaration.line.form</field>
<field name="model">intrastat.product.declaration.line</field>
<field name="arch" type="xml">
<form>
<group name="declaration">
<field
name="parent_id"
invisible="not context.get('intrastat_product_declaration_line_main_view')"
/>
<field name="declaration_type" invisible="1" />
<field name="reporting_level" invisible="1" />
<field name="company_country_code" invisible="1" />
<field
name="hs_code_id"
attrs="{'invisible': [('reporting_level', '!=', 'extended')]}"
/>
<field
name="src_dest_country_code"
attrs="{'invisible': [('reporting_level', '!=', 'extended')]}"
/>
<field
name="amount_company_currency"
widget="monetary"
options="{'currency_field': 'company_currency_id'}"
/>
<field name="company_currency_id" invisible="1" />
<field name="transaction_id" />
<label
for="weight"
attrs="{'invisible': [('reporting_level', '!=', 'extended')]}"
/>
<div
name="weight"
attrs="{'invisible': [('reporting_level', '!=', 'extended')]}"
>
<field name="weight" class="oe_inline" /> Kg
</div>
<field
name="suppl_unit_qty"
attrs="{'invisible': [('reporting_level', '!=', 'extended')]}"
/>
<field
name="intrastat_unit_id"
attrs="{'invisible': [('reporting_level', '!=', 'extended')]}"
/>
<field
name="transport_id"
attrs="{'invisible': [('reporting_level', '!=', 'extended')]}"
/>
<field
name="region_code"
attrs="{'invisible': [('reporting_level', '!=', 'extended')]}"
/>
<field name="incoterm_id" invisible="1" />
<field
name="product_origin_country_code"
attrs="{'invisible': [('reporting_level', '!=', 'extended')]}"
/>
<field name="vat" />
</group>
<group name="computation" string="Related Transactions">
<field name="computation_line_ids" nolabel="1" colspan="2" />
</group>
</form>
</field>
</record>
<record id="intrastat_product_declaration_line_view_tree" model="ir.ui.view">
<field name="name">intrastat.product.declaration.line.tree</field>
<field name="model">intrastat.product.declaration.line</field>
<field name="arch" type="xml">
<tree>
<field
name="parent_id"
invisible="not context.get('intrastat_product_declaration_line_main_view')"
/>
<field name="declaration_type" invisible="1" />
<field name="reporting_level" invisible="1" />
<field name="company_country_code" invisible="1" />
<field
name="hs_code_id"
attrs="{'column_invisible': [('parent.reporting_level', '!=', 'extended')]}"
optional="show"
/>
<field
name="src_dest_country_code"
attrs="{'column_invisible': [('parent.reporting_level', '!=', 'extended')]}"
optional="show"
/>
<field name="amount_company_currency" sum="1" />
<field name="transaction_code" />
<field
name="weight"
attrs="{'column_invisible': [('parent.reporting_level', '!=', 'extended')]}"
optional="show"
/>
<field
name="suppl_unit_qty"
attrs="{'column_invisible': [('parent.reporting_level', '!=', 'extended')]}"
optional="show"
/>
<field
name="intrastat_unit_id"
attrs="{'column_invisible': [('parent.reporting_level', '!=', 'extended')]}"
optional="show"
/>
<field
name="transport_id"
attrs="{'column_invisible': [('parent.reporting_level', '!=', 'extended')]}"
optional="show"
/>
<field
name="region_code"
attrs="{'column_invisible': [('parent.reporting_level', '!=', 'extended')]}"
optional="show"
/>
<field name="incoterm_id" invisible="1" />
<field
name="product_origin_country_code"
attrs="{'column_invisible': [('parent.reporting_level', '!=', 'extended')]}"
string="Product C/O"
optional="show"
/>
<field name="vat" />
</tree>
</field>
</record>
</odoo>

View File

@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record id="intrastat_region_view_form" model="ir.ui.view">
<field name="name">intrastat.region.form</field>
<field name="model">intrastat.region</field>
<field name="arch" type="xml">
<form>
<group name="main">
<field name="code" />
<field name="name" />
<field name="description" />
<field name="country_id" />
<field name="company_id" groups="base.group_multi_company" />
</group>
</form>
</field>
</record>
<record id="intrastat_region_view_tree" model="ir.ui.view">
<field name="name">intrastat.region.tree</field>
<field name="model">intrastat.region</field>
<field name="arch" type="xml">
<tree>
<field name="code" />
<field name="name" />
<field name="description" optional="show" />
<field name="country_id" />
<field name="company_id" groups="base.group_multi_company" />
</tree>
</field>
</record>
<record id="intrastat_region_view_search" model="ir.ui.view">
<field name="name">intrastat.region.search</field>
<field name="model">intrastat.region</field>
<field name="arch" type="xml">
<search>
<field
name="name"
string="Name, Code or Description"
filter_domain="['|', '|', ('code', 'ilike', self), ('name', 'ilike', self), ('description', 'ilike', self)]"
/>
<field name="code" />
<field name="country_id" />
<group name="groupby">
<filter
name="country_groupby"
string="Country"
context="{'group_by': 'country_id'}"
/>
</group>
</search>
</field>
</record>
<record id="intrastat_region_action" model="ir.actions.act_window">
<field name="name">Intrastat Regions</field>
<field name="res_model">intrastat.region</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem
id="intrastat_region_menu"
action="intrastat_region_action"
parent="intrastat_base.menu_intrastat_config_root"
sequence="50"
/>
</odoo>

View File

@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
Copyright 2010-2020 Akretion (http://www.akretion.com/)
Copyright 2015-2020 Noviat (http://www.noviat.com/)
@author Alexis de Lattre <alexis.delattre@akretion.com>
@author Luc De Meyer <luc.demeyer@noviat.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<!-- Intrastat Transaction Type -->
<record id="intrastat_transaction_form" model="ir.ui.view">
<field name="name">intrastat.transaction_form</field>
<field name="model">intrastat.transaction</field>
<field name="arch" type="xml">
<form>
<sheet>
<widget
name="web_ribbon"
title="Archived"
bg_color="bg-danger"
attrs="{'invisible': [('active', '=', True)]}"
/>
<field name="active" invisible="1" />
<group name="main">
<field name="code" />
<field name="description" />
<field name="company_id" groups="base.group_multi_company" />
</group>
</sheet>
</form>
</field>
</record>
<record id="intrastat_transaction_tree" model="ir.ui.view">
<field name="name">intrastat.transaction_tree</field>
<field name="model">intrastat.transaction</field>
<field name="arch" type="xml">
<tree>
<field name="code" />
<field name="description" />
<field name="company_id" groups="base.group_multi_company" />
</tree>
</field>
</record>
<record id="intrastat_transaction_mode_search" model="ir.ui.view">
<field name="name">intrastat.transaction.mode.search</field>
<field name="model">intrastat.transaction</field>
<field name="arch" type="xml">
<search>
<field
name="description"
string="Code or Description"
filter_domain="['|', ('code', 'ilike', self), ('description', 'ilike', self)]"
/>
<filter
string="Archived"
name="inactive"
domain="[('active', '=', False)]"
/>
<group string="Group By" name="groupby">
<filter
name="company_groupby"
string="Company"
context="{'group_by': 'company_id'}"
/>
</group>
</search>
</field>
</record>
<record id="intrastat_transaction_action" model="ir.actions.act_window">
<field name="name">Transaction Types</field>
<field name="res_model">intrastat.transaction</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem
id="intrastat_transaction_menu"
action="intrastat_transaction_action"
parent="intrastat_base.menu_intrastat_config_root"
sequence="20"
/>
</odoo>

View File

@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
© 2010-2017 Akretion (http://www.akretion.com/)
© 2015-2017 Noviat (http://www.noviat.com/)
@author Alexis de Lattre <alexis.delattre@akretion.com>
@author Luc De Meyer <luc.demeyer@noviat.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<!-- Intrastat Transport Mode -->
<record id="intrastat_transport_mode_form" model="ir.ui.view">
<field name="name">intrastat.transport.mode.form</field>
<field name="model">intrastat.transport_mode</field>
<field name="arch" type="xml">
<form>
<group>
<field name="name" />
<field name="code" />
<field name="description" />
</group>
</form>
</field>
</record>
<record id="intrastat_transport_mode_tree" model="ir.ui.view">
<field name="name">intrastat.transport.mode.tree</field>
<field name="model">intrastat.transport_mode</field>
<field name="arch" type="xml">
<tree>
<field name="code" />
<field name="name" />
<field name="description" optional="show" />
</tree>
</field>
</record>
<record id="intrastat_transport_mode_search" model="ir.ui.view">
<field name="name">intrastat.transport.mode.search</field>
<field name="model">intrastat.transport_mode</field>
<field name="arch" type="xml">
<search>
<field
name="name"
string="Name, Code or Description"
filter_domain="['|', '|', ('name', 'ilike', self), ('description', 'ilike', self), ('code', 'ilike', self)]"
/>
</search>
</field>
</record>
<record id="intrastat_transport_action" model="ir.actions.act_window">
<field name="name">Transport Modes</field>
<field name="res_model">intrastat.transport_mode</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem
id="intrastat_transport_menu"
action="intrastat_transport_action"
parent="intrastat_base.menu_intrastat_config_root"
sequence="30"
/>
</odoo>

View File

@@ -0,0 +1,77 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
© 2010-2017 Akretion (http://www.akretion.com/)
© 2015-2017 Noviat (http://www.noviat.com/)
@author Alexis de Lattre <alexis.delattre@akretion.com>
@author Luc De Meyer <luc.demeyer@noviat.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<!-- Intrastat Supplementary Unit -->
<record id="intrastat_unit_form" model="ir.ui.view">
<field name="name">intrastat.unit.form</field>
<field name="model">intrastat.unit</field>
<field name="arch" type="xml">
<form>
<field name="active" invisible="1" />
<widget
name="web_ribbon"
text="Archived"
bg_color="bg-danger"
attrs="{'invisible': [('active', '=', True)]}"
/>
<group name="main">
<field name="name" />
<field name="uom_id" required="1" />
<field name="description" />
</group>
</form>
</field>
</record>
<record id="intrastat_unit_tree" model="ir.ui.view">
<field name="name">intrastat.unit.tree</field>
<field name="model">intrastat.unit</field>
<field name="arch" type="xml">
<tree>
<field name="name" />
<field name="uom_id" />
<field name="description" optional="show" />
</tree>
</field>
</record>
<record id="intrastat_unit_search" model="ir.ui.view">
<field name="name">intrastat.unit.search</field>
<field name="model">intrastat.unit</field>
<field name="arch" type="xml">
<search>
<field
name="name"
filter_domain="['|', ('name', 'ilike', self), ('description', 'ilike', self)]"
/>
<filter
string="Archived"
name="inactive"
domain="[('active', '=', False)]"
/>
<group string="Group By" name="groupby">
<filter
name="uom_groupby"
string="Regular UoM"
context="{'group_by': 'uom_id'}"
/>
</group>
</search>
</field>
</record>
<record id="intrastat_unit_action" model="ir.actions.act_window">
<field name="name">Supplementary Units</field>
<field name="res_model">intrastat.unit</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem
id="intrastat_unit_menu"
action="intrastat_unit_action"
parent="intrastat_base.menu_intrastat_config_root"
sequence="40"
/>
</odoo>

View File

@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<template
id="report_invoice_document_intrastat_product"
inherit_id="account.report_invoice_document"
>
<xpath expr="//div[hasclass('page')]" position="inside">
<t t-if="o.partner_id.invoice_intrastat_detail">
<t
t-set="intrastat_lines_info"
t-value="o._get_intrastat_lines_info()"
/>
<t t-if="intrastat_lines_info">
<p style="page-break-before: always;" />
<h5>Intrastat information</h5>
<table name="intrastat_transaction_detail" class="table">
<thead>
<tr>
<th>Reference</th>
<th>Product</th>
<th>HS Code</th>
<th>Unit Weight</th>
<th>Weight</th>
<th>Origin country</th>
</tr>
</thead>
<tbody>
<tr t-foreach="intrastat_lines_info" t-as="line">
<td>
<span t-esc="line['product_id'].default_code" />
</td>
<td>
<span t-esc="line['product_id'].display_name" />
</td>
<td>
<span t-esc="line['hs_code_id'].local_code" />
</td>
<td>
<span t-esc="line['product_id'].weight" />
</td>
<td>
<span t-esc="round(line['weight'], 2)" />
</td>
<td>
<span t-esc="line['origin_country_id'].name" />
</td>
</tr>
</tbody>
</table>
</t>
</t>
</xpath>
</template>
</odoo>

View File

@@ -0,0 +1,64 @@
<?xml version="1.0" ?>
<!--
Copyright 2018-2020 brain-tec AG (Kumar Aberer <kumar.aberer@braintec-group.com>)
Copyright 2019-2020 Noviat (www.noviat.com)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="view_res_config_settings" model="ir.ui.view">
<field name="name">intrastat.account.config.settings.form</field>
<field name="model">res.config.settings</field>
<field
name="inherit_id"
ref="intrastat_base.view_intrastat_res_config_settings"
/>
<field name="arch" type="xml">
<div id="intrastat-settings" position="inside">
<div class="o_setting_left_pane" />
<div
class="o_setting_right_pane"
id="intrastat-product-main-params"
>
<div class="row">
<label for="intrastat_arrivals" class="col-md-5" />
<field name="intrastat_arrivals" />
<field name="country_id" invisible="1" />
</div>
<div class="row">
<label for="intrastat_dispatches" class="col-md-5" />
<field name="intrastat_dispatches" />
</div>
<div class="row">
<label for="intrastat_transport_id" class="col-md-5" />
<field name="intrastat_transport_id" />
</div>
<div
class="row"
attrs="{'invisible': [('country_code', 'not in', ['BE'])]}"
>
<label for="intrastat_region_id" class="col-md-5" />
<field
name="intrastat_region_id"
domain="[('country_id','=', country_id)]"
/>
</div>
</div>
<div class="o_setting_left_pane">
<field
name="intrastat_accessory_costs"
attrs="{'invisible': [('country_code', 'in', ['BE'])]}"
/>
</div>
<div class="o_setting_right_pane">
<div class="row">
<label
for="intrastat_accessory_costs"
class="col-12"
attrs="{'invisible': [('country_code', 'in', ['BE'])]}"
/>
</div>
</div>
</div>
</field>
</record>
</odoo>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" ?>
<odoo>
<record id="view_partner_property_form" model="ir.ui.view">
<field name="name">res.partner.form</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="account.view_partner_property_form" />
<field name="arch" type="xml">
<field name="property_account_position_id" position="after">
<field name="invoice_intrastat_detail" />
</field>
</field>
</record>
</odoo>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" ?>
<odoo>
<record id="sale_order_form" model="ir.ui.view">
<field name="name">intrastat.sale.order.form</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale_stock.view_order_form_inherit_sale_stock" />
<field name="arch" type="xml">
<field name="incoterm" position="after">
<field
name="intrastat_transport_id"
attrs="{'invisible': [('intrastat', '!=', 'extended')]}"
widget="selection"
/>
<field name="intrastat" invisible="1" />
</field>
</field>
</record>
</odoo>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" ?>
<odoo>
<record id="view_warehouse" model="ir.ui.view">
<field name="name">intrastat.stock.warehouse.form</field>
<field name="model">stock.warehouse</field>
<field name="inherit_id" ref="stock.view_warehouse" />
<field name="arch" type="xml">
<field name="partner_id" position="after">
<field name="region_id" />
</field>
</field>
</record>
</odoo>

View File

@@ -0,0 +1,2 @@
from . import res_config_settings
from . import intrastat_result_view

View File

@@ -0,0 +1,14 @@
# Copyright 2010-2021 Akretion (<alexis.delattre@akretion.com>)
# Copyright 2009-2021 Noviat (http://www.noviat.com)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models
class IntrastatResultView(models.TransientModel):
_name = "intrastat.result.view"
_description = "Pop-up to show errors on intrastat report generation"
note = fields.Html(
string="Notes", readonly=True, default=lambda self: self._context.get("note")
)

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
Copyright 2011-2021 Akretion France (http://www.akretion.com/)
Copyright 2015-2021 Noviat (http://www.noviat.com/)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="intrastat_result_view_form" model="ir.ui.view">
<field name="name">intrastat.result_view_form</field>
<field name="model">intrastat.result.view</field>
<field name="arch" type="xml">
<form string="Intrastat Result View">
<group name="main">
<field name="note" nolabel="1" colspan="2" />
</group>
<footer>
<button string="Ok" class="btn-primary" special="cancel" />
</footer>
</form>
</field>
</record>
</odoo>

View File

@@ -0,0 +1,28 @@
# Copyright 2017-2020 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# Copyright 2009-2020 Noviat (http://www.noviat.com)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import fields, models
class ResConfigSettings(models.TransientModel):
_inherit = "res.config.settings"
intrastat_arrivals = fields.Selection(
related="company_id.intrastat_arrivals", readonly=False
)
intrastat_dispatches = fields.Selection(
related="company_id.intrastat_dispatches", readonly=False
)
intrastat = fields.Char(related="company_id.intrastat")
intrastat_transport_id = fields.Many2one(
related="company_id.intrastat_transport_id", readonly=False
)
intrastat_region_id = fields.Many2one(
related="company_id.intrastat_region_id", readonly=False
)
intrastat_accessory_costs = fields.Boolean(
related="company_id.intrastat_accessory_costs", readonly=False
)
country_id = fields.Many2one(related="company_id.country_id")
# country_code is defined in the 'account' module

2
requirements.txt Normal file
View File

@@ -0,0 +1,2 @@
# generated from manifests external_dependencies
python-stdnum>=1.16

View File

@@ -0,0 +1 @@
../../../../intrastat_product

View File

@@ -0,0 +1,6 @@
import setuptools
setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)