Merge branch 'dev' into 7670-addSaleRenewPrice
gitea/salix/pipeline/pr-dev This commit looks good Details

This commit is contained in:
Robert Ferrús 2024-07-12 08:50:48 +00:00
commit 4da811cba6
29 changed files with 587 additions and 271 deletions

View File

@ -115,6 +115,9 @@ INSERT INTO `hedera`.`tpvConfig`(`id`, `currency`, `terminal`, `transactionType`
VALUES VALUES
(1, 978, 1, 0, 2000, 9, 0); (1, 978, 1, 0, 2000, 9, 0);
INSERT INTO hedera.orderConfig (`id`, `employeeFk`, `defaultAgencyFk`, `guestMethod`, `guestAgencyFk`, `reserveTime`, `defaultCompanyFk`)
VALUES (1, 1, 2, 'PICKUP', 1, '00:20:00', 442);
INSERT INTO `account`.`user`(`id`,`name`,`nickname`, `password`,`role`,`active`,`email`,`lang`, `image`) INSERT INTO `account`.`user`(`id`,`name`,`nickname`, `password`,`role`,`active`,`email`,`lang`, `image`)
VALUES VALUES
(1101, 'brucewayne', 'Bruce Wayne', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 2, 1, 'BruceWayne@mydomain.com', 'es','1101'), (1101, 'brucewayne', 'Bruce Wayne', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 2, 1, 'BruceWayne@mydomain.com', 'es','1101'),
@ -301,6 +304,17 @@ UPDATE `vn`.`agencyMode` SET `deliveryMethodFk` = 1 WHERE `id` = 8;
UPDATE `vn`.`agencyMode` SET `deliveryMethodFk` = 4 WHERE `id` = 23; UPDATE `vn`.`agencyMode` SET `deliveryMethodFk` = 4 WHERE `id` = 23;
UPDATE `vn`.`agencyMode` SET `deliveryMethodFk` = 1 WHERE `id` = 10; UPDATE `vn`.`agencyMode` SET `deliveryMethodFk` = 1 WHERE `id` = 10;
UPDATE `vn`.`agencyMode` SET `description` = 'inhouse pickup' WHERE `id` = 1;
UPDATE `vn`.`agencyMode` SET `description` = 'Super-Man delivery' WHERE `id` = 2;
UPDATE `vn`.`agencyMode` SET `description` = 'Teleportation device' WHERE `id` = 3;
UPDATE `vn`.`agencyMode` SET `description` = 'Entanglement' WHERE `id` = 4;
UPDATE `vn`.`agencyMode` SET `description` = 'Quantum break device' WHERE `id` = 5;
UPDATE `vn`.`agencyMode` SET `description` = 'Walking' WHERE `id` = 6;
UPDATE `vn`.`agencyMode` SET `description` = 'Gotham247' WHERE `id` = 7;
UPDATE `vn`.`agencyMode` SET `description` = 'Gotham247Expensive' WHERE `id` = 8;
UPDATE `vn`.`agencyMode` SET `description` = 'Other agency' WHERE `id` = 10;
UPDATE `vn`.`agencyMode` SET `description` = 'Refund' WHERE `id` = 23;
UPDATE `vn`.`agencyMode` SET `web` = 1, `reportMail` = 'no-reply@gothamcity.com'; UPDATE `vn`.`agencyMode` SET `web` = 1, `reportMail` = 'no-reply@gothamcity.com';
UPDATE `vn`.`agencyMode` SET `code` = 'refund' WHERE `id` = 23; UPDATE `vn`.`agencyMode` SET `code` = 'refund' WHERE `id` = 23;
@ -979,6 +993,14 @@ INSERT INTO `vn`.`priceFixed`(`id`, `itemFk`, `rate0`, `rate1`, `rate2`, `rate3`
(2, 3, 10, 10, 10, 10, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL +1 MONTH), 0, 1, util.VN_CURDATE()), (2, 3, 10, 10, 10, 10, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL +1 MONTH), 0, 1, util.VN_CURDATE()),
(3, 13, 8.5, 10, 7.5, 6, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL +1 MONTH), 1, 2, util.VN_CURDATE()); (3, 13, 8.5, 10, 7.5, 6, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL +1 MONTH), 1, 2, util.VN_CURDATE());
INSERT INTO `vn`.`itemMinimumQuantity`(`itemFk`, `quantity`, `started`, `ended`, `warehouseFk`)
VALUES
(1, 5, util.VN_CURDATE() - INTERVAL 2 MONTH, util.VN_CURDATE() + INTERVAL 1 MONTH, 1),
(2, 10, util.VN_CURDATE() - INTERVAL 2 DAY, NULL, 2),
(3, 15, util.VN_CURDATE() + INTERVAL 3 DAY, util.VN_CURDATE() + INTERVAL 2 WEEK, 3),
(2, 10, util.VN_CURDATE() + INTERVAL 2 MONTH, NULL, 5),
(4, 8, util.VN_CURDATE() - INTERVAL 3 MONTH, NULL, NULL);
INSERT INTO `vn`.`expeditionBoxVol`(`boxFk`, `m3`, `ratio`) INSERT INTO `vn`.`expeditionBoxVol`(`boxFk`, `m3`, `ratio`)
VALUES VALUES
(71,0.141,1); (71,0.141,1);

View File

@ -25,12 +25,7 @@ BEGIN
JOIN vn.warehouse w ON w.id = p.warehouseFk JOIN vn.warehouse w ON w.id = p.warehouseFk
ORDER BY warehouseFk, `grouping`; ORDER BY warehouseFk, `grouping`;
DROP TEMPORARY TABLE CALL vn.ticketCalculatePurge();
tmp.ticketCalculateItem, DROP TEMPORARY TABLE tmp.item;
tmp.ticketComponentPrice,
tmp.ticketComponent,
tmp.ticketLot,
tmp.zoneGetShipped,
tmp.item;
END$$ END$$
DELIMITER ; DELIMITER ;

View File

@ -56,11 +56,15 @@ BEGIN
CALL util.throw ('ORDER_ROW_UNAVAILABLE'); CALL util.throw ('ORDER_ROW_UNAVAILABLE');
END IF; END IF;
SELECT IFNULL(minQuantity, 0) INTO vMinQuantity SELECT quantity INTO vMinQuantity
FROM vn.item FROM vn.itemMinimumQuantity
WHERE id = vItem; WHERE itemFk = vItem
AND `started` <= vShipment
AND (`ended` >= vShipment OR `ended` IS NULL)
AND (warehouseFk = vWarehouse OR warehouseFk IS NULL)
LIMIT 1;
IF vAmount < LEAST(vMinQuantity, vAvailable) THEN IF vAmount < LEAST(IFNULL(vMinQuantity, 0), vAvailable) THEN
CALL util.throw ('quantityLessThanMin'); CALL util.throw ('quantityLessThanMin');
END IF; END IF;

View File

