spree_core 2.1.12 → 2.2.0

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 (172) hide show
  1. checksums.yaml +4 -4
  2. data/app/helpers/spree/base_helper.rb +4 -7
  3. data/app/helpers/spree/products_helper.rb +11 -9
  4. data/app/helpers/spree/store_helper.rb +5 -0
  5. data/app/models/spree/ability.rb +4 -0
  6. data/app/models/spree/address.rb +6 -6
  7. data/app/models/spree/adjustment.rb +40 -61
  8. data/app/models/spree/app_configuration.rb +1 -14
  9. data/app/models/spree/calculator.rb +12 -4
  10. data/app/models/spree/calculator/default_tax.rb +42 -38
  11. data/app/models/spree/calculator/flat_percent_item_total.rb +2 -4
  12. data/app/models/spree/calculator/free_shipping.rb +5 -2
  13. data/app/models/spree/calculator/percent_on_line_item.rb +15 -0
  14. data/app/models/spree/calculator/percent_per_item.rb +3 -0
  15. data/app/models/spree/classification.rb +3 -2
  16. data/app/models/spree/credit_card.rb +7 -25
  17. data/app/models/spree/gateway/bogus.rb +5 -5
  18. data/app/models/spree/gateway/bogus_simple.rb +0 -8
  19. data/app/models/spree/image.rb +0 -9
  20. data/app/models/spree/inventory_unit.rb +10 -4
  21. data/app/models/spree/item_adjustments.rb +65 -0
  22. data/app/models/spree/legacy_user.rb +1 -0
  23. data/app/models/spree/line_item.rb +33 -13
  24. data/app/models/spree/option_type.rb +2 -2
  25. data/app/models/spree/option_value.rb +1 -1
  26. data/app/models/spree/order.rb +109 -89
  27. data/app/models/spree/order/checkout.rb +48 -0
  28. data/app/models/spree/order_contents.rb +72 -37
  29. data/app/models/spree/order_inventory.rb +65 -68
  30. data/app/models/spree/order_populator.rb +3 -17
  31. data/app/models/spree/order_updater.rb +63 -44
  32. data/app/models/spree/payment.rb +20 -5
  33. data/app/models/spree/payment/processing.rb +19 -25
  34. data/app/models/spree/payment_capture_event.rb +9 -0
  35. data/app/models/spree/payment_method/check.rb +0 -2
  36. data/app/models/spree/price.rb +1 -1
  37. data/app/models/spree/product.rb +14 -16
  38. data/app/models/spree/product/scopes.rb +4 -6
  39. data/app/models/spree/product_option_type.rb +2 -2
  40. data/app/models/spree/product_property.rb +2 -2
  41. data/app/models/spree/promotion.rb +71 -50
  42. data/app/models/spree/promotion/actions/create_adjustment.rb +31 -32
  43. data/app/models/spree/promotion/actions/create_item_adjustments.rb +83 -0
  44. data/app/models/spree/promotion/actions/free_shipping.rb +36 -0
  45. data/app/models/spree/promotion/rules/first_order.rb +4 -0
  46. data/app/models/spree/promotion/rules/item_total.rb +5 -1
  47. data/app/models/spree/promotion/rules/product.rb +4 -0
  48. data/app/models/spree/promotion/rules/user.rb +5 -6
  49. data/app/models/spree/promotion/rules/user_logged_in.rb +4 -0
  50. data/app/models/spree/promotion_action.rb +1 -5
  51. data/app/models/spree/promotion_handler/cart.rb +38 -0
  52. data/app/models/spree/promotion_handler/coupon.rb +76 -0
  53. data/app/models/spree/promotion_handler/free_shipping.rb +31 -0
  54. data/app/models/spree/promotion_handler/page.rb +24 -0
  55. data/app/models/spree/promotion_rule.rb +15 -7
  56. data/app/models/spree/property.rb +1 -1
  57. data/app/models/spree/return_authorization.rb +7 -1
  58. data/app/models/spree/shipment.rb +113 -49
  59. data/app/models/spree/shipping_calculator.rb +4 -5
  60. data/app/models/spree/shipping_category.rb +2 -2
  61. data/app/models/spree/shipping_method.rb +12 -6
  62. data/app/models/spree/shipping_rate.rb +27 -7
  63. data/app/models/spree/stock/availability_validator.rb +1 -1
  64. data/app/models/spree/stock/estimator.rb +13 -1
  65. data/app/models/spree/stock/package.rb +11 -7
  66. data/app/models/spree/stock/packer.rb +3 -3
  67. data/app/models/spree/stock/quantifier.rb +9 -1
  68. data/app/models/spree/stock_item.rb +11 -6
  69. data/app/models/spree/stock_movement.rb +1 -2
  70. data/app/models/spree/tax_category.rb +6 -1
  71. data/app/models/spree/tax_rate.rb +57 -49
  72. data/app/models/spree/taxon.rb +10 -5
  73. data/app/models/spree/taxonomy.rb +5 -2
  74. data/app/models/spree/variant.rb +33 -16
  75. data/app/models/spree/zone.rb +24 -24
  76. data/app/views/spree/shared/_routes.html.erb +3 -0
  77. data/config/locales/en.yml +42 -26
  78. data/db/migrate/20130213191427_create_default_stock.rb +3 -3
  79. data/db/migrate/20130413230529_add_name_to_spree_credit_cards.rb +5 -0
  80. data/db/migrate/20130414000512_update_name_fields_on_spree_credit_cards.rb +13 -0
  81. data/db/migrate/20130417120035_update_adjustment_states.rb +2 -2
  82. data/db/migrate/20130417123427_add_shipping_rates_to_shipments.rb +1 -1
  83. data/db/migrate/20130509115210_add_number_to_stock_transfer.rb +1 -1
  84. data/db/migrate/20130611054351_rename_shipping_methods_zones_to_spree_shipping_methods_zones.rb +0 -5
  85. data/db/migrate/20130802022321_migrate_tax_categories_to_line_items.rb +7 -5
  86. data/db/migrate/20130807024301_upgrade_adjustments.rb +39 -0
  87. data/db/migrate/20130807024302_rename_adjustment_fields.rb +17 -0
  88. data/db/migrate/20130813004002_add_shipment_total_to_spree_orders.rb +5 -0
  89. data/db/migrate/20130813232134_rename_activators_to_promotions.rb +5 -0
  90. data/db/migrate/20130815000406_add_adjustment_total_to_line_items.rb +5 -0
  91. data/db/migrate/20130815024413_add_adjustment_total_to_shipments.rb +5 -0
  92. data/db/migrate/20130828234942_add_tax_total_to_line_items_shipments_and_orders.rb +8 -0
  93. data/db/migrate/20130830001159_migrate_old_shipping_calculators.rb +1 -1
  94. data/db/migrate/20130903183026_add_code_to_spree_promotion_rules.rb +5 -0
  95. data/db/migrate/20130917024658_remove_promotions_event_name_field.rb +5 -0
  96. data/db/migrate/20130924040529_add_promo_total_to_line_items_and_shipments_and_orders.rb +7 -0
  97. data/db/migrate/20131001013410_remove_unused_credit_card_fields.rb +7 -3
  98. data/db/migrate/20131107132123_add_tax_category_to_variants.rb +6 -0
  99. data/db/migrate/20131118043959_add_included_to_adjustments.rb +5 -0
  100. data/db/migrate/20131118050234_rename_tax_total_fields.rb +11 -0
  101. data/db/migrate/20131118183431_add_line_item_id_to_spree_inventory_units.rb +21 -0
  102. data/db/migrate/20131127001002_add_position_to_classifications.rb +5 -0
  103. data/db/migrate/20131211112807_create_spree_orders_promotions.rb +8 -0
  104. data/db/migrate/20131218054603_add_item_count_to_spree_orders.rb +5 -0
  105. data/db/migrate/20140106224208_rename_permalink_to_slug_for_products.rb +5 -0
  106. data/db/migrate/20140124023232_rename_activator_id_in_rules_and_actions_to_promotion_id.rb +6 -0
  107. data/db/migrate/20140203161722_add_approver_id_and_approved_at_to_orders.rb +6 -0
  108. data/db/migrate/20140204115338_add_confirmation_delivered_to_spree_orders.rb +5 -0
  109. data/db/migrate/20140205120320_create_spree_payment_capture_events.rb +12 -0
  110. data/db/migrate/20140205144710_add_uncaptured_amount_to_payments.rb +5 -0
  111. data/db/migrate/20140207085910_add_tax_category_id_to_shipping_methods.rb +5 -0
  112. data/db/migrate/20140207093021_add_tax_rate_id_to_shipping_rates.rb +5 -0
  113. data/db/migrate/20140211040159_add_pre_tax_amount_to_line_items_and_shipments.rb +6 -0
  114. data/db/migrate/20140213184916_add_more_indexes.rb +13 -0
  115. data/db/migrate/20140219060952_add_considered_risky_to_orders.rb +5 -0
  116. data/lib/generators/spree/dummy/dummy_generator.rb +1 -6
  117. data/lib/generators/spree/install/install_generator.rb +6 -6
  118. data/lib/generators/spree/install/templates/{app/assets/javascripts/admin → vendor/assets/javascripts/spree/backend}/all.js +3 -3
  119. data/lib/generators/spree/install/templates/{app/assets/javascripts/store → vendor/assets/javascripts/spree/frontend}/all.js +3 -3
  120. data/lib/generators/spree/install/templates/{app/assets/stylesheets/store → vendor/assets/stylesheets/spree/backend}/all.css +3 -3
  121. data/lib/generators/spree/install/templates/{app/assets/stylesheets/admin → vendor/assets/stylesheets/spree/frontend}/all.css +3 -3
  122. data/lib/spree/core.rb +21 -8
  123. data/lib/spree/core/calculated_adjustments.rb +0 -40
  124. data/lib/spree/core/controller_helpers.rb +5 -0
  125. data/lib/spree/core/controller_helpers/auth.rb +2 -2
  126. data/lib/spree/core/controller_helpers/common.rb +0 -5
  127. data/lib/spree/core/controller_helpers/order.rb +8 -9
  128. data/lib/spree/core/engine.rb +10 -17
  129. data/lib/spree/core/permalinks.rb +1 -1
  130. data/lib/spree/core/product_duplicator.rb +3 -8
  131. data/lib/spree/core/user_address.rb +1 -1
  132. data/lib/spree/core/validators/email.rb +23 -1
  133. data/lib/spree/core/version.rb +1 -1
  134. data/lib/spree/money.rb +1 -1
  135. data/lib/spree/permitted_attributes.rb +2 -2
  136. data/lib/spree/testing_support/caching.rb +47 -0
  137. data/lib/spree/testing_support/factories/adjustment_factory.rb +11 -2
  138. data/lib/spree/testing_support/factories/credit_card_factory.rb +2 -1
  139. data/lib/spree/testing_support/factories/order_factory.rb +10 -5
  140. data/lib/spree/testing_support/factories/payment_factory.rb +2 -2
  141. data/lib/spree/testing_support/factories/payment_method_factory.rb +3 -3
  142. data/lib/spree/testing_support/factories/promotion_factory.rb +16 -1
  143. data/lib/spree/testing_support/factories/shipment_factory.rb +8 -4
  144. data/lib/spree/testing_support/factories/shipping_method_factory.rb +1 -3
  145. data/lib/spree/testing_support/factories/stock_factory.rb +1 -1
  146. data/lib/spree/testing_support/factories/tax_rate_factory.rb +2 -2
  147. data/lib/spree/testing_support/order_walkthrough.rb +1 -1
  148. data/lib/tasks/core.rake +2 -2
  149. data/vendor/assets/fonts/FontAwesome.otf +0 -0
  150. data/vendor/assets/fonts/fontawesome-webfont.eot +0 -0
  151. data/vendor/assets/fonts/fontawesome-webfont.svg +399 -0
  152. data/vendor/assets/fonts/fontawesome-webfont.ttf +0 -0
  153. data/vendor/assets/fonts/fontawesome-webfont.woff +0 -0
  154. data/vendor/assets/stylesheets/font-awesome.scss +1475 -0
  155. metadata +73 -44
  156. data/app/assets/javascripts/admin/handlebar_extensions.js +0 -9
  157. data/app/helpers/spree/admin/adjustments_helper.rb +0 -26
  158. data/app/helpers/spree/admin/images_helper.rb +0 -18
  159. data/app/helpers/spree/promotion_rules_helper.rb +0 -13
  160. data/app/models/spree/activator.rb +0 -29
  161. data/app/models/spree/calculator/per_item.rb +0 -41
  162. data/app/models/spree/stock/remaining_packer.rb +0 -22
  163. data/app/views/spree/payments/_payment.html.erb +0 -18
  164. data/db/migrate/20131118041203_add_tax_total_to_spree_orders.rb +0 -5
  165. data/db/migrate/20131118043021_add_order_id_to_spree_adjustments.rb +0 -6
  166. data/db/migrate/20131118074808_add_included_to_spree_adjustments.rb +0 -5
  167. data/db/migrate/20140415041315_add_user_id_created_by_id_index_to_order.rb +0 -5
  168. data/lib/spree/core/gateway_error.rb +0 -5
  169. data/lib/spree/core/preference_rescue.rb +0 -25
  170. data/lib/spree/core/s3_support.rb +0 -25
  171. data/lib/spree/promo/coupon_applicator.rb +0 -71
  172. data/lib/spree/testing_support/factories/activator_factory.rb +0 -8
