3/25/10

Tips for building a CIM module in asp.net

**** NOTE: These functions re-written on 4/10/11. the upedated functions return more authorization data, and have a consistent naming scheme. I was going to use the sdk compiled code, but there was no method to create a profile and payment profile at the same time, resulting in twice the number of calls. This code will accomplish the same tasks that I need, and with fewer api calls. ******

Recently, I had to make an interface for the authorize.net CIM (Customer Information Management) web service, in order to store credit-card data off site in a pci-compliant manner. The authorize.net CIM service stores all kinds of customer and order data, but I only send it the info needed to charge a card (billing address, name, and card info). The steps in an average transaction are:


  • send request to create customer and payment profile

  • parse the response

  • send request for transaction (charge, void, or refund)

  • parse the response

Each communication and response is in the form of an xml file. The request is sent as an https post, and the response is sent back with the page request.


The first thing you will need is a function to send an https post request. The other functions will create an xml file in memory and write it to a string for the http post function. The http request returns an xml doc, which needs to be parsed, which is handled by some of the other fuinctions here.



Imports Microsoft.VisualBasic
Imports System.IO
Imports System.Xml
Imports System.Net
Imports weborders
Imports System.Text
Imports System.Web.HttpUtility

Public Class api

Public Shared Function PostData(ByVal data As String, ByVal url As String) As String

Dim response As String = ""
Dim tmpstr As String = ""
Try
Dim request As HttpWebRequest = WebRequest.Create(url)
request.Method = WebRequestMethods.Http.Post
request.ContentType = "text/xml"
request.ContentLength = data.Length
request.Timeout = 25000
Dim writer As New StreamWriter(request.GetRequestStream(), System.Text.Encoding.ASCII)
writer.Write(data)
writer.Close()

Dim stream As Stream = request.GetResponse().GetResponseStream()
Dim reader As New StreamReader(stream)
tmpstr = reader.ReadToEnd()
response = tmpstr
Catch ex As Exception
response = ex.Message
End Try
''get rid of namespace
response = response.Replace("xmlns:", "noname")
response = response.Replace("xmlns", "noname")
Return response
End Function

Public Shared Function xml_MerchAuth(ByRef xmlobj As XmlTextWriter) As Boolean
Dim loginname As String = ConstClass.ReadAppSettings("api_loginname")
Dim transactkey As String = ConstClass.ReadAppSettings("api_transactkey")
xmlobj.WriteStartElement("merchantAuthentication")
xmlobj.WriteElementString("name", loginname)
xmlobj.WriteElementString("transactionKey", transactkey)
xmlobj.WriteEndElement()
Return True
End Function

Public Shared Function apicall_get_response_type(ByRef xd As XmlDocument) As String
Dim t As String = "NA"
Try
t = xd.SelectSingleNode("/*").Name
Catch ex As Exception
End Try
Return t
End Function
Public Shared Function apicall_get_messages_resultCode(ByRef xd As XmlDocument) As String
Dim t As String = ""
Try
t = xd.SelectSingleNode("/*/messages/resultCode").InnerText
Catch
End Try
Return t
End Function
Public Shared Function apicall_get_messages_message_code(ByRef xd As XmlDocument) As String
Dim t As String = ""
Try
t = xd.SelectSingleNode("/*/messages/message/code").InnerText
Catch ex As Exception
End Try
Return t
End Function

Public Shared Function apicall_get_messages_message_text(ByRef xd As XmlDocument) As String
Dim t As String = ""
Try
t = xd.SelectSingleNode("/*/messages/message/text").InnerText
Catch ex As Exception
End Try
Return t
End Function
Public Shared Function apicall_get_customerProfileId(ByRef xd As XmlDocument) As String
Dim t As String = ""
Try
t = xd.SelectSingleNode("/createCustomerProfileResponse/customerProfileId").InnerText
Catch ex As Exception
End Try
Return t
End Function
Public Shared Function apicall_get_PayProfileId(ByRef xd As XmlDocument) As String
Dim t As String = ""
Try
t = xd.SelectSingleNode("/*/customerPaymentProfileIdList/numericString").InnerText
Catch ex As Exception
End Try
Return t
End Function
Public Shared Function apicall_get_tran_directResponse(ByRef xd As XmlDocument) As String
Dim t As String = ""
Try
t = xd.SelectSingleNode("/createCustomerProfileTransactionResponse/directResponse").InnerText
Catch ex As Exception
End Try
Return t
End Function
Public Shared Function apicall_get_profile_directResponse(ByRef xd As XmlDocument) As String
Dim t As String = ""
Try
t = xd.SelectSingleNode("/*/validationDirectResponseList/string").InnerText
Catch ex As Exception
End Try
Return t
End Function
Public Shared Function apicall_get_udprofile_directResponse(ByRef xd As XmlDocument) As String
Dim t As String = ""
Try
t = xd.SelectSingleNode("/*/validationDirectResponse").InnerText
Catch ex As Exception
End Try
Return t
End Function


