I'm currently charging a customer and then trying to create a customer profile based on that charge. The problem is that when I try and actually create the customer it fails, telling me that there is no response and instead prints out `
AttributeError: no such child: {AnetApi/xml/v1/schema/AnetApiSchema.xsd}customerProfileId
Here is the code, and below this chunk is a bit more explanation and what I'm doing to parse the response.
merchantAuth = apicontractsv1.merchantAuthenticationType() merchantAuth.name = app_config.AUTHORIZE_KEYS['apiLoginId'] merchantAuth.transactionKey = app_config.AUTHORIZE_KEYS['transactionKey'] # Create the payment object for a payment nonce opaqueData = apicontractsv1.opaqueDataType() opaqueData.dataDescriptor = request.form['dataDesc'] opaqueData.dataValue = request.form['dataValue'] # Add the payment data to a paymentType object paymentOne = apicontractsv1.paymentType() paymentOne.opaqueData = opaqueData # Create order information order = apicontractsv1.orderType() order.invoiceNumber = "invoice_%s" % user.id order.description = "Awesome" # Set the customer's identifying information customerData = apicontractsv1.customerDataType() customerData.type = "individual" customerData.id = "cus_%s" % user.id customerData.email = email # Giving the credit card info # Setting billing information billto = apicontractsv1.nameAndAddressType() billto.firstName = request.form['firstName'] billto.lastName = request.form['lastName'] billto.address = address1 billto.city = city billto.state = state billto.zip = zipcode billto.country = country item = request.form['item'] if item == 'dollar': amount = "3.00" if item == "monthly": amount = "5.00" length = 1 if item == "annual": amount = "50.00" length = 12 # Create order information order = apicontractsv1.orderType() order.invoiceNumber = "invoice_%s" % user.id order.description = "Awesomeness" # # Set the customer's Bill To address customerAddress = apicontractsv1.customerAddressType() customerAddress.firstName = request.form['firstName'] customerAddress.lastName = request.form['lastName'] customerAddress.address = address1 customerAddress.city = city customerAddress.state = state customerAddress.zip = zipcode customerAddress.country = country # Create customer profile on transaction createcustomerprofile = apicontractsv1.customerProfilePaymentType() createcustomerprofile.createProfile = True # Create a transactionRequestType object and add the previous objects to it. transactionrequest = apicontractsv1.transactionRequestType() transactionrequest.transactionType = "authCaptureTransaction" transactionrequest.amount = amount transactionrequest.payment = paymentOne transactionrequest.order = order transactionrequest.billTo = customerAddress transactionrequest.customer = customerData transactionrequest.profile = createcustomerprofile # Assemble the complete transaction request createtransactionrequest = apicontractsv1.createTransactionRequest() createtransactionrequest.merchantAuthentication = merchantAuth createtransactionrequest.refId = refId createtransactionrequest.transactionRequest = transactionrequest # Create the controller createtransactioncontroller = createTransactionController(createtransactionrequest) createtransactioncontroller.setenvironment(app_config.AUTH_NET_ENVIRONMENT) createtransactioncontroller.execute()
The problem seems to occur when I try and prase the response. but when I actually run the code as is suggested in the developers documenation
response = createtransactioncontroller.getresponse() logging.debug("%s" % response) if response is not None: # Check to see if the API request was successfully received and acted upon if response.messages.resultCode == "Ok": # Since the API request was successful, look for a transaction response # and parse it to display the results of authorizing the card if hasattr(response.transactionResponse, 'messages') == True: if hasattr(response.profileResponse, 'messages') == True: print('made it here') models.Payment(user=user, payment_date=datetime.utcnow(), authorize={'email': email, 'updated': False, 'address': u'%s %s' % (address1, address2), 'messages': {'transId':'%s' % response.transactionResponse.transId, 'responseCode':'%s' % response.transactionResponse.responseCode, 'auth_code':'%s' % response.transactionResponse.messages.message[0].code, 'Description':'%s' % response.transactionResponse.messages.message[0].description, 'email':email}, # 'customerProfileId': '%s' % response.profileResponse.customerProfileId, # 'customerPaymentProfileIdList': '%s' % response.profileResponse.customerPaymentProfileIdList, })
Given their [documentation][1] shows that the you can create the customer when making the transaction not sure why it's returning that it's not working.
Also when I check the [schema for the xml response][2] it seems I'm setting it correctly.
[1]: http://developer.authorize.net/api/reference/index.html#payment-transactions-charge-a-credit-card
[2]: https://api.authorize.net/xml/v1/schema/AnetApiSchema.xsd
09-13-2017 10:56 AM - edited 09-13-2017 10:58 AM
Ok, I tried changing the order, but it now in the log file it shows
Customer profile creation failed. This payment method does not support profile creation.
09-15-2017 12:46 PM
Your log should look like below:
2017-09-15 07:47:36,412 performing custom validation.. 2017-09-15 07:47:36,413 Executing http post to url: https://apitest.authorize.net/xml/v1/request.api 2017-09-15 07:47:36,413 building request.. 2017-09-15 07:47:36,921 Starting new HTTPS connection (1): apitest.authorize.net 2017-09-15 07:47:37,027 building request.. 2017-09-15 07:47:37,044 Request is: <?xml version="1.0" ?> <createTransactionRequest xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd"> <merchantAuthentication> <name></name> <transactionKey></transactionKey> </merchantAuthentication> <clientId>sdk-python-1.0.14</clientId> <refId>MerchantID-0001</refId> <transactionRequest> <transactionType>authCaptureTransaction</transactionType> <amount>12.23</amount> <payment> <creditCard> <cardNumber>4111111111111111</cardNumber> <expirationDate>2020-12</expirationDate> <cardCode>123</cardCode> </creditCard> </payment> <profile> <createProfile>true</createProfile> </profile> <order> <invoiceNumber>10101</invoiceNumber> <description>Golf Shirts</description> </order> <lineItems> <lineItem> <itemId>12345</itemId> <name>first</name> <description>Here's the first line item</description> <quantity>2.0</quantity> <unitPrice>12.95</unitPrice> </lineItem> <lineItem> <itemId>67890</itemId> <name>second</name> <description>Here's the second line item</description> <quantity>3.0</quantity> <unitPrice>7.95</unitPrice> </lineItem> </lineItems> <customer> <type>individual</type> <id>90999456654</id> <email>BubbaJohnson@example.com</email> </customer> <billTo> <firstName>Ellen</firstName> <lastName>Johnson</lastName> <company>Souveniropolis</company> <address>14 Main Street</address> <city>Pecan Springs</city> <state>TX</state> <zip>44628</zip> <country>USA</country> </billTo> <transactionSettings> <setting> <settingName>duplicateWindow</settingName> <settingValue>600</settingValue> </setting> </transactionSettings> </transactionRequest> </createTransactionRequest>
The Python that created the log above is below:
""" Charge a credit card """ import imp import os import sys # print sys.path from authorizenet import apicontractsv1 from authorizenet.apicontrollers import createTransactionController CONSTANTS = imp.load_source('modulename', 'constants.py') def charge_credit_card(amount): """ Charge a credit card """ # Create a merchantAuthenticationType object with authentication details # retrieved from the constants file merchantAuth = apicontractsv1.merchantAuthenticationType() merchantAuth.name = CONSTANTS.apiLoginId merchantAuth.transactionKey = CONSTANTS.transactionKey # Create the payment data for a credit card creditCard = apicontractsv1.creditCardType() creditCard.cardNumber = "4111111111111111" creditCard.expirationDate = "2020-12" creditCard.cardCode = "123" # Add the payment data to a paymentType object payment = apicontractsv1.paymentType() payment.creditCard = creditCard # Create order information order = apicontractsv1.orderType() order.invoiceNumber = "10101" order.description = "Golf Shirts" # Set the customer's Bill To address customerAddress = apicontractsv1.customerAddressType() customerAddress.firstName = "Ellen" customerAddress.lastName = "Johnson" customerAddress.company = "Souveniropolis" customerAddress.address = "14 Main Street" customerAddress.city = "Pecan Springs" customerAddress.state = "TX" customerAddress.zip = "44628" customerAddress.country = "USA" # Create customer profile on transaction createcustomerprofile = apicontractsv1.customerProfilePaymentType() createcustomerprofile.createProfile = True # Set the customer's identifying information customerData = apicontractsv1.customerDataType() customerData.type = "individual" customerData.id = "90999456654" customerData.email = "BubbaJohnson@example.com" # Add values for transaction settings duplicateWindowSetting = apicontractsv1.settingType() duplicateWindowSetting.settingName = "duplicateWindow" duplicateWindowSetting.settingValue = "600" settings = apicontractsv1.ArrayOfSetting() settings.setting.append(duplicateWindowSetting) # setup individual line items line_item_1 = apicontractsv1.lineItemType() line_item_1.itemId = "12345" line_item_1.name = "first" line_item_1.description = "Here's the first line item" line_item_1.quantity = "2" line_item_1.unitPrice = "12.95" line_item_2 = apicontractsv1.lineItemType() line_item_2.itemId = "67890" line_item_2.name = "second" line_item_2.description = "Here's the second line item" line_item_2.quantity = "3" line_item_2.unitPrice = "7.95" # build the array of line items line_items = apicontractsv1.ArrayOfLineItem() line_items.lineItem.append(line_item_1) line_items.lineItem.append(line_item_2) # Create a transactionRequestType object and add the previous objects to it. transactionrequest = apicontractsv1.transactionRequestType() transactionrequest.transactionType = "authCaptureTransaction" transactionrequest.amount = amount transactionrequest.payment = payment transactionrequest.profile = createcustomerprofile transactionrequest.order = order transactionrequest.billTo = customerAddress transactionrequest.customer = customerData transactionrequest.transactionSettings = settings transactionrequest.lineItems = line_items # Assemble the complete transaction request createtransactionrequest = apicontractsv1.createTransactionRequest() createtransactionrequest.merchantAuthentication = merchantAuth createtransactionrequest.refId = "MerchantID-0001" createtransactionrequest.transactionRequest = transactionrequest createtransactionrequest.profile = "createProfile" # Create the controller createtransactioncontroller = createTransactionController( createtransactionrequest) createtransactioncontroller.execute() response = createtransactioncontroller.getresponse() print response if response is not None: print response # Check to see if the API request was successfully received and acted upon if response.messages.resultCode == "Ok": # Since the API request was successful, look for a transaction response # and parse it to display the results of authorizing the card if hasattr(response.transactionResponse, 'messages') is True: print( 'Successfully created transaction with Transaction ID: %s' % response.transactionResponse.transId) print('Transaction Response Code: %s' % response.transactionResponse.responseCode) print('Message Code: %s' % response.transactionResponse.messages.message[0].code) print('Description: %s' % response.transactionResponse. messages.message[0].description) else: print('Failed Transaction.') if hasattr(response.transactionResponse, 'errors') is True: print('Error Code: %s' % str(response.transactionResponse. errors.error[0].errorCode)) print( 'Error message: %s' % response.transactionResponse.errors.error[0].errorText) # Or, print errors if the API request wasn't successful else: print('Failed Transaction.') if hasattr(response, 'transactionResponse') is True and hasattr( response.transactionResponse, 'errors') is True: print('Error Code: %s' % str( response.transactionResponse.errors.error[0].errorCode)) print('Error message: %s' % response.transactionResponse.errors.error[0].errorText) else: print('Error Code: %s' % response.messages.message[0]['code'].text) print('Error message: %s' % response.messages.message[0]['text'].text) else: print('Null Response.') return response if (os.path.basename(__file__) == os.path.basename(sys.argv[0])): charge_credit_card(CONSTANTS.amount)
09-15-2017 12:53 PM
Not sure if it's because I'm using the payment nooce, but my log file does not show the request, only the response
2017-09-15 13:58:27,152 performing custom validation..
2017-09-15 13:58:27,152 Executing http post to url: https://apitest.authorize.net/xml/v1/request.api
2017-09-15 13:58:27,152 building request..
2017-09-15 13:58:27,159 Starting new HTTPS connection (1): apitest.authorize.net
2017-09-15 13:58:30,192 "POST /xml/v1/request.api HTTP/1.1" 200 1138
2017-09-15 13:58:30,206 Multiple accepting paths for <class 'authorizenet.apicontractsv1.CTD_ANON_10'>
2017-09-15 13:58:30,206 Multiple accepting paths for <class 'authorizenet.apicontractsv1.CTD_ANON_9'>
2017-09-15 13:58:30,214 Multiple accepting paths for {AnetApi/xml/v1/schema/AnetApiSchema.xsd}transactionResponse
2017-09-15 13:58:30,216 Multiple accepting paths for <class 'authorizenet.apicontractsv1.CTD_ANON_73'>
2017-09-15 13:58:30,223 Received response: <?xml version="1.0" encoding="utf-8"?>
<createTransactionResponse xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<refId>ref 1505509107.15</refId>
<messages>
<resultCode>Ok</resultCode>
<message>
<code>I00001</code>
<text>Successful.</text>
</message>
</messages>
<transactionResponse>
<responseCode>1</responseCode>
<authCode>D3ZWDA</authCode>
<avsResultCode>Y</avsResultCode>
<cvvResultCode>P</cvvResultCode>
<cavvResultCode>2</cavvResultCode>
<transId>40007132129</transId>
<refTransID/>
<transHash>4AA30C7C2091E9DDF6E8516503EE8D5E</transHash>
<testRequest>0</testRequest>
<accountNumber>XXXX4242</accountNumber>
<accountType>Visa</accountType>
<messages>
<message>
<code>1</code>
<description>This transaction has been approved.</description>
</message>
</messages>
<transHashSha2/>
</transactionResponse>
<profileResponse>
<messages>
<resultCode>Error</resultCode>
<message>
<code>E00103</code>
<text>Customer profile creation failed. This payment method does not support profile creation.</text>
</message>
</messages>
</profileResponse>
</createTransactionResponse>
09-15-2017 01:59 PM
This is the code I'm using, in the order as you suggested
# Create a merchantAuthenticationType object with authentication details
# retrieved from the constants file
merchantAuth = apicontractsv1.merchantAuthenticationType()
merchantAuth.name = app_config.AUTHORIZE_KEYS['apiLoginId']
merchantAuth.transactionKey = app_config.AUTHORIZE_KEYS['transactionKey']
# Create the payment object for a payment nonce
opaqueData = apicontractsv1.opaqueDataType()
opaqueData.dataDescriptor = request.form['dataDesc']
opaqueData.dataValue = request.form['dataValue']
# Add the payment data to a paymentType object
paymentOne = apicontractsv1.paymentType()
paymentOne.opaqueData = opaqueData
# Create order information
order = apicontractsv1.orderType()
order.invoiceNumber = "invoice_%s_%s" % (randint(0, 100), user.id)
order.description = "The thing you upgraded"
# # Set the customer's Bill To address
customerAddress = apicontractsv1.customerAddressType()
customerAddress.firstName = request.form['firstName']
customerAddress.lastName = request.form['lastName']
customerAddress.address = address1
customerAddress.city = city
customerAddress.state = state
customerAddress.zip = zipcode
customerAddress.country = country
# Set the customer's identifying information
customerData = apicontractsv1.customerDataType()
customerData.type = "individual"
customerData.id = "cus_%s" % user.id
customerData.email = email
# Add values for transaction settings
duplicateWindowSetting = apicontractsv1.settingType()
duplicateWindowSetting.settingName = "duplicateWindow"
duplicateWindowSetting.settingValue = "600"
settings = apicontractsv1.ArrayOfSetting()
settings.setting.append(duplicateWindowSetting)
# Create customer profile on transaction
createcustomerprofile = apicontractsv1.customerProfilePaymentType()
createcustomerprofile.createProfile = True
# Create a transactionRequestType object and add the previous objects to it.
transactionrequest = apicontractsv1.transactionRequestType()
transactionrequest.transactionType = "authCaptureTransaction"
transactionrequest.amount = amount
transactionrequest.payment = paymentOne
transactionrequest.profile = createcustomerprofile
transactionrequest.order = order
transactionrequest.billTo = customerAddress
transactionrequest.customer = customerData
transactionrequest.transactionSettings = settings
# Assemble the complete transaction request
createtransactionrequest = apicontractsv1.createTransactionRequest()
createtransactionrequest.merchantAuthentication = merchantAuth
createtransactionrequest.refId = refId
createtransactionrequest.transactionRequest = transactionrequest
createtransactionrequest.profile = "createProfile"
# Create the controller
createtransactioncontroller = createTransactionController(createtransactionrequest)
createtransactioncontroller.setenvironment(app_config.AUTH_NET_ENVIRONMENT)
createtransactioncontroller.execute()
response = createtransactioncontroller.getresponse()
09-15-2017 02:20 PM - edited 09-15-2017 02:21 PM
It is because you are using opaqueData, this payment method does not support profile creation.
09-15-2017 03:03 PM
So in order to use this functionality you have to run the credit card through your server? What's the point of accept.js then?
09-15-2017 03:18 PM
Using a nonce from Accept.js to create a transaction and a profile at the same time is not currently supported, but is something we plan to fix in a future release. You can create a customer profile with the nonce and then perform a transaction using the customer profile.
Richard
09-15-2017 04:10 PM
Is there a ETA to this? I'll do a workaround till it's resolved.
09-15-2017 04:30 PM
Also, it seems there is another issue.
If I try and make a customer by sending the credit card information instead of the noonce and then within the same function try and make a ARB off that customer profile, it does not register, tells me that
<ARBCreateSubscriptionResponse xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<messages>
<resultCode>Error</resultCode>
<message>
<code>E00040</code>
<text>The record cannot be found.</text>
</message>
</messages>
</ARBCreateSubscriptionResponse>
So is there a delay between when a customer is created before you can send another request to create the ARB? Since clearly it does make the profile, I can see it in the CIM, as well as the payment profile.
Do I have to set this up as a seperate function that runs a cron a day later or something since it appears, as I had suspected earlier, that trying to run 2 calls within one function with your SDK makes it so nothing works.
09-15-2017 05:24 PM
@nadermx Creating a customer profile is done in realtime, but follow-on transactions to use a customer profile use replicated date for performance reasons. You may experience some delay in the sandbox but should perform much faster in production. If you get an E00040 when trying to create a transaction from a newly created customer profile, you can simply wait a few seconds and try again.
Our product team is aware of this issue and are working on improving performance.
Richard
09-15-2017 05:43 PM