spree_core 2.0.4 → 2.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/app/mailers/spree/test_mailer.rb +2 -1
  3. data/app/models/spree/adjustment.rb +18 -7
  4. data/app/models/spree/alert.rb +1 -1
  5. data/app/models/spree/credit_card.rb +2 -2
  6. data/app/models/spree/inventory_unit.rb +5 -0
  7. data/app/models/spree/line_item.rb +18 -4
  8. data/app/models/spree/order/checkout.rb +10 -14
  9. data/app/models/spree/order.rb +39 -27
  10. data/app/models/spree/order_contents.rb +2 -2
  11. data/app/models/spree/order_inventory.rb +2 -9
  12. data/app/models/spree/order_updater.rb +18 -7
  13. data/app/models/spree/payment/processing.rb +102 -102
  14. data/app/models/spree/payment.rb +10 -9
  15. data/app/models/spree/preferences/store.rb +1 -1
  16. data/app/models/spree/product.rb +11 -2
  17. data/app/models/spree/promotion/rules/user.rb +7 -2
  18. data/app/models/spree/property.rb +1 -1
  19. data/app/models/spree/shipment.rb +12 -7
  20. data/app/models/spree/shipping_method.rb +1 -1
  21. data/app/models/spree/stock/availability_validator.rb +9 -1
  22. data/app/models/spree/stock/coordinator.rb +1 -3
  23. data/app/models/spree/stock/estimator.rb +1 -1
  24. data/app/models/spree/stock/packer.rb +13 -5
  25. data/app/models/spree/stock_item.rb +10 -1
  26. data/app/models/spree/stock_location.rb +1 -1
  27. data/app/models/spree/tax_rate.rb +3 -1
  28. data/app/models/spree/zone.rb +37 -1
  29. data/app/views/spree/test_mailer/test_email.text.erb +4 -0
  30. data/config/locales/en.yml +24 -1
  31. data/db/default/spree/roles.rb +2 -2
  32. data/db/migrate/20130213191427_create_default_stock.rb +2 -1
  33. data/db/migrate/20130802022321_migrate_tax_categories_to_line_items.rb +1 -1
  34. data/db/migrate/20130806022521_drop_spree_mail_methods.rb +12 -0
  35. data/db/migrate/20130806145853_set_default_stock_location_on_shipments.rb +8 -0
  36. data/db/migrate/20130809164245_add_admin_name_column_to_spree_shipping_methods.rb +5 -0
  37. data/db/migrate/20130809164330_add_admin_name_column_to_spree_stock_locations.rb +5 -0
  38. data/db/migrate/20130813140619_expand_order_number_size.rb +9 -0
  39. data/db/migrate/20130826062534_add_depth_to_spree_taxons.rb +16 -0
  40. data/db/migrate/20130915032339_add_deleted_at_to_spree_stock_items.rb +5 -0
  41. data/lib/generators/spree/dummy/templates/rails/database.yml +0 -3
  42. data/lib/spree/core/engine.rb +1 -5
  43. data/lib/spree/core/permalinks.rb +4 -2
  44. data/lib/spree/core/version.rb +1 -1
  45. data/lib/spree/promo/coupon_applicator.rb +2 -2
  46. data/lib/spree/testing_support/capybara_ext.rb +2 -2
  47. data/lib/spree/testing_support/factories/order_factory.rb +8 -4
  48. metadata +17 -12
  49. data/app/models/spree/new_adjustment.rb +0 -4
  50. data/app/models/spree/shipping_adjustment.rb +0 -4
  51. data/db/migrate/20130805043440_create_spree_new_adjustments.rb +0 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b435838b2a77628006e2e2885f5dbe2039958630
4
- data.tar.gz: 1df2bcec2ac50c9d4716017752eb8c56ab2f9960
3
+ metadata.gz: 4eb6afc84186dd0b46d37daebea561e582412dfb
4
+ data.tar.gz: 96ad34a945d823c7f0ce6d17797c183eee5f4261
5
5
  SHA512:
