# License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later # holy cow, this is confusing RSpec.shared_context :shared_rd_donation_value_context do include_context :shared_donation_charge_context let(:fake_uuid) {"53a6bc06-0789-11e8-bb3f-f34cac607737"} let(:valid_uuid) {'fcf61bac-078a-11e8-aa53-cba5bdb8dcdd'} let(:other_uuid) {'a713018c-078f-11e8-ae3b-bf5007844fea'} let(:source_token) {force_create(:source_token, tokenizable: card, expiration: Time.now + 1.day, max_uses: 1, token: valid_uuid) } let(:source_tokens) { (0..10).map { |i| force_create(:source_token, tokenizable: card, expiration: Time.now + 1.day, max_uses: 1, token: SecureRandom.uuid) } } let(:other_source_token) {force_create(:source_token, tokenizable: card_for_other_supporter, expiration: Time.now + 1.day, max_uses: 1, token: other_uuid)} let(:charge_amount) {100} let(:default_edit_token) {'7903e34c-10fe-11e8-9ead-d302c690bee4'} before(:each){ Event.any_instance.stub(:geocode).and_return([1,1]) } def generate_expected(donation_id, payment_id, charge_id, card, supporter, nonprofit, stripe_charge_id, data = {}) payment_stuff = {} payment_stuff[:card_id] = card.id if card.is_a? Card payment_stuff[:direct_debit_detail_id] = card.id if card.is_a? DirectDebitDetail payment_stuff[:provider] = card.is_a?(Card) ? 'credit_card' : 'sepa' payment_stuff[:fee] = card.is_a?(Card) ? 33 : 0 result = { donation: { id: donation_id, nonprofit_id: nonprofit.id, supporter_id: supporter.id, card_id: payment_stuff[:card_id], date: Time.now, created_at: Time.now, updated_at: Time.now, event_id: data[:event] ? event.id : nil, campaign_id: data[:campaign] ? campaign.id : nil, anonymous: nil, amount: charge_amount, comment: nil, category: nil, dedication: 'dedication', designation: 'designation', imported_at: nil, manual: nil, offsite: nil, recurring: nil, recurring_donation_id: nil, origin_url: nil, payment_id: nil, profile_id: nil, charge_id: nil, payment_provider: payment_stuff[:provider], queued_for_import_at: nil, direct_debit_detail_id: payment_stuff[:direct_debit_detail_id] }, }.with_indifferent_access unless (payment_id == nil) result[:activity] = {} result[:payment] = { date: Time.now, donation_id: donation_id, fee_total: -payment_stuff[:fee], gross_amount: 100, id: payment_id || 55555, kind: data[:recurring_donation] ? 'RecurringDonation' : 'Donation', net_amount: 100 - payment_stuff[:fee], nonprofit_id: nonprofit.id, refund_total: 0, supporter_id: supporter.id, towards: 'designation', created_at: Time.now, updated_at: Time.now, search_vectors: nil } result[:charge] = { id: charge_id || 55555, amount: charge_amount, card_id: payment_stuff[:card_id], created_at: Time.now, updated_at: Time.now, stripe_charge_id: stripe_charge_id, fee: payment_stuff[:fee], disbursed: nil, failure_message: nil, payment_id: payment_id || 55555, nonprofit_id: nonprofit.id, status: 'pending', profile_id: nil, supporter_id: supporter.id, ticket_id: nil, donation_id: donation_id, direct_debit_detail_id: payment_stuff[:direct_debit_detail_id] } end if (data[:recurring_donation]) result[:recurring_donation] = { id: data[:recurring_donation].id, active: true, paydate: data[:recurring_donation_expected][:paydate], interval: data[:recurring_donation_expected][:interval], time_unit: data[:recurring_donation_expected][:time_unit], start_date: data[:recurring_donation_expected][:start_date], end_date: nil, n_failures: 0, edit_token: default_edit_token, cancelled_by: nil, cancelled_at: nil, donation_id: donation_id, nonprofit_id: nonprofit.id, created_at: Time.now, updated_at: Time.now, failure_message: nil, origin_url: nil, amount: charge_amount, supporter_id: supporter.id, #removable fields card_id: nil, campaign_id: nil, anonymous: nil, email: supporter.email, profile_id: nil } end result end def generate_expected_refund(data={}) result = {}.with_indifferent_access result end def validation_unauthorized expect(QuerySourceToken).to receive(:get_and_increment_source_token).with(fake_uuid, nil).and_raise(AuthenticationError) expect {yield()}.to raise_error {|e| expect(e).to be_a(AuthenticationError) } end def validation_expired expect(QuerySourceToken).to receive(:get_and_increment_source_token).with(fake_uuid, nil).and_raise(ExpiredTokenError) expect {yield()}.to raise_error {|e| expect(e).to be_a(ExpiredTokenError) } end def validation_basic_validation expect {yield()}.to raise_error {|e| expect(e).to be_a(ParamValidation::ValidationError) expect(e.message).to start_with 'amount' expect_validation_errors(e.data, [ {key: :amount, name: :required}, {key: :amount, name: :is_integer}, {key: :nonprofit_id, name: :required}, {key: :nonprofit_id, name: :is_reference}, {key: :supporter_id, name: :required}, {key: :supporter_id, name: :is_reference}, {key: :designation, name: :is_a}, {key: :dedication, name: :is_a}, {key: :campaign_id, name: :is_reference}, {key: :event_id, name: :is_reference}, {key: :token, name: :required}, {key: :token, name: :format}, ]) } end def validation_invalid_token expect {yield()}.to raise_error {|e| expect(e).to be_a(ParamValidation::ValidationError) expect(e.message).to eq "#{fake_uuid} doesn't represent a valid source" } end def find_error_supporter expect {yield()}.to raise_error {|e| expect(e).to be_a ParamValidation::ValidationError expect_validation_errors(e.data, [{key: :supporter_id}]) } end def find_error_nonprofit expect {yield()}.to raise_error {|e| expect(e).to be_a ParamValidation::ValidationError expect_validation_errors(e.data, [{key: :nonprofit_id}]) } end def find_error_campaign expect {yield()}.to raise_error {|e| expect(e).to be_a ParamValidation::ValidationError expect_validation_errors(e.data, [{key: :campaign_id}]) } end def find_error_event expect {yield()}.to raise_error {|e| expect(e).to be_a ParamValidation::ValidationError expect_validation_errors(e.data, [{key: :event_id}]) } end def find_error_ticket expect {yield()}.to raise_error {|e| expect(e).to be_a ParamValidation::ValidationError expect_validation_errors(e.data, [{key: :ticket_id}]) } end def find_error_profile expect {yield()}.to raise_error {|e| expect(e).to be_a ParamValidation::ValidationError expect_validation_errors(e.data, [{key: :profile_id}]) } end def validation_supporter_deleted supporter supporter.deleted = true supporter.save! expect {yield}.to raise_error {|e| expect(e).to be_a ParamValidation::ValidationError expect(e.message).to include 'deleted' expect_validation_errors(e.data, [{key: :supporter_id}]) } end def validation_event_deleted event.deleted = true event.save! expect { yield }.to raise_error {|error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, [{key: :event_id}]) expect(error.message).to include 'deleted' expect(error.message).to include "Event #{event.id}" } end def validation_campaign_deleted campaign.deleted = true campaign.save! expect { yield }.to raise_error {|error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, [{key: :campaign_id}]) expect(error.message).to include 'deleted' expect(error.message).to include "Campaign #{campaign.id}" } end def validation_supporter_not_with_nonprofit expect {yield}.to raise_error {|e| expect(e).to be_a ParamValidation::ValidationError expect(e.message).to include 'Supporter' expect(e.message).to include 'does not belong to nonprofit' expect_validation_errors(e.data, [{key: :supporter_id}]) } end def validation_campaign_not_with_nonprofit expect {yield}.to raise_error {|e| expect(e).to be_a ParamValidation::ValidationError expect(e.message).to include 'Campaign' expect(e.message).to include 'does not belong to nonprofit' expect_validation_errors(e.data, [{key: :campaign_id}]) } end def validation_event_not_with_nonprofit expect {yield}.to raise_error {|e| expect(e).to be_a ParamValidation::ValidationError expect(e.message).to include 'Event' expect(e.message).to include 'does not belong to nonprofit' expect_validation_errors(e.data, [{key: :event_id}]) } end def validation_card_not_with_supporter expect {yield}.to raise_error {|e| expect(e).to be_a ParamValidation::ValidationError expect(e.message).to include 'Supporter' expect(e.message).to include 'does not own card' expect_validation_errors(e.data, [{key: :token}]) } end def handle_charge_failed failure_message = 'failure message' expect(InsertCharge).to receive(:with_stripe).and_return({'charge' => {'status' => 'failed', 'failure_message' => failure_message}}) expect {yield}.to raise_error {|e| expect(e).to be_a ChargeError expect(e.message).to eq failure_message expect(Donation.count).to eq 0 expect(Charge.count).to eq 0 expect(Activity.count).to eq 0 expect(Payment.count).to eq 0 } end def before_each_success(expect_charge = true) expect(InsertDonation).to receive(:insert_donation).and_wrap_original do |m, *args| result = m.call(*args); @donation_id = result.id expect_email_queued.with(JobTypes::NonprofitPaymentNotificationJob, @donation_id) expect_email_queued.with(JobTypes::DonorPaymentNotificationJob, @donation_id, supporter.locale) expect(QueueDonations).to receive(:execute_for_donation).with(@donation_id) result end if (expect_charge) 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! expect(Stripe::Charge).to receive(:create).and_wrap_original {|m, *args| a = m.call(*args); @stripe_charge_id = a['id'] a } end end def before_each_successful_refund() expect(InsertRefund).to receive(:with_stripe).and_wrap_original do |m, *args| result = m.call(*args); @all_refunds&.push(result) || @all_refunds = [result] @fifo_refunds&.unshift(result) || @fifo_refunds = [ result] result end expect(Stripe::Refund).to receive(:create).and_wrap_original do |m, *args| a = m.call(*args); @stripe_refund_ids&.unshift(a['id']) || @stripe_refund_ids = [a['id']]; a end end def before_each_sepa_success() expect(InsertDonation).to receive(:insert_donation).and_wrap_original do |m, *args| result = m.call(*args); @donation_id = result.id expect_email_queued.with(JobTypes::NonprofitPaymentNotificationJob, @donation_id) expect_email_queued.with(JobTypes::DonorDirectDebitNotificationJob, @donation_id, supporter.locale) expect(QueueDonations).to receive(:execute_for_donation).with(@donation_id) result end end def process_event_donation(data = {}) pay_method = data[:sepa] ? direct_debit_detail : card result = yield expected = generate_expected(@donation_id, result['payment'].id, result['charge'].id, pay_method, supporter, nonprofit, @stripe_charge_id, event: event, recurring_donation_expected: data[:recurring_donation], recurring_donation: result['recurring_donation']) expect(result.count).to eq expected.count expect(result['donation'].attributes).to eq expected[:donation] expect(result['charge'].attributes).to eq expected[:charge] #expect(result[:json]['activity']).to eq expected[:activity] expect(result['payment'].attributes).to eq expected[:payment] if (data[:recurring_donation]) expect(result['recurring_donation'].attributes).to eq expected[:recurring_donation] end return result end def process_campaign_donation(data = {}) pay_method = data[:sepa] ? direct_debit_detail : card result = yield expected = generate_expected(@donation_id, result['payment'].id, result['charge'].id, pay_method, supporter, nonprofit, @stripe_charge_id, campaign: campaign, recurring_donation_expected: data[:recurring_donation], recurring_donation: result['recurring_donation']) expect(result.count).to eq expected.count expect(result['donation'].attributes).to eq expected[:donation] expect(result['charge'].attributes).to eq expected[:charge] #expect(result[:json]['activity']).to eq expected[:activity] expect(result['payment'].attributes).to eq expected[:payment] if (data[:recurring_donation]) expect(result['recurring_donation'].attributes).to eq expected[:recurring_donation] end return result end def process_general_donation(data = {}) pay_method = data[:sepa] ? direct_debit_detail : card result = yield expect_payment = nil_or_true(data[:expect_payment]) expect_charge = nil_or_true(data[:expect_charge]) expected = generate_expected(@donation_id, nil_or_true(data[:expect_payment]) ? result['payment'].id : nil, nil_or_true(data[:expect_payment]) ? result['charge'].id : nil, pay_method, supporter, nonprofit, @stripe_charge_id, recurring_donation_expected: data[:recurring_donation], recurring_donation: result['recurring_donation']) expected['donation'].merge!(profile_id: profile.id) expect(result.count).to eq expected.count expect(result['donation'].attributes).to eq expected[:donation] if (expect_charge) expect(result['charge'].attributes).to eq expected[:charge] end #expect(result[:json]['activity']).to eq expected[:activity] if (expect_payment) expect(result['payment'].attributes).to eq expected[:payment] end if (data[:recurring_donation]) expect(result['recurring_donation'].attributes).to eq expected[:recurring_donation] end return result end def process_general_refund(data = {}) result = yield expected = generate_expected_refund() expect(result['payment']).to eq expected[:payment] expect(result['refund']).to eq expected[:refund] return result end def nil_or_true(item) item.nil? || item end end