stall 0.2.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +60 -23
- data/app/assets/javascripts/para/stall.coffee +1 -0
- data/app/assets/javascripts/para/stall/inputs/variant-select.coffee +62 -0
- data/app/assets/javascripts/para/stall/inputs/variants-matrix.coffee +12 -0
- data/app/assets/javascripts/para/stall/inputs/variants-matrix/helpers.coffee +40 -0
- data/app/assets/javascripts/para/stall/inputs/variants-matrix/input.coffee +133 -0
- data/app/assets/javascripts/para/stall/inputs/variants-matrix/nested-fields.coffee +38 -0
- data/app/assets/javascripts/para/stall/inputs/variants-matrix/properties_select.coffee +45 -0
- data/app/assets/javascripts/para/stall/inputs/variants-matrix/variant.coffee +59 -0
- data/app/assets/javascripts/stall.coffee +1 -0
- data/app/assets/javascripts/stall/add-to-cart-form.coffee +53 -28
- data/app/assets/javascripts/stall/cart-form.coffee +7 -2
- data/app/assets/stylesheets/para/stall.sass +28 -0
- data/app/controllers/para/stall/admin/carts_controller.rb +27 -0
- data/app/controllers/stall/cart_credits_controller.rb +27 -0
- data/app/controllers/stall/carts_controller.rb +1 -1
- data/app/controllers/stall/checkout/steps_controller.rb +22 -12
- data/app/controllers/stall/checkouts_controller.rb +1 -0
- data/app/controllers/stall/line_items_controller.rb +1 -0
- data/app/controllers/stall/payments_controller.rb +16 -1
- data/app/helpers/stall/credit_notes_helper.rb +25 -0
- data/app/helpers/stall/customers_helper.rb +3 -1
- data/app/models/billing_address.rb +2 -0
- data/app/models/cart_credit_note_adjustment.rb +3 -0
- data/app/models/credit_note.rb +3 -0
- data/app/models/credit_note_adjustment.rb +3 -0
- data/app/models/credit_note_usage.rb +3 -0
- data/app/models/product.rb +3 -0
- data/app/models/product_category.rb +3 -0
- data/app/models/product_detail.rb +3 -0
- data/app/models/property.rb +3 -0
- data/app/models/property_value.rb +3 -0
- data/app/models/shipping_address.rb +2 -0
- data/app/models/stall/models/address.rb +2 -2
- data/app/models/stall/models/cart.rb +2 -15
- data/app/models/stall/models/cart_credit_note_adjustment.rb +11 -0
- data/app/models/stall/models/credit_note.rb +50 -0
- data/app/models/stall/models/credit_note_adjustment.rb +13 -0
- data/app/models/stall/models/credit_note_usage.rb +16 -0
- data/app/models/stall/models/customer.rb +20 -8
- data/app/models/stall/models/line_item.rb +9 -0
- data/app/models/stall/models/product.rb +45 -0
- data/app/models/stall/models/product_category.rb +31 -0
- data/app/models/stall/models/product_detail.rb +17 -0
- data/app/models/stall/models/product_list.rb +9 -45
- data/app/models/stall/models/property.rb +20 -0
- data/app/models/stall/models/property_value.rb +23 -0
- data/app/models/stall/models/variant.rb +34 -0
- data/app/models/stall/models/variant_property_value.rb +18 -0
- data/app/models/variant.rb +3 -0
- data/app/models/variant_property_value.rb +3 -0
- data/app/services/stall/cart_credit_note_creation_service.rb +40 -0
- data/app/services/stall/cart_payment_validation_service.rb +28 -0
- data/app/services/stall/cart_update_service.rb +17 -6
- data/app/services/stall/credit_usage_service.rb +102 -0
- data/app/services/stall/payment_notification_service.rb +4 -8
- data/app/services/stall/product_list_staleness_handling_service.rb +33 -0
- data/app/views/admin/addresses/_fields.html.haml +9 -0
- data/app/views/admin/carts/_filters.html.haml +17 -0
- data/app/views/admin/carts/_form.html.haml +43 -0
- data/app/views/admin/carts/_table.html.haml +17 -0
- data/app/views/admin/customers/_fields.html.haml +1 -0
- data/app/views/admin/line_items/_fields.html.haml +15 -0
- data/app/views/admin/products/_table.html.haml +12 -0
- data/app/views/admin/properties/_form.html.haml +6 -0
- data/app/views/admin/properties/_table.html.haml +8 -0
- data/app/views/admin/property_values/_fields.html.haml +1 -0
- data/app/views/admin/shipments/_fields.html.haml +7 -0
- data/app/views/checkout/steps/_informations.html.haml +3 -1
- data/app/views/checkout/steps/_payment.html.haml +2 -0
- data/app/views/checkout/steps/_payment_return.html.haml +0 -1
- data/app/views/para/admin/resources/_variant_row.html.haml +24 -0
- data/app/views/para/stall/inputs/_variant_select.html.haml +14 -0
- data/app/views/para/stall/inputs/_variants_matrix.html.haml +41 -0
- data/app/views/stall/addresses/_fields.html.haml +6 -12
- data/app/views/stall/carts/_cart.html.haml +45 -37
- data/app/views/stall/carts/_widget.html.haml +28 -0
- data/app/views/stall/carts/show.html.haml +2 -0
- data/app/views/stall/checkout/steps/_navigation.html.haml +13 -0
- data/app/views/stall/credit_note_adjustments/_form.html.haml +28 -0
- data/app/views/stall/line_items/_added.html.haml +2 -2
- data/app/views/stall/line_items/_form.html.haml +1 -1
- data/app/views/stall/payments/manual_payment_gateway/_form.html.haml +10 -0
- data/app/views/stall/shared/mailers/_cart.html.haml +1 -1
- data/config/locales/stall.fr.yml +82 -2
- data/db/migrate/20161129101956_add_type_to_stall_address_ownerships.rb +52 -0
- data/db/migrate/20161202080218_add_reference_to_product_lists.rb +17 -0
- data/db/migrate/20170118103916_create_credit_notes.rb +17 -0
- data/db/migrate/20170118144047_create_credit_note_adjustments.rb +13 -0
- data/db/migrate/20170123123115_create_stall_product_categories.rb +12 -0
- data/db/migrate/20170123123326_create_stall_products.rb +17 -0
- data/db/migrate/20170123125030_create_stall_variants.rb +13 -0
- data/db/migrate/20170123131748_create_stall_product_category_hierarchies.rb +16 -0
- data/db/migrate/20170123143704_create_stall_product_details.rb +14 -0
- data/db/migrate/20170125152622_convert_all_money_fields_to_decimal_to_use_infinite_precision.rb +27 -0
- data/db/migrate/20170131162537_add_data_to_stall_adjustments.rb +5 -0
- data/db/migrate/20170202165514_create_stall_properties.rb +9 -0
- data/db/migrate/20170202165516_create_stall_property_values.rb +13 -0
- data/db/migrate/20170202165518_create_stall_variant_property_values.rb +13 -0
- data/lib/generators/stall/install/templates/initializer.rb +21 -0
- data/lib/generators/stall/view/view_generator.rb +41 -19
- data/lib/para/stall.rb +32 -0
- data/lib/para/stall/inputs.rb +13 -0
- data/lib/para/stall/inputs/variant_input_helper.rb +34 -0
- data/lib/para/stall/inputs/variant_select_input.rb +79 -0
- data/lib/para/stall/inputs/variants_matrix_input.rb +72 -0
- data/lib/para/stall/routes.rb +11 -0
- data/lib/para/stall/variants_property_config.rb +78 -0
- data/lib/stall.rb +10 -0
- data/lib/stall/addressable.rb +11 -59
- data/lib/stall/addresses.rb +1 -0
- data/lib/stall/addresses/copier_base.rb +3 -1
- data/lib/stall/addresses/copy.rb +10 -0
- data/lib/stall/addresses/copy_source_to_target.rb +10 -24
- data/lib/stall/addresses/prefill_target_from_source.rb +8 -16
- data/lib/stall/adjustable.rb +20 -0
- data/lib/stall/archived_paid_cart_helper.rb +36 -0
- data/lib/stall/cart_helper.rb +15 -7
- data/lib/stall/checkout/informations_checkout_step.rb +47 -50
- data/lib/stall/checkout/payment_return_checkout_step.rb +4 -1
- data/lib/stall/checkout/step.rb +24 -3
- data/lib/stall/checkout/step_form.rb +11 -5
- data/lib/stall/checkout/wizard.rb +7 -6
- data/lib/stall/config.rb +9 -0
- data/lib/stall/default_currency_manager.rb +27 -0
- data/lib/stall/engine.rb +14 -3
- data/lib/stall/payments.rb +2 -0
- data/lib/stall/payments/gateway_request.rb +15 -0
- data/lib/stall/payments/gateway_response.rb +33 -0
- data/lib/stall/payments/manual_payment_gateway.rb +86 -0
- data/lib/stall/priceable.rb +4 -0
- data/lib/stall/reference_manager.rb +17 -0
- data/lib/stall/routes.rb +1 -0
- data/lib/stall/shippable.rb +18 -0
- data/lib/stall/total_prices_manager.rb +40 -0
- data/lib/stall/version.rb +1 -1
- metadata +120 -5
- data/app/models/address_ownership.rb +0 -3
- data/app/models/stall/models/address_ownership.rb +0 -26
@@ -6,7 +6,7 @@ module Stall
|
|
6
6
|
included do
|
7
7
|
self.table_name = 'stall_addresses'
|
8
8
|
|
9
|
-
|
9
|
+
belongs_to :addressable, polymorphic: true
|
10
10
|
|
11
11
|
enum civility: { :m => 1, :mme => 2 }
|
12
12
|
|
@@ -17,7 +17,7 @@ module Stall
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def civility_name
|
20
|
-
I18n.t("stall.addresses.civilities.#{ civility }")
|
20
|
+
I18n.t("stall.addresses.civilities.#{ civility }") if civility.present?
|
21
21
|
end
|
22
22
|
|
23
23
|
def country_name
|
@@ -6,12 +6,8 @@ module Stall
|
|
6
6
|
included do
|
7
7
|
include Stall::Addressable
|
8
8
|
include Stall::Payable
|
9
|
-
|
10
|
-
|
11
|
-
accepts_nested_attributes_for :shipment
|
12
|
-
|
13
|
-
has_many :adjustments, dependent: :destroy, inverse_of: :cart
|
14
|
-
accepts_nested_attributes_for :adjustments
|
9
|
+
include Stall::Shippable
|
10
|
+
include Stall::Adjustable
|
15
11
|
|
16
12
|
attr_accessor :terms
|
17
13
|
end
|
@@ -25,15 +21,6 @@ module Stall
|
|
25
21
|
def active?
|
26
22
|
!paid?
|
27
23
|
end
|
28
|
-
|
29
|
-
private
|
30
|
-
|
31
|
-
def items
|
32
|
-
items = line_items.to_a
|
33
|
-
items << shipment if shipment
|
34
|
-
items += adjustments.to_a
|
35
|
-
items
|
36
|
-
end
|
37
24
|
end
|
38
25
|
end
|
39
26
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Stall
|
2
|
+
module Models
|
3
|
+
module CreditNote
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
self.table_name = 'stall_credit_notes'
|
8
|
+
|
9
|
+
include Stall::Priceable
|
10
|
+
include Stall::DefaultCurrencyManager
|
11
|
+
include Stall::ReferenceManager
|
12
|
+
|
13
|
+
monetize :eot_amount_cents, :amount_cents,
|
14
|
+
with_model_currency: :currency, allow_nil: true
|
15
|
+
|
16
|
+
belongs_to :customer
|
17
|
+
belongs_to :source, polymorphic: true
|
18
|
+
|
19
|
+
has_many :credit_note_usages, dependent: :destroy
|
20
|
+
has_many :adjustments, through: :credit_note_usages
|
21
|
+
|
22
|
+
validates :amount, :customer, presence: true
|
23
|
+
|
24
|
+
def amount_with_eot_management=(value)
|
25
|
+
(self.amount_without_eot_management = value).tap do
|
26
|
+
self.eot_amount = amount / vat_coefficient
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# TODO : Check if we can use Module#prepend here without getting too
|
31
|
+
# complex
|
32
|
+
#
|
33
|
+
alias_method :amount_without_eot_management=, :amount=
|
34
|
+
alias_method :amount=, :amount_with_eot_management=
|
35
|
+
end
|
36
|
+
|
37
|
+
def remaining_amount
|
38
|
+
amount - adjustments.map(&:price).sum.abs
|
39
|
+
end
|
40
|
+
|
41
|
+
def vat_rate
|
42
|
+
read_attribute(:vat_rate) || write_attribute(:vat_rate, Stall.config.vat_rate)
|
43
|
+
end
|
44
|
+
|
45
|
+
def with_remaining_money?
|
46
|
+
remaining_amount.to_d > 0
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Stall
|
2
|
+
module Models
|
3
|
+
module CreditNoteAdjustment
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
has_one :credit_note_usage, foreign_key: :adjustment_id,
|
8
|
+
dependent: :destroy
|
9
|
+
has_one :credit_note, through: :credit_note_usage
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Joint model between credit notes and adjustments
|
2
|
+
#
|
3
|
+
module Stall
|
4
|
+
module Models
|
5
|
+
module CreditNoteUsage
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
self.table_name = 'stall_credit_note_usages'
|
10
|
+
|
11
|
+
belongs_to :credit_note
|
12
|
+
belongs_to :adjustment, class_name: 'CreditNoteAdjustment'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -8,23 +8,35 @@ module Stall
|
|
8
8
|
|
9
9
|
include Stall::Addressable
|
10
10
|
|
11
|
-
|
12
|
-
|
11
|
+
if Stall.config.default_user_model
|
12
|
+
belongs_to :user, polymorphic: true, inverse_of: :customer
|
13
|
+
accepts_nested_attributes_for :user
|
13
14
|
|
14
|
-
|
15
|
+
before_validation :ensure_user_email
|
16
|
+
end
|
15
17
|
|
16
|
-
|
17
|
-
|
18
|
+
has_many :product_lists, dependent: :destroy
|
19
|
+
has_many :credit_notes, dependent: :destroy
|
18
20
|
|
19
|
-
|
21
|
+
validates :email, presence: true,
|
22
|
+
format: { with: /\A[^@\s]+@([^@\s]+\.)+[^@\W]+\z/ }
|
20
23
|
|
21
24
|
def user_or_default
|
22
25
|
user || build_user
|
23
26
|
end
|
24
27
|
|
25
28
|
def build_user(attributes = {})
|
26
|
-
attributes.
|
27
|
-
|
29
|
+
(self.user = Stall.config.default_user_model.new(attributes)).tap do
|
30
|
+
user.customer = self if user.respond_to?(:customer)
|
31
|
+
end if Stall.config.default_user_model
|
32
|
+
end
|
33
|
+
|
34
|
+
def credit(currency = Stall.config.default_currency)
|
35
|
+
credit_notes.for_currency(currency).map(&:remaining_amount).sum
|
36
|
+
end
|
37
|
+
|
38
|
+
def credit?(currency = Stall.config.default_currency)
|
39
|
+
credit(currency).to_d > 0
|
28
40
|
end
|
29
41
|
|
30
42
|
private
|
@@ -27,6 +27,7 @@ module Stall
|
|
27
27
|
|
28
28
|
validate :stock_availability
|
29
29
|
|
30
|
+
before_validation :restore_valid_quantity
|
30
31
|
before_validation :refresh_total_prices
|
31
32
|
|
32
33
|
scope :ordered, -> { order(created_at: :asc) }
|
@@ -52,6 +53,14 @@ module Stall
|
|
52
53
|
self.eot_price = unit_eot_price * quantity if unit_eot_price && quantity
|
53
54
|
self.price = unit_price * quantity if unit_price && quantity
|
54
55
|
end
|
56
|
+
|
57
|
+
# Ensures that a quantity set to 0 to an existing line item doesn't return
|
58
|
+
# an error.
|
59
|
+
def restore_valid_quantity
|
60
|
+
if persisted? && quantity && (quantity < 1) && quantity_changed?
|
61
|
+
restore_quantity!
|
62
|
+
end
|
63
|
+
end
|
55
64
|
end
|
56
65
|
end
|
57
66
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Stall
|
2
|
+
module Models
|
3
|
+
module Product
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
self.table_name = 'stall_products'
|
8
|
+
|
9
|
+
acts_as_orderable
|
10
|
+
extend FriendlyId
|
11
|
+
friendly_id :name, use: [:slugged, :finders]
|
12
|
+
|
13
|
+
belongs_to :product_category
|
14
|
+
|
15
|
+
has_many :variants, dependent: :destroy, inverse_of: :product
|
16
|
+
accepts_nested_attributes_for :variants, allow_destroy: true
|
17
|
+
|
18
|
+
has_many :product_details, dependent: :destroy, inverse_of: :product
|
19
|
+
accepts_nested_attributes_for :product_details, allow_destroy: true
|
20
|
+
|
21
|
+
has_attached_file :image, styles: {
|
22
|
+
thumb: '100x100#',
|
23
|
+
show: '555x'
|
24
|
+
}
|
25
|
+
|
26
|
+
validates :name, :image, presence: true
|
27
|
+
validates_attachment :image, content_type: { content_type: /\Aimage\/.*\z/ }
|
28
|
+
|
29
|
+
scope :visible, -> { where(visible: true) }
|
30
|
+
|
31
|
+
def should_generate_new_friendly_id?
|
32
|
+
slug.blank?
|
33
|
+
end
|
34
|
+
|
35
|
+
def vat_rate
|
36
|
+
Stall.config.vat_rate
|
37
|
+
end
|
38
|
+
|
39
|
+
def price
|
40
|
+
variants.map(&:price).min
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Stall
|
2
|
+
module Models
|
3
|
+
module ProductCategory
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
self.table_name = 'stall_product_categories'
|
8
|
+
|
9
|
+
acts_as_tree order: 'position'
|
10
|
+
class_attribute :max_depth
|
11
|
+
|
12
|
+
extend FriendlyId
|
13
|
+
friendly_id :name, use: [:slugged, :finders]
|
14
|
+
|
15
|
+
has_many :products, dependent: :nullify
|
16
|
+
|
17
|
+
validates :name, presence: true
|
18
|
+
|
19
|
+
scope :ordered, -> { order(position: 'asc') }
|
20
|
+
|
21
|
+
def self.max_depth
|
22
|
+
2
|
23
|
+
end
|
24
|
+
|
25
|
+
def should_generate_new_friendly_id?
|
26
|
+
slug.blank?
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Stall
|
2
|
+
module Models
|
3
|
+
module ProductDetail
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
self.table_name = 'stall_product_details'
|
8
|
+
|
9
|
+
acts_as_orderable
|
10
|
+
|
11
|
+
belongs_to :product
|
12
|
+
|
13
|
+
validates :name, presence: true
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -6,7 +6,9 @@ module Stall
|
|
6
6
|
included do
|
7
7
|
self.table_name = 'stall_product_lists'
|
8
8
|
|
9
|
-
|
9
|
+
include Stall::DefaultCurrencyManager
|
10
|
+
include Stall::ReferenceManager
|
11
|
+
include Stall::TotalPricesManager
|
10
12
|
|
11
13
|
has_secure_token
|
12
14
|
|
@@ -16,13 +18,15 @@ module Stall
|
|
16
18
|
belongs_to :customer
|
17
19
|
accepts_nested_attributes_for :customer
|
18
20
|
|
21
|
+
has_many :generated_credit_notes, as: :source,
|
22
|
+
class_name: 'CreditNote',
|
23
|
+
dependent: :nullify
|
24
|
+
|
19
25
|
validates :type, presence: true
|
20
26
|
|
21
|
-
after_initialize :ensure_currency
|
22
27
|
after_initialize :ensure_state
|
23
28
|
|
24
29
|
before_save :save_customer_if_changed
|
25
|
-
after_save :ensure_reference, on: :create
|
26
30
|
|
27
31
|
scope :empty, -> {
|
28
32
|
joins(
|
@@ -52,27 +56,11 @@ module Stall
|
|
52
56
|
end
|
53
57
|
|
54
58
|
def subtotal
|
55
|
-
|
56
|
-
price = Money.new(price, currency) unless Money === price
|
57
|
-
price
|
59
|
+
ensure_money(line_items.map(&:price).sum)
|
58
60
|
end
|
59
61
|
|
60
62
|
def eot_subtotal
|
61
|
-
line_items.map(&:eot_price).sum
|
62
|
-
end
|
63
|
-
|
64
|
-
def total_price
|
65
|
-
price = items.map(&:price).sum
|
66
|
-
price = Money.new(price, currency) unless Money === price
|
67
|
-
price
|
68
|
-
end
|
69
|
-
|
70
|
-
def total_eot_price
|
71
|
-
items.map(&:eot_price).sum
|
72
|
-
end
|
73
|
-
|
74
|
-
def total_vat
|
75
|
-
items.map(&:vat).sum
|
63
|
+
ensure_money(line_items.map(&:eot_price).sum)
|
76
64
|
end
|
77
65
|
|
78
66
|
def total_quantity
|
@@ -91,20 +79,8 @@ module Stall
|
|
91
79
|
true
|
92
80
|
end
|
93
81
|
|
94
|
-
def currency
|
95
|
-
@currency ||= if (currency = read_attribute(:currency).presence)
|
96
|
-
Money::Currency.new(currency)
|
97
|
-
else
|
98
|
-
self.currency = Money.default_currency
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
82
|
private
|
103
83
|
|
104
|
-
def ensure_currency
|
105
|
-
self.currency ||= Money.default_currency
|
106
|
-
end
|
107
|
-
|
108
84
|
def ensure_state
|
109
85
|
self.state ||= (wizard.try(:steps).try(:first) || 'pending')
|
110
86
|
end
|
@@ -113,23 +89,11 @@ module Stall
|
|
113
89
|
line_items.to_a
|
114
90
|
end
|
115
91
|
|
116
|
-
def ensure_reference
|
117
|
-
unless reference.present?
|
118
|
-
reference = [Time.now.strftime('%Y%m%d'), ('%05d' % id)].join('-')
|
119
|
-
self.reference = reference
|
120
|
-
save(validate: false)
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
92
|
def save_customer_if_changed
|
125
93
|
customer.save if customer && customer.changed?
|
126
94
|
end
|
127
95
|
|
128
96
|
module ClassMethods
|
129
|
-
def find_by_reference(reference)
|
130
|
-
where("data->>'reference' = ?", reference).first
|
131
|
-
end
|
132
|
-
|
133
97
|
# The .aborted and .finalized scopes cannot be declared as actual rails
|
134
98
|
# scopes since subclasses that override the .wizard method wouldn't
|
135
99
|
# be taken into account, scopes being executed in the context of the
|