spree_core 2.1.12 → 2.2.0

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