Class: Creditcard

Inherits:
ActiveRecord::Base
  • Object
show all
Defined in:
app/models/creditcard.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#numberObject

Returns the value of attribute number.



6
7
8
# File 'app/models/creditcard.rb', line 6

def number
  @number
end

#verification_valueObject

Returns the value of attribute verification_value.



6
7
8
# File 'app/models/creditcard.rb', line 6

def verification_value
  @verification_value
end

Instance Method Details

#actionsObject



164
165
166
# File 'app/models/creditcard.rb', line 164

def actions
  %w{capture void credit}
end

#authorize(amount, payment) ⇒ Object



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'app/models/creditcard.rb', line 64

def authorize(amount, payment)
  # ActiveMerchant is configured to use cents so we need to multiply order total by 100
  response = payment_gateway.authorize((amount * 100).round, self, gateway_options(payment))
  record_log payment, response

  if response.success?
    payment.response_code = response.authorization
    payment.avs_response = response.avs_result['code']
    payment.pend
  else
    payment.fail
    gateway_error(response)
  end
rescue ActiveMerchant::ConnectionError => e
  gateway_error I18n.t(:unable_to_connect_to_gateway)
end

#brandObject

needed for some of the ActiveMerchant gateways (eg. SagePay)



58
59
60
# File 'app/models/creditcard.rb', line 58

def brand
  cc_type
end

#can_capture?(payment) ⇒ Boolean

Indicates whether its possible to capture the payment

Returns:

  • (Boolean)


169
170
171
# File 'app/models/creditcard.rb', line 169

def can_capture?(payment)
  payment.state == "pending"
end

#can_credit?(payment) ⇒ Boolean

Indicates whether its possible to credit the payment. Most gateways require that the payment be settled first which generally happens within 12-24 hours of the transaction. For this reason, the default behavior of Spree is to disallow credit operations until the payment is at least 12 hours old.

Returns:

  • (Boolean)


185
186
187
188
189
190
# File 'app/models/creditcard.rb', line 185

def can_credit?(payment)
  return false unless (Time.now - 12.hours) > payment.created_at
  return false unless payment.state == "completed"
  return false unless payment.order.payment_state == "credit_owed"
  payment.credit_allowed > 0
end

#can_void?(payment) ⇒ Boolean

Indicates whether its possible to void the payment. Most gateways require that the payment has not been settled yet when performing a void (which generally happens within 12-24 hours of the transaction.) For this reason, the default behavior of Spree is to only allow void operations within the first 12 hours of the payment creation time.

Returns:

  • (Boolean)


177
178
179
180
# File 'app/models/creditcard.rb', line 177

def can_void?(payment)
  return false unless (Time.now - 12.hours) < payment.created_at
  %w{completed pending}.include? payment.state
end

#capture(payment) ⇒ Object



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'app/models/creditcard.rb', line 98

def capture(payment)
  return unless payment.pending?
  if payment_gateway.payment_profiles_supported?
    # Gateways supporting payment profiles will need access to creditcard object because this stores the payment profile information
    # so supply the authorization itself as well as the creditcard, rather than just the authorization code
    response = payment_gateway.capture(payment, self, minimal_gateway_options(payment))
  else
    # Standard ActiveMerchant capture usage
    response = payment_gateway.capture((payment.amount * 100).round, payment.response_code, minimal_gateway_options(payment))
  end

  record_log payment, response

  if response.success?
    payment.response_code = response.authorization
    payment.complete
  else
    payment.fail
    gateway_error(response)
  end
rescue ActiveMerchant::ConnectionError => e
  gateway_error I18n.t(:unable_to_connect_to_gateway)
end

#credit(payment) ⇒ Object



136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'app/models/creditcard.rb', line 136

def credit(payment)
  amount = payment.credit_allowed >= payment.order.outstanding_balance.abs ? payment.order.outstanding_balance.abs : payment.credit_allowed.abs

  if payment_gateway.payment_profiles_supported?
    response = payment_gateway.credit((amount * 100).round, self, payment.response_code, minimal_gateway_options(payment))
  else
    response = payment_gateway.credit((amount * 100).round, payment.response_code, minimal_gateway_options(payment))
  end

  record_log payment, response

  if response.success?
    Payment.create(:order => payment.order,
                  :source => payment,
                  :payment_method => payment.payment_method,
                  :amount => amount.abs * -1,
                  :response_code => response.authorization,
                  :state => 'completed')
  else
    gateway_error(response)
  end
rescue ActiveMerchant::ConnectionError => e
  gateway_error I18n.t(:unable_to_connect_to_gateway)
end

#display_numberObject

Show the card number, with all but last 4 numbers replace with “X”. (XXXX-XXXX-XXXX-4338)



49
50
51
# File 'app/models/creditcard.rb', line 49

def display_number
 "XXXX-XXXX-XXXX-#{last_digits}"
end

#first_name?Boolean

Returns:

  • (Boolean)


32
33
34
# File 'app/models/creditcard.rb', line 32

def first_name?
  !self.first_name.blank?
end

#gateway_error(error) ⇒ Object



200
201
202
203
204
205
206
207
208
209
# File 'app/models/creditcard.rb', line 200

def gateway_error(error)
  if error.is_a? ActiveMerchant::Billing::Response
    text = error.params['message'] || error.params['response_reason_text'] || error.message
  else
    text = error.to_s
  end
  logger.error(I18n.t('gateway_error'))
  logger.error("  #{error.to_yaml}")
  raise Spree::GatewayError.new(text)
end

#gateway_options(payment) ⇒ Object



211
212
213
214
215
# File 'app/models/creditcard.rb', line 211

def gateway_options(payment)
  options = {:billing_address  => generate_address_hash(payment.order.bill_address),
             :shipping_address => generate_address_hash(payment.order.ship_address)}
  options.merge minimal_gateway_options(payment)
end

#generate_address_hash(address) ⇒ Object

Generates an ActiveMerchant compatible address hash from one of Spree’s address objects



218
219
220
221
222
# File 'app/models/creditcard.rb', line 218

def generate_address_hash(address)
  return {} if address.nil?
  {:name => address.full_name, :address1 => address.address1, :address2 => address.address2, :city => address.city,
   :state => address.state_text, :zip => address.zipcode, :country => address.country.iso, :phone => address.phone}
end

#has_payment_profile?Boolean

Returns:

  • (Boolean)


192
193
194
# File 'app/models/creditcard.rb', line 192

def has_payment_profile?
  gateway_customer_profile_id.present?
end

#last_name?Boolean

Returns:

  • (Boolean)


36
37
38
# File 'app/models/creditcard.rb', line 36

def last_name?
  !self.last_name.blank?
end

#minimal_gateway_options(payment) ⇒ Object

Generates a minimal set of gateway options. There appears to be some issues with passing in a billing address when authorizing/voiding a previously captured transaction. So omits these options in this case since they aren’t necessary.



227
228
229
230
231
232
233
234
235
# File 'app/models/creditcard.rb', line 227

def minimal_gateway_options(payment)
  {:email    => payment.order.email,
   :customer => payment.order.email,
   :ip       => payment.order.ip_address,
   :order_id => payment.order.number,
   :shipping => payment.order.ship_total * 100,
   :tax      => payment.order.tax_total * 100,
   :subtotal => payment.order.item_total * 100}
end

#nameObject



40
41
42
# File 'app/models/creditcard.rb', line 40

def name
  "#{self.first_name} #{self.last_name}"
end

#name?Boolean

Returns:

  • (Boolean)


28
29
30
# File 'app/models/creditcard.rb', line 28

def name?
  first_name? && last_name?
end

#payment_gatewayObject



242
243
244
# File 'app/models/creditcard.rb', line 242

def payment_gateway
  @payment_gateway ||= Gateway.current
end

#process!(payment) ⇒ Object



12
13
14
15
16
17
18
19
20
# File 'app/models/creditcard.rb', line 12

def process!(payment)
  begin
    if Spree::Config[:auto_capture]
      purchase(payment.amount.to_f, payment)
    else
      authorize(payment.amount.to_f, payment)
    end
  end
end

#purchase(amount, payment) ⇒ Object



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'app/models/creditcard.rb', line 81

def purchase(amount, payment)
  #combined Authorize and Capture that gets processed by the ActiveMerchant gateway as one single transaction.
  response = payment_gateway.purchase((amount * 100).round, self, gateway_options(payment))
  record_log payment, response

  if response.success?
    payment.response_code = response.authorization
    payment.avs_response = response.avs_result['code']
    payment.complete
  else
    payment.fail
    gateway_error(response) unless response.success?
  end
rescue ActiveMerchant::ConnectionError => e
  gateway_error t(:unable_to_connect_to_gateway)
end

#record_log(payment, response) ⇒ Object



196
197
198
# File 'app/models/creditcard.rb', line 196

def record_log(payment, response)
  payment.log_entries.create(:details => response.to_yaml)
end

#set_last_digitsObject



22
23
24
25
26
# File 'app/models/creditcard.rb', line 22

def set_last_digits
  number.to_s.gsub!(/\s/,'') unless number.nil?
  verification_value.to_s.gsub!(/\s/,'') unless number.nil?
  self.last_digits ||= number.to_s.length <= 4 ? number : number.to_s.slice(-4..-1)
end

#spree_cc_typeObject



237
238
239
240
# File 'app/models/creditcard.rb', line 237

def spree_cc_type
  return "visa" if ENV['RAILS_ENV'] == "development"
  self.class.type?(number)
end

#verification_value?Boolean

Returns:

  • (Boolean)


44
45
46
# File 'app/models/creditcard.rb', line 44

def verification_value?
  !verification_value.blank?
end

#void(payment) ⇒ Object



122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'app/models/creditcard.rb', line 122

def void(payment)
  response = payment_gateway.void(payment.response_code, self, minimal_gateway_options(payment))
  record_log payment, response

  if response.success?
    payment.response_code = response.authorization
    payment.void
  else
    gateway_error(response)
  end
rescue ActiveMerchant::ConnectionError => e
  gateway_error I18n.t(:unable_to_connect_to_gateway)
end