Merge pull request #70 from akretion/12-mig-all

Migrate all modules from v11 to v12
This commit is contained in:
Alexis de Lattre
2019-06-03 14:00:30 +02:00
committed by GitHub
64 changed files with 453 additions and 267 deletions

View File

@@ -5,14 +5,14 @@
{
'name': 'Intrastat Reporting Base',
'version': '11.0.1.0.0',
'version': '12.0.1.0.0',
'category': 'Intrastat',
'license': 'AGPL-3',
'summary': 'Base module for Intrastat reporting',
'author': 'Akretion,Noviat,Odoo Community Association (OCA)',
'website': 'https://github.com/OCA/intrastat',
'depends': ['base_vat', 'account'],
'conflicts': ['report_intrastat'],
'excludes': ['account_intrastat'],
'data': [
'data/country_data.xml',
'views/product_template.xml',
@@ -25,5 +25,5 @@
'demo': [
'demo/intrastat_demo.xml',
],
'installable': False,
'installable': True,
}

View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 2011-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
Copyright 2011-2019 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).
-->
@@ -10,7 +11,7 @@
<field name="vat">FR58441019213</field>
</record>
<record id="base.res_partner_2" model="res.partner"> <!-- Agrolait -->
<record id="base.res_partner_2" model="res.partner"> <!-- Deco Addict -->
<field name="vat">BE0884025633</field>
<field name="supplier">True</field>
</record>

View File

@@ -1,4 +1,4 @@
# © 2011-2016 Akretion (http://www.akretion.com).
# Copyright 2011-2019 Akretion France (http://www.akretion.com).
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models, fields

View File