@@ -10,7 +10,7 @@ module Spree
10
10
  quantity = line_item.quantity
11
11
  end
12
12
 
13
- quantifier = Stock::Quantifier.new(line_item.variant)
13
+ quantifier = Stock::Quantifier.new(line_item.variant_id)
14
14
 
15
15
  unless quantifier.can_supply? quantity
16
16
  variant = line_item.variant
@@ -29,7 +29,19 @@ module Spree
29
29
  def calculate_shipping_rates(package)
30
30
  shipping_methods(package).map do |shipping_method|
31
31
  cost = shipping_method.calculator.compute(package)
32
- shipping_method.shipping_rates.new(cost: cost) if cost
32
+ tax_category = shipping_method.tax_category
33
+ if tax_category
34
+ tax_rate = tax_category.tax_rates.detect do |rate|
35
+ rate.zone == package.order.tax_zone
36
+ end
37
+ end
38
+
39
+ if cost
40
+ rate = shipping_method.shipping_rates.new(cost: cost)
41
+ rate.tax_rate = tax_rate if tax_rate
42
+ end
43
+
44
+ rate
33
45
  end.compact
34
46
  end
35
47
 
@@ -1,7 +1,7 @@
1
1
  module Spree
2
2
  module Stock
3
3
  class Package
4
- ContentItem = Struct.new(:variant, :quantity, :state)
4
+ ContentItem = Struct.new(:line_item, :variant, :quantity, :state)
5
5
 
