spree_core 5.1.0.beta3 → 5.1.0.rc1
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/helpers/spree/base_helper.rb +6 -1
- data/app/helpers/spree/images_helper.rb +19 -16
- data/app/helpers/spree/shipment_helper.rb +12 -0
- data/app/jobs/spree/gift_cards/bulk_generate_job.rb +13 -0
- data/app/models/concerns/spree/parameterizable_name.rb +11 -0
- data/app/models/concerns/spree/payment_source_concern.rb +39 -0
- data/app/models/concerns/spree/product_scopes.rb +1 -5
- data/app/models/concerns/spree/stores/socials.rb +6 -2
- data/app/models/concerns/spree/user_methods.rb +2 -1
- data/app/models/spree/ability.rb +2 -0
- data/app/models/spree/address.rb +11 -3
- data/app/models/spree/credit_card.rb +2 -24
- data/app/models/spree/gateway/custom_payment_source_method.rb +33 -0
- data/app/models/spree/gift_card.rb +162 -0
- data/app/models/spree/gift_card_batch.rb +79 -0
- data/app/models/spree/inventory_unit.rb +11 -4
- data/app/models/spree/line_item.rb +13 -2
- data/app/models/spree/option_type.rb +5 -15
- data/app/models/spree/option_value.rb +18 -12
- data/app/models/spree/order/checkout.rb +2 -0
- data/app/models/spree/order/gift_card.rb +51 -0
- data/app/models/spree/order/store_credit.rb +20 -1
- data/app/models/spree/order.rb +51 -6
- data/app/models/spree/order_merger.rb +12 -0
- data/app/models/spree/page_sections/featured_posts.rb +4 -0
- data/app/models/spree/payment.rb +2 -1
- data/app/models/spree/payment_method/store_credit.rb +1 -1
- data/app/models/spree/payment_method.rb +1 -0
- data/app/models/spree/payment_source.rb +21 -0
- data/app/models/spree/post.rb +1 -0
- data/app/models/spree/price.rb +7 -1
- data/app/models/spree/product/slugs.rb +103 -0
- data/app/models/spree/product.rb +7 -81
- data/app/models/spree/product_property.rb +2 -2
- data/app/models/spree/promotion_handler/coupon.rb +39 -0
- data/app/models/spree/property.rb +2 -8
- data/app/models/spree/reimbursement_type/reimbursement_helpers.rb +1 -1
- data/app/models/spree/return_item.rb +4 -0
- data/app/models/spree/shipment.rb +19 -0
- data/app/models/spree/shipping_method.rb +8 -9
- data/app/models/spree/store.rb +2 -0
- data/app/models/spree/store_credit.rb +9 -6
- data/app/models/spree/store_credit_event.rb +8 -4
- data/app/models/spree/taxon.rb +8 -1
- data/app/models/spree/theme.rb +1 -1
- data/app/models/spree/variant.rb +1 -1
- data/app/models/spree/wishlist.rb +7 -0
- data/app/presenters/spree/csv/product_variant_presenter.rb +14 -3
- data/app/services/spree/addresses/phone_validator.rb +20 -0
- data/app/services/spree/cart/destroy.rb +1 -1
- data/app/services/spree/cart/recalculate.rb +1 -0
- data/app/services/spree/gift_cards/apply.rb +66 -0
- data/app/services/spree/gift_cards/redeem.rb +17 -0
- data/app/services/spree/gift_cards/remove.rb +38 -0
- data/app/services/spree/products/prepare_nested_attributes.rb +9 -2
- data/app/views/spree/addresses/_form.html.erb +1 -1
- data/app/views/spree/shared/_payment.html.erb +13 -4
- data/config/locales/en.yml +44 -14
- data/config/routes.rb +1 -0
- data/db/migrate/20250506073057_create_spree_gift_cards_and_spree_gift_card_batches.rb +37 -0
- data/db/migrate/20250530101236_enable_pg_trgm_extension.rb +13 -0
- data/db/migrate/20250605131334_add_missing_fields_to_users.rb +25 -0
- data/lib/generators/spree/install/install_generator.rb +0 -8
- data/lib/spree/core/configuration.rb +4 -0
- data/lib/spree/core/controller_helpers/store.rb +13 -1
- data/lib/spree/core/dependencies.rb +5 -0
- data/lib/spree/core/engine.rb +8 -1
- data/lib/spree/core/version.rb +1 -1
- data/lib/spree/core.rb +2 -1
- data/lib/spree/permitted_attributes.rb +23 -10
- data/lib/spree/testing_support/authorization_helpers.rb +5 -9
- data/lib/spree/testing_support/common_rake.rb +7 -1
- data/lib/spree/testing_support/factories/gift_card_batch_factory.rb +5 -0
- data/lib/spree/testing_support/factories/gift_card_factory.rb +17 -0
- data/lib/spree/testing_support/factories/page_section_factory.rb +2 -1
- data/lib/spree/testing_support/factories/payment_factory.rb +5 -0
- data/lib/spree/testing_support/factories/payment_method_factory.rb +5 -0
- data/lib/spree/testing_support/factories/payment_source_factory.rb +5 -0
- data/lib/spree/testing_support/factories/post_factory.rb +4 -0
- data/lib/spree/testing_support/factories/promotion_rule_factory.rb +4 -0
- data/lib/spree/testing_support/factories/theme_factory.rb +1 -1
- data/lib/spree/testing_support/factories/user_factory.rb +2 -2
- metadata +48 -11
- data/config/initializers/state_machine.rb +0 -37
@@ -48,7 +48,7 @@ module Spree
|
|
48
48
|
|
49
49
|
after_create :update_tax_charge
|
50
50
|
|
51
|
-
delegate :name, :description, :sku, :should_track_inventory?, :product, :options_text, :slug, :product_id, to: :variant
|
51
|
+
delegate :name, :description, :sku, :should_track_inventory?, :product, :options_text, :slug, :product_id, :dimensions_unit, :weight_unit, to: :variant
|
52
52
|
delegate :brand, :category, to: :product
|
53
53
|
delegate :tax_zone, to: :order
|
54
54
|
delegate :digital?, to: :variant
|
@@ -85,7 +85,7 @@ module Spree
|
|
85
85
|
extend DisplayMoney
|
86
86
|
money_methods :amount, :subtotal, :discounted_amount, :final_amount, :total, :price,
|
87
87
|
:adjustment_total, :additional_tax_total, :promo_total, :included_tax_total,
|
88
|
-
:pre_tax_amount, :shipping_cost, :tax_total
|
88
|
+
:pre_tax_amount, :shipping_cost, :tax_total, :compare_at_amount
|
89
89
|
|
90
90
|
alias single_money display_price
|
91
91
|
alias single_display_amount display_price
|
@@ -94,6 +94,10 @@ module Spree
|
|
94
94
|
price * quantity
|
95
95
|
end
|
96
96
|
|
97
|
+
def compare_at_amount
|
98
|
+
(variant.compare_at_amount_in(currency) || 0) * quantity
|
99
|
+
end
|
100
|
+
|
97
101
|
alias subtotal amount
|
98
102
|
|
99
103
|
def taxable_amount
|
@@ -114,6 +118,13 @@ module Spree
|
|
114
118
|
amount + adjustment_total
|
115
119
|
end
|
116
120
|
|
121
|
+
# Returns the weight of the line item
|
122
|
+
#
|
123
|
+
# @return [BigDecimal]
|
124
|
+
def item_weight
|
125
|
+
variant.weight * quantity
|
126
|
+
end
|
127
|
+
|
117
128
|
alias total final_amount
|
118
129
|
alias money display_total
|
119
130
|
|
@@ -10,12 +10,11 @@ module Spree
|
|
10
10
|
include Spree::Webhooks::HasWebhooks
|
11
11
|
end
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
translates(*TRANSLATABLE_FIELDS, column_fallback: true)
|
13
|
+
TRANSLATABLE_FIELDS = %i[presentation].freeze
|
14
|
+
translates(*TRANSLATABLE_FIELDS, column_fallback: !Spree.always_use_translations?)
|
15
|
+
|
16
|
+
self::Translation.class_eval do
|
17
|
+
auto_strip_attributes :presentation
|
19
18
|
end
|
20
19
|
|
21
20
|
#
|
@@ -23,7 +22,6 @@ module Spree
|
|
23
22
|
#
|
24
23
|
self.whitelisted_ransackable_scopes = %w[search_by_name]
|
25
24
|
acts_as_list
|
26
|
-
auto_strip_attributes :name, :presentation
|
27
25
|
|
28
26
|
#
|
29
27
|
# Associations
|
@@ -47,14 +45,6 @@ module Spree
|
|
47
45
|
scope :colors, -> { where(name: COLOR_NAMES) }
|
48
46
|
scope :filterable, -> { where(filterable: true) }
|
49
47
|
|
50
|
-
if defined?(PgSearch)
|
51
|
-
# full text search
|
52
|
-
include PgSearch::Model
|
53
|
-
pg_search_scope :search_by_name, against: %i[name presentation]
|
54
|
-
else
|
55
|
-
scope :search_by_name, ->(query) { where('name LIKE ?', "%#{query}%") }
|
56
|
-
end
|
57
|
-
|
58
48
|
#
|
59
49
|
# Attributes
|
60
50
|
#
|
@@ -7,19 +7,17 @@ module Spree
|
|
7
7
|
include Spree::Webhooks::HasWebhooks
|
8
8
|
end
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
translates(*TRANSLATABLE_FIELDS, column_fallback: true)
|
10
|
+
TRANSLATABLE_FIELDS = %i[presentation].freeze
|
11
|
+
translates(*TRANSLATABLE_FIELDS, column_fallback: !Spree.always_use_translations?)
|
12
|
+
|
13
|
+
self::Translation.class_eval do
|
14
|
+
auto_strip_attributes :presentation
|
16
15
|
end
|
17
16
|
|
18
17
|
#
|
19
18
|
# Magic methods
|
20
19
|
#
|
21
20
|
acts_as_list scope: :option_type
|
22
|
-
auto_strip_attributes :name, :presentation
|
23
21
|
self.whitelisted_ransackable_attributes = ['presentation']
|
24
22
|
|
25
23
|
#
|
@@ -48,8 +46,8 @@ module Spree
|
|
48
46
|
}
|
49
47
|
|
50
48
|
scope :for_products, lambda { |products|
|
51
|
-
|
52
|
-
|
49
|
+
# we need to use map(&:id) to avoid SQL errors when merging with other scopes
|
50
|
+
joins(:variants).where(Spree::Variant.table_name => { product_id: products.map(&:id) })
|
53
51
|
}
|
54
52
|
|
55
53
|
#
|
@@ -61,15 +59,23 @@ module Spree
|
|
61
59
|
|
62
60
|
delegate :name, :presentation, to: :option_type, prefix: true, allow_nil: true
|
63
61
|
|
62
|
+
# Using map here instead of pluck, as these values are translatable via Mobility gem
|
63
|
+
# @return [Array<Hash>]
|
64
64
|
def self.to_tom_select_json
|
65
|
-
all.
|
65
|
+
all.map do |ov|
|
66
66
|
{
|
67
|
-
id:
|
68
|
-
name: presentation
|
67
|
+
id: ov.name,
|
68
|
+
name: ov.presentation
|
69
69
|
}
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
73
|
+
# Returns the presentation with the option type presentation, eg. "Color: Red"
|
74
|
+
# @return [String]
|
75
|
+
def display_presentation
|
76
|
+
@display_presentation ||= "#{option_type.presentation}: #{presentation}"
|
77
|
+
end
|
78
|
+
|
73
79
|
private
|
74
80
|
|
75
81
|
def touch_all_variants
|
@@ -92,6 +92,7 @@ module Spree
|
|
92
92
|
after_transition to: :complete, do: :persist_user_credit_card
|
93
93
|
before_transition to: :payment, do: :set_shipments_cost
|
94
94
|
before_transition to: :payment, do: :create_tax_charge!
|
95
|
+
before_transition to: :payment, do: :recalculate_store_credit_payment
|
95
96
|
end
|
96
97
|
|
97
98
|
before_transition from: :cart, do: :ensure_line_items_present
|
@@ -118,6 +119,7 @@ module Spree
|
|
118
119
|
|
119
120
|
after_transition to: :complete, do: :finalize!
|
120
121
|
after_transition to: :complete, do: :use_all_coupon_codes
|
122
|
+
after_transition to: :complete, do: :redeem_gift_card
|
121
123
|
after_transition to: :resumed, do: :after_resume
|
122
124
|
after_transition to: :canceled, do: :after_cancel
|
123
125
|
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Spree
|
2
|
+
class Order < Spree.base_class
|
3
|
+
module GiftCard
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
# one GiftCard can be used on many orders, until it runs out
|
8
|
+
belongs_to :gift_card, class_name: 'Spree::GiftCard', optional: true
|
9
|
+
|
10
|
+
money_methods :gift_card_total
|
11
|
+
end
|
12
|
+
|
13
|
+
# Returns the total amount of the gift card applied to the order
|
14
|
+
# @return [Decimal]
|
15
|
+
def gift_card_total
|
16
|
+
return 0.to_d unless gift_card.present?
|
17
|
+
|
18
|
+
store_credit_ids = payments.store_credits.valid.pluck(:source_id)
|
19
|
+
store_credits = Spree::StoreCredit.where(id: store_credit_ids, originator: gift_card)
|
20
|
+
|
21
|
+
store_credits.sum(:amount)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Applies a gift card to the order
|
25
|
+
# @param gift_card [Spree::GiftCard] the gift card to apply
|
26
|
+
# @return [Spree::Order] the order with the gift card applied
|
27
|
+
def apply_gift_card(gift_card)
|
28
|
+
Spree::Dependencies.gift_card_apply_service.constantize.call(gift_card: gift_card, order: self)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Removes a gift card from the order
|
32
|
+
# @return [Spree::Order] the order with the gift card removed
|
33
|
+
def remove_gift_card
|
34
|
+
Spree::Dependencies.gift_card_remove_service.constantize.call(order: self)
|
35
|
+
end
|
36
|
+
|
37
|
+
def recalculate_gift_card
|
38
|
+
applied_gift_card = gift_card
|
39
|
+
|
40
|
+
remove_gift_card
|
41
|
+
apply_gift_card(applied_gift_card)
|
42
|
+
end
|
43
|
+
|
44
|
+
def redeem_gift_card
|
45
|
+
return unless gift_card.present?
|
46
|
+
|
47
|
+
Spree::Dependencies.gift_card_redeem_service.constantize.call(gift_card: gift_card)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -14,12 +14,19 @@ module Spree
|
|
14
14
|
end
|
15
15
|
alias covered_by_store_credit covered_by_store_credit?
|
16
16
|
|
17
|
+
# Returns the total amount of store credits available to the user associated with the order.
|
18
|
+
# Returns only store credit for this store and same currency as order
|
19
|
+
#
|
20
|
+
# @return [BigDecimal] The total amount of store credits available to the user associated with the order.
|
17
21
|
def total_available_store_credit
|
18
22
|
return 0.0 unless user
|
19
23
|
|
20
24
|
user.total_available_store_credit(currency, store)
|
21
25
|
end
|
22
26
|
|
27
|
+
# Returns the available store credits for the user associated with the order.
|
28
|
+
#
|
29
|
+
# @return [Array<Spree::StoreCredit>] The available store credits for the user associated with the order.
|
23
30
|
def available_store_credits
|
24
31
|
return Spree::StoreCredit.none if user.nil?
|
25
32
|
|
@@ -27,15 +34,21 @@ module Spree
|
|
27
34
|
end
|
28
35
|
|
29
36
|
def could_use_store_credit?
|
30
|
-
return false if
|
37
|
+
return false if store.payment_methods.store_credit.available.empty?
|
31
38
|
|
32
39
|
total_available_store_credit > 0
|
33
40
|
end
|
34
41
|
|
42
|
+
# Returns the total amount of the order minus the total amount of store credits applied to the order.
|
43
|
+
#
|
44
|
+
# @return [BigDecimal] The total amount of the order minus the total amount of store credits applied to the order.
|
35
45
|
def order_total_after_store_credit
|
36
46
|
total - total_applicable_store_credit
|
37
47
|
end
|
38
48
|
|
49
|
+
# Returns the total amount of the order minus the total amount of store credits applied to the order.
|
50
|
+
#
|
51
|
+
# @return [BigDecimal] The total amount of the order minus the total amount of store credits applied to the order.
|
39
52
|
def total_minus_store_credits
|
40
53
|
total - total_applied_store_credit
|
41
54
|
end
|
@@ -48,10 +61,16 @@ module Spree
|
|
48
61
|
end
|
49
62
|
end
|
50
63
|
|
64
|
+
# Returns the total amount of store credits applied to the order.
|
65
|
+
#
|
66
|
+
# @return [BigDecimal] The total amount of store credits applied to the order.
|
51
67
|
def total_applied_store_credit
|
52
68
|
payments.store_credits.valid.sum(:amount)
|
53
69
|
end
|
54
70
|
|
71
|
+
# Returns true if the order is using store credit.
|
72
|
+
#
|
73
|
+
# @return [Boolean] True if the order is using store credit, false otherwise.
|
55
74
|
def using_store_credit?
|
56
75
|
total_applied_store_credit > 0
|
57
76
|
end
|
data/app/models/spree/order.rb
CHANGED
@@ -4,6 +4,7 @@ require_dependency 'spree/order/digital'
|
|
4
4
|
require_dependency 'spree/order/payments'
|
5
5
|
require_dependency 'spree/order/store_credit'
|
6
6
|
require_dependency 'spree/order/emails'
|
7
|
+
require_dependency 'spree/order/gift_card'
|
7
8
|
|
8
9
|
module Spree
|
9
10
|
class Order < Spree.base_class
|
@@ -11,6 +12,8 @@ module Spree
|
|
11
12
|
SHIPMENT_STATES = %w(backorder canceled partial pending ready shipped)
|
12
13
|
LINE_ITEM_REMOVABLE_STATES = %w(cart address delivery payment confirm resumed)
|
13
14
|
|
15
|
+
extend Spree::DisplayMoney
|
16
|
+
|
14
17
|
include Spree::Order::Checkout
|
15
18
|
include Spree::Order::CurrencyUpdater
|
16
19
|
include Spree::Order::Digital
|
@@ -20,6 +23,7 @@ module Spree
|
|
20
23
|
include Spree::Order::Emails
|
21
24
|
include Spree::Order::Webhooks
|
22
25
|
include Spree::Core::NumberGenerator.new(prefix: 'R')
|
26
|
+
include Spree::Order::GiftCard
|
23
27
|
|
24
28
|
include Spree::NumberIdentifier
|
25
29
|
include Spree::NumberAsParam
|
@@ -38,7 +42,6 @@ module Spree
|
|
38
42
|
|
39
43
|
MEMOIZED_METHODS = %w(tax_zone)
|
40
44
|
|
41
|
-
extend Spree::DisplayMoney
|
42
45
|
money_methods :outstanding_balance, :item_total, :adjustment_total,
|
43
46
|
:included_tax_total, :additional_tax_total, :tax_total,
|
44
47
|
:shipment_total, :promo_total, :total,
|
@@ -313,10 +316,28 @@ module Spree
|
|
313
316
|
shipments.any?(&:backordered?)
|
314
317
|
end
|
315
318
|
|
319
|
+
# Check if the shipping address is a quick checkout address
|
320
|
+
# quick checkout addresses are incomplete as wallet providers like Apple Pay and Google Pay
|
321
|
+
# do not provide all the address fields until the checkout is completed (confirmed) on their side
|
322
|
+
# @return [Boolean]
|
316
323
|
def quick_checkout?
|
317
324
|
shipping_address.present? && shipping_address.quick_checkout?
|
318
325
|
end
|
319
326
|
|
327
|
+
# Check if quick checkout is available for this order
|
328
|
+
# Either fully digital or not digital at all
|
329
|
+
# @return [Boolean]
|
330
|
+
def quick_checkout_available?
|
331
|
+
payment_required? && shipments.count <= 1 && (digital? || !some_digital? || !delivery_required?)
|
332
|
+
end
|
333
|
+
|
334
|
+
# Check if quick checkout requires an address collection
|
335
|
+
# If the order is digital or not delivery required, then we don't need to collect an address
|
336
|
+
# @return [Boolean]
|
337
|
+
def quick_checkout_require_address?
|
338
|
+
!digital? && delivery_required?
|
339
|
+
end
|
340
|
+
|
320
341
|
# Returns the relevant zone (if any) to be used for taxation purposes.
|
321
342
|
# Uses default tax zone unless there is a specific match
|
322
343
|
def tax_zone
|
@@ -631,7 +652,7 @@ module Spree
|
|
631
652
|
#
|
632
653
|
# @return [BigDecimal] the total weight of the inventory units in the order
|
633
654
|
def total_weight
|
634
|
-
@total_weight ||= line_items.joins(:variant).includes(:variant).map
|
655
|
+
@total_weight ||= line_items.joins(:variant).includes(:variant).map(&:item_weight).sum
|
635
656
|
end
|
636
657
|
|
637
658
|
# Returns line items that have no shipping rates
|
@@ -742,6 +763,11 @@ module Spree
|
|
742
763
|
end
|
743
764
|
|
744
765
|
def can_be_destroyed?
|
766
|
+
Spree::Deprecation.warn('Spree::Order#can_be_destroyed? is deprecated and will be removed in the next major version. Use Spree::Order#can_be_deleted? instead.')
|
767
|
+
can_be_deleted?
|
768
|
+
end
|
769
|
+
|
770
|
+
def can_be_deleted?
|
745
771
|
!completed? && payments.completed.empty?
|
746
772
|
end
|
747
773
|
|
@@ -834,6 +860,10 @@ module Spree
|
|
834
860
|
line_items
|
835
861
|
end
|
836
862
|
|
863
|
+
def requires_ship_address?
|
864
|
+
!digital?
|
865
|
+
end
|
866
|
+
|
837
867
|
private
|
838
868
|
|
839
869
|
def link_by_email
|
@@ -870,10 +900,15 @@ module Spree
|
|
870
900
|
|
871
901
|
def after_cancel
|
872
902
|
shipments.each(&:cancel!)
|
873
|
-
payments.completed.each(&:cancel!)
|
874
903
|
|
875
|
-
#
|
876
|
-
|
904
|
+
# payments fully covered by gift card won't be refunded
|
905
|
+
# we want to only void the payment
|
906
|
+
if gift_card.present? && covered_by_store_credit?
|
907
|
+
payments.completed.store_credits.each(&:void!)
|
908
|
+
else
|
909
|
+
payments.completed.each(&:cancel!)
|
910
|
+
payments.store_credits.pending.each(&:void!)
|
911
|
+
end
|
877
912
|
|
878
913
|
send_cancel_email
|
879
914
|
update_with_updater!
|
@@ -895,7 +930,7 @@ module Spree
|
|
895
930
|
end
|
896
931
|
|
897
932
|
def ensure_currency_presence
|
898
|
-
self.currency ||= store
|
933
|
+
self.currency ||= store&.default_currency
|
899
934
|
end
|
900
935
|
|
901
936
|
def collect_payment_methods(store = nil)
|
@@ -911,5 +946,15 @@ module Spree
|
|
911
946
|
def credit_card_nil_payment?(attributes)
|
912
947
|
payments.store_credits.present? && attributes[:amount].to_f.zero?
|
913
948
|
end
|
949
|
+
|
950
|
+
def recalculate_store_credit_payment
|
951
|
+
updater.update_adjustment_total if using_store_credit?
|
952
|
+
|
953
|
+
if gift_card.present?
|
954
|
+
recalculate_gift_card
|
955
|
+
elsif using_store_credit?
|
956
|
+
Spree::Dependencies.checkout_add_store_credit_service.constantize.call(order: self)
|
957
|
+
end
|
958
|
+
end
|
914
959
|
end
|
915
960
|
end
|
@@ -8,6 +8,7 @@ module Spree
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def merge!(other_order, user = nil, discard_merged: true)
|
11
|
+
handle_gift_card(other_order)
|
11
12
|
other_order.line_items.each do |other_order_line_item|
|
12
13
|
next unless other_order_line_item.currency == order.currency
|
13
14
|
|
@@ -26,6 +27,8 @@ module Spree
|
|
26
27
|
end
|
27
28
|
end
|
28
29
|
|
30
|
+
private
|
31
|
+
|
29
32
|
# Compare the line item of the other order with mine.
|
30
33
|
# Make sure you allow any extensions to chime in on whether or
|
31
34
|
# not the extension-specific parts of the line item match
|
@@ -70,5 +73,14 @@ module Spree
|
|
70
73
|
updater.update_item_total
|
71
74
|
updater.persist_totals
|
72
75
|
end
|
76
|
+
|
77
|
+
def handle_gift_card(other_order)
|
78
|
+
return unless other_order.gift_card.present?
|
79
|
+
|
80
|
+
gift_card = other_order.gift_card
|
81
|
+
|
82
|
+
other_order.remove_gift_card
|
83
|
+
order.apply_gift_card(gift_card)
|
84
|
+
end
|
73
85
|
end
|
74
86
|
end
|
data/app/models/spree/payment.rb
CHANGED
@@ -302,7 +302,8 @@ module Spree
|
|
302
302
|
# Payment profile cannot be created without source
|
303
303
|
return unless source
|
304
304
|
# Imported payments shouldn't create a payment profile.
|
305
|
-
|
305
|
+
# Imported is only available on Spree::CreditCard, non-credit card payments should not have this attribute.
|
306
|
+
return if source.respond_to?(:imported) && source.imported
|
306
307
|
|
307
308
|
payment_method.create_profile(self)
|
308
309
|
rescue ActiveMerchant::ConnectionError => e
|
@@ -12,6 +12,7 @@ module Spree
|
|
12
12
|
|
13
13
|
scope :active, -> { where(active: true).order(position: :asc) }
|
14
14
|
scope :available, -> { active.where(display_on: [:front_end, :back_end, :both]) }
|
15
|
+
scope :store_credit, -> { where(type: 'Spree::PaymentMethod::StoreCredit') }
|
15
16
|
|
16
17
|
after_initialize :set_name, if: :new_record?
|
17
18
|
|
@@ -1,10 +1,31 @@
|
|
1
|
+
# This model is used to store payment sources for non-credit card payments, eg wallet, account, etc.
|
1
2
|
module Spree
|
2
3
|
class PaymentSource < Spree.base_class
|
3
4
|
include Spree::Metadata
|
5
|
+
include Spree::PaymentSourceConcern
|
4
6
|
|
7
|
+
#
|
8
|
+
# Associations
|
9
|
+
#
|
5
10
|
belongs_to :payment_method, class_name: 'Spree::PaymentMethod'
|
6
11
|
belongs_to :user, class_name: Spree.user_class.to_s, optional: true
|
7
12
|
|
13
|
+
#
|
14
|
+
# Validations
|
15
|
+
#
|
8
16
|
validates_uniqueness_of :gateway_payment_profile_id, scope: :type
|
17
|
+
|
18
|
+
#
|
19
|
+
# Delegations
|
20
|
+
#
|
21
|
+
delegate :profile_id, to: :gateway_customer, prefix: true, allow_nil: true
|
22
|
+
|
23
|
+
# Returns the gateway customer for the user.
|
24
|
+
# @return [Spree::GatewayCustomer]
|
25
|
+
def gateway_customer
|
26
|
+
return if user.blank?
|
27
|
+
|
28
|
+
payment_method.gateway_customers.find_by(user: user)
|
29
|
+
end
|
9
30
|
end
|
10
31
|
end
|
data/app/models/spree/post.rb
CHANGED
@@ -54,6 +54,7 @@ module Spree
|
|
54
54
|
# Scopes
|
55
55
|
#
|
56
56
|
scope :published, -> { where(published_at: [..Time.current]) }
|
57
|
+
scope :by_newest, -> { order(created_at: :desc) }
|
57
58
|
|
58
59
|
delegate :name, to: :author, prefix: true, allow_nil: true
|
59
60
|
delegate :title, to: :post_category, prefix: true, allow_nil: true
|
data/app/models/spree/price.rb
CHANGED
@@ -36,7 +36,13 @@ module Spree
|
|
36
36
|
scope :with_currency, ->(currency) { where(currency: currency) }
|
37
37
|
scope :non_zero, -> { where.not(amount: [nil, 0]) }
|
38
38
|
scope :discounted, -> { where('compare_at_amount > amount') }
|
39
|
-
scope :for_products, ->(products
|
39
|
+
scope :for_products, ->(products, currency = nil) do
|
40
|
+
currency ||= Spree::Store.default.default_currency
|
41
|
+
|
42
|
+
with_currency(currency).joins(:variant).where(
|
43
|
+
Spree::Variant.table_name => { product_id: products }
|
44
|
+
)
|
45
|
+
end
|
40
46
|
|
41
47
|
extend DisplayMoney
|
42
48
|
money_methods :amount, :price, :compare_at_amount
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module Spree
|
2
|
+
class Product < Spree.base_class
|
3
|
+
module Slugs
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
extend FriendlyId
|
8
|
+
include Spree::TranslatableResourceSlug
|
9
|
+
|
10
|
+
translates :slug
|
11
|
+
friendly_id :slug_candidates, use: [:history, :slugged, :scoped, :mobility], scope: spree_base_uniqueness_scope, slug_limit: 255
|
12
|
+
|
13
|
+
Product::Translation.class_eval do
|
14
|
+
before_save :set_slug
|
15
|
+
acts_as_paranoid
|
16
|
+
# deleted translation values also need to be accessible for index views listing deleted resources
|
17
|
+
default_scope { unscope(where: :deleted_at) }
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def set_slug
|
22
|
+
self.slug = generate_slug
|
23
|
+
end
|
24
|
+
|
25
|
+
def generate_slug
|
26
|
+
if name.blank? && slug.blank?
|
27
|
+
translated_model.name.to_url
|
28
|
+
elsif slug.blank?
|
29
|
+
name.to_url
|
30
|
+
else
|
31
|
+
slug.to_url
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
before_validation :downcase_slug
|
37
|
+
before_validation :normalize_slug, on: :update
|
38
|
+
after_destroy :punch_slugs
|
39
|
+
after_restore :regenerate_slug
|
40
|
+
|
41
|
+
validates :slug, presence: true, uniqueness: { allow_blank: true, case_sensitive: true, scope: spree_base_uniqueness_scope }
|
42
|
+
|
43
|
+
def self.slug_available?(slug, id)
|
44
|
+
!where(slug: slug).where.not(id: id).exists?
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def ensure_slug_is_unique(candidate_slug)
|
49
|
+
return slug if candidate_slug.blank? || slug.blank?
|
50
|
+
return candidate_slug if self.class.slug_available?(candidate_slug, id)
|
51
|
+
|
52
|
+
normalize_friendly_id([candidate_slug, uuid_for_friendly_id])
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def slug_candidates
|
58
|
+
if defined?(:deleted_at) && deleted_at.present?
|
59
|
+
[
|
60
|
+
['deleted', :name],
|
61
|
+
['deleted', :name, :sku],
|
62
|
+
['deleted', :name, :uuid_for_friendly_id]
|
63
|
+
]
|
64
|
+
else
|
65
|
+
[
|
66
|
+
[:name],
|
67
|
+
[:name, :sku],
|
68
|
+
[:name, :uuid_for_friendly_id]
|
69
|
+
]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def downcase_slug
|
74
|
+
slug&.downcase!
|
75
|
+
end
|
76
|
+
|
77
|
+
def normalize_slug
|
78
|
+
self.slug = normalize_friendly_id(slug)
|
79
|
+
end
|
80
|
+
|
81
|
+
def regenerate_slug
|
82
|
+
self.slug = nil
|
83
|
+
save!
|
84
|
+
end
|
85
|
+
|
86
|
+
def punch_slugs
|
87
|
+
return if new_record? || frozen?
|
88
|
+
|
89
|
+
self.slug = nil
|
90
|
+
|
91
|
+
set_slug
|
92
|
+
update_column(:slug, slug)
|
93
|
+
|
94
|
+
new_slug = ->(rec) { "deleted-#{rec.id}_#{rec.slug}"[..254] }
|
95
|
+
|
96
|
+
translations.with_deleted.each { |rec| rec.update_columns(slug: new_slug.call(rec)) }
|
97
|
+
slugs.with_deleted.each { |rec| rec.update_column(:slug, new_slug.call(rec)) }
|
98
|
+
|
99
|
+
translations.find_by!(locale: I18n.locale).update_column(:slug, slug) if Spree.use_translations?
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|