Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into 6897-entryMigration

This commit is contained in:
Carlos Satorres 2024-06-11 09:19:05 +02:00
commit b38c5cdecc
46 changed files with 542 additions and 579 deletions

View File

@ -1772,8 +1772,8 @@ INSERT INTO `ACL` VALUES (688,'ClientSms','create','WRITE','ALLOW','ROLE','emplo
INSERT INTO `ACL` VALUES (689,'Vehicle','sorted','WRITE','ALLOW','ROLE','employee'); INSERT INTO `ACL` VALUES (689,'Vehicle','sorted','WRITE','ALLOW','ROLE','employee');
INSERT INTO `ACL` VALUES (690,'Roadmap','*','*','ALLOW','ROLE','palletizerBoss'); INSERT INTO `ACL` VALUES (690,'Roadmap','*','*','ALLOW','ROLE','palletizerBoss');
INSERT INTO `ACL` VALUES (691,'Roadmap','*','*','ALLOW','ROLE','productionBoss'); INSERT INTO `ACL` VALUES (691,'Roadmap','*','*','ALLOW','ROLE','productionBoss');
INSERT INTO `ACL` VALUES (692,'ExpeditionTruck','*','*','ALLOW','ROLE','production'); INSERT INTO `ACL` VALUES (692,'RoadmapStop','*','*','ALLOW','ROLE','production');
INSERT INTO `ACL` VALUES (693,'ExpeditionTruck','*','*','ALLOW','ROLE','productionBoss'); INSERT INTO `ACL` VALUES (693,'RoadmapStop','*','*','ALLOW','ROLE','productionBoss');
INSERT INTO `ACL` VALUES (695,'ViaexpressConfig','internationalExpedition','WRITE','ALLOW','ROLE','employee'); INSERT INTO `ACL` VALUES (695,'ViaexpressConfig','internationalExpedition','WRITE','ALLOW','ROLE','employee');
INSERT INTO `ACL` VALUES (696,'ViaexpressConfig','renderer','READ','ALLOW','ROLE','employee'); INSERT INTO `ACL` VALUES (696,'ViaexpressConfig','renderer','READ','ALLOW','ROLE','employee');
INSERT INTO `ACL` VALUES (697,'Ticket','transferClient','WRITE','ALLOW','ROLE','administrative'); INSERT INTO `ACL` VALUES (697,'Ticket','transferClient','WRITE','ALLOW','ROLE','administrative');

View File

@ -2687,13 +2687,20 @@ INSERT INTO `vn`.`zoneAgencyMode`(`id`, `agencyModeFk`, `zoneFk`)
(3, 6, 5), (3, 6, 5),
(4, 7, 1); (4, 7, 1);
INSERT INTO `vn`.`roadmapAddress` (`addressFk`)
VALUES
(1),
(2),
(3),
(4);
INSERT INTO `vn`.`roadmap` (`id`, `name`, `tractorPlate`, `trailerPlate`, `phone`, `supplierFk`, `etd`, `observations`, `userFk`, `price`, `driverName`) INSERT INTO `vn`.`roadmap` (`id`, `name`, `tractorPlate`, `trailerPlate`, `phone`, `supplierFk`, `etd`, `observations`, `userFk`, `price`, `driverName`)
VALUES VALUES
(1, 'val-algemesi', 'RE-001', 'PO-001', '111111111', 1, util.VN_NOW(), 'this is test observation', 1, 15, 'Batman'), (1, 'val-algemesi', '1234-BCD', '9876-BCD', '111111111', 1, util.VN_NOW(), 'this is test observation', 1, 15, 'Batman'),
(2, 'alg-valencia', 'RE-002', 'PO-002', '111111111', 1, util.VN_NOW(), 'test observation', 1, 20, 'Robin'), (2, 'alg-valencia', '2345-CDF', '8765-BCD', '111111111', 1, util.VN_NOW(), 'test observation', 1, 20, 'Robin'),
(3, 'alz-algemesi', 'RE-003', 'PO-003', '222222222', 2, DATE_ADD(util.VN_NOW(), INTERVAL 2 DAY), 'observations...', 2, 25, 'Driverman'); (3, 'alz-algemesi', '3456-DFG', '7654-BCD', '222222222', 2, DATE_ADD(util.VN_NOW(), INTERVAL 2 DAY), 'observations...', 2, 25, 'Driverman');
INSERT INTO `vn`.`expeditionTruck` (`id`, `roadmapFk`, `warehouseFk`, `eta`, `description`, `userFk`) INSERT INTO `vn`.`roadmapStop` (`id`, `roadmapFk`, `addressFk`, `eta`, `description`, `userFk`)
VALUES VALUES
(1, 1, 1, DATE_ADD(util.VN_NOW(), INTERVAL 1 DAY), 'Best truck in fleet', 1), (1, 1, 1, DATE_ADD(util.VN_NOW(), INTERVAL 1 DAY), 'Best truck in fleet', 1),
(2, 1, 2, DATE_ADD(util.VN_NOW(), INTERVAL '1 2' DAY_HOUR), 'Second truck in fleet', 1), (2, 1, 2, DATE_ADD(util.VN_NOW(), INTERVAL '1 2' DAY_HOUR), 'Second truck in fleet', 1),

View File

@ -1,7 +1,7 @@
DELIMITER $$ DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` FUNCTION `util`.`midnight`() CREATE OR REPLACE DEFINER=`root`@`localhost` FUNCTION `util`.`midnight`()
RETURNS datetime RETURNS datetime
NOT DETERMINISTIC DETERMINISTIC
READS SQL DATA READS SQL DATA
BEGIN BEGIN

View File

@ -14,7 +14,7 @@ BEGIN
DECLARE vIsTooLittle TINYINT(1); DECLARE vIsTooLittle TINYINT(1);
SELECT (SUM(IFNULL(sv.litros, 0)) < vc.minTicketVolume SELECT (SUM(IFNULL(sv.litros, 0)) < vc.minTicketVolume
OR IFNULL(t.totalWithoutVat, 0) < vc.minTicketValue) INTO vIsTooLittle AND IFNULL(t.totalWithoutVat, 0) < vc.minTicketValue) INTO vIsTooLittle
FROM ticket t FROM ticket t
LEFT JOIN saleVolume sv ON sv.ticketFk = t.id LEFT JOIN saleVolume sv ON sv.ticketFk = t.id
JOIN volumeConfig vc JOIN volumeConfig vc

View File

@ -1,5 +1,7 @@
DELIMITER $$ DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`buy_afterUpsert`(vSelf INT) CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`buy_afterUpsert`(
vSelf INT
)
BEGIN BEGIN
/** /**
* Triggered actions when a buy is updated or inserted. * Triggered actions when a buy is updated or inserted.
@ -47,6 +49,9 @@ BEGIN
WHERE e.id = vEntryFk; WHERE e.id = vEntryFk;
IF vIsMerchandise THEN IF vIsMerchandise THEN
IF vWarehouse IS NULL THEN
CALL util.throw('The entry does not have travel');
END IF;
REPLACE itemCost SET REPLACE itemCost SET
itemFk = vItemFk, itemFk = vItemFk,

View File

@ -49,7 +49,10 @@ BEGIN
BEGIN BEGIN
IF vLockName IS NOT NULL THEN IF vLockName IS NOT NULL THEN
DO RELEASE_LOCK(vLockName); DO RELEASE_LOCK(vLockName);
CALL util.debugAdd('releaseLock', vLockName); -- Tmp CALL util.debugAdd(JSON_OBJECT(
'type', 'releaseLock',
'userFk', vUserFk
), vLockName); -- Tmp
END IF; END IF;
RESIGNAL; RESIGNAL;

View File

@ -1,9 +0,0 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`expeditionTruck_Add`(vHour VARCHAR(5), vDescription VARCHAR(45))
BEGIN
INSERT INTO vn.roadmapStop(eta,description)
VALUES(CONCAT(util.VN_CURDATE(), ' ', vHour), vDescription);
END$$
DELIMITER ;

View File

@ -1,12 +0,0 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`expeditionTruck_List`()
BEGIN
SELECT id truckFk,
eta,
description Destino
FROM roadmapStop
WHERE eta BETWEEN util.VN_CURDATE() AND util.dayend(util.VN_CURDATE())
ORDER BY eta;
END$$
DELIMITER ;

View File

@ -15,7 +15,8 @@ BEGIN
t.addressFk, t.addressFk,
a.nickname, a.nickname,
sub2.itemPackingTypeConcat, sub2.itemPackingTypeConcat,
est.code est.code,
es.isScanned
FROM expedition e FROM expedition e
JOIN ticket t ON t.id = e.ticketFk JOIN ticket t ON t.id = e.ticketFk
JOIN ticketState ts ON ts.ticketFk = e.ticketFk JOIN ticketState ts ON ts.ticketFk = e.ticketFk
@ -33,6 +34,10 @@ BEGIN
GROUP BY sub.ticketFk GROUP BY sub.ticketFk
) sub2 ON sub2.ticketFk = t.id ) sub2 ON sub2.ticketFk = t.id
LEFT JOIN expeditionStateType est ON est.id = e.stateTypeFk LEFT JOIN expeditionStateType est ON est.id = e.stateTypeFk
LEFT JOIN expeditionState es ON es.id = (
SELECT MAX(id)
FROM expeditionState es
WHERE expeditionFk = e.id)
WHERE t.routeFk = vRouteFk AND e.freightItemFk <> FALSE WHERE t.routeFk = vRouteFk AND e.freightItemFk <> FALSE
ORDER BY r.created, t.priority DESC; ORDER BY r.created, t.priority DESC;
END$$ END$$

View File

@ -148,10 +148,16 @@ proc: BEGIN
JOIN ( JOIN (
SELECT tt.ticketFk, SELECT tt.ticketFk,
COUNT(*) `lines`, COUNT(*) `lines`,
SUM(sv.volume) m3, SUM(s.quantity * ic.cm3delivery / 1000000) m3,
IFNULL(SUM(IF(sv.isPicked, sv.volume, 0)) / SUM(sv.volume), 0) rate IFNULL(SUM(IF(s.isPicked,
(s.quantity * ic.cm3delivery / 1000000),
0)) / SUM(s.quantity * ic.cm3delivery / 1000000),
0) rate
FROM tmp.productionTicket tt FROM tmp.productionTicket tt
JOIN saleVolume sv ON sv.ticketFk = tt.ticketFk JOIN sale s ON s.ticketFk = tt.ticketFk
AND s.quantity > 0
JOIN itemCost ic ON ic.itemFk = s.itemFk
AND ic.warehouseFk = vWarehouseFk
GROUP BY tt.ticketFk GROUP BY tt.ticketFk
) m ON m.ticketFk = pb.ticketFk ) m ON m.ticketFk = pb.ticketFk
SET pb.`lines` = m.`lines`, SET pb.`lines` = m.`lines`,
@ -219,6 +225,8 @@ proc: BEGIN
AND ish.visible AND ish.visible
GROUP BY ish.itemFk, p.sectorFk; GROUP BY ish.itemFk, p.sectorFk;
CREATE INDEX idxItem ON tItemShelvingStock (itemFk);
INSERT INTO tmp.ticketWithPrevia(ticketFk, salesCount) INSERT INTO tmp.ticketWithPrevia(ticketFk, salesCount)
SELECT pb.ticketFk, COUNT(DISTINCT s.id) SELECT pb.ticketFk, COUNT(DISTINCT s.id)
FROM tmp.productionBuffer pb FROM tmp.productionBuffer pb

View File

@ -64,10 +64,15 @@ BEGIN
FROM tmp.sale_getProblems tp FROM tmp.sale_getProblems tp
JOIN ticket t ON t.id = tp.ticketFk JOIN ticket t ON t.id = tp.ticketFk
JOIN ( JOIN (
SELECT t.addressFk, SUM(sv.litros) litros, t.totalWithoutVat SELECT t.addressFk,
SUM(ROUND(`ic`.`cm3delivery` * `s`.`quantity` / 1000, 0)) litros,
t.totalWithoutVat
FROM tmp.ticket_list tl FROM tmp.ticket_list tl
JOIN saleVolume sv ON sv.ticketFk = tl.ticketFk
JOIN ticket t ON t.id = tl.ticketFk JOIN ticket t ON t.id = tl.ticketFk
JOIN sale s ON s.ticketFk = t.id
AND s.quantity > 0
JOIN itemCost ic ON ic.itemFk = s.itemFk
AND ic.warehouseFk = t.warehouseFk
JOIN zoneClosure zc ON zc.zoneFk = t.zoneFk JOIN zoneClosure zc ON zc.zoneFk = t.zoneFk
AND zc.dated = util.VN_CURDATE() AND zc.dated = util.VN_CURDATE()
JOIN agencyMode am ON am.id = t.agencyModeFk JOIN agencyMode am ON am.id = t.agencyModeFk
@ -95,12 +100,12 @@ BEGIN
FROM ( FROM (
SELECT COUNT(s.id) nComp, tl.ticketFk, s.id saleFk SELECT COUNT(s.id) nComp, tl.ticketFk, s.id saleFk
FROM tmp.ticket_list tl FROM tmp.ticket_list tl
JOIN vn.sale s ON s.ticketFk = tl.ticketFk JOIN sale s ON s.ticketFk = tl.ticketFk
LEFT JOIN vn.saleComponent sc ON sc.saleFk = s.id LEFT JOIN saleComponent sc ON sc.saleFk = s.id
LEFT JOIN vn.component c ON c.id = sc.componentFk AND c.isRequired LEFT JOIN component c ON c.id = sc.componentFk AND c.isRequired
JOIN vn.ticket t ON t.id = tl.ticketFk JOIN ticket t ON t.id = tl.ticketFk
JOIN vn.agencyMode am ON am.id = t.agencyModeFk JOIN agencyMode am ON am.id = t.agencyModeFk
JOIN vn.deliveryMethod dm ON dm.id = am.deliveryMethodFk JOIN deliveryMethod dm ON dm.id = am.deliveryMethodFk
WHERE dm.code IN ('AGENCY','DELIVERY','PICKUP') WHERE dm.code IN ('AGENCY','DELIVERY','PICKUP')
AND s.quantity > 0 AND s.quantity > 0
GROUP BY s.id GROUP BY s.id

View File

@ -18,7 +18,7 @@ BEGIN
FROM ticket t FROM ticket t
JOIN sale s ON s.ticketFk = t.id JOIN sale s ON s.ticketFk = t.id
LEFT JOIN saleComponent sc ON sc.saleFk = s.id LEFT JOIN saleComponent sc ON sc.saleFk = s.id
WHERE t.shipped >= util.midnight() WHERE t.shipped >= util.VN_CURDATE()
AND (vComponentFk IS NULL OR sc.componentFk = vComponentFk) AND (vComponentFk IS NULL OR sc.componentFk = vComponentFk)
GROUP BY s.id) sub; GROUP BY s.id) sub;

View File

@ -13,7 +13,7 @@ BEGIN
ENGINE = MEMORY ENGINE = MEMORY
SELECT t.id ticketFk, FALSE hasProblem SELECT t.id ticketFk, FALSE hasProblem
FROM ticket t FROM ticket t
WHERE t.shipped >= util.midnight() WHERE t.shipped >= util.VN_CURDATE()
AND (vClientFk IS NULL OR t.clientFk = vClientFk); AND (vClientFk IS NULL OR t.clientFk = vClientFk);
UPDATE tmp.ticket t UPDATE tmp.ticket t

View File

@ -13,7 +13,7 @@ BEGIN
ENGINE = MEMORY ENGINE = MEMORY
SELECT t.id ticketFk, FALSE hasProblem SELECT t.id ticketFk, FALSE hasProblem
FROM ticket t FROM ticket t
WHERE t.shipped >= util.midnight() WHERE t.shipped >= util.VN_CURDATE()
AND (vSelf IS NULL OR t.id = vSelf); AND (vSelf IS NULL OR t.id = vSelf);
UPDATE tmp.ticket t UPDATE tmp.ticket t

View File

@ -14,7 +14,7 @@ BEGIN
SELECT t.id ticketFk, IF(c.isTaxDataChecked, FALSE, TRUE) hasProblem SELECT t.id ticketFk, IF(c.isTaxDataChecked, FALSE, TRUE) hasProblem
FROM ticket t FROM ticket t
JOIN client c ON c.id = t.clientFk JOIN client c ON c.id = t.clientFk
WHERE t.shipped >= util.midnight() WHERE t.shipped >= util.VN_CURDATE()
AND (c.id = vClientFk OR vClientFk IS NULL); AND (c.id = vClientFk OR vClientFk IS NULL);
CALL ticket_setProblem('isTaxDataChecked'); CALL ticket_setProblem('isTaxDataChecked');

View File

@ -16,7 +16,7 @@ BEGIN
SELECT t.id ticketFk SELECT t.id ticketFk
FROM vn.ticket t FROM vn.ticket t
LEFT JOIN vn.sale s ON s.ticketFk = t.id LEFT JOIN vn.sale s ON s.ticketFk = t.id
WHERE t.shipped >= util.midnight() WHERE t.shipped >= util.VN_CURDATE()
AND (s.itemFk = vItemFk OR vItemFk IS NULL) AND (s.itemFk = vItemFk OR vItemFk IS NULL)
GROUP BY t.id GROUP BY t.id
)SELECT ticketFk, ticket_isTooLittle(ticketFk) hasProblem )SELECT ticketFk, ticket_isTooLittle(ticketFk) hasProblem

View File

@ -1,19 +0,0 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn`.`expeditionTruck_Control`
AS SELECT `e`.`truckFk` AS `id`,
`e`.`eta` AS `ETD`,
`e`.`description` AS `description`,
COUNT(
DISTINCT IF(`e`.`expeditionFk` IS NULL, `e`.`ticketFk`, NULL)
) AS `ticketsSinBultos`,
COUNT(DISTINCT `e`.`palletFk`) AS `pallets`,
COUNT(DISTINCT `e`.`routeFk`) AS `routes`,
COUNT(DISTINCT `e`.`scanFk`) AS `scans`,
COUNT(DISTINCT `e`.`expeditionFk`) AS `expeditions`,
sum(`e`.`truckFk` <> `e`.`roadmapStopFk`) AS `fallos`,
max(`e`.`lastPacked`) AS `lastPacked`
FROM `vn`.`expeditionCommon` `e`
GROUP BY `e`.`truckFk`
ORDER BY sum(`e`.`truckFk` <> `e`.`roadmapStopFk`) DESC,
`e`.`eta`

View File

@ -1,18 +0,0 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn`.`expeditionTruck_Control_Detail`
AS SELECT `e`.`truckFk` AS `id`,
`e`.`eta` AS `eta`,
`e`.`description` AS `destino`,
`e`.`palletFk` AS `pallet`,
COUNT(DISTINCT `e`.`routeFk`) AS `routes`,
COUNT(DISTINCT `e`.`scanFk`) AS `scans`,
COUNT(DISTINCT `e`.`roadmapStopFk`) AS `destinos`,
sum(`e`.`truckFk` <> `e`.`roadmapStopFk`) AS `fallos`,
max(`e`.`lastPacked`) AS `lastPacked`
FROM `vn`.`expeditionCommon` `e`
GROUP BY `e`.`truckFk`,
`e`.`palletFk`
ORDER BY sum(`e`.`truckFk` <> `e`.`roadmapStopFk`) DESC,
`e`.`eta`,
`e`.`truckFk`

View File

@ -1,22 +0,0 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn`.`expeditionTruck_Control_Detail_Pallet`
AS SELECT `e`.`truckFk` AS `id`,
`e`.`eta` AS `eta`,
`e`.`description` AS `destino`,
`e`.`palletFk` AS `pallet`,
`e`.`routeFk` AS `route`,
COUNT(DISTINCT `e`.`scanFk`) AS `scans`,
`rs`.`description` AS `destinos`,
SUM(`e`.`truckFk` <> `e`.`roadmapStopFk`) AS `fallos`,
`e`.`roadmapStopFk` AS `roadmapStopFk`,
MAX(`e`.`lastPacked`) AS `lastPacked`
FROM (
`vn`.`expeditionCommon` `e`
LEFT JOIN `vn`.`roadmapStop` `rs` ON(`rs`.`id` = `e`.`roadmapStopFk`)
)
GROUP BY `e`.`truckFk`,
`e`.`palletFk`,
`e`.`routeFk`
ORDER BY SUM(`e`.`truckFk` <> `e`.`roadmapStopFk`) DESC,
`e`.`palletFk`

View File

@ -20,7 +20,7 @@ FROM (
`vn`.`saleGroup` `sg` `vn`.`saleGroup` `sg`
JOIN `vn`.`saleGroupDetail` `sgd` ON(`sgd`.`saleGroupFk` = `sg`.`id`) JOIN `vn`.`saleGroupDetail` `sgd` ON(`sgd`.`saleGroupFk` = `sg`.`id`)
) )
JOIN `vn`.`sale` `s` ON(`s`.`id` = `sgd`.`saleFk`) JOIN `vn`.`sale` `s` FORCE INDEX (PRIMARY) ON(`s`.`id` = `sgd`.`saleFk`)
) )
JOIN `vn`.`ticketState` `tls` ON(`tls`.`ticketFk` = `s`.`ticketFk`) JOIN `vn`.`ticketState` `tls` ON(`tls`.`ticketFk` = `s`.`ticketFk`)
) )

