spree_core 2.3.1 → 2.3.2

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