From b16731c3792e5f474d9d34c6aa46791894b2d901 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Tue, 5 Apr 2011 00:57:21 +0200 Subject: [PATCH 001/103] Complete change of design for intrastat_type ! Now that report_intrastat_product/service object is stored in database, we don't need the legal_intrastat state on invoices any more, because we will be able to create entry lines for DEB for a repair of equipment under warranty without using a legal_intrastat. Report_intrastat_type is now only required for DEB -> object moved to module l10n_fr_intrastat_product. For DEB, the button "regenerate lines" only regenerate DEB lines related to invoices. Renamed intrastat base module, because it doesn't have France-specific parameters any more. Add demo data. --- intrastat_base/__init__.py | 27 +++++ intrastat_base/__terp__.py | 53 ++++++++++ intrastat_base/country.py | 33 ++++++ intrastat_base/country_data.xml | 84 +++++++++++++++ intrastat_base/country_view.xml | 36 +++++++ intrastat_base/intrastat_common.py | 111 ++++++++++++++++++++ intrastat_base/intrastat_menu.xml | 16 +++ intrastat_base/partner_address.py | 36 +++++++ intrastat_base/product.py | 36 +++++++ intrastat_base/product_demo.xml | 22 ++++ intrastat_base/product_view.xml | 47 +++++++++ intrastat_base/security/ir.model.access.csv | 2 + 12 files changed, 503 insertions(+) create mode 100644 intrastat_base/__init__.py create mode 100644 intrastat_base/__terp__.py create mode 100644 intrastat_base/country.py create mode 100644 intrastat_base/country_data.xml create mode 100644 intrastat_base/country_view.xml create mode 100644 intrastat_base/intrastat_common.py create mode 100644 intrastat_base/intrastat_menu.xml create mode 100644 intrastat_base/partner_address.py create mode 100644 intrastat_base/product.py create mode 100644 intrastat_base/product_demo.xml create mode 100644 intrastat_base/product_view.xml create mode 100644 intrastat_base/security/ir.model.access.csv diff --git a/intrastat_base/__init__.py b/intrastat_base/__init__.py new file mode 100644 index 0000000..c593568 --- /dev/null +++ b/intrastat_base/__init__.py @@ -0,0 +1,27 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Report intrastat base module for OpenERP +# Copyright (C) 2011 Akretion (http://www.akretion.com). All Rights Reserved +# @author Alexis de Lattre +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +import country +import product +import partner_address +import intrastat_common + diff --git a/intrastat_base/__terp__.py b/intrastat_base/__terp__.py new file mode 100644 index 0000000..6ad92af --- /dev/null +++ b/intrastat_base/__terp__.py @@ -0,0 +1,53 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Report intrastat base module for OpenERP +# Copyright (C) 2011 Akretion (http://www.akretion.com). All Rights Reserved +# @author Alexis de Lattre +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + + +{ + 'name': 'Base module for Intrastat reporting', + 'version': '1.1', + 'category': 'Localisation/Report Intrastat', + 'license': 'AGPL-3', + 'description': """This module contains the common functions for 2 other modules : +- l10n_fr_intrastat_service : the module for the "Déclaration Européenne des Services" (DES) +- l10n_fr_intrastat_product : the module for the "Déclaration d'Echange de Biens" (DEB) +This module is not usefull if it's not used together with one of those 2 modules. + +This module doesn't have any France-specific stuff. So it can be used as a basis for other intrastat modules for other EU countries. + +WARNING : this module conflicts with the module "report_intrastat" from the addons. If you have already installed the module "report_intrastat", you should uninstall it first before installing this module. + +Please contact Alexis de Lattre from Akretion for any help or question about this module. + """, + 'author': 'Akretion', + 'website': 'http://www.akretion.com', + 'depends': ['account'], + 'init_xml': ['country_data.xml'], + 'update_xml': [ + 'security/ir.model.access.csv', + 'product_view.xml', + 'country_view.xml', + 'intrastat_menu.xml', + ], + 'demo_xml': ['product_demo.xml'], + 'installable': True, + 'active': False, +} diff --git a/intrastat_base/country.py b/intrastat_base/country.py new file mode 100644 index 0000000..fbd284c --- /dev/null +++ b/intrastat_base/country.py @@ -0,0 +1,33 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2009 Tiny SPRL (http://tiny.be). All Rights Reserved +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from osv import osv, fields + +class res_country(osv.osv): + _inherit = 'res.country' + _columns = { + 'intrastat': fields.boolean('Intrastat member'), + } + _defaults = { + 'intrastat': lambda *a: False, + } + +res_country() diff --git a/intrastat_base/country_data.xml b/intrastat_base/country_data.xml new file mode 100644 index 0000000..228c0b4 --- /dev/null +++ b/intrastat_base/country_data.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intrastat_base/country_view.xml b/intrastat_base/country_view.xml new file mode 100644 index 0000000..faa85d9 --- /dev/null +++ b/intrastat_base/country_view.xml @@ -0,0 +1,36 @@ + + + + + + + + + + intrastat.base.country.tree + res.country + + + + + + + + + + intrastat.base.country.form + res.country + + + + + + + + + + + diff --git a/intrastat_base/intrastat_common.py b/intrastat_base/intrastat_common.py new file mode 100644 index 0000000..d7e6ec8 --- /dev/null +++ b/intrastat_base/intrastat_common.py @@ -0,0 +1,111 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Report intrastat base module for OpenERP +# Copyright (C) 2010-2011 Akretion (http://www.akretion.com/). All rights reserved. +# @author Alexis de Lattre +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from osv import osv, fields +from datetime import datetime, timedelta +from dateutil.relativedelta import relativedelta +from tools.translate import _ + +class report_intrastat_common(osv.osv_memory): + _name = "report.intrastat.common" + _description = "Common functions for intrastat reports for products and services" + + def _compute_numbers(self, cr, uid, ids, object, context=None): + result = {} + for intrastat in object.browse(cr, uid, ids, context=context): + total_amount = 0.0 + num_lines = 0 + for line in intrastat.intrastat_line_ids: + total_amount += line.amount_company_currency + num_lines += 1 + result[intrastat.id] = {'num_lines': num_lines, 'total_amount': total_amount} + return result + + + def _compute_end_date(self, cr, uid, ids, object, context=None): + result = {} + for intrastat in object.browse(cr, uid, ids, context=context): + start_date_datetime = datetime.strptime(intrastat.start_date, '%Y-%m-%d') + end_date_str = datetime.strftime(start_date_datetime + relativedelta(day=31), '%Y-%m-%d') + result[intrastat.id] = end_date_str + return result + + + def _check_start_date(self, cr, uid, ids, object, context=None): + '''Check that the start date if the first day of the month''' + for date_to_check in object.read(cr, uid, ids, ['start_date'], context=context): + datetime_to_check = datetime.strptime(date_to_check['start_date'], '%Y-%m-%d') + if datetime_to_check.day != 1: + return False + return True + + + def _check_generate_lines(self, cr, uid, ids, intrastat, context=None): + if len(ids) != 1: + raise osv.except_osv(_('Error :'), 'Hara kiri in generate_lines') + if not intrastat.company_id.currency_id.code: + raise osv.except_osv(_('Error :'), _('The currency code is not set on the currency "%s".'%intrastat.company_id.currency_id.name)) + if not intrastat.currency_id.code == 'EUR': + raise osv.except_osv(_('Error :'), _('The company currency must be "EUR", but is currently "%s".'%intrastat.currency_id.code)) + return None + + + def _check_generate_xml(self, cr, uid, ids, intrastat, context=None): + if len(ids) != 1: + raise osv.except_osv(_('Error :'), 'Hara kiri in generate_xml') + if not intrastat.company_id.partner_id.vat: + raise osv.except_osv(_('Error :'), _('The VAT number is not set for the partner "%s".'%intrastat.company_id.partner_id.name)) + if not intrastat.company_id.partner_id.vat[0:2] == 'FR': + raise osv.except_osv(_('Error :'), _("The company '%s' should have a VAT number starting with 'FR' on it's related partner. Its current VAT number is '%s'."%(intrastat.company_id.name, intrastat.company_id.partner_id.vat))) + return None + + + def _check_xml_schema(self, cr, uid, xml_root, xml_string, xsd, context=None): + from lxml import etree + official_des_xml_schema = etree.XMLSchema(etree.fromstring(xsd)) + try: official_des_xml_schema.assertValid(xml_root) + except Exception, e: # if the validation of the XSD fails, we arrive here + import netsvc + logger = netsvc.Logger() + logger.notifyChannel('intrastat', netsvc.LOG_WARNING, "The XML file is invalid against the XSD") + logger.notifyChannel('intrastat', netsvc.LOG_WARNING, xml_string) + logger.notifyChannel('intrastat', netsvc.LOG_WARNING, e) + raise osv.except_osv(_('Error :'), _('The generated XML file is not valid against the official XML schema. The generated XML file and the full error have been written in the server logs. Here is the exact error, which may give you an idea of the cause of the problem : ' + str(e))) + return None + + def _attach_xml_file(self, cr, uid, ids, object, xml_string, start_date_datetime, declaration_name, context=None): + '''Attach the XML file to the intrastat_xxx object''' + import base64 + if len(ids) != 1: + raise osv.except_osv(_('Error :'), 'Hara kiri in attach_xml_file') + filename = datetime.strftime(start_date_datetime, '%Y-%m') + '_' + declaration_name + '.xml' + attach_name = declaration_name.upper() + ' ' + datetime.strftime(start_date_datetime, '%Y-%m') + attach_obj = self.pool.get('ir.attachment') + if not context: + context = {} + context.update({'default_res_id' : ids[0], 'default_res_model': object._name}) + attach_id = attach_obj.create(cr, uid, {'name': attach_name, 'datas': base64.encodestring(xml_string), 'datas_fname': filename}, context=context) + return None + + +report_intrastat_common() + diff --git a/intrastat_base/intrastat_menu.xml b/intrastat_base/intrastat_menu.xml new file mode 100644 index 0000000..42888ca --- /dev/null +++ b/intrastat_base/intrastat_menu.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + diff --git a/intrastat_base/partner_address.py b/intrastat_base/partner_address.py new file mode 100644 index 0000000..bc4e4f0 --- /dev/null +++ b/intrastat_base/partner_address.py @@ -0,0 +1,36 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Report intrastat base module for OpenERP +# Copyright (C) 2010-2011 Akretion (http://www.akretion.com/) All Rights Reserved +# @author Alexis de Lattre +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from osv import osv, fields + +# We want to have the country field of partner_address always set +# because the selection of invoices for intrastat reports is based +# on the country of the invoice partner address ! +class res_partner_address(osv.osv): + _name = 'res.partner.address' + _inherit = 'res.partner.address' + _columns = { + 'country_id': fields.many2one('res.country', 'Country', required=True), + } + +res_partner_address() + diff --git a/intrastat_base/product.py b/intrastat_base/product.py new file mode 100644 index 0000000..d6c30f5 --- /dev/null +++ b/intrastat_base/product.py @@ -0,0 +1,36 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Report intrastat base module for OpenERP +# Copyright (C) 2010-2011 Akretion (http://www.akretion.com/) All Rights Reserved +# @author Alexis de Lattre +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from osv import osv, fields + +class product_template(osv.osv): + _inherit = "product.template" + _columns = { + 'exclude_from_intrastat': fields.boolean('Exclude from Intrastat reports', help="If true, the product or service will not taken into account for Intrastat Product or Service reports. So you should leave this field to false unless you have a good reason. Exemple of good reason : 'Shipping' is a service that should probably be excluded from the Intrastat Service report."), + } + + _default = { + 'exclude_from_intrastat': lambda *a: False, + } + +product_template() + diff --git a/intrastat_base/product_demo.xml b/intrastat_base/product_demo.xml new file mode 100644 index 0000000..f29f16d --- /dev/null +++ b/intrastat_base/product_demo.xml @@ -0,0 +1,22 @@ + + + + + + + + + Shipping costs + SHIP + service + + 30 + False + + + + diff --git a/intrastat_base/product_view.xml b/intrastat_base/product_view.xml new file mode 100644 index 0000000..7173765 --- /dev/null +++ b/intrastat_base/product_view.xml @@ -0,0 +1,47 @@ + + + + + + + + + + intrastat.base.product.normal.form + product.product + + + + + + + + + + + + + + + + intrastat.base.product.template.form + product.template + + + + + + + + + + + + + + + diff --git a/intrastat_base/security/ir.model.access.csv b/intrastat_base/security/ir.model.access.csv new file mode 100644 index 0000000..d7a2bf1 --- /dev/null +++ b/intrastat_base/security/ir.model.access.csv @@ -0,0 +1,2 @@ +"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" +"access_report_intrastat_common","Read access on report.intrastat.common","model_report_intrastat_common","base.group_user",1,0,0,0 From d4a2e7d492ce4e8f2bb67821251fd212e364d064 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Tue, 19 Apr 2011 00:36:16 +0200 Subject: [PATCH 002/103] Full re-design of intrastat types : probably requires deleting the report_intrastat_type table, restarting OpenERP and re-creating intrastat types. Moved intrastat departments from stock.warehouse to stock.location. Dropped SQL queries ; replaced by traditionnal python code logic. No more need to have one rate per day for invoices with foreign currency. Add total fiscal value for DEB More code factorization. Prepare translation work. --- intrastat_base/country.py | 2 +- intrastat_base/intrastat_common.py | 34 ++++++++++++++++++------------ intrastat_base/partner_address.py | 3 +-- intrastat_base/product.py | 2 +- 4 files changed, 23 insertions(+), 18 deletions(-) diff --git a/intrastat_base/country.py b/intrastat_base/country.py index fbd284c..483014c 100644 --- a/intrastat_base/country.py +++ b/intrastat_base/country.py @@ -24,7 +24,7 @@ from osv import osv, fields class res_country(osv.osv): _inherit = 'res.country' _columns = { - 'intrastat': fields.boolean('Intrastat member'), + 'intrastat': fields.boolean('Intrastat member', help="Set as True for countries that must be selected in the intrastat reports, i.e. for all European Union countries other than your own country."), } _defaults = { 'intrastat': lambda *a: False, diff --git a/intrastat_base/intrastat_common.py b/intrastat_base/intrastat_common.py index d7e6ec8..240641d 100644 --- a/intrastat_base/intrastat_common.py +++ b/intrastat_base/intrastat_common.py @@ -51,7 +51,7 @@ class report_intrastat_common(osv.osv_memory): def _check_start_date(self, cr, uid, ids, object, context=None): - '''Check that the start date if the first day of the month''' + '''Check that the start date is the first day of the month''' for date_to_check in object.read(cr, uid, ids, ['start_date'], context=context): datetime_to_check = datetime.strptime(date_to_check['start_date'], '%Y-%m-%d') if datetime_to_check.day != 1: @@ -59,41 +59,39 @@ class report_intrastat_common(osv.osv_memory): return True - def _check_generate_lines(self, cr, uid, ids, intrastat, context=None): - if len(ids) != 1: - raise osv.except_osv(_('Error :'), 'Hara kiri in generate_lines') + def _check_generate_lines(self, cr, uid, intrastat, context=None): if not intrastat.company_id.currency_id.code: - raise osv.except_osv(_('Error :'), _('The currency code is not set on the currency "%s".'%intrastat.company_id.currency_id.name)) + raise osv.except_osv(_('Error :'), _("The currency code is not set on the currency '%s'.") %intrastat.company_id.currency_id.name) if not intrastat.currency_id.code == 'EUR': - raise osv.except_osv(_('Error :'), _('The company currency must be "EUR", but is currently "%s".'%intrastat.currency_id.code)) + raise osv.except_osv(_('Error :'), _("The company currency must be 'EUR', but is currently '%s'.") %intrastat.currency_id.code) return None - def _check_generate_xml(self, cr, uid, ids, intrastat, context=None): - if len(ids) != 1: - raise osv.except_osv(_('Error :'), 'Hara kiri in generate_xml') + def _check_generate_xml(self, cr, uid, intrastat, context=None): if not intrastat.company_id.partner_id.vat: - raise osv.except_osv(_('Error :'), _('The VAT number is not set for the partner "%s".'%intrastat.company_id.partner_id.name)) + raise osv.except_osv(_('Error :'), _("The VAT number is not set for the partner '%s'.") %intrastat.company_id.partner_id.name) if not intrastat.company_id.partner_id.vat[0:2] == 'FR': - raise osv.except_osv(_('Error :'), _("The company '%s' should have a VAT number starting with 'FR' on it's related partner. Its current VAT number is '%s'."%(intrastat.company_id.name, intrastat.company_id.partner_id.vat))) + raise osv.except_osv(_('Error :'), _("The company '%s' should have a VAT number starting with 'FR' on it's related partner. Its current VAT number is '%s'.") %(intrastat.company_id.name, intrastat.company_id.partner_id.vat)) return None def _check_xml_schema(self, cr, uid, xml_root, xml_string, xsd, context=None): + '''Validate the XML file against the XSD''' from lxml import etree official_des_xml_schema = etree.XMLSchema(etree.fromstring(xsd)) try: official_des_xml_schema.assertValid(xml_root) except Exception, e: # if the validation of the XSD fails, we arrive here import netsvc logger = netsvc.Logger() - logger.notifyChannel('intrastat', netsvc.LOG_WARNING, "The XML file is invalid against the XSD") + logger.notifyChannel('intrastat', netsvc.LOG_WARNING, "The XML file is invalid against the XML Schema Definition") logger.notifyChannel('intrastat', netsvc.LOG_WARNING, xml_string) logger.notifyChannel('intrastat', netsvc.LOG_WARNING, e) - raise osv.except_osv(_('Error :'), _('The generated XML file is not valid against the official XML schema. The generated XML file and the full error have been written in the server logs. Here is the exact error, which may give you an idea of the cause of the problem : ' + str(e))) + raise osv.except_osv(_('Error :'), _('The generated XML file is not valid against the official XML Schema Definition. The generated XML file and the full error have been written in the server logs. Here is the error, which may give you an idea on the cause of the problem : %s.') % str(e)) return None + def _attach_xml_file(self, cr, uid, ids, object, xml_string, start_date_datetime, declaration_name, context=None): - '''Attach the XML file to the intrastat_xxx object''' + '''Attach the XML file to the report_intrastat_product/service object''' import base64 if len(ids) != 1: raise osv.except_osv(_('Error :'), 'Hara kiri in attach_xml_file') @@ -107,5 +105,13 @@ class report_intrastat_common(osv.osv_memory): return None + def partner_on_change(self, cr, uid, ids, partner_id=False): + result = {} + result['value'] = {} + if partner_id: + company = self.pool.get('res.partner').read(cr, uid, partner_id, ['vat']) + result['value'].update({'partner_vat': company['vat']}) + return result + report_intrastat_common() diff --git a/intrastat_base/partner_address.py b/intrastat_base/partner_address.py index bc4e4f0..f36329b 100644 --- a/intrastat_base/partner_address.py +++ b/intrastat_base/partner_address.py @@ -22,11 +22,10 @@ from osv import osv, fields -# We want to have the country field of partner_address always set +# We want to have the country field on res_partner_address always set # because the selection of invoices for intrastat reports is based # on the country of the invoice partner address ! class res_partner_address(osv.osv): - _name = 'res.partner.address' _inherit = 'res.partner.address' _columns = { 'country_id': fields.many2one('res.country', 'Country', required=True), diff --git a/intrastat_base/product.py b/intrastat_base/product.py index d6c30f5..959eede 100644 --- a/intrastat_base/product.py +++ b/intrastat_base/product.py @@ -25,7 +25,7 @@ from osv import osv, fields class product_template(osv.osv): _inherit = "product.template" _columns = { - 'exclude_from_intrastat': fields.boolean('Exclude from Intrastat reports', help="If true, the product or service will not taken into account for Intrastat Product or Service reports. So you should leave this field to false unless you have a good reason. Exemple of good reason : 'Shipping' is a service that should probably be excluded from the Intrastat Service report."), + 'exclude_from_intrastat': fields.boolean('Exclude from Intrastat reports', help="If set to True, the product or service will not be taken into account for Intrastat Product or Service reports. So you should leave this field to False unless you have a good reason. Exemple of good reason : 'Shipping' is a service that should probably be excluded from the Intrastat Service report."), } _default = { From 8eb4b7c8e4ca15e1ff3803f018e7dfba9af04d84 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Tue, 26 Apr 2011 09:28:46 +0200 Subject: [PATCH 003/103] Moved some demo data from l10n_fr_intrastat_product to intrastat_base Moved configuration about taxes from company form to tax form Some modifications to ease v5 -> v6 migration : - object report_intrastat_code now belong to group account manager - button functions now return True Tried to implement the following feature : open attachement form when the XML file as been generated : works on v6, but make client crash en v5 -> code has been commented DEB lines with procedure code = 25 are now deducted from the fiscal total. Round invoice total. --- intrastat_base/__terp__.py | 2 +- intrastat_base/intrastat_common.py | 18 +++++++++- intrastat_base/intrastat_demo.xml | 57 ++++++++++++++++++++++++++++++ intrastat_base/product_demo.xml | 22 ------------ 4 files changed, 75 insertions(+), 24 deletions(-) create mode 100644 intrastat_base/intrastat_demo.xml delete mode 100644 intrastat_base/product_demo.xml diff --git a/intrastat_base/__terp__.py b/intrastat_base/__terp__.py index 6ad92af..a048ca2 100644 --- a/intrastat_base/__terp__.py +++ b/intrastat_base/__terp__.py @@ -47,7 +47,7 @@ Please contact Alexis de Lattre from Akretion for 'country_view.xml', 'intrastat_menu.xml', ], - 'demo_xml': ['product_demo.xml'], + 'demo_xml': ['intrastat_demo.xml'], 'installable': True, 'active': False, } diff --git a/intrastat_base/intrastat_common.py b/intrastat_base/intrastat_common.py index 240641d..011a050 100644 --- a/intrastat_base/intrastat_common.py +++ b/intrastat_base/intrastat_common.py @@ -102,7 +102,23 @@ class report_intrastat_common(osv.osv_memory): context = {} context.update({'default_res_id' : ids[0], 'default_res_model': object._name}) attach_id = attach_obj.create(cr, uid, {'name': attach_name, 'datas': base64.encodestring(xml_string), 'datas_fname': filename}, context=context) - return None + return attach_id + + + def _open_attach_view(self, cr, uid, attach_id, title='XML file', context=None): + '''Returns an action which opens the form view of the corresponding attachement''' + action = { + 'name': title, + 'view_type': 'form', + 'view_mode': 'form,tree', + 'view_id': False, + 'res_model': 'ir.attachment', + 'type': 'ir.actions.act_window', + 'nodestroy': True, + 'target': 'current', + 'res_id': [attach_id], + } + return action def partner_on_change(self, cr, uid, ids, partner_id=False): diff --git a/intrastat_base/intrastat_demo.xml b/intrastat_base/intrastat_demo.xml new file mode 100644 index 0000000..31aa565 --- /dev/null +++ b/intrastat_base/intrastat_demo.xml @@ -0,0 +1,57 @@ + + + + + + + + + FR58441019213 + + + + BE0828696437 + True + + + + BE0443167858 + True + + + + BE0884025633 + True + + + + True + + + + True + + + + True + + + + True + + + + Shipping costs + SHIP + service + + 30 + False + + + + diff --git a/intrastat_base/product_demo.xml b/intrastat_base/product_demo.xml deleted file mode 100644 index f29f16d..0000000 --- a/intrastat_base/product_demo.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - Shipping costs - SHIP - service - - 30 - False - - - - From 64c2cbdf208a810e2f428aa12b8187748eeb3746 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Mon, 9 May 2011 15:13:28 +0200 Subject: [PATCH 004/103] Moved the field exclude_from_intrastat_if_present of account.tax from l10n_fr_intrastat_product to intrastat_base, because it should also be used in the module l10n_fr_intrastat_service. Take this field into account in the generation of DEB lines (module l10n_fr_intrastat_service). --- intrastat_base/__init__.py | 1 + intrastat_base/__terp__.py | 1 + intrastat_base/tax.py | 33 +++++++++++++++++++++++++++++++++ intrastat_base/tax_view.xml | 28 ++++++++++++++++++++++++++++ 4 files changed, 63 insertions(+) create mode 100644 intrastat_base/tax.py create mode 100644 intrastat_base/tax_view.xml diff --git a/intrastat_base/__init__.py b/intrastat_base/__init__.py index c593568..13ca149 100644 --- a/intrastat_base/__init__.py +++ b/intrastat_base/__init__.py @@ -22,6 +22,7 @@ import country import product +import tax import partner_address import intrastat_common diff --git a/intrastat_base/__terp__.py b/intrastat_base/__terp__.py index a048ca2..555287d 100644 --- a/intrastat_base/__terp__.py +++ b/intrastat_base/__terp__.py @@ -45,6 +45,7 @@ Please contact Alexis de Lattre from Akretion for 'security/ir.model.access.csv', 'product_view.xml', 'country_view.xml', + 'tax_view.xml', 'intrastat_menu.xml', ], 'demo_xml': ['intrastat_demo.xml'], diff --git a/intrastat_base/tax.py b/intrastat_base/tax.py new file mode 100644 index 0000000..4d12d32 --- /dev/null +++ b/intrastat_base/tax.py @@ -0,0 +1,33 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Report intrastat base module for OpenERP +# Copyright (C) 2011 Akretion (http://www.akretion.com). All Rights Reserved +# @author Alexis de Lattre +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from osv import osv, fields + + +class account_tax(osv.osv): + _inherit = "account.tax" + _columns = { + 'exclude_from_intrastat_if_present': fields.boolean('Exclude invoice line from intrastat if this tax is present', help="If this tax is present on an invoice line, this invoice line will be skipped when generating Intrastat Product or Service lines from invoices."), + } + +account_tax() + diff --git a/intrastat_base/tax_view.xml b/intrastat_base/tax_view.xml new file mode 100644 index 0000000..5141c3e --- /dev/null +++ b/intrastat_base/tax_view.xml @@ -0,0 +1,28 @@ + + + + + + + + + + intrastat.base.tax + account.tax + form + + + + + + + + + + + + From 9e5b2cb7c4772ac4e433ac10c1ec466b602a8bd3 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Sun, 15 May 2011 22:29:36 +0200 Subject: [PATCH 005/103] It is now possible to set the H.S. code on the product category. Some "return None" changed to "return True" --- intrastat_base/country.py | 2 +- intrastat_base/intrastat_common.py | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/intrastat_base/country.py b/intrastat_base/country.py index 483014c..5d2cb1d 100644 --- a/intrastat_base/country.py +++ b/intrastat_base/country.py @@ -24,7 +24,7 @@ from osv import osv, fields class res_country(osv.osv): _inherit = 'res.country' _columns = { - 'intrastat': fields.boolean('Intrastat member', help="Set as True for countries that must be selected in the intrastat reports, i.e. for all European Union countries other than your own country."), + 'intrastat': fields.boolean('Intrastat country', help="Set as True for countries that must be selected in the intrastat reports, i.e. for all European Union countries other than your own country."), } _defaults = { 'intrastat': lambda *a: False, diff --git a/intrastat_base/intrastat_common.py b/intrastat_base/intrastat_common.py index 011a050..aef3930 100644 --- a/intrastat_base/intrastat_common.py +++ b/intrastat_base/intrastat_common.py @@ -64,15 +64,13 @@ class report_intrastat_common(osv.osv_memory): raise osv.except_osv(_('Error :'), _("The currency code is not set on the currency '%s'.") %intrastat.company_id.currency_id.name) if not intrastat.currency_id.code == 'EUR': raise osv.except_osv(_('Error :'), _("The company currency must be 'EUR', but is currently '%s'.") %intrastat.currency_id.code) - return None + return True def _check_generate_xml(self, cr, uid, intrastat, context=None): if not intrastat.company_id.partner_id.vat: raise osv.except_osv(_('Error :'), _("The VAT number is not set for the partner '%s'.") %intrastat.company_id.partner_id.name) - if not intrastat.company_id.partner_id.vat[0:2] == 'FR': - raise osv.except_osv(_('Error :'), _("The company '%s' should have a VAT number starting with 'FR' on it's related partner. Its current VAT number is '%s'.") %(intrastat.company_id.name, intrastat.company_id.partner_id.vat)) - return None + return True def _check_xml_schema(self, cr, uid, xml_root, xml_string, xsd, context=None): @@ -87,7 +85,7 @@ class report_intrastat_common(osv.osv_memory): logger.notifyChannel('intrastat', netsvc.LOG_WARNING, xml_string) logger.notifyChannel('intrastat', netsvc.LOG_WARNING, e) raise osv.except_osv(_('Error :'), _('The generated XML file is not valid against the official XML Schema Definition. The generated XML file and the full error have been written in the server logs. Here is the error, which may give you an idea on the cause of the problem : %s.') % str(e)) - return None + return True def _attach_xml_file(self, cr, uid, ids, object, xml_string, start_date_datetime, declaration_name, context=None): From 2ea16f5a7871723d50e110603384ba7b566ab231 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Mon, 6 Jun 2011 20:42:04 +0200 Subject: [PATCH 006/103] . Implemented the fiscal representative : for example, when you ship to the EU but invoice outside of the EU, your customer needs to have a fiscal representative inside the EU, which will be used for the DEB . depend on base_vat instead of account. --- intrastat_base/__terp__.py | 2 +- intrastat_base/intrastat_common.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/intrastat_base/__terp__.py b/intrastat_base/__terp__.py index 555287d..089173a 100644 --- a/intrastat_base/__terp__.py +++ b/intrastat_base/__terp__.py @@ -39,7 +39,7 @@ Please contact Alexis de Lattre from Akretion for """, 'author': 'Akretion', 'website': 'http://www.akretion.com', - 'depends': ['account'], + 'depends': ['base_vat'], 'init_xml': ['country_data.xml'], 'update_xml': [ 'security/ir.model.access.csv', diff --git a/intrastat_base/intrastat_common.py b/intrastat_base/intrastat_common.py index aef3930..a49da8a 100644 --- a/intrastat_base/intrastat_common.py +++ b/intrastat_base/intrastat_common.py @@ -105,6 +105,7 @@ class report_intrastat_common(osv.osv_memory): def _open_attach_view(self, cr, uid, attach_id, title='XML file', context=None): '''Returns an action which opens the form view of the corresponding attachement''' + # Only works in v6 -> not used in v5 action = { 'name': title, 'view_type': 'form', From 35e361e7553762dabebe0d97ccb980f4d3bc5931 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Fri, 10 Jun 2011 11:22:00 +0200 Subject: [PATCH 007/103] Update of some strings before translation. Started translation work. --- intrastat_base/i18n/fr_FR.po | 153 +++++++++++++++++++++++++ intrastat_base/i18n/intrastat_base.pot | 143 +++++++++++++++++++++++ intrastat_base/intrastat_common.py | 2 +- 3 files changed, 297 insertions(+), 1 deletion(-) create mode 100644 intrastat_base/i18n/fr_FR.po create mode 100644 intrastat_base/i18n/intrastat_base.pot diff --git a/intrastat_base/i18n/fr_FR.po b/intrastat_base/i18n/fr_FR.po new file mode 100644 index 0000000..362a726 --- /dev/null +++ b/intrastat_base/i18n/fr_FR.po @@ -0,0 +1,153 @@ +# Translation of OpenERP Server. +# This file contains the translation of the following modules: +# * intrastat_base +# +msgid "" +msgstr "" +"Project-Id-Version: OpenERP Server 5.0.16\n" +"Report-Msgid-Bugs-To: support@openerp.com\n" +"POT-Creation-Date: 2011-06-09 17:56:57+0000\n" +"PO-Revision-Date: 2011-06-09 17:56:57+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: intrastat_base +#: help:product.template,exclude_from_intrastat:0 +msgid "If set to True, the product or service will not be taken into account for Intrastat Product or Service reports. So you should leave this field to False unless you have a good reason. Exemple of good reason : 'Shipping' is a service that should probably be excluded from the Intrastat Service report." +msgstr "Si cette option est activée, le produit ou le service ne sera pas pris en compte pour les rapports de DEB et de DES. Sauf si vous avez une bonne raison, il faut donc laisser cette option désactivée. Exemple de bonne raison : 'Frais de port' est un service qui devrait a priori être exclu de la DES." + +#. module: intrastat_base +#: constraint:ir.model:0 +msgid "The Object name must start with x_ and not contain any special character !" +msgstr "Le nom de l'objet doit commencer avec x_ et ne pas contenir de charactères spéciaux !" + +#. module: intrastat_base +#: model:ir.ui.menu,name:intrastat_base.menu_intrastat_base_root +msgid "Intrastat reporting" +msgstr "DEB et DES" + +#. module: intrastat_base +#: constraint:product.template:0 +msgid "Error: The default UOM and the purchase UOM must be in the same category." +msgstr "Erreur: l'UdM par défaut et l'UdM d'achat doivent appartenir à la même catégorie." + +#. module: intrastat_base +#: field:account.tax,exclude_from_intrastat_if_present:0 +msgid "Exclude invoice line from intrastat if this tax is present" +msgstr "Exclue la ligne de facture de la DEB/DES si cette taxe est présente" + +#. module: intrastat_base +#: help:res.country,intrastat:0 +msgid "Set as True for countries that must be selected in the intrastat reports, i.e. for all European Union countries other than your own country." +msgstr "Activer cette option pour les pays qui doivent être inclus dans la DEB et la DES, i.e. tous les pays de l'Union Européenne sauf votre propre pays." + +#. module: intrastat_base +#: view:product.product:0 +#: view:product.template:0 +msgid "Intrastat properties" +msgstr "Paramètres pour la DEB et la DES" + +#. module: intrastat_base +#: model:ir.module.module,description:intrastat_base.module_meta_information +msgid "This module contains the common functions for 2 other modules :\n" +"- l10n_fr_intrastat_service : the module for the \"Déclaration Européenne des Services\" (DES)\n" +"- l10n_fr_intrastat_product : the module for the \"Déclaration d'Echange de Biens\" (DEB)\n" +"This module is not usefull if it's not used together with one of those 2 modules.\n" +"\n" +"This module doesn't have any France-specific stuff. So it can be used as a basis for other intrastat modules for other EU countries.\n" +"\n" +"WARNING : this module conflicts with the module \"report_intrastat\" from the addons. If you have already installed the module \"report_intrastat\", you should uninstall it first before installing this module.\n" +"\n" +"Please contact Alexis de Lattre from Akretion for any help or question about this module.\n" +" " +msgstr "This module contains the common functions for 2 other modules :\n" +"- l10n_fr_intrastat_service : the module for the \"Déclaration Européenne des Services\" (DES)\n" +"- l10n_fr_intrastat_product : the module for the \"Déclaration d'Echange de Biens\" (DEB)\n" +"This module is not usefull if it's not used together with one of those 2 modules.\n" +"\n" +"This module doesn't have any France-specific stuff. So it can be used as a basis for other intrastat modules for other EU countries.\n" +"\n" +"WARNING : this module conflicts with the module \"report_intrastat\" from the addons. If you have already installed the module \"report_intrastat\", you should uninstall it first before installing this module.\n" +"\n" +"Please contact Alexis de Lattre from Akretion for any help or question about this module.\n" +" " + +#. module: intrastat_base +#: help:account.tax,exclude_from_intrastat_if_present:0 +msgid "If this tax is present on an invoice line, this invoice line will be skipped when generating Intrastat Product or Service lines from invoices." +msgstr "Si cette taxe est présente sur une ligne de facture, cette ligne de facture ne sera pas prise en compte lors de la génération de la DEB et de la DES depuis les factures." + +#. module: intrastat_base +#: field:res.country,intrastat:0 +msgid "Intrastat country" +msgstr "Pays intrastat" + +#. module: intrastat_base +#: model:ir.model,name:intrastat_base.model_report_intrastat_common +msgid "Common functions for intrastat reports for products and services" +msgstr "Common functions for intrastat reports for products and services" + +#. module: intrastat_base +#: code:addons/intrastat_base/intrastat_common.py:0 +#, python-format +msgid "The company currency must be 'EUR', but is currently '%s'." +msgstr "La monnaie de la société doit être 'EUR', mais est actuellement '%s'." + +#. module: intrastat_base +#: code:addons/intrastat_base/intrastat_common.py:0 +#, python-format +msgid "The VAT number is not set for the partner '%s'." +msgstr "Le numéro de TVA n'est pas renseigné pour le partenaire '%s'." + +#. module: intrastat_base +#: constraint:ir.ui.view:0 +msgid "Invalid XML for View Architecture!" +msgstr "XML non valide pour l'architecture de la vue" + +#. module: intrastat_base +#: code:addons/intrastat_base/intrastat_common.py:0 +#, python-format +msgid "The currency code is not set on the currency '%s'." +msgstr "Il manque le code de monnaie sur la monnaie '%s'." + +#. module: intrastat_base +#: constraint:product.template:0 +msgid "Error: UOS must be in a different category than the UOM" +msgstr "Erreur : l'Unité Secondaire doit appartenir à une autre catégorie que l'Unité de Mesure." + +#. module: intrastat_base +#: model:ir.module.module,shortdesc:intrastat_base.module_meta_information +msgid "Base module for Intrastat reporting" +msgstr "Module de base pour les rapports intrastat" + +#. module: intrastat_base +#: field:product.template,exclude_from_intrastat:0 +msgid "Exclude from Intrastat reports" +msgstr "Exclure de la DEB et de la DES" + +#. module: intrastat_base +#: model:product.template,name:intrastat_base.shipping_costs_exclude_product_template +msgid "Shipping costs" +msgstr "Shipping costs" + +#. module: intrastat_base +#: code:addons/intrastat_base/intrastat_common.py:0 +#, python-format +msgid "The generated XML file is not valid against the official XML Schema Definition. The generated XML file and the full error have been written in the server logs. Here is the error, which may give you an idea on the cause of the problem : %s." +msgstr "La validation du fichier XML avec le schéma XML officiel a échoué. Le fichier XML généré et le détail de l'erreur ont été écrits dans les logs du serveur. Voici le message d'erreur, qui peut vous donner une idée de la cause du problème : %s." + +#. module: intrastat_base +#: constraint:product.product:0 +msgid "Error: Invalid ean code" +msgstr "Erreur: code EAN invalide" + +#. module: intrastat_base +#: code:addons/intrastat_base/intrastat_common.py:0 +#, python-format +msgid "Error :" +msgstr "Erreur :" + diff --git a/intrastat_base/i18n/intrastat_base.pot b/intrastat_base/i18n/intrastat_base.pot new file mode 100644 index 0000000..a57bce6 --- /dev/null +++ b/intrastat_base/i18n/intrastat_base.pot @@ -0,0 +1,143 @@ +# Translation of OpenERP Server. +# This file contains the translation of the following modules: +# * intrastat_base +# +msgid "" +msgstr "" +"Project-Id-Version: OpenERP Server 5.0.16\n" +"Report-Msgid-Bugs-To: support@openerp.com\n" +"POT-Creation-Date: 2011-06-09 17:51:13+0000\n" +"PO-Revision-Date: 2011-06-09 17:51:13+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: intrastat_base +#: help:product.template,exclude_from_intrastat:0 +msgid "If set to True, the product or service will not be taken into account for Intrastat Product or Service reports. So you should leave this field to False unless you have a good reason. Exemple of good reason : 'Shipping' is a service that should probably be excluded from the Intrastat Service report." +msgstr "" + +#. module: intrastat_base +#: constraint:ir.model:0 +msgid "The Object name must start with x_ and not contain any special character !" +msgstr "" + +#. module: intrastat_base +#: model:ir.ui.menu,name:intrastat_base.menu_intrastat_base_root +msgid "Intrastat reporting" +msgstr "" + +#. module: intrastat_base +#: constraint:product.template:0 +msgid "Error: The default UOM and the purchase UOM must be in the same category." +msgstr "" + +#. module: intrastat_base +#: field:account.tax,exclude_from_intrastat_if_present:0 +msgid "Exclude invoice line from intrastat if this tax is present" +msgstr "" + +#. module: intrastat_base +#: help:res.country,intrastat:0 +msgid "Set as True for countries that must be selected in the intrastat reports, i.e. for all European Union countries other than your own country." +msgstr "" + +#. module: intrastat_base +#: view:product.product:0 +#: view:product.template:0 +msgid "Intrastat properties" +msgstr "" + +#. module: intrastat_base +#: model:ir.module.module,description:intrastat_base.module_meta_information +msgid "This module contains the common functions for 2 other modules :\n" +"- l10n_fr_intrastat_service : the module for the \"Déclaration Européenne des Services\" (DES)\n" +"- l10n_fr_intrastat_product : the module for the \"Déclaration d'Echange de Biens\" (DEB)\n" +"This module is not usefull if it's not used together with one of those 2 modules.\n" +"\n" +"This module doesn't have any France-specific stuff. So it can be used as a basis for other intrastat modules for other EU countries.\n" +"\n" +"WARNING : this module conflicts with the module \"report_intrastat\" from the addons. If you have already installed the module \"report_intrastat\", you should uninstall it first before installing this module.\n" +"\n" +"Please contact Alexis de Lattre from Akretion for any help or question about this module.\n" +" " +msgstr "" + +#. module: intrastat_base +#: help:account.tax,exclude_from_intrastat_if_present:0 +msgid "If this tax is present on an invoice line, this invoice line will be skipped when generating Intrastat Product or Service lines from invoices." +msgstr "" + +#. module: intrastat_base +#: field:res.country,intrastat:0 +msgid "Intrastat country" +msgstr "" + +#. module: intrastat_base +#: model:ir.model,name:intrastat_base.model_report_intrastat_common +msgid "Common functions for intrastat reports for products and services" +msgstr "" + +#. module: intrastat_base +#: code:addons/intrastat_base/intrastat_common.py:0 +#, python-format +msgid "The company currency must be 'EUR', but is currently '%s'." +msgstr "" + +#. module: intrastat_base +#: code:addons/intrastat_base/intrastat_common.py:0 +#, python-format +msgid "The VAT number is not set for the partner '%s'." +msgstr "" + +#. module: intrastat_base +#: constraint:ir.ui.view:0 +msgid "Invalid XML for View Architecture!" +msgstr "" + +#. module: intrastat_base +#: code:addons/intrastat_base/intrastat_common.py:0 +#, python-format +msgid "The currency code is not set on the currency '%s'." +msgstr "" + +#. module: intrastat_base +#: constraint:product.template:0 +msgid "Error: UOS must be in a different category than the UOM" +msgstr "" + +#. module: intrastat_base +#: model:ir.module.module,shortdesc:intrastat_base.module_meta_information +msgid "Base module for Intrastat reporting" +msgstr "" + +#. module: intrastat_base +#: field:product.template,exclude_from_intrastat:0 +msgid "Exclude from Intrastat reports" +msgstr "" + +#. module: intrastat_base +#: model:product.template,name:intrastat_base.shipping_costs_exclude_product_template +msgid "Shipping costs" +msgstr "" + +#. module: intrastat_base +#: code:addons/intrastat_base/intrastat_common.py:0 +#, python-format +msgid "The generated XML file is not valid against the official XML Schema Definition. The generated XML file and the full error have been written in the server logs. Here is the error, which may give you an idea on the cause of the problem : %s." +msgstr "" + +#. module: intrastat_base +#: constraint:product.product:0 +msgid "Error: Invalid ean code" +msgstr "" + +#. module: intrastat_base +#: code:addons/intrastat_base/intrastat_common.py:0 +#, python-format +msgid "Error :" +msgstr "" + diff --git a/intrastat_base/intrastat_common.py b/intrastat_base/intrastat_common.py index a49da8a..5cbf191 100644 --- a/intrastat_base/intrastat_common.py +++ b/intrastat_base/intrastat_common.py @@ -21,7 +21,7 @@ ############################################################################## from osv import osv, fields -from datetime import datetime, timedelta +from datetime import datetime from dateutil.relativedelta import relativedelta from tools.translate import _ From 1ac373520f346ca764e340bc152fb6e2aaa1725a Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Fri, 8 Jul 2011 16:11:08 +0200 Subject: [PATCH 008/103] Modify demo data. --- intrastat_base/intrastat_demo.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intrastat_base/intrastat_demo.xml b/intrastat_base/intrastat_demo.xml index 31aa565..96bd880 100644 --- a/intrastat_base/intrastat_demo.xml +++ b/intrastat_base/intrastat_demo.xml @@ -13,7 +13,7 @@ FR58441019213 - + BE0828696437 True From af5f4c9ef5615c7b7ec210b9a650cbfb0c61416e Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Wed, 17 Aug 2011 22:35:08 +0200 Subject: [PATCH 009/103] Remove select="2", which is useless in v6 --- intrastat_base/product_view.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/intrastat_base/product_view.xml b/intrastat_base/product_view.xml index 7173765..12d7a52 100644 --- a/intrastat_base/product_view.xml +++ b/intrastat_base/product_view.xml @@ -19,7 +19,7 @@ - + @@ -36,7 +36,7 @@ - + From 9cf3a194e60e250d4343994a3847b86370b4ac3d Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Wed, 7 Sep 2011 17:53:07 +0200 Subject: [PATCH 010/103] Same modification as my previous commit for DEB : when we sell to a physical person in the EU with VAT, the move is not declared in DEB, so it must not block with a "raise" if the partner doesn't have a VAT number. --- intrastat_base/intrastat_demo.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/intrastat_base/intrastat_demo.xml b/intrastat_base/intrastat_demo.xml index 96bd880..d3114fa 100644 --- a/intrastat_base/intrastat_demo.xml +++ b/intrastat_base/intrastat_demo.xml @@ -13,12 +13,12 @@ FR58441019213 - + BE0828696437 True - + BE0443167858 True From f1609dd0b7322d246aa04a2798daab40728e468b Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Fri, 9 Sep 2011 11:15:01 +0200 Subject: [PATCH 011/103] Update translations. --- .../{__terp__.py => __openerp__.py} | 0 intrastat_base/i18n/fr_FR.po | 71 ++++++++++--------- intrastat_base/i18n/intrastat_base.pot | 65 +++++++++-------- 3 files changed, 75 insertions(+), 61 deletions(-) rename intrastat_base/{__terp__.py => __openerp__.py} (100%) diff --git a/intrastat_base/__terp__.py b/intrastat_base/__openerp__.py similarity index 100% rename from intrastat_base/__terp__.py rename to intrastat_base/__openerp__.py diff --git a/intrastat_base/i18n/fr_FR.po b/intrastat_base/i18n/fr_FR.po index 362a726..d7f2d53 100644 --- a/intrastat_base/i18n/fr_FR.po +++ b/intrastat_base/i18n/fr_FR.po @@ -4,10 +4,10 @@ # msgid "" msgstr "" -"Project-Id-Version: OpenERP Server 5.0.16\n" +"Project-Id-Version: OpenERP Server 6.0.3\n" "Report-Msgid-Bugs-To: support@openerp.com\n" -"POT-Creation-Date: 2011-06-09 17:56:57+0000\n" -"PO-Revision-Date: 2011-06-09 17:56:57+0000\n" +"POT-Creation-Date: 2011-09-09 08:21+0000\n" +"PO-Revision-Date: 2011-09-09 08:21+0000\n" "Last-Translator: <>\n" "Language-Team: \n" "MIME-Version: 1.0\n" @@ -20,21 +20,35 @@ msgstr "" msgid "If set to True, the product or service will not be taken into account for Intrastat Product or Service reports. So you should leave this field to False unless you have a good reason. Exemple of good reason : 'Shipping' is a service that should probably be excluded from the Intrastat Service report." msgstr "Si cette option est activée, le produit ou le service ne sera pas pris en compte pour les rapports de DEB et de DES. Sauf si vous avez une bonne raison, il faut donc laisser cette option désactivée. Exemple de bonne raison : 'Frais de port' est un service qui devrait a priori être exclu de la DES." -#. module: intrastat_base -#: constraint:ir.model:0 -msgid "The Object name must start with x_ and not contain any special character !" -msgstr "Le nom de l'objet doit commencer avec x_ et ne pas contenir de charactères spéciaux !" - #. module: intrastat_base #: model:ir.ui.menu,name:intrastat_base.menu_intrastat_base_root msgid "Intrastat reporting" msgstr "DEB et DES" +#. module: intrastat_base +#: sql_constraint:res.country:0 +msgid "The code of the country must be unique !" +msgstr "Le code du pays doit être unique !" + #. module: intrastat_base #: constraint:product.template:0 msgid "Error: The default UOM and the purchase UOM must be in the same category." msgstr "Erreur: l'UdM par défaut et l'UdM d'achat doivent appartenir à la même catégorie." +#. module: intrastat_base +#: code:addons/intrastat_base/intrastat_common.py:64 +#: code:addons/intrastat_base/intrastat_common.py:70 +#: code:addons/intrastat_base/intrastat_common.py:85 +#: code:addons/intrastat_base/intrastat_common.py:93 +#, python-format +msgid "Error :" +msgstr "Erreur :" + +#. module: intrastat_base +#: model:ir.model,name:intrastat_base.model_account_tax +msgid "account.tax" +msgstr "account.tax" + #. module: intrastat_base #: field:account.tax,exclude_from_intrastat_if_present:0 msgid "Exclude invoice line from intrastat if this tax is present" @@ -76,6 +90,11 @@ msgstr "This module contains the common functions for 2 other modules :\n" "Please contact Alexis de Lattre from Akretion for any help or question about this module.\n" " " +#. module: intrastat_base +#: sql_constraint:res.country:0 +msgid "The name of the country must be unique !" +msgstr "Le nom du pays doit être unique !" + #. module: intrastat_base #: help:account.tax,exclude_from_intrastat_if_present:0 msgid "If this tax is present on an invoice line, this invoice line will be skipped when generating Intrastat Product or Service lines from invoices." @@ -92,32 +111,26 @@ msgid "Common functions for intrastat reports for products and services" msgstr "Common functions for intrastat reports for products and services" #. module: intrastat_base -#: code:addons/intrastat_base/intrastat_common.py:0 +#: code:addons/intrastat_base/intrastat_common.py:64 #, python-format msgid "The company currency must be 'EUR', but is currently '%s'." msgstr "La monnaie de la société doit être 'EUR', mais est actuellement '%s'." #. module: intrastat_base -#: code:addons/intrastat_base/intrastat_common.py:0 +#: code:addons/intrastat_base/intrastat_common.py:70 #, python-format msgid "The VAT number is not set for the partner '%s'." msgstr "Le numéro de TVA n'est pas renseigné pour le partenaire '%s'." #. module: intrastat_base -#: constraint:ir.ui.view:0 -msgid "Invalid XML for View Architecture!" -msgstr "XML non valide pour l'architecture de la vue" +#: model:ir.model,name:intrastat_base.model_res_country +msgid "Country" +msgstr "Pays" #. module: intrastat_base -#: code:addons/intrastat_base/intrastat_common.py:0 -#, python-format -msgid "The currency code is not set on the currency '%s'." -msgstr "Il manque le code de monnaie sur la monnaie '%s'." - -#. module: intrastat_base -#: constraint:product.template:0 -msgid "Error: UOS must be in a different category than the UOM" -msgstr "Erreur : l'Unité Secondaire doit appartenir à une autre catégorie que l'Unité de Mesure." +#: model:ir.model,name:intrastat_base.model_product_template +msgid "Product Template" +msgstr "Modèle de produit" #. module: intrastat_base #: model:ir.module.module,shortdesc:intrastat_base.module_meta_information @@ -135,19 +148,13 @@ msgid "Shipping costs" msgstr "Shipping costs" #. module: intrastat_base -#: code:addons/intrastat_base/intrastat_common.py:0 +#: code:addons/intrastat_base/intrastat_common.py:85 #, python-format msgid "The generated XML file is not valid against the official XML Schema Definition. The generated XML file and the full error have been written in the server logs. Here is the error, which may give you an idea on the cause of the problem : %s." msgstr "La validation du fichier XML avec le schéma XML officiel a échoué. Le fichier XML généré et le détail de l'erreur ont été écrits dans les logs du serveur. Voici le message d'erreur, qui peut vous donner une idée de la cause du problème : %s." #. module: intrastat_base -#: constraint:product.product:0 -msgid "Error: Invalid ean code" -msgstr "Erreur: code EAN invalide" - -#. module: intrastat_base -#: code:addons/intrastat_base/intrastat_common.py:0 -#, python-format -msgid "Error :" -msgstr "Erreur :" +#: model:ir.model,name:intrastat_base.model_res_partner_address +msgid "Partner Addresses" +msgstr "Carnet d'adresses" diff --git a/intrastat_base/i18n/intrastat_base.pot b/intrastat_base/i18n/intrastat_base.pot index a57bce6..34dbc59 100644 --- a/intrastat_base/i18n/intrastat_base.pot +++ b/intrastat_base/i18n/intrastat_base.pot @@ -4,10 +4,10 @@ # msgid "" msgstr "" -"Project-Id-Version: OpenERP Server 5.0.16\n" +"Project-Id-Version: OpenERP Server 6.0.3\n" "Report-Msgid-Bugs-To: support@openerp.com\n" -"POT-Creation-Date: 2011-06-09 17:51:13+0000\n" -"PO-Revision-Date: 2011-06-09 17:51:13+0000\n" +"POT-Creation-Date: 2011-09-09 08:18+0000\n" +"PO-Revision-Date: 2011-09-09 08:18+0000\n" "Last-Translator: <>\n" "Language-Team: \n" "MIME-Version: 1.0\n" @@ -20,21 +20,35 @@ msgstr "" msgid "If set to True, the product or service will not be taken into account for Intrastat Product or Service reports. So you should leave this field to False unless you have a good reason. Exemple of good reason : 'Shipping' is a service that should probably be excluded from the Intrastat Service report." msgstr "" -#. module: intrastat_base -#: constraint:ir.model:0 -msgid "The Object name must start with x_ and not contain any special character !" -msgstr "" - #. module: intrastat_base #: model:ir.ui.menu,name:intrastat_base.menu_intrastat_base_root msgid "Intrastat reporting" msgstr "" +#. module: intrastat_base +#: sql_constraint:res.country:0 +msgid "The code of the country must be unique !" +msgstr "" + #. module: intrastat_base #: constraint:product.template:0 msgid "Error: The default UOM and the purchase UOM must be in the same category." msgstr "" +#. module: intrastat_base +#: code:addons/intrastat_base/intrastat_common.py:64 +#: code:addons/intrastat_base/intrastat_common.py:70 +#: code:addons/intrastat_base/intrastat_common.py:85 +#: code:addons/intrastat_base/intrastat_common.py:93 +#, python-format +msgid "Error :" +msgstr "" + +#. module: intrastat_base +#: model:ir.model,name:intrastat_base.model_account_tax +msgid "account.tax" +msgstr "" + #. module: intrastat_base #: field:account.tax,exclude_from_intrastat_if_present:0 msgid "Exclude invoice line from intrastat if this tax is present" @@ -66,6 +80,11 @@ msgid "This module contains the common functions for 2 other modules :\n" " " msgstr "" +#. module: intrastat_base +#: sql_constraint:res.country:0 +msgid "The name of the country must be unique !" +msgstr "" + #. module: intrastat_base #: help:account.tax,exclude_from_intrastat_if_present:0 msgid "If this tax is present on an invoice line, this invoice line will be skipped when generating Intrastat Product or Service lines from invoices." @@ -82,31 +101,25 @@ msgid "Common functions for intrastat reports for products and services" msgstr "" #. module: intrastat_base -#: code:addons/intrastat_base/intrastat_common.py:0 +#: code:addons/intrastat_base/intrastat_common.py:64 #, python-format msgid "The company currency must be 'EUR', but is currently '%s'." msgstr "" #. module: intrastat_base -#: code:addons/intrastat_base/intrastat_common.py:0 +#: code:addons/intrastat_base/intrastat_common.py:70 #, python-format msgid "The VAT number is not set for the partner '%s'." msgstr "" #. module: intrastat_base -#: constraint:ir.ui.view:0 -msgid "Invalid XML for View Architecture!" +#: model:ir.model,name:intrastat_base.model_res_country +msgid "Country" msgstr "" #. module: intrastat_base -#: code:addons/intrastat_base/intrastat_common.py:0 -#, python-format -msgid "The currency code is not set on the currency '%s'." -msgstr "" - -#. module: intrastat_base -#: constraint:product.template:0 -msgid "Error: UOS must be in a different category than the UOM" +#: model:ir.model,name:intrastat_base.model_product_template +msgid "Product Template" msgstr "" #. module: intrastat_base @@ -125,19 +138,13 @@ msgid "Shipping costs" msgstr "" #. module: intrastat_base -#: code:addons/intrastat_base/intrastat_common.py:0 +#: code:addons/intrastat_base/intrastat_common.py:85 #, python-format msgid "The generated XML file is not valid against the official XML Schema Definition. The generated XML file and the full error have been written in the server logs. Here is the error, which may give you an idea on the cause of the problem : %s." msgstr "" #. module: intrastat_base -#: constraint:product.product:0 -msgid "Error: Invalid ean code" -msgstr "" - -#. module: intrastat_base -#: code:addons/intrastat_base/intrastat_common.py:0 -#, python-format -msgid "Error :" +#: model:ir.model,name:intrastat_base.model_res_partner_address +msgid "Partner Addresses" msgstr "" From 8ab5fe09a5c7d4523959ac8d1350c23ca924388a Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Mon, 30 Jan 2012 11:30:47 +0100 Subject: [PATCH 012/103] Updated licence pointer. --- intrastat_base/country_view.xml | 2 +- intrastat_base/intrastat_demo.xml | 2 +- intrastat_base/intrastat_menu.xml | 2 +- intrastat_base/product_view.xml | 2 +- intrastat_base/tax_view.xml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/intrastat_base/country_view.xml b/intrastat_base/country_view.xml index faa85d9..bf62fa3 100644 --- a/intrastat_base/country_view.xml +++ b/intrastat_base/country_view.xml @@ -2,7 +2,7 @@ diff --git a/intrastat_base/intrastat_demo.xml b/intrastat_base/intrastat_demo.xml index d3114fa..7965c6d 100644 --- a/intrastat_base/intrastat_demo.xml +++ b/intrastat_base/intrastat_demo.xml @@ -3,7 +3,7 @@ diff --git a/intrastat_base/intrastat_menu.xml b/intrastat_base/intrastat_menu.xml index 42888ca..b078c6a 100644 --- a/intrastat_base/intrastat_menu.xml +++ b/intrastat_base/intrastat_menu.xml @@ -2,7 +2,7 @@ diff --git a/intrastat_base/product_view.xml b/intrastat_base/product_view.xml index 12d7a52..cd7aefd 100644 --- a/intrastat_base/product_view.xml +++ b/intrastat_base/product_view.xml @@ -3,7 +3,7 @@ diff --git a/intrastat_base/tax_view.xml b/intrastat_base/tax_view.xml index 5141c3e..e60a327 100644 --- a/intrastat_base/tax_view.xml +++ b/intrastat_base/tax_view.xml @@ -3,7 +3,7 @@ From 8f38ce5bec4da9413742605efb4005fb835d5921 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Thu, 1 Mar 2012 16:16:12 +0100 Subject: [PATCH 013/103] Modify help message. --- intrastat_base/product.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intrastat_base/product.py b/intrastat_base/product.py index 959eede..38cbcb7 100644 --- a/intrastat_base/product.py +++ b/intrastat_base/product.py @@ -25,7 +25,7 @@ from osv import osv, fields class product_template(osv.osv): _inherit = "product.template" _columns = { - 'exclude_from_intrastat': fields.boolean('Exclude from Intrastat reports', help="If set to True, the product or service will not be taken into account for Intrastat Product or Service reports. So you should leave this field to False unless you have a good reason. Exemple of good reason : 'Shipping' is a service that should probably be excluded from the Intrastat Service report."), + 'exclude_from_intrastat': fields.boolean('Exclude from Intrastat reports', help="If set to True, the product or service will not be taken into account for Intrastat Product or Service reports. So you should leave this field to False unless you have a very good reason."), } _default = { From 9fe090148e11080a4f5183e31269247afd003408 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Tue, 5 Jun 2012 15:04:00 +0200 Subject: [PATCH 014/103] Add option "is_accessory_cost" on product.template : If the invoice has is_accessory_cost services but no regular product -> DES If the invoice has is_accessory_cost services and regular product -> added to the cost of products in DEB Now allows "pricelist for statistical value" which is not in EUR (the currency conversion will be made from the pricelist currency to EUR) Usability improvements : - Order for DEB and DES tree view : "the more recent at the top" - distinction between "Information to declare" and "Additionnal information" in intrastat lines --- intrastat_base/intrastat_demo.xml | 2 +- intrastat_base/product.py | 15 ++++++++++++++- intrastat_base/product_view.xml | 6 ++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/intrastat_base/intrastat_demo.xml b/intrastat_base/intrastat_demo.xml index 7965c6d..d83640e 100644 --- a/intrastat_base/intrastat_demo.xml +++ b/intrastat_base/intrastat_demo.xml @@ -50,7 +50,7 @@ service 30 - False + True diff --git a/intrastat_base/product.py b/intrastat_base/product.py index 38cbcb7..0f29a02 100644 --- a/intrastat_base/product.py +++ b/intrastat_base/product.py @@ -2,7 +2,7 @@ ############################################################################## # # Report intrastat base module for OpenERP -# Copyright (C) 2010-2011 Akretion (http://www.akretion.com/) All Rights Reserved +# Copyright (C) 2010-2012 Akretion (http://www.akretion.com/) All Rights Reserved # @author Alexis de Lattre # # This program is free software: you can redistribute it and/or modify @@ -21,16 +21,29 @@ ############################################################################## from osv import osv, fields +from tools.translate import _ class product_template(osv.osv): _inherit = "product.template" _columns = { 'exclude_from_intrastat': fields.boolean('Exclude from Intrastat reports', help="If set to True, the product or service will not be taken into account for Intrastat Product or Service reports. So you should leave this field to False unless you have a very good reason."), + 'is_accessory_cost' : fields.boolean('Is accessory cost?', help='Activate this option for shipping costs, packaging costs and all services related to the sale of product. This option is used for Intrastat reports.'), } _default = { 'exclude_from_intrastat': lambda *a: False, } + + def _check_accessory_cost(self, cr, uid, ids): + for product in self.browse(cr, uid, ids): + if product.is_accessory_cost and product.type != 'service': + raise osv.except_osv(_('Error :'), _("The option 'Is accessory cost?' should only be activated on 'Service' products. You have activated this option for the product '%s' which is of type '%s'" % (product.name, product.type))) + return True + + _constraints = [ + (_check_accessory_cost, "Error msg is in raise", ['is_accessory_cost', 'type']) + ] + product_template() diff --git a/intrastat_base/product_view.xml b/intrastat_base/product_view.xml index cd7aefd..28b026e 100644 --- a/intrastat_base/product_view.xml +++ b/intrastat_base/product_view.xml @@ -22,6 +22,9 @@ + + + @@ -39,6 +42,9 @@ + + + From 567487680f5608e4121ce9930814982514e3778e Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Tue, 5 Jun 2012 15:34:32 +0200 Subject: [PATCH 015/103] Better string. Update French translation. --- intrastat_base/i18n/fr_FR.po | 40 ++++++++++++++++++-------- intrastat_base/i18n/intrastat_base.pot | 36 ++++++++++++++++------- intrastat_base/product.py | 2 +- 3 files changed, 55 insertions(+), 23 deletions(-) diff --git a/intrastat_base/i18n/fr_FR.po b/intrastat_base/i18n/fr_FR.po index d7f2d53..c3a85fe 100644 --- a/intrastat_base/i18n/fr_FR.po +++ b/intrastat_base/i18n/fr_FR.po @@ -4,10 +4,10 @@ # msgid "" msgstr "" -"Project-Id-Version: OpenERP Server 6.0.3\n" +"Project-Id-Version: OpenERP Server 6.0.4\n" "Report-Msgid-Bugs-To: support@openerp.com\n" -"POT-Creation-Date: 2011-09-09 08:21+0000\n" -"PO-Revision-Date: 2011-09-09 08:21+0000\n" +"POT-Creation-Date: 2012-06-05 13:28+0000\n" +"PO-Revision-Date: 2012-06-05 13:28+0000\n" "Last-Translator: <>\n" "Language-Team: \n" "MIME-Version: 1.0\n" @@ -15,11 +15,6 @@ msgstr "" "Content-Transfer-Encoding: \n" "Plural-Forms: \n" -#. module: intrastat_base -#: help:product.template,exclude_from_intrastat:0 -msgid "If set to True, the product or service will not be taken into account for Intrastat Product or Service reports. So you should leave this field to False unless you have a good reason. Exemple of good reason : 'Shipping' is a service that should probably be excluded from the Intrastat Service report." -msgstr "Si cette option est activée, le produit ou le service ne sera pas pris en compte pour les rapports de DEB et de DES. Sauf si vous avez une bonne raison, il faut donc laisser cette option désactivée. Exemple de bonne raison : 'Frais de port' est un service qui devrait a priori être exclu de la DES." - #. module: intrastat_base #: model:ir.ui.menu,name:intrastat_base.menu_intrastat_base_root msgid "Intrastat reporting" @@ -40,6 +35,7 @@ msgstr "Erreur: l'UdM par défaut et l'UdM d'achat doivent appartenir à la mêm #: code:addons/intrastat_base/intrastat_common.py:70 #: code:addons/intrastat_base/intrastat_common.py:85 #: code:addons/intrastat_base/intrastat_common.py:93 +#: code:addons/intrastat_base/product.py:41 #, python-format msgid "Error :" msgstr "Erreur :" @@ -95,20 +91,30 @@ msgstr "This module contains the common functions for 2 other modules :\n" msgid "The name of the country must be unique !" msgstr "Le nom du pays doit être unique !" +#. module: intrastat_base +#: constraint:product.template:0 +msgid "Error msg is in raise" +msgstr "Error msg is in raise" + #. module: intrastat_base #: help:account.tax,exclude_from_intrastat_if_present:0 msgid "If this tax is present on an invoice line, this invoice line will be skipped when generating Intrastat Product or Service lines from invoices." msgstr "Si cette taxe est présente sur une ligne de facture, cette ligne de facture ne sera pas prise en compte lors de la génération de la DEB et de la DES depuis les factures." +#. module: intrastat_base +#: field:product.template,is_accessory_cost:0 +msgid "Is accessory cost" +msgstr "Frais accessoires" + #. module: intrastat_base #: field:res.country,intrastat:0 msgid "Intrastat country" msgstr "Pays intrastat" #. module: intrastat_base -#: model:ir.model,name:intrastat_base.model_report_intrastat_common -msgid "Common functions for intrastat reports for products and services" -msgstr "Common functions for intrastat reports for products and services" +#: help:product.template,exclude_from_intrastat:0 +msgid "If set to True, the product or service will not be taken into account for Intrastat Product or Service reports. So you should leave this field to False unless you have a very good reason." +msgstr "Si l'option est activée, le produit ou service ne sera pris en compte ni pour la DEB ni pour la DES. Cette option doit donc rester désactivée sauf si vous avez une très bonne raison." #. module: intrastat_base #: code:addons/intrastat_base/intrastat_common.py:64 @@ -122,6 +128,11 @@ msgstr "La monnaie de la société doit être 'EUR', mais est actuellement '%s'. msgid "The VAT number is not set for the partner '%s'." msgstr "Le numéro de TVA n'est pas renseigné pour le partenaire '%s'." +#. module: intrastat_base +#: model:ir.model,name:intrastat_base.model_report_intrastat_common +msgid "Common functions for intrastat reports for products and services" +msgstr "Common functions for intrastat reports for products and services" + #. module: intrastat_base #: model:ir.model,name:intrastat_base.model_res_country msgid "Country" @@ -142,10 +153,15 @@ msgstr "Module de base pour les rapports intrastat" msgid "Exclude from Intrastat reports" msgstr "Exclure de la DEB et de la DES" +#. module: intrastat_base +#: help:product.template,is_accessory_cost:0 +msgid "Activate this option for shipping costs, packaging costs and all services related to the sale of products. This option is used for Intrastat reports." +msgstr "Activez cette option pour les frais de port, les frais d'emballage et tous les services liés à la vente de produits physiques. Cette option est utilisée pour la DEB et la DES." + #. module: intrastat_base #: model:product.template,name:intrastat_base.shipping_costs_exclude_product_template msgid "Shipping costs" -msgstr "Shipping costs" +msgstr "Frais de port" #. module: intrastat_base #: code:addons/intrastat_base/intrastat_common.py:85 diff --git a/intrastat_base/i18n/intrastat_base.pot b/intrastat_base/i18n/intrastat_base.pot index 34dbc59..d7baf12 100644 --- a/intrastat_base/i18n/intrastat_base.pot +++ b/intrastat_base/i18n/intrastat_base.pot @@ -4,10 +4,10 @@ # msgid "" msgstr "" -"Project-Id-Version: OpenERP Server 6.0.3\n" +"Project-Id-Version: OpenERP Server 6.0.4\n" "Report-Msgid-Bugs-To: support@openerp.com\n" -"POT-Creation-Date: 2011-09-09 08:18+0000\n" -"PO-Revision-Date: 2011-09-09 08:18+0000\n" +"POT-Creation-Date: 2012-06-05 13:28+0000\n" +"PO-Revision-Date: 2012-06-05 13:28+0000\n" "Last-Translator: <>\n" "Language-Team: \n" "MIME-Version: 1.0\n" @@ -15,11 +15,6 @@ msgstr "" "Content-Transfer-Encoding: \n" "Plural-Forms: \n" -#. module: intrastat_base -#: help:product.template,exclude_from_intrastat:0 -msgid "If set to True, the product or service will not be taken into account for Intrastat Product or Service reports. So you should leave this field to False unless you have a good reason. Exemple of good reason : 'Shipping' is a service that should probably be excluded from the Intrastat Service report." -msgstr "" - #. module: intrastat_base #: model:ir.ui.menu,name:intrastat_base.menu_intrastat_base_root msgid "Intrastat reporting" @@ -40,6 +35,7 @@ msgstr "" #: code:addons/intrastat_base/intrastat_common.py:70 #: code:addons/intrastat_base/intrastat_common.py:85 #: code:addons/intrastat_base/intrastat_common.py:93 +#: code:addons/intrastat_base/product.py:41 #, python-format msgid "Error :" msgstr "" @@ -85,19 +81,29 @@ msgstr "" msgid "The name of the country must be unique !" msgstr "" +#. module: intrastat_base +#: constraint:product.template:0 +msgid "Error msg is in raise" +msgstr "" + #. module: intrastat_base #: help:account.tax,exclude_from_intrastat_if_present:0 msgid "If this tax is present on an invoice line, this invoice line will be skipped when generating Intrastat Product or Service lines from invoices." msgstr "" +#. module: intrastat_base +#: field:product.template,is_accessory_cost:0 +msgid "Is accessory cost" +msgstr "" + #. module: intrastat_base #: field:res.country,intrastat:0 msgid "Intrastat country" msgstr "" #. module: intrastat_base -#: model:ir.model,name:intrastat_base.model_report_intrastat_common -msgid "Common functions for intrastat reports for products and services" +#: help:product.template,exclude_from_intrastat:0 +msgid "If set to True, the product or service will not be taken into account for Intrastat Product or Service reports. So you should leave this field to False unless you have a very good reason." msgstr "" #. module: intrastat_base @@ -112,6 +118,11 @@ msgstr "" msgid "The VAT number is not set for the partner '%s'." msgstr "" +#. module: intrastat_base +#: model:ir.model,name:intrastat_base.model_report_intrastat_common +msgid "Common functions for intrastat reports for products and services" +msgstr "" + #. module: intrastat_base #: model:ir.model,name:intrastat_base.model_res_country msgid "Country" @@ -132,6 +143,11 @@ msgstr "" msgid "Exclude from Intrastat reports" msgstr "" +#. module: intrastat_base +#: help:product.template,is_accessory_cost:0 +msgid "Activate this option for shipping costs, packaging costs and all services related to the sale of products. This option is used for Intrastat reports." +msgstr "" + #. module: intrastat_base #: model:product.template,name:intrastat_base.shipping_costs_exclude_product_template msgid "Shipping costs" diff --git a/intrastat_base/product.py b/intrastat_base/product.py index 0f29a02..870919b 100644 --- a/intrastat_base/product.py +++ b/intrastat_base/product.py @@ -27,7 +27,7 @@ class product_template(osv.osv): _inherit = "product.template" _columns = { 'exclude_from_intrastat': fields.boolean('Exclude from Intrastat reports', help="If set to True, the product or service will not be taken into account for Intrastat Product or Service reports. So you should leave this field to False unless you have a very good reason."), - 'is_accessory_cost' : fields.boolean('Is accessory cost?', help='Activate this option for shipping costs, packaging costs and all services related to the sale of product. This option is used for Intrastat reports.'), + 'is_accessory_cost' : fields.boolean('Is accessory cost', help='Activate this option for shipping costs, packaging costs and all services related to the sale of products. This option is used for Intrastat reports.'), } _default = { From 958c7c9c59d455021fef0ad67b061fdc39f7fc5a Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Mon, 16 Jul 2012 11:41:39 +0200 Subject: [PATCH 016/103] Use the new logger API of OpenERP 6.1 Move the "EU fiscal representative" field in order to avoid the "compression" of the VAT field that made it too small. --- intrastat_base/intrastat_common.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/intrastat_base/intrastat_common.py b/intrastat_base/intrastat_common.py index 5cbf191..6d7e47b 100644 --- a/intrastat_base/intrastat_common.py +++ b/intrastat_base/intrastat_common.py @@ -79,11 +79,11 @@ class report_intrastat_common(osv.osv_memory): official_des_xml_schema = etree.XMLSchema(etree.fromstring(xsd)) try: official_des_xml_schema.assertValid(xml_root) except Exception, e: # if the validation of the XSD fails, we arrive here - import netsvc - logger = netsvc.Logger() - logger.notifyChannel('intrastat', netsvc.LOG_WARNING, "The XML file is invalid against the XML Schema Definition") - logger.notifyChannel('intrastat', netsvc.LOG_WARNING, xml_string) - logger.notifyChannel('intrastat', netsvc.LOG_WARNING, e) + import logging + _logger = logging.getLogger(__name__) + _logger.warning("The XML file is invalid against the XML Schema Definition") + _logger.warning(xml_string) + _logger.warning(e) raise osv.except_osv(_('Error :'), _('The generated XML file is not valid against the official XML Schema Definition. The generated XML file and the full error have been written in the server logs. Here is the error, which may give you an idea on the cause of the problem : %s.') % str(e)) return True From 99e294c4af9b07248d8e7c1d152262e340a399c5 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Tue, 17 Jul 2012 18:07:32 +0200 Subject: [PATCH 017/103] default -> defaults --- intrastat_base/product.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/intrastat_base/product.py b/intrastat_base/product.py index 870919b..c535a72 100644 --- a/intrastat_base/product.py +++ b/intrastat_base/product.py @@ -30,8 +30,8 @@ class product_template(osv.osv): 'is_accessory_cost' : fields.boolean('Is accessory cost', help='Activate this option for shipping costs, packaging costs and all services related to the sale of products. This option is used for Intrastat reports.'), } - _default = { - 'exclude_from_intrastat': lambda *a: False, + _defaults = { + 'exclude_from_intrastat': False, } From c93829bc1236a8d18c1033b35493e1f7ebc20fc3 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Tue, 27 Nov 2012 17:08:30 +0100 Subject: [PATCH 018/103] Code clean-up : - context is not passed in constraints - don't use lambda when not necessary --- intrastat_base/country.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intrastat_base/country.py b/intrastat_base/country.py index 5d2cb1d..f747194 100644 --- a/intrastat_base/country.py +++ b/intrastat_base/country.py @@ -27,7 +27,7 @@ class res_country(osv.osv): 'intrastat': fields.boolean('Intrastat country', help="Set as True for countries that must be selected in the intrastat reports, i.e. for all European Union countries other than your own country."), } _defaults = { - 'intrastat': lambda *a: False, + 'intrastat': False, } res_country() From 481001d4a6064c8a0eb970e530a2f612b7ad9bb7 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Tue, 23 Apr 2013 15:39:08 +0200 Subject: [PATCH 019/103] IMPORTANT CHANGE : - All EU countries should now be intrastat=True, including your own country - When generating lines for Intrastat Product/Service, all invoices for which country == Company's country are excluded --- intrastat_base/country_data.xml | 55 ++++++++++++++++-------------- intrastat_base/intrastat_common.py | 8 ++--- 2 files changed, 33 insertions(+), 30 deletions(-) diff --git a/intrastat_base/country_data.xml b/intrastat_base/country_data.xml index 228c0b4..04fb439 100644 --- a/intrastat_base/country_data.xml +++ b/intrastat_base/country_data.xml @@ -2,83 +2,86 @@ + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/intrastat_base/intrastat_common.py b/intrastat_base/intrastat_common.py index 6d7e47b..8320b8a 100644 --- a/intrastat_base/intrastat_common.py +++ b/intrastat_base/intrastat_common.py @@ -60,10 +60,10 @@ class report_intrastat_common(osv.osv_memory): def _check_generate_lines(self, cr, uid, intrastat, context=None): - if not intrastat.company_id.currency_id.code: - raise osv.except_osv(_('Error :'), _("The currency code is not set on the currency '%s'.") %intrastat.company_id.currency_id.name) - if not intrastat.currency_id.code == 'EUR': - raise osv.except_osv(_('Error :'), _("The company currency must be 'EUR', but is currently '%s'.") %intrastat.currency_id.code) + if not intrastat.company_id.country_id: + raise osv.except_osv(_('Error :'), _("The country is not set on the company '%s'.") %intrastat.company_id.name) + if not intrastat.currency_id.name == 'EUR': + raise osv.except_osv(_('Error :'), _("The company currency must be 'EUR', but is currently '%s'.") %intrastat.currency_id.name) return True From f80e49e8da7160fe9c732acaa64934f8044eb45d Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Tue, 23 Apr 2013 16:08:58 +0200 Subject: [PATCH 020/103] Update help message according to my change of commit 61. Fix copyright header. --- intrastat_base/country.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/intrastat_base/country.py b/intrastat_base/country.py index f747194..2542d72 100644 --- a/intrastat_base/country.py +++ b/intrastat_base/country.py @@ -1,8 +1,9 @@ # -*- encoding: utf-8 -*- ############################################################################## # -# OpenERP, Open Source Management Solution -# Copyright (C) 2004-2009 Tiny SPRL (http://tiny.be). All Rights Reserved +# Report intrastat base module for OpenERP +# Copyright (C) 2011-2013 Akretion (http://www.akretion.com). All Rights Reserved +# @author Alexis de Lattre # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -24,8 +25,9 @@ from osv import osv, fields class res_country(osv.osv): _inherit = 'res.country' _columns = { - 'intrastat': fields.boolean('Intrastat country', help="Set as True for countries that must be selected in the intrastat reports, i.e. for all European Union countries other than your own country."), + 'intrastat': fields.boolean('EU country', help="Set to True for all European Union countries."), } + _defaults = { 'intrastat': False, } From 06630f9f090f2c93ba5dc5cf3995885d3fc209c8 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Wed, 24 Apr 2013 10:55:14 +0200 Subject: [PATCH 021/103] Initial port to v7.0. Not tested a lot for the moment. --- intrastat_base/__init__.py | 4 +-- intrastat_base/__openerp__.py | 7 ++-- intrastat_base/country.py | 4 +-- intrastat_base/country_view.xml | 4 +-- intrastat_base/intrastat_common.py | 10 +++--- intrastat_base/intrastat_demo.xml | 8 ++--- intrastat_base/intrastat_menu.xml | 2 +- .../{partner_address.py => partner.py} | 13 ++++---- intrastat_base/product.py | 8 ++--- intrastat_base/product_view.xml | 32 +++++++------------ intrastat_base/tax.py | 6 ++-- intrastat_base/tax_view.xml | 4 +-- 12 files changed, 46 insertions(+), 56 deletions(-) rename intrastat_base/{partner_address.py => partner.py} (77%) diff --git a/intrastat_base/__init__.py b/intrastat_base/__init__.py index 13ca149..c08cbac 100644 --- a/intrastat_base/__init__.py +++ b/intrastat_base/__init__.py @@ -2,7 +2,7 @@ ############################################################################## # # Report intrastat base module for OpenERP -# Copyright (C) 2011 Akretion (http://www.akretion.com). All Rights Reserved +# Copyright (C) 2011-2013 Akretion (http://www.akretion.com) # @author Alexis de Lattre # # This program is free software: you can redistribute it and/or modify @@ -23,6 +23,6 @@ import country import product import tax -import partner_address +import partner import intrastat_common diff --git a/intrastat_base/__openerp__.py b/intrastat_base/__openerp__.py index 089173a..a817d0d 100644 --- a/intrastat_base/__openerp__.py +++ b/intrastat_base/__openerp__.py @@ -2,7 +2,7 @@ ############################################################################## # # Report intrastat base module for OpenERP -# Copyright (C) 2011 Akretion (http://www.akretion.com). All Rights Reserved +# Copyright (C) 2011-2013 Akretion (http://www.akretion.com) # @author Alexis de Lattre # # This program is free software: you can redistribute it and/or modify @@ -22,14 +22,15 @@ { - 'name': 'Base module for Intrastat reporting', + 'name': 'Intrastat Reporting Base', 'version': '1.1', 'category': 'Localisation/Report Intrastat', 'license': 'AGPL-3', + 'summary': 'Base module for Intrastat reporting', 'description': """This module contains the common functions for 2 other modules : - l10n_fr_intrastat_service : the module for the "Déclaration Européenne des Services" (DES) - l10n_fr_intrastat_product : the module for the "Déclaration d'Echange de Biens" (DEB) -This module is not usefull if it's not used together with one of those 2 modules. +This module is not usefull if it's not used together with one of those 2 modules or other country-specific intrastat modules. This module doesn't have any France-specific stuff. So it can be used as a basis for other intrastat modules for other EU countries. diff --git a/intrastat_base/country.py b/intrastat_base/country.py index 2542d72..38ae403 100644 --- a/intrastat_base/country.py +++ b/intrastat_base/country.py @@ -20,9 +20,9 @@ # ############################################################################## -from osv import osv, fields +from openerp.osv import osv, fields -class res_country(osv.osv): +class res_country(osv.Model): _inherit = 'res.country' _columns = { 'intrastat': fields.boolean('EU country', help="Set to True for all European Union countries."), diff --git a/intrastat_base/country_view.xml b/intrastat_base/country_view.xml index bf62fa3..87e7ec9 100644 --- a/intrastat_base/country_view.xml +++ b/intrastat_base/country_view.xml @@ -1,7 +1,7 @@ @@ -26,7 +26,7 @@ - + diff --git a/intrastat_base/intrastat_common.py b/intrastat_base/intrastat_common.py index 8320b8a..622d3d2 100644 --- a/intrastat_base/intrastat_common.py +++ b/intrastat_base/intrastat_common.py @@ -2,7 +2,7 @@ ############################################################################## # # Report intrastat base module for OpenERP -# Copyright (C) 2010-2011 Akretion (http://www.akretion.com/). All rights reserved. +# Copyright (C) 2010-2013 Akretion (http://www.akretion.com/). All rights reserved. # @author Alexis de Lattre # # This program is free software: you can redistribute it and/or modify @@ -20,12 +20,12 @@ # ############################################################################## -from osv import osv, fields +from openerp.osv import osv +from openerp.tools.translate import _ from datetime import datetime from dateutil.relativedelta import relativedelta -from tools.translate import _ -class report_intrastat_common(osv.osv_memory): +class report_intrastat_common(osv.TransientModel): _name = "report.intrastat.common" _description = "Common functions for intrastat reports for products and services" @@ -115,7 +115,7 @@ class report_intrastat_common(osv.osv_memory): 'type': 'ir.actions.act_window', 'nodestroy': True, 'target': 'current', - 'res_id': [attach_id], + 'res_id': attach_id, } return action diff --git a/intrastat_base/intrastat_demo.xml b/intrastat_base/intrastat_demo.xml index d83640e..07c68ab 100644 --- a/intrastat_base/intrastat_demo.xml +++ b/intrastat_base/intrastat_demo.xml @@ -1,7 +1,7 @@ @@ -13,7 +13,7 @@ FR58441019213 - + BE0828696437 True @@ -23,7 +23,7 @@ True - + BE0884025633 True @@ -48,7 +48,7 @@ Shipping costs SHIP service - + 30 True diff --git a/intrastat_base/intrastat_menu.xml b/intrastat_base/intrastat_menu.xml index b078c6a..83434cb 100644 --- a/intrastat_base/intrastat_menu.xml +++ b/intrastat_base/intrastat_menu.xml @@ -1,7 +1,7 @@ diff --git a/intrastat_base/partner_address.py b/intrastat_base/partner.py similarity index 77% rename from intrastat_base/partner_address.py rename to intrastat_base/partner.py index f36329b..8ebe7ba 100644 --- a/intrastat_base/partner_address.py +++ b/intrastat_base/partner.py @@ -2,7 +2,7 @@ ############################################################################## # # Report intrastat base module for OpenERP -# Copyright (C) 2010-2011 Akretion (http://www.akretion.com/) All Rights Reserved +# Copyright (C) 2010-2013 Akretion (http://www.akretion.com/) # @author Alexis de Lattre # # This program is free software: you can redistribute it and/or modify @@ -20,16 +20,15 @@ # ############################################################################## -from osv import osv, fields +from openerp.osv import osv, fields -# We want to have the country field on res_partner_address always set +# We want to have the country field on res_partner always set # because the selection of invoices for intrastat reports is based -# on the country of the invoice partner address ! -class res_partner_address(osv.osv): - _inherit = 'res.partner.address' +# on the country of the invoice partner ! +class res_partner(osv.Model): + _inherit = 'res.partner' _columns = { 'country_id': fields.many2one('res.country', 'Country', required=True), } -res_partner_address() diff --git a/intrastat_base/product.py b/intrastat_base/product.py index c535a72..894dcbb 100644 --- a/intrastat_base/product.py +++ b/intrastat_base/product.py @@ -2,7 +2,7 @@ ############################################################################## # # Report intrastat base module for OpenERP -# Copyright (C) 2010-2012 Akretion (http://www.akretion.com/) All Rights Reserved +# Copyright (C) 2010-2013 Akretion (http://www.akretion.com/) # @author Alexis de Lattre # # This program is free software: you can redistribute it and/or modify @@ -20,10 +20,10 @@ # ############################################################################## -from osv import osv, fields -from tools.translate import _ +from openerp.osv import osv, fields +from openerp.tools.translate import _ -class product_template(osv.osv): +class product_template(osv.Model): _inherit = "product.template" _columns = { 'exclude_from_intrastat': fields.boolean('Exclude from Intrastat reports', help="If set to True, the product or service will not be taken into account for Intrastat Product or Service reports. So you should leave this field to False unless you have a very good reason."), diff --git a/intrastat_base/product_view.xml b/intrastat_base/product_view.xml index 28b026e..ba3d289 100644 --- a/intrastat_base/product_view.xml +++ b/intrastat_base/product_view.xml @@ -1,7 +1,7 @@ @@ -15,17 +15,12 @@ product.product - - - - - - - - + + + - - + + @@ -35,17 +30,12 @@ product.template - - - - - - - - + + + - - + + diff --git a/intrastat_base/tax.py b/intrastat_base/tax.py index 4d12d32..209c2b5 100644 --- a/intrastat_base/tax.py +++ b/intrastat_base/tax.py @@ -2,7 +2,7 @@ ############################################################################## # # Report intrastat base module for OpenERP -# Copyright (C) 2011 Akretion (http://www.akretion.com). All Rights Reserved +# Copyright (C) 2011-2013 Akretion (http://www.akretion.com). All Rights Reserved # @author Alexis de Lattre # # This program is free software: you can redistribute it and/or modify @@ -20,10 +20,10 @@ # ############################################################################## -from osv import osv, fields +from openerp.osv import osv, fields -class account_tax(osv.osv): +class account_tax(osv.Model): _inherit = "account.tax" _columns = { 'exclude_from_intrastat_if_present': fields.boolean('Exclude invoice line from intrastat if this tax is present', help="If this tax is present on an invoice line, this invoice line will be skipped when generating Intrastat Product or Service lines from invoices."), diff --git a/intrastat_base/tax_view.xml b/intrastat_base/tax_view.xml index e60a327..c481490 100644 --- a/intrastat_base/tax_view.xml +++ b/intrastat_base/tax_view.xml @@ -17,8 +17,8 @@ - - + + From 91ebde5768180425dbd0ad1eae35983002adefad Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Mon, 3 Jun 2013 23:17:36 +0200 Subject: [PATCH 022/103] Should now be compatible with both OCB and RS-OCB Add field import_obligation_level on res.company Add group group_detailed_intrastat_product, so that companies that only use obligation = simplified don't see all the additionnal fields. Remove transaction code corresponding to repairs in intrastat types Better on_change on intrastat types (code is mutualised with field.function) Update syntax : demo_xml/update_xml/init_xml -> data/demo --- intrastat_base/__openerp__.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/intrastat_base/__openerp__.py b/intrastat_base/__openerp__.py index a817d0d..058b764 100644 --- a/intrastat_base/__openerp__.py +++ b/intrastat_base/__openerp__.py @@ -41,15 +41,14 @@ Please contact Alexis de Lattre from Akretion for 'author': 'Akretion', 'website': 'http://www.akretion.com', 'depends': ['base_vat'], - 'init_xml': ['country_data.xml'], - 'update_xml': [ - 'security/ir.model.access.csv', + 'data': [ + 'country_data.xml', 'product_view.xml', 'country_view.xml', 'tax_view.xml', 'intrastat_menu.xml', ], - 'demo_xml': ['intrastat_demo.xml'], + 'demo': ['intrastat_demo.xml'], 'installable': True, 'active': False, } From 913b208738d14fdc76784c3885daec37fbdb562c Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Mon, 1 Jul 2013 18:42:53 +0200 Subject: [PATCH 023/103] Welcome to Croatia in the European Union ! --- intrastat_base/country_data.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/intrastat_base/country_data.xml b/intrastat_base/country_data.xml index 04fb439..c77f548 100644 --- a/intrastat_base/country_data.xml +++ b/intrastat_base/country_data.xml @@ -83,5 +83,8 @@ + + + From 6c390713c8e912040525dbd2ecd22719940b26b4 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Mon, 26 Aug 2013 11:07:40 +0200 Subject: [PATCH 024/103] Add an e-mail reminder for l10n_fr_intrastat_product and l10n_fr_intrastat_service (hope that Akretion France won't forget it's own declarations now !!!) On report.intrastat.product and report.intrastat.service : add copy() fonctions, tracking of important fields, a year_month function field and enhance views. Remove date_done field (the tracking in the chatter does the job). Remove class instanciation in the code. --- intrastat_base/__init__.py | 1 + intrastat_base/__openerp__.py | 1 + intrastat_base/company.py | 61 ++++++++++++++++++++++++++++++ intrastat_base/company_view.xml | 29 ++++++++++++++ intrastat_base/country.py | 1 - intrastat_base/intrastat_common.py | 24 ++++++++++-- intrastat_base/product.py | 2 - intrastat_base/tax.py | 2 - 8 files changed, 113 insertions(+), 8 deletions(-) create mode 100644 intrastat_base/company.py create mode 100644 intrastat_base/company_view.xml diff --git a/intrastat_base/__init__.py b/intrastat_base/__init__.py index c08cbac..f2258f6 100644 --- a/intrastat_base/__init__.py +++ b/intrastat_base/__init__.py @@ -24,5 +24,6 @@ import country import product import tax import partner +import company import intrastat_common diff --git a/intrastat_base/__openerp__.py b/intrastat_base/__openerp__.py index 058b764..973786b 100644 --- a/intrastat_base/__openerp__.py +++ b/intrastat_base/__openerp__.py @@ -46,6 +46,7 @@ Please contact Alexis de Lattre from Akretion for 'product_view.xml', 'country_view.xml', 'tax_view.xml', + 'company_view.xml', 'intrastat_menu.xml', ], 'demo': ['intrastat_demo.xml'], diff --git a/intrastat_base/company.py b/intrastat_base/company.py new file mode 100644 index 0000000..4fc63cb --- /dev/null +++ b/intrastat_base/company.py @@ -0,0 +1,61 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Intrastat base module for OpenERP +# Copyright (C) 2013 Akretion (http://www.akretion.com) +# @author Alexis de Lattre +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp.osv import osv, orm, fields +from openerp.tools.translate import _ + +class res_company(osv.Model): + _inherit = "res.company" + + def _compute_intrastat_email_list(self, cr, uid, ids, name, arg, context=None): + result = {} + for company in self.browse(cr, uid, ids, context=context): + result[company.id] = '' + for user in company.intrastat_remind_user_ids: + if result[company.id]: + result[company.id] += ',%s' % (user.email) + else: + result[company.id] = user.email + return result + + _columns = { + 'intrastat_remind_user_ids': fields.many2many('res.users', + id1='company_id', id2='user_id', + string="Users Receiving the Intrastat Reminder", + help="List of OpenERP users who will receive a notification to remind them about the Intrastat declaration."), + 'intrastat_email_list': fields.function(_compute_intrastat_email_list, + type='char', size=1000, + string='List of emails of Users Receiving the Intrastat Reminder', + help='Comma-separated list of email addresses of Users Receiving the Intrastat Reminder. For use in the email template.'), + } + + + def _check_intrastat_remind_users(self, cr, uid, ids): + for company in self.browse(cr, uid, ids): + for user in company.intrastat_remind_user_ids: + if not user.email: + raise orm.except_orm(_('Error :'), _("Missing e-mail address on user '%s'.") %(user.name)) + return True + + _constraints = [ + (_check_intrastat_remind_users, "error msg in raise", ['intrastat_remind_user_ids']), + ] diff --git a/intrastat_base/company_view.xml b/intrastat_base/company_view.xml new file mode 100644 index 0000000..14cf1fe --- /dev/null +++ b/intrastat_base/company_view.xml @@ -0,0 +1,29 @@ + + + + + + + + + intrastat.company.form + res.company + + + + + + + + + + + + + + + diff --git a/intrastat_base/country.py b/intrastat_base/country.py index 38ae403..3315476 100644 --- a/intrastat_base/country.py +++ b/intrastat_base/country.py @@ -32,4 +32,3 @@ class res_country(osv.Model): 'intrastat': False, } -res_country() diff --git a/intrastat_base/intrastat_common.py b/intrastat_base/intrastat_common.py index 622d3d2..fba3a08 100644 --- a/intrastat_base/intrastat_common.py +++ b/intrastat_base/intrastat_common.py @@ -24,6 +24,10 @@ from openerp.osv import osv from openerp.tools.translate import _ from datetime import datetime from dateutil.relativedelta import relativedelta +import logging + +logger = logging.getLogger(__name__) + class report_intrastat_common(osv.TransientModel): _name = "report.intrastat.common" @@ -41,12 +45,15 @@ class report_intrastat_common(osv.TransientModel): return result - def _compute_end_date(self, cr, uid, ids, object, context=None): + def _compute_dates(self, cr, uid, ids, object, context=None): result = {} for intrastat in object.browse(cr, uid, ids, context=context): start_date_datetime = datetime.strptime(intrastat.start_date, '%Y-%m-%d') end_date_str = datetime.strftime(start_date_datetime + relativedelta(day=31), '%Y-%m-%d') - result[intrastat.id] = end_date_str + result[intrastat.id] = { + 'end_date': end_date_str, + 'year_month': start_date_datetime.strftime('%Y-%m'), + } return result @@ -128,5 +135,16 @@ class report_intrastat_common(osv.TransientModel): result['value'].update({'partner_vat': company['vat']}) return result -report_intrastat_common() + def send_reminder_email(self, cr, uid, company, module_name, template_xmlid, intrastat_id, context=None): + template_data = self.pool['ir.model.data'].get_object_reference(cr, uid, module_name, template_xmlid) + if template_data and template_data[0] == 'email.template': + template_id = template_data[1] + else: + raise + if company.intrastat_remind_user_ids: + self.pool['email.template'].send_mail(cr, uid, template_id, intrastat_id, context=context) + logger.info('Intrastat Reminder email has been sent (XMLID: %s).' % template_xmlid) + else: + logger.warning('The list of users receiving the Intrastat Reminder is empty on company %s' % company.name) + return True diff --git a/intrastat_base/product.py b/intrastat_base/product.py index 894dcbb..640f9ea 100644 --- a/intrastat_base/product.py +++ b/intrastat_base/product.py @@ -45,5 +45,3 @@ class product_template(osv.Model): (_check_accessory_cost, "Error msg is in raise", ['is_accessory_cost', 'type']) ] -product_template() - diff --git a/intrastat_base/tax.py b/intrastat_base/tax.py index 209c2b5..5d37d1b 100644 --- a/intrastat_base/tax.py +++ b/intrastat_base/tax.py @@ -29,5 +29,3 @@ class account_tax(osv.Model): 'exclude_from_intrastat_if_present': fields.boolean('Exclude invoice line from intrastat if this tax is present', help="If this tax is present on an invoice line, this invoice line will be skipped when generating Intrastat Product or Service lines from invoices."), } -account_tax() - From 78298b3356fb782af8e24ae64f2bc1eed13f2a26 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Mon, 26 Aug 2013 14:52:04 +0200 Subject: [PATCH 025/103] Better form view of product category, courtesy of David Beal. --- intrastat_base/product_view.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/intrastat_base/product_view.xml b/intrastat_base/product_view.xml index ba3d289..fd7c2d4 100644 --- a/intrastat_base/product_view.xml +++ b/intrastat_base/product_view.xml @@ -16,7 +16,7 @@ - + @@ -31,7 +31,7 @@ - + From 8382ecb5f9557fb81459b8a64381fab45ef84cf6 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Mon, 26 Aug 2013 23:21:23 +0200 Subject: [PATCH 026/103] Raise an explicit exception (take into account Stefan remark on the merge proposal) --- intrastat_base/intrastat_common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intrastat_base/intrastat_common.py b/intrastat_base/intrastat_common.py index fba3a08..ba7060b 100644 --- a/intrastat_base/intrastat_common.py +++ b/intrastat_base/intrastat_common.py @@ -141,7 +141,7 @@ class report_intrastat_common(osv.TransientModel): if template_data and template_data[0] == 'email.template': template_id = template_data[1] else: - raise + raise osv.except_osv(_('Error :'), _("Wrong model for XMLID '%s.%s': model is '%s' and it should be 'email.template'.") %(module_name, template_xmlid, template_data[0])) if company.intrastat_remind_user_ids: self.pool['email.template'].send_mail(cr, uid, template_id, intrastat_id, context=context) logger.info('Intrastat Reminder email has been sent (XMLID: %s).' % template_xmlid) From 3f6cddd3ed068b5107872fb96b99e9d6ccc0b4c4 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Wed, 23 Oct 2013 23:23:35 +0200 Subject: [PATCH 027/103] Fix to make the module truly usable when user is not part of the group "Detailed intrastat product". Remove dead code and fields that was used when we had to put DEB lines for repair operations (a thing of the past !). Update coding style. Reduce the number of flake8 warnings. --- intrastat_base/__init__.py | 13 ++++++------ intrastat_base/company.py | 11 +++++----- intrastat_base/country.py | 6 +++--- intrastat_base/intrastat_common.py | 32 ++++++++++-------------------- intrastat_base/partner.py | 7 +++---- intrastat_base/product.py | 14 ++++++------- intrastat_base/tax.py | 5 ++--- 7 files changed, 38 insertions(+), 50 deletions(-) diff --git a/intrastat_base/__init__.py b/intrastat_base/__init__.py index f2258f6..8e2eaa0 100644 --- a/intrastat_base/__init__.py +++ b/intrastat_base/__init__.py @@ -20,10 +20,9 @@ # ############################################################################## -import country -import product -import tax -import partner -import company -import intrastat_common - +from . import country +from . import product +from . import tax +from . import partner +from . import company +from . import intrastat_common diff --git a/intrastat_base/company.py b/intrastat_base/company.py index 4fc63cb..69163f5 100644 --- a/intrastat_base/company.py +++ b/intrastat_base/company.py @@ -20,10 +20,11 @@ # ############################################################################## -from openerp.osv import osv, orm, fields +from openerp.osv import orm, fields from openerp.tools.translate import _ -class res_company(osv.Model): + +class res_company(orm.Model): _inherit = "res.company" def _compute_intrastat_email_list(self, cr, uid, ids, name, arg, context=None): @@ -48,14 +49,14 @@ class res_company(osv.Model): help='Comma-separated list of email addresses of Users Receiving the Intrastat Reminder. For use in the email template.'), } - def _check_intrastat_remind_users(self, cr, uid, ids): for company in self.browse(cr, uid, ids): for user in company.intrastat_remind_user_ids: if not user.email: - raise orm.except_orm(_('Error :'), _("Missing e-mail address on user '%s'.") %(user.name)) + raise orm.except_orm(_('Error :'), _("Missing e-mail address on user '%s'.") % (user.name)) return True _constraints = [ - (_check_intrastat_remind_users, "error msg in raise", ['intrastat_remind_user_ids']), + (_check_intrastat_remind_users, "error msg in raise", + ['intrastat_remind_user_ids']), ] diff --git a/intrastat_base/country.py b/intrastat_base/country.py index 3315476..2cb923f 100644 --- a/intrastat_base/country.py +++ b/intrastat_base/country.py @@ -20,9 +20,10 @@ # ############################################################################## -from openerp.osv import osv, fields +from openerp.osv import orm, fields -class res_country(osv.Model): + +class res_country(orm.Model): _inherit = 'res.country' _columns = { 'intrastat': fields.boolean('EU country', help="Set to True for all European Union countries."), @@ -31,4 +32,3 @@ class res_country(osv.Model): _defaults = { 'intrastat': False, } - diff --git a/intrastat_base/intrastat_common.py b/intrastat_base/intrastat_common.py index ba7060b..681f03a 100644 --- a/intrastat_base/intrastat_common.py +++ b/intrastat_base/intrastat_common.py @@ -20,7 +20,7 @@ # ############################################################################## -from openerp.osv import osv +from openerp.osv import orm from openerp.tools.translate import _ from datetime import datetime from dateutil.relativedelta import relativedelta @@ -29,7 +29,7 @@ import logging logger = logging.getLogger(__name__) -class report_intrastat_common(osv.TransientModel): +class report_intrastat_common(orm.TransientModel): _name = "report.intrastat.common" _description = "Common functions for intrastat reports for products and services" @@ -44,7 +44,6 @@ class report_intrastat_common(osv.TransientModel): result[intrastat.id] = {'num_lines': num_lines, 'total_amount': total_amount} return result - def _compute_dates(self, cr, uid, ids, object, context=None): result = {} for intrastat in object.browse(cr, uid, ids, context=context): @@ -56,7 +55,6 @@ class report_intrastat_common(osv.TransientModel): } return result - def _check_start_date(self, cr, uid, ids, object, context=None): '''Check that the start date is the first day of the month''' for date_to_check in object.read(cr, uid, ids, ['start_date'], context=context): @@ -65,54 +63,48 @@ class report_intrastat_common(osv.TransientModel): return False return True - def _check_generate_lines(self, cr, uid, intrastat, context=None): if not intrastat.company_id.country_id: - raise osv.except_osv(_('Error :'), _("The country is not set on the company '%s'.") %intrastat.company_id.name) + raise orm.except_orm(_('Error :'), _("The country is not set on the company '%s'.") % intrastat.company_id.name) if not intrastat.currency_id.name == 'EUR': - raise osv.except_osv(_('Error :'), _("The company currency must be 'EUR', but is currently '%s'.") %intrastat.currency_id.name) + raise orm.except_orm(_('Error :'), _("The company currency must be 'EUR', but is currently '%s'.") % intrastat.currency_id.name) return True - def _check_generate_xml(self, cr, uid, intrastat, context=None): if not intrastat.company_id.partner_id.vat: - raise osv.except_osv(_('Error :'), _("The VAT number is not set for the partner '%s'.") %intrastat.company_id.partner_id.name) + raise orm.except_orm(_('Error :'), _("The VAT number is not set for the partner '%s'.") % intrastat.company_id.partner_id.name) return True - def _check_xml_schema(self, cr, uid, xml_root, xml_string, xsd, context=None): '''Validate the XML file against the XSD''' from lxml import etree official_des_xml_schema = etree.XMLSchema(etree.fromstring(xsd)) - try: official_des_xml_schema.assertValid(xml_root) + try: + official_des_xml_schema.assertValid(xml_root) except Exception, e: # if the validation of the XSD fails, we arrive here import logging _logger = logging.getLogger(__name__) _logger.warning("The XML file is invalid against the XML Schema Definition") _logger.warning(xml_string) _logger.warning(e) - raise osv.except_osv(_('Error :'), _('The generated XML file is not valid against the official XML Schema Definition. The generated XML file and the full error have been written in the server logs. Here is the error, which may give you an idea on the cause of the problem : %s.') % str(e)) + raise orm.except_orm(_('Error :'), _('The generated XML file is not valid against the official XML Schema Definition. The generated XML file and the full error have been written in the server logs. Here is the error, which may give you an idea on the cause of the problem : %s.') % str(e)) return True - def _attach_xml_file(self, cr, uid, ids, object, xml_string, start_date_datetime, declaration_name, context=None): '''Attach the XML file to the report_intrastat_product/service object''' import base64 - if len(ids) != 1: - raise osv.except_osv(_('Error :'), 'Hara kiri in attach_xml_file') + assert len(ids) == 1, "Only one ID accepted" filename = datetime.strftime(start_date_datetime, '%Y-%m') + '_' + declaration_name + '.xml' attach_name = declaration_name.upper() + ' ' + datetime.strftime(start_date_datetime, '%Y-%m') attach_obj = self.pool.get('ir.attachment') if not context: context = {} - context.update({'default_res_id' : ids[0], 'default_res_model': object._name}) + context.update({'default_res_id': ids[0], 'default_res_model': object._name}) attach_id = attach_obj.create(cr, uid, {'name': attach_name, 'datas': base64.encodestring(xml_string), 'datas_fname': filename}, context=context) return attach_id - def _open_attach_view(self, cr, uid, attach_id, title='XML file', context=None): '''Returns an action which opens the form view of the corresponding attachement''' - # Only works in v6 -> not used in v5 action = { 'name': title, 'view_type': 'form', @@ -126,7 +118,6 @@ class report_intrastat_common(osv.TransientModel): } return action - def partner_on_change(self, cr, uid, ids, partner_id=False): result = {} result['value'] = {} @@ -135,13 +126,12 @@ class report_intrastat_common(osv.TransientModel): result['value'].update({'partner_vat': company['vat']}) return result - def send_reminder_email(self, cr, uid, company, module_name, template_xmlid, intrastat_id, context=None): template_data = self.pool['ir.model.data'].get_object_reference(cr, uid, module_name, template_xmlid) if template_data and template_data[0] == 'email.template': template_id = template_data[1] else: - raise osv.except_osv(_('Error :'), _("Wrong model for XMLID '%s.%s': model is '%s' and it should be 'email.template'.") %(module_name, template_xmlid, template_data[0])) + raise orm.except_orm(_('Error :'), _("Wrong model for XMLID '%s.%s': model is '%s' and it should be 'email.template'.") % (module_name, template_xmlid, template_data[0])) if company.intrastat_remind_user_ids: self.pool['email.template'].send_mail(cr, uid, template_id, intrastat_id, context=context) logger.info('Intrastat Reminder email has been sent (XMLID: %s).' % template_xmlid) diff --git a/intrastat_base/partner.py b/intrastat_base/partner.py index 8ebe7ba..a87c0ed 100644 --- a/intrastat_base/partner.py +++ b/intrastat_base/partner.py @@ -20,15 +20,14 @@ # ############################################################################## -from openerp.osv import osv, fields +from openerp.osv import orm, fields + # We want to have the country field on res_partner always set # because the selection of invoices for intrastat reports is based # on the country of the invoice partner ! -class res_partner(osv.Model): +class res_partner(orm.Model): _inherit = 'res.partner' _columns = { 'country_id': fields.many2one('res.country', 'Country', required=True), } - - diff --git a/intrastat_base/product.py b/intrastat_base/product.py index 640f9ea..60132f0 100644 --- a/intrastat_base/product.py +++ b/intrastat_base/product.py @@ -20,28 +20,28 @@ # ############################################################################## -from openerp.osv import osv, fields +from openerp.osv import orm, fields from openerp.tools.translate import _ -class product_template(osv.Model): + +class product_template(orm.Model): _inherit = "product.template" _columns = { 'exclude_from_intrastat': fields.boolean('Exclude from Intrastat reports', help="If set to True, the product or service will not be taken into account for Intrastat Product or Service reports. So you should leave this field to False unless you have a very good reason."), - 'is_accessory_cost' : fields.boolean('Is accessory cost', help='Activate this option for shipping costs, packaging costs and all services related to the sale of products. This option is used for Intrastat reports.'), + 'is_accessory_cost': fields.boolean('Is accessory cost', help='Activate this option for shipping costs, packaging costs and all services related to the sale of products. This option is used for Intrastat reports.'), } _defaults = { 'exclude_from_intrastat': False, } - def _check_accessory_cost(self, cr, uid, ids): for product in self.browse(cr, uid, ids): if product.is_accessory_cost and product.type != 'service': - raise osv.except_osv(_('Error :'), _("The option 'Is accessory cost?' should only be activated on 'Service' products. You have activated this option for the product '%s' which is of type '%s'" % (product.name, product.type))) + raise orm.except_orm(_('Error :'), _("The option 'Is accessory cost?' should only be activated on 'Service' products. You have activated this option for the product '%s' which is of type '%s'" % (product.name, product.type))) return True _constraints = [ - (_check_accessory_cost, "Error msg is in raise", ['is_accessory_cost', 'type']) + (_check_accessory_cost, "Error msg is in raise", + ['is_accessory_cost', 'type']) ] - diff --git a/intrastat_base/tax.py b/intrastat_base/tax.py index 5d37d1b..5e933d1 100644 --- a/intrastat_base/tax.py +++ b/intrastat_base/tax.py @@ -20,12 +20,11 @@ # ############################################################################## -from openerp.osv import osv, fields +from openerp.osv import orm, fields -class account_tax(osv.Model): +class account_tax(orm.Model): _inherit = "account.tax" _columns = { 'exclude_from_intrastat_if_present': fields.boolean('Exclude invoice line from intrastat if this tax is present', help="If this tax is present on an invoice line, this invoice line will be skipped when generating Intrastat Product or Service lines from invoices."), } - From 2335aecfda94502748bb2a3f0c4e1adf6857e824 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Mon, 9 Dec 2013 14:34:10 +0100 Subject: [PATCH 028/103] On OpenERP 7, when you have the document module installed and you download the attachement via the drop down list on the form view, the name of the file will be the name of the attachement and not datas_fname ; so we need to have name = datas_fname. --- intrastat_base/intrastat_common.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/intrastat_base/intrastat_common.py b/intrastat_base/intrastat_common.py index 681f03a..7a21a62 100644 --- a/intrastat_base/intrastat_common.py +++ b/intrastat_base/intrastat_common.py @@ -95,12 +95,11 @@ class report_intrastat_common(orm.TransientModel): import base64 assert len(ids) == 1, "Only one ID accepted" filename = datetime.strftime(start_date_datetime, '%Y-%m') + '_' + declaration_name + '.xml' - attach_name = declaration_name.upper() + ' ' + datetime.strftime(start_date_datetime, '%Y-%m') attach_obj = self.pool.get('ir.attachment') if not context: context = {} context.update({'default_res_id': ids[0], 'default_res_model': object._name}) - attach_id = attach_obj.create(cr, uid, {'name': attach_name, 'datas': base64.encodestring(xml_string), 'datas_fname': filename}, context=context) + attach_id = attach_obj.create(cr, uid, {'name': filename, 'datas': base64.encodestring(xml_string), 'datas_fname': filename}, context=context) return attach_id def _open_attach_view(self, cr, uid, attach_id, title='XML file', context=None): From b37adc8c76df877985cc932d514618d043f8c143 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20B=C3=A9al?= Date: Sun, 9 Mar 2014 09:29:59 +0100 Subject: [PATCH 029/103] switch required=True for country_id from model to views in res.partner --- intrastat_base/__init__.py | 1 - intrastat_base/__openerp__.py | 1 + intrastat_base/partner.py | 33 --------------------------------- intrastat_base/partner_view.xml | 31 +++++++++++++++++++++++++++++++ 4 files changed, 32 insertions(+), 34 deletions(-) delete mode 100644 intrastat_base/partner.py create mode 100644 intrastat_base/partner_view.xml diff --git a/intrastat_base/__init__.py b/intrastat_base/__init__.py index 8e2eaa0..3070e32 100644 --- a/intrastat_base/__init__.py +++ b/intrastat_base/__init__.py @@ -23,6 +23,5 @@ from . import country from . import product from . import tax -from . import partner from . import company from . import intrastat_common diff --git a/intrastat_base/__openerp__.py b/intrastat_base/__openerp__.py index 973786b..9661bd8 100644 --- a/intrastat_base/__openerp__.py +++ b/intrastat_base/__openerp__.py @@ -44,6 +44,7 @@ Please contact Alexis de Lattre from Akretion for 'data': [ 'country_data.xml', 'product_view.xml', + 'partner_view.xml', 'country_view.xml', 'tax_view.xml', 'company_view.xml', diff --git a/intrastat_base/partner.py b/intrastat_base/partner.py deleted file mode 100644 index a87c0ed..0000000 --- a/intrastat_base/partner.py +++ /dev/null @@ -1,33 +0,0 @@ -# -*- encoding: utf-8 -*- -############################################################################## -# -# Report intrastat base module for OpenERP -# Copyright (C) 2010-2013 Akretion (http://www.akretion.com/) -# @author Alexis de Lattre -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - -from openerp.osv import orm, fields - - -# We want to have the country field on res_partner always set -# because the selection of invoices for intrastat reports is based -# on the country of the invoice partner ! -class res_partner(orm.Model): - _inherit = 'res.partner' - _columns = { - 'country_id': fields.many2one('res.country', 'Country', required=True), - } diff --git a/intrastat_base/partner_view.xml b/intrastat_base/partner_view.xml new file mode 100644 index 0000000..61f4104 --- /dev/null +++ b/intrastat_base/partner_view.xml @@ -0,0 +1,31 @@ + + + + + + + + + + res.partner + + + + {'readonly': [('use_parent_address','=',True)], 'required': True} + + + + {'required': True} + + + + + + + From f0c9742f44800d5a8f9a326213171470209b8b9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20B=C3=A9al?= Date: Mon, 10 Mar 2014 11:46:37 +0100 Subject: [PATCH 030/103] xpath in partner view as Niels Huylebroeck suggest --- intrastat_base/partner_view.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intrastat_base/partner_view.xml b/intrastat_base/partner_view.xml index 61f4104..4e6f840 100644 --- a/intrastat_base/partner_view.xml +++ b/intrastat_base/partner_view.xml @@ -19,7 +19,7 @@ {'readonly': [('use_parent_address','=',True)], 'required': True} - {'required': True} From b2520441a79802297e281ade8968738a82606289 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20B=C3=A9al?= Date: Mon, 10 Mar 2014 11:55:02 +0100 Subject: [PATCH 031/103] simplify first xpath too in partner view --- intrastat_base/partner_view.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intrastat_base/partner_view.xml b/intrastat_base/partner_view.xml index 4e6f840..981715b 100644 --- a/intrastat_base/partner_view.xml +++ b/intrastat_base/partner_view.xml @@ -14,7 +14,7 @@ res.partner - {'readonly': [('use_parent_address','=',True)], 'required': True} From 566b682c6cb348421acf9540d07a39cd980395a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20B=C3=A9al?= Date: Mon, 10 Mar 2014 19:31:48 +0100 Subject: [PATCH 032/103] xpath in a more generic way --- intrastat_base/partner_view.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/intrastat_base/partner_view.xml b/intrastat_base/partner_view.xml index 981715b..7dc9f4e 100644 --- a/intrastat_base/partner_view.xml +++ b/intrastat_base/partner_view.xml @@ -14,12 +14,12 @@ res.partner - {'readonly': [('use_parent_address','=',True)], 'required': True} - {'required': True} From bf37d0073421c1453aa5386502e20334bdebf360 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Mon, 14 Apr 2014 16:32:08 +0200 Subject: [PATCH 033/103] Use l10n_fr_* : use the method _company_default_get() intrastat_base : - the module is now PEP-8 compliant ! - add search view on countries - is_accessory_cost is now invisible when product != service - update POT file and FR translation - remove double import of logging lib --- intrastat_base/company.py | 22 +- intrastat_base/country.py | 6 +- intrastat_base/country_view.xml | 15 ++ intrastat_base/i18n/fr_FR.po | 269 +++++++++++++------------ intrastat_base/i18n/intrastat_base.pot | 245 ++++++++++++---------- intrastat_base/intrastat_common.py | 113 ++++++++--- intrastat_base/product.py | 21 +- intrastat_base/product_view.xml | 6 +- intrastat_base/tax.py | 9 +- 9 files changed, 418 insertions(+), 288 deletions(-) diff --git a/intrastat_base/company.py b/intrastat_base/company.py index 69163f5..030101f 100644 --- a/intrastat_base/company.py +++ b/intrastat_base/company.py @@ -27,7 +27,8 @@ from openerp.tools.translate import _ class res_company(orm.Model): _inherit = "res.company" - def _compute_intrastat_email_list(self, cr, uid, ids, name, arg, context=None): + def _compute_intrastat_email_list( + self, cr, uid, ids, name, arg, context=None): result = {} for company in self.browse(cr, uid, ids, context=context): result[company.id] = '' @@ -39,21 +40,24 @@ class res_company(orm.Model): return result _columns = { - 'intrastat_remind_user_ids': fields.many2many('res.users', - id1='company_id', id2='user_id', + 'intrastat_remind_user_ids': fields.many2many( + 'res.users', id1='company_id', id2='user_id', string="Users Receiving the Intrastat Reminder", - help="List of OpenERP users who will receive a notification to remind them about the Intrastat declaration."), - 'intrastat_email_list': fields.function(_compute_intrastat_email_list, - type='char', size=1000, - string='List of emails of Users Receiving the Intrastat Reminder', - help='Comma-separated list of email addresses of Users Receiving the Intrastat Reminder. For use in the email template.'), + help="List of OpenERP users who will receive a notification to " + "remind them about the Intrastat declaration."), + 'intrastat_email_list': fields.function( + _compute_intrastat_email_list, type='char', size=1000, + string='List of emails of Users Receiving the Intrastat Reminder'), } def _check_intrastat_remind_users(self, cr, uid, ids): for company in self.browse(cr, uid, ids): for user in company.intrastat_remind_user_ids: if not user.email: - raise orm.except_orm(_('Error :'), _("Missing e-mail address on user '%s'.") % (user.name)) + raise orm.except_orm( + _('Error :'), + _("Missing e-mail address on user '%s'.") + % (user.name)) return True _constraints = [ diff --git a/intrastat_base/country.py b/intrastat_base/country.py index 2cb923f..e967e92 100644 --- a/intrastat_base/country.py +++ b/intrastat_base/country.py @@ -2,7 +2,7 @@ ############################################################################## # # Report intrastat base module for OpenERP -# Copyright (C) 2011-2013 Akretion (http://www.akretion.com). All Rights Reserved +# Copyright (C) 2011-2013 Akretion (http://www.akretion.com). # @author Alexis de Lattre # # This program is free software: you can redistribute it and/or modify @@ -26,7 +26,9 @@ from openerp.osv import orm, fields class res_country(orm.Model): _inherit = 'res.country' _columns = { - 'intrastat': fields.boolean('EU country', help="Set to True for all European Union countries."), + 'intrastat': fields.boolean( + 'EU Country', + help="Set to True for all European Union countries."), } _defaults = { diff --git a/intrastat_base/country_view.xml b/intrastat_base/country_view.xml index 87e7ec9..2177dbb 100644 --- a/intrastat_base/country_view.xml +++ b/intrastat_base/country_view.xml @@ -31,6 +31,21 @@ + + + intrastat.base.country.search + res.country + + + + + + + + + + diff --git a/intrastat_base/i18n/fr_FR.po b/intrastat_base/i18n/fr_FR.po index c3a85fe..0e099c0 100644 --- a/intrastat_base/i18n/fr_FR.po +++ b/intrastat_base/i18n/fr_FR.po @@ -4,10 +4,10 @@ # msgid "" msgstr "" -"Project-Id-Version: OpenERP Server 6.0.4\n" -"Report-Msgid-Bugs-To: support@openerp.com\n" -"POT-Creation-Date: 2012-06-05 13:28+0000\n" -"PO-Revision-Date: 2012-06-05 13:28+0000\n" +"Project-Id-Version: OpenERP Server 7.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-04-14 14:18+0000\n" +"PO-Revision-Date: 2014-04-14 14:18+0000\n" "Last-Translator: <>\n" "Language-Team: \n" "MIME-Version: 1.0\n" @@ -16,122 +16,24 @@ msgstr "" "Plural-Forms: \n" #. module: intrastat_base -#: model:ir.ui.menu,name:intrastat_base.menu_intrastat_base_root -msgid "Intrastat reporting" -msgstr "DEB et DES" +#: help:product.template,is_accessory_cost:0 +msgid "Activate this option for shipping costs, packaging costs and all services related to the sale of products. This option is used for Intrastat reports." +msgstr "Activez cette option pour les frais de port, les frais d'emballage et tous les services liés à la vente de produits physiques. Cette option est utilisée pour la DEB et la DES." #. module: intrastat_base -#: sql_constraint:res.country:0 -msgid "The code of the country must be unique !" -msgstr "Le code du pays doit être unique !" - -#. module: intrastat_base -#: constraint:product.template:0 -msgid "Error: The default UOM and the purchase UOM must be in the same category." -msgstr "Erreur: l'UdM par défaut et l'UdM d'achat doivent appartenir à la même catégorie." - -#. module: intrastat_base -#: code:addons/intrastat_base/intrastat_common.py:64 -#: code:addons/intrastat_base/intrastat_common.py:70 -#: code:addons/intrastat_base/intrastat_common.py:85 -#: code:addons/intrastat_base/intrastat_common.py:93 -#: code:addons/intrastat_base/product.py:41 -#, python-format -msgid "Error :" -msgstr "Erreur :" - -#. module: intrastat_base -#: model:ir.model,name:intrastat_base.model_account_tax -msgid "account.tax" -msgstr "account.tax" - -#. module: intrastat_base -#: field:account.tax,exclude_from_intrastat_if_present:0 -msgid "Exclude invoice line from intrastat if this tax is present" -msgstr "Exclue la ligne de facture de la DEB/DES si cette taxe est présente" - -#. module: intrastat_base -#: help:res.country,intrastat:0 -msgid "Set as True for countries that must be selected in the intrastat reports, i.e. for all European Union countries other than your own country." -msgstr "Activer cette option pour les pays qui doivent être inclus dans la DEB et la DES, i.e. tous les pays de l'Union Européenne sauf votre propre pays." - -#. module: intrastat_base -#: view:product.product:0 -#: view:product.template:0 -msgid "Intrastat properties" -msgstr "Paramètres pour la DEB et la DES" - -#. module: intrastat_base -#: model:ir.module.module,description:intrastat_base.module_meta_information -msgid "This module contains the common functions for 2 other modules :\n" -"- l10n_fr_intrastat_service : the module for the \"Déclaration Européenne des Services\" (DES)\n" -"- l10n_fr_intrastat_product : the module for the \"Déclaration d'Echange de Biens\" (DEB)\n" -"This module is not usefull if it's not used together with one of those 2 modules.\n" -"\n" -"This module doesn't have any France-specific stuff. So it can be used as a basis for other intrastat modules for other EU countries.\n" -"\n" -"WARNING : this module conflicts with the module \"report_intrastat\" from the addons. If you have already installed the module \"report_intrastat\", you should uninstall it first before installing this module.\n" -"\n" -"Please contact Alexis de Lattre from Akretion for any help or question about this module.\n" -" " -msgstr "This module contains the common functions for 2 other modules :\n" -"- l10n_fr_intrastat_service : the module for the \"Déclaration Européenne des Services\" (DES)\n" -"- l10n_fr_intrastat_product : the module for the \"Déclaration d'Echange de Biens\" (DEB)\n" -"This module is not usefull if it's not used together with one of those 2 modules.\n" -"\n" -"This module doesn't have any France-specific stuff. So it can be used as a basis for other intrastat modules for other EU countries.\n" -"\n" -"WARNING : this module conflicts with the module \"report_intrastat\" from the addons. If you have already installed the module \"report_intrastat\", you should uninstall it first before installing this module.\n" -"\n" -"Please contact Alexis de Lattre from Akretion for any help or question about this module.\n" -" " - -#. module: intrastat_base -#: sql_constraint:res.country:0 -msgid "The name of the country must be unique !" -msgstr "Le nom du pays doit être unique !" - -#. module: intrastat_base -#: constraint:product.template:0 -msgid "Error msg is in raise" -msgstr "Error msg is in raise" - -#. module: intrastat_base -#: help:account.tax,exclude_from_intrastat_if_present:0 -msgid "If this tax is present on an invoice line, this invoice line will be skipped when generating Intrastat Product or Service lines from invoices." -msgstr "Si cette taxe est présente sur une ligne de facture, cette ligne de facture ne sera pas prise en compte lors de la génération de la DEB et de la DES depuis les factures." - -#. module: intrastat_base -#: field:product.template,is_accessory_cost:0 -msgid "Is accessory cost" -msgstr "Frais accessoires" - -#. module: intrastat_base -#: field:res.country,intrastat:0 -msgid "Intrastat country" -msgstr "Pays intrastat" - -#. module: intrastat_base -#: help:product.template,exclude_from_intrastat:0 -msgid "If set to True, the product or service will not be taken into account for Intrastat Product or Service reports. So you should leave this field to False unless you have a very good reason." -msgstr "Si l'option est activée, le produit ou service ne sera pris en compte ni pour la DEB ni pour la DES. Cette option doit donc rester désactivée sauf si vous avez une très bonne raison." - -#. module: intrastat_base -#: code:addons/intrastat_base/intrastat_common.py:64 -#, python-format -msgid "The company currency must be 'EUR', but is currently '%s'." -msgstr "La monnaie de la société doit être 'EUR', mais est actuellement '%s'." - -#. module: intrastat_base -#: code:addons/intrastat_base/intrastat_common.py:70 -#, python-format -msgid "The VAT number is not set for the partner '%s'." -msgstr "Le numéro de TVA n'est pas renseigné pour le partenaire '%s'." +#: view:res.company:0 +msgid "Common Intrastat Settings" +msgstr "Paramètres communs DEB et DES" #. module: intrastat_base #: model:ir.model,name:intrastat_base.model_report_intrastat_common msgid "Common functions for intrastat reports for products and services" -msgstr "Common functions for intrastat reports for products and services" +msgstr "Fonctions communes pour la DEB et la DES" + +#. module: intrastat_base +#: model:ir.model,name:intrastat_base.model_res_company +msgid "Companies" +msgstr "Sociétés" #. module: intrastat_base #: model:ir.model,name:intrastat_base.model_res_country @@ -139,14 +41,26 @@ msgid "Country" msgstr "Pays" #. module: intrastat_base -#: model:ir.model,name:intrastat_base.model_product_template -msgid "Product Template" -msgstr "Modèle de produit" +#: view:res.country:0 +#: field:res.country,intrastat:0 +msgid "EU Country" +msgstr "Pays UE" #. module: intrastat_base -#: model:ir.module.module,shortdesc:intrastat_base.module_meta_information -msgid "Base module for Intrastat reporting" -msgstr "Module de base pour les rapports intrastat" +#: code:addons/intrastat_base/company.py:58 +#: code:addons/intrastat_base/intrastat_common.py:77 +#: code:addons/intrastat_base/intrastat_common.py:82 +#: code:addons/intrastat_base/intrastat_common.py:90 +#: code:addons/intrastat_base/intrastat_common.py:110 +#: code:addons/intrastat_base/product.py:51 +#, python-format +msgid "Error :" +msgstr "Erreur :" + +#. module: intrastat_base +#: constraint:product.template:0 +msgid "Error msg is in raise" +msgstr "Error msg is in raise" #. module: intrastat_base #: field:product.template,exclude_from_intrastat:0 @@ -154,9 +68,76 @@ msgid "Exclude from Intrastat reports" msgstr "Exclure de la DEB et de la DES" #. module: intrastat_base -#: help:product.template,is_accessory_cost:0 -msgid "Activate this option for shipping costs, packaging costs and all services related to the sale of products. This option is used for Intrastat reports." -msgstr "Activez cette option pour les frais de port, les frais d'emballage et tous les services liés à la vente de produits physiques. Cette option est utilisée pour la DEB et la DES." +#: field:account.tax,exclude_from_intrastat_if_present:0 +msgid "Exclude invoice line from intrastat if this tax is present" +msgstr "Exclue la ligne de facture de la DEB/DES si cette taxe est présente" + +#. module: intrastat_base +#: help:product.template,exclude_from_intrastat:0 +msgid "If set to True, the product or service will not be taken into account for Intrastat Product or Service reports. So you should leave this field to False unless you have a very good reason." +msgstr "Si l'option est activée, le produit ou service ne sera pris en compte ni pour la DEB ni pour la DES. Cette option doit donc rester désactivée sauf si vous avez une très bonne raison." + +#. module: intrastat_base +#: help:account.tax,exclude_from_intrastat_if_present:0 +msgid "If this tax is present on an invoice line, this invoice line will be skipped when generating Intrastat Product or Service lines from invoices." +msgstr "Si cette taxe est présente sur une ligne de facture, cette ligne de facture ne sera pas prise en compte lors de la génération de la DEB et de la DES depuis les factures." + +#. module: intrastat_base +#: view:product.product:0 +#: view:product.template:0 +msgid "Intrastat Properties" +msgstr "Propriétés DEB/DES" + +#. module: intrastat_base +#: view:res.company:0 +msgid "Intrastat Settings" +msgstr "Configuration DEB/DES" + +#. module: intrastat_base +#: model:ir.ui.menu,name:intrastat_base.menu_intrastat_base_root +msgid "Intrastat reporting" +msgstr "DEB et DES" + +#. module: intrastat_base +#: field:product.template,is_accessory_cost:0 +msgid "Is accessory cost" +msgstr "Frais accessoires" + +#. module: intrastat_base +#: help:res.company,intrastat_remind_user_ids:0 +msgid "List of OpenERP users who will receive a notification to remind them about the Intrastat declaration." +msgstr "Liste d'utilisateurs OpenERP qui recevront le rappel pour la DEB et/ou la DES." + +#. module: intrastat_base +#: field:res.company,intrastat_email_list:0 +msgid "List of emails of Users Receiving the Intrastat Reminder" +msgstr "Liste des emails d'utilisateurs qui recevront le rappel pour la DEB et/ou la DES" + +#. module: intrastat_base +#: code:addons/intrastat_base/company.py:59 +#, python-format +msgid "Missing e-mail address on user '%s'." +msgstr "Adresse e-mail manquante sur l'utilisateur '%s'." + +#. module: intrastat_base +#: model:ir.model,name:intrastat_base.model_res_partner +msgid "Partner" +msgstr "Partenaire" + +#. module: intrastat_base +#: model:ir.model,name:intrastat_base.model_product_template +msgid "Product Template" +msgstr "Modèle d'article" + +#. module: intrastat_base +#: view:res.country:0 +msgid "Search Countries" +msgstr "Recherche des pays" + +#. module: intrastat_base +#: help:res.country,intrastat:0 +msgid "Set to True for all European Union countries." +msgstr "A cocher pour tous les pays de l'Union Européenne." #. module: intrastat_base #: model:product.template,name:intrastat_base.shipping_costs_exclude_product_template @@ -164,13 +145,47 @@ msgid "Shipping costs" msgstr "Frais de port" #. module: intrastat_base -#: code:addons/intrastat_base/intrastat_common.py:85 +#: model:ir.model,name:intrastat_base.model_account_tax +msgid "Tax" +msgstr "Taxes" + +#. module: intrastat_base +#: code:addons/intrastat_base/intrastat_common.py:91 +#, python-format +msgid "The VAT number is not set for the partner '%s'." +msgstr "Le numéro de TVA n'est pas renseigné pour le partenaire '%s'." + +#. module: intrastat_base +#: code:addons/intrastat_base/intrastat_common.py:83 +#, python-format +msgid "The company currency must be 'EUR', but is currently '%s'." +msgstr "La monnaie de la société doit être 'EUR', mais est actuellement '%s'." + +#. module: intrastat_base +#: code:addons/intrastat_base/intrastat_common.py:78 +#, python-format +msgid "The country is not set on the company '%s'." +msgstr "Le pays n'est pas renseigné sur la société '%s'." + +#. module: intrastat_base +#: code:addons/intrastat_base/intrastat_common.py:111 #, python-format msgid "The generated XML file is not valid against the official XML Schema Definition. The generated XML file and the full error have been written in the server logs. Here is the error, which may give you an idea on the cause of the problem : %s." msgstr "La validation du fichier XML avec le schéma XML officiel a échoué. Le fichier XML généré et le détail de l'erreur ont été écrits dans les logs du serveur. Voici le message d'erreur, qui peut vous donner une idée de la cause du problème : %s." #. module: intrastat_base -#: model:ir.model,name:intrastat_base.model_res_partner_address -msgid "Partner Addresses" -msgstr "Carnet d'adresses" +#: code:addons/intrastat_base/product.py:56 +#, python-format +msgid "The option 'Is accessory cost?' should only be activated on 'Service' products. You have activated this option for the product '%s' which is of type '%s'" +msgstr "L'option 'Frais accessoires' ne doit être activée que sur les produits de type 'Service'. Vous avez activé cette option sur le produit '%s' qui est de type '%s'" + +#. module: intrastat_base +#: field:res.company,intrastat_remind_user_ids:0 +msgid "Users Receiving the Intrastat Reminder" +msgstr "Utilisateurs qui reçoivent le rappel DEB/DES" + +#. module: intrastat_base +#: constraint:res.company:0 +msgid "error msg in raise" +msgstr "error msg in raise" diff --git a/intrastat_base/i18n/intrastat_base.pot b/intrastat_base/i18n/intrastat_base.pot index d7baf12..b170abd 100644 --- a/intrastat_base/i18n/intrastat_base.pot +++ b/intrastat_base/i18n/intrastat_base.pot @@ -4,10 +4,10 @@ # msgid "" msgstr "" -"Project-Id-Version: OpenERP Server 6.0.4\n" -"Report-Msgid-Bugs-To: support@openerp.com\n" -"POT-Creation-Date: 2012-06-05 13:28+0000\n" -"PO-Revision-Date: 2012-06-05 13:28+0000\n" +"Project-Id-Version: OpenERP Server 7.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-04-14 14:18+0000\n" +"PO-Revision-Date: 2014-04-14 14:18+0000\n" "Last-Translator: <>\n" "Language-Team: \n" "MIME-Version: 1.0\n" @@ -16,106 +16,13 @@ msgstr "" "Plural-Forms: \n" #. module: intrastat_base -#: model:ir.ui.menu,name:intrastat_base.menu_intrastat_base_root -msgid "Intrastat reporting" +#: help:product.template,is_accessory_cost:0 +msgid "Activate this option for shipping costs, packaging costs and all services related to the sale of products. This option is used for Intrastat reports." msgstr "" #. module: intrastat_base -#: sql_constraint:res.country:0 -msgid "The code of the country must be unique !" -msgstr "" - -#. module: intrastat_base -#: constraint:product.template:0 -msgid "Error: The default UOM and the purchase UOM must be in the same category." -msgstr "" - -#. module: intrastat_base -#: code:addons/intrastat_base/intrastat_common.py:64 -#: code:addons/intrastat_base/intrastat_common.py:70 -#: code:addons/intrastat_base/intrastat_common.py:85 -#: code:addons/intrastat_base/intrastat_common.py:93 -#: code:addons/intrastat_base/product.py:41 -#, python-format -msgid "Error :" -msgstr "" - -#. module: intrastat_base -#: model:ir.model,name:intrastat_base.model_account_tax -msgid "account.tax" -msgstr "" - -#. module: intrastat_base -#: field:account.tax,exclude_from_intrastat_if_present:0 -msgid "Exclude invoice line from intrastat if this tax is present" -msgstr "" - -#. module: intrastat_base -#: help:res.country,intrastat:0 -msgid "Set as True for countries that must be selected in the intrastat reports, i.e. for all European Union countries other than your own country." -msgstr "" - -#. module: intrastat_base -#: view:product.product:0 -#: view:product.template:0 -msgid "Intrastat properties" -msgstr "" - -#. module: intrastat_base -#: model:ir.module.module,description:intrastat_base.module_meta_information -msgid "This module contains the common functions for 2 other modules :\n" -"- l10n_fr_intrastat_service : the module for the \"Déclaration Européenne des Services\" (DES)\n" -"- l10n_fr_intrastat_product : the module for the \"Déclaration d'Echange de Biens\" (DEB)\n" -"This module is not usefull if it's not used together with one of those 2 modules.\n" -"\n" -"This module doesn't have any France-specific stuff. So it can be used as a basis for other intrastat modules for other EU countries.\n" -"\n" -"WARNING : this module conflicts with the module \"report_intrastat\" from the addons. If you have already installed the module \"report_intrastat\", you should uninstall it first before installing this module.\n" -"\n" -"Please contact Alexis de Lattre from Akretion for any help or question about this module.\n" -" " -msgstr "" - -#. module: intrastat_base -#: sql_constraint:res.country:0 -msgid "The name of the country must be unique !" -msgstr "" - -#. module: intrastat_base -#: constraint:product.template:0 -msgid "Error msg is in raise" -msgstr "" - -#. module: intrastat_base -#: help:account.tax,exclude_from_intrastat_if_present:0 -msgid "If this tax is present on an invoice line, this invoice line will be skipped when generating Intrastat Product or Service lines from invoices." -msgstr "" - -#. module: intrastat_base -#: field:product.template,is_accessory_cost:0 -msgid "Is accessory cost" -msgstr "" - -#. module: intrastat_base -#: field:res.country,intrastat:0 -msgid "Intrastat country" -msgstr "" - -#. module: intrastat_base -#: help:product.template,exclude_from_intrastat:0 -msgid "If set to True, the product or service will not be taken into account for Intrastat Product or Service reports. So you should leave this field to False unless you have a very good reason." -msgstr "" - -#. module: intrastat_base -#: code:addons/intrastat_base/intrastat_common.py:64 -#, python-format -msgid "The company currency must be 'EUR', but is currently '%s'." -msgstr "" - -#. module: intrastat_base -#: code:addons/intrastat_base/intrastat_common.py:70 -#, python-format -msgid "The VAT number is not set for the partner '%s'." +#: view:res.company:0 +msgid "Common Intrastat Settings" msgstr "" #. module: intrastat_base @@ -123,19 +30,36 @@ msgstr "" msgid "Common functions for intrastat reports for products and services" msgstr "" +#. module: intrastat_base +#: model:ir.model,name:intrastat_base.model_res_company +msgid "Companies" +msgstr "" + #. module: intrastat_base #: model:ir.model,name:intrastat_base.model_res_country msgid "Country" msgstr "" #. module: intrastat_base -#: model:ir.model,name:intrastat_base.model_product_template -msgid "Product Template" +#: view:res.country:0 +#: field:res.country,intrastat:0 +msgid "EU Country" msgstr "" #. module: intrastat_base -#: model:ir.module.module,shortdesc:intrastat_base.module_meta_information -msgid "Base module for Intrastat reporting" +#: code:addons/intrastat_base/company.py:58 +#: code:addons/intrastat_base/intrastat_common.py:77 +#: code:addons/intrastat_base/intrastat_common.py:82 +#: code:addons/intrastat_base/intrastat_common.py:90 +#: code:addons/intrastat_base/intrastat_common.py:110 +#: code:addons/intrastat_base/product.py:51 +#, python-format +msgid "Error :" +msgstr "" + +#. module: intrastat_base +#: constraint:product.template:0 +msgid "Error msg is in raise" msgstr "" #. module: intrastat_base @@ -144,8 +68,75 @@ msgid "Exclude from Intrastat reports" msgstr "" #. module: intrastat_base -#: help:product.template,is_accessory_cost:0 -msgid "Activate this option for shipping costs, packaging costs and all services related to the sale of products. This option is used for Intrastat reports." +#: field:account.tax,exclude_from_intrastat_if_present:0 +msgid "Exclude invoice line from intrastat if this tax is present" +msgstr "" + +#. module: intrastat_base +#: help:product.template,exclude_from_intrastat:0 +msgid "If set to True, the product or service will not be taken into account for Intrastat Product or Service reports. So you should leave this field to False unless you have a very good reason." +msgstr "" + +#. module: intrastat_base +#: help:account.tax,exclude_from_intrastat_if_present:0 +msgid "If this tax is present on an invoice line, this invoice line will be skipped when generating Intrastat Product or Service lines from invoices." +msgstr "" + +#. module: intrastat_base +#: view:product.product:0 +#: view:product.template:0 +msgid "Intrastat Properties" +msgstr "" + +#. module: intrastat_base +#: view:res.company:0 +msgid "Intrastat Settings" +msgstr "" + +#. module: intrastat_base +#: model:ir.ui.menu,name:intrastat_base.menu_intrastat_base_root +msgid "Intrastat reporting" +msgstr "" + +#. module: intrastat_base +#: field:product.template,is_accessory_cost:0 +msgid "Is accessory cost" +msgstr "" + +#. module: intrastat_base +#: help:res.company,intrastat_remind_user_ids:0 +msgid "List of OpenERP users who will receive a notification to remind them about the Intrastat declaration." +msgstr "" + +#. module: intrastat_base +#: field:res.company,intrastat_email_list:0 +msgid "List of emails of Users Receiving the Intrastat Reminder" +msgstr "" + +#. module: intrastat_base +#: code:addons/intrastat_base/company.py:59 +#, python-format +msgid "Missing e-mail address on user '%s'." +msgstr "" + +#. module: intrastat_base +#: model:ir.model,name:intrastat_base.model_res_partner +msgid "Partner" +msgstr "" + +#. module: intrastat_base +#: model:ir.model,name:intrastat_base.model_product_template +msgid "Product Template" +msgstr "" + +#. module: intrastat_base +#: view:res.country:0 +msgid "Search Countries" +msgstr "" + +#. module: intrastat_base +#: help:res.country,intrastat:0 +msgid "Set to True for all European Union countries." msgstr "" #. module: intrastat_base @@ -154,13 +145,47 @@ msgid "Shipping costs" msgstr "" #. module: intrastat_base -#: code:addons/intrastat_base/intrastat_common.py:85 +#: model:ir.model,name:intrastat_base.model_account_tax +msgid "Tax" +msgstr "" + +#. module: intrastat_base +#: code:addons/intrastat_base/intrastat_common.py:91 +#, python-format +msgid "The VAT number is not set for the partner '%s'." +msgstr "" + +#. module: intrastat_base +#: code:addons/intrastat_base/intrastat_common.py:83 +#, python-format +msgid "The company currency must be 'EUR', but is currently '%s'." +msgstr "" + +#. module: intrastat_base +#: code:addons/intrastat_base/intrastat_common.py:78 +#, python-format +msgid "The country is not set on the company '%s'." +msgstr "" + +#. module: intrastat_base +#: code:addons/intrastat_base/intrastat_common.py:111 #, python-format msgid "The generated XML file is not valid against the official XML Schema Definition. The generated XML file and the full error have been written in the server logs. Here is the error, which may give you an idea on the cause of the problem : %s." msgstr "" #. module: intrastat_base -#: model:ir.model,name:intrastat_base.model_res_partner_address -msgid "Partner Addresses" +#: code:addons/intrastat_base/product.py:56 +#, python-format +msgid "The option 'Is accessory cost?' should only be activated on 'Service' products. You have activated this option for the product '%s' which is of type '%s'" +msgstr "" + +#. module: intrastat_base +#: field:res.company,intrastat_remind_user_ids:0 +msgid "Users Receiving the Intrastat Reminder" +msgstr "" + +#. module: intrastat_base +#: constraint:res.company:0 +msgid "error msg in raise" msgstr "" diff --git a/intrastat_base/intrastat_common.py b/intrastat_base/intrastat_common.py index 7a21a62..2e9d515 100644 --- a/intrastat_base/intrastat_common.py +++ b/intrastat_base/intrastat_common.py @@ -2,7 +2,7 @@ ############################################################################## # # Report intrastat base module for OpenERP -# Copyright (C) 2010-2013 Akretion (http://www.akretion.com/). All rights reserved. +# Copyright (C) 2010-2013 Akretion (http://www.akretion.com/). # @author Alexis de Lattre # # This program is free software: you can redistribute it and/or modify @@ -31,7 +31,8 @@ logger = logging.getLogger(__name__) class report_intrastat_common(orm.TransientModel): _name = "report.intrastat.common" - _description = "Common functions for intrastat reports for products and services" + _description = "Common functions for intrastat reports for products " + "and services" def _compute_numbers(self, cr, uid, ids, object, context=None): result = {} @@ -41,14 +42,19 @@ class report_intrastat_common(orm.TransientModel): for line in intrastat.intrastat_line_ids: total_amount += line.amount_company_currency num_lines += 1 - result[intrastat.id] = {'num_lines': num_lines, 'total_amount': total_amount} + result[intrastat.id] = { + 'num_lines': num_lines, + 'total_amount': total_amount, + } return result def _compute_dates(self, cr, uid, ids, object, context=None): result = {} for intrastat in object.browse(cr, uid, ids, context=context): - start_date_datetime = datetime.strptime(intrastat.start_date, '%Y-%m-%d') - end_date_str = datetime.strftime(start_date_datetime + relativedelta(day=31), '%Y-%m-%d') + start_date_datetime = datetime.strptime( + intrastat.start_date, '%Y-%m-%d') + end_date_str = datetime.strftime( + start_date_datetime + relativedelta(day=31), '%Y-%m-%d') result[intrastat.id] = { 'end_date': end_date_str, 'year_month': start_date_datetime.strftime('%Y-%m'), @@ -57,53 +63,87 @@ class report_intrastat_common(orm.TransientModel): def _check_start_date(self, cr, uid, ids, object, context=None): '''Check that the start date is the first day of the month''' - for date_to_check in object.read(cr, uid, ids, ['start_date'], context=context): - datetime_to_check = datetime.strptime(date_to_check['start_date'], '%Y-%m-%d') + for date_to_check in object.read( + cr, uid, ids, ['start_date'], context=context): + datetime_to_check = datetime.strptime( + date_to_check['start_date'], '%Y-%m-%d') if datetime_to_check.day != 1: return False return True def _check_generate_lines(self, cr, uid, intrastat, context=None): if not intrastat.company_id.country_id: - raise orm.except_orm(_('Error :'), _("The country is not set on the company '%s'.") % intrastat.company_id.name) + raise orm.except_orm( + _('Error :'), + _("The country is not set on the company '%s'.") + % intrastat.company_id.name) if not intrastat.currency_id.name == 'EUR': - raise orm.except_orm(_('Error :'), _("The company currency must be 'EUR', but is currently '%s'.") % intrastat.currency_id.name) + raise orm.except_orm( + _('Error :'), + _("The company currency must be 'EUR', but is currently '%s'.") + % intrastat.currency_id.name) return True def _check_generate_xml(self, cr, uid, intrastat, context=None): if not intrastat.company_id.partner_id.vat: - raise orm.except_orm(_('Error :'), _("The VAT number is not set for the partner '%s'.") % intrastat.company_id.partner_id.name) + raise orm.except_orm( + _('Error :'), + _("The VAT number is not set for the partner '%s'.") + % intrastat.company_id.partner_id.name) return True - def _check_xml_schema(self, cr, uid, xml_root, xml_string, xsd, context=None): + def _check_xml_schema( + self, cr, uid, xml_root, xml_string, xsd, context=None): '''Validate the XML file against the XSD''' from lxml import etree official_des_xml_schema = etree.XMLSchema(etree.fromstring(xsd)) try: official_des_xml_schema.assertValid(xml_root) - except Exception, e: # if the validation of the XSD fails, we arrive here - import logging + except Exception, e: + # if the validation of the XSD fails, we arrive here _logger = logging.getLogger(__name__) - _logger.warning("The XML file is invalid against the XML Schema Definition") + _logger.warning( + "The XML file is invalid against the XML Schema Definition") _logger.warning(xml_string) _logger.warning(e) - raise orm.except_orm(_('Error :'), _('The generated XML file is not valid against the official XML Schema Definition. The generated XML file and the full error have been written in the server logs. Here is the error, which may give you an idea on the cause of the problem : %s.') % str(e)) + raise orm.except_orm( + _('Error :'), + _("The generated XML file is not valid against the official " + "XML Schema Definition. The generated XML file and the " + "full error have been written in the server logs. " + "Here is the error, which may give you an idea on the " + "cause of the problem : %s.") + % str(e)) return True - def _attach_xml_file(self, cr, uid, ids, object, xml_string, start_date_datetime, declaration_name, context=None): - '''Attach the XML file to the report_intrastat_product/service object''' + def _attach_xml_file( + self, cr, uid, ids, object, xml_string, start_date_datetime, + declaration_name, context=None): + '''Attach the XML file to the report_intrastat_product/service ''' + '''object''' import base64 assert len(ids) == 1, "Only one ID accepted" - filename = datetime.strftime(start_date_datetime, '%Y-%m') + '_' + declaration_name + '.xml' - attach_obj = self.pool.get('ir.attachment') + filename = '%s_%s.xml' % ( + datetime.strftime(start_date_datetime, '%Y-%m'), + declaration_name) if not context: context = {} - context.update({'default_res_id': ids[0], 'default_res_model': object._name}) - attach_id = attach_obj.create(cr, uid, {'name': filename, 'datas': base64.encodestring(xml_string), 'datas_fname': filename}, context=context) + context.update({ + 'default_res_id': ids[0], + 'default_res_model': object._name + }) + attach_id = self.pool['ir.attachment'].create( + cr, uid, { + 'name': filename, + 'datas': base64.encodestring(xml_string), + 'datas_fname': filename}, + context=context) return attach_id - def _open_attach_view(self, cr, uid, attach_id, title='XML file', context=None): - '''Returns an action which opens the form view of the corresponding attachement''' + def _open_attach_view( + self, cr, uid, attach_id, title='XML file', context=None): + '''Returns an action which opens the form view of the ''' + '''corresponding attachement''' action = { 'name': title, 'view_type': 'form', @@ -121,19 +161,26 @@ class report_intrastat_common(orm.TransientModel): result = {} result['value'] = {} if partner_id: - company = self.pool.get('res.partner').read(cr, uid, partner_id, ['vat']) + company = self.pool['res.partner'].read( + cr, uid, partner_id, ['vat']) result['value'].update({'partner_vat': company['vat']}) return result - def send_reminder_email(self, cr, uid, company, module_name, template_xmlid, intrastat_id, context=None): - template_data = self.pool['ir.model.data'].get_object_reference(cr, uid, module_name, template_xmlid) - if template_data and template_data[0] == 'email.template': - template_id = template_data[1] - else: - raise orm.except_orm(_('Error :'), _("Wrong model for XMLID '%s.%s': model is '%s' and it should be 'email.template'.") % (module_name, template_xmlid, template_data[0])) + def send_reminder_email( + self, cr, uid, company, module_name, template_xmlid, + intrastat_id, context=None): + template_model, template_id =\ + self.pool['ir.model.data'].get_object_reference( + cr, uid, module_name, template_xmlid) + assert template_model == 'email.template', 'Wrong model' if company.intrastat_remind_user_ids: - self.pool['email.template'].send_mail(cr, uid, template_id, intrastat_id, context=context) - logger.info('Intrastat Reminder email has been sent (XMLID: %s).' % template_xmlid) + self.pool['email.template'].send_mail( + cr, uid, template_id, intrastat_id, context=context) + logger.info( + 'Intrastat Reminder email has been sent (XMLID: %s).' + % template_xmlid) else: - logger.warning('The list of users receiving the Intrastat Reminder is empty on company %s' % company.name) + logger.warning( + 'The list of users receiving the Intrastat Reminder is empty ' + 'on company %s' % company.name) return True diff --git a/intrastat_base/product.py b/intrastat_base/product.py index 60132f0..7181706 100644 --- a/intrastat_base/product.py +++ b/intrastat_base/product.py @@ -27,8 +27,17 @@ from openerp.tools.translate import _ class product_template(orm.Model): _inherit = "product.template" _columns = { - 'exclude_from_intrastat': fields.boolean('Exclude from Intrastat reports', help="If set to True, the product or service will not be taken into account for Intrastat Product or Service reports. So you should leave this field to False unless you have a very good reason."), - 'is_accessory_cost': fields.boolean('Is accessory cost', help='Activate this option for shipping costs, packaging costs and all services related to the sale of products. This option is used for Intrastat reports.'), + 'exclude_from_intrastat': fields.boolean( + 'Exclude from Intrastat reports', + help="If set to True, the product or service will not be " + "taken into account for Intrastat Product or Service reports. " + "So you should leave this field to False unless you have a " + "very good reason."), + 'is_accessory_cost': fields.boolean( + 'Is accessory cost', + help="Activate this option for shipping costs, packaging " + "costs and all services related to the sale of products. " + "This option is used for Intrastat reports."), } _defaults = { @@ -38,7 +47,13 @@ class product_template(orm.Model): def _check_accessory_cost(self, cr, uid, ids): for product in self.browse(cr, uid, ids): if product.is_accessory_cost and product.type != 'service': - raise orm.except_orm(_('Error :'), _("The option 'Is accessory cost?' should only be activated on 'Service' products. You have activated this option for the product '%s' which is of type '%s'" % (product.name, product.type))) + raise orm.except_orm( + _('Error :'), + _("The option 'Is accessory cost?' should only be " + "activated on 'Service' products. You have activated " + "this option for the product '%s' which is of type " + "'%s'" + % (product.name, product.type))) return True _constraints = [ diff --git a/intrastat_base/product_view.xml b/intrastat_base/product_view.xml index fd7c2d4..a551868 100644 --- a/intrastat_base/product_view.xml +++ b/intrastat_base/product_view.xml @@ -18,7 +18,8 @@ - + @@ -33,7 +34,8 @@ - + diff --git a/intrastat_base/tax.py b/intrastat_base/tax.py index 5e933d1..fae6a3d 100644 --- a/intrastat_base/tax.py +++ b/intrastat_base/tax.py @@ -2,7 +2,7 @@ ############################################################################## # # Report intrastat base module for OpenERP -# Copyright (C) 2011-2013 Akretion (http://www.akretion.com). All Rights Reserved +# Copyright (C) 2011-2013 Akretion (http://www.akretion.com). # @author Alexis de Lattre # # This program is free software: you can redistribute it and/or modify @@ -25,6 +25,11 @@ from openerp.osv import orm, fields class account_tax(orm.Model): _inherit = "account.tax" + _columns = { - 'exclude_from_intrastat_if_present': fields.boolean('Exclude invoice line from intrastat if this tax is present', help="If this tax is present on an invoice line, this invoice line will be skipped when generating Intrastat Product or Service lines from invoices."), + 'exclude_from_intrastat_if_present': fields.boolean( + 'Exclude invoice line from intrastat if this tax is present', + help="If this tax is present on an invoice line, this invoice " + "line will be skipped when generating Intrastat Product or " + "Service lines from invoices."), } From 5a57ee84f593d3b1eb6b4d3bddf8f29a71603f3d Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Mon, 14 Apr 2014 19:41:39 +0200 Subject: [PATCH 034/103] Add context in on_change (to be able to use web_context_tunnel) XSD files are now pure XSD files, not python file with the content as string. Convert l10n_fr_intrastat_service to PEP-8 Start to convert l10n_fr_intrastat_product to PEP-8 (not finished yet) l10n_fr_intrastat_product : Update POT file and FR translation. --- intrastat_base/intrastat_common.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/intrastat_base/intrastat_common.py b/intrastat_base/intrastat_common.py index 2e9d515..2129f8d 100644 --- a/intrastat_base/intrastat_common.py +++ b/intrastat_base/intrastat_common.py @@ -22,6 +22,7 @@ from openerp.osv import orm from openerp.tools.translate import _ +from openerp import tools from datetime import datetime from dateutil.relativedelta import relativedelta import logging @@ -93,12 +94,14 @@ class report_intrastat_common(orm.TransientModel): return True def _check_xml_schema( - self, cr, uid, xml_root, xml_string, xsd, context=None): + self, cr, uid, xml_root, xml_string, xsd_file, context=None): '''Validate the XML file against the XSD''' from lxml import etree - official_des_xml_schema = etree.XMLSchema(etree.fromstring(xsd)) + xsd_etree_obj = etree.parse( + tools.file_open(xsd_file)) + official_schema = etree.XMLSchema(xsd_etree_obj) try: - official_des_xml_schema.assertValid(xml_root) + official_schema.assertValid(xml_root) except Exception, e: # if the validation of the XSD fails, we arrive here _logger = logging.getLogger(__name__) @@ -157,13 +160,13 @@ class report_intrastat_common(orm.TransientModel): } return action - def partner_on_change(self, cr, uid, ids, partner_id=False): + def partner_on_change(self, cr, uid, ids, partner_id=False, context=None): result = {} result['value'] = {} if partner_id: company = self.pool['res.partner'].read( - cr, uid, partner_id, ['vat']) - result['value'].update({'partner_vat': company['vat']}) + cr, uid, partner_id, ['vat'], context=context) + result['value']['partner_vat'] = company['vat'] return result def send_reminder_email( From 319938a09951788d92d6db2ed18cdec05790a7ae Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Tue, 15 Apr 2014 00:11:40 +0200 Subject: [PATCH 035/103] l10n_fr_intrastat_service : update POT file and FR translation. l10n_fr_intrastat_product : continue PEP-8 compliance --- intrastat_base/i18n/fr_FR.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intrastat_base/i18n/fr_FR.po b/intrastat_base/i18n/fr_FR.po index 0e099c0..77ac6e9 100644 --- a/intrastat_base/i18n/fr_FR.po +++ b/intrastat_base/i18n/fr_FR.po @@ -8,7 +8,7 @@ msgstr "" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2014-04-14 14:18+0000\n" "PO-Revision-Date: 2014-04-14 14:18+0000\n" -"Last-Translator: <>\n" +"Last-Translator: Alexis de Lattre \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" From c7f132f397c960d38c5391d0184ab066a8bc4973 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Mon, 23 Jun 2014 12:12:40 +0200 Subject: [PATCH 036/103] Port intrastat_base to Odoo 8.0. --- intrastat_base/product_view.xml | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/intrastat_base/product_view.xml b/intrastat_base/product_view.xml index a551868..a79da20 100644 --- a/intrastat_base/product_view.xml +++ b/intrastat_base/product_view.xml @@ -1,7 +1,7 @@ @@ -9,11 +9,10 @@ - - - intrastat.base.product.normal.form - product.product - + + intrastat.base.product.template.form + product.template + @@ -25,21 +24,5 @@ - - - intrastat.base.product.template.form - product.template - - - - - - - - - - - From e722bcf08d848b3db598b6795d69c70e7b6e7552 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Fri, 4 Jul 2014 00:15:06 +0200 Subject: [PATCH 037/103] Continue the work on port to v8.0 --- intrastat_base/company_view.xml | 2 +- intrastat_base/country_view.xml | 7 +++---- intrastat_base/product_view.xml | 2 +- intrastat_base/tax_view.xml | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/intrastat_base/company_view.xml b/intrastat_base/company_view.xml index 14cf1fe..650d492 100644 --- a/intrastat_base/company_view.xml +++ b/intrastat_base/company_view.xml @@ -9,7 +9,7 @@ - + intrastat.company.form res.company diff --git a/intrastat_base/country_view.xml b/intrastat_base/country_view.xml index 2177dbb..a8c9da2 100644 --- a/intrastat_base/country_view.xml +++ b/intrastat_base/country_view.xml @@ -9,7 +9,7 @@ - + intrastat.base.country.tree res.country @@ -20,7 +20,7 @@ - + intrastat.base.country.form res.country @@ -32,7 +32,7 @@ - + intrastat.base.country.search res.country @@ -46,6 +46,5 @@ - diff --git a/intrastat_base/product_view.xml b/intrastat_base/product_view.xml index a79da20..dc61ca5 100644 --- a/intrastat_base/product_view.xml +++ b/intrastat_base/product_view.xml @@ -9,7 +9,7 @@ - + intrastat.base.product.template.form product.template diff --git a/intrastat_base/tax_view.xml b/intrastat_base/tax_view.xml index c481490..e927aa5 100644 --- a/intrastat_base/tax_view.xml +++ b/intrastat_base/tax_view.xml @@ -10,7 +10,7 @@ - + intrastat.base.tax account.tax form From 627105be9d8059fbb815d56c865804990ec5ff44 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Fri, 4 Jul 2014 00:16:37 +0200 Subject: [PATCH 038/103] Add intrastat_type_data and update demo data accordingly Remove version="7.0" from form views Add ondelete='restrict' on M2O pointing to intrastat.type Add graph views on intrastat.product and intrastat.service... because Odoo v8 graph views are so cool ! :) --- intrastat_base/i18n/fr_FR.po | 2 +- intrastat_base/i18n/intrastat_base.pot | 2 +- intrastat_base/intrastat_menu.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/intrastat_base/i18n/fr_FR.po b/intrastat_base/i18n/fr_FR.po index 77ac6e9..de7e5db 100644 --- a/intrastat_base/i18n/fr_FR.po +++ b/intrastat_base/i18n/fr_FR.po @@ -95,7 +95,7 @@ msgstr "Configuration DEB/DES" #. module: intrastat_base #: model:ir.ui.menu,name:intrastat_base.menu_intrastat_base_root -msgid "Intrastat reporting" +msgid "Intrastat Reporting" msgstr "DEB et DES" #. module: intrastat_base diff --git a/intrastat_base/i18n/intrastat_base.pot b/intrastat_base/i18n/intrastat_base.pot index b170abd..d184def 100644 --- a/intrastat_base/i18n/intrastat_base.pot +++ b/intrastat_base/i18n/intrastat_base.pot @@ -95,7 +95,7 @@ msgstr "" #. module: intrastat_base #: model:ir.ui.menu,name:intrastat_base.menu_intrastat_base_root -msgid "Intrastat reporting" +msgid "Intrastat Reporting" msgstr "" #. module: intrastat_base diff --git a/intrastat_base/intrastat_menu.xml b/intrastat_base/intrastat_menu.xml index 83434cb..ce05472 100644 --- a/intrastat_base/intrastat_menu.xml +++ b/intrastat_base/intrastat_menu.xml @@ -9,7 +9,7 @@ - + From 2e3f94bba0320092ffb336a4f4512f9c1e0824ae Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Thu, 30 Oct 2014 13:30:41 +0100 Subject: [PATCH 039/103] When the obligation level for import is none, the type of the DEB is automatically set to export. [FIX] country -> country_id type='string' -> type='char' (v8 only accepts char) Change "error msg in raise", because v8 displays this to the user Remove statistical_pricelist_id from demo data Harmonize labels of button between DEB and DES --- intrastat_base/company.py | 9 +++++---- intrastat_base/product.py | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/intrastat_base/company.py b/intrastat_base/company.py index 030101f..e475544 100644 --- a/intrastat_base/company.py +++ b/intrastat_base/company.py @@ -60,7 +60,8 @@ class res_company(orm.Model): % (user.name)) return True - _constraints = [ - (_check_intrastat_remind_users, "error msg in raise", - ['intrastat_remind_user_ids']), - ] + _constraints = [( + _check_intrastat_remind_users, + "Wrong configuration of the Users Receiving the Intrastat Reminder", + ['intrastat_remind_user_ids'] + )] diff --git a/intrastat_base/product.py b/intrastat_base/product.py index 7181706..1798280 100644 --- a/intrastat_base/product.py +++ b/intrastat_base/product.py @@ -56,7 +56,8 @@ class product_template(orm.Model): % (product.name, product.type))) return True - _constraints = [ - (_check_accessory_cost, "Error msg is in raise", - ['is_accessory_cost', 'type']) - ] + _constraints = [( + _check_accessory_cost, + "Wrong configuration of the product", + ['is_accessory_cost', 'type'] + )] From 505eb694201500f1e1784def9bdb30395fefb8d8 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Fri, 28 Nov 2014 23:51:23 +0100 Subject: [PATCH 040/103] Add module intrastat_product. Rename report.intrastat.product to l10n.fr.report.intrastat.product (same for service and for lines) + migration scripts --- intrastat_base/__openerp__.py | 1 - intrastat_product/__init__.py | 23 ++++ intrastat_product/__openerp__.py | 46 +++++++ intrastat_product/i18n/intrastat_product.pot | 122 ++++++++++++++++++ intrastat_product/intrastat.py | 84 ++++++++++++ intrastat_product/intrastat_demo.xml | 64 +++++++++ intrastat_product/intrastat_view.xml | 89 +++++++++++++ .../security/ir.model.access.csv | 3 + 8 files changed, 431 insertions(+), 1 deletion(-) create mode 100644 intrastat_product/__init__.py create mode 100644 intrastat_product/__openerp__.py create mode 100644 intrastat_product/i18n/intrastat_product.pot create mode 100644 intrastat_product/intrastat.py create mode 100644 intrastat_product/intrastat_demo.xml create mode 100644 intrastat_product/intrastat_view.xml create mode 100644 intrastat_product/security/ir.model.access.csv diff --git a/intrastat_base/__openerp__.py b/intrastat_base/__openerp__.py index 9661bd8..c9dd90d 100644 --- a/intrastat_base/__openerp__.py +++ b/intrastat_base/__openerp__.py @@ -52,5 +52,4 @@ Please contact Alexis de Lattre from Akretion for ], 'demo': ['intrastat_demo.xml'], 'installable': True, - 'active': False, } diff --git a/intrastat_product/__init__.py b/intrastat_product/__init__.py new file mode 100644 index 0000000..64a3431 --- /dev/null +++ b/intrastat_product/__init__.py @@ -0,0 +1,23 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Intrastat product module for OpenERP +# Copyright (C) 2011-2014 Akretion (http://www.akretion.com) +# @author Alexis de Lattre +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from . import intrastat diff --git a/intrastat_product/__openerp__.py b/intrastat_product/__openerp__.py new file mode 100644 index 0000000..5008ce6 --- /dev/null +++ b/intrastat_product/__openerp__.py @@ -0,0 +1,46 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Intrastat Product module for OpenERP +# Copyright (C) 2011-2014 Akretion (http://www.akretion.com) +# @author Alexis de Lattre +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + + +{ + 'name': 'Intrastat Product', + 'version': '1.1', + 'category': 'Localisation/Report Intrastat', + 'license': 'AGPL-3', + 'summary': 'Base module for Intrastat Product', + 'description': """ +This module contains the common objects for the Intrastat Product. +This module is country-independant. + +This module has been written by Alexis de Lattre from Akretion + + """, + 'author': 'Akretion', + 'website': 'http://www.akretion.com', + 'depends': ['intrastat_base'], + 'data': [ + 'intrastat_view.xml', + 'security/ir.model.access.csv', + ], + 'demo': ['intrastat_demo.xml'], + 'installable': True, +} diff --git a/intrastat_product/i18n/intrastat_product.pot b/intrastat_product/i18n/intrastat_product.pot new file mode 100644 index 0000000..15505ac --- /dev/null +++ b/intrastat_product/i18n/intrastat_product.pot @@ -0,0 +1,122 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * intrastat_product +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 8.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-11-28 22:48+0000\n" +"PO-Revision-Date: 2014-11-28 22:48+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: intrastat_product +#: help:product.category,intrastat_id:0 +msgid "Code from the Harmonised System. If this code is not set on the product itself, it will be read here, on the related product category." +msgstr "" + +#. module: intrastat_product +#: help:product.template,intrastat_id:0 +msgid "Code from the Harmonised System. Nomenclature is available from the World Customs Organisation, see http://www.wcoomd.org/. Some countries have made their own extensions to this nomenclature." +msgstr "" + +#. module: intrastat_product +#: field:report.intrastat.code,create_uid:0 +msgid "Created by" +msgstr "" + +#. module: intrastat_product +#: field:report.intrastat.code,create_date:0 +msgid "Created on" +msgstr "" + +#. module: intrastat_product +#: field:report.intrastat.code,description:0 +msgid "Description" +msgstr "" + +#. module: intrastat_product +#: help:report.intrastat.code,name:0 +msgid "Full length Harmonized System code (digits only). Full list is available from the World Customs Organisation, see http://www.wcoomd.org" +msgstr "" + +#. module: intrastat_product +#: model:ir.model,name:intrastat_product.model_report_intrastat_code +msgid "H.S. Code" +msgstr "" + +#. module: intrastat_product +#: field:report.intrastat.code,name:0 +msgid "H.S. code" +msgstr "" + +#. module: intrastat_product +#: code:addons/intrastat_product/intrastat.py:56 +#, python-format +msgid "H.S. codes should only contain digits. It is not the case of H.S. code '%s'." +msgstr "" + +#. module: intrastat_product +#: field:report.intrastat.code,id:0 +msgid "ID" +msgstr "" + +#. module: intrastat_product +#: model:ir.actions.act_window,name:intrastat_product.product_intrastat_code_act +#: model:ir.ui.menu,name:intrastat_product.product_intrastat_code_menu +#: field:product.category,intrastat_id:0 +#: field:product.template,intrastat_id:0 +#: view:report.intrastat.code:intrastat_product.product_intrastat_code_form +msgid "Intrastat Code" +msgstr "" + +#. module: intrastat_product +#: view:report.intrastat.code:intrastat_product.product_intrastat_code_tree +msgid "Intrastat Codes" +msgstr "" + +#. module: intrastat_product +#: view:product.category:intrastat_product.product_category_form_view +msgid "Intrastat Properties" +msgstr "" + +#. module: intrastat_product +#: field:report.intrastat.code,write_uid:0 +msgid "Last Updated by" +msgstr "" + +#. module: intrastat_product +#: field:report.intrastat.code,write_date:0 +msgid "Last Updated on" +msgstr "" + +#. module: intrastat_product +#: model:ir.model,name:intrastat_product.model_product_category +msgid "Product Category" +msgstr "" + +#. module: intrastat_product +#: model:ir.model,name:intrastat_product.model_product_template +msgid "Product Template" +msgstr "" + +#. module: intrastat_product +#: view:report.intrastat.code:intrastat_product.product_intrastat_code_search +msgid "Search Intrastat Codes" +msgstr "" + +#. module: intrastat_product +#: help:report.intrastat.code,description:0 +msgid "Short text description of the H.S. category" +msgstr "" + +#. module: intrastat_product +#: sql_constraint:report.intrastat.code:0 +msgid "This H.S. code already exists in Odoo !" +msgstr "" + diff --git a/intrastat_product/intrastat.py b/intrastat_product/intrastat.py new file mode 100644 index 0000000..11fd2f2 --- /dev/null +++ b/intrastat_product/intrastat.py @@ -0,0 +1,84 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Intrastat Product module for OpenERP +# Copyright (C) 2004-2009 Tiny SPRL (http://tiny.be) +# Copyright (C) 2010-2014 Akretion (http://www.akretion.com) +# @author Alexis de Lattre +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp import models, fields, api, _ +from openerp.exceptions import Warning + + +class ReportIntrastatCode(models.Model): + _name = "report.intrastat.code" + _description = "H.S. Code" + _order = "name" + + name = fields.Char( + string='H.S. code', required=True, + help="Full length Harmonized System code (digits only). Full list is " + "available from the World Customs Organisation, see " + "http://www.wcoomd.org") + description = fields.Char( + 'Description', help="Short text description of the H.S. category") + + @api.multi + @api.depends('name', 'description') + def name_get(self): + res = [] + for code in self: + name = code.name + if code.description: + name = u'%s %s' % (name, code.description) + res.append((code.id, name)) + return res + + @api.constrains('name') + def _hs_code(self): + if self.name and not self.name.isdigit(): + raise Warning( + _("H.S. codes should only contain digits. It is not the case " + "of H.S. code '%s'.") % self.name) + + _sql_constraints = [( + 'hs_code_uniq', + 'unique(name)', + 'This H.S. code already exists in Odoo !' + )] + + +class ProductTemplate(models.Model): + _inherit = "product.template" + + intrastat_id = fields.Many2one( + 'report.intrastat.code', string='Intrastat Code', + help="Code from the Harmonised System. Nomenclature is " + "available from the World Customs Organisation, see " + "http://www.wcoomd.org/. Some countries have made their own " + "extensions to this nomenclature.") + + +class ProductCategory(models.Model): + _inherit = "product.category" + + intrastat_id = fields.Many2one( + 'report.intrastat.code', string='Intrastat Code', + help="Code from the Harmonised System. If this code is not " + "set on the product itself, it will be read here, on the " + "related product category.") diff --git a/intrastat_product/intrastat_demo.xml b/intrastat_product/intrastat_demo.xml new file mode 100644 index 0000000..e831a6d --- /dev/null +++ b/intrastat_product/intrastat_demo.xml @@ -0,0 +1,64 @@ + + + + + + + + + 84715000 + Automatic data-processing machines (computers) + + + + 84717050 + Storage units + + + + 85340090 + Printed circuits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intrastat_product/intrastat_view.xml b/intrastat_product/intrastat_view.xml new file mode 100644 index 0000000..635724c --- /dev/null +++ b/intrastat_product/intrastat_view.xml @@ -0,0 +1,89 @@ + + + + + + + + + + intrastat.product.template.form + product.template + + + + + + + + + + + intrastat.product.category.form + product.category + + + + + + + + + + + + + intrastat.product.intrastat.code.search + report.intrastat.code + + + + + + + + + + intrastat.product.intrastat.code.tree + report.intrastat.code + + + + + + + + + + + fr.intrastat.product.intrastat.code.form + report.intrastat.code + +
+ + + + +
+
+
+ + + + Intrastat Code + report.intrastat.code + tree,form + + + + + +
+
diff --git a/intrastat_product/security/ir.model.access.csv b/intrastat_product/security/ir.model.access.csv new file mode 100644 index 0000000..1708adf --- /dev/null +++ b/intrastat_product/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_report_intrastat_code_sale_manager,Full access on report.intrastat.code to sale manager,model_report_intrastat_code,base.group_sale_manager,1,1,1,1 +access_report_intrastat_code_employee,Read access on report.intrastat.code to employee,model_report_intrastat_code,base.group_user,1,0,0,0 From 8ef3d81f024022c221eda73432f3dfc362cc34e2 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Mon, 1 Dec 2014 10:29:07 +0100 Subject: [PATCH 041/103] Rename field country_id to origin_country_id (TODO : write mig script) and move this field from l10n_fr_intrastat_product to intrastat_product --- intrastat_product/intrastat.py | 7 +++++++ intrastat_product/intrastat_demo.xml | 27 +++++++++++++++++++++++---- intrastat_product/intrastat_view.xml | 1 + 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/intrastat_product/intrastat.py b/intrastat_product/intrastat.py index 11fd2f2..b4f5d6c 100644 --- a/intrastat_product/intrastat.py +++ b/intrastat_product/intrastat.py @@ -72,6 +72,13 @@ class ProductTemplate(models.Model): "available from the World Customs Organisation, see " "http://www.wcoomd.org/. Some countries have made their own " "extensions to this nomenclature.") + origin_country_id = fields.Many2one( + 'res.country', string='Country of Origin', + help="Country of origin of the product i.e. product " + "'made in ____'. If you have different countries of origin " + "depending on the supplier from which you purchased the product, " + "leave this field empty and use the equivalent field on the " + "'product supplier info' form.") class ProductCategory(models.Model): diff --git a/intrastat_product/intrastat_demo.xml b/intrastat_product/intrastat_demo.xml index e831a6d..e0a8c33 100644 --- a/intrastat_product/intrastat_demo.xml +++ b/intrastat_product/intrastat_demo.xml @@ -26,39 +26,58 @@ + + 5 + + 6 - - - - + + 6.5 + + 0.5 + + 0.5 + + 0.5 + + 0.7 + + 0.8 + + + + 2 + + +
diff --git a/intrastat_product/intrastat_view.xml b/intrastat_product/intrastat_view.xml index 635724c..66c1a4f 100644 --- a/intrastat_product/intrastat_view.xml +++ b/intrastat_product/intrastat_view.xml @@ -17,6 +17,7 @@ + From a9792a52e89ed602f674a6cca958dec982678cc2 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Sat, 13 Dec 2014 00:58:38 +0100 Subject: [PATCH 042/103] Take into accout the remarks of Guewen --- intrastat_product/intrastat.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/intrastat_product/intrastat.py b/intrastat_product/intrastat.py index b4f5d6c..efcc04c 100644 --- a/intrastat_product/intrastat.py +++ b/intrastat_product/intrastat.py @@ -22,7 +22,7 @@ ############################################################################## from openerp import models, fields, api, _ -from openerp.exceptions import Warning +from openerp.exceptions import ValidationError class ReportIntrastatCode(models.Model): @@ -39,7 +39,6 @@ class ReportIntrastatCode(models.Model): 'Description', help="Short text description of the H.S. category") @api.multi - @api.depends('name', 'description') def name_get(self): res = [] for code in self: @@ -52,7 +51,7 @@ class ReportIntrastatCode(models.Model): @api.constrains('name') def _hs_code(self): if self.name and not self.name.isdigit(): - raise Warning( + raise ValidationError( _("H.S. codes should only contain digits. It is not the case " "of H.S. code '%s'.") % self.name) From 0adba342cc2cfaa29bc77d7b9788220d304d7dfe Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Sat, 13 Dec 2014 01:29:04 +0100 Subject: [PATCH 043/103] Move intrastat_code and uom_id of report.intrastat.code from l10n_fr_intrastat_product to intrastat_product, as discussed with Luc de Meyer --- intrastat_product/intrastat.py | 27 +++++++++++++++++++++++++-- intrastat_product/intrastat_demo.xml | 5 +++++ intrastat_product/intrastat_view.xml | 7 ++++++- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/intrastat_product/intrastat.py b/intrastat_product/intrastat.py index efcc04c..13ddd65 100644 --- a/intrastat_product/intrastat.py +++ b/intrastat_product/intrastat.py @@ -31,12 +31,24 @@ class ReportIntrastatCode(models.Model): _order = "name" name = fields.Char( - string='H.S. code', required=True, + string='H.S. code', help="Full length Harmonized System code (digits only). Full list is " "available from the World Customs Organisation, see " "http://www.wcoomd.org") description = fields.Char( 'Description', help="Short text description of the H.S. category") + intrastat_code = fields.Char( + string='European Intrastat Code', size=9, required=True, + help="Code used for the Intrastat declaration. Must be part " + "of the 'Combined Nomenclature' (CN), cf " + "http://en.wikipedia.org/wiki/Combined_Nomenclature" + "Must have 8 digits with sometimes a 9th digit.") + intrastat_uom_id = fields.Many2one( + 'product.uom', string='UoM for Intrastat Report', + help="Select the unit of measure if one is required for " + "this particular Intrastat Code (other than the weight in Kg). " + "If no particular unit of measure is required, leave empty.") + active = fields.Boolean(default=True) @api.multi def name_get(self): @@ -48,12 +60,23 @@ class ReportIntrastatCode(models.Model): res.append((code.id, name)) return res - @api.constrains('name') + @api.constrains('name', 'intrastat_code') def _hs_code(self): if self.name and not self.name.isdigit(): raise ValidationError( _("H.S. codes should only contain digits. It is not the case " "of H.S. code '%s'.") % self.name) + if self.intrastat_code and not self.intrastat_code.isdigit(): + raise ValidationError( + _("The field Intrastat Code should only contain digits. " + "It is not the case of Intrastat Code '%s'.") + % self.intrastat_code) + if self.intrastat_code and len(self.intrastat_code) not in (8, 9): + raise ValidationError( + _("The field Intrastat Code should " + "contain 8 or 9 digits. It is not the case of " + "Intrastat Code '%s'.") + % self.intrastat_code) _sql_constraints = [( 'hs_code_uniq', diff --git a/intrastat_product/intrastat_demo.xml b/intrastat_product/intrastat_demo.xml index e0a8c33..b5ae41b 100644 --- a/intrastat_product/intrastat_demo.xml +++ b/intrastat_product/intrastat_demo.xml @@ -11,16 +11,21 @@ 84715000 + 84715000 + Automatic data-processing machines (computers) 84717050 + 84717050 + Storage units 85340090 + 85340090 Printed circuits diff --git a/intrastat_product/intrastat_view.xml b/intrastat_product/intrastat_view.xml index 66c1a4f..da54ba6 100644 --- a/intrastat_product/intrastat_view.xml +++ b/intrastat_product/intrastat_view.xml @@ -43,7 +43,7 @@ + filter_domain="['|', '|', ('name', 'like', self), ('intrastat_code', 'like', self), ('description', 'ilike', self)]"/> @@ -55,6 +55,8 @@ + + @@ -68,7 +70,10 @@
+ + +
From d72091d4058bd56a65dbbdd3091ab4eb7debff78 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Sat, 27 Dec 2014 00:08:33 +0100 Subject: [PATCH 044/103] intrastat_base + l10n_fr_intrastat_service : port to new API --- intrastat_base/__init__.py | 4 +- intrastat_base/__openerp__.py | 4 +- intrastat_base/company.py | 71 +++++------ intrastat_base/company_view.xml | 2 +- intrastat_base/country.py | 19 ++- intrastat_base/country_view.xml | 2 +- intrastat_base/intrastat_common.py | 189 +++++++++++++---------------- intrastat_base/intrastat_demo.xml | 2 +- intrastat_base/intrastat_menu.xml | 2 +- intrastat_base/product.py | 62 ++++------ intrastat_base/tax.py | 20 ++- intrastat_base/tax_view.xml | 5 +- 12 files changed, 164 insertions(+), 218 deletions(-) diff --git a/intrastat_base/__init__.py b/intrastat_base/__init__.py index 3070e32..21b2067 100644 --- a/intrastat_base/__init__.py +++ b/intrastat_base/__init__.py @@ -1,8 +1,8 @@ # -*- encoding: utf-8 -*- ############################################################################## # -# Report intrastat base module for OpenERP -# Copyright (C) 2011-2013 Akretion (http://www.akretion.com) +# Report intrastat base module for Odoo +# Copyright (C) 2011-2014 Akretion (http://www.akretion.com) # @author Alexis de Lattre # # This program is free software: you can redistribute it and/or modify diff --git a/intrastat_base/__openerp__.py b/intrastat_base/__openerp__.py index c9dd90d..179cb4a 100644 --- a/intrastat_base/__openerp__.py +++ b/intrastat_base/__openerp__.py @@ -1,8 +1,8 @@ # -*- encoding: utf-8 -*- ############################################################################## # -# Report intrastat base module for OpenERP -# Copyright (C) 2011-2013 Akretion (http://www.akretion.com) +# Report intrastat base module for Odoo +# Copyright (C) 2011-2014 Akretion (http://www.akretion.com) # @author Alexis de Lattre # # This program is free software: you can redistribute it and/or modify diff --git a/intrastat_base/company.py b/intrastat_base/company.py index e475544..9fea8e4 100644 --- a/intrastat_base/company.py +++ b/intrastat_base/company.py @@ -1,8 +1,8 @@ # -*- encoding: utf-8 -*- ############################################################################## # -# Intrastat base module for OpenERP -# Copyright (C) 2013 Akretion (http://www.akretion.com) +# Intrastat base module for Odoo +# Copyright (C) 2013-2014 Akretion (http://www.akretion.com) # @author Alexis de Lattre # # This program is free software: you can redistribute it and/or modify @@ -20,48 +20,37 @@ # ############################################################################## -from openerp.osv import orm, fields -from openerp.tools.translate import _ +from openerp import models, fields, api, _ +from openerp.exceptions import ValidationError -class res_company(orm.Model): +class ResCompany(models.Model): _inherit = "res.company" - def _compute_intrastat_email_list( - self, cr, uid, ids, name, arg, context=None): - result = {} - for company in self.browse(cr, uid, ids, context=context): - result[company.id] = '' - for user in company.intrastat_remind_user_ids: - if result[company.id]: - result[company.id] += ',%s' % (user.email) - else: - result[company.id] = user.email - return result + @api.one + @api.depends( + 'intrastat_remind_user_ids', 'intrastat_remind_user_ids.email') + def _compute_intrastat_email_list(self): + emails = [] + for user in self.intrastat_remind_user_ids: + if user.email: + emails.append(user.email) + self.intrastat_email_list = ','.join(emails) - _columns = { - 'intrastat_remind_user_ids': fields.many2many( - 'res.users', id1='company_id', id2='user_id', - string="Users Receiving the Intrastat Reminder", - help="List of OpenERP users who will receive a notification to " - "remind them about the Intrastat declaration."), - 'intrastat_email_list': fields.function( - _compute_intrastat_email_list, type='char', size=1000, - string='List of emails of Users Receiving the Intrastat Reminder'), - } + intrastat_remind_user_ids = fields.Many2many( + 'res.users', column1='company_id', column2='user_id', + string="Users Receiving the Intrastat Reminder", + help="List of OpenERP users who will receive a notification to " + "remind them about the Intrastat declaration.") + intrastat_email_list = fields.Char( + compute='_compute_intrastat_email_list', + string='List of emails of Users Receiving the Intrastat Reminder') - def _check_intrastat_remind_users(self, cr, uid, ids): - for company in self.browse(cr, uid, ids): - for user in company.intrastat_remind_user_ids: - if not user.email: - raise orm.except_orm( - _('Error :'), - _("Missing e-mail address on user '%s'.") - % (user.name)) - return True - - _constraints = [( - _check_intrastat_remind_users, - "Wrong configuration of the Users Receiving the Intrastat Reminder", - ['intrastat_remind_user_ids'] - )] + @api.one + @api.constrains('intrastat_remind_user_ids') + def _check_intrastat_remind_users(self): + for user in self.intrastat_remind_user_ids: + if not user.email: + raise ValidationError( + _("Missing e-mail address on user '%s'.") + % (user.name)) diff --git a/intrastat_base/company_view.xml b/intrastat_base/company_view.xml index 650d492..87933f4 100644 --- a/intrastat_base/company_view.xml +++ b/intrastat_base/company_view.xml @@ -1,7 +1,7 @@ diff --git a/intrastat_base/country.py b/intrastat_base/country.py index e967e92..7f03e5d 100644 --- a/intrastat_base/country.py +++ b/intrastat_base/country.py @@ -1,8 +1,8 @@ # -*- encoding: utf-8 -*- ############################################################################## # -# Report intrastat base module for OpenERP -# Copyright (C) 2011-2013 Akretion (http://www.akretion.com). +# Report intrastat base module for Odoo +# Copyright (C) 2011-2014 Akretion (http://www.akretion.com). # @author Alexis de Lattre # # This program is free software: you can redistribute it and/or modify @@ -20,17 +20,12 @@ # ############################################################################## -from openerp.osv import orm, fields +from openerp import models, fields -class res_country(orm.Model): +class ResCountry(models.Model): _inherit = 'res.country' - _columns = { - 'intrastat': fields.boolean( - 'EU Country', - help="Set to True for all European Union countries."), - } - _defaults = { - 'intrastat': False, - } + intrastat = fields.Boolean( + string='EU Country', + help="Set to True for all European Union countries.") diff --git a/intrastat_base/country_view.xml b/intrastat_base/country_view.xml index a8c9da2..d887a22 100644 --- a/intrastat_base/country_view.xml +++ b/intrastat_base/country_view.xml @@ -1,7 +1,7 @@ diff --git a/intrastat_base/intrastat_common.py b/intrastat_base/intrastat_common.py index 2129f8d..fa65afe 100644 --- a/intrastat_base/intrastat_common.py +++ b/intrastat_base/intrastat_common.py @@ -1,8 +1,8 @@ # -*- encoding: utf-8 -*- ############################################################################## # -# Report intrastat base module for OpenERP -# Copyright (C) 2010-2013 Akretion (http://www.akretion.com/). +# Report intrastat base module for Odoo +# Copyright (C) 2010-2014 Akretion (http://www.akretion.com/). # @author Alexis de Lattre # # This program is free software: you can redistribute it and/or modify @@ -20,9 +20,9 @@ # ############################################################################## -from openerp.osv import orm -from openerp.tools.translate import _ -from openerp import tools +from openerp import models, api, tools, _ +from openerp.tools import DEFAULT_SERVER_DATE_FORMAT +from openerp.exceptions import Warning, ValidationError from datetime import datetime from dateutil.relativedelta import relativedelta import logging @@ -30,71 +30,64 @@ import logging logger = logging.getLogger(__name__) -class report_intrastat_common(orm.TransientModel): +class ReportIntrastatCommon(models.AbstractModel): _name = "report.intrastat.common" _description = "Common functions for intrastat reports for products " "and services" - def _compute_numbers(self, cr, uid, ids, object, context=None): - result = {} - for intrastat in object.browse(cr, uid, ids, context=context): - total_amount = 0.0 - num_lines = 0 - for line in intrastat.intrastat_line_ids: - total_amount += line.amount_company_currency - num_lines += 1 - result[intrastat.id] = { - 'num_lines': num_lines, - 'total_amount': total_amount, - } - return result + @api.one + @api.depends( + 'intrastat_line_ids', 'intrastat_line_ids.amount_company_currency') + def _compute_numbers(self): + total_amount = 0.0 + num_lines = 0 + for line in self.intrastat_line_ids: + total_amount += line.amount_company_currency + num_lines += 1 + self.num_lines = num_lines + self.total_amount = total_amount - def _compute_dates(self, cr, uid, ids, object, context=None): - result = {} - for intrastat in object.browse(cr, uid, ids, context=context): - start_date_datetime = datetime.strptime( - intrastat.start_date, '%Y-%m-%d') - end_date_str = datetime.strftime( - start_date_datetime + relativedelta(day=31), '%Y-%m-%d') - result[intrastat.id] = { - 'end_date': end_date_str, - 'year_month': start_date_datetime.strftime('%Y-%m'), - } - return result + @api.one + @api.depends('start_date') + def _compute_dates(self): + start_date_dt = datetime.strptime( + self.start_date, DEFAULT_SERVER_DATE_FORMAT) + self.end_date = datetime.strftime( + start_date_dt + relativedelta(day=31), DEFAULT_SERVER_DATE_FORMAT) + self.year_month = start_date_dt.strftime('%Y-%m') - def _check_start_date(self, cr, uid, ids, object, context=None): + @api.one + @api.constrains('start_date') + def _check_start_date(self): '''Check that the start date is the first day of the month''' - for date_to_check in object.read( - cr, uid, ids, ['start_date'], context=context): - datetime_to_check = datetime.strptime( - date_to_check['start_date'], '%Y-%m-%d') - if datetime_to_check.day != 1: - return False - return True + datetime_to_check = datetime.strptime( + self.start_date, DEFAULT_SERVER_DATE_FORMAT) + if datetime_to_check.day != 1: + return ValidationError( + _('The start date must be the first day of the month')) - def _check_generate_lines(self, cr, uid, intrastat, context=None): - if not intrastat.company_id.country_id: - raise orm.except_orm( - _('Error :'), + @api.one + def _check_generate_lines(self): + if not self.company_id.country_id: + raise Warning( _("The country is not set on the company '%s'.") - % intrastat.company_id.name) - if not intrastat.currency_id.name == 'EUR': - raise orm.except_orm( - _('Error :'), + % self.company_id.name) + if self.currency_id.name != 'EUR': + raise Warning( _("The company currency must be 'EUR', but is currently '%s'.") - % intrastat.currency_id.name) + % self.currency_id.name) return True - def _check_generate_xml(self, cr, uid, intrastat, context=None): - if not intrastat.company_id.partner_id.vat: - raise orm.except_orm( - _('Error :'), + @api.one + def _check_generate_xml(self): + if not self.company_id.partner_id.vat: + raise Warning( _("The VAT number is not set for the partner '%s'.") - % intrastat.company_id.partner_id.name) + % self.company_id.partner_id.name) return True - def _check_xml_schema( - self, cr, uid, xml_root, xml_string, xsd_file, context=None): + @api.model + def _check_xml_schema(self, xml_root, xml_string, xsd_file): '''Validate the XML file against the XSD''' from lxml import etree xsd_etree_obj = etree.parse( @@ -104,13 +97,12 @@ class report_intrastat_common(orm.TransientModel): official_schema.assertValid(xml_root) except Exception, e: # if the validation of the XSD fails, we arrive here - _logger = logging.getLogger(__name__) - _logger.warning( + logger = logging.getLogger(__name__) + logger.warning( "The XML file is invalid against the XML Schema Definition") - _logger.warning(xml_string) - _logger.warning(e) - raise orm.except_orm( - _('Error :'), + logger.warning(xml_string) + logger.warning(e) + raise Warning( _("The generated XML file is not valid against the official " "XML Schema Definition. The generated XML file and the " "full error have been written in the server logs. " @@ -119,39 +111,29 @@ class report_intrastat_common(orm.TransientModel): % str(e)) return True - def _attach_xml_file( - self, cr, uid, ids, object, xml_string, start_date_datetime, - declaration_name, context=None): + @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 - assert len(ids) == 1, "Only one ID accepted" - filename = '%s_%s.xml' % ( - datetime.strftime(start_date_datetime, '%Y-%m'), - declaration_name) - if not context: - context = {} - context.update({ - 'default_res_id': ids[0], - 'default_res_model': object._name - }) - attach_id = self.pool['ir.attachment'].create( - cr, uid, { - 'name': filename, - 'datas': base64.encodestring(xml_string), - 'datas_fname': filename}, - context=context) - return attach_id + filename = '%s_%s.xml' % (self.year_month, declaration_name) + attach = self.with_context( + default_res_id=self.id, + default_res_model=self._name).env['ir.attachment'].create({ + 'name': filename, + 'datas': base64.encodestring(xml_string), + 'datas_fname': filename}) + return attach.id - def _open_attach_view( - self, cr, uid, attach_id, title='XML file', context=None): + @api.model + def _open_attach_view(self, attach_id, title='XML file'): '''Returns an action which opens the form view of the ''' '''corresponding attachement''' action = { 'name': title, 'view_type': 'form', - 'view_mode': 'form,tree', - 'view_id': False, + 'view_mode': 'form', 'res_model': 'ir.attachment', 'type': 'ir.actions.act_window', 'nodestroy': True, @@ -160,30 +142,27 @@ class report_intrastat_common(orm.TransientModel): } return action - def partner_on_change(self, cr, uid, ids, partner_id=False, context=None): - result = {} - result['value'] = {} - if partner_id: - company = self.pool['res.partner'].read( - cr, uid, partner_id, ['vat'], context=context) - result['value']['partner_vat'] = company['vat'] - return result - - def send_reminder_email( - self, cr, uid, company, module_name, template_xmlid, - intrastat_id, context=None): - template_model, template_id =\ - self.pool['ir.model.data'].get_object_reference( - cr, uid, module_name, template_xmlid) - assert template_model == 'email.template', 'Wrong model' - if company.intrastat_remind_user_ids: + @api.one + def send_reminder_email(self, mail_template_xmlid): + mail_template = self.env.ref(mail_template_xmlid) + if self.company_id.intrastat_remind_user_ids: self.pool['email.template'].send_mail( - cr, uid, template_id, intrastat_id, context=context) + self._cr, self._uid, mail_template.id, self.id, + context=self._context) logger.info( 'Intrastat Reminder email has been sent (XMLID: %s).' - % template_xmlid) + % mail_template_xmlid) else: logger.warning( 'The list of users receiving the Intrastat Reminder is empty ' - 'on company %s' % company.name) + 'on company %s' % self.company_id.name) return True + + @api.multi + def unlink(self): + for intrastat in self: + if intrastat.state == 'done': + raise Warning( + _('Cannot delete the declaration %s ' + 'because it is in Done state') % self.year_month) + return super(ReportIntrastatCommon, self).unlink() diff --git a/intrastat_base/intrastat_demo.xml b/intrastat_base/intrastat_demo.xml index 07c68ab..953d92b 100644 --- a/intrastat_base/intrastat_demo.xml +++ b/intrastat_base/intrastat_demo.xml @@ -1,7 +1,7 @@ diff --git a/intrastat_base/intrastat_menu.xml b/intrastat_base/intrastat_menu.xml index ce05472..85303c1 100644 --- a/intrastat_base/intrastat_menu.xml +++ b/intrastat_base/intrastat_menu.xml @@ -1,7 +1,7 @@ diff --git a/intrastat_base/product.py b/intrastat_base/product.py index 1798280..ca1652e 100644 --- a/intrastat_base/product.py +++ b/intrastat_base/product.py @@ -2,7 +2,7 @@ ############################################################################## # # Report intrastat base module for OpenERP -# Copyright (C) 2010-2013 Akretion (http://www.akretion.com/) +# Copyright (C) 2010-2014 Akretion (http://www.akretion.com/) # @author Alexis de Lattre # # This program is free software: you can redistribute it and/or modify @@ -20,44 +20,32 @@ # ############################################################################## -from openerp.osv import orm, fields -from openerp.tools.translate import _ +from openerp import models, fields, api, _ +from openerp.exceptions import ValidationError -class product_template(orm.Model): +class ProductTemplate(models.Model): _inherit = "product.template" - _columns = { - 'exclude_from_intrastat': fields.boolean( - 'Exclude from Intrastat reports', - help="If set to True, the product or service will not be " - "taken into account for Intrastat Product or Service reports. " - "So you should leave this field to False unless you have a " - "very good reason."), - 'is_accessory_cost': fields.boolean( - 'Is accessory cost', - help="Activate this option for shipping costs, packaging " - "costs and all services related to the sale of products. " - "This option is used for Intrastat reports."), - } - _defaults = { - 'exclude_from_intrastat': False, - } + exclude_from_intrastat = fields.Boolean( + string='Exclude from Intrastat reports', + help="If set to True, the product or service will not be " + "taken into account for Intrastat Product or Service reports. " + "So you should leave this field to False unless you have a " + "very good reason.") + is_accessory_cost = fields.Boolean( + string='Is accessory cost', + help="Activate this option for shipping costs, packaging " + "costs and all services related to the sale of products. " + "This option is used for Intrastat reports.") - def _check_accessory_cost(self, cr, uid, ids): - for product in self.browse(cr, uid, ids): - if product.is_accessory_cost and product.type != 'service': - raise orm.except_orm( - _('Error :'), - _("The option 'Is accessory cost?' should only be " - "activated on 'Service' products. You have activated " - "this option for the product '%s' which is of type " - "'%s'" - % (product.name, product.type))) - return True - - _constraints = [( - _check_accessory_cost, - "Wrong configuration of the product", - ['is_accessory_cost', 'type'] - )] + @api.one + @api.constrains('type', 'is_accessory_cost') + def _check_accessory_cost(self): + if self.is_accessory_cost and self.type != 'service': + raise ValidationError( + _("The option 'Is accessory cost?' should only be " + "activated on 'Service' products. You have activated " + "this option for the product '%s' which is of type " + "'%s'" + % (self.name, self.type))) diff --git a/intrastat_base/tax.py b/intrastat_base/tax.py index fae6a3d..2b98678 100644 --- a/intrastat_base/tax.py +++ b/intrastat_base/tax.py @@ -1,8 +1,8 @@ # -*- encoding: utf-8 -*- ############################################################################## # -# Report intrastat base module for OpenERP -# Copyright (C) 2011-2013 Akretion (http://www.akretion.com). +# Report intrastat base module for Odoo +# Copyright (C) 2011-2014 Akretion (http://www.akretion.com). # @author Alexis de Lattre # # This program is free software: you can redistribute it and/or modify @@ -20,16 +20,14 @@ # ############################################################################## -from openerp.osv import orm, fields +from openerp import models, fields -class account_tax(orm.Model): +class AccountTax(models.Model): _inherit = "account.tax" - _columns = { - 'exclude_from_intrastat_if_present': fields.boolean( - 'Exclude invoice line from intrastat if this tax is present', - help="If this tax is present on an invoice line, this invoice " - "line will be skipped when generating Intrastat Product or " - "Service lines from invoices."), - } + exclude_from_intrastat_if_present = fields.Boolean( + string='Exclude invoice line from intrastat if this tax is present', + help="If this tax is present on an invoice line, this invoice " + "line will be skipped when generating Intrastat Product or " + "Service lines from invoices.") diff --git a/intrastat_base/tax_view.xml b/intrastat_base/tax_view.xml index e927aa5..5defe29 100644 --- a/intrastat_base/tax_view.xml +++ b/intrastat_base/tax_view.xml @@ -1,7 +1,7 @@ @@ -13,14 +13,11 @@ intrastat.base.tax account.tax - form - - From 8cc3851be68537477a6ed8071452facf14e4e81a Mon Sep 17 00:00:00 2001 From: Ronald Portier Date: Wed, 4 Feb 2015 20:11:31 +0100 Subject: [PATCH 045/103] Make dutch ICP report workable on odoo 8.0 [FIX] Some small changes in base, to make check_generate_lines better reusable (no need to force currency field on report), and do away with '_' before method name, as method should not be private, as it is called from other classes. --- intrastat_base/intrastat_common.py | 199 +++++++++++++++++------------ 1 file changed, 115 insertions(+), 84 deletions(-) diff --git a/intrastat_base/intrastat_common.py b/intrastat_base/intrastat_common.py index fa65afe..47c10ac 100644 --- a/intrastat_base/intrastat_common.py +++ b/intrastat_base/intrastat_common.py @@ -1,8 +1,8 @@ # -*- encoding: utf-8 -*- ############################################################################## # -# Report intrastat base module for Odoo -# Copyright (C) 2010-2014 Akretion (http://www.akretion.com/). +# Report intrastat base module for OpenERP +# Copyright (C) 2010-2013 Akretion (http://www.akretion.com/). # @author Alexis de Lattre # # This program is free software: you can redistribute it and/or modify @@ -20,9 +20,9 @@ # ############################################################################## -from openerp import models, api, tools, _ -from openerp.tools import DEFAULT_SERVER_DATE_FORMAT -from openerp.exceptions import Warning, ValidationError +from openerp.osv import orm +from openerp.tools.translate import _ +from openerp import tools from datetime import datetime from dateutil.relativedelta import relativedelta import logging @@ -30,64 +30,81 @@ import logging logger = logging.getLogger(__name__) -class ReportIntrastatCommon(models.AbstractModel): +class report_intrastat_common(orm.TransientModel): _name = "report.intrastat.common" _description = "Common functions for intrastat reports for products " "and services" - @api.one - @api.depends( - 'intrastat_line_ids', 'intrastat_line_ids.amount_company_currency') - def _compute_numbers(self): - total_amount = 0.0 - num_lines = 0 - for line in self.intrastat_line_ids: - total_amount += line.amount_company_currency - num_lines += 1 - self.num_lines = num_lines - self.total_amount = total_amount + def _compute_numbers(self, cr, uid, ids, object, context=None): + result = {} + for intrastat in object.browse(cr, uid, ids, context=context): + total_amount = 0.0 + num_lines = 0 + for line in intrastat.intrastat_line_ids: + total_amount += line.amount_company_currency + num_lines += 1 + result[intrastat.id] = { + 'num_lines': num_lines, + 'total_amount': total_amount, + } + return result - @api.one - @api.depends('start_date') - def _compute_dates(self): - start_date_dt = datetime.strptime( - self.start_date, DEFAULT_SERVER_DATE_FORMAT) - self.end_date = datetime.strftime( - start_date_dt + relativedelta(day=31), DEFAULT_SERVER_DATE_FORMAT) - self.year_month = start_date_dt.strftime('%Y-%m') + def _compute_dates(self, cr, uid, ids, object, context=None): + result = {} + for intrastat in object.browse(cr, uid, ids, context=context): + start_date_datetime = datetime.strptime( + intrastat.start_date, '%Y-%m-%d') + end_date_str = datetime.strftime( + start_date_datetime + relativedelta(day=31), '%Y-%m-%d') + result[intrastat.id] = { + 'end_date': end_date_str, + 'year_month': start_date_datetime.strftime('%Y-%m'), + } + return result - @api.one - @api.constrains('start_date') - def _check_start_date(self): + def _check_start_date(self, cr, uid, ids, object, context=None): '''Check that the start date is the first day of the month''' - datetime_to_check = datetime.strptime( - self.start_date, DEFAULT_SERVER_DATE_FORMAT) - if datetime_to_check.day != 1: - return ValidationError( - _('The start date must be the first day of the month')) + for date_to_check in object.read( + cr, uid, ids, ['start_date'], context=context): + datetime_to_check = datetime.strptime( + date_to_check['start_date'], '%Y-%m-%d') + if datetime_to_check.day != 1: + return False + return True - @api.one - def _check_generate_lines(self): - if not self.company_id.country_id: - raise Warning( + def check_generate_lines(self, cr, uid, intrastat, context=None): + """Check wether all requirements are met for generating lines.""" + if not intrastat.company_id: + # Should not be possible, but just in case: + raise orm.except_orm( + _('Error :'), + _("Company not yet set on intrastat report.") + ) + company_obj = intrastat.company_id # Simplify references + if not company_obj.country_id: + raise orm.except_orm( + _('Error :'), _("The country is not set on the company '%s'.") - % self.company_id.name) - if self.currency_id.name != 'EUR': - raise Warning( + % company_obj.name + ) + if not company_obj.currency_id.name == 'EUR': + raise orm.except_orm( + _('Error :'), _("The company currency must be 'EUR', but is currently '%s'.") - % self.currency_id.name) + % company_obj.currency_id.name + ) return True - @api.one - def _check_generate_xml(self): - if not self.company_id.partner_id.vat: - raise Warning( + def _check_generate_xml(self, cr, uid, intrastat, context=None): + if not intrastat.company_id.partner_id.vat: + raise orm.except_orm( + _('Error :'), _("The VAT number is not set for the partner '%s'.") - % self.company_id.partner_id.name) + % intrastat.company_id.partner_id.name) return True - @api.model - def _check_xml_schema(self, xml_root, xml_string, xsd_file): + def _check_xml_schema( + self, cr, uid, xml_root, xml_string, xsd_file, context=None): '''Validate the XML file against the XSD''' from lxml import etree xsd_etree_obj = etree.parse( @@ -97,12 +114,13 @@ class ReportIntrastatCommon(models.AbstractModel): official_schema.assertValid(xml_root) except Exception, e: # if the validation of the XSD fails, we arrive here - logger = logging.getLogger(__name__) - logger.warning( + _logger = logging.getLogger(__name__) + _logger.warning( "The XML file is invalid against the XML Schema Definition") - logger.warning(xml_string) - logger.warning(e) - raise Warning( + _logger.warning(xml_string) + _logger.warning(e) + raise orm.except_orm( + _('Error :'), _("The generated XML file is not valid against the official " "XML Schema Definition. The generated XML file and the " "full error have been written in the server logs. " @@ -111,29 +129,39 @@ class ReportIntrastatCommon(models.AbstractModel): % str(e)) return True - @api.multi - def _attach_xml_file(self, xml_string, declaration_name): + def _attach_xml_file( + self, cr, uid, ids, object, xml_string, start_date_datetime, + declaration_name, context=None): '''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.with_context( - default_res_id=self.id, - default_res_model=self._name).env['ir.attachment'].create({ - 'name': filename, - 'datas': base64.encodestring(xml_string), - 'datas_fname': filename}) - return attach.id + assert len(ids) == 1, "Only one ID accepted" + filename = '%s_%s.xml' % ( + datetime.strftime(start_date_datetime, '%Y-%m'), + declaration_name) + if not context: + context = {} + context.update({ + 'default_res_id': ids[0], + 'default_res_model': object._name + }) + attach_id = self.pool['ir.attachment'].create( + cr, uid, { + 'name': filename, + 'datas': base64.encodestring(xml_string), + 'datas_fname': filename}, + context=context) + return attach_id - @api.model - def _open_attach_view(self, attach_id, title='XML file'): + def _open_attach_view( + self, cr, uid, attach_id, title='XML file', context=None): '''Returns an action which opens the form view of the ''' '''corresponding attachement''' action = { 'name': title, 'view_type': 'form', - 'view_mode': 'form', + 'view_mode': 'form,tree', + 'view_id': False, 'res_model': 'ir.attachment', 'type': 'ir.actions.act_window', 'nodestroy': True, @@ -142,27 +170,30 @@ class ReportIntrastatCommon(models.AbstractModel): } return action - @api.one - def send_reminder_email(self, mail_template_xmlid): - mail_template = self.env.ref(mail_template_xmlid) - if self.company_id.intrastat_remind_user_ids: + def partner_on_change(self, cr, uid, ids, partner_id=False, context=None): + result = {} + result['value'] = {} + if partner_id: + company = self.pool['res.partner'].read( + cr, uid, partner_id, ['vat'], context=context) + result['value']['partner_vat'] = company['vat'] + return result + + def send_reminder_email( + self, cr, uid, company, module_name, template_xmlid, + intrastat_id, context=None): + template_model, template_id =\ + self.pool['ir.model.data'].get_object_reference( + cr, uid, module_name, template_xmlid) + assert template_model == 'email.template', 'Wrong model' + if company.intrastat_remind_user_ids: self.pool['email.template'].send_mail( - self._cr, self._uid, mail_template.id, self.id, - context=self._context) + cr, uid, template_id, intrastat_id, context=context) logger.info( 'Intrastat Reminder email has been sent (XMLID: %s).' - % mail_template_xmlid) + % template_xmlid) else: logger.warning( 'The list of users receiving the Intrastat Reminder is empty ' - 'on company %s' % self.company_id.name) + 'on company %s' % company.name) return True - - @api.multi - def unlink(self): - for intrastat in self: - if intrastat.state == 'done': - raise Warning( - _('Cannot delete the declaration %s ' - 'because it is in Done state') % self.year_month) - return super(ReportIntrastatCommon, self).unlink() From 21a3435d7a5855d8c782d8e723532ea37b8bcf69 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Sat, 7 Feb 2015 11:36:42 +0100 Subject: [PATCH 046/103] Continue the port to the new API Access for intrastat report to accounting user and not only accounting manager. --- intrastat_base/intrastat_common.py | 195 ++++++++++++----------------- 1 file changed, 80 insertions(+), 115 deletions(-) diff --git a/intrastat_base/intrastat_common.py b/intrastat_base/intrastat_common.py index 47c10ac..b6d8b2f 100644 --- a/intrastat_base/intrastat_common.py +++ b/intrastat_base/intrastat_common.py @@ -1,8 +1,8 @@ # -*- encoding: utf-8 -*- ############################################################################## # -# Report intrastat base module for OpenERP -# Copyright (C) 2010-2013 Akretion (http://www.akretion.com/). +# Report intrastat base module for Odoo +# Copyright (C) 2010-2014 Akretion (http://www.akretion.com/). # @author Alexis de Lattre # # This program is free software: you can redistribute it and/or modify @@ -20,9 +20,8 @@ # ############################################################################## -from openerp.osv import orm -from openerp.tools.translate import _ -from openerp import tools +from openerp import models, fields, api, tools, _ +from openerp.exceptions import Warning, ValidationError from datetime import datetime from dateutil.relativedelta import relativedelta import logging @@ -30,81 +29,61 @@ import logging logger = logging.getLogger(__name__) -class report_intrastat_common(orm.TransientModel): +class ReportIntrastatCommon(models.AbstractModel): _name = "report.intrastat.common" _description = "Common functions for intrastat reports for products " "and services" - def _compute_numbers(self, cr, uid, ids, object, context=None): - result = {} - for intrastat in object.browse(cr, uid, ids, context=context): - total_amount = 0.0 - num_lines = 0 - for line in intrastat.intrastat_line_ids: - total_amount += line.amount_company_currency - num_lines += 1 - result[intrastat.id] = { - 'num_lines': num_lines, - 'total_amount': total_amount, - } - return result + @api.one + @api.depends( + 'intrastat_line_ids', 'intrastat_line_ids.amount_company_currency') + def _compute_numbers(self): + total_amount = 0.0 + num_lines = 0 + for line in self.intrastat_line_ids: + total_amount += line.amount_company_currency + num_lines += 1 + self.num_lines = num_lines + self.total_amount = total_amount - def _compute_dates(self, cr, uid, ids, object, context=None): - result = {} - for intrastat in object.browse(cr, uid, ids, context=context): - start_date_datetime = datetime.strptime( - intrastat.start_date, '%Y-%m-%d') - end_date_str = datetime.strftime( - start_date_datetime + relativedelta(day=31), '%Y-%m-%d') - result[intrastat.id] = { - 'end_date': end_date_str, - 'year_month': start_date_datetime.strftime('%Y-%m'), - } - return result + @api.one + @api.depends('start_date') + def _compute_dates(self): + start_date_dt = fields.Date.from_string(self.start_date) + self.end_date = fields.Date.to_string( + start_date_dt + relativedelta(day=31)) + self.year_month = start_date_dt.strftime('%Y-%m') - def _check_start_date(self, cr, uid, ids, object, context=None): + @api.one + def _check_start_date(self): '''Check that the start date is the first day of the month''' - for date_to_check in object.read( - cr, uid, ids, ['start_date'], context=context): - datetime_to_check = datetime.strptime( - date_to_check['start_date'], '%Y-%m-%d') - if datetime_to_check.day != 1: - return False - return True + datetime_to_check = fields.Date.from_string(self.start_date) + if datetime_to_check.day != 1: + raise ValidationError( + _('The start date must be the first day of the month')) - def check_generate_lines(self, cr, uid, intrastat, context=None): - """Check wether all requirements are met for generating lines.""" - if not intrastat.company_id: - # Should not be possible, but just in case: - raise orm.except_orm( - _('Error :'), - _("Company not yet set on intrastat report.") - ) - company_obj = intrastat.company_id # Simplify references - if not company_obj.country_id: - raise orm.except_orm( - _('Error :'), + @api.one + def _check_generate_lines(self): + if not self.company_id.country_id: + raise Warning( _("The country is not set on the company '%s'.") - % company_obj.name - ) - if not company_obj.currency_id.name == 'EUR': - raise orm.except_orm( - _('Error :'), + % self.company_id.name) + if self.currency_id.name != 'EUR': + raise Warning( _("The company currency must be 'EUR', but is currently '%s'.") - % company_obj.currency_id.name - ) + % self.currency_id.name) return True - def _check_generate_xml(self, cr, uid, intrastat, context=None): - if not intrastat.company_id.partner_id.vat: - raise orm.except_orm( - _('Error :'), + @api.one + def _check_generate_xml(self): + if not self.company_id.partner_id.vat: + raise Warning( _("The VAT number is not set for the partner '%s'.") - % intrastat.company_id.partner_id.name) + % self.company_id.partner_id.name) return True - def _check_xml_schema( - self, cr, uid, xml_root, xml_string, xsd_file, context=None): + @api.model + def _check_xml_schema(self, xml_root, xml_string, xsd_file): '''Validate the XML file against the XSD''' from lxml import etree xsd_etree_obj = etree.parse( @@ -114,13 +93,12 @@ class report_intrastat_common(orm.TransientModel): official_schema.assertValid(xml_root) except Exception, e: # if the validation of the XSD fails, we arrive here - _logger = logging.getLogger(__name__) - _logger.warning( + logger = logging.getLogger(__name__) + logger.warning( "The XML file is invalid against the XML Schema Definition") - _logger.warning(xml_string) - _logger.warning(e) - raise orm.except_orm( - _('Error :'), + logger.warning(xml_string) + logger.warning(e) + raise Warning( _("The generated XML file is not valid against the official " "XML Schema Definition. The generated XML file and the " "full error have been written in the server logs. " @@ -129,39 +107,29 @@ class report_intrastat_common(orm.TransientModel): % str(e)) return True - def _attach_xml_file( - self, cr, uid, ids, object, xml_string, start_date_datetime, - declaration_name, context=None): + @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 - assert len(ids) == 1, "Only one ID accepted" - filename = '%s_%s.xml' % ( - datetime.strftime(start_date_datetime, '%Y-%m'), - declaration_name) - if not context: - context = {} - context.update({ - 'default_res_id': ids[0], - 'default_res_model': object._name - }) - attach_id = self.pool['ir.attachment'].create( - cr, uid, { - 'name': filename, - 'datas': base64.encodestring(xml_string), - 'datas_fname': filename}, - context=context) - return attach_id + filename = '%s_%s.xml' % (self.year_month, declaration_name) + attach = self.with_context( + default_res_id=self.id, + default_res_model=self._name).env['ir.attachment'].create({ + 'name': filename, + 'datas': base64.encodestring(xml_string), + 'datas_fname': filename}) + return attach.id - def _open_attach_view( - self, cr, uid, attach_id, title='XML file', context=None): + @api.model + def _open_attach_view(self, attach_id, title='XML file'): '''Returns an action which opens the form view of the ''' '''corresponding attachement''' action = { 'name': title, 'view_type': 'form', - 'view_mode': 'form,tree', - 'view_id': False, + 'view_mode': 'form', 'res_model': 'ir.attachment', 'type': 'ir.actions.act_window', 'nodestroy': True, @@ -170,30 +138,27 @@ class report_intrastat_common(orm.TransientModel): } return action - def partner_on_change(self, cr, uid, ids, partner_id=False, context=None): - result = {} - result['value'] = {} - if partner_id: - company = self.pool['res.partner'].read( - cr, uid, partner_id, ['vat'], context=context) - result['value']['partner_vat'] = company['vat'] - return result - - def send_reminder_email( - self, cr, uid, company, module_name, template_xmlid, - intrastat_id, context=None): - template_model, template_id =\ - self.pool['ir.model.data'].get_object_reference( - cr, uid, module_name, template_xmlid) - assert template_model == 'email.template', 'Wrong model' - if company.intrastat_remind_user_ids: + @api.one + def send_reminder_email(self, mail_template_xmlid): + mail_template = self.env.ref(mail_template_xmlid) + if self.company_id.intrastat_remind_user_ids: self.pool['email.template'].send_mail( - cr, uid, template_id, intrastat_id, context=context) + self._cr, self._uid, mail_template.id, self.id, + context=self._context) logger.info( 'Intrastat Reminder email has been sent (XMLID: %s).' - % template_xmlid) + % mail_template_xmlid) else: logger.warning( 'The list of users receiving the Intrastat Reminder is empty ' - 'on company %s' % company.name) + 'on company %s' % self.company_id.name) return True + + @api.multi + def unlink(self): + for intrastat in self: + if intrastat.state == 'done': + raise Warning( + _('Cannot delete the declaration %s ' + 'because it is in Done state') % self.year_month) + return super(ReportIntrastatCommon, self).unlink() From 23c54be82da47d03ef552b396fd68c35ae9c1ca2 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Mon, 9 Feb 2015 23:15:13 +0100 Subject: [PATCH 047/103] Continue port to new API + PEP8. First working version. --- intrastat_base/__openerp__.py | 3 +-- intrastat_product/__openerp__.py | 5 ++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/intrastat_base/__openerp__.py b/intrastat_base/__openerp__.py index 179cb4a..e795155 100644 --- a/intrastat_base/__openerp__.py +++ b/intrastat_base/__openerp__.py @@ -2,7 +2,7 @@ ############################################################################## # # Report intrastat base module for Odoo -# Copyright (C) 2011-2014 Akretion (http://www.akretion.com) +# Copyright (C) 2011-2015 Akretion (http://www.akretion.com) # @author Alexis de Lattre # # This program is free software: you can redistribute it and/or modify @@ -20,7 +20,6 @@ # ############################################################################## - { 'name': 'Intrastat Reporting Base', 'version': '1.1', diff --git a/intrastat_product/__openerp__.py b/intrastat_product/__openerp__.py index 5008ce6..6224d37 100644 --- a/intrastat_product/__openerp__.py +++ b/intrastat_product/__openerp__.py @@ -1,8 +1,8 @@ # -*- encoding: utf-8 -*- ############################################################################## # -# Intrastat Product module for OpenERP -# Copyright (C) 2011-2014 Akretion (http://www.akretion.com) +# Intrastat Product module for Odoo +# Copyright (C) 2011-2015 Akretion (http://www.akretion.com) # @author Alexis de Lattre # # This program is free software: you can redistribute it and/or modify @@ -20,7 +20,6 @@ # ############################################################################## - { 'name': 'Intrastat Product', 'version': '1.1', From 4443f9b4c5f80b1edb4faf43eb0254355ec84c78 Mon Sep 17 00:00:00 2001 From: Ronald Portier Date: Fri, 13 Feb 2015 11:24:14 +0100 Subject: [PATCH 048/103] Revert rename of _check_generate_lines to version withouth underscore. In pending merge request from Alexis, _check_generate_lines will no longer be called from outside the class, so no longer any need to change private function name convention to public name convention. This will also make it easier to merge all changes. --- intrastat_base/intrastat_common.py | 195 +++++++++++++++++------------ 1 file changed, 115 insertions(+), 80 deletions(-) diff --git a/intrastat_base/intrastat_common.py b/intrastat_base/intrastat_common.py index b6d8b2f..3db1764 100644 --- a/intrastat_base/intrastat_common.py +++ b/intrastat_base/intrastat_common.py @@ -1,8 +1,8 @@ # -*- encoding: utf-8 -*- ############################################################################## # -# Report intrastat base module for Odoo -# Copyright (C) 2010-2014 Akretion (http://www.akretion.com/). +# Report intrastat base module for OpenERP +# Copyright (C) 2010-2013 Akretion (http://www.akretion.com/). # @author Alexis de Lattre # # This program is free software: you can redistribute it and/or modify @@ -20,8 +20,9 @@ # ############################################################################## -from openerp import models, fields, api, tools, _ -from openerp.exceptions import Warning, ValidationError +from openerp.osv import orm +from openerp.tools.translate import _ +from openerp import tools from datetime import datetime from dateutil.relativedelta import relativedelta import logging @@ -29,61 +30,81 @@ import logging logger = logging.getLogger(__name__) -class ReportIntrastatCommon(models.AbstractModel): +class report_intrastat_common(orm.TransientModel): _name = "report.intrastat.common" _description = "Common functions for intrastat reports for products " "and services" - @api.one - @api.depends( - 'intrastat_line_ids', 'intrastat_line_ids.amount_company_currency') - def _compute_numbers(self): - total_amount = 0.0 - num_lines = 0 - for line in self.intrastat_line_ids: - total_amount += line.amount_company_currency - num_lines += 1 - self.num_lines = num_lines - self.total_amount = total_amount + def _compute_numbers(self, cr, uid, ids, object, context=None): + result = {} + for intrastat in object.browse(cr, uid, ids, context=context): + total_amount = 0.0 + num_lines = 0 + for line in intrastat.intrastat_line_ids: + total_amount += line.amount_company_currency + num_lines += 1 + result[intrastat.id] = { + 'num_lines': num_lines, + 'total_amount': total_amount, + } + return result - @api.one - @api.depends('start_date') - def _compute_dates(self): - start_date_dt = fields.Date.from_string(self.start_date) - self.end_date = fields.Date.to_string( - start_date_dt + relativedelta(day=31)) - self.year_month = start_date_dt.strftime('%Y-%m') + def _compute_dates(self, cr, uid, ids, object, context=None): + result = {} + for intrastat in object.browse(cr, uid, ids, context=context): + start_date_datetime = datetime.strptime( + intrastat.start_date, '%Y-%m-%d') + end_date_str = datetime.strftime( + start_date_datetime + relativedelta(day=31), '%Y-%m-%d') + result[intrastat.id] = { + 'end_date': end_date_str, + 'year_month': start_date_datetime.strftime('%Y-%m'), + } + return result - @api.one - def _check_start_date(self): + def _check_start_date(self, cr, uid, ids, object, context=None): '''Check that the start date is the first day of the month''' - datetime_to_check = fields.Date.from_string(self.start_date) - if datetime_to_check.day != 1: - raise ValidationError( - _('The start date must be the first day of the month')) + for date_to_check in object.read( + cr, uid, ids, ['start_date'], context=context): + datetime_to_check = datetime.strptime( + date_to_check['start_date'], '%Y-%m-%d') + if datetime_to_check.day != 1: + return False + return True - @api.one - def _check_generate_lines(self): - if not self.company_id.country_id: - raise Warning( + def _check_generate_lines(self, cr, uid, intrastat, context=None): + """Check wether all requirements are met for generating lines.""" + if not intrastat.company_id: + # Should not be possible, but just in case: + raise orm.except_orm( + _('Error :'), + _("Company not yet set on intrastat report.") + ) + company_obj = intrastat.company_id # Simplify references + if not company_obj.country_id: + raise orm.except_orm( + _('Error :'), _("The country is not set on the company '%s'.") - % self.company_id.name) - if self.currency_id.name != 'EUR': - raise Warning( + % company_obj.name + ) + if not company_obj.currency_id.name == 'EUR': + raise orm.except_orm( + _('Error :'), _("The company currency must be 'EUR', but is currently '%s'.") - % self.currency_id.name) + % company_obj.currency_id.name + ) return True - @api.one - def _check_generate_xml(self): - if not self.company_id.partner_id.vat: - raise Warning( + def _check_generate_xml(self, cr, uid, intrastat, context=None): + if not intrastat.company_id.partner_id.vat: + raise orm.except_orm( + _('Error :'), _("The VAT number is not set for the partner '%s'.") - % self.company_id.partner_id.name) + % intrastat.company_id.partner_id.name) return True - @api.model - def _check_xml_schema(self, xml_root, xml_string, xsd_file): + def _check_xml_schema( + self, cr, uid, xml_root, xml_string, xsd_file, context=None): '''Validate the XML file against the XSD''' from lxml import etree xsd_etree_obj = etree.parse( @@ -93,12 +114,13 @@ class ReportIntrastatCommon(models.AbstractModel): official_schema.assertValid(xml_root) except Exception, e: # if the validation of the XSD fails, we arrive here - logger = logging.getLogger(__name__) - logger.warning( + _logger = logging.getLogger(__name__) + _logger.warning( "The XML file is invalid against the XML Schema Definition") - logger.warning(xml_string) - logger.warning(e) - raise Warning( + _logger.warning(xml_string) + _logger.warning(e) + raise orm.except_orm( + _('Error :'), _("The generated XML file is not valid against the official " "XML Schema Definition. The generated XML file and the " "full error have been written in the server logs. " @@ -107,29 +129,39 @@ class ReportIntrastatCommon(models.AbstractModel): % str(e)) return True - @api.multi - def _attach_xml_file(self, xml_string, declaration_name): + def _attach_xml_file( + self, cr, uid, ids, object, xml_string, start_date_datetime, + declaration_name, context=None): '''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.with_context( - default_res_id=self.id, - default_res_model=self._name).env['ir.attachment'].create({ - 'name': filename, - 'datas': base64.encodestring(xml_string), - 'datas_fname': filename}) - return attach.id + assert len(ids) == 1, "Only one ID accepted" + filename = '%s_%s.xml' % ( + datetime.strftime(start_date_datetime, '%Y-%m'), + declaration_name) + if not context: + context = {} + context.update({ + 'default_res_id': ids[0], + 'default_res_model': object._name + }) + attach_id = self.pool['ir.attachment'].create( + cr, uid, { + 'name': filename, + 'datas': base64.encodestring(xml_string), + 'datas_fname': filename}, + context=context) + return attach_id - @api.model - def _open_attach_view(self, attach_id, title='XML file'): + def _open_attach_view( + self, cr, uid, attach_id, title='XML file', context=None): '''Returns an action which opens the form view of the ''' '''corresponding attachement''' action = { 'name': title, 'view_type': 'form', - 'view_mode': 'form', + 'view_mode': 'form,tree', + 'view_id': False, 'res_model': 'ir.attachment', 'type': 'ir.actions.act_window', 'nodestroy': True, @@ -138,27 +170,30 @@ class ReportIntrastatCommon(models.AbstractModel): } return action - @api.one - def send_reminder_email(self, mail_template_xmlid): - mail_template = self.env.ref(mail_template_xmlid) - if self.company_id.intrastat_remind_user_ids: + def partner_on_change(self, cr, uid, ids, partner_id=False, context=None): + result = {} + result['value'] = {} + if partner_id: + company = self.pool['res.partner'].read( + cr, uid, partner_id, ['vat'], context=context) + result['value']['partner_vat'] = company['vat'] + return result + + def send_reminder_email( + self, cr, uid, company, module_name, template_xmlid, + intrastat_id, context=None): + template_model, template_id =\ + self.pool['ir.model.data'].get_object_reference( + cr, uid, module_name, template_xmlid) + assert template_model == 'email.template', 'Wrong model' + if company.intrastat_remind_user_ids: self.pool['email.template'].send_mail( - self._cr, self._uid, mail_template.id, self.id, - context=self._context) + cr, uid, template_id, intrastat_id, context=context) logger.info( 'Intrastat Reminder email has been sent (XMLID: %s).' - % mail_template_xmlid) + % template_xmlid) else: logger.warning( 'The list of users receiving the Intrastat Reminder is empty ' - 'on company %s' % self.company_id.name) + 'on company %s' % company.name) return True - - @api.multi - def unlink(self): - for intrastat in self: - if intrastat.state == 'done': - raise Warning( - _('Cannot delete the declaration %s ' - 'because it is in Done state') % self.year_month) - return super(ReportIntrastatCommon, self).unlink() From 29c1089717ea6a7e91d2d44fb727a96af72abe0a Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Tue, 14 Apr 2015 22:23:00 +0200 Subject: [PATCH 049/103] Use display_name instead of an inherit of name_get (better use of new API) Inherit write and create of intrastat codes to remove spaces (patch by Luc De Meyer from Noviat) Add O2M fields from intrastat code to products and product categs --- intrastat_product/intrastat.py | 38 ++++++++++++++++++++-------- intrastat_product/intrastat_view.xml | 6 +++++ 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/intrastat_product/intrastat.py b/intrastat_product/intrastat.py index 13ddd65..efbfe37 100644 --- a/intrastat_product/intrastat.py +++ b/intrastat_product/intrastat.py @@ -29,6 +29,15 @@ class ReportIntrastatCode(models.Model): _name = "report.intrastat.code" _description = "H.S. Code" _order = "name" + _rec_name = "display_name" + + @api.one + @api.depends('name', 'description') + def _compute_display_name(self): + display_name = self.name or '' + if self.description: + display_name += ' ' + self.description + self.display_name = display_name name = fields.Char( string='H.S. code', @@ -37,6 +46,8 @@ class ReportIntrastatCode(models.Model): "http://www.wcoomd.org") description = fields.Char( 'Description', help="Short text description of the H.S. category") + display_name = fields.Char( + compute='_compute_display_name', string="Display Name", readonly=True) intrastat_code = fields.Char( string='European Intrastat Code', size=9, required=True, help="Code used for the Intrastat declaration. Must be part " @@ -49,16 +60,10 @@ class ReportIntrastatCode(models.Model): "this particular Intrastat Code (other than the weight in Kg). " "If no particular unit of measure is required, leave empty.") active = fields.Boolean(default=True) - - @api.multi - def name_get(self): - res = [] - for code in self: - name = code.name - if code.description: - name = u'%s %s' % (name, code.description) - res.append((code.id, name)) - return res + product_categ_ids = fields.One2many( + 'product.category', 'intrastat_id', string='Product Categories') + product_tmpl_ids = fields.One2many( + 'product.template', 'intrastat_id', string='Products') @api.constrains('name', 'intrastat_code') def _hs_code(self): @@ -84,6 +89,19 @@ class ReportIntrastatCode(models.Model): 'This H.S. code already exists in Odoo !' )] + @api.model + @api.returns('self', lambda value: value.id) + def create(self, vals): + if vals.get('intrastat_code'): + vals['intrastat_code'] = vals['intrastat_code'].replace(' ', '') + return super(ReportIntrastatCode, self).create(vals) + + @api.multi + def write(self, vals): + if vals.get('intrastat_code'): + vals['intrastat_code'] = vals['intrastat_code'].replace(' ', '') + return super(ReportIntrastatCode, self).write(vals) + class ProductTemplate(models.Model): _inherit = "product.template" diff --git a/intrastat_product/intrastat_view.xml b/intrastat_product/intrastat_view.xml index da54ba6..b62c280 100644 --- a/intrastat_product/intrastat_view.xml +++ b/intrastat_product/intrastat_view.xml @@ -75,6 +75,12 @@
+ + + + + +
From 22170dbd2905c272420a1db413b1fcad05415f8c Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Tue, 14 Apr 2015 22:33:32 +0200 Subject: [PATCH 050/103] Move description from __openerp__.py to README.rst Add conflict key in __openerp__.py Simplify code that create attachment Thanks to Luc de Meyer (Noviat) for his help on this. --- intrastat_base/README.rst | 29 +++++ intrastat_base/__openerp__.py | 12 +- intrastat_base/intrastat_common.py | 196 ++++++++++++----------------- 3 files changed, 112 insertions(+), 125 deletions(-) create mode 100644 intrastat_base/README.rst diff --git a/intrastat_base/README.rst b/intrastat_base/README.rst new file mode 100644 index 0000000..ab96e2f --- /dev/null +++ b/intrastat_base/README.rst @@ -0,0 +1,29 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :alt: License + +Intrastat Base Module +===================== + +This module contains common functions for the Intrastat reporting and +should be used in combination with country specific reporting modules +such as + +- l10n_fr_intrastat_service: + the module for the "Déclaration Européenne des Services" (DES) +- l10n_fr_intrastat_product: + the module for the "Déclaration d'Echange de Biens" (DEB) + +Installation +============ + +WARNING: +This module conflicts with the module "report_intrastat" from the addons. +If you have already installed the module "report_intrastat", +you should uninstall it first before installing this module. + +Credits +======= + +Author +------ +* Alexis de Lattre, Akretion diff --git a/intrastat_base/__openerp__.py b/intrastat_base/__openerp__.py index e795155..0ea5038 100644 --- a/intrastat_base/__openerp__.py +++ b/intrastat_base/__openerp__.py @@ -26,20 +26,10 @@ 'category': 'Localisation/Report Intrastat', 'license': 'AGPL-3', 'summary': 'Base module for Intrastat reporting', - 'description': """This module contains the common functions for 2 other modules : -- l10n_fr_intrastat_service : the module for the "Déclaration Européenne des Services" (DES) -- l10n_fr_intrastat_product : the module for the "Déclaration d'Echange de Biens" (DEB) -This module is not usefull if it's not used together with one of those 2 modules or other country-specific intrastat modules. - -This module doesn't have any France-specific stuff. So it can be used as a basis for other intrastat modules for other EU countries. - -WARNING : this module conflicts with the module "report_intrastat" from the addons. If you have already installed the module "report_intrastat", you should uninstall it first before installing this module. - -Please contact Alexis de Lattre from Akretion for any help or question about this module. - """, 'author': 'Akretion', 'website': 'http://www.akretion.com', 'depends': ['base_vat'], + 'conflicts': ['report_intrastat'], 'data': [ 'country_data.xml', 'product_view.xml', diff --git a/intrastat_base/intrastat_common.py b/intrastat_base/intrastat_common.py index 3db1764..ccd9920 100644 --- a/intrastat_base/intrastat_common.py +++ b/intrastat_base/intrastat_common.py @@ -1,8 +1,8 @@ # -*- encoding: utf-8 -*- ############################################################################## # -# Report intrastat base module for OpenERP -# Copyright (C) 2010-2013 Akretion (http://www.akretion.com/). +# Report intrastat base module for Odoo +# Copyright (C) 2010-2014 Akretion (http://www.akretion.com/). # @author Alexis de Lattre # # This program is free software: you can redistribute it and/or modify @@ -20,91 +20,73 @@ # ############################################################################## -from openerp.osv import orm -from openerp.tools.translate import _ -from openerp import tools -from datetime import datetime +from openerp import models, fields, api, tools, _ +from openerp.exceptions import Warning, ValidationError from dateutil.relativedelta import relativedelta import logging logger = logging.getLogger(__name__) -class report_intrastat_common(orm.TransientModel): +class ReportIntrastatCommon(models.AbstractModel): _name = "report.intrastat.common" _description = "Common functions for intrastat reports for products " "and services" - def _compute_numbers(self, cr, uid, ids, object, context=None): - result = {} - for intrastat in object.browse(cr, uid, ids, context=context): - total_amount = 0.0 - num_lines = 0 - for line in intrastat.intrastat_line_ids: - total_amount += line.amount_company_currency - num_lines += 1 - result[intrastat.id] = { - 'num_lines': num_lines, - 'total_amount': total_amount, - } - return result + @api.one + @api.depends( + 'intrastat_line_ids', 'intrastat_line_ids.amount_company_currency') + def _compute_numbers(self): + total_amount = 0.0 + num_lines = 0 + for line in self.intrastat_line_ids: + total_amount += line.amount_company_currency + num_lines += 1 + self.num_lines = num_lines + self.total_amount = total_amount - def _compute_dates(self, cr, uid, ids, object, context=None): - result = {} - for intrastat in object.browse(cr, uid, ids, context=context): - start_date_datetime = datetime.strptime( - intrastat.start_date, '%Y-%m-%d') - end_date_str = datetime.strftime( - start_date_datetime + relativedelta(day=31), '%Y-%m-%d') - result[intrastat.id] = { - 'end_date': end_date_str, - 'year_month': start_date_datetime.strftime('%Y-%m'), - } - return result + @api.one + @api.depends('start_date') + def _compute_dates(self): + start_date_dt = fields.Date.from_string(self.start_date) + self.end_date = fields.Date.to_string( + start_date_dt + relativedelta(day=31)) + self.year_month = start_date_dt.strftime('%Y-%m') - def _check_start_date(self, cr, uid, ids, object, context=None): + @api.one + def _check_start_date(self): '''Check that the start date is the first day of the month''' - for date_to_check in object.read( - cr, uid, ids, ['start_date'], context=context): - datetime_to_check = datetime.strptime( - date_to_check['start_date'], '%Y-%m-%d') - if datetime_to_check.day != 1: - return False - return True + datetime_to_check = fields.Date.from_string(self.start_date) + if datetime_to_check.day != 1: + raise ValidationError( + _('The start date must be the first day of the month')) - def _check_generate_lines(self, cr, uid, intrastat, context=None): + @api.one + def _check_generate_lines(self): """Check wether all requirements are met for generating lines.""" - if not intrastat.company_id: - # Should not be possible, but just in case: - raise orm.except_orm( - _('Error :'), - _("Company not yet set on intrastat report.") - ) - company_obj = intrastat.company_id # Simplify references + if not self.company_id: + raise Warning(_("Company not yet set on intrastat report.")) + company_obj = self.company_id if not company_obj.country_id: - raise orm.except_orm( - _('Error :'), + raise Warning( _("The country is not set on the company '%s'.") - % company_obj.name - ) - if not company_obj.currency_id.name == 'EUR': - raise orm.except_orm( - _('Error :'), + % company_obj.name) + if company_obj.currency_id.name != 'EUR': + raise Warning( _("The company currency must be 'EUR', but is currently '%s'.") - % company_obj.currency_id.name - ) + % company_obj.currency_id.name) return True - def _check_generate_xml(self, cr, uid, intrastat, context=None): - if not intrastat.company_id.partner_id.vat: - raise orm.except_orm( - _('Error :'), + @api.one + def _check_generate_xml(self): + if not self.company_id.partner_id.vat: + raise Warning( _("The VAT number is not set for the partner '%s'.") - % intrastat.company_id.partner_id.name) + % self.company_id.partner_id.name) return True - def _check_xml_schema( - self, cr, uid, xml_root, xml_string, xsd_file, context=None): + @api.model + def _check_xml_schema(self, xml_root, xml_string, xsd_file): '''Validate the XML file against the XSD''' from lxml import etree xsd_etree_obj = etree.parse( @@ -114,13 +96,12 @@ class report_intrastat_common(orm.TransientModel): official_schema.assertValid(xml_root) except Exception, e: # if the validation of the XSD fails, we arrive here - _logger = logging.getLogger(__name__) - _logger.warning( + logger = logging.getLogger(__name__) + logger.warning( "The XML file is invalid against the XML Schema Definition") - _logger.warning(xml_string) - _logger.warning(e) - raise orm.except_orm( - _('Error :'), + logger.warning(xml_string) + logger.warning(e) + raise Warning( _("The generated XML file is not valid against the official " "XML Schema Definition. The generated XML file and the " "full error have been written in the server logs. " @@ -129,39 +110,29 @@ class report_intrastat_common(orm.TransientModel): % str(e)) return True - def _attach_xml_file( - self, cr, uid, ids, object, xml_string, start_date_datetime, - declaration_name, context=None): + @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 - assert len(ids) == 1, "Only one ID accepted" - filename = '%s_%s.xml' % ( - datetime.strftime(start_date_datetime, '%Y-%m'), - declaration_name) - if not context: - context = {} - context.update({ - 'default_res_id': ids[0], - 'default_res_model': object._name - }) - attach_id = self.pool['ir.attachment'].create( - cr, uid, { - 'name': filename, - 'datas': base64.encodestring(xml_string), - 'datas_fname': filename}, - context=context) - return attach_id + filename = '%s_%s.xml' % (self.year_month, declaration_name) + attach = self.env['ir.attachment'].create({ + 'name': filename, + 'res_id': self.id, + 'res_model': self._name, + 'datas': base64.encodestring(xml_string), + 'datas_fname': filename}) + return attach.id - def _open_attach_view( - self, cr, uid, attach_id, title='XML file', context=None): + @api.model + def _open_attach_view(self, attach_id, title='XML file'): '''Returns an action which opens the form view of the ''' '''corresponding attachement''' action = { 'name': title, 'view_type': 'form', - 'view_mode': 'form,tree', - 'view_id': False, + 'view_mode': 'form', 'res_model': 'ir.attachment', 'type': 'ir.actions.act_window', 'nodestroy': True, @@ -170,30 +141,27 @@ class report_intrastat_common(orm.TransientModel): } return action - def partner_on_change(self, cr, uid, ids, partner_id=False, context=None): - result = {} - result['value'] = {} - if partner_id: - company = self.pool['res.partner'].read( - cr, uid, partner_id, ['vat'], context=context) - result['value']['partner_vat'] = company['vat'] - return result - - def send_reminder_email( - self, cr, uid, company, module_name, template_xmlid, - intrastat_id, context=None): - template_model, template_id =\ - self.pool['ir.model.data'].get_object_reference( - cr, uid, module_name, template_xmlid) - assert template_model == 'email.template', 'Wrong model' - if company.intrastat_remind_user_ids: + @api.one + def send_reminder_email(self, mail_template_xmlid): + mail_template = self.env.ref(mail_template_xmlid) + if self.company_id.intrastat_remind_user_ids: self.pool['email.template'].send_mail( - cr, uid, template_id, intrastat_id, context=context) + self._cr, self._uid, mail_template.id, self.id, + context=self._context) logger.info( 'Intrastat Reminder email has been sent (XMLID: %s).' - % template_xmlid) + % mail_template_xmlid) else: logger.warning( 'The list of users receiving the Intrastat Reminder is empty ' - 'on company %s' % company.name) + 'on company %s' % self.company_id.name) return True + + @api.multi + def unlink(self): + for intrastat in self: + if intrastat.state == 'done': + raise Warning( + _('Cannot delete the declaration %s ' + 'because it is in Done state') % self.year_month) + return super(ReportIntrastatCommon, self).unlink() From 4a1118a0c658da56d5086512ddae3058518152f5 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Fri, 15 May 2015 11:46:46 +0200 Subject: [PATCH 051/103] display_name must be stored as it is used as _rec_name, otherwise we cant, for instance, import files with name_search --- intrastat_product/intrastat.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/intrastat_product/intrastat.py b/intrastat_product/intrastat.py index efbfe37..5242514 100644 --- a/intrastat_product/intrastat.py +++ b/intrastat_product/intrastat.py @@ -47,7 +47,8 @@ class ReportIntrastatCode(models.Model): description = fields.Char( 'Description', help="Short text description of the H.S. category") display_name = fields.Char( - compute='_compute_display_name', string="Display Name", readonly=True) + compute='_compute_display_name', string="Display Name", readonly=True, + store=True) intrastat_code = fields.Char( string='European Intrastat Code', size=9, required=True, help="Code used for the Intrastat declaration. Must be part " From c802ac3fd01170262cfb940c71d35383dba6293a Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Tue, 26 May 2015 23:32:46 +0200 Subject: [PATCH 052/103] Try to shut-up pylint --- intrastat_base/intrastat_common.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/intrastat_base/intrastat_common.py b/intrastat_base/intrastat_common.py index ccd9920..5b2bfee 100644 --- a/intrastat_base/intrastat_common.py +++ b/intrastat_base/intrastat_common.py @@ -112,8 +112,8 @@ class ReportIntrastatCommon(models.AbstractModel): @api.multi def _attach_xml_file(self, xml_string, declaration_name): - '''Attach the XML file to the report_intrastat_product/service ''' - '''object''' + '''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) @@ -127,8 +127,8 @@ class ReportIntrastatCommon(models.AbstractModel): @api.model def _open_attach_view(self, attach_id, title='XML file'): - '''Returns an action which opens the form view of the ''' - '''corresponding attachement''' + '''Returns an action which opens the form view of the + corresponding attachement''' action = { 'name': title, 'view_type': 'form', From 7c5eb1de5259d3359c609f35a51ab63cb22711b1 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Wed, 27 May 2015 21:32:43 +0200 Subject: [PATCH 053/103] Update README.rst and translation files --- intrastat_base/README.rst | 41 +++++--- intrastat_base/__openerp__.py | 2 +- intrastat_base/i18n/fr_FR.po | 99 +++++++++----------- intrastat_base/i18n/intrastat_base.pot | 95 +++++++++---------- intrastat_product/README.rst | 41 ++++++++ intrastat_product/__openerp__.py | 2 +- intrastat_product/i18n/intrastat_product.pot | 70 +++++++++++++- 7 files changed, 226 insertions(+), 124 deletions(-) create mode 100644 intrastat_product/README.rst diff --git a/intrastat_base/README.rst b/intrastat_base/README.rst index ab96e2f..027add0 100644 --- a/intrastat_base/README.rst +++ b/intrastat_base/README.rst @@ -1,29 +1,44 @@ -.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg - :alt: License - Intrastat Base Module ===================== This module contains common functions for the Intrastat reporting and -should be used in combination with country specific reporting modules -such as +should be used in combination with country-specific reporting modules +such as: -- l10n_fr_intrastat_service: - the module for the "Déclaration Européenne des Services" (DES) -- l10n_fr_intrastat_product: - the module for the "Déclaration d'Echange de Biens" (DEB) +- *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_nl_intrastat*: + the module for the *Opgaaf IntraCommunautaire Prestaties* (ICP) for the Netherlands. + +These country-specific modules can be found in the OCA localization for those countries. Installation ============ WARNING: -This module conflicts with the module "report_intrastat" from the addons. -If you have already installed the module "report_intrastat", +This module conflicts with the module *report_intrastat* from the official addons. +If you have already installed the module *report_intrastat*, you should uninstall it first before installing this module. Credits ======= -Author ------- +Contributors +------------ + * Alexis de Lattre, Akretion + +Maintainer +---------- + +.. image:: http://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: http://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 http://odoo-community.org. diff --git a/intrastat_base/__openerp__.py b/intrastat_base/__openerp__.py index 0ea5038..cdf0dd6 100644 --- a/intrastat_base/__openerp__.py +++ b/intrastat_base/__openerp__.py @@ -26,7 +26,7 @@ 'category': 'Localisation/Report Intrastat', 'license': 'AGPL-3', 'summary': 'Base module for Intrastat reporting', - 'author': 'Akretion', + 'author': 'Akretion,Odoo Community Association (OCA)', 'website': 'http://www.akretion.com', 'depends': ['base_vat'], 'conflicts': ['report_intrastat'], diff --git a/intrastat_base/i18n/fr_FR.po b/intrastat_base/i18n/fr_FR.po index de7e5db..1b3d759 100644 --- a/intrastat_base/i18n/fr_FR.po +++ b/intrastat_base/i18n/fr_FR.po @@ -1,14 +1,14 @@ -# Translation of OpenERP Server. +# Translation of Odoo Server. # This file contains the translation of the following modules: # * intrastat_base # msgid "" msgstr "" -"Project-Id-Version: OpenERP Server 7.0\n" +"Project-Id-Version: Odoo Server 8.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-04-14 14:18+0000\n" -"PO-Revision-Date: 2014-04-14 14:18+0000\n" -"Last-Translator: Alexis de Lattre \n" +"POT-Creation-Date: 2015-05-27 18:43+0000\n" +"PO-Revision-Date: 2015-05-27 18:43+0000\n" +"Last-Translator: <>\n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -21,47 +21,43 @@ msgid "Activate this option for shipping costs, packaging costs and all services msgstr "Activez cette option pour les frais de port, les frais d'emballage et tous les services liés à la vente de produits physiques. Cette option est utilisée pour la DEB et la DES." #. module: intrastat_base -#: view:res.company:0 +#: code:addons/intrastat_base/intrastat_common.py:165 +#, python-format +msgid "Cannot delete the declaration %s because it is in Done state" +msgstr "Impossible de supprimer la déclaration %s car elle est à l'état déclaré" + +#. module: intrastat_base +#: view:res.company:intrastat_base.view_company_form msgid "Common Intrastat Settings" msgstr "Paramètres communs DEB et DES" #. module: intrastat_base #: model:ir.model,name:intrastat_base.model_report_intrastat_common -msgid "Common functions for intrastat reports for products and services" -msgstr "Fonctions communes pour la DEB et la DES" +msgid "Common functions for intrastat reports for products " +msgstr "" #. module: intrastat_base #: model:ir.model,name:intrastat_base.model_res_company msgid "Companies" msgstr "Sociétés" +#. module: intrastat_base +#: code:addons/intrastat_base/intrastat_common.py:68 +#, python-format +msgid "Company not yet set on intrastat report." +msgstr "Société non configurée sur le rapport intrastat." + #. module: intrastat_base #: model:ir.model,name:intrastat_base.model_res_country msgid "Country" msgstr "Pays" #. module: intrastat_base -#: view:res.country:0 +#: view:res.country:intrastat_base.view_country_search #: field:res.country,intrastat:0 msgid "EU Country" msgstr "Pays UE" -#. module: intrastat_base -#: code:addons/intrastat_base/company.py:58 -#: code:addons/intrastat_base/intrastat_common.py:77 -#: code:addons/intrastat_base/intrastat_common.py:82 -#: code:addons/intrastat_base/intrastat_common.py:90 -#: code:addons/intrastat_base/intrastat_common.py:110 -#: code:addons/intrastat_base/product.py:51 -#, python-format -msgid "Error :" -msgstr "Erreur :" - -#. module: intrastat_base -#: constraint:product.template:0 -msgid "Error msg is in raise" -msgstr "Error msg is in raise" - #. module: intrastat_base #: field:product.template,exclude_from_intrastat:0 msgid "Exclude from Intrastat reports" @@ -72,6 +68,11 @@ msgstr "Exclure de la DEB et de la DES" msgid "Exclude invoice line from intrastat if this tax is present" msgstr "Exclue la ligne de facture de la DEB/DES si cette taxe est présente" +#. module: intrastat_base +#: field:report.intrastat.common,id:0 +msgid "ID" +msgstr "ID" + #. module: intrastat_base #: help:product.template,exclude_from_intrastat:0 msgid "If set to True, the product or service will not be taken into account for Intrastat Product or Service reports. So you should leave this field to False unless you have a very good reason." @@ -83,21 +84,20 @@ msgid "If this tax is present on an invoice line, this invoice line will be skip msgstr "Si cette taxe est présente sur une ligne de facture, cette ligne de facture ne sera pas prise en compte lors de la génération de la DEB et de la DES depuis les factures." #. module: intrastat_base -#: view:product.product:0 -#: view:product.template:0 +#: view:product.template:intrastat_base.product_template_form_view msgid "Intrastat Properties" msgstr "Propriétés DEB/DES" -#. module: intrastat_base -#: view:res.company:0 -msgid "Intrastat Settings" -msgstr "Configuration DEB/DES" - #. module: intrastat_base #: model:ir.ui.menu,name:intrastat_base.menu_intrastat_base_root msgid "Intrastat Reporting" msgstr "DEB et DES" +#. module: intrastat_base +#: view:res.company:intrastat_base.view_company_form +msgid "Intrastat Settings" +msgstr "Configuration DEB/DES" + #. module: intrastat_base #: field:product.template,is_accessory_cost:0 msgid "Is accessory cost" @@ -109,28 +109,18 @@ msgid "List of OpenERP users who will receive a notification to remind them abou msgstr "Liste d'utilisateurs OpenERP qui recevront le rappel pour la DEB et/ou la DES." #. module: intrastat_base -#: field:res.company,intrastat_email_list:0 -msgid "List of emails of Users Receiving the Intrastat Reminder" -msgstr "Liste des emails d'utilisateurs qui recevront le rappel pour la DEB et/ou la DES" - -#. module: intrastat_base -#: code:addons/intrastat_base/company.py:59 +#: code:addons/intrastat_base/company.py:55 #, python-format msgid "Missing e-mail address on user '%s'." msgstr "Adresse e-mail manquante sur l'utilisateur '%s'." -#. module: intrastat_base -#: model:ir.model,name:intrastat_base.model_res_partner -msgid "Partner" -msgstr "Partenaire" - #. module: intrastat_base #: model:ir.model,name:intrastat_base.model_product_template msgid "Product Template" msgstr "Modèle d'article" #. module: intrastat_base -#: view:res.country:0 +#: view:res.country:intrastat_base.view_country_search msgid "Search Countries" msgstr "Recherche des pays" @@ -150,42 +140,43 @@ msgid "Tax" msgstr "Taxes" #. module: intrastat_base -#: code:addons/intrastat_base/intrastat_common.py:91 +#: code:addons/intrastat_base/intrastat_common.py:84 #, python-format msgid "The VAT number is not set for the partner '%s'." msgstr "Le numéro de TVA n'est pas renseigné pour le partenaire '%s'." #. module: intrastat_base -#: code:addons/intrastat_base/intrastat_common.py:83 +#: code:addons/intrastat_base/intrastat_common.py:76 #, python-format msgid "The company currency must be 'EUR', but is currently '%s'." msgstr "La monnaie de la société doit être 'EUR', mais est actuellement '%s'." #. module: intrastat_base -#: code:addons/intrastat_base/intrastat_common.py:78 +#: code:addons/intrastat_base/intrastat_common.py:72 #, python-format msgid "The country is not set on the company '%s'." msgstr "Le pays n'est pas renseigné sur la société '%s'." #. module: intrastat_base -#: code:addons/intrastat_base/intrastat_common.py:111 +#: code:addons/intrastat_base/intrastat_common.py:105 #, python-format msgid "The generated XML file is not valid against the official XML Schema Definition. The generated XML file and the full error have been written in the server logs. Here is the error, which may give you an idea on the cause of the problem : %s." msgstr "La validation du fichier XML avec le schéma XML officiel a échoué. Le fichier XML généré et le détail de l'erreur ont été écrits dans les logs du serveur. Voici le message d'erreur, qui peut vous donner une idée de la cause du problème : %s." #. module: intrastat_base -#: code:addons/intrastat_base/product.py:56 +#: code:addons/intrastat_base/product.py:51 #, python-format msgid "The option 'Is accessory cost?' should only be activated on 'Service' products. You have activated this option for the product '%s' which is of type '%s'" msgstr "L'option 'Frais accessoires' ne doit être activée que sur les produits de type 'Service'. Vous avez activé cette option sur le produit '%s' qui est de type '%s'" +#. module: intrastat_base +#: code:addons/intrastat_base/intrastat_common.py:62 +#, python-format +msgid "The start date must be the first day of the month" +msgstr "La date de début doit être le premier jour du mois" + #. module: intrastat_base #: field:res.company,intrastat_remind_user_ids:0 msgid "Users Receiving the Intrastat Reminder" msgstr "Utilisateurs qui reçoivent le rappel DEB/DES" -#. module: intrastat_base -#: constraint:res.company:0 -msgid "error msg in raise" -msgstr "error msg in raise" - diff --git a/intrastat_base/i18n/intrastat_base.pot b/intrastat_base/i18n/intrastat_base.pot index d184def..fdc6996 100644 --- a/intrastat_base/i18n/intrastat_base.pot +++ b/intrastat_base/i18n/intrastat_base.pot @@ -1,13 +1,13 @@ -# Translation of OpenERP Server. +# Translation of Odoo Server. # This file contains the translation of the following modules: # * intrastat_base # msgid "" msgstr "" -"Project-Id-Version: OpenERP Server 7.0\n" +"Project-Id-Version: Odoo Server 8.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-04-14 14:18+0000\n" -"PO-Revision-Date: 2014-04-14 14:18+0000\n" +"POT-Creation-Date: 2015-05-27 18:43+0000\n" +"PO-Revision-Date: 2015-05-27 18:43+0000\n" "Last-Translator: <>\n" "Language-Team: \n" "MIME-Version: 1.0\n" @@ -21,13 +21,19 @@ msgid "Activate this option for shipping costs, packaging costs and all services msgstr "" #. module: intrastat_base -#: view:res.company:0 +#: code:addons/intrastat_base/intrastat_common.py:165 +#, python-format +msgid "Cannot delete the declaration %s because it is in Done state" +msgstr "" + +#. module: intrastat_base +#: view:res.company:intrastat_base.view_company_form msgid "Common Intrastat Settings" msgstr "" #. module: intrastat_base #: model:ir.model,name:intrastat_base.model_report_intrastat_common -msgid "Common functions for intrastat reports for products and services" +msgid "Common functions for intrastat reports for products " msgstr "" #. module: intrastat_base @@ -35,33 +41,23 @@ msgstr "" msgid "Companies" msgstr "" +#. module: intrastat_base +#: code:addons/intrastat_base/intrastat_common.py:68 +#, python-format +msgid "Company not yet set on intrastat report." +msgstr "" + #. module: intrastat_base #: model:ir.model,name:intrastat_base.model_res_country msgid "Country" msgstr "" #. module: intrastat_base -#: view:res.country:0 +#: view:res.country:intrastat_base.view_country_search #: field:res.country,intrastat:0 msgid "EU Country" msgstr "" -#. module: intrastat_base -#: code:addons/intrastat_base/company.py:58 -#: code:addons/intrastat_base/intrastat_common.py:77 -#: code:addons/intrastat_base/intrastat_common.py:82 -#: code:addons/intrastat_base/intrastat_common.py:90 -#: code:addons/intrastat_base/intrastat_common.py:110 -#: code:addons/intrastat_base/product.py:51 -#, python-format -msgid "Error :" -msgstr "" - -#. module: intrastat_base -#: constraint:product.template:0 -msgid "Error msg is in raise" -msgstr "" - #. module: intrastat_base #: field:product.template,exclude_from_intrastat:0 msgid "Exclude from Intrastat reports" @@ -72,6 +68,11 @@ msgstr "" msgid "Exclude invoice line from intrastat if this tax is present" msgstr "" +#. module: intrastat_base +#: field:report.intrastat.common,id:0 +msgid "ID" +msgstr "" + #. module: intrastat_base #: help:product.template,exclude_from_intrastat:0 msgid "If set to True, the product or service will not be taken into account for Intrastat Product or Service reports. So you should leave this field to False unless you have a very good reason." @@ -83,21 +84,20 @@ msgid "If this tax is present on an invoice line, this invoice line will be skip msgstr "" #. module: intrastat_base -#: view:product.product:0 -#: view:product.template:0 +#: view:product.template:intrastat_base.product_template_form_view msgid "Intrastat Properties" msgstr "" -#. module: intrastat_base -#: view:res.company:0 -msgid "Intrastat Settings" -msgstr "" - #. module: intrastat_base #: model:ir.ui.menu,name:intrastat_base.menu_intrastat_base_root msgid "Intrastat Reporting" msgstr "" +#. module: intrastat_base +#: view:res.company:intrastat_base.view_company_form +msgid "Intrastat Settings" +msgstr "" + #. module: intrastat_base #: field:product.template,is_accessory_cost:0 msgid "Is accessory cost" @@ -109,28 +109,18 @@ msgid "List of OpenERP users who will receive a notification to remind them abou msgstr "" #. module: intrastat_base -#: field:res.company,intrastat_email_list:0 -msgid "List of emails of Users Receiving the Intrastat Reminder" -msgstr "" - -#. module: intrastat_base -#: code:addons/intrastat_base/company.py:59 +#: code:addons/intrastat_base/company.py:55 #, python-format msgid "Missing e-mail address on user '%s'." msgstr "" -#. module: intrastat_base -#: model:ir.model,name:intrastat_base.model_res_partner -msgid "Partner" -msgstr "" - #. module: intrastat_base #: model:ir.model,name:intrastat_base.model_product_template msgid "Product Template" msgstr "" #. module: intrastat_base -#: view:res.country:0 +#: view:res.country:intrastat_base.view_country_search msgid "Search Countries" msgstr "" @@ -150,42 +140,43 @@ msgid "Tax" msgstr "" #. module: intrastat_base -#: code:addons/intrastat_base/intrastat_common.py:91 +#: code:addons/intrastat_base/intrastat_common.py:84 #, python-format msgid "The VAT number is not set for the partner '%s'." msgstr "" #. module: intrastat_base -#: code:addons/intrastat_base/intrastat_common.py:83 +#: code:addons/intrastat_base/intrastat_common.py:76 #, python-format msgid "The company currency must be 'EUR', but is currently '%s'." msgstr "" #. module: intrastat_base -#: code:addons/intrastat_base/intrastat_common.py:78 +#: code:addons/intrastat_base/intrastat_common.py:72 #, python-format msgid "The country is not set on the company '%s'." msgstr "" #. module: intrastat_base -#: code:addons/intrastat_base/intrastat_common.py:111 +#: code:addons/intrastat_base/intrastat_common.py:105 #, python-format msgid "The generated XML file is not valid against the official XML Schema Definition. The generated XML file and the full error have been written in the server logs. Here is the error, which may give you an idea on the cause of the problem : %s." msgstr "" #. module: intrastat_base -#: code:addons/intrastat_base/product.py:56 +#: code:addons/intrastat_base/product.py:51 #, python-format msgid "The option 'Is accessory cost?' should only be activated on 'Service' products. You have activated this option for the product '%s' which is of type '%s'" msgstr "" +#. module: intrastat_base +#: code:addons/intrastat_base/intrastat_common.py:62 +#, python-format +msgid "The start date must be the first day of the month" +msgstr "" + #. module: intrastat_base #: field:res.company,intrastat_remind_user_ids:0 msgid "Users Receiving the Intrastat Reminder" msgstr "" -#. module: intrastat_base -#: constraint:res.company:0 -msgid "error msg in raise" -msgstr "" - diff --git a/intrastat_product/README.rst b/intrastat_product/README.rst new file mode 100644 index 0000000..27d8f71 --- /dev/null +++ b/intrastat_product/README.rst @@ -0,0 +1,41 @@ +Intrastat Product Module +===================== + +This module contains common objects and fields for the Intrastat Product reporting, such as the *H.S. codes* (if you are not familiar with H.S. codes, read `Wikipedia `) and the *country of origin* on the products. + +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 + +These country-specific modules can be found in the OCA localization for those countries. + +Installation +============ + +WARNING: +This module conflicts with the module *report_intrastat* from the official addons. +If you have already installed the module *report_intrastat*, +you should uninstall it before installing this module. + +Credits +======= + +Contributors +------------ + +* Alexis de Lattre, Akretion + +Maintainer +---------- + +.. image:: http://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: http://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 http://odoo-community.org. diff --git a/intrastat_product/__openerp__.py b/intrastat_product/__openerp__.py index 6224d37..2db666f 100644 --- a/intrastat_product/__openerp__.py +++ b/intrastat_product/__openerp__.py @@ -33,7 +33,7 @@ This module is country-independant. This module has been written by Alexis de Lattre from Akretion """, - 'author': 'Akretion', + 'author': 'Akretion,Odoo Community Association (OCA)', 'website': 'http://www.akretion.com', 'depends': ['intrastat_base'], 'data': [ diff --git a/intrastat_product/i18n/intrastat_product.pot b/intrastat_product/i18n/intrastat_product.pot index 15505ac..6b1f00f 100644 --- a/intrastat_product/i18n/intrastat_product.pot +++ b/intrastat_product/i18n/intrastat_product.pot @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 8.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-11-28 22:48+0000\n" -"PO-Revision-Date: 2014-11-28 22:48+0000\n" +"POT-Creation-Date: 2015-05-27 18:43+0000\n" +"PO-Revision-Date: 2015-05-27 18:43+0000\n" "Last-Translator: <>\n" "Language-Team: \n" "MIME-Version: 1.0\n" @@ -15,6 +15,11 @@ msgstr "" "Content-Transfer-Encoding: \n" "Plural-Forms: \n" +#. module: intrastat_product +#: field:report.intrastat.code,active:0 +msgid "Active" +msgstr "" + #. module: intrastat_product #: help:product.category,intrastat_id:0 msgid "Code from the Harmonised System. If this code is not set on the product itself, it will be read here, on the related product category." @@ -25,6 +30,21 @@ msgstr "" msgid "Code from the Harmonised System. Nomenclature is available from the World Customs Organisation, see http://www.wcoomd.org/. Some countries have made their own extensions to this nomenclature." msgstr "" +#. module: intrastat_product +#: help:report.intrastat.code,intrastat_code:0 +msgid "Code used for the Intrastat declaration. Must be part of the 'Combined Nomenclature' (CN), cf http://en.wikipedia.org/wiki/Combined_NomenclatureMust have 8 digits with sometimes a 9th digit." +msgstr "" + +#. module: intrastat_product +#: field:product.template,origin_country_id:0 +msgid "Country of Origin" +msgstr "" + +#. module: intrastat_product +#: help:product.template,origin_country_id:0 +msgid "Country of origin of the product i.e. product 'made in ____'. If you have different countries of origin depending on the supplier from which you purchased the product, leave this field empty and use the equivalent field on the 'product supplier info' form." +msgstr "" + #. module: intrastat_product #: field:report.intrastat.code,create_uid:0 msgid "Created by" @@ -40,6 +60,16 @@ msgstr "" msgid "Description" msgstr "" +#. module: intrastat_product +#: field:report.intrastat.code,display_name:0 +msgid "Display Name" +msgstr "" + +#. module: intrastat_product +#: field:report.intrastat.code,intrastat_code:0 +msgid "European Intrastat Code" +msgstr "" + #. module: intrastat_product #: help:report.intrastat.code,name:0 msgid "Full length Harmonized System code (digits only). Full list is available from the World Customs Organisation, see http://www.wcoomd.org" @@ -56,7 +86,7 @@ msgid "H.S. code" msgstr "" #. module: intrastat_product -#: code:addons/intrastat_product/intrastat.py:56 +#: code:addons/intrastat_product/intrastat.py:73 #, python-format msgid "H.S. codes should only contain digits. It is not the case of H.S. code '%s'." msgstr "" @@ -95,6 +125,12 @@ msgstr "" msgid "Last Updated on" msgstr "" +#. module: intrastat_product +#: view:report.intrastat.code:intrastat_product.product_intrastat_code_form +#: field:report.intrastat.code,product_categ_ids:0 +msgid "Product Categories" +msgstr "" + #. module: intrastat_product #: model:ir.model,name:intrastat_product.model_product_category msgid "Product Category" @@ -105,18 +141,46 @@ msgstr "" msgid "Product Template" msgstr "" +#. module: intrastat_product +#: view:report.intrastat.code:intrastat_product.product_intrastat_code_form +#: field:report.intrastat.code,product_tmpl_ids:0 +msgid "Products" +msgstr "" + #. module: intrastat_product #: view:report.intrastat.code:intrastat_product.product_intrastat_code_search msgid "Search Intrastat Codes" msgstr "" +#. module: intrastat_product +#: help:report.intrastat.code,intrastat_uom_id:0 +msgid "Select the unit of measure if one is required for this particular Intrastat Code (other than the weight in Kg). If no particular unit of measure is required, leave empty." +msgstr "" + #. module: intrastat_product #: help:report.intrastat.code,description:0 msgid "Short text description of the H.S. category" msgstr "" +#. module: intrastat_product +#: code:addons/intrastat_product/intrastat.py:82 +#, python-format +msgid "The field Intrastat Code should contain 8 or 9 digits. It is not the case of Intrastat Code '%s'." +msgstr "" + +#. module: intrastat_product +#: code:addons/intrastat_product/intrastat.py:77 +#, python-format +msgid "The field Intrastat Code should only contain digits. It is not the case of Intrastat Code '%s'." +msgstr "" + #. module: intrastat_product #: sql_constraint:report.intrastat.code:0 msgid "This H.S. code already exists in Odoo !" msgstr "" +#. module: intrastat_product +#: field:report.intrastat.code,intrastat_uom_id:0 +msgid "UoM for Intrastat Report" +msgstr "" + From c19bb72c31f9f97fabb1b2cbcb85654fbf60e7ed Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Wed, 27 May 2015 21:37:14 +0200 Subject: [PATCH 054/103] Simplify @depends, as suggested by Yannick --- intrastat_base/intrastat_common.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/intrastat_base/intrastat_common.py b/intrastat_base/intrastat_common.py index 5b2bfee..111cda6 100644 --- a/intrastat_base/intrastat_common.py +++ b/intrastat_base/intrastat_common.py @@ -34,8 +34,7 @@ class ReportIntrastatCommon(models.AbstractModel): "and services" @api.one - @api.depends( - 'intrastat_line_ids', 'intrastat_line_ids.amount_company_currency') + @api.depends('intrastat_line_ids.amount_company_currency') def _compute_numbers(self): total_amount = 0.0 num_lines = 0 From 07d5a29dbb9116c9e192959bf852f182e0eb6a41 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Wed, 27 May 2015 21:46:03 +0200 Subject: [PATCH 055/103] Better use of the new API for send_mail(), as suggested by Yannick (and tested be me) --- intrastat_base/intrastat_common.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/intrastat_base/intrastat_common.py b/intrastat_base/intrastat_common.py index 111cda6..bf417c1 100644 --- a/intrastat_base/intrastat_common.py +++ b/intrastat_base/intrastat_common.py @@ -144,9 +144,7 @@ class ReportIntrastatCommon(models.AbstractModel): def send_reminder_email(self, mail_template_xmlid): mail_template = self.env.ref(mail_template_xmlid) if self.company_id.intrastat_remind_user_ids: - self.pool['email.template'].send_mail( - self._cr, self._uid, mail_template.id, self.id, - context=self._context) + mail_template.send_mail(self.id) logger.info( 'Intrastat Reminder email has been sent (XMLID: %s).' % mail_template_xmlid) From 1526648ee657b07d130980da08b236362a5f9bc2 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Wed, 27 May 2015 21:49:06 +0200 Subject: [PATCH 056/103] Add index=True on some fields on which we often search, as suggested by Yannick --- intrastat_product/intrastat.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/intrastat_product/intrastat.py b/intrastat_product/intrastat.py index 5242514..db416f4 100644 --- a/intrastat_product/intrastat.py +++ b/intrastat_product/intrastat.py @@ -40,7 +40,7 @@ class ReportIntrastatCode(models.Model): self.display_name = display_name name = fields.Char( - string='H.S. code', + string='H.S. code', index=True, help="Full length Harmonized System code (digits only). Full list is " "available from the World Customs Organisation, see " "http://www.wcoomd.org") @@ -50,7 +50,7 @@ class ReportIntrastatCode(models.Model): compute='_compute_display_name', string="Display Name", readonly=True, store=True) intrastat_code = fields.Char( - string='European Intrastat Code', size=9, required=True, + string='European Intrastat Code', size=9, required=True, index=True, help="Code used for the Intrastat declaration. Must be part " "of the 'Combined Nomenclature' (CN), cf " "http://en.wikipedia.org/wiki/Combined_Nomenclature" From 90a546291715d686d1bed3f294cd70916b45740a Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Mon, 1 Jun 2015 14:42:15 +0200 Subject: [PATCH 057/103] Remove description in __openerp__.py --- intrastat_product/README.rst | 2 +- intrastat_product/__openerp__.py | 7 ------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/intrastat_product/README.rst b/intrastat_product/README.rst index 27d8f71..455c358 100644 --- a/intrastat_product/README.rst +++ b/intrastat_product/README.rst @@ -1,5 +1,5 @@ Intrastat Product Module -===================== +======================== This module contains common objects and fields for the Intrastat Product reporting, such as the *H.S. codes* (if you are not familiar with H.S. codes, read `Wikipedia `) and the *country of origin* on the products. diff --git a/intrastat_product/__openerp__.py b/intrastat_product/__openerp__.py index 2db666f..7a4e35c 100644 --- a/intrastat_product/__openerp__.py +++ b/intrastat_product/__openerp__.py @@ -26,13 +26,6 @@ 'category': 'Localisation/Report Intrastat', 'license': 'AGPL-3', 'summary': 'Base module for Intrastat Product', - 'description': """ -This module contains the common objects for the Intrastat Product. -This module is country-independant. - -This module has been written by Alexis de Lattre from Akretion - - """, 'author': 'Akretion,Odoo Community Association (OCA)', 'website': 'http://www.akretion.com', 'depends': ['intrastat_base'], From a68e51c04bb7930962ccc49453b183048b3930a7 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Wed, 10 Jun 2015 17:51:02 +0200 Subject: [PATCH 058/103] Move ACL from l10n_fr_intrastat_product module to intrastat_product module --- intrastat_product/security/ir.model.access.csv | 1 + 1 file changed, 1 insertion(+) diff --git a/intrastat_product/security/ir.model.access.csv b/intrastat_product/security/ir.model.access.csv index 1708adf..df031fb 100644 --- a/intrastat_product/security/ir.model.access.csv +++ b/intrastat_product/security/ir.model.access.csv @@ -1,3 +1,4 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_report_intrastat_code_sale_manager,Full access on report.intrastat.code to sale manager,model_report_intrastat_code,base.group_sale_manager,1,1,1,1 +access_report_intrastat_code_account_manager,Full access on report.intrastat.code to finance manager,model_report_intrastat_code,account.group_account_manager,1,1,1,1 access_report_intrastat_code_employee,Read access on report.intrastat.code to employee,model_report_intrastat_code,base.group_user,1,0,0,0 From 1f63ecc1732703d1e450ce3340b93e27e9288220 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Sun, 19 Jul 2015 14:24:56 +0200 Subject: [PATCH 059/103] Large code re-engineering following the Akretion-Noviat code sprint on intrastat This code has been written both by Luc de Meyer and myself. --- intrastat_base/README.rst | 4 +- intrastat_base/__openerp__.py | 6 +- intrastat_base/company_view.xml | 2 +- intrastat_base/country.py | 2 +- intrastat_base/intrastat_common.py | 19 +- intrastat_base/intrastat_menu.xml | 16 - intrastat_base/intrastat_view.xml | 36 + intrastat_base/product.py | 2 +- intrastat_base/tax.py | 2 +- intrastat_product/__init__.py | 24 +- intrastat_product/__openerp__.py | 23 +- intrastat_product/account_invoice.py | 88 +++ intrastat_product/account_invoice_view.xml | 44 ++ .../data/intrastat_transport_mode.xml | 53 ++ intrastat_product/data/intrastat_unit.xml | 125 ++++ intrastat_product/intrastat.py | 182 +++-- intrastat_product/intrastat_declaration.py | 663 ++++++++++++++++++ .../intrastat_declaration_view.xml | 177 +++++ intrastat_product/intrastat_demo.xml | 77 +- intrastat_product/intrastat_view.xml | 266 ++++--- intrastat_product/res_company.py | 67 ++ intrastat_product/res_company_view.xml | 21 + .../security/intrastat_security.xml | 12 + .../security/ir.model.access.csv | 12 +- intrastat_product/stock.py | 40 ++ intrastat_product/stock_view.xml | 28 + product_harmonized_system/README.rst | 48 ++ product_harmonized_system/__init__.py | 4 + product_harmonized_system/__openerp__.py | 41 ++ product_harmonized_system/hs.py | 85 +++ product_harmonized_system/hs_view.xml | 67 ++ product_harmonized_system/i18n/fr.po | 156 +++++ .../i18n/product_harmonized_system.pot | 156 +++++ product_harmonized_system/product.py | 73 ++ product_harmonized_system/product_demo.xml | 92 +++ product_harmonized_system/product_view.xml | 40 ++ .../security/ir.model.access.csv | 3 + .../security/product_hs_security.xml | 12 + 38 files changed, 2461 insertions(+), 307 deletions(-) delete mode 100644 intrastat_base/intrastat_menu.xml create mode 100644 intrastat_base/intrastat_view.xml create mode 100644 intrastat_product/account_invoice.py create mode 100644 intrastat_product/account_invoice_view.xml create mode 100644 intrastat_product/data/intrastat_transport_mode.xml create mode 100644 intrastat_product/data/intrastat_unit.xml create mode 100644 intrastat_product/intrastat_declaration.py create mode 100644 intrastat_product/intrastat_declaration_view.xml create mode 100644 intrastat_product/res_company.py create mode 100644 intrastat_product/res_company_view.xml create mode 100644 intrastat_product/security/intrastat_security.xml create mode 100644 intrastat_product/stock.py create mode 100644 intrastat_product/stock_view.xml create mode 100644 product_harmonized_system/README.rst create mode 100644 product_harmonized_system/__init__.py create mode 100644 product_harmonized_system/__openerp__.py create mode 100644 product_harmonized_system/hs.py create mode 100644 product_harmonized_system/hs_view.xml create mode 100644 product_harmonized_system/i18n/fr.po create mode 100644 product_harmonized_system/i18n/product_harmonized_system.pot create mode 100644 product_harmonized_system/product.py create mode 100644 product_harmonized_system/product_demo.xml create mode 100644 product_harmonized_system/product_view.xml create mode 100644 product_harmonized_system/security/ir.model.access.csv create mode 100644 product_harmonized_system/security/product_hs_security.xml diff --git a/intrastat_base/README.rst b/intrastat_base/README.rst index 027add0..a941d1d 100644 --- a/intrastat_base/README.rst +++ b/intrastat_base/README.rst @@ -9,8 +9,8 @@ such as: 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_nl_intrastat*: - the module for the *Opgaaf IntraCommunautaire Prestaties* (ICP) for the Netherlands. +- *l10n_be_intrastat_product*: + the module for the Intrastat Declaration for Belgium. These country-specific modules can be found in the OCA localization for those countries. diff --git a/intrastat_base/__openerp__.py b/intrastat_base/__openerp__.py index cdf0dd6..ea5483f 100644 --- a/intrastat_base/__openerp__.py +++ b/intrastat_base/__openerp__.py @@ -1,7 +1,7 @@ # -*- encoding: utf-8 -*- ############################################################################## # -# Report intrastat base module for Odoo +# Intrastat base module for Odoo # Copyright (C) 2011-2015 Akretion (http://www.akretion.com) # @author Alexis de Lattre # @@ -23,7 +23,7 @@ { 'name': 'Intrastat Reporting Base', 'version': '1.1', - 'category': 'Localisation/Report Intrastat', + 'category': 'Intrastat', 'license': 'AGPL-3', 'summary': 'Base module for Intrastat reporting', 'author': 'Akretion,Odoo Community Association (OCA)', @@ -37,7 +37,7 @@ 'country_view.xml', 'tax_view.xml', 'company_view.xml', - 'intrastat_menu.xml', + 'intrastat_view.xml', ], 'demo': ['intrastat_demo.xml'], 'installable': True, diff --git a/intrastat_base/company_view.xml b/intrastat_base/company_view.xml index 87933f4..1df7aed 100644 --- a/intrastat_base/company_view.xml +++ b/intrastat_base/company_view.xml @@ -16,7 +16,7 @@ - + diff --git a/intrastat_base/country.py b/intrastat_base/country.py index 7f03e5d..7a34e77 100644 --- a/intrastat_base/country.py +++ b/intrastat_base/country.py @@ -1,7 +1,7 @@ # -*- encoding: utf-8 -*- ############################################################################## # -# Report intrastat base module for Odoo +# Intrastat base module for Odoo # Copyright (C) 2011-2014 Akretion (http://www.akretion.com). # @author Alexis de Lattre # diff --git a/intrastat_base/intrastat_common.py b/intrastat_base/intrastat_common.py index bf417c1..9b5c4ba 100644 --- a/intrastat_base/intrastat_common.py +++ b/intrastat_base/intrastat_common.py @@ -1,7 +1,7 @@ # -*- encoding: utf-8 -*- ############################################################################## # -# Report intrastat base module for Odoo +# Intrastat base module for Odoo # Copyright (C) 2010-2014 Akretion (http://www.akretion.com/). # @author Alexis de Lattre # @@ -34,14 +34,14 @@ class ReportIntrastatCommon(models.AbstractModel): "and services" @api.one - @api.depends('intrastat_line_ids.amount_company_currency') + @api.depends('declaration_line_ids.amount_company_currency') def _compute_numbers(self): total_amount = 0.0 num_lines = 0 - for line in self.intrastat_line_ids: + for line in self.declaration_line_ids: total_amount += line.amount_company_currency num_lines += 1 - self.num_lines = num_lines + self.num_decl_lines = num_lines self.total_amount = total_amount @api.one @@ -162,3 +162,14 @@ class ReportIntrastatCommon(models.AbstractModel): _('Cannot delete the declaration %s ' 'because it is in Done state') % self.year_month) return super(ReportIntrastatCommon, self).unlink() + + +class IntrastatResultView(models.TransientModel): + """ + Transient Model to display Intrastat Report results + """ + _name = 'intrastat.result.view' + + note = fields.Text( + string='Notes', readonly=True, + default=lambda self: self._context.get('note')) diff --git a/intrastat_base/intrastat_menu.xml b/intrastat_base/intrastat_menu.xml deleted file mode 100644 index 85303c1..0000000 --- a/intrastat_base/intrastat_menu.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - diff --git a/intrastat_base/intrastat_view.xml b/intrastat_base/intrastat_view.xml new file mode 100644 index 0000000..4d9c22a --- /dev/null +++ b/intrastat_base/intrastat_view.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + intrastat.result_view_form + intrastat.result.view + +
+ + + +
+
+
+
+
+ +
+
diff --git a/intrastat_base/product.py b/intrastat_base/product.py index ca1652e..5373cb3 100644 --- a/intrastat_base/product.py +++ b/intrastat_base/product.py @@ -1,7 +1,7 @@ # -*- encoding: utf-8 -*- ############################################################################## # -# Report intrastat base module for OpenERP +# Intrastat base module for Odoo # Copyright (C) 2010-2014 Akretion (http://www.akretion.com/) # @author Alexis de Lattre # diff --git a/intrastat_base/tax.py b/intrastat_base/tax.py index 2b98678..197e51d 100644 --- a/intrastat_base/tax.py +++ b/intrastat_base/tax.py @@ -1,7 +1,7 @@ # -*- encoding: utf-8 -*- ############################################################################## # -# Report intrastat base module for Odoo +# Intrastat base module for Odoo # Copyright (C) 2011-2014 Akretion (http://www.akretion.com). # @author Alexis de Lattre # diff --git a/intrastat_product/__init__.py b/intrastat_product/__init__.py index 64a3431..063edb0 100644 --- a/intrastat_product/__init__.py +++ b/intrastat_product/__init__.py @@ -1,23 +1,7 @@ # -*- encoding: utf-8 -*- -############################################################################## -# -# Intrastat product module for OpenERP -# Copyright (C) 2011-2014 Akretion (http://www.akretion.com) -# @author Alexis de Lattre -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## +from . import res_company from . import intrastat +from . import intrastat_declaration +from . import stock +from . import account_invoice diff --git a/intrastat_product/__openerp__.py b/intrastat_product/__openerp__.py index 7a4e35c..7a593e8 100644 --- a/intrastat_product/__openerp__.py +++ b/intrastat_product/__openerp__.py @@ -3,7 +3,9 @@ # # Intrastat Product module for Odoo # Copyright (C) 2011-2015 Akretion (http://www.akretion.com) +# Copyright (C) 2015 Noviat (http://www.noviat.com) # @author Alexis de Lattre +# @author Luc de Meyer # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -22,16 +24,27 @@ { 'name': 'Intrastat Product', - 'version': '1.1', - 'category': 'Localisation/Report Intrastat', + 'version': '1.3', + 'category': 'Intrastat', 'license': 'AGPL-3', 'summary': 'Base module for Intrastat Product', - 'author': 'Akretion,Odoo Community Association (OCA)', - 'website': 'http://www.akretion.com', - 'depends': ['intrastat_base'], + 'author': 'Akretion, Noviat, Odoo Community Association (OCA)', + 'depends': [ + 'intrastat_base', + 'product_harmonized_system', + 'stock', + ], + 'conflicts': ['report_intrastat'], 'data': [ 'intrastat_view.xml', + 'intrastat_declaration_view.xml', + 'res_company_view.xml', + 'account_invoice_view.xml', + 'stock_view.xml', + 'security/intrastat_security.xml', 'security/ir.model.access.csv', + 'data/intrastat_transport_mode.xml', + 'data/intrastat_unit.xml', ], 'demo': ['intrastat_demo.xml'], 'installable': True, diff --git a/intrastat_product/account_invoice.py b/intrastat_product/account_invoice.py new file mode 100644 index 0000000..3179012 --- /dev/null +++ b/intrastat_product/account_invoice.py @@ -0,0 +1,88 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Copyright (c) 2012-2015 Noviat nv/sa (www.noviat.com) +# Copyright (C) 2015 Akretion (http://www.akretion.com) +# @author Luc de Meyer +# @author Alexis de Lattre +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp import models, fields, api + + +class AccountInvoice(models.Model): + _inherit = 'account.invoice' + + @api.model + def _default_intrastat_transaction(self): + """ placeholder for localisation modules """ + return self.env['intrastat.transaction'].browse([]) + + intrastat_transaction_id = fields.Many2one( + 'intrastat.transaction', string='Intrastat Transaction Type', + default=_default_intrastat_transaction, ondelete='restrict', + help="Intrastat nature of transaction") + intrastat_transport_id = fields.Many2one( + 'intrastat.transport_mode', string='Intrastat Transport Mode', + ondelete='restrict') + src_dest_country_id = fields.Many2one( + 'res.country', string='Origin/Destination Country', + ondelete='restrict') + intrastat_country = fields.Boolean( + related='src_dest_country_id.intrastat', + store=True, string='Intrastat Country', readonly=True) + intrastat = fields.Char( + string='Intrastat Declaration', + related='company_id.intrastat', store=True, readonly=True) + + @api.multi + def onchange_partner_id( + self, type, partner_id, date_invoice=False, + payment_term=False, partner_bank_id=False, company_id=False): + res = super(AccountInvoice, self).onchange_partner_id( + type, partner_id, date_invoice=date_invoice, + payment_term=payment_term, partner_bank_id=partner_bank_id, + company_id=company_id) + if partner_id: + partner = self.env['res.partner'].browse(partner_id) + res['value']['src_dest_country_id'] = partner.country_id.id + return res + + +class AccountInvoiceLine(models.Model): + _inherit = 'account.invoice.line' + + hs_code_id = fields.Many2one( + 'hs.code', string='Intrastat Code', ondelete='restrict') + + @api.multi + def product_id_change( + self, product, uom_id, qty=0, name='', type='out_invoice', + partner_id=False, fposition_id=False, price_unit=False, + currency_id=False, company_id=None): + res = super(AccountInvoiceLine, self).product_id_change( + product, uom_id, qty=qty, name=name, type=type, + partner_id=partner_id, fposition_id=fposition_id, + price_unit=price_unit, currency_id=currency_id, + company_id=company_id) + + if product: + product = self.env['product.product'].browse(product) + hs_code = product.get_hs_code_recursively() + if hs_code: + res['value']['hs_code_id'] = hs_code.id + return res diff --git a/intrastat_product/account_invoice_view.xml b/intrastat_product/account_invoice_view.xml new file mode 100644 index 0000000..cccb557 --- /dev/null +++ b/intrastat_product/account_invoice_view.xml @@ -0,0 +1,44 @@ + + + + + + intrastat.invoice.form + account.invoice + + + + + + + + + + + + + + + + intrastat.invoice.supplier.form + account.invoice + + + + + + + + + + + + + + + + diff --git a/intrastat_product/data/intrastat_transport_mode.xml b/intrastat_product/data/intrastat_transport_mode.xml new file mode 100644 index 0000000..4b4d245 --- /dev/null +++ b/intrastat_product/data/intrastat_transport_mode.xml @@ -0,0 +1,53 @@ + + + + + + 1 + Sea + Sea Transport (including wagons, motor vehicles, trailers, semi-trailers and lighters on board of a ship) + + + 2 + Rail + Railway transport (including lorries on railway wagons) + + + 3 + Road + Road Transport + + + 4 + Air + Air Transport + + + 5 + Post + Postal consignments + + + 7 + Fixed installations + Fixed transport installations (e.g. pipelines, high-tension cables) + + + + 8 + Inland waterway + Inland waterway transport + + + 9 + Own propulsion + Own propulsion (imported or exported means of transport crossing the border under their own power, e.g. aircraft, lorries, boats, etc.) + + + + + + + + + diff --git a/intrastat_product/data/intrastat_unit.xml b/intrastat_product/data/intrastat_unit.xml new file mode 100644 index 0000000..a6fbaff --- /dev/null +++ b/intrastat_product/data/intrastat_unit.xml @@ -0,0 +1,125 @@ + + + + + + + + c/k + Carats - 1 metric carat = 2 × 10exp(–4) kg + + + ce/el + Number of cells + + + ct/l + Carrying capacity in tonnes + + + g + Gram + + + + gi F/S + Gram of fissile isotopes + + + kg H2O2 + Kilogram of hydrogen peroxide + + + kg K2O + Kilogram of potassium oxide + + + kg KOH + Kilogram of potassium hydroxide (caustic potash) + + + kg met.am. + Kilogram of methylamines + + + kg N + Kilogram of nitrogen + + + kg NaOH + Kilogram of sodium hydroxide (caustic soda) + + + kg/net eda + Kilogram drained net weight + + + kg P2O5 + Kilogram of diphosphorus pentaoxide + + + kg 90 pct sdt + Kilogram of substance 90 % dry + + + kg U + Kilogram of uranium + + + 1000 kWh + Thousand kilowatt hours + + + l + Litre + + + + 1000 l + Thousand litres + + + l alc. 100 pct + Litre pure (100 %) alcohol + + + m + Metre + + + + m2 + Square metre + + + m3 + Cubic metre + + + 1000 m3 + Thousand cubic metres + + + pa + Number of pairs + + + items + Number of items + + + + 100 items + Hundred items + + + 1000 items + Thousand items + + + TJ + Terajoule (gross calorific value) + + + + diff --git a/intrastat_product/intrastat.py b/intrastat_product/intrastat.py index db416f4..b87953a 100644 --- a/intrastat_product/intrastat.py +++ b/intrastat_product/intrastat.py @@ -1,10 +1,11 @@ # -*- encoding: utf-8 -*- ############################################################################## # -# Intrastat Product module for OpenERP -# Copyright (C) 2004-2009 Tiny SPRL (http://tiny.be) -# Copyright (C) 2010-2014 Akretion (http://www.akretion.com) +# Intrastat Product module for Odoo +# Copyright (C) 2011-2015 Akretion (http://www.akretion.com) +# Copyright (C) 2015 Noviat (http://www.noviat.com) # @author Alexis de Lattre +# @author Luc de Meyer # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -25,108 +26,97 @@ from openerp import models, fields, api, _ from openerp.exceptions import ValidationError -class ReportIntrastatCode(models.Model): - _name = "report.intrastat.code" - _description = "H.S. Code" - _order = "name" - _rec_name = "display_name" - - @api.one - @api.depends('name', 'description') - def _compute_display_name(self): - display_name = self.name or '' - if self.description: - display_name += ' ' + self.description - self.display_name = display_name +class IntrastatUnit(models.Model): + _name = 'intrastat.unit' + _description = 'Intrastat Supplementary Units' name = fields.Char( - string='H.S. code', index=True, - help="Full length Harmonized System code (digits only). Full list is " - "available from the World Customs Organisation, see " - "http://www.wcoomd.org") + string='Name', required=True) description = fields.Char( - 'Description', help="Short text description of the H.S. category") - display_name = fields.Char( - compute='_compute_display_name', string="Display Name", readonly=True, - store=True) - intrastat_code = fields.Char( - string='European Intrastat Code', size=9, required=True, index=True, - help="Code used for the Intrastat declaration. Must be part " - "of the 'Combined Nomenclature' (CN), cf " - "http://en.wikipedia.org/wiki/Combined_Nomenclature" - "Must have 8 digits with sometimes a 9th digit.") - intrastat_uom_id = fields.Many2one( - 'product.uom', string='UoM for Intrastat Report', - help="Select the unit of measure if one is required for " - "this particular Intrastat Code (other than the weight in Kg). " - "If no particular unit of measure is required, leave empty.") - active = fields.Boolean(default=True) - product_categ_ids = fields.One2many( - 'product.category', 'intrastat_id', string='Product Categories') - product_tmpl_ids = fields.One2many( - 'product.template', 'intrastat_id', string='Products') + string='Description', required=True) + uom_id = fields.Many2one( + 'product.uom', string='Regular UoM', + help="Select the regular Unit of Measure of Odoo that corresponds " + "to this Intrastat Supplementary Unit.") + active = fields.Boolean( + string='Active', default=True) - @api.constrains('name', 'intrastat_code') + +class HSCode(models.Model): + _inherit = "hs.code" + + intrastat_unit_id = fields.Many2one( + 'intrastat.unit', string='Intrastat Supplementary Unit') + + @api.constrains('local_code') def _hs_code(self): - if self.name and not self.name.isdigit(): - raise ValidationError( - _("H.S. codes should only contain digits. It is not the case " - "of H.S. code '%s'.") % self.name) - if self.intrastat_code and not self.intrastat_code.isdigit(): - raise ValidationError( - _("The field Intrastat Code should only contain digits. " - "It is not the case of Intrastat Code '%s'.") - % self.intrastat_code) - if self.intrastat_code and len(self.intrastat_code) not in (8, 9): - raise ValidationError( - _("The field Intrastat Code should " - "contain 8 or 9 digits. It is not the case of " - "Intrastat Code '%s'.") - % self.intrastat_code) + if self.company_id.country_id.intrastat: + if not self.local_code.isdigit(): + raise ValidationError( + _("Intrastat Codes should only contain digits. " + "This is not the case for code '%s'.") + % self.local_code) + if len(self.local_code) != 8: + raise ValidationError( + _("Intrastat Codes should " + "contain 8 digits. This is not the case for " + "Intrastat Code '%s' which has %d digits.") + % (self.local_code, len(self.local_code))) + + +class IntrastatTransaction(models.Model): + _name = 'intrastat.transaction' + _description = "Intrastat Transaction" + _order = 'code' + _rec_name = 'display_name' + + @api.one + @api.depends('code', 'description') + def _compute_display_name(self): + display_name = self.code + if self.description: + display_name += ' ' + self.description + self.display_name = len(display_name) > 55 \ + and display_name[:55] + '...' \ + or display_name + + code = fields.Char(string='Code', required=True) + description = fields.Text(string='Description') + display_name = fields.Char( + compute='_compute_display_name', string="Display Name", readonly=True) + company_id = fields.Many2one( + 'res.company', string='Company', + default=lambda self: self.env['res.company']._company_default_get( + 'intrastat.transaction')) _sql_constraints = [( - 'hs_code_uniq', - 'unique(name)', - 'This H.S. code already exists in Odoo !' - )] - - @api.model - @api.returns('self', lambda value: value.id) - def create(self, vals): - if vals.get('intrastat_code'): - vals['intrastat_code'] = vals['intrastat_code'].replace(' ', '') - return super(ReportIntrastatCode, self).create(vals) - - @api.multi - def write(self, vals): - if vals.get('intrastat_code'): - vals['intrastat_code'] = vals['intrastat_code'].replace(' ', '') - return super(ReportIntrastatCode, self).write(vals) + 'intrastat_transaction_code_unique', + 'UNIQUE(code, company_id)', + 'Code must be unique.')] -class ProductTemplate(models.Model): - _inherit = "product.template" +class IntrastatTransportMode(models.Model): + _name = 'intrastat.transport_mode' + _description = "Intrastat Transport Mode" + _rec_name = 'display_name' + _order = 'code' - intrastat_id = fields.Many2one( - 'report.intrastat.code', string='Intrastat Code', - help="Code from the Harmonised System. Nomenclature is " - "available from the World Customs Organisation, see " - "http://www.wcoomd.org/. Some countries have made their own " - "extensions to this nomenclature.") - origin_country_id = fields.Many2one( - 'res.country', string='Country of Origin', - help="Country of origin of the product i.e. product " - "'made in ____'. If you have different countries of origin " - "depending on the supplier from which you purchased the product, " - "leave this field empty and use the equivalent field on the " - "'product supplier info' form.") + @api.one + @api.depends('name', 'code') + def _display_name(self): + print "display_name self=", self + print "self.code=", self.code + print "self.name=", self.name + self.display_name = '%s. %s' % (self.code, self.name) + display_name = fields.Char( + string='Display Name', 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) -class ProductCategory(models.Model): - _inherit = "product.category" - - intrastat_id = fields.Many2one( - 'report.intrastat.code', string='Intrastat Code', - help="Code from the Harmonised System. If this code is not " - "set on the product itself, it will be read here, on the " - "related product category.") + _sql_constraints = [( + 'intrastat_transport_code_unique', + 'UNIQUE(code)', + 'Code must be unique.')] diff --git a/intrastat_product/intrastat_declaration.py b/intrastat_product/intrastat_declaration.py new file mode 100644 index 0000000..654fef9 --- /dev/null +++ b/intrastat_product/intrastat_declaration.py @@ -0,0 +1,663 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Intrastat Product module for Odoo +# Copyright (C) 2011-2015 Akretion (http://www.akretion.com) +# Copyright (C) 2011-2015 Noviat (http://www.noviat.com) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp import models, fields, api, _ +from openerp.exceptions import Warning, RedirectWarning, ValidationError +import openerp.addons.decimal_precision as dp +from datetime import datetime, date +from dateutil.relativedelta import relativedelta +from lxml import etree +import logging +_logger = logging.getLogger(__name__) + + +class IntrastatProductDeclaration(models.Model): + _name = 'intrastat.product.declaration' + _description = "Intrastat Product Report Base Object" + _rec_name = 'year_month' + _inherit = ['mail.thread', 'report.intrastat.common'] + _order = 'year_month desc, type, revision' + _track = { + 'state': { + 'intrastat_product.declaration_done': + lambda self, cr, uid, obj, ctx=None: obj['state'] == 'done', + } + } + + @api.model + def _get_type(self): + res = [] + company = self.env.user.company_id + arrivals = company.intrastat_arrivals + dispatches = company.intrastat_dispatches + if arrivals != 'exempt': + res.append(('arrivals', _('Declaration for Arrivals'))) + if dispatches != 'exempt': + res.append(('dispatches', _('Declaration for Dispatches'))) + return res + + @api.model + def _get_reporting_level(self): + return [ + ('standard', _('Standard')), + ('extended', _('Extended'))] + + @api.onchange('type') + def _onchange_type(self): + if self.type == 'arrivals': + self.reporting_level = \ + self.company_id.intrastat_arrivals == 'extended' \ + and 'extended' or 'standard' + if self.type == 'dispatches': + self.reporting_level = \ + self.company_id.intrastat_dispatches == 'extended' \ + and 'extended' or 'standard' + + @api.model + def _get_company(self): + return self.env.user.company_id + + @api.model + def _get_year(self): + if datetime.now().month == 1: + return datetime.now().year - 1 + else: + return datetime.now().year + + @api.model + def _get_month(self): + if datetime.now().month == 1: + return 12 + else: + return datetime.now().month - 1 + + @api.model + def _get_action(self): + return [ + ('replace', 'Replace'), + ('append', 'Append'), + ('nihil', 'Nihil')] + + @api.model + def _get_default_action(self): + return 'replace' + + company_id = fields.Many2one( + 'res.company', string='Company', readonly=True, + default=lambda self: self.env[ + 'res.company']._company_default_get('intrastat.product.declaration')) + year = fields.Integer( + string='Year', required=True, + default=_get_year) + month = fields.Selection([ + (1, '01'), + (2, '02'), + (3, '03'), + (4, '04'), + (5, '05'), + (6, '06'), + (7, '07'), + (8, '08'), + (9, '09'), + (10, '10'), + (11, '11'), + (12, '12') + ], string='Month', required=True, + default=_get_month) + year_month = fields.Char( + compute='_compute_year_month', string='Month', readonly=True, + track_visibility='always', store=True, + help="Year and month of the declaration.") + type = fields.Selection( + '_get_type', string='Type', required=True, + states={'done': [('readonly', True)]}, + track_visibility='always', help="Select the declaration type.") + action = fields.Selection( + '_get_action', + string='Action', required=True, + default=_get_default_action, + states={'done': [('readonly', True)]}, + track_visibility='onchange') + revision = fields.Integer( + string='Revision', default=1, + states={'done': [('readonly', True)]}, + help="Used to keep track of changes") + computation_line_ids = fields.One2many( + 'intrastat.product.computation.line', + 'parent_id', string='Intrastat Product Computation Lines', + states={'done': [('readonly', True)]}) + declaration_line_ids = fields.One2many( + 'intrastat.product.declaration.line', + 'parent_id', string='Intrastat Product Declaration Lines', + states={'done': [('readonly', True)]}) + num_decl_lines = fields.Integer( + compute='_compute_numbers', string='Number of Declaration Lines', + store=True, track_visibility='onchange') + total_amount = fields.Float( + compute='_compute_numbers', digits=dp.get_precision('Account'), + string='Total Amount', store=True, + help="Total amount in company currency of the declaration.") + currency_id = fields.Many2one( + 'res.currency', related='company_id.currency_id', readonly=True, + string='Currency') + state = fields.Selection([ + ('draft', 'Draft'), + ('done', 'Done'), + ], string='State', readonly=True, track_visibility='onchange', + copy=False, default='draft', + help="State of the declaration. When the state is set to 'Done', " + "the parameters become read-only.") + note = fields.Text( + string='Notes', + help="You can add some comments here if you want.") + reporting_level = fields.Selection( + '_get_reporting_level', + string='Reporting Level') + valid = fields.Boolean( + compute='_check_validity', + string='Valid') + + @api.one + @api.constrains('year') + def _check_year(self): + s = str(self.year) + if len(s) != 4 or s[0] != '2': + raise ValidationError( + _("Invalid Year !")) + + _sql_constraints = [ + ('date_uniq', + 'unique(year_month, company_id, type)', + "A declaration of the same type already exists for this month !" + "\nYou should update the existing declaration " + "or change the revision number of this one."), + ] + + @api.one + @api.depends('year', 'month') + def _compute_year_month(self): + if self.year and self.month: + self.year_month = '-'.join([str(self.year), format(self.month, '02')]) + + @api.one + @api.depends('month') + def _check_validity(self): + """ TO DO: logic based upon computation lines """ + self.valid = True + + @api.one + @api.returns('self', lambda value: value.id) + def copy(self, default=None): + default = default or {} + default['revision'] = self.revision + 1 + return super(L10nBeReportIntrastatProduct, self).copy(default) + + def _company_warning(self, msg): + xmlid_mod = self.pool['ir.model.data'] + action_id = xmlid_mod.xmlid_to_res_id( + cr, uid, 'base.action_res_company_form') + raise RedirectWarning( + msg, action_id, + _('Go to company configuration screen')) + + def _get_partner_country(self, inv_line): + country = inv_line.invoice_id.intrastat_country_id \ + or inv_line.invoice_id.partner_id.country_id + if not country.intrastat: + country = False + elif country == self.company_id.country_id: + country = False + return country + + def _get_intrastat_transaction(self, inv_line): + if inv_line.invoice_id.intrastat_transaction_id: + tr = inv_line.invoice_id.intrastat_transaction_id.code + else: + tr = self.env.ref( + 'l10n_be_intrastat_advanced.intrastat_transaction_1') + return tr + + def _get_region(self, inv_line): + """ + Logic copied from standard addons, l10n_be_intrastat module: + + 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. + """ + region = False + if inv_line.invoice_id.type in ('in_invoice', 'in_refund'): + po_lines = self.env['purchase.order.line'].search( + [('invoice_lines', 'in', inv_line.id)]) + if po_lines: + po = po_lines.order_id + region = self.env['stock.warehouse'].get_region_from_location( + po.location_id) + elif inv_line.invoice_id.type in ('out_invoice', 'out_refund'): + so_lines = self.env['sale.order.line'].search( + [('invoice_lines', 'in', inv_line.id)]) + if so_lines: + so = so_lines.order_id + region = so.warehouse_id.region_id + if not region: + if self.company_id.intrastat_region_id: + region = self.company_id.intrastat_region_id + else: + msg = _( + "The Intrastat Region of the Company is not set, " + "please configure it first.") + self._company_warning(msg) + return region + + def _get_weight_and_supplunits(self, inv_line): + line_qty = inv_line.quantity + product = inv_line.product_id + invoice = inv_line.invoice_id + intrastat_unit_id = inv_line.intrastat_id.intrastat_unit_id + source_uom = inv_line.uos_id + weight_uom_categ = self._uom_refs['weight_uom_categ'] + kg_uom = self._uom_refs['kg_uom'] + pce_uom_categ = self._uom_refs['pce_uom_categ'] + pce_uom = self._uom_refs['pce_uom'] + weight = suppl_unit_qty = 0.0 + + if not source_uom: + note = "\n" + _( + "Missing unit of measure on the line with %d " + "product(s) '%s' on invoice '%s'." + ) % (line_qty, product.name, invoice.number) + note += "\n" + _( + "Please adjust this line manually.") + self._note += note + return weight, suppl_unit_qty + + if intrastat_unit_id: + target_uom = intrastat_unit_id.uom_id + if not target_uom: + note = "\n" + _( + "Conversion from Intrastat Supplementary Unit '%s' to " + "Unit of Measure is not implemented yet." + ) % intrastat_unit_id.name + note += "\n" + _( + "Please correct the Intrastat Supplementary Unit " + "settingsand regenerate the lines or adjust the lines " + "with Intrastat Code 'ùs' manually" + ) % intrastat_code + self._note += note + return weight, suppl_unit_qty + if target_uom.categ_id == source_uom.category_id: + suppl_unit_qty = self.env['product.uom']._compute_qty_obj( + source_uom, line_qty, target_uom) + else: + note = "\n" + _( + "Conversion from unit of measure '%s' to '%s' " + "is not implemented yet." + ) % (source_uom.name, target_uom.name) + note += "\n" + _( + "Please correct the unit of measure settings and regenerate " + "the lines or adjust the impacted lines manually") + self._note += note + return weight, suppl_unit_qty + + else: + if source_uom == kg_uom: + weight = line_qty + elif source_uom.category_id == weight_uom_categ: + weight = self.env['product.uom']._compute_qty_obj( + source_uom, line_qty, kg_uom) + elif source_uom.category_id == pce_uom_categ: + if not product.weight_net: + note = "\n" + _( + "Missing net weight on product '%s'." + ) % product.name + note += "\n" + _( + "Please correct the product record and regenerate " + "the lines or adjust the impacted lines manually") + self._note += note + return weight, suppl_unit_qty + if source_uom == pce_uom: + weight = product.weight_net * line_qty + else: + # Here, I suppose that, on the product, the + # weight is per PCE and not per uom_id + weight = product.weight_net * \ + self.env['product.uom']._compute_qty_obj( + source_uom, line_qty, pce_uom) + else: + note = "\n" + _( + "Conversion from unit of measure '%s' to 'Kg' " + "is not implemented yet." + ) % source_uom.name + note += "\n" + _( + "Please correct the unit of measure settings and regenerate " + "the lines or adjust the impacted lines manually") + self._note += note + return weight, suppl_unit_qty + + return weight, suppl_unit_qty + + def _get_amount(self, inv_line): + invoice = inv_line.invoice_id + amount = inv_line.price_subtotal + if invoice.currency_id.name != 'EUR': + amount = self.env['res.currency'].with_context( + date=invoice.date_invoice).compute( + invoice.currency_id, + self.company_id.currency_id, + amount) + return amount + + def _get_transport(self, inv_line): + transport = inv_line.invoice.transport_mode_id \ + or self.company_id.intrastat_transport_id + if not transport: + msg = _( + "The default Intrastat Transport Mode " + "of the Company is not set, " + "please configure it first.") + self._company_warning(msg) + return transport + + def _get_incoterm(self, inv_line): + incoterm = inv_line.invoice.incoterm_id \ + or self.company_id.incoterm_id + if not incoterm: + msg = _( + "The default Incoterm " + "of the Company is not set, " + "please configure it first.") + self._company_warning(msg) + return transport + + def _gather_invoices(self): + + decl_lines = [] + start_date = date(self.year, self.month, 1) + end_date = start_date + relativedelta(day=1, months=+1, days=-1) + + invoices = self.env['account.invoice'].search([ + ('date_invoice', '>=', start_date), + ('date_invoice', '<=', end_date), + ('state', 'in', ['open', 'paid']), + ('intrastat_country', '=', True), + ('company_id', '=', self.company_id.id)]) + + for invoice in invoices: + + if self.type == 'arrivals': + if invoice.type in ['out_invoice', 'in_refund']: + continue + else: + if invoice.type in ['in_invoice', 'out_refund']: + continue + + for inv_line in invoice.invoice_line: + + intrastat = inv_line.intrastat_id + if not intrastat: + continue + if not inv_line.quantity: + continue + + partner_country = self._get_partner_country(inv_line) + if not partner_country: + continue + + intrastat_transaction = \ + self._get_intrastat_transaction(inv_line) + + region = self._get_region(inv_line) + + weight, suppl_unit_qty = self._get_weight_and_supplunits(inv_line) + + amount_company_currency = self._get_amount(inv_line) + + line_vals = { + 'parent_id': self.id, + 'invoice_line_id': inv_line.id, + 'partner_country_id': partner_country.id, + 'product_id': inv_line.product_id.id, + 'intrastat_code_id': intrastat.id, + 'weight': weight, + 'suppl_unit_qty': suppl_unit_qty, + 'amount_company_currency': amount_company_currency, + 'transaction_id': intrastat_transaction.id, + 'region_id': region.id, + 'extended': self._extended, + } + + # extended declaration + if self._extended: + transport = self._get_transport(inv_line) + incoterm = self._get_incoterm(inv_line) + line_vals.update({ + 'transport_id': transport.id, + 'incoterm_id' : incoterm.id, + }) + + decl_lines.append((0, 0, line_vals)) + + return decl_lines + + @api.multi + def action_gather(self): + self.ensure_one() + self._note = '' + self._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') + } + if (self.type == 'arrivals' + and self.company_id.intrastat_arrivals == 'extended') or ( + self.type == 'dispatches' + and self.company_id.intrastat_dispatches == 'extended'): + self._extended = True + else: + self._extended = False + + decl_lines_init = [(6, 0, [])] + decl_lines = decl_lines_init[:] + + decl_lines += self._gather_invoices() + + if decl_lines == decl_lines_init: + self.action = 'nihil' + note = "\n" + \ + _("No records found for the selected period !") + '\n' + \ + _("The Declaration Action has been set to 'nihil'.") + self._note += note + + # To DO: add check on tax cases 46, 48, 84, 86 + + self.write({'intrastat_line_ids': decl_lines}) + + if self._note: + note_header = '\n\n>>> ' + str(date.today()) + '\n' + self.note = (self.note or '') + note_header + self._note + result_view = self.env.ref( + 'l10n_be_intrastat_advanced.intrastat_result_view') + return { + 'name': _("Generate lines from invoices: results"), + 'view_type': 'form', + 'view_mode': 'form', + 'res_model': 'intrastat.result.view', + 'view_id': result_view.id, + 'target': 'new', + 'context': dict(self._context, note=self._note), + 'type': 'ir.actions.act_window', + } + + return True + + @api.multi + def generate_declaration(self): + """ generate declaration lines """ + self.ensure_one() + WIP + + +class IntrastatProductComputationLine(models.Model): + _name = 'intrastat.product.computation.line' + _description = "Intrastat Product Computataion Lines" + + parent_id = fields.Many2one( + '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_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) + valid = fields.Boolean( + compute='_check_validity', + string='Valid') + invoice_line_id = fields.Many2one( + 'account.invoice.line', string='Invoice Line', readonly=True) + invoice_id = fields.Many2one( + 'account.invoice', related='invoice_line_id.invoice_id', + string='Invoice', readonly=True) + declaration_line_id = fields.Many2one( + 'intrastat.product.declaration.line', + string='Declaration Line', readonly=True) + src_dest_country_id = fields.Many2one( + 'res.country', string='Country', + help="Country of Origin/Destination", + domain=[('intrastat', '=', True)]) + product_id = fields.Many2one( + 'product.product', related='invoice_line_id.product_id', + string='Product', readonly=True) + 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") + weight = fields.Float( + string='Weight (Kg)', + digits=dp.get_precision('Stock Weight')) + suppl_unit_qty = fields.Float( + string='Suppl. Unit Qty', + digits=dp.get_precision('Product Unit of Measure'), + help="Supplementary Units Quantity") + amount_company_currency = fields.Float( + string='Fiscal Value', + digits= dp.get_precision('Account'), required=True, + help="Amount in company currency to write in the declaration. " + "Amount in company currency = amount in invoice currency " + "converted to company currency with the rate of the invoice date.") + transaction_id = fields.Many2one( + 'intrastat.transaction', + string='Intrastat Transaction') + # extended declaration + transport_id = fields.Many2one( + 'intrastat.transport_mode', + string='Transport Mode') + + @api.one + @api.depends('transport_id') + def _check_validity(self): + """ TO DO: logic based upon fields """ + self.valid = True + + @api.onchange('product_id') + def _onchange_product(self): + self.weight = 0.0 + self.suppl_unit_qty = 0.0 + self.intrastat_code_id = False + self.intrastat_unit_id = False + if self.product_id: + self.intrastat_code_id = product.intrastat_id + self.intrastat_unit_id = product.intrastat_id.intrastat_unit_id + if not self.intrastat_unit_id: + self.weight = self.product_id.weight_net + + +class IntrastatProductDeclarationLine(models.Model): + _name = 'intrastat.product.declaration.line' + _description = "Intrastat Product Declaration Lines" + + parent_id = fields.Many2one( + '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_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) + computation_line_ids = fields.One2many( + 'intrastat.product.computation.line', 'declaration_line_id', + string='Computation Lines', readonly=True) + src_dest_country_id = fields.Many2one( + 'res.country', string='Country', + help="Country of Origin/Destination", + domain=[('intrastat', '=', True)]) + 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") + weight = fields.Integer( + string='Weight (Kg)') + suppl_unit_qty = fields.Integer( + string='Suppl. Unit Qty', + help="Supplementary Units Quantity") + amount_company_currency = fields.Integer( + string='Fiscal Value', + help="Amount in company currency to write in the declaration. " + "Amount in company currency = amount in invoice currency " + "converted to company currency with the rate of the invoice date.") + transaction_id = fields.Many2one( + 'intrastat.transaction', + string='Intrastat Transaction') + # extended declaration + transport_id = fields.Many2one( + 'intrastat.transport_mode', + string='Transport Mode') diff --git a/intrastat_product/intrastat_declaration_view.xml b/intrastat_product/intrastat_declaration_view.xml new file mode 100644 index 0000000..100eb93 --- /dev/null +++ b/intrastat_product/intrastat_declaration_view.xml @@ -0,0 +1,177 @@ + + + + + + intrastat.product.declaration.form + intrastat.product.declaration + +
+
+
+ +
+

+

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+
+ + + + Intrastat Product Declaration Validated + intrastat.product.declaration + + Intrastat Product Declaration Validated + + + + intrastat.product.tree + intrastat.product.declaration + + + + + + + + + + + + + + + intrastat.product.search + intrastat.product.declaration + + + + + + + + + + + + + + + + intrastat.product.graph + intrastat.product.declaration + + + + + + + + + + + Intrastat Product Declaration + intrastat.product.declaration + tree,form,graph + + + + + +
+
diff --git a/intrastat_product/intrastat_demo.xml b/intrastat_product/intrastat_demo.xml index b5ae41b..61b1c39 100644 --- a/intrastat_product/intrastat_demo.xml +++ b/intrastat_product/intrastat_demo.xml @@ -1,7 +1,7 @@ @@ -9,80 +9,13 @@ - - 84715000 - 84715000 - - Automatic data-processing machines (computers) + + - - 84717050 - 84717050 - - Storage units + + - - 85340090 - 85340090 - Printed circuits - - - - - - 5 - - - - - - 6 - - - - - - 6.5 - - - - - - 0.5 - - - - - - 0.5 - - - - - - 0.5 - - - - - - 0.7 - - - - - - 0.8 - - - - - - 2 - - - diff --git a/intrastat_product/intrastat_view.xml b/intrastat_product/intrastat_view.xml index b62c280..c61fc61 100644 --- a/intrastat_product/intrastat_view.xml +++ b/intrastat_product/intrastat_view.xml @@ -1,101 +1,203 @@ - + - - - intrastat.product.template.form - product.template - - - - - + + + + + + intrastat.hs.code.tree + hs.code + + + + - - + + - - - intrastat.product.category.form - product.category - - - - - - - - - + + + intrastat.hs.code.form + hs.code + + + + + + + - - - intrastat.product.intrastat.code.search - report.intrastat.code - - - - - - - - - - intrastat.product.intrastat.code.tree - report.intrastat.code - - + + + intrastat.unit.form + intrastat.unit + +
+ - - + - - - - - - - fr.intrastat.product.intrastat.code.form - report.intrastat.code - - - - - - - - - - - - - - - + +
-
-
+
+
- - - Intrastat Code - report.intrastat.code - tree,form - + + intrastat.unit.tree + intrastat.unit + + + + + + + + - - + + intrastat.unit.search + intrastat.unit + + + + + + + + + -
+ + + Supplementary Units + intrastat.unit + tree,form + + + + + + + intrastat.transaction_form + intrastat.transaction + +
+ + + + + +
+
+
+ + + intrastat.transaction_tree + intrastat.transaction + + + + + + + + + + + intrastat.transaction.mode.search + intrastat.transaction + + + + + + + + + + + + Transaction Types + intrastat.transaction + tree,form + + + + + + + + intrastat.transport.mode.form + intrastat.transport_mode + +
+ + + + + +
+
+
+ + + intrastat.transport.mode.tree + intrastat.transport_mode + + + + + + + + + + + intrastat.transport.mode.search + intrastat.transport_mode + + + + + + + + + Transport Modes + intrastat.transport_mode + tree,form + + + + +
diff --git a/intrastat_product/res_company.py b/intrastat_product/res_company.py new file mode 100644 index 0000000..65e0e3f --- /dev/null +++ b/intrastat_product/res_company.py @@ -0,0 +1,67 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Copyright (c) 2012-2015 Noviat nv/sa (www.noviat.com) +# Copyright (C) 2015 Akretion (http://www.akretion.com) +# @author Luc de Meyer +# @author Alexis de Lattre +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp import models, fields, api + + +class ResCompany(models.Model): + _inherit = 'res.company' + + @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.one + @api.depends('intrastat_arrivals', 'intrastat_dispatches') + def _compute_intrastat(self): + if self.intrastat_arrivals == 'exempt' \ + and self.intrastat_dispatches == 'exempt': + self.intrastat = 'exempt' + elif self.intrastat_arrivals == 'extended' \ + or self.intrastat_dispatches == 'extended': + self.intrastat = 'extended' + else: + self.intrastat = 'standard' + + intrastat_arrivals = fields.Selection( + '_intrastat_arrivals', string='Arrivals', + default='extended', required=True) + intrastat_dispatches = fields.Selection( + '_intrastat_arrivals', string='Dispatches', + default='extended', required=True) + intrastat_transport_id = fields.Many2one( + 'intrastat.transport_mode', + string='Default Transport Mode', ondelete='restrict') + intrastat = fields.Char( + string='Intrastat Declaration', store=True, readonly=True, + compute='_compute_intrastat') diff --git a/intrastat_product/res_company_view.xml b/intrastat_product/res_company_view.xml new file mode 100644 index 0000000..9761cb4 --- /dev/null +++ b/intrastat_product/res_company_view.xml @@ -0,0 +1,21 @@ + + + + + + intrastat.company.form + res.company + + + + + + + + + + + + + diff --git a/intrastat_product/security/intrastat_security.xml b/intrastat_product/security/intrastat_security.xml new file mode 100644 index 0000000..cd4f161 --- /dev/null +++ b/intrastat_product/security/intrastat_security.xml @@ -0,0 +1,12 @@ + + + + + + Intrastat Transaction Company rule + + ['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])] + + + + diff --git a/intrastat_product/security/ir.model.access.csv b/intrastat_product/security/ir.model.access.csv index df031fb..bd6835f 100644 --- a/intrastat_product/security/ir.model.access.csv +++ b/intrastat_product/security/ir.model.access.csv @@ -1,4 +1,10 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink -access_report_intrastat_code_sale_manager,Full access on report.intrastat.code to sale manager,model_report_intrastat_code,base.group_sale_manager,1,1,1,1 -access_report_intrastat_code_account_manager,Full access on report.intrastat.code to finance manager,model_report_intrastat_code,account.group_account_manager,1,1,1,1 -access_report_intrastat_code_employee,Read access on report.intrastat.code to employee,model_report_intrastat_code,base.group_user,1,0,0,0 +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_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 diff --git a/intrastat_product/stock.py b/intrastat_product/stock.py new file mode 100644 index 0000000..c97cf75 --- /dev/null +++ b/intrastat_product/stock.py @@ -0,0 +1,40 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2010-2015 Akretion (http://www.akretion.com) +# @author Alexis de Lattre +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp import models, fields, api + + +class StockPicking(models.Model): + _inherit = "stock.picking" + + intrastat_transport_id = fields.Many2one( + 'intrastat.transport_mode', string='Transport Mode', + help="This information is used in Intrastat reports") + intrastat = fields.Char(related='company_id.intrastat') + + @api.model + def _create_invoice_from_picking(self, picking, vals): + '''Copy transport and department from picking to invoice''' + vals['intrastat_transport_id'] = picking.intrastat_transport_id.id + if picking.partner_id and picking.partner_id.country_id: + vals['src_dest_country_id'] = picking.partner_id.country_id.id + return super(StockPicking, self)._create_invoice_from_picking( + picking, vals) diff --git a/intrastat_product/stock_view.xml b/intrastat_product/stock_view.xml new file mode 100644 index 0000000..80ce61e --- /dev/null +++ b/intrastat_product/stock_view.xml @@ -0,0 +1,28 @@ + + + + + + + + + + intrastat.product.picking.form + stock.picking + + + + + + + + + + + diff --git a/product_harmonized_system/README.rst b/product_harmonized_system/README.rst new file mode 100644 index 0000000..52304f1 --- /dev/null +++ b/product_harmonized_system/README.rst @@ -0,0 +1,48 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :alt: License + +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 `. 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*). + +Credits +======= + +Author +------- + +* Alexis de Lattre, Akretion +* Luc De Meyer, Noviat + +Maintainer +---------- +.. image:: http://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: http://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 http://odoo-community.org. diff --git a/product_harmonized_system/__init__.py b/product_harmonized_system/__init__.py new file mode 100644 index 0000000..a64ddf0 --- /dev/null +++ b/product_harmonized_system/__init__.py @@ -0,0 +1,4 @@ +# -*- encoding: utf-8 -*- + +from . import hs +from . import product diff --git a/product_harmonized_system/__openerp__.py b/product_harmonized_system/__openerp__.py new file mode 100644 index 0000000..3575e46 --- /dev/null +++ b/product_harmonized_system/__openerp__.py @@ -0,0 +1,41 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2011-2015 Akretion (http://www.akretion.com) +# Copyright (C) 2015 Noviat (http://www.noviat.com) +# @author Alexis de Lattre +# @author Luc de Meyer +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +{ + 'name': 'Product Harmonized System Codes', + 'version': '0.1', + 'category': 'Reporting', + 'license': 'AGPL-3', + 'summary': 'Base module for Product Import/Export reports', + 'author': 'Akretion, Noviat, Odoo Community Association (OCA)', + 'depends': ['product'], + 'conflicts': ['report_intrastat'], + 'data': [ + 'product_view.xml', + 'hs_view.xml', + 'security/product_hs_security.xml', + 'security/ir.model.access.csv', + ], + 'demo': ['product_demo.xml'], + 'installable': True, +} diff --git a/product_harmonized_system/hs.py b/product_harmonized_system/hs.py new file mode 100644 index 0000000..ea1e007 --- /dev/null +++ b/product_harmonized_system/hs.py @@ -0,0 +1,85 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2011-2015 Akretion (http://www.akretion.com) +# Copyright (C) 2015 Noviat (http://www.noviat.com) +# @author Alexis de Lattre +# @author Luc de Meyer +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp import models, fields, api + + +class HSCode(models.Model): + _name = "hs.code" + _description = "H.S. Code" + _order = "local_code" + _rec_name = "display_name" + + @api.one + @api.depends('local_code') + def _get_hs_code(self): + self.hs_code = self.local_code and self.local_code[:6] + + @api.one + @api.depends('local_code', 'description') + def _compute_display_name(self): + display_name = self.local_code + if self.description: + display_name += ' ' + self.description + self.display_name = display_name > 55 \ + and display_name[:55] + '...' \ + or display_name + + hs_code = fields.Char( + string='H.S. Code', compute='_get_hs_code', readonly=True, + help="Harmonized System code (6 digits). Full list is " + "available from the World Customs Organisation, see " + "http://www.wcoomd.org") + description = fields.Char( + 'Description', translate=True, + help="Short text description of the H.S. category") + display_name = fields.Char( + compute='_compute_display_name', string="Display Name", + store=True, readonly=True) + local_code = fields.Char( + string='Local Code', required=True, + help="Code used for the national Import/Export declaration. " + "The national code starts with the 6 digits of the H.S. and often " + "has a few additional digits to extend the H.S. code.") + 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')) + + _sql_constraints = [ + ('local_code_company_uniq', 'unique(local_code, company_id)', + 'This code already exists for this company !'), + ] + + @api.model + def create(self, vals): + if vals.get('local_code'): + 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(' ', '') + return super(HSCode, self).write(vals) diff --git a/product_harmonized_system/hs_view.xml b/product_harmonized_system/hs_view.xml new file mode 100644 index 0000000..0b9a2a7 --- /dev/null +++ b/product_harmonized_system/hs_view.xml @@ -0,0 +1,67 @@ + + + + + + + + + + hs.code.search + hs.code + + + + + + + + + + hs.code.tree + hs.code + + + + + + + + + + + + + hs.code.form + hs.code + +
+ + + + + + + +
+
+
+ + + + H.S. Codes + hs.code + tree,form + + + + + +
+
diff --git a/product_harmonized_system/i18n/fr.po b/product_harmonized_system/i18n/fr.po new file mode 100644 index 0000000..f8c57a1 --- /dev/null +++ b/product_harmonized_system/i18n/fr.po @@ -0,0 +1,156 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_harmonized_system +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 8.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-07-16 13:11+0000\n" +"PO-Revision-Date: 2015-07-16 13:11+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: product_harmonized_system +#: field:hs.code,active:0 +msgid "Active" +msgstr "Actif" + +#. module: product_harmonized_system +#: model:hs.code,description:product_harmonized_system.84715000 +msgid "Automatic data-processing machines (computers)" +msgstr "" + +#. module: product_harmonized_system +#: help:hs.code,local_code:0 +msgid "Code used for the national Import/Export declaration. e.g. Intrastat for the European Union" +msgstr "Code utilisé pour la déclaration nationale d'import/export, par exemple la DEB pour la France" + +#. module: product_harmonized_system +#: field:hs.code,company_id:0 +msgid "Company" +msgstr "Société" + +#. module: product_harmonized_system +#: field:product.template,origin_country_id:0 +msgid "Country of Origin" +msgstr "Pays d'origine" + +#. module: product_harmonized_system +#: help:product.template,origin_country_id:0 +msgid "Country of origin of the product i.e. product 'made in ____'. If you have different countries of origin depending on the supplier from which you purchased the product, leave this field empty and use the equivalent field on the 'product supplier info' form." +msgstr "" + +#. module: product_harmonized_system +#: field:hs.code,create_uid:0 +msgid "Created by" +msgstr "Créé par" + +#. module: product_harmonized_system +#: field:hs.code,create_date:0 +msgid "Created on" +msgstr "Créé le" + +#. module: product_harmonized_system +#: field:hs.code,description:0 +msgid "Description" +msgstr "Description" + +#. module: product_harmonized_system +#: field:hs.code,display_name:0 +msgid "Display Name" +msgstr "Nom affiché" + +#. module: product_harmonized_system +#: model:ir.model,name:product_harmonized_system.model_hs_code +#: field:product.category,hs_code_id:0 +#: field:product.template,hs_code_id:0 +msgid "H.S. Code" +msgstr "Code S.H." + +#. module: product_harmonized_system +#: view:hs.code:product_harmonized_system.hs_code_form +msgid "HS Code" +msgstr "Code S.H." + +#. module: product_harmonized_system +#: view:hs.code:product_harmonized_system.hs_code_tree +#: model:ir.actions.act_window,name:product_harmonized_system.hs_code_act +#: model:ir.ui.menu,name:product_harmonized_system.hs_code_menu +msgid "HS Codes" +msgstr "Codes S.H." + +#. module: product_harmonized_system +#: help:product.category,hs_code_id:0 +msgid "Harmonised System Code. If this code is not set on the product itself, it will be read here, on the related product category." +msgstr "" + +#. module: product_harmonized_system +#: help:product.template,hs_code_id:0 +msgid "Harmonised System Code. Nomenclature is available from the World Customs Organisation, see http://www.wcoomd.org/. You can leave this field empty and configure the H.S. code on the product category." +msgstr "" + +#. module: product_harmonized_system +#: field:hs.code,id:0 +msgid "ID" +msgstr "ID" + +#. module: product_harmonized_system +#: view:product.category:product_harmonized_system.product_category_form_view +msgid "Import/Export Properties" +msgstr "Propriétés pour l'import/export" + +#. module: product_harmonized_system +#: field:hs.code,write_uid:0 +msgid "Last Updated by" +msgstr "Dernière modification par" + +#. module: product_harmonized_system +#: field:hs.code,write_date:0 +msgid "Last Updated on" +msgstr "Dernière modification le" + +#. module: product_harmonized_system +#: field:hs.code,local_code:0 +msgid "Local Code" +msgstr "Code local" + +#. module: product_harmonized_system +#: model:hs.code,description:product_harmonized_system.85340090 +msgid "Printed circuits" +msgstr "" + +#. module: product_harmonized_system +#: model:ir.model,name:product_harmonized_system.model_product_category +msgid "Product Category" +msgstr "Catégorie d'articles" + +#. module: product_harmonized_system +#: model:ir.model,name:product_harmonized_system.model_product_template +msgid "Product Template" +msgstr "Modèle d'article" + +#. module: product_harmonized_system +#: view:hs.code:product_harmonized_system.hs_code_search +msgid "Search HS Codes" +msgstr "Recherche dans les codes S.H." + +#. module: product_harmonized_system +#: help:hs.code,description:0 +msgid "Short text description of the H.S. category" +msgstr "Courte description de la catégorie H.S." + +#. module: product_harmonized_system +#: model:hs.code,description:product_harmonized_system.84717050 +msgid "Storage units" +msgstr "" + +#. module: product_harmonized_system +#: sql_constraint:hs.code:0 +msgid "This code already exists for this company !" +msgstr "Ce code existe déjà pour cette société !" + diff --git a/product_harmonized_system/i18n/product_harmonized_system.pot b/product_harmonized_system/i18n/product_harmonized_system.pot new file mode 100644 index 0000000..b1389e9 --- /dev/null +++ b/product_harmonized_system/i18n/product_harmonized_system.pot @@ -0,0 +1,156 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_harmonized_system +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 8.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-07-16 13:10+0000\n" +"PO-Revision-Date: 2015-07-16 13:10+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: product_harmonized_system +#: field:hs.code,active:0 +msgid "Active" +msgstr "" + +#. module: product_harmonized_system +#: model:hs.code,description:product_harmonized_system.84715000 +msgid "Automatic data-processing machines (computers)" +msgstr "" + +#. module: product_harmonized_system +#: help:hs.code,local_code:0 +msgid "Code used for the national Import/Export declaration. e.g. Intrastat for the European Union" +msgstr "" + +#. module: product_harmonized_system +#: field:hs.code,company_id:0 +msgid "Company" +msgstr "" + +#. module: product_harmonized_system +#: field:product.template,origin_country_id:0 +msgid "Country of Origin" +msgstr "" + +#. module: product_harmonized_system +#: help:product.template,origin_country_id:0 +msgid "Country of origin of the product i.e. product 'made in ____'. If you have different countries of origin depending on the supplier from which you purchased the product, leave this field empty and use the equivalent field on the 'product supplier info' form." +msgstr "" + +#. module: product_harmonized_system +#: field:hs.code,create_uid:0 +msgid "Created by" +msgstr "" + +#. module: product_harmonized_system +#: field:hs.code,create_date:0 +msgid "Created on" +msgstr "" + +#. module: product_harmonized_system +#: field:hs.code,description:0 +msgid "Description" +msgstr "" + +#. module: product_harmonized_system +#: field:hs.code,display_name:0 +msgid "Display Name" +msgstr "" + +#. module: product_harmonized_system +#: model:ir.model,name:product_harmonized_system.model_hs_code +#: field:product.category,hs_code_id:0 +#: field:product.template,hs_code_id:0 +msgid "H.S. Code" +msgstr "" + +#. module: product_harmonized_system +#: view:hs.code:product_harmonized_system.hs_code_form +msgid "HS Code" +msgstr "" + +#. module: product_harmonized_system +#: view:hs.code:product_harmonized_system.hs_code_tree +#: model:ir.actions.act_window,name:product_harmonized_system.hs_code_act +#: model:ir.ui.menu,name:product_harmonized_system.hs_code_menu +msgid "HS Codes" +msgstr "" + +#. module: product_harmonized_system +#: help:product.category,hs_code_id:0 +msgid "Harmonised System Code. If this code is not set on the product itself, it will be read here, on the related product category." +msgstr "" + +#. module: product_harmonized_system +#: help:product.template,hs_code_id:0 +msgid "Harmonised System Code. Nomenclature is available from the World Customs Organisation, see http://www.wcoomd.org/. You can leave this field empty and configure the H.S. code on the product category." +msgstr "" + +#. module: product_harmonized_system +#: field:hs.code,id:0 +msgid "ID" +msgstr "" + +#. module: product_harmonized_system +#: view:product.category:product_harmonized_system.product_category_form_view +msgid "Import/Export Properties" +msgstr "" + +#. module: product_harmonized_system +#: field:hs.code,write_uid:0 +msgid "Last Updated by" +msgstr "" + +#. module: product_harmonized_system +#: field:hs.code,write_date:0 +msgid "Last Updated on" +msgstr "" + +#. module: product_harmonized_system +#: field:hs.code,local_code:0 +msgid "Local Code" +msgstr "" + +#. module: product_harmonized_system +#: model:hs.code,description:product_harmonized_system.85340090 +msgid "Printed circuits" +msgstr "" + +#. module: product_harmonized_system +#: model:ir.model,name:product_harmonized_system.model_product_category +msgid "Product Category" +msgstr "" + +#. module: product_harmonized_system +#: model:ir.model,name:product_harmonized_system.model_product_template +msgid "Product Template" +msgstr "" + +#. module: product_harmonized_system +#: view:hs.code:product_harmonized_system.hs_code_search +msgid "Search HS Codes" +msgstr "" + +#. module: product_harmonized_system +#: help:hs.code,description:0 +msgid "Short text description of the H.S. category" +msgstr "" + +#. module: product_harmonized_system +#: model:hs.code,description:product_harmonized_system.84717050 +msgid "Storage units" +msgstr "" + +#. module: product_harmonized_system +#: sql_constraint:hs.code:0 +msgid "This code already exists for this company !" +msgstr "" + diff --git a/product_harmonized_system/product.py b/product_harmonized_system/product.py new file mode 100644 index 0000000..2801a10 --- /dev/null +++ b/product_harmonized_system/product.py @@ -0,0 +1,73 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2011-2015 Akretion (http://www.akretion.com) +# Copyright (C) 2015 Noviat (http://www.noviat.com) +# @author Alexis de Lattre +# @author Luc de Meyer +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp import models, fields, api + + +class ProductTemplate(models.Model): + _inherit = "product.template" + + hs_code_id = fields.Many2one( + 'hs.code', string='H.S. Code', + company_dependent=True, ondelete='restrict', + help="Harmonised System Code. Nomenclature is " + "available from the World Customs Organisation, see " + "http://www.wcoomd.org/. You can leave this field empty " + "and configure the H.S. code on the product category.") + origin_country_id = fields.Many2one( + 'res.country', string='Country of Origin', + help="Country of origin of the product i.e. product " + "'made in ____'.") + + @api.multi + def get_hs_code_recursively(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() + else: + res = None + return res + + +class ProductCategory(models.Model): + _inherit = "product.category" + + hs_code_id = fields.Many2one( + 'hs.code', string='H.S. Code', + company_dependent=True, ondelete='restrict', + help="Harmonised System Code. If this code is not " + "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: + res = self.hs_code_id + elif self.parent_id: + res = self.parent_id.get_hs_code_recursively() + else: + res = None + return res diff --git a/product_harmonized_system/product_demo.xml b/product_harmonized_system/product_demo.xml new file mode 100644 index 0000000..fc11a8b --- /dev/null +++ b/product_harmonized_system/product_demo.xml @@ -0,0 +1,92 @@ + + + + + + + + + 84715000 + Automatic data-processing machines (computers) + + + + 84717050 + Storage units + + + + 85340090 + Printed circuits + + + + + + 8 + 8.7 + + + + + + 0.5 + 1.1 + + + + + + 7.5 + 8.2 + + + + + + 0.45 + 0.7 + + + + + + 0.42 + 0.67 + + + + + + 0.52 + 0.75 + + + + + + 0.6 + 1.05 + + + + + + 0.65 + 1.1 + + + + + + 3.3 + 4.6 + + + + + diff --git a/product_harmonized_system/product_view.xml b/product_harmonized_system/product_view.xml new file mode 100644 index 0000000..7c15e95 --- /dev/null +++ b/product_harmonized_system/product_view.xml @@ -0,0 +1,40 @@ + + + + + + + + + + hs_code.product.template.form + product.template + + + + + + + + + + + + hs_code.product.category.form + product.category + + + + + + + + + + + + diff --git a/product_harmonized_system/security/ir.model.access.csv b/product_harmonized_system/security/ir.model.access.csv new file mode 100644 index 0000000..133a7cd --- /dev/null +++ b/product_harmonized_system/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_hs_code_sale_manager,Full access on hs.code to sale manager,model_hs_code,base.group_sale_manager,1,1,1,1 +access_hs_code_read,Read access on hs.code to everybody,model_hs_code,,1,0,0,0 diff --git a/product_harmonized_system/security/product_hs_security.xml b/product_harmonized_system/security/product_hs_security.xml new file mode 100644 index 0000000..fae60ac --- /dev/null +++ b/product_harmonized_system/security/product_hs_security.xml @@ -0,0 +1,12 @@ + + + + + + HS Code Company rule + + ['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])] + + + + From 6cc2d578e5a7da50572e267f27ca6565dcf1f6c6 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Tue, 21 Jul 2015 09:31:48 +0200 Subject: [PATCH 060/103] Add first draft of code to generate decl lines --- intrastat_base/intrastat_common.py | 6 +- intrastat_product/intrastat_declaration.py | 119 ++++++++++++++++----- 2 files changed, 93 insertions(+), 32 deletions(-) diff --git a/intrastat_base/intrastat_common.py b/intrastat_base/intrastat_common.py index 9b5c4ba..a18ea07 100644 --- a/intrastat_base/intrastat_common.py +++ b/intrastat_base/intrastat_common.py @@ -28,8 +28,8 @@ import logging logger = logging.getLogger(__name__) -class ReportIntrastatCommon(models.AbstractModel): - _name = "report.intrastat.common" +class IntrastatCommon(models.AbstractModel): + _name = "intrastat.common" _description = "Common functions for intrastat reports for products " "and services" @@ -161,7 +161,7 @@ class ReportIntrastatCommon(models.AbstractModel): raise Warning( _('Cannot delete the declaration %s ' 'because it is in Done state') % self.year_month) - return super(ReportIntrastatCommon, self).unlink() + return super(IntrastatCommon, self).unlink() class IntrastatResultView(models.TransientModel): diff --git a/intrastat_product/intrastat_declaration.py b/intrastat_product/intrastat_declaration.py index 654fef9..9f4f731 100644 --- a/intrastat_product/intrastat_declaration.py +++ b/intrastat_product/intrastat_declaration.py @@ -25,8 +25,8 @@ from openerp.exceptions import Warning, RedirectWarning, ValidationError import openerp.addons.decimal_precision as dp from datetime import datetime, date from dateutil.relativedelta import relativedelta -from lxml import etree import logging + _logger = logging.getLogger(__name__) @@ -34,7 +34,7 @@ class IntrastatProductDeclaration(models.Model): _name = 'intrastat.product.declaration' _description = "Intrastat Product Report Base Object" _rec_name = 'year_month' - _inherit = ['mail.thread', 'report.intrastat.common'] + _inherit = ['mail.thread', 'intrastat.common'] _order = 'year_month desc, type, revision' _track = { 'state': { @@ -103,8 +103,8 @@ class IntrastatProductDeclaration(models.Model): company_id = fields.Many2one( '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( + 'intrastat.product.declaration')) year = fields.Integer( string='Year', required=True, default=_get_year) @@ -196,7 +196,8 @@ class IntrastatProductDeclaration(models.Model): @api.depends('year', 'month') def _compute_year_month(self): if self.year and self.month: - self.year_month = '-'.join([str(self.year), format(self.month, '02')]) + self.year_month = '-'.join( + [str(self.year), format(self.month, '02')]) @api.one @api.depends('month') @@ -209,14 +210,12 @@ class IntrastatProductDeclaration(models.Model): def copy(self, default=None): default = default or {} default['revision'] = self.revision + 1 - return super(L10nBeReportIntrastatProduct, self).copy(default) + return super(IntrastatProductDeclaration, self).copy(default) def _company_warning(self, msg): - xmlid_mod = self.pool['ir.model.data'] - action_id = xmlid_mod.xmlid_to_res_id( - cr, uid, 'base.action_res_company_form') + action = self.env.ref('base.action_res_company_form') raise RedirectWarning( - msg, action_id, + msg, action.id, _('Go to company configuration screen')) def _get_partner_country(self, inv_line): @@ -239,14 +238,12 @@ class IntrastatProductDeclaration(models.Model): def _get_region(self, inv_line): """ Logic copied from standard addons, l10n_be_intrastat module: - 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. """ region = False @@ -305,7 +302,7 @@ class IntrastatProductDeclaration(models.Model): note += "\n" + _( "Please correct the Intrastat Supplementary Unit " "settingsand regenerate the lines or adjust the lines " - "with Intrastat Code 'ùs' manually" + "with Intrastat Code '%s' manually" ) % intrastat_code self._note += note return weight, suppl_unit_qty @@ -318,8 +315,9 @@ class IntrastatProductDeclaration(models.Model): "is not implemented yet." ) % (source_uom.name, target_uom.name) note += "\n" + _( - "Please correct the unit of measure settings and regenerate " - "the lines or adjust the impacted lines manually") + "Please correct the unit of measure settings and " + "regenerate the lines or adjust the impacted " + "lines manually") self._note += note return weight, suppl_unit_qty @@ -353,8 +351,9 @@ class IntrastatProductDeclaration(models.Model): "is not implemented yet." ) % source_uom.name note += "\n" + _( - "Please correct the unit of measure settings and regenerate " - "the lines or adjust the impacted lines manually") + "Please correct the unit of measure settings and " + "regenerate the lines or adjust the impacted lines " + "manually") self._note += note return weight, suppl_unit_qty @@ -391,7 +390,7 @@ class IntrastatProductDeclaration(models.Model): "of the Company is not set, " "please configure it first.") self._company_warning(msg) - return transport + return incoterm def _gather_invoices(self): @@ -408,7 +407,7 @@ class IntrastatProductDeclaration(models.Model): for invoice in invoices: - if self.type == 'arrivals': + if self.type == 'arrivals': if invoice.type in ['out_invoice', 'in_refund']: continue else: @@ -432,7 +431,8 @@ class IntrastatProductDeclaration(models.Model): region = self._get_region(inv_line) - weight, suppl_unit_qty = self._get_weight_and_supplunits(inv_line) + weight, suppl_unit_qty = self._get_weight_and_supplunits( + inv_line) amount_company_currency = self._get_amount(inv_line) @@ -456,7 +456,7 @@ class IntrastatProductDeclaration(models.Model): incoterm = self._get_incoterm(inv_line) line_vals.update({ 'transport_id': transport.id, - 'incoterm_id' : incoterm.id, + 'incoterm_id': incoterm.id, }) decl_lines.append((0, 0, line_vals)) @@ -473,10 +473,11 @@ class IntrastatProductDeclaration(models.Model): 'pce_uom_categ': self.env.ref('product.product_uom_categ_unit'), 'pce_uom': self.env.ref('product.product_uom_unit') } - if (self.type == 'arrivals' - and self.company_id.intrastat_arrivals == 'extended') or ( - self.type == 'dispatches' - and self.company_id.intrastat_dispatches == 'extended'): + if ( + self.type == 'arrivals' and + self.company_id.intrastat_arrivals == 'extended') or ( + self.type == 'dispatches' and + self.company_id.intrastat_dispatches == 'extended'): self._extended = True else: self._extended = False @@ -515,11 +516,38 @@ class IntrastatProductDeclaration(models.Model): return True + @api.model + def group_line_hashcode(self, computation_line): + hashcode = "%s-%s-%s-%s-%s" % ( + computation_line.src_dest_country_id.id or False, + computation_line.hs_code or False, + computation_line.intrastat_unit_id.id or False, + computation_line.transaction_id.id or False, + computation_line.transport_id.id or False + ) + return hashcode + @api.multi def generate_declaration(self): """ generate declaration lines """ self.ensure_one() - WIP + assert self.valid, 'Computation lines are not valid' + # Delete existing declaration lines + self.declaration_line_ids.unlink() + # Regenerate declaration lines from computation lines + dl_group = {} + for cl in self.computation_line_ids: + hashcode = self.group_line_hashcode(cl) + if hashcode in dl_group: + dl_group[hashcode].append(cl) + else: + dl_group[hashcode] = [cl] + ipdlo = self.pool['intrastat.product.declaration.line'] + for cl_lines in dl_group.values(): + vals = ipdlo._prepare_declaration_line(cl_lines) + declaration_line = ipdlo.create(vals) + cl_lines.write({'declaration_line_id': declaration_line.id}) + return True class IntrastatProductComputationLine(models.Model): @@ -577,7 +605,7 @@ class IntrastatProductComputationLine(models.Model): help="Supplementary Units Quantity") amount_company_currency = fields.Float( string='Fiscal Value', - digits= dp.get_precision('Account'), required=True, + digits=dp.get_precision('Account'), required=True, help="Amount in company currency to write in the declaration. " "Amount in company currency = amount in invoice currency " "converted to company currency with the rate of the invoice date.") @@ -602,8 +630,9 @@ class IntrastatProductComputationLine(models.Model): self.intrastat_code_id = False self.intrastat_unit_id = False if self.product_id: - self.intrastat_code_id = product.intrastat_id - self.intrastat_unit_id = product.intrastat_id.intrastat_unit_id + self.intrastat_code_id = self.product_id.intrastat_id + self.intrastat_unit_id =\ + self.product_id.intrastat_id.intrastat_unit_id if not self.intrastat_unit_id: self.weight = self.product_id.weight_net @@ -661,3 +690,35 @@ class IntrastatProductDeclarationLine(models.Model): transport_id = fields.Many2one( 'intrastat.transport_mode', string='Transport Mode') + + @api.model + def _prepare_grouped_fields(computation_line, fields_to_sum): + vals = { + 'src_dest_country_id': computation_line.src_dest_country_id.id, + 'intrastat_unit_id': computation_line.intrastat_unit_id.id, + 'hs_code': computation_line.hs_code_id.local_code, + 'transaction_id': computation_line.transaction_id.id, + 'transport_id': computation_line.transport_id.id, + 'parent_id': computation_line.parent_id.id, + } + for field in fields_to_sum: + vals[field] = 0.0 + return vals + + def _fields_to_sum(): + fields_to_sum = [ + 'weight', + 'suppl_unit_qty', + 'amount_company_currency', + ] + return fields_to_sum + + @api.model + def _prepare_declaration_line(self, computation_lines): + fields_to_sum = self._fields_to_sum() + vals = self._prepare_grouped_fields( + computation_lines[0], fields_to_sum) + for computation_line in computation_lines: + for field in fields_to_sum: + vals[field] += computation_line[field] + return vals From a7b5d9090f3d3bcadfd4b9ab3c1a6e0d1475ebf6 Mon Sep 17 00:00:00 2001 From: Luc De Meyer Date: Sat, 25 Jul 2015 12:10:54 +0200 Subject: [PATCH 061/103] hs_code display_name fix --- product_harmonized_system/hs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/product_harmonized_system/hs.py b/product_harmonized_system/hs.py index ea1e007..bbf34c5 100644 --- a/product_harmonized_system/hs.py +++ b/product_harmonized_system/hs.py @@ -41,7 +41,7 @@ class HSCode(models.Model): display_name = self.local_code if self.description: display_name += ' ' + self.description - self.display_name = display_name > 55 \ + self.display_name = len(display_name) > 55 \ and display_name[:55] + '...' \ or display_name From 48afff883012f406beda833955449db85aecb11e Mon Sep 17 00:00:00 2001 From: Luc De Meyer Date: Sat, 25 Jul 2015 17:18:44 +0200 Subject: [PATCH 062/103] Update README.rst --- intrastat_product/README.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/intrastat_product/README.rst b/intrastat_product/README.rst index 455c358..248d1b7 100644 --- a/intrastat_product/README.rst +++ b/intrastat_product/README.rst @@ -8,6 +8,8 @@ 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. @@ -26,6 +28,7 @@ Contributors ------------ * Alexis de Lattre, Akretion +* Luc De Meyer, Noviat Maintainer ---------- From e0664db3b93d60e0b4927a818656f5cdfa047d7e Mon Sep 17 00:00:00 2001 From: Luc De Meyer Date: Sat, 25 Jul 2015 17:21:43 +0200 Subject: [PATCH 063/103] Update intrastat.py remove print statements from def _display_name --- intrastat_product/intrastat.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/intrastat_product/intrastat.py b/intrastat_product/intrastat.py index b87953a..79a25b2 100644 --- a/intrastat_product/intrastat.py +++ b/intrastat_product/intrastat.py @@ -104,9 +104,6 @@ class IntrastatTransportMode(models.Model): @api.one @api.depends('name', 'code') def _display_name(self): - print "display_name self=", self - print "self.code=", self.code - print "self.name=", self.name self.display_name = '%s. %s' % (self.code, self.name) display_name = fields.Char( From f61a01cc7d0fb4d223435f085bf9dd2b57fe07b8 Mon Sep 17 00:00:00 2001 From: luc-demeyer Date: Tue, 20 Oct 2015 20:26:19 +0200 Subject: [PATCH 064/103] major update intrastat V3 modules --- intrastat_base/README.rst | 37 +++- intrastat_base/__init__.py | 6 +- intrastat_base/__openerp__.py | 20 +- intrastat_base/{ => data}/country_data.xml | 0 intrastat_base/{ => demo}/intrastat_demo.xml | 0 intrastat_base/models/__init__.py | 27 +++ .../{tax.py => models/account_tax.py} | 0 .../{ => models}/intrastat_common.py | 0 .../product_template.py} | 0 .../{company.py => models/res_company.py} | 20 +- .../{country.py => models/res_country.py} | 0 .../{tax_view.xml => views/account_tax.xml} | 0 .../intrastat.xml} | 2 +- .../product_template.xml} | 0 .../res_company.xml} | 0 .../res_country.xml} | 2 +- .../res_partner.xml} | 0 intrastat_product/README.rst | 78 ++++++- intrastat_product/__init__.py | 6 +- intrastat_product/__openerp__.py | 19 +- .../{ => demo}/intrastat_demo.xml | 0 intrastat_product/intrastat.py | 119 ---------- intrastat_product/intrastat_view.xml | 203 ------------------ intrastat_product/models/__init__.py | 10 + .../{ => models}/account_invoice.py | 32 +-- intrastat_product/models/hs_code.py | 48 +++++ .../intrastat_product_declaration.py} | 148 ++++++------- .../models/intrastat_transaction.py | 56 +++++ .../models/intrastat_transport_mode.py | 49 +++++ intrastat_product/models/intrastat_unit.py | 41 ++++ intrastat_product/{ => models}/res_company.py | 43 ++-- .../{stock.py => models/stock_picking.py} | 5 +- .../account_invoice.xml} | 8 + intrastat_product/views/hs_code.xml | 45 ++++ .../intrastat_product_declaration.xml} | 30 ++- .../views/intrastat_transaction.xml | 68 ++++++ .../views/intrastat_transport_mode.xml | 64 ++++++ intrastat_product/views/intrastat_unit.xml | 70 ++++++ .../res_company.xml} | 2 + .../stock_picking.xml} | 0 product_harmonized_system/README.rst | 28 ++- product_harmonized_system/__init__.py | 3 +- product_harmonized_system/__openerp__.py | 13 +- .../{ => demo}/product_demo.xml | 0 product_harmonized_system/models/__init__.py | 5 + .../{hs.py => models/hs_code.py} | 34 +-- .../models/product_category.py | 46 ++++ .../product_template.py} | 24 +-- .../{hs_view.xml => views/hs_code.xml} | 6 +- .../views/product_category.xml | 27 +++ .../product_template.xml} | 14 -- 51 files changed, 893 insertions(+), 565 deletions(-) rename intrastat_base/{ => data}/country_data.xml (100%) rename intrastat_base/{ => demo}/intrastat_demo.xml (100%) create mode 100644 intrastat_base/models/__init__.py rename intrastat_base/{tax.py => models/account_tax.py} (100%) rename intrastat_base/{ => models}/intrastat_common.py (100%) rename intrastat_base/{product.py => models/product_template.py} (100%) rename intrastat_base/{company.py => models/res_company.py} (100%) rename intrastat_base/{country.py => models/res_country.py} (100%) rename intrastat_base/{tax_view.xml => views/account_tax.xml} (100%) rename intrastat_base/{intrastat_view.xml => views/intrastat.xml} (94%) rename intrastat_base/{product_view.xml => views/product_template.xml} (100%) rename intrastat_base/{company_view.xml => views/res_company.xml} (100%) rename intrastat_base/{country_view.xml => views/res_country.xml} (96%) rename intrastat_base/{partner_view.xml => views/res_partner.xml} (100%) rename intrastat_product/{ => demo}/intrastat_demo.xml (100%) delete mode 100644 intrastat_product/intrastat.py delete mode 100644 intrastat_product/intrastat_view.xml create mode 100644 intrastat_product/models/__init__.py rename intrastat_product/{ => models}/account_invoice.py (81%) create mode 100644 intrastat_product/models/hs_code.py rename intrastat_product/{intrastat_declaration.py => models/intrastat_product_declaration.py} (86%) create mode 100644 intrastat_product/models/intrastat_transaction.py create mode 100644 intrastat_product/models/intrastat_transport_mode.py create mode 100644 intrastat_product/models/intrastat_unit.py rename intrastat_product/{ => models}/res_company.py (79%) rename intrastat_product/{stock.py => models/stock_picking.py} (89%) rename intrastat_product/{account_invoice_view.xml => views/account_invoice.xml} (82%) create mode 100644 intrastat_product/views/hs_code.xml rename intrastat_product/{intrastat_declaration_view.xml => views/intrastat_product_declaration.xml} (88%) create mode 100644 intrastat_product/views/intrastat_transaction.xml create mode 100644 intrastat_product/views/intrastat_transport_mode.xml create mode 100644 intrastat_product/views/intrastat_unit.xml rename intrastat_product/{res_company_view.xml => views/res_company.xml} (81%) rename intrastat_product/{stock_view.xml => views/stock_picking.xml} (100%) rename product_harmonized_system/{ => demo}/product_demo.xml (100%) create mode 100644 product_harmonized_system/models/__init__.py rename product_harmonized_system/{hs.py => models/hs_code.py} (95%) create mode 100644 product_harmonized_system/models/product_category.py rename product_harmonized_system/{product.py => models/product_template.py} (73%) rename product_harmonized_system/{hs_view.xml => views/hs_code.xml} (92%) create mode 100644 product_harmonized_system/views/product_category.xml rename product_harmonized_system/{product_view.xml => views/product_template.xml} (60%) diff --git a/intrastat_base/README.rst b/intrastat_base/README.rst index a941d1d..1a5cc85 100644 --- a/intrastat_base/README.rst +++ b/intrastat_base/README.rst @@ -1,3 +1,9 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + + +===================== Intrastat Base Module ===================== @@ -12,16 +18,39 @@ such as: - *l10n_be_intrastat_product*: the module for the Intrastat Declaration for Belgium. -These country-specific modules can be found in the OCA localization for those countries. Installation ============ WARNING: + This module conflicts with the module *report_intrastat* from the official addons. If you have already installed the module *report_intrastat*, you should uninstall it first before installing this module. +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/91/8.0 + + +Bug Tracker +=========== + +Bugs are tracked on `GitHub 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 `here `_. + + Credits ======= @@ -29,16 +58,18 @@ Contributors ------------ * Alexis de Lattre, Akretion +* Luc De Meyer, Noviat Maintainer ---------- - .. image:: http://odoo-community.org/logo.png :alt: Odoo Community Association :target: http://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. +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 http://odoo-community.org. diff --git a/intrastat_base/__init__.py b/intrastat_base/__init__.py index 21b2067..cd5b2df 100644 --- a/intrastat_base/__init__.py +++ b/intrastat_base/__init__.py @@ -20,8 +20,4 @@ # ############################################################################## -from . import country -from . import product -from . import tax -from . import company -from . import intrastat_common +from . import models diff --git a/intrastat_base/__openerp__.py b/intrastat_base/__openerp__.py index ea5483f..f50f146 100644 --- a/intrastat_base/__openerp__.py +++ b/intrastat_base/__openerp__.py @@ -22,7 +22,7 @@ { 'name': 'Intrastat Reporting Base', - 'version': '1.1', + 'version': '1.2', 'category': 'Intrastat', 'license': 'AGPL-3', 'summary': 'Base module for Intrastat reporting', @@ -31,14 +31,16 @@ 'depends': ['base_vat'], 'conflicts': ['report_intrastat'], 'data': [ - 'country_data.xml', - 'product_view.xml', - 'partner_view.xml', - 'country_view.xml', - 'tax_view.xml', - 'company_view.xml', - 'intrastat_view.xml', + 'data/country_data.xml', + 'views/product_template.xml', + 'views/res_partner.xml', + 'views/res_country.xml', + 'views/account_tax.xml', + 'views/res_company.xml', + 'views/intrastat.xml', + ], + 'demo': [ + 'demo/intrastat_demo.xml', ], - 'demo': ['intrastat_demo.xml'], 'installable': True, } diff --git a/intrastat_base/country_data.xml b/intrastat_base/data/country_data.xml similarity index 100% rename from intrastat_base/country_data.xml rename to intrastat_base/data/country_data.xml diff --git a/intrastat_base/intrastat_demo.xml b/intrastat_base/demo/intrastat_demo.xml similarity index 100% rename from intrastat_base/intrastat_demo.xml rename to intrastat_base/demo/intrastat_demo.xml diff --git a/intrastat_base/models/__init__.py b/intrastat_base/models/__init__.py new file mode 100644 index 0000000..18530f9 --- /dev/null +++ b/intrastat_base/models/__init__.py @@ -0,0 +1,27 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Report intrastat base module for Odoo +# Copyright (C) 2011-2014 Akretion (http://www.akretion.com) +# @author Alexis de Lattre +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from . import res_country +from . import product_template +from . import account_tax +from . import res_company +from . import intrastat_common diff --git a/intrastat_base/tax.py b/intrastat_base/models/account_tax.py similarity index 100% rename from intrastat_base/tax.py rename to intrastat_base/models/account_tax.py diff --git a/intrastat_base/intrastat_common.py b/intrastat_base/models/intrastat_common.py similarity index 100% rename from intrastat_base/intrastat_common.py rename to intrastat_base/models/intrastat_common.py diff --git a/intrastat_base/product.py b/intrastat_base/models/product_template.py similarity index 100% rename from intrastat_base/product.py rename to intrastat_base/models/product_template.py diff --git a/intrastat_base/company.py b/intrastat_base/models/res_company.py similarity index 100% rename from intrastat_base/company.py rename to intrastat_base/models/res_company.py index 9fea8e4..2206c76 100644 --- a/intrastat_base/company.py +++ b/intrastat_base/models/res_company.py @@ -27,16 +27,6 @@ from openerp.exceptions import ValidationError class ResCompany(models.Model): _inherit = "res.company" - @api.one - @api.depends( - 'intrastat_remind_user_ids', 'intrastat_remind_user_ids.email') - def _compute_intrastat_email_list(self): - emails = [] - for user in self.intrastat_remind_user_ids: - if user.email: - emails.append(user.email) - self.intrastat_email_list = ','.join(emails) - intrastat_remind_user_ids = fields.Many2many( 'res.users', column1='company_id', column2='user_id', string="Users Receiving the Intrastat Reminder", @@ -46,6 +36,16 @@ class ResCompany(models.Model): compute='_compute_intrastat_email_list', string='List of emails of Users Receiving the Intrastat Reminder') + @api.one + @api.depends( + 'intrastat_remind_user_ids', 'intrastat_remind_user_ids.email') + def _compute_intrastat_email_list(self): + emails = [] + for user in self.intrastat_remind_user_ids: + if user.email: + emails.append(user.email) + self.intrastat_email_list = ','.join(emails) + @api.one @api.constrains('intrastat_remind_user_ids') def _check_intrastat_remind_users(self): diff --git a/intrastat_base/country.py b/intrastat_base/models/res_country.py similarity index 100% rename from intrastat_base/country.py rename to intrastat_base/models/res_country.py diff --git a/intrastat_base/tax_view.xml b/intrastat_base/views/account_tax.xml similarity index 100% rename from intrastat_base/tax_view.xml rename to intrastat_base/views/account_tax.xml diff --git a/intrastat_base/intrastat_view.xml b/intrastat_base/views/intrastat.xml similarity index 94% rename from intrastat_base/intrastat_view.xml rename to intrastat_base/views/intrastat.xml index 4d9c22a..7b4cdf7 100644 --- a/intrastat_base/intrastat_view.xml +++ b/intrastat_base/views/intrastat.xml @@ -17,7 +17,7 @@ parent="account.menu_finance_configuration" sequence="50"/> - + intrastat.result_view_form intrastat.result.view diff --git a/intrastat_base/product_view.xml b/intrastat_base/views/product_template.xml similarity index 100% rename from intrastat_base/product_view.xml rename to intrastat_base/views/product_template.xml diff --git a/intrastat_base/company_view.xml b/intrastat_base/views/res_company.xml similarity index 100% rename from intrastat_base/company_view.xml rename to intrastat_base/views/res_company.xml diff --git a/intrastat_base/country_view.xml b/intrastat_base/views/res_country.xml similarity index 96% rename from intrastat_base/country_view.xml rename to intrastat_base/views/res_country.xml index d887a22..ac0f6f6 100644 --- a/intrastat_base/country_view.xml +++ b/intrastat_base/views/res_country.xml @@ -32,7 +32,7 @@ - + intrastat.base.country.search res.country diff --git a/intrastat_base/partner_view.xml b/intrastat_base/views/res_partner.xml similarity index 100% rename from intrastat_base/partner_view.xml rename to intrastat_base/views/res_partner.xml diff --git a/intrastat_product/README.rst b/intrastat_product/README.rst index 248d1b7..1ad1510 100644 --- a/intrastat_product/README.rst +++ b/intrastat_product/README.rst @@ -1,3 +1,8 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +======================== Intrastat Product Module ======================== @@ -17,10 +22,74 @@ Installation ============ WARNING: + This module conflicts with the module *report_intrastat* from the official addons. If you have already installed the module *report_intrastat*, you should uninstall it before installing this module. + +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. + + +.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas + :alt: Try me on Runbot + :target: https://runbot.odoo-community.org/runbot/91/8.0 + + +Known issues / Roadmap +====================== + +Work is in progress to migrate the existing l10n_fr_intrastat_product module +to this new reporting framework, cf. Alexis de Lattre, Akretion . + + +Bug Tracker +=========== + +Bugs are tracked on `GitHub 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 `here `_. + + Credits ======= @@ -30,15 +99,18 @@ Contributors * Alexis de Lattre, Akretion * Luc De Meyer, Noviat + Maintainer ---------- -.. image:: http://odoo-community.org/logo.png +.. image:: https://odoo-community.org/logo.png :alt: Odoo Community Association - :target: http://odoo-community.org + :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. +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 http://odoo-community.org. diff --git a/intrastat_product/__init__.py b/intrastat_product/__init__.py index 063edb0..21ff7c2 100644 --- a/intrastat_product/__init__.py +++ b/intrastat_product/__init__.py @@ -1,7 +1,3 @@ # -*- encoding: utf-8 -*- -from . import res_company -from . import intrastat -from . import intrastat_declaration -from . import stock -from . import account_invoice +from . import models diff --git a/intrastat_product/__openerp__.py b/intrastat_product/__openerp__.py index 7a593e8..4c3496f 100644 --- a/intrastat_product/__openerp__.py +++ b/intrastat_product/__openerp__.py @@ -3,7 +3,7 @@ # # Intrastat Product module for Odoo # Copyright (C) 2011-2015 Akretion (http://www.akretion.com) -# Copyright (C) 2015 Noviat (http://www.noviat.com) +# Copyright (C) 2009-2015 Noviat (http://www.noviat.com) # @author Alexis de Lattre # @author Luc de Meyer # @@ -24,7 +24,7 @@ { 'name': 'Intrastat Product', - 'version': '1.3', + 'version': '1.4', 'category': 'Intrastat', 'license': 'AGPL-3', 'summary': 'Base module for Intrastat Product', @@ -36,16 +36,19 @@ ], 'conflicts': ['report_intrastat'], 'data': [ - 'intrastat_view.xml', - 'intrastat_declaration_view.xml', - 'res_company_view.xml', - 'account_invoice_view.xml', - 'stock_view.xml', + 'views/hs_code.xml', + 'views/intrastat_unit.xml', + 'views/intrastat_transaction.xml', + 'views/intrastat_transport_mode.xml', + 'views/intrastat_product_declaration.xml', + 'views/res_company.xml', + 'views/account_invoice.xml', + 'views/stock_picking.xml', 'security/intrastat_security.xml', 'security/ir.model.access.csv', 'data/intrastat_transport_mode.xml', 'data/intrastat_unit.xml', ], - 'demo': ['intrastat_demo.xml'], + 'demo': ['demo/intrastat_demo.xml'], 'installable': True, } diff --git a/intrastat_product/intrastat_demo.xml b/intrastat_product/demo/intrastat_demo.xml similarity index 100% rename from intrastat_product/intrastat_demo.xml rename to intrastat_product/demo/intrastat_demo.xml diff --git a/intrastat_product/intrastat.py b/intrastat_product/intrastat.py deleted file mode 100644 index 79a25b2..0000000 --- a/intrastat_product/intrastat.py +++ /dev/null @@ -1,119 +0,0 @@ -# -*- encoding: utf-8 -*- -############################################################################## -# -# Intrastat Product module for Odoo -# Copyright (C) 2011-2015 Akretion (http://www.akretion.com) -# Copyright (C) 2015 Noviat (http://www.noviat.com) -# @author Alexis de Lattre -# @author Luc de Meyer -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - -from openerp import models, fields, api, _ -from openerp.exceptions import ValidationError - - -class IntrastatUnit(models.Model): - _name = 'intrastat.unit' - _description = 'Intrastat Supplementary Units' - - name = fields.Char( - string='Name', required=True) - description = fields.Char( - string='Description', required=True) - uom_id = fields.Many2one( - 'product.uom', string='Regular UoM', - help="Select the regular Unit of Measure of Odoo that corresponds " - "to this Intrastat Supplementary Unit.") - active = fields.Boolean( - string='Active', default=True) - - -class HSCode(models.Model): - _inherit = "hs.code" - - intrastat_unit_id = fields.Many2one( - 'intrastat.unit', string='Intrastat Supplementary Unit') - - @api.constrains('local_code') - def _hs_code(self): - if self.company_id.country_id.intrastat: - if not self.local_code.isdigit(): - raise ValidationError( - _("Intrastat Codes should only contain digits. " - "This is not the case for code '%s'.") - % self.local_code) - if len(self.local_code) != 8: - raise ValidationError( - _("Intrastat Codes should " - "contain 8 digits. This is not the case for " - "Intrastat Code '%s' which has %d digits.") - % (self.local_code, len(self.local_code))) - - -class IntrastatTransaction(models.Model): - _name = 'intrastat.transaction' - _description = "Intrastat Transaction" - _order = 'code' - _rec_name = 'display_name' - - @api.one - @api.depends('code', 'description') - def _compute_display_name(self): - display_name = self.code - if self.description: - display_name += ' ' + self.description - self.display_name = len(display_name) > 55 \ - and display_name[:55] + '...' \ - or display_name - - code = fields.Char(string='Code', required=True) - description = fields.Text(string='Description') - display_name = fields.Char( - compute='_compute_display_name', string="Display Name", readonly=True) - company_id = fields.Many2one( - 'res.company', string='Company', - default=lambda self: self.env['res.company']._company_default_get( - 'intrastat.transaction')) - - _sql_constraints = [( - 'intrastat_transaction_code_unique', - 'UNIQUE(code, company_id)', - 'Code must be unique.')] - - -class IntrastatTransportMode(models.Model): - _name = 'intrastat.transport_mode' - _description = "Intrastat Transport Mode" - _rec_name = 'display_name' - _order = 'code' - - @api.one - @api.depends('name', 'code') - def _display_name(self): - self.display_name = '%s. %s' % (self.code, self.name) - - display_name = fields.Char( - string='Display Name', 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) - - _sql_constraints = [( - 'intrastat_transport_code_unique', - 'UNIQUE(code)', - 'Code must be unique.')] diff --git a/intrastat_product/intrastat_view.xml b/intrastat_product/intrastat_view.xml deleted file mode 100644 index c61fc61..0000000 --- a/intrastat_product/intrastat_view.xml +++ /dev/null @@ -1,203 +0,0 @@ - - - - - - - - - - - - - intrastat.hs.code.tree - hs.code - - - - - - - - - - - intrastat.hs.code.form - hs.code - - - - - - - - - - - intrastat.unit.form - intrastat.unit - -
- - - - - - -
-
-
- - - intrastat.unit.tree - intrastat.unit - - - - - - - - - - - intrastat.unit.search - intrastat.unit - - - - - - - - - - - - - Supplementary Units - intrastat.unit - tree,form - - - - - - - intrastat.transaction_form - intrastat.transaction - -
- - - - - -
-
-
- - - intrastat.transaction_tree - intrastat.transaction - - - - - - - - - - - intrastat.transaction.mode.search - intrastat.transaction - - - - - - - - - - - - Transaction Types - intrastat.transaction - tree,form - - - - - - - - intrastat.transport.mode.form - intrastat.transport_mode - -
- - - - - -
-
-
- - - intrastat.transport.mode.tree - intrastat.transport_mode - - - - - - - - - - - intrastat.transport.mode.search - intrastat.transport_mode - - - - - - - - - Transport Modes - intrastat.transport_mode - tree,form - - - - -
-
diff --git a/intrastat_product/models/__init__.py b/intrastat_product/models/__init__.py new file mode 100644 index 0000000..9663fcd --- /dev/null +++ b/intrastat_product/models/__init__.py @@ -0,0 +1,10 @@ +# -*- encoding: utf-8 -*- + +from . import res_company +from . import hs_code +from . import intrastat_transaction +from . import intrastat_unit +from . import intrastat_transport_mode +from . import intrastat_product_declaration +from . import stock_picking +from . import account_invoice diff --git a/intrastat_product/account_invoice.py b/intrastat_product/models/account_invoice.py similarity index 81% rename from intrastat_product/account_invoice.py rename to intrastat_product/models/account_invoice.py index 3179012..74f713a 100644 --- a/intrastat_product/account_invoice.py +++ b/intrastat_product/models/account_invoice.py @@ -1,10 +1,11 @@ # -*- encoding: utf-8 -*- ############################################################################## # -# Copyright (c) 2012-2015 Noviat nv/sa (www.noviat.com) -# Copyright (C) 2015 Akretion (http://www.akretion.com) -# @author Luc de Meyer +# Intrastat Product module for Odoo +# Copyright (C) 2011-2015 Akretion (http://www.akretion.com) +# Copyright (C) 2009-2015 Noviat (http://www.noviat.com) # @author Alexis de Lattre +# @author Luc de Meyer # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -13,11 +14,11 @@ # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . +# along with this program. If not, see . # ############################################################################## @@ -27,14 +28,14 @@ from openerp import models, fields, api class AccountInvoice(models.Model): _inherit = 'account.invoice' - @api.model - def _default_intrastat_transaction(self): - """ placeholder for localisation modules """ - return self.env['intrastat.transaction'].browse([]) - + incoterm_id = fields.Many2one( + 'stock.incoterms', string='Incoterm', + help="International Commercial Terms are a series of predefined " + "commercial terms used in international transactions.") intrastat_transaction_id = fields.Many2one( 'intrastat.transaction', string='Intrastat Transaction Type', - default=_default_intrastat_transaction, ondelete='restrict', + default=lambda self: self._default_intrastat_transaction(), + ondelete='restrict', help="Intrastat nature of transaction") intrastat_transport_id = fields.Many2one( 'intrastat.transport_mode', string='Intrastat Transport Mode', @@ -49,6 +50,11 @@ class AccountInvoice(models.Model): string='Intrastat Declaration', related='company_id.intrastat', store=True, readonly=True) + @api.model + def _default_intrastat_transaction(self): + """ placeholder for localisation modules """ + return self.env['intrastat.transaction'].browse([]) + @api.multi def onchange_partner_id( self, type, partner_id, date_invoice=False, @@ -82,7 +88,9 @@ class AccountInvoiceLine(models.Model): if product: product = self.env['product.product'].browse(product) - hs_code = product.get_hs_code_recursively() + hs_code = product.product_tmpl_id.get_hs_code_recursively() if hs_code: res['value']['hs_code_id'] = hs_code.id + else: + res['value']['hs_code_id'] = False return res diff --git a/intrastat_product/models/hs_code.py b/intrastat_product/models/hs_code.py new file mode 100644 index 0000000..6e23770 --- /dev/null +++ b/intrastat_product/models/hs_code.py @@ -0,0 +1,48 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Intrastat Product module for Odoo +# Copyright (C) 2011-2015 Akretion (http://www.akretion.com) +# Copyright (C) 2009-2015 Noviat (http://www.noviat.com) +# @author Alexis de Lattre +# @author Luc de Meyer +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp import models, fields, api, _ +from openerp.exceptions import ValidationError + + +class HSCode(models.Model): + _inherit = "hs.code" + + intrastat_unit_id = fields.Many2one( + 'intrastat.unit', string='Intrastat Supplementary Unit') + + @api.constrains('local_code') + def _hs_code(self): + if self.company_id.country_id.intrastat: + if not self.local_code.isdigit(): + raise ValidationError( + _("Intrastat Codes should only contain digits. " + "This is not the case for code '%s'.") + % self.local_code) + if len(self.local_code) != 8: + raise ValidationError( + _("Intrastat Codes should " + "contain 8 digits. This is not the case for " + "Intrastat Code '%s' which has %d digits.") + % (self.local_code, len(self.local_code))) diff --git a/intrastat_product/intrastat_declaration.py b/intrastat_product/models/intrastat_product_declaration.py similarity index 86% rename from intrastat_product/intrastat_declaration.py rename to intrastat_product/models/intrastat_product_declaration.py index 9f4f731..ab35776 100644 --- a/intrastat_product/intrastat_declaration.py +++ b/intrastat_product/models/intrastat_product_declaration.py @@ -3,7 +3,9 @@ # # Intrastat Product module for Odoo # Copyright (C) 2011-2015 Akretion (http://www.akretion.com) -# Copyright (C) 2011-2015 Noviat (http://www.noviat.com) +# Copyright (C) 2009-2015 Noviat (http://www.noviat.com) +# @author Alexis de Lattre +# @author Luc de Meyer # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -21,12 +23,11 @@ ############################################################################## from openerp import models, fields, api, _ -from openerp.exceptions import Warning, RedirectWarning, ValidationError +from openerp.exceptions import RedirectWarning, ValidationError import openerp.addons.decimal_precision as dp from datetime import datetime, date from dateutil.relativedelta import relativedelta import logging - _logger = logging.getLogger(__name__) @@ -105,6 +106,10 @@ class IntrastatProductDeclaration(models.Model): 'res.company', string='Company', readonly=True, default=lambda self: self.env['res.company']._company_default_get( 'intrastat.product.declaration')) + 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.Integer( string='Year', required=True, default=_get_year) @@ -186,12 +191,19 @@ class IntrastatProductDeclaration(models.Model): _sql_constraints = [ ('date_uniq', - 'unique(year_month, company_id, type)', + 'unique(year_month, company_id, type, revision)', "A declaration of the same type already exists for this month !" "\nYou should update the existing declaration " "or change the revision number of this one."), ] + @api.one + @api.depends('company_id') + def _compute_company_country_code(self): + if self.company_id: + self.company_country_code = \ + self.company_id.country_id.code.lower() + @api.one @api.depends('year', 'month') def _compute_year_month(self): @@ -219,7 +231,7 @@ class IntrastatProductDeclaration(models.Model): _('Go to company configuration screen')) def _get_partner_country(self, inv_line): - country = inv_line.invoice_id.intrastat_country_id \ + country = inv_line.invoice_id.src_dest_country_id \ or inv_line.invoice_id.partner_id.country_id if not country.intrastat: country = False @@ -228,53 +240,13 @@ class IntrastatProductDeclaration(models.Model): return country def _get_intrastat_transaction(self, inv_line): - if inv_line.invoice_id.intrastat_transaction_id: - tr = inv_line.invoice_id.intrastat_transaction_id.code - else: - tr = self.env.ref( - 'l10n_be_intrastat_advanced.intrastat_transaction_1') - return tr - - def _get_region(self, inv_line): - """ - Logic copied from standard addons, l10n_be_intrastat module: - 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. - """ - region = False - if inv_line.invoice_id.type in ('in_invoice', 'in_refund'): - po_lines = self.env['purchase.order.line'].search( - [('invoice_lines', 'in', inv_line.id)]) - if po_lines: - po = po_lines.order_id - region = self.env['stock.warehouse'].get_region_from_location( - po.location_id) - elif inv_line.invoice_id.type in ('out_invoice', 'out_refund'): - so_lines = self.env['sale.order.line'].search( - [('invoice_lines', 'in', inv_line.id)]) - if so_lines: - so = so_lines.order_id - region = so.warehouse_id.region_id - if not region: - if self.company_id.intrastat_region_id: - region = self.company_id.intrastat_region_id - else: - msg = _( - "The Intrastat Region of the Company is not set, " - "please configure it first.") - self._company_warning(msg) - return region + return inv_line.invoice_id.intrastat_transaction_id def _get_weight_and_supplunits(self, inv_line): line_qty = inv_line.quantity product = inv_line.product_id invoice = inv_line.invoice_id - intrastat_unit_id = inv_line.intrastat_id.intrastat_unit_id + intrastat_unit_id = inv_line.hs_code_id.intrastat_unit_id source_uom = inv_line.uos_id weight_uom_categ = self._uom_refs['weight_uom_categ'] kg_uom = self._uom_refs['kg_uom'] @@ -303,10 +275,10 @@ class IntrastatProductDeclaration(models.Model): "Please correct the Intrastat Supplementary Unit " "settingsand regenerate the lines or adjust the lines " "with Intrastat Code '%s' manually" - ) % intrastat_code + ) % inv_line.hs_code_id.local_code self._note += note return weight, suppl_unit_qty - if target_uom.categ_id == source_uom.category_id: + if target_uom.category_id == source_uom.category_id: suppl_unit_qty = self.env['product.uom']._compute_qty_obj( source_uom, line_qty, target_uom) else: @@ -371,7 +343,7 @@ class IntrastatProductDeclaration(models.Model): return amount def _get_transport(self, inv_line): - transport = inv_line.invoice.transport_mode_id \ + transport = inv_line.invoice_id.intrastat_transport_id \ or self.company_id.intrastat_transport_id if not transport: msg = _( @@ -382,8 +354,8 @@ class IntrastatProductDeclaration(models.Model): return transport def _get_incoterm(self, inv_line): - incoterm = inv_line.invoice.incoterm_id \ - or self.company_id.incoterm_id + incoterm = inv_line.invoice_id.incoterm_id \ + or self.company_id.intrastat_incoterm_id if not incoterm: msg = _( "The default Incoterm " @@ -392,9 +364,13 @@ class IntrastatProductDeclaration(models.Model): self._company_warning(msg) return incoterm + def _update_computation_line_vals(self, inv_line, line_vals): + """ placeholder for localization modules """ + pass + def _gather_invoices(self): - decl_lines = [] + lines = [] start_date = date(self.year, self.month, 1) end_date = start_date + relativedelta(day=1, months=+1, days=-1) @@ -416,7 +392,7 @@ class IntrastatProductDeclaration(models.Model): for inv_line in invoice.invoice_line: - intrastat = inv_line.intrastat_id + intrastat = inv_line.hs_code_id if not intrastat: continue if not inv_line.quantity: @@ -429,8 +405,6 @@ class IntrastatProductDeclaration(models.Model): intrastat_transaction = \ self._get_intrastat_transaction(inv_line) - region = self._get_region(inv_line) - weight, suppl_unit_qty = self._get_weight_and_supplunits( inv_line) @@ -439,29 +413,27 @@ class IntrastatProductDeclaration(models.Model): line_vals = { 'parent_id': self.id, 'invoice_line_id': inv_line.id, - 'partner_country_id': partner_country.id, + 'src_dest_country_id': partner_country.id, 'product_id': inv_line.product_id.id, - 'intrastat_code_id': intrastat.id, + 'hs_code_id': intrastat.id, 'weight': weight, 'suppl_unit_qty': suppl_unit_qty, 'amount_company_currency': amount_company_currency, 'transaction_id': intrastat_transaction.id, - 'region_id': region.id, - 'extended': self._extended, } # extended declaration if self._extended: transport = self._get_transport(inv_line) - incoterm = self._get_incoterm(inv_line) line_vals.update({ 'transport_id': transport.id, - 'incoterm_id': incoterm.id, }) - decl_lines.append((0, 0, line_vals)) + self._update_computation_line_vals(inv_line, line_vals) - return decl_lines + lines.append((line_vals)) + + return lines @api.multi def action_gather(self): @@ -482,27 +454,23 @@ class IntrastatProductDeclaration(models.Model): else: self._extended = False - decl_lines_init = [(6, 0, [])] - decl_lines = decl_lines_init[:] + self.computation_line_ids.unlink() + lines = self._gather_invoices() - decl_lines += self._gather_invoices() - - if decl_lines == decl_lines_init: + if not lines: self.action = 'nihil' note = "\n" + \ _("No records found for the selected period !") + '\n' + \ _("The Declaration Action has been set to 'nihil'.") self._note += note - - # To DO: add check on tax cases 46, 48, 84, 86 - - self.write({'intrastat_line_ids': decl_lines}) + else: + self.write({'computation_line_ids': [(0, 0, x) for x in lines]}) if self._note: note_header = '\n\n>>> ' + str(date.today()) + '\n' - self.note = (self.note or '') + note_header + self._note + self.note = note_header + self._note + (self.note or '') result_view = self.env.ref( - 'l10n_be_intrastat_advanced.intrastat_result_view') + 'intrastat_base.intrastat_result_view_form') return { 'name': _("Generate lines from invoices: results"), 'view_type': 'form', @@ -520,7 +488,7 @@ class IntrastatProductDeclaration(models.Model): def group_line_hashcode(self, computation_line): hashcode = "%s-%s-%s-%s-%s" % ( computation_line.src_dest_country_id.id or False, - computation_line.hs_code or False, + computation_line.hs_code_id.id or False, computation_line.intrastat_unit_id.id or False, computation_line.transaction_id.id or False, computation_line.transport_id.id or False @@ -542,13 +510,22 @@ class IntrastatProductDeclaration(models.Model): dl_group[hashcode].append(cl) else: dl_group[hashcode] = [cl] - ipdlo = self.pool['intrastat.product.declaration.line'] + ipdl = self.declaration_line_ids for cl_lines in dl_group.values(): - vals = ipdlo._prepare_declaration_line(cl_lines) - declaration_line = ipdlo.create(vals) - cl_lines.write({'declaration_line_id': declaration_line.id}) + vals = ipdl._prepare_declaration_line(cl_lines) + declaration_line = ipdl.create(vals) + for cl in cl_lines: + cl.write({'declaration_line_id': declaration_line.id}) return True + @api.multi + def done(self): + self.write({'state': 'done'}) + + @api.multi + def back2draft(self): + self.write({'state': 'draft'}) + class IntrastatProductComputationLine(models.Model): _name = 'intrastat.product.computation.line' @@ -613,6 +590,8 @@ class IntrastatProductComputationLine(models.Model): 'intrastat.transaction', string='Intrastat Transaction') # extended declaration + incoterm_id = fields.Many2one( + 'stock.incoterms', string='Incoterm') transport_id = fields.Many2one( 'intrastat.transport_mode', string='Transport Mode') @@ -687,16 +666,19 @@ class IntrastatProductDeclarationLine(models.Model): 'intrastat.transaction', string='Intrastat Transaction') # extended declaration + # extended declaration + incoterm_id = fields.Many2one( + 'stock.incoterms', string='Incoterm') transport_id = fields.Many2one( 'intrastat.transport_mode', string='Transport Mode') @api.model - def _prepare_grouped_fields(computation_line, fields_to_sum): + def _prepare_grouped_fields(self, computation_line, fields_to_sum): vals = { 'src_dest_country_id': computation_line.src_dest_country_id.id, 'intrastat_unit_id': computation_line.intrastat_unit_id.id, - 'hs_code': computation_line.hs_code_id.local_code, + 'hs_code_id': computation_line.hs_code_id.id, 'transaction_id': computation_line.transaction_id.id, 'transport_id': computation_line.transport_id.id, 'parent_id': computation_line.parent_id.id, @@ -705,7 +687,7 @@ class IntrastatProductDeclarationLine(models.Model): vals[field] = 0.0 return vals - def _fields_to_sum(): + def _fields_to_sum(self): fields_to_sum = [ 'weight', 'suppl_unit_qty', diff --git a/intrastat_product/models/intrastat_transaction.py b/intrastat_product/models/intrastat_transaction.py new file mode 100644 index 0000000..3734fa6 --- /dev/null +++ b/intrastat_product/models/intrastat_transaction.py @@ -0,0 +1,56 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Intrastat Product module for Odoo +# Copyright (C) 2011-2015 Akretion (http://www.akretion.com) +# Copyright (C) 2009-2015 Noviat (http://www.noviat.com) +# @author Alexis de Lattre +# @author Luc de Meyer +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp import models, fields, api + + +class IntrastatTransaction(models.Model): + _name = 'intrastat.transaction' + _description = "Intrastat Transaction" + _order = 'code' + _rec_name = 'display_name' + + code = fields.Char(string='Code', required=True) + description = fields.Text(string='Description') + display_name = fields.Char( + compute='_compute_display_name', string="Display Name", readonly=True) + company_id = fields.Many2one( + 'res.company', string='Company', + default=lambda self: self.env['res.company']._company_default_get( + 'intrastat.transaction')) + + @api.one + @api.depends('code', 'description') + def _compute_display_name(self): + display_name = self.code + if self.description: + display_name += ' ' + self.description + self.display_name = len(display_name) > 55 \ + and display_name[:55] + '...' \ + or display_name + + _sql_constraints = [( + 'intrastat_transaction_code_unique', + 'UNIQUE(code, company_id)', + 'Code must be unique.')] diff --git a/intrastat_product/models/intrastat_transport_mode.py b/intrastat_product/models/intrastat_transport_mode.py new file mode 100644 index 0000000..6157459 --- /dev/null +++ b/intrastat_product/models/intrastat_transport_mode.py @@ -0,0 +1,49 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Intrastat Product module for Odoo +# Copyright (C) 2011-2015 Akretion (http://www.akretion.com) +# Copyright (C) 2009-2015 Noviat (http://www.noviat.com) +# @author Alexis de Lattre +# @author Luc de Meyer +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp import models, fields, api + + +class IntrastatTransportMode(models.Model): + _name = 'intrastat.transport_mode' + _description = "Intrastat Transport Mode" + _rec_name = 'display_name' + _order = 'code' + + display_name = fields.Char( + string='Display Name', 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.one + @api.depends('name', 'code') + def _display_name(self): + self.display_name = '%s. %s' % (self.code, self.name) + + _sql_constraints = [( + 'intrastat_transport_code_unique', + 'UNIQUE(code)', + 'Code must be unique.')] diff --git a/intrastat_product/models/intrastat_unit.py b/intrastat_product/models/intrastat_unit.py new file mode 100644 index 0000000..65a86f2 --- /dev/null +++ b/intrastat_product/models/intrastat_unit.py @@ -0,0 +1,41 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Intrastat Product module for Odoo +# Copyright (C) 2011-2015 Akretion (http://www.akretion.com) +# Copyright (C) 2009-2015 Noviat (http://www.noviat.com) +# @author Alexis de Lattre +# @author Luc de Meyer +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp import models, fields + + +class IntrastatUnit(models.Model): + _name = 'intrastat.unit' + _description = 'Intrastat Supplementary Units' + + name = fields.Char( + string='Name', required=True) + description = fields.Char( + string='Description', required=True) + uom_id = fields.Many2one( + 'product.uom', string='Regular UoM', + help="Select the regular Unit of Measure of Odoo that corresponds " + "to this Intrastat Supplementary Unit.") + active = fields.Boolean( + string='Active', default=True) diff --git a/intrastat_product/res_company.py b/intrastat_product/models/res_company.py similarity index 79% rename from intrastat_product/res_company.py rename to intrastat_product/models/res_company.py index 65e0e3f..988048f 100644 --- a/intrastat_product/res_company.py +++ b/intrastat_product/models/res_company.py @@ -1,10 +1,11 @@ # -*- encoding: utf-8 -*- ############################################################################## # -# Copyright (c) 2012-2015 Noviat nv/sa (www.noviat.com) -# Copyright (C) 2015 Akretion (http://www.akretion.com) -# @author Luc de Meyer +# Intrastat Product module for Odoo +# Copyright (C) 2011-2015 Akretion (http://www.akretion.com) +# Copyright (C) 2009-2015 Noviat (http://www.noviat.com) # @author Alexis de Lattre +# @author Luc de Meyer # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -13,11 +14,11 @@ # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . +# along with this program. If not, see . # ############################################################################## @@ -27,6 +28,25 @@ from openerp import models, fields, api class ResCompany(models.Model): _inherit = 'res.company' + intrastat_incoterm_id = fields.Many2one( + 'stock.incoterms', + string='Default incoterm for Intrastat', + help="International Commercial Terms are a series of " + "predefined commercial terms used in international " + "transactions.") + intrastat_arrivals = fields.Selection( + '_intrastat_arrivals', string='Arrivals', + default='extended', required=True) + intrastat_dispatches = fields.Selection( + '_intrastat_arrivals', string='Dispatches', + default='extended', required=True) + intrastat_transport_id = fields.Many2one( + 'intrastat.transport_mode', + string='Default Transport Mode', ondelete='restrict') + intrastat = fields.Char( + string='Intrastat Declaration', store=True, readonly=True, + compute='_compute_intrastat') + @api.model def _intrastat_arrivals(self): return [ @@ -52,16 +72,3 @@ class ResCompany(models.Model): self.intrastat = 'extended' else: self.intrastat = 'standard' - - intrastat_arrivals = fields.Selection( - '_intrastat_arrivals', string='Arrivals', - default='extended', required=True) - intrastat_dispatches = fields.Selection( - '_intrastat_arrivals', string='Dispatches', - default='extended', required=True) - intrastat_transport_id = fields.Many2one( - 'intrastat.transport_mode', - string='Default Transport Mode', ondelete='restrict') - intrastat = fields.Char( - string='Intrastat Declaration', store=True, readonly=True, - compute='_compute_intrastat') diff --git a/intrastat_product/stock.py b/intrastat_product/models/stock_picking.py similarity index 89% rename from intrastat_product/stock.py rename to intrastat_product/models/stock_picking.py index c97cf75..db97f5b 100644 --- a/intrastat_product/stock.py +++ b/intrastat_product/models/stock_picking.py @@ -1,8 +1,11 @@ # -*- encoding: utf-8 -*- ############################################################################## # -# Copyright (C) 2010-2015 Akretion (http://www.akretion.com) +# Intrastat Product module for Odoo +# Copyright (C) 2011-2015 Akretion (http://www.akretion.com) +# Copyright (C) 2009-2015 Noviat (http://www.noviat.com) # @author Alexis de Lattre +# @author Luc de Meyer # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/intrastat_product/account_invoice_view.xml b/intrastat_product/views/account_invoice.xml similarity index 82% rename from intrastat_product/account_invoice_view.xml rename to intrastat_product/views/account_invoice.xml index cccb557..709ebbb 100644 --- a/intrastat_product/account_invoice_view.xml +++ b/intrastat_product/views/account_invoice.xml @@ -7,6 +7,10 @@ account.invoice + + + @@ -26,6 +30,10 @@ account.invoice + + + diff --git a/intrastat_product/views/hs_code.xml b/intrastat_product/views/hs_code.xml new file mode 100644 index 0000000..f6e54f2 --- /dev/null +++ b/intrastat_product/views/hs_code.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + intrastat.hs.code.tree + hs.code + + + + + + + + + + + intrastat.hs.code.form + hs.code + + + + + + + + + + diff --git a/intrastat_product/intrastat_declaration_view.xml b/intrastat_product/views/intrastat_product_declaration.xml similarity index 88% rename from intrastat_product/intrastat_declaration_view.xml rename to intrastat_product/views/intrastat_product_declaration.xml index 100eb93..ed429e3 100644 --- a/intrastat_product/intrastat_declaration_view.xml +++ b/intrastat_product/views/intrastat_product_declaration.xml @@ -2,7 +2,7 @@ - + intrastat.product.declaration.form intrastat.product.declaration @@ -40,6 +40,7 @@ +
@@ -74,6 +75,7 @@ + @@ -91,6 +93,9 @@ + + @@ -117,8 +122,8 @@ Intrastat Product Declaration Validated - - intrastat.product.tree + + intrastat.product.declaration.tree intrastat.product.declaration @@ -133,8 +138,8 @@ - - intrastat.product.search + + intrastat.product.declaration.search intrastat.product.declaration @@ -150,8 +155,8 @@ - - intrastat.product.graph + + intrastat.product.declaration.graph intrastat.product.declaration @@ -162,16 +167,7 @@ - - Intrastat Product Declaration - intrastat.product.declaration - tree,form,graph - - - - + diff --git a/intrastat_product/views/intrastat_transaction.xml b/intrastat_product/views/intrastat_transaction.xml new file mode 100644 index 0000000..7f80b6b --- /dev/null +++ b/intrastat_product/views/intrastat_transaction.xml @@ -0,0 +1,68 @@ + + + + + + + + + + intrastat.transaction_form + intrastat.transaction + +
+ + + + + +
+
+
+ + + intrastat.transaction_tree + intrastat.transaction + + + + + + + + + + + intrastat.transaction.mode.search + intrastat.transaction + + + + + + + + + + + + Transaction Types + intrastat.transaction + tree,form + + + + +
+
diff --git a/intrastat_product/views/intrastat_transport_mode.xml b/intrastat_product/views/intrastat_transport_mode.xml new file mode 100644 index 0000000..94d51be --- /dev/null +++ b/intrastat_product/views/intrastat_transport_mode.xml @@ -0,0 +1,64 @@ + + + + + + + + + + intrastat.transport.mode.form + intrastat.transport_mode + +
+ + + + + +
+
+
+ + + intrastat.transport.mode.tree + intrastat.transport_mode + + + + + + + + + + + intrastat.transport.mode.search + intrastat.transport_mode + + + + + + + + + Transport Modes + intrastat.transport_mode + tree,form + + + + +
+
diff --git a/intrastat_product/views/intrastat_unit.xml b/intrastat_product/views/intrastat_unit.xml new file mode 100644 index 0000000..2bfa2da --- /dev/null +++ b/intrastat_product/views/intrastat_unit.xml @@ -0,0 +1,70 @@ + + + + + + + + + + intrastat.unit.form + intrastat.unit + +
+ + + + + + +
+
+
+ + + intrastat.unit.tree + intrastat.unit + + + + + + + + + + + intrastat.unit.search + intrastat.unit + + + + + + + + + + + + + Supplementary Units + intrastat.unit + tree,form + + + + +
+
diff --git a/intrastat_product/res_company_view.xml b/intrastat_product/views/res_company.xml similarity index 81% rename from intrastat_product/res_company_view.xml rename to intrastat_product/views/res_company.xml index 9761cb4..06e1ea1 100644 --- a/intrastat_product/res_company_view.xml +++ b/intrastat_product/views/res_company.xml @@ -13,6 +13,8 @@ +
diff --git a/intrastat_product/stock_view.xml b/intrastat_product/views/stock_picking.xml similarity index 100% rename from intrastat_product/stock_view.xml rename to intrastat_product/views/stock_picking.xml diff --git a/product_harmonized_system/README.rst b/product_harmonized_system/README.rst index 52304f1..12798c0 100644 --- a/product_harmonized_system/README.rst +++ b/product_harmonized_system/README.rst @@ -1,6 +1,9 @@ .. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg - :alt: License + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +============================================ Harmonized System Codes (and National Codes) ============================================ @@ -12,11 +15,13 @@ You will also be able to configure the country of origin of a product, which is 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 ===== @@ -24,15 +29,32 @@ To create H.S. codes, go to the menu *Sales > Configuration > Product Categories 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/91/8.0 + + +Bug Tracker +=========== + +Bugs are tracked on `GitHub 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 `here `_. + + Credits ======= -Author -------- +Contributors +------------ * Alexis de Lattre, Akretion * Luc De Meyer, Noviat + Maintainer ---------- .. image:: http://odoo-community.org/logo.png diff --git a/product_harmonized_system/__init__.py b/product_harmonized_system/__init__.py index a64ddf0..21ff7c2 100644 --- a/product_harmonized_system/__init__.py +++ b/product_harmonized_system/__init__.py @@ -1,4 +1,3 @@ # -*- encoding: utf-8 -*- -from . import hs -from . import product +from . import models diff --git a/product_harmonized_system/__openerp__.py b/product_harmonized_system/__openerp__.py index 3575e46..069e1c5 100644 --- a/product_harmonized_system/__openerp__.py +++ b/product_harmonized_system/__openerp__.py @@ -2,7 +2,7 @@ ############################################################################## # # Copyright (C) 2011-2015 Akretion (http://www.akretion.com) -# Copyright (C) 2015 Noviat (http://www.noviat.com) +# Copyright (C) 2009-2015 Noviat (http://www.noviat.com) # @author Alexis de Lattre # @author Luc de Meyer # @@ -23,7 +23,7 @@ { 'name': 'Product Harmonized System Codes', - 'version': '0.1', + 'version': '0.2', 'category': 'Reporting', 'license': 'AGPL-3', 'summary': 'Base module for Product Import/Export reports', @@ -31,11 +31,14 @@ 'depends': ['product'], 'conflicts': ['report_intrastat'], 'data': [ - 'product_view.xml', - 'hs_view.xml', 'security/product_hs_security.xml', 'security/ir.model.access.csv', + 'views/hs_code.xml', + 'views/product_category.xml', + 'views/product_template.xml', + ], + 'demo': [ + 'demo/product_demo.xml', ], - 'demo': ['product_demo.xml'], 'installable': True, } diff --git a/product_harmonized_system/product_demo.xml b/product_harmonized_system/demo/product_demo.xml similarity index 100% rename from product_harmonized_system/product_demo.xml rename to product_harmonized_system/demo/product_demo.xml diff --git a/product_harmonized_system/models/__init__.py b/product_harmonized_system/models/__init__.py new file mode 100644 index 0000000..9750aa8 --- /dev/null +++ b/product_harmonized_system/models/__init__.py @@ -0,0 +1,5 @@ +# -*- encoding: utf-8 -*- + +from . import hs_code +from . import product_category +from . import product_template diff --git a/product_harmonized_system/hs.py b/product_harmonized_system/models/hs_code.py similarity index 95% rename from product_harmonized_system/hs.py rename to product_harmonized_system/models/hs_code.py index bbf34c5..ee61855 100644 --- a/product_harmonized_system/hs.py +++ b/product_harmonized_system/models/hs_code.py @@ -2,7 +2,7 @@ ############################################################################## # # Copyright (C) 2011-2015 Akretion (http://www.akretion.com) -# Copyright (C) 2015 Noviat (http://www.noviat.com) +# Copyright (C) 2009-2015 Noviat (http://www.noviat.com) # @author Alexis de Lattre # @author Luc de Meyer # @@ -30,23 +30,8 @@ class HSCode(models.Model): _order = "local_code" _rec_name = "display_name" - @api.one - @api.depends('local_code') - def _get_hs_code(self): - self.hs_code = self.local_code and self.local_code[:6] - - @api.one - @api.depends('local_code', 'description') - def _compute_display_name(self): - display_name = self.local_code - if self.description: - display_name += ' ' + self.description - self.display_name = len(display_name) > 55 \ - and display_name[:55] + '...' \ - or display_name - hs_code = fields.Char( - string='H.S. Code', compute='_get_hs_code', readonly=True, + string='H.S. Code', compute='_compute_hs_code', readonly=True, help="Harmonized System code (6 digits). Full list is " "available from the World Customs Organisation, see " "http://www.wcoomd.org") @@ -67,6 +52,21 @@ class HSCode(models.Model): default=lambda self: self.env['res.company']._company_default_get( 'hs.code')) + @api.one + @api.depends('local_code') + def _compute_hs_code(self): + self.hs_code = self.local_code and self.local_code[:6] + + @api.one + @api.depends('local_code', 'description') + def _compute_display_name(self): + display_name = self.local_code + if self.description: + display_name += ' ' + self.description + self.display_name = len(display_name) > 55 \ + and display_name[:55] + '...' \ + or display_name + _sql_constraints = [ ('local_code_company_uniq', 'unique(local_code, company_id)', 'This code already exists for this company !'), diff --git a/product_harmonized_system/models/product_category.py b/product_harmonized_system/models/product_category.py new file mode 100644 index 0000000..85e904a --- /dev/null +++ b/product_harmonized_system/models/product_category.py @@ -0,0 +1,46 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2011-2015 Akretion (http://www.akretion.com) +# Copyright (C) 2009-2015 Noviat (http://www.noviat.com) +# @author Alexis de Lattre +# @author Luc de Meyer +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp import models, fields, api + + +class ProductCategory(models.Model): + _inherit = "product.category" + + hs_code_id = fields.Many2one( + 'hs.code', string='H.S. Code', + company_dependent=True, ondelete='restrict', + help="Harmonised System Code. If this code is not " + "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: + res = self.hs_code_id + elif self.parent_id: + res = self.parent_id.get_hs_code_recursively() + else: + res = None + return res diff --git a/product_harmonized_system/product.py b/product_harmonized_system/models/product_template.py similarity index 73% rename from product_harmonized_system/product.py rename to product_harmonized_system/models/product_template.py index 2801a10..497f344 100644 --- a/product_harmonized_system/product.py +++ b/product_harmonized_system/models/product_template.py @@ -2,7 +2,7 @@ ############################################################################## # # Copyright (C) 2011-2015 Akretion (http://www.akretion.com) -# Copyright (C) 2015 Noviat (http://www.noviat.com) +# Copyright (C) 2009-2015 Noviat (http://www.noviat.com) # @author Alexis de Lattre # @author Luc de Meyer # @@ -49,25 +49,3 @@ class ProductTemplate(models.Model): else: res = None return res - - -class ProductCategory(models.Model): - _inherit = "product.category" - - hs_code_id = fields.Many2one( - 'hs.code', string='H.S. Code', - company_dependent=True, ondelete='restrict', - help="Harmonised System Code. If this code is not " - "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: - res = self.hs_code_id - elif self.parent_id: - res = self.parent_id.get_hs_code_recursively() - else: - res = None - return res diff --git a/product_harmonized_system/hs_view.xml b/product_harmonized_system/views/hs_code.xml similarity index 92% rename from product_harmonized_system/hs_view.xml rename to product_harmonized_system/views/hs_code.xml index 0b9a2a7..34b22de 100644 --- a/product_harmonized_system/hs_view.xml +++ b/product_harmonized_system/views/hs_code.xml @@ -10,7 +10,7 @@ - + hs.code.search hs.code @@ -22,7 +22,7 @@ - + hs.code.tree hs.code @@ -36,7 +36,7 @@ - + hs.code.form hs.code diff --git a/product_harmonized_system/views/product_category.xml b/product_harmonized_system/views/product_category.xml new file mode 100644 index 0000000..71b7010 --- /dev/null +++ b/product_harmonized_system/views/product_category.xml @@ -0,0 +1,27 @@ + + + + + + + + + + hs_code.product.category.form + product.category + + + + + + + + + + + + diff --git a/product_harmonized_system/product_view.xml b/product_harmonized_system/views/product_template.xml similarity index 60% rename from product_harmonized_system/product_view.xml rename to product_harmonized_system/views/product_template.xml index 7c15e95..2037b69 100644 --- a/product_harmonized_system/product_view.xml +++ b/product_harmonized_system/views/product_template.xml @@ -22,19 +22,5 @@ - - - hs_code.product.category.form - product.category - - - - - - - - - - From ce293b57db55d1c5351939472cb41d9caa867be1 Mon Sep 17 00:00:00 2001 From: luc-demeyer Date: Tue, 27 Oct 2015 15:06:54 +0100 Subject: [PATCH 065/103] update intrastat modules --- intrastat_base/models/intrastat_common.py | 27 +++++++++++++++++-- .../models/intrastat_product_declaration.py | 19 ++++++++++++- .../views/intrastat_product_declaration.xml | 9 ++++++- 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/intrastat_base/models/intrastat_common.py b/intrastat_base/models/intrastat_common.py index a18ea07..ae892c0 100644 --- a/intrastat_base/models/intrastat_common.py +++ b/intrastat_base/models/intrastat_common.py @@ -85,14 +85,16 @@ class IntrastatCommon(models.AbstractModel): return True @api.model - def _check_xml_schema(self, xml_root, xml_string, xsd_file): + def _check_xml_schema(self, xml_string, xsd_file): '''Validate the XML file against the XSD''' from lxml import etree + from StringIO import StringIO xsd_etree_obj = etree.parse( tools.file_open(xsd_file)) official_schema = etree.XMLSchema(xsd_etree_obj) try: - official_schema.assertValid(xml_root) + t = etree.parse(StringIO(xml_string)) + official_schema.assertValid(t) except Exception, e: # if the validation of the XSD fails, we arrive here logger = logging.getLogger(__name__) @@ -124,6 +126,13 @@ 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), + ('res_id', '=', self.id)]) + atts.unlink() + @api.model def _open_attach_view(self, attach_id, title='XML file'): '''Returns an action which opens the form view of the @@ -140,6 +149,20 @@ class IntrastatCommon(models.AbstractModel): } return action + @api.multi + def _generate_xml(self): + """ + Inherit this method in the localization module + to generate the INTRASTAT Declaration XML file + + Returns: + string with XML data + + Call the _check_xml_schema() method + before returning the XML string. + """ + return False + @api.one def send_reminder_email(self, mail_template_xmlid): mail_template = self.env.ref(mail_template_xmlid) diff --git a/intrastat_product/models/intrastat_product_declaration.py b/intrastat_product/models/intrastat_product_declaration.py index ab35776..db561e2 100644 --- a/intrastat_product/models/intrastat_product_declaration.py +++ b/intrastat_product/models/intrastat_product_declaration.py @@ -23,7 +23,7 @@ ############################################################################## from openerp import models, fields, api, _ -from openerp.exceptions import RedirectWarning, ValidationError +from openerp.exceptions import RedirectWarning, ValidationError, Warning import openerp.addons.decimal_precision as dp from datetime import datetime, date from dateutil.relativedelta import relativedelta @@ -438,6 +438,7 @@ class IntrastatProductDeclaration(models.Model): @api.multi def action_gather(self): self.ensure_one() + self._check_generate_lines() self._note = '' self._uom_refs = { 'weight_uom_categ': self.env.ref('product.product_uom_categ_kgm'), @@ -518,6 +519,22 @@ 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() + self._check_generate_xml() + self._unlink_attachments() + xml_string = self._generate_xml() + if xml_string: + attach_id = self._attach_xml_file( + xml_string, '%s_%s' % (self.type, self.revision)) + return self._open_attach_view(attach_id) + else: + raise Warning( + _("Programming Error."), + _("No XML File has been generated.")) + @api.multi def done(self): self.write({'state': 'done'}) diff --git a/intrastat_product/views/intrastat_product_declaration.xml b/intrastat_product/views/intrastat_product_declaration.xml index ed429e3..860c8da 100644 --- a/intrastat_product/views/intrastat_product_declaration.xml +++ b/intrastat_product/views/intrastat_product_declaration.xml @@ -12,7 +12,13 @@ attrs="{'invisible': ['|', ('state', '!=', 'draft'), ('action', '=', 'nihil')]}" string="Generate lines from invoices" class="oe_highlight"/> -