@@ -5,6 +5,7 @@
from io import BytesIO
from lxml import etree
from sys import exc_info
import base64
from traceback import format_exception
import logging
@@ -19,7 +20,6 @@ class IntrastatCommon(models.AbstractModel):
_description = "Common functions for intrastat reports for products "
"and services"
@api.multi
@api.depends('declaration_line_ids.amount_company_currency')
def _compute_numbers(self):
for this in self:
@@ -31,7 +31,6 @@ class IntrastatCommon(models.AbstractModel):
this.num_decl_lines = num_lines
this.total_amount = total_amount
@api.multi
def _check_generate_lines(self):
"""Check wether all requirements are met for generating lines."""
for this in self:
@@ -44,7 +43,6 @@ class IntrastatCommon(models.AbstractModel):
% company.name)
return True
@api.multi
def _check_generate_xml(self):
for this in self:
if not this.company_id.partner_id.vat:
@@ -76,12 +74,10 @@ class IntrastatCommon(models.AbstractModel):
logger.warning(error)
raise UserError(error)
@api.multi
def _attach_xml_file(self, xml_string, declaration_name):
'''Attach the XML file to the report_intrastat_product/service
object'''
self.ensure_one()
import base64
filename = '%s_%s.xml' % (self.year_month, declaration_name)
attach = self.env['ir.attachment'].create({
'name': filename,
@@ -91,7 +87,6 @@ class IntrastatCommon(models.AbstractModel):
'datas_fname': filename})
return attach.id
@api.multi
def _unlink_attachments(self):
atts = self.env['ir.attachment'].search(
[('res_model', '=', self._name),
@@ -114,7 +109,6 @@ class IntrastatCommon(models.AbstractModel):
}
return action
@api.multi
def _generate_xml(self):
"""
Inherit this method in the localization module
@@ -128,7 +122,6 @@ class IntrastatCommon(models.AbstractModel):
"""
return False
@api.multi
def send_reminder_email(self, mail_template_xmlid):
mail_template = self.env.ref(mail_template_xmlid)
for this in self:
@@ -143,7 +136,6 @@ class IntrastatCommon(models.AbstractModel):
'empty on company %s' % this.company_id.name)
return True
@api.multi
def unlink(self):
for intrastat in self:
if intrastat.state == 'done':
@@ -158,6 +150,7 @@ class IntrastatResultView(models.TransientModel):
Transient Model to display Intrastat Report results
"""
_name = 'intrastat.result.view'
_description = 'Pop-up to show errors on intrastat report generation'
note = fields.Text(
string='Notes', readonly=True,

View File

@@ -14,7 +14,6 @@ class ProductTemplate(models.Model):
"costs and all services related to the sale of products. "
"This option is used for Intrastat reports.")
@api.multi
@api.constrains('type', 'is_accessory_cost')
def _check_accessory_cost(self):
for this in self:

View File

@@ -1,4 +1,5 @@
# Copyright 2013-2017 Akretion (<alexis.delattre@akretion.com>)
# Copyright 2013-2017 Akretion France (http://www.akretion.com/)
# @author: <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models, _
@@ -17,7 +18,6 @@ class ResCompany(models.Model):
compute='_compute_intrastat_email_list',
string='List of emails of Users Receiving the Intrastat Reminder')
@api.multi
@api.depends(
'intrastat_remind_user_ids', 'intrastat_remind_user_ids.email')
def _compute_intrastat_email_list(self):
@@ -28,7 +28,6 @@ class ResCompany(models.Model):
emails.append(user.email)
this.intrastat_email_list = ','.join(emails)
@api.multi
@api.constrains('intrastat_remind_user_ids')
def _check_intrastat_remind_users(self):
for this in self:

View File

@@ -9,4 +9,4 @@ class ResConfigSettings(models.TransientModel):
_inherit = 'res.config.settings'
intrastat_remind_user_ids = fields.Many2many(
related='company_id.intrastat_remind_user_ids')
related='company_id.intrastat_remind_user_ids', readonly=False)

View File

@@ -1,4 +1,5 @@
# Copyright 2011-2014 Akretion (<alexis.delattre@akretion.com>)
# Copyright 2011-2019 Akretion France (http://www.akretion.com/)
# @author: <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models

View File

@@ -0,0 +1,4 @@
* Alexis de Lattre, Akretion <alexis.delattre@akretion.com>
* Luc De Meyer, Noviat <info@noviat.com>
* Kumar Aberer, brain-tec AG <kumar.aberer@braintec-group.com>
* Andrea Stirpe <a.stirpe@onestein.nl>

View File

@@ -0,0 +1,11 @@
This module contains common functions for the intrastat reporting and
should be used in combination with the generic reporting module
*intrastat_product* and with the country-specific reporting modules such
as:
- *l10n_fr_intrastat_service*:
the module for the *Déclaration Européenne des Services* (DES) for France
- *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 Declaration for Belgium.

View File

@@ -0,0 +1,5 @@
WARNING:
This module conflicts with the module *account_intrastat* from Odoo Enterprise.
If you have already installed the module *account_intrastat*,
you should uninstall it first before installing this module.

View File

@@ -0,0 +1,9 @@
This module adds an intrastat property on countries and activates this property
on the countries of the European Union.
With this module, the country field on partners becomes a required field.
It adds an option *Exclude invoice line from intrastat if this tax is present*
on taxes.
It adds an *Intrastat* section on the *Invoicing* configuration page.

View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 2011-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
Copyright 2011-2019 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).
-->

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 2011-2016 Akretion (http://www.akretion.com/)
© 2015-2016 Noviat (http://www.noviat.com/)
Copyright 2011-2016 Akretion France (http://www.akretion.com/)
Copyright 2015-2016 Noviat (http://www.noviat.com/)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->

View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 2010-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
Copyright 2010-2019 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).
-->

View File

@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 2013-2017 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
© 2018 brain-tec AG (Kumar Aberer <kumar.aberer@braintec-group.com>)
Copyright 2013-2019 Akretion France (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
Copyright 2018 brain-tec AG (Kumar Aberer <kumar.aberer@braintec-group.com>)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
@@ -21,7 +22,7 @@
<div class="row">
<label for="intrastat_remind_user_ids" class="col-md-5 o_light_label"/>
<field name="intrastat_remind_user_ids" widget="many2many_tags"/>
</div>
</div>
</div>
</div>
</div>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 2011-2016 Akretion (http://www.akretion.com)
Copyright 2011-2016 Akretion France (http://www.akretion.com)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
@@ -36,10 +36,14 @@
<field name="model">res.country</field>
<field name="arch" type="xml">
<search string="Search Countries">
<field name="name" />
<field name="name" filter_domain="['|', ('name', 'ilike', self), ('code', '=', self)]" string="Name or Code"/>
<field name="code" />
<field name="currency_id"/>
<filter name="intrastat" string="EU Country"
domain="[('intrastat', '=', True)]" />
domain="[('intrastat', '=', True)]" />
<group string="Group By" name="groupby">
<filter name="currency_groupby" string="Currency" context="{'group_by': 'currency_id'}"/>
</group>
</search>
</field>
</record>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 2010-2016 Akretion (http://www.akretion.com/)
Copyright 2010-2019 Akretion France (http://www.akretion.com/)
@author David BEAL <david.beal@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->

View File

@@ -7,7 +7,7 @@
{
'name': 'Intrastat Product',
'version': '11.0.1.2.0',
'version': '12.0.1.0.0',
'category': 'Intrastat',
'license': 'AGPL-3',
'summary': 'Base module for Intrastat Product',
@@ -17,10 +17,10 @@
'intrastat_base',
'product_harmonized_system',
'sale_stock',
'purchase',
'purchase_stock',
'report_xlsx_helper',
],
'excludes': ['report_intrastat'],
'excludes': ['account_intrastat'],
'data': [
'views/hs_code.xml',
'views/intrastat_region.xml',
@@ -38,5 +38,5 @@
'data/intrastat_unit.xml',
],
'demo': ['demo/intrastat_demo.xml'],
'installable': False,
'installable': True,
}

View File

@@ -18,7 +18,7 @@
<record id="intrastat_unit_g" model="intrastat.unit">
<field name="name">g</field>
<field name="description">Gram</field>
<field name="uom_id" ref="product.product_uom_gram"/>
<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>
@@ -71,7 +71,7 @@
<record id="intrastat_unit_l" model="intrastat.unit">
<field name="name">l</field>
<field name="description">Litre</field>
<field name="uom_id" ref="product.product_uom_litre"/>
<field name="uom_id" ref="uom.product_uom_litre"/>
</record>
<record id="intrastat_unit_1000l" model="intrastat.unit">
<field name="name">1000 l</field>
@@ -84,7 +84,7 @@
<record id="intrastat_unit_m" model="intrastat.unit">
<field name="name">m</field>
<field name="description">Metre</field>
<field name="uom_id" ref="product.product_uom_meter"/>
<field name="uom_id" ref="uom.product_uom_meter"/>
</record>
<record id="intrastat_unit_m2" model="intrastat.unit">
<field name="name">m2</field>
@@ -105,7 +105,7 @@
<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="product.product_uom_unit"/>
<field name="uom_id" ref="uom.product_uom_unit"/>
</record>
<record id="intrastat_unit_100pce" model="intrastat.unit">
<field name="name">100 items</field>

View File

@@ -18,7 +18,7 @@
<record id="base.main_company" model="res.company">
<field name="intrastat_arrivals">extended</field>
<field name="intrastat_dispatches">extended</field>
<field name="intrastat_incoterm_id" ref="stock.incoterm_DDU"/>
<field name="intrastat_incoterm_id" ref="account.incoterm_DDU"/>
<field name="intrastat_transport_id" ref="intrastat_transport_3"/>
</record>

View File

@@ -1,4 +1,4 @@
# Copyright 2011-2017 Akretion (http://www.akretion.com)
# Copyright 2011-2017 Akretion France (http://www.akretion.com)
# Copyright 2009-2018 Noviat (http://www.noviat.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# @author Luc de Meyer <info@noviat.com>
@@ -9,8 +9,6 @@ from odoo import api, fields, models
class AccountInvoice(models.Model):
_inherit = 'account.invoice'
# in v10, the sale_stock module defines an incoterms_id
# Odoo v8 name: incoterm_id
intrastat_transaction_id = fields.Many2one(
comodel_name='intrastat.transaction',
string='Intrastat Transaction Type',
@@ -29,7 +27,7 @@ class AccountInvoice(models.Model):
"arrivals.")
intrastat_country = fields.Boolean(
compute='_compute_intrastat_country', string='Intrastat Country',
store=True, readonly=True, compute_sudo=True)
store=True, compute_sudo=True)
src_dest_region_id = fields.Many2one(
comodel_name='intrastat.region',
string='Origin/Destination Region',
@@ -39,9 +37,8 @@ class AccountInvoice(models.Model):
ondelete='restrict')
intrastat = fields.Char(
string='Intrastat Declaration',
related='company_id.intrastat', readonly=True, compute_sudo=True)
related='company_id.intrastat')
@api.multi
@api.depends('partner_shipping_id.country_id', 'partner_id.country_id')
def _compute_intrastat_country(self):
for inv in self:
@@ -55,7 +52,7 @@ class AccountInvoice(models.Model):
@api.model
def _default_src_dest_region_id(self):
rco = self.env['res.company']
company = rco._company_default_get('account.invoice')
company = rco._company_default_get()
return company.intrastat_region_id

View File

@@ -1,4 +1,4 @@
# Copyright 2011-2017 Akretion (http://www.akretion.com)
# Copyright 2011-2017 Akretion France (http://www.akretion.com)
# Copyright 2009-2018 Noviat (http://www.noviat.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# @author Luc de Meyer <info@noviat.com>
@@ -27,35 +27,24 @@ class IntrastatProductDeclaration(models.Model):
]
@api.model
def _default_year(self):
if datetime.now().month == 1:
year = datetime.now().year - 1
else:
year = datetime.now().year
return str(year)
@api.model
def _default_month(self):
if datetime.now().month == 1:
return 12
else:
return datetime.now().month - 1
@api.model
def _default_action(self):
return 'replace'
def default_get(self, fields_list):
res = super(IntrastatProductDeclaration, self).default_get(fields_list)
decl_date = fields.Date.context_today(self) - relativedelta(months=1)
res.update({
'year': str(decl_date.year),
'month': decl_date.month,
})
return res
company_id = fields.Many2one(
comodel_name='res.company', string='Company', readonly=True,
default=lambda self: self.env['res.company']._company_default_get(
'intrastat.product.declaration'))
default=lambda self: self.env['res.company']._company_default_get())
company_country_code = fields.Char(
compute='_compute_company_country_code',
string='Company Country Code', readonly=True, store=True,
help="Used in views and methods of localization modules.")
year = fields.Char(
string='Year', required=True,
default=lambda self: self._default_year(),
states={'done': [('readonly', True)]})
month = fields.Selection([
(1, '01'),
@@ -71,7 +60,6 @@ class IntrastatProductDeclaration(models.Model):
(11, '11'),
(12, '12')
], string='Month', required=True,
default=lambda self: self._default_month(),
states={'done': [('readonly', True)]})
year_month = fields.Char(
compute='_compute_year_month', string='Period', readonly=True,
@@ -84,7 +72,7 @@ class IntrastatProductDeclaration(models.Model):
action = fields.Selection(
selection='_get_action',
string='Action', required=True,
default=lambda self: self._default_action(),
default='replace',
states={'done': [('readonly', True)]},
track_visibility='onchange')
revision = fields.Integer(
@@ -107,8 +95,7 @@ class IntrastatProductDeclaration(models.Model):
compute='_compute_numbers', string='Total Fiscal Amount', store=True,
help="Total fiscal amount in company currency of the declaration.")
currency_id = fields.Many2one(
'res.currency', related='company_id.currency_id', readonly=True,
string='Currency')
'res.currency', related='company_id.currency_id', string='Currency')
state = fields.Selection(
selection=[('draft', 'Draft'),
('done', 'Done')],
@@ -152,7 +139,6 @@ class IntrastatProductDeclaration(models.Model):
('append', 'Append'),
('nihil', 'Nihil')]
@api.multi
@api.depends('company_id')
def _compute_company_country_code(self):
for this in self:
@@ -163,7 +149,6 @@ class IntrastatProductDeclaration(models.Model):
this.company_country_code = \
this.company_id.country_id.code.lower()
@api.multi
@api.depends('year', 'month')
def _compute_year_month(self):
for this in self:
@@ -171,7 +156,6 @@ class IntrastatProductDeclaration(models.Model):
this.year_month = '-'.join(
[this.year, format(this.month, '02')])
@api.multi
@api.depends('month')
def _compute_check_validity(self):
""" TO DO: logic based upon computation lines """
@@ -196,7 +180,6 @@ class IntrastatProductDeclaration(models.Model):
self.company_id.intrastat_dispatches == 'extended' \
and 'extended' or 'standard'
@api.multi
def copy(self, default=None):
self.ensure_one()
default = default or {}
@@ -322,10 +305,9 @@ class IntrastatProductDeclaration(models.Model):
def _get_amount(self, inv_line):
invoice = inv_line.invoice_id
amount = invoice.currency_id.with_context(
date=invoice.date_invoice).compute(
inv_line.price_subtotal,
self.company_id.currency_id)
amount = invoice.currency_id._convert(
inv_line.price_subtotal, self.company_id.currency_id,
self.company_id, invoice.date_invoice)
return amount
def _get_region(self, inv_line):
@@ -379,7 +361,10 @@ class IntrastatProductDeclaration(models.Model):
return transport
def _get_incoterm(self, inv_line):
incoterm = inv_line.invoice_id.incoterms_id \
# WARNING for v12: there are 2 incoterm fields on account.invoice
# cf https://github.com/odoo/odoo/issues/31641
# the field to use is 'incoterm_id' defined in the 'account' module
incoterm = inv_line.invoice_id.incoterm_id \
or self.company_id.intrastat_incoterm_id
if not incoterm:
msg = _(
@@ -441,7 +426,7 @@ class IntrastatProductDeclaration(models.Model):
domain = [
('date_invoice', '>=', start_date),
('date_invoice', '<=', end_date),
('state', 'in', ['open', 'paid']),
('state', 'in', ['open', 'in_payment', 'paid']),
('intrastat_country', '=', True),
('company_id', '=', self.company_id.id)]
return domain
@@ -479,10 +464,11 @@ class IntrastatProductDeclaration(models.Model):
accessory_costs and
inv_line.product_id and
inv_line.product_id.is_accessory_cost):
acost = invoice.currency_id.with_context(
date=invoice.date_invoice).compute(
inv_line.price_subtotal,
self.company_id.currency_id)
acost = invoice.currency_id._convert(
inv_line.price_subtotal,
self.company_id.currency_id,
self.company_id,
invoice.date_invoice)
total_inv_accessory_costs_cc += acost
continue
@@ -599,14 +585,13 @@ class IntrastatProductDeclaration(models.Model):
def _get_uom_refs(self, ref):
uom_refs = {
'weight_uom_categ': self.env.ref('product.product_uom_categ_kgm'),
'kg_uom': self.env.ref('product.product_uom_kgm'),
'pce_uom_categ': self.env.ref('product.product_uom_categ_unit'),
'pce_uom': self.env.ref('product.product_uom_unit')
'weight_uom_categ': self.env.ref('uom.product_uom_categ_kgm'),
'kg_uom': self.env.ref('uom.product_uom_kgm'),
'pce_uom_categ': self.env.ref('uom.product_uom_categ_unit'),
'pce_uom': self.env.ref('uom.product_uom_unit')
}
return uom_refs[ref]
@api.multi
def action_gather(self):
self.ensure_one()
self.message_post(body=_("Generate Lines from Invoices"))
@@ -716,7 +701,6 @@ class IntrastatProductDeclaration(models.Model):
vals['amount_company_currency']))
return vals
@api.multi
def generate_declaration(self):
""" generate declaration lines """
self.ensure_one()
@@ -740,7 +724,6 @@ class IntrastatProductDeclaration(models.Model):
cl.write({'declaration_line_id': declaration_line.id})
return True
@api.multi
def generate_xml(self):
""" generate the INTRASTAT Declaration XML file """
self.ensure_one()
@@ -756,7 +739,6 @@ class IntrastatProductDeclaration(models.Model):
raise UserError(
_("No XML File has been generated."))
@api.multi
def create_xls(self):
if self.env.context.get('computation_lines'):
report_file = 'instrastat_transactions'
@@ -802,11 +784,9 @@ class IntrastatProductDeclaration(models.Model):
"""
return {}
@api.multi
def done(self):
self.write({'state': 'done'})
@api.multi
def back2draft(self):
self.write({'state': 'draft'})
@@ -819,20 +799,11 @@ class IntrastatProductComputationLine(models.Model):
'intrastat.product.declaration',
string='Intrastat Product Declaration',
ondelete='cascade', readonly=True)
company_id = fields.Many2one(
'res.company', related='parent_id.company_id',
string="Company", readonly=True)
company_id = fields.Many2one(related='parent_id.company_id')
company_currency_id = fields.Many2one(
'res.currency', related='company_id.currency_id',
string="Company currency", readonly=True)
type = fields.Selection(
related='parent_id.type',
string='Type',
readonly=True)
reporting_level = fields.Selection(
related='parent_id.reporting_level',
string='Reporting Level',
readonly=True)
related='company_id.currency_id', string="Company currency")
type = fields.Selection(related='parent_id.type')
reporting_level = fields.Selection(related='parent_id.reporting_level')
valid = fields.Boolean(
compute='_compute_check_validity',
string='Valid')
@@ -840,7 +811,7 @@ class IntrastatProductComputationLine(models.Model):
'account.invoice.line', string='Invoice Line', readonly=True)
invoice_id = fields.Many2one(
'account.invoice', related='invoice_line_id.invoice_id',
string='Invoice', readonly=True)
string='Invoice')
declaration_line_id = fields.Many2one(
'intrastat.product.declaration.line',
string='Declaration Line', readonly=True)
@@ -849,14 +820,12 @@ class IntrastatProductComputationLine(models.Model):
help="Country of Origin/Destination",
domain=[('intrastat', '=', True)])
product_id = fields.Many2one(
'product.product', related='invoice_line_id.product_id',
string='Product', readonly=True)
'product.product', related='invoice_line_id.product_id')
hs_code_id = fields.Many2one(
'hs.code', string='Intrastat Code')
intrastat_unit_id = fields.Many2one(
'intrastat.unit', related='hs_code_id.intrastat_unit_id',
string='Suppl. Unit', readonly=True,
help="Intrastat Supplementary Unit")
string='Suppl. Unit', help="Intrastat Supplementary Unit")
weight = fields.Float(
string='Weight',
digits=dp.get_precision('Stock Weight'), help="Net weight in Kg")
@@ -883,7 +852,7 @@ class IntrastatProductComputationLine(models.Model):
'intrastat.region', string='Intrastat Region')
# extended declaration
incoterm_id = fields.Many2one(
'stock.incoterms', string='Incoterm')
'account.incoterms', string='Incoterm')
transport_id = fields.Many2one(
'intrastat.transport_mode',
string='Transport Mode')
@@ -891,13 +860,15 @@ class IntrastatProductComputationLine(models.Model):
'res.country', string='Country of Origin of the Product',
help="Country of origin of the product i.e. product 'made in ____'")
@api.multi
@api.depends('transport_id')
def _compute_check_validity(self):
""" TO DO: logic based upon fields """
for this in self:
this.valid = True
# TODO: product_id is a readonly related field 'invoice_line_id.product_id'
# so the onchange is non-sense. Either we convert product_id to a regular
# field or we keep it a related field and we remove this onchange
@api.onchange('product_id')
def _onchange_product(self):
self.weight = 0.0
@@ -920,20 +891,11 @@ class IntrastatProductDeclarationLine(models.Model):
'intrastat.product.declaration',
string='Intrastat Product Declaration',
ondelete='cascade', readonly=True)
company_id = fields.Many2one(
'res.company', related='parent_id.company_id',
string="Company", readonly=True)
company_id = fields.Many2one(related='parent_id.company_id')
company_currency_id = fields.Many2one(
'res.currency', related='company_id.currency_id',
string="Company currency", readonly=True)
type = fields.Selection(
related='parent_id.type',
string='Type',
readonly=True)
reporting_level = fields.Selection(
related='parent_id.reporting_level',
string='Reporting Level',
readonly=True)
related='company_id.currency_id', string="Company currency")
type = fields.Selection(related='parent_id.type')
reporting_level = fields.Selection(related='parent_id.reporting_level')
computation_line_ids = fields.One2many(
'intrastat.product.computation.line', 'declaration_line_id',
string='Computation Lines', readonly=True)
@@ -946,8 +908,7 @@ class IntrastatProductDeclarationLine(models.Model):
string='Intrastat Code')
intrastat_unit_id = fields.Many2one(
'intrastat.unit', related='hs_code_id.intrastat_unit_id',
string='Suppl. Unit', readonly=True,
help="Intrastat Supplementary Unit")
string='Suppl. Unit', help="Intrastat Supplementary Unit")
weight = fields.Integer(
string='Weight', help="Net weight in Kg")
suppl_unit_qty = fields.Integer(
@@ -965,7 +926,7 @@ class IntrastatProductDeclarationLine(models.Model):
'intrastat.region', string='Intrastat Region')
# extended declaration
incoterm_id = fields.Many2one(
'stock.incoterms', string='Incoterm')
'account.incoterms', string='Incoterm')
transport_id = fields.Many2one(
'intrastat.transport_mode',
string='Transport Mode')

