solidus_core 2.7.4 → 2.8.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of solidus_core might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/README.md +19 -17
- data/app/assets/images/logo/solidus.svg +18 -0
- data/app/assets/javascripts/spree.js.erb +2 -2
- data/app/helpers/spree/base_helper.rb +1 -7
- data/app/helpers/spree/taxons_helper.rb +2 -2
- data/app/mailers/spree/carton_mailer.rb +4 -4
- data/app/models/spree/calculator/flat_percent_item_total.rb +4 -1
- data/app/models/spree/calculator/shipping/flat_percent_item_total.rb +5 -3
- data/app/models/spree/calculator/tiered_percent.rb +2 -1
- data/app/models/spree/country.rb +8 -0
- data/app/models/spree/fulfilment_changer.rb +9 -1
- data/app/models/spree/gallery/product_gallery.rb +18 -0
- data/app/models/spree/gallery/variant_gallery.rb +21 -0
- data/app/models/spree/image.rb +11 -1
- data/app/models/spree/inventory_unit.rb +8 -0
- data/app/models/spree/line_item.rb +1 -1
- data/app/models/spree/order.rb +0 -4
- data/app/models/spree/order_cancellations.rb +31 -10
- data/app/models/spree/order_contents.rb +1 -5
- data/app/models/spree/order_inventory.rb +5 -4
- data/app/models/spree/product.rb +9 -0
- data/app/models/spree/product/scopes.rb +3 -4
- data/app/models/spree/promotion.rb +1 -6
- data/app/models/spree/promotion_handler/coupon.rb +15 -0
- data/app/models/spree/reimbursement.rb +21 -6
- data/app/models/spree/reimbursement_performer.rb +12 -6
- data/app/models/spree/reimbursement_type.rb +1 -1
- data/app/models/spree/reimbursement_type/credit.rb +5 -2
- data/app/models/spree/reimbursement_type/exchange.rb +1 -1
- data/app/models/spree/reimbursement_type/original_payment.rb +1 -1
- data/app/models/spree/reimbursement_type/reimbursement_helpers.rb +6 -6
- data/app/models/spree/reimbursement_type/store_credit.rb +18 -3
- data/app/models/spree/shipment.rb +11 -11
- data/app/models/spree/stock/allocator/base.rb +19 -0
- data/app/models/spree/stock/allocator/on_hand_first.rb +42 -0
- data/app/models/spree/stock/content_item.rb +1 -1
- data/app/models/spree/stock/inventory_units_finalizer.rb +47 -0
- data/app/models/spree/stock/location_sorter/base.rb +38 -0
- data/app/models/spree/stock/location_sorter/default_first.rb +15 -0
- data/app/models/spree/stock/location_sorter/unsorted.rb +14 -0
- data/app/models/spree/stock/simple_coordinator.rb +24 -10
- data/app/models/spree/stock_location.rb +2 -0
- data/app/models/spree/store_credit.rb +4 -12
- data/app/models/spree/store_credit_event.rb +2 -2
- data/app/models/spree/store_credit_reason.rb +11 -0
- data/app/models/spree/taxon.rb +8 -3
- data/app/models/spree/unit_cancel.rb +3 -0
- data/app/models/spree/variant.rb +18 -7
- data/config/initializers/money.rb +5 -0
- data/config/locales/en.yml +661 -527
- data/db/default/spree/store_credit.rb +1 -1
- data/db/default/spree/zones.rb +2 -2
- data/db/migrate/20180710170104_create_spree_store_credit_reasons_table.rb +42 -0
- data/db/migrate/20190106184413_remove_code_from_spree_promotions.rb +41 -0
- data/lib/generators/spree/dummy/templates/rails/test.rb +0 -3
- data/lib/generators/spree/install/install_generator.rb +2 -2
- data/lib/generators/spree/install/templates/config/initializers/spree.rb.tt +2 -2
- data/lib/generators/spree/install/templates/vendor/assets/javascripts/spree/backend/all.js +1 -1
- data/lib/generators/spree/install/templates/vendor/assets/javascripts/spree/frontend/all.js +1 -1
- data/lib/solidus/migrations/promotions_with_code_handlers.rb +66 -0
- data/lib/spree/app_configuration.rb +20 -4
- data/lib/spree/core/controller_helpers/common.rb +1 -1
- data/lib/spree/core/stock_configuration.rb +12 -0
- data/lib/spree/core/version.rb +1 -1
- data/lib/spree/i18n.rb +4 -0
- data/lib/spree/money.rb +13 -11
- data/lib/spree/permission_sets.rb +0 -1
- data/lib/spree/permission_sets/promotion_management.rb +1 -0
- data/lib/spree/testing_support/dummy_app.rb +13 -2
- data/lib/spree/testing_support/dummy_app/assets/javascripts/spree/backend/all.js +1 -1
- data/lib/spree/testing_support/dummy_app/assets/javascripts/spree/frontend/all.js +1 -1
- data/lib/spree/testing_support/factories/store_credit_event_factory.rb +5 -5
- data/lib/spree/testing_support/factories/{store_credit_update_reason_factory.rb → store_credit_reason_factory.rb} +1 -1
- data/lib/spree/testing_support/partial_double_verification.rb +13 -0
- data/lib/spree/testing_support/shared_examples/gallery.rb +18 -0
- data/spec/helpers/products_helper_spec.rb +10 -8
- data/spec/helpers/taxons_helper_spec.rb +3 -1
- data/spec/lib/i18n_spec.rb +5 -0
- data/spec/lib/spree/core/controller_helpers/auth_spec.rb +6 -2
- data/spec/lib/spree/core/stock_configuration_spec.rb +19 -0
- data/spec/lib/spree/core/testing_support/factories/store_credit_reason_factory_spec.rb +14 -0
- data/spec/lib/spree/money_spec.rb +12 -13
- data/spec/migrate/20190106184413_remove_code_from_spree_promotions_spec.rb +136 -0
- data/spec/models/spree/calculator/flat_percent_item_total_spec.rb +10 -1
- data/spec/models/spree/calculator/shipping/flat_percent_item_total_spec.rb +18 -6
- data/spec/models/spree/calculator/tiered_percent_spec.rb +7 -1
- data/spec/models/spree/country_spec.rb +76 -0
- data/spec/models/spree/customer_return_spec.rb +2 -1
- data/spec/models/spree/fulfilment_changer_spec.rb +33 -0
- data/spec/models/spree/gallery/product_gallery_spec.rb +21 -0
- data/spec/models/spree/gallery/variant_gallery_spec.rb +21 -0
- data/spec/models/spree/inventory_unit_spec.rb +1 -4
- data/spec/models/spree/order/checkout_spec.rb +6 -6
- data/spec/models/spree/order/finalizing_spec.rb +1 -20
- data/spec/models/spree/order/outstanding_balance_integration_spec.rb +2 -1
- data/spec/models/spree/order/updating_spec.rb +1 -1
- data/spec/models/spree/order_cancellations_spec.rb +55 -14
- data/spec/models/spree/order_inventory_spec.rb +12 -5
- data/spec/models/spree/order_merger_spec.rb +6 -3
- data/spec/models/spree/order_spec.rb +3 -7
- data/spec/models/spree/order_updater_spec.rb +3 -8
- data/spec/models/spree/payment/cancellation_spec.rb +4 -3
- data/spec/models/spree/payment_spec.rb +1 -17
- data/spec/models/spree/permission_sets/promotion_management_spec.rb +2 -0
- data/spec/models/spree/product_spec.rb +10 -1
- data/spec/models/spree/promotion_handler/coupon_spec.rb +62 -8
- data/spec/models/spree/promotion_spec.rb +24 -10
- data/spec/models/spree/refund_spec.rb +2 -1
- data/spec/models/spree/reimbursement_performer_spec.rb +5 -4
- data/spec/models/spree/reimbursement_spec.rb +26 -2
- data/spec/models/spree/reimbursement_type/credit_spec.rb +2 -1
- data/spec/models/spree/reimbursement_type/exchange_spec.rb +2 -1
- data/spec/models/spree/reimbursement_type/original_payment_spec.rb +2 -1
- data/spec/models/spree/reimbursement_type/store_credit_spec.rb +14 -2
- data/spec/models/spree/return_item_spec.rb +1 -1
- data/spec/models/spree/shipment_spec.rb +20 -13
- data/spec/models/spree/shipping_calculator_spec.rb +13 -3
- data/spec/models/spree/stock/allocator/on_hand_first_spec.rb +146 -0
- data/spec/models/spree/stock/content_item_spec.rb +70 -0
- data/spec/models/spree/stock/estimator_spec.rb +5 -2
- data/spec/models/spree/stock/inventory_units_finalizer_spec.rb +34 -0
- data/spec/models/spree/stock/location_sorter/default_first_spec.rb +20 -0
- data/spec/models/spree/stock/location_sorter/unsorted_spec.rb +19 -0
- data/spec/models/spree/stock/simple_coordinator_spec.rb +17 -0
- data/spec/models/spree/store_credit_event_spec.rb +12 -12
- data/spec/models/spree/store_credit_spec.rb +2 -2
- data/spec/models/spree/unit_cancel_spec.rb +20 -1
- data/spec/models/spree/variant_spec.rb +46 -24
- data/spec/spec_helper.rb +1 -0
- metadata +30 -9
- data/.yardopts +0 -1
- data/app/models/spree/store_credit_update_reason.rb +0 -4
- data/lib/spree/permission_sets/report_display.rb +0 -11
- data/spec/lib/spree/core/testing_support/factories/store_credit_update_reason_factory_spec.rb +0 -14
- data/spec/models/spree/permission_sets/report_display_spec.rb +0 -25
@@ -60,18 +60,19 @@ module Spree
|
|
60
60
|
end
|
61
61
|
|
62
62
|
def add_to_shipment(shipment, quantity)
|
63
|
+
pending_units = []
|
63
64
|
if variant.should_track_inventory?
|
64
65
|
on_hand, back_order = shipment.stock_location.fill_status(variant, quantity)
|
65
66
|
|
66
|
-
on_hand.times { shipment.set_up_inventory('on_hand', variant, order, line_item) }
|
67
|
-
back_order.times { shipment.set_up_inventory('backordered', variant, order, line_item) }
|
67
|
+
on_hand.times { pending_units << shipment.set_up_inventory('on_hand', variant, order, line_item) }
|
68
|
+
back_order.times { pending_units << shipment.set_up_inventory('backordered', variant, order, line_item) }
|
68
69
|
else
|
69
|
-
quantity.times { shipment.set_up_inventory('on_hand', variant, order, line_item) }
|
70
|
+
quantity.times { pending_units << shipment.set_up_inventory('on_hand', variant, order, line_item) }
|
70
71
|
end
|
71
72
|
|
72
73
|
# adding to this shipment, and removing from stock_location
|
73
74
|
if order.completed?
|
74
|
-
|
75
|
+
Spree::Stock::InventoryUnitsFinalizer.new(pending_units).run!
|
75
76
|
end
|
76
77
|
|
77
78
|
quantity
|
data/app/models/spree/product.rb
CHANGED
@@ -297,6 +297,7 @@ module Spree
|
|
297
297
|
# variants. If all else fails, will return a new image object.
|
298
298
|
# @return [Spree::Image] the image to display
|
299
299
|
def display_image
|
300
|
+
Spree::Deprecation.warn('Spree::Product#display_image is DEPRECATED. Choose an image from Spree::Product#gallery instead.')
|
300
301
|
images.first || variant_images.first || Spree::Image.new
|
301
302
|
end
|
302
303
|
|
@@ -310,6 +311,14 @@ module Spree
|
|
310
311
|
end
|
311
312
|
end
|
312
313
|
|
314
|
+
# The gallery for the product, which represents all the images
|
315
|
+
# associated with it, including those on its variants
|
316
|
+
#
|
317
|
+
# @return [Spree::Gallery] the media for a variant
|
318
|
+
def gallery
|
319
|
+
@gallery ||= Spree::Config.product_gallery_class.new(self)
|
320
|
+
end
|
321
|
+
|
313
322
|
private
|
314
323
|
|
315
324
|
def any_variants_not_track_inventory?
|
@@ -63,10 +63,9 @@ module Spree
|
|
63
63
|
#
|
64
64
|
# SELECT COUNT(*) ...
|
65
65
|
add_search_scope :in_taxon do |taxon|
|
66
|
-
includes(:classifications)
|
67
|
-
|
68
|
-
|
69
|
-
.order(Spree::Classification.arel_table[:position].asc)
|
66
|
+
includes(:classifications).
|
67
|
+
where("spree_products_taxons.taxon_id" => taxon.self_and_descendants.pluck(:id)).
|
68
|
+
order(Spree::Classification.arel_table[:position].asc)
|
70
69
|
end
|
71
70
|
|
72
71
|
# This scope selects products in all taxons AND all its descendants
|
@@ -36,7 +36,7 @@ module Spree
|
|
36
36
|
|
37
37
|
before_save :normalize_blank_values
|
38
38
|
|
39
|
-
scope :coupons, -> {
|
39
|
+
scope :coupons, -> { joins(:codes).distinct }
|
40
40
|
scope :advertised, -> { where(advertise: true) }
|
41
41
|
scope :active, -> do
|
42
42
|
table = arel_table
|
@@ -49,11 +49,6 @@ module Spree
|
|
49
49
|
self.whitelisted_ransackable_associations = ['codes']
|
50
50
|
self.whitelisted_ransackable_attributes = ['path', 'promotion_category_id']
|
51
51
|
|
52
|
-
# temporary code. remove after the column is dropped from the db.
|
53
|
-
def columns
|
54
|
-
super.reject { |column| column.name == "code" }
|
55
|
-
end
|
56
|
-
|
57
52
|
def self.order_activatable?(order)
|
58
53
|
order && !UNACTIVATABLE_ORDER_STATES.include?(order.state)
|
59
54
|
end
|
@@ -25,6 +25,20 @@ module Spree
|
|
25
25
|
self
|
26
26
|
end
|
27
27
|
|
28
|
+
def remove
|
29
|
+
if promotion.blank?
|
30
|
+
set_error_code :coupon_code_not_found
|
31
|
+
elsif !promotion_exists_on_order?(order, promotion)
|
32
|
+
set_error_code :coupon_code_not_present
|
33
|
+
else
|
34
|
+
promotion.remove_from(order)
|
35
|
+
order.recalculate
|
36
|
+
set_success_code :coupon_code_removed
|
37
|
+
end
|
38
|
+
|
39
|
+
self
|
40
|
+
end
|
41
|
+
|
28
42
|
def set_success_code(status_code)
|
29
43
|
@status_code = status_code
|
30
44
|
@success = I18n.t(status_code, scope: 'spree')
|
@@ -56,6 +70,7 @@ module Spree
|
|
56
70
|
def handle_present_promotion(promotion)
|
57
71
|
return promotion_usage_limit_exceeded if promotion.usage_limit_exceeded? || promotion_code.usage_limit_exceeded?
|
58
72
|
return promotion_applied if promotion_exists_on_order?(order, promotion)
|
73
|
+
|
59
74
|
unless promotion.eligible?(order, promotion_code: promotion_code)
|
60
75
|
self.error = promotion.eligibility_errors.full_messages.first unless promotion.eligibility_errors.blank?
|
61
76
|
return (error || ineligible_for_this_order)
|
@@ -18,6 +18,7 @@ module Spree
|
|
18
18
|
accepts_nested_attributes_for :return_items, allow_destroy: true
|
19
19
|
|
20
20
|
before_create :generate_number
|
21
|
+
before_create :calculate_total
|
21
22
|
|
22
23
|
scope :reimbursed, -> { where(reimbursement_status: 'reimbursed') }
|
23
24
|
|
@@ -98,12 +99,15 @@ module Spree
|
|
98
99
|
total - paid_amount
|
99
100
|
end
|
100
101
|
|
101
|
-
def perform!
|
102
|
+
def perform!(created_by: nil)
|
103
|
+
unless created_by
|
104
|
+
Spree::Deprecation.warn("Calling #perform on #{self} without created_by is deprecated")
|
105
|
+
end
|
102
106
|
reimbursement_tax_calculator.call(self)
|
103
107
|
reload
|
104
108
|
update!(total: calculated_total)
|
105
109
|
|
106
|
-
reimbursement_performer.perform(self)
|
110
|
+
reimbursement_performer.perform(self, created_by: created_by)
|
107
111
|
|
108
112
|
if unpaid_amount_within_tolerance?
|
109
113
|
reimbursed!
|
@@ -116,12 +120,15 @@ module Spree
|
|
116
120
|
end
|
117
121
|
end
|
118
122
|
|
119
|
-
def simulate
|
123
|
+
def simulate(created_by: nil)
|
124
|
+
unless created_by
|
125
|
+
Spree::Deprecation.warn("Calling #simulate on #{self} without created_by is deprecated")
|
126
|
+
end
|
120
127
|
reimbursement_simulator_tax_calculator.call(self)
|
121
128
|
reload
|
122
129
|
update!(total: calculated_total)
|
123
130
|
|
124
|
-
reimbursement_performer.simulate(self)
|
131
|
+
reimbursement_performer.simulate(self, created_by: created_by)
|
125
132
|
end
|
126
133
|
|
127
134
|
def return_items_requiring_exchange
|
@@ -139,15 +146,23 @@ module Spree
|
|
139
146
|
# Accepts all return items, saves the reimbursement, and performs the reimbursement
|
140
147
|
#
|
141
148
|
# @api public
|
149
|
+
# @param [Spree.user_class] created_by the user that is performing this action
|
142
150
|
# @return [void]
|
143
|
-
def return_all
|
151
|
+
def return_all(created_by: nil)
|
152
|
+
unless created_by
|
153
|
+
Spree::Deprecation.warn("Calling #return_all on #{self} without created_by is deprecated")
|
154
|
+
end
|
144
155
|
return_items.each(&:accept!)
|
145
156
|
save!
|
146
|
-
perform!
|
157
|
+
perform!(created_by: created_by)
|
147
158
|
end
|
148
159
|
|
149
160
|
private
|
150
161
|
|
162
|
+
def calculate_total
|
163
|
+
self.total ||= calculated_total
|
164
|
+
end
|
165
|
+
|
151
166
|
def generate_number
|
152
167
|
self.number ||= loop do
|
153
168
|
random = "RI#{Array.new(9){ rand(9) }.join}"
|
@@ -11,22 +11,28 @@ module Spree
|
|
11
11
|
# - #description
|
12
12
|
# - #display_amount
|
13
13
|
# so they can be displayed in the Admin UI appropriately.
|
14
|
-
def simulate(reimbursement)
|
15
|
-
|
14
|
+
def simulate(reimbursement, created_by: nil)
|
15
|
+
unless created_by
|
16
|
+
Spree::Deprecation.warn("Calling #simulate on #{self} without created_by is deprecated")
|
17
|
+
end
|
18
|
+
execute(reimbursement, true, created_by: created_by)
|
16
19
|
end
|
17
20
|
|
18
21
|
# Actually perform the reimbursement
|
19
|
-
def perform(reimbursement)
|
20
|
-
|
22
|
+
def perform(reimbursement, created_by: nil)
|
23
|
+
unless created_by
|
24
|
+
Spree::Deprecation.warn("Calling #perform on #{self} without created_by is deprecated")
|
25
|
+
end
|
26
|
+
execute(reimbursement, false, created_by: created_by)
|
21
27
|
end
|
22
28
|
|
23
29
|
private
|
24
30
|
|
25
|
-
def execute(reimbursement, simulate)
|
31
|
+
def execute(reimbursement, simulate, created_by:)
|
26
32
|
reimbursement_type_hash = calculate_reimbursement_types(reimbursement)
|
27
33
|
|
28
34
|
reimbursement_type_hash.flat_map do |reimbursement_type, return_items|
|
29
|
-
reimbursement_type.reimburse(reimbursement, return_items, simulate)
|
35
|
+
reimbursement_type.reimburse(reimbursement, return_items, simulate, created_by: created_by)
|
30
36
|
end
|
31
37
|
end
|
32
38
|
|
@@ -11,7 +11,7 @@ module Spree
|
|
11
11
|
# This method will reimburse the return items based on however it child implements it
|
12
12
|
# By default it takes a reimbursement, the return items it needs to reimburse, and if
|
13
13
|
# it is a simulation or a real reimbursement. This should return an array
|
14
|
-
def self.reimburse(_reimbursement, _return_items, _simulate)
|
14
|
+
def self.reimburse(_reimbursement, _return_items, _simulate, *_optional_args)
|
15
15
|
raise "Implement me"
|
16
16
|
end
|
17
17
|
end
|
@@ -5,9 +5,12 @@ module Spree
|
|
5
5
|
extend Spree::ReimbursementType::ReimbursementHelpers
|
6
6
|
|
7
7
|
class << self
|
8
|
-
def reimburse(reimbursement, return_items, simulate)
|
8
|
+
def reimburse(reimbursement, return_items, simulate, created_by: nil)
|
9
|
+
unless created_by
|
10
|
+
Spree::Deprecation.warn("Calling #reimburse on #{self} without created_by is deprecated")
|
11
|
+
end
|
9
12
|
unpaid_amount = return_items.sum(&:total).round(2, :down)
|
10
|
-
reimbursement_list, _unpaid_amount = create_credits(reimbursement, unpaid_amount, simulate)
|
13
|
+
reimbursement_list, _unpaid_amount = create_credits(reimbursement, unpaid_amount, simulate, created_by: created_by)
|
11
14
|
reimbursement_list
|
12
15
|
end
|
13
16
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class Spree::ReimbursementType::Exchange < Spree::ReimbursementType
|
4
|
-
def self.reimburse(reimbursement, return_items, simulate)
|
4
|
+
def self.reimburse(reimbursement, return_items, simulate, *_optional_args)
|
5
5
|
return [] unless return_items.present?
|
6
6
|
|
7
7
|
exchange = Spree::Exchange.new(reimbursement.order, return_items)
|
@@ -4,7 +4,7 @@ class Spree::ReimbursementType::OriginalPayment < Spree::ReimbursementType
|
|
4
4
|
extend Spree::ReimbursementType::ReimbursementHelpers
|
5
5
|
|
6
6
|
class << self
|
7
|
-
def reimburse(reimbursement, return_items, simulate)
|
7
|
+
def reimburse(reimbursement, return_items, simulate, _created_by)
|
8
8
|
unpaid_amount = return_items.sum(&:total).round(2, :down)
|
9
9
|
payments = reimbursement.order.payments.completed
|
10
10
|
|
@@ -20,8 +20,8 @@ module Spree
|
|
20
20
|
[reimbursement_list, unpaid_amount]
|
21
21
|
end
|
22
22
|
|
23
|
-
def create_credits(reimbursement, unpaid_amount, simulate, reimbursement_list = [])
|
24
|
-
credits = [create_credit(reimbursement, unpaid_amount, simulate)]
|
23
|
+
def create_credits(reimbursement, unpaid_amount, simulate, reimbursement_list = [], created_by:)
|
24
|
+
credits = [create_credit(reimbursement, unpaid_amount, simulate, created_by: created_by)]
|
25
25
|
unpaid_amount -= credits.sum(&:amount)
|
26
26
|
reimbursement_list += credits
|
27
27
|
|
@@ -43,19 +43,19 @@ module Spree
|
|
43
43
|
|
44
44
|
# If you have multiple methods of crediting a customer, overwrite this method
|
45
45
|
# Must return an array of objects the respond to #description, #display_amount
|
46
|
-
def create_credit(reimbursement, unpaid_amount, simulate)
|
47
|
-
creditable = create_creditable(reimbursement, unpaid_amount)
|
46
|
+
def create_credit(reimbursement, unpaid_amount, simulate, created_by:)
|
47
|
+
creditable = create_creditable(reimbursement, unpaid_amount, created_by: created_by)
|
48
48
|
credit = reimbursement.credits.build(creditable: creditable, amount: unpaid_amount)
|
49
49
|
simulate ? credit.readonly! : credit.save!
|
50
50
|
credit
|
51
51
|
end
|
52
52
|
|
53
|
-
def create_creditable(reimbursement, unpaid_amount)
|
53
|
+
def create_creditable(reimbursement, unpaid_amount, created_by:)
|
54
54
|
Spree::Reimbursement::Credit.default_creditable_class.new(
|
55
55
|
user: reimbursement.order.user,
|
56
56
|
amount: unpaid_amount,
|
57
57
|
category: Spree::StoreCreditCategory.reimbursement_category(reimbursement),
|
58
|
-
created_by:
|
58
|
+
created_by: created_by,
|
59
59
|
memo: "Refund for uncreditable payments on order #{reimbursement.order.number}",
|
60
60
|
currency: reimbursement.order.currency
|
61
61
|
)
|
@@ -4,17 +4,32 @@ class Spree::ReimbursementType::StoreCredit < Spree::ReimbursementType
|
|
4
4
|
extend Spree::ReimbursementType::ReimbursementHelpers
|
5
5
|
|
6
6
|
class << self
|
7
|
-
def reimburse(reimbursement, return_items, simulate)
|
7
|
+
def reimburse(reimbursement, return_items, simulate, created_by: nil)
|
8
|
+
unless created_by
|
9
|
+
Spree::Deprecation.warn("Calling #reimburse on #{self} without created_by is deprecated")
|
10
|
+
end
|
8
11
|
unpaid_amount = return_items.sum(&:total).to_d.round(2, :down)
|
9
12
|
payments = store_credit_payments(reimbursement)
|
10
13
|
reimbursement_list = []
|
11
14
|
|
12
15
|
# Credit each store credit that was used on the order
|
13
|
-
reimbursement_list, unpaid_amount = create_refunds(
|
16
|
+
reimbursement_list, unpaid_amount = create_refunds(
|
17
|
+
reimbursement,
|
18
|
+
payments,
|
19
|
+
unpaid_amount,
|
20
|
+
simulate,
|
21
|
+
reimbursement_list
|
22
|
+
)
|
14
23
|
|
15
24
|
# If there is any amount left to pay out to the customer, then create credit with that amount
|
16
25
|
if unpaid_amount > 0.0
|
17
|
-
reimbursement_list, _unpaid_amount = create_credits(
|
26
|
+
reimbursement_list, _unpaid_amount = create_credits(
|
27
|
+
reimbursement,
|
28
|
+
unpaid_amount,
|
29
|
+
simulate,
|
30
|
+
reimbursement_list,
|
31
|
+
created_by: created_by
|
32
|
+
)
|
18
33
|
end
|
19
34
|
|
20
35
|
reimbursement_list
|
@@ -13,6 +13,7 @@ module Spree
|
|
13
13
|
has_many :shipping_methods, through: :shipping_rates
|
14
14
|
has_many :state_changes, as: :stateful
|
15
15
|
has_many :cartons, -> { distinct }, through: :inventory_units
|
16
|
+
has_many :line_items, -> { distinct }, through: :inventory_units
|
16
17
|
|
17
18
|
before_validation :set_cost_zero_when_nil
|
18
19
|
|
@@ -32,7 +33,10 @@ module Spree
|
|
32
33
|
scope :trackable, -> { where("tracking IS NOT NULL AND tracking != ''") }
|
33
34
|
scope :with_state, ->(*s) { where(state: s) }
|
34
35
|
# sort by most recent shipped_at, falling back to created_at. add "id desc" to make specs that involve this scope more deterministic.
|
35
|
-
scope :reverse_chronological, -> {
|
36
|
+
scope :reverse_chronological, -> {
|
37
|
+
order(Arel.sql("coalesce(#{Spree::Shipment.table_name}.shipped_at, #{Spree::Shipment.table_name}.created_at) desc"), id: :desc)
|
38
|
+
}
|
39
|
+
|
36
40
|
scope :by_store, ->(store) { joins(:order).merge(Spree::Order.by_store(store)) }
|
37
41
|
|
38
42
|
# shipment state machine (see http://github.com/pluginaweek/state_machine/tree/master for details)
|
@@ -164,12 +168,7 @@ module Spree
|
|
164
168
|
# Any previous non-pending inventory units are skipped as their stock had
|
165
169
|
# already been allocated.
|
166
170
|
def finalize!
|
167
|
-
|
168
|
-
pending_units = inventory_units.select(&:pending?)
|
169
|
-
pending_manifest = Spree::ShippingManifest.new(inventory_units: pending_units)
|
170
|
-
pending_manifest.items.each { |item| manifest_unstock(item) }
|
171
|
-
Spree::InventoryUnit.finalize_units!(pending_units)
|
172
|
-
end
|
171
|
+
finalize_pending_inventory_units
|
173
172
|
end
|
174
173
|
|
175
174
|
def include?(variant)
|
@@ -188,10 +187,6 @@ module Spree
|
|
188
187
|
line_items.map(&:total).sum
|
189
188
|
end
|
190
189
|
|
191
|
-
def line_items
|
192
|
-
inventory_units.includes(:line_item).map(&:line_item).uniq
|
193
|
-
end
|
194
|
-
|
195
190
|
def ready_or_pending?
|
196
191
|
ready? || pending?
|
197
192
|
end
|
@@ -398,6 +393,11 @@ module Spree
|
|
398
393
|
|
399
394
|
private
|
400
395
|
|
396
|
+
def finalize_pending_inventory_units
|
397
|
+
pending_units = inventory_units.select(&:pending?)
|
398
|
+
Spree::Stock::InventoryUnitsFinalizer.new(pending_units).run!
|
399
|
+
end
|
400
|
+
|
401
401
|
def after_ship
|
402
402
|
order.shipping.ship_shipment(self, suppress_mailer: suppress_mailer)
|
403
403
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
module Stock
|
5
|
+
module Allocator
|
6
|
+
class Base
|
7
|
+
attr_reader :availability
|
8
|
+
|
9
|
+
def initialize(availability)
|
10
|
+
@availability = availability
|
11
|
+
end
|
12
|
+
|
13
|
+
def allocate_inventory(_desired)
|
14
|
+
raise NotImplementedError
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
module Stock
|
5
|
+
module Allocator
|
6
|
+
class OnHandFirst < Spree::Stock::Allocator::Base
|
7
|
+
def allocate_inventory(desired)
|
8
|
+
# Allocate any available on hand inventory
|
9
|
+
on_hand = allocate_on_hand(desired)
|
10
|
+
desired -= on_hand.values.sum if on_hand.present?
|
11
|
+
|
12
|
+
# Allocate remaining desired inventory from backorders
|
13
|
+
backordered = allocate_backordered(desired)
|
14
|
+
desired -= backordered.values.sum if backordered.present?
|
15
|
+
|
16
|
+
# If all works at this point desired must be empty
|
17
|
+
[on_hand, backordered, desired]
|
18
|
+
end
|
19
|
+
|
20
|
+
protected
|
21
|
+
|
22
|
+
def allocate_on_hand(desired)
|
23
|
+
allocate(availability.on_hand_by_stock_location_id, desired)
|
24
|
+
end
|
25
|
+
|
26
|
+
def allocate_backordered(desired)
|
27
|
+
allocate(availability.backorderable_by_stock_location_id, desired)
|
28
|
+
end
|
29
|
+
|
30
|
+
def allocate(availability_by_location, desired)
|
31
|
+
availability_by_location.transform_values do |available|
|
32
|
+
# Find the desired inventory which is available at this location
|
33
|
+
packaged = available & desired
|
34
|
+
# Remove found inventory from desired
|
35
|
+
desired -= packaged
|
36
|
+
packaged
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|