@ -45,8 +45,7 @@ BEGIN
CALL catalog_componentPrepare(); CALL catalog_componentPrepare();
DROP TEMPORARY TABLE IF EXISTS tmp.ticketCalculateItem; CREATE OR REPLACE TEMPORARY TABLE tmp.ticketCalculateItem(
CREATE TEMPORARY TABLE tmp.ticketCalculateItem(
itemFk INT(11) NOT NULL, itemFk INT(11) NOT NULL,
available INT(11), available INT(11),
producer VARCHAR(50), producer VARCHAR(50),
@ -60,11 +59,11 @@ BEGIN
price DECIMAL(10,2), price DECIMAL(10,2),
priceKg DECIMAL(10,2), priceKg DECIMAL(10,2),
`grouping` INT(10) UNSIGNED, `grouping` INT(10) UNSIGNED,
minQuantity INT(10) UNSIGNED,
PRIMARY KEY `itemFk` (`itemFk`) PRIMARY KEY `itemFk` (`itemFk`)
) ENGINE = MEMORY DEFAULT CHARSET=utf8; ) ENGINE = MEMORY DEFAULT CHARSET=utf8;
OPEN cTravelTree; OPEN cTravelTree;
l: LOOP l: LOOP
SET vDone = FALSE; SET vDone = FALSE;
FETCH cTravelTree INTO vZoneFk, vWarehouseFk, vShipped; FETCH cTravelTree INTO vZoneFk, vWarehouseFk, vShipped;
@ -136,7 +135,7 @@ BEGIN
CALL vn.catalog_componentCalculate(vZoneFk, vAddressFk, vShipped, vWarehouseFk); CALL vn.catalog_componentCalculate(vZoneFk, vAddressFk, vShipped, vWarehouseFk);
INSERT INTO tmp.ticketCalculateItem ( INSERT INTO tmp.ticketCalculateItem(
itemFk, itemFk,
available, available,
producer, producer,
@ -149,9 +148,9 @@ BEGIN
origin, origin,
price, price,
priceKg, priceKg,
`grouping`) `grouping`,
SELECT minQuantity)
tl.itemFk, SELECT tl.itemFk,
SUM(tl.available) available, SUM(tl.available) available,
p.name producer, p.name producer,
i.name item, i.name item,
@ -163,7 +162,8 @@ BEGIN
o.code origin, o.code origin,
bl.price, bl.price,
bl.priceKg, bl.priceKg,
bl.`grouping` bl.`grouping`,
mq.quantity
FROM tmp.ticketLot tl FROM tmp.ticketLot tl
JOIN item i ON tl.itemFk = i.id JOIN item i ON tl.itemFk = i.id
LEFT JOIN producer p ON p.id = i.producerFk AND p.isVisible LEFT JOIN producer p ON p.id = i.producerFk AND p.isVisible
@ -179,12 +179,19 @@ BEGIN
) sub ) sub
GROUP BY itemFk GROUP BY itemFk
) bl ON bl.itemFk = tl.itemFk ) bl ON bl.itemFk = tl.itemFk
LEFT JOIN (
SELECT itemFk, quantity, warehouseFk
FROM itemMinimumQuantity
WHERE `started` <= vShipped
AND (`ended` >= vShipped OR `ended` IS NULL)
GROUP BY itemFk, warehouseFk
ORDER BY warehouseFk DESC
) mq ON mq.itemFk = tl.itemFk
AND (mq.warehouseFk = tl.warehouseFk OR mq.warehouseFk IS NULL)
WHERE tl.zoneFk = vZoneFk AND tl.warehouseFk = vWarehouseFk WHERE tl.zoneFk = vZoneFk AND tl.warehouseFk = vWarehouseFk
GROUP BY tl.itemFk GROUP BY tl.itemFk
ON DUPLICATE KEY UPDATE available = available + VALUES(available); ON DUPLICATE KEY UPDATE available = available + VALUES(available);
END LOOP; END LOOP;
CLOSE cTravelTree; CLOSE cTravelTree;
END$$ END$$
DELIMITER ; DELIMITER ;

View File

@ -1,15 +1,18 @@
DELIMITER $$ DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`collection_setParking`(IN `vCollectionFk` VARCHAR(8), IN `vParkingFk` INT) CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`collection_setParking`(
proc: BEGIN vSelf INT,
vParkingFk INT
)
BEGIN
/** /**
* Aparca una colección en un parking. * Aparca una colección en un parking.
* *
* @param vCollectionFk Id de la colección * @param vSelf Id colección
* @param vParkingFk Id del parking * @param vParkingFk Id parking
*/ */
REPLACE vn.ticketParking(ticketFk, parkingFk) REPLACE ticketParking(ticketFk, parkingFk)
SELECT tc.ticketFk, vParkingFk SELECT tc.ticketFk, vParkingFk
FROM vn.ticketCollection tc FROM ticketCollection tc
WHERE tc.collectionFk = vCollectionFk; WHERE tc.collectionFk = vSelf;
END$$ END$$
DELIMITER ; DELIMITER ;

View File