6
6
  attr_reader :stock_location, :order, :contents
7
7
  attr_accessor :shipping_rates
@@ -13,8 +13,8 @@ module Spree
13
13
  @shipping_rates = Array.new
14
14
  end
15
15
 
16
- def add(variant, quantity, state=:on_hand)
17
- contents << ContentItem.new(variant, quantity, state)
16
+ def add(line_item, quantity, state = :on_hand, variant = nil)
17
+ contents << ContentItem.new(line_item, variant || line_item.variant, quantity, state)
18
18
  end
19
19
 
20
20
  def weight
@@ -29,10 +29,13 @@ module Spree
29
29
  contents.select { |item| item.state == :backordered }
30
30
  end
31
31
 
32
- def find_item(variant, state=:on_hand)
32
+ # Consider extensions and applications might create a inventory unit
33
+ # where the variant and the line_item might not refer to the same product
34
+ def find_item(variant, state = :on_hand, line_item = nil)
33
35
  contents.select do |item|
34
36
  item.variant == variant &&
35
- item.state == state
37
+ item.state == state &&
38
+ (line_item.nil? || line_item == item.line_item)
36
39
  end.first
37
40
  end
38
41
 
@@ -55,7 +58,7 @@ module Spree
55
58
  flat = []
56
59
  contents.each do |item|
