stall 0.3.2 → 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (126) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +15 -21
  3. data/app/assets/javascripts/para/stall/inputs/variants-matrix/input.coffee +8 -1
  4. data/app/assets/javascripts/para/stall/inputs/variants-matrix/variant.coffee +9 -0
  5. data/app/assets/javascripts/stall.coffee +7 -1
  6. data/app/assets/javascripts/stall/add-to-cart-form.coffee +1 -4
  7. data/app/assets/javascripts/stall/products-filters.coffee +29 -0
  8. data/app/assets/stylesheets/para/stall.sass +5 -0
  9. data/app/assets/stylesheets/stall.sass +0 -0
  10. data/app/controllers/stall/checkout/steps_controller.rb +6 -5
  11. data/app/controllers/stall/checkout_base_controller.rb +14 -0
  12. data/app/controllers/stall/checkouts_controller.rb +7 -4
  13. data/app/controllers/stall/curated_product_lists_controller.rb +10 -0
  14. data/app/controllers/stall/line_items_controller.rb +1 -5
  15. data/app/controllers/stall/manufacturers_controller.rb +12 -0
  16. data/app/controllers/stall/omniauth_callbacks_controller.rb +49 -0
  17. data/app/controllers/stall/product_categories_controller.rb +13 -0
  18. data/app/controllers/stall/products_breadcrumbs.rb +16 -0
  19. data/app/controllers/stall/products_controller.rb +20 -0
  20. data/app/controllers/stall/products_search.rb +11 -0
  21. data/app/helpers/stall/customers_helper.rb +0 -10
  22. data/app/helpers/stall/omniauth_helper.rb +7 -0
  23. data/app/helpers/stall/prices_helper.rb +12 -0
  24. data/app/helpers/stall/products_filters_helper.rb +34 -0
  25. data/app/mailers/stall/customer_mailer.rb +4 -3
  26. data/app/models/curated_list_product.rb +3 -0
  27. data/app/models/curated_product_list.rb +3 -0
  28. data/app/models/image.rb +3 -0
  29. data/app/models/product_suggestion.rb +3 -0
  30. data/app/models/stall/models/curated_list_product.rb +15 -0
  31. data/app/models/stall/models/curated_product_list.rb +22 -0
  32. data/app/models/stall/models/customer.rb +5 -8
  33. data/app/models/stall/models/image.rb +21 -0
  34. data/app/models/stall/models/manufacturer.rb +4 -0
  35. data/app/models/stall/models/product.rb +30 -7
  36. data/app/models/stall/models/product_category.rb +5 -2
  37. data/app/models/stall/models/product_list.rb +1 -1
  38. data/app/models/stall/models/product_suggestion.rb +14 -0
  39. data/app/models/stall/models/shipment.rb +0 -2
  40. data/app/models/stall/models/user.rb +18 -0
  41. data/app/models/stall/models/user_omniauth_account.rb +13 -0
  42. data/app/models/stall/models/variant.rb +11 -11
  43. data/app/models/user.rb +3 -0
  44. data/app/models/user_omniauth_account.rb +3 -0
  45. data/app/services/stall/add_to_cart_service.rb +19 -4
  46. data/app/services/stall/available_stocks_service.rb +11 -0
  47. data/app/services/stall/cart_credit_note_creation_service.rb +4 -0
  48. data/app/services/stall/cart_payment_validation_service.rb +5 -3
  49. data/app/services/stall/credit_usage_service.rb +8 -2
  50. data/app/services/stall/omniauth_user_authentication_service.rb +48 -0
  51. data/app/services/stall/product_list_staleness_handling_service.rb +6 -3
  52. data/app/services/stall/products_search_service.rb +23 -0
  53. data/app/services/stall/shipping_notification_service.rb +1 -1
  54. data/app/views/admin/carts/_filters.html.haml +10 -4
  55. data/app/views/admin/carts/_form.html.haml +9 -9
  56. data/app/views/admin/manufacturers/_form.html.haml +7 -0
  57. data/app/views/admin/manufacturers/_table.html.haml +8 -0
  58. data/app/views/admin/product_categories/_form.html.haml +7 -0
  59. data/app/views/admin/products/_form.html.haml +23 -0
  60. data/app/views/admin/products/_table.html.haml +4 -2
  61. data/app/views/checkout/steps/_informations.html.haml +2 -2
  62. data/app/views/para/admin/resources/_variant_row.html.haml +9 -1
  63. data/app/views/para/admin/resources/_variant_row_header.html.haml +14 -0
  64. data/app/views/para/stall/inputs/_variant_select.html.haml +3 -3
  65. data/app/views/para/stall/inputs/_variants_matrix.html.haml +7 -16
  66. data/app/views/para/stall/inputs/shipping_notes/new.html.haml +22 -0
  67. data/app/views/para/stall/inputs/shipping_notes/sent.html.haml +11 -0
  68. data/app/views/stall/carts/_cart.html.haml +1 -1
  69. data/app/views/stall/credit_note_adjustments/_form.html.haml +1 -1
  70. data/app/views/stall/curated_product_lists/show.html.haml +8 -0
  71. data/app/views/stall/customers/_fields.html.haml +17 -5
  72. data/app/views/stall/customers/_sign_in.html.haml +22 -10
  73. data/app/views/stall/line_items/_form.html.haml +2 -3
  74. data/app/views/stall/manufacturers/show.html.haml +8 -0
  75. data/app/views/stall/product_categories/show.html.haml +8 -0
  76. data/app/views/stall/products/_filters.html.haml +4 -0
  77. data/app/views/stall/products/_list.html.haml +7 -0
  78. data/app/views/stall/products/_product.html.haml +4 -0
  79. data/app/views/stall/products/_product_details.html.haml +13 -0
  80. data/app/views/stall/products/filters/_category_filter.html.haml +2 -0
  81. data/app/views/stall/products/filters/_manufacturer_filter.html.haml +2 -0
  82. data/app/views/stall/products/filters/_price_filter.html.haml +2 -0
  83. data/app/views/stall/products/filters/_property_filter.html.haml +2 -0
  84. data/app/views/stall/products/index.html.haml +8 -0
  85. data/app/views/stall/products/show.html.haml +26 -0
  86. data/config/locales/stall.fr.yml +97 -11
  87. data/db/migrate/20170221094450_add_slug_to_stall_manufacturers.rb +5 -0
  88. data/db/migrate/20170303122616_create_stall_product_suggestions.rb +13 -0
  89. data/db/migrate/20170303151939_add_position_to_stall_manufacturers.rb +5 -0
  90. data/db/migrate/20170308162740_create_stall_curated_product_lists.rb +10 -0
  91. data/db/migrate/20170308163532_create_stall_curated_list_products.rb +14 -0
  92. data/db/migrate/20170317103740_create_stall_users.rb +28 -0
  93. data/db/migrate/20170317104332_create_stall_user_omniauth_accounts.rb +14 -0
  94. data/db/migrate/20170320133513_fix_curated_product_list_bad_foreign_key.rb +6 -0
  95. data/db/migrate/20170321104203_create_stall_images.rb +11 -0
  96. data/db/migrate/20170321112248_remove_image_attachment_to_stall_products.rb +5 -0
  97. data/db/migrate/20170411134756_add_stock_to_stall_variants.rb +5 -0
  98. data/lib/ext/ransack.rb +13 -0
  99. data/lib/generators/stall/install/templates/initializer.rb +50 -15
  100. data/lib/generators/stall/service/service_generator.rb +0 -4
  101. data/lib/generators/stall/view/view_generator.rb +10 -8
  102. data/lib/para/stall/inputs/variant_select_input.rb +11 -1
  103. data/lib/para/stall/inputs/variants_matrix_input.rb +12 -6
  104. data/lib/stall.rb +14 -0
  105. data/lib/stall/addressable.rb +2 -2
  106. data/lib/stall/addresses/copy_source_to_target.rb +7 -3
  107. data/lib/stall/addresses/prefill_target_from_source.rb +4 -2
  108. data/lib/stall/cart_helper.rb +3 -3
  109. data/lib/stall/carts_cleaner.rb +2 -2
  110. data/lib/stall/checkout/informations_checkout_step.rb +2 -2
  111. data/lib/stall/config.rb +29 -9
  112. data/lib/stall/engine.rb +28 -13
  113. data/lib/stall/omniauth_provider.rb +41 -0
  114. data/lib/stall/payable.rb +3 -1
  115. data/lib/stall/product_filters.rb +12 -0
  116. data/lib/stall/product_filters/base_filter.rb +43 -0
  117. data/lib/stall/product_filters/builder.rb +59 -0
  118. data/lib/stall/product_filters/category_filter.rb +28 -0
  119. data/lib/stall/product_filters/manufacturer_filter.rb +19 -0
  120. data/lib/stall/product_filters/price_filter.rb +39 -0
  121. data/lib/stall/product_filters/property_filter.rb +38 -0
  122. data/lib/stall/routes.rb +40 -0
  123. data/lib/stall/shipping/calculator.rb +3 -1
  124. data/lib/stall/version.rb +1 -1
  125. metadata +158 -7
  126. data/app/assets/stylesheets/stall/carts.css +0 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: af3519db9164c6f4fd61e1e56f019ef90c3e6a5d
