stall 0.3.2 → 0.3.3
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/README.md +15 -21
- data/app/assets/javascripts/para/stall/inputs/variants-matrix/input.coffee +8 -1
- data/app/assets/javascripts/para/stall/inputs/variants-matrix/variant.coffee +9 -0
- data/app/assets/javascripts/stall.coffee +7 -1
- data/app/assets/javascripts/stall/add-to-cart-form.coffee +1 -4
- data/app/assets/javascripts/stall/products-filters.coffee +29 -0
- data/app/assets/stylesheets/para/stall.sass +5 -0
- data/app/assets/stylesheets/stall.sass +0 -0
- data/app/controllers/stall/checkout/steps_controller.rb +6 -5
- data/app/controllers/stall/checkout_base_controller.rb +14 -0
- data/app/controllers/stall/checkouts_controller.rb +7 -4
- data/app/controllers/stall/curated_product_lists_controller.rb +10 -0
- data/app/controllers/stall/line_items_controller.rb +1 -5
- data/app/controllers/stall/manufacturers_controller.rb +12 -0
- data/app/controllers/stall/omniauth_callbacks_controller.rb +49 -0
- data/app/controllers/stall/product_categories_controller.rb +13 -0
- data/app/controllers/stall/products_breadcrumbs.rb +16 -0
- data/app/controllers/stall/products_controller.rb +20 -0
- data/app/controllers/stall/products_search.rb +11 -0
- data/app/helpers/stall/customers_helper.rb +0 -10
- data/app/helpers/stall/omniauth_helper.rb +7 -0
- data/app/helpers/stall/prices_helper.rb +12 -0
- data/app/helpers/stall/products_filters_helper.rb +34 -0
- data/app/mailers/stall/customer_mailer.rb +4 -3
- data/app/models/curated_list_product.rb +3 -0
- data/app/models/curated_product_list.rb +3 -0
- data/app/models/image.rb +3 -0
- data/app/models/product_suggestion.rb +3 -0
- data/app/models/stall/models/curated_list_product.rb +15 -0
- data/app/models/stall/models/curated_product_list.rb +22 -0
- data/app/models/stall/models/customer.rb +5 -8
- data/app/models/stall/models/image.rb +21 -0
- data/app/models/stall/models/manufacturer.rb +4 -0
- data/app/models/stall/models/product.rb +30 -7
- data/app/models/stall/models/product_category.rb +5 -2
- data/app/models/stall/models/product_list.rb +1 -1
- data/app/models/stall/models/product_suggestion.rb +14 -0
- data/app/models/stall/models/shipment.rb +0 -2
- data/app/models/stall/models/user.rb +18 -0
- data/app/models/stall/models/user_omniauth_account.rb +13 -0
- data/app/models/stall/models/variant.rb +11 -11
- data/app/models/user.rb +3 -0
- data/app/models/user_omniauth_account.rb +3 -0
- data/app/services/stall/add_to_cart_service.rb +19 -4
- data/app/services/stall/available_stocks_service.rb +11 -0
- data/app/services/stall/cart_credit_note_creation_service.rb +4 -0
- data/app/services/stall/cart_payment_validation_service.rb +5 -3
- data/app/services/stall/credit_usage_service.rb +8 -2
- data/app/services/stall/omniauth_user_authentication_service.rb +48 -0
- data/app/services/stall/product_list_staleness_handling_service.rb +6 -3
- data/app/services/stall/products_search_service.rb +23 -0
- data/app/services/stall/shipping_notification_service.rb +1 -1
- data/app/views/admin/carts/_filters.html.haml +10 -4
- data/app/views/admin/carts/_form.html.haml +9 -9
- data/app/views/admin/manufacturers/_form.html.haml +7 -0
- data/app/views/admin/manufacturers/_table.html.haml +8 -0
- data/app/views/admin/product_categories/_form.html.haml +7 -0
- data/app/views/admin/products/_form.html.haml +23 -0
- data/app/views/admin/products/_table.html.haml +4 -2
- data/app/views/checkout/steps/_informations.html.haml +2 -2
- data/app/views/para/admin/resources/_variant_row.html.haml +9 -1
- data/app/views/para/admin/resources/_variant_row_header.html.haml +14 -0
- data/app/views/para/stall/inputs/_variant_select.html.haml +3 -3
- data/app/views/para/stall/inputs/_variants_matrix.html.haml +7 -16
- data/app/views/para/stall/inputs/shipping_notes/new.html.haml +22 -0
- data/app/views/para/stall/inputs/shipping_notes/sent.html.haml +11 -0
- data/app/views/stall/carts/_cart.html.haml +1 -1
- data/app/views/stall/credit_note_adjustments/_form.html.haml +1 -1
- data/app/views/stall/curated_product_lists/show.html.haml +8 -0
- data/app/views/stall/customers/_fields.html.haml +17 -5
- data/app/views/stall/customers/_sign_in.html.haml +22 -10
- data/app/views/stall/line_items/_form.html.haml +2 -3
- data/app/views/stall/manufacturers/show.html.haml +8 -0
- data/app/views/stall/product_categories/show.html.haml +8 -0
- data/app/views/stall/products/_filters.html.haml +4 -0
- data/app/views/stall/products/_list.html.haml +7 -0
- data/app/views/stall/products/_product.html.haml +4 -0
- data/app/views/stall/products/_product_details.html.haml +13 -0
- data/app/views/stall/products/filters/_category_filter.html.haml +2 -0
- data/app/views/stall/products/filters/_manufacturer_filter.html.haml +2 -0
- data/app/views/stall/products/filters/_price_filter.html.haml +2 -0
- data/app/views/stall/products/filters/_property_filter.html.haml +2 -0
- data/app/views/stall/products/index.html.haml +8 -0
- data/app/views/stall/products/show.html.haml +26 -0
- data/config/locales/stall.fr.yml +97 -11
- data/db/migrate/20170221094450_add_slug_to_stall_manufacturers.rb +5 -0
- data/db/migrate/20170303122616_create_stall_product_suggestions.rb +13 -0
- data/db/migrate/20170303151939_add_position_to_stall_manufacturers.rb +5 -0
- data/db/migrate/20170308162740_create_stall_curated_product_lists.rb +10 -0
- data/db/migrate/20170308163532_create_stall_curated_list_products.rb +14 -0
- data/db/migrate/20170317103740_create_stall_users.rb +28 -0
- data/db/migrate/20170317104332_create_stall_user_omniauth_accounts.rb +14 -0
- data/db/migrate/20170320133513_fix_curated_product_list_bad_foreign_key.rb +6 -0
- data/db/migrate/20170321104203_create_stall_images.rb +11 -0
- data/db/migrate/20170321112248_remove_image_attachment_to_stall_products.rb +5 -0
- data/db/migrate/20170411134756_add_stock_to_stall_variants.rb +5 -0
- data/lib/ext/ransack.rb +13 -0
- data/lib/generators/stall/install/templates/initializer.rb +50 -15
- data/lib/generators/stall/service/service_generator.rb +0 -4
- data/lib/generators/stall/view/view_generator.rb +10 -8
- data/lib/para/stall/inputs/variant_select_input.rb +11 -1
- data/lib/para/stall/inputs/variants_matrix_input.rb +12 -6
- data/lib/stall.rb +14 -0
- data/lib/stall/addressable.rb +2 -2
- data/lib/stall/addresses/copy_source_to_target.rb +7 -3
- data/lib/stall/addresses/prefill_target_from_source.rb +4 -2
- data/lib/stall/cart_helper.rb +3 -3
- data/lib/stall/carts_cleaner.rb +2 -2
- data/lib/stall/checkout/informations_checkout_step.rb +2 -2
- data/lib/stall/config.rb +29 -9
- data/lib/stall/engine.rb +28 -13
- data/lib/stall/omniauth_provider.rb +41 -0
- data/lib/stall/payable.rb +3 -1
- data/lib/stall/product_filters.rb +12 -0
- data/lib/stall/product_filters/base_filter.rb +43 -0
- data/lib/stall/product_filters/builder.rb +59 -0
- data/lib/stall/product_filters/category_filter.rb +28 -0
- data/lib/stall/product_filters/manufacturer_filter.rb +19 -0
- data/lib/stall/product_filters/price_filter.rb +39 -0
- data/lib/stall/product_filters/property_filter.rb +38 -0
- data/lib/stall/routes.rb +40 -0
- data/lib/stall/shipping/calculator.rb +3 -1
- data/lib/stall/version.rb +1 -1
- metadata +158 -7
- data/app/assets/stylesheets/stall/carts.css +0 -4
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
module Stall
|
|
2
|
+
module PricesHelper
|
|
3
|
+
def displayed_price_for_variants variants
|
|
4
|
+
if variants.length == 1
|
|
5
|
+
number_to_currency(variants.first.price)
|
|
6
|
+
else
|
|
7
|
+
price = variants.map(&:price).min
|
|
8
|
+
t('stall.products.prices.from', price: number_to_currency(price)) if price
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module Stall
|
|
2
|
+
module ProductsFiltersHelper
|
|
3
|
+
# Display various filters for the given products including :
|
|
4
|
+
#
|
|
5
|
+
# - Product categories filters (:category)
|
|
6
|
+
# - Manufacturer filters (:manufacturer)
|
|
7
|
+
# - Price filter (:price)
|
|
8
|
+
# - Properties filters (:property)
|
|
9
|
+
#
|
|
10
|
+
# Those filters allow automatically searching into the provided products
|
|
11
|
+
# and should only be provided a list of prodcts that can be displayed
|
|
12
|
+
# for the current products list. e.g. for the brands#show products list,
|
|
13
|
+
# we pass the filters all the products from the manufacturer.
|
|
14
|
+
#
|
|
15
|
+
# In Stall, it is handled by the @filterable_products instance variables
|
|
16
|
+
# from the ProductCategoriesController, ManufacturersController and
|
|
17
|
+
# ProductsController.
|
|
18
|
+
#
|
|
19
|
+
# By default, all available filters (which contains possible results) are
|
|
20
|
+
# shown. If you need to remove a filter, you can pass an option with
|
|
21
|
+
# its name as false. The following would remove the category filter :
|
|
22
|
+
#
|
|
23
|
+
# product_filters_for(@filterable_products, category: false)
|
|
24
|
+
#
|
|
25
|
+
# If, at the opposite, you need to force the display of a certain filter
|
|
26
|
+
# even if there's no results available, you can do the following :
|
|
27
|
+
#
|
|
28
|
+
# product_filters_for(@filterable_products, category: { force: true })
|
|
29
|
+
#
|
|
30
|
+
def product_filters_for(products, options = {})
|
|
31
|
+
Stall::ProductFilters::Builder.new(products, options).filters.select(&:available?)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -14,10 +14,11 @@ module Stall
|
|
|
14
14
|
I18n.with_locale(cart.customer.locale) do
|
|
15
15
|
@cart = cart
|
|
16
16
|
|
|
17
|
-
calculator_class = Stall::Shipping::Calculator.for(cart.shipment.shipping_method)
|
|
18
|
-
|
|
17
|
+
@calculator = if (calculator_class = Stall::Shipping::Calculator.for(cart.shipment.shipping_method))
|
|
18
|
+
calculator_class.new(cart, cart.shipment.shipping_method)
|
|
19
|
+
end
|
|
19
20
|
|
|
20
|
-
@tracking_url = if @calculator.trackable?
|
|
21
|
+
@tracking_url = if @calculator.try(:trackable?)
|
|
21
22
|
cart.shipment.tracking_code.presence && @calculator.tracking_url
|
|
22
23
|
end
|
|
23
24
|
|
data/app/models/image.rb
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Stall
|
|
2
|
+
module Models
|
|
3
|
+
module CuratedListProduct
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
|
|
6
|
+
included do
|
|
7
|
+
self.table_name = 'stall_curated_list_products'
|
|
8
|
+
acts_as_orderable
|
|
9
|
+
|
|
10
|
+
belongs_to :product
|
|
11
|
+
belongs_to :curated_product_list
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Stall
|
|
2
|
+
module Models
|
|
3
|
+
module CuratedProductList
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
|
|
6
|
+
included do
|
|
7
|
+
self.table_name = 'stall_curated_product_lists'
|
|
8
|
+
|
|
9
|
+
has_many :curated_list_products, -> { ordered }, dependent: :destroy
|
|
10
|
+
has_many :products, through: :curated_list_products
|
|
11
|
+
|
|
12
|
+
accepts_nested_attributes_for :curated_list_products,
|
|
13
|
+
allow_destroy: true
|
|
14
|
+
|
|
15
|
+
extend FriendlyId
|
|
16
|
+
friendly_id :name, use: [:slugged, :finders]
|
|
17
|
+
|
|
18
|
+
validates :name, presence: true
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -8,15 +8,14 @@ module Stall
|
|
|
8
8
|
|
|
9
9
|
include Stall::Addressable
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
accepts_nested_attributes_for :user
|
|
11
|
+
belongs_to :user, polymorphic: true, inverse_of: :customer
|
|
12
|
+
accepts_nested_attributes_for :user
|
|
14
13
|
|
|
15
|
-
|
|
16
|
-
end
|
|
14
|
+
before_validation :ensure_user_email
|
|
17
15
|
|
|
18
16
|
has_many :product_lists, dependent: :destroy
|
|
19
17
|
has_many :credit_notes, dependent: :destroy
|
|
18
|
+
has_many :carts, dependent: :nullify
|
|
20
19
|
|
|
21
20
|
validates :email, presence: true,
|
|
22
21
|
format: { with: /\A[^@\s]+@([^@\s]+\.)+[^@\W]+\z/ }
|
|
@@ -26,9 +25,7 @@ module Stall
|
|
|
26
25
|
end
|
|
27
26
|
|
|
28
27
|
def build_user(attributes = {})
|
|
29
|
-
|
|
30
|
-
user.customer = self if user.respond_to?(:customer)
|
|
31
|
-
end if Stall.config.default_user_model
|
|
28
|
+
self.user = ::User.new(attributes.merge(customer: self))
|
|
32
29
|
end
|
|
33
30
|
|
|
34
31
|
def credit(currency = Stall.config.default_currency)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Stall
|
|
2
|
+
module Models
|
|
3
|
+
module Image
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
|
|
6
|
+
included do
|
|
7
|
+
self.table_name = 'stall_images'
|
|
8
|
+
|
|
9
|
+
acts_as_orderable
|
|
10
|
+
|
|
11
|
+
belongs_to :imageable, polymorphic: true
|
|
12
|
+
|
|
13
|
+
has_attached_file :file, styles: {
|
|
14
|
+
thumb: '100x100#',
|
|
15
|
+
show: '555x'
|
|
16
|
+
}
|
|
17
|
+
validates_attachment :file, content_type: { content_type: /\Aimage\/.*\z/ }
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -16,16 +16,28 @@ module Stall
|
|
|
16
16
|
has_many :variants, dependent: :destroy, inverse_of: :product
|
|
17
17
|
accepts_nested_attributes_for :variants, allow_destroy: true
|
|
18
18
|
|
|
19
|
-
has_many :product_details, dependent: :destroy,
|
|
19
|
+
has_many :product_details, -> { ordered }, dependent: :destroy,
|
|
20
|
+
inverse_of: :product
|
|
20
21
|
accepts_nested_attributes_for :product_details, allow_destroy: true
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
23
|
+
has_many :product_suggestions, dependent: :destroy
|
|
24
|
+
has_many :suggested_products, through: :product_suggestions,
|
|
25
|
+
source: :suggestion
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
has_many :suggester_product_suggestions, dependent: :destroy,
|
|
28
|
+
foreign_key: :suggestion_id,
|
|
29
|
+
class_name: 'ProductSuggestion'
|
|
30
|
+
has_many :suggester_products, through: :suggester_product_suggestions,
|
|
31
|
+
source: :product
|
|
32
|
+
|
|
33
|
+
has_many :images, -> { ordered }, as: :imageable
|
|
34
|
+
|
|
35
|
+
has_many :curated_list_products, dependent: :destroy
|
|
36
|
+
has_many :curated_product_lists, through: :curated_list_products
|
|
37
|
+
|
|
38
|
+
accepts_nested_attributes_for :images, allow_destroy: true
|
|
39
|
+
|
|
40
|
+
validates :name, presence: true
|
|
29
41
|
|
|
30
42
|
scope :visible, -> { where(visible: true) }
|
|
31
43
|
end
|
|
@@ -37,6 +49,17 @@ module Stall
|
|
|
37
49
|
def price
|
|
38
50
|
variants.map(&:price).min
|
|
39
51
|
end
|
|
52
|
+
|
|
53
|
+
def image(*args)
|
|
54
|
+
if (image = images.first)
|
|
55
|
+
image.file
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Support paperclip attachment presence helper for #image
|
|
60
|
+
def image?
|
|
61
|
+
!!image
|
|
62
|
+
end
|
|
40
63
|
end
|
|
41
64
|
end
|
|
42
65
|
end
|
|
@@ -7,7 +7,6 @@ module Stall
|
|
|
7
7
|
self.table_name = 'stall_product_categories'
|
|
8
8
|
|
|
9
9
|
acts_as_tree order: 'position'
|
|
10
|
-
class_attribute :max_depth
|
|
11
10
|
|
|
12
11
|
extend FriendlyId
|
|
13
12
|
friendly_id :name, use: [:slugged, :finders]
|
|
@@ -16,7 +15,11 @@ module Stall
|
|
|
16
15
|
|
|
17
16
|
validates :name, presence: true
|
|
18
17
|
|
|
19
|
-
scope :ordered, -> { order(position: '
|
|
18
|
+
scope :ordered, -> { order(position: 'ASC') }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def all_child_products
|
|
22
|
+
::Product.where(product_category_id: ([id] + descendant_ids))
|
|
20
23
|
end
|
|
21
24
|
|
|
22
25
|
module ClassMethods
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module Stall
|
|
2
|
+
module Models
|
|
3
|
+
module User
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
|
|
6
|
+
included do
|
|
7
|
+
self.table_name = 'stall_users'
|
|
8
|
+
|
|
9
|
+
devise :database_authenticatable, :registerable, :recoverable,
|
|
10
|
+
:rememberable, :trackable, :validatable, :omniauthable,
|
|
11
|
+
omniauth_providers: Stall.config.omniauth_providers.map(&:name)
|
|
12
|
+
|
|
13
|
+
has_one :customer, as: :user, dependent: :nullify
|
|
14
|
+
has_many :user_omniauth_accounts, dependent: :destroy
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -26,22 +26,22 @@ module Stall
|
|
|
26
26
|
delegate :image, :image?, :vat_rate, to: :product, allow_nil: true
|
|
27
27
|
|
|
28
28
|
scope :published, -> { where(published: true) }
|
|
29
|
+
end
|
|
29
30
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
private
|
|
31
|
+
def currency
|
|
32
|
+
@currency ||= Money::Currency.new(Stall.config.default_currency)
|
|
33
|
+
end
|
|
35
34
|
|
|
36
|
-
|
|
37
|
-
product_name = product.try(:name)
|
|
35
|
+
private
|
|
38
36
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
end
|
|
37
|
+
def refresh_name
|
|
38
|
+
product_name = product.try(:name)
|
|
42
39
|
|
|
43
|
-
|
|
40
|
+
properties = variant_property_values.map do |variant_property_value|
|
|
41
|
+
variant_property_value.property_value.name
|
|
44
42
|
end
|
|
43
|
+
|
|
44
|
+
self.name = [product_name, properties.join(' - ')].join(' / ')
|
|
45
45
|
end
|
|
46
46
|
end
|
|
47
47
|
end
|
data/app/models/user.rb
ADDED
|
@@ -8,7 +8,7 @@ module Stall
|
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
def call
|
|
11
|
-
return false unless
|
|
11
|
+
return false unless line_item_valid?
|
|
12
12
|
|
|
13
13
|
unless assemble_identical_line_items
|
|
14
14
|
cart.line_items << line_item
|
|
@@ -23,9 +23,18 @@ module Stall
|
|
|
23
23
|
end
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
+
def line_item_valid?
|
|
27
|
+
line_item.valid? && enough_stock?
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def enough_stock?
|
|
31
|
+
stock_service = Stall.config.service_for(:available_stocks).new
|
|
32
|
+
stock_service.on_hand?(line_item)
|
|
33
|
+
end
|
|
34
|
+
|
|
26
35
|
def line_item
|
|
27
36
|
@line_item ||= sellable.to_line_item.tap do |line_item|
|
|
28
|
-
line_item.quantity =
|
|
37
|
+
line_item.quantity = line_item_params[:quantity]
|
|
29
38
|
end
|
|
30
39
|
end
|
|
31
40
|
|
|
@@ -48,15 +57,21 @@ module Stall
|
|
|
48
57
|
end
|
|
49
58
|
|
|
50
59
|
def sellable
|
|
51
|
-
@sellable ||= sellable_class.find(
|
|
60
|
+
@sellable ||= sellable_class.find(line_item_params[:sellable_id])
|
|
52
61
|
end
|
|
53
62
|
|
|
54
63
|
def sellable_class
|
|
55
|
-
@sellable_class ||=
|
|
64
|
+
@sellable_class ||= line_item_params[:sellable_type].camelize.constantize
|
|
56
65
|
end
|
|
57
66
|
|
|
58
67
|
def shipping_fee_service
|
|
59
68
|
@shipping_fee_service ||= Stall::ShippingFeeCalculatorService.new(cart)
|
|
60
69
|
end
|
|
70
|
+
|
|
71
|
+
def line_item_params
|
|
72
|
+
@line_item_params ||= params.require(:line_item).permit(
|
|
73
|
+
:sellable_type, :sellable_id, :quantity
|
|
74
|
+
)
|
|
75
|
+
end
|
|
61
76
|
end
|
|
62
77
|
end
|