View File

@@ -20,5 +20,4 @@ class IntrastatRegion(models.Model):
description = fields.Char(string='Description')
company_id = fields.Many2one(
comodel_name='res.company', string='Company',
default=lambda self: self.env['res.company']._company_default_get(
'intrastat.region'))
default=lambda self: self.env['res.company']._company_default_get())

View File

@@ -1,4 +1,4 @@
# Copyright 2011-2017 Akretion (http://www.akretion.com)
# Copyright 2011-2017 Akretion France (http://www.akretion.com)
# Copyright 2009-2018 Noviat (http://www.noviat.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# @author Luc de Meyer <info@noviat.com>
@@ -10,7 +10,6 @@ class IntrastatTransaction(models.Model):
_name = 'intrastat.transaction'
_description = "Intrastat Transaction"
_order = 'code'
_rec_name = 'display_name'
_sql_constraints = [(
'intrastat_transaction_code_unique',
'UNIQUE(code, company_id)',
@@ -18,21 +17,17 @@ class IntrastatTransaction(models.Model):
code = fields.Char(string='Code', required=True)
description = fields.Text(string='Description')
display_name = fields.Char(
compute='_compute_display_name_field', string="Display Name",
readonly=True, store=True)
company_id = fields.Many2one(
comodel_name='res.company', string='Company',
default=lambda self: self.env['res.company']._company_default_get(
'intrastat.transaction'))
default=lambda self: self.env['res.company']._company_default_get())
@api.multi
@api.depends('code', 'description')
def _compute_display_name_field(self):
def name_get(self):
res = []
for this in self:
display_name = this.code
name = this.code
if this.description:
display_name += ' ' + this.description
this.display_name = len(display_name) > 55 \
and display_name[:55] + '...' \
or display_name
name += ' ' + this.description
name = len(name) > 55 and name[:55] + '...' or name
res.append((this.id, this.name))
return res

View File

@@ -9,22 +9,20 @@ from odoo import api, fields, models
class IntrastatTransportMode(models.Model):
_name = 'intrastat.transport_mode'
_description = "Intrastat Transport Mode"
_rec_name = 'display_name'
_order = 'code'
_sql_constraints = [(
'intrastat_transport_code_unique',
'UNIQUE(code)',
'Code must be unique.')]
display_name = fields.Char(
string='Display Name', compute='_compute_display_name', store=True,
readonly=True)
code = fields.Char(string='Code', required=True)
name = fields.Char(string='Name', required=True, translate=True)
description = fields.Char(string='Description', translate=True)
@api.multi
@api.depends('name', 'code')
def _compute_display_name(self):
for this in self:
this.display_name = '%s. %s' % (this.code, this.name)
def name_get(self):
res = []
for mode in self:
name = '%s. %s' % (mode.code, mode.name)
res.append((mode.id, name))
return res

View File

@@ -13,7 +13,7 @@ class IntrastatUnit(models.Model):
name = fields.Char(string='Name', required=True)
description = fields.Char(string='Description', required=True)
uom_id = fields.Many2one(
comodel_name='product.uom', string='Regular UoM',
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

@@ -10,7 +10,7 @@ class ResCompany(models.Model):
_inherit = 'res.company'
intrastat_incoterm_id = fields.Many2one(
comodel_name='stock.incoterms',
comodel_name='account.incoterms',
string='Default Incoterm for Intrastat',
help="International Commercial Terms are a series of "
"predefined commercial terms used in international "
@@ -59,7 +59,6 @@ class ResCompany(models.Model):
('standard', 'Standard'),
('extended', 'Extended')]
@api.multi
@api.depends('intrastat_arrivals', 'intrastat_dispatches')
def _compute_intrastat(self):
for this in self:

View File

@@ -9,27 +9,25 @@ class ResConfigSettings(models.TransientModel):
_inherit = 'res.config.settings'
intrastat_incoterm_id = fields.Many2one(
related='company_id.intrastat_incoterm_id')
related='company_id.intrastat_incoterm_id', readonly=False)
intrastat_arrivals = fields.Selection(
related='company_id.intrastat_arrivals')
related='company_id.intrastat_arrivals', readonly=False)
intrastat_dispatches = fields.Selection(
related='company_id.intrastat_dispatches')
intrastat = fields.Char(related='company_id.intrastat', readonly=True)
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')
related='company_id.intrastat_transport_id', readonly=False)
intrastat_region_id = fields.Many2one(
related='company_id.intrastat_region_id')
related='company_id.intrastat_region_id', readonly=False)
intrastat_transaction_out_invoice = fields.Many2one(
related='company_id.intrastat_transaction_out_invoice')
related='company_id.intrastat_transaction_out_invoice', readonly=False)
intrastat_transaction_out_refund = fields.Many2one(
related='company_id.intrastat_transaction_out_refund')
related='company_id.intrastat_transaction_out_refund', readonly=False)
intrastat_transaction_in_invoice = fields.Many2one(
related='company_id.intrastat_transaction_in_invoice')
related='company_id.intrastat_transaction_in_invoice', readonly=False)
intrastat_transaction_in_refund = fields.Many2one(
related='company_id.intrastat_transaction_in_refund')
related='company_id.intrastat_transaction_in_refund', readonly=False)
intrastat_accessory_costs = fields.Boolean(
related='company_id.intrastat_accessory_costs')
country_id = fields.Many2one(
related='company_id.country_id', readonly=True)
country_code = fields.Char(
related='company_id.country_id.code', readonly=True)
related='company_id.intrastat_accessory_costs', readonly=False)
country_id = fields.Many2one(related='company_id.country_id')
country_code = fields.Char(related='company_id.country_id.code')