View File

@ -0,0 +1,8 @@
CREATE TABLE `vn`.`roadmapAddress` (
addressFk int(11) NULL,
isActive TINYINT DEFAULT 1 NULL,
PRIMARY KEY (addressFk)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci COMMENT='Direcciones de los troncales';
ALTER TABLE vn.roadmapAddress
ADD CONSTRAINT roadmapAddress_address_FK FOREIGN KEY (addressFk) REFERENCES vn.address(id) ON DELETE RESTRICT ON UPDATE CASCADE;

View File

@ -0,0 +1,7 @@
ALTER TABLE vn.roadmapStop DROP FOREIGN KEY expeditionTruck_FK_1;
ALTER TABLE vn.roadmapStop DROP COLUMN warehouseFk;
ALTER TABLE vn.roadmapStop ADD addressFk int(11) NULL;
ALTER TABLE vn.roadmapStop CHANGE addressFk addressFk int(11) DEFAULT NULL NULL AFTER roadmapFk;
ALTER TABLE vn.roadmapStop
ADD CONSTRAINT roadmapStop_roadmapAddress_FK FOREIGN KEY (addressFk) REFERENCES vn.roadmapAddress(addressFk) ON DELETE RESTRICT ON UPDATE CASCADE;

View File

@ -0,0 +1,11 @@
DELETE FROM salix.ACL
WHERE model in ('expeditionTruck', 'Roadmap', 'roadmapStop', 'roadmapAddress');
INSERT INTO salix.ACL (model, property, accessType, permission, principalType, principalId)
VALUES
('RoadmapAddress', '*', 'WRITE', 'ALLOW', 'ROLE', 'palletizerBoss'),
('RoadmapAddress', '*', 'READ', 'ALLOW', 'ROLE', 'production'),
('Roadmap', '*', 'WRITE', 'ALLOW', 'ROLE', 'palletizerBoss'),
('Roadmap', '*', 'READ', 'ALLOW', 'ROLE', 'production'),
('RoadmapStop', '*', 'WRITE', 'ALLOW', 'ROLE', 'palletizerBoss'),
('RoadmapStop', '*', 'READ', 'ALLOW', 'ROLE', 'production');

View File

@ -0,0 +1,5 @@
-- Place your SQL code here
USE vn;
ALTER TABLE vn.expeditionState ADD isScanned tinyint(1) DEFAULT false NOT NULL;

View File

@ -0,0 +1,3 @@
INSERT INTO salix.ACL(model,property,accessType,permission,principalType,principalId)
VALUES('InvoiceIn', 'create', 'WRITE', 'ALLOW', 'ROLE', 'administrative'),
('InvoiceIn', 'create', 'WRITE', 'ALLOW', 'ROLE', 'buyer');

View File

@ -229,5 +229,8 @@
"InvoiceIn is already booked": "InvoiceIn is already booked", "InvoiceIn is already booked": "InvoiceIn is already booked",
"This workCenter is already assigned to this agency": "This workCenter is already assigned to this agency", "This workCenter is already assigned to this agency": "This workCenter is already assigned to this agency",
"You can only have one PDA": "You can only have one PDA", "You can only have one PDA": "You can only have one PDA",
"Incoterms and Customs agent are required for a non UEE member": "Incoterms and Customs agent are required for a non UEE member" "Incoterms and Customs agent are required for a non UEE member": "Incoterms and Customs agent are required for a non UEE member",
"It has been invoiced but the PDF could not be generated": "It has been invoiced but the PDF could not be generated",
"It has been invoiced but the PDF of refund not be generated": "It has been invoiced but the PDF of refund not be generated"
} }

