Skip to content

Commit c30b4d4

Browse files
committed
Merge remote-tracking branch 'origin/main' into dependabot/bundler/rails-7.2.2
Conflicts: Gemfile.lock app/models/request.rb
2 parents cf88808 + 36f4fe8 commit c30b4d4

File tree

431 files changed

+6074
-4572
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

431 files changed

+6074
-4572
lines changed
File renamed without changes.

.rubocop_todo.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,6 @@ Layout/SpaceInsideHashLiteralBraces:
225225
- 'app/models/product_drive_participant.rb'
226226
- 'app/models/distribution.rb'
227227
- 'app/models/donation.rb'
228-
- 'app/models/inventory_item.rb'
229228
- 'app/models/item.rb'
230229
- 'app/models/item_category.rb'
231230
- 'app/models/kit.rb'

CONTRIBUTING.md

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,20 +53,49 @@ Make sure to install **Ubuntu** as your Linux distribution. (This should be defa
5353
<details>
5454
<summary> Bank Users 🏦 </summary>
5555

56+
Pawnee Diaper Bank
57+
A fully set up bank with items, storage locations, donations, distributions, requests, etc.
58+
The bank has multiple partners associated with it.
5659
```
5760
Organization Admin
58-
61+
5962
Password: password!
6063
6164
User
6265
6366
Password: password!
6467
```
68+
69+
Second City Essentials Bank
70+
A fully set up bank with items, storage locations, donations, distributions, requests, etc.
71+
The bank has four items unique to it (named Second City Item #).
72+
```
73+
Organization Admin
74+
75+
Password: password!
76+
77+
User
78+
79+
Password: password!
80+
```
81+
82+
SF Diaper Bank
83+
A bank which has just been accepted and so is not fully set up. It lacks many of the records the other banks have.
84+
```
85+
Organization Admin
86+
87+
Password: password!
88+
89+
User
90+
91+
Password: password!
92+
```
6593
</details>
6694

6795
<details>
6896
<summary> Partner Users 👥 </summary>
6997

98+
Partners in Pawnee Diaper Bank partner groups
7099
```
71100
Verified Partner
72101
@@ -87,10 +116,17 @@ Make sure to install **Ubuntu** as your Linux distribution. (This should be defa
87116
Waiting Approval Partner
88117
89118
Password: password!
90-
91-
Another approved partner (with all groups):
119+
120+
Another verified partner (in second partner group):
92121
93-
Pasword: password!
122+
Password: password!
123+
```
124+
125+
Partners in Second City Essentials Bank partner group
126+
```
127+
Verified partner
128+
129+
Password: password!
94130
```
95131
</details>
96132

@@ -221,7 +257,7 @@ Before submitting a pull request, run all tests and lints. Fix any broken tests
221257
- Once your first PR has been merged, all commits pushed to an open PR will also run these workflows.
222258
223259
#### Local testing
224-
- Run all lints with `bin/lint`.
260+
- Run all lints with `bin/lint`. (You can lint a single file/folder with `bin/lint {path_to_folder_or_file}`.)
225261
- Run all tests with `bundle exec rspec`
226262
- You can run a single test with `bundle exec rspec {path_to_test_name}_spec.rb` or on a specific line by appending `:LineNumber`
227263
- If you need to skip a failing test, place `pending("Reason you are skipping the test")` into the `it` block rather than skipping with `xit`. This will allow rspec to deliver the error message without causing the test suite to fail.

Gemfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ gem "jwt"
100100
gem "newrelic_rpm"
101101
# Used to manage periodic cron-like jobs
102102
gem "clockwork"
103+
# Speed up app boot time by caching expensive operations
104+
gem 'bootsnap', require: false
103105

104106
##### DEPENDENCY PINS ######
105107
# These are gems that aren't used directly, only as dependencies for other gems.

Gemfile.lock

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ GEM
109109
bindex (0.8.1)
110110
binding_of_caller (1.0.1)
111111
debug_inspector (>= 1.2.0)
112+
bootsnap (1.18.4)
113+
msgpack (~> 1.2)
112114
bootstrap (5.2.3)
113115
autoprefixer-rails (>= 9.1.0)
114116
popper_js (>= 2.11.6, < 3)
@@ -381,6 +383,7 @@ GEM
381383
monetize (~> 1.9)
382384
money (~> 6.13)
383385
railties (>= 3.0)
386+
msgpack (1.7.5)
384387
multi_xml (0.7.1)
385388
bigdecimal (~> 3.1)
386389
multipart-post (2.4.1)
@@ -716,6 +719,7 @@ DEPENDENCIES
716719
azure-storage-blob
717720
better_errors
718721
binding_of_caller
722+
bootsnap
719723
bootstrap (~> 5.2)
720724
brakeman
721725
bugsnag

app/assets/stylesheets/custom.scss

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,13 @@
9898
margin-top: 40px;
9999
}
100100
}
101+
102+
.accordion-button.saving::after {
103+
background-image: none;
104+
content: "Saving...";
105+
font-size: 0.875rem;
106+
color: #005568;
107+
transform: none;
108+
width: 3rem;
109+
cursor: not-allowed;
110+
}

