diff --git a/app/controllers/requests_controller.rb b/app/controllers/requests_controller.rb index ce5677da0c..bf89ccd067 100644 --- a/app/controllers/requests_controller.rb +++ b/app/controllers/requests_controller.rb @@ -3,39 +3,16 @@ class RequestsController < ApplicationController def index setup_date_range_picker - @requests = current_organization - .ordered_requests - .undiscarded - .during(helpers.selected_range) - .class_filter(filter_params) - @unfulfilled_requests_count = current_organization.requests.where(status: [:pending, :started]).during(helpers.selected_range).class_filter(filter_params).count - @paginated_requests = @requests.includes(:partner).page(params[:page]) - @calculate_product_totals = RequestsTotalItemsService.new(requests: @requests).calculate - @items = current_organization.items.alphabetized.select(:id, :name) - @partners = current_organization.partners.alphabetized.select(:id, :name, :status) - @statuses = Request.statuses.transform_keys(&:humanize) - @partner_users = User.where(id: @paginated_requests.map(&:partner_user_id)).select(:id, :name, :email) - @request_types = Request.request_types.transform_keys(&:humanize) - @selected_request_type = filter_params[:by_request_type] - @selected_request_item = filter_params[:by_request_item_id] - @selected_partner = filter_params[:by_partner] - @selected_status = filter_params[:by_status] + @requests_info = View::Requests.from_params(params: params, organization: current_organization, helpers: helpers) respond_to do |format| format.html - format.csv { send_data Exports::ExportRequestService.new(@requests).generate_csv, filename: "Requests-#{Time.zone.today}.csv" } + format.csv { send_data Exports::ExportRequestService.new(@requests_info.requests).generate_csv, filename: "Requests-#{Time.zone.today}.csv" } end end def show - @request = current_organization.requests.find(params[:id]) - @item_requests = @request.item_requests.includes(:item) - - @inventory = View::Inventory.new(@request.organization_id) - @default_storage_location = @request.partner.default_storage_location_id || @request.organization.default_storage_location - @location = StorageLocation.find_by(id: @default_storage_location) - - @custom_units = Flipper.enabled?(:enable_packs) && @request.item_requests.any? { |item| item.request_unit } + @request_info = View::RequestInfo.from_params(params:, organization: current_organization) end # Clicking the "New Distribution" button will set the the request to started diff --git a/app/models/view/donations.rb b/app/models/view/donations.rb index 9518e98047..24e52d16f1 100644 --- a/app/models/view/donations.rb +++ b/app/models/view/donations.rb @@ -31,7 +31,6 @@ def from_params(params:, organization:, helpers:) .includes(:storage_location, :donation_site, :product_drive, - :product_drive_participant, :manufacturer, line_items: [:item]) .order(created_at: :desc) diff --git a/app/models/view/request_info.rb b/app/models/view/request_info.rb new file mode 100644 index 0000000000..9e325e232a --- /dev/null +++ b/app/models/view/request_info.rb @@ -0,0 +1,33 @@ +module View + RequestInfo = Data.define( + :request + ) do + class << self + def from_params(params:, organization:) + request = organization.requests.find(params[:id]) + + new(request:) + end + end + + def item_requests + request.item_requests.includes(:item) + end + + def inventory + View::Inventory.new(request.organization_id) + end + + def default_storage_location + request.partner.default_storage_location_id || request.organization.default_storage_location + end + + def location + StorageLocation.find_by(id: default_storage_location) + end + + def custom_units + Flipper.enabled?(:enable_packs) && request.item_requests.any? { |item| item.request_unit } + end + end +end diff --git a/app/models/view/requests.rb b/app/models/view/requests.rb new file mode 100644 index 0000000000..0a9697aa05 --- /dev/null +++ b/app/models/view/requests.rb @@ -0,0 +1,84 @@ +module View + Requests = Data.define( + :requests, + :filters, + :paginated_requests, + :organization, + :helpers + ) do + include DateRangeHelper + + class << self + def filter_params(params = {}) + if params.key?(:filters) + params.require(:filters).permit(:by_request_item_id, :by_partner, :by_status, :by_request_type) + else + {} + end + end + + def from_params(params:, organization:, helpers:) + filters = filter_params(params) + + requests = organization + .ordered_requests + .undiscarded + .during(helpers.selected_range) + .class_filter(filters) + + paginated_requests = requests.includes(:partner).page(params[:page]) + + new(requests:, filters:, paginated_requests:, organization:, helpers:) + end + end + + def unfulfilled_requests_count + organization + .requests + .where(status: [:pending, :started]) + .during(helpers.selected_range) + .class_filter(filters) + .count + end + + def calculate_product_totals + RequestsTotalItemsService.new(requests: requests).calculate + end + + def items + organization.items.alphabetized.select(:id, :name) + end + + def partners + organization.partners.alphabetized.select(:id, :name, :status) + end + + def statuses + Request.statuses.transform_keys(&:humanize) + end + + def partner_users + User.where(id: paginated_requests.map(&:partner_user_id)).select(:id, :name, :email) + end + + def request_types + Request.request_types.transform_keys(&:humanize) + end + + def selected_request_type + filters[:by_request_type] + end + + def selected_request_item + filters[:by_request_item_id] + end + + def selected_partner + filters[:by_partner] + end + + def selected_status + filters[:by_status] + end + end +end diff --git a/app/views/requests/_calculate_product_totals.html.erb b/app/views/requests/_calculate_product_totals.html.erb index 5410923fb9..add383533f 100644 --- a/app/views/requests/_calculate_product_totals.html.erb +++ b/app/views/requests/_calculate_product_totals.html.erb @@ -16,7 +16,7 @@ - <% @calculate_product_totals.sort_by { |name, quantity| name.downcase }.each do |name, quantity| %> + <% @requests_info.calculate_product_totals.sort_by { |name, quantity| name.downcase }.each do |name, quantity| %> <%= name %> <%= quantity %> diff --git a/app/views/requests/_new.html.erb b/app/views/requests/_new.html.erb index 9463b0b9ff..a4a1c075e9 100644 --- a/app/views/requests/_new.html.erb +++ b/app/views/requests/_new.html.erb @@ -10,7 +10,7 @@ diff --git a/app/views/requests/show.html.erb b/app/views/requests/show.html.erb index 19a44d5cd5..b3bd1f21d2 100644 --- a/app/views/requests/show.html.erb +++ b/app/views/requests/show.html.erb @@ -2,10 +2,10 @@
- <% content_for :title, "Requests - #{@request.id} - #{current_organization.name}" %> + <% content_for :title, "Requests - #{@request_info.request.id} - #{current_organization.name}" %>