57
60
  item.quantity.times do
58
- flat << ContentItem.new(item.variant, 1, item.state)
61
+ flat << ContentItem.new(item.line_item, item.variant, 1, item.state)
59
62
  end
60
63
  end
61
64
  flat
@@ -68,7 +71,7 @@ module Spree
68
71
  if current_item
69
72
  current_item.quantity += 1
70
73
  else
71
- add(item.variant, item.quantity, item.state)
74
+ add(item.line_item, item.quantity, item.state)
72
75
  end
73
76
  end
74
77
  end
@@ -105,6 +108,7 @@ module Spree
105
108
  unit.pending = true
106
109
  unit.order = order
107
110
  unit.variant = item.variant
111
+ unit.line_item = item.line_item
108
112
  unit.state = item.state.to_s
109
113
  end
110
114
  end
@@ -24,10 +24,10 @@ module Spree
24
24
  next unless stock_location.stock_item(line_item.variant)
25
25
 
26
26
  on_hand, backordered = stock_location.fill_status(line_item.variant, line_item.quantity)
27
- package.add line_item.variant, on_hand, :on_hand if on_hand > 0
28
- package.add line_item.variant, backordered, :backordered if backordered > 0
27
+ package.add line_item, on_hand, :on_hand if on_hand > 0
28
+ package.add line_item, backordered, :backordered if backordered > 0
29
29
  else
