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
@@ -84,11 +84,22 @@ module Spree
84
84
  if states[:delivery]
85
85
  before_transition :to => :delivery, :do => :create_proposed_shipments
86
86
  before_transition :to => :delivery, :do => :ensure_available_shipping_rates
87
+ before_transition :from => :delivery, :do => :apply_free_shipping_promotions
88
+ end
89
+
90
+ if states[:payment]
91
+ before_transition :to => :payment, :do => :set_shipments_cost
92
+ before_transition :to => :payment, :do => :create_tax_charge!
87
93
  end
88
94
 
89
95
  after_transition :to => :complete, :do => :finalize!
90
96
  after_transition :to => :resumed, :do => :after_resume
91
97
  after_transition :to => :canceled, :do => :after_cancel
98
+
99
+ after_transition :from => any - :cart, :to => any - [:confirm, :complete] do |order|
100
+ order.update_totals
101
+ order.persist_totals
102
+ end
92
103
  end
93
104
  end
94
105
 
@@ -190,6 +201,43 @@ module Spree
190
201
  return false unless has_checkout_step?(self.state) && has_checkout_step?(state)
191
202
  checkout_step_index(state) > checkout_step_index(self.state)
192
203
  end
204
+
205
+ define_callbacks :updating_from_params, terminator: 'result == false'
206
+
207
+ set_callback :updating_from_params, :before, :update_params_payment_source
208
+
209
+ def update_from_params(params, permitted_params)
210
+ success = false
211
+ @updating_params = params
212
+ run_callbacks :updating_from_params do
213
+ attributes = @updating_params[:order] ? @updating_params[:order].permit(permitted_params) : {}
214
+ success = self.update_attributes(attributes)
215
+ end
216
+ @updating_params = nil
217
+ success
218
+ end
219
+
220
+ private
221
+ # For payment step, filter order parameters to produce the expected nested
222
+ # attributes for a single payment and its source, discarding attributes
223
+ # for payment methods other than the one selected
224
+ def update_params_payment_source
225
+ # respond_to check is necessary due to issue described in #2910
226
+ if has_checkout_step?("payment") && self.payment?
227
+ if @updating_params[:payment_source].present?
228
+ source_params = @updating_params.delete(:payment_source)[@updating_params[:order][:payments_attributes].first[:payment_method_id].underscore]
229
+
230
+ if source_params
231
+ @updating_params[:order][:payments_attributes].first[:source_attributes] = source_params
232
+ end
233
+ end
234
+
235
+ if (@updating_params[:order][:payments_attributes])
236
+ @updating_params[:order][:payments_attributes].first[:amount] = self.total
237
+ end
238
+ end
239
+ end
240
+
193
241
  end
194
242
  end
195
243
  end
@@ -6,62 +6,97 @@ module Spree
6
6
  @order = order
7
7
  end
8
8
 
9
- # Get current line item for variant if exists
10
- # Add variant qty to line_item
11
9
  def add(variant, quantity = 1, currency = nil, shipment = nil)
12
- line_item = order.find_line_item_by_variant(variant)
13
- add_to_line_item(line_item, variant, quantity, currency, shipment)
10
+ line_item = add_to_line_item(variant, quantity, currency, shipment)
11
+ reload_totals
12
+ PromotionHandler::Cart.new(order, line_item).activate
13
+ ItemAdjustments.new(line_item).update
14
+ reload_totals
15
+ line_item
14
16
  end
15
17
 
16
- # Get current line item for variant
17
- # Remove variant qty from line_item
18
18
  def remove(variant, quantity = 1, shipment = nil)
19
- line_item = order.find_line_item_by_variant(variant)
19
+ line_item = remove_from_line_item(variant, quantity, shipment)
20
+ reload_totals
21
+ PromotionHandler::Cart.new(order, line_item).activate
22
+ ItemAdjustments.new(line_item).update
23
+ reload_totals
24
+ line_item
25
+ end
20
26
 
21
- unless line_item
22
- raise ActiveRecord::RecordNotFound, "Line item not found for variant #{variant.sku}"
27
+ def update_cart(params)
28
+ if order.update_attributes(params)
29
+ order.line_items = order.line_items.select {|li| li.quantity > 0 }
30
+ # Update totals, then check if the order is eligible for any cart promotions.
31
+ # If we do not update first, then the item total will be wrong and ItemTotal
32
+ # promotion rules would not be triggered.
33
+ reload_totals
34
+ PromotionHandler::Cart.new(order).activate
35
+ order.ensure_updated_shipments
36
+ reload_totals
37
+ true
38
+ else
39
+ false
23
40
  end
