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 7 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
14 changes: 13 additions & 1 deletion app/controllers/partners/requests_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ def new
@partner_request.item_requests.build

@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 = current_partner.organization.items.to_h do |i|
[i.id, i.request_units.to_h { |u| [u.name, u.name.pluralize] }]
end
Copy link
Collaborator

Choose a reason for hiding this comment

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

Since this is identical to the one in create please extract it into a private method.

end
end

def show
Expand All @@ -34,6 +40,12 @@ def create
@errors = create_service.errors

@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 = current_partner.organization.items.to_h do |i|
[i.id, i.request_units.to_h { |u| [u.name, u.name.pluralize] }]
end
end

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

Expand All @@ -44,7 +56,7 @@ def create
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
end
end
51 changes: 51 additions & 0 deletions app/javascript/controllers/item_units_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
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, selected) {
let option = document.createElement("option");
option.value = val;
option.text = text;
if (selected) {
option.selected = true;
}
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('', 'Units')
for (const [index, [name, displayName]] of Object.entries(Object.entries(units))) {
this.addOption(name, displayName, index === "0")
}
}
}

}
1 change: 1 addition & 0 deletions app/services/partners/request_create_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ def populate_item_request(partner_request)
else
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
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 @@ -39,15 +39,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
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 @@ -100,6 +100,7 @@
item_requests_attributes: {
"0" => {
item_id: item1.id,
request_unit: 'pack',
quantity: Faker::Number.within(range: 4..13)
}
}
Expand All @@ -109,6 +110,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
66 changes: 66 additions & 0 deletions spec/system/partners/requests_system_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
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 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: "packs", options: ["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"

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