donation.* event publishing

This commit is contained in:
Eric Schultz 2021-02-08 14:55:31 -06:00 committed by Eric Schultz
parent a401f4bea4
commit 6ab7473ef7
18 changed files with 304 additions and 22 deletions

View file

@ -45,5 +45,7 @@ class Donation < ApplicationRecord
belongs_to :campaign
belongs_to :event
has_one :modern_donation, inverse_of: :legacy_donation
scope :anonymous, -> { where(anonymous: true) }
end

View file

@ -0,0 +1,55 @@
# frozen_string_literal: true
# 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
class ModernDonation < ApplicationRecord
include Model::Houidable
include Model::Jbuilder
include Model::Eventable
setup_houid :don
# TODO must associate with events and campaigns somehow
add_builder_expansion :nonprofit, :supporter
add_builder_expansion :trx,
json_attrib: :transaction
has_one :transaction_assignment, as: :assignable
has_one :trx, through: :transaction_assignment
has_one :supporter, through: :trx
has_one :nonprofit, through: :supporter
belongs_to :legacy_donation, class_name: 'Donation', foreign_key: :donation_id, inverse_of: :modern_donation
delegate :designation, :dedication, to: :legacy_donation
def to_builder(*expand)
init_builder(*expand) do |json|
json.(self, :id, :designation)
json.object 'donation'
json.dedication do
json.type dedication['type']
json.name dedication['name']
contact = dedication['contact']
json.contact do
json.email contact['email'] if contact['email']
json.address contact['address'] if contact['address']
json.phone contact['phone'] if contact['phone']
end if contact
end if dedication
# TODO the line above is a hacky solution
json.amount do
json.value_in_cents amount
json.currency nonprofit.currency
end
end
end
def publish_created
Houdini.event_publisher.announce(:donation_created, to_event('donation.created', :nonprofit, :supporter, :trx).attributes!)
end
def publish_updated
Houdini.event_publisher.announce(:donation_updated, to_event('donation.updated', :nonprofit, :supporter, :trx).attributes!)
end
end

View file

@ -15,6 +15,7 @@ class Transaction < ApplicationRecord
has_many :transaction_assignments
has_many :donations, through: :transaction_assignments, source: :assignable, source_type: 'ModernDonation'
has_many :ticket_purchases, through: :transaction_assignments, source: :assignable, source_type: 'TicketPurchase'
validates :supporter, presence: true

View file

@ -0,0 +1,10 @@
class CreateModernDonations < ActiveRecord::Migration[6.1]
def change
create_table :modern_donations, id: :string do |t|
t.integer :amount
t.references :donation
t.timestamps
end
end
end

View file

@ -0,0 +1,17 @@
# frozen_string_literal: true
# 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
class ConvertDonationDedicationToJsonb < ActiveRecord::Migration[6.1]
def up
execute <<-SQL
ALTER TABLE "donations" ALTER COLUMN "dedication" TYPE jsonb USING dedication::jsonb
SQL
end
def down
execute <<-SQL
ALTER TABLE "donations" ALTER COLUMN "dedication" TYPE text USING dedication::text
SQL
end
end

View file