app/controllers/admin/base_items_controller.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# [Super Admin] Manage the BaseItems -- this is the only place in the app where Base Items can be
22
# added / modified. Base Items are both the template and common thread for regular Items
3+
#
4+
# See #4656, BaseItems are pending significant changes/possible deletion
35
class Admin::BaseItemsController < AdminController
46
def edit
57
@base_item = BaseItem.find(params[:id])
@@ -40,7 +42,9 @@ def show
4042

4143
def destroy
4244
@base_item = BaseItem.includes(:items).find(params[:id])
43-
if @base_item.items.any? && @base_item.destroy
45+
if @base_item.id == KitCreateService.find_or_create_kit_base_item!.id
46+
redirect_to admin_base_items_path, alert: "You cannot delete the Kits base item. This is reserved for all Kits."
47+
elsif @base_item.items.empty? && @base_item.destroy
4448
redirect_to admin_base_items_path, notice: "Base Item deleted!"
4549
else
4650
redirect_to admin_base_items_path, alert: "Failed to delete Base Item. Are there still items attached?"

app/controllers/admin/organizations_controller.rb

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,14 @@ def new
4646

4747
def create
4848
@organization = Organization.new(organization_params)
49+
@user = User.new(user_params)
4950

5051
if @organization.save
5152
Organization.seed_items(@organization)
52-
@user = UserInviteService.invite(name: user_params[:name],
53-
email: user_params[:email],
54-
roles: [Role::ORG_USER, Role::ORG_ADMIN],
55-
resource: @organization)
53+
UserInviteService.invite(name: user_params[:name],
54+
email: user_params[:email],
55+
roles: [Role::ORG_USER, Role::ORG_ADMIN],
56+
resource: @organization)
5657
SnapshotEvent.publish(@organization) # need one to start with
5758
redirect_to admin_organizations_path, notice: "Organization added!"
5859
else

app/controllers/audits_controller.rb

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,7 @@ def index
1010
end
1111

1212
def show
13-
if Event.read_events?(@audit.organization)
14-
@items = View::Inventory.items_for_location(@audit.storage_location)
15-
else
16-
@inventory_items = @audit.storage_location.inventory_items
17-
end
13+
@items = View::Inventory.items_for_location(@audit.storage_location, include_omitted: true)
1814
end
1915

2016
def edit
@@ -28,24 +24,7 @@ def finalize
2824
@audit.adjustment = Adjustment.new(organization_id: @audit.organization_id, storage_location_id: @audit.storage_location_id, user_id: current_user.id, comment: 'Created Automatically through the Auditing Process')
2925
@audit.save
3026

31-
inventory_items = @audit.storage_location.inventory_items
32-
33-
inventory_items.each do |inventory_item|
34-
line_item = @audit.line_items.find_by(item: inventory_item.item)
35-
36-
next if line_item.nil?
37-
38-
if line_item.quantity != inventory_item.quantity
39-
@audit.adjustment.line_items.create(item_id: inventory_item.item.id, quantity: line_item.quantity - inventory_item.quantity)
40-
end
41-
end
42-
43-
increasing_adjustment, decreasing_adjustment = @audit.adjustment.split_difference
44-
ActiveRecord::Base.transaction do
45-
@audit.storage_location.increase_inventory(increasing_adjustment.line_item_values)
46-
@audit.storage_location.decrease_inventory(decreasing_adjustment.line_item_values)
47-
AuditEvent.publish(@audit)
48-
end
27+
AuditEvent.publish(@audit)
4928
@audit.finalized!
5029
redirect_to audit_path(@audit), notice: "Audit is Finalized."
5130
rescue => e
@@ -114,7 +93,7 @@ def set_storage_locations
11493
end
11594

