saasaparilla 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
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,363 @@
1
+ class Subscription < ActiveRecord::Base
2
+
3
+ has_statuses "active", "overdue", "suspended", "pending_cancel", "canceled"
4
+ has_many :transactions
5
+ has_many :payments
6
+ has_one :contact_info
7
+ belongs_to :plan
8
+ belongs_to :downgrade_to_plan, :class_name => "Plan", :foreign_key => :downgrade_to_plan_id
9
+ accepts_nested_attributes_for :contact_info
10
+ has_many :billing_activities
11
+ belongs_to :billable, :polymorphic => true
12
+ has_one :credit_card
13
+ accepts_nested_attributes_for :credit_card
14
+ before_create :create_cim_profile
15
+ before_create :create_payment_profile
16
+ before_validation :set_status, :on => :create
17
+ before_validation :set_credit_card_name
18
+ before_create :set_initial_balance
19
+ after_rollback :delete_profile
20
+ after_create :initial_bill
21
+ after_create :send_subscription_created_email
22
+ after_save :check_if_should_bill_for_upgrade, :on => :update
23
+ validates_presence_of :plan, :message => "can't be blank"
24
+ validates_associated :credit_card, :contact_info, :on => :create
25
+
26
+
27
+ scope :active, where("status != ?", "canceled")
28
+
29
+ scope :all_billable_subscriptions, lambda {|date|
30
+ where("billing_date < ? and balance > 0.0", date.to_time)
31
+ }
32
+
33
+ scope :all_invoiceable, lambda {|date|
34
+ #find all subscriptions not been invoiced within the last month
35
+ where("billing_date <= ? and (invoiced_on > ? OR invoiced_on is null)", date + 5.days, (date - 1.months).to_time)
36
+ }
37
+
38
+ scope :all_paid, where("no_charge != ?", true)
39
+
40
+
41
+ Plan::BILLING_PERIODS.each do |period|
42
+ define_method "#{period.downcase}?" do
43
+ plan.billing_period.downcase == period.downcase
44
+ end
45
+ end
46
+
47
+ ContactInfo.column_names.each do |col|
48
+ unless col.include? "id"
49
+ define_method "#{col}" do
50
+ contact_info.send(col)
51
+ end
52
+ end
53
+ end
54
+
55
+ class << self
56
+ def find_and_bill_recurring_subscriptions
57
+ #find_all_subscriptions need billing
58
+ @billable_subscriptions = Subscription.active.all_paid.all_billable_subscriptions(Date.today)
59
+ for subscription in @billable_subscriptions
60
+
61
+ subscription.downgrade if subscription.downgrade_to_plan.present?
62
+ begin
63
+ subscription.bill!(subscription.balance)
64
+ rescue
65
+ subscription.billing_failed
66
+ end
67
+ end
68
+
69
+ end
70
+
71
+ def find_and_invoice_subscriptions
72
+ @invoiceable_subscriptions = Subscription.active.all_paid.all_invoiceable(Date.today)
73
+ for subscription in @invoiceable_subscriptions
74
+ subscription.invoice!
75
+ end
76
+ end
77
+ end
78
+
79
+ def downgrade
80
+ self.plan = downgrade_to_plan
81
+ self.downgrade_to_plan = nil
82
+ self.balance = plan.price
83
+
84
+ self.save!
85
+
86
+ end
87
+
88
+ def downgrade_plan_to(plan_id)
89
+
90
+ if self.update_attributes(:downgrade_to_plan => Plan.find(plan_id))
91
+ return true
92
+ else
93
+ return false
94
+ end
95
+ end
96
+
97
+ def last_transaction_date
98
+ @transaction = transactions.recent.first
99
+ if @transaction.nil?
100
+ "-"
101
+ else
102
+ @transaction.created_at.to_s(:month_day_year)
103
+ end
104
+ end
105
+
106
+ def last_transaction_amount
107
+ @transaction = transactions.recent.first
108
+ if @transaction.nil?
109
+ "-"
110
+ else
111
+ @transaction.amount
112
+ end
113
+ end
114
+
115
+ def plan_name
116
+ plan.name
117
+ end
118
+ def initial_bill
119
+ if Saasaparilla::CONFIG["trial_period"] > 0
120
+ set_next_billing_date(Saasaparilla::CONFIG["trial_period"])
121
+ else
122
+ bill!
123
+ end
124
+
125
+ end
126
+
127
+ def bill!(bill_amount = nil)
128
+ bill_amount ||= balance
129
+ if charge_amount(bill_amount)
130
+ set_next_billing_date
131
+ set_status_active if balance == 0.0
132
+ send_billing_successful_email(bill_amount)
133
+ return true
134
+ end
135
+
136
+ end
137
+
138
+
139
+ def invoice!
140
+ add_to_balance(plan.price)
141
+ create_invoice
142
+ self.update_attributes(:invoiced_on => Date.today)
143
+ #if invoice_subscription
144
+ # set_next_invoice_date()
145
+ end
146
+
147
+ def cancel
148
+ set_canceled
149
+ send_subscription_canceled_email
150
+ end
151
+
152
+ def reactivate!
153
+ self.update_attributes(:billing_date => nil)
154
+ self.balance = 0
155
+ add_to_balance(plan.price)
156
+ bill!
157
+ end
158
+
159
+ def billing_failed
160
+ set_status_overdue
161
+
162
+ if billing_date == Date.today
163
+ send_billing_failed_email
164
+ end
165
+
166
+ if billing_date == Date.today - Saasaparilla::CONFIG["grace_period"].days + 1
167
+ send_pending_cancellation_notice_email
168
+ end
169
+
170
+ if billing_date < Date.today - Saasaparilla::CONFIG["grace_period"].days
171
+ cancel
172
+ end
173
+ end
174
+
175
+
176
+ private
177
+
178
+ def create_invoice
179
+ @invoice = Invoice.create(:subscription => self, :price => plan.price, :from => get_beginning_of_billing_cycle, :to => billing_date)
180
+ end
181
+
182
+ def get_beginning_of_billing_cycle
183
+ if monthly?
184
+ return billing_date - 1.months
185
+ elsif annually?
186
+ return billing_date - 1.years
187
+ end
188
+ end
189
+
190
+ def set_next_billing_date(grace_period = 0)
191
+ grace_period = grace_period - 1 if grace_period > 0
192
+ if monthly?
193
+ if billing_date.nil?
194
+ self.update_attributes(:billing_date => Date.today + 1.months + grace_period.months)
195
+ else
196
+ self.update_attributes(:billing_date => billing_date + 1.months)
197
+ end
198
+
199
+ elsif annually?
200
+ if billing_date.nil?
201
+ self.update_attributes(:billing_date => Date.today + 1.years + grace_period.months)
202
+ else
203
+ self.update_attributes(:billing_date => billing_date + 1.years)
204
+ end
205
+ end
206
+ end
207
+
208
+ def set_status_active
209
+ self.update_attributes(:status => "active") if !active?
210
+ end
211
+
212
+ def set_canceled
213
+ self.update_attributes(:status => "canceled")
214
+ end
215
+
216
+ def set_status_overdue
217
+ unless overdue?
218
+ self.overdue_on = Date.today
219
+ end
220
+ self.status = "overdue"
221
+ self.save
222
+
223
+ end
224
+ def add_to_balance(cost)
225
+ self.increment!(:balance, cost)
226
+ end
227
+
228
+ def create_cim_profile
229
+ #Login to the gateway using your credentials in environment.rb
230
+ #setup the user object to save
231
+ @profile = {:profile => profile}
232
+
233
+ #send the create message to the gateway API
234
+ response = ::GATEWAYCIM.create_customer_profile(@profile)
235
+
236
+ if response.success? and response.authorization
237
+ self.customer_cim_id = response.authorization
238
+ return true
239
+ else
240
+ raise response.message
241
+ return false
242
+ end
243
+
244
+ end
245
+
246
+
247
+
248
+ def create_payment_profile
249
+
250
+ unless customer_payment_profile_id.nil?
251
+ return false
252
+ end
253
+ @profile = {:customer_profile_id => customer_cim_id,
254
+ :payment_profile => {:bill_to => contact_info.to_hash, :payment => {:credit_card => credit_card.active_merchant_card}
255
+ }
256
+ }
257
+
258
+ response = GATEWAYCIM.create_customer_payment_profile(@profile)
259
+
260
+ logger.info "payment_response #{response.to_yaml}"
261
+ if response.success? and response.params['customer_payment_profile_id']
262
+ self.customer_payment_profile_id = response.params['customer_payment_profile_id']
263
+ return true
264
+ end
265
+
266
+ raise response.message
267
+ return false
268
+ end
269
+
270
+ def profile
271
+ return {:merchant_customer_id => self.id, :email => contact_info.email, :description => contact_info.full_name}
272
+ end
273
+
274
+ def set_status
275
+ self.status = "active"
276
+ end
277
+
278
+ def set_initial_balance
279
+ self.balance = plan.price
280
+ end
281
+
282
+
283
+ def charge_amount(amount)
284
+ response = GATEWAYCIM.create_customer_profile_transaction(:transaction => {:type => :auth_capture,
285
+ :amount => amount,
286
+ :customer_profile_id => customer_cim_id,
287
+ :customer_payment_profile_id => customer_payment_profile_id})
288
+
289
+ transaction = self.transactions.create(:action => "purchase", :amount => amount, :response => response, :subscription => self)
290
+ if response.success?
291
+ self.update_attributes(:balance => balance - amount)
292
+ return true
293
+ else
294
+ raise response.message
295
+ return false
296
+ end
297
+ end
298
+
299
+ def delete_profile
300
+ if new_record?
301
+ response = GATEWAYCIM::delete_customer_profile(:customer_profile_id => self.customer_cim_id) if customer_cim_id
302
+ end
303
+ end
304
+
305
+ def check_if_should_bill_for_upgrade
306
+ if plan_id_changed? && !new_record? && plan_id_was != nil
307
+ old_plan_price = Plan.find(plan_id_was).price
308
+ if !old_plan_price.nil? && old_plan_price < plan.price
309
+ # Upgrade
310
+ if billing_date <= Date.today + 5.days
311
+ # For accounts w/ current invoice and close to renew date. Should recieve a few days free on new plan
312
+ balance = plan.price
313
+ old_plan_price = nil
314
+ else
315
+ # Pro-rate for account in the middle of billing cycle. Should recieve a credit.
316
+ if monthly?
317
+ time_to_credit = billing_date.to_time - Date.today.to_time
318
+ percentage = time_to_credit / 1.month
319
+ elsif yearly?
320
+ time_to_credit = billing_date.to_time - Date.today.to_time
321
+ percentage = time_to_credit / 1.year
322
+ end
323
+ credit = (old_plan_price * percentage).round(1)
324
+
325
+ # debugger
326
+
327
+ old_plan_price = nil
328
+ @changed_attributes.clear
329
+ add_to_balance(plan.price - credit)
330
+ self.update_attributes(:billing_date => nil)
331
+ bill!
332
+ end
333
+ end
334
+ # Do nothing for downgrade. Plan won't change until next cycle.
335
+ end
336
+ end
337
+
338
+ def set_credit_card_name
339
+ self.credit_card.first_name = contact_info.first_name
340
+ self.credit_card.last_name = contact_info.last_name
341
+ end
342
+
343
+ def send_subscription_created_email
344
+ Saasaparilla::Notifier.subscription_created(self).deliver
345
+ end
346
+
347
+ def send_billing_successful_email(amount)
348
+ Saasaparilla::Notifier.billing_successful(self, amount).deliver
349
+ end
350
+
351
+ def send_billing_failed_email
352
+ Saasaparilla::Notifier.billing_failed(self).deliver
353
+ end
354
+
355
+ def send_pending_cancellation_notice_email
356
+ Saasaparilla::Notifier.pending_cancellation_notice(self).deliver
357
+ end
358
+
359
+ def send_subscription_canceled_email
360
+ Saasaparilla::Notifier.subscription_canceled(self).deliver
361
+ end
362
+
363
+ end
@@ -0,0 +1,32 @@
1
+ class Transaction < ActiveRecord::Base
2
+
3
+ belongs_to :subscription
4
+ serialize :params
5
+ belongs_to :billing_activity
6
+ after_create :generate_billing_activity
7
+
8
+
9
+ def response=(response)
10
+ self.success = response.success?
11
+ self.authorization = response.authorization
12
+ self.message = response.message
13
+ self.params = response.params
14
+ rescue ActiveMerchant::ActiveMerchantError => e
15
+ self.success = false
16
+ self.authorization = nil
17
+ self.message = e.message
18
+ self.params = {}
19
+ end
20
+
21
+ scope :successful, lambda {
22
+ where("success = ?", true)
23
+ }
24
+ scope :recent, order("created_at DESC")
25
+
26
+ private
27
+ def generate_billing_activity
28
+ if success
29
+ self.create_billing_activity(:message => BillingActivity::MESSAGES[:success], :subscription => subscription, :amount => amount)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,9 @@
1
+ !!!
2
+ %html
3
+ %head
4
+ = stylesheet_link_tag :all
5
+ = javascript_include_tag :defaults
6
+ = csrf_meta_tag
7
+ %body
8
+ = flash[:notice]
9
+ = yield
@@ -0,0 +1,45 @@
1
+ = simple_form_for([:admin, @plan]) do |f|
2
+ - if @plan.errors.any?
3
+ #error_explanation
4
+ %h2= "#{pluralize(@plan.errors.count, "error")} prohibited this plan from being saved:"
5
+
6
+ %ul
7
+ -@plan.errors.full_messages.each do |msg|
8
+ %li= msg
9
+
10
+
11
+ = f.input :name
12
+ = f.input :price
13
+ = f.input :billing_period, :collection => Plan::BILLING_PERIODS, :include_blank => false
14
+
15
+ %fieldset
16
+ %h4 Plan Attributes
17
+ = f.label "Add new attribute"
18
+ = text_field_tag "attribute_name"
19
+ = link_to "Add attribute", "#", :id => "add_attribute"
20
+ #optional_attributes
21
+ -begin
22
+ - @plan.dynamic_attributes.each do |da|
23
+ = f.label da[0].gsub("field_", "")
24
+ = text_field_tag "plan[#{da[0]}]", da[1]
25
+ %br
26
+ - rescue
27
+
28
+ .actions
29
+ = f.submit
30
+ = link_to 'Cancel', :back
31
+
32
+ :javascript
33
+ $(document).ready(function(){
34
+ $('#add_attribute').click(function(event) {
35
+ event.preventDefault();
36
+ if ($('#attribute_name').val() == '') {
37
+ alert("You must give your attribute a name.");
38
+ } else {
39
+ $('#optional_attributes').append("<br><label>" + $('#attribute_name').val() +"</label><input name='plan[field_" + $('#attribute_name').val() +"]' id='field_" + $('#attribute_name').val() +"'>");
40
+ }
41
+ })
42
+ })
43
+
44
+
45
+