spree_core 4.1.13 → 4.2.0.rc4

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.
Files changed (150) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/spree/base_controller.rb +1 -2
  3. data/app/finders/spree/addresses/find.rb +1 -12
  4. data/app/finders/spree/base_finder.rb +14 -0
  5. data/app/finders/spree/countries/find.rb +11 -3
  6. data/app/finders/spree/credit_cards/find.rb +2 -2
  7. data/app/finders/spree/orders/find_current.rb +1 -1
  8. data/app/helpers/spree/base_helper.rb +61 -20
  9. data/app/helpers/spree/mail_helper.rb +29 -0
  10. data/app/helpers/spree/products_helper.rb +2 -1
  11. data/app/mailers/spree/base_mailer.rb +19 -5
  12. data/app/mailers/spree/order_mailer.rb +13 -4
  13. data/app/mailers/spree/reimbursement_mailer.rb +4 -2
  14. data/app/mailers/spree/shipment_mailer.rb +4 -2
  15. data/app/models/concerns/spree/default_price.rb +3 -6
  16. data/app/models/concerns/spree/user_methods.rb +11 -5
  17. data/app/models/concerns/spree/user_payment_source.rb +1 -1
  18. data/app/models/spree/ability.rb +45 -34
  19. data/app/models/spree/address.rb +17 -1
  20. data/app/models/spree/adjustment.rb +1 -0
  21. data/app/models/spree/app_configuration.rb +4 -0
  22. data/app/models/spree/app_dependencies.rb +4 -2
  23. data/app/models/spree/base.rb +5 -0
  24. data/app/models/spree/credit_card.rb +5 -0
  25. data/app/models/spree/fulfilment_changer.rb +58 -16
  26. data/app/models/spree/inventory_unit.rb +2 -7
  27. data/app/models/spree/line_item.rb +8 -7
  28. data/app/models/spree/log_entry.rb +1 -1
  29. data/app/models/spree/option_type.rb +7 -1
  30. data/app/models/spree/order.rb +27 -5
  31. data/app/models/spree/order/payments.rb +10 -2
  32. data/app/models/spree/payment.rb +18 -4
  33. data/app/models/spree/payment/processing.rb +2 -2
  34. data/app/models/spree/payment_method.rb +3 -3
  35. data/app/models/spree/preferences/store.rb +1 -1
  36. data/app/models/spree/price.rb +25 -6
  37. data/app/models/spree/product.rb +29 -9
  38. data/app/models/spree/promotion.rb +10 -15
  39. data/app/models/spree/promotion/rules/product.rb +2 -1
  40. data/app/models/spree/promotion/rules/user.rb +2 -1
  41. data/app/models/spree/promotion_handler/coupon.rb +1 -1
  42. data/app/models/spree/promotion_handler/promotion_duplicator.rb +9 -3
  43. data/app/models/spree/refund.rb +2 -2
  44. data/app/models/spree/reimbursement.rb +2 -0
  45. data/app/models/spree/return_item/eligibility_validator/default.rb +0 -2
  46. data/app/models/spree/return_item/eligibility_validator/{r_m_a_required.rb → rma_required.rb} +0 -0
  47. data/app/models/spree/shipment.rb +3 -6
  48. data/app/models/spree/shipping_method.rb +1 -5
  49. data/app/models/spree/shipping_rate.rb +2 -11
  50. data/app/models/spree/stock/availability_validator.rb +3 -4
  51. data/app/models/spree/stock_item.rb +1 -5
  52. data/app/models/spree/stock_location.rb +13 -2
  53. data/app/models/spree/store.rb +51 -2
  54. data/app/models/spree/store_credit.rb +1 -1
  55. data/app/models/spree/variant.rb +16 -10
  56. data/app/models/spree/zone.rb +17 -4
  57. data/app/presenters/spree/variant_presenter.rb +9 -1
  58. data/app/presenters/spree/variants/option_types_presenter.rb +1 -0
  59. data/app/services/spree/account/addresses/create.rb +6 -1
  60. data/app/services/spree/account/addresses/{base.rb → helper.rb} +1 -3
  61. data/app/services/spree/account/addresses/update.rb +6 -1
  62. data/app/services/spree/compare_line_items.rb +4 -2
  63. data/app/sorters/spree/base_sorter.rb +35 -0
  64. data/app/sorters/spree/orders/sort.rb +1 -37
  65. data/app/sorters/spree/products/sort.rb +9 -32
  66. data/app/validators/email_validator.rb +1 -1
  67. data/app/views/layouts/spree/base_mailer.html.erb +45 -40
  68. data/app/views/spree/order_mailer/cancel_email.html.erb +19 -25
  69. data/app/views/spree/order_mailer/cancel_email.text.erb +24 -2
  70. data/app/views/spree/order_mailer/confirm_email.html.erb +18 -65
  71. data/app/views/spree/order_mailer/confirm_email.text.erb +2 -1
  72. data/app/views/spree/order_mailer/store_owner_notification_email.html.erb +23 -0
  73. data/app/views/spree/order_mailer/store_owner_notification_email.text.erb +38 -0
  74. data/app/views/spree/reimbursement_mailer/reimbursement_email.html.erb +53 -58
  75. data/app/views/spree/reimbursement_mailer/reimbursement_email.text.erb +3 -1
  76. data/app/views/spree/shared/_base_mailer_footer.html.erb +6 -14
  77. data/app/views/spree/shared/_base_mailer_header.html.erb +12 -32
  78. data/app/views/spree/shared/_base_mailer_stylesheets.html.erb +293 -625
  79. data/app/views/spree/shared/_purchased_items_table.html.erb +60 -0
  80. data/app/views/spree/shared/purchased_items_table/_adjustment.html.erb +13 -0
  81. data/app/views/spree/shared/purchased_items_table/_line_item.html.erb +27 -0
  82. data/app/views/spree/shared/purchased_items_table/_subtotal.html.erb +13 -0
  83. data/app/views/spree/shared/purchased_items_table/_total.html.erb +13 -0
  84. data/app/views/spree/shipment_mailer/shipped_email.html.erb +31 -36
  85. data/app/views/spree/shipment_mailer/shipped_email.text.erb +2 -1
  86. data/config/initializers/assets.rb +1 -0
  87. data/config/initializers/inflections.rb +3 -0
  88. data/config/initializers/rails61_fixes.rb +3 -0
  89. data/config/locales/en.yml +145 -19
  90. data/db/default/spree/countries.rb +10 -4
  91. data/db/default/spree/states.rb +42 -5
  92. data/db/default/spree/stores.rb +17 -12
  93. data/db/default/spree/zones.rb +5 -2
  94. data/db/migrate/20130326175857_add_stock_location_to_rma.rb +1 -1
  95. data/db/migrate/20140309033438_create_store_from_preferences.rb +1 -1
  96. data/db/migrate/20191017121054_add_supported_currencies_to_store.rb +10 -0
  97. data/db/migrate/20200102141311_add_social_to_spree_stores.rb +3 -0
  98. data/db/migrate/20200308210757_add_default_locale_to_spree_store.rb +7 -0
  99. data/db/migrate/20200310145140_add_customer_support_email_to_spree_store.rb +7 -0
  100. data/db/migrate/20200421095017_add_compare_at_amount_to_spree_prices.rb +7 -0
  101. data/db/migrate/20200423123001_add_default_country_id_to_spree_store.rb +9 -0
  102. data/db/migrate/20200430072209_add_footer_fields_to_spree_stores.rb +8 -0
  103. data/db/migrate/20200513154939_add_show_property_to_spree_product_properties.rb +5 -0
  104. data/db/migrate/20200607161221_add_store_owner_order_notification_delivered_to_spree_orders.rb +7 -0
  105. data/db/migrate/20200607161222_add_new_order_notifications_email_to_spree_stores.rb +7 -0
  106. data/db/migrate/20200610113542_add_label_to_spree_addresses.rb +5 -0
  107. data/db/migrate/20200826075557_add_unique_index_on_taxon_id_and_product_id_to_spree_products_taxons.rb +5 -0
  108. data/db/migrate/20201006110150_add_checkout_zone_field_to_store.rb +12 -0
  109. data/db/migrate/20201012091259_add_filterable_column_to_spree_option_types.rb +6 -0
  110. data/db/migrate/20201013084504_add_seo_robots_to_spree_stores.rb +5 -0
  111. data/db/migrate/20201127084048_add_default_country_kind_to_spree_zones.rb +5 -0
  112. data/db/migrate/20210112193440_remove_contact_email_from_spree_stores.rb +5 -0
  113. data/db/migrate/20210114182625_create_spree_payment_methods_stores.rb +10 -0
  114. data/db/migrate/20210114220232_migrate_data_payment_methods_stores.rb +15 -0
  115. data/db/migrate/20210117112551_remove_store_id_from_spree_payment_methods.rb +5 -0
  116. data/lib/generators/spree/install/templates/vendor/assets/javascripts/spree/backend/all.js +0 -2
  117. data/lib/generators/spree/install/templates/vendor/assets/javascripts/spree/frontend/all.js +0 -2
  118. data/lib/generators/spree/mailers_preview/mailers_preview_generator.rb +23 -0
  119. data/lib/generators/spree/mailers_preview/templates/mailers/previews/order_preview.rb +13 -0
  120. data/lib/generators/spree/mailers_preview/templates/mailers/previews/reimbursement_preview.rb +5 -0
  121. data/lib/generators/spree/mailers_preview/templates/mailers/previews/shipment_preview.rb +5 -0
  122. data/lib/generators/spree/mailers_preview/templates/mailers/previews/user_preview.rb +11 -0
  123. data/lib/spree/core.rb +2 -0
  124. data/lib/spree/core/controller_helpers/common.rb +1 -0
  125. data/lib/spree/core/controller_helpers/currency_helpers.rb +15 -0
  126. data/lib/spree/core/controller_helpers/order.rb +9 -4
  127. data/lib/spree/core/controller_helpers/store.rb +16 -1
  128. data/lib/spree/core/importer/order.rb +9 -9
  129. data/lib/spree/core/product_filters.rb +3 -3
  130. data/lib/spree/core/version.rb +1 -1
  131. data/lib/spree/i18n.rb +7 -21
  132. data/lib/spree/permitted_attributes.rb +8 -5
  133. data/lib/spree/service_module.rb +6 -2
  134. data/lib/spree/testing_support/authorization_helpers.rb +7 -4
  135. data/lib/spree/testing_support/capybara_config.rb +1 -1
  136. data/lib/spree/testing_support/factories/promotion_factory.rb +29 -17
  137. data/lib/spree/testing_support/factories/shipment_factory.rb +7 -9
  138. data/lib/spree/testing_support/factories/store_factory.rb +11 -8
  139. data/lib/spree/testing_support/factories/zone_factory.rb +16 -13
  140. data/lib/spree/testing_support/i18n.rb +1 -1
  141. data/lib/spree/testing_support/order_walkthrough.rb +8 -3
  142. data/lib/spree/testing_support/rspec_retry_config.rb +10 -0
  143. data/spree_core.gemspec +10 -8
  144. data/vendor/assets/javascripts/cleave.js +1669 -0
  145. metadata +105 -30
  146. data/app/views/spree/order_mailer/_adjustment.html.erb +0 -8
  147. data/app/views/spree/order_mailer/_subtotal.html.erb +0 -8
  148. data/app/views/spree/order_mailer/_total.html.erb +0 -8
  149. data/lib/spree/i18n/base.rb +0 -17
  150. data/lib/spree/i18n/initializer.rb +0 -1
