Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into test
gitea/salix/pipeline/head This commit looks good Details

This commit is contained in:
Joan Sanchez 2022-08-05 11:19:39 +02:00
commit e08619d126
102 changed files with 1994 additions and 193 deletions

View File

@ -18,6 +18,7 @@
"modules/supplier/front/**/*", "modules/supplier/front/**/*",
"modules/ticket/front/**/*", "modules/ticket/front/**/*",
"modules/travel/front/**/*", "modules/travel/front/**/*",
"modules/shelving/front/**/*",
"modules/worker/front/**/*", "modules/worker/front/**/*",
"modules/zone/front/**/*" "modules/zone/front/**/*"
] ]

View File

@ -0,0 +1,3 @@
INSERT INTO `salix`.`ACL` (model,property,accessType,permission,principalType,principalId)
VALUES
('ShelvingLog','*','READ','ALLOW','ROLE','employee');

View File

@ -0,0 +1,4 @@
INSERT INTO `salix`.`ACL`(`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('ZoneExclusionGeo', '*', 'READ', 'ALLOW', 'ROLE', 'employee'),
('ZoneExclusionGeo', '*', 'WRITE', 'ALLOW', 'ROLE', 'deliveryBoss');

View File

@ -0,0 +1,10 @@
UPDATE `vn`.`route` r
JOIN(SELECT r.id, wl.workcenterFk
FROM `vn`.`route` r
JOIN `vn`.`routeLog` rl ON rl.originFk = r.id
JOIN `vn`.`workerLabour` wl ON wl.workerFk = rl.userFk
AND r.created BETWEEN wl.started AND IFNULL(wl.ended, r.created)
WHERE r.created BETWEEN '2021-12-01' AND CURDATE()
AND rl.action = 'insert'
)sub ON sub.id = r.id
SET r.commissionWorkCenterFk = sub.workcenterFk;

View File

@ -0,0 +1,18 @@
ALTER TABLE `vn`.`itemShelving` DROP FOREIGN KEY itemShelving_fk2;
ALTER TABLE `vn`.`shelvingLog` DROP FOREIGN KEY shelvingLog_FK_ibfk_1;
ALTER TABLE `vn`.`smartTag` DROP FOREIGN KEY smartTag_shelving_fk;
ALTER TABLE `vn`.`workerShelving` DROP FOREIGN KEY workerShelving_shelving_fk;
ALTER TABLE `vn`.`shelving` DROP PRIMARY KEY;
ALTER TABLE `vn`.`shelving` ADD id INT auto_increment PRIMARY KEY NULL;
ALTER TABLE `vn`.`shelving` CHANGE id id int(11) auto_increment NOT NULL FIRST;
ALTER TABLE `vn`.`shelving` ADD CONSTRAINT shelving_UN UNIQUE KEY (code);
ALTER TABLE `vn`.`itemShelving` ADD CONSTRAINT itemShelving_fk2 FOREIGN KEY (shelvingFk) REFERENCES `vn`.`shelving`(code) ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE `vn`.`shelvingLog` ADD CONSTRAINT shelvingLog_FK_ibfk_1 FOREIGN KEY (originFk) REFERENCES `vn`.`shelving`(code) ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE `vn`.`smartTag` ADD CONSTRAINT smartTag_FK FOREIGN KEY (shelvingFk) REFERENCES `vn`.`shelving`(code) ON DELETE RESTRICT ON UPDATE CASCADE;
ALTER TABLE `vn`.`workerShelving` ADD CONSTRAINT workerShelving_FK_1 FOREIGN KEY (shelvingFk) REFERENCES `vn`.`shelving`(code) ON DELETE RESTRICT ON UPDATE CASCADE;
ALTER TABLE vn.shelvingLog DROP FOREIGN KEY shelvingLog_FK_ibfk_1;
ALTER TABLE vn.shelvingLog MODIFY COLUMN originFk INT NOT NULL;
ALTER TABLE vn.shelvingLog ADD CONSTRAINT shelvingLog_FK FOREIGN KEY (originFk) REFERENCES vn.shelving(id) ON DELETE CASCADE ON UPDATE CASCADE;

View File

@ -0,0 +1,2 @@
INSERT INTO `salix`.`ACL` (model,property,accessType,permission,principalType,principalId)
VALUES ('Parking','*','*','ALLOW','ROLE','employee')

View File

@ -0,0 +1,2 @@
INSERT INTO `salix`.`ACL` (model,property,accessType,permission,principalType,principalId)
VALUES ('Shelving','*','*','ALLOW','ROLE','employee')

View File

@ -155,14 +155,29 @@ INSERT INTO `vn`.`sector`(`id`, `description`, `warehouseFk`, `isPreviousPrepare
INSERT INTO `vn`.`parking` (`id`, `column`, `row`, `sectorFk`, `code`, `pickingOrder`) INSERT INTO `vn`.`parking` (`id`, `column`, `row`, `sectorFk`, `code`, `pickingOrder`)
VALUES VALUES
('1', '700', '01', '1', '700-01', '70001'), ('1', 700, '01', 1, '700-01', 70001),
('2', '700', '02', '2', '700-02', '70002'); ('2', 700, '02', 2, '700-02', 70002),
('3', 100, '01', 1, '100-01', 1),
(32397, 100, '02', 1, 'A-47-1', 1165),
(34831, 200, '01', 1, 'K-26-2', 20220),
(34965, 200, '02', 2, 'L-08-4', 21800),
(39096, 200, '03', 2, 'LR-02-3', 99999);
INSERT INTO `vn`.`shelving` (`code`, `parkingFk`, `isPrinted`, `priority`, `parked`, `userFk`) INSERT INTO `vn`.`shelving` (`code`, `parkingFk`, `isPrinted`, `priority`, `userFk`, `isRecyclable`)
VALUES VALUES
('GVC', 1, 0, 1, 0, 1106), ('AA6', 34965, 1, 0, NULL, 0),
('HEJ', 2, 0, 1, 0, 1106), ('AA7', 34965, 1, 0, NULL, 0),
('UXN', 1, 0, 1, 0, 1106); ('AA8', 34965, 1, 0, NULL, 0),
('AA9', NULL, 1, 0, NULL, 0),
('AAA', NULL, 0, 0, 1109, 1),
('AAB', NULL, 0, 0, 1109, 1),
('AAC', NULL, 1, 99, 1109, 1),
('AAD', NULL, 0, 0, 1109, 1),
('AAE', 39096, 1, 0, 1109, 1),
('AAF', 34831, 1, 0, 1109, 1),
('GVC', 1, 0, 1, 1106, 1),
('HEJ', 2, 0, 1, 1106, 1),
('UXN', 1, 0, 1, 1106, 1);
INSERT INTO `vn`.`accountingType`(`id`, `description`, `receiptDescription`,`code`, `maxAmount`, `daysInFuture`) INSERT INTO `vn`.`accountingType`(`id`, `description`, `receiptDescription`,`code`, `maxAmount`, `daysInFuture`)
VALUES VALUES
@ -1137,6 +1152,9 @@ INSERT INTO `vn`.`ticketCollection`(`ticketFk`, `collectionFk`, `level`)
(3, 2, NULL), (3, 2, NULL),
(23, 1, NULL); (23, 1, NULL);
INSERT INTO `vn`.`ticketCollection` (`ticketFk`, `collectionFk`, `level`)
VALUES
(1, 1, 1);
INSERT INTO `vn`.`parking` (`column`, `row`, `sectorFk`, `code`, `pickingOrder`) INSERT INTO `vn`.`parking` (`column`, `row`, `sectorFk`, `code`, `pickingOrder`)
VALUES VALUES
('100', '01', 1, '100-01', 1); ('100', '01', 1, '100-01', 1);
@ -1340,7 +1358,7 @@ INSERT INTO `vn`.`ticketWeekly`(`ticketFk`, `weekDay`)
(4, 4), (4, 4),
(5, 6); (5, 6);
INSERT INTO `vn`.`travel`(`id`,`shipped`, `landed`, `warehouseInFk`, `warehouseOutFk`, `agencyFk`, `m3`, `kg`,`ref`, `totalEntries`, `cargoSupplierFk`) INSERT INTO `vn`.`travel`(`id`,`shipped`, `landed`, `warehouseInFk`, `warehouseOutFk`, `agencyModeFk`, `m3`, `kg`,`ref`, `totalEntries`, `cargoSupplierFk`)
VALUES VALUES
(1, DATE_ADD(util.VN_CURDATE(), INTERVAL -2 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -2 MONTH), 1, 2, 1, 100.00, 1000, 'first travel', 1, 1), (1, DATE_ADD(util.VN_CURDATE(), INTERVAL -2 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -2 MONTH), 1, 2, 1, 100.00, 1000, 'first travel', 1, 1),
(2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1, 2, 1, 150, 2000, 'second travel', 2, 2), (2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1, 2, 1, 150, 2000, 'second travel', 2, 2),
@ -2582,6 +2600,15 @@ INSERT INTO `vn`.`machineWorker` (`workerFk`, `machineFk`, `inTimed`, `outTimed`
(1106, 2, util.VN_CURDATE(), NULL), (1106, 2, util.VN_CURDATE(), NULL),
(1106, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL +1 DAY)); (1106, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL +1 DAY));
INSERT INTO `vn`.`zoneExclusion` (`id`, `zoneFk`, `dated`, `created`, `userFk`)
VALUES
(1, 1, DATE_ADD(CURDATE(), INTERVAL (IF(DAYOFWEEK(CURDATE())<=7, 7, 14) - DAYOFWEEK(CURDATE())) DAY), CURDATE(), 100),
(2, 1, DATE_ADD(CURDATE(), INTERVAL (IF(DAYOFWEEK(CURDATE())<=8, 8, 15) - DAYOFWEEK(CURDATE())) DAY), CURDATE(), 100);
INSERT INTO `vn`.`zoneExclusionGeo` (`zoneExclusionFk`, `geoFk`)
VALUES
(2, 1);
INSERT INTO `vn`.`mdbBranch` (`name`) INSERT INTO `vn`.`mdbBranch` (`name`)
VALUES VALUES
('test'), ('test'),
@ -2611,3 +2638,7 @@ INSERT INTO `vn`.`sectorCollectionSaleGroup` (`sectorCollectionFk`, `saleGroupFk
INSERT INTO `vn`.`workerTimeControlConfig` (`id`, `dayBreak`, `dayBreakDriver`, `shortWeekBreak`, `longWeekBreak`, `weekScope`, `mailPass`, `mailHost`, `mailSuccessFolder`, `mailErrorFolder`, `mailUser`, `minHoursToBreak`, `breakHours`, `hoursCompleteWeek`, `startNightlyHours`, `endNightlyHours`, `maxTimePerDay`, `breakTime`, `timeToBreakTime`, `dayMaxTime`, `shortWeekDays`, `longWeekDays`) INSERT INTO `vn`.`workerTimeControlConfig` (`id`, `dayBreak`, `dayBreakDriver`, `shortWeekBreak`, `longWeekBreak`, `weekScope`, `mailPass`, `mailHost`, `mailSuccessFolder`, `mailErrorFolder`, `mailUser`, `minHoursToBreak`, `breakHours`, `hoursCompleteWeek`, `startNightlyHours`, `endNightlyHours`, `maxTimePerDay`, `breakTime`, `timeToBreakTime`, `dayMaxTime`, `shortWeekDays`, `longWeekDays`)
VALUES VALUES
(1, 43200, 32400, 129600, 259200, 604800, '', '', 'Leidos.exito', 'Leidos.error', 'timeControl', 5.33, 0.33, 40, '22:00:00', '06:00:00', 57600, 1200, 18000, 57600, 6, 13); (1, 43200, 32400, 129600, 259200, 604800, '', '', 'Leidos.exito', 'Leidos.error', 'timeControl', 5.33, 0.33, 40, '22:00:00', '06:00:00', 57600, 1200, 18000, 57600, 6, 13);
INSERT INTO `vn`.`routeConfig` (`id`, `defaultWorkCenterFk`)
VALUES
(1, 9);

View File

@ -34349,6 +34349,7 @@ CREATE TABLE `route` (
`priority` int(11) NOT NULL DEFAULT '0', `priority` int(11) NOT NULL DEFAULT '0',
`invoiceInFk` mediumint(8) unsigned DEFAULT NULL, `invoiceInFk` mediumint(8) unsigned DEFAULT NULL,
`beachFk` int(11) DEFAULT NULL, `beachFk` int(11) DEFAULT NULL,
`commissionWorkCenterFk` int(11) DEFAULT NULL COMMENT 'WorkerCenter que gestiona la ruta',
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
KEY `Id_Agencia` (`agencyModeFk`), KEY `Id_Agencia` (`agencyModeFk`),
KEY `Fecha` (`created`), KEY `Fecha` (`created`),
@ -34357,7 +34358,9 @@ CREATE TABLE `route` (
KEY `fk_route_1_idx` (`zoneFk`), KEY `fk_route_1_idx` (`zoneFk`),
KEY `asdfasdf_idx` (`invoiceInFk`), KEY `asdfasdf_idx` (`invoiceInFk`),
KEY `route_idxIsOk` (`isOk`), KEY `route_idxIsOk` (`isOk`),
KEY `route_WorkCenterFk_idx` (`commissionWorkCenterFk`),
CONSTRAINT `fk_route_1` FOREIGN KEY (`zoneFk`) REFERENCES `zone` (`id`) ON DELETE SET NULL ON UPDATE CASCADE, CONSTRAINT `fk_route_1` FOREIGN KEY (`zoneFk`) REFERENCES `zone` (`id`) ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT `route_WorkCenterFk` FOREIGN KEY (`commissionWorkCenterFk`) REFERENCES `workCenter` (`id`) ON UPDATE CASCADE,
CONSTRAINT `route_fk5` FOREIGN KEY (`agencyModeFk`) REFERENCES `agencyMode` (`id`) ON DELETE SET NULL ON UPDATE CASCADE, CONSTRAINT `route_fk5` FOREIGN KEY (`agencyModeFk`) REFERENCES `agencyMode` (`id`) ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT `route_ibfk_1` FOREIGN KEY (`gestdocFk`) REFERENCES `dms` (`id`) ON DELETE SET NULL ON UPDATE CASCADE, CONSTRAINT `route_ibfk_1` FOREIGN KEY (`gestdocFk`) REFERENCES `dms` (`id`) ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT `route_ibfk_2` FOREIGN KEY (`workerFk`) REFERENCES `worker` (`id`) ON UPDATE CASCADE, CONSTRAINT `route_ibfk_2` FOREIGN KEY (`workerFk`) REFERENCES `worker` (`id`) ON UPDATE CASCADE,
@ -34514,6 +34517,7 @@ CREATE TABLE `routeConfig` (
`plusCategory1Concept` varchar(45) COLLATE utf8_unicode_ci DEFAULT NULL, `plusCategory1Concept` varchar(45) COLLATE utf8_unicode_ci DEFAULT NULL,
`plusCategory2Concept` varchar(45) COLLATE utf8_unicode_ci DEFAULT NULL, `plusCategory2Concept` varchar(45) COLLATE utf8_unicode_ci DEFAULT NULL,
`defaultCompanyFk` smallint(5) unsigned DEFAULT '442', `defaultCompanyFk` smallint(5) unsigned DEFAULT '442',
`defaultWorkCenterFk` int(11) DEFAULT 9 COMMENT 'Para el cálculo de las comisiones, en caso de el creador de la ruta no tenga workCenter',
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
KEY `routeConfig_FK` (`defaultCompanyFk`), KEY `routeConfig_FK` (`defaultCompanyFk`),
CONSTRAINT `routeConfig_FK` FOREIGN KEY (`defaultCompanyFk`) REFERENCES `company` (`id`) CONSTRAINT `routeConfig_FK` FOREIGN KEY (`defaultCompanyFk`) REFERENCES `company` (`id`)
@ -38644,26 +38648,29 @@ CREATE TABLE `travel` (
`warehouseInFk` smallint(6) unsigned DEFAULT NULL, `warehouseInFk` smallint(6) unsigned DEFAULT NULL,
`warehouseOutFk` smallint(6) unsigned DEFAULT NULL, `warehouseOutFk` smallint(6) unsigned DEFAULT NULL,
`agencyFk` int(11) DEFAULT NULL, `agencyFk` int(11) DEFAULT NULL,
`ref` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL, `agencyModeFk` int(11) DEFAULT NULL,
`isDelivered` tinyint(1) NOT NULL DEFAULT '0', `ref` varchar(20) COLLATE utf8mb3_unicode_ci DEFAULT NULL,
`isReceived` tinyint(1) NOT NULL DEFAULT '0', `isDelivered` tinyint(1) NOT NULL DEFAULT 0,
`isReceived` tinyint(1) NOT NULL DEFAULT 0,
`m3` decimal(10,2) unsigned DEFAULT NULL, `m3` decimal(10,2) unsigned DEFAULT NULL,
`kg` decimal(10,0) unsigned DEFAULT NULL, `kg` decimal(10,0) unsigned DEFAULT NULL,
`cargoSupplierFk` int(11) DEFAULT NULL, `cargoSupplierFk` int(11) DEFAULT NULL,
`totalEntries` tinyint(4) unsigned DEFAULT '0', `totalEntries` tinyint(4) unsigned DEFAULT 0,
`appointment` datetime DEFAULT NULL, `appointment` datetime DEFAULT NULL,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
UNIQUE KEY `shipment_2` (`shipped`,`landed`,`warehouseInFk`,`warehouseOutFk`,`agencyFk`,`ref`), UNIQUE KEY `shipment_1` (`shipped`,`landed`,`warehouseInFk`,`warehouseOutFk`,`agencyFk`,`agencyModeFk`,`ref`),
KEY `agency_id` (`agencyFk`), KEY `agency_id` (`agencyFk`),
KEY `shipment` (`shipped`), KEY `shipment` (`shipped`),
KEY `landing` (`landed`), KEY `landing` (`landed`),
KEY `warehouse_landing` (`warehouseInFk`,`landed`), KEY `warehouse_landing` (`warehouseInFk`,`landed`),
KEY `warehouse_out_shipment` (`warehouseOutFk`,`shipped`), KEY `warehouse_out_shipment` (`warehouseOutFk`,`shipped`),
KEY `travel_ibfk_4_idx` (`cargoSupplierFk`), KEY `travel_ibfk_4_idx` (`cargoSupplierFk`),
KEY `travel_FK` (`agencyModeFk`),
CONSTRAINT `travel_FK` FOREIGN KEY (`agencyModeFk`) REFERENCES `agencyMode` (`id`) ON UPDATE CASCADE,
CONSTRAINT `travel_ibfk_1` FOREIGN KEY (`warehouseInFk`) REFERENCES `warehouse` (`id`) ON UPDATE CASCADE, CONSTRAINT `travel_ibfk_1` FOREIGN KEY (`warehouseInFk`) REFERENCES `warehouse` (`id`) ON UPDATE CASCADE,
CONSTRAINT `travel_ibfk_2` FOREIGN KEY (`warehouseOutFk`) REFERENCES `warehouse` (`id`) ON UPDATE CASCADE, CONSTRAINT `travel_ibfk_2` FOREIGN KEY (`warehouseOutFk`) REFERENCES `warehouse` (`id`) ON UPDATE CASCADE,
CONSTRAINT `travel_ibfk_3` FOREIGN KEY (`agencyFk`) REFERENCES `agencyMode` (`id`) ON UPDATE CASCADE CONSTRAINT `travel_ibfk_3` FOREIGN KEY (`agencyFk`) REFERENCES `agencyMode` (`id`) ON UPDATE CASCADE
) ENGINE=InnoDBDEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ROW_FORMAT=DYNAMIC; ) ENGINE=InnoDB AUTO_INCREMENT=195614 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci ROW_FORMAT=DYNAMIC;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
/*!50003 SET @saved_cs_client = @@character_set_client */ ; /*!50003 SET @saved_cs_client = @@character_set_client */ ;
/*!50003 SET @saved_cs_results = @@character_set_results */ ; /*!50003 SET @saved_cs_results = @@character_set_results */ ;
@ -38679,6 +38686,15 @@ DELIMITER ;;
FOR EACH ROW FOR EACH ROW
BEGIN BEGIN
CALL travel_checkDates(NEW.shipped, NEW.landed); CALL travel_checkDates(NEW.shipped, NEW.landed);
-- Actualizar agencyFk y agencyModeFk
IF NEW.agencyFk THEN
SET NEW.agencyModeFk = NEW.agencyFk;
END IF;
IF NEW.agencyModeFk THEN
SET NEW.agencyFk = NEW.agencyModeFk;
END IF;
END */;; END */;;
DELIMITER ; DELIMITER ;
/*!50003 SET sql_mode = @saved_sql_mode */ ; /*!50003 SET sql_mode = @saved_sql_mode */ ;
@ -38702,6 +38718,15 @@ BEGIN
OR !(NEW.shipped <=> OLD.shipped) THEN OR !(NEW.shipped <=> OLD.shipped) THEN
CALL travel_checkDates(NEW.shipped, NEW.landed); CALL travel_checkDates(NEW.shipped, NEW.landed);
END IF; END IF;
-- Actualizar agencyFk y agencyModeFk
IF !(NEW.agencyFk <=> OLD.agencyFk)THEN
SET NEW.agencyModeFk = NEW.agencyFk;
END IF;
IF !(NEW.agencyModeFk <=> OLD.agencyModeFk) THEN
SET NEW.agencyFk = NEW.agencyModeFk;
END IF;
END */;; END */;;
DELIMITER ; DELIMITER ;
/*!50003 SET sql_mode = @saved_sql_mode */ ; /*!50003 SET sql_mode = @saved_sql_mode */ ;
@ -39331,38 +39356,39 @@ DROP TABLE IF EXISTS `worker`;
/*!40101 SET character_set_client = utf8 */; /*!40101 SET character_set_client = utf8 */;
CREATE TABLE `worker` ( CREATE TABLE `worker` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT, `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`code` varchar(3) COLLATE utf8_unicode_ci NOT NULL, `code` varchar(3) COLLATE utf8mb3_unicode_ci NOT NULL,
`firstName` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL, `firstName` varchar(50) COLLATE utf8mb3_unicode_ci DEFAULT NULL,
`lastName` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL, `lastName` varchar(50) COLLATE utf8mb3_unicode_ci DEFAULT NULL,
`password__` varchar(50) CHARACTER SET utf8 DEFAULT NULL, `password__` varchar(50) CHARACTER SET utf8mb3 DEFAULT NULL,
`email__` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL, `email__` varchar(50) COLLATE utf8mb3_unicode_ci DEFAULT NULL,
`extension__` varchar(10) COLLATE utf8_unicode_ci DEFAULT NULL, `extension__` varchar(10) COLLATE utf8mb3_unicode_ci DEFAULT NULL,
`sub` int(11) unsigned DEFAULT NULL, `sub` int(11) unsigned DEFAULT NULL,
`user__` varchar(20) CHARACTER SET utf8 DEFAULT NULL, `user__` varchar(20) CHARACTER SET utf8mb3 DEFAULT NULL,
`typeBussines__` varchar(30) CHARACTER SET utf8 DEFAULT 'no dejar vacio' COMMENT 'campo obsoleto, actualmente se rellena en laboral', `typeBussines__` varchar(30) CHARACTER SET utf8mb3 DEFAULT 'no dejar vacio' COMMENT 'campo obsoleto, actualmente se rellena en laboral',
`laborCategory__` varchar(45) COLLATE utf8_unicode_ci DEFAULT NULL, `laborCategory__` varchar(45) COLLATE utf8mb3_unicode_ci DEFAULT NULL,
`started__` datetime DEFAULT NULL, `started__` datetime DEFAULT NULL,
`ended__` datetime DEFAULT NULL, `ended__` datetime DEFAULT NULL,
`notes__` varchar(254) COLLATE utf8_unicode_ci DEFAULT NULL, `notes__` varchar(254) COLLATE utf8mb3_unicode_ci DEFAULT NULL,
`photo` blob, `photo` blob DEFAULT NULL,
`fi__` varchar(9) COLLATE utf8_unicode_ci DEFAULT NULL, `fi__` varchar(9) COLLATE utf8mb3_unicode_ci DEFAULT NULL,
`address__` varchar(50) COLLATE utf8_unicode_ci NOT NULL, `address__` varchar(50) COLLATE utf8mb3_unicode_ci NOT NULL,
`birthed__` date NOT NULL, `birthed__` date NOT NULL,
`phone` varchar(9) COLLATE utf8_unicode_ci NOT NULL, `phone` varchar(9) COLLATE utf8mb3_unicode_ci DEFAULT NULL,
`mobileExtension` int(4) DEFAULT NULL,
`clientFk__` int(11) DEFAULT NULL, `clientFk__` int(11) DEFAULT NULL,
`userFk` int(10) unsigned DEFAULT NULL, `userFk` int(10) unsigned DEFAULT NULL,
`bossFk` int(11) NOT NULL DEFAULT '103', `bossFk` int(11) NOT NULL DEFAULT 103,
`fiDueDate` datetime DEFAULT NULL, `fiDueDate` datetime DEFAULT NULL,
`hasMachineryAuthorized` tinyint(2) DEFAULT '0', `hasMachineryAuthorized` tinyint(2) DEFAULT 0,
`seniority` date DEFAULT NULL, `seniority` date DEFAULT NULL,
`isTodayRelative` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'Para el F11. Calcula los problemas de visiblidad en funcion del dia actual', `isTodayRelative` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'Para el F11. Calcula los problemas de visiblidad en funcion del dia actual',
`isF11Allowed` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'Usuario autorizado para abrir el F11', `isF11Allowed` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'Usuario autorizado para abrir el F11',
`sectorFk` int(11) DEFAULT NULL COMMENT 'Sector que tiene asociado el trabajador.', `sectorFk` int(11) DEFAULT NULL COMMENT 'Sector que tiene asociado el trabajador.',
`maritalStatus` enum('S','M') COLLATE utf8_unicode_ci NOT NULL, `maritalStatus` enum('S','M') COLLATE utf8mb3_unicode_ci NOT NULL,
`labelerFk` tinyint(3) unsigned DEFAULT NULL, `labelerFk` tinyint(3) unsigned DEFAULT NULL,
`originCountryFk` mediumint(8) unsigned DEFAULT NULL COMMENT 'País de origen', `originCountryFk` mediumint(8) unsigned DEFAULT NULL COMMENT 'País de origen',
`educationLevelFk` smallint(6) DEFAULT NULL, `educationLevelFk` smallint(6) DEFAULT NULL,
`SSN` varchar(15) COLLATE utf8_unicode_ci DEFAULT NULL, `SSN` varchar(15) COLLATE utf8mb3_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
UNIQUE KEY `CodigoTrabajador_UNIQUE` (`code`), UNIQUE KEY `CodigoTrabajador_UNIQUE` (`code`),
UNIQUE KEY `user` (`user__`), UNIQUE KEY `user` (`user__`),
@ -39378,7 +39404,7 @@ CREATE TABLE `worker` (
CONSTRAINT `worker_FK_1` FOREIGN KEY (`originCountryFk`) REFERENCES `country` (`id`) ON UPDATE CASCADE, CONSTRAINT `worker_FK_1` FOREIGN KEY (`originCountryFk`) REFERENCES `country` (`id`) ON UPDATE CASCADE,
CONSTRAINT `worker_FK_2` FOREIGN KEY (`educationLevelFk`) REFERENCES `educationLevel` (`id`) ON UPDATE CASCADE, CONSTRAINT `worker_FK_2` FOREIGN KEY (`educationLevelFk`) REFERENCES `educationLevel` (`id`) ON UPDATE CASCADE,
CONSTRAINT `worker_ibfk_1` FOREIGN KEY (`id`) REFERENCES `account`.`user` (`id`) CONSTRAINT `worker_ibfk_1` FOREIGN KEY (`id`) REFERENCES `account`.`user` (`id`)
) ENGINE=InnoDBDEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; ) ENGINE=InnoDB AUTO_INCREMENT=22748 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
-- --
@ -46798,7 +46824,7 @@ BEGIN
JOIN entry e ON e.id = b.entryFk JOIN entry e ON e.id = b.entryFk
JOIN itemType it ON it.id = i.typeFk JOIN itemType it ON it.id = i.typeFk
JOIN travel tr ON tr.id = e.travelFk JOIN travel tr ON tr.id = e.travelFk
JOIN agencyMode am ON am.id = tr.agencyFk JOIN agencyMode am ON am.id = tr.agencyModeFk
JOIN tmp.rate r JOIN tmp.rate r
SET b.freightValue = @PF:= SET b.freightValue = @PF:=
ROUND(IFNULL(((am.m3 * @cm3:= item_getVolume(b.itemFk, b.packageFk)) / 1000000) / b.packing,0),3), ROUND(IFNULL(((am.m3 * @cm3:= item_getVolume(b.itemFk, b.packageFk)) / 1000000) / b.packing,0),3),
@ -72287,7 +72313,7 @@ BEGIN
END; END;
START TRANSACTION; START TRANSACTION;
INSERT INTO travel (shipped, landed, warehouseInFk, warehouseOutFk, agencyFk, `ref`, isDelivered, isReceived, m3, kg) INSERT INTO travel (shipped, landed, warehouseInFk, warehouseOutFk, agencyModeFk, `ref`, isDelivered, isReceived, m3, kg)
SELECT vDateStart, vDateEnd, vWarehouseInFk, vWarehouseOutFk, vAgencyModeFk, vRef, isDelivered, isReceived, m3, kg SELECT vDateStart, vDateEnd, vWarehouseInFk, vWarehouseOutFk, vAgencyModeFk, vRef, isDelivered, isReceived, m3, kg
FROM travel FROM travel
WHERE id = vTravelFk; WHERE id = vTravelFk;