View File

@ -359,8 +359,11 @@
"Select ticket or client": "Elija un ticket o un client", "Select ticket or client": "Elija un ticket o un client",
"It was not able to create the invoice": "No se pudo crear la factura", "It was not able to create the invoice": "No se pudo crear la factura",
"ticketCommercial": "El ticket {{ ticket }} para el vendedor {{ salesMan }} está en preparación. (mensaje generado automáticamente)", "ticketCommercial": "El ticket {{ ticket }} para el vendedor {{ salesMan }} está en preparación. (mensaje generado automáticamente)",
"This PDA is already assigned to another user": "Esta PDA ya está asignado a otro usuario",
"You can only have one PDA": "Solo puedes tener una PDA",
"Incoterms and Customs agent are required for a non UEE member": "Se requieren Incoterms y agente de aduanas para un no miembro de la UEE", "Incoterms and Customs agent are required for a non UEE member": "Se requieren Incoterms y agente de aduanas para un no miembro de la UEE",
"You can not use the same password": "No puedes usar la misma contraseña" "You can not use the same password": "No puedes usar la misma contraseña",
"This PDA is already assigned to another user": "Este PDA ya está asignado a otro usuario",
"You can only have one PDA": "Solo puedes tener un PDA",
"It has been invoiced but the PDF could not be generated": "Se ha facturado pero no se ha podido generar el PDF",
"It has been invoiced but the PDF of refund not be generated": "Se ha facturado pero no se ha podido generar el PDF del abono",
"Payment method is required": "El método de pago es obligatorio"
} }