@ -848,7 +848,7 @@ CREATE TABLE public.donations (
recurring_donation_id integer,
comment text,
recurring boolean,
dedication text,
dedication jsonb,
event_id integer,
imported_at timestamp without time zone,
charge_id integer,
@ -1436,6 +1436,19 @@ CREATE SEQUENCE public.miscellaneous_np_infos_id_seq
ALTER SEQUENCE public.miscellaneous_np_infos_id_seq OWNED BY public.miscellaneous_np_infos.id;
--
-- Name: modern_donations; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.modern_donations (
id character varying NOT NULL,
amount integer,
donation_id bigint,
created_at timestamp(6) without time zone NOT NULL,
updated_at timestamp(6) without time zone NOT NULL
);
--
-- Name: nonprofit_keys; Type: TABLE; Schema: public; Owner: -
--
@ -3062,6 +3075,14 @@ ALTER TABLE ONLY public.miscellaneous_np_infos
ADD CONSTRAINT miscellaneous_np_infos_pkey PRIMARY KEY (id);
--
-- Name: modern_donations modern_donations_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.modern_donations
ADD CONSTRAINT modern_donations_pkey PRIMARY KEY (id);
--
-- Name: bank_accounts nonprofit_bank_accounts_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
@ -3423,6 +3444,13 @@ CREATE INDEX index_exports_on_user_id ON public.exports USING btree (user_id);
CREATE INDEX index_import_requests_on_nonprofit_id ON public.import_requests USING btree (nonprofit_id);
--
-- Name: index_modern_donations_on_donation_id; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX index_modern_donations_on_donation_id ON public.modern_donations USING btree (donation_id);
--
-- Name: index_payments_on_created_at; Type: INDEX; Schema: public; Owner: -
--
@ -4286,7 +4314,9 @@ INSERT INTO "schema_migrations" (version) VALUES
('20210122203303'),
('20210127193411'),
('20210128215402'),
('20210204013426'),
('20210204172319');
('20210204172319'),
('20210204174909'),
('20210204210627'),
('20210204223643');

View file

@ -0,0 +1,30 @@
// License: LGPL-3.0-or-later
import type { Amount, HoudiniObject, IdType, HouID, HoudiniEvent } from "../../common";
import type Nonprofit from '../';
import type Supporter from "../Supporter";
import type Transaction from './';
interface Dedication {
contact?: {
address?: string;
email?: string;
phone?: string;
};
name: string;
note?: string;
type: 'honor' | 'memory';
}
export interface Donation extends HoudiniObject<HouID> {
amount: Amount;
dedication?: Dedication | null;
designation?: string | null;
nonprofit: IdType | Nonprofit;
object: 'donation';
supporter: IdType | Supporter;
transaction: HouID | Transaction;
}
export type DonationCreated = HoudiniEvent<'donation.created', Donation>;
export type DonationUpdated = HoudiniEvent<'donation.updated', Donation>;
export type DonationDeleted = HoudiniEvent<'donation.deleted', Donation>;

View file

@ -42,7 +42,13 @@ module InsertDonation
# Create the donation record
result['donation'] = insert_donation(data, entities)
trx = entities[:supporter_id].transactions.build(amount: data['amount'])
update_donation_keys(result)
don = trx.donations.build(amount: result['donation'].amount, legacy_donation: result['donation'])
trx.save!
don.save!
don.publish_created
result['activity'] = InsertActivities.for_one_time_donations([result['payment'].id])
Houdini.event_publisher.announce(:donation_create, result['donation'], result['donation'].supporter.locale)
result
@ -222,7 +228,7 @@ module InsertDonation
nonprofit_id: { required: true, is_reference: true },
supporter_id: { required: true, is_reference: true },
designation: { is_a: String },
dedication: { is_a: String },
dedication: { is_a: Hash },
campaign_id: { is_reference: true },
event_id: { is_reference: true }
}

View file

