Skip to content

Commit

Permalink
Merge pull request #4510 from rubyforgood/4398-pack-requests
Browse files Browse the repository at this point in the history
#4398: Support units in requests
  • Loading branch information
awwaiid authored Aug 19, 2024
2 parents c037a8c + 5799256 commit c2782e7
Show file tree
Hide file tree
Showing 10 changed files with 186 additions and 7 deletions.
16 changes: 13 additions & 3 deletions app/controllers/partners/requests_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def new
@partner_request = ::Request.new
@partner_request.item_requests.build

@requestable_items = PartnerFetchRequestableItemsService.new(partner_id: current_partner.id).call
fetch_items
end

def show
Expand All @@ -33,7 +33,7 @@ def create
@partner_request = create_service.partner_request
@errors = create_service.errors

@requestable_items = PartnerFetchRequestableItemsService.new(partner_id: current_partner.id).call
fetch_items

Rails.logger.info("[Request Creation Failure] partner_user_id=#{current_user.id} reason=#{@errors.full_messages}")

Expand Down Expand Up @@ -61,7 +61,17 @@ def validate
private

def partner_request_params
params.require(:request).permit(:comments, item_requests_attributes: [:item_id, :quantity])
params.require(:request).permit(:comments, item_requests_attributes: [:item_id, :quantity, :request_unit])
end

def fetch_items
@requestable_items = PartnerFetchRequestableItemsService.new(partner_id: current_partner.id).call
if Flipper.enabled?(:enable_packs)
# hash of (item ID => hash of (request unit name => request unit plural name))
@item_units = Item.where(id: @requestable_items.to_h.values).to_h do |i|
[i.id, i.request_units.to_h { |u| [u.name, u.name.pluralize] }]
end
end
end
end
end
49 changes: 49 additions & 0 deletions app/javascript/controllers/item_units_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { Controller } from "@hotwired/stimulus";

