caboose-cms 0.5.122 → 0.5.123

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +8 -8
  2. data/app/assets/javascripts/caboose/admin.js +1 -0
  3. data/app/assets/javascripts/caboose/admin_edit_order.js +6 -8
  4. data/app/assets/javascripts/caboose/cart.js +2 -2
  5. data/app/assets/javascripts/caboose/jquery.datetimepicker.js +1925 -0
  6. data/app/assets/javascripts/caboose/model/all.js +1 -0
  7. data/app/assets/javascripts/caboose/model/bound_date.js +10 -3
  8. data/app/assets/javascripts/caboose/model/bound_date_time.js +121 -0
  9. data/app/assets/javascripts/caboose/model/model_binder.js +3 -0
  10. data/app/assets/stylesheets/caboose/admin.css +1 -0
  11. data/app/assets/stylesheets/caboose/jquery.datetimepicker.css +523 -0
  12. data/app/assets/templates/caboose/cart/line_items.jst.ejs +1 -1
  13. data/app/assets/templates/caboose/checkout/line_items.jst.ejs +2 -2
  14. data/app/controllers/caboose/checkout_controller.rb +3 -2
  15. data/app/controllers/caboose/line_items_controller.rb +4 -2
  16. data/app/controllers/caboose/my_account_controller.rb +43 -0
  17. data/app/controllers/caboose/my_account_orders_controller.rb +40 -6
  18. data/app/controllers/caboose/orders_controller.rb +26 -20
  19. data/app/controllers/caboose/products_controller.rb +1 -0
  20. data/app/controllers/caboose/sites_controller.rb +15 -1
  21. data/app/controllers/caboose/users_controller.rb +0 -35
  22. data/app/controllers/caboose/variants_controller.rb +51 -2
  23. data/app/controllers/caboose/vendors_controller.rb +3 -2
  24. data/app/models/caboose/address.rb +9 -1
  25. data/app/models/caboose/line_item.rb +17 -9
  26. data/app/models/caboose/model_binder.rb +63 -0
  27. data/app/models/caboose/order.rb +21 -14
  28. data/app/models/caboose/order_pdf.rb +3 -3
  29. data/app/models/caboose/pending_orders_pdf.rb +1 -1
  30. data/app/models/caboose/product.rb +15 -16
  31. data/app/models/caboose/schema.rb +20 -13
  32. data/app/models/caboose/site.rb +9 -0
  33. data/app/models/caboose/store_config.rb +6 -0
  34. data/app/models/caboose/variant.rb +15 -1
  35. data/app/views/caboose/checkout/_cart.html.erb +3 -3
  36. data/app/views/caboose/checkout/_confirm.html.erb +3 -3
  37. data/app/views/caboose/login/index.html.erb +7 -3
  38. data/app/views/caboose/{users/my_account.html.erb → my_account/index.html.erb} +7 -6
  39. data/app/views/caboose/my_account_orders/edit.html.erb +104 -0
  40. data/app/views/caboose/my_account_orders/index.html.erb +36 -0
  41. data/app/views/caboose/sites/admin_edit.html.erb +2 -0
  42. data/app/views/caboose/variants/admin_edit.html.erb +11 -1
  43. data/app/views/caboose/variants/admin_index.html.erb +5 -2
  44. data/config/routes.rb +7 -2
  45. data/lib/caboose/#Untitled-1# +264 -0
  46. data/lib/caboose/engine.rb +23 -140
  47. data/lib/caboose/version.rb +1 -1
  48. data/lib/tasks/caboose.rake +15 -1
  49. metadata +11 -4
  50. data/app/views/caboose/orders/admin_edit_old.html.erb +0 -155
@@ -26,7 +26,7 @@
26
26
  </section>
27
27
 
28
28
  <section>
29
- <p class="price">$<%= parseFloat(Math.round(lineItem.price * 100) / 100).toFixed(2) %></p>
29
+ <p class="price">$<%= parseFloat(Math.round(lineItem.subtotal * 100) / 100).toFixed(2) %></p>
30
30
  </section>
31
31
  </li>
32
32
  <% }); %>
