solidus_core 2.7.4 → 2.8.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/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
|