@ -64,6 +64,7 @@ module PayRecurringDonation
raise ParamValidation::ValidationError.new("#{rd['donation_id']} is not a valid donation", {})
end
trx = nonprofit.transactions.build(amount: donation['amount'])
result = {}
result = result.merge(InsertDonation.insert_charge(
'card_id' => donation['card_id'],
@ -78,7 +79,13 @@ module PayRecurringDonation
if result['charge']['status'] != 'failed'
rd.update(n_failures: 0)
result['recurring_donation'] = rd
Houdini.event_publisher.announce(:recurring_donation_payment_succeeded, donation, donation&.supporter&.locale || 'en')
donation = trx.donations.build(amount: donation['amount'], designation: donation['designation'], dedication: donation["dedication"])
trx.save!
donation.save!
donation.publish_created
InsertActivities.for_recurring_donations([result['payment']['id']])
else

View file

@ -328,7 +328,7 @@ module QueryPayments
end
def self.get_dedication_or_empty(*path)
"json_extract_path_text(coalesce(nullif(trim(both from donations.dedication), ''), '{}')::json, #{path.map { |i| "'#{i}'" }.join(',')})"
"json_extract_path_text(coalesce(donations.dedication, '{}')::json, #{path.map { |i| "'#{i}'" }.join(',')})"
end
def self.export_selects

View file

@ -86,6 +86,8 @@ module UpdateDonation
donation.date = data[:date] if data[:date]
end
modern_donation = donation.modern_donation
trx = modern_donation.trx
# edits_to_payments
if is_offsite
# if offline, set date, gross_amount, fee_total, net_amount
@ -95,7 +97,13 @@ module UpdateDonation
existing_payment.fee_total = data[:fee_total] if data[:fee_total]
existing_payment.net_amount = existing_payment.gross_amount - existing_payment.fee_total
existing_payment.save! if existing_payment.changed?
if existing_payment.changed?
existing_payment.save!
if existing_payment.previous_changes.has_key? 'gross_amount'
modern_donation.amount = existing_payment.gross_amount
trx.amount = existing_payment.gross_amount
end
end
else
if donation.designation
Payment.where('donation_id = ?', donation.id).update_all(towards: donation.designation, updated_at: Time.now)
@ -111,7 +119,14 @@ module UpdateDonation
offsite_payment.save! if offsite_payment.changed?
end
trx.save! if trx.changed?
donation.save! if donation.changed?
md_changed = modern_donation.changed?
modern_donation.save! if modern_donation.changed?
if (['dedication', 'designation'].any? {|i| donation.previous_changes.has_key? i} || md_changed)
modern_donation.publish_updated
end
existing_payment.reload

View file

@ -0,0 +1,9 @@
# frozen_string_literal: true
# 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
FactoryBot.define do
factory :modern_donation do
amount { 1 }
end
end

View file

@ -13,6 +13,9 @@ describe InsertDonation do
include_context :shared_rd_donation_value_context
describe 'param validation' do
before(:each) do
expect(Houdini.event_publisher).to_not receive(:announce).with(:donation_created,any_args)
end
it 'does basic validation' do
validation_basic_validation { InsertDonation.with_stripe(designation: 34_124, dedication: 35_141, event_id: 'bad', campaign_id: 'bad') }
end
@ -83,24 +86,27 @@ describe InsertDonation do
end
it 'charge returns failed' do
expect(Houdini.event_publisher).to_not receive(:announce).with(:donation_created,any_args)
handle_charge_failed { InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token) }
end
describe 'success' do
before(:each) do
before_each_success
allow(Houdini.event_publisher).to receive(:announce)
expect(Houdini.event_publisher).to receive(:announce).with(:donation_created,any_args)
end
it 'process event donation' do
process_event_donation { InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: event.id, date: (Time.now + 1.day).to_s, dedication: 'dedication', designation: 'designation') }
process_event_donation { InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: event.id, date: (Time.now + 1.day).to_s, dedication: {'type' => 'honor', 'name' => 'a name'}, designation: 'designation') }
end
it 'process campaign donation' do
expect(Houdini.event_publisher).to receive(:announce).with(:campaign_create, any_args)
process_campaign_donation { InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, campaign_id: campaign.id, date: (Time.now + 1.day).to_s, dedication: 'dedication', designation: 'designation') }
process_campaign_donation { InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, campaign_id: campaign.id, date: (Time.now + 1.day).to_s, dedication: {'type' => 'honor', 'name' => 'a name'}, designation: 'designation') }
end
it 'processes general donation' do
process_general_donation { InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, profile_id: profile.id, date: (Time.now + 1.day).to_s, dedication: 'dedication', designation: 'designation') }
process_general_donation { InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, profile_id: profile.id, date: (Time.now + 1.day).to_s, dedication: {'type' => 'honor', 'name' => 'a name'}, designation: 'designation') }
end
end
end
@ -113,18 +119,17 @@ describe InsertDonation do
before_each_sepa_success
end
it 'process event donation' do
process_event_donation(sepa: true) { InsertDonation.with_sepa(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, direct_debit_detail_id: direct_debit_detail.id, event_id: event.id, date: (Time.now + 1.day).to_s, dedication: 'dedication', designation: 'designation') }
process_event_donation(sepa: true) { InsertDonation.with_sepa(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, direct_debit_detail_id: direct_debit_detail.id, event_id: event.id, date: (Time.now + 1.day).to_s, dedication: {'type' => 'honor', 'name' => 'a name'}, designation: 'designation') }
end
it 'process campaign donation' do
expect(Houdini.event_publisher).to receive(:announce).with(:supporter_created, anything)
expect(Houdini.event_publisher).to receive(:announce).with(:supporter_address_created, anything)
allow(Houdini.event_publisher).to receive(:announce)
expect(Houdini.event_publisher).to receive(:announce).with(:campaign_create, any_args)
process_campaign_donation(sepa: true) { InsertDonation.with_sepa(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, direct_debit_detail_id: direct_debit_detail.id, campaign_id: campaign.id, date: (Time.now + 1.day).to_s, dedication: 'dedication', designation: 'designation') }
process_campaign_donation(sepa: true) { InsertDonation.with_sepa(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, direct_debit_detail_id: direct_debit_detail.id, campaign_id: campaign.id, date: (Time.now + 1.day).to_s, dedication: {'type' => 'honor', 'name' => 'a name'}, designation: 'designation') }
end
it 'processes general donation' do
process_general_donation(sepa: true) { InsertDonation.with_sepa(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, direct_debit_detail_id: direct_debit_detail.id, profile_id: profile.id, date: (Time.now + 1.day).to_s, dedication: 'dedication', designation: 'designation') }
process_general_donation(sepa: true) { InsertDonation.with_sepa(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, direct_debit_detail_id: direct_debit_detail.id, profile_id: profile.id, date: (Time.now + 1.day).to_s, dedication: {'type' => 'honor', 'name' => 'a name'}, designation: 'designation') }
end
end
end