View File

@ -357,5 +357,7 @@
"InvoiceIn is already booked": "La facture reçue est déjà comptabilisée", "InvoiceIn is already booked": "La facture reçue est déjà comptabilisée",
"This workCenter is already assigned to this agency": "Ce centre de travail est déjà assigné à cette agence", "This workCenter is already assigned to this agency": "Ce centre de travail est déjà assigné à cette agence",
"Select ticket or client": "Choisissez un ticket ou un client", "Select ticket or client": "Choisissez un ticket ou un client",
"It was not able to create the invoice": "Il n'a pas été possible de créer la facture" "It was not able to create the invoice": "Il n'a pas été possible de créer la facture",
"It has been invoiced but the PDF could not be generated": "La facture a été émise mais le PDF n'a pas pu être généré",
"It has been invoiced but the PDF of refund not be generated": "Il a été facturé mais le PDF de remboursement n'a pas été généré"
} }

View File

@ -357,5 +357,7 @@
"InvoiceIn is already booked": "InvoiceIn já está reservado", "InvoiceIn is already booked": "InvoiceIn já está reservado",
"This workCenter is already assigned to this agency": "Este centro de trabalho já está atribuído a esta agência", "This workCenter is already assigned to this agency": "Este centro de trabalho já está atribuído a esta agência",
"Select ticket or client": "Selecione um ticket ou cliente", "Select ticket or client": "Selecione um ticket ou cliente",
"It was not able to create the invoice": "Não foi possível criar a fatura" "It was not able to create the invoice": "Não foi possível criar a fatura",
"It has been invoiced but the PDF could not be generated": "Foi faturado, mas o PDF não pôde ser gerado",
"It has been invoiced but the PDF of refund not be generated": "Foi faturado mas não foi gerado o PDF do reembolso"
} }

View File

