From 059c28ac04afa9aedc80b1675cc4905c6ded9279 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Wed, 23 Oct 2013 00:25:06 +0200 Subject: [PATCH] 2 modifications following a real-life SDD with a French bank: - convert accented chars to ascii chars (via the unidecode lib) - use "PrvtId" instead of "OrgId" in the XML Use the sequence of payment.order as the "Message identification" of the XML file (advantages : it is unique, users can easily customize the sequence and users can easily find the payment corresponding to the "Message Identification" in OpenERP). It is also used as the Payment Identification, combined with the sequence type. Use the sequence of payment.line in the "EndtoEnd Identification" field. Reduce flake8 warnings. --- account_banking_sepa_direct_debit/__init__.py | 1 - .../account_banking_sdd.py | 50 +- .../account_banking_sdd_view.xml | 3 +- account_banking_sepa_direct_debit/company.py | 22 +- .../data/mandate_reference_sequence.xml | 2 +- .../account_banking_sepa_direct_debit.pot | 494 ++++++++++++++++++ .../wizard/export_sdd.py | 73 ++- .../wizard/export_sdd_view.xml | 2 - 8 files changed, 567 insertions(+), 80 deletions(-) create mode 100644 account_banking_sepa_direct_debit/i18n/account_banking_sepa_direct_debit.pot diff --git a/account_banking_sepa_direct_debit/__init__.py b/account_banking_sepa_direct_debit/__init__.py index ce46fda33..f852fb7bd 100644 --- a/account_banking_sepa_direct_debit/__init__.py +++ b/account_banking_sepa_direct_debit/__init__.py @@ -23,4 +23,3 @@ from . import company from . import wizard from . import account_banking_sdd - diff --git a/account_banking_sepa_direct_debit/account_banking_sdd.py b/account_banking_sepa_direct_debit/account_banking_sdd.py index 55c5921fd..0a57ee839 100644 --- a/account_banking_sepa_direct_debit/account_banking_sdd.py +++ b/account_banking_sepa_direct_debit/account_banking_sdd.py @@ -22,18 +22,19 @@ from openerp.osv import orm, fields from openerp.tools.translate import _ from openerp.addons.decimal_precision import decimal_precision as dp +from unidecode import unidecode class banking_export_sdd(orm.Model): '''SEPA Direct Debit export''' _name = 'banking.export.sdd' _description = __doc__ - _rec_name = 'msg_identification' + _rec_name = 'filename' def _generate_filename(self, cr, uid, ids, name, arg, context=None): res = {} for sepa_file in self.browse(cr, uid, ids, context=context): - res[sepa_file.id] = 'sdd_' + (sepa_file.msg_identification or '') + '.xml' + res[sepa_file.id] = 'sdd_%s.xml' % (sepa_file.payment_order_ids[0].reference and unidecode(sepa_file.payment_order_ids[0].reference.replace('/', '-')) or 'error') return res _columns = { @@ -43,13 +44,15 @@ class banking_export_sdd(orm.Model): 'banking_export_sepa_id', 'account_order_id', 'Payment orders', readonly=True), - 'requested_collec_date': fields.date('Requested collection date', readonly=True), - 'nb_transactions': fields.integer('Number of transactions', readonly=True), - 'total_amount': fields.float('Total amount', - digits_compute=dp.get_precision('Account'), readonly=True), - 'msg_identification': fields.char('Message identification', size=35, + 'requested_collec_date': fields.date( + 'Requested collection date', readonly=True), + 'nb_transactions': fields.integer( + 'Number of transactions', readonly=True), + 'total_amount': fields.float( + 'Total amount', digits_compute=dp.get_precision('Account'), readonly=True), - 'batch_booking': fields.boolean('Batch booking', readonly=True, + 'batch_booking': fields.boolean( + 'Batch booking', readonly=True, help="If true, the bank statement will display only one credit line for all the direct debits of the SEPA XML file ; if false, the bank statement will display one credit line per direct debit of the SEPA XML file."), 'charge_bearer': fields.selection([ ('SHAR', 'Shared'), @@ -58,15 +61,15 @@ class banking_export_sdd(orm.Model): ('SLEV', 'Following service level'), ], 'Charge bearer', readonly=True, help='Shared : transaction charges on the sender side are to be borne by the debtor, transaction charges on the receiver side are to be borne by the creditor (most transfers use this). Borne by creditor : all transaction charges are to be borne by the creditor. Borne by debtor : all transaction charges are to be borne by the debtor. Following service level : transaction charges are to be applied following the rules agreed in the service level and/or scheme.'), - 'generation_date': fields.datetime('Generation date', - readonly=True), + 'generation_date': fields.datetime('Generation date', readonly=True), 'file': fields.binary('SEPA XML file', readonly=True), - 'filename': fields.function(_generate_filename, type='char', size=256, - method=True, string='Filename', readonly=True), + 'filename': fields.function( + _generate_filename, type='char', size=256, + string='Filename', readonly=True, store=True), 'state': fields.selection([ - ('draft', 'Draft'), - ('sent', 'Sent'), - ('done', 'Reconciled'), + ('draft', 'Draft'), + ('sent', 'Sent'), + ('done', 'Reconciled'), ], 'State', readonly=True), } @@ -97,7 +100,8 @@ class sdd_mandate(orm.Model): ], 'Type of Mandate', required=True), 'signature_date': fields.date('Date of Signature of the Mandate'), 'scan': fields.binary('Scan of the mandate'), - 'last_debit_date': fields.date('Date of the Last Debit', + 'last_debit_date': fields.date( + 'Date of the Last Debit', help="For recurrent mandates, this field is used to know if the SDD will be of type 'First' or 'Recurring'. For one-off mandates, this field is used to know if the SDD has already been used or not."), 'state': fields.selection([ ('valid', 'Valid'), @@ -113,10 +117,10 @@ class sdd_mandate(orm.Model): )] _defaults = { - 'company_id': lambda self, cr, uid, context: \ + 'company_id': lambda self, cr, uid, context: self.pool['res.users'].browse(cr, uid, uid, context=context).\ company_id.id, - 'unique_mandate_reference': lambda self, cr, uid, context: \ + 'unique_mandate_reference': lambda self, cr, uid, context: self.pool['ir.sequence'].get(cr, uid, 'sdd.mandate.reference'), 'state': 'valid', } @@ -143,15 +147,13 @@ class payment_line(orm.Model): for payline in self.browse(cr, uid, ids): if payline.sdd_mandate_id and not payline.bank_id: raise orm.except_orm( - _('Error :'), - _("Missing bank account on the payment line with SEPA\ - Direct Debit Mandate '%s'." - % payline.sdd_mandate_id.unique_mandate_reference)) + _('Error:'), + _("Missing bank account on the payment line with SEPA Direct Debit Mandate '%s'.") + % payline.sdd_mandate_id.unique_mandate_reference) elif payline.sdd_mandate_id and payline.bank_id and payline.sdd_mandate_id.partner_bank_id != payline.bank_id.id: raise orm.except_orm( - _('Error :'), + _('Error:'), _("The SEPA Direct Debit Mandate '%s' is not related??")) - return True # _constraints = [ diff --git a/account_banking_sepa_direct_debit/account_banking_sdd_view.xml b/account_banking_sepa_direct_debit/account_banking_sdd_view.xml index 2f0d64c9d..8249da13e 100644 --- a/account_banking_sepa_direct_debit/account_banking_sdd_view.xml +++ b/account_banking_sepa_direct_debit/account_banking_sdd_view.xml @@ -14,7 +14,6 @@
- @@ -47,7 +46,7 @@ banking.export.sdd - + diff --git a/account_banking_sepa_direct_debit/company.py b/account_banking_sepa_direct_debit/company.py index aed40f64b..eb3730d57 100644 --- a/account_banking_sepa_direct_debit/company.py +++ b/account_banking_sepa_direct_debit/company.py @@ -34,9 +34,11 @@ class res_company(orm.Model): help="Enter the Creditor Identifier that has been attributed to your company to make SEPA Direct Debits. This identifier is composed of :\n- your country ISO code (2 letters)\n- a 2-digits checkum\n- a 3-letters business code\n- a country-specific identifier"), } - def is_sepa_creditor_identifier_valid(self, cr, uid, sepa_creditor_identifier, context=None): + def is_sepa_creditor_identifier_valid( + self, cr, uid, sepa_creditor_identifier, context=None): """Check if SEPA Creditor Identifier is valid - @param sepa_creditor_identifier: SEPA Creditor Identifier as str or unicode + @param sepa_creditor_identifier: SEPA Creditor Identifier as str + or unicode @return: True if valid, False otherwise """ if not isinstance(sepa_creditor_identifier, (str, unicode)): @@ -44,20 +46,23 @@ class res_company(orm.Model): try: sci_str = str(sepa_creditor_identifier) except: - logger.warning("SEPA Creditor ID should contain only ASCII caracters.") + logger.warning( + "SEPA Creditor ID should contain only ASCII caracters.") return False sci = sci_str.lower() if len(sci) < 9: return False before_replacement = sci[7:] + sci[0:2] + '00' - logger.debug("SEPA ID check before_replacement = %s" % before_replacement) + logger.debug( + "SEPA ID check before_replacement = %s" % before_replacement) after_replacement = '' for char in before_replacement: if char.isalpha(): after_replacement += str(ord(char)-87) else: after_replacement += char - logger.debug("SEPA ID check after_replacement = %s" % after_replacement) + logger.debug( + "SEPA ID check after_replacement = %s" % after_replacement) if int(sci[2:4]) == (98 - (int(after_replacement) % 97)): return True else: @@ -66,10 +71,13 @@ class res_company(orm.Model): def _check_sepa_creditor_identifier(self, cr, uid, ids): for company in self.browse(cr, uid, ids): if company.sepa_creditor_identifier: - if not self.is_sepa_creditor_identifier_valid(cr, uid, company.sepa_creditor_identifier): + if not self.is_sepa_creditor_identifier_valid( + cr, uid, company.sepa_creditor_identifier): return False return True _constraints = [ - (_check_sepa_creditor_identifier, "Invalid SEPA Creditor Identifier.", ['sepa_creditor_identifier']), + (_check_sepa_creditor_identifier, + "Invalid SEPA Creditor Identifier.", + ['sepa_creditor_identifier']), ] diff --git a/account_banking_sepa_direct_debit/data/mandate_reference_sequence.xml b/account_banking_sepa_direct_debit/data/mandate_reference_sequence.xml index 6a3143cca..68075d526 100644 --- a/account_banking_sepa_direct_debit/data/mandate_reference_sequence.xml +++ b/account_banking_sepa_direct_debit/data/mandate_reference_sequence.xml @@ -1,6 +1,6 @@ - + diff --git a/account_banking_sepa_direct_debit/i18n/account_banking_sepa_direct_debit.pot b/account_banking_sepa_direct_debit/i18n/account_banking_sepa_direct_debit.pot new file mode 100644 index 000000000..6c772f970 --- /dev/null +++ b/account_banking_sepa_direct_debit/i18n/account_banking_sepa_direct_debit.pot @@ -0,0 +1,494 @@ +# Translation of OpenERP Server. +# This file contains the translation of the following modules: +# * account_banking_sepa_direct_debit +# +msgid "" +msgstr "" +"Project-Id-Version: OpenERP Server 7.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-10-21 21:21+0000\n" +"PO-Revision-Date: 2013-10-21 21:21+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: account_banking_sepa_direct_debit +#: field:banking.export.sdd,file:0 +msgid "SEPA XML file" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: field:banking.export.sdd,nb_transactions:0 +#: field:banking.export.sdd.wizard,nb_transactions:0 +msgid "Number of transactions" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: code:addons/account_banking_sepa_direct_debit/wizard/export_sdd.py:79 +#, python-format +msgid "This IBAN is not valid : %s" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: code:addons/account_banking_sepa_direct_debit/wizard/export_sdd.py:132 +#, python-format +msgid "Payment Type Code '%s' is not supported. The only Payment Type Code supported for SEPA Direct Debit are 'pain.008.001.02', 'pain.008.001.03' and 'pain.008.001.04'." +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: selection:banking.export.sdd.wizard,state:0 +msgid "Create" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: selection:sdd.mandate,type:0 +msgid "Recurrent" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: field:sdd.mandate,type:0 +msgid "Type of Mandate" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: code:addons/account_banking_sepa_direct_debit/wizard/export_sdd.py:192 +#, python-format +msgid "Missing signature date on SEPA Direct Debit mandate with reference '%s' for partner '%s'." +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: field:banking.export.sdd,filename:0 +#: field:banking.export.sdd.wizard,filename:0 +msgid "Filename" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: model:ir.actions.act_window,name:account_banking_sepa_direct_debit.act_banking_export_sdd_payment_order +msgid "Generated SEPA Direct Debit files" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: field:banking.export.sdd,state:0 +#: field:banking.export.sdd.wizard,state:0 +msgid "State" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: selection:sdd.mandate,state:0 +msgid "Valid" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: selection:banking.export.sdd,state:0 +msgid "Draft" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: code:addons/account_banking_sepa_direct_debit/wizard/export_sdd.py:185 +#, python-format +msgid "The SEPA Direct Debit mandate with reference '%s' for partner '%s' has expired." +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: code:addons/account_banking_sepa_direct_debit/wizard/export_sdd.py:100 +#, python-format +msgid "Cannot compute the '%s' of the Payment Line with Invoice Reference '%s'." +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: view:res.partner.bank:0 +#: field:res.partner.bank,sdd_mandate_ids:0 +msgid "SEPA Direct Debit Mandates" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: field:banking.export.sdd,total_amount:0 +#: field:banking.export.sdd.wizard,total_amount:0 +msgid "Total amount" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: view:banking.export.sdd:0 +msgid "SEPA Direct Debit" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: view:sdd.mandate:0 +msgid "Type" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: field:banking.export.sdd,generation_date:0 +msgid "Generation date" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: selection:banking.export.sdd,state:0 +msgid "Sent" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: field:sdd.mandate,scan:0 +msgid "Scan of the mandate" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: help:banking.export.sdd.wizard,requested_collec_date:0 +msgid "This is the date on which the collection should be made by the bank. Please keep in mind that banks only execute on working days." +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: model:ir.actions.act_window,name:account_banking_sepa_direct_debit.action_account_banking_sdd +#: model:ir.ui.menu,name:account_banking_sepa_direct_debit.menu_account_banking_sdd +msgid "Generated SEPA Direct Debit XML files" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: selection:banking.export.sdd.wizard,state:0 +msgid "Finish" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: view:res.partner:0 +#: view:res.partner.bank:0 +msgid "SDD Mandates" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: code:addons/account_banking_sepa_direct_debit/wizard/export_sdd.py:198 +#, python-format +msgid "The signature date on SEPA Direct Debit mandate with reference '%s' for partner '%s' is '%s', which is in the future !" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: field:res.company,sepa_creditor_identifier:0 +msgid "SEPA Creditor Identifier" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: field:sdd.mandate,company_id:0 +msgid "Company" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: selection:banking.export.sdd,charge_bearer:0 +#: selection:banking.export.sdd.wizard,charge_bearer:0 +msgid "Shared" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: field:sdd.mandate,unique_mandate_reference:0 +msgid "Unique Mandate Reference" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: code:addons/account_banking_sepa_direct_debit/wizard/export_sdd.py:102 +#, python-format +msgid "Cannot compute the '%s'." +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: code:addons/account_banking_sepa_direct_debit/wizard/export_sdd.py:104 +#, python-format +msgid "The type of the field '%s' is %s. It should be a string or unicode." +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: model:ir.model,name:account_banking_sepa_direct_debit.model_banking_export_sdd +msgid "SEPA Direct Debit export" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: model:ir.model,name:account_banking_sepa_direct_debit.model_payment_line +msgid "Payment Line" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: view:payment.order:0 +msgid "SDD Mandate" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: code:addons/account_banking_sepa_direct_debit/account_banking_sdd.py:156 +#, python-format +msgid "The SEPA Direct Debit Mandate '%s' is not related??" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: selection:sdd.mandate,state:0 +msgid "Expired" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: view:banking.export.sdd.wizard:0 +msgid "Generate" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: model:ir.actions.act_window,name:account_banking_sepa_direct_debit.sdd_mandate_action +#: model:ir.model,name:account_banking_sepa_direct_debit.model_sdd_mandate +#: model:ir.ui.menu,name:account_banking_sepa_direct_debit.sdd_mandate_menu +#: field:payment.line,sdd_mandate_id:0 +#: view:sdd.mandate:0 +msgid "SEPA Direct Debit Mandate" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: help:res.company,sepa_creditor_identifier:0 +msgid "Enter the Creditor Identifier that has been attributed to your company to make SEPA Direct Debits. This identifier is composed of :\n" +"- your country ISO code (2 letters)\n" +"- a 2-digits checkum\n" +"- a 3-letters business code\n" +"- a country-specific identifier" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: code:addons/account_banking_sepa_direct_debit/account_banking_sdd.py:151 +#, python-format +msgid "Missing bank account on the payment line with SEPA Direct Debit Mandate '%s'." +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: view:sdd.mandate:0 +msgid "Status" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: code:addons/account_banking_sepa_direct_debit/wizard/export_sdd.py:385 +#, 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: account_banking_sepa_direct_debit +#: sql_constraint:sdd.mandate:0 +msgid "A Mandate with the same reference already exists for this company !" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: code:addons/account_banking_sepa_direct_debit/wizard/export_sdd.py:106 +#, python-format +msgid "The '%s' is empty or 0. It should have a non-null value." +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: code:addons/account_banking_sepa_direct_debit/account_banking_sdd.py:150 +#: code:addons/account_banking_sepa_direct_debit/account_banking_sdd.py:155 +#: code:addons/account_banking_sepa_direct_debit/wizard/export_sdd.py:79 +#: code:addons/account_banking_sepa_direct_debit/wizard/export_sdd.py:100 +#: code:addons/account_banking_sepa_direct_debit/wizard/export_sdd.py:102 +#: code:addons/account_banking_sepa_direct_debit/wizard/export_sdd.py:106 +#: code:addons/account_banking_sepa_direct_debit/wizard/export_sdd.py:132 +#: code:addons/account_banking_sepa_direct_debit/wizard/export_sdd.py:178 +#: code:addons/account_banking_sepa_direct_debit/wizard/export_sdd.py:184 +#: code:addons/account_banking_sepa_direct_debit/wizard/export_sdd.py:191 +#: code:addons/account_banking_sepa_direct_debit/wizard/export_sdd.py:197 +#: code:addons/account_banking_sepa_direct_debit/wizard/export_sdd.py:211 +#: code:addons/account_banking_sepa_direct_debit/wizard/export_sdd.py:385 +#, python-format +msgid "Error:" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: field:sdd.mandate,partner_bank_id:0 +msgid "Bank Account" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: model:ir.model,name:account_banking_sepa_direct_debit.model_res_company +msgid "Companies" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: help:banking.export.sdd,charge_bearer:0 +#: help:banking.export.sdd.wizard,charge_bearer:0 +msgid "Shared : transaction charges on the sender side are to be borne by the debtor, transaction charges on the receiver side are to be borne by the creditor (most transfers use this). Borne by creditor : all transaction charges are to be borne by the creditor. Borne by debtor : all transaction charges are to be borne by the debtor. Following service level : transaction charges are to be applied following the rules agreed in the service level and/or scheme." +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: selection:banking.export.sdd,charge_bearer:0 +#: selection:banking.export.sdd.wizard,charge_bearer:0 +msgid "Borne by creditor" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: field:banking.export.sdd,payment_order_ids:0 +#: field:banking.export.sdd.wizard,payment_order_ids:0 +msgid "Payment orders" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: view:sdd.mandate:0 +msgid "Signature Date" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: help:banking.export.sdd,batch_booking:0 +msgid "If true, the bank statement will display only one credit line for all the direct debits of the SEPA XML file ; if false, the bank statement will display one credit line per direct debit of the SEPA XML file." +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: view:banking.export.sdd.wizard:0 +msgid "Processing details" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: field:banking.export.sdd.wizard,file_id:0 +msgid "SDD XML file" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: model:ir.model,name:account_banking_sepa_direct_debit.model_banking_export_sdd_wizard +msgid "Export SEPA Direct Debit XML file" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: code:addons/account_banking_sepa_direct_debit/wizard/export_sdd.py:104 +#, python-format +msgid "Field type error:" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: model:ir.actions.act_window,help:account_banking_sepa_direct_debit.sdd_mandate_action +msgid "

