spree_core 4.1.15 → 4.2.0.beta

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 (92) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/spree/base_controller.rb +1 -0
  3. data/app/helpers/spree/base_helper.rb +23 -2
  4. data/app/helpers/spree/mail_helper.rb +24 -0
  5. data/app/mailers/spree/base_mailer.rb +17 -3
  6. data/app/mailers/spree/order_mailer.rb +11 -2
  7. data/app/mailers/spree/reimbursement_mailer.rb +4 -2
  8. data/app/mailers/spree/shipment_mailer.rb +4 -2
  9. data/app/models/concerns/spree/default_price.rb +2 -1
  10. data/app/models/concerns/spree/user_methods.rb +11 -5
  11. data/app/models/spree/app_configuration.rb +5 -0
  12. data/app/models/spree/app_dependencies.rb +1 -7
  13. data/app/models/spree/line_item.rb +11 -3
  14. data/app/models/spree/option_type.rb +5 -1
  15. data/app/models/spree/order/address_book.rb +20 -7
  16. data/app/models/spree/order/store_credit.rb +0 -8
  17. data/app/models/spree/order.rb +28 -12
  18. data/app/models/spree/price.rb +26 -2
  19. data/app/models/spree/product.rb +17 -7
  20. data/app/models/spree/promotion_handler/coupon.rb +3 -2
  21. data/app/models/spree/reimbursement.rb +2 -0
  22. data/app/models/spree/shipment.rb +2 -5
  23. data/app/models/spree/stock_location.rb +13 -2
  24. data/app/models/spree/store.rb +19 -2
  25. data/app/models/spree/variant.rb +15 -2
  26. data/app/presenters/spree/variant_presenter.rb +7 -0
  27. data/app/presenters/spree/variants/option_types_presenter.rb +1 -0
  28. data/app/services/spree/checkout/update.rb +2 -13
  29. data/app/views/layouts/spree/base_mailer.html.erb +45 -40
  30. data/app/views/spree/order_mailer/cancel_email.html.erb +19 -25
  31. data/app/views/spree/order_mailer/cancel_email.text.erb +24 -2
  32. data/app/views/spree/order_mailer/confirm_email.html.erb +18 -65
  33. data/app/views/spree/order_mailer/confirm_email.text.erb +2 -1
  34. data/app/views/spree/order_mailer/store_owner_notification_email.html.erb +23 -0
  35. data/app/views/spree/order_mailer/store_owner_notification_email.text.erb +38 -0
  36. data/app/views/spree/reimbursement_mailer/reimbursement_email.html.erb +53 -58
  37. data/app/views/spree/reimbursement_mailer/reimbursement_email.text.erb +3 -1
  38. data/app/views/spree/shared/_base_mailer_footer.html.erb +6 -14
  39. data/app/views/spree/shared/_base_mailer_header.html.erb +12 -32
  40. data/app/views/spree/shared/_base_mailer_stylesheets.html.erb +293 -625
  41. data/app/views/spree/shared/_purchased_items_table.html.erb +60 -0
  42. data/app/views/spree/shared/purchased_items_table/_adjustment.html.erb +13 -0
  43. data/app/views/spree/shared/purchased_items_table/_line_item.html.erb +27 -0
  44. data/app/views/spree/shared/purchased_items_table/_subtotal.html.erb +13 -0
  45. data/app/views/spree/shared/purchased_items_table/_total.html.erb +13 -0
  46. data/app/views/spree/shipment_mailer/shipped_email.html.erb +31 -36
  47. data/app/views/spree/shipment_mailer/shipped_email.text.erb +2 -1
  48. data/config/initializers/assets.rb +1 -0
  49. data/config/locales/en.yml +113 -13
  50. data/db/default/spree/stores.rb +11 -10
  51. data/db/migrate/20140309033438_create_store_from_preferences.rb +1 -1
  52. data/db/migrate/20191016134113_add_deafult_value_for_store_default_currency.rb +1 -1
  53. data/db/migrate/20191017121054_add_supported_currencies_to_store.rb +10 -0
  54. data/db/migrate/20200102141311_add_social_to_spree_stores.rb +4 -1
  55. data/db/migrate/20200212144523_add_hide_from_nav_to_taxons.rb +1 -1
  56. data/db/migrate/20200308210757_add_default_locale_to_spree_store.rb +7 -0
  57. data/db/migrate/20200310145140_add_customer_support_email_to_spree_store.rb +7 -0
  58. data/db/migrate/20200421095017_add_compare_at_amount_to_spree_prices.rb +7 -0
  59. data/db/migrate/20200423123001_add_default_country_id_to_spree_store.rb +9 -0
  60. data/db/migrate/20200430072209_add_footer_fields_to_spree_stores.rb +8 -0
  61. data/db/migrate/20200513154939_add_show_property_to_spree_product_properties.rb +5 -0
  62. data/db/migrate/20200607161221_add_store_owner_order_notification_delivered_to_spree_orders.rb +7 -0
  63. data/db/migrate/20200607161222_add_new_order_notifications_email_to_spree_stores.rb +7 -0
  64. data/db/migrate/20200826075557_add_unique_index_on_taxon_id_and_product_id_to_spree_products_taxons.rb +5 -0
  65. data/lib/generators/spree/dummy/dummy_generator.rb +1 -0
  66. data/lib/generators/spree/install/templates/vendor/assets/javascripts/spree/backend/all.js +0 -2
  67. data/lib/generators/spree/install/templates/vendor/assets/javascripts/spree/frontend/all.js +0 -2
  68. data/lib/generators/spree/mailers_preview/mailers_preview_generator.rb +23 -0
  69. data/lib/generators/spree/mailers_preview/templates/mailers/previews/order_preview.rb +13 -0
  70. data/lib/generators/spree/mailers_preview/templates/mailers/previews/reimbursement_preview.rb +5 -0
  71. data/lib/generators/spree/mailers_preview/templates/mailers/previews/shipment_preview.rb +5 -0
  72. data/lib/generators/spree/mailers_preview/templates/mailers/previews/user_preview.rb +11 -0
  73. data/lib/spree/core/controller_helpers/common.rb +1 -0
  74. data/lib/spree/core/controller_helpers/currency_helpers.rb +15 -0
  75. data/lib/spree/core/controller_helpers/store.rb +12 -1
  76. data/lib/spree/core/version.rb +1 -1
  77. data/lib/spree/core.rb +1 -0
  78. data/lib/spree/permitted_attributes.rb +7 -4
  79. data/lib/spree/testing_support/authorization_helpers.rb +7 -4
  80. data/lib/spree/testing_support/capybara_ext.rb +0 -7
  81. data/lib/spree/testing_support/factories/store_factory.rb +11 -8
  82. data/spree_core.gemspec +6 -6
  83. data/vendor/assets/javascripts/cleave.js +1669 -0
  84. metadata +44 -32
  85. data/app/finders/spree/addresses/find.rb +0 -17
  86. data/app/models/spree/order_contents.rb +0 -31
  87. data/app/services/spree/account/addresses/base.rb +0 -39
  88. data/app/services/spree/account/addresses/create.rb +0 -18
  89. data/app/services/spree/account/addresses/update.rb +0 -18
  90. data/app/views/spree/order_mailer/_adjustment.html.erb +0 -8
  91. data/app/views/spree/order_mailer/_subtotal.html.erb +0 -8
  92. data/app/views/spree/order_mailer/_total.html.erb +0 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 839249efbd80112c669ba2a4790ab353b6c31476be2c845de2edfbda03d6cd6b
