spree_core 3.4.6 → 3.5.0.rc1

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 (70) hide show
  1. checksums.yaml +5 -5
  2. data/app/assets/javascripts/spree.js.coffee +1 -1
  3. data/app/helpers/spree/base_helper.rb +4 -0
  4. data/app/models/concerns/spree/named_type.rb +1 -1
  5. data/app/models/concerns/spree/user_methods.rb +21 -4
  6. data/app/models/concerns/spree/user_reporting.rb +2 -2
  7. data/app/models/spree/address.rb +6 -12
  8. data/app/models/spree/adjustable/adjustments_updater.rb +2 -1
  9. data/app/models/spree/country.rb +2 -1
  10. data/app/models/spree/line_item.rb +8 -2
  11. data/app/models/spree/log_entry.rb +1 -1
  12. data/app/models/spree/order.rb +8 -6
  13. data/app/models/spree/order/checkout.rb +1 -0
  14. data/app/models/spree/order_contents.rb +20 -12
  15. data/app/models/spree/order_inventory.rb +24 -12
  16. data/app/models/spree/payment/processing.rb +2 -2
  17. data/app/models/spree/preferences/preferable.rb +1 -1
  18. data/app/models/spree/product/scopes.rb +1 -1
  19. data/app/models/spree/promotion.rb +15 -1
  20. data/app/models/spree/promotion/rules/option_value.rb +13 -5
  21. data/app/models/spree/promotion/rules/product.rb +2 -1
  22. data/app/models/spree/promotion/rules/taxon.rb +3 -1
  23. data/app/models/spree/promotion_action_line_item.rb +3 -0
  24. data/app/models/spree/promotion_handler/promotion_duplicator.rb +52 -0
  25. data/app/models/spree/refund.rb +1 -1
  26. data/app/models/spree/reimbursement.rb +1 -1
  27. data/app/models/spree/reimbursement/reimbursement_type_engine.rb +7 -18
  28. data/app/models/spree/reimbursement_performer.rb +3 -7
  29. data/app/models/spree/reimbursement_type/original_payment.rb +2 -2
  30. data/app/models/spree/reimbursement_type/reimbursement_helpers.rb +3 -7
  31. data/app/models/spree/reimbursement_type/store_credit.rb +2 -10
  32. data/app/models/spree/shipment.rb +10 -4
  33. data/app/models/spree/stock/availability_validator.rb +1 -1
  34. data/app/models/spree/stock/packer.rb +1 -1
  35. data/app/models/spree/stock/splitter/backordered.rb +5 -7
  36. data/app/models/spree/stock/splitter/base.rb +1 -0
  37. data/app/models/spree/stock/splitter/shipping_category.rb +9 -16
  38. data/app/models/spree/stock/splitter/weight.rb +18 -20
  39. data/app/models/spree/stock_transfer.rb +2 -1
  40. data/app/models/spree/store_credit_category.rb +13 -0
  41. data/app/models/spree/taxon.rb +7 -0
  42. data/app/models/spree/variant.rb +1 -1
  43. data/app/validators/email_validator.rb +7 -0
  44. data/config/locales/en.yml +18 -27
  45. data/db/default/spree/states.rb +9 -27
  46. data/db/migrate/20150128032538_remove_environment_from_tracker.rb +2 -0
  47. data/db/migrate/20171004223836_remove_icon_from_taxons.rb +8 -0
  48. data/db/migrate/20180222133746_add_unique_index_on_spree_promotions_code.rb +6 -0
  49. data/lib/generators/spree/dummy_model/dummy_model_generator.rb +23 -0
  50. data/lib/generators/spree/dummy_model/templates/migration.rb.tt +10 -0
  51. data/lib/generators/spree/dummy_model/templates/model.rb.tt +6 -0
  52. data/lib/spree/core/controller_helpers/auth.rb +1 -1
  53. data/lib/spree/core/controller_helpers/common.rb +4 -0
  54. data/lib/spree/core/controller_helpers/order.rb +6 -5
  55. data/lib/spree/core/engine.rb +10 -10
  56. data/lib/spree/core/environment_extension.rb +3 -0
  57. data/lib/spree/core/importer/order.rb +1 -1
  58. data/lib/spree/core/validators/email.rb +1 -0
  59. data/lib/spree/core/version.rb +1 -1
  60. data/lib/spree/money.rb +1 -5
  61. data/lib/spree/permitted_attributes.rb +1 -1
  62. data/lib/spree/testing_support/capybara_ext.rb +16 -13
  63. data/lib/spree/testing_support/common_rake.rb +4 -1
  64. data/lib/spree/testing_support/factories/inventory_unit_factory.rb +7 -0
  65. data/lib/spree/testing_support/factories/taxon_factory.rb +1 -1
  66. data/spree_core.gemspec +1 -1
  67. data/vendor/assets/javascripts/jsuri.js +458 -2
  68. metadata +13 -7
  69. data/app/models/spree/tracker.rb +0 -25
  70. data/lib/spree/testing_support/factories/tracker_factory.rb +0 -7
