2019-07-30 21:29:24 +00:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2020-06-12 20:03:43 +00:00
|
|
|
# License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later
|
|
|
|
# Full license explanation at https://github.com/houdiniproject/houdini/blob/master/LICENSE
|
2018-03-25 17:30:42 +00:00
|
|
|
require 'rails_helper'
|
2020-05-08 21:19:35 +00:00
|
|
|
require 'support/test_upload_service'
|
2018-03-25 17:30:42 +00:00
|
|
|
|
|
|
|
describe ExportPayments do
|
|
|
|
before(:each) do
|
2020-05-08 21:19:35 +00:00
|
|
|
stub_const('CHUNKED_UPLOAD_SERVICE', TestUploadService.new)
|
2018-03-25 17:30:42 +00:00
|
|
|
end
|
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
let(:email) { 'example@example.com' }
|
|
|
|
let(:user) { force_create(:user, email: email) }
|
2020-04-16 20:50:03 +00:00
|
|
|
let(:nonprofit) { force_create(:nm_justice) }
|
2019-07-30 21:29:24 +00:00
|
|
|
let(:supporters) do
|
|
|
|
[force_create(:supporter, name: 'supporter-0', nonprofit: nonprofit),
|
|
|
|
force_create(:supporter, name: 'supporter-1', nonprofit: nonprofit)]
|
|
|
|
end
|
|
|
|
let(:payments) do
|
|
|
|
[force_create(:payment, gross_amount: 1000, fee_total: 99, net_amount: 901, supporter: supporters[0], nonprofit: nonprofit),
|
|
|
|
force_create(:payment, gross_amount: 2000, fee_total: 22, net_amount: 1978, supporter: supporters[1], nonprofit: nonprofit)]
|
|
|
|
end
|
|
|
|
|
2020-05-08 21:47:39 +00:00
|
|
|
let(:export_url_regex) { /http:\/\/fake\.url\/tmp\/csv-exports\/payments-04-06-2020--01-02-03-#{UUID::Regex}\.csv/}
|
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
before(:each) do
|
|
|
|
payments
|
|
|
|
end
|
2018-03-25 17:30:42 +00:00
|
|
|
context '.initiate_export' do
|
|
|
|
context 'param verification' do
|
|
|
|
it 'performs initial verification' do
|
|
|
|
expect { ExportPayments.initiate_export(nil, nil, nil) }.to(raise_error do |error|
|
|
|
|
expect(error).to be_a(ParamValidation::ValidationError)
|
|
|
|
expect(error.data.length).to eq(6)
|
|
|
|
expect_validation_errors(error.data, [{ key: 'npo_id', name: :required },
|
|
|
|
{ key: 'npo_id', name: :is_integer },
|
|
|
|
{ key: 'user_id', name: :required },
|
|
|
|
{ key: 'user_id', name: :is_integer },
|
|
|
|
{ key: 'params', name: :required },
|
|
|
|
{ key: 'params', name: :is_hash }])
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'nonprofit doesnt exist' do
|
|
|
|
fake_npo = 8_888_881
|
|
|
|
expect { ExportPayments.initiate_export(fake_npo, {}, 8_888_883) }.to(raise_error do |error|
|
|
|
|
expect(error).to be_a(ParamValidation::ValidationError)
|
|
|
|
expect(error.message).to eq "Nonprofit #{fake_npo} doesn't exist!"
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'user doesnt exist' do
|
|
|
|
fake_user = 8_888_883
|
|
|
|
expect { ExportPayments.initiate_export(nonprofit.id, {}, fake_user) }.to(raise_error do |error|
|
|
|
|
expect(error).to be_a(ParamValidation::ValidationError)
|
|
|
|
expect(error.message).to eq "User #{fake_user} doesn't exist!"
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'creates an export object and schedules job' do
|
|
|
|
Timecop.freeze(2020, 4, 5) do
|
2019-07-30 21:29:24 +00:00
|
|
|
params = { param1: 'pp' }.with_indifferent_access
|
2019-11-07 23:11:56 +00:00
|
|
|
expect{
|
|
|
|
ExportPayments.initiate_export(nonprofit.id, params, user.id)
|
|
|
|
}.to have_enqueued_job(PaymentExportCreateJob)
|
|
|
|
|
2018-03-25 17:30:42 +00:00
|
|
|
export = Export.first
|
2019-03-21 18:06:04 +00:00
|
|
|
expected_export = { id: export.id,
|
2018-03-25 17:30:42 +00:00
|
|
|
user_id: user.id,
|
|
|
|
nonprofit_id: nonprofit.id,
|
|
|
|
status: 'queued',
|
|
|
|
export_type: 'ExportPayments',
|
|
|
|
parameters: params.to_json,
|
|
|
|
updated_at: Time.now,
|
|
|
|
created_at: Time.now,
|
|
|
|
url: nil,
|
|
|
|
ended: nil,
|
|
|
|
exception: nil }.with_indifferent_access
|
|
|
|
expect(export.attributes).to eq(expected_export)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
context '.run_export' do
|
|
|
|
context 'param validation' do
|
|
|
|
it 'rejects basic invalid data' do
|
|
|
|
expect { ExportPayments.run_export(nil, nil, nil, nil) }.to(raise_error do |error|
|
|
|
|
expect(error).to be_a(ParamValidation::ValidationError)
|
|
|
|
expect_validation_errors(error, [{ key: 'npo_id', name: :required },
|
|
|
|
{ key: 'npo_id', name: :is_integer },
|
|
|
|
{ key: 'user_id', name: :required },
|
|
|
|
{ key: 'user_id', name: :is_integer },
|
|
|
|
{ key: 'params', name: :required },
|
|
|
|
{ key: 'params', name: :is_json },
|
|
|
|
{ key: 'export_id', name: :required },
|
|
|
|
{ key: 'export_id', name: :is_integer }])
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'rejects json which isnt a hash' do
|
|
|
|
expect { ExportPayments.run_export(1, [{ item: '' }, { item: '' }].to_json, 1, 1) }.to(raise_error do |error|
|
|
|
|
expect(error).to be_a(ParamValidation::ValidationError)
|
|
|
|
expect_validation_errors(error, [
|
|
|
|
{ key: :params, name: :is_hash }
|
|
|
|
])
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'no export throw an exception' do
|
|
|
|
expect { ExportPayments.run_export(0, { x: 1 }.to_json, 0, 11_111) }.to(raise_error do |error|
|
|
|
|
expect(error).to be_a ParamValidation::ValidationError
|
|
|
|
expect(error.data[:key]).to eq :export_id
|
|
|
|
expect(error.message).to start_with('Export')
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'no nonprofit' do
|
|
|
|
Timecop.freeze(2020, 4, 5) do
|
|
|
|
@export = force_create(:export, user: user)
|
|
|
|
Timecop.freeze(2020, 4, 6) do
|
|
|
|
expect { ExportPayments.run_export(0, { x: 1 }.to_json, user.id, @export.id) }.to(raise_error do |error|
|
|
|
|
expect(error).to be_a ParamValidation::ValidationError
|
|
|
|
expect(error.data[:key]).to eq :npo_id
|
|
|
|
expect(error.message).to start_with('Nonprofit')
|
|
|
|
|
|
|
|
@export.reload
|
|
|
|
expect(@export.status).to eq 'failed'
|
|
|
|
expect(@export.exception).to eq error.to_s
|
|
|
|
expect(@export.ended).to eq Time.now
|
|
|
|
expect(@export.updated_at).to eq Time.now
|
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
# expect(user).to have_received_email(subject: "Your payment export has failed")
|
2018-03-25 17:30:42 +00:00
|
|
|
end)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'no user' do
|
|
|
|
Timecop.freeze(2020, 4, 5) do
|
|
|
|
@export = force_create(:export, user: user)
|
|
|
|
Timecop.freeze(2020, 4, 6) do
|
|
|
|
expect { ExportPayments.run_export(nonprofit.id, { x: 1 }.to_json, 0, @export.id) }.to(raise_error do |error|
|
|
|
|
expect(error).to be_a ParamValidation::ValidationError
|
|
|
|
expect(error.data[:key]).to eq :user_id
|
|
|
|
expect(error.message).to start_with('User')
|
|
|
|
|
|
|
|
@export.reload
|
|
|
|
expect(@export.status).to eq 'failed'
|
|
|
|
expect(@export.exception).to eq error.to_s
|
|
|
|
expect(@export.ended).to eq Time.now
|
|
|
|
expect(@export.updated_at).to eq Time.now
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'handles exception in upload properly' do
|
|
|
|
Timecop.freeze(2020, 4, 5) do
|
|
|
|
@export = force_create(:export, user: user)
|
2020-05-08 21:19:35 +00:00
|
|
|
CHUNKED_UPLOAD_SERVICE.raise_error
|
2018-03-25 17:30:42 +00:00
|
|
|
Timecop.freeze(2020, 4, 6) do
|
|
|
|
expect { ExportPayments.run_export(nonprofit.id, {}.to_json, user.id, @export.id) }.to(raise_error do |error|
|
|
|
|
expect(error).to be_a StandardError
|
2020-05-08 21:19:35 +00:00
|
|
|
expect(error.message).to eq TestUploadService::TEST_ERROR_MESSAGE
|
2018-03-25 17:30:42 +00:00
|
|
|
|
|
|
|
@export.reload
|
|
|
|
expect(@export.status).to eq 'failed'
|
|
|
|
expect(@export.exception).to eq error.to_s
|
|
|
|
expect(@export.ended).to eq Time.now
|
|
|
|
expect(@export.updated_at).to eq Time.now
|
|
|
|
end)
|
2019-11-08 20:03:09 +00:00
|
|
|
expect(ExportPaymentsFailedJob).to have_been_enqueued.with(@export)
|
2018-03-25 17:30:42 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'uploads as expected' do
|
|
|
|
Timecop.freeze(2020, 4, 5) do
|
|
|
|
@export = create(:export, user: user, created_at: Time.now, updated_at: Time.now)
|
|
|
|
Timecop.freeze(2020, 4, 6, 1, 2, 3) do
|
|
|
|
ExportPayments.run_export(nonprofit.id, {}.to_json, user.id, @export.id)
|
2019-11-08 20:03:09 +00:00
|
|
|
expect(ExportPaymentsCompletedJob).to have_been_enqueued.with(@export)
|
2018-03-25 17:30:42 +00:00
|
|
|
@export.reload
|
|
|
|
|
2020-05-08 21:47:39 +00:00
|
|
|
expect(@export.url).to match export_url_regex
|
2018-03-25 17:30:42 +00:00
|
|
|
expect(@export.status).to eq 'completed'
|
|
|
|
expect(@export.exception).to be_nil
|
|
|
|
expect(@export.ended).to eq Time.now
|
|
|
|
expect(@export.updated_at).to eq Time.now
|
2020-05-08 21:19:35 +00:00
|
|
|
csv = CSV.parse(CHUNKED_UPLOAD_SERVICE.output)
|
2019-07-30 21:29:24 +00:00
|
|
|
expect(csv.length).to eq 3
|
2018-03-25 17:30:42 +00:00
|
|
|
|
|
|
|
expect(csv[0]).to eq MockHelpers.payment_export_headers
|
|
|
|
|
2020-05-08 21:19:35 +00:00
|
|
|
expect(CHUNKED_UPLOAD_SERVICE.options[:content_type]).to eq 'text/csv'
|
|
|
|
expect(CHUNKED_UPLOAD_SERVICE.options[:content_disposition]).to eq 'attachment'
|
2018-03-25 17:30:42 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|