From 076473f46e70968fe498850a2ec1819267299dba Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 18 Sep 2025 10:37:43 +0000 Subject: [PATCH 1/3] Initial plan From 5d0d2d963149635735ac13fe60c19b7023a40fd3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 18 Sep 2025 10:43:21 +0000 Subject: [PATCH 2/3] Add RemittanceInformationFull field to capture all Ustrd elements - fixes #6 Co-authored-by: ODAncona <71207824+ODAncona@users.noreply.github.com> --- pycamt/parser.py | 5 ++ tests/test_parser.py | 164 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 169 insertions(+) diff --git a/pycamt/parser.py b/pycamt/parser.py index 2d1b4e3..094ca8e 100644 --- a/pycamt/parser.py +++ b/pycamt/parser.py @@ -306,6 +306,11 @@ def _extract_transaction_details(self, tx_detail): if tx_detail.find(".//RmtInf//Ustrd", self.namespaces) is not None else None ), + "RemittanceInformationFull": ( + " ".join(rinfo.text.strip() for rinfo in tx_detail.findall(".//RmtInf//Ustrd", self.namespaces) if rinfo.text) + if tx_detail.findall(".//RmtInf//Ustrd", self.namespaces) + else None + ), } structured_remittance_elem = tx_detail.find(".//RmtInf//Strd", self.namespaces) diff --git a/tests/test_parser.py b/tests/test_parser.py index 6b4e7ad..af424fc 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -88,3 +88,167 @@ def test_get_statement_info(self, parser): "ClosingBalanceDate": None }] assert parser.get_statement_info() == expected + + def test_multiple_remittance_information(self): + """Test that multiple Ustrd elements in RemittanceInformation are captured""" + xml_data = """ + + + + ABC123 + 2020-06-23T18:56:25.64Z + + + + + GB33BUKB20201555555555 + + + + 69.06 + CRDT + +
2020-07-07
+
+ +
2020-07-07
+
+ 123 + + + + ENDTOENDID123 + + + Ref.. 1234567890123456 + Betrag EUR 69,06 + /ADRS CH/Basel,1234 + A12345/ Best 00123456 + 7185) Peter Pan + Urspr. EUR 69,06 + ADRS Re xxxxx,4 CH/Basel + Land,1234/ + ERST RAIFCH12345 + + + +
+
+
+
+ """ + parser = Camt053Parser(xml_data) + transactions = parser.get_transactions() + + assert len(transactions) == 1 + transaction = transactions[0] + + # Current behavior: only first Ustrd element + assert transaction["RemittanceInformation"] == "Ref.. 1234567890123456" + + # New behavior: all Ustrd elements joined + expected_full = ( + "Ref.. 1234567890123456 Betrag EUR 69,06 " + "/ADRS CH/Basel,1234 A12345/ Best 00123456 7185) Peter Pan " + "Urspr. EUR 69,06 ADRS Re xxxxx,4 CH/Basel " + "Land,1234/ ERST RAIFCH12345" + ) + assert "RemittanceInformationFull" in transaction + assert transaction["RemittanceInformationFull"] == expected_full + + def test_single_remittance_information_backward_compatibility(self): + """Test that single Ustrd element works for both fields""" + xml_data = """ + + + + ABC123 + 2020-06-23T18:56:25.64Z + + + + + GB33BUKB20201555555555 + + + + 500.00 + CRDT + +
2020-06-23
+
+ +
2020-06-23
+
+ 123 + + + + ENDTOENDID123 + + + Single remittance info + + + +
+
+
+
+ """ + parser = Camt053Parser(xml_data) + transactions = parser.get_transactions() + + assert len(transactions) == 1 + transaction = transactions[0] + + # Both fields should have the same value for single Ustrd + assert transaction["RemittanceInformation"] == "Single remittance info" + assert transaction["RemittanceInformationFull"] == "Single remittance info" + + def test_no_remittance_information(self): + """Test that transactions without RemittanceInformation still work""" + xml_data = """ + + + + ABC123 + 2020-06-23T18:56:25.64Z + + + + + GB33BUKB20201555555555 + + + + 500.00 + CRDT + +
2020-06-23
+
+ +
2020-06-23
+
+ 123 + + + + ENDTOENDID123 + + + +
+
+
+
+ """ + parser = Camt053Parser(xml_data) + transactions = parser.get_transactions() + + assert len(transactions) == 1 + transaction = transactions[0] + + # Both fields should be None when no remittance info exists + assert "RemittanceInformation" not in transaction # Filtered out by return statement + assert "RemittanceInformationFull" not in transaction # Filtered out by return statement From 8073b2e04a0c764f3ded940d7399231a6e6f749f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 18 Sep 2025 10:44:43 +0000 Subject: [PATCH 3/3] Update documentation for new RemittanceInformationFull field Co-authored-by: ODAncona <71207824+ODAncona@users.noreply.github.com> --- docs/index.md | 6 ++++++ pycamt/parser.py | 3 +++ 2 files changed, 9 insertions(+) diff --git a/docs/index.md b/docs/index.md index 46e007e..63b3038 100644 --- a/docs/index.md +++ b/docs/index.md @@ -61,6 +61,12 @@ for transaction in transactions: print(transaction) ``` +**Note**: Each transaction includes remittance information in two fields: +- `RemittanceInformation`: Contains only the first unstructured remittance line +- `RemittanceInformationFull`: Contains all unstructured remittance lines joined with spaces + +This is particularly useful for international transactions that may contain multiple lines of remittance information. + ### Extracting Statement Information To get basic statement information like IBAN and opening/closing balance: diff --git a/pycamt/parser.py b/pycamt/parser.py index 094ca8e..1475397 100644 --- a/pycamt/parser.py +++ b/pycamt/parser.py @@ -258,6 +258,9 @@ def _extract_transaction_details(self, tx_detail): ------- dict Detailed information extracted from the transaction detail element. + Includes RemittanceInformation (first Ustrd) and RemittanceInformationFull + (all Ustrd elements joined with spaces) for backward compatibility and + comprehensive remittance data capture. """ data = {