11695
def set_items
117-
@items = current_organization.items.alphabetized
96+
@items = current_organization.items.where(active: true).alphabetized
11897
end
11998

12099
def save_audit_status_and_redirect(params)

app/controllers/distributions_controller.rb

Lines changed: 40 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -43,30 +43,33 @@ def index
4343

4444
@distributions = current_organization
4545
.distributions
46-
.includes(:partner, :storage_location, line_items: [:item])
47-
.order('issued_at DESC')
48-
.apply_filters(filter_params, helpers.selected_range)
46+
.order(issued_at: :desc)
47+
.includes(:partner, :storage_location)
48+
.class_filter(scope_filters)
4949
@paginated_distributions = @distributions.page(params[:page])
50-
@items = current_organization.items.alphabetized
51-
@item_categories = current_organization.item_categories
52-
@storage_locations = current_organization.storage_locations.active_locations.alphabetized
53-
@partners = @distributions.collect(&:partner).uniq.sort_by(&:name)
50+
@items = current_organization.items.alphabetized.select(:id, :name)
51+
@item_categories = current_organization.item_categories.select(:id, :name)
52+
@storage_locations = current_organization.storage_locations.active_locations.alphabetized.select(:id, :name)
53+
@partners = current_organization.partners.active.alphabetized.select(:id, :name)
5454
@selected_item = filter_params[:by_item_id].presence
55-
@total_value_all_distributions = total_value(@distributions)
56-
@total_items_all_distributions = total_items(@distributions, @selected_item)
57-
@total_value_paginated_distributions = total_value(@paginated_distributions)
58-
@total_items_paginated_distributions = total_items(@paginated_distributions, @selected_item)
55+
@distribution_totals = DistributionTotalsService.new(current_organization.distributions, scope_filters)
56+
@total_value_all_distributions = @distribution_totals.total_value
57+
@total_items_all_distributions = @distribution_totals.total_quantity
58+
paginated_ids = @paginated_distributions.ids
59+
@total_value_paginated_distributions = @distribution_totals.total_value(paginated_ids)
60+
@total_items_paginated_distributions = @distribution_totals.total_quantity(paginated_ids)
5961
@selected_item_category = filter_params[:by_item_category_id]
6062
@selected_partner = filter_params[:by_partner]
6163
@selected_status = filter_params[:by_state]
6264
@selected_location = filter_params[:by_location]
6365
# FIXME: one of these needs to be removed but it's unclear which at this point
6466
@statuses = Distribution.states.transform_keys(&:humanize)
67+
@distributions_with_inactive_items = @distributions.joins(:inactive_items).pluck(:id)
6568

6669
respond_to do |format|
6770
format.html
6871
format.csv do
69-
send_data Exports::ExportDistributionsCSVService.new(distributions: @distributions, organization: current_organization, filters: filter_params).generate_csv, filename: "Distributions-#{Time.zone.today}.csv"
72+
send_data Exports::ExportDistributionsCSVService.new(distributions: @distributions, organization: current_organization, filters: scope_filters).generate_csv, filename: "Distributions-#{Time.zone.today}.csv"
7073
end
7174
end
7275
end
@@ -114,16 +117,12 @@ def create
114117
elsif request_id
115118
@distribution.initialize_request_items
116119
end
117-
@items = current_organization.items.alphabetized
120+
@items = current_organization.items.active.alphabetized
118121
@partner_list = current_organization.partners.where.not(status: 'deactivated').alphabetized
119122

120-
if Event.read_events?(current_organization)
121-
inventory = View::Inventory.new(@distribution.organization_id)
122-
@storage_locations = current_organization.storage_locations.active_locations.alphabetized.select do |storage_loc|
123-
inventory.quantity_for(storage_location: storage_loc.id).positive?
124-
end
125-
else
126-
@storage_locations = current_organization.storage_locations.active_locations.has_inventory_items.alphabetized
123+
inventory = View::Inventory.new(@distribution.organization_id)
124+
@storage_locations = current_organization.storage_locations.active_locations.alphabetized.select do |storage_loc|
125+
inventory.quantity_for(storage_location: storage_loc.id).positive?
127126
end
128127

129128
flash_error = insufficient_error_message(result.error.message)
@@ -148,16 +147,12 @@ def new
148147
@distribution.line_items.build
149148
@distribution.copy_from_donation(params[:donation_id], params[:storage_location_id])
150149
end
151-
@items = current_organization.items.alphabetized
150+
@items = current_organization.items.active.alphabetized
152151
@partner_list = current_organization.partners.where.not(status: 'deactivated').alphabetized
153152

