spree_core 3.6.6 → 3.7.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (218) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/spree.js +60 -0
  3. data/app/finders/spree/countries/find.rb +31 -0
  4. data/app/finders/spree/credit_cards/find.rb +12 -0
  5. data/app/finders/spree/line_items/find_by_variant.rb +13 -0
  6. data/app/finders/spree/orders/find_current.rb +34 -0
  7. data/app/finders/spree/products/find.rb +93 -0
  8. data/app/finders/spree/taxons/find.rb +79 -0
  9. data/app/helpers/spree/base_helper.rb +7 -3
  10. data/app/helpers/spree/products_helper.rb +2 -1
  11. data/app/models/concerns/spree/adjustment_source.rb +11 -6
  12. data/app/models/concerns/spree/user_address.rb +2 -2
  13. data/app/models/concerns/spree/vat_price_calculation.rb +2 -1
  14. data/app/models/spree/ability.rb +2 -2
  15. data/app/models/spree/address.rb +23 -14
  16. data/app/models/spree/adjustable/adjustments_updater.rb +1 -1
  17. data/app/models/spree/adjustable/promotion_accumulator.rb +2 -1
  18. data/app/models/spree/adjustment.rb +18 -3
  19. data/app/models/spree/asset/support/active_storage.rb +1 -1
  20. data/app/models/spree/calculator.rb +1 -4
  21. data/app/models/spree/calculator/flexi_rate.rb +8 -11
  22. data/app/models/spree/calculator/returns/default_refund_amount.rb +3 -1
  23. data/app/models/spree/calculator/shipping/flexi_rate.rb +13 -13
  24. data/app/models/spree/country.rb +4 -0
  25. data/app/models/spree/credit_card.rb +8 -2
  26. data/app/models/spree/customer_return.rb +1 -0
  27. data/app/models/spree/fulfilment_changer.rb +117 -0
  28. data/app/models/spree/gateway.rb +1 -0
  29. data/app/models/spree/gateway/bogus.rb +3 -2
  30. data/app/models/spree/image.rb +13 -0
  31. data/app/models/spree/image/configuration/active_storage.rb +3 -3
  32. data/app/models/spree/inventory_unit.rb +1 -1
  33. data/app/models/spree/line_item.rb +3 -2
  34. data/app/models/spree/order.rb +72 -28
  35. data/app/models/spree/order/checkout.rb +10 -0
  36. data/app/models/spree/order/store_credit.rb +14 -35
  37. data/app/models/spree/order_contents.rb +22 -118
  38. data/app/models/spree/order_inventory.rb +6 -2
  39. data/app/models/spree/order_merger.rb +1 -3
  40. data/app/models/spree/order_promotion.rb +10 -0
  41. data/app/models/spree/order_updater.rb +11 -8
  42. data/app/models/spree/payment.rb +9 -3
  43. data/app/models/spree/payment/processing.rb +4 -4
  44. data/app/models/spree/preferences/store.rb +3 -3
  45. data/app/models/spree/product.rb +32 -0
  46. data/app/models/spree/product/scopes.rb +13 -34
  47. data/app/models/spree/product_property.rb +1 -1
  48. data/app/models/spree/promotion.rb +2 -0
  49. data/app/models/spree/promotion/actions/create_adjustment.rb +6 -1
  50. data/app/models/spree/promotion/actions/create_item_adjustments.rb +10 -2
  51. data/app/models/spree/promotion/actions/create_line_items.rb +3 -2
  52. data/app/models/spree/promotion/actions/free_shipping.rb +1 -0
  53. data/app/models/spree/promotion/rules/item_total.rb +2 -2
  54. data/app/models/spree/promotion_handler/coupon.rb +10 -6
  55. data/app/models/spree/promotion_handler/page.rb +1 -1
  56. data/app/models/spree/promotion_handler/promotion_duplicator.rb +4 -4
  57. data/app/models/spree/refund.rb +1 -1
  58. data/app/models/spree/reimbursement/reimbursement_type_engine.rb +1 -0
  59. data/app/models/spree/reimbursement_tax_calculator.rb +2 -2
  60. data/app/models/spree/return_item.rb +7 -4
  61. data/app/models/spree/return_item/eligibility_validator/default.rb +6 -6
  62. data/app/models/spree/return_item/exchange_variant_eligibility/same_product.rb +1 -1
  63. data/app/models/spree/shipment.rb +27 -34
  64. data/app/models/spree/shipping_method.rb +2 -0
  65. data/app/models/spree/shipping_rate.rb +31 -16
  66. data/app/models/spree/stock/adjuster.rb +1 -0
  67. data/app/models/spree/stock/estimator.rb +2 -0
  68. data/app/models/spree/stock/inventory_unit_builder.rb +5 -5
  69. data/app/models/spree/stock/packer.rb +1 -0
  70. data/app/models/spree/stock/quantifier.rb +16 -4
  71. data/app/models/spree/stock_item.rb +1 -0
  72. data/app/models/spree/stock_location.rb +1 -1
  73. data/app/models/spree/stock_movement.rb +1 -0
  74. data/app/models/spree/stock_transfer.rb +1 -1
  75. data/app/models/spree/store_credit.rb +5 -10
  76. data/app/models/spree/tax_rate.rb +3 -0
  77. data/app/models/spree/taxon.rb +2 -2
  78. data/app/models/spree/taxon_image.rb +18 -0
  79. data/app/models/spree/{taxon_icon → taxon_image}/configuration/active_storage.rb +2 -2
  80. data/app/models/spree/{taxon_icon → taxon_image}/configuration/paperclip.rb +1 -1
  81. data/app/models/spree/variant.rb +28 -2
  82. data/app/models/spree/zone.rb +5 -5
  83. data/app/paginators/spree/shared/paginate.rb +19 -0
  84. data/app/services/spree/cart/add_item.rb +43 -0
  85. data/app/services/spree/cart/create.rb +21 -0
  86. data/app/services/spree/cart/recalculate.rb +32 -0
  87. data/app/services/spree/cart/remove_item.rb +37 -0
  88. data/app/services/spree/cart/remove_line_item.rb +16 -0
  89. data/app/services/spree/cart/set_quantity.rb +22 -0
  90. data/app/services/spree/cart/update.rb +37 -0
  91. data/app/services/spree/checkout/add_store_credit.rb +51 -0
  92. data/app/services/spree/checkout/advance.rb +18 -0
  93. data/app/services/spree/checkout/complete.rb +23 -0
  94. data/app/services/spree/checkout/get_shipping_rates.rb +48 -0
  95. data/app/services/spree/checkout/next.rb +13 -0
  96. data/app/services/spree/checkout/remove_store_credit.rb +17 -0
  97. data/app/services/spree/checkout/update.rb +13 -0
  98. data/app/services/spree/compare_line_items.rb +21 -0
  99. data/app/services/spree/generate_token.rb +20 -0
  100. data/app/sorters/spree/products/sort.rb +58 -0
  101. data/config/locales/en.yml +20 -1
  102. data/db/default/spree/countries.rb +1 -1
  103. data/db/default/spree/default_reimbursement_type.rb +1 -1
  104. data/db/default/spree/roles.rb +2 -2
  105. data/db/default/spree/states.rb +2 -1
  106. data/db/default/spree/stores.rb +1 -1
  107. data/db/default/spree/zones.rb +5 -6
  108. data/db/migrate/20120831092320_spree_one_two.rb +36 -36
  109. data/db/migrate/20120831092359_spree_promo_one_two.rb +1 -1
  110. data/db/migrate/20130211190146_create_spree_stock_items.rb +1 -1
  111. data/db/migrate/20130211191120_create_spree_stock_locations.rb +1 -1
  112. data/db/migrate/20130301162924_create_shipping_method_categories.rb +1 -1
  113. data/db/migrate/20130304162240_create_spree_shipping_rates.rb +1 -1
  114. data/db/migrate/20130305143310_create_stock_movements.rb +1 -1
  115. data/db/migrate/20130418125341_create_spree_stock_transfers.rb +1 -1
  116. data/db/migrate/20140205120320_create_spree_payment_capture_events.rb +1 -1
  117. data/db/migrate/20140309023735_migrate_old_preferences.rb +5 -1
  118. data/db/migrate/20140309024355_create_spree_stores.rb +1 -1
  119. data/db/migrate/20140625214618_create_spree_refunds.rb +1 -1
  120. data/db/migrate/20140702140656_create_spree_return_authorization_inventory_unit.rb +1 -1
  121. data/db/migrate/20140713140455_create_spree_return_authorization_reasons.rb +1 -1
  122. data/db/migrate/20140713140527_create_spree_refund_reasons.rb +1 -1
  123. data/db/migrate/20140715182625_create_spree_promotion_categories.rb +1 -1
  124. data/db/migrate/20140718133010_create_spree_customer_returns.rb +1 -1
  125. data/db/migrate/20140725131539_create_spree_reimbursements.rb +1 -1
  126. data/db/migrate/20140731150017_create_spree_reimbursement_types.rb +1 -1
  127. data/db/migrate/20150118210639_create_spree_store_credits.rb +1 -1
  128. data/db/migrate/20150118211500_create_spree_store_credit_categories.rb +1 -1
  129. data/db/migrate/20150118212051_create_spree_store_credit_events.rb +1 -1
  130. data/db/migrate/20150118212101_create_spree_store_credit_types.rb +1 -1
  131. data/db/migrate/20150309161154_ensure_payments_have_numbers.rb +6 -2
  132. data/db/migrate/20180613080857_rename_guest_token_to_token_in_orders.rb +5 -0
  133. data/db/migrate/20180915160001_add_timestamps_to_spree_prices.rb +12 -0
  134. data/db/migrate/20181024100754_add_deleted_at_to_spree_credit_cards.rb +6 -0
  135. data/lib/generators/spree/custom_user/custom_user_generator.rb +1 -3
  136. data/lib/generators/spree/dummy/dummy_generator.rb +30 -33
  137. data/lib/generators/spree/dummy/templates/rails/database.yml +6 -1
  138. data/lib/generators/spree/dummy/templates/rails/test.rb +2 -0
  139. data/lib/generators/spree/dummy_model/dummy_model_generator.rb +1 -1
  140. data/lib/generators/spree/install/install_generator.rb +2 -1
  141. data/lib/spree/core.rb +2 -4
  142. data/lib/spree/core/controller_helpers/auth.rb +15 -5
  143. data/lib/spree/core/controller_helpers/common.rb +0 -11
  144. data/lib/spree/core/controller_helpers/order.rb +6 -6
  145. data/lib/spree/core/controller_helpers/respond_with.rb +3 -1
  146. data/lib/spree/core/controller_helpers/strong_parameters.rb +1 -0
  147. data/lib/spree/core/engine.rb +9 -3
  148. data/lib/spree/core/importer/order.rb +8 -12
  149. data/lib/spree/core/product_duplicator.rb +6 -1
  150. data/lib/spree/core/product_filters.rb +15 -14
  151. data/lib/spree/core/query_filters.rb +11 -0
  152. data/lib/spree/core/query_filters/comparable.rb +46 -0
  153. data/lib/spree/core/query_filters/date.rb +8 -0
  154. data/lib/spree/core/query_filters/number.rb +8 -0
  155. data/lib/spree/core/query_filters/text.rb +32 -0
  156. data/lib/spree/core/token_generator.rb +2 -2
  157. data/lib/spree/core/version.rb +1 -1
  158. data/lib/spree/i18n.rb +1 -1
  159. data/lib/spree/migrations.rb +2 -0
  160. data/lib/spree/money.rb +12 -12
  161. data/lib/spree/permitted_attributes.rb +11 -6
  162. data/lib/spree/service_module.rb +98 -0
  163. data/lib/spree/testing_support/capybara_config.rb +20 -0
  164. data/lib/spree/testing_support/capybara_ext.rb +6 -3
  165. data/lib/spree/testing_support/factories.rb +1 -1
  166. data/lib/spree/testing_support/factories/address_factory.rb +10 -9
  167. data/lib/spree/testing_support/factories/adjustment_factory.rb +8 -6
  168. data/lib/spree/testing_support/factories/country_factory.rb +4 -4
  169. data/lib/spree/testing_support/factories/credit_card_factory.rb +7 -5
  170. data/lib/spree/testing_support/factories/customer_return_factory.rb +1 -1
  171. data/lib/spree/testing_support/factories/image_factory.rb +7 -1
  172. data/lib/spree/testing_support/factories/inventory_unit_factory.rb +5 -4
  173. data/lib/spree/testing_support/factories/line_item_factory.rb +3 -2
  174. data/lib/spree/testing_support/factories/options_factory.rb +2 -3
  175. data/lib/spree/testing_support/factories/order_factory.rb +16 -12
  176. data/lib/spree/testing_support/factories/order_promotion_factory.rb +6 -0
  177. data/lib/spree/testing_support/factories/payment_factory.rb +9 -7
  178. data/lib/spree/testing_support/factories/payment_method_factory.rb +8 -8
  179. data/lib/spree/testing_support/factories/price_factory.rb +2 -2
  180. data/lib/spree/testing_support/factories/product_factory.rb +10 -10
  181. data/lib/spree/testing_support/factories/promotion_category_factory.rb +1 -1
  182. data/lib/spree/testing_support/factories/promotion_factory.rb +14 -4
  183. data/lib/spree/testing_support/factories/property_factory.rb +2 -2
  184. data/lib/spree/testing_support/factories/prototype_factory.rb +3 -3
  185. data/lib/spree/testing_support/factories/refund_factory.rb +6 -6
  186. data/lib/spree/testing_support/factories/reimbursement_factory.rb +1 -1
  187. data/lib/spree/testing_support/factories/reimbursement_type_factory.rb +2 -2
  188. data/lib/spree/testing_support/factories/return_authorization_factory.rb +4 -3
  189. data/lib/spree/testing_support/factories/role_factory.rb +1 -1
  190. data/lib/spree/testing_support/factories/shipment_factory.rb +3 -3
  191. data/lib/spree/testing_support/factories/shipping_method_factory.rb +4 -4
  192. data/lib/spree/testing_support/factories/state_factory.rb +2 -5
  193. data/lib/spree/testing_support/factories/stock_factory.rb +3 -3
  194. data/lib/spree/testing_support/factories/stock_item_factory.rb +1 -1
  195. data/lib/spree/testing_support/factories/stock_location_factory.rb +7 -7
  196. data/lib/spree/testing_support/factories/stock_movement_factory.rb +3 -3
  197. data/lib/spree/testing_support/factories/store_credit_category_factory.rb +2 -2
  198. data/lib/spree/testing_support/factories/store_credit_type_factory.rb +1 -1
  199. data/lib/spree/testing_support/factories/store_factory.rb +5 -4
  200. data/lib/spree/testing_support/factories/tax_rate_factory.rb +2 -1
  201. data/lib/spree/testing_support/factories/user_factory.rb +4 -4
  202. data/lib/spree/testing_support/factories/variant_factory.rb +15 -15
  203. data/lib/spree/testing_support/factories/zone_factory.rb +3 -3
  204. data/lib/spree/testing_support/image_helpers.rb +19 -0
  205. data/lib/tasks/core.rake +21 -4
  206. data/lib/tasks/exchanges.rake +4 -4
  207. data/spree_core.gemspec +3 -3
  208. data/vendor/assets/javascripts/fetch.umd.js +531 -0
  209. data/vendor/assets/javascripts/polyfill.min.js +1 -0
  210. metadata +50 -17
  211. data/app/assets/javascripts/spree.js.coffee +0 -59
  212. data/app/models/spree/taxon_icon.rb +0 -5
  213. data/lib/generators/spree/dummy/templates/initializers/custom_user.rb +0 -1
  214. data/lib/spree/core/environment.rb +0 -15
  215. data/lib/spree/core/environment/calculators.rb +0 -11
  216. data/lib/spree/core/environment_extension.rb +0 -28
  217. data/lib/spree/core/validators/email.rb +0 -8
  218. data/lib/spree/promo/environment.rb +0 -9
