Skip to content

Commit 812a3b2

Browse files
committed
Transfers exports include quantity moved for each item
1 parent a1f82e7 commit 812a3b2

File tree

3 files changed

+125
-3
lines changed

3 files changed

+125
-3
lines changed

app/controllers/transfers_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ def index
1515
@to_storage_locations = StorageLocation.with_transfers_to(current_organization)
1616
respond_to do |format|
1717
format.html
18-
format.csv { send_data Exports::ExportTransfersCSVService.new(transfers: @transfers, organization: current_organization).generate_csv, filename: "Transfers-#{Time.zone.today}.csv" }
18+
format.csv { send_data Exports::ExportTransfersCSVService.new(transfers: @transfers.includes(line_items: :item), organization: current_organization).generate_csv, filename: "Transfers-#{Time.zone.today}.csv" }
1919
end
2020
end
2121

app/services/exports/export_transfers_csv_service.rb

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def generate_csv_data
2727
private
2828

2929
def headers
30-
base_headers
30+
base_headers + item_headers
3131
end
3232

3333
def base_table
@@ -51,8 +51,28 @@ def base_headers
5151
base_table.keys
5252
end
5353

54+
def item_headers
55+
@item_headers ||= @organization.items.select("DISTINCT ON (LOWER(name)) items.name").order("LOWER(name) ASC").map(&:name)
56+
end
57+
58+
def headers_with_indexes
59+
@headers_with_indexes ||= headers.each_with_index.to_h
60+
end
61+
5462
def build_row_data(transfer)
55-
base_table.values.map { |closure| closure.call(transfer) }
63+
row = base_table.values.map { |closure| closure.call(transfer) }
64+
65+
row += Array.new(item_headers.size, 0)
66+
67+
transfer.line_items.each do |line_item|
68+
item_name = line_item.item.name
69+
item_column_idx = headers_with_indexes[item_name]
70+
next unless item_column_idx
71+
72+
row[item_column_idx] += line_item.quantity
73+
end
74+
75+
row
5676
end
5777
end
5878
end
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
RSpec.describe Exports::ExportTransfersCSVService do
2+
let!(:organization) { create(:organization) }
3+
4+
describe "#generate_csv_data" do
5+
subject { described_class.new(transfers:, organization:).generate_csv_data }
6+
7+
let(:from_location) { create(:storage_location, name: "From Location") }
8+
let(:to_location) { create(:storage_location, name: "To Location") }
9+
let(:duplicate_item) { create(:item, name: "Dupe Item") }
10+
11+
let(:items_lists) do # Used to created four transfers
12+
[
13+
[
14+
[duplicate_item, 5],
15+
[create(:item), 7],
16+
[duplicate_item, 3]
17+
],
18+
19+
*(Array.new(3) do |i|
20+
[[create(:item), i + 1]]
21+
end)
22+
]
23+
end
24+
25+
let(:transfers) do
26+
items_lists.map do |items|
27+
transfer = create(:transfer, from: from_location, to: to_location)
28+
29+
items.each do |(item, quantity)|
30+
transfer.line_items << create(:line_item, quantity:, item:)
31+
end
32+
33+
transfer
34+
end
35+
end
36+
37+
let(:all_org_items) { organization.items.sort_by { |item| item.name.downcase } }
38+
39+
let(:total_item_quantities) do
40+
template = all_org_items.pluck(:name).index_with(0)
41+
42+
items_lists.map do |items_list|
43+
row = template.dup
44+
items_list.each do |(item, quantity)|
45+
row[item.name] += quantity
46+
end
47+
row.values
48+
end
49+
end
50+
51+
let(:non_item_headers) { ["From", "To", "Comment", "Total Moved"] }
52+
let(:expected_headers) { non_item_headers + all_org_items.pluck(:name) }
53+
54+
it "should match the expected content for the csv" do
55+
expect(subject[0]).to eq(expected_headers)
56+
57+
transfers.zip(total_item_quantities).each_with_index do |(transfer, total_item_quantity), idx|
58+
row = [
59+
transfer.from.name,
60+
transfer.to.name,
61+
transfer.comment,
62+
transfer.line_items.total
63+
]
64+
row += total_item_quantity
65+
66+
expect(subject[idx + 1]).to eq(row)
67+
end
68+
end
69+
70+
context "when a new item is added to the organization" do
71+
let!(:new_item) { create(:item, name: "New Item") }
72+
73+
it "should be included as the last column of the csv" do
74+
expect(subject[0]).to eq(expected_headers).and end_with(new_item.name)
75+
end
76+
77+
it "should have a quantity of 0 if this item isn't part of any transfer" do
78+
transfers.zip(total_item_quantities).each_with_index do |(transfer, total_item_quantity), idx|
79+
row = [
80+
transfer.from.name,
81+
transfer.to.name,
82+
transfer.comment,
83+
transfer.line_items.total
84+
]
85+
row += total_item_quantity
86+
87+
expect(subject[idx + 1]).to eq(row).and end_with(0)
88+
end
89+
end
90+
end
91+
92+
context "when there are no transfers but the report is requested" do
93+
let(:transfers) { Transfer.none }
94+
95+
it "returns a csv with only headers and no rows" do
96+
expect(subject.size).to eq(1)
97+
header_row = subject[0]
98+
expect(header_row).to eq(expected_headers)
99+
end
100+
end
101+
end
102+
end

0 commit comments

Comments
 (0)