diff --git a/app/models/enable_banking_item/importer.rb b/app/models/enable_banking_item/importer.rb index bf1bb48cd..a2c5f1452 100644 --- a/app/models/enable_banking_item/importer.rb +++ b/app/models/enable_banking_item/importer.rb @@ -250,6 +250,20 @@ class EnableBankingItem::Importer psu_headers: enable_banking_item.build_psu_headers ) + if include_pending + # Tag any transaction in all_transactions (fetched as BOOK but actually PDNG) with _pending: true + all_transactions = all_transactions.map do |tx| + tx_ia = tx.with_indifferent_access + tx_ia[:status] == "PDNG" ? tx_ia.merge(_pending: true) : tx_ia + end + else + # If include_pending is false, we must filter out any pending transactions + # that were returned (e.g. if the bank ignores transaction_status="BOOK"). + all_transactions = all_transactions.reject do |tx| + tx.with_indifferent_access[:status] == "PDNG" + end + end + pending_transactions = [] if include_pending # Also fetch pending transactions (visible for 1-3 days before they become BOOK) if setting is enabled. @@ -272,14 +286,16 @@ class EnableBankingItem::Importer end end - book_fingerprints = all_transactions + booked_transactions = all_transactions.reject { |tx| tx.with_indifferent_access[:_pending] } + + book_fingerprints = booked_transactions .map { |tx| EnableBankingEntry::Processor.compute_external_id(tx) } .compact.to_set # Also index all booked entry_references so a pending row that lacks # transaction_id can still be matched when the settled BOOK row adds one # (fingerprints differ; entry_reference stays the same across settlement). - book_entry_refs = all_transactions + book_entry_refs = booked_transactions .map { |tx| tx.with_indifferent_access[:entry_reference].presence } .compact.to_set @@ -323,13 +339,13 @@ class EnableBankingItem::Importer # no transaction_id but the settled BOOK row gained one — fingerprints # diverge (enable_banking_ vs enable_banking_) but the # shared entry_reference is a reliable settlement signal. - book_fingerprints = all_transactions - .reject { |tx| tx.with_indifferent_access[:_pending] } + booked_transactions_for_settlement = all_transactions.reject { |tx| tx.with_indifferent_access[:_pending] } + + book_fingerprints = booked_transactions_for_settlement .map { |tx| EnableBankingEntry::Processor.compute_external_id(tx) } .compact.to_set - book_entry_refs = all_transactions - .reject { |tx| tx.with_indifferent_access[:_pending] } + book_entry_refs = booked_transactions_for_settlement .map { |tx| tx.with_indifferent_access[:entry_reference].presence } .compact.to_set diff --git a/test/models/enable_banking_item/importer_pdng_test.rb b/test/models/enable_banking_item/importer_pdng_test.rb index 3d444ebf4..3fd1d18af 100644 --- a/test/models/enable_banking_item/importer_pdng_test.rb +++ b/test/models/enable_banking_item/importer_pdng_test.rb @@ -143,4 +143,49 @@ class EnableBankingItem::ImporterPdngTest < ActiveSupport::TestCase assert_equal @enable_banking_account.id, found.id end + + # --- fetch_and_store_transactions behavior --- + + test "fetch_and_store_transactions tags PDNG transaction as pending when include_pending is true" do + @importer.stubs(:include_pending?).returns(true) + + # Some ASPSPs ignore transaction_status=BOOK and return PDNG transactions anyway. + tx = { + entry_reference: "tx_ref", + transaction_id: "tx_id", + booking_date: "2026-03-05", + transaction_amount: { amount: "10.00", currency: "EUR" }, + status: "PDNG" + } + + @importer.stubs(:fetch_paginated_transactions).with(@enable_banking_account, has_entries(transaction_status: "BOOK")).returns([ tx ]) + @importer.stubs(:fetch_paginated_transactions).with(@enable_banking_account, has_entries(transaction_status: "PDNG")).returns([ tx ]) + + result = @importer.send(:fetch_and_store_transactions, @enable_banking_account) + + assert result[:success] + stored = @enable_banking_account.raw_transactions_payload + assert_equal 1, stored.size + assert_equal true, stored.first.with_indifferent_access[:_pending] + end + + test "fetch_and_store_transactions filters out PDNG transaction when include_pending is false" do + @importer.stubs(:include_pending?).returns(false) + + # If include_pending is false, we must reject any PDNG transactions returned in the BOOK fetch. + tx = { + entry_reference: "tx_ref", + transaction_id: "tx_id", + booking_date: "2026-03-05", + transaction_amount: { amount: "10.00", currency: "EUR" }, + status: "PDNG" + } + + @importer.stubs(:fetch_paginated_transactions).with(@enable_banking_account, has_entries(transaction_status: "BOOK")).returns([ tx ]) + + result = @importer.send(:fetch_and_store_transactions, @enable_banking_account) + + assert result[:success] + assert_nil @enable_banking_account.raw_transactions_payload + end end