Skip to content

Commit 7030ad3

Browse files
cyang-eldorner
andauthored
4981 adjuments export with item changes (#5173)
* Add specs for adjusment csv export * Add service for csv exporting adjustments * Change header to comply with existing documentation * Lint the specs * Move adjustment export format tests into requests spec * Adapt adjustments specs to test csv export text and use module method * Hardcode adjustments_requests spec strings --------- Co-authored-by: Daniel Orner <[email protected]>
1 parent f0f2f61 commit 7030ad3

File tree

5 files changed

+204
-16
lines changed

5 files changed

+204
-16
lines changed

app/models/adjustment.rb

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,11 @@ def split_difference
3434
[increasing_adjustment, decreasing_adjustment]
3535
end
3636

37-
def self.csv_export_headers
38-
["Created", "Organization", "Storage Location", "Comment", "Changes"]
39-
end
37+
def self.generate_csv(adjustments)
38+
return nil if adjustments.empty?
4039

41-
def csv_export_attributes
42-
[
43-
created_at.strftime("%F"),
44-
organization.name,
45-
storage_location.name,
46-
comment,
47-
line_items.count
48-
]
40+
Exports::ExportAdjustmentsCSVService
41+
.generate_csv(adjustments, adjustments.first.organization)
4942
end
5043

5144
private
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
module Exports
2+
module ExportAdjustmentsCSVService
3+
class << self
4+
def generate_csv(adjustments, organization)
5+
CSV.generate(headers: true) do |csv|
6+
generate_csv_data(adjustments, organization).each { |row| csv << row }
7+
end
8+
end
9+
10+
def generate_csv_data(adjustments, organization)
11+
item_names = get_item_names(organization)
12+
headers = [
13+
"Created date", "Storage Area",
14+
"Comment", "# of changes"
15+
] + item_names
16+
17+
[headers] + adjustments.map { |adjustment| build_row(adjustment, item_names) }
18+
end
19+
20+
private
21+
22+
def get_item_names(organization)
23+
organization.items.order(:name).pluck(:name).uniq
24+
end
25+
26+
def build_row(adjustment, item_names)
27+
row = [
28+
adjustment.created_at.strftime("%F"),
29+
adjustment.storage_location.name,
30+
adjustment.comment,
31+
adjustment.line_items.count { |item| !item.quantity.eql?(0) }
32+
]
33+
34+
item_quantities = Hash.new(0)
35+
36+
adjustment.line_items.each do |line_item|
37+
item_quantities[line_item.item.name] += line_item.quantity
38+
end
39+
40+
item_names.each do |item_name|
41+
row << item_quantities[item_name]
42+
end
43+
44+
row
45+
end
46+
end
47+
end
48+
end

docs/user_guide/bank/exports.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,10 @@ The exports available include (in alphabetical order):
2727
Click "Inventory", then "Inventory Adjustments" in the left-hand menu. Then click "Export Adjustments",
2828

2929
### Contents of adjustment export
30-
Creation date, Organization, Storage Area, Comment, # of changes.
31-
32-
[! NOTE] We have improving the adjustments export to include the changes made in each adjustment on our todo list. We'll also remove the organization as redundant information. Please reach out if this is a priority for you.
30+
- Creation date
31+
- Storage Area, Comment
32+
- # of changes
33+
- the quantity of each of your organization's Items in the adjustments
3334

3435
## Annual Survey
3536
### Navigating to export annual survey

spec/requests/adjustments_requests_spec.rb

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,63 @@
7272

7373
context "csv" do
7474
let(:response_format) { 'csv' }
75+
let(:storage_location) { create(:storage_location, organization: organization) }
76+
let(:item1) { create(:item, name: "Item One", organization: organization) }
77+
let(:item2) { create(:item, name: "Item Two", organization: organization) }
78+
79+
let!(:adjustment1) do
80+
adj = create(:adjustment,
81+
organization: organization,
82+
storage_location: storage_location,
83+
comment: "First adjustment",
84+
created_at: 1.day.ago)
85+
adj.line_items << build(:line_item, quantity: 10, item: item1, itemizable: adj)
86+
adj.line_items << build(:line_item, quantity: 5, item: item2, itemizable: adj)
87+
adj
88+
end
89+
90+
let!(:adjustment2) do
91+
adj = create(:adjustment,
92+
organization: organization,
93+
storage_location: storage_location,
94+
comment: "Second adjustment",
95+
created_at: 5.days.ago)
96+
adj.line_items << build(:line_item, quantity: -5, item: item1, itemizable: adj)
97+
adj
98+
end
7599

76-
before { adjustment }
100+
before { get adjustments_path(format: 'csv') }
77101

78-
it { is_expected.to be_successful }
102+
it "returns a CSV file" do
103+
expect(response).to be_successful
104+
expect(response.header['Content-Type']).to include 'text/csv'
105+
end
106+
107+
it "includes appropriate headers and data" do
108+
csv = <<~CSV
109+
Created date,Storage Area,Comment,# of changes,#{item1.name},#{item2.name}
110+
2019-06-30,Smithsonian Conservation Center,First adjustment,2,10,5
111+
2019-06-26,Smithsonian Conservation Center,Second adjustment,1,-5,0
112+
CSV
113+
114+
expect(response.body).to eq(csv)
115+
end
116+
117+
context "when filtering by date" do
118+
it "returns adjustments filtered by date range" do
119+
start_date = 3.days.ago.to_fs(:date_picker)
120+
end_date = Time.zone.today.to_fs(:date_picker)
121+
122+
get adjustments_path, params: { filters: { date_range: "#{start_date} - #{end_date}" }, format: 'csv' }
123+
124+
csv = <<~CSV
125+
Created date,Storage Area,Comment,# of changes,Item One,Item Two
126+
2019-06-30,Smithsonian Conservation Center,First adjustment,2,10,5
127+
CSV
128+
129+
expect(response.body).to eq(csv)
130+
end
131+
end
79132
end
80133
end
81134

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
RSpec.describe Exports::ExportAdjustmentsCSVService do
2+
# Create organization after items to ensure proper associations
3+
let!(:item1) { create(:item, name: "item1") }
4+
let!(:item2) { create(:item, name: "item2") }
5+
let!(:item3) { create(:item, name: "item3") }
6+
let!(:item4) { create(:item, name: "item4") }
7+
let!(:item5) { create(:item, :inactive, name: "item5") }
8+
9+
# Now create organization and associate items with it
10+
let(:organization) do
11+
org = create(:organization)
12+
[item1, item2, item3, item4, item5].each do |item|
13+
item.update!(organization_id: org.id)
14+
end
15+
org
16+
end
17+
18+
let(:sorted_item_names) do
19+
[item1, item2, item3, item4, item5].map(&:name).sort
20+
end
21+
22+
let(:storage_location) { create(:storage_location, organization: organization) }
23+
let(:user) { create(:user, organization: organization) }
24+
25+
around do |example|
26+
travel_to Time.zone.local(2024, 12, 25)
27+
example.run
28+
travel_back
29+
end
30+
31+
describe "#generate_csv_data" do
32+
subject { described_class.generate_csv(adjustments, organization) }
33+
34+
context "with multiple adjustments and items" do
35+
let(:adjustments) do
36+
[
37+
# 1st adjustment with 2 items
38+
create(:adjustment,
39+
user_id: user.id,
40+
storage_location: storage_location,
41+
organization: organization,
42+
comment: "adjustment 1",
43+
line_items_attributes: [
44+
{item_id: item1.id, quantity: 10},
45+
{item_id: item2.id, quantity: -5}
46+
]),
47+
48+
# 2nd adjustment with 1 item
49+
create(:adjustment,
50+
user_id: user.id,
51+
storage_location: storage_location,
52+
organization: organization,
53+
comment: "adjustment 2",
54+
line_items_attributes: [
55+
{item_id: item3.id, quantity: 3}
56+
]),
57+
58+
# 3rd adjustment with the :with_items trait
59+
create(:adjustment, :with_items,
60+
user_id: user.id,
61+
storage_location: storage_location,
62+
organization: organization,
63+
comment: "adjustment 3",
64+
item: item1,
65+
item_quantity: 7)
66+
]
67+
end
68+
69+
it "should include the correct adjustment data" do
70+
csv = <<~CSV
71+
Created date,Storage Area,Comment,# of changes,item1,item2,item3,item4,item5
72+
2024-12-25,Smithsonian Conservation Center,adjustment 1,2,10,-5,0,0,0
73+
2024-12-25,Smithsonian Conservation Center,adjustment 2,1,0,0,3,0,0
74+
2024-12-25,Smithsonian Conservation Center,adjustment 3,1,7,0,0,0,0
75+
CSV
76+
77+
expect(subject).to eq(csv)
78+
end
79+
end
80+
81+
context "when there are no adjustments" do
82+
let(:adjustments) { [] }
83+
84+
it "returns only headers row" do
85+
csv = <<~CSV
86+
Created date,Storage Area,Comment,# of changes,item1,item2,item3,item4,item5
87+
CSV
88+
89+
expect(subject).to eq(csv)
90+
end
91+
end
92+
end
93+
end

0 commit comments

Comments
 (0)