Skip to content

Commit

Permalink
Merge branch 'rubyforgood:main' into 4035-manufacturer-donations
Browse files Browse the repository at this point in the history
  • Loading branch information
Benjamin-Couey authored Dec 12, 2024
2 parents 6a62c61 + e1e3d11 commit 2217817
Show file tree
Hide file tree
Showing 61 changed files with 915 additions and 414 deletions.
20 changes: 10 additions & 10 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ GEM
bugsnag (6.27.1)
concurrent-ruby (~> 1.0)
builder (3.3.0)
bullet (7.2.0)
bullet (8.0.0)
activesupport (>= 3.0.0)
uniform_notifier (~> 1.11)
capybara (3.40.0)
Expand All @@ -143,7 +143,7 @@ GEM
coderay (1.1.3)
concurrent-ruby (1.3.4)
connection_pool (2.4.1)
coverband (6.1.2)
coverband (6.1.4)
redis (>= 3.0)
crack (1.0.0)
bigdecimal
Expand Down Expand Up @@ -259,11 +259,11 @@ GEM
ffi (1.17.0-x86_64-darwin)
ffi (1.17.0-x86_64-linux-gnu)
filterrific (5.2.5)
flipper (1.3.1)
flipper (1.3.2)
concurrent-ruby (< 2)
flipper-active_record (1.3.0)
activerecord (>= 4.2, < 8)
flipper (~> 1.3.0)
flipper-active_record (1.3.2)
activerecord (>= 4.2, < 9)
flipper (~> 1.3.2)
flipper-ui (1.3.1)
erubi (>= 1.0.0, < 2.0.0)
flipper (~> 1.3.1)
Expand Down Expand Up @@ -373,7 +373,7 @@ GEM
method_source (1.1.0)
mini_magick (4.13.2)
mini_mime (1.1.5)
minitest (5.25.1)
minitest (5.25.2)
monetize (1.12.0)
money (~> 6.12)
money (6.16.0)
Expand All @@ -388,7 +388,7 @@ GEM
multipart-post (2.4.1)
mustermann (3.0.0)
ruby2_keywords (~> 0.0.1)
mutex_m (0.2.0)
mutex_m (0.3.0)
nenv (0.3.0)
net-http-persistent (4.0.2)
connection_pool (~> 2.2)
Expand All @@ -401,7 +401,7 @@ GEM
timeout
net-smtp (0.5.0)
net-protocol
newrelic_rpm (9.13.0)
newrelic_rpm (9.16.0)
nio4r (2.7.3)
nokogiri (1.16.7-arm64-darwin)
racc (~> 1.4)
Expand Down Expand Up @@ -669,7 +669,7 @@ GEM
execjs (>= 0.3.0, < 3)
thor (1.3.2)
tilt (2.2.0)
timeout (0.4.1)
timeout (0.4.2)
ttfunk (1.7.0)
turbo-rails (2.0.10)
actionpack (>= 6.0.0)
Expand Down
6 changes: 5 additions & 1 deletion app/controllers/admin/base_items_controller.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# [Super Admin] Manage the BaseItems -- this is the only place in the app where Base Items can be
# added / modified. Base Items are both the template and common thread for regular Items
#
# See #4656, BaseItems are pending significant changes/possible deletion
class Admin::BaseItemsController < AdminController
def edit
@base_item = BaseItem.find(params[:id])
Expand Down Expand Up @@ -40,7 +42,9 @@ def show

def destroy
@base_item = BaseItem.includes(:items).find(params[:id])
if @base_item.items.any? && @base_item.destroy
if @base_item.id == KitCreateService.find_or_create_kit_base_item!.id
redirect_to admin_base_items_path, alert: "You cannot delete the Kits base item. This is reserved for all Kits."
elsif @base_item.items.empty? && @base_item.destroy
redirect_to admin_base_items_path, notice: "Base Item deleted!"
else
redirect_to admin_base_items_path, alert: "Failed to delete Base Item. Are there still items attached?"
Expand Down
56 changes: 27 additions & 29 deletions app/controllers/distributions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,30 +43,33 @@ def index