@ -1,4 +1,3 @@
const models = require('vn-loopback/server/server').models; const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context'); const LoopBackContext = require('loopback-context');
@ -17,26 +16,27 @@ describe('InvoiceOut transferInvoice()', () => {
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx active: activeCtx
}); });
spyOn(models.InvoiceOut, 'makePdfAndNotify');
}); });
it('should return the id of the created issued invoice', async() => { it('should return the id of the created issued invoice', async() => {
const tx = await models.InvoiceOut.beginTransaction({}); const tx = await models.InvoiceOut.beginTransaction({});
const options = {transaction: tx}; const options = {transaction: tx};
const args = { const id = 4;
id: '4', const newClient = 1;
refFk: 'T4444444', spyOn(models.InvoiceOut, 'makePdfList');
newClientFk: 1,
cplusRectificationTypeFk: 1,
siiTypeInvoiceOutFk: 1,
invoiceCorrectionTypeFk: 1
};
ctx.args = args;
try { try {
const {clientFk: oldClient} = await models.InvoiceOut.findById(args.id, {fields: ['clientFk']}); const {clientFk: oldClient} = await models.InvoiceOut.findById(id, {fields: ['clientFk']});
const invoicesBefore = await models.InvoiceOut.find({}, options); const invoicesBefore = await models.InvoiceOut.find({}, options);
const result = await models.InvoiceOut.transferInvoice( const result = await models.InvoiceOut.transferInvoice(
ctx, ctx,
id,
'T4444444',
newClient,
1,
1,
1,
true,
options); options);
const invoicesAfter = await models.InvoiceOut.find({}, options); const invoicesAfter = await models.InvoiceOut.find({}, options);
const rectificativeInvoice = invoicesAfter[invoicesAfter.length - 2]; const rectificativeInvoice = invoicesAfter[invoicesAfter.length - 2];
@ -45,7 +45,7 @@ describe('InvoiceOut transferInvoice()', () => {
expect(result).toBeDefined(); expect(result).toBeDefined();
expect(invoicesAfter.length - invoicesBefore.length).toEqual(2); expect(invoicesAfter.length - invoicesBefore.length).toEqual(2);
expect(rectificativeInvoice.clientFk).toEqual(oldClient); expect(rectificativeInvoice.clientFk).toEqual(oldClient);
expect(newInvoice.clientFk).toEqual(args.newClientFk); expect(newInvoice.clientFk).toEqual(newClient);
await tx.rollback(); await tx.rollback();
} catch (e) { } catch (e) {
@ -54,22 +54,13 @@ describe('InvoiceOut transferInvoice()', () => {
} }
}); });
it('should throw an UserError when it is the same client', async() => { it('should throw an error when it is the same client', async() => {
const tx = await models.InvoiceOut.beginTransaction({}); const tx = await models.InvoiceOut.beginTransaction({});
const options = {transaction: tx}; const options = {transaction: tx};
const args = { spyOn(models.InvoiceOut, 'makePdfList');
id: '1',
refFk: 'T1111111',
newClientFk: 1101,
cplusRectificationTypeFk: 1,
siiTypeInvoiceOutFk: 1,
invoiceCorrectionTypeFk: 1
};
ctx.args = args;
try { try {
await models.InvoiceOut.transferInvoice( await models.InvoiceOut.transferInvoice(ctx, '1', 'T1111111', 1101, 1, 1, 1, true, options);
ctx,
options);
await tx.rollback(); await tx.rollback();
} catch (e) { } catch (e) {
expect(e.message).toBe(`Select a different client`); expect(e.message).toBe(`Select a different client`);
@ -77,26 +68,49 @@ describe('InvoiceOut transferInvoice()', () => {
} }
}); });
it('should throw an UserError when it is refund', async() => { it('should throw an error when it is refund', async() => {
const tx = await models.InvoiceOut.beginTransaction({}); const tx = await models.InvoiceOut.beginTransaction({});
const options = {transaction: tx}; const options = {transaction: tx};
const args = { spyOn(models.InvoiceOut, 'makePdfList');
id: '1',
refFk: 'T1111111',
newClientFk: 1102,
cplusRectificationTypeFk: 1,
siiTypeInvoiceOutFk: 1,
invoiceCorrectionTypeFk: 1
};
ctx.args = args;
try { try {
await models.InvoiceOut.transferInvoice( await models.InvoiceOut.transferInvoice(ctx, '1', 'T1111111', 1102, 1, 1, 1, true, options);
ctx,
options);
await tx.rollback(); await tx.rollback();
} catch (e) { } catch (e) {
expect(e.message).toContain(`This ticket is already a refund`); expect(e.message).toContain(`This ticket is already a refund`);
await tx.rollback(); await tx.rollback();
} }
}); });
it('should throw an error when pdf failed', async() => {
const tx = await models.InvoiceOut.beginTransaction({});
const options = {transaction: tx};
spyOn(models.InvoiceOut, 'makePdfList').and.returnValue(() => {
throw new Error('test');
});
try {
await models.InvoiceOut.transferInvoice(ctx, '1', 'T1111111', 1102, 1, 1, 1, true, options);
await tx.rollback();
} catch (e) {
expect(e.message).toContain(`It has been invoiced but the PDF could not be generated`);
await tx.rollback();
}
});
it('should not generate an invoice', async() => {
const tx = await models.InvoiceOut.beginTransaction({});
const options = {transaction: tx};
spyOn(models.InvoiceOut, 'makePdfList');
let response;
try {
response = await models.InvoiceOut.transferInvoice(ctx, '1', 'T1111111', 1102, 1, 1, 1, false, options);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
expect(response).not.toBeDefined();
});
}); });

View File

@ -37,13 +37,13 @@ module.exports = Self => {
required: true required: true
}, },
{ {
arg: 'checked', arg: 'makeInvoice',
type: 'boolean', type: 'boolean',
required: true required: true
}, },
], ],
returns: { returns: {
type: 'boolean', type: 'object',
root: true root: true
}, },
http: { http: {
@ -52,11 +52,22 @@ module.exports = Self => {
} }
}); });
Self.transferInvoice = async(ctx, options) => { Self.transferInvoice = async(
ctx,
id,
refFk,
newClientFk,
cplusRectificationTypeFk,
siiTypeInvoiceOutFk,
invoiceCorrectionTypeFk,
makeInvoice,
options
) => {
const models = Self.app.models; const models = Self.app.models;
const myOptions = {userId: ctx.req.accessToken.userId}; const myOptions = {userId: ctx.req.accessToken.userId};
const {id, refFk, newClientFk, cplusRectificationTypeFk, siiTypeInvoiceOutFk, invoiceCorrectionTypeFk} = ctx.args; let invoiceId;
const checked = ctx.args.checked; let refundId;
let tx; let tx;
if (typeof options == 'object') if (typeof options == 'object')
Object.assign(myOptions, options); Object.assign(myOptions, options);
@ -100,15 +111,29 @@ module.exports = Self => {
}; };
const refundTicketIds = refundTickets.map(ticket => ticket.id); const refundTicketIds = refundTickets.map(ticket => ticket.id);
await models.Ticket.invoiceTickets(ctx, refundTicketIds, invoiceCorrection, myOptions); refundId = await models.Ticket.invoiceTickets(ctx, refundTicketIds, invoiceCorrection, myOptions);
if (!checked) { if (makeInvoice)
const [invoiceId] = await models.Ticket.invoiceTicketsAndPdf(ctx, clonedTicketIds, null, myOptions); invoiceId = await models.Ticket.invoiceTickets(ctx, clonedTicketIds, null, myOptions);
return invoiceId;
} tx && await tx.commit();
} catch (e) { } catch (e) {
if (tx) await tx.rollback(); if (tx) await tx.rollback();
throw e; throw e;
} }
if (tx && makeInvoice) {
try {
await models.InvoiceOut.makePdfList(ctx, invoiceId);
} catch (e) {
throw new UserError('It has been invoiced but the PDF could not be generated');
}
try {
await models.InvoiceOut.makePdfList(ctx, refundId);
} catch (e) {
throw new UserError('It has been invoiced but the PDF of refund not be generated');
}
}
return invoiceId;
}; };
}; };

View File

