Skip to content

Commit

Permalink
Merge branch 'main' into 4135-request-value-preservation
Browse files Browse the repository at this point in the history
  • Loading branch information
elasticspoon committed Mar 4, 2024
2 parents 68187fe + fd551b6 commit 339672d
Show file tree
Hide file tree
Showing 45 changed files with 333 additions and 112 deletions.
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ group :development, :test do
gem 'rubocop-performance'
gem "rubocop-rails", "~> 2.23.1"
# Default rules for Rubocop.
gem "standard", "~> 1.33"
gem "standard", "~> 1.34"
# Erb linter.
gem "erb_lint"
end
Expand Down
28 changes: 14 additions & 14 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,9 @@ GEM
discard (1.3.0)
activerecord (>= 4.2, < 8)
docile (1.4.0)
dotenv (3.0.3)
dotenv-rails (3.0.3)
dotenv (= 3.0.3)
dotenv (3.1.0)
dotenv-rails (3.1.0)
dotenv (= 3.1.0)
railties (>= 6.1)
dry-core (1.0.1)
concurrent-ruby (~> 1.0)
Expand Down Expand Up @@ -295,7 +295,7 @@ GEM
actionview (>= 5.0.0)
activesupport (>= 5.0.0)
json (2.7.1)
jwt (2.8.0)
jwt (2.8.1)
base64
kaminari (1.2.2)
activesupport (>= 4.1.0)
Expand Down Expand Up @@ -533,19 +533,19 @@ GEM
rspec-mocks (~> 3.12)
rspec-support (~> 3.12)
rspec-support (3.12.1)
rubocop (1.59.0)
rubocop (1.61.0)
json (~> 2.3)
language_server-protocol (>= 3.17.0)
parallel (~> 1.10)
parser (>= 3.2.2.4)
parser (>= 3.3.0.2)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.8, < 3.0)
rexml (>= 3.2.5, < 4.0)
rubocop-ast (>= 1.30.0, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 3.0)
rubocop-ast (1.30.0)
parser (>= 3.2.1.0)
rubocop-ast (1.31.1)
parser (>= 3.3.0.4)
rubocop-performance (1.20.2)
rubocop (>= 1.48.1, < 2.0)
rubocop-ast (>= 1.30.0, < 2.0)
Expand Down Expand Up @@ -602,18 +602,18 @@ GEM
actionpack (>= 5.2)
activesupport (>= 5.2)
sprockets (>= 3.0.0)
standard (1.33.0)
standard (1.34.0)
language_server-protocol (~> 3.17.0.2)
lint_roller (~> 1.0)
rubocop (~> 1.59.0)
rubocop (~> 1.60)
standard-custom (~> 1.0.0)
standard-performance (~> 1.3)
standard-custom (1.0.2)
lint_roller (~> 1.0)
rubocop (~> 1.50)
standard-performance (1.3.0)
standard-performance (1.3.1)
lint_roller (~> 1.1)
rubocop-performance (~> 1.20.1)
rubocop-performance (~> 1.20.2)
stimulus-rails (1.3.3)
railties (>= 6.0.0)
strong_migrations (1.7.0)
Expand Down Expand Up @@ -742,7 +742,7 @@ DEPENDENCIES
simple_form
simplecov
sprockets (~> 4.2.1)
standard (~> 1.33)
standard (~> 1.34)
stimulus-rails
strong_migrations (= 1.7.0)
terser
Expand All @@ -751,4 +751,4 @@ DEPENDENCIES
webmock (~> 3.23)

BUNDLED WITH
2.5.4
2.5.6
1 change: 1 addition & 0 deletions app/assets/stylesheets/application.scss
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ body a {

#copy-calendar-button {
margin-left: 10px;
height: fit-content;
}

select.selectpicker + .dropdown-toggle::after {
Expand Down
3 changes: 2 additions & 1 deletion app/assets/stylesheets/custom.scss
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@

#calendar {
background-color: #ffffff;
width: 100%
width: 100%;
height: 80%
}

#csvImportModal .modal-dialog.onboarding_steps .modal-body li {
Expand Down
13 changes: 12 additions & 1 deletion app/controllers/items_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ class ItemsController < ApplicationController
def index
@items = current_organization.items.includes(:base_item, :kit).alphabetized.class_filter(filter_params)
@items = @items.active unless params[:include_inactive_items]