@@ -26,7 +26,7 @@ module Spree
26
26
  if units_count < line_item.quantity
27
27
  quantity = line_item.quantity - units_count
28
28
 
29
- shipment = determine_target_shipment unless shipment
29
+ shipment ||= determine_target_shipment
30
30
  add_to_shipment(shipment, quantity)
31
31
  elsif (units_count > line_item.quantity) || (units_count == line_item.quantity && line_item_changed)
32
32
  remove(units_count, shipment)
@@ -43,6 +43,7 @@ module Spree
43
43
  else
44
44
  order.shipments.each do |shipment|
45
45
  break if quantity.zero?
46
+
46
47
  quantity -= remove_from_shipment(shipment, quantity)
47
48
  end
48
49
  end
@@ -71,7 +72,9 @@ module Spree
71
72
  end
72
73
 
73
74
  def add_to_shipment(shipment, quantity)
74
- if variant.should_track_inventory?
75
+ if shipment.nil?
76
+ shipment = order.create_proposed_shipments.first
77
+ elsif variant.should_track_inventory?
75
78
  on_hand, back_order = shipment.stock_location.fill_status(variant, quantity)
76
79
 
77
80
  shipment.set_up_inventory('on_hand', variant, order, line_item, on_hand)
@@ -99,6 +102,7 @@ module Spree
99
102
  shipment_units.each do |inventory_unit|
100
103
  inventory_unit.quantity.times do
101
104
  break if removed_quantity == quantity
105
+
102
106
  if inventory_unit.quantity > 1
103
107
  inventory_unit.decrement(:quantity)
104
108
  else
@@ -29,9 +29,7 @@ module Spree
29
29
  def find_matching_line_item(other_order_line_item)
30
30
  order.line_items.detect do |my_li|
31
31
  my_li.variant == other_order_line_item.variant &&
32
- order.line_item_comparison_hooks.all? do |hook|
33
- order.send(hook, my_li, other_order_line_item.serializable_hash)
34
- end
32
+ CompareLineItems.new.call(order: order, line_item: my_li, options: other_order_line_item.serializable_hash).value
35
33
  end
36
34
  end
37
35
 
@@ -2,5 +2,15 @@ module Spree
2
2
  class OrderPromotion < Spree::Base
3
3
  belongs_to :order, class_name: 'Spree::Order'
4
4
  belongs_to :promotion, class_name: 'Spree::Promotion'
5
+
6
+ delegate :name, :description, :code, to: :promotion
7
+ delegate :currency, to: :order
8
+
9
+ extend Spree::DisplayMoney
10
+ money_methods :amount
11
+
12
+ def amount
13
+ order.all_adjustments.promotion.where(source: promotion.actions).sum(:amount)
14
+ end
5
15
  end
6
16
  end
@@ -53,10 +53,13 @@ module Spree
53
53
 
54
54
  # give each of the shipments a chance to update themselves
55
55
  def update_shipments
56
+ shipping_method_filter = order.completed? ? ShippingMethod::DISPLAY_ON_BACK_END : ShippingMethod::DISPLAY_ON_FRONT_END
57
+
56
58
  shipments.each do |shipment|
57
59
  next unless shipment.persisted?
60
+
58
61
  shipment.update!(order)
59
- shipment.refresh_rates
62
+ shipment.refresh_rates(shipping_method_filter)
60
63
  shipment.update_amounts
61
64
  end
62
65
  end
@@ -132,16 +135,16 @@ module Spree
132
135
  # get all the shipment states for this order
133
136
  shipment_states = shipments.states
134
137
  order.shipment_state = if shipment_states.size > 1
135
- # multiple shiment states means it's most likely partially shipped
138
+ # multiple shipment states means it's most likely partially shipped
136
139
  'partial'
137
140
  else
138
- # will return nil if no shipments are found
141
+ # will return nil if no shipments are found
139
142
  shipment_states.first
140
- # TODO: inventory unit states?
141
- # if order.shipment_state && order.inventory_units.where(shipment_id: nil).exists?
142
- # shipments exist but there are unassigned inventory units
143
- # order.shipment_state = 'partial'
144
- # end
143
+ # TODO: inventory unit states?
144
+ # if order.shipment_state && order.inventory_units.where(shipment_id: nil).exists?
145
+ # shipments exist but there are unassigned inventory units
146
+ # order.shipment_state = 'partial'
147
+ # end
145
148
  end