@ -2,94 +2,84 @@ DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`item_getBalance`( CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`item_getBalance`(
vItemFk INT, vItemFk INT,
vWarehouseFk INT, vWarehouseFk INT,
vDate DATETIME vDated DATETIME
) )
BEGIN BEGIN
/** /**
* @vItemFk item a buscar * Calcula el balance de un artículo.
* @vWarehouseFk almacen donde buscar *
* @vDate Si la fecha es null, muestra el histórico desde el inventario. * @vItemFk Id de artículo
* Si la fecha no es null, muestra histórico desde la fecha de vDate. * @vWarehouseFk Id de almacén
* @vDated Fecha a calcular, si es NULL muestra el histórico desde el inventario
*/ */
DECLARE vDateInventory DATETIME; DECLARE vDateInventory DATETIME
DEFAULT (
SELECT IF(vDated, uc.mockUtcTime, c.inventoried)
FROM config c
JOIN util.config uc
);
DECLARE vSupplierInventoryFk INT
DEFAULT (SELECT supplierFk FROM inventoryConfig);
IF vDate IS NULL THEN IF NOT vSupplierInventoryFk OR NOT vDateInventory THEN
SELECT inventoried INTO vDateInventory CALL util.throw('Config variables are not set');
FROM config;
ELSE
SELECT mockUtcTime INTO vDateInventory
FROM util.config;
END IF; END IF;
CREATE OR REPLACE TEMPORARY TABLE tItemDiary( CREATE OR REPLACE TEMPORARY TABLE tItemDiary
shipped DATE, ENGINE = MEMORY
`in` INT(11),
`out` INT(11),
alertLevel INT(11),
stateName VARCHAR(20),
`name` VARCHAR(50),
reference VARCHAR(50),
origin INT(11),
clientFk INT(11),
isPicked INT(11),
isTicket TINYINT(1),
lineFk INT(11),
`order` TINYINT(3) UNSIGNED,
clientType VARCHAR(20),
claimFk INT(10) UNSIGNED,
inventorySupplierFk INT(10)
);
INSERT INTO tItemDiary
WITH entriesIn AS ( WITH entriesIn AS (
SELECT tr.landed shipped, SELECT 'entry' originType,
e.id originId,
tr.landed shipped,
b.quantity `in`, b.quantity `in`,
NULL `out`, NULL `out`,
st.alertLevel , st.alertLevel ,
st.name stateName, st.name stateName,
s.name `name`,
e.invoiceNumber reference, e.invoiceNumber reference,
e.id origin, 'supplier' entityType,
s.id clientFk, s.id entityId,
s.name entityName,
IF(st.`code` = 'DELIVERED', TRUE, FALSE) isPicked, IF(st.`code` = 'DELIVERED', TRUE, FALSE) isPicked,
FALSE isTicket, FALSE isTicket,
b.id lineFk, b.id lineFk,
NULL `order`, NULL `order`,
NULL clientType, NULL clientType,
NULL claimFk, NULL claimFk,
ec.inventorySupplierFk vSupplierInventoryFk inventorySupplierFk
FROM vn.buy b FROM vn.buy b
JOIN vn.entry e ON e.id = b.entryFk JOIN vn.entry e ON e.id = b.entryFk
JOIN vn.travel tr ON tr.id = e.travelFk JOIN vn.travel tr ON tr.id = e.travelFk
JOIN vn.supplier s ON s.id = e.supplierFk JOIN vn.supplier s ON s.id = e.supplierFk
JOIN vn.state st ON st.`code` = IF( tr.landed < util.VN_CURDATE() JOIN vn.state st ON st.`code` = IF(tr.landed < util.VN_CURDATE()
OR (util.VN_CURDATE() AND tr.isReceived), OR (util.VN_CURDATE() AND tr.isReceived),
'DELIVERED', 'DELIVERED',
'FREE') 'FREE')
JOIN vn.entryConfig ec
WHERE tr.landed >= vDateInventory WHERE tr.landed >= vDateInventory
AND vWarehouseFk = tr.warehouseInFk AND tr.warehouseInFk = vWarehouseFk
AND (s.id <> ec.inventorySupplierFk OR vDate IS NULL) AND (s.id <> vSupplierInventoryFk OR vDated IS NULL)
AND b.itemFk = vItemFk AND b.itemFk = vItemFk
AND NOT e.isExcludedFromAvailable AND NOT e.isExcludedFromAvailable
AND NOT e.isRaid AND NOT e.isRaid
), entriesOut AS ( ),
SELECT tr.shipped, entriesOut AS (
SELECT 'entry',
e.id originType,
tr.shipped,
NULL, NULL,
b.quantity, b.quantity,
st.alertLevel, st.alertLevel,
st.name stateName, st.name stateName,
s.name ,
e.invoiceNumber, e.invoiceNumber,
e.id entryFk, 'supplier' entityType,
s.id supplierFk, s.id entityId,
s.name,
IF(st.`code` = 'DELIVERED' , TRUE, FALSE), IF(st.`code` = 'DELIVERED' , TRUE, FALSE),
FALSE isTicket, FALSE isTicket,
b.id, b.id,
NULL `order`, NULL `order`,
NULL clientType, NULL clientType,
NULL claimFk, NULL claimFk,
ec.inventorySupplierFk vSupplierInventoryFk
FROM vn.buy b FROM vn.buy b
JOIN vn.entry e ON e.id = b.entryFk JOIN vn.entry e ON e.id = b.entryFk
JOIN vn.travel tr ON tr.id = e.travelFk JOIN vn.travel tr ON tr.id = e.travelFk
@ -99,86 +89,108 @@ BEGIN
OR (tr.shipped = util.VN_CURDATE() AND tr.isReceived), OR (tr.shipped = util.VN_CURDATE() AND tr.isReceived),
'DELIVERED', 'DELIVERED',
'FREE') 'FREE')
JOIN vn.entryConfig ec
WHERE tr.shipped >= vDateInventory WHERE tr.shipped >= vDateInventory
AND vWarehouseFk = tr.warehouseOutFk AND tr.warehouseOutFk = vWarehouseFk
AND (s.id <> ec.inventorySupplierFk OR vDate IS NULL) AND (s.id <> vSupplierInventoryFk OR vDated IS NULL)
AND b.itemFk = vItemFk AND b.itemFk = vItemFk
AND NOT e.isExcludedFromAvailable AND NOT e.isExcludedFromAvailable
AND NOT w.isFeedStock AND NOT w.isFeedStock
AND NOT e.isRaid AND NOT e.isRaid
), sales AS ( ),
SELECT DATE(t.shipped) shipped, sales AS (
s.quantity, WITH itemSales AS (
st2.alertLevel, SELECT DATE(t.shipped) shipped,
st2.name, s.quantity,
t.nickname, st2.alertLevel,
t.refFk, st2.name,
t.id ticketFk, t.refFk,
t.clientFk, t.id ticketFk,
s.id saleFk, 'client' entityType,
st.`order`, t.clientFk entityId,
c.typeFk, t.nickname,
cb.claimFk s.id saleFk,
FROM vn.sale s st.`order`,
JOIN vn.ticket t ON t.id = s.ticketFk c.typeFk,
LEFT JOIN vn.ticketState ts ON ts.ticketFk = t.id cb.claimFk
LEFT JOIN vn.state st ON st.`code` = ts.`code` FROM vn.sale s
JOIN vn.client c ON c.id = t.clientFk JOIN vn.ticket t ON t.id = s.ticketFk
JOIN vn.state st2 ON st2.`code` = IF(t.shipped < util.VN_CURDATE(), LEFT JOIN vn.ticketState ts ON ts.ticketFk = t.id
'DELIVERED', LEFT JOIN vn.state st ON st.code = ts.code
IF (t.shipped > util.dayEnd(util.VN_CURDATE()), JOIN vn.client c ON c.id = t.clientFk
'FREE', JOIN vn.state st2 ON st2.`code` = IF(t.shipped < util.VN_CURDATE(),
IFNULL(ts.code, 'FREE'))) 'DELIVERED',
LEFT JOIN vn.claimBeginning cb ON s.id = cb.saleFk IF (t.shipped > util.dayEnd(util.VN_CURDATE()),
WHERE t.shipped >= vDateInventory 'FREE',
AND s.itemFk = vItemFk IFNULL(st.code, 'FREE')))
AND vWarehouseFk = t.warehouseFk LEFT JOIN vn.claimBeginning cb ON cb.saleFk = s.id
),sale AS ( WHERE t.shipped >= vDateInventory
SELECT s.shipped, AND s.itemFk = vItemFk
AND t.warehouseFk = vWarehouseFk
)
SELECT 'ticket',
s.ticketFk,
s.shipped,
NULL `in`, NULL `in`,
s.quantity, s.quantity,
s.alertLevel, s.alertLevel,
s.name, s.name,
s.nickname,
s.refFk, s.refFk,
s.ticketFk, s.entityType,
s.clientFk, s.entityId,
IF(stk.saleFk, TRUE, NULL), s.nickname,
IF(stk.saleFk, TRUE, FALSE),
TRUE, TRUE,
s.saleFk, s.saleFk,
s.`order`, s.`order`,
s.typeFk, s.typeFk,
s.claimFk, s.claimFk,
NULL NULL
FROM sales s FROM itemSales s
LEFT JOIN vn.state stPrep ON stPrep.`code` = 'PREPARED' LEFT JOIN vn.state stPrep ON stPrep.`code` = 'PREPARED'
LEFT JOIN vn.saleTracking stk ON stk.saleFk = s.saleFk LEFT JOIN vn.saleTracking stk ON stk.saleFk = s.saleFk
AND stk.stateFk = stPrep.id AND stk.stateFk = stPrep.id
GROUP BY s.saleFk GROUP BY s.saleFk
) SELECT shipped, ),
`in`, orders AS (
`out`, SELECT 'order' originType,
alertLevel, o.id originId,
stateName, r.shipment,
`name`, NULL 'in',
reference, r.amount,
origin, NULL alertLevel,
clientFk, NULL stateName,
isPicked, NULL invoiceNumber,
isTicket, 'client' entityType,
lineFk, c.id,
`order`, c.name,
clientType, FALSE,
claimFk, FALSE isTicket,
inventorySupplierFk NULL buyFk,
FROM entriesIn NULL 'order',
c.typeFk,
NULL claimFk,
NULL
FROM hedera.orderRow r
JOIN hedera.`order` o ON o.id = r.orderFk
JOIN vn.client c ON c.id = o.customer_id
WHERE r.shipment >= vDateInventory
AND r.warehouseFk = vWarehouseFk
AND r.created >= (
SELECT SUBTIME(util.VN_NOW(), reserveTime)
FROM hedera.orderConfig
)
AND NOT o.confirmed
AND r.itemFk = vItemFk
)
SELECT * FROM entriesIn
UNION ALL UNION ALL
SELECT * FROM entriesOut SELECT * FROM entriesOut
UNION ALL UNION ALL
SELECT * FROM sale SELECT * FROM sales
UNION ALL
SELECT * FROM orders
ORDER BY shipped, ORDER BY shipped,
(inventorySupplierFk = clientFk) DESC, (inventorySupplierFk = entityId) DESC,
alertLevel DESC, alertLevel DESC,
isTicket, isTicket,
`order` DESC, `order` DESC,
@ -186,19 +198,20 @@ BEGIN
`in` DESC, `in` DESC,
`out` DESC; `out` DESC;
IF vDate IS NULL THEN IF vDated IS NULL THEN
SET @a := 0; SET @a := 0;
SET @currentLineFk := 0; SET @currentLineFk := 0;
SET @shipped := ''; SET @shipped := '';
SELECT DATE(@shipped:= t.shipped) shipped, SELECT t.originType,
t.originId,
DATE(@shipped:= t.shipped) shipped,
t.alertLevel, t.alertLevel,
t.stateName, t.stateName,
t.origin,
t.reference, t.reference,
t.clientFk, t.entityType,
t.name, t.entityId,
t.entityName,
t.`in` invalue, t.`in` invalue,
t.`out`, t.`out`,
@a := @a + IFNULL(t.`in`, 0) - IFNULL(t.`out`, 0) balance, @a := @a + IFNULL(t.`in`, 0) - IFNULL(t.`out`, 0) balance,
@ -214,37 +227,41 @@ BEGIN
t.`order` t.`order`
FROM tItemDiary t FROM tItemDiary t
LEFT JOIN alertLevel a ON a.id = t.alertLevel; LEFT JOIN alertLevel a ON a.id = t.alertLevel;
ELSE ELSE
SELECT IFNULL(SUM(IFNULL(`in`, 0)) - SUM(IFNULL(`out`, 0)), 0) INTO @a SELECT IFNULL(SUM(IFNULL(`in`, 0)) - SUM(IFNULL(`out`, 0)), 0) INTO @a
FROM tItemDiary FROM tItemDiary
WHERE shipped < vDate; WHERE shipped < vDated;
SELECT vDate shipped, SELECT NULL originType,
0 alertLevel, NULL originId,
0 stateName, vDated shipped,
0 origin, NULL alertLevel,
'' reference, NULL stateName,
0 clientFk, NULL reference,
NULL entityType,
NULL entityId,
'Inventario calculado', 'Inventario calculado',
@a invalue, @a invalue,
NULL `out`, NULL `out`,
@a balance, @a balance,
0 lastPreparedLineFk, NULL lastPreparedLineFk,
0 isTicket, NULL isTicket,
0 lineFk, NULL lineFk,
0 isPicked, NULL isPicked,
0 clientType, NULL clientType,
0 claimFk, NULL claimFk,
NULL `order` NULL `order`
UNION ALL UNION ALL
SELECT shipped, SELECT originType,
originId,
shipped,
alertlevel, alertlevel,
stateName, stateName,
origin, reference,
reference, entityType,
clientFk, entityId,
name, `in`, entityName,
`in`,
`out`, `out`,
@a := @a + IFNULL(`in`, 0) - IFNULL(`out`, 0), @a := @a + IFNULL(`in`, 0) - IFNULL(`out`, 0),
0, 0,
@ -255,7 +272,7 @@ BEGIN
claimFk, claimFk,
`order` `order`
FROM tItemDiary FROM tItemDiary
WHERE shipped >= vDate; WHERE shipped >= vDated;
END IF; END IF;
DROP TEMPORARY TABLE tItemDiary; DROP TEMPORARY TABLE tItemDiary;

