Merge lp:~akretion-team/banking-addons/70-sepa-trf-dd-updates into lp:banking-addons

Proposed by Alexis de Lattre
Status: Merged
Merged at revision: 219
Proposed branch: lp:~akretion-team/banking-addons/70-sepa-trf-dd-updates
Merge into: lp:banking-addons
Diff against target: 8121 lines (+6854/-635)
51 files modified
account_banking_pain_base/__init__.py (+26/-0)
account_banking_pain_base/__openerp__.py (+50/-0)
account_banking_pain_base/banking_export_pain.py (+439/-0)
account_banking_pain_base/company.py (+78/-0)
account_banking_pain_base/company_view.xml (+24/-0)
account_banking_pain_base/i18n/account_banking_pain_base.pot (+146/-0)
account_banking_pain_base/i18n/fr.po (+146/-0)
account_banking_pain_base/payment_line.py (+52/-0)
account_banking_pain_base/payment_line_view.xml (+41/-0)
account_banking_pain_base/payment_mode.py (+39/-0)
account_banking_pain_base/payment_mode_view.xml (+22/-0)
account_banking_payment/__openerp__.py (+1/-0)
account_banking_payment/model/__init__.py (+1/-1)
account_banking_payment/model/account_payment.py (+1/-0)
account_banking_payment/model/payment_mode.py (+7/-4)
account_banking_payment/view/payment_mode.xml (+1/-0)
account_banking_payment/view/payment_order_create_view.xml (+23/-0)
account_banking_sepa_credit_transfer/__openerp__.py (+1/-1)
account_banking_sepa_credit_transfer/account_banking_sepa.py (+15/-6)
account_banking_sepa_credit_transfer/account_banking_sepa_view.xml (+0/-2)
account_banking_sepa_credit_transfer/i18n/account_banking_sepa_credit_transfer.pot (+12/-70)
account_banking_sepa_credit_transfer/i18n/fr.po (+29/-235)
account_banking_sepa_credit_transfer/wizard/export_sepa.py (+130/-284)
account_banking_sepa_credit_transfer/wizard/export_sepa_view.xml (+0/-1)
account_banking_sepa_direct_debit/__init__.py (+25/-0)
account_banking_sepa_direct_debit/__openerp__.py (+60/-0)
account_banking_sepa_direct_debit/account_banking_sdd.py (+424/-0)
account_banking_sepa_direct_debit/account_banking_sdd_view.xml (+80/-0)
account_banking_sepa_direct_debit/account_invoice_view.xml (+22/-0)
account_banking_sepa_direct_debit/account_payment_view.xml (+26/-0)
account_banking_sepa_direct_debit/company.py (+89/-0)
account_banking_sepa_direct_debit/company_view.xml (+23/-0)
account_banking_sepa_direct_debit/data/mandate_reference_sequence.xml (+21/-0)
account_banking_sepa_direct_debit/data/pain.008.001.02.xsd (+879/-0)
account_banking_sepa_direct_debit/data/pain.008.001.03.xsd (+925/-0)
account_banking_sepa_direct_debit/data/pain.008.001.04.xsd (+892/-0)
account_banking_sepa_direct_debit/data/payment_type_sdd.xml (+37/-0)
account_banking_sepa_direct_debit/i18n/account_banking_sepa_direct_debit.pot (+633/-0)
account_banking_sepa_direct_debit/i18n/fr.po (+642/-0)
account_banking_sepa_direct_debit/mandate_expire_cron.xml (+26/-0)
account_banking_sepa_direct_debit/res_partner_bank_view.xml (+48/-0)
account_banking_sepa_direct_debit/sdd_mandate_view.xml (+149/-0)
account_banking_sepa_direct_debit/security/ir.model.access.csv (+4/-0)
account_banking_sepa_direct_debit/security/original_mandate_required_security.xml (+17/-0)
account_banking_sepa_direct_debit/wizard/__init__.py (+23/-0)
account_banking_sepa_direct_debit/wizard/export_sdd.py (+451/-0)
account_banking_sepa_direct_debit/wizard/export_sdd_view.xml (+37/-0)
account_direct_debit/model/account_invoice.py (+3/-3)
account_direct_debit/model/account_move_line.py (+31/-0)
account_direct_debit/model/account_payment.py (+0/-28)
account_direct_debit/view/account_payment.xml (+3/-0)
To merge this branch: bzr merge lp:~akretion-team/banking-addons/70-sepa-trf-dd-updates
Reviewer Review Type Date Requested Status
Guewen Baconnier @ Camptocamp Approve
Christophe Combelles (community) Approve
Stefan Rijnhart (Opener) Approve
Stéphane Bidoul (Acsone) (community) test sct Approve
Review via email: mp+200019@code.launchpad.net

Description of the change

This branch contains :
- support for SEPA direct debit
- the work I carried out with Luc de Meyer (Noviat) during a code sprint on November 21st to get the additionnal features that were present in Luc's module account_pain for SEPA credit transfer (including the "Initiating Party Issuer", which is required by a few countries including Belgium and structured remittance info)
- the module account_banking_pain_base : this module allows to share as much code as possible between the module for credit transfers and the module for direct debits

This merge proposal replaces my former merge proposal which took too much time (the code was already out-dated) :
https://code.launchpad.net/~akretion-team/banking-addons/70-sepa-direct-debit/+merge/195139

P.S. : 38 days left before SEPA migration deadline !

To post a comment you must log in.
Revision history for this message
Alexis de Lattre (alexis-via) wrote :

One small note for the PEP8 fundamentalists : the 3 modules account_banking_pain_base, account_banking_sepa_credit_transfer and account_banking_sepa_direct_debit are fully PEP8 compliant, so you won't be able to block this merge proposal for such a stupid reason :)

Revision history for this message
Stefan Rijnhart (Opener) (stefan-opener) wrote :

Hi,

first of all sorry for my absense on the community front, I have been too busy with first of January deadlines. Hope to show my face more often soon.

So I just had a quick glance and I must thank you Alexis and Luc for your great work. Just one thought about the removal of the communication2 field from the payment line view: does SEPA not allow additional comments on the order lines? And if it really doesn't, maybe we could make the payment view a little bit more dynamic depending on the payment type in a future proposal. Could you leave it in for now?

A cosmetic thing: it seems that remittance_info_unstructured_2_100 should be called remittance_info_structured_2_100

review: Needs Information
Revision history for this message
Stéphane Bidoul (Acsone) (sbi) wrote :

Thanks Alexis and Luc for this great effort.

I made a quick test of account_banking_sepa_credit_transfer and it looks good.

In combination with base_iban_bic_not_required however, it complains with Cannot compute 'Debtor BIC' or 'Creditor BIC'. the PAIN xsd have the BIC elements optional. Can you fix that one?

On the nitpicking side, I noticed a few "return True" and the end of generate_*_block methods which are unncessary.

review: Needs Fixing (sct test)
226. By Alexis de Lattre

Put the field communication2 back in the view of payment lines.
Rename a badly named variable (thanks to Stefan Rijnhart for spotting this)

Revision history for this message
Alexis de Lattre (alexis-via) wrote :
Download full text (3.5 KiB)

@Stefan :

I fixed the variable name, thanks for spotting.

About the communication2 field :
- for the unstructured remittance info, there is only a single field of 140 chars. The PAIN standard says "[0..n]" for the unstructured tag, but the EPC guidelines explicitely say "Format Rule: Only one occurrence of ‘Unstructured’ is allowed."
- for the structured remittance info, we use the communication field for the 2.126 reference field (35 chars) ; maybe we could use the communication2 field for the 2.129 "Additionnal Remittance information" field, which is fully optional. But, at the moment, when you have the communication type set to structured, OpenERP prevent you from using the field "communication2" ; it seems that this is managed by addons-70/account_payment/account_payment.py in the function fields_get() at the end of the file.

I must say that I don't like to have these 2 fields "communication" and "communication2", because I find it confusing for the users, and I would prefer a single field "communication" to make things simple and avoid mistakes.

By the way, investigating this made me realize that, when communication type = "Free", you can't use the field "communication" because it is readonly ; only the field "communication2" is usable in this case. This is really a mess and the help message on the communication fields don't mention that at all ; I find it very confusing.

@Stéphane Bidoul:

About the "BIC not required". First, looking at the XSD file is not enough, because the target is to respect the guidelines of the European Payment Council (EPC) for SEPA, which may add some constrains that are not in the PAIN standard and thus that are not in the XSD file. When I look at the EPC guidelines, I understand this :

- for the Debtor agent (2.21), this tag is [1..1], but it seems possible to not use the "BIC" and set "Debtor Agent > Financial Institution Identification > Other > Identification" to "NOTPROVIDED".

- for the Creditor agent (2.77), it says explicitely "Usage Rule: Only BIC is allowed", but the Credit Agent tag (2.77) is [0..1], so it may be dropped.

From what I understand, BIC is required for international payments but not required for national payment. When I look at the code of the module "base_iban_bic_not_required", I see that it drops the constraint all together, so, with this module, the user is allowed to enter a foreigh bank account without BIC, which is a problem.

So who handles the check that BIC is present if the IBAN is from a different country than the country of the company ?
Option A : we update the module "base_iban_bic_not_required" to have a constraints which make BIC required when the country of the IBAN is different from the country of "Your Company".
Option B : I handle this check in the code of the SEPA modules.

I think option B is better because it will block user earlier in the process (when entering the bank account in OpenERP, not when generating the SEPA XML file). If we agree on option B :
- someone has to update the module "base_iban_bic_not_required" to have a constraints which make BIC required when the country of the IBAN is different from the country of "Your Company".
- I will update ...

Read more...

Revision history for this message
Stefan Rijnhart (Opener) (stefan-opener) wrote :

Thanks for your changes! As for optional bics, you wrote you preferred B but I when I read carefully you mean option A.
However, res.partner.bank is not linked to a company, unless it is a bank account of the company itself. Therefore, I do think option B is the only feasible possibility for the constraint, because only then the company and therefore its country is known.

Revision history for this message
Alexis de Lattre (alexis-via) wrote :

@Stefan

Yes, I meant option A, but I understand you remark about the fact that res.partner.bank is not linked to a company.

So it leaves us with option B... which means I will have to do all the work in my code ! :) But it shouldn't be very hard, as I just have to check that the 2 first letters of the IBAN of the creditor correspond to the country of the debtor (for a SCT).

227. By Alexis de Lattre

If it's a national payment, we now support "BIC not provided".

Revision history for this message
Alexis de Lattre (alexis-via) wrote :

@Stéphane Bidoul:

I have implemented option B in revno 227.

I am wondering something : if it's a cross-border credit transfer, we have to provide the BIC of the foreign creditors (my code checks this and raises a nice error msg if it's not the case), but do we have to provide the BIC of the debtor (= Your Company) ?

I am still interested in reading more documentation about the "BIC not required", because I haven't found accurate info about it yet.

Revision history for this message
Stefan Rijnhart (Opener) (stefan-opener) wrote :

Basic facts:

The Business Identifier Code (BIC) may still be required until 1 February 2014 for domestic payments and 1 February 2016 for cross-border payments. Member States may defer the requirement relating to the provision of the BIC for national payment transactions until 1 February 2016.

http://www.ecb.europa.eu/paym/sepa/about/migration/html/index.en.html

This is expressed differently in different bank's specifications. One bank says: the BIC field is ignored, don't use it. Another bank says: the field is optional. You should use it if the bank cannot determine the BIC by itself.

I know it's not that well specified, but it seems to me that there is even less need for the bank to know the BIC of their own customers. Then again, it seems just good practice if the company BIC were stored properly in OpenERP (I think it is printed by default in the standard report footer). Maybe this is something that can be implemented as a contraint in the not_required module.

Revision history for this message
Stefan Rijnhart (Opener) (stefan-opener) wrote :

BTW thanks for already coding the support for missing BICs. In this code, you catch the general exception. Can you catch the actual exception raised instead, or if it's only an exception caused by missing BIC, deal with this differently than a try/catch block?

review: Needs Fixing
228. By Alexis de Lattre

For SCT, if BIC is not provided, we should not put the 'Creditor Agent' block at all, according to EPC guidelines (on this point, it is different from the Direct Debit !)

Revision history for this message
Alexis de Lattre (alexis-via) wrote :

@Stefan

Thanks for your very clear explaination about BIC and for the URL you provided. It is very clear for me now.

I made some test on the website of a French bank and read this interesting document which precisely deal with this topic (the doc is in French, sorry) :
http://universwiftnet.files.wordpress.com/2013/07/addendum-guides-utilisation-standard-iso20022-remises-ordres-sepa-v1-0.pdf

This document underline a small detail that I didn't catch when reading the guidelines of the EPC : in a credit transfer, for the creditor, you should not put the CreditorAgent block at all (but, in a direct debit, for the debtor, you should use the current implementation Financial Institution Identification > Other > Identification = NOTPROVIDED). I checked again in the guidelines of the EPC and it confirm this. So I have just modified my code to reflect this.

About the exception, you are right, my code is not as good as it should. I am not an expert in this, but i'll try to do better in a later commit.

Revision history for this message
Stéphane Bidoul (Acsone) (sbi) wrote :

Thanks a lot for the improvement with missing BICs.

I tested it again and checked with the ING validator.

LGTM for SCT.

review: Approve (test sct)
229. By Alexis de Lattre

Only catch the openerp exception in generate_party_agent(), as suggested by Stefan on the MP.

Revision history for this message
Alexis de Lattre (alexis-via) wrote :

@Stefan

Could you tell me if my last commit revno 229 addresses your point about the management of the exception ?

Revision history for this message
Stefan Rijnhart (Opener) (stefan-opener) wrote :

To be honest, I am still wondering what exception is actually raised in the 'try' block. Is it a direct consequence of the missing BIC? In that case, a simple if-clause would be nicer.

review: Needs Information
Revision history for this message
Alexis de Lattre (alexis-via) wrote :

@Stefan

Yes, it is a direct consequence of the support of the missing BIC. I can't put an "if" clause, because the content of the if would be different depending on the origin of the function call :

- if we are in block B, we would have to test "sepa_export.payment_order_ids[0].mode.bank_id.bank.bic"

- if we are in block C, we would have to test "line.bank_id.bank.bic"

I think that, if we want to avoid this "try/except" in generate_party_agent(), I would need to fully re-organize the code about BIC following the introduction of the support of the missing BIC :
- check if we have a BIC or not in wizard/export_sepa.py just before each call to the function generate_party_block() and pass this information in the call of the function generate_party_block()
- then I could remove the try/except in the function generate_party_agent()

So, if you still want me to remove the try/except in generate_party_agent() and you agree with my proposal to re-organise the code, I will make the change described above.

Revision history for this message
Stefan Rijnhart (Opener) (stefan-opener) wrote :

Thank you for your response, Alexis. I see it is a little more complicated than a simple if-clause. An alternative solution could be to throw proper ValueError (if it is empty) and TypeError (if it is not a str/unicode) exceptions in _prepare_field, so you could catch these specific exceptions in the try/catch block. But if these were to occur elsewhere, the user would be confronted with a backtrace instead of a popup error from the except_orm.

Given the deadline, maybe this issue should better be put this on the todo list so I'll approve this one now.

review: Approve
Revision history for this message
Christophe Combelles (ccomb) wrote :

We're successfully using this module in production for a few weeks,
thanks for the work!

review: Approve
Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

Excellent work. Thanks

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added directory 'account_banking_pain_base'
=== added file 'account_banking_pain_base/__init__.py'
--- account_banking_pain_base/__init__.py 1970-01-01 00:00:00 +0000
+++ account_banking_pain_base/__init__.py 2014-01-13 12:42:46 +0000
@@ -0,0 +1,26 @@
1# -*- encoding: utf-8 -*-
2##############################################################################
3#
4# PAIN Base module for OpenERP
5# Copyright (C) 2013 Akretion (http://www.akretion.com)
6# @author: Alexis de Lattre <alexis.delattre@akretion.com>
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Affero General Public License as
10# published by the Free Software Foundation, either version 3 of the
11# License, or (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.
17#
18# You should have received a copy of the GNU Affero General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20#
21##############################################################################
22
23from . import payment_line
24from . import payment_mode
25from . import company
26from . import banking_export_pain
027
=== added file 'account_banking_pain_base/__openerp__.py'
--- account_banking_pain_base/__openerp__.py 1970-01-01 00:00:00 +0000
+++ account_banking_pain_base/__openerp__.py 2014-01-13 12:42:46 +0000
@@ -0,0 +1,50 @@
1##############################################################################
2#
3# PAIN base module for OpenERP
4# Copyright (C) 2013 Akretion (http://www.akretion.com)
5# @author: Alexis de Lattre <alexis.delattre@akretion.com>
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as
9# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU Affero General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21{
22 'name': 'Account Banking PAIN Base Module',
23 'summary': 'Base module for PAIN file generation',
24 'version': '0.1',
25 'license': 'AGPL-3',
26 'author': 'Akretion, Noviat',
27 'website': 'http://openerp-community-association.org/',
28 'category': 'Hidden',
29 'depends': ['account_banking_payment_export'],
30 'external_dependencies': {
31 'python': ['unidecode', 'lxml'],
32 },
33 'data': [
34 'payment_line_view.xml',
35 'payment_mode_view.xml',
36 'company_view.xml',
37 ],
38 'description': '''
39Base module for PAIN file generation
40====================================
41
42This module contains fields and functions that are used by the module for SEPA Credit Transfer (account_banking_sepa_credit_transfer) and SEPA Direct Debit (account_banking_sepa_direct_debit). This module doesn't provide any functionnality by itself.
43
44This module is part of the banking addons: https://launchpad.net/banking-addons
45
46This module was started during the Akretion-Noviat code sprint of November 21st 2013 in Epiais les Louvres (France).
47 ''',
48 'active': False,
49 'installable': True,
50}
051
=== added file 'account_banking_pain_base/banking_export_pain.py'
--- account_banking_pain_base/banking_export_pain.py 1970-01-01 00:00:00 +0000
+++ account_banking_pain_base/banking_export_pain.py 2014-01-13 12:42:46 +0000
@@ -0,0 +1,439 @@
1# -*- encoding: utf-8 -*-
2##############################################################################
3#
4# PAIN Base module for OpenERP
5# Copyright (C) 2013 Akretion (http://www.akretion.com)
6# @author: Alexis de Lattre <alexis.delattre@akretion.com>
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Affero General Public License as
10# published by the Free Software Foundation, either version 3 of the
11# License, or (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.
17#
18# You should have received a copy of the GNU Affero General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20#
21##############################################################################
22
23from openerp.osv import orm
24from openerp.tools.translate import _
25from openerp.tools.safe_eval import safe_eval
26from datetime import datetime
27from unidecode import unidecode
28from lxml import etree
29from openerp import tools
30import logging
31import base64
32
33logger = logging.getLogger(__name__)
34
35
36class banking_export_pain(orm.AbstractModel):
37 _name = 'banking.export.pain'
38
39 def _validate_iban(self, cr, uid, iban, context=None):
40 '''if IBAN is valid, returns IBAN
41 if IBAN is NOT valid, raises an error message'''
42 partner_bank_obj = self.pool.get('res.partner.bank')
43 if partner_bank_obj.is_iban_valid(cr, uid, iban, context=context):
44 return iban.replace(' ', '')
45 else:
46 raise orm.except_orm(
47 _('Error:'), _("This IBAN is not valid : %s") % iban)
48
49 def _prepare_field(
50 self, cr, uid, field_name, field_value, eval_ctx, max_size=0,
51 gen_args=None, context=None):
52 '''This function is designed to be inherited !'''
53 if gen_args is None:
54 gen_args = {}
55 assert isinstance(eval_ctx, dict), 'eval_ctx must contain a dict'
56 try:
57 value = safe_eval(field_value, eval_ctx)
58 # SEPA uses XML ; XML = UTF-8 ; UTF-8 = support for all characters
59 # But we are dealing with banks...
60 # and many banks don't want non-ASCCI characters !
61 # cf section 1.4 "Character set" of the SEPA Credit Transfer
62 # Scheme Customer-to-bank guidelines
63 if gen_args.get('convert_to_ascii'):
64 value = unidecode(value)
65 unallowed_ascii_chars = [
66 '"', '#', '$', '%', '&', '*', ';', '<', '>', '=', '@',
67 '[', ']', '^', '_', '`', '{', '}', '|', '~', '\\', '!']
68 for unallowed_ascii_char in unallowed_ascii_chars:
69 value = value.replace(unallowed_ascii_char, '-')
70 except:
71 line = eval_ctx.get('line')
72 if line:
73 raise orm.except_orm(
74 _('Error:'),
75 _("Cannot compute the '%s' of the Payment Line with "
76 "reference '%s'.")
77 % (field_name, line.name))
78 else:
79 raise orm.except_orm(
80 _('Error:'),
81 _("Cannot compute the '%s'.") % field_name)
82 if not isinstance(value, (str, unicode)):
83 raise orm.except_orm(
84 _('Field type error:'),
85 _("The type of the field '%s' is %s. It should be a string "
86 "or unicode.")
87 % (field_name, type(value)))
88 if not value:
89 raise orm.except_orm(
90 _('Error:'),
91 _("The '%s' is empty or 0. It should have a non-null value.")
92 % field_name)
93 if max_size and len(value) > max_size:
94 value = value[0:max_size]
95 return value
96
97 def _prepare_export_sepa(
98 self, cr, uid, total_amount, transactions_count, xml_string,
99 gen_args, context=None):
100 return {
101 'batch_booking': gen_args['sepa_export'].batch_booking,
102 'charge_bearer': gen_args['sepa_export'].charge_bearer,
103 'total_amount': total_amount,
104 'nb_transactions': transactions_count,
105 'file': base64.encodestring(xml_string),
106 'payment_order_ids': [(
107 6, 0, [x.id for x in gen_args['sepa_export'].payment_order_ids]
108 )],
109 }
110
111 def _validate_xml(self, cr, uid, xml_string, gen_args, context=None):
112 xsd_etree_obj = etree.parse(
113 tools.file_open(gen_args['pain_xsd_file']))
114 official_pain_schema = etree.XMLSchema(xsd_etree_obj)
115
116 try:
117 root_to_validate = etree.fromstring(xml_string)
118 official_pain_schema.assertValid(root_to_validate)
119 except Exception, e:
120 logger.warning(
121 "The XML file is invalid against the XML Schema Definition")
122 logger.warning(xml_string)
123 logger.warning(e)
124 raise orm.except_orm(
125 _('Error:'),
126 _("The generated XML file is not valid against the official "
127 "XML Schema Definition. The generated XML file and the "
128 "full error have been written in the server logs. Here "
129 "is the error, which may give you an idea on the cause "
130 "of the problem : %s")
131 % str(e))
132 return True
133
134 def finalize_sepa_file_creation(
135 self, cr, uid, ids, xml_root, total_amount, transactions_count,
136 gen_args, context=None):
137 xml_string = etree.tostring(
138 xml_root, pretty_print=True, encoding='UTF-8',
139 xml_declaration=True)
140 logger.debug(
141 "Generated SEPA XML file in format %s below"
142 % gen_args['pain_flavor'])
143 logger.debug(xml_string)
144 self._validate_xml(cr, uid, xml_string, gen_args, context=context)
145
146 file_id = gen_args['file_obj'].create(
147 cr, uid, self._prepare_export_sepa(
148 cr, uid, total_amount, transactions_count,
149 xml_string, gen_args, context=context),
150 context=context)
151
152 self.write(
153 cr, uid, ids, {
154 'file_id': file_id,
155 'state': 'finish',
156 }, context=context)
157
158 action = {
159 'name': 'SEPA File',
160 'type': 'ir.actions.act_window',
161 'view_type': 'form',
162 'view_mode': 'form,tree',
163 'res_model': self._name,
164 'res_id': ids[0],
165 'target': 'new',
166 }
167 return action
168
169 def generate_group_header_block(
170 self, cr, uid, parent_node, gen_args, context=None):
171 group_header_1_0 = etree.SubElement(parent_node, 'GrpHdr')
172 message_identification_1_1 = etree.SubElement(
173 group_header_1_0, 'MsgId')
174 message_identification_1_1.text = self._prepare_field(
175 cr, uid, 'Message Identification',
176 'sepa_export.payment_order_ids[0].reference',
177 {'sepa_export': gen_args['sepa_export']}, 35,
178 gen_args=gen_args, context=context)
179 creation_date_time_1_2 = etree.SubElement(group_header_1_0, 'CreDtTm')
180 creation_date_time_1_2.text = datetime.strftime(
181 datetime.today(), '%Y-%m-%dT%H:%M:%S')
182 if gen_args.get('pain_flavor') == 'pain.001.001.02':
183 # batch_booking is in "Group header" with pain.001.001.02
184 # and in "Payment info" in pain.001.001.03/04
185 batch_booking = etree.SubElement(group_header_1_0, 'BtchBookg')
186 batch_booking.text = \
187 str(gen_args['sepa_export'].batch_booking).lower()
188 nb_of_transactions_1_6 = etree.SubElement(
189 group_header_1_0, 'NbOfTxs')
190 control_sum_1_7 = etree.SubElement(group_header_1_0, 'CtrlSum')
191 # Grpg removed in pain.001.001.03
192 if gen_args.get('pain_flavor') == 'pain.001.001.02':
193 grouping = etree.SubElement(group_header_1_0, 'Grpg')
194 grouping.text = 'GRPD'
195 self.generate_initiating_party_block(
196 cr, uid, group_header_1_0, gen_args,
197 context=context)
198 return group_header_1_0, nb_of_transactions_1_6, control_sum_1_7
199
200 def generate_start_payment_info_block(
201 self, cr, uid, parent_node, payment_info_ident,
202 priority, local_instrument, sequence_type, requested_date,
203 eval_ctx, gen_args, context=None):
204 payment_info_2_0 = etree.SubElement(parent_node, 'PmtInf')
205 payment_info_identification_2_1 = etree.SubElement(
206 payment_info_2_0, 'PmtInfId')
207 payment_info_identification_2_1.text = self._prepare_field(
208 cr, uid, 'Payment Information Identification',
209 payment_info_ident, eval_ctx, 35,
210 gen_args=gen_args, context=context)
211 payment_method_2_2 = etree.SubElement(payment_info_2_0, 'PmtMtd')
212 payment_method_2_2.text = gen_args['payment_method']
213 if gen_args.get('pain_flavor') != 'pain.001.001.02':
214 batch_booking_2_3 = etree.SubElement(payment_info_2_0, 'BtchBookg')
215 batch_booking_2_3.text = \
216 str(gen_args['sepa_export'].batch_booking).lower()
217 # The "SEPA Customer-to-bank
218 # Implementation guidelines" for SCT and SDD says that control sum
219 # and nb_of_transactions should be present
220 # at both "group header" level and "payment info" level
221 nb_of_transactions_2_4 = etree.SubElement(
222 payment_info_2_0, 'NbOfTxs')
223 control_sum_2_5 = etree.SubElement(payment_info_2_0, 'CtrlSum')
224 payment_type_info_2_6 = etree.SubElement(
225 payment_info_2_0, 'PmtTpInf')
226 if priority:
227 instruction_priority_2_7 = etree.SubElement(
228 payment_type_info_2_6, 'InstrPrty')
229 instruction_priority_2_7.text = priority
230 service_level_2_8 = etree.SubElement(
231 payment_type_info_2_6, 'SvcLvl')
232 service_level_code_2_9 = etree.SubElement(service_level_2_8, 'Cd')
233 service_level_code_2_9.text = 'SEPA'
234 if local_instrument:
235 local_instrument_2_11 = etree.SubElement(
236 payment_type_info_2_6, 'LclInstrm')
237 local_instr_code_2_12 = etree.SubElement(
238 local_instrument_2_11, 'Cd')
239 local_instr_code_2_12.text = local_instrument
240 if sequence_type:
241 sequence_type_2_14 = etree.SubElement(
242 payment_type_info_2_6, 'SeqTp')
243 sequence_type_2_14.text = sequence_type
244
245 if gen_args['payment_method'] == 'DD':
246 request_date_tag = 'ReqdColltnDt'
247 else:
248 request_date_tag = 'ReqdExctnDt'
249 requested_date_2_17 = etree.SubElement(
250 payment_info_2_0, request_date_tag)
251 requested_date_2_17.text = requested_date
252 return payment_info_2_0, nb_of_transactions_2_4, control_sum_2_5
253
254 def generate_initiating_party_block(
255 self, cr, uid, parent_node, gen_args, context=None):
256 my_company_name = self._prepare_field(
257 cr, uid, 'Company Name',
258 'sepa_export.payment_order_ids[0].mode.bank_id.partner_id.name',
259 {'sepa_export': gen_args['sepa_export']},
260 gen_args.get('name_maxsize'), gen_args=gen_args, context=context)
261 initiating_party_1_8 = etree.SubElement(parent_node, 'InitgPty')
262 initiating_party_name = etree.SubElement(initiating_party_1_8, 'Nm')
263 initiating_party_name.text = my_company_name
264 initiating_party_identifier = self.pool['res.company'].\
265 _get_initiating_party_identifier(
266 cr, uid,
267 gen_args['sepa_export'].payment_order_ids[0].company_id.id,
268 context=context)
269 initiating_party_issuer = gen_args['sepa_export'].\
270 payment_order_ids[0].company_id.initiating_party_issuer
271 if initiating_party_identifier and initiating_party_issuer:
272 iniparty_id = etree.SubElement(initiating_party_1_8, 'Id')
273 iniparty_org_id = etree.SubElement(iniparty_id, 'OrgId')
274 iniparty_org_other = etree.SubElement(iniparty_org_id, 'Othr')
275 iniparty_org_other_id = etree.SubElement(iniparty_org_other, 'Id')
276 iniparty_org_other_id.text = initiating_party_identifier
277 iniparty_org_other_issuer = etree.SubElement(
278 iniparty_org_other, 'Issr')
279 iniparty_org_other_issuer.text = initiating_party_issuer
280 return True
281
282 def generate_party_agent(
283 self, cr, uid, parent_node, party_type, party_type_label,
284 order, party_name, iban, bic, eval_ctx, gen_args, context=None):
285 '''Generate the piece of the XML file corresponding to BIC
286 This code is mutualized between TRF and DD'''
287 assert order in ('B', 'C'), "Order can be 'B' or 'C'"
288 try:
289 bic = self._prepare_field(
290 cr, uid, '%s BIC' % party_type_label, bic, eval_ctx,
291 gen_args=gen_args, context=context)
292 party_agent = etree.SubElement(parent_node, '%sAgt' % party_type)
293 party_agent_institution = etree.SubElement(
294 party_agent, 'FinInstnId')
295 party_agent_bic = etree.SubElement(
296 party_agent_institution, gen_args.get('bic_xml_tag'))
297 party_agent_bic.text = bic
298 except except_orm:
299 if order == 'C':
300 if iban[0:2] != gen_args['initiating_party_country_code']:
301 raise orm.except_orm(
302 _('Error:'),
303 _("The bank account with IBAN '%s' of partner '%s' "
304 "must have an associated BIC because it is a "
305 "cross-border SEPA operation.")
306 % (iban, party_name))
307 if order == 'B' or (
308 order == 'C' and gen_args['payment_method'] == 'DD'):
309 party_agent = etree.SubElement(
310 parent_node, '%sAgt' % party_type)
311 party_agent_institution = etree.SubElement(
312 party_agent, 'FinInstnId')
313 party_agent_other = etree.SubElement(
314 party_agent_institution, 'Othr')
315 party_agent_other_identification = etree.SubElement(
316 party_agent_other, 'Id')
317 party_agent_other_identification.text = 'NOTPROVIDED'
318 # for Credit Transfers, in the 'C' block, if BIC is not provided,
319 # we should not put the 'Creditor Agent' block at all,
320 # as per the guidelines of the EPC
321 return True
322
323 def generate_party_block(
324 self, cr, uid, parent_node, party_type, order, name, iban, bic,
325 eval_ctx, gen_args, context=None):
326 '''Generate the piece of the XML file corresponding to Name+IBAN+BIC
327 This code is mutualized between TRF and DD'''
328 assert order in ('B', 'C'), "Order can be 'B' or 'C'"
329 if party_type == 'Cdtr':
330 party_type_label = 'Creditor'
331 elif party_type == 'Dbtr':
332 party_type_label = 'Debtor'
333 party_name = self._prepare_field(
334 cr, uid, '%s Name' % party_type_label, name, eval_ctx,
335 gen_args.get('name_maxsize'),
336 gen_args=gen_args, context=context)
337 piban = self._prepare_field(
338 cr, uid, '%s IBAN' % party_type_label, iban, eval_ctx,
339 gen_args=gen_args,
340 context=context)
341 viban = self._validate_iban(cr, uid, piban, context=context)
342 # At C level, the order is : BIC, Name, IBAN
343 # At B level, the order is : Name, IBAN, BIC
344 if order == 'B':
345 gen_args['initiating_party_country_code'] = viban[0:2]
346 elif order == 'C':
347 self.generate_party_agent(
348 cr, uid, parent_node, party_type, party_type_label,
349 order, party_name, viban, bic,
350 eval_ctx, gen_args, context=context)
351 party = etree.SubElement(parent_node, party_type)
352 party_nm = etree.SubElement(party, 'Nm')
353 party_nm.text = party_name
354 party_account = etree.SubElement(
355 parent_node, '%sAcct' % party_type)
356 party_account_id = etree.SubElement(party_account, 'Id')
357 party_account_iban = etree.SubElement(
358 party_account_id, 'IBAN')
359 party_account_iban.text = viban
360 if order == 'B':
361 self.generate_party_agent(
362 cr, uid, parent_node, party_type, party_type_label,
363 order, party_name, viban, bic,
364 eval_ctx, gen_args, context=context)
365 return True
366
367 def generate_remittance_info_block(
368 self, cr, uid, parent_node, line, gen_args, context=None):
369
370 remittance_info_2_91 = etree.SubElement(
371 parent_node, 'RmtInf')
372 if line.state == 'normal':
373 remittance_info_unstructured_2_99 = etree.SubElement(
374 remittance_info_2_91, 'Ustrd')
375 remittance_info_unstructured_2_99.text = \
376 self._prepare_field(
377 cr, uid, 'Remittance Unstructured Information',
378 'line.communication', {'line': line}, 140,
379 gen_args=gen_args,
380 context=context)
381 else:
382 if not line.struct_communication_type:
383 raise orm.except_orm(
384 _('Error:'),
385 _("Missing 'Structured Communication Type' on payment "
386 "line with reference '%s'.")
387 % (line.name))
388 remittance_info_structured_2_100 = etree.SubElement(
389 remittance_info_2_91, 'Strd')
390 creditor_ref_information_2_120 = etree.SubElement(
391 remittance_info_structured_2_100, 'CdtrRefInf')
392 if gen_args.get('pain_flavor') == 'pain.001.001.02':
393 creditor_ref_info_type_2_121 = etree.SubElement(
394 creditor_ref_information_2_120, 'CdtrRefTp')
395 creditor_ref_info_type_code_2_123 = etree.SubElement(
396 creditor_ref_info_type_2_121, 'Cd')
397 creditor_ref_info_type_issuer_2_125 = etree.SubElement(
398 creditor_ref_info_type_2_121, 'Issr')
399 creditor_reference_2_126 = etree.SubElement(
400 creditor_ref_information_2_120, 'CdtrRef')
401 else:
402 creditor_ref_info_type_2_121 = etree.SubElement(
403 creditor_ref_information_2_120, 'Tp')
404 creditor_ref_info_type_or_2_122 = etree.SubElement(
405 creditor_ref_info_type_2_121, 'CdOrPrtry')
406 creditor_ref_info_type_code_2_123 = etree.SubElement(
407 creditor_ref_info_type_or_2_122, 'Cd')
408 creditor_ref_info_type_issuer_2_125 = etree.SubElement(
409 creditor_ref_info_type_2_121, 'Issr')
410 creditor_reference_2_126 = etree.SubElement(
411 creditor_ref_information_2_120, 'Ref')
412
413 creditor_ref_info_type_code_2_123.text = 'SCOR'
414 creditor_ref_info_type_issuer_2_125.text = \
415 line.struct_communication_type
416 creditor_reference_2_126.text = \
417 self._prepare_field(
418 cr, uid, 'Creditor Structured Reference',
419 'line.communication', {'line': line}, 35,
420 gen_args=gen_args,
421 context=context)
422 return True
423
424 def generate_creditor_scheme_identification(
425 self, cr, uid, parent_node, identification, identification_label,
426 eval_ctx, scheme_name_proprietary, gen_args, context=None):
427 csi_id = etree.SubElement(
428 parent_node, 'Id')
429 csi_privateid = csi_id = etree.SubElement(csi_id, 'PrvtId')
430 csi_other = etree.SubElement(csi_privateid, 'Othr')
431 csi_other_id = etree.SubElement(csi_other, 'Id')
432 csi_other_id.text = self._prepare_field(
433 cr, uid, identification_label, identification, eval_ctx,
434 gen_args=gen_args, context=context)
435 csi_scheme_name = etree.SubElement(csi_other, 'SchmeNm')
436 csi_scheme_name_proprietary = etree.SubElement(
437 csi_scheme_name, 'Prtry')
438 csi_scheme_name_proprietary.text = scheme_name_proprietary
439 return True
0440
=== added file 'account_banking_pain_base/company.py'
--- account_banking_pain_base/company.py 1970-01-01 00:00:00 +0000
+++ account_banking_pain_base/company.py 2014-01-13 12:42:46 +0000
@@ -0,0 +1,78 @@
1# -*- encoding: utf-8 -*-
2##############################################################################
3#
4# PAIN Base module for OpenERP
5# Copyright (C) 2013 Akretion (http://www.akretion.com)
6# Copyright (C) 2013 Noviat (http://www.noviat.com)
7# @author: Alexis de Lattre <alexis.delattre@akretion.com>
8# @author: Luc de Meyer (Noviat)
9#
10# This program is free software: you can redistribute it and/or modify
11# it under the terms of the GNU Affero General Public License as
12# published by the Free Software Foundation, either version 3 of the
13# License, or (at your option) any later version.
14#
15# This program is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18# GNU Affero General Public License for more details.
19#
20# You should have received a copy of the GNU Affero General Public License
21# along with this program. If not, see <http://www.gnu.org/licenses/>.
22#
23##############################################################################
24
25from openerp.osv import orm, fields
26
27
28class res_company(orm.Model):
29 _inherit = 'res.company'
30
31 _columns = {
32 'initiating_party_issuer': fields.char(
33 'Initiating Party Issuer', size=35,
34 help="This will be used as the 'Initiating Party Issuer' in the "
35 "PAIN files generated by OpenERP."),
36 }
37
38 def _get_initiating_party_identifier(
39 self, cr, uid, company_id, context=None):
40 '''The code here may be different from one country to another.
41 If you need to add support for an additionnal country, you can
42 contribute your code here or inherit this function in the
43 localization modules for your country'''
44 assert isinstance(company_id, int), 'Only one company ID'
45 company = self.browse(cr, uid, company_id, context=context)
46 company_vat = company.vat
47 party_identifier = False
48 if company_vat and company_vat[0:2].upper() in ['BE']:
49 party_identifier = company_vat[2:].replace(' ', '')
50 return party_identifier
51
52 def _initiating_party_issuer_default(self, cr, uid, context=None):
53 '''If you need to add support for an additionnal country, you can
54 add an entry in the dict "party_issuer_per_country" here
55 or inherit this function in the localization modules for
56 your country'''
57 initiating_party_issuer = ''
58 # If your country require the 'Initiating Party Issuer', you should
59 # contribute the entry for your country in the dict below
60 party_issuer_per_country = {
61 'BE': 'KBO-BCE', # KBO-BCE = the registry of companies in Belgium
62 }
63 company_id = self._company_default_get(
64 cr, uid, 'res.company', context=context)
65 if company_id:
66 company = self.browse(cr, uid, company_id, context=context)
67 country_code = company.country_id.code
68 initiating_party_issuer = party_issuer_per_country.get(
69 country_code, '')
70 return initiating_party_issuer
71
72 def _initiating_party_issuer_def(self, cr, uid, context=None):
73 return self._initiating_party_issuer_default(
74 cr, uid, context=context)
75
76 _defaults = {
77 'initiating_party_issuer': _initiating_party_issuer_def,
78 }
079
=== added file 'account_banking_pain_base/company_view.xml'
--- account_banking_pain_base/company_view.xml 1970-01-01 00:00:00 +0000
+++ account_banking_pain_base/company_view.xml 2014-01-13 12:42:46 +0000
@@ -0,0 +1,24 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!--
3 Copyright (C) 2013 Akretion (http://www.akretion.com)
4 @author: Alexis de Lattre <alexis.delattre@akretion.com>
5 The licence is in the file __openerp__.py
6-->
7<openerp>
8<data>
9
10<record id="view_company_form" model="ir.ui.view">
11 <field name="name">pain.group.on.res.company.form</field>
12 <field name="model">res.company</field>
13 <field name="inherit_id" ref="base.view_company_form"/>
14 <field name="arch" type="xml">
15 <group name="account_grp" position="after">
16 <group name="pain" string="Payment Initiation">
17 <field name="initiating_party_issuer"/>
18 </group>
19 </group>
20 </field>
21</record>
22
23</data>
24</openerp>
025
=== added directory 'account_banking_pain_base/i18n'
=== added file 'account_banking_pain_base/i18n/account_banking_pain_base.pot'
--- account_banking_pain_base/i18n/account_banking_pain_base.pot 1970-01-01 00:00:00 +0000
+++ account_banking_pain_base/i18n/account_banking_pain_base.pot 2014-01-13 12:42:46 +0000
@@ -0,0 +1,146 @@
1# Translation of OpenERP Server.
2# This file contains the translation of the following modules:
3# * account_banking_pain_base
4#
5msgid ""
6msgstr ""
7"Project-Id-Version: OpenERP Server 7.0\n"
8"Report-Msgid-Bugs-To: \n"
9"POT-Creation-Date: 2013-12-23 21:26+0000\n"
10"PO-Revision-Date: 2013-12-23 21:26+0000\n"
11"Last-Translator: <>\n"
12"Language-Team: \n"
13"MIME-Version: 1.0\n"
14"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Transfer-Encoding: \n"
16"Plural-Forms: \n"
17
18#. module: account_banking_pain_base
19#: field:res.company,initiating_party_issuer:0
20msgid "Initiating Party Issuer"
21msgstr ""
22
23#. module: account_banking_pain_base
24#: code:addons/account_banking_pain_base/banking_export_pain.py:122
25#, python-format
26msgid "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"
27msgstr ""
28
29#. module: account_banking_pain_base
30#: field:payment.line,priority:0
31msgid "Priority"
32msgstr ""
33
34#. module: account_banking_pain_base
35#: model:ir.model,name:account_banking_pain_base.model_payment_line
36msgid "Payment Line"
37msgstr ""
38
39#. module: account_banking_pain_base
40#: model:ir.model,name:account_banking_pain_base.model_payment_mode
41msgid "Payment Mode"
42msgstr ""
43
44#. module: account_banking_pain_base
45#: help:res.company,initiating_party_issuer:0
46msgid "This will be used as the 'Initiating Party Issuer' in the PAIN files generated by OpenERP."
47msgstr ""
48
49#. module: account_banking_pain_base
50#: code:addons/account_banking_pain_base/banking_export_pain.py:351
51#, python-format
52msgid "Missing 'Structured Communication Type' on payment line with reference '%s'."
53msgstr ""
54
55#. module: account_banking_pain_base
56#: selection:payment.line,priority:0
57msgid "Normal"
58msgstr ""
59
60#. module: account_banking_pain_base
61#: code:addons/account_banking_pain_base/banking_export_pain.py:70
62#, python-format
63msgid "Cannot compute the '%s' of the Payment Line with reference '%s'."
64msgstr ""
65
66#. module: account_banking_pain_base
67#: code:addons/account_banking_pain_base/banking_export_pain.py:77
68#, python-format
69msgid "Cannot compute the '%s'."
70msgstr ""
71
72#. module: account_banking_pain_base
73#: code:addons/account_banking_pain_base/banking_export_pain.py:81
74#, python-format
75msgid "The type of the field '%s' is %s. It should be a string or unicode."
76msgstr ""
77
78#. module: account_banking_pain_base
79#: code:addons/account_banking_pain_base/banking_export_pain.py:47
80#: code:addons/account_banking_pain_base/banking_export_pain.py:69
81#: code:addons/account_banking_pain_base/banking_export_pain.py:76
82#: code:addons/account_banking_pain_base/banking_export_pain.py:86
83#: code:addons/account_banking_pain_base/banking_export_pain.py:121
84#: code:addons/account_banking_pain_base/banking_export_pain.py:350
85#, python-format
86msgid "Error:"
87msgstr ""
88
89#. module: account_banking_pain_base
90#: model:ir.model,name:account_banking_pain_base.model_res_company
91msgid "Companies"
92msgstr ""
93
94#. module: account_banking_pain_base
95#: code:addons/account_banking_pain_base/banking_export_pain.py:47
96#, python-format
97msgid "This IBAN is not valid : %s"
98msgstr ""
99
100#. module: account_banking_pain_base
101#: code:addons/account_banking_pain_base/banking_export_pain.py:80
102#, python-format
103msgid "Field type error:"
104msgstr ""
105
106#. module: account_banking_pain_base
107#: field:payment.line,struct_communication_type:0
108msgid "Structured Communication Type"
109msgstr ""
110
111#. module: account_banking_pain_base
112#: code:addons/account_banking_pain_base/banking_export_pain.py:87
113#, python-format
114msgid "The '%s' is empty or 0. It should have a non-null value."
115msgstr ""
116
117#. module: account_banking_pain_base
118#: model:ir.model,name:account_banking_pain_base.model_banking_export_pain
119msgid "banking.export.pain"
120msgstr ""
121
122#. module: account_banking_pain_base
123#: help:payment.mode,convert_to_ascii:0
124msgid "If active, OpenERP will convert each accented caracter to the corresponding unaccented caracter, so that only ASCII caracters are used in the generated PAIN file."
125msgstr ""
126
127#. module: account_banking_pain_base
128#: help:payment.line,priority:0
129msgid "This field will be used as the 'Instruction Priority' in the generated PAIN file."
130msgstr ""
131
132#. module: account_banking_pain_base
133#: view:res.company:0
134msgid "Payment Initiation"
135msgstr ""
136
137#. module: account_banking_pain_base
138#: selection:payment.line,priority:0
139msgid "High"
140msgstr ""
141
142#. module: account_banking_pain_base
143#: field:payment.mode,convert_to_ascii:0
144msgid "Convert to ASCII"
145msgstr ""
146
0147
=== added file 'account_banking_pain_base/i18n/fr.po'
--- account_banking_pain_base/i18n/fr.po 1970-01-01 00:00:00 +0000
+++ account_banking_pain_base/i18n/fr.po 2014-01-13 12:42:46 +0000
@@ -0,0 +1,146 @@
1# Translation of OpenERP Server.
2# This file contains the translation of the following modules:
3# * account_banking_pain_base
4#
5msgid ""
6msgstr ""
7"Project-Id-Version: OpenERP Server 7.0\n"
8"Report-Msgid-Bugs-To: \n"
9"POT-Creation-Date: 2013-12-23 21:27+0000\n"
10"PO-Revision-Date: 2013-12-23 21:27+0000\n"
11"Last-Translator: <>\n"
12"Language-Team: \n"
13"MIME-Version: 1.0\n"
14"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Transfer-Encoding: \n"
16"Plural-Forms: \n"
17
18#. module: account_banking_pain_base
19#: field:res.company,initiating_party_issuer:0
20msgid "Initiating Party Issuer"
21msgstr "Initiating Party Issuer"
22
23#. module: account_banking_pain_base
24#: code:addons/account_banking_pain_base/banking_export_pain.py:122
25#, python-format
26msgid "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"
27msgstr "Le fichier XML généré n'est pas valide par rapport à la Définition du Schéma XML officiel. Le fichier XML généré et le message d'erreur complet ont été écrits dans les logs du serveur. Voici l'erreur, qui vous donnera peut-être une idée sur la cause du problème : %s"
28
29#. module: account_banking_pain_base
30#: field:payment.line,priority:0
31msgid "Priority"
32msgstr "Priorité"
33
34#. module: account_banking_pain_base
35#: model:ir.model,name:account_banking_pain_base.model_payment_line
36msgid "Payment Line"
37msgstr "Ligne de paiement"
38
39#. module: account_banking_pain_base
40#: model:ir.model,name:account_banking_pain_base.model_payment_mode
41msgid "Payment Mode"
42msgstr "Mode de paiement"
43
44#. module: account_banking_pain_base
45#: help:res.company,initiating_party_issuer:0
46msgid "This will be used as the 'Initiating Party Issuer' in the PAIN files generated by OpenERP."
47msgstr "Ce champ sera le 'Initiating Party Issuer' dans les fichiers PAIN générés par OpenERP."
48
49#. module: account_banking_pain_base
50#: code:addons/account_banking_pain_base/banking_export_pain.py:351
51#, python-format
52msgid "Missing 'Structured Communication Type' on payment line with reference '%s'."
53msgstr "Le 'Type de communication structuré' n'est pas renseigné sur la ligne de paiement ayant la référence '%s'."
54
55#. module: account_banking_pain_base
56#: selection:payment.line,priority:0
57msgid "Normal"
58msgstr "Normal"
59
60#. module: account_banking_pain_base
61#: code:addons/account_banking_pain_base/banking_export_pain.py:70
62#, python-format
63msgid "Cannot compute the '%s' of the Payment Line with reference '%s'."
64msgstr "Impossible de calculer le '%s' de la ligne de paiement ayant la référence '%s'."
65
66#. module: account_banking_pain_base
67#: code:addons/account_banking_pain_base/banking_export_pain.py:77
68#, python-format
69msgid "Cannot compute the '%s'."
70msgstr "Impossible de calculer le '%s'."
71
72#. module: account_banking_pain_base
73#: code:addons/account_banking_pain_base/banking_export_pain.py:81
74#, python-format
75msgid "The type of the field '%s' is %s. It should be a string or unicode."
76msgstr "Le type du champ '%s' est %s. Il devrait être de type string ou unicode."
77
78#. module: account_banking_pain_base
79#: code:addons/account_banking_pain_base/banking_export_pain.py:47
80#: code:addons/account_banking_pain_base/banking_export_pain.py:69
81#: code:addons/account_banking_pain_base/banking_export_pain.py:76
82#: code:addons/account_banking_pain_base/banking_export_pain.py:86
83#: code:addons/account_banking_pain_base/banking_export_pain.py:121
84#: code:addons/account_banking_pain_base/banking_export_pain.py:350
85#, python-format
86msgid "Error:"
87msgstr "Erreur :"
88
89#. module: account_banking_pain_base
90#: model:ir.model,name:account_banking_pain_base.model_res_company
91msgid "Companies"
92msgstr "Sociétés"
93
94#. module: account_banking_pain_base
95#: code:addons/account_banking_pain_base/banking_export_pain.py:47
96#, python-format
97msgid "This IBAN is not valid : %s"
98msgstr "Cet IBAN n'est pas valide : %s"
99
100#. module: account_banking_pain_base
101#: code:addons/account_banking_pain_base/banking_export_pain.py:80
102#, python-format
103msgid "Field type error:"
104msgstr "Erreur dans le type de champ :"
105
106#. module: account_banking_pain_base
107#: field:payment.line,struct_communication_type:0
108msgid "Structured Communication Type"
109msgstr "Type de communication structurée"
110
111#. module: account_banking_pain_base
112#: code:addons/account_banking_pain_base/banking_export_pain.py:87
113#, python-format
114msgid "The '%s' is empty or 0. It should have a non-null value."
115msgstr "Le '%s' est vide ou égal à 0. Il devrait avoir une valeur non-nulle."
116
117#. module: account_banking_pain_base
118#: model:ir.model,name:account_banking_pain_base.model_banking_export_pain
119msgid "banking.export.pain"
120msgstr "banking.export.pain"
121
122#. module: account_banking_pain_base
123#: help:payment.mode,convert_to_ascii:0
124msgid "If active, OpenERP will convert each accented caracter to the corresponding unaccented caracter, so that only ASCII caracters are used in the generated PAIN file."
125msgstr "Si actif, OpenERP convertira chaque caractère accentué en son équivalent non accentué, de telle façon que seuls des caractères ASCII soient utilisés dans le fichier PAIN généré."
126
127#. module: account_banking_pain_base
128#: help:payment.line,priority:0
129msgid "This field will be used as the 'Instruction Priority' in the generated PAIN file."
130msgstr "Ce champ sera le 'Instruction Priority' dans le fichier PAIN généré."
131
132#. module: account_banking_pain_base
133#: view:res.company:0
134msgid "Payment Initiation"
135msgstr "Payment Initiation"
136
137#. module: account_banking_pain_base
138#: selection:payment.line,priority:0
139msgid "High"
140msgstr "Élevé"
141
142#. module: account_banking_pain_base
143#: field:payment.mode,convert_to_ascii:0
144msgid "Convert to ASCII"
145msgstr "Convertir en ASCII"
146
0147
=== added file 'account_banking_pain_base/payment_line.py'
--- account_banking_pain_base/payment_line.py 1970-01-01 00:00:00 +0000
+++ account_banking_pain_base/payment_line.py 2014-01-13 12:42:46 +0000
@@ -0,0 +1,52 @@
1# -*- encoding: utf-8 -*-
2##############################################################################
3#
4# PAIN Base module for OpenERP
5# Copyright (C) 2013 Akretion (http://www.akretion.com)
6# @author: Alexis de Lattre <alexis.delattre@akretion.com>
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Affero General Public License as
10# published by the Free Software Foundation, either version 3 of the
11# License, or (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.
17#
18# You should have received a copy of the GNU Affero General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20#
21##############################################################################
22
23from openerp.osv import orm, fields
24
25
26class payment_line(orm.Model):
27 _inherit = 'payment.line'
28
29 def _get_struct_communication_types(self, cr, uid, context=None):
30 return [('ISO', 'ISO')]
31
32 _columns = {
33 'priority': fields.selection([
34 ('NORM', 'Normal'),
35 ('HIGH', 'High'),
36 ], 'Priority',
37 help="This field will be used as the 'Instruction Priority' in "
38 "the generated PAIN file."),
39 # Update size from 64 to 140, because PAIN allows 140 caracters
40 'communication': fields.char(
41 'Communication', size=140, required=True,
42 help="Used as the message between ordering customer and current "
43 "company. Depicts 'What do you want to say to the recipient "
44 "about this order ?'"),
45 'struct_communication_type': fields.selection(
46 _get_struct_communication_types, 'Structured Communication Type'),
47 }
48
49 _defaults = {
50 'priority': 'NORM',
51 'struct_communication_type': 'ISO',
52 }
053
=== added file 'account_banking_pain_base/payment_line_view.xml'
--- account_banking_pain_base/payment_line_view.xml 1970-01-01 00:00:00 +0000
+++ account_banking_pain_base/payment_line_view.xml 2014-01-13 12:42:46 +0000
@@ -0,0 +1,41 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!--
3 Copyright (C) 2013 Akretion (http://www.akretion.com)
4 @author: Alexis de Lattre <alexis.delattre@akretion.com>
5 The licence is in the file __openerp__.py
6-->
7<openerp>
8<data>
9
10<record id="view_payment_line_form" model="ir.ui.view">
11 <field name="name">pain.base.payment.line.form</field>
12 <field name="model">payment.line</field>
13 <field name="inherit_id" ref="account_payment.view_payment_line_form"/>
14 <field name="arch" type="xml">
15 <field name="bank_id" position="after">
16 <field name="priority"/>
17 <newline />
18 </field>
19 <field name="state" position="after">
20 <field name="struct_communication_type" attrs="{'invisible': [('state', '!=', 'structured')], 'required': [('state', '=', 'structured')]}"/>
21 </field>
22 </field>
23</record>
24
25<record id="view_payment_order_form" model="ir.ui.view">
26 <field name="name">pain.base.payment.line.inside.order.form</field>
27 <field name="model">payment.order</field>
28 <field name="inherit_id" ref="account_payment.view_payment_order_form"/>
29 <field name="arch" type="xml">
30 <xpath expr="//field[@name='line_ids']/form//field[@name='bank_id']" position="after">
31 <field name="priority"/>
32 <newline />
33 </xpath>
34 <xpath expr="//field[@name='line_ids']/form//field[@name='state']" position="after">
35 <field name="struct_communication_type" attrs="{'invisible': [('state', '!=', 'structured')], 'required': [('state', '=', 'structured')]}"/>
36 </xpath>
37 </field>
38</record>
39
40</data>
41</openerp>
042
=== added file 'account_banking_pain_base/payment_mode.py'
--- account_banking_pain_base/payment_mode.py 1970-01-01 00:00:00 +0000
+++ account_banking_pain_base/payment_mode.py 2014-01-13 12:42:46 +0000
@@ -0,0 +1,39 @@
1# -*- encoding: utf-8 -*-
2##############################################################################
3#
4# PAIN Base module for OpenERP
5# Copyright (C) 2013 Akretion (http://www.akretion.com)
6# @author: Alexis de Lattre <alexis.delattre@akretion.com>
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Affero General Public License as
10# published by the Free Software Foundation, either version 3 of the
11# License, or (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.
17#
18# You should have received a copy of the GNU Affero General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20#
21##############################################################################
22
23from openerp.osv import orm, fields
24
25
26class payment_mode(orm.Model):
27 _inherit = 'payment.mode'
28
29 _columns = {
30 'convert_to_ascii': fields.boolean(
31 'Convert to ASCII',
32 help="If active, OpenERP will convert each accented caracter to "
33 "the corresponding unaccented caracter, so that only ASCII "
34 "caracters are used in the generated PAIN file."),
35 }
36
37 _defaults = {
38 'convert_to_ascii': True,
39 }
040
=== added file 'account_banking_pain_base/payment_mode_view.xml'
--- account_banking_pain_base/payment_mode_view.xml 1970-01-01 00:00:00 +0000
+++ account_banking_pain_base/payment_mode_view.xml 2014-01-13 12:42:46 +0000
@@ -0,0 +1,22 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!--
3 Copyright (C) 2013 Akretion (http://www.akretion.com)
4 @author: Alexis de Lattre <alexis.delattre@akretion.com>
5 The licence is in the file __openerp__.py
6-->
7<openerp>
8<data>
9
10<record id="view_payment_mode_form_inherit" model="ir.ui.view">
11 <field name="name">add.convert_to_ascii.in.payment.mode.form</field>
12 <field name="model">payment.mode</field>
13 <field name="inherit_id" ref="account_banking_payment_export.view_payment_mode_form_inherit"/>
14 <field name="arch" type="xml">
15 <field name="type" position="after">
16 <field name="convert_to_ascii"/>
17 </field>
18 </field>
19</record>
20
21</data>
22</openerp>
023
=== modified file 'account_banking_payment/__openerp__.py'
--- account_banking_payment/__openerp__.py 2013-08-13 09:18:15 +0000
+++ account_banking_payment/__openerp__.py 2014-01-13 12:42:46 +0000
@@ -39,6 +39,7 @@
39 'view/banking_transaction_wizard.xml',39 'view/banking_transaction_wizard.xml',
40 'view/payment_mode.xml',40 'view/payment_mode.xml',
41 'view/payment_mode_type.xml',41 'view/payment_mode_type.xml',
42 'view/payment_order_create_view.xml',
42 'workflow/account_payment.xml',43 'workflow/account_payment.xml',
43 ],44 ],
44 'description': '''45 'description': '''
4546
=== modified file 'account_banking_payment/model/__init__.py'
--- account_banking_payment/model/__init__.py 2013-08-13 09:18:15 +0000
+++ account_banking_payment/model/__init__.py 2014-01-13 12:42:46 +0000
@@ -1,7 +1,7 @@
1import account_payment1import account_payment
2import payment_line2import payment_line
3import payment_mode_type
3import payment_mode4import payment_mode
4import payment_mode_type
5import payment_order_create5import payment_order_create
6import banking_import_transaction6import banking_import_transaction
7import banking_transaction_wizard7import banking_transaction_wizard
88
=== modified file 'account_banking_payment/model/account_payment.py'
--- account_banking_payment/model/account_payment.py 2013-10-14 11:18:42 +0000
+++ account_banking_payment/model/account_payment.py 2014-01-13 12:42:46 +0000
@@ -107,6 +107,7 @@
107 'payment_order_type': fields.selection(107 'payment_order_type': fields.selection(
108 [('payment', 'Payment'),('debit', 'Direct debit')],108 [('payment', 'Payment'),('debit', 'Direct debit')],
109 'Payment order type', required=True,109 'Payment order type', required=True,
110 readonly=True, states={'draft': [('readonly', False)]},
110 ),111 ),
111 'date_sent': fields.date('Send date', readonly=True),112 'date_sent': fields.date('Send date', readonly=True),
112 }113 }
113114
=== modified file 'account_banking_payment/model/payment_mode.py'
--- account_banking_payment/model/payment_mode.py 2013-08-13 09:18:15 +0000
+++ account_banking_payment/model/payment_mode.py 2014-01-13 12:42:46 +0000
@@ -34,10 +34,9 @@
34 'account.account', 'Transfer account',34 'account.account', 'Transfer account',
35 domain=[('type', '=', 'other'),35 domain=[('type', '=', 'other'),
36 ('reconcile', '=', True)],36 ('reconcile', '=', True)],
37 help=('Pay off lines in sent orders with a '37 help=('Pay off lines in sent orders with a move on this '
38 'move on this account. For debit type modes only. '38 'account. You can only select accounts of type regular '
39 'You can only select accounts of type regular that '39 'that are marked for reconciliation'),
40 'are marked for reconciliation'),
41 ),40 ),
42 'transfer_journal_id': fields.many2one(41 'transfer_journal_id': fields.many2one(
43 'account.journal', 'Transfer journal',42 'account.journal', 'Transfer journal',
@@ -50,4 +49,8 @@
50 help=('Limit selected invoices to invoices with these payment '49 help=('Limit selected invoices to invoices with these payment '
51 'terms')50 'terms')
52 ),51 ),
52 'payment_order_type': fields.related(
53 'type', 'payment_order_type', readonly=True, type='selection',
54 selection=[('payment', 'Payment'), ('debit', 'Direct debit')],
55 string="Payment Order Type"),
53 }56 }
5457
=== modified file 'account_banking_payment/view/payment_mode.xml'
--- account_banking_payment/view/payment_mode.xml 2013-08-13 09:18:15 +0000
+++ account_banking_payment/view/payment_mode.xml 2014-01-13 12:42:46 +0000
@@ -11,6 +11,7 @@
11 <field name="inherit_id" ref="account_banking_payment_export.view_payment_mode_form_inherit"/>11 <field name="inherit_id" ref="account_banking_payment_export.view_payment_mode_form_inherit"/>
12 <field name="arch" type="xml">12 <field name="arch" type="xml">
13 <field name="type" position="after">13 <field name="type" position="after">
14 <field name="payment_order_type"/>
14 <group colspan="4" col="4">15 <group colspan="4" col="4">
15 <group colspan="2">16 <group colspan="2">
16 <separator colspan="2"17 <separator colspan="2"
1718
=== added file 'account_banking_payment/view/payment_order_create_view.xml'
--- account_banking_payment/view/payment_order_create_view.xml 1970-01-01 00:00:00 +0000
+++ account_banking_payment/view/payment_order_create_view.xml 2014-01-13 12:42:46 +0000
@@ -0,0 +1,23 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!--
3 Copyright (C) 2013 Akretion (http://www.akretion.com)
4 @author: Alexis de Lattre <alexis.delattre@akretion.com>
5 The licence is in the file __openerp__.py
6-->
7<openerp>
8<data>
9
10<record id="view_create_payment_order_lines" model="ir.ui.view">
11 <field name="name">add.context.to.display.maturity.date</field>
12 <field name="model">payment.order.create</field>
13 <field name="inherit_id" ref="account_payment.view_create_payment_order_lines"/>
14 <field name="arch" type="xml">
15 <field name="entries" position="attributes">
16 <attribute name="context">{'journal_type': 'sale'}</attribute>
17 <attribute name="nolabel">1</attribute>
18 </field>
19 </field>
20</record>
21
22</data>
23</openerp>
024
=== modified file 'account_banking_sepa_credit_transfer/__openerp__.py'
--- account_banking_sepa_credit_transfer/__openerp__.py 2013-11-13 08:19:50 +0000
+++ account_banking_sepa_credit_transfer/__openerp__.py 2014-01-13 12:42:46 +0000
@@ -26,7 +26,7 @@
26 'author': 'Akretion',26 'author': 'Akretion',
27 'website': 'http://www.akretion.com',27 'website': 'http://www.akretion.com',
28 'category': 'Banking addons',28 'category': 'Banking addons',
29 'depends': ['account_banking_payment_export'],29 'depends': ['account_banking_pain_base'],
30 'external_dependencies': {30 'external_dependencies': {
31 'python': ['unidecode', 'lxml'],31 'python': ['unidecode', 'lxml'],
32 },32 },
3333
=== modified file 'account_banking_sepa_credit_transfer/account_banking_sepa.py'
--- account_banking_sepa_credit_transfer/account_banking_sepa.py 2013-11-12 21:38:21 +0000
+++ account_banking_sepa_credit_transfer/account_banking_sepa.py 2014-01-13 12:42:46 +0000
@@ -48,22 +48,31 @@
48 'banking_export_sepa_id', 'account_order_id',48 'banking_export_sepa_id', 'account_order_id',
49 'Payment Orders',49 'Payment Orders',
50 readonly=True),50 readonly=True),
51 'prefered_exec_date': fields.date(
52 'Prefered Execution Date', readonly=True),
53 'nb_transactions': fields.integer(51 'nb_transactions': fields.integer(
54 'Number of Transactions', readonly=True),52 'Number of Transactions', readonly=True),
55 'total_amount': fields.float('Total Amount',53 'total_amount': fields.float(
56 digits_compute=dp.get_precision('Account'), readonly=True),54 'Total Amount', digits_compute=dp.get_precision('Account'),
55 readonly=True),
57 'batch_booking': fields.boolean(56 'batch_booking': fields.boolean(
58 'Batch Booking', readonly=True,57 'Batch Booking', readonly=True,
59 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."),58 help="If true, the bank statement will display only one debit "
59 "line for all the wire transfers of the SEPA XML file ; "
60 "if false, the bank statement will display one debit line "
61 "per wire transfer of the SEPA XML file."),
60 'charge_bearer': fields.selection([62 'charge_bearer': fields.selection([
61 ('SLEV', 'Following Service Level'),63 ('SLEV', 'Following Service Level'),
62 ('SHAR', 'Shared'),64 ('SHAR', 'Shared'),
63 ('CRED', 'Borne by Creditor'),65 ('CRED', 'Borne by Creditor'),
64 ('DEBT', 'Borne by Debtor'),66 ('DEBT', 'Borne by Debtor'),
65 ], 'Charge Bearer', readonly=True,67 ], 'Charge Bearer', readonly=True,
66 help='Following service level : transaction charges are to be applied following the rules agreed in the service level and/or scheme (SEPA Core messages must use this). Shared : transaction charges on the creditor side are to be borne by the creditor, transaction charges on the debtor side are to be borne by the debtor. 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.'),68 help="Following service level : transaction charges are to be "
69 "applied following the rules agreed in the service level and/or "
70 "scheme (SEPA Core messages must use this). Shared : "
71 "transaction charges on the creditor side are to be borne by "
72 "the creditor, transaction charges on the debtor side are to "
73 "be borne by the debtor. Borne by creditor : all transaction "
74 "charges are to be borne by the creditor. Borne by debtor : "
75 "all transaction charges are to be borne by the debtor."),
67 'create_date': fields.datetime('Generation Date', readonly=True),76 'create_date': fields.datetime('Generation Date', readonly=True),
68 'file': fields.binary('SEPA XML File', readonly=True),77 'file': fields.binary('SEPA XML File', readonly=True),
69 'filename': fields.function(78 'filename': fields.function(
7079
=== modified file 'account_banking_sepa_credit_transfer/account_banking_sepa_view.xml'
--- account_banking_sepa_credit_transfer/account_banking_sepa_view.xml 2013-11-07 11:50:36 +0000
+++ account_banking_sepa_credit_transfer/account_banking_sepa_view.xml 2014-01-13 12:42:46 +0000
@@ -16,7 +16,6 @@
16 <page string="General Information">16 <page string="General Information">
17 <field name="total_amount" />17 <field name="total_amount" />
18 <field name="nb_transactions" />18 <field name="nb_transactions" />
19 <field name="prefered_exec_date" />
20 <field name="batch_booking" />19 <field name="batch_booking" />
21 <field name="charge_bearer"/>20 <field name="charge_bearer"/>
22 <field name="create_date" />21 <field name="create_date" />
@@ -47,7 +46,6 @@
47 <field name="arch" type="xml">46 <field name="arch" type="xml">
48 <tree string="SEPA Credit Transfer">47 <tree string="SEPA Credit Transfer">
49 <field name="filename"/>48 <field name="filename"/>
50 <field name="prefered_exec_date"/>
51 <field name="create_date"/>49 <field name="create_date"/>
52 <field name="nb_transactions"/>50 <field name="nb_transactions"/>
53 </tree>51 </tree>
5452
=== modified file 'account_banking_sepa_credit_transfer/i18n/account_banking_sepa_credit_transfer.pot'
--- account_banking_sepa_credit_transfer/i18n/account_banking_sepa_credit_transfer.pot 2013-11-13 09:17:33 +0000
+++ account_banking_sepa_credit_transfer/i18n/account_banking_sepa_credit_transfer.pot 2014-01-13 12:42:46 +0000
@@ -6,8 +6,8 @@
6msgstr ""6msgstr ""
7"Project-Id-Version: OpenERP Server 7.0\n"7"Project-Id-Version: OpenERP Server 7.0\n"
8"Report-Msgid-Bugs-To: \n"8"Report-Msgid-Bugs-To: \n"
9"POT-Creation-Date: 2013-11-13 09:13+0000\n"9"POT-Creation-Date: 2013-12-23 22:49+0000\n"
10"PO-Revision-Date: 2013-11-13 09:13+0000\n"10"PO-Revision-Date: 2013-12-23 22:49+0000\n"
11"Last-Translator: <>\n"11"Last-Translator: <>\n"
12"Language-Team: \n"12"Language-Team: \n"
13"MIME-Version: 1.0\n"13"MIME-Version: 1.0\n"
@@ -16,12 +16,6 @@
16"Plural-Forms: \n"16"Plural-Forms: \n"
1717
18#. module: account_banking_sepa_credit_transfer18#. module: account_banking_sepa_credit_transfer
19#: field:banking.export.sepa,prefered_exec_date:0
20#: field:banking.export.sepa.wizard,prefered_exec_date:0
21msgid "Prefered Execution Date"
22msgstr ""
23
24#. module: account_banking_sepa_credit_transfer
25#: selection:banking.export.sepa.wizard,state:019#: selection:banking.export.sepa.wizard,state:0
26msgid "Create"20msgid "Create"
27msgstr ""21msgstr ""
@@ -55,12 +49,6 @@
55msgstr ""49msgstr ""
5650
57#. module: account_banking_sepa_credit_transfer51#. module: account_banking_sepa_credit_transfer
58#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:117
59#, python-format
60msgid "Cannot compute the '%s' of the Payment Line with Invoice Reference '%s'."
61msgstr ""
62
63#. module: account_banking_sepa_credit_transfer
64#: selection:banking.export.sepa,charge_bearer:052#: selection:banking.export.sepa,charge_bearer:0
65#: selection:banking.export.sepa.wizard,charge_bearer:053#: selection:banking.export.sepa.wizard,charge_bearer:0
66msgid "Shared"54msgid "Shared"
@@ -73,8 +61,13 @@
73msgstr ""61msgstr ""
7462
75#. module: account_banking_sepa_credit_transfer63#. module: account_banking_sepa_credit_transfer
64#: selection:banking.export.sepa,state:0
65msgid "Sent"
66msgstr ""
67
68#. module: account_banking_sepa_credit_transfer
76#: model:ir.model,name:account_banking_sepa_credit_transfer.model_banking_export_sepa_wizard69#: model:ir.model,name:account_banking_sepa_credit_transfer.model_banking_export_sepa_wizard
77msgid "Export SEPA Credit Transfer XML file"70msgid "Export SEPA Credit Transfer File"
78msgstr ""71msgstr ""
7972
80#. module: account_banking_sepa_credit_transfer73#. module: account_banking_sepa_credit_transfer
@@ -105,23 +98,6 @@
105msgstr ""98msgstr ""
10699
107#. module: account_banking_sepa_credit_transfer100#. module: account_banking_sepa_credit_transfer
108#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:122
109#, python-format
110msgid "Cannot compute the '%s'."
111msgstr ""
112
113#. module: account_banking_sepa_credit_transfer
114#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:126
115#, python-format
116msgid "The type of the field '%s' is %s. It should be a string or unicode."
117msgstr ""
118
119#. module: account_banking_sepa_credit_transfer
120#: selection:banking.export.sepa,state:0
121msgid "Sent"
122msgstr ""
123
124#. module: account_banking_sepa_credit_transfer
125#: view:banking.export.sepa.wizard:0101#: view:banking.export.sepa.wizard:0
126msgid "Validate"102msgid "Validate"
127msgstr ""103msgstr ""
@@ -132,25 +108,14 @@
132msgstr ""108msgstr ""
133109
134#. module: account_banking_sepa_credit_transfer110#. module: account_banking_sepa_credit_transfer
135#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:169
136#, python-format
137msgid "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"
138msgstr ""
139
140#. module: account_banking_sepa_credit_transfer
141#: selection:banking.export.sepa,charge_bearer:0111#: selection:banking.export.sepa,charge_bearer:0
142#: selection:banking.export.sepa.wizard,charge_bearer:0112#: selection:banking.export.sepa.wizard,charge_bearer:0
143msgid "Borne by Debtor"113msgid "Borne by Debtor"
144msgstr ""114msgstr ""
145115
146#. module: account_banking_sepa_credit_transfer116#. module: account_banking_sepa_credit_transfer
147#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:90117#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:128
148#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:116118#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:245
149#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:121
150#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:130
151#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:168
152#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:206
153#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:350
154#, python-format119#, python-format
155msgid "Error:"120msgid "Error:"
156msgstr ""121msgstr ""
@@ -173,18 +138,12 @@
173msgstr ""138msgstr ""
174139
175#. module: account_banking_sepa_credit_transfer140#. module: account_banking_sepa_credit_transfer
176#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:125
177#, python-format
178msgid "Field type error:"
179msgstr ""
180
181#. module: account_banking_sepa_credit_transfer
182#: model:ir.model,name:account_banking_sepa_credit_transfer.model_banking_export_sepa141#: model:ir.model,name:account_banking_sepa_credit_transfer.model_banking_export_sepa
183msgid "SEPA export"142msgid "SEPA export"
184msgstr ""143msgstr ""
185144
186#. module: account_banking_sepa_credit_transfer145#. module: account_banking_sepa_credit_transfer
187#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:351146#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:246
188#, python-format147#, python-format
189msgid "Missing Bank Account on invoice '%s' (payment order line reference '%s')."148msgid "Missing Bank Account on invoice '%s' (payment order line reference '%s')."
190msgstr ""149msgstr ""
@@ -196,29 +155,17 @@
196msgstr ""155msgstr ""
197156
198#. module: account_banking_sepa_credit_transfer157#. module: account_banking_sepa_credit_transfer
199#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:131
200#, python-format
201msgid "The '%s' is empty or 0. It should have a non-null value."
202msgstr ""
203
204#. module: account_banking_sepa_credit_transfer
205#: help:banking.export.sepa,charge_bearer:0158#: help:banking.export.sepa,charge_bearer:0
206msgid "Following service level : transaction charges are to be applied following the rules agreed in the service level and/or scheme (SEPA Core messages must use this). Shared : transaction charges on the creditor side are to be borne by the creditor, transaction charges on the debtor side are to be borne by the debtor. 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."159msgid "Following service level : transaction charges are to be applied following the rules agreed in the service level and/or scheme (SEPA Core messages must use this). Shared : transaction charges on the creditor side are to be borne by the creditor, transaction charges on the debtor side are to be borne by the debtor. 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."
207msgstr ""160msgstr ""
208161
209#. module: account_banking_sepa_credit_transfer162#. module: account_banking_sepa_credit_transfer
210#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:207163#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:129
211#, python-format164#, python-format
212msgid "Payment Type Code '%s' is not supported. The only Payment Type Codes supported for SEPA Credit Transfers are 'pain.001.001.02', 'pain.001.001.03', 'pain.001.001.04' and 'pain.001.001.05'."165msgid "Payment Type Code '%s' is not supported. The only Payment Type Codes supported for SEPA Credit Transfers are 'pain.001.001.02', 'pain.001.001.03', 'pain.001.001.04' and 'pain.001.001.05'."
213msgstr ""166msgstr ""
214167
215#. module: account_banking_sepa_credit_transfer168#. module: account_banking_sepa_credit_transfer
216#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:90
217#, python-format
218msgid "This IBAN is not valid : %s"
219msgstr ""
220
221#. module: account_banking_sepa_credit_transfer
222#: view:banking.export.sepa:0169#: view:banking.export.sepa:0
223#: field:banking.export.sepa,payment_order_ids:0170#: field:banking.export.sepa,payment_order_ids:0
224#: field:banking.export.sepa.wizard,payment_order_ids:0171#: field:banking.export.sepa.wizard,payment_order_ids:0
@@ -244,11 +191,6 @@
244msgstr ""191msgstr ""
245192
246#. module: account_banking_sepa_credit_transfer193#. module: account_banking_sepa_credit_transfer
247#: help:banking.export.sepa.wizard,prefered_exec_date:0
248msgid "This is the date on which the file should be processed by the bank. Please keep in mind that banks only execute on working days and typically use a delay of two days between execution date and effective transfer date."
249msgstr ""
250
251#. module: account_banking_sepa_credit_transfer
252#: field:banking.export.sepa.wizard,file:0194#: field:banking.export.sepa.wizard,file:0
253msgid "File"195msgid "File"
254msgstr ""196msgstr ""
255197
=== modified file 'account_banking_sepa_credit_transfer/i18n/fr.po'
--- account_banking_sepa_credit_transfer/i18n/fr.po 2013-12-03 06:20:09 +0000
+++ account_banking_sepa_credit_transfer/i18n/fr.po 2014-01-13 12:42:46 +0000
@@ -6,21 +6,14 @@
6msgstr ""6msgstr ""
7"Project-Id-Version: OpenERP Server 7.0\n"7"Project-Id-Version: OpenERP Server 7.0\n"
8"Report-Msgid-Bugs-To: \n"8"Report-Msgid-Bugs-To: \n"
9"POT-Creation-Date: 2013-11-13 09:13+0000\n"9"POT-Creation-Date: 2013-12-23 22:52+0000\n"
10"PO-Revision-Date: 2013-12-02 16:36+0000\n"10"PO-Revision-Date: 2013-12-23 22:52+0000\n"
11"Last-Translator: Alexis de Lattre <alexis@via.ecp.fr>\n"11"Last-Translator: <>\n"
12"Language-Team: \n"12"Language-Team: \n"
13"MIME-Version: 1.0\n"13"MIME-Version: 1.0\n"
14"Content-Type: text/plain; charset=UTF-8\n"14"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Transfer-Encoding: 8bit\n"15"Content-Transfer-Encoding: \n"
16"X-Launchpad-Export-Date: 2013-12-03 06:20+0000\n"16"Plural-Forms: \n"
17"X-Generator: Launchpad (build 16856)\n"
18
19#. module: account_banking_sepa_credit_transfer
20#: field:banking.export.sepa,prefered_exec_date:0
21#: field:banking.export.sepa.wizard,prefered_exec_date:0
22msgid "Prefered Execution Date"
23msgstr "Date d'exécution demandée"
2417
25#. module: account_banking_sepa_credit_transfer18#. module: account_banking_sepa_credit_transfer
26#: selection:banking.export.sepa.wizard,state:019#: selection:banking.export.sepa.wizard,state:0
@@ -52,31 +45,8 @@
5245
53#. module: account_banking_sepa_credit_transfer46#. module: account_banking_sepa_credit_transfer
54#: help:banking.export.sepa.wizard,charge_bearer:047#: help:banking.export.sepa.wizard,charge_bearer:0
55msgid ""48msgid "Following service level : transaction charges are to be applied following the rules agreed in the service level and/or scheme (SEPA Core messages must use this). Shared : transaction charges on the debtor side are to be borne by the debtor, transaction charges on the creditor side are to be borne by the creditor. 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."
56"Following service level : transaction charges are to be applied following "49msgstr "Suivant le niveau de service : la répartition des frais bancaires suit les règles pré-établies dans le schema ou dans le contrat avec la banque (les messages SEPA Core doivent utiliser ce paramètre). Partagés : les frais bancaires côté débiteur sont à la charge du débiteur, les frais bancaires côté créancier sont à la charge du créancier. Supportés par le créancier : tous les frais bancaires sont à la charge du créancier. Supportés par le débiteur : tous les frais bancaires sont à la charge du débiteur."
57"the rules agreed in the service level and/or scheme (SEPA Core messages must "
58"use this). Shared : transaction charges on the debtor side are to be borne "
59"by the debtor, transaction charges on the creditor side are to be borne by "
60"the creditor. Borne by creditor : all transaction charges are to be borne by "
61"the creditor. Borne by debtor : all transaction charges are to be borne by "
62"the debtor."
63msgstr ""
64"Suivant le niveau de service : la répartition des frais bancaires suit les "
65"règles pré-établies dans le schema ou dans le contrat avec la banque (les "
66"messages SEPA Core doivent utiliser ce paramètre). Partagés : les frais "
67"bancaires côté débiteur sont à la charge du débiteur, les frais bancaires "
68"côté créancier sont à la charge du créancier. Supportés par le créancier : "
69"tous les frais bancaires sont à la charge du créancier. Supportés par le "
70"débiteur : tous les frais bancaires sont à la charge du débiteur."
71
72#. module: account_banking_sepa_credit_transfer
73#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:117
74#, python-format
75msgid ""
76"Cannot compute the '%s' of the Payment Line with Invoice Reference '%s'."
77msgstr ""
78"Impossible de générer le '%s' de la ligne de paiement ayant la référence de "
79"facture '%s'."
8050
81#. module: account_banking_sepa_credit_transfer51#. module: account_banking_sepa_credit_transfer
82#: selection:banking.export.sepa,charge_bearer:052#: selection:banking.export.sepa,charge_bearer:0
@@ -91,9 +61,14 @@
91msgstr "Débit groupé"61msgstr "Débit groupé"
9262
93#. module: account_banking_sepa_credit_transfer63#. module: account_banking_sepa_credit_transfer
64#: selection:banking.export.sepa,state:0
65msgid "Sent"
66msgstr "Envoyé"
67
68#. module: account_banking_sepa_credit_transfer
94#: model:ir.model,name:account_banking_sepa_credit_transfer.model_banking_export_sepa_wizard69#: model:ir.model,name:account_banking_sepa_credit_transfer.model_banking_export_sepa_wizard
95msgid "Export SEPA Credit Transfer XML file"70msgid "Export SEPA Credit Transfer File"
96msgstr "Exporte the fichier de virement SEPA XML"71msgstr "Exporte le fichier de virement SEPA"
9772
98#. module: account_banking_sepa_credit_transfer73#. module: account_banking_sepa_credit_transfer
99#: view:banking.export.sepa:074#: view:banking.export.sepa:0
@@ -123,24 +98,6 @@
123msgstr "Supportés par le destinataire"98msgstr "Supportés par le destinataire"
12499
125#. module: account_banking_sepa_credit_transfer100#. module: account_banking_sepa_credit_transfer
126#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:122
127#, python-format
128msgid "Cannot compute the '%s'."
129msgstr "Impossible de générer le '%s'."
130
131#. module: account_banking_sepa_credit_transfer
132#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:126
133#, python-format
134msgid "The type of the field '%s' is %s. It should be a string or unicode."
135msgstr ""
136"Le champ '%s' est de type %s. Le type devrait être string ou unicode."
137
138#. module: account_banking_sepa_credit_transfer
139#: selection:banking.export.sepa,state:0
140msgid "Sent"
141msgstr "Envoyé"
142
143#. module: account_banking_sepa_credit_transfer
144#: view:banking.export.sepa.wizard:0101#: view:banking.export.sepa.wizard:0
145msgid "Validate"102msgid "Validate"
146msgstr "Valider"103msgstr "Valider"
@@ -151,33 +108,14 @@
151msgstr "Générer"108msgstr "Générer"
152109
153#. module: account_banking_sepa_credit_transfer110#. module: account_banking_sepa_credit_transfer
154#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:169
155#, python-format
156msgid ""
157"The generated XML file is not valid against the official XML Schema "
158"Definition. The generated XML file and the full error have been written in "
159"the server logs. Here is the error, which may give you an idea on the cause "
160"of the problem : %s"
161msgstr ""
162"Le fichier XML généré n'est pas valide par rapport à la Définition du Schéma "
163"XML officiel. Le fichier XML généré et le message d'erreur complet ont été "
164"écrits dans les logs du serveur. Voici l'erreur, qui vous donnera peut-être "
165"une idée sur la cause du problème : %s"
166
167#. module: account_banking_sepa_credit_transfer
168#: selection:banking.export.sepa,charge_bearer:0111#: selection:banking.export.sepa,charge_bearer:0
169#: selection:banking.export.sepa.wizard,charge_bearer:0112#: selection:banking.export.sepa.wizard,charge_bearer:0
170msgid "Borne by Debtor"113msgid "Borne by Debtor"
171msgstr "Supportés par l'émetteur"114msgstr "Supportés par l'émetteur"
172115
173#. module: account_banking_sepa_credit_transfer116#. module: account_banking_sepa_credit_transfer
174#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:90117#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:128
175#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:116118#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:245
176#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:121
177#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:130
178#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:168
179#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:206
180#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:350
181#, python-format119#, python-format
182msgid "Error:"120msgid "Error:"
183msgstr "Erreur :"121msgstr "Erreur :"
@@ -200,24 +138,15 @@
200msgstr "Génération du fichier SEPA"138msgstr "Génération du fichier SEPA"
201139
202#. module: account_banking_sepa_credit_transfer140#. module: account_banking_sepa_credit_transfer
203#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:125
204#, python-format
205msgid "Field type error:"
206msgstr "Erreur dans le type de champ:"
207
208#. module: account_banking_sepa_credit_transfer
209#: model:ir.model,name:account_banking_sepa_credit_transfer.model_banking_export_sepa141#: model:ir.model,name:account_banking_sepa_credit_transfer.model_banking_export_sepa
210msgid "SEPA export"142msgid "SEPA export"
211msgstr "Export SEPA"143msgstr "Export SEPA"
212144
213#. module: account_banking_sepa_credit_transfer145#. module: account_banking_sepa_credit_transfer
214#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:351146#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:246
215#, python-format147#, python-format
216msgid ""148msgid "Missing Bank Account on invoice '%s' (payment order line reference '%s')."
217"Missing Bank Account on invoice '%s' (payment order line reference '%s')."149msgstr "Compte bancaire manquant sur la facture '%s' (référence de la ligne de paiement : '%s')."
218msgstr ""
219"Compte bancaire manquant sur la facture '%s' (référence de la ligne de "
220"paiement : '%s')."
221150
222#. module: account_banking_sepa_credit_transfer151#. module: account_banking_sepa_credit_transfer
223#: field:banking.export.sepa,file:0152#: field:banking.export.sepa,file:0
@@ -226,47 +155,15 @@
226msgstr "Fichier SEPA XML"155msgstr "Fichier SEPA XML"
227156
228#. module: account_banking_sepa_credit_transfer157#. module: account_banking_sepa_credit_transfer
229#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:131
230#, python-format
231msgid "The '%s' is empty or 0. It should have a non-null value."
232msgstr "Le '%s' est vide ou égal à 0. La valeur devrait être non nulle."
233
234#. module: account_banking_sepa_credit_transfer
235#: help:banking.export.sepa,charge_bearer:0158#: help:banking.export.sepa,charge_bearer:0
236msgid ""159msgid "Following service level : transaction charges are to be applied following the rules agreed in the service level and/or scheme (SEPA Core messages must use this). Shared : transaction charges on the creditor side are to be borne by the creditor, transaction charges on the debtor side are to be borne by the debtor. 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."
237"Following service level : transaction charges are to be applied following "160msgstr "Suivant le niveau de service : la répartition des frais bancaires suit les règles pré-établies dans le schema ou dans le contrat avec la banque (les messages SEPA Core doivent utiliser ce paramètre). Partagés : les frais bancaires côté débiteur sont à la charge du débiteur, les frais bancaires côté créancier sont à la charge du créancier. Supportés par le créancier : tous les frais bancaires sont à la charge du créancier. Supportés par le débiteur : tous les frais bancaires sont à la charge du débiteur."
238"the rules agreed in the service level and/or scheme (SEPA Core messages must "161
239"use this). Shared : transaction charges on the creditor side are to be borne "162#. module: account_banking_sepa_credit_transfer
240"by the creditor, transaction charges on the debtor side are to be borne by "163#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:129
241"the debtor. Borne by creditor : all transaction charges are to be borne by "164#, python-format
242"the creditor. Borne by debtor : all transaction charges are to be borne by "165msgid "Payment Type Code '%s' is not supported. The only Payment Type Codes supported for SEPA Credit Transfers are 'pain.001.001.02', 'pain.001.001.03', 'pain.001.001.04' and 'pain.001.001.05'."
243"the debtor."166msgstr "Le code du Type de paiement '%s' n'est pas supporté. Les seuls codes de Type de paiement supportés pour les virements SEPA sont 'pain.001.001.02', 'pain.001.001.03', 'pain.001.001.04' et 'pain.001.001.05'."
244msgstr ""
245"Suivant le niveau de service : la répartition des frais bancaires suit les "
246"règles pré-établies dans le schema ou dans le contrat avec la banque (les "
247"messages SEPA Core doivent utiliser ce paramètre). Partagés : les frais "
248"bancaires côté débiteur sont à la charge du débiteur, les frais bancaires "
249"côté créancier sont à la charge du créancier. Supportés par le créancier : "
250"tous les frais bancaires sont à la charge du créancier. Supportés par le "
251"débiteur : tous les frais bancaires sont à la charge du débiteur."
252
253#. module: account_banking_sepa_credit_transfer
254#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:207
255#, python-format
256msgid ""
257"Payment Type Code '%s' is not supported. The only Payment Type Codes "
258"supported for SEPA Credit Transfers are 'pain.001.001.02', "
259"'pain.001.001.03', 'pain.001.001.04' and 'pain.001.001.05'."
260msgstr ""
261"Le code du Type de paiement '%s' n'est pas supporté. Les seuls codes de Type "
262"de paiement supportés pour les virements SEPA sont 'pain.001.001.02', "
263"'pain.001.001.03', 'pain.001.001.04' et 'pain.001.001.05'."
264
265#. module: account_banking_sepa_credit_transfer
266#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:90
267#, python-format
268msgid "This IBAN is not valid : %s"
269msgstr "Cet IBAN n'est pas valide : %s"
270167
271#. module: account_banking_sepa_credit_transfer168#. module: account_banking_sepa_credit_transfer
272#: view:banking.export.sepa:0169#: view:banking.export.sepa:0
@@ -290,26 +187,8 @@
290#. module: account_banking_sepa_credit_transfer187#. module: account_banking_sepa_credit_transfer
291#: help:banking.export.sepa,batch_booking:0188#: help:banking.export.sepa,batch_booking:0
292#: help:banking.export.sepa.wizard,batch_booking:0189#: help:banking.export.sepa.wizard,batch_booking:0
293msgid ""190msgid "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."
294"If true, the bank statement will display only one debit line for all the "191msgstr "Si coché, le relevé de compte ne comportera qu'une ligne de débit pour tous les virements du fichier SEPA XML ; si non coché, le relevé de compte comportera une ligne de débit pour chaque virement du fichier SEPA XML."
295"wire transfers of the SEPA XML file ; if false, the bank statement will "
296"display one debit line per wire transfer of the SEPA XML file."
297msgstr ""
298"Si coché, le relevé de compte ne comportera qu'une ligne de débit pour tous "
299"les virements du fichier SEPA XML ; si non coché, le relevé de compte "
300"comportera une ligne de débit pour chaque virement du fichier SEPA XML."
301
302#. module: account_banking_sepa_credit_transfer
303#: help:banking.export.sepa.wizard,prefered_exec_date:0
304msgid ""
305"This is the date on which the file should be processed by the bank. Please "
306"keep in mind that banks only execute on working days and typically use a "
307"delay of two days between execution date and effective transfer date."
308msgstr ""
309"C'est la date à laquelle le fichier doit être traité par la banque. Gardez "
310"en tête que les banques réalisent des traitements seulement les jours ouvrés "
311"et ont habituellement un délai de 2 jours entre la date de traitement et la "
312"date du transfert effectif."
313192
314#. module: account_banking_sepa_credit_transfer193#. module: account_banking_sepa_credit_transfer
315#: field:banking.export.sepa.wizard,file:0194#: field:banking.export.sepa.wizard,file:0
@@ -326,88 +205,3 @@
326msgid "Generation Date"205msgid "Generation Date"
327msgstr "Date de génération"206msgstr "Date de génération"
328207
329#~ msgid "SEPA XML file"
330#~ msgstr "Fichier SEPA XML"
331
332#~ msgid "Payment order"
333#~ msgstr "Ordre de paiement"
334
335#~ msgid ""
336#~ "This is the message identification of the entire SEPA XML file. 35 "
337#~ "characters max."
338#~ msgstr ""
339#~ "Ceci est le libellé d'identification du fichier SEPA XML. 35 caractères "
340#~ "maximum."
341
342#~ msgid "Prefered execution date"
343#~ msgstr "Date d'exécution demandée"
344
345#~ msgid "Generation date"
346#~ msgstr "Date de génération"
347
348#~ msgid "Message identification"
349#~ msgstr "Libellé d'identification"
350
351#~ msgid "Total amount"
352#~ msgstr "Montant total"
353
354#~ msgid ""
355#~ "Shared : transaction charges on the sender side are to be borne by the "
356#~ "debtor, transaction charges on the receiver side are to be borne by the "
357#~ "creditor (most transfers use this). Borne by creditor : all transaction "
358#~ "charges are to be borne by the creditor. Borne by debtor : all transaction "
359#~ "charges are to be borne by the debtor. Following service level : transaction "
360#~ "charges are to be applied following the rules agreed in the service level "
361#~ "and/or scheme."
362#~ msgstr ""
363#~ "Partagés : les frais bancaires côté émetteur sont à la charge de l'émetteur "
364#~ "et les frais bancaires côté destinataire sont à la charge du destinataire "
365#~ "(la plupart des virements utilisent cette répartition). Supportés par le "
366#~ "destinataire : tous les frais bancaires sont à la charge du destinataire. "
367#~ "Supportés par l'émetteur : tous les frais bancaires sont à la charge de "
368#~ "l'émetteur. Suivant le niveau de service : la répartition des frais "
369#~ "bancaires suit les règles pré-établies dans le contrat avec la banque."
370
371#~ msgid "Borne by creditor"
372#~ msgstr "Supportés par le destinataire"
373
374#~ msgid "Payment orders"
375#~ msgstr "Ordres de paiement"
376
377#~ msgid "SEPA XML file generation"
378#~ msgstr "Génération du fichier SEPA XML"
379
380#~ msgid "Reference for further communication"
381#~ msgstr "Référence pour communication ultérieure"
382
383#~ msgid "Processing details"
384#~ msgstr "Paramètres"
385
386#~ msgid "Borne by debtor"
387#~ msgstr "Supportés par l'émetteur"
388
389#~ msgid "Number of transactions"
390#~ msgstr "Nombre de transactions"
391
392#~ msgid "Following service level"
393#~ msgstr "Suivant le niveau de service"
394
395#~ msgid "Charge bearer"
396#~ msgstr "Répartition des frais"
397
398#, python-format
399#~ msgid ""
400#~ "Payment Type Code '%s' is not supported. The only Payment Type Codes "
401#~ "supported for SEPA Credit Transfers are 'pain.001.001.02', 'pain.001.001.03' "
402#~ "and 'pain.001.001.04'."
403#~ msgstr ""
404#~ "Le code '%s' pour le Type de Paiment n'est pas supporté. Les seuls codes de "
405#~ "Types de Paiement supportés pour les virements SEPA sont 'pain.001.001.02', "
406#~ "'pain.001.001.03' et 'pain.001.001.04'."
407
408#, python-format
409#~ msgid "Error :"
410#~ msgstr "Erreur :"
411
412#~ msgid "Batch booking"
413#~ msgstr "Débit groupé"
414208
=== modified file 'account_banking_sepa_credit_transfer/wizard/export_sepa.py'
--- account_banking_sepa_credit_transfer/wizard/export_sepa.py 2013-11-12 21:38:21 +0000
+++ account_banking_sepa_credit_transfer/wizard/export_sepa.py 2014-01-13 12:42:46 +0000
@@ -22,20 +22,14 @@
2222
2323
24from openerp.osv import orm, fields24from openerp.osv import orm, fields
25import base64
26from datetime import datetime
27from openerp.tools.translate import _25from openerp.tools.translate import _
28from openerp.tools.safe_eval import safe_eval26from openerp import netsvc
29from openerp import tools, netsvc
30from lxml import etree27from lxml import etree
31import logging
32from unidecode import unidecode
33
34_logger = logging.getLogger(__name__)
3528
3629
37class banking_export_sepa_wizard(orm.TransientModel):30class banking_export_sepa_wizard(orm.TransientModel):
38 _name = 'banking.export.sepa.wizard'31 _name = 'banking.export.sepa.wizard'
32 _inherit = ['banking.export.pain']
39 _description = 'Export SEPA Credit Transfer File'33 _description = 'Export SEPA Credit Transfer File'
4034
41 _columns = {35 _columns = {
@@ -45,17 +39,24 @@
45 ], 'State', readonly=True),39 ], 'State', readonly=True),
46 'batch_booking': fields.boolean(40 'batch_booking': fields.boolean(
47 'Batch Booking',41 'Batch Booking',
48 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."),42 help="If true, the bank statement will display only one debit "
49 'prefered_exec_date': fields.date(43 "line for all the wire transfers of the SEPA XML file ; if "
50 'Prefered Execution Date',44 "false, the bank statement will display one debit line per wire "
51 help='This is the date on which the file should be processed by the bank. Please keep in mind that banks only execute on working days and typically use a delay of two days between execution date and effective transfer date.'),45 "transfer of the SEPA XML file."),
52 'charge_bearer': fields.selection([46 'charge_bearer': fields.selection([
53 ('SLEV', 'Following Service Level'),47 ('SLEV', 'Following Service Level'),
54 ('SHAR', 'Shared'),48 ('SHAR', 'Shared'),
55 ('CRED', 'Borne by Creditor'),49 ('CRED', 'Borne by Creditor'),
56 ('DEBT', 'Borne by Debtor'),50 ('DEBT', 'Borne by Debtor'),
57 ], 'Charge Bearer', required=True,51 ], 'Charge Bearer', required=True,
58 help='Following service level : transaction charges are to be applied following the rules agreed in the service level and/or scheme (SEPA Core messages must use this). Shared : transaction charges on the debtor side are to be borne by the debtor, transaction charges on the creditor side are to be borne by the creditor. 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.'),52 help="Following service level : transaction charges are to be "
53 "applied following the rules agreed in the service level and/or "
54 "scheme (SEPA Core messages must use this). Shared : transaction "
55 "charges on the debtor side are to be borne by the debtor, "
56 "transaction charges on the creditor side are to be borne by "
57 "the creditor. Borne by creditor : all transaction charges are "
58 "to be borne by the creditor. Borne by debtor : all transaction "
59 "charges are to be borne by the debtor."),
59 'nb_transactions': fields.related(60 'nb_transactions': fields.related(
60 'file_id', 'nb_transactions', type='integer',61 'file_id', 'nb_transactions', type='integer',
61 string='Number of Transactions', readonly=True),62 string='Number of Transactions', readonly=True),
@@ -79,16 +80,6 @@
79 'state': 'create',80 'state': 'create',
80 }81 }
8182
82 def _validate_iban(self, cr, uid, iban, context=None):
83 '''if IBAN is valid, returns IBAN
84 if IBAN is NOT valid, raises an error message'''
85 partner_bank_obj = self.pool.get('res.partner.bank')
86 if partner_bank_obj.is_iban_valid(cr, uid, iban, context=context):
87 return iban.replace(' ', '')
88 else:
89 raise orm.except_orm(
90 _('Error:'), _("This IBAN is not valid : %s") % iban)
91
92 def create(self, cr, uid, vals, context=None):83 def create(self, cr, uid, vals, context=None):
93 payment_order_ids = context.get('active_ids', [])84 payment_order_ids = context.get('active_ids', [])
94 vals.update({85 vals.update({
@@ -97,85 +88,16 @@
97 return super(banking_export_sepa_wizard, self).create(88 return super(banking_export_sepa_wizard, self).create(
98 cr, uid, vals, context=context)89 cr, uid, vals, context=context)
9990
100 def _prepare_field(
101 self, cr, uid, field_name, field_value, eval_ctx, max_size=0,
102 context=None):
103 '''This function is designed to be inherited !'''
104 assert isinstance(eval_ctx, dict), 'eval_ctx must contain a dict'
105 try:
106 # SEPA uses XML ; XML = UTF-8 ; UTF-8 = support for all characters
107 # But we are dealing with banks...
108 # and many banks don't want non-ASCCI characters !
109 # cf section 1.4 "Character set" of the SEPA Credit Transfer
110 # Scheme Customer-to-bank guidelines
111 value = unidecode(safe_eval(field_value, eval_ctx))
112 except:
113 line = eval_ctx.get('line')
114 if line:
115 raise orm.except_orm(
116 _('Error:'),
117 _("Cannot compute the '%s' of the Payment Line with Invoice Reference '%s'.")
118 % (field_name, self.pool['account.invoice'].name_get(cr, uid, [line.ml_inv_ref.id], context=context)[0][1]))
119 else:
120 raise orm.except_orm(
121 _('Error:'),
122 _("Cannot compute the '%s'.") % field_name)
123 if not isinstance(value, (str, unicode)):
124 raise orm.except_orm(
125 _('Field type error:'),
126 _("The type of the field '%s' is %s. It should be a string or unicode.")
127 % (field_name, type(value)))
128 if not value:
129 raise orm.except_orm(
130 _('Error:'),
131 _("The '%s' is empty or 0. It should have a non-null value.")
132 % field_name)
133 if max_size and len(value) > max_size:
134 value = value[0:max_size]
135 return value
136
137 def _prepare_export_sepa(
138 self, cr, uid, sepa_export, total_amount, transactions_count,
139 xml_string, context=None):
140 return {
141 'batch_booking': sepa_export.batch_booking,
142 'charge_bearer': sepa_export.charge_bearer,
143 'prefered_exec_date': sepa_export.prefered_exec_date,
144 'total_amount': total_amount,
145 'nb_transactions': transactions_count,
146 'file': base64.encodestring(xml_string),
147 'payment_order_ids': [
148 (6, 0, [x.id for x in sepa_export.payment_order_ids])
149 ],
150 }
151
152 def _validate_xml(self, cr, uid, xml_string, pain_flavor):
153 xsd_etree_obj = etree.parse(
154 tools.file_open(
155 'account_banking_sepa_credit_transfer/data/%s.xsd'
156 % pain_flavor))
157 official_pain_schema = etree.XMLSchema(xsd_etree_obj)
158
159 try:
160 root_to_validate = etree.fromstring(xml_string)
161 official_pain_schema.assertValid(root_to_validate)
162 except Exception, e:
163 _logger.warning(
164 "The XML file is invalid against the XML Schema Definition")
165 _logger.warning(xml_string)
166 _logger.warning(e)
167 raise orm.except_orm(
168 _('Error:'),
169 _('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')
170 % str(e))
171 return True
172
173 def create_sepa(self, cr, uid, ids, context=None):91 def create_sepa(self, cr, uid, ids, context=None):
174 '''92 '''
175 Creates the SEPA Credit Transfer file. That's the important code !93 Creates the SEPA Credit Transfer file. That's the important code !
176 '''94 '''
95 if context is None:
96 context = {}
177 sepa_export = self.browse(cr, uid, ids[0], context=context)97 sepa_export = self.browse(cr, uid, ids[0], context=context)
178 pain_flavor = sepa_export.payment_order_ids[0].mode.type.code98 pain_flavor = sepa_export.payment_order_ids[0].mode.type.code
99 convert_to_ascii = \
100 sepa_export.payment_order_ids[0].mode.convert_to_ascii
179 if pain_flavor == 'pain.001.001.02':101 if pain_flavor == 'pain.001.001.02':
180 bic_xml_tag = 'BIC'102 bic_xml_tag = 'BIC'
181 name_maxsize = 70103 name_maxsize = 70
@@ -204,124 +126,98 @@
204 else:126 else:
205 raise orm.except_orm(127 raise orm.except_orm(
206 _('Error:'),128 _('Error:'),
207 _("Payment Type Code '%s' is not supported. The only Payment Type Codes supported for SEPA Credit Transfers are 'pain.001.001.02', 'pain.001.001.03', 'pain.001.001.04' and 'pain.001.001.05'.")129 _("Payment Type Code '%s' is not supported. The only "
130 "Payment Type Codes supported for SEPA Credit Transfers "
131 "are 'pain.001.001.02', 'pain.001.001.03', "
132 "'pain.001.001.04' and 'pain.001.001.05'.")
208 % pain_flavor)133 % pain_flavor)
209 if sepa_export.prefered_exec_date:134
210 my_requested_exec_date = sepa_export.prefered_exec_date135 gen_args = {
211 else:136 'bic_xml_tag': bic_xml_tag,
212 my_requested_exec_date = fields.date.context_today(137 'name_maxsize': name_maxsize,
213 self, cr, uid, context=context)138 'convert_to_ascii': convert_to_ascii,
139 'payment_method': 'TRF',
140 'pain_flavor': pain_flavor,
141 'sepa_export': sepa_export,
142 'file_obj': self.pool['banking.export.sepa'],
143 'pain_xsd_file':
144 'account_banking_sepa_credit_transfer/data/%s.xsd'
145 % pain_flavor,
146 }
214147
215 pain_ns = {148 pain_ns = {
216 'xsi': 'http://www.w3.org/2001/XMLSchema-instance',149 'xsi': 'http://www.w3.org/2001/XMLSchema-instance',
217 None: 'urn:iso:std:iso:20022:tech:xsd:%s' % pain_flavor,150 None: 'urn:iso:std:iso:20022:tech:xsd:%s' % pain_flavor,
218 }151 }
219152
220 root = etree.Element('Document', nsmap=pain_ns)153 xml_root = etree.Element('Document', nsmap=pain_ns)
221 pain_root = etree.SubElement(root, root_xml_tag)154 pain_root = etree.SubElement(xml_root, root_xml_tag)
222155 pain_03_to_05 = \
223 my_company_name = self._prepare_field(156 ['pain.001.001.03', 'pain.001.001.04', 'pain.001.001.05']
224 cr, uid, 'Company Name',
225 'sepa_export.payment_order_ids[0].mode.bank_id.partner_id.name',
226 {'sepa_export': sepa_export}, name_maxsize, context=context)
227157
228 # A. Group header158 # A. Group header
229 group_header_1_0 = etree.SubElement(pain_root, 'GrpHdr')159 group_header_1_0, nb_of_transactions_1_6, control_sum_1_7 = \
230 message_identification_1_1 = etree.SubElement(160 self.generate_group_header_block(
231 group_header_1_0, 'MsgId')161 cr, uid, pain_root, gen_args, context=context)
232 message_identification_1_1.text = self._prepare_field(162
233 cr, uid, 'Message Identification',163 transactions_count_1_6 = 0
234 'sepa_export.payment_order_ids[0].reference',
235 {'sepa_export': sepa_export}, 35, context=context)
236 creation_date_time_1_2 = etree.SubElement(group_header_1_0, 'CreDtTm')
237 creation_date_time_1_2.text = datetime.strftime(
238 datetime.today(), '%Y-%m-%dT%H:%M:%S')
239 if pain_flavor == 'pain.001.001.02':
240 # batch_booking is in "Group header" with pain.001.001.02
241 # and in "Payment info" in pain.001.001.03/04
242 batch_booking = etree.SubElement(group_header_1_0, 'BtchBookg')
243 batch_booking.text = str(sepa_export.batch_booking).lower()
244 nb_of_transactions_1_6 = etree.SubElement(
245 group_header_1_0, 'NbOfTxs')
246 control_sum_1_7 = etree.SubElement(group_header_1_0, 'CtrlSum')
247 # Grpg removed in pain.001.001.03
248 if pain_flavor == 'pain.001.001.02':
249 grouping = etree.SubElement(group_header_1_0, 'Grpg')
250 grouping.text = 'GRPD'
251 initiating_party_1_8 = etree.SubElement(group_header_1_0, 'InitgPty')
252 initiating_party_name = etree.SubElement(initiating_party_1_8, 'Nm')
253 initiating_party_name.text = my_company_name
254
255 # B. Payment info
256 payment_info_2_0 = etree.SubElement(pain_root, 'PmtInf')
257 payment_info_identification_2_1 = etree.SubElement(
258 payment_info_2_0, 'PmtInfId')
259 payment_info_identification_2_1.text = self._prepare_field(
260 cr, uid, 'Payment Information Identification',
261 "sepa_export.payment_order_ids[0].reference",
262 {'sepa_export': sepa_export}, 35, context=context)
263 payment_method_2_2 = etree.SubElement(payment_info_2_0, 'PmtMtd')
264 payment_method_2_2.text = 'TRF'
265 if pain_flavor in [
266 'pain.001.001.03', 'pain.001.001.04', 'pain.001.001.05']:
267 # batch_booking is in "Group header" with pain.001.001.02
268 # and in "Payment info" in pain.001.001.03/04
269 batch_booking_2_3 = etree.SubElement(payment_info_2_0, 'BtchBookg')
270 batch_booking_2_3.text = str(sepa_export.batch_booking).lower()
271 # It may seem surprising, but the
272 # "SEPA Credit Transfer Scheme Customer-to-bank Implementation
273 # guidelines" v6.0 says that control sum and nb_of_transactions
274 # should be present at both "group header" level and "payment info"
275 # level. This seems to be confirmed by the tests carried out at
276 # BNP Paribas in PAIN v001.001.03
277 if pain_flavor in [
278 'pain.001.001.03', 'pain.001.001.04', 'pain.001.001.05']:
279 nb_of_transactions_2_4 = etree.SubElement(
280 payment_info_2_0, 'NbOfTxs')
281 control_sum_2_5 = etree.SubElement(payment_info_2_0, 'CtrlSum')
282 payment_type_info_2_6 = etree.SubElement(payment_info_2_0, 'PmtTpInf')
283 service_level_2_8 = etree.SubElement(payment_type_info_2_6, 'SvcLvl')
284 service_level_code_2_9 = etree.SubElement(service_level_2_8, 'Cd')
285 service_level_code_2_9.text = 'SEPA'
286 requested_exec_date_2_17 = etree.SubElement(
287 payment_info_2_0, 'ReqdExctnDt')
288 requested_exec_date_2_17.text = my_requested_exec_date
289 debtor_2_19 = etree.SubElement(payment_info_2_0, 'Dbtr')
290 debtor_name = etree.SubElement(debtor_2_19, 'Nm')
291 debtor_name.text = my_company_name
292 debtor_account_2_20 = etree.SubElement(payment_info_2_0, 'DbtrAcct')
293 debtor_account_id = etree.SubElement(debtor_account_2_20, 'Id')
294 debtor_account_iban = etree.SubElement(debtor_account_id, 'IBAN')
295 debtor_account_iban.text = self._validate_iban(
296 cr, uid, self._prepare_field(
297 cr, uid, 'Company IBAN',
298 'sepa_export.payment_order_ids[0].mode.bank_id.acc_number',
299 {'sepa_export': sepa_export}, context=context),
300 context=context)
301 debtor_agent_2_21 = etree.SubElement(payment_info_2_0, 'DbtrAgt')
302 debtor_agent_institution = etree.SubElement(
303 debtor_agent_2_21, 'FinInstnId')
304 debtor_agent_bic = etree.SubElement(
305 debtor_agent_institution, bic_xml_tag)
306 # TODO validate BIC with pattern
307 # [A-Z]{6,6}[A-Z2-9][A-NP-Z0-9]([A-Z0-9]{3,3}){0,1}
308 # because OpenERP doesn't have a constraint on BIC
309 debtor_agent_bic.text = self._prepare_field(
310 cr, uid, 'Company BIC',
311 'sepa_export.payment_order_ids[0].mode.bank_id.bank.bic',
312 {'sepa_export': sepa_export}, context=context)
313 charge_bearer_2_24 = etree.SubElement(payment_info_2_0, 'ChrgBr')
314 charge_bearer_2_24.text = sepa_export.charge_bearer
315
316 transactions_count = 0
317 total_amount = 0.0164 total_amount = 0.0
318 amount_control_sum = 0.0165 amount_control_sum_1_7 = 0.0
319 # Iterate on payment orders166 lines_per_group = {}
167 # key = (requested_date, priority)
168 # values = list of lines as object
169 today = fields.date.context_today(self, cr, uid, context=context)
320 for payment_order in sepa_export.payment_order_ids:170 for payment_order in sepa_export.payment_order_ids:
321 total_amount = total_amount + payment_order.total171 total_amount = total_amount + payment_order.total
322 # Iterate each payment lines
323 for line in payment_order.line_ids:172 for line in payment_order.line_ids:
324 transactions_count += 1173 priority = line.priority
174 if payment_order.date_prefered == 'due':
175 requested_date = line.ml_maturity_date or today
176 elif payment_order.date_prefered == 'fixed':
177 requested_date = payment_order.date_scheduled or today
178 else:
179 requested_date = today
180 key = (requested_date, priority)
181 if key in lines_per_group:
182 lines_per_group[key].append(line)
183 else:
184 lines_per_group[key] = [line]
185 # Write requested_date on 'Payment date' of the pay line
186 if requested_date != line.date:
187 self.pool['payment.line'].write(
188 cr, uid, line.id,
189 {'date': requested_date}, context=context)
190
191 for (requested_date, priority), lines in lines_per_group.items():
192 # B. Payment info
193 payment_info_2_0, nb_of_transactions_2_4, control_sum_2_5 = \
194 self.generate_start_payment_info_block(
195 cr, uid, pain_root,
196 "sepa_export.payment_order_ids[0].reference + '-' "
197 "+ requested_date.replace('-', '') + '-' + priority",
198 priority, False, False, requested_date, {
199 'sepa_export': sepa_export,
200 'priority': priority,
201 'requested_date': requested_date,
202 }, gen_args, context=context)
203
204 self.generate_party_block(
205 cr, uid, payment_info_2_0, 'Dbtr', 'B',
206 'sepa_export.payment_order_ids[0].mode.bank_id.partner_id.'
207 'name',
208 'sepa_export.payment_order_ids[0].mode.bank_id.acc_number',
209 'sepa_export.payment_order_ids[0].mode.bank_id.bank.bic',
210 {'sepa_export': sepa_export},
211 gen_args, context=context)
212
213 charge_bearer_2_24 = etree.SubElement(payment_info_2_0, 'ChrgBr')
214 charge_bearer_2_24.text = sepa_export.charge_bearer
215
216 transactions_count_2_4 = 0
217 amount_control_sum_2_5 = 0.0
218 for line in lines:
219 transactions_count_1_6 += 1
220 transactions_count_2_4 += 1
325 # C. Credit Transfer Transaction Info221 # C. Credit Transfer Transaction Info
326 credit_transfer_transaction_info_2_27 = etree.SubElement(222 credit_transfer_transaction_info_2_27 = etree.SubElement(
327 payment_info_2_0, 'CdtTrfTxInf')223 payment_info_2_0, 'CdtTrfTxInf')
@@ -331,104 +227,54 @@
331 payment_identification_2_28, 'EndToEndId')227 payment_identification_2_28, 'EndToEndId')
332 end2end_identification_2_30.text = self._prepare_field(228 end2end_identification_2_30.text = self._prepare_field(
333 cr, uid, 'End to End Identification', 'line.name',229 cr, uid, 'End to End Identification', 'line.name',
334 {'line': line}, 35, context=context)230 {'line': line}, 35, gen_args=gen_args,
231 context=context)
335 currency_name = self._prepare_field(232 currency_name = self._prepare_field(
336 cr, uid, 'Currency Code', 'line.currency.name',233 cr, uid, 'Currency Code', 'line.currency.name',
337 {'line': line}, 3, context=context)234 {'line': line}, 3, gen_args=gen_args,
235 context=context)
338 amount_2_42 = etree.SubElement(236 amount_2_42 = etree.SubElement(
339 credit_transfer_transaction_info_2_27, 'Amt')237 credit_transfer_transaction_info_2_27, 'Amt')
340 instructed_amount_2_43 = etree.SubElement(238 instructed_amount_2_43 = etree.SubElement(
341 amount_2_42, 'InstdAmt', Ccy=currency_name)239 amount_2_42, 'InstdAmt', Ccy=currency_name)
342 instructed_amount_2_43.text = '%.2f' % line.amount_currency240 instructed_amount_2_43.text = '%.2f' % line.amount_currency
343 amount_control_sum += line.amount_currency241 amount_control_sum_1_7 += line.amount_currency
344 creditor_agent_2_77 = etree.SubElement(242 amount_control_sum_2_5 += line.amount_currency
345 credit_transfer_transaction_info_2_27, 'CdtrAgt')243
346 creditor_agent_institution = etree.SubElement(
347 creditor_agent_2_77, 'FinInstnId')
348 if not line.bank_id:244 if not line.bank_id:
349 raise orm.except_orm(245 raise orm.except_orm(
350 _('Error:'),246 _('Error:'),
351 _("Missing Bank Account on invoice '%s' (payment order line reference '%s').")247 _("Missing Bank Account on invoice '%s' (payment "
248 "order line reference '%s').")
352 % (line.ml_inv_ref.number, line.name))249 % (line.ml_inv_ref.number, line.name))
353 creditor_agent_bic = etree.SubElement(250 self.generate_party_block(
354 creditor_agent_institution, bic_xml_tag)251 cr, uid, credit_transfer_transaction_info_2_27, 'Cdtr',
355 creditor_agent_bic.text = self._prepare_field(252 'C', 'line.partner_id.name', 'line.bank_id.acc_number',
356 cr, uid, 'Customer BIC', 'line.bank_id.bank.bic',253 'line.bank_id.bank.bic', {'line': line}, gen_args,
357 {'line': line}, context=context)
358 creditor_2_79 = etree.SubElement(
359 credit_transfer_transaction_info_2_27, 'Cdtr')
360 creditor_name = etree.SubElement(creditor_2_79, 'Nm')
361 creditor_name.text = self._prepare_field(
362 cr, uid, 'Customer Name', 'line.partner_id.name',
363 {'line': line}, name_maxsize, context=context)
364 creditor_account_2_80 = etree.SubElement(
365 credit_transfer_transaction_info_2_27, 'CdtrAcct')
366 creditor_account_id = etree.SubElement(
367 creditor_account_2_80, 'Id')
368 creditor_account_iban = etree.SubElement(
369 creditor_account_id, 'IBAN')
370 creditor_account_iban.text = self._validate_iban(
371 cr, uid, self._prepare_field(
372 cr, uid, 'Customer IBAN',
373 'line.bank_id.acc_number', {'line': line},
374 context=context),
375 context=context)254 context=context)
376 remittance_info_2_91 = etree.SubElement(255
377 credit_transfer_transaction_info_2_27, 'RmtInf')256 self.generate_remittance_info_block(
378 # switch to Structured (Strdr) ?257 cr, uid, credit_transfer_transaction_info_2_27,
379 # If we do it, beware that the format is not the same258 line, gen_args, context=context)
380 # between pain 02 and pain 03259
381 remittance_info_unstructured_2_99 = etree.SubElement(260 if pain_flavor in pain_03_to_05:
382 remittance_info_2_91, 'Ustrd')261 nb_of_transactions_2_4.text = str(transactions_count_2_4)
383 remittance_info_unstructured_2_99.text = self._prepare_field(262 control_sum_2_5.text = '%.2f' % amount_control_sum_2_5
384 cr, uid, 'Remittance Information', 'line.communication',263
385 {'line': line}, 140, context=context)264 if pain_flavor in pain_03_to_05:
386265 nb_of_transactions_1_6.text = str(transactions_count_1_6)
387 if pain_flavor in [266 control_sum_1_7.text = '%.2f' % amount_control_sum_1_7
388 'pain.001.001.03', 'pain.001.001.04', 'pain.001.001.05']:
389 nb_of_transactions_1_6.text = nb_of_transactions_2_4.text = \
390 str(transactions_count)
391 control_sum_1_7.text = control_sum_2_5.text = \
392 '%.2f' % amount_control_sum
393 else:267 else:
394 nb_of_transactions_1_6.text = str(transactions_count)268 nb_of_transactions_1_6.text = str(transactions_count_1_6)
395 control_sum_1_7.text = '%.2f' % amount_control_sum269 control_sum_1_7.text = '%.2f' % amount_control_sum_1_7
396270
397 xml_string = etree.tostring(271 return self.finalize_sepa_file_creation(
398 root, pretty_print=True, encoding='UTF-8', xml_declaration=True)272 cr, uid, ids, xml_root, total_amount, transactions_count_1_6,
399 _logger.debug(273 gen_args, context=context)
400 "Generated SEPA Credit Transfer XML file in format %s below"
401 % pain_flavor)
402 _logger.debug(xml_string)
403 self._validate_xml(cr, uid, xml_string, pain_flavor)
404
405 # CREATE the banking.export.sepa record
406 file_id = self.pool.get('banking.export.sepa').create(
407 cr, uid, self._prepare_export_sepa(
408 cr, uid, sepa_export, total_amount, transactions_count,
409 xml_string, context=context),
410 context=context)
411
412 self.write(
413 cr, uid, ids, {
414 'file_id': file_id,
415 'state': 'finish',
416 }, context=context)
417
418 action = {
419 'name': 'SEPA Credit Transfer File',
420 'type': 'ir.actions.act_window',
421 'view_type': 'form',
422 'view_mode': 'form,tree',
423 'res_model': self._name,
424 'res_id': ids[0],
425 'target': 'new',
426 }
427 return action
428274
429 def cancel_sepa(self, cr, uid, ids, context=None):275 def cancel_sepa(self, cr, uid, ids, context=None):
430 '''276 '''
431 Cancel the SEPA PAIN: just drop the file277 Cancel the SEPA file: just drop the file
432 '''278 '''
433 sepa_export = self.browse(cr, uid, ids[0], context=context)279 sepa_export = self.browse(cr, uid, ids[0], context=context)
434 self.pool.get('banking.export.sepa').unlink(280 self.pool.get('banking.export.sepa').unlink(
@@ -437,7 +283,7 @@
437283
438 def save_sepa(self, cr, uid, ids, context=None):284 def save_sepa(self, cr, uid, ids, context=None):
439 '''285 '''
440 Save the SEPA PAIN: send the done signal to all payment286 Save the SEPA file: send the done signal to all payment
441 orders in the file. With the default workflow, they will287 orders in the file. With the default workflow, they will
442 transition to 'done', while with the advanced workflow in288 transition to 'done', while with the advanced workflow in
443 account_banking_payment they will transition to 'sent' waiting289 account_banking_payment they will transition to 'sent' waiting
444290
=== modified file 'account_banking_sepa_credit_transfer/wizard/export_sepa_view.xml'
--- account_banking_sepa_credit_transfer/wizard/export_sepa_view.xml 2013-11-07 11:50:36 +0000
+++ account_banking_sepa_credit_transfer/wizard/export_sepa_view.xml 2014-01-13 12:42:46 +0000
@@ -15,7 +15,6 @@
15 <field name="state" invisible="True"/>15 <field name="state" invisible="True"/>
16 <group states="create">16 <group states="create">
17 <field name="batch_booking" />17 <field name="batch_booking" />
18 <field name="prefered_exec_date" />
19 <field name="charge_bearer" />18 <field name="charge_bearer" />
20 </group>19 </group>
21 <group states="finish">20 <group states="finish">
2221
=== added directory 'account_banking_sepa_direct_debit'
=== added file 'account_banking_sepa_direct_debit/__init__.py'
--- account_banking_sepa_direct_debit/__init__.py 1970-01-01 00:00:00 +0000
+++ account_banking_sepa_direct_debit/__init__.py 2014-01-13 12:42:46 +0000
@@ -0,0 +1,25 @@
1# -*- encoding: utf-8 -*-
2##############################################################################
3#
4# SEPA Direct Debit module for OpenERP
5# Copyright (C) 2013 Akretion (http://www.akretion.com)
6# @author: Alexis de Lattre <alexis.delattre@akretion.com>
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Affero General Public License as
10# published by the Free Software Foundation, either version 3 of the
11# License, or (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.
17#
18# You should have received a copy of the GNU Affero General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20#
21##############################################################################
22
23from . import company
24from . import wizard
25from . import account_banking_sdd
026
=== added file 'account_banking_sepa_direct_debit/__openerp__.py'
--- account_banking_sepa_direct_debit/__openerp__.py 1970-01-01 00:00:00 +0000
+++ account_banking_sepa_direct_debit/__openerp__.py 2014-01-13 12:42:46 +0000
@@ -0,0 +1,60 @@
1##############################################################################
2#
3# SEPA Direct Debit module for OpenERP
4# Copyright (C) 2013 Akretion (http://www.akretion.com)
5# @author: Alexis de Lattre <alexis.delattre@akretion.com>
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as
9# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU Affero General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21{
22 'name': 'Account Banking SEPA Direct Debit',
23 'summary': 'Create SEPA files for Direct Debit',
24 'version': '0.1',
25 'license': 'AGPL-3',
26 'author': 'Akretion',
27 'website': 'http://www.akretion.com',
28 'category': 'Banking addons',
29 'depends': ['account_direct_debit', 'account_banking_pain_base'],
30 'external_dependencies': {
31 'python': ['unidecode', 'lxml'],
32 },
33 'data': [
34 'security/original_mandate_required_security.xml',
35 'account_banking_sdd_view.xml',
36 'sdd_mandate_view.xml',
37 'res_partner_bank_view.xml',
38 'account_payment_view.xml',
39 'company_view.xml',
40 'mandate_expire_cron.xml',
41 'account_invoice_view.xml',
42 'wizard/export_sdd_view.xml',
43 'data/payment_type_sdd.xml',
44 'data/mandate_reference_sequence.xml',
45 'security/ir.model.access.csv',
46 ],
47 'description': '''
48Module to export direct debit payment orders in SEPA XML file format.
49
50SEPA PAIN (PAyment INitiation) is the new european standard for Customer-to-Bank payment instructions. This module implements SEPA Direct Debit (SDD), more specifically PAIN versions 008.001.02, 008.001.03 and 008.001.04. It is part of the ISO 20022 standard, available on http://www.iso20022.org.
51
52The Implementation Guidelines for SEPA Direct Debit published by the European Payments Council (http://http://www.europeanpaymentscouncil.eu) use PAIN version 008.001.02. So if you don't know which version your bank supports, you should try version 008.001.02 first.
53
54This module uses the framework provided by the banking addons, cf https://launchpad.net/banking-addons
55
56Please contact Alexis de Lattre from Akretion <alexis.delattre@akretion.com> for any help or question about this module.
57 ''',
58 'active': False,
59 'installable': True,
60}
061
=== added file 'account_banking_sepa_direct_debit/account_banking_sdd.py'
--- account_banking_sepa_direct_debit/account_banking_sdd.py 1970-01-01 00:00:00 +0000
+++ account_banking_sepa_direct_debit/account_banking_sdd.py 2014-01-13 12:42:46 +0000
@@ -0,0 +1,424 @@
1##############################################################################
2#
3# SEPA Direct Debit module for OpenERP
4# Copyright (C) 2013 Akretion (http://www.akretion.com)
5# @author: Alexis de Lattre <alexis.delattre@akretion.com>
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as
9# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU Affero General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21
22from openerp.osv import orm, fields
23from openerp.tools.translate import _
24from openerp.addons.decimal_precision import decimal_precision as dp
25from unidecode import unidecode
26from datetime import datetime
27from dateutil.relativedelta import relativedelta
28import logging
29
30NUMBER_OF_UNUSED_MONTHS_BEFORE_EXPIRY = 36
31
32logger = logging.getLogger(__name__)
33
34
35class banking_export_sdd(orm.Model):
36 '''SEPA Direct Debit export'''
37 _name = 'banking.export.sdd'
38 _description = __doc__
39 _rec_name = 'filename'
40
41 def _generate_filename(self, cr, uid, ids, name, arg, context=None):
42 res = {}
43 for sepa_file in self.browse(cr, uid, ids, context=context):
44 ref = sepa_file.payment_order_ids[0].reference
45 if ref:
46 label = unidecode(ref.replace('/', '-'))
47 else:
48 label = 'error'
49 res[sepa_file.id] = 'sdd_%s.xml' % label
50 return res
51
52 _columns = {
53 'payment_order_ids': fields.many2many(
54 'payment.order',
55 'account_payment_order_sdd_rel',
56 'banking_export_sepa_id', 'account_order_id',
57 'Payment Orders',
58 readonly=True),
59 'nb_transactions': fields.integer(
60 'Number of Transactions', readonly=True),
61 'total_amount': fields.float(
62 'Total Amount', digits_compute=dp.get_precision('Account'),
63 readonly=True),
64 'batch_booking': fields.boolean(
65 'Batch Booking', readonly=True,
66 help="If true, the bank statement will display only one credit "
67 "line for all the direct debits of the SEPA file ; if false, "
68 "the bank statement will display one credit line per direct "
69 "debit of the SEPA file."),
70 'charge_bearer': fields.selection([
71 ('SLEV', 'Following Service Level'),
72 ('SHAR', 'Shared'),
73 ('CRED', 'Borne by Creditor'),
74 ('DEBT', 'Borne by Debtor'),
75 ], 'Charge Bearer', readonly=True,
76 help="Following service level : transaction charges are to be "
77 "applied following the rules agreed in the service level and/or "
78 "scheme (SEPA Core messages must use this). Shared : "
79 "transaction charges on the creditor side are to be borne by "
80 "the creditor, transaction charges on the debtor side are to be "
81 "borne by the debtor. Borne by creditor : all transaction "
82 "charges are to be borne by the creditor. Borne by debtor : "
83 "all transaction charges are to be borne by the debtor."),
84 'create_date': fields.datetime('Generation Date', readonly=True),
85 'file': fields.binary('SEPA File', readonly=True),
86 'filename': fields.function(
87 _generate_filename, type='char', size=256,
88 string='Filename', readonly=True, store=True),
89 'state': fields.selection([
90 ('draft', 'Draft'),
91 ('sent', 'Sent'),
92 ('done', 'Reconciled'),
93 ], 'State', readonly=True),
94 }
95
96 _defaults = {
97 'state': 'draft',
98 }
99
100
101class sdd_mandate(orm.Model):
102 '''SEPA Direct Debit Mandate'''
103 _name = 'sdd.mandate'
104 _description = __doc__
105 _rec_name = 'unique_mandate_reference'
106 _inherit = ['mail.thread']
107 _order = 'signature_date desc'
108 _track = {
109 'state': {
110 'account_banking_sepa_direct_debit.mandate_valid':
111 lambda self, cr, uid, obj, ctx=None:
112 obj['state'] == 'valid',
113 'account_banking_sepa_direct_debit.mandate_expired':
114 lambda self, cr, uid, obj, ctx=None:
115 obj['state'] == 'expired',
116 'account_banking_sepa_direct_debit.mandate_cancel':
117 lambda self, cr, uid, obj, ctx=None:
118 obj['state'] == 'cancel',
119 },
120 'recurrent_sequence_type': {
121 'account_banking_sepa_direct_debit.recurrent_sequence_type_first':
122 lambda self, cr, uid, obj, ctx=None:
123 obj['recurrent_sequence_type'] == 'first',
124 'account_banking_sepa_direct_debit.'
125 'recurrent_sequence_type_recurring':
126 lambda self, cr, uid, obj, ctx=None:
127 obj['recurrent_sequence_type'] == 'recurring',
128 'account_banking_sepa_direct_debit.recurrent_sequence_type_final':
129 lambda self, cr, uid, obj, ctx=None:
130 obj['recurrent_sequence_type'] == 'final',
131 }
132 }
133
134 _columns = {
135 'partner_bank_id': fields.many2one(
136 'res.partner.bank', 'Bank Account', track_visibility='onchange'),
137 'partner_id': fields.related(
138 'partner_bank_id', 'partner_id', type='many2one',
139 relation='res.partner', string='Partner', readonly=True),
140 'company_id': fields.many2one('res.company', 'Company', required=True),
141 'unique_mandate_reference': fields.char(
142 'Unique Mandate Reference', size=35, readonly=True,
143 track_visibility='always'),
144 'type': fields.selection([
145 ('recurrent', 'Recurrent'),
146 ('oneoff', 'One-Off'),
147 ], 'Type of Mandate', required=True, track_visibility='always'),
148 'recurrent_sequence_type': fields.selection([
149 ('first', 'First'),
150 ('recurring', 'Recurring'),
151 ('final', 'Final'),
152 ], 'Sequence Type for Next Debit', track_visibility='onchange',
153 help="This field is only used for Recurrent mandates, not for "
154 "One-Off mandates."),
155 'signature_date': fields.date(
156 'Date of Signature of the Mandate', track_visibility='onchange'),
157 'scan': fields.binary('Scan of the Mandate'),
158 'last_debit_date': fields.date(
159 'Date of the Last Debit', readonly=True),
160 'state': fields.selection([
161 ('draft', 'Draft'),
162 ('valid', 'Valid'),
163 ('expired', 'Expired'),
164 ('cancel', 'Cancelled'),
165 ], 'Status',
166 help="Only valid mandates can be used in a payment line. A "
167 "cancelled mandate is a mandate that has been cancelled by "
168 "the customer. A one-off mandate expires after its first use. "
169 "A recurrent mandate expires after it's final use or if it "
170 "hasn't been used for 36 months."),
171 'payment_line_ids': fields.one2many(
172 'payment.line', 'sdd_mandate_id', "Related Payment Lines"),
173 'sepa_migrated': fields.boolean(
174 'Migrated to SEPA', track_visibility='onchange',
175 help="If this field is not active, the mandate section of the "
176 "next direct debit file that include this mandate will contain "
177 "the 'Original Mandate Identification' and the 'Original "
178 "Creditor Scheme Identification'. This is required in a few "
179 "countries (Belgium for instance), but not in all countries. "
180 "If this is not required in your country, you should keep this "
181 "field always active."),
182 'original_mandate_identification': fields.char(
183 'Original Mandate Identification', size=35,
184 track_visibility='onchange',
185 help="When the field 'Migrated to SEPA' is not active, this "
186 "field will be used as the Original Mandate Identification in "
187 "the Direct Debit file."),
188 }
189
190 _defaults = {
191 'company_id': lambda self, cr, uid, context:
192 self.pool['res.company']._company_default_get(
193 cr, uid, 'sdd.mandate', context=context),
194 'unique_mandate_reference': lambda self, cr, uid, ctx:
195 self.pool['ir.sequence'].get(cr, uid, 'sdd.mandate.reference'),
196 'state': 'draft',
197 'sepa_migrated': True,
198 }
199
200 _sql_constraints = [(
201 'mandate_ref_company_uniq',
202 'unique(unique_mandate_reference, company_id)',
203 'A Mandate with the same reference already exists for this company !'
204 )]
205
206 def _check_sdd_mandate(self, cr, uid, ids):
207 for mandate in self.browse(cr, uid, ids):
208 if (mandate.signature_date and
209 mandate.signature_date >
210 datetime.today().strftime('%Y-%m-%d')):
211 raise orm.except_orm(
212 _('Error:'),
213 _("The date of signature of mandate '%s' is in the "
214 "future !")
215 % mandate.unique_mandate_reference)
216 if mandate.state == 'valid' and not mandate.signature_date:
217 raise orm.except_orm(
218 _('Error:'),
219 _("Cannot validate the mandate '%s' without a date of "
220 "signature.")
221 % mandate.unique_mandate_reference)
222 if mandate.state == 'valid' and not mandate.partner_bank_id:
223 raise orm.except_orm(
224 _('Error:'),
225 _("Cannot validate the mandate '%s' because it is not "
226 "attached to a bank account.")
227 % mandate.unique_mandate_reference)
228
229 if (mandate.signature_date and mandate.last_debit_date and
230 mandate.signature_date > mandate.last_debit_date):
231 raise orm.except_orm(
232 _('Error:'),
233 _("The mandate '%s' can't have a date of last debit "
234 "before the date of signature.")
235 % mandate.unique_mandate_reference)
236 if (mandate.type == 'recurrent'
237 and not mandate.recurrent_sequence_type):
238 raise orm.except_orm(
239 _('Error:'),
240 _("The recurrent mandate '%s' must have a sequence type.")
241 % mandate.unique_mandate_reference)
242 if (mandate.type == 'recurrent' and not mandate.sepa_migrated
243 and mandate.recurrent_sequence_type != 'first'):
244 raise orm.except_orm(
245 _('Error:'),
246 _("The recurrent mandate '%s' which is not marked as "
247 "'Migrated to SEPA' must have its recurrent sequence "
248 "type set to 'First'.")
249 % mandate.unique_mandate_reference)
250 if (mandate.type == 'recurrent' and not mandate.sepa_migrated
251 and not mandate.original_mandate_identification):
252 raise orm.except_orm(
253 _('Error:'),
254 _("You must set the 'Original Mandate Identification' "
255 "on the recurrent mandate '%s' which is not marked "
256 "as 'Migrated to SEPA'.")
257 % mandate.unique_mandate_reference)
258 return True
259
260 _constraints = [
261 (_check_sdd_mandate, "Error msg in raise", [
262 'last_debit_date', 'signature_date', 'state', 'partner_bank_id',
263 'type', 'recurrent_sequence_type', 'sepa_migrated',
264 'original_mandate_identification',
265 ]),
266 ]
267
268 def mandate_type_change(self, cr, uid, ids, type):
269 if type == 'recurrent':
270 recurrent_sequence_type = 'first'
271 else:
272 recurrent_sequence_type = False
273 res = {'value': {'recurrent_sequence_type': recurrent_sequence_type}}
274 return res
275
276 def mandate_partner_bank_change(
277 self, cr, uid, ids, partner_bank_id, type, recurrent_sequence_type,
278 last_debit_date, state):
279 res = {'value': {}}
280 if partner_bank_id:
281 partner_bank_read = self.pool['res.partner.bank'].read(
282 cr, uid, partner_bank_id, ['partner_id'])['partner_id']
283 if partner_bank_read:
284 res['value']['partner_id'] = partner_bank_read[0]
285 if (state == 'valid' and partner_bank_id
286 and type == 'recurrent'
287 and recurrent_sequence_type != 'first'):
288 res['value']['recurrent_sequence_type'] = 'first'
289 res['warning'] = {
290 'title': _('Mandate update'),
291 'message': _(
292 "As you changed the bank account attached to this "
293 "mandate, the 'Sequence Type' has been set back to "
294 "'First'."),
295 }
296 return res
297
298 def validate(self, cr, uid, ids, context=None):
299 to_validate_ids = []
300 for mandate in self.browse(cr, uid, ids, context=context):
301 assert mandate.state == 'draft', 'Mandate should be in draft state'
302 to_validate_ids.append(mandate.id)
303 self.write(
304 cr, uid, to_validate_ids, {'state': 'valid'}, context=context)
305 return True
306
307 def cancel(self, cr, uid, ids, context=None):
308 to_cancel_ids = []
309 for mandate in self.browse(cr, uid, ids, context=context):
310 assert mandate.state in ('draft', 'valid'),\
311 'Mandate should be in draft or valid state'
312 to_cancel_ids.append(mandate.id)
313 self.write(
314 cr, uid, to_cancel_ids, {'state': 'cancel'}, context=context)
315 return True
316
317 def _sdd_mandate_set_state_to_expired(self, cr, uid, context=None):
318 logger.info('Searching for SDD Mandates that must be set to Expired')
319 expire_limit_date = datetime.today() + \
320 relativedelta(months=-NUMBER_OF_UNUSED_MONTHS_BEFORE_EXPIRY)
321 expire_limit_date_str = expire_limit_date.strftime('%Y-%m-%d')
322 expired_mandate_ids = self.search(cr, uid, [
323 '|',
324 ('last_debit_date', '=', False),
325 ('last_debit_date', '<=', expire_limit_date_str),
326 ('state', '=', 'valid'),
327 ('signature_date', '<=', expire_limit_date_str),
328 ], context=context)
329 if expired_mandate_ids:
330 self.write(
331 cr, uid, expired_mandate_ids, {'state': 'expired'},
332 context=context)
333 logger.info(
334 'The following SDD Mandate IDs has been set to expired: %s'
335 % expired_mandate_ids)
336 else:
337 logger.info('0 SDD Mandates must be set to Expired')
338 return True
339
340
341class res_partner_bank(orm.Model):
342 _inherit = 'res.partner.bank'
343
344 _columns = {
345 'sdd_mandate_ids': fields.one2many(
346 'sdd.mandate', 'partner_bank_id', 'SEPA Direct Debit Mandates'),
347 }
348
349
350class payment_line(orm.Model):
351 _inherit = 'payment.line'
352
353 _columns = {
354 'sdd_mandate_id': fields.many2one(
355 'sdd.mandate', 'SEPA Direct Debit Mandate',
356 domain=[('state', '=', 'valid')]),
357 }
358
359 def create(self, cr, uid, vals, context=None):
360 '''If the customer invoice has a mandate, take it
361 otherwise, take the first valid mandate of the bank account'''
362 if context is None:
363 context = {}
364 if not vals:
365 vals = {}
366 partner_bank_id = vals.get('bank_id')
367 move_line_id = vals.get('move_line_id')
368 if (context.get('default_payment_order_type') == 'debit'
369 and 'sdd_mandate_id' not in vals):
370 if move_line_id:
371 line = self.pool['account.move.line'].browse(
372 cr, uid, move_line_id, context=context)
373 if (line.invoice and line.invoice.type == 'out_invoice'
374 and line.invoice.sdd_mandate_id):
375 vals.update({
376 'sdd_mandate_id': line.invoice.sdd_mandate_id.id,
377 'bank_id':
378 line.invoice.sdd_mandate_id.partner_bank_id.id,
379 })
380 if partner_bank_id and 'sdd_mandate_id' not in vals:
381 mandate_ids = self.pool['sdd.mandate'].search(cr, uid, [
382 ('partner_bank_id', '=', partner_bank_id),
383 ('state', '=', 'valid'),
384 ], context=context)
385 if mandate_ids:
386 vals['sdd_mandate_id'] = mandate_ids[0]
387 return super(payment_line, self).create(cr, uid, vals, context=context)
388
389 def _check_mandate_bank_link(self, cr, uid, ids):
390 for payline in self.browse(cr, uid, ids):
391 if (payline.sdd_mandate_id and payline.bank_id
392 and payline.sdd_mandate_id.partner_bank_id.id !=
393 payline.bank_id.id):
394 raise orm.except_orm(
395 _('Error:'),
396 _("The payment line with reference '%s' has the bank "
397 "account '%s' which is not attached to the mandate "
398 "'%s' (this mandate is attached to the bank account "
399 "'%s').") % (
400 payline.name,
401 self.pool['res.partner.bank'].name_get(
402 cr, uid, [payline.bank_id.id])[0][1],
403 payline.sdd_mandate_id.unique_mandate_reference,
404 self.pool['res.partner.bank'].name_get(
405 cr, uid,
406 [payline.sdd_mandate_id.partner_bank_id.id])[0][1],
407 ))
408 return True
409
410 _constraints = [
411 (_check_mandate_bank_link, 'Error msg in raise',
412 ['sdd_mandate_id', 'bank_id']),
413 ]
414
415
416class account_invoice(orm.Model):
417 _inherit = 'account.invoice'
418
419 _columns = {
420 'sdd_mandate_id': fields.many2one(
421 'sdd.mandate', 'SEPA Direct Debit Mandate',
422 domain=[('state', '=', 'valid')], readonly=True,
423 states={'draft': [('readonly', False)]})
424 }
0425
=== added file 'account_banking_sepa_direct_debit/account_banking_sdd_view.xml'
--- account_banking_sepa_direct_debit/account_banking_sdd_view.xml 1970-01-01 00:00:00 +0000
+++ account_banking_sepa_direct_debit/account_banking_sdd_view.xml 2014-01-13 12:42:46 +0000
@@ -0,0 +1,80 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!--
3 Copyright (C) 2013 Akretion (http://www.akretion.com)
4 @author: Alexis de Lattre <alexis.delattre@akretion.com>
5 The licence is in the file __openerp__.py
6-->
7<openerp>
8<data>
9
10<record id="view_banking_export_sdd_form" model="ir.ui.view">
11 <field name="name">account.banking.export.sdd.form</field>
12 <field name="model">banking.export.sdd</field>
13 <field name="arch" type="xml">
14 <form string="SEPA Direct Debit">
15 <notebook>
16 <page string="General Information">
17 <field name="total_amount" />
18 <field name="nb_transactions" />
19 <field name="batch_booking" />
20 <field name="charge_bearer"/>
21 <field name="create_date" />
22 <newline />
23 <field name="file" filename="filename"/>
24 <field name="filename" invisible="True"/>
25 </page>
26 <page string="Payment Orders">
27 <field name="payment_order_ids" colspan="4" nolabel="1">
28 <tree colors="blue:state in ('draft');gray:state in ('cancel','done');black:state in ('open')" string="Payment Orders">
29 <field name="reference"/>
30 <field name="date_created"/>
31 <field name="date_done"/>
32 <field name="total"/>
33 <field name="state"/>
34 </tree>
35 </field>
36 </page>
37 </notebook>
38 </form>
39 </field>
40</record>
41
42
43<record id="view_banking_export_sdd_tree" model="ir.ui.view">
44 <field name="name">account.banking.export.sdd.tree</field>
45 <field name="model">banking.export.sdd</field>
46 <field name="arch" type="xml">
47 <tree string="SEPA Direct Debit">
48 <field name="filename"/>
49 <field name="create_date"/>
50 <field name="nb_transactions"/>
51 </tree>
52 </field>
53</record>
54
55
56<record id="action_account_banking_sdd" model="ir.actions.act_window">
57 <field name="name">SEPA Direct Debit Files</field>
58 <field name="res_model">banking.export.sdd</field>
59 <field name="view_type">form</field>
60 <field name="view_mode">tree,form</field>
61</record>
62
63
64<menuitem id="menu_account_banking_sdd"
65 parent="account_payment.menu_main_payment"
66 action="action_account_banking_sdd"
67 sequence="20"
68 />
69
70<act_window id="act_banking_export_sdd_payment_order"
71 name="Generated SEPA Direct Debit Files"
72 domain="[('payment_order_ids', '=', active_id)]"
73 res_model="banking.export.sdd"
74 src_model="payment.order"
75 view_type="form"
76 view_mode="tree,form"
77/>
78
79</data>
80</openerp>
081
=== added file 'account_banking_sepa_direct_debit/account_invoice_view.xml'
--- account_banking_sepa_direct_debit/account_invoice_view.xml 1970-01-01 00:00:00 +0000
+++ account_banking_sepa_direct_debit/account_invoice_view.xml 2014-01-13 12:42:46 +0000
@@ -0,0 +1,22 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!--
3 Copyright (C) 2013 Akretion (http://www.akretion.com)
4 @author: Alexis de Lattre <alexis.delattre@akretion.com>
5 The licence is in the file __openerp__.py
6-->
7<openerp>
8<data>
9
10<record id="invoice_form" model="ir.ui.view">
11 <field name="name">add.sdd.mandate.on.customer.invoice.form</field>
12 <field name="model">account.invoice</field>
13 <field name="inherit_id" ref="account.invoice_form"/>
14 <field name="arch" type="xml">
15 <field name="partner_bank_id" position="after">
16 <field name="sdd_mandate_id" domain="[('partner_id', '=', partner_id), ('state', '=', 'valid')]" attrs="{'invisible': [('type', '=', 'out_refund')]}"/>
17 </field>
18 </field>
19</record>
20
21</data>
22</openerp>
023
=== added file 'account_banking_sepa_direct_debit/account_payment_view.xml'
--- account_banking_sepa_direct_debit/account_payment_view.xml 1970-01-01 00:00:00 +0000
+++ account_banking_sepa_direct_debit/account_payment_view.xml 2014-01-13 12:42:46 +0000
@@ -0,0 +1,26 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!--
3 Copyright (C) 2013 Akretion (http://www.akretion.com)
4 @author: Alexis de Lattre <alexis.delattre@akretion.com>
5 The licence is in the file __openerp__.py
6-->
7<openerp>
8<data>
9
10<record id="sdd_view_payment_order_form" model="ir.ui.view">
11 <field name="name">sdd.payment.order.form</field>
12 <field name="model">payment.order</field>
13 <field name="inherit_id" ref="account_payment.view_payment_order_form"/>
14 <field name="arch" type="xml">
15 <xpath expr="//field[@name='line_ids']/form/notebook/page/group/field[@name='bank_id']" position="after">
16 <field name="sdd_mandate_id" domain="[('partner_bank_id', '=', bank_id), ('state', '=', 'valid')]" invisible="context.get('default_payment_order_type')!='debit'" context="{'default_partner_bank_id': bank_id}"/>
17 <newline />
18 </xpath>
19 <xpath expr="//field[@name='line_ids']/tree/field[@name='bank_id']" position="after">
20 <field name="sdd_mandate_id" string="SDD Mandate" invisible="context.get('default_payment_order_type')!='debit'"/>
21 </xpath>
22 </field>
23</record>
24
25</data>
26</openerp>
027
=== added file 'account_banking_sepa_direct_debit/company.py'
--- account_banking_sepa_direct_debit/company.py 1970-01-01 00:00:00 +0000
+++ account_banking_sepa_direct_debit/company.py 2014-01-13 12:42:46 +0000
@@ -0,0 +1,89 @@
1##############################################################################
2#
3# SEPA Direct Debit module for OpenERP
4# Copyright (C) 2013 Akretion (http://www.akretion.com)
5# @author: Alexis de Lattre <alexis.delattre@akretion.com>
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as
9# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU Affero General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21
22from openerp.osv import orm, fields
23import logging
24
25logger = logging.getLogger(__name__)
26
27
28class res_company(orm.Model):
29 _inherit = 'res.company'
30
31 _columns = {
32 'sepa_creditor_identifier': fields.char(
33 'SEPA Creditor Identifier', size=35,
34 help="Enter the Creditor Identifier that has been attributed "
35 "to your company to make SEPA Direct Debits. This identifier "
36 "is composed of :\n- your country ISO code (2 letters)\n- a "
37 "2-digits checkum\n- a 3-letters business code\n- a "
38 "country-specific identifier"),
39 'original_creditor_identifier': fields.char(
40 'Original Creditor Identifier', size=70),
41 }
42
43 def is_sepa_creditor_identifier_valid(
44 self, cr, uid, sepa_creditor_identifier, context=None):
45 """Check if SEPA Creditor Identifier is valid
46 @param sepa_creditor_identifier: SEPA Creditor Identifier as str
47 or unicode
48 @return: True if valid, False otherwise
49 """
50 if not isinstance(sepa_creditor_identifier, (str, unicode)):
51 return False
52 try:
53 sci_str = str(sepa_creditor_identifier)
54 except:
55 logger.warning(
56 "SEPA Creditor ID should contain only ASCII caracters.")
57 return False
58 sci = sci_str.lower()
59 if len(sci) < 9:
60 return False
61 before_replacement = sci[7:] + sci[0:2] + '00'
62 logger.debug(
63 "SEPA ID check before_replacement = %s" % before_replacement)
64 after_replacement = ''
65 for char in before_replacement:
66 if char.isalpha():
67 after_replacement += str(ord(char)-87)
68 else:
69 after_replacement += char
70 logger.debug(
71 "SEPA ID check after_replacement = %s" % after_replacement)
72 if int(sci[2:4]) == (98 - (int(after_replacement) % 97)):
73 return True
74 else:
75 return False
76
77 def _check_sepa_creditor_identifier(self, cr, uid, ids):
78 for company in self.browse(cr, uid, ids):
79 if company.sepa_creditor_identifier:
80 if not self.is_sepa_creditor_identifier_valid(
81 cr, uid, company.sepa_creditor_identifier):
82 return False
83 return True
84
85 _constraints = [
86 (_check_sepa_creditor_identifier,
87 "Invalid SEPA Creditor Identifier.",
88 ['sepa_creditor_identifier']),
89 ]
090
=== added file 'account_banking_sepa_direct_debit/company_view.xml'
--- account_banking_sepa_direct_debit/company_view.xml 1970-01-01 00:00:00 +0000
+++ account_banking_sepa_direct_debit/company_view.xml 2014-01-13 12:42:46 +0000
@@ -0,0 +1,23 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!--
3 Copyright (C) 2013 Akretion (http://www.akretion.com)
4 @author: Alexis de Lattre <alexis.delattre@akretion.com>
5 The licence is in the file __openerp__.py
6-->
7<openerp>
8<data>
9
10<record id="sdd_res_company_form" model="ir.ui.view">
11 <field name="name">sepa_direct_debit.res.company.form</field>
12 <field name="model">res.company</field>
13 <field name="inherit_id" ref="account_banking_pain_base.view_company_form"/>
14 <field name="arch" type="xml">
15 <group name="pain" position="inside">
16 <field name="sepa_creditor_identifier"/>
17 <field name="original_creditor_identifier" groups="account_banking_sepa_direct_debit.group_original_mandate_required"/>
18 </group>
19 </field>
20</record>
21
22</data>
23</openerp>
024
=== added directory 'account_banking_sepa_direct_debit/data'
=== added file 'account_banking_sepa_direct_debit/data/mandate_reference_sequence.xml'
--- account_banking_sepa_direct_debit/data/mandate_reference_sequence.xml 1970-01-01 00:00:00 +0000
+++ account_banking_sepa_direct_debit/data/mandate_reference_sequence.xml 2014-01-13 12:42:46 +0000
@@ -0,0 +1,21 @@
1<?xml version="1.0" encoding="utf-8"?>
2<openerp>
3<data noupdate="1">
4
5
6<record id="sdd_mandate_seq_type" model="ir.sequence.type">
7 <field name="name">SDD Mandate Reference</field>
8 <field name="code">sdd.mandate.reference</field>
9</record>
10
11<record id="sdd_mandate_seq" model="ir.sequence">
12 <field name="name">SDD Mandate Reference</field>
13 <field name="code">sdd.mandate.reference</field>
14 <field name="prefix">RUM</field>
15 <field name="padding" eval="7"/>
16 <!-- remember that max size for the mandate ref is 35 -->
17</record>
18
19
20</data>
21</openerp>
022
=== added file 'account_banking_sepa_direct_debit/data/pain.008.001.02.xsd'
--- account_banking_sepa_direct_debit/data/pain.008.001.02.xsd 1970-01-01 00:00:00 +0000
+++ account_banking_sepa_direct_debit/data/pain.008.001.02.xsd 2014-01-13 12:42:46 +0000
@@ -0,0 +1,879 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<!--Generated by SWIFTStandards Workstation (build:R6.1.0.2) on 2009 Jan 08 17:30:53-->
3<xs:schema xmlns="urn:iso:std:iso:20022:tech:xsd:pain.008.001.02" xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="urn:iso:std:iso:20022:tech:xsd:pain.008.001.02">
4 <xs:element name="Document" type="Document"/>
5 <xs:complexType name="AccountIdentification4Choice">
6 <xs:sequence>
7 <xs:choice>
8 <xs:element name="IBAN" type="IBAN2007Identifier"/>
9 <xs:element name="Othr" type="GenericAccountIdentification1"/>
10 </xs:choice>
11 </xs:sequence>
12 </xs:complexType>
13 <xs:complexType name="AccountSchemeName1Choice">
14 <xs:sequence>
15 <xs:choice>
16 <xs:element name="Cd" type="ExternalAccountIdentification1Code"/>
17 <xs:element name="Prtry" type="Max35Text"/>
18 </xs:choice>
19 </xs:sequence>
20 </xs:complexType>
21 <xs:simpleType name="ActiveOrHistoricCurrencyAndAmount_SimpleType">
22 <xs:restriction base="xs:decimal">
23 <xs:minInclusive value="0"/>
24 <xs:fractionDigits value="5"/>
25 <xs:totalDigits value="18"/>
26 </xs:restriction>
27 </xs:simpleType>
28 <xs:complexType name="ActiveOrHistoricCurrencyAndAmount">
29 <xs:simpleContent>
30 <xs:extension base="ActiveOrHistoricCurrencyAndAmount_SimpleType">
31 <xs:attribute name="Ccy" type="ActiveOrHistoricCurrencyCode" use="required"/>
32 </xs:extension>
33 </xs:simpleContent>
34 </xs:complexType>
35 <xs:simpleType name="ActiveOrHistoricCurrencyCode">
36 <xs:restriction base="xs:string">
37 <xs:pattern value="[A-Z]{3,3}"/>
38 </xs:restriction>
39 </xs:simpleType>
40 <xs:simpleType name="AddressType2Code">
41 <xs:restriction base="xs:string">
42 <xs:enumeration value="ADDR"/>
43 <xs:enumeration value="PBOX"/>
44 <xs:enumeration value="HOME"/>
45 <xs:enumeration value="BIZZ"/>
46 <xs:enumeration value="MLTO"/>
47 <xs:enumeration value="DLVY"/>
48 </xs:restriction>
49 </xs:simpleType>
50 <xs:complexType name="AmendmentInformationDetails6">
51 <xs:sequence>
52 <xs:element maxOccurs="1" minOccurs="0" name="OrgnlMndtId" type="Max35Text"/>
53 <xs:element maxOccurs="1" minOccurs="0" name="OrgnlCdtrSchmeId" type="PartyIdentification32"/>
54 <xs:element maxOccurs="1" minOccurs="0" name="OrgnlCdtrAgt" type="BranchAndFinancialInstitutionIdentification4"/>
55 <xs:element maxOccurs="1" minOccurs="0" name="OrgnlCdtrAgtAcct" type="CashAccount16"/>
56 <xs:element maxOccurs="1" minOccurs="0" name="OrgnlDbtr" type="PartyIdentification32"/>
57 <xs:element maxOccurs="1" minOccurs="0" name="OrgnlDbtrAcct" type="CashAccount16"/>
58 <xs:element maxOccurs="1" minOccurs="0" name="OrgnlDbtrAgt" type="BranchAndFinancialInstitutionIdentification4"/>
59 <xs:element maxOccurs="1" minOccurs="0" name="OrgnlDbtrAgtAcct" type="CashAccount16"/>
60 <xs:element maxOccurs="1" minOccurs="0" name="OrgnlFnlColltnDt" type="ISODate"/>
61 <xs:element maxOccurs="1" minOccurs="0" name="OrgnlFrqcy" type="Frequency1Code"/>
62 </xs:sequence>
63 </xs:complexType>
64 <xs:simpleType name="AnyBICIdentifier">
65 <xs:restriction base="xs:string">
66 <xs:pattern value="[A-Z]{6,6}[A-Z2-9][A-NP-Z0-9]([A-Z0-9]{3,3}){0,1}"/>
67 </xs:restriction>
68 </xs:simpleType>
69 <xs:complexType name="Authorisation1Choice">
70 <xs:sequence>
71 <xs:choice>
72 <xs:element name="Cd" type="Authorisation1Code"/>
73 <xs:element name="Prtry" type="Max128Text"/>
74 </xs:choice>
75 </xs:sequence>
76 </xs:complexType>
77 <xs:simpleType name="Authorisation1Code">
78 <xs:restriction base="xs:string">
79 <xs:enumeration value="AUTH"/>
80 <xs:enumeration value="FDET"/>
81 <xs:enumeration value="FSUM"/>
82 <xs:enumeration value="ILEV"/>
83 </xs:restriction>
84 </xs:simpleType>
85 <xs:simpleType name="BICIdentifier">
86 <xs:restriction base="xs:string">
87 <xs:pattern value="[A-Z]{6,6}[A-Z2-9][A-NP-Z0-9]([A-Z0-9]{3,3}){0,1}"/>
88 </xs:restriction>
89 </xs:simpleType>
90 <xs:simpleType name="BatchBookingIndicator">
91 <xs:restriction base="xs:boolean"/>
92 </xs:simpleType>
93 <xs:complexType name="BranchAndFinancialInstitutionIdentification4">
94 <xs:sequence>
95 <xs:element name="FinInstnId" type="FinancialInstitutionIdentification7"/>
96 <xs:element maxOccurs="1" minOccurs="0" name="BrnchId" type="BranchData2"/>
97 </xs:sequence>
98 </xs:complexType>
99 <xs:complexType name="BranchData2">
100 <xs:sequence>
101 <xs:element maxOccurs="1" minOccurs="0" name="Id" type="Max35Text"/>
102 <xs:element maxOccurs="1" minOccurs="0" name="Nm" type="Max140Text"/>
103 <xs:element maxOccurs="1" minOccurs="0" name="PstlAdr" type="PostalAddress6"/>
104 </xs:sequence>
105 </xs:complexType>
106 <xs:complexType name="CashAccount16">
107 <xs:sequence>
108 <xs:element name="Id" type="AccountIdentification4Choice"/>
109 <xs:element maxOccurs="1" minOccurs="0" name="Tp" type="CashAccountType2"/>
110 <xs:element maxOccurs="1" minOccurs="0" name="Ccy" type="ActiveOrHistoricCurrencyCode"/>
111 <xs:element maxOccurs="1" minOccurs="0" name="Nm" type="Max70Text"/>
112 </xs:sequence>
113 </xs:complexType>
114 <xs:complexType name="CashAccountType2">
115 <xs:sequence>
116 <xs:choice>
117 <xs:element name="Cd" type="CashAccountType4Code"/>
118 <xs:element name="Prtry" type="Max35Text"/>
119 </xs:choice>
120 </xs:sequence>
121 </xs:complexType>
122 <xs:simpleType name="CashAccountType4Code">
123 <xs:restriction base="xs:string">
124 <xs:enumeration value="CASH"/>
125 <xs:enumeration value="CHAR"/>
126 <xs:enumeration value="COMM"/>
127 <xs:enumeration value="TAXE"/>
128 <xs:enumeration value="CISH"/>
129 <xs:enumeration value="TRAS"/>
130 <xs:enumeration value="SACC"/>
131 <xs:enumeration value="CACC"/>
132 <xs:enumeration value="SVGS"/>
133 <xs:enumeration value="ONDP"/>
134 <xs:enumeration value="MGLD"/>
135 <xs:enumeration value="NREX"/>
136 <xs:enumeration value="MOMA"/>
137 <xs:enumeration value="LOAN"/>
138 <xs:enumeration value="SLRY"/>
139 <xs:enumeration value="ODFT"/>
140 </xs:restriction>
141 </xs:simpleType>
142 <xs:complexType name="CategoryPurpose1Choice">
143 <xs:sequence>
144 <xs:choice>
145 <xs:element name="Cd" type="ExternalCategoryPurpose1Code"/>
146 <xs:element name="Prtry" type="Max35Text"/>
147 </xs:choice>
148 </xs:sequence>
149 </xs:complexType>
150 <xs:simpleType name="ChargeBearerType1Code">
151 <xs:restriction base="xs:string">
152 <xs:enumeration value="DEBT"/>
153 <xs:enumeration value="CRED"/>
154 <xs:enumeration value="SHAR"/>
155 <xs:enumeration value="SLEV"/>
156 </xs:restriction>
157 </xs:simpleType>
158 <xs:complexType name="ClearingSystemIdentification2Choice">
159 <xs:sequence>
160 <xs:choice>
161 <xs:element name="Cd" type="ExternalClearingSystemIdentification1Code"/>
162 <xs:element name="Prtry" type="Max35Text"/>
163 </xs:choice>
164 </xs:sequence>
165 </xs:complexType>
166 <xs:complexType name="ClearingSystemMemberIdentification2">
167 <xs:sequence>
168 <xs:element maxOccurs="1" minOccurs="0" name="ClrSysId" type="ClearingSystemIdentification2Choice"/>
169 <xs:element name="MmbId" type="Max35Text"/>
170 </xs:sequence>
171 </xs:complexType>
172 <xs:complexType name="ContactDetails2">
173 <xs:sequence>
174 <xs:element maxOccurs="1" minOccurs="0" name="NmPrfx" type="NamePrefix1Code"/>
175 <xs:element maxOccurs="1" minOccurs="0" name="Nm" type="Max140Text"/>
176 <xs:element maxOccurs="1" minOccurs="0" name="PhneNb" type="PhoneNumber"/>
177 <xs:element maxOccurs="1" minOccurs="0" name="MobNb" type="PhoneNumber"/>
178 <xs:element maxOccurs="1" minOccurs="0" name="FaxNb" type="PhoneNumber"/>
179 <xs:element maxOccurs="1" minOccurs="0" name="EmailAdr" type="Max2048Text"/>
180 <xs:element maxOccurs="1" minOccurs="0" name="Othr" type="Max35Text"/>
181 </xs:sequence>
182 </xs:complexType>
183 <xs:simpleType name="CountryCode">
184 <xs:restriction base="xs:string">
185 <xs:pattern value="[A-Z]{2,2}"/>
186 </xs:restriction>
187 </xs:simpleType>
188 <xs:simpleType name="CreditDebitCode">
189 <xs:restriction base="xs:string">
190 <xs:enumeration value="CRDT"/>
191 <xs:enumeration value="DBIT"/>
192 </xs:restriction>
193 </xs:simpleType>
194 <xs:complexType name="CreditorReferenceInformation2">
195 <xs:sequence>
196 <xs:element maxOccurs="1" minOccurs="0" name="Tp" type="CreditorReferenceType2"/>
197 <xs:element maxOccurs="1" minOccurs="0" name="Ref" type="Max35Text"/>
198 </xs:sequence>
199 </xs:complexType>
200 <xs:complexType name="CreditorReferenceType1Choice">