Public Shared Function apicall_create_profile(ByVal orderid As Integer, ByVal fname As String, _
ByVal lname As String, ByVal company As String, ByVal address As String, ByVal city As String, _
ByVal state As String, ByVal zip As String, ByVal country As String, ByVal phone As String, _
ByVal fax As String, ByVal cardnumber As String, ByVal exp As String, _
ByVal cardcode As String, ByVal bank_routing As String, ByVal bank_account As String, ByVal bank_nameonacct As String, _
ByVal bankName As String, ByVal accountType As String, _
ByVal is_bank As Boolean, ByVal validate As Boolean, ByRef out_message As String, ByRef out_code As String) _
As Boolean 'will return "I00001" or error text if error.
'out message returns reason for decline, or success message
'out_code returns response code (I00001, etc)

Dim vmode As String = "testMode" 'will only validate fields
If validate Then vmode = "liveMode" 'will send test transaction to processor for 0.01

If orderid = Nothing Then
out_code = "null"
out_message = "order id is not set"
Return False
End If
If is_bank = False And cardnumber.Length < 13 Or cardnumber.Length > 16 Then
out_code = "ER"
out_message = "Card number length is not valid"
Return False
End If
If is_bank = True And (bank_routing.Length <> 9 Or bank_account.Length < 5 Or bank_account.Length > 17 Or bank_nameonacct.Length = 0) Then
out_code = "ER"
out_message = "Bank account information is not valid."
Return False
End If

Dim RandomClass As New Random()
Dim last4 As String = ""
If is_bank Then
last4 = bank_account.Substring(bank_account.Length - 4, 4)
Else
last4 = cardnumber.Substring(cardnumber.Length - 4, 4)
End If
If bank_nameonacct.Length > 22 Then bank_nameonacct = bank_nameonacct.Substring(0, 22)

Dim callstr As String = ""
Dim memory_stream As New MemoryStream
Dim writer As New XmlTextWriter(memory_stream, System.Text.Encoding.UTF8)

Try
writer.Formatting = Formatting.Indented
writer.Indentation = 4
writer.WriteStartDocument(True)

writer.WriteStartElement("createCustomerProfileRequest")
writer.WriteAttributeString("xmlns", "AnetApi/xml/v1/schema/AnetApiSchema.xsd")
api.xml_MerchAuth(writer) 'this adds the xml that will authenticate to auth.net
writer.WriteStartElement("profile")
writer.WriteElementString("merchantCustomerId", orderid.ToString)
writer.WriteElementString("description", RandomClass.Next().ToString)
writer.WriteStartElement("paymentProfiles")
writer.WriteStartElement("billTo")
writer.WriteElementString("firstName", fname)
writer.WriteElementString("lastName", lname)
writer.WriteElementString("company", company)
writer.WriteElementString("address", address)
writer.WriteElementString("city", city)
writer.WriteElementString("state", state)
writer.WriteElementString("zip", zip)
writer.WriteElementString("country", country)
writer.WriteElementString("phoneNumber", phone)
writer.WriteElementString("faxNumber", fax)
writer.WriteEndElement() 'end for billTo
writer.WriteStartElement("payment")