146
149
  end
147
150
 
@@ -24,6 +24,7 @@ module Spree
24
24
 
25
25
  validates :payment_method, presence: true
26
26
  validates :number, uniqueness: true
27
+ validates :source, presence: true, if: -> { payment_method&.source_required? }
27
28
 
28
29
  before_validation :validate_source
29
30
 
@@ -43,6 +44,7 @@ module Spree
43
44
  validates :amount, numericality: true
44
45
 
45
46
  delegate :store_credit?, to: :payment_method, allow_nil: true
47
+ delegate :name, to: :payment_method, allow_nil: true, prefix: true
46
48
  default_scope { order(:created_at) }
47
49
 
48
50
  scope :from_credit_card, -> { where(source_type: 'Spree::CreditCard') }
@@ -102,8 +104,8 @@ module Spree
102
104
  after_transition do |payment, transition|
103
105
  payment.state_changes.create!(
104
106
  previous_state: transition.from,
105
- next_state: transition.to,
106
- name: 'payment'
107
+ next_state: transition.to,
108
+ name: 'payment'
107
109
  )
108
110
  end
109
111
  end
@@ -138,6 +140,7 @@ module Spree
138
140
  # see https://github.com/spree/spree/issues/981
139
141
  def build_source
140
142
  return unless new_record?
143
+
141
144
  if source_attributes.present? && source.blank? && payment_method.try(:payment_source_class)
142
145
  self.source = payment_method.payment_source_class.new(source_attributes)
143
146
  source.payment_method_id = payment_method.id
@@ -146,7 +149,8 @@ module Spree
146
149
  end
147
150
 
148
151
  def actions
149
- return [] unless payment_source && payment_source.respond_to?(:actions)
152
+ return [] unless payment_source&.respond_to?(:actions)
153
+
150
154
  payment_source.actions.select { |action| !payment_source.respond_to?("can_#{action}?") || payment_source.send("can_#{action}?", self) }
151
155
  end
152
156
 
@@ -157,6 +161,7 @@ module Spree
157
161
 
158
162
  def is_avs_risky?
159
163
  return false if avs_response.blank? || NON_RISKY_AVS_CODES.include?(avs_response)
164
+
160
165
  true
161
166
  end
162
167
 
@@ -164,6 +169,7 @@ module Spree
164
169
  return false if cvv_response_code == 'M'
165
170
  return false if cvv_response_code.nil?
166
171
  return false if cvv_response_message.present?
172
+
167
173
  true
168
174
  end
169
175
 
@@ -8,7 +8,7 @@ module Spree
8
8
  end
9
9
 
10
10
  def process!
11
- if payment_method && payment_method.auto_capture?
11
+ if payment_method&.auto_capture?
12
12
  purchase!
13
13
  else
14
14
  authorize!
@@ -29,6 +29,7 @@ module Spree
29
29
  # a new pending payment record for the remaining amount to capture later.
30
30
  def capture!(amount = nil)
31
31
  return true if completed?
32
+
32
33
  amount ||= money.amount_in_cents
33
34
  started_processing!
34
35
  protect_from_connection_error do
@@ -47,6 +48,7 @@ module Spree
47
48
 
48
49
  def void_transaction!
49
50
  return true if void?
51
+
50
52
  protect_from_connection_error do
51
53
  if payment_method.payment_profiles_supported?
52
54
  # Gateways supporting payment profiles will need access to credit card object because this stores the payment profile information
@@ -96,7 +98,7 @@ module Spree
96
98
  raise ArgumentError, 'handle_payment_preconditions must be called with a block'
97
99
  end
98
100
 
99
- if payment_method && payment_method.source_required?
101
+ if payment_method&.source_required?
100
102
  if source
101
103
  unless processing?
102
104
  if payment_method.supports?(source) || token_based?
@@ -146,11 +148,9 @@ module Spree
146
148
  end
147
149
 
148
150
  def protect_from_connection_error
149
-
150
151
  yield
151
152
  rescue ActiveMerchant::ConnectionError => e
152
153
  gateway_error(e)
153
-
154
154
  end
155
155
 
156
156
  def gateway_error(error)
@@ -48,10 +48,10 @@ module Spree::Preferences
48
48
 
49
49
  # does it exist in the database?
50
50
  val = if preference = Spree::Preference.find_by(key: key)
51
- # it does exist
51
+ # it does exist
52
52
  preference.value
53
53
  else
54
- # use the fallback value
54
+ # use the fallback value
55
55
  yield
56
56
  end
57
57
 
@@ -89,7 +89,7 @@ module Spree::Preferences
89
89
  return unless should_persist?
90
90
 
91
91
  preference = Spree::Preference.find_by(key: cache_key)
92
- preference.destroy if preference
92
+ preference&.destroy
93
93
  end
94
94
 
95
95
  def should_persist?
@@ -125,6 +125,21 @@ module Spree
125
125
 
126
126
  alias master_images images
127
127
 
128
+ # Cant use short form block syntax due to https://github.com/Netflix/fast_jsonapi/issues/259
129
+ def purchasable?
130
+ variants_including_master.any?(&:purchasable?)
131
+ end
132
+
133
+ # Cant use short form block syntax due to https://github.com/Netflix/fast_jsonapi/issues/259
134
+ def in_stock?
135
+ variants_including_master.any?(&:in_stock?)
136
+ end
137
+
138
+ # Cant use short form block syntax due to https://github.com/Netflix/fast_jsonapi/issues/259
139
+ def backorderable?
140
+ variants_including_master.any?(&:backorderable?)
141
+ end
142
+
128
143
  def find_or_build_master
129
144
  master || build_master
130
145
  end
@@ -134,6 +149,14 @@ module Spree
134
149
  variants.any?
135
150
  end
136
151
 
152
+ def default_variant
153
+ has_variants? ? variants.first : master
154
+ end
155
+
156
+ def default_variant_id
157
+ default_variant.id
158
+ end
159
+
137
160
  def tax_category
138
161
  super || TaxCategory.find_by(is_default: true)
139
162
  end
@@ -147,6 +170,7 @@ module Spree
147
170
  # Ensures option_types and product_option_types exist for keys in option_values_hash
148
171
  def ensure_option_types_exist_for_values_hash
149
172
  return if option_values_hash.nil?
173
+
150
174
  required_option_type_ids = option_values_hash.keys.map(&:to_i)
151
175
  missing_option_type_ids = required_option_type_ids - option_type_ids
152
176
  missing_option_type_ids.each do |id|
@@ -188,10 +212,16 @@ module Spree
188
212
  variants_including_master.any?(&:can_supply?)
189
213
  end
190
214
 
215
+ # determine if any variant (including master) is out of stock and backorderable
216
+ def backordered?
217
+ variants_including_master.any?(&:backordered?)
218
+ end
219
+
191
220
  # split variants list into hash which shows mapping of opt value onto matching variants
192
221
  # eg categorise_variants_from_option(color) => {"red" -> [...], "blue" -> [...]}
193
222
  def categorise_variants_from_option(opt_type)
194
223
  return {} unless option_types.include?(opt_type)
224
+
195
225
  variants.active.group_by { |v| v.option_values.detect { |o| o.option_type == opt_type } }
196
226
  end
197
227
 
@@ -270,6 +300,7 @@ module Spree
270
300
 
271
301
  def any_variants_not_track_inventory?
272
302
  return true unless Spree::Config.track_inventory_levels
303
+
273
304
  if variants_including_master.loaded?
274
305
  variants_including_master.any? { |v| !v.track_inventory? }
275
306
  else
@@ -294,6 +325,7 @@ module Spree
294
325
 
295
326
  def ensure_master
296
327
  return unless new_record?
328
+
297
329
  self.master ||= build_master
298
330
  end
299
331
 
@@ -22,6 +22,7 @@ module Spree
22
22
  scopes.each do |name|
23
23
  # We should not define price scopes here, as they require something slightly different
24
24
  next if name.to_s.include?('master_price')
25
+
25
26
  parts = name.to_s.match(/(.*)_by_(.*)/)
26
27
  scope(name.to_s, -> { order(Arel.sql("#{Product.quoted_table_name}.#{parts[2]} #{parts[1] == 'ascend' ? 'ASC' : 'DESC'}")) })
27
28
  end
@@ -29,10 +30,10 @@ module Spree
29
30
 
30
31
  def self.property_conditions(property)
31
32
  properties = Property.table_name
32
- conditions = case property
33
- when String then { "#{properties}.name" => property }
34
- when Property then { "#{properties}.id" => property.id }
35
- else { "#{properties}.id" => property.to_i }
33
+ case property
34
+ when String then { "#{properties}.name" => property }
35
+ when Property then { "#{properties}.id" => property.id }
36
+ else { "#{properties}.id" => property.to_i }
36
37
  end
37
38
  end
38
39
 
@@ -109,7 +110,7 @@ module Spree
109
110
  when String then { "#{option_types}.name" => option }
110
111
  when OptionType then { "#{option_types}.id" => option.id }
111
112
  else { "#{option_types}.id" => option.to_i }
112
- end
113
+ end
113
114
 
114
115
  joins(:option_types).where(conditions)
115
116
  end
@@ -120,7 +121,7 @@ module Spree
120
121
  when String then OptionType.find_by(name: option) || option.to_i
121
122
  when OptionType then option.id
122
123
  else option.to_i
123
- end
124
+ end
124
125
 
125
126
  conditions = "#{option_values}.name = ? AND #{option_values}.option_type_id = ?", value, option_type_id
126
127
  group('spree_products.id').joins(variants_including_master: :option_values).where(conditions)
@@ -210,50 +211,27 @@ module Spree
210
211
  group('spree_products.id').joins(:taxons).where(Taxon.arel_table[:name].eq(name))
211
212
  end
212
213
 