@@ -9,7 +9,7 @@ module Spree
9
9
  end
10
10
 
11
11
  def payment_sources
12
- credit_cards.with_payment_profile
12
+ credit_cards.with_payment_profile.not_expired
13
13
  end
14
14
 
15
15
  def drop_payment_source(source)
@@ -23,59 +23,70 @@ module Spree
23
23
  end
24
24
 
25
25
  def initialize(user)
26
- # add cancancan aliasing
27
- alias_action :delete, to: :destroy
28
- alias_action :create, :update, :destroy, to: :modify
26
+ alias_cancan_delete_action
29
27
 
30
28
  user ||= Spree.user_class.new
31
29
 
32
30
  if user.respond_to?(:has_spree_role?) && user.has_spree_role?('admin')
33
- can :manage, :all
31
+ apply_admin_permissions(user)
34
32
  else
35
- can :read, Country
36
- can :read, OptionType
37
- can :read, OptionValue
38
- can :create, Order
39
- can :show, Order do |order, token|
40
- order.user == user || order.token && token == order.token
41
- end
42
- can :update, Order do |order, token|
43
- !order.completed? && (order.user == user || order.token && token == order.token)
44
- end
45
- can :manage, Spree::Address do |address|
46
- address.user == user
47
- end
48
- can :create, Spree::Address do |_address|
49
- user.id.present?
50
- end
51
- can :read, CreditCard, user_id: user.id
52
- can :read, Product
53
- can :read, ProductProperty
54
- can :read, Property
55
- can :create, Spree.user_class
56
- can [:show, :update, :destroy], Spree.user_class, id: user.id
57
- can :read, State
58
- can :read, Taxon
59
- can :read, Taxonomy
60
- can :read, Variant
61
- can :read, Zone
33
+ apply_user_permissions(user)
62
34
  end
