Add recurring donations
This commit is contained in:
parent
5723b91ba2
commit
d55d149d7d
|
@ -1,10 +1,11 @@
|
|||
require_dependency 'discourse'
|
||||
|
||||
module DiscourseDonations
|
||||
class ChargesController < ApplicationController
|
||||
class ChargesController < ::ApplicationController
|
||||
|
||||
skip_before_action :verify_authenticity_token, only: [:create]
|
||||
skip_before_action :check_xhr
|
||||
before_action :set_user_and_email, only: [:create]
|
||||
|
||||
def create
|
||||
Rails.logger.info user_params.inspect
|
||||
|
@ -12,7 +13,7 @@ module DiscourseDonations
|
|||
output = { 'messages' => [], 'rewards' => [] }
|
||||
|
||||
if create_account
|
||||
if !email.present? || !user_params[:username].present?
|
||||
if !@email.present? || !user_params[:username].present?
|
||||
output['messages'] << I18n.t('login.missing_user_field')
|
||||
end
|
||||
if user_params[:password] && user_params[:password].length > User.max_password_length
|
||||
|
@ -32,15 +33,19 @@ module DiscourseDonations
|
|||
|
||||
begin
|
||||
Rails.logger.debug "Creating a Stripe charge for #{user_params[:amount]}"
|
||||
charge_params = [user_params[:stripeToken], user_params[:amount]]
|
||||
opts = {
|
||||
email: @email,
|
||||
token: user_params[:stripeToken],
|
||||
amount: user_params[:amount]
|
||||
}
|
||||
|
||||
if user
|
||||
charge_params.unshift(user, user.email)
|
||||
if user_params[:type] === 'once'
|
||||
charge = payment.charge(@user, opts)
|
||||
else
|
||||
charge_params.unshift(nil, email)
|
||||
opts[:type] = user_params[:type]
|
||||
charge = payment.subscribe(@user, opts)
|
||||
end
|
||||
|
||||
charge = payment.charge(*charge_params)
|
||||
rescue ::Stripe::CardError => e
|
||||
err = e.json_body[:error]
|
||||
|
||||
|
@ -58,7 +63,7 @@ module DiscourseDonations
|
|||
output['rewards'] << { type: :group, name: group_name } if group_name
|
||||
output['rewards'] << { type: :badge, name: badge_name } if badge_name
|
||||
|
||||
if create_account && email.present?
|
||||
if create_account && @email.present?
|
||||
args = user_params.to_h.slice(:email, :username, :password, :name).merge(rewards: output['rewards'])
|
||||
Jobs.enqueue(:donation_user, args)
|
||||
end
|
||||
|
@ -97,19 +102,27 @@ module DiscourseDonations
|
|||
end
|
||||
|
||||
def user_params
|
||||
params.permit(:user_id, :name, :username, :email, :password, :stripeToken, :amount, :create_account)
|
||||
params.permit(:user_id, :name, :username, :email, :password, :stripeToken, :type, :amount, :create_account)
|
||||
end
|
||||
|
||||
def email
|
||||
user_params[:email] || user.try(:email)
|
||||
end
|
||||
|
||||
def user
|
||||
if user_params[:user_id]
|
||||
User.find(user_params[:user_id])
|
||||
else
|
||||
current_user
|
||||
def set_user_and_email
|
||||
user = current_user
|
||||
|
||||
if user_params[:user_id].present?
|
||||
user = User.find(user_params[:user_id])
|
||||
end
|
||||
|
||||
if user_params[:email].present?
|
||||
email = user_params[:email]
|
||||
else
|
||||
email = user.try(:email)
|
||||
end
|
||||
|
||||
@user = user
|
||||
@email = email
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
RECURRING_DONATION_PRODUCT_ID = 'discourse_donation_recurring'
|
||||
|
||||
module DiscourseDonations
|
||||
class Stripe
|
||||
attr_reader :charge, :currency, :description
|
||||
|
@ -10,32 +12,47 @@ module DiscourseDonations
|
|||
|
||||
def checkoutCharge(user = nil, email, token, amount)
|
||||
customer = customer(user, email, token)
|
||||
|
||||
charge = ::Stripe::Charge.create(
|
||||
customer: customer.id,
|
||||
amount: amount,
|
||||
description: @description,
|
||||
currency: @currency
|
||||
)
|
||||
|
||||
charge
|
||||
end
|
||||
|
||||
def charge(user = nil, email, token, amount)
|
||||
customer = customer(user, email, token)
|
||||
def charge(user = nil, opts)
|
||||
customer = customer(user, opts[:email], opts[:token])
|
||||
|
||||
@charge = ::Stripe::Charge.create(
|
||||
customer: customer.id,
|
||||
amount: amount,
|
||||
description: description,
|
||||
currency: currency
|
||||
amount: opts[:amount],
|
||||
description: @description,
|
||||
currency: @currency
|
||||
)
|
||||
|
||||
@charge
|
||||
end
|
||||
|
||||
def subscribe(user = nil, email, opts)
|
||||
customer = customer(user, email, opts[:stripeToken])
|
||||
def subscribe(user = nil, opts)
|
||||
customer = customer(user, opts[:email], opts[:token])
|
||||
|
||||
plans = ::Stripe::Plan.list
|
||||
type = opts[:type]
|
||||
plan_id = create_plan_id(type)
|
||||
|
||||
unless plans.data && plans.data.any? { |p| p['id'] === plan_id }
|
||||
result = create_plan(type, opts[:amount])
|
||||
plan_id = result['id']
|
||||
end
|
||||
|
||||
@subscription = ::Stripe::Subscription.create(
|
||||
customer: customer.id,
|
||||
plan: opts[:plan]
|
||||
items: [{ plan: plan_id }]
|
||||
)
|
||||
|
||||
@subscription
|
||||
end
|
||||
|
||||
|
@ -47,10 +64,12 @@ module DiscourseDonations
|
|||
email: email,
|
||||
source: source
|
||||
)
|
||||
|
||||
if user
|
||||
user.custom_fields['stripe_customer_id'] = customer.id
|
||||
user.save_custom_fields(true)
|
||||
end
|
||||
|
||||
customer
|
||||
end
|
||||
end
|
||||
|
@ -58,5 +77,40 @@ module DiscourseDonations
|
|||
def successful?
|
||||
@charge[:paid]
|
||||
end
|
||||
|
||||
def create_plan(type, amount)
|
||||
id = create_plan_id(type)
|
||||
nickname = id.gsub(/_/, ' ').titleize
|
||||
|
||||
products = ::Stripe::Product.list(type: 'service')
|
||||
|
||||
if products['data'] && products['data'].any? { |p| p['id'] === RECURRING_DONATION_PRODUCT_ID }
|
||||
product = RECURRING_DONATION_PRODUCT_ID
|
||||
else
|
||||
result = create_product
|
||||
product = result['id']
|
||||
end
|
||||
|
||||
::Stripe::Plan.create(
|
||||
id: id,
|
||||
nickname: nickname,
|
||||
interval: type.tr('ly', ''),
|
||||
currency: @currency,
|
||||
product: product,
|
||||
amount: amount.to_i
|
||||
)
|
||||
end
|
||||
|
||||
def create_product
|
||||
::Stripe::Product.create(
|
||||
id: RECURRING_DONATION_PRODUCT_ID,
|
||||
name: "Discourse Donation Recurring",
|
||||
type: 'service'
|
||||
)
|
||||
end
|
||||
|
||||
def create_plan_id(type)
|
||||
"discourse_donation_recurring_#{type}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -16,6 +16,39 @@ export default Ember.Component.extend({
|
|||
this.set('settings', getRegister(this).lookup('site-settings:main'));
|
||||
this.set('create_accounts', this.get('anon') && this.get('settings').discourse_donations_enable_create_accounts);
|
||||
this.set('stripe', Stripe(this.get('settings').discourse_donations_public_key));
|
||||
|
||||
const types = Discourse.SiteSettings.discourse_donations_types.split('|') || [];
|
||||
this.set('types', types);
|
||||
this.set('type', types[0]);
|
||||
},
|
||||
|
||||
@computed('types')
|
||||
donationTypes(types) {
|
||||
return types.map((type) => {
|
||||
return {
|
||||
id: type,
|
||||
name: I18n.t(`discourse_donations.types.${type}`)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
@computed('type')
|
||||
period(type) {
|
||||
let anchor;
|
||||
|
||||
if (type === 'weekly') {
|
||||
anchor = moment().format('dddd');
|
||||
}
|
||||
|
||||
if (type === 'monthly') {
|
||||
anchor = moment().format('Do');
|
||||
}
|
||||
|
||||
if (type === 'yearly') {
|
||||
anchor = moment().format('MMMM D');
|
||||
}
|
||||
|
||||
return I18n.t(`discourse_donations.period.${type}`, { anchor });
|
||||
},
|
||||
|
||||
@computed
|
||||
|
@ -91,6 +124,7 @@ export default Ember.Component.extend({
|
|||
const amount = transactionFeeEnabled ? this.get('totalAmount') : this.get('amount');
|
||||
let params = {
|
||||
stripeToken: data.token.id,
|
||||
type: self.get('type'),
|
||||
amount: amount * 100,
|
||||
email: self.get('email'),
|
||||
username: self.get('username'),
|
||||
|
|
|
@ -1,5 +1,14 @@
|
|||
<form id="payment-form" class="form-horizontal">
|
||||
|
||||
<div class="control-group">
|
||||
<label class="control-label">
|
||||
{{i18n 'discourse_donations.type'}}
|
||||
</label>
|
||||
<div class="controls controls-dropdown">
|
||||
{{combo-box content=donationTypes value=type}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="card-element">
|
||||
{{i18n 'discourse_donations.amount'}}
|
||||
|
@ -14,7 +23,7 @@
|
|||
<div class="control-group">
|
||||
<div class="controls">
|
||||
{{input type="checkbox" checked=includeTransactionFee}}
|
||||
{{i18n 'discourse_donations.transaction_fee.label' transactionFee=transactionFee currency=settings.discourse_donations_currency}}
|
||||
<span>{{i18n 'discourse_donations.transaction_fee.label' transactionFee=transactionFee currency=settings.discourse_donations_currency}}</span>
|
||||
<div class='transaction-fee-description' {{action 'toggleTransactionFeeDescription'}}>
|
||||
{{d-icon 'info-circle'}}
|
||||
{{#if showTransactionFeeDescription}}
|
||||
|
@ -32,6 +41,7 @@
|
|||
<div class="controls">
|
||||
{{settings.discourse_donations_currency}}
|
||||
{{totalAmount}}
|
||||
{{period}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
|
|
@ -17,6 +17,7 @@ en:
|
|||
discourse_donations_transaction_fee_percent: "Percent part of Stripe transaction fee (changes per region). See <a href='https://stripe.com/pricing'>Stripe's pricing for your region</a> and <a href='https://support.stripe.com/questions/can-i-charge-my-stripe-fees-to-my-customers'>Stripe's explaination of passing fees onto customers</a>."
|
||||
discourse_donations_amounts: "Donation amounts available to user"
|
||||
discourse_donations_custom_amount: "Allow custom donation amount"
|
||||
discourse_donations_types: "Donation types. First listed will be the default."
|
||||
errors:
|
||||
discourse_donations_amount_must_be_number: "Amounts must be numbers"
|
||||
|
||||
|
@ -25,7 +26,7 @@ en:
|
|||
title: Donate
|
||||
nav_item: Donate
|
||||
amount: Amount
|
||||
card: Credit or debit card
|
||||
card: Card
|
||||
submit: Make Payment
|
||||
submit_with_create_account: Make Payment and Create Account
|
||||
transaction_fee:
|
||||
|
@ -34,3 +35,14 @@ en:
|
|||
total: "Total"
|
||||
messages:
|
||||
success: Thank you for your donation!
|
||||
type: "Type"
|
||||
types:
|
||||
once: "Once"
|
||||
weekly: "Weekly"
|
||||
monthly: "Monthly"
|
||||
yearly: "Yearly"
|
||||
period:
|
||||
once: "once."
|
||||
weekly: "every week on {{anchor}}."
|
||||
monthly: "on the {{anchor}} of every month."
|
||||
yearly: "every year on {{anchor}}."
|
||||
|
|
|
@ -50,3 +50,12 @@ plugins:
|
|||
default: '1|2|5|10|20|50'
|
||||
regex: "^[0-9\\|]+$"
|
||||
regex_error: "site_settings.errors.discourse_donations_amount_must_be_number"
|
||||
discourse_donations_types:
|
||||
client: true
|
||||
type: list
|
||||
default: 'monthly|once'
|
||||
choices:
|
||||
- yearly
|
||||
- monthly
|
||||
- weekly
|
||||
- once
|
||||
|
|
Loading…
Reference in New Issue