4
- data.tar.gz: 170887f258fae01503d713b33f709fdff05f8f8298c3bdfb11d659881be58a3d
3
+ metadata.gz: dd3e3f16eb808f16f592360085f02f1382ee4ddd6ee0903c3eb8a8079e5d8bad
4
+ data.tar.gz: 8567b7555de6f0f578d6277e6943af11b68329e5e17a77d13c7e66085e7fe09f
5
5
  SHA512:
6
- metadata.gz: b8492dc3ea5d4c89f2cc6de08ac9aee6b28bbc04fa9518550c72c51c9ccf60bf1930fe0c5db5000a5baee6faa1a2924d84e32c20bfd1fc58cbe3c73db27b593a
7
- data.tar.gz: 95128587c2913170eccf5dd5bcf1cd39686c5e57cd4ec952e8fcfa89079ff28671f7630c975fd6e2af0243a71c54fab8f6605d01a9b038f368e3aa6dde90c2e8
6
+ metadata.gz: 113900d45a999bb7aa47209797e8ab47a5ed6f40caa445242952eac3a604cc43bc658fec8fb86dc148743032f71341d97331cd7d6d7b77d84df36ffc979f122b
7
+ data.tar.gz: a175395cbe157f6ca1704ab5bdacbbf5c9abbee4bdae89f19363c06fc7a1fe06610fab87347342ecddd297d3bf22bf9354116340e8e408270a4f968a78883a0e
@@ -7,6 +7,7 @@ class Spree::BaseController < ApplicationController
7
7
  include Spree::Core::ControllerHelpers::Search