4
- data.tar.gz: 9fad0f1035c6510b67c80865b6284f844e4686ca
3
+ metadata.gz: d3c1c5916425f5f689fed5cb2167bc48e6046ea6
4
+ data.tar.gz: 31301c3457145a56633b53d3b44c12a49ebd03db
5
5
  SHA512:
6
- metadata.gz: 31367405801aa97eca7302b4286ee0d39c46540ba389eff0c43a3a9461123217c0414afa82249d073b3ebef0f143a6f1fbc151a5e63235c0773681eb8e873861
7
- data.tar.gz: 8114b8156abd5b6cd53d861d6c952347f01f09c49040c30a67c0c3224fd7c3297e2fa09248ac75d46ef4bacc2db9c14759d01420d84c865ea5971c496afe5df2
6
+ metadata.gz: 125ee1c9e7804ebd54017e364dde2e578a729dd18e9b0283f6d3b1ee71b34e861177febbf509b7387c430b54fae86ed093911f16ab150554ec84148d126cd332
7
+ data.tar.gz: 2d1e7e7b43e0bc1b1f22710c00f652231529e8e2205613acdf22b0acbff30c371f95fd88e436c093451d35a5186941eed0d189458044e155f133e49381eed391
data/README.md CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  [![Build Status](https://api.travis-ci.org/rails-stall/stall.svg?branch=master)](http://travis-ci.org/rails-stall/stall)
4
4
  [![Test Coverage](https://codeclimate.com/github/rails-stall/stall/badges/coverage.svg)](https://codeclimate.com/github/rails-stall/stall/coverage)
5
+ [![Code Climate](https://codeclimate.com/github/rails-stall/stall/badges/gpa.svg)](https://codeclimate.com/github/rails-stall/stall)
5
6
 
6
7
  Stall is a flexible e-commerce framework for Rails with some specific concerns
7
8
  in mind :
@@ -63,33 +64,26 @@ Here are the mandatory ones :
63
64
 
64
65
  ### 2. Configuring shop users
65
66
 
66
- The default cart behavior admits that you have a user model, named `User` and
67
- that you are using [Devise](https://github.com/plataformatec/devise)
68
- compatible helpers in your controllers (`current_user`).
67
+ Stall uses [Devise](https://github.com/plataformatec/devise) to authenticate
68
+ shop customers through a `User` model.
69
69
 
70
- You can configure those settings by setting the following initializer config
71
- parameters :
70
+ To add behavior to this model, you can override the model like any other Stall
71
+ model by using the model generator :
72
72
 
73
- - `default_user_model_name`
74
- - `default_user_helper_method`
75
-
76
- Also, the user should include an inverse `:customer` relation targeting the
77
- Stall's customer model like the following :
78
-
79
- ```ruby
80
- has_one :customer, as: :user
73
+ ```bash
74
+ rails generate stall:model user
81
75
  ```
82
76
 
83
- #### Remove user management
77
+ #### Omniauth
78
+
79
+ You can easily make customers sign in and up with omniauth. Stall comes with
80
+ Facebook and Google OAuth2 integrations, but other other integrations can be
81
+ easily added.
84
82
 
85
- If you don't want to associate a user account to your customers, you'll need
86
- to set those variables to `nil` and remove the user creation form in the
87
- informations checkout step (See
88
- [Configuring the checkout flow](#4-configuring-the-checkout-flow) and
89
- [Customizing views](#5-customizing-views) for more informations on how to
90
- do this).
83
+ To use this feature, just uncomment the `config.omniauth_provider` lines in
84
+ the initializer.
91
85
 
92
- Note that this is untested for now, but should be doable quite easily.
86
+ For more information, please see the initializer comments.
93
87
 
94
88
  ### 3. Making a model sellable
95
89
 
@@ -3,6 +3,8 @@ class VariantsMatrix.Input extends Vertebra.View
3
3
  @$variantsContainer = @$('[data-variants-matrix-variants-container]')
4
4
  @$variantsTableHeader = @$('[data-variants-matrix-variants-table-header]')
5
5
 
6
+ @allowEmptyVariant = @$el.is('[data-allow-empty-variant]')
7
+
6
8
  @propertiesSelect = new VariantsMatrix.PropertiesSelect(el: @$('[data-variants-matrix-properties-select]'))
7
9
  @listenTo(@propertiesSelect, 'change', @onPropertySelectChanged)
8
10
 
@@ -16,6 +18,7 @@ class VariantsMatrix.Input extends Vertebra.View
16
18
  @variants = for row in @$('[data-variants-matrix-variant-row]').get()
17
19
  combination = @findCombinationForRow(row, existingCombinations)
18
20
  variant = new VariantsMatrix.Variant(el: row, combination: combination, input: this)
21
+ @listenTo(variant, 'applytoall', @onVariantApplyToAll)
19
22
  @listenTo(variant, 'destroy', @onVariantDestroyed)
20
23
 
21
24
  variant
@@ -83,6 +86,7 @@ class VariantsMatrix.Input extends Vertebra.View
83
86
  variant = new VariantsMatrix.Variant(combination: combination, input: this)
84
87
  variant.renderTo(@$variantsContainer)
85
88
  @listenTo(variant, 'destroy', @onVariantDestroyed)
89
+ @listenTo(variant, 'applytoall', @onVariantApplyToAll)
86
90
  @variants.push(variant)
87
91
 
88
92
  variant
@@ -122,7 +126,10 @@ class VariantsMatrix.Input extends Vertebra.View
122
126
  # one for next iterations to use it
123
127
  combinations = new_combinations
124
128
 
125
- combinations
129
+ if !combinations.length && @allowEmptyVariant then [{}] else combinations
130
+
131
+ onVariantApplyToAll: (variant) =>
132
+ v.copyInputsFrom(variant) for v in @variants when v.cid isnt variant.cid
126
133
 
127
134
  # Cleanup destroyed variants
128
135
  #
@@ -1,6 +1,7 @@
1
1
  class VariantsMatrix.Variant extends Vertebra.View
2
2
  events:
3
3
  'change [data-variants-matrix-variant-enabled]': 'onEnabledStateChanged'
4
+ 'click [data-variants-matrix-apply-to-all]': 'onApplyToAllClicked'
4
5
 
5
6
  initialize: (options = {}) ->
6
7
  @combination = options.combination
@@ -57,3 +58,11 @@ class VariantsMatrix.Variant extends Vertebra.View
57
58
 
58
59
  setDestroyed: (state) ->
59
60
  @$el.find('[data-variant-remove]').val(if state then 'true' else 'false')
61
+
62
+ onApplyToAllClicked: ->
63
+ @trigger('applytoall', this)
64
+
65
+ copyInputsFrom: (otherVariant) ->
66
+ @$('input:visible').each (i, el) ->
67
+ otherValue = otherVariant.$('input:visible').eq(i).val()
68
+ $(el).val(otherValue)
@@ -1,11 +1,17 @@
1
1
  #= require vertebra
2
2
  #= require cocoon
3
+ #
3
4
  #= require_self
5
+ #
4
6
  #= require stall/add-to-cart-form
5
7
  #= require stall/cart-form
6
8
  #= require stall/addresses-fields
7
9
  #= require stall/remote-sign-in-form
8
-
10
+ #= require stall/products-filters
11
+ #
12
+ #= require para/stall/inputs/variant-select
13
+ #= require para/lib/turbolinks-forms
14
+ #
9
15
 
10
16
  @Stall =
11
17
  onDomReady: (callback) ->
@@ -25,9 +25,7 @@ class Stall.AddToCartForm extends Vertebra.View
25
25
  @errorMessages = @$el.data('error-messages')
26
26
 
27
27
  sendRequest: ->
28
- unless (v = @validate(submit: true)) and (e = !@errors.length)
29
- console.log 'sendRequest', v, e
30
- return false
28
+ return false unless (v = @validate(submit: true)) and (e = !@errors.length)
31
29
  @setLoading(true)
32
30
  true
33
31
 
@@ -85,7 +83,6 @@ class Stall.AddToCartForm extends Vertebra.View
85
83
  @$button.tooltip('disable') if @$button.data('bs.tooltip')
86
84
  @$button.prop('disabled', false)
87
85
 
88
-
89
86
  setLoading: (loading) ->
90
87
  state = if loading then 'loading' else 'reset'
91
88
  @$button.button(state)
@@ -0,0 +1,29 @@
1
+ class Stall.ProductsFilters extends Vertebra.View
2
+ events:
3
+ 'change [data-filter-submission="change"]': 'filterChanged'
4
+ 'slideStop [data-filter-submission="slide"]': 'filterChanged'
5
+ 'submit': 'setSubmitted'
6
+
7
+ filterChanged: (e) ->
8
+ @submit()
9
+
10
+ submit: ->
11
+ setTimeout((=> @$el.submit()), 0)
12
+
13
+ setSubmitted: (e) ->
14
+ return e.preventDefault() if @submitted
15
+ @submitted = true
16
+
17
+ $overlay = $('<div/>', class: 'overlay').css(
18
+ position: 'absolute',
19
+ width: '100%',
20
+ height: '100%',
21
+ background: '#fafafa',
22
+ zIndex: '100',
23
+ opacity: '0.4'
24
+ )
25
+
26
+ @$el.prepend($overlay)
27
+
28
+ Stall.onDomReady ->
29
+ $('[data-products-filters]').each (i, el) -> new Stall.ProductsFilters(el: el)
@@ -17,6 +17,11 @@
17
17
  display: block
18
18
  padding: 5px
19
19
 
20
+ .variants-matrix-properties-list
21
+ .list-group-item
22
+ padding: 10px 0
23
+ border: none
24
+
20
25
  .form-group.variants_matrix
21
26
  padding-right: 0
22
27
 
File without changes
@@ -1,8 +1,6 @@
1
1
  module Stall
2
2
  module Checkout
3
- class StepsController < Stall::ApplicationController
4
- include Stall::CheckoutHelper
5
-
3
+ class StepsController < Stall::CheckoutBaseController
6
4
  skip_before_action :verify_authenticity_token, on: :foreign_update
7
5
  before_action :load_cart
8
6
  before_action :load_step
@@ -43,6 +41,9 @@ module Stall
43
41
  def load_cart
44
42
  @cart = current_cart
45
43
 
44
+ # If the cart is not checkoutable, look for a potential cart could have
45
+ # just been paid and that would be archived it a specific cookie, or
46
+ # exit from the checkout
46
47
  unless @cart.checkoutable?
47
48
  if archived_paid_cart?
48
49
  @cart = archived_paid_cart
@@ -66,8 +67,8 @@ module Stall
66
67
  step.inject(:cookies, cookies)
67
68
  step.inject(:request, request)
68
69
  step.inject(:flash, flash)
69
- step.inject(:stall_user_signed_in?, stall_user_signed_in?)
70
- step.inject(:current_stall_user, current_stall_user)
70
+ step.inject(:user_signed_in?, user_signed_in?)
71
+ step.inject(:current_user, current_user)
71
72
 
72
73
  if Stall.config.steps_initialization
73
74
  instance_exec(step, &Stall.config.steps_initialization)
@@ -0,0 +1,14 @@
1
+ module Stall
2
+ class CheckoutBaseController < Stall::ApplicationController
3
+ include CheckoutHelper
4
+
5
+ # Use specific checkout layout if needed or default to parent one
6
+ #
7
+ def set_stall_layout
8
+ return false if request.xhr?
9
+ return Stall.config.checkout_layout if Stall.config.checkout_layout
10
+
11
+ super
12
+ end
13
+ end
14
+ end
@@ -1,12 +1,10 @@
1
1
  module Stall
2
- class CheckoutsController < Stall::ApplicationController
3
- include CheckoutHelper
4
-
2
+ class CheckoutsController < Stall::CheckoutBaseController
5
3
  before_action :load_cart
6
4
 
7
5
  def show
8
6
  @cart.reset_state!
9
- Stall.config.service_for(:cart_update).new(@cart).refresh_associated_services!
7
+ refresh_cart!
10
8
  redirect_to step_path
11
9
  end
12
10
 
@@ -15,5 +13,10 @@ module Stall
15
13
  def load_cart
16
14
  @cart = current_cart
17
15
  end
16
+
17
+ def refresh_cart!
18
+ service = Stall.config.service_for(:cart_update).new(@cart)
19
+ service.refresh_associated_services!
20
+ end
18
21
  end
19
22
  end
@@ -0,0 +1,10 @@
1
+ module Stall
2
+ class CuratedProductListsController < Stall::ApplicationController
3
+ include ProductsSearch
4
+
5
+ def show
6
+ @curated_product_list = CuratedProductList.friendly.find(params[:id])
7
+ search_products_among(@curated_product_list.products)
8
+ end
9
+ end
10
+ end
@@ -1,7 +1,7 @@
1
1
  module Stall
2
2
  class LineItemsController < Stall::ApplicationController
3
3
  def create
4
- service = Stall.config.service_for(:add_to_cart).new(cart, line_item_params)
4
+ service = Stall.config.service_for(:add_to_cart).new(cart, params)
5
5
 
6
6
  if service.call
7
7
  @quantity = params[:line_item][:quantity].to_i
@@ -16,10 +16,6 @@ module Stall
16
16
 
17
17
  private
18
18
 
19
- def line_item_params
20
- params.require(:line_item).permit(:sellable_type, :sellable_id, :quantity)
21
- end
22
-
23
19
  def cart
24
20
  @cart ||= ProductList.find_by_token(params[:cart_id]) || current_cart
25
21
  end
@@ -0,0 +1,12 @@
1
+ module Stall
2
+ class ManufacturersController < Stall::ApplicationController
3
+ include ProductsSearch
4
+
5
+ def show
6
+ @manufacturer = Manufacturer.friendly.find(params[:id])
7
+ search_products_among(@manufacturer.products)
8
+
9
+ add_breadcrumb(@manufacturer)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,49 @@
1
+ module Stall
2
+ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
3
+ include Stall::OmniauthHelper
4
+
5
+ # Pre-authorize request to store the redirect path, allowing users to get
6
+ # back to the checkout wether the authentication is successful or not.
7
+ #
8
+ def redirect
9
+ session['omniauth.after_sign_in_redirect_path'] = params[:_redirect_to] if params[:_redirect_to]
10
+ redirect_to user_omniauth_authorize_path_for(params[:provider])
11
+ end
12
+
13
+ def facebook
14
+ authenticate_user_from_oauth_callback!
15
+ end
16
+
17
+ def google_oauth2
18
+ authenticate_user_from_oauth_callback!
19
+ end
20
+
21
+ private
22
+
23
+ def authenticate_user_from_oauth_callback!
24
+ user = Stall.config.service_for(:omniauth_user_authentication).new(auth.info.email, auth).call
25
+ sign_in_and_redirect(user, event: :authentication)
26
+ set_flash_message(:notice, :success, kind: auth.provider.humanize) if is_navigational_format?
27
+ end
28
+
29
+ def auth
30
+ @auth ||= request.env['omniauth.auth']
31
+ end
32
+
33
+ def after_omniauth_failure_path_for(scope)
34
+ redirect_path || new_session_path(scope)
35
+ end
36
+
37
+ def after_sign_in_path_for(scope)
38
+ redirect_path || stored_location_for(scope) || root_path
39
+ end
40
+
41
+ def after_sign_up_path_for(scope)
42
+ redirect_path || stored_location_for(scope) || root_path
43
+ end
44
+
45
+ def redirect_path
46
+ session.delete('omniauth.after_sign_in_redirect_path')
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,13 @@
1
+ module Stall
2
+ class ProductCategoriesController < Stall::ApplicationController
3
+ include ProductsSearch
4
+ include ProductsBreadcrumbs
5
+
6
+ def show
7
+ @product_category = ProductCategory.friendly.find(params[:id])
8
+ search_products_among(@product_category.all_child_products)
9
+
10
+ add_product_category_breadcrumbs(@product_category)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,16 @@
1
+ module Stall
2
+ module ProductsBreadcrumbs
3
+ private
4
+
5
+ def add_product_breadcrumbs
6
+ add_product_category_breadcrumbs(@product.product_category)
7
+ add_breadcrumb(@product)
8
+ end
9
+
10
+ def add_product_category_breadcrumbs(product_category)
11
+ product_category.self_and_ancestors.reverse.each do |category|
12
+ add_breadcrumb category
13
+ end if product_category
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,20 @@
1
+ module Stall
2
+ class ProductsController < Stall::ApplicationController
3
+ include ProductsSearch
4
+ include ProductsBreadcrumbs
5
+
6
+ def index
7
+ search_products_among(Product.all)
8
+
9
+ add_breadcrumb :products
10
+ end
11
+
12
+ def show
13
+ @product = Product.friendly.includes(
14
+ variants: [variant_property_values: [property_value: :property]]
15
+ ).find(params[:id])
16
+
17
+ add_product_breadcrumbs
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,11 @@
1
+ module Stall
2
+ module ProductsSearch
3
+ private
4
+
5
+ def search_products_among(products)
6
+ @filterable_products = products
7
+ @search = Stall.config.service_for(:products_search).new(@filterable_products, params)
8
+ @products = @search.records.page(params[:page])
9
+ end
10
+ end
11
+ end
@@ -1,15 +1,5 @@
1
1
  module Stall
2
2
  module CustomersHelper
3
- def stall_user_signed_in?
4
- !!current_stall_user
5
- end
6
-
7
- def current_stall_user
8
- if (method = Stall.config.default_user_helper_method) && respond_to?(method, true)
9
- send(Stall.config.default_user_helper_method)
10
- end
11
- end
12
-
13
3
  # Copy e-mail error messages from user to customer, allowing them to be
14
4
  # displayed in customer e-mail input to the visitor
15
5
  #