Skip to content

Commit 328876e

Browse files
authored
Merge pull request #5322 from john-huang-121/5308-export-audit-csv
5308 Audit CSV Export
2 parents bda56a6 + af74324 commit 328876e

File tree

6 files changed

+105
-9
lines changed

6 files changed

+105
-9
lines changed

app/controllers/audits_controller.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ def index
77
@selected_location = filter_params[:at_location]
88
@audits = current_organization.audits.includes(:line_items, :storage_location).class_filter(filter_params)
99
@storage_locations = StorageLocation.with_audits_for(current_organization).select(:id, :name)
10+
11+
respond_to do |format|
12+
format.html
13+
format.csv do
14+
send_data Audit.generate_csv(@audits), filename: "Audits-#{Time.zone.today}.csv"
15+
end
16+
end
1017
end
1118

1219
def show

app/models/audit.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ class Audit < ApplicationRecord
1919
belongs_to :storage_location
2020
belongs_to :adjustment, optional: true
2121

22+
include Exportable
2223
include Itemizable
2324
include Filterable
2425

@@ -50,6 +51,26 @@ def user_is_organization_admin_of_the_organization
5051
end
5152
end
5253

54+
def self.generate_csv(audits)
55+
audited_items = audits.flat_map { |audit| audit.line_items.map(&:name) }.uniq
56+
headers = csv_export_headers + audited_items
57+
58+
CSV.generate(write_headers: true, headers: headers) do |csv|
59+
audits.map do |audit|
60+
audit_hash = audited_items.index_with(0)
61+
audit.line_items.each { |li| audit_hash[li.name] = li.quantity }
62+
63+
row = [audit.updated_at.strftime("%B %d %Y"), audit.status, audit.storage_location.name] + audit_hash.values
64+
65+
csv << row.map { |attr| normalize_csv_attribute(attr) }
66+
end
67+
end
68+
end
69+
70+
def self.csv_export_headers
71+
["Audit Date", "Audit Status", "Storage Location Name"]
72+
end
73+
5374
private
5475

5576
def line_items_unique_by_item_id

app/views/audits/index.html.erb

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,13 @@
4646
<%= filter_button %>
4747
<%= clear_filter_button %>
4848

49-
<div class="btn-group pull-right">
49+
<span class="float-right">
50+
<%= download_button_to(audits_path(format: :csv), {text: "Export Audits", size: "md"}) %>
5051
<%= new_button_to new_audit_path, {text: "New Audit"} %>
51-
</div>
52+
</span>
5253
<% end # form %>
5354
</div>
54-
</div>
55+
</div>
5556
<!-- /.card -->
5657
</div>
5758
<!--/.col (left) -->

docs/user_guide/bank/exports.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Many of these can be filtered down to the information you might need for a speci
77
The exports available include (in alphabetical order):
88
- Adjustments
99
- Annual Survey
10+
- Audits
1011
- Barcode Items
1112
- Distributions
1213
- Donations
@@ -89,6 +90,19 @@ For more information on these, please see the [Annual Survey Report](reports_ann
8990
- % difference in yearly Donations,
9091
- % difference in total money donated,
9192
- % difference in disposable diaper Donations
93+
94+
## Audits
95+
### Navigating to export Audits
96+
Click "Inventory", then "Inventory Audit" in the left-hand menu. Then click "Export Audits".
97+
98+
### Contents of Audit exports
99+
For each Audit of Storage Location in the list:
100+
- Audit Date
101+
- Audit Status
102+
- Storage Location Name
103+
- Audited Items
104+
- Quantity for each of the audited items.
105+
92106
## Barcode Items
93107
### Navigating to export barcode Items
94108
Click "Inventory" then "Barcode Items" in the left-hand menu. Then click "Export Barcode Items."

spec/models/audit_spec.rb

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,35 @@
127127
expect(Audit.finalized_since?(xfer3, storage_location4)).to be false # no audits at location
128128
expect(Audit.finalized_since?(xfer3, storage_location5)).to be false # since status isn't finalized
129129
end
130+
131+
describe ".generate_csv" do
132+
let!(:item_1) { create(:item, name: "Baby Diapers") }
133+
let!(:item_2) { create(:item, name: "Adult Diapers") }
134+
let!(:sl_1) { create(:storage_location, organization: organization, name: "Diaperhaus") }
135+
let!(:sl_2) { create(:storage_location, organization: organization, name: "Pawnee Diaper Bank") }
136+
let!(:time_1) { Time.zone.parse("2025-10-02 01:00:00") }
137+
let!(:time_2) { Time.zone.parse("2025-10-03 01:00:00") }
138+
let!(:audit) { create(:audit, organization: organization, storage_location: sl_1, status: 1, updated_at: time_1) }
139+
let!(:audit_2) { create(:audit, organization: organization, storage_location: sl_2, status: 2, updated_at: time_2) }
140+
141+
before do
142+
audit.line_items.create!(item: item_1, quantity: 150)
143+
audit_2.line_items.create!(item: item_2, quantity: 250)
144+
end
145+
146+
it "generates a CSV" do
147+
csv_data = described_class.generate_csv([audit, audit_2])
148+
149+
expect(csv_data).to be_a(String)
150+
expect(csv_data).to eq(
151+
<<~CSV
152+
Audit Date,Audit Status,Storage Location Name,Baby Diapers,Adult Diapers
153+
October 02 2025,confirmed,Diaperhaus,150,0
154+
October 03 2025,finalized,Pawnee Diaper Bank,0,250
155+
CSV
156+
)
157+
end
158+
end
130159
end
131160

132161
describe "versioning" do

spec/requests/audits_requests_spec.rb

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
RSpec.describe "Audits", type: :request do
22
let(:organization) { create(:organization) }
33
let(:organization_admin) { create(:organization_admin, organization: organization) }
4-
4+
let(:storage_location) { create(:storage_location, organization: organization) }
55
let(:valid_attributes) do
66
{
77
organization_id: organization.id,
8-
storage_location_id: create(:storage_location, organization: organization).id,
8+
storage_location_id: storage_location.id,
99
user_id: create(:organization_admin, organization: organization).id
1010
}
1111
end
@@ -30,10 +30,34 @@
3030
end
3131

3232
describe "GET #index" do
33-
it "is successful" do
34-
Audit.create! valid_attributes
35-
get audits_path
36-
expect(response).to be_successful
33+
context "html" do
34+
it "is successful" do
35+
Audit.create! valid_attributes
36+
get audits_path
37+
expect(response).to be_successful
38+
end
39+
end
40+
41+
context "csv" do
42+
let(:response_format) { 'csv' }
43+
let(:csv_body) { "Stubbed CSV" }
44+
45+
before do
46+
allow(Audit).to receive(:generate_csv).and_return(csv_body)
47+
end
48+
49+
it "succeeds" do
50+
get audits_path(format: response_format)
51+
expect(response.content_type).to eq("text/csv")
52+
expect(response).to be_successful
53+
end
54+
55+
it "returns a CSV" do
56+
get audits_path(format: response_format)
57+
58+
expect(Audit).to have_received(:generate_csv)
59+
expect(response.body).to eq(csv_body)
60+
end
3761
end
3862
end
3963

0 commit comments

Comments
 (0)