Merge branch 'dev' into 7709-supplierPackaging_ReportSource_2
gitea/salix/pipeline/pr-dev This commit looks good
Details
gitea/salix/pipeline/pr-dev This commit looks good
Details
This commit is contained in:
commit
6c15f3836d
|
@ -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,7 +4038,9 @@ 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 IGNORE 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,
|
||||||
supplierFk = 4;
|
supplierFk = 4;
|
||||||
|
|
|
@ -11,6 +11,7 @@ BEGIN
|
||||||
DECLARE vCurrentCommission INT;
|
DECLARE vCurrentCommission INT;
|
||||||
DECLARE vIsNotEUR INT;
|
DECLARE vIsNotEUR INT;
|
||||||
DECLARE vLastEntryFk INT;
|
DECLARE vLastEntryFk INT;
|
||||||
|
DECLARE vLanded INT;
|
||||||
|
|
||||||
SELECT count(*) INTO vIsNotEUR
|
SELECT count(*) INTO vIsNotEUR
|
||||||
FROM currency c
|
FROM currency c
|
||||||
|
@ -26,23 +27,25 @@ BEGIN
|
||||||
|
|
||||||
RETURN IFNULL(vCommission, 0);
|
RETURN IFNULL(vCommission, 0);
|
||||||
ELSE
|
ELSE
|
||||||
|
SELECT landed INTO vLanded
|
||||||
|
FROM travel
|
||||||
|
WHERE id = vTravelFk;
|
||||||
|
|
||||||
SELECT e.id INTO vLastEntryFk
|
SELECT e.id INTO vLastEntryFk
|
||||||
FROM `entry` e
|
FROM `entry` e
|
||||||
JOIN travel tr ON tr.id = e.travelFk
|
JOIN travel tr ON tr.id = e.travelFk
|
||||||
WHERE e.supplierFk = vSupplierFk
|
WHERE e.supplierFk = vSupplierFk
|
||||||
ORDER BY tr.landed DESC
|
ORDER BY (vLanded <= tr.landed), tr.landed DESC
|
||||||
LIMIT 1;
|
LIMIT 1;
|
||||||
|
|
||||||
IF vLastEntryFk THEN
|
IF vLastEntryFk THEN
|
||||||
SELECT commission INTO vCurrentCommission
|
SELECT commission INTO vCurrentCommission
|
||||||
FROM `entry`
|
FROM `entry`
|
||||||
WHERE id = vLastEntryFk;
|
WHERE id = vLastEntryFk;
|
||||||
|
|
||||||
ELSE
|
ELSE
|
||||||
SELECT commission INTO vCurrentCommission
|
SELECT commission INTO vCurrentCommission
|
||||||
FROM supplier s
|
FROM supplier s
|
||||||
WHERE s.id = vSupplierFk;
|
WHERE s.id = vSupplierFk;
|
||||||
|
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
RETURN vCurrentCommission;
|
RETURN vCurrentCommission;
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
DELIMITER $$
|
|
||||||
CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`inventoryFailureAdd`()
|
|
||||||
BEGIN
|
|
||||||
|
|
||||||
DECLARE done BOOL DEFAULT FALSE;
|
|
||||||
DECLARE vTicketFk INT;
|
|
||||||
|
|
||||||
DECLARE rs CURSOR FOR
|
|
||||||
SELECT id FROM vn.ticket
|
|
||||||
WHERE shipped = util.yesterday()
|
|
||||||
AND clientFk = 400
|
|
||||||
AND warehouseFk IN (1,44);
|
|
||||||
|
|
||||||
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
|
|
||||||
|
|
||||||
OPEN rs;
|
|
||||||
|
|
||||||
FETCH rs INTO vTicketFk;
|
|
||||||
|
|
||||||
WHILE NOT done DO
|
|
||||||
|
|
||||||
INSERT INTO vn.inventoryFailure(dated, itemFk, quantity, value, warehouseFk, throwerFk)
|
|
||||||
SELECT t.shipped,
|
|
||||||
s.itemFk,
|
|
||||||
s.quantity,
|
|
||||||
b.buyingValue + b.freightValue + b.packageValue + b.comissionValue,
|
|
||||||
t.warehouseFk,
|
|
||||||
w.id
|
|
||||||
FROM vn.ticket t
|
|
||||||
JOIN vn.sale s ON s.ticketFk = t.id
|
|
||||||
LEFT JOIN cache.last_buy lb ON lb.warehouse_id = t.warehouseFk AND item_id = s.itemFk
|
|
||||||
LEFT JOIN vn.buy b ON b.id = lb.buy_id
|
|
||||||
LEFT JOIN vn.worker w ON w.code = LEFT(s.concept, 3)
|
|
||||||
WHERE t.id = vTicketFk
|
|
||||||
AND s.quantity > 0;
|
|
||||||
|
|
||||||
FETCH rs INTO vTicketFk;
|
|
||||||
|
|
||||||
END WHILE;
|
|
||||||
|
|
||||||
|
|
||||||
CLOSE rs;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
|
@ -164,10 +164,6 @@ BEGIN
|
||||||
SET itemFk = vItemNew
|
SET itemFk = vItemNew
|
||||||
WHERE itemFk = vItemOld;
|
WHERE itemFk = vItemOld;
|
||||||
|
|
||||||
UPDATE inventoryFailure
|
|
||||||
SET itemFk = vItemNew
|
|
||||||
WHERE itemFk = vItemOld;
|
|
||||||
|
|
||||||
UPDATE genericAllocation
|
UPDATE genericAllocation
|
||||||
SET itemFk = vItemNew
|
SET itemFk = vItemNew
|
||||||
WHERE itemFk = vItemOld;
|
WHERE itemFk = vItemOld;
|
||||||
|
|
|
@ -0,0 +1,185 @@
|
||||||
|
CREATE TABLE IF NOT EXISTS `vn`.`sim` (
|
||||||
|
`code` VARCHAR(25) COMMENT 'No se ha puesto BIGINT por incompatibilidad con Access',
|
||||||
|
`line` VARCHAR(15) NOT NULL CHECK (`line` REGEXP '^[0-9]+$'),
|
||||||
|
`ext` INT(4) NOT NULL,
|
||||||
|
`pin` VARCHAR(4) NOT NULL CHECK (`pin` REGEXP '^[0-9]+$'),
|
||||||
|
`puk` VARCHAR(15) NOT NULL CHECK (`pin` REGEXP '^[0-9]+$'),
|
||||||
|
PRIMARY KEY (`code`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||||
|
|
||||||
|
ALTER TABLE vn.deviceProductionUser CHANGE simSerialNumber simFk VARCHAR(25) DEFAULT NULL NULL;
|
||||||
|
ALTER TABLE vn.deviceProductionUser MODIFY COLUMN simFk VARCHAR(25) DEFAULT NULL NULL;
|
||||||
|
|
||||||
|
INSERT IGNORE INTO `vn`.`sim` (`line`, `ext`, `pin`, `code`, `puk`) VALUES
|
||||||
|
('621188151', 2209, '1486', '3456985220092508','14213470'),
|
||||||
|
('621188152', 2210, '8765', '3456985220092509','99473093'),
|
||||||
|
('621188153', 2211, '3064', '3456985220092510','52967210'),
|
||||||
|
('621188759', 2081, '3700', '3456985220123637','56600999'),
|
||||||
|
('621188760', 2082, '3259', '345698522023638','87492404'),
|
||||||
|
('621188761', 2083, '2790', '3456985220123639','94009456'),
|
||||||
|
('621188762', 2084, '2480', '3456985220123644','1484999'),
|
||||||
|
('621188763', 2085, '6876', '3456985220123641','36577064'),
|
||||||
|
('621188766', 2086, '7775', '3456985220123642','80761698'),
|
||||||
|
('621188769', 2088, '4027', '3456985220123643','37921712'),
|
||||||
|
('621188771', 2089, '8797', '3456985220123640','63092540'),
|
||||||
|
('621188772', 2090, '8404', '3456985220123645','21014997'),
|
||||||
|
('621188773', 2091, '5481', '3456985220123646','16317277'),
|
||||||
|
('621188774', 2092, '9632', '3456985220123647','22235994'),
|
||||||
|
('621188775', 2093, '4654', '3456985220123648','28506486'),
|
||||||
|
('621188838', 2094, '1392', '3456985220123649','29498627'),
|
||||||
|
('621188839', 2095, '7774', '3456985220123650','46263490'),
|
||||||
|
('621188840', 2096, '7304', '3456985220123658','8212044'),
|
||||||
|
('621188841', 2097, '5569', '3456985220123652','81597658'),
|
||||||
|
('621188842', 2098, '4944', '3456985220123653','24961501'),
|
||||||
|
('621188843', 2099, '5142', '3456985220123654','17035634'),
|
||||||
|
('621188844', 2111, '7245', '3456985220123655','90231951'),
|
||||||
|
('621188846', 2110, '6590', '3456985220123656','72201537'),
|
||||||
|
('667680207', 2564, '4042', '34569832200759166','48401979'),
|
||||||
|
('667680315', 2565, '7143', '34569832200759372','32143252'),
|
||||||
|
('667680318', 2566, '6342', '34569832200759364','39597112'),
|
||||||
|
('667680413', 2567, '5580', '34569832200759356','32786992'),
|
||||||
|
('667680463', 2568, '0171', '34569832200759349','34240853'),
|
||||||
|
('667688217', 2569, '2500', '34569832200759331','5687589'),
|
||||||
|
('633603945', 2212, '7129', '34569832200759323','51554019'),
|
||||||
|
('622130186', 2213, '4826', '34569832200759307','19623551'),
|
||||||
|
('633973424', 2214, '8535', '34569832200759299','94619307'),
|
||||||
|
('633703828', 2215, '8628', '34569832200759281','22468012'),
|
||||||
|
('622025110', 2216, '2399', '34569832200759273','34602918'),
|
||||||
|
('622924867', 2217, '5665', '34569832200759265','26920216'),
|
||||||
|
('722409630', 2218, '5211', '34569832200759240','93750137'),
|
||||||
|
('623590529', 2219, '0493', '34569832200759208','47077088'),
|
||||||
|
('633243462', 2220, '6902', '34569832200759174','6421962'),
|
||||||
|
('633047286', 2221, '5592', '34569832200759182','32069439'),
|
||||||
|
('744716801', 2112, '9184', '34569832200759190','57049814'),
|
||||||
|
('655995021', 2131, '8896', '34569852202049093','19497356'),
|
||||||
|
('685522718', 2132, '1955', '34569852202049101','28519879'),
|
||||||
|
('674587213', 2994, '2006', '34569332200223743','62360135'),
|
||||||
|
('674587227', 2993, '9271', '34569332200223750','81628192'),
|
||||||
|
('674587229', 2993, '0900', '34569332200223768','91119071'),
|
||||||
|
('674587231', 2992, '5007', '34569332200223776','45826232'),
|
||||||
|
('674587234', 2991, '1378', '34569332200223784','91245744'),
|
||||||
|
('674587240', 2990, '0905', '34569332200223792','13083224'),
|
||||||
|
('674587245', 2989, '9059', '34569332200223800','15291807'),
|
||||||
|
('674587250', 2988, '8188', '34569332200223818','83017918'),
|
||||||
|
('674587254', 2987, '2962', '34569332200223826','92809271'),
|
||||||
|
('674587256', 2986, '0358', '34569332200223834','81067040'),
|
||||||
|
('674592713', 2570, '2537', '34569332200230672','82325850'),
|
||||||
|
('697832478', 2579, '0936', '34568732200494825','49658372'),
|
||||||
|
('697832176', 2571, '5944', '34568732200494742','19039461'),
|
||||||
|
('697832477', 2572, '5138', '34568732200494759','25712504'),
|
||||||
|
('697832178', 2573, '4597', '34568732200494767','66241760'),
|
||||||
|
('697832182', 2574, '9241', '34568732200494775','07342562'),
|
||||||
|
('697832196', 2575, '2995', '34568732200494783','53929026'),
|
||||||
|
('697832214', 2576, '7434', '34568732200494791','49698432'),
|
||||||
|
('697832230', 2577, '7004', '34568732200494809','21578612'),
|
||||||
|
('697832235', 2578, '9674', '34568732200494817','93090700'),
|
||||||
|
('673420375', 2599, '5430', '34562052300117259','35911412'),
|
||||||
|
('673420367', 2598, '8402', '34562052300117242','924654'),
|
||||||
|
('673420361', 2597, '5125', '34562052300117234','12027970'),
|
||||||
|
('673420355', 2596, '5069', '34562052300117226','34978149'),
|
||||||
|
('673420348', 2595, '8911', '34562052300117218','4228121'),
|
||||||
|
('673420346', 2594, '2461', '34562052300117200','67670772'),
|
||||||
|
('673420345', 2593, '2226', '34562052300117192','90586404'),
|
||||||
|
('673420306', 2592, '3355', '34562052300117184','97850017'),
|
||||||
|
('673420257', 2591, '9395', '34562052300117176','50713786'),
|
||||||
|
('673420231', 2590, '1378', '34562052300117168','50151763'),
|
||||||
|
('673420223', 2589, '9580', '34562052300117150','99534550'),
|
||||||
|
('673420216', 2588, '4955', '34562052300117143','317554'),
|
||||||
|
('673420203', 2587, '6742', '34562052300117135','69321531'),
|
||||||
|
('673420201', 2586, '1659', '34562052300117127','54720480'),
|
||||||
|
('673420199', 2585, '7823', '34562052300117119','22923796'),
|
||||||
|
('673420198', 2584, '1787', '34562052300117101','54414630'),
|
||||||
|
('673420168', 2583, '6334', '34562052300117093','50694894'),
|
||||||
|
('673420147', 2582, '8951', '34562052300117085','1402535'),
|
||||||
|
('673420125', 2581, '3068', '34562052300117077','86216200'),
|
||||||
|
('673420124', 2580, '9517', '34562052300117069','42504099'),
|
||||||
|
('600294609', 2715, '7474', '34569832304894588','55923317'),
|
||||||
|
('600084713', 2703, '8342', '34569832304894570','8392636'),
|
||||||
|
('600084732', 2704, '1625', '34569832304894513','75477452'),
|
||||||
|
('600084850', 2705, '9896', '34569832304894653','28589813'),
|
||||||
|
('600084951', 2706, '5520', '34569832304894661','75353012'),
|
||||||
|
('600084978', 2707, '2698', '34569832304894679','9005523'),
|
||||||
|
('600085403', 2708, '0837', '34569832304894646','77051152'),
|
||||||
|
('600085513', 2709, '3106', '34569832304894687','41571002'),
|
||||||
|
('600293916', 2712, '8990', '34569832304894620','95188676'),
|
||||||
|
('600294160', 2714, '6376', '34569832304894703','79879896'),
|
||||||
|
('671919529', 2975, '9184', '34569832304806236','7535392'),
|
||||||
|
('671919942', 2981, '0328', '34569832304806269','31052894'),
|
||||||
|
('671919530', 2976, '0344', '34569832304806251','89860304'),
|
||||||
|
('671919533', 2977, '0668', '34569832304806244','42921771'),
|
||||||
|
('671919535', 2978, '0105', '34569832304806277','31009417'),
|
||||||
|
('671919537', 2979, '0881', '34569832304806285','33479769'),
|
||||||
|
('671919540', 2980, '9874', '34569832304806293','14103929'),
|
||||||
|
('671919525', 2972, '2089', '34569832304806301','45903729'),
|
||||||
|
('671919527', 2973, '8206', '34569832304806368','1586035'),
|
||||||
|
('671919528', 2974, '2532', '34569832304806327','62310124'),
|
||||||
|
('673668717', 2836, '7973', '34562032301044223','15635496'),
|
||||||
|
('673668734', 2837, '4457', '34562032301044231','18313118'),
|
||||||
|
('673668738', 2824, '2911', '34562032301044249','30875583'),
|
||||||
|
('673668745', 2838, '7253', '34562032301044256','62754222'),
|
||||||
|
('673668796', 2839, '0068', '34562032301044264','15556829'),
|
||||||
|
('673668803', 2840, '2386', '34562032301044272','17572287'),
|
||||||
|
('673669591', 2850, '3833', '34562032301044280','34828896'),
|
||||||
|
('673668808', 2841, '3584', '34562032301044298','16234497'),
|
||||||
|
('673670102', 2851, '3554', '34562032301044306','23652625'),
|
||||||
|
('673670131', 2852, '4412', '34562032301044314','88611709'),
|
||||||
|
('673670135', 2827, '6058', '34562032301044322','53918579'),
|
||||||
|
('673670201', 2828, '8066', '34562032301044330','92369343'),
|
||||||
|
('673670225', 2829, '4592', '34562032301044348','24126635'),
|
||||||
|
('673670236', 2830, '2974', '34562032301044355','88608465'),
|
||||||
|
('673671485', 2849, '0349', '34562032301044363','44944874'),
|
||||||
|
('673461977', 2871, '1728', '34562032400157090','46975780'),
|
||||||
|
('673461975', 2870, '4734', '34562032400157082','69628432'),
|
||||||
|
('673461972', 2867, '6276', '34562032400157058','53338365'),
|
||||||
|
('673461979', 2872, '6043', '34562032400157108','36525197'),
|
||||||
|
('673461958', 2859, '3164', '34562032400156977','58947831'),
|
||||||
|
('673461957', 2857, '8685', '34562032400156969','15826386'),
|
||||||
|
('673461944', 2853, '1073', '34562032400156910','20452195'),
|
||||||
|
('673461974', 2869, '7121', '34562032400157074','32044645'),
|
||||||
|
('673461973', 2868, '8022', '34562032400157066','29282044'),
|
||||||
|
('673461971', 2866, '3089', '34562032400157041','66149978'),
|
||||||
|
('673461969', 2865, '7555', '34562032400157033','78391293'),
|
||||||
|
('673461960', 2860, '5203', '34562032400156985','37138232'),
|
||||||
|
('673461952', 2855, '6915', '34562032400156936','62724661'),
|
||||||
|
('673461949', 2854, '8706', '34562032400156928','5594345'),
|
||||||
|
('673461966', 2863, '2496', '34562032400157017','93450666'),
|
||||||
|
('673461968', 2864, '3703', '34562032400157025','23208841'),
|
||||||
|
('673461963', 2862, '9364', '34562032400157009','29712130'),
|
||||||
|
('673462719', 2873, '9387', '34562032400156951','50434348'),
|
||||||
|
('673461962', 2861, '8441', '34562032400156993','39686909'),
|
||||||
|
('673461956', 2826, '5392', '34562032400156944','5496107'),
|
||||||
|
('673465284', 2694, '1523', '34562032400171349','14554994'),
|
||||||
|
('673465282', 2692, '4645', '34562032400171323','24871187'),
|
||||||
|
('673465283', 2693, '5253', '34562032400171331','28303238'),
|
||||||
|
('673465841', 2696, '0849', '34562032400171257','21673222'),
|
||||||
|
('673465258', 2679, '4140', '34562032400171174','39793881'),
|
||||||
|
('673465263', 2680, '6922', '34562032400171182','12253261'),
|
||||||
|
('673465265', 2681, '9112', '34562032400171190','93894366'),
|
||||||
|
('673465267', 2682, '3259', '34562032400171208','2342189'),
|
||||||
|
('673465268', 2683, '8540', '34562032400171216','63886925'),
|
||||||
|
('673465285', 2695, '4167', '34562032400171356','79227618'),
|
||||||
|
('673465270', 2684, '4292', '34562032400171224','19216349'),
|
||||||
|
('673465272', 2685, '4007', '34562032400171232','14396903'),
|
||||||
|
('673465273', 2686, '6894', '34562032400171240','13569394'),
|
||||||
|
('673465274', 2687, '5268', '34562032400171265','59453667'),
|
||||||
|
('673465275', 2688, '0232', '34562032400171273','62324713'),
|
||||||
|
('673465276', 2689, '2720', '34562032400171281','65977200'),
|
||||||
|
('673465843', 2698, '4773', '34562032400171364','78387158'),
|
||||||
|
('673465842', 2697, '3729', '34562032400171315','94201789'),
|
||||||
|
('673465280', 2691, '0503', '34562032400171307','12298533'),
|
||||||
|
('673465279', 2690, '8239', '34562032400171299','76183877');
|
||||||
|
|
||||||
|
UPDATE vn.deviceProductionUser
|
||||||
|
SET simFk = NULL
|
||||||
|
WHERE id IN (
|
||||||
|
SELECT dpu.id
|
||||||
|
FROM vn.deviceProductionUser dpu
|
||||||
|
LEFT JOIN vn.sim s ON s.code = dpu.simFk
|
||||||
|
WHERE s.code IS NULL
|
||||||
|
AND dpu.simFk IS NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE vn.deviceProductionUser ADD CONSTRAINT deviceProductionUser_sim_FK
|
||||||
|
FOREIGN KEY (simFk) REFERENCES vn.sim(code) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
GRANT SELECT, INSERT, DELETE, UPDATE ON TABLE vn.sim TO hr;
|
|
@ -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;
|
|
@ -0,0 +1,5 @@
|
||||||
|
INSERT IGNORE INTO salix.ACL (model,property,accessType,permission,principalType,principalId)
|
||||||
|
VALUES ('OsrmConfig','optimize','READ','ALLOW','ROLE','employee'),
|
||||||
|
('Route', 'optimizePriority','*','ALLOW','ROLE','employee');
|
||||||
|
INSERT IGNORE INTO vn.osrmConfig (id,url,tolerance)
|
||||||
|
VALUES (1,'https://router.project-osrm.org', 0.002);
|
|
@ -0,0 +1,3 @@
|
||||||
|
ALTER TABLE vn.mistakeType
|
||||||
|
ADD `time` int(10) NULL COMMENT 'Segundos que se suelen tardar en arreglar el fallo',
|
||||||
|
ADD code varchar(50) DEFAULT NULL NULL AFTER id;
|
|
@ -0,0 +1,5 @@
|
||||||
|
RENAME TABLE vn.inventoryFailure TO vn.inventoryFailure__;
|
||||||
|
ALTER TABLE vn.inventoryFailure__ COMMENT='@deprecated 2024-12-16';
|
||||||
|
|
||||||
|
RENAME TABLE vn.inventoryFailureCause TO vn.inventoryFailureCause__;
|
||||||
|
ALTER TABLE vn.inventoryFailureCause__ COMMENT='@deprecated 2024-12-16';
|
|
@ -248,6 +248,6 @@
|
||||||
"Payment method is required": "Payment method is required",
|
"Payment method is required": "Payment method is required",
|
||||||
"Sales already moved": "Sales already moved",
|
"Sales already moved": "Sales already moved",
|
||||||
"Holidays to past days not available": "Holidays to past days not available",
|
"Holidays to past days not available": "Holidays to past days not available",
|
||||||
"There are tickets to be invoiced": "There are tickets to be invoiced for this zone, please delete them first",
|
"Price cannot be blank": "Price cannot be blank",
|
||||||
"Price cannot be blank": "Price cannot be blank"
|
"There are tickets to be invoiced": "There are tickets to be invoiced"
|
||||||
}
|
}
|
||||||
|
|
|
@ -390,8 +390,13 @@
|
||||||
"The web user's email already exists": "El correo del usuario web ya existe",
|
"The web user's email already exists": "El correo del usuario web ya existe",
|
||||||
"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",
|
"No trips found because input coordinates are not connected": "No se encontraron rutas porque las coordenadas de entrada no están conectadas",
|
||||||
"Price cannot be blank": "Price cannot be blank",
|
"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",
|
||||||
|
"There are tickets to be invoiced": "La zona tiene tickets por facturar"
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
|
@ -54,9 +54,17 @@ module.exports = Self => {
|
||||||
throw new UserError(`That item doesn't exists`);
|
throw new UserError(`That item doesn't exists`);
|
||||||
|
|
||||||
const request = await models.TicketRequest.findById(ctx.args.id, {
|
const request = await models.TicketRequest.findById(ctx.args.id, {
|
||||||
include: {relation: 'ticket'}
|
include: {
|
||||||
|
relation: 'ticket',
|
||||||
|
scope: {
|
||||||
|
include: {
|
||||||
|
relation: 'client',
|
||||||
|
scope: {
|
||||||
|
fields: ['id', 'name', 'salesPersonFk']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
}, myOptions);
|
}, myOptions);
|
||||||
|
|
||||||
const itemStock = await models.Item.getVisibleAvailable(
|
const itemStock = await models.Item.getVisibleAvailable(
|
||||||
ctx.args.itemFk,
|
ctx.args.itemFk,
|
||||||
request.ticket().warehouseFk,
|
request.ticket().warehouseFk,
|
||||||
|
@ -89,19 +97,19 @@ module.exports = Self => {
|
||||||
const query = `CALL vn.sale_calculateComponent(?, NULL)`;
|
const query = `CALL vn.sale_calculateComponent(?, NULL)`;
|
||||||
await Self.rawSql(query, [sale.id], myOptions);
|
await Self.rawSql(query, [sale.id], myOptions);
|
||||||
|
|
||||||
const url = await Self.app.models.Url.getUrl();
|
const salesPerson = request.ticket().client().salesPersonFk;
|
||||||
const requesterId = request.requesterFk;
|
if (salesPerson) {
|
||||||
|
const url = await Self.app.models.Url.getUrl();
|
||||||
const message = $t('Bought units from buy request', {
|
const message = $t('Bought units from buy request', {
|
||||||
quantity: sale.quantity,
|
quantity: sale.quantity,
|
||||||
concept: sale.concept,
|
concept: sale.concept,
|
||||||
itemId: sale.itemFk,
|
itemId: sale.itemFk,
|
||||||
ticketId: sale.ticketFk,
|
ticketId: sale.ticketFk,
|
||||||
url: `${url}ticket/${sale.ticketFk}/summary`,
|
url: `${url}ticket/${sale.ticketFk}/summary`,
|
||||||
urlItem: `${url}item/${sale.itemFk}/summary`
|
urlItem: `${url}item/${sale.itemFk}/summary`
|
||||||
});
|
});
|
||||||
await models.Chat.sendCheckingPresence(ctx, requesterId, message, myOptions);
|
await models.Chat.sendCheckingPresence(ctx, salesPerson, message, myOptions);
|
||||||
|
}
|
||||||
if (tx) await tx.commit();
|
if (tx) await tx.commit();
|
||||||
|
|
||||||
return sale;
|
return sale;
|
||||||
|
|
|
@ -1,18 +1,22 @@
|
||||||
|
const UserError = require('vn-loopback/util/user-error');
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
Self.remoteMethodCtx('deny', {
|
Self.remoteMethodCtx('deny', {
|
||||||
description: 'sets a ticket request to denied and returns the changes',
|
description: 'Sets a ticket request to denied and returns the changes',
|
||||||
accessType: 'WRITE',
|
accessType: 'WRITE',
|
||||||
accepts: [{
|
accepts: [
|
||||||
arg: 'id',
|
{
|
||||||
type: 'number',
|
arg: 'id',
|
||||||
required: true,
|
type: 'number',
|
||||||
description: 'The request ID',
|
required: true,
|
||||||
}, {
|
description: 'The request ID',
|
||||||
arg: 'observation',
|
},
|
||||||
type: 'String',
|
{
|
||||||
required: true,
|
arg: 'observation',
|
||||||
description: 'The request observation',
|
type: 'string',
|
||||||
}],
|
required: true,
|
||||||
|
description: 'The request observation',
|
||||||
|
}
|
||||||
|
],
|
||||||
returns: {
|
returns: {
|
||||||
type: 'number',
|
type: 'number',
|
||||||
root: true
|
root: true
|
||||||
|
@ -29,7 +33,7 @@ module.exports = Self => {
|
||||||
const myOptions = {};
|
const myOptions = {};
|
||||||
let tx;
|
let tx;
|
||||||
|
|
||||||
if (typeof options == 'object')
|
if (typeof options === 'object')
|
||||||
Object.assign(myOptions, options);
|
Object.assign(myOptions, options);
|
||||||
|
|
||||||
if (!myOptions.transaction) {
|
if (!myOptions.transaction) {
|
||||||
|
@ -39,7 +43,7 @@ module.exports = Self => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const userId = ctx.req.accessToken.userId;
|
const userId = ctx.req.accessToken.userId;
|
||||||
const worker = await Self.app.models.Worker.findOne({where: {id: userId}}, myOptions);
|
const worker = await models.Worker.findById(userId, {fields: ['id']}, myOptions);
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
isOk: false,
|
isOk: false,
|
||||||
|
@ -47,19 +51,32 @@ module.exports = Self => {
|
||||||
response: ctx.args.observation,
|
response: ctx.args.observation,
|
||||||
};
|
};
|
||||||
|
|
||||||
const request = await Self.app.models.TicketRequest.findById(ctx.args.id, null, myOptions);
|
const request = await models.TicketRequest.findById(ctx.args.id, {
|
||||||
await request.updateAttributes(params, myOptions);
|
include: {
|
||||||
|
relation: 'ticket',
|
||||||
|
scope: {
|
||||||
|
include: {
|
||||||
|
relation: 'client',
|
||||||
|
scope: {
|
||||||
|
fields: ['id', 'name', 'salesPersonFk']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, myOptions);
|
||||||
|
|
||||||
const url = await Self.app.models.Url.getUrl();
|
const salesPerson = request.ticket().client().salesPersonFk;
|
||||||
const requesterId = request.requesterFk;
|
if (salesPerson) {
|
||||||
|
const url = await models.Url.getUrl();
|
||||||
|
const message = $t('Deny buy request', {
|
||||||
|
ticketId: request.ticketFk,
|
||||||
|
url: `${url}ticket/${request.ticketFk}/request/index`,
|
||||||
|
observation: params.response
|
||||||
|
});
|
||||||
|
|
||||||
const message = $t('Deny buy request', {
|
await models.Chat.sendCheckingPresence(ctx, salesPerson, message, myOptions);
|
||||||
ticketId: request.ticketFk,
|
await request.updateAttributes(params, myOptions);
|
||||||
url: `${url}ticket/${request.ticketFk}/request/index`,
|
}
|
||||||
observation: params.response
|
|
||||||
});
|
|
||||||
|
|
||||||
await models.Chat.sendCheckingPresence(ctx, requesterId, message, myOptions);
|
|
||||||
|
|
||||||
if (tx) await tx.commit();
|
if (tx) await tx.commit();
|
||||||
|
|
||||||
|
|
|
@ -128,7 +128,10 @@ module.exports = Self => {
|
||||||
const account = await models.VnUser.findById(userId, null, myOptions);
|
const account = await models.VnUser.findById(userId, null, myOptions);
|
||||||
const subordinated = await models.VnUser.findById(id, null, myOptions);
|
const subordinated = await models.VnUser.findById(id, null, myOptions);
|
||||||
const worker = await models.Worker.findById(subordinated.id, null, myOptions);
|
const worker = await models.Worker.findById(subordinated.id, null, myOptions);
|
||||||
const departmentBoss = await models.VnUser.findById(worker.bossFk, null, myOptions);
|
const receiver = await models.EmailUser.findOne({
|
||||||
|
fields: ['email'],
|
||||||
|
where: {userFk: worker.bossFk}
|
||||||
|
}, myOptions);
|
||||||
const url = await Self.app.models.Url.getUrl();
|
const url = await Self.app.models.Url.getUrl();
|
||||||
const body = $t('Created absence', {
|
const body = $t('Created absence', {
|
||||||
author: account.nickname,
|
author: account.nickname,
|
||||||
|
@ -140,7 +143,7 @@ module.exports = Self => {
|
||||||
await models.Mail.create({
|
await models.Mail.create({
|
||||||
subject: $t('Absence change notification on the labour calendar'),
|
subject: $t('Absence change notification on the labour calendar'),
|
||||||
body: body,
|
body: body,
|
||||||
receiver: departmentBoss.email
|
receiver: receiver.email
|
||||||
}, myOptions);
|
}, myOptions);
|
||||||
|
|
||||||
if (tx) await tx.commit();
|
if (tx) await tx.commit();
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
"userFk": {
|
"userFk": {
|
||||||
"type": "number"
|
"type": "number"
|
||||||
},
|
},
|
||||||
"simSerialNumber": {
|
"simFk": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"created": {
|
"created": {
|
||||||
|
|
|
@ -51,7 +51,7 @@ module.exports = Self => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const ticketList = await models.Ticket.find(filter, myOptions);
|
const ticketList = await models.Ticket.find(filter, myOptions);
|
||||||
const hasRefFk = ticketList.some(ticket => ticket.refFk);
|
const hasRefFk = ticketList.some(ticket => !ticket.refFk);
|
||||||
if (hasRefFk)
|
if (hasRefFk)
|
||||||
throw new UserError('There are tickets to be invoiced');
|
throw new UserError('There are tickets to be invoiced');
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,9 @@
|
||||||
{
|
{
|
||||||
"name": "Zone",
|
"name": "Zone",
|
||||||
"base": "VnModel",
|
"base": "VnModel",
|
||||||
"mixins": {
|
"mixins": {
|
||||||
"Loggable": true
|
"Loggable": true
|
||||||
},
|
},
|
||||||
"options": {
|
"options": {
|
||||||
"mysql": {
|
"mysql": {
|
||||||
"table": "zone"
|
"table": "zone"
|
||||||
|
@ -48,30 +48,35 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"relations": {
|
"relations": {
|
||||||
"agencyMode": {
|
"agencyMode": {
|
||||||
"type": "belongsTo",
|
"type": "belongsTo",
|
||||||
"model": "AgencyMode",
|
"model": "AgencyMode",
|
||||||
"foreignKey": "agencyModeFk"
|
"foreignKey": "agencyModeFk"
|
||||||
},
|
},
|
||||||
"events": {
|
"events": {
|
||||||
"type": "hasMany",
|
"type": "hasMany",
|
||||||
"model": "ZoneEvent",
|
"model": "ZoneEvent",
|
||||||
"foreignKey": "zoneFk"
|
"foreignKey": "zoneFk"
|
||||||
},
|
},
|
||||||
"exclusions": {
|
"exclusions": {
|
||||||
"type": "hasMany",
|
"type": "hasMany",
|
||||||
"model": "ZoneExclusion",
|
"model": "ZoneExclusion",
|
||||||
"foreignKey": "zoneFk"
|
"foreignKey": "zoneFk"
|
||||||
},
|
},
|
||||||
"warehouses": {
|
"warehouses": {
|
||||||
"type": "hasMany",
|
"type": "hasMany",
|
||||||
"model": "ZoneWarehouse",
|
"model": "ZoneWarehouse",
|
||||||
"foreignKey": "zoneFk"
|
"foreignKey": "zoneFk"
|
||||||
},
|
},
|
||||||
"closures": {
|
"closures": {
|
||||||
"type": "hasMany",
|
"type": "hasMany",
|
||||||
"model": "ZoneClosure",
|
"model": "ZoneClosure",
|
||||||
"foreignKey": "zoneFk"
|
"foreignKey": "zoneFk"
|
||||||
}
|
},
|
||||||
}
|
"address": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "Address",
|
||||||
|
"foreignKey": "addressFk"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue