mirror of
https://github.com/we-promise/sure
synced 2026-04-25 17:15:07 +02:00
fix: prefer booked over available balance types in Enable Banking sync (#825)
The balance selection logic prioritized ITAV (Interim Available) which includes overdraft capacity, inflating displayed balances. Reorder to prefer booked types (CLBD > XPCD > ITBD) before available types (CLAV > ITAV). https://claude.ai/code/session_01EhxhgQqun8RuzfgkMxbp8x
This commit is contained in:
@@ -3,6 +3,10 @@ class EnableBankingItem::Importer
|
|||||||
# Enable Banking typically returns ~100 transactions per page, so 100 pages = ~10,000 transactions
|
# Enable Banking typically returns ~100 transactions per page, so 100 pages = ~10,000 transactions
|
||||||
MAX_PAGINATION_PAGES = 100
|
MAX_PAGINATION_PAGES = 100
|
||||||
|
|
||||||
|
# Balance type priority: prefer booked balances over available balances.
|
||||||
|
# Available types (CLAV, ITAV) include overdraft/credit capacity and inflate balances.
|
||||||
|
BALANCE_TYPE_PRIORITY = %w[CLBD XPCD ITBD CLAV ITAV].freeze
|
||||||
|
|
||||||
attr_reader :enable_banking_item, :enable_banking_provider
|
attr_reader :enable_banking_item, :enable_banking_provider
|
||||||
|
|
||||||
def initialize(enable_banking_item, enable_banking_provider:)
|
def initialize(enable_banking_item, enable_banking_provider:)
|
||||||
@@ -161,12 +165,8 @@ class EnableBankingItem::Importer
|
|||||||
balances = balance_data[:balances] || []
|
balances = balance_data[:balances] || []
|
||||||
return if balances.empty?
|
return if balances.empty?
|
||||||
|
|
||||||
# Find the most relevant balance (prefer "ITAV" or "CLAV" types)
|
# Find the most relevant balance (prefer booked over available types)
|
||||||
balance = balances.find { |b| b[:balance_type] == "ITAV" } ||
|
balance = select_balance(balances)
|
||||||
balances.find { |b| b[:balance_type] == "CLAV" } ||
|
|
||||||
balances.find { |b| b[:balance_type] == "ITBD" } ||
|
|
||||||
balances.find { |b| b[:balance_type] == "CLBD" } ||
|
|
||||||
balances.first
|
|
||||||
|
|
||||||
if balance.present?
|
if balance.present?
|
||||||
amount = balance.dig(:balance_amount, :amount) || balance[:amount]
|
amount = balance.dig(:balance_amount, :amount) || balance[:amount]
|
||||||
@@ -183,6 +183,14 @@ class EnableBankingItem::Importer
|
|||||||
Rails.logger.error "EnableBankingItem::Importer - Error fetching balance for account #{enable_banking_account.uid}: #{e.message}"
|
Rails.logger.error "EnableBankingItem::Importer - Error fetching balance for account #{enable_banking_account.uid}: #{e.message}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def select_balance(balances)
|
||||||
|
BALANCE_TYPE_PRIORITY.each do |type|
|
||||||
|
found = balances.find { |b| b[:balance_type] == type }
|
||||||
|
return found if found
|
||||||
|
end
|
||||||
|
balances.first
|
||||||
|
end
|
||||||
|
|
||||||
def fetch_and_store_transactions(enable_banking_account)
|
def fetch_and_store_transactions(enable_banking_account)
|
||||||
start_date = determine_sync_start_date(enable_banking_account)
|
start_date = determine_sync_start_date(enable_banking_account)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
require "test_helper"
|
||||||
|
|
||||||
|
class EnableBankingItem::ImporterBalanceSelectionTest < ActiveSupport::TestCase
|
||||||
|
setup do
|
||||||
|
@family = families(:dylan_family)
|
||||||
|
@enable_banking_item = EnableBankingItem.create!(
|
||||||
|
family: @family,
|
||||||
|
name: "Test Enable Banking",
|
||||||
|
country_code: "AT",
|
||||||
|
application_id: "test_app_id",
|
||||||
|
client_certificate: "test_cert",
|
||||||
|
session_id: "test_session",
|
||||||
|
session_expires_at: 1.day.from_now
|
||||||
|
)
|
||||||
|
|
||||||
|
mock_provider = mock()
|
||||||
|
@importer = EnableBankingItem::Importer.new(@enable_banking_item, enable_banking_provider: mock_provider)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "prefers CLBD when multiple balance types are present" do
|
||||||
|
balances = [
|
||||||
|
{ balance_type: "ITAV", balance_amount: { amount: "4332.81", currency: "EUR" } },
|
||||||
|
{ balance_type: "CLAV", balance_amount: { amount: "4332.81", currency: "EUR" } },
|
||||||
|
{ balance_type: "ITBD", balance_amount: { amount: "232.81", currency: "EUR" } },
|
||||||
|
{ balance_type: "CLBD", balance_amount: { amount: "232.81", currency: "EUR" } }
|
||||||
|
]
|
||||||
|
|
||||||
|
result = @importer.send(:select_balance, balances)
|
||||||
|
|
||||||
|
assert_equal "CLBD", result[:balance_type]
|
||||||
|
assert_equal "232.81", result[:balance_amount][:amount]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "prefers XPCD over ITBD" do
|
||||||
|
balances = [
|
||||||
|
{ balance_type: "ITBD", balance_amount: { amount: "100.00", currency: "EUR" } },
|
||||||
|
{ balance_type: "XPCD", balance_amount: { amount: "150.00", currency: "EUR" } }
|
||||||
|
]
|
||||||
|
|
||||||
|
result = @importer.send(:select_balance, balances)
|
||||||
|
|
||||||
|
assert_equal "XPCD", result[:balance_type]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "falls back through priority chain" do
|
||||||
|
balances = [
|
||||||
|
{ balance_type: "ITAV", balance_amount: { amount: "5000.00", currency: "EUR" } },
|
||||||
|
{ balance_type: "ITBD", balance_amount: { amount: "900.00", currency: "EUR" } }
|
||||||
|
]
|
||||||
|
|
||||||
|
result = @importer.send(:select_balance, balances)
|
||||||
|
|
||||||
|
assert_equal "ITBD", result[:balance_type]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "CLAV is preferred over ITAV" do
|
||||||
|
balances = [
|
||||||
|
{ balance_type: "ITAV", balance_amount: { amount: "5000.00", currency: "EUR" } },
|
||||||
|
{ balance_type: "CLAV", balance_amount: { amount: "4800.00", currency: "EUR" } }
|
||||||
|
]
|
||||||
|
|
||||||
|
result = @importer.send(:select_balance, balances)
|
||||||
|
|
||||||
|
assert_equal "CLAV", result[:balance_type]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "falls back to first balance when no known types present" do
|
||||||
|
balances = [
|
||||||
|
{ balance_type: "PRCD", balance_amount: { amount: "500.00", currency: "EUR" } },
|
||||||
|
{ balance_type: "INFO", balance_amount: { amount: "600.00", currency: "EUR" } }
|
||||||
|
]
|
||||||
|
|
||||||
|
result = @importer.send(:select_balance, balances)
|
||||||
|
|
||||||
|
assert_equal "PRCD", result[:balance_type]
|
||||||
|
assert_equal "500.00", result[:balance_amount][:amount]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns single balance regardless of type" do
|
||||||
|
balances = [
|
||||||
|
{ balance_type: "ITAV", balance_amount: { amount: "1000.00", currency: "EUR" } }
|
||||||
|
]
|
||||||
|
|
||||||
|
result = @importer.send(:select_balance, balances)
|
||||||
|
|
||||||
|
assert_equal "ITAV", result[:balance_type]
|
||||||
|
end
|
||||||
|
end
|
||||||
Reference in New Issue
Block a user