24
-
25
- remove_from_line_item(line_item, variant, quantity, shipment)
26
41
  end
27
42
 
28
43
  private
44
+ def order_updater
45
+ @updater ||= OrderUpdater.new(order)
46
+ end
29
47
 
30
- def add_to_line_item(line_item, variant, quantity, currency=nil, shipment=nil)
31
- if line_item
32
- line_item.target_shipment = shipment
33
- line_item.quantity += quantity.to_i
34
- line_item.currency = currency unless currency.nil?
35
- else
36
- line_item = order.line_items.new(quantity: quantity, variant: variant)
37
- line_item.target_shipment = shipment
38
- if currency
48
+ def reload_totals
49
+ order_updater.update_item_count
50
+ order_updater.update_item_total
51
+ order_updater.update_adjustment_total
52
+ order_updater.persist_totals
53
+ order.reload
54
+ end
55
+
56
+ def add_to_line_item(variant, quantity, currency=nil, shipment=nil)
57
+ line_item = grab_line_item_by_variant(variant)
58
+
59
+ if line_item
60
+ line_item.target_shipment = shipment
61
+ line_item.quantity += quantity.to_i
39
62
  line_item.currency = currency unless currency.nil?
40
- line_item.price = variant.price_in(currency).amount
41
63
  else
42
- line_item.price = variant.price
64
+ line_item = order.line_items.new(quantity: quantity, variant: variant)
65
+ line_item.target_shipment = shipment
66
+ if currency
67
+ line_item.currency = currency
68
+ line_item.price = variant.price_in(currency).amount
69
+ else
70
+ line_item.price = variant.price
71
+ end
43
72
  end
73
+
74
+ line_item.save
75
+ line_item
44
76
  end
45
77
 
46
- line_item.save
47
- order.reload
48
- line_item
49
- end
78
+ def remove_from_line_item(variant, quantity, shipment=nil)
79
+ line_item = grab_line_item_by_variant(variant, true)
80
+ line_item.quantity += -quantity
81
+ line_item.target_shipment= shipment
50
82
 
51
- def remove_from_line_item(line_item, variant, quantity, shipment=nil)
52
- line_item.quantity += -quantity
53
- line_item.target_shipment= shipment
83
+ if line_item.quantity == 0
84
+ line_item.destroy
85
+ else
86
+ line_item.save!
87
+ end
54
88
 
55
- if line_item.quantity == 0
56
- Spree::OrderInventory.new(order).verify(line_item, shipment)
57
- line_item.destroy
58
- else
59
- line_item.save!
89
+ line_item
60
90
  end
61
91
 
62
- order.reload
63
- line_item
64
- end
92
+ def grab_line_item_by_variant(variant, raise_error = false)
93
+ line_item = order.find_line_item_by_variant(variant)
65
94
 
95
+ if !line_item.present? && raise_error
96
+ raise ActiveRecord::RecordNotFound, "Line item not found for variant #{variant.sku}"
97
+ end
98
+
99
+ line_item
100
+ end
66
101
  end
67
102
  end
@@ -1,9 +1,11 @@
1
1
  module Spree
2
2
  class OrderInventory
3
- attr_accessor :order
3
+ attr_accessor :order, :line_item, :variant
4
4
 
5
- def initialize(order)
5
+ def initialize(order, line_item)
6
6
  @order = order
7
+ @line_item = line_item
8
+ @variant = line_item.variant
7
9
  end
8
10
 
9
11
  # Only verify inventory for completed orders (as orders in frontend checkout
@@ -13,98 +15,93 @@ module Spree
13
15
  # In case shipment is passed the stock location should only unstock or
14
16
  # restock items if the order is completed. That is so because stock items
15
17
  # are always unstocked when the order is completed through +shipment.finalize+
16
- def verify(line_item, shipment = nil)
18
+ def verify(shipment = nil)
17
19
  if order.completed? || shipment.present?
18
20
 
19
- variant_units = inventory_units_for(line_item.variant)
21
+ if inventory_units.size < line_item.quantity
22
+ quantity = line_item.quantity - inventory_units.size
20
23
 