If is_bank = False Then
writer.WriteStartElement("creditCard")
writer.WriteElementString("cardNumber", cardnumber)
writer.WriteElementString("expirationDate", exp) ''YYYY-MM
If cardcode.Length > 0 Then writer.WriteElementString("cardCode", cardcode) ''cvv/cvv2...
writer.WriteEndElement() 'end for creditcard
Else
writer.WriteStartElement("bankAccount")
writer.WriteElementString("accountType", accountType) ''(checking|savings)
writer.WriteElementString("bankName", bankName) ''(checking|savings)

writer.WriteElementString("routingNumber", bank_routing)
writer.WriteElementString("accountNumber", bank_account)
writer.WriteElementString("nameOnAccount", bank_nameonacct)
writer.WriteElementString("echeckType", "WEB") ''(CCD|PPD|TEL|WEB)
writer.WriteEndElement() 'end for bankAcount
End If

writer.WriteEndElement() 'end for payment
writer.WriteEndElement() 'end for payprofiles
writer.WriteEndElement() 'end for profile
writer.WriteElementString("validationMode", vmode)
writer.WriteEndElement() 'end for createcustomer...
writer.WriteEndDocument()
writer.Flush()

Dim stream_reader As New StreamReader(memory_stream)
memory_stream.Seek(0, SeekOrigin.Begin)
callstr = stream_reader.ReadToEnd()
writer.Close()
Catch ex As Exception
ConstClass.record_error("api.vb: apicall_create_profile, generate xml", ex.ToString)
out_code = "ER"
out_message = "Error constructing XML"
Return False
End Try


Dim response As String = "" 'string containing xml response
Dim xd As XmlDocument = New XmlDocument()
Try
response = PostData(callstr, ConstClass.ReadAppSettings("api_url"))
If response = "Unable to connect to the remote server" Then
out_code = "TO"
out_message = response
Return False
Else
xd.LoadXml(response)
End If
Catch ex As Exception
ConstClass.record_error("api.vb: apicall_create_profile, get response", ex.ToString)
out_code = "ER"
out_message = "Unable to load response."
Return False
End Try

Dim responsetype As String = "", profileid As Integer = 0, payprofileid As Integer = 0
Dim authmessage As String = ""
Dim auth_response_code As String = "", auth_response_reason_code As String = "", db_reason_text As String = ""
Try
responsetype = apicall_get_response_type(xd)
out_code = apicall_get_messages_message_code(xd)
out_message = "Message: " + apicall_get_messages_message_text(xd)
authmessage = apicall_get_profile_directResponse(xd)
If authmessage <> "" Then
auth_response_code = authmessage.Split(",")(0) '1
auth_response_reason_code = authmessage.Split(",")(2) '3
out_message = authmessage.Split(",")(3) '4

'get translation for common errors from db;
Dim qta As New weborders_apiTableAdapters.QueriesTableAdapter
db_reason_text = qta.get_decline_message(auth_response_code, auth_response_reason_code)
If db_reason_text <> "" Then out_message = db_reason_text

End If
Catch ex As Exception
ConstClass.record_error("api.vb: apicall_create_profile, parse response", ex.ToString)
out_code = "ER"
out_message = "Unable to parse response."
Return False
End Try

If responsetype = "ErrorResponse" Then Return False

'record new profile/payprofileid's if not error
If out_code = "I00001" Then
Try
profileid = api.apicall_get_customerProfileId(xd)
payprofileid = api.apicall_get_PayProfileId(xd)
Catch ex As Exception
ConstClass.record_error("api.vb: apicall_create_profile, parse profileid", ex.ToString)
out_code = "ER"
out_message = "Unable to parse profile_ids"
Return False
End Try
Try
Dim cctype As Integer = -1, ccdigit As String = ""
If is_bank = False Then
ccdigit = cardnumber.Substring(0, 1)
If cardnumber.Length = 14 And ccdigit = "3" Then
cctype = 5 'DinersClub
ElseIf ccdigit = "4" Then
cctype = 1 'visa
ElseIf ccdigit = "5" Then
cctype = 2 'MC
ElseIf ccdigit = "3" Then
cctype = 3 'Amex
ElseIf ccdigit = "6" Then
cctype = 4 'Discover
End If
Else
cctype = 101 'EFT bank transfer
End If
If exp = "" Then exp = "3000-01"
Dim tc As New webordersTableAdapters.ordersTableAdapter
tc.UpdateQuery_cim(1, last4, exp, profileid, payprofileid, cctype, orderid)
Catch ex As Exception
ConstClass.record_error("api.vb: apicall_create_profile, record response", ex.ToString)
out_code = "ER"
out_message = "Unable to record response."
Return False
End Try
End If
If out_code = "" Then out_code = "ER"