View File

@@ -1,7 +1,8 @@
# Copyright 2010-2017 Akretion (http://www.akretion.com)
# Copyright 2010-2019 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 api, fields, models
from odoo import fields, models
class SaleOrder(models.Model):
@@ -12,9 +13,8 @@ class SaleOrder(models.Model):
help="This information is used in Intrastat reports")
intrastat = fields.Selection(
string='Intrastat Declaration',
related='company_id.intrastat_dispatches', readonly=True)
related='company_id.intrastat_dispatches')
@api.multi
def _prepare_invoice(self):
'''Copy destination country to invoice'''
vals = super(SaleOrder, self)._prepare_invoice()

View File

@@ -2,7 +2,7 @@
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# @author Luc de Meyer <info@noviat.com>
from odoo import api, fields, models
from odoo import fields, models
class StockWarehouse(models.Model):
@@ -15,14 +15,11 @@ class StockWarehouse(models.Model):
class StockLocation(models.Model):
_inherit = 'stock.location'
@api.multi
def get_intrastat_region(self):
self.ensure_one()
locations = self.search(
[('parent_left', '<=', self.parent_left),
('parent_right', '>=', self.parent_right)])
locations = self.search([('id', 'parent_of', self.id)])
warehouses = self.env['stock.warehouse'].search([
('lot_stock_id', 'in', [x.id for x in locations]),
('lot_stock_id', 'in', locations.ids),
('region_id', '!=', False)])
if warehouses:
return warehouses[0].region_id

