AuthorizeNet / inperson-sdk-ios

Card-present, in-person SDK for Authorize.Net.
Other
38 stars 47 forks source link

Why "emv data is not supported with this market type" error appears when card transaction is processed? #59

Closed orafoxinc closed 7 years ago

orafoxinc commented 7 years ago

I'm developing an iPad application. I have integrated unperson sdk in my project. Running app with ENV_LIVE environment and process card transaction, gives me this error. What is the reason for this error to pop? Below is my code:

-(void)swipeCard
{
    LineItemType *anItem = [LineItemType lineItem];
    anItem.itemID = @"0";
    anItem.itemPrice = self.tfTotalAmount.text;
    anItem.itemName = @"AuthDemo";
    anItem.itemTaxable = NO;
    anItem.itemQuantity = @"1";
    anItem.itemDescription = @"goods";

    AnetEMVTransactionRequest *aRequest = [[AnetEMVTransactionRequest alloc] init];
    aRequest.lineItems = [NSMutableArray arrayWithObject:anItem];
    aRequest.emvTransactionType = EMVTransactionType_Payment;
    aRequest.anetApiRequest.merchantAuthentication.sessionToken = self.strSessionToken;
    aRequest.anetApiRequest.merchantAuthentication.mobileDeviceId = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
    aRequest.amount = self.tfTotalAmount.text;

    [emvManager startEMVWithTransactionRequest:aRequest presentingViewController:self completionBlock:^(AnetEMVTransactionResponse * _Nullable response, AnetEMVError * _Nullable error) {

        NSLog(@"Response: %@", response.responseCode);
        NSLog(@"Response: %@", error);

        UIAlertView *alert=[[UIAlertView alloc]initWithTitle:@"" message:response.responseCode delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
        [alert show];

    } andCancelActionBlock:^{
        NSLog(@"canceled");
    }];

}
jtraynham commented 7 years ago

You need to add something like this:

aRequest.retail = [[TransRetailInfoType alloc] init];
aRequest.retail.marketType = @"2"; // "Retail"
aRequest.retail.deviceType = @"7"; // "Wireless POS"
hiren43 commented 7 years ago

Thank you for your response. Adding your code did not change anything as same error still pops up. Then I noticed in your code that 'aRequest' is allocated as type TransRetailInfoType. I was using AnetEMVTransactionRequest *aRequest = [[AnetEMVTransactionRequest alloc] init];

Allocating aRequest object of type 'TransRetailInfoType' did not work as it could not find other methods from 'AnetEMVTransactionRequest' class such as lineItems and emvTransactionType. So can you please give me a complete solution for this?

ptaneja commented 7 years ago
func transactionObject() -> AnetEMVTransactionRequest {
    let aRequest = AnetEMVTransactionRequest()
    aRequest.emvTransactionType = .goods;
    let amountAndProducts = self.totalAmountAndProduct()
    aRequest.lineItems = amountAndProducts.products
    aRequest.anetApiRequest.merchantAuthentication.sessionToken = self.sessionToken
    aRequest.anetApiRequest.merchantAuthentication.mobileDeviceId = "454545454545454545454"
    aRequest.amount = "\(amountAndProducts.totalAmount)"

    let order = OrderType()
    order.invoiceNumber = randoMax10DigitString()
    order.orderDescription = "Order from Sample Application"
    aRequest.order = order

    aRequest.retail = TransRetailInfoType()
    aRequest.retail.marketType = "2"
    aRequest.retail.deviceType = "7"

    }
hiren43 commented 7 years ago
   LineItemType *anItem = [LineItemType lineItem];
    anItem.itemID = @"0";
    anItem.itemPrice = self.tfTotalAmount.text;
    anItem.itemName = @"AuthDemo";
    anItem.itemTaxable = NO;
    anItem.itemQuantity = @"1";
    anItem.itemDescription = @"goods";

    AnetEMVTransactionRequest *aRequest = [[AnetEMVTransactionRequest alloc] init];
    //aRequest.lineItems = (NSMutableArray *)anItem;
    aRequest.lineItems = [NSMutableArray arrayWithObject:anItem];
    aRequest.emvTransactionType = EMVTransactionType_Goods;
    aRequest.anetApiRequest.merchantAuthentication.sessionToken = self.strSessionToken;
    aRequest.anetApiRequest.merchantAuthentication.mobileDeviceId = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
    aRequest.amount = self.tfTotalAmount.text;

    OrderType *orderTest = [[OrderType alloc] init];
    orderTest.invoiceNumber = [NSString stringWithFormat:@"%ld", random()];
    orderTest.orderDescription = @"Order from Sample Application";
    aRequest.order = orderTest;

    aRequest.retail = [[TransRetailInfoType alloc] init];
    aRequest.retail.marketType = @"2"; // "Retail"
    aRequest.retail.deviceType = @"7"; // "Wireless POS"

Processing debit card with above code gives me "Transaction was unsuccessful" alert with this log in xcode: "AUTHORISATION SUCCESSFUL BUT CARD DECLINED OR TERMINATED THE TRANSACTION". Am I doing anything wrong here?

ptaneja commented 7 years ago

Could you try with some other card?

hiren43 commented 7 years ago

I've already tried with 4-5 cards including debit and credit cards. Even the demo project I downloaded showing same alert "transaction unsuccessful". But amount is deducted

ptaneja commented 7 years ago

Only authorization was successful, transaction did not go thruogh. Amount will be reversed automatically. Which is your processor?

hiren43 commented 7 years ago

A9X. I do not think device processor as an issue. I'm trying this on iPad pro 9.7-Inch. I also tried on an old iPad as well. If transaction didn't occur, I'm wondering how the amount was deducted from my account. I'm getting logged in with merchant account credentials by setting live environment. Can you please recheck my code I mentioned in my last post and let me know if I did anything wrong?

ptaneja commented 7 years ago

Who is your merchant account processor? Like FDC or TSYS? Transaction occured but only authorization was successful, card declined thr transaction hence settlement did not even start. Whatever you see in your account will be in pending state and removed once transaction is automatically reversed.

hiren43 commented 7 years ago

Okay below is my processor configuration setting.

Processor Configuration Processor: First Data Nashville

hiren43 commented 7 years ago

So all the transactions come under 'unsettled transaction' with trans status: Authorized/Pending Capture(Transactions with this status have been authorized by the processor but will not be sent for settlement until a capture is performed). How do I need to perform capture?

Can anyone help me with this?

hiren43 commented 7 years ago
    CreditCardType *creditCardType = [CreditCardType creditCardType];
    creditCardType.cardNumber = @"41111111111111111"";
    creditCardType.cardCode = @"100";
    creditCardType.expirationDate = @"01/20";

    PaymentType *paymentType = [PaymentType paymentType];
    paymentType.creditCard = creditCardType;

    ExtendedAmountType *extendedAmountTypeTax = [ExtendedAmountType extendedAmountType];
    extendedAmountTypeTax.amount = @"0";
    extendedAmountTypeTax.name = @"Tax";

    ExtendedAmountType *extendedAmountTypeShipping = [ExtendedAmountType extendedAmountType];
    extendedAmountTypeShipping.amount = @"0";
    extendedAmountTypeShipping.name = @"Shipping";

    LineItemType *lineItem = [LineItemType lineItem];
    lineItem.itemName = @"AuthCaptureProduct";
    lineItem.itemDescription = @"AuthCaptureProductDescription";
    lineItem.itemQuantity = @"1";
    lineItem.itemPrice = @"0.01";
    lineItem.itemID = @"1";

    TransactionRequestType *requestType = [TransactionRequestType transactionRequest];
    requestType.lineItems = [NSMutableArray arrayWithObject:lineItem];
    requestType.amount = lineItem.itemPrice;
    requestType.payment = paymentType;
    requestType.tax = extendedAmountTypeTax;
    requestType.shipping = extendedAmountTypeShipping;

    CreateTransactionRequest *request = [CreateTransactionRequest createTransactionRequest];
    request.transactionRequest = requestType;
    request.transactionType = AUTH_CAPTURE;
    request.anetApiRequest.merchantAuthentication.mobileDeviceId = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
    request.anetApiRequest.merchantAuthentication.sessionToken = self.strSessionToken;

    AuthNet *an = [AuthNet getInstance];
    [an setDelegate:self];
    [an purchaseWithRequest:request];

Above code works perfectly. But only problem is how do I get credit card information from user? User is supposed to swipe credit card to make payment but I'm not able to find any callback delegate when card is swiped. The document itself is so messy.

ptaneja commented 7 years ago

You are trying to implement two different flow at the same time.

  1. EMV flow: Where in Framework talks with the reader and does the full transaction, your application won't get any callback. Your application will be notified about the Status of the transaction(Success/Failure) or if user cancels the transaction in completion blocks.

  2. Request which works for you is Non-EMV transaction flow, where in your application accepts the card information from the user and sends it to the framework by populating CreditCardType and CreateTransactionRequest objects.

Below is your EMV request, which looks ok LineItemType *anItem = [LineItemType lineItem]; anItem.itemID = @"0"; anItem.itemPrice = self.tfTotalAmount.text; anItem.itemName = @"AuthDemo"; anItem.itemTaxable = NO; anItem.itemQuantity = @"1"; anItem.itemDescription = @"goods";

AnetEMVTransactionRequest *aRequest = [[AnetEMVTransactionRequest alloc] init];
//aRequest.lineItems = (NSMutableArray *)anItem;
aRequest.lineItems = [NSMutableArray arrayWithObject:anItem];
aRequest.emvTransactionType = EMVTransactionType_Goods;
aRequest.anetApiRequest.merchantAuthentication.sessionToken = self.strSessionToken;
aRequest.anetApiRequest.merchantAuthentication.mobileDeviceId = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
aRequest.amount = self.tfTotalAmount.text;

OrderType *orderTest = [[OrderType alloc] init];
orderTest.invoiceNumber = [NSString stringWithFormat:@"%ld", random()];
orderTest.orderDescription = @"Order from Sample Application";
aRequest.order = orderTest;

aRequest.retail = [[TransRetailInfoType alloc] init];
aRequest.retail.marketType = @"2"; // "Retail"
aRequest.retail.deviceType = @"7"; // "Wireless POS"

How many readers you own?

hiren43 commented 7 years ago

I have only one reader: Anywherecommerce. With the EMV flow, I get "Unsuccessful Transaction alert" like I said before. And transaction status in my merchant account shows as "Authorized/Pending Capture". So with this flow, do I need to capture the transaction separately?

ptaneja commented 7 years ago

@hiren43 No, you don't need to capture the transaction separately.

Below is the EMV transaction flow: Once online Authorization is done, online authorization response is sent to the chip in the card which decides to approve/decline the transaction. Once card approves the transaction, framework will capture the transaction automatically, you don't need to do anything.

Possible reason for unsuccessful transaction in your case:

  1. The account you use, doesn't have permission to capture/void the transaction.
  2. Reader is missing the set of keys, due to which card declines the transaction.

Let me share the steps to check if your account have permission to capture/void the transaction in my next reply.

hiren43 commented 7 years ago

Can you please share steps to find the permission to capture transaction in merchant account? Or whatever reason might be causing this error. This is what I do in my EMV flow

  1. Setting up AuthNet with ENV_LIVE environment

  2. Performing login with 'MobileDeviceLoginRequest' using merchant account and password

  3. Getting session token from login success and transferring to payment screen.

  4. Setting up AnetEMVManager object using 'initWithCurrecyCode: terminalID: skipSignature: showReceipt:'

  5. Executing code mentioned in above post when Pay button is tapped

Am I doing anything wrong here?

ptaneja commented 7 years ago

Yes, above steps are correct.

  1. Your Account Owner needs to log into the account.
  2. Once logged in click on Account
  3. Then Click on User Administration
  4. Click on the User’s Name
  5. Click Edit Permissions
  6. Check this box Update unsettled transactions Void transactions, submit previously authorized transactions for capture, approve or decline FDS transactions
  7. Enter the Secret Answer and hit submit
hiren43 commented 7 years ago

As of now I do not have permission to change user's role. I will check that out soon. I have one query regarding code.

Do I need to keep this "aRequest.retail = [[TransRetailInfoType alloc] init];" line in my code? Keeping this line shows me alert "Unsuccessful Transaction". If I comment out this line, I'm shown a receipt mentioning status "EMV data is not supported with this market type". I guess I need to keep this line. After getting role to update unsettled transactions, I will be shown this receipt on payment success.

Following is the log when "Unsuccessful Transaction" alert pops. It mentions here "This account has not been given the permission(s) required for this request"

2017-11-08 12:38:26.858 AuthnetDemo[3448:1171953] Error = (null)
2017-11-08 12:38:27.369 AuthnetDemo[3448:1171953] AUTHORISATION SUCCESSFUL BUT CARD DECLINED OR TERMINATED THE TRANSACTION
2017-11-08 12:38:27.378 AuthnetDemo[3448:1171953] ENV value in defaults (null)
2017-11-08 12:38:27.378 AuthnetDemo[3448:1171953] URL: https://api.authorize.net/xml/v1/request.api 
2017-11-08 12:38:27.383 AuthnetDemo[3448:1171953] Reachability Flag Status: -R ------- networkStatusForFlags
2017-11-08 12:38:27.385 AuthnetDemo[3448:1171953] CreateTransactionRequest: <transactionRequest><transactionType>voidTransaction</transactionType><amount>0.01</amount><solution><id>A1000025</id></solution><terminalNumber>6958543</terminalNumber><refTransId>60763918409</refTransId><order></order><lineItems></lineItems><customer></customer><billTo></billTo><shipTo></shipTo><retail><marketType>2</marketType><deviceType>7</deviceType></retail><transactionSettings></transactionSettings><userFields></userFields></transactionRequest>
2017-11-08 12:38:30.642 AuthnetDemo[3448:1171953] CreateTransactionResponse <?xml version="1.0" encoding="utf-8"?><createTransactionResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd"><messages><resultCode>Error</resultCode><message><code>E00027</code><text>The transaction was unsuccessful.</text></message></messages><sessionToken>f_gjTCH6NSQOO3tjYps1a7IkmJwCq$Hp2TmFN1PZECHcGqfGpNsMTK0Y8RgUl$z7z7k0R3zlIq9Tq_i2xmgDjXBgbLb45$0zSaowwECTo$0xS0C4eyg1fm$xQbH6Z$4yTK6xZ2FDKd5vPCj1V_U0rQAA</sessionToken><transactionResponse><responseCode>3</responseCode><authCode /><avsResultCode>P</avsResultCode><cvvResultCode /><transId>0</transId><refTransID>60763918409</refTransID><transHash>58D4B1DD58012A0B4034DB59CE140410</transHash><testRequest>0</testRequest><accountNumber /><accountType>Visa</accountType><errors><error><errorCode>123</errorCode><errorText>This account has not been given the permission(s) required for this request.</errorText></error></errors><transHashSha2 /></transactionResponse></createTransactionResponse>
namespace warning : xmlns: URI AnetApi/xml/v1/schema/AnetApiSchema.xsd is not absolute
ttp://www.w3.org/2001/XMLSchema" xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd"
ptaneja commented 7 years ago

You need that line and object to be set. Once you have permission issue resolved that will be successful transactions.aRequest.retail = [[TransRetailInfoType alloc] init]; aRequest.retail.marketType = @"2"; // "Retail" aRequest.retail.deviceType = @"7"; // "Wireless POS"

hiren43 commented 7 years ago

It was indeed permission related issue. Logging in as a transaction manager solved my issue. Thank you.