@distributions = current_organization
.distributions
.includes(:partner, :storage_location, line_items: [:item])
.order('issued_at DESC')
.apply_filters(filter_params.except(:date_range), helpers.selected_range)
.order(issued_at: :desc)
.includes(:partner, :storage_location)
.class_filter(scope_filters)
@paginated_distributions = @distributions.page(params[:page])
@items = current_organization.items.alphabetized
@item_categories = current_organization.item_categories
@storage_locations = current_organization.storage_locations.active_locations.alphabetized
@partners = @distributions.collect(&:partner).uniq.sort_by(&:name)
@items = current_organization.items.alphabetized.select(:id, :name)
@item_categories = current_organization.item_categories.select(:id, :name)
@storage_locations = current_organization.storage_locations.active_locations.alphabetized.select(:id, :name)
@partners = current_organization.partners.active.alphabetized.select(:id, :name)
@selected_item = filter_params[:by_item_id].presence
@total_value_all_distributions = total_value(@distributions)
@total_items_all_distributions = total_items(@distributions, @selected_item)
@total_value_paginated_distributions = total_value(@paginated_distributions)
@total_items_paginated_distributions = total_items(@paginated_distributions, @selected_item)
@distribution_totals = DistributionTotalsService.new(current_organization.distributions, scope_filters)
@total_value_all_distributions = @distribution_totals.total_value
@total_items_all_distributions = @distribution_totals.total_quantity
paginated_ids = @paginated_distributions.ids
@total_value_paginated_distributions = @distribution_totals.total_value(paginated_ids)
@total_items_paginated_distributions = @distribution_totals.total_quantity(paginated_ids)
@selected_item_category = filter_params[:by_item_category_id]
@selected_partner = filter_params[:by_partner]
@selected_status = filter_params[:by_state]
@selected_location = filter_params[:by_location]
# FIXME: one of these needs to be removed but it's unclear which at this point
@statuses = Distribution.states.transform_keys(&:humanize)
@distributions_with_inactive_items = @distributions.joins(:inactive_items).pluck(:id)

respond_to do |format|
format.html
format.csv do
send_data Exports::ExportDistributionsCSVService.new(distributions: @distributions, organization: current_organization, filters: filter_params).generate_csv, filename: "Distributions-#{Time.zone.today}.csv"
send_data Exports::ExportDistributionsCSVService.new(distributions: @distributions, organization: current_organization, filters: scope_filters).generate_csv, filename: "Distributions-#{Time.zone.today}.csv"
end
end
end
Expand Down Expand Up @@ -285,16 +288,6 @@ def request_id
params.dig(:distribution, :request_attributes, :id)
end

def total_items(distributions, item)
query = LineItem.where(itemizable_type: "Distribution", itemizable_id: distributions.pluck(:id))
query = query.where(item_id: item.to_i) if item
query.sum('quantity')
end

def total_value(distributions)
distributions.sum(&:value_per_itemizable)
end

def daily_items(pick_ups)
item_groups = LineItem.where(itemizable_type: "Distribution", itemizable_id: pick_ups.pluck(:id)).group_by(&:item_id)
item_groups.map do |_id, items|
Expand All @@ -306,21 +299,26 @@ def daily_items(pick_ups)
end
end

def scope_filters
filter_params
.except(:date_range)
.merge(during: helpers.selected_range)
end

helper_method \
def filter_params
return {} unless params.key?(:filters)

params.require(:filters).permit(:by_item_id, :by_item_category_id, :by_partner, :by_state, :by_location, :date_range)
params
.require(:filters)
.permit(:by_item_id, :by_item_category_id, :by_partner, :by_state, :by_location, :date_range)
end

def perform_inventory_check
inventory_check_result = InventoryCheckService.new(@distribution).call

if inventory_check_result.error.present?
flash[:error] = inventory_check_result.error
end
if inventory_check_result.alert.present?
flash[:alert] = inventory_check_result.alert
end
alerts = [inventory_check_result.minimum_alert, inventory_check_result.recommended_alert]
merged_alert = alerts.compact.join("\n")
flash[:alert] = merged_alert if merged_alert.present?
end
end
2 changes: 1 addition & 1 deletion app/controllers/donations_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ def strip_unnecessary_params

# If line_items have submitted with empty rows, clear those out first.
def compact_line_items
return params unless params[:donation].key?(:line_item_attributes)
return params unless params[:donation].key?(:line_items_attributes)

