diff --git a/app/models/campaign.rb b/app/models/campaign.rb index d5f9164a..b0dfebb7 100644 --- a/app/models/campaign.rb +++ b/app/models/campaign.rb @@ -69,6 +69,7 @@ class Campaign < ApplicationRecord has_many :campaign_gifts, through: :campaign_gift_options has_many :supporters, through: :donations has_many :recurring_donations + has_many :campaign_gift_purchases has_many :roles, as: :host, dependent: :destroy has_many :comments, as: :host, dependent: :destroy has_many :activities, as: :host, dependent: :destroy diff --git a/app/models/campaign_gift_option.rb b/app/models/campaign_gift_option.rb index 8e735544..46fdace2 100644 --- a/app/models/campaign_gift_option.rb +++ b/app/models/campaign_gift_option.rb @@ -30,10 +30,9 @@ class CampaignGiftOption < ApplicationRecord after_update_commit :publish_updated after_destroy_commit :publish_deleted - add_builder_expansion :campaign - add_builder_expansion :nonprofit, - to_attrib: -> (model) {model.campaign.nonprofit} + add_builder_expansion :campaign, :nonprofit + has_one :nonprofit, through: :campaign def total_gifts @@ -82,7 +81,10 @@ class CampaignGiftOption < ApplicationRecord json.deleted !persisted? json.gift_option_amount gift_option_amount do |desc| - json.amount desc[:amount] + json.amount do + json.currency desc[:amount][:currency] + json.value_in_cents desc[:amount][:value_in_cents] + end json.recurrence(desc[:recurrence]) if desc[:recurrence] end end diff --git a/app/models/campaign_gift_purchase.rb b/app/models/campaign_gift_purchase.rb index 390201ee..aff2463b 100644 --- a/app/models/campaign_gift_purchase.rb +++ b/app/models/campaign_gift_purchase.rb @@ -3,6 +3,12 @@ # 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 CampaignGiftPurchase < ApplicationRecord + include Model::Houidable + include Model::Jbuilder + include Model::Eventable + + setup_houid :cgpur + belongs_to :campaign has_many :campaign_gifts, class_name: 'ModernCampaignGift' @@ -19,4 +25,23 @@ class CampaignGiftPurchase < ApplicationRecord validates :campaign, presence: true validates :campaign_gifts, length: { minimum: 1 } + def to_builder(*expand) + init_builder(*expand) do |json| + json.(self, :id, :deleted) + json.object 'campaign_gift_purchase' + + json.amount do + json.value_in_cents amount + json.currency nonprofit.currency + end + + if expand.include? :campaign_gifts + json.campaign_gifts campaign_gifts do |gift| + gift.to_builder + end + else + json.campaign_gifts campaign_gifts.pluck(:id) + end + end + end end diff --git a/app/models/modern_campaign_gift.rb b/app/models/modern_campaign_gift.rb index e0825432..527efbf0 100644 --- a/app/models/modern_campaign_gift.rb +++ b/app/models/modern_campaign_gift.rb @@ -7,7 +7,8 @@ class ModernCampaignGift < ApplicationRecord include Model::Jbuilder include Model::Eventable setup_houid :cgift - add_builder_expansion :nonprofit, :supporter, :campaign, :campaign_gift_option + + add_builder_expansion :nonprofit, :supporter, :campaign, :campaign_gift_option, :campaign_gift_purchase add_builder_expansion :trx, json_attrib: :transaction @@ -23,7 +24,7 @@ class ModernCampaignGift < ApplicationRecord # TODO replace with Discard gem define_model_callbacks :discard - after_discard :publish_deleted + # after_discard :publish_deleted validates :amount, presence: true validates :legacy_campaign_gift, presence: true @@ -38,8 +39,8 @@ class ModernCampaignGift < ApplicationRecord end def to_builder(*expand) - init_builder(*expand) do - json.(self, :id, :name, :deleted) + init_builder(*expand) do |json| + json.(self, :id, :deleted) json.object 'campaign_gift' json.amount do json.value_in_cents amount @@ -49,14 +50,14 @@ class ModernCampaignGift < ApplicationRecord end def publish_created - Houdini.event_publisher.announce(:campaign_gift_created, to_event('campaign_gift.created', :nonprofit, :supporter, :trx, :campaign, :campaign_gift_option).attributes!) + Houdini.event_publisher.announce(:campaign_gift_created, to_event('campaign_gift.created', :nonprofit, :supporter, :trx, :campaign, :campaign_gift_option, :campaign_gift_purchase).attributes!) end def publish_updated - Houdini.event_publisher.announce(:campaign_gift_updated, to_event('campaign_gift.updated', :nonprofit, :supporter, :trx, :campaign, :campaign_gift_option).attributes!) + Houdini.event_publisher.announce(:campaign_gift_updated, to_event('campaign_gift.updated', :nonprofit, :supporter, :trx, :campaign, :campaign_gift_option, :campaign_gift_purchase).attributes!) end def publish_deleted - Houdini.event_publisher.announce(:campaign_gift_deleted, to_event('campaign_gift.deleted', :nonprofit, :supporter, :trx, :campaign, :campaign_gift_option).attributes!) + Houdini.event_publisher.announce(:campaign_gift_deleted, to_event('campaign_gift.deleted', :nonprofit, :supporter, :trx, :campaign, :campaign_gift_option, :campaign_gift_purchase).attributes!) end end diff --git a/app/models/transaction.rb b/app/models/transaction.rb index f41922bd..9d3481ec 100644 --- a/app/models/transaction.rb +++ b/app/models/transaction.rb @@ -17,6 +17,7 @@ class Transaction < ApplicationRecord has_many :donations, through: :transaction_assignments, source: :assignable, source_type: 'ModernDonation' has_many :ticket_purchases, through: :transaction_assignments, source: :assignable, source_type: 'TicketPurchase' + has_many :campaign_gift_purchases, through: :transaction_assignments, source: :assignable, source_type: 'CampaignGiftPurchase' validates :supporter, presence: true diff --git a/spec/factories/campaign_gift_purchases.rb b/spec/factories/campaign_gift_purchases.rb index f6668190..b120d758 100644 --- a/spec/factories/campaign_gift_purchases.rb +++ b/spec/factories/campaign_gift_purchases.rb @@ -4,8 +4,5 @@ # Full license explanation at https://github.com/houdiniproject/houdini/blob/master/LICENSE FactoryBot.define do factory :campaign_gift_purchase do - deleted { false } - amount { 1 } - campaign { nil } end end diff --git a/spec/models/modern_campaign_gift_spec.rb b/spec/models/modern_campaign_gift_spec.rb index 9766fdbe..fe8aeea9 100644 --- a/spec/models/modern_campaign_gift_spec.rb +++ b/spec/models/modern_campaign_gift_spec.rb @@ -5,5 +5,177 @@ require 'rails_helper' RSpec.describe ModernCampaignGift, type: :model do - pending "add some examples to (or delete) #{__FILE__}" + 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: 400)} + + let(:campaign_gift_purchase) {trx.campaign_gift_purchases.create(campaign: campaign, amount: 400, campaign_gifts: [ModernCampaignGift.new(amount: 400, legacy_campaign_gift:lcg)])} + let(:lcg) { CampaignGift.create( + donation: supporter.donations.create(amount: 400, campaign: campaign, nonprofit: nonprofit, supporter:supporter), + campaign_gift_option: campaign_gift_option + )} + let(:campaign_gift_option) { create(:campaign_gift_option, amount_one_time: 400, campaign: campaign)} + let(:campaign_gift) { campaign_gift_purchase.campaign_gifts.first} + + let(:campaign_builder_expanded) do + { + 'id' => kind_of(Numeric), + 'name' => campaign.name, + 'object' => "campaign", + 'nonprofit' => nonprofit.id + } + end + + let(:cgo_builder_expanded) do + { + 'id' => kind_of(Numeric), + 'name' => campaign_gift_option.name, + 'description' => campaign_gift_option.description, + 'hide_contributions' => campaign_gift_option.hide_contributions, + 'order' => campaign_gift_option.order, + 'to_ship' => campaign_gift_option.to_ship, + 'object' => 'campaign_gift_option', + 'deleted' => false, + 'gift_option_amount' => [{ + 'amount' => { + 'value_in_cents' => 400, + 'currency' => 'usd' + }, + }], + 'campaign' => kind_of(Numeric), + 'nonprofit' => kind_of(Numeric) + } + end + + let(:np_builder_expanded) do + { + 'id' => nonprofit.id, + 'name' => nonprofit.name, + 'object' => 'nonprofit' + } + end + + let(:supporter_builder_expanded) do + supporter_to_builder_base.merge({'name'=> 'Fake Supporter Name'}) + end + + let(:transaction_builder_expanded) do + { + 'id' => match_houid('trx'), + 'object' => 'transaction', + 'amount' => { + 'value_in_cents' => trx.amount, + 'currency' => 'usd' + }, + 'supporter' => kind_of(Numeric), + 'nonprofit' => kind_of(Numeric) + } + end + + let(:cgp_builder_expanded) do + { + 'id' => match_houid('cgpur'), + 'campaign' => kind_of(Numeric), + 'object' => 'campaign_gift_purchase', + 'campaign_gifts' => [match_houid('cgift')], + 'amount' => { + 'value_in_cents' => trx.amount, + 'currency' => 'usd' + }, + 'supporter' => kind_of(Numeric), + 'nonprofit' => kind_of(Numeric), + 'transaction' => match_houid('trx'), + 'deleted' => false + } + end + + + + + it 'announces created properly when called' do + allow(Houdini.event_publisher).to receive(:announce) + expect(Houdini.event_publisher).to receive(:announce).with(:campaign_gift_created, { + 'id' => match_houid('objevt'), + 'object' => 'object_event', + 'type' => 'campaign_gift.created', + 'data' => { + 'object' => { + 'amount' => { + 'value_in_cents' => 400, + 'currency' => 'usd' + }, + 'campaign' => campaign_builder_expanded, + 'campaign_gift_option' => cgo_builder_expanded, + 'campaign_gift_purchase' => cgp_builder_expanded, + 'deleted' => false, + 'id' => match_houid('cgift'), + 'nonprofit'=> np_builder_expanded, + 'object' => 'campaign_gift', + 'supporter' => supporter_builder_expanded, + 'transaction' => transaction_builder_expanded + } + } + }) + + campaign_gift.publish_created + end + + it 'announces updated properly when called' do + allow(Houdini.event_publisher).to receive(:announce) + expect(Houdini.event_publisher).to receive(:announce).with(:campaign_gift_updated, { + 'id' => match_houid('objevt'), + 'object' => 'object_event', + 'type' => 'campaign_gift.updated', + 'data' => { + 'object' => { + 'amount' => { + 'value_in_cents' => 400, + 'currency' => 'usd' + }, + 'campaign' => campaign_builder_expanded, + 'campaign_gift_option' => cgo_builder_expanded, + 'campaign_gift_purchase' => cgp_builder_expanded, + 'deleted' => false, + 'id' => match_houid('cgift'), + 'nonprofit'=> np_builder_expanded, + 'object' => 'campaign_gift', + 'supporter' => supporter_builder_expanded, + 'transaction' => transaction_builder_expanded + } + } + }) + + campaign_gift.publish_updated + end + + it 'announces updated deleted properly when called' do + allow(Houdini.event_publisher).to receive(:announce) + expect(Houdini.event_publisher).to receive(:announce).with(:campaign_gift_deleted, { + 'id' => match_houid('objevt'), + 'object' => 'object_event', + 'type' => 'campaign_gift.deleted', + 'data' => { + 'object' => { + 'amount' => { + 'value_in_cents' => 400, + 'currency' => 'usd' + }, + 'campaign' => campaign_builder_expanded, + 'campaign_gift_option' => cgo_builder_expanded, + 'campaign_gift_purchase' => cgp_builder_expanded, + 'deleted' => true, + 'id' => match_houid('cgift'), + 'nonprofit'=> np_builder_expanded, + 'object' => 'campaign_gift', + 'supporter' => supporter_builder_expanded, + 'transaction' => transaction_builder_expanded + } + } + }) + + campaign_gift.discard! + campaign_gift.publish_deleted + end end