spree_core 5.1.0.beta4 → 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/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/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_method/store_credit.rb +1 -1
- data/app/models/spree/payment_method.rb +1 -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/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 +2 -2
- data/app/views/spree/addresses/_form.html.erb +1 -1
- data/app/views/spree/shared/_payment.html.erb +4 -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 +7 -1
- data/lib/spree/core/version.rb +1 -1
- data/lib/spree/core.rb +2 -1
- data/lib/spree/permitted_attributes.rb +22 -9
- 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/post_factory.rb +4 -0
- data/lib/spree/testing_support/factories/promotion_rule_factory.rb +4 -0
- data/lib/spree/testing_support/factories/user_factory.rb +2 -2
- metadata +45 -11
- data/config/initializers/state_machine.rb +0 -37
@@ -9,19 +9,13 @@ module Spree
|
|
9
9
|
include Spree::Webhooks::HasWebhooks
|
10
10
|
end
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
translates(*TRANSLATABLE_FIELDS)
|
15
|
-
else
|
16
|
-
TRANSLATABLE_FIELDS = %i[presentation].freeze
|
17
|
-
translates(*TRANSLATABLE_FIELDS, column_fallback: true)
|
18
|
-
end
|
12
|
+
TRANSLATABLE_FIELDS = %i[presentation].freeze
|
13
|
+
translates(*TRANSLATABLE_FIELDS, column_fallback: !Spree.always_use_translations?)
|
19
14
|
|
20
15
|
self::Translation.class_eval do
|
21
16
|
auto_strip_attributes :presentation
|
22
17
|
end
|
23
18
|
|
24
|
-
auto_strip_attributes :name, :presentation
|
25
19
|
acts_as_list
|
26
20
|
|
27
21
|
has_many :property_prototypes, class_name: 'Spree::PropertyPrototype'
|
@@ -49,7 +49,7 @@ module Spree
|
|
49
49
|
user: reimbursement.order.user,
|
50
50
|
amount: unpaid_amount,
|
51
51
|
category: category,
|
52
|
-
created_by:
|
52
|
+
created_by: reimbursement.order.store.users.first,
|
53
53
|
memo: "Refund for uncreditable payments on order #{reimbursement.order.number}",
|
54
54
|
currency: reimbursement.order.currency,
|
55
55
|
store: reimbursement.order.store
|
@@ -13,6 +13,10 @@ module Spree
|
|
13
13
|
@_return_quantity = value.to_i
|
14
14
|
end
|
15
15
|
|
16
|
+
def pre_tax_amount=(amount)
|
17
|
+
self[:pre_tax_amount] = Spree::LocalizedNumber.parse(amount)
|
18
|
+
end
|
19
|
+
|
16
20
|
def return_quantity
|
17
21
|
@_return_quantity.nil? ? inventory_unit.quantity : @_return_quantity
|
18
22
|
end
|
@@ -221,10 +221,27 @@ module Spree
|
|
221
221
|
inventory_units.where(line_item_id: line_item.id, variant_id: line_item.variant_id || variant.id)
|
222
222
|
end
|
223
223
|
|
224
|
+
# Returns the cost of the shipment
|
225
|
+
#
|
226
|
+
# @return [BigDecimal]
|
224
227
|
def item_cost
|
225
228
|
manifest.map { |m| (m.line_item.price + (m.line_item.adjustment_total / m.line_item.quantity)) * m.quantity }.sum
|
226
229
|
end
|
227
230
|
|
231
|
+
# Returns the weight of the shipment
|
232
|
+
#
|
233
|
+
# @return [BigDecimal]
|
234
|
+
def item_weight
|
235
|
+
manifest.map { |m| m.line_item.item_weight }.sum
|
236
|
+
end
|
237
|
+
|
238
|
+
# Returns the weight unit of the shipment
|
239
|
+
#
|
240
|
+
# @return [String]
|
241
|
+
def weight_unit
|
242
|
+
manifest.first.line_item.weight_unit
|
243
|
+
end
|
244
|
+
|
228
245
|
def line_items
|
229
246
|
inventory_units.includes(:line_item).map(&:line_item).uniq
|
230
247
|
end
|
@@ -416,6 +433,8 @@ module Spree
|
|
416
433
|
end
|
417
434
|
|
418
435
|
def can_get_rates?
|
436
|
+
return true unless order.requires_ship_address?
|
437
|
+
|
419
438
|
order.ship_address&.valid?
|
420
439
|
end
|
421
440
|
|
@@ -39,22 +39,21 @@ module Spree
|
|
39
39
|
joins(:calculator).where(spree_calculators: { type: Spree::Calculator::Shipping::DigitalDelivery.to_s })
|
40
40
|
}
|
41
41
|
|
42
|
-
|
43
|
-
# full text search
|
44
|
-
include PgSearch::Model
|
45
|
-
pg_search_scope :search_by_name, against: %i[name]
|
46
|
-
else
|
47
|
-
scope :search_by_name, ->(query) { where('name LIKE ?', "%#{query}%") }
|
48
|
-
end
|
42
|
+
scope :search_by_name, ->(query) { where(arel_table[:name].lower.matches("%#{query}%")) }
|
49
43
|
|
50
44
|
def include?(address)
|
45
|
+
return true unless requires_zone_check?
|
51
46
|
return false unless address
|
52
47
|
|
53
|
-
zones.includes(zone_members
|
48
|
+
zones.includes(:zone_members).any? do |zone|
|
54
49
|
zone.include?(address)
|
55
50
|
end
|
56
51
|
end
|
57
52
|
|
53
|
+
def requires_zone_check?
|
54
|
+
!calculator.is_a?(Spree::Calculator::Shipping::DigitalDelivery)
|
55
|
+
end
|
56
|
+
|
58
57
|
def build_tracking_url(tracking)
|
59
58
|
return if tracking.blank?
|
60
59
|
|
@@ -93,7 +92,7 @@ module Spree
|
|
93
92
|
if estimated_transit_business_days_min == estimated_transit_business_days_max
|
94
93
|
estimated_transit_business_days_min.to_s
|
95
94
|
else
|
96
|
-
|
95
|
+
[estimated_transit_business_days_min, estimated_transit_business_days_max].compact.join("-")
|
97
96
|
end
|
98
97
|
end
|
99
98
|
|
data/app/models/spree/store.rb
CHANGED
@@ -16,13 +16,12 @@ module Spree
|
|
16
16
|
AUTHORIZE_ACTION = 'authorize'.freeze
|
17
17
|
ALLOCATION_ACTION = 'allocation'.freeze
|
18
18
|
|
19
|
-
|
20
|
-
|
19
|
+
belongs_to :store, class_name: 'Spree::Store'
|
21
20
|
belongs_to :user, class_name: "::#{Spree.user_class}", foreign_key: 'user_id'
|
22
21
|
belongs_to :category, class_name: 'Spree::StoreCreditCategory', optional: true
|
23
22
|
belongs_to :created_by, class_name: "::#{Spree.admin_user_class}", foreign_key: 'created_by_id', optional: true
|
24
23
|
belongs_to :credit_type, class_name: 'Spree::StoreCreditType', foreign_key: 'type_id', optional: true
|
25
|
-
belongs_to :
|
24
|
+
belongs_to :originator, polymorphic: true, optional: true
|
26
25
|
|
27
26
|
has_many :store_credit_events, class_name: 'Spree::StoreCreditEvent'
|
28
27
|
has_many :payments, as: :source, class_name: 'Spree::Payment'
|
@@ -34,14 +33,16 @@ module Spree
|
|
34
33
|
validate :amount_used_less_than_or_equal_to_amount
|
35
34
|
validate :amount_authorized_less_than_or_equal_to_amount
|
36
35
|
|
37
|
-
delegate :name, to: :category, prefix: true
|
38
|
-
delegate :email, to: :created_by, prefix: true
|
36
|
+
delegate :name, to: :category, prefix: true, allow_nil: true
|
37
|
+
delegate :email, to: :created_by, prefix: true, allow_nil: true
|
39
38
|
|
40
39
|
scope :order_by_priority, -> { includes(:credit_type).order('spree_store_credit_types.priority ASC') }
|
41
40
|
|
42
41
|
scope :not_authorized, -> { where(amount_authorized: 0) }
|
43
42
|
scope :not_used, -> { where("#{Spree::StoreCredit.table_name}.amount_used < #{Spree::StoreCredit.table_name}.amount") }
|
44
43
|
scope :available, -> { not_authorized.not_used }
|
44
|
+
scope :with_gift_card, -> { where(originator_type: 'Spree::GiftCard') }
|
45
|
+
scope :without_gift_card, -> { where(originator_type: [nil, '']).or(where.not(originator_type: 'Spree::GiftCard')) }
|
45
46
|
|
46
47
|
after_save :store_event
|
47
48
|
before_destroy :validate_no_amount_used
|
@@ -184,7 +185,9 @@ module Spree
|
|
184
185
|
|
185
186
|
class << self
|
186
187
|
def default_created_by
|
187
|
-
Spree.
|
188
|
+
Spree::Deprecation.warn('StoreCredit#default_created_by is deprecated and will be removed in Spree 6.0. Please use store.users.first instead.')
|
189
|
+
|
190
|
+
Spree::Store.current.users.first
|
188
191
|
end
|
189
192
|
end
|
190
193
|
|
@@ -2,9 +2,15 @@ module Spree
|
|
2
2
|
class StoreCreditEvent < Spree.base_class
|
3
3
|
acts_as_paranoid
|
4
4
|
|
5
|
+
#
|
6
|
+
# Associations
|
5
7
|
belongs_to :store_credit
|
6
8
|
belongs_to :originator, polymorphic: true
|
9
|
+
has_one :payment, -> { where(source_type: Spree::StoreCredit.to_s) }, foreign_key: :response_code, primary_key: :authorization_code
|
10
|
+
has_one :order, through: :payment
|
7
11
|
|
12
|
+
#
|
13
|
+
# Scopes
|
8
14
|
scope :exposed_events, -> { where.not(action: [Spree::StoreCredit::ELIGIBLE_ACTION, Spree::StoreCredit::AUTHORIZE_ACTION]) }
|
9
15
|
scope :reverse_chronological, -> { order(created_at: :desc) }
|
10
16
|
|
@@ -21,15 +27,13 @@ module Spree
|
|
21
27
|
Spree.t('store_credit.authorized')
|
22
28
|
when Spree::StoreCredit::ALLOCATION_ACTION
|
23
29
|
Spree.t('store_credit.allocated')
|
30
|
+
when Spree::StoreCredit::ELIGIBLE_ACTION
|
31
|
+
Spree.t('store_credit.eligible')
|
24
32
|
when Spree::StoreCredit::VOID_ACTION, Spree::StoreCredit::CREDIT_ACTION
|
25
33
|
Spree.t('store_credit.credit')
|
26
34
|
end
|
27
35
|
end
|
28
36
|
|
29
|
-
def order
|
30
|
-
store.payments.find_by(response_code: authorization_code).try(:order)
|
31
|
-
end
|
32
|
-
|
33
37
|
def allocation?
|
34
38
|
action == Spree::StoreCredit::ALLOCATION_ACTION
|
35
39
|
end
|
data/app/models/spree/taxon.rb
CHANGED
@@ -17,10 +17,13 @@ module Spree
|
|
17
17
|
include Spree::TranslatableResource
|
18
18
|
include Spree::TranslatableResourceSlug
|
19
19
|
include Spree::Metadata
|
20
|
+
include Spree::MemoizedData
|
20
21
|
if defined?(Spree::Webhooks::HasWebhooks)
|
21
22
|
include Spree::Webhooks::HasWebhooks
|
22
23
|
end
|
23
24
|
|
25
|
+
MEMOIZED_METHODS = %w[cached_self_and_descendants_ids].freeze
|
26
|
+
|
24
27
|
#
|
25
28
|
# Magic methods
|
26
29
|
#
|
@@ -154,6 +157,10 @@ module Spree
|
|
154
157
|
sort_order == 'manual'
|
155
158
|
end
|
156
159
|
|
160
|
+
def page_builder_image
|
161
|
+
square_image.presence || image
|
162
|
+
end
|
163
|
+
|
157
164
|
def active_products_with_descendants
|
158
165
|
@active_products_with_descendants ||= store.products.
|
159
166
|
joins(:classifications).
|
@@ -368,7 +375,7 @@ module Spree
|
|
368
375
|
end
|
369
376
|
|
370
377
|
def cached_self_and_descendants_ids
|
371
|
-
Rails.cache.fetch("#{cache_key_with_version}/descendant-ids") do
|
378
|
+
@cached_self_and_descendants_ids ||= Rails.cache.fetch("#{cache_key_with_version}/descendant-ids") do
|
372
379
|
self_and_descendants.ids
|
373
380
|
end
|
374
381
|
end
|
data/app/models/spree/theme.rb
CHANGED
@@ -155,7 +155,7 @@ module Spree
|
|
155
155
|
end
|
156
156
|
end
|
157
157
|
|
158
|
-
# Returns an array of available layout section classes for the theme
|
158
|
+
# Returns an array of available layout section classes for the theme, eg. header, footer, newsletter, etc.
|
159
159
|
#
|
160
160
|
# @return [Array<Class>]
|
161
161
|
def available_layout_sections
|
data/app/models/spree/variant.rb
CHANGED
@@ -82,7 +82,7 @@ module Spree
|
|
82
82
|
|
83
83
|
after_touch :clear_in_stock_cache
|
84
84
|
|
85
|
-
scope :in_stock, -> { left_joins(:stock_items).where("#{Spree::
|
85
|
+
scope :in_stock, -> { left_joins(:stock_items).where("#{Spree::Variant.table_name}.track_inventory = ? OR #{Spree::StockItem.table_name}.count_on_hand > ?", false, 0) }
|
86
86
|
scope :backorderable, -> { left_joins(:stock_items).where(spree_stock_items: { backorderable: true }) }
|
87
87
|
scope :in_stock_or_backorderable, -> { in_stock.or(backorderable) }
|
88
88
|
|
@@ -1,6 +1,8 @@
|
|
1
1
|
module Spree
|
2
2
|
module CSV
|
3
3
|
class ProductVariantPresenter
|
4
|
+
include Spree::ImagesHelper
|
5
|
+
|
4
6
|
CSV_HEADERS = [
|
5
7
|
'product_id',
|
6
8
|
'sku',
|
@@ -99,9 +101,9 @@ module Spree
|
|
99
101
|
variant.backorderable?,
|
100
102
|
variant.tax_category&.name,
|
101
103
|
variant.digital?,
|
102
|
-
variant.images[0]
|
103
|
-
variant.images[1]
|
104
|
-
variant.images[2]
|
104
|
+
spree_image_url(variant.images[0], image_url_options),
|
105
|
+
spree_image_url(variant.images[1], image_url_options),
|
106
|
+
spree_image_url(variant.images[2], image_url_options),
|
105
107
|
index.positive? ? option_type(0)&.presentation : nil,
|
106
108
|
index.positive? ? option_value(option_type(0)) : nil,
|
107
109
|
index.positive? ? option_type(1)&.presentation : nil,
|
@@ -125,6 +127,15 @@ module Spree
|
|
125
127
|
def option_value(option_type)
|
126
128
|
variant.option_values.find { |ov| ov.option_type == option_type }&.presentation
|
127
129
|
end
|
130
|
+
|
131
|
+
private
|
132
|
+
|
133
|
+
def image_url_options
|
134
|
+
{
|
135
|
+
width: 1000,
|
136
|
+
height: 1000
|
137
|
+
}
|
138
|
+
end
|
128
139
|
end
|
129
140
|
end
|
130
141
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# This validator can be overridden to implement custom phone validation logic.
|
2
|
+
# Currently uses the phonelib gem to validate phone numbers and ensure they
|
3
|
+
# belong to the address country.
|
4
|
+
|
5
|
+
require 'phonelib'
|
6
|
+
|
7
|
+
module Spree
|
8
|
+
module Addresses
|
9
|
+
class PhoneValidator < ActiveModel::Validator
|
10
|
+
def validate(address)
|
11
|
+
return if !Spree::Config[:address_requires_phone] || address.phone.blank? || address.country.blank? || address.country_iso.blank?
|
12
|
+
|
13
|
+
phone = Phonelib.parse(address.phone)
|
14
|
+
unless phone.valid_for_country?(address.country_iso)
|
15
|
+
address.errors.add(:phone, :invalid)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -14,7 +14,7 @@ module Spree
|
|
14
14
|
private
|
15
15
|
|
16
16
|
def check_if_can_be_destroyed(order:)
|
17
|
-
return failure(false, Spree.t(:cannot_be_destroyed)) unless order&.
|
17
|
+
return failure(false, Spree.t(:cannot_be_destroyed)) unless order&.can_be_deleted?
|
18
18
|
|
19
19
|
success(order: order)
|
20
20
|
end
|
@@ -4,6 +4,7 @@ module Spree
|
|
4
4
|
prepend Spree::ServiceModule::Base
|
5
5
|
|
6
6
|
def call(order:, line_item:, line_item_created: false, options: {})
|
7
|
+
order.remove_gift_card if order.gift_card.present?
|
7
8
|
order_updater = ::Spree::OrderUpdater.new(order)
|
8
9
|
|
9
10
|
order.payments.store_credits.checkout.destroy_all
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Applies a gift card to an order
|
3
|
+
# under the hood it creates a store credit payment record and updates the gift card amount used
|
4
|
+
# @param gift_card [Spree::GiftCard] the gift card to apply
|
5
|
+
# @param order [Spree::Order] the order to apply the gift card to
|
6
|
+
# @return [Spree::Order] the order with the gift card applied
|
7
|
+
module Spree
|
8
|
+
module GiftCards
|
9
|
+
class Apply
|
10
|
+
prepend Spree::ServiceModule::Base
|
11
|
+
|
12
|
+
def call(gift_card:, order:)
|
13
|
+
# we shouldn't mix an order with a gift card and a store credit
|
14
|
+
return failure(:gift_card_using_store_credit_error) if order.using_store_credit?
|
15
|
+
|
16
|
+
# we shouldn't allow a gift card to be applied to an order with a different currency
|
17
|
+
return failure(:gift_card_mismatched_currency) if gift_card.currency != order.currency
|
18
|
+
|
19
|
+
amount = [gift_card.amount_remaining, order.total].min
|
20
|
+
store = order.store
|
21
|
+
|
22
|
+
return failure(:gift_card_no_amount_remaining) unless amount.positive? || order.total.zero?
|
23
|
+
|
24
|
+
payment_method = ensure_store_credit_payment_method!(store)
|
25
|
+
|
26
|
+
gift_card.lock!
|
27
|
+
order.with_lock do
|
28
|
+
store_credit = gift_card.store_credits.create!(
|
29
|
+
store: store,
|
30
|
+
user: order.user,
|
31
|
+
amount: amount,
|
32
|
+
currency: order.currency,
|
33
|
+
originator: gift_card,
|
34
|
+
action_originator: gift_card
|
35
|
+
)
|
36
|
+
gift_card.amount_used += amount
|
37
|
+
gift_card.save!
|
38
|
+
|
39
|
+
order.update!(gift_card: gift_card)
|
40
|
+
order.payments.create!(
|
41
|
+
source: store_credit,
|
42
|
+
payment_method: payment_method,
|
43
|
+
amount: amount,
|
44
|
+
state: 'checkout',
|
45
|
+
response_code: store_credit.generate_authorization_code
|
46
|
+
)
|
47
|
+
end
|
48
|
+
|
49
|
+
success(order.reload)
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def ensure_store_credit_payment_method!(store)
|
55
|
+
payment_method = store.payment_methods.find_or_initialize_by(
|
56
|
+
type: 'Spree::PaymentMethod::StoreCredit'
|
57
|
+
)
|
58
|
+
payment_method.name ||= Spree.t(:store_credit_name)
|
59
|
+
payment_method.active = true
|
60
|
+
payment_method.save! if payment_method.new_record?
|
61
|
+
|
62
|
+
payment_method
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Spree
|
2
|
+
module GiftCards
|
3
|
+
class Redeem
|
4
|
+
prepend Spree::ServiceModule::Base
|
5
|
+
|
6
|
+
def call(gift_card:)
|
7
|
+
if gift_card.amount_remaining.zero?
|
8
|
+
gift_card.redeem!
|
9
|
+
else
|
10
|
+
gift_card.partial_redeem!
|
11
|
+
end
|
12
|
+
|
13
|
+
success(gift_card)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Spree
|
2
|
+
module GiftCards
|
3
|
+
class Remove
|
4
|
+
prepend Spree::ServiceModule::Base
|
5
|
+
|
6
|
+
def call(order:)
|
7
|
+
return failure(:remove_gift_card_on_completed_order_error) if order.completed?
|
8
|
+
return success(true) if order.gift_card.nil?
|
9
|
+
|
10
|
+
gift_card = order.gift_card
|
11
|
+
|
12
|
+
return failure(:gift_card_not_found) if gift_card.nil?
|
13
|
+
|
14
|
+
order.with_lock do
|
15
|
+
payments = order.payments.checkout.store_credits.where(source: gift_card.store_credits)
|
16
|
+
payment_total = payments.sum(:amount)
|
17
|
+
payments.each(&:invalidate!)
|
18
|
+
|
19
|
+
gift_card.with_lock do
|
20
|
+
gift_card.amount_used -= payment_total
|
21
|
+
gift_card.save!
|
22
|
+
end
|
23
|
+
|
24
|
+
# we need to destroy the store credits here because they are not associated with the order
|
25
|
+
# and we need to remove them from the gift card
|
26
|
+
# TODO: rather than destroying the store credits, we should void them
|
27
|
+
payments.each do |payment|
|
28
|
+
payment.source.destroy!
|
29
|
+
end
|
30
|
+
|
31
|
+
order.update!(gift_card: nil)
|
32
|
+
end
|
33
|
+
|
34
|
+
success(true)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -141,10 +141,10 @@ module Spree
|
|
141
141
|
opt[:option_value_name]
|
142
142
|
else
|
143
143
|
opt[:option_value_presentation].parameterize
|
144
|
-
end
|
144
|
+
end.strip
|
145
145
|
|
146
146
|
option_value = option_type.option_values.where(name: option_value_identificator).first_or_initialize do |o|
|
147
|
-
o.
|
147
|
+
o.presentation = opt[:option_value_presentation]
|
148
148
|
o.save!
|
149
149
|
end
|
150
150
|
|
@@ -5,7 +5,7 @@
|
|
5
5
|
data-controller="address-form address-autocomplete"
|
6
6
|
data-address-form-countries-value="<%= available_countries.to_json %>"
|
7
7
|
data-address-form-states-value="<%= available_states.to_json %>"
|
8
|
-
data-address-form-current-state-id-value="<%= address.state_id %>"
|
8
|
+
data-address-form-current-state-id-value="<%= address.state_id || address_form.object.state_id %>"
|
9
9
|
>
|
10
10
|
<div id="<%= "#{address_id}country" %>">
|
11
11
|
<div class="form-group mb-0">
|
@@ -12,11 +12,11 @@
|
|
12
12
|
<p class="mb-0"><%= Spree.t(:expiration) %> <%= source.month %>/<%= source.year %></p>
|
13
13
|
</div>
|
14
14
|
<% elsif source.is_a?(Spree::StoreCredit) %>
|
15
|
-
<% if source.
|
16
|
-
<div class="d-flex
|
17
|
-
<%= icon('gift', height: 30, class: 'mr-3 text-muted') %>
|
15
|
+
<% if source.originator_type == 'Spree::GiftCard' %>
|
16
|
+
<div class="d-flex align-items-center">
|
17
|
+
<%= icon('gift', height: 30, class: 'mr-3 text-muted opacity-50') %>
|
18
18
|
<div>
|
19
|
-
<p class="mb-1"><%= Spree.t(:gift_card) %>: <strong><%= source.
|
19
|
+
<p class="mb-1"><%= Spree.t(:gift_card) %>: <strong><%= source.originator.code.upcase %></strong></p>
|
20
20
|
<%= @order.display_gift_card_total %>
|
21
21
|
</div>
|
22
22
|
</div>
|