@item_categories = current_organization.item_categories.includes(:items).order('name ASC')
@kits = current_organization.kits.includes(line_items: :item, inventory_items: :storage_location)
@storages = current_organization.storage_locations.active_locations.order(id: :asc)
Expand Down Expand Up @@ -74,7 +75,17 @@ def show

def update
@item = current_organization.items.find(params[:id])
if @item.update(item_params)
@item.attributes = item_params

deactivated = @item.active_changed? && !@item.active
if deactivated && !@item.can_deactivate?
@base_items = BaseItem.without_kit.alphabetized
flash[:error] = "Can't deactivate this item - it is currently assigned to either an active kit or a storage location!"
render action: :edit
return
end

if @item.save
redirect_to items_path, notice: "#{@item.name} updated!"
else
@base_items = BaseItem.without_kit.alphabetized
Expand Down
8 changes: 6 additions & 2 deletions app/controllers/kits_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,12 @@ def deactivate

def reactivate
@kit = Kit.find(params[:id])
@kit.reactivate
redirect_back(fallback_location: dashboard_path, notice: "Kit has been reactivated!")
if @kit.can_reactivate?
@kit.reactivate
redirect_back(fallback_location: dashboard_path, notice: "Kit has been reactivated!")
else
redirect_back(fallback_location: dashboard_path, alert: "Cannot reactivate kit - it has inactive items! Please reactivate the items first.")
end
end

def allocations
Expand Down
3 changes: 2 additions & 1 deletion app/controllers/partners_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,8 @@ def invite

