diff --git a/account_statement_import_camt54/README.rst b/account_statement_import_camt54/README.rst new file mode 100644 index 00000000..54f8f43d --- /dev/null +++ b/account_statement_import_camt54/README.rst @@ -0,0 +1,90 @@ +========================== +Bank Account Camt54 Import +========================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fbank--statement--import-lightgray.png?logo=github + :target: https://github.com/OCA/bank-statement-import/tree/13.0/account_bank_statement_import_oca_camt54 + :alt: OCA/bank-statement-import +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/bank-statement-import-13-0/bank-statement-import-13-0-account_bank_statement_import_oca_camt54 + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/174/13.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + + This module allows you to import CAMT.054 file (details of customers payments batch) into a dedicated journal taking care of the start/end balance and the remittance reference number. + +Customer invoices will be reconciled/Paid. Payment entries will be posted into an internal transfer account (that you have to create with a type current asset and set on the journal) + +After this first step, import normally your CAMT.053 (full bank statement) into the bank journal. You will be able to clear the internal transfer account to end up the accounting flow. + + +Switzerland localisation +------------------------ + +For ISR containing a partner reference, uses the config parameter key `isr_partner_ref`. +Doing so will fill the partners on bank statement lines and speed up the matches in the reconciliation process. + +Value to set in `isr_partner_ref` defines the position of the partner reference inside the ISR. +The format is `i[,n]` +For instance `13,6` to start on position 13 with a 6 digit long reference. +`n` is optional and it's default value is `6`. + +**Table of contents** + +.. contents:: + :local: + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* camptocamp + +Contributors +~~~~~~~~~~~~ + +* Yannick Vaucher +* Timon Tschanz + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +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. + +This module is part of the `OCA/bank-statement-import `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/account_statement_import_camt54/__init__.py b/account_statement_import_camt54/__init__.py new file mode 100644 index 00000000..0650744f --- /dev/null +++ b/account_statement_import_camt54/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/account_statement_import_camt54/__manifest__.py b/account_statement_import_camt54/__manifest__.py new file mode 100644 index 00000000..a9a8b6a2 --- /dev/null +++ b/account_statement_import_camt54/__manifest__.py @@ -0,0 +1,12 @@ +# Copyright 2019 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +{ + "name": "Bank Account Camt54 Import", + "version": "14.0.1.0.0", + "category": "Account", + "website": "https://github.com/OCA/bank-statement-import", + "author": "camptocamp, " "Odoo Community Association (OCA)", + "license": "AGPL-3", + "installable": True, + "depends": ["account_statement_import_camt"], +} diff --git a/account_statement_import_camt54/models/__init__.py b/account_statement_import_camt54/models/__init__.py new file mode 100644 index 00000000..11ac1bbc --- /dev/null +++ b/account_statement_import_camt54/models/__init__.py @@ -0,0 +1,2 @@ +from . import account_statement_import +from . import parser diff --git a/account_statement_import_camt54/models/account_statement_import.py b/account_statement_import_camt54/models/account_statement_import.py new file mode 100644 index 00000000..ae863028 --- /dev/null +++ b/account_statement_import_camt54/models/account_statement_import.py @@ -0,0 +1,40 @@ +# Copyright 2019 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +import logging + +from odoo import models + +_logger = logging.getLogger(__name__) + + +class AccountStatementImport(models.TransientModel): + """Add process_camt method to account.bank.statement.import.""" + + _inherit = "account.statement.import" + + def _create_bank_statements(self, stmts_vals): + """ Set balance_end_real if not already provided by the file.""" + + statement_line_ids, notifications = super()._create_bank_statements(stmts_vals) + statements = self.env["account.bank.statement"].search( + [("line_ids", "in", statement_line_ids)] + ) + for statement in statements: + if not statement.balance_end_real: + amount = sum(statement.line_ids.mapped("amount")) + statement.balance_end_real = statement.balance_start + amount + return statement_line_ids, notifications + + def _complete_stmts_vals(self, stmts_vals, journal, account_number): + """Search partner from partner reference""" + stmts_vals = super()._complete_stmts_vals(stmts_vals, journal, account_number) + for st_vals in stmts_vals: + for line_vals in st_vals["transactions"]: + if "partner_ref" in line_vals: + partner_ref = line_vals.pop("partner_ref") + partner = self.env["res.partner"].search( + [("ref", "=", partner_ref)], limit=1 + ) + line_vals["partner_id"] = partner.id + + return stmts_vals diff --git a/account_statement_import_camt54/models/parser.py b/account_statement_import_camt54/models/parser.py new file mode 100644 index 00000000..7c6d4190 --- /dev/null +++ b/account_statement_import_camt54/models/parser.py @@ -0,0 +1,100 @@ +# Copyright 2019 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import _, exceptions, models + + +class CamtParser(models.AbstractModel): + """Parser for camt bank statement import files.""" + + _inherit = "account.statement.import.camt.parser" + + def _get_partner_ref(self, isr): + ICP = self.env["ir.config_parameter"] + ref_format = ICP.sudo().get_param("isr_partner_ref") + if not ref_format: + return + config = ref_format.split(",") + if len(config) == 2: + start, size = config + elif len(config) == 1: + start = config[0] + size = 6 + else: + raise exceptions.UserError( + _( + "Config parameter `isr_partner_ref` is wrong.\n" + "It must be in format `i[,n]` \n" + "where `i` is the position of the first digit and\n" + "`n` the number of digit in the reference," + " by default 6.\n" + 'e.g. "13,6"' + ) + ) + try: + start = int(start) - 1 # count from 1 instead of 0 + size = int(size) + end = start + size + except ValueError: + raise exceptions.UserError( + _( + "Config parameter `isr_partner_ref` is wrong.\n" + "It must be in format `i[,n]` \n" + "`i` and `n` must be integers.\n" + 'e.g. "13,6"' + ) + ) + return isr[start:end].lstrip("0") + + def parse_transaction_details(self, ns, node, transaction): + """Put ESR in label and add aditional information to label + if no esr is available + """ + super().parse_transaction_details(ns, node, transaction) + # put the esr in the label. odoo reconciles based on the label, + # if there is no esr it tries to use the information textfield + + isr_number = node.xpath( + "./ns:RmtInf/ns:Strd/ns:CdtrRefInf/ns:Ref", namespaces={"ns": ns} + ) + if len(isr_number): + transaction["name"] = isr_number[0].text + partner_ref = self._get_partner_ref(isr_number[0].text) + if partner_ref: + transaction["partner_ref"] = partner_ref + else: + xpath_exprs = [ + "./ns:RmtInf/ns:Ustrd|./ns:RtrInf/ns:AddtlInf", + "./ns:AddtlNtryInf", + "/ns:Refs/ns:InstrId", + ] + name = transaction["name"] + for xpath_expr in xpath_exprs: + found_node = node.xpath(xpath_expr, namespaces={"ns": ns}) + if found_node: + name = found_node[0].text + break + trans_id_node = ( + node.getparent() + .getparent() + .xpath("./ns:AcctSvcrRef", namespaces={"ns": ns}) + ) + if trans_id_node: + name = "{} ({})".format(name, trans_id_node[0].text) + if name: + transaction["name"] = name + # End add esr to the label. + + # add transaction id to ref + self.add_value_from_node( + ns, + node, + [ + "./../../ns:AcctSvcrRef", + "./ns:RmtInf/ns:Strd/ns:CdtrRefInf/ns:Ref", + "./ns:Refs/ns:EndToEndId", + ], + transaction, + "ref", + ) + return True diff --git a/account_statement_import_camt54/readme/CONTRIBUTORS.rst b/account_statement_import_camt54/readme/CONTRIBUTORS.rst new file mode 100644 index 00000000..0cf04074 --- /dev/null +++ b/account_statement_import_camt54/readme/CONTRIBUTORS.rst @@ -0,0 +1,2 @@ +* Yannick Vaucher +* Timon Tschanz diff --git a/account_statement_import_camt54/readme/DESCRIPTION.rst b/account_statement_import_camt54/readme/DESCRIPTION.rst new file mode 100644 index 00000000..63b1f4cf --- /dev/null +++ b/account_statement_import_camt54/readme/DESCRIPTION.rst @@ -0,0 +1,17 @@ + This module allows you to import CAMT.054 file (details of customers payments batch) into a dedicated journal taking care of the start/end balance and the remittance reference number. + +Customer invoices will be reconciled/Paid. Payment entries will be posted into an internal transfer account (that you have to create with a type current asset and set on the journal) + +After this first step, import normally your CAMT.053 (full bank statement) into the bank journal. You will be able to clear the internal transfer account to end up the accounting flow. + + +Switzerland localisation +------------------------ + +For ISR containing a partner reference, uses the config parameter key `isr_partner_ref`. +Doing so will fill the partners on bank statement lines and speed up the matches in the reconciliation process. + +Value to set in `isr_partner_ref` defines the position of the partner reference inside the ISR. +The format is `i[,n]` +For instance `13,6` to start on position 13 with a 6 digit long reference. +`n` is optional and it's default value is `6`. diff --git a/account_statement_import_camt54/static/description/icon.png b/account_statement_import_camt54/static/description/icon.png new file mode 100644 index 00000000..3a0328b5 Binary files /dev/null and b/account_statement_import_camt54/static/description/icon.png differ diff --git a/account_statement_import_camt54/static/description/index.html b/account_statement_import_camt54/static/description/index.html new file mode 100644 index 00000000..fc09fe3d --- /dev/null +++ b/account_statement_import_camt54/static/description/index.html @@ -0,0 +1,432 @@ + + + + + + +Bank Account Camt54 Import + + + +
+

