I’ve been developing an online payment solution in Joomla that accepts recurring gifts using Accept Hosted and Accept Customer. I’m using the Accept Hosted iFrame method described in the docs. My development has been on a staging site, and I’m trying to test it on a private page of our live website.
On the live site, when I fill out payment details and click the Submit/Pay button in the iFrame, the button grays out and the iFrame just hangs there. I’m expecting a transactResponse event from the communicator, but I don’t receive it. On the staging site, when I click the Submit/Pay button, I receive the transactResponse event as expected and the recurring subscription shows up in the Authorize.Net merchant backend.
In hostedPaymentReturnOptions, showReceipt is set to false and a URL is defined. A communicator URL is defined as well, and I make sure that it’s set to the appropriate site domain before testing the system. I’ve also checked the order of the elements in the JSON GetHostedPaymentPageRequest object and as far as I can tell they match the Accept Hosted docs.
I've found several similar issues on the forums (like this one), but I'm still stuck with this.
My communicator:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <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.AuthorizeNetIFrame && window.parent.parent.AuthorizeNetIFrame.onReceiveCommunication) { // Errors indicate a mismatch in domain between the page containing the iframe and this page. window.parent.parent.AuthorizeNetIFrame.onReceiveCommunication(str); } } function receiveMessage(event) { if (event && event.data) { callParentFunction(event.data); } } if (window.addEventListener) { 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>
Relevant code from get hosted payment page request in PHP:
public static function fetchHostedPaymentTokenAjax() { /* Create a merchantAuthenticationType object with authentication details retrieved from the constants file */ $merchantAuthentication = new AnetAPI\MerchantAuthenticationType(); $merchantAuthentication->setName(MERCHANT_AUTH_NAME); $merchantAuthentication->setTransactionKey(MERCHANT_AUTH_TRANSACTION_KEY); // Set the transaction's refId $refId = 'ref' . strval(time()); //create a transaction $transactionRequestType = new AnetAPI\TransactionRequestType(); $transactionRequestType->setTransactionType("authCaptureTransaction"); $transactionRequestType->setAmount($amount); // Set Order options and add to transaction $order = new AnetApi\OrderType(); $order->setDescription($orderDescription); $order->setInvoiceNumber(strval(time())); $transactionRequestType->setOrder($order); // Set Hosted Form options $setting1 = new AnetAPI\SettingType(); $setting1->setSettingName("hostedPaymentReturnOptions"); $setting1->setSettingValue("{\"showReceipt\": false, \"url\": \"<<<staging site url here>>>\"}"); $setting2 = new AnetAPI\SettingType(); $setting2->setSettingName("hostedPaymentButtonOptions"); $setting2->setSettingValue("{\"text\": \"Submit\"}"); $setting3 = new AnetAPI\SettingType(); $setting3->setSettingName("hostedPaymentStyleOptions"); $setting3->setSettingValue("{\"bgColor\": \"#E86C1F\"}"); $setting4 = new AnetAPI\SettingType(); $setting4->setSettingName("hostedPaymentPaymentOptions"); $setting4->setSettingValue("{\"cardCodeRequired\": true, \"showBankAccount\": true}"); $setting5 = new AnetAPI\SettingType(); $setting5->setSettingName("hostedPaymentSecurityOptions"); $setting5->setSettingValue("{\"captcha\": false}"); $setting6 = new AnetAPI\SettingType(); $setting6->setSettingName("hostedPaymentShippingAddressOptions"); $setting6->setSettingValue("{\"show\": false, \"required\": false}"); $setting7 = new AnetAPI\SettingType(); $setting7->setSettingName("hostedPaymentBillingAddressOptions"); $setting7->setSettingValue("{\"show\": true, \"required\": true}"); $setting8 = new AnetAPI\SettingType(); $setting8->setSettingName("hostedPaymentCustomerOptions"); $setting8->setSettingValue("{\"showEmail\": true, \"requiredEmail\": true}"); $setting9 = new AnetAPI\SettingType(); $setting9->setSettingName("hostedPaymentOrderOptions"); $setting9->setSettingValue("{\"show\": false}"); $setting10 = new AnetAPI\SettingType(); $setting10->setSettingName("hostedPaymentIFrameCommunicatorUrl"); $setting10->setSettingValue("{\"url\": \"<<My communicator URL here>>>\"}"); // Build transaction request $request = new AnetAPI\GetHostedPaymentPageRequest(); $request->setMerchantAuthentication($merchantAuthentication); $request->setRefId($refId); $request->setTransactionRequest($transactionRequestType); $request->addToHostedPaymentSettings($setting1); $request->addToHostedPaymentSettings($setting2); $request->addToHostedPaymentSettings($setting3); $request->addToHostedPaymentSettings($setting4); $request->addToHostedPaymentSettings($setting5); $request->addToHostedPaymentSettings($setting6); $request->addToHostedPaymentSettings($setting7); $request->addToHostedPaymentSettings($setting8); $request->addToHostedPaymentSettings($setting9); $request->addToHostedPaymentSettings($setting10); //execute request $controller = new AnetController\GetHostedPaymentPageController($request); $response = $controller->executeWithApiResponse(\net\authorize\api\constants\ANetEnvironment::SANDBOX); if (($response != null) && ($response->getMessages()->getResultCode() == "Ok")) { return $response->getToken(); } else { return "ERROR : Failed to get hosted payment page token." . "RESPONSE : " . $errorMessages[0]->getCode() . " " .$errorMessages[0]->getText(); } } }
Function in JavaScript to handle messages from the communicator:
(function () { if (!window.AuthorizeNetIFrame) window.AuthorizeNetIFrame = {}; AuthorizeNetIFrame.onReceiveCommunication = function (querystr) { var params = parseQueryString(querystr ); var ifrm = document.getElementById("add_payment"); switch (params["action"]) { case "successfulSave": break; case "cancel": ifrm.style.display = 'none'; location.reload(); break; case "resizeWindow": var w = parseInt(params["width"] ); var h = parseInt(params["height"] ); ifrm.style.width = w.toString() + "px"; ifrm.style.height = h.toString() + "px"; break; case "transactResponse": finalizeTransaction(params["response"]); } }; function parseQueryString(str) { var vars = []; var arr = str.split( '&'); var pair; for (var i = 0; i < arr.length; i++) { pair = arr[i].split( '='); vars.push(pair[0]); vars[pair[0]] = unescape(pair[1]); } return vars; } }());
JavaScript code to show the iFrame:
function displayPaymentForm(donationFormData) { request = { 'option': 'com_ajax', 'module': 'donationformtest', 'data': donationFormData, 'format': 'raw', 'method': 'fetchHostedPaymentToken' }; jQuery.ajax({ type: 'POST', data: request, success: function(response){ displayPaymentInfoIframe(response); } else { console.log(response); } }, error: function (response) { console.log("ERROR: ", response); } }); } function displayPaymentInfoIframe(token){ window.addEventListener('resize', checkIframeHeight); document.getElementById('tokenInput').value = token; document.getElementById("iframe_container").style.display = "block"; document.getElementById("add_payment").style.display = "block"; document.getElementById("send_token").action = "https://test.authorize.net/payment/payment"; document.getElementById("send_token").target = "add_payment"; document.getElementById("send_token").submit(); }
Relevant DOM elements in the HTML:
<form id="send_token" action="" method="post" target="" > <input type="hidden" name="token" value="" id="tokenInput"/> </form> <div id="iframe_container" > <iframe id="add_payment" name="add_payment" width="100%" height="100%" frameborder="0" scrolling="no" hidden="true" sandbox="allow-scripts allow-same-origin" ></iframe> </div>
05-12-2021 02:39 PM