houdini/spec/lib/insert/insert_refunds_spec.rb

397 lines
12 KiB
Ruby
Raw Permalink Normal View History

# 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
require 'rails_helper'
describe InsertRefunds do
let!(:nonprofit) { create(:nm_justice) }
let!(:supporter) { create(:supporter, nonprofit: nonprofit) }
let!(:payment) do
force_create(
:payment,
gross_amount: 500,
net_amount: 500 + CalculateFees.for_single_amount(500),
fee_total: CalculateFees.for_single_amount(500),
date: Time.zone.now,
nonprofit: nonprofit,
supporter: supporter,
refund_total: 0
)
end
let!(:charge) do
create(
:charge,
payment: payment,
stripe_charge_id: 'ch_s0m3th1ng',
nonprofit: nonprofit,
supporter: supporter,
amount: 500
)
end
before do
trx = supporter.transactions.build(amount: 500)
trx.build_subtransaction(
subtransactable: StripeTransaction.new(amount: 500),
subtransaction_payments: [
build(:subtransaction_payment, paymentable: create(:stripe_charge, payment: payment))
]
)
trx.save!
trx
end
describe '.with_stripe' do
context 'when invalid' do
it 'raises an error with an invalid charge' do
charge.update(stripe_charge_id: 'xxx')
expect { described_class.with_stripe(charge, amount: 1) }.to raise_error(ParamValidation::ValidationError)
end
it 'sets a failure message an error with an invalid amount' do
charge.update(amount: 0)
expect { described_class.with_stripe(charge, amount: 0) }.to raise_error(ParamValidation::ValidationError)
end
it 'returns err if refund amount is greater than payment gross minus payment refund total' do
expect { described_class.with_stripe(charge, 'amount' => 600) }.to raise_error(RuntimeError)
end
end
context 'when valid' do
let(:result) { described_class.with_stripe(charge, 'amount' => 100) }
let(:retrieved_stripe_charge) { double }
let(:stripe_charge_refunds) { double }
let(:created_stripe_charge_refund) { double }
before do
allow(Stripe::Charge)
.to receive(:retrieve)
.with('ch_s0m3th1ng')
.and_return(retrieved_stripe_charge)
allow(retrieved_stripe_charge)
.to receive(:refunds)
.and_return(stripe_charge_refunds)
allow(stripe_charge_refunds)
.to receive(:create)
.with({ 'amount' => 100, 'refund_application_fee' => true, 'reverse_transfer' => true })
.and_return(created_stripe_charge_refund)
allow(created_stripe_charge_refund)
.to receive(:id)
.and_return('re_f@k3')
end
it 'sets the stripe refund id' do
expect(result['refund']['stripe_refund_id']).to match(/^re_/)
end
it 'creates a negative payment for the refund with the gross amount' do
expect(result['payment']['gross_amount']).to eq(-100)
end
it 'creates a negative payment for the refund with the net amount' do
expect(result['payment']['net_amount']).to eq(-109)
end
it 'updates the payment_id on the refund' do
expect(result['refund']['payment_id']).to eq(result['payment']['id'])
end
it 'increments the payment refund total by the gross amount' do
result
expect(payment.reload['refund_total']).to eq(100)
end
it 'sets the payment supporter id' do
expect(result['payment']['supporter_id']).to eq(supporter['id'])
end
describe 'event publishing' do
let(:event_publisher) { double }
let(:expected_event) do
{
'data' => {
'object' => {
'created' => kind_of(Numeric),
'fee_total' => {
'cents' => -9, 'currency' => nonprofit.currency
},
'gross_amount' => {
'cents' => -100, 'currency' => nonprofit.currency
},
'id' => match_houid('striperef'),
'stripe_id' => kind_of(String),
'net_amount' => {
'cents' => -109, 'currency' => nonprofit.currency
},
'nonprofit' => {
'id' => nonprofit.id,
'name' => nonprofit.name,
'object' => 'nonprofit'
},
'object' => 'stripe_transaction_refund',
'subtransaction' => {
'created' => kind_of(Numeric),
'id' => match_houid('stripetrx'),
'initial_amount' => {
'cents' => 500, 'currency' => nonprofit.currency
},
'net_amount' => {
'cents' => 432, 'currency' => nonprofit.currency
},
'nonprofit' => nonprofit.id,
'object' => 'stripe_transaction',
'payments' => [
{
'id' => match_houid('stripechrg'),
'object' => 'stripe_transaction_charge',
'type' => 'payment'
},
{
'id' => match_houid('striperef'),
'object' => 'stripe_transaction_refund',
'type' => 'payment'
}
],
'supporter' => supporter.id,
'transaction' => match_houid('trx'),
'type' => 'subtransaction'
},
'supporter' => {
'anonymous' => supporter.anonymous,
'deleted' => supporter.deleted,
'id' => supporter.id,
'merged_into' => supporter.merged_into,
'name' => supporter.name,
'nonprofit' => nonprofit.id,
'object' => 'supporter',
'organization' => supporter.organization,
'phone' => supporter.phone,
'supporter_addresses' => [kind_of(Numeric)]
},
'transaction' => {
'amount' => {
'cents' => 400, 'currency' => nonprofit.currency
},
'created' => kind_of(Numeric),
'id' => match_houid('trx'),
'nonprofit' => nonprofit.id,
'object' => 'transaction',
'subtransaction' => {
'id' => match_houid('stripetrx'),
'object' => 'stripe_transaction',
'type' => 'subtransaction'
},
'subtransaction_payments' => [
{
'id' => match_houid('stripechrg'),
'object' => 'stripe_transaction_charge',
'type' => 'payment'
}, {
'id' => match_houid('striperef'),
'object' => 'stripe_transaction_refund',
'type' => 'payment'
}
],
'supporter' => supporter.id,
'transaction_assignments' => []
},
'type' => 'payment'
}
},
'id' => match_houid('objevt'),
'object' => 'object_event',
'type' => 'event_type'
}
end
let(:expected_transaction_event) do
{
'data' => {
'object' => {
'amount' => {
'cents' => 400,
'currency' => nonprofit.currency
},
'created' => kind_of(Numeric),
'id' => match_houid('trx'),
'nonprofit' => {
'id' => nonprofit.id,
'name' => nonprofit.name,
'object' => 'nonprofit'
},
'object' => 'transaction',
'subtransaction' => {
'created' => kind_of(Numeric),
'id' => match_houid('stripetrx'),
'initial_amount' => {
'cents' => 500,
'currency' => nonprofit.currency
},
'net_amount' => {
'cents' => 432,
'currency' => nonprofit.currency
},
'nonprofit' => nonprofit.id,
'object' => 'stripe_transaction',
'payments' => [
{
'id' => match_houid('stripechrg'),
'object' => 'stripe_transaction_charge',
'type' => 'payment'
}, {
'id' => match_houid('striperef'),
'object' => 'stripe_transaction_refund',
'type' => 'payment'
}
],
'supporter' => supporter.id,
'transaction' => match_houid('trx'),
'type' => 'subtransaction'
},
'subtransaction_payments' => [
{
'created' => kind_of(Numeric),
'fee_total' => {
'cents' => 41,
'currency' => nonprofit.currency
},
'gross_amount' => {
'cents' => 500,
'currency' => nonprofit.currency
},
'id' => match_houid('stripechrg'),
'net_amount' => {
'cents' => 541,
'currency' => nonprofit.currency
},
'nonprofit' => nonprofit.id,
'object' => 'stripe_transaction_charge',
'stripe_id' => 'ch_s0m3th1ng',
'subtransaction' => {
'id' => match_houid('stripetrx'),
'object' => 'stripe_transaction',
'type' => 'subtransaction'
},
'supporter' => supporter.id,
'transaction' => match_houid('trx'),
'type' => 'payment'
}, {
'created' => kind_of(Numeric),
'fee_total' => {
'cents' => -9,
'currency' => nonprofit.currency
},
'gross_amount' => {
'cents' => -100,
'currency' => nonprofit.currency
},
'id' => match_houid('striperef'),
'net_amount' => {
'cents' => -109,
'currency' => nonprofit.currency
},
'nonprofit' => nonprofit.id,
'object' => 'stripe_transaction_refund',
'stripe_id' => 're_f@k3',
'subtransaction' => {
'id' => match_houid('stripetrx'),
'object' => 'stripe_transaction',
'type' => 'subtransaction'
},
'supporter' => supporter.id,
'transaction' => match_houid('trx'),
'type' => 'payment'
}
],
'supporter' => {
'anonymous' => false,
'deleted' => false,
'id' => supporter.id,
'merged_into' => nil,
'name' => supporter.name,
'nonprofit' => nonprofit.id,
'object' => 'supporter',
'organization' => nil,
'phone' => nil,
'supporter_addresses' => [kind_of(Numeric)]
},
'transaction_assignments' => []
}
},
'id' => match_houid('objevt'),
'object' => 'object_event',
'type' => 'transaction.updated'
}
end
before do
allow(Houdini)
.to receive(:event_publisher)
.and_return(event_publisher)
allow(event_publisher)
.to receive(:announce)
.with(:payment_created, anything)
allow(event_publisher)
.to receive(:announce)
.with(:stripe_transaction_refund_created, anything)
allow(event_publisher)
.to receive(:announce)
.with(:transaction_refunded, anything)
allow(event_publisher)
.to receive(:announce)
.with(:transaction_updated, anything)
allow(event_publisher)
.to receive(:announce)
.with(:create_refund, anything)
result
end
it 'publishes that a transaction was updated' do
expected_transaction_event['type'] = 'transaction.updated'
expect(event_publisher)
.to have_received(:announce)
.with(:transaction_updated, expected_transaction_event)
end
it 'publishes that a transaction was refunded' do
expected_transaction_event['type'] = 'transaction.refunded'
expect(event_publisher)
.to have_received(:announce)
.with(:transaction_refunded, expected_transaction_event)
end
it 'publishes that a stripe_transaction_refund was created' do
expected_event['type'] = 'stripe_transaction_refund.created'
expect(event_publisher)
.to have_received(:announce)
.with(:stripe_transaction_refund_created, expected_event)
end
it 'publishes that a payment was created' do
expected_event['type'] = 'payment.created'
expect(event_publisher)
.to have_received(:announce)
.with(:payment_created, expected_event)
end
it 'publishes that a refund was created' do
expect(event_publisher)
.to have_received(:announce)
.with(:create_refund, kind_of(Refund))
end
end
end
end
end