View File

@@ -0,0 +1,2 @@
* Alexis de Lattre, Akretion <alexis.delattre@akretion.com>
* Luc De Meyer, Noviat <info@noviat.com>

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,34 @@
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.

View File

@@ -205,8 +205,9 @@ class IntrastatProductDeclarationXlsx(models.AbstractModel):
wl = declaration._xls_declaration_line_fields()
report = 'declaration'
title = self._get_title(declaration, report, format='normal')
title_short = self._get_title(declaration, report, format='short')
title = self._get_title(declaration, report, title_format='normal')
title_short = self._get_title(declaration, report,
title_format='short')
sheet_name = title_short[:31].replace('/', '-')
params = {
@@ -218,9 +219,9 @@ class IntrastatProductDeclarationXlsx(models.AbstractModel):
}
return [params]
def _get_title(self, declaration, report, format='normal'):
def _get_title(self, declaration, report, title_format='normal'):
title = declaration.year_month
if format == 'normal':
if title_format == 'normal':
if report == 'computation':
title += ' : ' + _('Computation Lines')
else:

View File

@@ -120,7 +120,7 @@
<field name="name">intrastat.product.declaration.graph</field>
<field name="model">intrastat.product.declaration</field>
<field name="arch" type="xml">
<graph string="Intrastat Product" type="bar">
<graph string="Intrastat Product" type="bar" stacked="False">
<field name="year_month" type="row"/>
<field name="type" type="row"/>
<field name="total_amount" type="measure"/>
@@ -128,6 +128,19 @@
</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 string="Intrastat Product">
<field name="year_month" type="row"/>
<field name="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">
@@ -150,9 +163,8 @@
<field name="company_currency_id" invisible="1"/>
<field name="transaction_id"/>
<label for="weight"/>
<div>
<field name="weight" class="oe_inline"/>
<label string=" Kg" class="oe_inline"/>
<div name="weight">
<field name="weight" class="oe_inline"/> Kg
</div>
<field name="suppl_unit_qty"/>
<field name="intrastat_unit_id"/>
@@ -216,9 +228,8 @@
<field name="company_currency_id" invisible="1"/>
<field name="transaction_id"/>
<label for="weight"/>
<div>
<field name="weight" class="oe_inline"/>
<label string=" Kg" class="oe_inline"/>
<div name="weight">
<field name="weight" class="oe_inline"/> Kg
</div>
<field name="suppl_unit_qty"/>
<field name="intrastat_unit_id"/>

