caboose-cms 0.5.69 → 0.5.70

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 (58) hide show
  1. checksums.yaml +8 -8
  2. data/app/assets/javascripts/caboose/admin.js +2 -1
  3. data/app/assets/javascripts/caboose/admin_edit_order.js +0 -13
  4. data/app/assets/javascripts/caboose/admin_main.js +13 -0
  5. data/app/assets/javascripts/caboose/cart.js +145 -161
  6. data/app/assets/javascripts/caboose/cart_old.js +176 -0
  7. data/app/assets/javascripts/caboose/checkout.js +1 -1
  8. data/app/assets/javascripts/caboose/{checkout_step2.js → checkout_addresses.js} +3 -3
  9. data/app/assets/javascripts/caboose/checkout_gift_cards.js +47 -0
  10. data/app/assets/javascripts/caboose/{checkout_step1.js → checkout_login_register.js} +5 -53
  11. data/app/assets/javascripts/caboose/checkout_module.js +3 -4
  12. data/app/assets/javascripts/caboose/{checkout_step4.js → checkout_payment.js} +8 -8
  13. data/app/assets/javascripts/caboose/{checkout_step3.js → checkout_shipping.js} +5 -5
  14. data/app/assets/javascripts/caboose/imageZoom.js +66 -0
  15. data/app/assets/javascripts/caboose/model/attribute.js +2 -1
  16. data/app/assets/javascripts/caboose/model/bound_select.js +15 -6
  17. data/app/assets/javascripts/caboose/product.js +12 -2
  18. data/app/assets/stylesheets/caboose/checkout.css.scss +1 -0
  19. data/app/assets/templates/caboose/checkout/address.jst.ejs +1 -1
  20. data/app/controllers/caboose/cart_controller.rb +60 -8
  21. data/app/controllers/caboose/checkout_controller.rb +42 -71
  22. data/app/controllers/caboose/gift_cards_controller.rb +216 -0
  23. data/app/controllers/caboose/users_controller.rb +2 -2
  24. data/app/helpers/caboose/checkout_helper.rb +6 -5
  25. data/app/models/caboose/core_plugin.rb +2 -1
  26. data/app/models/caboose/discount.rb +8 -13
  27. data/app/models/caboose/gift_card.rb +49 -0
  28. data/app/models/caboose/order.rb +66 -46
  29. data/app/models/caboose/order_package.rb +11 -4
  30. data/app/models/caboose/order_package_calculator.rb +102 -0
  31. data/app/models/caboose/product_image.rb +10 -0
  32. data/app/models/caboose/schema.rb +38 -29
  33. data/app/models/caboose/shipping_calculator.rb +4 -2
  34. data/app/models/caboose/shipping_package.rb +7 -0
  35. data/app/views/caboose/cart/index.html.erb +12 -2
  36. data/app/views/caboose/checkout/#Untitled-1# +2 -0
  37. data/app/views/caboose/checkout/_cart.html.erb +45 -48
  38. data/app/views/caboose/checkout/_cart_old.html.erb +49 -0
  39. data/app/views/caboose/checkout/_confirm.html.erb +6 -4
  40. data/app/views/caboose/checkout/_confirm_table.html.erb +0 -0
  41. data/app/views/caboose/checkout/{step_two.html.erb → addresses.html.erb} +2 -2
  42. data/app/views/caboose/checkout/gift_cards.html.erb +35 -0
  43. data/app/views/caboose/checkout/index.html.erb +53 -42
  44. data/app/views/caboose/checkout/payment.html.erb +108 -75
  45. data/app/views/caboose/checkout/shipping.html.erb +62 -13
  46. data/app/views/caboose/gift_cards/admin_edit.html.erb +89 -0
  47. data/app/views/caboose/gift_cards/admin_index.html.erb +52 -0
  48. data/config/routes.rb +39 -19
  49. data/lib/caboose/engine.rb +1 -0
  50. data/lib/caboose/version.rb +1 -1
  51. metadata +20 -14
  52. data/app/assets/javascripts/caboose/cart2.js +0 -98
  53. data/app/views/caboose/checkout/step_four.html.erb +0 -67
  54. data/app/views/caboose/checkout/step_four_old.html.erb +0 -63
  55. data/app/views/caboose/checkout/step_one.html.erb +0 -54
  56. data/app/views/caboose/checkout/step_one_old.html.erb +0 -13
  57. data/app/views/caboose/checkout/step_three.html.erb +0 -55
  58. data/app/views/caboose/checkout/step_two_old.html.erb +0 -14
