spree_core 4.8.3 → 4.9.0
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/finders/spree/line_items/find_by_variant.rb +4 -2
- data/app/finders/spree/products/find.rb +1 -1
- data/app/finders/spree/variants/find.rb +30 -0
- data/app/models/spree/address.rb +12 -2
- data/app/models/spree/adjustment.rb +5 -0
- data/app/models/spree/asset.rb +8 -0
- data/app/models/spree/calculator/flat_rate.rb +3 -0
- data/app/models/spree/calculator/flexi_rate.rb +3 -0
- data/app/models/spree/calculator/percent_on_line_item.rb +3 -0
- data/app/models/spree/calculator/shipping/flat_rate.rb +13 -1
- data/app/models/spree/cms_section_image.rb +0 -6
- data/app/models/spree/customer_return.rb +1 -0
- data/app/models/spree/icon.rb +0 -6
- data/app/models/spree/image/configuration/active_storage.rb +0 -8
- data/app/models/spree/image.rb +17 -0
- data/app/models/spree/line_item.rb +23 -6
- data/app/models/spree/option_value_variant.rb +4 -0
- data/app/models/spree/order/currency_updater.rb +2 -2
- data/app/models/spree/order/webhooks.rb +19 -0
- data/app/models/spree/order.rb +17 -6
- data/app/models/spree/order_merger.rb +6 -0
- data/app/models/spree/payment/gateway_options.rb +4 -0
- data/app/models/spree/payment/webhooks.rb +15 -0
- data/app/models/spree/payment.rb +7 -7
- data/app/models/spree/price.rb +45 -0
- data/app/models/spree/product/webhooks.rb +17 -0
- data/app/models/spree/product.rb +7 -9
- data/app/models/spree/promotion/actions/free_shipping.rb +13 -0
- data/app/models/spree/promotion/rules/first_order.rb +6 -1
- data/app/models/spree/promotion.rb +2 -2
- data/app/models/spree/promotion_handler/coupon.rb +3 -2
- data/app/models/spree/refund.rb +14 -2
- data/app/models/spree/reimbursement/emails.rb +11 -0
- data/app/models/spree/reimbursement.rb +1 -6
- data/app/models/spree/role_user.rb +1 -1
- data/app/models/spree/shipment/emails.rb +11 -0
- data/app/models/spree/shipment/webhooks.rb +11 -0
- data/app/models/spree/shipment.rb +58 -7
- data/app/models/spree/shipment_handler.rb +2 -6
- data/app/models/spree/shipping_method.rb +6 -0
- data/app/models/spree/shipping_method_zone.rb +4 -2
- data/app/models/spree/shipping_rate.rb +1 -1
- data/app/models/spree/stock/package.rb +4 -0
- data/app/models/spree/stock/quantifier.rb +22 -4
- data/app/models/spree/stock_item/webhooks.rb +6 -0
- data/app/models/spree/stock_item.rb +1 -3
- data/app/models/spree/stock_location.rb +15 -0
- data/app/models/spree/stock_movement/webhooks.rb +6 -0
- data/app/models/spree/stock_movement.rb +1 -3
- data/app/models/spree/store.rb +1 -5
- data/app/models/spree/store_credit.rb +11 -12
- data/app/models/spree/store_favicon_image.rb +0 -6
- data/app/models/spree/store_logo.rb +0 -5
- data/app/models/spree/store_mailer_logo.rb +0 -6
- data/app/models/spree/tax_rate.rb +3 -1
- data/app/models/spree/taxon_image/configuration/active_storage.rb +0 -6
- data/app/models/spree/variant/webhooks.rb +6 -0
- data/app/models/spree/variant.rb +21 -3
- data/app/models/spree/wishlist.rb +9 -0
- data/app/presenters/spree/variants/options_presenter.rb +34 -2
- data/app/services/spree/cart/add_item.rb +2 -0
- data/app/services/spree/cart/destroy.rb +14 -4
- data/app/services/spree/seeds/all.rb +3 -0
- data/app/services/spree/seeds/payment_methods.rb +18 -0
- data/app/services/spree/seeds/stock_locations.rb +1 -1
- data/app/services/spree/seeds/zones.rb +19 -19
- data/config/locales/en.yml +2 -0
- data/db/migrate/20240623172111_add_deleted_at_to_spree_stock_locations.rb +6 -0
- data/db/migrate/20240725124530_add_refunder_to_spree_refunds.rb +6 -0
- data/lib/spree/core/controller_helpers/order.rb +5 -5
- data/lib/spree/core/dependencies.rb +2 -1
- data/lib/spree/core/preferences/preferable.rb +4 -2
- data/lib/spree/core/preferences/preferable_class_methods.rb +3 -2
- data/lib/spree/core/version.rb +1 -1
- data/lib/spree/core/webhooks.rb +15 -7
- data/lib/spree/core.rb +1 -0
- data/lib/spree/money.rb +1 -1
- data/lib/spree/testing_support/authorization_helpers.rb +2 -2
- data/lib/spree/testing_support/common_rake.rb +1 -1
- data/spree_core.gemspec +1 -0
- metadata +31 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3966d98b01b3e3ac7e23384c37933bfd0cd961d05a112b6b538e3973bf62e0df
|
4
|
+
data.tar.gz: d1305f1376e401557ae786799c862ab927c4aa26986cb444bdd8db4230d92cd8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 768f2fb6195ca9528398233360ab1f4b7be974e7fa5999ba32a5aa53b89d52bcce93ef252dd45ba7bd627ea329e5ebb9e11200dea6fecdb494c45078b2a97e88
|
7
|
+
data.tar.gz: 1a3c031451d48a9fd021eb0529e942db6adcd732a9e558c7fdefd7574c749192982cece0854678a198489512d421e22aa466bdd958f240d8bc5af23a4de9d240
|
@@ -2,11 +2,13 @@ module Spree
|
|
2
2
|
module LineItems
|
3
3
|
class FindByVariant
|
4
4
|
def execute(order:, variant:, options: {})
|
5
|
-
order.line_items.detect
|
6
|
-
next unless line_item.variant_id == variant.id
|
5
|
+
line_item = order.line_items.loaded? ? order.line_items.detect { |li| li.variant_id == variant.id } : order.line_items.find_by(variant_id: variant.id)
|
7
6
|
|
7
|
+
if line_item
|
8
8
|
Spree::Dependencies.cart_compare_line_items_service.constantize.call(order: order, line_item: line_item, options: options).value
|
9
9
|
end
|
10
|
+
|
11
|
+
line_item
|
10
12
|
end
|
11
13
|
end
|
12
14
|
end
|
@@ -263,7 +263,7 @@ module Spree
|
|
263
263
|
def taxon_ids(taxons_ids)
|
264
264
|
return if taxons_ids.nil? || taxons_ids.to_s.blank?
|
265
265
|
|
266
|
-
taxons = store.
|
266
|
+
taxons = Spree::Taxon.for_store(store).where(id: taxons_ids.to_s.split(','))
|
267
267
|
taxons.map(&:cached_self_and_descendants_ids).flatten.compact.uniq.map(&:to_s)
|
268
268
|
end
|
269
269
|
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Spree
|
2
|
+
module Variants
|
3
|
+
class Find
|
4
|
+
def initialize(scope:, params:)
|
5
|
+
@scope = scope
|
6
|
+
@options = params.dig(:filter, :options).try(:to_unsafe_hash)
|
7
|
+
end
|
8
|
+
|
9
|
+
def execute
|
10
|
+
variants = by_options(scope)
|
11
|
+
variants.distinct
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
attr_reader :scope, :options
|
17
|
+
|
18
|
+
def options?
|
19
|
+
options.present?
|
20
|
+
end
|
21
|
+
|
22
|
+
def by_options(variants)
|
23
|
+
return variants unless options?
|
24
|
+
|
25
|
+
variants_ids = options.map { |key, value| variants.with_option_value(key, value)&.ids }.compact.uniq
|
26
|
+
variants.where(id: variants_ids.reduce(&:intersection))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/app/models/spree/address.rb
CHANGED
@@ -46,7 +46,9 @@ module Spree
|
|
46
46
|
before_validation :clear_invalid_state_entities, if: -> { country.present? }, on: :update
|
47
47
|
|
48
48
|
with_options presence: true do
|
49
|
-
validates :firstname, :lastname, :
|
49
|
+
validates :firstname, :lastname, if: :require_name?
|
50
|
+
validates :address1, if: :require_street?
|
51
|
+
validates :city, :country
|
50
52
|
validates :zipcode, if: :require_zipcode?
|
51
53
|
validates :phone, if: :require_phone?
|
52
54
|
end
|
@@ -137,12 +139,20 @@ module Spree
|
|
137
139
|
country ? country.zipcode_required? : true
|
138
140
|
end
|
139
141
|
|
142
|
+
def require_name?
|
143
|
+
true
|
144
|
+
end
|
145
|
+
|
146
|
+
def require_street?
|
147
|
+
true
|
148
|
+
end
|
149
|
+
|
140
150
|
def editable?
|
141
151
|
new_record? || (shipments.empty? && !Order.complete.where('bill_address_id = ? OR ship_address_id = ?', id, id).exists?)
|
142
152
|
end
|
143
153
|
|
144
154
|
def can_be_deleted?
|
145
|
-
shipments.empty? && !Order.where('bill_address_id = ? OR ship_address_id = ?', id, id).exists?
|
155
|
+
shipments.empty? && !Order.complete.where('bill_address_id = ? OR ship_address_id = ?', id, id).exists?
|
146
156
|
end
|
147
157
|
|
148
158
|
def check
|
@@ -64,6 +64,7 @@ module Spree
|
|
64
64
|
scope :charge, -> { where("#{quoted_table_name}.amount >= 0") }
|
65
65
|
scope :credit, -> { where("#{quoted_table_name}.amount < 0") }
|
66
66
|
scope :nonzero, -> { where("#{quoted_table_name}.amount != 0") }
|
67
|
+
scope :non_zero, -> { where.not(amount: [nil, 0]) }
|
67
68
|
scope :promotion, -> { where(source_type: 'Spree::PromotionAction') }
|
68
69
|
scope :return_authorization, -> { where(source_type: 'Spree::ReturnAuthorization') }
|
69
70
|
scope :is_included, -> { where(included: true) }
|
@@ -87,6 +88,10 @@ module Spree
|
|
87
88
|
source_type == 'Spree::PromotionAction'
|
88
89
|
end
|
89
90
|
|
91
|
+
def tax?
|
92
|
+
source_type == 'Spree::TaxRate'
|
93
|
+
end
|
94
|
+
|
90
95
|
# Passing a target here would always be recommended as it would avoid
|
91
96
|
# hitting the database again and would ensure you're compute values over
|
92
97
|
# the specific object amount passed here.
|
data/app/models/spree/asset.rb
CHANGED
@@ -8,5 +8,13 @@ module Spree
|
|
8
8
|
|
9
9
|
belongs_to :viewable, polymorphic: true, touch: true
|
10
10
|
acts_as_list scope: [:viewable_id, :viewable_type]
|
11
|
+
|
12
|
+
if Spree.public_storage_service_name
|
13
|
+
has_one_attached :attachment, service: Spree.public_storage_service_name
|
14
|
+
else
|
15
|
+
has_one_attached :attachment
|
16
|
+
end
|
17
|
+
|
18
|
+
default_scope { includes(attachment_attachment: :blob) }
|
11
19
|
end
|
12
20
|
end
|
@@ -4,12 +4,15 @@ module Spree
|
|
4
4
|
class Calculator::FlatRate < Calculator
|
5
5
|
preference :amount, :decimal, default: 0
|
6
6
|
preference :currency, :string, default: -> { Spree::Store.default.default_currency }
|
7
|
+
preference :apply_only_on_full_priced_items, :boolean, default: false
|
7
8
|
|
8
9
|
def self.description
|
9
10
|
Spree.t(:flat_rate_per_order)
|
10
11
|
end
|
11
12
|
|
12
13
|
def compute(object = nil)
|
14
|
+
return 0 if preferred_apply_only_on_full_priced_items && object&.variant&.compare_at_amount_in(object.currency).present?
|
15
|
+
|
13
16
|
if object && preferred_currency.casecmp(object.currency.upcase).zero?
|
14
17
|
preferred_amount
|
15
18
|
else
|
@@ -6,6 +6,7 @@ module Spree
|
|
6
6
|
preference :additional_item, :decimal, default: 0.0
|
7
7
|
preference :max_items, :integer, default: 0
|
8
8
|
preference :currency, :string, default: -> { Spree::Store.default.default_currency }
|
9
|
+
preference :apply_only_on_full_priced_items, :boolean, default: false
|
9
10
|
|
10
11
|
def self.description
|
11
12
|
Spree.t(:flexible_rate)
|
@@ -16,6 +17,8 @@ module Spree
|
|
16
17
|
end
|
17
18
|
|
18
19
|
def compute(object)
|
20
|
+
return 0 if preferred_apply_only_on_full_priced_items && object.variant.compare_at_amount_in(object.currency).present?
|
21
|
+
|
19
22
|
compute_from_quantity(object.quantity)
|
20
23
|
end
|
21
24
|
|
@@ -2,12 +2,15 @@ module Spree
|
|
2
2
|
class Calculator
|
3
3
|
class PercentOnLineItem < Calculator
|
4
4
|
preference :percent, :decimal, default: 0
|
5
|
+
preference :apply_only_on_full_priced_items, :boolean, default: false
|
5
6
|
|
6
7
|
def self.description
|
7
8
|
Spree.t(:percent_per_item)
|
8
9
|
end
|
9
10
|
|
10
11
|
def compute(object)
|
12
|
+
return 0 if preferred_apply_only_on_full_priced_items && object.variant.compare_at_amount_in(object.currency).present?
|
13
|
+
|
11
14
|
computed_amount = (object.amount * preferred_percent / 100).round(2)
|
12
15
|
|
13
16
|
# We don't want to cause the promotion adjustments to push the order into a negative total.
|
@@ -6,11 +6,23 @@ module Spree
|
|
6
6
|
preference :amount, :decimal, default: 0
|
7
7
|
preference :currency, :string, default: -> { Spree::Store.default.default_currency }
|
8
8
|
|
9
|
+
preference :minimum_item_total, :decimal, default: nil, nullable: true
|
10
|
+
preference :maximum_item_total, :decimal, default: nil, nullable: true
|
11
|
+
|
12
|
+
preference :minimum_weight, :decimal, default: nil, nullable: true
|
13
|
+
preference :maximum_weight, :decimal, default: nil, nullable: true
|
14
|
+
|
9
15
|
def self.description
|
10
16
|
Spree.t(:shipping_flat_rate_per_order)
|
11
17
|
end
|
12
18
|
|
13
|
-
def compute_package(
|
19
|
+
def compute_package(package)
|
20
|
+
return nil if preferred_minimum_weight.present? && preferred_minimum_weight >= package.weight
|
21
|
+
return nil if preferred_maximum_weight.present? && preferred_maximum_weight < package.weight
|
22
|
+
|
23
|
+
return nil if preferred_minimum_item_total.present? && preferred_minimum_item_total >= package.item_total
|
24
|
+
return nil if preferred_maximum_item_total.present? && preferred_maximum_item_total < package.item_total
|
25
|
+
|
14
26
|
preferred_amount
|
15
27
|
end
|
16
28
|
end
|
@@ -1,11 +1,5 @@
|
|
1
1
|
module Spree
|
2
2
|
class CmsSectionImage < Asset
|
3
|
-
if Spree.public_storage_service_name
|
4
|
-
has_one_attached :attachment, service: Spree.public_storage_service_name
|
5
|
-
else
|
6
|
-
has_one_attached :attachment
|
7
|
-
end
|
8
|
-
|
9
3
|
IMAGE_COUNT = ['one', 'two', 'three']
|
10
4
|
IMAGE_TYPES = ['image/png', 'image/jpg', 'image/jpeg', 'image/gif'].freeze
|
11
5
|
IMAGE_SIZE = ['sm', 'md', 'lg', 'xl']
|
data/app/models/spree/icon.rb
CHANGED
@@ -1,11 +1,5 @@
|
|
1
1
|
module Spree
|
2
2
|
class Icon < Spree::Asset
|
3
|
-
if Spree.public_storage_service_name
|
4
|
-
has_one_attached :attachment, service: Spree.public_storage_service_name
|
5
|
-
else
|
6
|
-
has_one_attached :attachment
|
7
|
-
end
|
8
|
-
|
9
3
|
ICON_TYPES = %i[png jpg jpeg gif svg]
|
10
4
|
|
11
5
|
validates :attachment, attached: true, content_type: ICON_TYPES
|
@@ -5,16 +5,8 @@ module Spree
|
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
7
|
included do
|
8
|
-
if Spree.public_storage_service_name
|
9
|
-
has_one_attached :attachment, service: Spree.public_storage_service_name
|
10
|
-
else
|
11
|
-
has_one_attached :attachment
|
12
|
-
end
|
13
|
-
|
14
8
|
validates :attachment, attached: true, content_type: /\Aimage\/.*\z/
|
15
9
|
|
16
|
-
default_scope { includes(attachment_attachment: :blob) }
|
17
|
-
|
18
10
|
def self.styles
|
19
11
|
@styles ||= {
|
20
12
|
mini: '48x48>',
|
data/app/models/spree/image.rb
CHANGED
@@ -4,6 +4,8 @@ module Spree
|
|
4
4
|
include Rails.application.routes.url_helpers
|
5
5
|
include Spree::ImageMethods
|
6
6
|
|
7
|
+
after_commit :touch_product_variants, if: :should_touch_product_variants?, on: :update
|
8
|
+
|
7
9
|
# In Rails 5.x class constants are being undefined/redefined during the code reloading process
|
8
10
|
# in a rails development environment, after which the actual ruby objects stored in those class constants
|
9
11
|
# are no longer equal (subclass == self) what causes error ActiveRecord::SubclassNotFound
|
@@ -51,5 +53,20 @@ module Spree
|
|
51
53
|
def plp_url
|
52
54
|
generate_url(size: self.class.styles[:plp_and_carousel])
|
53
55
|
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def touch_product_variants
|
60
|
+
viewable.product.variants.touch_all
|
61
|
+
end
|
62
|
+
|
63
|
+
def should_touch_product_variants?
|
64
|
+
return false unless viewable.is_a?(Spree::Variant)
|
65
|
+
return false unless viewable.is_master?
|
66
|
+
return false unless viewable.product.has_variants?
|
67
|
+
return false unless saved_change_to_position?
|
68
|
+
|
69
|
+
true
|
70
|
+
end
|
54
71
|
end
|
55
72
|
end
|
@@ -13,7 +13,7 @@ module Spree
|
|
13
13
|
end
|
14
14
|
belongs_to :tax_category, -> { with_deleted }, class_name: 'Spree::TaxCategory'
|
15
15
|
|
16
|
-
has_one :product, through: :variant
|
16
|
+
has_one :product, -> { with_deleted }, class_name: 'Spree::Product', through: :variant
|
17
17
|
|
18
18
|
has_many :adjustments, as: :adjustable, dependent: :destroy
|
19
19
|
has_many :inventory_units, inverse_of: :line_item
|
@@ -70,11 +70,7 @@ module Spree
|
|
70
70
|
def update_price
|
71
71
|
currency_price = variant.price_in(order.currency)
|
72
72
|
|
73
|
-
self.price = if currency_price.
|
74
|
-
currency_price.price_including_vat_for(tax_zone: tax_zone)
|
75
|
-
else
|
76
|
-
0
|
77
|
-
end
|
73
|
+
self.price = currency_price.price_including_vat_for(tax_zone: tax_zone) if currency_price.present?
|
78
74
|
end
|
79
75
|
|
80
76
|
def copy_tax_category
|
@@ -99,6 +95,13 @@ module Spree
|
|
99
95
|
amount + taxable_adjustment_total
|
100
96
|
end
|
101
97
|
|
98
|
+
# returns the total tax amount
|
99
|
+
#
|
100
|
+
# @return [BigDecimal]
|
101
|
+
def tax_total
|
102
|
+
included_tax_total + additional_tax_total
|
103
|
+
end
|
104
|
+
|
102
105
|
alias discounted_money display_discounted_amount
|
103
106
|
alias discounted_amount taxable_amount
|
104
107
|
|
@@ -117,6 +120,20 @@ module Spree
|
|
117
120
|
!sufficient_stock?
|
118
121
|
end
|
119
122
|
|
123
|
+
# returns true if any of the inventory units are shipped
|
124
|
+
#
|
125
|
+
# @return [Boolean]
|
126
|
+
def any_shipped?
|
127
|
+
inventory_units.any?(&:shipped?)
|
128
|
+
end
|
129
|
+
|
130
|
+
# returns true if all of the inventory units are shipped
|
131
|
+
#
|
132
|
+
# @return [Boolean]
|
133
|
+
def fully_shipped?
|
134
|
+
inventory_units.all?(&:shipped?)
|
135
|
+
end
|
136
|
+
|
120
137
|
def options=(options = {})
|
121
138
|
return unless options.present?
|
122
139
|
|
@@ -5,5 +5,9 @@ module Spree
|
|
5
5
|
|
6
6
|
validates :option_value, :variant, presence: true
|
7
7
|
validates :option_value_id, uniqueness: { scope: :variant_id }
|
8
|
+
|
9
|
+
scope :for_option_types, lambda { |option_types|
|
10
|
+
joins(:option_value).merge(Spree::OptionValue.where(option_types: option_types))
|
11
|
+
}
|
8
12
|
end
|
9
13
|
end
|
@@ -26,10 +26,10 @@ module Spree
|
|
26
26
|
def update_line_item_price!(line_item)
|
27
27
|
price = price_from_line_item(line_item)
|
28
28
|
|
29
|
-
if price
|
29
|
+
if price&.currency && price.amount
|
30
30
|
line_item.update!(currency: price.currency, price: price.amount)
|
31
31
|
else
|
32
|
-
|
32
|
+
line_item.destroy
|
33
33
|
end
|
34
34
|
end
|
35
35
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Spree
|
2
|
+
class Order < Spree::Base
|
3
|
+
module Webhooks
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
def send_order_canceled_webhook
|
7
|
+
# Implement your logic of sending cancale webhooks
|
8
|
+
end
|
9
|
+
|
10
|
+
def send_order_placed_webhook
|
11
|
+
# Implement your logic of sending order placed webhooks
|
12
|
+
end
|
13
|
+
|
14
|
+
def send_order_resumed_webhook
|
15
|
+
# Implement your logic of sending after resume webhooks
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/app/models/spree/order.rb
CHANGED
@@ -17,6 +17,7 @@ module Spree
|
|
17
17
|
include Spree::Order::StoreCredit
|
18
18
|
include Spree::Order::AddressBook
|
19
19
|
include Spree::Order::Emails
|
20
|
+
include Spree::Order::Webhooks
|
20
21
|
include Spree::Core::NumberGenerator.new(prefix: 'R')
|
21
22
|
include Spree::Core::TokenGenerator
|
22
23
|
|
@@ -25,9 +26,6 @@ module Spree
|
|
25
26
|
include Spree::SingleStoreResource
|
26
27
|
include Spree::MemoizedData
|
27
28
|
include Spree::Metadata
|
28
|
-
if defined?(Spree::Webhooks::HasWebhooks)
|
29
|
-
include Spree::Webhooks::HasWebhooks
|
30
|
-
end
|
31
29
|
if defined?(Spree::Security::Orders)
|
32
30
|
include Spree::Security::Orders
|
33
31
|
end
|
@@ -91,9 +89,9 @@ module Spree
|
|
91
89
|
belongs_to :user, optional: true
|
92
90
|
end
|
93
91
|
if Spree.admin_user_class
|
94
|
-
belongs_to :created_by, class_name: Spree.admin_user_class
|
95
|
-
belongs_to :approver, class_name: Spree.admin_user_class
|
96
|
-
belongs_to :canceler, class_name: Spree.admin_user_class
|
92
|
+
belongs_to :created_by, class_name: "::#{Spree.admin_user_class}", optional: true
|
93
|
+
belongs_to :approver, class_name: "::#{Spree.admin_user_class}", optional: true
|
94
|
+
belongs_to :canceler, class_name: "::#{Spree.admin_user_class}", optional: true
|
97
95
|
else
|
98
96
|
belongs_to :created_by, optional: true
|
99
97
|
belongs_to :approver, optional: true
|
@@ -401,6 +399,8 @@ module Spree
|
|
401
399
|
deliver_order_confirmation_email unless confirmation_delivered?
|
402
400
|
deliver_store_owner_order_notification_email if deliver_store_owner_order_notification_email?
|
403
401
|
|
402
|
+
send_order_placed_webhook
|
403
|
+
|
404
404
|
consider_risk
|
405
405
|
end
|
406
406
|
|
@@ -522,6 +522,14 @@ module Spree
|
|
522
522
|
self.shipments = Spree::Stock::Coordinator.new(self).shipments
|
523
523
|
end
|
524
524
|
|
525
|
+
# Returns the total weight of the inventory units in the order
|
526
|
+
# This is used to calculate the shipping rates for the order
|
527
|
+
#
|
528
|
+
# @return [BigDecimal] the total weight of the inventory units in the order
|
529
|
+
def total_weight
|
530
|
+
@total_weight ||= line_items.joins(:variant).includes(:variant).map { |li| li.variant.weight * li.quantity }.sum
|
531
|
+
end
|
532
|
+
|
525
533
|
def apply_free_shipping_promotions
|
526
534
|
Spree::PromotionHandler::FreeShipping.new(self).activate
|
527
535
|
shipments.each { |shipment| Spree::Adjustable::AdjustmentsUpdater.update(shipment) }
|
@@ -566,6 +574,7 @@ module Spree
|
|
566
574
|
def set_shipments_cost
|
567
575
|
shipments.each(&:update_amounts)
|
568
576
|
updater.update_shipment_total
|
577
|
+
updater.update_adjustment_total
|
569
578
|
persist_totals
|
570
579
|
end
|
571
580
|
|
@@ -726,11 +735,13 @@ module Spree
|
|
726
735
|
|
727
736
|
send_cancel_email
|
728
737
|
update_with_updater!
|
738
|
+
send_order_canceled_webhook
|
729
739
|
end
|
730
740
|
|
731
741
|
def after_resume
|
732
742
|
shipments.each(&:resume!)
|
733
743
|
consider_risk
|
744
|
+
send_order_resumed_webhook
|
734
745
|
end
|
735
746
|
|
736
747
|
def use_billing?
|
@@ -16,6 +16,7 @@ module Spree
|
|
16
16
|
end
|
17
17
|
|
18
18
|
set_user(user)
|
19
|
+
clear_addresses(other_order)
|
19
20
|
persist_merge
|
20
21
|
|
21
22
|
# So that the destroy doesn't take out line items which may have been re-assigned
|
@@ -39,6 +40,11 @@ module Spree
|
|
39
40
|
order.associate_user!(user) if !order.user && !user.blank?
|
40
41
|
end
|
41
42
|
|
43
|
+
def clear_addresses(other_order)
|
44
|
+
other_order.ship_address = nil
|
45
|
+
other_order.bill_address = nil
|
46
|
+
end
|
47
|
+
|
42
48
|
# The idea is the end developer can choose to override the merge
|
43
49
|
# to their own choosing. Default is merge with errors.
|
44
50
|
def handle_merge(current_line_item, other_order_line_item)
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Spree
|
2
|
+
class Payment < Spree::Base
|
3
|
+
module Webhooks
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
def send_payment_voided_webhook
|
7
|
+
# Implement your logic here
|
8
|
+
end
|
9
|
+
|
10
|
+
def send_payment_completed_webhook
|
11
|
+
# Implement your logic here
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/app/models/spree/payment.rb
CHANGED
@@ -6,14 +6,12 @@ module Spree
|
|
6
6
|
include Spree::NumberIdentifier
|
7
7
|
include Spree::NumberAsParam
|
8
8
|
include Spree::Metadata
|
9
|
-
if defined?(Spree::Webhooks::HasWebhooks)
|
10
|
-
include Spree::Webhooks::HasWebhooks
|
11
|
-
end
|
12
9
|
if defined?(Spree::Security::Payments)
|
13
10
|
include Spree::Security::Payments
|
14
11
|
end
|
15
12
|
|
16
13
|
include Spree::Payment::Processing
|
14
|
+
include Spree::Payment::Webhooks
|
17
15
|
|
18
16
|
NON_RISKY_AVS_CODES = ['B', 'D', 'H', 'J', 'M', 'Q', 'T', 'V', 'X', 'Y'].freeze
|
19
17
|
RISKY_AVS_CODES = ['A', 'C', 'E', 'F', 'G', 'I', 'K', 'L', 'N', 'O', 'P', 'R', 'S', 'U', 'W', 'Z'].freeze
|
@@ -67,6 +65,8 @@ module Spree
|
|
67
65
|
scope :processing, -> { with_state('processing') }
|
68
66
|
scope :failed, -> { with_state('failed') }
|
69
67
|
|
68
|
+
scope :incomplete, -> { where.not(state: 'completed') }
|
69
|
+
|
70
70
|
scope :risky, -> { where("avs_response IN (?) OR (cvv_response_code IS NOT NULL and cvv_response_code != 'M') OR state = 'failed'", RISKY_AVS_CODES) }
|
71
71
|
scope :valid, -> { where.not(state: INVALID_STATES) }
|
72
72
|
|
@@ -105,11 +105,11 @@ module Spree
|
|
105
105
|
event :complete do
|
106
106
|
transition from: [:processing, :pending, :checkout], to: :completed
|
107
107
|
end
|
108
|
-
after_transition to: :completed, do: :after_completed
|
108
|
+
after_transition to: :completed, do: [:after_completed, :send_payment_completed_webhook]
|
109
109
|
event :void do
|
110
110
|
transition from: [:pending, :processing, :completed, :checkout], to: :void
|
111
111
|
end
|
112
|
-
after_transition to: :void, do: :after_void
|
112
|
+
after_transition to: :void, do: [:after_void, :send_payment_voided_webhook]
|
113
113
|
# when the card brand isn't supported
|
114
114
|
event :invalidate do
|
115
115
|
transition from: [:checkout], to: :invalid
|
@@ -209,11 +209,11 @@ module Spree
|
|
209
209
|
private
|
210
210
|
|
211
211
|
def after_void
|
212
|
-
#
|
212
|
+
# Implement your logic here
|
213
213
|
end
|
214
214
|
|
215
215
|
def after_completed
|
216
|
-
#
|
216
|
+
# Implement your logic here
|
217
217
|
end
|
218
218
|
|
219
219
|
def has_invalid_state?
|
data/app/models/spree/price.rb
CHANGED
@@ -12,6 +12,7 @@ module Spree
|
|
12
12
|
belongs_to :variant, -> { with_deleted }, class_name: 'Spree::Variant', inverse_of: :prices, touch: true
|
13
13
|
|
14
14
|
before_validation :ensure_currency
|
15
|
+
before_save :remove_compare_at_amount_if_equals_amount
|
15
16
|
|
16
17
|
validates :amount, allow_nil: true, numericality: {
|
17
18
|
greater_than_or_equal_to: 0,
|
@@ -23,6 +24,10 @@ module Spree
|
|
23
24
|
less_than_or_equal_to: MAXIMUM_AMOUNT
|
24
25
|
}
|
25
26
|
|
27
|
+
scope :with_currency, ->(currency) { where(currency: currency) }
|
28
|
+
scope :non_zero, -> { where.not(amount: [nil, 0]) }
|
29
|
+
scope :discounted, -> { where('compare_at_amount > amount') }
|
30
|
+
|
26
31
|
extend DisplayMoney
|
27
32
|
money_methods :amount, :price, :compare_at_amount
|
28
33
|
alias display_compare_at_price display_compare_at_amount
|
@@ -68,10 +73,50 @@ module Spree
|
|
68
73
|
Spree::Money.new(compare_at_price_including_vat_for(price_options), currency: currency)
|
69
74
|
end
|
70
75
|
|
76
|
+
# returns the name of the price in a format of variant name and currency
|
77
|
+
#
|
78
|
+
# @return [String]
|
79
|
+
def name
|
80
|
+
"#{variant.name} - #{currency.upcase}"
|
81
|
+
end
|
82
|
+
|
83
|
+
# returns true if the price is discounted
|
84
|
+
#
|
85
|
+
# @return [Boolean]
|
86
|
+
def discounted?
|
87
|
+
compare_at_amount.to_i.positive? && compare_at_amount > amount
|
88
|
+
end
|
89
|
+
|
90
|
+
# returns true if the price was discounted
|
91
|
+
#
|
92
|
+
# @return [Boolean]
|
93
|
+
def was_discounted?
|
94
|
+
compare_at_amount_was.to_i.positive? && compare_at_amount_was > amount_was
|
95
|
+
end
|
96
|
+
|
97
|
+
# returns true if the price is zero
|
98
|
+
#
|
99
|
+
# @return [Boolean]
|
100
|
+
def zero?
|
101
|
+
amount.nil? || amount.zero?
|
102
|
+
end
|
103
|
+
|
104
|
+
# returns true if the price is not zero
|
105
|
+
#
|
106
|
+
# @return [Boolean]
|
107
|
+
def non_zero?
|
108
|
+
!zero?
|
109
|
+
end
|
110
|
+
|
71
111
|
private
|
72
112
|
|
73
113
|
def ensure_currency
|
74
114
|
self.currency ||= Spree::Store.default.default_currency
|
75
115
|
end
|
116
|
+
|
117
|
+
# removes the compare at amount if it is the same as the amount
|
118
|
+
def remove_compare_at_amount_if_equals_amount
|
119
|
+
self.compare_at_amount = nil if compare_at_amount == amount
|
120
|
+
end
|
76
121
|
end
|
77
122
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Spree
|
2
|
+
class Product < Spree::Base
|
3
|
+
module Webhooks
|
4
|
+
def send_product_activated_webhook
|
5
|
+
# Implement your logic here
|
6
|
+
end
|
7
|
+
|
8
|
+
def send_product_archived_webhook
|
9
|
+
# Implement your logic here
|
10
|
+
end
|
11
|
+
|
12
|
+
def send_product_drafted_webhook
|
13
|
+
# Implement your logic here
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|