Class: Caboose::Authnet

Inherits:
Object
  • Object
show all
Defined in:
app/models/caboose/authnet.rb

Instance Method Summary collapse

Constructor Details

#initialize(login_id, trans_key) ⇒ Authnet

Returns a new instance of Authnet.



9
10
11
12
# File 'app/models/caboose/authnet.rb', line 9

def initialize(, trans_key)
  @api_login_id = 
  @api_transaction_key = trans_key
end

Instance Method Details

#create_empty_payment_profile(user) ⇒ Object

Create empty payment profile



242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
# File 'app/models/caboose/authnet.rb', line 242

def create_empty_payment_profile(user)      
  options = {
    :customer_profile_id => user.authnet_customer_profile_id.to_i,      
    :payment_profile => {
      :bill_to => { :first_name => user.first_name, :last_name => user.last_name, :address => '', :city => '', :state => '', :zip => '', :phone_number => '', :email => user.email },        
      :payment => { :credit_card => Caboose::StdClass.new({ :number => '4111111111111111', :month => 1, :year => 2020, :first_name => user.first_name, :last_name => user.last_name }) }
    }
    #, :validation_mode => :live
  }    
  resp = self.gateway.create_customer_payment_profile(options)            
  if resp.success?        
    user.authnet_payment_profile_id = resp.params['customer_payment_profile_id']        
    user.save
  else
    puts "=================================================================="            
    puts resp.message
    puts ""
    puts resp.inspect
    puts "=================================================================="
  end
end

#customer_profile(user) ⇒ Object

Create or update the CIM record in authorize.net for the given user.



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'app/models/caboose/authnet.rb', line 26

def customer_profile(user)
  resp = Caboose::StdClass.new('success' => true)    
  options = { :profile => { :merchant_customer_id => user.id, :email => user.email }}
  
  if user.authnet_customer_profile_id.nil? || user.authnet_customer_profile_id.strip.length == 0 # No customer profile, so create it 
    response = self.gateway.create_customer_profile(options)
    if response.success?
      user.authnet_customer_profile_id = response.params['customer_profile_id']
      user.save
    elsif response.message.starts_with?("A duplicate record with ID ")
      user.authnet_customer_profile_id = response.message.gsub("A duplicate record with ID ", '').gsub(" already exists.", '')
      user.save
    else
      resp.success = false
      resp.error = "A fatal error occured, the web administrator has been notified. Please try again later."        
    end        	
  else # Update the profile
    options[:profile][:customer_profile_id] = user.authnet_customer_profile_id      
    response = self.gateway.update_customer_profile(options)    
    if !response.success?
      resp.success = false
      resp.error = "A fatal error occured, the web administrator has been notified. Please try again later."        
    end
  end
  return resp 
end

#gatewayObject



14
15
16
17
18
19
20
21
22
# File 'app/models/caboose/authnet.rb', line 14

def gateway
  return @_gateway if @_gateway
  @_gateway = ActiveMerchant::Billing::AuthorizeNetCimGateway.new(
    :login    => @api_login_id,
    :password => @api_transaction_key,
    :test     => false
  )
  return @_gateway
end

#get_card_suffix(user) ⇒ Object

Get card number from profile



304
305
306
307
308
309
310
311
312
313
314
315
316
# File 'app/models/caboose/authnet.rb', line 304

def get_card_suffix(user)
  card_number = nil
  if user.valid_authnet_payment_profile_id && user.authnet_payment_profile_id
    resp = self.gateway.get_customer_payment_profile({
      :customer_profile_id => user.authnet_customer_profile_id.to_i,
      :customer_payment_profile_id => user.authnet_payment_profile_id.to_i
    })            
    if resp.success? && resp.params['payment_profile'] && resp.params['payment_profile']['payment'] && resp.params['payment_profile']['payment']['credit_card'] && resp.params['payment_profile']['payment']['credit_card']['card_number']                         
      card_number = resp.params['payment_profile']['payment']['credit_card']['card_number'].gsub('X', '')         
    end
  end    
  return card_number
end

#get_hosted_profile_page_request(profile_id, return_url) ⇒ Object

Get hosted profile token


268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
# File 'app/models/caboose/authnet.rb', line 268