8
8
  include Spree::Core::ControllerHelpers::Store
9
9
  include Spree::Core::ControllerHelpers::StrongParameters
10
+ include Spree::Core::ControllerHelpers::CurrencyHelpers
10
11
 
11
12
  respond_to :html
12
13
  end
@@ -22,6 +22,13 @@ module Spree
22
22
  to_html
23
23
  end
24
24
 
25
+ def display_compare_at_price(product_or_variant)
26
+ product_or_variant.
27
+ price_in(current_currency).
28
+ display_compare_at_price_including_vat_for(current_price_options).
29
+ to_html
30
+ end
31
+
25
32
  def link_to_tracking(shipment, options = {})
26
33
  return unless shipment.tracking && shipment.shipping_method
27
34
 
@@ -34,7 +41,15 @@ module Spree
34
41
  end
35
42
  end
36
43
 
37
- def logo(image_path = Spree::Config[:logo], options = {})
44
+ def logo(image_path = nil, options = {})
45
+ image_path ||= if current_store.logo.attached? && current_store.logo.variable?
46
+ main_app.url_for(current_store.logo.variant(resize: '244x104>'))
47
+ elsif current_store.logo.attached? && current_store.logo.image?
48
+ main_app.url_for(current_store.logo)
49
+ else
50
+ Spree::Config[:logo]
51
+ end
52
+
38
53
  path = spree.respond_to?(:root_path) ? spree.root_path : main_app.root_path
39
54
 
40
55
  link_to path, 'aria-label': current_store.name, method: options[:method] do
@@ -97,7 +112,13 @@ module Spree
97
112
  def pretty_time(time)
98
113
  return '' if time.blank?
99
114
 
100
- [I18n.l(time.to_date, format: :long), time.strftime('%l:%M %p')].join(' ')
115
+ [I18n.l(time.to_date, format: :long), time.strftime('%l:%M %p %Z')].join(' ')
116
+ end
117
+
118
+ def pretty_date(date)
119
+ return '' if date.blank?
120
+
121
+ [I18n.l(date.to_date, format: :long)].join(' ')
101
122
  end
102
123
 
103
124
  def seo_url(taxon, options = nil)
@@ -0,0 +1,24 @@
1
+ module Spree
2
+ module MailHelper
3
+ include BaseHelper
4
+
5
+ def variant_image_url(variant)
6
+ image = default_image_for_product_or_variant(variant)
7
+ image ? main_app.url_for(image.url(:small)) : 'noimage/small.png'
8
+ end
9
+
10
+ def name_for(order)
11
+ order.name || Spree.t('customer')
12
+ end
13
+
14
+ def logo_path
15
+ if current_store.present? && current_store.logo.attached? && current_store.logo.variable?
16
+ main_app.url_for(current_store.logo.variant(resize: '244x104>'))
17
+ elsif current_store.present? && current_store.logo.attached? && current_store.logo.image?
18
+ main_app.url_for(current_store.logo)
19
+ else
20
+ Spree::Config.mailer_logo || Spree::Config.logo
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,10 +1,18 @@
1
1
  module Spree
2
2
  class BaseMailer < ActionMailer::Base
3
+ add_template_helper(MailHelper)
4
+
5
+ def current_store
6
+ @current_store ||= Spree::Store.current
7
+ end
8
+ helper_method :current_store
9
+
3
10
  def from_address
4
- Spree::Store.current.mail_from_address
11
+ current_store.mail_from_address
5
12
  end
6
13
 
7
- def money(amount, currency = Spree::Config[:currency])
14
+ def money(amount, currency = nil)
15
+ currency ||= current_store.default_currency
8
16
  Spree::Money.new(amount, currency: currency).to_s
9
17
  end
10
18
  helper_method :money
@@ -16,6 +24,7 @@ module Spree
16
24
 
17
25
  def mail(headers = {}, &block)
18
26
  ensure_default_action_mailer_url_host
27
+ set_email_locale
19
28
  super if Spree::Config[:send_core_emails]
20
29
  end
21
30
 
@@ -26,7 +35,12 @@ module Spree
26
35
  # http://guides.rubyonrails.org/action_mailer_basics.html#generating-urls-in-action-mailer-views
27
36
  def ensure_default_action_mailer_url_host
28
37
  ActionMailer::Base.default_url_options ||= {}