@@ -6,10 +6,10 @@
6
6
  <div class="wrapper">
7
7
  <aside>
8
8
  <figure style="background-image: url(<%= lineItem.variant.images[0].urls.thumb %>)"></figure>
9
- <p><%= lineItem.title %><br />Qty: <%= lineItem.quantity %><br /><span class="price">$<%= ((parseFloat(lineItem.price) * 100) / 100).toFixed(2) %></span></p>
9
+ <p><%= lineItem.title %><br />Qty: <%= lineItem.quantity %><br /><span class="price">$<%= ((parseFloat(lineItem.unit_price) * 100) / 100).toFixed(2) %></span></p>
10
10
  </aside>
11
11
  <section>
12
- <p>$<%= ((parseFloat(lineItem.price) * 100) / 100).toFixed(2) %></p>
12
+ <p>$<%= ((parseFloat(lineItem.subtotal) * 100) / 100).toFixed(2) %></p>
13
13
  </section>
14
14
  </div>
15
15
  </li>
@@ -257,8 +257,9 @@ module Caboose
257
257
 
258
258
  error = nil
259
259
  if ot.success
260
- order.financial_status = 'authorized'
261
- order.status = 'pending'
260
+ order.financial_status = Order::FINANCIAL_STATUS_AUTHORIZED
261
+ order.status = Order::STATUS_PENDING
262
+ order.order_number = @site.store_config.next_order_number
262
263
 
263
264
  # Take funds from any gift cards that were used on the order
264
265
  order.take_gift_card_funds
@@ -24,7 +24,8 @@ module Caboose
24
24
  :order_id => params[:order_id],
25
25
  :variant_id => params[:variant_id],
26
26
  :quantity => 1,
27
- :price => v.price,
27
+ :unit_price => v.price,
28
+ :subtotal => v.price,
28
29
  :status => 'pending'
29
30
  )
30
31
  resp.success = li.save
@@ -46,7 +47,8 @@ module Caboose
46
47
  when 'order_package_id' then li.order_package_id = value
47
48
  when 'variant_id' then li.variant_id = value
48
49
  when 'parent_id' then li.parent_id = value
49
- when 'price' then li.price = value
50
+ when 'unit_price' then li.unit_price = value
51
+ when 'subtotal' then li.subtotal = value
50
52
  when 'notes' then li.notes = value
51
53
  when 'custom1' then li.custom1 = value
52
54
  when 'custom2' then li.custom2 = value
@@ -0,0 +1,43 @@
1
+ module Caboose
2
+ class MyAccountController < Caboose::ApplicationController
3
+
4
+ # GET /my-account
5
+ def index
6
+ return if !verify_logged_in
7
+ @user = logged_in_user
8
+ end
9
+
10
+ # PUT /my-account
11
+ def update
12
+ return if !logged_in?
13
+
14
+ resp = StdClass.new
15
+ user = logged_in_user
16
+
17
+ save = true
18
+ params.each do |name,value|
19
+ case name
20
+ when "first_name" then user.first_name = value
21
+ when "last_name" then user.last_name = value
22
+ when "username" then user.username = value
23
+ when "email" then user.email = value
24
+ when "phone" then user.phone = value
25
+ when "password"
26
+ confirm = params[:confirm]
27
+ if value != confirm
28
+ resp.error = "Passwords do not match.";
29
+ save = false
30
+ elsif value.length < 8
31
+ resp.error = "Passwords must be at least 8 characters.";
32
+ save = false
33
+ else
34
+ user.password = Digest::SHA1.hexdigest(Caboose::salt + value)
35
+ end
36
+ end
37
+ end
38
+
39
+ resp.success = save && user.save
40
+ render :json => resp
41
+ end
42
+ end
43
+ end
@@ -6,17 +6,16 @@ module Caboose
6
6
  return if !logged_in?
7
7
 
8
8
  @pager = Caboose::PageBarGenerator.new(params, {
9
- 'customer_id' => @logged_in_user_id.id,
10
- 'status' => '',
11
- 'id' => ''
9
+ 'customer_id' => logged_in_user.id,
10
+ 'status' => [Order::STATUS_PENDING, Order::STATUS_CANCELED, Order::STATUS_SHIPPED]
12
11
  }, {
13
12
  'model' => 'Caboose::Order',
14
- 'sort' => 'id',
13
+ 'sort' => 'order_number',
15
14
  'desc' => 1,
16
15
  'base_url' => '/my-account/orders',
17
16
  'use_url_params' => false
18
17
  })
19
- @orders = @pager.items
18
+ @orders = @pager.all_items
20
19
  end
21
20
 
22
21
  # GET /my-account/orders/:id
@@ -30,6 +29,41 @@ module Caboose
30
29
  return
31
30
  end
32
31
  end
33
-
32
+ # GET /my-account
33
+ def my_account
34
+ return if !logged_in?
35
+ @user = logged_in_user
36
+ render :layout => 'caboose/modal'
37
+ end
38
+
39
+ # PUT /my-account
40
+ def update_my_account
41
+ return if !logged_in?
42
+
43
+ resp = StdClass.new
44
+ user = logged_in_user
45
+
46
+ save = true
47
+ params.each do |name,value|
48
+ case name
49
+ when "first_name", "last_name", "username", "email", "phone"
50
+ user[name.to_sym] = value
51
+ when "password"
52
+ confirm = params[:confirm]
53
+ if (value != confirm)
54
+ resp.error = "Passwords do not match.";
55
+ save = false
56
+ elsif (value.length < 8)
57
+ resp.error = "Passwords must be at least 8 characters.";
58
+ save = false
59
+ else
60
+ user.password = Digest::SHA1.hexdigest(Caboose::salt + value)
61
+ end
62
+ end
63
+ end
64
+
65
+ resp.success = save && user.save
66
+ render json: resp
67
+ end
34
68
  end
35
69
  end
@@ -16,7 +16,7 @@ module Caboose
16
16
  @pager = Caboose::PageBarGenerator.new(params, {
17
17
  'site_id' => @site.id,
18
18
  'customer_id' => '',
19
- 'status' => 'pending',
19
+ 'status' => Order::STATUS_PENDING,
20
20
  'shipping_method_code' => '',
21
21
  'id' => ''
22
22
  }, {
@@ -43,8 +43,8 @@ module Caboose
43
43
  def admin_add
44
44
  return if !user_is_allowed('orders', 'add')
45
45
  order = Order.create(
46
- :status => 'pending',
47
- :financial_status => 'pending'
46
+ :status => Order::STATUS_PENDING,
47
+ :financial_status => Order::FINANCIAL_STATUS_PENDING
48
48
  )
49
49
  render :json => { :sucess => true, :redirect => "/admin/orders/#{order.id}" }
50
50
  end
@@ -64,7 +64,7 @@ module Caboose
64
64
  order = Order.find(params[:id])
65
65
  t = OrderTransaction.where(:order_id => order.id, :transaction_type => OrderTransaction::TYPE_AUTHORIZE, :success => true).first
66
66
 
67
- if order.financial_status == 'captured'
67
+ if order.financial_status == Order::FINANCIAL_STATUS_CAPTURED
68
68
  resp.error = "This order has already been captured, you will need to refund instead"
69
69
  elsif t.nil?
70
70
  resp.error = "This order doesn't seem to be authorized."
@@ -78,12 +78,12 @@ module Caboose
78
78
  sc.pp_username,
79
79
  sc.pp_password,
80
80
  order.total,
81
- :transaction_type => 'VOID',
81
+ :transaction_type => OrderTransaction::TYPE_VOID,
82
82
  :transaction_id => t.transaction_id
83
83
  )
84
84
  order.update_attributes(
85
- :financial_status => 'voided',
86
- :status => 'cancelled'
85
+ :financial_status => Order::FINANCIAL_STATUS_VOIDED,
86
+ :status => Order::STATUS_CANCELED
87
87
  )
88
88
  order.save
89
89
  # TODO: Add the variant quantities ordered back
@@ -109,13 +109,13 @@ module Caboose
109
109
 
110
110
  order = Order.find(params[:id])
111
111
 
112
- if order.financial_status != 'captured'
112
+ if order.financial_status != Order::FINANCIAL_STATUS_CAPTURED
113
113
  response.error = "This order hasn't been captured yet, you will need to void instead"
114
114
  else
115
115
  if PaymentProcessor.refund(order)
116
116
  order.update_attributes(
117
- :financial_status => 'refunded',
118
- :status => 'cancelled'
117
+ :financial_status => Order::FINANCIAL_STATUS_REFUNDED,
118
+ :status => Order::STATUS_CANCELED
119
119
  )
120
120
 
121
121
  response.success = 'Order refunded successfully'
@@ -214,7 +214,7 @@ module Caboose
214
214
  return if !user_is_allowed('orders', 'edit')
215
215
 
216
216
  pdf = PendingOrdersPdf.new
217
- pdf.orders = Order.where(:status => 'pending').all
217
+ pdf.orders = Order.where(:status => Order::STATUS_PENDING).all
218
218
  send_data pdf.to_pdf, :filename => "pending_orders.pdf", :type => "application/pdf", :disposition => "inline"
219
219
  end
220
220
 
@@ -258,7 +258,7 @@ module Caboose
258
258
  order = Order.find(params[:id])
259
259
  t = OrderTransaction.where(:order_id => order.id, :transaction_type => OrderTransaction::TYPE_AUTHORIZE, :success => true).first
260
260
 
261
- if order.financial_status == 'captured'
261
+ if order.financial_status == Order::FINANCIAL_STATUS_CAPTURED
262
262
  resp.error = "Funds for this order have already been captured."
263
263
  elsif order.total > order.auth_amount
264
264
  resp.error = "The order total exceeds the authorized amount."
@@ -277,7 +277,7 @@ module Caboose
277
277
  :transaction_type => 'CAPTURE_ONLY',
278
278
  :transaction_id => t.transaction_id
279
279
  )
280
- order.update_attribute(:financial_status, 'captured')
280
+ order.update_attribute(:financial_status, Order::FINANCIAL_STATUS_CAPTURED)
281
281
  resp.success = 'Captured funds successfully'
282
282
  when 'payscape'
283
283
  # TODO: Implement capture funds for payscape
@@ -372,9 +372,15 @@ module Caboose
372
372
 
373
373
  # GET /admin/orders/status-options
374
374
  def admin_status_options
375
- return if !user_is_allowed('categories', 'view')
376
- statuses = ['cart', 'pending', 'ready to ship', 'shipped', 'canceled']
377
- options = statuses.collect{ |s| { 'text' => s, 'value' => s }}
375
+ return if !user_is_allowed('orders', 'view')
376
+ statuses = [
377
+ Order::STATUS_CART,
378
+ Order::STATUS_PENDING,
379
+ Order::STATUS_READY_TO_SHIP,
380
+ Order::STATUS_SHIPPED,
381
+ Order::STATUS_CANCELED
382
+ ]
383
+ options = statuses.collect{ |s| { 'text' => s.capitalize, 'value' => s }}
378
384
  render :json => options
379
385
  end
380
386
 
@@ -397,16 +403,16 @@ module Caboose
397
403
  if Caboose::Setting.exists?(:name => 'google_feed_date_last_submitted')
398
404
  d1 = Caboose::Setting.where(:name => 'google_feed_date_last_submitted').first.value
399
405
  d1 = DateTime.parse(d1)
400
- elsif Order.exists?("status = 'shipped' and date_authorized is not null")
401
- d1 = Order.where("status = ? and date_authorized is not null", 'shipped').reorder("date_authorized DESC").limit(1).pluck('date_authorized')
406
+ elsif Order.exists?("status = ? and date_authorized is not null", Order::STATUS_SHIPPED)
407
+ d1 = Order.where("status = ? and date_authorized is not null", Order::STATUS_SHIPPED).reorder("date_authorized DESC").limit(1).pluck('date_authorized')
402
408
  d1 = DateTime.parse(d1)
403
409
  end
404
410
 
405
411
  # Google Feed Docs
406
412
  # https://support.google.com/trustedstoresmerchant/answer/3272612?hl=en&ref_topic=3272286?hl=en
407
413
  tsv = ["merchant order id\ttracking number\tcarrier code\tother carrier name\tship date"]