30
- package.add line_item.variant, line_item.quantity, :on_hand
30
+ package.add line_item, line_item.quantity, :on_hand
31
31
  end
32
32
  end
33
33
  package
@@ -4,7 +4,7 @@ module Spree
4
4
  attr_reader :stock_items
5
5
 
6
6
  def initialize(variant)
7
- @variant = variant
7
+ @variant = resolve_variant_id(variant)
8
8
  @stock_items = Spree::StockItem.joins(:stock_location).where(:variant_id => @variant, Spree::StockLocation.table_name =>{ :active => true})
9
9
  end
10
10
 
@@ -24,6 +24,14 @@ module Spree
24
24
  total_on_hand >= required || backorderable?
25
25
  end
26
26
 
27
+ private
28
+
29
+ # return variant when passed either variant object or variant id
30
+ def resolve_variant_id(variant)
31
+ variant = Spree::Variant.find_by_id(variant) unless variant.respond_to?(:should_track_inventory?)
32
+ variant
33
+ end
34
+
27
35
  end
28
36
  end
29
37
  end
@@ -3,14 +3,17 @@ module Spree
3
3
  acts_as_paranoid
4
4
 
5
5
  belongs_to :stock_location, class_name: 'Spree::StockLocation'
6
- belongs_to :variant, class_name: 'Spree::Variant', touch: true
7
- has_many :stock_movements
6
+ belongs_to :variant, class_name: 'Spree::Variant', inverse_of: :stock_items
7
+ has_many :stock_movements, inverse_of: :stock_item
8
8
 
9
9
  validates_presence_of :stock_location, :variant
10
10
  validates_uniqueness_of :variant_id, scope: [:stock_location_id, :deleted_at]
11
11
 
12
12
  delegate :weight, :should_track_inventory?, to: :variant
13
13
 
14
+ after_save :conditional_variant_touch
15
+ after_touch { variant.touch }
16
+
14
17
  def backordered_inventory_units
15
18
  Spree::InventoryUnit.backordered_for_stock_item(self)
16
19
  end
@@ -44,10 +47,6 @@ module Spree
44
47
  self.in_stock? || self.backorderable?
45
48
  end
46
49
 
47
- def variant
48
- Spree::Variant.unscoped { super }
49
- end
50
-
51
50
  private
52
51
  def count_on_hand=(value)
53
52
  write_attribute(:count_on_hand, value)
@@ -63,5 +62,11 @@ module Spree
63
62
  end
64
63
  end
65
64
  end
65
+
66
+ def conditional_variant_touch
67
+ if !Spree::Config.binary_inventory_cache || (count_on_hand_changed? && count_on_hand_change.any?(&:zero?))
68
+ variant.touch
69
+ end
70
+ end
66
71
  end
67
72
  end
@@ -1,9 +1,8 @@
1
1
  module Spree
2
2
  class StockMovement < ActiveRecord::Base
3
- belongs_to :stock_item, class_name: 'Spree::StockItem'
3
+ belongs_to :stock_item, class_name: 'Spree::StockItem', inverse_of: :stock_movements
4
4
  belongs_to :originator, polymorphic: true
5
5
 
6
-
7
6
  after_create :update_stock_item_quantity
8
7
 
9
8
  validates :stock_item, presence: true