21
- if variant_units.size < line_item.quantity
22
- quantity = line_item.quantity - variant_units.size
23
-
24
- shipment = determine_target_shipment(line_item.variant) unless shipment
25
- add_to_shipment(shipment, line_item.variant, quantity)
26
- elsif variant_units.size > line_item.quantity
27
- remove(line_item, variant_units, shipment)
24
+ shipment = determine_target_shipment unless shipment
25
+ add_to_shipment(shipment, quantity)
26
+ elsif inventory_units.size > line_item.quantity
27
+ remove(inventory_units, shipment)
28
28
  end
29
- else
30
- true
31
29
  end
32
30
  end
33
31
 
34
- def inventory_units_for(variant)
35
- units = order.shipments.collect{|s| s.inventory_units.to_a}.flatten
36
- units.group_by(&:variant_id)[variant.id] || []
32
+ def inventory_units
33
+ line_item.inventory_units
37
34
  end
38
35
 
39
36
  private
40
- def remove(line_item, variant_units, shipment = nil)
41
- quantity = variant_units.size - line_item.quantity
42
-
43
- if shipment.present?
44
- remove_from_shipment(shipment, line_item.variant, quantity)
45
- else
46
- order.shipments.each do |shipment|
47
- break if quantity == 0
48
- quantity -= remove_from_shipment(shipment, line_item.variant, quantity)
37
+ def remove(item_units, shipment = nil)
38
+ quantity = item_units.size - line_item.quantity
39
+
40
+ if shipment.present?
41
+ remove_from_shipment(shipment, quantity)
42
+ else
43
+ order.shipments.each do |shipment|
44
+ break if quantity == 0
45
+ quantity -= remove_from_shipment(shipment, quantity)
46
+ end
49
47
  end
50
48
  end
51
- end
52
49
 
53
- # Returns either one of the shipment:
54
- #
55
- # first unshipped that already includes this variant
56
- # first unshipped that's leaving from a stock_location that stocks this variant
57
- def determine_target_shipment(variant)
58
- shipment = order.shipments.detect do |shipment|
59
- (shipment.ready? || shipment.pending?) && shipment.include?(variant)
60
- end
50
+ # Returns either one of the shipment:
51
+ #
52
+ # first unshipped that already includes this variant
53
+ # first unshipped that's leaving from a stock_location that stocks this variant
54
+ def determine_target_shipment
55
+ shipment = order.shipments.detect do |shipment|
56
+ shipment.ready_or_pending? && shipment.include?(variant)
57
+ end
61
58
 
62
- shipment ||= order.shipments.detect do |shipment|
63
- (shipment.ready? || shipment.pending?) && variant.stock_location_ids.include?(shipment.stock_location_id)
59
+ shipment ||= order.shipments.detect do |shipment|
60
+ shipment.ready_or_pending? && variant.stock_location_ids.include?(shipment.stock_location_id)
61
+ end
64
62
  end
65
- end
66
63
 
67
- def add_to_shipment(shipment, variant, quantity)
68
- if variant.should_track_inventory?
69
- on_hand, back_order = shipment.stock_location.fill_status(variant, quantity)
64
+ def add_to_shipment(shipment, quantity)
65
+ if variant.should_track_inventory?
66
+ on_hand, back_order = shipment.stock_location.fill_status(variant, quantity)
70
67
 
71
- on_hand.times { shipment.set_up_inventory('on_hand', variant, order) }
72
- back_order.times { shipment.set_up_inventory('backordered', variant, order) }
73
- else
74
- quantity.times { shipment.set_up_inventory('on_hand', variant, order) }
75
- end
68
+ on_hand.times { shipment.set_up_inventory('on_hand', variant, order, line_item) }
69
+ back_order.times { shipment.set_up_inventory('backordered', variant, order, line_item) }
70
+ else
71
+ quantity.times { shipment.set_up_inventory('on_hand', variant, order, line_item) }
72
+ end
76
73
 
77
- # adding to this shipment, and removing from stock_location
78
- if order.completed?
79
- shipment.stock_location.unstock(variant, quantity, shipment)
74
+ # adding to this shipment, and removing from stock_location
75
+ if order.completed?
76
+ shipment.stock_location.unstock(variant, quantity, shipment)
77
+ end
78
+
79
+ quantity
80
80
  end
81
81
 