\n" +" Click to create a new SEPA Direct Debit Mandate.\n" +"

\n" +" The SEPA Direct Debit Mandate is a document signed by your customer that gives you the autorization to do one or several direct debits on his bank account.\n" +"

\n" +" " +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: selection:sdd.mandate,type:0 +msgid "One-Off" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: code:addons/account_banking_sepa_direct_debit/wizard/export_sdd.py:179 +#, python-format +msgid "Missing SEPA Direct Debit mandate on the payment line with partner '%s' and Invoice ref '%s'." +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: view:banking.export.sdd.wizard:0 +msgid "Validate" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: code:addons/account_banking_sepa_direct_debit/wizard/export_sdd.py:212 +#, python-format +msgid "The mandate with reference '%s' for partner '%s' has type set to 'One-Off' and it has a last debit date set to '%s', so we can't use it." +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: help:sdd.mandate,last_debit_date:0 +msgid "For recurrent mandates, this field is used to know if the SDD will be of type 'First' or 'Recurring'. For one-off mandates, this field is used to know if the SDD has already been used or not." +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: field:sdd.mandate,signature_date:0 +msgid "Date of Signature of the Mandate" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: field:sdd.mandate,last_debit_date:0 +msgid "Date of the Last Debit" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: view:sdd.mandate:0 +msgid "Reference" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: constraint:res.company:0 +msgid "Invalid SEPA Creditor Identifier." +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: field:banking.export.sdd,requested_collec_date:0 +#: field:banking.export.sdd.wizard,requested_collec_date:0 +msgid "Requested collection date" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: selection:banking.export.sdd,charge_bearer:0 +#: selection:banking.export.sdd.wizard,charge_bearer:0 +msgid "Borne by debtor" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: model:ir.model,name:account_banking_sepa_direct_debit.model_res_partner_bank +msgid "Bank Accounts" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: selection:banking.export.sdd,charge_bearer:0 +#: selection:banking.export.sdd.wizard,charge_bearer:0 +msgid "Following service level" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: view:banking.export.sdd:0 +msgid "Payment Orders" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: view:banking.export.sdd.wizard:0 +msgid "SEPA Direct Debit XML file generation" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: view:banking.export.sdd:0 +msgid "General Information" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: field:banking.export.sdd,charge_bearer:0 +#: field:banking.export.sdd.wizard,charge_bearer:0 +msgid "Charge bearer" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: field:sdd.mandate,state:0 +msgid "Mandate Status" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: help:banking.export.sdd.wizard,batch_booking:0 +msgid "If true, the bank statement will display only one debit line for all the wire transfers of the SEPA XML file ; if false, the bank statement will display one debit line per wire transfer of the SEPA XML file." +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: field:banking.export.sdd.wizard,file:0 +msgid "File" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: view:banking.export.sdd.wizard:0 +msgid "Cancel" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: field:sdd.mandate,partner_id:0 +msgid "Partner" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: help:sdd.mandate,state:0 +msgid "For a recurrent mandate, this field indicate if the mandate is still valid or if it has expired (a recurrent mandate expires if it's not used during 36 months). For a one-off mandate, it expires after its first use." +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: field:banking.export.sdd,batch_booking:0 +#: field:banking.export.sdd.wizard,batch_booking:0 +msgid "Batch booking" +msgstr "" + +#. module: account_banking_sepa_direct_debit +#: selection:banking.export.sdd,state:0 +msgid "Reconciled" +msgstr "" + diff --git a/account_banking_sepa_direct_debit/wizard/export_sdd.py b/account_banking_sepa_direct_debit/wizard/export_sdd.py index 66e478188..0e935aa7f 100644 --- a/account_banking_sepa_direct_debit/wizard/export_sdd.py +++ b/account_banking_sepa_direct_debit/wizard/export_sdd.py @@ -28,6 +28,7 @@ import base64 from datetime import datetime, timedelta from lxml import etree import logging +from unidecode import unidecode _logger = logging.getLogger(__name__) @@ -38,10 +39,6 @@ class banking_export_sdd_wizard(orm.TransientModel): _columns = { 'state': fields.selection([('create', 'Create'), ('finish', 'Finish')], 'State', readonly=True), - 'msg_identification': fields.char('Message identification', size=35, - # Can't set required=True on the field because it blocks - # the launch of the wizard -> I set it as required in the view - help='This is the message identification of the entire SEPA XML file. 35 characters max.'), 'batch_booking': fields.boolean('Batch booking', help="If true, the bank statement will display only one debit line for all the wire transfers of the SEPA XML file ; if false, the bank statement will display one debit line per wire transfer of the SEPA XML file."), 'requested_collec_date': fields.date('Requested collection date', @@ -72,22 +69,6 @@ class banking_export_sdd_wizard(orm.TransientModel): 'state': 'create', } - - def _check_msg_identification(self, cr, uid, ids): - '''Check that the msg_identification is unique''' - for export_sdd in self.browse(cr, uid, ids): - res = self.pool.get('banking.export.sdd').search(cr, uid, - [('msg_identification', '=', export_sdd.msg_identification)]) - if len(res) > 1: - return False - return True - - - _constraints = [ - (_check_msg_identification, "The field 'Message Identification' should be uniue. Another SEPA Direct Debit file already exists with the same 'Message Identification'.", ['msg_identification']) - ] - - def _validate_iban(self, cr, uid, iban, context=None): '''if IBAN is valid, returns IBAN if IBAN is NOT valid, raises an error message''' @@ -95,7 +76,7 @@ class banking_export_sdd_wizard(orm.TransientModel): if partner_bank_obj.is_iban_valid(cr, uid, iban, context=context): return iban.replace(' ', '') else: - raise orm.except_orm(_('Error :'), _("This IBAN is not valid : %s") % iban) + raise orm.except_orm(_('Error:'), _("This IBAN is not valid : %s") % iban) def create(self, cr, uid, vals, context=None): payment_order_ids = context.get('active_ids', []) @@ -105,24 +86,27 @@ class banking_export_sdd_wizard(orm.TransientModel): return super(banking_export_sdd_wizard, self).create(cr, uid, vals, context=context) - - def _prepare_field(self, cr, uid, field_name, field_value, max_size=0, sepa_export=False, line=False, context=None): + def _prepare_field(self, cr, uid, field_name, field_value, max_size=0, sepa_export=False, line=False, sequence_type=False, context=None): try: - value = eval(field_value) + # SEPA uses XML, and XML = UTF-8 with support for all characters... + # But we are dealing with banks + # and many banks don't want non-ASCCI characters ! + # cf section 1.4 "Character set" of the SEPA Core Direct Debit + # Customer-to-bank implementation guidelines version 6.0 + value = unidecode(eval(field_value)) except: if line: - raise orm.except_orm(_('Error :'), _("Cannot compute the '%s' of the Payment Line with Invoice Reference '%s'.") % (field_name, self.pool['account.invoice'].name_get(cr, uid, [line.ml_inv_ref.id], context=context)[0][1])) + raise orm.except_orm(_('Error:'), _("Cannot compute the '%s' of the Payment Line with Invoice Reference '%s'.") % (field_name, self.pool['account.invoice'].name_get(cr, uid, [line.ml_inv_ref.id], context=context)[0][1])) else: - raise orm.except_orm(_('Error :'), _("Cannot compute the '%s'.") % field_name) + raise orm.except_orm(_('Error:'), _("Cannot compute the '%s'.") % field_name) if not isinstance(value, (str, unicode)): - raise orm.except_orm(_('Field type error :'), _("The type of the field '%s' is %s. It should be a string or unicode.") % (field_name, type(value))) + raise orm.except_orm(_('Field type error:'), _("The type of the field '%s' is %s. It should be a string or unicode.") % (field_name, type(value))) if not value: - raise orm.except_orm(_('Error :'), _("The '%s' is empty or 0. It should have a non-null value.") % field_name) + raise orm.except_orm(_('Error:'), _("The '%s' is empty or 0. It should have a non-null value.") % field_name) if max_size and len(value) > max_size: value = value[0:max_size] return value - def create_sepa(self, cr, uid, ids, context=None): ''' Creates the SEPA Direct Debit file. That's the important code ! @@ -143,7 +127,7 @@ class banking_export_sdd_wizard(orm.TransientModel): name_maxsize = 140 root_xml_tag = 'CstmrDrctDbtInitn' else: - raise orm.except_orm(_('Error :'), _("Payment Type Code '%s' is not supported. The only Payment Type Code supported for SEPA Direct Debit are 'pain.008.001.02', 'pain.008.001.03' and 'pain.008.001.04'.") % pain_flavor) + raise orm.except_orm(_('Error:'), _("Payment Type Code '%s' is not supported. The only Payment Type Code supported for SEPA Direct Debit are 'pain.008.001.02', 'pain.008.001.03' and 'pain.008.001.04'.") % pain_flavor) if sepa_export.requested_collec_date: my_requested_collec_date = sepa_export.requested_collec_date else: @@ -158,13 +142,16 @@ class banking_export_sdd_wizard(orm.TransientModel): pain_root = etree.SubElement(root, root_xml_tag) my_company_name = self._prepare_field(cr, uid, 'Company Name', - 'sepa_export.payment_order_ids[0].company_id.name', - name_maxsize, sepa_export, context=context) + 'sepa_export.payment_order_ids[0].company_id.partner_id.name', + name_maxsize, sepa_export=sepa_export, context=context) # A. Group header group_header_1_0 = etree.SubElement(pain_root, 'GrpHdr') message_identification_1_1 = etree.SubElement(group_header_1_0, 'MsgId') - message_identification_1_1.text = sepa_export.msg_identification + message_identification_1_1.text = self._prepare_field(cr, uid, + 'Message Identification', + 'sepa_export.payment_order_ids[0].reference', 35, + sepa_export=sepa_export, context=context) creation_date_time_1_2 = etree.SubElement(group_header_1_0, 'CreDtTm') creation_date_time_1_2.text = datetime.strftime(datetime.today(), '%Y-%m-%dT%H:%M:%S') nb_of_transactions_1_6 = etree.SubElement(group_header_1_0, 'NbOfTxs') @@ -219,7 +206,7 @@ class banking_export_sdd_wizard(orm.TransientModel): first_recur_lines['OOFF'] = [line] else: raise orm.except_orm( - _('Error :'), + _('Error:'), _("The mandate with reference '%s' for partner '%s' has type set to 'One-Off' and it has a last debit date set to '%s', so we can't use it.") % (line.sdd_mandate_id.unique_mandate_reference, line.sdd_mandate_id.partner_id.name, @@ -240,7 +227,11 @@ class banking_export_sdd_wizard(orm.TransientModel): # B. Payment info payment_info_2_0 = etree.SubElement(pain_root, 'PmtInf') payment_info_identification_2_1 = etree.SubElement(payment_info_2_0, 'PmtInfId') - payment_info_identification_2_1.text = sepa_export.msg_identification + payment_info_identification_2_1.text = self._prepare_field( + cr, uid, 'Payment Information Identification', + "sequence_type + '-' + sepa_export.payment_order_ids[0].reference", + 35, sepa_export=sepa_export, sequence_type=sequence_type, + context=context) payment_method_2_2 = etree.SubElement(payment_info_2_0, 'PmtMtd') payment_method_2_2.text = 'DD' # batch_booking is in "Payment Info" with pain.008.001.02/03 @@ -292,8 +283,8 @@ class banking_export_sdd_wizard(orm.TransientModel): creditor_scheme_identification_2_27 = etree.SubElement(payment_info_2_0, 'CdtrSchmeId') csi_id = etree.SubElement(creditor_scheme_identification_2_27, 'Id') - csi_orgid = csi_id = etree.SubElement(csi_id, 'OrgId') - csi_other = etree.SubElement(csi_orgid, 'Othr') + csi_privateid = csi_id = etree.SubElement(csi_id, 'PrvtId') + csi_other = etree.SubElement(csi_privateid, 'Othr') csi_other_id = etree.SubElement(csi_other, 'Id') csi_other_id.text = self._prepare_field(cr, uid, 'SEPA Creditor Identifier', @@ -313,9 +304,8 @@ class banking_export_sdd_wizard(orm.TransientModel): # Instruction identification (2.30) is not mandatory, so we don't use it end2end_identification_2_31 = etree.SubElement(payment_identification_2_29, 'EndToEndId') end2end_identification_2_31.text = self._prepare_field(cr, uid, - 'End to End Identification', 'line.communication', 35, + 'End to End Identification', 'line.name', 35, line=line, context=context) - payment_type_2_32 = etree.SubElement(dd_transaction_info_2_28, 'PmtTpInf') currency_name = self._prepare_field(cr, uid, 'Currency Code', 'line.currency.name', 3, line=line, context=context) instructed_amount_2_44 = etree.SubElement(dd_transaction_info_2_28, 'InstdAmt', Ccy=currency_name) @@ -389,12 +379,11 @@ class banking_export_sdd_wizard(orm.TransientModel): _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)) # CREATE the banking.export.sepa record file_id = self.pool.get('banking.export.sdd').create(cr, uid, { - 'msg_identification': sepa_export.msg_identification, 'batch_booking': sepa_export.batch_booking, 'charge_bearer': sepa_export.charge_bearer, 'requested_collec_date': sepa_export.requested_collec_date, @@ -422,7 +411,6 @@ class banking_export_sdd_wizard(orm.TransientModel): } return action - def cancel_sepa(self, cr, uid, ids, context=None): ''' Cancel the SEPA Direct Debit file: just drop the file @@ -432,7 +420,6 @@ class banking_export_sdd_wizard(orm.TransientModel): cr, uid, sepa_export.file_id.id, context=context) return {'type': 'ir.actions.act_window_close'} - def save_sepa(self, cr, uid, ids, context=None): ''' Save the SEPA Direct Debit file: mark all payments in the file as 'sent'. diff --git a/account_banking_sepa_direct_debit/wizard/export_sdd_view.xml b/account_banking_sepa_direct_debit/wizard/export_sdd_view.xml index 8357e3f5d..4afa6bb01 100644 --- a/account_banking_sepa_direct_debit/wizard/export_sdd_view.xml +++ b/account_banking_sepa_direct_debit/wizard/export_sdd_view.xml @@ -18,8 +18,6 @@ - -