@@ -390,6 +390,7 @@
390
390
  }
391
391
 
392
392
  #checkout-confirm {
393
+ margin-top: 10px;
393
394
  width: 100%;
394
395
  #line-items { width: 100%; margin: 0 auto;
395
396
  table {
@@ -1,5 +1,5 @@
1
1
  <div class="wrapper">
2
- <form action="/checkout/address" method="put">
2
+ <form action="/checkout/addresses" method="put">
3
3
  <section>
4
4
  <fieldset id="shipping">
5
5
  <h3>Shipping Address</h3>
@@ -7,14 +7,29 @@ module Caboose
7
7
 
8
8
  # GET /cart/items
9
9
  def list
10
- render :json => @order.as_json(:include => [
11
- { :line_items => { :include => { :variant => { :include => :product }}}},
12
- { :order_packages => { :include => [:shipping_package, :shipping_method] }},
13
- :customer,
14
- :shipping_address,
15
- :billing_address,
16
- :order_transactions
17
- ])
10
+ render :json => @order.as_json(
11
+ :include => [
12
+ {
13
+ :line_items => {
14
+ :include => {
15
+ :variant => {
16
+ :include => [
17
+ { :product_images => { :methods => :urls }},
18
+ { :product => { :include => { :product_images => { :methods => :urls }}}}
19
+ ],
20
+ :methods => :title
21
+ }
22
+ }
23
+ }
24
+ },
25
+ { :order_packages => { :include => [:shipping_package, :shipping_method] }},
26
+ :customer,
27
+ :shipping_address,
28
+ :billing_address,
29
+ :order_transactions,
30
+ { :discounts => { :include => :gift_card }}
31
+ ]
32
+ )
18
33
  end
19
34
 
20
35
  # GET /cart/item-count
@@ -60,6 +75,43 @@ module Caboose
60
75
  li = LineItem.find(params[:line_item_id]).destroy
61
76
  render :json => { :success => true, :item_count => @order.line_items.count }
62
77
  end
78
+
79
+ # POST /cart/gift-cards
80
+ def add_gift_card
81
+ resp = StdClass.new
82
+ code = params[:code].strip
83
+ gc = GiftCard.where("lower(code) = ?", code.downcase).first
84
+
85
+ if gc.nil? then resp.error = "Invalid gift card code."
86
+ elsif gc.status != GiftCard::STATUS_ACTIVE then resp.error = "That gift card is not active."
87
+ elsif gc.date_available && DateTime.now.utc < self.date_available then resp.error = "That gift card is not active yet."
88
+ elsif gc.date_expires && DateTime.now.utc > self.date_expires then resp.error = "That gift card is expired."
89
+ elsif gc.card_type == GiftCard::CARD_TYPE_AMOUNT && gc.balance <= 0 then resp.error = "That gift card has a zero balance."
90
+ elsif gc.min_order_total && @order.total < gc.min_order_total then resp.error = "Your order must be at least $#{sprintf('%.2f',gc.min_order_total)} to use this gift card."
91
+ elsif Discount.where(:order_id => @order.id, :gift_card_id => gc.id).exists? then resp.error = "That gift card has already been applied to this order."
92
+ else
93
+ # Determine how much the discount will be
94
+ d = Discount.new(:order_id => @order.id, :gift_card_id => gc.id, :amount => 0.0)
95
+ case gc.card_type
96
+ when GiftCard::CARD_TYPE_AMOUNT then d.amount = (@order.total > gc.balance ? gc.balance : @order.total)
97
+ when GiftCard::CARD_TYPE_PERCENTAGE then d.amount = @order.subtotal * gc.total
98
+ when GiftCard::CARD_TYPE_NO_SHIPPING then d.amount = @order.shipping
99
+ when GiftCard::CARD_TYPE_NO_TAX then d.amount = @order.tax
100
+ end
101
+ d.save
102
+ @order.calculate
103
+ resp.success = true
104
+ resp.order_total = @order.total
105
+ end
106
+ render :json => resp
107
+ end
108
+
109
+ # DELETE /cart/discounts/:discount_id
110
+ def remove_discount
111
+ Discount.find(params[:discount_id]).destroy
112
+ @order.calculate
113
+ render :json => { :success => true }
114
+ end
63
115
  end
64
116
  end
65
117
 
@@ -10,52 +10,57 @@ module Caboose
10
10
  redirect_to '/checkout/empty' if @order.line_items.empty?
11
11
  end
12
12
 
13
+ # Step 1 - Login or register
13
14
  # GET /checkout
14
- def index
15
- redirect_to '/checkout/step-one'
16
- end
17
-
18
- # GET /checkout/step-one
19
- def step_one
15
+ def index
20
16
  if logged_in?
21
17
  if @order.customer_id.nil?
22
18
  @order.customer_id = logged_in_user.id
23
19
  @order.save
24
20
  end
25
- redirect_to '/checkout/step-two'
21
+ redirect_to '/checkout/addresses'
26
22
  return
27
23
  end
28
24
  end
29
25
 
30
- # GET /checkout/step-two
31
- def step_two
32
- #redirect_to '/checkout/step-one' if !@order.shipping_address || !@order.billing_address
33
- redirect_to '/checkout/step-one' if !logged_in?
26
+ # Step 2 - Shipping and billing addresses
27
+ # GET /checkout/addresses
28
+ def addresses
29
+ redirect_to '/checkout' if !logged_in?
34
30
  end
35
31
 
36
- # GET /checkout/step-three
37
- def step_three
38
- redirect_to '/checkout/step-one' and return if !logged_in?
39
- redirect_to '/checkout/step-two' and return if @order.shipping_address.nil? || @order.billing_address.nil?
40
-
32
+ # Step 3 - Shipping method
33
+ # GET /checkout/shipping
34
+ def shipping
35
+ redirect_to '/checkout' and return if !logged_in?
36
+ redirect_to '/checkout/addresses' and return if @order.shipping_address.nil? || @order.billing_address.nil?
37
+
41
38
  # Remove any order packages
42
39
  LineItem.where(:order_id => @order.id).update_all(:order_package_id => nil)
43
40
  OrderPackage.where(:order_id => @order.id).destroy_all
44
-
41
+
45
42
  # Calculate what shipping packages we'll need
46
43
  OrderPackage.create_for_order(@order)
47
44
 
48
- # Now get the rates for those packages
49
- Caboose.log("Getting rates...")
45
+ # Now get the rates for those packages
50
46
  @rates = ShippingCalculator.rates(@order)
51
47
  Caboose.log(@rates.inspect)
52
48
  end
53
49
 
54
- # GET /checkout/step-four
55
- def step_four
56
- redirect_to '/checkout/step-one' and return if !logged_in?
57
- redirect_to '/checkout/step-two' and return if @order.shipping_address.nil? || @order.billing_address.nil?
58
- redirect_to '/checkout/step-three' and return if @order.shipping_service_code.nil?
50
+ # Step 4 - Gift cards
51
+ # GET /checkout/gift-cards
52
+ def gift_cards
53
+ redirect_to '/checkout' and return if !logged_in?
54
+ redirect_to '/checkout/addresses' and return if @order.shipping_address.nil? || @order.billing_address.nil?
55
+ redirect_to '/checkout/shipping' and return if @order.shipping_service_code.nil?
56
+ end
57
+
58
+ # Step 5 - Payment
59
+ # GET /checkout/payment
60
+ def payment
61
+ redirect_to '/checkout' and return if !logged_in?
62
+ redirect_to '/checkout/addresses' and return if @order.shipping_address.nil? || @order.billing_address.nil?
63
+ redirect_to '/checkout/shipping' and return if @order.shipping_service_code.nil?
59
64
 
60
65
  # Make sure all the variants still exist
61
66
  @order.line_items.each do |li|
@@ -103,8 +108,8 @@ module Caboose
103
108
  }
104
109
  end
105
110
 
106
- # PUT /checkout/address
107
- def update_address
111
+ # PUT /checkout/addresses
112
+ def update_addresses
108
113
 
109
114
  # Grab or create addresses
110
115
  shipping_address = if @order.shipping_address then @order.shipping_address else Address.new end
@@ -177,7 +182,7 @@ module Caboose
177
182
  resp.errors = @order.errors.full_messages
178
183
  else
179
184
  @order.save
180
- resp.redirect = '/checkout/step-two'
185
+ resp.redirect = '/checkout/addresses'
181
186
  end
182
187
  end
183
188
  render :json => resp
@@ -190,29 +195,13 @@ module Caboose
190
195
 
191
196
  # PUT /checkout/shipping
192
197
  def update_shipping
193
-
194
- rates = ShippingCalculator.rates(@order)
195
-
196
- if @site.store_config.calculate_packages
197
- # TODO: Add the separate shipping costs for each package
198
- else
199
- @order.shipping_carrier = params[:carrier]
200
- @order.shipping_service_code = params[:service_code]
201
- @order.shipping_service_name = params[:service_name]
202
-
203
- rates[0][:rates].each do |rate|
204
- if rate[:carrier] == params[:carrier] && rate[:service_code] == params[:service_code]
205
- @order.shipping = rate[:total_price]
206
- break
207
- end
208
- end
209
- end
210
- render :json => {
211
- :success => @order.save,
212
- :errors => @order.errors.full_messages
213
- #:order => @order,
214
- #:selected_rate => ShippingCalculator.rate(@order)
215
- }
198
+ op = OrderPackage.find(params[:order_package_id])
199
+ op.shipping_method_id = params[:shipping_method_id]
200
+ op.total = params[:total]
201
+ op.save
202
+ op.order.calculate
203
+
204
+ render :json => { :success => true }
216
205
  end