View file

@ -128,17 +128,17 @@ describe InsertRecurringDonation do
before_each_success
end
it 'process event donation' do
process_event_donation(recurring_donation: { paydate: nil, interval: 1, time_unit: 'year', start_date: Time.current.beginning_of_day }) { InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: event.id, date: (Time.now + 1.day).to_s, dedication: 'dedication', designation: 'designation', recurring_donation: { time_unit: 'year' }) }
process_event_donation(recurring_donation: { paydate: nil, interval: 1, time_unit: 'year', start_date: Time.current.beginning_of_day }) { InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: event.id, date: (Time.now + 1.day).to_s, dedication: {'type' => 'honor', 'name' => 'a name'}, designation: 'designation', recurring_donation: { time_unit: 'year' }) }
end
it 'process campaign donation' do
expect(Houdini.event_publisher).to receive(:announce).with(:campaign_create, any_args)
process_campaign_donation(recurring_donation: { paydate: nil, interval: 2, time_unit: 'month', start_date: Time.current.beginning_of_day }) { InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, campaign_id: campaign.id, date: (Time.now + 1.day).to_s, dedication: 'dedication', designation: 'designation', recurring_donation: { interval: 2 }) }
process_campaign_donation(recurring_donation: { paydate: nil, interval: 2, time_unit: 'month', start_date: Time.current.beginning_of_day }) { InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, campaign_id: campaign.id, date: (Time.now + 1.day).to_s, dedication: {'type' => 'honor', 'name' => 'a name'}, designation: 'designation', recurring_donation: { interval: 2 }) }
end
it 'processes general donation with no recurring donation hash' do
process_general_donation(recurring_donation: { paydate: Time.now.day, interval: 1, time_unit: 'month', start_date: Time.now.beginning_of_day }) do
InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, profile_id: profile.id, date: Time.now.to_s, dedication: 'dedication', designation: 'designation')
InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, profile_id: profile.id, date: Time.now.to_s, dedication: {'type' => 'honor', 'name' => 'a name'}, designation: 'designation')
end
end
end
@ -150,7 +150,7 @@ describe InsertRecurringDonation do
it 'processes general donation' do
process_general_donation(expect_payment: false, expect_charge: false, recurring_donation: { paydate: (Time.now + 5.days).day, interval: 1, time_unit: 'month', start_date: (Time.now + 5.days).beginning_of_day }) do
InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, profile_id: profile.id, date: (Time.now + 1.day).to_s, dedication: 'dedication', designation: 'designation', recurring_donation: { start_date: (Time.now + 5.days).to_s })
InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, profile_id: profile.id, date: (Time.now + 1.day).to_s, dedication: {'type' => 'honor', 'name' => 'a name'}, designation: 'designation', recurring_donation: { start_date: (Time.now + 5.days).to_s })
end
end
end

View file

@ -186,7 +186,7 @@ describe QueryPayments do
token: token,
date: date,
dedication: 'dedication',
dedication: {'type' => 'honor', 'name' => 'a name'},
designation: 'designation' }
input[:event_id] = h[:event_id] if h[:event_id]

View file

@ -24,6 +24,13 @@ describe UpdateDonation do
supporter: supporter)
end
let(:trx) {
trx = force_create(:transaction, supporter: supporter, amount: initial_amount)
trx.donations.create(amount: initial_amount, legacy_donation: donation)
trx
}
let(:payment) do
force_create(:payment, nonprofit: np, donation: donation,
towards: initial_designation,
@ -76,12 +83,14 @@ describe UpdateDonation do
let(:payment2_date) { initial_date + 10.days }
before(:each) do
allow(Houdini.event_publisher).to receive(:announce)
initial_time
payment
end
describe '.update_payment' do
describe 'param validation' do
it 'basic validation' do
expect(Houdini.event_publisher).to_not receive(:announce).with(:donation_updated,anything)
expect { UpdateDonation.update_payment(nil, nil) }.to raise_error { |error|
expect(error).to be_a ParamValidation::ValidationError
expect_validation_errors(error.data, [{ key: :id, name: :required },
@ -92,6 +101,7 @@ describe UpdateDonation do
end
it 'validates whether payment is valid' do
expect(Houdini.event_publisher).to_not receive(:announce).with(:donation_updated,anything)
expect { UpdateDonation.update_payment(5555, {}) }.to raise_error { |error|
expect(error).to be_a ParamValidation::ValidationError
expect_validation_errors(error.data, [{ key: :id }])
@ -132,6 +142,7 @@ describe UpdateDonation do
end
it 'for offsite donations' do
offsite_payment
expect(Houdini.event_publisher).to_not receive(:announce).with(:donation_updated,anything)
expect { UpdateDonation.update_payment(donation.id, expanded_invalid_arguments) }.to(raise_error do |error|
expect(error).to be_a ParamValidation::ValidationError
expect_validation_errors(error.data, initial_validation_errors.concat([
@ -146,6 +157,7 @@ describe UpdateDonation do
end
it 'for online donation' do
expect(Houdini.event_publisher).to_not receive(:announce).with(:donation_updated,anything)
expect { UpdateDonation.update_payment(donation.id, expanded_invalid_arguments) }.to(raise_error do |error|
expect(error).to be_a ParamValidation::ValidationError
expect_validation_errors(error.data, initial_validation_errors)
@ -154,6 +166,7 @@ describe UpdateDonation do
end
it 'validate campaign_id' do
expect(Houdini.event_publisher).to_not receive(:announce).with(:donation_updated,anything)
expect { UpdateDonation.update_payment(donation.id, campaign_id: 444, event_id: 444) }.to(raise_error do |error|
expect(error).to be_a ParamValidation::ValidationError
expect_validation_errors(error.data, [{ key: :campaign_id }])
@ -161,6 +174,7 @@ describe UpdateDonation do
end
it 'validate event_id' do
expect(Houdini.event_publisher).to_not receive(:announce).with(:donation_updated,anything)
expect { UpdateDonation.update_payment(donation.id, event_id: 4444, campaign_id: campaign.id) }.to(raise_error do |error|
expect(error).to be_a ParamValidation::ValidationError
expect_validation_errors(error.data, [{ key: :event_id }])
@ -168,26 +182,33 @@ describe UpdateDonation do
end
it 'validates campaign belongs to payment org' do
expect(Houdini.event_publisher).to_not receive(:announce).with(:donation_updated,anything)
campaign_belongs { UpdateDonation.update_payment(donation.id, campaign_id: other_campaign.id, event_id: event.id) }
end
it 'validates event belongs to payment org' do
expect(Houdini.event_publisher).to_not receive(:announce).with(:donation_updated,anything)
event_belongs { UpdateDonation.update_payment(donation.id, event_id: other_event.id, campaign_id: campaign.id) }
end
end
describe 'most of the values arent changed if not provided' do
it 'online donation' do
trx
payment2
result = verify_nothing_changed
expect(Houdini.event_publisher).to_not receive(:announce).with(:donation_updated,anything)
expect(result).to eq donation.attributes.merge(payment: payment2.attributes)
trx.reload
expect(trx.amount).to eq initial_amount
expect(trx.donations.first.amount).to eq initial_amount
end
it 'offsite donation' do
trx
offsite_payment
result = verify_nothing_changed
expect(Houdini.event_publisher).to_not receive(:announce).with(:donation_updated,anything)
p2_attributes = payment2.attributes
payment2.reload
expect(p2_attributes).to eq payment2.attributes
@ -196,9 +217,13 @@ describe UpdateDonation do
offsite_payment.reload
expect(o_attributes).to eq offsite_payment.attributes
expect(result).to eq donation.attributes.merge(payment: payment.attributes, offsite_payment: offsite_payment.attributes)
trx.reload
expect(trx.amount).to eq initial_amount
expect(trx.donations.first.amount).to eq initial_amount
end
def verify_nothing_changed
expect(Houdini.event_publisher).to_not receive(:announce).with(:donation_updated,anything)
result = UpdateDonation.update_payment(donation.id, campaign_id: '', event_id: '')
p_attributes = payment.attributes
@ -209,6 +234,9 @@ describe UpdateDonation do
donation.reload
expect(d_attributes).to eq donation.attributes
trx.reload
expect(trx.amount).to eq initial_amount
expect(trx.donations.first.amount).to eq initial_amount
result
end
end
@ -227,8 +255,10 @@ describe UpdateDonation do
date: new_date_input }
end
it 'online donation' do
trx
payment2
Timecop.freeze(1.day) do
expect(Houdini.event_publisher).to receive(:announce).with(:donation_updated,anything)
result = UpdateDonation.update_payment(donation.id, new_data)
expected_donation = donation.attributes.merge(designation: new_designation,
@ -259,8 +289,10 @@ describe UpdateDonation do
end
it 'offline donation' do
trx
offsite_payment
Timecop.freeze(1.day) do
expect(Houdini.event_publisher).to receive(:announce).with(:donation_updated,anything)
result = UpdateDonation.update_payment(donation.id, new_data)
expected_donation = donation.attributes.merge(
@ -276,6 +308,7 @@ describe UpdateDonation do
updated_at: Time.now
).with_indifferent_access
trx.reload
donation.reload
expect(donation.attributes).to eq expected_donation
@ -291,6 +324,10 @@ describe UpdateDonation do
expect(offsite_payment.attributes).to eq expected_offsite_payment
expect(result).to eq create_expected_result(donation, payment, offsite_payment)
expect(trx.amount).to eq new_amount
expect(trx.donations.first.amount).to eq new_amount
end
end
@ -309,8 +346,10 @@ describe UpdateDonation do
end
it 'online donation' do
trx
payment2
Timecop.freeze(1.day) do
expect(Houdini.event_publisher).to receive(:announce).with(:donation_updated,anything)
UpdateDonation.update_payment(donation.id, new_data)
result = UpdateDonation.update_payment(donation.id, blank_data)
@ -342,8 +381,10 @@ describe UpdateDonation do
end
it 'offline donation' do
trx
offsite_payment
Timecop.freeze(1.day) do
expect(Houdini.event_publisher).to receive(:announce).with(:donation_updated,anything)
UpdateDonation.update_payment(donation.id, new_data)
result = UpdateDonation.update_payment(donation.id, blank_data)

View file

@ -0,0 +1,54 @@
# frozen_string_literal: true
# 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'
RSpec.describe ModernDonation, type: :model do
include_context :shared_donation_charge_context
# TODO Why are we manually setting everything here? It's not clear what order things should
# go in for a transaction. Therefore, we don't assume the order for now and just make sure the
# the output of to_builder is right
let(:trx) { force_create(:transaction, supporter: supporter, amount: 1200)}
let(:legacy_donation) { force_create(:donation, amount: 1200) }
let(:dedication) {{
type: 'honor',
name: "Grandma Schultz"
}}
let(:legacy_donation_with_dedication_and_designation) { force_create(:donation, amount: 1200, designation: 'designation', dedication: dedication) }
describe 'to_builder' do
let(:don_default) do
{
'id' => match_houid('don'),
'object' => 'donation',
'nonprofit' => nonprofit.id,
'supporter' => supporter.id,
'amount' => {'currency' => 'usd', 'value_in_cents' => 1200},
'transaction' => trx.id,
'designation' => nil
}
end
it 'without dedication or designation' do
donation = trx.donations.create(amount: 1200)
donation.legacy_donation = legacy_donation
donation.save!
expect(donation.to_builder.attributes!).to match(don_default)
end
it 'with designation and dedication' do
donation = trx.donations.create(amount: 1200)
donation.legacy_donation = legacy_donation_with_dedication_and_designation
donation.save!
expect(donation.to_builder.attributes!).to match(don_default.merge({
'designation' => 'designation',
'dedication' => {
'type' => 'honor',
'name' => 'Grandma Schultz'
}
}))
end
end
end

View file

@ -48,7 +48,7 @@ RSpec.shared_context :shared_rd_donation_value_context do
amount: charge_amount,
comment: nil,
category: nil,
dedication: 'dedication',
dedication: {'type' => 'honor', 'name' => 'a name'},
designation: 'designation',
imported_at: nil,
manual: nil,