[FIX] l10n_be_intrastat: adapt to new regulation for belgian intrastat
This is essentially a backport of module l10n_be_intrastat_2019 made for Enterprise v12 + the refactoring needed on the original v10 module to allow the changes to apply where needed. Was requested by opw-1887019 closes odoo/odoo#30400
This commit is contained in:
committed by
Nicolas Martinelli
parent
a909bb3391
commit
c5a8e39758
@@ -102,35 +102,140 @@ class XmlDeclaration(models.TransientModel):
|
||||
'res_id': self.id,
|
||||
}
|
||||
|
||||
def _build_intrastat_line(self, numlgn, item, linekey, amounts, dispatchmode, extendedmode):
|
||||
self._set_Dim(item, 'EXSEQCODE', unicode(numlgn))
|
||||
self._set_Dim(item, 'EXTRF', unicode(linekey.EXTRF))
|
||||
self._set_Dim(item, 'EXCNT', unicode(linekey.EXCNT))
|
||||
self._set_Dim(item, 'EXTTA', unicode(linekey.EXTTA))
|
||||
self._set_Dim(item, 'EXREG', unicode(linekey.EXREG))
|
||||
self._set_Dim(item, 'EXTGO', unicode(linekey.EXGO))
|
||||
if extendedmode:
|
||||
self._set_Dim(item, 'EXTPC', unicode(linekey.EXTPC))
|
||||
self._set_Dim(item, 'EXDELTRM', unicode(linekey.EXDELTRM))
|
||||
self._set_Dim(item, 'EXTXVAL', unicode(round(amounts[0], 0)).replace(".", ","))
|
||||
self._set_Dim(item, 'EXWEIGHT', unicode(round(amounts[1], 0)).replace(".", ","))
|
||||
self._set_Dim(item, 'EXUNITS', unicode(round(amounts[2], 0)).replace(".", ","))
|
||||
|
||||
def _get_intrastat_linekey(self, declcode, inv_line, dispatchmode, extendedmode):
|
||||
IntrastatRegion = self.env['l10n_be_intrastat.region']
|
||||
company = self.company_id
|
||||
|
||||
#Check type of transaction
|
||||
if inv_line.intrastat_transaction_id:
|
||||
extta = inv_line.intrastat_transaction_id.code
|
||||
else:
|
||||
extta = "1"
|
||||
#Check country
|
||||
if inv_line.invoice_id.intrastat_country_id:
|
||||
excnt = inv_line.invoice_id.intrastat_country_id.code
|
||||
else:
|
||||
excnt = inv_line.invoice_id.partner_shipping_id.country_id.code or inv_line.invoice_id.partner_id.country_id.code
|
||||
|
||||
#Check region
|
||||
#If purchase, comes from purchase order, linked to a location,
|
||||
#which is linked to the warehouse
|
||||
#if sales, the sale order is linked to the warehouse
|
||||
#if sales, from a delivery order, linked to a location,
|
||||
#which is linked to the warehouse
|
||||
#If none found, get the company one.
|
||||
exreg = None
|
||||
if inv_line.invoice_id.type in ('in_invoice', 'in_refund'):
|
||||
#comes from purchase
|
||||
po_lines = self.env['purchase.order.line'].search([('invoice_lines', 'in', inv_line.id)], limit=1)
|
||||
if po_lines:
|
||||
if self._is_situation_triangular(company, po_line=po_lines):
|
||||
return
|
||||
location = self.env['stock.location'].browse(po_lines.order_id._get_destination_location())
|
||||
region_id = self.env['stock.warehouse'].get_regionid_from_locationid(location)
|
||||
if region_id:
|
||||
exreg = IntrastatRegion.browse(region_id).code
|
||||
elif inv_line.invoice_id.type in ('out_invoice', 'out_refund'):
|
||||
#comes from sales
|
||||
so_lines = self.env['sale.order.line'].search([('invoice_lines', 'in', inv_line.id)], limit=1)
|
||||
if so_lines:
|
||||
if self._is_situation_triangular(company, so_line=so_lines):
|
||||
return
|
||||
saleorder = so_lines.order_id
|
||||
if saleorder and saleorder.warehouse_id and saleorder.warehouse_id.region_id:
|
||||
exreg = IntrastatRegion.browse(saleorder.warehouse_id.region_id.id).code
|
||||
|
||||
if not exreg:
|
||||
if company.region_id:
|
||||
exreg = company.region_id.code
|
||||
else:
|
||||
self._company_warning(_('The Intrastat Region of the selected company is not set, '
|
||||
'please make sure to configure it first.'))
|
||||
|
||||
#Check commodity codes
|
||||
intrastat_id = inv_line.product_id.get_intrastat_recursively()
|
||||
if intrastat_id:
|
||||
exgo = self.env['report.intrastat.code'].browse(intrastat_id).name
|
||||
else:
|
||||
raise exceptions.Warning(
|
||||
_('Product "%s" has no intrastat code, please configure it') % inv_line.product_id.display_name)
|
||||
|
||||
#In extended mode, 2 more fields required
|
||||
if extendedmode:
|
||||
#Check means of transport
|
||||
if inv_line.invoice_id.transport_mode_id:
|
||||
extpc = inv_line.invoice_id.transport_mode_id.code
|
||||
elif company.transport_mode_id:
|
||||
extpc = company.transport_mode_id.code
|
||||
else:
|
||||
self._company_warning(_('The default Intrastat transport mode of your company '
|
||||
'is not set, please make sure to configure it first.'))
|
||||
|
||||
#Check incoterm
|
||||
if inv_line.invoice_id.incoterm_id:
|
||||
exdeltrm = inv_line.invoice_id.incoterm_id.code
|
||||
elif company.incoterm_id:
|
||||
exdeltrm = company.incoterm_id.code
|
||||
else:
|
||||
self._company_warning(_('The default Incoterm of your company is not set, '
|
||||
'please make sure to configure it first.'))
|
||||
else:
|
||||
extpc = ""
|
||||
exdeltrm = ""
|
||||
intrastatkey = namedtuple("intrastatkey",
|
||||
['EXTRF', 'EXCNT', 'EXTTA', 'EXREG',
|
||||
'EXGO', 'EXTPC', 'EXDELTRM'])
|
||||
return intrastatkey(EXTRF=declcode, EXCNT=excnt,
|
||||
EXTTA=extta, EXREG=exreg, EXGO=exgo,
|
||||
EXTPC=extpc, EXDELTRM=exdeltrm)
|
||||
|
||||
def _get_reception_code(self, extended):
|
||||
return 'EX19E' if extended else 'EX19S'
|
||||
|
||||
def _get_reception_form(self, extended):
|
||||
return 'EXF19E' if extended else 'EXF19S'
|
||||
|
||||
def _get_expedition_code(self, extended):
|
||||
return 'EX29E' if extended else 'EX29S'
|
||||
|
||||
def _get_expedition_form(self, extended):
|
||||
return 'EXF29E' if extended else 'EXF29S'
|
||||
|
||||
@api.multi
|
||||
def _get_lines(self, dispatchmode=False, extendedmode=False):
|
||||
company = self.company_id
|
||||
IntrastatRegion = self.env['l10n_be_intrastat.region']
|
||||
|
||||
if dispatchmode:
|
||||
mode1 = 'out_invoice'
|
||||
mode2 = 'in_refund'
|
||||
declcode = "29"
|
||||
declcode = self._get_expedition_code(extendedmode)
|
||||
declform = self._get_expedition_form(extendedmode)
|
||||
else:
|
||||
mode1 = 'in_invoice'
|
||||
mode2 = 'out_refund'
|
||||
declcode = "19"
|
||||
declcode = self._get_reception_code(extendedmode)
|
||||
declform = self._get_reception_form(extendedmode)
|
||||
|
||||
decl = ET.Element('Report')
|
||||
if not extendedmode:
|
||||
decl.set('code', 'EX%sS' % declcode)
|
||||
else:
|
||||
decl.set('code', 'EX%sE' % declcode)
|
||||
decl.set('code', declcode)
|
||||
decl.set('date', '%s-%s' % (self.year, self.month))
|
||||
datas = ET.SubElement(decl, 'Data')
|
||||
if not extendedmode:
|
||||
datas.set('form', 'EXF%sS' % declcode)
|
||||
else:
|
||||
datas.set('form', 'EXF%sE' % declcode)
|
||||
datas.set('form', declform)
|
||||
datas.set('close', 'true')
|
||||
intrastatkey = namedtuple("intrastatkey",
|
||||
['EXTRF', 'EXCNT', 'EXTTA', 'EXREG',
|
||||
'EXGO', 'EXTPC', 'EXDELTRM'])
|
||||
entries = {}
|
||||
|
||||
query = """
|
||||
@@ -166,86 +271,10 @@ class XmlDeclaration(models.TransientModel):
|
||||
invoicelines = self.env['account.invoice.line'].browse(invoicelines_ids)
|
||||
|
||||
for inv_line in invoicelines:
|
||||
linekey = self._get_intrastat_linekey(declcode, inv_line, dispatchmode, extendedmode)
|
||||
if linekey is None:
|
||||
continue
|
||||
|
||||
#Check type of transaction
|
||||
if inv_line.intrastat_transaction_id:
|
||||
extta = inv_line.intrastat_transaction_id.code
|
||||
else:
|
||||
extta = "1"
|
||||
#Check country
|
||||
if inv_line.invoice_id.intrastat_country_id:
|
||||
excnt = inv_line.invoice_id.intrastat_country_id.code
|
||||
else:
|
||||
excnt = inv_line.invoice_id.partner_shipping_id.country_id.code or inv_line.invoice_id.partner_id.country_id.code
|
||||
|
||||
#Check region
|
||||
#If purchase, comes from purchase order, linked to a location,
|
||||
#which is linked to the warehouse
|
||||
#if sales, the sale order is linked to the warehouse
|
||||
#if sales, from a delivery order, linked to a location,
|
||||
#which is linked to the warehouse
|
||||
#If none found, get the company one.
|
||||
exreg = None
|
||||
if inv_line.invoice_id.type in ('in_invoice', 'in_refund'):
|
||||
#comes from purchase
|
||||
po_lines = self.env['purchase.order.line'].search([('invoice_lines', 'in', inv_line.id)], limit=1)
|
||||
if po_lines:
|
||||
if self._is_situation_triangular(company, po_line=po_lines):
|
||||
continue
|
||||
location = self.env['stock.location'].browse(po_lines.order_id._get_destination_location())
|
||||
region_id = self.env['stock.warehouse'].get_regionid_from_locationid(location)
|
||||
if region_id:
|
||||
exreg = IntrastatRegion.browse(region_id).code
|
||||
elif inv_line.invoice_id.type in ('out_invoice', 'out_refund'):
|
||||
#comes from sales
|
||||
so_lines = self.env['sale.order.line'].search([('invoice_lines', 'in', inv_line.id)], limit=1)
|
||||
if so_lines:
|
||||
if self._is_situation_triangular(company, so_line=so_lines):
|
||||
continue
|
||||
saleorder = so_lines.order_id
|
||||
if saleorder and saleorder.warehouse_id and saleorder.warehouse_id.region_id:
|
||||
exreg = IntrastatRegion.browse(saleorder.warehouse_id.region_id.id).code
|
||||
|
||||
if not exreg:
|
||||
if company.region_id:
|
||||
exreg = company.region_id.code
|
||||
else:
|
||||
self._company_warning(_('The Intrastat Region of the selected company is not set, '
|
||||
'please make sure to configure it first.'))
|
||||
|
||||
#Check commodity codes
|
||||
intrastat_id = inv_line.product_id.get_intrastat_recursively()
|
||||
if intrastat_id:
|
||||
exgo = self.env['report.intrastat.code'].browse(intrastat_id).name
|
||||
else:
|
||||
raise exceptions.Warning(
|
||||
_('Product "%s" has no intrastat code, please configure it') % inv_line.product_id.display_name)
|
||||
|
||||
#In extended mode, 2 more fields required
|
||||
if extendedmode:
|
||||
#Check means of transport
|
||||
if inv_line.invoice_id.transport_mode_id:
|
||||
extpc = inv_line.invoice_id.transport_mode_id.code
|
||||
elif company.transport_mode_id:
|
||||
extpc = company.transport_mode_id.code
|
||||
else:
|
||||
self._company_warning(_('The default Intrastat transport mode of your company '
|
||||
'is not set, please make sure to configure it first.'))
|
||||
|
||||
#Check incoterm
|
||||
if inv_line.invoice_id.incoterm_id:
|
||||
exdeltrm = inv_line.invoice_id.incoterm_id.code
|
||||
elif company.incoterm_id:
|
||||
exdeltrm = company.incoterm_id.code
|
||||
else:
|
||||
self._company_warning(_('The default Incoterm of your company is not set, '
|
||||
'please make sure to configure it first.'))
|
||||
else:
|
||||
extpc = ""
|
||||
exdeltrm = ""
|
||||
linekey = intrastatkey(EXTRF=declcode, EXCNT=excnt,
|
||||
EXTTA=extta, EXREG=exreg, EXGO=exgo,
|
||||
EXTPC=extpc, EXDELTRM=exdeltrm)
|
||||
#We have the key
|
||||
#calculate amounts
|
||||
if inv_line.price_unit and inv_line.quantity:
|
||||
@@ -269,18 +298,7 @@ class XmlDeclaration(models.TransientModel):
|
||||
continue
|
||||
numlgn += 1
|
||||
item = ET.SubElement(datas, 'Item')
|
||||
self._set_Dim(item, 'EXSEQCODE', unicode(numlgn))
|
||||
self._set_Dim(item, 'EXTRF', unicode(linekey.EXTRF))
|
||||
self._set_Dim(item, 'EXCNT', unicode(linekey.EXCNT))
|
||||
self._set_Dim(item, 'EXTTA', unicode(linekey.EXTTA))
|
||||
self._set_Dim(item, 'EXREG', unicode(linekey.EXREG))
|
||||
self._set_Dim(item, 'EXTGO', unicode(linekey.EXGO))
|
||||
if extendedmode:
|
||||
self._set_Dim(item, 'EXTPC', unicode(linekey.EXTPC))
|
||||
self._set_Dim(item, 'EXDELTRM', unicode(linekey.EXDELTRM))
|
||||
self._set_Dim(item, 'EXTXVAL', unicode(round(amounts[0], 0)).replace(".", ","))
|
||||
self._set_Dim(item, 'EXWEIGHT', unicode(round(amounts[1], 0)).replace(".", ","))
|
||||
self._set_Dim(item, 'EXUNITS', unicode(round(amounts[2], 0)).replace(".", ","))
|
||||
self._build_intrastat_line(numlgn, item, linekey, amounts, dispatchmode, extendedmode)
|
||||
|
||||
if numlgn == 0:
|
||||
#no datas
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import models
|
||||
@@ -0,0 +1,15 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
{
|
||||
'name': 'Belgian Intrastat Declaration - Complement for 2019',
|
||||
'category': 'Accounting',
|
||||
'description': """
|
||||
Adds the possibility to specify the origin country of goods and the partner VAT in the Intrastat XML report.
|
||||
""",
|
||||
'depends': ['l10n_be_intrastat'],
|
||||
'data': [
|
||||
'views/account_invoice_line_view.xml',
|
||||
],
|
||||
'auto_install': True,
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * l10n_be_intrastat_2019
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 10.0+e\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-01-21 11:04+0000\n"
|
||||
"PO-Revision-Date: 2019-01-21 11:04+0000\n"
|
||||
"Last-Translator: <>\n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Plural-Forms: \n"
|
||||
|
||||
#. module: l10n_be_intrastat_2019
|
||||
#: model:ir.model,name:l10n_be_intrastat_2019.model_l10n_be_intrastat_xml_xml_decl
|
||||
msgid "Intrastat XML Declaration"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_be_intrastat_2019
|
||||
#: model:ir.model,name:l10n_be_intrastat_2019.model_account_invoice_line
|
||||
msgid "Invoice Line"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_be_intrastat_2019
|
||||
#: model:ir.model.fields,field_description:l10n_be_intrastat_2019.field_account_invoice_line_intrastat_product_origin_country_id
|
||||
msgid "Origin Country of Product"
|
||||
msgstr ""
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import account_intrastat_report
|
||||
from . import account_invoice_line
|
||||
@@ -0,0 +1,33 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import models
|
||||
from collections import namedtuple
|
||||
|
||||
|
||||
class XmlDeclaration(models.TransientModel):
|
||||
"""
|
||||
Intrastat XML Declaration
|
||||
"""
|
||||
_inherit = "l10n_be_intrastat_xml.xml_decl"
|
||||
|
||||
def _build_intrastat_line(self, numlgn, item, linekey, amounts, dispatchmode, extendedmode):
|
||||
super(XmlDeclaration, self)._build_intrastat_line(numlgn, item, linekey, amounts, dispatchmode, extendedmode)
|
||||
if dispatchmode:
|
||||
self._set_Dim(item, 'EXCNTORI', unicode(linekey.EXCNTORI))
|
||||
self._set_Dim(item, 'PARTNERID', unicode(linekey.PARTNERID))
|
||||
|
||||
def _get_intrastat_linekey(self, declcode, inv_line, dispatchmode, extendedmode):
|
||||
res = super(XmlDeclaration, self)._get_intrastat_linekey(declcode, inv_line, dispatchmode, extendedmode)
|
||||
if res and dispatchmode:
|
||||
res_dict = res._asdict()
|
||||
res_dict['EXCNTORI'] = inv_line.intrastat_product_origin_country_id.code or 'QU'
|
||||
res_dict['PARTNERID'] = inv_line.invoice_id.partner_id.vat or 'QV999999999999'
|
||||
return namedtuple('intrastatkey', res_dict.keys())(**res_dict)
|
||||
return res
|
||||
|
||||
def _get_expedition_code(self, extended):
|
||||
return 'INTRASTAT_X_E' if extended else 'INTRASTAT_X_S'
|
||||
|
||||
def _get_expedition_form(self, extended):
|
||||
return 'INTRASTAT_X_EF' if extended else 'INTRASTAT_X_SF'
|
||||
@@ -0,0 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
class AccountInvoiceLine(models.Model):
|
||||
_inherit = 'account.invoice.line'
|
||||
|
||||
intrastat_product_origin_country_id = fields.Many2one('res.country', string='Origin Country of Product')
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="invoice_line_be_intrastat_data_form" model="ir.ui.view">
|
||||
<field name="name">account.invoice.form.inherit.account.be.intrastat</field>
|
||||
<field name="model">account.invoice</field>
|
||||
<field name="inherit_id" ref="account.invoice_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='invoice_line_ids']//field[@name='quantity']" position="before">
|
||||
<field name="intrastat_product_origin_country_id" options="{'no_create_edit': True}"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user