spree_core 2.3.1 → 2.3.2

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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/app/helpers/spree/base_helper.rb +3 -3
  3. data/app/models/spree/ability.rb +1 -0
  4. data/app/models/spree/app_configuration.rb +0 -1
  5. data/app/models/spree/base.rb +6 -0
  6. data/app/models/spree/calculator/flat_percent_item_total.rb +9 -3
  7. data/app/models/spree/calculator/flexi_rate.rb +1 -1
  8. data/app/models/spree/calculator/percent_on_line_item.rb +1 -1
  9. data/app/models/spree/calculator/tiered_flat_rate.rb +37 -0
  10. data/app/models/spree/calculator/tiered_percent.rb +44 -0
  11. data/app/models/spree/credit_card.rb +35 -14
  12. data/app/models/spree/inventory_unit.rb +1 -0
  13. data/app/models/spree/item_adjustments.rb +3 -2
  14. data/app/models/spree/line_item.rb +2 -2
  15. data/app/models/spree/order.rb +36 -20
  16. data/app/models/spree/order/checkout.rb +60 -24
  17. data/app/models/spree/order_contents.rb +3 -6
  18. data/app/models/spree/order_populator.rb +1 -1
  19. data/app/models/spree/order_updater.rb +19 -4
  20. data/app/models/spree/payment.rb +4 -0
  21. data/app/models/spree/payment/processing.rb +6 -2
  22. data/app/models/spree/price.rb +10 -0
  23. data/app/models/spree/product.rb +81 -54
  24. data/app/models/spree/promotion/actions/create_adjustment.rb +2 -11
  25. data/app/models/spree/promotion/actions/create_item_adjustments.rb +2 -19
  26. data/app/models/spree/promotion_handler/cart.rb +14 -2
  27. data/app/models/spree/promotion_handler/coupon.rb +8 -2
  28. data/app/models/spree/return_authorization.rb +2 -2
  29. data/app/models/spree/shipping_rate.rb +2 -2
  30. data/app/models/spree/stock/availability_validator.rb +3 -7
  31. data/app/models/spree/stock/estimator.rb +1 -1
  32. data/app/models/spree/stock/package.rb +1 -0
  33. data/app/models/spree/stock_item.rb +6 -1
  34. data/app/models/spree/stock_location.rb +4 -0
  35. data/app/models/spree/tax_rate.rb +15 -2
  36. data/app/models/spree/variant.rb +8 -3
  37. data/app/models/spree/zone.rb +2 -2
  38. data/config/locales/en.yml +33 -3
  39. data/db/default/spree/countries.rb +2 -1
  40. data/db/migrate/20130807024302_rename_adjustment_fields.rb +2 -5
  41. data/db/migrate/20140804185157_add_default_to_shipment_cost.rb +10 -0
  42. data/lib/generators/spree/custom_user/templates/authentication_helpers.rb.tt +12 -4
  43. data/lib/generators/spree/install/install_generator.rb +8 -0
  44. data/lib/spree/core.rb +1 -0
  45. data/lib/spree/core/adjustment_source.rb +26 -0
  46. data/lib/spree/core/controller_helpers.rb +10 -9
  47. data/lib/spree/core/controller_helpers/order.rb +18 -5
  48. data/lib/spree/core/engine.rb +6 -2
  49. data/lib/spree/core/importer/order.rb +52 -9
  50. data/lib/spree/core/version.rb +1 -1
  51. data/lib/spree/permitted_attributes.rb +4 -4
  52. data/lib/spree/testing_support/authorization_helpers.rb +1 -1
  53. data/lib/spree/testing_support/factories/product_factory.rb +1 -1
  54. metadata +27 -37
@@ -81,8 +81,14 @@ module Spree
81
81
  order.persist_totals
82
82
  self.success = Spree.t(:coupon_code_applied)
83
83
  else
84
- # if the promotion was created after the order
85
- self.error = Spree.t(:coupon_code_not_found)
84
+ # if the promotion exists on an order, but wasn't found above,
85
+ # we've already selected a better promotion
86
+ if order.promotions.with_coupon_code(order.coupon_code)
87
+ self.error = Spree.t(:coupon_code_better_exists)
88
+ else
89
+ # if the promotion was created after the order
90
+ self.error = Spree.t(:coupon_code_not_found)
91
+ end
86
92
  end
87
93
  end
88
94
  end
@@ -2,7 +2,7 @@ module Spree
2
2
  class ReturnAuthorization < Spree::Base
3
3
  belongs_to :order, class_name: 'Spree::Order'
4
4
 
5
- has_many :inventory_units
5
+ has_many :inventory_units, dependent: :nullify
6
6
  belongs_to :stock_location
7
7
  before_create :generate_number
8
8
  before_save :force_positive_amount
@@ -62,7 +62,7 @@ module Spree
62
62
  order.shipped_shipments.collect{|s| s.inventory_units.to_a}.flatten
63
63
  end
64
64
 
65
- # Used when Adjustment#update! wants to update the related adjustmenrt
65
+ # Used when Adjustment#update! wants to update the related adjustment
66
66
  def compute_amount(*args)
67
67
  amount.abs * -1
68
68
  end
@@ -23,10 +23,10 @@ module Spree
23
23
  if tax_rate.included_in_price?
24
24
  if tax_amount > 0
25
25
  amount = "#{display_tax_amount(tax_amount)} #{tax_rate.name}"
26
- price += " (incl. #{amount})"
26
+ price += " (#{Spree.t(:incl)} #{amount})"
27
27
  else
28
28
  amount = "#{display_tax_amount(tax_amount*-1)} #{tax_rate.name}"
29
- price += " (excl. #{amount})"
29
+ price += " (#{Spree.t(:excl)} #{amount})"
30
30
  end
31
31
  else
32
32
  amount = "#{display_tax_amount(tax_amount)} #{tax_rate.name}"
@@ -2,13 +2,9 @@ module Spree
2
2
  module Stock
3
3
  class AvailabilityValidator < ActiveModel::Validator
4
4
  def validate(line_item)
5
- if shipment = line_item.target_shipment
6
- units = shipment.inventory_units_for(line_item.variant)
7
- return if units.count > line_item.quantity
8
- quantity = line_item.quantity - units.count
9
- else
10
- quantity = line_item.quantity
11
- end
5
+ unit_count = line_item.inventory_units.size
6
+ return if unit_count >= line_item.quantity
7
+ quantity = line_item.quantity - unit_count
12
8
 
13
9
  quantifier = Stock::Quantifier.new(line_item.variant)
14
10
 
@@ -54,7 +54,7 @@ module Spree
54
54
  begin
55
55
  ship_method.include?(order.ship_address) &&
56
56
  calculator.available?(package) &&
57
- (calculator.preferences[:currency].nil? ||
57
+ (calculator.preferences[:currency].blank? ||
58
58
  calculator.preferences[:currency] == currency)
59
59
  rescue Exception => exception
60
60
  log_calculator_exception(ship_method, exception)
@@ -76,6 +76,7 @@ module Spree
76
76
 
77
77
  def to_shipment
78
78
  shipment = Spree::Shipment.new
79
+ shipment.address = order.ship_address
79
80
  shipment.order = order
80
81
  shipment.stock_location = stock_location
81
82
  shipment.shipping_rates = shipping_rates
@@ -8,10 +8,11 @@ module Spree
8
8
 
9
9
  validates_presence_of :stock_location, :variant
10
10
  validates_uniqueness_of :variant_id, scope: [:stock_location_id, :deleted_at]
11
+ validates :count_on_hand, numericality: { greater_than_or_equal_to: 0 }, if: :verify_count_on_hand?
11
12
 
12
13
  delegate :weight, :should_track_inventory?, to: :variant
13
14
 
14
- after_save :conditional_variant_touch
15
+ after_save :conditional_variant_touch, if: :changed?
15
16
  after_touch { variant.touch }
16
17
 
17
18
  def backordered_inventory_units
@@ -56,6 +57,10 @@ module Spree
56
57
  end
57
58
 
58
59
  private
60
+ def verify_count_on_hand?
61
+ count_on_hand_changed? && !backorderable? && (count_on_hand < count_on_hand_was) && (count_on_hand < 0)
62
+ end
63
+
59
64
  def count_on_hand=(value)
60
65
  write_attribute(:count_on_hand, value)
61
66
  end
@@ -13,6 +13,10 @@ module Spree
13
13
 
14
14
  after_create :create_stock_items, :if => "self.propagate_all_variants?"
15
15
 
16
+ def state_text
17
+ state.try(:abbr) || state.try(:name) || state_name
18
+ end
19
+
16
20
  # Wrapper for creating a new stock item respecting the backorderable config
17
21
  def propagate_variant(variant)
18
22
  self.stock_items.create!(variant: variant, backorderable: self.backorderable_default)
@@ -12,15 +12,18 @@ module Spree
12
12
  class TaxRate < Spree::Base
13
13
  acts_as_paranoid
14
14
  include Spree::Core::CalculatedAdjustments
15
+ include Spree::Core::AdjustmentSource
15
16
  belongs_to :zone, class_name: "Spree::Zone"
16
17
  belongs_to :tax_category, class_name: "Spree::TaxCategory"
17
18
 
18
- has_many :adjustments, as: :source, dependent: :destroy
19
+ has_many :adjustments, as: :source
19
20
 
20
21
  validates :amount, presence: true, numericality: true
21
22
  validates :tax_category_id, presence: true
22
23
  validates_with DefaultTaxZoneValidator
23
24
 
25
+ before_destroy :deals_with_adjustments_for_deleted_source
26
+
24
27
  scope :by_zone, ->(zone) { where(zone_id: zone) }
25
28
 
26
29
  # Gets the array of TaxRates appropriate for the specified order
@@ -71,7 +74,7 @@ module Spree
71
74
  def self.adjust(order_tax_zone, items)
72
75
  rates = self.match(order_tax_zone)
73
76
  tax_categories = rates.map(&:tax_category)
74
- relevant_items = items.select { |item| tax_categories.include?(item.tax_category) }
77
+ relevant_items, non_relevant_items = items.partition { |item| tax_categories.include?(item.tax_category) }
75
78
  relevant_items.each do |item|
76
79
  item.adjustments.tax.delete_all
77
80
  relevant_rates = rates.select { |rate| rate.tax_category == item.tax_category }
@@ -80,6 +83,13 @@ module Spree
80
83
  rate.adjust(order_tax_zone, item)
81
84
  end
82
85
  end
86
+ non_relevant_items.each do |item|
87
+ if item.adjustments.tax.present?
88
+ item.adjustments.tax.delete_all
89
+ item.update_column(:pre_tax_amount, nil)
90
+ item.send(:recalculate_adjustments)
91
+ end
92
+ end
83
93
  end
84
94
 
85
95
  # Tax rates can *potentially* be applicable to an order.
@@ -176,6 +186,9 @@ module Spree
176
186
  label = ""
177
187
  label << (name.present? ? name : tax_category.name) + " "
178
188
  label << (show_rate_in_label? ? "#{amount * 100}%" : "")
189
+ label << " (#{Spree.t(:included_in_price)})" if included_in_price?
190
+ label
179
191
  end
192
+
180
193
  end
181
194
  end
@@ -11,6 +11,7 @@ module Spree
11
11
 
12
12
  has_many :inventory_units
13
13
  has_many :line_items, inverse_of: :variant
14
+ has_many :orders, through: :line_items
14
15
 
15
16
  has_many :stock_items, dependent: :destroy, inverse_of: :variant
16
17
  has_many :stock_locations, through: :stock_items
@@ -32,9 +33,9 @@ module Spree
32
33
  inverse_of: :variant
33
34
 
34
35
  validate :check_price
35
- validates :price, numericality: { greater_than_or_equal_to: 0 }
36
-
37
36
  validates :cost_price, numericality: { greater_than_or_equal_to: 0, allow_nil: true }
37
+ validates :price, numericality: { greater_than_or_equal_to: 0 }
38
+ validates_uniqueness_of :sku, allow_blank: true, conditions: -> { where(deleted_at: nil) }
38
39
 
39
40
  before_validation :set_cost_currency
40
41
  after_save :save_default_price
@@ -207,8 +208,12 @@ module Spree
207
208
  end
208
209
  end
209
210
 
211
+ def default_price_changed?
212
+ default_price && (default_price.changed? || default_price.new_record?)
213
+ end
214
+
210
215
  def save_default_price
211
- default_price.save if default_price && (default_price.changed? || default_price.new_record?)
216
+ default_price.save if default_price_changed?
212
217
  end
213
218
 
214
219
  def set_cost_currency
@@ -14,7 +14,7 @@ module Spree
14
14
  def self.default_tax
15
15
  where(default_tax: true).first
16
16
  end
17
-
17
+
18
18
  # Returns the matching zone with the highest priority zone type (State, Country, Zone.)
19
19
  # Returns nil in the case of no matches.
20
20
  def self.match(address)
@@ -61,7 +61,7 @@ module Spree
61
61
  @countries ||= case kind
62
62
  when 'country' then zoneables
63
63
  when 'state' then zoneables.collect(&:country)
64
- else nil
64
+ else []
65
65
  end.flatten.compact.uniq
66
66
  end
67
67
 
@@ -11,6 +11,12 @@ en:
11
11
  phone: Phone
12
12
  state: State
13
13
  zipcode: Zip Code
14
+ spree/calculator/tiered_flat_rate:
15
+ preferred_base_amount: Base Amount
16
+ preferred_tiers: Tiers
17
+ spree/calculator/tiered_percent:
18
+ preferred_base_percent: Base Percent
19
+ preferred_tiers: Tiers
14
20
  spree/country:
15
21
  iso: ISO
16
22
  iso3: ISO3
@@ -230,6 +236,19 @@ en:
230
236
  other: Zones
231
237
  errors:
232
238
  models:
239
+ spree/calculator/tiered_flat_rate:
240
+ attributes:
241
+ base:
242
+ keys_should_be_positive_number: "Tier keys should all be numbers larger than 0"
243
+ preferred_tiers:
244
+ should_be_hash: "should be a hash"
245
+ spree/calculator/tiered_percent:
246
+ attributes:
247
+ base:
248
+ keys_should_be_positive_number: "Tier keys should all be numbers larger than 0"
249
+ values_should_be_percent: "Tier values should all be percentages between 0% and 100%"
250
+ preferred_tiers:
251
+ should_be_hash: "should be a hash"
233
252
  spree/classification:
234
253
  attributes:
235
254
  taxon_id:
@@ -238,6 +257,7 @@ en:
238
257
  attributes:
239
258
  base:
240
259
  card_expired: "Card has expired"
260
+ expiry_invalid: "Card expiration is invalid"
241
261
  spree/line_item:
242
262
  attributes:
243
263
  currency:
@@ -404,6 +424,7 @@ en:
404
424
  back_to_prototypes_list: Back To Prototypes List
405
425
  back_to_reports_list: Back To Reports List
406
426
  back_to_shipping_categories: Back To Shipping Categories
427
+ back_to_shipping_categories_list: Back To Shipping Categories List
407
428
  back_to_shipping_methods_list: Back To Shipping Methods List
408
429
  back_to_states_list: Back To States List
409
430
  back_to_stock_locations_list: Back to Stock Locations List
@@ -418,6 +439,8 @@ en:
418
439
  backorderable: Backorderable
419
440
  backorders_allowed: backorders allowed
420
441
  balance_due: Balance Due
442
+ base_amount: Base Amount
443
+ base_percent: Base Percent
421
444
  bill_address: Bill Address
422
445
  billing: Billing
423
446
  billing_address: Billing Address
@@ -449,6 +472,7 @@ en:
449
472
  choose_dashboard_locale: Choose Dashboard Locale
450
473
  choose_location: Choose location
451
474
  city: City
475
+ click_and_drag_on_the_products_to_sort_them: 'Click &amp; drag on the products to sort them.'
452
476
  clone: Clone
453
477
  close: Close
454
478
  close_all_adjustments: Close All Adjustments
@@ -488,6 +512,7 @@ en:
488
512
  coupon_code_unknown_error: This coupon code could not be applied to the cart at this time.
489
513
  create: Create
490
514
  create_a_new_account: Create a new account
515
+ create_new_order: Create new order
491
516
  created_at: Created At
492
517
  credit: Credit
493
518
  credit_card: Credit Card
@@ -585,6 +610,7 @@ en:
585
610
  signup: User signup
586
611
  exceptions:
587
612
  count_on_hand_setter: Cannot set count_on_hand manually, as it is set automatically by the recalculate_count_on_hand callback. Please use `update_column(:count_on_hand, value)` instead.
613
+ excl: excl.
588
614
  expiration: Expiration
589
615
  extension: Extension
590
616
  existing_shipments: Existing shipments
@@ -634,10 +660,12 @@ en:
634
660
  image: Image
635
661
  images: Images
636
662
  inactive: Inactive
663
+ incl: incl.
637
664
  included_in_price: Included in Price
638
665
  included_price_validation: cannot be selected unless you have set a Default Tax Zone
639
666
  instructions_to_reset_password: Please enter your email on the form below
640
667
  insufficient_stock: Insufficient stock available, only %{on_hand} remaining
668
+ insufficient_stock_lines_present: Some line items in this order have insufficient quantity.
641
669
  intercept_email_address: Intercept Email Address
642
670
  intercept_email_instructions: Override email recipient and replace with this address.
643
671
  internal_name: Internal Name
@@ -739,6 +767,7 @@ en:
739
767
  new_zone: New Zone
740
768
  next: Next
741
769
  no_actions_added: No actions added
770
+ no_images_found: No images found
742
771
  no_orders_found: No orders found
743
772
  no_payment_methods_found: No payment methods found
744
773
  no_payment_found: No payment found
@@ -884,7 +913,7 @@ en:
884
913
  label: Order must contain %{select} of these products
885
914
  match_all: all
886
915
  match_any: at least one
887
- match_none: none
916
+ match_none: none
888
917
  product_source:
889
918
  group: From product group
890
919
  manual: Manually choose
@@ -1001,7 +1030,6 @@ en:
1001
1030
  shipment: Shipment
1002
1031
  shipment_adjustments: "Shipment adjustments"
1003
1032
  shipment_details: "From %{stock_location} via %{shipping_method}"
1004
- shipment_inc_vat: Shipment including VAT
1005
1033
  shipment_mailer:
1006
1034
  shipped_email:
1007
1035
  dear_customer: Dear Customer,
@@ -1082,7 +1110,6 @@ en:
1082
1110
  tax_category: Tax Category
1083
1111
  tax_rate_amount_explanation: Tax rates are a decimal amount to aid in calculations, (i.e. if the tax rate is 5% then enter 0.05)
1084
1112
  tax_rates: Tax Rates
1085
- tax_settings: Tax Settings
1086
1113
  taxon: Taxon
1087
1114
  taxon_edit: Edit Taxon
1088
1115
  taxon_placeholder: Add a Taxon
@@ -1103,6 +1130,9 @@ en:
1103
1130
  there_are_no_items_for_this_order: There are no items for this order. Please add an item to the order to continue.
1104
1131
  there_were_problems_with_the_following_fields: There were problems with the following fields
1105
1132
  thumbnail: Thumbnail
1133
+ tiers: Tiers
1134
+ tiered_flat_rate: Tiered Flat Rate
1135
+ tiered_percent: Tiered Percent
1106
1136
  time: Time
1107
1137
  to_add_variants_you_must_first_define: To add variants, you must first define
1108
1138
  total: Total
@@ -226,6 +226,7 @@ Spree::Country.create!([
226
226
  { name: "New Zealand", iso3: "NZL", iso: "NZ", iso_name: "NEW ZEALAND", numcode: "554" },
227
227
  { name: "Saint Kitts and Nevis", iso3: "KNA", iso: "KN", iso_name: "SAINT KITTS AND NEVIS", numcode: "659", states_required: true },
228
228
  { name: "Serbia", iso3: "SRB", iso: "RS", "iso_name" => "SERBIA", numcode: "999" },
229
- { name: "Montenegro", iso3: "MNE", iso: "ME", iso_name: "MONTENEGRO", numcode: "499" }
229
+ { name: "Montenegro", iso3: "MNE", iso: "ME", iso_name: "MONTENEGRO", numcode: "499" },
230
+ { name: "Jersey", iso3: "JEY", iso: "JE", iso_name: "JERSEY", numcode: "44" }
230
231
  ])
231
232
  Spree::Config[:default_country_id] = Spree::Country.find_by(name: "United States").id
@@ -7,11 +7,8 @@ class RenameAdjustmentFields < ActiveRecord::Migration
7
7
 
8
8
  # This enables the Spree::Order#all_adjustments association to work correctly
9
9
  Spree::Adjustment.reset_column_information
10
- Spree::Adjustment.find_each do |adjustment|
11
- if adjustment.adjustable.is_a?(Spree::Order)
12
- adjustment.order = adjustment.adjustable
13
- adjustment.save
14
- end
10
+ Spree::Adjustment.where(adjustable_type: "Spree::Order").find_each do |adjustment|
11
+ adjustment.update_column(:order_id, adjustment.adjustable_id)
15
12
  end
16
13
  end
17
14
  end
@@ -0,0 +1,10 @@
1
+ class AddDefaultToShipmentCost < ActiveRecord::Migration
2
+ def up
3
+ change_column :spree_shipments, :cost, :decimal, precision: 10, scale: 2, default: 0.0
4
+ Spree::Shipment.where(cost: nil).update_all(cost: 0)
5
+ end
6
+
7
+ def down
8
+ change_column :spree_shipments, :cost, :decimal, precision: 10, scale: 2
9
+ end
10
+ end
@@ -1,15 +1,20 @@
1
1
  module Spree
2
- module AuthenticationHelpers
2
+ module CurrentUserHelpers
3
3
  def self.included(receiver)
4
- receiver.send :helper_method, :spree_login_path
5
- receiver.send :helper_method, :spree_signup_path
6
- receiver.send :helper_method, :spree_logout_path
7
4
  receiver.send :helper_method, :spree_current_user
8
5
  end
9
6
 
10
7
  def spree_current_user
11
8
  current_user
12
9
  end
10
+ end
11
+
12
+ module AuthenticationHelpers
13
+ def self.included(receiver)
14
+ receiver.send :helper_method, :spree_login_path
15
+ receiver.send :helper_method, :spree_signup_path
16
+ receiver.send :helper_method, :spree_logout_path
17
+ end
13
18
 
14
19
  def spree_login_path
15
20
  main_app.login_path
@@ -26,3 +31,6 @@ module Spree
26
31
  end
27
32
 
28
33
  ApplicationController.send :include, Spree::AuthenticationHelpers
34
+ ApplicationController.send :include, Spree::CurrentUserHelpers
35
+
36
+ Spree::Api::BaseController.send :include, Spree::CurrentUserHelpers
@@ -13,6 +13,7 @@ module Spree
13
13
  class_option :admin_email, :type => :string
14
14
  class_option :admin_password, :type => :string
15
15
  class_option :lib_name, :type => :string, :default => 'spree'
16
+ class_option :enforce_available_locales, :type => :boolean, :default => nil
16
17
 
17
18
  def self.source_paths
18
19
  paths = self.superclass.source_paths
@@ -100,6 +101,13 @@ Disallow: /account
100
101
  end
101
102
  end
102
103
  APP
104
+
105
+ if !options[:enforce_available_locales].nil?
106
+ application <<-APP
107
+ # Prevent this deprecation message: https://github.com/svenfuchs/i18n/commit/3b6e56e
108
+ I18n.enforce_available_locales = #{options[:enforce_available_locales]}
109
+ APP
110
+ end
103
111
  end
104
112
 
105
113
  def include_seed_data