View File

@ -29,7 +29,7 @@ describe('Entry descriptor path', () => {
it('should click the travels button to be redirected to the travels index filtered by the current agency', async() => { it('should click the travels button to be redirected to the travels index filtered by the current agency', async() => {
await page.waitToClick(selectors.entryDescriptor.travelsQuicklink); await page.waitToClick(selectors.entryDescriptor.travelsQuicklink);
await page.expectURL('/travel/index'); await page.expectURL('/travel/index');
await page.expectURL('agencyFk'); await page.expectURL('agencyModeFk');
}); });
it('should go back to the entry summary', async() => { it('should go back to the entry summary', async() => {

View File

@ -21,6 +21,7 @@ export default function moduleImport(moduleName) {
case 'entry' : return import('entry/front'); case 'entry' : return import('entry/front');
case 'account' : return import('account/front'); case 'account' : return import('account/front');
case 'supplier' : return import('supplier/front'); case 'supplier' : return import('supplier/front');
case 'shelving' : return import('shelving/front');
case 'monitor' : return import('monitor/front'); case 'monitor' : return import('monitor/front');
} }
} }

View File

@ -13,6 +13,7 @@ import './modules/route/front/module.js';
import './modules/ticket/front/module.js'; import './modules/ticket/front/module.js';
import './modules/travel/front/module.js'; import './modules/travel/front/module.js';
import './modules/worker/front/module.js'; import './modules/worker/front/module.js';
import './modules/shelving/front/module.js';
core.run(vnInterceptor => { core.run(vnInterceptor => {
vnInterceptor.setApiPath(null); vnInterceptor.setApiPath(null);

View File

@ -43,7 +43,7 @@ module.exports = Self => {
'name', 'name',
'shipped', 'shipped',
'landed', 'landed',
'agencyFk', 'agencyModeFk',
'warehouseOutFk', 'warehouseOutFk',
'warehouseInFk', 'warehouseInFk',
'isReceived', 'isReceived',

View File

@ -137,7 +137,7 @@
<vn-horizontal> <vn-horizontal>
<vn-autocomplete <vn-autocomplete
label="Agency" label="Agency"
ng-model="$ctrl.travelFilterParams.agencyFk" ng-model="$ctrl.travelFilterParams.agencyModeFk"
url="AgencyModes" url="AgencyModes"
show-field="name" show-field="name"
value-field="id"> value-field="id">

View File

@ -46,7 +46,7 @@ class Controller extends Section {
if (!value) continue; if (!value) continue;
switch (key) { switch (key) {
case 'agencyFk': case 'agencyModeFk':
case 'warehouseInFk': case 'warehouseInFk':
case 'warehouseOutFk': case 'warehouseOutFk':
case 'shipped': case 'shipped':

View File

@ -14,7 +14,7 @@ class Controller extends ModuleCard {
{ {
relation: 'travel', relation: 'travel',
scope: { scope: {
fields: ['id', 'landed', 'agencyFk', 'warehouseOutFk'], fields: ['id', 'landed', 'agencyModeFk', 'warehouseOutFk'],
include: [ include: [
{ {
relation: 'agency', relation: 'agency',

View File

@ -14,9 +14,9 @@ class Controller extends Descriptor {
let travelFilter; let travelFilter;
const entryTravel = this.entry && this.entry.travel; const entryTravel = this.entry && this.entry.travel;
if (entryTravel && entryTravel.agencyFk) { if (entryTravel && entryTravel.agencyModeFk) {
travelFilter = this.entry && JSON.stringify({ travelFilter = this.entry && JSON.stringify({
agencyFk: entryTravel.agencyFk agencyModeFk: entryTravel.agencyModeFk
}); });
} }
return travelFilter; return travelFilter;
@ -49,7 +49,7 @@ class Controller extends Descriptor {
{ {
relation: 'travel', relation: 'travel',
scope: { scope: {
fields: ['id', 'landed', 'agencyFk', 'warehouseOutFk'], fields: ['id', 'landed', 'agencyModeFk', 'warehouseOutFk'],
include: [ include: [
{ {
relation: 'agency', relation: 'agency',

View File

@ -0,0 +1,51 @@
const models = require('vn-loopback/server/server').models;
describe('route updateWorkCenter()', () => {
const routeId = 1;
it('should set the commission work center if the worker has workCenter', async() => {
const tx = await models.Route.beginTransaction({});
try {
const developerId = 9;
const ctx = {
req: {
accessToken: {userId: developerId}
}
};
const options = {transaction: tx};
const expectedResult = 1;
const updatedRoute = await models.Route.updateWorkCenter(ctx, routeId, options);
expect(updatedRoute.commissionWorkCenterFk).toEqual(expectedResult);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it(`shoul set the default commision work center if that worker didn't have one yet`, async() => {
const tx = await models.Route.beginTransaction({});
try {
const userWithoutWorkCenter = 2;
const ctx = {
req: {
accessToken: {userId: userWithoutWorkCenter}
}
};
const options = {transaction: tx};
const expectedResult = 9;
const updatedRoute = await models.Route.updateWorkCenter(ctx, routeId, options);
expect(updatedRoute.commissionWorkCenterFk).toEqual(expectedResult);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -0,0 +1,54 @@
module.exports = Self => {
Self.remoteMethodCtx('updateWorkCenter', {
description: 'Update the commission work center through user salix connected',
accessType: 'WRITE',
accepts: {
arg: 'id',
type: 'number',
description: 'Route Id',
http: {source: 'path'}
},
returns: {
type: 'object',
root: true
},
http: {
path: `/:id/updateWorkCenter`,
verb: 'POST'
}
});
Self.updateWorkCenter = async(ctx, id, options) => {
const models = Self.app.models;
const myOptions = {};
let tx;
const userId = ctx.req.accessToken.userId;
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
const [result] = await Self.rawSql(`
SELECT IFNULL(wl.workCenterFk, r.defaultWorkCenterFk) AS commissionWorkCenter
FROM vn.routeConfig r
LEFT JOIN vn.workerLabour wl ON wl.workerFk = ?
AND CURDATE() BETWEEN wl.started AND IFNULL(wl.ended, CURDATE());
`, [userId], myOptions);
const route = await models.Route.findById(id, null, myOptions);
await route.updateAttribute('commissionWorkCenterFk', result.commissionWorkCenter, myOptions);
if (tx) await tx.commit();
return route;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
};
};

View File

@ -9,6 +9,7 @@ module.exports = Self => {
require('../methods/route/clone')(Self); require('../methods/route/clone')(Self);
require('../methods/route/getSuggestedTickets')(Self); require('../methods/route/getSuggestedTickets')(Self);
require('../methods/route/unlink')(Self); require('../methods/route/unlink')(Self);
require('../methods/route/updateWorkCenter')(Self);
Self.validate('kmStart', validateDistance, { Self.validate('kmStart', validateDistance, {
message: 'Distance must be lesser than 1000' message: 'Distance must be lesser than 1000'

View File

@ -47,6 +47,9 @@
}, },
"description": { "description": {
"type": "string" "type": "string"
},
"commissionWorkCenterFk": {
"type": "number"
} }
}, },
"relations": { "relations": {

View File

@ -4,7 +4,12 @@ import Section from 'salix/components/section';
export default class Controller extends Section { export default class Controller extends Section {
onSubmit() { onSubmit() {
this.$.watcher.submit().then( this.$.watcher.submit().then(
res => this.$state.go('route.card.summary', {id: res.data.id}) res => {
this.$http.post(`Routes/${res.data.id}/updateWorkCenter`, null)
.then(() => {
this.$state.go('route.card.summary', {id: res.data.id});
});
}
); );
} }
} }

View File

@ -0,0 +1,52 @@
module.exports = Self => {
Self.remoteMethod('getSummary', {
description: 'Returns the shelving summary',
accessType: 'READ',
accepts: {
arg: 'code',
type: 'string',
required: true,
description: 'The shelving code',
http: {source: 'path'}
},
returns: {
type: 'object',
root: true
},
http: {
path: `/:code/getSummary`,
verb: 'GET'
}
});
Self.getSummary = async code => {
let filter = {
where: {code: code},
fields: [
'code',
'parkingFk',
'priority',
'userFk',
'isRecyclable'
],
include: [
{
relation: 'parking'
},
{
relation: 'worker',
scope: {
fields: ['id', 'userFk'],
include: {
relation: 'user',
scope: {
fields: ['id', 'nickname']
}
}
}
}
]
};
return Self.app.models.Shelving.findOne(filter);
};
};

View File

@ -0,0 +1,11 @@
{
"Parking": {
"dataSource": "vn"
},
"Shelving": {
"dataSource": "vn"
},
"ShelvingLog": {
"dataSource": "vn"
}
}

View File

@ -0,0 +1,33 @@
{
"name": "Parking",
"base": "VnModel",
"options": {
"mysql": {
"table": "parking"
}
},
"properties": {
"id": {
"type": "number",
"id": true,
"description": "Identifier"
},
"column": {
"type": "string",
"required": true
},
"row": {
"type": "string",
"required": true
},
"sectorFk": {
"type": "number"
},
"code": {
"type": "string"
},
"pickingOrder": {
"type": "number"
}
}
}

View File

@ -0,0 +1,58 @@
{
"name": "ShelvingLog",
"base": "VnModel",
"options": {
"mysql": {
"table": "shelvingLog"
}
},
"properties": {
"id": {
"id": true,
"type": "number",
"forceId": false
},
"originFk": {
"type": "number",
"required": true
},
"userFk": {
"type": "number"
},
"action": {
"type": "string",
"required": true
},
"changedModel": {
"type": "string"
},
"oldInstance": {
"type": "object"
},
"newInstance": {
"type": "object"
},
"creationDate": {
"type": "date"
},
"changedModelId": {
"type": "number"
},
"changedModelValue": {
"type": "string"
},
"description": {
"type": "string"
}
},
"relations": {
"user": {
"type": "belongsTo",
"model": "Account",
"foreignKey": "userFk"
}
},
"scope": {
"order": ["creationDate DESC", "id DESC"]
}
}

View File

@ -0,0 +1,3 @@
module.exports = Self => {
require('../methods/shelving/getSummary')(Self);
};

View File

@ -0,0 +1,51 @@
{
"name": "Shelving",
"base": "Loggable",
"log": {
"model": "ShelvingLog",
"showField": "id"
},
"options": {
"mysql": {
"table": "shelving"
}
},
"properties": {
"id": {
"type": "number",
"id": true,
"description": "Identifier"
},
"code": {
"type": "string",
"required": true
},
"parkingFk": {
"type": "number"
},
"isPrinted": {
"type": "boolean"
},
"priority": {
"type": "number"
},
"userFk": {
"type": "number"
},
"isRecyclable": {
"type": "boolean"
}
},
"relations": {
"parking": {
"type": "belongsTo",
"model": "Parking",
"foreignKey": "parkingFk"
},
"worker": {
"type": "belongsTo",
"model": "Worker",
"foreignKey": "userFk"
}
}
}

View File

@ -0,0 +1,52 @@
<mg-ajax path="Shelvings/{{patch.params.id}}" options="vnPatch"></mg-ajax>
<vn-watcher
vn-id="watcher"
data="$ctrl.shelving"
form="form"
save="patch">
</vn-watcher>
<form name="form" ng-submit="watcher.submit()" class="vn-w-md">
<vn-card class="vn-pa-lg">
<vn-vertical>
<vn-horizontal>
<vn-textfield
label="Code"
ng-model="$ctrl.shelving.code"
rule
vn-focus>
</vn-textfield>
<vn-autocomplete
vn-one
url="Parkings"
label="Parking"
show-field="code"
value-field="id"
ng-model="$ctrl.shelving.parkingFk">
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-input-number vn-one
label="Priority"
ng-model="$ctrl.shelving.priority"
rule>
</vn-input-number>
<vn-check
label="Recyclable"
ng-model="$ctrl.shelving.isRecyclable">
</vn-check>
</vn-horizontal>
</vn-vertical>
</vn-card>
<vn-button-bar>
<vn-submit
disabled="!watcher.dataChanged()"
label="Save">
</vn-submit>
<vn-button
class="cancel"
label="Undo changes"
disabled="!watcher.dataChanged()"
ng-click="watcher.loadOriginalData()">
</vn-button>
</vn-button-bar>
</form>

View File

@ -0,0 +1,10 @@
import ngModule from '../module';
import Section from 'salix/components/section';
ngModule.vnComponent('vnShelvingBasicData', {
template: require('./index.html'),
controller: Section,
bindings: {
shelving: '<'
}
});

View File

@ -0,0 +1,8 @@
<vn-portal slot="menu">
<vn-shelving-descriptor
shelving="$ctrl.shelving"
on-change="$ctrl.reload()">
</vn-shelving-descriptor>
<vn-left-menu source="card"></vn-left-menu>
</vn-portal>
<ui-view></ui-view>

View File

@ -0,0 +1,29 @@
import ngModule from '../module';
import ModuleCard from 'salix/components/module-card';
class Controller extends ModuleCard {
reload() {
const filter = {
include: [
{relation: 'worker',
scope: {
fields: ['userFk'],
include: {
relation: 'user',
scope: {
fields: ['nickname']
}
}
}},
{relation: 'parking'}
]
};
this.$http.get(`Shelvings/${this.$params.id}`, {filter})
.then(res => this.shelving = res.data);
}
}
ngModule.vnComponent('vnShelvingCard', {
template: require('./index.html'),
controller: Controller
});

View File

@ -0,0 +1,26 @@
import './index';
describe('component vnShelvingCard', () => {
let controller;
let $httpBackend;
const data = {id: 1, code: 'AAA'};
beforeEach(ngModule('shelving'));
beforeEach(inject(($componentController, _$httpBackend_, $stateParams) => {
$httpBackend = _$httpBackend_;
let $element = angular.element('<div></div>');
controller = $componentController('vnShelvingCard', {$element});
$stateParams.id = data.id;
$httpBackend.whenRoute('GET', 'Shelvings/:id').respond(data);
}));
it('should reload the controller data', () => {
controller.reload();
$httpBackend.flush();
expect(controller.shelving).toEqual(data);
});
});

View File

@ -0,0 +1,51 @@
<vn-watcher
vn-id="watcher"
url="Shelvings"
data="$ctrl.shelving"
insert-mode="true"
form="form">
</vn-watcher>
<form name="form" vn-http-submit="$ctrl.onSubmit()" class="vn-w-md">
<vn-card class="vn-pa-lg">
<vn-vertical>
<vn-horizontal>
<vn-textfield
label="Code"
ng-model="$ctrl.shelving.code"
rule
vn-focus>
</vn-textfield>
<vn-autocomplete
vn-one
url="Parkings"
label="Parking"
show-field="code"
value-field="id"
ng-model="$ctrl.shelving.parkingFk">
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-input-number vn-one
label="Priority"
ng-model="$ctrl.shelving.priority"
rule>
</vn-input-number>
<vn-check
label="Recyclable"
ng-model="$ctrl.shelving.isRecyclable">
</vn-check>
</vn-horizontal>
</vn-vertical>
</vn-card>
<vn-button-bar>
<vn-submit
disabled="!watcher.dataChanged()"
label="Create">
</vn-submit>
<vn-button
class="cancel"
label="Cancel"
ui-sref="shelving.index">
</vn-button>
</vn-button-bar>
</form>

View File

@ -0,0 +1,15 @@
import ngModule from '../module';
import Section from 'salix/components/section';
export default class Controller extends Section {
onSubmit() {
return this.$.watcher.submit().then(res =>
this.$state.go('shelving.card.basicData', {id: res.data.id})
);
}
}
ngModule.vnComponent('vnShelvingCreate', {
template: require('./index.html'),
controller: Controller
});

View File

@ -0,0 +1,38 @@
import './index';
describe('Shelving', () => {
describe('Component vnShelvingCreate', () => {
let $scope;
let $state;
let controller;
beforeEach(ngModule('shelving'));
beforeEach(inject(($componentController, $rootScope, _$state_) => {
$scope = $rootScope.$new();
$state = _$state_;
$scope.watcher = {
submit: () => {
return {
then: callback => {
callback({data: {id: 1}});
}
};
}
};
const $element = angular.element('<vn-shelving-create></vn-shelving-create>');
controller = $componentController('vnShelvingCreate', {$element, $scope});
controller.$params = {};
}));
describe('onSubmit()', () => {
it(`should redirect to basic data by calling the $state.go function`, () => {
jest.spyOn(controller.$state, 'go');
controller.onSubmit();
expect(controller.$state.go).toHaveBeenCalledWith('shelving.card.basicData', {id: 1});
});
});
});
});

View File

@ -0,0 +1,45 @@
<vn-descriptor-content
module="shelving"
description="$ctrl.shelving.code"
summary="$ctrl.$.summary">
<slot-menu>
<vn-item
ng-click="deleteShelving.show()"
name="deleteShelving"
translate>
Delete
</vn-item>
</slot-menu>
<slot-body>
<div class="attributes">
<vn-label-value
label="Code"
value="{{$ctrl.shelving.code}}">
</vn-label-value>
<vn-label-value
label="Parking"
value="{{$ctrl.shelving.parking.code}}">
</vn-label-value>
<vn-label-value
label="Worker">
<span
ng-click="workerDescriptor.show($event, $ctrl.shelving.userFk)"
class="link">
{{::$ctrl.shelving.worker.user.nickname}}
</span>
</vn-label-value>
</div>
</slot-body>
</vn-descriptor-content>
<vn-confirm
vn-id="delete-shelving"
on-accept="$ctrl.onDelete()"
question="Are you sure you want to continue?"
message="Shelving will be removed">
</vn-confirm>
<vn-popup vn-id="summary">
<vn-shelving-summary shelving="$ctrl.shelving"></vn-shelving-summary>
</vn-popup>
<vn-worker-descriptor-popover
vn-id="workerDescriptor">
</vn-worker-descriptor-popover>

View File

@ -0,0 +1,26 @@
import ngModule from '../module';
import Descriptor from 'salix/components/descriptor';
class Controller extends Descriptor {
get shelving() {
return this.entity;
}
set shelving(value) {
this.entity = value;
}
onDelete() {
return this.$http.delete(`Shelvings/${this.shelving.id}`)
.then(() => this.$state.go('shelving.index'))
.then(() => this.vnApp.showSuccess(this.$t('Shelving removed')));
}
}
ngModule.vnComponent('vnShelvingDescriptor', {
template: require('./index.html'),
controller: Controller,
bindings: {
shelving: '<'
}
});

View File

@ -0,0 +1,29 @@
import './index.js';
describe('component vnShelvingDescriptor', () => {
let $httpBackend;
let controller;
const shelving = {id: 1, code: 'AA6'};
beforeEach(ngModule('shelving'));
beforeEach(inject(($componentController, _$httpBackend_, _$httpParamSerializer_) => {
$httpBackend = _$httpBackend_;
controller = $componentController('vnShelvingDescriptor', {$element: null}, {shelving});
jest.spyOn(controller.vnApp, 'showSuccess');
}));
describe('onDelete()', () => {
it('should delete entity and go to index', () => {
controller.$state.go = jest.fn();
$httpBackend.expectDELETE('Shelvings/1').respond();
controller.onDelete();
$httpBackend.flush();
expect(controller.$state.go).toHaveBeenCalledWith('shelving.index');
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
});
});
});

View File

@ -0,0 +1,11 @@
export * from './module';
import './basic-data';
import './card';
import './create';
import './descriptor';
import './index/';
import './main';
import './search-panel';
import './summary';
import './log';

View File

@ -0,0 +1,47 @@
<vn-auto-search
model="model">
</vn-auto-search>
<vn-data-viewer
model="model"
class="vn-w-sm">
<vn-card>
<div class="vn-list separated">
<a
ng-repeat="shelving in model.data track by shelving.id"
ui-sref="shelving.card.summary(::{id: shelving.id})"
translate-attr="{title: 'View shelving'}"
class="vn-item search-result">
<vn-item-section>
<h6>{{::shelving.code}}</h6>
<vn-label-value label="Parking"
value="{{::shelving.parking.code}}">
</vn-label-value>
<vn-label-value label="Priority"
value="{{::shelving.priority}}">
</vn-label-value>
</vn-item-section>
<vn-item-section side>
<vn-icon-button
vn-click-stop="$ctrl.preview(shelving)"
vn-tooltip="Preview"
icon="preview">
</vn-icon-button>
</vn-item-section>
</a>
</div>
</vn-card>
</vn-data-viewer>
<vn-popup vn-id="summary">
<vn-shelving-summary
shelving="$ctrl.selectedShelving">
</vn-shelving-summary>
</vn-popup>
<a
ui-sref="shelving.create"
vn-tooltip="New shelving"
vn-bind="+"
vn-acl-action="remove"
fixed-bottom-right>
<vn-float-button icon="add"></vn-float-button>
</a>

View File

@ -0,0 +1,14 @@
import ngModule from '../module';
import Section from 'salix/components/section';
export default class Controller extends Section {
preview(shelving) {
this.selectedShelving = shelving;
this.$.summary.show();
}
}
ngModule.vnComponent('vnShelvingIndex', {
template: require('./index.html'),
controller: Controller
});

View File

@ -0,0 +1,39 @@
import './index.js';
describe('Component vnShelvingIndex', () => {
let controller;
let $window;
let shelvings = [{
id: 1,
code: 'AAA'
}, {
id: 2,
code: 'AA1'
}, {
id: 3,
code: 'AA2'
}];
beforeEach(ngModule('shelving'));
beforeEach(inject(($componentController, _$window_) => {
$window = _$window_;
const $element = angular.element('<vn-shelving-index></vn-shelving-index>');
controller = $componentController('vnShelvingIndex', {$element});
}));
describe('preview()', () => {
it('should show the dialog summary', () => {
controller.$.summary = {show: () => {}};
jest.spyOn(controller.$.summary, 'show');
let event = new MouseEvent('click', {
view: $window,
bubbles: true,
cancelable: true
});
controller.preview(event, shelvings[0]);
expect(controller.$.summary.show).toHaveBeenCalledWith();
});
});
});

View File

@ -0,0 +1,2 @@
Parking: Parking
Priority: Prioridad

View File

@ -0,0 +1 @@
<vn-log url="ShelvingLogs" origin-id="$ctrl.$params.id"></vn-log>

View File

@ -0,0 +1,7 @@
import ngModule from '../module';
import Section from 'salix/components/section';
ngModule.vnComponent('vnShelvingLog', {
template: require('./index.html'),
controller: Section,
});

View File

@ -0,0 +1 @@
Changed by: Cambiado por

View File

@ -0,0 +1,19 @@
<vn-crud-model
vn-id="model"
url="Shelvings"
filter="$ctrl.filter"
limit="20">
</vn-crud-model>
<vn-portal slot="topbar">
<vn-searchbar
vn-focus
panel="vn-shelving-search-panel"
info="Search shelving by code, parking or worker"
model="model"
expr-builder="$ctrl.exprBuilder(param, value)">
</vn-searchbar>
</vn-portal>
<vn-portal slot="menu">
<vn-left-menu></vn-left-menu>
</vn-portal>
<ui-view></ui-view>

View File

@ -0,0 +1,29 @@
import ngModule from '../module';
import ModuleMain from 'salix/components/module-main';
export default class Shelving extends ModuleMain {
constructor($element, $) {
super($element, $);
this.filter = {
include: [
{relation: 'parking'}
],
};
}
exprBuilder(param, value) {
switch (param) {
case 'search':
return {code: {like: `%${value}%`}};
case 'parkingFk':
case 'userFk':
case 'isRecyclable':
return {[param]: value};
}
}
}
ngModule.vnComponent('vnShelving', {
controller: Shelving,
template: require('./index.html')
});

View File

@ -0,0 +1,19 @@
import './index';
describe('component vnShelving', () => {
let controller;
beforeEach(ngModule('shelving'));
beforeEach(inject($componentController => {
controller = $componentController('vnShelving', {$element: null});
}));
describe('exprBuilder()', () => {
it('should search by code', () => {
let expr = controller.exprBuilder('search', 'UXN');
expect(expr).toEqual({code: {like: '%UXN%'}},);
});
});
});

View File

@ -0,0 +1 @@
Search shelving by code, parking or worker: Busca carros por código, parking o trabajador

View File

@ -0,0 +1,3 @@
import {ng} from 'core/vendor';
export default ng.module('shelving', ['salix']);

View File

@ -0,0 +1,70 @@
{
"module": "shelving",
"name": "Shelvings",
"icon" : "contact_support",
"dependencies": ["worker"],
"validations" : true,
"menus": {
"main": [
{"state": "shelving.index", "icon": "contact_support"}
],
"card": [
{"state": "shelving.card.basicData", "icon": "settings"},
{"state": "shelving.card.log", "icon": "history"}
]
},
"keybindings": [
{"key": "s", "state": "shelving.index"}
],
"routes": [
{
"url": "/shelving",
"state": "shelving",
"abstract": true,
"component": "vn-shelving",
"description": "Shelvings"
},
{
"url": "/index?q",
"state": "shelving.index",
"component": "vn-shelving-index",
"description": "Shelvings"
},
{
"url": "/create",
"state": "shelving.create",
"component": "vn-shelving-create",
"description": "New shelving"
},
{
"url": "/:id",
"state": "shelving.card",
"abstract": true,
"component": "vn-shelving-card"
},
{
"url": "/summary",
"state": "shelving.card.summary",
"component": "vn-shelving-summary",
"description": "Summary",
"params": {
"shelving": "$ctrl.shelving"
}
},
{
"url": "/basic-data",
"state": "shelving.card.basicData",
"component": "vn-shelving-basic-data",
"description": "Basic data",
"params": {
"shelving": "$ctrl.shelving"
}
},
{
"url" : "/log",
"state": "shelving.card.log",
"component": "vn-shelving-log",
"description": "Log"
}
]
}

View File

@ -0,0 +1,43 @@
<div class="search-panel">
<form ng-submit="$ctrl.onSearch()">
<vn-horizontal>
<vn-textfield
vn-one
label="General search"
ng-model="filter.search"
info="Search shelvings by code"
vn-focus>
</vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete
vn-one
url="Parkings"
label="Parking"
show-field="code"
value-field="id"
ng-model="filter.parkingFk">
</vn-autocomplete>
<vn-autocomplete
vn-one
url="Workers"
label="Worker"
search-function="{or: [{id: $search}, {firstName: {like: $search}}]}"
show-field="firstName"
value-field="id"
ng-model="filter.userFk">
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-check
vn-one
label="Recyclable"
ng-model="filter.isRecyclable"
triple-state="true">
</vn-check>
</vn-horizontal>
<vn-horizontal class="vn-mt-lg">
<vn-submit label="Search"></vn-submit>
</vn-horizontal>
</form>
</div>

View File

@ -0,0 +1,7 @@
import ngModule from '../module';
import SearchPanel from 'core/components/searchbar/search-panel';
ngModule.vnComponent('vnShelvingSearchPanel', {
template: require('./index.html'),
controller: SearchPanel
});

View File

@ -0,0 +1 @@
Search shelvings by code: Busca carros por código

View File

@ -0,0 +1,51 @@
<vn-card class="summary">
<h5>
<a ng-if="::$ctrl.summary.code"
vn-tooltip="Go to the shelving"
ui-sref="shelving.card.summary({id: {{::$ctrl.summary.code}}})"
name="goToSummary">
<vn-icon-button icon="launch"></vn-icon-button>
</a>
<span>{{::$ctrl.summary.code}}</span>
</h5>
<vn-horizontal>
<vn-one>
<h4>
<a
ui-sref="shelving.card.basicData({id: $ctrl.summary.id})"
target="_self">
<span translate vn-tooltip="Go to">Basic data</span>
</a>
</h4>
<vn-vertical>
<vn-label-value
label="Code"
value="{{::$ctrl.summary.code}}">
</vn-label-value>
<vn-label-value
label="Parking"
value="{{::$ctrl.summary.parking.code}}">
</vn-label-value>
<vn-label-value
label="Priority"
value="{{::$ctrl.summary.priority}}">
</vn-label-value>
<vn-label-value label="Worker">
<span
ng-click="workerDescriptor.show($event, $ctrl.summary.worker.user.id)"
class="link">
{{$ctrl.summary.worker.user.nickname}}
</span>
</vn-label-value>
<vn-check
label="Recyclable"
ng-model="$ctrl.summary.isRecyclable"
disabled="true">
</vn-check>
</vn-vertical>
</vn-one>
</vn-horizontal>
</vn-card>
<vn-worker-descriptor-popover
vn-id="workerDescriptor">
</vn-worker-descriptor-popover>

View File

@ -0,0 +1,41 @@
import ngModule from '../module';
import Summary from 'salix/components/summary';
import './style.scss';
class Controller extends Summary {
set shelving(value) {
this._shelving = value;
this.summary = null;
if (!value) return;
const filter = {
include: [
{relation: 'worker',
scope: {
fields: ['userFk'],
include: {
relation: 'user',
scope: {
fields: ['nickname']
}
}
}},
{relation: 'parking'}
]
};
this.$http.get(`Shelvings/${value.id}`, {filter})
.then(res => this.summary = res.data);
}
get shelving() {
return this._shelving;
}
}
ngModule.vnComponent('vnShelvingSummary', {
template: require('./index.html'),
controller: Controller,
bindings: {
shelving: '<'
}
});

View File

@ -0,0 +1,5 @@
Code: Código
Parking: Parking
Priority: Prioridad
Worker: Trabajador
Recyclable: Reciclable

View File

@ -0,0 +1,7 @@
@import "variables";
vn-client-summary {
.alert span {
color: $color-alert
}
}

View File

@ -35,7 +35,7 @@ module.exports = Self => {
'landed', 'landed',
'warehouseInFk', 'warehouseInFk',
'warehouseOutFk', 'warehouseOutFk',
'agencyFk', 'agencyModeFk',
'ref' 'ref'
] ]
}); });
@ -56,7 +56,7 @@ module.exports = Self => {
travel.warehouseOutFk, travel.warehouseOutFk,
travel.warehouseInFk, travel.warehouseInFk,
travel.ref, travel.ref,
travel.agencyFk travel.agencyModeFk
] ]
); );
stmts.push(stmt); stmts.push(stmt);
@ -76,7 +76,7 @@ module.exports = Self => {
'landed', 'landed',
'warehouseInFk', 'warehouseInFk',
'warehouseOutFk', 'warehouseOutFk',
'agencyFk', 'agencyModeFk',
'ref' 'ref'
] ]
}); });

View File

@ -34,7 +34,7 @@ module.exports = Self => {
description: 'The landed to date filter' description: 'The landed to date filter'
}, },
{ {
arg: 'agencyFk', arg: 'agencyModeFk',
type: 'number', type: 'number',
description: 'The agencyModeFk id' description: 'The agencyModeFk id'
}, },
@ -96,7 +96,7 @@ module.exports = Self => {
case 'continent': case 'continent':
return {'cnt.code': value}; return {'cnt.code': value};
case 'id': case 'id':
case 'agencyFk': case 'agencyModeFk':
case 'warehouseOutFk': case 'warehouseOutFk':
case 'warehouseInFk': case 'warehouseInFk':
case 'totalEntries': case 'totalEntries':
@ -143,7 +143,7 @@ module.exports = Self => {
JOIN warehouse wo ON wo.id = t.warehouseOutFk JOIN warehouse wo ON wo.id = t.warehouseOutFk
JOIN country c ON c.id = wo.countryFk JOIN country c ON c.id = wo.countryFk
LEFT JOIN continent cnt ON cnt.id = c.continentFk LEFT JOIN continent cnt ON cnt.id = c.continentFk
JOIN agencyMode am ON am.id = t.agencyFk` JOIN agencyMode am ON am.id = t.agencyModeFk`
); );
stmt.merge(conn.makeWhere(filter.where)); stmt.merge(conn.makeWhere(filter.where));

View File

@ -44,7 +44,7 @@ module.exports = Self => {
description: 'The landed to date filter', description: 'The landed to date filter',
http: {source: 'query'} http: {source: 'query'}
}, { }, {
arg: 'agencyFk', arg: 'agencyModeFk',
type: 'number', type: 'number',
description: 'The agencyModeFk id', description: 'The agencyModeFk id',
http: {source: 'query'} http: {source: 'query'}
@ -102,7 +102,7 @@ module.exports = Self => {
case 'landedTo': case 'landedTo':
return {'t.landed': {lte: value}}; return {'t.landed': {lte: value}};
case 'id': case 'id':
case 'agencyFk': case 'agencyModeFk':
case 'warehouseOutFk': case 'warehouseOutFk':
case 'warehouseInFk': case 'warehouseInFk':
case 'totalEntries': case 'totalEntries':
@ -124,7 +124,7 @@ module.exports = Self => {
t.landed, t.landed,
t.warehouseInFk, t.warehouseInFk,
t.warehouseOutFk, t.warehouseOutFk,
t.agencyFk, t.agencyModeFk,
t.ref, t.ref,
t.isDelivered, t.isDelivered,
t.isReceived, t.isReceived,
@ -137,7 +137,7 @@ module.exports = Self => {
wout.name warehouseOutName, wout.name warehouseOutName,
cnt.code continent cnt.code continent
FROM vn.travel t FROM vn.travel t
JOIN vn.agencyMode am ON am.id = t.agencyFk JOIN vn.agencyMode am ON am.id = t.agencyModeFk
JOIN vn.warehouse win ON win.id = t.warehouseInFk JOIN vn.warehouse win ON win.id = t.warehouseInFk
JOIN vn.warehouse wout ON wout.id = t.warehouseOutFk JOIN vn.warehouse wout ON wout.id = t.warehouseOutFk
JOIN warehouse wo ON wo.id = t.warehouseOutFk JOIN warehouse wo ON wo.id = t.warehouseOutFk

View File

@ -32,9 +32,9 @@ module.exports = Self => {
t.warehouseOutFk, t.warehouseOutFk,
t.landed, t.landed,
t.shipped, t.shipped,
t.agencyFk t.agencyModeFk
FROM travel t FROM travel t
WHERE t.agencyFk = ? LIMIT 50)`, [agencyModeFk]); WHERE t.agencyModeFk = ? LIMIT 50)`, [agencyModeFk]);
stmts.push(stmt); stmts.push(stmt);
stmt = new ParameterizedSQL(` stmt = new ParameterizedSQL(`
@ -44,10 +44,10 @@ module.exports = Self => {
t.warehouseOutFk, t.warehouseOutFk,
(SELECT ROUND(AVG(DATEDIFF(t.landed, t.shipped ))) (SELECT ROUND(AVG(DATEDIFF(t.landed, t.shipped )))
FROM tmp.travel t FROM tmp.travel t
WHERE t.agencyFk WHERE t.agencyModeFk
ORDER BY id DESC LIMIT 50) AS dayDuration ORDER BY id DESC LIMIT 50) AS dayDuration
FROM tmp.travel t FROM tmp.travel t
WHERE t.agencyFk WHERE t.agencyModeFk
ORDER BY t.id DESC LIMIT 1`); ORDER BY t.id DESC LIMIT 1`);
const avgDaysIndex = stmts.push(stmt) - 1; const avgDaysIndex = stmts.push(stmt) - 1;

View File

@ -71,7 +71,7 @@ describe('Travel cloneWithEntries()', () => {
expect(newTravel.ref).toEqual('fifth travel'); expect(newTravel.ref).toEqual('fifth travel');
expect(newTravel.warehouseInFk).toEqual(warehouseThree); expect(newTravel.warehouseInFk).toEqual(warehouseThree);
expect(newTravel.warehouseOutFk).toEqual(warehouseThree); expect(newTravel.warehouseOutFk).toEqual(warehouseThree);
expect(newTravel.agencyFk).toEqual(agencyModeOne); expect(newTravel.agencyModeFk).toEqual(agencyModeOne);
expect(travelEntries.length).toBeGreaterThan(0); expect(travelEntries.length).toBeGreaterThan(0);
}); });
}); });

View File

@ -70,10 +70,10 @@ describe('Travel extraCommunityFilter()', () => {
expect(result.length).toEqual(3); expect(result.length).toEqual(3);
}); });
it('should return the travel matching "agencyFk"', async() => { it('should return the travel matching "agencyModeFk"', async() => {
const ctx = { const ctx = {
args: { args: {
agencyFk: 1 agencyModeFk: 1
} }
}; };

View File

@ -44,17 +44,14 @@
"type": "number" "type": "number"
}, },
"agencyModeFk": { "agencyModeFk": {
"type": "number", "type": "number"
"mysql": {
"columnName": "agencyFk"
}
} }
}, },
"relations": { "relations": {
"agency": { "agency": {
"type": "belongsTo", "type": "belongsTo",
"model": "AgencyMode", "model": "AgencyMode",
"foreignKey": "agencyFk" "foreignKey": "agencyModeFk"
}, },
"warehouseIn": { "warehouseIn": {
"type": "belongsTo", "type": "belongsTo",

View File

@ -25,7 +25,7 @@ class Controller extends Section {
'shipped', 'shipped',
'landed', 'landed',
'totalEntries', 'totalEntries',
'agencyFk', 'agencyModeFk',
'warehouseInFk', 'warehouseInFk',
'warehouseOutFk', 'warehouseOutFk',
'cargoSupplierFk' 'cargoSupplierFk'
@ -64,7 +64,7 @@ class Controller extends Section {
onCloneAccept() { onCloneAccept() {
const params = JSON.stringify({ const params = JSON.stringify({
ref: this.travel.ref, ref: this.travel.ref,
agencyModeFk: this.travel.agencyFk, agencyModeFk: this.travel.agencyModeFk,
shipped: this.travel.shipped, shipped: this.travel.shipped,
landed: this.travel.landed, landed: this.travel.landed,
warehouseInFk: this.travel.warehouseInFk, warehouseInFk: this.travel.warehouseInFk,

View File

@ -18,7 +18,7 @@ describe('Travel Component vnTravelDescriptorMenu', () => {
controller.travel = { controller.travel = {
ref: 'the ref', ref: 'the ref',
agencyFk: 'the agency', agencyModeFk: 'the agency',
shipped: 'the shipped date', shipped: 'the shipped date',
landed: 'the landing date', landed: 'the landing date',
warehouseInFk: 'the receiver warehouse', warehouseInFk: 'the receiver warehouse',
@ -29,7 +29,7 @@ describe('Travel Component vnTravelDescriptorMenu', () => {
const params = JSON.stringify({ const params = JSON.stringify({
ref: controller.travel.ref, ref: controller.travel.ref,
agencyModeFk: controller.travel.agencyFk, agencyModeFk: controller.travel.agencyModeFk,
shipped: controller.travel.shipped, shipped: controller.travel.shipped,
landed: controller.travel.landed, landed: controller.travel.landed,
warehouseInFk: controller.travel.warehouseInFk, warehouseInFk: controller.travel.warehouseInFk,

View File

@ -14,9 +14,9 @@ class Controller extends Descriptor {
let travelFilter; let travelFilter;
const travel = this.travel; const travel = this.travel;
if (travel && travel.agencyFk) { if (travel && travel.agencyModeFk) {
travelFilter = this.travel && JSON.stringify({ travelFilter = this.travel && JSON.stringify({
agencyFk: this.travel.agencyFk agencyModeFk: this.travel.agencyModeFk
}); });
} }
return travelFilter; return travelFilter;

View File

@ -29,7 +29,7 @@
</vn-textfield> </vn-textfield>
<vn-autocomplete vn-one <vn-autocomplete vn-one
label="Agency" label="Agency"
ng-model="filter.agencyFk" ng-model="filter.agencyModeFk"
url="AgencyModes" url="AgencyModes"
show-field="name" show-field="name"
value-field="id"> value-field="id">

View File

@ -11,7 +11,7 @@
<vn-tr> <vn-tr>
<vn-th field="id" number filter-enabled="false">Id</vn-th> <vn-th field="id" number filter-enabled="false">Id</vn-th>
<vn-th field="ref">Reference</vn-th> <vn-th field="ref">Reference</vn-th>
<vn-th field="agencyFk">Agency</vn-th> <vn-th field="agencyModeFk">Agency</vn-th>
<vn-th field="warehouseOutFk">Warehouse Out</vn-th> <vn-th field="warehouseOutFk">Warehouse Out</vn-th>
<vn-th field="shipped" center shrink-date>Shipped</vn-th> <vn-th field="shipped" center shrink-date>Shipped</vn-th>
<vn-th field="isDelivered" center>Delivered</vn-th> <vn-th field="isDelivered" center>Delivered</vn-th>

View File

@ -10,7 +10,7 @@ export default class Controller extends Section {
onCloneAccept(travel) { onCloneAccept(travel) {
const params = JSON.stringify({ const params = JSON.stringify({
ref: travel.ref, ref: travel.ref,
agencyModeFk: travel.agencyFk, agencyModeFk: travel.agencyModeFk,
shipped: travel.shipped, shipped: travel.shipped,
landed: travel.landed, landed: travel.landed,
warehouseInFk: travel.warehouseInFk, warehouseInFk: travel.warehouseInFk,
@ -44,7 +44,7 @@ export default class Controller extends Section {
case 'landed': case 'landed':
return {'t.landed': {between: this.dateRange(value)}}; return {'t.landed': {between: this.dateRange(value)}};
case 'id': case 'id':
case 'agencyFk': case 'agencyModeFk':
case 'warehouseOutFk': case 'warehouseOutFk':
case 'warehouseInFk': case 'warehouseInFk':
case 'totalEntries': case 'totalEntries':

View File

@ -35,11 +35,11 @@ describe('Travel Component vnTravelIndex', () => {
const travel = { const travel = {
ref: 1, ref: 1,
agencyFk: 1 agencyModeFk: 1
}; };
const travelParams = { const travelParams = {
ref: travel.ref, ref: travel.ref,
agencyModeFk: travel.agencyFk agencyModeFk: travel.agencyModeFk
}; };
const queryParams = JSON.stringify(travelParams); const queryParams = JSON.stringify(travelParams);
controller.onCloneAccept(travel); controller.onCloneAccept(travel);

View File

@ -29,7 +29,7 @@
</vn-textfield> </vn-textfield>
<vn-autocomplete vn-one <vn-autocomplete vn-one
label="Agency" label="Agency"
ng-model="filter.agencyFk" ng-model="filter.agencyModeFk"
url="AgencyModes" url="AgencyModes"
show-field="name" show-field="name"
value-field="id"> value-field="id">

View File

@ -49,6 +49,9 @@
}, },
"labelerFk": { "labelerFk": {
"type" : "number" "type" : "number"
},
"mobileExtension": {
"type" : "number"
} }
}, },
"relations": { "relations": {

View File

@ -25,10 +25,18 @@
<vn-horizontal> <vn-horizontal>
<vn-textfield <vn-textfield
vn-one vn-one
label="Phone" label="Business phone"
ng-model="$ctrl.worker.phone" ng-model="$ctrl.worker.phone"
rule> rule>
</vn-textfield> </vn-textfield>
<vn-textfield
vn-one
label="Mobile extension"
ng-model="$ctrl.worker.mobileExtension"
rule>
</vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete <vn-autocomplete
ng-model="$ctrl.worker.bossFk" ng-model="$ctrl.worker.bossFk"
url="Workers/activeWithInheritedRole" url="Workers/activeWithInheritedRole"
@ -37,8 +45,6 @@
where="{role: 'employee'}" where="{role: 'employee'}"
label="Boss"> label="Boss">
</vn-autocomplete> </vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete <vn-autocomplete
label="Marital status" label="Marital status"
data="$ctrl.maritalStatus" data="$ctrl.maritalStatus"
@ -46,6 +52,8 @@
value-field="code" value-field="code"
ng-model="$ctrl.worker.maritalStatus"> ng-model="$ctrl.worker.maritalStatus">
</vn-autocomplete> </vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete <vn-autocomplete
ng-model="$ctrl.worker.originCountryFk" ng-model="$ctrl.worker.originCountryFk"
url="Countries" url="Countries"
@ -54,8 +62,6 @@
value-field="id" value-field="id"
label="Origin country"> label="Origin country">
</vn-autocomplete> </vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete <vn-autocomplete
ng-model="$ctrl.worker.educationLevelFk" ng-model="$ctrl.worker.educationLevelFk"
url="EducationLevels" url="EducationLevels"
@ -64,6 +70,8 @@
value-field="id" value-field="id"
label="Education level"> label="Education level">
</vn-autocomplete> </vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-textfield <vn-textfield
vn-one vn-one
label="SSN" label="SSN"

View File

@ -4,3 +4,5 @@ Education level: Nivel educación
SSN: NSS SSN: NSS
Married: Casado/a Married: Casado/a
Single: Soltero/a Single: Soltero/a
Business phone: Teléfono de empresa
Mobile extension: Extensión móvil

View File

@ -38,9 +38,15 @@
{{::worker.boss.nickname}} {{::worker.boss.nickname}}
</span> </span>
</vn-label-value> </vn-label-value>
<vn-label-value label="Phone" <vn-label-value label="Mobile extension"
value="{{worker.mobileExtension}}">
</vn-label-value>
<vn-label-value label="Business phone"
value="{{worker.phone}}"> value="{{worker.phone}}">
</vn-label-value> </vn-label-value>
<vn-label-value label="Personal phone"
value="{{worker.client.phone}}">
</vn-label-value>
</vn-one> </vn-one>
<vn-one> <vn-one>
<h4 translate>User data</h4> <h4 translate>User data</h4>

View File

@ -34,7 +34,7 @@ class Controller extends Summary {
}, },
{ {
relation: 'client', relation: 'client',
scope: {fields: ['fi']} scope: {fields: ['fi', 'phone']}
}, },
{ {
relation: 'boss', relation: 'boss',

View File

@ -0,0 +1,3 @@
Business phone: Teléfono de empresa
Personal phone: Teléfono personal
Mobile extension: Extensión móvil

View File

@ -0,0 +1,64 @@
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.remoteMethod('exclusionGeo', {
description: 'Exclude a geo from a zone',
accepts: [
{
arg: 'zoneFk',
type: 'number',
description: 'The zone id'
},
{
arg: 'date',
type: 'date',
description: 'The date to exclude'
},
{
arg: 'geoIds',
type: ['number'],
description: 'The geos id'
}
],
returns: {
type: 'object',
root: true
},
http: {
path: `/exclusionGeo`,
verb: 'POST'
}
});
Self.exclusionGeo = async(zoneFk, date, geoIds, options) => {
const models = Self.app.models;
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!geoIds[0]) throw new UserError(`You must select a location`);
const newZoneExclusion = await models.ZoneExclusion.create({
zoneFk: zoneFk,
dated: date
}, myOptions);
const promises = [];
for (const geoId of geoIds) {
const newZoneExclusionGeo = await models.ZoneExclusionGeo.create({
zoneExclusionFk: newZoneExclusion.id,
geoFk: geoId
}, myOptions);
promises.push(newZoneExclusionGeo);
}
const newZoneExclusionGeos = await Promise.all(promises);
return newZoneExclusionGeos;
};
};

View File

@ -56,12 +56,23 @@ module.exports = Self => {
[zoneFk, started, ended, started, ended, started, ended, started, ended], myOptions); [zoneFk, started, ended, started, ended, started, ended, started, ended], myOptions);
query = ` query = `
SELECT * SELECT e.*
FROM vn.zoneExclusion FROM vn.zoneExclusion e
WHERE zoneFk = ? LEFT JOIN vn.zoneExclusionGeo eg ON eg.zoneExclusionFk = e.id
AND dated BETWEEN ? AND ?;`; WHERE e.zoneFk = ?
AND e.dated BETWEEN ? AND ?
AND eg.zoneExclusionFk IS NULL;`;
const exclusions = await Self.rawSql(query, [zoneFk, started, ended], myOptions); const exclusions = await Self.rawSql(query, [zoneFk, started, ended], myOptions);
return {events, exclusions}; query = `
SELECT eg.*, e.zoneFk, e.dated, e.created, e.userFk
FROM vn.zoneExclusion e
LEFT JOIN vn.zoneExclusionGeo eg ON eg.zoneExclusionFk = e.id
WHERE e.zoneFk = ?
AND e.dated BETWEEN ? AND ?
AND eg.zoneExclusionFk IS NOT NULL;`;
const geoExclusions = await Self.rawSql(query, [zoneFk, started, ended], myOptions);
return {events, exclusions, geoExclusions};
}; };
}; };

View File

@ -0,0 +1,41 @@
const models = require('vn-loopback/server/server').models;
describe('zone exclusionGeo()', () => {
const zoneId = 1;
const today = new Date();
it(`should show an error when location isn't selected`, async() => {
const tx = await models.Zone.beginTransaction({});
try {
const options = {transaction: tx};
const geoIds = [];
await models.Zone.exclusionGeo(zoneId, today, geoIds, options);
await tx.rollback();
} catch (e) {
await tx.rollback();
error = e;
}
expect(error.message).toContain(`You must select a location`);
});
it('should create two exclusion by geo', async() => {
const tx = await models.Zone.beginTransaction({});
try {
const options = {transaction: tx};
const geoIds = [1, 2];
const result = await models.Zone.exclusionGeo(zoneId, today, geoIds, options);
expect(result.length).toEqual(2);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -0,0 +1,40 @@
const models = require('vn-loopback/server/server').models;
describe('zone updateExclusionGeo()', () => {
it(`should show an error when location isn't selected`, async() => {
const tx = await models.Zone.beginTransaction({});
try {
const options = {transaction: tx};
const zoneId = 1;
const geoIds = [];
await models.Zone.updateExclusionGeo(zoneId, geoIds, options);
await tx.rollback();
} catch (e) {
await tx.rollback();
error = e;
}
expect(error.message).toContain(`You must select a location`);
});
it('should delete all exclusion and then create two exclusion by geo for a zone', async() => {
const tx = await models.Zone.beginTransaction({});
try {
const options = {transaction: tx};
const zoneId = 2;
const geoIds = [1, 2];
const result = await models.Zone.updateExclusionGeo(zoneId, geoIds, options);
expect(result.length).toEqual(2);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -0,0 +1,55 @@
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.remoteMethod('updateExclusionGeo', {
description: 'Update the geos excluded from a zone',
accepts: [
{
arg: 'zoneExclusionFk',
type: 'number',
description: 'The zoneExclusion id'
},
{
arg: 'geoIds',
type: ['number'],
description: 'The geos id'
}
],
returns: {
type: 'object',
root: true
},
http: {
path: `/updateExclusionGeo`,
verb: 'POST'
}
});
Self.updateExclusionGeo = async(zoneExclusionFk, geoIds, options) => {
const models = Self.app.models;
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!geoIds[0]) throw new UserError(`You must select a location`);
await models.ZoneExclusionGeo.destroyAll({
zoneExclusionFk: zoneExclusionFk
}, myOptions);
const promises = [];
for (const geoId of geoIds) {
const params = {
zoneExclusionFk: zoneExclusionFk,
geoFk: geoId
};
const deletedZoneExclusionGeos = models.ZoneExclusionGeo.create(params, myOptions);
promises.push(deletedZoneExclusionGeos);
}
return Promise.all(promises);
};
};

View File

@ -23,6 +23,9 @@
"ZoneExclusion": { "ZoneExclusion": {
"dataSource": "vn" "dataSource": "vn"
}, },
"ZoneExclusionGeo": {
"dataSource": "vn"
},
"ZoneGeo": { "ZoneGeo": {
"dataSource": "vn" "dataSource": "vn"
}, },

View File

@ -0,0 +1,21 @@
{
"name": "ZoneExclusionGeo",
"base": "VnModel",
"options": {
"mysql": {
"table": "zoneExclusionGeo"
}
},
"properties": {
"id": {
"id": true,
"type": "number"
},
"zoneExclusionFk": {
"type": "number"
},
"geoFk": {
"type": "number"
}
}
}

View File

@ -8,6 +8,8 @@ module.exports = Self => {
require('../methods/zone/deleteZone')(Self); require('../methods/zone/deleteZone')(Self);
require('../methods/zone/includingExpired')(Self); require('../methods/zone/includingExpired')(Self);
require('../methods/zone/getZoneClosing')(Self); require('../methods/zone/getZoneClosing')(Self);
require('../methods/zone/exclusionGeo')(Self);
require('../methods/zone/updateExclusionGeo')(Self);
Self.validatesPresenceOf('agencyModeFk', { Self.validatesPresenceOf('agencyModeFk', {
message: `Agency cannot be blank` message: `Agency cannot be blank`

View File

@ -75,6 +75,17 @@ class Controller extends Component {
} }
} }
this.geoExclusions = {};
let geoExclusions = value.geoExclusions;
if (geoExclusions) {
for (let geoExclusion of geoExclusions) {
let stamp = toStamp(geoExclusion.dated);
if (!this.geoExclusions[stamp]) this.geoExclusions[stamp] = [];
this.geoExclusions[stamp].push(geoExclusion);
}
}
let events = value.events; let events = value.events;
if (events) { if (events) {
@ -135,11 +146,13 @@ class Controller extends Component {
onSelection($event, $days, $type, $weekday) { onSelection($event, $days, $type, $weekday) {
let $events = []; let $events = [];
let $exclusions = []; let $exclusions = [];
let $geoExclusions = [];
for (let day of $days) { for (let day of $days) {
let stamp = day.getTime(); let stamp = day.getTime();
$events = $events.concat(this.days[stamp] || []); $events = $events.concat(this.days[stamp] || []);
$exclusions = $exclusions.concat(this.exclusions[stamp] || []); $exclusions = $exclusions.concat(this.exclusions[stamp] || []);
$geoExclusions = $geoExclusions.concat(this.geoExclusions[stamp] || []);
} }
this.emit('selection', { this.emit('selection', {
@ -148,19 +161,23 @@ class Controller extends Component {
$type, $type,
$weekday, $weekday,
$events, $events,
$exclusions $exclusions,
$geoExclusions
}); });
} }
hasEvents(day) { hasEvents(day) {
let stamp = day.getTime(); let stamp = day.getTime();
return this.days[stamp] || this.exclusions[stamp]; return this.days[stamp] || this.exclusions[stamp] || this.geoExclusions[stamp];
} }
getClass(day) { getClass(day) {
let stamp = day.getTime(); let stamp = day.getTime();
return this.exclusions[stamp] && !this.days[stamp] if (this.geoExclusions[stamp])
? 'excluded' : ''; return 'geoExcluded';
else if (this.exclusions[stamp])
return 'excluded';
else return '';
} }
} }
Controller.$inject = ['$element', '$scope', 'vnWeekDays']; Controller.$inject = ['$element', '$scope', 'vnWeekDays'];

View File

@ -15,6 +15,7 @@ describe('component vnZoneCalendar', () => {
controller.zone = {id: 1}; controller.zone = {id: 1};
controller.days = []; controller.days = [];
controller.exclusions = []; controller.exclusions = [];
controller.geoExclusions = [];
})); }));
describe('date() setter', () => { describe('date() setter', () => {
@ -57,7 +58,7 @@ describe('component vnZoneCalendar', () => {
}); });
describe('data() setter', () => { describe('data() setter', () => {
it('should set the events and exclusions and then call the refreshEvents() method', () => { it('should set the events, exclusions and geoExclusions and then call the refreshEvents() method', () => {
jest.spyOn(controller, 'refreshEvents').mockReturnThis(); jest.spyOn(controller, 'refreshEvents').mockReturnThis();
controller.data = { controller.data = {
@ -66,13 +67,17 @@ describe('component vnZoneCalendar', () => {
}], }],
events: [{ events: [{
dated: new Date() dated: new Date()
}] }],
geoExclusions: [{
dated: new Date()
}],
}; };
expect(controller.refreshEvents).toHaveBeenCalledWith(); expect(controller.refreshEvents).toHaveBeenCalledWith();
expect(controller.events).toBeDefined(); expect(controller.events).toBeDefined();
expect(controller.events.length).toEqual(1); expect(controller.events.length).toEqual(1);
expect(controller.exclusions).toBeDefined(); expect(controller.exclusions).toBeDefined();
expect(controller.geoExclusions).toBeDefined();
expect(Object.keys(controller.exclusions).length).toEqual(1); expect(Object.keys(controller.exclusions).length).toEqual(1);
}); });
}); });
@ -122,7 +127,8 @@ describe('component vnZoneCalendar', () => {
$events: [], $events: [],
$exclusions: [], $exclusions: [],
$type: 'day', $type: 'day',
$weekday: 1 $weekday: 1,
$geoExclusions: [],
} }
); );
}); });
@ -151,5 +157,16 @@ describe('component vnZoneCalendar', () => {
expect(result).toEqual('excluded'); expect(result).toEqual('excluded');
}); });
it('should return the className "geoExcluded" for a date with geo excluded', () => {
const dated = new Date();
controller.geoExclusions = [];
controller.geoExclusions[dated.getTime()] = true;
const result = controller.getClass(dated);
expect(result).toEqual('geoExcluded');
});
}); });
}); });

View File

@ -33,6 +33,9 @@ vn-zone-calendar {
&.excluded .day-number { &.excluded .day-number {
background-color: $color-alert; background-color: $color-alert;
} }
&.geoExcluded .day-number {
background-color: $color-main;
}
} }
} }
} }

View File

@ -2,7 +2,7 @@
id="calendar" id="calendar"
vn-id="calendar" vn-id="calendar"
data="data" data="data"
on-selection="$ctrl.onSelection($days, $type, $weekday, $events, $exclusions)" on-selection="$ctrl.onSelection($days, $type, $weekday, $events, $exclusions, $geoExclusions)"
on-step="$ctrl.refresh()" on-step="$ctrl.refresh()"
class="vn-w-md"> class="vn-w-md">
</vn-zone-calendar> </vn-zone-calendar>
@ -98,7 +98,7 @@
fixed-bottom-right> fixed-bottom-right>
</vn-float-button> </vn-float-button>
<vn-dialog <vn-dialog
vn-id="dialog" vn-id="includeDialog"
on-response="$ctrl.onIncludeResponse($response)" on-response="$ctrl.onIncludeResponse($response)"
message="{{$ctrl.isNew ? 'Add event' : 'Edit event'}}"> message="{{$ctrl.isNew ? 'Add event' : 'Edit event'}}">
<tpl-body> <tpl-body>
@ -198,3 +198,80 @@
message="This item will be deleted" message="This item will be deleted"
question="Are you sure you want to continue?"> question="Are you sure you want to continue?">
</vn-confirm> </vn-confirm>
<vn-dialog
vn-id="excludeDialog"
on-response="$ctrl.onExcludeResponse($response)"
message="{{$ctrl.isNew ? 'Exclusion' : 'Edit exclusion'}}"
on-open="$ctrl.onSearch($params)"
on-close="$ctrl.resetExclusions()">
<tpl-body>
<vn-date-picker
label="Day"
ng-model="$ctrl.excludeSelected.dated">
</vn-date-picker>
<vn-vertical class="width">
<vn-vertical class="vn-pb-md">
<vn-radio
ng-model="$ctrl.excludeSelected.type"
label="All"
on-change="$ctrl.test()"
val="all">
</vn-radio>
<vn-radio
ng-model="$ctrl.excludeSelected.type"
label="Specific locations"
on-change="$ctrl.onSearch($params)"
val="specificLocations">
</vn-radio>
</vn-vertical>
<vn-crud-model
vn-id="model"
url="Zones/{{$ctrl.$params.id}}/getLeaves"
filter="$ctrl.filter">
</vn-crud-model>
<div ng-if="$ctrl.excludeSelected.type == 'specificLocations'">
<vn-textfield
label="Search"
ng-keydown="$ctrl.onKeyDown($event)"
ng-model="$ctrl.excludeSearch">
<prepend>
<vn-icon icon="search"></vn-icon>
</prepend>
</vn-textfield>
<div class="treeview">
<vn-treeview
vn-id="treeview"
root-label="Locations where it is not distributed"
fetch-func="$ctrl.onFetch($item)"
sort-func="$ctrl.onSort($a, $b)">
<vn-check
ng-model="item.checked"
ng-click="$event.preventDefault()"
on-change="$ctrl.onItemCheck(item.id, value)"
label="{{::item.name}}">
</vn-check>
</vn-treeview>
</div>
</div>
</vn-vertical>
</tpl-body>
<tpl-buttons>
<input
type="button"
response="cancel"
translate-attr="{value: 'Cancel'}"
tabindex="0">
</input>
<input
type="button"
ng-if="!$ctrl.isNew"
response="delete"
translate-attr="{value: 'Delete'}"
tabindex="0">
</input>
<button response="accept">
<span ng-if="$ctrl.isNew" translate>Add</span>
<span ng-if="!$ctrl.isNew" translate>Save</span>
</button>
</tpl-buttons>
</vn-dialog>

View File

@ -1,5 +1,6 @@
import ngModule from '../module'; import ngModule from '../module';
import Section from 'salix/components/section'; import Section from 'salix/components/section';
import './style.scss';
class Controller extends Section { class Controller extends Section {
constructor($element, $, vnWeekDays) { constructor($element, $, vnWeekDays) {
@ -20,6 +21,16 @@ class Controller extends Section {
return `Zones/${this.$params.id}/exclusions`; return `Zones/${this.$params.id}/exclusions`;
} }
get checked() {
const geos = this.$.model.data || [];
const checkedLines = [];
for (let geo of geos) {
if (geo.checked)
checkedLines.push(geo);
}
return checkedLines;
}
refresh() { refresh() {
this.$.data = null; this.$.data = null;
this.$.$applyAsync(() => { this.$.$applyAsync(() => {
@ -48,33 +59,56 @@ class Controller extends Section {
: this.$t('Everyday'); : this.$t('Everyday');
} }
onSelection(days, type, weekday, events, exclusions) { onSelection(days, type, weekday, events, exclusions, exclusionGeos) {
if (this.editMode == 'include') { if (this.editMode == 'include') {
if (events.length) if (events.length)
this.edit(events[0]); return this.editInclusion(events[0]);
else return this.createInclusion(type, days, weekday);
this.create(type, days, weekday); } else if (this.editMode == 'exclude') {
} else { if (exclusions.length || exclusionGeos.length)
if (exclusions.length) return this.editExclusion(exclusions[0] || {}, exclusionGeos);
this.exclusionDelete(exclusions); return this.createExclusion(days);
else
this.exclusionCreate(days);
} }
} }
editExclusion(exclusion, exclusionGeos) {
this.isNew = false;
this.excludeSelected = angular.copy(exclusion);
this.excludeSelected.type = exclusionGeos.length ?
'specificLocations' : 'all';
this.exclusionGeos = new Set();
if (exclusionGeos.length) {
this.excludeSelected.id = exclusionGeos[0].zoneExclusionFk;
exclusionGeos.forEach(x => this.exclusionGeos.add(x.geoFk));
}
this.$.excludeDialog.show();
}
createExclusion(days) {
this.isNew = true;
this.excludeSelected = {
type: 'all',
dated: days[0]
};
this.exclusionGeos = new Set();
this.$.excludeDialog.show();
}
onEditClick(row, event) { onEditClick(row, event) {
if (event.defaultPrevented) return; if (event.defaultPrevented) return;
this.edit(row); this.editInclusion(row);
} }
edit(row) { editInclusion(row) {
this.isNew = false; this.isNew = false;
this.selected = angular.copy(row); this.selected = angular.copy(row);
this.selected.wdays = this.vnWeekDays.fromSet(row.weekDays); this.selected.wdays = this.vnWeekDays.fromSet(row.weekDays);
this.$.dialog.show(); this.$.includeDialog.show();
} }
create(type, days, weekday) { createInclusion(type, days, weekday) {
this.isNew = true; this.isNew = true;
if (type == 'weekday') { if (type == 'weekday') {
@ -92,7 +126,7 @@ class Controller extends Section {
}; };
} }
this.$.dialog.show(); this.$.includeDialog.show();
} }
onIncludeResponse(response) { onIncludeResponse(response) {
@ -132,6 +166,19 @@ class Controller extends Section {
} }
} }
onExcludeResponse(response) {
const type = this.excludeSelected.type;
switch (response) {
case 'accept': {
if (type == 'all')
return this.exclusionCreate();
return this.exclusionGeoCreate();
}
case 'delete':
return this.exclusionDelete(this.excludeSelected);
}
}
onDeleteClick(id, event) { onDeleteClick(id, event) {
if (event.defaultPrevented) return; if (event.defaultPrevented) return;
event.preventDefault(); event.preventDefault();
@ -149,31 +196,121 @@ class Controller extends Section {
.then(() => this.refresh()); .then(() => this.refresh());
} }
exclusionCreate(days) { exclusionCreate() {
let exclusions = days.map(dated => { const excludeSelected = this.excludeSelected;
return {dated}; const dated = excludeSelected.dated;
let req;
if (this.isNew)
req = this.$http.post(this.exclusionsPath, [{dated}]);
if (!this.isNew)
req = this.$http.put(`${this.exclusionsPath}/${excludeSelected.id}`, {dated});
return req.then(() => {
this.refresh();
}); });
}
this.$http.post(this.exclusionsPath, exclusions) exclusionGeoCreate() {
const excludeSelected = this.excludeSelected;
let req;
const geoIds = [];
this.exclusionGeos.forEach(id => geoIds.push(id));
if (this.isNew) {
const params = {
zoneFk: parseInt(this.$params.id),
date: excludeSelected.dated,
geoIds
};
req = this.$http.post(`Zones/exclusionGeo`, params);
} else {
const params = {
zoneExclusionFk: this.excludeSelected.id,
geoIds
};
req = this.$http.post(`Zones/updateExclusionGeo`, params);
}
return req.then(() => this.refresh());
}
exclusionDelete(exclusion) {
const path = `${this.exclusionsPath}/${exclusion.id}`;
return this.$http.delete(path)
.then(() => this.refresh()); .then(() => this.refresh());
} }
exclusionDelete(exclusions) { set excludeSearch(value) {
let reqs = []; this._excludeSearch = value;
if (!value) this.onSearch();
for (let exclusion of exclusions) {
if (!exclusion.id) continue;
let path = `${this.exclusionsPath}/${exclusion.id}`;
reqs.push(this.$http.delete(path));
} }
this.$q.all(reqs) get excludeSearch() {
.then(() => this.refresh()); return this._excludeSearch;
}
onKeyDown(event) {
if (event.key == 'Enter') {
event.preventDefault();
this.onSearch();
}
}
onSearch() {
const params = {search: this._excludeSearch};
if (this.excludeSelected.type == 'specificLocations') {
this.$.model.applyFilter({}, params).then(() => {
const data = this.$.model.data;
this.getChecked(data);
this.$.treeview.data = data;
});
}
}
onFetch(item) {
const params = item ? {parentId: item.id} : null;
return this.$.model.applyFilter({}, params).then(() => {
const data = this.$.model.data;
this.getChecked(data);
return data;
});
}
onSort(a, b) {
if (b.selected !== a.selected) {
if (a.selected == null)
return 1;
if (b.selected == null)
return -1;
return b.selected - a.selected;
}
return a.name.localeCompare(b.name);
}
getChecked(data) {
for (let geo of data) {
geo.checked = this.exclusionGeos.has(geo.id);
if (geo.childs) this.getChecked(geo.childs);
}
}
onItemCheck(geoId, checked) {
if (checked)
this.exclusionGeos.add(geoId);
else
this.exclusionGeos.delete(geoId);
} }
} }
Controller.$inject = ['$element', '$scope', 'vnWeekDays']; Controller.$inject = ['$element', '$scope', 'vnWeekDays'];
ngModule.vnComponent('vnZoneEvents', { ngModule.vnComponent('vnZoneEvents', {
template: require('./index.html'), template: require('./index.html'),
controller: Controller controller: Controller,
bindings: {
zone: '<'
},
require: {
card: '^vnZoneCard'
}
}); });

View File

@ -1,4 +1,5 @@
import './index'; import './index';
import crudModel from 'core/mocks/crud-model';
describe('component vnZoneEvents', () => { describe('component vnZoneEvents', () => {
let $scope; let $scope;
@ -34,7 +35,8 @@ describe('component vnZoneEvents', () => {
const query = `Zones/getEventsFiltered?ended=${date}&started=${date}&zoneFk=${params.zoneFk}`; const query = `Zones/getEventsFiltered?ended=${date}&started=${date}&zoneFk=${params.zoneFk}`;
const response = { const response = {
events: 'myEvents', events: 'myEvents',
exclusions: 'myExclusions' exclusions: 'myExclusions',
geoExclusions: 'myGeoExclusions',
}; };
$httpBackend.whenGET(query).respond(response); $httpBackend.whenGET(query).respond(response);
controller.refresh(); controller.refresh();
@ -48,71 +50,129 @@ describe('component vnZoneEvents', () => {
}); });
describe('onSelection()', () => { describe('onSelection()', () => {
it('should call the edit() method', () => { it('should call the editInclusion() method', () => {
jest.spyOn(controller, 'edit').mockReturnThis(); jest.spyOn(controller, 'editInclusion').mockReturnThis();
const weekday = {}; const weekday = {};
const days = []; const days = [];
const type = 'EventType'; const type = 'EventType';
const events = [{name: 'Event'}]; const events = [{name: 'Event'}];
const exclusions = []; const exclusions = [];
const exclusionsGeo = [];
controller.editMode = 'include'; controller.editMode = 'include';
controller.onSelection(days, type, weekday, events, exclusions); controller.onSelection(days, type, weekday, events, exclusions, exclusionsGeo);
expect(controller.edit).toHaveBeenCalledWith({name: 'Event'}); expect(controller.editInclusion).toHaveBeenCalledWith({name: 'Event'});
}); });
it('should call the create() method', () => { it('should call the createInclusion() method', () => {
jest.spyOn(controller, 'create').mockReturnThis(); jest.spyOn(controller, 'createInclusion').mockReturnThis();
const weekday = {dated: new Date()}; const weekday = {dated: new Date()};
const days = [weekday]; const days = [weekday];
const type = 'EventType'; const type = 'EventType';
const events = []; const events = [];
const exclusions = []; const exclusions = [];
const exclusionsGeo = [];
controller.editMode = 'include'; controller.editMode = 'include';
controller.onSelection(days, type, weekday, events, exclusions); controller.onSelection(days, type, weekday, events, exclusions, exclusionsGeo);
expect(controller.create).toHaveBeenCalledWith(type, days, weekday); expect(controller.createInclusion).toHaveBeenCalledWith(type, days, weekday);
}); });
it('should call the exclusionDelete() method', () => { it('should call the editExclusion() method with exclusions', () => {
jest.spyOn(controller, 'exclusionDelete').mockReturnThis(); jest.spyOn(controller, 'editExclusion').mockReturnThis();
const weekday = {}; const weekday = {};
const days = []; const days = [];
const type = 'EventType'; const type = 'EventType';
const events = []; const events = [];
const exclusions = [{id: 1}]; const exclusions = [{name: 'Exclusion'}];
controller.editMode = 'delete'; const exclusionsGeo = [];
controller.onSelection(days, type, weekday, events, exclusions); controller.editMode = 'exclude';
controller.onSelection(days, type, weekday, events, exclusions, exclusionsGeo);
expect(controller.exclusionDelete).toHaveBeenCalledWith(exclusions); expect(controller.editExclusion).toHaveBeenCalled();
}); });
it('should call the exclusionCreate() method', () => { it('should call the editExclusion() method with exclusionsGeo', () => {
jest.spyOn(controller, 'exclusionCreate').mockReturnThis(); jest.spyOn(controller, 'editExclusion').mockReturnThis();
const weekday = {};
const days = [];
const type = 'EventType';
const events = [];
const exclusions = [];
const exclusionsGeo = [{name: 'GeoExclusion'}];
controller.editMode = 'exclude';
controller.onSelection(days, type, weekday, events, exclusions, exclusionsGeo);
expect(controller.editExclusion).toHaveBeenCalled();
});
it('should call the createExclusion() method', () => {
jest.spyOn(controller, 'createExclusion').mockReturnThis();
const weekday = {}; const weekday = {};
const days = [{dated: new Date()}]; const days = [{dated: new Date()}];
const type = 'EventType'; const type = 'EventType';
const events = []; const events = [];
const exclusions = []; const exclusions = [];
controller.editMode = 'delete'; const exclusionsGeo = [];
controller.onSelection(days, type, weekday, events, exclusions); controller.editMode = 'exclude';
controller.onSelection(days, type, weekday, events, exclusions, exclusionsGeo);
expect(controller.exclusionCreate).toHaveBeenCalledWith(days); expect(controller.createExclusion).toHaveBeenCalledWith(days);
}); });
}); });
describe('create()', () => { describe('editExclusion()', () => {
it('shoud set the selected property and then call the dialog show() method', () => { it('shoud set the excludeSelected.type = "specificLocations" and then call the excludeDialog show() method', () => {
controller.$.dialog = {show: jest.fn()}; controller.$.excludeDialog = {show: jest.fn()};
const exclusionGeos = [{id: 1}];
const exclusions = [];
controller.editExclusion(exclusions, exclusionGeos);
expect(controller.excludeSelected.type).toEqual('specificLocations');
expect(controller.$.excludeDialog.show).toHaveBeenCalledWith();
});
it('shoud set the excludeSelected.type = "all" and then call the excludeDialog show() method', () => {
controller.$.excludeDialog = {show: jest.fn()};
const exclusionGeos = [];
const exclusions = [{id: 1}];
controller.editExclusion(exclusions, exclusionGeos);
expect(controller.excludeSelected.type).toEqual('all');
expect(controller.$.excludeDialog.show).toHaveBeenCalledWith();
});
});
describe('createExclusion()', () => {
it('shoud set the excludeSelected property and then call the excludeDialog show() method', () => {
controller.$.excludeDialog = {show: jest.fn()};
const days = [new Date()];
controller.createExclusion(days);
expect(controller.excludeSelected).toBeDefined();
expect(controller.isNew).toBeTruthy();
expect(controller.$.excludeDialog.show).toHaveBeenCalledWith();
});
});
describe('createInclusion()', () => {
it('shoud set the selected property and then call the includeDialog show() method', () => {
controller.$.includeDialog = {show: jest.fn()};
const type = 'weekday'; const type = 'weekday';
const days = [new Date()]; const days = [new Date()];
const weekday = 1; const weekday = 1;
controller.create(type, days, weekday); controller.createInclusion(type, days, weekday);
const selection = controller.selected; const selection = controller.selected;
const firstWeekday = selection.wdays[weekday]; const firstWeekday = selection.wdays[weekday];
@ -120,23 +180,23 @@ describe('component vnZoneEvents', () => {
expect(selection.type).toEqual('indefinitely'); expect(selection.type).toEqual('indefinitely');
expect(firstWeekday).toBeTruthy(); expect(firstWeekday).toBeTruthy();
expect(controller.isNew).toBeTruthy(); expect(controller.isNew).toBeTruthy();
expect(controller.$.dialog.show).toHaveBeenCalledWith(); expect(controller.$.includeDialog.show).toHaveBeenCalledWith();
}); });
it('shoud set the selected property with the first day and then call the dialog show() method', () => { it('shoud set the selected property with the first day and then call the includeDialog show() method', () => {
controller.$.dialog = {show: jest.fn()}; controller.$.includeDialog = {show: jest.fn()};
const type = 'nonListedType'; const type = 'nonListedType';
const days = [new Date()]; const days = [new Date()];
const weekday = 1; const weekday = 1;
controller.create(type, days, weekday); controller.createInclusion(type, days, weekday);
const selection = controller.selected; const selection = controller.selected;
expect(selection.type).toEqual('day'); expect(selection.type).toEqual('day');
expect(selection.dated).toEqual(days[0]); expect(selection.dated).toEqual(days[0]);
expect(controller.isNew).toBeTruthy(); expect(controller.isNew).toBeTruthy();
expect(controller.$.dialog.show).toHaveBeenCalledWith(); expect(controller.$.includeDialog.show).toHaveBeenCalledWith();
}); });
}); });
@ -180,6 +240,35 @@ describe('component vnZoneEvents', () => {
}); });
}); });
describe('onExcludeResponse()', () => {
it('should call the exclusionCreate() method', () => {
jest.spyOn(controller, 'exclusionCreate').mockReturnThis();
controller.excludeSelected = {type: 'all'};
controller.onExcludeResponse('accept');
expect(controller.exclusionCreate).toHaveBeenCalledWith();
});
it('should call the exclusionGeoCreate() method', () => {
jest.spyOn(controller, 'exclusionGeoCreate').mockReturnThis();
controller.excludeSelected = {type: 'specificLocations'};
controller.onExcludeResponse('accept');
expect(controller.exclusionGeoCreate).toHaveBeenCalledWith();
});
it('should call the exclusionDelete() method', () => {
jest.spyOn(controller, 'exclusionDelete').mockReturnThis();
controller.excludeSelected = {id: 1, type: 'all'};
controller.onExcludeResponse('delete');
expect(controller.exclusionDelete).toHaveBeenCalledWith(controller.excludeSelected);
});
});
describe('onDeleteResponse()', () => { describe('onDeleteResponse()', () => {
it('shoud make an HTTP DELETE query and then call the refresh() method', () => { it('shoud make an HTTP DELETE query and then call the refresh() method', () => {
jest.spyOn(controller, 'refresh').mockReturnThis(); jest.spyOn(controller, 'refresh').mockReturnThis();
@ -197,9 +286,10 @@ describe('component vnZoneEvents', () => {
it('shoud make an HTTP POST query and then call the refresh() method', () => { it('shoud make an HTTP POST query and then call the refresh() method', () => {
jest.spyOn(controller, 'refresh').mockReturnThis(); jest.spyOn(controller, 'refresh').mockReturnThis();
const dates = [new Date()]; controller.excludeSelected = {};
controller.isNew = true;
$httpBackend.expect('POST', `Zones/1/exclusions`).respond({id: 1}); $httpBackend.expect('POST', `Zones/1/exclusions`).respond({id: 1});
controller.exclusionCreate(dates); controller.exclusionCreate();
$httpBackend.flush(); $httpBackend.flush();
expect(controller.refresh).toHaveBeenCalledWith(); expect(controller.refresh).toHaveBeenCalledWith();
@ -210,25 +300,41 @@ describe('component vnZoneEvents', () => {
it('shoud make an HTTP DELETE query once and then call the refresh() method', () => { it('shoud make an HTTP DELETE query once and then call the refresh() method', () => {
jest.spyOn(controller, 'refresh').mockReturnThis(); jest.spyOn(controller, 'refresh').mockReturnThis();
const exclusions = [{id: 1}]; const exclusions = {id: 1};
const firstExclusionId = 1; const firstExclusionId = 1;
$httpBackend.when('DELETE', `Zones/1/exclusions/${firstExclusionId}`).respond(200); $httpBackend.expectDELETE(`Zones/1/exclusions/${firstExclusionId}`).respond(200);
controller.exclusionDelete(exclusions); controller.exclusionDelete(exclusions);
$httpBackend.flush(); $httpBackend.flush();
expect(controller.refresh).toHaveBeenCalledWith(); expect(controller.refresh).toHaveBeenCalledWith();
}); });
});
it('shoud make an HTTP DELETE query for every event and then call the refresh() method', () => { describe('onSearch()', () => {
jest.spyOn(controller, 'refresh').mockReturnThis(); it('should call the applyFilter() method and then set the data', () => {
jest.spyOn(controller.$http, 'delete').mockReturnValue(200); jest.spyOn(controller, 'getChecked').mockReturnValue([1, 2, 3]);
const exclusions = [{id: 1}, {id: 2}, {id: 3}, {id: 4}]; controller.$.treeview = {};
controller.exclusionDelete(exclusions); controller.$.model = crudModel;
$scope.$apply(); controller.excludeSelected = {type: 'specificLocations'};
controller._excludeSearch = 'es';
expect(controller.$http.delete).toHaveBeenCalledTimes(4); controller.onSearch();
expect(controller.refresh).toHaveBeenCalledWith(); const treeviewData = controller.$.treeview.data;
expect(treeviewData).toBeDefined();
expect(treeviewData.length).toEqual(3);
});
});
describe('onFetch()', () => {
it('should call the applyFilter() method and then return the model data', () => {
jest.spyOn(controller, 'getChecked').mockReturnValue([1, 2, 3]);
controller.$.model = crudModel;
const result = controller.onFetch();
expect(result.length).toEqual(3);
}); });
}); });
}); });

View File

@ -4,3 +4,7 @@ Exclude: Excluir
Events: Eventos Events: Eventos
Add event: Añadir evento Add event: Añadir evento
Edit event: Editar evento Edit event: Editar evento
All: Todo
Specific locations: Localizaciones concretas
Locations where it is not distributed: Localizaciones en las que no se reparte
You must select a location: Debes seleccionar una localización

View File

@ -0,0 +1,11 @@
@import "variables";
.width{
width: 600px
}
.treeview{
max-height: 300px;
overflow: auto;
}

View File

@ -1,5 +1,6 @@
@import "variables"; @import "variables";
vn-zone-location {
vn-treeview-child { vn-treeview-child {
.content > .vn-check:not(.indeterminate):not(.checked) { .content > .vn-check:not(.indeterminate):not(.checked) {
color: $color-alert; color: $color-alert;
@ -17,3 +18,4 @@ vn-treeview-child {
} }
} }
} }
}

View File

@ -85,10 +85,13 @@
"description": "Warehouses" "description": "Warehouses"
}, },
{ {
"url": "/events", "url": "/events?q",
"state": "zone.card.events", "state": "zone.card.events",
"component": "vn-zone-events", "component": "vn-zone-events",
"description": "Calendar" "description": "Calendar",
"params": {
"zone": "$ctrl.zone"
}
}, },
{ {
"url": "/location?q", "url": "/location?q",

View File

@ -12,7 +12,7 @@ module.exports = {
shippedFrom: this.shippedStart, shippedFrom: this.shippedStart,
continent: this.continent, continent: this.continent,
id: this.id, id: this.id,
agencyFk: this.agencyFk, agencyModeFk: this.agencyModeFk,
warehouseInFk: this.warehouseInFk, warehouseInFk: this.warehouseInFk,
warehouseOutFk: this.warehouseOutFk, warehouseOutFk: this.warehouseOutFk,
totalEntries: this.totalEntries, totalEntries: this.totalEntries,
@ -68,7 +68,7 @@ module.exports = {
return {'t.ref': {like: `%${value}%`}}; return {'t.ref': {like: `%${value}%`}};
case 'id': case 'id':
return `t.id = ${value}`; return `t.id = ${value}`;
case 'agencyFk': case 'agencyModeFk':
return `am.id = ${value}`; return `am.id = ${value}`;
case 'warehouseOutFk': case 'warehouseOutFk':
return `wo.id = ${value}`; return `wo.id = ${value}`;
@ -101,7 +101,7 @@ module.exports = {
'continent', 'continent',
'ref', 'ref',
'id', 'id',
'agencyFk', 'agencyModeFk',
'warehouseOutFk', 'warehouseOutFk',
'warehouseInFk', 'warehouseInFk',
'totalEntries', 'totalEntries',

Some files were not shown because too many files have changed in this diff Show More