Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#4398: Support units in requests #4510

Merged
merged 12 commits into from
Aug 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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'},
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So here we already only show the @requestable_items in the item select drop-down, so that already narrows down what we might show in the units drop down. So the generated @item_units having all possible items it works fine, but could be narrowed down to building off of @requestable_items

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