solidus_auction 0.0.1

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/LICENSE +26 -0
  3. data/README.md +57 -0
  4. data/Rakefile +30 -0
  5. data/app/assets/javascripts/auctions.js +2 -0
  6. data/app/assets/javascripts/countdown.js +20 -0
  7. data/app/assets/javascripts/local-time.js +1 -0
  8. data/app/assets/javascripts/spree/backend/product_autocomplete.js +50 -0
  9. data/app/assets/javascripts/spree/backend/solidus_auction.js +7 -0
  10. data/app/assets/javascripts/spree/ends_in.js +31 -0
  11. data/app/assets/javascripts/spree/frontend/solidus_auction.js +8 -0
  12. data/app/assets/javascripts/spree/frontend/starts_in.js +32 -0
  13. data/app/assets/javascripts/spree/frontend/votes.js +83 -0
  14. data/app/assets/stylesheets/spree/backend/solidus_auction.css +16 -0
  15. data/app/assets/stylesheets/spree/frontend/solidus_auction.css +24 -0
  16. data/app/controllers/spree/admin/auction_settings_controller.rb +16 -0
  17. data/app/controllers/spree/admin/auctions_controller.rb +46 -0
  18. data/app/controllers/spree/admin/bids_controller.rb +2 -0
  19. data/app/controllers/spree/admin/resource_controller_decorator.rb +9 -0
  20. data/app/controllers/spree/auctions_controller.rb +52 -0
  21. data/app/controllers/spree/bids_controller.rb +48 -0
  22. data/app/controllers/spree/helpers/local_time_helper.rb +77 -0
  23. data/app/controllers/spree/users_controller_decorator.rb +5 -0
  24. data/app/controllers/spree/votes_controller.rb +5 -0
  25. data/app/helpers/spree/strong_params_decorator.rb +8 -0
  26. data/app/models/spree/auction.rb +291 -0
  27. data/app/models/spree/auction_ability.rb +13 -0
  28. data/app/models/spree/bid.rb +19 -0
  29. data/app/models/spree/product_decorator.rb +3 -0
  30. data/app/models/spree/user_decorator.rb +5 -0
  31. data/app/models/spree/variant_decorator.rb +3 -0
  32. data/app/overrides/add_auction_links_to_order_info.rb +6 -0
  33. data/app/overrides/add_auction_settings_tab.rb +8 -0
  34. data/app/overrides/add_auctions_tab_to_admin.rb +8 -0
  35. data/app/overrides/add_auctions_table_to_user_show.rb +6 -0
  36. data/app/overrides/add_auctions_to_main_nav.rb +6 -0
  37. data/app/overrides/add_timezone_to_admin.rb +8 -0
  38. data/app/overrides/change_line_item_delete_button.rb +6 -0
  39. data/app/overrides/change_line_item_link_to.rb +6 -0
  40. data/app/overrides/change_line_item_number_field_disabled.rb +6 -0
  41. data/app/overrides/change_order_item_description.rb +6 -0
  42. data/app/overrides/change_stock_item_name.rb +6 -0
  43. data/app/overrides/change_variant_row_show.rb +6 -0
  44. data/app/overrides/change_variant_stock_item_show.rb +6 -0
  45. data/app/validators/in_future_validator.rb +10 -0
  46. data/app/views/spree/admin/active_shipping_settings/edit.html.erb +108 -0
  47. data/app/views/spree/admin/auction_settings/edit.html.erb +45 -0
  48. data/app/views/spree/admin/auctions/_form.html.erb +189 -0
  49. data/app/views/spree/admin/auctions/edit.html.erb +18 -0
  50. data/app/views/spree/admin/auctions/index.html.erb +89 -0
  51. data/app/views/spree/admin/auctions/new.html.erb +14 -0
  52. data/app/views/spree/admin/shared/_auction_links_to_order_info.html.erb +18 -0
  53. data/app/views/spree/admin/shared/_auction_settings_button.html.erb +3 -0
  54. data/app/views/spree/admin/shared/_auctions_tab.html.erb +3 -0
  55. data/app/views/spree/admin/shared/_time_zone_field.html.erb +5 -0
  56. data/app/views/spree/auctions/_bid_form.html.erb +81 -0
  57. data/app/views/spree/auctions/_bids.html.erb +52 -0
  58. data/app/views/spree/auctions/_image.html.erb +5 -0
  59. data/app/views/spree/auctions/_promotions.html.erb +19 -0
  60. data/app/views/spree/auctions/_properties.html.erb +15 -0
  61. data/app/views/spree/auctions/_taxons.html.erb +14 -0
  62. data/app/views/spree/auctions/_thumbnails.html.erb +19 -0
  63. data/app/views/spree/auctions/index.html.erb +3 -0
  64. data/app/views/spree/auctions/show.html.erb +58 -0
  65. data/app/views/spree/bids/index.html.erb +0 -0
  66. data/app/views/spree/bids/new.html.erb +0 -0
  67. data/app/views/spree/products/_cart_form.html.erb +65 -0
  68. data/app/views/spree/products/_promotions.html.erb +19 -0
  69. data/app/views/spree/products/_properties.html.erb +15 -0
  70. data/app/views/spree/products/_taxons.html.erb +14 -0
  71. data/app/views/spree/products/_thumbnails.html.erb +19 -0
  72. data/app/views/spree/products/index.html.erb +15 -0
  73. data/app/views/spree/products/show.html.erb +51 -0
  74. data/app/views/spree/shared/_auction_order_link.html.erb +9 -0
  75. data/app/views/spree/shared/_auctions.html.erb +39 -0
  76. data/app/views/spree/shared/_auctions_link.html.erb +7 -0
  77. data/app/views/spree/shared/_auctions_table_show.html.erb +93 -0
  78. data/app/views/spree/shared/_ends_in.html.erb +14 -0
  79. data/app/views/spree/shared/_image.html.erb +12 -0
  80. data/app/views/spree/shared/_line_item_delete.html.erb +5 -0
  81. data/app/views/spree/shared/_line_item_link_to.erb +22 -0
  82. data/app/views/spree/shared/_line_item_number_field_disabled.erb +9 -0
  83. data/app/views/spree/shared/_order_item_description.html.erb +15 -0
  84. data/app/views/spree/shared/_starts_in.html.erb +14 -0
  85. data/app/views/spree/shared/_stock_item_name.html.erb +5 -0
  86. data/app/views/spree/shared/_time_in_words_display.html.erb +11 -0
  87. data/app/views/spree/shared/_variant_row_disable.html.erb +21 -0
  88. data/app/views/spree/shared/_variant_stock_item_disable.html.erb +62 -0
  89. data/app/views/spree/shared/_votes.html.erb +12 -0
  90. data/app/views/spree/votes/index.html.erb +13 -0
  91. data/config/locales/en.yml +76 -0
  92. data/config/routes.rb +17 -0
  93. data/db/migrate/20180225234309_create_auctions.rb +25 -0
  94. data/db/migrate/20180225235226_create_bids.rb +13 -0
  95. data/db/migrate/20180316051158_add_deleted_to_spree_auction.rb +5 -0
  96. data/db/migrate/20180320010358_change_auction_reserve_price_column_to_big_decimal.rb +8 -0
  97. data/db/migrate/20180321203019_add_time_zone_to_spree_user.rb +5 -0
  98. data/db/migrate/20180322014713_add_default_to_datetimes.rb +7 -0
  99. data/db/migrate/20180328233438_add_variant_id_to_auction.rb +5 -0
  100. data/db/migrate/20180410025053_acts_as_votable_migration.rb +22 -0
  101. data/db/migrate/20180410031333_add_cached_votes_to_spree_auctions.rb +13 -0
  102. data/lib/assets/javascripts/src/local-time/calendar_date.coffee +37 -0
  103. data/lib/assets/javascripts/src/local-time/config/i18n.coffee +74 -0
  104. data/lib/assets/javascripts/src/local-time/config/locale.coffee +2 -0
  105. data/lib/assets/javascripts/src/local-time/config/timer.coffee +1 -0
  106. data/lib/assets/javascripts/src/local-time/controller.coffee +59 -0
  107. data/lib/assets/javascripts/src/local-time/helpers/date_parse.coffee +15 -0
  108. data/lib/assets/javascripts/src/local-time/helpers/dom.coffee +11 -0
  109. data/lib/assets/javascripts/src/local-time/helpers/i18n.coffee +24 -0
  110. data/lib/assets/javascripts/src/local-time/helpers/strftime.coffee +55 -0
  111. data/lib/assets/javascripts/src/local-time/index.coffee +20 -0
  112. data/lib/assets/javascripts/src/local-time/page_observer.coffee +43 -0
  113. data/lib/assets/javascripts/src/local-time/relative_time.coffee +72 -0
  114. data/lib/assets/javascripts/src/local-time/start.coffee +25 -0
  115. data/lib/generators/solidus_auction/install/install_generator.rb +30 -0
  116. data/lib/local_time.rb +0 -0
  117. data/lib/solidus_auction.rb +3 -0
  118. data/lib/solidus_auction/configuration.rb +8 -0
  119. data/lib/solidus_auction/engine.rb +29 -0
  120. data/lib/solidus_auction/factories.rb +19 -0
  121. data/lib/solidus_auction/version.rb +3 -0
  122. metadata +388 -0
