diff --git a/app/controllers/transactions_controller.rb b/app/controllers/transactions_controller.rb
index 55bb8100..accdeab3 100644
--- a/app/controllers/transactions_controller.rb
+++ b/app/controllers/transactions_controller.rb
@@ -67,9 +67,6 @@ class TransactionsController < ApplicationController
redirect_back_or_to transactions_url, notice: t(".success")
end
- def rules
- end
-
private
def amount
@@ -93,7 +90,8 @@ class TransactionsController < ApplicationController
end
def search_params
- params.fetch(:q, {}).permit(:start_date, :end_date, :search, accounts: [], account_ids: [], categories: [], merchants: [])
+ params.fetch(:q, {})
+ .permit(:start_date, :end_date, :search, :amount, :amount_operator, accounts: [], account_ids: [], categories: [], merchants: [], types: [])
end
def transaction_entry_params
diff --git a/app/helpers/transactions_helper.rb b/app/helpers/transactions_helper.rb
index eab4bce1..23bbede6 100644
--- a/app/helpers/transactions_helper.rb
+++ b/app/helpers/transactions_helper.rb
@@ -1,12 +1,12 @@
module TransactionsHelper
def transaction_search_filters
[
- { key: "account_filter", name: "Account", icon: "layers" },
- { key: "date_filter", name: "Date", icon: "calendar" },
- { key: "type_filter", name: "Type", icon: "shapes" },
- { key: "amount_filter", name: "Amount", icon: "hash" },
- { key: "category_filter", name: "Category", icon: "tag" },
- { key: "merchant_filter", name: "Merchant", icon: "store" }
+ { key: "account_filter", icon: "layers" },
+ { key: "date_filter", icon: "calendar" },
+ { key: "type_filter", icon: "shapes" },
+ { key: "amount_filter", icon: "hash" },
+ { key: "category_filter", icon: "tag" },
+ { key: "merchant_filter", icon: "store" }
]
end
diff --git a/app/models/account/entry.rb b/app/models/account/entry.rb
index 56754cb6..9bedbab0 100644
--- a/app/models/account/entry.rb
+++ b/app/models/account/entry.rb
@@ -148,6 +148,27 @@ class Account::Entry < ApplicationRecord
query = query.where("account_entries.date >= ?", params[:start_date]) if params[:start_date].present?
query = query.where("account_entries.date <= ?", params[:end_date]) if params[:end_date].present?
+ if params[:types].present?
+ query = query.where(marked_as_transfer: false) unless params[:types].include?("transfer")
+
+ if params[:types].include?("income") && !params[:types].include?("expense")
+ query = query.where("account_entries.amount < 0")
+ elsif params[:types].include?("expense") && !params[:types].include?("income")
+ query = query.where("account_entries.amount >= 0")
+ end
+ end
+
+ if params[:amount].present? && params[:amount_operator].present?
+ case params[:amount_operator]
+ when "equal"
+ query = query.where("ABS(ABS(account_entries.amount) - ?) <= 0.01", params[:amount].to_f.abs)
+ when "less"
+ query = query.where("ABS(account_entries.amount) < ?", params[:amount].to_f.abs)
+ when "greater"
+ query = query.where("ABS(account_entries.amount) > ?", params[:amount].to_f.abs)
+ end
+ end
+
if params[:accounts].present? || params[:account_ids].present?
query = query.joins(:account)
end
diff --git a/app/views/transactions/searches/_menu.html.erb b/app/views/transactions/searches/_menu.html.erb
index 2964ea1d..d474ca55 100644
--- a/app/views/transactions/searches/_menu.html.erb
+++ b/app/views/transactions/searches/_menu.html.erb
@@ -1,3 +1,5 @@
+<%# locals: (form:) %>
+
-
+
<% transaction_search_filters.each do |filter| %>
<%= render partial: get_transaction_search_filter_partial_path(filter), locals: { form: form } %>
<% end %>
-
- <%= button_tag type: "reset", data: { action: "menu#close" }, class: "py-2 px-3 bg-gray-50 rounded-lg text-sm text-gray-900 font-medium" do %>
- Cancel
- <% end %>
- <%= form.submit "Apply", name: nil, class: "py-2 px-3 bg-gray-900 hover:bg-gray-700 rounded-lg text-sm text-white font-medium cursor-pointer" %>
+
+
+
+ <% if @q.present? %>
+ <%= link_to t(".clear_filters"), transactions_path, class: "text-sm underline text-gray-500" %>
+ <% end %>
+
+
+
+ <%= button_tag type: "reset", data: { action: "menu#close" }, class: "py-2 px-3 bg-gray-50 rounded-lg text-sm text-gray-900 font-medium" do %>
+ <%= t(".cancel") %>
+ <% end %>
+ <%= form.submit t(".apply"), name: nil, class: "py-2 px-3 bg-gray-900 hover:bg-gray-700 rounded-lg text-sm text-white font-medium cursor-pointer" %>
+
diff --git a/app/views/transactions/searches/_search.html.erb b/app/views/transactions/searches/_search.html.erb
index 506444ea..0108d95a 100644
--- a/app/views/transactions/searches/_search.html.erb
+++ b/app/views/transactions/searches/_search.html.erb
@@ -1,10 +1,24 @@
<%= render "transactions/searches/form" %>
- <% @q.each do |param_key, param_value| %>
+ <% @q.reject { |key| key == "amount_operator" }.each do |param_key, param_value| %>
<% unless param_value.blank? %>
- <% Array(param_value).each do |value| %>
- <%= render partial: "transactions/searches/filters/badge", locals: { param_key: param_key, param_value: value } %>
+ <% if param_key == "amount" %>
+ <% amount_operator = case @q[:amount_operator]
+ when "equal"
+ t(".equal_to")
+ when "greater"
+ t(".greater_than")
+ when "less"
+ t(".less_than")
+ else
+ t(@q[:amount_operator])
+ end %>
+ <%= render partial: "transactions/searches/filters/badge", locals: { param_key: "amount", param_value: "#{amount_operator} #{param_value}" } %>
+ <% else %>
+ <% Array(param_value).each do |value| %>
+ <%= render partial: "transactions/searches/filters/badge", locals: { param_key: param_key, param_value: value } %>
+ <% end %>
<% end %>
<% end %>
<% end %>
diff --git a/app/views/transactions/searches/filters/_amount_filter.html.erb b/app/views/transactions/searches/filters/_amount_filter.html.erb
index ae785f06..c1f629ba 100644
--- a/app/views/transactions/searches/filters/_amount_filter.html.erb
+++ b/app/views/transactions/searches/filters/_amount_filter.html.erb
@@ -1,4 +1,15 @@
<%# locals: (form:) %>
-
-
Filter by amount coming soon...
+
+
+
+ <%= form.select :amount_operator, options_for_select([
+ [t(".equal_to"), "equal"],
+ [t(".greater_than"), "greater"],
+ [t(".less_than"), "less"]
+ ], @q[:amount_operator] || "equal"), {}, class: "form-field__input" %>
+
+
+
+ <%= form.number_field :amount, step: 0.01, class: "form-field__input", placeholder: t(".placeholder"), value: @q[:amount] %>
+
diff --git a/app/views/transactions/searches/filters/_badge.html.erb b/app/views/transactions/searches/filters/_badge.html.erb
index 14f1bf64..f0ec8b1a 100644
--- a/app/views/transactions/searches/filters/_badge.html.erb
+++ b/app/views/transactions/searches/filters/_badge.html.erb
@@ -1,14 +1,13 @@
<%# locals: (param_key:, param_value:) %>
-
-
<% if param_key == "start_date" || param_key == "end_date" %>
<%= lucide_icon "calendar", class: "w-5 h-5 text-gray-500" %>
<% if param_key == "start_date" %>
- on or after <%= param_value %>
+ <%= t(".on_or_after", date: param_value) %>
<% else %>
- on or before <%= param_value %>
+ <%= t(".on_or_before", date: param_value) %>
<% end %>
@@ -22,6 +21,20 @@
<%= param_value[0].upcase %>
<%= param_value %>
+ <% elsif param_key == "amount" %>
+
+ <%= lucide_icon "hash", class: "w-5 h-5 text-gray-500" %>
+
<%= param_value %>
+
+ <% elsif param_key == "types" %>
+
+
">
+
<%= t(".#{param_value.downcase}") %>
+
<% else %>
<%= param_value %>
diff --git a/app/views/transactions/searches/filters/_type_filter.html.erb b/app/views/transactions/searches/filters/_type_filter.html.erb
index a273a374..5effc7e9 100644
--- a/app/views/transactions/searches/filters/_type_filter.html.erb
+++ b/app/views/transactions/searches/filters/_type_filter.html.erb
@@ -1,4 +1,37 @@
<%# locals: (form:) %>
-
-
Filter by type coming soon...
+
+
+
+ <%= form.check_box :types,
+ {
+ multiple: true,
+ checked: @q[:types]&.include?("income"),
+ class: "maybe-checkbox maybe-checkbox--light"
+ },
+ "income",
+ nil %>
+ <%= form.label :types, t(".income"), value: "income", class: "text-sm text-gray-900" %>
+
+
+ <%= form.check_box :types,
+ {
+ multiple: true,
+ checked: @q[:types]&.include?("expense"),
+ class: "maybe-checkbox maybe-checkbox--light"
+ },
+ "expense",
+ nil %>
+ <%= form.label :types, t(".expense"), value: "expense", class: "text-sm text-gray-900" %>
+
+
+ <%= form.check_box :types,
+ {
+ multiple: true,
+ checked: @q[:types]&.include?("transfer"),
+ class: "maybe-checkbox maybe-checkbox--light"
+ },
+ "transfer",
+ nil %>
+ <%= form.label :types, t(".transfer"), value: "transfer", class: "text-sm text-gray-900" %>
+
diff --git a/config/locales/views/transactions/en.yml b/config/locales/views/transactions/en.yml
index 6b9490c5..5089fad5 100644
--- a/config/locales/views/transactions/en.yml
+++ b/config/locales/views/transactions/en.yml
@@ -44,5 +44,36 @@ en:
success: Marked as transfer
new:
new_transaction: New transaction
+ searches:
+ filters:
+ amount_filter:
+ equal_to: Equal to
+ greater_than: Greater than
+ less_than: Less than
+ placeholder: '0'
+ badge:
+ expense: Expense
+ income: Income
+ on_or_after: on or after %{date}
+ on_or_before: on or before %{date}
+ transfer: Transfer
+ type_filter:
+ expense: Expense
+ income: Income
+ transfer: Transfer
+ menu:
+ account_filter: Account
+ amount_filter: Amount
+ apply: Apply
+ cancel: Cancel
+ category_filter: Category
+ clear_filters: Clear filters
+ date_filter: Date
+ merchant_filter: Merchant
+ type_filter: Type
+ search:
+ equal_to: equal to
+ greater_than: greater than
+ less_than: less than
unmark_transfers:
success: Transfer removed
diff --git a/config/routes.rb b/config/routes.rb
index 13469d26..2dfcd4da 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -91,7 +91,6 @@ Rails.application.routes.draw do
post "bulk_update"
post "mark_transfers"
post "unmark_transfers"
- get "rules"
end
end
diff --git a/test/system/transactions_test.rb b/test/system/transactions_test.rb
index 8b31372b..4544c6c4 100644
--- a/test/system/transactions_test.rb
+++ b/test/system/transactions_test.rb
@@ -77,10 +77,11 @@ class TransactionsTest < ApplicationSystemTestCase
fill_in "q_end_date", with: 1.day.ago.to_date
click_button "Type"
- assert_text "Filter by type coming soon..."
+ check("Income")
click_button "Amount"
- assert_text "Filter by amount coming soon..."
+ select "Less than"
+ fill_in "q_amount", with: 200
click_button "Category"
check(category.name)
@@ -102,6 +103,8 @@ class TransactionsTest < ApplicationSystemTestCase
find("li", text: account.name).first("a").click
find("li", text: "on or after #{10.days.ago.to_date}").first("a").click
find("li", text: "on or before #{1.day.ago.to_date}").first("a").click
+ find("li", text: "Income").first("a").click
+ find("li", text: "less than 200").first("a").click
find("li", text: category.name).first("a").click
find("li", text: merchant.name).first("a").click
end