def invite_partner_user
partner = current_organization.partners.find(params[:partner])
UserInviteService.invite(email: params[:email],
UserInviteService.invite(name: params[:name],
email: params[:email],
roles: [Role::PARTNER],
resource: partner)

Expand Down
2 changes: 2 additions & 0 deletions app/controllers/product_drives_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ def index
.class_filter(filter_params)
.within_date_range(@selected_date_range)
.order(start_date: :desc)
# to be used in the name filter to sort product drives in alpha order
@product_drives_alphabetical = @product_drives.sort_by { |pd| pd.name.downcase }
@item_categories = current_organization.item_categories
@selected_name_filter = filter_params[:by_name]
@selected_item_category = filter_params[:by_item_category_id]
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/storage_locations_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,8 @@ def inventory
.includes(inventory_items: :item)
.find(params[:id])
.inventory_items
.active

@inventory_items = @inventory_items.active unless params[:include_inactive_items] == "true"
@inventory_items += include_omitted_items(@inventory_items.collect(&:item_id)) if params[:include_omitted_items] == "true"
respond_to :json
end
Expand Down
2 changes: 1 addition & 1 deletion app/helpers/dashboard_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def future_distributed
end

def recently_added_user_display_text(user)
(user.name == "Name Not Provided") ? user.email : user.name
(user.name.blank? || user.name == "Name Not Provided") ? user.email : user.name
end

private
Expand Down
13 changes: 13 additions & 0 deletions app/models/item.rb
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,19 @@ def self.reactivate(item_ids)
Item.where(id: item_ids).find_each { |item| item.update(active: true) }
end

# @return [Boolean]
def can_deactivate?
# Cannot deactivate if it's currently in inventory in a storage location. It doesn't make sense
# to have physical inventory of something we're now saying isn't valid.
inventory_items.where("quantity > 0").none? &&
# If an active kit includes this item, then changing kit allocations would change inventory
# for an inactive item - which we said above we don't want to allow.
organization.kits
.active
.joins(:line_items)
.where(line_items: { item_id: id}).none?
end

def deactivate
if kit
kit.deactivate
Expand Down
7 changes: 7 additions & 0 deletions app/models/kit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ def deactivate
item.update!(active: false)
end

# Kits can't reactivate if they have any inactive items, because now whenever they are allocated
# or deallocated, we are changing inventory for inactive items (which we don't allow).
# @return [Boolean]
def can_reactivate?
line_items.joins(:item).where(items: { active: false }).none?
end

def reactivate
update!(active: true)
item.update!(active: true)
Expand Down
1 change: 0 additions & 1 deletion app/models/storage_location.rb
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,6 @@ def increase_inventory(itemizable_array)
# This is, at least for now, how we log changes to the inventory made in this call
log = {}
# Iterate through each of the line-items in the moving box
Item.reactivate(itemizable_array.map { |item_hash| item_hash[:item_id] })
itemizable_array.each do |item_hash|
# Locate the storage box for the item, or create a new storage box for it
inventory_item = inventory_items.find_or_create_by!(item_id: item_hash[:item_id])
Expand Down
4 changes: 0 additions & 4 deletions app/queries/items_by_storage_collection_and_quantity_query.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ class ItemsByStorageCollectionAndQuantityQuery
def self.call(organization:, filter_params:, inventory: nil)
if inventory
items = organization.items.order(name: :asc).class_filter(filter_params)
items = items.active if filter_params[:include_inactive_items]
return items.to_h do |item|
locations = inventory.storage_locations_for_item(item.id).map do |sl|
{
Expand All @@ -31,9 +30,6 @@ def self.call(organization:, filter_params:, inventory: nil)
end

items_by_storage_collection = ItemsByStorageCollectionQuery.new(organization: organization, filter_params: filter_params).call
unless filter_params[:include_inactive_items]
items_by_storage_collection = items_by_storage_collection.active
end
items_by_storage_collection_and_quantity = Hash.new
items_by_storage_collection.each do |row|
unless items_by_storage_collection_and_quantity.key?(row.id)
Expand Down
1 change: 1 addition & 0 deletions app/queries/items_by_storage_collection_query.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ def initialize(organization:, filter_params:)
def call
@items ||= organization
.items
.active
.joins(' LEFT OUTER JOIN "inventory_items" ON "inventory_items"."item_id" = "items"."id"')
.joins(' LEFT OUTER JOIN "storage_locations" ON "storage_locations"."id" = "inventory_items"."storage_location_id"')
.select('
Expand Down
5 changes: 4 additions & 1 deletion app/services/itemizable_update_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ module ItemizableUpdateService
def self.call(itemizable:, type: :increase, params: {}, event_class: nil)
StorageLocation.transaction do
item_ids = params[:line_items_attributes]&.values&.map { |i| i[:item_id].to_i } || []
Item.reactivate(item_ids)
inactive_item_names = Item.where(id: item_ids, active: false).pluck(:name)
if inactive_item_names.any?
raise "Update failed: The following items are currently inactive: #{inactive_item_names.join(", ")}. Please reactivate them before continuing."
end

from_location = to_location = itemizable.storage_location
to_location = StorageLocation.find(params[:storage_location_id]) if params[:storage_location_id]
Expand Down
3 changes: 1 addition & 2 deletions app/services/partner_profile_update_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,8 @@ def call

if @return_value
@profile.served_areas.destroy_all
@profile.reload
@profile.attributes = @profile_params
@profile.save!(context: :edit)
@profile.reload
end
end
end
Expand All @@ -29,6 +27,7 @@ def perform_profile_service(&block)
@profile.transaction do
yield block
end
@profile.reload
rescue ActiveRecord::RecordNotFound => e
Rails.logger.error "[!] #{self.class.name} failed to update profile #{@profile.id} because it does not exist"
set_error(e)
Expand Down
3 changes: 2 additions & 1 deletion app/services/partners/family_request_create_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ def valid?
end

def item_requests_attributes
@item_requests_attributes ||= family_requests_attributes.map do |fr_attr|
@item_requests_attributes ||= family_requests_attributes.filter_map do |fr_attr|
next if fr_attr[:item_id].blank? && fr_attr[:person_count].blank?
{
item_id: fr_attr[:item_id],
quantity: convert_person_count_to_item_quantity(item_id: fr_attr[:item_id], person_count: fr_attr[:person_count])&.to_i,
Expand Down
2 changes: 1 addition & 1 deletion app/services/reports/partner_info_report_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def partner_agency_counts
end

def partner_zipcodes_serviced
partner_agency_profiles.map(&:zips_served).uniq.join(', ')
partner_agency_profiles.map(&:zips_served).uniq.sort.join(', ')
end
end
end
2 changes: 1 addition & 1 deletion app/services/user_invite_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def self.invite(email:, resource:, name: nil, roles: [], force: false)
end

User.invite!(email: email) do |user1|
user1.name = name if name # Does this get persisted somewhere up the line? - CLF 20230203
user1.name = name.presence || "Name Not Provided"
add_roles(user1, resource: resource, roles: roles)
user1.skip_invitation = user1.errors[:email].any?
end
Expand Down
2 changes: 1 addition & 1 deletion app/views/audits/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
</div>
<div class="box-body">
<%= simple_form_for @audit, html: {class: "storage-location-required"} do |f| %>
<%= render partial: "storage_locations/source", object: f, locals: { label: "Storage location", error: "What storage location are you auditing?", include_inactive_items: true} %>
<%= render partial: "storage_locations/source", object: f, locals: { label: "Storage location", error: "What storage location are you auditing?" } %>
<fieldset style="margin-bottom: 2rem;">
<legend>Items in this audit</legend>
<div id="audit_line_items" class="line-item-fields" data-capture-barcode="true">
Expand Down
2 changes: 1 addition & 1 deletion app/views/distributions/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
</div>
</div>

<%= render partial: "storage_locations/source", object: f, locals: { include_inactive_items: false, include_omitted_items: true } %>
<%= render partial: "storage_locations/source", object: f, locals: { include_omitted_items: true } %>
<%= f.input :comment, label: "Comment" %>

Expand Down
8 changes: 6 additions & 2 deletions app/views/partners/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,11 @@
<%= form_tag invite_partner_user_partner_path do %>
<div class="input-group">
<span class="input-group-text" id="spn_env_fa_icon"><%= fa_icon "envelope" %></span>
<input type="email" name="email" class="form-control" placeholder="Email" aria-describedby="spn_env_fa_icon" autocomplete="on">
<input type="email" name="email" class="form-control" placeholder="Email" aria-describedby="spn_env_fa_icon" required autocomplete="off">
</div>
<div class="input-group mt-3">
<span class="input-group-text" id="spn_env_fa_icon"><%= fa_icon "user" %></span>
<input type="text" name="name" class="form-control" placeholder="Name" aria-describedby="name_icon" required autocomplete="off">
<%= hidden_field_tag :partner, @partner.id %><br>
</div>
<br>
Expand All @@ -331,7 +335,7 @@
<%= form_tag partner_user_reset_password_users_path do %>
<div class="input-group">
<span class="input-group-text" id="spn_env_fa_icon"><%= fa_icon "envelope" %></span>
<input type="email" name="email" class="form-control" placeholder="Email" aria-describedby="spn_env_fa_icon" autocomplete="on">
<input type="email" name="email" class="form-control" placeholder="Email" aria-describedby="spn_env_fa_icon" autocomplete="off">
<%= hidden_field_tag :partner_id, @partner.id %><br>
</div>
<br>
Expand Down
2 changes: 1 addition & 1 deletion app/views/product_drives/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
<%= form_tag(product_drives_path, method: :get, organization_id: current_organization) do |f| %>
<div class="row">
<div class="form-group col-lg-3 col-md-4 col-sm-6 col-xs-12">
<%= filter_select(scope: :by_name, collection: @product_drives, key: :name, value: :name, selected: @selected_name_filter) %>
<%= filter_select(scope: :by_name, collection: @product_drives_alphabetical, key: :name, value: :name, selected: @selected_name_filter) %>
</div>
<div class="form-group col-lg-3 col-md-4 col-sm-6 col-xs-12">
<%= filter_select(label: "Filter by item category", scope: :by_item_category_id, collection: @item_categories, selected: @selected_item_category) %>
Expand Down
2 changes: 0 additions & 2 deletions app/views/storage_locations/_source.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
label ||= "From storage location"
error ||= "From what location are you moving inventory?"
association_field ||= :storage_location
include_inactive_items ||= false
include_omitted_items ||= false
%>
<%= source.association association_field,
Expand All @@ -16,7 +15,6 @@
data: {
storage_location_inventory_path: inventory_storage_location_path(
organization_id: current_organization,
include_inactive_items: include_inactive_items,
include_omitted_items: include_omitted_items,
id: ":id",
format: :json
Expand Down
8 changes: 6 additions & 2 deletions config/initializers/bugsnag.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
Bugsnag.configure do |config|
config.api_key = ENV["BUGSNAG_API_KEY"]
if ENV["BUGSNAG_API_KEY"].present?
Bugsnag.configure do |config|
config.api_key = ENV["BUGSNAG_API_KEY"]
end
else
Bugsnag.configuration.logger = ::Logger.new("/dev/null")
end
Loading

0 comments on commit 339672d

Please sign in to comment.