6
- metadata.gz: 1154f9c96163b14b0f85379e73718b6e5a95a6b60688399df8b724e109880d1e21deb4dbd77d44ae8dd29fe1cd98bd563d74c6ce191ac89eff57424dba437602
7
- data.tar.gz: 5d008b1beae9dc20bf209bcc59063debee39ae36c6426569f970af0aad14b64287b61f9bed6454190e694ce96cb9b145be04b15066bc8abc80da9fb3c91c21fe
6
+ metadata.gz: 2a990089d87e7ed851394892fe747d8146fdd7992a1f1d70f1cb7447a6471c937dd1faf5380cbec891844f048049b5f8b65312bae912ae69cf46690f235e2dab
7
+ data.tar.gz: c13e7f2071ddac220493da65f4407b25e00cf0704a7d205637c67513487f7646e60ab209d43ed3a2365d81d473420c6fb56760331a7598dc2e66c7966837e9e6
@@ -1,8 +1,9 @@
1
1
  module Spree
2
2
  class TestMailer < BaseMailer
3
3
  def test_email(user)
4
+ recipient = user.respond_to?(:id) ? user : Spree.user_class.find(user)
4
5
  subject = "#{Spree::Config[:site_name]} #{Spree.t('test_mailer.test_email.subject')}"
5
- mail(to: user.email, from: from_address, subject: subject)
6
+ mail(to: recipient.email, from: from_address, subject: subject)
6
7
  end
7
8
  end
8
9
  end
@@ -60,10 +60,14 @@ module Spree
60
60
  scope :promotion, -> { where(originator_type: 'Spree::PromotionAction') }
61
61
  scope :return_authorization, -> { where(source_type: "Spree::ReturnAuthorization") }
62
62
 
63
+ def promotion?
64
+ originator_type == 'Spree::PromotionAction'
65
+ end
66
+
63
67
  # Update the boolean _eligible_ attribute which determines which adjustments
64
68
  # count towards the order's adjustment_total.
65
69
  def set_eligibility
66
- result = self.mandatory || (self.amount != 0 && self.eligible_for_originator?)
70
+ result = mandatory || ((amount != 0 || promotion?) && eligible_for_originator?)
67
71
  update_attribute_without_callbacks(:eligible, result)
68
72
  end
69
73
 
@@ -74,20 +78,27 @@ module Spree
74
78
  !originator.respond_to?(:eligible?) || originator.eligible?(source)
75
79
  end
76
80
 
77
- # Update both the eligibility and amount of the adjustment. Adjustments
81
+ # Update both the eligibility and amount of the adjustment. Adjustments
78
82
  # delegate updating of amount to their Originator when present, but only if
79
83
  # +locked+ is false. Adjustments that are +locked+ will never change their amount.
80
84
  #
81
- # order#update_adjustments passes self as the src, this is so calculations can
82
- # be performed on the # current values. If we used source it would load the old
83
- # record from db for the association
84
- def update!
85
+ # Adjustments delegate updating of amount to their Originator when present,
86
+ # but only if when they're in "open" state, closed or finalized adjustments
87
+ # are not recalculated.
88
+ #
89
+ # It receives +calculable+ as the updated source here so calculations can be
90
+ # performed on the current values of that source. If we used +source+ it
91
+ # could load the old record from db for the association. e.g. when updating
92
+ # more than on line items at once via accepted_nested_attributes the order
93
+ # object on the association would be in a old state and therefore the
94
+ # adjustment calculations would not performed on proper values
95
+ def update!(calculable = nil)
85
96
  return if immutable?
86
97
  # Fix for #3381
87
98
  # If we attempt to call 'source' before the reload, then source is currently
88
99
  # the order object. After calling a reload, the source is the Shipment.
89
100
  reload
90
- originator.update_adjustment(self, source) if originator.present?
101
+ originator.update_adjustment(self, calculable || source) if originator.present?
91
102
  set_eligibility
92
103
  end
93
104
 
@@ -11,7 +11,7 @@ module Spree
11
11
  rails_version: Rails.version
12
12
  }
13
13
 
14
- HTTParty.get('http://alerts.spreecommerce.com/alerts.json', body: params).parsed_response
14
+ HTTParty.get('http://alerts.spreecommerce.com/alerts.json', query: params).parsed_response
15
15
  end
16
16
  end
17
17
  end
@@ -105,9 +105,9 @@ module Spree
105
105
  private
106
106
 
107
107
  def expiry_not_in_the_past
108
- if year && month
108
+ if year.present? && month.present?
109
109
  time = "#{year}-#{month}-1".to_time
110
- if time < Time.zone.now.beginning_of_month
110
+ if time < Time.zone.now.to_time.beginning_of_month
111
111
  errors.add(:base, :card_expired)
112
112
  end
113
113
  end
