Repository: rubyforgood/human-essentials
Pull request #5093: 4176 customizing reminder message to partner
Author: login: Sukhpreet-s
Created: 2025-03-12T19:24:39Z | Merged: 2025-03-27T01:06:00Z

Resolves #4176

### Description
This PR adds functionality to include a customized message in the reminder email sent to partners. A rich text input field is added to the Organization edit form. It also allows interpolation for `partner_name` as a variable in the customized message similar to `default_email_text` field.

The following components are added/updated: 
- `reminder_email_text` rich text field is added to the [`Organization` model](https://github.com/Sukhpreet-s/human-essentials/blob/43c1b3e9ef6189f922078e0d1ce6d5d8bb2f9f5b/app/models/organization.rb#L118).
- The form field is added to the [edit](https://github.com/Sukhpreet-s/human-essentials/blob/43c1b3e9ef6189f922078e0d1ce6d5d8bb2f9f5b/app/views/organizations/edit.html.erb#L141-L144) and [show details](https://github.com/Sukhpreet-s/human-essentials/blob/43c1b3e9ef6189f922078e0d1ce6d5d8bb2f9f5b/app/views/organizations/_details.html.erb#L229-L235) `Organization` files.
- The `reminder_email_text` is displayed in both [html](https://github.com/Sukhpreet-s/human-essentials/blob/43c1b3e9ef6189f922078e0d1ce6d5d8bb2f9f5b/app/views/reminder_deadline_mailer/notify_deadline.html.erb) and [text](https://github.com/Sukhpreet-s/human-essentials/blob/43c1b3e9ef6189f922078e0d1ce6d5d8bb2f9f5b/app/views/reminder_deadline_mailer/notify_deadline.text.erb) versions of the `notify_deadline` email.

#### Looking for feedback:
1. I allowed interpolation only for `partner_name` variable in the customized message as none of the other values made sense to include. Is there any other value that need to be allowed here, like `deadline_day`?

2. The plain text version of the email looks like below. It contains some HTML comments.
<details><summary>Screenshot</summary>
<p>
<img src="https://github.com/user-attachments/assets/b431a192-d626-4347-8ac1-e3dc744ac34f" width=700/>
</p>
</details> 

I've followed the `DistributionMailer.partner_mailer` implementation and noticed that even the `DistributionMailer` has the same behaviour for the plain text version of the email. I wonder if this only happens in development environment for debugging purposes... 🤔? I've opened [an issue](https://github.com/rubyforgood/human-essentials/issues/5098) describing it in details and trying to find a fix for this.

### Type of change

* New feature (non-breaking change which adds functionality)

### How Has This Been Tested?

- Wrote test case to verify if the custom message is included in the email text when it is added by the org admin.

Also tested manually. Here are the steps:
1. Sign in as org admin.
2. Open org profile by clicking "My Organization" in the sidebar.
3. Edit the profile by clicking "Edit" button at the bottom of the page. 
4. Add some text in "Reminder Email Content" input field and save.
5. Since this email is sent via a job that runs daily at some set time, it is convenient to execute the Mailer function directly from the `rails console` using the following set of commands:
    - Execute rails console from terminal: `bundle exec rails console`
    - Get associated partner: `partner = Partner.find_by_name("<Enter name of any Partner connected to your Org>")`
    - Send email: `ReminderDeadlineMailer.notify_deadline(partner).deliver_now`
6. The email should be sent and can be accessed from `tmp/letter_opener` folder in the project locally.




### Screenshots
<details><summary>Example screenshot of the email:</summary>
<p>
The first sentence in the following screenshot is the custom reminder message.
</p>
<img src="https://github.com/user-attachments/assets/cee8982b-2f0a-4843-832c-e3afa7307a3e" />
</details> 

<details><summary>Input field in Organization profile edit page:</summary>
<img src="https://github.com/user-attachments/assets/783e0bde-eac5-4110-ba63-dd9c0af20ce2" />
</details> 

<details><summary>Reminder email text in Organization profile details page:</summary>
<img src="https://github.com/user-attachments/assets/c24e7845-bc57-4e76-b008-0b64a2ff796e" />
</details> 

<details><summary>Documentation update:</summary>
<img src="https://github.com/user-attachments/assets/de3e0ddd-7fe6-46ae-aa06-cb30224719ba" />
</details> 


Linked issue #4176: Customizing Reminder Message to Partners
# Summary
Provide the ability to customize the reminder  message for partners,  similar to how we currently allow customization of the distribution email content

# Why?
Bank request -- The banks may want to include more info in their reminder message 

# Details

For clarity, the request is to be able to customize the message that goes out to partners to remind them to put their requests in.


Please follow the pattern we have established with the distribution message.   Places that you'll want to look at include 
-- the organization edit and show pages (where we let them configure the distribution email)
-- the organization model
-- the distribution mailer 
-- the distribution mailer view

# Criteria for completion
- [ ] implementation of customized reminder messages
- [ ] tests supporting customized reminder messages

# Bonus round
- [ ] Also allow customization of the message reminding partners to pick up the distributions


    
Linked issue comments: user: login: nathangthomas
created_at: 2024-03-11T15:06:20Z
body: Good morning! I would like to take this ticket. 

author_association: CONTRIBUTOR
user: login: dorner
created_at: 2024-03-11T15:13:09Z
body: You have taken it!
author_association: COLLABORATOR
user: login: nathangthomas
created_at: 2024-03-14T18:01:27Z
body: Question regarding the Bonus: `Also allow customization of the message reminding partners to pick up the distributions`

I am having trouble finding a specific reminder message that goes out to partners who need to pick up. Is there one that I am missing or is this suggesting that if `distribution.delivery_method` is `pick_up` we should add another line to `distribution_mailer/reminder_email` reminding partners of this? Thanks! 

author_association: CONTRIBUTOR
user: login: cielf
created_at: 2024-03-14T19:32:03Z
body: You know -- I can't find it either.   Please ignore the bonus -- if I find it, I'll create a new issue.
author_association: COLLABORATOR
user: login: github-actions[bot]
created_at: 2024-04-14T00:15:48Z
body: This issue is marked as stale due to no activity within 30 days. If no further activity is detected within 7 days, it will be unassigned.
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2024-04-22T00:12:48Z
body: Automatically unassigned after 7 days of inactivity.
author_association: CONTRIBUTOR
user: login: Sukhpreet-s
created_at: 2025-03-06T18:33:03Z
body: Is this issue still open? Checking on it since it has the `stale` label and an open PR. If so, I'm happy to work on it.

Also, [the open PR](https://github.com/unabridged/human-essentials/pull/1) seems like a duplicate one from the closed one which was using the wrong approach as mentioned in [the other PR comment](https://github.com/rubyforgood/human-essentials/pull/4197#issuecomment-2294095334), so I guess that can be closed 🤔
author_association: CONTRIBUTOR
user: login: cielf
created_at: 2025-03-06T19:11:56Z
body: I was just noting that I need to check into this -- I'm pretty sure the functionality doesn't exist in production yet.   Do you want to just start fresh?  
author_association: COLLABORATOR
user: login: cielf
created_at: 2025-03-06T19:13:06Z
body: @Sukhpreet-s If you want to start fresh, yes , we will close that PR.
author_association: COLLABORATOR
user: login: Sukhpreet-s
created_at: 2025-03-06T19:37:51Z
body: Now that you asked me 😅 -- I took a thorough look at the PR and I think the existing code can be used. I'll try to use that PR for now. Thanks!
author_association: CONTRIBUTOR
user: login: nathangthomas
created_at: 2025-03-07T00:16:02Z
body: Hi all, I am the one who originally worked on this story... my
apologies for letting it go stale. Strange circumstance, but I was getting
jerked around a bit at work and had to put my attention elsewhere. I'm back
now with some time if there is something I can do to assist.

Best,

Nathan Thomas

On Thu, Mar 6, 2025 at 12:38 PM Sukh ***@***.***> wrote:

> Now that you asked me 😅 -- I took a thorough look at the PR and I think
> the existing code can be used. I'll try to use that PR for now. Thanks!
>
> —
> Reply to this email directly, view it on GitHub
> <https://github.com/rubyforgood/human-essentials/issues/4176#issuecomment-2704775240>,
> or unsubscribe
> <https://github.com/notifications/unsubscribe-auth/ALKEMUZHR2MPOV2NDM6QWJD2TCP2JAVCNFSM6AAAAABYPMTYSGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDOMBUG43TKMRUGA>
> .
> You are receiving this because you were assigned.Message ID:
> ***@***.***>
> [image: Sukhpreet-s]*Sukhpreet-s* left a comment
> (rubyforgood/human-essentials#4176)
> <https://github.com/rubyforgood/human-essentials/issues/4176#issuecomment-2704775240>
>
> Now that you asked me 😅 -- I took a thorough look at the PR and I think
> the existing code can be used. I'll try to use that PR for now. Thanks!
>
> —
> Reply to this email directly, view it on GitHub
> <https://github.com/rubyforgood/human-essentials/issues/4176#issuecomment-2704775240>,
> or unsubscribe
> <https://github.com/notifications/unsubscribe-auth/ALKEMUZHR2MPOV2NDM6QWJD2TCP2JAVCNFSM6AAAAABYPMTYSGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDOMBUG43TKMRUGA>
> .
> You are receiving this because you were assigned.Message ID:
> ***@***.***>
>

author_association: CONTRIBUTOR
user: login: Sukhpreet-s
created_at: 2025-03-12T19:59:16Z
body: @cielf I realized that the old open PR (authored by @nathangthomas) is not merging in rubyforgood/human-essentials repo instead it's merging in the fork itself. And because the PR descriptions mentions this issue, hence the PR is getting tracked here even though it's not merging to this repo.

So I ended up creating a fresh PR.

@nathangthomas Can you please close [your PR](https://github.com/unabridged/human-essentials/pull/1)? Also I wonder if you accidentally created that PR with base branch as your own fork? 🤔 
author_association: CONTRIBUTOR
user: login: nathangthomas
created_at: 2025-03-17T12:45:55Z
body: @Sukhpreet-s  Thank you. Original PR has been closed. 
author_association: CONTRIBUTOR

Diff:
diff --git a/app/controllers/organizations_controller.rb b/app/controllers/organizations_controller.rb
index d45392af44..536f2d81e9 100644
--- a/app/controllers/organizations_controller.rb
+++ b/app/controllers/organizations_controller.rb
@@ -94,7 +94,7 @@ def organization_params
     params.require(:organization).permit(
       :name, :short_name, :street, :city, :state,
       :zipcode, :email, :url, :logo, :intake_location,
-      :default_storage_location, :default_email_text,
+      :default_storage_location, :default_email_text, :reminder_email_text,
       :invitation_text, :reminder_day, :deadline_day,
       :repackage_essentials, :distribute_monthly,
       :ndbn_member_id, :enable_child_based_requests,
diff --git a/app/mailers/reminder_deadline_mailer.rb b/app/mailers/reminder_deadline_mailer.rb
index 9407f41d27..a7268bbb94 100644
--- a/app/mailers/reminder_deadline_mailer.rb
+++ b/app/mailers/reminder_deadline_mailer.rb
@@ -4,6 +4,10 @@ def notify_deadline(partner)
     @partner = partner
     @organization = partner.organization
     @deadline = deadline_date(partner)
+    reminder_email_text = @organization.reminder_email_text
+    @reminder_email_text_interpolated = TextInterpolatorService.new(reminder_email_text.body.to_s, {
+      partner_name: @partner.name
+    }).call
 
     mail(to: @partner.email, subject: "#{@organization.name} Deadline Reminder")
   end
diff --git a/app/models/organization.rb b/app/models/organization.rb
index 55408e9d3c..5c70feaf7c 100644
--- a/app/models/organization.rb
+++ b/app/models/organization.rb
@@ -115,6 +115,7 @@ def flipper_id
   ].freeze
 
   has_rich_text :default_email_text
+  has_rich_text :reminder_email_text
 
   has_one_attached :logo
 
diff --git a/app/views/organizations/_details.html.erb b/app/views/organizations/_details.html.erb
index 5cfc6a2125..911ea552a8 100644
--- a/app/views/organizations/_details.html.erb
+++ b/app/views/organizations/_details.html.erb
@@ -76,6 +76,12 @@
                   <%= @organization.deadline_day.blank? ? 'Not defined' : "The #{@organization.deadline_day.ordinalize} of each month" %>
                 </p>
               </div>
+              <div class="mb-4">
+                <h3 class='font-bold'>Additional text for reminder email</h3>
+                <p>
+                  <%= @organization.reminder_email_text.presence || 'Not defined' %>
+                </p>
+              </div>
               <div class="mb-4">
                 <h3 class='font-bold'>Default Intake Location</h3>
                 <p>
diff --git a/app/views/organizations/edit.html.erb b/app/views/organizations/edit.html.erb
index 3f65bcbe39..b3f19ef5dc 100644
--- a/app/views/organizations/edit.html.erb
+++ b/app/views/organizations/edit.html.erb
@@ -87,6 +87,11 @@
 
                 <%= render 'shared/deadline_day_fields', f: f %>
 
+                <% default_reminder_email_text_hint = "You can use the variable <code>%{partner_name}</code> to include the partner's name in the message." %>
+                <%= f.input :reminder_email_text, label: "Additional text for reminder email", hint: default_reminder_email_text_hint.html_safe do %>
+                  <%= f.rich_text_area :reminder_email_text, placeholder: 'Enter reminder email content...' %>
+                <% end %>
+
                 <%= f.input :intake_location, :collection => current_organization.storage_locations.active.alphabetized, :label_method => :name, :value_method => :id, :label => "Default Intake Location", :include_blank => true, wrapper: :input_group %>
 
                 <%= f.label :partner_form_fields, 'Partner Profile Sections' %>
diff --git a/app/views/reminder_deadline_mailer/notify_deadline.html.erb b/app/views/reminder_deadline_mailer/notify_deadline.html.erb
index b9bce0e6c6..4db99382d5 100644
--- a/app/views/reminder_deadline_mailer/notify_deadline.html.erb
+++ b/app/views/reminder_deadline_mailer/notify_deadline.html.erb
@@ -6,3 +6,4 @@ if you would like to receive a distribution next month.</p>
 before this date and submit your request if you are intending to submit an essentials request.</p>
     <p>Please contact <%= @organization.name %> at <%= @organization.email %>
 if you have any questions about this!</p>
+    <p><%= @reminder_email_text_interpolated.html_safe %></p>
diff --git a/app/views/reminder_deadline_mailer/notify_deadline.text.erb b/app/views/reminder_deadline_mailer/notify_deadline.text.erb
deleted file mode 100644
index feb1e10a5f..0000000000
--- a/app/views/reminder_deadline_mailer/notify_deadline.text.erb
+++ /dev/null
@@ -1,9 +0,0 @@
-Hello <%= @partner.name %>,
-
-This is a friendly reminder that <%= @organization.name %> requires your human essentials requests to be submitted by <%= @deadline.strftime('%a, %d %b %Y') %>
-if you would like to receive a distribution next month.
-
-Please log into Human Essentials at https://humanessentials.app before this date and submit your request if you are intending to submit an essentials request.
-
-Please contact <%= @organization.name %> at <%= @organization.email %>
-if you have any questions about this!
diff --git a/docs/user_guide/bank/getting_started_customization.md b/docs/user_guide/bank/getting_started_customization.md
index e2bcbe2fbd..a84dd60c84 100644
--- a/docs/user_guide/bank/getting_started_customization.md
+++ b/docs/user_guide/bank/getting_started_customization.md
@@ -54,18 +54,23 @@ There is also a check-box on the Partner that must be checked for the Partner to
 
 The text of this email will be:  
 
+<blockquote>
 Hello [Partner's name],
-
+<br/>
+<br/>
 This is a friendly reminder that [Your bank's name] requires your human essentials requests to be submitted by [the deadline date, including month and year]
 if you would like to receive a Distribution next month.
-
+<br/>
+<br/>
 Please log into Human Essentials at https://humanessentials.app before this date and submit your request if you are intending to submit an essentials request.
-
-Please contact [Your bank's name] at <%= @organization.email %>
+<br/>
+<br/>
+Please contact [Your bank's name] at [Your bank's email]
 if you have any questions about this!
-
-
-
+<br/>
+<br/>
+[Additional text for reminder email (see below)]
+</blockquote>
 
 
 
@@ -76,6 +81,9 @@ If you do not pick a day, no reminder emails are sent.
 #### Deadline day (Final day of the month to submit Requests)
 This day will be included in the reminder email message,
 
+#### Additional text for reminder email
+If present, this text will be included in the reminder email after the default text. In the above email template, this additional message will replace `[Additional text for reminder email (see below)]`.
+
 ----------
 
 #### Default Intake Location
diff --git a/spec/mailers/reminder_deadline_mailer_spec.rb b/spec/mailers/reminder_deadline_mailer_spec.rb
index fde33fa564..51c71c55c5 100644
--- a/spec/mailers/reminder_deadline_mailer_spec.rb
+++ b/spec/mailers/reminder_deadline_mailer_spec.rb
@@ -6,6 +6,7 @@
     let(:partner) { create(:partner, organization: organization) }
 
     before(:each) do
+      organization.reminder_email_text = "Custom reminder message"
       organization.update!(reminder_day: today.day, deadline_day: 1)
     end
 
@@ -25,13 +26,14 @@
 
     it 'renders the body' do
       travel_to today do
-        expect(html_body(subject))
-          .to include("This is a friendly reminder that #{organization.name} requires your human essentials requests to " \
-                       "be submitted by Tue, 01 Feb 2022")
-        expect(text_body(subject))
+        expect(subject.body.encoded)
           .to include("This is a friendly reminder that #{organization.name} requires your human essentials requests to " \
                        "be submitted by Tue, 01 Feb 2022")
       end
     end
+
+    it 'renders the body with the reminder email text' do
+      expect(subject.body.encoded).to include("Custom reminder message")
+    end
   end
 end


Reviews:
user: login: cielf
body: Hey @Sukpreet-s   

Thank you for picking this up! 

It works well.  I'd like to make  some adjustments so that it's easier for the users, though.

1/   Please move the field in Organizations  to just below the reminder deadline field.

2/  Let's also change the label on it to "Additional text for reminder email."  This will make it clearer that it isn't a total replacement of the reminder email text.

3/  Let's put the custom content in the email just above the 'Please contact...'  

This issue was created  before we wrote the user guide -- we're going to need to make some updates there as well -- are you comfortable with drafting those changes?  




state: CHANGES_REQUESTED
author_association: COLLABORATOR
submitted_at: 2025-03-13T16:49:51Z
user: login: cielf
body: The user guide is very new and rough -- unfortunately you ran into an uncaught issue with it -- the bits that look like code in that text should be a bit more user-friendly.   

Other than that I'm quite happy with this functionally -- I'm passing it on to our senior tech folk for input.    

Thanks again!
state: DISMISSED
author_association: COLLABORATOR
submitted_at: 2025-03-15T22:38:20Z
user: login: cielf
body: LGTM
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-16T06:48:16Z
user: login: dorner
body: Good on my end as well.
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-03-27T01:05:51Z

Review comments:
diff_hunk: @@ -54,18 +54,23 @@ There is also a check-box on the Partner that must be checked for the Partner to
 
 The text of this email will be:  
 
+<blockquote>
 Hello [Partner's name],
-
+<br/>
+<br/>
 This is a friendly reminder that [Your bank's name] requires your human essentials requests to be submitted by [the deadline date, including month and year]
 if you would like to receive a Distribution next month.
-
+<br/>
+<br/>
 Please log into Human Essentials at https://humanessentials.app before this date and submit your request if you are intending to submit an essentials request.
-
+<br/>
+<br/>
 Please contact [Your bank's name] at <%= @organization.email %>
path: docs/user_guide/bank/getting_started_customization.md
user: login: cielf
body: Ok -- I didn't realize we still had something so ... codey... in this.

Please change  <%= @organization.email %>  to [ Your bank's email]
created_at: 2025-03-15T22:28:58Z
author_association: COLLABORATOR
diff_hunk: @@ -54,18 +54,23 @@ There is also a check-box on the Partner that must be checked for the Partner to
 
 The text of this email will be:  
 
+<blockquote>
 Hello [Partner's name],
-
+<br/>
+<br/>
 This is a friendly reminder that [Your bank's name] requires your human essentials requests to be submitted by [the deadline date, including month and year]
 if you would like to receive a Distribution next month.
-
+<br/>
+<br/>
 Please log into Human Essentials at https://humanessentials.app before this date and submit your request if you are intending to submit an essentials request.
-
+<br/>
+<br/>
 Please contact [Your bank's name] at <%= @organization.email %>
 if you have any questions about this!
-
-
-
+<br/>
+<br/>
+<%= @organization.reminder_email_text %>
path: docs/user_guide/bank/getting_started_customization.md
user: login: cielf
body: and then change this to [Additional text for reminder email (see below)]
created_at: 2025-03-15T22:29:03Z
author_association: COLLABORATOR
diff_hunk: @@ -76,6 +81,9 @@ If you do not pick a day, no reminder emails are sent.
 #### Deadline day (Final day of the month to submit Requests)
 This day will be included in the reminder email message,
 
+#### Additional text for reminder email
+If present, this text will be included in the reminder email placed at the end of the email. In the above email template, this additional message is placed in the position of `<%= @organization.reminder_email_text %>`.
+
path: docs/user_guide/bank/getting_started_customization.md
user: login: cielf
body: If present, this text will be included in the reminder email after the default text. In the above email template, this additional message will replace [Additional text for reminder email (see below)].
created_at: 2025-03-15T22:30:53Z
author_association: COLLABORATOR

PR comments:
user: login: Sukhpreet-s
created_at: 2025-03-13T19:05:39Z
body: Thank you for the review! ✨ I'll make the requested changes.



> This issue was created before we wrote the user guide -- we're going to need to make some updates there as well -- are you comfortable with drafting those changes?

Sure thing 💯   I looked around the docs and it seems like the changes need to go [here](https://github.com/rubyforgood/human-essentials/blob/main/docs/user_guide/bank/getting_started_customization.md#reminder-emails-optional) 💭 Is that right or am I missing some other spot in the docs?

author_association: CONTRIBUTOR
user: login: cielf
created_at: 2025-03-13T20:49:39Z
body: Pretty sure that's the only spot.   Thanks!
author_association: COLLABORATOR
user: login: Sukhpreet-s
created_at: 2025-03-14T19:45:45Z
body: @cielf The changes are ready for review. The screenshots are updated in the description above for reference.

Also, I noticed the organization edit and show pages are also shown for superuser (superadmin@example.com). 

Based on the current setup, the superusers can see `reminder_email_text` but cannot edit it -- Is this okay? or do we want them to be able to edit it as well? 🤔 




author_association: CONTRIBUTOR
user: login: cielf
created_at: 2025-03-14T22:34:56Z
body: As it happens, we've got a draft issue waiting regarding  removing the superuser's ability to change organization settings that the org can change themselves,  so I think it's ok.  
author_association: COLLABORATOR
user: login: Sukhpreet-s
created_at: 2025-03-23T20:54:57Z
body: As discussed in https://github.com/rubyforgood/human-essentials/issues/5098, the plain text version for `deadline_reminder` email is removed (in https://github.com/rubyforgood/human-essentials/pull/5093/commits/05b69b9434b8ad6ce611d4383bfcb9f0dff21a6b) because this email also includes rich text content which is not rendered properly in the plain text emails.
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-03-30T14:12:41Z
body: @Sukhpreet-s: Your PR `4176 customizing reminder message to partner` is part of today's Human Essentials production release: [2025.03.30](https://github.com/rubyforgood/human-essentials/releases/tag/2025.03.30). 
Thank you very much for your contribution!
author_association: CONTRIBUTOR