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'
|
|
|
|
|
2021-05-13 19:18:30 +00:00
|
|
|
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
|
2018-03-25 17:30:42 +00:00
|
|
|
end
|