Compare commits

..

1 Commits
dev ... test

Author SHA1 Message Date
Alex Moreno 05af629a62 build: empty commit
gitea/salix/pipeline/head This commit looks good Details
2025-02-14 14:32:15 +01:00
96 changed files with 2685 additions and 5041 deletions

View File

@ -54,8 +54,7 @@
"type": "string"
},
"hasGrant": {
"type": "boolean",
"default": false
"type": "boolean"
},
"passExpired": {
"type": "date"
@ -169,7 +168,6 @@
"emailVerified",
"twoFactor"
]
}
}
}

View File

@ -77,8 +77,8 @@ INSERT INTO `vn`.`agency` (`name`, `warehouseFk`, `isOwn`, `isAnyVolumeAllowed`)
('Otra agencia ', '1', '0', '0');
INSERT INTO `vn`.`expedition` (`agencyModeFk`, `ticketFk`, `isBox`, `counter`, `workerFk`, `externalId`, `packagingFk`, `hostFk`, `itemPackingTypeFk`, `hasNewRoute`) VALUES
('1', '1', 1, '1', '1', '1', '1', 'pc1', 'F', 0),
('1', '1', 1, '2', '1', '1', '1', 'pc1', 'F', 0);
('1', '1', 1, '1', '1', '1', '1', 'pc00', 'F', 0),
('1', '1', 1, '2', '1', '1', '1', 'pc00', 'F', 0);
INSERT INTO vn.client (id,name,defaultAddressFk,street,fi,email,dueDay,isTaxDataChecked,accountingAccount,city,provinceFk,postcode,socialName,contact,credit,countryFk,quality,riskCalculated) VALUES
(100,'root',110,'Valle de la muerte','74974747G','root@mydomain.com',0,1,'4300000078','ALGEMESI',1,'46680','rootSocial','rootContact',500.0,1,10,'2025-01-01');

File diff suppressed because it is too large Load Diff

View File

@ -89,12 +89,12 @@ proc: BEGIN
AND (ir.ended IS NULL OR i.shipped <= ir.ended)
AND i.warehouseFk = vWarehouse
UNION ALL
SELECT i.itemFk, IFNULL(i.availabled, i.landed), i.quantity
SELECT i.itemFk, i.landed, i.quantity
FROM vn.itemEntryIn i
JOIN itemRange ir ON ir.itemFk = i.itemFk
WHERE IFNULL(i.availabled, i.landed) >= vStartDate
WHERE i.landed >= vStartDate
AND IFNULL(i.availabled, i.landed) <= vAvailabled
AND (ir.ended IS NULL OR IFNULL(i.availabled, i.landed) <= ir.ended)
AND (ir.ended IS NULL OR i.landed <= ir.ended)
AND i.warehouseInFk = vWarehouse
UNION ALL
SELECT i.itemFk, i.shipped, i.quantity

View File

