diff --git a/app/controllers/rules_controller.rb b/app/controllers/rules_controller.rb
index 07c355a56..5e7496cb8 100644
--- a/app/controllers/rules_controller.rb
+++ b/app/controllers/rules_controller.rb
@@ -11,7 +11,7 @@ class RulesController < ApplicationController
@sort_by = "name" unless allowed_columns.include?(@sort_by)
@direction = "asc" unless [ "asc", "desc" ].include?(@direction)
- @rules = Current.family.rules.order(@sort_by => @direction)
+ @rules = Current.family.rules.includes(conditions: :sub_conditions).order(@sort_by => @direction)
# Fetch recent rule runs with pagination
recent_runs_scope = RuleRun
diff --git a/app/models/rule.rb b/app/models/rule.rb
index cd18deadc..74dbaece8 100644
--- a/app/models/rule.rb
+++ b/app/models/rule.rb
@@ -86,14 +86,23 @@ class Rule < ApplicationRecord
end
def primary_condition_title
- return "No conditions" if conditions.none?
+ condition = displayed_condition
+ return I18n.t("rules.no_condition") if condition.blank?
- first_condition = conditions.first
- if first_condition.compound? && first_condition.sub_conditions.any?
- first_sub_condition = first_condition.sub_conditions.first
- "If #{first_sub_condition.filter.label.downcase} #{first_sub_condition.operator} #{first_sub_condition.value_display}"
- else
- "If #{first_condition.filter.label.downcase} #{first_condition.operator} #{first_condition.value_display}"
+ "If #{condition.filter.label.downcase} #{condition.operator} #{condition.value_display}"
+ end
+
+ def displayed_condition
+ displayable_conditions.first
+ end
+
+ def additional_displayable_conditions_count
+ [ displayable_conditions.size - 1, 0 ].max
+ end
+
+ def displayable_conditions
+ conditions.filter_map do |condition|
+ condition.compound? ? condition.sub_conditions.first : condition
end
end
diff --git a/app/views/rules/_rule.html.erb b/app/views/rules/_rule.html.erb
index c0d59bea2..2e882e4ba 100644
--- a/app/views/rules/_rule.html.erb
+++ b/app/views/rules/_rule.html.erb
@@ -6,20 +6,22 @@
<%= rule.name %>
<% end %>
<% if rule.conditions.any? %>
+ <% displayed_condition = rule.displayed_condition %>
+ <% additional_condition_count = rule.additional_displayable_conditions_count %>
IF
- <% if rule.conditions.first.compound? %>
- <%= rule.conditions.first.sub_conditions.first.filter.label %> <%= rule.conditions.first.sub_conditions.first.operator %> <%= rule.conditions.first.sub_conditions.first.value_display %>
+ <% if displayed_condition.present? %>
+ <%= displayed_condition.filter.label %> <%= displayed_condition.operator %> <%= displayed_condition.value_display %>
<% else %>
- <%= rule.conditions.first.filter.label %> <%= rule.conditions.first.operator %> <%= rule.conditions.first.value_display %>
+ <%= t("rules.no_condition") %>
<% end %>
- <% if rule.conditions.count > 1 %>
- and <%= rule.conditions.count - 1 %> more <%= rule.conditions.count - 1 == 1 ? "condition" : "conditions" %>
+ <% if additional_condition_count.positive? %>
+ and <%= additional_condition_count %> more <%= additional_condition_count == 1 ? "condition" : "conditions" %>
<% end %>
diff --git a/config/locales/views/rules/ca.yml b/config/locales/views/rules/ca.yml
index c4b40ca90..b1cacb21f 100644
--- a/config/locales/views/rules/ca.yml
+++ b/config/locales/views/rules/ca.yml
@@ -19,6 +19,7 @@ ca:
success: Totes les regles s'han posat a cua per a execució
view_usage: Veure l'historial d'ús
no_action: Sense acció
+ no_condition: Sense condició
recent_runs:
columns:
date_time: Data/Hora
diff --git a/config/locales/views/rules/de.yml b/config/locales/views/rules/de.yml
index a8a80bdff..cc57171b0 100644
--- a/config/locales/views/rules/de.yml
+++ b/config/locales/views/rules/de.yml
@@ -2,6 +2,7 @@
de:
rules:
no_action: Keine Aktion
+ no_condition: Keine Bedingung
recent_runs:
title: Letzte Ausführungen
description: Zeige die Ausführungsgeschichte deiner Regeln einschließlich Erfolgs-/Fehlerstatus und Transaktionsanzahlen.
@@ -22,4 +23,3 @@ de:
pending: Ausstehend
success: Erfolgreich
failed: Fehlgeschlagen
-
diff --git a/config/locales/views/rules/en.yml b/config/locales/views/rules/en.yml
index e390e0ecc..81eccc7e8 100644
--- a/config/locales/views/rules/en.yml
+++ b/config/locales/views/rules/en.yml
@@ -2,6 +2,7 @@
en:
rules:
no_action: No Action
+ no_condition: No condition
actions:
value_placeholder: Enter a value
apply_all:
diff --git a/config/locales/views/rules/es.yml b/config/locales/views/rules/es.yml
index 472ed0240..3c494e8fb 100644
--- a/config/locales/views/rules/es.yml
+++ b/config/locales/views/rules/es.yml
@@ -2,6 +2,7 @@
es:
rules:
no_action: Sin acción
+ no_condition: Sin condición
recent_runs:
title: Ejecuciones Recientes
description: Ver el historial de ejecución de tus reglas incluyendo el estado de éxito/fallo y los conteos de transacciones.
@@ -22,4 +23,3 @@ es:
pending: Pendiente
success: Éxito
failed: Fallido
-
diff --git a/config/locales/views/rules/fr.yml b/config/locales/views/rules/fr.yml
index daa5c42cc..dfa7b9755 100644
--- a/config/locales/views/rules/fr.yml
+++ b/config/locales/views/rules/fr.yml
@@ -2,6 +2,7 @@
fr:
rules:
no_action: Aucune action
+ no_condition: Aucune condition
actions:
value_placeholder: Entrez une valeur
apply_all:
diff --git a/config/locales/views/rules/nb.yml b/config/locales/views/rules/nb.yml
index 1787cf18e..c4a333b40 100644
--- a/config/locales/views/rules/nb.yml
+++ b/config/locales/views/rules/nb.yml
@@ -2,6 +2,7 @@
nb:
rules:
no_action: Ingen handling
+ no_condition: Ingen betingelse
recent_runs:
title: Siste Kjøringer
description: Se kjøringsloggen for reglene dine inkludert suksess/feil-status og transaksjonsantall.
@@ -22,4 +23,3 @@ nb:
pending: Ventende
success: Vellykket
failed: Mislyktes
-
diff --git a/config/locales/views/rules/nl.yml b/config/locales/views/rules/nl.yml
index 9ef32b833..a789d20c9 100644
--- a/config/locales/views/rules/nl.yml
+++ b/config/locales/views/rules/nl.yml
@@ -2,6 +2,7 @@
nl:
rules:
no_action: Geen actie
+ no_condition: Geen voorwaarde
actions:
value_placeholder: Voer een waarde in
apply_all:
diff --git a/config/locales/views/rules/ro.yml b/config/locales/views/rules/ro.yml
index 3f3ccb8c5..c5e877aab 100644
--- a/config/locales/views/rules/ro.yml
+++ b/config/locales/views/rules/ro.yml
@@ -2,6 +2,7 @@
ro:
rules:
no_action: Nicio acțiune
+ no_condition: Nicio condiție
recent_runs:
title: Rulări Recente
description: Vezi istoricul de execuție al regulilor tale incluzând statusul de succes/eșec și numărul de tranzacții.
@@ -22,4 +23,3 @@ ro:
pending: În Așteptare
success: Succes
failed: Eșuat
-
diff --git a/config/locales/views/rules/tr.yml b/config/locales/views/rules/tr.yml
index c2d50c11d..b1418415e 100644
--- a/config/locales/views/rules/tr.yml
+++ b/config/locales/views/rules/tr.yml
@@ -2,6 +2,7 @@
tr:
rules:
no_action: İşlem yok
+ no_condition: Koşul yok
recent_runs:
title: Son Çalıştırmalar
description: Başarı/başarısızlık durumu ve işlem sayıları dahil olmak üzere kurallarınızın yürütme geçmişini görüntüleyin.
@@ -22,4 +23,3 @@ tr:
pending: Beklemede
success: Başarılı
failed: Başarısız
-
diff --git a/config/locales/views/rules/zh-CN.yml b/config/locales/views/rules/zh-CN.yml
index 5044d8b00..6f44adc5f 100644
--- a/config/locales/views/rules/zh-CN.yml
+++ b/config/locales/views/rules/zh-CN.yml
@@ -2,6 +2,7 @@
zh-CN:
rules:
no_action: 无操作
+ no_condition: 无条件
recent_runs:
columns:
date_time: 日期/时间
diff --git a/config/locales/views/rules/zh-TW.yml b/config/locales/views/rules/zh-TW.yml
index 5a8bdf3bd..84846ce24 100644
--- a/config/locales/views/rules/zh-TW.yml
+++ b/config/locales/views/rules/zh-TW.yml
@@ -2,6 +2,7 @@
zh-TW:
rules:
no_action: 無動作
+ no_condition: 無條件
recent_runs:
title: 最近執行紀錄
description: 查看規則的執行歷史,包括成功/失敗狀態以及交易處理筆數。
diff --git a/test/controllers/rules_controller_test.rb b/test/controllers/rules_controller_test.rb
index 681bac37b..baa30a1f3 100644
--- a/test/controllers/rules_controller_test.rb
+++ b/test/controllers/rules_controller_test.rb
@@ -180,6 +180,36 @@ class RulesControllerTest < ActionDispatch::IntegrationTest
assert_redirected_to rules_url
end
+ test "index renders when rule has empty compound condition" do
+ malformed_rule = @user.family.rules.build(resource_type: "transaction")
+ malformed_rule.conditions.build(condition_type: "compound", operator: "and")
+ malformed_rule.actions.build(action_type: "exclude_transaction")
+ malformed_rule.save!
+
+ get rules_url
+
+ assert_response :success
+ assert_includes response.body, I18n.t("rules.no_condition")
+ end
+
+ test "index uses next valid condition when first compound condition is empty" do
+ rule = @user.family.rules.build(resource_type: "transaction")
+ rule.conditions.build(condition_type: "compound", operator: "and")
+ rule.conditions.build(condition_type: "transaction_name", operator: "like", value: "edge-case-name")
+ rule.actions.build(action_type: "exclude_transaction")
+ rule.save!
+
+ get rules_url
+
+ assert_response :success
+
+ assert_select "##{ActionView::RecordIdentifier.dom_id(rule)}" do
+ assert_select "span", text: /edge-case-name/
+ assert_select "span", text: /#{Regexp.escape(I18n.t("rules.no_condition"))}/, count: 0
+ assert_select "p", text: /and 1 more condition/, count: 0
+ end
+ end
+
test "should get confirm_all" do
get confirm_all_rules_url
assert_response :success
diff --git a/test/models/rule_test.rb b/test/models/rule_test.rb
index 408cb8cca..6f50221be 100644
--- a/test/models/rule_test.rb
+++ b/test/models/rule_test.rb
@@ -138,6 +138,40 @@ class RuleTest < ActiveSupport::TestCase
assert_equal [ "Compound conditions cannot be nested" ], rule.errors.full_messages
end
+ test "displayed_condition falls back to next valid condition when first compound condition is empty" do
+ rule = Rule.new(
+ family: @family,
+ resource_type: "transaction",
+ actions: [ Rule::Action.new(action_type: "exclude_transaction") ],
+ conditions: [
+ Rule::Condition.new(condition_type: "compound", operator: "and"),
+ Rule::Condition.new(condition_type: "transaction_name", operator: "like", value: "starbucks")
+ ]
+ )
+
+ displayed_condition = rule.displayed_condition
+
+ assert_not_nil displayed_condition
+ assert_equal "transaction_name", displayed_condition.condition_type
+ assert_equal "like", displayed_condition.operator
+ assert_equal "starbucks", displayed_condition.value
+ end
+
+ test "additional_displayable_conditions_count ignores empty compound conditions" do
+ rule = Rule.new(
+ family: @family,
+ resource_type: "transaction",
+ actions: [ Rule::Action.new(action_type: "exclude_transaction") ],
+ conditions: [
+ Rule::Condition.new(condition_type: "compound", operator: "and"),
+ Rule::Condition.new(condition_type: "transaction_name", operator: "like", value: "first"),
+ Rule::Condition.new(condition_type: "transaction_amount", operator: ">", value: 100)
+ ]
+ )
+
+ assert_equal 1, rule.additional_displayable_conditions_count
+ end
+
test "rule matching on transaction details" do
# Create PayPal transaction with underlying merchant in details
paypal_entry = create_transaction(