217
206
 
218
207
  # GET /checkout/payment
@@ -254,6 +243,9 @@ module Caboose
254
243
  if ot.success
255
244
  order.financial_status = 'authorized'
256
245
  order.status = 'pending'
246
+
247
+ # Take funds from any gift cards that were used on the order
248
+ order.take_gift_card_funds
257
249
 
258
250
  # Send out emails
259
251
  OrdersMailer.configure_for_site(@site.id).customer_new_order(order).deliver
@@ -291,27 +283,6 @@ module Caboose
291
283
  render :layout => false
292
284
  end
293
285
 
294
- # GET /checkout/discount
295
- #def discount
296
- # # TODO make it possible to use multiple discounts
297
- #
298
- # @gift_card = @order.discounts.first
299
- #end
300
-
301
- # POST /checkout/update-discount
302
- #def add_discount
303
- # gift_card = Discount.find_by_code(params[:gift_card_number])
304
- #
305
- # render :json => { :error => true, :message => 'Gift card not found.' } and return if gift_card.nil?
306
- # render :json => { :error => true, :message => 'Gift card has no remaining funds.' } and return if gift_card.amount_current <= 0
307
- #
308
- # @order.discounts.delete_all if @order.discounts.any?
309
- # @order.discounts << gift_card
310
- # @order.calculate_total
311
- #
312
- # render :json => { :success => true, :message => 'Gift card added successfully.' }
313
- #end
314
-
315
286
  #def relay
316
287
  #
317
288
  # # Check to see that the order has a valid total and was authorized
