effective_orders 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (146) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +856 -0
  4. data/Rakefile +24 -0
  5. data/app/assets/images/effective_orders/stripe_connect.png +0 -0
  6. data/app/assets/javascripts/effective_orders/shipping_address_toggle.js.coffee +30 -0
  7. data/app/assets/javascripts/effective_orders/stripe_charges.js.coffee +26 -0
  8. data/app/assets/javascripts/effective_orders/stripe_subscriptions.js.coffee +28 -0
  9. data/app/assets/javascripts/effective_orders.js +2 -0
  10. data/app/assets/stylesheets/effective_orders/_order.scss +30 -0
  11. data/app/assets/stylesheets/effective_orders.css.scss +1 -0
  12. data/app/controllers/admin/customers_controller.rb +15 -0
  13. data/app/controllers/admin/orders_controller.rb +22 -0
  14. data/app/controllers/effective/carts_controller.rb +70 -0
  15. data/app/controllers/effective/orders_controller.rb +191 -0
  16. data/app/controllers/effective/providers/moneris.rb +94 -0
  17. data/app/controllers/effective/providers/paypal.rb +29 -0
  18. data/app/controllers/effective/providers/stripe.rb +125 -0
  19. data/app/controllers/effective/providers/stripe_connect.rb +47 -0
  20. data/app/controllers/effective/subscriptions_controller.rb +123 -0
  21. data/app/controllers/effective/webhooks_controller.rb +86 -0
  22. data/app/helpers/effective_carts_helper.rb +90 -0
  23. data/app/helpers/effective_orders_helper.rb +108 -0
  24. data/app/helpers/effective_paypal_helper.rb +37 -0
  25. data/app/helpers/effective_stripe_helper.rb +63 -0
  26. data/app/mailers/effective/orders_mailer.rb +64 -0
  27. data/app/models/concerns/acts_as_purchasable.rb +134 -0
  28. data/app/models/effective/access_denied.rb +17 -0
  29. data/app/models/effective/cart.rb +65 -0
  30. data/app/models/effective/cart_item.rb +40 -0
  31. data/app/models/effective/customer.rb +61 -0
  32. data/app/models/effective/datatables/customers.rb +45 -0
  33. data/app/models/effective/datatables/orders.rb +53 -0
  34. data/app/models/effective/order.rb +247 -0
  35. data/app/models/effective/order_item.rb +69 -0
  36. data/app/models/effective/stripe_charge.rb +35 -0
  37. data/app/models/effective/subscription.rb +95 -0
  38. data/app/models/inputs/price_field.rb +63 -0
  39. data/app/models/inputs/price_form_input.rb +7 -0
  40. data/app/models/inputs/price_formtastic_input.rb +9 -0
  41. data/app/models/inputs/price_input.rb +19 -0
  42. data/app/models/inputs/price_simple_form_input.rb +8 -0
  43. data/app/models/validators/effective/sold_out_validator.rb +7 -0
  44. data/app/views/active_admin/effective_orders/orders/_show.html.haml +70 -0
  45. data/app/views/admin/customers/_actions.html.haml +2 -0
  46. data/app/views/admin/customers/index.html.haml +10 -0
  47. data/app/views/admin/orders/index.html.haml +7 -0
  48. data/app/views/admin/orders/show.html.haml +11 -0
  49. data/app/views/effective/carts/_cart.html.haml +33 -0
  50. data/app/views/effective/carts/show.html.haml +18 -0
  51. data/app/views/effective/orders/_checkout_step_1.html.haml +39 -0
  52. data/app/views/effective/orders/_checkout_step_2.html.haml +18 -0
  53. data/app/views/effective/orders/_my_purchases.html.haml +15 -0
  54. data/app/views/effective/orders/_order.html.haml +4 -0
  55. data/app/views/effective/orders/_order_header.html.haml +21 -0
  56. data/app/views/effective/orders/_order_items.html.haml +39 -0
  57. data/app/views/effective/orders/_order_payment_details.html.haml +11 -0
  58. data/app/views/effective/orders/_order_shipping.html.haml +19 -0
  59. data/app/views/effective/orders/_order_user_fields.html.haml +10 -0
  60. data/app/views/effective/orders/checkout.html.haml +3 -0
  61. data/app/views/effective/orders/declined.html.haml +10 -0
  62. data/app/views/effective/orders/moneris/_form.html.haml +34 -0
  63. data/app/views/effective/orders/my_purchases.html.haml +6 -0
  64. data/app/views/effective/orders/my_sales.html.haml +28 -0
  65. data/app/views/effective/orders/new.html.haml +4 -0
  66. data/app/views/effective/orders/paypal/_form.html.haml +5 -0
  67. data/app/views/effective/orders/purchased.html.haml +10 -0
  68. data/app/views/effective/orders/show.html.haml +17 -0
  69. data/app/views/effective/orders/stripe/_form.html.haml +8 -0
  70. data/app/views/effective/orders/stripe/_subscription_fields.html.haml +7 -0
  71. data/app/views/effective/orders_mailer/order_receipt_to_admin.html.haml +8 -0
  72. data/app/views/effective/orders_mailer/order_receipt_to_buyer.html.haml +8 -0
  73. data/app/views/effective/orders_mailer/order_receipt_to_seller.html.haml +30 -0
  74. data/app/views/effective/subscriptions/index.html.haml +16 -0
  75. data/app/views/effective/subscriptions/new.html.haml +10 -0
  76. data/app/views/effective/subscriptions/show.html.haml +49 -0
  77. data/config/routes.rb +57 -0
  78. data/db/migrate/01_create_effective_orders.rb.erb +91 -0
  79. data/db/upgrade/02_upgrade_effective_orders_from03x.rb.erb +29 -0
  80. data/db/upgrade/upgrade_price_column_on_table.rb.erb +17 -0
  81. data/lib/effective_orders/engine.rb +52 -0
  82. data/lib/effective_orders/version.rb +3 -0
  83. data/lib/effective_orders.rb +76 -0
  84. data/lib/generators/effective_orders/install_generator.rb +38 -0
  85. data/lib/generators/effective_orders/upgrade_from03x_generator.rb +34 -0
  86. data/lib/generators/effective_orders/upgrade_price_column_generator.rb +34 -0
  87. data/lib/generators/templates/README +1 -0
  88. data/lib/generators/templates/effective_orders.rb +210 -0
  89. data/spec/controllers/carts_controller_spec.rb +143 -0
  90. data/spec/controllers/moneris_orders_controller_spec.rb +245 -0
  91. data/spec/controllers/orders_controller_spec.rb +418 -0
  92. data/spec/controllers/stripe_orders_controller_spec.rb +127 -0
  93. data/spec/controllers/webhooks_controller_spec.rb +79 -0
  94. data/spec/dummy/README.rdoc +8 -0
  95. data/spec/dummy/Rakefile +6 -0
  96. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  97. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  98. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  99. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  100. data/spec/dummy/app/models/product.rb +17 -0
  101. data/spec/dummy/app/models/product_with_float_price.rb +17 -0
  102. data/spec/dummy/app/models/user.rb +28 -0
  103. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  104. data/spec/dummy/bin/bundle +3 -0
  105. data/spec/dummy/bin/rails +4 -0
  106. data/spec/dummy/bin/rake +4 -0
  107. data/spec/dummy/config/application.rb +31 -0
  108. data/spec/dummy/config/boot.rb +5 -0
  109. data/spec/dummy/config/database.yml +25 -0
  110. data/spec/dummy/config/environment.rb +5 -0
  111. data/spec/dummy/config/environments/development.rb +37 -0
  112. data/spec/dummy/config/environments/production.rb +83 -0
  113. data/spec/dummy/config/environments/test.rb +39 -0
  114. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  115. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  116. data/spec/dummy/config/initializers/devise.rb +254 -0
  117. data/spec/dummy/config/initializers/effective_addresses.rb +15 -0
  118. data/spec/dummy/config/initializers/effective_orders.rb +22 -0
  119. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  120. data/spec/dummy/config/initializers/inflections.rb +16 -0
  121. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  122. data/spec/dummy/config/initializers/session_store.rb +3 -0
  123. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  124. data/spec/dummy/config/locales/en.yml +23 -0
  125. data/spec/dummy/config/routes.rb +3 -0
  126. data/spec/dummy/config/secrets.yml +22 -0
  127. data/spec/dummy/config.ru +4 -0
  128. data/spec/dummy/db/schema.rb +142 -0
  129. data/spec/dummy/db/test.sqlite3 +0 -0
  130. data/spec/dummy/log/development.log +487 -0
  131. data/spec/dummy/log/test.log +347 -0
  132. data/spec/dummy/public/404.html +67 -0
  133. data/spec/dummy/public/422.html +67 -0
  134. data/spec/dummy/public/500.html +66 -0
  135. data/spec/dummy/public/favicon.ico +0 -0
  136. data/spec/helpers/effective_orders_helper_spec.rb +21 -0
  137. data/spec/models/acts_as_purchasable_spec.rb +107 -0
  138. data/spec/models/customer_spec.rb +71 -0
  139. data/spec/models/factories_spec.rb +13 -0
  140. data/spec/models/order_item_spec.rb +35 -0
  141. data/spec/models/order_spec.rb +323 -0
  142. data/spec/models/stripe_charge_spec.rb +39 -0
  143. data/spec/models/subscription_spec.rb +103 -0
  144. data/spec/spec_helper.rb +44 -0
  145. data/spec/support/factories.rb +118 -0
  146. metadata +387 -0
@@ -0,0 +1,418 @@
1
+ require 'spec_helper'
2
+
3
+ describe Effective::OrdersController do
4
+ routes { EffectiveOrders::Engine.routes }
5
+
6
+ let(:purchased_order) { FactoryGirl.create(:purchased_order) }
7
+ let(:order) { FactoryGirl.create(:order) }
8
+
9
+ let(:cart) { FactoryGirl.create(:cart) }
10
+ let(:address) { FactoryGirl.create(:address) }
11
+
12
+ let(:billing_address) { FactoryGirl.create(:address) }
13
+ let(:billing_atts) { billing_address.attributes.reject { |k, v| ['id', 'addressable_type', 'addressable_id', 'category', 'updated_at', 'created_at'].include?(k) } }
14
+
15
+ let(:shipping_address) { FactoryGirl.create(:address) }
16
+ let(:shipping_atts) { shipping_address.attributes.reject { |k, v| ['id', 'addressable_type', 'addressable_id', 'category', 'updated_at', 'created_at'].include?(k) } }
17
+
18
+ let(:valid_order_attributes) do
19
+ {
20
+ :effective_order => {
21
+ :billing_address => billing_atts, :save_billing_address => false,
22
+ :shipping_address => shipping_atts, :save_shipping_address => false,
23
+ }
24
+ }
25
+ end
26
+
27
+ it 'uses authenticate_user! to redirect to sign in if not signed in' do
28
+ get :new
29
+ response.should redirect_to '/users/sign_in'
30
+ end
31
+
32
+ describe '#new' do
33
+ it 'should assign an @order based off the user cart' do
34
+ sign_in cart.user
35
+ get :new
36
+
37
+ assigns(:order).user.should eq cart.user
38
+
39
+ assigns(:order).order_items.size.should eq cart.cart_items.size
40
+ assigns(:order).total.should eq cart.total
41
+ end
42
+
43
+ it 'redirects if there is an empty order' do
44
+ sign_in cart.user
45
+ cart.cart_items.destroy_all
46
+
47
+ get :new
48
+
49
+ flash[:danger].downcase.include?('add one or more item to your cart').should eq true
50
+ response.should redirect_to '/cart' # cart_path
51
+ end
52
+
53
+ it 'redirects if order total is less than minimum charge' do
54
+ sign_in cart.user
55
+ Effective::CartItem.any_instance.stub(:price).and_return(10)
56
+
57
+ get :new
58
+
59
+ flash[:danger].downcase.include?('a minimum order of $0.50 is required').should eq true
60
+ response.should redirect_to '/cart' # cart_path
61
+ end
62
+ end
63
+
64
+ # "effective_order"=> {
65
+ # "order_items_attributes"=> {
66
+ # "0"=> {
67
+ # "class"=>"Effective::Subscription", "stripe_coupon_id"=>"50OFF", "id"=>"2"}},
68
+ # "billing_address"=>{"address1"=>"1234 Fake street", "address2"=>"", "city"=>"Edmonton", "country_code"=>"KH", "state_code"=>"1", "postal_code"=>"T5T2T1"},
69
+ # "save_billing_address"=>"1",
70
+ # "shipping_address"=>{"address1"=>"123 Shipping street", "address2"=>"", "city"=>"Edmonton", "country_code"=>"KH", "state_code"=>"10", "postal_code"=>"t5t2t1"},
71
+ # "save_shipping_address"=>"1"},
72
+ # "commit"=>"Continue Checkout"
73
+ # }
74
+
75
+ describe '#create' do
76
+ before(:each) do
77
+ sign_in cart.user
78
+ end
79
+
80
+ it 'should assign an @order based off the user cart' do
81
+ post :create
82
+
83
+ assigns(:order).user.should eq cart.user
84
+ assigns(:order).order_items.size.should eq cart.cart_items.size
85
+ assigns(:order).total.should eq cart.total
86
+ assigns(:order).purchased?.should eq false
87
+ end
88
+
89
+ it 'assign appropriate User fields' do
90
+ post :create, :effective_order => {
91
+ :billing_address => billing_atts, :save_billing_address => false,
92
+ :shipping_address => shipping_atts, :save_shipping_address => false,
93
+ :shipping_address_same_as_billing => false,
94
+ :user_attributes => {:first_name => 'First', :last_name => 'Last', :email => 'email@somwhere.com'}
95
+ }
96
+
97
+ (assigns(:order).valid? && assigns(:order).persisted?).should eq true
98
+
99
+ assigns(:order).user.first_name.should eq 'First'
100
+ assigns(:order).user.last_name.should eq 'Last'
101
+ assigns(:order).user.email.should_not eq 'email@somwhere.com'
102
+ end
103
+
104
+ it 'assign addresses to the order and not the user' do
105
+ post :create, :effective_order => {
106
+ :billing_address => billing_atts, :save_billing_address => false,
107
+ :shipping_address => shipping_atts, :save_shipping_address => false,
108
+ :shipping_address_same_as_billing => false
109
+ }
110
+
111
+ (assigns(:order).valid? && assigns(:order).persisted?).should eq true
112
+
113
+ assigns(:order).billing_address.address1.should eq billing_atts['address1']
114
+ assigns(:order).shipping_address.address1.should eq shipping_atts['address1']
115
+
116
+ assigns(:order).user.billing_address.present?.should eq false
117
+ assigns(:order).user.shipping_address.present?.should eq false
118
+ end
119
+
120
+ it 'assign addresses to the order and the user' do
121
+ post :create, :effective_order => {
122
+ :billing_address => billing_atts, :save_billing_address => true,
123
+ :shipping_address => shipping_atts, :save_shipping_address => true,
124
+ :shipping_address_same_as_billing => false
125
+ }
126
+
127
+ (assigns(:order).valid? && assigns(:order).persisted?).should eq true
128
+
129
+ assigns(:order).billing_address.address1.should eq billing_atts['address1']
130
+ assigns(:order).shipping_address.address1.should eq shipping_atts['address1']
131
+
132
+ assigns(:order).user.billing_address.address1.should eq billing_atts['address1']
133
+ assigns(:order).user.shipping_address.address1.should eq shipping_atts['address1']
134
+
135
+ response.should redirect_to "/orders/#{assigns(:order).to_param}"
136
+ end
137
+
138
+ it 'does not assign the billing_address to user if save_billing_address is false' do
139
+ post :create, :effective_order => {
140
+ :billing_address => billing_atts, :save_billing_address => false,
141
+ :shipping_address => shipping_atts, :save_shipping_address => true,
142
+ :shipping_address_same_as_billing => false
143
+ }
144
+
145
+ (assigns(:order).valid? && assigns(:order).persisted?).should eq true
146
+
147
+ assigns(:order).billing_address.address1.should eq billing_atts['address1']
148
+ assigns(:order).shipping_address.address1.should eq shipping_atts['address1']
149
+
150
+ assigns(:order).user.billing_address.present?.should eq false
151
+ assigns(:order).user.shipping_address.address1.should eq shipping_atts['address1']
152
+
153
+ response.should redirect_to "/orders/#{assigns(:order).to_param}"
154
+ end
155
+
156
+ it 'does not assign the shipping_address to user if save_shipping_address is false' do
157
+ post :create, :effective_order => {
158
+ :billing_address => billing_atts, :save_billing_address => true,
159
+ :shipping_address => shipping_atts, :save_shipping_address => false,
160
+ :shipping_address_same_as_billing => false
161
+ }
162
+
163
+ (assigns(:order).valid? && assigns(:order).persisted?).should eq true
164
+
165
+ assigns(:order).billing_address.address1.should eq billing_atts['address1']
166
+ assigns(:order).shipping_address.address1.should eq shipping_atts['address1']
167
+
168
+ assigns(:order).user.billing_address.address1.should eq billing_atts['address1']
169
+ assigns(:order).user.shipping_address.present?.should eq false
170
+
171
+ response.should redirect_to "/orders/#{assigns(:order).to_param}"
172
+ end
173
+
174
+ it 'assign billing address to the order shipping_address when shipping_address_same_as_billing' do
175
+ post :create, :effective_order => {
176
+ :billing_address => billing_atts, :save_billing_address => true,
177
+ :shipping_address => shipping_atts, :save_shipping_address => true,
178
+ :shipping_address_same_as_billing => true
179
+ }
180
+
181
+ (assigns(:order).valid? && assigns(:order).persisted?).should eq true
182
+
183
+ assigns(:order).billing_address.address1.should eq billing_atts['address1']
184
+ assigns(:order).shipping_address.address1.should eq billing_atts['address1']
185
+
186
+ assigns(:order).user.billing_address.address1.should eq billing_atts['address1']
187
+ assigns(:order).user.shipping_address.address1.should eq billing_atts['address1']
188
+
189
+ response.should redirect_to "/orders/#{assigns(:order).to_param}"
190
+ end
191
+
192
+ it 'assign billing address to the order shipping_address when shipping_address_same_as_billing and no shipping provided' do
193
+ post :create, :effective_order => {
194
+ :billing_address => billing_atts, :save_billing_address => true,
195
+ :shipping_address_same_as_billing => true
196
+ }
197
+
198
+ (assigns(:order).valid? && assigns(:order).persisted?).should eq true
199
+
200
+ assigns(:order).billing_address.address1.should eq billing_atts['address1']
201
+ assigns(:order).shipping_address.address1.should eq billing_atts['address1']
202
+
203
+ assigns(:order).user.billing_address.address1.should eq billing_atts['address1']
204
+ assigns(:order).user.shipping_address.address1.should eq billing_atts['address1']
205
+
206
+ response.should redirect_to "/orders/#{assigns(:order).to_param}"
207
+ end
208
+
209
+ it 'assign billing address to the order shipping_address but not the user when shipping_address_same_as_billing provided' do
210
+ post :create, :effective_order => {
211
+ :billing_address => billing_atts, :save_billing_address => false,
212
+ :save_shipping_address => false,
213
+ :shipping_address_same_as_billing => true
214
+ }
215
+
216
+ (assigns(:order).valid? && assigns(:order).persisted?).should eq true
217
+
218
+ assigns(:order).billing_address.address1.should eq billing_atts['address1']
219
+ assigns(:order).shipping_address.address1.should eq billing_atts['address1']
220
+
221
+ assigns(:order).user.billing_address.present?.should eq false
222
+ assigns(:order).user.shipping_address.present?.should eq false
223
+
224
+ response.should redirect_to "/orders/#{assigns(:order).to_param}"
225
+ end
226
+
227
+ it 'is invalid when passed an invalid address' do
228
+ post :create, :effective_order => {
229
+ :billing_address => billing_atts, :save_billing_address => true,
230
+ :shipping_address => shipping_atts.tap { |x| x[:address1] = nil }, :save_shipping_address => true,
231
+ :shipping_address_same_as_billing => false
232
+ }
233
+
234
+ (assigns(:order).valid? && assigns(:order).persisted?).should eq false
235
+ assigns(:order).errors[:addresses].present?.should eq true
236
+ assigns(:order).errors[:shipping_address].present?.should eq true
237
+
238
+ response.should render_template(:new)
239
+ end
240
+
241
+ it 'is invalid when passed an invalid order_item' do
242
+ Effective::OrderItem.any_instance.stub(:valid?).and_return(false)
243
+
244
+ post :create, :effective_order => {
245
+ :billing_address => billing_atts, :save_billing_address => true,
246
+ :shipping_address => shipping_atts, :save_shipping_address => true,
247
+ }
248
+
249
+ (assigns(:order).valid? && assigns(:order).persisted?).should eq false
250
+ response.should render_template(:new)
251
+ end
252
+
253
+ it 'is invalid when passed an invalid user' do
254
+ User.any_instance.stub(:valid?).and_return(false)
255
+
256
+ post :create, :effective_order => {
257
+ :billing_address => billing_atts, :save_billing_address => true,
258
+ :shipping_address => shipping_atts, :save_shipping_address => true,
259
+ }
260
+
261
+ (assigns(:order).valid? && assigns(:order).persisted?).should eq false
262
+ response.should render_template(:new)
263
+ end
264
+
265
+ it 'is invalid when passed an invalid purchasable' do
266
+ Product.any_instance.stub(:valid?).and_return(false)
267
+
268
+ post :create, :effective_order => {
269
+ :billing_address => billing_atts, :save_billing_address => true,
270
+ :shipping_address => shipping_atts, :save_shipping_address => true,
271
+ }
272
+
273
+ (assigns(:order).valid? && assigns(:order).persisted?).should eq false
274
+ response.should render_template(:new)
275
+ end
276
+
277
+ it 'prevents the order from proceeding when missing a required address' do
278
+ post :create, :effective_order => { :billing_address => billing_atts, :save_billing_address => true, :shipping_address_same_as_billing => false }
279
+
280
+ (assigns(:order).valid? && assigns(:order).persisted?).should eq false
281
+ assigns(:order).errors[:shipping_address].present?.should eq true
282
+
283
+ response.should render_template(:new)
284
+ end
285
+ end
286
+
287
+ describe '#create with a Stripe Subscription object' do
288
+ let(:cart_with_subscription) { FactoryGirl.create(:cart_with_subscription) }
289
+ let(:subscription) { cart_with_subscription.cart_items.find { |obj| obj.purchasable.kind_of?(Effective::Subscription)}.purchasable }
290
+
291
+ let(:valid_order_with_new_subscription_coupon_attributes) do
292
+ valid_order_attributes.tap { |x| x[:effective_order]['order_items_attributes'] = {'0' => {"class"=>"Effective::Subscription", "stripe_coupon_id"=>"#{::Stripe::Coupon.create().id}", 'id' => "#{subscription.id}"}} }
293
+ end
294
+
295
+ before do
296
+ StripeMock.start
297
+ sign_in cart_with_subscription.user
298
+ end
299
+
300
+ after { StripeMock.stop }
301
+
302
+ it 'has an OrderItem that is a Subscription' do
303
+ post :create, valid_order_attributes
304
+ assigns(:order).persisted?.should eq true
305
+
306
+ subscription = assigns(:order).order_items.find { |obj| obj.purchasable.kind_of?(Effective::Subscription) }
307
+ subscription.present?.should eq true
308
+ end
309
+
310
+ it 'does not alter the subscription.stripe_coupon_id' do
311
+ post :create, valid_order_attributes
312
+ assigns(:order).persisted?.should eq true
313
+
314
+ order_subscription = assigns(:order).order_items.find { |obj| obj.purchasable.kind_of?(Effective::Subscription) }.purchasable
315
+ order_subscription.stripe_coupon_id.should eq subscription.stripe_coupon_id
316
+ end
317
+
318
+ it 'updates the subscription.stripe_coupon_id when passed' do
319
+ post :create, valid_order_with_new_subscription_coupon_attributes
320
+ assigns(:order).persisted?.should eq true
321
+
322
+ order_subscription = assigns(:order).order_items.find { |obj| obj.purchasable.kind_of?(Effective::Subscription) }.purchasable
323
+ order_subscription.stripe_coupon_id.should_not eq subscription.stripe_coupon_id
324
+ end
325
+
326
+ it 'is invalid when passed an invalid coupon code' do
327
+ invalid_coupon_atts = valid_order_with_new_subscription_coupon_attributes.tap { |x| x[:effective_order]['order_items_attributes']['0']['stripe_coupon_id'] = 'SOMETHING INVALID' }
328
+
329
+ post :create, invalid_coupon_atts
330
+
331
+ assigns(:order).errors['order_items.purchasable'].present?.should eq true
332
+ assigns(:order).errors['order_items.purchasable.stripe_coupon_id'].present?.should eq true
333
+ assigns(:order).persisted?.should eq false
334
+ end
335
+ end
336
+
337
+ describe '#order_purchased (with a free order)' do
338
+ before(:each) do
339
+ sign_in cart.user
340
+ cart.cart_items.each { |cart_item| cart_item.purchasable.update_attributes(:price => 0.0) }
341
+ end
342
+
343
+ it 'creates a purchased order' do
344
+ post :create, valid_order_attributes
345
+ assigns(:order).purchased?.should eq true
346
+ assigns(:order).payment[:details].should eq 'zero-dollar order'
347
+ end
348
+
349
+ it 'destroys the current user cart' do
350
+ post :create, valid_order_attributes
351
+
352
+ expect { Effective::Cart.find(cart.id) }.to raise_error(ActiveRecord::RecordNotFound)
353
+ assigns(:cart).cart_items.size.should eq 0
354
+ end
355
+
356
+ it 'redirects to the purchased page' do
357
+ post :create, valid_order_attributes
358
+ response.should redirect_to "/orders/#{assigns(:order).to_param}/purchased"
359
+ end
360
+ end
361
+
362
+ describe '#show' do
363
+
364
+ it 'finds the order by obfuscated ID' do
365
+ sign_in purchased_order.user
366
+ get :show, :id => purchased_order.to_param
367
+ assigns(:order).id.should eq purchased_order.id
368
+ end
369
+
370
+ it 'does not find an order by regular ID' do
371
+ sign_in purchased_order.user
372
+ expect { get :show, :id => purchased_order.id }.to raise_error(ActiveRecord::RecordNotFound)
373
+ end
374
+
375
+ it 'renders the show template for a purchased order' do
376
+ sign_in purchased_order.user
377
+ get :show, :id => purchased_order.to_param
378
+ response.should render_template(:show)
379
+ end
380
+
381
+ it 'renders the checkout template for a non-purchased order' do
382
+ sign_in order.user
383
+ get :show, :id => order.to_param
384
+ response.should render_template(:checkout)
385
+ end
386
+ end
387
+
388
+ describe '#purchased' do
389
+ before(:each) do
390
+ sign_in purchased_order.user
391
+ end
392
+
393
+ it 'finds the order by obfuscated ID' do
394
+ get :purchased, :id => purchased_order.to_param
395
+ assigns(:order).id.should eq purchased_order.id
396
+ end
397
+
398
+ it 'does not find an order by regular ID' do
399
+ expect { get :purchased, :id => purchased_order.id }.to raise_error(ActiveRecord::RecordNotFound)
400
+ end
401
+ end
402
+
403
+ describe '#declined' do
404
+ before(:each) do
405
+ sign_in purchased_order.user
406
+ end
407
+
408
+ it 'finds the order by obfuscated ID' do
409
+ get :declined, :id => purchased_order.to_param
410
+ assigns(:order).id.should eq purchased_order.id
411
+ end
412
+
413
+ it 'does not find an order by regular ID' do
414
+ expect { get :declined, :id => purchased_order.id }.to raise_error(ActiveRecord::RecordNotFound)
415
+ end
416
+ end
417
+
418
+ end
@@ -0,0 +1,127 @@
1
+ require 'spec_helper'
2
+
3
+ # We're testing the effective/providers/stripe.rb file, which is included into the OrdersController at runtime
4
+
5
+ describe Effective::OrdersController do
6
+ routes { EffectiveOrders::Engine.routes }
7
+
8
+ before { StripeMock.start }
9
+ after { StripeMock.stop }
10
+
11
+ let(:order) { FactoryGirl.create(:order) }
12
+ let(:buyer) { Effective::Customer.for_user(order.user) }
13
+ let(:token) { 'tok_123456789' }
14
+ let(:stripe_charge_params) do
15
+ {:effective_stripe_charge => {'effective_order_id' => order.to_param, 'token' => token}}
16
+ end
17
+
18
+ describe '#stripe_charge' do
19
+ before do
20
+ sign_in order.user
21
+ end
22
+
23
+ describe 'invalid parameters' do
24
+ it 'raises RecordNotFound when passed an unknown order id' do
25
+ expect {
26
+ post :stripe_charge, stripe_charge_params.tap { |x| x[:effective_stripe_charge]['effective_order_id'] = 999 }
27
+ }.to raise_error(ActiveRecord::RecordNotFound)
28
+ end
29
+
30
+ it 'renders the :create action on validation failure' do
31
+ subject.should_not_receive(:process_stripe_charge)
32
+
33
+ post :stripe_charge, stripe_charge_params.tap { |x| x[:effective_stripe_charge]['token'] = nil }
34
+
35
+ flash[:danger].downcase.include?('token').should eq true
36
+ assigns(:stripe_charge).errors[:token].present?.should eq true
37
+
38
+ assigns(:order).purchased?.should eq false
39
+ response.should render_template(:checkout)
40
+ end
41
+ end
42
+
43
+ describe 'valid parameters' do
44
+ it 'redirects to order_purchase_path on success' do
45
+ post :stripe_charge, stripe_charge_params
46
+ assigns(:order).purchased?.should eq true
47
+ response.should redirect_to "/orders/#{assigns(:order).to_param}/purchased"
48
+ end
49
+
50
+ it 'assigns the @stripe_charge, @order and @buyer properly' do
51
+ post :stripe_charge, stripe_charge_params
52
+
53
+ assigns(:stripe_charge).valid?.should eq true
54
+ assigns(:stripe_charge).order.should eq order
55
+ assigns(:order).should eq order
56
+ assigns(:buyer).should eq buyer
57
+ end
58
+
59
+ it 'calls process_stripe_charge when the stripe_charge form object is valid' do
60
+ subject.should_receive(:process_stripe_charge)
61
+ post :stripe_charge, stripe_charge_params
62
+ end
63
+
64
+ it 'assigns the buyer a new card based on the passed token' do
65
+ Effective::Customer.any_instance.should_receive(:update_card!).with(token)
66
+ post :stripe_charge, stripe_charge_params
67
+ end
68
+
69
+ it 'stores the Stripe::Charge info in the order.payment' do
70
+ post :stripe_charge, stripe_charge_params
71
+ assigns(:order).payment[:charge]['object'].should eq 'charge'
72
+ assigns(:order).payment[:charge]['amount'].should eq order.total
73
+ assigns(:order).payment[:charge]['customer'].should eq buyer.stripe_customer_id
74
+ end
75
+ end
76
+
77
+ describe 'stripe charge errors' do
78
+ it 'rollsback the entire transaction when Stripe::Charge fails' do
79
+ StripeMock.prepare_card_error(:card_declined)
80
+
81
+ post :stripe_charge, stripe_charge_params
82
+
83
+ assigns(:order).purchased?.should eq false
84
+ assigns(:stripe_charge).errors[:base].first.downcase.include?('unable to process order with stripe').should eq true
85
+ assigns(:stripe_charge).errors[:base].first.downcase.include?('the card was declined').should eq true
86
+ response.should render_template(:checkout)
87
+ end
88
+ end
89
+ end
90
+
91
+ describe '#stripe_charge with a subscription' do
92
+ let(:order) { FactoryGirl.create(:order_with_subscription) }
93
+ let(:buyer) { Effective::Customer.for_user(order.user) }
94
+ let(:subscription) { order.order_items[1].purchasable }
95
+ let(:token) { 'tok_123456789' }
96
+ let(:stripe_charge_params) do
97
+ {:effective_stripe_charge => {'effective_order_id' => order.to_param, 'token' => token}}
98
+ end
99
+
100
+ before do
101
+ sign_in order.user
102
+ end
103
+
104
+ it 'redirects to order_purchase_path on success' do
105
+ post :stripe_charge, stripe_charge_params
106
+ assigns(:order).purchased?.should eq true
107
+ response.should redirect_to "/orders/#{assigns(:order).to_param}/purchased"
108
+ end
109
+
110
+ it 'makes a Stripe::Charge for only the non-Subscription OrderItems' do
111
+ post :stripe_charge, stripe_charge_params
112
+ assigns(:order).payment[:charge]['object'].should eq 'charge'
113
+ assigns(:order).payment[:charge]['amount'].should eq order.order_items.first.total
114
+ end
115
+
116
+ it 'makes a Stripe::Subscription for the Subscriptions' do
117
+ post :stripe_charge, stripe_charge_params
118
+
119
+ assigns(:order).payment[:subscriptions]["#{subscription.stripe_plan_id}"]['object'].should eq 'subscription'
120
+ assigns(:order).payment[:subscriptions]["#{subscription.stripe_plan_id}"]['plan'].should eq subscription.stripe_plan_id
121
+ subscription.reload.stripe_subscription_id.present?.should eq true
122
+ subscription.reload.stripe_coupon_id.present?.should eq true
123
+
124
+ Effective::Subscription.find(subscription.id).purchased?.should eq true
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,79 @@
1
+ require 'spec_helper'
2
+
3
+ describe Effective::WebhooksController do
4
+ routes { EffectiveOrders::Engine.routes }
5
+
6
+ before { StripeMock.start }
7
+ after { StripeMock.stop }
8
+
9
+ let(:order) { FactoryGirl.create(:order) }
10
+ let(:buyer) { Effective::Customer.for_user(order.user) }
11
+
12
+ let(:event) { StripeMock.mock_webhook_event('customer.subscription.created') }
13
+ let(:event_hash) { event.to_hash }
14
+
15
+ describe '#stripe' do
16
+ it 'retrieves the real event from Stripe based on passed ID' do
17
+ Stripe::Event.should_receive(:retrieve).with(event_hash[:id])
18
+ post :stripe, event_hash
19
+ response.code.should eq '200'
20
+ end
21
+
22
+ it 'assigns the @event based on the passed ID' do
23
+ post :stripe, event_hash
24
+ assigns(:event).id.should eq event_hash[:id]
25
+ response.code.should eq '200'
26
+ end
27
+
28
+ it 'exits immediately when passed a livemode=false event in Production' do
29
+ event_hash[:livemode] = false
30
+ Rails.env.stub(:production?).and_return(true)
31
+
32
+ post :stripe, event_hash
33
+ assigns(:event).should eq nil
34
+ response.code.should eq '200'
35
+ end
36
+
37
+ it 'exits immediately when passed a non-object event' do
38
+ event_hash[:object] = 'not-object'
39
+
40
+ post :stripe, event_hash
41
+ assigns(:event).should eq nil
42
+ response.code.should eq '200'
43
+ end
44
+
45
+ end
46
+
47
+ describe '#stripe.subscription_created' do
48
+ before(:each) do
49
+ buyer.update_attributes(:stripe_customer_id => event.data.object.customer)
50
+ end
51
+
52
+ it 'assigns the existing customer, if exists' do
53
+ post :stripe, event_hash
54
+ assigns(:customer).should eq buyer
55
+ end
56
+
57
+ it 'creates a new purchased Order for the Subscription' do
58
+ Effective::Subscription.any_instance.stub(:valid?).and_return(true)
59
+ Effective::Subscription.any_instance.stub(:purchased?).and_return(false)
60
+
61
+ post :stripe, event_hash
62
+
63
+ assigns(:order).purchased?.should eq true
64
+ assigns(:order).user.should eq buyer.user
65
+ assigns(:order).payment.to_s.include?(event_hash[:id]).should eq true
66
+ end
67
+
68
+ it 'does not create an Order for an existing purchased Subscription' do
69
+ Effective::Subscription.any_instance.stub(:valid?).and_return(true)
70
+ Effective::Subscription.any_instance.stub(:purchased?).and_return(true)
71
+
72
+ post :stripe, event_hash
73
+
74
+ assigns(:order).present?.should eq false
75
+ end
76
+
77
+ end
78
+
79
+ end
@@ -0,0 +1,8 @@
1
+ == README
2
+
3
+ To change the test database in this dummy app:
4
+
5
+ - Delete the existing test.sqlite3
6
+ - No migrations, so just make whatever changes you want to schema.rb
7
+
8
+ bundle exec rake app:db:test:prepare
@@ -0,0 +1,6 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require File.expand_path('../config/application', __FILE__)
5
+
6
+ Rails.application.load_tasks
@@ -0,0 +1,13 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file.
9
+ //
10
+ // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require_tree .
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any styles
10
+ * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
11
+ * file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,5 @@
1
+ class ApplicationController < ActionController::Base
2
+ # Prevent CSRF attacks by raising an exception.
3
+ # For APIs, you may want to use :null_session instead.
4
+ protect_from_forgery with: :exception
5
+ end
@@ -0,0 +1,2 @@
1
+ module ApplicationHelper
2
+ end