408
- if Order.exists?("status = 'shipped' and date_authorized > '#{d1.strftime("%F %T")}'")
409
- Order.where("status = ? and date_authorized > ?", 'shipped', d1).reorder(:id).all.each do |order|
414
+ if Order.exists?("status = ? and date_authorized > '#{d1.strftime("%F %T")}'", Order::STATUS_SHIPPED)
415
+ Order.where("status = ? and date_authorized > ?", Order::STATUS_SHIPPED, d1).reorder(:id).all.each do |order|
410
416
  tracking_numbers = order.line_items.collect{ |li| li.tracking_number }.compact.uniq
411
417
  tn = tracking_numbers && tracking_numbers.count >= 1 ? tracking_numbers[0] : ""
412
418
  tsv << "#{order.id}\t#{tn}\tUPS\t\t#{order.date_shipped.strftime("%F")}"
@@ -47,6 +47,7 @@ module Caboose
47
47
  # Otherwise looking at a category or search parameters
48
48
  @pager = Caboose::Pager.new(params, {
49
49
  'site_id' => @site.id,
50
+ 'on_sale' => '',
50
51
  'category_id' => '',
51
52
  'vendor_id' => '',
52
53
  'vendor_name' => '',
@@ -87,7 +87,21 @@ module Caboose
87
87
 
88
88
  resp.success = save && site.save
89
89
  render :json => resp
90
- end
90
+ end
91
+
92
+ # POST /admin/sites/:id/logo
93
+ def admin_update_logo
94
+ return if !user_is_allowed('sites', 'edit')
95
+
96
+ site = Site.find(params[:id])
97
+ site.logo = params[:logo]
98
+ site.save
99
+
100
+ resp = StdClass.new
101
+ resp.success = true
102
+ resp.attributes = { :image => { :value => site.logo.url(:thumb) }}
103
+ render :json => resp
104
+ end
91
105
 
92
106
  # DELETE /admin/sites/:id
93
107
  def admin_delete
@@ -12,42 +12,7 @@ module Caboose
12
12
  # Non-admin actions
13
13
  #===========================================================================
14
14
 
15
- # GET /my-account
16
- def my_account
17
- return if !logged_in?
18
- @user = logged_in_user
19
- render :layout => 'caboose/modal'
20
- end
21
-
22
- # PUT /my-account
23
- def update_my_account
24
- return if !logged_in?
25
-
26
- resp = StdClass.new
27
- user = logged_in_user
28
15
 
29
- save = true
30
- params.each do |name,value|
31
- case name
32
- when "first_name", "last_name", "username", "email", "phone"
33
- user[name.to_sym] = value
34
- when "password"
35
- confirm = params[:confirm]
36
- if (value != confirm)
37
- resp.error = "Passwords do not match.";
38
- save = false
39
- elsif (value.length < 8)
40
- resp.error = "Passwords must be at least 8 characters.";
41
- save = false
42
- else
43
- user.password = Digest::SHA1.hexdigest(Caboose::salt + value)
44
- end
45
- end
46
- end
47
-
48
- resp.success = save && user.save
49
- render json: resp
50
- end
51
16
 
52
17
  #===========================================================================
53
18
  # Admin actions
@@ -119,7 +119,7 @@ module Caboose
119
119
  when 'alternate_id' then v.alternate_id = value
120
120
  when 'sku' then v.sku = value
121
121
  when 'barcode' then v.barcode = value
122
- when 'price' then v.price = value
122
+ when 'price' then v.price = value
123
123
  when 'quantity_in_stock' then v.quantity_in_stock = value
124
124
  when 'ignore_quantity' then v.ignore_quantity = value
125
125
  when 'allow_backorder' then v.allow_backorder = value
@@ -135,6 +135,16 @@ module Caboose
135
135
  when 'taxable' then v.taxable = value
136
136
  when 'downloadable' then v.downloadable = value
137
137
  when 'download_path' then v.download_path = value
138
+
139
+ when 'sale_price'
140
+ v.sale_price = value
141
+ v.product.delay(:run_at => 3.seconds.from_now).update_on_sale
142
+ when 'date_sale_starts'
143
+ v.date_sale_starts = ModelBinder.local_datetime_to_utc(value, @logged_in_user.timezone)
144
+ v.product.delay(:run_at => v.date_sale_starts).update_on_sale
145
+ when 'date_sale_ends'
146
+ v.date_sale_ends = ModelBinder.local_datetime_to_utc(value, @logged_in_user.timezone)
147
+ v.product.delay(:run_at => v.date_sale_ends).update_on_sale
138
148
  end
139
149
  end
140
150
  resp.success = save && v.save
@@ -380,7 +390,7 @@ module Caboose
380
390
  return unless user_is_allowed_to 'edit', 'sites'
381
391
 
382
392
  resp = Caboose::StdClass.new
383
- variants = params[:model_ids].collect{ |variant_id| Variant.find(variant_id) }
393
+ variants = params[:model_ids].collect{ |variant_id| Variant.find(variant_id) }
384
394
 
385
395
  save = true
386
396
  params.each do |k,value|
@@ -404,6 +414,45 @@ module Caboose
404
414
  when 'taxable' then variants.each { |v| v.taxable = value }
405
415
  when 'downloadable' then variants.each { |v| v.downloadable = value }
406
416
  when 'download_path' then variants.each { |v| v.download_path = value }
417
+
418
+ when 'sale_price'
419
+ variants.each_with_index do |v, i|
420
+ v.sale_price = value
421
+ v.product.delay(:run_at => 3.seconds.from_now).update_on_sale if i == 0
422
+ end
423
+ when 'date_sale_starts'
424
+ variants.each_with_index do |v, i|
425
+ v.date_sale_starts = ModelBinder.update_date(v.date_sale_starts, value, @logged_in_user.timezone)
426
+ if i == 0
427
+ v.product.delay(:run_at => v.date_sale_starts).update_on_sale
428
+ v.product.delay(:run_at => 3.seconds.from_now).update_on_sale
429
+ end
430
+ end
431
+ when 'time_sale_starts'
432
+ variants.each_with_index do |v, i|
433
+ v.date_sale_starts = ModelBinder.update_time(v.date_sale_starts, value, @logged_in_user.timezone)
434
+ if i == 0
435
+ v.product.delay(:run_at => v.date_sale_starts).update_on_sale
436
+ v.product.delay(:run_at => 3.seconds.from_now).update_on_sale
437
+ end
438
+ end
439
+ when 'date_sale_ends'
440
+ variants.each_with_index do |v, i|
441
+ v.date_sale_ends = ModelBinder.update_date(v.date_sale_ends, value, @logged_in_user.timezone)
442
+ if i == 0
443
+ v.product.delay(:run_at => v.date_sale_ends).update_on_sale
444
+ v.product.delay(:run_at => 3.seconds.from_now).update_on_sale
445
+ end
446
+ end
447
+ when 'time_sale_ends'
448
+ variants.each_with_index do |v, i|
449
+ v.date_sale_ends = ModelBinder.update_time(v.date_sale_ends, value, @logged_in_user.timezone)
450
+ if i == 0
451
+ v.product.delay(:run_at => v.date_sale_ends).update_on_sale
452
+ v.product.delay(:run_at => 3.seconds.from_now).update_on_sale
453
+ end
454
+ end
455
+
407
456
  end
408
457
  end
409
458
  variants.each{ |v| v.save }
@@ -46,7 +46,7 @@ module Caboose
46
46
  render :json => { :success => vendor.save }
47
47
  end
48
48
 
49
- # POST /admin/vendors/:id/update/image
49
+ # POST /admin/vendors/:id/image
50
50
  def admin_update_image
51
51
  return if !user_is_allowed('vendors', 'edit')
52
52
 
@@ -55,8 +55,9 @@ module Caboose
55
55
  vendor.save
56
56
 
57
57
  resp = StdClass.new
58
+ resp.success = true
58
59
  resp.attributes = { :image => { :value => vendor.image.url(:thumb) }}
59
- resp.success = vendor.save
60
+ render :json => resp
60
61
  end
61
62
 
62
63
  # GET /admin/vendors/new