@@ -53,6 +53,11 @@ module Spree
53
53
  variant_id: variant_id).first
54
54
  end
55
55
 
56
+ # Remove variant default_scope `deleted_at: nil`
57
+ def variant
58
+ Spree::Variant.unscoped { super }
59
+ end
60
+
56
61
  private
57
62
 
58
63
  def allow_ship?
@@ -85,15 +85,29 @@ module Spree
85
85
  @preferred_shipment = shipment
86
86
  end
87
87
 
88
+ # Remove product default_scope `deleted_at: nil`
89
+ def product
90
+ variant.product
91
+ end
92
+
93
+ # Remove variant default_scope `deleted_at: nil`
94
+ def variant
95
+ Spree::Variant.unscoped { super }
96
+ end
97
+
88
98
  private
89
99
  def update_inventory
90
- Spree::OrderInventory.new(self.order).verify(self, target_shipment)
100
+ if changed?
101
+ Spree::OrderInventory.new(self.order).verify(self, target_shipment)
102
+ end
91
103
  end
92
104
 
93
105
  def update_order
94
- # update the order totals, etc.
95
- order.create_tax_charge!
96
- order.update!
106
+ if changed? || destroyed?
107
+ # update the order totals, etc.
108
+ order.create_tax_charge!
109
+ order.update!
110
+ end
97
111
  end
98
112
  end
99
113
  end
@@ -63,10 +63,12 @@ module Spree
63
63
  transition :to => :awaiting_return
64
64
  end
65
65
 
66
-
67
- before_transition :to => :complete do |order|
68
- order.process_payments! if order.payment_required?
66
+ if states[:payment]
67
+ before_transition :to => :complete do |order|
68
+ order.process_payments! if order.payment_required?
69
+ end
69
70
  end
71
+
70
72
  before_transition :from => :cart, :do => :ensure_line_items_present
71
73
 
72
74
  before_transition :to => :delivery, :do => :create_proposed_shipments
@@ -125,12 +127,11 @@ module Spree
125
127
 
126
128
  def self.remove_transition(options={})
127
129
  self.removed_transitions << options
128
- if transition = find_transition(options)
129
- self.next_event_transitions.delete(transition)
130
- end
130
+ self.next_event_transitions.delete(find_transition(options))
131
131
  end
132
132
 
133
133
  def self.find_transition(options={})
134
+ return nil if options.nil? || !options.include?(:from) || !options.include?(:to)
134
135
  self.next_event_transitions.detect do |transition|
135
136
  transition[options[:from].to_sym] == options[:to].to_sym
136
137
  end
@@ -149,15 +150,10 @@ module Spree
149
150
  end
150
151
 
151
152
  def checkout_steps
152
- checkout_steps = []
153
- # TODO: replace this with each_with_object once Ruby 1.9 is standard
154
- self.class.checkout_steps.each do |step, options|
155
- if options[:if]
156
- next unless options[:if].call(self)
157
- end
153
+ steps = self.class.checkout_steps.each_with_object([]) { |(step, options), checkout_steps|
154
+ next if options.include?(:if) && !options[:if].call(self)
158
155
  checkout_steps << step
159
- end
160
- steps = checkout_steps.map(&:to_s)
156
+ }.map(&:to_s)
161
157
  # Ensure there is always a complete step
162
158
  steps << "complete" unless steps.include?("complete")
163
159
  steps
@@ -47,9 +47,12 @@ module Spree
47
47
  belongs_to :ship_address, foreign_key: :ship_address_id, class_name: 'Spree::Address'
48
48
  alias_attribute :shipping_address, :ship_address
49
49
 
50
+ has_many :adjustments, as: :adjustable, dependent: :destroy, order: 'created_at ASC'
51
+ has_many :line_item_adjustments, through: :line_items, source: :adjustments
52
+ has_many :line_items, dependent: :destroy, order: 'created_at ASC'
53
+ has_many :payments, dependent: :destroy
54
+ has_many :return_authorizations, dependent: :destroy
50
55
  has_many :state_changes, as: :stateful
51
- has_many :line_items, dependent: :destroy, order: "#{Spree::LineItem.table_name}.created_at ASC"
52
- has_many :payments, dependent: :destroy, :class_name => "Spree::Payment"
53
56
 
54
57
  has_many :shipments, dependent: :destroy, :class_name => "Shipment" do
55
58
  def states
@@ -57,13 +60,6 @@ module Spree
57
60
  end