View File

@@ -15,11 +15,17 @@
<field name="model">intrastat.unit</field>
<field name="arch" type="xml">
<form string="Intrastat Supplementary Unit">
<group>
<div class="oe_button_box" name="button_box">
<button name="toggle_active" type="object"
class="oe_stat_button" icon="fa-archive">
<field name="active" widget="boolean_button"
options='{"terminology": "archive"}'/>
</button>
</div>
<group name="main">
<field name="name"/>
<field name="uom_id" required="1"/>
<field name="description"/>
<field name="active"/>
</group>
</form>
</field>
@@ -43,11 +49,12 @@
<field name="arch" type="xml">
<search string="Search Intrastat Supplementary Units">
<field name="name"
filter_domain="['|', ('name', 'ilike', self), ('description', 'ilike', self)]"/>
<group string="Group By" name="groupby">
<filter name="uom_groupby" string="Regular UoM"
context="{'group_by': 'uom_id'}"/>
</group>
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>

View File

@@ -21,7 +21,7 @@
<div class="col-xs-12 col-md-12 o_setting_box">
<div class="o_setting_left_pane"/>
<div class="o_setting_right_pane">
<div class="o_setting_right_pane" id="intrastat-product-main-params">
<div class="row">
<label for="intrastat_arrivals" class="col-md-5 o_light_label"/>
<field name="intrastat_arrivals"/>
@@ -34,7 +34,7 @@
<label for="intrastat_transport_id" class="col-md-5 o_light_label"/>
<field name="intrastat_transport_id"/>
</div>
<div class="row">
<div class="row" attrs="{'invisible': [('country_code', 'in', ['FR'])]}">
<label for="intrastat_incoterm_id" class="col-md-5 o_light_label"/>
<field name="intrastat_incoterm_id"/>
</div>
@@ -50,7 +50,7 @@
<label for="intrastat_transaction_in_invoice" class="col-md-5 o_light_label"/>
<field name="intrastat_transaction_in_invoice"/>
</div>
<div class="row">
<div class="row" attrs="{'invisible': [('country_code', 'in', ['FR'])]}">
<label for="intrastat_transaction_in_refund" class="col-md-5 o_light_label"/>
<field name="intrastat_transaction_in_refund"/>
</div>

View File