@@ -4,7 +4,7 @@ module Spree
4
4
 
5
5
  has_many :stock_movements, as: :originator
6
6
 
7
- belongs_to :source_location, class_name: 'StockLocation'
7
+ belongs_to :source_location, class_name: 'StockLocation', optional: true
8
8
  belongs_to :destination_location, class_name: 'StockLocation'
9
9
 
10
10
  validates :number, uniqueness: true
@@ -36,6 +36,7 @@ module Spree
36
36
  end
37
37
  end
38
38
 
39
+ # receive inventory from external vendor
39
40
  def receive(destination_location, variants)
40
41
  transfer(nil, destination_location, variants)
41
42
  end
@@ -2,6 +2,8 @@ module Spree
2
2
  class StoreCreditCategory < Spree::Base
3
3
  validates :name, presence: true
4
4
 
5
+ before_destroy :validate_not_used
6
+
5
7
  GIFT_CARD_CATEGORY_NAME = 'Gift Card'.freeze
6
8
  DEFAULT_NON_EXPIRING_TYPES = [GIFT_CARD_CATEGORY_NAME]
7
9
 
@@ -13,6 +15,17 @@ module Spree
13
15
  DEFAULT_NON_EXPIRING_TYPES | Spree::Config[:non_expiring_credit_types]
14
16
  end
15
17
 
18
+ def store_credit_category_used?
19
+ Spree::StoreCredit.exists?(category_id: id)
20
+ end
21
+
22
+ def validate_not_used
23
+ if store_credit_category_used?
24
+ errors.add(:base, :cannot_destroy_if_used_in_store_credit)
25
+ throw(:abort)
26
+ end
27
+ end
28
+
16
29
  class << self
17
30
  def default_reimbursement_category(_options = {})
18
31
  Spree::StoreCreditCategory.first
@@ -21,6 +21,7 @@ module Spree
21
21
 
22
22
  validates :name, presence: true, uniqueness: { scope: [:parent_id, :taxonomy_id], allow_blank: true }
23
23
  validates :permalink, uniqueness: { case_sensitive: false }
24
+ validate :check_for_root, on: :create
24
25
  with_options length: { maximum: 255 }, allow_blank: true do
25
26
  validates :meta_keywords
26
27
  validates :meta_description
@@ -93,5 +94,11 @@ module Spree
93
94
  # Have taxonomy touch happen in #touch_ancestors_and_taxonomy rather than association option in order for imports to override.
94
95
  taxonomy.try!(:touch)
95
96
  end
97
+
98
+ def check_for_root
99
+ if taxonomy.try(:root).present? && parent_id == nil
100
+ errors.add(:root_conflict, 'this taxonomy already has a root taxon')
101
+ end
102
+ end
96
103
  end
97
104
  end
@@ -67,7 +67,7 @@ module Spree
67
67
 
68
68
  scope :not_deleted, -> { where("#{Variant.quoted_table_name}.deleted_at IS NULL") }
69
69
 
70
- scope :for_currency_and_available_price_amount, ->(currency) do
70
+ scope :for_currency_and_available_price_amount, ->(currency = nil) do
71
71
  currency ||= Spree::Config[:currency]
72
72
  joins(:prices).where('spree_prices.currency = ?', currency).where('spree_prices.amount IS NOT NULL').distinct
73
73
  end