@@ -11,7 +11,12 @@ module Spree
11
11
  #set existing default tax category to false if this one has been marked as default
12
12
 
13
13
  if is_default && tax_category = self.class.where(is_default: true).first
14
- tax_category.update_column(:is_default, false) unless tax_category == self
14
+ unless tax_category == self
15
+ tax_category.update_columns(
16
+ is_default: false,
17
+ updated_at: Time.now,
18
+ )
19
+ end
15
20
  end
16
21
  end
17
22
  end
@@ -15,6 +15,8 @@ module Spree
15
15
  belongs_to :zone, class_name: "Spree::Zone"
16
16
  belongs_to :tax_category, class_name: "Spree::TaxCategory"
17
17
 
18
+ has_many :adjustments, as: :source, dependent: :destroy
19
+
18
20
  validates :amount, presence: true, numericality: true
19
21
  validates :tax_category_id, presence: true
20
22
  validates_with DefaultTaxZoneValidator
@@ -23,20 +25,40 @@ module Spree
23
25
 
24
26
  # Gets the array of TaxRates appropriate for the specified order
25
27
  def self.match(order)
26
- order_zone = order.tax_zone
27
- return [] unless order_zone
28
- includes(zone: { zone_members: :zoneable }).load.select do |rate|
28
+ return [] unless order.tax_zone
29
+ all.select do |rate|
29
30
  (!rate.included_in_price && (rate.zone == order.tax_zone || rate.zone.contains?(order.tax_zone) || (order.tax_address.nil? && rate.zone.default_tax))) ||
30
31
  rate.included_in_price
31
32
  end
32
33
  end
33
34
 
34
- def self.adjust(order)
35
- order.adjustments.tax.destroy_all
36
- order.line_item_adjustments.where(originator_type: 'Spree::TaxRate').destroy_all
35
+ # Pre-tax amounts must be stored so that we can calculate
36
+ # correct rate amounts in the future. For example:
37
+ # https://github.com/spree/spree/issues/4318#issuecomment-34723428
38
+ def self.store_pre_tax_amount(item, rates)
39
+ if rates.any? { |r| r.included_in_price }
40
+ case item
41
+ when Spree::LineItem
42
+ item_amount = item.discounted_amount
43
+ when Spree::Shipment
44
+ item_amount = item.discounted_cost
45
+ end
46
+ pre_tax_amount = item_amount / (1 + rates.map(&:amount).sum)
47
+ item.update_column(:pre_tax_amount, pre_tax_amount)
48
+ end
49
+ end
37
50
 
38
- self.match(order).each do |rate|
39
- rate.adjust(order)
51
+ def self.adjust(order, items)
52
+ rates = self.match(order)
53
+ tax_categories = rates.map(&:tax_category)
54
+ relevant_items = items.select { |item| tax_categories.include?(item.tax_category) }
55
+ relevant_items.each do |item|
56
+ item.adjustments.tax.delete_all
57
+ relevant_rates = rates.select { |rate| rate.tax_category == item.tax_category }
58
+ store_pre_tax_amount(item, relevant_rates)
59
+ relevant_rates.each do |rate|
60
+ rate.adjust(order, item)
61
+ end
40
62
  end
41
63
  end
42
64
 
@@ -54,51 +76,37 @@ module Spree
54
76
  end
55
77
 
56
78
  # Creates necessary tax adjustments for the order.
57
- def adjust(order)
58
- # (rate.included_in_price && !order.tax_address.nil? && !rate.zone.contains?(order.tax_zone) && rate.zone.default_tax)
59
- label = create_label
79
+ def adjust(order, item)
80
+ amount = calculator.compute(item)
81
+ return if amount == 0
82
+
83
+ included = included_in_price &&
84
+ Zone.default_tax.contains?(item.order.tax_zone)
85
+
86
+ if amount < 0
87
+ label = Spree.t(:refund) + ' ' + create_label
88
+ end
89
+
90
+ self.adjustments.create!({
91
+ :adjustable => item,
92
+ :amount => amount,
93
+ :order => order,
94
+ :label => label || create_label,
95
+ :included => included
96
+ })
97
+ end
98
+
99
+ # This method is used by Adjustment#update to recalculate the cost.
100
+ def compute_amount(item)
60
101
  if included_in_price