63
35
 
64
36
  # Include any abilities registered by extensions, etc.
37
+ # this is legacy behaviour and should be removed in Spree 5.0
65
38
  Ability.abilities.merge(abilities_to_register).each do |clazz|
66
39
  merge clazz.new(user)
67
40
  end
68
41
 
69
- # Protect admin role
70
- cannot [:update, :destroy], Role, name: ['admin']
42
+ protect_admin_role
71
43
  end
72
44
 
73
- private
45
+ protected
74
46
 
75
47
  # you can override this method to register your abilities
76
48
  # this method has to return array of classes
77
49
  def abilities_to_register
78
50
  []
79
51
  end
52
+
53
+ def alias_cancan_delete_action
54
+ alias_action :delete, to: :destroy
55
+ alias_action :create, :update, :destroy, to: :modify
56
+ end
57
+
58
+ def apply_admin_permissions(user)
59
+ can :manage, :all
60
+ end
61
+
62
+ def apply_user_permissions(user)
63
+ can :read, ::Spree::Country
64
+ can :read, ::Spree::OptionType
65
+ can :read, ::Spree::OptionValue
66
+ can :create, ::Spree::Order
67
+ can :show, ::Spree::Order do |order, token|
68
+ order.user == user || order.token && token == order.token
69
+ end
70
+ can :update, ::Spree::Order do |order, token|
71
+ !order.completed? && (order.user == user || order.token && token == order.token)
72
+ end
73
+ can :manage, ::Spree::Address, user_id: user.id
74
+ can :read, ::Spree::CreditCard, user_id: user.id
75
+ can :read, ::Spree::Product
76
+ can :read, ::Spree::ProductProperty
77
+ can :read, ::Spree::Property
78
+ can :create, ::Spree.user_class
79
+ can [:show, :update, :destroy], ::Spree.user_class, id: user.id
80
+ can :read, ::Spree::State
81
+ can :read, ::Spree::Store
82
+ can :read, ::Spree::Taxon
83
+ can :read, ::Spree::Taxonomy
84
+ can :read, ::Spree::Variant
85
+ can :read, ::Spree::Zone
86
+ end
87
+
88
+ def protect_admin_role
89
+ cannot [:update, :destroy], ::Spree::Role, name: ['admin']
90
+ end
80
91
  end
