authorizenet / sdk-java Goto Github PK
View Code? Open in Web Editor NEWJava SDK for Authorize.Net API
License: Other
Java SDK for Authorize.Net API
License: Other
A few weeks back a came across a HTTP response map decode exception caused by a product description that has "... 100% ..." on.
The immediate fix was to simply encode this description string before making the API request with net.authorize.data.Order, but after some digging I found what might be an extra
URLDecoder.decode(responseString, HTTP.UTF_8);
Can anyone else confirm this problem? I can provide more details if needed.
Does not seem to support encrypted card readers.
Any planned support for this?
ApiOperationBase.setMerchantAuthentication(merchantAuthenticationType);
ApiOperationBase.setEnvironment(Environment.SANDBOX);
Is there currently a way to wrap the environment and authentication values into an object that gets used and destroyed per request? The above usage may not be great for those supporting several auth.net accounts. Plz correct me if wrong. thx.
The SDK's HttpUtility is needlessly creating threads for every request execution.
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<ANetApiResponse> future = executor.submit(new HttpCallTask(env, request, classType));
executor.shutdown(); // Important!
try {
response = future.get();
logger.debug(String.format("Response: '%s'", response));
} ...
This is creating a new thread for every execution. EXPENSIVE!
I could be wrong, but I think it's a race condition where to assume the HTTPCallTask is started before the executor gets shutdown.
Waiting on future.get() which means no call is ever asynchronous.
As it stands, I have to duplicate more of the API than I want in order to get this functionality since I cannot extend net.authorize.cim.Transaction
(no default constructor means I cannot extend it).
I basically had to copy/paste a lot of the communication code in HttpClient
in order to support this very basic request/response because that class specifically checks for instanceof net.authorize.cim.Transaction
, that object requires an net.authorize.cim.TransactionType
, and there is not a TransactionType
for createCustomerProfileFromTransactionRequest
.
It seems that all that would be required is to:
createCustomerProfileFromTransactionRequest
enum value to auth.net.cim.TransactionType
net.authorize.cim.Transaction
for transId
net.authorize.cim.Transaction.toXML()
methodnet.authorize.cim.Result
Hi all,
Anyone having this issue?
I'm just running the Java example code the perform an authorization and getting a null response.
Debugging it I see that controller object has no properly set the environment. The exact message is:
"Environment not set. Set environment using setter or use overloaded method to pass appropriate environment"
I'm setting the environment as the example, didn't change anything:
ApiOperationBase.setEnvironment(Environment.SANDBOX);
Any idea?
XmlTreeUtil._printTree currently does not escape attribute values or text nodes. This causes parsing errors when incorrectly formatted XML is submitted.
NullPointerException is thrown in net.authorize.reporting.Result
---- Stack Trace -----
CAUSED_BY: java.lang.NullPointerException :::
-- net.authorize.reporting.Result.importRefId(Result.java:491)
-- net.authorize.reporting.Result.createResult(Result.java:58)
-- net.authorize.Merchant.postTransaction(Merchant.java:300)
This is occurring frequently after the transaction processing outage on Jan 29, 2016.
The recent change to Environment.java added semi-colons to the end of LOCAL_VM and HOSTED_VM instead of commas. This is causing the build to fail.
I am facing exact issue mentioned in the link: https://stackoverflow.com/questions/44325790/e00007-user-authentication-failed-due-to-invalid-authentication-values-in-aut. Please guide/repy.
Phone number is not imported from respond XML to billTo Adress class, but it presents in XML.
Version: Java SDK 1.4.6
Method: net.authorize.cim.Result#importBillTo
We are unable to retrieve shipping or billing information for one of our transactions due to a defect in the Java Reporting API.
The XML that we are receiving is missing the "customer" element, and as a result it is not falling into the
if(customer_list != null && customer_list.getLength() == 1)
block of code of the net.authorize.reporting.Results class so that the shipTo and billTo elements can be processed.
According to the authorize.net xml schema, the billto and shipto elements are not children of a customer element, so the java code should not require the customer element to be present before processing these records.
I will take a look at hacking together a solution that will get me by. Please let me know when I can expect a fix.
Quick follow up question. Is anyone else using the Java Reporting API? I've submitted three defects for it in the past two months, and none of them have been fixed yet. Is everyone working off of their own forked version of the code? Just trying to find out if there is a better way of getting these fixes pushed out to our customers.
Thank you for your help.
How we can see the list of Settled and Unsettled transactions using anet-java-sdk? Could you please share code snippet?
I have used this SDK for years without issues, but yesterday this came up repeatedly for a particular transaction:
java.lang.NullPointerException
at net.authorize.aim.cardpresent.Result.importResponseCode(Result.java:166)
I went on authorize.net web site and manually entered the card; It worked fine.
I was looking at this sample of yours ChargeCreditCard
and comparing it with the one that I have
Merchant merchant = Merchant.createMerchant("environment", "loginId", "transactionKey"); merchant.setMarketType(MarketType.RETAIL); merchant.setDeviceType(DeviceType.VIRTUAL_TERMINAL);
I was wondering how can I set a MarketType and DeviceType using MerchantAuthenticationType
I am getting following error for the Java code below. Basically I am looking to get the Transaction Details, settled and unsettled..
The element 'getTransactionDetailsRequest' in namespace 'AnetApi/xml/v1/schema/AnetApiSchema.xsd' has incomplete content. List of possible elements expected: 'refId, transId' in namespace 'AnetApi/xml/v1/schema/AnetApiSchema.xsd'.
The Java code for reference
Merchant merchant = Merchant.createMerchant(Environment.SANDBOX, apiLoginID, transactionKey);
Transaction transaction = merchant.createReportingTransaction(TransactionType.GET_TRANSACTION_DETAILS);
ReportingDetails details = ReportingDetails.createReportingDetails();
details.setBatchIncludeStatistics(true);
transaction.setReportingDetails(details);
Result<Transaction> result = (Result<Transaction>) merchant.postTransaction(transaction);
System.out.println("Code : "+result.getMessages().get(0).getResultCode());
System.out.println("Text : "+result.getMessages().get(0).getText());
for (BatchDetails batchDetail : result.getReportingDetails().getBatchDetailsList()) {
System.out.println("---------------------");
System.out.println("ID : "+ batchDetail.getBatchId() );
System.out.println("Settlement State : "+ batchDetail.getSettlementState().value());
System.out.println("local settlementTime: "+ batchDetail.getSettlementTimeLocal().toString());
}
Merchant merchant = Merchant.createMerchant(authorizeEnvironment, authorizeLoginId, authorizeTransactionId);
Subscription subscription = Subscription.createSubscription();
subscription.setCustomerProfile(); <--- does not exist
Transaction transaction = merchant.createARBTransaction(TransactionType.CREATE_SUBSCRIPTION, subscription);
Result<Transaction> result = (Result<Transaction>) merchant.postTransaction(transaction);
Logs are generated every time the build runs and don't need to be checked in to Git
I'm using DebitBankAccount.java and simply I run it so it gives me following error
how can I get / add sample bank details in Authorized.net ?
11/05/15 22:24:44,05: INFO [pool-1-thread-1] (net.authorize.util.LogHelper:24) - Use Proxy: 'false' Failed Transaction: 2
public class DebitBankAccount {
public static final String apiLoginId= "CXXXX";
public static final String transactionKey= "XXXXXXXX";
public static void main(String[] args) {
//Common code to set for all requests
ApiOperationBase.setEnvironment(Environment.SANDBOX);
MerchantAuthenticationType merchantAuthenticationType = new MerchantAuthenticationType() ;
merchantAuthenticationType.setName(apiLoginId);
merchantAuthenticationType.setTransactionKey(transactionKey);
ApiOperationBase.setMerchantAuthentication(merchantAuthenticationType);
// Populate the payment data
PaymentType paymentType = new PaymentType();
BankAccountType bankAccountType = new BankAccountType();
bankAccountType.setAccountType(BankAccountTypeEnum.CHECKING);
bankAccountType.setRoutingNumber("125000024");
bankAccountType.setAccountNumber("12345678");
bankAccountType.setNameOnAccount("John Doe");
paymentType.setBankAccount(bankAccountType);
// Create the payment transaction request
TransactionRequestType txnRequest = new TransactionRequestType();
txnRequest.setTransactionType(TransactionTypeEnum.AUTH_CAPTURE_TRANSACTION.value());
txnRequest.setPayment(paymentType);
txnRequest.setAmount(new BigDecimal(500.00));
// Make the API Request
CreateTransactionRequest apiRequest = new CreateTransactionRequest();
apiRequest.setTransactionRequest(txnRequest);
CreateTransactionController controller = new CreateTransactionController(apiRequest);
controller.execute();
CreateTransactionResponse response = controller.getApiResponse();
if (response!=null) {
// If API Response is ok, go ahead and check the transaction response
if (response.getMessages().getResultCode() == MessageTypeEnum.OK) {
TransactionResponse result = response.getTransactionResponse();
if (result.getResponseCode().equals("1")) {
System.out.println(result.getResponseCode());
System.out.println("Successful Debit Bank Transaction");
System.out.println(result.getAuthCode());
System.out.println(result.getTransId());
}
else {
System.out.println("Failed Transaction: "+result.getResponseCode());
}
}
else{
System.out.println("Failed Transaction: "+response.getMessages().getResultCode());
}
}
}
}
This SDK currently uses "DefaultHttpClient()" to make HTTP requests. As an experiment I upgraded the httpclient-4.0.1 and httpcore-4.0.1 JARs and added some functions to build a custom SSLContext into the HttpClient executed by the SDK API calls.
Does this SDK expect us to configure our servers to only make TLS 1.2 HTTPS requests?
Options like "-Dhttps.protocols=TLSv1.2 -Djdk.tls.client.protocols=TLSv1.2" or "SSLProtocol -all +TLSv1.2"
Is there a newer version of the SDK coming that has the upgraded HttpClient libraries built in for us?
Is there some way to insert a custom HttpClient into the
CreateTransactionController controller = new CreateTransactionController(apiRequest); controller.execute(); CreateTransactionResponse response = controller.getApiResponse();
or
response = merchant.postTransaction(transaction);
process?
So far, I've only been able to place new sandbox transactions with my modified SDK, changing my web and application server options has not worked yet.
This API is needlessly difficult to use. It lacks a coherent abstraction for what it is actually doing. Ideally, this API would work like the following:
AuthorizeAndCaptureResponse authorizeAndCapture(boolean testMode, String userId, String userKey, String cardNumber, Expiration expiration, double amount) {
try {
Gateway gateway = new Gateway(testMode);
Client client = new Client(userId, userKey);
AuthorizeAndCaptureRequest request = client.getAuthorizeAndCaptureBuilder()
.setCardNumber(cardNumber)
.setExpiration(expiration)
.setAmount(amount)
.build();
return (AuthorizeAndCaptureResponse) client.send(request, gateway);
} catch(ValidationException e) {
e.printStackTrace();
return null;
}
}
Gateway is responsible for processing requests. Client is responsible for providing builders for all of the request types and for sending authenticated requests to Gateway. The Response objects should provide straightforward access to the results by encapsulating their underlying objects rather than the obnoxious layers that we have to try to wrap our heads around now. Objects like Expiration provide more convenient and intuitive abstractions for things like the expiration date with methods like setMonth(int month)
and setYear(int year)
or similar constructors like Expiration(int month, int year)
. As a bonus, these kinds of objects can provide early validation to inform users when the data they've entered makes no sense.
Not only will this type of straightforward abstraction be easier for users to work with, but it should also be easier for you to maintain. I'm considering doing some of this work for you since I don't want to put the code I've written against your current API into production because of how hard it is to read and understand.
Also, you SHOULD NOT provide examples of embedding this kind of code into JSPs since that represents a severe violation of the Separation of Concerns. JSPs should only contain presentation logic and should delegate this kind of work to Servlets which should delegate it to Services which bear responsibility for the business logic.
No connection time out and read time out for http calls.
I am trying to delete user profiles in java via the code below.
net.authorize.cim.Transaction transaction=merchant.createCIMTransaction(TransactionType.DELETE_CUSTOMER_PROFILE);
transaction.setRefId(generateRefId());
transaction.setCustomerProfileId(profileId);
Result result = (Result) merchant.postTransaction(transaction);
Every response I get it the following
deleting user with profileId =32441194
Result Code: Error
E00040 - The record cannot be found.
The weird thing is the user profile Id is in fact active/correct and the deletion of the account completes successfully in the sandbox, even though the response claims there is an error.
Any ideas?
When updating an existing customer payment profile (createCustomerPaymentProfileRequest) using CIM and the profile contains existing credit card info, the element includes an empty element which causes XML schema validation error. The element should only be included when a value is specified.
Hello,
I am facing below error:
2016-08-18 11:28:34 INFO net.authorize.util.HttpClient - Use Proxy: 'false'
2016-08-18 11:28:34 DEBUG o.a.h.i.conn.SingleClientConnManager - Get connection for route HttpRoute[{s}->https://apitest.authorize.net]
2016-08-18 11:28:35 DEBUG o.a.h.i.conn.DefaultClientConnection - Connection shut down
2016-08-18 11:28:35 DEBUG o.a.h.i.conn.SingleClientConnManager - Releasing connection org.apache.http.impl.conn.SingleClientConnManager$ConnAdapter@14a2ec7
2016-08-18 11:28:35 WARN net.authorize.util.HttpClient - Exception getting response: 'Connection to https://apitest.authorize.net refused': 'java.net.ConnectException: Connection refused: connect', '[org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:127), org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:147), org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:108), org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:415), org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:641), org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:576), org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:554), net.authorize.util.HttpClient.executeXML(HttpClient.java:227), net.authorize.Merchant.postTransaction(Merchant.java:298), com.auth.net.commons.authorize.net.SettledTransactionDetails.main(SettledTransactionDetails.java:39)]'
Exception in thread "main" java.lang.NullPointerException
at net.authorize.reporting.Result.importRefId(Result.java:490)
at net.authorize.reporting.Result.createResult(Result.java:58)
at net.authorize.Merchant.postTransaction(Merchant.java:299)
at com.auth.net.commons.authorize.net.SettledTransactionDetails.main(SettledTransactionDetails.java:39)
It looks like proxy is enabled and which is blocking the transaction to be hit to target system. We must need to set/write proxy code to allow proxy to pass this transaction in the following code, how we can do that ? Does Auth.net SDK allows such provision? It looks to me that Auth.net using HTTPClient API to make the call, so it must be possible to do that isn't it ?
bug with BankAccountType. The CIM and ARB APIs expect a value of checking, savings, and businessChecking for the account type for bank account payments. However when the request is being built, the code simply lower cases the enum, therefore all the specific requests involing the the business checking type fail because it evaluates to businesschecking instead of businessChecking. You can see my temporary work around below. I added a second value value2 which holds the right value to be used when making a request.
package net.authorize.data.echeck;
import java.io.Serializable;
/**
Supported bank account types.
*
*/
public enum BankAccountType implements Serializable {
CHECKING("CHECKING","checking"),
BUSINESSCHECKING("BUSINESSCHECKING","businessChecking"),
SAVINGS("SAVINGS","savings"),
UNKNOWN("UNKNOWN","unknown");
private final String value;
private final String value2;
private BankAccountType(String value, String value2) {
this.value = value;
this.value2 = value2;
}
public static BankAccountType findByValue(String value) {
for(BankAccountType bankAccountType : values()) {
if(bankAccountType.value.equals(value) || bankAccountType.value2.equals(value)) {
return bankAccountType;
}
}
return BankAccountType.UNKNOWN;
}
/**
/**
if(bank_account.getBankAccountType() != null) {
Element account_type_el = document.createElement(AuthNetField.ELEMENT_ACCOUNT_TYPE.getFieldName());
account_type_el.appendChild(document.getDocument().createTextNode(bank_account.getBankAccountType().getValue().toLowerCase()));
bankacct_el.appendChild(account_type_el);
}
to make use of value2 instead of the lower cased value:
if(bank_account.getBankAccountType() != null) {
Element account_type_el = document.createElement(AuthNetField.ELEMENT_ACCOUNT_TYPE.getFieldName()); account_type_el.appendChild(document.getDocument().createTextNode(bank_account.getBankAccountType().getValue2()));
bankacct_el.appendChild(account_type_el);
}
getCustomerPaymentProfileIdList() is returning only one profile Id even when multiple payment profile Id's are returned
I'm using latest anet-sdk version for java and im integrating it in Spring MVC project,I have used code from authorize.net sample code for java but it is giving null response now,it was working fine a month ago
When the SDK is built from ant, the following error occurs whenever submitting a request:
SEVERE: Execution error for http post Message: 'java.lang.ArrayStoreException: sun.reflect.annotation.TypeNotPresentExceptionProxy'
Also, the ant build produces jars labeled "1.8.2" rather than "1.8.9".
Please either remove the Apache Ant build process if it will not be maintained, or update it so that it produces identical results as using Apache Maven. Thanks!
Is it possible to implement proxy authentication? Or at least decouple code from util.HttpClient static calls to use custom configurable instance of HttpClient?
Currently, x_trans_id is sent for CNP transactions, but x_ref_trans_id must be used for CP. The Card Present implementation is built on top of AIM, but doesn't make the necessary change from x_trans_id to x_ref_trans_id.
Hi,
I've been trying to migrate to use your SDK and found that I've been unable to send international characters without the request failing. I've figured out that you are missing encoding the StringEntity in HttpUtility.java.
Can you please change (currently line 68):
httpPost.setEntity(new StringEntity(xmlRequest));
to be:
httpPost.setEntity(new StringEntity(xmlRequest,"UTF-8"));
and it fixes the issue.
Thanks!
Hi,
I upgraded anet-java-sdk version from 1.8.1 to 1.8.2. Upon testing, I encountered a 404 when creating a transaction. It looks like the endpoint for Environment.SANDBOX was changed from test.authorize.net to sandbox.authorize.net . Here's the 404 I'm getting:
INFO : net.authorize.util.HttpClient - Use Proxy: 'false'
DEBUG: org.apache.http.wire - >> "POST /gateway/transact.dll HTTP/1.1[\r][\n]"
DEBUG: org.apache.http.wire - >> "Content-Type: application/x-www-form-urlencoded; charset=utf-8[\r][\n]"
DEBUG: org.apache.http.wire - >> "Content-Length: 408[\r][\n]"
DEBUG: org.apache.http.wire - >> "Host: sandbox.authorize.net[\r][\n]"
DEBUG: org.apache.http.wire - >> "Connection: Keep-Alive[\r][\n]"
DEBUG: org.apache.http.wire - >> "User-Agent: Apache-HttpClient/4.3.1 (java 1.5)[\r][\n]"
DEBUG: org.apache.http.wire - >> "[\r][\n]"
DEBUG: org.apache.http.wire - >> "x_tran_key=9Ktc364dmk6T94Fz&x_allow_partial_Auth=FALSE&x_market_type=2&x_card_num=&x_method=CC&x_delim_data=TRUE&x_exp_date=&x_relay_response=FALSE&x_login=3uDJcL26PRN&x_version=3.1&x_device_type=10&x_amount=1.75&x_test_request=FALSE&x_type=AUTH_CAPTURE&x_delim_char=%7C&x_cpversion=1.0&x_response_format=0&x_track2=&x_encap_char=&x_track1=BMASKED**0002%5ECARDUSER%2FJOHN%5EMASKED**0000MASKED**0000"
DEBUG: org.apache.http.wire - << "HTTP/1.1 404 Not Found[\r][\n]"
DEBUG: org.apache.http.wire - << "Content-Type: text/html[\r][\n]"
DEBUG: org.apache.http.wire - << "Server: Microsoft-IIS/7.5[\r][\n]"
DEBUG: org.apache.http.wire - << "X-Powered-By: ASP.NET[\r][\n]"
DEBUG: org.apache.http.wire - << "Date: Fri, 10 Oct 2014 02:01:51 GMT[\r][\n]"
DEBUG: org.apache.http.wire - << "Content-Length: 103[\r][\n]"
DEBUG: org.apache.http.wire - << "[\r][\n]"
Any ideas why I'm getting a 404 when communicating with sandbox.authorize.net?
Thanks!
We are looking into managing all payment method information using CIM with hosted forms so that credit card information never passes through our services. However, since CreateCustomerProfileController
's validation methods require that PaymentProfiles be provided, as currently implemented, you cannot use hosted forms until a customer profile exists, and you cannot create a customer profile without providing payment information, which forces credit card information to pass through the merchant's services at least once.
I was able to work around the issue by creating my own FixedCreateCustomerProfileController
which doesn't validate PaymentProfiles or ValidationMode settings, but the correct fix would be to allow empty payment profile values and ValidationMode to be undefined whenever no payment profiles are provided.
private static class FixedCreateCustomerProfileController extends ApiOperationBase<CreateCustomerProfileRequest, CreateCustomerProfileResponse> {
public FixedCreateCustomerProfileController(CreateCustomerProfileRequest apiRequest) {
super(apiRequest);
}
@Override
protected void validateRequest() {
CreateCustomerProfileRequest request = this.getApiRequest();
if ( null == request.getProfile()) throw new NullPointerException("Profile cannot be null");
// if ( null == request.getRefId()) throw new NullPointerException("RefId cannot be null");
// if ( null == request.getValidationMode() || ValidationModeEnum.NONE == request.getValidationMode()) throw new NullPointerException("ValidationMode cannot be null");
// if ( null == request.getProfile().getPaymentProfiles() || 0 == request.getProfile().getPaymentProfiles().size()) throw new NullPointerException("Payment Profile cannot be null or empty");
}
@Override
protected Class<CreateCustomerProfileResponse> getResponseType() {
return CreateCustomerProfileResponse.class;
}
}
I also hit the non-null RefId validation issue, but I see that's been fixed in the Future branch.
Please, see #72
Basically while running ValidateCustomerPaymentProfile.java, I was getting exceptions. This was caused because cardCode and CustomerShippingAddressID were not being set in the sample code. However, the controller validates these fields and throws exception if not found. Following is the piece of code which does the validation in the ValidateCustomerPaymentProfileController:
//validate required fields
if ( null == request.getCustomerProfileId()) throw new NullPointerException("CustomerProfileId cannot be null");
if ( null == request.getCardCode()) throw new NullPointerException("CardCode cannot be null");
if ( null == request.getCustomerPaymentProfileId()) throw new NullPointerException("CustomerPaymentProfileId cannot be null");
if ( null == request.getCustomerShippingAddressId()) throw new NullPointerException("CustomerShippingAddressId cannot be null");
Now in the API reference nothing is mentioned about which fields are required.
It has broken all the loggin of my jboss application and got me crazy until I found this. Not sure if it is a way to everride it, but it should not re-define the root logger
Every time I set
PaymentType paymentType = new PaymentType();
CreditCardTrackType creditCardTrackType = new CreditCardTrackType();
creditCardTrackType.setTrack1("track1");
creditCardTrackType.setTrack2("track2");
paymentType.setTrackData(creditCardTrackType);
TransRetailInfoType retailInfo = new TransRetailInfoType();
retailInfo.setMarketType(MarketType.RETAIL.getValue());
retailInfo.setDeviceType(DeviceType.VIRTUAL_TERMINAL.getValue());
// Create the payment transaction request
TransactionRequestType transactionRequestType = new TransactionRequestType();
transactionRequestType.setTransactionType(TransactionTypeEnum.AUTH_CAPTURE_TRANSACTION.value());
transactionRequestType.setPayment(paymentType);
transactionRequestType.setOrder(orderType);
transactionRequestType.setRetail(retailInfo);
I'm getting this error E00003:The element 'trackData' in namespace 'AnetApi/xml/v1/schema/AnetApiSchema.xsd' has invalid child element 'track2' in namespace 'AnetApi/xml/v1/schema/AnetApiSchema.xsd'.
{
"code" : "E00003",
"text" : "An error occurred while parsing the XML request.",
"description" : "This is the result of an XML parser error.",
"integration_suggestions": "",
"other_suggestions": ""
}
if I remove track2 I get transaction Approved
Thanks
The result object for AIM card present currently does not provide a method of obtaining the split tender ID or the prepaid card elements.
This data can be accessed by reading the XML response directly, but it should be parsed automatically like the other response elements.
Hi,
I'm using the CIM API in your sdk. I have a use case where I need to be able to create a customer profile with a payment profile that does not have a card code. To do that, I set the card code to null and then call the API. However, the SDK calls Authorize.net and receives an error message:
[Error] E00003: The 'AnetApi/xml/v1/schema/AnetApiSchema.xsd:cardCode' element is invalid - The value '' is invalid according to its datatype 'AnetApi/xml/v1/schema/AnetApiSchema.xsd:cardCode' - The Pattern constraint failed.
The reason it receives the error is because the SDK creates the cardCode element in the XML and it is left empty (Please notice the '' in the request below):
<?xml version="1.0"?>
<createCustomerProfileRequest xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd">
<merchantAuthentication>
<name>LOGIN_ID_MASKED</name>
<transactionKey>TRANSACTION_KEY_MASKED</transactionKey>
</merchantAuthentication>
<profile>
<merchantCustomerId>AAAAAA</merchantCustomerId>
<description>df98d979-0dd0-4f98-bc66-ed654b3f1388</description>
<email></email>
<paymentProfiles>
<customerType>individual</customerType>
<billTo>
<firstName></firstName>
<lastName></lastName>
<company></company>
<address></address>
<city></city>
<state></state>
<zip></zip>
<country></country>
<phoneNumber></phoneNumber>
<faxNumber></faxNumber>
</billTo>
<payment>
<creditCard>
<cardNumber>MASKED**0002</cardNumber>
<expirationDate>2029-07</expirationDate>
<cardCode></cardCode>
</creditCard>
</payment>
</paymentProfiles>
</profile>
<validationMode>testMode</validationMode>
</createCustomerProfileRequest>
Here is a test case that you can use to reproduce this issue:
@Test
public void testCase() {
final String authorizeNetCardNotPresentApiLoginId = "YOUR_API_LOGIN_ID";
final String authorizeNetCardNotPresentTransactionKey = "YOUR_TRANSACTION_KEY";
final Merchant merchant = Merchant.createMerchant(Environment.SANDBOX, authorizeNetCardNotPresentApiLoginId, authorizeNetCardNotPresentTransactionKey);
final CreditCard creditCard = CreditCard.createCreditCard();
creditCard.setCreditCardNumber("370000000000002");
creditCard.setExpirationDate("2029-07");
creditCard.setCardCode(null);
final Address address = Address.createAddress();
address.setZipPostalCode(null);
final PaymentProfile paymentProfile = PaymentProfile.createPaymentProfile();
paymentProfile.addPayment(Payment.createPayment(creditCard));
paymentProfile.setCustomerType(CustomerType.INDIVIDUAL);
paymentProfile.setBillTo(address);
final CustomerProfile customerProfile = CustomerProfile.createCustomerProfile();
customerProfile.setMerchantCustomerId("AAAAAA");
customerProfile.setDescription(UUID.randomUUID().toString());
final ValidationModeType validationMode = ValidationModeType.TEST_MODE;
// Create a new customer profile
final net.authorize.cim.Transaction transaction = merchant.createCIMTransaction(TransactionType.CREATE_CUSTOMER_PROFILE);
transaction.setCustomerProfile(customerProfile);
transaction.addPaymentProfile(paymentProfile);
transaction.setValidationMode(validationMode);
final net.authorize.cim.Result<Transaction> result = (net.authorize.cim.Result<Transaction>) merchant.postTransaction(transaction);
if (false == result.isOk()) {
final StringBuilder stringBuilder = new StringBuilder();
boolean isFirst = true;
for (final Message message : result.getMessages()) {
final String code = message.getCode();
final String text = message.getText();
if (isFirst == false) {
stringBuilder.append(", ");
}
stringBuilder.append(code+": "+text);
isFirst = false;
}
throw new RuntimeException("["+result.getResultCode()+"] "+stringBuilder.toString());
}
}
Luckily, the fix for this is very simple. In your net.authorize.cim.Transaction.java file, in the addPayment method you need to modify the following lines:
Element card_code_el = document.createElement(AuthNetField.ELEMENT_CARD_CODE.getFieldName());
card_code_el.appendChild(document.getDocument().createTextNode(credit_card.getCardCode()));
cc_el.appendChild(card_code_el);
All you need to do is wrap an if statement around it, like so:
if (StringUtils.isNotEmpty(credit_card.getCardCode())) {
Element card_code_el = document.createElement(AuthNetField.ELEMENT_CARD_CODE.getFieldName());
card_code_el.appendChild(document.getDocument().createTextNode(credit_card.getCardCode()));
cc_el.appendChild(card_code_el);
}
Hi,
I tested the use case where a transaction is created using the card's track data (a card present transaction) and then followed up with voiding that transaction. When I void it, it fails with a NumberFormatException. I think I've traced it down to the response code being "1.0" instead of "1", which triggers the exception when trying to convert it to an Integer. It's important to note that if the transaction is created without using the track data, say by setting the card number manually, the void works fine (that's because the response code returns a "1" instead of a "1.0" allowing a successful integer conversion.
Also, note that I'm using a Card Not Present (CNP) Authorize.net account with CIM enabled, if that matters.
Let's start with the test case (substitute your credentials):
package com.thinkreservations.service.gateway.impl;
import java.math.BigDecimal;
import net.authorize.Environment;
import net.authorize.Merchant;
import net.authorize.Transaction;
import net.authorize.data.creditcard.CreditCard;
import org.junit.Test;
import com.thinkreservations.service.exception.restful.CreditCardProcessorFailedException;
public class AuthorizeNetTest {
@Test
public void test() {
final String apiLoginId = "YOUR_API_LOGIN_ID_TO_A_CARD_NOT_PRESENT_ACCOUNT";
final String transactionKey = "YOUR_TRANSACTION_KEY_TO_A_CARD_NOT_PRESENT_ACCOUNT";
// Create the Card Present transaction
String transactionId;
{
final Merchant merchant = Merchant.createMerchant(Environment.SANDBOX, apiLoginId, transactionKey);
merchant.setDeviceType(net.authorize.DeviceType.VIRTUAL_TERMINAL);
merchant.setMarketType(net.authorize.MarketType.RETAIL);
final CreditCard creditCard = CreditCard.createCreditCard();
creditCard.setTrack1("%B370000000000002^CARDUSER/JOHN^1803101000000000020000831000000?");
final BigDecimal amount = BigDecimal.valueOf(1.99);
final net.authorize.aim.Transaction transaction = merchant.createAIMTransaction(net.authorize.TransactionType.AUTH_CAPTURE, amount);
transaction.setCreditCard(creditCard);
final net.authorize.aim.cardpresent.Result<Transaction> result = (net.authorize.aim.cardpresent.Result<Transaction>) merchant.postTransaction(transaction);
if (false == result.isApproved()) {
throw new CreditCardProcessorFailedException("["+result.getResponseCode()+"] "+result.getResponseReasonCodes().get(0)+": "+result.getResponseReasonCodes().get(0).getReasonText());
}
transactionId = result.getTransId();
}
// Void the transaction
{
final Merchant merchant = Merchant.createMerchant(Environment.SANDBOX, apiLoginId, transactionKey);
final net.authorize.aim.Transaction transaction = merchant.createAIMTransaction(net.authorize.TransactionType.VOID, null);
transaction.setTransactionId(transactionId);
final net.authorize.aim.Result<Transaction> result = (net.authorize.aim.Result<Transaction>) merchant.postTransaction(transaction);
if (false == result.isApproved()) {
throw new CreditCardProcessorFailedException("["+result.getResponseCode()+"] "+result.getResponseText());
}
}
}
}
Wire log:
DEBUG: org.apache.http.wire - >> "POST /gateway/transact.dll HTTP/1.1[\r][\n]"
DEBUG: org.apache.http.wire - >> "Content-Type: application/x-www-form-urlencoded; charset=utf-8[\r][\n]"
DEBUG: org.apache.http.wire - >> "Content-Length: 408[\r][\n]"
DEBUG: org.apache.http.wire - >> "Host: test.authorize.net[\r][\n]"
DEBUG: org.apache.http.wire - >> "Connection: Keep-Alive[\r][\n]"
DEBUG: org.apache.http.wire - >> "User-Agent: Apache-HttpClient/4.3.1 (java 1.5)[\r][\n]"
DEBUG: org.apache.http.wire - >> "[\r][\n]"
DEBUG: org.apache.http.wire - >> "x_tran_key=9Ktc364dmk6T94Fz&x_allow_partial_Auth=FALSE&x_market_type=2&x_card_num=&x_method=CC&x_delim_data=TRUE&x_exp_date=&x_relay_response=FALSE&x_login=3uDJcL26PRN&x_version=3.1&x_device_type=10&x_amount=1.99&x_test_request=FALSE&x_type=AUTH_CAPTURE&x_delim_char=%7C&x_cpversion=1.0&x_response_format=0&x_track2=&x_encap_char=&x_track1=BMASKED**0002%5ECARDUSER%2FJOHN%5EMASKED**0000MASKED**0000"
DEBUG: org.apache.http.wire - << "HTTP/1.1 200 OK[\r][\n]"
DEBUG: org.apache.http.wire - << "Cache-Control: private, must-revalidate, max-age=0[\r][\n]"
DEBUG: org.apache.http.wire - << "Content-Length: 516[\r][\n]"
DEBUG: org.apache.http.wire - << "Content-Type: text/xml[\r][\n]"
DEBUG: org.apache.http.wire - << "Expires: Tue, 01 Jan 1980 00:00:00 GMT[\r][\n]"
DEBUG: org.apache.http.wire - << "Server: Microsoft-IIS/7.5[\r][\n]"
DEBUG: org.apache.http.wire - << "X-Powered-By: ASP.NET[\r][\n]"
DEBUG: org.apache.http.wire - << "Date: Fri, 10 Oct 2014 18:34:24 GMT[\r][\n]"
DEBUG: org.apache.http.wire - << "Connection: close[\r][\n]"
DEBUG: org.apache.http.wire - << "[\r][\n]"
DEBUG: org.apache.http.wire - << "<?xml version="1.0" ?><response><ResponseCode>1</ResponseCode><Messages><Message><Code>1</Code><Description><![CDATA[This transaction has been approved.]]></Description></Message></Messages><AuthCode><![CDATA[AXOFVN]]></AuthCode><AVSResultCode>Y</AVSResultCode><CVVResultCode></CVVResultCode><TransID>2222211937</TransID><RefTransID></RefTransID><TransHash>305F339BA37F634C7B4FA0A7DA8894EC</TransHash><TestMode>0</TestMode><AccountNumber>XXXX0002</AccountNumber><AccountType>American Express</AccountType></response>"
DEBUG: org.apache.http.wire - >> "POST /gateway/transact.dll HTTP/1.1[\r][\n]"
DEBUG: org.apache.http.wire - >> "Content-Type: application/x-www-form-urlencoded; charset=utf-8[\r][\n]"
DEBUG: org.apache.http.wire - >> "Content-Length: 229[\r][\n]"
DEBUG: org.apache.http.wire - >> "Host: test.authorize.net[\r][\n]"
DEBUG: org.apache.http.wire - >> "Connection: Keep-Alive[\r][\n]"
DEBUG: org.apache.http.wire - >> "User-Agent: Apache-HttpClient/4.3.1 (java 1.5)[\r][\n]"
DEBUG: org.apache.http.wire - >> "[\r][\n]"
DEBUG: org.apache.http.wire - >> "x_tran_key=9Ktc364dmk6T94Fz&x_allow_partial_Auth=FALSE&x_trans_id=2222211937&x_version=3.1&x_amount=0.00&x_delim_data=TRUE&x_type=VOID&x_test_request=FALSE&x_delim_char=%7C&x_relay_response=FALSE&x_encap_char=&x_login=3uDJcL26PRN"
DEBUG: org.apache.http.wire - << "HTTP/1.1 200 OK[\r][\n]"
DEBUG: org.apache.http.wire - << "Cache-Control: private, must-revalidate, max-age=0[\r][\n]"
DEBUG: org.apache.http.wire - << "Content-Length: 128[\r][\n]"
DEBUG: org.apache.http.wire - << "Content-Type: text/html[\r][\n]"
DEBUG: org.apache.http.wire - << "Expires: Tue, 01 Jan 1980 00:00:00 GMT[\r][\n]"
DEBUG: org.apache.http.wire - << "Server: Microsoft-IIS/7.5[\r][\n]"
DEBUG: org.apache.http.wire - << "X-Powered-By: ASP.NET[\r][\n]"
DEBUG: org.apache.http.wire - << "Date: Fri, 10 Oct 2014 18:34:24 GMT[\r][\n]"
DEBUG: org.apache.http.wire - << "Connection: close[\r][\n]"
DEBUG: org.apache.http.wire - << "[\r][\n]"
DEBUG: org.apache.http.wire - << "1.0|1|1|This transaction has been approved.||P||2222211937|12B1AA66FCCF02D998C3CD2623973A91||||||||||||XXXX0002|American Express"
Stack trace:
java.lang.NumberFormatException: For input string: "1.0"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
at java.lang.Integer.parseInt(Integer.java:458)
at java.lang.Integer.parseInt(Integer.java:499)
at net.authorize.aim.Result.createResult(Result.java:33)
at net.authorize.Merchant.postTransaction(Merchant.java:287)
at com.thinkreservations.service.gateway.impl.AuthorizeNetTest.test(AuthorizeNetTest.java:53)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
If you look at the last line of the wire log, you'll notice that the response code (the first number in the string) is set to "1.0". That causes line 33 in Result.java to throw an exception. Here's the relevant code (the Integer.parseInt method throws the exception):
String responseCodeStr = responseMap.get(ResponseField.RESPONSE_CODE);
result.responseCode = responseCodeStr!=null && !"".equals(responseCodeStr)?
ResponseCode.findByResponseCode(Integer.parseInt(responseCodeStr)):
ResponseCode.ERROR;
Thanks for looking into this.
Alfred
XMLUtility.java line 73 uses java.lang.String.isEmpty() which is only available starting from java 1.6. So API fails to run on Java 1.5
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.