@ -158,7 +158,7 @@ class Controller extends Section {
cplusRectificationTypeFk: this.cplusRectificationType, cplusRectificationTypeFk: this.cplusRectificationType,
siiTypeInvoiceOutFk: this.siiTypeInvoiceOut, siiTypeInvoiceOutFk: this.siiTypeInvoiceOut,
invoiceCorrectionTypeFk: this.invoiceCorrectionType, invoiceCorrectionTypeFk: this.invoiceCorrectionType,
checked: this.checked makeInvoice: this.checked
}; };
this.$http.get(`Clients/${this.clientId}`).then(response => { this.$http.get(`Clients/${this.clientId}`).then(response => {

View File

@ -13,7 +13,6 @@ columns:
m3: m3 m3: m3
priority: priority priority: priority
etd: etd etd: etd
expeditionTruckFk: truck
m3boxes: m3 boxes m3boxes: m3 boxes
bufferFk: buffer bufferFk: buffer
isPickingAllowed: is picking allowed isPickingAllowed: is picking allowed

View File

@ -13,7 +13,6 @@ columns:
m3: m3 m3: m3
priority: prioridad priority: prioridad
etd: etd etd: etd
expeditionTruckFk: camión
m3boxes: m3 cajas m3boxes: m3 cajas
bufferFk: buffer bufferFk: buffer
isPickingAllowed: está permitido recoger isPickingAllowed: está permitido recoger

View File

@ -37,17 +37,12 @@ module.exports = Self => {
fields: [ fields: [
'id', 'id',
'name', 'name',
'tractorPlate',
'trailerPlate',
'phone',
'supplierFk', 'supplierFk',
'etd', 'etd'],
'observations',
'price'],
include: [{ include: [{
relation: 'expeditionTruck', relation: 'roadmapStop',
scope: { scope: {
fields: ['roadmapFk', 'warehouseFk', 'eta', 'description'] fields: ['roadmapFk', 'addressFk', 'eta', 'description']
} }
}] }]

View File

@ -8,6 +8,9 @@
"DeliveryPoint": { "DeliveryPoint": {
"dataSource": "vn" "dataSource": "vn"
}, },
"RoadmapAddress": {
"dataSource": "vn"
},
"RoadmapStop": { "RoadmapStop": {
"dataSource": "vn" "dataSource": "vn"
}, },
@ -25,8 +28,5 @@
}, },
"RoutesMonitor": { "RoutesMonitor": {
"dataSource": "vn" "dataSource": "vn"
},
"ExpeditionTruck": {
"dataSource": "vn"
} }
} }

View File

@ -1,9 +0,0 @@
{
"name": "ExpeditionTruck",
"base": "RoadmapStop",
"options": {
"mysql": {
"table": "expeditionTruck"
}
}
}

View File

@ -0,0 +1,26 @@
{
"name": "RoadmapAddress",
"base": "VnModel",
"options": {
"mysql": {
"table": "roadmapAddress"
}
},
"properties": {
"addressFk": {
"type": "number",
"id": true,
"description": "Identifier"
},
"isActive": {
"type": "number"
}
},
"relations": {
"address": {
"type": "belongsTo",
"model": "Address",
"foreignKey": "addressFk"
}
}
}

View File

@ -15,7 +15,7 @@
"roadmapFk": { "roadmapFk": {
"type": "number" "type": "number"
}, },
"warehouseFk": { "addressFk": {
"type": "number" "type": "number"
}, },
"eta": { "eta": {
@ -34,10 +34,10 @@
"model": "Roadmap", "model": "Roadmap",
"foreignKey": "roadmapFk" "foreignKey": "roadmapFk"
}, },
"warehouse": { "address": {
"type": "belongsTo", "type": "belongsTo",
"model": "Warehouse", "model": "Address",
"foreignKey": "warehouseFk" "foreignKey": "addressFk"
} }
} }
} }

View File

@ -48,9 +48,6 @@
"priority": { "priority": {
"type": "number" "type": "number"
}, },
"expeditionTruckFk": {
"type": "number"
},
"m3boxes": { "m3boxes": {
"type": "number" "type": "number"
}, },

View File

@ -44,11 +44,13 @@ module.exports = Self => {
const typeFk = expeditionStateType.id; const typeFk = expeditionStateType.id;
expeditionId = expedition.expeditionFk; expeditionId = expedition.expeditionFk;
const isScannedExpedition = expedition.isScanned ?? false;
await models.ExpeditionState.create({ await models.ExpeditionState.create({
expeditionFk: expedition.expeditionFk, expeditionFk: expedition.expeditionFk,
typeFk, typeFk,
userFk: userId, userFk: userId,
isScanned: isScannedExpedition,
}, myOptions); }, myOptions);
} }

View File

