solidus_core 2.8.6 → 2.9.0.rc.1

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.

Files changed (141) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/images/logo/solidus.svg +1 -18
  3. data/app/assets/images/logo/solidus_logo.png +0 -0
  4. data/app/mailers/spree/test_mailer.rb +2 -0
  5. data/app/models/concerns/spree/default_price.rb +1 -1
  6. data/app/models/concerns/spree/ransackable_attributes.rb +1 -1
  7. data/app/models/concerns/spree/user_reporting.rb +1 -1
  8. data/app/models/spree/billing_integration.rb +7 -2
  9. data/app/models/spree/country.rb +2 -0
  10. data/app/models/spree/customer_return.rb +1 -1
  11. data/app/models/spree/image.rb +2 -44
  12. data/app/models/spree/image/paperclip_attachment.rb +55 -0
  13. data/app/models/spree/inventory_unit.rb +0 -1
  14. data/app/models/spree/option_type.rb +2 -0
  15. data/app/models/spree/option_value.rb +1 -1
  16. data/app/models/spree/order.rb +8 -13
  17. data/app/models/spree/payment.rb +1 -1
  18. data/app/models/spree/payment_method.rb +8 -4
  19. data/app/models/spree/product.rb +1 -1
  20. data/app/models/spree/promotion.rb +18 -11
  21. data/app/models/spree/promotion/rules/first_order.rb +1 -3
  22. data/app/models/spree/promotion/rules/item_total.rb +9 -1
  23. data/app/models/spree/promotion/rules/one_use_per_user.rb +2 -2
  24. data/app/models/spree/promotion/rules/product.rb +3 -3
  25. data/app/models/spree/promotion/rules/taxon.rb +5 -8
  26. data/app/models/spree/promotion/rules/user_logged_in.rb +1 -1
  27. data/app/models/spree/promotion_handler/coupon.rb +19 -3
  28. data/app/models/spree/property.rb +2 -0
  29. data/app/models/spree/reimbursement.rb +5 -5
  30. data/app/models/spree/return_item.rb +6 -2
  31. data/app/models/spree/state.rb +6 -0
  32. data/app/models/spree/stock/location_filter/active.rb +14 -0
  33. data/app/models/spree/stock/location_filter/base.rb +43 -0
  34. data/app/models/spree/stock/simple_coordinator.rb +4 -1
  35. data/app/models/spree/stock_location.rb +2 -0
  36. data/app/models/spree/tax_category.rb +11 -0
  37. data/app/models/spree/taxon.rb +4 -11
  38. data/app/models/spree/taxon/paperclip_attachment.rb +21 -0
  39. data/app/models/spree/taxonomy.rb +2 -0
  40. data/app/models/spree/unit_cancel.rb +12 -1
  41. data/app/models/spree/variant.rb +1 -1
  42. data/app/models/spree/variant/pricing_options.rb +10 -0
  43. data/app/models/spree/wallet_payment_source.rb +26 -10
  44. data/app/models/spree/zone.rb +1 -1
  45. data/app/views/spree/order_mailer/inventory_cancellation_email.text.erb +3 -3
  46. data/config/locales/en.yml +26 -53
  47. data/db/default/spree/store_credit.rb +1 -0
  48. data/db/migrate/20161123154034_add_available_to_users_and_remove_display_on_from_shipping_methods.rb +1 -1
  49. data/db/migrate/20170608074534_rename_bogus_gateways.rb +9 -8
  50. data/db/migrate/20190220093635_drop_spree_store_credit_update_reasons.rb +19 -0
  51. data/lib/generators/spree/install/install_generator.rb +0 -3
  52. data/lib/generators/spree/install/templates/config/initializers/spree.rb.tt +3 -0
  53. data/lib/solidus/migrations/rename_gateways.rb +2 -0
  54. data/lib/spree/app_configuration.rb +24 -0
  55. data/lib/spree/core.rb +1 -0
  56. data/lib/spree/core/controller_helpers/pricing.rb +1 -4
  57. data/lib/spree/core/controller_helpers/strong_parameters.rb +7 -21
  58. data/lib/spree/core/engine.rb +5 -0
  59. data/lib/spree/core/importer/order.rb +1 -3
  60. data/lib/spree/core/stock_configuration.rb +5 -0
  61. data/lib/spree/core/version.rb +3 -1
  62. data/lib/spree/deprecation.rb +50 -0
  63. data/lib/spree/event.rb +111 -0
  64. data/lib/spree/event/adapters/active_support_notifications.rb +35 -0
  65. data/lib/spree/event/configuration.rb +17 -0
  66. data/lib/spree/event/processors/mailer_processor.rb +27 -0
  67. data/lib/spree/event/subscriber.rb +84 -0
  68. data/lib/spree/permitted_attributes.rb +7 -76
  69. data/lib/spree/testing_support/capybara_ext.rb +15 -0
  70. data/lib/spree/testing_support/common_rake.rb +1 -1
  71. data/lib/spree/testing_support/dummy_app.rb +3 -10
  72. data/lib/spree/testing_support/factories/promotion_factory.rb +10 -0
  73. data/lib/spree/testing_support/factories/return_item_factory.rb +1 -0
  74. data/lib/spree/testing_support/preferences.rb +62 -0
  75. data/lib/tasks/email.rake +2 -0
  76. data/lib/tasks/migrations/copy_order_bill_address_to_credit_card.rake +4 -0
  77. data/lib/tasks/migrations/migrate_shipping_rate_taxes.rake +2 -0
  78. data/lib/tasks/migrations/migrate_user_addresses.rake +3 -0
  79. data/lib/tasks/migrations/rename_gateways.rake +2 -0
  80. data/lib/tasks/order_capturing.rake +2 -0
  81. data/spec/helpers/base_helper_spec.rb +3 -3
  82. data/spec/helpers/products_helper_spec.rb +2 -2
  83. data/spec/{models → lib}/spree/app_configuration_spec.rb +11 -1
  84. data/spec/lib/spree/core/controller_helpers/pricing_spec.rb +13 -0
  85. data/spec/lib/spree/core/controller_helpers/strong_parameters_spec.rb +1 -8
  86. data/spec/lib/spree/core/testing_support/factories/shipping_method_factory_spec.rb +1 -1
  87. data/spec/lib/spree/core/testing_support/preferences_spec.rb +33 -0
  88. data/spec/lib/spree/event/subscriber_spec.rb +85 -0
  89. data/spec/lib/spree/event_spec.rb +92 -0
  90. data/spec/lib/spree/money_spec.rb +3 -9
  91. data/spec/lib/tasks/migrations/migrate_shipping_rate_taxes_spec.rb +5 -3
  92. data/spec/mailers/order_mailer_spec.rb +1 -1
  93. data/spec/mailers/test_mailer_spec.rb +3 -1
  94. data/spec/models/spree/address_spec.rb +5 -4
  95. data/spec/models/spree/concerns/user_address_book_spec.rb +4 -4
  96. data/spec/models/spree/country_spec.rb +5 -5
  97. data/spec/models/spree/customer_return_spec.rb +1 -1
  98. data/spec/models/spree/order/checkout_spec.rb +3 -7
  99. data/spec/models/spree/order/finalizing_spec.rb +1 -1
  100. data/spec/models/spree/order/payment_spec.rb +3 -3
  101. data/spec/models/spree/order_inventory_spec.rb +1 -1
  102. data/spec/models/spree/order_spec.rb +67 -2
  103. data/spec/models/spree/order_updater_spec.rb +2 -2
  104. data/spec/models/spree/payment_spec.rb +12 -0
  105. data/spec/models/spree/product_spec.rb +3 -3
  106. data/spec/models/spree/promotion/rules/first_order_spec.rb +13 -3
  107. data/spec/models/spree/promotion/rules/item_total_spec.rb +15 -0
  108. data/spec/models/spree/promotion/rules/one_use_per_user_spec.rb +10 -0
  109. data/spec/models/spree/promotion/rules/product_spec.rb +15 -0
  110. data/spec/models/spree/promotion/rules/taxon_spec.rb +59 -8
  111. data/spec/models/spree/promotion/rules/user_logged_in_spec.rb +5 -0
  112. data/spec/models/spree/promotion_handler/shipping_spec.rb +1 -1
  113. data/spec/models/spree/promotion_spec.rb +80 -0
  114. data/spec/models/spree/reimbursement_spec.rb +3 -2
  115. data/spec/models/spree/return_item_spec.rb +9 -0
  116. data/spec/models/spree/shipment_spec.rb +3 -3
  117. data/spec/models/spree/stock/availability_spec.rb +1 -1
  118. data/spec/models/spree/stock/estimator_spec.rb +5 -7
  119. data/spec/models/spree/stock/location_filter/active_spec.rb +22 -0
  120. data/spec/models/spree/stock/location_sorter/default_first_spec.rb +4 -2
  121. data/spec/models/spree/stock/location_sorter/unsorted_spec.rb +3 -1
  122. data/spec/models/spree/stock/quantifier_spec.rb +1 -1
  123. data/spec/models/spree/stock/simple_coordinator_spec.rb +5 -0
  124. data/spec/models/spree/stock_item_spec.rb +3 -2
  125. data/spec/models/spree/stock_movement_spec.rb +1 -1
  126. data/spec/models/spree/store_credit_spec.rb +1 -1
  127. data/spec/models/spree/tax/order_adjuster_spec.rb +1 -1
  128. data/spec/models/spree/tax/taxation_integration_spec.rb +1 -1
  129. data/spec/models/spree/tax_category_spec.rb +21 -0
  130. data/spec/models/spree/taxon_spec.rb +28 -0
  131. data/spec/models/spree/unit_cancel_spec.rb +41 -0
  132. data/spec/models/spree/user_spec.rb +3 -3
  133. data/spec/models/spree/variant/pricing_options_spec.rb +23 -0
  134. data/spec/models/spree/variant/vat_price_generator_spec.rb +1 -1
  135. data/spec/models/spree/variant_spec.rb +11 -8
  136. data/spec/models/spree/wallet_payment_source_spec.rb +35 -6
  137. data/spec/models/spree/wallet_spec.rb +1 -1
  138. data/spec/spec_helper.rb +0 -4
  139. data/spec/support/concerns/default_price.rb +8 -0
  140. metadata +18 -5
  141. data/spec/lib/spree/permitted_attributes_spec.rb +0 -41