@@ -0,0 +1,216 @@
1
+ module Caboose
2
+ class GiftCardsController < Caboose::ApplicationController
3
+
4
+ # GET /admin/gift-cards
5
+ def admin_index
6
+ return if !user_is_allowed('giftcards', 'view')
7
+ render :layout => 'caboose/admin'
8
+ end
9
+
10
+ # GET /admin/gift-cards/json
11
+ def admin_json
12
+ return if !user_is_allowed('giftcards', 'view')
13
+
14
+ pager = PageBarGenerator.new(params, {
15
+ 'site_id' => @site.id,
16
+ 'name' => '',
17
+ 'code' => '',
18
+ 'card_type' => '',
19
+ 'total_lte' => '',
20
+ 'total_gte' => '',
21
+ 'balance_lte' => '',
22
+ 'balance_gte' => '',
23
+ 'min_order_total_lte' => '',
24
+ 'min_order_total_gte' => '',
25
+ 'date_available_lte' => '',
26
+ 'date_available_gte' => '',
27
+ 'date_expires_lte' => '',
28
+ 'date_expires_gte' => '',
29
+ 'status' => ''
30
+ },{
31
+ 'model' => 'Caboose::GiftCard',
32
+ 'sort' => 'code',
33
+ 'desc' => false,
34
+ 'base_url' => "/admin/gift-cards",
35
+ 'use_url_params' => false
36
+ })
37
+ render :json => {
38
+ :pages => pager,
39
+ :models => pager.items
40
+ }
41
+ end
42
+
43
+ # GET /admin/gift-cards/:id/json
44
+ def admin_json_single
45
+ return if !user_is_allowed('giftcards', 'view')
46
+ gc = GiftCard.find(params[:id])
47
+ render :json => gc
48
+ end
49
+
50
+ # GET /admin/gift-cards/new
51
+ def admin_new
52
+ return if !user_is_allowed('giftcards', 'add')
53
+ render :layout => 'caboose/admin'
54
+ end
55
+
56
+ # POST /admin/gift-cards
57
+ def admin_add
58
+ return if !user_is_allowed('giftcards', 'add')
59
+
60
+ resp = StdClass.new
61
+ code = params[:code].strip
62
+
63
+ if code.length == 0
64
+ resp.error = "A valid code is required."
65
+ elsif GiftCard.where(:code => code).exists?
66
+ resp.error = "A gift card with that code already exists."
67
+ else
68
+ gc = GiftCard.new(
69
+ :site_id => @site.id,
70
+ :code => code,
71
+ :status => GiftCard::STATUS_INACTIVE
72
+ )
73
+ resp.success = gc.save
74
+ resp.new_id = gc.id
75
+ resp.redirect = "/admin/gift-cards/#{gc.id}"
76
+ end
77
+
78
+ render :json => resp
79
+ end
80
+
81
+ # POST /admin/gift-cards/bulk
82
+ def admin_bulk_add
83
+ return if !user_is_allowed('sites', 'add')
84
+
85
+ resp = Caboose::StdClass.new
86
+ i = 0
87
+ CSV.parse(params[:csv_data].strip).each do |row|
88
+ if row[0].nil? || row[0].strip.length == 0
89
+ resp.error = "Code not defined on row #{i+1}."
90
+ end
91
+ i = i + 1
92
+ end
93
+
94
+ if resp.error.nil?
95
+ CSV.parse(params[:csv_data]).each do |row|
96
+ Caboose::GiftCard.create(
97
+ :site_id => @site.id,
98
+ :code => row[0].strip,
99
+ :status => GiftCard::STATUS_INACTIVE
100
+ )
101
+ end
102
+ resp.success = true
103
+ end
104
+
105
+ render :json => resp
106
+ end
107
+
108
+ # GET /admin/gift-cards/:id
109
+ def admin_edit
110
+ return if !user_is_allowed('giftcards', 'edit')
111
+ @gift_card = GiftCard.find(params[:id])
112
+ render :layout => 'caboose/admin'
113
+ end
114
+
115
+ # PUT /admin/gift-cards/:id
116
+ def admin_update
117
+ return if !user_is_allowed('giftcards', 'edit')
118
+
119
+ resp = Caboose::StdClass.new
120
+ gc = GiftCard.find(params[:id])
121
+
122
+ save = true
123
+ params.each do |name,value|
124
+ case name
125
+ when 'site_id' then gc.site_id = value
126
+ when 'name' then gc.name = value
127
+ when 'code' then gc.code = value
128
+ when 'card_type' then gc.card_type = value
129
+ when 'total' then gc.total = value
130
+ when 'balance' then gc.balance = value
131
+ when 'min_order_total' then gc.min_order_total = value
132
+ when 'date_available' then gc.date_available = DateTime.strptime(value, '%m/%d/%Y')
133
+ when 'date_expires' then gc.date_expires = DateTime.strptime(value, '%m/%d/%Y')
134
+ when 'status' then gc.status = value
135
+ end
136
+ end
137
+ resp.success = save && gc.save
138
+ render :json => resp
139
+ end
140
+
141
+ # PUT /admin/gift-cards/bulk
142
+ def admin_bulk_update
143
+ return unless user_is_allowed_to 'edit', 'sites'
144
+
145
+ resp = Caboose::StdClass.new
146
+ gift_cards = params[:model_ids].collect{ |gc_id| GiftCard.find(gc_id) }
147
+
148
+ save = true
149
+ params.each do |k,v|
150
+ case k
151
+ when 'site_id' then gift_cards.each{ |gc| gc.site_id = v }
152
+ when 'name' then gift_cards.each{ |gc| gc.name = v }
153
+ when 'code' then gift_cards.each{ |gc| gc.code = v }
154
+ when 'card_type' then gift_cards.each{ |gc| gc.card_type = v }
155
+ when 'total' then gift_cards.each{ |gc| gc.total = v }
156
+ when 'balance' then gift_cards.each{ |gc| gc.balance = v }
157
+ when 'min_order_total' then gift_cards.each{ |gc| gc.min_order_total = v }
158
+ when 'date_available' then gift_cards.each{ |gc| gc.date_available = DateTime.strptime(v, '%m/%d/%Y') }
159
+ when 'date_expires' then gift_cards.each{ |gc| gc.date_expires = DateTime.strptime(v, '%m/%d/%Y') }
160
+ when 'status' then gift_cards.each{ |gc| gc.status = v }
161
+ end
162
+ end
163
+ gift_cards.each{ |gc| gc.save }
164
+
165
+ resp.success = true
166
+ render :json => resp
167
+ end
168
+
169
+ # DELETE /admin/gift-cards/:id
170
+ def admin_delete
171
+ return if !user_is_allowed('giftcards', 'delete')
172
+ GiftCard.find(params[:id]).destroy
173
+ render :json => Caboose::StdClass.new({
174
+ :redirect => '/admin/gift-cards'
175
+ })
176
+ end
177
+
178
+ # DELETE /admin/gift-cards/:id/bulk
179
+ def admin_bulk_delete
180
+ return if !user_is_allowed('sites', 'delete')
181
+
182
+ resp = Caboose::StdClass.new
183
+ params[:model_ids].each do |gc_id|
184
+ GiftCard.find(gc_id).destroy
185
+ end
186
+ resp.success = true
187
+ render :json => resp
188
+ end
189
+
190
+ # GET /admin/gift-cards/status-options
191
+ def admin_status_options
192
+ return if !user_is_allowed('categories', 'view')
193
+ statuses = [
194
+ GiftCard::STATUS_INACTIVE,
195
+ GiftCard::STATUS_ACTIVE,
196
+ GiftCard::STATUS_EXPIRED
197
+ ]
198
+ options = statuses.collect{ |s| { 'text' => s, 'value' => s }}
199
+ render :json => options
200
+ end
201
+
202
+ # GET /admin/gift-cards/card-type-options
203
+ def admin_card_type_options
204
+ return if !user_is_allowed('categories', 'view')
205
+ types = [
206
+ GiftCard::CARD_TYPE_AMOUNT,
207
+ GiftCard::CARD_TYPE_PERCENTAGE,
208
+ GiftCard::CARD_TYPE_NO_SHIPPING,
209
+ GiftCard::CARD_TYPE_NO_TAX,
210
+ ]
211
+ options = types.collect{ |s| { 'text' => s, 'value' => s }}
212
+ render :json => options
213
+ end
214
+
215
+ end
216
+ end