-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
6411a78
commit bd90e69
Showing
14 changed files
with
243 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
class Admin::CsvUploadsController < ApplicationController | ||
expose(:csv_upload) | ||
|
||
def create | ||
if csv_upload.save | ||
ParseCsvUploadJob.perform_later(csv_upload.id) | ||
flash.notice = "CSV Upload successfully created" | ||
redirect_to admin_csv_upload_path(csv_upload) | ||
else | ||
flash.alert = csv_upload.errors.full_messages.join(",") | ||
redirect_to new_admin_csv_upload_path | ||
end | ||
end | ||
|
||
private | ||
|
||
def csv_upload_params | ||
safe_params = params.require(:csv_upload).permit(:parser_class_name) | ||
safe_params[:original_filename] = params[:file].original_filename | ||
safe_params[:data] = params[:file].read | ||
safe_params | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
class ParseCsvUploadJob < ApplicationJob | ||
def perform(csv_upload_id) | ||
csv_upload = CsvUpload.find_by(id: csv_upload_id) | ||
return unless csv_upload | ||
|
||
parser = csv_upload.parser_class_name.constantize | ||
parser.parse(csv_upload) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,11 @@ | ||
require "csv" | ||
|
||
class CsvUpload < ApplicationRecord | ||
validates_presence_of :data, :original_filename, :parser_class_name | ||
|
||
def parsed_data | ||
CSV.parse(data) | ||
rescue CSV::MalformedCSVError | ||
nil | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
class WellsFargoParser | ||
def self.parse(csv_upload) | ||
table = csv_upload.parsed_data | ||
return unless table | ||
|
||
wf_checking = FinancialAccount.wf_checking | ||
|
||
table.each do |row| | ||
amount_cents = (row[1].to_r * 100).to_i | ||
posted_on = Date.strptime(row[0], "%m/%d/%Y") | ||
|
||
attrs = { | ||
amount_cents: amount_cents, | ||
description: row[4], | ||
posted_on: posted_on | ||
} | ||
|
||
wf_checking.financial_transactions.create!(attrs) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
%h1 New CSV Upload | ||
|
||
= form_with model: [:admin, csv_upload], multipart: true do |form| | ||
%select#csv_upload_parser_class_name(name="csv_upload[parser_class_name]" required="true") | ||
%option(value="" disabled="true" selected hidden) pick parser | ||
%option(value="WellsFargoParser") WellsFargoParser | ||
%input#file_picker(required="true" type="file" name="file") | ||
= form.button "create" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
%h1 CSV Upload #{csv_upload.id} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
"12/29/2023","0.89","","","random fee" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
require "rails_helper" | ||
|
||
describe ParseCsvUploadJob do | ||
let(:parser_class_name) { "WellsFargoParser" } | ||
|
||
let(:csv_upload) do | ||
FactoryBot.create(:csv_upload, parser_class_name: parser_class_name) | ||
end | ||
|
||
let(:csv_upload_id) { csv_upload.id } | ||
|
||
context "with an invalid csv_upload_id" do | ||
let(:csv_upload_id) { "invalid" } | ||
|
||
it "exits early" do | ||
job = ParseCsvUploadJob.new | ||
expect do | ||
job.perform(csv_upload_id) | ||
end.to_not raise_error | ||
end | ||
end | ||
|
||
context "with a CsvUpload that has an invalid parser_class_name" do | ||
let(:parser_class_name) { "InvalidParser" } | ||
|
||
it "raises an error" do | ||
job = ParseCsvUploadJob.new | ||
expect do | ||
job.perform(csv_upload_id) | ||
end.to raise_error(NameError) | ||
end | ||
end | ||
|
||
context "with a valid CsvUpload" do | ||
it "calls the parser with that CsvUpload" do | ||
job = ParseCsvUploadJob.new | ||
expect(WellsFargoParser).to receive(:parse).with(csv_upload) | ||
job.perform(csv_upload_id) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
require "rails_helper" | ||
|
||
describe WellsFargoParser do | ||
describe ".parse" do | ||
let!(:wf_checking) { FactoryBot.create(:wf_checking) } | ||
let(:csv_upload) { FactoryBot.create(:csv_upload, data: data) } | ||
|
||
context "with nil parsed data" do | ||
let(:data) { '"invalid' } | ||
|
||
it "exits early" do | ||
expect do | ||
WellsFargoParser.parse(csv_upload) | ||
end.to_not raise_error | ||
end | ||
end | ||
|
||
context "with a properly formatted transaction" do | ||
let(:data) { "12/29/2023,-0.89,,,random fee" } | ||
|
||
it "creates a transaction for the Wells Fargo Checking account" do | ||
WellsFargoParser.parse(csv_upload) | ||
expect(wf_checking.financial_transactions.count).to eq 1 | ||
|
||
financial_transaction = wf_checking.financial_transactions.last | ||
expect(financial_transaction.amount_cents).to eq(-89) | ||
expect(financial_transaction.description).to eq "random fee" | ||
expect(financial_transaction.posted_on).to eq Date.parse("2023-12-29") | ||
end | ||
end | ||
|
||
context "with a few transactions" do | ||
let(:data) do | ||
<<~EOL | ||
12/01/2023,100.00,ignore,,check deposit | ||
12/07/2023,-77.77,,ignore,groceries | ||
12/29/2023,-0.89,,,random fee | ||
EOL | ||
end | ||
|
||
it "creates those transactions on the Wells Fargo Checking account" do | ||
WellsFargoParser.parse(csv_upload) | ||
|
||
ordered_transactions = wf_checking.financial_transactions.order(:posted_on) | ||
expect(ordered_transactions.count).to eq 3 | ||
|
||
amounts = ordered_transactions.pluck(:amount_cents) | ||
expect(amounts).to eq [100_00, -77_77, -89] | ||
|
||
dates = ordered_transactions.pluck(:posted_on) | ||
expect(dates.map(&:to_s)).to eq ["2023-12-01", "2023-12-07", "2023-12-29"] | ||
|
||
descriptions = ordered_transactions.pluck(:description) | ||
expect(descriptions).to eq [ | ||
"check deposit", | ||
"groceries", | ||
"random fee" | ||
] | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
require "rails_helper" | ||
|
||
describe "Admin creates CsvUpload" do | ||
include_context "admin password matches" | ||
|
||
scenario "without a parser" do | ||
visit "/admin/csv_uploads/new" | ||
click_on "create" | ||
expect(CsvUpload.count).to eq 0 | ||
select = page.find("#csv_upload_parser_class_name") | ||
error_message = select.native.attribute("validationMessage") | ||
expect(error_message).to eq "Please select an item in the list." | ||
end | ||
|
||
scenario "without a file" do | ||
visit "/admin/csv_uploads/new" | ||
select "WellsFargoParser", from: "csv_upload_parser_class_name" | ||
click_on "create" | ||
expect(CsvUpload.count).to eq 0 | ||
file_input = page.find("#file_picker") | ||
error_message = file_input.native.attribute("validationMessage") | ||
expect(error_message).to eq "Please select a file." | ||
end | ||
|
||
scenario "with an empty file" do | ||
visit "/admin/csv_uploads/new" | ||
select "WellsFargoParser", from: "csv_upload_parser_class_name" | ||
attach_file "file", "spec/csv_files/empty.csv" | ||
click_on "create" | ||
expect(CsvUpload.count).to eq 0 | ||
expect(page).to have_content "Data can't be blank" | ||
end | ||
|
||
scenario "with valid financial transactions" do | ||
visit "/admin/csv_uploads/new" | ||
select "WellsFargoParser", from: "csv_upload_parser_class_name" | ||
attach_file "file", "spec/csv_files/one_wf_transaction.csv" | ||
click_on "create" | ||
expect(page).to have_content "CSV Upload successfully created" | ||
csv_upload = CsvUpload.last | ||
expect(page).to have_content "CSV Upload #{csv_upload.id}" | ||
expect(ParseCsvUploadJob).to have_been_enqueued | ||
end | ||
end |