// Connects to data-controller="form-input"
export default class extends Controller {
static targets = ["itemSelect", "requestSelect"]
static values = {
// hash of (item ID => hash of (request unit name => request unit plural name))
"itemUnits": Object
}

addOption(val, text) {
let option = document.createElement("option");
option.value = val;
option.text = text;
this.requestSelectTarget.appendChild(option);
}

clearOptions() {
while (this.requestSelectTarget.options.length > 0) {
this.requestSelectTarget.remove(this.requestSelectTarget.options[0])
}
}

connect() {
this.itemSelected();
}

itemSelected() {
if (!this.hasRequestSelectTarget) {
return;
}
let option = this.itemSelectTarget.options[this.itemSelectTarget.selectedIndex]
let units = this.itemUnitsValue[option.value]
if (!units || Object.keys(units).length === 0) {
this.requestSelectTarget.style.display = 'none';
this.requestSelectTarget.selectedIndex = -1;
}
else {
this.requestSelectTarget.style.display = 'inline';
this.clearOptions()
this.addOption('-1', 'Please select a unit')
this.addOption('', 'Units')
for (const [index, [name, displayName]] of Object.entries(Object.entries(units))) {
this.addOption(name, displayName)
}
}
}

}
5 changes: 5 additions & 0 deletions app/services/partners/request_create_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,13 @@ def populate_item_request(partner_request)
# object (either this one or the FamilyRequestCreateService).
pre_existing_entry.children = (pre_existing_entry.children + (input_item['children'] || [])).uniq
else
if input_item['request_unit'].to_s == '-1' # nothing selected
errors.add(:base, "Please select a unit for #{Item.find(input_item["item_id"]).name}")
next
end
items[input_item['item_id']] = Partners::ItemRequest.new(
item_id: input_item['item_id'],
request_unit: input_item['request_unit'],
quantity: input_item['quantity'],
children: input_item['children'] || [], # will create ChildItemRequests if there are any
name: fetch_organization_item_name(input_item['item_id']),
Expand Down
3 changes: 3 additions & 0 deletions app/views/partners/requests/_error.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
<h3 class='text-4xl font-extrabold'>Oops! Something went wrong with your Request</h3>
<p class='text-lg font-bold'>
Ensure each line item has a item selected AND a quantity greater than 0.
<% if Flipper.enabled?(:enable_packs) && current_partner.organization.request_units.any? %>
Please ensure a unit is selected for each item that supports it.
<% end %>
</p>
<p class='text-md'>
Still need help? Please contact your essentials bank, <%= current_partner.organization.name %>, if you need further assistance.<br>
Expand Down
16 changes: 14 additions & 2 deletions app/views/partners/requests/_item_request.html.erb
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
<%= form.fields_for :item_requests, defined?(object) ? object : nil do |field| %>
<tr>
<tr data-controller="item-units" data-item-units-item-units-value="<%= item_units.to_json %>">
<td>
<%= field.label :item_id, "Item Requested", {class: 'sr-only'} %>
<%= field.select :item_id, @requestable_items, {include_blank: 'Select an item'}, {class: 'form-control'} %>
<%= field.select :item_id, @requestable_items, {include_blank: 'Select an item'},
data: { :'item-units-target' => 'itemSelect',
action: 'change->item-units#itemSelected'},
class: 'form-control' %>
</td>
<td>
<%= field.label :quantity, "Quantity", {class: 'sr-only'} %>
<%= field.number_field :quantity, label: false, step: 1, min: 1, class: 'form-control' %>
</td>

<% if Flipper.enabled?(:enable_packs) && current_partner.organization.request_units.any? %>
<td>
<%= field.label :request_unit, "Unit", {class: 'sr-only'} %>
<%= field.select :request_unit, [], {include_blank: 'Units'},
{ :'data-item-units-target' => 'requestSelect', class: 'form-control'} %>

</td>
<% end %>
<td>
<%= remove_element_button "Remove", container_selector: "tr" %>
</td>
Expand Down
7 changes: 5 additions & 2 deletions app/views/partners/requests/new.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,18 @@
<tr>
<th>Item Requested</th>
<th>Quantity</th>
<% if Flipper.enabled?(:enable_packs) && current_partner.organization.request_units.any? %>
<th>Units (if applicable)</th>
<% end %>
</tr>
</thead>
<tbody class='fields'>
<%= render 'item_request', form: form %>
<%= render partial: 'item_request', locals: { form: form, item_units: @item_units } %>
</tbody>
</table>
<div>
<%= add_element_button('Add Another Item', container_selector: '.fields') do %>
<%= render 'item_request', form: form, object: @partner_request.item_requests.build %>
<%= render partial: 'item_request', locals: { form: form, item_units: @item_units }, object: @partner_request.item_requests.build %>
<% end %>
</div>

Expand Down
6 changes: 6 additions & 0 deletions app/views/partners/requests/validate.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,19 @@
<tr>
<th>Item Name</th>
<th>Total Items</th>
<% if Flipper.enabled?(:enable_packs) && @partner_request.item_requests.any?( &:request_unit ) %>
<th>Units</th>
<% end %>
</tr>
</thead>
<tbody>
<% @partner_request.item_requests.each do |line_item| %>
<tr>
<td><%= line_item.name %></td>
<td><%= line_item.quantity %></td>
<% if Flipper.enabled?(:enable_packs) && @partner_request.item_requests.any?( &:request_unit ) %>
<td><%= line_item.request_unit %></td>
<% end %>
</tr>
<% end %>
</tbody>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
class BackfillPartnerChildRequestedItems < ActiveRecord::Migration[7.1]
def up
return unless Rails.env.production?

safety_assured do
execute <<-SQL
INSERT INTO children_items (child_id, item_id)
Expand Down
3 changes: 3 additions & 0 deletions spec/requests/partners/requests_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@
item_requests_attributes: {
"0" => {
item_id: item1.id,
request_unit: 'pack',
quantity: Faker::Number.within(range: 4..13)
}
}
Expand All @@ -141,6 +142,8 @@

before do
sign_in(partner_user)
FactoryBot.create(:unit, organization: organization, name: 'pack')
FactoryBot.create(:item_unit, item: item1, name: 'pack')
end

context 'when given valid parameters' do
Expand Down
86 changes: 86 additions & 0 deletions spec/system/partners/requests_system_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
RSpec.describe "Partners profile served area behaviour", type: :system, js: true do
let(:organization) { create(:organization) }
let(:partner) { create(:partner, organization: organization) }
let(:partner_user) { partner.primary_user }

before(:each) do
sign_in(partner_user)
end

describe "GET #index" do
let!(:item1) { FactoryBot.create(:item, organization: organization, name: "Item 1") }
let!(:item2) { FactoryBot.create(:item, organization: organization, name: "Item 2") }
before(:each) do
FactoryBot.create(:item_unit, name: "pack", item: item1)
end

context "with packs off" do
before(:each) do
Flipper.disable(:enable_packs)
end

it "should not show packs on selection" do
visit new_partners_request_path
select "Item 1", from: "request_item_requests_attributes_0_item_id"
expect(page).not_to have_selector("#request_item_requests_attributes_0_request_unit", visible: true)
end
end

context "with packs on" do
before(:each) do
Flipper.enable(:enable_packs)
end

it "should require a unit selection" do
visit new_partners_request_path
expect(Request.count).to eq(0)
expect(page).not_to have_selector("#request_item_requests_attributes_0_request_unit", visible: true)
select "Item 1", from: "request_item_requests_attributes_0_item_id"
expect(page).to have_selector("#request_item_requests_attributes_0_request_unit", visible: true)
expect(page).to have_select("request_item_requests_attributes_0_request_unit",
selected: "Please select a unit",
options: ["Please select a unit", "Units", "packs"])
fill_in "request_item_requests_attributes_0_quantity", with: 50
click_on "Submit Essentials Request"

expect(page).to have_text "Please ensure a unit is selected for each item that supports it."
expect(Request.count).to eq(0)
end

it "should show packs on selection" do
visit new_partners_request_path
expect(Request.count).to eq(0)
expect(page).not_to have_selector("#request_item_requests_attributes_0_request_unit", visible: true)
select "Item 1", from: "request_item_requests_attributes_0_item_id"
expect(page).to have_selector("#request_item_requests_attributes_0_request_unit", visible: true)
expect(page).to have_select("request_item_requests_attributes_0_request_unit",
selected: "Please select a unit",
options: ["Please select a unit", "Units", "packs"])
select "packs", from: "request_item_requests_attributes_0_request_unit"
click_on "Add Another Item"

# get selector to use in subsequent steps
new_item = find_all(:css, "select[data-item-units-target=itemSelect]")[1]
id = new_item[:id].match(/\d+/)[0]

expect(page).not_to have_selector("request_item_requests_attributes_#{id}_request_unit", visible: true)
select "Item 2", from: "request_item_requests_attributes_#{id}_item_id"
expect(page).not_to have_selector("request_item_requests_attributes_#{id}_request_unit", visible: true)
fill_in "request_item_requests_attributes_0_quantity", with: 50
fill_in "request_item_requests_attributes_#{id}_quantity", with: 20
click_on "Submit Essentials Request"
click_on "Yes, it's correct"
expect(page).to have_text "Request has been successfully created"

expect(Request.count).to eq(1)
request = Request.last
expect(request.item_requests[0].quantity).to eq("50")
expect(request.item_requests[0].item_id).to eq(item1.id)
expect(request.item_requests[0].request_unit).to eq("pack")
expect(request.item_requests[1].quantity).to eq("20")
expect(request.item_requests[1].item_id).to eq(item2.id)
expect(request.item_requests[1].request_unit).to eq(nil)
end
end
end
end

0 comments on commit c2782e7

Please sign in to comment.