Class: Creditcard

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

Direct Known Subclasses

TestCard

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



174
175
176
# File 'app/models/creditcard.rb', line 174

def actions
  %w{capture void credit}
end

#authorize(amount, payment) ⇒ Object



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

def authorize(amount, payment)
  # ActiveMerchant is configured to use cents so we need to multiply order total by 100
  payment_gateway = payment.payment_method
  check_environment(payment_gateway)

  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
  gateway_error I18n.t(:unable_to_connect_to_gateway)
end

#brandObject

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



56
57
58
# File 'app/models/creditcard.rb', line 56

def brand
  cc_type
end

#can_capture?(payment) ⇒ Boolean

Indicates whether its possible to capture the payment

Returns:

  • (Boolean)


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

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

#can_credit?(payment) ⇒ Boolean

Indicates whether its possible to credit the payment. Note that most gateways require that the payment be settled first which generally happens within 12-24 hours of the transaction.

Returns:

  • (Boolean)


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

def can_credit?(payment)
  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.

Returns:

  • (Boolean)


184
185
186
# File 'app/models/creditcard.rb', line 184

def can_void?(payment)
  payment.state == "void" ? false : true
end

#capture(payment) ⇒ Object



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'app/models/creditcard.rb', line 102

def capture(payment)
  return unless payment.pending?
  payment_gateway = payment.payment_method
  check_environment(payment_gateway)

  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
  gateway_error I18n.t(:unable_to_connect_to_gateway)
end

#check_environment(gateway) ⇒ Object

Saftey check to make sure we’re not accidentally performing operations on a live gateway. Ex. When testing in staging environment with a copy of production data.



248
249
250
251
252
# File 'app/models/creditcard.rb', line 248

def check_environment(gateway)
  return if gateway.environment == Rails.env
  message = I18n.t(:gateway_config_unavailable) + " - #{Rails.env}"
  raise Spree::GatewayError.new(message)
end

#credit(payment) ⇒ Object



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'app/models/creditcard.rb', line 146

def credit(payment)
  payment_gateway = payment.payment_method
  check_environment(payment_gateway)

  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
  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)



47
48
49
# File 'app/models/creditcard.rb', line 47

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

#first_name?Boolean

Returns:

  • (Boolean)


30
31
32
# File 'app/models/creditcard.rb', line 30

def first_name?
  first_name.present?
end

#gateway_error(error) ⇒ Object



204
205
206
207
208
209
210
211
212
213
# File 'app/models/creditcard.rb', line 204

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



215
216
217
218
219
# File 'app/models/creditcard.rb', line 215

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



222
223
224
225
226
# File 'app/models/creditcard.rb', line 222

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)


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

def has_payment_profile?
  gateway_customer_profile_id.present?
end

#last_name?Boolean

Returns:

  • (Boolean)


34
35
36
# File 'app/models/creditcard.rb', line 34

def last_name?
  last_name.present?
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.



231
232
233
234
235
236
237
238
239
# File 'app/models/creditcard.rb', line 231

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



38
39
40
# File 'app/models/creditcard.rb', line 38

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

#name?Boolean

Returns:

  • (Boolean)


26
27
28
# File 'app/models/creditcard.rb', line 26

def name?
  first_name? && last_name?
end

#process!(payment) ⇒ Object



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

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

#purchase(amount, payment) ⇒ Object



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

def purchase(amount, payment)
  #combined Authorize and Capture that gets processed by the ActiveMerchant gateway as one single transaction.
  payment_gateway = payment.payment_method
  check_environment(payment_gateway)

  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
  gateway_error t(:unable_to_connect_to_gateway)
end

#record_log(payment, response) ⇒ Object



200
201
202
# File 'app/models/creditcard.rb', line 200

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

#set_last_digitsObject



20
21
22
23
24
# File 'app/models/creditcard.rb', line 20

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



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

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

#verification_value?Boolean

Returns:

  • (Boolean)


42
43
44
# File 'app/models/creditcard.rb', line 42

def verification_value?
  verification_value.present?
end

#void(payment) ⇒ Object



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'app/models/creditcard.rb', line 129

def void(payment)
  payment_gateway = payment.payment_method
  check_environment(payment_gateway)

  response = payment_gateway.void(payment.response_code, 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
  gateway_error I18n.t(:unable_to_connect_to_gateway)
end