Skip to content
Open
Show file tree
Hide file tree
Changes from 4 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
11 changes: 8 additions & 3 deletions app/controllers/items_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -177,12 +177,17 @@ def item_params
:distribution_quantity,
:visible_to_partners,
:active,
:additional_info
:additional_info,
:unit_request_limit
)
end

def request_unit_ids
params.require(:item).permit(request_unit_ids: []).fetch(:request_unit_ids, [])
params.require(:item).permit(unit_ids: []).fetch(:unit_ids, []).compact_blank
end

def request_unit_limits
(params.require(:item).permit(unit_limits: {})[:unit_limits] || {}).to_h
end

# We need to update both the item and the request_units together and fail together
Expand All @@ -198,7 +203,7 @@ def update_item_and_request_units
begin
Item.transaction do
@item.save!
@item.sync_request_units!(request_unit_ids)
@item.sync_request_units!(request_unit_ids, request_unit_limits)
end
rescue
return false
Expand Down
3 changes: 2 additions & 1 deletion app/controllers/partners/requests_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ def create
else
@partner_request = create_service.partner_request
@errors = create_service.errors
flash[:error] = @errors.full_messages.join("; ").capitalize + "." if @errors.present?

fetch_items

Expand Down Expand Up @@ -84,7 +85,7 @@ def fetch_items
# hash of (item ID => hash of (request unit name => request unit plural name))
item_ids = @requestable_items.to_h.values
if item_ids.present?
@item_units = Item.where(id: item_ids).to_h do |i|
@item_units = Item.where(id: item_ids).includes(:request_units).to_h do |i|
[i.id, i.request_units.to_h { |u| [u.name, u.name.pluralize] }]
end
end
Expand Down
9 changes: 6 additions & 3 deletions app/models/item.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
# package_size :integer
# partner_key :string
# reporting_category :string
# unit_request_limit :integer
# value_in_cents :integer default(0)
# visible_to_partners :boolean default(TRUE), not null
# created_at :datetime not null
Expand Down Expand Up @@ -186,10 +187,12 @@ def default_quantity
distribution_quantity || 50
end

def sync_request_units!(unit_ids)
def sync_request_units!(unit_ids, limits = {})
request_units.clear
organization.request_units.where(id: unit_ids).pluck(:name).each do |name|
request_units.create!(name:)
organization.request_units.where(id: unit_ids).find_each do |unit|
item_unit = request_units.create!(name: unit.name)
limit = limits[unit.id.to_s]
item_unit.update!(request_limit: limit.to_i) if limit.present?
end
end

Expand Down
11 changes: 6 additions & 5 deletions app/models/item_unit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
#
# Table name: item_units
#
# id :bigint not null, primary key
# name :string not null
# created_at :datetime not null
# updated_at :datetime not null
# item_id :bigint
# id :bigint not null, primary key
# name :string not null
# request_limit :integer
# created_at :datetime not null
# updated_at :datetime not null
# item_id :bigint
#
class ItemUnit < ApplicationRecord
belongs_to :item
Expand Down
17 changes: 17 additions & 0 deletions app/services/partners/request_create_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,23 @@ def populate_item_request(partner_request)
}.compact
end

# Validate if request quantity exceeds the request limit for the item and unit type
partner_request.request_items.each do |ir|
item = Item.find(ir["item_id"])
unit_type = ir["request_unit"]
quantity_requested = ir["quantity"].to_i

limit = if unit_type.blank?
item.unit_request_limit
else
item.request_units.where(name: unit_type)&.first&.request_limit
end

if limit.present? && (quantity_requested > limit)
errors.add(:base, "#{item.name}: You requested #{quantity_requested} #{unit_type.pluralize}, but are limited to #{limit} #{unit_type.pluralize}")
end
end

partner_request
end

Expand Down
35 changes: 34 additions & 1 deletion app/views/items/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,43 @@
<%= f.input_field :package_size, class: "form-control", min: 0 %>
<% end %>

