donation.* event publishing
This commit is contained in:
parent
a401f4bea4
commit
6ab7473ef7
18 changed files with 304 additions and 22 deletions
|
@ -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
|
||||
|
|
55
app/models/modern_donation.rb
Normal file
55
app/models/modern_donation.rb
Normal 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
|
|
@ -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
|
||||
|
|
10
db/migrate/20210204210627_create_modern_donations.rb
Normal file
10
db/migrate/20210204210627_create_modern_donations.rb
Normal 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
|
|
@ -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
|
|
@ -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');
|
||||
|
||||
|
||||
|
|
30
docs/event_definitions/Nonprofit/Transaction/Donation.ts
Normal file
30
docs/event_definitions/Nonprofit/Transaction/Donation.ts
Normal 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>;
|
|
@ -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 }
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
9
spec/factories/modern_donations.rb
Normal file
9
spec/factories/modern_donations.rb
Normal 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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
54
spec/models/modern_donation_spec.rb
Normal file
54
spec/models/modern_donation_spec.rb
Normal 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
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue