tb_checkout 1.0.3

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 (122) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +162 -0
  4. data/Rakefile +24 -0
  5. data/app/assets/images/tb_checkout/admin/shopping_carts.png +0 -0
  6. data/app/assets/images/tb_checkout/admin/transactions.png +0 -0
  7. data/app/assets/javascripts/tb_checkout/admin/carts.js +2 -0
  8. data/app/assets/javascripts/tb_checkout/admin/transactions.js +2 -0
  9. data/app/assets/javascripts/tb_checkout/application.js +13 -0
  10. data/app/assets/javascripts/tb_checkout/cart_items.js +2 -0
  11. data/app/assets/javascripts/tb_checkout/carts.js +2 -0
  12. data/app/assets/javascripts/tb_checkout/transactions.js +2 -0
  13. data/app/assets/stylesheets/tb_checkout/admin/carts.css +4 -0
  14. data/app/assets/stylesheets/tb_checkout/admin/transactions.css +4 -0
  15. data/app/assets/stylesheets/tb_checkout/application.css +15 -0
  16. data/app/assets/stylesheets/tb_checkout/cart_items.css +4 -0
  17. data/app/assets/stylesheets/tb_checkout/carts.css +4 -0
  18. data/app/assets/stylesheets/tb_checkout/transactions.css +4 -0
  19. data/app/controllers/concerns/tb_checkout/controller_helpers.rb +16 -0
  20. data/app/controllers/tb_checkout/admin/carts_controller.rb +39 -0
  21. data/app/controllers/tb_checkout/admin/transactions_controller.rb +26 -0
  22. data/app/controllers/tb_checkout/application_controller.rb +6 -0
  23. data/app/controllers/tb_checkout/cart_items_controller.rb +63 -0
  24. data/app/controllers/tb_checkout/carts_controller.rb +8 -0
  25. data/app/controllers/tb_checkout/transactions_controller.rb +87 -0
  26. data/app/helpers/tb_checkout/admin/carts_helper.rb +13 -0
  27. data/app/helpers/tb_checkout/admin/transactions_helper.rb +16 -0
  28. data/app/helpers/tb_checkout/application_helper.rb +138 -0
  29. data/app/helpers/tb_checkout/transactions_helper.rb +2 -0
  30. data/app/models/concerns/tb_checkout/belongs_to_user_session.rb +15 -0
  31. data/app/models/concerns/tb_checkout/purchasable.rb +81 -0
  32. data/app/models/tb_checkout/basic_product.rb +6 -0
  33. data/app/models/tb_checkout/cart.rb +56 -0
  34. data/app/models/tb_checkout/cart_item.rb +48 -0
  35. data/app/models/tb_checkout/transaction.rb +253 -0
  36. data/app/views/tb_checkout/admin/carts/index.html.erb +54 -0
  37. data/app/views/tb_checkout/admin/carts/show.html.erb +45 -0
  38. data/app/views/tb_checkout/admin/transactions/_table.html.erb +24 -0
  39. data/app/views/tb_checkout/admin/transactions/index.html.erb +7 -0
  40. data/app/views/tb_checkout/admin/transactions/show.html.erb +70 -0
  41. data/app/views/tb_checkout/cart_items/create.html.erb +2 -0
  42. data/app/views/tb_checkout/cart_items/destroy.html.erb +2 -0
  43. data/app/views/tb_checkout/cart_items/update.html.erb +2 -0
  44. data/app/views/tb_checkout/carts/_cart.html.erb +65 -0
  45. data/app/views/tb_checkout/carts/show.html.erb +10 -0
  46. data/app/views/tb_checkout/transactions/_details.html.erb +17 -0
  47. data/app/views/tb_checkout/transactions/confirm.html.erb +11 -0
  48. data/app/views/tb_checkout/transactions/index.html.erb +29 -0
  49. data/app/views/tb_checkout/transactions/new.html.erb +90 -0
  50. data/app/views/tb_checkout/transactions/show.html.erb +14 -0
  51. data/config/locales/en.yml +23 -0
  52. data/config/routes.rb +20 -0
  53. data/db/migrate/20140703185256_create_tb_checkout_carts.rb +12 -0
  54. data/db/migrate/20140703185258_create_tb_checkout_cart_items.rb +15 -0
  55. data/db/migrate/20140703185259_create_tb_checkout_transactions.rb +23 -0
  56. data/db/migrate/20140707142350_create_tb_checkout_basic_products.rb +8 -0
  57. data/db/migrate/20140915202848_add_spud_user_and_session_id_to_transactions.rb +10 -0
  58. data/lib/tasks/tb_checkout_tasks.rake +19 -0
  59. data/lib/tb_checkout.rb +4 -0
  60. data/lib/tb_checkout/configuration.rb +8 -0
  61. data/lib/tb_checkout/engine.rb +36 -0
  62. data/lib/tb_checkout/schema.rb +51 -0
  63. data/lib/tb_checkout/version.rb +3 -0
  64. data/spec/controllers/tb_checkout/carts_controller_spec.rb +11 -0
  65. data/spec/controllers/tb_checkout/transactions_controller_spec.rb +110 -0
  66. data/spec/dummy/README.rdoc +28 -0
  67. data/spec/dummy/Rakefile +6 -0
  68. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  69. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  70. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  71. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  72. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  73. data/spec/dummy/bin/bundle +3 -0
  74. data/spec/dummy/bin/rails +4 -0
  75. data/spec/dummy/bin/rake +4 -0
  76. data/spec/dummy/config.ru +4 -0
  77. data/spec/dummy/config/application.rb +30 -0
  78. data/spec/dummy/config/boot.rb +5 -0
  79. data/spec/dummy/config/database.yml +13 -0
  80. data/spec/dummy/config/environment.rb +5 -0
  81. data/spec/dummy/config/environments/development.rb +37 -0
  82. data/spec/dummy/config/environments/production.rb +82 -0
  83. data/spec/dummy/config/environments/test.rb +39 -0
  84. data/spec/dummy/config/initializers/assets.rb +8 -0
  85. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  86. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  87. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  88. data/spec/dummy/config/initializers/inflections.rb +16 -0
  89. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  90. data/spec/dummy/config/initializers/session_store.rb +3 -0
  91. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  92. data/spec/dummy/config/locales/en.yml +23 -0
  93. data/spec/dummy/config/routes.rb +4 -0
  94. data/spec/dummy/config/secrets.yml +22 -0
  95. data/spec/dummy/db/migrate/20140915202259_create_spud_admin_permissions.tb_core.rb +12 -0
  96. data/spec/dummy/db/migrate/20140915202260_create_spud_users.tb_core.rb +30 -0
  97. data/spec/dummy/db/migrate/20140915202261_add_time_zone_to_spud_user.tb_core.rb +7 -0
  98. data/spec/dummy/db/migrate/20140915202262_add_scope_to_spud_admin_permissions.tb_core.rb +7 -0
  99. data/spec/dummy/db/migrate/20140915202263_create_spud_user_settings.tb_core.rb +12 -0
  100. data/spec/dummy/db/migrate/20140915202264_create_spud_roles.tb_core.rb +11 -0
  101. data/spec/dummy/db/migrate/20140915202265_create_spud_permissions.tb_core.rb +11 -0
  102. data/spec/dummy/db/migrate/20140915202266_create_spud_role_permissions.tb_core.rb +12 -0
  103. data/spec/dummy/db/migrate/20140915202267_drop_spud_admin_permissions.tb_core.rb +16 -0
  104. data/spec/dummy/db/migrate/20140915202268_create_tb_checkout_carts.tb_checkout_engine.rb +13 -0
  105. data/spec/dummy/db/migrate/20140915202269_create_tb_checkout_cart_items.tb_checkout_engine.rb +16 -0
  106. data/spec/dummy/db/migrate/20140915202270_create_tb_checkout_transactions.tb_checkout_engine.rb +24 -0
  107. data/spec/dummy/db/migrate/20140915202271_create_tb_checkout_basic_products.tb_checkout_engine.rb +9 -0
  108. data/spec/dummy/db/migrate/20140915234534_add_spud_user_and_session_id_to_transactions.tb_checkout_engine.rb +11 -0
  109. data/spec/dummy/db/schema.rb +135 -0
  110. data/spec/dummy/public/404.html +67 -0
  111. data/spec/dummy/public/422.html +67 -0
  112. data/spec/dummy/public/500.html +66 -0
  113. data/spec/dummy/public/favicon.ico +0 -0
  114. data/spec/factories/spud_users.rb +16 -0
  115. data/spec/factories/tb_checkout_basic_products.rb +8 -0
  116. data/spec/factories/tb_checkout_cart_items.rb +11 -0
  117. data/spec/factories/tb_checkout_carts.rb +14 -0
  118. data/spec/factories/tb_checkout_transactions.rb +37 -0
  119. data/spec/models/tb_checkout/transaction_spec.rb +5 -0
  120. data/spec/rails_helper.rb +73 -0
  121. data/spec/spec_helper.rb +85 -0
  122. metadata +335 -0
@@ -0,0 +1,8 @@
1
+ class TbCheckout::CartsController < TbCheckout::ApplicationController
2
+
3
+ def show
4
+ @cart = tb_checkout_current_cart
5
+ respond_with @cart
6
+ end
7
+
8
+ end
@@ -0,0 +1,87 @@
1
+ class TbCheckout::TransactionsController < TbCheckout::ApplicationController
2
+
3
+ before_action :load_cart, :only => [:new, :create, :confirm, :capture]
4
+
5
+ def index
6
+ @transactions = TbCheckout::Transaction.captured.for_user_or_session(current_user_id, session.id).includes(:cart => :cart_items).paginate(:page => params[:page], :per_page => 10)
7
+ respond_with @transactions
8
+ end
9
+
10
+ def new
11
+ @transaction = @cart.transactions.new()
12
+ if !Rails.env.production?
13
+ # These values will work against the Authorize.Net sandbox environment
14
+ @transaction.card_type = 'visa'
15
+ @transaction.card_number = 4007000000027
16
+ @transaction.card_ccv = 123
17
+ @transaction.card_expiration = Date.today.next_year
18
+ end
19
+ end
20
+
21
+ def create
22
+ @transaction = @cart.transactions.new(transaction_params)
23
+ if @transaction.save() && @transaction.authorize!
24
+ redirect_to confirm_tb_checkout_transaction_path(@transaction)
25
+ else
26
+ if @transaction.response
27
+ flash.now[:error] = @transaction.response.message
28
+ end
29
+ if @transaction.status == TbCheckout::Transaction::Status::FAIL
30
+ @transaction = TbCheckout::Transaction.new(transaction_params)
31
+ end
32
+ render 'new'
33
+ end
34
+ end
35
+
36
+ def confirm
37
+ @transaction = @cart.transactions.authorized.where(:id => params[:id]).first
38
+ if @transaction.blank?
39
+ redirect_to new_tb_checkout_transaction_path
40
+ else
41
+ render 'confirm'
42
+ end
43
+ end
44
+
45
+ def capture
46
+ @transaction = @cart.transactions.authorized.where(:id => params[:id]).first
47
+ if @transaction.blank?
48
+ redirect_to new_tb_checkout_transaction_path
49
+ return false
50
+ else
51
+ if @transaction.capture!
52
+ flash[:notice] = 'Thanks! Your payment was collected successfully'
53
+ redirect_to tb_checkout_transaction_path(@transaction)
54
+ else
55
+ flash.now[:error] = @transaction.response.message if @transaction.response
56
+ render 'confirm'
57
+ end
58
+ end
59
+ end
60
+
61
+ def show
62
+ @transaction = TbCheckout::Transaction.captured.find_by(:id => params[:id])
63
+ if @transaction.present? && @transaction.belongs_to?(user_id:current_user_id, session_id:session.id)
64
+ render 'show'
65
+ else
66
+ flash[:error] = 'The transaction you were looking for could not be found'
67
+ redirect_to tb_checkout_cart_path
68
+ end
69
+ end
70
+
71
+ private
72
+
73
+ def transaction_params
74
+ params.require(:tb_checkout_transaction).permit(:card_type, :card_number, :card_ccv, :card_expiration,
75
+ :billing_first_name, :billing_last_name, :billing_address_1, :billing_address_2, :billing_city, :billing_state, :billing_postal)
76
+ end
77
+
78
+ def load_cart
79
+ @cart = tb_checkout_current_cart
80
+ if @cart.blank? || @cart.is_empty?
81
+ flash[:error] = 'You cannot check out with an empty cart'
82
+ redirect_to tb_checkout_cart_path
83
+ return false
84
+ end
85
+ end
86
+
87
+ end
@@ -0,0 +1,13 @@
1
+ module TbCheckout::Admin::CartsHelper
2
+
3
+ def tb_checkout_status_label_for_cart(cart)
4
+ if cart.is_completed?
5
+ content_tag :span, 'Complete', :class => 'label label-success'
6
+ elsif cart.is_abandoned?
7
+ content_tag :span, 'Abandoned', :class => 'label label-inverse'
8
+ else
9
+ content_tag :span, 'In Progress', :class => 'label label-warning'
10
+ end
11
+ end
12
+
13
+ end
@@ -0,0 +1,16 @@
1
+ module TbCheckout::Admin::TransactionsHelper
2
+
3
+ def tb_checkout_status_label_for_transaction(status)
4
+ if status == 'captured'
5
+ cls = 'success'
6
+ elsif status == 'fail'
7
+ cls = 'important'
8
+ elsif status == 'refunded' || status == 'voided'
9
+ cls = 'warning'
10
+ else
11
+ cls = 'default'
12
+ end
13
+ content_tag :span, status.titleize, :class => "label label-#{cls}"
14
+ end
15
+
16
+ end
@@ -0,0 +1,138 @@
1
+ module TbCheckout
2
+ module ApplicationHelper
3
+
4
+ # Return a link to the user's shopping cart, with the number of items in the text
5
+ #
6
+ # * link_text: The text of the link. Defaults: "My Cart"
7
+ #
8
+ def tb_checkout_cart_link(link_text:'My Cart')
9
+ if tb_checkout_current_cart.present?
10
+ count = tb_checkout_current_cart.cart_items.count
11
+ else
12
+ count = 0
13
+ end
14
+ link_to "#{link_text} (#{count})", tb_checkout_cart_path, :class => 'tb-checkout-cart-link'
15
+ end
16
+
17
+ # Return a form used to add a product to the user's shopping cart
18
+ #
19
+ # * product: The product you wish to add. Should be an ActiveRecord model that conforms to TbCheckout::Purchasable
20
+ # * quantity: Whether to display a quantity picker. Defaults to false
21
+ # * submit_text: Text of the submit button. Default: "Add to Cart"
22
+ # * submit_class: CSS class of the submit button. Default: "btn btn-primary"
23
+ #
24
+ def tb_checkout_add_to_cart(product, quantity: false, submit_text:'Add to Cart', submit_class:'btn btn-primary')
25
+ cart_item = TbCheckout::CartItem.new({
26
+ :item => product,
27
+ :quantity => 1
28
+ })
29
+ return form_for cart_item, :html => {:class => 'tb-checkout-add-to-cart-form'} do |f|
30
+ concat f.hidden_field :item_type
31
+ concat f.hidden_field :item_id
32
+ if quantity
33
+ concat f.number_field :quantity, {:class => 'tb-checkout-add-to-cart-quantity'}
34
+ else
35
+ concat f.hidden_field :quantity
36
+ end
37
+ concat f.submit submit_text, :class => "#{submit_class} tb-checkout-add-to-cart-submit"
38
+ end
39
+ end
40
+
41
+ # Return a list of states for use in a form select field
42
+ #
43
+ def tb_checkout_options_for_states()
44
+ us_states = [
45
+ ['Alabama', 'AL'],
46
+ ['Alaska', 'AK'],
47
+ ['Arizona', 'AZ'],
48
+ ['Arkansas', 'AR'],
49
+ ['California', 'CA'],
50
+ ['Colorado', 'CO'],
51
+ ['Connecticut', 'CT'],
52
+ ['Delaware', 'DE'],
53
+ ['District of Columbia', 'DC'],
54
+ ['Florida', 'FL'],
55
+ ['Georgia', 'GA'],
56
+ ['Hawaii', 'HI'],
57
+ ['Idaho', 'ID'],
58
+ ['Illinois', 'IL'],
59
+ ['Indiana', 'IN'],
60
+ ['Iowa', 'IA'],
61
+ ['Kansas', 'KS'],
62
+ ['Kentucky', 'KY'],
63
+ ['Louisiana', 'LA'],
64
+ ['Maine', 'ME'],
65
+ ['Maryland', 'MD'],
66
+ ['Massachusetts', 'MA'],
67
+ ['Michigan', 'MI'],
68
+ ['Minnesota', 'MN'],
69
+ ['Mississippi', 'MS'],
70
+ ['Missouri', 'MO'],
71
+ ['Montana', 'MT'],
72
+ ['Nebraska', 'NE'],
73
+ ['Nevada', 'NV'],
74
+ ['New Hampshire', 'NH'],
75
+ ['New Jersey', 'NJ'],
76
+ ['New Mexico', 'NM'],
77
+ ['New York', 'NY'],
78
+ ['North Carolina', 'NC'],
79
+ ['North Dakota', 'ND'],
80
+ ['Ohio', 'OH'],
81
+ ['Oklahoma', 'OK'],
82
+ ['Oregon', 'OR'],
83
+ ['Pennsylvania', 'PA'],
84
+ ['Puerto Rico', 'PR'],
85
+ ['Rhode Island', 'RI'],
86
+ ['South Carolina', 'SC'],
87
+ ['South Dakota', 'SD'],
88
+ ['Tennessee', 'TN'],
89
+ ['Texas', 'TX'],
90
+ ['Utah', 'UT'],
91
+ ['Vermont', 'VT'],
92
+ ['Virginia', 'VA'],
93
+ ['Washington', 'WA'],
94
+ ['West Virginia', 'WV'],
95
+ ['Wisconsin', 'WI'],
96
+ ['Wyoming', 'WY']
97
+ ]
98
+ if TbCheckout.config.canada_is_real
99
+ return {
100
+ 'United States' => us_states,
101
+ 'Canada' => [
102
+ ['Alberta', 'AB'],
103
+ ['British Columbia ', 'BC'],
104
+ ['Manitoba', 'MB'],
105
+ ['New Brunswick', 'NB'],
106
+ ['Newfoundland and Labrador', 'NL'],
107
+ ['Nova Scotia', 'NS'],
108
+ ['Northwest Territories', 'NT'],
109
+ ['Nunavut', 'NU'],
110
+ ['Ontario', 'ON'],
111
+ ['Prince Edward Island', 'PE'],
112
+ ['Quebec', 'QC'],
113
+ ['Saskatchewan', 'SK'],
114
+ ['Yukon', 'YT']
115
+ ]
116
+ }
117
+ else
118
+ return us_states
119
+ end
120
+ end
121
+
122
+ # Return a list of credit card types for use with a form select
123
+ #
124
+ def tb_checkout_credit_card_types()
125
+ types = [
126
+ ['Visa', 'visa'],
127
+ ['MasterCard', 'master'],
128
+ ['Discover', 'discover'],
129
+ ['American Express', 'american_express']
130
+ ]
131
+ types.select!{ |a, b|
132
+ TbCheckout.config.card_types.include?(b.to_sym)
133
+ }
134
+ return types
135
+ end
136
+
137
+ end
138
+ end
@@ -0,0 +1,2 @@
1
+ module TbCheckout::TransactionsHelper
2
+ end
@@ -0,0 +1,15 @@
1
+ module TbCheckout::BelongsToUserSession
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ belongs_to :spud_user
6
+ scope :for_user_or_session, ->(user_id, session_id){
7
+ where('(session_id = ?) OR (spud_user_id IS NOT NULL AND spud_user_id != 0 AND spud_user_id = ?)', session_id, user_id)
8
+ }
9
+ end
10
+
11
+ def belongs_to?(user_id:nil, session_id:nil)
12
+ return (self.session_id == session_id) || (self.spud_user_id.present? && self.spud_user_id == user_id)
13
+ end
14
+
15
+ end
@@ -0,0 +1,81 @@
1
+ module TbCheckout::Purchasable
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ has_many :cart_items, :class_name => 'TbCheckout::CartItem', :as => :item
6
+ tb_checkout_quantity_is_editable(true)
7
+ tb_checkout_delete_on_removal(false)
8
+
9
+ include ActiveSupport::Callbacks
10
+ define_callbacks :capture
11
+ set_callback :capture, :after, :tb_checkout_after_capture!
12
+ end
13
+
14
+ module ClassMethods
15
+ attr_reader :quantity_is_editable, :after_capture, :delete_on_removal, :url_builder, :cart_detail_view
16
+
17
+ # Configure whether or not the given class of product should support multiple quantities
18
+ # * Default: true
19
+ #
20
+ def tb_checkout_quantity_is_editable(is_editable)
21
+ @quantity_is_editable = is_editable
22
+ end
23
+
24
+ # Configure a hook to run after the corresponding transaction is successfully captured
25
+ # Use this to perform any cleanup tasks on the product model
26
+ #
27
+ # Ex:
28
+ # tb_checkout_after_capture ->(instance){
29
+ # instance.update_column(:is_captured, true)
30
+ # }
31
+ #
32
+ def tb_checkout_after_capture(symbol_or_lambda)
33
+ @after_capture = symbol_or_lambda
34
+ end
35
+
36
+ # Configure whether or not the given class of product should self destruct when it is removed from the shopping cart
37
+ # For example, this may make sense for a purchasable record that is only used one time
38
+ # * Default: false
39
+ #
40
+ def tb_checkout_delete_on_removal(should_delete)
41
+ @delete_on_removal = should_delete
42
+ end
43
+
44
+ # Configure a callback that builds a URL for the given product page
45
+ #
46
+ # Ex:
47
+ # tb_checkout_url_builder ->(instance, context){
48
+ # context.widget_path(instance.id)
49
+ # }
50
+ def tb_checkout_url_builder(symbol_or_lambda)
51
+ @url_builder = symbol_or_lambda
52
+ end
53
+
54
+ # Configure a partial to be displayed in the shopping cart
55
+ #
56
+ def tb_checkout_cart_detail_view(detail_view)
57
+ @cart_detail_view = detail_view
58
+ end
59
+ end
60
+
61
+ def tb_checkout_build_url(view)
62
+ url_builder = self.class.url_builder
63
+ if url_builder.is_a? Proc
64
+ return url_builder.call(self, view)
65
+ elsif url_builder.is_a? Symbol
66
+ return send(url_builder, view)
67
+ end
68
+ end
69
+
70
+ private
71
+
72
+ def tb_checkout_after_capture!
73
+ after_capture = self.class.after_capture
74
+ if after_capture.is_a? Proc
75
+ after_capture.call(self)
76
+ elsif after_capture.is_a? Symbol
77
+ send(after_capture)
78
+ end
79
+ end
80
+
81
+ end
@@ -0,0 +1,6 @@
1
+ module TbCheckout
2
+ class BasicProduct < ActiveRecord::Base
3
+ self.table_name = 'tb_checkout_basic_products'
4
+ include TbCheckout::Purchasable
5
+ end
6
+ end
@@ -0,0 +1,56 @@
1
+ module TbCheckout
2
+ class Cart < ActiveRecord::Base
3
+ self.table_name = 'tb_checkout_carts'
4
+ has_many :cart_items, :inverse_of => :cart
5
+ has_many :transactions, :inverse_of => :cart
6
+
7
+ scope :completed, ->{ where(:is_completed => true) }
8
+ scope :in_progress, ->{ where(:is_completed => false, :is_abandoned => false) }
9
+ scope :abandoned, ->{ where(:is_abandoned => true) }
10
+
11
+ include TbCheckout::BelongsToUserSession
12
+
13
+ # Look for carts that have outlived the configured TbCheckout.config.cart_lifespan value and mark them as abandoned
14
+ #
15
+ def self.check_abandoned!
16
+ carts = in_progress.where('updated_at < ?', DateTime.now - TbCheckout.config.cart_lifespan)
17
+ return carts.update_all(:is_abandoned => true)
18
+ end
19
+
20
+ # Build a short description of the cart contents
21
+ #
22
+ def description
23
+ if cart_items.length == 0
24
+ desc = "This cart is currently empty"
25
+ elsif cart_items.length > 1
26
+ desc = "#{cart_items.first.item_description} and #{cart_items.length-1} other #{'item'.pluralize(cart_items.length-1)}"
27
+ else
28
+ desc = cart_items.first.item_description
29
+ end
30
+ return desc
31
+ end
32
+
33
+ def total_price
34
+ return self.cart_items.collect(&:total_price).sum()
35
+ end
36
+
37
+ def add_to_cart(product, quantity: 1)
38
+ if !product.class.included_modules.map(&:to_s).include?("TbCheckout::Purchasable")
39
+ raise ArgumentError, 'product must conform to TbCheckout::Purchasable'
40
+ end
41
+ return self.cart_items.create({
42
+ :item => product,
43
+ :quantity => quantity
44
+ })
45
+ end
46
+
47
+ def is_empty?
48
+ return self.cart_items.count == 0
49
+ end
50
+
51
+ def user_full_name
52
+ return self.spud_user.try(:full_name) || 'Anonymous'
53
+ end
54
+
55
+ end
56
+ end
@@ -0,0 +1,48 @@
1
+ module TbCheckout
2
+ class CartItem < ActiveRecord::Base
3
+ self.table_name = 'tb_checkout_cart_items'
4
+ belongs_to :cart, :inverse_of => :cart_items, :touch => true
5
+ belongs_to :item, :polymorphic => true
6
+
7
+ validates :cart, :item, :presence => true
8
+ validates :quantity, :numericality => {:greater_than => 0}
9
+ before_save :set_item_values
10
+ after_destroy :cleanup_purchasable_item
11
+
12
+ def total_price
13
+ return item_price * quantity
14
+ end
15
+
16
+ def has_item_url?
17
+ return self.item && self.item.class.url_builder.present?
18
+ end
19
+
20
+ def item_url(view)
21
+ return item.tb_checkout_build_url(view)
22
+ end
23
+
24
+ def has_detail_view?
25
+ return self.item && self.item.class.cart_detail_view.present?
26
+ end
27
+
28
+ def detail_view
29
+ return self.item.class.cart_detail_view
30
+ end
31
+
32
+ private
33
+
34
+ def set_item_values
35
+ if self.item
36
+ self.item_description = self.item.description
37
+ self.item_price = self.item.price
38
+ end
39
+ end
40
+
41
+ def cleanup_purchasable_item
42
+ if self.item && self.item.class.delete_on_removal
43
+ self.item.destroy()
44
+ end
45
+ end
46
+
47
+ end
48
+ end