diff --git a/back/methods/quadminds-api-config/sendOrders.js b/back/methods/quadminds-api-config/sendOrders.js
new file mode 100644
index 000000000..760d622b6
--- /dev/null
+++ b/back/methods/quadminds-api-config/sendOrders.js
@@ -0,0 +1,88 @@
+const axios = require('axios');
+const UserError = require('vn-loopback/util/user-error');
+const moment = require('moment');
+
+module.exports = Self => {
+ Self.remoteMethod('sendOrders', {
+ description: 'Sends a set of orders',
+ accessType: 'WRITE',
+ accepts: [{
+ arg: 'tickets',
+ type: ['number'],
+ required: true
+ }
+ ],
+ returns: {
+ type: 'string',
+ root: true
+ },
+ http: {
+ path: `/sendOrders`,
+ verb: 'POST'
+ }
+ });
+ Self.sendOrders = async tickets => {
+ const config = await Self.app.models.QuadmindsApiConfig.findOne();
+ if (!config) throw new UserError('Config params not set');
+
+ if (tickets.length > config.maxObjects)
+ throw new UserError(`Quadminds does not support more than ${config.maxObjects} tickets`);
+
+ let poisData = [];
+ let isOk;
+ for (let offset = 0; !isOk; offset = offset + config.limit) {
+ const pois = await axios.get(`${config.url}pois/search?limit=${config.limit}&offset=${offset}`, {
+ headers: {
+ 'Accept': 'application/json',
+ 'X-Saas-Apikey': config.key
+ }
+ });
+ pois.data.data.length ? poisData.push(...pois.data.data) : isOk = true;
+ }
+
+ const poiMap = new Map(poisData.map(poi => [poi.code, poi._id]));
+
+ let orders = await Self.rawSql(`
+ SELECT a.id poiCode,
+ t.id code,
+ t.shipped date,
+ 'PEDIDO' operation,
+ t.totalWithVat totalAmount,
+ t.totalWithoutVat totalAmountWithoutTaxes,
+ SUM(sv.volume) volume
+ FROM ticket t
+ JOIN address a ON a.id = t.addressFk
+ JOIN saleVolume sv ON sv.ticketFk = t.id
+ WHERE t.id IN (?)
+ GROUP BY t.id
+ `, [tickets]);
+
+ // Transformo code en string ya que lo obtenermos como integer
+ orders = orders.map(order => {
+ return {
+ ...order,
+ poiId: poiMap.get(order.poiCode.toString()) || undefined,
+ code: order.code.toString(),
+ date: moment(order.date).format('YYYY-MM-DD'),
+ totalAmount: order.totalAmount || undefined,
+ totalAmountWithoutTaxes: order.totalAmountWithoutTaxes || undefined,
+ timeWindow: [{
+ from: config.orderTimeFrom,
+ to: config.orderTimeTo
+ }],
+ orderMeasures: [{
+ constraintId: 3, // Volumen
+ value: order.volume
+ }]
+ };
+ });
+
+ await axios.post(`${config.url}orders`, orders, {
+ headers: {
+ 'Accept': 'application/json',
+ 'Content-Type': 'application/json',
+ 'X-Saas-Apikey': config.key
+ }
+ });
+ };
+};
diff --git a/back/methods/quadminds-api-config/sendPois.js b/back/methods/quadminds-api-config/sendPois.js
new file mode 100644
index 000000000..cb5eef93e
--- /dev/null
+++ b/back/methods/quadminds-api-config/sendPois.js
@@ -0,0 +1,87 @@
+const axios = require('axios');
+const UserError = require('vn-loopback/util/user-error');
+
+module.exports = Self => {
+ Self.remoteMethod('sendPois', {
+ description: 'Sends a set of pois',
+ accessType: 'WRITE',
+ accepts: [{
+ arg: 'tickets',
+ type: ['number'],
+ required: true
+ }
+ ],
+ returns: {
+ type: 'string',
+ root: true
+ },
+ http: {
+ path: `/sendPois`,
+ verb: 'POST'
+ }
+ });
+ Self.sendPois = async tickets => {
+ const config = await Self.app.models.QuadmindsApiConfig.findOne();
+ if (!config) throw new UserError('Config params not set');
+
+ if (tickets.length > config.maxObjects)
+ throw new UserError(`Quadminds does not support more than ${config.maxObjects} tickets`);
+
+ let pois = await Self.rawSql(`
+ WITH deliveryNotes AS (
+ SELECT t.id, t.routeFk, tn.description
+ FROM ticket t
+ JOIN ticketObservation tn ON tn.ticketFk = t.id
+ JOIN observationType ot ON ot.id = tn.observationTypeFk
+ WHERE ot.code = 'delivery'
+ )
+ SELECT a.id code,
+ c.socialName name,
+ IF(ABS(a.latitude - ROUND(a.latitude)) < 0.000001, NULL, a.latitude) latitude,
+ IF(ABS(a.longitude - ROUND(a.longitude)) < 0.000001, NULL, a.longitude) longitude,
+ a.street,
+ a.city locality,
+ p.name state,
+ co.name country,
+ CONCAT_WS(', ', IFNULL(a.street, ''), IFNULL(a.city, ''), IFNULL(p.name, '')) longAddress,
+ CONCAT(IFNULL(a.mobile, c.mobile)) phoneNumber,
+ dn.description poiDeliveryComments,
+ c.email email
+ FROM ticket t
+ JOIN address a ON a.id = t.addressFk
+ JOIN province p ON p.id = a.provinceFk
+ JOIN country co ON co.id = p.countryFk
+ JOIN client c ON c.id = t.clientFk
+ LEFT JOIN deliveryNotes dn ON dn.id = t.id
+ WHERE t.id IN (?)
+ GROUP BY t.id
+ `, [tickets]);
+
+ // Transformo code en string ya que lo obtenermos como integer
+ pois = pois.map(poi => {
+ return {
+ ...poi,
+ code: poi.code.toString(),
+ latitude: poi.latitude || undefined,
+ longitude: poi.longitude || undefined,
+ address: {
+ street: poi.street || undefined,
+ locality: poi.locality || undefined,
+ state: poi.state || undefined,
+ country: poi.country || undefined
+ },
+ poiDeliveryComments: poi.poiDeliveryComments || undefined,
+ phoneNumber: poi.phoneNumber || undefined,
+ email: poi.email || undefined
+ };
+ });
+
+ await axios.post(`${config.url}pois`, pois, {
+ headers: {
+ 'Accept': 'application/json',
+ 'Content-Type': 'application/json',
+ 'X-Saas-Apikey': config.key
+ }
+ });
+ };
+};
diff --git a/back/model-config.json b/back/model-config.json
index 07ce5fe88..20bfb06bd 100644
--- a/back/model-config.json
+++ b/back/model-config.json
@@ -124,6 +124,9 @@
"Province": {
"dataSource": "vn"
},
+ "QuadmindsApiConfig": {
+ "dataSource": "vn"
+ },
"Autonomy": {
"dataSource": "vn"
},
diff --git a/back/models/quadminds-api-config.js b/back/models/quadminds-api-config.js
new file mode 100644
index 000000000..c2773fa0b
--- /dev/null
+++ b/back/models/quadminds-api-config.js
@@ -0,0 +1,4 @@
+module.exports = Self => {
+ require('../methods/quadminds-api-config/sendPois')(Self);
+ require('../methods/quadminds-api-config/sendOrders')(Self);
+};
diff --git a/back/models/quadminds-api-config.json b/back/models/quadminds-api-config.json
new file mode 100644
index 000000000..4213699a9
--- /dev/null
+++ b/back/models/quadminds-api-config.json
@@ -0,0 +1,28 @@
+{
+ "name": "QuadmindsApiConfig",
+ "base": "VnModel",
+ "options": {
+ "mysql": {
+ "table": "quadmindsApiConfig"
+ }
+ },
+ "properties": {
+ "id": {
+ "type": "number",
+ "id": true,
+ "required": true
+ },
+ "url": {
+ "type": "string"
+ },
+ "key": {
+ "type": "string"
+ },
+ "maxObjects": {
+ "type": "number"
+ },
+ "limit": {
+ "type": "number"
+ }
+ }
+}
diff --git a/db/dump/fixtures.before.sql b/db/dump/fixtures.before.sql
index ea689c609..6992dd6f8 100644
--- a/db/dump/fixtures.before.sql
+++ b/db/dump/fixtures.before.sql
@@ -3180,7 +3180,7 @@ UPDATE vn.department
SET workerFk = null;
INSERT INTO vn.packaging
- VALUES('--', 2745600.00, 100.00, 120.00, 220.00, 0.00, 1, '2001-01-01 00:00:00.000', NULL, NULL, NULL, 0.00, 16, 0.00, 0, NULL, 0.00, NULL, NULL, 0, NULL, 0, 0);
+ VALUES('--', 2745600.00, 100.00, 120.00, 220.00, 0.00, 1, '2001-01-01 00:00:00.000', NULL, NULL, NULL, 0.00, 16, 0.00, 0, NULL, 0.00, NULL, NULL, 0, NULL, 0, 0,0);
INSERT IGNORE INTO vn.intrastat
diff --git a/db/routines/vn/procedures/collection_new.sql b/db/routines/vn/procedures/collection_new.sql
index 41f1a1028..6a15ce73c 100644
--- a/db/routines/vn/procedures/collection_new.sql
+++ b/db/routines/vn/procedures/collection_new.sql
@@ -1,8 +1,5 @@
DELIMITER $$
-CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`collection_new`(
- vUserFk INT,
- OUT vCollectionFk INT
-)
+CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`collection_new`(vUserFk INT, OUT vCollectionFk INT)
BEGIN
/**
* Genera colecciones de tickets sin asignar trabajador.
@@ -15,29 +12,30 @@ BEGIN
DECLARE vLinesLimit INT;
DECLARE vTicketLines INT;
DECLARE vVolumeLimit DECIMAL;
- DECLARE vSizeLimit INT;
DECLARE vTicketVolume DECIMAL;
+ DECLARE vSizeLimit INT;
DECLARE vMaxTickets INT;
- DECLARE vStateCode VARCHAR(45);
+ DECLARE vStateFk VARCHAR(45);
DECLARE vFirstTicketFk INT;
+ DECLARE vHour INT;
+ DECLARE vMinute INT;
DECLARE vWorkerCode VARCHAR(3);
- DECLARE vWagonCounter INT DEFAULT 1;
+ DECLARE vWagonCounter INT DEFAULT 0;
DECLARE vTicketFk INT;
DECLARE vItemPackingTypeFk VARCHAR(1);
- DECLARE vHasAssignedTickets BOOL;
+ DECLARE vHasAssignedTickets BOOLEAN;
DECLARE vHasUniqueCollectionTime BOOL;
- DECLARE vHeight INT;
- DECLARE vVolume INT;
- DECLARE vLiters INT;
- DECLARE vLines INT;
- DECLARE vTotalLines INT DEFAULT 0;
- DECLARE vTotalVolume INT DEFAULT 0;
- DECLARE vFreeWagonFk INT;
DECLARE vDone INT DEFAULT FALSE;
+ DECLARE vLockName VARCHAR(215);
+ DECLARE vLockTime INT DEFAULT 30;
+ DECLARE vFreeWagonFk INT;
+ DECLARE vErrorNumber INT;
+ DECLARE vErrorMsg TEXT;
- DECLARE vTickets CURSOR FOR
+ DECLARE c1 CURSOR FOR
SELECT ticketFk, `lines`, m3
FROM tmp.productionBuffer
+ WHERE ticketFk <> vFirstTicketFk
ORDER BY HH,
mm,
productionOrder DESC,
@@ -50,6 +48,26 @@ BEGIN
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE;
+ DECLARE EXIT HANDLER FOR SQLEXCEPTION
+ BEGIN
+ GET DIAGNOSTICS CONDITION 1
+ vErrorNumber = MYSQL_ERRNO,
+ vErrorMsg = MESSAGE_TEXT;
+
+ CALL util.debugAdd('collection_new', JSON_OBJECT(
+ 'errorNumber', vErrorNumber,
+ 'errorMsg', vErrorMsg,
+ 'lockName', vLockName,
+ 'userFk', vUserFk,
+ 'ticketFk', vTicketFk
+ )); -- Tmp
+
+ IF vLockName IS NOT NULL THEN
+ DO RELEASE_LOCK(vLockName);
+ END IF;
+ RESIGNAL;
+ END;
+
SELECT pc.ticketTrolleyMax * o.numberOfWagons,
pc.hasUniqueCollectionTime,
w.code,
@@ -60,26 +78,36 @@ BEGIN
o.trainFk,
o.linesLimit,
o.volumeLimit,
- o.sizeLimit
+ o.sizeLimit,
+ pc.collection_new_lockname
INTO vMaxTickets,
- vHasUniqueCollectionTime,
- vWorkerCode,
- vWarehouseFk,
- vItemPackingTypeFk,
- vStateCode,
- vWagons,
- vTrainFk,
- vLinesLimit,
- vVolumeLimit,
- vSizeLimit
- FROM worker w
- JOIN operator o ON o.workerFk = w.id
+ vHasUniqueCollectionTime,
+ vWorkerCode,
+ vWarehouseFk,
+ vItemPackingTypeFk,
+ vStateFk,
+ vWagons,
+ vTrainFk,
+ vLinesLimit,
+ vVolumeLimit,
+ vSizeLimit,
+ vLockName
+ FROM productionConfig pc
+ JOIN worker w ON w.id = vUserFk
JOIN state st ON st.`code` = 'ON_PREPARATION'
- JOIN productionConfig pc
- WHERE w.id = vUserFk;
+ JOIN operator o ON o.workerFk = vUserFk;
+
+ SET vLockName = CONCAT_WS('/',
+ vLockName,
+ vWarehouseFk,
+ vItemPackingTypeFk
+ );
+
+ IF NOT GET_LOCK(vLockName, vLockTime) THEN
+ CALL util.throw(CONCAT('Cannot get lock: ', vLockName));
+ END IF;
-- Se prepara el tren, con tantos vagones como sea necesario.
-
CREATE OR REPLACE TEMPORARY TABLE tTrain
(wagon INT,
shelve INT,
@@ -90,58 +118,59 @@ BEGIN
PRIMARY KEY(wagon, shelve))
ENGINE = MEMORY;
- INSERT INTO tTrain (wagon, shelve, liters, `lines`, height)
- WITH RECURSIVE wagonSequence AS (
- SELECT vWagonCounter wagon
- UNION ALL
- SELECT wagon + 1 wagon
- FROM wagonSequence
- WHERE wagon < vWagonCounter + vWagons -1
- )
- SELECT ws.wagon, cv.`level`, cv.liters, cv.`lines`, cv.height
- FROM wagonSequence ws
- JOIN vn.collectionVolumetry cv ON cv.trainFk = vTrainFk
+ WHILE vWagons > vWagonCounter DO
+ SET vWagonCounter = vWagonCounter + 1;
+
+ INSERT INTO tTrain(wagon, shelve, liters, `lines`, height)
+ SELECT vWagonCounter, cv.`level` , cv.liters , cv.`lines` , cv.height
+ FROM collectionVolumetry cv
+ WHERE cv.trainFk = vTrainFk
AND cv.itemPackingTypeFk = vItemPackingTypeFk;
+ END WHILE;
-- Esto desaparecerá cuando tengamos la table cache.ticket
-
CALL productionControl(vWarehouseFk, 0);
ALTER TABLE tmp.productionBuffer
ADD COLUMN liters INT,
ADD COLUMN height INT;
+ -- Se obtiene nº de colección.
+ INSERT INTO collection
+ SET itemPackingTypeFk = vItemPackingTypeFk,
+ trainFk = vTrainFk,
+ wagons = vWagons,
+ warehouseFk = vWarehouseFk;
+
+ SELECT LAST_INSERT_ID() INTO vCollectionFk;
+
-- Los tickets de recogida en Algemesí sólo se sacan si están asignados.
-- Los pedidos con riesgo no se sacan aunque se asignen.
-
- DELETE pb
+ DELETE pb.*
FROM tmp.productionBuffer pb
JOIN state s ON s.id = pb.state
WHERE (pb.agency = 'REC_ALGEMESI'
AND s.code <> 'PICKER_DESIGNED')
OR pb.problem LIKE '%RIESGO%';
- -- Si hay tickets asignados, nos centramos exclusivamente en esos tickets
- -- y los sacamos independientemente de problemas o tamaños
-
- SELECT EXISTS (
- SELECT TRUE
- FROM tmp.productionBuffer pb
- JOIN state s ON s.id = pb.state
- WHERE s.code = 'PICKER_DESIGNED'
- AND pb.workerCode = vWorkerCode
- ) INTO vHasAssignedTickets;
+ -- Comprobamos si hay tickets asignados. En ese caso, nos centramos
+ -- exclusivamente en esos tickets y los sacamos independientemente
+ -- de problemas o tamaños
+ SELECT COUNT(*) INTO vHasAssignedTickets
+ FROM tmp.productionBuffer pb
+ JOIN state s ON s.id = pb.state
+ WHERE s.code = 'PICKER_DESIGNED'
+ AND pb.workerCode = vWorkerCode;
-- Se dejan en la tabla tmp.productionBuffer sólo aquellos tickets adecuados
-
IF vHasAssignedTickets THEN
- DELETE pb
+ DELETE pb.*
FROM tmp.productionBuffer pb
JOIN state s ON s.id = pb.state
WHERE s.code <> 'PICKER_DESIGNED'
OR pb.workerCode <> vWorkerCode;
ELSE
- DELETE pb
+ DELETE pb.*
FROM tmp.productionBuffer pb
JOIN state s ON s.id = pb.state
JOIN agencyMode am ON am.id = pb.agencyModeFk
@@ -164,7 +193,7 @@ BEGIN
OR (NOT pb.H AND pb.V > 0 AND vItemPackingTypeFk = 'H')
OR (NOT pb.V AND vItemPackingTypeFk = 'V')
OR (pc.isPreviousPreparationRequired AND pb.previousWithoutParking)
- OR LENGTH(pb.problem)
+ OR LENGTH(pb.problem) > 0
OR pb.lines > vLinesLimit
OR pb.m3 > vVolumeLimit
OR sub.maxSize > vSizeLimit
@@ -191,37 +220,37 @@ BEGIN
ticketFk
LIMIT 1;
- OPEN vTickets;
- l: LOOP
- SET vDone = FALSE;
- FETCH vTickets INTO vTicketFk, vTicketLines, vTicketVolume;
+ SET vTicketFk = vFirstTicketFk;
+ SET @lines = 0;
+ SET @volume = 0;
- IF vDone THEN
- LEAVE l;
- END IF;
+ OPEN c1;
+ read_loop: LOOP
+ SET vDone = FALSE;
-- Buscamos un ticket que cumpla con los requisitos en el listado
-
- IF (vLinesLimit IS NULL OR (vTotalLines + vTicketLines) <= vLinesLimit)
- AND (vVolumeLimit IS NULL OR (vTotalVolume + vTicketVolume) <= vVolumeLimit) THEN
+ IF ((vTicketLines + @lines) <= vLinesLimit OR vLinesLimit IS NULL)
+ AND ((vTicketVolume + @volume) <= vVolumeLimit OR vVolumeLimit IS NULL) THEN
CALL ticket_splitItemPackingType(vTicketFk, vItemPackingTypeFk);
DROP TEMPORARY TABLE tmp.ticketIPT;
- SELECT COUNT(*), SUM(litros), MAX(i.`size`), SUM(sv.volume)
- INTO vLines, vLiters, vHeight, vVolume
- FROM saleVolume sv
- JOIN sale s ON s.id = sv.saleFk
- JOIN item i ON i.id = s.itemFk
- WHERE sv.ticketFk = vTicketFk;
-
- SET vTotalVolume = vTotalVolume + vVolume,
- vTotalLines = vTotalLines + vLines;
-
UPDATE tmp.productionBuffer pb
- SET pb.liters = vLiters,
- pb.`lines` = vLines,
- pb.height = vHeight
+ JOIN (
+ SELECT SUM(litros) liters,
+ @lines:= COUNT(*) + @lines,
+ COUNT(*) `lines`,
+ MAX(i.`size`) height,
+ @volume := SUM(sv.volume) + @volume,
+ SUM(sv.volume) volume
+ FROM saleVolume sv
+ JOIN sale s ON s.id = sv.saleFk
+ JOIN item i ON i.id = s.itemFk
+ WHERE sv.ticketFk = vTicketFk
+ ) sub
+ SET pb.liters = sub.liters,
+ pb.`lines` = sub.`lines`,
+ pb.height = sub.height
WHERE pb.ticketFk = vTicketFk;
UPDATE tTrain tt
@@ -238,13 +267,17 @@ BEGIN
tt.height
LIMIT 1;
- -- Si no le encuentra una balda, intentamos darle un carro entero libre
-
+ -- Si no le encuentra una balda adecuada, intentamos darle un carro entero si queda alguno libre
IF NOT (SELECT COUNT(*) FROM tTrain WHERE ticketFk) THEN
- SELECT wagon INTO vFreeWagonFk
- FROM tTrain
- GROUP BY wagon
- HAVING SUM(IFNULL(ticketFk, 0)) = 0
+ SELECT tt.wagon
+ INTO vFreeWagonFk
+ FROM tTrain tt
+ LEFT JOIN (
+ SELECT DISTINCT wagon
+ FROM tTrain
+ WHERE ticketFk IS NOT NULL
+ ) nn ON nn.wagon = tt.wagon
+ WHERE nn.wagon IS NULL
ORDER BY wagon
LIMIT 1;
@@ -253,35 +286,38 @@ BEGIN
SET ticketFk = vFirstTicketFk
WHERE wagon = vFreeWagonFk;
- -- Se anulan el resto de carros libres,
- -- máximo un carro con pedido excesivo
-
- DELETE tt
+ -- Se anulan el resto de carros libres para que sólo uno lleve un pedido excesivo
+ DELETE tt.*
FROM tTrain tt
- JOIN (SELECT wagon
- FROM tTrain
- GROUP BY wagon
- HAVING SUM(IFNULL(ticketFk, 0)) = 0
- ) sub ON sub.wagon = tt.wagon;
+ LEFT JOIN (
+ SELECT DISTINCT wagon
+ FROM tTrain
+ WHERE ticketFk IS NOT NULL
+ ) nn ON nn.wagon = tt.wagon
+ WHERE nn.wagon IS NULL;
END IF;
- END IF;
+ END IF;
+
+ FETCH c1 INTO vTicketFk, vTicketLines, vTicketVolume;
+ IF vDone OR NOT (SELECT COUNT(*) FROM tTrain WHERE ticketFk IS NULL) THEN
+ LEAVE read_loop;
+ END IF;
+ ELSE
+ FETCH c1 INTO vTicketFk, vTicketLines, vTicketVolume;
+ IF vDone THEN
+ LEAVE read_loop;
+ END IF;
END IF;
END LOOP;
- CLOSE vTickets;
+ CLOSE c1;
IF (SELECT COUNT(*) FROM tTrain WHERE ticketFk) THEN
- -- Se obtiene nº de colección
-
- INSERT INTO collection
- SET itemPackingTypeFk = vItemPackingTypeFk,
- trainFk = vTrainFk,
- wagons = vWagons,
- warehouseFk = vWarehouseFk;
-
- SELECT LAST_INSERT_ID() INTO vCollectionFk;
+ UPDATE collection c
+ JOIN state st ON st.code = 'ON_PREPARATION'
+ SET c.stateFk = st.id
+ WHERE c.id = vCollectionFk;
-- Asigna las bandejas
-
INSERT IGNORE INTO ticketCollection(ticketFk, collectionFk, `level`, wagon, liters)
SELECT tt.ticketFk, vCollectionFk, tt.shelve, tt.wagon, tt.liters
FROM tTrain tt
@@ -289,36 +325,39 @@ BEGIN
ORDER BY tt.wagon, tt.shelve;
-- Actualiza el estado de los tickets
-
- CALL collection_setState(vCollectionFk, vStateCode);
+ CALL collection_setState(vCollectionFk, vStateFk);
-- Aviso para la preparacion previa
-
INSERT INTO ticketDown(ticketFk, collectionFk)
SELECT tc.ticketFk, tc.collectionFk
FROM ticketCollection tc
WHERE tc.collectionFk = vCollectionFk;
- CALL collection_mergeSales(vCollectionFk);
+ CALL sales_mergeByCollection(vCollectionFk);
UPDATE `collection` c
- JOIN(
+ JOIN (
SELECT COUNT(*) saleTotalCount,
SUM(s.isPicked <> 0) salePickedCount
FROM ticketCollection tc
JOIN sale s ON s.ticketFk = tc.ticketFk
- WHERE tc.collectionFk = vCollectionFk
- AND s.quantity > 0
- )sub
+ WHERE tc.collectionFk = vCollectionFk
+ AND s.quantity > 0
+ ) sub
SET c.saleTotalCount = sub.saleTotalCount,
c.salePickedCount = sub.salePickedCount
WHERE c.id = vCollectionFk;
+
ELSE
- SET vCollectionFk = NULL;
+ DELETE FROM `collection`
+ WHERE id = vCollectionFk;
+ SET vCollectionFk = NULL;
END IF;
+ DO RELEASE_LOCK(vLockName);
+
DROP TEMPORARY TABLE
tTrain,
tmp.productionBuffer;
END$$
-DELIMITER ;
+DELIMITER ;
\ No newline at end of file
diff --git a/db/routines/vn/procedures/itemShelvingSale_addBySale.sql b/db/routines/vn/procedures/itemShelvingSale_addBySale.sql
index aa50f0ed8..6625e89b8 100644
--- a/db/routines/vn/procedures/itemShelvingSale_addBySale.sql
+++ b/db/routines/vn/procedures/itemShelvingSale_addBySale.sql
@@ -48,6 +48,13 @@ proc: BEGIN
RESIGNAL;
END;
+ START TRANSACTION;
+
+ SELECT id INTO vSaleFk
+ FROM sale
+ WHERE id = vSaleFk
+ FOR UPDATE;
+
SELECT MAX(p.pickingOrder), s.quantity - SUM(IFNULL(iss.quantity, 0)), s.quantity
INTO vLastPickingOrder, vOutStanding, vSaleQuantity
FROM sale s
@@ -57,7 +64,8 @@ proc: BEGIN
LEFT JOIN parking p ON p.id = sh.parkingFk
WHERE s.id = vSaleFk;
- IF vOutStanding <= 0 THEN
+ IF vOutStanding <= 0 THEN
+ COMMIT;
LEAVE proc;
END IF;
@@ -84,10 +92,8 @@ proc: BEGIN
END IF;
LEAVE l;
END IF;
-
- START TRANSACTION;
-
- SELECT id INTO vItemShelvingFk
+
+ SELECT id INTO vItemShelvingFk
FROM itemShelving
WHERE id = vItemShelvingFk
FOR UPDATE;
@@ -115,9 +121,8 @@ proc: BEGIN
WHERE id = vItemShelvingFk;
END IF;
-
- COMMIT;
END LOOP;
CLOSE vItemShelvingAvailable;
+ COMMIT;
END$$
DELIMITER ;
\ No newline at end of file
diff --git a/db/routines/vn/procedures/ticket_mergeSales.sql b/db/routines/vn/procedures/ticket_mergeSales.sql
index 2dc3a39da..28b2dc1c0 100644
--- a/db/routines/vn/procedures/ticket_mergeSales.sql
+++ b/db/routines/vn/procedures/ticket_mergeSales.sql
@@ -3,47 +3,41 @@ CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticket_mergeSales`(
vSelf INT
)
BEGIN
- DECLARE vHasSalesToMerge BOOL;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
RESIGNAL;
END;
- START TRANSACTION;
-
- SELECT id INTO vSelf
- FROM ticket
- WHERE id = vSelf FOR UPDATE;
-
CREATE OR REPLACE TEMPORARY TABLE tSalesToPreserve
(PRIMARY KEY (id))
ENGINE = MEMORY
- SELECT s.id, s.itemFk, SUM(s.quantity) newQuantity
+ SELECT s.id, s.itemFk, SUM(s.quantity) newQuantity
FROM sale s
JOIN item i ON i.id = s.itemFk
JOIN itemType it ON it.id = i.typeFk
WHERE s.ticketFk = vSelf
AND it.isMergeable
- GROUP BY s.itemFk, s.price, s.discount
- HAVING COUNT(*) > 1;
+ GROUP BY s.itemFk, s.price, s.discount;
- SELECT COUNT(*) INTO vHasSalesToMerge
- FROM tSalesToPreserve;
+ START TRANSACTION;
- IF vHasSalesToMerge THEN
- UPDATE sale s
- JOIN tSalesToPreserve stp ON stp.id = s.id
- SET s.quantity = newQuantity;
+ UPDATE sale s
+ JOIN tSalesToPreserve stp ON stp.id = s.id
+ SET s.quantity = newQuantity
+ WHERE s.ticketFk = vSelf;
- DELETE s
- FROM sale s
- JOIN tSalesToPreserve stp ON stp.itemFk = s.itemFk
- WHERE s.ticketFk = vSelf
- AND s.id <> stp.id;
- END IF;
+ DELETE s.*
+ FROM sale s
+ LEFT JOIN tSalesToPreserve stp ON stp.id = s.id
+ JOIN item i ON i.id = s.itemFk
+ JOIN itemType it ON it.id = i.typeFk
+ WHERE s.ticketFk = vSelf
+ AND stp.id IS NULL
+ AND it.isMergeable;
COMMIT;
+
DROP TEMPORARY TABLE tSalesToPreserve;
END$$
DELIMITER ;
diff --git a/db/routines/vn/procedures/ticket_setVolume.sql b/db/routines/vn/procedures/ticket_setVolume.sql
index 060a6fa57..d0fe9740c 100644
--- a/db/routines/vn/procedures/ticket_setVolume.sql
+++ b/db/routines/vn/procedures/ticket_setVolume.sql
@@ -4,7 +4,7 @@ CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticket_setVolume`(
)
BEGIN
/**
- * Update the volume ticket
+ * Update the volume ticket.
*
* @param vSelf Ticket id
*/
diff --git a/db/routines/vn/procedures/ticket_setVolumeItemCost.sql b/db/routines/vn/procedures/ticket_setVolumeItemCost.sql
index f266cd769..d7fb4473d 100644
--- a/db/routines/vn/procedures/ticket_setVolumeItemCost.sql
+++ b/db/routines/vn/procedures/ticket_setVolumeItemCost.sql
@@ -4,26 +4,36 @@ CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticket_setVolumeIte
)
BEGIN
/**
- * Update the volume tickets of item
+ * Update the volume of tickets containing the item.
*
- * @param vSelf Ticket id
+ * @param vItemFk Item id
*/
- CREATE OR REPLACE TEMPORARY TABLE tTicket
- (PRIMARY KEY (id))
- ENGINE = MEMORY
- SELECT t.id, SUM(s.quantity * ic.cm3delivery / 1000000) volume
+ DECLARE vTicket INT;
+ DECLARE vDone BOOL;
+
+ DECLARE vTickets CURSOR FOR
+ SELECT DISTINCT t.id
FROM sale s
JOIN ticket t ON t.id = s.ticketFk
JOIN itemCost ic ON ic.itemFk = s.itemFk
AND ic.warehouseFk = t.warehouseFk
WHERE s.itemFk = vItemFk
AND t.shipped >= util.VN_CURDATE()
- GROUP BY t.id;
+ AND t.refFk IS NULL;
- UPDATE ticket t
- JOIN tTicket tt ON tt.id = t.id
- SET t.volume = tt.volume;
+ DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE;
- DROP TEMPORARY TABLE tTicket;
+ OPEN vTickets;
+ l: LOOP
+ FETCH vTickets INTO vTicket;
+
+ IF vDone THEN
+ LEAVE l;
+ END IF;
+
+ CALL ticket_setVolume(vTicket);
+
+ END LOOP l;
+ CLOSE vTickets;
END$$
DELIMITER ;
diff --git a/db/routines/vn/procedures/ticket_splitItemPackingType.sql b/db/routines/vn/procedures/ticket_splitItemPackingType.sql
index 7839b0008..6baf944ee 100644
--- a/db/routines/vn/procedures/ticket_splitItemPackingType.sql
+++ b/db/routines/vn/procedures/ticket_splitItemPackingType.sql
@@ -5,21 +5,23 @@ CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`ticket_splitItemPacki
)
proc: BEGIN
/**
- * Clona y reparte las líneas de ventas de un ticket en funcion del tipo de empaquetado.
- * Respeta el id de ticket inicial para el tipo de empaquetado propuesto.
+ * Clona y reparte las ventas de un ticket en funcion del tipo de empaquetado.
+ * Respeta el id inicial para el tipo propuesto.
*
* @param vSelf Id ticket
- * @param vOriginalItemPackingTypeFk Tipo empaquetado al que se mantiene el ticket original
+ * @param vOriginalItemPackingTypeFk Tipo para el que se reserva el número de ticket original
* @return table tmp.ticketIPT(ticketFk, itemPackingTypeFk)
*/
- DECLARE vDone INT DEFAULT FALSE;
- DECLARE vHasItemPackingType BOOL;
- DECLARE vItemPackingTypeFk INT;
+ DECLARE vItemPackingTypeFk VARCHAR(1) DEFAULT 'H';
DECLARE vNewTicketFk INT;
+ DECLARE vPackingTypesToSplit INT;
+ DECLARE vDone INT DEFAULT FALSE;
- DECLARE vItemPackingTypes CURSOR FOR
- SELECT DISTINCT itemPackingTypeFk
- FROM tSalesToMove;
+ DECLARE vSaleGroup CURSOR FOR
+ SELECT itemPackingTypeFk
+ FROM tSaleGroup
+ WHERE itemPackingTypeFk IS NOT NULL
+ ORDER BY (itemPackingTypeFk = vOriginalItemPackingTypeFk) DESC;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE;
@@ -34,39 +36,59 @@ proc: BEGIN
LEAVE proc;
END IF;
- CREATE OR REPLACE TEMPORARY TABLE tSalesToMove (
+ CREATE OR REPLACE TEMPORARY TABLE tmp.ticketIPT(
ticketFk INT,
- saleFk INT,
- itemPackingTypeFk INT
- ) ENGINE=MEMORY;
+ itemPackingTypeFk VARCHAR(1)
+ ) ENGINE = MEMORY;
- INSERT INTO tSalesToMove (saleFk, itemPackingTypeFk)
- SELECT s.id, i.itemPackingTypeFk
- FROM ticket t
- JOIN sale s ON s.ticketFk = t.id
- JOIN item i ON i.id = s.itemFk
- WHERE t.id = vSelf
- AND i.itemPackingTypeFk <> vOriginalItemPackingTypeFk;
+ CASE vPackingTypesToSplit
+ WHEN 0 THEN
+ INSERT INTO tmp.ticketIPT(ticketFk, itemPackingTypeFk)
+ VALUES(vSelf, vItemPackingTypeFk);
+ WHEN 1 THEN
+ INSERT INTO tmp.ticketIPT(ticketFk, itemPackingTypeFk)
+ SELECT vSelf, itemPackingTypeFk
+ FROM tSaleGroup
+ WHERE itemPackingTypeFk IS NOT NULL;
+ ELSE
+ OPEN vSaleGroup;
+ FETCH vSaleGroup INTO vItemPackingTypeFk;
- OPEN vItemPackingTypes;
+ INSERT INTO tmp.ticketIPT(ticketFk, itemPackingTypeFk)
+ VALUES(vSelf, vItemPackingTypeFk);
- l: LOOP
- SET vDone = FALSE;
- FETCH vItemPackingTypes INTO vItemPackingTypeFk;
+ l: LOOP
+ SET vDone = FALSE;
+ FETCH vSaleGroup INTO vItemPackingTypeFk;
- IF vDone THEN
- LEAVE l;
- END IF;
+ IF vDone THEN
+ LEAVE l;
+ END IF;
- CALL ticket_Clone(vSelf, vNewTicketFk);
+ CALL ticket_Clone(vSelf, vNewTicketFk);
- UPDATE tSalesToMove
- SET ticketFk = vNewTicketFk
- WHERE itemPackingTypeFk = vItemPackingTypeFk;
+ INSERT INTO tmp.ticketIPT(ticketFk, itemPackingTypeFk)
+ VALUES(vNewTicketFk, vItemPackingTypeFk);
+ END LOOP;
- END LOOP;
+ CLOSE vSaleGroup;
- CLOSE vItemPackingTypes;
+ SELECT s.id
+ FROM sale s
+ JOIN tSale ts ON ts.id = s.id
+ JOIN tmp.ticketIPT t ON t.itemPackingTypeFk = ts.itemPackingTypeFk
+ FOR UPDATE;
+
+ UPDATE sale s
+ JOIN tSale ts ON ts.id = s.id
+ JOIN tmp.ticketIPT t ON t.itemPackingTypeFk = ts.itemPackingTypeFk
+ SET s.ticketFk = t.ticketFk;
+
+ SELECT itemPackingTypeFk INTO vItemPackingTypeFk
+ FROM tSaleGroup sg
+ WHERE sg.itemPackingTypeFk IS NOT NULL
+ ORDER BY sg.itemPackingTypeFk
+ LIMIT 1;
UPDATE sale s
JOIN tSalesToMove stm ON stm.saleFk = s.id
@@ -83,6 +105,8 @@ proc: BEGIN
UNION
SELECT vSelf, vOriginalItemPackingTypeFk;
- DROP TEMPORARY TABLE tSalesToMove;
+ DROP TEMPORARY TABLE
+ tSale,
+ tSaleGroup;
END$$
-DELIMITER ;
\ No newline at end of file
+DELIMITER ;
diff --git a/db/versions/11196-blackCymbidium/00-firstScript.sql b/db/versions/11196-blackCymbidium/00-firstScript.sql
new file mode 100644
index 000000000..e05225204
--- /dev/null
+++ b/db/versions/11196-blackCymbidium/00-firstScript.sql
@@ -0,0 +1,7 @@
+RENAME TABLE vn.quadMindsApiConfig TO vn.quadmindsApiConfig;
+
+ALTER TABLE vn.quadmindsApiConfig
+ ADD maxObjects INT NULL COMMENT 'Número máximo de objetos en el array por petición',
+ ADD `limit` INT NULL COMMENT 'Limite de objetos solicitados por petición',
+ ADD `orderTimeFrom` VARCHAR(5) NULL COMMENT 'Inicio de ventana horaria de pedido',
+ ADD `orderTimeTo` VARCHAR(5) NULL COMMENT 'Fin de ventana horaria de pedido';
diff --git a/db/versions/11239-goldenBirch/00-firstScript.sql b/db/versions/11239-goldenBirch/00-firstScript.sql
new file mode 100644
index 000000000..559982081
--- /dev/null
+++ b/db/versions/11239-goldenBirch/00-firstScript.sql
@@ -0,0 +1,2 @@
+-- Place your SQL code here
+ALTER TABLE vn.packaging ADD IF NOT EXISTS isPlantTray BOOL DEFAULT FALSE NOT NULL COMMENT 'The container is a plant tray. Used to restrict the picking of full plant trays, to make previous picking.';
diff --git a/modules/ticket/front/descriptor-menu/index.html b/modules/ticket/front/descriptor-menu/index.html
index 82094d7b8..b861b0c0e 100644
--- a/modules/ticket/front/descriptor-menu/index.html
+++ b/modules/ticket/front/descriptor-menu/index.html
@@ -349,13 +349,6 @@
message="Recalculate components">
-
-
-
-