Bank Account Camt54 Import

+ + +

Beta License: AGPL-3 OCA/bank-statement-import Translate me on Weblate Try me on Runbot

+
+This module allows you to import CAMT.054 file (details of customers payments batch) into a dedicated journal taking care of the start/end balance and the remittance reference number.
+

Customer invoices will be reconciled/Paid. Payment entries will be posted into an internal transfer account (that you have to create with a type current asset and set on the journal)

+

After this first step, import normally your CAMT.053 (full bank statement) into the bank journal. You will be able to clear the internal transfer account to end up the accounting flow.

+
+

Switzerland localisation

+

For ISR containing a partner reference, uses the config parameter key isr_partner_ref. +Doing so will fill the partners on bank statement lines and speed up the matches in the reconciliation process.

+

Value to set in isr_partner_ref defines the position of the partner reference inside the ISR. +The format is i[,n] +For instance 13,6 to start on position 13 with a 6 digit long reference. +n is optional and it’s default value is 6.

+

Table of contents

+ +
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • camptocamp
  • +
+
+ +
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

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.

+

This module is part of the OCA/bank-statement-import project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+
+ + diff --git a/account_statement_import_camt54/tests/__init__.py b/account_statement_import_camt54/tests/__init__.py new file mode 100644 index 00000000..c2592574 --- /dev/null +++ b/account_statement_import_camt54/tests/__init__.py @@ -0,0 +1 @@ +from . import test_get_partner_ref diff --git a/account_statement_import_camt54/tests/test_get_partner_ref.py b/account_statement_import_camt54/tests/test_get_partner_ref.py new file mode 100644 index 00000000..01170a18 --- /dev/null +++ b/account_statement_import_camt54/tests/test_get_partner_ref.py @@ -0,0 +1,65 @@ +# Copyright 2019 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from odoo.exceptions import UserError +from odoo.tests import common + + +class TestGetPartnerRef(common.TransactionCase): + def setUp(self): + super().setUp() + self.Parser = self.env["account.statement.import.camt.parser"] + self.ICP = self.env["ir.config_parameter"] + + def test_no_ICP(self): + """Test no partner ref is read if param is not set""" + ref = "11 11111 11111 11111 11111 11111".replace(" ", "") + partner_ref = self.Parser._get_partner_ref(ref) + self.assertFalse(partner_ref) + + def test_ICP_empty(self): + self.ICP.set_param("isr_partner_ref", "") + ref = "11 11111 11111 11111 11111 11111".replace(" ", "") + partner_ref = self.Parser._get_partner_ref(ref) + self.assertFalse(partner_ref) + + def test_ICP_no_len(self): + """Test a default len of 6 is set if not provided""" + self.ICP.set_param("isr_partner_ref", "12") + ref = "11 11111 11112 34567 11111 11111".replace(" ", "") + partner_ref = self.Parser._get_partner_ref(ref) + self.assertEquals(partner_ref, "234567") + + def test_ICP_full(self): + """Test full format of partner ref definition""" + self.ICP.set_param("isr_partner_ref", "12,6") + ref = "11 11111 11112 34567 11111 11111".replace(" ", "") + partner_ref = self.Parser._get_partner_ref(ref) + self.assertEquals(partner_ref, "234567") + + def test_zero_stripped(self): + """Test full format of partner ref definition""" + self.ICP.set_param("isr_partner_ref", "12,6") + ref = "11 11111 11110 00560 11111 11111".replace(" ", "") + partner_ref = self.Parser._get_partner_ref(ref) + self.assertEquals(partner_ref, "560") + + def test_bad_ICP(self): + """Test ir config parameter validation""" + self.ICP.set_param("isr_partner_ref", "") + ref = "11 11111 11111 11111 11111 11111".replace(" ", "") + + self.ICP.set_param("isr_partner_ref", "A") + with self.assertRaises(UserError): + self.Parser._get_partner_ref(ref) + + self.ICP.set_param("isr_partner_ref", "A,B") + with self.assertRaises(UserError): + self.Parser._get_partner_ref(ref) + + self.ICP.set_param("isr_partner_ref", "1,X") + with self.assertRaises(UserError): + self.Parser._get_partner_ref(ref) + + self.ICP.set_param("isr_partner_ref", "A,8") + with self.assertRaises(UserError): + self.Parser._get_partner_ref(ref)