213
- def self.distinct_by_product_ids(sort_order = nil)
214
- sort_column = sort_order.split(' ').first
215
-
216
- # Postgres will complain when using ordering by expressions not present in
217
- # SELECT DISTINCT. e.g.
218
- #
219
- # PG::InvalidColumnReference: ERROR: for SELECT DISTINCT, ORDER BY
220
- # expressions must appear in select list. e.g.
221
- #
222
- # SELECT DISTINCT "spree_products".* FROM "spree_products" LEFT OUTER JOIN
223
- # "spree_variants" ON "spree_variants"."product_id" = "spree_products"."id" AND "spree_variants"."is_master" = 't'
224
- # AND "spree_variants"."deleted_at" IS NULL LEFT OUTER JOIN "spree_prices" ON
225
- # "spree_prices"."variant_id" = "spree_variants"."id" AND "spree_prices"."currency" = 'USD'
226
- # AND "spree_prices"."deleted_at" IS NULL WHERE "spree_products"."deleted_at" IS NULL AND ('t'='t')
227
- # ORDER BY "spree_prices"."amount" ASC LIMIT 10 OFFSET 0
228
- #
229
- # Don't allow sort_column, a variable coming from params,
230
- # to be anything but a column in the database
231
- if ApplicationRecord.connection.adapter_name == 'PostgreSQL' && !column_names.include?(sort_column)
232
- all
233
- else
234
- distinct
235
- end
236
- end
237
-
238
- private
239
-
240
214
  def self.price_table_name
241
215
  Price.quoted_table_name
242
216
  end
217
+ private_class_method :price_table_name
243
218
 
244
219
  # specifically avoid having an order for taxon search (conflicts with main order)
245
220
  def self.prepare_taxon_conditions(taxons)
246
221
  ids = taxons.map { |taxon| taxon.self_and_descendants.pluck(:id) }.flatten.uniq
247
222
  joins(:classifications).where(Classification.table_name => { taxon_id: ids })
248
223
  end
224
+ private_class_method :prepare_taxon_conditions
249
225
 
250
226
  # Produce an array of keywords for use in scopes.
251
227
  # Always return array with at least an empty string to avoid SQL errors
252
228
  def self.prepare_words(words)
253
229
  return [''] if words.blank?
230
+
254
231
  a = words.split(/[,\s]/).map(&:strip)
255
232
  a.any? ? a : ['']
256
233
  end
234
+ private_class_method :prepare_words
257
235
 
258
236
  def self.get_taxons(*ids_or_records_or_names)
259
237
  taxons = Taxon.table_name
@@ -267,5 +245,6 @@ module Spree
267
245
  end
268
246
  end.compact.flatten.uniq
269
247
  end
270
- end
248
+ private_class_method :get_taxons
249
+ end
271
250
  end
@@ -17,7 +17,7 @@ module Spree
17
17
  self.whitelisted_ransackable_associations = ['property']
18
18
 
19
19
  # virtual attributes for use with AJAX completion stuff
20
- delegate :name, to: :property, prefix: true, allow_nil: true
20
+ delegate :name, :presentation, to: :property, prefix: true, allow_nil: true
21
21
 
22
22
  def property_name=(name)
23
23
  if name.present?
@@ -119,6 +119,7 @@ module Spree
119
119
  # called anytime order.update_with_updater! happens
120
120
  def eligible?(promotable)
121
121
  return false if expired? || usage_limit_exceeded?(promotable) || blacklisted?(promotable)
122
+
122
123
  !!eligible_rules(promotable, {})
123
124
  end
124
125
 
@@ -128,6 +129,7 @@ module Spree
128
129
  def eligible_rules(promotable, options = {})
129
130
  # Promotions without rules are eligible by default.
130
131
  return [] if rules.none?
132
+
131
133
  specific_rules = rules.select { |rule| rule.applicable?(promotable) }
132
134
  return [] if specific_rules.none?
133
135
 
@@ -9,11 +9,16 @@ module Spree
9
9
 
10
10
  def perform(options = {})
11
11
  order = options[:order]
12
+
12
13
  create_unique_adjustment(order, order)
13
14
  end
14
15
 
15
16
  def compute_amount(order)
16
- [(order.item_total + order.ship_total - order.shipping_discount), compute(order)].min * -1
17
+ [order_total(order), compute(order)].min * -1
18
+ end
19
+
20
+ def order_total(order)
21
+ order.item_total + order.ship_total - order.shipping_discount
17
22
  end
18
23
  end
19
24
  end