def get_hosted_profile_page_request(profile_id, return_url)
    
  xml = ""
  xml << "<?xml version=\"1.0\"?>\n"
  xml << "<getHostedProfilePageRequest xmlns=\"AnetApi/xml/v1/schema/AnetApiSchema.xsd\">\n"    
  xml << "  <merchantAuthentication>\n"             
  xml << "    <name>#{@api_login_id}</name>\n"
  xml << "    <transactionKey>#{@api_transaction_key}</transactionKey>\n"
  xml << "  </merchantAuthentication>\n"
  xml << "  <customerProfileId>#{profile_id}</customerProfileId>\n"
  xml << "  <hostedProfileSettings>\n"
  xml << "    <setting><settingName>hostedProfilePageBorderVisible</settingName><settingValue>false</settingValue></setting>\n"
  xml << "    <setting><settingName>hostedProfileHeadingBgColor</settingName><settingValue>#ffffff</settingValue></setting>\n"
  xml << "    <setting><settingName>hostedProfileBillingAddressRequired</settingName><settingValue>true</settingValue></setting>\n"
  xml << "    <setting><settingName>hostedProfileCardCodeRequired</settingName><settingValue>true</settingValue></setting>\n"
  xml << "    <setting><settingName>hostedProfileReturnUrl</settingName><settingValue>#{return_url}</settingValue></setting>\n"
  xml << "  </hostedProfileSettings>\n"
  xml << "</getHostedProfilePageRequest>\n"
  
  response = HTTParty.post('https://api.authorize.net/xml/v1/request.api', { :body => xml, :headers => { 'Content-Type' => 'text/xml' }})
  #Caboose.log(response.body)
  
  # Note: Can't parse response with httparty because of namespace issue in the 
  #       response xml. Have to strip the namespace out before parsing.            
  str = response.body.gsub("xmlns=\"AnetApi/xml/v1/schema/AnetApiSchema.xsd\"", '')
  xml = Nokogiri::XML(str)
  token_nodes = xml.xpath('//getHostedProfilePageResponse//token')
  token = token_nodes ? token_nodes.first.content : nil
  #Caboose.log(token)
  
  return token    
end

#payment_profile(user, params) ⇒ Object

Create or update the authorize.net payment profile for the given user.



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'app/models/caboose/authnet.rb', line 55

def payment_profile(user, params)
  resp = Caboose::StdClass.new('success' => true)            
  response = nil
  
  card_num = params[:credit_card][:number]
  user.card_brand = 'Amex'       if card_num.starts_with?('3')   
  user.card_brand = 'Visa'       if card_num.starts_with?('4')   
  user.card_brand = 'MasterCard' if card_num.starts_with?('5')   
  user.card_brand = 'Discover'   if card_num.starts_with?('6011')
  user.save

  # Make sure the customer profile exists    
  if user.authnet_customer_profile_id.nil?      
    response = self.customer_profile(user)
    if !response.success
      user.authnet_customer_profile_id = nil
      user.authnet_payment_profile_id = nil
      user.save
      resp.error = "Error creating customer profile."
    else
      user.authnet_payment_profile_id = nil
      user.save
    end
  end

  # Now see if the payment profile exists
  if user.authnet_customer_profile_id && user.authnet_payment_profile_id
    options = payment_profile_options(user, params)
    options[:payment_profile][:customer_payment_profile_id] = user.authnet_payment_profile_id
    response = self.gateway.update_customer_payment_profile(options)            
    if response.success?
      user.authnet_payment_profile_id = response.params['customer_payment_profile_id']        
      user.save        
      resp.success = true
    elsif response.message == 'ProfileID is invalid.'
      user.authnet_customer_profile_id = nil
      user.authnet_payment_profile_id = nil
      user.save
      resp.error = "Invalid customer profile ID. Please submit again."
    elsif response.message == "The credit card number is invalid."
      resp.error = "The credit card number is invalid."
    elsif response.message == "This transaction has been declined."                
      resp.error = "We couldn't validate the credit card information."
    elsif response.message == "A duplicate transaction has been submitted." # The user submitted the same information within two minutes                
      resp.error = "We couldn't validate the credit card information."
    else        
      puts "=================================================================="
      puts "Response from gateway.update_customer_payment_profile(#{options})"
      puts ""
      puts response.message
      puts ""
      puts response.inspect
      puts "=================================================================="
      user.authnet_payment_profile_id = nil
      user.save        
    end
  end
  
  if user.authnet_customer_profile_id && user.authnet_payment_profile_id.nil?
    options = payment_profile_options(user, params)
    response = self.gateway.create_customer_payment_profile(options)            
    if response.success?        
      user.authnet_payment_profile_id = response.params['customer_payment_profile_id']        
      user.save
      resp.success = true        
    elsif response.message == "A duplicate customer payment profile already exists."
      response = self.gateway.get_customer_profile({ :customer_profile_id => user.authnet_customer_profile_id })        
      if response.success?
        arr = response.params['profile']['payment_profiles']
        arr = [arr] if arr.is_a?(Hash)
        arr.each do |h|
          if h['payment'] && h['payment']['credit_card'] && h['payment']['credit_card']['card_number']
            x = h['payment']['credit_card']['card_number'].split(//).last(4).join("")
            y = params[:credit_card][:number].split(//).last(4).join("")            
            if x == y
              user.authnet_payment_profile_id = h['customer_payment_profile_id']
              user.save
              break
            end
          end
        end
      end
    elsif response.message == "The credit card number is invalid."                
      resp.error = "The credit card number is invalid."
    elsif response.message == "This transaction has been declined."        
      resp.error = "We couldn't validate the credit card information."
    elsif response.message == "A duplicate transaction has been submitted." # The user submitted the same information within two minutes        
      resp.error = "We couldn't validate the credit card information."
    else
      puts "=================================================================="
      puts "Response from gateway.create_customer_payment_profile(#{options})"
      puts ""
      puts response.message
      puts ""
      puts response.inspect
      puts "=================================================================="
      resp.error = "A fatal error occured, the web administrator has been notified. Please try again later."
    end          
  end
  return resp
end

#payment_profile_options(user, params) ⇒ Object

Returns the options hash for the gateway.create_customer_payment_profile method.


159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'app/models/caboose/authnet.rb', line 159

def payment_profile_options(user, params)
  bt_address = "#{params[:billing][:address]}"
  bt_address << ", #{params[:billing][:address2]}" if params[:billing][:address2] && params[:billing][:address2].strip.length > 0          
            
  return {      
    :customer_profile_id => user.authnet_customer_profile_id.to_i,      
    :payment_profile => {
      :bill_to => {
        :first_name   => params[:billing][:first_name],
        :last_name    => params[:billing][:last_name],
        :address      => bt_address,
        :city         => params[:billing][:city],
        :state        => params[:billing][:state],
        :zip          => params[:billing][:zip],
        :phone_number => user.phone,
        :email        => user.email
      },        
      :payment => {
        :credit_card => Caboose::StdClass.new({
          :number     => params[:credit_card][:number],
          :month      => params[:credit_card][:expiration_month].to_i,
          :year       => "20#{params[:credit_card][:expiration_year].to_i}",
          :first_name => params[:billing][:first_name],
          :last_name  => params[:billing][:last_name]
        })
      }
    },
    :validation_mode => :live
  }
end

#verify_customer_profile(user) ⇒ Object

Verifies that the given user has a CIM record.



192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
# File 'app/models/caboose/authnet.rb', line 192

def verify_customer_profile(user)

  if user.authnet_customer_profile_id
    resp = self.gateway.get_customer_profile({ :customer_profile_id => user.authnet_customer_profile_id })
    if resp.success? # The profile id is valid
      return true
    else
      user.authnet_customer_profile_id = nil
      user.save
    end
  end

  # No customer profile, so create it 
  resp = self.gateway.create_customer_profile({ :profile => { :merchant_customer_id => user.id, :email => user.email }})
  Caboose.log(resp.inspect)
  if resp.success?
    user.authnet_customer_profile_id = resp.params['customer_profile_id']
    user.save
  elsif resp.message.starts_with?("A duplicate record with ID ")
    user.authnet_customer_profile_id = resp.message.gsub("A duplicate record with ID ", '').gsub(" already exists.", '')
    user.save
  else
    Caboose.log("Error creating authnet customer profile for user #{user.id}")
    return false                
  end
  return true         
end

#verify_payment_profile(user) ⇒ Object

Verifies that the user has a payment profile and that the payment profile is valid. Creates an empty payment profile for the user if the payment profile is missing or invalid.



223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
# File 'app/models/caboose/authnet.rb', line 223

def verify_payment_profile(user)            
  resp = self.gateway.get_customer_profile({ :customer_profile_id => user.authnet_customer_profile_id })      
  if resp.success?
    arr = resp.params['profile']['payment_profiles']      
    arr = [arr] if arr && arr.is_a?(Hash)
    if arr.nil? || arr.count == 0
      self.create_empty_payment_profile(user)
      user.valid_authnet_payment_profile_id = false        
    else                
      h = arr[0]
      user.authnet_payment_profile_id = h['customer_payment_profile_id']                 
      user.valid_authnet_payment_profile_id = h['bill_to'] && h['bill_to']['address'] && h['bill_to']['address'].strip.length > 0                    
      user.save
    end
  end    
end