From a9a22ebdea17c89f9a1ccbd7e802b8120cfaa3e5 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Sun, 3 Apr 2011 17:37:07 +0200 Subject: [PATCH] More work on full DEB+DES implementation. Added full support for "transport type" and partial support for the department. More factorisation between product & service module. Add date_done field. More checks. --- l10n_fr_intrastat_base/__init__.py | 8 +- l10n_fr_intrastat_base/__terp__.py | 18 +- l10n_fr_intrastat_base/account_invoice.py | 2 +- l10n_fr_intrastat_base/company.py | 2 +- l10n_fr_intrastat_base/company_view.xml | 7 + l10n_fr_intrastat_base/country_view.xml | 6 + l10n_fr_intrastat_base/intrastat_common.py | 197 +++--------------- ...{report_intrastat.py => intrastat_type.py} | 3 +- ...astat_demo.xml => intrastat_type_data.xml} | 7 + ...astat_view.xml => intrastat_type_view.xml} | 6 + l10n_fr_intrastat_base/partner_address.py | 3 +- l10n_fr_intrastat_base/product.py | 3 +- l10n_fr_intrastat_base/product_view.xml | 7 + .../security/ir.model.access.csv | 2 +- 14 files changed, 88 insertions(+), 183 deletions(-) rename l10n_fr_intrastat_base/{report_intrastat.py => intrastat_type.py} (97%) rename l10n_fr_intrastat_base/{intrastat_demo.xml => intrastat_type_data.xml} (80%) rename l10n_fr_intrastat_base/{report_intrastat_view.xml => intrastat_type_view.xml} (96%) diff --git a/l10n_fr_intrastat_base/__init__.py b/l10n_fr_intrastat_base/__init__.py index 01b3a141..4fbf7213 100644 --- a/l10n_fr_intrastat_base/__init__.py +++ b/l10n_fr_intrastat_base/__init__.py @@ -1,9 +1,9 @@ # -*- encoding: utf-8 -*- ############################################################################## # -# OpenERP, Open Source Management Solution -# Copyright (C) 2004-2009 Tiny SPRL (http://tiny.be). All Rights Reserved -# Copyright (C) 2010-2011 Akretion (http://www.akretion.com). All Rights Reserved +# 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 @@ -20,7 +20,7 @@ # ############################################################################## -import report_intrastat +import intrastat_type import country import product import account_invoice diff --git a/l10n_fr_intrastat_base/__terp__.py b/l10n_fr_intrastat_base/__terp__.py index 60ff12fb..4d0e4b1f 100644 --- a/l10n_fr_intrastat_base/__terp__.py +++ b/l10n_fr_intrastat_base/__terp__.py @@ -1,9 +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 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 @@ -22,31 +22,33 @@ { - 'name': 'Base module for Intrastat reporting (DEB + DES) for France', + 'name': 'Base module for Intrastat reporting (DEB & DES) for France', '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 the other 2 modules. +This module is not usefull if it's not used together with one of those 2 modules. 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 and OpenERP S.A.', + 'author': 'Akretion', 'website': 'http://www.akretion.com', 'depends': ['account'], - 'init_xml': ['country_data.xml'], + 'init_xml': ['country_data.xml', 'intrastat_type_data.xml'], 'update_xml': [ 'security/ir.model.access.csv', 'product_view.xml', 'country_view.xml', - 'report_intrastat_view.xml', + 'intrastat_type_view.xml', 'company_view.xml', 'account_invoice_view.xml', 'account_invoice_workflow.xml', ], - 'demo_xml': ['intrastat_demo.xml'], + 'demo_xml': [], 'installable': True, 'active': False, } diff --git a/l10n_fr_intrastat_base/account_invoice.py b/l10n_fr_intrastat_base/account_invoice.py index 35f2e0c6..56196eb4 100644 --- a/l10n_fr_intrastat_base/account_invoice.py +++ b/l10n_fr_intrastat_base/account_invoice.py @@ -1,7 +1,7 @@ # -*- encoding: utf-8 -*- ############################################################################## # -# OpenERP, Open Source Management Solution +# Report intrastat base module for OpenERP # Copyright (C) 2009-2011 Akretion (http://www.akretion.com/) All Rights Reserved # # This program is free software: you can redistribute it and/or modify diff --git a/l10n_fr_intrastat_base/company.py b/l10n_fr_intrastat_base/company.py index abe72567..22dccc6a 100644 --- a/l10n_fr_intrastat_base/company.py +++ b/l10n_fr_intrastat_base/company.py @@ -1,7 +1,7 @@ # -*- encoding: utf-8 -*- ############################################################################## # -# OpenERP, Open Source Management Solution +# Report intrastat base module for OpenERP # Copyright (C) 2009-2011 Akretion (http://www.akretion.com/) All Rights Reserved # # This program is free software: you can redistribute it and/or modify diff --git a/l10n_fr_intrastat_base/company_view.xml b/l10n_fr_intrastat_base/company_view.xml index 47ff9446..1fa71c65 100644 --- a/l10n_fr_intrastat_base/company_view.xml +++ b/l10n_fr_intrastat_base/company_view.xml @@ -1,4 +1,11 @@ + + + diff --git a/l10n_fr_intrastat_base/country_view.xml b/l10n_fr_intrastat_base/country_view.xml index a851262c..3e7d4321 100644 --- a/l10n_fr_intrastat_base/country_view.xml +++ b/l10n_fr_intrastat_base/country_view.xml @@ -1,4 +1,10 @@ + + + diff --git a/l10n_fr_intrastat_base/intrastat_common.py b/l10n_fr_intrastat_base/intrastat_common.py index deee25fe..ff7b4b1d 100644 --- a/l10n_fr_intrastat_base/intrastat_common.py +++ b/l10n_fr_intrastat_base/intrastat_common.py @@ -1,9 +1,9 @@ # -*- encoding: utf-8 -*- ############################################################################## # -# Report intrastat module for OpenERP +# Report intrastat base module for OpenERP # Copyright (C) 2010-2011 Akretion (http://www.akretion.com/). All rights reserved. -# Code written by Alexis de Lattre +# @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 @@ -21,7 +21,6 @@ ############################################################################## from osv import osv, fields -import netsvc from datetime import datetime, timedelta from dateutil.relativedelta import relativedelta from tools.translate import _ @@ -63,184 +62,54 @@ class report_intrastat_common(osv.osv_memory): return False return True - def generate_service_lines(self, cr, uid, ids, context=None): - print "generate lines, ids=", ids + + def _check_generate_lines(self, cr, uid, ids, intrastat, context=None): + print "START _check_generate_lines ids=", ids if len(ids) != 1: - raise osv.except_osv(_('Error :'), _('Hara kiri in generate_service_lines')) - intrastat = self.browse(cr, uid, ids[0], context=context) - # Check that the company currency is EUR + 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)) - # Get current service lines and delete them - line_remove = self.read(cr, uid, ids[0], ['intrastat_line_ids'], context=context) - print "line_remove", line_remove - if line_remove['intrastat_line_ids']: - self.pool.get('report.intrastat.service.line').unlink(cr, uid, line_remove['intrastat_line_ids'], context=context) - sql = ''' - select - min(inv_line.id) as id, - company.id, - inv.name as name, - inv.number as invoice_number, - inv.date_invoice, - inv.currency_id as invoice_currency_id, - prt.vat as partner_vat, - prt.name as partner_name, - res_currency_rate.rate as invoice_currency_rate, - sum(case when inv.type = 'out_refund' - then inv_line.price_subtotal * (-1) - when inv.type = 'out_invoice' - then inv_line.price_subtotal - end) as amount_invoice_currency, - sum(case when company.currency_id != inv.currency_id and res_currency_rate.rate is not null - then - case when inv.type = 'out_refund' - then round(inv_line.price_subtotal/res_currency_rate.rate * (-1), 2) - when inv.type = 'out_invoice' - then round(inv_line.price_subtotal/res_currency_rate.rate, 2) - end - when company.currency_id = inv.currency_id - then - case when inv.type = 'out_refund' - then inv_line.price_subtotal * (-1) - when inv.type = 'out_invoice' - then inv_line.price_subtotal - end - end) as amount_company_currency, - company.currency_id as company_currency_id - - from account_invoice inv - left join account_invoice_line inv_line on inv_line.invoice_id=inv.id - left join (product_template pt - left join product_product pp on pp.product_tmpl_id = pt.id - ) - on (inv_line.product_id = pt.id) - left join (res_partner_address inv_address - left join res_country inv_country on (inv_country.id = inv_address.country_id)) - on (inv_address.id = inv.address_invoice_id) - left join res_partner prt on inv.partner_id = prt.id - left join report_intrastat_type intr on inv.intrastat_type_id = intr.id - left join res_currency_rate on (inv.currency_id = res_currency_rate.currency_id and inv.date_invoice = res_currency_rate.name) - left join res_company company on inv.company_id=company.id - - where - inv.type in ('out_invoice', 'out_refund') - and inv.state in ('open', 'paid') - and inv_line.product_id is not null - and inv_line.price_subtotal != 0 - and inv_country.intrastat = true - and pt.type = 'service' - and pt.exclude_from_intrastat is not true - and intr.type != 'other' - and company.id = %s - and inv.date_invoice >= %s - and inv.date_invoice <= %s - - group by company.id, inv.date_invoice, inv.number, inv.currency_id, prt.vat, prt.name, inv.name, invoice_currency_rate, company_currency_id - ''' - user = self.pool.get('res.users').browse(cr, uid, uid, context=context) - company_id = str(user.company_id.id) - print "company_id =", company_id - start_date_str = intrastat.start_date - end_date_str = intrastat.end_date - # Execute the big SQL query to get all service lines - cr.execute(sql, (company_id, start_date_str, end_date_str)) - res_sql = cr.fetchall() - print "res_sql=", res_sql - line_obj = self.pool.get('report.intrastat.service.line') - for id, name, company_id, invoice_number, date_invoice, invoice_currency_id, partner_vat, partner_name, invoice_currency_rate, amount_invoice_currency, amount_company_currency, company_currency_id in res_sql: - print "amount_invoice_currency =", amount_invoice_currency - print "amount_company_currency =", amount_company_currency - # Store the service lines - line_obj.create(cr, uid, { - 'parent_id': ids[0], - 'name': name, - 'invoice_number': invoice_number, - 'partner_vat': partner_vat, - 'partner_name': partner_name, - 'date_invoice': date_invoice, - 'amount_invoice_currency': int(round(amount_invoice_currency, 0)), - 'invoice_currency_id': invoice_currency_id, - 'amount_company_currency': int(round(amount_company_currency, 0)), - 'company_currency_id': company_currency_id, - }, context=context) return None - def done(self, cr, uid, ids, context=None): - if len(ids) != 1: - raise osv.except_osv(_('Error :'), _('Hara kiri in generate_xml')) - self.write(cr, uid, ids[0], {'state': 'done'}, context=context) - return None - - def back2draft(self, cr, uid, ids, context=None): + def _check_generate_xml(self, cr, uid, ids, intrastat, context=None): + print "START _check_generate_xml ids=", ids if len(ids) != 1: - raise osv.except_osv(_('Error :'), _('Hara kiri in generate_xml')) - self.write(cr, uid, ids[0], {'state': 'draft'}, context=context) + 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 generate_xml(self, cr, uid, ids, context=None): - intrastat = self.browse(cr, uid, ids[0], context=context) - start_date_str = intrastat.start_date - end_date_str = intrastat.end_date - start_date_datetime = datetime.strptime(start_date_str, '%Y-%m-%d') - - user = self.pool.get('res.users').browse(cr, uid, uid, context=context) - - 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 user.company_id.partner_id.vat: - raise osv.except_osv(_('Error :'), _('The VAT number is not set for the partner "%s".'%user.company_id.partner_id.name)) - my_company_vat = user.company_id.partner_id.vat.replace(' ', '') - - # Tech spec of XML export are available here : - # https://pro.douane.gouv.fr/download/downloadUrl.asp?file=PubliwebBO/fichiers/DES_DTIPlus.pdf - root = etree.Element('fichier_des') - decl = etree.SubElement(root, 'declaration_des') - num_des = etree.SubElement(decl, 'num_des') - num_des.text = datetime.strftime(start_date_datetime, '%Y%m') - num_tva = etree.SubElement(decl, 'num_tvaFr') - num_tva.text = my_company_vat - mois_des = etree.SubElement(decl, 'mois_des') - mois_des.text = datetime.strftime(start_date_datetime, '%m') # month 2 digits - an_des = etree.SubElement(decl, 'an_des') - an_des.text = datetime.strftime(start_date_datetime, '%Y') - line = 0 - # we now go through each service line - for sline in intrastat.intrastat_line_ids: - line += 1 # increment line number - ligne_des = etree.SubElement(decl, 'ligne_des') - numlin_des = etree.SubElement(ligne_des, 'numlin_des') - numlin_des.text = str(line) - valeur = etree.SubElement(ligne_des, 'valeur') - # We take amount_company_currency, to be sure we have amounts in EUR - valeur.text = str(sline.amount_company_currency) - partner_des = etree.SubElement(ligne_des, 'partner_des') - try: partner_des.text = sline.partner_vat.replace(' ', '') - except: raise osv.except_osv(_('Error :'), _('Missing VAT number for partner "%s".'%sline.partner_name)) - xml_string = etree.tostring(root, pretty_print=True, encoding='UTF-8', xml_declaration=True) - print "xml_string", xml_string - - # We now validate the XML file against the official XML Schema Definition - official_des_xml_schema = etree.XMLSchema(etree.fromstring(des_xsd.des_xsd)) - try: official_des_xml_schema.assertValid(root) + 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_service', netsvc.LOG_WARNING, "The XML file is invalid against the XSD") - logger.notifyChannel('intrastat_service', netsvc.LOG_WARNING, xml_string) - logger.notifyChannel('intrastat_service', netsvc.LOG_WARNING, e) + 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))) - #let's give a pretty name to the filename : - filename = datetime.strftime(start_date_datetime, '%Y-%m') + '_des.xml' - attach_name = 'DES ' + datetime.strftime(start_date_datetime, '%Y-%m') + return None - # Attach the XML file to the intrastat_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 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': 'report.intrastat.service'}) + print "object name = ", 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 None diff --git a/l10n_fr_intrastat_base/report_intrastat.py b/l10n_fr_intrastat_base/intrastat_type.py similarity index 97% rename from l10n_fr_intrastat_base/report_intrastat.py rename to l10n_fr_intrastat_base/intrastat_type.py index 1b37aac2..1e3fdc39 100644 --- a/l10n_fr_intrastat_base/report_intrastat.py +++ b/l10n_fr_intrastat_base/intrastat_type.py @@ -1,7 +1,7 @@ # -*- encoding: utf-8 -*- ############################################################################## # -# OpenERP, Open Source Management Solution +# Report intrastat base module for OpenERP # Copyright (C) 2010-2011 Akretion (http://www.akretion.com/) All Rights Reserved # # This program is free software: you can redistribute it and/or modify @@ -20,7 +20,6 @@ ############################################################################## from osv import osv, fields -from tools.translate import _ class report_intrastat_type(osv.osv): diff --git a/l10n_fr_intrastat_base/intrastat_demo.xml b/l10n_fr_intrastat_base/intrastat_type_data.xml similarity index 80% rename from l10n_fr_intrastat_base/intrastat_demo.xml rename to l10n_fr_intrastat_base/intrastat_type_data.xml index bc7cc2d7..a65ce931 100644 --- a/l10n_fr_intrastat_base/intrastat_demo.xml +++ b/l10n_fr_intrastat_base/intrastat_type_data.xml @@ -1,4 +1,11 @@ + + + diff --git a/l10n_fr_intrastat_base/report_intrastat_view.xml b/l10n_fr_intrastat_base/intrastat_type_view.xml similarity index 96% rename from l10n_fr_intrastat_base/report_intrastat_view.xml rename to l10n_fr_intrastat_base/intrastat_type_view.xml index 35f24f28..f3cc92a5 100644 --- a/l10n_fr_intrastat_base/report_intrastat_view.xml +++ b/l10n_fr_intrastat_base/intrastat_type_view.xml @@ -1,4 +1,10 @@ + + + diff --git a/l10n_fr_intrastat_base/partner_address.py b/l10n_fr_intrastat_base/partner_address.py index 4d4bb34f..bc4e4f06 100644 --- a/l10n_fr_intrastat_base/partner_address.py +++ b/l10n_fr_intrastat_base/partner_address.py @@ -1,8 +1,9 @@ # -*- encoding: utf-8 -*- ############################################################################## # -# OpenERP, Open Source Management Solution +# 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 diff --git a/l10n_fr_intrastat_base/product.py b/l10n_fr_intrastat_base/product.py index 122a5759..d6c30f5a 100644 --- a/l10n_fr_intrastat_base/product.py +++ b/l10n_fr_intrastat_base/product.py @@ -1,8 +1,9 @@ # -*- encoding: utf-8 -*- ############################################################################## # -# OpenERP, Open Source Management Solution +# 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 diff --git a/l10n_fr_intrastat_base/product_view.xml b/l10n_fr_intrastat_base/product_view.xml index 070492d3..30d253c6 100644 --- a/l10n_fr_intrastat_base/product_view.xml +++ b/l10n_fr_intrastat_base/product_view.xml @@ -1,4 +1,11 @@ + + + diff --git a/l10n_fr_intrastat_base/security/ir.model.access.csv b/l10n_fr_intrastat_base/security/ir.model.access.csv index 62543002..fe43ec70 100644 --- a/l10n_fr_intrastat_base/security/ir.model.access.csv +++ b/l10n_fr_intrastat_base/security/ir.model.access.csv @@ -1,3 +1,3 @@ "id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" "access_report_intrastat_type","report.intrastat.type","model_report_intrastat_type","account.group_account_manager",1,1,1,1 -"access_report_intrastat_common","Read access on report.intrastat.common","model_report_intrastat_common","base.user",1,0,0,0 +"access_report_intrastat_common","Read access on report.intrastat.common","model_report_intrastat_common","base.group_user",1,0,0,0