29
- ActionMailer::Base.default_url_options[:host] ||= Spree::Store.current.url
38
+ ActionMailer::Base.default_url_options[:host] ||= current_store.url
39
+ end
40
+
41
+ def set_email_locale
42
+ locale = @order&.store&.default_locale || current_store&.default_locale
43
+ I18n.locale = locale if locale.present?
30
44
  end
31
45
  end
32
46
  end
@@ -2,15 +2,24 @@ module Spree
2
2
  class OrderMailer < BaseMailer
3
3
  def confirm_email(order, resend = false)
4
4
  @order = order.respond_to?(:id) ? order : Spree::Order.find(order)
5
+ current_store = @order.store
5
6
  subject = (resend ? "[#{Spree.t(:resend).upcase}] " : '')
6
- subject += "#{Spree::Store.current.name} #{Spree.t('order_mailer.confirm_email.subject')} ##{@order.number}"
7
+ subject += "#{current_store.name} #{Spree.t('order_mailer.confirm_email.subject')} ##{@order.number}"
7
8
  mail(to: @order.email, from: from_address, subject: subject)
8
9
  end
9
10
 
11
+ def store_owner_notification_email(order)
12
+ @order = order.respond_to?(:id) ? order : Spree::Order.find(order)
13
+ current_store = @order.store
14
+ subject = Spree.t('order_mailer.store_owner_notification_email.subject', store_name: current_store.name)
15
+ mail(to: current_store.new_order_notifications_email, from: from_address, subject: subject)
16
+ end
17
+
10
18
  def cancel_email(order, resend = false)
11
19
  @order = order.respond_to?(:id) ? order : Spree::Order.find(order)
20
+ current_store = @order.store
12
21
  subject = (resend ? "[#{Spree.t(:resend).upcase}] " : '')
13
- subject += "#{Spree::Store.current.name} #{Spree.t('order_mailer.cancel_email.subject')} ##{@order.number}"
22
+ subject += "#{current_store.name} #{Spree.t('order_mailer.cancel_email.subject')} ##{@order.number}"
14
23
  mail(to: @order.email, from: from_address, subject: subject)
15
24
  end
16
25
  end
@@ -2,9 +2,11 @@ module Spree
2
2
  class ReimbursementMailer < BaseMailer
3
3
  def reimbursement_email(reimbursement, resend = false)
4
4
  @reimbursement = reimbursement.respond_to?(:id) ? reimbursement : Spree::Reimbursement.find(reimbursement)
5
+ @order = @reimbursement.order
6
+ current_store = @reimbursement.store || Spree::Store.current
5
7
  subject = (resend ? "[#{Spree.t(:resend).upcase}] " : '')
6
- subject += "#{Spree::Store.current.name} #{Spree.t('reimbursement_mailer.reimbursement_email.subject')} ##{@reimbursement.order.number}"
7
- mail(to: @reimbursement.order.email, from: from_address, subject: subject)
8
+ subject += "#{current_store.name} #{Spree.t('reimbursement_mailer.reimbursement_email.subject')} ##{@order.number}"
9
+ mail(to: @order.email, from: current_store.mail_from_address, subject: subject)
8
10
  end
9
11
  end
10
12
  end
@@ -2,9 +2,11 @@ module Spree
2
2
  class ShipmentMailer < BaseMailer
3
3
  def shipped_email(shipment, resend = false)
4
4
  @shipment = shipment.respond_to?(:id) ? shipment : Spree::Shipment.find(shipment)
5
+ @order = @shipment.order
6
+ current_store = @shipment.store
5
7
  subject = (resend ? "[#{Spree.t(:resend).upcase}] " : '')
6
- subject += "#{Spree::Store.current.name} #{Spree.t('shipment_mailer.shipped_email.subject')} ##{@shipment.order.number}"
7
- mail(to: @shipment.order.email, from: from_address, subject: subject)
8
+ subject += "#{current_store.name} #{Spree.t('shipment_mailer.shipped_email.subject')} ##{@order.number}"
9
+ mail(to: @order.email, from: from_address, subject: subject)
8
10
  end
9
11
  end
10
12
  end
@@ -9,7 +9,8 @@ module Spree
9
9
  dependent: :destroy
10
10
 
11
11
  delegate :display_price, :display_amount, :price, :currency, :price=,
12
- :price_including_vat_for, :currency=, to: :find_or_build_default_price
12
+ :price_including_vat_for, :currency=, :display_compare_at_price,
13
+ :compare_at_price, :compare_at_price=, to: :find_or_build_default_price
13
14
 
14
15
  after_save :save_default_price