If out_code = "I00001" Then
Return True
Else
Return False 'if not I00001, the profile did not validate.
End If
End Function

Public Shared Function apicall_update_payment_profile(ByVal profileid As Integer, ByVal payprofileid As Integer, _
ByVal userid As Integer, ByVal newccnum As String, ByVal newexp As String, ByVal orderid As Integer, _
ByVal is_bank As Boolean, ByVal bank_account As String, ByVal bank_routing As String, ByVal bank_nameonacct As String, _
ByVal validate As Boolean, ByRef out_code As String, ByRef out_message As String) As Boolean

Dim callstr As String = ""
Dim memory_stream As New MemoryStream
Dim writer As New XmlTextWriter(memory_stream, System.Text.Encoding.UTF8)
Dim vmode As String = "testMode" 'will only validate fields
If validate Then vmode = "liveMode" 'will send test transaction to processor for 0.01

If bank_nameonacct.Length > 22 Then bank_nameonacct = bank_nameonacct.Substring(0, 22)

Dim last4 As String = ""
If is_bank = True Then
last4 = bank_account.Substring(bank_account.Length - 4, 4)
Else
last4 = newccnum.Substring(newccnum.Length - 4, 4)
End If

Try
writer.Formatting = Formatting.Indented
writer.Indentation = 4
writer.WriteStartDocument(True)

writer.WriteStartElement("updateCustomerPaymentProfileRequest")
writer.WriteAttributeString("xmlns", "AnetApi/xml/v1/schema/AnetApiSchema.xsd")
api.xml_MerchAuth(writer) 'this adds the xml that will authenticate to auth.net

writer.WriteElementString("customerProfileId", profileid)
writer.WriteStartElement("paymentProfile")
writer.WriteStartElement("payment")

If is_bank = False Then
writer.WriteStartElement("creditCard")
writer.WriteElementString("cardNumber", newccnum)
writer.WriteElementString("expirationDate", newexp) ''YYYY-MM
writer.WriteEndElement() 'end for creditcard
Else
writer.WriteStartElement("bankAccount")
'writer.WriteElementString("accountType", accountType) ''(checking|savings)
writer.WriteElementString("routingNumber", bank_routing)
writer.WriteElementString("accountNumber", bank_account)
writer.WriteElementString("nameOnAccount", bank_nameonacct)
writer.WriteElementString("echeckType", "WEB") ''(CCD|PPD|TEL|WEB)
writer.WriteEndElement() 'end for bankAcount
End If

writer.WriteEndElement() 'end for payment
writer.WriteElementString("customerPaymentProfileId", payprofileid)
writer.WriteEndElement() 'end for paymentProfile
writer.WriteElementString("validationMode", vmode)
writer.WriteEndElement() 'end for root element...
writer.WriteEndDocument()
writer.Flush()

Dim stream_reader As New StreamReader(memory_stream)
memory_stream.Seek(0, SeekOrigin.Begin)
callstr = stream_reader.ReadToEnd()
writer.Close()
Catch ex As Exception
ConstClass.record_error("api.vb: apicall_update_payment_profile, generate xml", ex.ToString)
out_code = "ER"
out_message = "error generating xml"
Return False
End Try

Dim responsetype As String = ""
Dim xd As XmlDocument = New XmlDocument()
Dim response As String = "", authmessage As String = ""
Dim auth_response_code As String = "", auth_response_reason_code As String = "", db_reason_text As String = ""
Dim qta As New weborders_apiTableAdapters.QueriesTableAdapter
Try
response = PostData(callstr, ConstClass.ReadAppSettings("api_url"))
xd.LoadXml(response)
responsetype = api.apicall_get_response_type(xd)
out_code = apicall_get_messages_message_code(xd)
out_message = api.apicall_get_messages_message_text(xd)
authmessage = apicall_get_udprofile_directResponse(xd)
If authmessage <> "" Then
auth_response_code = authmessage.Split(",")(0) '1
auth_response_reason_code = authmessage.Split(",")(2) '3
out_message = authmessage.Split(",")(3) '4
End If