@ -135,6 +135,7 @@ module.exports = Self => {
const now = Date.vnNew(); const now = Date.vnNew();
const ticket = await models.Ticket.findById(ticketId, null, myOptions); const ticket = await models.Ticket.findById(ticketId, null, myOptions);
if (!ctx.args) ctx.args = {};
ctx.args.clientId = ticket.clientFk; ctx.args.clientId = ticket.clientFk;
ctx.args.shipped = now; ctx.args.shipped = now;
ctx.args.landed = now; ctx.args.landed = now;

View File

@ -23,6 +23,9 @@
}, },
"userFk": { "userFk": {
"type": "number" "type": "number"
},
"isScanned": {
"type": "boolean"
} }
}, },
"relations": { "relations": {

View File

@ -5,108 +5,80 @@ module.exports = Self => {
Self.remoteMethodCtx('new', { Self.remoteMethodCtx('new', {
description: 'Creates a new worker and returns the id', description: 'Creates a new worker and returns the id',
accessType: 'WRITE', accessType: 'WRITE',
accepts: [ accepts: [{
{
arg: 'fi', arg: 'fi',
type: 'string', type: 'string',
description: `The worker fi`, description: `The worker fi`,
required: true, }, {
},
{
arg: 'name', arg: 'name',
type: 'string', type: 'string',
description: `The user name`, description: `The user name`,
required: true, }, {
},
{
arg: 'firstName', arg: 'firstName',
type: 'string', type: 'string',
description: `The worker firstname`, description: `The worker firstname`,
required: true, }, {
},
{
arg: 'lastNames', arg: 'lastNames',
type: 'string', type: 'string',
description: `The worker lastnames`, description: `The worker lastnames`,
required: true, }, {
},
{
arg: 'email', arg: 'email',
type: 'string', type: 'string',
description: `The worker email`, description: `The worker email`,
required: true, required: true,
}, }, {
{
arg: 'street', arg: 'street',
type: 'string', type: 'string',
description: `The worker address`, description: `The worker address`,
required: true, }, {
},
{
arg: 'city', arg: 'city',
type: 'string', type: 'string',
description: `The worker city`, description: `The worker city`,
required: true, }, {
},
{
arg: 'provinceFk', arg: 'provinceFk',
type: 'number', type: 'number',
description: `The worker province`, description: `The worker province`,
required: true, }, {
},
{
arg: 'companyFk', arg: 'companyFk',
type: 'number', type: 'number',
description: `The worker company`, description: `The worker company`,
required: true, }, {
},
{
arg: 'postcode', arg: 'postcode',
type: 'string', type: 'string',
description: `The worker postcode`, description: `The worker postcode`,
required: true, }, {
},
{
arg: 'phone', arg: 'phone',
type: 'string', type: 'string',
description: `The worker phone`, description: `The worker phone`,
required: true, }, {
},
{
arg: 'code', arg: 'code',
type: 'string', type: 'string',
description: `The worker code`, description: `The worker code`,
required: true, }, {
},
{
arg: 'bossFk', arg: 'bossFk',
type: 'number', type: 'number',
description: `The worker boss`, description: `The worker boss`,
required: true, required: true,
}, }, {
{
arg: 'birth', arg: 'birth',
type: 'date', type: 'date',
description: `The worker birth`, description: `The worker birth`,
required: true, }, {
},
{
arg: 'payMethodFk', arg: 'payMethodFk',
type: 'number', type: 'number',
description: `The client payMethod`, description: `The client payMethod`,
required: true, }, {
},
{
arg: 'iban', arg: 'iban',
type: 'string', type: 'string',
description: `The client iban`, description: `The client iban`,
}, }, {
{
arg: 'bankEntityFk', arg: 'bankEntityFk',
type: 'number', type: 'number',
description: `The client bank entity`, description: `The client bank entity`,
} }, {
], arg: 'isFreelance',
type: 'boolean',
}],
returns: { returns: {
type: 'number', type: 'number',
root: true, root: true,
@ -117,11 +89,30 @@ module.exports = Self => {
}, },
}); });
Self.new = async(ctx, options) => { Self.new = async(
ctx,
fi,
name,
firstName,
lastNames,
email,
street,
city,
provinceFk,
companyFk,
postcode,
phone,
code,
bossFk,
birth,
payMethodFk,
iban,
bankEntityFk,
isFreelance,
options
) => {
const models = Self.app.models; const models = Self.app.models;
const myOptions = {userId: ctx.req.accessToken.userId}; const myOptions = {userId: ctx.req.accessToken.userId};
const args = ctx.args;
let tx; let tx;
if (typeof options == 'object') Object.assign(myOptions, options); if (typeof options == 'object') Object.assign(myOptions, options);
@ -132,132 +123,105 @@ module.exports = Self => {
} }
let client; let client;
let user;
try { try {
client = await models.Client.findOne( client = await models.Client.findOne({where: {fi}}, myOptions);
{ const nickname = firstName.concat(' ', lastNames);
where: {fi: args.fi}, const {roleFk, businessTypeFk} = await models.WorkerConfig.findOne({fields: ['roleFk', 'businessTypeFk']});
},
myOptions
);
if (!client) { if (!isFreelance && !payMethodFk) throw new UserError('Payment method is required');
const nickname = args.firstName.concat(' ', args.lastNames);
const workerConfig = await models.WorkerConfig.findOne({fields: ['roleFk', 'businessTypeFk']});
const [randomPassword] = await models.Worker.rawSql(
'SELECT account.passwordGenerate() as password;'
);
const user = await models.VnUser.create( if (isFreelance || !client) {
{ const [{password}] = await models.Worker.rawSql('SELECT account.passwordGenerate() as password;');
name: args.name, const freelancer = isFreelance && await models.VnRole.findOne({fields: ['id'], where: {name: 'freelancer'}});
user = await models.VnUser.create({
name,
nickname, nickname,
password: randomPassword.password, password,
email: args.email, email,
roleFk: workerConfig.roleFk, roleFk: freelancer ? freelancer.id : roleFk,
}, }, myOptions);
myOptions
);
await models.Account.create( await models.Account.create({
{ id: user.id
id: user.id, }, myOptions);
}, } else if (client) user = await models.VnUser.findById(client.id, null, myOptions);
myOptions
);
const payMethod = await models.PayMethod.findById(args.payMethodFk, {fields: ['isIbanRequiredForClients']}); if (!client && !isFreelance) {
if (payMethod.isIbanRequiredForClients && !args.iban) const payMethod = await models.PayMethod.findById(payMethodFk, {fields: ['isIbanRequiredForClients']});
throw new UserError(`That payment method requires an IBAN`); if (payMethod.isIbanRequiredForClients && !iban) throw new UserError('That payment method requires an IBAN');
await models.Worker.rawSql( await models.Worker.rawSql('CALL vn.client_create(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
'CALL vn.client_create(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
[ [
args.firstName, firstName,
args.lastNames, lastNames,
args.fi, fi,
args.street, street,
args.postcode, postcode,
args.city, city,
args.provinceFk, provinceFk,
args.companyFk, companyFk,
args.phone, phone,
args.email, email,
user.id, user.id,
], ],
myOptions myOptions);
);
const address = await models.Address.create( const address = await models.Address.create({
{
clientFk: user.id, clientFk: user.id,
street: args.street, street: street,
city: args.city, city: city,
provinceFk: args.provinceFk, provinceFk: provinceFk,
postalCode: args.postcode, postalCode: postcode,
mobile: args.phone, mobile: phone,
nickname: nickname, nickname: nickname,
isDefaultAddress: true, isDefaultAddress: true,
}, }, myOptions);
myOptions
);
client = await models.Client.findById( client = await models.Client.findById(user.id, {
user.id, fields: ['id', 'name', 'socialName', 'street', 'city', 'iban', 'bankEntityFk', 'defaultAddressFk', 'businessTypeFk', 'fi']
{fields: ['id', 'name', 'socialName', 'street', 'city', 'iban', 'bankEntityFk', 'defaultAddressFk', 'businessTypeFk', 'fi']}, }, myOptions);
myOptions
);
await client.updateAttributes( await client.updateAttributes({
{ payMethod: payMethodFk,
payMethod: args.payMethod, iban,
iban: args.iban, bankEntityFk,
bankEntityFk: args.bankEntityFk,
defaultAddressFk: address.id, defaultAddressFk: address.id,
businessTypeFk: workerConfig.businessTypeFk, businessTypeFk,
}, }, myOptions);
myOptions
);
} }
const user = await models.VnUser.findById(client.id, null, myOptions); await user.updateAttribute('email', email, myOptions);
await user.updateAttribute('email', args.email, myOptions);
await models.Worker.create({ await models.Worker.create({
id: client.id, id: user.id,
code: args.code, firstName,
firstName: args.firstName, lastName: lastNames,
lastName: args.lastNames, code,
bossFk: args.bossFk, bossFk,
fi: args.fi, fi,
birth: args.birth, birth,
}, myOptions); }, myOptions);
if (tx) await tx.commit(); if (tx) await tx.commit();
} catch (error) { } catch (e) {
if (tx) await tx.rollback(); if (tx) await tx.rollback();
const code = error.code; const code = e.code;
const message = error.sqlMessage; const message = e.sqlMessage;
if (error.message && error.message.includes(`Email already exists`)) if (e.message && e.message.includes(`Email already exists`)) throw new UserError(`This personal mail already exists`);
throw new UserError(`This personal mail already exists`);
if (code === 'ER_DUP_ENTRY' && message.includes(`CodigoTrabajador_UNIQUE`)) if (code === 'ER_DUP_ENTRY' && message.includes(`CodigoTrabajador_UNIQUE`)) throw new UserError(`This worker code already exists`);
throw new UserError(`This worker code already exists`);
if (code === 'ER_DUP_ENTRY' && message.includes(`PRIMARY`)) if (code === 'ER_DUP_ENTRY' && message.includes(`PRIMARY`)) throw new UserError(`This worker already exists`);
throw new UserError(`This worker already exists`);
throw error; throw e;
} }
await models.VnUser.resetPassword({ await models.VnUser.resetPassword({email, emailTemplate: 'worker-welcome', id: user.id});
email: args.email,
emailTemplate: 'worker-welcome',
id: client.id
});
return {id: client.id}; return {id: user.id};
}; };
}; };

View File

@ -1,189 +1,114 @@
const models = require('vn-loopback/server/server').models; const {models} = require('vn-loopback/server/server');
const LoopBackContext = require('loopback-context'); const LoopBackContext = require('loopback-context');
describe('Worker new', () => { describe('Worker new', () => {
beforeAll(async() => { const developerId = 9;
const activeCtx = {
accessToken: {userId: 9},
http: {
req: {
headers: {origin: 'http://localhost'}
}
}
};
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
});
const employeeId = 1; const employeeId = 1;
const defaultWorker = { const bruceWayneId = 1101;
fi: '78457139E', const accessToken = {accessToken: {userId: developerId}};
name: 'defaulterworker', const ctx = {req: accessToken};
firstName: 'DEFAULT', let tx;
lastNames: 'WORKER', let opts;
email: 'defaultWorker@mydomain.com',
street: 'S/ DEFAULTWORKERSTREET',
city: 'defaultWorkerCity',
provinceFk: 1,
companyFk: 442,
postcode: '46680',
phone: '123456789',
code: 'DWW',
bossFk: 9,
birth: '2022-12-11T23:00:00.000Z',
payMethodFk: 1,
roleFk: 1
};
const req = {accessToken: {userId: 9}}; beforeAll(async() => {
const activeCtx = {accessToken, http: {req: {headers: {origin: 'http://localhost'}}}};
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({active: activeCtx});
});
it('should return error if personal mail already exists', async() => { describe('should return error', () => {
beforeEach(async() => {
tx = await models.Worker.beginTransaction({});
opts = {transaction: tx};
});
afterEach(async() => await tx.rollback());
it('if personal mail already exists', async() => {
const user = await models.VnUser.findById(employeeId, {fields: ['email']}); const user = await models.VnUser.findById(employeeId, {fields: ['email']});
const tx = await models.Worker.beginTransaction({});
let error;
try { try {
const options = {transaction: tx}; await createWorker(ctx, opts, {email: user.email});
const ctx = {
args: Object.assign({}, defaultWorker, {email: user.email}),
req
};
await models.Worker.new(ctx, options);
await tx.rollback();
} catch (e) { } catch (e) {
error = e; expect(e.message).toEqual('This personal mail already exists');
await tx.rollback();
} }
expect(error.message).toEqual('This personal mail already exists');
}); });
it('should return error if worker code already exists', async() => { it('if worker code already exists', async() => {
const worker = await models.Worker.findById(employeeId, {fields: ['code']}); const worker = await models.Worker.findById(employeeId, {fields: ['code']});
const tx = await models.Worker.beginTransaction({});
let error;
try { try {
const options = {transaction: tx}; await createWorker(ctx, opts, {code: worker.code});
const ctx = {
args: Object.assign({}, defaultWorker, {code: worker.code}),
req
};
await models.Worker.new(ctx, options);
await tx.rollback();
} catch (e) { } catch (e) {
error = e; expect(e.message).toEqual('This worker code already exists');
await tx.rollback();
} }
expect(error.message).toEqual('This worker code already exists');
}); });
it('should return error if worker already exists', async() => { it('if worker already exists', async() => {
const worker = await models.Client.findById(employeeId, {fields: ['fi']}); const worker = await models.Client.findById(employeeId, {fields: ['fi']});
const tx = await models.Worker.beginTransaction({});
let error;
try { try {
const options = {transaction: tx}; await createWorker(ctx, opts, {fi: worker.fi});
const ctx = {
args: Object.assign({}, defaultWorker, {fi: worker.fi}),
req
};
await models.Worker.new(ctx, options);
await tx.rollback();
} catch (e) { } catch (e) {
error = e; expect(e.message).toEqual('This worker already exists');
await tx.rollback();
} }
expect(error.message).toEqual('This worker already exists');
}); });
it('should return error if payMethod require iban', async() => { it('if payMethod require iban', async() => {
const payMethodIbanRequired = await models.PayMethod.findOne({ const payMethodIbanRequired = await models.PayMethod.findOne({
where: { fields: ['id'], where: {isIbanRequiredForClients: true}
isIbanRequiredForClients: true
},
fields: ['id']
}); });
const tx = await models.Worker.beginTransaction({});
let error;
try { try {
const options = {transaction: tx}; await createWorker(ctx, opts, {payMethodFk: payMethodIbanRequired.id});
const ctx = {
args: Object.assign({}, defaultWorker, {payMethodFk: payMethodIbanRequired.id}),
req
};
await models.Worker.new(ctx, options);
await tx.rollback();
} catch (e) { } catch (e) {
error = e; expect(e.message).toEqual('That payment method requires an IBAN');
await tx.rollback();
} }
});
expect(error.message).toEqual('That payment method requires an IBAN');
}); });
it('should create a new worker', async() => { it('should create a new worker', async() => {
let newWorker; let newWorker;
try { try {
newWorker = await models.Worker.new({args: defaultWorker, req}); newWorker = await createWorker(ctx);
expect(newWorker.id).toBeDefined();
} finally { } finally {
await removeWorker(newWorker.id); await removeWorker(newWorker.id);
} }
expect(newWorker.id).toBeDefined();
}); });
it('should create a new client', async() => { it('should create a new client', async() => {
let newWorker; let newWorker;
let client;
try { try {
newWorker = await models.Worker.new({args: defaultWorker, req}); newWorker = await createWorker(ctx);
client = await models.Client.findById(newWorker.id); let client = await models.Client.findById(newWorker.id);
expect(client).toBeDefined();
} finally { } finally {
await removeWorker(newWorker.id); await removeWorker(newWorker.id);
} }
expect(client).toBeDefined();
}); });
it('should create a new worker in client', async() => { it('should create a new worker in client', async() => {
const bruceWayneId = 1101;
const client = await models.Client.findById(bruceWayneId, {fields: ['fi', 'email']}); const client = await models.Client.findById(bruceWayneId, {fields: ['fi', 'email']});
const newWorkerData = {
args: Object.assign(
{},
defaultWorker,
{
fi: client.fi,
email: client.email
}),
req
};
let newWorker; let newWorker;
try { try {
newWorker = await models.Worker.new(newWorkerData); newWorker = await createWorker(ctx, undefined, {fi: client.fi, email: client.email});
expect(newWorker.id).toEqual(bruceWayneId);
} finally { } finally {
await models.Worker.destroyById(newWorker.id); await models.Worker.destroyById(newWorker.id);
} }
});
expect(newWorker.id).toEqual(bruceWayneId); it('should create a new external worker', async() => {
let newWorker;
try {
newWorker = await createWorker(ctx, undefined, {isFreelance: true});
const client = await models.Client.findById(newWorker.id);
expect(newWorker.id).toBeDefined();
expect(client).toBeNull();
} finally {
await removeWorker(newWorker.id);
}
}); });
}); });
@ -194,3 +119,28 @@ async function removeWorker(id) {
await models.Client.destroyById(id); await models.Client.destroyById(id);
await models.VnUser.destroyById(id); await models.VnUser.destroyById(id);
} }
async function createWorker(ctx, opts = undefined, params = {}) {
return models.Worker.new(
ctx,
params.fi ?? '78457139E',
params.name ?? 'defaulterworker',
params.firstName ?? 'DEFAULT',
params.lastNames ?? 'WORKER',
params.email ?? 'defaultWorker@mydomain.com',
params.street ?? 'S/ DEFAULTWORKERSTREET',
params.city ?? 'defaultWorkerCity',
params.provinceFk ?? 1,
params.companyFk ?? 442,
params.postcode ?? '46680',
params.phone ?? '123456789',
params.code ?? 'DWW',
params.bossFk ?? 9,
params.birth ?? '2022-12-11T23:00:00.000Z',
params.payMethodFk ?? 1,
undefined,
undefined,
params.isFreelance ?? false,
opts
);
}

View File

@ -46,7 +46,8 @@
"type": "number" "type": "number"
}, },
"code": { "code": {
"type" : "string" "type": "string",
"required": true
}, },
"fi": { "fi": {
"type": "string" "type": "string"
@ -78,7 +79,6 @@
"isSsDiscounted": { "isSsDiscounted": {
"type": "boolean" "type": "boolean"
} }
}, },
"relations": { "relations": {
"user": { "user": {