stall 0.3.3 → 0.3.4
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.
- 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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ac018d181d2997364eeca462e80758d50ab4c9e2
|
4
|
+
data.tar.gz: 4e3396a2466fab227f83d9d201a237e22147acc3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c612280b92d9cbff047f8e7e0adf1f8dcc8abea245f7cd4cbf37170a68261c0d732f53266c11ba666fbf103c3b3998f267ce970fbb553b40880f88a2e52ee21e
|
7
|
+
data.tar.gz: b35431b6aa8856a8b3dc21686dff0346d0b724ec443176f044d022e0495563584a7e6d8ff537b227be52f91aed929b9e23bbacfa85ff7fb1c827024d7749cb51
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class VariantSelectInput extends Vertebra.View
|
1
|
+
class Stall.VariantSelectInput extends Vertebra.View
|
2
2
|
events:
|
3
3
|
'change [data-variant-select-property]': 'onInputChanged'
|
4
4
|
|
@@ -57,6 +57,7 @@ class VariantSelectInput extends Vertebra.View
|
|
57
57
|
price = if variant then variant.price else @originalPrice
|
58
58
|
@$priceTarget.html(price)
|
59
59
|
|
60
|
-
|
60
|
+
|
61
|
+
Stall.onDomReady ->
|
61
62
|
$('[data-variant-select-input]').each (i, el) ->
|
62
|
-
new VariantSelectInput(el: el)
|
63
|
+
new Stall.VariantSelectInput(el: el)
|
@@ -4,7 +4,9 @@
|
|
4
4
|
#= require_self
|
5
5
|
#
|
6
6
|
#= require stall/add-to-cart-form
|
7
|
-
#= require stall/
|
7
|
+
#= require stall/add-to-wish-list-button
|
8
|
+
#= require stall/add-product-to-wish-list-button
|
9
|
+
#= require stall/product-list-form
|
8
10
|
#= require stall/addresses-fields
|
9
11
|
#= require stall/remote-sign-in-form
|
10
12
|
#= require stall/products-filters
|
@@ -0,0 +1,99 @@
|
|
1
|
+
class Stall.AddProductToWishListButton extends Vertebra.View
|
2
|
+
events:
|
3
|
+
'click': 'onButtonClicked'
|
4
|
+
|
5
|
+
onButtonClicked: ->
|
6
|
+
if @$el.is('[data-included]') then @remove() else @add()
|
7
|
+
|
8
|
+
add: ->
|
9
|
+
@setLoading(true)
|
10
|
+
|
11
|
+
data =
|
12
|
+
product_id: @$el.data('product-id')
|
13
|
+
|
14
|
+
$.post(@$el.data('url'), data).then(@onResponse)
|
15
|
+
|
16
|
+
remove: ->
|
17
|
+
@setLoading(true)
|
18
|
+
|
19
|
+
data =
|
20
|
+
_method: 'delete'
|
21
|
+
|
22
|
+
$.post(@$el.data('url'), data).then(@onResponse)
|
23
|
+
|
24
|
+
onResponse: (resp) =>
|
25
|
+
@popover?.destroy()
|
26
|
+
@setLoading(false)
|
27
|
+
@setNewElement($(resp))
|
28
|
+
|
29
|
+
setNewElement: ($el) ->
|
30
|
+
@$el.tooltip('hide')
|
31
|
+
@$el.replaceWith($el)
|
32
|
+
@setElement($el)
|
33
|
+
# Open popover if provided
|
34
|
+
if (content = $el.data('popover-content')) then @openPopover(content)
|
35
|
+
|
36
|
+
openPopover: (content) ->
|
37
|
+
@popover = new Stall.WishListFormPopover(content: content)
|
38
|
+
@popover.renderTo(@$el)
|
39
|
+
@listenTo(@popover, 'send', => @setLoading(true))
|
40
|
+
@listenTo(@popover, 'added', @onResponse)
|
41
|
+
|
42
|
+
setLoading: (state) ->
|
43
|
+
@popover?.hide()
|
44
|
+
@$el.toggleClass('loading', state)
|
45
|
+
@$('[data-wish-list-icon]').toggleClass('hidden', state)
|
46
|
+
@$('[data-wish-list-loading-spinner]').toggleClass('hidden', !state)
|
47
|
+
|
48
|
+
class Stall.WishListFormPopover extends Vertebra.View
|
49
|
+
events:
|
50
|
+
'ajax:beforeSend [data-add-to-wish-list-form]': 'onBeforeSend'
|
51
|
+
'ajax:success [data-add-to-wish-list-form]': 'onItemAdded'
|
52
|
+
'click [data-cancel-button]': 'onCancelClicked'
|
53
|
+
|
54
|
+
initialize: (options = {}) ->
|
55
|
+
@content = options.content
|
56
|
+
|
57
|
+
renderTo: ($parent) ->
|
58
|
+
$parent.popover
|
59
|
+
title: false
|
60
|
+
content: @content
|
61
|
+
html: true
|
62
|
+
trigger: 'manual'
|
63
|
+
placement: 'auto'
|
64
|
+
container: 'body'
|
65
|
+
|
66
|
+
@popover = $parent.data('bs.popover')
|
67
|
+
@popover.show()
|
68
|
+
|
69
|
+
@setElement(@popover.$tip)
|
70
|
+
@initializeForm()
|
71
|
+
|
72
|
+
initializeForm: ->
|
73
|
+
@$('[data-variant-select-input]').each (i, el) ->
|
74
|
+
new Stall.VariantSelectInput(el: el)
|
75
|
+
|
76
|
+
hide: ->
|
77
|
+
@popover?.hide()
|
78
|
+
|
79
|
+
onBeforeSend: ->
|
80
|
+
@trigger('send')
|
81
|
+
|
82
|
+
onItemAdded: (e, resp) ->
|
83
|
+
@trigger('added', resp)
|
84
|
+
|
85
|
+
onCancelClicked: ->
|
86
|
+
console.log 'onCancelClicked', this
|
87
|
+
@destroy()
|
88
|
+
|
89
|
+
destroy: ->
|
90
|
+
return if @destroyed
|
91
|
+
@popover.destroy()
|
92
|
+
@popover = null
|
93
|
+
super()
|
94
|
+
@destroyed = true
|
95
|
+
|
96
|
+
|
97
|
+
Stall.onDomReady ->
|
98
|
+
$('[data-add-to-wish-list="product"]').each (i, el) ->
|
99
|
+
new Stall.AddProductToWishListButton(el: el)
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class Stall.AddToWishListButton extends Vertebra.View
|
2
|
+
events:
|
3
|
+
'click': 'add'
|
4
|
+
|
5
|
+
initialize: ->
|
6
|
+
@url = @$el.data('url')
|
7
|
+
|
8
|
+
add: ->
|
9
|
+
data = @$el.closest('form').serialize()
|
10
|
+
$.post(@url, data).then(@onResponse)
|
11
|
+
|
12
|
+
onResponse: (resp) =>
|
13
|
+
$(resp).modal()
|
14
|
+
|
15
|
+
Stall.onDomReady ->
|
16
|
+
$('[data-add-to-wish-list="line-item-form"]').each (i, el) ->
|
17
|
+
new Stall.AddToWishListButton(el: el)
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class Stall.ProductListForm extends Vertebra.View
|
2
|
+
events:
|
3
|
+
'change [data-quantity-field]': 'formUpdated'
|
4
|
+
'cocoon:after-remove': 'formUpdated'
|
5
|
+
'ajax:success': 'updateSuccess'
|
6
|
+
|
7
|
+
initialize: ->
|
8
|
+
@clean()
|
9
|
+
|
10
|
+
clean: ->
|
11
|
+
@$('[data-product-list-update-button]').hide(0)
|
12
|
+
# Backwards compatibility with app overriden cart forms
|
13
|
+
@$('[data-cart-update-button]').hide(0)
|
14
|
+
|
15
|
+
formUpdated: (e) ->
|
16
|
+
@$el.submit()
|
17
|
+
|
18
|
+
updateSuccess: (e, resp) ->
|
19
|
+
@updateProductListFormWith(resp)
|
20
|
+
|
21
|
+
updateProductListFormWith: (markup) =>
|
22
|
+
$form = $(markup).find('[data-product-list-form], [data-cart-form]')
|
23
|
+
@$el.html($form.html())
|
24
|
+
@clean()
|
25
|
+
|
26
|
+
|
27
|
+
Stall.onDomReady ->
|
28
|
+
# Backwards compatibility with app overriden cart forms
|
29
|
+
if ($product_listForm = $('[data-product-list-form], [data-cart-form]')).length
|
30
|
+
product_listForm = new Stall.ProductListForm(el: $product_listForm)
|
31
|
+
$product_listForm.data('stall.product-list-form', product_listForm)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Stall
|
2
|
+
class CartLineItemsController < Stall::LineItemsController
|
3
|
+
def create
|
4
|
+
super do |success|
|
5
|
+
if success
|
6
|
+
@widget_partial = render_to_string(partial: 'stall/carts/widget', locals: { cart: product_list })
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def product_list
|
14
|
+
@product_list ||= ProductList.find_by_token(params[:cart_id]) || current_cart
|
15
|
+
end
|
16
|
+
|
17
|
+
def service
|
18
|
+
@service ||= Stall.config.service_for(:add_to_cart).new(product_list, params)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -5,6 +5,12 @@ module Stall
|
|
5
5
|
def show
|
6
6
|
@curated_product_list = CuratedProductList.friendly.find(params[:id])
|
7
7
|
search_products_among(@curated_product_list.products)
|
8
|
+
|
9
|
+
# Also select curated list product positions to allow distinct call to
|
10
|
+
# work when ordering results by position
|
11
|
+
@products = @products.select('stall_products.*, stall_curated_list_products.position')
|
12
|
+
|
13
|
+
add_breadcrumb(@curated_product_list)
|
8
14
|
end
|
9
15
|
end
|
10
16
|
end
|
@@ -1,23 +1,30 @@
|
|
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, params)
|
5
|
-
|
6
4
|
if service.call
|
7
5
|
@quantity = params[:line_item][:quantity].to_i
|
8
6
|
@line_item = service.line_item
|
9
|
-
|
10
|
-
|
7
|
+
# Allow subclasses to hook into successful product list add
|
8
|
+
yield(true) if block_given?
|
9
|
+
# We do not render if the yield bock already has done it
|
10
|
+
render partial: 'added' unless response_body
|
11
11
|
else
|
12
12
|
@line_item = service.line_item
|
13
|
-
|
13
|
+
# Allow subclasses to hook into failed product list add
|
14
|
+
yield(false) if block_given?
|
15
|
+
# We do not render if the yield bock already has done it
|
16
|
+
render partial: 'add_error' unless response_body
|
14
17
|
end
|
15
18
|
end
|
16
19
|
|
17
20
|
private
|
18
21
|
|
19
|
-
def
|
20
|
-
|
22
|
+
def product_list
|
23
|
+
fail NotImplementedError, 'Override #product_list in subclass'
|
24
|
+
end
|
25
|
+
|
26
|
+
def service
|
27
|
+
fail NotImplementedError, 'Override #service in subclass'
|
21
28
|
end
|
22
29
|
end
|
23
30
|
end
|
@@ -3,7 +3,14 @@ module Stall
|
|
3
3
|
private
|
4
4
|
|
5
5
|
def add_product_breadcrumbs
|
6
|
-
|
6
|
+
if @curated_product_list
|
7
|
+
add_breadcrumb(@curated_product_list)
|
8
|
+
elsif @manufacturer
|
9
|
+
add_breadcrumb(@manufacturer)
|
10
|
+
else
|
11
|
+
add_product_category_breadcrumbs(@product.product_category)
|
12
|
+
end
|
13
|
+
|
7
14
|
add_breadcrumb(@product)
|
8
15
|
end
|
9
16
|
|
@@ -3,6 +3,8 @@ module Stall
|
|
3
3
|
include ProductsSearch
|
4
4
|
include ProductsBreadcrumbs
|
5
5
|
|
6
|
+
before_action :load_parent_data
|
7
|
+
|
6
8
|
def index
|
7
9
|
search_products_among(Product.all)
|
8
10
|
|
@@ -16,5 +18,15 @@ module Stall
|
|
16
18
|
|
17
19
|
add_product_breadcrumbs
|
18
20
|
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def load_parent_data
|
25
|
+
if params[:curated_product_list_id]
|
26
|
+
@curated_product_list = CuratedProductList.find(params[:curated_product_list_id])
|
27
|
+
elsif params[:manufacturer_id]
|
28
|
+
@manufacturer = Manufacturer.find(params[:manufacturer_id])
|
29
|
+
end
|
30
|
+
end
|
19
31
|
end
|
20
32
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Stall
|
2
|
+
class WishListLineItemsController < Stall::LineItemsController
|
3
|
+
include Stall::AddToWishListHelper
|
4
|
+
|
5
|
+
def create
|
6
|
+
if !service.line_item_params? && (product_id = params[:product_id]).present?
|
7
|
+
product = Product.find(product_id)
|
8
|
+
|
9
|
+
if product.variants.length > 1
|
10
|
+
form = render_to_string(
|
11
|
+
partial: 'stall/wish_list_line_items/form', locals: {
|
12
|
+
wish_list: product_list, line_item: LineItem.new, product: product
|
13
|
+
}
|
14
|
+
)
|
15
|
+
|
16
|
+
add_to_wish_list_button(product, {
|
17
|
+
wish_list: product_list, popover_content: form
|
18
|
+
})
|
19
|
+
else
|
20
|
+
service.add(product.variants.first)
|
21
|
+
add_to_wish_list_button(product, wish_list: product_list)
|
22
|
+
end
|
23
|
+
else
|
24
|
+
super do |valid|
|
25
|
+
if (product = @line_item.sellable.try(:product))
|
26
|
+
add_to_wish_list_button(product, wish_list: product_list)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def destroy
|
33
|
+
line_item = product_list.line_items.find(params[:id])
|
34
|
+
product = line_item.sellable.try(:product)
|
35
|
+
product_list.line_items.destroy(line_item)
|
36
|
+
|
37
|
+
if product
|
38
|
+
add_to_wish_list_button(product, wish_list: product_list)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def product_list
|
45
|
+
@product_list ||= ProductList.find_by_token(params[:cart_id]) || current_wish_list
|
46
|
+
end
|
47
|
+
|
48
|
+
def service
|
49
|
+
@service ||= Stall.config.service_for(:add_to_wish_list).new(product_list, params)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -1,9 +1,10 @@
|
|
1
1
|
module Stall
|
2
2
|
module AddToCartHelper
|
3
3
|
def add_to_cart_form_for(sellable, cart: nil)
|
4
|
-
render partial: 'stall/
|
4
|
+
render partial: 'stall/cart_line_items/form', locals: {
|
5
5
|
cart: (cart || current_cart),
|
6
|
-
line_item: LineItem.new(sellable: sellable)
|
6
|
+
line_item: LineItem.new(sellable: sellable),
|
7
|
+
product: sellable
|
7
8
|
}
|
8
9
|
end
|
9
10
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Stall
|
2
|
+
module AddToWishListHelper
|
3
|
+
def add_to_wish_list_button(product, variant: nil, wish_list: current_wish_list, popover_content: nil)
|
4
|
+
included = wish_list.includes_product?(product)
|
5
|
+
|
6
|
+
url = if included
|
7
|
+
line_item = wish_list.line_item_for_product(product)
|
8
|
+
wish_list_line_item_path(current_wish_list, line_item)
|
9
|
+
else
|
10
|
+
wish_list_line_items_path(current_wish_list)
|
11
|
+
end
|
12
|
+
|
13
|
+
title = if included
|
14
|
+
t('stall.wish_list_line_items.form.remove')
|
15
|
+
else
|
16
|
+
t('stall.wish_list_line_items.form.add')
|
17
|
+
end
|
18
|
+
|
19
|
+
render partial: 'stall/wish_list_line_items/button', locals: {
|
20
|
+
product: product,
|
21
|
+
variant: variant,
|
22
|
+
cart: wish_list,
|
23
|
+
included: included,
|
24
|
+
url: url,
|
25
|
+
title: title,
|
26
|
+
popover_content: popover_content
|
27
|
+
}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Stall
|
2
|
+
module ProductsHelper
|
3
|
+
def product_path(*args)
|
4
|
+
if @curated_product_list
|
5
|
+
curated_product_list_product_path(@curated_product_list, *args)
|
6
|
+
elsif @manufacturer
|
7
|
+
manufacturer_product_path(@manufacturer, *args)
|
8
|
+
else
|
9
|
+
Rails.application.routes.url_helpers.product_path(*args)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -14,12 +14,21 @@ module Stall
|
|
14
14
|
before_validation :ensure_user_email
|
15
15
|
|
16
16
|
has_many :product_lists, dependent: :destroy
|
17
|
+
has_many :wish_lists, class_name: 'WishList'
|
17
18
|
has_many :credit_notes, dependent: :destroy
|
18
19
|
has_many :carts, dependent: :nullify
|
19
20
|
|
20
21
|
validates :email, presence: true,
|
21
22
|
format: { with: /\A[^@\s]+@([^@\s]+\.)+[^@\W]+\z/ }
|
22
23
|
|
24
|
+
def name
|
25
|
+
if billing_address && (billing_address.first_name.present? || billing_address.last_name.present?)
|
26
|
+
[billing_address.last_name, billing_address.first_name].join(' ')
|
27
|
+
else
|
28
|
+
email
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
23
32
|
def user_or_default
|
24
33
|
user || build_user
|
25
34
|
end
|