We are attempting to create a routing (TSP) algorithm that loops through a data structure that holds our vehicles and our trip information.
It all starts with an ASYNC function called acquireData that makes a $.getJSON call to our own API which returns a large object structure of all our vans and trips and all (too much) the information. This async function loops through the API object return and builds a brand new object with a LOT less data...
It returns the new object as a result.
At the bottom we call the async function and then we want to do all the TSP solving in the .then().
In the .then() we log "data" (which is the returned object from the async function acquireData()) and everything looks good. The image aboce is console.log(data.trucks). You can see all the avilableAt properties have a different date/time except for the ones who do not have a trip. This is the way its supposed to be. All is good up to this point, the data is exactly as we want it.
Now here is where we start to run into the issue...
When we attempt to loop through this data.trucks, the availableAt properties go haywire. $.each(data.trucks, function(d, j){ console.log(d, j.availableAt)})
Once we loop through this and display the availableAt properties, they all get the same date/time. Compare the two picture's and look at "Med 2" you'll see the difference.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<title>Document</title>
</head>
<body>
<script>
function createDateObject(dateString, militaryTime) {
if (typeof dateString === "boolean" || typeof militaryTime === "boolean" || militaryTime == ""){
return "No Date"
} else {
const year = parseInt(dateString.slice(0, 4));
const month = parseInt(dateString.slice(5, 7)) - 1;
const day = parseInt(dateString.slice(8, 10));
const hours = parseInt(militaryTime);
const date = new Date(year, month, day, hours);
return date;
}
}
function formatCityState(city, state) {
const formattedCity = city.replace(/ /g, '+');
const formattedState = state.toUpperCase();
return `${formattedCity},${formattedState}`;
}
function addSeconds(date, seconds) {
var newDate = new Date(date.getTime() + seconds * 1000);
return newDate;
}
function isBefore(date1, date2) {
return date1.getTime() < date2.getTime();
}
function addHalfHourEvery4Hours(seconds) {
var hours = seconds / 3600; // convert to hours
var timeSlots = Math.floor(hours / 4); // calculate number of 4-hour time slots
var extraHours = timeSlots * 0.5; // calculate extra half-hours
var newHours = hours + extraHours; // add extra half-hours to original hours
var newSeconds = newHours * 3600; // convert back to seconds
return newSeconds;
}
const callGoogle = async(origin, destination) => {
const params = encodeURIComponent('&origins=' + origin + '&destinations=' + destination);
const grabData = await $.getJSON('no-cors.php?url=https://maps.googleapis.com/maps/api/distancematrix/json?' + params + '&key=xxxxxxx')
return grabData;
}
async function acquireData() {
const data = await new Promise((resolve, reject) => {
$.getJSON('https://xxxxxxxxxx/xxxxx.php', function(data) {
const newData = {
// employees: {},
trucks: {},
trips: [],
trips_unscheduled: []
};
$.each(data.trucks, function(j, k) {
const truckObj = {
trips: [],
standing_location: k.name_value_list.location_c.value
};
if (j.includes('Med') || j == "") {
if (k.trips) {
for (let i = 0; i < k.trips.length; i++) {
const tripDate = new Date(k.trips[i].name_value_list.transport_date_2_c.value);
const now = new Date();
const timeDiff = tripDate - now;
const diffInHours = timeDiff / (1000 * 3600);
const tripObj = {
trip_id: k.trips[i].name_value_list.trip_id_c.value,
dropoff_location: formatCityState(k.trips[i].name_value_list.arrival_city_c.value, k.trips[i].name_value_list.arrival_state_c.value),
pickup_location: formatCityState(k.trips[i].name_value_list.departure_city_c.value, k.trips[i].name_value_list.deprature_state_c.value),
pickup_time: createDateObject(k.trips[i].name_value_list.transport_date_2_c.value, k.trips[i].name_value_list.pick_up_time_c.value, k.trips[i].name_value_list.trip_id_c.value)
};
if (diffInHours > 48 && tripObj.pickup_time != "No Date") {
newData.trips.push(tripObj);
} else if (diffInHours < -45000 || tripObj.pickup_time == "No Date") {
newData.trips_unscheduled.push(tripObj)
} else {
truckObj.trips.push(tripObj);
}
}
//Generate availableAt for trucks with trips.
if (truckObj.trips.length > 0) {
var Corndogs = callGoogle(truckObj.trips[truckObj.trips.length - 1].pickup_location, truckObj.trips[truckObj.trips.length - 1].dropoff_location)
.then((data) => {
truckObj.availableAt = addSeconds(truckObj.trips[truckObj.trips.length - 1].pickup_time ,addHalfHourEvery4Hours(data.rows[0].elements[0].duration.value))
newData.trucks[j] = truckObj;
})
}
}
//Generate availableAt for trucks with no trips.
let t = new Date()
let tomorrow = new Date(t.setHours(t.getHours() + 24))
truckObj.availableAt = tomorrow
newData.trucks[j] = truckObj;
}
});
resolve(newData);
});
});
return data;
}
//now that we have our data built out the way we want it, we can loop through it and find the best truck for each trip.
//We will start by looping through each trip.
//Loop through each truck
//if truck availableAt is before pickup time that means this truck is a possibility for current trip
//calculate if the truck can make it to the trip pickup location in time
//if it can lets save the travel time and distance in a variable as well as the good truck
//loop through trips again and if there is a trip that is closer and has less sitting time lets replace
//continue looping through all the trucks ; everytime we find a truck that can make the trip but is less travel time and distance , save these details to the variable.
//Loop through each truck
//Loop through each trip
//if truck availableAt is before the tripPickUpTime then lets dive further
//calculate travel time and distance from trucks drop off and avaialbleAt
//if truck can make it in time
//lets save that distance and time spent sitting into a variable and save that truck
//continue to compare it to other trucks nd if we find a lower distance/time
//once we have looked through all the trucks
acquireData().then((data) => {
console.log(data)
$.each(data.trucks, function(d, j){
console.log(d, j.availableAt)
})
// console.log(data.trucks)
}).catch((error) => {
console.error(error);
});
</script>
</body>
</html>
if (k.trips)tryif (k.trips.length > 0). Also be aware that the part you set the date is in that if, so it would set it for all. I'd suggest to put those 4 lines into the else part of that if-statement.