View File

@ -63,7 +63,7 @@ BEGIN
WHEN b.groupingMode = 'grouping' THEN b.grouping WHEN b.groupingMode = 'grouping' THEN b.grouping
WHEN b.groupingMode = 'packing' THEN b.packing WHEN b.groupingMode = 'packing' THEN b.packing
ELSE 1 ELSE 1
END AS minQuantity, END minQuantity,
v.visible located, v.visible located,
b.price2 b.price2
FROM vn.item i FROM vn.item i

View File

@ -1,17 +1,25 @@
DELIMITER $$ DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`saleGroup_setParking`(IN `vSaleGroupFk` VARCHAR(8), IN `vParkingFk` INT) CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`saleGroup_setParking`(
proc: BEGIN vSaleGroupFk VARCHAR(8),
vParkingFk INT
)
BEGIN
/** /**
* Aparca una preparación previa en un parking * Aparca una preparación previa en un parking.
* *
* @param vSaleGroupFk id de la preparación previa * @param vSaleGroupFk id de la preparación previa
* @param vParkingFk id del parking * @param vParkingFk id del parking
*/ */
UPDATE vn.saleGroup sg DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
RESIGNAL;
END;
UPDATE saleGroup sg
SET sg.parkingFk = vParkingFk SET sg.parkingFk = vParkingFk
WHERE sg.id = vSaleGroupFk WHERE sg.id = vSaleGroupFk
AND sg.created >= TIMESTAMPADD(WEEK,-1,util.VN_CURDATE()); AND sg.created >= util.VN_CURDATE() - INTERVAL 1 WEEK;
CALL vn.ticket_setNextState(vn.ticket_get(vSaleGroupFk)); CALL ticket_setNextState(ticket_get(vSaleGroupFk));
END$$ END$$
DELIMITER ; DELIMITER ;

View File

@ -1,6 +1,9 @@
DELIMITER $$ DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`setParking`(IN `vParam` VARCHAR(8), IN `vParkingCode` VARCHAR(8)) CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`setParking`(
proc: BEGIN vParam VARCHAR(8),
vParkingCode VARCHAR(8)
)
BEGIN
/** /**
* Aparca una colección, un ticket, un saleGroup o un shelving en un parking * Aparca una colección, un ticket, un saleGroup o un shelving en un parking
* *
@ -8,56 +11,41 @@ proc: BEGIN
* @param vParkingCode código del parking * @param vParkingCode código del parking
*/ */
DECLARE vParkingFk INT; DECLARE vParkingFk INT;
DECLARE vIsSaleGroup BOOL; DECLARE vLastWeek DATE;
DECLARE vIsTicket BOOL;
DECLARE vIsCollection BOOL;
SET vParkingCode = replace(vParkingCode,' ',''); DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
RESIGNAL;
END;
SET vParkingCode = REPLACE(vParkingCode, ' ', '');
SELECT id INTO vParkingFk SELECT id INTO vParkingFk
FROM vn.parking FROM parking
WHERE code = vParkingCode COLLATE utf8_unicode_ci; WHERE code = vParkingCode COLLATE utf8_unicode_ci;
IF vParkingFk IS NULL THEN IF vParkingFk IS NULL THEN
CALL util.throw('parkingNotExist'); CALL util.throw('parkingNotExist');
LEAVE proc;
END IF; END IF;
IF vParam REGEXP '^[0-9]+$' THEN
-- Se comprueba si es una preparación previa
SELECT COUNT(*) INTO vIsSaleGroup
FROM vn.saleGroup sg
WHERE sg.id = vParam;
IF vIsSaleGroup THEN START TRANSACTION;
CALL vn.saleGroup_setParking(vParam, vParkingFk);
LEAVE proc;
END IF;
-- Se comprueba si es un ticket SET vLastWeek = util.VN_CURDATE() - INTERVAL 1 WEEK;
SELECT COUNT(*) INTO vIsTicket
FROM vn.ticket t
WHERE t.id = vParam
AND t.shipped >= TIMESTAMPADD(WEEK,-1,util.VN_CURDATE());
IF vIsTicket THEN -- Comprobamos si es una prep. previa, ticket, colección o shelving
CALL vn.ticket_setParking(vParam, vParkingFk); IF (SELECT TRUE FROM saleGroup WHERE id = vParam) THEN
LEAVE proc; CALL saleGroup_setParking(vParam, vParkingFk);
END IF; ELSEIF (SELECT TRUE FROM ticket WHERE id = vParam AND shipped >= vLastWeek) THEN
CALL ticket_setParking(vParam, vParkingFk);
-- Se comprueba si es una coleccion de tickets ELSEIF (SELECT TRUE FROM `collection` WHERE id = vParam AND created >= vLastWeek) THEN
SELECT COUNT(*) INTO vIsCollection CALL collection_setParking(vParam, vParkingFk);
FROM vn.collection c ELSEIF (SELECT TRUE FROM shelving WHERE code = vParam COLLATE utf8_unicode_ci) THEN
WHERE c.id = vParam CALL shelving_setParking(vParam, vParkingFk);
AND c.created >= TIMESTAMPADD(WEEK,-1,util.VN_CURDATE());
IF vIsCollection THEN
CALL vn.collection_setParking(vParam, vParkingFk);
LEAVE proc;
END IF;
ELSE ELSE
-- Por descarte, se considera una matrícula CALL util.throw('paramNotExist');
CALL vn.shelving_setParking(vParam, vParkingFk);
END IF; END IF;
COMMIT;
END$$ END$$
DELIMITER ; DELIMITER ;

View File

@ -1,14 +1,21 @@
DELIMITER $$ DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticket_setNextState`(vSelf INT) CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticket_setNextState`(
vSelf INT
)
BEGIN BEGIN
/** /**
* Cambia el estado del ticket al siguiente estado según la tabla state * Cambia el estado del ticket al siguiente estado según la tabla state.
* *
* @param vSelf id dle ticket * @param vSelf Id ticket
*/ */
DECLARE vStateFk INT; DECLARE vStateFk INT;
DECLARE vNewStateFk INT; DECLARE vNewStateFk INT;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
RESIGNAL;
END;
SELECT stateFk INTO vStateFk SELECT stateFk INTO vStateFk
FROM ticketState FROM ticketState
WHERE ticketFk = vSelf; WHERE ticketFk = vSelf;
@ -17,6 +24,10 @@ BEGIN
FROM state FROM state
WHERE id = vStateFk; WHERE id = vStateFk;
IF vNewStateFk IS NULL THEN
CALL util.throw('The ticket not have next state');
END IF;
INSERT INTO ticketTracking(stateFk, ticketFk, userFk) INSERT INTO ticketTracking(stateFk, ticketFk, userFk)
VALUES (vNewStateFk, vSelf, account.myUser_getId()); VALUES (vNewStateFk, vSelf, account.myUser_getId());
END$$ END$$

View File

@ -1,11 +1,14 @@
DELIMITER $$ DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticket_setParking`(IN `vTicketFk` VARCHAR(8), IN `vParkingFk` INT) CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticket_setParking`(
proc: BEGIN vSelf INT,
vParkingFk INT
)
BEGIN
/** /**
* Aparca un ticket en un parking * Aparca un ticket en un parking.
* *
* @param vTicketFk id del ticket * @param vSelf Id ticket
* @param vParkingFk id del parking * @param vParkingFk Id parking
*/ */
DECLARE vDone INT DEFAULT FALSE; DECLARE vDone INT DEFAULT FALSE;
DECLARE vCollectionTicketFk INT; DECLARE vCollectionTicketFk INT;
@ -14,16 +17,21 @@ proc: BEGIN
FROM ticket t FROM ticket t
LEFT JOIN ticketCollection tc1 ON tc1.ticketFk = t.id LEFT JOIN ticketCollection tc1 ON tc1.ticketFk = t.id
LEFT JOIN ticketCollection tc2 ON tc2.collectionFk = tc1.collectionFk LEFT JOIN ticketCollection tc2 ON tc2.collectionFk = tc1.collectionFk
WHERE t.id = vTicketFk; WHERE t.id = vSelf;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE; DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
RESIGNAL;
END;
INSERT INTO vn.ticketParking(ticketFk, parkingFk) INSERT INTO vn.ticketParking(ticketFk, parkingFk)
SELECT IFNULL(tc2.ticketFk, t.id), vParkingFk SELECT IFNULL(tc2.ticketFk, t.id), vParkingFk
FROM ticket t FROM ticket t
LEFT JOIN ticketCollection tc1 ON tc1.ticketFk = t.id LEFT JOIN ticketCollection tc1 ON tc1.ticketFk = t.id
LEFT JOIN ticketCollection tc2 ON tc2.collectionFk = tc1.collectionFk LEFT JOIN ticketCollection tc2 ON tc2.collectionFk = tc1.collectionFk
WHERE t.id = vTicketFk WHERE t.id = vSelf
ON DUPLICATE KEY UPDATE parkingFk = vParkingFk; ON DUPLICATE KEY UPDATE parkingFk = vParkingFk;
OPEN vCursor; OPEN vCursor;

View File

@ -0,0 +1,12 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`itemMinimumQuantity_afterDelete`
AFTER DELETE ON `itemMinimumQuantity`
FOR EACH ROW
BEGIN
INSERT INTO itemLog
SET `action` = 'delete',
`changedModel` = 'ItemMinimumQuantity',
`changedModelId` = OLD.id,
`userFk` = account.myUser_getId();
END$$
DELIMITER ;

View File

@ -0,0 +1,8 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`itemMinimumQuantity_beforeInsert`
BEFORE INSERT ON `itemMinimumQuantity`
FOR EACH ROW
BEGIN
SET NEW.editorFk = account.myUser_getId();
END$$
DELIMITER ;

View File

@ -0,0 +1,8 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`itemMinimumQuantity_beforeUpdate`
BEFORE UPDATE ON `itemMinimumQuantity`
FOR EACH ROW
BEGIN
SET NEW.editorFk = account.myUser_getId();
END$$
DELIMITER ;

View File

@ -1,5 +1,5 @@
DELIMITER $$ DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`itemShelving _afterDelete` CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`itemShelving_afterDelete`
AFTER DELETE ON `itemShelving` AFTER DELETE ON `itemShelving`
FOR EACH ROW FOR EACH ROW
BEGIN BEGIN

View File