15
16
 
@@ -30,15 +30,20 @@ module Spree
30
30
  self.whitelisted_ransackable_associations = %w[bill_address ship_address]
31
31
  self.whitelisted_ransackable_attributes = %w[id email]
32
32
 
33
+ def self.with_email(query)
34
+ where('email LIKE ?', "%#{query}%")
35
+ end
36
+
33
37
  def self.with_address(query, address = :ship_address)
34
38
  left_outer_joins(address).
35
39
  where("#{Spree::Address.table_name}.firstname like ?", "%#{query}%").
36
40
  or(left_outer_joins(address).where("#{Spree::Address.table_name}.lastname like ?", "%#{query}%"))
37
41
  end
38
42
 
39
- def self.with_email_or_addresses_ids(query, addresses_ids = [])
40
- where('email LIKE ?', "%#{query}%").
41
- or(where(id: addresses_ids))
43
+ def self.with_email_or_address(email, address)
44
+ left_outer_joins(:addresses).
45
+ where("#{Spree::Address.table_name}.firstname LIKE ? or #{Spree::Address.table_name}.lastname LIKE ? or email LIKE ?",
46
+ "%#{address}%", "%#{address}%", "%#{email}%")
42
47
  end
43
48
  end
44
49
 
@@ -54,8 +59,9 @@ module Spree
54
59
  first
55
60
  end
56
61
 
57
- def total_available_store_credit
58
- store_credits.reload.to_a.sum(&:amount_remaining)
62
+ def total_available_store_credit(currency = nil)
63
+ currency ||= Spree::Config[:currency]
64
+ store_credits.where(currency: currency).reload.to_a.sum(&:amount_remaining)
59
65
  end
60
66
 
61
67
  private
@@ -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,10 @@ 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 currency configurations
72
+ preference :allow_currency_change, :boolean, default: false
73
+ preference :show_currency_selector, :boolean, default: false
74
+
70
75
  # searcher_class allows spree extension writers to provide their own Search class
71
76
  def searcher_class
72
77
  @searcher_class ||= Spree::Core::Search::Base
@@ -11,8 +11,7 @@ module Spree
11
11
  :checkout_remove_store_credit_service, :checkout_get_shipping_rates_service,
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
- :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
14
+ :products_finder, :taxon_finder, :line_item_by_variant_finder, :cart_estimate_shipping_rates_service
16
15
  ].freeze
17
16
 
18
17
  attr_accessor *INJECTION_POINTS
@@ -60,14 +59,9 @@ module Spree
60
59
  # coupons
61
60
  # TODO: we should split this service into 2 seperate - Add and Remove
62
61
  @coupon_handler = 'Spree::PromotionHandler::Coupon'
63
-
64
- # account
65
- @account_create_address_service = 'Spree::Account::Addresses::Create'
66
- @account_update_address_service = 'Spree::Account::Addresses::Update'
67
62
  end
68
63
 
69
64
  def set_default_finders
70
- @address_finder = 'Spree::Addresses::Find'
71
65
  @country_finder = 'Spree::Countries::Find'
72
66
  @current_order_finder = 'Spree::Orders::FindCurrent'
73
67
  @completed_order_finder = 'Spree::Orders::FindComplete'
@@ -57,7 +57,16 @@ 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
+ if Spree::Config.allow_currency_change == true
61
+ currency_price = Spree::Price.where(
62
+ currency: order.currency,
63
+ variant_id: variant_id
64
+ ).first
65
+
66
+ self.price = currency_price.price_including_vat_for(tax_zone: tax_zone)
67
+ else
68
+ self.price = variant.price_including_vat_for(tax_zone: tax_zone)
69
+ end
61
70
  end
62
71
 
63
72
  def copy_tax_category
@@ -66,8 +75,7 @@ module Spree
66
75
 
67
76
  extend DisplayMoney
68
77
  money_methods :amount, :subtotal, :discounted_amount, :final_amount, :total, :price,
69
- :adjustment_total, :additional_tax_total, :promo_total, :included_tax_total,
70
- :pre_tax_amount
78
+ :adjustment_total, :additional_tax_total, :promo_total, :included_tax_total
71
79
 
72
80
  alias single_money display_price
73
81
  alias single_display_amount display_price
@@ -24,7 +24,11 @@ module Spree
24
24
  after_touch :touch_all_products
25
25
 
26
26
  def filter_param
27
- presentation.titleize.delete(' ').downcase
27
+ name.titleize.delete(' ').downcase
28
+ end
29
+
30
+ def self.color
31
+ find_by(name: 'color')
28
32
  end