81
92
  end
@@ -2,6 +2,10 @@ module Spree
2
2
  class Address < Spree::Base
3
3
  require 'twitter_cldr'
4
4
 
5
+ if Rails::VERSION::STRING >= '6.1'
6
+ serialize :preferences, Hash, default: {}
7
+ end
8
+
5
9
  NO_ZIPCODE_ISO_CODES ||= [
6
10
  'AO', 'AG', 'AW', 'BS', 'BZ', 'BJ', 'BM', 'BO', 'BW', 'BF', 'BI', 'CM', 'CF', 'KM', 'CG',
7
11
  'CD', 'CK', 'CUW', 'CI', 'DJ', 'DM', 'GQ', 'ER', 'FJ', 'TF', 'GAB', 'GM', 'GH', 'GD', 'GN',
@@ -10,10 +14,16 @@ module Spree
10
14
  'TO', 'TV', 'UG', 'AE', 'VU', 'YE', 'ZW'
11
15
  ].freeze
12
16
 
17
+ # The required states listed below match those used by PayPal and Shopify.
18
+ STATES_REQUIRED = [
19
+ 'AU', 'AE', 'BR', 'CA', 'CN', 'ES', 'HK', 'IE', 'IN',
20
+ 'IT', 'MY', 'MX', 'NZ', 'PT', 'RO', 'TH', 'US', 'ZA'
21
+ ].freeze
22
+
13
23
  # we're not freezing this on purpose so developers can extend and manage
14
24
  # those attributes depending of the logic of their applications
15
25
  ADDRESS_FIELDS = %w(firstname lastname company address1 address2 city state zipcode country phone)
16
- EXCLUDED_KEYS_FOR_COMPARISION = %w(id updated_at created_at deleted_at user_id)
26
+ EXCLUDED_KEYS_FOR_COMPARISION = %w(id updated_at created_at deleted_at label user_id)
17
27
 
18
28
  belongs_to :country, class_name: 'Spree::Country'
19
29
  belongs_to :state, class_name: 'Spree::State', optional: true
@@ -31,6 +41,12 @@ module Spree
31
41
 
32
42
  validate :state_validate, :postal_code_validate
33
43
 
44
+ validates :label, uniqueness: { conditions: -> { where(deleted_at: nil) },
45
+ scope: :user_id,
46
+ case_sensitive: false,
47
+ allow_blank: true,
48
+ allow_nil: true }
49
+
34
50
  delegate :name, :iso3, :iso, :iso_name, to: :country, prefix: true
35
51
  delegate :abbr, to: :state, prefix: true, allow_nil: true
36
52
 
@@ -27,6 +27,7 @@ module Spree
27
27
  belongs_to :source
28
28
  end
29
29
  belongs_to :order, class_name: 'Spree::Order', inverse_of: :all_adjustments
30
+ belongs_to :promotion_action, class_name: 'Spree::PromotionAction', foreign_key: :source_id, optional: true # created only for has_free_shipping?
30
31
 
31
32
  validates :adjustable, :order, :label, presence: true
32
33
  validates :amount, numericality: true
@@ -49,6 +49,7 @@ module Spree
49
49
  preference :expedited_exchanges_days_window, :integer, default: 14 # the amount of days the customer has to return their item after the expedited exchange is shipped in order to avoid being charged
50
50
  preference :layout, :string, default: 'spree/layouts/spree_application'
51
51
  preference :logo, :string, default: 'logo/spree_50.png'
52
+ preference :mailer_logo, :string, default: 'logo/spree_50.png'
52
53
  preference :max_level_in_taxons_menu, :integer, default: 1 # maximum nesting level in taxons menu
53
54
  preference :products_per_page, :integer, default: 12
54
55
  preference :require_master_price, :boolean, default: true
@@ -67,6 +68,9 @@ module Spree
67
68
  preference :non_expiring_credit_types, :array, default: []
68
69
  preference :credit_to_new_allocation, :boolean, default: false
69
70
 
71
+ # Multi store configurations
72
+ preference :show_store_selector, :boolean, default: false
73
+
70
74
  # searcher_class allows spree extension writers to provide their own Search class
71
75
  def searcher_class
72
76
  @searcher_class ||= Spree::Core::Search::Base
@@ -12,7 +12,8 @@ module Spree
12
12
  :coupon_handler, :country_finder, :current_order_finder, :credit_card_finder,
13
13
  :completed_order_finder, :order_sorter, :cart_compare_line_items_service, :collection_paginator, :products_sorter,
14
14
  :products_finder, :taxon_finder, :line_item_by_variant_finder, :cart_estimate_shipping_rates_service,
15
- :account_create_address_service, :account_update_address_service, :address_finder
15
+ :account_create_address_service, :account_update_address_service, :address_finder,
16
+ :collection_sorter
16
17
  ].freeze
17
18
 
18
19
  attr_accessor *INJECTION_POINTS
@@ -51,7 +52,8 @@ module Spree
51
52
  @checkout_get_shipping_rates_service = 'Spree::Checkout::GetShippingRates'
52
53
 
53
54
  # sorter
54
- @order_sorter = 'Spree::Orders::Sort'
55
+ @collection_sorter = 'Spree::BaseSorter'
56
+ @order_sorter = 'Spree::BaseSorter'
55
57
  @products_sorter = 'Spree::Products::Sort'
56
58
 
57
59
  # paginator
@@ -25,4 +25,9 @@ class Spree::Base < ApplicationRecord
25
25
  def self.spree_base_scopes
26
26
  where(nil)
27
27
  end
28
+
29
+ # FIXME: https://github.com/rails/rails/issues/40943
30
+ def self.has_many_inversing
31
+ false
32
+ end
28
33
  end
@@ -37,6 +37,11 @@ module Spree
37
37
 
38
38
  scope :with_payment_profile, -> { where.not(gateway_customer_profile_id: nil) }
39
39
  scope :default, -> { where(default: true) }
40
+ scope :not_expired, lambda {
41
+ where('CAST(spree_credit_cards.year AS DECIMAL) > ?', Time.current.year).
42
+ or(where('CAST(spree_credit_cards.year AS DECIMAL) = ?', Time.current.year).
43
+ where('CAST(spree_credit_cards.month AS DECIMAL) >= ?', Time.current.month))
44
+ }
40
45
 
41
46
  # needed for some of the ActiveMerchant gateways (eg. SagePay)
42
47
  alias_attribute :brand, :cc_type
@@ -36,7 +36,7 @@ module Spree
36
36
  private
37
37
 
38
38
  attr_reader :variant, :quantity, :current_stock_location, :desired_stock_location,
39
- :current_shipment, :desired_shipment, :available_quantity
39
+ :current_shipment, :desired_shipment, :available_quantity
40
40
 
41
41
  def handle_stock
42
42
  ActiveRecord::Base.transaction do
@@ -45,13 +45,64 @@ module Spree
45
45
  desired_stock_location.unstock(variant, unstock_quantity, desired_shipment)
46
46
  end
47
47
 
48
- update_current_shipment_inventory_units(new_on_hand_quantity, :on_hand)
49
- update_current_shipment_inventory_units(quantity - new_on_hand_quantity, :backordered)
48
+ move_inventory_units_between_shipments
49
+ end
50
+ end
51
+
52
+ def move_inventory_units_between_shipments
53
+ update_desired_shipment_inventory_units
54
+ update_current_shipment_inventory_units
55
+ end
56
+
57
+ def current_shipment_units
58
+ @current_shipment_units ||= current_shipment.inventory_units.on_hand_or_backordered.where(variant_id: variant.id)
59
+ end
60
+
61
+ def update_desired_shipment_inventory_units
62
+ on_hand_unit = get_desired_shipment_inventory_unit(:on_hand)
63
+ on_hand_unit.update(quantity: on_hand_unit.quantity + new_on_hand_quantity)
64
+
65
+ new_backorder_quantity = current_on_hand_quantity - new_on_hand_quantity
66
+ if new_backorder_quantity > 0
67
+ backordered_unit = get_desired_shipment_inventory_unit(:backordered)
68
+ backordered_unit.update(quantity: backordered_unit.quantity + new_backorder_quantity)
69
+ end
70
+ end
71
+
72
+ def update_current_shipment_inventory_units
73
+ reduced_quantity = current_on_hand_quantity
74
+
75
+ # Reduce quantities from all backordered units first in case there is more than one.
76
+ backorder_units = current_shipment_units.backordered
77
+ reduced_quantity = reduce_units_quantities(reduced_quantity, backorder_units) if backorder_units.any?
78
+
79
+ # Reduce quantities from all on_hand units in case there is more than one.
80
+ if reduced_quantity > 0
81
+ on_hand_units = current_shipment_units.on_hand
82
+ reduce_units_quantities(reduced_quantity, on_hand_units) if on_hand_units.any?
83
+ end
84
+ end
85
+
86
+ def reduce_units_quantities(reduced_quantity, units)
87
+ units.each do |unit|
88
+ unit.quantity > reduced_quantity ? unit.update(quantity: unit.quantity - reduced_quantity) : unit.destroy!
89
+ reduced_quantity -= unit.quantity
90
+ end
91
+ reduced_quantity
92
+ end
93
+
94
+ def get_desired_shipment_inventory_unit(state)
95
+ desired_shipment.inventory_units.find_or_create_by(state: state) do |unit|
96
+ current_shipment_unit = current_shipment_units.first
97
+ unit.variant_id = current_shipment_unit.variant_id
98
+ unit.order_id = current_shipment_unit.order_id
99
+ unit.line_item_id = current_shipment_unit.line_item_id
100
+ unit.quantity = 0
50
101
  end
51
102
  end
52
103
 
53
104
  def after_process_shipments
54
- if current_shipment.inventory_units.length.zero?
105
+ if current_shipment.inventory_units.sum(:quantity).zero?
55
106
  current_shipment.destroy!
56
107
  else
57
108
  current_shipment.refresh_rates
@@ -64,7 +115,7 @@ module Spree
64
115
  end
65
116
 
66
117
  def new_on_hand_quantity
67
- [available_quantity, quantity].min
118
+ [available_quantity, current_on_hand_quantity].min
68
119
  end
69
120
 
70
121
  def unstock_quantity
@@ -72,16 +123,7 @@ module Spree
72
123
  end
73
124
 
74
125
  def current_on_hand_quantity
75
- [current_shipment.inventory_units.on_hand_or_backordered.size, quantity].min
76
- end
77
-
78
- def update_current_shipment_inventory_units(quantity, state)
79
- current_shipment.
80
- inventory_units.
81
- where(variant: variant).
82
- order(state: :asc).
83
- limit(quantity).
84
- update_all(shipment_id: desired_shipment.id, state: state)
126
+ [current_shipment.inventory_units.on_hand_or_backordered.sum(:quantity), quantity].min
85
127
  end
86
128
 
87
129
  def reload_shipment_inventory_units
@@ -105,7 +147,7 @@ module Spree
105
147
  def enough_stock_at_desired_location
106
148
  return if Spree::Stock::Quantifier.new(variant, desired_stock_location).can_supply?(quantity)
107
149
 
108
- errors.add(:desired_shipment, :not_enough_stock_at_desired_location)
150
+ errors.add(:desired_shipment, :has_not_enough_stock_at_desired_location)
109
151
  end
110
152
 
111
153
  def desired_shipment_different_from_current
@@ -1,10 +1,10 @@
1
1
  module Spree
2
2
  class InventoryUnit < Spree::Base
3
3
  with_options inverse_of: :inventory_units do
4
- belongs_to :variant, class_name: 'Spree::Variant'
4
+ belongs_to :variant, -> { with_deleted }, class_name: 'Spree::Variant'
5
5
  belongs_to :order, class_name: 'Spree::Order'
6
6
  belongs_to :shipment, class_name: 'Spree::Shipment', touch: true, optional: true
7
- has_many :return_items
7
+ has_many :return_items, inverse_of: :inventory_unit
8
8
  has_many :return_authorizations, class_name: 'Spree::ReturnAuthorization', through: :return_items
9
9
  belongs_to :line_item, class_name: 'Spree::LineItem'
10
10
  end
@@ -84,11 +84,6 @@ module Spree
84
84
  split_inventory!(1)
85
85
  end
86
86
 
87
- # Remove variant default_scope `deleted_at: nil`
88
- def variant
89
- Spree::Variant.unscoped { super }
90
- end
91
-
92
87
  def current_or_new_return_item
93
88
  Spree::ReturnItem.from_inventory_unit(self)
94
89
  end
@@ -4,7 +4,7 @@ module Spree
4
4
 
5
5
  with_options inverse_of: :line_items do
6
6
  belongs_to :order, class_name: 'Spree::Order', touch: true
7
- belongs_to :variant, class_name: 'Spree::Variant'
7
+ belongs_to :variant, -> { with_deleted }, class_name: 'Spree::Variant'
8
8
  end
9
9
  belongs_to :tax_category, class_name: 'Spree::TaxCategory'
10
10
 
@@ -57,7 +57,13 @@ module Spree
57
57
  end
58
58
 
59
59
  def update_price
60
- self.price = variant.price_including_vat_for(tax_zone: tax_zone)
60
+ currency_price = variant.price_in(order.currency)
61
+
62
+ self.price = if currency_price.amount.present?
63
+ currency_price.price_including_vat_for(tax_zone: tax_zone)
64
+ else
65
+ 0
66
+ end
61
67
  end
62
68
 
63
69
  def copy_tax_category
@@ -111,11 +117,6 @@ module Spree
111
117
  assign_attributes opts
112
118
  end
113
119
 
