houdini/spec/lib/insert/insert_charge_spec.rb
Bradley M. Kuhn 6772312ea7 Relicense all .rb files under new project license.
The primary license of the project is changing to:
  AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later

with some specific files to be licensed under the one of two licenses:
   CC0-1.0
   LGPL-3.0-or-later

This commit is one of the many steps to relicense the entire codebase.

Documentation granting permission for this relicensing (from all past
contributors who hold copyrights) is on file with Software Freedom
Conservancy, Inc.
2018-03-25 15:10:40 -04:00

534 lines
26 KiB
Ruby

# License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later
require 'rails_helper'
require 'stripe_mock'
describe InsertCharge do
include_context :shared_donation_charge_context
let!(:donation) {force_create(:donation, id: 555)}
describe '.with_stripe' do
before(:each){
Settings.payment_provider.stripe_connect = true
}
describe 'param validation' do
it 'does basic validation' do
expect { InsertCharge.with_stripe(nil) }.to(raise_error {|error|
expect(error).to be_a ParamValidation::ValidationError
expect_validation_errors(error.data,
[
{:key => :amount, :name => :required},
{:key => :amount, :name => :is_integer},
{:key => :amount, :name => :min},
{:key => :nonprofit_id, :name => :required},
{:key => :nonprofit_id, :name => :is_integer},
{:key => :supporter_id, :name => :required},
{:key => :supporter_id, :name => :is_integer},
{:key => :card_id, :name => :required},
{:key => :card_id, :name => :is_integer},
{:key => :statement, :name => :required},
{:key => :statement, :name => :not_blank}
])
})
end
it 'verify the amount minimum works' do
expect { InsertCharge.with_stripe({amount: -1}) }.to(raise_error {|error|
expect(error).to be_a ParamValidation::ValidationError
expect_validation_errors(error.data,
[
{:key => :amount, :name => :min},
{:key => :nonprofit_id, :name => :required},
{:key => :nonprofit_id, :name => :is_integer},
{:key => :supporter_id, :name => :required},
{:key => :supporter_id, :name => :is_integer},
{:key => :card_id, :name => :required},
{:key => :card_id, :name => :is_integer},
{:key => :statement, :name => :required},
{:key => :statement, :name => :not_blank}
])
})
end
it 'verify that we check for valid nonprofit' do
expect { InsertCharge.with_stripe({amount: 100,
:nonprofit_id => 5555,
:supporter_id => 5555,
:card_id => 5555,
:statement => 'our statement'}) }.to(raise_error {|error|
expect(error).to be_a ParamValidation::ValidationError
expect_validation_errors(error.data,
[
{:key => :nonprofit_id}
])
})
end
it 'verify that we check for valid supporter' do
expect { InsertCharge.with_stripe({amount: 100,
:nonprofit_id => nonprofit.id,
:supporter_id => 5555,
:card_id => 5555,
:statement => 'our statement'}) }.to(raise_error {|error|
expect(error).to be_a ParamValidation::ValidationError
expect_validation_errors(error.data,
[
{:key => :supporter_id}
])
})
end
it 'verify that we check for valid card' do
expect { InsertCharge.with_stripe({amount: 100,
:nonprofit_id => nonprofit.id,
:supporter_id => supporter.id,
:card_id => 5555,
:statement => 'our statement'}) }.to(raise_error {|error|
expect(error).to be_a ParamValidation::ValidationError
expect_validation_errors(error.data,
[
{:key => :card_id}
])
})
end
it 'verify that we check that the supporter belongs to the correct nonprofit' do
expect { InsertCharge.with_stripe({amount: 100,
:nonprofit_id => other_nonprofit.id,
:supporter_id => supporter.id,
:card_id => card.id,
:statement => 'our statement'}) }.to(raise_error {|error|
expect(error).to be_a ParamValidation::ValidationError
expect(error.message).to eq "#{supporter.id} does not belong to this nonprofit #{other_nonprofit.id}"
expect_validation_errors(error.data,
[
{:key => :supporter_id}
])
})
end
it 'verify that we check that the card belongs to the correct supporter' do
expect { InsertCharge.with_stripe({amount: 100,
:nonprofit_id => nonprofit.id,
:supporter_id => supporter.id,
:card_id => card_for_other_supporter.id,
:statement => 'our statement'}) }.to(raise_error {|error|
expect(error).to be_a ParamValidation::ValidationError
expect(error.message).to eq "#{card_for_other_supporter.id} does not belong to this supporter #{supporter.id}"
expect_validation_errors(error.data,
[
{:key => :card_id}
])
})
end
end
describe 'handle StripeAccount Find and Create failure' do
before(:each){
StripeMock.prepare_error(Stripe::StripeError.new("chaos"), :new_account)
}
it 'does it fail properly' do
expect{ InsertCharge.with_stripe(amount: 100,
:nonprofit_id => nonprofit.id,
:supporter_id => supporter.id,
:card_id => card.id,
:statement => 'our statement') }.to( raise_error{|error|
expect(error).to be_a Stripe::StripeError
})
expect(Charge).to_not be_exists
expect(Payment).to_not be_exists
end
end
describe 'charge when customer belongs to client' do
before(:each){
nonprofit.stripe_account_id = Stripe::Account.create()['id']
nonprofit.save!
card.stripe_customer_id = 'some other id'
card.save!
StripeMock.prepare_error(Stripe::StripeError.new("chaos"), :get_customer)
}
it 'handles card error' do
expect(Stripe::Charge).to receive(:create).with({application_fee: 33,
customer: card.stripe_customer_id,
amount: 100,
currency: 'usd',
description: 'our statement<> blah-no-way',
statement_descriptor: 'our statement blah-n',
metadata: nil
}, {stripe_account: nonprofit.stripe_account_id}).and_wrap_original{|m, *args| m.call(*args)}
StripeMock.prepare_card_error(:card_declined)
finished_result = InsertCharge.with_stripe(amount: 100,
:nonprofit_id => nonprofit.id,
:supporter_id => supporter.id,
:card_id => card.id,
:statement => 'our statement<> blah-no-way')
common_expected = {id: Charge.first.id, amount: 100, fee: 33, stripe_charge_id: nil, status: 'failed', failure_message: 'There was an error with your card: The card was declined', created_at: Time.now, updated_at: Time.now, disbursed: nil}
result_expected = common_expected.merge({card_id: card.id, nonprofit_id: nonprofit.id, donation_id: nil, supporter_id: supporter.id, ticket_id: nil, payment_id: nil, profile_id: nil, direct_debit_detail_id: nil}).with_indifferent_access
expect(finished_result['charge'].attributes).to eq result_expected
expect(Charge.first.attributes).to eq result_expected
expect(Payment).to_not be_exists
end
it 'handles general Stripe error' do
expect(Stripe::Charge).to receive(:create).with({application_fee: 33,
customer: card.stripe_customer_id,
amount: 100,
currency: 'usd',
description: 'our statement<> blah-no-way',
statement_descriptor: 'our statement blah-n',
metadata: nil
}, {stripe_account: nonprofit.stripe_account_id}).and_wrap_original{|m, *args| m.call(*args)}
StripeMock.prepare_error(Stripe::StripeError.new("blah"), :new_charge)
finished_result = InsertCharge.with_stripe(amount: 100,
:nonprofit_id => nonprofit.id,
:supporter_id => supporter.id,
:card_id => card.id,
:statement => 'our statement<> blah-no-way')
common_expected = {id: Charge.first.id, amount: 100, fee: 33, stripe_charge_id: nil, status: 'failed', failure_message: "We're sorry, but something went wrong. We've been notified about this issue.", created_at: Time.now, updated_at: Time.now, disbursed: nil}
result_expected = common_expected.merge({card_id: card.id, nonprofit_id: nonprofit.id, donation_id: nil, supporter_id: supporter.id, ticket_id: nil, payment_id: nil, profile_id: nil, direct_debit_detail_id: nil}).with_indifferent_access
expect(finished_result['charge'].attributes).to eq result_expected
expect(Charge.first.attributes).to eq result_expected
expect(Payment).to_not be_exists
end
describe 'input success' do
let(:valid_input) { {amount: 100,
:nonprofit_id => nonprofit.id,
:supporter_id => supporter.id,
:card_id => card.id,
:donation_id => 555,
:towards => 'blah',
:kind => 'kind',
:statement => 'our statement<> blah-no-way'} }
let (:date) { Time.new(2002,10,31)}
let(:valid_input_with_date) { valid_input.merge(:date => date)}
it 'saves the payment and updates the charge' do
stripe_charge_id = nil
expect(Stripe::Charge).to receive(:create).with({application_fee: 33,
customer: card.stripe_customer_id,
amount: 100,
currency: 'usd',
description: 'our statement<> blah-no-way',
statement_descriptor: 'our statement blah-n',
metadata: nil
}, {stripe_account: nonprofit.stripe_account_id}).and_wrap_original{|m, *args| a= m.call(*args);
stripe_charge_id = a['id']
a}
finished_result = InsertCharge.with_stripe(valid_input)
common_charge_expected = {id: Charge.first.id, amount: 100, fee: 33, stripe_charge_id:stripe_charge_id, status: 'pending', failure_message: nil, created_at: Time.now, updated_at: Time.now, disbursed: nil}
result_charge_expected = common_charge_expected.merge({card_id: card.id, nonprofit_id: nonprofit.id, donation_id: 555, supporter_id: supporter.id, ticket_id: nil, payment_id: Payment.first.id, profile_id: nil, direct_debit_detail_id: nil}).with_indifferent_access
expect(finished_result['charge'].attributes).to eq result_charge_expected
expect(Charge.first.attributes).to eq result_charge_expected
expect(Charge.count).to eq 1
common_payment_expected = {id: Payment.first.id,
gross_amount: 100,
fee_total: -33,
net_amount: 67,
towards: 'blah',
kind: 'kind',
donation_id: 555,
nonprofit_id: nonprofit.id,
supporter_id: supporter.id,
refund_total: 0,
date: Time.now,
created_at: Time.now,
updated_at: Time.now,
search_vectors: nil
}.with_indifferent_access
expect(finished_result['payment'].attributes).to eq common_payment_expected
expect(Payment.first.attributes).to eq common_payment_expected
expect(Payment.count).to eq 1
end
it 'saves the payment and updates the charge with passed date' do
stripe_charge_id = nil
expect(Stripe::Charge).to receive(:create).with({application_fee: 33,
customer: card.stripe_customer_id,
amount: 100,
currency: 'usd',
description: 'our statement<> blah-no-way',
statement_descriptor: 'our statement blah-n',
metadata: nil
}, {stripe_account: nonprofit.stripe_account_id}).and_wrap_original{|m, *args| a= m.call(*args);
stripe_charge_id = a['id']
a}
finished_result = InsertCharge.with_stripe(valid_input_with_date)
common_charge_expected = {id: Charge.first.id, amount: 100, fee: 33, stripe_charge_id:stripe_charge_id, status: 'pending', failure_message: nil, created_at: Time.now, updated_at: Time.now, disbursed: nil}
result_charge_expected = common_charge_expected.merge({card_id: card.id, nonprofit_id: nonprofit.id, donation_id: 555, supporter_id: supporter.id, ticket_id: nil, payment_id: Payment.first.id, profile_id: nil, direct_debit_detail_id: nil}).with_indifferent_access
expect(finished_result['charge'].attributes).to eq result_charge_expected
expect(Charge.first.attributes).to eq result_charge_expected
expect(Charge.count).to eq 1
common_payment_expected = {id: Payment.first.id,
gross_amount: 100,
fee_total: -33,
net_amount: 67,
towards: 'blah',
kind: 'kind',
donation_id: 555,
nonprofit_id: nonprofit.id,
supporter_id: supporter.id,
refund_total: 0,
date: date,
created_at: Time.now,
updated_at: Time.now,
search_vectors: nil
}.with_indifferent_access
expect(finished_result['payment'].attributes).to eq common_payment_expected
expect(Payment.first.attributes).to eq common_payment_expected
expect(Payment.count).to eq 1
end
end
end
describe 'charge when customer belongs to us' do
before(:each){
nonprofit.stripe_account_id = Stripe::Account.create()['id']
nonprofit.save!
card.stripe_customer_id = 'some other id'
cust = Stripe::Customer.create()
card.stripe_customer_id = cust['id']
card.save!
new_cust = Stripe::Customer.create()
card_for_other_supporter.stripe_customer_id = new_cust['id']
card_for_other_supporter.save!
# StripeMock.prepare_error(Stripe::StripeError.new("chaos"), :get_customer)
}
def create_expected_charge_args(expected_card)
[{application_fee: 33,
customer: expected_card.stripe_customer_id,
amount: 100,
currency: 'usd',
description: 'our statement<> blah-no-way',
statement_descriptor: 'our statement blah-n',
metadata: nil,
destination: nonprofit.stripe_account_id
}, {}]
end
it 'handles card error' do
expect(Stripe::Charge).to receive(:create).with(*create_expected_charge_args(card)).and_wrap_original{|m, *args| m.call(*args)}
StripeMock.prepare_card_error(:card_declined)
finished_result = InsertCharge.with_stripe(amount: 100,
:nonprofit_id => nonprofit.id,
:supporter_id => supporter.id,
:card_id => card.id,
:statement => 'our statement<> blah-no-way')
common_expected = {id: Charge.first.id, amount: 100, fee: 33, stripe_charge_id: nil, status: 'failed', failure_message: 'There was an error with your card: The card was declined', created_at: Time.now, updated_at: Time.now, disbursed: nil}
result_expected = common_expected.merge({card_id: card.id, nonprofit_id: nonprofit.id, donation_id: nil, supporter_id: supporter.id, ticket_id: nil, payment_id: nil, profile_id: nil, direct_debit_detail_id: nil}).with_indifferent_access
expect(finished_result['charge'].attributes).to eq result_expected
expect(Charge.first.attributes).to eq result_expected
expect(Payment).to_not be_exists
end
it 'handles general Stripe error' do
expect(Stripe::Charge).to receive(:create).with(*create_expected_charge_args(card)).and_wrap_original{|m, *args| m.call(*args)}
StripeMock.prepare_error(Stripe::StripeError.new("blah"), :new_charge)
finished_result = InsertCharge.with_stripe(amount: 100,
:nonprofit_id => nonprofit.id,
:supporter_id => supporter.id,
:card_id => card.id,
:statement => 'our statement<> blah-no-way')
common_expected = {id: Charge.first.id, amount: 100, fee: 33, stripe_charge_id: nil, status: 'failed', failure_message: "We're sorry, but something went wrong. We've been notified about this issue.", created_at: Time.now, updated_at: Time.now, disbursed: nil}
result_expected = common_expected.merge({card_id: card.id, nonprofit_id: nonprofit.id, donation_id: nil, supporter_id: supporter.id, ticket_id: nil, payment_id: nil, profile_id: nil, direct_debit_detail_id: nil}).with_indifferent_access
expect(finished_result['charge'].attributes).to eq result_expected
expect(Charge.first.attributes).to eq result_expected
expect(Payment).to_not be_exists
end
describe 'input success' do
let (:date) { Time.new(2002,10,31)}
it 'saves the payment and updates the charge' do
saves_the_payment_updates_the_charge(card)
end
it 'saves the payment and updates the charge, if old rd and using wrong card' do
saves_the_payment_updates_the_charge(card_for_other_supporter, true)
end
it 'saves the payment and updates the charge with passed date' do
saves_the_payment_and_updates_the_charge_with_passed_date(card)
end
it 'saves the payment and updates the charge with passed date, if old rd and using wrong card' do
saves_the_payment_and_updates_the_charge_with_passed_date(card, true)
end
def insert_charge_input(expected_card, pass_old_donation=nil, pass_date=nil)
inner = {amount: 100,
:nonprofit_id => nonprofit.id,
:supporter_id => supporter.id,
card_id: expected_card.id,
:donation_id => 555,
:towards => 'blah',
:kind => 'kind',
:statement => 'our statement<> blah-no-way',
}
if pass_old_donation
inner = inner.merge(old_donation: true)
end
if pass_date
inner = inner.merge(date: date)
end
inner
end
def saves_the_payment_updates_the_charge(expected_card, pass_old_donation=nil)
stripe_charge_id = nil
expect(Stripe::Charge).to receive(:create).with(*create_expected_charge_args(expected_card)).and_wrap_original{|m, *args| a= m.call(*args);
stripe_charge_id = a['id']
a}
finished_result = InsertCharge.with_stripe(insert_charge_input(expected_card, pass_old_donation))
common_charge_expected = {id: Charge.first.id, amount: 100, fee: 33, stripe_charge_id:stripe_charge_id, status: 'pending', failure_message: nil, created_at: Time.now, updated_at: Time.now, disbursed: nil}
result_charge_expected = common_charge_expected.merge({card_id: expected_card.id, nonprofit_id: nonprofit.id, donation_id: 555, supporter_id: supporter.id, ticket_id: nil, payment_id: Payment.first.id, profile_id: nil, direct_debit_detail_id: nil}).with_indifferent_access
expect(finished_result['charge'].attributes).to eq result_charge_expected
expect(Charge.first.attributes).to eq result_charge_expected
expect(Charge.count).to eq 1
common_payment_expected = {id: Payment.first.id,
gross_amount: 100,
fee_total: -33,
net_amount: 67,
towards: 'blah',
kind: 'kind',
donation_id: 555,
nonprofit_id: nonprofit.id,
supporter_id: supporter.id,
refund_total: 0,
date: Time.now,
created_at: Time.now,
updated_at: Time.now,
search_vectors: nil
}.with_indifferent_access
expect(finished_result['payment'].attributes).to eq common_payment_expected
expect(Payment.first.attributes).to eq common_payment_expected
expect(Payment.count).to eq 1
end
def saves_the_payment_and_updates_the_charge_with_passed_date(expected_card, pass_old_donation=nil)
stripe_charge_id = nil
expect(Stripe::Charge).to receive(:create).with(*create_expected_charge_args(expected_card)).and_wrap_original{|m, *args| a= m.call(*args);
stripe_charge_id = a['id']
a}
finished_result = InsertCharge.with_stripe(insert_charge_input(expected_card, pass_old_donation, true))
common_charge_expected = {id: Charge.first.id, amount: 100, fee: 33, stripe_charge_id:stripe_charge_id, status: 'pending', failure_message: nil, created_at: Time.now, updated_at: Time.now, disbursed: nil}
result_charge_expected = common_charge_expected.merge({card_id: card.id, nonprofit_id: nonprofit.id, donation_id: 555, supporter_id: supporter.id, ticket_id: nil, payment_id: Payment.first.id, profile_id: nil, direct_debit_detail_id: nil}).with_indifferent_access
expect(finished_result['charge'].attributes).to eq result_charge_expected
expect(Charge.first.attributes).to eq result_charge_expected
expect(Charge.count).to eq 1
common_payment_expected = {id: Payment.first.id,
gross_amount: 100,
fee_total: -33,
net_amount: 67,
towards: 'blah',
kind: 'kind',
donation_id: 555,
nonprofit_id: nonprofit.id,
supporter_id: supporter.id,
refund_total: 0,
date: date,
created_at: Time.now,
updated_at: Time.now,
search_vectors: nil
}.with_indifferent_access
expect(finished_result['payment'].attributes).to eq common_payment_expected
expect(Payment.first.attributes).to eq common_payment_expected
expect(Payment.count).to eq 1
end
end
end
end
end