@@ -11,10 +11,10 @@ module Spree
11
11
  def eligible?(order, _options = {})
12
12
  if order.user.present?
13
13
  if promotion.used_by?(order.user, [order])
14
- eligibility_errors.add(:base, eligibility_error_message(:limit_once_per_user))
14
+ eligibility_errors.add(:base, eligibility_error_message(:limit_once_per_user), error_code: :limit_once_per_user)
15
15
  end
16
16
  else
17
- eligibility_errors.add(:base, eligibility_error_message(:no_user_specified))
17
+ eligibility_errors.add(:base, eligibility_error_message(:no_user_specified), error_code: :no_user_specified)
18
18
  end
19
19
 
20
20
  eligibility_errors.empty?
@@ -33,15 +33,15 @@ module Spree
33
33
  case preferred_match_policy
34
34
  when 'all'
35
35
  unless eligible_products.all? { |p| order.products.include?(p) }
36
- eligibility_errors.add(:base, eligibility_error_message(:missing_product))
36
+ eligibility_errors.add(:base, eligibility_error_message(:missing_product), error_code: :missing_product)
37
37
  end
38
38
  when 'any'
39
39
  unless order.products.any? { |p| eligible_products.include?(p) }
40
- eligibility_errors.add(:base, eligibility_error_message(:no_applicable_products))
40
+ eligibility_errors.add(:base, eligibility_error_message(:no_applicable_products), error_code: :no_applicable_products)
41
41
  end
42
42
  when 'none'
43
43
  unless order.products.none? { |p| eligible_products.include?(p) }
44
- eligibility_errors.add(:base, eligibility_error_message(:has_excluded_product))
44
+ eligibility_errors.add(:base, eligibility_error_message(:has_excluded_product), error_code: :has_excluded_product)
45
45
  end
46
46
  else
47
47
  raise "unexpected match policy: #{preferred_match_policy.inspect}"
@@ -27,34 +27,31 @@ module Spree
27
27
  end
28
28
 
29
29
  unless matches_all
30
- eligibility_errors.add(:base, eligibility_error_message(:missing_taxon))
30
+ eligibility_errors.add(:base, eligibility_error_message(:missing_taxon), error_code: :missing_taxon)
31
31
  end
32
32
  when 'any'
33
33
  unless order_taxons.where(id: rule_taxon_ids_with_children).exists?
34
- eligibility_errors.add(:base, eligibility_error_message(:no_matching_taxons))
34
+ eligibility_errors.add(:base, eligibility_error_message(:no_matching_taxons), error_code: :no_matching_taxons)
35
35
  end
36
36
  when 'none'
37
37
  if order_taxons.where(id: rule_taxon_ids_with_children).exists?
38
- eligibility_errors.add(:base, eligibility_error_message(:has_excluded_taxon))
38
+ eligibility_errors.add(:base, eligibility_error_message(:has_excluded_taxon), error_code: :has_excluded_taxon)
39
39
  end
40
40
  else
41
41
  # Change this to an exception in a future version of Solidus
42
42
  warn_invalid_match_policy(assume: 'any')
43
43
  unless order_taxons.where(id: rule_taxon_ids_with_children).exists?
44
- eligibility_errors.add(:base, eligibility_error_message(:no_matching_taxons))
44
+ eligibility_errors.add(:base, eligibility_error_message(:no_matching_taxons), error_code: :no_matching_taxons)
45
45
  end
46
46
  end
47
47
 
48
48
  eligibility_errors.empty?
49
49
  end
50
50
 
51
- # TODO: Fix bug - well described by jhawthorn in #1409:
52
- # `eligible?` checks the configured taxons and all descendants,
53
- # `actionable?` only seems to check against the taxons themselves (not children)
54
51
  def actionable?(line_item)
55
52
  found = Spree::Classification.where(
56
53
  product_id: line_item.variant.product_id,
57
- taxon_id: taxon_ids
54
+ taxon_id: rule_taxon_ids_with_children
58
55
  ).exists?
59
56
 
60
57
  case preferred_match_policy
@@ -10,7 +10,7 @@ module Spree
10
10
 
11
11
  def eligible?(order, _options = {})
12
12
  unless order.user.present?
13
- eligibility_errors.add(:base, eligibility_error_message(:no_user_specified))
13
+ eligibility_errors.add(:base, eligibility_error_message(:no_user_specified), error_code: :no_user_specified)
14
14
  end
15
15
  eligibility_errors.empty?
16
16
  end
@@ -44,9 +44,9 @@ module Spree
44
44
  @success = I18n.t(status_code, scope: 'spree')
45
45
  end
46
46
 
47
- def set_error_code(status_code)
47
+ def set_error_code(status_code, options = {})
48
48
  @status_code = status_code
49
- @error = I18n.t(status_code, scope: 'spree')
49
+ @error = options[:error] || I18n.t(status_code, scope: 'spree')
50
50
  end
51
51
 
52
52
  def promotion
@@ -72,7 +72,7 @@ module Spree
72
72
  return promotion_applied if promotion_exists_on_order?(order, promotion)
73
73
 
74
74
  unless promotion.eligible?(order, promotion_code: promotion_code)
75
- self.error = promotion.eligibility_errors.full_messages.first unless promotion.eligibility_errors.blank?
75
+ set_promotion_eligibility_error_code(promotion)
76
76
  return (error || ineligible_for_this_order)
77
77
  end
78
78
 
@@ -87,6 +87,15 @@ module Spree
87
87
  end
88
88
  end
89
89
 
90
+ def set_promotion_eligibility_error_code(promotion)
91
+ return unless eligibility_error_code_present?(promotion)
92
+
93
+ eligibility_error = promotion.eligibility_errors.details[:base].first
94
+
95
+ @status_code = eligibility_error[:error_code]
96
+ @error = eligibility_error[:error]
97
+ end
98
+
90
99
  def promotion_usage_limit_exceeded
91
100
  set_error_code :coupon_code_max_usage
92
101
  end
@@ -102,6 +111,13 @@ module Spree
102
111
  def promotion_exists_on_order?(order, promotion)
103
112
  order.promotions.include? promotion
104
113
  end
114
+
115
+ def eligibility_error_code_present?(promotion)
116
+ promotion.eligibility_errors.present? &&
117
+ promotion.eligibility_errors.details.present? &&
118
+ promotion.eligibility_errors.details.key?(:base) &&
119
+ promotion.eligibility_errors.details[:base].first[:error_code].present?
120
+ end
105
121
  end
106
122
  end
107
123
  end
@@ -11,6 +11,8 @@ module Spree
11
11
 
12
12
  after_touch :touch_all_products
13
13
 
14
+ self.whitelisted_ransackable_attributes = %w[name]
15
+
14
16
  private
15
17
 
16
18
  def touch_all_products
@@ -111,11 +111,15 @@ module Spree
111
111
 
112
112
  if unpaid_amount_within_tolerance?
113
113
  reimbursed!
114
+ Spree::Event.fire 'reimbursement_reimbursed', reimbursement: self
114
115
  reimbursement_success_hooks.each { |h| h.call self }
115
- send_reimbursement_email
116
116
  else
117
117
  errored!
118
+ Spree::Event.fire 'reimbursement_errored', reimbursement: self
118
119
  reimbursement_failure_hooks.each { |h| h.call self }
120
+ end
121
+
122
+ if errored?
119
123
  raise IncompleteReimbursementError, I18n.t("spree.validation.unpaid_amount_not_zero", amount: unpaid_amount)
120
124
  end
121
125
  end
@@ -176,10 +180,6 @@ module Spree
176
180
  end
177
181
  end
178
182
 
179
- def send_reimbursement_email
180
- Spree::Config.reimbursement_mailer_class.reimbursement_email(id).deliver_later
181
- end
182
-
183
183
  # If there are multiple different reimbursement types for a single
184
184
  # reimbursement we open ourselves to a one-cent rounding error for every
185
185
  # type over the first one. This is due to how we round #unpaid_amount and
@@ -130,6 +130,8 @@ module Spree
130
130
  after_transition any => any, do: :persist_acceptance_status_errors
131
131
  end
132
132
 
133
+ attr_accessor :skip_customer_return_processing
134
+
133
135
  # @param inventory_unit [Spree::InventoryUnit] the inventory for which we
134
136
  # want a return item
135
137
  # @return [Spree::ReturnItem] a valid return item for the given inventory
@@ -233,10 +235,12 @@ module Spree
233
235
 
234
236
  def process_inventory_unit!
235
237
  inventory_unit.return!
236
-
237
238
  if customer_return
238
239
  customer_return.stock_location.restock(inventory_unit.variant, 1, customer_return) if should_restock?
239
- customer_return.process_return!
240
+ unless skip_customer_return_processing
241
+ Deprecation.warn 'From Solidus v2.9 onwards, #process_inventory_unit! will not call customer_return#process_return!'
242
+ customer_return.process_return!
243
+ end
240
244
  end
241
245
  end
242
246
 
@@ -19,6 +19,8 @@ module Spree
19
19
  deprecate find_all_by_name_or_abbr: :with_name_or_abbr, deprecator: Spree::Deprecation
20
20
  end
21
21
 
22
+ self.whitelisted_ransackable_attributes = %w[name]
23
+
22
24
  # table of { country.id => [ state.id , state.name ] }, arrays sorted by name
23
25
  # blank is added elsewhere, if needed
24
26
  def self.states_group_by_country_id
@@ -36,5 +38,9 @@ module Spree
36
38
  def to_s
37
39
  name
38
40
  end
41
+
42
+ def state_with_country
43
+ "#{name} (#{country})"
44
+ end
39
45
  end
40
46
  end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ module Stock
5
+ module LocationFilter
6
+ # This stock location filter return all active stock locations
7
+ class Active < Spree::Stock::LocationFilter::Base
8
+ def filter
9
+ stock_locations.active
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ module Stock
5
+ module LocationFilter
6
+ # Stock location filters are used to which stock location should be
7
+ # considered when allocating stocks for a new shipment
8
+ #
9
+ # @abstract To implement your own location filter, subclass and
10
+ # implement {#filter}.
11
+ class Base
12
+ # @!attribute [r] stock_locations
13
+ # @return [Enumerable<Spree::StockLocation>]
14
+ # a collection of locations to sort
15
+ attr_reader :stock_locations
16
+
17
+ # @!attribute [r] order
18
+ # @return <Spree::Order>
19
+ # the order we are creating the shipment for
20
+ attr_reader :order
21
+
22
+ # Initializes the stock location filter.
23
+ #
24
+ # @param stock_locations [Enumerable<Spree::StockLocation>]
25
+ # a collection of locations to sort
26
+ # @param order <Spree::Order>
27
+ # the order we are creating the shipment for
28
+ def initialize(stock_locations, order)
29
+ @stock_locations = stock_locations
30
+ @order = order
31
+ end
32
+
33
+ # Filter the stock locations.
34
+ #
35
+ # @return [Enumerable<Spree::StockLocation>]
36
+ # a collection of filtered stock locations
37
+ def filter
38
+ raise NotImplementedError
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -26,7 +26,10 @@ module Spree
26
26
  @order = order
27
27
  @inventory_units = inventory_units || InventoryUnitBuilder.new(order).units
28
28
  @splitters = Spree::Config.environment.stock_splitters
29
- @stock_locations = Spree::Config.stock.location_sorter_class.new(Spree::StockLocation.active).sort
29
+
30
+ filtered_stock_locations = Spree::Config.stock.location_filter_class.new(Spree::StockLocation.all, @order).filter
31
+ sorted_stock_locations = Spree::Config.stock.location_sorter_class.new(filtered_stock_locations).sort
32
+ @stock_locations = sorted_stock_locations
30
33
 
31
34
  @inventory_units_by_variant = @inventory_units.group_by(&:variant)
32
35
  @desired = Spree::StockQuantities.new(@inventory_units_by_variant.transform_values(&:count))
@@ -31,6 +31,8 @@ module Spree
31
31
  after_create :create_stock_items, if: :propagate_all_variants?
32
32
  after_save :ensure_one_default
33
33
 
34
+ self.whitelisted_ransackable_attributes = %w[name]
35
+
34
36
  def state_text
35
37
  state.try(:abbr) || state.try(:name) || state_name
36
38
  end
@@ -1,8 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'discard'
4
+
3
5
  module Spree
4
6
  class TaxCategory < Spree::Base
5
7
  acts_as_paranoid
8
+ include Spree::ParanoiaDeprecations
9
+
10
+ include Discard::Model
11
+ self.discard_column = :deleted_at
12
+
13
+ after_discard do
14
+ self.tax_rate_tax_categories = []
15
+ end
16
+
6
17
  validates :name, presence: true
7
18
  validates_uniqueness_of :name, unless: :deleted_at
8
19
 
@@ -25,15 +25,9 @@ module Spree
25
25
  after_save :touch_ancestors_and_taxonomy
26
26
  after_touch :touch_ancestors_and_taxonomy
27
27
 
28
- has_attached_file :icon,
29
- styles: { mini: '32x32>', normal: '128x128>' },
30
- default_style: :mini,
31
- url: '/spree/taxons/:id/:style/:basename.:extension',
32
- path: ':rails_root/public/spree/taxons/:id/:style/:basename.:extension',
33
- default_url: '/assets/default_taxon.png'
28
+ include ::Spree::Config.taxon_attachment_module
34
29
 
35
- validates_attachment :icon,
36
- content_type: { content_type: ["image/jpg", "image/jpeg", "image/png", "image/gif"] }
30
+ self.whitelisted_ransackable_attributes = %w[name]
37
31
 
38
32
  # @note This method is meant to be overridden on a store by store basis.
39
33
  # @return [Array] filters that should be used for a taxon
@@ -59,9 +53,8 @@ module Spree
59
53
  # Sets this taxons permalink to a valid url encoded string based on its
60
54
  # name and its parents permalink (if present.)
61
55
  def set_permalink
62
- permalink_tail = permalink.split('/').last if permalink.present?
63
- permalink_tail ||= Spree::Config.taxon_url_parametizer_class.parameterize(name)
64
- self.permalink_part = permalink_tail
56
+ permalink_tail = permalink.present? ? permalink.split('/').last : name
57
+ self.permalink_part = Spree::Config.taxon_url_parametizer_class.parameterize(permalink_tail)
65
58
  end
66
59
 
67
60
  # Update the permalink for this taxon and all children (if necessary)
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree::Taxon::PaperclipAttachment
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ has_attached_file :icon,
8
+ styles: { mini: '32x32>', normal: '128x128>' },
9
+ default_style: :mini,
10
+ url: '/spree/taxons/:id/:style/:basename.:extension',
11
+ path: ':rails_root/public/spree/taxons/:id/:style/:basename.:extension',
12
+ default_url: '/assets/default_taxon.png'
13
+
14
+ validates_attachment :icon,
15
+ content_type: { content_type: %w[image/jpg image/jpeg image/png image/gif] }
16
+ end
17
+
18
+ def icon_present?
19
+ icon.present?
20
+ end
21
+ end
@@ -13,6 +13,8 @@ module Spree
13
13
 