@@ -0,0 +1,7 @@
1
+ class EmailValidator < ActiveModel::EachValidator
2
+ def validate_each(record, attribute, value)
3
+ unless value =~ /\A[^@\s]+@[^@\s]+\z/
4
+ record.errors.add(attribute, :invalid, { value: value }.merge!(options))
5
+ end
6
+ end
7
+ end
@@ -92,6 +92,7 @@ en:
92
92
  description: Description
93
93
  event_name: Event Name
94
94
  expires_at: Expires At
95
+ generate_code: Generate coupon code
95
96
  name: Name
96
97
  path: Path
97
98
  starts_at: Starts At
@@ -350,6 +351,10 @@ en:
350
351
  greater_than_zero_restrict_delete: is greater than zero. Can not delete store credit.
351
352
  amount_authorized:
352
353
  exceeds_total_credits: Exceeds total credits.
354
+ spree/store_credit_category:
355
+ attributes:
356
+ base:
357
+ cannot_destroy_if_used_in_store_credit: Cannot delete store credit categories once they are used in store credit.
353
358
  spree/variant:
354
359
  attributes:
355
360
  base:
@@ -507,18 +512,9 @@ en:
507
512
  all_adjustments_opened: All adjustments successfully opened!
508
513
  all_departments: All departments
509
514
  all_items_have_been_returned: All items have been returned
510
- already_signed_up_for_analytics: You have already signed up for Spree Analytics
511
515
  alt_text: Alternative Text
512
516
  alternative_phone: Alternative Phone
513
517
  amount: Amount
514
- analytics_desc_header_1: Spree Analytics
515
- analytics_desc_header_2: Live analytics integrated into your Spree dashboard
516
- analytics_desc_list_1: Get live sales information as it happens
517
- analytics_desc_list_2: Requires only a free Spree account to activate
518
- analytics_desc_list_3: Absolutely no code to install
519
- analytics_desc_list_4: It's completely free!
520
- analytics_engine: Analytics Engine
521
- analytics_trackers: Analytics Trackers
522
518
  and: and
523
519
  approve: approve
524
520
  approver: Approver
@@ -605,7 +601,6 @@ en:
605
601
  continue_shopping: Continue shopping
606
602
  cost_currency: Cost Currency
607
603
  cost_price: Cost Price
608
- could_not_connect_to_jirafe: Could not connect to Jirafe to sync data. This will be automatically retried later.
609
604
  could_not_create_customer_return: Could not create customer return
610
605
  could_not_create_stock_movement: There was a problem saving this stock movement. Please try again.
611
606
  count_on_hand: Count On Hand
@@ -655,16 +650,6 @@ en:
655
650
  customer_search: Customer Search
656
651
  cut: Cut
657
652
  cvv_response: CVV Response
658
- dash:
659
- jirafe:
660
- app_id: App ID
661
- app_token: App Token
662
- currently_unavailable: Jirafe is currently unavailable. Spree will automatically connect to Jirafe once it is available.
663
- explanation: The fields below may already be populated if you chose to register with Jirafe from the admin dashboard.
664
- header: Jirafe Analytics Settings
665
- site_id: Site ID
666
- token: Token
667
- jirafe_settings_updated: Jirafe Settings have been updated.
668
653
  date: Date
669
654
  date_completed: Date Completed
670
655
  date_picker:
@@ -773,8 +758,7 @@ en:
773
758
  gateway_error: Gateway Error
774
759
  general: General
775
760
  general_settings: General Settings
776
- google_analytics: Google Analytics
777
- google_analytics_id: Analytics ID
761
+ generate_code: Generate coupon code
778
762
  guest_checkout: Guest Checkout
779
763
  guest_user_account: Checkout as a Guest
780
764
  has_no_shipped_units: has no shipped units
@@ -838,7 +822,6 @@ en:
838
822
  items_in_rmas: Items in Return Authorizations
839
823
  items_to_be_reimbursed: Items to be reimbursed
840
824
  items_reimbursed: Items reimbursed
841
- jirafe: Jirafe
842
825
  join_slack: Join Slack
843
826
  last_name: Last Name
844
827
  last_name_begins_with: Last Name Begins With
@@ -868,6 +851,7 @@ en:
868
851
  manual_intervention_required: Manual intervention required
869
852
  manage_variants: Manage Variants
