stall 0.3.3 → 0.3.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/javascripts/para/stall/inputs/variant-select.coffee +4 -3
- data/app/assets/javascripts/stall.coffee +3 -1
- data/app/assets/javascripts/stall/add-product-to-wish-list-button.coffee +99 -0
- data/app/assets/javascripts/stall/add-to-wish-list-button.coffee +17 -0
- data/app/assets/javascripts/stall/product-list-form.coffee +31 -0
- data/app/controllers/stall/cart_line_items_controller.rb +21 -0
- data/app/controllers/stall/curated_product_lists_controller.rb +6 -0
- data/app/controllers/stall/line_items_controller.rb +14 -7
- data/app/controllers/stall/products_breadcrumbs.rb +8 -1
- data/app/controllers/stall/products_controller.rb +12 -0
- data/app/controllers/stall/wish_list_line_items_controller.rb +52 -0
- data/app/controllers/stall/wish_lists_controller.rb +7 -0
- data/app/helpers/stall/add_to_cart_helper.rb +3 -2
- data/app/helpers/stall/add_to_wish_list_helper.rb +30 -0
- data/app/helpers/stall/products_helper.rb +13 -0
- data/app/models/stall/models/cart.rb +0 -6
- data/app/models/stall/models/customer.rb +9 -0
- data/app/models/stall/models/line_item.rb +13 -0
- data/app/models/stall/models/product.rb +1 -1
- data/app/models/stall/models/product_list.rb +4 -0
- data/app/models/stall/models/variant.rb +4 -0
- data/app/models/stall/models/wish_list.rb +18 -0
- data/app/models/wish_list.rb +3 -0
- data/app/services/stall/add_to_cart_service.rb +4 -47
- data/app/services/stall/add_to_product_list_service.rb +63 -0
- data/app/services/stall/add_to_wish_list_service.rb +17 -0
- data/app/services/stall/available_stocks_service.rb +1 -1
- data/app/services/stall/shipping_fee_calculator_service.rb +22 -9
- data/app/views/admin/products/_form.html.haml +5 -0
- data/app/views/checkout/steps/_informations.html.haml +1 -1
- data/app/views/stall/addresses/_fields.html.haml +4 -4
- data/app/views/stall/{line_items → cart_line_items}/_add_error.html.haml +0 -0
- data/app/views/stall/{line_items → cart_line_items}/_added.html.haml +2 -2
- data/app/views/stall/{line_items → cart_line_items}/_form.html.haml +1 -1
- data/app/views/stall/carts/_widget.html.haml +1 -1
- data/app/views/stall/carts/show.html.haml +4 -4
- data/app/views/stall/curated_product_lists/show.html.haml +1 -1
- data/app/views/stall/customers/_fields.html.haml +1 -1
- data/app/views/stall/customers/_sign_in.html.haml +2 -2
- data/app/views/stall/products/_list.html.haml +2 -0
- data/app/views/stall/products/_product.html.haml +2 -1
- data/app/views/stall/wish_list_line_items/_add_error.html.haml +17 -0
- data/app/views/stall/wish_list_line_items/_added.html.haml +19 -0
- data/app/views/stall/wish_list_line_items/_button.html.haml +3 -0
- data/app/views/stall/wish_list_line_items/_form.html.haml +12 -0
- data/app/views/stall/wish_lists/show.html.haml +21 -0
- data/config/locales/stall.fr.yml +26 -0
- data/db/migrate/20170425085606_add_weight_to_stall_products_and_variants.rb +6 -0
- data/db/migrate/20170426163450_add_vat_rate_to_stall_products.rb +5 -0
- data/db/migrate/20170522062334_change_variants_weight_default_to_nil.rb +11 -0
- data/lib/generators/stall/install/templates/initializer.rb +18 -0
- data/lib/stall.rb +1 -0
- data/lib/stall/addressable.rb +35 -4
- data/lib/stall/addresses/copy_source_to_target.rb +14 -10
- data/lib/stall/addresses/prefill_target_from_source.rb +10 -6
- data/lib/stall/config.rb +4 -0
- data/lib/stall/engine.rb +1 -0
- data/lib/stall/routes.rb +42 -19
- data/lib/stall/sellable.rb +1 -1
- data/lib/stall/shipping/calculator.rb +1 -1
- data/lib/stall/shipping/country_weight_table_calculator.rb +3 -2
- data/lib/stall/version.rb +1 -1
- data/lib/stall/wish_list_helper.rb +93 -0
- metadata +26 -6
- data/app/assets/javascripts/stall/cart-form.coffee +0 -28
@@ -0,0 +1,17 @@
|
|
1
|
+
.modal.danger.fade{ role: 'dialog', tabindex: '-1', data: { :'line-item' => @line_item.as_json(only: [:name, :quantity, :eot_price, :price, :vat_rate]) } }
|
2
|
+
.modal-dialog
|
3
|
+
.modal-content
|
4
|
+
.modal-header
|
5
|
+
%button.close{ type: 'button', :'aria-label' => 'Close', data: { dismiss: 'modal' } }
|
6
|
+
%span{ :'aria-hidden' => 'true' }
|
7
|
+
×
|
8
|
+
%h4.modal-title
|
9
|
+
= t('stall.line_items.add_error.title')
|
10
|
+
|
11
|
+
.modal-body
|
12
|
+
%p.text-danger
|
13
|
+
= t('stall.line_items.add_error.description')
|
14
|
+
|
15
|
+
.modal-footer
|
16
|
+
%button.btn.btn-default{ type: 'button', data: { dismiss: 'modal' } }
|
17
|
+
= t('stall.shared.close')
|
@@ -0,0 +1,19 @@
|
|
1
|
+
.modal.fade{ role: 'dialog', tabindex: '-1', data: { :'wish-list' => { token: @product_list.token, :'total-quantity' => @product_list.total_quantity } } }
|
2
|
+
.modal-dialog
|
3
|
+
.modal-content
|
4
|
+
.modal-header
|
5
|
+
%button.close{ type: 'button', :'aria-label' => 'Close', data: { dismiss: 'modal' } }
|
6
|
+
%span{ :'aria-hidden' => 'true' }
|
7
|
+
×
|
8
|
+
%h4.modal-title
|
9
|
+
= t('stall.wish_list_line_items.added.title')
|
10
|
+
|
11
|
+
.modal-body
|
12
|
+
= @line_item.name
|
13
|
+
|
14
|
+
.modal-footer
|
15
|
+
%button.btn.btn-default{ type: 'button', data: { dismiss: 'modal' } }
|
16
|
+
= t('stall.wish_list_line_items.added.continue_shopping')
|
17
|
+
|
18
|
+
= link_to wish_list_path(@product_list), class: 'btn btn-primary', rel: 'nofollow' do
|
19
|
+
= t('stall.wish_lists.actions.view_wish_list')
|
@@ -0,0 +1,3 @@
|
|
1
|
+
%button.btn.btn-default.add-to-wish-list-btn{ type: 'button', data: { :'add-to-wish-list' => true, title: title, url: url, included: included, :'product-id' => product.id, :'variant-id' => variant.try(:id), :'popover-content' => popover_content } }
|
2
|
+
= fa_icon (included ? 'heart' : 'heart-o'), data: { :'wish-list-icon' => true }
|
3
|
+
= fa_icon 'spinner spin', class: 'hidden', data: { :'wish-list-loading-spinner' => true }
|
@@ -0,0 +1,12 @@
|
|
1
|
+
= simple_form_for line_item, as: :line_item, url: wish_list_line_items_path(wish_list), remote: true, data: { :'add-to-wish-list-form' => true, :'error-messages' => { choose: t('stall.line_items.errors.choose'), quantity: t('stall.line_items.errors.quantity') } } do |form|
|
2
|
+
= form.hidden_field :sellable_type, value: 'Variant'
|
3
|
+
= form.input_field :sellable, as: :variant_select, product: product
|
4
|
+
= form.hidden_field :quantity, value: 1
|
5
|
+
|
6
|
+
%button.btn.btn-primary{ type: 'submit', autocomplete: 'off', data: { :'loading-text' => t('stall.shared.sending') } }
|
7
|
+
= fa_icon 'heart-o'
|
8
|
+
= t('stall.wish_list_line_items.form.add')
|
9
|
+
|
10
|
+
%button.btn.btn-danger{ type: 'button', data: { :'cancel-button' => true } }
|
11
|
+
= fa_icon 'times'
|
12
|
+
= t('stall.shared.cancel')
|
@@ -0,0 +1,21 @@
|
|
1
|
+
.wish-list-recap{ data: { :'product-list-recap' => true } }
|
2
|
+
= simple_form_for @wish_list, url: wish_list_path(@wish_list), as: :wish_list, remote: true, data: { :'product-list-form' => true } do |form|
|
3
|
+
%table.table.table-striped
|
4
|
+
%thead
|
5
|
+
%tr
|
6
|
+
%th= LineItem.human_attribute_name(:name)
|
7
|
+
%th= LineItem.human_attribute_name(:unit_price)
|
8
|
+
%th
|
9
|
+
|
10
|
+
%tbody
|
11
|
+
= form.fields_for :line_items do |line_item_fields|
|
12
|
+
%tr.line-item-row{ data: { :'line-item-id' => line_item_fields.object.id } }
|
13
|
+
%td= line_item_fields.object.name
|
14
|
+
%td= line_item_fields.object.unit_price
|
15
|
+
%td= link_to_remove_association '×'.html_safe, line_item_fields, wrapper_class: 'line-item-row'
|
16
|
+
|
17
|
+
.form-actions
|
18
|
+
%button.btn.btn-default{ type: 'submit', data: { :'product-list-update-button' => true } }
|
19
|
+
= t('stall.wish_lists.recap.update')
|
20
|
+
|
21
|
+
|
data/config/locales/stall.fr.yml
CHANGED
@@ -5,6 +5,7 @@ fr:
|
|
5
5
|
filters:
|
6
6
|
paid_after: Payé après le
|
7
7
|
paid_before: Payé avant le
|
8
|
+
|
8
9
|
variants_matrix:
|
9
10
|
enabled: "Publier ?"
|
10
11
|
price: "Prix"
|
@@ -31,6 +32,10 @@ fr:
|
|
31
32
|
sent: "Notification envoyée !"
|
32
33
|
sent_description: "Le client a bien été notifié de l'expédition de sa commande. "
|
33
34
|
|
35
|
+
products:
|
36
|
+
weight_hint: "Indiquez le poids du produit <b>en grammes</b>"
|
37
|
+
vat_rate_hint: "Taux de TVA en %. <b>%{rate} si vide.</b>"
|
38
|
+
|
34
39
|
forms:
|
35
40
|
tabs:
|
36
41
|
cart:
|
@@ -45,15 +50,18 @@ fr:
|
|
45
50
|
images: "Images"
|
46
51
|
descriptions: "Descriptions"
|
47
52
|
variants: "Déclinaisons"
|
53
|
+
shipping: "Livraison"
|
48
54
|
|
49
55
|
components:
|
50
56
|
section:
|
51
57
|
products: "Catalogue"
|
58
|
+
selling: "Vente"
|
52
59
|
component:
|
53
60
|
products: "Produits"
|
54
61
|
product_categories: "Catégories de produits"
|
55
62
|
properties: "Propriétés de produit"
|
56
63
|
manufacturers: "Fabricants"
|
64
|
+
carts: "Commandes / Paniers"
|
57
65
|
|
58
66
|
stall:
|
59
67
|
shared:
|
@@ -99,6 +107,10 @@ fr:
|
|
99
107
|
validate: "Passer la commande"
|
100
108
|
paid_at: "Payée le %{at}"
|
101
109
|
|
110
|
+
wish_lists:
|
111
|
+
actions:
|
112
|
+
view_wish_list: "Voir ma liste"
|
113
|
+
|
102
114
|
line_items:
|
103
115
|
form:
|
104
116
|
add_to_cart: "Ajouter au panier"
|
@@ -112,6 +124,14 @@ fr:
|
|
112
124
|
choose: "Merci de choisir un produit afin de l'ajouter au panier"
|
113
125
|
quantity: "Merci de choisir une quantité à ajouter au panier"
|
114
126
|
|
127
|
+
wish_list_line_items:
|
128
|
+
form:
|
129
|
+
add: "Ajouter à ma Wish list"
|
130
|
+
remove: "Retirer de ma Wish list"
|
131
|
+
added:
|
132
|
+
title: "Votre produit a bien été ajouté à votre Wish list"
|
133
|
+
continue_shopping: "Continuer ma visite"
|
134
|
+
|
115
135
|
checkout:
|
116
136
|
shared:
|
117
137
|
not_checkoutable: "Le panier a expiré, celui-ci a probablement déjà été payé."
|
@@ -349,6 +369,12 @@ fr:
|
|
349
369
|
manufacturer: "Fabricant"
|
350
370
|
suggested_products: "Produits suggérés"
|
351
371
|
price: "Prix"
|
372
|
+
vat_rate: "Taux de TVA"
|
373
|
+
weight: "Poids du produit"
|
374
|
+
variant:
|
375
|
+
price: "Prix"
|
376
|
+
stock: "Quantité en stock"
|
377
|
+
weight: "Poids"
|
352
378
|
product_category:
|
353
379
|
name: "Nom"
|
354
380
|
slug: "Fragment d'URL"
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class ChangeVariantsWeightDefaultToNil < ActiveRecord::Migration
|
2
|
+
def up
|
3
|
+
change_column_default :stall_variants, :weight, nil
|
4
|
+
|
5
|
+
Variant.where(weight: 0).find_each { |v| v.update(weight: nil) }
|
6
|
+
end
|
7
|
+
|
8
|
+
def down
|
9
|
+
change_column_default :stall_variants, :weight, 0
|
10
|
+
end
|
11
|
+
end
|
@@ -33,6 +33,24 @@ Stall.configure do |config|
|
|
33
33
|
#
|
34
34
|
# config.prices_precision = 2
|
35
35
|
|
36
|
+
# Override the controllers used in stall's default routing.
|
37
|
+
#
|
38
|
+
# This allows to extend or replace default controller behaviors by providing
|
39
|
+
# a route-compatible controller name with the right key
|
40
|
+
#
|
41
|
+
# Please read the routes source to see which controllers your can override
|
42
|
+
# with this config :
|
43
|
+
#
|
44
|
+
# https://github.com/rails-stall/stall/blob/master/lib/stall/routes.rb
|
45
|
+
#
|
46
|
+
# Note : If you define controllers here that inherit from stall controllers,
|
47
|
+
# to extend their behavior, please fill the `config.default_layout`
|
48
|
+
# config to avoid layout issues, or define the `#set_stall_layout`
|
49
|
+
# in your controllers, returing the layout name to render, or set
|
50
|
+
# the `.layout` macro in your controller.
|
51
|
+
#
|
52
|
+
# config.controllers = { products: 'products' }
|
53
|
+
|
36
54
|
# User omniauth providers that will be allowed for customers to authenticate
|
37
55
|
# with.
|
38
56
|
#
|
data/lib/stall.rb
CHANGED
data/lib/stall/addressable.rb
CHANGED
@@ -22,23 +22,54 @@ module Stall
|
|
22
22
|
end
|
23
23
|
|
24
24
|
# Allow billing address to fall back to shipping address when not filled
|
25
|
-
def billing_address
|
26
|
-
association(:billing_address).load_target
|
25
|
+
def billing_address(force_actual_address: false)
|
26
|
+
if (billing_address = association(:billing_address).load_target)
|
27
|
+
billing_address
|
28
|
+
elsif !@_force_actual_address_association && !force_actual_address
|
27
29
|
association(:shipping_address).load_target
|
30
|
+
end
|
28
31
|
end
|
29
32
|
|
30
33
|
def billing_address?
|
31
34
|
billing_address.try(:persisted?) && billing_address.billing?
|
32
35
|
end
|
33
36
|
|
37
|
+
def billing_address_attributes=(attributes)
|
38
|
+
with_actual_address_associations do
|
39
|
+
assign_nested_attributes_for_one_to_one_association(:billing_address, attributes)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
34
43
|
# Allow shipping address to fall back to billing address when not filled
|
35
|
-
def shipping_address
|
36
|
-
association(:shipping_address).load_target
|
44
|
+
def shipping_address(force_actual_address: false)
|
45
|
+
if (shipping_address = association(:shipping_address).load_target)
|
46
|
+
shipping_address
|
47
|
+
elsif !@_force_actual_address_association && !force_actual_address
|
37
48
|
association(:billing_address).load_target
|
49
|
+
end
|
38
50
|
end
|
39
51
|
|
40
52
|
def shipping_address?
|
41
53
|
shipping_address.try(:persisted?) && shipping_address.shipping?
|
42
54
|
end
|
55
|
+
|
56
|
+
def shipping_address_attributes=(attributes)
|
57
|
+
with_actual_address_associations do
|
58
|
+
assign_nested_attributes_for_one_to_one_association(:shipping_address, attributes)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Allow forcing actual address associations to be retrieved, thus disabling
|
63
|
+
# addresses fallback for the duration of the block.
|
64
|
+
#
|
65
|
+
# This is used for nested attributes assignation which calls the
|
66
|
+
# associations reader directly, which happen to merge addresses when
|
67
|
+
# both billing and shipping addresses are assigned at the same time.
|
68
|
+
#
|
69
|
+
def with_actual_address_associations
|
70
|
+
@_force_actual_address_association = true
|
71
|
+
yield
|
72
|
+
@_force_actual_address_association = false
|
73
|
+
end
|
43
74
|
end
|
44
75
|
end
|
@@ -17,17 +17,21 @@ module Stall
|
|
17
17
|
# Update or create target address with source attributes
|
18
18
|
#
|
19
19
|
def copy_address(type)
|
20
|
-
|
21
|
-
target.
|
22
|
-
|
23
|
-
|
24
|
-
|
20
|
+
source.with_actual_address_associations do
|
21
|
+
target.with_actual_address_associations do
|
22
|
+
address = if target.send(:"#{ type }_address?")
|
23
|
+
target.send(:"#{ type }_address")
|
24
|
+
else
|
25
|
+
target.send(:"build_#{ type }_address")
|
26
|
+
end
|
25
27
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
28
|
+
if source.send(:"#{ type }_address?")
|
29
|
+
attributes = duplicate_attributes(source.send(:"#{ type }_address"))
|
30
|
+
address.assign_attributes(attributes)
|
31
|
+
else
|
32
|
+
address.try(:mark_for_destruction)
|
33
|
+
end
|
34
|
+
end
|
31
35
|
end
|
32
36
|
end
|
33
37
|
end
|
@@ -9,13 +9,17 @@ module Stall
|
|
9
9
|
private
|
10
10
|
|
11
11
|
def prefill_address(type)
|
12
|
-
|
12
|
+
source.with_actual_address_associations do
|
13
|
+
target.with_actual_address_associations do
|
14
|
+
source_address = source.send("#{ type }_address")
|
13
15
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
if source_address && !target.send("#{ type }_address?")
|
17
|
+
attributes = duplicate_attributes(source_address)
|
18
|
+
target.send("build_#{ type }_address", attributes)
|
19
|
+
elsif !target.send("#{ type }_address?")
|
20
|
+
target.send("build_#{ type }_address")
|
21
|
+
end
|
22
|
+
end
|
19
23
|
end
|
20
24
|
end
|
21
25
|
end
|
data/lib/stall/config.rb
CHANGED
@@ -21,6 +21,10 @@ module Stall
|
|
21
21
|
# Default prices precision for rounding
|
22
22
|
param :prices_precision, 2
|
23
23
|
|
24
|
+
# Controller overrides to allow extending or replacing default controllers
|
25
|
+
# behaviors
|
26
|
+
param :controllers, {}.with_indifferent_access
|
27
|
+
|
24
28
|
# User omniauth providers
|
25
29
|
param :devise_for_user_config, { controllers: { omniauth_callbacks: 'stall/omniauth_callbacks' } }
|
26
30
|
|
data/lib/stall/engine.rb
CHANGED
@@ -21,6 +21,7 @@ module Stall
|
|
21
21
|
config.to_prepare do
|
22
22
|
::ApplicationController.send(:include, Stall::CartHelper)
|
23
23
|
::ApplicationController.send(:include, Stall::ArchivedPaidCartHelper)
|
24
|
+
::ApplicationController.send(:include, Stall::WishListHelper)
|
24
25
|
end
|
25
26
|
|
26
27
|
initializer 'stall.ensure_shipping_method_for_all_calculators' do
|
data/lib/stall/routes.rb
CHANGED
@@ -7,6 +7,8 @@ module Stall
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def draw(mount_location)
|
10
|
+
routes = self
|
11
|
+
|
10
12
|
router.instance_eval do
|
11
13
|
devise_for :users, Stall.config.devise_for_user_config
|
12
14
|
|
@@ -14,33 +16,43 @@ module Stall
|
|
14
16
|
get '/users/omniauth/:provider/redirect' => 'stall/omniauth_callbacks#redirect', as: :user_omniauth_redirect
|
15
17
|
end
|
16
18
|
|
17
|
-
scope mount_location
|
18
|
-
resources :products, only: [:index], as: :products
|
19
|
+
scope mount_location do
|
20
|
+
resources :products, only: [:index], as: :products, controller: routes.controller_for(:products)
|
19
21
|
|
20
22
|
constraints ProductExistsConstraint.new do
|
21
|
-
resources :products, path: '/', only: [:show]
|
23
|
+
resources :products, path: '/', only: [:show], controller: routes.controller_for(:products)
|
24
|
+
end
|
25
|
+
|
26
|
+
constraints ProductCategoryExistsConstraint.new do
|
27
|
+
resources :product_categories, path: '/', only: [:show], controller: routes.controller_for(:product_categories)
|
22
28
|
end
|
23
29
|
|
24
30
|
constraints CuratedProductListExistsConstraint.new do
|
25
|
-
resources :curated_product_lists, path: '/', only: [:show]
|
31
|
+
resources :curated_product_lists, path: '/', only: [:show], controller: routes.controller_for(:curated_product_lists) do
|
32
|
+
resources :products, only: [:show], path: '/', controller: routes.controller_for(:products)
|
33
|
+
end
|
26
34
|
end
|
27
35
|
|
28
|
-
constraints
|
29
|
-
resources :
|
36
|
+
constraints ManufacturerExistsConstraint.new do
|
37
|
+
resources :manufacturers, path: '/', only: [:show], controller: routes.controller_for(:manufacturers) do
|
38
|
+
resources :products, only: [:show], path: '/', controller: routes.controller_for(:products)
|
39
|
+
end
|
30
40
|
end
|
31
41
|
|
32
|
-
resources :
|
42
|
+
resources :carts, controller: routes.controller_for(:carts) do
|
43
|
+
resources :line_items, only: [:create], controller: routes.controller_for(:cart_line_items)
|
44
|
+
resource :credit, only: [:update, :destroy], controller: routes.controller_for(:cart_credits)
|
45
|
+
end
|
33
46
|
|
34
|
-
resources :
|
35
|
-
resources :line_items
|
36
|
-
resource :credit, controller: 'cart_credits', only: [:update, :destroy]
|
47
|
+
resources :wish_lists, only: [:show], controller: routes.controller_for(:wish_lists) do
|
48
|
+
resources :line_items, only: [:create, :destroy], controller: routes.controller_for(:wish_list_line_items)
|
37
49
|
end
|
38
50
|
|
39
|
-
get 'checkout/:cart_key' =>
|
51
|
+
get 'checkout/:cart_key' => "#{routes.controller_for(:checkouts)}#show", as: :checkout
|
40
52
|
|
41
|
-
scope 'checkout',
|
53
|
+
scope 'checkout', as: :checkout do
|
42
54
|
scope '(:cart_key)' do
|
43
|
-
resource :step, only: [:show, :update] do
|
55
|
+
resource :step, only: [:show, :update], controller: routes.controller_for(:'checkout/steps') do
|
44
56
|
post '/', action: :update, as: :update
|
45
57
|
get '/process', action: :update, as: :process
|
46
58
|
# Allow external URLs process steps, allowing some payment
|
@@ -51,9 +63,8 @@ module Stall
|
|
51
63
|
end
|
52
64
|
end
|
53
65
|
|
54
|
-
|
55
66
|
scope '/:gateway' do
|
56
|
-
resource :payment, only: [] do
|
67
|
+
resource :payment, only: [], controller: routes.controller_for(:payments) do
|
57
68
|
member do
|
58
69
|
match 'notify', action: 'notify', via: [:get, :post]
|
59
70
|
end
|
@@ -63,10 +74,8 @@ module Stall
|
|
63
74
|
end
|
64
75
|
end
|
65
76
|
|
66
|
-
|
67
|
-
|
68
|
-
CuratedProductList.exists?(slug: request.params[:id])
|
69
|
-
end
|
77
|
+
def controller_for(key)
|
78
|
+
Stall.config.controllers[key] || "stall/#{key}"
|
70
79
|
end
|
71
80
|
|
72
81
|
class ProductExistsConstraint
|
@@ -80,5 +89,19 @@ module Stall
|
|
80
89
|
ProductCategory.exists?(slug: request.params[:id])
|
81
90
|
end
|
82
91
|
end
|
92
|
+
|
93
|
+
class CuratedProductListExistsConstraint
|
94
|
+
def matches?(request)
|
95
|
+
id = request.params[:curated_product_list_id] || request.params[:id]
|
96
|
+
CuratedProductList.exists?(slug: id)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
class ManufacturerExistsConstraint
|
101
|
+
def matches?(request)
|
102
|
+
id = request.params[:manufacturer_id] || request.params[:id]
|
103
|
+
Manufacturer.exists?(slug: id)
|
104
|
+
end
|
105
|
+
end
|
83
106
|
end
|
84
107
|
end
|