1
0
Fork 0
mirror of https://github.com/maybe-finance/maybe.git synced 2025-08-09 07:25:19 +02:00

fix(sync): Fixing various sync issues

- Fixing credit card charges being considered income
- Fixing family syncs not re-syncing SimpleFIN accounts
- Fixing considerations for "credit card" account types
This commit is contained in:
Cameron Roudebush 2025-05-17 12:12:03 -04:00
parent bf4ee058ec
commit a4bbc22b4c
3 changed files with 35 additions and 26 deletions

View file

@ -75,6 +75,11 @@ class Family < ApplicationRecord
account.sync_later(start_date: start_date, parent_sync: sync) account.sync_later(start_date: start_date, parent_sync: sync)
end end
Rails.logger.info("Syncing simple_fin items for family #{id}")
simple_fin_items.each do |simple_fin_item|
simple_fin_item.sync_later(start_date: start_date, parent_sync: sync)
end
Rails.logger.info("Applying rules for family #{id}") Rails.logger.info("Applying rules for family #{id}")
rules.each do |rule| rules.each do |rule|
rule.apply_later rule.apply_later

View file

@ -89,7 +89,7 @@ class Provider::SimpleFin
# @param [Boolean] trans_pending If we should include pending transactions. Default is false as I don't think maybe supports pending. # @param [Boolean] trans_pending If we should include pending transactions. Default is false as I don't think maybe supports pending.
def get_available_accounts(accountable_type, trans_start_date = nil, trans_end_date = nil, trans_pending = false) def get_available_accounts(accountable_type, trans_start_date = nil, trans_end_date = nil, trans_pending = false)
check_rate_limit check_rate_limit
endpoint = "/accounts?pending=#{trans_pending}" endpoint = "/accounts"
if trans_end_date == nil if trans_end_date == nil
trans_end_date = Time.now.to_i trans_end_date = Time.now.to_i
@ -100,6 +100,11 @@ class Provider::SimpleFin
end end
# Add any parameters we care about # Add any parameters we care about
if trans_pending
endpoint += "?pending=1"
else
endpoint += "?"
end
if trans_start_date if trans_start_date
endpoint += "&start-date=#{trans_start_date}" endpoint += "&start-date=#{trans_start_date}"
end end
@ -107,20 +112,10 @@ class Provider::SimpleFin
endpoint += "&end-date=#{trans_end_date}" endpoint += "&end-date=#{trans_end_date}"
end end
# request_content = send_request_to_sf(endpoint) response = send_request_to_sf(endpoint)
# # TODO: Remove JSON Reading for real requests. Disabled currently due to preventing rate limits.
json_file_path = Rails.root.join("sample.simple.fin.json")
accounts = []
error_messages = []
if File.exist?(json_file_path)
request_content = File.read(json_file_path)
else
Rails.logger.warn "SimpleFIN: Sample JSON file not found at #{json_file_path}. Returning empty accounts."
end
# Parse our content # Parse our content
parsed_json = JSON.parse(request_content) accounts = response["accounts"] || []
accounts = parsed_json["accounts"] || [] error_messages = response["errors"] || []
error_messages = parsed_json["errors"] || []
# The only way we can really determine types right now is by some properties. Try and set their types # The only way we can really determine types right now is by some properties. Try and set their types
@ -128,7 +123,7 @@ class Provider::SimpleFin
# Accounts can be considered Investment accounts if they have any holdings associated to them # Accounts can be considered Investment accounts if they have any holdings associated to them
if account.key?("holdings") && account["holdings"].is_a?(Array) && !account["holdings"].empty? if account.key?("holdings") && account["holdings"].is_a?(Array) && !account["holdings"].empty?
account["type"] = "Investment" account["type"] = "Investment"
elsif account["balance"].to_d <= 0 && account["name"]&.downcase&.include?("card") elsif account["balance"].to_d <= 0 && (account["name"]&.downcase&.include?("card") || account["name"]&.downcase&.include?("signature"))
account["type"] = "CreditCard" account["type"] = "CreditCard"
elsif account["balance"].to_d.negative? # Could be loan or credit card elsif account["balance"].to_d.negative? # Could be loan or credit card
account["type"] = "Loan" # Default for negative balance if not clearly a card account["type"] = "Loan" # Default for negative balance if not clearly a card

