From 4e5b0957bff914bc3264e0fca4975a0e8749621a Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 23 Nov 2025 10:45:52 +0000
Subject: [PATCH] Add validation and flash message for invalid date range in
Reports
Co-authored-by: jjmata <187772+jjmata@users.noreply.github.com>
---
app/controllers/reports_controller.rb | 13 ++++++++
app/views/reports/index.html.erb | 7 +++++
config/locales/views/reports/en.yml | 1 +
test/controllers/reports_controller_test.rb | 35 +++++++++++++++++++++
4 files changed, 56 insertions(+)
diff --git a/app/controllers/reports_controller.rb b/app/controllers/reports_controller.rb
index 57791639a..724b0b789 100644
--- a/app/controllers/reports_controller.rb
+++ b/app/controllers/reports_controller.rb
@@ -11,6 +11,13 @@ class ReportsController < ApplicationController
@start_date = parse_date_param(:start_date) || default_start_date
@end_date = parse_date_param(:end_date) || default_end_date
+ # Validate and fix date range if end_date is before start_date
+ if @start_date > @end_date
+ # Swap the dates to maintain user's intended date range
+ @start_date, @end_date = @end_date, @start_date
+ flash.now[:alert] = t("reports.invalid_date_range")
+ end
+
# Build the period
@period = Period.custom(start_date: @start_date, end_date: @end_date)
@previous_period = build_previous_period
@@ -41,6 +48,12 @@ class ReportsController < ApplicationController
@period_type = params[:period_type]&.to_sym || :monthly
@start_date = parse_date_param(:start_date) || default_start_date
@end_date = parse_date_param(:end_date) || default_end_date
+
+ # Validate and fix date range if end_date is before start_date
+ if @start_date > @end_date
+ @start_date, @end_date = @end_date, @start_date
+ end
+
@period = Period.custom(start_date: @start_date, end_date: @end_date)
# Build monthly breakdown data for export
diff --git a/app/views/reports/index.html.erb b/app/views/reports/index.html.erb
index 0ad469bec..13fd9d1fc 100644
--- a/app/views/reports/index.html.erb
+++ b/app/views/reports/index.html.erb
@@ -9,6 +9,13 @@
+ <%# Flash messages %>
+ <% if flash[:alert].present? %>
+
+ <%= flash[:alert] %>
+
+ <% end %>
+
<%# Period Navigation Tabs %>
<%= render DS::Link.new(
diff --git a/config/locales/views/reports/en.yml b/config/locales/views/reports/en.yml
index 87dd04b9a..b09c5b97d 100644
--- a/config/locales/views/reports/en.yml
+++ b/config/locales/views/reports/en.yml
@@ -15,6 +15,7 @@ en:
from: From
to: To
showing_period: "Showing data from %{start} to %{end}"
+ invalid_date_range: "End date cannot be before start date. The dates have been swapped."
summary:
total_income: Total Income
total_expenses: Total Expenses
diff --git a/test/controllers/reports_controller_test.rb b/test/controllers/reports_controller_test.rb
index 4c454bf6a..0b35a6bfd 100644
--- a/test/controllers/reports_controller_test.rb
+++ b/test/controllers/reports_controller_test.rb
@@ -92,6 +92,24 @@ class ReportsControllerTest < ActionDispatch::IntegrationTest
assert_response :ok # Should not crash, uses defaults
end
+ test "index swaps dates when end_date is before start_date" do
+ start_date = Date.current
+ end_date = 1.month.ago.to_date
+
+ get reports_path(
+ period_type: :custom,
+ start_date: start_date.to_s,
+ end_date: end_date.to_s
+ )
+
+ assert_response :ok
+ # Should show flash message about invalid date range
+ assert flash[:alert].present?, "Flash alert should be present"
+ assert_match /End date cannot be before start date/, flash[:alert]
+ # Should display the swapped date range
+ assert_select ".text-sm.text-secondary", text: /Showing data from #{Regexp.escape(end_date.strftime("%b %-d, %Y"))} to #{Regexp.escape(start_date.strftime("%b %-d, %Y"))}/
+ end
+
test "spending patterns returns data when expense transactions exist" do
# Create expense category
expense_category = @family.categories.create!(
@@ -185,4 +203,21 @@ class ReportsControllerTest < ActionDispatch::IntegrationTest
assert_response :ok, "Export should work with session auth. Response: #{@response.body}"
assert_equal "text/csv", @response.media_type
end
+
+ test "export transactions swaps dates when end_date is before start_date" do
+ start_date = Date.current
+ end_date = 1.month.ago.to_date
+
+ get export_transactions_reports_path(
+ format: :csv,
+ period_type: :custom,
+ start_date: start_date.to_s,
+ end_date: end_date.to_s
+ )
+
+ assert_response :ok
+ assert_equal "text/csv", @response.media_type
+ # Verify the CSV content is generated (should not crash)
+ assert_not_nil @response.body
+ end
end