saasaparilla 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. data/.gitignore +13 -0
  2. data/.rspec +2 -0
  3. data/Gemfile +36 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.rdoc +3 -0
  6. data/Rakefile +39 -0
  7. data/app/controllers/saasaparilla/admin/plans_controller.rb +87 -0
  8. data/app/controllers/saasaparilla/admin/subscriptions_controller.rb +34 -0
  9. data/app/controllers/saasaparilla/admin/transactions_controller.rb +14 -0
  10. data/app/controllers/saasaparilla/application_controller.rb +4 -0
  11. data/app/controllers/saasaparilla/billing_history_controller.rb +9 -0
  12. data/app/controllers/saasaparilla/contact_info_controller.rb +31 -0
  13. data/app/controllers/saasaparilla/credit_card_controller.rb +41 -0
  14. data/app/controllers/saasaparilla/invoices_controller.rb +19 -0
  15. data/app/controllers/saasaparilla/payments_controller.rb +71 -0
  16. data/app/controllers/saasaparilla/plans_controller.rb +34 -0
  17. data/app/controllers/saasaparilla/subscription_controller.rb +71 -0
  18. data/app/helpers/application_helper.rb +3 -0
  19. data/app/helpers/plans_helper.rb +2 -0
  20. data/app/helpers/saasaparilla/billing_history_helper.rb +4 -0
  21. data/app/mailers/saasaparilla/notifier.rb +38 -0
  22. data/app/models/billing_activity.rb +12 -0
  23. data/app/models/contact_info.rb +107 -0
  24. data/app/models/credit_card.rb +109 -0
  25. data/app/models/invoice.rb +31 -0
  26. data/app/models/invoice_line_item.rb +3 -0
  27. data/app/models/payment.rb +39 -0
  28. data/app/models/plan.rb +36 -0
  29. data/app/models/subscription.rb +363 -0
  30. data/app/models/transaction.rb +32 -0
  31. data/app/views/layouts/saasaparilla.html.haml +9 -0
  32. data/app/views/saasaparilla/admin/plans/_form.html.haml +45 -0
  33. data/app/views/saasaparilla/admin/plans/edit.html.erb +4 -0
  34. data/app/views/saasaparilla/admin/plans/index.html.erb +31 -0
  35. data/app/views/saasaparilla/admin/plans/new.html.haml +4 -0
  36. data/app/views/saasaparilla/admin/plans/show.html.haml +20 -0
  37. data/app/views/saasaparilla/admin/subscriptions/_subscription.html.haml +7 -0
  38. data/app/views/saasaparilla/admin/subscriptions/index.html.haml +14 -0
  39. data/app/views/saasaparilla/admin/subscriptions/show.html.haml +52 -0
  40. data/app/views/saasaparilla/admin/transactions/_transaction.html.haml +6 -0
  41. data/app/views/saasaparilla/admin/transactions/index.html.haml +16 -0
  42. data/app/views/saasaparilla/billing_history/_billing_activity.html.haml +10 -0
  43. data/app/views/saasaparilla/billing_history/show.html.haml +11 -0
  44. data/app/views/saasaparilla/contact_info/edit.html.haml +8 -0
  45. data/app/views/saasaparilla/credit_card/edit.html.haml +18 -0
  46. data/app/views/saasaparilla/invoices/show.html.haml +17 -0
  47. data/app/views/saasaparilla/notifier/billing_failed.html.haml +5 -0
  48. data/app/views/saasaparilla/notifier/billing_successful.html.haml +5 -0
  49. data/app/views/saasaparilla/notifier/invoice_created.html.haml +24 -0
  50. data/app/views/saasaparilla/notifier/pending_cancellation_notice.html.haml +6 -0
  51. data/app/views/saasaparilla/notifier/subscription_canceled.html.haml +4 -0
  52. data/app/views/saasaparilla/notifier/subscription_created.html.haml +5 -0
  53. data/app/views/saasaparilla/payments/edit.html.haml +10 -0
  54. data/app/views/saasaparilla/payments/new.html.haml +10 -0
  55. data/app/views/saasaparilla/payments/show.html.haml +8 -0
  56. data/app/views/saasaparilla/plans/edit.html.haml +34 -0
  57. data/app/views/saasaparilla/subscription/_contact_info_form.html.haml +19 -0
  58. data/app/views/saasaparilla/subscription/_credit_card_form.html.haml +10 -0
  59. data/app/views/saasaparilla/subscription/new.html.haml +24 -0
  60. data/app/views/saasaparilla/subscription/show.html.haml +73 -0
  61. data/autotest/discover.rb +2 -0
  62. data/config/routes.rb +27 -0
  63. data/lib/country_select/MIT-LICENSE +20 -0
  64. data/lib/country_select/README +15 -0
  65. data/lib/country_select/init.rb +1 -0
  66. data/lib/country_select/install.rb +2 -0
  67. data/lib/country_select/lib/country_select.rb +88 -0
  68. data/lib/country_select/uninstall.rb +1 -0
  69. data/lib/extensions/action_controller/base.rb +7 -0
  70. data/lib/extensions/active_record/nested_attributes.rb +36 -0
  71. data/lib/extensions/active_record/statuses.rb +16 -0
  72. data/lib/extensions/billable.rb +12 -0
  73. data/lib/generators/saasaparilla/install/install_generator.rb +29 -0
  74. data/lib/generators/saasaparilla/install/templates/create_saasaparilla_tables.rb +106 -0
  75. data/lib/generators/saasaparilla/install/templates/saasaparilla.yml +32 -0
  76. data/lib/initializers/auth_dot_net.rb +25 -0
  77. data/lib/initializers/simple_form.rb +77 -0
  78. data/lib/initializers/time_format.rb +3 -0
  79. data/lib/saasaparilla.rb +16 -0
  80. data/lib/saasaparilla/authentication.rb +18 -0
  81. data/lib/saasaparilla/authorization.rb +26 -0
  82. data/lib/saasaparilla/engine.rb +30 -0
  83. data/lib/saasaparilla/version.rb +3 -0
  84. data/saasaparilla.gemspec +48 -0
  85. data/spec/.livereload +21 -0
  86. data/spec/dummy/Rakefile +7 -0
  87. data/spec/dummy/app/controllers/application_controller.rb +11 -0
  88. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  89. data/spec/dummy/app/model/user.rb +4 -0
  90. data/spec/dummy/app/views/layouts/application.html.erb +15 -0
  91. data/spec/dummy/config.ru +4 -0
  92. data/spec/dummy/config/application.rb +46 -0
  93. data/spec/dummy/config/boot.rb +10 -0
  94. data/spec/dummy/config/database.yml +22 -0
  95. data/spec/dummy/config/environment.rb +5 -0
  96. data/spec/dummy/config/environments/development.rb +30 -0
  97. data/spec/dummy/config/environments/production.rb +49 -0
  98. data/spec/dummy/config/environments/test.rb +39 -0
  99. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  100. data/spec/dummy/config/initializers/inflections.rb +10 -0
  101. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  102. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  103. data/spec/dummy/config/initializers/session_store.rb +8 -0
  104. data/spec/dummy/config/initializers/simple_form.rb +77 -0
  105. data/spec/dummy/config/locales/en.yml +5 -0
  106. data/spec/dummy/config/locales/simple_form.en.yml +24 -0
  107. data/spec/dummy/config/routes.rb +58 -0
  108. data/spec/dummy/config/saasaparilla.yml +32 -0
  109. data/spec/dummy/lib/templates/erb/scaffold/_form.html.erb +13 -0
  110. data/spec/dummy/public/404.html +26 -0
  111. data/spec/dummy/public/422.html +26 -0
  112. data/spec/dummy/public/500.html +26 -0
  113. data/spec/dummy/public/favicon.ico +0 -0
  114. data/spec/dummy/public/index.html +0 -0
  115. data/spec/dummy/public/javascripts/application.js +2 -0
  116. data/spec/dummy/public/javascripts/jquery.js +8374 -0
  117. data/spec/dummy/public/javascripts/jquery.min.js +16 -0
  118. data/spec/dummy/public/javascripts/rails.js +159 -0
  119. data/spec/dummy/public/stylesheets/.gitkeep +0 -0
  120. data/spec/dummy/script/rails +6 -0
  121. data/spec/dummy/vendor/plugins/active_merchant_testing/MIT-LICENSE +20 -0
  122. data/spec/dummy/vendor/plugins/active_merchant_testing/README +32 -0
  123. data/spec/dummy/vendor/plugins/active_merchant_testing/Rakefile +23 -0
  124. data/spec/dummy/vendor/plugins/active_merchant_testing/init.rb +1 -0
  125. data/spec/dummy/vendor/plugins/active_merchant_testing/install.rb +1 -0
  126. data/spec/dummy/vendor/plugins/active_merchant_testing/lib/authorize_net_cim_gateway_test.rb +492 -0
  127. data/spec/dummy/vendor/plugins/active_merchant_testing/lib/authorize_net_gateway_test.rb +133 -0
  128. data/spec/dummy/vendor/plugins/active_merchant_testing/lib/paypal_express_gateway_test.rb +138 -0
  129. data/spec/dummy/vendor/plugins/active_merchant_testing/tasks/activemerchant_testing_tasks.rake +4 -0
  130. data/spec/dummy/vendor/plugins/active_merchant_testing/test/activemerchant_testing_test.rb +8 -0
  131. data/spec/dummy/vendor/plugins/active_merchant_testing/test/test_helper.rb +3 -0
  132. data/spec/dummy/vendor/plugins/active_merchant_testing/uninstall.rb +1 -0
  133. data/spec/factories/factories.rb +75 -0
  134. data/spec/integration/navigation_spec.rb +9 -0
  135. data/spec/mailers/notifier_spec.rb +167 -0
  136. data/spec/models/billing_activity_spec.rb +27 -0
  137. data/spec/models/contact_info_spec.rb +32 -0
  138. data/spec/models/credit_card_spec.rb +57 -0
  139. data/spec/models/invoice_line_item_spec.rb +7 -0
  140. data/spec/models/invoice_spec.rb +25 -0
  141. data/spec/models/payment_spec.rb +29 -0
  142. data/spec/models/plan_spec.rb +16 -0
  143. data/spec/models/subscription_spec.rb +414 -0
  144. data/spec/requests/admin_plans_spec.rb +32 -0
  145. data/spec/requests/admin_subscriptions_spec.rb +31 -0
  146. data/spec/requests/billing_history_spec.rb +26 -0
  147. data/spec/requests/contact_info_controller_spec.rb +42 -0
  148. data/spec/requests/credit_cards_spec.rb +79 -0
  149. data/spec/requests/invoices_spec.rb +23 -0
  150. data/spec/requests/payments_spec.rb +89 -0
  151. data/spec/requests/subscription_plans_spec.rb +34 -0
  152. data/spec/requests/subscriptions_spec.rb +80 -0
  153. data/spec/spec_helper.rb +68 -0
  154. data/spec/spec_helpers/spec_helpers.rb +8 -0
  155. metadata +611 -0