61
- if Zone.default_tax.contains? order.tax_zone
62
- order.line_items.each do |line_item|
63
- amount = calculator.compute(line_item)
64
- unless amount == 0
65
- line_item.adjustments.create(
66
- order: order,
67
- amount: amount,
68
- source: line_item,
69
- originator: self,
70
- label: label,
71
- mandatory: false,
72
- state: "closed",
73
- included: true
74
- )
75
- end
76
- end
102
+ if Zone.default_tax.contains? item.order.tax_zone
103
+ calculator.compute(item)
77
104
  else
78
- amount = -1 * calculator.compute(order)
79
- label = Spree.t(:refund) + label
80
-
81
- order.adjustments.create(
82
- order: order,
83
- amount: amount,
84
- source: order,
85
- originator: self,
86
- state: "closed",
87
- label: label
88
- )
105
+ # In this case, it's a refund.
106
+ calculator.compute(item) * - 1
89
107
  end
90
108
  else
91
- amount = calculator.compute(order)
92
- unless amount == 0
93
- order.adjustments.create(
94
- order: order,
95
- amount: amount,
96
- source: order,
97
- originator: self,
98
- state: "closed",
99
- label: label
100
- )
101
- end
109
+ calculator.compute(item)
102
110
  end
103
111
  end
104
112
 
@@ -2,14 +2,16 @@ module Spree
2
2
  class Taxon < ActiveRecord::Base
3
3
  acts_as_nested_set dependent: :destroy
4
4
 
5
- belongs_to :taxonomy, class_name: 'Spree::Taxonomy', :touch => true
6
- has_many :classifications, dependent: :delete_all
5
+ belongs_to :taxonomy, class_name: 'Spree::Taxonomy', touch: true, inverse_of: :taxons
6
+ has_many :classifications, -> { order(:position) }, dependent: :delete_all, inverse_of: :taxon
7
7
  has_many :products, through: :classifications
8
8
 
9
9
  before_create :set_permalink
10
10
 
11
11
  validates :name, presence: true
12
12
 
13
+ after_touch :touch_parent
14
+
13
15
  has_attached_file :icon,
14
16
  styles: { mini: '32x32>', normal: '128x128>' },
15
17
  default_style: :mini,
@@ -17,9 +19,6 @@ module Spree
17
19
  path: ':rails_root/public/spree/taxons/:id/:style/:basename.:extension',
18
20
  default_url: '/assets/default_taxon.png'
19
21
 
20
- include Spree::Core::S3Support
21
- supports_s3 :icon
22
-
23
22
  include Spree::Core::ProductFilters # for detailed defs of filters
24
23
 
25
24
  # indicate which filters should be used for a taxon
@@ -78,5 +77,11 @@ module Spree
78
77
  def child_index=(idx)
79
78
  move_to_child_with_index(parent, idx.to_i) unless self.new_record?
80
79
  end
80
+
81
+ private
82
+
83
+ def touch_parent
84
+ parent.touch if parent
85
+ end
81
86
  end
82
87
  end
@@ -2,7 +2,7 @@ module Spree
2
2
  class Taxonomy < ActiveRecord::Base
3
3
  validates :name, presence: true
4
4
 
5
- has_many :taxons
5
+ has_many :taxons, inverse_of: :taxonomy
6
6
  has_one :root, -> { where parent_id: nil }, class_name: "Spree::Taxon", dependent: :destroy
7
7
 
8
8
  after_save :set_name
@@ -12,7 +12,10 @@ module Spree
12
12
  private
13
13
  def set_name
14
14
  if root
15
- root.update_column(:name, name)
15
+ root.update_columns(
16
+ name: name,
17
+ updated_at: Time.now,
18
+ )
16
19
  else
17
20
  self.root = Taxon.create!(taxonomy_id: id, name: name)
18
21
  end
@@ -2,20 +2,21 @@ module Spree
2
2
  class Variant < ActiveRecord::Base
3
3
  acts_as_paranoid
4
4
 
5
- belongs_to :product, touch: true, class_name: 'Spree::Product'
5
+ belongs_to :product, touch: true, class_name: 'Spree::Product', inverse_of: :variants
6
+ belongs_to :tax_category, class_name: 'Spree::TaxCategory'
6
7
 