<%= f.input :name, label: "Request limit (individual items)", wrapper: :input_group do %>
<%= f.input_field :unit_request_limit, class: "form-control", min: 0 %>
<% end %>

<% if Flipper.enabled?(:enable_packs) %>
<%= f.input :request_units, label: "Additional Custom Request Units" do %>
<%= f.association :request_units, as: :check_boxes, collection: current_organization.request_units, checked: selected_item_request_units(@item), label_method: :name, value_method: :id, class: "form-check-input" %>
<% current_organization.request_units.each do |unit| %>
<% item_unit = @item.request_units.find { |item_unit| item_unit.name == unit.name } %>
<% selected = item_unit.present? %>

<div class="form-check mb-2">
<%= check_box_tag "item[unit_ids][]", unit.id, selected, id: "unit_#{unit.id}", class: "form-check-input" %>
<%= label_tag "unit_#{unit.id}", unit.name, class: "form-check-label me-2" %>

<%= number_field_tag "item[unit_limits][#{unit.id}]",
item_unit&.request_limit,
class: "form-control d-inline-block w-auto",
min: 0,
placeholder: "Limit",
disabled: !selected %>
</div>
<% end %>

<!-- keep the param key present even if nothing checked -->
<%= hidden_field_tag "item[unit_ids][]", "" %>
<% end %>

<script>
// Optional: toggle limit input enabled state with the checkbox
document.addEventListener("change", (e) => {
if (e.target.matches('input[type="checkbox"][id^="unit_"]')) {
const id = e.target.id.replace("unit_", "");
const limit = document.querySelector(`input[name="item[unit_limits][${id}]"]`);
if (limit) limit.disabled = !e.target.checked;
}
});
</script>
<% end %>

<%= f.input :visible, label: "Item is Visible to Partners?", wrapper: :input_group do %>
Expand Down
37 changes: 19 additions & 18 deletions app/views/partners/individuals_requests/new.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -24,29 +24,29 @@
<div class="col-md-12">
<!-- Default box -->
<div class="card"
data-controller="confirmation"
data-confirmation-pre-check-path-value="<%= validate_partners_individuals_requests_path(format: :json) %>">
data-controller="confirmation"
data-confirmation-pre-check-path-value="<%= validate_partners_individuals_requests_path(format: :json) %>">
<div class="card-body">

<% if @errors.present? %>
<%= render partial: 'partners/requests/error' %>
<% end %>

<%= simple_form_for @request, url: partners_individuals_requests_path, html: {role: 'form', class: 'form-horizontal'},
data: {controller: 'form-input', confirmation_target: "form"} do |form| %>
<%= simple_form_for @request, url: partners_individuals_requests_path, html: { role: 'form', class: 'form-horizontal' },
data: { controller: 'form-input', confirmation_target: "form" } do |form| %>

<%= form.input :comments, label: "Comments:", as: :text, class: "form-control", wrapper: :input_group %>

<table class='table'>
<thead>
<tr>
<th>Item Requested</th>
<th>Number of Individuals</th>
</tr>
<tr>
<th>Item Requested</th>
<th>Number of Individuals</th>
</tr>
</thead>

<tbody class='fields'>
<%= render 'partners/individuals_requests/item_request', form: form %>
<%= render 'partners/individuals_requests/item_request', form: form %>
</tbody>
</table>

Expand All @@ -65,15 +65,16 @@
</div>
<% end %>

<%# Confirmation modal: See confirmation_controller.js for how this gets displayed %>
<%# and app/controllers/partners/individuals_requests_controller.rb#validate for how it gets populated. %>
<div id="partnerIndividualRequestConfirmationModal"
class="modal confirm"
aria-labelledby="partnerIndividualRequestConfirmationModal"
aria-hidden="true"
tabindex="-1"
data-bs-backdrop="static"
data-confirmation-target="modal">
<%# Confirmation modal: See confirmation_controller.js for how this gets displayed %>
<%# and app/controllers/partners/individuals_requests_controller.rb#validate for how it gets populated. %>
<div id="partnerIndividualRequestConfirmationModal"
class="modal confirm"
aria-labelledby="partnerIndividualRequestConfirmationModal"
aria-hidden="true"
tabindex="-1"
data-bs-backdrop="static"
data-confirmation-target="modal">
</div>
Copy link
Copy Markdown
Collaborator Author

