2024-12-08 13:30:05 +00:00
|
|
|
const UserError = require('vn-loopback/util/user-error');
|
|
|
|
const axios = require('axios');
|
|
|
|
|
|
|
|
module.exports = Self => {
|
|
|
|
Self.remoteMethod('optimize', {
|
|
|
|
description: 'Return optimized coords',
|
|
|
|
accessType: 'READ',
|
|
|
|
accepts: [{
|
|
|
|
arg: 'addressIds',
|
|
|
|
type: 'array',
|
|
|
|
required: true
|
2024-12-11 08:03:14 +00:00
|
|
|
}, {
|
|
|
|
arg: 'firstAddressId',
|
|
|
|
type: 'number',
|
|
|
|
required: false
|
2024-12-16 06:15:47 +00:00
|
|
|
}, {
|
|
|
|
arg: 'lastAddressId',
|
|
|
|
type: 'number',
|
|
|
|
required: false
|
2024-12-08 13:30:05 +00:00
|
|
|
}],
|
|
|
|
returns: {
|
2024-12-11 08:03:14 +00:00
|
|
|
type: 'object',
|
2024-12-08 13:30:05 +00:00
|
|
|
root: true
|
|
|
|
},
|
|
|
|
http: {
|
|
|
|
path: `/optimize`,
|
|
|
|
verb: 'GET'
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2024-12-11 13:55:26 +00:00
|
|
|
Self.optimize = async(addressIds, firstAddressId, lastAddressId) => {
|
2024-12-08 13:30:05 +00:00
|
|
|
const models = Self.app.models;
|
|
|
|
try {
|
2024-12-09 09:01:59 +00:00
|
|
|
const osrmConfig = await models.OsrmConfig.findOne();
|
|
|
|
if (!osrmConfig) throw new UserError(`OSRM service is not configured`);
|
2024-12-08 13:30:05 +00:00
|
|
|
|
|
|
|
let coords = [];
|
2024-12-11 08:03:14 +00:00
|
|
|
if (firstAddressId) {
|
2024-12-12 07:23:02 +00:00
|
|
|
const address = await models.Address.findById(firstAddressId);
|
|
|
|
if (address.latitude && address.longitude) {
|
2024-12-11 08:03:14 +00:00
|
|
|
coords.push({
|
2024-12-12 07:23:02 +00:00
|
|
|
addressId: address.id,
|
|
|
|
latitude: address.latitude.toFixed(6),
|
|
|
|
longitude: address.longitude.toFixed(6)
|
2024-12-11 08:03:14 +00:00
|
|
|
});
|
|
|
|
}
|
2024-12-08 13:30:05 +00:00
|
|
|
}
|
2024-12-09 13:45:31 +00:00
|
|
|
|
|
|
|
for (const addressId of addressIds) {
|
|
|
|
const address = await models.Address.findById(addressId);
|
|
|
|
if (address.latitude && address.longitude) {
|
|
|
|
coords.push({
|
|
|
|
addressId,
|
|
|
|
latitude: address.latitude.toFixed(6),
|
|
|
|
longitude: address.longitude.toFixed(6)
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2024-12-11 08:03:14 +00:00
|
|
|
|
2024-12-11 13:55:26 +00:00
|
|
|
if (lastAddressId) {
|
|
|
|
const firstAddress = await models.Address.findById(lastAddressId);
|
|
|
|
if (firstAddress.latitude && firstAddress.longitude) {
|
|
|
|
coords.push({
|
|
|
|
addressId: firstAddress.id,
|
|
|
|
latitude: firstAddress.latitude.toFixed(6),
|
|
|
|
longitude: firstAddress.longitude.toFixed(6)
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-11 08:03:14 +00:00
|
|
|
if (!coords.length) throw new UserError('No address has coordinates');
|
|
|
|
|
2024-12-08 13:30:05 +00:00
|
|
|
const concatCoords = coords
|
|
|
|
.map(coord => `${coord.longitude},${coord.latitude}`)
|
|
|
|
.join(';');
|
2024-12-09 08:11:55 +00:00
|
|
|
const response = await axios.post(`
|
2024-12-11 13:55:26 +00:00
|
|
|
${osrmConfig.url}/trip/v1/driving/${concatCoords}?source=first&destination=last&roundtrip=true
|
2024-12-09 08:11:55 +00:00
|
|
|
`);
|
2024-12-09 09:01:59 +00:00
|
|
|
const tolerance = osrmConfig.tolerance;
|
2024-12-12 07:23:02 +00:00
|
|
|
for (const waypoint of response.data.waypoints) {
|
2024-12-08 13:30:05 +00:00
|
|
|
const longitude = waypoint.location[0];
|
|
|
|
const latitude = waypoint.location[1];
|
|
|
|
|
|
|
|
const matchedAddress = coords.find(coord =>
|
2024-12-09 09:21:23 +00:00
|
|
|
coord.position === undefined &&
|
2024-12-08 13:30:05 +00:00
|
|
|
Math.abs(coord.latitude - latitude) <= tolerance &&
|
|
|
|
Math.abs(coord.longitude - longitude) <= tolerance
|
|
|
|
);
|
2024-12-09 08:11:55 +00:00
|
|
|
if (matchedAddress)
|
|
|
|
matchedAddress.position = waypoint.waypoint_index;
|
2024-12-08 13:30:05 +00:00
|
|
|
}
|
|
|
|
coords.sort((a, b) => {
|
|
|
|
const posA = a.position !== undefined ? a.position : Infinity;
|
|
|
|
const posB = b.position !== undefined ? b.position : Infinity;
|
|
|
|
return posA - posB;
|
|
|
|
});
|
2024-12-09 09:21:23 +00:00
|
|
|
|
2024-12-12 13:35:58 +00:00
|
|
|
return coords;
|
2024-12-08 13:30:05 +00:00
|
|
|
} catch (err) {
|
|
|
|
switch (err.response?.data?.code) {
|
|
|
|
case 'NoTrips':
|
|
|
|
throw new UserError('No trips found because input coordinates are not connected');
|
|
|
|
case 'NotImplemented':
|
|
|
|
throw new UserError('This request is not supported');
|
2024-12-09 08:11:55 +00:00
|
|
|
case 'InvalidOptions':
|
|
|
|
throw new UserError('Invalid options or too many coordinates');
|
2024-12-08 13:30:05 +00:00
|
|
|
default:
|
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|