question

yasu avatar image
yasu asked yasu commented

Refund fails with the error: "Could not void\/return transaction: TOKEN FAILURE"

Hello, I have been testing refund transaction, but it does not work anymore. Last time when I saw the refund works was August 20th (2 month ago). Is there anyone who has had same issue? What should I do with the error message

Could not void\/return transaction: TOKEN FAILURE

?

Log

I/--- Server:send: Rest of the delay: 56959
D/MainActivity: RefundPaymentRequest - Full: RefundPaymentRequest{json='{"paymentId":"CVN5583C3N32W","orderId":"T4TPSJQQ52ZWA","fullRefund":true}', bundle=null, changeLog=Bundle[{orderId=null, fullRefund=null, paymentId=null}]}
I/--- Server:send: Rest of the delay: 53952
I/--- Server:send: Rest of the delay: 50906
I/--- Server:send: Rest of the delay: 47864
I/--- Server:send: Rest of the delay: 44820
I/--- Server:send: Rest of the delay: 41784
I/--- Server:send: Rest of the delay: 38740
I/--- Server:send: Rest of the delay: 35696
D/FullRefund: Full Refund Request was sent successfully.
    check# : 9
    amount : -1149
    tip : 0
I/Choreographer: Skipped 1244 frames!  The application may be doing too much work on its main thread.
W/MainActivity: onPause -----------------6
V/RenderScript: 0xb8d8af58 Launching thread(s), CPUs 4
W/IInputConnectionWrapper: showStatusIcon on inactive InputConnection
I/--- Server:send: Rest of the delay: 32660
I/--- Server:send: Rest of the delay: 29616
W/PAY-----: onRefundPaymentResponse: RefundPaymentResponse{json='{"success":false,"result":"FAIL","message":"Could not void\/return transaction: TOKEN FAILURE","refund":null}', bundle=null, changeLog=Bundle[{success=null, refund=null, result=null, message=null}]}
I/--- Server:send: Rest of the delay: 26571
I/--- Server:send: Rest of the delay: 23526
I/--- Server:send: Rest of the delay: 20477
I/--- Server:send: Rest of the delay: 17434
I/--- Server:send: Rest of the delay: 14374
I/--- Server:send: Rest of the delay: 11287
W/System.err: Refund Request Failed - null

Refund request

private void makeFullRefund(){
        PayInfo payInfo = mEmporterPayInfo;
        boolean isRefundRequestSent = false;
        int enteredCheckNum = 0;

        // 1. Check if exists the sale transaction to refund
        for (CheckInfo aTransaction : pastTransactions) {
            int checkNumTrans = aTransaction.getNumber();//The check number which was stored beforehand
            enteredCheckNum = payInfo.mCheckInfo.getNumber();
            if(aTransaction.getDate() == null)
                continue;

            if(aTransaction.getDate().equals(payInfo.mCheckInfo.getDate())) {
                if (aTransaction.getStatus() == CheckInfo.Status.PAID) {
                    if (checkNumTrans == enteredCheckNum) {

                        //prepare to show tip amount after getting a refund request's response successfully
                        payInfo.mTipAmount = aTransaction.getTip();

                        // 2. Process full refund transaction
                        RefundPaymentRequest refund = new RefundPaymentRequest();
                        refund.setPaymentId(aTransaction.getPaymentId());
                        refund.setOrderId(aTransaction.getOrderId());
                        refund.setFullRefund(true);
                        Log.d(TAG, "RefundPaymentRequest - Full: " + refund.toString());
                        isRefundRequestSent = true;
                        paymentConnector.refundPayment(refund);// check payInfo.mTipAmount
                    }
                } else if (aTransaction.getStatus() == CheckInfo.Status.REFUNDED) {
                    Toast.makeText(this, "The refund for check #" + enteredCheckNum + " was already completed.", Toast.LENGTH_SHORT).show();
                    Log.d("FullRefund", "The refund was already completed.");
                }
            }
        }

        if (isRefundRequestSent) {
            Toast.makeText(this, "Full Refund Request was sent successfully.", Toast.LENGTH_LONG).show();
            Log.d("FullRefund", "Full Refund Request was sent successfully.");
        } else {
            // In case you have found nothing
            Log.d("FullRefund", "Full Refund Request was not sent because the check #" + enteredCheckNum + " does not exist in this app." );
            UI_sendMessage(MSG_ERROR_NO_CHECK_TO_REFUND);
        }

        logCheckNumAmount("FullRefund", payInfo);
    }

Response

@Override
public void onRefundPaymentResponse(RefundPaymentResponse response) {
                if (DEBUG) Log.w("PAY-----", "onRefundPaymentResponse: " + response);
                
                PayInfo payInfo = mEmporterPayInfo;
                try {
                    if (response.getSuccess()) {
                        int checkNumToDelete = payInfo.mCheckInfo.getNumber();
                        String checkNumDate = payInfo.mCheckInfo.getDate();
                        deleteOneRecord(checkNumToDelete, checkNumDate);

                        Refund refund = response.getRefund();
                        System.out.println("Refund Request Successful");
                        System.out.println("  ID: " + refund.getId());
                        System.out.println("  Amount: " + refund.getAmount());
                        System.out.println("  Order ID: " + response.getOrderId());
                        System.out.println("  Payment ID: " + response.getPaymentId());

                        payInfo.mRespCode = CODE_OK;
                        payInfo.mRespMessage = "";

                        payInfo.mExpDate = null;
                        payInfo.mPurchaseAmount = refund.getAmount();
                        payInfo.mCashBackAmount = 0;
                        payInfo.mSurchargeAmount = 0;
                        payInfo.mTipAmount = -payInfo.mTipAmount;

                        payInfo.mCheckInfo.setStatus(CheckInfo.Status.REFUNDED);
                        logCheckNumAmount("REFUND-----", payInfo);
                        UI_sendMessage(MSG_REFUND_FINISH);
                        return;
                    } else {
                        System.err.println("Refund Request Failed - " + response.getReason());
                    }
                } catch (Exception ex) {
                    System.err.println("Error handling sale response: " + ex);
                }
            }


Clover Android SDKClover Flex
10 |2000 characters needed characters left characters exceeded

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

David Marginian avatar image
David Marginian answered yasu commented

I assume this is happening in sandbox? What SDK are you using?

1 comment
10 |2000 characters needed characters left characters exceeded

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Yes it is. I'm using Clover SDK for Android.

In gradle file:

implementation 'com.clover.sdk:clover-android-sdk:262.2'
implementation 'com.clover.sdk:clover-android-connector-sdk:262.2'
0 Likes 0 ·
yasu avatar image
yasu answered

I have found this (it's JavaScript though...), but without any specific solution...

https://community.clover.com/questions/32358/refund-request-failed-could-not-voidreturn-transac.html

10 |2000 characters needed characters left characters exceeded

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

David Marginian avatar image
David Marginian answered yasu commented

Is this happening on Sandbox or Production?

1 comment
10 |2000 characters needed characters left characters exceeded

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

This is happening on Sandbox.
0 Likes 0 ·

Write an Answer

Hint: Notify or tag a user in this post by typing @username.

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Welcome to the
Clover Developer Community