@ -54,8 +54,7 @@ AS SELECT `b`.`entryFk` AS `Id_Entrada`,
`i`.`packingOut` AS `packingOut`, `i`.`packingOut` AS `packingOut`,
`b`.`itemOriginalFk` AS `itemOriginalFk`, `b`.`itemOriginalFk` AS `itemOriginalFk`,
`io`.`longName` AS `itemOriginalName`, `io`.`longName` AS `itemOriginalName`,
`it`.`gramsMax` AS `gramsMax`, `it`.`gramsMax` AS `gramsMax`
`i`.`minQuantity` AS `minQuantity`
FROM ( FROM (
( (
( (

View File

@ -0,0 +1 @@
CREATE INDEX travel_landed_IDX USING BTREE ON vn.travel (landed DESC,warehouseInFk,warehouseOutFk);

View File

@ -0,0 +1,30 @@
ALTER TABLE vn.item CHANGE minQuantity minQuantity__ int(10) unsigned DEFAULT
NULL NULL COMMENT '@deprecated 2024-07-11 refs #7704 Cantidad mínima para una línea de venta';
CREATE TABLE `vn`.`itemMinimumQuantity` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`itemFk` int(10) NOT NULL,
`quantity` int(10) NOT NULL,
`started` date NOT NULL,
`ended` date DEFAULT NULL,
`warehouseFk` smallint(5) unsigned DEFAULT NULL,
`created` timestamp NOT NULL DEFAULT current_timestamp(),
`editorFk` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `itemMinimumQuantity_UNIQUE` (`itemFk`, `started`, `ended`, `warehouseFk`),
KEY `itemFk` (`itemFk`),
KEY `started` (`started`),
KEY `ended` (`ended`),
KEY `warehouseFk` (`warehouseFk`),
KEY `editorFk` (`editorFk`),
CONSTRAINT `itemMinimumQuantity_ibfk_1` FOREIGN KEY (`itemFk`) REFERENCES `item` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `itemMinimumQuantity_ibfk_2` FOREIGN KEY (`warehouseFk`) REFERENCES `warehouse` (`id`) ON UPDATE CASCADE,
CONSTRAINT `itemMinimumQuantity_ibfk_3` FOREIGN KEY (`editorFk`) REFERENCES `account`.`user` (`id`),
CONSTRAINT `itemMinimumQuantity_check_1` CHECK (`started` <= `ended`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
GRANT SELECT, UPDATE, DELETE, INSERT ON TABLE vn.itemMinimumQuantity TO buyer;
GRANT EXECUTE ON PROCEDURE vn.ticketCalculatePurge TO guest;
ALTER TABLE vn.itemLog MODIFY COLUMN changedModel enum('Item','ItemBarcode','ItemBotanical','ItemNiche','ItemTag','ItemTaxCountry','ItemMinimumQuantity')
CHARACTER SET utf8mb3 COLLATE utf8mb3_unicode_ci DEFAULT 'Item' NOT NULL;

View File

@ -61,7 +61,7 @@ describe('item getBalance()', () => {
const secondItemBalance = await models.Item.getBalance(ctx, secondFilter, options); const secondItemBalance = await models.Item.getBalance(ctx, secondFilter, options);
expect(firstItemBalance[9].claimFk).toEqual(null); expect(firstItemBalance[9].claimFk).toEqual(null);
expect(secondItemBalance[7].claimFk).toEqual(2); expect(secondItemBalance[7].claimFk).toEqual(1);
await tx.rollback(); await tx.rollback();
} catch (e) { } catch (e) {

View File

@ -32,6 +32,9 @@
"ItemLog": { "ItemLog": {
"dataSource": "vn" "dataSource": "vn"
}, },
"ItemMinimumQuantity": {
"dataSource": "vn"
},
"ItemPackingType": { "ItemPackingType": {
"dataSource": "vn" "dataSource": "vn"
}, },

View File

@ -0,0 +1,63 @@
{
"name": "ItemMinimumQuantity",
"base": "VnModel",
"options": {
"mysql": {
"table": "itemMinimumQuantity"
}
},
"mixins": {
"Loggable": true
},
"properties": {
"id": {
"type": "number",
"id": true,
"description": "Id"
},
"itemFk": {
"type": "number",
"required": true
},
"quantity": {
"type": "number",
"required": true
},
"started": {
"type": "date",
"required": true
},
"ended": {
"type": "date"
},
"warehouseFk": {
"type": "number"
},
"created": {
"type": "date"
},
"editorFk": {
"type": "number"
}
},
"relations": {
"item": {
"type": "belongsTo",
"model": "Item",
"foreignKey": "itemFk"
},
"warehouse": {
"type": "belongsTo",
"model": "Warehouse",
"foreignKey": "warehouseFk"
}
},
"acls": [
{
"accessType": "READ",
"principalType": "ROLE",
"principalId": "buyer",
"permission": "ALLOW"
}
]
}

View File

@ -152,10 +152,6 @@
"columnName": "doPhoto" "columnName": "doPhoto"
} }
}, },
"minQuantity": {
"type": "number",
"description": "Min quantity"
},
"photoMotivation": { "photoMotivation": {
"type": "string" "type": "string"
} }

View File

@ -0,0 +1,101 @@
const {models} = require('vn-loopback/server/server');
describe('itemMinimumQuantity model', () => {
const itemFk = 5;
const warehouseFk = 60;
beforeAll(async() => {
await models.ItemMinimumQuantity.destroyAll({where: {itemFk: itemFk}});
});
describe('CRUD operations', () => {
it('should create a new itemMinimumQuantity record', async() => {
const newRecord = {
itemFk: itemFk,
quantity: 100,
started: Date.vnNew(),
ended: new Date(Date.vnNew().setFullYear(Date.vnNew().getFullYear() + 1)),
warehouseFk: warehouseFk
};
const createdRecord = await models.ItemMinimumQuantity.create(newRecord);
expect(createdRecord).toBeDefined();
expect(createdRecord.quantity).toEqual(newRecord.quantity);
});
it('should read an existing itemMinimumQuantity record', async() => {
const newRecord = {
itemFk: itemFk,
quantity: 100,
started: Date.vnNew(),
ended: new Date(Date.vnNew().setFullYear(Date.vnNew().getFullYear() + 2)),
warehouseFk: warehouseFk
};
await models.ItemMinimumQuantity.create(newRecord);
const existingRecord = await models.ItemMinimumQuantity.findOne({where: {itemFk: itemFk}});
expect(existingRecord).toBeDefined();
expect(existingRecord.itemFk).toEqual(itemFk);
});
it('should update an existing itemMinimumQuantity record', async() => {
const newRecord = {
itemFk: itemFk,
quantity: 100,
started: Date.vnNew(),
ended: new Date(Date.vnNew().setFullYear(Date.vnNew().getFullYear() + 3)),
warehouseFk: warehouseFk
};
await models.ItemMinimumQuantity.create(newRecord);
const newQuantity = 150;
const existingRecord = await models.ItemMinimumQuantity.findOne({where: {itemFk: itemFk}});
existingRecord.quantity = newQuantity;
await existingRecord.save();
const updatedRecord = await models.ItemMinimumQuantity.findOne({where: {itemFk: itemFk}});
expect(updatedRecord.quantity).toEqual(newQuantity);
});
});
describe('validation and constraints', () => {
it('should enforce unique constraint on itemFk, started, ended, and warehouseFk', async() => {
const newRecord = {
itemFk: itemFk,
quantity: 100,
started: Date.vnNew(),
ended: Date.vnNew().setFullYear(Date.vnNew().getFullYear() + 5),
warehouseFk: warehouseFk
};
try {
await models.ItemMinimumQuantity.create(newRecord);
await models.ItemMinimumQuantity.create(newRecord);
} catch (e) {
expect(e).toBeDefined();
expect(e.code).toContain('ER_DUP_ENTRY');
}
});
it('should allow null values for ended and warehouseFk', async() => {
const newRecord = {
itemFk: itemFk,
quantity: 100,
started: Date.vnNew(),
ended: null,
warehouseFk: null
};
const createdRecord = await models.ItemMinimumQuantity.create(newRecord);
expect(createdRecord).toBeDefined();
expect(createdRecord.ended).toBeNull();
expect(createdRecord.warehouseFk).toBeNull();
});
});
});

View File

@ -128,9 +128,6 @@
<vn-label-value label="Non recycled plastic" <vn-label-value label="Non recycled plastic"
value="{{$ctrl.summary.item.nonRecycledPlastic}}"> value="{{$ctrl.summary.item.nonRecycledPlastic}}">
</vn-label-value> </vn-label-value>
<vn-label-value label="Minimum sales quantity"
value="{{$ctrl.summary.item.minQuantity}}">
</vn-label-value>
</vn-one> </vn-one>
<vn-one name="tags"> <vn-one name="tags">
<h4 ng-show="$ctrl.isBuyer || $ctrl.isReplenisher"> <h4 ng-show="$ctrl.isBuyer || $ctrl.isReplenisher">

View File

@ -119,7 +119,7 @@ module.exports = Self => {
w.firstName, w.firstName,
tci.priceKg, tci.priceKg,
ink.hex, ink.hex,
i.minQuantity tci.minQuantity
FROM tmp.ticketCalculateItem tci FROM tmp.ticketCalculateItem tci
JOIN vn.item i ON i.id = tci.itemFk JOIN vn.item i ON i.id = tci.itemFk
JOIN vn.itemType it ON it.id = i.typeFk JOIN vn.itemType it ON it.id = i.typeFk
@ -158,21 +158,19 @@ module.exports = Self => {
// Apply item prices // Apply item prices
const pricesIndex = stmts.push( const pricesIndex = stmts.push(
`SELECT `SELECT tcp.itemFk,
tcp.itemFk,
tcp.grouping, tcp.grouping,
tcp.price, tcp.price,
tcp.rate, tcp.rate,
tcp.warehouseFk, tcp.warehouseFk,
tcp.priceKg, tcp.priceKg,
w.name AS warehouse w.name warehouse
FROM tmp.ticketComponentPrice tcp FROM tmp.ticketComponentPrice tcp
JOIN vn.warehouse w ON w.id = tcp.warehouseFk`) - 1; JOIN vn.warehouse w ON w.id = tcp.warehouseFk`) - 1;
// Get tags from all items // Get tags from all items
const itemTagsIndex = stmts.push( const itemTagsIndex = stmts.push(
`SELECT `SELECT t.id,
t.id,
t.name, t.name,
t.isFree, t.isFree,
t.sourceTable, t.sourceTable,

View File

@ -37,18 +37,18 @@
value="{{::item.value7}}"> value="{{::item.value7}}">
</vn-label-value> </vn-label-value>
</div> </div>
<vn-horizontal <vn-horizontal
class="text-right text-caption alert vn-mr-xs" class="text-right text-caption alert vn-mr-xs"
ng-if="::item.minQuantity"> ng-if="::item.minQuantity">
<vn-one> <vn-one>
<vn-icon <vn-icon
icon="production_quantity_limits" icon="production_quantity_limits"
translate-attr="{title: 'Minimal quantity'}" translate-attr="{title: 'Minimal quantity'}"
class="text-subtitle1"> class="text-subtitle1">
</vn-icon> </vn-icon>
</vn-one> </vn-one>
{{::item.minQuantity}} {{::item.minQuantity}}
</vn-horizontal> </vn-horizontal>
<div class="footer"> <div class="footer">
<div class="price"> <div class="price">
<vn-one> <vn-one>

View File

@ -1,2 +1 @@
Order created: Orden creada Order created: Orden creada
Minimal quantity: Cantidad mínima

View File

@ -65,7 +65,7 @@ module.exports = Self => {
throw new UserError('You can only add negative amounts in refund tickets'); throw new UserError('You can only add negative amounts in refund tickets');
const item = await models.Item.findOne({ const item = await models.Item.findOne({
fields: ['family', 'minQuantity'], fields: ['family'],
where: {id: itemId}, where: {id: itemId},
}, ctx.options); }, ctx.options);
if (item.family == 'EMB') return; if (item.family == 'EMB') return;
@ -88,7 +88,25 @@ module.exports = Self => {
if (await models.ACL.checkAccessAcl(ctx, 'Ticket', 'isRoleAdvanced', '*')) return; if (await models.ACL.checkAccessAcl(ctx, 'Ticket', 'isRoleAdvanced', '*')) return;
if (newQuantity < item.minQuantity && newQuantity != available) const minQuantity = await models.ItemMinimumQuantity.findOne({
fields: ['quantity'],
where: {
itemFk: itemId,
started: {lte: ticket.shipped},
or: [
{ended: {gte: ticket.shipped}},
{ended: null}
],
// eslint-disable-next-line no-dupe-keys
or: [
{warehouseFk: ticket.warehouseFk},
{warehouseFk: null}
]
},
limit: 1
}, ctx.options);
if (newQuantity < minQuantity?.quantity && newQuantity != available)
throw new UserError('The amount cannot be less than the minimum'); throw new UserError('The amount cannot be less than the minimum');
if (ctx.isNewInstance || isReduction) return; if (ctx.isNewInstance || isReduction) return;
@ -114,4 +132,3 @@ module.exports = Self => {
throw new UserError('The price of the item changed'); throw new UserError('The price of the item changed');
}); });
}; };

View File

@ -112,14 +112,10 @@ describe('sale model ', () => {
it('should throw an error if the quantity is less than the minimum quantity of the item', async() => { it('should throw an error if the quantity is less than the minimum quantity of the item', async() => {
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true)); spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true));
const itemId = 2;
const saleId = 17; const saleId = 17;
const minQuantity = 30; const newQuantity = 1;
const newQuantity = minQuantity - 1;
try { try {
const item = await models.Item.findById(itemId, null, opts);
await item.updateAttribute('minQuantity', minQuantity, opts);
spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, opts) => { spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, opts) => {
if (sqlStatement.includes('catalog_calcFromItem')) { if (sqlStatement.includes('catalog_calcFromItem')) {
sqlStatement = `CREATE OR REPLACE TEMPORARY TABLE tmp.ticketCalculateItem ENGINE = MEMORY sqlStatement = `CREATE OR REPLACE TEMPORARY TABLE tmp.ticketCalculateItem ENGINE = MEMORY
@ -138,13 +134,8 @@ describe('sale model ', () => {
it('should change quantity if has minimum quantity and new quantity is equal than item available', async() => { it('should change quantity if has minimum quantity and new quantity is equal than item available', async() => {
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true)); spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true));
const itemId = 2;
const saleId = 17; const saleId = 17;
const minQuantity = 30; const newQuantity = 8;
const newQuantity = minQuantity - 1;
const item = await models.Item.findById(itemId, null, opts);
await item.updateAttribute('minQuantity', minQuantity, opts);
spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, opts) => { spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, opts) => {
if (sqlStatement.includes('catalog_calcFromItem')) { if (sqlStatement.includes('catalog_calcFromItem')) {
@ -162,13 +153,9 @@ describe('sale model ', () => {
it('should increase quantity if you have enough available and the new price is the same as the previous one', async() => { it('should increase quantity if you have enough available and the new price is the same as the previous one', async() => {
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true)); spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true));
const itemId = 2;
const saleId = 17; const saleId = 17;
const minQuantity = 30;
const newQuantity = 31; const newQuantity = 31;
const item = await models.Item.findById(itemId, null, opts);
await item.updateAttribute('minQuantity', minQuantity, opts);
spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, opts) => { spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, opts) => {
if (sqlStatement.includes('catalog_calcFromItem')) { if (sqlStatement.includes('catalog_calcFromItem')) {
sqlStatement = ` sqlStatement = `
@ -185,13 +172,9 @@ describe('sale model ', () => {
it('should increase quantity when the new price is lower than the previous one', async() => { it('should increase quantity when the new price is lower than the previous one', async() => {
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true)); spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true));
const itemId = 2;
const saleId = 17; const saleId = 17;
const minQuantity = 30;
const newQuantity = 31; const newQuantity = 31;
const item = await models.Item.findById(itemId, null, opts);
await item.updateAttribute('minQuantity', minQuantity, opts);
spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, opts) => { spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, opts) => {
if (sqlStatement.includes('catalog_calcFromItem')) { if (sqlStatement.includes('catalog_calcFromItem')) {
sqlStatement = ` sqlStatement = `
@ -208,14 +191,10 @@ describe('sale model ', () => {
it('should throw error when increase quantity and the new price is higher than the previous one', async() => { it('should throw error when increase quantity and the new price is higher than the previous one', async() => {
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true)); spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true));
const itemId = 2;
const saleId = 17; const saleId = 17;
const minQuantity = 30;
const newQuantity = 31; const newQuantity = 31;
try { try {
const item = await models.Item.findById(itemId, null, opts);
await item.updateAttribute('minQuantity', minQuantity, opts);
spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, opts) => { spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, opts) => {
if (sqlStatement.includes('catalog_calcFromItem')) { if (sqlStatement.includes('catalog_calcFromItem')) {
sqlStatement = ` sqlStatement = `
@ -231,6 +210,48 @@ describe('sale model ', () => {
expect(e).toEqual(new Error('The price of the item changed')); expect(e).toEqual(new Error('The price of the item changed'));
} }
}); });
it('should throw an error if the quantity is lower than the minimum quantity of the item and is in range', async() => {
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true));
const saleId = 25;
const newQuantity = 5;
try {
spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, opts) => {
if (sqlStatement.includes('catalog_calcFromItem')) {
sqlStatement = `
CREATE OR REPLACE TEMPORARY TABLE tmp.ticketCalculateItem ENGINE = MEMORY SELECT ${newQuantity} as available;
CREATE OR REPLACE TEMPORARY TABLE tmp.ticketComponentPrice ENGINE = MEMORY SELECT 1 as grouping, 100000 as price;`;
params = null;
}
return models.Ticket.rawSql(sqlStatement, params, opts);
});
await models.Sale.updateQuantity(ctx, saleId, newQuantity, opts);
} catch (e) {
expect(e).toEqual(new Error('The amount cannot be less than the minimum'));
}
});
it('should update the quantity if the quantity is lower than the minimum quantity of the item and is out of the range', async() => {
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true));
const saleId = 17;
const newQuantity = 8;
spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, opts) => {
if (sqlStatement.includes('catalog_calcFromItem')) {
sqlStatement = `
CREATE OR REPLACE TEMPORARY TABLE tmp.ticketCalculateItem ENGINE = MEMORY SELECT ${newQuantity} as available;
CREATE OR REPLACE TEMPORARY TABLE tmp.ticketComponentPrice ENGINE = MEMORY SELECT 1 as grouping, 100000 as price;`;
params = null;
}
return models.Ticket.rawSql(sqlStatement, params, opts);
});
await models.Sale.updateQuantity(ctx, saleId, newQuantity, opts);
});
}); });
}); });