params[:donation][:line_items_attributes].delete_if { |_row, data| data["quantity"].blank? && data["item_id"].blank? }
params
Expand Down
2 changes: 2 additions & 0 deletions app/controllers/partners/requests_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ def show

def create
create_service = Partners::RequestCreateService.new(
request_type: "quantity",
partner_user_id: current_user.id,
comments: partner_request_params[:comments],
item_requests_attributes: partner_request_params[:item_requests_attributes]&.values || []
Expand All @@ -43,6 +44,7 @@ def create

def validate
@partner_request = Partners::RequestCreateService.new(
request_type: "quantity",
partner_user_id: current_user.id,
comments: partner_request_params[:comments],
item_requests_attributes: partner_request_params[:item_requests_attributes]&.values || []
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/purchases_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ def filter_params

# If line_items have submitted with empty rows, clear those out first.
def compact_line_items
return params unless params[:purchase].key?(:line_item_attributes)
return params unless params[:purchase].key?(:line_items_attributes)

params[:purchase][:line_items_attributes].delete_if { |_row, data| data["quantity"].blank? && data["item_id"].blank? }
params
Expand Down
4 changes: 3 additions & 1 deletion app/controllers/requests_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ def index
@partners = current_organization.partners.order(:name)
@statuses = Request.statuses.transform_keys(&:humanize)
@partner_users = User.where(id: @paginated_requests.pluck(:partner_user_id))
@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]
Expand Down Expand Up @@ -71,6 +73,6 @@ def load_items
def filter_params
return {} unless params.key?(:filters)

params.require(:filters).permit(:by_request_item_id, :by_partner, :by_status)
params.require(:filters).permit(:by_request_item_id, :by_partner, :by_status, :by_request_type)
end
end
4 changes: 4 additions & 0 deletions app/helpers/application_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -124,4 +124,8 @@ def storage_location_for_source(source_object)
end
current_organization.default_storage_location
end

def default_location(source_object)
current_organization.default_storage_location || source_object.storage_location_id.presence || current_organization.intake_location
end
end
15 changes: 0 additions & 15 deletions app/helpers/distribution_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,6 @@ def hashed_calendar_path
calendar_distributions_url(hash: crypt.encrypt_and_sign(current_organization.id))
end

def quantity_by_item_id(distribution, item_id)
item_id = Integer(item_id)
quantities = distribution.line_items.quantities_by_name

single_item = quantities.values.find { |li| item_id == li[:item_id] } || {}
single_item[:quantity]
end

def quantity_by_item_category_id(distribution, item_category_id)
item_category_id = Integer(item_category_id)
quantities = distribution.line_items.quantities_by_category

quantities[item_category_id]
end

def distribution_shipping_cost(shipping_cost)
(shipping_cost && shipping_cost != 0) ? number_to_currency(shipping_cost) : ""
end
Expand Down
4 changes: 0 additions & 4 deletions app/helpers/purchases_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,4 @@ module PurchasesHelper
def purchased_from(purchase)
purchase.purchased_from.nil? ? "" : "(#{purchase.purchased_from})"
end

def new_purchase_default_location(purchase)
purchase.storage_location_id.presence || current_organization.intake_location
end
end
1 change: 0 additions & 1 deletion app/models/base_item.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,3 @@ def to_h
{ partner_key: partner_key, name: name }
end
end

6 changes: 4 additions & 2 deletions app/models/concerns/itemizable.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Creates a veritable powerhouse.
# This module provides Duck Typed behaviors for anything that shuttle Items
# This module provides Duck Typed behaviors for anything that shuttles LINE ITEMS (not items)
# throughout the system. e.g. things that `has_many :line_items` -- this provides
# all the logic about how those kinds of things behave.
module Itemizable
Expand All @@ -18,7 +18,7 @@ def has_inactive_item?
inactive_items.any?
end

# @return [Array<Item>]
# @return [Array<Item>] or [Item::ActiveRecord_Relation]
def inactive_items
line_items.map(&:item).select { |i| !i.active? }
end
Expand Down Expand Up @@ -94,6 +94,8 @@ def total_value
end

has_many :items, through: :line_items
has_many :inactive_items, -> { inactive }, through: :line_items, source: :item

accepts_nested_attributes_for :line_items,
allow_destroy: true,
reject_if: proc { |l| l[:item_id].blank? || l[:quantity].blank? }
Expand Down
8 changes: 3 additions & 5 deletions app/models/distribution.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ class Distribution < ApplicationRecord
enum delivery_method: { pick_up: 0, delivery: 1, shipped: 2 }
scope :active, -> { joins(:line_items).joins(:items).where(items: { active: true }) }
# add item_id scope to allow filtering distributions by item
scope :by_item_id, ->(item_id) { joins(:items).where(items: { id: item_id }) }
scope :by_item_id, ->(item_id) { includes(:items).where(items: { id: item_id }) }
# partner scope to allow filtering by partner
scope :by_item_category_id, ->(item_category_id) { joins(:items).where(items: { item_category_id: item_category_id }) }
scope :by_item_category_id, ->(item_category_id) { includes(:items).where(items: { item_category_id: item_category_id }) }
scope :by_partner, ->(partner_id) { where(partner_id: partner_id) }
# location scope to allow filtering distributions by location
scope :by_location, ->(storage_location_id) { where(storage_location_id: storage_location_id) }
Expand All @@ -65,9 +65,7 @@ class Distribution < ApplicationRecord
.apply_filters(filters, date_range)
}
scope :apply_filters, ->(filters, date_range) {
includes(:partner, :storage_location, :line_items, :items)
.order(issued_at: :desc)
.class_filter(filters.merge(during: date_range))
class_filter(filters.merge(during: date_range))
}
scope :this_week, -> do
where("issued_at > :start_date AND issued_at <= :end_date",
Expand Down
7 changes: 4 additions & 3 deletions app/models/item.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,10 @@ class Item < ApplicationRecord

scope :active, -> { where(active: true) }

# Add spec for these
scope :kits, -> { where.not(kit_id: nil) }
# :housing_a_kit are items which house a kit, NOT items is_in_kit
scope :housing_a_kit, -> { where.not(kit_id: nil) }
scope :loose, -> { where(kit_id: nil) }
scope :inactive, -> { where.not(active: true) }

scope :visible, -> { where(visible_to_partners: true) }
scope :alphabetized, -> { order(:name) }
Expand Down Expand Up @@ -142,7 +143,7 @@ def is_in_kit?(kits = nil)
end

def can_delete?(inventory = nil, kits = nil)
can_deactivate_or_delete?(inventory, kits) && line_items.none? && !barcode_count&.positive? && !in_request?
can_deactivate_or_delete?(inventory, kits) && line_items.none? && !barcode_count&.positive? && !in_request? && kit.blank?
end

# @return [Boolean]
Expand Down
7 changes: 7 additions & 0 deletions app/models/request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
# discard_reason :text
# discarded_at :datetime
# request_items :jsonb
# request_type :string
# status :integer default("pending")
# created_at :datetime not null
# updated_at :datetime not null
Expand All @@ -31,6 +32,7 @@ class Request < ApplicationRecord
has_many :child_item_requests, through: :item_requests

enum status: { pending: 0, started: 1, fulfilled: 2, discarded: 3 }, _prefix: true
enum request_type: %w[quantity individual child].map { |v| [v, v] }.to_h

validates :distribution_id, uniqueness: true, allow_nil: true
validate :item_requests_uniqueness_by_item_id
Expand All @@ -45,6 +47,7 @@ class Request < ApplicationRecord
scope :by_partner, ->(partner_id) { where(partner_id: partner_id) }
# status scope to allow filtering by status
scope :by_status, ->(status) { where(status: status) }
scope :by_request_type, ->(request_type) { where(request_type: request_type) }
scope :during, ->(range) { where(created_at: range) }
scope :for_csv_export, ->(organization, *) {
where(organization: organization)
Expand All @@ -60,6 +63,10 @@ def user_email
partner_user_id ? User.find_by(id: partner_user_id).email : Partner.find_by(id: partner_id).email
end

def request_type_label
request_type&.first&.capitalize
end

private

def item_requests_uniqueness_by_item_id
Expand Down
Loading

0 comments on commit 2217817

Please sign in to comment.