简体   繁体   中英

Authorize.net embedded iFrame accept.js response transaction

I have integrated authorize.net accept.js embedded iFrame in my application. Having trouble setting the transaction respone in my lambda function to get the response. I've seen similar questions on stack overflow but nothing worked out for me yet.

Using Nodejs for my backend and angular7 for the front-end.

I successfully get the token from my lambda function so my iframe appears on the ui. I've set \"showReceipt\": false providing url for cancel & continue, since the documentation says I have to set the show receipt parameter "false" in order to communicate with the IFrameCommunicator.html in the ui. But when I click on "Pay" its stuck at "Processing.." for a long time.

Following are the request & response headers respectively from the.network tab:

* Cookie: __cfruid=deb63d2f12d9690aeea838cf7f31ada6da92bc1c-1602260930
* Host: test.authorize.net
* Origin: https://test.authorize.net
* Referer: https://test.authorize.net/payment/payment
* Sec-Fetch-Dest: empty
* Sec-Fetch-Mode: cors
* 
Sec-Fetch-Site: same-origin
{"resultCode":"Ok","messageCode":"Ok","transactionData":{"accountType":"Discover","accountNumber":"XXXX0012","transId":"40055282319","responseCode":"4","authorization":"TYIUU7","merchantName":"iMart Inc.","totalAmount":"1999.9","dateTime":"10/09/2020 4:20:27 PM"}}

I'm sure the transaction is happening looking at the response but not sure why it's not connecting with the communicator.

I've read the steps in the documentation and also followed the GitHub sample code-https://github.com/AuthorizeNet/accept-sample-app, which made me more confused since they both say different things at some places. Following are the steps I've accomplished until now:

  1. Created a lambda hosted payment function with all the settings (followed the correct sequence) to get back a token.
  2. Created a hosted payment form to display the iframe.
  3. Able to make a payment --> get the receipt page --> routing to success screen.

What I'm trying to accomplish:

  1. After I make the payment, initial idea was to trigger a different lambda function based on the response from authorize.net without communicating with IFrameCommunicator.html, but as I cannot do that, I want to get a response to initiate the next process at the backend.

  2. Also, we're not storing any user details in our server and not interested in creating a customer profile unless it's a necessary step to get the transaction response. Please suggest the step integration if I can do it in the same lambda function I've created to get a token or I would have to create a different one for this and when will that step be implemented?

  3. I know about the Webhooks but not sure if it's an absolute necessity at this point of time when I'm just trying to implement a simple transaction.

I'm a newbie and I couldn't find a lot of examples related to the same to resolve my issues/confusions. Would highly appreciate if I get a clear explanation on the steps here and where am I going wrong.

Following is the code -

accept-hosted.js Lambda function:

    merchantAuthenticationType.setName('*****');
    merchantAuthenticationType.setTransactionKey('******');

    var transactionRequestType = new ApiContracts.TransactionRequestType();
    transactionRequestType.setTransactionType(ApiContracts.TransactionTypeEnum.AUTHCAPTURETRANSACTION);
    transactionRequestType.setAmount(Total);

    var setting1 = new ApiContracts.SettingType();
    var setting2 = new ApiContracts.SettingType();
    var setting4 = new ApiContracts.SettingType();
    var setting5 = new ApiContracts.SettingType();
    var setting6 = new ApiContracts.SettingType();
    var setting7 = new ApiContracts.SettingType();
    var setting8 = new ApiContracts.SettingType();
    var setting9 = new ApiContracts.SettingType();
    var setting10 = new ApiContracts.SettingType();
    var setting11 = new ApiContracts.SettingType();

    setting2.setSettingName("hostedPaymentButtonOptions");
    setting2.setSettingValue("{\"text\": \"Pay\"}");

    setting1.setSettingName("hostedPaymentReturnOptions");
    setting1.setSettingValue(
        "{\"showReceipt\": false, \"url\": \"https://iMart.com/success.html\", \"urlText\": \"Continue\", \"cancelUrl\": \"https://iMart.com/error.html\", \"cancelUrlText\": \"Cancel\"}");


    setting10.setSettingName("hostedPaymentOrderOptions");
    setting10.setSettingValue("{\"show\": false, \"merchantName\": \"iMart Inc.\"}");

    setting5.setSettingName("hostedPaymentPaymentOptions");
    setting5.setSettingValue("{\"cardCodeRequired\": true, \"showCreditCard\": true, \"showBankAccount\": false}");

    setting7.setSettingName("hostedPaymentShippingAddressOptions");
    setting7.setSettingValue("{\"show\": false, \"required\": false}");

    setting8.setSettingName("hostedPaymentBillingAddressOptions");
    setting8.setSettingValue("{\"show\": false, \"required\": false}");

    setting6.setSettingName("hostedPaymentSecurityOptions");
    setting6.setSettingValue("{\"captcha\": true}");

    setting4.setSettingName("hostedPaymentStyleOptions");
    setting4.setSettingValue("{\"bgColor\": \"blue\"}");

    setting9.setSettingName("hostedPaymentCustomerOptions");
    setting9.setSettingValue("{\"showEmail\": false, \"requiredEmail\": false, \"addPaymentProfile\": true }");

    setting11.setSettingName("hostedPaymentIFrameCommunicatorUrl");
    setting11.setSettingValue("{\"url\": \"https://iMart.com/IFrameCommunicator.html\"}");
    
    var settingList = [];

    settingList.push(setting2);
    settingList.push(setting10);
    settingList.push(setting5);
    settingList.push(setting7);
    settingList.push(setting8);
    settingList.push(setting6);
    settingList.push(setting4);
    settingList.push(setting9);
    settingList.push(setting11);
    settingList.push(setting1);


    var alist = new ApiContracts.ArrayOfSetting();
    alist.setSetting(settingList);
    var firstname = new ApiContracts.UserField();
    firstname.setName('First Name');
    firstname.setValue(firstName);

    var lastname = new ApiContracts.UserField();
    lastname.setName('Last Name');
    lastname.setValue(lastName);

    var userFieldList = [];
    userFieldList.push(firstname);
    userFieldList.push(lastname);

    var userFields = new ApiContracts.TransactionRequestType.UserFields();
    userFields.setUserField(userFieldList);

    var transactionSetting1 = new ApiContracts.SettingType();
    transactionSetting1.setSettingName('duplicateWindow');
    transactionSetting1.setSettingValue('120');

    var transactionSetting2 = new ApiContracts.SettingType();
    transactionSetting2.setSettingName('recurringBilling');
    transactionSetting2.setSettingValue('false');

    var transactionSetting3 = new ApiContracts.SettingType();
    transactionSetting3.setSettingName('emailCustomer');
    transactionSetting3.setSettingValue('true');

    var transactionSetting4 = new ApiContracts.SettingType();
    transactionSetting4.setSettingName('headerEmailReceipt');
    transactionSetting3.setSettingValue('You are all set!');

    var transactionSetting5 = new ApiContracts.SettingType();
    transactionSetting5.setSettingName('footerEmailReceipt');
    transactionSetting5.setSettingValue('This is the footer');

    var getRequest = new ApiContracts.GetHostedPaymentPageRequest();
    getRequest.setMerchantAuthentication(merchantAuthenticationType);
    getRequest.setTransactionRequest(transactionRequestType);
    getRequest.setHostedPaymentSettings(alist);
    
    var ctrl = new ApiControllers.GetHostedPaymentPageController(getRequest.getJSON());

    const basicAuth = encode.encode("*****", 'base64');
    await axios({
      method: 'post',
      url: 'https://apitest.authorize.net/xml/v1/request.api',
      headers: {
        'Authorization': 'Basic '+basicAuth,
        'Content-Type': 'application/json'
        
      },
      data:JSON.stringify(ctrl._request)
        }).then(async (data : any)=>{
          if(data.data.token) {
            callback(null, data.data) ; 
          } else callErr(data);   
        });
      async function callErr(data: any){
        callback(null, res) ;
      }
    
}

IFrameCommunicator.html:

<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Iframe Communicator</title>
        <script type="text/javascript">
            //<![CDATA[
                function callParentFunction(str) {
                    if (str && str.length > 0 
                        && window.parent 
                        && window.parent.parent
                        && window.parent.parent.AuthorizeNetPopup 
                        && window.parent.parent.AuthorizeNetPopup.onReceiveCommunication)
                        {
// Errors indicate a mismatch in domain between the page containing the iframe and this page.
                            window.parent.parent.AuthorizeNetPopup.onReceiveCommunication(str);
                        }
                    }

                function receiveMessage(event) {
                    if (event && event.data) {
                        callParentFunction(event.data);
                        }
                    }

                if (window.addEventListener) {
                        console.log('addEventListener');
                        console.log(receiveMessage);
                    window.addEventListener("message", receiveMessage, false);
                    } else if (window.attachEvent) {
                        window.attachEvent("onmessage", receiveMessage);
                    }

                if (window.location.hash && window.location.hash.length > 1) {                  callParentFunction(window.location.hash.substring(1));
                    }
            //]]/>
        </script>
    </head>
    <body>
    </body>
</html>

Angular code for showing the iFrame:

   <iframe id="add_payment" class="embed-responsive-item panel" name="add_payment" width="100%" frameborder="0" scrolling="yes">
   </iframe>
 </div>
 <form id="send_token" action="" method="post" target="add_payment" >
   <input id="token" type="hidden" name="token" />
 </form>

I have been struggling a lot since many days now with a time crunch. Would be really helpful if someone provides me with a good insight here. Please let me know if additional info is required. Thank you in advance!!!

Here are the answer for all your question, I hope it works:

1)if you are using iFrame then iFrameCommunicator is mandatory

2)the success url can only be used when you set "showReceipt" as true, here you cannot navigate automatically to yoour success page, this is the link for "Continue" button which appears when "showReceipt" is allowed

3)If you want to trigger any function or want to navigate after the response then add the following code in your html file

  <script type="text/javascript">

    $(document).ready(function () {

        window.CommunicationHandler = {};

        function parseQueryString(str) {
            var vars = [];
            var arr = str.split('&');
            var pair;
            for (var i = 0; i < arr.length; i++) {
                pair = arr[i].split('=');
                vars[pair[0]] = unescape(pair[1]);
            }
            return vars;
        }

        window.CommunicationHandler.onReceiveCommunication = function (argument) {

            console.log('communication handler enter', argument);

            var params = parseQueryString(argument.qstr)

            switch (params['action']) {
                case "resizeWindow":

                    console.log('resize'); break;

                case "successfulSave":

                    console.log('save'); break;

                case "cancel":

                    console.log('cancel'); break;

                case "transactResponse":

                    sessionStorage.removeItem("HPTokenTime");

                    console.log('transaction complete');

                    var transResponse = JSON.parse(params['response']);

                    console.log('transaction complete1', transResponse);
                // window.location.href = '/checkout/complete';

            }
        }

        //send the token
        $('#send_hptoken').submit();


    });
</script>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM