Move fundraising models into the Fundraising module

This was mostly straightforward it seems, whew!
This commit is contained in:
Emi Matchu 2024-02-18 20:29:31 -08:00
parent 82be7fe301
commit d39e7cea81
11 changed files with 126 additions and 120 deletions

View file

@ -65,7 +65,7 @@ class ClosetHangersController < ApplicationController
current_user.assign_closeted_to_items!(items) current_user.assign_closeted_to_items!(items)
end end
@campaign = Campaign.current @campaign = Fundraising::Campaign.current
end end
def petpage def petpage

View file

@ -18,7 +18,7 @@ class ItemsController < ApplicationController
assign_closeted! assign_closeted!
respond_to do |format| respond_to do |format|
format.html { format.html {
@campaign = Campaign.current rescue nil @campaign = Fundraising::Campaign.current rescue nil
if @items.count == 1 if @items.count == 1
redirect_to @items.first redirect_to @items.first
else else
@ -45,7 +45,7 @@ class ItemsController < ApplicationController
else else
respond_to do |format| respond_to do |format|
format.html { format.html {
@campaign = Campaign.current rescue nil @campaign = Fundraising::Campaign.current rescue nil
@newest_items = Item.newest.includes(:translations).limit(18) @newest_items = Item.newest.includes(:translations).limit(18)
} }
format.js { render json: {error: '$q required'}} format.js { render json: {error: '$q required'}}

View file

@ -76,7 +76,7 @@ class OutfitsController < ApplicationController
@neopets_usernames = user_signed_in? ? current_user.neopets_usernames : [] @neopets_usernames = user_signed_in? ? current_user.neopets_usernames : []
@campaign = Campaign.current rescue nil @campaign = Fundraising::Campaign.current rescue nil
end end
def show def show

View file

@ -1,20 +0,0 @@
class Campaign < ApplicationRecord
has_many :donations
def progress_percent
[(progress.to_f / goal) * 100, 100].min
end
def remaining
goal - progress
end
def complete?
progress >= goal
end
def self.current
self.where(active: true).first or
raise ActiveRecord::RecordNotFound.new("no current campaign")
end
end

View file

@ -1,69 +0,0 @@
class Donation < ApplicationRecord
FEATURE_COST = 500 # in cents = $5.00
belongs_to :campaign
belongs_to :user, optional: true
has_many :features, class_name: 'DonationFeature'
def to_param
"#{id}-#{secret}"
end
def self.create_from_charge(campaign, user, params)
amount = (BigDecimal.new(params[:amount]) * 100).floor
campaign.progress += amount
charge_params = {
amount: amount,
description: 'Donation (thank you!)',
currency: 'usd'
}
if params[:stripe_token_type] == 'card'
customer = Stripe::Customer.create(
card: params[:stripe_token]
)
charge_params[:customer] = customer.id
elsif params[:stripe_token_type] == 'bitcoin_receiver'
charge_params[:card] = params[:stripe_token]
else
raise ArgumentError, "unexpected stripe token type #{params[:stripe_token_type]}"
end
charge = Stripe::Charge.create(charge_params)
donation = campaign.donations.build
donation.amount = amount
donation.charge_id = charge.id
donation.user = user
donation.donor_name = user.try(:name)
donation.donor_email = params[:donor_email]
donation.secret = new_secret
num_features = amount / FEATURE_COST
features = []
num_features.times do
features << donation.features.new
end
Donation.transaction do
campaign.save!
donation.save!
features.each(&:save!)
end
DonationMailer.thank_you_email(donation, donation.donor_email).deliver
donation
end
def self.new_secret
SecureRandom.urlsafe_base64 8
end
def self.from_param(param)
id, secret = param.split('-', 2)
self.where(secret: secret).find(id)
end
end

View file

@ -1,24 +0,0 @@
class DonationFeature < ApplicationRecord
belongs_to :donation
belongs_to :outfit, optional: true
validates :outfit, presence: true, if: :outfit_id_present?
delegate :donor_name, to: :donation
def as_json(options={})
{donor_name: donor_name, outfit_image_url: outfit_image_url}
end
def outfit_url=(outfit_url)
self.outfit_id = outfit_url.split('/').last rescue nil
end
def outfit_id_present?
outfit_id.present?
end
def outfit_image_url
outfit && outfit.image ? outfit.image.medium.url : nil
end
end

View file

@ -0,0 +1,22 @@
module Fundraising
class Campaign < ApplicationRecord
has_many :donations
def progress_percent
[(progress.to_f / goal) * 100, 100].min
end
def remaining
goal - progress
end
def complete?
progress >= goal
end
def self.current
self.where(active: true).first or
raise ActiveRecord::RecordNotFound.new("no current campaign")
end
end
end

View file

@ -0,0 +1,71 @@
module Fundraising
class Donation < ApplicationRecord
FEATURE_COST = 500 # in cents = $5.00
belongs_to :campaign
belongs_to :user, optional: true
has_many :features, class_name: 'DonationFeature'
def to_param
"#{id}-#{secret}"
end
def self.create_from_charge(campaign, user, params)
amount = (BigDecimal.new(params[:amount]) * 100).floor
campaign.progress += amount
charge_params = {
amount: amount,
description: 'Donation (thank you!)',
currency: 'usd'
}
if params[:stripe_token_type] == 'card'
customer = Stripe::Customer.create(
card: params[:stripe_token]
)
charge_params[:customer] = customer.id
elsif params[:stripe_token_type] == 'bitcoin_receiver'
charge_params[:card] = params[:stripe_token]
else
raise ArgumentError, "unexpected stripe token type #{params[:stripe_token_type]}"
end
charge = Stripe::Charge.create(charge_params)
donation = campaign.donations.build
donation.amount = amount
donation.charge_id = charge.id
donation.user = user
donation.donor_name = user.try(:name)
donation.donor_email = params[:donor_email]
donation.secret = new_secret
num_features = amount / FEATURE_COST
features = []
num_features.times do
features << donation.features.new
end
Donation.transaction do
campaign.save!
donation.save!
features.each(&:save!)
end
DonationMailer.thank_you_email(donation, donation.donor_email).deliver
donation
end
def self.new_secret
SecureRandom.urlsafe_base64 8
end
def self.from_param(param)
id, secret = param.split('-', 2)
self.where(secret: secret).find(id)
end
end
end

View file

@ -0,0 +1,26 @@
module Fundraising
class DonationFeature < ApplicationRecord
belongs_to :donation
belongs_to :outfit, optional: true
validates :outfit, presence: true, if: :outfit_id_present?
delegate :donor_name, to: :donation
def as_json(options={})
{donor_name: donor_name, outfit_image_url: outfit_image_url}
end
def outfit_url=(outfit_url)
self.outfit_id = outfit_url.split('/').last rescue nil
end
def outfit_id_present?
outfit_id.present?
end
def outfit_image_url
outfit && outfit.image ? outfit.image.medium.url : nil
end
end
end

View file

@ -79,15 +79,15 @@ OpenneoImpressItems::Application.routes.draw do
end end
# Donation campaign stuff! # Donation campaign stuff!
scope module: "fundraising" do scope module: "fundraising", as: "fundraising" do
resources :donations, only: [:create, :show, :update] do resources :donations, only: [:create, :show, :update] do
collection do collection do
resources :donation_features, path: 'features', only: [:index] resources :donation_features, path: 'features', only: [:index]
end end
end end
resources :campaigns, only: [:show], path: '/donate/campaigns' resources :campaigns, only: [:show], path: '/donate/campaigns'
get '/donate' => 'campaigns#current', as: :donate
end end
get '/donate' => 'fundraising/campaigns#current', as: :donate
# Static pages! # Static pages!
get '/terms', as: :terms, get '/terms', as: :terms,

View file

@ -209,4 +209,4 @@ Zone.create(:id => 52, :label => "Foreground", :plain_label => "foreground", :de
# NOTE: Creating an AuthUser automatically creates a User, too. # NOTE: Creating an AuthUser automatically creates a User, too.
AuthUser.create(name: "test", password: "test123", email: "test@gmail.example") AuthUser.create(name: "test", password: "test123", email: "test@gmail.example")
Campaign.create(goal: 100_00, active: true, advertised: false, description: "") Fundraising::Campaign.create(goal: 100_00, active: true, advertised: false, description: "")