Reduce pep8 warnings Use create_date instead of a dedicated datetime field The creation of the SEPA file now has a _prepare function Other improvements in the code.

This commit is contained in:
Alexis de Lattre
2013-11-07 12:52:08 +01:00
committed by Enric Tobella
parent 137377a445
commit e08ee1676e
5 changed files with 252 additions and 163 deletions

View File

@@ -34,7 +34,12 @@ class banking_export_sdd(orm.Model):
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_%s.xml' % (sepa_file.payment_order_ids[0].reference and unidecode(sepa_file.payment_order_ids[0].reference.replace('/', '-')) or 'error')
ref = sepa_file.payment_order_ids[0].reference
if ref:
label = unidecode(ref.replace('/', '-'))
else:
label = 'error'
res[sepa_file.id] = 'sdd_%s.xml' % label
return res
_columns = {
@@ -42,27 +47,27 @@ class banking_export_sdd(orm.Model):
'payment.order',
'account_payment_order_sdd_rel',
'banking_export_sepa_id', 'account_order_id',
'Payment orders',
'Payment Orders',
readonly=True),
'requested_collec_date': fields.date(
'Requested collection date', readonly=True),
'Requested Collection Date', readonly=True),
'nb_transactions': fields.integer(
'Number of transactions', readonly=True),
'Number of Transactions', readonly=True),
'total_amount': fields.float(
'Total amount', digits_compute=dp.get_precision('Account'),
'Total Amount', digits_compute=dp.get_precision('Account'),
readonly=True),
'batch_booking': fields.boolean(
'Batch booking', readonly=True,
'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'),
('CRED', 'Borne by creditor'),
('DEBT', 'Borne by debtor'),
('SLEV', 'Following service level'),
], 'Charge bearer', readonly=True,
('CRED', 'Borne by Creditor'),
('DEBT', 'Borne by Debtor'),
('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),
'file': fields.binary('SEPA XML file', readonly=True),
'create_date': fields.datetime('Generation Date', readonly=True),
'file': fields.binary('SEPA XML File', readonly=True),
'filename': fields.function(
_generate_filename, type='char', size=256,
string='Filename', readonly=True, store=True),
@@ -74,7 +79,6 @@ class banking_export_sdd(orm.Model):
}
_defaults = {
'generation_date': fields.date.context_today,
'state': 'draft',
}
@@ -117,10 +121,9 @@ class sdd_mandate(orm.Model):
)]
_defaults = {
'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:
'company_id': lambda self, cr, uid, ctx:
self.pool['res.users'].browse(cr, uid, uid, ctx=ctx).company_id.id,
'unique_mandate_reference': lambda self, cr, uid, ctx:
self.pool['ir.sequence'].get(cr, uid, 'sdd.mandate.reference'),
'state': 'valid',
}
@@ -150,10 +153,12 @@ class payment_line(orm.Model):
_('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:
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:'),
_("The SEPA Direct Debit Mandate '%s' is not related??"))
_("The SEPA Direct Debit Mandate '%s' is not related???"))
return True
# _constraints = [

View File

@@ -19,7 +19,7 @@
<field name="requested_collec_date" />
<field name="batch_booking" />
<field name="charge_bearer"/>
<field name="generation_date" />
<field name="create_date" />
<newline />
<field name="file" filename="filename"/>
<field name="filename" invisible="True"/>
@@ -48,7 +48,7 @@
<tree string="SEPA Direct Debit">
<field name="filename"/>
<field name="requested_collec_date"/>
<field name="generation_date"/>
<field name="create_date"/>
<field name="nb_transactions"/>
</tree>
</field>

View File

@@ -5,7 +5,7 @@
<!-- TODO In the suitable_bank_types field, we should add l10n_fr_rib via a small stupid module -->
<record id="export_sdd_008_001_02" model="payment.mode.type">
<field name="name">SEPA Direct Debit v02</field>
<field name="name">SEPA Direct Debit v02 (recommended)</field>
<field name="code">pain.008.001.02</field>
<field name="suitable_bank_types"
eval="[(6,0,[ref('base_iban.bank_iban')])]" />

View File

@@ -23,6 +23,7 @@
from openerp.osv import orm, fields
from openerp.tools.translate import _
from openerp.tools.safe_eval import safe_eval
from openerp import tools, netsvc
import base64
from datetime import datetime, timedelta
@@ -35,33 +36,41 @@ _logger = logging.getLogger(__name__)
class banking_export_sdd_wizard(orm.TransientModel):
_name = 'banking.export.sdd.wizard'
_description = 'Export SEPA Direct Debit XML file'
_description = 'Export SEPA Direct Debit File'
_columns = {
'state': fields.selection([('create', 'Create'), ('finish', 'Finish')],
'State', readonly=True),
'batch_booking': fields.boolean('Batch booking',
'state': fields.selection([
('create', 'Create'),
('finish', 'Finish'),
], 'State', readonly=True),
'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',
'requested_collec_date': fields.date(
'Requested Collection Date',
help='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.'),
'charge_bearer': fields.selection([
('SHAR', 'Shared'),
('CRED', 'Borne by creditor'),
('DEBT', 'Borne by debtor'),
('SLEV', 'Following service level'),
], 'Charge bearer', required=True,
('CRED', 'Borne by Creditor'),
('DEBT', 'Borne by Debtor'),
('SLEV', 'Following Service Level'),
], 'Charge Bearer', required=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.'),
'nb_transactions': fields.related('file_id', 'nb_transactions',
type='integer', string='Number of transactions', readonly=True),
'total_amount': fields.related('file_id', 'total_amount', type='float',
string='Total amount', readonly=True),
'file_id': fields.many2one('banking.export.sdd', 'SDD XML file', readonly=True),
'file': fields.related('file_id', 'file', string="File", type='binary',
'nb_transactions': fields.related(
'file_id', 'nb_transactions', type='integer',
string='Number of Transactions', readonly=True),
'total_amount': fields.related(
'file_id', 'total_amount', type='float', string='Total Amount',
readonly=True),
'filename': fields.related('file_id', 'filename', string="Filename",
type='char', size=256, readonly=True),
'payment_order_ids': fields.many2many('payment.order',
'wiz_sdd_payorders_rel', 'wizard_id', 'payment_order_id',
'Payment orders', readonly=True),
'file_id': fields.many2one(
'banking.export.sdd', 'SDD XML File', readonly=True),
'file': fields.related(
'file_id', 'file', string="File", type='binary', readonly=True),
'filename': fields.related(
'file_id', 'filename', string="Filename", type='char', size=256,
readonly=True),
'payment_order_ids': fields.many2many(
'payment.order', 'wiz_sdd_payorders_rel', 'wizard_id',
'payment_order_id', 'Payment Orders', readonly=True),
}
_defaults = {
@@ -76,37 +85,94 @@ 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', [])
vals.update({
'payment_order_ids': [[6, 0, payment_order_ids]],
})
return super(banking_export_sdd_wizard, self).create(cr, uid,
vals, context=context)
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, sequence_type=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):
'''This function is designed to be inherited !'''
eval_ctx = {
'sepa_export': sepa_export,
'line': line,
'sequence_type': sequence_type,
}
try:
# SEPA uses XML, and XML = UTF-8 with support for all characters...
# But we are dealing with banks
# SEPA uses XML ; XML = UTF-8 ; UTF-8 = 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))
# Customer-to-bank implementation guidelines
value = unidecode(safe_eval(field_value, eval_ctx))
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 _prepare_export_sepa(
self, cr, uid, sepa_export, total_amount, transactions_count,
xml_string, context=None):
return {
'batch_booking': sepa_export.batch_booking,
'charge_bearer': sepa_export.charge_bearer,
'requested_collec_date': sepa_export.requested_collec_date,
'total_amount': total_amount,
'nb_transactions': transactions_count,
'file': base64.encodestring(xml_string),
'payment_order_ids': [
(6, 0, [x.id for x in sepa_export.payment_order_ids])
],
}
def _validate_xml(self, cr, uid, xml_string, pain_flavor):
xsd_etree_obj = etree.parse(
tools.file_open(
'account_banking_sepa_direct_debit/data/%s.xsd'
% pain_flavor))
official_pain_schema = etree.XMLSchema(xsd_etree_obj)
try:
root_to_validate = etree.fromstring(xml_string)
official_pain_schema.assertValid(root_to_validate)
except Exception, e:
_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))
return True
def create_sepa(self, cr, uid, ids, context=None):
'''
Creates the SEPA Direct Debit file. That's the important code !
@@ -131,7 +197,8 @@ class banking_export_sdd_wizard(orm.TransientModel):
if sepa_export.requested_collec_date:
my_requested_collec_date = sepa_export.requested_collec_date
else:
my_requested_collec_date = datetime.strftime(datetime.today() + timedelta(days=1), '%Y-%m-%d')
my_requested_collec_date = datetime.strftime(
datetime.today() + timedelta(days=1), '%Y-%m-%d')
pain_ns = {
'xsi': 'http://www.w3.org/2001/XMLSchema-instance',
@@ -141,19 +208,22 @@ class banking_export_sdd_wizard(orm.TransientModel):
root = etree.Element('Document', nsmap=pain_ns)
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.partner_id.name',
name_maxsize, sepa_export=sepa_export, context=context)
my_company_name = self._prepare_field(
cr, uid, 'Company Name',
'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 = self._prepare_field(cr, uid,
'Message Identification',
message_identification_1_1 = etree.SubElement(
group_header_1_0, 'MsgId')
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')
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')
control_sum_1_7 = etree.SubElement(group_header_1_0, 'CtrlSum')
initiating_party_1_8 = etree.SubElement(group_header_1_0, 'InitgPty')
@@ -176,7 +246,7 @@ class banking_export_sdd_wizard(orm.TransientModel):
_('Error:'),
_("Missing SEPA Direct Debit mandate on the payment line with partner '%s' and Invoice ref '%s'.")
% (line.partner_id.name,
line.ml_inv_ref.number))
line.ml_inv_ref.number))
if line.sdd_mandate_id.state != 'valid':
raise orm.except_orm(
_('Error:'),
@@ -190,7 +260,8 @@ class banking_export_sdd_wizard(orm.TransientModel):
_("Missing signature date on SEPA Direct Debit mandate with reference '%s' for partner '%s'.")
% (line.sdd_mandate_id.unique_mandate_reference,
line.sdd_mandate_id.partner_id.name))
elif line.sdd_mandate_id.signature_date > datetime.today().strftime('%Y-%m-%d'):
elif (line.sdd_mandate_id.signature_date >
datetime.today().strftime('%Y-%m-%d')):
raise orm.except_orm(
_('Error:'),
_("The signature date on SEPA Direct Debit mandate with reference '%s' for partner '%s' is '%s', which is in the future !")
@@ -206,11 +277,11 @@ class banking_export_sdd_wizard(orm.TransientModel):
first_recur_lines['OOFF'] = [line]
else:
raise orm.except_orm(
_('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,
line.sdd_mandate_id.last_debit_date))
_('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,
line.sdd_mandate_id.last_debit_date))
elif line.sdd_mandate_id.type == 'recurrent':
if line.sdd_mandate_id.last_debit_date:
if first_recur_lines.get('RCUR'):
@@ -226,7 +297,8 @@ class banking_export_sdd_wizard(orm.TransientModel):
for sequence_type, lines in first_recur_lines.items():
# 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 = etree.SubElement(
payment_info_2_0, 'PmtInfId')
payment_info_identification_2_1.text = self._prepare_field(
cr, uid, 'Payment Information Identification',
"sequence_type + '-' + sepa_export.payment_order_ids[0].reference",
@@ -241,57 +313,73 @@ class banking_export_sdd_wizard(orm.TransientModel):
# Implementation guidelines" v6.0 says that control sum
# and nb_of_transactions should be present
# at both "group header" level and "payment info" level
nb_of_transactions_2_4 = etree.SubElement(payment_info_2_0, 'NbOfTxs')
nb_of_transactions_2_4 = etree.SubElement(
payment_info_2_0, 'NbOfTxs')
control_sum_2_5 = etree.SubElement(payment_info_2_0, 'CtrlSum')
payment_type_info_2_6 = etree.SubElement(payment_info_2_0, 'PmtTpInf')
service_level_2_8 = etree.SubElement(payment_type_info_2_6, 'SvcLvl')
payment_type_info_2_6 = etree.SubElement(
payment_info_2_0, 'PmtTpInf')
service_level_2_8 = etree.SubElement(
payment_type_info_2_6, 'SvcLvl')
service_level_code_2_9 = etree.SubElement(service_level_2_8, 'Cd')
service_level_code_2_9.text = 'SEPA'
local_instrument_2_11 = etree.SubElement(payment_type_info_2_6, 'LclInstrm')
local_instr_code_2_12 = etree.SubElement(local_instrument_2_11, 'Cd')
local_instrument_2_11 = etree.SubElement(
payment_type_info_2_6, 'LclInstrm')
local_instr_code_2_12 = etree.SubElement(
local_instrument_2_11, 'Cd')
local_instr_code_2_12.text = 'CORE'
# 2.14 Sequence Type MANDATORY
# this message element must indicate FRST
# 'FRST' = First ; 'OOFF' = One Off ; 'RCUR' : Recurring
# 'FNAL' = Final
sequence_type_2_14 = etree.SubElement(payment_type_info_2_6, 'SeqTp')
sequence_type_2_14 = etree.SubElement(
payment_type_info_2_6, 'SeqTp')
sequence_type_2_14.text = sequence_type
requested_collec_date_2_18 = etree.SubElement(payment_info_2_0, 'ReqdColltnDt')
requested_collec_date_2_18 = etree.SubElement(
payment_info_2_0, 'ReqdColltnDt')
requested_collec_date_2_18.text = my_requested_collec_date
creditor_2_19 = etree.SubElement(payment_info_2_0, 'Cdtr')
creditor_name = etree.SubElement(creditor_2_19, 'Nm')
creditor_name.text = my_company_name
creditor_account_2_20 = etree.SubElement(payment_info_2_0, 'CdtrAcct')
creditor_account_2_20 = etree.SubElement(
payment_info_2_0, 'CdtrAcct')
creditor_account_id = etree.SubElement(creditor_account_2_20, 'Id')
creditor_account_iban = etree.SubElement(creditor_account_id, 'IBAN')
creditor_account_iban.text = self._validate_iban(cr, uid,
self._prepare_field(cr, uid, 'Company IBAN',
creditor_account_iban = etree.SubElement(
creditor_account_id, 'IBAN')
creditor_account_iban.text = self._validate_iban(
cr, uid, self._prepare_field(
cr, uid, 'Company IBAN',
'sepa_export.payment_order_ids[0].mode.bank_id.acc_number',
sepa_export=sepa_export, context=context),
context=context)
creditor_agent_2_21 = etree.SubElement(payment_info_2_0, 'CdtrAgt')
creditor_agent_institution = etree.SubElement(creditor_agent_2_21, 'FinInstnId')
creditor_agent_bic = etree.SubElement(creditor_agent_institution, bic_xml_tag)
creditor_agent_bic.text = self._prepare_field(cr, uid, 'Company BIC',
creditor_agent_institution = etree.SubElement(
creditor_agent_2_21, 'FinInstnId')
creditor_agent_bic = etree.SubElement(
creditor_agent_institution, bic_xml_tag)
creditor_agent_bic.text = self._prepare_field(
cr, uid, 'Company BIC',
'sepa_export.payment_order_ids[0].mode.bank_id.bank.bic',
sepa_export=sepa_export, context=context)
charge_bearer_2_24 = etree.SubElement(payment_info_2_0, 'ChrgBr')
charge_bearer_2_24.text = sepa_export.charge_bearer
creditor_scheme_identification_2_27 = etree.SubElement(payment_info_2_0, 'CdtrSchmeId')
csi_id = etree.SubElement(creditor_scheme_identification_2_27, 'Id')
creditor_scheme_identification_2_27 = etree.SubElement(
payment_info_2_0, 'CdtrSchmeId')
csi_id = etree.SubElement(
creditor_scheme_identification_2_27, 'Id')
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',
csi_other_id.text = self._prepare_field(
cr, uid, 'SEPA Creditor Identifier',
'sepa_export.payment_order_ids[0].company_id.sepa_creditor_identifier',
sepa_export=sepa_export, context=context)
csi_scheme_name = etree.SubElement(csi_other, 'SchmeNm')
csi_scheme_name_proprietary = etree.SubElement(csi_scheme_name, 'Prtry')
csi_scheme_name_proprietary = etree.SubElement(
csi_scheme_name, 'Prtry')
csi_scheme_name_proprietary.text = 'SEPA'
transactions_count_2_4 = 0
@@ -299,22 +387,29 @@ class banking_export_sdd_wizard(orm.TransientModel):
for line in lines:
transactions_count_2_4 += 1
# C. Direct Debit Transaction Info
dd_transaction_info_2_28 = etree.SubElement(payment_info_2_0, 'DrctDbtTxInf')
payment_identification_2_29 = etree.SubElement(dd_transaction_info_2_28, 'PmtId')
# 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.name', 35,
dd_transaction_info_2_28 = etree.SubElement(
payment_info_2_0, 'DrctDbtTxInf')
payment_identification_2_29 = etree.SubElement(
dd_transaction_info_2_28, 'PmtId')
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.name', 35,
line=line, context=context)
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)
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)
instructed_amount_2_44.text = '%.2f' % line.amount_currency
amount_control_sum_1_7 += line.amount_currency
amount_control_sum_2_5 += line.amount_currency
dd_transaction_2_46 = etree.SubElement(dd_transaction_info_2_28, 'DrctDbtTx')
mandate_related_info_2_47 = etree.SubElement(dd_transaction_2_46, 'MndtRltdInf')
mandate_identification_2_48 = etree.SubElement(mandate_related_info_2_47, 'MndtId')
dd_transaction_2_46 = etree.SubElement(
dd_transaction_info_2_28, 'DrctDbtTx')
mandate_related_info_2_47 = etree.SubElement(
dd_transaction_2_46, 'MndtRltdInf')
mandate_identification_2_48 = etree.SubElement(
mandate_related_info_2_47, 'MndtId')
mandate_identification_2_48.text = self._prepare_field(
cr, uid, 'Unique Mandate Reference',
'line.sdd_mandate_id.unique_mandate_reference',
@@ -327,81 +422,67 @@ class banking_export_sdd_wizard(orm.TransientModel):
line=line, context=context)
# TODO look at 2.50 "Amendment Indicator
debtor_agent_2_70 = etree.SubElement(dd_transaction_info_2_28, 'DbtrAgt')
debtor_agent_institution = etree.SubElement(debtor_agent_2_70, 'FinInstnId')
debtor_agent_bic = etree.SubElement(debtor_agent_institution, bic_xml_tag)
debtor_agent_bic.text = self._prepare_field(cr, uid,
'Customer BIC', 'line.bank_id.bank.bic',
debtor_agent_2_70 = etree.SubElement(
dd_transaction_info_2_28, 'DbtrAgt')
debtor_agent_institution = etree.SubElement(
debtor_agent_2_70, 'FinInstnId')
debtor_agent_bic = etree.SubElement(
debtor_agent_institution, bic_xml_tag)
debtor_agent_bic.text = self._prepare_field(
cr, uid, 'Customer BIC', 'line.bank_id.bank.bic',
line=line, context=context)
debtor_2_72 = etree.SubElement(dd_transaction_info_2_28, 'Dbtr')
debtor_2_72 = etree.SubElement(
dd_transaction_info_2_28, 'Dbtr')
debtor_name = etree.SubElement(debtor_2_72, 'Nm')
debtor_name.text = self._prepare_field(cr, uid,
'Customer Name', 'line.partner_id.name',
debtor_name.text = self._prepare_field(
cr, uid, 'Customer Name', 'line.partner_id.name',
name_maxsize, line=line, context=context)
debtor_account_2_73 = etree.SubElement(dd_transaction_info_2_28, 'DbtrAcct')
debtor_account_2_73 = etree.SubElement(
dd_transaction_info_2_28, 'DbtrAcct')
debtor_account_id = etree.SubElement(debtor_account_2_73, 'Id')
debtor_account_iban = etree.SubElement(debtor_account_id, 'IBAN')
debtor_account_iban.text = self._validate_iban(cr, uid,
self._prepare_field(cr, uid, 'Customer IBAN',
debtor_account_iban = etree.SubElement(
debtor_account_id, 'IBAN')
debtor_account_iban.text = self._validate_iban(
cr, uid, self._prepare_field(
cr, uid, 'Customer IBAN',
'line.bank_id.acc_number', line=line,
context=context),
context=context)
remittance_info_2_88 = etree.SubElement(dd_transaction_info_2_28, 'RmtInf')
context=context),
context=context)
remittance_info_2_88 = etree.SubElement(
dd_transaction_info_2_28, 'RmtInf')
# switch to Structured (Strdr) ? If we do it, beware that the format is not the same between pain 02 and pain 03
remittance_info_unstructured_2_89 = etree.SubElement(remittance_info_2_88, 'Ustrd')
remittance_info_unstructured_2_89.text = self._prepare_field(cr, uid,
'Remittance Information', 'line.communication',
remittance_info_unstructured_2_89 = etree.SubElement(
remittance_info_2_88, 'Ustrd')
remittance_info_unstructured_2_89.text = self._prepare_field(
cr, uid, 'Remittance Information', 'line.communication',
140, line=line, context=context)
nb_of_transactions_2_4.text = str(transactions_count_2_4)
control_sum_2_5.text = '%.2f' % amount_control_sum_2_5
nb_of_transactions_1_6.text = str(transactions_count_1_6)
control_sum_1_7.text = '%.2f' % amount_control_sum_1_7
xml_string = etree.tostring(root, pretty_print=True, encoding='UTF-8', xml_declaration=True)
_logger.debug("Generated SDD XML file in format %s below" % pain_flavor)
xml_string = etree.tostring(
root, pretty_print=True, encoding='UTF-8', xml_declaration=True)
_logger.debug(
"Generated SDD XML file in format %s below" % pain_flavor)
_logger.debug(xml_string)
xsd_etree_obj = etree.parse(tools.file_open('account_banking_sepa_direct_debit/data/%s.xsd' % pain_flavor))
official_pain_schema = etree.XMLSchema(xsd_etree_obj)
_logger.debug("Printing %s XML Schema definition:" % pain_flavor)
_logger.debug(etree.tostring(xsd_etree_obj, pretty_print=True, encoding='UTF-8', xml_declaration=True))
try:
# If I do official_pain_schema.assertValid(root), then I get this
# error msg in the exception :
# 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 : Element 'Document': No matching global declaration available for the validation root.
# So I re-import the SEPA XML from the string, and give this
# so validation
# If you know how I can avoid that, please tell me -- Alexis
root_to_validate = etree.fromstring(xml_string)
official_pain_schema.assertValid(root_to_validate)
except Exception, e:
_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))
self._validate_xml(cr, uid, xml_string, pain_flavor)
# CREATE the banking.export.sepa record
file_id = self.pool.get('banking.export.sdd').create(cr, uid,
{
'batch_booking': sepa_export.batch_booking,
'charge_bearer': sepa_export.charge_bearer,
'requested_collec_date': sepa_export.requested_collec_date,
'total_amount': total_amount,
'nb_transactions': transactions_count_1_6,
'file': base64.encodestring(xml_string),
'payment_order_ids': [
(6, 0, [x.id for x in sepa_export.payment_order_ids])
],
}, context=context)
file_id = self.pool.get('banking.export.sdd').create(
cr, uid, self._prepare_export_sepa(
cr, uid, sepa_export, total_amount, transactions_count_1_6,
xml_string, context=context),
context=context)
self.write(cr, uid, ids, {
'file_id': file_id,
'state': 'finish',
self.write(
cr, uid, ids, {
'file_id': file_id,
'state': 'finish',
}, context=context)
action = {
'name': 'SEPA Direct Debit XML',
'name': 'SEPA Direct Debit File',
'type': 'ir.actions.act_window',
'view_type': 'form',
'view_mode': 'form,tree',
@@ -422,12 +503,14 @@ class banking_export_sdd_wizard(orm.TransientModel):
def save_sepa(self, cr, uid, ids, context=None):
'''
Save the SEPA Direct Debit file: mark all payments in the file as 'sent'.
Write 'last debit date' on mandate and set oneoff mandate to expired
Save the SEPA Direct Debit file: mark all payments in the file
as 'sent'. Write 'last debit date' on mandate and set oneoff
mandate to expired
'''
sepa_export = self.browse(cr, uid, ids[0], context=context)
self.pool.get('banking.export.sdd').write(cr, uid,
sepa_export.file_id.id, {'state': 'sent'}, context=context)
self.pool.get('banking.export.sdd').write(
cr, uid, sepa_export.file_id.id, {'state': 'sent'},
context=context)
wf_service = netsvc.LocalService('workflow')
for order in sepa_export.payment_order_ids:
wf_service.trg_validate(uid, 'payment.order', order.id, 'done', cr)
@@ -437,7 +520,9 @@ class banking_export_sdd_wizard(orm.TransientModel):
'last_debit_date': datetime.today().strftime('%Y-%m-%d')
},
context=context)
oneoff_mandate_ids = [line.sdd_mandate_id.id for line in order.line_ids if line.sdd_mandate_id.type == 'oneoff']
oneoff_mandate_ids = \
[line.sdd_mandate_id.id for line in order.line_ids
if line.sdd_mandate_id.type == 'oneoff']
self.pool['sdd.mandate'].write(
cr, uid, oneoff_mandate_ids, {'state': 'expired'},
context=context)

View File

@@ -14,7 +14,6 @@
<form string="SEPA Direct Debit XML file generation" version="7.0">
<field name="state" invisible="True"/>
<group states="create">
<separator colspan="4" string="Processing details" />
<field name="batch_booking" />
<field name="requested_collec_date" />
<field name="charge_bearer" />