Inherited ECommerce platform with custom built Ajax JS system is failing to respond. Link: http://www.bebeautifulsalonandspa.com/store/checkout/
Go into the store and add a product, then try to enter your postal code and lookup rates. Postal code lookup is not responding. Looking for assistance with the debug, I've hit a wall. I know the response from Canada Post is coming back okay into PHP land. Sample dump of Array in PHP land before returning:
Array
(
[0] => Array
(
[type] => Expedited Parcel
[price] => 10.95
[estimatedDeliveryDate] => 2018-06-19
[estimatedDeliveryDays] => 1
)
[1] => Array
(
[type] => Priority
[price] => 22.26
[estimatedDeliveryDate] => 2018-06-19
[estimatedDeliveryDays] => 1
)
[2] => Array
(
[type] => Regular Parcel
[price] => 10.95
[estimatedDeliveryDate] => 2018-06-20
[estimatedDeliveryDays] => 2
)
[3] => Array
(
[type] => Xpresspost
[price] => 11.73
[estimatedDeliveryDate] => 2018-06-19
[estimatedDeliveryDays] => 1
)
)
This same system seems to be working okay on another website. I've tried copy pasting the other site's JS, PHP, HTML into this site and it is still failing to respond.
The JS code that is running the Ajax request is many files and I have no idea what part would need to be pasted here, honestly.
If you were me, where would you look first?
EDITS: Some of the code here...it's a completely custom "system" across like 10 files however. This is the piece that is the core system that runs generic Ajax requests:
(function(EVO){
EVO.LoadSingletonFactory('Ajax', Ajax);
/* Currently this is an ugly piece of code and required refactoring and cleanup */
function Ajax(){
var interrupt = false;
var processing = false;
var currentRequest;
var ajaxQ = [];
var settings = {
'requestHandler':'',
'freezeDelay':2500,
'timeout':10000,
'method':'post',
'flatten':false
};
var $return = {
'Settings':SettingsAPI,
'Send':Send
};
return $return;
/* Public Methods */
function SettingsAPI(){
var $return = {
'RequestHandler':RequestHandler,
'FreezeDelay':FreezeDelay,
'Method':Method,
'Timeout':Timeout
};
return $return;
function RequestHandler(_urlOrFunction){
if(_urlOrFunction){
settings.requestHandler = _urlOrFunction;
}
return settings.requestHandler;
};
function Timeout(_ms){
if(EVO.Is(_ms) == 'number'){
settings.timeout = _ms;
}
return settings.timeout;
};
function FreezeDelay(_ms){
if(EVO.Is(_ms) == 'number'){
settings.freezeDelay = _ms;
}
return settings.freezeDelay;
};
function Method(_method){
if(EVO.Is(_method) == 'string'){
switch(_method.toLowerCase()){
case 'get': case 'post': case 'put':
settings.method = _method.toLowerCase();
break;
}
}
return settings.method;
};
function Flatten(_bool){
if(_bool === true || _bool === false){
settings.flatten = _bool;
}
return settings.flatten;
};
function Format(_json){
};
};
function Send(_json, _interrupt){
if(_interrupt === true){
interrupt = true;
if(currentRequest){
currentRequest.cancel();
}
$return.Once('clearedQ', function(){
Send(_json);
});
startQ();
}
else{
addRequestToQ(_json, copySettings(settings));
if(!processing && ajaxQ.length){
startQ();
}
}
};
function Cancel(){
if(processing && currentRequest){
currentRequest.cancel();
ajaxQ = [];
processing = false;
}
};
/* Private Methods */
function addRequestToQ(_json, _settings){
var add = true;
for(var i=0,length=ajaxQ.length;i<length;i++){
if(ajaxQ.json == _json && ajaxQ.settings == _settings){
add = false;
break;
}
}
if(add){
ajaxQ[ajaxQ.length] = {'json':_json, 'settings':_settings};
}
};
function startQ(_fireQEvent){
if(ajaxQ.shift && ajaxQ.length > 0 && !processing){
var obj = ajaxQ.shift();
if(interrupt){
startQ();
}
else{
currentRequest = startRequest(obj.json, obj.settings);
}
}
else{
interrupt = false;
if(_fireQEvent !== false){
$return.Emit('clearedQ');
}
}
};
function startRequest(_data, _settings){
var requestData,response,XHR;
var timer = {};
var $api = {
'cancel':cancel
};
processing = true;
if(EVO.Is(_settings.requestHandler) == 'string'){
//XHR Request
var XHR = initXHR();
if(XHR){
requestData = setupMethod(XHR,_settings.method,_settings.requestHandler,_data,_settings.flatten);
if(!requestData){
requestData = '';
}
XHR.onreadystatechange = function(){
if(EVO.Is(XHR) != 'undefined' && XHR.readyState == 4){
//In theory our request has responded, but as we've found this doesn't work entirely how expected
try{
response = XHR.responseText;
try{
response = JSON.parse(response);
}
catch(e){/*Parsing JSON would have failed. Somehow.*/}
completeRequest(response);
}
catch(e){throw e;}
}
}
startRequestTimer();
XHR.send(requestData);
$return.Emit('request', $api);
}
}
else{
//We're in function land
startRequestTimer();
response = _settings.requestHandler.call(undefined,_data);
if(EVO.Is(response) == 'object' && response.On && response.HandleRequest){
response.On('ready', function(responseData){
completeRequest(responseData);
});
response.HandleRequest(_data);
}
else{
completeRequest(response);
}
}
return $api;
/* request methods */
function initXHR(){
try { return new XMLHttpRequest(); } catch(e) {}
try { return new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) {}
};
function setupMethod(_XHR, _method, _url, _data, _flatten){
var $return,count,key,val,uri;
switch(_method){
case 'post':
_XHR.open('post', _url, true);
_XHR.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
if(_flatten && EVO.Is(_data) == 'object'){
count = 0;
$return = '';
for(var prop in _data){
key = prop;
val = (EVO.Is(_data[prop]) == 'object' ? JSON.stringify(_data[prop]) : _data[prop]);
$return = $return+(!count ? key+'='+val : '&'+key+'='+val);
count++;
}
}
else if(!_flatten && EVO.Is(_data) == 'object'){
$return = 'data='+(EVO.Is(_data) == 'object' ? JSON.stringify(_data) : _data);
}
else{
$return = 'data='+_data;
}
break;
case 'put':
_XHR.open('put', _url, true);
(EVO.Is(_data) == 'object' ? _XHR.setRequestHeader("Content-type", "application/json") : _XHR.setRequestHeader("Content-type", "text/plain"));
$return = _data;
break;
case 'get':
if(EVO.Is(_data) == 'object'){
count = 0;
uri = '';
for(var prop in _data){
if(_data.hasOwnProperty(prop)){
key = encodeURIComponent(prop);
if(EVO.Is(_data[prop] == 'object')){
val = encodeURIComponent(JSON.stringify(_data[prop]).replace(/'|"/g,''));
//val = _data[prop];
}
else if(EVO.Is(_data[prop] == 'string')){
val = encodeURIComponent(_data[prop].replace(/'|"/g,''));
//val = _data[prop];
}
else{
val = '';
}
//val = (EVO.Is(_data[prop]) == 'object' ? encodeURIComponent(JSON.stringify(_data[prop])) : (EVO.Is(_data[prop]) == 'string' ? encodeURIComponent(_data[prop]) : ''));
uri = uri+(!count ? "?"+key+'='+val : '&'+key+'='+val);
count++;
}
}
}
_XHR.open('get', _url+uri, true);
break;
}
return $return;
};
function startRequestTimer(){
var D = new Date();
timer.startTime = D.getTime();
if(settings.freezeDelay){
timer.freezeTimer = setTimeout(function(){ $return.Emit('freeze', true); }, settings.freezeDelay);
}
if(settings.timeout){
timer.timeoutTimer = setTimeout(function(){ $return.Emit('timeout', _data); cancel(); }, settings.timeout)
}
};
function cancel(){
//Abort
if(EVO.Is(XHR) == 'object' && XHR.abort){
XHR.aborted = true;
XHR.abort();
}
else if(EVO.Is(response) == 'object' && response.Emit){
response.Emit('abort', _data);
}
//Cancel our freeze
requestData = undefined;
response = undefined;
if(timer.freezeTimer){
clearTimeout(timer.freezeTimer);
}
$return.Emit('freeze', false);
if(timer.timeoutTimer){
clearTimeout(timer.timeoutTimer);
}
timer = {};
currentRequest = undefined;
XHR = undefined;
processing = false;
};
function completeRequest(_response){
//Cancel our freeze if it exists
$return.Emit('freeze', false);
//First we cancel our timers
if(timer.freezeTimer){
clearTimeout(timer.freezeTimer);
}
if(timer.timeoutTimer){
clearTimeout(timer.timeoutTimer);
}
timer = {};
//Now we kill our currentXHR
currentRequest = undefined;
//We Emit our response
if(XHR){
if(processing && XHR.status !== 0){
$return.Emit('response', _response);
}
}
else{
$return.Emit('response', _response);
}
//We flag our processing to finished
XHR = undefined;
processing = false;
//We let our Q take over
startQ(false);
};
};
function copySettings(_obj){
var $return = {};
if(EVO.Is(_obj) == 'object'){
for(var prop in _obj){
if(_obj.hasOwnProperty(prop)){
$return[prop] = _obj[prop];
}
}
}
return $return;
};
};
})(EVO);
This is the Checkout JS calling the Ajax system mentioned above.
EVO.DomJack().Ready(function(){
var shippingSet = false;
var ECQuantUpdate = EVO.Ajax('ECQuantity');
ECQuantUpdate.Settings().RequestHandler('/_app/');
var ECRedrawItems = EVO.Ajax('ECRedrawItems');
ECRedrawItems.Settings().RequestHandler('/_app/');
var ECRedrawSubtotal = EVO.Ajax('ECRedrawSubtotal');
ECRedrawSubtotal.Settings().RequestHandler('/_app/');
var ECRedrawCartTotal = EVO.Ajax('ECRedrawCartTotal');
ECRedrawCartTotal.Settings().RequestHandler('/_app/');
function redraw(){
ECRedrawItems.Send({
'appAddress': 'ArraySoft/ECommerce',
'name': 'GetMapJson',
'mapVars': {'map': 'Checkout'},
'mapName': 'cartItemMap',
'autoMerge': true
});
ECRedrawSubtotal.Send({
'appAddress': 'ArraySoft/ECommerce',
'name': 'GetMapJson',
'mapVars': {'map': 'Checkout'},
'mapName': 'shippingMap',
'autoMerge': true
});
ECRedrawCartTotal.Send({
'appAddress': 'ArraySoft/ECommerce',
'name': 'GetMapJson',
'mapVars': {'map': 'Checkout'},
'mapName': 'cartItemMap',
'autoMerge': false
});
};
ECRedrawItems.On('response',function(data){
EVO.Select('#itemContainer')[0].SetInner(data.mergedMap);
bindButtons();
rebindQuantity();
});
ECRedrawSubtotal.On('response',function(data){
EVO.Select('#summaryContainer')[0].SetInner(data.mergedMap);
EVO.Select('#subtotal .total')[0].SetInner("$"+data['data']['blocks'][1]['data']['subtotal']['1']);
});
ECRedrawCartTotal.On('response',function(_data){
});
function bindButtons(){
var EDAJ = EVO.Ajax('EDAJ');
EDAJ.Settings().RequestHandler('/_app/');
EVO.Select('.itemList .delete_button').Each(function(){
var _djThis = this;
_djThis.On('click',function(){
var itemId = _djThis.GetAttribute('data-itemId');
if(itemId){
EDAJ.Send({
'appAddress':'ArraySoft/ECommerce',
'name':'publicUpdateItemInCartById',
'data': {
'itemId': itemId,
'qty': 0
}
})
EDAJ.Once('response',function(_data){
redraw();
});
}
});
});
EVO.Select('.itemList .subtract').Each(function(){
var _djThis = this;
_djThis.On('click',function(){
var itemId = _djThis.GetAttribute('data-itemId');
var input = EVO.Select('input',_djThis.GetParent().GetNode())[0];
var val = parseInt(input.Value());
input.Value((val - 1 < 0 ? 0 : val - 1));
input.Emit('blur');
});
});
EVO.Select('.itemList .add').Each(function(){
var _djThis = this;
_djThis.On('click',function(){
var itemId = _djThis.GetAttribute('data-itemId');
var input = EVO.Select('input',_djThis.GetParent().GetNode())[0];
var val = parseInt(input.Value());
input.Value(val + 1);
input.Emit('blur');
});
});
}
bindButtons();
function rebindQuantity(){
EVO.Select("input.number-item").Each(function(){
var DJ = this;
var SODJ = EVO.Select('#shippingOptions')[0];
DJ.On('blur',function(){
//Update quantity, and re-call shippingOptions. Maybe store what the type was and attempt to restore it.
var newQuantity = DJ.GetNode().value; //I don't know if DomJack is okay with Value() so let's be safe :)
var itemID = DJ.GetAttribute('data-item-id');
ECQuantUpdate.Send({
'appAddress':'ArraySoft/ECommerce',
'name': 'publicUpdateItemInCartById',
'data': {
'qty': newQuantity,
'itemId': itemID
}
},true);
ECQuantUpdate.Once('response',function(){
redraw();
});
});
});
}
rebindQuantity();
EVO.Select("#shipping form[name=shipping]")[0].On('submit',function(){
waitingSpinner(true); //I triggered the spinner!
var ECShipAJ = EVO.Ajax('ECShipAJ');
ECShipAJ.Settings().RequestHandler('/_app/');
var ECShipSelect = EVO.Ajax('ECShipSelect');
ECShipSelect.Settings().RequestHandler('/_app/');
var formData = this.Gather();
//Lets validate the postal code and show a message.
if(!(/[A-z][0-9][A-z][\s\-]*?[0-9][A-z][0-9]/.test(formData.postalCode))){
promptInvalidPostalCode();
return false;
}
ECShipAJ.Once('response',function(data){
waitingSpinner(false); //I turned the spinner off!
if(data.fail){
alert('We were unable to get shipping prices for your order. If you are ordering in bulk - 4 or more units - please contact ');
promptInvalidPostalCode();
}
else{
//console.log('Result received');
var SODJ = EVO.Select('#shippingOptions')[0];
//console.log(SODJ);
var shippingOptions = generateShippingOptionsSelect(data);
shippingOptions.On('change',function(){
if(this.Value()){
ECShipSelect.Send({
'appAddress':'ArraySoft/ECommerce',
'name':'publicSetShippingOption',
'data':{
'postalCode': formData.postalCode,
'price': shippingOptions.Value(),
'type': EVO.DomJack(shippingOptions.GetSelected()).GetAttribute('data-shipping-type')
}
});
ECShipSelect.Once('response',function(data){
updateTotals(data.totals);
});
shippingSet = true;
}
else{
shippingSet = false;
}
});
SODJ.Dump();
var label = EVO.DomJack('span');
label.SetInner('Delivery Method: ');
label;
SODJ.Append(label);
SODJ.Append(shippingOptions);
$('#shippingOptions span').addClass('summary_label');
$('#shippingOptions option').addClass('total');
}
});
ECShipAJ.Send({
'appAddress':'ArraySoft/ECommerce',
'name':'publicGetShippingRates',
'data':{
'postalCode': formData.postalCode
}
});
return false;
});
function promptInvalidPostalCode(){
triggerMessage("Postal Code is invalid",3000);
waitingSpinner(0);
}
function generateShippingOptionsSelect(shippingData){
//console.log('shipping options');
//console.log(shippingData);
var ret = EVO.DomJack('select');
ret.Append(EVO.DomJack('option').SetInner('Choose Shipping Option'));
// console.log('domjack error');
if(EVO.Is(shippingData) == "array"){
//console.log('is array');
for(var i = 0; i < shippingData.length; i++){
var current = shippingData[i];
ret.Append(handleOption(current));
}
}else { /*console.log('not an array'); */}
function handleOption(optionData){
// console.log('handling result option');
// console.log(optionData);
var option = EVO.DomJack('option');
option.SetAttribute('value',optionData.price);
option.SetAttribute('data-shipping-type',optionData.type);
option.SetInner(optionData.type + ' - ' +
"Est Delivery: "+optionData.estimatedDeliveryDays+" day(s)");
return option;
}
//console.log(ret);
return ret;
}
function updateTotals(totalsData){
EVO.Select('#total .total')[0].SetInner("$"+totalsData.grandTotal);
EVO.Select('#taxes .total')[0].SetInner("$"+totalsData.taxTotal);
EVO.Select('#shipping .total')[0].SetInner("$"+totalsData.shTotal);
EVO.Select('#subtotal .total')[0].SetInner("$"+totalsData.subTotal);
}
function addSubtract(condition){
var inputVal = parseInt($('#input_'+inputID+' .number-item').attr('value'));
if(condition == 1){
inputVal = inputVal+1;
}else{
inputVal = inputVal-1;
}
$('#input_'+inputID+' .number-item').attr('value',inputVal);
redraw();
rebindQuantity();
}
function waitingSpinner(state){
if(state){
//console.log("I'm spinning!");
$('#spinner').show();
}
else{
//console.log("I'm not spinning :(");
$('#spinner').hide();
}
}
var reviewButton = EVO.Select('#review_button')[0];
reviewButton.GetParent().On('click',function(){
if(!shippingSet){
//Do something pretty here that says shipping must be valid before checking out
triggerMessage("Shipping must be valid before checking out",1000);
}
return shippingSet;
});
/*
reviewButton.Submit(function(){
alert('test');
return false;
});
*/
});
function triggerMessage(msg,time){
time = time || 1000;
$('#shippingMessageWrap').html(msg);
$('#shippingMessageContainer').fadeIn().delay(time).fadeOut();
}