Skip to content

Commit b818390

Browse files
authored
Bank admins can enter requests on behalf of partners (#4961)
* Requests page: add button for bank admins to create new requests. Fix styling of buttons * Requests page: select partner from list * Bank admins can view new request page * Remove extraneous requests#create action; post to partners/requests#create directly * Bank admins can submit new request * RequestsConfirmationMailer: display name of person who submitted the request * RequestsConfirmationMailer: always send to the user who submitted the request * DistributionMailer uses new Request#requester method * Cancel partner request uses correct link for bank admins * Document new feature for bank admins to submit request on behalf of partner * Bank admin can request requests for active partners only * RequestsConfirmationMailer: rename @requester_name * Partners::RequestsController: set layout for all actions * Fix error page not showing for requests submitted by bank admin * Fix confirmation modal not showing for requests submitted by bank admin
1 parent 7bf1805 commit b818390

23 files changed

+312
-54
lines changed

app/controllers/partners/requests_controller.rb

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
module Partners
22
class RequestsController < BaseController
3+
skip_before_action :require_partner, only: [:new, :create, :validate]
4+
before_action :require_partner_or_org_admin, only: [:new, :create, :validate]
5+
layout :layout
6+
37
protect_from_forgery with: :exception
48

59
def index
@@ -21,15 +25,20 @@ def show
2125
def create
2226
create_service = Partners::RequestCreateService.new(
2327
request_type: "quantity",
24-
partner_user_id: current_user.id,
28+
partner_id: partner.id,
29+
user_id: current_user.id,
2530
comments: partner_request_params[:comments],
2631
item_requests_attributes: partner_request_params[:item_requests_attributes]&.values || []
2732
)
2833

2934
create_service.call
3035
if create_service.errors.none?
3136
flash[:success] = 'Request was successfully created.'
32-
redirect_to partners_request_path(create_service.partner_request.id)
37+
if current_partner
38+
redirect_to partners_request_path(create_service.partner_request.id)
39+
else
40+
redirect_to request_path(create_service.partner_request.id)
41+
end
3342
else
3443
@partner_request = create_service.partner_request
3544
@errors = create_service.errors
@@ -45,15 +54,16 @@ def create
4554
def validate
4655
create_service = Partners::RequestCreateService.new(
4756
request_type: "quantity",
48-
partner_user_id: current_user.id,
57+
partner_id: partner.id,
58+
user_id: current_user.id,
4959
comments: partner_request_params[:comments],
5060
item_requests_attributes: partner_request_params[:item_requests_attributes]&.values || []
5161
).initialize_only
5262

5363
if create_service.errors.none?
5464
@partner_request = create_service.partner_request
5565
@total_items = @partner_request.total_items
56-
@quota_exceeded = current_partner.quota_exceeded?(@total_items)
66+
@quota_exceeded = partner.quota_exceeded?(@total_items)
5767
body = render_to_string(template: 'partners/requests/validate', formats: [:html], layout: false)
5868
render json: {valid: true, body: body}
5969
else
@@ -68,13 +78,42 @@ def partner_request_params
6878
end
6979

7080
def fetch_items
71-
@requestable_items = PartnerFetchRequestableItemsService.new(partner_id: current_partner.id).call
81+
@requestable_items = PartnerFetchRequestableItemsService.new(partner_id: partner.id).call
7282
if Flipper.enabled?(:enable_packs)
7383
# hash of (item ID => hash of (request unit name => request unit plural name))
7484
@item_units = Item.where(id: @requestable_items.to_h.values).to_h do |i|
7585
[i.id, i.request_units.to_h { |u| [u.name, u.name.pluralize] }]
7686
end
7787
end
7888
end
89+
90+
def require_partner_or_org_admin
91+
return if current_partner
92+
93+
partner_id = params.permit(:partner_id)[:partner_id]
94+
return redirect_invalid_user if partner_id.blank?
95+
96+
partner = Partner.find(partner_id)
97+
if current_user.has_role?(Role::ORG_ADMIN, current_organization) && current_organization == partner&.organization
98+
@partner = partner
99+
else
100+
redirect_invalid_user
101+
end
102+
end
103+
104+
def redirect_invalid_user
105+
respond_to do |format|
106+
format.html { redirect_to dashboard_path, flash: {error: "Logged in user is not set up as a 'partner'."} }
107+
format.json { render body: nil, status: :forbidden }
108+
end
109+
end
110+
111+
def partner
112+
@partner ||= current_partner
113+
end
114+
115+
def layout
116+
@layout ||= current_partner ? "partners/application" : "application"
117+
end
79118
end
80119
end

app/controllers/requests_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ def index
1212
@paginated_requests = @requests.includes(:partner).page(params[:page])
1313
@calculate_product_totals = RequestsTotalItemsService.new(requests: @requests).calculate
1414
@items = current_organization.items.alphabetized.select(:id, :name)
15-
@partners = current_organization.partners.alphabetized.select(:id, :name)
15+
@partners = current_organization.partners.alphabetized.select(:id, :name, :status)
1616
@statuses = Request.statuses.transform_keys(&:humanize)
1717
@partner_users = User.where(id: @paginated_requests.map(&:partner_user_id)).select(:id, :name, :email)
1818
@request_types = Request.request_types.transform_keys(&:humanize)

app/mailers/distribution_mailer.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ def partner_mailer(current_organization, distribution, subject, distribution_cha
1111
@partner = distribution.partner
1212
@distribution = distribution
1313
@comment = distribution.comment
14-
requestee_email = distribution.request ? distribution.request.user_email : @partner.email
14+
requester_email = distribution.request ? distribution.request.requester.email : @partner.email
1515

1616
delivery_method = @distribution.delivery? ? 'delivered' : 'picked up'
1717
@default_email_text = current_organization.default_email_text
@@ -35,17 +35,17 @@ def partner_mailer(current_organization, distribution, subject, distribution_cha
3535
cc.compact!
3636
cc.uniq!
3737

38-
mail(to: requestee_email, cc: cc, subject: "#{subject} from #{current_organization.name}")
38+
mail(to: requester_email, cc: cc, subject: "#{subject} from #{current_organization.name}")
3939
end
4040

4141
def reminder_email(distribution_id)
4242
distribution = Distribution.find(distribution_id)
4343
@partner = distribution.partner
4444
@distribution = distribution
45-
requestee_email = distribution.request ? distribution.request.user_email : @partner.email
45+
requester_email = distribution.request ? distribution.request.requester.email : @partner.email
4646

4747
return if @distribution.past? || !@partner.send_reminders || @partner.deactivated?
4848

49-
mail(to: requestee_email, cc: @partner.email, subject: "#{@partner.name} Distribution Reminder")
49+
mail(to: requester_email, cc: @partner.email, subject: "#{@partner.name} Distribution Reminder")
5050
end
5151
end

app/mailers/requests_confirmation_mailer.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,17 @@ def confirmation_email(request)
33
@organization = request.organization
44
@partner = request.partner
55
@request_items = fetch_items(request)
6-
requestee_email = request.user_email
7-
# If the requestee organization has opted in to receiving an email when a
8-
# request is made, CC them
6+
requester = request.requester
7+
@requester_user_name = requester.is_a?(User) ? requester.name : nil # Requester can be the partner, if no user is specified
8+
# If the organization has opted in to receiving an email when a request is made, CC them
99
cc = [@partner.email]
1010
if @organization.receive_email_on_requests
1111
cc.push(@organization.email)
1212
end
1313
cc.flatten!
1414
cc.compact!
1515
cc.uniq!
16-
mail(to: requestee_email, cc: cc, subject: "#{@organization.name} - Requests Confirmation")
16+
mail(to: requester.email, cc: cc, subject: "#{@organization.name} - Requests Confirmation")
1717
end
1818

1919
private

app/models/request.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,9 @@ def total_items
5959
request_items.sum { |item| item["quantity"] }
6060
end
6161

62-
def user_email
63-
partner_user_id ? User.find_by(id: partner_user_id).email : Partner.find_by(id: partner_id).email
62+
def requester
63+
# Despite the field being called "partner_user_id", it can refer to both a partner user or an organization admin
64+
partner_user_id ? partner_user : partner
6465
end
6566

6667
def request_type_label

app/services/partners/family_request_create_service.rb

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ def call
1919
return self unless valid?
2020

2121
request_create_svc = Partners::RequestCreateService.new(
22-
partner_user_id: partner_user_id,
22+
partner_id: partner.id,
23+
user_id: partner_user_id,
2324
comments: comments,
2425
request_type: request_type,
2526
item_requests_attributes: item_requests_attributes
@@ -41,7 +42,8 @@ def call
4142

4243
def initialize_only
4344
Partners::RequestCreateService.new(
44-
partner_user_id: partner_user_id,
45+
partner_id: partner.id,
46+
user_id: partner_user_id,
4547
comments: comments,
4648
request_type: request_type,
4749
item_requests_attributes: item_requests_attributes
@@ -81,5 +83,9 @@ def convert_person_count_to_item_quantity(item_id:, person_count:)
8183
def included_items_by_id
8284
@included_items_by_id ||= Item.where(id: family_requests_attributes.pluck(:item_id)).index_by(&:id)
8385
end
86+
87+
def partner
88+
@partner ||= ::User.find(partner_user_id).partner
89+
end
8490
end
8591
end

app/services/partners/request_create_service.rb

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ class RequestCreateService
44

55
attr_reader :partner_request
66

7-
def initialize(request_type:, partner_user_id:, comments: nil, item_requests_attributes: [], additional_attrs: {})
8-
@partner_user_id = partner_user_id
7+
def initialize(request_type:, partner_id:, user_id:, comments: nil, item_requests_attributes: [], additional_attrs: {})
8+
@partner_id = partner_id
9+
@user_id = user_id
910
@comments = comments
1011
@request_type = request_type
1112
@item_requests_attributes = item_requests_attributes
@@ -34,7 +35,7 @@ def initialize_only
3435
organization_id: organization_id,
3536
comments: comments,
3637
request_type: request_type,
37-
partner_user_id: partner_user_id
38+
partner_user_id: user_id
3839
)
3940
@partner_request = populate_item_request(partner_request)
4041
@partner_request.assign_attributes(additional_attrs)
@@ -50,7 +51,7 @@ def initialize_only
5051

5152
private
5253

53-
attr_reader :partner_user_id, :comments, :item_requests_attributes, :additional_attrs, :request_type
54+
attr_reader :user_id, :partner_id, :comments, :item_requests_attributes, :additional_attrs, :request_type
5455

5556
def populate_item_request(partner_request)
5657
# Exclude any line item that is completely empty
@@ -130,7 +131,7 @@ def organization_id
130131
end
131132

132133
def partner
133-
@partner ||= ::User.find(partner_user_id).partner
134+
@partner ||= Partner.find(partner_id)
134135
end
135136
end
136137
end

app/views/partners/requests/_error.html.erb

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@
88
<h3 class='text-4xl font-extrabold'>Oops! Something went wrong with your Request</h3>
99
<p class='text-lg font-bold'>
1010
Ensure each line item has a item selected AND a quantity greater than 0.
11-
<% if Flipper.enabled?(:enable_packs) && current_partner.organization.request_units.any? %>
11+
<% if Flipper.enabled?(:enable_packs) && (current_partner&.organization || current_organization).request_units.any? %>
1212
Please ensure a single unit is selected for each item that supports it.
1313
<% end %>
1414
</p>
15-
<p class='text-md'>
16-
Still need help? Please contact your essentials bank, <%= current_partner.organization.name %>, if you need further assistance.<br>
17-
Our email on record for them is: <%= mail_to current_partner.organization.email %>
15+
<% if current_partner %>
16+
<p class='text-md'>
17+
Still need help? Please contact your essentials bank, <%= current_partner.organization.name %>, if you need further assistance.<br>
18+
Our email on record for them is: <%= mail_to current_partner.organization.email %>
19+
<% end %>
1820
</p>
1921
</div>
2022
</div>

app/views/partners/requests/new.html.erb

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22
<div class="container-fluid">
33
<div class="row mb-2">
44
<div class="col-sm-6">
5-
<% content_for :title, "New Request - #{current_user.display_name}" %>
5+
<% content_for :title, "New Request - #{current_partner ? current_user.display_name : @partner.name}" %>
66
<h1><i class="fa fa-users"></i>&nbsp;&nbsp;
77
New Request
8-
<small>for <%= current_user.display_name %></small>
8+
<small>for <%= current_partner ? current_user.display_name : @partner.name %></small>
99
</h1>
1010
</div>
1111
<div class="col-sm-6">
1212
<ol class="breadcrumb float-sm-right">
13-
<li class="breadcrumb-item"><a href="<%= partner_user_root_path %>"><i class="fa fa-home fa-lg"></i></a></li>
13+
<li class="breadcrumb-item"><a href="<%= current_partner ? partner_user_root_path : dashboard_path %>"><i class="fa fa-home fa-lg"></i></a></li>
1414
<li class="breadcrumb-item"><a href="#">New Essentials Request</a></li>
1515
</ol>
1616
</div>
@@ -35,6 +35,7 @@
3535
<%= simple_form_for @partner_request, url: partners_requests_path(@partner_request),
3636
html: {role: 'form', class: 'form-horizontal'}, method: :post, data: { controller: 'form-input', confirmation_target: "form" } do |form| %>
3737
<%= form.input :comments, label: "Comments:", as: :text, class: "form-control", wrapper: :input_group %>
38+
<%= hidden_field_tag :partner_id, params[:partner_id] %>
3839

3940
<table class='table'>
4041
<thead>
@@ -61,7 +62,7 @@
6162
</div>
6263
<div class="card-footer">
6364
<!-- TODO(chaserx): we should add some js to prevent submission if the items selected are the blank option or any item has an empty quantity -->
64-
<%= form.submit("Submit Essentials Request", class: "btn btn-success", data: { action: "click->confirmation#openModal" }) %> <%= link_to "Cancel Request", partners_requests_path, class: "btn btn-danger" %>
65+
<%= form.submit("Submit Essentials Request", class: "btn btn-success", data: { action: "click->confirmation#openModal" }) %> <%= link_to "Cancel Request", (current_partner ? partners_requests_path : requests_path), class: "btn btn-danger" %>
6566
</div>
6667
<% end %>
6768

app/views/requests/_new.html.erb

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<div id="newRequest" class="modal fade">
2+
<div class="modal-dialog modal-dialog-scrollable">
3+
<div class="modal-content">
4+
<div class="modal-header">
5+
<h4 class="modal-title">New Quantity Request</h4>
6+
<button type="button" class="close" data-bs-dismiss="modal" aria-label="Close">
7+
<span aria-hidden="true">&times;</span>
8+
</button>
9+
</div>
10+
<div class="modal-body p-4">
11+
<%= form_with(url: new_partners_request_path, method: :get) do |form| %>
12+
<%= form.collection_select(:partner_id, @partners.active, :id, :name, {include_blank: "Select a partner", required: true}, {class: "form-control mb-2"} ) %>
13+
<%= submit_button({text: "Next", icon: nil, name: ""}) %>
14+
<% end %>
15+
</div>
16+
</div>
17+
</div>
18+
</div>

0 commit comments

Comments
 (0)