@ -19,15 +19,13 @@ BEGIN
* @return tmp.ticketComponentPrice
*/
DECLARE vAvailableCalc INT;
DECLARE vAvailabled DATETIME;
DECLARE vDone BOOL;
DECLARE vHour INT;
DECLARE vAvailableNoRaidsCalc INT;
DECLARE vShipped DATE;
DECLARE vWarehouseFk SMALLINT;
DECLARE vZoneFk INT;
DECLARE vDone BOOL;
DECLARE cTravelTree CURSOR FOR
SELECT zoneFk, warehouseFk, shipped, `hour` FROM tmp.zoneGetShipped;
SELECT zoneFk, warehouseFk, shipped FROM tmp.zoneGetShipped;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE;
@ -68,15 +66,14 @@ BEGIN
OPEN cTravelTree;
l: LOOP
SET vDone = FALSE;
FETCH cTravelTree INTO vZoneFk, vWarehouseFk, vShipped, vHour;
SET vAvailabled = vShipped + INTERVAL HOUR(vHour) HOUR;
FETCH cTravelTree INTO vZoneFk, vWarehouseFk, vShipped;
IF vDone THEN
LEAVE l;
END IF;
CALL `cache`.available_refresh(vAvailableCalc, FALSE, vWarehouseFk, vAvailabled);
CALL `cache`.available_refresh(vAvailableCalc, FALSE, vWarehouseFk, vShipped);
CALL `cache`.availableNoRaids_refresh(vAvailableNoRaidsCalc, FALSE, vWarehouseFk, vShipped);
CALL buy_getUltimate(NULL, vWarehouseFk, vShipped);
INSERT INTO tmp.ticketLot (warehouseFk, itemFk, available, buyFk, zoneFk)
@ -86,10 +83,31 @@ BEGIN
bu.buyFk,
vZoneFk
FROM `cache`.available a
LEFT JOIN cache.availableNoRaids anr ON anr.item_id = a.item_id
AND anr.calc_id = vAvailableNoRaidsCalc
JOIN tmp.item i ON i.itemFk = a.item_id
JOIN item it ON it.id = i.itemFk
JOIN `zone` z ON z.id = vZoneFk
LEFT JOIN tmp.buyUltimate bu ON bu.itemFk = a.item_id
LEFT JOIN edi.supplyResponse sr ON sr.ID = it.supplyResponseFk
LEFT JOIN edi.VMPSettings v ON v.VMPID = sr.vmpID
LEFT JOIN edi.marketPlace mp ON mp.id = sr.MarketPlaceID
LEFT JOIN (SELECT isVNHSupplier, isEarlyBird, TRUE AS itemAllowed
FROM addressFilter af
JOIN (SELECT ad.provinceFk, p.countryFk, ad.isLogifloraAllowed
FROM address ad
JOIN province p ON p.id = ad.provinceFk
WHERE ad.id = vAddressFk
) sub2 ON sub2.provinceFk <=> IFNULL(af.provinceFk, sub2.provinceFk)
AND sub2.countryFk <=> IFNULL(af.countryFk, sub2.countryFk)
AND sub2.isLogifloraAllowed <=> IFNULL(af.isLogifloraAllowed, sub2.isLogifloraAllowed)
WHERE vWarehouseFk = af.warehouseFk
AND (vShipped < af.beforeDated
OR ISNULL(af.beforeDated)
OR vShipped > af.afterDated
OR ISNULL(af.afterDated))
) sub ON sub.isVNHSupplier = v.isVNHSupplier
AND (sub.isEarlyBird = mp.isEarlyBird OR ISNULL(sub.isEarlyBird))
JOIN agencyMode am ON am.id = vAgencyModeFk
JOIN agency ag ON ag.id = am.agencyFk
JOIN itemType itt ON itt.id = it.typeFk
@ -106,6 +124,7 @@ BEGIN
AND ait.itemTypeFk = itt.id
WHERE a.calc_id = vAvailableCalc
AND a.available > 0
AND (sub.itemAllowed OR NOT it.isFloramondo OR anr.available > 0)
AND (ag.isAnyVolumeAllowed OR NOT itt.isUnconventionalSize)
AND (it.`size` IS NULL
OR IF(itc.isReclining,

View File

@ -160,11 +160,9 @@ BEGIN
OR (NOT s.isPreparable AND NOT s.isPrintable)
OR pb.collectionH IS NOT NULL
OR pb.collectionV IS NOT NULL
OR pb.collectionA IS NOT NULL
OR pb.collectionN IS NOT NULL
OR (NOT pb.H AND pb.V + pb.A > 0 AND vItemPackingTypeFk = 'H')
OR (NOT pb.H AND pb.V > 0 AND vItemPackingTypeFk = 'H')
OR (NOT pb.V AND vItemPackingTypeFk = 'V')
OR (NOT pb.A AND vItemPackingTypeFk = 'A')
OR (pc.isPreviousPreparationRequired AND pb.previousWithoutParking)
OR LENGTH(pb.problem)
OR pb.lines > vLinesLimit

View File

@ -30,7 +30,7 @@ BEGIN
WITH entriesIn AS (
SELECT 'entry' originType,
e.id originId,
IFNULL(tr.availabled, tr.landed) shipped,
tr.landed shipped,
b.quantity `in`,
NULL `out`,
st.alertLevel ,
@ -54,7 +54,7 @@ BEGIN
OR (util.VN_CURDATE() AND tr.isReceived),
'DELIVERED',
'FREE')
WHERE IFNULL(tr.availabled, tr.landed) >= vDateInventory
WHERE tr.landed >= vDateInventory
AND tr.warehouseInFk = vWarehouseFk
AND (s.id <> vSupplierInventoryFk OR vDated IS NULL)
AND b.itemFk = vItemFk
@ -99,7 +99,7 @@ BEGIN
),
sales AS (
WITH itemSales AS (
SELECT DATE(t.shipped) + INTERVAL HOUR(z.`hour`) HOUR shipped,
SELECT DATE(t.shipped) shipped,
s.quantity,
st2.alertLevel,
st2.name,
@ -114,7 +114,6 @@ BEGIN
cb.claimFk
FROM vn.sale s
JOIN vn.ticket t ON t.id = s.ticketFk
JOIN vn.`zone` z ON z.id = t.zoneFk
LEFT JOIN vn.ticketState ts ON ts.ticketFk = t.id
LEFT JOIN vn.state st ON st.code = ts.code
JOIN vn.client c ON c.id = t.clientFk
@ -190,15 +189,14 @@ BEGIN
SELECT * FROM sales
UNION ALL
SELECT * FROM orders
ORDER BY DATE(shipped),
ORDER BY shipped,
(inventorySupplierFk = entityId) DESC,
alertLevel DESC,
isTicket,
`order` DESC,
isPicked DESC,
`in` DESC,
`out` DESC,
shipped;
`out` DESC;
IF vDated IS NULL THEN
SET @a := 0;
@ -207,7 +205,7 @@ BEGIN
SELECT t.originType,
t.originId,
@shipped:= t.shipped,
DATE(@shipped:= t.shipped) shipped,
t.alertLevel,
t.stateName,
t.reference,

View File

@ -1,20 +1,9 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`item_getLack`(
vSelf INT,
vForce BOOLEAN,
vDays INT,
vLongname VARCHAR(255),
vProducerName VARCHAR(255),
vColor VARCHAR(255),
vSize INT,
vOrigen INT,
vLack INT,
vWarehouseFk INT
)
CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`item_getLack`(IN vForce BOOLEAN, IN vDays INT)
BEGIN
/**
* Calcula una tabla con el máximo negativo visible para cada producto y almacen
*
*
* @param vForce Fuerza el recalculo del stock
* @param vDays Numero de dias a considerar
**/
@ -24,33 +13,33 @@ BEGIN
CALL item_getMinETD();
CALL item_zoneClosure();
SELECT i.id itemFk,
SELECT i.id itemFk,
i.longName,
w.id warehouseFk,
p.`name` producer,
p.`name` producer,
i.`size`,
i.category,
w.name warehouse,
w.name warehouse,
SUM(IFNULL(sub.amount,0)) lack,
i.inkFk,
IFNULL(im.timed, util.midnight()) timed,
IFNULL(izc.timed, util.midnight()) minTimed,
o.name originFk
FROM (SELECT item_id,
warehouse_id,
FROM (SELECT item_id,
warehouse_id,
amount
FROM cache.stock
WHERE amount > 0
UNION ALL
SELECT itemFk,
warehouseFk,
SELECT itemFk,
warehouseFk,
amount
FROM tmp.itemMinacum
) sub
JOIN warehouse w ON w.id = sub.warehouse_id
JOIN item i ON i.id = sub.item_id
LEFT JOIN producer p ON p.id = i.producerFk
JOIN itemType it ON it.id = i.typeFk
LEFT JOIN producer p ON p.id = i.producerFk
JOIN itemType it ON it.id = i.typeFk
JOIN itemCategory ic ON ic.id = it.categoryFk
LEFT JOIN tmp.itemMinETD im ON im.itemFk = i.id
LEFT JOIN tmp.itemZoneClosure izc ON izc.itemFk = i.id
@ -58,14 +47,6 @@ BEGIN
WHERE w.isForTicket
AND ic.display
AND it.code != 'GEN'
AND (vSelf IS NULL OR i.id = vSelf)
AND (vLongname IS NULL OR i.name = vLongname)
AND (vProducerName IS NULL OR p.`name` LIKE CONCAT('%', vProducerName, '%'))
AND (vColor IS NULL OR vColor = i.inkFk)
AND (vSize IS NULL OR vSize = i.`size`)
AND (vOrigen IS NULL OR vOrigen = w.id)
AND (vLack IS NULL OR vLack = sub.amount)
AND (vWarehouseFk IS NULL OR vWarehouseFk = w.id)
GROUP BY i.id, w.id
HAVING lack < 0;

View File

@ -82,26 +82,21 @@ BEGIN
AND it.priority = vPriority
LEFT JOIN vn.tag t ON t.id = it.tagFk
LEFT JOIN vn.buy b ON b.id = bu.buyFk
LEFT JOIN vn.itemShelvingStock iss ON iss.itemFk = i.id
AND iss.warehouseFk = vWarehouseFk
LEFT JOIN vn.ink ink ON ink.id = i.tag5
JOIN itemTags its
WHERE a.available > 0
AND (i.typeFk = its.typeFk OR NOT vShowType)
AND i.id <> vSelf
ORDER BY (a.available > 0) DESC,
`counter` DESC,
(t.name = its.name) DESC,
(it.value = its.value) DESC,
(i.tag5 = its.tag5) DESC,
(ink.`showOrder`) DESC,
match5 DESC,
(i.tag6 = its.tag6) DESC,
match6 DESC,
(i.tag7 = its.tag7) DESC,
match7 DESC,
(i.tag8 = its.tag8) DESC,
match8 DESC
ORDER BY `counter` DESC,
(t.name = its.name) DESC,
(it.value = its.value) DESC,
(i.tag5 = its.tag5) DESC,
match5 DESC,
(i.tag6 = its.tag6) DESC,
match6 DESC,
(i.tag7 = its.tag7) DESC,
match7 DESC,
(i.tag8 = its.tag8) DESC,
match8 DESC
LIMIT 100;
DROP TEMPORARY TABLE tmp.buyUltimate;

View File

@ -35,8 +35,8 @@ BEGIN
SELECT iei.itemFk, iei.quantity
FROM itemEntryIn iei
JOIN item i ON i.id = iei.itemFk
WHERE IFNULL(iei.availabled, iei.landed) >= util.VN_CURDATE()
AND IFNULL(iei.availabled, iei.landed) < vDated
WHERE iei.landed >= util.VN_CURDATE()
AND iei.landed < vDated
AND iei.warehouseInFk = vWarehouseFk
AND (vItemFk IS NULL OR iei.itemFk = vItemFk)
UNION ALL

View File

@ -1,18 +1,16 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`prepareTicketList`(
vStartingDate DATETIME,
vEndingDate DATETIME
)
CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`prepareTicketList`(vStartingDate DATETIME, vEndingDate DATETIME)
BEGIN
DROP TEMPORARY TABLE IF EXISTS tmp.productionTicket;
CREATE TEMPORARY TABLE tmp.productionTicket
(PRIMARY KEY (ticketFk))
ENGINE = MEMORY
SELECT t.id ticketFk
SELECT t.id ticketFk, t.clientFk
FROM ticket t
JOIN alertLevel al ON al.code = 'DELIVERED'
LEFT JOIN ticketState ts ON ts.ticketFk = t.id
JOIN client c ON c.id = t.clientFk
WHERE c.typeFk IN ('normal','handMaking','internalUse')
AND (
t.shipped BETWEEN util.VN_CURDATE() AND vEndingDate

View File

@ -24,31 +24,24 @@ proc: BEGIN
CALL prepareTicketList(util.yesterday(), vEndingDate);
CREATE OR REPLACE TEMPORARY TABLE tmp.ticket
SELECT * FROM tmp.productionTicket;
CALL prepareClientList();
CREATE OR REPLACE TEMPORARY TABLE tmp.sale_getProblems
(INDEX (ticketFk))
ENGINE = MEMORY
SELECT ticketFk
FROM tmp.productionTicket;
SELECT tt.ticketFk, tt.clientFk, t.warehouseFk, t.shipped
FROM tmp.productionTicket tt
JOIN ticket t ON t.id = tt.ticketFk;
CALL ticket_getProblems(vIsTodayRelative);
CREATE OR REPLACE TEMPORARY TABLE tmp.productionBuffer
(PRIMARY KEY(ticketFk), previaParking VARCHAR(255))
ENGINE = MEMORY
WITH saleProblemsDescription AS(
SELECT s.ticketFk,
LEFT(CONCAT('F: ', GROUP_CONCAT(CONCAT(i.id, ' ', i.longName) SEPARATOR ', ')), 250) itemShortage,
LEFT(CONCAT('R: ', GROUP_CONCAT(CONCAT(i2.id, ' ', i2.longName) SEPARATOR ', ')), 250) itemDelay,
LEFT(CONCAT('I: ', GROUP_CONCAT(CONCAT(i3.id, ' ', i3.longName) SEPARATOR ', ')), 250) itemLost
FROM tmp.saleProblems sp
JOIN vn.sale s ON s.id = sp.saleFk
LEFT JOIN vn.item i ON i.id = s.itemFk AND sp.hasItemShortage
LEFT JOIN vn.item i2 ON i2.id = s.itemFk AND sp.hasItemDelay
LEFT JOIN vn.item i3 ON i3.id = s.itemFk AND sp.hasItemLost
WHERE hasItemShortage OR hasItemDelay OR hasItemLost
GROUP BY s.ticketFk
)
SELECT tt.ticketFk,
t.clientFk,
tt.clientFk,
t.warehouseFk,
t.nickname,
t.packages,
@ -66,17 +59,7 @@ proc: BEGIN
0 `lines`,
CAST( 0 AS DECIMAL(5,2)) m3,
CAST( 0 AS DECIMAL(5,2)) preparationRate,
TRIM(CAST(CONCAT( IFNULL(sp.itemShortage, ''),
IFNULL(sp.itemDelay, ''),
IFNULL(sp.itemLost, ''),
IF(tpr.isFreezed, ' CONGELADO',''),
IF(tpr.hasHighRisk, ' RIESGO',''),
IF(tpr.hasTicketRequest, ' COD 100',''),
IF(tpr.isTaxDataChecked, '',' FICHA INCOMPLETA'),
IF(tpr.hasComponentLack, ' COMPONENTES', ''),
IF(HOUR(util.VN_NOW()) < IF(HOUR(t.shipped), HOUR(t.shipped), COALESCE(HOUR(zc.hour),HOUR(z.hour)))
AND tpr.isTooLittle, ' PEQUEÑO', '')
) AS char(255))) problem,
"" problem,
IFNULL(tls.state,2) state,
w.code workerCode,
DATE(t.shipped) shipped,
@ -91,37 +74,34 @@ proc: BEGIN
pk.code parking,
0 H,
0 V,
0 A,
0 N,
st.isOk,
ag.isOwn,
rm.bufferFk
FROM tmp.productionTicket tt
JOIN vn.ticket t ON tt.ticketFk = t.id
JOIN vn.alertLevel al ON al.code = 'FREE'
LEFT JOIN vn.ticketStateToday tst ON tst.ticketFk = t.id
LEFT JOIN vn.`state` st ON st.id = tst.state
LEFT JOIN vn.client c ON c.id = t.clientFk
LEFT JOIN vn.worker wk ON wk.id = c.salesPersonFk
JOIN vn.address a ON a.id = t.addressFk
LEFT JOIN vn.province p ON p.id = a.provinceFk
JOIN vn.agencyMode am ON am.id = t.agencyModeFk
JOIN vn.deliveryMethod dm ON dm.id = am.deliveryMethodFk
JOIN vn.agency ag ON ag.id = am.agencyFk
LEFT JOIN vn.ticketState tls ON tls.ticketFk = tt.ticketFk
LEFT JOIN vn.ticketLastUpdated tlu ON tlu.ticketFk = tt.ticketFk
LEFT JOIN vn.worker w ON w.id = tls.userFk
LEFT JOIN vn.routesMonitor rm ON rm.routeFk = t.routeFk
LEFT JOIN vn.`zone` z ON z.id = t.zoneFk
LEFT JOIN vn.zoneClosure zc ON zc.zoneFk = t.zoneFk
JOIN ticket t ON tt.ticketFk = t.id
JOIN alertLevel al ON al.code = 'FREE'
LEFT JOIN ticketStateToday tst ON tst.ticketFk = t.id
LEFT JOIN `state` st ON st.id = tst.state
LEFT JOIN client c ON c.id = t.clientFk
LEFT JOIN worker wk ON wk.id = c.salesPersonFk
JOIN address a ON a.id = t.addressFk
LEFT JOIN province p ON p.id = a.provinceFk
JOIN agencyMode am ON am.id = t.agencyModeFk
JOIN deliveryMethod dm ON dm.id = am.deliveryMethodFk
JOIN agency ag ON ag.id = am.agencyFk
LEFT JOIN ticketState tls ON tls.ticketFk = tt.ticketFk
LEFT JOIN ticketLastUpdated tlu ON tlu.ticketFk = tt.ticketFk
LEFT JOIN worker w ON w.id = tls.userFk
LEFT JOIN routesMonitor rm ON rm.routeFk = t.routeFk
LEFT JOIN `zone` z ON z.id = t.zoneFk
LEFT JOIN zoneClosure zc ON zc.zoneFk = t.zoneFk
AND DATE(t.shipped) = zc.dated
LEFT JOIN vn.ticketParking tp ON tp.ticketFk = t.id
LEFT JOIN vn.parking pk ON pk.id = tp.parkingFk
LEFT JOIN tmp.ticketProblems tpr ON tpr.ticketFk = tt.ticketFk
LEFT JOIN saleProblemsDescription sp ON sp.ticketFk = tt.ticketFk
LEFT JOIN ticketParking tp ON tp.ticketFk = t.id
LEFT JOIN parking pk ON pk.id = tp.parkingFk
WHERE t.warehouseFk = vWarehouseFk
AND dm.code IN ('AGENCY', 'DELIVERY', 'PICKUP');
UPDATE tmp.productionBuffer pb
JOIN (
SELECT pb.ticketFk, GROUP_CONCAT(p.code) previaParking
@ -139,9 +119,21 @@ proc: BEGIN
CHANGE COLUMN `problem` `problem` VARCHAR(255),
ADD COLUMN `collectionH` INT,
ADD COLUMN `collectionV` INT,
ADD COLUMN `collectionA` INT,
ADD COLUMN `collectionN` INT;
UPDATE tmp.productionBuffer pb
JOIN tmp.ticket_problems tp ON tp.ticketFk = pb.ticketFk
SET pb.problem = TRIM(CAST(CONCAT( IFNULL(tp.itemShortage, ''),
IFNULL(tp.itemDelay, ''),
IFNULL(tp.itemLost, ''),
IF(tp.isFreezed, ' CONGELADO',''),
IF(tp.hasHighRisk, ' RIESGO',''),
IF(tp.hasTicketRequest, ' COD 100',''),
IF(tp.isTaxDataChecked, '',' FICHA INCOMPLETA'),
IF(tp.hasComponentLack, ' COMPONENTES', ''),
IF(HOUR(util.VN_NOW()) < pb.HH AND tp.isTooLittle, ' PEQUEÑO', '')
) AS char(255)));
-- Clientes Nuevos o Recuperados
UPDATE tmp.productionBuffer pb
LEFT JOIN bs.clientNewBorn cnb ON cnb.clientFk = pb.clientFk
@ -180,14 +172,12 @@ proc: BEGIN
ENGINE = MEMORY
SELECT ticketFk,
SUM(sub.H) H,
SUM(sub.V) V,
SUM(sub.A) A,
SUM(sub.V) V,
SUM(sub.N) N
FROM (
SELECT t.ticketFk,
SUM(i.itemPackingTypeFk = 'H') H,
SUM(i.itemPackingTypeFk = 'V') V,
SUM(i.itemPackingTypeFk = 'A') A,
SUM(i.itemPackingTypeFk IS NULL) N
FROM tmp.productionTicket t
JOIN sale s ON s.ticketFk = t.ticketFk
@ -200,7 +190,6 @@ proc: BEGIN
JOIN tItemPackingType ti ON ti.ticketFk = pb.ticketFk
SET pb.H = ti.H,
pb.V = ti.V,
pb.A = ti.A,
pb.N = ti.N;
-- Colecciones segun tipo de encajado
@ -208,7 +197,6 @@ proc: BEGIN
JOIN ticketCollection tc ON pb.ticketFk = tc.ticketFk
SET pb.collectionH = IF(pb.H, tc.collectionFk, NULL),
pb.collectionV = IF(pb.V, tc.collectionFk, NULL),
pb.collectionA = IF(pb.A, tc.collectionFk, NULL),
pb.collectionN = IF(pb.N, tc.collectionFk, NULL);
-- Previa pendiente
@ -290,8 +278,7 @@ proc: BEGIN
DROP TEMPORARY TABLE
tmp.productionTicket,
tmp.ticket,
tmp.ticketProblems,
tmp.saleProblems,
tmp.ticket_problems,
tmp.ticketWithPrevia,
tItemShelvingStock,
tItemPackingType;

View File

@ -1,42 +1,86 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`sale_getProblems`(
vIsTodayRelative TINYINT(1)
vIsTodayRelative tinyint(1)
)
BEGIN
/**
* Calcula los problemas para un conjunto de sale
* Calcula los problemas de cada venta para un conjunto de tickets.
*
* @param vIsTodayRelative Indica si se calcula el disponible como si todo saliera hoy
* @table tmp.sale(saleFk) Identificadores de los sale a calcular
* @return tmp.saleProblems
* @table tmp.sale_getProblems(ticketFk, clientFk, warehouseFk, shipped) Tickets a calcular
* @return tmp.sale_problems
*/
DECLARE vWarehouseFk INT;
DECLARE vWarehouseFk INT;
DECLARE vDate DATE;
DECLARE vAvailableCache INT;
DECLARE vAvailableCache INT;
DECLARE vVisibleCache INT;
DECLARE vDone BOOL;
DECLARE vCursor CURSOR FOR
SELECT t.warehouseFk, IF(vIsTodayRelative, util.VN_CURDATE(), DATE(t.shipped)) dated
FROM tmp.sale ts
JOIN sale s ON s.id = ts.saleFk
JOIN ticket t ON t.id = s.ticketFk
WHERE t.shipped BETWEEN util.VN_CURDATE()
AND util.dayEnd(util.VN_CURDATE() + INTERVAL IF(vIsTodayRelative, 9.9, 1.9) DAY)
GROUP BY warehouseFk, dated;
DECLARE vCursor CURSOR FOR
SELECT DISTINCT warehouseFk, IF(vIsTodayRelative, util.VN_CURDATE(), DATE(shipped))
FROM tmp.sale_getProblems
WHERE shipped BETWEEN util.VN_CURDATE()
AND util.dayEnd(util.VN_CURDATE() + INTERVAL IF(vIsTodayRelative, 9.9, 1.9) DAY);
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE;
CREATE OR REPLACE TEMPORARY TABLE tmp.saleProblems(
CREATE OR REPLACE TEMPORARY TABLE tmp.sale_problems (
ticketFk INT(11),
saleFk INT(11),
hasItemShortage BOOL DEFAULT FALSE,
hasItemLost BOOL DEFAULT FALSE,
hasComponentLack BOOL DEFAULT FALSE,
hasItemDelay BOOL DEFAULT FALSE,
hasRounding BOOL DEFAULT FALSE,
PRIMARY KEY (saleFk)
) ENGINE = MEMORY;
isFreezed INTEGER(1) DEFAULT 0,
risk DECIMAL(10,1) DEFAULT 0,
hasRisk TINYINT(1) DEFAULT 0,
hasHighRisk TINYINT(1) DEFAULT 0,
hasTicketRequest INTEGER(1) DEFAULT 0,
itemShortage VARCHAR(255),
isTaxDataChecked INTEGER(1) DEFAULT 1,
itemDelay VARCHAR(255),
itemLost VARCHAR(255),
hasComponentLack INTEGER(1),
hasRounding VARCHAR(255),
isTooLittle BOOL DEFAULT FALSE,
isVip BOOL DEFAULT FALSE,
PRIMARY KEY (ticketFk, saleFk)
); -- No memory
CREATE OR REPLACE TEMPORARY TABLE tItemShelving
INSERT INTO tmp.sale_problems(ticketFk,
saleFk,
isFreezed,
risk,
hasRisk,
hasHighRisk,
hasTicketRequest,
isTaxDataChecked,
hasComponentLack,
isTooLittle)
SELECT sgp.ticketFk,
s.id,
IF(FIND_IN_SET('isFreezed', t.problem), TRUE, FALSE) isFreezed,
t.risk,
IF(FIND_IN_SET('hasRisk', t.problem), TRUE, FALSE) hasRisk,
IF(FIND_IN_SET('hasHighRisk', t.problem), TRUE, FALSE) hasHighRisk,
IF(FIND_IN_SET('hasTicketRequest', t.problem), TRUE, FALSE) hasTicketRequest,
IF(FIND_IN_SET('isTaxDataChecked', t.problem), FALSE, TRUE) isTaxDataChecked,
IF(FIND_IN_SET('hasComponentLack', s.problem), TRUE, FALSE) hasComponentLack,
IF(FIND_IN_SET('isTooLittle', t.problem)
AND util.VN_NOW() < (util.VN_CURDATE() + INTERVAL HOUR(zc.`hour`) HOUR) + INTERVAL MINUTE(zc.`hour`) MINUTE,
TRUE, FALSE) isTooLittle
FROM tmp.sale_getProblems sgp
JOIN ticket t ON t.id = sgp.ticketFk
LEFT JOIN sale s ON s.ticketFk = t.id
LEFT JOIN item i ON i.id = s.itemFk
LEFT JOIN zoneClosure zc ON zc.zoneFk = t.zoneFk
AND zc.dated = util.VN_CURDATE()
WHERE s.problem <> '' OR t.problem <> '' OR t.risk
GROUP BY t.id, s.id;
INSERT INTO tmp.sale_problems(ticketFk, isVip)
SELECT sgp.ticketFk, TRUE
FROM tmp.sale_getProblems sgp
JOIN client c ON c.id = sgp.clientFk
WHERE c.businessTypeFk = 'VIP'
ON DUPLICATE KEY UPDATE isVIP = TRUE;
CREATE OR REPLACE TEMPORARY TABLE tItemShelvingStock_byWarehouse
(INDEX (itemFk, warehouseFk))
ENGINE = MEMORY
SELECT ish.itemFk itemFk,
@ -48,14 +92,6 @@ BEGIN
JOIN sector s ON s.id = p.sectorFk
GROUP BY ish.itemFk, s.warehouseFk;
-- Componentes: Algún componente obligatorio no se ha calcualdo
INSERT INTO tmp.saleProblems(saleFk, hasComponentLack)
SELECT s.id, TRUE
FROM tmp.sale ts
JOIN sale s ON s.id = ts.saleFk
WHERE FIND_IN_SET('hasComponentLack', s.problem)
GROUP BY s.id;
-- Disponible, faltas, inventario y retrasos
OPEN vCursor;
l: LOOP
@ -68,112 +104,130 @@ BEGIN
-- Disponible: no va a haber suficiente producto para preparar todos los pedidos
CALL cache.available_refresh(vAvailableCache, FALSE, vWarehouseFk, vDate);
-- Faltas: visible, disponible y ubicado son menores que la cantidad vendida
-- Faltas: visible, disponible y ubicado son menores que la cantidad vendida
CALL cache.visible_refresh(vVisibleCache, FALSE, vWarehouseFk);
INSERT INTO tmp.saleProblems(saleFk, hasItemShortage)
SELECT s.id, TRUE
FROM tmp.sale ts
JOIN sale s ON s.id = ts.saleFk
JOIN ticket t ON t.id = s.ticketFk
JOIN item i ON i.id = s.itemFk
JOIN itemType it ON it.id = i.typeFk
JOIN itemCategory ic ON ic.id = it.categoryFk
LEFT JOIN cache.visible v ON v.item_id = i.id
AND v.calc_id = vVisibleCache
LEFT JOIN cache.available av ON av.item_id = i.id
AND av.calc_id = vAvailableCache
LEFT JOIN tItemShelving tis ON tis.itemFk = i.id
AND tis.warehouseFk = t.warehouseFk
WHERE (s.quantity > v.visible OR (s.quantity > 0 AND v.visible IS NULL))
AND (av.available < 0 OR av.available IS NULL)
AND (s.quantity > tis.visible OR tis.visible IS NULL)
AND NOT s.isPicked
AND NOT s.reserved
AND ic.merchandise
AND IF(vIsTodayRelative, TRUE, DATE(t.shipped) = vDate)
AND NOT i.generic
AND util.VN_CURDATE() = vDate
AND t.warehouseFk = vWarehouseFk
GROUP BY s.id
ON DUPLICATE KEY UPDATE hasItemShortage = TRUE;
INSERT INTO tmp.sale_problems(ticketFk, itemShortage, saleFk)
SELECT ticketFk, problem, saleFk
FROM (
SELECT sgp.ticketFk,
LEFT(CONCAT('F: ', GROUP_CONCAT(i.id, ' ', i.longName, ' ')), 250) problem,
s.id saleFk
FROM tmp.sale_getProblems sgp
JOIN ticket t ON t.id = sgp.ticketFk
JOIN sale s ON s.ticketFk = t.id
JOIN item i ON i.id = s.itemFk
JOIN itemType it ON it.id = i.typeFk
JOIN itemCategory ic ON ic.id = it.categoryFk
LEFT JOIN cache.visible v ON v.item_id = i.id
AND v.calc_id = vVisibleCache
LEFT JOIN cache.available av ON av.item_id = i.id
AND av.calc_id = vAvailableCache
LEFT JOIN tItemShelvingStock_byWarehouse issw ON issw.itemFk = i.id
AND issw.warehouseFk = t.warehouseFk
WHERE IFNULL(v.visible, 0) < s.quantity
AND IFNULL(av.available, 0) < 0
AND IFNULL(issw.visible, 0) < s.quantity
AND NOT s.isPicked
AND NOT s.reserved
AND ic.merchandise
AND IF(vIsTodayRelative, TRUE, DATE(t.shipped) = vDate)
AND NOT i.generic
AND util.VN_CURDATE() = vDate
AND t.warehouseFk = vWarehouseFk
GROUP BY sgp.ticketFk) sub
ON DUPLICATE KEY UPDATE itemShortage = sub.problem, saleFk = sub.saleFk;
-- Inventario: Visible suficiente, pero ubicado menor a la cantidad vendida
INSERT INTO tmp.saleProblems(saleFk, hasItemLost)
SELECT s.id, TRUE
FROM tmp.sale ts
JOIN sale s ON s.id = ts.saleFk
JOIN ticket t ON t.id = s.ticketFk
JOIN item i ON i.id = s.itemFk
JOIN itemType it ON it.id = i.typeFk
JOIN itemCategory ic ON ic.id = it.categoryFk
LEFT JOIN cache.visible v ON v.item_id = s.itemFk
AND v.calc_id = vVisibleCache
LEFT JOIN tItemShelving tis ON tis.itemFk = i.id
AND tis.warehouseFk = t.warehouseFk
WHERE (v.visible >= s.quantity OR v.visible IS NULL)
AND (s.quantity > tis.visible AND tis.visible IS NOT NULL)
AND s.quantity > 0
AND NOT s.isPicked
AND NOT s.reserved
AND ic.merchandise
AND IF(vIsTodayRelative, TRUE, DATE(t.shipped) = vDate)
AND NOT i.generic
AND util.VN_CURDATE() = vDate
AND t.warehouseFk = vWarehouseFk
GROUP BY s.id
ON DUPLICATE KEY UPDATE hasItemLost = TRUE;
INSERT INTO tmp.sale_problems(ticketFk, itemLost, saleFk)
SELECT ticketFk, problem, saleFk
FROM (
SELECT sgp.ticketFk,
LEFT(GROUP_CONCAT('I: ', i.id, ' ', i.longName, ' '), 250) problem,
s.id saleFk
FROM tmp.sale_getProblems sgp
JOIN ticket t ON t.id = sgp.ticketFk
JOIN sale s ON s.ticketFk = t.id
JOIN item i ON i.id = s.itemFk
JOIN itemType it ON it.id = i.typeFk
JOIN itemCategory ic ON ic.id = it.categoryFk
LEFT JOIN cache.visible v ON v.item_id = s.itemFk
AND v.calc_id = vVisibleCache
LEFT JOIN tItemShelvingStock_byWarehouse issw ON issw.itemFk = i.id
AND issw.warehouseFk = t.warehouseFk
WHERE IFNULL(v.visible, 0) >= s.quantity
AND IFNULL(issw.visible, 0) < s.quantity
AND s.quantity > 0
AND NOT s.isPicked
AND NOT s.reserved
AND ic.merchandise
AND IF(vIsTodayRelative, TRUE, DATE(t.shipped) = vDate)
AND NOT i.generic
AND util.VN_CURDATE() = vDate
AND t.warehouseFk = vWarehouseFk
GROUP BY sgp.ticketFk
) sub
ON DUPLICATE KEY UPDATE itemLost = sub.problem, saleFk = sub.saleFk;
-- Retraso: Disponible suficiente, pero no visible ni ubicado
INSERT INTO tmp.saleProblems(saleFk, hasItemDelay)
SELECT s.id, TRUE
FROM tmp.sale ts
JOIN sale s ON s.id = ts.saleFk
JOIN ticket t ON t.id = s.ticketFk
JOIN item i ON i.id = s.itemFk
JOIN itemType it ON it.id = i.typeFk
JOIN itemCategory ic ON ic.id = it.categoryFk
LEFT JOIN cache.visible v ON v.item_id = s.itemFk
AND v.calc_id = vVisibleCache
LEFT JOIN cache.available av ON av.item_id = i.id
AND av.calc_id = vAvailableCache
LEFT JOIN tItemShelving tis ON tis.itemFk = i.id
AND tis.warehouseFk = t.warehouseFk
WHERE (s.quantity > v.visible AND v.visible IS NULL)
AND (av.available >= 0 OR av.available IS NULL)
AND (s.quantity > tis.visible AND tis.visible IS NOT NULL)
AND s.quantity > 0
AND NOT s.isPicked
AND NOT s.reserved
AND ic.merchandise
AND IF(vIsTodayRelative, TRUE, DATE(t.shipped) = vDate)
AND NOT i.generic
AND util.VN_CURDATE() = vDate
AND t.warehouseFk = vWarehouseFk
GROUP BY s.id
ON DUPLICATE KEY UPDATE hasItemDelay = TRUE;
INSERT INTO tmp.sale_problems(ticketFk, itemDelay, saleFk)
SELECT ticketFk, problem, saleFk
FROM (
SELECT sgp.ticketFk,
LEFT(GROUP_CONCAT('R: ', i.id, ' ', i.longName, ' '), 250) problem,
s.id saleFk
FROM tmp.sale_getProblems sgp
JOIN ticket t ON t.id = sgp.ticketFk
JOIN sale s ON s.ticketFk = t.id
JOIN item i ON i.id = s.itemFk
JOIN itemType it ON it.id = i.typeFk
JOIN itemCategory ic ON ic.id = it.categoryFk
LEFT JOIN cache.visible v ON v.item_id = s.itemFk
AND v.calc_id = vVisibleCache
LEFT JOIN cache.available av ON av.item_id = i.id
AND av.calc_id = vAvailableCache
LEFT JOIN tItemShelvingStock_byWarehouse issw ON issw.itemFk = i.id
AND issw.warehouseFk = t.warehouseFk
WHERE IFNULL(v.visible, 0) < s.quantity
AND IFNULL(av.available, 0) >= 0
AND IFNULL(issw.visible, 0) < s.quantity
AND s.quantity > 0
AND NOT s.isPicked
AND NOT s.reserved
AND ic.merchandise
AND IF(vIsTodayRelative, TRUE, DATE(t.shipped) = vDate)
AND NOT i.generic
AND util.VN_CURDATE() = vDate
AND t.warehouseFk = vWarehouseFk
GROUP BY sgp.ticketFk
) sub
ON DUPLICATE KEY UPDATE itemDelay = sub.problem, saleFk = sub.saleFk;
-- Redondeo: cantidad incorrecta con respecto al grouping
-- Redondeo: cantidad incorrecta con respecto al grouping
CALL buy_getUltimate(NULL, vWarehouseFk, vDate);
INSERT INTO tmp.saleProblems(saleFk, hasRounding)
SELECT s.id, TRUE
FROM tmp.sale ts
JOIN sale s ON s.id = ts.saleFk
JOIN ticket t ON t.id = s.ticketFk
AND t.warehouseFk = vWarehouseFk
JOIN item i ON i.id = s.itemFk
JOIN tmp.buyUltimate bu ON bu.itemFk = s.itemFk
JOIN buy b ON b.id = bu.buyFk
WHERE MOD(s.quantity, b.`grouping`)
GROUP BY s.id
ON DUPLICATE KEY UPDATE hasRounding = TRUE;
INSERT INTO tmp.sale_problems(ticketFk, hasRounding, saleFk)
SELECT ticketFk, problem, saleFk
FROM (
SELECT sgp.ticketFk,
s.id saleFk,
LEFT(GROUP_CONCAT('RE: ',i.id, ' ', IFNULL(i.longName,'') SEPARATOR ', '), 250) problem
FROM tmp.sale_getProblems sgp
JOIN ticket t ON t.id = sgp.ticketFk
AND t.warehouseFk = vWarehouseFk
JOIN sale s ON s.ticketFk = sgp.ticketFk
JOIN item i ON i.id = s.itemFk
JOIN tmp.buyUltimate bu ON bu.itemFk = s.itemFk
JOIN buy b ON b.id = bu.buyFk
WHERE MOD(s.quantity, b.`grouping`)
GROUP BY sgp.ticketFk
)sub
ON DUPLICATE KEY UPDATE hasRounding = sub.problem, saleFk = sub.saleFk;
DROP TEMPORARY TABLE tmp.buyUltimate;
END LOOP;
CLOSE vCursor;
DROP TEMPORARY TABLE tItemShelving;
DROP TEMPORARY TABLE tItemShelvingStock_byWarehouse;
END$$
DELIMITER ;

View File

@ -1,25 +1,25 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`sale_getProblemsByTicket`(
IN vTicketFk INT,
IN vIsTodayRelative TINYINT(1)
)
CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`sale_getProblemsByTicket`(IN vTicketFk INT, IN vIsTodayRelative TINYINT(1))
BEGIN
/**
* Calcula los problemas de cada venta para un tickets.
* Calcula los problemas de cada venta
* para un conjunto de tickets.
*
* @return Problems result
*/
CREATE OR REPLACE TEMPORARY TABLE tmp.sale
(INDEX (saleFk))
ENGINE = MEMORY
SELECT id saleFk FROM sale WHERE ticketFk = vTicketFk;
CREATE OR REPLACE TEMPORARY TABLE tmp.sale_getProblems
(INDEX (ticketFk))
ENGINE = MEMORY
SELECT t.id ticketFk, t.clientFk, t.warehouseFk, t.shipped
FROM ticket t
WHERE t.id = vTicketFk;
CALL sale_getProblems(vIsTodayRelative);
CALL sale_getProblems(vIsTodayRelative);
SELECT * FROM tmp.saleProblems;
SELECT * FROM tmp.sale_problems;
DROP TEMPORARY TABLE
tmp.saleProblems,
tmp.sale;
DROP TEMPORARY TABLE
tmp.sale_getProblems,
tmp.sale_problems;
END$$
DELIMITER ;

View File

@ -25,11 +25,9 @@ BEGIN
DECLARE vNewSaleFk INT;
DECLARE vFinalPrice DECIMAL(10,2);
DECLARE vIsRequiredTx BOOL DEFAULT NOT @@in_transaction;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
CALL util.tx_rollback(vIsRequiredTx);
ROLLBACK;
RESIGNAL;
END;
@ -64,7 +62,7 @@ BEGIN
WHERE tmp.itemFk = vNewItemFk AND tmp.WarehouseFk = vWarehouseFk;
DROP TEMPORARY TABLE tmp.buyUltimate;
IF vGroupingMode = 'packing' AND vPacking > 0 THEN
SET vRoundQuantity = vPacking;
END IF;
@ -131,6 +129,6 @@ BEGIN
VALUES(vItemFk, vNewItemFk, 1)
ON DUPLICATE KEY UPDATE counter = counter + 1;
CALL util.tx_commit(vIsRequiredTx);
COMMIT;
END$$
DELIMITER ;

View File

@ -30,16 +30,11 @@ BEGIN
st.code stateCode,
sub2.code futureStateCode,
st.classColor,
sub2.classColor futureClassColor,
am.id agencyFk,
am.name agency,
sub2.agencyModeFk futureAgencyFk,
sub2.agencyMode futureAgency
sub2.classColor futureClassColor
FROM vn.saleVolume sv
JOIN vn.sale s ON s.id = sv.saleFk
JOIN vn.item i ON i.id = s.itemFk
JOIN vn.ticket t ON t.id = sv.ticketFk
JOIN vn.agencyMode am ON am.id = t.agencyModeFk
JOIN vn.address a ON a.id = t.addressFk
JOIN vn.province p ON p.id = a.provinceFk
JOIN vn.country c ON c.id = p.countryFk
@ -59,19 +54,16 @@ BEGIN
st.name state,
st.code,
st.classColor,
am.id agencyModeFk,
am.name agencyMode,
GROUP_CONCAT(DISTINCT i.itemPackingTypeFk ORDER BY i.itemPackingTypeFk) iptd
FROM vn.ticket t
JOIN vn.agencyMode am ON am.id = t.agencyModeFk
JOIN vn.ticketState ts ON ts.ticketFk = t.id
JOIN vn.state st ON st.id = ts.stateFk
JOIN vn.sale s ON s.ticketFk = t.id
JOIN vn.item i ON i.id = s.itemFk
WHERE t.shipped BETWEEN vFutureDated
AND util.dayend(vFutureDated)
AND t.warehouseFk = vWarehouseFk
GROUP BY t.id
FROM vn.ticket t
JOIN vn.ticketState ts ON ts.ticketFk = t.id
JOIN vn.state st ON st.id = ts.stateFk
JOIN vn.sale s ON s.ticketFk = t.id
JOIN vn.item i ON i.id = s.itemFk
WHERE t.shipped BETWEEN vFutureDated
AND util.dayend(vFutureDated)
AND t.warehouseFk = vWarehouseFk
GROUP BY t.id
) sub
GROUP BY sub.addressFk
) sub2 ON sub2.addressFk = t.addressFk AND t.id != sub2.id

View File

@ -1,109 +1,53 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`ticket_getProblems`(
vIsTodayRelative TINYINT(1)
vIsTodayRelative tinyint(1)
)
BEGIN
/**
* Calcula los problemas para un conjunto de tickets.
* Agrupados por ticket
*
* @param vIsTodayRelative Indica si se calcula el disponible como si todo saliera hoy
* @table tmp.ticket(ticketFk) Identificadores de los tickets a calcular
* @return tmp.ticketProblems, tmp.saleProblems
* @table tmp.sale_getProblems(ticketFk, clientFk, warehouseFk, shipped) Identificadores de los tickets a calcular
* @return tmp.ticket_problems
*/
CREATE OR REPLACE TEMPORARY TABLE tmp.sale (
saleFk INT(11),
PRIMARY KEY (saleFk)
) ENGINE = MEMORY
SELECT DISTINCT s.id saleFk
FROM tmp.ticket tt
JOIN ticket t ON t.id = tt.ticketFk
JOIN sale s ON s.ticketFk = t.id
GROUP BY s.id;
CALL sale_getProblems(vIsTodayRelative);
CREATE OR REPLACE TEMPORARY TABLE tmp.ticketProblems (
ticketFk INT(11),
isFreezed BOOL DEFAULT FALSE,
risk DECIMAL(10,1) DEFAULT 0,
hasRisk BOOL DEFAULT FALSE,
hasHighRisk BOOL DEFAULT FALSE,
hasTicketRequest BOOL DEFAULT FALSE,
isTaxDataChecked BOOL DEFAULT FALSE,
isTooLittle BOOL DEFAULT FALSE,
isVip BOOL DEFAULT FALSE,
hasItemShortage BOOL DEFAULT FALSE,
hasItemDelay BOOL DEFAULT FALSE,
hasItemLost BOOL DEFAULT FALSE,
hasComponentLack BOOL DEFAULT FALSE,
hasRounding BOOL DEFAULT FALSE,
PRIMARY KEY (ticketFk)
) ENGINE = MEMORY
WITH hasItemShortage AS(
SELECT s.ticketFk
FROM tmp.saleProblems sp
JOIN vn.sale s ON s.id = sp.saleFk
WHERE sp.hasItemShortage
GROUP BY s.ticketFk
),hasItemLost AS(
SELECT s.ticketFk
FROM tmp.saleProblems sp
JOIN vn.sale s ON s.id = sp.saleFk
WHERE sp.hasItemLost
GROUP BY s.ticketFk
),hasRounding AS(
SELECT s.ticketFk
FROM tmp.saleProblems sp
JOIN vn.sale s ON s.id = sp.saleFk
WHERE sp.hasRounding
GROUP BY s.ticketFk
), hasItemDelay AS(
SELECT s.ticketFk
FROM tmp.saleProblems sp
JOIN vn.sale s ON s.id = sp.saleFk
WHERE sp.hasItemDelay
GROUP BY s.ticketFk
), hasComponentLack AS(
SELECT s.ticketFk
FROM tmp.saleProblems sp
JOIN vn.sale s ON s.id = sp.saleFk
WHERE sp.hasComponentLack
GROUP BY s.ticketFk
)SELECT tt.ticketFk,
FIND_IN_SET('isFreezed', t.problem) > 0 isFreezed,
t.risk,
FIND_IN_SET('hasRisk', t.problem) > 0 hasRisk,
FIND_IN_SET('hasHighRisk', t.problem) > 0 hasHighRisk,
FIND_IN_SET('hasTicketRequest', t.problem) > 0 hasTicketRequest,
FIND_IN_SET('isTaxDataChecked', t.problem) > 0 isTaxDataChecked,
FIND_IN_SET('isTooLittle', t.problem) > 0
AND util.VN_NOW() < (util.VN_CURDATE() +
INTERVAL HOUR(zc.`hour`) HOUR) +
INTERVAL MINUTE(zc.`hour`) MINUTE isTooLittle,
c.businessTypeFk = 'VIP' isVip,
NOT (his.ticketFk IS NULL) hasItemShortage,
NOT (hid.ticketFk IS NULL) hasItemDelay,
NOT (hil.ticketFk IS NULL) hasItemLost,
NOT (hcl.ticketFk IS NULL) hasComponentLack,
NOT (hr.ticketFk IS NULL) hasRounding,
CREATE OR REPLACE TEMPORARY TABLE tmp.ticket_problems
(PRIMARY KEY (ticketFk))
ENGINE = MEMORY
SELECT ticketFk,
MAX(isFreezed) isFreezed,
MAX(risk) risk,
MAX(hasRisk) hasRisk,
MAX(hasHighRisk) hasHighRisk,
MAX(hasTicketRequest) hasTicketRequest,
MAX(itemShortage) itemShortage,
MIN(isTaxDataChecked) isTaxDataChecked,
MAX(hasComponentLack) hasComponentLack,
MAX(isTooLittle) isTooLittle,
MAX(itemDelay) itemDelay,
MAX(hasRounding) hasRounding,
MAX(itemLost) itemLost,
MAX(isVip) isVip,
0 totalProblems
FROM tmp.ticket tt
JOIN vn.ticket t ON t.id = tt.ticketFk
JOIN vn.client c ON c.id = t.clientFk
LEFT JOIN hasItemShortage his ON his.ticketFk = t.id
LEFT JOIN hasItemLost hil ON hil.ticketFk = t.id
LEFT JOIN hasRounding hr ON hr.ticketFk = t.id
LEFT JOIN hasItemDelay hid ON hid.ticketFk = t.id
LEFT JOIN hasComponentLack hcl ON hcl.ticketFk = t.id
LEFT JOIN vn.zoneClosure zc ON zc.zoneFk = t.zoneFk
AND zc.dated = util.VN_CURDATE()
GROUP BY t.id;
FROM tmp.sale_problems
GROUP BY ticketFk;
UPDATE tmp.ticketProblems
SET totalProblems = isFreezed + hasHighRisk + hasTicketRequest +
isTaxDataChecked + hasComponentLack + hasItemDelay +
isTooLittle + hasItemLost + hasRounding + hasItemShortage + isVip;
UPDATE tmp.ticket_problems
SET totalProblems = (
(isFreezed) +
(hasHighRisk) +
(hasTicketRequest) +
(!isTaxDataChecked) +
(hasComponentLack) +
(itemDelay IS NOT NULL) +
(isTooLittle) +
(itemLost IS NOT NULL) +
(hasRounding IS NOT NULL) +
(itemShortage IS NOT NULL) +
(isVip)
);
DROP TEMPORARY TABLE tmp.sale;
DROP TEMPORARY TABLE tmp.sale_problems;
END$$
DELIMITER ;

View File

@ -1,6 +0,0 @@
INSERT IGNORE INTO salix.ACL (model,property,accessType,permission,principalType,principalId)
VALUES
('Ticket','itemLack','READ','ALLOW','ROLE','employee'),
('Ticket','itemLackDetail','READ','ALLOW','ROLE','employee'),
('Ticket','split','WRITE','ALLOW','ROLE','employee'),
('Sale','replaceItem','WRITE','ALLOW','ROLE','employee');

View File

@ -1,2 +0,0 @@
ALTER TABLE vn.ticketConfig ADD lackAlertPrice int(11) DEFAULT 30 NOT NULL COMMENT 'Value to alert when item proposal exceed price';
ALTER TABLE vn.ticketConfig ADD lackScopeDays int(11) DEFAULT 2 NOT NULL COMMENT 'Number of days to look back for ticket with negatives';

View File

@ -1,3 +0,0 @@
-- Place your SQL code here
INSERT INTO salix.ACL (model,property,accessType,permission,principalType,principalId)
VALUES ('Ticket','getTicketProblems','READ','ALLOW','ROLE','employee');

View File

@ -1,2 +0,0 @@
-- Place your SQL code here
ALTER TABLE vn.claimConfig ADD IF NOT EXISTS daysToClaim int(11) NOT NULL DEFAULT 7 COMMENT 'Dias para reclamar';

View File

@ -1,23 +0,0 @@
CREATE TABLE vn.parkingCoordinates (
parkingFk int(11) NOT NULL,
x varchar(5) NOT NULL,
y varchar(5) NOT NULL,
z varchar(5) NOT NULL,
CONSTRAINT parkingCoordinates_pk PRIMARY KEY (parkingFk),
CONSTRAINT parkingCoordinates_parking_FK FOREIGN KEY (parkingFk) REFERENCES vn.parking(id) ON DELETE CASCADE ON UPDATE CASCADE
)
ENGINE=InnoDB
DEFAULT CHARSET=utf8mb3
COLLATE=utf8mb3_unicode_ci;
INSERT INTO vn.parkingCoordinates (parkingFk, x, y, z)
SELECT id, `column`, `row`, `floor`
FROM vn.parking
WHERE `column` IS NOT NULL
OR `row` IS NOT NULL
OR `floor` IS NOT NULL;
ALTER TABLE vn.parking
DROP COLUMN `column`,
DROP COLUMN `row`,
DROP COLUMN `floor`;

View File

@ -1,41 +0,0 @@
USE vn;
INSERT INTO salix.ACL (model, property, accessType, permission, principalType, principalId)
VALUES ('Vehicle', 'filter', 'READ', 'ALLOW', 'ROLE', 'administrative'),
('Vehicle', 'filter', 'READ', 'ALLOW', 'ROLE', 'deliveryAssistant'),
('Vehicle', 'find', 'READ', 'ALLOW', 'ROLE', 'administrative'),
('Vehicle', 'find', 'READ', 'ALLOW', 'ROLE', 'deliveryAssistant'),
('Vehicle', 'findById', 'READ', 'ALLOW', 'ROLE', 'administrative'),
('Vehicle', 'findById', 'READ', 'ALLOW', 'ROLE', 'deliveryAssistant'),
('Vehicle', '__get__active', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Vehicle', 'updateAttributes', 'WRITE', 'ALLOW', 'ROLE', 'administrative'),
('Vehicle', 'updateAttributes', 'WRITE', 'ALLOW', 'ROLE', 'deliveryAssistant'),
('Vehicle', 'deleteById', 'WRITE', 'ALLOW', 'ROLE', 'administrative'),
('Vehicle', 'deleteById', 'WRITE', 'ALLOW', 'ROLE', 'deliveryAssistant'),
('Vehicle', 'create', 'WRITE', 'ALLOW', 'ROLE', 'administrative'),
('Vehicle', 'create', 'WRITE', 'ALLOW', 'ROLE', 'deliveryAssistant'),
('BankPolicy', 'find', 'READ', 'ALLOW', 'ROLE', 'administrative'),
('BankPolicy', 'find', 'READ', 'ALLOW', 'ROLE', 'deliveryAssistant'),
('VehicleState', 'find', 'READ', 'ALLOW', 'ROLE', 'administrative'),
('VehicleState', 'find', 'READ', 'ALLOW', 'ROLE', 'deliveryAssistant'),
('Ppe', 'find', 'READ', 'ALLOW', 'ROLE', 'administrative' ),
('Ppe', 'find', 'READ', 'ALLOW', 'ROLE', 'deliveryAssistant' ),
('VehicleType', 'find', 'READ', 'ALLOW', 'ROLE', 'employee'),
('DeliveryPoint', 'find', 'READ', 'ALLOW', 'ROLE', 'deliveryAssistant'),
('DeliveryPoint', 'find', 'READ', 'ALLOW', 'ROLE', 'administrative');
CREATE TABLE IF NOT EXISTS vehicleType (
id INT(11) PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(45) NOT NULL
);
INSERT IGNORE INTO vehicleType (id, name)
VALUES (1,'vehículo empresa'),
(2, 'furgoneta'),
(3, 'cabeza tractora'),
(4, 'remolque');
ALTER TABLE vehicle ADD COLUMN importCooler decimal(10,2) DEFAULT NULL;
ALTER TABLE vehicle ADD COLUMN vehicleTypeFk INT(11) DEFAULT 1;
ALTER TABLE vehicle ADD CONSTRAINT fk_vehicle_vehicleType FOREIGN KEY (vehicleTypeFk) REFERENCES vehicleType(id);

View File

@ -1,90 +0,0 @@
INSERT INTO salix.ACL (model,property,accessType,permission,principalType,principalId)
VALUES ('Entry','getBuyList','READ','ALLOW','ROLE','buyer'),
('Entry','getBuyUltimate','READ','ALLOW','ROLE','buyer'),
('Entry','search','READ','ALLOW','ROLE','buyer'),
('Entry','create','WRITE','ALLOW','ROLE','buyer'),
('Entry','cloneEntry','WRITE','ALLOW','ROLE','buyer'),
('Entry','deleteEntry','WRITE','ALLOW','ROLE','buyer'),
('Entry','recalcEntryPrices','WRITE','ALLOW','ROLE','buyer'),
('EntryType','find','READ','ALLOW','ROLE','buyer'),
('EntryConfig','findOne','READ','ALLOW','ROLE','buyer');
ALTER TABLE vn.ink ADD IF NOT EXISTS hexJson TEXT NOT NULL;
UPDATE vn.ink
SET hexJson = CONCAT('{"value": ["',hex,'"]}');
UPDATE vn.ink
SET hexJson = CASE `name`
WHEN 'Blanco/Naranja' THEN '{"value": ["FFFFFF", "FFA500"]}'
WHEN 'Sin especificar' THEN '{"value": ["808080"]}'
WHEN '2 Colores' THEN '{"value": ["000000", "FFFFFF"]}'
WHEN 'Amarillo/Marrón' THEN '{"value": ["FFFF00", "8B4513"]}'
WHEN 'Amarillo/Naranja' THEN '{"value": ["FFFF00", "FFA500"]}'
WHEN 'Rosa/Blanco/Amarillo' THEN '{"value": ["FFC0CB", "FFFFFF", "FFFF00"]}'
WHEN 'Rosa/Amarillo' THEN '{"value": ["FFC0CB", "FFFF00"]}'
WHEN 'Antracita' THEN '{"value": ["2F2F2F"]}'
WHEN 'Azul/Amarillo' THEN '{"value": ["0000FF", "FFFF00"]}'
WHEN 'Azul Claro' THEN '{"value": ["ADD8E6"]}'
WHEN 'Azul/Marron' THEN '{"value": ["0000FF", "8B4513"]}'
WHEN 'Azul/Verde' THEN '{"value": ["0000FF", "008000"]}'
WHEN 'Blanco/Amarillo' THEN '{"value": ["FFFFFF", "FFFF00"]}'
WHEN 'Blaugrana' THEN '{"value": ["A50044", "004D98"]}'
WHEN 'Blanco/Negro' THEN '{"value": ["FFFFFF", "000000"]}'
WHEN 'Blanco/Verde' THEN '{"value": ["FFFFFF", "008000"]}'
WHEN 'Blanco/Azul' THEN '{"value": ["FFFFFF", "0000FF"]}'
WHEN 'Blanco/Rosa' THEN '{"value": ["FFFFFF", "FFC0CB"]}'
WHEN 'Cognac/Verde' THEN '{"value": ["9A463D", "008000"]}'
WHEN 'Champagne/Verde' THEN '{"value": ["F7E7CE", "008000"]}'
WHEN 'Camuflaje' THEN '{"value": ["6B8E23", "556B2F", "8B4513"]}'
WHEN 'Crema/Rosa' THEN '{"value": ["FFFDD0", "FFC0CB"]}'
WHEN 'Fucsia/Amarillo' THEN '{"value": ["FF00FF", "FFFF00"]}'
WHEN 'Fucsia/Blanco' THEN '{"value": ["FF00FF", "FFFFFF"]}'
WHEN 'Fucsia/Crema' THEN '{"value": ["FF00FF", "FFFDD0"]}'
WHEN 'Fucsia/Rosa' THEN '{"value": ["FF00FF", "FFC0CB"]}'
WHEN 'Fucsia/Verde' THEN '{"value": ["FF00FF", "008000"]}'
WHEN 'Granate/Blanco' THEN '{"value": ["800000", "FFFFFF"]}'
WHEN 'Gris Lila' THEN '{"value": ["808080", "C8A2C8"]}'
WHEN 'Lavanda/Amarillo' THEN '{"value": ["E6E6FA", "FFFF00"]}'
WHEN 'Lavanda/Gris' THEN '{"value": ["E6E6FA", "808080"]}'
WHEN 'Lividum' THEN '{"value": ["702963"]}'
WHEN 'Morado/Amarillo' THEN '{"value": ["800080", "FFFF00"]}'
WHEN 'Marrón/Blanco' THEN '{"value": ["8B4513", "FFFFFF"]}'
WHEN 'Marron/Gris' THEN '{"value": ["8B4513", "808080"]}'
WHEN 'Marron/Negro' THEN '{"value": ["8B4513", "000000"]}'
WHEN 'Marrón/Verde' THEN '{"value": ["8B4513", "008000"]}'
WHEN 'Matizado' THEN '{"value": ["D3D3D3", "808080", "FFFFFF"]}'
WHEN 'Mixto' THEN '{"value": ["FF0000", "0000FF", "008000", "FFFF00"]}'
WHEN 'Marrón Oscuro' THEN '{"value": ["654321"]}'
WHEN 'Naranja/Marron' THEN '{"value": ["FFA500", "8B4513"]}'
WHEN 'Naranja/Rosa' THEN '{"value": ["FFA500", "FFC0CB"]}'
WHEN 'Ocre/Burgundi' THEN '{"value": ["CC7722", "800020"]}'
WHEN 'Oro/Plata' THEN '{"value": ["FFD700", "C0C0C0"]}'
WHEN 'Oro/Negro' THEN '{"value": ["FFD700", "000000"]}'
WHEN 'Oro/Verde' THEN '{"value": ["FFD700", "008000"]}'
WHEN 'Purpura/Blanco' THEN '{"value": ["800080", "FFFFFF"]}'
WHEN 'Purpura/Rosa' THEN '{"value": ["800080", "FFC0CB"]}'
WHEN 'Pastel' THEN '{"value": ["FFB6C1", "87CEFA", "98FB98"]}'
WHEN 'Plata' THEN '{"value": ["C0C0C0"]}'
WHEN 'Plata/Verde' THEN '{"value": ["C0C0C0", "008000"]}'
WHEN 'Rojo/Amarillo' THEN '{"value": ["FF0000", "FFFF00"]}'
WHEN 'Rojo/Blanco' THEN '{"value": ["FF0000", "FFFFFF"]}'
WHEN 'Rojo/Naranja' THEN '{"value": ["FF0000", "FFA500"]}'
WHEN 'Rojo/Oro' THEN '{"value": ["FF0000", "FFD700"]}'
WHEN 'Rojo/Verde' THEN '{"value": ["FF0000", "008000"]}'
WHEN 'Rosa/Lila' THEN '{"value": ["FFC0CB", "C8A2C8"]}'
WHEN 'Rosa/Naranja' THEN '{"value": ["FFC0CB", "FFA500"]}'
WHEN 'Rojo/Rosa' THEN '{"value": ["FF0000", "FFC0CB"]}'
WHEN 'Rosa empolvado' THEN '{"value": ["E6B8AF"]}'
WHEN 'Rosa/Verde' THEN '{"value": ["FFC0CB", "008000"]}'
WHEN 'Topo/Blanco' THEN '{"value": ["8B8589", "FFFFFF"]}'
WHEN 'Topo' THEN '{"value": ["8B8589"]}'
WHEN 'Transparente' THEN '{"value": ["00000000"]}'
WHEN 'Verde/Amarillo' THEN '{"value": ["008000", "FFFF00"]}'
WHEN 'Verde/Negro' THEN '{"value": ["008000", "000000"]}'
WHEN 'Variado' THEN '{"value": ["FF0000", "0000FF", "008000", "FFFF00", "FFA500"]}'
WHEN 'Verde Claro/Morado' THEN '{"value": ["90EE90", "800080"]}'
WHEN 'Verde/Lila' THEN '{"value": ["008000", "C8A2C8"]}'
WHEN 'Vaquero Neon' THEN '{"value": ["1560BD", "FFFF00"]}'
ELSE hexJson
END;

View File

@ -1,6 +0,0 @@
INSERT INTO salix.ACL (model, property, accessType, permission, principalType, principalId)
VALUES
('WorkerDms', 'hasHighPrivs', 'READ', 'ALLOW', 'ROLE', 'hr'),
('Business', 'updateAttributes', 'WRITE', 'ALLOW', 'ROLE', 'hr'),
('Worker', '__get__business', 'READ', 'ALLOW', 'ROLE', 'hr')
;

View File

@ -1,8 +0,0 @@
UPDATE vn.expedition e
JOIN (
SELECT id
FROM vn.expedition
WHERE hostFk COLLATE utf8mb3_unicode_ci NOT IN
(SELECT code COLLATE utf8mb3_unicode_ci FROM vn.host WHERE code IS NOT NULL)
) s ON e.id = s.id
SET e.hostFk = 'pc336';

View File

@ -1,9 +0,0 @@
ALTER TABLE vn.expedition
MODIFY COLUMN hostFk VARCHAR(30) COLLATE utf8mb3_general_ci;
ALTER TABLE vn.expedition
ADD CONSTRAINT fk_expedition_host_code
FOREIGN KEY (hostFk)
REFERENCES host(code)
ON UPDATE CASCADE
ON DELETE CASCADE;

View File

@ -58,10 +58,10 @@
"Swift / BIC can't be empty": "Swift / BIC can't be empty",
"Deleted sales from ticket": "I have deleted the following lines from the ticket [{{ticketId}}]({{{ticketUrl}}}): {{{deletions}}}",
"Added sale to ticket": "I have added the following line to the ticket [{{ticketId}}]({{{ticketUrl}}}): {{{addition}}}",
"Changed sale discount": "I have changed the following lines discounts from the ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}} {{ticketWeekly}}",
"Changed sale discount": "I have changed the following lines discounts from the ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}",
"Created claim": "I have created the claim [{{claimId}}]({{{claimUrl}}}) for the following lines from the ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}",
"Changed sale price": "I have changed the price of [{{itemId}} {{concept}}]({{{itemUrl}}}) ({{quantity}}) from {{oldPrice}}€ ➔ *{{newPrice}}€* of the ticket [{{ticketId}}]({{{ticketUrl}}}) {{ticketWeekly}}",
"Changed sale quantity": "I have changed {{changes}} of the ticket [{{ticketId}}]({{{ticketUrl}}}) {{ticketWeekly}}",
"Changed sale price": "I have changed the price of [{{itemId}} {{concept}}]({{{itemUrl}}}) ({{quantity}}) from {{oldPrice}}€ ➔ *{{newPrice}}€* of the ticket [{{ticketId}}]({{{ticketUrl}}})",
"Changed sale quantity": "I have changed {{changes}} of the ticket [{{ticketId}}]({{{ticketUrl}}})",
"Changes in sales": "the quantity of [{{itemId}} {{concept}}]({{{itemUrl}}}) from {{oldQuantity}} ➔ *{{newQuantity}}*",
"Changed sale reserved state": "I have changed the following lines reserved state from the ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}",
"Bought units from buy request": "Bought {{quantity}} units of [{{itemId}} {{concept}}]({{{urlItem}}}) for the ticket id [{{ticketId}}]({{{url}}})",
@ -234,7 +234,6 @@
"It has been invoiced but the PDF of refund not be generated": "It has been invoiced but the PDF of refund not be generated",
"Cannot add holidays on this day": "Cannot add holidays on this day",
"Cannot send mail": "Cannot send mail",
"This worker already exists": "This worker already exists",
"CONSTRAINT `chkParkingCodeFormat` failed for `vn`.`parking`": "CONSTRAINT `chkParkingCodeFormat` failed for `vn`.`parking`",
"This postcode already exists": "This postcode already exists",
"Original invoice not found": "Original invoice not found",
@ -254,8 +253,5 @@
"Sales already moved": "Sales already moved",
"Holidays to past days not available": "Holidays to past days not available",
"Incorrect delivery order alert on route": "Incorrect delivery order alert on route: {{ route }} zone: {{ zone }}",
"Ticket has been delivered out of order": "The ticket {{ticket}} of route {{{fullUrl}}} has been delivered out of order.",
"clonedFromTicketWeekly": ", that is a cloned sale from ticket {{ ticketWeekly }}",
"negativeReplaced": "Replaced item [#{{oldItemId}}]({{{oldItemUrl}}}) {{oldItem}} with [#{{newItemId}}]({{{newItemUrl}}}) {{newItem}} from ticket [{{ticketId}}]({{{ticketUrl}}})",
"The tag and priority can't be repeated": "The tag and priority can't be repeated"
}
"Ticket has been delivered out of order": "The ticket {{ticket}} of route {{{fullUrl}}} has been delivered out of order."
}

View File

@ -22,7 +22,7 @@
"Cannot change the payment method if no salesperson": "No se puede cambiar la forma de pago si no hay comercial asignado",
"can't be blank": "El campo no puede estar vacío",
"Observation type must be unique": "El tipo de observación no puede repetirse",
"The credit must be an integer greater than or equal to zero": "The credit must be an integer greater than or equal to zero",
"The credit must be an integer greater than or equal to zero": "The credit must be an integer greater than or equal to zero",
"The grade must be similar to the last one": "El grade debe ser similar al último",
"Only manager can change the credit": "Solo el gerente puede cambiar el credito de este cliente",
"Name cannot be blank": "El nombre no puede estar en blanco",
@ -121,10 +121,10 @@
"Incoterms is required for a non UEE member": "El incoterms es requerido para los clientes extracomunitarios",
"Deleted sales from ticket": "He eliminado las siguientes lineas del ticket [{{ticketId}}]({{{ticketUrl}}}): {{{deletions}}}",
"Added sale to ticket": "He añadido la siguiente linea al ticket [{{ticketId}}]({{{ticketUrl}}}): {{{addition}}}",
"Changed sale discount": "He cambiado el descuento de las siguientes lineas al ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}} {{ticketWeekly}}",
"Changed sale discount": "He cambiado el descuento de las siguientes lineas al ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}",
"Created claim": "He creado la reclamación [{{claimId}}]({{{claimUrl}}}) de las siguientes lineas del ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}",
"Changed sale price": "He cambiado el precio de [{{itemId}} {{concept}}]({{{itemUrl}}}) ({{quantity}}) de {{oldPrice}}€ ➔ *{{newPrice}}€* del ticket [{{ticketId}}]({{{ticketUrl}}}) {{ticketWeekly}} ",
"Changed sale quantity": "He cambiado {{changes}} del ticket [{{ticketId}}]({{{ticketUrl}}}) {{ticketWeekly}}",
"Changed sale price": "He cambiado el precio de [{{itemId}} {{concept}}]({{{itemUrl}}}) ({{quantity}}) de {{oldPrice}}€ ➔ *{{newPrice}}€* del ticket [{{ticketId}}]({{{ticketUrl}}})",
"Changed sale quantity": "He cambiado {{changes}} del ticket [{{ticketId}}]({{{ticketUrl}}})",
"Changes in sales": "la cantidad de [{{itemId}} {{concept}}]({{{itemUrl}}}) de {{oldQuantity}} ➔ *{{newQuantity}}*",
"State": "Estado",
"regular": "normal",
@ -396,7 +396,6 @@
"There are tickets to be invoiced": "La zona tiene tickets por facturar",
"Incorrect delivery order alert on route": "Alerta de orden de entrega incorrecta en ruta: {{ route }} zona: {{ zone }}",
"Ticket has been delivered out of order": "El ticket {{ticket}} {{{fullUrl}}} no ha sido entregado en su orden.",
"Price cannot be blank": "El precio no puede estar en blanco",
"clonedFromTicketWeekly": ", que es una linea clonada del ticket {{ticketWeekly}}",
"negativeReplaced": "Sustituido el articulo [#{{oldItemId}}]({{{oldItemUrl}}}) {{oldItem}} por [#{{newItemId}}]({{{newItemUrl}}}) {{newItem}} del ticket [{{ticketId}}]({{{ticketUrl}}})"
"Price cannot be blank": "El precio no puede estar en blanco"
}

View File

@ -368,6 +368,5 @@
"ticketLostExpedition": "Le ticket [{{ticketId}}]({{{ticketUrl}}}) a l'expédition perdue suivante : {{expeditionId}}",
"The web user's email already exists": "L'email de l'internaute existe déjà",
"Incorrect delivery order alert on route": "Alerte de bon de livraison incorrect sur l'itinéraire: {{ route }} zone : {{ zone }}",
"Ticket has been delivered out of order": "Le ticket {{ticket}} de la route {{{fullUrl}}} a été livré hors service.",
"negativeReplaced": "Remplacé l'article [#{{oldItemId}}]({{{oldItemUrl}}}) {{oldItem}} par [#{{newItemId}}]({{{newItemUrl}}}) {{newItem}} du ticket [{{ticketId}}]({{{ticketUrl}}})"
}
"Ticket has been delivered out of order": "Le ticket {{ticket}} de la route {{{fullUrl}}} a été livré hors service."
}

View File

@ -367,6 +367,5 @@
"ticketLostExpedition": "O ticket [{{ticketId}}]({{{ticketUrl}}}) tem a seguinte expedição perdida: {{expeditionId}}",
"The web user's email already exists": "O e-mail do utilizador da web já existe.",
"Incorrect delivery order alert on route": "Alerta de ordem de entrega incorreta na rota: {{ route }} zona: {{ zone }}",
"Ticket has been delivered out of order": "O ticket {{ticket}} da rota {{{fullUrl}}} foi entregue fora de ordem.",
"negativeReplaced": "Substituído o artigo [#{{oldItemId}}]({{{oldItemUrl}}}) {{oldItem}} por [#{{newItemId}}]({{{newItemUrl}}}) {{newItem}} do ticket [{{ticketId}}]({{{ticketUrl}}})"
}
"Ticket has been delivered out of order": "O ticket {{ticket}} da rota {{{fullUrl}}} foi entregue fora de ordem."
}

View File

@ -4,7 +4,7 @@ const LoopBackContext = require('loopback-context');
describe('ClaimBeginning model()', () => {
const claimFk = 1;
const activeCtx = {
accessToken: {userId: 72},
accessToken: {userId: 18},
headers: {origin: 'localhost:5000'},
__: () => {}
};

View File

@ -3,18 +3,22 @@ const LoopBackContext = require('loopback-context');
describe('Claim createFromSales()', () => {
const ticketId = 23;
const newSale = [{id: 31, instance: 0, quantity: 10}];
let activeCtx;
let ctx;
const newSale = [{
id: 31,
instance: 0,
quantity: 10
}];
const activeCtx = {
accessToken: {userId: 1},
headers: {origin: 'localhost:5000'},
__: () => {}
};
const ctx = {
req: activeCtx
};
beforeEach(() => {
activeCtx = {
accessToken: {userId: 72},
headers: {origin: 'localhost:5000'},
__: () => {}
};
ctx = {req: activeCtx};
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});

View File

@ -1,7 +1,6 @@
const UserError = require('vn-loopback/util/user-error');
const LoopBackContext = require('loopback-context');
const moment = require('moment');
module.exports = Self => {
require('../methods/claim-beginning/importToNewRefundTicket')(Self);
@ -14,51 +13,10 @@ module.exports = Self => {
const options = ctx.options;
const models = Self.app.models;
const saleFk = ctx?.currentInstance?.saleFk || ctx?.instance?.saleFk;
const claimFk = ctx?.instance?.claimFk || ctx?.currentInstance?.claimFk;
const myOptions = {};
const accessToken = ctx?.options?.accessToken || LoopBackContext.getCurrentContext().active.accessToken;
const ctxToken = {req: {accessToken}};
if (typeof options == 'object')
Object.assign(myOptions, options);
const sale = await models.Sale.findById(saleFk, {fields: ['ticketFk', 'quantity']}, options);
const canCreateClaimAfterDeadline = models.ACL.checkAccessAcl(
ctxToken,
'Claim',
'createAfterDeadline',
myOptions
);
const canUpdateClaim = models.ACL.checkAccessAcl(
ctxToken,
'Claim',
'updateClaim',
myOptions
);
if (!canUpdateClaim && !canCreateClaimAfterDeadline)
throw new UserError(`You don't have permission to modify this claim`);
if (canUpdateClaim) {
const query = `
SELECT daysToClaim
FROM vn.claimConfig`;
const res = await Self.rawSql(query);
const daysToClaim = res[0]?.daysToClaim;
const claim = await models.Claim.findById(claimFk, {fields: ['created']}, options);
const claimDate = moment.utc(claim.created);
const currentDate = moment.utc();
const daysSinceSale = currentDate.diff(claimDate, 'days');
if (daysSinceSale > daysToClaim && !canCreateClaimAfterDeadline)
throw new UserError(`You can't modify this claim because the deadline has already passed`);
}
if (ctx.isNewInstance) {
const claim = await models.Claim.findById(claimFk, {fields: ['ticketFk']}, options);
const claim = await models.Claim.findById(ctx.instance.claimFk, {fields: ['ticketFk']}, options);
if (sale.ticketFk != claim.ticketFk)
throw new UserError(`Cannot create a new claimBeginning from a different ticket`);
}
@ -83,7 +41,7 @@ module.exports = Self => {
if (ctx.options && ctx.options.transaction)
myOptions.transaction = ctx.options.transaction;
const claimBeginning = ctx.instance ?? await Self.findById(ctx?.where?.id);
const claimBeginning = ctx.instance ?? await Self.findById(ctx.where.id);
const filter = {
where: {id: claimBeginning.claimFk},

View File

@ -1,303 +0,0 @@
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
const buildFilter = require('vn-loopback/util/filter').buildFilter;
const mergeFilters = require('vn-loopback/util/filter').mergeFilters;
module.exports = Self => {
Self.remoteMethodCtx('getBuyList', {
description: 'Returns buys for editing of one entry',
accessType: 'READ',
accepts: [{
arg: 'entryFk',
type: 'number',
required: true,
description: 'The entry id',
http: {source: 'path'}
},
{
arg: 'filter',
type: 'object',
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string'
},
{
arg: 'isIgnored',
type: 'boolean',
description: 'check if the buy is ignored',
http: {source: 'query'}
},
{
arg: 'itemFk',
type: 'number',
description: 'item id',
http: {source: 'query'}
},
{
arg: 'name',
type: 'string',
description: 'item name',
http: {source: 'query'}
},
{
arg: 'size',
type: 'number',
description: 'item size',
http: {source: 'query'}
},
{
arg: 'stickers',
type: 'number',
description: 'sticker quantity',
http: {source: 'query'}
},
{
arg: 'packagingFk',
type: 'number',
description: 'packaging id',
http: {source: 'query'}
},
{
arg: 'weight',
type: 'number',
description: 'weight',
http: {source: 'query'}
},
{
arg: 'packing',
type: 'number',
description: 'packing quantity',
http: {source: 'query'}
},
{
arg: 'grouping',
type: 'number',
description: 'grouping quantity',
http: {source: 'query'}
},
{
arg: 'quantity',
type: 'number',
http: {source: 'query'}
},
{
arg: 'buyingValue',
type: 'number',
http: {source: 'query'}
},
{
arg: 'amount',
type: 'number',
description: 'buying value * quantity',
http: {source: 'query'}
},
{
arg: 'price2',
type: 'number',
description: 'price for the package',
http: {source: 'query'}
},
{
arg: 'price3',
type: 'number',
description: 'price for the box',
http: {source: 'query'}
},
{
arg: 'minPrice',
type: 'number',
description: 'item minimum price',
http: {source: 'query'}
},
{
arg: 'packingOut',
type: 'number',
description: 'quantity of package on a vn box',
http: {source: 'query'}
},
{
arg: 'comment',
type: 'string',
description: 'item comment',
http: {source: 'query'}
},
{
arg: 'subName',
type: 'string',
description: 'supplier name',
http: {source: 'query'}
},
{
arg: 'subName',
type: 'string',
description: 'supplier name',
http: {source: 'query'}
},
{
arg: 'company_name',
type: 'string',
description: 'company name',
http: {source: 'query'}
},
{
arg: 'workerFk',
type: 'number',
description: 'buyer id',
http: {source: 'query'}
},
{
arg: 'itemTypeFk',
type: 'number',
description: 'item family id',
http: {source: 'query'}
},
{
arg: 'groupingMode',
type: 'string',
description: 'grouping mode',
http: {source: 'query'}
},
{
arg: 'hasMinPrice',
type: 'boolean',
description: 'grouping mode',
http: {source: 'query'}
},
{
arg: 'groupBy',
type: 'string',
description: 'group by',
http: {source: 'query'}
},
],
returns: {
type: ['object'],
root: true
},
http: {
path: `/:entryFk/getBuyList`,
verb: 'GET'
}
});
Self.getBuyList = async(ctx, entryFk, filter, options) => {
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
let conn = Self.dataSource.connector;
let where = buildFilter(ctx.args, (param, value) => {
switch (param) {
case 'name':
case 'subName':
case 'company_name':
case 'comment':
return {[param]: {like: `%${value}%`}};
case 'size':
case 'isIgnored':
case 'itemFk':
case 'stickers':
case 'packagingFk':
case 'weight':
case 'packing':
case 'grouping':
case 'quantity':
case 'buyingValue':
case 'amount':
case 'price2':
case 'price3':
case 'packingOut':
case 'minPrice':
case 'workerFk':
case 'itemTypeFk':
case 'groupingMode':
case 'hasMinPrice':
return {[param]: value};
}
});
filter = mergeFilters(filter, {where});
let stmts = [];
let stmt;
const selectFields = `b.id,
b.isIgnored,
b.itemFk,
b.printedStickers,
b.stickers,
b.packagingFk,
b.weight,
b.packing,
b.groupingMode,
b.grouping,
b.quantity,
b.buyingValue,
ROUND(b.buyingValue * b.quantity, 2) amount,
b.isChecked,
b.price2,
b.price3,
i.name,
i.size,
i.minPrice,
i.hasMinPrice,
i.packingOut,
i.comment,
i.subName,
i.tag5,
i.value5,
i.tag6,
i.value6,
i.tag7,
i.value7,
i.tag8,
i.value8,
i.tag9,
i.value9,
i.tag10,
i.value10,
s.company_name,
ik.hexJson,
it.workerFk,
it.id itemTypeFk
`;
const groupByFields = `SUM(b.printedStickers) printedStickers,
SUM(b.packing) packing,
SUM(b.stickers) stickers,
SUM(b.weight) weight,
SUM(b.quantity) quantity,
SUM(ROUND(b.buyingValue * b.quantity, 2)) amount
`;
const groupBy = ctx.args.groupBy;
stmt = new ParameterizedSQL(
`SELECT *
FROM(
SELECT
${ groupBy ? groupByFields : selectFields}
FROM item i
LEFT JOIN ink ik ON ik.id = i.inkFk
LEFT JOIN buy b ON b.itemFk = i.id
LEFT JOIN edi.ekt e ON e.id = b.ektFk
LEFT JOIN edi.supplier s ON e.pro = s.supplier_id
LEFT JOIN itemType it ON it.id = i.typeFk
WHERE b.entryFk = ?
${groupBy ?? ''}
) sub`,
[entryFk]
);
stmt.merge(conn.makeSuffix(filter));
let itemsIndex = stmts.push(stmt) - 1;
let sql = ParameterizedSQL.join(stmts, ';');
let result = await conn.executeStmt(sql, myOptions);
if (groupBy && result.length) {
const buys = await Self.app.models.Buy.find({where: {entryFk}}, myOptions);
const buysChecked = buys.filter(buy => buy?.isChecked);
result[0].isChecked = buysChecked.length === buys.length;
}
return itemsIndex === 0 ? result : result[itemsIndex];
};
};

View File

@ -1,46 +0,0 @@
module.exports = Self => {
Self.remoteMethodCtx('getBuyUltimate', {
description: 'Returns the last buy of the item',
accessType: 'READ',
accepts: [
{
arg: 'itemFk',
type: 'number',
required: true
}, {
arg: 'warehouseFk',
type: 'number',
required: true
}, {
arg: 'date',
type: 'date',
required: true
}
],
returns: {
type: 'object',
root: true
},
http: {
path: `/getBuyUltimate`,
verb: 'GET'
}
});
Self.getBuyUltimate = async(ctx, itemFk, warehouseFk, date, options) => {
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
await Self.rawSql('CALL vn.buy_getUltimate(?, ?, ?)', [itemFk, warehouseFk, date], myOptions);
return Self.rawSql(
`SELECT b.*
FROM cache.last_buy lb
JOIN buy b ON b.id = lb.buy_id
WHERE lb.item_id = ?
ORDER BY (lb.warehouse_id = ?) desc
LIMIT 1`,
[itemFk, warehouseFk], myOptions
);
};
};

View File

@ -1,46 +0,0 @@
module.exports = Self => {
Self.remoteMethodCtx('cloneEntry', {
description: 'Clones an entry',
accessType: 'WRITE',
accepts: [{
arg: 'id',
type: 'number',
required: true,
description: 'The entry id',
http: {source: 'path'}
}],
returns: {
type: 'object',
root: true
},
http: {
path: `/:id/cloneEntry`,
verb: 'POST'
}
});
Self.cloneEntry = async(ctx, id, options) => {
const userId = ctx.req.accessToken.userId;
const myOptions = {userId};
let tx;
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
await Self.rawSql('CALL entry_clone(?, @newEntryId)', [id], myOptions);
const result = await Self.rawSql('SELECT @newEntryId', [], myOptions);
const newEntryId = result[0]['@newEntryId'];
if (tx) await tx.commit();
return newEntryId;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
};
};

View File

@ -1,48 +0,0 @@
module.exports = Self => {
Self.remoteMethodCtx('deleteEntry', {
description: 'Clones an entry',
accessType: 'WRITE',
accepts: [{
arg: 'id',
type: 'number',
required: true,
description: 'The entry id',
http: {source: 'path'}
}],
http: {
path: `/:id/deleteEntry`,
verb: 'POST'
}
});
Self.deleteEntry = async(ctx, id, options) => {
const userId = ctx.req.accessToken.userId;
const myOptions = {userId};
let tx;
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
const entry = await Self.findById(id, null, myOptions);
await entry.updateAttribute('travelFk', null, myOptions);
await Self.rawSql('DELETE FROM vn.duaEntry WHERE entryFk = ?;', [id], myOptions);
await Self.rawSql(`
DELETE i.*
FROM vn.invoiceIn i
JOIN vn.entry e ON e.invoiceInFk = i.id
WHERE e.id = ?`, [id], myOptions
);
if (tx) await tx.commit();
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
};
};

View File

@ -129,68 +129,7 @@ module.exports = Self => {
arg: 'finalTemperature',
type: 'number',
description: 'Final temperature value'
},
{
arg: 'isExcludedFromAvailable',
type: 'boolean',
description: `landing date`
},
{
arg: 'isReceived',
type: 'boolean',
description: `travel received`
},
{
arg: 'isRaid',
type: 'boolean',
description: `travel isRaid`
},
{
arg: 'landed',
type: 'date',
description: `landing date`
},
{
arg: 'invoiceNumber',
type: 'string',
description: `entry invoice`
},
{
arg: 'reference',
type: 'string',
description: `entry reference`
},
{
arg: 'awbCode',
type: 'string',
description: `awb code`
},
{
arg: 'agencyModeId',
type: 'number',
description: `agency mode id`
},
{
arg: 'evaNotes',
type: 'string',
description: `observation`
},
{
arg: 'warehouseInFk',
type: 'number',
description: `warehouse in id`
},
{
arg: 'warehouseOutFk',
type: 'number',
description: `warehouse out id`
},
{
arg: 'entryTypeCode',
type: 'string',
description: 'entry type code'
},
}
],
returns: {
type: ['object'],
@ -217,12 +156,19 @@ module.exports = Self => {
{'s.name': {like: `%${value}%`}},
{'s.nickname': {like: `%${value}%`}}
]};
case 'invoiceNumber':
case 'reference':
case 'ref':
case 'evaNotes':
param = `e.${param}`;
return {[param]: {like: `%${value}%`}};
case 'created':
return {'e.created': {gte: value}};
case 'from':
return {'t.landed': {gte: value}};
case 'fromShipped':
return {'t.shipped': {gte: value}};
case 'to':
return {'t.landed': {lte: value}};
case 'toShipped':
return {'t.shipped': {lte: value}};
case 'id':
case 'isBooked':
case 'isConfirmed':
@ -232,20 +178,8 @@ module.exports = Self => {
case 'currencyFk':
case 'supplierFk':
case 'invoiceInFk':
case 'isExcludedFromAvailable':
return {[`e.${param}`]: value};
case 'isReceived':
case 'landed':
case 'isRaid':
case 'warehouseInFk':
case 'warehouseOutFk':
return {[`t.${param}`]: value};
case 'awbCode':
return {'a.code': {like: `%${value}%`}};
case 'agencyModeId':
return {[`am.id`]: value};
case 'entryTypeCode':
return {[`et.code`]: value};
param = `e.${param}`;
return {[param]: value};
case 'initialTemperature':
return {'e.initialTemperature': {lte: value}};
case 'finalTemperature':
@ -263,14 +197,15 @@ module.exports = Self => {
const stmts = [];
let stmt;
stmt = new ParameterizedSQL(
`SELECT e.id,
`SELECT
e.id,
e.supplierFk,
e.dated,
e.reference,
e.invoiceNumber,
e.isBooked,
e.isExcludedFromAvailable,
e.evaNotes,
e.evaNotes observation,
e.isConfirmed,
e.isOrdered,
t.isRaid,
@ -292,27 +227,15 @@ module.exports = Self => {
cu.code currencyCode,
t.shipped,
t.landed,
t.ref travelRef,
t.ref AS travelRef,
t.warehouseInFk,
w.name warehouseInName,
t.warehouseOutFk,
w2.name warehouseOutName,
a.code awbCode,
am.id agencyModeId,
am.name agencyModeName,
et.code entryTypeCode,
et.description entryTypeDescription,
t.isReceived
w.name warehouseInName
FROM vn.entry e
JOIN vn.supplier s ON s.id = e.supplierFk
LEFT JOIN vn.travel t ON t.id = e.travelFk
LEFT JOIN vn.warehouse w ON w.id = t.warehouseInFk
LEFT JOIN vn.warehouse w2 ON w2.id = t.warehouseOutFk
LEFT JOIN vn.company co ON co.id = e.companyFk
LEFT JOIN vn.currency cu ON cu.id = e.currencyFk
LEFT JOIN vn.awb a ON a.id = t.awbFk
LEFT JOIN vn.agencyMode am ON am.id = t.agencyModeFk
LEFT JOIN vn.entryType et ON et.code = e.typeFk`
JOIN vn.travel t ON t.id = e.travelFk
JOIN vn.warehouse w ON w.id = t.warehouseInFk
JOIN vn.company co ON co.id = e.companyFk
JOIN vn.currency cu ON cu.id = e.currencyFk`
);
stmt.merge(conn.makeWhere(filter.where));

View File

@ -1,49 +0,0 @@
module.exports = Self => {
Self.remoteMethodCtx('recalcEntryPrices', {
description: 'Clones an entry',
accessType: 'WRITE',
accepts: [{
arg: 'entryFk',
type: 'number',
required: true,
description: 'The entry id',
http: {source: 'path'}
}],
returns: {
type: 'object',
root: true
},
http: {
path: `/:entryFk/recalcEntryPrices`,
verb: 'POST'
}
});
Self.recalcEntryPrices = async(ctx, entryFk, options) => {
const userId = ctx.req.accessToken.userId;
const myOptions = {userId};
let tx;
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
const entry = await Self.findById(entryFk, myOptions);
const entryConfig = await Self.app.models.EntryConfig.findOne({}, myOptions);
if (entry.supplierFk === entryConfig.inventorySupplierFk) return;
try {
const result = await Self.rawSql('CALL vn.buy_recalcPricesByEntry(?)', [entryFk], myOptions);
if (tx) await tx.commit();
return result[0];
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
};
};

View File

@ -31,8 +31,5 @@
},
"InventoryConfig": {
"dataSource": "vn"
},
"EntryConfig": {
"dataSource": "vn"
}
}

View File

@ -1,30 +0,0 @@
{
"name": "EntryConfig",
"base": "VnModel",
"mixins": {
"Loggable": true
},
"options": {
"mysql": {
"table": "entryConfig"
}
},
"properties": {
"defaultEntry": {
"type": "number",
"id": true
},
"mailToNotify": {
"type": "string"
},
"inventorySupplierFk": {
"type": "number"
},
"maxLockTime": {
"type": "number"
},
"defaultSupplierFk": {
"type": "number"
}
}
}

View File

@ -15,13 +15,8 @@ module.exports = Self => {
require('../methods/entry/transfer')(Self);
require('../methods/entry/labelSupplier')(Self);
require('../methods/entry/buyLabelSupplier')(Self);
require('../methods/entry-buys/getBuyList')(Self);
require('../methods/entry-buys/getBuyUltimate')(Self);
require('../methods/entry/cloneEntry')(Self);
require('../methods/entry/deleteEntry')(Self);
require('../methods/entry/recalcEntryPrices')(Self);
Self.observe('before save', async(ctx, options) => {
Self.observe('before save', async function(ctx, options) {
if (ctx.isNewInstance) return;
const changes = ctx.data || ctx.instance;

View File

@ -56,7 +56,8 @@
"required": true
},
"travelFk": {
"type": "number"
"type": "number",
"required": true
},
"companyFk": {
"type": "number",
@ -73,12 +74,6 @@
},
"finalTemperature": {
"type": "number"
},
"lockerUserFk":{
"type": "number"
},
"locked":{
"type": "date"
}
},
"relations": {
@ -112,16 +107,6 @@
"type": "belongsTo",
"model": "EntryType",
"foreignKey": "typeFk"
},
"invoiceIn": {
"type": "belongsTo",
"model": "InvoiceIn",
"foreignKey": "invoiceInFk"
},
"user": {
"type": "belongsTo",
"model": "VnUser",
"foreignKey": "lockerUserFk"
}
}
}
}

View File

@ -22,11 +22,6 @@ module.exports = Self => {
type: 'integer',
description: 'The item id',
},
{
arg: 'name',
type: 'string',
description: 'The item name',
},
{
arg: 'typeFk',
type: 'integer',
@ -117,8 +112,6 @@ module.exports = Self => {
: {'it.code': {like: `%${value}%`}};
case 'categoryFk':
return {'it.categoryFk': value};
case 'name':
return {'i.name': {like: `%${value}%`}};
case 'buyerFk':
return {'it.workerFk': value};
case 'warehouseFk':

View File

@ -1,43 +0,0 @@
module.exports = Self => {
Self.remoteMethodCtx('getSimilar', {
description: 'Returns list of items with similar item requested',
accessType: 'READ',
accepts: [
{
arg: 'filter',
type: 'Object',
required: true,
description: 'Filter defining where and paginated data',
http: {source: 'query'}
}
],
returns: {
type: ['Object'],
root: true
},
http: {
path: `/getSimilar`,
verb: 'GET'
}
});
Self.getSimilar = async(ctx, filter, options) => {
const myOptions = {userId: ctx.req.accessToken.userId};
if (typeof options == 'object')
Object.assign(myOptions, options);
const {where} = filter;
const query = [
filter.itemFk,
where.warehouseFk,
where.date,
where.showType,
where.scopeDays
];
const [results] = await Self.rawSql('CALL vn.item_getSimilar(?, ?, ?, ?, ?)', query, myOptions);
return results;
};
};

View File

@ -1,38 +0,0 @@
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
module.exports = Self => {
Self.remoteMethodCtx('search', {
description: 'Returns an array of search results for a specified item',
accepts: [{
arg: 'filter',
type: 'object',
description: 'Filter to define conditions and paginate the data.',
required: true
}],
returns: {
type: ['object'],
root: true
},
http: {
path: `/search`,
verb: 'GET'
}
});
Self.search = async(ctx, filter) => {
const conn = Self.dataSource.connector;
const stmt = new ParameterizedSQL(`
SELECT *
FROM(
SELECT i.id, i.name, i.size, p.name producerName
FROM item i
LEFT JOIN producer p ON p.id = i.producerFk
) sub
`);
stmt.merge(conn.makeSuffix(filter));
return conn.executeStmt(stmt);
};
};

View File

@ -89,7 +89,7 @@ describe('item filter()', () => {
const ctx = {args: {filter: filter, workerFk: 16}, req: {accessToken: {userId: 1}}};
const result = await models.Item.filter(ctx, filter, options);
expect(result.length).toEqual(3);
expect(result.length).toEqual(2);
expect(result[0].id).toEqual(16);
expect(result[1].id).toEqual(71);

View File

@ -1,49 +0,0 @@
const models = require('vn-loopback/server/server').models;
describe('Item get similar', () => {
let options;
let tx;
const ctx = beforeAll.getCtx();
beforeAll.mockLoopBackContext();
beforeEach(async() => {
tx = await models.Item.beginTransaction({});
options = {transaction: tx};
});
afterEach(async() => {
if (tx)
await tx.rollback();
});
it('should return similar items', async() => {
const filter = {
itemFk: 88, sales: 43,
where: {
'scopeDays': '2',
'showType': true,
'alertLevelCode': 'FREE',
'date': '2001-01-01T11:00:00.000Z',
'warehouseFk': 1
}
};
const result = await models.Item.getSimilar(ctx, filter, options);
expect(result.length).toEqual(2);
});
it('should return empty array is if not exists', async() => {
const filter = {
itemFk: 88, sales: 43,
where: {
'scopeDays': '2',
'showType': true,
'alertLevelCode': 'FREE',
'date': '2001-01-01T11:00:00.000Z',
'warehouseFk': 60
}
};
const result = await models.Item.getSimilar(ctx, filter, options);
expect(result.length).toEqual(0);
});
});

View File

@ -26,7 +26,7 @@ describe('tag filterValue()', () => {
const filter = {where: {value: 'Blue'}, limit: 5};
const result = await models.Tag.filterValue(colorTagId, filter, options);
expect(result.length).toEqual(3);
expect(result.length).toEqual(2);
expect(result[0].value).toEqual('Blue');
expect(result[1].value).toEqual('Blue/Silver');

View File

@ -17,9 +17,6 @@
},
"showOrder": {
"type": "number"
},
"hexJson": {
"type": "string"
}
},
"acls": [

View File

@ -5,7 +5,6 @@ module.exports = Self => {
require('../methods/item/clone')(Self);
require('../methods/item/updateTaxes')(Self);
require('../methods/item/getBalance')(Self);
require('../methods/item/getSimilar')(Self);
require('../methods/item/lastEntriesFilter')(Self);
require('../methods/item/getSummary')(Self);
require('../methods/item/getCard')(Self);
@ -18,7 +17,6 @@ module.exports = Self => {
require('../methods/item/buyerWasteEmail')(Self);
require('../methods/item/setVisibleDiscard')(Self);
require('../methods/item/get')(Self);
require('../methods/item/search')(Self);
Self.validatesPresenceOf('originFk', {message: 'Cannot be blank'});

View File

@ -258,10 +258,10 @@ module.exports = Self => {
stmts.push(`SET SESSION optimizer_search_depth = @_optimizer_search_depth`);
stmt = new ParameterizedSQL(`
CREATE OR REPLACE TEMPORARY TABLE tmp.ticket
CREATE OR REPLACE TEMPORARY TABLE tmp.sale_getProblems
(INDEX (ticketFk))
ENGINE = MEMORY
SELECT f.id ticketFk
SELECT f.id ticketFk, f.clientFk, f.warehouseFk, f.shipped
FROM tmp.filter f
LEFT JOIN alertLevel al ON al.id = f.alertLevel
WHERE (al.code = 'FREE' OR f.alertLevel IS NULL)
@ -282,7 +282,7 @@ module.exports = Self => {
stmts.push('CALL ticket_getWarnings()');
stmt = new ParameterizedSQL(`
UPDATE tmp.ticketProblems
UPDATE tmp.ticket_problems
SET risk = IF(hasRisk, risk, 0)
`);
stmts.push(stmt);
@ -290,7 +290,7 @@ module.exports = Self => {
stmt = new ParameterizedSQL(`
SELECT *
FROM tmp.filter f
LEFT JOIN tmp.ticketProblems tp ON tp.ticketFk = f.id
LEFT JOIN tmp.ticket_problems tp ON tp.ticketFk = f.id
LEFT JOIN tmp.ticket_warnings tw ON tw.ticketFk = f.id
`);
stmts.push(stmt);
@ -307,8 +307,8 @@ module.exports = Self => {
{'tp.hasRisk': true},
{'tp.hasTicketRequest': true},
{'tp.hasComponentLack': true},
{'tp.isTaxDataChecked': true},
{'tp.hasItemShortage': true},
{'tp.isTaxDataChecked': false},
{'tp.itemShortage': {neq: null}},
{'tp.isTooLittle': true}
]};
} else if (hasProblems === false) {
@ -317,8 +317,8 @@ module.exports = Self => {
{'tp.hasRisk': false},
{'tp.hasTicketRequest': false},
{'tp.hasComponentLack': false},
{'tp.isTaxDataChecked': false},
{'tp.hasItemShortage': false},
{'tp.isTaxDataChecked': true},
{'tp.itemShortage': null},
{'tp.isTooLittle': false}
]};
}
@ -392,9 +392,9 @@ module.exports = Self => {
stmts.push(`
DROP TEMPORARY TABLE
tmp.ticket,
tmp.filter,
tmp.ticketProblems,
tmp.ticket_problems,
tmp.sale_getProblems,
tmp.sale_getWarnings,
tmp.ticket_warnings
`);

View File

@ -68,7 +68,7 @@ describe('SalesMonitor salesFilter()', () => {
const filter = {};
const result = await models.SalesMonitor.salesFilter(ctx, filter, options);
expect(result.length).toEqual(5);
expect(result.length).toEqual(4);
await tx.rollback();
} catch (e) {

View File

@ -31,7 +31,7 @@ describe('route getSuggestedTickets()', () => {
const length = result.length;
const anyResult = result[Math.floor(Math.random() * Math.floor(length))];
expect(result.length).toEqual(5);
expect(result.length).toEqual(4);
expect(anyResult.zoneFk).toEqual(1);
expect(anyResult.agencyModeFk).toEqual(8);

View File

@ -14,7 +14,7 @@ describe('route unlink()', () => {
let tickets = await models.Route.getSuggestedTickets(routeId, options);
expect(zoneAgencyModes.length).toEqual(4);
expect(tickets.length).toEqual(4);
expect(tickets.length).toEqual(3);
await models.Route.unlink(agencyModeId, zoneId, options);

View File

@ -1,128 +0,0 @@
const {ParameterizedSQL} = require('loopback-connector');
const {buildFilter, mergeFilters} = require('vn-loopback/util/filter');
module.exports = Self => {
Self.remoteMethodCtx('filter', {
description: 'Find all instances of the model matched by filter from the data source.',
accessType: 'READ',
accepts: [{
arg: 'filter',
type: 'object',
description: 'Filter defining where, order, skip and limit - must be a JSON-encoded string',
http: {source: 'query'}
}, {
arg: 'search',
type: 'string',
description: 'Searchs the vehicle by id or numberPlate',
http: {source: 'query'}
}, {
arg: 'id',
type: 'number'
}, {
arg: 'description',
type: 'string'
}, {
arg: 'companyFk',
type: 'number'
}, {
arg: 'tradeMark',
type: 'string'
}, {
arg: 'numberPlate',
type: 'string'
}, {
arg: 'warehouseFk',
type: 'number'
}, {
arg: 'chassis',
type: 'string'
}, {
arg: 'leasing',
type: 'string'
}, {
arg: 'countryCodeFk',
type: 'string'
}, {
arg: 'vehicleTypeFk',
type: 'number'
}, {
arg: 'vehicleStateFk',
type: 'number'
}],
returns: {
type: ['object'],
root: true
},
http: {
path: `/filter`,
verb: `GET`
}
});
Self.filter = async(ctx, filter, options) => {
const conn = Self.dataSource.connector;
const myOptions = {};
if (typeof options == 'object') Object.assign(myOptions, options);
const where = buildFilter(ctx.args, (param, value) => {
switch (param) {
case 'search':
return {or: [{'v.id': value}, {numberPlate: {like: `%${value}%`}}]};
case 'id':
return {'v.id': value};
case 'description':
case 'tradeMark':
case 'numberPlate':
case 'chassis':
case 'leasing':
return {[param]: {like: `%${value}%`}};
case 'companyFk':
case 'warehouseFk':
case 'countryCodeFk':
case 'vehicleStateFk':
case 'vehicleTypeFk':
return {[param]: value};
}
});
filter = mergeFilters(filter, {where});
const stmt = new ParameterizedSQL(`
SELECT v.id,
v.numberPlate,
v.tradeMark,
v.model,
v.m3,
v.description,
v.isActive,
v.countryCodeFk,
v.chassis,
v.leasing,
vt.name type,
w.name warehouse,
c.code company,
sub.state
FROM vehicle v
JOIN vehicleType vt ON vt.id = v.vehicleTypeFk
LEFT JOIN warehouse w ON w.id = v.warehouseFk
LEFT JOIN company c ON c.id = v.companyFk
LEFT JOIN (
SELECT e.vehicleFk,
e.vehicleStateFk,
s.state,
ROW_NUMBER() OVER (PARTITION BY e.vehicleFk ORDER BY e.started DESC) rn
FROM vehicleEvent e
LEFT JOIN vehicleState s ON e.vehicleStateFk = s.id
) sub ON sub.vehicleFk = v.id AND sub.rn = 1
`);
const sqlWhere = conn.makeWhere(filter.where);
stmt.merge(sqlWhere);
stmt.merge(conn.makePagination(filter));
const sql = ParameterizedSQL.join([stmt], ';');
return conn.executeStmt(sql, myOptions);
};
};

View File

@ -1,127 +0,0 @@
const {models} = require('vn-loopback/server/server');
describe('Vehicle filter()', () => {
const deliveryAssiId = 123;
const ctx = beforeAll.getCtx(deliveryAssiId);
let options;
let tx;
beforeEach(async() => {
ctx.args = {};
options = {};
tx = await models.Sale.beginTransaction({});
options.transaction = tx;
});
afterEach(async() => {
await tx.rollback();
});
it('should return the vehicles matching "search"', async() => {
const {id} = await models.Vehicle.findById(1, null, options);
const {numberPlate} = await models.Vehicle.findById(2, null, options);
ctx.args = {search: id};
const [searchResult] = await models.Vehicle.filter(ctx);
ctx.args = {search: numberPlate};
const [searchResult2] = await models.Vehicle.filter(ctx);
expect(searchResult.id).toEqual(id);
expect(searchResult2.numberPlate).toEqual(numberPlate);
});
it('should return the vehicles matching "companyFk"', async() => {
const company = await models.Company.findOne({where: {code: 'VNL'}}, options);
ctx.args = {companyFk: company.id};
const searchResult = await models.Vehicle.filter(ctx, null, options);
searchResult.forEach(record => {
expect(record.company).toEqual(company.code);
});
});
it('should return the vehicles matching "tradeMark"', async() => {
const tradeMark = 'WAYNE INDUSTRIES';
ctx.args = {tradeMark};
const searchResult = await models.Vehicle.filter(ctx);
searchResult.forEach(record => {
expect(record.tradeMark).toEqual(tradeMark);
});
});
it('should return the vehicles matching "numberPlate"', async() => {
const {numberPlate} = await models.Vehicle.findById(1, null, options);
ctx.args = {numberPlate};
const searchResult = await models.Vehicle.filter(ctx);
searchResult.forEach(record => {
expect(record.numberPlate).toEqual(numberPlate);
});
});
it('should return the vehicles matching "warehouseFk"', async() => {
const warehouse = await models.Warehouse.findById(1, null, options);
ctx.args = {warehouseFk: warehouse.id};
const searchResult = await models.Vehicle.filter(ctx);
searchResult.forEach(record => {
expect(record.warehouse).toEqual(warehouse.name);
});
});
it('should return the vehicles matching "chassis"', async() => {
const {chassis} = await models.Vehicle.findById(1, null, options);
ctx.args = {chassis};
const [searchResult] = await models.Vehicle.filter(ctx);
expect(searchResult.chassis).toEqual(chassis);
});
it('should return the vehicles matching "leasing"', async() => {
const leasing = 'Wayne leasing';
ctx.args = {leasing};
const searchResult = await models.Vehicle.filter(ctx);
searchResult.forEach(record => {
expect(record.leasing).toEqual(leasing);
});
});
it('should return the vehicles matching "countryCodeFk"', async() => {
const countryCodeFk = 'ES';
ctx.args = {countryCodeFk};
const searchResult = await models.Vehicle.filter(ctx);
searchResult.forEach(record => {
expect(record.countryCodeFk).toEqual(countryCodeFk);
});
});
it('should return the vehicles matching "vehicleTypeFk"', async() => {
const {name, id} = await models.VehicleType.findById(1, null, options);
ctx.args = {vehicleTypeFk: id};
const searchResult = await models.Vehicle.filter(ctx);
searchResult.forEach(record => {
expect(record.type).toEqual(name);
});
});
it('should return the vehicles matching "vehicleStateFk"', async() => {
const {state, id} = await models.VehicleState.findById(3);
ctx.args = {vehicleStateFk: id};
const searchResult = await models.Vehicle.filter(ctx);
searchResult.forEach(record => {
expect(record.state).toEqual(state);
});
});
it('should return the vehicles matching "description"', async() => {
const {description} = await models.Vehicle.findById(2);
ctx.args = {description};
const searchResult = await models.Vehicle.filter(ctx);
searchResult.forEach(record => {
expect(record.description).toEqual(description);
});
});
});

View File

@ -5,21 +5,12 @@
"AgencyTermConfig": {
"dataSource": "vn"
},
"BankPolicy": {
"dataSource": "vn"
},
"Cmr": {
"dataSource": "vn"
},
"DeliveryPoint": {
"dataSource": "vn"
},
"FuelType": {
"dataSource": "vn"
},
"Ppe": {
"dataSource": "vn"
},
"RoadmapAddress": {
"dataSource": "vn"
},
@ -44,12 +35,6 @@
"Vehicle": {
"dataSource": "vn"
},
"VehicleState": {
"dataSource": "vn"
},
"VehicleType": {
"dataSource": "vn"
},
"RoutesMonitor": {
"dataSource": "vn"
}

View File

@ -1,21 +0,0 @@
{
"name": "BankPolicy",
"base": "VnModel",
"options": {
"mysql": {
"table": "bankPolicy"
}
},
"properties": {
"id": {
"type": "number",
"id": true
},
"ref": {
"type": "string"
},
"dmsFk": {
"type": "number"
}
}
}

View File

@ -1,30 +0,0 @@
{
"name": "FuelType",
"base": "VnModel",
"options": {
"mysql": {
"table": "fuelType"
}
},
"properties": {
"id": {
"type": "number",
"id": true,
"description": "Identifier"
},
"name": {
"type": "string"
},
"code": {
"type": "string"
}
},
"acls": [
{
"accessType": "READ",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
}
]
}

View File

@ -1,15 +0,0 @@
{
"name": "Ppe",
"base": "VnModel",
"options": {
"mysql": {
"table": "ppe"
}
},
"properties": {
"id": {
"type": "number",
"id": true
}
}
}

View File

@ -1,21 +0,0 @@
{
"name": "VehicleState",
"base": "VnModel",
"options": {
"mysql": {
"table": "vehicleState"
}
},
"properties": {
"id": {
"type": "number",
"id": true
},
"state": {
"type": "string"
},
"hasToNotify": {
"type": "number"
}
}
}

View File

@ -1,19 +0,0 @@
{
"name": "VehicleType",
"base": "VnModel",
"options": {
"mysql": {
"table": "vehicleType"
}
},
"properties": {
"id": {
"type": "number",
"id": true,
"description": "Identifier"
},
"name": {
"type": "string"
}
}
}

View File

@ -1,4 +1,3 @@
module.exports = Self => {
require('../methods/vehicle/sorted')(Self);
require('../methods/vehicle/filter')(Self);
};

View File

@ -3,7 +3,7 @@
"base": "VnModel",
"options": {
"mysql": {
"table": "vehicle"
"table": "vehicle"
}
},
"properties": {
@ -29,39 +29,6 @@
},
"isActive": {
"type": "number"
},
"countryCodeFk": {
"type": "string"
},
"chassis": {
"type": "string"
},
"leasing": {
"type": "string"
},
"isKmTruckRate": {
"type": "number"
},
"fuelTypeFk": {
"type": "number"
},
"import": {
"type": "number"
},
"importCooler": {
"type": "number"
},
"vin": {
"type": "string"
},
"ppeFk": {
"type": "number"
},
"vehicleTypeFk": {
"type": "number"
},
"deliveryPointFk": {
"type": "number"
}
},
"relations": {
@ -79,57 +46,21 @@
"type": "belongsTo",
"model": "DeliveryPoint",
"foreignKey": "deliveryPointFk"
},
"event": {
"type": "hasMany",
"model": "VehicleEvent",
"foreignKey": "vehicleFk",
"property": "id"
},
"supplier": {
"type": "belongsTo",
"model": "Supplier",
"foreignKey": "supplierFk"
},
"supplierCooler": {
"type": "belongsTo",
"model": "Supplier",
"foreignKey": "supplierCoolerFk"
},
"bankPolicy": {
"type": "belongsTo",
"model": "BankPolicy",
"foreignKey": "bankPolicyFk"
},
"fuelType": {
"type": "belongsTo",
"model": "FuelType",
"foreignKey": "fuelTypeFk"
},
"ppe": {
"type": "hasOne",
"model": "Ppe",
"foreignKey": "id",
"property": "ppeFk"
},
"type": {
"type": "hasOne",
"model": "VehicleType",
"foreignKey": "id",
"property": "vehicleTypeFk"
}
},
"scopes": {
"active": {
"fields": [
"id",
"numberPlate"
],
"where": {
"isActive": {
"scope": {
"where": {
"isActive": {
"neq": false
}
}
},
"acls": [
{
"accessType": "READ",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
}
}
}
]
}

View File

@ -7,6 +7,6 @@ describe('Supplier getItemsPackaging()', () => {
expect(item.id).toEqual(1);
expect(item.name).toEqual('Ranged weapon longbow 200cm');
expect(item.quantity).toEqual(5000);
expect(item.quantityTotal).toEqual(5200);
expect(item.quantityTotal).toEqual(5100);
});
});

View File

@ -49,7 +49,7 @@ module.exports = Self => {
ps.monitorId,
e.created
FROM expedition e
JOIN host h ON h.code = e.hostFk
JOIN host h ON Convert(h.code USING utf8mb3) COLLATE utf8mb3_unicode_ci = e.hostFk
JOIN packingSite ps ON ps.hostFk = h.id
WHERE e.id = ?;`;
const [expedition] = await models.Expedition.rawSql(query, [id]);

View File

@ -44,14 +44,12 @@ module.exports = Self => {
ps.monitorId,
e.created
FROM expedition e
JOIN host h ON h.code = e.hostFk
JOIN packingSite ps ON ps.hostFk = h.id
JOIN host h ON Convert(h.code USING utf8mb3) COLLATE utf8mb3_unicode_ci = e.hostFk
JOIN packingSite ps ON ps.hostFk = h.id
WHERE e.id = ?;`;
const [expedition] = await models.PackingSiteConfig.rawSql(query, [id], myOptions);
const [expedition] = await models.PackingSiteConfig.rawSql(query, [id]);
if (!from && !expedition) return [];
let start = new Date(expedition.created);
let end = new Date(start.getTime() + (packingSiteConfig.avgBoxingTime * 1000));
@ -59,13 +57,9 @@ module.exports = Self => {
start.setHours(from, 0, 0);
end.setHours(to, 0, 0);
}
const offset = start.getTimezoneOffset();
start = new Date(start.getTime() - (offset * 60 * 1000));
end = new Date(end.getTime() - (offset * 60 * 1000));
const minutes = start.getMinutes();
const roundedMinutes = minutes - (minutes % 15);
start.setMinutes(roundedMinutes, 0, 0);
const videoUrl =
`/${packingSiteConfig.shinobiToken}/videos/${packingSiteConfig.shinobiGroupKey}/${expedition.monitorId}`;
@ -79,7 +73,6 @@ module.exports = Self => {
} catch (e) {
return [];
}
return response.data.videos.map(video => video.filename);
};
};

View File

@ -2,28 +2,35 @@ const models = require('vn-loopback/server/server').models;
const axios = require('axios');
describe('boxing getVideoList()', () => {
let tx;
let options;
it('should return video list', async() => {
const tx = await models.PackingSiteConfig.beginTransaction({});
beforeEach(async() => {
tx = await models.PackingSiteConfig.beginTransaction({});
options = {transaction: tx};
});
try {
const options = {transaction: tx};
afterEach(async() => {
await tx.rollback();
});
const id = 1;
const from = 1;
const to = 2;
it('should make the correct API call', async() => {
const expedition = await models.Expedition.findById(15, null, options);
await expedition.updateAttribute('created', '2000-12-01 07:07:00', options);
const response = {
data: {
videos: [{
id: 1,
filename: 'video1.mp4'
}]
}
};
const axiosSpy = spyOn(axios, 'get').and.callThrough();
await models.Boxing.getVideoList(expedition.id, undefined, undefined, options);
spyOn(axios, 'get').and.returnValue(new Promise(resolve => resolve(response)));
const expectedStartTime = '2000-12-01T07:00:00';
const calledUrl = axiosSpy.calls.mostRecent().args[0];
const result = await models.Boxing.getVideoList(id, from, to, options);
expect(calledUrl).toContain(`start=${expectedStartTime}`);
expect(result[0]).toEqual(response.data.videos[0].filename);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -30,6 +30,7 @@ module.exports = Self => {
SELECT
s.id AS saleFk,
t.id AS ticketFk,
t.landed,
s.concept,
s.itemFk,
s.quantity,
@ -40,10 +41,11 @@ module.exports = Self => {
INNER JOIN vn.sale s ON s.ticketFk = t.id
LEFT JOIN vn.claimBeginning cb ON cb.saleFk = s.id
WHERE t.id = ?
AND cb.id IS NULL`;
WHERE (t.landed) >= TIMESTAMPADD(DAY, -7, ?)
AND t.id = ? AND cb.id IS NULL
ORDER BY t.landed DESC, t.id DESC`;
const claimableSales = await Self.rawSql(query, [ticketFk], myOptions);
const claimableSales = await Self.rawSql(query, [date, ticketFk], myOptions);
return claimableSales;
};

View File

@ -1,99 +0,0 @@
module.exports = Self => {
Self.remoteMethodCtx('replaceItem', {
description: 'Replace item from sale',
accessType: 'WRITE',
accepts: [
{
arg: 'saleFk',
type: 'number',
required: true,
},
{
arg: 'substitutionFk',
type: 'number',
required: true
},
{
arg: 'quantity',
type: 'number',
required: true
}
],
returns: {
type: 'object',
root: true
},
http: {
path: `/replaceItem`,
verb: 'POST'
}
});
Self.replaceItem = async(ctx, saleFk, substitutionFk, quantity, options) => {
const myOptions = {userId: ctx.req.accessToken.userId};
let tx;
const $t = ctx.req.__;
const models = Self.app.models;
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
const replaceItemQuery = {
sql: 'CALL sale_replaceItem(?,?,?)',
query: [saleFk, substitutionFk, quantity]
};
const resultReplaceItem = await Self.rawSql(replaceItemQuery.sql, replaceItemQuery.query, myOptions);
const sale = await models.Sale.findById(saleFk, {
fields: ['id', 'ticketFk', 'itemFk', 'quantity', 'price'],
include: [
{
relation: 'ticket',
scope: {
fields: ['id']
},
}, {
relation: 'item',
scope: {
fields: ['id', 'name', 'longName']
}
}
]
}, myOptions);
const salesPersonQuery = {
sql: 'SELECT vn.client_getSalesPersonByTicket(?)',
query: [sale.ticketFk]
};
const salesPerson = await Self.rawSql(salesPersonQuery.sql, salesPersonQuery.query, myOptions);
const url = await models.Url.getUrl();
const substitution = await models.Item.findById(substitutionFk, {
fields: ['id', 'name', 'longName']
}, myOptions);
const message = $t('negativeReplaced', {
oldItemId: sale.itemFk,
oldItem: sale.item().longName,
oldItemUrl: `${url}item/${sale.itemFk}/summary`,
newItemId: substitution.id,
newItem: substitution.longName,
newItemUrl: `${url}item/${substitution.id}/summary`,
ticketId: sale.ticketFk,
ticketUrl: `${url}ticket/${sale.ticketFk}/sale`
});
await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message);
return resultReplaceItem;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
};
};

View File

@ -1,61 +0,0 @@
const {models} = require('vn-loopback/server/server');
describe('Sale - replaceItem function', () => {
let options;
let tx;
const ctx = beforeAll.getCtx();
beforeAll.mockLoopBackContext();
beforeEach(async() => {
tx = await models.Sale.beginTransaction({});
options = {transaction: tx};
});
afterEach(async() => {
if (tx)
await tx.rollback();
});
it('should replace full item in sale and send notification', async() => {
const saleFk = 43;
const substitutionFk = 3;
const quantity = 15;
const ticketFk = 1000000;
const salesBefore = await models.Sale.find({where: {ticketFk}}, options);
const salesLength = salesBefore.length;
expect(1).toEqual(salesBefore.length);
await models.Sale.replaceItem(ctx, saleFk, substitutionFk, quantity, options);
const salesAfter = await models.Sale.find({where: {ticketFk}}, options);
expect(salesLength).toBeLessThan(salesAfter.length);
expect(salesAfter[0].id).toEqual(saleFk);
expect(salesAfter[salesLength].itemFk).toEqual(substitutionFk);
expect(salesAfter[salesLength].quantity).toEqual(quantity);
expect(salesAfter[0].quantity).toEqual(0);
expect(salesAfter[salesLength].concept).toMatch(/^\+/);
});
it('should replace half item in sale and send notification', async() => {
const saleFk = 43;
const substitutionFk = 3;
const quantity = 10;
const ticketFk = 1000000;
const salesBefore = await models.Sale.find({where: {ticketFk}}, options);
const salesLength = salesBefore.length;
expect(1).toEqual(salesBefore.length);
await models.Sale.replaceItem(ctx, saleFk, substitutionFk, quantity, options);
const salesAfter = await models.Sale.find({where: {ticketFk}}, options);
expect(salesLength).toBeLessThan(salesAfter.length);
expect(salesAfter[0].id).toEqual(saleFk);
expect(salesAfter[salesLength].itemFk).toEqual(substitutionFk);
expect(salesAfter[salesLength].quantity).toEqual(quantity);
expect(salesAfter[0].quantity).toEqual(5);
expect(salesAfter[salesLength].concept).toMatch(/^\+/);
});
});

View File

@ -113,12 +113,6 @@ module.exports = Self => {
const salesPerson = sale.ticket().client().salesPersonUser();
if (salesPerson) {
const url = await Self.app.models.Url.getUrl();
const saleCloned = await Self.app.models.SaleCloned.findById(sale.id, {
include: 'saleOriginal',
});
const ticketWeekly = saleCloned?.saleOriginal()?.ticketFk || null;
const message = $t('Changed sale price', {
ticketId: sale.ticket().id,
itemId: sale.itemFk,
@ -127,8 +121,7 @@ module.exports = Self => {
oldPrice: oldPrice,
newPrice: newPrice,
ticketUrl: `${url}ticket/${sale.ticket().id}/sale`,
itemUrl: `${url}item/${sale.itemFk}/summary`,
ticketWeekly: ticketWeekly ? $t('clonedFromTicketWeekly', {ticketWeekly}) : null
itemUrl: `${url}item/${sale.itemFk}/summary`
});
await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message, myOptions);
}

View File

@ -72,12 +72,6 @@ module.exports = Self => {
const salesPerson = sale.ticket().client().salesPersonUser();
if (salesPerson) {
const url = await Self.app.models.Url.getUrl();
const saleCloned = await Self.app.models.SaleCloned.findById(sale.id, {
include: 'saleOriginal',
});
const ticketWeekly = saleCloned?.saleOriginal()?.ticketFk || null;
const change = $t('Changes in sales', {
itemId: sale.itemFk,
concept: sale.concept,
@ -90,7 +84,6 @@ module.exports = Self => {
ticketId: sale.ticket().id,
changes: JSON.stringify(change),
ticketUrl: `${url}ticket/${sale.ticket().id}/sale`,
ticketWeekly: ticketWeekly ? $t('clonedFromTicketWeekly', {ticketWeekly}) : null
});
await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message, myOptions);

View File

@ -288,17 +288,21 @@ module.exports = Self => {
stmts.push(stmt);
stmt = new ParameterizedSQL(`
CREATE OR REPLACE TEMPORARY TABLE tmp.ticket
CREATE OR REPLACE TEMPORARY TABLE tmp.sale_getProblems
(INDEX (ticketFk))
ENGINE = MEMORY
SELECT f.id ticketFk
FROM tmp.filter f`);
SELECT f.id ticketFk, f.clientFk, f.warehouseFk, f.shipped
FROM tmp.filter f
LEFT JOIN alertLevel al ON al.id = f.alertLevel
WHERE (al.code = 'FREE' OR f.alertLevel IS NULL)
AND f.shipped >= ?
`, [date]);
stmts.push(stmt);
stmts.push('CALL ticket_getProblems(FALSE)');
stmt = new ParameterizedSQL(`
UPDATE tmp.ticketProblems
UPDATE tmp.ticket_problems
SET risk = IF(hasRisk, risk, 0)
`);
stmts.push(stmt);
@ -306,19 +310,43 @@ module.exports = Self => {
stmt = new ParameterizedSQL(`
SELECT f.*, tp.*
FROM tmp.filter f
LEFT JOIN tmp.ticketProblems tp ON tp.ticketFk = f.id
LEFT JOIN tmp.ticket_problems tp ON tp.ticketFk = f.id
`);
if (args.problems != undefined && (!args.from && !args.to))
throw new UserError('Choose a date range or days forward');
if (typeof args.problems == 'boolean') {
let condition = 0;
if (args.problems)
condition = {neq: condition};
stmt.merge(conn.makeWhere({'tp.totalProblems': condition}));
let condition;
let hasProblem;
let range;
let hasWhere;
switch (args.problems) {
case true:
condition = `or`;
hasProblem = true;
range = {neq: null};
hasWhere = true;
break;
case false:
condition = `and`;
hasProblem = null;
range = null;
hasWhere = true;
break;
}
const problems = {[condition]: [
{'tp.isFreezed': hasProblem},
{'tp.hasRisk': hasProblem},
{'tp.hasTicketRequest': hasProblem},
{'tp.itemShortage': range},
{'tp.hasRounding': hasProblem}
]};
if (hasWhere)
stmt.merge(conn.makeWhere(problems));
if (filter.order) {
if (typeof filter.order == 'string') filter.order = [filter.order];
const index = filter.order.findIndex(o => o.includes('stateFk'));
@ -337,9 +365,8 @@ module.exports = Self => {
stmts.push(
`DROP TEMPORARY TABLE
tmp.ticket,
tmp.filter,
tmp.ticketProblems`);
tmp.ticket_problems`);
const sql = ParameterizedSQL.join(stmts, ';');
const result = await conn.executeStmt(sql, myOptions);

View File

@ -98,9 +98,14 @@ module.exports = Self => {
for (let sale of sales) {
const problems = saleProblems.get(sale.id);
const itemStock = itemAvailable.get(sale.itemFk);
sale.available = itemStock.available;
sale.visible = itemStock.visible;
sale.claim = claimedSales.get(sale.id);
if (problems) {
for (const problem in problems)
sale[problem] = problems[problem];
sale.itemShortage = problems.itemShortage;
sale.hasTicketRequest = problems.hasTicketRequest;
sale.hasComponentLack = problems.hasComponentLack;
}
if (salesWithLogs.includes(sale.id))
sale.$hasLogs = true;

View File

@ -1,83 +0,0 @@
const {buildFilter} = require('vn-loopback/util/filter');
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
module.exports = Self => {
Self.remoteMethodCtx('getTicketProblems', {
description: 'Get problems for a ticket',
accessType: 'READ',
accepts: [{
arg: 'id',
type: 'number',
required: true,
description: 'The ticket id',
http: {source: 'path'}
}],
returns: {
type: ['object'],
root: true
},
http: {
path: `/:id/getTicketProblems`,
verb: 'get'
}
});
Self.getTicketProblems = async(ctx, id, options) => {
const myOptions = {};
const stmts = [];
const conn = Self.dataSource.connector;
let stmt;
const ticketId = id;
const where = buildFilter(ctx.args, param => {
switch (param) {
case 'id':
return {'t.id': ticketId};
}
});
if (typeof options == 'object')
Object.assign(myOptions, options);
stmt = new ParameterizedSQL(`
CREATE OR REPLACE TEMPORARY TABLE tmp.filter
(INDEX (id))
ENGINE = MEMORY
SELECT t.id
FROM ticket t
`);
stmt.merge(conn.makeWhere(where));
stmts.push(stmt);
stmt = new ParameterizedSQL(`
CREATE OR REPLACE TEMPORARY TABLE tmp.ticket
(INDEX (ticketFk))
ENGINE = MEMORY
SELECT f.id AS ticketFk
FROM tmp.filter f
`);
stmts.push(stmt);
stmts.push('CALL ticket_getProblems(FALSE)');
stmt = new ParameterizedSQL(`
SELECT f.*, tp.*
FROM tmp.filter f
LEFT JOIN tmp.ticketProblems tp ON tp.ticketFk = f.id
`);
const ticketsIndex = stmts.push(stmt) - 1;
stmts.push(`
DROP TEMPORARY TABLE IF EXISTS
tmp.filter,
tmp.ticket,
tmp.ticketProblems
`);
const sql = ParameterizedSQL.join(stmts, ';');
const result = await conn.executeStmt(sql, myOptions);
return result[ticketsIndex];
};
};

View File

@ -146,10 +146,10 @@ module.exports = Self => {
stmts.push(stmt);
stmt = new ParameterizedSQL(`
CREATE OR REPLACE TEMPORARY TABLE tmp.ticket
CREATE OR REPLACE TEMPORARY TABLE tmp.sale_getProblems
(INDEX (ticketFk))
ENGINE = MEMORY
SELECT f.id ticketFk
SELECT f.id ticketFk, f.clientFk, f.warehouseFk, f.shipped, f.lines, f.liters
FROM tmp.filter f
LEFT JOIN alertLevel al ON al.id = f.alertLevel
WHERE (al.code = 'FREE' OR f.alertLevel IS NULL)
@ -159,7 +159,7 @@ module.exports = Self => {
stmts.push('CALL ticket_getProblems(FALSE)');
stmt = new ParameterizedSQL(`
UPDATE tmp.ticketProblems
UPDATE tmp.ticket_problems
SET risk = IF(hasRisk, risk, 0)
`);
stmts.push(stmt);
@ -167,7 +167,7 @@ module.exports = Self => {
stmt = new ParameterizedSQL(`
SELECT f.*, tp.*
FROM tmp.filter f
LEFT JOIN tmp.ticketProblems tp ON tp.ticketFk = f.id
LEFT JOIN tmp.ticket_problems tp ON tp.ticketFk = f.id
`);
if (args.problems != undefined && (!args.originScopeDays && !args.futureScopeDays))
@ -175,17 +175,20 @@ module.exports = Self => {
let condition;
let hasProblem;
let range;
let hasWhere;
switch (args.problems) {
case true:
condition = `or`;
hasProblem = true;
range = {neq: null};
hasWhere = true;
break;
case false:
condition = `and`;
hasProblem = null;
range = null;
hasWhere = true;
break;
}
@ -195,7 +198,7 @@ module.exports = Self => {
{'tp.isFreezed': hasProblem},
{'tp.hasRisk': hasProblem},
{'tp.hasTicketRequest': hasProblem},
{'tp.hasItemShortage': hasProblem},
{'tp.itemShortage': range},
{'tp.hasComponentLack': hasProblem},
{'tp.isTooLittle': hasProblem},
{'tp.hasRounding': hasProblem}
@ -213,9 +216,8 @@ module.exports = Self => {
stmts.push(
`DROP TEMPORARY TABLE
tmp.ticket,
tmp.filter,
tmp.ticketProblems`);
tmp.ticket_problems`);
const sql = ParameterizedSQL.join(stmts, ';');
const result = await conn.executeStmt(sql, myOptions);

View File

@ -1,111 +0,0 @@
module.exports = Self => {
Self.remoteMethod('itemLack', {
description: 'Get tickets as negative status',
accessType: 'READ',
accepts: [
{
arg: 'ctx',
type: 'object',
http: {source: 'context'}
},
{
arg: 'filter',
type: 'object',
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string',
http: {source: 'query'}
},
{
arg: 'id',
type: 'number',
description: 'The item id',
},
{
arg: 'longname',
type: 'string',
description: 'Article name',
},
{
arg: 'supplier',
type: 'string',
description: 'Supplier id',
},
{
arg: 'colour',
type: 'string',
description: 'Colour\'s item',
},
{
arg: 'size',
type: 'string',
description: 'Size\'s item',
},
{
arg: 'origen',
type: 'string',
description: 'origen id',
},
{
arg: 'warehouseFk',
type: 'number',
description: 'The warehouse id',
},
{
arg: 'lack',
type: 'number',
description: 'The item id',
},
{
arg: 'days',
type: 'number',
description: 'The range days',
}
],
returns: [
{
arg: 'body',
type: ['object'],
root: true
}
],
http: {
path: `/itemLack`,
verb: 'GET'
}
});
Self.itemLack = async(ctx, filter, options) => {
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const filterKeyOrder = [
'id', 'force', 'days', 'longname', 'supplier',
'colour', 'size', 'originFk',
'lack', 'warehouseFk'
];
delete ctx?.args?.ctx;
delete ctx?.args?.filter;
Object.assign(filter, ctx.args ?? {});
let procedureParams = [];
procedureParams.push(...filterKeyOrder.map(clave => filter[clave] ?? null));
// Default values
const forceIndex = filterKeyOrder.indexOf('force');
if (!procedureParams[forceIndex])procedureParams[forceIndex] = true;
const daysIndex = filterKeyOrder.indexOf('days');
if (!procedureParams[daysIndex])procedureParams[daysIndex] = 2;
const procedureArgs = Array(procedureParams.length).fill('?').join(', ');
let query = `CALL vn.item_getLack(${procedureArgs})`;
const result = await Self.rawSql(query, procedureParams, myOptions);
const itemsIndex = 0;
return result[itemsIndex];
};
};

View File

@ -1,167 +0,0 @@
const {ParameterizedSQL} = require('loopback-connector');
module.exports = Self => {
Self.remoteMethod('itemLackDetail', {
description: 'Retrieve detail from ticket as negative',
accessType: 'READ',
accepts: [
{
arg: 'itemFk',
type: 'number',
description: 'The item as negative status',
},
{
arg: 'filter',
type: 'object',
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string',
http: {source: 'query'}
}
],
returns: [
{
arg: 'body',
type: ['object'],
root: true,
},
],
http: {
path: `/itemLack/:itemFk`,
verb: 'GET',
},
});
Self.itemLackDetail = async(itemFk, filter, options) => {
const conn = Self.dataSource.connector;
const myOptions = {};
if (typeof options == 'object') Object.assign(myOptions, options);
const vDated = (Date.vnNew());
vDated.setHours(0, 0, 0, 0);
const scopeDays = filter.where.scopeDays ?? 0;
let alertLevels = filter.where.alertLevelCode;
if (!alertLevels)
alertLevels = (await Self.app.models.AlertLevel.find({fields: ['code']})).map(({code}) => code);
const stmt = new ParameterizedSQL(`
SELECT s.id,
st.code,
t.id,
t.nickname,
c.id customerId,
t.shipped,
s.quantity,
ag.name,
ag.id agencyFk,
tls.alertLevel alertLevel,
st.name stateName,
s.id saleFk,
s.itemFk,
s.price price,
al.code alertLevelCode,
z.name zoneName,
z.id zoneFk,
z.hour theoreticalhour,
cn.isRookie,
sc.saleClonedFk turno,
tr.saleFk peticionCompra,
DATE_FORMAT(IF(HOUR(t.shipped), t.shipped, IF(zc.hour, zc.hour, z.hour)),'%H:%i') minTimed,
FALSE isBasket,
substitution.hasObservation,
(d.code = 'spainTeamVip') hasToIgnore
FROM sale s
LEFT JOIN saleGroupDetail sgd ON sgd.saleFk = s.id
JOIN ticket t ON t.id = s.ticketFk
LEFT JOIN zone z ON z.id = t.zoneFk
LEFT JOIN zoneClosure zc ON zc.zoneFk = t.zoneFk
AND t.shipped BETWEEN zc.dated AND util.dayEnd(t.shipped)
JOIN client c ON c.id=t.clientFk
LEFT JOIN bs.clientNewBorn cn ON cn.clientFk=c.id
JOIN agencyMode ag ON ag.id=t.agencyModeFk
JOIN ticketState tls ON tls.ticketFk=t.id
LEFT JOIN state st ON st.id=tls.state
LEFT JOIN alertLevel al ON al.id = st.alertLevel
LEFT JOIN saleCloned sc ON sc.saleClonedFk = s.id
LEFT JOIN ticketRequest tr ON tr.saleFk = s.id
LEFT JOIN workerDepartment wd ON wd.workerFk = c.salesPersonFk
LEFT JOIN department d ON d.id = wd.departmentFk
LEFT JOIN (
SELECT co.clientFk, COUNT(*) hasObservation
FROM clientObservation co
JOIN observationType ot ON ot.id = co.observationTypeFk
WHERE ot.code = 'substitution'
GROUP BY co.clientFk
) substitution ON substitution.clientFk = c.id
WHERE t.warehouseFk = ?
AND s.itemFk = ?
AND s.quantity <> 0
AND t.shipped BETWEEN ? AND (? + INTERVAL ? DAY)
AND sgd.saleFk IS NULL
AND (al.code IN (?) OR al.id IS NULL)
UNION ALL
SELECT r.id,
NULL,
r.orderFk,
c.name customerName,
c.id customerId,
r.shipment,
r.amount,
ag.name,
ag.id,
NULL,
NULL,
NULL,
r.itemFk,
NULL,
NULL,
NULL,
NULL,
NULL,
cn.isRookie,
NULL,
NULL,
NULL,
TRUE,
substitution.hasObservation,
d.code = 'spainTeamVip'
FROM hedera.orderRow r
JOIN hedera.order o ON o.id = r.orderFk
JOIN client c ON c.id = o.customer_id
JOIN agencyMode ag ON ag.id=o.agency_id
LEFT JOIN bs.clientNewBorn cn ON cn.clientFk=c.id
LEFT JOIN workerDepartment wd ON wd.workerFk = c.salesPersonFk
LEFT JOIN department d ON d.id = wd.departmentFk
LEFT JOIN (
SELECT co.clientFk, COUNT(*) hasObservation
FROM clientObservation co
JOIN observationType ot ON ot.id = co.observationTypeFk
WHERE ot.code = 'substitution'
GROUP BY co.clientFk
) substitution ON substitution.clientFk = c.id
WHERE r.shipment BETWEEN ? AND ? + INTERVAL ? DAY
AND r.created >= ?
AND r.warehouseFk = ?
AND NOT o.confirmed
AND r.itemFk = ?
AND r.amount
ORDER BY hasToIgnore, isBasket
`,
[
filter.where.warehouseFk,
itemFk,
vDated, vDated,
scopeDays,
alertLevels,
scopeDays,
vDated, vDated, vDated,
filter.where.warehouseFk,
itemFk
]);
const sql = ParameterizedSQL.join([stmt], ';');
const result = await conn.executeStmt(sql, myOptions);
return result;
};
};

View File

@ -42,11 +42,11 @@ describe('ticket filter()', () => {
const result = await models.Ticket.filter(ctx, filter, options);
const hasProblemTicket = result.some(ticket =>
ticket.isFreezed == true ||
ticket.hasRisk == true ||
ticket.hasTicketRequest == true ||
ticket.hasRounding == true ||
ticket.hasItemShortage == true
ticket.isFreezed === true ||
ticket.hasRisk === true ||
ticket.hasTicketRequest === true ||
(typeof ticket.hasRounding === 'string' && ticket.hasRounding.trim().length > 0) ||
(typeof ticket.itemShortage === 'string' && ticket.itemShortage.trim().length > 0)
);
expect(hasProblemTicket).toBe(true);
@ -80,11 +80,11 @@ describe('ticket filter()', () => {
const result = await models.Ticket.filter(ctx, filter, options);
result.forEach(ticket => {
expect(ticket.isFreezed).toEqual(0);
expect(ticket.hasRisk).toEqual(0);
expect(ticket.hasTicketRequest).toEqual(0);
expect(ticket.hasItemShortage).toEqual(0);
expect(ticket.hasRounding).toEqual(0);
expect(ticket.isFreezed).toEqual(null);
expect(ticket.hasRisk).toEqual(null);
expect(ticket.hasTicketRequest).toEqual(null);
expect(ticket.itemShortage).toEqual(null);
expect(ticket.hasRounding).toEqual(null);
});
await tx.rollback();

View File

@ -15,6 +15,7 @@ describe('ticket getSales()', () => {
expect(sales[1].item).toBeDefined();
expect(sales[2].item).toBeDefined();
expect(sales[3].item).toBeDefined();
expect(sales[0].claim).toBeDefined();
await tx.rollback();
} catch (e) {

View File

@ -1,21 +0,0 @@
const models = require('vn-loopback/server/server').models;
describe('ticket getTicketProblems()', () => {
const ctx = {req: {accessToken: 9}};
it('should return the problems of a ticket', async() => {
const tx = await models.Ticket.beginTransaction({});
try {
const options = {transaction: tx};
const problems = await models.Ticket.getTicketProblems(ctx, 11, options);
expect(problems[7].totalProblems).toEqual(3);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -1,80 +0,0 @@
const {models} = require('vn-loopback/server/server');
describe('Item Lack', () => {
let options;
let tx;
const ctx = beforeAll.getCtx();
beforeAll.mockLoopBackContext();
beforeEach(async() => {
tx = await models.Ticket.beginTransaction({});
options = {transaction: tx};
});
afterEach(async() => {
if (tx)
await tx.rollback();
});
it('should return data with NO filters', async() => {
const filter = {};
const result = await models.Ticket.itemLack(ctx, filter, options);
expect(result.length).toEqual(2);
});
it('should return data with filter.id', async() => {
const filter = {
id: 5
};
const result = await models.Ticket.itemLack(ctx, filter, options);
expect(result.length).toEqual(1);
});
it('should return data with filter.longname', async() => {
const filter = {
longname: 'Ranged weapon pistol 9mm'
};
const result = await models.Ticket.itemLack(ctx, filter, options);
expect(result.length).toEqual(1);
});
it('should return data with filter.color', async() => {
const filter = {
colour: 'WHT'
};
const result = await models.Ticket.itemLack(ctx, filter, options);
expect(result.length).toEqual(1);
});
it('should return data with filter.origen', async() => {
const filter = {
originFk: 1
};
const result = await models.Ticket.itemLack(ctx, filter, options);
expect(result.length).toEqual(2);
});
it('should return data with filter.size', async() => {
const filter = {
size: '15'
};
const result = await models.Ticket.itemLack(ctx, filter, options);
expect(result.length).toEqual(1);
});
it('should return data with filter.lack', async() => {
const filter = {
lack: '-15'
};
const result = await models.Ticket.itemLack(ctx, filter, options);
expect(result.length).toEqual(1);
});
});

View File

@ -1,55 +0,0 @@
const models = require('vn-loopback/server/server').models;
describe('Item Lack Detail', () => {
it('should return false if id is null', async() => {
const tx = await models.Ticket.beginTransaction({});
try {
const options = {transaction: tx};
const itemFk = null;
const filter = {where: {warehouseFk: 60}};
const result = await models.Ticket.itemLackDetail(itemFk, filter, options);
expect(result.length).toEqual(0);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return data if id exists', async() => {
const tx = await models.Ticket.beginTransaction({});
try {
const options = {transaction: tx};
const itemFk = 1167;
const filter = {where: {warehouseFk: 60}};
const result = await models.Ticket.itemLackDetail(itemFk, filter, options);
expect(result.length).toEqual(0);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return error is if not exists', async() => {
const tx = await models.Ticket.beginTransaction({});
try {
const options = {transaction: tx};
const itemFk = 0;
const filter = {where: {warehouseFk: 60}};
const result = await models.Ticket.itemLackDetail(itemFk, filter, options);
expect(result.length).toEqual(0);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -1,47 +0,0 @@
const {models} = require('vn-loopback/server/server');
describe('Split', () => {
let options;
let tx;
const ctx = beforeAll.getCtx();
beforeAll.mockLoopBackContext();
beforeEach(async() => {
tx = await models.Ticket.beginTransaction({});
options = {transaction: tx};
});
afterEach(async() => {
if (tx)
await tx.rollback();
});
it('should split tickets with count 1', async() => {
const data =
{ticketFk: 7, sales: [1]};
const result = await models.Ticket.split(ctx, data, options);
expect(data.ticketFk).toEqual(result.ticket);
expect('noSplit').toEqual(result.status);
});
it('should split tickets with count 2 and error', async() => {
const data =
{ticketFk: 11, sales: [7]}
;
const result = await models.Ticket.split(ctx, data, options);
expect(data.ticketFk).toEqual(result.ticket);
expect('error').toEqual(result.status);
expect('Can\'t transfer claimed sales').toEqual(result.message);
});
it('should split tickets with count 2 and success', async() => {
const data =
{ticketFk: 14, sales: [33]};
const result = await models.Ticket.split(ctx, data, options);
expect(data.ticketFk).toEqual(result.ticket);
expect('split').toEqual(result.status);
});
});

View File

@ -1,73 +0,0 @@
module.exports = Self => {
Self.remoteMethodCtx('split', {
description: 'Split ticket with custom date',
accessType: 'WRITE',
accepts: [
{
arg: 'ticket',
type: 'Object',
required: true,
http: {source: 'body'}
},
{
arg: 'date',
type: 'date',
required: true,
}
],
returns: {
type: ['Object'],
root: true
},
http: {
path: `/split`,
verb: 'POST'
}
});
Self.split = async(ctx, ticket, options) => {
const {ticketFk} = ticket;
const models = Self.app.models;
const myOptions = {};
let tx;
let result = [];
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
const count = await models.Sale.count({
ticketFk
}, myOptions);
if (count === 1)
return {ticket: ticketFk, status: 'noSplit'};
const [, [{vNewTicket}]] = await Self.rawSql(`
CALL vn.ticket_clone(?, @vNewTicket);
SELECT @vNewTicket vNewTicket;`,
[ticketFk], myOptions);
if (vNewTicket === 0) return result;
const sales = await models.Sale.find({
where: {id: {inq: ticket.sales}}
}, myOptions);
const updateIsPicked = sales.map(({sid}) => Self.rawSql(`
UPDATE vn.sale SET isPicked = (id = ?) WHERE ticketFk = ?`,
[sid, ticketFk], myOptions));
await Promise.all(updateIsPicked);
await Self.transferSales(ctx, ticketFk, vNewTicket, sales, myOptions);
await Self.rawSql(`CALL vn.ticket_setState(?, ?)`, [ticketFk, 'FIXING'], myOptions);
if (tx) await tx.commit();
return {ticket: ticketFk, newTicket: vNewTicket, status: 'split'};
} catch (e) {
if (tx) await tx.rollback();
return {ticket: ticketFk, status: 'error', message: e.message};
}
};
};

View File

@ -43,8 +43,8 @@ module.exports = Self => {
const {code} = await models.State.findById(params.stateFk, {fields: ['code']}, myOptions);
params.code = code;
} else {
const state = await models.State.findOne({where: {id: params.code}}, myOptions);
params.stateFk = state.id;
const {id} = await models.State.findOne({where: {code: params.code}}, myOptions);
params.stateFk = id;
}
if (!params.userFk) {

View File

@ -166,18 +166,10 @@ module.exports = Self => {
const salesPerson = ticket.client().salesPersonUser();
if (salesPerson) {
const url = await Self.app.models.Url.getUrl();
const saleId = sales[0].id;
const saleCloned = await Self.app.models.SaleCloned.findById(saleId, {
include: 'saleOriginal',
});
const ticketWeekly = saleCloned?.saleOriginal()?.ticketFk || null;
const message = $t('Changed sale discount', {
ticketId: id,
ticketUrl: `${url}ticket/${id}/sale`,
changes: changesMade,
ticketWeekly: ticketWeekly ? $t('clonedFromTicketWeekly', {ticketWeekly}) : null
changes: changesMade
});
await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message, myOptions);
}

View File

@ -13,7 +13,6 @@ module.exports = Self => {
require('../methods/sale/usesMana')(Self);
require('../methods/sale/clone')(Self);
require('../methods/sale/getFromSectorCollection')(Self);
require('../methods/sale/replaceItem')(Self);
Self.validatesPresenceOf('concept', {
message: `Concept cannot be blank`

View File

@ -26,12 +26,6 @@
},
"defaultAttenderFk": {
"type": "number"
},
"lackAlertPrice": {
"type": "number"
},
"lackScopeDays": {
"type": "number"
}
},
"relations": {

View File

@ -46,8 +46,4 @@ module.exports = function(Self) {
require('../methods/ticket/docuwareDownload')(Self);
require('../methods/ticket/myLastModified')(Self);
require('../methods/ticket/setWeight')(Self);
require('../methods/ticket/itemLack')(Self);
require('../methods/ticket/itemLackDetail')(Self);
require('../methods/ticket/split')(Self);
require('../methods/ticket/getTicketProblems')(Self);
};

View File

@ -1,6 +1,5 @@
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
const {mergeFilters, mergeWhere} = require('vn-loopback/util/filter');
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.remoteMethodCtx('filter', {
@ -34,10 +33,7 @@ module.exports = Self => {
const conn = Self.dataSource.connector;
const userId = ctx.req.accessToken.userId;
const models = Self.app.models;
const hasPrivs = await models.ACL.checkAccessAcl(ctx, 'WorkerDms', 'hasHighPrivs', '*');
if (!hasPrivs && userId !== id)
throw new UserError('You don\'t have enough privileges');
// Get ids alloweds
const account = await models.VnUser.findById(userId);

View File

@ -155,11 +155,6 @@
"type": "hasMany",
"model": "WorkerRelative",
"foreignKey": "workerFK"
},
"business": {
"type": "hasMany",
"model": "Business",
"foreignKey": "workerFk"
}
},
"acls": [

View File

@ -1,6 +1,6 @@
{
"name": "salix-back",
"version": "25.08.0",
"version": "25.06.0",
"author": "Verdnatura Levante SL",
"description": "Salix backend",
"license": "GPL-3.0",