diff --git a/account_banking_sepa_credit_transfer/README.rst b/account_banking_sepa_credit_transfer/README.rst index 209255356..746559822 100644 --- a/account_banking_sepa_credit_transfer/README.rst +++ b/account_banking_sepa_credit_transfer/README.rst @@ -11,10 +11,10 @@ SEPA PAIN (PAyment INitiation) is the new european standard for Customer-to-Bank payment instructions. This module implements SEPA Credit Transfer (SCT), more specifically PAIN versions 001.001.02, 001.001.03, 001.001.04 and 001.001.05. It is part of the ISO 20022 standard, available on -http://www.iso20022.org. +https://www.iso20022.org. The Implementation Guidelines for SEPA Credit Transfer published by the -European Payments Council (http://http://www.europeanpaymentscouncil.eu) use +European Payments Council (https://www.europeanpaymentscouncil.eu) use PAIN version 001.001.03, so it's probably the version of PAIN that you should try first. @@ -43,13 +43,13 @@ Configuration Usage ===== -In the menu *Accounting > Payments > Payment Order*, create a new +In the menu *Invoicing/Accounting > Payments > Payment Order*, create a new payment order and select the Payment Mode dedicated to SEPA Credit Transfer that you created during the configuration step. .. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas :alt: Try me on Runbot - :target: https://runbot.odoo-community.org/runbot/173/10.0 + :target: https://runbot.odoo-community.org/runbot/173/11.0 Known issues / Roadmap ====================== @@ -84,12 +84,12 @@ Contributors Maintainer ---------- -.. image:: http://odoo-community.org/logo.png +.. image:: https://odoo-community.org/logo.png :alt: Odoo Community Association - :target: http://odoo-community.org + :target: https://odoo-community.org This module is maintained by the OCA. OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use. -To contribute to this module, please visit http://odoo-community.org. +To contribute to this module, please visit https://odoo-community.org. diff --git a/account_banking_sepa_credit_transfer/__manifest__.py b/account_banking_sepa_credit_transfer/__manifest__.py index 6014c05d0..decd94359 100644 --- a/account_banking_sepa_credit_transfer/__manifest__.py +++ b/account_banking_sepa_credit_transfer/__manifest__.py @@ -2,12 +2,12 @@ # © 2010-2016 Akretion (www.akretion.com) # © 2014 Tecnativa - Pedro M. Baeza # © 2016 Tecnativa - Antonio Espinosa -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). { 'name': 'Account Banking SEPA Credit Transfer', 'summary': 'Create SEPA XML files for Credit Transfers', - 'version': '10.0.1.0.0', + 'version': '11.0.1.0.0', 'license': 'AGPL-3', 'author': "Akretion, " "Tecnativa, " diff --git a/account_banking_sepa_credit_transfer/models/account_payment_line.py b/account_banking_sepa_credit_transfer/models/account_payment_line.py index 009887250..4800b255a 100644 --- a/account_banking_sepa_credit_transfer/models/account_payment_line.py +++ b/account_banking_sepa_credit_transfer/models/account_payment_line.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # © 2017 Akretion - Alexis de Lattre -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). from odoo import models, fields diff --git a/account_banking_sepa_credit_transfer/models/account_payment_method.py b/account_banking_sepa_credit_transfer/models/account_payment_method.py index 99dc6d0bf..54d061e49 100644 --- a/account_banking_sepa_credit_transfer/models/account_payment_method.py +++ b/account_banking_sepa_credit_transfer/models/account_payment_method.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # © 2016 Akretion (Alexis de Lattre ) -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). from odoo import models, fields, api diff --git a/account_banking_sepa_credit_transfer/models/account_payment_order.py b/account_banking_sepa_credit_transfer/models/account_payment_order.py index f656a3bb9..f39f046e3 100644 --- a/account_banking_sepa_credit_transfer/models/account_payment_order.py +++ b/account_banking_sepa_credit_transfer/models/account_payment_order.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # © 2010-2016 Akretion (www.akretion.com) # © 2014 Serv. Tecnol. Avanzados - Pedro M. Baeza -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). from odoo import models, api, _ from odoo.exceptions import UserError @@ -19,11 +19,12 @@ class AccountPaymentOrder(models.Model): return super(AccountPaymentOrder, self).generate_payment_file() pain_flavor = self.payment_method_id.pain_version - if not pain_flavor: - pain_flavor = 'pain.001.001.03' # We use pain_flavor.startswith('pain.001.001.xx') # to support country-specific extensions such as # pain.001.001.03.ch.02 (cf l10n_ch_sepa) + if not pain_flavor: + raise UserError( + _("PAIN version '%s' is not supported.") % pain_flavor) if pain_flavor.startswith('pain.001.001.02'): bic_xml_tag = 'BIC' name_maxsize = 70 @@ -94,7 +95,7 @@ class AccountPaymentOrder(models.Model): else: lines_per_group[key] = [line] for (requested_date, priority, local_instrument, categ_purpose),\ - lines in lines_per_group.items(): + lines in list(lines_per_group.items()): # B. Payment info payment_info, nb_of_transactions_b, control_sum_b = \ self.generate_start_payment_info_block( @@ -155,12 +156,12 @@ class AccountPaymentOrder(models.Model): self.generate_remittance_info_block( credit_transfer_transaction_info, line, gen_args) if not pain_flavor.startswith('pain.001.001.02'): - nb_of_transactions_b.text = unicode(transactions_count_b) + nb_of_transactions_b.text = str(transactions_count_b) control_sum_b.text = '%.2f' % amount_control_sum_b if not pain_flavor.startswith('pain.001.001.02'): - nb_of_transactions_a.text = unicode(transactions_count_a) + nb_of_transactions_a.text = str(transactions_count_a) control_sum_a.text = '%.2f' % amount_control_sum_a else: - nb_of_transactions_a.text = unicode(transactions_count_a) + nb_of_transactions_a.text = str(transactions_count_a) control_sum_a.text = '%.2f' % amount_control_sum_a return self.finalize_sepa_file_creation(xml_root, gen_args) diff --git a/account_banking_sepa_credit_transfer/post_install.py b/account_banking_sepa_credit_transfer/post_install.py index 573ece934..b7c219e27 100644 --- a/account_banking_sepa_credit_transfer/post_install.py +++ b/account_banking_sepa_credit_transfer/post_install.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # © 2016 Akretion (Alexis de Lattre ) -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). from odoo import api, SUPERUSER_ID diff --git a/account_banking_sepa_credit_transfer/tests/test_sct.py b/account_banking_sepa_credit_transfer/tests/test_sct.py index 7a5ef853c..51b785347 100644 --- a/account_banking_sepa_credit_transfer/tests/test_sct.py +++ b/account_banking_sepa_credit_transfer/tests/test_sct.py @@ -1,9 +1,10 @@ # -*- coding: utf-8 -*- # © 2016 Akretion (Alexis de Lattre ) -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -from odoo.addons.account.tests.account_test_classes\ - import AccountingTestCase +import base64 +from odoo.addons.account.tests.account_test_classes import AccountingTestCase +from odoo.exceptions import UserError from odoo.tools import float_compare import time from lxml import etree @@ -60,7 +61,28 @@ class TestSCT(AccountingTestCase): for bank_acc in self.partner_bank_model.search([]): bank_acc.acc_number = bank_acc.acc_number - def test_eur_currency_sct(self): + def test_no_pain(self): + self.payment_mode.payment_method_id.pain_version = False + with self.assertRaises(UserError): + self.check_eur_currency_sct() + + def test_pain_001_03(self): + self.payment_mode.payment_method_id.pain_version = 'pain.001.001.03' + self.check_eur_currency_sct() + + def test_pain_001_04(self): + self.payment_mode.payment_method_id.pain_version = 'pain.001.001.04' + self.check_eur_currency_sct() + + def test_pain_001_05(self): + self.payment_mode.payment_method_id.pain_version = 'pain.001.001.05' + self.check_eur_currency_sct() + + def test_pain_003_03(self): + self.payment_mode.payment_method_id.pain_version = 'pain.001.003.03' + self.check_eur_currency_sct() + + def check_eur_currency_sct(self): invoice1 = self.create_invoice( self.partner_agrolait.id, 'account_payment_mode.res_partner_2_iban', self.eur_currency.id, @@ -83,70 +105,70 @@ class TestSCT(AccountingTestCase): 41.0, 'I1643') for inv in [invoice1, invoice2, invoice3, invoice4, invoice5]: action = inv.create_account_payment_line() - self.assertEquals(action['res_model'], 'account.payment.order') + self.assertEqual(action['res_model'], 'account.payment.order') self.payment_order = self.payment_order_model.browse(action['res_id']) - self.assertEquals( + self.assertEqual( self.payment_order.payment_type, 'outbound') - self.assertEquals( + self.assertEqual( self.payment_order.payment_mode_id, self.payment_mode) - self.assertEquals( + self.assertEqual( self.payment_order.journal_id, self.bank_journal) pay_lines = self.payment_line_model.search([ ('partner_id', '=', self.partner_agrolait.id), ('order_id', '=', self.payment_order.id)]) - self.assertEquals(len(pay_lines), 3) + self.assertEqual(len(pay_lines), 3) agrolait_pay_line1 = pay_lines[0] accpre = self.env['decimal.precision'].precision_get('Account') - self.assertEquals(agrolait_pay_line1.currency_id, self.eur_currency) - self.assertEquals( + self.assertEqual(agrolait_pay_line1.currency_id, self.eur_currency) + self.assertEqual( agrolait_pay_line1.partner_bank_id, invoice1.partner_bank_id) - self.assertEquals(float_compare( + self.assertEqual(float_compare( agrolait_pay_line1.amount_currency, 42, precision_digits=accpre), 0) - self.assertEquals(agrolait_pay_line1.communication_type, 'normal') - self.assertEquals(agrolait_pay_line1.communication, 'F1341') + self.assertEqual(agrolait_pay_line1.communication_type, 'normal') + self.assertEqual(agrolait_pay_line1.communication, 'F1341') self.payment_order.draft2open() - self.assertEquals(self.payment_order.state, 'open') - self.assertEquals(self.payment_order.sepa, True) + self.assertEqual(self.payment_order.state, 'open') + self.assertEqual(self.payment_order.sepa, True) bank_lines = self.bank_line_model.search([ ('partner_id', '=', self.partner_agrolait.id)]) - self.assertEquals(len(bank_lines), 1) + self.assertEqual(len(bank_lines), 1) agrolait_bank_line = bank_lines[0] - self.assertEquals(agrolait_bank_line.currency_id, self.eur_currency) - self.assertEquals(float_compare( + self.assertEqual(agrolait_bank_line.currency_id, self.eur_currency) + self.assertEqual(float_compare( agrolait_bank_line.amount_currency, 49.0, precision_digits=accpre), 0) - self.assertEquals(agrolait_bank_line.communication_type, 'normal') - self.assertEquals( + self.assertEqual(agrolait_bank_line.communication_type, 'normal') + self.assertEqual( agrolait_bank_line.communication, 'F1341-F1342-A1301') - self.assertEquals( + self.assertEqual( agrolait_bank_line.partner_bank_id, invoice1.partner_bank_id) action = self.payment_order.open2generated() - self.assertEquals(self.payment_order.state, 'generated') - self.assertEquals(action['res_model'], 'ir.attachment') + self.assertEqual(self.payment_order.state, 'generated') + self.assertEqual(action['res_model'], 'ir.attachment') attachment = self.attachment_model.browse(action['res_id']) - self.assertEquals(attachment.datas_fname[-4:], '.xml') - xml_file = attachment.datas.decode('base64') + self.assertEqual(attachment.datas_fname[-4:], '.xml') + xml_file = base64.b64decode(attachment.datas) xml_root = etree.fromstring(xml_file) namespaces = xml_root.nsmap namespaces['p'] = xml_root.nsmap[None] namespaces.pop(None) pay_method_xpath = xml_root.xpath( '//p:PmtInf/p:PmtMtd', namespaces=namespaces) - self.assertEquals(pay_method_xpath[0].text, 'TRF') + self.assertEqual(pay_method_xpath[0].text, 'TRF') sepa_xpath = xml_root.xpath( '//p:PmtInf/p:PmtTpInf/p:SvcLvl/p:Cd', namespaces=namespaces) - self.assertEquals(sepa_xpath[0].text, 'SEPA') + self.assertEqual(sepa_xpath[0].text, 'SEPA') debtor_acc_xpath = xml_root.xpath( '//p:PmtInf/p:DbtrAcct/p:Id/p:IBAN', namespaces=namespaces) - self.assertEquals( + self.assertEqual( debtor_acc_xpath[0].text, self.payment_order.company_partner_bank_id.sanitized_acc_number) self.payment_order.generated2uploaded() - self.assertEquals(self.payment_order.state, 'uploaded') + self.assertEqual(self.payment_order.state, 'uploaded') for inv in [invoice1, invoice2, invoice3, invoice4, invoice5]: - self.assertEquals(inv.state, 'paid') + self.assertEqual(inv.state, 'paid') return def test_usd_currency_sct(self): @@ -160,70 +182,70 @@ class TestSCT(AccountingTestCase): 1012.0, 'Inv9033') for inv in [invoice1, invoice2]: action = inv.create_account_payment_line() - self.assertEquals(action['res_model'], 'account.payment.order') + self.assertEqual(action['res_model'], 'account.payment.order') self.payment_order = self.payment_order_model.browse(action['res_id']) - self.assertEquals( + self.assertEqual( self.payment_order.payment_type, 'outbound') - self.assertEquals( + self.assertEqual( self.payment_order.payment_mode_id, self.payment_mode) - self.assertEquals( + self.assertEqual( self.payment_order.journal_id, self.bank_journal) pay_lines = self.payment_line_model.search([ ('partner_id', '=', self.partner_asus.id), ('order_id', '=', self.payment_order.id)]) - self.assertEquals(len(pay_lines), 2) + self.assertEqual(len(pay_lines), 2) asus_pay_line1 = pay_lines[0] accpre = self.env['decimal.precision'].precision_get('Account') - self.assertEquals(asus_pay_line1.currency_id, self.usd_currency) - self.assertEquals( + self.assertEqual(asus_pay_line1.currency_id, self.usd_currency) + self.assertEqual( asus_pay_line1.partner_bank_id, invoice1.partner_bank_id) - self.assertEquals(float_compare( + self.assertEqual(float_compare( asus_pay_line1.amount_currency, 2042, precision_digits=accpre), 0) - self.assertEquals(asus_pay_line1.communication_type, 'normal') - self.assertEquals(asus_pay_line1.communication, 'Inv9032') + self.assertEqual(asus_pay_line1.communication_type, 'normal') + self.assertEqual(asus_pay_line1.communication, 'Inv9032') self.payment_order.draft2open() - self.assertEquals(self.payment_order.state, 'open') - self.assertEquals(self.payment_order.sepa, False) + self.assertEqual(self.payment_order.state, 'open') + self.assertEqual(self.payment_order.sepa, False) bank_lines = self.bank_line_model.search([ ('partner_id', '=', self.partner_asus.id)]) - self.assertEquals(len(bank_lines), 1) + self.assertEqual(len(bank_lines), 1) asus_bank_line = bank_lines[0] - self.assertEquals(asus_bank_line.currency_id, self.usd_currency) - self.assertEquals(float_compare( + self.assertEqual(asus_bank_line.currency_id, self.usd_currency) + self.assertEqual(float_compare( asus_bank_line.amount_currency, 3054.0, precision_digits=accpre), 0) - self.assertEquals(asus_bank_line.communication_type, 'normal') - self.assertEquals( + self.assertEqual(asus_bank_line.communication_type, 'normal') + self.assertEqual( asus_bank_line.communication, 'Inv9032-Inv9033') - self.assertEquals( + self.assertEqual( asus_bank_line.partner_bank_id, invoice1.partner_bank_id) action = self.payment_order.open2generated() - self.assertEquals(self.payment_order.state, 'generated') - self.assertEquals(action['res_model'], 'ir.attachment') + self.assertEqual(self.payment_order.state, 'generated') + self.assertEqual(action['res_model'], 'ir.attachment') attachment = self.attachment_model.browse(action['res_id']) - self.assertEquals(attachment.datas_fname[-4:], '.xml') - xml_file = attachment.datas.decode('base64') + self.assertEqual(attachment.datas_fname[-4:], '.xml') + xml_file = base64.b64decode(attachment.datas) xml_root = etree.fromstring(xml_file) namespaces = xml_root.nsmap namespaces['p'] = xml_root.nsmap[None] namespaces.pop(None) pay_method_xpath = xml_root.xpath( '//p:PmtInf/p:PmtMtd', namespaces=namespaces) - self.assertEquals(pay_method_xpath[0].text, 'TRF') + self.assertEqual(pay_method_xpath[0].text, 'TRF') sepa_xpath = xml_root.xpath( '//p:PmtInf/p:PmtTpInf/p:SvcLvl/p:Cd', namespaces=namespaces) - self.assertEquals(len(sepa_xpath), 0) + self.assertEqual(len(sepa_xpath), 0) debtor_acc_xpath = xml_root.xpath( '//p:PmtInf/p:DbtrAcct/p:Id/p:IBAN', namespaces=namespaces) - self.assertEquals( + self.assertEqual( debtor_acc_xpath[0].text, self.payment_order.company_partner_bank_id.sanitized_acc_number) self.payment_order.generated2uploaded() - self.assertEquals(self.payment_order.state, 'uploaded') + self.assertEqual(self.payment_order.state, 'uploaded') for inv in [invoice1, invoice2]: - self.assertEquals(inv.state, 'paid') + self.assertEqual(inv.state, 'paid') return def create_invoice(