Last active
December 17, 2015 03:28
-
-
Save schof/5542970 to your computer and use it in GitHub Desktop.
Basic logic for recurring subscriptions. NOTE: Uses older version of Spree so it needs some tweaks for Spree 2.0
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class CreateSubscriptions < ActiveRecord::Migration | |
def self.up | |
create_table :subscriptions do |t| | |
t.date :start_date | |
t.date :end_date | |
t.integer :duration | |
t.string :interval | |
t.string :state | |
t.references :user | |
t.references :variant | |
t.timestamps | |
end | |
end | |
def self.down | |
drop_table :subscriptions | |
end | |
end | |
class AddSubcriptionIdToPayments < ActiveRecord::Migration | |
def self.up | |
add_column :payments, :subscription_id, :integer | |
end | |
def self.down | |
remove_column :payments, :subscription_id | |
end | |
end | |
class AddFieldsToVariant < ActiveRecord::Migration | |
def self.up | |
add_column :variants, :subscribable, :boolean, :default => false | |
end | |
def self.down | |
remove_column :variants, :subscribable | |
end | |
end | |
class AddCcToSubscription < ActiveRecord::Migration | |
def self.up | |
add_column :subscriptions, :creditcard_id, :integer | |
end | |
def self.down | |
remove_column :subscriptions, :creditcard_id | |
end | |
end | |
class CreateExpiryNotifications < ActiveRecord::Migration | |
def self.up | |
create_table :expiry_notifications do |t| | |
t.integer :subscription_id | |
t.integer :interval | |
t.timestamps | |
end | |
end | |
def self.down | |
drop_table :expiry_notifications | |
end | |
end | |
class AddPaymentProfileKeyToSubscription < ActiveRecord::Migration | |
def self.up | |
add_column :subscriptions, :payment_profile_key, :string | |
end | |
def self.down | |
remove_column :subscriptions, :payment_profile_key | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class ExpiryNotification < ActiveRecord::Base | |
belongs_to :subscription | |
end | |
class Subscription < ActiveRecord::Base | |
belongs_to :user | |
belongs_to :variant | |
belongs_to :creditcard | |
has_many :payments, :dependent => :destroy, :order => :created_at | |
has_many :expiry_notifications | |
before_save :set_dates | |
state_machine :state, :initial => 'active' do | |
event :cancel do | |
transition :to => 'canceled', :if => :allow_cancel? | |
end | |
event :expire do | |
transition :to => 'expired', :from => 'active' | |
end | |
event :reactivate do | |
transition :to => 'active', :from => 'expired' | |
end | |
end | |
def allow_cancel? | |
self.state != 'canceled' | |
end | |
def due_on | |
self.active? ? self.start_date + eval(self.duration.to_s + "." + self.interval.to_s) : nil | |
end | |
def renew | |
set_dates | |
end | |
private | |
def set_dates | |
self.start_date = Time.now if self.start_date.nil? | |
self.end_date = Time.now + eval(self.duration.to_s + "." + self.interval.to_s) | |
end | |
end | |
class SubscriptionMailer < ActionMailer::QueueMailer | |
helper "spree/base" | |
def paymenet_receipt(subscription) | |
@subject = Spree::Config[:site_name] + ' ' + 'Subscription Renewal #' + subscription.id.to_s | |
@body = {"subscription" => subscription} | |
@recipients = subscription.user.email | |
@from = Spree::Config[:order_from] | |
@sent_on = Time.now | |
end | |
def expiry_warning(subscription, within) | |
@subject = Spree::Config[:site_name] + ' ' + 'Creditcard for Subscription #' + subscription.id.to_s + ' is due to expire' | |
@body = {"subscription" => subscription, "within" => within} | |
@recipients = subscription.user.email | |
@from = Spree::Config[:order_from] | |
@sent_on = Time.now | |
end | |
def creditcard_expired(subscription) | |
@subject = Spree::Config[:site_name] + ' ' + 'Creditcard for Subscription #' + subscription.id.to_s + ' has expired' | |
@body = {"subscription" => subscription} | |
@recipients = subscription.user.email | |
@from = Spree::Config[:order_from] | |
@sent_on = Time.now | |
end | |
def subscription_reactivated(subscription) | |
@subject = Spree::Config[:site_name] + ' ' + 'Subscription #' + subscription.id.to_s + ' has been reactivated' | |
@body = {"subscription" => subscription} | |
@recipients = subscription.user.email | |
@from = Spree::Config[:order_from] | |
@sent_on = Time.now | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
include ActionView::Helpers::DateHelper | |
class SubscriptionManager | |
def SubscriptionManager.process | |
subscriptions = Subscription.find(:all, :conditions => {:state => 'active'}) | |
check_for_renewals(subscriptions) | |
check_for_creditcard_expiry(subscriptions) | |
end | |
def SubscriptionManager.check_for_renewals(subscriptions) | |
subscriptions.each do |sub| | |
next unless sub.due_on.to_time <= Time.now() | |
#subscription due for renewal | |
#re-curring payment | |
amount = sub.variant.price * 100 | |
gateway = Gateway.find(:first, :conditions => {:active => true, :environment => ENV['RAILS_ENV']}) | |
response = gateway.purchase(amount, sub.payment_profile_key) | |
puts response.to_yaml | |
if response.success? | |
payment = CreditcardPayment.create(:subscription => sub, :amount => sub.variant.price, :type => "CreditcardPayment", :creditcard => sub.creditcard) | |
payment.creditcard_txns << CreditcardTxn.new( | |
:amount => amount, | |
:response_code => response.authorization, | |
:txn_type => CreditcardTxn::TxnType::PURCHASE | |
) | |
subscription.payments << payment | |
SubscriptionMailer.deliver_paymenet_receipt(sub) | |
end | |
end | |
end | |
def SubscriptionManager.check_for_creditcard_expiry(subscriptions) | |
subscriptions.each do |sub| | |
next unless sub.creditcard.expiry_date.expiration < (Time.now + 3.months) | |
#checks for credit cards due to expiry with all the following ranges | |
[1.day, 3.days, 1.week, 2.weeks, 3.weeks, 1.month, 2.months, 3.months].each do |interval| | |
within = distance_of_time_in_words(Time.now, Time.now + interval) | |
if sub.creditcard.expiry_date.expiration.to_time < (Time.now + interval) && sub.end_date.to_time > (Time.now + interval) | |
unless ExpiryNotification.exists?(:subscription_id => sub.id, :interval => interval.seconds.to_i) | |
notification = ExpiryNotification.create(:subscription_id => sub.id, :interval => interval.seconds) | |
SubscriptionMailer.deliver_expiry_warning(sub, within) | |
end | |
break | |
end | |
end | |
#final check if credit card has actually expired | |
if sub.creditcard.expiry_date.expiration < Time.now | |
sub.expire | |
SubscriptionMailer.deliver_creditcard_expired(sub) | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment