From 567e179a7aa94fe565f443abcbdf321e1a566dc2 Mon Sep 17 00:00:00 2001 From: Manu Gurudath Date: Wed, 5 Aug 2026 10:39:01 -0700 Subject: [PATCH 1/3] Normalize payee emails and downcase existing ones --- app/models/payee.rb | 2 ++ app/policies/payroll/position_policy.rb | 5 ++++- .../20260805120000_downcase_payee_emails.rb | 16 ++++++++++++++++ db/schema.rb | 2 +- 4 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20260805120000_downcase_payee_emails.rb diff --git a/app/models/payee.rb b/app/models/payee.rb index a3a92b13f6..34bc8e3bb3 100644 --- a/app/models/payee.rb +++ b/app/models/payee.rb @@ -38,6 +38,8 @@ class Payee < ApplicationRecord validate :managed_legal_entity_constraints + normalizes :email, with: ->(email) { email.strip.downcase } + scope :not_archived, -> { where(archived_at: nil) } pg_search_scope :search, against: [:display_name, :email], using: { tsearch: { prefix: true, dictionary: "english" } } diff --git a/app/policies/payroll/position_policy.rb b/app/policies/payroll/position_policy.rb index 48210963ca..5d0a8fc237 100644 --- a/app/policies/payroll/position_policy.rb +++ b/app/policies/payroll/position_policy.rb @@ -52,7 +52,10 @@ def review? end def onboarding? - user&.auditor? || record.payee.legal_entity&.users&.include?(user) || user&.email == record.payee.email + return true if user&.auditor? + return true if record.payee.legal_entity&.users&.include?(user) + + user&.email.present? && user.email.casecmp?(record.payee.email.to_s) end private diff --git a/db/migrate/20260805120000_downcase_payee_emails.rb b/db/migrate/20260805120000_downcase_payee_emails.rb new file mode 100644 index 0000000000..c88030c32b --- /dev/null +++ b/db/migrate/20260805120000_downcase_payee_emails.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +class DowncasePayeeEmails < ActiveRecord::Migration[8.1] + disable_ddl_transaction! + + def up + Payee.where("email <> lower(btrim(email))").in_batches(of: 1_000) do |batch| + batch.update_all("email = lower(btrim(email))") + end + end + + def down + # Irreversible: the original casing isn't recoverable. + end + +end diff --git a/db/schema.rb b/db/schema.rb index c4f4818db7..5b41390f54 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -12,7 +12,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[8.1].define(version: 2026_08_04_120000) do +ActiveRecord::Schema[8.1].define(version: 2026_08_05_120000) do # These are extensions that must be enabled in order to support this database enable_extension "citext" enable_extension "pg_catalog.plpgsql" From 92094fb19fb2c4b12d4c501114122e89b3ffef81 Mon Sep 17 00:00:00 2001 From: Manu Gurudath Date: Wed, 5 Aug 2026 12:41:10 -0700 Subject: [PATCH 2/3] Update 20260805120000_downcase_payee_emails.rb --- db/migrate/20260805120000_downcase_payee_emails.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/migrate/20260805120000_downcase_payee_emails.rb b/db/migrate/20260805120000_downcase_payee_emails.rb index c88030c32b..6b5f849891 100644 --- a/db/migrate/20260805120000_downcase_payee_emails.rb +++ b/db/migrate/20260805120000_downcase_payee_emails.rb @@ -10,7 +10,7 @@ def up end def down - # Irreversible: the original casing isn't recoverable. + # irreversible end end From a02d6f500eca0c96a3064bd700629bf59d9c7c09 Mon Sep 17 00:00:00 2001 From: Manu Gurudath Date: Sat, 8 Aug 2026 15:17:46 -0700 Subject: [PATCH 3/3] Fix gary's feedback --- app/policies/payroll/position_policy.rb | 5 +++-- .../maintenance/downcase_payee_emails_task.rb | 14 ++++++++++++++ .../20260805120000_downcase_payee_emails.rb | 16 ---------------- db/schema.rb | 2 +- 4 files changed, 18 insertions(+), 19 deletions(-) create mode 100644 app/tasks/maintenance/downcase_payee_emails_task.rb delete mode 100644 db/migrate/20260805120000_downcase_payee_emails.rb diff --git a/app/policies/payroll/position_policy.rb b/app/policies/payroll/position_policy.rb index 5d0a8fc237..095f2cdc29 100644 --- a/app/policies/payroll/position_policy.rb +++ b/app/policies/payroll/position_policy.rb @@ -52,10 +52,11 @@ def review? end def onboarding? - return true if user&.auditor? + return false if user.nil? + return true if user.auditor? return true if record.payee.legal_entity&.users&.include?(user) - user&.email.present? && user.email.casecmp?(record.payee.email.to_s) + user.email == record.payee.email end private diff --git a/app/tasks/maintenance/downcase_payee_emails_task.rb b/app/tasks/maintenance/downcase_payee_emails_task.rb new file mode 100644 index 0000000000..c477bfa385 --- /dev/null +++ b/app/tasks/maintenance/downcase_payee_emails_task.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module Maintenance + class DowncasePayeeEmailsTask < MaintenanceTasks::Task + def collection + Payee.where("email <> lower(btrim(email))") + end + + def process(payee) + payee.update!(email: payee.email) + end + + end +end diff --git a/db/migrate/20260805120000_downcase_payee_emails.rb b/db/migrate/20260805120000_downcase_payee_emails.rb deleted file mode 100644 index 6b5f849891..0000000000 --- a/db/migrate/20260805120000_downcase_payee_emails.rb +++ /dev/null @@ -1,16 +0,0 @@ -# frozen_string_literal: true - -class DowncasePayeeEmails < ActiveRecord::Migration[8.1] - disable_ddl_transaction! - - def up - Payee.where("email <> lower(btrim(email))").in_batches(of: 1_000) do |batch| - batch.update_all("email = lower(btrim(email))") - end - end - - def down - # irreversible - end - -end diff --git a/db/schema.rb b/db/schema.rb index 5b41390f54..c4f4818db7 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -12,7 +12,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[8.1].define(version: 2026_08_05_120000) do +ActiveRecord::Schema[8.1].define(version: 2026_08_04_120000) do # These are extensions that must be enabled in order to support this database enable_extension "citext" enable_extension "pg_catalog.plpgsql"