870
853
  master_price: Master Price
854
+ master_sku: Master SKU
871
855
  match_choices:
872
856
  all: All
873
857
  none: None
@@ -953,10 +937,10 @@ en:
953
937
  notice_messages:
954
938
  product_cloned: Product has been cloned
955
939
  product_deleted: Product has been deleted
956
- product_not_cloned: Product could not be cloned
957
- product_not_deleted: Product could not be deleted
940
+ product_not_cloned: "Product could not be cloned. Reason: %{error}"
941
+ product_not_deleted: "Product could not be deleted. Reason: %{error}"
958
942
  variant_deleted: Variant has been deleted
959
- variant_not_deleted: Variant could not be deleted
943
+ variant_not_deleted: "Variant could not be deleted. Reason: %{error}"
960
944
  num_orders: "# Orders"
961
945
  number: Number
962
946
  on_hand: On Hand
@@ -1065,6 +1049,7 @@ en:
1065
1049
  pre_tax_total: Pre-Tax Total
1066
1050
  preferred_reimbursement_type: Preferred Reimbursement Type
1067
1051
  presentation: Presentation
1052
+ preview_product: Preview Product
1068
1053
  previous: Previous
1069
1054
  previous_state_missing: "n/a"
1070
1055
  price: Price
@@ -1088,6 +1073,8 @@ en:
1088
1073
  products: Products
1089
1074
  promotion: Promotion
1090
1075
  promotionable: Promotable
1076
+ promotion_cloned: Promotion has been cloned
1077
+ promotion_not_cloned: "Promotion has not been cloned. Reason: %{error}"
1091
1078
  promotion_action: Promotion Action
1092
1079
  promotion_action_types:
1093
1080
  create_adjustment:
@@ -1392,6 +1379,7 @@ en:
1392
1379
  unable_to_delete: Unable to delete store credit
1393
1380
  unable_to_fund: Unable to pay for order using store credits
1394
1381
  unable_to_update: Unable to update store credit
1382
+ store_credits: Store Credits
1395
1383
  store_credit_categories: Store Credit Categories
1396
1384
  store_credit_payment_method:
1397
1385
  unable_to_void: "Unable to void code: %{auth_code}"
@@ -1404,6 +1392,10 @@ en:
1404
1392
  unable_to_find_for_action: "Could not find store credit for auth code: %{auth_code} for action: %{action}"
1405
1393
  user_has_no_store_credits: "User does not have any available store credit"
1406
1394
  select_one_store_credit: "Select store credit to go towards remaining balance"
1395
+ store_default: Default store
1396
+ store_set_default_button: Set as default
1397
+ store_not_set_as_default: Couldn't set store %{store} as a default store
1398
+ store_set_as_default: Store %{store} is now a default store
1407
1399
  street_address: Street Address
1408
1400
  street_address_2: Street Address (cont'd)
1409
1401
  subtotal: Subtotal
@@ -1412,7 +1404,6 @@ en:
1412
1404
  successfully_created: ! '%{resource} has been successfully created!'
1413
1405
  successfully_refunded: ! '%{resource} has been successfully refunded!'
1414
1406
  successfully_removed: ! '%{resource} has been successfully removed!'
1415
- successfully_signed_up_for_analytics: Successfully signed up for Spree Analytics
1416
1407
  successfully_updated: ! '%{resource} has been successfully updated!'
1417
1408
  summary: Summary
1418
1409
  tax: Tax
@@ -1,29 +1,11 @@
1
- connection = ApplicationRecord.connection
2
- state_inserts = []
3
-
4
- state_values = -> do
5
- Spree::Country.where(states_required: true).each do |country|
6
- carmen_country = Carmen::Country.named(country.name)
7
- next if !carmen_country
8
- carmen_country.subregions.each do |subregion|
9
- name = connection.quote subregion.name
10
- abbr = connection.quote subregion.code
11
- country_id = connection.quote country.id
12
-
13
- state_inserts << [name, abbr, country_id].join(", ")
14
- end
1
+ Spree::Country.where(states_required: true).each do |country|
2
+ carmen_country = Carmen::Country.named(country.name)
3
+ next if !carmen_country
4
+ carmen_country.subregions.each do |subregion|
5
+ country.states.where(
6
+ name: subregion.name,
7
+ abbr: subregion.code,
8
+ country_id: country.id
9
+ ).first_or_create
15
10
  end
16
-
17
- state_inserts.map { |x| "(#{x})" }
18
- end
19
-
20
- columns = ["name", "abbr", "country_id"].map do |column|
21
- connection.quote_column_name column
22
- end.join(', ')
23
-
24
- state_values.call.each_slice(500) do |state_values_batch|
25
- connection.execute <<-SQL
26
- INSERT INTO spree_states (#{columns})
27
- VALUES #{state_values_batch.join(", ")};
28
- SQL
29
11
  end
@@ -1,4 +1,6 @@
1
1
  class RemoveEnvironmentFromTracker < ActiveRecord::Migration[4.2]
2
+ class Spree::Tracker < Spree::Base; end
3
+
2
4
  def up
3
5
  Spree::Tracker.where('environment != ?', Rails.env).update_all(active: false)
4
6
  remove_column :spree_trackers, :environment
@@ -0,0 +1,8 @@
1
+ class RemoveIconFromTaxons < ActiveRecord::Migration[5.1]
2
+ def change
3
+ remove_column :spree_taxons, :icon_file_name
4
+ remove_column :spree_taxons, :icon_content_type
5
+ remove_column :spree_taxons, :icon_file_size
6
+ remove_column :spree_taxons, :icon_updated_at
7
+ end
8
+ end
@@ -0,0 +1,6 @@
1
+ class AddUniqueIndexOnSpreePromotionsCode < ActiveRecord::Migration[5.1]
2
+ def change
3
+ remove_index :spree_promotions, :code
4
+ add_index :spree_promotions, :code, unique: true
5
+ end
6
+ end
@@ -0,0 +1,23 @@
1
+ module Spree
2
+ class DummyModelGenerator < Rails::Generators::NamedBase
3
+ include Rails::Generators::ResourceHelpers
4
+ include Rails::Generators::Migration
5
+
6
+ desc 'Set up Dummy Model which is used for tests'
7
+
8
+ def self.source_paths
9
+ paths = superclass.source_paths
10
+ paths << File.expand_path('../templates', __FILE__)
11
+ paths.flatten
12
+ end
13
+
14
+ def generate
15
+ migration_template 'migration.rb.tt', 'db/migrate/create_spree_dummy_models.rb'
16
+ template 'model.rb.tt', 'app/models/spree/dummy_model.rb'
17
+ end
18
+
19
+ def self.next_migration_number(dirname)
20
+ format('%.3d', (current_migration_number(dirname) + 1))
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,10 @@
1
+ class CreateSpreeDummyModels < ActiveRecord::Migration[5.1]
2
+ def change
3
+ create_table :spree_dummy_models do |t|
4
+ t.string :name
5
+ t.integer :position
6
+
7
+ t.timestamps
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,6 @@
1
+ module Spree
2
+ class Spree::DummyModel < ApplicationRecord
3
+ acts_as_list
4
+ validates :name, presence: true
5
+ end
6
+ end
@@ -26,7 +26,7 @@ module Spree
26
26
 
27
27
  def set_guest_token
28
28
  if cookies.signed[:guest_token].blank?
29
- cookies.permanent.signed[:guest_token] = generate_guest_token
29
+ cookies.permanent.signed[:guest_token] = { value: generate_guest_token, httponly: true }
30
30
  end
31
31
  end
32
32
 
@@ -41,6 +41,10 @@ module Spree
41
41
  end
42
42
 
43
43
  def render_404(_exception = nil)
44
+ ActiveSupport::Deprecation.warn(<<-EOS, caller)
45
+ #render_404 will be removed in Spree 3.6
46
+ You should switch to 404 handled by rails
47
+ EOS
44
48
  respond_to do |type|
45
49
  type.html { render status: :not_found, file: "#{::Rails.root}/public/404", formats: [:html], layout: nil }
46
50
  type.all { head :not_found }
@@ -29,19 +29,20 @@ module Spree
29
29
  def current_order(options = {})
30
30
  options[:create_order_if_necessary] ||= false
31
31
 
32
- return @current_order if @current_order
32
+ if @current_order
33
+ @current_order.last_ip_address = ip_address
34
+ return @current_order
35
+ end
33
36
 
34
37
  @current_order = find_order_by_token_or_user(options, true)
35
38
 
36
39
  if options[:create_order_if_necessary] && (@current_order.nil? || @current_order.completed?)
37
40
  @current_order = Spree::Order.create!(current_order_params)
38
41
  @current_order.associate_user! try_spree_current_user if try_spree_current_user
39
- end
40
-
41
- if @current_order
42
42
  @current_order.last_ip_address = ip_address
43
- return @current_order
44
43
  end
44
+
45
+ @current_order
45
46
  end
46
47
 
47
48
  def associate_user
@@ -1,6 +1,9 @@
1
1
  module Spree
2
2
  module Core
3
3
  class Engine < ::Rails::Engine
4
+ Environment = Struct.new(:calculators, :preferences, :payment_methods, :adjusters, :stock_splitters, :promotions)
5
+ SpreeCalculators = Struct.new(:shipping_methods, :tax_rates, :promotion_actions_create_adjustments, :promotion_actions_create_item_adjustments)
6
+ PromoEnvironment = Struct.new(:rules, :actions)
4
7
  isolate_namespace Spree
5
8
  engine_name 'spree'
6
9
 
@@ -9,8 +12,8 @@ module Spree
9
12
  end
10
13
 
11
14
  initializer 'spree.environment', before: :load_config_initializers do |app|
12
- app.config.spree = Spree::Core::Environment.new
13
- Spree::Config = app.config.spree.preferences # legacy access
15
+ app.config.spree = Environment.new(SpreeCalculators.new, Spree::AppConfiguration.new)
16
+ Spree::Config = app.config.spree.preferences
14
17
  end
15
18
 
16
19
  initializer 'spree.register.calculators' do |app|
@@ -27,7 +30,7 @@ module Spree
27
30
  ]
28
31
  end
29
32
 
30
- initializer 'spree.register.stock_splitters' do |app|
33
+ initializer 'spree.register.stock_splitters', before: :load_config_initializers do |app|
31
34
  app.config.spree.stock_splitters = [
32
35
  Spree::Stock::Splitter::ShippingCategory,
33
36
  Spree::Stock::Splitter::Backordered
@@ -53,13 +56,11 @@ module Spree
53
56
  # We need to define promotions rules here so extensions and existing apps
54
57
  # can add their custom classes on their initializer files
55
58
  initializer 'spree.promo.environment' do |app|
56
- app.config.spree.add_class('promotions')
57
- app.config.spree.promotions = Spree::Promo::Environment.new
59
+ app.config.spree.promotions = PromoEnvironment.new
58
60
  app.config.spree.promotions.rules = []
59
61
  end
60
62
 
61
63
  initializer 'spree.promo.register.promotion.calculators' do |app|
62
- app.config.spree.calculators.add_class('promotion_actions_create_adjustments')
63
64
  app.config.spree.calculators.promotion_actions_create_adjustments = [
64
65
  Spree::Calculator::FlatPercentItemTotal,
65
66
  Spree::Calculator::FlatRate,
@@ -68,7 +69,6 @@ module Spree
68
69
  Spree::Calculator::TieredFlatRate
69
70
  ]
70
71
 
71
- app.config.spree.calculators.add_class('promotion_actions_create_item_adjustments')
72
72
  app.config.spree.calculators.promotion_actions_create_item_adjustments = [
73
73
  Spree::Calculator::PercentOnLineItem,
74
74
  Spree::Calculator::FlatRate,
@@ -116,12 +116,12 @@ module Spree
116
116
  end
117
117
 
118
118
  config.to_prepare do
119
- # Ensure spree locale paths are present before decorators
120
- I18n.load_path.unshift(*(Dir.glob(
119
+ # Load spree locales before decorators
120
+ I18n.load_path += Dir.glob(
121
121
  File.join(
122
122
  File.dirname(__FILE__), '../../../config/locales', '*.{rb,yml}'
123
123
  )
124
- ) - I18n.load_path))
124
+ )
125
125
 
126
126
  # Load application's model / class decorators
127
127
  Dir.glob(File.join(File.dirname(__FILE__), '../../../app/**/*_decorator*.rb')) do |c|