154-
if Event.read_events?(current_organization)
155-
inventory = View::Inventory.new(current_organization.id)
156-
@storage_locations = current_organization.storage_locations.active_locations.alphabetized.select do |storage_loc|
157-
inventory.quantity_for(storage_location: storage_loc.id).positive?
158-
end
159-
else
160-
@storage_locations = current_organization.storage_locations.active_locations.has_inventory_items.alphabetized
153+
inventory = View::Inventory.new(current_organization.id)
154+
@storage_locations = current_organization.storage_locations.active_locations.alphabetized.select do |storage_loc|
155+
inventory.quantity_for(storage_location: storage_loc.id).positive?
161156
end
162157
end
163158

@@ -178,18 +173,14 @@ def edit
178173
if (!@distribution.complete? && @distribution.future?) ||
179174
current_user.has_role?(Role::ORG_ADMIN, current_organization)
180175
@distribution.line_items.build if @distribution.line_items.size.zero?
181-
@items = current_organization.items.alphabetized
176+
@items = current_organization.items.active.alphabetized
182177
@partner_list = current_organization.partners.alphabetized
183178
@audit_warning = current_organization.audits
184179
.where(storage_location_id: @distribution.storage_location_id)
185180
.where("updated_at > ?", @distribution.created_at).any?
186-
if Event.read_events?(current_organization)
187-
inventory = View::Inventory.new(@distribution.organization_id)
188-
@storage_locations = current_organization.storage_locations.active_locations.alphabetized.select do |storage_loc|
189-
!inventory.quantity_for(storage_location: storage_loc.id).negative?
190-
end
191-
else
192-
@storage_locations = current_organization.storage_locations.active_locations.has_inventory_items.alphabetized
181+
inventory = View::Inventory.new(@distribution.organization_id)
182+
@storage_locations = current_organization.storage_locations.active_locations.alphabetized.select do |storage_loc|
183+
!inventory.quantity_for(storage_location: storage_loc.id).negative?
193184
end
194185
else
195186
redirect_to distributions_path, error: 'To edit a distribution,
@@ -213,7 +204,7 @@ def update
213204
flash[:error] = insufficient_error_message(result.error.message)
214205
@distribution.line_items.build if @distribution.line_items.size.zero?
215206
@distribution.initialize_request_items
216-
@items = current_organization.items.alphabetized
207+
@items = current_organization.items.active.alphabetized
217208
@storage_locations = current_organization.storage_locations.active_locations.alphabetized
218209
render :edit
219210
end
@@ -297,16 +288,6 @@ def request_id
297288
params.dig(:distribution, :request_attributes, :id)
298289
end
299290

300-
def total_items(distributions, item)
301-
query = LineItem.where(itemizable_type: "Distribution", itemizable_id: distributions.pluck(:id))
302-
query = query.where(item_id: item.to_i) if item
303-
query.sum('quantity')
304-
end
305-
306-
def total_value(distributions)
307-
distributions.sum(&:value_per_itemizable)
308-
end
309-
310291
def daily_items(pick_ups)
311292
item_groups = LineItem.where(itemizable_type: "Distribution", itemizable_id: pick_ups.pluck(:id)).group_by(&:item_id)
312293
item_groups.map do |_id, items|
@@ -318,21 +299,26 @@ def daily_items(pick_ups)
318299
end
319300
end
320301

302+
def scope_filters
303+
filter_params
304+
.except(:date_range)
305+
.merge(during: helpers.selected_range)
306+
end
307+
321308
helper_method \
322309
def filter_params
323310
return {} unless params.key?(:filters)
324311

325-
params.require(:filters).permit(:by_item_id, :by_item_category_id, :by_partner, :by_state, :by_location)
312+
params
313+
.require(:filters)
314+
.permit(:by_item_id, :by_item_category_id, :by_partner, :by_state, :by_location, :date_range)
326315
end
327316

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

331-
if inventory_check_result.error.present?
332-
flash[:error] = inventory_check_result.error
333-
end
334-
if inventory_check_result.alert.present?
335-
flash[:alert] = inventory_check_result.alert
336-
end
320+
alerts = [inventory_check_result.minimum_alert, inventory_check_result.recommended_alert]
321+
merged_alert = alerts.compact.join("\n")
322+
flash[:alert] = merged_alert if merged_alert.present?
337323
end
338324
end

0 commit comments

Comments
 (0)