7
- delegate_belongs_to :product, :name, :description, :permalink, :available_on,
8
- :tax_category_id, :shipping_category_id, :meta_description,
9
- :meta_keywords, :tax_category, :shipping_category
8
+ delegate_belongs_to :product, :name, :description, :slug, :available_on,
9
+ :shipping_category_id, :meta_description, :meta_keywords,
10
+ :shipping_category
10
11
 
11
12
  has_many :inventory_units
12
- has_many :line_items
13
+ has_many :line_items, inverse_of: :variant
13
14
 
14
- has_many :stock_items, dependent: :destroy
15
+ has_many :stock_items, dependent: :destroy, inverse_of: :variant
15
16
  has_many :stock_locations, through: :stock_items
16
17
  has_many :stock_movements
17
18
 
18
- has_and_belongs_to_many :option_values, join_table: :spree_option_values_variants, class_name: "Spree::OptionValue"
19
+ has_and_belongs_to_many :option_values, join_table: :spree_option_values_variants
19
20
  has_many :images, -> { order(:position) }, as: :viewable, dependent: :destroy, class_name: "Spree::Image"
20
21
 
21
22
  has_one :default_price,
@@ -27,7 +28,8 @@ module Spree
27
28
 
28
29
  has_many :prices,
29
30
  class_name: 'Spree::Price',
30
- dependent: :destroy
31
+ dependent: :destroy,
32
+ inverse_of: :variant
31
33
 
32
34
  validate :check_price
33
35
  validates :price, numericality: { greater_than_or_equal_to: 0 }
@@ -39,6 +41,8 @@ module Spree
39
41
  after_create :create_stock_items
40
42
  after_create :set_position
41
43
 
44
+ after_touch :clear_in_stock_cache
45
+
42
46
  # default variant scope only lists non-deleted variants
43
47
  scope :deleted, lambda { where.not(deleted_at: nil) }
44
48
 
@@ -46,6 +50,14 @@ module Spree
46
50
  joins(:prices).where(deleted_at: nil).where('spree_prices.currency' => currency || Spree::Config[:currency]).where('spree_prices.amount IS NOT NULL')
47
51
  end
48
52
 
53
+ def tax_category
54
+ if self[:tax_category_id].nil?
55
+ product.tax_category
56
+ else
57
+ TaxCategory.find(self[:tax_category_id])
58
+ end
59
+ end
60
+
49
61
  def cost_price=(price)
50
62
  self[:cost_price] = parse_price(price) if price.present?
51
63
  end
@@ -75,7 +87,7 @@ module Spree
75
87
  # allows extensions to override deleted? if they want to provide
76
88
  # their own definition.
77
89
  def deleted?
78
- !!deleted_at
90
+ deleted_at
79
91
  end
80
92
 
81
93
  # Product may be created with deleted_at already set,
@@ -149,16 +161,13 @@ module Spree
149
161
  "#{sku} #{options_text}".strip
150
162
  end
151
163
 
152
- def in_stock?(quantity=:argument_here_is_deprecated)
153
- if quantity == :argument_here_is_deprecated
154
- can_stock?(1)
155
- else
156
- puts %q{[DEPRECATION] In Spree 2.2, Variant#in_stock? will no longer take a quantity. Use Variant#can_supply? instead.}
157
- can_stock?(quantity)
164
+ def in_stock?
165
+ Rails.cache.fetch(in_stock_cache_key) do
166
+ total_on_hand > 0
158
167
  end
159
168
  end
160
169
 
161
- def can_stock?(quantity=1)
170
+ def can_supply?(quantity=1)
162
171
  Spree::Stock::Quantifier.new(self).can_supply?(quantity)
163
172
  end
164
173
 
@@ -214,6 +223,14 @@ module Spree
214
223
  def set_position
215
224
  self.update_column(:position, product.variants.maximum(:position).to_i + 1)
216
225
  end
226
+
227
+ def in_stock_cache_key
228
+ "variant-#{id}-in_stock"
229
+ end
230
+
231
+ def clear_in_stock_cache
232
+ Rails.cache.delete(in_stock_cache_key)
233
+ end
217
234
  end
218
235
  end
219
236