14
14
  default_scope -> { order(position: :asc) }
15
15
 
16
+ self.whitelisted_ransackable_attributes = %w[name]
17
+
16
18
  private
17
19
 
18
20
  def set_name
@@ -34,6 +34,17 @@ class Spree::UnitCancel < Spree::Base
34
34
  # This method is used by Adjustment#update to recalculate the cost.
35
35
  def compute_amount(line_item)
36
36
  raise "Adjustable does not match line item" unless line_item == inventory_unit.line_item
37
- -(line_item.total.to_d / line_item.inventory_units.not_canceled.reject(&:original_return_item ).size)
37
+
38
+ -weighted_line_item_amount(line_item)
39
+ end
40
+
41
+ private
42
+
43
+ def weighted_line_item_amount(line_item)
44
+ line_item.total_before_tax / quantity_of_line_item(line_item)
45
+ end
46
+
47
+ def quantity_of_line_item(line_item)
48
+ BigDecimal(line_item.inventory_units.not_canceled.reject(&:original_return_item).size)
38
49
  end
39
50
  end
@@ -121,7 +121,7 @@ module Spree
121
121
  Spree::StockItem.arel_table[:count_on_hand].gt(0),
122
122
  Spree::StockItem.arel_table[:backorderable].eq(true)
123
123
  ]
124
- joins(:stock_items).where(arel_conditions.inject(:or))
124
+ joins(:stock_items).where(arel_conditions.inject(:or)).distinct
125
125
  end
126
126
 
127
127
  self.whitelisted_ransackable_associations = %w[option_values product prices default_price]
@@ -49,6 +49,16 @@ module Spree
49
49
  new(currency: price.currency, country_iso: price.country_iso)
50
50
  end
51
51
 
52
+ # This creates the correct pricing options for a price, so the store owners can easily customize how to
53
+ # find the pricing based on the view context, having available current_store, current_spree_user, request.host_name, etc.
54
+ # @return [Spree::Variant::PricingOptions] pricing options for pricing a line item
55
+ def self.from_context(context)
56
+ new(
57
+ currency: context.current_store.try!(:default_currency).presence || Spree::Config[:currency],
58
+ country_iso: context.current_store.try!(:cart_tax_country_iso).presence
59
+ )
60
+ end
61
+
52
62
  # @return [Hash] The hash of exact desired attributes
53
63
  attr_reader :desired_attributes
54
64
 
@@ -1,19 +1,35 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Spree::WalletPaymentSource < ActiveRecord::Base
4
- belongs_to :user, class_name: Spree::UserClassHandle.new, foreign_key: 'user_id', inverse_of: :wallet_payment_sources
5
- belongs_to :payment_source, polymorphic: true, inverse_of: :wallet_payment_sources
3
+ module Spree
4
+ class WalletPaymentSource < Spree::Base
5
+ belongs_to :user, class_name: Spree::UserClassHandle.new, foreign_key: 'user_id', inverse_of: :wallet_payment_sources
6
+ belongs_to :payment_source, polymorphic: true, inverse_of: :wallet_payment_sources
6
7
 
7
- validates_presence_of :user
8
- validates_presence_of :payment_source
8
+ validates_presence_of :user
9
+ validates_presence_of :payment_source
10
+ validates :user_id, uniqueness: {
11
+ scope: [:payment_source_type, :payment_source_id],
12
+ message: :payment_source_already_exists
13
+ }
9
14
 
10
- validate :check_for_payment_source_class
15
+ validate :check_for_payment_source_class
16
+ validate :validate_payment_source_ownership
11
17
 
12
- private
18
+ private
13
19
 
14
- def check_for_payment_source_class
15
- if !payment_source.is_a?(Spree::PaymentSource)
16
- errors.add(:payment_source, :has_to_be_payment_source_class)
20
+ def check_for_payment_source_class
21
+ if !payment_source.is_a?(Spree::PaymentSource)
22
+ errors.add(:payment_source, :has_to_be_payment_source_class)
23
+ end
24
+ end
25
+
26
+ def validate_payment_source_ownership
27
+ return unless payment_source.present?
28
+
29
+ if payment_source.respond_to?(:user_id) &&
30
+ payment_source.user_id != user_id
31
+ errors.add(:payment_source, :not_owned_by_user)
32
+ end
17
33
  end
18
34
  end
19
35
  end