'get translation for common errors from db;
db_reason_text = qta.get_decline_message(auth_response_code, auth_response_reason_code)
If db_reason_text <> "" Then out_message = db_reason_text

Catch ex As Exception
ConstClass.record_error("api.vb: apicall_update_payment_profile, get response", ex.ToString)
out_message = "Error loading / parsing response."
out_code = "ER"
Return False
End Try

If responsetype = "ErrorResponse" Then Return False

'record new data if not error
If out_code = "I00001" Then
Try
Dim tc As New webordersTableAdapters.ordersTableAdapter
Dim cctype As Integer = -1, ccdigit As String = ""

If is_bank = False Then
ccdigit = newccnum.Substring(0, 1)
If ccdigit = "X" Or newccnum.Length < 12 Then 'updating only exp
tc.UpdateCim_ccExpirationDt(newexp, orderid)
Else 'updating card number too
If newccnum.Length = 14 And ccdigit = "3" Then
cctype = 5 'DinersClub
ElseIf ccdigit = "4" Then
cctype = 1 'visa
ElseIf ccdigit = "5" Then
cctype = 2 'MC
ElseIf ccdigit = "3" Then
cctype = 3 'Amex
ElseIf ccdigit = "6" Then
cctype = 4 'Discover
End If
tc.Update_cim_cc_payprofile(last4, newexp, cctype, orderid)
End If
Else 'update for bank
tc.Update_cim_cc_payprofile(last4, CDate("1/1/3000"), 101, orderid)
End If
Catch ex As Exception
ConstClass.record_error("api.vb: apicall_update_payment_profile, record response", ex.ToString)
out_message = "Error recording response."
out_code = "ER"
Return False
End Try
End If
If out_code = "I00001" Then
Return True
Else
Return False
End If
End Function


Public Shared Function apicall_create_charge_request(ByVal profileid As Integer, ByVal payprofileid As Integer, _
ByVal amount As Decimal, ByVal ccv As String, ByVal userid As Integer, ByVal orderid As Integer, _
ByVal payscheduleid As Integer, ByVal cctype As Integer, ByVal last4 As String, _
ByRef out_code As String, ByRef out_message As String) As Boolean

Dim callstr As String = "", responsetype As String = ""
Dim authcode As String = "", authmessage As String = ""
Dim authtransid As String = "", authpaymethod As String = "", paymethod As Integer = 0
Dim xd As XmlDocument = New XmlDocument()
Dim response As String = ""

Dim memory_stream As New MemoryStream
Dim writer As New XmlTextWriter(memory_stream, _
System.Text.Encoding.UTF8)
Try
writer.Formatting = Formatting.Indented
writer.Indentation = 4
writer.WriteStartDocument(True)

writer.WriteStartElement("createCustomerProfileTransactionRequest")
writer.WriteAttributeString("xmlns", "AnetApi/xml/v1/schema/AnetApiSchema.xsd")
api.xml_MerchAuth(writer) 'this adds the xml that will authenticate to auth.net
writer.WriteStartElement("transaction")
writer.WriteStartElement("profileTransAuthCapture")
writer.WriteElementString("amount", amount)
writer.WriteElementString("customerProfileId", profileid)
writer.WriteElementString("customerPaymentProfileId", payprofileid)
writer.WriteElementString("recurringBilling", "false")
If ccv.Length > 2 Then
writer.WriteElementString("cardCode", ccv)
End If
writer.WriteEndElement() 'end ProfileTransAuthCapture
writer.WriteEndElement() 'end transaction
writer.WriteEndElement() 'end for base
writer.WriteEndDocument()
writer.Flush()
'dump xml mem stream into string
Dim stream_reader As New StreamReader(memory_stream)
memory_stream.Seek(0, SeekOrigin.Begin)
callstr = stream_reader.ReadToEnd()
writer.Close()
Catch ex As Exception
ConstClass.record_error("api.vb: apicall_create_tran_request, generate xml portion", ex.ToString)
out_code = "ER"
out_message = "error generating xml."
Return False
End Try

'send api request

Try
response = PostData(callstr, ConstClass.ReadAppSettings("api_url"))
If response = "Unable to connect to the remote server" Then
out_code = "TO"
out_message = response
Return False
Else
xd.LoadXml(response)
End If
Catch ex As Exception
ConstClass.record_error("api.vb: apicall_create_tran_request, get response portion", ex.ToString)
out_code = "ER"
out_message = "error getting response ."
Return False
End Try

Try
responsetype = api.apicall_get_response_type(xd)

out_code = api.apicall_get_messages_message_code(xd)
out_message = api.apicall_get_messages_message_text(xd)
authmessage = apicall_get_tran_directResponse(xd)
If responsetype = "ErrorResponse" Then Return False

Dim auth_response_code As String = "", auth_response_reason_code As String = "", db_reason_text As String = ""
If authmessage <> "" Then
auth_response_code = authmessage.Split(",")(0) '1
auth_response_reason_code = authmessage.Split(",")(2) '3
out_message = authmessage.Split(",")(3) '4
authcode = authmessage.Split(",")(4) ''vb.net has 0 based array - auth is 5th record
authtransid = authmessage.Split(",")(6) '7
authpaymethod = authmessage.Split(",")(10) '11

'get translation for common errors from db;
Dim qta As New weborders_apiTableAdapters.QueriesTableAdapter
db_reason_text = qta.get_decline_message(auth_response_code, auth_response_reason_code)
If db_reason_text <> "" Then out_message = db_reason_text

If authpaymethod = "CC" Then
paymethod = 1
End If
If authpaymethod = "ECHECK" Then
paymethod = 2
End If

If out_code = "I00001" Then
Dim pl As New webordersTableAdapters.payments_logTableAdapter
pl.InsertCharge(orderid, profileid, payprofileid, payscheduleid, amount, _
True, authcode, authmessage, userid, authtransid, paymethod, False, 0, 0, cctype, last4)
If payscheduleid > 0 Then
Dim tps As New webordersTableAdapters.payments_scheduledTableAdapter
tps.UpdateStatusById(1, payscheduleid)
End If
End If
End If
Catch ex As Exception
ConstClass.record_error("api.vb: function apicall_create_tran_request, parse xml portion", ex.ToString)
out_code = "ER"
out_message = "Error parsing response."
Return False
End Try

If out_code = "I00001" Then
Return True
Else
Return False
End If
End Function

Public Shared Function _
apicall_create_void_request(ByVal userid As Integer, ByVal gateway_id As Long, ByVal paymentid As Integer, _
ByVal payscheduleid As Integer, ByRef out_code As String, ByRef out_message As String) As Boolean
Dim refid As String = "" ''dont have a use for it yet...
Dim callstr As String = ""
Dim memory_stream As New MemoryStream
Dim responsetype As String = ""
Try
Dim writer As New XmlTextWriter(memory_stream, _
System.Text.Encoding.UTF8)

writer.Formatting = Formatting.Indented
writer.Indentation = 4
writer.WriteStartDocument(True)

writer.WriteStartElement("createCustomerProfileTransactionRequest")
writer.WriteAttributeString("xmlns", "AnetApi/xml/v1/schema/AnetApiSchema.xsd")
api.xml_MerchAuth(writer) 'this adds the xml that will authenticate to auth.net
writer.WriteStartElement("transaction")
writer.WriteStartElement("profileTransVoid")
writer.WriteElementString("transId", gateway_id)
writer.WriteEndElement() 'profileTransvoid
writer.WriteEndElement() 'transaction
writer.WriteEndElement() 'createcustomer...
writer.WriteEndDocument()
writer.Flush()
Dim stream_reader As New StreamReader(memory_stream)
memory_stream.Seek(0, SeekOrigin.Begin)
callstr = stream_reader.ReadToEnd()
writer.Close()
Catch ex As Exception
ConstClass.record_error("api.vb: function apicall_create_void_request, xml generate request portion", ex.ToString)
out_code = "ER"
out_message = "Error generating xml."
Return False
End Try

Dim xd As XmlDocument = New XmlDocument()
Dim response As String = ""