29
33
 
30
34
  private
@@ -55,18 +55,31 @@ module Spree
55
55
  def update_or_create_address(attributes = {})
56
56
  return if attributes.blank?
57
57
 
58
- attributes.transform_values! { |v| v == '' ? nil : v }
58
+ attributes = attributes.select { |_k, v| v.present? }
59
59
 
60
- default_address_scope = user ? user.addresses : ::Spree::Address
61
- default_address = default_address_scope.find_by(id: attributes[:id])
60
+ if user
61
+ address = user.addresses.build(attributes.except(:id)).check
62
+ return address if address.id
63
+ end
64
+
65
+ if attributes[:id]
66
+ address = Spree::Address.find(attributes[:id])
67
+ attributes.delete(:id)
62
68
 
63
- if default_address&.editable?
64
- default_address.update(attributes)
69
+ if address&.editable?
70
+ address.update(attributes)
71
+ return address
72
+ else
73
+ attributes.delete(:id)
74
+ end
75
+ end
65
76
 
66
- return default_address
77
+ unless attributes[:id]
78
+ address = Spree::Address.new(attributes)
79
+ address.save
67
80
  end
68
81
 
69
- ::Spree::Address.find_or_create_by(attributes.except(:id, :updated_at, :created_at))
82
+ address
70
83
  end
71
84
  end
72
85
  end
@@ -1,14 +1,6 @@
1
1
  module Spree
2
2
  class Order < Spree::Base
3
3
  module StoreCredit
4
- def add_store_credit_payments(amount = nil)
5
- Spree::Dependencies.checkout_add_store_credit_service.constantize.call(order: self, amount: amount)
6
- end
7
-
8
- def remove_store_credit_payments
9
- Spree::Dependencies.checkout_remove_store_credit_service.constantize.call(order: self)
10
- end
11
-
12
4
  def covered_by_store_credit?
13
5
  return false unless user
14
6
 
@@ -22,7 +22,7 @@ module Spree
22
22
  money_methods :outstanding_balance, :item_total, :adjustment_total,
23
23
  :included_tax_total, :additional_tax_total, :tax_total,
24
24
  :shipment_total, :promo_total, :total,
25
- :cart_promo_total, :pre_tax_item_amount, :pre_tax_total
25
+ :cart_promo_total
26
26
 
27
27
  alias display_ship_total display_shipment_total
28
28
  alias_attribute :ship_total, :shipment_total
@@ -174,12 +174,7 @@ module Spree
174
174
 
175
175
  # Sum of all line item amounts pre-tax
176
176
  def pre_tax_item_amount
177
- line_items.sum(:pre_tax_amount)
178
- end
179
-
180
- # Sum of all line item and shipment pre-tax
181
- def pre_tax_total
182
- pre_tax_item_amount + shipments.sum(:pre_tax_amount)
177
+ line_items.to_a.sum(&:pre_tax_amount)
183
178
  end
184
179
 
185
180
  def shipping_discount
@@ -302,15 +297,15 @@ module Spree
302
297
  def outstanding_balance
303
298
  if canceled?
304
299
  -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
300
  else
310
- total - payment_total
301
+ total - (payment_total + reimbursement_paid_total)
311
302
  end
312
303
  end
313
304
 
305
+ def reimbursement_paid_total
306
+ reimbursements.sum(&:paid_amount)
307
+ end
308
+
314
309
  def outstanding_balance?
315
310
  outstanding_balance != 0
316
311
  end
@@ -356,6 +351,8 @@ module Spree
356
351
 
357
352
  deliver_order_confirmation_email unless confirmation_delivered?
358
353
 
354
+ deliver_store_owner_order_notification_email if deliver_store_owner_order_notification_email?
355
+
359
356
  consider_risk
360
357
  end
361
358
 
@@ -646,6 +643,13 @@ module Spree
646
643
  sum(:amount)
647
644
  end
648
645
 
646
+ def has_free_shipping?
647
+ promotions.
648
+ joins(:promotion_actions).
649
+ where(spree_promotion_actions: { type: 'Spree::Promotion::Actions::FreeShipping' }).
650
+ exists?
651
+ end
652
+
649
653
  private
650
654
 
651
655
  def link_by_email
@@ -711,5 +715,17 @@ module Spree
711
715
  def credit_card_nil_payment?(attributes)
712
716
  payments.store_credits.present? && attributes[:amount].to_f.zero?
713
717
  end
718
+
719
+ # Returns true if:
720
+ # 1. an email address is set for new order notifications AND
721
+ # 2. no notification for this order has been sent yet.
722
+ def deliver_store_owner_order_notification_email?
723
+ store.new_order_notifications_email.present? && !store_owner_notification_delivered?
724
+ end
725
+
726
+ def deliver_store_owner_order_notification_email
727
+ OrderMailer.store_owner_notification_email(id).deliver_later
728
+ update_column(:store_owner_notification_delivered, true)
729
+ end
714
730
  end
715
731
  end
@@ -15,10 +15,16 @@ module Spree
15
15
  less_than_or_equal_to: MAXIMUM_AMOUNT
16
16
  }
17
17
 
18
+ validates :compare_at_amount, allow_nil: true, numericality: {
19
+ greater_than_or_equal_to: 0,
20
+ less_than_or_equal_to: MAXIMUM_AMOUNT
21
+ }
22
+
18
23
  extend DisplayMoney
19
- money_methods :amount, :price
24
+ money_methods :amount, :price, :compare_at_amount
25
+ alias display_compare_at_price display_compare_at_amount
20
26
 
21
- self.whitelisted_ransackable_attributes = ['amount']
27
+ self.whitelisted_ransackable_attributes = ['amount', 'compare_at_amount']
22
28
 
23
29
  def money
24
30
  Spree::Money.new(amount || 0, currency: currency)
@@ -28,17 +34,35 @@ module Spree
28
34
  self[:amount] = Spree::LocalizedNumber.parse(amount)
29
35
  end
30
36
 
37
+ def compare_at_money
38
+ Spree::Money.new(compare_at_amount || 0, currency: currency)
39
+ end
40
+
41
+ def compare_at_amount=(compare_at_amount)
42
+ self[:compare_at_amount] = Spree::LocalizedNumber.parse(compare_at_amount)
43
+ end
44
+
31
45
  alias_attribute :price, :amount
46
+ alias_attribute :compare_at_price, :compare_at_amount
32
47
 
33
48
  def price_including_vat_for(price_options)
34
49
  options = price_options.merge(tax_category: variant.tax_category)
35
50
  gross_amount(price, options)
36
51
  end
37
52
 
53
+ def compare_at_price_including_vat_for(price_options)
54
+ options = price_options.merge(tax_category: variant.tax_category)
55
+ gross_amount(compare_at_price, options)
56
+ end
57
+
38
58
  def display_price_including_vat_for(price_options)
39
59
  Spree::Money.new(price_including_vat_for(price_options), currency: currency)
40
60
  end
41
61
 
62
+ def display_compare_at_price_including_vat_for(price_options)
63
+ Spree::Money.new(compare_at_price_including_vat_for(price_options), currency: currency)
64
+ end
65
+
42
66
  # Remove variant default_scope `deleted_at: nil`
43
67
  def variant
44
68
  Spree::Variant.unscoped { super }
@@ -113,17 +113,17 @@ module Spree
113
113
 
114
114
  self.whitelisted_ransackable_associations = %w[taxons stores variants_including_master master variants]
115
115
  self.whitelisted_ransackable_attributes = %w[description name slug discontinue_on]
116
- self.whitelisted_ransackable_scopes = %w[not_discontinued]
116
+ self.whitelisted_ransackable_scopes = %w[not_discontinued search_by_name]
117
117
 
118
118
  [
119
119
  :sku, :price, :currency, :weight, :height, :width, :depth, :is_master,
120
- :cost_currency, :price_in, :amount_in, :cost_price
120
+ :cost_currency, :price_in, :amount_in, :cost_price, :compare_at_price
121
121
  ].each do |method_name|
122
122
  delegate method_name, :"#{method_name}=", to: :find_or_build_master
123
123
  end
124
124
 
125
125
  delegate :display_amount, :display_price, :has_default_price?,
126
- :images, to: :find_or_build_master
126
+ :display_compare_at_price, :images, to: :find_or_build_master
127
127
 
128
128
  alias master_images images
129
129
 
@@ -160,10 +160,8 @@ module Spree
160
160
  #
161
161
  # @return [Spree::Variant]
162
162
  def default_variant
163
- track_inventory = Spree::Config[:track_inventory_levels]
164
-
165
- Rails.cache.fetch("spree/default-variant/#{cache_key_with_version}/#{track_inventory}") do
166
- if track_inventory && variants.in_stock_or_backorderable.any?
163
+ Rails.cache.fetch(default_variant_cache_key) do
164
+ if Spree::Config[:track_inventory_levels] && variants.in_stock_or_backorderable.any?
167
165
  variants.in_stock_or_backorderable.first
168
166
  else
169
167
  has_variants? ? variants.first : master
@@ -252,6 +250,14 @@ module Spree
252
250
  where conditions.inject(:or)
253
251
  end
254
252
 
253
+ def self.search_by_name(query)
254
+ if defined?(SpreeGlobalize)
255
+ joins(:translations).order(:name).where("LOWER(#{Product::Translation.table_name}.name) LIKE LOWER(:query)", query: "%#{query}%").distinct
256
+ else
257
+ where("LOWER(#{Product.table_name}.name) LIKE LOWER(:query)", query: "%#{query}%")
258
+ end
259
+ end
260
+
255
261
  # Suitable for displaying only variants that has at least one option value.
256
262
  # There may be scenarios where an option type is removed and along with it
257
263
  # all option values. At that point all variants associated with only those
@@ -344,6 +350,10 @@ module Spree
344
350
  save
345
351
  end
346
352
 
353
+ def default_variant_cache_key
354
+ "spree/default-variant/#{cache_key_with_version}/#{Spree::Config[:track_inventory_levels]}"
355
+ end
356
+
347
357
  def ensure_master
348
358
  return unless new_record?
349
359
 
@@ -25,9 +25,10 @@ module Spree
25
25
 
26
26
  def remove(coupon_code)
27
27
  promotion = order.promotions.with_coupon_code(coupon_code)
28
+
28
29
  if promotion.present?
29
30
  # Order promotion has to be destroyed before line item removing
30
- order.order_promotions.find_by!(promotion_id: promotion.id).destroy
31
+ order.order_promotions.where(promotion_id: promotion.id).destroy_all
31
32
 
32
33
  remove_promotion_adjustments(promotion)
33
34
  remove_promotion_line_items(promotion)
@@ -75,7 +76,7 @@ module Spree
75
76
  line_item = order.find_line_item_by_variant(item.variant)
76
77
  next if line_item.blank?
77
78
 
78
- Spree::Dependencies.cart_remove_item_service.constantize.call(order: order, item: item.variant, quantity: item.quantity)
79
+ Spree::Dependencies.cart_remove_item_service(order: order, item: item.variant, quantity: item.quantity)
79
80
  end
80
81
  end
81
82
 
@@ -60,6 +60,8 @@ module Spree
60
60
  class_attribute :reimbursement_failure_hooks
61
61
  self.reimbursement_failure_hooks = []
62
62
 
63
+ delegate :store, :currency, to: :order
64
+
63
65
  state_machine :reimbursement_status, initial: :pending do
64
66
  event :errored do
65
67
  transition to: :errored, from: :pending
@@ -42,6 +42,8 @@ module Spree
42
42
  scope :reverse_chronological, -> { order(Arel.sql('coalesce(spree_shipments.shipped_at, spree_shipments.created_at) desc'), id: :desc) }
43
43
  scope :valid, -> { where.not(state: :canceled) }
44
44
 
45
+ delegate :store, :currency, to: :order
46
+
45
47
  # shipment state machine (see http://github.com/pluginaweek/state_machine/tree/master for details)
46
48
  state_machine initial: :pending, use_transactions: false do
47
49
  event :ready do
@@ -104,11 +106,6 @@ module Spree
104
106
  inventory_units.any?(&:backordered?)
105
107
  end
106
108
 
107
- # TODO: delegate currency to Order, order.currency is mandatory
108
- def currency
109
- order ? order.currency : Spree::Config[:currency]
110
- end
111
-
112
109
  # Determines the appropriate +state+ according to the following logic:
113
110
  #
114
111
  # pending unless order is complete and +order.payment_state+ is +paid+
@@ -106,8 +106,19 @@ module Spree
106
106
  private
107
107
 
108
108
  def create_stock_items
109
- Variant.includes(:product).find_each do |variant|
110
- propagate_variant(variant)
109
+ variants_scope = Spree::Variant
110
+ prepared_stock_items = variants_scope.ids.map do |variant_id|
111
+ Hash[
112
+ 'stock_location_id', id,
113
+ 'variant_id', variant_id,
114
+ 'backorderable', backorderable_default,
115
+ 'created_at', Time.current,
116
+ 'updated_at', Time.current
117
+ ]
118
+ end
119
+ if prepared_stock_items.any?
120
+ stock_items.insert_all(prepared_stock_items)
121
+ variants_scope.touch_all
111
122
  end
112
123
  end
113
124