Request - from <%= @request.partner.name %> + from <%= @request_info.request.partner.name %>

@@ -29,7 +29,7 @@
-

This request was sent on <%= @request.created_at.to_fs(:distribution_date) %>

+

This request was sent on <%= @request_info.request.created_at.to_fs(:distribution_date) %>

@@ -44,11 +44,11 @@ - - - - - + + + + +
<%= @request.partner.name %><%= @request.partner_user&.formatted_email %><%= @request.request_type&.humanize %><%= render partial: "status", locals: {status: @request.status} %><%= @request.comments || 'None' %><%= @request_info.request.partner.name %><%= @request_info.request.partner_user&.formatted_email %><%= @request_info.request.request_type&.humanize %><%= render partial: "status", locals: {status: @request_info.request.status} %><%= @request_info.request.comments || 'None' %>
@@ -67,36 +67,36 @@ Item Quantity - <% if @custom_units %> + <% if @request_info.custom_units %> Units (if applicable) <% end %> - <% if @default_storage_location %> + <% if @request_info.default_storage_location %> Default storage location inventory <% end %> Total Inventory - <% @item_requests.each do |item_request| %> + <% @request_info.item_requests.each do |item_request| %> <%= item_request.item_name %> <%= item_request.quantity %> - <% if @custom_units %> + <% if @request_info.custom_units %> <%= item_request.request_unit&.pluralize(item_request.quantity.to_i) %> <% end %> - <% if @default_storage_location %> - <% on_hand_for_location = @inventory.quantity_for(storage_location: @location&.id, item_id: item_request.item_id) %> + <% if @request_info.default_storage_location %> + <% on_hand_for_location = @request_info.inventory.quantity_for(storage_location: @request_info.location&.id, item_id: item_request.item_id) %> <%= on_hand_for_location&.positive? ? on_hand_for_location : 'N/A' %> <% end %> - <% on_hand = @inventory.quantity_for(item_id: item_request.item_id) %> + <% on_hand = @request_info.inventory.quantity_for(item_id: item_request.item_id) %> <%= on_hand || 0 %> <% end %> Total (Quota) - <%= @request.total_items %> - <%= quota_display(@request.partner) %> + <%= @request_info.request.total_items %> + <%= quota_display(@request_info.request.partner) %> @@ -104,11 +104,11 @@
diff --git a/spec/models/view/request_info_spec.rb b/spec/models/view/request_info_spec.rb new file mode 100644 index 0000000000..fd8a64706b --- /dev/null +++ b/spec/models/view/request_info_spec.rb @@ -0,0 +1,82 @@ +RSpec.describe View::RequestInfo do + describe "#default_storage_location" do + context "when the request partner has a default_storage_location_id" do + it "returns the request partner's default_storage_location_id" do + storage_location = build(:storage_location) + organization = build(:organization) + request = create( + :request, + partner: build(:partner, default_storage_location_id: storage_location.id), + organization: + ) + + request = View::RequestInfo.from_params(params: {id: request.id}, organization:) + + expect(request.default_storage_location).to eq(storage_location.id) + end + end + + context "when the request organization has a default_storage_location_id" do + it "returns the request organization's default_storage_location_id" do + organization = build(:organization) + storage_location = build(:storage_location, organization:) + organization.update!(default_storage_location: storage_location.id) + request = create( + :request, + organization: + ) + + request = View::RequestInfo.from_params(params: {id: request.id}, organization:) + + expect(request.default_storage_location).to eq(storage_location.id) + end + end + end + + describe "#custom_units" do + context "when there are request units for an item request" do + context "when enable_packs is disabled" do + it "returns false" do + organization = build(:organization) + item = build(:item, name: "First item") + create(:item_unit, item: item, name: "flat") + request = create( + :request, + :with_item_requests, + organization:, + request_items: [ + {item_id: item.id, quantity: "559", request_unit: "flat"} + ] + ) + + request = View::RequestInfo.from_params(params: {id: request.id}, organization:) + + expect(request.custom_units).to be_falsey + end + end + + context "when enable_packs is enabled" do + it "returns true" do + Flipper.enable(:enable_packs) + + organization = build(:organization) + item = build(:item, name: "First item") + create(:item_unit, item: item, name: "flat") + request = create( + :request, + :with_item_requests, + organization:, + request_items: [ + {item_id: item.id, quantity: "559", request_unit: "flat"} + ] + ) + request = View::RequestInfo.from_params(params: {id: request.id}, organization:) + + expect(request.custom_units).to be_truthy + + Flipper.disable(:enable_packs) + end + end + end + end +end diff --git a/spec/models/view/requests_spec.rb b/spec/models/view/requests_spec.rb new file mode 100644 index 0000000000..855af78a0b --- /dev/null +++ b/spec/models/view/requests_spec.rb @@ -0,0 +1,59 @@ +RSpec.describe View::Requests do + describe "#unfulfilled_requests_count" do + it "returns the unfulfilled requests count" do + organization = build(:organization) + create(:request, :pending, organization:) + create(:request, :started, organization:) + create(:request, :fulfilled, organization:) + + requests = View::Requests.from_params(params: {}, organization:, helpers:) + + expect(requests.unfulfilled_requests_count).to eq(2) + end + end + + describe "#calculate_product_totals" do + it "returns the calculated product total items" do + organization = build(:organization) + build(:request, :pending, organization:) + total_items_service_double = instance_double(RequestsTotalItemsService, calculate: {"Diaper" => 10}) + allow(RequestsTotalItemsService).to receive(:new).with(requests: organization.requests).and_return(total_items_service_double) + + requests = View::Requests.from_params(params: {}, organization:, helpers:) + + expect(requests.calculate_product_totals).to eq({"Diaper" => 10}) + end + end + + describe "selected filter params" do + it "returns the given filter params" do + organization = build(:organization) + build(:request, :pending, organization:) + params = ActionController::Parameters.new( + { + filters: { + by_request_type: "quantity", + by_request_item_id: "1", + by_partner: "A Local Partner", + by_status: "pending" + } + } + ).permit! + + requests = View::Requests.from_params(params:, organization:, helpers:) + + expect(requests.selected_request_type).to eq("quantity") + expect(requests.selected_request_item).to eq("1") + expect(requests.selected_partner).to eq("A Local Partner") + expect(requests.selected_status).to eq("pending") + end + end + + def helpers + Module.new do + def self.selected_range + (1.month.ago..2.days.from_now) + end + end + end +end