@@ -3,13 +3,13 @@
{
'name': 'Generic Intrastat Product Declaration',
'version': '11.0.1.0.0',
'version': '12.0.1.0.0',
'category': 'Accounting & Finance',
'website': 'https://github.com/OCA/intrastat',
'author': 'Noviat,'
'Odoo Community Association (OCA)',
'license': 'AGPL-3',
'installable': False,
'installable': True,
'depends': [
'intrastat_product',
],

View File

@@ -0,0 +1 @@
* Luc De Meyer <luc.demeyer@noviat.com>

View File

@@ -0,0 +1,2 @@
This module adds a menu entry for a Generic Intrastat Product Declaration.
This is useful to cover countries for which there is no localization module.

View File

@@ -5,7 +5,7 @@
<field name="name">Generic Intrastat Product Declaration</field>
</record>
<record id="base.user_root" model="res.users">
<record id="base.user_admin" model="res.users">
<field eval="[(4, ref('group_intrastat_product_generic'))]" name="groups_id"/>
</record>

View File

@@ -4,7 +4,7 @@
<record id="intrastat_product_declaration_action_generic" model="ir.actions.act_window">
<field name="name">Generic Intrastat Product Declaration</field>
<field name="res_model">intrastat.product.declaration</field>
<field name="view_mode">tree,form,graph</field>
<field name="view_mode">tree,form,graph,pivot</field>
<field name="context">{'generic_intrastat_product_declaration': 1}</field>
</record>

View File

@@ -8,14 +8,14 @@
{
'name': 'Product Harmonized System Codes',
'version': '11.0.1.0.0',
'version': '12.0.1.0.0',
'category': 'Reporting',
'license': 'AGPL-3',
'summary': 'Base module for Product Import/Export reports',
'author': 'brain-tec AG, Akretion, Noviat, '
'Odoo Community Association (OCA)',
'depends': ['product'],
'conflicts': ['report_intrastat'],
'excludes': ['account_intrastat'],
'data': [
'security/product_hs_security.xml',
'security/ir.model.access.csv',
@@ -26,5 +26,5 @@
'demo': [
'demo/product_demo.xml',
],
'installable': False,
'installable': True,
}

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 2011-2016 Akretion (http://www.akretion.com/)
Copyright 2011-2019 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).
-->
@@ -53,12 +53,6 @@
<field name="weight">0.67</field>
</record>
<record id="product.product_product_17" model="product.product">
<field name="hs_code_id" ref="84717050" />
<field name="origin_country_id" ref="base.sg" />
<field name="weight">0.75</field>
</record>
<record id="product.product_product_20" model="product.product">
<field name="hs_code_id" ref="85340090" />
<field name="origin_country_id" ref="base.tw" />

View File

@@ -1,4 +1,4 @@
# Copyright 2011-2016 Akretion (http://www.akretion.com)
# Copyright 2011-2016 Akretion France (http://www.akretion.com)
# Copyright 2009-2016 Noviat (http://www.noviat.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# @author Luc de Meyer <info@noviat.com>
@@ -11,7 +11,7 @@ class HSCode(models.Model):
_name = "hs.code"
_description = "H.S. Code"
_order = "local_code"
_rec_name = "display_name"
_rec_name = "local_code"
hs_code = fields.Char(
string='H.S. Code', compute='_compute_hs_code', readonly=True,
@@ -21,9 +21,6 @@ class HSCode(models.Model):
description = fields.Char(
translate=True,
help="Short text description of the H.S. category")
display_name = fields.Char(
compute='_compute_display_name_field',
store=True, readonly=True)
local_code = fields.Char(
required=True,
help="Code used for the national Import/Export declaration. "
@@ -32,8 +29,7 @@ class HSCode(models.Model):
active = fields.Boolean(default=True)
company_id = fields.Many2one(
'res.company', string='Company', readonly=True, required=True,
default=lambda self: self.env['res.company']._company_default_get(
'hs.code'))
default=lambda self: self.env['res.company']._company_default_get())
product_categ_ids = fields.One2many(
comodel_name='product.category',
inverse_name='hs_code_id',
@@ -44,23 +40,39 @@ class HSCode(models.Model):
inverse_name='hs_code_id',
string='Products',
readonly=True)
product_categ_count = fields.Integer(
compute='_compute_product_categ_count')
product_tmpl_count = fields.Integer(compute='_compute_product_tmpl_count')
@api.multi
@api.depends('local_code')
def _compute_hs_code(self):
for this in self:
this.hs_code = this.local_code and this.local_code[:6]
@api.multi
@api.depends('product_categ_ids')
def _compute_product_categ_count(self):
# hs_code_id on product.category is company_dependent=True
# so we can't use a read_group()
for code in self:
code.product_categ_count = len(code.product_categ_ids)
@api.depends('product_tmpl_ids')
def _compute_product_tmpl_count(self):
# hs_code_id on product.template is company_dependent=True
# so we can't use a read_group()
for code in self:
code.product_tmpl_count = len(code.product_tmpl_ids)
@api.depends('local_code', 'description')
def _compute_display_name_field(self):
def name_get(self):
res = []
for this in self:
display_name = this.local_code
name = this.local_code
if this.description:
display_name += ' ' + this.description
this.display_name = len(display_name) > 55 \
and display_name[:55] + '...' \
or display_name
name += ' ' + this.description
name = len(name) > 55 and name[:55] + '...' or name
res.append((this.id, name))
return res
_sql_constraints = [
('local_code_company_uniq', 'unique(local_code, company_id)',
@@ -73,7 +85,6 @@ class HSCode(models.Model):
vals['local_code'] = vals['local_code'].replace(' ', '')
return super(HSCode, self).create(vals)
@api.multi
def write(self, vals):
if vals.get('local_code'):
vals['local_code'] = vals['local_code'].replace(' ', '')

View File

@@ -1,10 +1,10 @@
# Copyright 2011-2016 Akretion (http://www.akretion.com)
# Copyright 2011-2016 Akretion France (http://www.akretion.com)
# Copyright 2009-2016 Noviat (http://www.noviat.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# @author Luc de Meyer <info@noviat.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models
from odoo import fields, models
class ProductCategory(models.Model):
@@ -17,7 +17,6 @@ class ProductCategory(models.Model):
"set on the product itself, it will be read here, on the "
"related product category.")
@api.multi
def get_hs_code_recursively(self):
self.ensure_one()
if self.hs_code_id:

View File

@@ -4,7 +4,7 @@
# @author Luc de Meyer <info@noviat.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models
from odoo import fields, models
class ProductTemplate(models.Model):
@@ -26,15 +26,12 @@ class ProductTemplate(models.Model):
class ProductProduct(models.Model):
_inherit = 'product.product'
@api.multi
def get_hs_code_recursively(self):
res = self.env['hs.code']
if not self:
return res
else:
if self:
self.ensure_one()
if self.hs_code_id:
res = self.hs_code_id
elif self.categ_id:
res = self.categ_id.get_hs_code_recursively()
return res
return res

View File

@@ -0,0 +1,3 @@
* Alexis de Lattre, Akretion <alexis.delattre@akretion.com>
* Luc De Meyer, Noviat <info@noviat.com>
* Kumar Aberer, brain-tec AG <kumar.aberer@braintec-group.com>

View File

@@ -0,0 +1,69 @@
.. 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
============================================
Harmonized System Codes (and National Codes)
============================================
This module contains the objects for Harmonised System Codes (H.S. codes). The full nomenclature is available from the `World Customs Organisation <http://www.wcoomd.org/>`. These code are usually required on the Proforma invoices that are attached to the packages that are shipped abroad.
This module also handle the local/national extensions to the H.S. codes. The import of the full nomenclature is not provided by this module ; it should be provided by localization modules.
You will also be able to configure the country of origin of a product, which is often required on the proforma invoice for the customs.
This module should be usefull for all companies that export physical goods abroad. This module is also used by the Intrastat modules for the European Union, cf the *intrastat_product* module.
Installation
============
This module is NOT compatible with the *report_intrastat* module from the official addons.
Usage
=====
To create H.S. codes, go to the menu *Sales > Configuration > Product Categories and Attributes > H.S. Codes*.
Then you will be able to set the H.S. code on an product (under the *Information* tab) or on a product category. On the product form, you will also be able to set the *Country of Origin* of a product (for example, if the product is *made in China*, select *China* as *Country of Origin*).
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot
:target: https://runbot.odoo-community.org/runbot/227/11.0
Bug Tracker
===========
Bugs are tracked on `GitHub Issues
<https://github.com/OCA/intrastat/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.
Credits
=======
Contributors
------------
* Alexis de Lattre, Akretion <alexis.delattre@akretion.com>
* Luc De Meyer, Noviat <info@noviat.com>
* Kumar Aberer, brain-tec AG <kumar.aberer@braintec-group.com>
Maintainer
----------
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
This module is maintained by the OCA.
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.
To contribute to this module, please visit https://odoo-community.org.

View File

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

View File

@@ -0,0 +1,3 @@
As this module only depends on the *product* module and that module doesn't provide any menu entry, this module lacks a menu entry for H.S. Codes. A menu entry for H.S. codes is provided by the module *product_harmonized_system_stock*.
Once the H.S. codes are created, you will be able to set the H.S. code on an product (under the *Information* tab) or on a product category. On the product form, you will also be able to set the *Country of Origin* of a product (for example, if the product is *made in China*, select *China* as *Country of Origin*).

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 2010-2016 Akretion (http://www.akretion.com/)
Copyright 2010-2019 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).
-->
@@ -14,7 +14,8 @@
<field name="arch" type="xml">
<search string="Search H.S. Codes">
<field name="local_code"
filter_domain="['|', ('local_code', 'like', self), ('description', 'ilike', self)]"/>
filter_domain="['|', ('local_code', 'like', self), ('description', 'ilike', self)]"/>
<filter string="Archived" name="inactive" domain="[('active', '=', False)]"/>
</search>
</field>
</record>
@@ -33,24 +34,57 @@
</field>
</record>
<!-- Action used in the form view for HS codes -->
<record id="product_categ_hs_code_action" model="ir.actions.act_window">
<field name="name">Product Categories</field>
<field name="res_model">product.category</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('hs_code_id', '=', active_id)]</field>
</record>
<record id="product_template_hs_code_action" model="ir.actions.act_window">
<field name="name">Products</field>
<field name="res_model">product.template</field>
<field name="view_mode">kanban,tree,form</field>
<field name="domain">[('hs_code_id', '=', active_id)]</field>
</record>
<!-- Form view for H.S. code -->
<record id="hs_code_view_form" model="ir.ui.view">
<field name="name">hs.code.form</field>
<field name="model">hs.code</field>
<field name="arch" type="xml">
<form string="H.S. Code">
<div class="oe_button_box" name="button_box">
<button class="oe_stat_button"
name="%(product_categ_hs_code_action)d"
icon="fa-th-list"
type="action">
<div class="o_field_widget o_stat_info">
<span class="o_stat_value"><field name="product_categ_count"/></span>
<span class="o_stat_text"> Product Categs</span>
</div>
</button>
<button class="oe_stat_button"
name="%(product_template_hs_code_action)d"
icon="fa-th-list"
type="action">
<div class="o_field_widget o_stat_info">
<span class="o_stat_value"><field name="product_tmpl_count"/></span>
<span class="o_stat_text"> Products</span>
</div>
</button>
<button name="toggle_active" type="object"
class="oe_stat_button" icon="fa-archive">
<field name="active" widget="boolean_button"
options='{"terminology": "archive"}'/>
</button>
</div>
<group name="main">
<field name="local_code" />
<field name="hs_code"/>
<field name="description"/>
<field name="company_id" groups="base.group_multi_company"/>
<field name="active"/>
</group>
<group name="product-categ" string="Product Categories">
<field name="product_categ_ids" nolabel="1"/>
</group>
<group name="product-tmpl" string="Products">
<field name="product_tmpl_ids" nolabel="1"/>
</group>
</form>
</field>
@@ -63,10 +97,7 @@
<field name="view_mode">tree,form</field>
</record>
<!-- Menu entry for H.S. code -->
<!-- TODO: find a way to put a menu entry without depending on another module ?
<menuitem id="hs_code_menu" action="hs_code_action"
parent="product.prod_config_main" sequence="60"/>
-->
<!-- The menu entry for H.S. code is now provided by the module
product_harmonized_system_stock -->
</odoo>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 2010-2016 Akretion (http://www.akretion.com/)
Copyright 2010-2019 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).
-->

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 2010-2016 Akretion (http://www.akretion.com/)
Copyright 2010-2019 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).
-->

View File

@@ -4,13 +4,14 @@
{
'name': 'Product Harmonized System Codes - Delivery',
'version': '11.0.1.0.0',
'version': '12.0.1.0.0',
'category': 'Reporting',
'license': 'AGPL-3',
'summary': 'Hide native hs_code field provided by the delivery module',
'summary': 'Hide native hs_code field provided by the delivery_hs_code '
'module',
'author': 'Akretion, Odoo Community Association (OCA)',
'depends': ['delivery', 'product_harmonized_system'],
'depends': ['delivery_hs_code', 'product_harmonized_system'],
'data': ['views/product_template.xml'],
'installable': False,
'installable': True,
'auto_install': True,
}

View File

@@ -1 +1 @@
The OCA module *product_harmonized_system* adds a many2one field *hs_code_id* on product templates that points to an *H.S. Code* object. But the *delivery* module from the official addons adds a char field *hs_code* on product templates, which has the same purpose, but we can't use it because we need structured data for H.S. codes. This module hides the *hs_code* field added by the *delivery* module, to avoid confusion.
The OCA module *product_harmonized_system* adds a many2one field *hs_code_id* on product templates that points to an *H.S. Code* object. But the *delivery_hs_code* module from the official addons (an auto-install module that depends on *delivery*) adds a char field *hs_code* on product templates, which has the same purpose, but we can't use it because we need structured data for H.S. codes. This module hides the *hs_code* field added by the *delivery_hs_code* module, to avoid confusion.

View File

@@ -11,7 +11,7 @@
<record id="product_template_hs_code" model="ir.ui.view">
<field name="name">hide_native_hs_code_field.product.template.form</field>
<field name="model">product.template</field>
<field name="inherit_id" ref="delivery.product_template_hs_code" />
<field name="inherit_id" ref="delivery_hs_code.product_template_hs_code" />
<field name="arch" type="xml">
<field name="hs_code" position="attributes">
<attribute name="invisible">1</attribute>

View File

@@ -0,0 +1,18 @@
# Copyright 2019 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).
{
'name': 'Product Harmonized System (menu entry)',
'version': '12.0.1.0.0',
'category': 'Reporting',
'license': 'AGPL-3',
'summary': 'Adds a menu entry for H.S. codes',
'author': 'Akretion, Odoo Community Association (OCA)',
'depends': ['product_harmonized_system', 'stock'],
'data': [
'views/hs_code_menu.xml',
],
'installable': True,
'auto_install': True,
}

View File

@@ -0,0 +1 @@
* Alexis de Lattre <alexis.delattre@akretion.com>

View File

@@ -0,0 +1 @@
This module adds a menu entry for H.S. Codes. This menu entry is available under *Inventory > Configuration > Products*.

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2019 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>
<!-- Menu entry for H.S. code -->
<menuitem id="hs_code_menu" action="product_harmonized_system.hs_code_action"
parent="stock.menu_product_in_config_stock" sequence="60"/>
</odoo>