@embarnard embarnard Sep 13, 2025

Choose a reason for hiding this comment

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

just added a missing div in this file, rest of the changes are just spacing from auto-format

</div>
</div>
</div>
Expand Down
5 changes: 0 additions & 5 deletions app/views/partners/requests/new.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,6 @@
data-controller="confirmation"
data-confirmation-pre-check-path-value="<%= validate_partners_requests_path(format: :json) %>">
<div class="card-body">

<% if @errors.present? %>
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

removed this error message in favor of flash messages instead
Screenshot 2025-09-13 at 10 27 44 AM

<%= render partial: 'partners/requests/error' %>
<% end %>

<%= simple_form_for @partner_request, url: partners_requests_path(@partner_request),
html: {role: 'form', class: 'form-horizontal'}, method: :post, data: { controller: 'form-input', confirmation_target: "form" } do |form| %>
<%= form.input :comments, label: "Comments:", as: :text, class: "form-control", wrapper: :input_group %>
Expand Down
6 changes: 6 additions & 0 deletions db/migrate/20250912155420_add_request_limit_to_item_unit.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class AddRequestLimitToItemUnit < ActiveRecord::Migration[8.0]
def change
add_column :item_units, :request_limit, :integer, default: nil, null: true
add_column :items, :unit_request_limit, :integer, default: nil, null: true
end
end
4 changes: 3 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema[8.0].define(version: 2025_08_11_094943) do
ActiveRecord::Schema[8.0].define(version: 2025_09_12_155420) do
# These are extensions that must be enabled in order to support this database
enable_extension "pg_catalog.plpgsql"

Expand Down Expand Up @@ -387,6 +387,7 @@
t.bigint "item_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "request_limit"
t.index ["item_id"], name: "index_item_units_on_item_id"
end

Expand All @@ -408,6 +409,7 @@
t.integer "item_category_id"
t.text "additional_info"
t.string "reporting_category"
t.integer "unit_request_limit"
t.index ["kit_id"], name: "index_items_on_kit_id"
t.index ["organization_id"], name: "index_items_on_organization_id"
t.index ["partner_key"], name: "index_items_on_partner_key"
Expand Down
11 changes: 6 additions & 5 deletions spec/factories/item_units.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
#
# Table name: item_units
#
# id :bigint not null, primary key
# name :string not null
# created_at :datetime not null
# updated_at :datetime not null
# item_id :bigint
# id :bigint not null, primary key
# name :string not null
# request_limit :integer
# created_at :datetime not null
# updated_at :datetime not null
# item_id :bigint
#
FactoryBot.define do
factory :item_unit do
Expand Down
1 change: 1 addition & 0 deletions spec/factories/items.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
# package_size :integer
# partner_key :string
# reporting_category :string
# unit_request_limit :integer
# value_in_cents :integer default(0)
# visible_to_partners :boolean default(TRUE), not null
# created_at :datetime not null
Expand Down
1 change: 1 addition & 0 deletions spec/models/item_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
# package_size :integer
# partner_key :string
# reporting_category :string
# unit_request_limit :integer
# value_in_cents :integer default(0)
# visible_to_partners :boolean default(TRUE), not null
# created_at :datetime not null
Expand Down
11 changes: 6 additions & 5 deletions spec/models/item_unit_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
#
# Table name: item_units
#
# id :bigint not null, primary key
# name :string not null
# created_at :datetime not null
# updated_at :datetime not null
# item_id :bigint
# id :bigint not null, primary key
# name :string not null
# request_limit :integer
# created_at :datetime not null
# updated_at :datetime not null
# item_id :bigint
#
RSpec.describe ItemUnit, type: :model do
context "Validations >" do
Expand Down
Loading