Try
'send api request
response = PostData(callstr, ConstClass.ReadAppSettings("api_url"))

If response = "Unable to connect to the remote server" Then
out_code = "TO"
out_message = response
Return False
Else
xd.LoadXml(response)
End If
Catch ex As Exception
ConstClass.record_error("api.vb: function apicall_create_void_request, response portion", ex.ToString)
out_code = "ER"
out_message = "Error loading response."
Return False
End Try

Try
out_code = apicall_get_messages_message_code(xd)
out_message = apicall_get_messages_message_text(xd)
If out_code = "I00001" Then
Dim tc As New webordersTableAdapters.payments_logTableAdapter
tc.UpdateVoid(userid, paymentid)
If payscheduleid > 0 Then
Dim psta As New webordersTableAdapters.payments_scheduledTableAdapter
psta.UpdateStatusById(0, payscheduleid)
End If
Return True
Else
Return False
End If
Catch ex As Exception
ConstClass.record_error("api.vb: function apicall_create_void_request, parse response portion", ex.ToString)
out_code = "ER"
out_message = "Error parsing response."
Return False
End Try
End Function

Public Shared Function _
apicall_create_refund_request(ByVal orderid As Integer, ByVal userid As Integer, ByVal gateway_id As Long, ByVal paymentid As Integer, _
ByVal payscheduleid As Integer, ByVal profileid As Integer, ByVal payprofileid As Integer, _
ByVal amount As Decimal, ByRef out_code As String, ByRef out_message As String) As Boolean

Dim callstr As String = ""
Dim memory_stream As New MemoryStream
Dim writer As New XmlTextWriter(memory_stream, System.Text.Encoding.UTF8)
Dim response As String = "", responsetype As String = ""
Dim xd As XmlDocument = New XmlDocument()
Dim authcode As String = ""
Dim authtransid As String = "", paymethod As Integer = 0
Try
writer.Formatting = Formatting.Indented
writer.Indentation = 4
writer.WriteStartDocument(True)
writer.WriteStartElement("createCustomerProfileTransactionRequest")
writer.WriteAttributeString("xmlns", "AnetApi/xml/v1/schema/AnetApiSchema.xsd")
api.xml_MerchAuth(writer) 'this adds the xml that will authenticate to auth.net
writer.WriteStartElement("transaction")
writer.WriteStartElement("profileTransRefund")
writer.WriteElementString("amount", amount)
writer.WriteElementString("customerProfileId", profileid)
writer.WriteElementString("customerPaymentProfileId", payprofileid)
writer.WriteElementString("transId", gateway_id) 'original transaction id
writer.WriteEndElement() 'profileTransRefund
writer.WriteEndElement() 'transaction
writer.WriteEndElement() 'createcustomer...
writer.WriteEndDocument()
writer.Flush()
Dim stream_reader As New StreamReader(memory_stream)
memory_stream.Seek(0, SeekOrigin.Begin)
callstr = stream_reader.ReadToEnd()
writer.Close()
Catch ex As Exception
ConstClass.record_error("api.vb: function apicall_create_refund_request, generate xml portion", ex.ToString)
out_code = "ER"
out_message = "Error generating xml."
Return False
End Try
Try
'send api request
response = PostData(callstr, ConstClass.ReadAppSettings("api_url"))
If response = "Unable to connect to the remote server" Then
out_code = "TO"
out_message = response
Return False
Else
xd.LoadXml(response)
End If
Catch ex As Exception
ConstClass.record_error("api.vb: function apicall_create_refund_request, get response portion", ex.ToString)
out_code = "ER"
out_message = "Error loading response."
Return False
End Try

Dim auth_response_code As String = "", auth_response_reason_code As String = "", db_reason_text As String = ""
Dim qta As New weborders_apiTableAdapters.QueriesTableAdapter
Try
out_code = api.apicall_get_messages_message_code(xd)
out_message = api.apicall_get_messages_message_text(xd)
Dim authmessage As String = apicall_get_tran_directResponse(xd)
If authmessage <> "" Then
auth_response_code = authmessage.Split(",")(0) '1
auth_response_reason_code = authmessage.Split(",")(2) '3
out_message = authmessage.Split(",")(3) '4 = reason for decline
authcode = authmessage.Split(",")(4) ''vb.net has 0 based array - auth is 5th record
authtransid = authmessage.Split(",")(6) '7

db_reason_text = qta.get_decline_message(auth_response_code, auth_response_reason_code)
If db_reason_text <> "" Then out_message = db_reason_text

End If
'I00001 is success, anything else is fail
If out_code = "I00001" Then
Dim tc As New webordersTableAdapters.payments_logTableAdapter
Dim cc_type As Integer = tc.get_cctype_by_id(paymentid)
Dim last4 As String = tc.get_last4_by_id(paymentid)
tc.InsertCharge(orderid, profileid, payprofileid, payscheduleid, amount * -1, 1, authcode, authmessage, userid, authtransid, 1, 1, gateway_id, payscheduleid, cc_type, last4)
If payscheduleid > 0 Then
Dim psta As New webordersTableAdapters.payments_scheduledTableAdapter
psta.UpdateStatusById(6, payscheduleid)
End If
Return True
Else
Return False
End If
Catch ex As Exception
ConstClass.record_error("api.vb: function apicall_create_refund_request, parse response portion", ex.ToString)
out_code = "ER"
out_message = "Error parsing response."
Return False
End Try
End Function


'''''''''''''''''''''''''''''''''''''
''FUNCTIONS THAT ARE NOT USED (YET)''
'''''''''''''''''''''''''''''''''''''

Public Shared Function apicall_delete_profile(ByVal profileid As Integer, ByVal orderid As Integer) As Boolean
Dim callstr As String = ""
Dim memory_stream As New MemoryStream
Dim writer As New XmlTextWriter(memory_stream, _
System.Text.Encoding.UTF8)

Try
writer.Formatting = Formatting.Indented
writer.Indentation = 4
writer.WriteStartDocument(True)
writer.WriteStartElement("deleteCustomerProfileRequest")
writer.WriteAttributeString("xmlns", "AnetApi/xml/v1/schema/AnetApiSchema.xsd")
api.xml_MerchAuth(writer) 'this adds the xml that will authenticate to auth.net
writer.WriteElementString("customerProfileId", profileid)
writer.WriteEndElement()
writer.WriteEndDocument()
writer.Flush()

'dump xml mem stream into string
Dim stream_reader As New StreamReader(memory_stream)
memory_stream.Seek(0, SeekOrigin.Begin)
callstr = stream_reader.ReadToEnd()
writer.Close()
Catch ex As Exception
ConstClass.record_error("api.vb: apicall_delete_profile, generate xml portion", ex.ToString)
Return False
End Try
Dim responsetype As String = ""
Dim result As String = ""
Dim responsemessagetext As String = ""
Dim response As String = ""
Dim xd As XmlDocument = New XmlDocument()
Try
'send api request
response = PostData(callstr, ConstClass.ReadAppSettings("api_url"))
xd.LoadXml(response)
responsetype = api.apicall_get_response_type(xd)
Catch ex As Exception
ConstClass.record_error("api.vb: apicall_delete_profile, get response portion", ex.ToString)
Return False
End Try
'record response data
Try
result = api.apicall_get_messages_resultCode(xd)
responsemessagetext = api.apicall_get_messages_message_text(xd)
If result <> "Error" Then
Dim tc As New webordersTableAdapters.ordersTableAdapter
tc.UpdateQuery_cim(0, "", "1/1/1900", 0, 0, 0, orderid)
Return True
Else
Return False
End If
Catch ex As Exception
ConstClass.record_error("api.vb: apicall_delete_profile, parse xml portion", ex.ToString)
Return False
End Try

End Function

End Class


I have references in this example to record the results, which you will have to update to your own data table references of course.

Other Tips:



  • Record the resulting authorize.net transaction ID as a BIGINT - they use numbers well over +2^31, which would cause arithmetic overflow errors if the data type is not right. (I guess they do alot of business?)

  • ASP.net info: http://www.asp.net/get-started/

  • debug by adding something to the post-function to record all calls and responses, but disable this for live runs (the call would contan card data...)

  • If an xml node is not found, an error is thrown. There may be another way around this, but I like to use the Try...catch...end try to handle this.


Good luck!

No comments: