solidus_frontend_devise_token_auth 2.8.0.alpha.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +26 -0
- data/README.md +42 -0
- data/Rakefile +17 -0
- data/app/assets/config/solidus_frontend_manifest.js +4 -0
- data/app/assets/images/credit_cards/amex_cid.gif +0 -0
- data/app/assets/images/credit_cards/credit_card.gif +0 -0
- data/app/assets/images/credit_cards/discover_cid.gif +0 -0
- data/app/assets/images/credit_cards/icons/american_express.png +0 -0
- data/app/assets/images/credit_cards/icons/cirrus.png +0 -0
- data/app/assets/images/credit_cards/icons/delta.png +0 -0
- data/app/assets/images/credit_cards/icons/diners_club.png +0 -0
- data/app/assets/images/credit_cards/icons/directdebit.png +0 -0
- data/app/assets/images/credit_cards/icons/discover.png +0 -0
- data/app/assets/images/credit_cards/icons/egold.png +0 -0
- data/app/assets/images/credit_cards/icons/maestro.png +0 -0
- data/app/assets/images/credit_cards/icons/master.png +0 -0
- data/app/assets/images/credit_cards/icons/paypal.png +0 -0
- data/app/assets/images/credit_cards/icons/solo.png +0 -0
- data/app/assets/images/credit_cards/icons/switch.png +0 -0
- data/app/assets/images/credit_cards/icons/visa.png +0 -0
- data/app/assets/images/credit_cards/icons/visaelectron.png +0 -0
- data/app/assets/images/credit_cards/icons/westernunion.png +0 -0
- data/app/assets/images/credit_cards/icons/wirecard.png +0 -0
- data/app/assets/images/credit_cards/icons/worldpay.png +0 -0
- data/app/assets/images/credit_cards/master_cid.jpg +0 -0
- data/app/assets/images/credit_cards/visa_cid.gif +0 -0
- data/app/assets/images/favicon.ico +0 -0
- data/app/assets/images/icons/add-to-cart.png +0 -0
- data/app/assets/images/icons/checkout.png +0 -0
- data/app/assets/images/icons/delete.png +0 -0
- data/app/assets/images/icons/update.png +0 -0
- data/app/assets/images/spinner.gif +0 -0
- data/app/assets/images/spree/frontend/cart.png +0 -0
- data/app/assets/javascripts/spree/frontend/cart.js +30 -0
- data/app/assets/javascripts/spree/frontend/checkout/address.js +127 -0
- data/app/assets/javascripts/spree/frontend/checkout/coupon-code.js +41 -0
- data/app/assets/javascripts/spree/frontend/checkout/payment.js +55 -0
- data/app/assets/javascripts/spree/frontend/checkout.js +24 -0
- data/app/assets/javascripts/spree/frontend/locale_selector.js +5 -0
- data/app/assets/javascripts/spree/frontend/product.js +81 -0
- data/app/assets/javascripts/spree/frontend.js +5 -0
- data/app/assets/stylesheets/spree/frontend/_skeleton.scss +242 -0
- data/app/assets/stylesheets/spree/frontend/_variables.scss +65 -0
- data/app/assets/stylesheets/spree/frontend/screen.css.scss +1387 -0
- data/app/assets/stylesheets/spree/frontend.css +5 -0
- data/app/controllers/spree/checkout_controller.rb +236 -0
- data/app/controllers/spree/content_controller.rb +11 -0
- data/app/controllers/spree/home_controller.rb +14 -0
- data/app/controllers/spree/locale_controller.rb +20 -0
- data/app/controllers/spree/orders_controller.rb +138 -0
- data/app/controllers/spree/products_controller.rb +52 -0
- data/app/controllers/spree/store_controller.rb +30 -0
- data/app/controllers/spree/taxons_controller.rb +31 -0
- data/app/helpers/spree/orders_helper.rb +18 -0
- data/app/helpers/spree/taxon_filters_helper.rb +13 -0
- data/app/models/spree/frontend_configuration.rb +10 -0
- data/app/views/spree/address/_form.html.erb +96 -0
- data/app/views/spree/address/_form_hidden.html.erb +12 -0
- data/app/views/spree/checkout/_address.html.erb +33 -0
- data/app/views/spree/checkout/_confirm.html.erb +25 -0
- data/app/views/spree/checkout/_coupon_code.html.erb +12 -0
- data/app/views/spree/checkout/_delivery.html.erb +108 -0
- data/app/views/spree/checkout/_payment.html.erb +67 -0
- data/app/views/spree/checkout/_summary.html.erb +76 -0
- data/app/views/spree/checkout/_terms_and_conditions.en.html.erb +1 -0
- data/app/views/spree/checkout/edit.html.erb +32 -0
- data/app/views/spree/checkout/existing_payment/_gateway.html.erb +9 -0
- data/app/views/spree/checkout/payment/_check.html.erb +0 -0
- data/app/views/spree/checkout/payment/_gateway.html.erb +36 -0
- data/app/views/spree/content/cvv.html.erb +13 -0
- data/app/views/spree/home/index.html.erb +12 -0
- data/app/views/spree/layouts/spree_application.html.erb +36 -0
- data/app/views/spree/orders/_adjustment_row.html.erb +8 -0
- data/app/views/spree/orders/_adjustments.html.erb +24 -0
- data/app/views/spree/orders/_form.html.erb +29 -0
- data/app/views/spree/orders/_line_item.html.erb +34 -0
- data/app/views/spree/orders/edit.html.erb +47 -0
- data/app/views/spree/orders/show.html.erb +22 -0
- data/app/views/spree/payments/_payment.html.erb +18 -0
- data/app/views/spree/products/_cart_form.html.erb +65 -0
- data/app/views/spree/products/_image.html.erb +8 -0
- data/app/views/spree/products/_promotions.html.erb +19 -0
- data/app/views/spree/products/_properties.html.erb +15 -0
- data/app/views/spree/products/_taxons.html.erb +14 -0
- data/app/views/spree/products/_thumbnails.html.erb +21 -0
- data/app/views/spree/products/index.html.erb +27 -0
- data/app/views/spree/products/show.html.erb +51 -0
- data/app/views/spree/shared/_address.html.erb +38 -0
- data/app/views/spree/shared/_filters.html.erb +27 -0
- data/app/views/spree/shared/_footer.html.erb +6 -0
- data/app/views/spree/shared/_head.html.erb +14 -0
- data/app/views/spree/shared/_header.html.erb +5 -0
- data/app/views/spree/shared/_image.html.erb +12 -0
- data/app/views/spree/shared/_link_to_cart.html.erb +1 -0
- data/app/views/spree/shared/_locale_selector.html.erb +25 -0
- data/app/views/spree/shared/_login_bar_items.html.erb +1 -0
- data/app/views/spree/shared/_main_nav_bar.html.erb +12 -0
- data/app/views/spree/shared/_nav_bar.html.erb +9 -0
- data/app/views/spree/shared/_order_details.html.erb +146 -0
- data/app/views/spree/shared/_products.html.erb +51 -0
- data/app/views/spree/shared/_search.html.erb +11 -0
- data/app/views/spree/shared/_shipment_tracking.html.erb +9 -0
- data/app/views/spree/shared/_sidebar.html.erb +3 -0
- data/app/views/spree/shared/_taxonomies.html.erb +9 -0
- data/app/views/spree/shared/unauthorized.html.erb +0 -0
- data/app/views/spree/store/cart_link.html.erb +1 -0
- data/app/views/spree/taxons/_taxon.html.erb +4 -0
- data/app/views/spree/taxons/show.html.erb +20 -0
- data/config/initializers/assets.rb +3 -0
- data/config/initializers/canonical_rails.rb +16 -0
- data/config/routes.rb +33 -0
- data/lib/generators/solidus/views/override_generator.rb +49 -0
- data/lib/solidus_frontend.rb +3 -0
- data/lib/spree/frontend/engine.rb +13 -0
- data/lib/spree/frontend/middleware/seo_assist.rb +52 -0
- data/lib/spree/frontend.rb +15 -0
- data/lib/spree_frontend.rb +3 -0
- data/lib/tasks/rake_util.rb +18 -0
- data/lib/tasks/taxon.rake +16 -0
- data/script/rails +10 -0
- data/solidus_frontend.gemspec +35 -0
- data/spec/controllers/controller_helpers_spec.rb +30 -0
- data/spec/controllers/locale_controller_spec.rb +57 -0
- data/spec/controllers/spree/checkout_controller_spec.rb +539 -0
- data/spec/controllers/spree/checkout_controller_with_views_spec.rb +37 -0
- data/spec/controllers/spree/content_controller_spec.rb +9 -0
- data/spec/controllers/spree/current_order_tracking_spec.rb +47 -0
- data/spec/controllers/spree/home_controller_spec.rb +29 -0
- data/spec/controllers/spree/orders_controller_ability_spec.rb +93 -0
- data/spec/controllers/spree/orders_controller_spec.rb +225 -0
- data/spec/controllers/spree/orders_controller_transitions_spec.rb +33 -0
- data/spec/controllers/spree/products_controller_spec.rb +38 -0
- data/spec/controllers/spree/taxons_controller_spec.rb +14 -0
- data/spec/features/address_spec.rb +78 -0
- data/spec/features/automatic_promotion_adjustments_spec.rb +49 -0
- data/spec/features/caching/products_spec.rb +48 -0
- data/spec/features/caching/taxons_spec.rb +21 -0
- data/spec/features/cart_spec.rb +85 -0
- data/spec/features/checkout_spec.rb +690 -0
- data/spec/features/checkout_unshippable_spec.rb +37 -0
- data/spec/features/coupon_code_spec.rb +266 -0
- data/spec/features/currency_spec.rb +20 -0
- data/spec/features/free_shipping_promotions_spec.rb +60 -0
- data/spec/features/locale_spec.rb +27 -0
- data/spec/features/order_spec.rb +73 -0
- data/spec/features/products_spec.rb +291 -0
- data/spec/features/promotion_code_invalidation_spec.rb +54 -0
- data/spec/features/quantity_promotions_spec.rb +130 -0
- data/spec/features/taxons_spec.rb +158 -0
- data/spec/features/template_rendering_spec.rb +20 -0
- data/spec/fixtures/thinking-cat.jpg +0 -0
- data/spec/generators/solidus/views/override_generator_spec.rb +50 -0
- data/spec/helpers/base_helper_spec.rb +13 -0
- data/spec/helpers/order_helper_spec.rb +14 -0
- data/spec/helpers/taxon_filters_helper_spec.rb +12 -0
- data/spec/spec_helper.rb +106 -0
- data/spec/support/features/fill_in_with_force.rb +12 -0
- data/spec/support/shared_contexts/checkout_setup.rb +12 -0
- data/spec/support/shared_contexts/custom_products.rb +28 -0
- data/spec/support/shared_contexts/locales.rb +16 -0
- data/spec/views/spree/checkout/_summary_spec.rb +11 -0
- metadata +337 -0
@@ -0,0 +1,236 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
# This is somewhat contrary to standard REST convention since there is not
|
5
|
+
# actually a Checkout object. There's enough distinct logic specific to
|
6
|
+
# checkout which has nothing to do with updating an order that this approach
|
7
|
+
# is warranted.
|
8
|
+
class CheckoutController < Spree::StoreController
|
9
|
+
before_action :load_order
|
10
|
+
around_action :lock_order
|
11
|
+
before_action :set_state_if_present
|
12
|
+
|
13
|
+
before_action :ensure_order_not_completed
|
14
|
+
before_action :ensure_checkout_allowed
|
15
|
+
before_action :ensure_sufficient_stock_lines
|
16
|
+
before_action :ensure_valid_state
|
17
|
+
|
18
|
+
before_action :associate_user
|
19
|
+
before_action :check_authorization
|
20
|
+
before_action :apply_coupon_code
|
21
|
+
|
22
|
+
before_action :setup_for_current_state, only: [:edit, :update]
|
23
|
+
|
24
|
+
helper 'spree/orders'
|
25
|
+
|
26
|
+
rescue_from Spree::Core::GatewayError, with: :rescue_from_spree_gateway_error
|
27
|
+
|
28
|
+
# Updates the order and advances to the next state (when possible.)
|
29
|
+
def update
|
30
|
+
if update_order
|
31
|
+
|
32
|
+
assign_temp_address
|
33
|
+
|
34
|
+
unless transition_forward
|
35
|
+
redirect_on_failure
|
36
|
+
return
|
37
|
+
end
|
38
|
+
|
39
|
+
if @order.completed?
|
40
|
+
finalize_order
|
41
|
+
else
|
42
|
+
send_to_next_state
|
43
|
+
end
|
44
|
+
|
45
|
+
else
|
46
|
+
render :edit
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def update_order
|
53
|
+
OrderUpdateAttributes.new(@order, update_params, request_env: request.headers.env).apply
|
54
|
+
end
|
55
|
+
|
56
|
+
def assign_temp_address
|
57
|
+
@order.temporary_address = !params[:save_user_address]
|
58
|
+
end
|
59
|
+
|
60
|
+
def redirect_on_failure
|
61
|
+
flash[:error] = @order.errors.full_messages.join("\n")
|
62
|
+
redirect_to(checkout_state_path(@order.state))
|
63
|
+
end
|
64
|
+
|
65
|
+
def transition_forward
|
66
|
+
if @order.can_complete?
|
67
|
+
@order.complete
|
68
|
+
else
|
69
|
+
@order.next
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def finalize_order
|
74
|
+
@current_order = nil
|
75
|
+
set_successful_flash_notice
|
76
|
+
redirect_to completion_route
|
77
|
+
end
|
78
|
+
|
79
|
+
def set_successful_flash_notice
|
80
|
+
flash.notice = t('spree.order_processed_successfully')
|
81
|
+
flash['order_completed'] = true
|
82
|
+
end
|
83
|
+
|
84
|
+
def send_to_next_state
|
85
|
+
redirect_to checkout_state_path(@order.state)
|
86
|
+
end
|
87
|
+
|
88
|
+
def update_params
|
89
|
+
if update_params = massaged_params[:order]
|
90
|
+
update_params.permit(permitted_checkout_attributes)
|
91
|
+
else
|
92
|
+
# We currently allow update requests without any parameters in them.
|
93
|
+
{}
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def massaged_params
|
98
|
+
massaged_params = params.deep_dup
|
99
|
+
|
100
|
+
move_payment_source_into_payments_attributes(massaged_params)
|
101
|
+
if massaged_params[:order] && massaged_params[:order][:existing_card].present?
|
102
|
+
Spree::Deprecation.warn("Passing order[:existing_card] is deprecated. Send order[:wallet_payment_source_id] instead.", caller)
|
103
|
+
move_existing_card_into_payments_attributes(massaged_params) # deprecated
|
104
|
+
end
|
105
|
+
move_wallet_payment_source_id_into_payments_attributes(massaged_params)
|
106
|
+
set_payment_parameters_amount(massaged_params, @order)
|
107
|
+
|
108
|
+
massaged_params
|
109
|
+
end
|
110
|
+
|
111
|
+
def ensure_valid_state
|
112
|
+
unless skip_state_validation?
|
113
|
+
if (params[:state] && !@order.has_checkout_step?(params[:state])) ||
|
114
|
+
(!params[:state] && !@order.has_checkout_step?(@order.state))
|
115
|
+
@order.state = 'cart'
|
116
|
+
redirect_to checkout_state_path(@order.checkout_steps.first)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# Fix for https://github.com/spree/spree/issues/4117
|
121
|
+
# If confirmation of payment fails, redirect back to payment screen
|
122
|
+
if params[:state] == "confirm" && @order.payment_required? && @order.payments.valid.empty?
|
123
|
+
flash.keep
|
124
|
+
redirect_to checkout_state_path("payment")
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# Should be overriden if you have areas of your checkout that don't match
|
129
|
+
# up to a step within checkout_steps, such as a registration step
|
130
|
+
def skip_state_validation?
|
131
|
+
false
|
132
|
+
end
|
133
|
+
|
134
|
+
def load_order
|
135
|
+
@order = current_order
|
136
|
+
redirect_to(spree.cart_path) && return unless @order
|
137
|
+
end
|
138
|
+
|
139
|
+
def set_state_if_present
|
140
|
+
if params[:state]
|
141
|
+
redirect_to checkout_state_path(@order.state) if @order.can_go_to_state?(params[:state]) && !skip_state_validation?
|
142
|
+
@order.state = params[:state]
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def ensure_checkout_allowed
|
147
|
+
unless @order.checkout_allowed?
|
148
|
+
redirect_to spree.cart_path
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def ensure_order_not_completed
|
153
|
+
redirect_to spree.cart_path if @order.completed?
|
154
|
+
end
|
155
|
+
|
156
|
+
def ensure_sufficient_stock_lines
|
157
|
+
if @order.insufficient_stock_lines.present?
|
158
|
+
out_of_stock_items = @order.insufficient_stock_lines.collect(&:name).to_sentence
|
159
|
+
flash[:error] = t('spree.inventory_error_flash_for_insufficient_quantity', names: out_of_stock_items)
|
160
|
+
redirect_to spree.cart_path
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
# Provides a route to redirect after order completion
|
165
|
+
def completion_route
|
166
|
+
spree.order_path(@order)
|
167
|
+
end
|
168
|
+
|
169
|
+
def apply_coupon_code
|
170
|
+
if update_params[:coupon_code].present?
|
171
|
+
@order.coupon_code = update_params[:coupon_code]
|
172
|
+
|
173
|
+
handler = PromotionHandler::Coupon.new(@order).apply
|
174
|
+
|
175
|
+
if handler.error.present?
|
176
|
+
flash.now[:error] = handler.error
|
177
|
+
elsif handler.success
|
178
|
+
flash[:success] = handler.success
|
179
|
+
end
|
180
|
+
|
181
|
+
setup_for_current_state
|
182
|
+
respond_with(@order) { |format| format.html { render :edit } } && return
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def setup_for_current_state
|
187
|
+
method_name = :"before_#{@order.state}"
|
188
|
+
send(method_name) if respond_to?(method_name, true)
|
189
|
+
end
|
190
|
+
|
191
|
+
def before_address
|
192
|
+
@order.assign_default_user_addresses
|
193
|
+
# If the user has a default address, the previous method call takes care
|
194
|
+
# of setting that; but if he doesn't, we need to build an empty one here
|
195
|
+
default = { country_id: Spree::Country.default.id }
|
196
|
+
@order.build_bill_address(default) unless @order.bill_address
|
197
|
+
@order.build_ship_address(default) if @order.checkout_steps.include?('delivery') && !@order.ship_address
|
198
|
+
end
|
199
|
+
|
200
|
+
def before_delivery
|
201
|
+
return if params[:order].present?
|
202
|
+
|
203
|
+
packages = @order.shipments.map(&:to_package)
|
204
|
+
@differentiator = Spree::Stock::Differentiator.new(@order, packages)
|
205
|
+
end
|
206
|
+
|
207
|
+
def before_payment
|
208
|
+
if @order.checkout_steps.include? "delivery"
|
209
|
+
packages = @order.shipments.map(&:to_package)
|
210
|
+
@differentiator = Spree::Stock::Differentiator.new(@order, packages)
|
211
|
+
@differentiator.missing.each do |variant, quantity|
|
212
|
+
@order.contents.remove(variant, quantity)
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
if try_spree_current_user && try_spree_current_user.respond_to?(:wallet)
|
217
|
+
@wallet_payment_sources = try_spree_current_user.wallet.wallet_payment_sources
|
218
|
+
@default_wallet_payment_source = @wallet_payment_sources.detect(&:default) ||
|
219
|
+
@wallet_payment_sources.first
|
220
|
+
# TODO: How can we deprecate this instance variable? We could try
|
221
|
+
# wrapping it in a delegating object that produces deprecation warnings.
|
222
|
+
@payment_sources = try_spree_current_user.wallet.wallet_payment_sources.map(&:payment_source).select { |ps| ps.is_a?(Spree::CreditCard) }
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def rescue_from_spree_gateway_error(exception)
|
227
|
+
flash.now[:error] = t('spree.spree_gateway_error_flash_for_checkout')
|
228
|
+
@order.errors.add(:base, exception.message)
|
229
|
+
render :edit
|
230
|
+
end
|
231
|
+
|
232
|
+
def check_authorization
|
233
|
+
authorize!(:edit, current_order, cookies.signed[:guest_token])
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
class HomeController < Spree::StoreController
|
5
|
+
helper 'spree/products'
|
6
|
+
respond_to :html
|
7
|
+
|
8
|
+
def index
|
9
|
+
@searcher = build_searcher(params.merge(include_images: true))
|
10
|
+
@products = @searcher.retrieve_products
|
11
|
+
@taxonomies = Spree::Taxonomy.includes(root: :children)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
class LocaleController < Spree::StoreController
|
5
|
+
def set
|
6
|
+
available_locales = Spree.i18n_available_locales
|
7
|
+
requested_locale = params[:switch_to_locale] || params[:locale]
|
8
|
+
|
9
|
+
if requested_locale && available_locales.map(&:to_s).include?(requested_locale)
|
10
|
+
session[:locale] = requested_locale
|
11
|
+
I18n.locale = requested_locale
|
12
|
+
flash.notice = t('spree.locale_changed')
|
13
|
+
else
|
14
|
+
flash[:error] = t('spree.locale_not_changed')
|
15
|
+
end
|
16
|
+
|
17
|
+
redirect_to spree.root_path
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
class OrdersController < Spree::StoreController
|
5
|
+
helper 'spree/products', 'spree/orders'
|
6
|
+
|
7
|
+
respond_to :html
|
8
|
+
|
9
|
+
before_action :store_guest_token
|
10
|
+
before_action :assign_order, only: :update
|
11
|
+
# note: do not lock the #edit action because that's where we redirect when we fail to acquire a lock
|
12
|
+
around_action :lock_order, only: :update
|
13
|
+
before_action :apply_coupon_code, only: :update
|
14
|
+
skip_before_action :verify_authenticity_token, only: [:populate]
|
15
|
+
|
16
|
+
def show
|
17
|
+
@order = Spree::Order.find_by!(number: params[:id])
|
18
|
+
authorize! :read, @order, cookies.signed[:guest_token]
|
19
|
+
end
|
20
|
+
|
21
|
+
def update
|
22
|
+
authorize! :update, @order, cookies.signed[:guest_token]
|
23
|
+
if @order.contents.update_cart(order_params)
|
24
|
+
@order.next if params.key?(:checkout) && @order.cart?
|
25
|
+
|
26
|
+
respond_with(@order) do |format|
|
27
|
+
format.html do
|
28
|
+
if params.key?(:checkout)
|
29
|
+
redirect_to checkout_state_path(@order.checkout_steps.first)
|
30
|
+
else
|
31
|
+
redirect_to cart_path
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
else
|
36
|
+
respond_with(@order)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Shows the current incomplete order from the session
|
41
|
+
def edit
|
42
|
+
@order = current_order || Spree::Order.incomplete.find_or_initialize_by(guest_token: cookies.signed[:guest_token])
|
43
|
+
authorize! :read, @order, cookies.signed[:guest_token]
|
44
|
+
associate_user
|
45
|
+
end
|
46
|
+
|
47
|
+
# Adds a new item to the order (creating a new order if none already exists)
|
48
|
+
def populate
|
49
|
+
@order = current_order(create_order_if_necessary: true)
|
50
|
+
authorize! :update, @order, cookies.signed[:guest_token]
|
51
|
+
|
52
|
+
variant = Spree::Variant.find(params[:variant_id])
|
53
|
+
quantity = params[:quantity].present? ? params[:quantity].to_i : 1
|
54
|
+
|
55
|
+
# 2,147,483,647 is crazy. See issue https://github.com/spree/spree/issues/2695.
|
56
|
+
if !quantity.between?(1, 2_147_483_647)
|
57
|
+
@order.errors.add(:base, t('spree.please_enter_reasonable_quantity'))
|
58
|
+
end
|
59
|
+
|
60
|
+
begin
|
61
|
+
@line_item = @order.contents.add(variant, quantity)
|
62
|
+
rescue ActiveRecord::RecordInvalid => e
|
63
|
+
@order.errors.add(:base, e.record.errors.full_messages.join(", "))
|
64
|
+
end
|
65
|
+
|
66
|
+
respond_with(@order) do |format|
|
67
|
+
format.html do
|
68
|
+
if @order.errors.any?
|
69
|
+
flash[:error] = @order.errors.full_messages.join(", ")
|
70
|
+
redirect_back_or_default(spree.root_path)
|
71
|
+
return
|
72
|
+
else
|
73
|
+
redirect_to cart_path
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def populate_redirect
|
80
|
+
flash[:error] = t('spree.populate_get_error')
|
81
|
+
redirect_to spree.cart_path
|
82
|
+
end
|
83
|
+
|
84
|
+
def empty
|
85
|
+
if @order = current_order
|
86
|
+
authorize! :update, @order, cookies.signed[:guest_token]
|
87
|
+
@order.empty!
|
88
|
+
end
|
89
|
+
|
90
|
+
redirect_to spree.cart_path
|
91
|
+
end
|
92
|
+
|
93
|
+
def accurate_title
|
94
|
+
if @order && @order.completed?
|
95
|
+
t('spree.order_number', number: @order.number)
|
96
|
+
else
|
97
|
+
t('spree.shopping_cart')
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
def store_guest_token
|
104
|
+
cookies.permanent.signed[:guest_token] = params[:token] if params[:token]
|
105
|
+
end
|
106
|
+
|
107
|
+
def order_params
|
108
|
+
if params[:order]
|
109
|
+
params[:order].permit(*permitted_order_attributes)
|
110
|
+
else
|
111
|
+
{}
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def assign_order
|
116
|
+
@order = current_order
|
117
|
+
unless @order
|
118
|
+
flash[:error] = t('spree.order_not_found')
|
119
|
+
redirect_to(root_path) && return
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def apply_coupon_code
|
124
|
+
if order_params[:coupon_code].present?
|
125
|
+
@order.coupon_code = order_params[:coupon_code]
|
126
|
+
|
127
|
+
handler = PromotionHandler::Coupon.new(@order).apply
|
128
|
+
|
129
|
+
if handler.error.present?
|
130
|
+
flash.now[:error] = handler.error
|
131
|
+
respond_with(@order) { |format| format.html { render :edit } } && return
|
132
|
+
elsif handler.success
|
133
|
+
flash[:success] = handler.success
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
class ProductsController < Spree::StoreController
|
5
|
+
before_action :load_product, only: :show
|
6
|
+
before_action :load_taxon, only: :index
|
7
|
+
|
8
|
+
helper 'spree/taxons', 'spree/taxon_filters'
|
9
|
+
|
10
|
+
respond_to :html
|
11
|
+
|
12
|
+
def index
|
13
|
+
@searcher = build_searcher(params.merge(include_images: true))
|
14
|
+
@products = @searcher.retrieve_products
|
15
|
+
@taxonomies = Spree::Taxonomy.includes(root: :children)
|
16
|
+
end
|
17
|
+
|
18
|
+
def show
|
19
|
+
@variants = @product.
|
20
|
+
variants_including_master.
|
21
|
+
display_includes.
|
22
|
+
with_prices(current_pricing_options).
|
23
|
+
includes([:option_values, :images])
|
24
|
+
|
25
|
+
@product_properties = @product.product_properties.includes(:property)
|
26
|
+
@taxon = Spree::Taxon.find(params[:taxon_id]) if params[:taxon_id]
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def accurate_title
|
32
|
+
if @product
|
33
|
+
@product.meta_title.blank? ? @product.name : @product.meta_title
|
34
|
+
else
|
35
|
+
super
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def load_product
|
40
|
+
if try_spree_current_user.try(:has_spree_role?, "admin")
|
41
|
+
@products = Spree::Product.with_deleted
|
42
|
+
else
|
43
|
+
@products = Spree::Product.available
|
44
|
+
end
|
45
|
+
@product = @products.friendly.find(params[:id])
|
46
|
+
end
|
47
|
+
|
48
|
+
def load_taxon
|
49
|
+
@taxon = Spree::Taxon.find(params[:taxon]) if params[:taxon].present?
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
class StoreController < Spree::BaseController
|
5
|
+
include Spree::Core::ControllerHelpers::Pricing
|
6
|
+
include Spree::Core::ControllerHelpers::Order
|
7
|
+
|
8
|
+
def unauthorized
|
9
|
+
render 'spree/shared/unauthorized', layout: Spree::Config[:layout], status: 401
|
10
|
+
end
|
11
|
+
|
12
|
+
def cart_link
|
13
|
+
render partial: 'spree/shared/link_to_cart'
|
14
|
+
fresh_when(current_order, template: 'spree/shared/_link_to_cart')
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def config_locale
|
20
|
+
Spree::Frontend::Config[:locale]
|
21
|
+
end
|
22
|
+
|
23
|
+
def lock_order
|
24
|
+
Spree::OrderMutex.with_lock!(@order) { yield }
|
25
|
+
rescue Spree::OrderMutex::LockFailed
|
26
|
+
flash[:error] = t('spree.order_mutex_error')
|
27
|
+
redirect_to spree.cart_path
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
class TaxonsController < Spree::StoreController
|
5
|
+
helper 'spree/products', 'spree/taxon_filters'
|
6
|
+
|
7
|
+
before_action :load_taxon, only: [:show]
|
8
|
+
|
9
|
+
respond_to :html
|
10
|
+
|
11
|
+
def show
|
12
|
+
@searcher = build_searcher(params.merge(taxon: @taxon.id, include_images: true))
|
13
|
+
@products = @searcher.retrieve_products
|
14
|
+
@taxonomies = Spree::Taxonomy.includes(root: :children)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def load_taxon
|
20
|
+
@taxon = Spree::Taxon.find_by!(permalink: params[:id])
|
21
|
+
end
|
22
|
+
|
23
|
+
def accurate_title
|
24
|
+
if @taxon
|
25
|
+
@taxon.seo_title
|
26
|
+
else
|
27
|
+
super
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'truncate_html'
|
4
|
+
require 'app/helpers/truncate_html_helper'
|
5
|
+
|
6
|
+
module Spree
|
7
|
+
module OrdersHelper
|
8
|
+
include TruncateHtmlHelper
|
9
|
+
|
10
|
+
def truncated_product_description(product)
|
11
|
+
truncate_html(raw(product.description))
|
12
|
+
end
|
13
|
+
|
14
|
+
def order_just_completed?(order)
|
15
|
+
flash[:order_completed] && order.present?
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spree/core/product_filters'
|
4
|
+
|
5
|
+
module Spree
|
6
|
+
module TaxonFiltersHelper
|
7
|
+
def applicable_filters_for(_taxon)
|
8
|
+
[:brand_filter, :price_filter].map do |filter_name|
|
9
|
+
Spree::Core::ProductFilters.send(filter_name) if Spree::Core::ProductFilters.respond_to?(filter_name)
|
10
|
+
end.compact
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
class FrontendConfiguration < Preferences::Configuration
|
5
|
+
preference :locale, :string, default: Rails.application.config.i18n.default_locale
|
6
|
+
|
7
|
+
# Add your terms and conditions in app/views/spree/checkout/_terms_and_conditions.en.html.erb
|
8
|
+
preference :require_terms_and_conditions_acceptance, :boolean, default: false
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
<% address_id = address_type.chars.first %>
|
2
|
+
<div class="inner" data-hook=<%="#{address_type}_inner" %>>
|
3
|
+
<div class="field field-required" id=<%="#{address_id}firstname" %>>
|
4
|
+
<%= form.label :firstname, t('spree.first_name') %>
|
5
|
+
<%= form.text_field :firstname, class: 'required', autocomplete: address_type + ' given-name', required: true, autofocus: true %>
|
6
|
+
</div>
|
7
|
+
|
8
|
+
<div class="field" id=<%="#{address_id}lastname" %>>
|
9
|
+
<%= form.label :lastname, t('spree.last_name') %>
|
10
|
+
<%= form.text_field :lastname, autocomplete: address_type + ' family-name' %>
|
11
|
+
</div>
|
12
|
+
|
13
|
+
<% if Spree::Config[:company] %>
|
14
|
+
<div class="field" id=<%="#{address_id}company" %>>
|
15
|
+
<%= form.label :company, t('spree.company') %>
|
16
|
+
<%= form.text_field :company, autocomplete: address_type + ' organization' %>
|
17
|
+
</div>
|
18
|
+
<% end %>
|
19
|
+
|
20
|
+
<div class="field field-required" id=<%="#{address_id}address1" %>>
|
21
|
+
<%= form.label :address1, t('spree.street_address') %>
|
22
|
+
<%= form.text_field :address1, class: 'required', autocomplete: address_type + ' address-line1', required: true %>
|
23
|
+
</div>
|
24
|
+
|
25
|
+
<div class="field" id=<%="#{address_id}address2" %>>
|
26
|
+
<%= form.label :address2, I18n.t('spree.street_address_2') %>
|
27
|
+
<%= form.text_field :address2, autocomplete: address_type + ' address-line2' %>
|
28
|
+
</div>
|
29
|
+
|
30
|
+
<div class="field field-required" id=<%="#{address_id}city" %>>
|
31
|
+
<%= form.label :city, t('spree.city') %>
|
32
|
+
<%= form.text_field :city, class: 'required', autocomplete: address_type + ' address-level2', required: true %>
|
33
|
+
</div>
|
34
|
+
|
35
|
+
<div class="field field-required" id=<%="#{address_id}country" %>>
|
36
|
+
<%= form.label :country_id, t('spree.country') %>
|
37
|
+
<span id=<%="#{address_id}country-selection" %>>
|
38
|
+
<%= form.collection_select :country_id, available_countries, :id, :name, {},
|
39
|
+
class: 'required',
|
40
|
+
autocomplete: address_type + ' country-name',
|
41
|
+
required: true
|
42
|
+
%>
|
43
|
+
</span>
|
44
|
+
</div>
|
45
|
+
|
46
|
+
<% if Spree::Config[:address_requires_state] %>
|
47
|
+
<div class="field field-required" id=<%="#{address_id}state" %>>
|
48
|
+
<% have_states = !address.country.states.empty? %>
|
49
|
+
<%= form.label :state, t('spree.state') %>
|
50
|
+
|
51
|
+
<span class="js-address-fields" style="display: none;">
|
52
|
+
<%=
|
53
|
+
form.collection_select(
|
54
|
+
:state_id, address.country.states, :id, :name,
|
55
|
+
{include_blank: true},
|
56
|
+
{
|
57
|
+
class: have_states ? 'required' : '',
|
58
|
+
style: have_states ? '' : 'display: none;',
|
59
|
+
disabled: !have_states,
|
60
|
+
autocomplete: address_type + ' address-level1',
|
61
|
+
})
|
62
|
+
%>
|
63
|
+
<%=
|
64
|
+
form.text_field(
|
65
|
+
:state_name,
|
66
|
+
class: !have_states ? 'required' : '',
|
67
|
+
style: have_states ? 'display: none;' : '',
|
68
|
+
disabled: have_states,
|
69
|
+
autocomplete: address_type + ' address-level1',
|
70
|
+
)
|
71
|
+
%>
|
72
|
+
</span>
|
73
|
+
<noscript>
|
74
|
+
<%= form.text_field :state_name, class: 'required', autocomplete: address_type + ' address-level1', required: true %>
|
75
|
+
</noscript>
|
76
|
+
</div>
|
77
|
+
<% end %>
|
78
|
+
|
79
|
+
<div class="field <%= 'field-required' if address.require_zipcode? %>" id=<%="#{address_id}zipcode" %>>
|
80
|
+
<%= form.label :zipcode, t('spree.zip') %>
|
81
|
+
<%= form.text_field :zipcode, class: "#{'required' if address.require_zipcode?}", autocomplete: address_type + ' postal-code', required: true %>
|
82
|
+
</div>
|
83
|
+
|
84
|
+
<div class="field <%= 'field-required' if address.require_phone? %>" id=<%="#{address_id}phone" %>>
|
85
|
+
<%= form.label :phone, t('spree.phone') %>
|
86
|
+
<% phone_hash = address.require_phone? ? { class: 'required', required: true } : {} %>
|
87
|
+
<%= form.phone_field :phone, phone_hash.merge({ autocomplete: address_type + ' home tel' }) %>
|
88
|
+
</div>
|
89
|
+
|
90
|
+
<% if Spree::Config[:alternative_shipping_phone] %>
|
91
|
+
<div class="field" id=<%="#{address_id}altphone" %>>
|
92
|
+
<%= form.label :alternative_phone, t('spree.alternative_phone') %>
|
93
|
+
<%= form.phone_field :alternative_phone, autocomplete: address_type + ' tel'%>
|
94
|
+
</div>
|
95
|
+
<% end %>
|
96
|
+
</div>
|