solidus_frontend_devise_token_auth 2.8.0.alpha.2

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 (163) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +26 -0
  3. data/README.md +42 -0
  4. data/Rakefile +17 -0
  5. data/app/assets/config/solidus_frontend_manifest.js +4 -0
  6. data/app/assets/images/credit_cards/amex_cid.gif +0 -0
  7. data/app/assets/images/credit_cards/credit_card.gif +0 -0
  8. data/app/assets/images/credit_cards/discover_cid.gif +0 -0
  9. data/app/assets/images/credit_cards/icons/american_express.png +0 -0
  10. data/app/assets/images/credit_cards/icons/cirrus.png +0 -0
  11. data/app/assets/images/credit_cards/icons/delta.png +0 -0
  12. data/app/assets/images/credit_cards/icons/diners_club.png +0 -0
  13. data/app/assets/images/credit_cards/icons/directdebit.png +0 -0
  14. data/app/assets/images/credit_cards/icons/discover.png +0 -0
  15. data/app/assets/images/credit_cards/icons/egold.png +0 -0
  16. data/app/assets/images/credit_cards/icons/maestro.png +0 -0
  17. data/app/assets/images/credit_cards/icons/master.png +0 -0
  18. data/app/assets/images/credit_cards/icons/paypal.png +0 -0
  19. data/app/assets/images/credit_cards/icons/solo.png +0 -0
  20. data/app/assets/images/credit_cards/icons/switch.png +0 -0
  21. data/app/assets/images/credit_cards/icons/visa.png +0 -0
  22. data/app/assets/images/credit_cards/icons/visaelectron.png +0 -0
  23. data/app/assets/images/credit_cards/icons/westernunion.png +0 -0
  24. data/app/assets/images/credit_cards/icons/wirecard.png +0 -0
  25. data/app/assets/images/credit_cards/icons/worldpay.png +0 -0
  26. data/app/assets/images/credit_cards/master_cid.jpg +0 -0
  27. data/app/assets/images/credit_cards/visa_cid.gif +0 -0
  28. data/app/assets/images/favicon.ico +0 -0
  29. data/app/assets/images/icons/add-to-cart.png +0 -0
  30. data/app/assets/images/icons/checkout.png +0 -0
  31. data/app/assets/images/icons/delete.png +0 -0
  32. data/app/assets/images/icons/update.png +0 -0
  33. data/app/assets/images/spinner.gif +0 -0
  34. data/app/assets/images/spree/frontend/cart.png +0 -0
  35. data/app/assets/javascripts/spree/frontend/cart.js +30 -0
  36. data/app/assets/javascripts/spree/frontend/checkout/address.js +127 -0
  37. data/app/assets/javascripts/spree/frontend/checkout/coupon-code.js +41 -0
  38. data/app/assets/javascripts/spree/frontend/checkout/payment.js +55 -0
  39. data/app/assets/javascripts/spree/frontend/checkout.js +24 -0
  40. data/app/assets/javascripts/spree/frontend/locale_selector.js +5 -0
  41. data/app/assets/javascripts/spree/frontend/product.js +81 -0
  42. data/app/assets/javascripts/spree/frontend.js +5 -0
  43. data/app/assets/stylesheets/spree/frontend/_skeleton.scss +242 -0
  44. data/app/assets/stylesheets/spree/frontend/_variables.scss +65 -0
  45. data/app/assets/stylesheets/spree/frontend/screen.css.scss +1387 -0
  46. data/app/assets/stylesheets/spree/frontend.css +5 -0
  47. data/app/controllers/spree/checkout_controller.rb +236 -0
  48. data/app/controllers/spree/content_controller.rb +11 -0
  49. data/app/controllers/spree/home_controller.rb +14 -0
  50. data/app/controllers/spree/locale_controller.rb +20 -0
  51. data/app/controllers/spree/orders_controller.rb +138 -0
  52. data/app/controllers/spree/products_controller.rb +52 -0
  53. data/app/controllers/spree/store_controller.rb +30 -0
  54. data/app/controllers/spree/taxons_controller.rb +31 -0
  55. data/app/helpers/spree/orders_helper.rb +18 -0
  56. data/app/helpers/spree/taxon_filters_helper.rb +13 -0
  57. data/app/models/spree/frontend_configuration.rb +10 -0
  58. data/app/views/spree/address/_form.html.erb +96 -0
  59. data/app/views/spree/address/_form_hidden.html.erb +12 -0
  60. data/app/views/spree/checkout/_address.html.erb +33 -0
  61. data/app/views/spree/checkout/_confirm.html.erb +25 -0
  62. data/app/views/spree/checkout/_coupon_code.html.erb +12 -0
  63. data/app/views/spree/checkout/_delivery.html.erb +108 -0
  64. data/app/views/spree/checkout/_payment.html.erb +67 -0
  65. data/app/views/spree/checkout/_summary.html.erb +76 -0
  66. data/app/views/spree/checkout/_terms_and_conditions.en.html.erb +1 -0
  67. data/app/views/spree/checkout/edit.html.erb +32 -0
  68. data/app/views/spree/checkout/existing_payment/_gateway.html.erb +9 -0
  69. data/app/views/spree/checkout/payment/_check.html.erb +0 -0
  70. data/app/views/spree/checkout/payment/_gateway.html.erb +36 -0
  71. data/app/views/spree/content/cvv.html.erb +13 -0
  72. data/app/views/spree/home/index.html.erb +12 -0
  73. data/app/views/spree/layouts/spree_application.html.erb +36 -0
  74. data/app/views/spree/orders/_adjustment_row.html.erb +8 -0
  75. data/app/views/spree/orders/_adjustments.html.erb +24 -0
  76. data/app/views/spree/orders/_form.html.erb +29 -0
  77. data/app/views/spree/orders/_line_item.html.erb +34 -0
  78. data/app/views/spree/orders/edit.html.erb +47 -0
  79. data/app/views/spree/orders/show.html.erb +22 -0
  80. data/app/views/spree/payments/_payment.html.erb +18 -0
  81. data/app/views/spree/products/_cart_form.html.erb +65 -0
  82. data/app/views/spree/products/_image.html.erb +8 -0
  83. data/app/views/spree/products/_promotions.html.erb +19 -0
  84. data/app/views/spree/products/_properties.html.erb +15 -0
  85. data/app/views/spree/products/_taxons.html.erb +14 -0
  86. data/app/views/spree/products/_thumbnails.html.erb +21 -0
  87. data/app/views/spree/products/index.html.erb +27 -0
  88. data/app/views/spree/products/show.html.erb +51 -0
  89. data/app/views/spree/shared/_address.html.erb +38 -0
  90. data/app/views/spree/shared/_filters.html.erb +27 -0
  91. data/app/views/spree/shared/_footer.html.erb +6 -0
  92. data/app/views/spree/shared/_head.html.erb +14 -0
  93. data/app/views/spree/shared/_header.html.erb +5 -0
  94. data/app/views/spree/shared/_image.html.erb +12 -0
  95. data/app/views/spree/shared/_link_to_cart.html.erb +1 -0
  96. data/app/views/spree/shared/_locale_selector.html.erb +25 -0
  97. data/app/views/spree/shared/_login_bar_items.html.erb +1 -0
  98. data/app/views/spree/shared/_main_nav_bar.html.erb +12 -0
  99. data/app/views/spree/shared/_nav_bar.html.erb +9 -0
  100. data/app/views/spree/shared/_order_details.html.erb +146 -0
  101. data/app/views/spree/shared/_products.html.erb +51 -0
  102. data/app/views/spree/shared/_search.html.erb +11 -0
  103. data/app/views/spree/shared/_shipment_tracking.html.erb +9 -0
  104. data/app/views/spree/shared/_sidebar.html.erb +3 -0
  105. data/app/views/spree/shared/_taxonomies.html.erb +9 -0
  106. data/app/views/spree/shared/unauthorized.html.erb +0 -0
  107. data/app/views/spree/store/cart_link.html.erb +1 -0
  108. data/app/views/spree/taxons/_taxon.html.erb +4 -0
  109. data/app/views/spree/taxons/show.html.erb +20 -0
  110. data/config/initializers/assets.rb +3 -0
  111. data/config/initializers/canonical_rails.rb +16 -0
  112. data/config/routes.rb +33 -0
  113. data/lib/generators/solidus/views/override_generator.rb +49 -0
  114. data/lib/solidus_frontend.rb +3 -0
  115. data/lib/spree/frontend/engine.rb +13 -0
  116. data/lib/spree/frontend/middleware/seo_assist.rb +52 -0
  117. data/lib/spree/frontend.rb +15 -0
  118. data/lib/spree_frontend.rb +3 -0
  119. data/lib/tasks/rake_util.rb +18 -0
  120. data/lib/tasks/taxon.rake +16 -0
  121. data/script/rails +10 -0
  122. data/solidus_frontend.gemspec +35 -0
  123. data/spec/controllers/controller_helpers_spec.rb +30 -0
  124. data/spec/controllers/locale_controller_spec.rb +57 -0
  125. data/spec/controllers/spree/checkout_controller_spec.rb +539 -0
  126. data/spec/controllers/spree/checkout_controller_with_views_spec.rb +37 -0
  127. data/spec/controllers/spree/content_controller_spec.rb +9 -0
  128. data/spec/controllers/spree/current_order_tracking_spec.rb +47 -0
  129. data/spec/controllers/spree/home_controller_spec.rb +29 -0
  130. data/spec/controllers/spree/orders_controller_ability_spec.rb +93 -0
  131. data/spec/controllers/spree/orders_controller_spec.rb +225 -0
  132. data/spec/controllers/spree/orders_controller_transitions_spec.rb +33 -0
  133. data/spec/controllers/spree/products_controller_spec.rb +38 -0
  134. data/spec/controllers/spree/taxons_controller_spec.rb +14 -0
  135. data/spec/features/address_spec.rb +78 -0
  136. data/spec/features/automatic_promotion_adjustments_spec.rb +49 -0
  137. data/spec/features/caching/products_spec.rb +48 -0
  138. data/spec/features/caching/taxons_spec.rb +21 -0
  139. data/spec/features/cart_spec.rb +85 -0
  140. data/spec/features/checkout_spec.rb +690 -0
  141. data/spec/features/checkout_unshippable_spec.rb +37 -0
  142. data/spec/features/coupon_code_spec.rb +266 -0
  143. data/spec/features/currency_spec.rb +20 -0
  144. data/spec/features/free_shipping_promotions_spec.rb +60 -0
  145. data/spec/features/locale_spec.rb +27 -0
  146. data/spec/features/order_spec.rb +73 -0
  147. data/spec/features/products_spec.rb +291 -0
  148. data/spec/features/promotion_code_invalidation_spec.rb +54 -0
  149. data/spec/features/quantity_promotions_spec.rb +130 -0
  150. data/spec/features/taxons_spec.rb +158 -0
  151. data/spec/features/template_rendering_spec.rb +20 -0
  152. data/spec/fixtures/thinking-cat.jpg +0 -0
  153. data/spec/generators/solidus/views/override_generator_spec.rb +50 -0
  154. data/spec/helpers/base_helper_spec.rb +13 -0
  155. data/spec/helpers/order_helper_spec.rb +14 -0
  156. data/spec/helpers/taxon_filters_helper_spec.rb +12 -0
  157. data/spec/spec_helper.rb +106 -0
  158. data/spec/support/features/fill_in_with_force.rb +12 -0
  159. data/spec/support/shared_contexts/checkout_setup.rb +12 -0
  160. data/spec/support/shared_contexts/custom_products.rb +28 -0
  161. data/spec/support/shared_contexts/locales.rb +16 -0
  162. data/spec/views/spree/checkout/_summary_spec.rb +11 -0
  163. metadata +337 -0
@@ -0,0 +1,5 @@
1
+ /*
2
+ * This is a manifest file that includes stylesheets for spree_frontend
3
+ *= require normalize
4
+ *= require spree/frontend/screen
5
+ */
@@ -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,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ class ContentController < Spree::StoreController
5
+ respond_to :html
6
+
7
+ def cvv
8
+ render layout: false
9
+ end
10
+ end
11
+ 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>