View file

@ -19,21 +19,24 @@ class SimpleFinAccount < ApplicationRecord
class << self class << self
# Gets what balance we should use as our account balance ##
def get_adjusted_balance(sf_account_data) # In most instances, SimpleFIN returns either negative or positive values based on the account type. So credit would be negative, cash would be positive.
balance_from_sf = sf_account_data["balance"].to_d # This is however an issue for this application as it tries to handle that for you. This function is intended just to invert the type, based on the account type.
account_type = sf_account_data["type"] def get_adjusted_number(sf_num, acc_type)
# Adjust balance: liabilities (CreditCard, Loan) should be negative # Adjust balance: liabilities (CreditCard, Loan) should be negative
if [ "CreditCard", "Loan" ].include?(account_type) if [ "CreditCard", "Loan" ].include?(acc_type)
balance_from_sf * -1 sf_num * -1
else else
balance_from_sf sf_num
end end
end end
def find_or_create_from_simple_fin_data!(sf_account_data, sfc) def find_or_create_from_simple_fin_data!(sf_account_data, sfc)
sfc.simple_fin_accounts.find_or_create_by!(external_id: sf_account_data["id"]) do |sfa| sfc.simple_fin_accounts.find_or_create_by!(external_id: sf_account_data["id"]) do |sfa|
balance = get_adjusted_balance(sf_account_data) balance_from_sf = sf_account_data["balance"].to_d
account_type = sf_account_data["type"]
balance = get_adjusted_number(balance_from_sf, account_type)
sfa.current_balance = balance sfa.current_balance = balance
sfa.available_balance = sf_account_data["available-balance"]&.to_d sfa.available_balance = sf_account_data["available-balance"]&.to_d
sfa.currency = sf_account_data["currency"] sfa.currency = sf_account_data["currency"]
@ -93,8 +96,9 @@ class SimpleFinAccount < ApplicationRecord
## ##
# Syncs all account data for the given sf_account_data parameter # Syncs all account data for the given sf_account_data parameter
def sync_account_data!(sf_account_data) def sync_account_data!(sf_account_data)
balance = SimpleFinAccount.get_adjusted_balance(sf_account_data) balance_from_sf = sf_account_data["balance"].to_d
puts "SFA #{sf_account_data} #{self.account.inspect}" account_type = sf_account_data["type"]
balance = SimpleFinAccount.get_adjusted_number(balance_from_sf, account_type)
self.update!( self.update!(
current_balance: balance, current_balance: balance,
available_balance: sf_account_data["available-balance"]&.to_d available_balance: sf_account_data["available-balance"]&.to_d
@ -166,9 +170,14 @@ class SimpleFinAccount < ApplicationRecord
sf_transactions_data.each do |transaction_data| sf_transactions_data.each do |transaction_data|
entry = self.account.entries.find_or_initialize_by(simple_fin_transaction_id: transaction_data["id"]) entry = self.account.entries.find_or_initialize_by(simple_fin_transaction_id: transaction_data["id"])
amount_from_sf = transaction_data["amount"].to_d
account_type = self.account.accountable_type
amount = SimpleFinAccount.get_adjusted_number(amount_from_sf, account_type)
puts "AMOUNT #{amount} #{amount_from_sf} #{transaction_data}"
entry.assign_attributes( entry.assign_attributes(
name: transaction_data["description"], name: transaction_data["description"],
amount: transaction_data["amount"].to_d, amount: amount,
currency: self.account.currency, currency: self.account.currency,
date: Time.at(transaction_data["posted"].to_i).to_date, date: Time.at(transaction_data["posted"].to_i).to_date,
source: "simple_fin" source: "simple_fin"