@@ -0,0 +1,71 @@
1
+ class Saasaparilla::SubscriptionController < ApplicationController
2
+ unloadable
3
+ ssl_required :new, :create, :show
4
+ include Authentication::InstanceMethods
5
+ before_filter :get_subscription, :only => [:show, :destroy, :reactivate]
6
+
7
+ before_filter :require_no_subscription, :only => [:new]
8
+ #overide with authorization
9
+ def new
10
+ @subscription = current_billable.build_subscription
11
+ @subscription.build_contact_info
12
+ @subscription.build_credit_card
13
+ end
14
+
15
+ def create
16
+ @subscription = current_billable.build_subscription(params[:subscription])
17
+
18
+ begin
19
+ if @subscription.save
20
+ redirect_to subscription_path
21
+ flash[:notice] = "Your subscription was successfully created."
22
+ else
23
+ render :action => "new"
24
+ flash[:error] = "Your subscription could not be created due to errors. Please review the form and correct them."
25
+ end
26
+ rescue Exception => e
27
+ flash[:error] = e.message
28
+ render :action => "new"
29
+ flash.discard
30
+ end
31
+ end
32
+
33
+ def show
34
+
35
+ end
36
+
37
+ def reactivate
38
+ if @subscription.reactivate!
39
+ redirect_to subscription_path
40
+ flash[:notice] = "Your subscription was successfully reactivated."
41
+ else
42
+ redirect_to subscription_path
43
+ flash[:error] = "There was a problem reactivating your account."
44
+ end
45
+ end
46
+
47
+ def destroy
48
+ if @subscription.cancel
49
+ flash[:notice] = "Your subscription has been canceled."
50
+ redirect_to subscription_path
51
+
52
+ end
53
+ end
54
+
55
+ private
56
+ def require_no_subscription
57
+ unless current_billable.subscription.nil?
58
+ flash[:error] = "You already have a subscription"
59
+ redirect_to subscription_path
60
+ end
61
+ end
62
+ def get_subscription
63
+ @subscription = current_billable.subscription
64
+ if @subscription.nil?
65
+ flash[:error] = "You do not have a current subscription"
66
+ redirect_to new_subscription_path
67
+ end
68
+ end
69
+
70
+
71
+ end
@@ -0,0 +1,3 @@
1
+ module ApplicationHelper
2
+
3
+ end
@@ -0,0 +1,2 @@
1
+ module PlansHelper
2
+ end
@@ -0,0 +1,4 @@
1
+ module Saasaparilla::BillingHistoryHelper
2
+
3
+
4
+ end
@@ -0,0 +1,38 @@
1
+ class Saasaparilla::Notifier < ActionMailer::Base
2
+ default :from => Saasaparilla::CONFIG["from_email"]
3
+
4
+ def subscription_created(subscription)
5
+ @subscription = subscription
6
+ mail(:to => subscription.contact_info.email, :subject => "Subscription Created")
7
+ end
8
+
9
+ def invoice_created(subscription, invoice)
10
+ @subscription = subscription
11
+ @invoice = invoice
12
+ mail(:to => subscription.contact_info.email, :subject => "Invoice Created")
13
+ end
14
+
15
+ def billing_successful(subscription, amount)
16
+ @subscription = subscription
17
+ @amount = amount
18
+ mail(:to => subscription.contact_info.email, :subject => "Account Billing Successful")
19
+ end
20
+
21
+ def billing_failed(subscription)
22
+ @subscription = subscription
23
+ @url = edit_subscription_credit_card_url
24
+ mail(:to => subscription.contact_info.email, :subject => "Account Billing Failed")
25
+ end
26
+
27
+ def pending_cancellation_notice(subscription)
28
+ @subscription = subscription
29
+ @url = edit_subscription_credit_card_url
30
+ mail(:to => subscription.contact_info.email, :subject => "Your subscription will be canceled soon")
31
+ end
32
+
33
+ def subscription_canceled(subscription)
34
+ @subscription = subscription
35
+ mail(:to => subscription.contact_info.email, :subject => "Your subscription has been canceled")
36
+ end
37
+
38
+ end
@@ -0,0 +1,12 @@
1
+ class BillingActivity < ActiveRecord::Base
2
+ belongs_to :subscription
3
+ has_one :invoice
4
+ has_one :transaction
5
+
6
+ MESSAGES = {:success => "Thank you for your payment."}
7
+ scope :recent, order("created_at DESC")
8
+
9
+ scope :limit, lambda {|num|
10
+ limit(num)
11
+ }
12
+ end
@@ -0,0 +1,107 @@
1
+ class ContactInfo < ActiveRecord::Base
2
+
3
+ belongs_to :subscription, :dependent => :destroy
4
+ validates_presence_of :first_name, :last_name
5
+ validates_format_of :email, :with => ::Authlogic::Regex.email
6
+ validates_presence_of :email
7
+
8
+ with_options :if => :require_billing_address? do |contact_info|
9
+ contact_info.validates_presence_of :address
10
+ contact_info.validates_presence_of :city
11
+ contact_info.validates_presence_of :state
12
+ contact_info.validates_presence_of :zip
13
+ contact_info.validates_presence_of :country
14
+ contact_info.validates_format_of :zip, :with => /^\d{5}$/
15
+ end
16
+
17
+ with_options :if => :require_phone_number? do |contact_info|
18
+ contact_info.validates_numericality_of :phone_area_code
19
+ contact_info.validates_numericality_of :phone_prefix
20
+ contact_info.validates_numericality_of :phone_suffix
21
+ contact_info.validates_length_of :phone_area_code, :is => 3
22
+ contact_info.validates_length_of :phone_prefix, :is => 3
23
+ contact_info.validates_length_of :phone_suffix, :is => 4
24
+ contact_info.validates_format_of :phone_number, :with => /\d\d\d-\d\d\d-\d\d\d\d/
25
+ contact_info.before_validation :update_phone_number
26
+ end
27
+
28
+ attr_accessor :phone_area_code, :phone_prefix, :phone_suffix
29
+
30
+ def phone_area_code
31
+ self.phone_number.split('-')[0] if self.phone_number
32
+ end
33
+
34
+ def phone_prefix
35
+ self.phone_number.split('-')[1] if self.phone_number
36
+ end
37
+
38
+ def phone_suffix
39
+ self.phone_number.split('-')[2] if self.phone_number
40
+ end
41
+
42
+ def full_name
43
+ "#{first_name} #{last_name}"
44
+ end
45
+
46
+ def to_hash
47
+ return {:first_name => first_name,
48
+ :last_name => last_name,
49
+ :address => address,
50
+ :company => company,
51
+ :city => city,
52
+ :state => state,
53
+ :zip => zip,
54
+ :country => "US",
55
+ :phone_number => phone_number}
56
+ end
57
+
58
+
59
+ def require_billing_address?
60
+ Saasaparilla::CONFIG["require_billing_address"] == true
61
+ end
62
+
63
+ def require_phone_number?
64
+ Saasaparilla::CONFIG["require_phone_number"] == true
65
+ end
66
+
67
+ private
68
+
69
+ def update_phone_number
70
+ if @phone_area_code && @phone_prefix && @phone_suffix
71
+ self.phone_number = "#{@phone_area_code}-#{@phone_prefix}-#{@phone_suffix}"
72
+ end
73
+ end
74
+
75
+
76
+
77
+
78
+ # def validate_phone_number
79
+ # return_value = true
80
+ # unless self.phone_area_code.length == 3
81
+ # self.errors.add(:base, "Area code must be three digits.")
82
+ # return_value = false
83
+ # end
84
+ # unless (/[0-9]/).match(self.phone_area_code)
85
+ # self.errors.add(:base, "Area code must be numbers only.")
86
+ # return_value = false
87
+ # end
88
+ # unless self.phone_prefix.length == 3
89
+ # self.errors.add(:base, "Phone prefix must be three digits.")
90
+ # return_value = false
91
+ # end
92
+ # unless (/[0-9]/).match(self.phone_prefix)
93
+ # self.errors.add(:base, "Phone prefix must be numbers only.")
94
+ # return_value = false
95
+ # end
96
+ # unless self.phone_suffix.length == 4
97
+ # self.errors.add(:base, "Phone suffix must be four digits.")
98
+ # return_value = false
99
+ # end
100
+ # unless (/[0-9]/).match(self.phone_suffix)
101
+ # self.errors.add(:base, "Phone suffix must be numbers only.")
102
+ # return_value = false
103
+ # end
104
+ # return_value
105
+ # end
106
+
107
+ end
@@ -0,0 +1,109 @@
1
+ class CreditCard < ActiveRecord::Base
2
+
3
+ before_validation :set_first_last_name, :on => :update
4
+ validate :validate_card
5
+ validates_presence_of :card_verification
6
+ validates_presence_of :first_name
7
+ validates_presence_of :last_name, :message => "can't be blank"
8
+ validates_presence_of :card_type, :message => "can't be blank"
9
+ validates_presence_of :card_number, :message => "can't be blank"
10
+ validates_presence_of :expiry_month, :message => "can't be blank"
11
+ validates_presence_of :expiry_year, :message => "can't be blank"
12
+ validates_numericality_of :expiry_month, :message => "is not a number"
13
+ validates_numericality_of :expiry_year, :message => "is not a number"
14
+
15
+ attr_accessor :card_type, :card_verification, :expiry_month, :expiry_year, :first_name, :last_name
16
+ CARD_TYPES = [["Visa", "Visa"], ["Mastercard", "Mastercard"], ["American Express", "American Express" ], ["Discover", "Discover"]]
17
+
18
+ MONTHS = (1..12).to_a
19
+ YEARS = ((Date.today.year)..(Date.today.year + 8)).to_a
20
+
21
+ belongs_to :subscription
22
+
23
+ before_save :mask_card_number
24
+ before_save :create_expiration_date
25
+ before_save :update_payment_profile
26
+
27
+
28
+ def validate_card
29
+ unless active_merchant_card.valid?
30
+ active_merchant_card.errors.full_messages.each do |message|
31
+ case message
32
+ when "First name connot be empty"
33
+ errors[:card_name] = "cannot be empty"
34
+ when "Last name cannot be empty"
35
+ errors[:card_name] = "cannot be empty"
36
+ when "Month is not a valid month"
37
+ errors[:expiry_month] = "Month is not a valid month"
38
+ when "Year expired"
39
+ errors[:expiry_year] = "Year expired"
40
+ when "Number is not a valid credit card number"
41
+ errors[:card_number] = "is not a valid credit card number"
42
+ when "Verification value is required"
43
+ errors[:card_verification] = "value is required"
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+ def active_merchant_card
50
+ @card_attributes ||= ActiveMerchant::Billing::CreditCard.new(
51
+ :type => card_type,
52
+ :number => card_number,
53
+ :verification_value => card_verification,
54
+ :month => expiry_month,
55
+ :year => expiry_year,
56
+ :first_name => first_name,
57
+ :last_name => last_name
58
+ )
59
+ end
60
+
61
+ def card_attributes=(cstring)
62
+ @card_attributes = cstring
63
+ end
64
+
65
+
66
+ private
67
+
68
+
69
+ def create_expiration_date
70
+ self.expiration_date = "#{expiry_month}/#{expiry_year}"
71
+ end
72
+
73
+
74
+ def mask_card_number
75
+
76
+ length = card_number.length
77
+ masked_number = ""
78
+ (1..(length - 4)).each do
79
+ masked_number << "X"
80
+ end
81
+ masked_number << card_number[length - 4, length]
82
+ self.card_number = masked_number
83
+ end
84
+
85
+ def update_payment_profile
86
+
87
+ unless new_record?
88
+ @profile = {:customer_profile_id => subscription.customer_cim_id,
89
+ :payment_profile => {:customer_payment_profile_id => subscription.customer_payment_profile_id,
90
+ :bill_to => subscription.contact_info.to_hash,
91
+ :payment => {:credit_card => active_merchant_card}
92
+ }
93
+ }
94
+ response = GATEWAYCIM.update_customer_payment_profile(@profile)
95
+ if response.success?
96
+ return true
97
+ else
98
+ raise response.message
99
+ return false
100
+ end
101
+ end
102
+ end
103
+
104
+ def set_first_last_name
105
+ self.first_name = subscription.contact_info.first_name
106
+ self.last_name = subscription.contact_info.last_name
107
+ end
108
+
109
+ end
@@ -0,0 +1,31 @@
1
+ class Invoice < ActiveRecord::Base
2
+ belongs_to :billing_activity
3
+ has_many :invoice_line_items
4
+
5
+ after_create :create_invoice_line_item
6
+ after_create :generate_billing_activity
7
+ after_create :send_invoice_created_email
8
+ attr_accessor :subscription, :price, :from, :to
9
+
10
+
11
+ def amount
12
+ invoice_line_items.sum(:price)
13
+ end
14
+
15
+ private
16
+
17
+
18
+ def create_invoice_line_item
19
+ self.invoice_line_items.create(:price => price, :from => from, :to => to )
20
+ end
21
+
22
+
23
+ def generate_billing_activity
24
+ self.create_billing_activity(:message => "<a href='/subscription/invoices/#{self.id}'>Invoice</a>", :subscription => subscription, :amount => amount, :invoice => self)
25
+ end
26
+
27
+ def send_invoice_created_email
28
+ Saasaparilla::Notifier.invoice_created(billing_activity.subscription, self).deliver
29
+ end
30
+
31
+ end
@@ -0,0 +1,3 @@
1
+ class InvoiceLineItem < ActiveRecord::Base
2
+ belongs_to :invoice
3
+ end
@@ -0,0 +1,39 @@
1
+ class Payment < ActiveRecord::Base
2
+ before_validation :set_status_pending, :on => :create
3
+ before_update :charge_subscription
4
+ validate :valid_amount
5
+ validates_presence_of :subscription_id
6
+ validates_presence_of :amount, :message => "can't be blank"
7
+ validates_numericality_of :amount
8
+ has_statuses "pending", "paid", "failed"
9
+ belongs_to :subscription
10
+
11
+
12
+
13
+
14
+ def valid_amount
15
+ if amount < 0
16
+ errors[:amount] = "cannot be less than 0"
17
+ end
18
+ if amount > subscription.balance
19
+ errors[:amount] = "cannot be more than your balance"
20
+ end
21
+ if amount == 0
22
+ errors[:amount] = "cannot be zero"
23
+ end
24
+ end
25
+
26
+
27
+ private
28
+
29
+ def charge_subscription
30
+
31
+ if subscription.bill!(amount)
32
+ self.status = "paid"
33
+ end
34
+
35
+ end
36
+ def set_status_pending
37
+ self.status = "pending"
38
+ end
39
+ end
@@ -0,0 +1,36 @@
1
+ class Plan < ActiveRecord::Base
2
+ has_dynamic_attributes
3
+ validates_presence_of :name, :message => "can't be blank"
4
+ validates_presence_of :billing_period, :message => "can't be blank"
5
+ validates_numericality_of :price, :message => "is not a number"
6
+ validates_presence_of :price, :message => "can't be blank"
7
+
8
+ has_many :subscriptions
9
+
10
+ BILLING_PERIODS = ["Monthly", "Annually"]
11
+
12
+ def respond_to?(method_sym, include_private = false)
13
+ @column_names = []
14
+ unless dynamic_attributes.nil?
15
+ dynamic_attributes.each do |dm|
16
+ @column_names << dm[0].gsub("field_", "")
17
+ end
18
+ if @column_names.include? method_sym.to_s
19
+ return true
20
+ end
21
+ end
22
+
23
+ super
24
+ end
25
+
26
+ def method_missing(method, *args)
27
+
28
+ if has_dynamic_attribute?("field_#{method}")
29
+ return self.send("field_#{method}")
30
+ end
31
+ super
32
+ end
33
+
34
+
35
+
36
+ end