diff --git a/back/methods/osrm-config/optimize.js b/back/methods/osrm-config/optimize.js new file mode 100644 index 000000000..e0412c74c --- /dev/null +++ b/back/methods/osrm-config/optimize.js @@ -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; + } + } + }; +}; diff --git a/back/methods/osrm-config/specs/optimize.spec.js b/back/methods/osrm-config/specs/optimize.spec.js new file mode 100644 index 000000000..9f2adccc6 --- /dev/null +++ b/back/methods/osrm-config/specs/optimize.spec.js @@ -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'); + }); +}); diff --git a/back/model-config.json b/back/model-config.json index c1682f29a..2ced867f7 100644 --- a/back/model-config.json +++ b/back/model-config.json @@ -88,6 +88,9 @@ "Language": { "dataSource": "vn" }, + "OsrmConfig": { + "dataSource": "vn" + }, "Machine": { "dataSource": "vn" }, diff --git a/back/models/osrm-config.js b/back/models/osrm-config.js new file mode 100644 index 000000000..f738f305c --- /dev/null +++ b/back/models/osrm-config.js @@ -0,0 +1,4 @@ +module.exports = Self => { + require('../methods/osrm-config/optimize')(Self); +}; + diff --git a/back/models/osrm-config.json b/back/models/osrm-config.json new file mode 100644 index 000000000..ae712ba05 --- /dev/null +++ b/back/models/osrm-config.json @@ -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 + } + } +} diff --git a/db/dump/fixtures.before.sql b/db/dump/fixtures.before.sql index 663705ff5..c108bc0f6 100644 --- a/db/dump/fixtures.before.sql +++ b/db/dump/fixtures.before.sql @@ -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`) VALUES - (1, 'Bruce Wayne', '1007 Mountain Drive, Gotham', 'Gotham', 46460, 1, 1111111111, 222222222, 1, 1101, 2, NULL, NULL, 0, 1), - (2, 'Petter Parker', '20 Ingram Street', 'Gotham', 46460, 1, 1111111111, 222222222, 1, 1102, 2, NULL, NULL, 0, 1), - (3, 'Clark Kent', '344 Clinton Street', 'Gotham', 46460, 1, 1111111111, 222222222, 1, 1103, 2, NULL, NULL, 0, 1), - (4, 'Tony Stark', '10880 Malibu Point', 'Gotham', 46460, 1, 1111111111, 222222222, 1 , 1104, 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, -74.2222222, 10.2222222, 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, -74.4444444, 10.4444444, 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), (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), (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), - (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), (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), @@ -1520,17 +1520,18 @@ INSERT INTO `vn`.`travel`(`id`,`shipped`, `landed`, `warehouseInFk`, `warehouseO INSERT INTO `vn`.`entry`(`id`, `supplierFk`, `created`, `travelFk`, `isConfirmed`, `companyFk`, `invoiceNumber`, `reference`, `isExcludedFromAvailable`, `evaNotes`, `typeFk`) VALUES - (1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1, 1, 442, 'IN2001', 'Movement 1', 0, '', 'packaging'), - (2, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 2, 0, 442, 'IN2002', 'Movement 2', 0, 'observation two', 'product'), + (1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1, 1, 442, 'IN2001', 'Movement 1', 0, '', 'packaging'), + (2, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 2, 0, 442, 'IN2002', 'Movement 2', 0, 'observation two' , 'product'), (3, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 3, 0, 442, 'IN2003', 'Movement 3', 0, 'observation three', 'product'), - (4, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 2, 0, 69, 'IN2004', 'Movement 4', 0, 'observation four', 'product'), - (5, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 5, 0, 442, 'IN2005', 'Movement 5', 0, 'observation five', 'product'), - (6, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 6, 0, 442, 'IN2006', 'Movement 6', 0, 'observation six', 'product'), + (4, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 2, 0, 69, 'IN2004', 'Movement 4', 0, 'observation four' , 'product'), + (5, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 5, 0, 442, 'IN2005', 'Movement 5', 0, 'observation five' , 'product'), + (6, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 6, 0, 442, 'IN2006', 'Movement 6', 0, 'observation six' , 'product'), (7, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 7, 0, 442, 'IN2007', 'Movement 7', 0, 'observation seven', 'product'), - (8, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 7, 0, 442, 'IN2008', 'Movement 8', 1, '', 'product'), - (9, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL +2 DAY), 10, 0, 442, 'IN2009', 'Movement 9', 1, '', 'product'), - (10, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL +2 DAY), 10, 0, 442, 'IN2009', 'Movement 10', 1, '', 'product'), - (99, 69, util.VN_CURDATE() - INTERVAL 1 MONTH, 11, 0, 442, 'IN2009', 'Movement 99', 0, '', 'product'); + (8, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 7, 0, 442, 'IN2008', 'Movement 8', 1, '', 'product'), + (9, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL +2 DAY), 10, 0, 442, 'IN2009', 'Movement 9', 1, '', 'product'), + (10, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL +2 DAY), 10, 0, 442, 'IN2009', 'Movement 10',1, '', 'product'), + (11, 4, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1, 1, 442, 'IN2001', 'Movement 11',0, '', 'product'), + (99, 69, util.VN_CURDATE() - INTERVAL 1 MONTH, 11, 0, 442, 'IN2009', 'Movement 99',0, '', 'product'); INSERT INTO `vn`.`entryConfig` (`defaultEntry`, `inventorySupplierFk`, `defaultSupplierFk`) VALUES (2, 4, 1); @@ -1570,7 +1571,8 @@ INSERT INTO `bs`.`waste`(`buyerFk`, `year`, `week`, `itemFk`, `itemTypeFk`, `sal (13, 7, 1, 50, 0, 3, 1, 2.000, 2.000, 0.000, 1, 1, 'packing', NULL, 0.00, 99.6, 99.4, 0, 1, 0, 4, util.VN_CURDATE()), (14, 7, 2, 5, 0, 3, 1, 2.000, 2.000, 0.000, 10, 10, 'grouping', NULL, 0.00, 7.30, 7.00, 0, 1, 0, 4, util.VN_CURDATE()), (15, 7, 4, 1.25, 0, 3, 1, 2.000, 2.000, 0.000, 10, 10, 'grouping', NULL, 0.00, 1.75, 1.67, 0, 1, 0, 4, util.VN_CURDATE()), - (16, 99,1,50.0000, 5000, 4, 1, 1.500, 1.500, 0.000, 1, 1, 'packing', NULL, 0.00, 99.60, 99.40, 0, 1, 0, 1.00, '2024-07-30 08:13:51.000'); + (16, 99,1,50.0000, 5000, 4, 1, 1.500, 1.500, 0.000, 1, 1, 'packing', NULL, 0.00, 99.60, 99.40, 0, 1, 0, 1.00, '2024-07-30 08:13:51.000'), + (17, 11, 1, 50, 5000, 4, 1, 1.500, 1.500, 0.000, 1, 1, 'packing', NULL, 0.00, 99.6, 99.4, 0, 1, 0, 1, util.VN_CURDATE() - INTERVAL 2 MONTH); INSERT INTO `hedera`.`order`(`id`, `date_send`, `customer_id`, `delivery_method_id`, `agency_id`, `address_id`, `company_id`, `note`, `source_app`, `confirmed`,`total`, `date_make`, `first_row_stamp`, `confirm_date`) VALUES @@ -4035,3 +4037,10 @@ INSERT IGNORE INTO vn.saySimpleConfig (url, defaultChannel) INSERT INTO vn.workerIrpf (workerFk,spouseNif, geographicMobilityDate) 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 + SET id = 1, + supplierFk = 4; diff --git a/db/routines/sage/procedures/invoiceIn_add.sql b/db/routines/sage/procedures/invoiceIn_add.sql index 1d411cfd0..76618ce50 100644 --- a/db/routines/sage/procedures/invoiceIn_add.sql +++ b/db/routines/sage/procedures/invoiceIn_add.sql @@ -25,7 +25,7 @@ BEGIN DECLARE vIsInformativeExportation BOOL DEFAULT FALSE; DECLARE vCursor CURSOR FOR - SELECT it.taxableBase, + SELECT SUM(it.taxableBase), CAST(SUM((( it.taxableBase / 100) * t.PorcentajeIva)) AS DECIMAL (10,2)), t.PorcentajeIva, it.transactionTypeSageFk, @@ -204,17 +204,17 @@ BEGIN FROM vn.invoiceInCorrection WHERE correctingFk = vInvoiceInFk; - IF vInvoiceInOriginalFk THEN + IF vInvoiceInOriginalFk THEN UPDATE movContaIVA mci JOIN vn.invoiceInRefund iir ON iir.invoiceInRefundFk = vInvoiceInFk JOIN (SELECT issued, - SUM(sub.taxableBase) taxableBase, + SUM(sub.taxableBase) taxableBase, SUM(ROUND((sub.taxableBase * sub.PorcentajeIva) / 100 , 2)) vat FROM(SELECT issued, - SUM(iit.taxableBase) taxableBase, + SUM(iit.taxableBase) taxableBase, ti.PorcentajeIva - FROM vn.invoiceIn i + FROM vn.invoiceIn i JOIN vn.invoiceInTax iit ON iit.invoiceInFk = i.id JOIN sage.TiposIva ti ON ti.CodigoIva = iit.taxTypeSageFk WHERE i.id = vInvoiceInOriginalFk @@ -222,7 +222,7 @@ BEGIN )invoiceInOriginal JOIN ClavesOperacion co ON co.Descripcion = 'Factura rectificativa' SET mci.TipoRectificativa = iir.refundCategoryFk, - mci.ClaseAbonoRectificativas = iir.refundType, + mci.ClaseAbonoRectificativas = iir.refundType, mci.FechaFacturaOriginal = invoiceInOriginal.issued, mci.FechaOperacion = invoiceInOriginal.issued, mci.BaseImponibleOriginal = invoiceInOriginal.taxableBase, @@ -232,4 +232,4 @@ BEGIN END IF; END$$ -DELIMITER ; \ No newline at end of file +DELIMITER ; diff --git a/db/routines/vn/procedures/claimRatio_add.sql b/db/routines/vn/procedures/claimRatio_add.sql index 8c3213644..5e2e66a8e 100644 --- a/db/routines/vn/procedures/claimRatio_add.sql +++ b/db/routines/vn/procedures/claimRatio_add.sql @@ -46,7 +46,7 @@ BEGIN JOIN claimDestination cd ON cd.id = ce.claimDestinationFk JOIN claim c ON c.id = ce.claimFk JOIN claimState cs ON cs.id = c.claimStateFk - WHERE cd.description NOT IN ('Bueno', 'Corregido') + WHERE cd.code NOT IN ('good', 'corrected', 'supplierClaim') AND NOT ce.isGreuge AND cs.code = 'resolved'; @@ -71,7 +71,7 @@ BEGIN JOIN claimDestination cd ON cd.id = ce.claimDestinationFk JOIN claim c ON c.id = ce.claimFk JOIN claimState cs ON cs.id = c.claimStateFk - WHERE cd.description NOT IN ('Bueno', 'Corregido') + WHERE cd.code NOT IN ('good', 'corrected', 'supplierClaim') AND NOT ce.isGreuge AND cs.code = 'resolved' AND c.isChargedToMana; @@ -82,7 +82,7 @@ BEGIN JOIN claim c ON c.id = ce.claimFk JOIN claimState cs ON cs.id = c.claimStateFk SET ce.isGreuge = TRUE - WHERE cd.description NOT IN ('Bueno', 'Corregido') + WHERE cd.code NOT IN ('good', 'corrected', 'supplierClaim') AND NOT ce.isGreuge AND cs.code = 'resolved'; @@ -161,7 +161,7 @@ BEGIN JOIN claimDestination cd ON cd.id = ce.claimDestinationFk JOIN claim c ON c.id = ce.claimFk JOIN claimState cs ON cs.id = c.claimStateFk - WHERE cd.description NOT IN ('Bueno', 'Corregido') + WHERE cd.code NOT IN ('good', 'corrected', 'supplierClaim') AND cs.code = 'resolved' AND c.ticketCreated >= util.VN_CURDATE() - INTERVAL 1 YEAR GROUP BY c.clientFk diff --git a/db/routines/vn/procedures/travel_checkRaid.sql b/db/routines/vn/procedures/travel_checkRaid.sql index 64f3355e2..885fc718a 100644 --- a/db/routines/vn/procedures/travel_checkRaid.sql +++ b/db/routines/vn/procedures/travel_checkRaid.sql @@ -10,8 +10,8 @@ BEGIN * @param vIsRaid idRaid value * @param vDaysInForward daysInForward value */ - IF (NOT vIsRaid AND vDaysInForward IS NOT NULL) OR (vIsRaid AND vDaysInForward IS NULL) THEN - CALL util.throw('The raid information is not correct'); + IF NOT vIsRaid AND vDaysInForward THEN + CALL util.throw('If daysInForward has a value, the raid cannot be unchecked'); END IF; END$$ DELIMITER ; diff --git a/db/routines/vn/procedures/travel_moveRaids.sql b/db/routines/vn/procedures/travel_moveRaids.sql index cf0fce23c..17d7ecc4c 100644 --- a/db/routines/vn/procedures/travel_moveRaids.sql +++ b/db/routines/vn/procedures/travel_moveRaids.sql @@ -8,22 +8,15 @@ BEGIN DECLARE vDone BOOL DEFAULT FALSE; DECLARE vBuyerEmail VARCHAR(40); DECLARE vTravelLink TEXT; - DECLARE vMailBody TEXT DEFAULT ''; + DECLARE vMailBody TEXT; + DECLARE vDaysBetweenDates INT; + DECLARE vSubject VARCHAR(30); - DECLARE vCur CURSOR FOR - SELECT GROUP_CONCAT(DISTINCT - CONCAT('https://salix.verdnatura.es/#!/travel/', - ttm.travelFk, - '/summary ') - ORDER BY ttm.travelFk SEPARATOR '\n\r') travelLink, - CONCAT(u.name, '@verdnatura.es') buyerEmail - FROM tTravelToMove ttm - JOIN entry e ON e.travelFk = ttm.travelFk - JOIN buy b ON b.entryFk = e.id - JOIN item i ON i.id = b.itemFk - JOIN itemType it ON it.id = i.typeFk - JOIN account.user u ON u.id = it.workerFk - GROUP BY u.name; + DECLARE vTravels CURSOR FOR + SELECT GROUP_CONCAT(DISTINCT travelLink ORDER BY id SEPARATOR '\n\r'), + buyerEmail + FROM tTravelToMove + GROUP BY buyerEmail; DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE; @@ -34,35 +27,50 @@ BEGIN END; CREATE OR REPLACE TEMPORARY TABLE tTravelToMove - SELECT id travelFk, - util.VN_CURDATE() + INTERVAL daysInForward DAY newLanded - FROM travel + WITH travels AS ( + SELECT id, + CONCAT('https://salix.verdnatura.es/#!/travel/', id,'/summary') travelLink, + util.VN_CURDATE() + INTERVAL daysInForward DAY newLanded, + util.VN_CURDATE() - INTERVAL DATEDIFF(landed, shipped) + daysInForward DAY newShipped + FROM vn.travel WHERE isRaid - AND daysInForward; + AND daysInForward + )SELECT t.id, + t.travelLink, + t.newLanded, + t.newShipped, + CONCAT(u.name, '@verdnatura.es') buyerEmail + FROM travels t + STRAIGHT_JOIN vn.entry e ON e.travelFk = t.id + JOIN vn.buy b ON b.entryFk = e.id + JOIN vn.item i ON i.id = b.itemFk + JOIN vn.itemType it ON it.id = i.typeFk + JOIN account.user u ON u.id = it.workerFk + GROUP BY t.id; START TRANSACTION; UPDATE travel tr - JOIN tTravelToMove ttm ON ttm.travelFk = tr.id - SET tr.landed = ttm.newLanded; + JOIN tTravelToMove ttm ON ttm.id = tr.id + SET tr.landed = ttm.newLanded, + tr.shipped = ttm.newShipped; - OPEN vCur; + OPEN vTravels; l: LOOP SET vDone = FALSE; - FETCH vCur INTO vTravelLink, vBuyerEmail; + FETCH vTravels INTO vTravelLink, vBuyerEmail; IF vDone THEN LEAVE l; END IF; - CALL `vn`.`mail_insert`( - vBuyerEmail, - 'noreply@verdnatura.es', - 'Cambio de fecha en Redadas', - CONCAT('Se ha movido los siguientes travels: \n\r ', vTravelLink)); + SET vSubject = 'Cambio de fecha en Redadas', + vMailBody = CONCAT('Se ha movido los siguientes travels: \n\r ', vTravelLink); + + CALL mail_insert(vBuyerEmail, 'noreply@verdnatura.es', vSubject, vMailBody); END LOOP; - CLOSE vCur; + CLOSE vTravels; COMMIT; DROP TEMPORARY TABLE tTravelToMove; END$$ diff --git a/db/routines/vn/triggers/travel_beforeUpdate.sql b/db/routines/vn/triggers/travel_beforeUpdate.sql index 256dd35f8..5a27b43b4 100644 --- a/db/routines/vn/triggers/travel_beforeUpdate.sql +++ b/db/routines/vn/triggers/travel_beforeUpdate.sql @@ -20,6 +20,10 @@ BEGIN CALL travel_checkWarehouseIsFeedStock(NEW.warehouseInFk); END IF; + IF NOT (NEW.isRaid <=> OLD.isRaid) OR NOT (NEW.daysInForward <=> OLD.daysInForward) THEN + CALL travel_checkRaid(NEW.isRaid, NEW.daysInForward); + END IF; + IF NOT (NEW.awbFk <=> OLD.awbFk)THEN SELECT COUNT(*) INTO vHasAnyInvoiceBooked FROM travel t diff --git a/db/versions/11327-maroonOak/00-firstScript.sql b/db/versions/11327-maroonOak/00-firstScript.sql new file mode 100644 index 000000000..7c9d8e6e8 --- /dev/null +++ b/db/versions/11327-maroonOak/00-firstScript.sql @@ -0,0 +1,183 @@ +CREATE TABLE IF NOT EXISTS `vn`.`sim` ( + `id` BIGINT UNSIGNED, + `line` VARCHAR(15) NOT NULL CHECK (`line` REGEXP '^[0-9]+$'), + `ext` INT(4) NOT NULL, + `pin` INT(4) NOT NULL, + `puk` INT(15) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci; + +ALTER TABLE vn.deviceProductionUser CHANGE simSerialNumber simFk BIGINT unsigned DEFAULT NULL NULL; +ALTER TABLE vn.deviceProductionUser MODIFY COLUMN simFk BIGINT unsigned DEFAULT NULL NULL; + +INSERT IGNORE INTO `vn`.`sim` (`line`, `ext`, `pin`, `id`, `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.id = dpu.simFk + WHERE s.id IS NULL + AND dpu.simFk IS NOT NULL + ); + +ALTER TABLE vn.deviceProductionUser ADD CONSTRAINT deviceProductionUser_sim_FK + FOREIGN KEY (simFk) REFERENCES vn.sim(id) ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/db/versions/11352-blackErica/00-firstScript.sql b/db/versions/11352-blackErica/00-firstScript.sql new file mode 100644 index 000000000..659f50161 --- /dev/null +++ b/db/versions/11352-blackErica/00-firstScript.sql @@ -0,0 +1,3 @@ +-- Place your SQL code here +INSERT IGNORE INTO salix.ACL (model, property, accessType, permission, principalType, principalId) + VALUES('InventoryConfig', 'find', 'READ', 'ALLOW', 'ROLE', 'buyer'); \ No newline at end of file diff --git a/db/versions/11379-yellowCordyline/00-firstScript.sql b/db/versions/11379-yellowCordyline/00-firstScript.sql new file mode 100644 index 000000000..8d90ee90c --- /dev/null +++ b/db/versions/11379-yellowCordyline/00-firstScript.sql @@ -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; diff --git a/loopback/locale/es.json b/loopback/locale/es.json index d7fcb8805..73efce216 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -391,9 +391,14 @@ "Sales already moved": "Ya han sido transferidas", "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", - "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", - "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", "Worker not found": "Trabajador no encontrado", "Invalid request or related ticket/client data": "Solicitud no válida o datos de ticket/cliente relacionados" diff --git a/modules/client/back/methods/client/updateAddress.js b/modules/client/back/methods/client/updateAddress.js index 7342b28f1..efef83d6b 100644 --- a/modules/client/back/methods/client/updateAddress.js +++ b/modules/client/back/methods/client/updateAddress.js @@ -72,6 +72,14 @@ module.exports = function(Self) { { arg: 'isLogifloraAllowed', type: 'boolean' + }, + { + arg: 'longitude', + type: 'any', + }, + { + arg: 'latitude', + type: 'any', } ], returns: { diff --git a/modules/entry/back/methods/entry/specs/filter.spec.js b/modules/entry/back/methods/entry/specs/filter.spec.js index 4bf5127b0..b139b00b6 100644 --- a/modules/entry/back/methods/entry/specs/filter.spec.js +++ b/modules/entry/back/methods/entry/specs/filter.spec.js @@ -38,8 +38,9 @@ describe('Entry filter()', () => { }; const result = await models.Entry.filter(ctx, options); + const resultWithCurrency = result.filter(entry => entry.currencyFk === 1); - expect(result.length).toEqual(12); + expect(result.length).toEqual(resultWithCurrency.length); await tx.rollback(); } catch (e) { @@ -141,18 +142,21 @@ describe('Entry filter()', () => { it('should return the entry matching the company', async() => { const tx = await models.Entry.beginTransaction({}); const options = {transaction: tx}; + const companyFk = 442; try { const ctx = { args: { - companyFk: 442 + companyFk }, req: {accessToken: {userId: 9}} }; const result = await models.Entry.filter(ctx, options); - expect(result.length).toEqual(11); + const resultWithCurrency = result.filter(entry => entry.companyFk === companyFk); + + expect(result.length).toEqual(resultWithCurrency.length); await tx.rollback(); } catch (e) { diff --git a/modules/entry/back/model-config.json b/modules/entry/back/model-config.json index 5c45b6e07..49c2df2db 100644 --- a/modules/entry/back/model-config.json +++ b/modules/entry/back/model-config.json @@ -28,5 +28,8 @@ }, "StockBought": { "dataSource": "vn" + }, + "InventoryConfig": { + "dataSource": "vn" } } diff --git a/modules/entry/back/models/inventory-config.json b/modules/entry/back/models/inventory-config.json new file mode 100644 index 000000000..caa39db88 --- /dev/null +++ b/modules/entry/back/models/inventory-config.json @@ -0,0 +1,18 @@ +{ + "name": "InventoryConfig", + "base": "VnModel", + "options": { + "mysql": { + "table": "inventoryConfig" + } + }, + "properties": { + "id": { + "type": "number", + "id": true + }, + "supplierFk": { + "type": "number" + } + } +} diff --git a/modules/item/back/methods/item/lastEntriesFilter.js b/modules/item/back/methods/item/lastEntriesFilter.js index 5aafbb4f6..06c60162f 100644 --- a/modules/item/back/methods/item/lastEntriesFilter.js +++ b/modules/item/back/methods/item/lastEntriesFilter.js @@ -54,7 +54,8 @@ module.exports = Self => { b.packageValue, b.packagingFk , s.id AS supplierFk, - s.name AS supplier + s.name AS supplier, + b.printedStickers FROM itemType it RIGHT JOIN (entry e LEFT JOIN supplier s ON s.id = e.supplierFk diff --git a/modules/item/back/methods/item/specs/lastEntriesFilter.spec.js b/modules/item/back/methods/item/specs/lastEntriesFilter.spec.js index 2fd30c2ca..d4429e158 100644 --- a/modules/item/back/methods/item/specs/lastEntriesFilter.spec.js +++ b/modules/item/back/methods/item/specs/lastEntriesFilter.spec.js @@ -34,10 +34,31 @@ describe('item lastEntriesFilter()', () => { const options = {transaction: tx}; try { - const filter = {where: {itemFk: 1, landed: {between: [minDate, maxDate]}}}; + const itemFk = 1; + const filter = {where: {itemFk, landed: {between: [minDate, maxDate]}}}; const result = await models.Item.lastEntriesFilter(filter, options); + const minDateUtc = new Date(minDate).getTime(); + const maxDateUtc = new Date(maxDate).getTime(); - expect(result.length).toEqual(6); + const resultMatch = ( + await Promise.all( + result.map(async item => { + const itemRecord = await models.Buy.findOne({ + fields: ['id'], + where: {id: item.id}, + options, + }); + + const isItemFkValid = itemRecord?.id === itemFk; + const landedDate = new Date(item.landed).getTime(); + const isLandedValid = landedDate >= minDateUtc && landedDate <= maxDateUtc; + + return isItemFkValid && isLandedValid; + }) + ) + ).filter(Boolean).length; + + expect(result.length).toEqual(resultMatch); await tx.rollback(); } catch (e) { diff --git a/modules/route/back/methods/route/optimizePriority.js b/modules/route/back/methods/route/optimizePriority.js new file mode 100644 index 000000000..56db4ffb5 --- /dev/null +++ b/modules/route/back/methods/route/optimizePriority.js @@ -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; + } + }; +}; diff --git a/modules/route/back/methods/route/specs/optimizePriority.spec.js b/modules/route/back/methods/route/specs/optimizePriority.spec.js new file mode 100644 index 000000000..c1c2dc45e --- /dev/null +++ b/modules/route/back/methods/route/specs/optimizePriority.spec.js @@ -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'); + }); +}); diff --git a/modules/route/back/models/route.js b/modules/route/back/models/route.js index cd8685cec..f73ff3e51 100644 --- a/modules/route/back/models/route.js +++ b/modules/route/back/models/route.js @@ -16,4 +16,5 @@ module.exports = Self => { require('../methods/route/downloadZip')(Self); require('../methods/route/getExpeditionSummary')(Self); require('../methods/route/getByWorker')(Self); + require('../methods/route/optimizePriority')(Self); }; diff --git a/modules/ticket/back/methods/expedition/filter.js b/modules/ticket/back/methods/expedition/filter.js index 43be14349..bd2012668 100644 --- a/modules/ticket/back/methods/expedition/filter.js +++ b/modules/ticket/back/methods/expedition/filter.js @@ -49,7 +49,8 @@ module.exports = Self => { es.workerFk expeditionScanWorkerFk, su.name scannerUserName, es.scanned, - est.description state + est.description state, + de.longName FROM vn.expedition e LEFT JOIN vn.expeditionStateType est ON est.id = e.stateTypeFk INNER JOIN vn.item i1 ON i1.id = e.freightItemFk @@ -59,6 +60,7 @@ module.exports = Self => { LEFT JOIN account.user u ON u.id = e.workerFk LEFT JOIN vn.expeditionScan es ON es.expeditionFk = e.id LEFT JOIN account.user su ON su.id = es.workerFk + LEFT JOIN dipole.expedition_PrintOut de ON de.expeditionFk = e.id ) e `); stmt.merge(conn.makeWhere(filter.where)); diff --git a/modules/ticket/back/methods/sale/updateQuantity.js b/modules/ticket/back/methods/sale/updateQuantity.js index 36d75ffed..4de1bcbd6 100644 --- a/modules/ticket/back/methods/sale/updateQuantity.js +++ b/modules/ticket/back/methods/sale/updateQuantity.js @@ -82,7 +82,7 @@ module.exports = Self => { const message = $t('Changed sale quantity', { ticketId: sale.ticket().id, - changes: change, + changes: JSON.stringify(change), ticketUrl: `${url}ticket/${sale.ticket().id}/sale`, }); diff --git a/modules/ticket/back/methods/ticket-request/filter.js b/modules/ticket/back/methods/ticket-request/filter.js index 53f90b98f..c2edcae81 100644 --- a/modules/ticket/back/methods/ticket-request/filter.js +++ b/modules/ticket/back/methods/ticket-request/filter.js @@ -64,6 +64,11 @@ module.exports = Self => { arg: 'myTeam', type: 'boolean', description: `Team partners` + }, + { + arg: 'daysOnward', + type: 'number', + description: 'The days onward' } ], returns: { @@ -104,6 +109,9 @@ module.exports = Self => { teamMembersId.push(userId); } + const today = Date.vnNew(); + const future = Date.vnNew(); + let where = buildFilter(ctx.args, (param, value) => { switch (param) { case 'search': @@ -140,9 +148,13 @@ module.exports = Self => { return {'tr.requesterFk': {inq: teamMembersId}}; else return {'tr.requesterFk': {nin: teamMembersId}}; + case 'daysOnward': + today.setHours(0, 0, 0, 0); + future.setDate(today.getDate() + value); + future.setHours(23, 59, 59, 999); + return {'t.shipped': {between: [today, future]}}; } }); - if (!where) where = {}; where['tw.ticketFk'] = null; diff --git a/modules/travel/back/methods/travel/specs/getEntries.spec.js b/modules/travel/back/methods/travel/specs/getEntries.spec.js index fcaa80d02..9286a9d55 100644 --- a/modules/travel/back/methods/travel/specs/getEntries.spec.js +++ b/modules/travel/back/methods/travel/specs/getEntries.spec.js @@ -3,9 +3,10 @@ const models = require('vn-loopback/server/server').models; describe('travel getEntries()', () => { const travelId = 1; it('should check the response contains the id', async() => { - const entries = await models.Travel.getEntries(travelId); + const result = await models.Travel.getEntries(travelId); + const entries = await models.Entry.find({where: {travelFk: travelId}}); - expect(entries.length).toEqual(1); + expect(entries.length).toEqual(result.length); expect(entries[0].id).toEqual(1); }); diff --git a/modules/worker/back/models/worker-irpf.json b/modules/worker/back/models/worker-irpf.json index 65f72a1fd..eafda0596 100644 --- a/modules/worker/back/models/worker-irpf.json +++ b/modules/worker/back/models/worker-irpf.json @@ -23,7 +23,7 @@ "type" : "number" }, "isDependend": { - "type" : "number" + "type" : "boolean" }, "familySituation": { "type" : "number" @@ -35,15 +35,17 @@ "type" : "number" }, "hasHousingPaymentBefore": { - "type" : "number" + "type" : "boolean" }, "hasHousingPaymentAfter": { - "type" : "number" + "type" : "boolean" }, "updated": { "type" : "date" + }, + "hasExtendedWorking": { + "type" : "boolean" } - }, "relations": { "disabilityGrade": { diff --git a/modules/zone/back/model-config.json b/modules/zone/back/model-config.json index 3bbbe0d1b..2cd3f9d01 100644 --- a/modules/zone/back/model-config.json +++ b/modules/zone/back/model-config.json @@ -17,6 +17,9 @@ "ZoneClosure": { "dataSource": "vn" }, + "ZoneConfig": { + "dataSource": "vn" + }, "ZoneEvent": { "dataSource": "vn" }, diff --git a/modules/zone/back/models/zone-config.json b/modules/zone/back/models/zone-config.json new file mode 100644 index 000000000..a5da7fe55 --- /dev/null +++ b/modules/zone/back/models/zone-config.json @@ -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" + } + } +} diff --git a/modules/zone/back/models/zone.json b/modules/zone/back/models/zone.json index 5b25e40d1..141b28750 100644 --- a/modules/zone/back/models/zone.json +++ b/modules/zone/back/models/zone.json @@ -1,9 +1,9 @@ { "name": "Zone", "base": "VnModel", - "mixins": { - "Loggable": true - }, + "mixins": { + "Loggable": true + }, "options": { "mysql": { "table": "zone" @@ -48,30 +48,35 @@ } }, "relations": { - "agencyMode": { - "type": "belongsTo", - "model": "AgencyMode", - "foreignKey": "agencyModeFk" + "agencyMode": { + "type": "belongsTo", + "model": "AgencyMode", + "foreignKey": "agencyModeFk" }, "events": { - "type": "hasMany", - "model": "ZoneEvent", - "foreignKey": "zoneFk" - }, + "type": "hasMany", + "model": "ZoneEvent", + "foreignKey": "zoneFk" + }, "exclusions": { - "type": "hasMany", - "model": "ZoneExclusion", + "type": "hasMany", + "model": "ZoneExclusion", "foreignKey": "zoneFk" }, "warehouses": { "type": "hasMany", "model": "ZoneWarehouse", "foreignKey": "zoneFk" - }, + }, "closures": { "type": "hasMany", "model": "ZoneClosure", "foreignKey": "zoneFk" - } - } + }, + "address": { + "type": "belongsTo", + "model": "Address", + "foreignKey": "addressFk" + } + } }