[tryton-debian-vcs] tryton-modules-account-payment-sepa branch upstream updated. upstream/3.4.1-1-ged4d9d8
Mathias Behrle
tryton-debian-vcs at alioth.debian.org
Thu Apr 23 15:56:51 UTC 2015
The following commit has been merged in the upstream branch:
https://alioth.debian.org/plugins/scmgit/cgi-bin/gitweb.cgi/?p=tryton/tryton-modules-account-payment-sepa.git;a=commitdiff;h=upstream/3.4.1-1-ged4d9d8
commit ed4d9d8dbb787927ba7face5ee01c8ed05163743
Author: Mathias Behrle <mathiasb at m9s.biz>
Date: Thu Apr 23 16:59:51 2015 +0200
Adding upstream version 3.6.0.
Signed-off-by: Mathias Behrle <mathiasb at m9s.biz>
diff --git a/CHANGELOG b/CHANGELOG
index 39d44f3..7dff6f2 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,10 @@
-Version 3.4.1 - 2015-03-01
+Version 3.6.0 - 2015-04-20
* Bug fixes (see mercurial logs for details)
+* Add support for PyPy
+* Use value date of camt.054 as clearing date
+* Allow to re-generate message of a payment group
+* Use right sequence type in case of previous rejected payments
+* Add pain.001.003.03 and pain.008.003.02 flavors
Version 3.4.0 - 2014-10-20
* Bug fixes (see mercurial logs for details)
diff --git a/INSTALL b/INSTALL
index 1341054..523986f 100644
--- a/INSTALL
+++ b/INSTALL
@@ -6,6 +6,7 @@ Prerequisites
* Python 2.7 or later (http://www.python.org/)
* Genshi (http://genshi.edgewall.org/)
+ * python-dateutil (https://dateutil.readthedocs.org/)
* trytond (http://www.tryton.org/)
* trytond_party (http://www.tryton.org/)
* trytond_account_payment (http://www.tryton.org/)
diff --git a/PKG-INFO b/PKG-INFO
index 5a270b1..4a40a90 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,12 +1,12 @@
Metadata-Version: 1.1
Name: trytond_account_payment_sepa
-Version: 3.4.1
+Version: 3.6.0
Summary: Tryton module for SEPA payment
Home-page: http://www.tryton.org/
Author: Tryton
Author-email: issue_tracker at tryton.org
License: GPL-3
-Download-URL: http://downloads.tryton.org/3.4/
+Download-URL: http://downloads.tryton.org/3.6/
Description: trytond_account_payment_sepa
============================
@@ -64,5 +64,7 @@ Classifier: Natural Language :: Slovenian
Classifier: Natural Language :: Spanish
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: Implementation :: CPython
+Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Topic :: Office/Business
Classifier: Topic :: Office/Business :: Financial :: Accounting
diff --git a/__init__.py b/__init__.py
index 6b0570d..5ac6d23 100644
--- a/__init__.py
+++ b/__init__.py
@@ -1,5 +1,5 @@
-#This file is part of Tryton. The COPYRIGHT file at the top level of
-#this repository contains the full copyright notices and license terms.
+# This file is part of Tryton. The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
from trytond.pool import Pool
from .payment import *
from .party import *
diff --git a/account.py b/account.py
index 5e3f57b..da88600 100644
--- a/account.py
+++ b/account.py
@@ -1,7 +1,8 @@
-#This file is part of Tryton. The COPYRIGHT file at the top level of
-#this repository contains the full copyright notices and license terms.
+# This file is part of Tryton. The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
from trytond.pool import PoolMeta
from trytond.model import fields
+from trytond.pyson import Eval
__all__ = ['Configuration']
__metaclass__ = PoolMeta
@@ -12,4 +13,6 @@ class Configuration:
sepa_mandate_sequence = fields.Property(fields.Many2One('ir.sequence',
'SEPA Mandate Sequence', domain=[
('code', '=', 'account.payment.sepa.mandate'),
+ ('company', 'in', [Eval('context', {}).get('company', -1),
+ None]),
]))
diff --git a/account.xml b/account.xml
index ec6a1d9..035654e 100644
--- a/account.xml
+++ b/account.xml
@@ -8,7 +8,9 @@ this repository contains the full copyright notices and license terms. -->
id="act_move_line_form_domain_receivable_mandate">
<field name="name">Receivable with Mandate</field>
<field name="sequence" eval="25"/>
- <field name="domain">['AND', ['OR', ('debit', '>', 0), ('credit', '<', 0)], ('party.sepa_mandates', '!=', None)]</field>
+ <field name="domain"
+ eval="['AND', ['OR', ('debit', '>', 0), ('credit', '<', 0)], ('party.sepa_mandates', '!=', None)]"
+ pyson="1"/>
<field name="act_window" ref="account_payment.act_move_line_form"/>
</record>
diff --git a/locale/ca_ES.po b/locale/ca_ES.po
index 7964207..d3cf77a 100644
--- a/locale/ca_ES.po
+++ b/locale/ca_ES.po
@@ -233,7 +233,7 @@ msgstr "Cancel·lat"
msgctxt "model:ir.action.act_window.domain,name:act_message_form_domain_done"
msgid "Done"
-msgstr "Realitzat"
+msgstr "Finalitzat"
msgctxt "model:ir.action.act_window.domain,name:act_message_form_domain_draft"
msgid "Draft"
@@ -451,7 +451,7 @@ msgstr "Cancel·lat"
msgctxt "selection:account.payment.sepa.message,state:"
msgid "Done"
-msgstr "Realitzat"
+msgstr "Finalitzat"
msgctxt "selection:account.payment.sepa.message,state:"
msgid "Draft"
@@ -469,6 +469,10 @@ msgctxt "selection:account.payment.sepa.message,type:"
msgid "OUT"
msgstr "Sortida"
+msgctxt "view:account.payment.group:"
+msgid "Generate Message"
+msgstr "Missatge generat"
+
msgctxt "view:account.payment.journal:"
msgid "SEPA"
msgstr "SEPA"
diff --git a/locale/de_DE.po b/locale/de_DE.po
index e3580a5..0688785 100644
--- a/locale/de_DE.po
+++ b/locale/de_DE.po
@@ -466,6 +466,10 @@ msgctxt "selection:account.payment.sepa.message,type:"
msgid "OUT"
msgstr "OUT"
+msgctxt "view:account.payment.group:"
+msgid "Generate Message"
+msgstr "Nachricht erzeugen"
+
msgctxt "view:account.payment.journal:"
msgid "SEPA"
msgstr "SEPA"
@@ -500,7 +504,7 @@ msgstr "Prüfen"
msgctxt "view:account.payment.sepa.message:"
msgid "Cancel"
-msgstr "Annulliert"
+msgstr "Annullieren"
msgctxt "view:account.payment.sepa.message:"
msgid "Do"
diff --git a/locale/es_AR.po b/locale/es_AR.po
index 45c6fd2..28909a8 100644
--- a/locale/es_AR.po
+++ b/locale/es_AR.po
@@ -465,6 +465,10 @@ msgctxt "selection:account.payment.sepa.message,type:"
msgid "OUT"
msgstr "SALIDA"
+msgctxt "view:account.payment.group:"
+msgid "Generate Message"
+msgstr "Generar mensaje"
+
msgctxt "view:account.payment.journal:"
msgid "SEPA"
msgstr "Área Única de Pagos en Euros (SEPA)"
diff --git a/locale/es_CO.po b/locale/es_CO.po
index 20fe05c..e9d49f4 100644
--- a/locale/es_CO.po
+++ b/locale/es_CO.po
@@ -102,7 +102,7 @@ msgstr "Identificación de Solo Lectura"
msgctxt "field:account.payment.sepa.mandate,party:"
msgid "Party"
-msgstr "Terceros"
+msgstr "Tercero"
msgctxt "field:account.payment.sepa.mandate,payments:"
msgid "Payments"
@@ -178,7 +178,7 @@ msgstr "Tipo"
msgctxt "field:account.payment.sepa.message,write_date:"
msgid "Write Date"
-msgstr "Modificado por Usuario"
+msgstr "Fecha de Modificación"
msgctxt "field:account.payment.sepa.message,write_uid:"
msgid "Write User"
@@ -463,6 +463,10 @@ msgctxt "selection:account.payment.sepa.message,type:"
msgid "OUT"
msgstr "SALIDA"
+msgctxt "view:account.payment.group:"
+msgid "Generate Message"
+msgstr "Generar Mensaje"
+
msgctxt "view:account.payment.journal:"
msgid "SEPA"
msgstr "SEPA"
diff --git a/locale/es_EC.po b/locale/es_EC.po
index 0d938ef..d7793e7 100644
--- a/locale/es_EC.po
+++ b/locale/es_EC.po
@@ -465,6 +465,10 @@ msgctxt "selection:account.payment.sepa.message,type:"
msgid "OUT"
msgstr "Salida"
+msgctxt "view:account.payment.group:"
+msgid "Generate Message"
+msgstr "Generar mensaje"
+
msgctxt "view:account.payment.journal:"
msgid "SEPA"
msgstr "SEPA"
diff --git a/locale/es_ES.po b/locale/es_ES.po
index 9313192..ac4e247 100644
--- a/locale/es_ES.po
+++ b/locale/es_ES.po
@@ -233,7 +233,7 @@ msgstr "Cancelado"
msgctxt "model:ir.action.act_window.domain,name:act_message_form_domain_done"
msgid "Done"
-msgstr "Realizado"
+msgstr "Finalizado"
msgctxt "model:ir.action.act_window.domain,name:act_message_form_domain_draft"
msgid "Draft"
@@ -449,7 +449,7 @@ msgstr "Cancelado"
msgctxt "selection:account.payment.sepa.message,state:"
msgid "Done"
-msgstr "Realizado"
+msgstr "Finalizado"
msgctxt "selection:account.payment.sepa.message,state:"
msgid "Draft"
@@ -467,6 +467,10 @@ msgctxt "selection:account.payment.sepa.message,type:"
msgid "OUT"
msgstr "Salida"
+msgctxt "view:account.payment.group:"
+msgid "Generate Message"
+msgstr "Generar mensaje"
+
msgctxt "view:account.payment.journal:"
msgid "SEPA"
msgstr "SEPA"
diff --git a/locale/fr_FR.po b/locale/fr_FR.po
index 6e21205..5499bb9 100644
--- a/locale/fr_FR.po
+++ b/locale/fr_FR.po
@@ -465,6 +465,10 @@ msgctxt "selection:account.payment.sepa.message,type:"
msgid "OUT"
msgstr "Sortant"
+msgctxt "view:account.payment.group:"
+msgid "Generate Message"
+msgstr "Générer le message"
+
msgctxt "view:account.payment.journal:"
msgid "SEPA"
msgstr "SEPA"
diff --git a/locale/sl_SI.po b/locale/sl_SI.po
index 5db1d7f..34c380e 100644
--- a/locale/sl_SI.po
+++ b/locale/sl_SI.po
@@ -18,7 +18,7 @@ msgstr "Soglasja \"%s\" ni možno zbrisati, ker ni v pripravi ali preklicano."
msgctxt "field:account.configuration,sepa_mandate_sequence:"
msgid "SEPA Mandate Sequence"
-msgstr "Štetje soglasij SEPA"
+msgstr "Štetje SEPA soglasij"
msgctxt "field:account.payment,sepa_end_to_end_id:"
msgid "SEPA End To End ID"
@@ -26,7 +26,7 @@ msgstr "ID SEPA End-to-End "
msgctxt "field:account.payment,sepa_instruction_id:"
msgid "SEPA Instruction ID"
-msgstr "ID navodila SEPA"
+msgstr "ID SEPA navodila"
msgctxt "field:account.payment,sepa_mandate:"
msgid "Mandate"
@@ -46,7 +46,7 @@ msgstr "Podrobnosti razloga zavrnitve"
msgctxt "field:account.payment.group,sepa_messages:"
msgid "SEPA Messages"
-msgstr "Sporočila SEPA"
+msgstr "SEPA sporočilo"
msgctxt "field:account.payment.journal,company_party:"
msgid "Company Party"
@@ -126,7 +126,7 @@ msgstr "Stanje"
msgctxt "field:account.payment.sepa.mandate,type:"
msgid "Type"
-msgstr "Vrsta"
+msgstr "Tip"
msgctxt "field:account.payment.sepa.mandate,write_date:"
msgid "Write Date"
@@ -174,7 +174,7 @@ msgstr "Stanje"
msgctxt "field:account.payment.sepa.message,type:"
msgid "Type"
-msgstr "Vrsta"
+msgstr "Tip"
msgctxt "field:account.payment.sepa.message,write_date:"
msgid "Write Date"
@@ -186,27 +186,27 @@ msgstr "Zapisal"
msgctxt "field:party.party,sepa_creditor_identifier:"
msgid "SEPA Creditor Identifier"
-msgstr "Identifikacija upnika SEPA"
+msgstr "Identifikacija SEPA upnika"
msgctxt "field:party.party,sepa_creditor_identifier_used:"
msgid "SEPA Creditor Identifier Used"
-msgstr "Uporabljena Identifikacija upnika SEPA"
+msgstr "Uporabljena Identifikacija SEPA upnika"
msgctxt "field:party.party,sepa_mandates:"
msgid "SEPA Mandates"
-msgstr "Soglasja SEPA"
+msgstr "SEPA soglasja"
msgctxt "model:account.payment.sepa.mandate,name:"
msgid "SEPA Mandate"
-msgstr "Soglasje SEPA"
+msgstr "SEPA soglasje"
msgctxt "model:account.payment.sepa.message,name:"
msgid "SEPA Message"
-msgstr "Sporočilo SEPA"
+msgstr "SEPA sporočilo"
msgctxt "model:ir.action,name:act_mandate_form"
msgid "SEPA Mandates"
-msgstr "Soglasja SEPA"
+msgstr "SEPA soglasja"
msgctxt "model:ir.action,name:act_mandate_form2"
msgid "Mandates"
@@ -214,7 +214,7 @@ msgstr "Soglasja"
msgctxt "model:ir.action,name:act_message_form"
msgid "SEPA Messages"
-msgstr "Sporočila SEPA"
+msgstr "SEPA sporočilo"
msgctxt "model:ir.action,name:report_mandate"
msgid "Mandate"
@@ -235,7 +235,7 @@ msgstr "Zaključeno"
msgctxt "model:ir.action.act_window.domain,name:act_message_form_domain_draft"
msgid "Draft"
-msgstr "V pripravi"
+msgstr "Priprava"
msgctxt ""
"model:ir.action.act_window.domain,name:act_message_form_domain_waiting"
@@ -249,15 +249,15 @@ msgstr "Terjatve s soglasjem"
msgctxt "model:ir.sequence.type,name:sequence_type_mandate"
msgid "SEPA Mandate"
-msgstr "Soglasje SEPA"
+msgstr "SEPA soglasje"
msgctxt "model:ir.ui.menu,name:menu_mandate_form"
msgid "SEPA Mandates"
-msgstr "Soglasja SEPA"
+msgstr "SEPA soglasja"
msgctxt "model:ir.ui.menu,name:menu_message_form"
msgid "SEPA Messages"
-msgstr "Sporočila SEPA"
+msgstr "SEPA sporočilo"
msgctxt "odt:account.payment.sepa.mandate:"
msgid "."
@@ -312,7 +312,7 @@ msgstr "Datum"
msgctxt "odt:account.payment.sepa.mandate:"
msgid "Direct Debit MANDATE"
-msgstr "Soglasje direktne obremenitve"
+msgstr "Soglasje direktne bremenitve"
msgctxt "odt:account.payment.sepa.mandate:"
msgid "E-Mail:"
@@ -462,6 +462,10 @@ msgctxt "selection:account.payment.sepa.message,type:"
msgid "OUT"
msgstr "Izhod"
+msgctxt "view:account.payment.group:"
+msgid "Generate Message"
+msgstr "Izdelava sporočila"
+
msgctxt "view:account.payment.journal:"
msgid "SEPA"
msgstr "SEPA"
@@ -504,15 +508,15 @@ msgstr "Izvedi"
msgctxt "view:account.payment.sepa.message:"
msgid "Draft"
-msgstr "V pripravi"
+msgstr "Priprava"
msgctxt "view:account.payment.sepa.message:"
msgid "SEPA Message"
-msgstr "Sporočilo SEPA"
+msgstr "SEPA sporočilo"
msgctxt "view:account.payment.sepa.message:"
msgid "SEPA Messages"
-msgstr "Sporočila SEPA"
+msgstr "SEPA sporočilo"
msgctxt "view:account.payment.sepa.message:"
msgid "Wait"
diff --git a/mandate.odt b/mandate.odt
index ac7e364..44937ce 100644
Binary files a/mandate.odt and b/mandate.odt differ
diff --git a/party.py b/party.py
index 5154440..944635e 100644
--- a/party.py
+++ b/party.py
@@ -1,5 +1,5 @@
-#This file is part of Tryton. The COPYRIGHT file at the top level of
-#this repository contains the full copyright notices and license terms.
+# This file is part of Tryton. The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
from trytond.pool import PoolMeta
from trytond.model import fields
diff --git a/party.xml b/party.xml
index 8783a35..688d00c 100644
--- a/party.xml
+++ b/party.xml
@@ -11,7 +11,8 @@ this repository contains the full copyright notices and license terms. -->
<record model="ir.action.act_window" id="act_mandate_form2">
<field name="name">Mandates</field>
<field name="res_model">account.payment.sepa.mandate</field>
- <field name="domain">[("party", "=", Eval('active_id'))]</field>
+ <field name="domain"
+ eval="[('party', '=', Eval('active_id'))]" pyson="1"/>
</record>
<record model="ir.action.act_window.view" id="act_mandate_form2_view1">
<field name="sequence" eval="10"/>
diff --git a/payment.py b/payment.py
index 6ce3d7c..4d6da05 100644
--- a/payment.py
+++ b/payment.py
@@ -1,7 +1,8 @@
-#This file is part of Tryton. The COPYRIGHT file at the top level of
-#this repository contains the full copyright notices and license terms.
+# This file is part of Tryton. The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
import datetime
import os
+import unicodedata
from itertools import groupby
from io import BytesIO
@@ -11,7 +12,7 @@ from lxml import etree
from sql import Literal
from trytond.pool import PoolMeta, Pool
-from trytond.model import ModelSQL, ModelView, Workflow, fields
+from trytond.model import ModelSQL, ModelView, Workflow, fields, dualmethod
from trytond.pyson import Eval, If
from trytond.transaction import Transaction
from trytond.tools import reduce_ids, grouped_slice
@@ -43,6 +44,7 @@ class Journal:
(None, ''),
('pain.001.001.03', 'pain.001.001.03'),
('pain.001.001.05', 'pain.001.001.05'),
+ ('pain.001.003.03', 'pain.001.003.03'),
], 'Payable Flavor', states={
'required': Eval('process_method') == 'sepa',
'invisible': Eval('process_method') != 'sepa',
@@ -53,6 +55,7 @@ class Journal:
(None, ''),
('pain.008.001.02', 'pain.008.001.02'),
('pain.008.001.04', 'pain.008.001.04'),
+ ('pain.008.003.02', 'pain.008.003.02'),
], 'Receivable Flavor', states={
'required': Eval('process_method') == 'sepa',
'invisible': Eval('process_method') != 'sepa',
@@ -127,6 +130,9 @@ class Group:
cls._error_messages.update({
'no_mandate': 'No valid mandate for payment "%s"',
})
+ cls._buttons.update({
+ 'generate_message': {},
+ })
def get_sepa_template(self):
if self.kind == 'payable':
@@ -137,11 +143,9 @@ class Group:
def process_sepa(self):
pool = Pool()
Payment = pool.get('account.payment')
- Message = pool.get('account.payment.sepa.message')
if self.kind == 'receivable':
- payments = [p for p in self.payments if not p.sepa_mandate]
- mandates = Payment.get_sepa_mandates(payments)
- for payment, mandate in zip(payments, mandates):
+ mandates = Payment.get_sepa_mandates(self.payments)
+ for payment, mandate in zip(self.payments, mandates):
if not mandate:
self.raise_user_error('no_mandate', payment.rec_name)
# Write one by one becasue mandate.sequence_type must be
@@ -150,15 +154,27 @@ class Group:
'sepa_mandate': mandate,
'sepa_mandate_sequence_type': mandate.sequence_type,
})
- tmpl = self.get_sepa_template()
- if not tmpl:
- raise NotImplementedError
- if not self.sepa_messages:
- self.sepa_messages = ()
- message = tmpl.generate(group=self,
- datetime=datetime).filter(remove_comment).render()
- message = Message(message=message, type='out', state='waiting')
- self.sepa_messages += (message,)
+ self.generate_message(_save=False)
+
+ @dualmethod
+ @ModelView.button
+ def generate_message(cls, groups, _save=True):
+ pool = Pool()
+ Message = pool.get('account.payment.sepa.message')
+ for group in groups:
+ tmpl = group.get_sepa_template()
+ if not tmpl:
+ raise NotImplementedError
+ if not group.sepa_messages:
+ group.sepa_messages = ()
+ message = tmpl.generate(group=group,
+ datetime=datetime, normalize=unicodedata.normalize,
+ ).filter(remove_comment).render()
+ message = Message(message=message, type='out', state='waiting',
+ company=group.company)
+ group.sepa_messages += (message,)
+ if _save:
+ cls.save(groups)
@property
def sepa_initiating_party(self):
@@ -192,8 +208,9 @@ class Payment:
ondelete='RESTRICT',
domain=[
('party', '=', Eval('party', -1)),
+ ('company', '=', Eval('company', -1)),
],
- depends=['party'])
+ depends=['party', 'company'])
sepa_mandate_sequence_type = fields.Char('Mandate Sequence Type',
readonly=True)
sepa_return_reason_code = fields.Char('Return Reason Code', readonly=True,
@@ -215,14 +232,27 @@ class Payment:
'get_sepa_instruction_id', searcher='search_sepa_instruction_id')
@classmethod
+ def copy(cls, payments, default=None):
+ if default is None:
+ default = {}
+ default.setdefault('sepa_mandate_sequence_type', None)
+ return super(Payment, cls).copy(payments, default=default)
+
+ @classmethod
def get_sepa_mandates(cls, payments):
mandates = []
for payment in payments:
- for mandate in payment.party.sepa_mandates:
- if mandate.is_valid:
- break
+ if payment.sepa_mandate:
+ if payment.sepa_mandate.is_valid:
+ mandate = payment.sepa_mandate
+ else:
+ mandate = None
else:
- mandate = None
+ for mandate in payment.party.sepa_mandates:
+ if mandate.is_valid:
+ break
+ else:
+ mandate = None
mandates.append(mandate)
return mandates
@@ -233,7 +263,7 @@ class Payment:
def search_end_to_end_id(cls, name, domain):
table = cls.__table__()
_, operator, value = domain
- cast = cls.sepa_end_to_end_id._field.sql_type().base
+ cast = cls.sepa_end_to_end_id.sql_type().base
Operator = fields.SQL_OPERATORS[operator]
query = table.select(table.id,
where=Operator(table.id.cast(cast), value))
@@ -260,6 +290,17 @@ class Payment:
if number.type == 'iban':
return number
+ @property
+ def rejected(self):
+ return (self.state == 'failed'
+ and self.sepa_return_reason_code
+ and self.sepa_return_reason_information == '/RTYP/RJCT')
+
+ def create_clearing_move(self, date=None):
+ if not date:
+ date = Transaction().context.get('date_value')
+ return super(Payment, self).create_clearing_move(date=date)
+
class Mandate(Workflow, ModelSQL, ModelView):
'SEPA Mandate'
@@ -271,6 +312,7 @@ class Mandate(Workflow, ModelSQL, ModelView):
},
depends=['state'])
account_number = fields.Many2One('bank.account.number', 'Account Number',
+ ondelete='RESTRICT',
states={
'readonly': Eval('state').in_(['validated', 'canceled']),
'required': Eval('state') == 'validated',
@@ -443,7 +485,9 @@ class Mandate(Workflow, ModelSQL, ModelView):
def sequence_type(self):
if self.type == 'one-off':
return 'OOFF'
- elif not self.payments:
+ elif (not self.payments
+ or all(not p.sepa_mandate_sequence_type for p in self.payments)
+ or all(p.rejected for p in self.payments)):
return 'FRST'
# TODO manage FNAL
else:
diff --git a/payment.xml b/payment.xml
index 751007e..87b796c 100644
--- a/payment.xml
+++ b/payment.xml
@@ -55,10 +55,19 @@ this repository contains the full copyright notices and license terms. -->
<field name="global_p" eval="True"/>
</record>
<record model="ir.rule" id="rule_payment1">
- <field name="domain">[('company', '=', user.company.id if user.company else None)]</field>
+ <field name="domain"
+ eval="[('company', '=', Eval('user', {}).get('company', None))]"
+ pyson="1"/>
<field name="rule_group" ref="rule_group_mandate"/>
</record>
+ <record model="ir.model.access" id="access_mandate">
+ <field name="model" search="[('model', '=', 'account.payment.sepa.mandate')]"/>
+ <field name="perm_read" eval="False"/>
+ <field name="perm_write" eval="False"/>
+ <field name="perm_create" eval="False"/>
+ <field name="perm_delete" eval="False"/>
+ </record>
<record model="ir.model.access" id="access_mandate_account_admin">
<field name="model" search="[('model', '=', 'account.payment.sepa.mandate')]"/>
<field name="group" ref="account.group_account_admin"/>
@@ -121,25 +130,25 @@ this repository contains the full copyright notices and license terms. -->
<record model="ir.action.act_window.domain" id="act_message_form_domain_draft">
<field name="name">Draft</field>
<field name="sequence" eval="10"/>
- <field name="domain">[('state', '=', 'draft')]</field>
+ <field name="domain" eval="[('state', '=', 'draft')]" pyson="1"/>
<field name="act_window" ref="act_message_form"/>
</record>
<record model="ir.action.act_window.domain" id="act_message_form_domain_waiting">
<field name="name">Waiting</field>
<field name="sequence" eval="20"/>
- <field name="domain">[('state', '=', 'waiting')]</field>
+ <field name="domain" eval="[('state', '=', 'waiting')]" pyson="1"/>
<field name="act_window" ref="act_message_form"/>
</record>
<record model="ir.action.act_window.domain" id="act_message_form_domain_done">
<field name="name">Done</field>
<field name="sequence" eval="30"/>
- <field name="domain">[('state', '=', 'done')]</field>
+ <field name="domain" eval="[('state', '=', 'done')]" pyson="1"/>
<field name="act_window" ref="act_message_form"/>
</record>
<record model="ir.action.act_window.domain" id="act_message_form_domain_canceled">
<field name="name">Canceled</field>
<field name="sequence" eval="40"/>
- <field name="domain">[('state', '=', 'canceled')]</field>
+ <field name="domain" eval="[('state', '=', 'canceled')]" pyson="1"/>
<field name="act_window" ref="act_message_form"/>
</record>
<record model="ir.action.act_window.domain" id="act_message_form_domain_all">
@@ -157,10 +166,20 @@ this repository contains the full copyright notices and license terms. -->
<field name="global_p" eval="True"/>
</record>
<record model="ir.rule" id="rule_message1">
- <field name="domain">[('company', '=', user.company.id if user.company else None)]</field>
+ <field name="domain"
+ eval="[('company', '=', Eval('user', {}).get('company', None))]"
+ pyson="1"/>
<field name="rule_group" ref="rule_group_message"/>
</record>
+ <record model="ir.model.access" id="access_message">
+ <field name="model"
+ search="[('model', '=', 'account.payment.sepa.message')]"/>
+ <field name="perm_read" eval="False"/>
+ <field name="perm_write" eval="False"/>
+ <field name="perm_create" eval="False"/>
+ <field name="perm_delete" eval="False"/>
+ </record>
<record model="ir.model.access" id="access_message_account_admin">
<field name="model" search="[('model', '=', 'account.payment.sepa.message')]"/>
<field name="group" ref="account.group_account_admin"/>
diff --git a/sepa_handler.py b/sepa_handler.py
index 7c4271c..2360b1d 100644
--- a/sepa_handler.py
+++ b/sepa_handler.py
@@ -1,6 +1,9 @@
-#This file is part of Tryton. The COPYRIGHT file at the top level of
-#this repository contains the full copyright notices and license terms.
+# This file is part of Tryton. The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
from lxml import etree
+from dateutil.parser import parse
+
+from trytond.transaction import Transaction
__all__ = ['SEPAHandler', 'CAMT054']
@@ -32,13 +35,16 @@ class CAMT054(SEPAHandler):
element.clear()
def handle_entry(self, element):
- payment = self.get_payment(element)
+ payments = self.get_payments(element)
if self.is_returned(element):
- self.set_return_information(payment, element)
- payment.save()
- self.Payment.fail([payment])
+ for payment in payments:
+ self.set_return_information(payment, element)
+ self.Payment.save(payments)
+ self.Payment.fail(payments)
else:
- self.Payment.succeed([payment])
+ date_value = self.date_value(element)
+ with Transaction().set_context(date_value=date_value):
+ self.Payment.succeed(payments)
def get_payment_kind(self, element):
tag = etree.QName(element)
@@ -49,7 +55,7 @@ class CAMT054(SEPAHandler):
'DBIT': 'receivable',
}
- def get_payment(self, element):
+ def get_payments(self, element):
tag = etree.QName(element)
details = element.find('./{%s}NtryDtls' % tag.namespace)
if details is None:
@@ -59,18 +65,30 @@ class CAMT054(SEPAHandler):
return
instr_id = details.find('.//{%s}InstrId' % tag.namespace)
if instr_id is not None:
- payment, = self.Payment.search([
+ payments = self.Payment.search([
('sepa_instuction_id', '=', instr_id.text),
('kind', '=', self.get_payment_kind(element)),
])
- return payment
+ return payments
end_to_end_id = details.find('.//{%s}EndToEndId' % tag.namespace)
if end_to_end_id is not None:
- payment, = self.Payment.search([
+ payments = self.Payment.search([
('sepa_end_to_end_id', '=', end_to_end_id.text),
('kind', '=', self.get_payment_kind(element)),
])
- return payment
+ return payments
+
+ def date_value(self, element):
+ tag = etree.QName(element)
+ date = element.find('./{%(ns)s}ValDt/{%(ns)s}Dt'
+ % {'ns': tag.namespace})
+ if date is not None:
+ return parse(date.text)
+ else:
+ datetime = element.find('./{%(ns)s}ValDt/{%(ns)s}DtTm'
+ % {'ns': tag.namespace})
+ if datetime:
+ return parse(datetime.text).date()
def is_returned(self, element):
tag = etree.QName(element)
diff --git a/setup.py b/setup.py
index 545faeb..854e49b 100644
--- a/setup.py
+++ b/setup.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
-#This file is part of Tryton. The COPYRIGHT file at the top level of
-#this repository contains the full copyright notices and license terms.
+# This file is part of Tryton. The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
from setuptools import setup
import re
@@ -41,7 +41,7 @@ if minor_version % 2:
'hg+http://hg.tryton.org/modules/%s#egg=%s-%s' % (
name[8:], name, version))
-requires = ['Genshi', 'lxml']
+requires = ['Genshi', 'lxml', 'python-dateutil']
for dep in info.get('depends', []):
if not re.match(r'(ir|res|webdav)(\W|$)', dep):
requires.append(get_require_version('trytond_%s' % dep))
@@ -88,6 +88,8 @@ setup(name=name,
'Natural Language :: Spanish',
'Operating System :: OS Independent',
'Programming Language :: Python :: 2.7',
+ 'Programming Language :: Python :: Implementation :: CPython',
+ 'Programming Language :: Python :: Implementation :: PyPy',
'Topic :: Office/Business',
'Topic :: Office/Business :: Financial :: Accounting',
],
diff --git a/template/base.003.xml b/template/base.003.xml
new file mode 100644
index 0000000..39555e0
--- /dev/null
+++ b/template/base.003.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
+this repository contains the full copyright notices and license terms. -->
+<py:strip xmlns:py="http://genshi.edgewall.org/">
+ <!-- only ASCII -->
+ <py:def function="PartyIdentification(party, id=True, with_name=True, with_address=True)">
+ <!-- EPC limits to 70 instead of 140 -->
+ <Nm py:if="with_name">${normalize('NFKD', party.name).encode('ascii', 'replace')[:70]}</Nm>
+ <py:if test="with_address">
+ <py:with vars="address = party.address_get()">
+ <PstlAdr py:if="address">
+ ${PostalAddress(address)}
+ </PstlAdr>
+ </py:with>
+ </py:if>
+ <Id py:if="id and party.sepa_creditor_identifier_used">
+ <PrvtId>
+ <Othr>
+ <Id>${party.sepa_creditor_identifier_used}</Id>
+ <SchmeNm>
+ <Prtry>SEPA</Prtry>
+ </SchmeNm>
+ <!-- Issr -->
+ </Othr>
+ </PrvtId>
+ </Id>
+ <!-- CtryOfRes -->
+ <!-- CtctDtls -->
+ </py:def>
+ <py:def function="PostalAddress(address)">
+ <Ctry py:if="address.country">${normalize('NFKD', address.country.code).encode('ascii', 'replace')}</Ctry>
+ <AdrLine py:if="address.street">${normalize('NFKD', address.street).encode('ascii', 'replace')[:70]}</AdrLine>
+ <AdrLine py:if="address.streetbis">${normalize('NFKD', address.streetbis).encode('ascii', 'replace')[:70]}</AdrLine>
+ </py:def>
+ <py:def function="Account(account_number, with_ccy=True)">
+ <Id>
+ <!-- EPC only IBAN is allowed -->
+ <IBAN>${account_number.compact_iban}</IBAN>
+ </Id>
+ <!-- Tp -->
+ <Ccy py:if="with_ccy and account_number.account.currency">${account_number.account.currency.code}</Ccy>
+ <!-- Nm -->
+ </py:def>
+ <!-- uses BIC instead of BICFI -->
+ <py:def function="FinancialInstitution(bank, only_bic=False)">
+ <FinInstnId>
+ <BIC py:if="bank.bic">${bank.bic}</BIC>
+ <Othr py:if="not bank.bic">
+ <Id>NOTPROVIDED</Id>
+ </Othr>
+ </FinInstnId>
+ </py:def>
+</py:strip>
diff --git a/template/base.xml b/template/base.xml
index c6830af..0441aa4 100644
--- a/template/base.xml
+++ b/template/base.xml
@@ -36,13 +36,13 @@ this repository contains the full copyright notices and license terms. -->
<Ctry py:if="address.country">${address.country.code}</Ctry>
<!-- AdrLine -->
</py:def>
- <py:def function="Account(account_number)">
+ <py:def function="Account(account_number, currency=True)">
<Id>
<!-- EPC only IBAN is allowed -->
<IBAN>${account_number.compact_iban}</IBAN>
</Id>
<!-- Tp -->
- <Ccy py:if="account_number.account.currency">${account_number.account.currency.code}</Ccy>
+ <Ccy py:if="currency and account_number.account.currency">${account_number.account.currency.code}</Ccy>
<!-- Nm -->
</py:def>
<py:def function="FinancialInstitution(bank, only_bic=False)">
diff --git a/template/pain.001.001.03.xml b/template/pain.001.001.03.xml
index 29ea6d6..25073f6 100644
--- a/template/pain.001.001.03.xml
+++ b/template/pain.001.001.03.xml
@@ -31,7 +31,7 @@ this repository contains the full copyright notices and license terms. -->
<MsgId>${group.reference[:35]}</MsgId>
<CreDtTm>${datetime.datetime.now().isoformat()}</CreDtTm>
<!-- Authstn -->
- <NbOfTxs>${len(group.payments)}</NbOfTxs>
+ <NbOfTxs>${sum(len(payments) for _, payments in group.sepa_payments)}</NbOfTxs>
<CtrlSum>${sum(p.amount for p in group.payments)}</CtrlSum>
<!-- PmtTpInf -->
<!-- ReqdColltnDt -->
diff --git a/template/pain.001.001.05.xml b/template/pain.001.001.05.xml
index db275a5..319afcb 100644
--- a/template/pain.001.001.05.xml
+++ b/template/pain.001.001.05.xml
@@ -12,7 +12,7 @@ this repository contains the full copyright notices and license terms. -->
<MsgId>${group.reference[:35]}</MsgId>
<CreDtTm>${datetime.datetime.now().isoformat()}</CreDtTm>
<!-- Authstn -->
- <NbOfTxs>${len(group.payments)}</NbOfTxs>
+ <NbOfTxs>${sum(len(payments) for _, payments in group.sepa_payments)}</NbOfTxs>
<CtrlSum>${sum(p.amount for p in group.payments)}</CtrlSum>
<!-- PmtTpInf -->
<!-- ReqdColltnDt -->
diff --git a/template/pain.001.001.05.xml b/template/pain.001.003.03.xml
similarity index 69%
copy from template/pain.001.001.05.xml
copy to template/pain.001.003.03.xml
index db275a5..9b613b4 100644
--- a/template/pain.001.001.05.xml
+++ b/template/pain.001.003.03.xml
@@ -1,25 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
-<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.001.05"
+<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.003.03"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="urn:iso:std:iso:20022:tech:xsd:pain.001.003.03
+ pain.001.003.03.xsd"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:py="http://genshi.edgewall.org/">
<xi:include href="base.xml"/>
+ <xi:include href="base.003.xml"/>
<CstmrCdtTrfInitn>
<GrpHdr>
<MsgId>${group.reference[:35]}</MsgId>
<CreDtTm>${datetime.datetime.now().isoformat()}</CreDtTm>
- <!-- Authstn -->
- <NbOfTxs>${len(group.payments)}</NbOfTxs>
+ <NbOfTxs>${sum(len(payments) for _, payments in group.sepa_payments)}</NbOfTxs>
<CtrlSum>${sum(p.amount for p in group.payments)}</CtrlSum>
- <!-- PmtTpInf -->
- <!-- ReqdColltnDt -->
<InitgPty>
- ${PartyIdentification(group.sepa_initiating_party)}
+ ${PartyIdentification(group.sepa_initiating_party, with_address=False)}
</InitgPty>
- <!-- FwdgAgt -->
</GrpHdr>
<PmtInf py:for="key, payments in group.sepa_payments">
<PmtInfId>${group.sepa_group_payment_id(key)[:35]}</PmtInfId>
@@ -32,11 +31,9 @@ this repository contains the full copyright notices and license terms. -->
<SvcLvl>
<Cd>SEPA</Cd>
</SvcLvl>
- <!-- LclInstrm -->
<!-- CtgyPurp -->
</PmtTpInf>
<ReqdExctnDt>${key['date'].isoformat()}</ReqdExctnDt>
- <!-- PoolgAdjstmntDt -->
<Dbtr>
${PartyIdentification(group.company.party)}
</Dbtr>
@@ -46,12 +43,8 @@ this repository contains the full copyright notices and license terms. -->
<DbtrAgt>
${FinancialInstitution(group.journal.sepa_bank_account_number.account.bank, only_bic=True)}
</DbtrAgt>
- <!-- DbtrAgtAcct -->
- <!-- InstrForDbtrAgt -->
<!-- UltmtDbtr -->
- <ChrgBr>${group.journal.sepa_charge_bearer}</ChrgBr>
- <!-- ChrgsAcct -->
- <!-- ChrgsAcctAgt -->
+ <ChrgBr>SLEV</ChrgBr>
<CdtTrfTxInf py:for="payment in payments">
<PmtId>
<InstrId>${payment.sepa_instruction_id}</InstrId>
@@ -60,41 +53,24 @@ this repository contains the full copyright notices and license terms. -->
<!-- PmtTpInf --> <!-- EPC only at payment information level -->
<Amt>
<InstdAmt py:attrs="{'Ccy': payment.currency.code}">${payment.amount}</InstdAmt>
- <!-- EqvtAmt -->
</Amt>
- <!-- XchgRateInf -->
<!-- ChrgBr --> <!-- EPC only at payment information level -->
- <!-- ChqInstr -->
<!-- UltmtDbtr -->
- <!-- IntrmyAgt1 -->
- <!-- IntrmyAgt1Acct -->
- <!-- IntrmyAgt2 -->
- <!-- IntrmyAgt2Acct -->
- <!-- IntrmyAgt3 -->
- <!-- IntrmyAgt3Acct -->
<CdtrAgt>
${FinancialInstitution(payment.sepa_bank_account_number.account.bank, only_bic=True)}
</CdtrAgt>
- <!-- CdtrAgtAcct -->
<Cdtr>
${PartyIdentification(payment.party)}
</Cdtr>
<CdtrAcct>
- ${Account(payment.sepa_bank_account_number)}
+ ${Account(payment.sepa_bank_account_number, with_ccy=False)}
</CdtrAcct>
<!-- UltmtCdtr -->
- <!-- InstrForCdtrAgt -->
- <!-- InstrForDbtrAgt -->
<!-- Purp -->
- <!-- RgltryRptg -->
- <!-- Tax -->
- <!-- RltdRmtInf -->
<RmtInf py:if="payment.sepa_remittance_information">
- <Ustrd>${payment.sepa_remittance_information[:140]}</Ustrd>
+ <Ustrd>${normalize('NFKD', payment.sepa_remittance_information).encode('ascii', 'replace')[:140]}</Ustrd>
</RmtInf>
- <!-- SplmtryData -->
</CdtTrfTxInf>
</PmtInf>
- <!-- SplmtryData -->
</CstmrCdtTrfInitn>
</Document>
diff --git a/template/pain.008.001.02.xml b/template/pain.008.001.02.xml
index 002db1a..86a28ef 100644
--- a/template/pain.008.001.02.xml
+++ b/template/pain.008.001.02.xml
@@ -31,7 +31,7 @@ this repository contains the full copyright notices and license terms. -->
<MsgId>${group.reference[:35]}</MsgId>
<CreDtTm>${datetime.datetime.now().isoformat()}</CreDtTm>
<!-- Authstn -->
- <NbOfTxs>${len(group.payments)}</NbOfTxs>
+ <NbOfTxs>${sum(len(payments) for _, payments in group.sepa_payments)}</NbOfTxs>
<CtrlSum>${sum(p.amount for p in group.payments)}</CtrlSum>
<!-- PmtTpInf -->
<!-- ReqdColltnDt -->
@@ -109,7 +109,7 @@ this repository contains the full copyright notices and license terms. -->
${PartyIdentification(payment.party)}
</Dbtr>
<DbtrAcct>
- ${Account(payment.sepa_bank_account_number)}
+ ${Account(payment.sepa_bank_account_number, currency=False)}
</DbtrAcct>
<!-- UltmtDbtr -->
<!-- InstrForCdtrAgt -->
diff --git a/template/pain.008.001.04.xml b/template/pain.008.001.04.xml
index 2ec8914..57c680e 100644
--- a/template/pain.008.001.04.xml
+++ b/template/pain.008.001.04.xml
@@ -90,7 +90,7 @@ this repository contains the full copyright notices and license terms. -->
${PartyIdentification(payment.party)}
</Dbtr>
<DbtrAcct>
- ${Account(payment.sepa_bank_account_number)}
+ ${Account(payment.sepa_bank_account_number, currency=False)}
</DbtrAcct>
<!-- UltmtDbtr -->
<!-- InstrForCdtrAgt -->
diff --git a/template/pain.008.001.04.xml b/template/pain.008.003.02.xml
similarity index 74%
copy from template/pain.008.001.04.xml
copy to template/pain.008.003.02.xml
index 2ec8914..7fdb45d 100644
--- a/template/pain.008.001.04.xml
+++ b/template/pain.008.003.02.xml
@@ -1,25 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
-<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.008.001.04"
+<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.008.003.02"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="urn:iso:std:iso:20022:tech:xsd:pain.008.003.02
+ pain.008.003.02.xsd"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:py="http://genshi.edgewall.org/">
<xi:include href="base.xml"/>
+ <xi:include href="base.003.xml"/>
<CstmrDrctDbtInitn>
<GrpHdr>
<MsgId>${group.reference[:35]}</MsgId>
<CreDtTm>${datetime.datetime.now().isoformat()}</CreDtTm>
- <!-- Authstn -->
- <NbOfTxs>${len(group.payments)}</NbOfTxs>
+ <NbOfTxs>${sum(len(payments) for _, payments in group.sepa_payments)}</NbOfTxs>
<CtrlSum>${sum(p.amount for p in group.payments)}</CtrlSum>
- <!-- PmtTpInf -->
- <!-- ReqdColltnDt -->
<InitgPty>
- ${PartyIdentification(group.sepa_initiating_party)}
+ ${PartyIdentification(group.sepa_initiating_party, with_address=False)}
</InitgPty>
- <!-- FwdgAgt -->
</GrpHdr>
<PmtInf py:for="key, payments in group.sepa_payments">
<PmtInfId>${group.sepa_group_payment_id(key)[:35]}</PmtInfId>
@@ -28,14 +27,11 @@ this repository contains the full copyright notices and license terms. -->
<NbOfTxs>${len(payments)}</NbOfTxs>
<CtrlSum>${sum(p.amount for p in payments)}</CtrlSum>
<PmtTpInf>
- <!-- InstrPrty -->
<SvcLvl>
<Cd>SEPA</Cd>
- <!-- Prtry -->
</SvcLvl>
<LclInstrm>
<Cd>${key['scheme']}</Cd>
- <!-- Prtry -->
</LclInstrm>
<SeqTp>${key['sequence_type']}</SeqTp>
<!-- CtgyPurp -->
@@ -50,20 +46,16 @@ this repository contains the full copyright notices and license terms. -->
<CdtrAgt>
${FinancialInstitution(group.journal.sepa_bank_account_number.account.bank, only_bic=True)}
</CdtrAgt>
- <!-- CdtrAgtAcct -->
<!-- UltmtCdtr -->
- <ChrgBr>${group.journal.sepa_charge_bearer}</ChrgBr>
- <!-- ChrgsAcct -->
- <!-- ChrgsAcctAgt -->
+ <ChrgBr>SLEV</ChrgBr>
<CdtrSchmeId>
- ${PartyIdentification(group.company.party)}
+ ${PartyIdentification(group.company.party, with_name=False, with_address=False)}
</CdtrSchmeId>
<DrctDbtTxInf py:for="payment in payments">
<PmtId>
<InstrId>${payment.sepa_instruction_id}</InstrId>
<EndToEndId>${payment.sepa_end_to_end_id}</EndToEndId>
</PmtId>
- <!-- PmtTpInf -->
<InstdAmt py:attrs="{'Ccy': payment.currency.code}">${payment.amount}</InstdAmt>
<!-- ChrgBr --> <!-- EPC only at payment information level -->
<DrctDbtTx>
@@ -73,37 +65,26 @@ this repository contains the full copyright notices and license terms. -->
<!-- AmdmntInd -->
<!-- AmdmntInfDtls -->
<!-- ElctrncSgntr -->
- <!-- FrstColltnDt -->
- <!-- FnlColltnDt -->
- <!-- Frqcy -->
</MndtRltdInf>
<!-- CdtrSchmeId -->
- <!-- PreNtfctnId -->
- <!-- PreNtfctnDt -->
</DrctDbtTx>
<!-- UltmtCdtr -->
<DbtrAgt>
${FinancialInstitution(payment.sepa_bank_account_number.account.bank, only_bic=True)}
</DbtrAgt>
- <!-- DbtrAgtAcct -->
<Dbtr>
${PartyIdentification(payment.party)}
</Dbtr>
<DbtrAcct>
- ${Account(payment.sepa_bank_account_number)}
+ ${Account(payment.sepa_bank_account_number, with_ccy=False)}
</DbtrAcct>
<!-- UltmtDbtr -->
- <!-- InstrForCdtrAgt -->
<!-- Purp -->
- <!-- RgltryRptg -->
- <!-- Tax -->
- <!-- RltdRmtInf -->
<RmtInf py:if="payment.sepa_remittance_information">
- <Ustrd>${payment.sepa_remittance_information[:140]}</Ustrd>
+ <Ustrd>${normalize('NFKD', payment.sepa_remittance_information).encode('ascii', 'replace')[:140]}</Ustrd>
+ <!-- Strd -->
</RmtInf>
- <!-- SplmtryData -->
</DrctDbtTxInf>
</PmtInf>
- <!-- SplmtryData -->
</CstmrDrctDbtInitn>
</Document>
diff --git a/tests/__init__.py b/tests/__init__.py
index 84e2248..9e31e2c 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -1,5 +1,5 @@
-#This file is part of Tryton. The COPYRIGHT file at the top level of
-#this repository contains the full copyright notices and license terms.
+# This file is part of Tryton. The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
from .test_account_payment_sepa import suite
diff --git a/tests/pain.001.003.03.xsd b/tests/pain.001.003.03.xsd
new file mode 100644
index 0000000..a90ed99
--- /dev/null
+++ b/tests/pain.001.003.03.xsd
@@ -0,0 +1,474 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Version gemäß DFÜ-Abkommen Anlage 3, Version 2.7, gültig ab November 2013 mit Umsetzung von IBAN Only gemäß EPC SCT 7.0, zudem Erweiterung Service Level auf Externe Codeliste-->
+<!-- Mit XMLSpy v2008 am 29.11.2012 von der SIZ GmbH bearbeitet -->
+<xs:schema xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.003.03" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:iso:std:iso:20022:tech:xsd:pain.001.003.03" elementFormDefault="qualified">
+ <xs:element name="Document" type="Document"/>
+ <xs:complexType name="AccountIdentificationSEPA">
+ <xs:sequence>
+ <xs:element name="IBAN" type="IBAN2007Identifier"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="ActiveOrHistoricCurrencyAndAmount_SimpleTypeSEPA">
+ <xs:restriction base="xs:decimal">
+ <xs:minInclusive value="0.01"/>
+ <xs:maxInclusive value="999999999.99"/>
+ <xs:fractionDigits value="2"/>
+ <xs:totalDigits value="11"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="ActiveOrHistoricCurrencyCode">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="[A-Z]{3,3}"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="ActiveOrHistoricCurrencyAndAmountSEPA">
+ <xs:simpleContent>
+ <xs:extension base="ActiveOrHistoricCurrencyAndAmount_SimpleTypeSEPA">
+ <xs:attribute name="Ccy" type="ActiveOrHistoricCurrencyCodeEUR" use="required"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <xs:simpleType name="ActiveOrHistoricCurrencyCodeEUR">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="EUR"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="AmountTypeSEPA">
+ <xs:sequence>
+ <xs:element name="InstdAmt" type="ActiveOrHistoricCurrencyAndAmountSEPA"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="AnyBICIdentifier">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="[A-Z]{6,6}[A-Z2-9][A-NP-Z0-9]([A-Z0-9]{3,3}){0,1}"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="BICIdentifier">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="[A-Z]{6,6}[A-Z2-9][A-NP-Z0-9]([A-Z0-9]{3,3}){0,1}"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="BatchBookingIndicator">
+ <xs:restriction base="xs:boolean"/>
+ </xs:simpleType>
+ <xs:complexType name="BranchAndFinancialInstitutionIdentificationSEPA1">
+ <xs:sequence>
+ <xs:element name="FinInstnId" type="FinancialInstitutionIdentificationSEPA1"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="BranchAndFinancialInstitutionIdentificationSEPA3">
+ <xs:sequence>
+ <xs:element name="FinInstnId" type="FinancialInstitutionIdentificationSEPA3"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="CashAccountSEPA1">
+ <xs:sequence>
+ <xs:element name="Id" type="AccountIdentificationSEPA"/>
+ <xs:element name="Ccy" type="ActiveOrHistoricCurrencyCode" minOccurs="0"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="CashAccountSEPA2">
+ <xs:sequence>
+ <xs:element name="Id" type="AccountIdentificationSEPA"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="CategoryPurposeSEPA">
+ <xs:sequence>
+ <xs:element name="Cd" type="ExternalCategoryPurpose1Code"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="ChargeBearerTypeSEPACode">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="SLEV"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="CountryCode">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="[A-Z]{2,2}"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="CreditTransferTransactionInformationSCT">
+ <xs:sequence>
+ <xs:element name="PmtId" type="PaymentIdentificationSEPA"/>
+ <xs:element name="PmtTpInf" type="PaymentTypeInformationSCT2" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>If used, it is recommended to be used at ‘Payment Information’ level and not at ‘Credit Transfer Transaction Information’ level.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="Amt" type="AmountTypeSEPA"/>
+ <xs:element name="ChrgBr" type="ChargeBearerTypeSEPACode" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>It is recommended that this element be specified at ‘Payment Information’ level.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="UltmtDbtr" type="PartyIdentificationSEPA1" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>This data element may be present either at ‘Payment Information’ or at ‘Credit Transfer Transaction Information’ level.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="CdtrAgt" type="BranchAndFinancialInstitutionIdentificationSEPA1" minOccurs="0"/>
+ <xs:element name="Cdtr" type="PartyIdentificationSEPA2"/>
+ <xs:element name="CdtrAcct" type="CashAccountSEPA2"/>
+ <xs:element name="UltmtCdtr" type="PartyIdentificationSEPA1" minOccurs="0"/>
+ <xs:element name="Purp" type="PurposeSEPA" minOccurs="0"/>
+ <xs:element name="RmtInf" type="RemittanceInformationSEPA1Choice" minOccurs="0"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="CreditorReferenceInformationSEPA1">
+ <xs:sequence>
+ <xs:element name="Tp" type="CreditorReferenceTypeSEPA"/>
+ <xs:element name="Ref" type="Max35Text">
+ <xs:annotation>
+ <xs:documentation>If a Creditor Reference contains a check digit, the receiving bank is not required to validate this.
+If the receiving bank validates the check digit and if this validation fails, the bank may continue its processing and send the transaction to the next party in the chain.
+RF Creditor Reference may be used (ISO 11649).</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="CreditorReferenceTypeSEPA">
+ <xs:sequence>
+ <xs:element name="CdOrPrtry" type="CreditorReferenceTypeCodeSEPA"/>
+ <xs:element name="Issr" type="Max35Text" minOccurs="0"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="CreditorReferenceTypeCodeSEPA">
+ <xs:sequence>
+ <xs:element name="Cd" type="DocumentType3CodeSEPA"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="CustomerCreditTransferInitiationV03">
+ <xs:sequence>
+ <xs:element name="GrpHdr" type="GroupHeaderSCT"/>
+ <xs:element name="PmtInf" type="PaymentInstructionInformationSCT" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="DateAndPlaceOfBirth">
+ <xs:sequence>
+ <xs:element name="BirthDt" type="ISODate"/>
+ <xs:element name="PrvcOfBirth" type="Max35Text" minOccurs="0"/>
+ <xs:element name="CityOfBirth" type="Max35Text"/>
+ <xs:element name="CtryOfBirth" type="CountryCode"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="DecimalNumber">
+ <xs:restriction base="xs:decimal">
+ <xs:fractionDigits value="17"/>
+ <xs:totalDigits value="18"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="Document">
+ <xs:sequence>
+ <xs:element name="CstmrCdtTrfInitn" type="CustomerCreditTransferInitiationV03"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="DocumentType3CodeSEPA">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="SCOR"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="ExternalCategoryPurpose1Code">
+ <xs:restriction base="xs:string">
+ <xs:minLength value="1"/>
+ <xs:maxLength value="4"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="ExternalOrganisationIdentification1Code">
+ <xs:restriction base="xs:string">
+ <xs:minLength value="1"/>
+ <xs:maxLength value="4"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="ExternalPersonIdentification1Code">
+ <xs:restriction base="xs:string">
+ <xs:minLength value="1"/>
+ <xs:maxLength value="4"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="ExternalPurpose1Code">
+ <xs:restriction base="xs:string">
+ <xs:minLength value="1"/>
+ <xs:maxLength value="4"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="ExternalServiceLevel1Code">
+ <xs:restriction base="xs:string">
+ <xs:minLength value="1"/>
+ <xs:maxLength value="4"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="FinancialInstitutionIdentificationSEPA1">
+ <xs:sequence>
+ <xs:element name="BIC" type="BICIdentifier"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="FinancialInstitutionIdentificationSEPA3">
+ <xs:sequence>
+ <xs:choice>
+ <xs:element name="BIC" type="BICIdentifier"/>
+ <xs:element name="Othr" type="OthrIdentification"/>
+ </xs:choice>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="OthrIdentification">
+ <xs:sequence>
+ <xs:element name="Id" type="OthrIdentificationCode"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="OthrIdentificationCode">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="NOTPROVIDED"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="GenericOrganisationIdentification1">
+ <xs:sequence>
+ <xs:element name="Id" type="Max35Text"/>
+ <xs:element name="SchmeNm" type="OrganisationIdentificationSchemeName1Choice" minOccurs="0"/>
+ <xs:element name="Issr" type="Max35Text" minOccurs="0"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="GenericPersonIdentification1">
+ <xs:sequence>
+ <xs:element name="Id" type="Max35Text"/>
+ <xs:element name="SchmeNm" type="PersonIdentificationSchemeName1Choice" minOccurs="0"/>
+ <xs:element name="Issr" type="Max35Text" minOccurs="0"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="GroupHeaderSCT">
+ <xs:sequence>
+ <xs:element name="MsgId" type="RestrictedIdentificationSEPA1"/>
+ <xs:element name="CreDtTm" type="ISODateTime"/>
+ <xs:element name="NbOfTxs" type="Max15NumericText"/>
+ <xs:element name="CtrlSum" type="DecimalNumber" minOccurs="0"/>
+ <xs:element name="InitgPty" type="PartyIdentificationSEPA1"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="IBAN2007Identifier">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="[A-Z]{2,2}[0-9]{2,2}[a-zA-Z0-9]{1,30}"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="ISODate">
+ <xs:restriction base="xs:date"/>
+ </xs:simpleType>
+ <xs:simpleType name="ISODateTime">
+ <xs:restriction base="xs:dateTime"/>
+ </xs:simpleType>
+ <xs:simpleType name="Max140Text">
+ <xs:restriction base="xs:string">
+ <xs:minLength value="1"/>
+ <xs:maxLength value="140"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="Max15NumericText">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="[0-9]{1,15}"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="Max35Text">
+ <xs:restriction base="xs:string">
+ <xs:minLength value="1"/>
+ <xs:maxLength value="35"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="Max70Text">
+ <xs:restriction base="xs:string">
+ <xs:minLength value="1"/>
+ <xs:maxLength value="70"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="OrganisationIdentificationSEPAChoice">
+ <xs:sequence>
+ <xs:choice>
+ <xs:element name="BICOrBEI" type="AnyBICIdentifier"/>
+ <xs:element name="Othr" type="GenericOrganisationIdentification1"/>
+ </xs:choice>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="OrganisationIdentificationSchemeName1Choice">
+ <xs:sequence>
+ <xs:choice>
+ <xs:element name="Cd" type="ExternalOrganisationIdentification1Code"/>
+ <xs:element name="Prtry" type="Max35Text"/>
+ </xs:choice>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="PartySEPAChoice">
+ <xs:sequence>
+ <xs:choice>
+ <xs:element name="OrgId" type="OrganisationIdentificationSEPAChoice">
+ <xs:annotation>
+ <xs:documentation>Either ‘BIC or BEI’ or one
+occurrence of ‘Other’ is allowed.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="PrvtId" type="PersonIdentificationSEPA1Choice">
+ <xs:annotation>
+ <xs:documentation>Either ‘Date and Place of Birth’ or one occurrence of ‘Other’ is allowed.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ </xs:choice>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="PartyIdentificationSEPA1">
+ <xs:sequence>
+ <xs:element name="Nm" type="Max70Text" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>‘Name’ is limited to 70 characters
+in length.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="Id" type="PartySEPAChoice" minOccurs="0"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="PartyIdentificationSEPA2">
+ <xs:sequence>
+ <xs:element name="Nm" type="Max70Text">
+ <xs:annotation>
+ <xs:documentation>‘Name’ is limited to 70 characters
+in length.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="PstlAdr" type="PostalAddressSEPA" minOccurs="0"/>
+ <xs:element name="Id" type="PartySEPAChoice" minOccurs="0"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="PaymentIdentificationSEPA">
+ <xs:sequence>
+ <xs:element name="InstrId" type="RestrictedIdentificationSEPA1" minOccurs="0"/>
+ <xs:element name="EndToEndId" type="RestrictedIdentificationSEPA1"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="PaymentInstructionInformationSCT">
+ <xs:sequence>
+ <xs:element name="PmtInfId" type="RestrictedIdentificationSEPA1"/>
+ <xs:element name="PmtMtd" type="PaymentMethodSCTCode">
+ <xs:annotation>
+ <xs:documentation>Only ‘TRF’ is allowed.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="BtchBookg" type="BatchBookingIndicator" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>If present and contains ‘true’, batch booking is requested. If present and contains ‘false’, booking per transaction is requested. If element is not present, pre-agreed customer-to-bank conditions apply.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="NbOfTxs" type="Max15NumericText" minOccurs="0"/>
+ <xs:element name="CtrlSum" type="DecimalNumber" minOccurs="0"/>
+ <xs:element name="PmtTpInf" type="PaymentTypeInformationSCT1" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>If used, it is recommended to be used only at ‘Payment Information’ level and not at Credit Transfer Transaction Information’ level.
+When Instruction Priority is to be used, ‘Payment Type Information’ must be present at ‘Payment Information’ level. </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="ReqdExctnDt" type="ISODate"/>
+ <xs:element name="Dbtr" type="PartyIdentificationSEPA2"/>
+ <xs:element name="DbtrAcct" type="CashAccountSEPA1"/>
+ <xs:element name="DbtrAgt" type="BranchAndFinancialInstitutionIdentificationSEPA3"/>
+ <xs:element name="UltmtDbtr" type="PartyIdentificationSEPA1" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>This data element may be present either at ‘Payment Information’ or at ‘Credit Transfer Transaction Information’ level.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="ChrgBr" type="ChargeBearerTypeSEPACode" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>It is recommended that this element be specified at ‘Payment Information’ level.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="CdtTrfTxInf" type="CreditTransferTransactionInformationSCT" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="PaymentMethodSCTCode">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="TRF"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="PaymentTypeInformationSCT1">
+ <xs:sequence>
+ <xs:element name="InstrPrty" type="Priority2Code" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>If present, pre-agreed customer-to-bank conditions apply.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="SvcLvl" type="ServiceLevelSEPA"/>
+ <xs:element name="CtgyPurp" type="CategoryPurposeSEPA" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>Depending on the agreement between the Originator and the Originator Bank, ‘Category Purpose’ may be forwarded to the Beneficiary Bank.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="PaymentTypeInformationSCT2">
+ <xs:sequence>
+ <xs:element name="SvcLvl" type="ServiceLevelSEPA"/>
+ <xs:element name="CtgyPurp" type="CategoryPurposeSEPA" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>Depending on the agreement between the Originator and the Originator Bank, ‘Category Purpose’ may be forwarded to the Beneficiary Bank.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="PersonIdentificationSEPA1Choice">
+ <xs:sequence>
+ <xs:choice>
+ <xs:element name="DtAndPlcOfBirth" type="DateAndPlaceOfBirth"/>
+ <xs:element name="Othr" type="GenericPersonIdentification1"/>
+ </xs:choice>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="PersonIdentificationSchemeName1Choice">
+ <xs:sequence>
+ <xs:choice>
+ <xs:element name="Cd" type="ExternalPersonIdentification1Code"/>
+ <xs:element name="Prtry" type="Max35Text"/>
+ </xs:choice>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="PostalAddressSEPA">
+ <xs:sequence>
+ <xs:element name="Ctry" type="CountryCode" minOccurs="0"/>
+ <xs:element name="AdrLine" type="Max70Text" minOccurs="0" maxOccurs="2"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="Priority2Code">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="HIGH"/>
+ <xs:enumeration value="NORM"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="PurposeSEPA">
+ <xs:sequence>
+ <xs:element name="Cd" type="ExternalPurpose1Code">
+ <xs:annotation>
+ <xs:documentation>Only codes from the ISO 20022 ExternalPurposeCode list are allowed.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="RemittanceInformationSEPA1Choice">
+ <xs:sequence>
+ <xs:choice>
+ <xs:element name="Ustrd" type="Max140Text"/>
+ <xs:element name="Strd" type="StructuredRemittanceInformationSEPA1"/>
+ </xs:choice>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="ServiceLevelSEPA">
+ <xs:sequence>
+ <xs:element name="Cd" type="ExternalServiceLevel1Code"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="StructuredRemittanceInformationSEPA1">
+ <xs:sequence>
+ <xs:element name="CdtrRefInf" type="CreditorReferenceInformationSEPA1" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>When present, the receiving bank is not obliged to validate the the reference information. </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="RestrictedIdentificationSEPA1">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="([A-Za-z0-9]|[\+|\?|/|\-|:|\(|\)|\.|,|'| ]){1,35}"/>
+ </xs:restriction>
+ </xs:simpleType>
+</xs:schema>
diff --git a/tests/pain.008.003.02.xsd b/tests/pain.008.003.02.xsd
new file mode 100644
index 0000000..99992b5
--- /dev/null
+++ b/tests/pain.008.003.02.xsd
@@ -0,0 +1,614 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Mit XMLSpy v2008 rel. 2 (http://www.altova.com) von Wenzel (SIZ Bonn) bearbeitet -->
+<!-- Version gemäß DFÜ-Abkommen Anlage 3, Version 2.7, gültig ab November 2013 mit Umsetzung von IBAN Only gemäß EPC SDD Core IG 7.0 bzw. SDD B2B IG 5.0 , zudem Einbau der COR1-Option durch Erweiterung Local Instrument und Erweiterung Service Level auf Externe Codeliste-->
+<!-- Mit XMLSpy v2008 rel. 2 sp2 (http://www.altova.com) am 29.11.2012 von der SIZ GmbH bearbeitet -->
+<xs:schema xmlns="urn:iso:std:iso:20022:tech:xsd:pain.008.003.02" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:iso:std:iso:20022:tech:xsd:pain.008.003.02" elementFormDefault="qualified">
+ <xs:element name="Document" type="Document"/>
+ <xs:complexType name="AccountIdentificationSEPA">
+ <xs:sequence>
+ <xs:element name="IBAN" type="IBAN2007Identifier"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="ActiveOrHistoricCurrencyAndAmount_SimpleTypeSEPA">
+ <xs:restriction base="xs:decimal">
+ <xs:minInclusive value="0.01"/>
+ <xs:maxInclusive value="999999999.99"/>
+ <xs:fractionDigits value="2"/>
+ <xs:totalDigits value="11"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="ActiveOrHistoricCurrencyAndAmountSEPA">
+ <xs:simpleContent>
+ <xs:extension base="ActiveOrHistoricCurrencyAndAmount_SimpleTypeSEPA">
+ <xs:attribute name="Ccy" type="ActiveOrHistoricCurrencyCodeEUR" use="required"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <xs:simpleType name="ActiveOrHistoricCurrencyCodeEUR">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="EUR"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="ActiveOrHistoricCurrencyCode">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="[A-Z]{3,3}"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="AmendmentInformationDetailsSDD">
+ <xs:sequence>
+ <xs:element name="OrgnlMndtId" type="RestrictedIdentificationSEPA2" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>Mandatory if changes occur in ‘Mandate Identification’, otherwise not to be used.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="OrgnlCdtrSchmeId" type="PartyIdentificationSEPA4" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>Mandatory if changes occur in 'Creditor Scheme Identification', otherwise not to be used.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="OrgnlDbtrAcct" type="CashAccountSEPA2" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>To be used only for changes of accounts within the same bank.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="OrgnlDbtrAgt" type="BranchAndFinancialInstitutionIdentificationSEPA2" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>To use 'Identification’ under 'Other' under 'Financial Institution Identifier with code ‘SMNDA’ to indicate same mandate with new Debtor Agent. To be used with the ‘FRST’ indicator in the ‘Sequence Type’.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="AnyBICIdentifier">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="[A-Z]{6,6}[A-Z2-9][A-NP-Z0-9]([A-Z0-9]{3,3}){0,1}"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="BICIdentifier">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="[A-Z]{6,6}[A-Z2-9][A-NP-Z0-9]([A-Z0-9]{3,3}){0,1}"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="BatchBookingIndicator">
+ <xs:restriction base="xs:boolean"/>
+ </xs:simpleType>
+ <xs:complexType name="BranchAndFinancialInstitutionIdentificationSEPA3">
+ <xs:sequence>
+ <xs:element name="FinInstnId" type="FinancialInstitutionIdentificationSEPA3"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="BranchAndFinancialInstitutionIdentificationSEPA2">
+ <xs:sequence>
+ <xs:element name="FinInstnId" type="FinancialInstitutionIdentificationSEPA2"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="CashAccountSEPA1">
+ <xs:sequence>
+ <xs:element name="Id" type="AccountIdentificationSEPA"/>
+ <xs:element name="Ccy" type="ActiveOrHistoricCurrencyCode" minOccurs="0"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="CashAccountSEPA2">
+ <xs:sequence>
+ <xs:element name="Id" type="AccountIdentificationSEPA"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="CategoryPurposeSEPA">
+ <xs:sequence>
+ <xs:element name="Cd" type="ExternalCategoryPurpose1Code"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="ChargeBearerTypeSEPACode">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="SLEV"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="CountryCode">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="[A-Z]{2,2}"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="CreditorReferenceInformationSEPA1">
+ <xs:sequence>
+ <xs:element name="Tp" type="CreditorReferenceTypeSEPA"/>
+ <xs:element name="Ref" type="Max35Text">
+ <xs:annotation>
+ <xs:documentation>If a Creditor Reference contains a check digit, the receiving bank is not required to validate this.
+If the receiving bank validates the check digit and if this validation fails, the bank may continue its processing and send the transaction to the next party in the chain.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="CreditorReferenceTypeSEPA">
+ <xs:sequence>
+ <xs:element name="CdOrPrtry" type="CreditorReferenceTypeCodeSEPA"/>
+ <xs:element name="Issr" type="Max35Text" minOccurs="0"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="CreditorReferenceTypeCodeSEPA">
+ <xs:sequence>
+ <xs:element name="Cd" type="DocumentType3CodeSEPA"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="CustomerDirectDebitInitiationV02">
+ <xs:sequence>
+ <xs:element name="GrpHdr" type="GroupHeaderSDD"/>
+ <xs:element name="PmtInf" type="PaymentInstructionInformationSDD" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="DateAndPlaceOfBirth">
+ <xs:sequence>
+ <xs:element name="BirthDt" type="ISODate"/>
+ <xs:element name="PrvcOfBirth" type="Max35Text" minOccurs="0"/>
+ <xs:element name="CityOfBirth" type="Max35Text"/>
+ <xs:element name="CtryOfBirth" type="CountryCode"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="DecimalNumber">
+ <xs:restriction base="xs:decimal">
+ <xs:fractionDigits value="17"/>
+ <xs:totalDigits value="18"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="DirectDebitTransactionSDD">
+ <xs:sequence>
+ <xs:element name="MndtRltdInf" type="MandateRelatedInformationSDD"/>
+ <xs:element name="CdtrSchmeId" type="PartyIdentificationSEPA3" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>It is recommended that all transactions within the same ‘Payment Information’ block have the same ‘Creditor Scheme Identification’.
+This data element must be present at either ‘Payment Information’ or ‘Direct Debit
+Transaction’ level.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="DirectDebitTransactionInformationSDD">
+ <xs:sequence>
+ <xs:element name="PmtId" type="PaymentIdentificationSEPA"/>
+ <xs:element name="InstdAmt" type="ActiveOrHistoricCurrencyAndAmountSEPA"/>
+ <xs:element name="ChrgBr" type="ChargeBearerTypeSEPACode" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>It is recommended that this element be specified at ‘Payment Information’ level.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="DrctDbtTx" type="DirectDebitTransactionSDD"/>
+ <xs:element name="UltmtCdtr" type="PartyIdentificationSEPA1" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>This data element may be present either at ‘Payment Information’ or at ‘Direct Debit Transaction Information’ level.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="DbtrAgt" type="BranchAndFinancialInstitutionIdentificationSEPA3"/>
+ <xs:element name="Dbtr" type="PartyIdentificationSEPA2"/>
+ <xs:element name="DbtrAcct" type="CashAccountSEPA2"/>
+ <xs:element name="UltmtDbtr" type="PartyIdentificationSEPA1" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>Mandatory if provided by the debtor in the mandate.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="Purp" type="PurposeSEPA" minOccurs="0"/>
+ <xs:element name="RmtInf" type="RemittanceInformationSEPA1Choice" minOccurs="0"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="Document">
+ <xs:sequence>
+ <xs:element name="CstmrDrctDbtInitn" type="CustomerDirectDebitInitiationV02"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="DocumentType3CodeSEPA">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="SCOR"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="ExternalCategoryPurpose1Code">
+ <xs:restriction base="xs:string">
+ <xs:minLength value="1"/>
+ <xs:maxLength value="4"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="ExternalLocalInstrument1Code">
+ <xs:restriction base="xs:string">
+ <xs:minLength value="1"/>
+ <xs:maxLength value="35"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="ExternalOrganisationIdentification1Code">
+ <xs:restriction base="xs:string">
+ <xs:minLength value="1"/>
+ <xs:maxLength value="4"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="ExternalPersonIdentification1Code">
+ <xs:restriction base="xs:string">
+ <xs:minLength value="1"/>
+ <xs:maxLength value="4"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="ExternalPurpose1Code">
+ <xs:restriction base="xs:string">
+ <xs:minLength value="1"/>
+ <xs:maxLength value="4"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="ExternalServiceLevel1Code">
+ <xs:restriction base="xs:string">
+ <xs:minLength value="1"/>
+ <xs:maxLength value="4"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="FinancialInstitutionIdentificationSEPA3">
+ <xs:sequence>
+ <xs:choice>
+ <xs:element name="BIC" type="BICIdentifier"/>
+ <xs:element name="Othr" type="OthrIdentification"/>
+ </xs:choice>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="OthrIdentification">
+ <xs:sequence>
+ <xs:element name="Id" type="OthrIdentificationCode"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="OthrIdentificationCode">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="NOTPROVIDED"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="FinancialInstitutionIdentificationSEPA2">
+ <xs:sequence>
+ <xs:element name="Othr" type="RestrictedFinancialIdentificationSEPA"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="RestrictedFinancialIdentificationSEPA">
+ <xs:sequence>
+ <xs:element name="Id" type="RestrictedSMNDACode"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="RestrictedSMNDACode">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="SMNDA"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="GenericOrganisationIdentification1">
+ <xs:sequence>
+ <xs:element name="Id" type="Max35Text"/>
+ <xs:element name="SchmeNm" type="OrganisationIdentificationSchemeName1Choice" minOccurs="0"/>
+ <xs:element name="Issr" type="Max35Text" minOccurs="0"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="GenericPersonIdentification1">
+ <xs:sequence>
+ <xs:element name="Id" type="Max35Text"/>
+ <xs:element name="SchmeNm" type="PersonIdentificationSchemeName1Choice" minOccurs="0"/>
+ <xs:element name="Issr" type="Max35Text" minOccurs="0"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="RestrictedPersonIdentificationSEPA">
+ <xs:sequence>
+ <xs:element name="Id" type="RestrictedPersonIdentifierSEPA"/>
+ <xs:element name="SchmeNm" type="RestrictedPersonIdentificationSchemeNameSEPA"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="RestrictedPersonIdentifierSEPA">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="[a-zA-Z]{2,2}[0-9]{2,2}([A-Za-z0-9]|[\+|\?|/|\-|:|\(|\)|\.|,|']){3,3}([A-Za-z0-9]|[\+|\?|/|\-|:|\(|\)|\.|,|']){1,28}"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="GroupHeaderSDD">
+ <xs:sequence>
+ <xs:element name="MsgId" type="RestrictedIdentificationSEPA1"/>
+ <xs:element name="CreDtTm" type="ISODateTime"/>
+ <xs:element name="NbOfTxs" type="Max15NumericText"/>
+ <xs:element name="CtrlSum" type="DecimalNumber" minOccurs="0"/>
+ <xs:element name="InitgPty" type="PartyIdentificationSEPA1"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="IBAN2007Identifier">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="[A-Z]{2,2}[0-9]{2,2}[a-zA-Z0-9]{1,30}"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="ISODate">
+ <xs:restriction base="xs:date"/>
+ </xs:simpleType>
+ <xs:simpleType name="ISODateTime">
+ <xs:restriction base="xs:dateTime"/>
+ </xs:simpleType>
+ <xs:complexType name="LocalInstrumentSEPA">
+ <xs:sequence>
+ <xs:element name="Cd" type="ExternalLocalInstrument1Code"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="MandateRelatedInformationSDD">
+ <xs:sequence>
+ <xs:element name="MndtId" type="RestrictedIdentificationSEPA2"/>
+ <xs:element name="DtOfSgntr" type="ISODate"/>
+ <xs:element name="AmdmntInd" type="TrueFalseIndicator" minOccurs="0"/>
+ <xs:element name="AmdmntInfDtls" type="AmendmentInformationDetailsSDD" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>Mandatory if 'Amendment Indicator' is 'TRUE'
+The reason code from the Rulebook is indicated using one of the following message subelements.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="ElctrncSgntr" type="Max1025Text" minOccurs="0"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="Max1025Text">
+ <xs:restriction base="xs:string">
+ <xs:minLength value="1"/>
+ <xs:maxLength value="1025"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="Max140Text">
+ <xs:restriction base="xs:string">
+ <xs:minLength value="1"/>
+ <xs:maxLength value="140"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="Max15NumericText">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="[0-9]{1,15}"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="Max35Text">
+ <xs:restriction base="xs:string">
+ <xs:minLength value="1"/>
+ <xs:maxLength value="35"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="Max70Text">
+ <xs:restriction base="xs:string">
+ <xs:minLength value="1"/>
+ <xs:maxLength value="70"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="OrganisationIdentificationSEPAChoice">
+ <xs:sequence>
+ <xs:choice>
+ <xs:element name="BICOrBEI" type="AnyBICIdentifier"/>
+ <xs:element name="Othr" type="GenericOrganisationIdentification1"/>
+ </xs:choice>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="OrganisationIdentificationSchemeName1Choice">
+ <xs:sequence>
+ <xs:choice>
+ <xs:element name="Cd" type="ExternalOrganisationIdentification1Code"/>
+ <xs:element name="Prtry" type="Max35Text"/>
+ </xs:choice>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="PartySEPAChoice">
+ <xs:sequence>
+ <xs:choice>
+ <xs:element name="OrgId" type="OrganisationIdentificationSEPAChoice">
+ <xs:annotation>
+ <xs:documentation>Either ‘BIC or BEI’ or one
+occurrence of ‘Other’ is allowed.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="PrvtId" type="PersonIdentificationSEPA1Choice">
+ <xs:annotation>
+ <xs:documentation>Either ‘Date and Place of Birth’ or one occurrence of ‘Other’ is allowed</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ </xs:choice>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="PartySEPA2">
+ <xs:sequence>
+ <xs:element name="PrvtId" type="PersonIdentificationSEPA2">
+ <xs:annotation>
+ <xs:documentation>Private Identification is used to identify either an organisation or a private
+person.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="PartyIdentificationSEPA1">
+ <xs:sequence>
+ <xs:element name="Nm" type="Max70Text" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>‘Name’ is limited to 70 characters in length.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="Id" type="PartySEPAChoice" minOccurs="0"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="PartyIdentificationSEPA2">
+ <xs:sequence>
+ <xs:element name="Nm" type="Max70Text">
+ <xs:annotation>
+ <xs:documentation>‘Name’ is limited to 70 characters in length.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="PstlAdr" type="PostalAddressSEPA" minOccurs="0"/>
+ <xs:element name="Id" type="PartySEPAChoice" minOccurs="0"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="PartyIdentificationSEPA3">
+ <xs:sequence>
+ <xs:element name="Id" type="PartySEPA2"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="PartyIdentificationSEPA4">
+ <xs:sequence>
+ <xs:element name="Nm" type="Max70Text" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>If present the new’ Name’ must be specified under ‘Creditor’. ‘Name’ is limited to 70 characters in length.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="Id" type="PartySEPA2" minOccurs="0"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="PartyIdentificationSEPA5">
+ <xs:sequence>
+ <xs:element name="Nm" type="Max70Text">
+ <xs:annotation>
+ <xs:documentation>‘Name’ is limited to 70 characters in length.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="PstlAdr" type="PostalAddressSEPA" minOccurs="0"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="PaymentIdentificationSEPA">
+ <xs:sequence>
+ <xs:element name="InstrId" type="RestrictedIdentificationSEPA1" minOccurs="0"/>
+ <xs:element name="EndToEndId" type="RestrictedIdentificationSEPA1"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="PaymentInstructionInformationSDD">
+ <xs:sequence>
+ <xs:element name="PmtInfId" type="RestrictedIdentificationSEPA1"/>
+ <xs:element name="PmtMtd" type="PaymentMethod2Code"/>
+ <xs:element name="BtchBookg" type="BatchBookingIndicator" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>If present and contains ‘true’, batch booking is requested. If present and contains ‘false’, booking per transaction is requested. If element is not present, pre-agreed customer-to-bank conditions apply.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="NbOfTxs" type="Max15NumericText" minOccurs="0"/>
+ <xs:element name="CtrlSum" type="DecimalNumber" minOccurs="0"/>
+ <xs:element name="PmtTpInf" type="PaymentTypeInformationSDD"/>
+ <xs:element name="ReqdColltnDt" type="ISODate"/>
+ <xs:element name="Cdtr" type="PartyIdentificationSEPA5"/>
+ <xs:element name="CdtrAcct" type="CashAccountSEPA1"/>
+ <xs:element name="CdtrAgt" type="BranchAndFinancialInstitutionIdentificationSEPA3"/>
+ <xs:element name="UltmtCdtr" type="PartyIdentificationSEPA1" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>This data element may be present either at ‘Payment Information’ or at ‘Direct Debit Transaction Information’ level.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="ChrgBr" type="ChargeBearerTypeSEPACode" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>It is recommended that this element be specified at ‘Payment Information’ level.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="CdtrSchmeId" type="PartyIdentificationSEPA3" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>It is recommended that all transactions within the same ‘Payment Information’ block have the same ‘Creditor Scheme Identification’.
+This data element must be present at either ‘Payment Information’ or ‘Direct Debit
+Transaction’ level.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="DrctDbtTxInf" type="DirectDebitTransactionInformationSDD" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="PaymentMethod2Code">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="DD"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="PaymentTypeInformationSDD">
+ <xs:sequence>
+ <xs:element name="SvcLvl" type="ServiceLevelSEPA"/>
+ <xs:element name="LclInstrm" type="LocalInstrumentSEPA">
+ <xs:annotation>
+ <xs:documentation>Only ‘B2B’, 'CORE' or 'COR1' is allowed. The mixing of different Local Instrument values is not allowed in the same message.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="SeqTp" type="SequenceType1Code">
+ <xs:annotation>
+ <xs:documentation>If 'Amendment Indicator' is 'true' and 'Original Debtor Agent' is set to 'SMNDA' this message element must indicate 'FRST'</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="CtgyPurp" type="CategoryPurposeSEPA" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>Depending on the agreement between the Creditor and the Creditor Bank, ‘Category Purpose’ may be forwarded to the Debtor Bank.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="PersonIdentificationSEPA1Choice">
+ <xs:sequence>
+ <xs:choice>
+ <xs:element name="DtAndPlcOfBirth" type="DateAndPlaceOfBirth"/>
+ <xs:element name="Othr" type="GenericPersonIdentification1"/>
+ </xs:choice>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="PersonIdentificationSEPA2">
+ <xs:sequence>
+ <xs:element name="Othr" type="RestrictedPersonIdentificationSEPA">
+ <xs:annotation>
+ <xs:documentation>Only one occurrence of ‘Other’ is allowed, and no other sub-elements are allowed.
+Identification must be used with an identifier described in General Message Element Specifications, Chapter 1.5.2 of the Implementation Guide.
+Scheme Name’ under ‘Other’ must specify ‘SEPA’ under ‘Proprietary</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="PersonIdentificationSchemeName1Choice">
+ <xs:sequence>
+ <xs:choice>
+ <xs:element name="Cd" type="ExternalPersonIdentification1Code"/>
+ <xs:element name="Prtry" type="Max35Text"/>
+ </xs:choice>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="RestrictedPersonIdentificationSchemeNameSEPA">
+ <xs:sequence>
+ <xs:element name="Prtry" type="IdentificationSchemeNameSEPA"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="IdentificationSchemeNameSEPA">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="SEPA"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="PostalAddressSEPA">
+ <xs:sequence>
+ <xs:element name="Ctry" type="CountryCode" minOccurs="0"/>
+ <xs:element name="AdrLine" type="Max70Text" minOccurs="0" maxOccurs="2"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="PurposeSEPA">
+ <xs:sequence>
+ <xs:element name="Cd" type="ExternalPurpose1Code">
+ <xs:annotation>
+ <xs:documentation>Only codes from the ISO 20022 ExternalPurposeCode list are allowed.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="RemittanceInformationSEPA1Choice">
+ <xs:sequence>
+ <xs:choice>
+ <xs:element name="Ustrd" type="Max140Text"/>
+ <xs:element name="Strd" type="StructuredRemittanceInformationSEPA1"/>
+ </xs:choice>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="SequenceType1Code">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="FRST"/>
+ <xs:enumeration value="RCUR"/>
+ <xs:enumeration value="FNAL"/>
+ <xs:enumeration value="OOFF"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="ServiceLevelSEPA">
+ <xs:sequence>
+ <xs:element name="Cd" type="ExternalServiceLevel1Code"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="StructuredRemittanceInformationSEPA1">
+ <xs:sequence>
+ <xs:element name="CdtrRefInf" type="CreditorReferenceInformationSEPA1" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>When present, the receiving bank is not obliged to validate the reference information.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="TrueFalseIndicator">
+ <xs:restriction base="xs:boolean"/>
+ </xs:simpleType>
+ <xs:simpleType name="RestrictedIdentificationSEPA1">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="([A-Za-z0-9]|[\+|\?|/|\-|:|\(|\)|\.|,|'| ]){1,35}"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="RestrictedIdentificationSEPA2">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="([A-Za-z0-9]|[\+|\?|/|\-|:|\(|\)|\.|,|']){1,35}"/>
+ </xs:restriction>
+ </xs:simpleType>
+</xs:schema>
diff --git a/tests/test_account_payment_sepa.py b/tests/test_account_payment_sepa.py
index 9b1658a..f688c65 100644
--- a/tests/test_account_payment_sepa.py
+++ b/tests/test_account_payment_sepa.py
@@ -1,5 +1,5 @@
-#This file is part of Tryton. The COPYRIGHT file at the top level of
-#this repository contains the full copyright notices and license terms.
+# This file is part of Tryton. The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
import os
import unittest
import doctest
@@ -11,165 +11,191 @@ from io import BytesIO
from mock import Mock, patch
import trytond.tests.test_tryton
-from trytond.tests.test_tryton import test_view, test_depends
-from trytond.tests.test_tryton import POOL, DB_NAME, USER, CONTEXT
+from trytond.tests.test_tryton import ModuleTestCase
+from trytond.tests.test_tryton import DB_NAME, USER, CONTEXT
from trytond.transaction import Transaction
from trytond.exceptions import UserError
from trytond.modules.account_payment_sepa.payment import CAMT054
-
-
-class AccountPaymentSepaTestCase(unittest.TestCase):
+from trytond.pool import Pool
+
+
+def setup_environment():
+ pool = Pool()
+ Address = pool.get('party.address')
+ Company = pool.get('company.company')
+ Currency = pool.get('currency.currency')
+ Party = pool.get('party.party')
+ Bank = pool.get('bank')
+
+ company, = Company.search([
+ ('rec_name', '=', 'Dunder Mifflin'),
+ ])
+ euro, = Currency.create([{
+ 'name': 'Euro',
+ 'symbol': 'EUR',
+ 'code': 'EUR',
+ }])
+ company.currency = euro
+ company.party.sepa_creditor_identifier = 'BE68539007547034'
+ company.party.save()
+ company.save()
+ bank_party = Party(name='European Bank')
+ bank_party.save()
+ bank = Bank(party=bank_party, bic='BICODEBBXXX')
+ bank.save()
+ customer = Party(name='Customer')
+ address = Address(street='street', streetbis='street bis',
+ zip='1234', city='City')
+ customer.addresses = [address]
+ customer.save()
+ return {
+ 'company': company,
+ 'bank': bank,
+ 'customer': customer,
+ }
+
+
+def setup_accounts(bank, company, customer):
+ pool = Pool()
+ Account = pool.get('bank.account')
+ return Account.create([{
+ 'bank': bank,
+ 'owners': [('add', [company.party])],
+ 'currency': company.currency.id,
+ 'numbers': [('create', [{
+ 'type': 'iban',
+ 'number': 'ES8200000000000000000000',
+ }])]}, {
+ 'bank': bank,
+ 'owners': [('add', [customer])],
+ 'currency': company.currency.id,
+ 'numbers': [('create', [{
+ 'type': 'iban',
+ 'number': 'ES3600000000050000000001',
+ }])]}])
+
+
+def setup_mandate(company, customer, account):
+ pool = Pool()
+ Mandate = pool.get('account.payment.sepa.mandate')
+ Date = pool.get('ir.date')
+ return Mandate.create([{
+ 'company': company,
+ 'party': customer,
+ 'account_number': account.numbers[0],
+ 'identification': 'MANDATE',
+ 'type': 'recurrent',
+ 'signature_date': Date.today(),
+ 'state': 'validated',
+ }])[0]
+
+
+def setup_journal(flavor, kind, company, account):
+ pool = Pool()
+ Journal = pool.get('account.payment.journal')
+ journal = Journal()
+ journal.name = flavor
+ journal.company = company
+ journal.currency = company.currency
+ journal.process_method = 'sepa'
+ journal.sepa_bank_account_number = account.numbers[0]
+ journal.sepa_payable_flavor = 'pain.001.001.03'
+ journal.sepa_receivable_flavor = 'pain.008.001.02'
+ setattr(journal, 'sepa_%s_flavor' % kind, flavor)
+ journal.save()
+ return journal
+
+
+def validate_file(flavor, kind, xsd=None):
+ 'Test generated files are valid'
+ pool = Pool()
+ Payment = pool.get('account.payment')
+ PaymentGroup = pool.get('account.payment.group')
+ Date = pool.get('ir.date')
+ ProcessPayment = pool.get('account.payment.process', type='wizard')
+
+ if xsd is None:
+ xsd = flavor
+
+ environment = setup_environment()
+ company = environment['company']
+ bank = environment['bank']
+ customer = environment['customer']
+ company_account, customer_account = setup_accounts(
+ bank, company, customer)
+ setup_mandate(company, customer, customer_account)
+ journal = setup_journal(flavor, kind, company, company_account)
+
+ payment, = Payment.create([{
+ 'company': company,
+ 'party': customer,
+ 'journal': journal,
+ 'kind': kind,
+ 'amount': Decimal('1000.0'),
+ 'state': 'approved',
+ 'description': 'PAYMENT',
+ 'date': Date.today(),
+ }])
+
+ session_id, _, _ = ProcessPayment.create()
+ process_payment = ProcessPayment(session_id)
+ with Transaction().set_context(active_ids=[payment.id]):
+ _, data = process_payment.do_process(None)
+ group, = PaymentGroup.browse(data['res_id'])
+ message, = group.sepa_messages
+ assert message.type == 'out', message.type
+ assert message.state == 'waiting', message.state
+ sepa_string = message.message.encode('utf-8')
+ sepa_xml = etree.fromstring(sepa_string)
+ schema_file = os.path.join(os.path.dirname(__file__),
+ '%s.xsd' % xsd)
+ schema = etree.XMLSchema(etree.parse(schema_file))
+ schema.assertValid(sepa_xml)
+
+
+class AccountPaymentSepaTestCase(ModuleTestCase):
'Test Account Payment SEPA module'
-
- def setUp(self):
- trytond.tests.test_tryton.install_module('account_payment_sepa')
- self.bank = POOL.get('bank')
- self.bank_account = POOL.get('bank.account')
- self.bank_number = POOL.get('bank.account.number')
- self.company = POOL.get('company.company')
- self.currency = POOL.get('currency.currency')
- self.date = POOL.get('ir.date')
- self.mandate = POOL.get('account.payment.sepa.mandate')
- self.party = POOL.get('party.party')
- self.payment = POOL.get('account.payment')
- self.payment_group = POOL.get('account.payment.group')
- self.payment_journal = POOL.get('account.payment.journal')
- self.process_payment = POOL.get('account.payment.process',
- type='wizard')
- self.user = POOL.get('res.user')
-
- def test0005views(self):
- 'Test views'
- test_view('account_payment_sepa')
-
- def test0006depends(self):
- 'Test depends'
- test_depends()
-
- def setup_environment(self):
- company, = self.company.search([
- ('rec_name', '=', 'Dunder Mifflin'),
- ])
- euro, = self.currency.create([{
- 'name': 'Euro',
- 'symbol': 'EUR',
- 'code': 'EUR',
- }])
- company.currency = euro
- company.party.sepa_creditor_identifier = 'BE68539007547034'
- company.party.save()
- company.save()
- bank_party = self.party(name='European Bank')
- bank_party.save()
- bank = self.bank(party=bank_party, bic='BICODEBBXXX')
- bank.save()
- customer = self.party(name='Customer')
- customer.save()
- return {
- 'company': company,
- 'bank': bank,
- 'customer': customer,
- }
-
- def setup_accounts(self, bank, company, customer):
- return self.bank_account.create([{
- 'bank': bank,
- 'owners': [('add', [company.party])],
- 'numbers': [('create', [{
- 'type': 'iban',
- 'number': 'ES8200000000000000000000',
- }])]}, {
- 'bank': bank,
- 'owners': [('add', [customer])],
- 'numbers': [('create', [{
- 'type': 'iban',
- 'number': 'ES3600000000050000000001',
- }])]}])
-
- def setup_mandate(self, company, customer, account):
- return self.mandate.create([{
- 'company': company,
- 'party': customer,
- 'account_number': account.numbers[0],
- 'identification': 'MANDATE',
- 'type': 'recurrent',
- 'signature_date': self.date.today(),
- 'state': 'validated',
- }])[0]
-
- def setup_journal(self, flavor, kind, company, account):
- journal = self.payment_journal()
- journal.name = flavor
- journal.company = company
- journal.currency = company.currency
- journal.process_method = 'sepa'
- journal.sepa_bank_account_number = account.numbers[0]
- journal.sepa_payable_flavor = 'pain.001.001.03'
- journal.sepa_receivable_flavor = 'pain.008.001.02'
- setattr(journal, 'sepa_%s_flavor' % kind, flavor)
- journal.save()
- return journal
-
- def validate_file(self, flavor, kind):
- 'Test generated files are valid'
- with Transaction().start(DB_NAME, USER, context=CONTEXT):
- environment = self.setup_environment()
- company = environment['company']
- bank = environment['bank']
- customer = environment['customer']
- company_account, customer_account = self.setup_accounts(bank,
- company, customer)
- self.setup_mandate(company, customer, customer_account)
- journal = self.setup_journal(flavor, kind, company,
- company_account)
-
- payment, = self.payment.create([{
- 'company': company,
- 'party': customer,
- 'journal': journal,
- 'kind': kind,
- 'amount': Decimal('1000.0'),
- 'state': 'approved',
- 'description': 'PAYMENT',
- 'date': self.date.today(),
- }])
-
- session_id, _, _ = self.process_payment.create()
- process_payment = self.process_payment(session_id)
- with Transaction().set_context(active_ids=[payment.id]):
- _, data = process_payment.do_process(None)
- group, = self.payment_group.browse(data['res_id'])
- message, = group.sepa_messages
- sepa_string = message.message.encode('utf-8')
- sepa_xml = etree.fromstring(sepa_string)
- schema_file = os.path.join(os.path.dirname(__file__),
- '%s.xsd' % flavor)
- schema = etree.XMLSchema(etree.parse(schema_file))
- schema.assertValid(sepa_xml)
+ module = 'account_payment_sepa'
def test_pain001_001_03(self):
'Test pain001.001.03 xsd validation'
- self.validate_file('pain.001.001.03', 'payable')
+ with Transaction().start(DB_NAME, USER, context=CONTEXT):
+ validate_file('pain.001.001.03', 'payable')
def test_pain001_001_05(self):
'Test pain001.001.05 xsd validation'
- self.validate_file('pain.001.001.05', 'payable')
+ with Transaction().start(DB_NAME, USER, context=CONTEXT):
+ validate_file('pain.001.001.05', 'payable')
+
+ def test_pain001_003_03(self):
+ 'Test pain001.003.03 xsd validation'
+ with Transaction().start(DB_NAME, USER, context=CONTEXT):
+ validate_file('pain.001.003.03', 'payable')
def test_pain008_001_02(self):
'Test pain008.001.02 xsd validation'
- self.validate_file('pain.008.001.02', 'receivable')
+ with Transaction().start(DB_NAME, USER, context=CONTEXT):
+ validate_file('pain.008.001.02', 'receivable')
def test_pain008_001_04(self):
'Test pain008.001.04 xsd validation'
- self.validate_file('pain.008.001.04', 'receivable')
+ with Transaction().start(DB_NAME, USER, context=CONTEXT):
+ validate_file('pain.008.001.04', 'receivable')
+
+ def test_pain008_003_02(self):
+ 'Test pain008.003.02 xsd validation'
+ with Transaction().start(DB_NAME, USER, context=CONTEXT):
+ validate_file('pain.008.003.02', 'receivable')
def test_sepa_mandate_sequence(self):
'Test SEPA mandate sequence'
- Configuration = POOL.get('account.configuration')
- Sequence = POOL.get('ir.sequence')
- Party = POOL.get('party.party')
- Mandate = POOL.get('account.payment.sepa.mandate')
with Transaction().start(DB_NAME, USER, context=CONTEXT):
+ pool = Pool()
+ Configuration = pool.get('account.configuration')
+ Sequence = pool.get('ir.sequence')
+ Party = pool.get('party.party')
+ Mandate = pool.get('account.payment.sepa.mandate')
+
party = Party(name='Test')
party.save()
mandate = Mandate(party=party)
@@ -189,10 +215,13 @@ class AccountPaymentSepaTestCase(unittest.TestCase):
def test_identification_unique(self):
'Test unique identification constraint'
- Party = POOL.get('party.party')
- Mandate = POOL.get('account.payment.sepa.mandate')
- same_id = '1'
with Transaction().start(DB_NAME, USER, context=CONTEXT):
+ pool = Pool()
+ Party = pool.get('party.party')
+ Mandate = pool.get('account.payment.sepa.mandate')
+
+ same_id = '1'
+
party = Party(name='Test')
party.save()
mandate = Mandate(party=party, identification=same_id)
@@ -219,11 +248,12 @@ class AccountPaymentSepaTestCase(unittest.TestCase):
def test_payment_sepa_bank_account_number(self):
'Test Payment.sepa_bank_account_number'
with Transaction().start(DB_NAME, USER, context=CONTEXT):
- Payment = POOL.get('account.payment')
- Mandate = POOL.get('account.payment.sepa.mandate')
- AccountNumber = POOL.get('bank.account.number')
- Party = POOL.get('party.party')
- BankAccount = POOL.get('bank.account')
+ pool = Pool()
+ Payment = pool.get('account.payment')
+ Mandate = pool.get('account.payment.sepa.mandate')
+ AccountNumber = pool.get('bank.account.number')
+ Party = pool.get('party.party')
+ BankAccount = pool.get('bank.account')
account_number = AccountNumber()
mandate = Mandate(account_number=account_number)
@@ -246,17 +276,22 @@ class AccountPaymentSepaTestCase(unittest.TestCase):
def test_payment_sequence_type(self):
'Test payment sequence type'
with Transaction().start(DB_NAME, USER, context=CONTEXT):
- environment = self.setup_environment()
+ pool = Pool()
+ Date = pool.get('ir.date')
+ Payment = pool.get('account.payment')
+ ProcessPayment = pool.get('account.payment.process', type='wizard')
+
+ environment = setup_environment()
company = environment['company']
bank = environment['bank']
customer = environment['customer']
- company_account, customer_account = self.setup_accounts(bank,
- company, customer)
- self.setup_mandate(company, customer, customer_account)
- journal = self.setup_journal('pain.008.001.02', 'receivable',
+ company_account, customer_account = setup_accounts(
+ bank, company, customer)
+ setup_mandate(company, customer, customer_account)
+ journal = setup_journal('pain.008.001.02', 'receivable',
company, company_account)
- payment, = self.payment.create([{
+ payment, = Payment.create([{
'company': company,
'party': customer,
'journal': journal,
@@ -264,17 +299,17 @@ class AccountPaymentSepaTestCase(unittest.TestCase):
'amount': Decimal('1000.0'),
'state': 'approved',
'description': 'PAYMENT',
- 'date': self.date.today(),
+ 'date': Date.today(),
}])
- session_id, _, _ = self.process_payment.create()
- process_payment = self.process_payment(session_id)
+ session_id, _, _ = ProcessPayment.create()
+ process_payment = ProcessPayment(session_id)
with Transaction().set_context(active_ids=[payment.id]):
_, data = process_payment.do_process(None)
self.assertEqual(payment.sepa_mandate_sequence_type, 'FRST')
- payments = self.payment.create([{
+ payments = Payment.create([{
'company': company,
'party': customer,
'journal': journal,
@@ -282,7 +317,7 @@ class AccountPaymentSepaTestCase(unittest.TestCase):
'amount': Decimal('2000.0'),
'state': 'approved',
'description': 'PAYMENT',
- 'date': self.date.today(),
+ 'date': Date.today(),
}, {
'company': company,
'party': customer,
@@ -291,12 +326,12 @@ class AccountPaymentSepaTestCase(unittest.TestCase):
'amount': Decimal('3000.0'),
'state': 'approved',
'description': 'PAYMENT',
- 'date': self.date.today(),
+ 'date': Date.today(),
},
])
- session_id, _, _ = self.process_payment.create()
- process_payment = self.process_payment(session_id)
+ session_id, _, _ = ProcessPayment.create()
+ process_payment = ProcessPayment(session_id)
payment_ids = [p.id for p in payments]
with Transaction().set_context(active_ids=payment_ids):
_, data = process_payment.do_process(None)
@@ -307,7 +342,8 @@ class AccountPaymentSepaTestCase(unittest.TestCase):
def handle_camt054(self, flavor):
'Handle camt.054'
with Transaction().start(DB_NAME, USER, context=CONTEXT):
- Message = POOL.get('account.payment.sepa.message')
+ pool = Pool()
+ Message = pool.get('account.payment.sepa.message')
message_file = os.path.join(os.path.dirname(__file__),
'%s.xml' % flavor)
@@ -335,7 +371,7 @@ class AccountPaymentSepaTestCase(unittest.TestCase):
is_returned.return_value = True
handler = CAMT054(BytesIO(message), Payment)
- payment.save.assert_called_with()
+ Payment.save.assert_called_with([payment])
Payment.fail.assert_called_with([payment])
def test_camt054_001_01(self):
@@ -354,6 +390,24 @@ class AccountPaymentSepaTestCase(unittest.TestCase):
'Test camt.054.001.04 handling'
self.handle_camt054('camt.054.001.04')
+ def test_sepa_mandate_report(self):
+ 'Test sepa mandate report'
+ with Transaction().start(DB_NAME, USER, context=CONTEXT):
+ pool = Pool()
+ Report = pool.get('account.payment.sepa.mandate', type='report')
+
+ environment = setup_environment()
+ company = environment['company']
+ bank = environment['bank']
+ customer = environment['customer']
+ company_account, customer_account = setup_accounts(
+ bank, company, customer)
+ mandate = setup_mandate(company, customer, customer_account)
+
+ oext, content, _, _ = Report.execute([mandate.id], {})
+ self.assertEqual(oext, 'odt')
+ self.assertTrue(content)
+
def suite():
suite = trytond.tests.test_tryton.suite()
diff --git a/tryton.cfg b/tryton.cfg
index ff9390b..d842ac8 100644
--- a/tryton.cfg
+++ b/tryton.cfg
@@ -1,11 +1,13 @@
[tryton]
-version=3.4.1
+version=3.6.0
depends:
account_payment
company
ir
bank
party
+extra_depends:
+ account_payment_clearing
xml:
payment.xml
party.xml
diff --git a/trytond_account_payment_sepa.egg-info/PKG-INFO b/trytond_account_payment_sepa.egg-info/PKG-INFO
index b2371b2..0d8e740 100644
--- a/trytond_account_payment_sepa.egg-info/PKG-INFO
+++ b/trytond_account_payment_sepa.egg-info/PKG-INFO
@@ -1,12 +1,12 @@
Metadata-Version: 1.1
Name: trytond-account-payment-sepa
-Version: 3.4.1
+Version: 3.6.0
Summary: Tryton module for SEPA payment
Home-page: http://www.tryton.org/
Author: Tryton
Author-email: issue_tracker at tryton.org
License: GPL-3
-Download-URL: http://downloads.tryton.org/3.4/
+Download-URL: http://downloads.tryton.org/3.6/
Description: trytond_account_payment_sepa
============================
@@ -64,5 +64,7 @@ Classifier: Natural Language :: Slovenian
Classifier: Natural Language :: Spanish
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: Implementation :: CPython
+Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Topic :: Office/Business
Classifier: Topic :: Office/Business :: Financial :: Accounting
diff --git a/trytond_account_payment_sepa.egg-info/SOURCES.txt b/trytond_account_payment_sepa.egg-info/SOURCES.txt
index 317be22..bff80a2 100644
--- a/trytond_account_payment_sepa.egg-info/SOURCES.txt
+++ b/trytond_account_payment_sepa.egg-info/SOURCES.txt
@@ -28,11 +28,14 @@ tryton.cfg
./locale/es_ES.po
./locale/fr_FR.po
./locale/sl_SI.po
+./template/base.003.xml
./template/base.xml
./template/pain.001.001.03.xml
./template/pain.001.001.05.xml
+./template/pain.001.003.03.xml
./template/pain.008.001.02.xml
./template/pain.008.001.04.xml
+./template/pain.008.003.02.xml
./tests/__init__.py
./tests/camt.054.001.01.xsd
./tests/camt.054.001.02.xsd
@@ -40,8 +43,10 @@ tryton.cfg
./tests/camt.054.001.04.xsd
./tests/pain.001.001.03.xsd
./tests/pain.001.001.05.xsd
+./tests/pain.001.003.03.xsd
./tests/pain.008.001.02.xsd
./tests/pain.008.001.04.xsd
+./tests/pain.008.003.02.xsd
./tests/test_account_payment_sepa.py
./view/configuration_form.xml
./view/mandate_form.xml
@@ -61,19 +66,24 @@ locale/es_EC.po
locale/es_ES.po
locale/fr_FR.po
locale/sl_SI.po
+template/base.003.xml
template/base.xml
template/pain.001.001.03.xml
template/pain.001.001.05.xml
+template/pain.001.003.03.xml
template/pain.008.001.02.xml
template/pain.008.001.04.xml
+template/pain.008.003.02.xml
tests/camt.054.001.01.xsd
tests/camt.054.001.02.xsd
tests/camt.054.001.03.xsd
tests/camt.054.001.04.xsd
tests/pain.001.001.03.xsd
tests/pain.001.001.05.xsd
+tests/pain.001.003.03.xsd
tests/pain.008.001.02.xsd
tests/pain.008.001.04.xsd
+tests/pain.008.003.02.xsd
trytond_account_payment_sepa.egg-info/PKG-INFO
trytond_account_payment_sepa.egg-info/SOURCES.txt
trytond_account_payment_sepa.egg-info/dependency_links.txt
diff --git a/trytond_account_payment_sepa.egg-info/requires.txt b/trytond_account_payment_sepa.egg-info/requires.txt
index d610120..643da8e 100644
--- a/trytond_account_payment_sepa.egg-info/requires.txt
+++ b/trytond_account_payment_sepa.egg-info/requires.txt
@@ -1,7 +1,8 @@
Genshi
lxml
-trytond_account_payment >= 3.4, < 3.5
-trytond_company >= 3.4, < 3.5
-trytond_bank >= 3.4, < 3.5
-trytond_party >= 3.4, < 3.5
-trytond >= 3.4, < 3.5
\ No newline at end of file
+python-dateutil
+trytond_account_payment >= 3.6, < 3.7
+trytond_company >= 3.6, < 3.7
+trytond_bank >= 3.6, < 3.7
+trytond_party >= 3.6, < 3.7
+trytond >= 3.6, < 3.7
\ No newline at end of file
diff --git a/view/payment_group_form.xml b/view/payment_group_form.xml
index 2a2a169..e2409eb 100644
--- a/view/payment_group_form.xml
+++ b/view/payment_group_form.xml
@@ -4,5 +4,6 @@ this repository contains the full copyright notices and license terms. -->
<data>
<xpath expr="/form/field[@name='kind']" position="after">
<field name="sepa_messages" colspan="4"/>
+ <button name="generate_message" string="Generate Message" colspan="4"/>
</xpath>
</data>
diff --git a/view/payment_journal_form.xml b/view/payment_journal_form.xml
index 0f2e1b1..c14b08c 100644
--- a/view/payment_journal_form.xml
+++ b/view/payment_journal_form.xml
@@ -3,8 +3,7 @@
this repository contains the full copyright notices and license terms. -->
<data>
<xpath expr="/form/field[@name='process_method']" position="after">
- <separator id="sepa" string="SEPA" colspan="4"
- states="{'invisible': Eval('process_method') != 'sepa'}"/>
+ <separator name="sepa_bank_account_number" string="SEPA" colspan="4"/>
<label name="sepa_bank_account_number"/>
<field name="sepa_bank_account_number"/>
<newline/>
--
tryton-modules-account-payment-sepa
More information about the tryton-debian-vcs
mailing list