billingly 0.1.10 → 0.1.11

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -34,5 +34,5 @@ Billingly does not receive payments directly (from Paypal, or Worldpay for examp
34
34
  * Explore the [Docs](http://rubydoc.info/github/nubis/billingly/master/frames/file/README.md).
35
35
 
36
36
  # License
37
- MIT License. Copyright 2012 Nubis (nubis@woobiz.com.ar)
37
+ MIT License. Copyright 2012 Nubis (yo@nubis.im)
38
38
 
@@ -0,0 +1,7 @@
1
+ # (see Billingly::RedemptionsControllerBase)
2
+ class Billingly::RedemptionsController < Billingly::RedemptionsControllerBase
3
+
4
+ def on_redemption_by_non_customer
5
+ redirect_to subscriptions_path
6
+ end
7
+ end
@@ -0,0 +1,47 @@
1
+ # People who have a {Billingly::SpecialPlanCode SpecialPlanCode} can redeem it through
2
+ # the {Billingly::RedemptionsController}
3
+ class Billingly::RedemptionsControllerBase < ::ApplicationController
4
+ def new
5
+ end
6
+
7
+ def create
8
+ code = Billingly::SpecialPlanCode.find_redeemable(params[:promo_code])
9
+ if code.nil?
10
+ flash[:invalid_promo_code] = t('billingly.promo_codes.invalid')
11
+ redirect_to new_redemption_path
12
+ return
13
+ end
14
+
15
+ unless current_customer
16
+ session[:current_promo_code] = params[:promo_code]
17
+ on_redemption_by_non_customer
18
+ return
19
+ end
20
+
21
+ unless current_customer.can_subscribe_to?(code.plan)
22
+ flash[:invalid_promo_code_plan] = t('billingly.promo_codes.cannot_subscribe_to_plan')
23
+ redirect_to new_redemption_path
24
+ return
25
+ end
26
+
27
+ current_customer.redeem_special_plan_code(code)
28
+ on_redemption
29
+ end
30
+
31
+ # When a code is redeemed successfully by the current customer this callback is called.
32
+ # The default behavior is redirecting to the subscriptions index page.
33
+ def on_redemption
34
+ redirect_to subscriptions_path, notice: t('billingly.promo_codes.redeemed_successfully')
35
+ end
36
+
37
+ # The redemptions page is public, therefore there may be people redeeming valid codes
38
+ # without being a customer.
39
+ #
40
+ # In such cases, the validated code is stored in the session and this callback is called.
41
+ # You should redirect to your signup page here, and subscribe the customer using the saved
42
+ # code after they sign up.
43
+ # The code and plan associated to this code can be retrieved using {#current_promo_code}
44
+ # and {#current_promo_code_plan}
45
+ def on_redemption_by_non_customer
46
+ end
47
+ end
@@ -8,7 +8,7 @@ class Billingly::SubscriptionsController < ::ApplicationController
8
8
  # It's likely the only reachable page for deactivated customers.
9
9
  def index
10
10
  @subscription = current_customer.active_subscription
11
- @plans = Billingly::Plan.all
11
+ @plans = Billingly::Plan.where('hidden = false')
12
12
  @invoices = current_customer.invoices.order('created_at DESC')
13
13
  end
14
14
 
@@ -133,10 +133,9 @@ module Billingly
133
133
 
134
134
  # Customers can subscribe to a plan using a special subscription code which would
135
135
  # allow them to access an otherwise hidden plan.
136
- # @param code [String] The 13 digit EAN-13 code being redeemed
137
- def redeem_special_plan_code(code_string)
138
- code = Billingly::SpecialPlanCode.find_by_code(code_string)
139
- return if code.nil?
136
+ # The {SpecialPlanCode} can also contain an amount to be redeemed.
137
+ # @param code [SpecialPlanCode] The code being redeemed.
138
+ def redeem_special_plan_code(code)
140
139
  return if code.redeemed?
141
140
  credit_payment(code.bonus_amount) if code.bonus_amount
142
141
  subscribe_to_plan(code.plan)
@@ -5,7 +5,7 @@ module Billingly
5
5
  self.table_name = 'billingly_plans'
6
6
 
7
7
  attr_accessible :name, :plan_code, :description, :periodicity,
8
- :amount, :payable_upfront, :grace_period
8
+ :amount, :payable_upfront, :grace_period, :hidden
9
9
 
10
10
  has_duration :grace_period
11
11
  validates :grace_period, presence: true
@@ -57,4 +57,12 @@ class Billingly::SpecialPlanCode < ActiveRecord::Base
57
57
  def self.cleanup_exported_files
58
58
  `rm #{File.expand_path('~/ean_13_codes_for_*.csv')}`
59
59
  end
60
+
61
+ # Shorthand finder for a redeemable code.
62
+ # This means that the code exists and has not been redeemed yet.
63
+ # @param code [String] The code to lookup.
64
+ # @return [SpecialPlanCode, nil] the SpecialPlanCode instance, or nothing.
65
+ def self.find_redeemable(code)
66
+ self.find_by_code_and_redeemed_on(code, nil)
67
+ end
60
68
  end
@@ -0,0 +1,6 @@
1
+ .span4.offset4
2
+ .well
3
+ %h3 Enter your Promo Code
4
+ = form_tag redemptions_path, :class => 'form-inline' do
5
+ = text_field_tag :promo_code, params[:promo_code], :class => 'input-large', :placeholder => 'Promo Code'
6
+ = submit_tag 'Redeem!', :class => 'btn btn-success btn-large'
@@ -1,5 +1,9 @@
1
1
  en:
2
2
  billingly:
3
+ promo_codes:
4
+ redeemed_successfully: Your promo code has been redeemed!
5
+ invalid: The promo code you entered was invalid
6
+ cannot_subscribe_to_plan: You can't subscribe to the plan provided by your promo code
3
7
  your_account_was_suspended: Your account was suspended
4
8
  your_invoice_is_available: Your invoice is available
5
9
  payment_receipt: Payment Receipt
@@ -33,6 +33,21 @@ module Billingly
33
33
  redirect_to(subscriptions_path)
34
34
  end
35
35
  end
36
+
37
+ # When an anonymous user redeems a {SpecialPlanCode} the code is stored
38
+ # in the session. You should first sign them up and then subscribe them
39
+ # using the code they previously redeemed.
40
+ # @return [SpecialPlanCode] The instance for the code they redeemed.
41
+ def current_promo_code
42
+ @current_promo_code ||=
43
+ Billingly::SpecialPlanCode.find_redeemable(session[:current_promo_code])
44
+ end
45
+
46
+ # Shortcut for getting the plan for the current promo code, if any.
47
+ # @return [Billingly::Plan] The plan referred to by the current code.
48
+ def current_promo_code_plan
49
+ @current_promo_code.plan if @current_promo_code
50
+ end
36
51
  end
37
52
 
38
53
  helper_method :current_customer
@@ -8,6 +8,8 @@ class ActionDispatch::Routing::Mapper
8
8
  post :deactivate
9
9
  end
10
10
  end
11
+ resources :redemptions, controller: 'billingly/redemptions', only: [:new, :create]
12
+ get 'redeem' => "billingly/redemptions#new"
11
13
  end
12
14
  if skope then scope(skope, as: skope, &route) else route.call end
13
15
  end
@@ -1,3 +1,3 @@
1
1
  module Billingly
2
- VERSION = "0.1.10"
2
+ VERSION = "0.1.11"
3
3
  end
@@ -63,7 +63,7 @@ class CreateBillinglyTables < ActiveRecord::Migration
63
63
  t.boolean 'payable_upfront', null: false
64
64
  t.string 'grace_period', null: false
65
65
  t.integer 'signup_price'
66
- t.boolean 'hidden_on'
66
+ t.boolean 'hidden', default: false, null: false
67
67
  t.timestamps
68
68
  end
69
69
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: billingly
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.10
4
+ version: 0.1.11
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-11-05 00:00:00.000000000 Z
12
+ date: 2012-11-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
16
- requirement: &70101883663420 !ruby/object:Gem::Requirement
16
+ requirement: &70200335482980 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 3.2.0
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70101883663420
24
+ version_requirements: *70200335482980
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: validates_email_format_of
27
- requirement: &70101883679240 !ruby/object:Gem::Requirement
27
+ requirement: &70200335482480 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70101883679240
35
+ version_requirements: *70200335482480
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: has_duration
38
- requirement: &70101883678660 !ruby/object:Gem::Requirement
38
+ requirement: &70200335481840 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *70101883678660
46
+ version_requirements: *70200335481840
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: ean13
49
- requirement: &70101883678160 !ruby/object:Gem::Requirement
49
+ requirement: &70200335481100 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '0'
55
55
  type: :runtime
56
56
  prerelease: false
57
- version_requirements: *70101883678160
57
+ version_requirements: *70200335481100
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: timecop
60
- requirement: &70101883677620 !ruby/object:Gem::Requirement
60
+ requirement: &70200335496720 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: '0'
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *70101883677620
68
+ version_requirements: *70200335496720
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: sqlite3
71
- requirement: &70101883677080 !ruby/object:Gem::Requirement
71
+ requirement: &70200335496140 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: '0'
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *70101883677080
79
+ version_requirements: *70200335496140
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: rspec-rails
82
- requirement: &70101883676580 !ruby/object:Gem::Requirement
82
+ requirement: &70200335495700 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ! '>='
@@ -87,10 +87,10 @@ dependencies:
87
87
  version: '0'
88
88
  type: :development
89
89
  prerelease: false
90
- version_requirements: *70101883676580
90
+ version_requirements: *70200335495700
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: factory_girl_rails
93
- requirement: &70101883676080 !ruby/object:Gem::Requirement
93
+ requirement: &70200335495240 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - ! '>='
@@ -98,7 +98,18 @@ dependencies:
98
98
  version: '0'
99
99
  type: :development
100
100
  prerelease: false
101
- version_requirements: *70101883676080
101
+ version_requirements: *70200335495240
102
+ - !ruby/object:Gem::Dependency
103
+ name: capybara
104
+ requirement: &70200335494780 !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: *70200335494780
102
113
  description: Rails Engine for SaaS subscription management. Manage subscriptions,
103
114
  plan changes, free trials and more!!!
104
115
  email:
@@ -107,6 +118,8 @@ executables: []
107
118
  extensions: []
108
119
  extra_rdoc_files: []
109
120
  files:
121
+ - app/controllers/billingly/redemptions_controller.rb
122
+ - app/controllers/billingly/redemptions_controller_base.rb
110
123
  - app/controllers/billingly/subscriptions_controller.rb
111
124
  - app/mailers/billingly/base_mailer.rb
112
125
  - app/mailers/billingly/mailer.rb
@@ -126,6 +139,7 @@ files:
126
139
  - app/views/billingly/mailer/pending_notification.html.erb
127
140
  - app/views/billingly/mailer/task_results.html.erb
128
141
  - app/views/billingly/mailer/trial_expired_notification.html.erb
142
+ - app/views/billingly/redemptions/new.html.haml
129
143
  - app/views/billingly/subscriptions/_current_subscription.html.haml
130
144
  - app/views/billingly/subscriptions/_deactivation_notice.html.haml
131
145
  - app/views/billingly/subscriptions/_invoice_details.html.haml