Merge pull request 'feat: refs #7882 Added osrmservice' (!3281) from 7882-locationiq into dev
gitea/salix/pipeline/head There was a failure building this commit
Details
gitea/salix/pipeline/head There was a failure building this commit
Details
Reviewed-on: #3281 Reviewed-by: Alex Moreno <alexm@verdnatura.es> Reviewed-by: Javi Gallego <jgallego@verdnatura.es>
This commit is contained in:
commit
eadffe1ed9
|
@ -0,0 +1,112 @@
|
||||||
|
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
|
||||||
|
}, {
|
||||||
|
arg: 'firstAddressId',
|
||||||
|
type: 'number',
|
||||||
|
required: false
|
||||||
|
}, {
|
||||||
|
arg: 'lastAddressId',
|
||||||
|
type: 'number',
|
||||||
|
required: false
|
||||||
|
}],
|
||||||
|
returns: {
|
||||||
|
type: 'object',
|
||||||
|
root: true
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
path: `/optimize`,
|
||||||
|
verb: 'GET'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.optimize = async(addressIds, firstAddressId, lastAddressId) => {
|
||||||
|
const models = Self.app.models;
|
||||||
|
try {
|
||||||
|
const osrmConfig = await models.OsrmConfig.findOne();
|
||||||
|
if (!osrmConfig) throw new UserError(`OSRM service is not configured`);
|
||||||
|
|
||||||
|
let coords = [];
|
||||||
|
if (firstAddressId) {
|
||||||
|
const address = await models.Address.findById(firstAddressId);
|
||||||
|
if (address.latitude && address.longitude) {
|
||||||
|
coords.push({
|
||||||
|
addressId: address.id,
|
||||||
|
latitude: address.latitude.toFixed(6),
|
||||||
|
longitude: address.longitude.toFixed(6)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!coords.length) throw new UserError('No address has coordinates');
|
||||||
|
|
||||||
|
const concatCoords = coords
|
||||||
|
.map(coord => `${coord.longitude},${coord.latitude}`)
|
||||||
|
.join(';');
|
||||||
|
const response = await axios.post(`
|
||||||
|
${osrmConfig.url}/trip/v1/driving/${concatCoords}?source=first&destination=last&roundtrip=true
|
||||||
|
`);
|
||||||
|
const tolerance = osrmConfig.tolerance;
|
||||||
|
for (const waypoint of response.data.waypoints) {
|
||||||
|
const longitude = waypoint.location[0];
|
||||||
|
const latitude = waypoint.location[1];
|
||||||
|
|
||||||
|
const matchedAddress = coords.find(coord =>
|
||||||
|
coord.position === undefined &&
|
||||||
|
Math.abs(coord.latitude - latitude) <= tolerance &&
|
||||||
|
Math.abs(coord.longitude - longitude) <= tolerance
|
||||||
|
);
|
||||||
|
if (matchedAddress)
|
||||||
|
matchedAddress.position = waypoint.waypoint_index;
|
||||||
|
}
|
||||||
|
coords.sort((a, b) => {
|
||||||
|
const posA = a.position !== undefined ? a.position : Infinity;
|
||||||
|
const posB = b.position !== undefined ? b.position : Infinity;
|
||||||
|
return posA - posB;
|
||||||
|
});
|
||||||
|
|
||||||
|
return coords;
|
||||||
|
} 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');
|
||||||
|
case 'InvalidOptions':
|
||||||
|
throw new UserError('Invalid options or too many coordinates');
|
||||||
|
default:
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,33 @@
|
||||||
|
const models = require('vn-loopback/server/server').models;
|
||||||
|
|
||||||
|
describe('osrmConfig optimize()', function() {
|
||||||
|
it('should send coords, receive OSRM response, and return a correctly ordered result', async function() {
|
||||||
|
const result = await models.OsrmConfig.optimize([4, 3], 1, 2);
|
||||||
|
|
||||||
|
// Verifications
|
||||||
|
expect(Array.isArray(result)).toBe(true);
|
||||||
|
expect(result.length).toBe(4);
|
||||||
|
|
||||||
|
// Check the order
|
||||||
|
expect(result[0].addressId).toBe(1);
|
||||||
|
expect(result[1].addressId).toBe(4);
|
||||||
|
expect(result[2].addressId).toBe(3);
|
||||||
|
expect(result[3].addressId).toBe(2);
|
||||||
|
|
||||||
|
// Check the coordinates format
|
||||||
|
expect(result[0].latitude).toBe('10.111111');
|
||||||
|
expect(result[0].longitude).toBe('-74.111111');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error if no addresses are provided', async function() {
|
||||||
|
let error;
|
||||||
|
try {
|
||||||
|
await models.OsrmConfig.optimize([], null);
|
||||||
|
} catch (e) {
|
||||||
|
error = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error).toBeDefined();
|
||||||
|
expect(error.message).toBe('No address has coordinates');
|
||||||
|
});
|
||||||
|
});
|
|
@ -88,6 +88,9 @@
|
||||||
"Language": {
|
"Language": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
"OsrmConfig": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
"Machine": {
|
"Machine": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
module.exports = Self => {
|
||||||
|
require('../methods/osrm-config/optimize')(Self);
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
"name": "OsrmConfig",
|
||||||
|
"base": "VnModel",
|
||||||
|
"options": {
|
||||||
|
"mysql": {
|
||||||
|
"table": "osrmConfig"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "number",
|
||||||
|
"id": true,
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"type": "string",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"tolerance": {
|
||||||
|
"type": "number",
|
||||||
|
"required": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -428,10 +428,10 @@ INSERT INTO `vn`.`clientConfig`(`id`, `riskTolerance`, `maxCreditRows`, `maxPric
|
||||||
|
|
||||||
INSERT INTO `vn`.`address`(`id`, `nickname`, `street`, `city`, `postalCode`, `provinceFk`, `phone`, `mobile`, `isActive`, `clientFk`, `agencyModeFk`, `longitude`, `latitude`, `isEqualizated`, `isDefaultAddress`)
|
INSERT INTO `vn`.`address`(`id`, `nickname`, `street`, `city`, `postalCode`, `provinceFk`, `phone`, `mobile`, `isActive`, `clientFk`, `agencyModeFk`, `longitude`, `latitude`, `isEqualizated`, `isDefaultAddress`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, 'Bruce Wayne', '1007 Mountain Drive, Gotham', 'Gotham', 46460, 1, 1111111111, 222222222, 1, 1101, 2, NULL, NULL, 0, 1),
|
(1, 'Bruce Wayne', '1007 Mountain Drive, Gotham', 'Gotham', 46460, 1, 1111111111, 222222222, 1, 1101, 2, -74.1111111, 10.1111111, 0, 1),
|
||||||
(2, 'Petter Parker', '20 Ingram Street', 'Gotham', 46460, 1, 1111111111, 222222222, 1, 1102, 2, NULL, NULL, 0, 1),
|
(2, 'Petter Parker', '20 Ingram Street', 'Gotham', 46460, 1, 1111111111, 222222222, 1, 1102, 2, -74.2222222, 10.2222222, 0, 1),
|
||||||
(3, 'Clark Kent', '344 Clinton Street', 'Gotham', 46460, 1, 1111111111, 222222222, 1, 1103, 2, NULL, NULL, 0, 1),
|
(3, 'Clark Kent', '344 Clinton Street', 'Gotham', 46460, 1, 1111111111, 222222222, 1, 1103, 2, -74.3333333, 10.3333333, 0, 1),
|
||||||
(4, 'Tony Stark', '10880 Malibu Point', 'Gotham', 46460, 1, 1111111111, 222222222, 1 , 1104, 2, NULL, NULL, 0, 1),
|
(4, 'Tony Stark', '10880 Malibu Point', 'Gotham', 46460, 1, 1111111111, 222222222, 1 , 1104, 2, -74.4444444, 10.4444444, 0, 1),
|
||||||
(5, 'Max Eisenhardt', 'Unknown Whereabouts', 'Gotham', 46460, 1, 1111111111, 222222222, 1, 1105, 2, NULL, NULL, 0, 1),
|
(5, 'Max Eisenhardt', 'Unknown Whereabouts', 'Gotham', 46460, 1, 1111111111, 222222222, 1, 1105, 2, NULL, NULL, 0, 1),
|
||||||
(6, 'DavidCharlesHaller', 'Evil hideout', 'Gotham', 46460, 1, 1111111111, 222222222, 1, 1106, 2, NULL, NULL, 0, 1),
|
(6, 'DavidCharlesHaller', 'Evil hideout', 'Gotham', 46460, 1, 1111111111, 222222222, 1, 1106, 2, NULL, NULL, 0, 1),
|
||||||
(7, 'Hank Pym', 'Anthill', 'Gotham', 46460, 1, 1111111111, 222222222, 1, 1107, 2, NULL, NULL, 0, 1),
|
(7, 'Hank Pym', 'Anthill', 'Gotham', 46460, 1, 1111111111, 222222222, 1, 1107, 2, NULL, NULL, 0, 1),
|
||||||
|
@ -462,7 +462,7 @@ INSERT INTO `vn`.`address`(`id`, `nickname`, `street`, `city`, `postalCode`, `pr
|
||||||
(120, 'Somewhere in Montortal', 'address 20', 'Gotham', 46460, 1, 1111111111, 222222222, 1, 1109, 2, NULL, NULL, 0, 0),
|
(120, 'Somewhere in Montortal', 'address 20', 'Gotham', 46460, 1, 1111111111, 222222222, 1, 1109, 2, NULL, NULL, 0, 0),
|
||||||
(121, 'the bat cave', 'address 21', 'Gotham', 46460, 1, 1111111111, 222222222, 1, 1101, 2, NULL, NULL, 0, 0),
|
(121, 'the bat cave', 'address 21', 'Gotham', 46460, 1, 1111111111, 222222222, 1, 1101, 2, NULL, NULL, 0, 0),
|
||||||
(122, 'NY roofs', 'address 22', 'Gotham', 46460, 1, 1111111111, 222222222, 1, 1102, 2, NULL, NULL, 0, 0),
|
(122, 'NY roofs', 'address 22', 'Gotham', 46460, 1, 1111111111, 222222222, 1, 1102, 2, NULL, NULL, 0, 0),
|
||||||
(123, 'The phone box', 'address 23', 'Gotham', 46460, 1, 1111111111, 222222222, 1, 1103, 2, NULL, NULL, 0, 0),
|
(123, 'The phone box', 'address 23', 'Gotham', 46460, 1, 1111111111, 222222222, 1, 1103, 2, -74.555555, 10.555555, 0, 0),
|
||||||
(124, 'Stark tower Gotham', 'address 24', 'Gotham', 46460, 1, 1111111111, 222222222, 1, 1104, 2, NULL, NULL, 0, 0),
|
(124, 'Stark tower Gotham', 'address 24', 'Gotham', 46460, 1, 1111111111, 222222222, 1, 1104, 2, NULL, NULL, 0, 0),
|
||||||
(125, 'The plastic cell', 'address 25', 'Gotham', 46460, 1, 1111111111, 222222222, 1, 1105, 2, NULL, NULL, 0, 0),
|
(125, 'The plastic cell', 'address 25', 'Gotham', 46460, 1, 1111111111, 222222222, 1, 1105, 2, NULL, NULL, 0, 0),
|
||||||
(126, 'Many places', 'address 26', 'Gotham', 46460, 1, 1111111111, 222222222, 1, 1106, 2, NULL, NULL, 0, 0),
|
(126, 'Many places', 'address 26', 'Gotham', 46460, 1, 1111111111, 222222222, 1, 1106, 2, NULL, NULL, 0, 0),
|
||||||
|
@ -4038,6 +4038,8 @@ INSERT IGNORE INTO vn.saySimpleConfig (url, defaultChannel)
|
||||||
INSERT INTO vn.workerIrpf (workerFk,spouseNif, geographicMobilityDate)
|
INSERT INTO vn.workerIrpf (workerFk,spouseNif, geographicMobilityDate)
|
||||||
VALUES (1106,'26493101E','2019-09-20');
|
VALUES (1106,'26493101E','2019-09-20');
|
||||||
|
|
||||||
|
INSERT INTO vn.osrmConfig (id,url,tolerance)
|
||||||
|
VALUES (1,'https://router.project-osrm.org', 0.002);
|
||||||
|
|
||||||
INSERT IGNORE INTO vn.inventoryConfig
|
INSERT IGNORE INTO vn.inventoryConfig
|
||||||
SET id = 1,
|
SET id = 1,
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
CREATE TABLE `vn`.`osrmConfig` (
|
||||||
|
`id` int(10) unsigned NOT NULL,
|
||||||
|
`url` varchar(100) NOT NULL COMMENT 'Dirección base de la API',
|
||||||
|
`tolerance` decimal(6,6) NOT NULL DEFAULT 0 COMMENT 'Tolerancia entre las coordenadas enviadas y las retornadas',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
CONSTRAINT `osrmConfig_check` CHECK (`id` = 1)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||||
|
|
||||||
|
-- Para que no de error al añadir la FK de zone
|
||||||
|
UPDATE vn.zone
|
||||||
|
SET price = 0.1
|
||||||
|
WHERE price = 0;
|
||||||
|
|
||||||
|
ALTER TABLE vn.`zone`
|
||||||
|
ADD addressFk int(11) DEFAULT NULL COMMENT 'Punto de distribución de donde salen para repartir',
|
||||||
|
ADD CONSTRAINT zone_address_FK FOREIGN KEY (addressFk) REFERENCES vn.address(id) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
ALTER TABLE vn.zoneConfig
|
||||||
|
ADD defaultAddressFk int(11) DEFAULT NULL NULL COMMENT 'Punto de distribución por defecto',
|
||||||
|
ADD CONSTRAINT zoneConfig_address_FK FOREIGN KEY (defaultAddressFk) REFERENCES vn.address(id) ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
@ -391,7 +391,12 @@
|
||||||
"Sales already moved": "Ya han sido transferidas",
|
"Sales already moved": "Ya han sido transferidas",
|
||||||
"The raid information is not correct": "La información de la redada no es correcta",
|
"The raid information is not correct": "La información de la redada no es correcta",
|
||||||
"There are tickets to be invoiced": "Hay tickets para esta zona, borralos primero",
|
"There are tickets to be invoiced": "Hay tickets para esta zona, borralos primero",
|
||||||
"Price cannot be blank": "Price cannot be blank",
|
"No trips found because input coordinates are not connected": "No se encontraron rutas porque las coordenadas de entrada no están conectadas",
|
||||||
|
"This request is not supported": "Esta solicitud no es compatible",
|
||||||
|
"Invalid options or too many coordinates": "Opciones invalidas o demasiadas coordenadas",
|
||||||
|
"No address has coordinates": "Ninguna dirección tiene coordenadas",
|
||||||
"An item type with the same code already exists": "Un tipo con el mismo código ya existe",
|
"An item type with the same code already exists": "Un tipo con el mismo código ya existe",
|
||||||
"Holidays to past days not available": "Las vacaciones a días pasados no están disponibles"
|
"Holidays to past days not available": "Las vacaciones a días pasados no están disponibles",
|
||||||
|
"All tickets have a route order": "Todos los tickets tienen orden de ruta",
|
||||||
|
"Price cannot be blank": "Price cannot be blank"
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,6 +72,14 @@ module.exports = function(Self) {
|
||||||
{
|
{
|
||||||
arg: 'isLogifloraAllowed',
|
arg: 'isLogifloraAllowed',
|
||||||
type: 'boolean'
|
type: 'boolean'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'longitude',
|
||||||
|
type: 'any',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'latitude',
|
||||||
|
type: 'any',
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
returns: {
|
returns: {
|
||||||
|
|
|
@ -0,0 +1,122 @@
|
||||||
|
const UserError = require('vn-loopback/util/user-error');
|
||||||
|
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethod('optimizePriority', {
|
||||||
|
description: 'Updates the ticket priority of tickets without priority',
|
||||||
|
accepts: {
|
||||||
|
arg: 'id',
|
||||||
|
type: 'number',
|
||||||
|
required: true,
|
||||||
|
description: 'Route id',
|
||||||
|
http: {source: 'path'}
|
||||||
|
},
|
||||||
|
returns: {
|
||||||
|
type: 'object',
|
||||||
|
root: true
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
path: '/:id/optimizePriority',
|
||||||
|
verb: 'POST'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.optimizePriority = async(id, options) => {
|
||||||
|
const models = Self.app.models;
|
||||||
|
const myOptions = {};
|
||||||
|
let tx;
|
||||||
|
|
||||||
|
if (typeof options == 'object')
|
||||||
|
Object.assign(myOptions, options);
|
||||||
|
|
||||||
|
const tickets = await models.Ticket.find({
|
||||||
|
where: {routeFk: id}
|
||||||
|
}, myOptions);
|
||||||
|
|
||||||
|
let ticketAddress = [];
|
||||||
|
for (const ticket of tickets) {
|
||||||
|
ticketAddress.push({
|
||||||
|
ticketId: ticket.id,
|
||||||
|
addressId: ticket.addressFk,
|
||||||
|
zoneId: ticket.zoneFk,
|
||||||
|
priority: ticket.priority
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Igualamos los priority del mismo addressId
|
||||||
|
const addressPriorityMap = ticketAddress.reduce((acc, {addressId, priority}) => {
|
||||||
|
if (priority !== null) {
|
||||||
|
acc[addressId] = acc[addressId] === undefined
|
||||||
|
? priority
|
||||||
|
: Math.max(acc[addressId], priority);
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
});
|
||||||
|
ticketAddress.forEach(item => {
|
||||||
|
const maxPriority = addressPriorityMap[item.addressId];
|
||||||
|
if (maxPriority) item.priority = maxPriority;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Añadimos las direcciones a optimizar
|
||||||
|
let addressIds = [];
|
||||||
|
ticketAddress.forEach(h => {
|
||||||
|
if (!addressIds.includes(h.addressId) && !h.priority)
|
||||||
|
addressIds.push(h.addressId);
|
||||||
|
});
|
||||||
|
if (!addressIds.length) throw new UserError('All tickets have a route order');
|
||||||
|
|
||||||
|
// Obtenemos el zoneId más frecuente
|
||||||
|
const zoneFrequency = ticketAddress.reduce((acc, {zoneId}) => {
|
||||||
|
if (zoneId != null) acc[zoneId] = (acc[zoneId] || 0) + 1;
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
const [mostFrequentZoneId] = Object.entries(zoneFrequency)
|
||||||
|
.reduce((maxEntry, entry) => entry[1] > maxEntry[1] ? entry : maxEntry, [null, 0]);
|
||||||
|
|
||||||
|
// Obtenemos los address inicio y fin
|
||||||
|
const maxPosition = Math.max(...ticketAddress.map(g => g.priority));
|
||||||
|
let firstAddress = (await models.Zone.findById(mostFrequentZoneId, myOptions))?.addressFk
|
||||||
|
|| (await models.ZoneConfig.findOne())?.defaultAddressFk;
|
||||||
|
const lastAddress = firstAddress;
|
||||||
|
if (maxPosition) firstAddress = ticketAddress.find(g => g.priority === maxPosition)?.addressId;
|
||||||
|
|
||||||
|
// Revisamos las coincidencias y actualizamos la prioridad en el array
|
||||||
|
const addressPositions = await models.OsrmConfig.optimize(addressIds, firstAddress, lastAddress, myOptions);
|
||||||
|
await Promise.all(ticketAddress.map(async i => {
|
||||||
|
const foundPosition = addressPositions.find(item => item.addressId === i.addressId);
|
||||||
|
if (foundPosition) i.priority = foundPosition.position + (maxPosition + 1);
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Suavizado de prioridad para que no hayan escalones
|
||||||
|
const allPriorities = ticketAddress
|
||||||
|
.map(item => item.priority)
|
||||||
|
.filter(p => p !== null);
|
||||||
|
const uniquePriorities = [...new Set(allPriorities)].sort((a, b) => a - b);
|
||||||
|
const priorityMap = {};
|
||||||
|
uniquePriorities.forEach((p, index) => {
|
||||||
|
priorityMap[p] = index + 1;
|
||||||
|
});
|
||||||
|
ticketAddress.forEach(item => {
|
||||||
|
if (item.priority !== null) item.priority = priorityMap[item.priority];
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!myOptions.transaction) {
|
||||||
|
tx = await Self.beginTransaction({});
|
||||||
|
myOptions.transaction = tx;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Realizamos el update en la base de datos
|
||||||
|
try {
|
||||||
|
await Promise.all(ticketAddress.map(async y => {
|
||||||
|
if (y.priority) {
|
||||||
|
const ticket = await models.Ticket.findById(y.ticketId);
|
||||||
|
await ticket.updateAttribute('priority', y.priority, myOptions);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
if (tx) await tx.commit();
|
||||||
|
return;
|
||||||
|
} catch (err) {
|
||||||
|
if (tx) await tx.rollback();
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,36 @@
|
||||||
|
const models = require('vn-loopback/server/server').models;
|
||||||
|
const routeId = 1;
|
||||||
|
|
||||||
|
describe('route optimizePriority())', function() {
|
||||||
|
it('should execute without throwing errors', async function() {
|
||||||
|
const tx = await models.Route.beginTransaction({});
|
||||||
|
let error;
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
await models.Ticket.updateAll(
|
||||||
|
{routeFk: routeId},
|
||||||
|
{priority: null},
|
||||||
|
options
|
||||||
|
);
|
||||||
|
await models.Route.optimizePriority(routeId, options);
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
error = e;
|
||||||
|
await tx.rollback();
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should execute with error', async function() {
|
||||||
|
let error;
|
||||||
|
try {
|
||||||
|
await models.Route.optimizePriority(routeId);
|
||||||
|
} catch (e) {
|
||||||
|
error = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error).toBeDefined();
|
||||||
|
expect(error.message).toBe('All tickets have a route order');
|
||||||
|
});
|
||||||
|
});
|
|
@ -16,4 +16,5 @@ module.exports = Self => {
|
||||||
require('../methods/route/downloadZip')(Self);
|
require('../methods/route/downloadZip')(Self);
|
||||||
require('../methods/route/getExpeditionSummary')(Self);
|
require('../methods/route/getExpeditionSummary')(Self);
|
||||||
require('../methods/route/getByWorker')(Self);
|
require('../methods/route/getByWorker')(Self);
|
||||||
|
require('../methods/route/optimizePriority')(Self);
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,6 +17,9 @@
|
||||||
"ZoneClosure": {
|
"ZoneClosure": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
"ZoneConfig": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
"ZoneEvent": {
|
"ZoneEvent": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"name": "ZoneConfig",
|
||||||
|
"options": {
|
||||||
|
"mysql": {
|
||||||
|
"table": "zoneConfig"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "number",
|
||||||
|
"id": true,
|
||||||
|
"description": "Identifier"
|
||||||
|
},
|
||||||
|
"scope": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"forwardDays": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"relations": {
|
||||||
|
"address": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "Address",
|
||||||
|
"foreignKey": "defaultAddressFk"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -72,6 +72,11 @@
|
||||||
"type": "hasMany",
|
"type": "hasMany",
|
||||||
"model": "ZoneClosure",
|
"model": "ZoneClosure",
|
||||||
"foreignKey": "zoneFk"
|
"foreignKey": "zoneFk"
|
||||||
|
},
|
||||||
|
"address": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "Address",
|
||||||
|
"foreignKey": "addressFk"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue