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
@@ -0,0 +1,24 @@
1
+ module Spree
2
+ module PromotionHandler
3
+ class Page
4
+ attr_reader :order, :path
5
+
6
+ def initialize(order, path)
7
+ @order = order
8
+ @path = path.gsub(/\A\//, '')
9
+ end
10
+
11
+ def activate
12
+ if promotion && promotion.eligible?(order)
13
+ promotion.activate(:order => order)
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def promotion
20
+ @promotion ||= Promotion.active.find_by(:path => path)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,23 +1,31 @@
1
1
  # Base class for all promotion rules
2
2
  module Spree
3
3
  class PromotionRule < ActiveRecord::Base
4
- belongs_to :promotion, foreign_key: 'activator_id', class_name: 'Spree::Promotion'
4
+ belongs_to :promotion, class_name: 'Spree::Promotion', inverse_of: :promotion_rules
5
5
 
6
6
  scope :of_type, ->(t) { where(type: t) }
7
7
 
8
8
  validate :promotion, presence: true
9
- validate :unique_per_activator, on: :create
9
+ validate :unique_per_promotion, on: :create
10
10
 
11
- def eligible?(order, options = {})
12
- raise 'eligible? should be implemented in a sub-class of Promotion::PromotionRule'
11
+ def self.for(promotable)
12
+ all.select { |rule| rule.applicable?(promotable) }
13
+ end
14
+
15
+ def applicable?(promotable)
16
+ raise 'applicable? should be implemented in a sub-class of Spree::PromotionRule'
17
+ end
18
+
19
+ def eligible?(promotable, options = {})
20
+ raise 'eligible? should be implemented in a sub-class of Spree::PromotionRule'
13
21
  end
14
22
 
15
23
  private
16
- def unique_per_activator
17
- if Spree::PromotionRule.exists?(activator_id: activator_id, type: self.class.name)
24
+ def unique_per_promotion
25
+ if Spree::PromotionRule.exists?(promotion_id: promotion_id, type: self.class.name)
18
26
  errors[:base] << "Promotion already contains this rule type"
19
27
  end
20
28
  end
21
-
29
+
22
30
  end
23
31
  end
@@ -2,7 +2,7 @@ module Spree
2
2
  class Property < ActiveRecord::Base
3
3
  has_and_belongs_to_many :prototypes, join_table: 'spree_properties_prototypes'
4
4
 
5
- has_many :product_properties, dependent: :delete_all
5
+ has_many :product_properties, dependent: :delete_all, inverse_of: :property
6
6
  has_many :products, through: :product_properties
7
7
 
8
8
  validates :name, :presentation, presence: true
@@ -62,6 +62,11 @@ 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
66
+ def compute_amount(*args)
67
+ amount.abs * -1
68
+ end
69
+
65
70
  private
66
71
 
67
72
  def must_have_shipped_units
@@ -82,10 +87,11 @@ module Spree
82
87
  Spree::StockMovement.create!(stock_item_id: stock_item.id, quantity: 1)
83
88
  end
84
89
 
85
- credit = Adjustment.new(amount: amount.abs * -1, label: Spree.t(:rma_credit))
90
+ credit = Adjustment.new(amount: compute_amount, label: Spree.t(:rma_credit))
86
91
  credit.source = self
87
92
  credit.adjustable = order
88
93
  credit.save
94
+ order.update!
89
95
 
90
96
  order.return if inventory_units.all?(&:returned?)
91
97
  end
@@ -2,17 +2,19 @@ require 'ostruct'
2
2
 
3
3
  module Spree
4
4
  class Shipment < ActiveRecord::Base
5
- belongs_to :order, class_name: 'Spree::Order', touch: true
6
- belongs_to :address, class_name: 'Spree::Address'
5
+ belongs_to :order, class_name: 'Spree::Order', touch: true, inverse_of: :shipments
6
+ belongs_to :address, class_name: 'Spree::Address', inverse_of: :shipments
7
7
  belongs_to :stock_location, class_name: 'Spree::StockLocation'
8
8
 
9
9
  has_many :shipping_rates, dependent: :delete_all
10
10
  has_many :shipping_methods, through: :shipping_rates
11
11
  has_many :state_changes, as: :stateful
12
- has_many :inventory_units, dependent: :delete_all
13
- has_one :adjustment, as: :source, dependent: :destroy
12
+ has_many :inventory_units, dependent: :delete_all, inverse_of: :shipment
13
+ has_many :adjustments, as: :adjustable, dependent: :delete_all
14
14
 
15
- after_save :ensure_correct_adjustment, :update_order
15
+ after_save :update_adjustments
16
+
17
+ before_validation :set_cost_zero_when_nil
16
18
 
17
19
  attr_accessor :special_instructions
18
20
 
@@ -60,6 +62,14 @@ module Spree
60
62
  transition from: :canceled, to: :pending
61
63
  end
62
64
  after_transition from: :canceled, to: [:pending, :ready], do: :after_resume
65
+
66
+ after_transition do |shipment, transition|
67
+ shipment.state_changes.create!(
68
+ previous_state: transition.from,
69
+ next_state: transition.to,
70
+ name: 'shipment',
71
+ )
72
+ end
63
73
  end
64
74
 
65
75
  def to_param
@@ -70,6 +80,10 @@ module Spree
70
80
  inventory_units.any? { |inventory_unit| inventory_unit.backordered? }
71
81
  end
72
82
 
83
+ def ready_or_pending?
84
+ self.ready? || self.pending?
85
+ end
86
+
73
87
  def shipped=(value)
74
88
  return unless value == '1' && shipped_at.nil?
75
89
  self.shipped_at = Time.now
@@ -97,6 +111,10 @@ module Spree
97
111
  self.save!
98
112
  end
99
113
 
114
+ def tax_category
115
+ selected_shipping_rate.try(:tax_rate).try(:tax_category)
116
+ end
117
+
100
118
  def refresh_rates
101
119
  return shipping_rates if shipped?
102
120
  return [] unless can_get_rates?
@@ -120,54 +138,59 @@ module Spree
120
138
  order ? order.currency : Spree::Config[:currency]
121
139
  end
122
140
 
123
- # The adjustment amount associated with this shipment (if any.) Returns only the first adjustment to match
124
- # the shipment but there should never really be more than one.
125
- def cost
126
- adjustment ? adjustment.amount : 0
127
- end
128
-
129
- alias_method :amount, :cost
130
-
131
141
  def display_cost
132
142
  Spree::Money.new(cost, { currency: currency })
133
143
  end
134
-
135
- alias_method :display_amount, :display_cost
144
+ alias display_amount display_cost
136
145
 
137
146
  def item_cost
138
147
  line_items.map(&:amount).sum
139
148
  end
140
149
 
141
- def display_item_cost
142
- Spree::Money.new(item_cost, { currency: currency })
150
+ def discounted_cost
151
+ cost + promo_total
152
+ end
153
+ alias discounted_amount discounted_cost
154
+
155
+ # Only one of either included_tax_total or additional_tax_total is set
156
+ # This method returns the total of the two. Saves having to check if
157
+ # tax is included or additional.
158
+ def tax_total
159
+ included_tax_total + additional_tax_total
160
+ end
161
+
162
+ def final_price
163
+ discounted_cost + tax_total
143
164
  end
144
165
 
145
- def total_cost
146
- cost + item_cost
166
+ def display_discounted_cost
167
+ Spree::Money.new(discounted_cost, { currency: currency })
147
168
  end
148
169
 
149
- def display_total_cost
150
- Spree::Money.new(total_cost, { currency: currency })
170
+ def display_item_cost
171
+ Spree::Money.new(item_cost, { currency: currency })
151
172
  end
152
173
 
153
174
  def editable_by?(user)
154
175
  !shipped?
155
176
  end
156
177
 
178
+ ManifestItem = Struct.new(:line_item, :variant, :quantity, :states)
179
+
157
180
  def manifest
158
181
  inventory_units.group_by(&:variant).map do |variant, units|
159
- states = {}
160
- units.group_by(&:state).each { |state, iu| states[state] = iu.count }
161
- OpenStruct.new(variant: variant, quantity: units.length, states: states)
162
- end
182
+ units.group_by(&:line_item).map do |line_item, units|
183
+
184
+ states = {}
185
+ units.group_by(&:state).each { |state, iu| states[state] = iu.count }
186
+
187
+ ManifestItem.new(line_item, variant, units.length, states)
188
+ end
189
+ end.flatten
163
190
  end
164
191
 
165
192
  def line_items
166
- if order.complete? and Spree::Config.track_inventory_levels
167
- order.line_items.select { |li| !li.should_track_inventory? || inventory_units.pluck(:variant_id).include?(li.variant_id) }
168
- else
169
- order.line_items
170
- end
193
+ inventory_units.includes(:line_item).map(&:line_item).uniq
171
194
  end
172
195
 
173
196
  def finalize!
@@ -189,7 +212,10 @@ module Spree
189
212
  def update!(order)
190
213
  old_state = state
191
214
  new_state = determine_state(order)
192
- update_column :state, new_state
215
+ update_columns(
216
+ state: new_state,
217
+ updated_at: Time.now,
218
+ )
193
219
  after_ship if new_state == 'shipped' and old_state != 'shipped'
194
220
  end
195
221
 
@@ -215,19 +241,45 @@ module Spree
215
241
  end
216
242
 
217
243
  def inventory_units_for(variant)
218
- inventory_units.group_by(&:variant_id)[variant.id] || []
244
+ inventory_units.where(variant_id: variant.id)
245
+ end
246
+
247
+ def inventory_units_for_item(line_item, variant = nil)
248
+ inventory_units.where(line_item_id: line_item.id, variant_id: line_item.variant.id || variant.id)
219
249
  end
220
250
 
221
251
  def to_package
222
252
  package = Stock::Package.new(stock_location, order)
223
- inventory_units.includes(:variant).each do |inventory_unit|
224
- package.add inventory_unit.variant, 1, inventory_unit.state_name
253
+ grouped_inventory_units = inventory_units.includes(:line_item).group_by do |iu|
254
+ [iu.line_item, iu.state_name]
255
+ end
256
+
257
+ grouped_inventory_units.each do |(line_item, state_name), inventory_units|
258
+ package.add line_item, inventory_units.count, state_name
225
259
  end
226
260
  package
227
261
  end
228
262
 
229
- def set_up_inventory(state, variant, order)
230
- self.inventory_units.create(variant_id: variant.id, state: state, order_id: order.id)
263
+ def set_up_inventory(state, variant, order, line_item)
264
+ self.inventory_units.create(
265
+ state: state,
266
+ variant_id: variant.id,
267
+ order_id: order.id,
268
+ line_item_id: line_item.id
269
+ )
270
+ end
271
+
272
+ def persist_cost
273
+ self.cost = selected_shipping_rate.cost
274
+ update_amounts
275
+ end
276
+
277
+ def update_amounts
278
+ self.update_columns(
279
+ cost: selected_shipping_rate.cost,
280
+ adjustment_total: adjustments.map(&:update!).compact.sum,
281
+ updated_at: Time.now,
282
+ )
231
283
  end
232
284
 
233
285
  private
@@ -250,32 +302,44 @@ module Spree
250
302
  "#{Spree.t(:shipping)} (#{shipping_method.name})"
251
303
  end
252
304
 
305
+ def validate_shipping_method
306
+ unless shipping_method.nil?
307
+ errors.add :shipping_method, Spree.t(:is_not_available_to_shipment_address) unless shipping_method.include?(address)
308
+ end
309
+ end
310
+
253
311
  def after_ship
254
312
  inventory_units.each &:ship!
255
- adjustment.finalize!
256
313
  send_shipped_email
257
314
  touch :shipped_at
315
+ update_order_shipment_state
316
+ end
317
+
318
+ def update_order_shipment_state
319
+ new_state = OrderUpdater.new(order).update_shipment_state
320
+ order.update_columns(
321
+ shipment_state: new_state,
322
+ updated_at: Time.now,
323
+ )
258
324
  end
259
325
 
260
326
  def send_shipped_email
261
327
  ShipmentMailer.shipped_email(self.id).deliver
262
328
  end
263
329
 
264
- def ensure_correct_adjustment
265
- if adjustment
266
- adjustment.originator = shipping_method
267
- adjustment.label = shipping_method.adjustment_label
268
- adjustment.amount = selected_shipping_rate.cost if adjustment.open?
269
- adjustment.save!
270
- adjustment.reload
271
- elsif selected_shipping_rate_id
272
- shipping_method.create_adjustment shipping_method.adjustment_label, order, self, true, "open"
273
- reload #ensure adjustment is present on later saves
330
+ def set_cost_zero_when_nil
331
+ self.cost = 0 unless self.cost
332
+ end
333
+
334
+
335
+ def update_adjustments
336
+ if cost_changed? && state != 'shipped'
337
+ recalculate_adjustments
274
338
  end
275
339
  end
276
340
 
277
- def update_order
278
- order.update!
341
+ def recalculate_adjustments
342
+ Spree::ItemAdjustments.new(self).update
279
343
  end
280
344
 
281
345
  def can_get_rates?
@@ -1,13 +1,12 @@
1
1
  module Spree
2
2
  class ShippingCalculator < Calculator
3
- def compute(package_or_shipment)
4
- package = package_or_shipment.respond_to?(:to_package) ?
5
- package_or_shipment.to_package : package_or_shipment
6
- compute_package package
3
+
4
+ def compute_shipment(shipment)
5
+ raise NotImplementedError, "Please implement 'compute_shipment(shipment)' in your calculator: #{self.class.name}"
7
6
  end
8
7
 
9
8
  def compute_package(package)
10
- raise(NotImplementedError, 'please use concrete calculator')
9
+ raise NotImplementedError, "Please implement 'compute_package(package)' in your calculator: #{self.class.name}"
11
10
  end
12
11
 
13
12
  def available?(package)
@@ -1,8 +1,8 @@
1
1
  module Spree
2
2
  class ShippingCategory < ActiveRecord::Base
3
3
  validates :name, presence: true
4
- has_many :products
4
+ has_many :products, inverse_of: :shipping_category
5
5
  has_many :shipping_method_categories
6
6
  has_many :shipping_methods, through: :shipping_method_categories
7
7
  end
8
- end
8
+ end
@@ -1,28 +1,26 @@
1
1
  module Spree
2
2
  class ShippingMethod < ActiveRecord::Base
3
- acts_as_paranoid
4
3
  include Spree::Core::CalculatedAdjustments
5
4
  DISPLAY = [:both, :front_end, :back_end]
6
5
 
7
6
  default_scope -> { where(deleted_at: nil) }
8
7
 
8
+ has_many :adjustments, as: :source
9
+ has_many :shipments
9
10
  has_many :shipping_method_categories, :dependent => :destroy
10
11
  has_many :shipping_categories, through: :shipping_method_categories
11
12
  has_many :shipping_rates, inverse_of: :shipping_method
12
- has_many :shipments, :through => :shipping_rates
13
13
 
14
14
  has_and_belongs_to_many :zones, :join_table => 'spree_shipping_methods_zones',
15
15
  :class_name => 'Spree::Zone',
16
16
  :foreign_key => 'shipping_method_id'
17
17
 
18
+ belongs_to :tax_category, :class_name => 'Spree::TaxCategory'
19
+
18
20
  validates :name, presence: true
19
21
 
20
22
  validate :at_least_one_shipping_category
21
23
 
22
- def adjustment_label
23
- Spree.t(:shipping)
24
- end
25
-
26
24
  def include?(address)
27
25
  return false unless address
28
26
  zones.any? do |zone|
@@ -44,7 +42,15 @@ module Spree
44
42
  self.display_on != "back_end"
45
43
  end
46
44
 
45
+ def tax_category
46
+ Spree::TaxCategory.unscoped { super }
47
+ end
48
+
47
49
  private
50
+ def compute_amount(calculable)
51
+ self.calculator.compute(calculable)
52
+ end
53
+
48
54
  def at_least_one_shipping_category
49
55
  if self.shipping_categories.empty?
50
56
  self.errors[:base] << "You need to select at least one shipping category"
@@ -2,24 +2,44 @@ module Spree
2
2
  class ShippingRate < ActiveRecord::Base
3
3
  belongs_to :shipment, class_name: 'Spree::Shipment'
4
4
  belongs_to :shipping_method, class_name: 'Spree::ShippingMethod', inverse_of: :shipping_rates
5
+ belongs_to :tax_rate, class_name: 'Spree::TaxRate'
6
+
7
+ scope :with_shipping_method,
8
+ -> { includes(:shipping_method).
9
+ references(:shipping_method).
10
+ order("cost ASC") }
5
11
 
6
12
  delegate :order, :currency, to: :shipment
7
13
  delegate :name, to: :shipping_method
8
14
 
9
- def display_price
10
- if Spree::Config[:shipment_inc_vat]
11
- price = (1 + Spree::TaxRate.default) * cost
12
- else
13
- price = cost
14
- end
15
+ def display_base_price
16
+ Spree::Money.new(cost, currency: currency)
17
+ end
15
18
 
16
- Spree::Money.new(price, { currency: currency })
19
+ def display_tax_amount
20
+ Spree::Money.new(tax_rate.calculator.compute_shipping_rate(self), currency: currency)
17
21
  end
18
22
 
23
+ def display_price
24
+ price = display_base_price.to_s
25
+ if tax_rate
26
+ amount = "#{display_tax_amount} #{tax_rate.name}"
27
+ if tax_rate.included_in_price?
28
+ price += " (incl. #{amount})"
29
+ else
30
+ price += " (+ #{amount})"
31
+ end
32
+ end
33
+ price
34
+ end
19
35
  alias_method :display_cost, :display_price
20
36
 
21
37
  def shipping_method
22
38
  Spree::ShippingMethod.unscoped { super }
23
39
  end
40
+
41
+ def tax_rate
42
+ Spree::TaxRate.unscoped { super }
43
+ end
24
44
  end
25
45
  end