@@ -0,0 +1,2 @@
1
+ class Spree::Admin::BidsController < Spree::Admin::ResourceController
2
+ end
@@ -0,0 +1,9 @@
1
+ Spree::Admin::ResourceController.class_eval do
2
+ around_action :set_time_zone, if: :spree_current_user
3
+
4
+ private
5
+
6
+ def set_time_zone(&block)
7
+ Time.use_zone(spree_current_user.time_zone, &block)
8
+ end
9
+ end
@@ -0,0 +1,52 @@
1
+ class Spree::AuctionsController < Spree::StoreController
2
+ helper Spree::BaseHelper
3
+ helper Spree::Helpers::LocalTimeHelper
4
+ helper_method :config
5
+
6
+ def index
7
+ @auctions = Spree::Auction.in_progress.incomplete.current_end_datetime_ascending
8
+ end
9
+
10
+ def starting_soon
11
+ @auctions = Spree::Auction.incomplete.starting_soon.starting_datetime_ascending
12
+ render :index
13
+ end
14
+
15
+ def ending_soon
16
+ @auctions = Spree::Auction.incomplete.ending_soon
17
+ render :index
18
+ end
19
+
20
+ def recently_completed
21
+ @auctions = Spree::Auction.recently_completed
22
+ render :index
23
+ end
24
+
25
+ def show
26
+ @auction = Spree::Auction.find(params[:id])
27
+ @product = @auction.product
28
+ @product_properties = @product.product_properties.includes(:property)
29
+ end
30
+
31
+ def vote_count
32
+ auction = Spree::Auction.find_by(id: params[:auction_id])
33
+ votes = auction.cached_votes_up
34
+ render json: { votes: votes }
35
+ end
36
+
37
+ def vote_up
38
+ auction = Spree::Auction.find_by(id: params[:auction_id])
39
+ user = Spree::User.find_by(id: params[:user_id])
40
+ auction.liked_by user
41
+ votes = auction.cached_votes_up
42
+ render json: { votes: votes, voted_for: 1 }
43
+ end
44
+
45
+ def vote_down
46
+ auction = Spree::Auction.find_by(id: params[:auction_id])
47
+ user = Spree::User.find_by(id: params[:user_id])
48
+ auction.downvote_from user
49
+ votes = auction.cached_votes_up
50
+ render json: { votes: votes, voted_for: 0 }
51
+ end
52
+ end
@@ -0,0 +1,48 @@
1
+ class Spree::BidsController < Spree::StoreController
2
+ def index
3
+ @auction = Spree::Auction.find(params[:auction_id])
4
+ @bids = @auction.visible_bids_in_chron_order
5
+ end
6
+
7
+ def new
8
+ @auction = Spree::Auction.find(params[:auction_id])
9
+ if spree_current_user
10
+ @bid = Spree::Bid.new(auction: @auction)
11
+ else
12
+ flash[:error] = Spree.t("must_be_signed_in_to_bid")
13
+ redirect_to auction_path @auction
14
+ end
15
+ end
16
+
17
+ def create
18
+ @auction = Spree::Auction.find(params[:auction_id])
19
+ if spree_current_user
20
+ @bid = Spree::Bid.create(auction: @auction, bidder: spree_current_user, amount: params[:amount])
21
+ @recorded_bid, message = @auction.receive_bid(@bid)
22
+ if @recorded_bid
23
+ flash[:success] = message
24
+ else
25
+ flash[:error] = message
26
+ end
27
+ else
28
+ flash[:error] = Spree.t("must_be_signed_in_to_bid")
29
+ end
30
+ redirect_to auction_path @auction
31
+ end
32
+
33
+ private
34
+
35
+ def flash_message_for(object, event_sym)
36
+ resource_desc = object.class.model_name.human
37
+ resource_desc += " \"#{object.name}\"" if object.respond_to?(:name) && object.name.present?
38
+ t(event_sym, resource: resource_desc, scope: 'spree')
39
+ end
40
+
41
+ def permitted_bid_attributes
42
+ %i{auction_id amount}
43
+ end
44
+
45
+ def bid_params
46
+ params.require(:bid).permit(permitted_bid_attributes)
47
+ end
48
+ end
@@ -0,0 +1,77 @@
1
+ module Spree::Helpers::LocalTimeHelper
2
+ module LocalTime
3
+ mattr_accessor(:default_time_format) { "%A, %B %e %Y %l:%M%p" }
4
+ mattr_accessor(:default_date_format) { "%B %e, %Y" }
5
+
6
+ class Engine < ::Rails::Engine
7
+ end
8
+ end
9
+ def local_time(time, options = nil)
10
+ time = utc_time(time)
11
+
12
+ options, format = extract_options_and_value(options, :format)
13
+ format = find_time_format(format)
14
+
15
+ options[:data] ||= {}
16
+ options[:data].merge! local: :time, format: format
17
+
18
+ time_tag time, time.strftime(format), options
19
+ end
20
+
21
+ def local_date(time, options = nil)
22
+ options, format = extract_options_and_value(options, :format)
23
+ options[:format] = format || LocalTime.default_date_format
24
+ local_time time, options
25
+ end
26
+
27
+ def local_relative_time(time, options = nil)
28
+ time = utc_time(time)
29
+ options, type = extract_options_and_value(options, :type)
30
+
31
+ options[:data] ||= {}
32
+ options[:data].merge! local: type
33
+
34
+ time_tag time, time.strftime(LocalTime.default_time_format), options
35
+ end
36
+
37
+ def local_time_ago(time, options = nil)
38
+ options, * = extract_options_and_value(options, :type)
39
+ options[:type] = 'time-ago'
40
+ local_relative_time time, options
41
+ end
42
+
43
+ def utc_time(time_or_date)
44
+ if time_or_date.respond_to?(:in_time_zone)
45
+ time_or_date.in_time_zone.utc
46
+ else
47
+ time_or_date.to_time.utc
48
+ end
49
+ end
50
+
51
+ private
52
+ def find_time_format(format)
53
+ if format.is_a?(Symbol)
54
+ if (i18n_format = I18n.t("time.formats.#{format}", default: [:"date.formats.#{format}", ''])).present?
55
+ i18n_format
56
+ elsif (date_format = Time::DATE_FORMATS[format] || Date::DATE_FORMATS[format])
57
+ date_format.is_a?(Proc) ? LocalTime.default_time_format : date_format
58
+ else
59
+ LocalTime.default_time_format
60
+ end
61
+ else
62
+ format.presence || LocalTime.default_time_format
63
+ end
64
+ end
65
+
66
+ def extract_options_and_value(options, value_key = nil)
67
+ case options
68
+ when Hash
69
+ value = options.delete(value_key)
70
+ [ options, value ]
71
+ when NilClass
72
+ [ {} ]
73
+ else
74
+ [ {}, options ]
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,5 @@
1
+ if !Rails.env.test?
2
+ Spree::UsersController.class_eval do
3
+ helper Spree::Helpers::LocalTimeHelper
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class Spree::VotesController < Spree::StoreController
2
+ def index
3
+ @auctions = spree_current_user.find_up_voted_items
4
+ end
5
+ end
@@ -0,0 +1,8 @@
1
+ Spree::Core::ControllerHelpers::StrongParameters.class_eval do
2
+ def permitted_user_attributes
3
+ permitted_attributes.user_attributes + [
4
+ bill_address_attributes: permitted_address_attributes,
5
+ ship_address_attributes: permitted_address_attributes
6
+ ] + %i{time_zone username}
7
+ end
8
+ end
@@ -0,0 +1,291 @@
1
+ class Spree::Auction < Spree::Base
2
+ belongs_to :product, class_name: 'Spree::Product'
3
+ belongs_to :creator, class_name: 'Spree::User'
4
+ belongs_to :variant, class_name: 'Spree::Variant'
5
+ belongs_to :highest_bidder, class_name: 'Spree::User'
6
+ has_many :bids, class_name: 'Spree::Bid'
7
+
8
+ before_save :init_current_price, if: :new_record?
9
+ before_save :set_current_end_datetime
10
+ after_find :set_complete
11
+
12
+ validates :title, presence: true
13
+ validates :description, presence: true
14
+ validates :starting_datetime, presence: true, in_future: true, if: :new_record?
15
+ validates :planned_end_datetime, presence: true, in_future: true, if: :new_record?
16
+ validates :product_id, presence: true
17
+ validates :creator_id, presence: true
18
+ validates :starting_price, presence: true, numericality: { greater_than_or_equal_to: 0 }
19
+ validates :reserve_price, numericality: { greater_than_or_equal_to: 0 }
20
+ validates :bid_increment, numericality: { greater_than_or_equal_to: 0 }
21
+ validates :time_increment, numericality: { greater_than_or_equal_to: 0 }
22
+ validates :countdown, numericality: { greater_than_or_equal_to: 0 }
23
+
24
+ scope :current_end_datetime_descending, -> { order("current_end_datetime DESC") }
25
+ scope :current_end_datetime_ascending, -> { order(:current_end_datetime) }
26
+ scope :starting_datetime_descending, -> { order("starting_datetime DESC") }
27
+ scope :starting_datetime_ascending, -> { order("starting_datetime") }
28
+ scope :in_progress, -> { where("starting_datetime <= ?", Time.now) }
29
+ scope :incomplete, -> { where(complete: false) }
30
+ scope :complete, -> { where(complete: true) }
31
+
32
+ config = Spree::AuctionSettings::Config
33
+
34
+ scope :starting_soon, -> { where(starting_datetime: Time.now..(Time.now + config.starting_soon_hours.hours)) }
35
+ scope :ending_soon, -> { where(current_end_datetime: Time.now..(Time.now + config.ending_soon_hours.hours)) }
36
+ scope :recently_completed, -> { where(current_end_datetime: (Time.now - config.recently_completed_hours.hours)..Time.now).complete }
37
+
38
+ acts_as_votable
39
+
40
+ def init_current_price
41
+ self.current_price = starting_price
42
+ end
43
+
44
+ def set_current_end_datetime
45
+ if planned_end_datetime != planned_end_datetime_was
46
+ self.current_end_datetime = planned_end_datetime
47
+ end
48
+ end
49
+
50
+ def reserve_met?
51
+ current_price >= reserve_price
52
+ end
53
+
54
+ def won?
55
+ complete && reserve_met? && highest_bidder
56
+ end
57
+
58
+ def started?
59
+ if starting_datetime
60
+ Time.now >= starting_datetime
61
+ end
62
+ end
63
+
64
+ def order
65
+ variant.orders.first
66
+ end
67
+
68
+ def in_progress?
69
+ started? && !complete
70
+ end
71
+
72
+ def visible_bids
73
+ bids.where(visible: true)
74
+ end
75
+
76
+ def visible_bids_in_chron_order
77
+ visible_bids.order("updated_at DESC")
78
+ end
79
+
80
+ def visible_bids_in_id_order
81
+ visible_bids.order("id")
82
+ end
83
+
84
+ def current_end_datetime_as_float
85
+ current_end_datetime.to_f * 1000
86
+ end
87
+
88
+ def starting_datetime_as_float
89
+ starting_datetime.to_f * 1000
90
+ end
91
+
92
+ def accepted_bids
93
+ bids.where(accepted: true)
94
+ end
95
+
96
+ def accepted_bids_in_order
97
+ accepted_bids.order("amount DESC")
98
+ end
99
+
100
+ def highest_bid
101
+ accepted_bids_in_order.first
102
+ end
103
+
104
+ def second_highest_bid
105
+ accepted_bids_in_order.second
106
+ end
107
+
108
+ def top_bids_tied
109
+ if second_highest_bid
110
+ highest_bid.amount == second_highest_bid.amount
111
+ end
112
+ end
113
+
114
+ def ending_soon?
115
+ current_end_datetime - Time.now <= 1.hour
116
+ end
117
+
118
+ def in_countdown?
119
+ current_end_datetime - Time.now <= countdown.seconds
120
+ end
121
+
122
+ extend Spree::DisplayMoney
123
+ money_methods :reserve_price, :current_price, :starting_price, :bid_increment
124
+
125
+ def reserve_price_as_usd
126
+ as_usd reserve_price
127
+ end
128
+
129
+ def current_price_as_usd
130
+ as_usd current_price
131
+ end
132
+
133
+ def as_usd(price_in_dollars)
134
+ Money.new(price_in_dollars)
135
+ end
136
+
137
+ def deleted?
138
+ deleted
139
+ end
140
+
141
+ def set_complete
142
+ if !complete && current_end_datetime <= Time.now
143
+ self.complete = true
144
+ save
145
+ if won?
146
+ add_winning_item_to_highest_bidder_cart
147
+ end
148
+ end
149
+ end
150
+
151
+ def add_winning_item_to_highest_bidder_cart
152
+ user = highest_bidder
153
+ cart = get_user_cart(user)
154
+ new_variant = product.variants.create(price: current_price, track_inventory: false)
155
+ cart.contents.add(new_variant)
156
+ self.variant = new_variant
157
+ save
158
+ end
159
+
160
+ def get_user_cart(user)
161
+ last_user_order = user.last_incomplete_spree_order
162
+
163
+ if last_user_order
164
+ last_user_order
165
+ else
166
+ user.orders.create
167
+ end
168
+ end
169
+
170
+ def set_current_price_and_highest_bidder(price, id)
171
+ self.current_price = price
172
+ self.highest_bidder_id = id
173
+ end
174
+
175
+ def receive_bid(bid)
176
+ bid_amount = bid.amount
177
+ current_price_with_increment = current_price + bid_increment
178
+ bid_undercuts_current_price = bid_amount < current_price_with_increment
179
+ if complete
180
+ bid = nil
181
+ message = Spree.t("auction_is_complete")
182
+ elsif bid_undercuts_current_price
183
+ bid = nil
184
+ message = Spree.t("bid_not_high_enough")
185
+ else
186
+ max_bid = highest_bid
187
+ if max_bid
188
+ max_bid_amount = max_bid.amount
189
+ if max_bid.bidder_id == bid.bidder_id
190
+ if bid_amount > max_bid_amount
191
+ if reserve_met? && top_bids_tied
192
+ amount = current_price_with_increment
193
+ new_bid = bids.create(bidder_id: max_bid.bidder_id, amount: amount, visible: true, accepted: true)
194
+ bid.update(visible: false, accepted: true)
195
+ message = "#{Spree.t(:autobid_up_to)} #{bid.display_amount}. #{Spree.t(:you_successfully_bid)} #{new_bid.display_amount}."
196
+ set_current_price_and_highest_bidder(amount, bid.bidder_id)
197
+ elsif !reserve_met? && bid_amount >= reserve_price
198
+ amount = reserve_price
199
+ set_current_price_and_highest_bidder(amount, max_bid.bidder_id)
200
+ new_bid = bids.create(bidder_id: max_bid.bidder_id, amount: amount, visible: true, accepted: true)
201
+ bid.update(visible: false, accepted: true)
202
+ message = "#{Spree.t(:autobid_up_to)} #{bid.display_amount}. #{Spree.t(:you_successfully_bid)} #{new_bid.display_amount}. #{Spree.t(:met_reserve_price)}."
203
+ elsif !reserve_met? && bid_amount < reserve_price
204
+ bid.update(visible: false, accepted: true)
205
+ message = "#{Spree.t(:autobid_up_to)} #{bid.display_amount}."
206
+ elsif reserve_met? && bid_amount > current_price_with_increment && max_bid.is_autobid?
207
+ bid.update(visible: false, accepted: true)
208
+ max_bid.update(visible: false, accepted: true)
209
+ message = "#{Spree.t(:autobid_up_to)} #{bid.display_amount}."
210
+ elsif reserve_met? && bid_amount > current_price_with_increment && !max_bid.is_autobid?
211
+ bid.update(visible: false, accepted: true)
212
+ message = "#{Spree.t(:autobid_up_to)} #{bid.display_amount}."
213
+ else
214
+ amount = bid_amount
215
+ max_bid.update(visible: false, accepted: false)
216
+ bid.update(visible: false, accepted: true)
217
+ set_current_price_and_highest_bidder(amount, bid.bidder_id)
218
+ message = "#{Spree.t(:autobid_up_to)} #{bid.display_amount}."
219
+ end
220
+ else
221
+ bid = nil
222
+ message = Spree.t(:less_than_original_autobid)
223
+ end
224
+ else
225
+ max_bid_is_higher = max_bid_amount > bid_amount
226
+ max_bid_is_lower = max_bid_amount < bid_amount
227
+ max_bid_with_increment = max_bid.amount + bid_increment
228
+ if max_bid_is_higher
229
+ bid_amount_with_increment = bid_amount + bid_increment
230
+ if bid_amount_with_increment > max_bid_amount
231
+ amount = max_bid_amount
232
+ else
233
+ amount = bid_amount_with_increment
234
+ end
235
+ bid.update(visible: true, accepted: true)
236
+ bids.create(bidder_id: max_bid.bidder_id, amount: amount, visible: true, accepted: true)
237
+ set_current_price_and_highest_bidder(amount, max_bid.bidder_id)
238
+ bid = nil
239
+ message = Spree.t(:you_were_outbid)
240
+ elsif max_bid_is_lower
241
+ if !reserve_met? && bid_amount >= reserve_price
242
+ amount = reserve_price
243
+ elsif max_bid_with_increment > bid_amount
244
+ amount = bid_amount
245
+ else
246
+ amount = max_bid_with_increment
247
+ end
248
+
249
+ max_bid.update(visible: true, accepted: true)
250
+ if max_bid_with_increment == bid_amount
251
+ bid.update(visible: true, accepted: true)
252
+ message = "#{Spree.t(:you_successfully_bid)} #{bid.display_amount}."
253
+ else
254
+ new_bid = bids.create(bidder_id: bid.bidder_id, amount: amount, visible: true, accepted: true)
255
+ bid.update(visible: false, accepted: true)
256
+ message = "#{Spree.t(:autobid_up_to)} #{bid.display_amount}. #{Spree.t(:you_successfully_bid)} #{new_bid.display_amount}."
257
+ end
258
+ set_current_price_and_highest_bidder(amount, bid.bidder_id)
259
+ else
260
+ amount = max_bid.amount
261
+ bid.update(visible: true, accepted: true)
262
+ max_bid.update(visible: true, accepted: true)
263
+ set_current_price_and_highest_bidder(amount, max_bid.bidder_id)
264
+ bid = nil
265
+ message = Spree.t(:there_was_a_tie_autobid_wins)
266
+ end
267
+ end
268
+ elsif bid_amount > current_price_with_increment
269
+ if !reserve_met? && bid_amount >= reserve_price
270
+ amount = reserve_price
271
+ else
272
+ amount = current_price_with_increment
273
+ end
274
+ set_current_price_and_highest_bidder(amount, bid.bidder_id)
275
+ bid.update(visible: false, accepted: true)
276
+ new_bid = bids.create(bidder_id: bid.bidder_id, amount: amount, visible: true, accepted: true)
277
+ message = "#{Spree.t(:autobid_up_to)} #{bid.display_amount}. #{Spree.t(:you_successfully_bid)} #{new_bid.display_amount}."
278
+ else
279
+ bid.update(visible: true, accepted: true)
280
+ amount = current_price_with_increment
281
+ set_current_price_and_highest_bidder(amount, bid.bidder_id)
282
+ message = "#{Spree.t(:you_successfully_bid)} #{bid.display_amount}."
283
+ end
284
+ if in_countdown?
285
+ self.current_end_datetime += time_increment.seconds
286
+ end
287
+ save
288
+ end
289
+ [bid, message]
290
+ end
291
+ end