Skip to content

Commit dd99336

Browse files
fix(transactions): address PR review feedback for one-time budget scoping
Route Budget#actual_income through budget-scoped income_totals, update report exclusion comments, harden excluded_kinds_sql quoting, and add budget tests. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent ba88d96 commit dd99336

4 files changed

Lines changed: 56 additions & 5 deletions

File tree

app/controllers/reports_controller.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ def build_trends_data
356356

357357
def build_transactions_breakdown
358358
# Base query: all transactions in the period
359-
# Exclude transfers, one-time, and CC payments (matching income_statement logic)
359+
# Exclude transfers and CC payments (matching income_statement report logic)
360360
transactions = Transaction
361361
.joins(:entry)
362362
.joins(entry: :account)
@@ -660,7 +660,7 @@ def apply_entry_filters(scope)
660660

661661
def build_transactions_breakdown_for_export
662662
# Get flat transactions list (not grouped) for export
663-
# Exclude transfers, one-time, and CC payments (matching income_statement logic)
663+
# Exclude transfers and CC payments (matching income_statement report logic)
664664
transactions = Transaction
665665
.joins(:entry)
666666
.joins(entry: :account)
@@ -697,7 +697,7 @@ def build_monthly_breakdown_for_export
697697
end
698698

699699
# Get all transactions in the period
700-
# Exclude transfers, one-time, and CC payments (matching income_statement logic)
700+
# Exclude transfers and CC payments (matching income_statement report logic)
701701
transactions = Transaction
702702
.joins(:entry)
703703
.joins(entry: :account)

app/models/budget.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@ def estimated_income
291291
end
292292

293293
def actual_income
294-
family.income_statement.income_totals(period: self.period).total
294+
income_totals.total
295295
end
296296

297297
def actual_income_percent

app/models/income_statement/totals.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ def include_finance_accounts_sql
162162
end
163163

164164
def excluded_kinds_sql
165-
@excluded_kinds_sql ||= @excluded_kinds.map { |k| "'#{k}'" }.join(", ")
165+
@excluded_kinds_sql ||= @excluded_kinds.map { |k| ActiveRecord::Base.connection.quote(k.to_s) }.join(", ")
166166
end
167167

168168
def validate_date_range!

test/models/budget_test.rb

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,4 +453,55 @@ class BudgetTest < ActiveSupport::TestCase
453453
# Other Investments synthetic categories previously caused this to return 0
454454
assert spending >= 75, "Uncategorized actual spending should include the $75 transaction, got #{spending}"
455455
end
456+
457+
test "actual_spending and actual_income exclude one-time transactions" do
458+
family = families(:empty)
459+
account = family.accounts.create!(
460+
name: "Checking",
461+
currency: family.currency,
462+
balance: 5000,
463+
accountable: Depository.new
464+
)
465+
income_category = family.categories.create!(name: "Income")
466+
expense_category = family.categories.create!(name: "Groceries")
467+
468+
Entry.create!(
469+
account: account,
470+
entryable: Transaction.create!(category: expense_category, kind: "standard"),
471+
date: Date.current,
472+
name: "Groceries",
473+
amount: 100,
474+
currency: family.currency
475+
)
476+
Entry.create!(
477+
account: account,
478+
entryable: Transaction.create!(category: expense_category, kind: "one_time"),
479+
date: Date.current,
480+
name: "One-time expense",
481+
amount: 250,
482+
currency: family.currency
483+
)
484+
Entry.create!(
485+
account: account,
486+
entryable: Transaction.create!(category: income_category, kind: "standard"),
487+
date: Date.current,
488+
name: "Paycheck",
489+
amount: -500,
490+
currency: family.currency
491+
)
492+
Entry.create!(
493+
account: account,
494+
entryable: Transaction.create!(category: income_category, kind: "one_time"),
495+
date: Date.current,
496+
name: "One-time bonus",
497+
amount: -300,
498+
currency: family.currency
499+
)
500+
501+
budget = Budget.find_or_bootstrap(family, start_date: Date.current.beginning_of_month)
502+
budget = Budget.find(budget.id)
503+
504+
assert_equal 100, budget.actual_spending
505+
assert_equal 500, budget.actual_income
506+
end
456507
end

0 commit comments

Comments
 (0)