spree_core 3.4.6 → 3.5.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
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|