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.
This commit is contained in:
Alexis de Lattre
2013-10-23 00:25:06 +02:00
parent 819be28513
commit 059c28ac04
8 changed files with 567 additions and 80 deletions

View File

@@ -23,4 +23,3 @@
from . import company
from . import wizard
from . import account_banking_sdd

View File

@@ -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 = [

View File

@@ -14,7 +14,6 @@
<form string="SEPA Direct Debit">
<notebook>
<page string="General Information">
<field name="msg_identification" />
<field name="total_amount" />
<field name="nb_transactions" />
<field name="requested_collec_date" />
@@ -47,7 +46,7 @@
<field name="model">banking.export.sdd</field>
<field name="arch" type="xml">
<tree string="SEPA Direct Debit">
<field name="msg_identification"/>
<field name="filename"/>
<field name="requested_collec_date"/>
<field name="generation_date"/>
<field name="nb_transactions"/>

View File

@@ -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']),
]

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="0"> <!-- TODO : put to 1 when dev of the module is finished -->
<data noupdate="1">
<record id="sdd_mandate_seq_type" model="ir.sequence.type">

View File

@@ -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 "<p class=\"oe_view_nocontent_create\">\n"
" Click to create a new SEPA Direct Debit Mandate.\n"
" </p><p>\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"
" </p>\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 ""

View File

@@ -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'.

View File

@@ -18,8 +18,6 @@
<field name="batch_booking" />
<field name="requested_collec_date" />
<field name="charge_bearer" />
<separator colspan="4" string="Reference for further communication" />
<field name="msg_identification" required="True" />
</group>
<group states="finish">
<field name="total_amount" />