114
- # Remove variant default_scope `deleted_at: nil`
115
- def variant
116
- Spree::Variant.unscoped { super }
117
- end
118
-
119
120
  private
120
121
 
121
122
  def ensure_valid_quantity
@@ -11,7 +11,7 @@ module Spree
11
11
  end
12
12
 
13
13
  def parsed_details
14
- @details ||= YAML.load(details)
14
+ @details ||= YAML.safe_load(details, [ActiveMerchant::Billing::Response])
15
15
  end
16
16
  end
17
17
  end
@@ -19,12 +19,18 @@ module Spree
19
19
 
20
20
  default_scope { order(:position) }
21
21
 
22
+ scope :filterable, -> { where(filterable: true) }
23
+
22
24
  accepts_nested_attributes_for :option_values, reject_if: ->(ov) { ov[:name].blank? || ov[:presentation].blank? }, allow_destroy: true
23
25
 
24
26
  after_touch :touch_all_products
25
27
 
26
28
  def filter_param
27
- presentation.titleize.delete(' ').downcase
29
+ name.titleize.delete(' ').downcase
30
+ end
31
+
32
+ def self.color
33
+ find_by(name: 'color')
28
34
  end
29
35
 
30
36
  private
@@ -157,6 +157,7 @@ module Spree
157
157
  scope :completed_between, ->(start_date, end_date) { where(completed_at: start_date..end_date) }
158
158
  scope :complete, -> { where.not(completed_at: nil) }
159
159
  scope :incomplete, -> { where(completed_at: nil) }
160
+ scope :not_canceled, -> { where.not(state: 'canceled') }
160
161
 
161
162
  # shows completed orders first, by their completed_at date, then uncompleted orders by their created_at
162
163
  scope :reverse_chronological, -> { order(Arel.sql('spree_orders.completed_at IS NULL'), completed_at: :desc, created_at: :desc) }
@@ -302,15 +303,15 @@ module Spree
302
303
  def outstanding_balance
303
304
  if canceled?
304
305
  -1 * payment_total
305
- elsif refunds.exists?
306
- # If refund has happened add it back to total to prevent balance_due payment state
307
- # See: https://github.com/spree/spree/issues/6229 & https://github.com/spree/spree/issues/8136
308
- total - (payment_total + refunds.sum(:amount))
309
306
  else
310
- total - payment_total
307
+ total - (payment_total + reimbursement_paid_total)
311
308
  end
312
309
  end
313
310
 
311
+ def reimbursement_paid_total
312
+ reimbursements.sum(&:paid_amount)
313
+ end
314
+
314
315
  def outstanding_balance?
315
316
  outstanding_balance != 0
316
317
  end
@@ -356,6 +357,8 @@ module Spree
356
357
 
357
358
  deliver_order_confirmation_email unless confirmation_delivered?
358
359
 
360
+ deliver_store_owner_order_notification_email if deliver_store_owner_order_notification_email?
361
+
359
362
  consider_risk
360
363
  end
361
364
 
@@ -646,6 +649,13 @@ module Spree
646
649
  sum(:amount)
647
650
  end
648
651
 
652
+ def has_free_shipping?
653
+ shipment_adjustments.
654
+ joins(:promotion_action).
655
+ where(spree_adjustments: { eligible: true, source_type: 'Spree::PromotionAction' },
656
+ spree_promotion_actions: { type: 'Spree::Promotion::Actions::FreeShipping' }).exists?
657
+ end
658
+
649
659
  private
650
660
 
651
661
  def link_by_email
@@ -711,5 +721,17 @@ module Spree
711
721
  def credit_card_nil_payment?(attributes)
712
722
  payments.store_credits.present? && attributes[:amount].to_f.zero?
713
723
  end
724
+
725
+ # Returns true if:
726
+ # 1. an email address is set for new order notifications AND
727
+ # 2. no notification for this order has been sent yet.
728
+ def deliver_store_owner_order_notification_email?
729
+ store.new_order_notifications_email.present? && !store_owner_notification_delivered?
730
+ end
731
+
732
+ def deliver_store_owner_order_notification_email
733
+ OrderMailer.store_owner_notification_email(id).deliver_later
734
+ update_column(:store_owner_notification_delivered, true)
735
+ end
714
736
  end
715
737
  end