82
- quantity
83
- end
82
+ def remove_from_shipment(shipment, quantity)
83
+ return 0 if quantity == 0 || shipment.shipped?
84
84
 
85
- def remove_from_shipment(shipment, variant, quantity)
86
- return 0 if quantity == 0 || shipment.shipped?
85
+ shipment_units = shipment.inventory_units_for_item(line_item, variant).reject do |variant_unit|
86
+ variant_unit.state == 'shipped'
87
+ end.sort_by(&:state)
87
88
 
88
- shipment_units = shipment.inventory_units_for(variant).reject do |variant_unit|
89
- variant_unit.state == 'shipped'
90
- end.sort_by(&:state)
89
+ removed_quantity = 0
91
90
 
92
- removed_quantity = 0
91
+ shipment_units.each do |inventory_unit|
92
+ break if removed_quantity == quantity
93
+ inventory_unit.destroy
94
+ removed_quantity += 1
95
+ end
93
96
 
94
- shipment_units.each do |inventory_unit|
95
- break if removed_quantity == quantity
96
- inventory_unit.destroy
97
- removed_quantity += 1
98
- end
97
+ shipment.destroy if shipment.inventory_units.count == 0
99
98
 
100
- shipment.destroy if shipment.inventory_units.count == 0
99
+ # removing this from shipment, and adding to stock_location
100
+ if order.completed?
101
+ shipment.stock_location.restock variant, removed_quantity, shipment
102
+ end
101
103
 
102
- # removing this from shipment, and adding to stock_location
103
- if order.completed?
104
- shipment.stock_location.restock variant, removed_quantity, shipment
104
+ removed_quantity
105
105
  end
106
-
107
- removed_quantity
108
- end
109
106
  end
110
107
  end
@@ -9,23 +9,9 @@ module Spree
9
9
  @errors = ActiveModel::Errors.new(self)
10
10
  end
11
11
 
12
- #
13
- # Parameters can be passed using the following possible parameter configurations:
14
- #
15
- # * Single variant/quantity pairing
16
- # +:variants => { variant_id => quantity }+
17
- #
18
- # * Multiple products at once
19
- # +:products => { product_id => variant_id, product_id => variant_id }, :quantity => quantity+
20
- def populate(from_hash)
21
- from_hash[:products].each do |product_id,variant_id|
22
- attempt_cart_add(variant_id, from_hash[:quantity])
23
- end if from_hash[:products]
24
-
25
- from_hash[:variants].each do |variant_id, quantity|
26
- attempt_cart_add(variant_id, quantity)
27
- end if from_hash[:variants]
28
-
12
+
13
+ def populate(variant_id, quantity)
14
+ attempt_cart_add(variant_id, quantity)
29
15
  valid?
30
16
  end
31
17
 
@@ -16,35 +16,23 @@ module Spree
16
16
  # associations try to save and then in turn try to call +update!+ again.)
17
17
  def update
18
18
  update_totals
19
-
20
19
  if order.completed?
21
20
  update_payment_state
22
-
23
- # give each of the shipments a chance to update themselves
24
- shipments.each { |shipment| shipment.update!(order) }
21
+ update_shipments
25
22
  update_shipment_state
26
23
  end
27
-
28
- update_adjustments
29
- # update totals a second time in case updated adjustments have an effect on the total
30
- update_totals
31
-
32
- order.update_columns({
33
- payment_state: order.payment_state,
34
- shipment_state: order.shipment_state,
35
- item_total: order.item_total,
36
- adjustment_total: order.adjustment_total,
37
- payment_total: order.payment_total,
38
- total: order.total
39
- })
40
-
41
24
  run_hooks
25
+ persist_totals
42
26
  end
43
27
 
44
28
  def run_hooks
45
29
  update_hooks.each { |hook| order.send hook }
46
30
  end
47
31
 
32
+ def recalculate_adjustments
33
+ adjustments.includes(:source).each { |adjustment| adjustment.update! order }
34
+ end
35
+
48
36
  # Updates the following Order total values:
49
37
  #
50
38
  # +payment_total+ The total value of all finalized Payments (NOTE: non-finalized Payments are excluded)
@@ -52,11 +40,61 @@ module Spree
52
40
  # +adjustment_total+ The total value of all adjustments (promotions, credits, etc.)
53
41
  # +total+ The so-called "order total." This is equivalent to +item_total+ plus +adjustment_total+.
54
42
  def update_totals
55
- order.payment_total = payments.completed.map(&:amount).sum
43
+ order.payment_total = payments.completed.sum(:amount)
44
+ update_item_total
45
+ update_shipment_total
46
+ update_adjustment_total
47
+ end
48
+
49
+
50
+ # give each of the shipments a chance to update themselves
51
+ def update_shipments
52
+ shipments.each { |shipment| shipment.update!(order) }
53
+ end
54
+
55
+ def update_shipment_total
56
+ order.shipment_total = shipments.sum("cost + promo_total")
57
+ update_order_total
58
+ end
59
+
60
+ def update_order_total
61
+ order.total = order.item_total + order.shipment_total + order.adjustment_total
62
+ end
63
+
64
+ def update_adjustment_total
65
+ recalculate_adjustments
66
+ order.adjustment_total = line_items.sum(:adjustment_total) +
67
+ shipments.sum(:adjustment_total) +
68
+ adjustments.eligible.sum(:amount)
69
+ order.included_tax_total = line_items.sum(:included_tax_total) + shipments.sum(:included_tax_total)
70
+ order.additional_tax_total = line_items.sum(:additional_tax_total) + shipments.sum(:additional_tax_total)
71
+
72
+ update_order_total
73
+ end
74
+
75
+ def update_item_count
76
+ order.item_count = line_items.sum(:quantity)
77
+ end
78
+
79
+ def update_item_total
56
80
  order.item_total = line_items.map(&:amount).sum
57
- order.adjustment_total = adjustments.eligible.map(&:amount).sum
58
- order.tax_total = order.all_adjustments.tax.map(&:amount).sum
59
- order.total = order.item_total + order.adjustment_total
81
+ update_order_total
82
+ end
83
+
84
+ def persist_totals
85
+ order.update_columns(
86
+ payment_state: order.payment_state,
87
+ shipment_state: order.shipment_state,
88
+ item_total: order.item_total,
89
+ item_count: order.item_count,
90
+ adjustment_total: order.adjustment_total,
91
+ included_tax_total: order.included_tax_total,
92
+ additional_tax_total: order.additional_tax_total,
93
+ payment_total: order.payment_total,
94
+ shipment_total: order.shipment_total,
95
+ total: order.total,
96
+ updated_at: Time.now,
97
+ )
60
98
  end
61
99
 
62
100
  # Updates the +shipment_state+ attribute according to the following logic:
@@ -90,6 +128,7 @@ module Spree
90
128
  end
91
129
 
92
130
  order.state_changed('shipment')
131
+ order.shipment_state
93
132
  end
94
133
 
95
134
  # Updates the +payment_state+ attribute according to the following logic:
@@ -107,6 +146,8 @@ module Spree
107
146
  if payments.present?
108
147
  if payments.last.state == 'failed'
109
148
  order.payment_state = 'failed'
149
+ elsif payments.last.state == 'checkout'
150
+ order.payment_state = 'pending'
110
151
  elsif payments.last.state == 'completed'
111
152
  order.payment_state = 'credit_owed'
112
153
  else
@@ -124,30 +165,8 @@ module Spree
124
165
  order.state_changed('payment')
125
166
  end
126
167
 
127
- # Updates each of the Order adjustments.
128
- #
129
- # This is intended to be called from an Observer so that the Order can
130
- # respond to external changes to LineItem, Shipment, other Adjustments, etc.
131
- #
132
- # Adjustments will check if they are still eligible. Ineligible adjustments
133
- # are preserved but not counted towards adjustment_total.
134
- def update_adjustments
135
- order.adjustments.reload.each { |adjustment| adjustment.update!(order) }
136
- choose_best_promotion_adjustment
137
- end
138
-
139
168
  private
140
169
 
141
- # Picks one (and only one) promotion to be eligible for this order
142
- # This promotion provides the most discount, and if two promotions
143
- # have the same amount, then it will pick the latest one.
144
- def choose_best_promotion_adjustment
145
- if best_promotion_adjustment = order.adjustments.promotion.eligible.reorder("amount ASC, created_at DESC").first
146
- other_promotions = order.adjustments.promotion.where("id NOT IN (?)", best_promotion_adjustment.id)
147
- other_promotions.update_all(eligible: false)
148
- end
149
- end
150
-
151
170
  def round_money(n)
152
171
  (n * 100).round / 100.0
153
172
  end