effective_orders 1.0.0

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 (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,107 @@
1
+ require 'spec_helper'
2
+
3
+ # # Attributes
4
+ describe Product do
5
+ let(:user) { FactoryGirl.create(:user) }
6
+ let(:order) { FactoryGirl.create(:order) }
7
+ let(:product) { order.order_items.first.purchasable }
8
+ let(:product_with_float_price) { FactoryGirl.create(:product_with_float_price) }
9
+
10
+ describe 'assumptions' do
11
+ it 'should be effectively purchasable' do
12
+ product.is_effectively_purchasable?.should eq true
13
+ end
14
+ end
15
+
16
+ describe 'purchased' do
17
+ it 'is purchased? when in a purchased Order' do
18
+ order.purchase!('by a test')
19
+
20
+ product.purchased?.should eq true
21
+ product.purchased_orders.include?(order).should eq true
22
+ end
23
+
24
+ it 'is returned by the purchased scopes' do
25
+ order.purchase!('by a test')
26
+
27
+ Product.purchased.to_a.include?(product).should eq true
28
+ Product.purchased_by(order.user).to_a.include?(product).should eq true
29
+
30
+ Product.sold.to_a.include?(product).should eq true
31
+
32
+ Product.not_purchased.to_a.include?(product).should eq false
33
+ end
34
+ end
35
+
36
+ describe 'float prices' do
37
+ it 'should automatically convert float prices to integer' do
38
+ product_with_float_price.price = 20.00
39
+ product_with_float_price.tax_exempt = true
40
+
41
+ order = Effective::Order.new(product_with_float_price, user)
42
+
43
+ order.subtotal.should eq 2000
44
+ order.tax.should eq 0
45
+ order.total.should eq 2000
46
+ end
47
+
48
+ it 'should automatically convert tax floats to integers' do
49
+ product_with_float_price.price = 20.00
50
+ product_with_float_price.tax_exempt = false
51
+
52
+ order = Effective::Order.new(product_with_float_price, user)
53
+
54
+ order.subtotal.should eq 2000
55
+ order.tax.should eq 100
56
+ order.total.should eq 2100
57
+ end
58
+ end
59
+
60
+ describe 'price=' do
61
+ it 'should accept an integer price' do
62
+ product = Product.new()
63
+ product.price = 1250
64
+
65
+ product.price.should eq 1250
66
+ end
67
+
68
+ it 'should convert a String that looks like an Integer' do
69
+ product = Product.new()
70
+ product.price = '1250'
71
+
72
+ product.price.should eq 1250
73
+ end
74
+
75
+ it 'should convert a String that looks like a Float' do
76
+ product = Product.new()
77
+ product.price = '12.50'
78
+
79
+ product.price.should eq 1250
80
+ end
81
+
82
+ it 'should convert from a Float' do
83
+ product = Product.new()
84
+ product.price = 12.50
85
+ product.price.should eq 1250
86
+
87
+ product.price = Float(12.50)
88
+ product.price.should eq 1250
89
+ end
90
+
91
+ it 'should convert from a BigDecimal' do
92
+ product = Product.new()
93
+ product.price = BigDecimal.new(12.5, 4)
94
+
95
+ product.price.should eq 1250
96
+ end
97
+
98
+ it 'should treat nil as a zero' do
99
+ product = Product.new()
100
+ product.price = nil
101
+
102
+ product.price.should eq 0
103
+ end
104
+
105
+ end
106
+
107
+ end
@@ -0,0 +1,71 @@
1
+ require 'spec_helper'
2
+
3
+ require 'stripe_mock'
4
+
5
+ # # Attributes
6
+ describe Effective::Customer do
7
+ let(:customer) { FactoryGirl.create(:customer) }
8
+ let(:user) { FactoryGirl.create(:user) }
9
+
10
+ describe 'Customer.for_user' do
11
+ it 'creates a new Customer when passed a new user' do
12
+ c = Effective::Customer.for_user(user)
13
+
14
+ c.kind_of?(Effective::Customer).should eq true
15
+ c.persisted?.should eq true
16
+ c.valid?.should eq true
17
+ c.user.should eq user
18
+ end
19
+
20
+ it 'returns an existing Customer when passed an existing user' do
21
+ c = Effective::Customer.for_user(customer.user)
22
+ c.should eq customer
23
+ end
24
+ end
25
+
26
+ describe 'Stripe Integration' do
27
+ before { StripeMock.start }
28
+ after { StripeMock.stop }
29
+
30
+ describe '#stripe_customer' do
31
+ it 'creates a new Stripe::Customer if one doesnt exist.' do
32
+ stripe_customer = customer.stripe_customer
33
+
34
+ stripe_customer.kind_of?(::Stripe::Customer).should eq true
35
+
36
+ stripe_customer.email.should eq customer.user.email
37
+ stripe_customer.id.should eq customer.stripe_customer_id
38
+ end
39
+
40
+ it 'retrieves an existing Stripe::Customer if exists' do
41
+ # Test set up. Create the user.
42
+ user = customer.user
43
+ stripe_customer = ::Stripe::Customer.create(:email => user.email, :description => user.id.to_s)
44
+ customer.update_attributes(:stripe_customer_id => stripe_customer.id)
45
+
46
+ customer.reload
47
+
48
+ customer.stripe_customer.id.should eq stripe_customer.id
49
+ end
50
+ end
51
+
52
+ describe '#update_card' do
53
+ it 'can update the card' do
54
+ customer.update_card!('sometoken').should eq true
55
+ end
56
+
57
+ it 'updates stripe_active_card when updating the card' do
58
+ customer.should_receive(:save!).and_return(true)
59
+ customer.update_card!('sometoken').should eq true
60
+
61
+ customer.stripe_active_card.present?.should eq true
62
+ end
63
+
64
+ end
65
+
66
+ end
67
+
68
+
69
+
70
+
71
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ # Attributes
4
+ describe 'Factories' do
5
+ let(:factories) { [:user, :customer, :subscription, :address, :product, :cart, :order_item, :order, :purchased_order, :declined_order, :cart_with_subscription, :order_with_subscription] }
6
+
7
+ before { StripeMock.start }
8
+ after { StripeMock.stop }
9
+
10
+ it 'should have all valid factories' do
11
+ factories.each { |factory| FactoryGirl.create(factory).valid?.should eq true }
12
+ end
13
+ end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ # # Attributes
4
+ describe Effective::OrderItem do
5
+ let(:order) { FactoryGirl.create(:order) }
6
+ let(:order_item) { FactoryGirl.create(:order_item) }
7
+
8
+ describe 'validations' do
9
+ it 'is invalid without required fields' do
10
+ order_item = Effective::OrderItem.new()
11
+ order_item.valid?.should eq false
12
+
13
+ order_item.errors[:title].present?.should eq true
14
+ order_item.errors[:quantity].present?.should eq true
15
+ order_item.errors[:tax_exempt].present?.should eq true
16
+ order_item.errors[:purchasable].present?.should eq true
17
+ end
18
+ end
19
+
20
+ describe 'scopes' do
21
+ it 'is included in the Sold scope when order is purchased' do
22
+ order.purchase!('from a test')
23
+ (order.order_items.size > 0).should eq true
24
+
25
+ sold_items = Effective::OrderItem.sold.to_a
26
+ sold_items.size.should eq order.order_items.size
27
+
28
+ order.order_items.each { |oi| sold_items.include?(oi).should eq true }
29
+ end
30
+
31
+ end
32
+
33
+
34
+
35
+ end
@@ -0,0 +1,323 @@
1
+ require 'spec_helper'
2
+
3
+ describe Effective::Order do
4
+ let(:cart) { FactoryGirl.create(:cart) }
5
+ let(:order) { FactoryGirl.create(:order) }
6
+ let(:user) { FactoryGirl.create(:user) }
7
+ let(:product) { FactoryGirl.create(:product) }
8
+ let(:product2) { FactoryGirl.create(:product) }
9
+
10
+ it 'calculates dollars based on its order items' do
11
+ order.total.should eq order.order_items.collect(&:total).sum
12
+ order.subtotal.should eq order.order_items.collect(&:subtotal).sum
13
+ order.tax.should eq order.order_items.collect(&:tax).sum
14
+ order.num_items.should eq order.order_items.collect(&:quantity).sum
15
+ end
16
+
17
+ describe '#initialize' do
18
+ it 'creates appropriate OrderItems when initialized with a Cart' do
19
+ order = Effective::Order.new(cart)
20
+
21
+ order.order_items.each_with_index do |order_item, x|
22
+ order_item.title.should eq cart.cart_items[x].title
23
+ order_item.price.should eq cart.cart_items[x].price
24
+ order_item.quantity.should eq cart.cart_items[x].quantity
25
+ order_item.purchasable.should eq cart.cart_items[x].purchasable
26
+ end
27
+
28
+ order.order_items.length.should eq cart.cart_items.length
29
+ order.total.should eq cart.total
30
+ order.subtotal.should eq cart.subtotal
31
+ order.tax.should eq cart.tax
32
+ end
33
+
34
+ it 'creates appropriate OrderItems when initialized with an array of purchasables' do
35
+ order = Effective::Order.new([product, product2])
36
+ order.order_items.size.should eq 2
37
+
38
+ order.subtotal.should eq (product.price + product2.price)
39
+ order.total.should eq ((product.price + product2.price) * 1.05)
40
+ end
41
+
42
+ it 'creates appropriate OrderItems when initialized with a single purchasable' do
43
+ order = Effective::Order.new(product)
44
+ order.order_items.size.should eq 1
45
+
46
+ order_item = order.order_items.first
47
+
48
+ order_item.title.should eq product.title
49
+ order_item.price.should eq product.price
50
+ order_item.purchasable.should eq product
51
+ order_item.quantity.should eq 1
52
+ end
53
+
54
+ it 'throws an ArgumentError when passed something unexpected' do
55
+ expect { Effective::Order.new(Object.new()) }.to raise_error(ArgumentError)
56
+ end
57
+ end
58
+
59
+ describe 'minimum zero math' do
60
+ it 'has a minimum order total of 0' do
61
+ order.order_items.each { |order_item| order_item.stub(:total).and_return(-1000) }
62
+
63
+ order.order_items.collect(&:total).sum.should eq -3000
64
+ order.total.should eq 0
65
+ end
66
+
67
+ it 'has no minimum subtotal' do
68
+ order.order_items.each { |order_item| order_item.stub(:subtotal).and_return(-1000) }
69
+
70
+ order.order_items.collect(&:subtotal).sum.should eq -3000
71
+ order.subtotal.should eq -3000
72
+ end
73
+
74
+ it 'has a minimum order tax of 0.00' do
75
+ order.order_items.each { |order_item| order_item.stub(:tax).and_return(-1000) }
76
+
77
+ order.order_items.collect(&:tax).sum.should eq -3000
78
+ order.tax.should eq 0
79
+ end
80
+ end
81
+
82
+ describe 'user=' do
83
+ it 'assigns the user' do
84
+ order = Effective::Order.new()
85
+ order.user = user
86
+ order.user.should eq user
87
+ end
88
+
89
+ it 'assigns addresses from the user' do
90
+ order = Effective::Order.new()
91
+
92
+ user.billing_address = FactoryGirl.create(:address, :category => :billing)
93
+ user.shipping_address = FactoryGirl.create(:address, :category => :shipping)
94
+
95
+ order.user = user
96
+
97
+ order.billing_address.should eq user.billing_address
98
+ order.save_billing_address.should eq true
99
+
100
+ order.shipping_address.should eq user.shipping_address
101
+ order.save_shipping_address.should eq true
102
+ end
103
+ end
104
+
105
+ describe 'validations' do
106
+ it 'should be invalid without a user or order_items' do
107
+ order = Effective::Order.new()
108
+ order.valid?.should eq false
109
+
110
+ order.errors[:user_id].present?.should eq true
111
+ order.errors[:order_items].present?.should eq true
112
+ end
113
+
114
+ it 'should be invalid when user is invalid' do
115
+ order.user.stub(:valid?).and_return(false)
116
+ order.valid?.should eq false
117
+
118
+ order.errors[:user].present?.should eq true
119
+ end
120
+
121
+ it 'should be invalid when an order_item is invalid' do
122
+ order.order_items.first.stub(:valid?).and_return(false)
123
+ order.valid?.should eq false
124
+
125
+ order.errors[:order_items].present?.should eq true
126
+ end
127
+
128
+ it 'should be invalid when less than the minimum charge' do
129
+ order.stub(:total).and_return(49)
130
+
131
+ order.valid?.should eq false
132
+
133
+ order.errors[:total].present?.should eq true
134
+ order.errors[:total].first.downcase.include?('minimum order of 50 is required').should eq true
135
+ end
136
+
137
+ it 'should be valid when >= minimum charge' do
138
+ order.stub(:total).and_return(50)
139
+ order.valid?.should eq true
140
+
141
+ order.stub(:total).and_return(51)
142
+ order.valid?.should eq true
143
+ end
144
+
145
+ it 'should be valid for a free order' do
146
+ order.order_items.each { |order_item| order_item.stub(:total).and_return(0) }
147
+
148
+ order.valid?.should eq true
149
+ order.errors[:total].present?.should eq false
150
+ end
151
+ end
152
+
153
+ describe 'purchase!' do
154
+ it 'assigns the purchase_state, purchase_at and payment' do
155
+ order.purchase!('by a test').should eq true
156
+
157
+ order.purchase_state.should eq EffectiveOrders::PURCHASED
158
+ order.purchased_at.kind_of?(Time).should eq true
159
+ order.payment[:details].should eq 'by a test'
160
+ end
161
+
162
+ it 'sends purchased callback to all order_items' do
163
+ order.order_items.each { |oi| oi.purchasable.should_receive(:purchased!).with(order, oi) }
164
+ order.purchase!('by a test')
165
+ end
166
+
167
+ it 'throws an error when purchased twice' do
168
+ order.purchase!('first time')
169
+
170
+ expect { order.purchase!('second time') }.to raise_error(EffectiveOrders::AlreadyPurchasedException)
171
+ end
172
+
173
+ it 'sends emails to the admin, buyer and seller' do
174
+ Effective::OrdersMailer.deliveries.clear
175
+
176
+ order.purchase!('by a test')
177
+
178
+ Effective::OrdersMailer.deliveries.length.should eq 2
179
+
180
+ Effective::OrdersMailer.deliveries[0].to.first.should eq 'admin@example.com'
181
+ Effective::OrdersMailer.deliveries[0].subject.include?("Order ##{order.to_param} Receipt").should eq true
182
+
183
+ Effective::OrdersMailer.deliveries[1].to.first.should eq order.user.email
184
+ Effective::OrdersMailer.deliveries[1].subject.include?("Order ##{order.to_param} Receipt").should eq true
185
+ end
186
+
187
+ it 'does not send email if passed :email => false' do
188
+ Effective::OrdersMailer.deliveries.clear
189
+
190
+ order.purchase!('by a test', :email => false)
191
+
192
+ Effective::OrdersMailer.deliveries.length.should eq 0
193
+ end
194
+
195
+ it 'is included with the purchased scope' do
196
+ order.purchase!('by a test')
197
+ Effective::Order.purchased.to_a.include?(order).should eq true
198
+ Effective::Order.purchased_by(order.user).to_a.include?(order).should eq true
199
+ end
200
+
201
+ it 'is not included with the declined scope' do
202
+ order.purchase!('by a test')
203
+ Effective::Order.declined.to_a.include?(order).should eq false
204
+ end
205
+
206
+ it 'should return false when the Order is invalid' do
207
+ order.stub(:valid?).and_return(false)
208
+ expect { order.purchase!('by a test') }.to raise_exception
209
+ end
210
+
211
+ it 'should return true when the Order is invalid and :validate => false is passed' do
212
+ order.stub(:valid?).and_return(false)
213
+ order.purchase!('by a test', :validate => false).should eq true
214
+ end
215
+
216
+ end
217
+
218
+ describe 'purchased?' do
219
+ it 'returns true when a purchased order' do
220
+ order.purchase!('by a test')
221
+ order.purchased?.should eq true
222
+ end
223
+
224
+ it 'returns false when not purchased' do
225
+ order.purchased?.should eq false
226
+ end
227
+
228
+ it 'returns false when declined' do
229
+ order.decline!('by a test')
230
+ order.purchased?.should eq false
231
+ end
232
+ end
233
+
234
+ describe 'decline!' do
235
+ it 'assigns the purchase_state' do
236
+ order.decline!('by a test').should eq true
237
+
238
+ order.purchase_state.should eq EffectiveOrders::DECLINED
239
+ order.payment[:details].should eq 'by a test'
240
+ order.purchased_at.should eq nil
241
+ end
242
+
243
+ it 'sends declined callback to all order_items' do
244
+ order.order_items.each { |oi| oi.purchasable.should_receive(:declined!).with(order, oi) }
245
+ order.decline!('by a test')
246
+ end
247
+
248
+ it 'throws an error when declined twice' do
249
+ order.decline!('first time')
250
+
251
+ expect { order.decline!('second time') }.to raise_error(EffectiveOrders::AlreadyDeclinedException)
252
+ end
253
+
254
+ it 'is included with the declined scope' do
255
+ order.decline!('by a test')
256
+ Effective::Order.declined.to_a.include?(order).should eq true
257
+ end
258
+
259
+ it 'is not included with the purchased scope' do
260
+ order.decline!('by a test')
261
+ Effective::Order.purchased.to_a.include?(order).should eq false
262
+ Effective::Order.purchased_by(order.user).to_a.include?(order).should eq false
263
+ end
264
+ end
265
+
266
+ describe 'declined?' do
267
+ it 'returns true when a declined order' do
268
+ order.decline!('by a test')
269
+ order.declined?.should eq true
270
+ end
271
+
272
+ it 'returns false when not declined' do
273
+ order.declined?.should eq false
274
+ end
275
+
276
+ it 'returns false when purchased' do
277
+ order.purchase!('by a test')
278
+ order.declined?.should eq false
279
+ end
280
+ end
281
+
282
+ describe '#save_billing_address?' do
283
+ it 'is true when save_billing_address is 1' do
284
+ order.save_billing_address = '1'
285
+ order.save_billing_address?.should eq true
286
+ end
287
+
288
+ it 'is false when save_billing_address is 0' do
289
+ order.save_billing_address = '0'
290
+ order.save_billing_address?.should eq false
291
+ end
292
+
293
+ it 'is false when save_billing_address is nil' do
294
+ order.save_billing_address = nil
295
+ order.save_billing_address?.should eq false
296
+ end
297
+ end
298
+
299
+ describe '#save_shipping_address?' do
300
+ it 'is true when save_shipping_address is 1' do
301
+ order.save_shipping_address = '1'
302
+ order.save_shipping_address?.should eq true
303
+ end
304
+
305
+ it 'is false when save_shipping_address is 0' do
306
+ order.save_shipping_address = '0'
307
+ order.save_shipping_address?.should eq false
308
+ end
309
+
310
+ it 'is false when save_shipping_address is nil' do
311
+ order.save_shipping_address = nil
312
+ order.save_shipping_address?.should eq false
313
+ end
314
+ end
315
+
316
+ describe '#to_param' do
317
+ it 'returns an obfuscated ID' do
318
+ (order.to_param.length >= 10).should eq true
319
+ end
320
+ end
321
+
322
+
323
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ # # Attributes
4
+ describe Effective::StripeCharge do
5
+ let(:order) { FactoryGirl.create(:order_with_subscription) }
6
+ let(:charge) { Effective::StripeCharge.new(order) }
7
+
8
+ before { StripeMock.start }
9
+ after { StripeMock.stop }
10
+
11
+ it 'can be initialized with an order' do
12
+ charge = Effective::StripeCharge.new(order)
13
+ charge.order.should eq order
14
+ charge.effective_order_id.should eq order.to_param
15
+ end
16
+
17
+ it 'can be initialized without an order' do
18
+ charge = Effective::StripeCharge.new(:token => 'tok_123', :effective_order_id => 3)
19
+ charge.token.should eq 'tok_123'
20
+ charge.effective_order_id.should eq 3
21
+ charge.order.nil?.should eq true
22
+ end
23
+
24
+ it 'performs validations' do
25
+ charge = Effective::StripeCharge.new()
26
+ charge.valid?.should eq false
27
+ charge.errors[:token].present?.should eq true
28
+ charge.errors[:effective_order_id].present?.should eq true
29
+ end
30
+
31
+ it '#order_items returns all OrderItems where the purchasable is not a Subscription' do
32
+ charge.order_items.all? { |oi| oi.purchasable_type != 'Effective::Subscription'}.should eq true
33
+ end
34
+
35
+ it '#subscriptions returns all Subscriptions (not order items)' do
36
+ charge.subscriptions.all? { |oi| oi.kind_of?(Effective::Subscription) }.should eq true
37
+ end
38
+
39
+ end
@@ -0,0 +1,103 @@
1
+ require 'spec_helper'
2
+
3
+ # # Attributes
4
+ describe Effective::Subscription do
5
+ let(:subscription) { FactoryGirl.create(:subscription) }
6
+
7
+ before { StripeMock.start }
8
+ after { StripeMock.stop }
9
+
10
+ describe '#stripe_plan' do
11
+
12
+ end
13
+
14
+ describe '#stripe_plan_id=' do
15
+ it 'assigns the stripe_plan_id' do
16
+ subscription.stripe_plan_id = 'Plan 9'
17
+ subscription.stripe_plan_id.should eq 'Plan 9'
18
+ end
19
+
20
+ it 'rejects an invalid stripe_plan' do
21
+ subscription.stripe_plan.present?.should eq true # From the Factory
22
+
23
+ subscription.stripe_plan_id = 'Plan 9' # Set it to an Invalid plan
24
+ subscription.stripe_plan_id.should eq 'Plan 9'
25
+
26
+ subscription.stripe_plan.should eq nil
27
+ end
28
+
29
+ it 'sets the stripe plan' do
30
+ subscription = Effective::Subscription.new()
31
+
32
+ plan = ::Stripe::Plan.create()
33
+ subscription.stripe_plan_id = plan.id
34
+ subscription.stripe_plan.id.should eq plan.id
35
+ end
36
+ end
37
+
38
+ describe '#stripe_coupon_id=' do
39
+ it 'assigns the stripe_coupon_id' do
40
+ subscription.stripe_coupon_id = 'Plan 9'
41
+ subscription.stripe_coupon_id.should eq 'Plan 9'
42
+ end
43
+
44
+ it 'rejects an invalid stripe_coupon' do
45
+ subscription.stripe_coupon.present?.should eq true # From the Factory
46
+
47
+ subscription.stripe_coupon_id = 'Plan 9' # Set it to an Invalid plan
48
+ subscription.stripe_coupon_id.should eq 'Plan 9'
49
+
50
+ subscription.stripe_coupon.should eq nil
51
+ end
52
+
53
+ it 'sets the stripe coupon' do
54
+ subscription = Effective::Subscription.new()
55
+
56
+ coupon = ::Stripe::Coupon.create()
57
+ subscription.stripe_coupon_id = coupon.id
58
+ subscription.stripe_coupon.id.should eq coupon.id
59
+ end
60
+ end
61
+
62
+ describe '#assign_price_and_title' do
63
+ it 'assigns the price and title as per the stripe plan and coupon' do
64
+ subscription = Effective::Subscription.new()
65
+
66
+ plan = ::Stripe::Plan.create()
67
+
68
+ subscription.stripe_plan_id = plan.id
69
+
70
+ subscription.price.should eq plan.amount
71
+ subscription.title.include?(plan.name).should eq true
72
+ subscription.title.include?(plan.interval).should eq true
73
+ end
74
+
75
+ it 'assigns the price and title as per the stripe plan and coupon amount off' do
76
+ subscription = Effective::Subscription.new()
77
+
78
+ plan = ::Stripe::Plan.create()
79
+ coupon = ::Stripe::Coupon.create(:percent_off => 25)
80
+
81
+ subscription.stripe_plan_id = plan.id
82
+ subscription.stripe_coupon_id = coupon.id
83
+
84
+ subscription.price.should eq (plan.amount * (coupon.percent_off.to_i / 100.0)).floor
85
+ subscription.title.include?('25% off').should eq true
86
+ end
87
+
88
+ it 'assigns the price and title as per the stripe plan and coupon percent off' do
89
+ subscription = Effective::Subscription.new()
90
+
91
+ plan = ::Stripe::Plan.create()
92
+ coupon = ::Stripe::Coupon.create(:percent_off => nil, :amount_off => 100)
93
+
94
+ subscription.stripe_plan_id = plan.id
95
+ subscription.stripe_coupon_id = coupon.id
96
+
97
+ subscription.price.should eq plan.amount - coupon.amount_off
98
+ subscription.title.include?('$1.00 off').should eq true
99
+ end
100
+ end
101
+
102
+
103
+ end