58
61
  end
59
62
 
60
- has_many :return_authorizations, dependent: :destroy
61
- has_many :adjustments,
62
- as: :adjustable,
63
- dependent: :destroy,
64
- order: "#{Spree::Adjustment.table_name}.created_at ASC",
65
- inverse_of: :source
66
-
67
63
  accepts_nested_attributes_for :line_items
68
64
  accepts_nested_attributes_for :bill_address
69
65
  accepts_nested_attributes_for :ship_address
@@ -202,26 +198,26 @@ module Spree
202
198
  return tax_zone != Zone.default_tax
203
199
  end
204
200
 
205
- # Array of adjustments that are inclusive in the variant price. Useful for when
206
- # prices include tax (ex. VAT) and you need to record the tax amount separately.
207
201
  def price_adjustments
208
- adjustments = []
209
-
210
- line_items.each { |line_item| adjustments.concat line_item.adjustments }
211
-
212
- adjustments
202
+ ActiveSupport::Deprecation.warn("Order#price_adjustments will be deprecated in Spree 2.1, please use Order#line_item_adjustments instead.")
203
+ self.line_item_adjustments
213
204
  end
214
205
 
215
- # Array of totals grouped by Adjustment#label. Useful for displaying price
206
+ # Array of totals grouped by Adjustment#label. Useful for displaying line item
216
207
  # adjustments on an invoice. For example, you can display tax breakout for
217
208
  # cases where tax is included in price.
218
- def price_adjustment_totals
219
- Hash[price_adjustments.group_by(&:label).map do |label, adjustments|
209
+ def line_item_adjustment_totals
210
+ Hash[self.line_item_adjustments.eligible.group_by(&:label).map do |label, adjustments|
220
211
  total = adjustments.sum(&:amount)
221
212
  [label, Spree::Money.new(total, { currency: currency })]
222
213
  end]
223
214
  end
224
215
 
216
+ def price_adjustment_totals
217
+ ActiveSupport::Deprecation.warn("Order#price_adjustment_totals will be deprecated in Spree 2.1, please use Order#line_item_adjustment_totals instead.")
218
+ self.line_item_adjustment_totals
219
+ end
220
+
225
221
  def updater
226
222
  @updater ||= OrderUpdater.new(self)
227
223
  end
@@ -279,10 +275,11 @@ module Spree
279
275
  def associate_user!(user)
280
276
  self.user = user
281
277
  self.email = user.email
278
+ self.created_by = user if self.created_by.blank?
282
279
 
283
280
  if persisted?
284
281
  # immediately persist the changes we just made, but don't use save since we might have an invalid address associated
285
- self.class.unscoped.where(id: id).update_all(email: user.email, user_id: user.id)
282
+ self.class.unscoped.where(id: id).update_all(email: user.email, user_id: user.id, created_by_id: self.created_by_id)
286
283
  end
287
284
  end
288
285
 
@@ -368,7 +365,7 @@ module Spree
368
365
  touch :completed_at
369
366
 
370
367
  # lock all adjustments (coupon promotions, etc.)
371
- adjustments.each { |adjustment| adjustment.update_column('state', "closed") }
368
+ adjustments.update_all state: 'closed'
372
369
 
373
370
  # update payment and shipment(s) states, and save
374
371
  updater.update_payment_state
@@ -462,7 +459,7 @@ module Spree
462
459
  end
463
460
 
464
461
  def insufficient_stock_lines
465
- line_items.select &:insufficient_stock?
462
+ @insufficient_stock_lines ||= line_items.select(&:insufficient_stock?)
466
463
  end
467
464
 
468
465
  def merge!(order)
@@ -487,11 +484,9 @@ module Spree
487
484
  adjustments.destroy_all
488
485
  end
489
486
 
490
- # destroy any previous adjustments.
491
- # Adjustments will be recalculated during order update.
492
487
  def clear_adjustments!
493
- adjustments.tax.each(&:destroy)
494
- price_adjustments.each(&:destroy)
488
+ self.adjustments.destroy_all
489
+ self.line_item_adjustments.destroy_all
495
490
  end
496
491
 
497
492
  def has_step?(step)
@@ -522,7 +517,7 @@ module Spree
522
517
  # Receives an adjustment +originator+ (here a PromotionAction object) and tells
523
518
  # if the order has adjustments from that already
524
519
  def promotion_credit_exists?(originator)
525
- !! adjustments.promotion.reload.detect { |credit| credit.originator.id == originator.id }
520
+ !! adjustments.includes(:originator).promotion.reload.detect { |credit| credit.originator.id == originator.id }
526
521
  end
527
522
 
528
523
  def promo_total
@@ -534,6 +529,7 @@ module Spree
534
529
  end
535
530
 
536
531
  def create_proposed_shipments
532
+ adjustments.shipping.delete_all
537
533
  shipments.destroy_all
538
534
 
539
535
  packages = Spree::Stock::Coordinator.new(self).packages
@@ -544,6 +540,22 @@ module Spree
544
540
  shipments
545
541
  end
546
542
 
543
+ # Clean shipments and make order back to address state
544
+ #
545
+ # At some point the might need to force the order to transition from address
546
+ # to delivery again so that proper updated shipments are created.
547
+ # e.g. customer goes back from payment step and changes order items
548
+ def ensure_updated_shipments
549
+ if shipments.any?
550
+ self.shipments.destroy_all
551
+ self.update_column(:state, "address")
552
+ end
553
+ end
554
+
555
+ def refresh_shipment_rates
556
+ shipments.map &:refresh_rates
557
+ end
558
+
547
559
  private
548
560
 
549
561
  def link_by_email
@@ -8,14 +8,14 @@ module Spree
8
8
 
9
9
  # Get current line item for variant if exists
10
10
  # Add variant qty to line_item
11
- def add(variant, quantity, currency=nil, shipment=nil)
11
+ def add(variant, quantity=1, currency=nil, shipment=nil)
12
12
  line_item = order.find_line_item_by_variant(variant)
13
13
  add_to_line_item(line_item, variant, quantity, currency, shipment)
14
14
  end
15
15
 
16
16
  # Get current line item for variant
17
17
  # Remove variant qty from line_item
18
- def remove(variant, quantity, shipment=nil)
18
+ def remove(variant, quantity=1, shipment=nil)
19
19
  line_item = order.find_line_item_by_variant(variant)
20
20
 
21
21
  unless line_item
@@ -67,15 +67,8 @@ module Spree
67
67
  def add_to_shipment(shipment, variant, quantity)
68
68
  on_hand, back_order = shipment.stock_location.fill_status(variant, quantity)
69
69
 
70
- on_hand.times do
71
- shipment.inventory_units.create({variant_id: variant.id,
72
- state: 'on_hand'}, without_protection: true)
73
- end
74
-
75
- back_order.times do
76
- shipment.inventory_units.create({variant_id: variant.id,
77
- state: 'backordered'}, without_protection: true)
78
- end
70
+ on_hand.times { shipment.set_up_inventory('on_hand', variant, order) }
71
+ back_order.times { shipment.set_up_inventory('backordered', variant, order) }
79
72
 
80
73
  # adding to this shipment, and removing from stock_location
81
74
  if order.completed?
@@ -16,12 +16,17 @@ 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
- update_payment_state
20
19
 
21
- # give each of the shipments a chance to update themselves
22
- shipments.each { |shipment| shipment.update!(order) }#(&:update!)
23
- update_shipment_state
24
- update_adjustments
20
+ if order.completed?
21
+ update_payment_state
22
+
23
+ # give each of the shipments a chance to update themselves
24
+ shipments.each { |shipment| shipment.update!(order) }
25
+ update_shipment_state
26
+ end
27
+
28
+ update_promotion_adjustments
29
+ update_shipping_adjustments
25
30
  # update totals a second time in case updated adjustments have an effect on the total
26
31
  update_totals
27
32
 
@@ -120,11 +125,17 @@ module Spree
120
125
  #
121
126
  # Adjustments will check if they are still eligible. Ineligible adjustments
122
127
  # are preserved but not counted towards adjustment_total.
123
- def update_adjustments
124
- order.adjustments.reload.each { |adjustment| adjustment.update! }
128
+ def update_promotion_adjustments
129
+ order.adjustments.reload.promotion.each { |adjustment| adjustment.update!(order) }
125
130
  choose_best_promotion_adjustment
126
131
  end
127
132
 
133
+ # Shipping adjustments don't receive order on update! because they calculated
134
+ # over a shipping / package object rather than an order object
135
+ def update_shipping_adjustments
136
+ order.adjustments.reload.shipping.each { |adjustment| adjustment.update! }
137
+ end
138
+
128
139
  private
129
140
 
130
141
  # Picks one (and only one) promotion to be eligible for this order
@@ -76,133 +76,133 @@ module Spree
76
76
  end
77
77
  end
78
78
  end
79
- end
80
79
 
81
- def credit!(credit_amount=nil)
82
- protect_from_connection_error do
83
- check_environment
80
+ def credit!(credit_amount=nil)
81
+ protect_from_connection_error do
82
+ check_environment
84
83
 
85
- credit_amount ||= credit_allowed >= order.outstanding_balance.abs ? order.outstanding_balance.abs : credit_allowed.abs
86
- credit_amount = credit_amount.to_f
84
+ credit_amount ||= credit_allowed >= order.outstanding_balance.abs ? order.outstanding_balance.abs : credit_allowed.abs
85
+ credit_amount = credit_amount.to_f
87
86
 
88
- if payment_method.payment_profiles_supported?
89
- response = payment_method.credit((credit_amount * 100).round, source, response_code, gateway_options)
90
- else
91
- response = payment_method.credit((credit_amount * 100).round, response_code, gateway_options)
92
- end
87
+ if payment_method.payment_profiles_supported?
88
+ response = payment_method.credit((credit_amount * 100).round, source, response_code, gateway_options)
89
+ else
90
+ response = payment_method.credit((credit_amount * 100).round, response_code, gateway_options)
91
+ end
93
92
 
94
- record_response(response)
93
+ record_response(response)
95
94
 
96
- if response.success?
97
- self.class.create({ :order => order,
98
- :source => self,
99
- :payment_method => payment_method,
100
- :amount => credit_amount.abs * -1,
101
- :response_code => response.authorization,
102
- :state => 'completed' }, :without_protection => true)
103
- else
104
- gateway_error(response)
95
+ if response.success?
96
+ self.class.create({ :order => order,
97
+ :source => self,
98
+ :payment_method => payment_method,
99
+ :amount => credit_amount.abs * -1,
100
+ :response_code => response.authorization,
101
+ :state => 'completed' }, :without_protection => true)
102
+ else
103
+ gateway_error(response)
104
+ end
105
105
  end
106
106
  end
107
- end
108
107
 
109
- def partial_credit(amount)
110
- return if amount > credit_allowed
111
- started_processing!
112
- credit!(amount)
113
- end
108
+ def partial_credit(amount)
109
+ return if amount > credit_allowed
110
+ started_processing!
111
+ credit!(amount)
112
+ end
114
113
 
115
- def gateway_options
116
- options = { :email => order.email,
117
- :customer => order.email,
118
- :ip => order.last_ip_address,
119
- # Need to pass in a unique identifier here to make some
120
- # payment gateways happy.
121
- #
122
- # For more information, please see Spree::Payment#set_unique_identifier
123
- :order_id => gateway_order_id }
124
-
125
- options.merge!({ :shipping => order.ship_total * 100,
126
- :tax => order.tax_total * 100,
127
- :subtotal => order.item_total * 100,
128
- :discount => order.promo_total * 100,
129
- :currency => currency })
130
-
131
- options.merge!({ :billing_address => order.bill_address.try(:active_merchant_hash),
132
- :shipping_address => order.ship_address.try(:active_merchant_hash) })
133
-
134
- options
135
- end
114
+ def gateway_options
115
+ options = { :email => order.email,
116
+ :customer => order.email,
117
+ :ip => order.last_ip_address,
118
+ # Need to pass in a unique identifier here to make some
119
+ # payment gateways happy.
120
+ #
121
+ # For more information, please see Spree::Payment#set_unique_identifier
122
+ :order_id => gateway_order_id }
123
+
124
+ options.merge!({ :shipping => order.ship_total * 100,
125
+ :tax => order.tax_total * 100,
126
+ :subtotal => order.item_total * 100,
127
+ :discount => order.promo_total * 100,
128
+ :currency => currency })
129
+
130
+ options.merge!({ :billing_address => order.bill_address.try(:active_merchant_hash),
131
+ :shipping_address => order.ship_address.try(:active_merchant_hash) })
132
+
133
+ options
134
+ end
136
135
 
137
- private
136
+ private
138
137
 
139
- def gateway_action(source, action, success_state)
140
- protect_from_connection_error do
141
- check_environment
138
+ def gateway_action(source, action, success_state)
139
+ protect_from_connection_error do
140
+ check_environment
142
141
 
143
- response = payment_method.send(action, (amount * 100).round,
144
- source,
145
- gateway_options)
146
- handle_response(response, success_state, :failure)
142
+ response = payment_method.send(action, (amount * 100).round,
143
+ source,
144
+ gateway_options)
145
+ handle_response(response, success_state, :failure)
146
+ end
147
147
  end
148
- end
149
148
 
150
- def handle_response(response, success_state, failure_state)
151
- record_response(response)
149
+ def handle_response(response, success_state, failure_state)
150
+ record_response(response)
152
151
 
153
- if response.success?
154
- unless response.authorization.nil?
155
- self.response_code = response.authorization
156
- self.avs_response = response.avs_result['code']
152
+ if response.success?
153
+ unless response.authorization.nil?
154
+ self.response_code = response.authorization
155
+ self.avs_response = response.avs_result['code']
157
156
 
158
- if response.cvv_result
159
- self.cvv_response_code = response.cvv_result['code']
160
- self.cvv_response_message = response.cvv_result['message']
157
+ if response.cvv_result
158
+ self.cvv_response_code = response.cvv_result['code']
159
+ self.cvv_response_message = response.cvv_result['message']
160
+ end
161
161
  end
162
+ self.send("#{success_state}!")
163
+ else
164
+ self.send(failure_state)
165
+ gateway_error(response)
162
166
  end
163
- self.send("#{success_state}!")
164
- else
165
- self.send(failure_state)
166
- gateway_error(response)
167
167
  end
168
- end
169
168
 
170
- def record_response(response)
171
- log_entries.create({:details => response.to_yaml}, :without_protection => true)
172
- end
169
+ def record_response(response)
170
+ log_entries.create({:details => response.to_yaml}, :without_protection => true)
171
+ end
173
172
 
174
- def protect_from_connection_error
175
- begin
176
- yield
177
- rescue ActiveMerchant::ConnectionError => e
178
- gateway_error(e)
173
+ def protect_from_connection_error
174
+ begin
175
+ yield
176
+ rescue ActiveMerchant::ConnectionError => e
177
+ gateway_error(e)
178
+ end
179
179
  end
180
- end
181
180
 
182
- def gateway_error(error)
183
- if error.is_a? ActiveMerchant::Billing::Response
184
- text = error.params['message'] || error.params['response_reason_text'] || error.message
185
- elsif error.is_a? ActiveMerchant::ConnectionError
186
- text = Spree.t(:unable_to_connect_to_gateway)
187
- else
188
- text = error.to_s
181
+ def gateway_error(error)
182
+ if error.is_a? ActiveMerchant::Billing::Response
183
+ text = error.params['message'] || error.params['response_reason_text'] || error.message
184
+ elsif error.is_a? ActiveMerchant::ConnectionError
185
+ text = Spree.t(:unable_to_connect_to_gateway)
186
+ else
187
+ text = error.to_s
188
+ end
189
+ logger.error(Spree.t(:gateway_error))
190
+ logger.error(" #{error.to_yaml}")
191
+ raise Core::GatewayError.new(text)
189
192
  end
190
- logger.error(Spree.t(:gateway_error))
191
- logger.error(" #{error.to_yaml}")
192
- raise Core::GatewayError.new(text)
193
- end
194
193
 
195
- # Saftey check to make sure we're not accidentally performing operations on a live gateway.
196
- # Ex. When testing in staging environment with a copy of production data.
197
- def check_environment
198
- return if payment_method.environment == Rails.env
199
- message = Spree.t(:gateway_config_unavailable) + " - #{Rails.env}"
200
- raise Core::GatewayError.new(message)
201
- end
194
+ # Saftey check to make sure we're not accidentally performing operations on a live gateway.
195
+ # Ex. When testing in staging environment with a copy of production data.
196
+ def check_environment
197
+ return if payment_method.environment == Rails.env
198
+ message = Spree.t(:gateway_config_unavailable) + " - #{Rails.env}"
199
+ raise Core::GatewayError.new(message)
200
+ end
202
201
 
203
- # The unique identifier to be passed in to the payment gateway
204
- def gateway_order_id
205
- "#{order.number}-#{self.identifier}"
202
+ # The unique identifier to be passed in to the payment gateway
203
+ def gateway_order_id
204
+ "#{order.number}-#{self.identifier}"
205
+ end
206
206
  end
207
207
  end
208
- end
208
+ end