mirror of
https://github.com/we-promise/sure.git
synced 2026-04-20 12:34:12 +00:00
Recurring fixes (#454)
* Fix record violation and add toggle for recurring feature * Run only once per sync cycle ( 30 sec ) * FIX params passing * Add collapsible to recurring section * FIX preferences error catch
This commit is contained in:
@@ -29,7 +29,7 @@ class Family::SyncCompleteEvent
|
||||
Rails.logger.error("Family::SyncCompleteEvent net_worth_chart broadcast failed: #{e.message}\n#{e.backtrace&.join("\n")}")
|
||||
end
|
||||
|
||||
# Identify recurring transaction patterns after sync
|
||||
# Schedule recurring transaction pattern identification (debounced to run after all syncs complete)
|
||||
begin
|
||||
RecurringTransaction.identify_patterns_for(family)
|
||||
rescue => e
|
||||
|
||||
@@ -37,7 +37,14 @@ class RecurringTransaction < ApplicationRecord
|
||||
scope :expected_soon, -> { active.where("next_expected_date <= ?", 1.month.from_now) }
|
||||
|
||||
# Class methods for identification and cleanup
|
||||
# Schedules pattern identification with debounce to run after all syncs complete
|
||||
def self.identify_patterns_for(family)
|
||||
IdentifyRecurringTransactionsJob.schedule_for(family)
|
||||
0 # Return immediately, actual count will be determined by the job
|
||||
end
|
||||
|
||||
# Synchronous pattern identification (for manual triggers from UI)
|
||||
def self.identify_patterns_for!(family)
|
||||
Identifier.new(family).identify_recurring_patterns
|
||||
end
|
||||
|
||||
|
||||
@@ -81,35 +81,55 @@ class RecurringTransaction
|
||||
find_conditions[:merchant_id] = nil
|
||||
end
|
||||
|
||||
recurring_transaction = family.recurring_transactions.find_or_initialize_by(find_conditions)
|
||||
begin
|
||||
recurring_transaction = family.recurring_transactions.find_or_initialize_by(find_conditions)
|
||||
|
||||
# Handle manual recurring transactions specially
|
||||
if recurring_transaction.persisted? && recurring_transaction.manual?
|
||||
# Update variance for manual recurring transactions
|
||||
update_manual_recurring_variance(recurring_transaction, pattern)
|
||||
next
|
||||
end
|
||||
|
||||
# Set the name or merchant_id on new records
|
||||
if recurring_transaction.new_record?
|
||||
if pattern[:merchant_id].present?
|
||||
recurring_transaction.merchant_id = pattern[:merchant_id]
|
||||
else
|
||||
recurring_transaction.name = pattern[:name]
|
||||
# Handle manual recurring transactions specially
|
||||
if recurring_transaction.persisted? && recurring_transaction.manual?
|
||||
# Update variance for manual recurring transactions
|
||||
update_manual_recurring_variance(recurring_transaction, pattern)
|
||||
next
|
||||
end
|
||||
# New auto-detected recurring transactions are not manual
|
||||
recurring_transaction.manual = false
|
||||
|
||||
# Set the name or merchant_id on new records
|
||||
if recurring_transaction.new_record?
|
||||
if pattern[:merchant_id].present?
|
||||
recurring_transaction.merchant_id = pattern[:merchant_id]
|
||||
else
|
||||
recurring_transaction.name = pattern[:name]
|
||||
end
|
||||
# New auto-detected recurring transactions are not manual
|
||||
recurring_transaction.manual = false
|
||||
end
|
||||
|
||||
recurring_transaction.assign_attributes(
|
||||
expected_day_of_month: pattern[:expected_day_of_month],
|
||||
last_occurrence_date: pattern[:last_occurrence_date],
|
||||
next_expected_date: calculate_next_expected_date(pattern[:last_occurrence_date], pattern[:expected_day_of_month]),
|
||||
occurrence_count: pattern[:occurrence_count],
|
||||
status: recurring_transaction.new_record? ? "active" : recurring_transaction.status
|
||||
)
|
||||
|
||||
recurring_transaction.save!
|
||||
rescue ActiveRecord::RecordNotUnique
|
||||
# Race condition: another process created the same record between find and save.
|
||||
# Retry with find to get the existing record and update it.
|
||||
recurring_transaction = family.recurring_transactions.find_by(find_conditions)
|
||||
next unless recurring_transaction
|
||||
|
||||
# Skip manual recurring transactions
|
||||
if recurring_transaction.manual?
|
||||
update_manual_recurring_variance(recurring_transaction, pattern)
|
||||
next
|
||||
end
|
||||
|
||||
recurring_transaction.update!(
|
||||
expected_day_of_month: pattern[:expected_day_of_month],
|
||||
last_occurrence_date: pattern[:last_occurrence_date],
|
||||
next_expected_date: calculate_next_expected_date(pattern[:last_occurrence_date], pattern[:expected_day_of_month]),
|
||||
occurrence_count: pattern[:occurrence_count]
|
||||
)
|
||||
end
|
||||
|
||||
recurring_transaction.assign_attributes(
|
||||
expected_day_of_month: pattern[:expected_day_of_month],
|
||||
last_occurrence_date: pattern[:last_occurrence_date],
|
||||
next_expected_date: calculate_next_expected_date(pattern[:last_occurrence_date], pattern[:expected_day_of_month]),
|
||||
occurrence_count: pattern[:occurrence_count],
|
||||
status: recurring_transaction.new_record? ? "active" : recurring_transaction.status
|
||||
)
|
||||
|
||||
recurring_transaction.save!
|
||||
end
|
||||
|
||||
# Also check for manual recurring transactions that might need variance updates
|
||||
|
||||
@@ -234,6 +234,29 @@ class User < ApplicationRecord
|
||||
end
|
||||
end
|
||||
|
||||
# Transactions preferences management
|
||||
def transactions_section_collapsed?(section_key)
|
||||
preferences&.dig("transactions_collapsed_sections", section_key) == true
|
||||
end
|
||||
|
||||
def update_transactions_preferences(prefs)
|
||||
transaction do
|
||||
lock!
|
||||
|
||||
updated_prefs = (preferences || {}).deep_dup
|
||||
prefs.each do |key, value|
|
||||
if value.is_a?(Hash)
|
||||
updated_prefs["transactions_#{key}"] ||= {}
|
||||
updated_prefs["transactions_#{key}"] = updated_prefs["transactions_#{key}"].merge(value)
|
||||
else
|
||||
updated_prefs["transactions_#{key}"] = value
|
||||
end
|
||||
end
|
||||
|
||||
update!(preferences: updated_prefs)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def default_dashboard_section_order
|
||||
%w[cashflow_sankey outflows_donut net_worth_chart balance_sheet]
|
||||
|
||||
Reference in New Issue
Block a user