Merge branch 'master' into hotifx-loadDataDepartment
gitea/salix/pipeline/head This commit looks good Details

This commit is contained in:
Alex Moreno 2023-08-01 12:12:17 +00:00
commit b8780dfbbf
107 changed files with 2532 additions and 625 deletions

View File

@ -5,6 +5,22 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [2330.01] - 2023-07-27
### Added
- (Artículos -> Vista Previa) Añadido campo "Plástico reciclado"
- (Rutas -> Troncales) Nueva sección
- (Tickets -> Opciones) Opción establecer peso
- (Clientes -> SMS) Nueva sección
### Changed
- (General -> Iconos) Añadidos nuevos iconos
- (Clientes -> Razón social) Permite crear clientes con la misma razón social según el país
### Fixed
## [2328.01] - 2023-07-13
### Added

View File

@ -22,6 +22,9 @@
},
"isUeeMember": {
"type": "boolean"
},
"isSocialNameUnique": {
"type": "boolean"
}
},
"relations": {
@ -39,4 +42,4 @@
"permission": "ALLOW"
}
]
}
}

View File

View File

@ -0,0 +1,15 @@
CREATE TABLE `vn`.`clientSms` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`clientFk` int(11) NOT NULL,
`smsFk` mediumint(8) unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `clientSms_FK` (`clientFk`),
KEY `clientSms_FK_1` (`smsFk`),
CONSTRAINT `clientSms_FK` FOREIGN KEY (`clientFk`) REFERENCES `client` (`id`) ON UPDATE CASCADE,
CONSTRAINT `clientSms_FK_1` FOREIGN KEY (`smsFk`) REFERENCES `sms` (`id`) ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('ClientSms', 'find', 'READ', 'ALLOW', 'ROLE', 'employee'),
('ClientSms', 'create', 'WRITE', 'ALLOW', 'ROLE', 'employee');

View File

@ -0,0 +1,3 @@
INSERT INTO `salix`.`ACL` (`model`,`property`,`accessType`,`permission`,`principalId`)
VALUES
('Vehicle','sorted','WRITE','ALLOW','employee');

View File

@ -0,0 +1,2 @@
ALTER TABLE `vn`.`item` ADD recycledPlastic INT NULL;
ALTER TABLE `vn`.`item` ADD nonRecycledPlastic INT NULL;

View File

@ -0,0 +1,64 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`itemShelving_inventory`(vParkingFromFk VARCHAR(8), vParkingToFk VARCHAR(8))
BEGIN
/**
* Devuelve un listado de ubicaciones a revisar
*
* @param vParkingFromFk Parking de partida, identificador de parking
* @param vParkingToFk Parking de llegada, identificador de parking
*/
DECLARE vSectorFk INT;
DECLARE vPickingOrderFrom INT;
DECLARE vPickingOrderTo INT;
SELECT p.sectorFk, p.pickingOrder INTO vSectorFk, vPickingOrderFrom
FROM parking p
WHERE p.code = vParkingFromFk COLLATE 'utf8mb3_general_ci';
SELECT p.pickingOrder INTO vPickingOrderTo
FROM parking p
WHERE p.code = vParkingToFk COLLATE 'utf8mb3_general_ci';
CALL visible_getMisfit(vSectorFk);
SELECT ish.id,
p.pickingOrder,
p.code parking,
ish.shelvingFk,
ish.itemFk,
i.longName,
ish.visible,
p.sectorFk,
it.workerFk buyer,
CONCAT('http:',ic.url, '/catalog/1600x900/',i.image) urlImage,
ish.isChecked,
CASE
WHEN s.notPrepared > sm.parked THEN 0
WHEN sm.visible > sm.parked THEN 1
ELSE 2
END priority
FROM itemShelving ish
JOIN item i ON i.id = ish.itemFk
JOIN itemType it ON it.id = i.typeFk
JOIN tmp.stockMisfit sm ON sm.itemFk = ish.itemFk
JOIN shelving sh ON sh.code = ish.shelvingFk
JOIN parking p ON p.id = sh.parkingFk
JOIN (SELECT s.itemFk, sum(s.quantity) notPrepared
FROM sale s
JOIN ticket t ON t.id = s.ticketFk
JOIN warehouse w ON w.id = t.warehouseFk
JOIN config c ON c.mainWarehouseFk = w.id
WHERE t.shipped BETWEEN util.VN_CURDATE()
AND util.dayEnd(util.VN_CURDATE())
AND s.isPicked = FALSE
GROUP BY s.itemFk) s ON s.itemFk = i.id
JOIN hedera.imageConfig ic
WHERE p.pickingOrder BETWEEN vPickingOrderFrom AND vPickingOrderTo
AND p.sectorFk = vSectorFk
ORDER BY p.pickingOrder;
END$$
DELIMITER ;

View File

@ -0,0 +1,2 @@
ALTER TABLE `vn`.`country`
ADD COLUMN `isSocialNameUnique` tinyint(1) NOT NULL DEFAULT 1;

View File

@ -0,0 +1,8 @@
ALTER TABLE `vn`.`roadmap` COMMENT='Troncales diarios que se contratan';
ALTER TABLE `vn`.`roadmap` ADD price decimal(10,2) NULL;
ALTER TABLE `vn`.`roadmap` ADD driverName varchar(45) NULL;
ALTER TABLE `vn`.`roadmap` ADD name varchar(45) NOT NULL;
ALTER TABLE `vn`.`roadmap` CHANGE name name varchar(45) CHARACTER SET utf8mb3 COLLATE utf8mb3_unicode_ci NOT NULL AFTER id;
ALTER TABLE `vn`.`roadmap` MODIFY COLUMN etd datetime NOT NULL;
ALTER TABLE `vn`.`expeditionTruck` COMMENT='Distintas paradas que hacen los trocales';

View File

@ -0,0 +1,6 @@
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('Roadmap', '*', '*', 'ALLOW', 'ROLE', 'palletizerBoss'),
('Roadmap', '*', '*', 'ALLOW', 'ROLE', 'productionBoss'),
('ExpeditionTruck', '*', '*', 'ALLOW', 'ROLE', 'palletizerBoss'),
('ExpeditionTruck', '*', '*', 'ALLOW', 'ROLE', 'productionBoss');

View File

@ -0,0 +1,7 @@
UPDATE `vn`.`ticket` t
JOIN `vn`.`ticketObservation` o ON o.ticketFk = t.id
SET t.weight = cast(REPLACE(o.description, ',', '.') as decimal(10,2))
WHERE o.observationTypeFk = 6;
DELETE FROM `vn`.`ticketObservation` WHERE observationTypeFk = 6;
DELETE FROM `vn`.`observationType` WHERE id = 6;

View File

@ -37,7 +37,7 @@ ALTER TABLE `vn`.`ticket` AUTO_INCREMENT = 1;
INSERT INTO `salix`.`AccessToken` (`id`, `ttl`, `created`, `userId`)
VALUES
('DEFAULT_TOKEN', '1209600', util.VN_CURDATE(), 66);
('DEFAULT_TOKEN', '1209600', CURDATE(), 66);
INSERT INTO `salix`.`printConfig` (`id`, `itRecipient`, `incidencesEmail`)
VALUES
@ -710,40 +710,40 @@ INSERT INTO `vn`.`route`(`id`, `time`, `workerFk`, `created`, `vehicleFk`, `agen
(6, NULL, 57, util.VN_CURDATE(), 5, 7, 'sixth route', 1.7, 60, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 3),
(7, NULL, 57, util.VN_CURDATE(), 6, 8, 'seventh route', 0, 70, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 5);
INSERT INTO `vn`.`ticket`(`id`, `priority`, `agencyModeFk`,`warehouseFk`,`routeFk`, `shipped`, `landed`, `clientFk`,`nickname`, `addressFk`, `refFk`, `isDeleted`, `zoneFk`, `zonePrice`, `zoneBonus`, `created`)
INSERT INTO `vn`.`ticket`(`id`, `priority`, `agencyModeFk`,`warehouseFk`,`routeFk`, `shipped`, `landed`, `clientFk`,`nickname`, `addressFk`, `refFk`, `isDeleted`, `zoneFk`, `zonePrice`, `zoneBonus`, `created`, `weight`)
VALUES
(1 , 3, 1, 1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -1 MONTH), INTERVAL +1 DAY), 1101, 'Bat cave', 121, NULL, 0, 1, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH)),
(2 , 1, 1, 1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -1 MONTH), INTERVAL +1 DAY), 1104, 'Stark tower', 124, NULL, 0, 1, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH)),
(3 , 1, 7, 1, 6, DATE_ADD(util.VN_CURDATE(), INTERVAL -2 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -2 MONTH), INTERVAL +1 DAY), 1104, 'Stark tower', 124, NULL, 0, 3, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -2 MONTH)),
(4 , 3, 2, 1, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -3 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -3 MONTH), INTERVAL +1 DAY), 1104, 'Stark tower', 124, NULL, 0, 9, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -3 MONTH)),
(5 , 3, 3, 3, 3, DATE_ADD(util.VN_CURDATE(), INTERVAL -4 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -4 MONTH), INTERVAL +1 DAY), 1104, 'Stark tower', 124, NULL, 0, 10, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -4 MONTH)),
(6 , 1, 3, 3, 3, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -1 MONTH), INTERVAL +1 DAY), 1101, 'Mountain Drive Gotham', 1, NULL, 0, 10, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH)),
(7 , NULL, 7, 1, 6, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1101, 'Mountain Drive Gotham', 1, NULL, 0, 3, 5, 1, util.VN_CURDATE()),
(8 , NULL, 7, 1, 6, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1101, 'Bat cave', 121, NULL, 0, 3, 5, 1, util.VN_CURDATE()),
(9 , NULL, 7, 1, 6, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1104, 'Stark tower', 124, NULL, 0, 3, 5, 1, util.VN_CURDATE()),
(10, 1, 1, 5, 1, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1102, 'Ingram Street', 2, NULL, 0, 1, 5, 1, util.VN_CURDATE()),
(11, 1, 7, 1, 6, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1102, 'NY roofs', 122, NULL, 0, 3, 5, 1, util.VN_CURDATE()),
(12, 1, 8, 1, 1, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, util.VN_CURDATE()),
(13, 1, 7, 1, 6, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1103, 'Phone Box', 123, NULL, 0, 3, 5, 1, util.VN_CURDATE()),
(14, 1, 2, 1, NULL, util.VN_CURDATE(), util.VN_CURDATE(), 1104, 'Malibu Point', 4, NULL, 0, 9, 5, 1, util.VN_CURDATE()),
(15, 1, 7, 1, 6, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1105, 'An incredibly long alias for testing purposes', 125, NULL, 0, 3, 5, 1, util.VN_CURDATE()),
(16, 1, 7, 1, 6, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1106, 'Many Places', 126, NULL, 0, 3, 5, 1, util.VN_CURDATE()),
(17, 1, 7, 2, 6, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1106, 'Many Places', 126, NULL, 0, 3, 5, 1, util.VN_CURDATE()),
(18, 1, 4, 4, 4, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1108, 'Cerebro', 128, NULL, 0, 12, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL +12 HOUR)),
(19, 1, 5, 5, NULL, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1109, 'Somewhere in Thailand', 129, NULL, 1, NULL, 5, 1, util.VN_CURDATE()),
(20, 1, 5, 5, 3, DATE_ADD(util.VN_CURDATE(), INTERVAL +1 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL +1 MONTH), INTERVAL +1 DAY), 1109, 'Somewhere in Thailand', 129, NULL, 0, 13, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL +1 MONTH)),
(21, NULL, 5, 5, 5, DATE_ADD(util.VN_CURDATE(), INTERVAL +1 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL +1 MONTH), INTERVAL +1 DAY), 1109, 'Somewhere in Holland', 102, NULL, 0, 13, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL +1 MONTH)),
(22, NULL, 5, 5, 5, DATE_ADD(util.VN_CURDATE(), INTERVAL +1 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL +1 MONTH), INTERVAL +1 DAY), 1109, 'Somewhere in Japan', 103, NULL, 0, 13, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL +1 MONTH)),
(23, NULL, 8, 1, 7, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1101, 'address 21', 121, NULL, 0, 5, 5, 1, util.VN_CURDATE()),
(24 ,NULL, 8, 1, 7, util.VN_CURDATE(), util.VN_CURDATE(), 1101, 'Bruce Wayne', 1, NULL, 0, 5, 5, 1, util.VN_CURDATE()),
(25 ,NULL, 8, 1, NULL, util.VN_CURDATE(), util.VN_CURDATE(), 1101, 'Bruce Wayne', 1, NULL, 0, 1, 5, 1, util.VN_CURDATE()),
(26 ,NULL, 8, 1, NULL, util.VN_CURDATE(), util.VN_CURDATE(), 1101, 'An incredibly long alias for testing purposes', 1, NULL, 0, 1, 5, 1, util.VN_CURDATE()),
(27 ,NULL, 8, 1, NULL, util.VN_CURDATE(), util.VN_CURDATE(), 1101, 'Wolverine', 1, NULL, 0, 1, 5, 1, util.VN_CURDATE()),
(28, 1, 8, 1, 1, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, util.VN_CURDATE()),
(29, 1, 8, 1, 1, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, util.VN_CURDATE()),
(30, 1, 8, 1, 1, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, util.VN_CURDATE()),
(31, 1, 8, 1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL + 2 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, util.VN_CURDATE()),
(32, 1, 8, 1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL + 2 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, util.VN_CURDATE());
(1 , 3, 1, 1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -1 MONTH), INTERVAL +1 DAY), 1101, 'Bat cave', 121, NULL, 0, 1, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1),
(2 , 1, 1, 1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -1 MONTH), INTERVAL +1 DAY), 1104, 'Stark tower', 124, NULL, 0, 1, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 2),
(3 , 1, 7, 1, 6, DATE_ADD(util.VN_CURDATE(), INTERVAL -2 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -2 MONTH), INTERVAL +1 DAY), 1104, 'Stark tower', 124, NULL, 0, 3, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -2 MONTH), NULL),
(4 , 3, 2, 1, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -3 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -3 MONTH), INTERVAL +1 DAY), 1104, 'Stark tower', 124, NULL, 0, 9, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -3 MONTH), NULL),
(5 , 3, 3, 3, 3, DATE_ADD(util.VN_CURDATE(), INTERVAL -4 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -4 MONTH), INTERVAL +1 DAY), 1104, 'Stark tower', 124, NULL, 0, 10, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -4 MONTH), NULL),
(6 , 1, 3, 3, 3, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -1 MONTH), INTERVAL +1 DAY), 1101, 'Mountain Drive Gotham', 1, NULL, 0, 10, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), NULL),
(7 , NULL, 7, 1, 6, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1101, 'Mountain Drive Gotham', 1, NULL, 0, 3, 5, 1, util.VN_CURDATE(), NULL),
(8 , NULL, 7, 1, 6, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1101, 'Bat cave', 121, NULL, 0, 3, 5, 1, util.VN_CURDATE(), NULL),
(9 , NULL, 7, 1, 6, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1104, 'Stark tower', 124, NULL, 0, 3, 5, 1, util.VN_CURDATE(), NULL),
(10, 1, 1, 5, 1, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1102, 'Ingram Street', 2, NULL, 0, 1, 5, 1, util.VN_CURDATE(), NULL),
(11, 1, 7, 1, 6, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1102, 'NY roofs', 122, NULL, 0, 3, 5, 1, util.VN_CURDATE(), NULL),
(12, 1, 8, 1, 1, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, util.VN_CURDATE(), NULL),
(13, 1, 7, 1, 6, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1103, 'Phone Box', 123, NULL, 0, 3, 5, 1, util.VN_CURDATE(), NULL),
(14, 1, 2, 1, NULL, util.VN_CURDATE(), util.VN_CURDATE(), 1104, 'Malibu Point', 4, NULL, 0, 9, 5, 1, util.VN_CURDATE(), NULL),
(15, 1, 7, 1, 6, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1105, 'An incredibly long alias for testing purposes', 125, NULL, 0, 3, 5, 1, util.VN_CURDATE(), NULL),
(16, 1, 7, 1, 6, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1106, 'Many Places', 126, NULL, 0, 3, 5, 1, util.VN_CURDATE(), NULL),
(17, 1, 7, 2, 6, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1106, 'Many Places', 126, NULL, 0, 3, 5, 1, util.VN_CURDATE(), NULL),
(18, 1, 4, 4, 4, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1108, 'Cerebro', 128, NULL, 0, 12, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL +12 HOUR), NULL),
(19, 1, 5, 5, NULL, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1109, 'Somewhere in Thailand', 129, NULL, 1, NULL, 5, 1, util.VN_CURDATE(), NULL),
(20, 1, 5, 5, 3, DATE_ADD(util.VN_CURDATE(), INTERVAL +1 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL +1 MONTH), INTERVAL +1 DAY), 1109, 'Somewhere in Thailand', 129, NULL, 0, 13, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL +1 MONTH), NULL),
(21, NULL, 5, 5, 5, DATE_ADD(util.VN_CURDATE(), INTERVAL +1 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL +1 MONTH), INTERVAL +1 DAY), 1109, 'Somewhere in Holland', 102, NULL, 0, 13, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL +1 MONTH), NULL),
(22, NULL, 5, 5, 5, DATE_ADD(util.VN_CURDATE(), INTERVAL +1 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL +1 MONTH), INTERVAL +1 DAY), 1109, 'Somewhere in Japan', 103, NULL, 0, 13, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL +1 MONTH), NULL),
(23, NULL, 8, 1, 7, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1101, 'address 21', 121, NULL, 0, 5, 5, 1, util.VN_CURDATE(), NULL),
(24 ,NULL, 8, 1, 7, util.VN_CURDATE(), util.VN_CURDATE(), 1101, 'Bruce Wayne', 1, NULL, 0, 5, 5, 1, util.VN_CURDATE(), NULL),
(25 ,NULL, 8, 1, NULL, util.VN_CURDATE(), util.VN_CURDATE(), 1101, 'Bruce Wayne', 1, NULL, 0, 1, 5, 1, util.VN_CURDATE(), NULL),
(26 ,NULL, 8, 1, NULL, util.VN_CURDATE(), util.VN_CURDATE(), 1101, 'An incredibly long alias for testing purposes', 1, NULL, 0, 1, 5, 1, util.VN_CURDATE(), NULL),
(27 ,NULL, 8, 1, NULL, util.VN_CURDATE(), util.VN_CURDATE(), 1101, 'Wolverine', 1, NULL, 0, 1, 5, 1, util.VN_CURDATE(), NULL),
(28, 1, 8, 1, 1, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, util.VN_CURDATE(), NULL),
(29, 1, 8, 1, 1, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, util.VN_CURDATE(), NULL),
(30, 1, 8, 1, 1, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, util.VN_CURDATE(), NULL),
(31, 1, 8, 1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL + 2 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, util.VN_CURDATE(), NULL),
(32, 1, 8, 1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL + 2 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, util.VN_CURDATE(), NULL);
INSERT INTO `vn`.`ticketObservation`(`id`, `ticketFk`, `observationTypeFk`, `description`)
VALUES
@ -2606,9 +2606,18 @@ INSERT INTO `vn`.`zoneAgencyMode`(`id`, `agencyModeFk`, `zoneFk`)
(3, 6, 5),
(4, 7, 1);
INSERT INTO `vn`.`expeditionTruck` (`id`, `eta`, `description`)
INSERT INTO `vn`.`roadmap` (`id`, `name`, `tractorPlate`, `trailerPlate`, `phone`, `supplierFk`, `etd`, `observations`, `userFk`, `price`, `driverName`)
VALUES
(1, CONCAT(YEAR(DATE_ADD(util.VN_CURDATE(), INTERVAL +3 YEAR))), 'Best truck in fleet');
(1, 'val-algemesi', 'RE-001', 'PO-001', '111111111', 1, util.VN_NOW(), 'this is test observation', 1, 15, 'Batman'),
(2, 'alg-valencia', 'RE-002', 'PO-002', '111111111', 1, util.VN_NOW(), 'test observation', 1, 20, 'Robin'),
(3, 'alz-algemesi', 'RE-003', 'PO-003', '222222222', 2, DATE_ADD(util.VN_NOW(), INTERVAL 2 DAY), 'observations...', 2, 25, 'Driverman');
INSERT INTO `vn`.`expeditionTruck` (`id`, `roadmapFk`, `warehouseFk`, `eta`, `description`, `userFk`)
VALUES
(1, 1, 1, DATE_ADD(util.VN_NOW(), INTERVAL 1 DAY), 'Best truck in fleet', 1),
(2, 1, 2, DATE_ADD(util.VN_NOW(), INTERVAL '1 2' DAY_HOUR), 'Second truck in fleet', 1),
(3, 1, 3, DATE_ADD(util.VN_NOW(), INTERVAL '1 4' DAY_HOUR), 'Third truck in fleet', 1),
(4, 2, 1, DATE_ADD(util.VN_NOW(), INTERVAL 3 DAY), 'Truck red', 1);
INSERT INTO `vn`.`expeditionPallet` (`id`, `truckFk`, `built`, `position`, `isPrint`)
VALUES
@ -2944,3 +2953,8 @@ INSERT INTO `vn`.`invoiceInSerial` (`code`, `description`, `cplusTerIdNifFk`, `t
('E', 'Midgard', 1, 'CEE'),
('R', 'Jotunheim', 1, 'NATIONAL'),
('W', 'Vanaheim', 1, 'WORLD');
INSERT INTO `hedera`.`imageConfig` (`id`, `maxSize`, `useXsendfile`, `url`)
VALUES
(1, 0, 0, 'marvel.com');

View File

@ -77831,7 +77831,7 @@ BEGIN
LEAVE cur1Loop;
END IF;
CALL zone_getLeaves2(vZoneFk, NULL, NULL);
CALL zone_getLeaves(vZoneFk, NULL, NULL, TRUE);
myLoop: LOOP
SET vGeoFk = NULL;
@ -77844,7 +77844,7 @@ BEGIN
LEAVE myLoop;
END IF;
CALL zone_getLeaves2(vZoneFk, vGeoFk, NULL);
CALL zone_getLeaves(vZoneFk, vGeoFk, NULL, TRUE);
UPDATE tmp.zoneNodes
SET isChecked = TRUE
WHERE geoFk = vGeoFk;
@ -78130,55 +78130,58 @@ DELIMITER ;
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
/*!50003 SET sql_mode = 'IGNORE_SPACE,NO_ENGINE_SUBSTITUTION' */ ;
DELIMITER ;;
CREATE DEFINER=`root`@`localhost` PROCEDURE `zone_getLeaves`(vSelf INT, vParentFk INT, vSearch VARCHAR(255))
BEGIN
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`zone_getLeaves`(
vSelf INT,
vParentFk INT,
vSearch VARCHAR(255),
vHasInsert BOOL
)
BEGIN
/**
* Devuelve las ubicaciones incluidas en la ruta y que sean hijos de parentFk.
* @param vSelf Id de la zona
* @param vParentFk Id del geo a calcular
* @param vSearch cadena a buscar
* @param vSearch Cadena a buscar
* @param vHasInsert Indica si inserta en tmp.zoneNodes
* Optional @table tmp.zoneNodes(geoFk, name, parentFk, sons, isChecked, zoneFk)
*/
DECLARE vIsNumber BOOL;
DECLARE vIsSearch BOOL DEFAULT vSearch IS NOT NULL AND vSearch != '';
DECLARE vIsSearch BOOL DEFAULT vSearch IS NOT NULL AND vSearch <> '';
DROP TEMPORARY TABLE IF EXISTS tNodes;
CREATE TEMPORARY TABLE tNodes
CREATE OR REPLACE TEMPORARY TABLE tNodes
(UNIQUE (id))
ENGINE = MEMORY
SELECT id
FROM zoneGeo
SELECT id
FROM zoneGeo
LIMIT 0;
IF vIsSearch THEN
SET vIsNumber = vSearch REGEXP '^[0-9]+$';
INSERT INTO tNodes
SELECT id
SELECT id
FROM zoneGeo
WHERE (vIsNumber AND `name` = vSearch)
OR (!vIsNumber AND `name` LIKE CONCAT('%', vSearch, '%'))
LIMIT 1000;
ELSEIF vParentFk IS NULL THEN
INSERT INTO tNodes
SELECT geoFk
SELECT geoFk
FROM zoneIncluded
WHERE zoneFk = vSelf;
END IF;
IF vParentFk IS NULL THEN
DROP TEMPORARY TABLE IF EXISTS tChilds;
CREATE TEMPORARY TABLE tChilds
CREATE OR REPLACE TEMPORARY TABLE tChilds
(INDEX(id))
ENGINE = MEMORY
SELECT id
FROM tNodes;
SELECT id FROM tNodes;
DROP TEMPORARY TABLE IF EXISTS tParents;
CREATE TEMPORARY TABLE tParents
CREATE OR REPLACE TEMPORARY TABLE tParents
(INDEX(id))
ENGINE = MEMORY
SELECT id
FROM zoneGeo
LIMIT 0;
SELECT id FROM zoneGeo LIMIT 0;
myLoop: LOOP
DELETE FROM tParents;
@ -78186,43 +78189,67 @@ BEGIN
SELECT parentFk id
FROM zoneGeo g
JOIN tChilds c ON c.id = g.id
WHERE g.parentFk IS NOT NULL;
WHERE g.parentFk IS NOT NULL;
INSERT IGNORE INTO tNodes
SELECT id
FROM tParents;
IF ROW_COUNT() = 0 THEN
SELECT id FROM tParents;
IF NOT ROW_COUNT() THEN
LEAVE myLoop;
END IF;
DELETE FROM tChilds;
INSERT INTO tChilds
SELECT id
FROM tParents;
SELECT id FROM tParents;
END LOOP;
DROP TEMPORARY TABLE tChilds, tParents;
END IF;
IF !vIsSearch THEN
IF NOT vIsSearch THEN
INSERT IGNORE INTO tNodes
SELECT id
SELECT id
FROM zoneGeo
WHERE parentFk <=> vParentFk;
END IF;
SELECT g.id,
g.name,
g.parentFk,
g.sons,
isIncluded selected
FROM zoneGeo g
JOIN tNodes n ON n.id = g.id
LEFT JOIN zoneIncluded i ON i.geoFk = g.id AND i.zoneFk = vSelf
ORDER BY `depth`, selected DESC, name;
CREATE OR REPLACE TEMPORARY TABLE tZones
SELECT g.id,
g.name,
g.parentFk,
g.sons,
NOT g.sons OR `type` = 'country' isChecked,
i.isIncluded selected,
g.`depth`,
vSelf
FROM zoneGeo g
JOIN tNodes n ON n.id = g.id
LEFT JOIN zoneIncluded i ON i.geoFk = g.id
AND i.zoneFk = vSelf
ORDER BY g.`depth`, selected DESC, g.name;
DROP TEMPORARY TABLE tNodes;
IF vHasInsert THEN
INSERT IGNORE INTO tmp.zoneNodes(geoFk, name, parentFk, sons, isChecked, zoneFk)
SELECT id,
name,
parentFk,
sons,
isChecked,
vSelf
FROM tZones
WHERE selected
OR (selected IS NULL AND vParentFk IS NOT NULL);
ELSE
SELECT id,
name,
parentFk,
sons,
selected
FROM tZones
ORDER BY `depth`, selected DESC, name;
END IF;
DROP TEMPORARY TABLE tNodes, tZones;
END ;;
DELIMITER ;
/*!50003 SET sql_mode = @saved_sql_mode */ ;
@ -78540,7 +78567,7 @@ BEGIN
INDEX(geoFk))
ENGINE = MEMORY;
CALL zone_getLeaves2(vSelf, NULL , NULL);
CALL zone_getLeaves(vSelf, NULL , NULL, TRUE);
UPDATE tmp.zoneNodes zn
SET isChecked = 0
@ -78553,7 +78580,7 @@ BEGIN
WHERE NOT isChecked
LIMIT 1;
CALL zone_getLeaves2(vSelf, vGeoFk, NULL);
CALL zone_getLeaves(vSelf, vGeoFk, NULL, TRUE);
UPDATE tmp.zoneNodes
SET isChecked = TRUE
WHERE geoFk = vGeoFk;

View File

@ -547,6 +547,7 @@ export default {
moreMenuMakeInvoice: '.vn-menu [name="makeInvoice"]',
moreMenuRegenerateInvoice: '.vn-menu [name="regenerateInvoice"]',
moreMenuChangeShippedHour: '.vn-menu [name="changeShipped"]',
moreMenuSMSOptions: '.vn-menu [name="smsOptions"]',
moreMenuPaymentSMS: '.vn-menu [name="sendPaymentSms"]',
moreMenuSendImportSms: '.vn-menu [name="sendImportSms"]',
SMStext: 'textarea[name="message"]',

View File

@ -124,6 +124,7 @@ describe('Ticket descriptor path', () => {
describe('SMS', () => {
it('should send the payment SMS using the descriptor menu', async() => {
await page.waitToClick(selectors.ticketDescriptor.moreMenu);
await page.waitToClick(selectors.ticketDescriptor.moreMenuSMSOptions);
await page.waitToClick(selectors.ticketDescriptor.moreMenuPaymentSMS);
await page.waitForSelector(selectors.ticketDescriptor.SMStext);
await page.waitPropertyLength(selectors.ticketDescriptor.SMStext, 'value', 128);
@ -134,8 +135,7 @@ describe('Ticket descriptor path', () => {
});
it('should send the import SMS using the descriptor menu', async() => {
await page.waitToClick(selectors.ticketDescriptor.moreMenu);
await page.waitForContentLoaded();
await page.waitToClick(selectors.ticketDescriptor.moreMenuSMSOptions);
await page.waitToClick(selectors.ticketDescriptor.moreMenuSendImportSms);
await page.waitForSelector(selectors.ticketDescriptor.SMStext);
await page.waitPropertyLength(selectors.ticketDescriptor.SMStext, 'value', 144);

View File

@ -1,402 +1,411 @@
@font-face {
font-family: 'salixfont';
src:
url('./salixfont.ttf?wtrl3') format('truetype'),
url('./salixfont.woff?wtrl3') format('woff'),
url('./salixfont.svg?wtrl3#salixfont') format('svg');
font-weight: normal;
font-style: normal;
}
font-family: 'salixfont';
src:
url('./salixfont.ttf?wtrl3') format('truetype'),
url('./salixfont.woff?wtrl3') format('woff'),
url('./salixfont.svg?wtrl3#salixfont') format('svg');
font-weight: normal;
font-style: normal;
}
[class^="icon-"], [class*=" icon-"] {
/* use !important to prevent issues with browser extensions that change fonts */
font-family: 'salixfont' !important;
speak: none;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
[class^="icon-"], [class*=" icon-"] {
/* use !important to prevent issues with browser extensions that change fonts */
font-family: 'salixfont' !important;
speak: none;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
/* Better Font Rendering =========== */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* Better Font Rendering =========== */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-agency-term:before {
content: "\e950";
}
.icon-defaulter:before {
content: "\e94b";
}
.icon-100:before {
content: "\e95a";
}
.icon-clientUnpaid:before {
content: "\e95b";
}
.icon-history:before {
content: "\e968";
}
.icon-Person:before {
content: "\e901";
}
.icon-accessory:before {
content: "\e90a";
}
.icon-account:before {
content: "\e92a";
}
.icon-actions:before {
content: "\e960";
}
.icon-addperson:before {
content: "\e90e";
}
.icon-agency:before {
content: "\e938";
}
.icon-albaran:before {
content: "\e94d";
}
.icon-anonymous:before {
content: "\e930";
}
.icon-apps:before {
content: "\e951";
}
.icon-artificial:before {
content: "\e90b";
}
.icon-attach:before {
content: "\e92e";
}
.icon-barcode:before {
content: "\e971";
}
.icon-basket:before {
content: "\e914";
}
.icon-basketadd:before {
content: "\e913";
}
.icon-bin:before {
content: "\e96f";
}
.icon-botanical:before {
content: "\e972";
}
.icon-bucket:before {
content: "\e97a";
}
.icon-buscaman:before {
content: "\e93b";
}
.icon-buyrequest:before {
content: "\e932";
}
.icon-calc_volum .path1:before {
content: "\e915";
}
.icon-calc_volum .path2:before {
content: "\e916";
margin-left: -1em;
}
.icon-calc_volum .path3:before {
content: "\e917";
margin-left: -1em;
}
.icon-calc_volum .path4:before {
content: "\e918";
margin-left: -1em;
}
.icon-calc_volum .path5:before {
content: "\e919";
margin-left: -1em;
}
.icon-calc_volum .path6:before {
content: "\e91a";
margin-left: -1em;
}
.icon-calendar:before {
content: "\e93d";
}
.icon-catalog:before {
content: "\e937";
}
.icon-claims:before {
content: "\e963";
}
.icon-client:before {
content: "\e928";
}
.icon-clone:before {
content: "\e973";
}
.icon-columnadd:before {
content: "\e954";
}
.icon-columndelete:before {
content: "\e953";
}
.icon-components:before {
content: "\e946";
}
.icon-consignatarios:before {
content: "\e93f";
}
.icon-control:before {
content: "\e949";
}
.icon-credit:before {
content: "\e927";
}
.icon-deletedTicket:before {
content: "\e935";
}
.icon-deleteline:before {
content: "\e955";
}
.icon-delivery:before {
content: "\e939";
}
.icon-deliveryprices:before {
content: "\e91c";
}
.icon-details:before {
content: "\e961";
}
.icon-dfiscales:before {
content: "\e984";
}
.icon-disabled:before {
content: "\e921";
}
.icon-doc:before {
content: "\e977";
}
.icon-entry:before {
content: "\e934";
}
.icon-exit:before {
content: "\e92f";
}
.icon-eye:before {
content: "\e976";
}
.icon-fixedPrice:before {
content: "\e90d";
}
.icon-flower:before {
content: "\e90c";
}
.icon-frozen:before {
content: "\e900";
}
.icon-fruit:before {
content: "\e903";
}
.icon-funeral:before {
content: "\e904";
}
.icon-greenery:before {
content: "\e907";
}
.icon-greuge:before {
content: "\e944";
}
.icon-grid:before {
content: "\e980";
}
.icon-handmade:before {
content: "\e909";
}
.icon-handmadeArtificial:before {
content: "\e902";
}
.icon-headercol:before {
content: "\e958";
}
.icon-info:before {
content: "\e952";
}
.icon-inventory:before {
content: "\e92b";
}
.icon-invoice:before {
content: "\e923";
}
.icon-invoice-in:before {
content: "\e911";
}
.icon-invoice-in-create:before {
content: "\e912";
}
.icon-invoice-out:before {
content: "\e910";
}
.icon-isTooLittle:before {
content: "\e91b";
}
.icon-item:before {
content: "\e956";
}
.icon-languaje:before {
content: "\e926";
}
.icon-lines:before {
content: "\e942";
}
.icon-linesprepaired:before {
content: "\e948";
}
.icon-logout:before {
content: "\e936";
}
.icon-mana:before {
content: "\e96a";
}
.icon-mandatory:before {
content: "\e97b";
}
.icon-net:before {
content: "\e931";
}
.icon-niche:before {
content: "\e96c";
}
.icon-no036:before {
content: "\e920";
}
.icon-noPayMethod:before {
content: "\e905";
}
.icon-notes:before {
content: "\e941";
}
.icon-noweb:before {
content: "\e91f";
}
.icon-onlinepayment:before {
content: "\e91d";
}
.icon-package:before {
content: "\e978";
}
.icon-payment:before {
content: "\e97e";
}
.icon-pbx:before {
content: "\e93c";
}
.icon-pets:before {
content: "\e947";
}
.icon-photo:before {
content: "\e924";
}
.icon-plant:before {
content: "\e908";
}
.icon-polizon:before {
content: "\e95e";
}
.icon-preserved:before {
content: "\e906";
}
.icon-recovery:before {
content: "\e97c";
}
.icon-regentry:before {
content: "\e964";
}
.icon-reserva:before {
content: "\e959";
}
.icon-revision:before {
content: "\e94a";
}
.icon-risk:before {
content: "\e91e";
}
.icon-services:before {
content: "\e94c";
}
.icon-settings:before {
content: "\e979";
}
.icon-shipment-01:before {
content: "\e929";
}
.icon-sign:before {
content: "\e95d";
}
.icon-sms:before {
content: "\e975";
}
.icon-solclaim:before {
content: "\e95f";
}
.icon-solunion:before {
content: "\e94e";
}
.icon-stowaway:before {
content: "\e94f";
}
.icon-splitline:before {
content: "\e93e";
}
.icon-splur:before {
content: "\e970";
}
.icon-supplier:before {
content: "\e925";
}
.icon-supplierfalse:before {
content: "\e90f";
}
.icon-tags:before {
content: "\e96d";
}
.icon-tax:before {
content: "\e940";
}
.icon-thermometer:before {
content: "\e933";
}
.icon-ticket:before {
content: "\e96b";
}
.icon-ticketAdd:before {
content: "\e945";
}
.icon-traceability:before {
content: "\e962";
}
.icon-transaction:before {
content: "\e966";
}
.icon-treatments:before {
content: "\e922";
}
.icon-unavailable:before {
content: "\e92c";
}
.icon-volume:before {
content: "\e96e";
}
.icon-wand:before {
content: "\e93a";
}
.icon-web:before {
content: "\e982";
}
.icon-wiki:before {
content: "\e92d";
}
.icon-worker:before {
content: "\e957";
}
.icon-zone:before {
content: "\e943";
}
.icon-trailer:before {
content: "\e967";
}
.icon-grafana:before {
content: "\e965";
}
.icon-trolley:before {
content: "\e95c";
}
.icon-agency-term:before {
content: "\e950";
}
.icon-defaulter:before {
content: "\e94b";
}
.icon-100:before {
content: "\e95a";
}
.icon-clientUnpaid:before {
content: "\e95b";
}
.icon-history:before {
content: "\e968";
}
.icon-Person:before {
content: "\e901";
}
.icon-accessory:before {
content: "\e90a";
}
.icon-account:before {
content: "\e92a";
}
.icon-actions:before {
content: "\e960";
}
.icon-addperson:before {
content: "\e90e";
}
.icon-agency:before {
content: "\e938";
}
.icon-albaran:before {
content: "\e94d";
}
.icon-anonymous:before {
content: "\e930";
}
.icon-apps:before {
content: "\e951";
}
.icon-artificial:before {
content: "\e90b";
}
.icon-attach:before {
content: "\e92e";
}
.icon-barcode:before {
content: "\e971";
}
.icon-basket:before {
content: "\e914";
}
.icon-basketadd:before {
content: "\e913";
}
.icon-bin:before {
content: "\e96f";
}
.icon-botanical:before {
content: "\e972";
}
.icon-bucket:before {
content: "\e97a";
}
.icon-buscaman:before {
content: "\e93b";
}
.icon-buyrequest:before {
content: "\e932";
}
.icon-calc_volum .path1:before {
content: "\e915";
}
.icon-calc_volum .path2:before {
content: "\e916";
margin-left: -1em;
}
.icon-calc_volum .path3:before {
content: "\e917";
margin-left: -1em;
}
.icon-calc_volum .path4:before {
content: "\e918";
margin-left: -1em;
}
.icon-calc_volum .path5:before {
content: "\e919";
margin-left: -1em;
}
.icon-calc_volum .path6:before {
content: "\e91a";
margin-left: -1em;
}
.icon-calendar:before {
content: "\e93d";
}
.icon-catalog:before {
content: "\e937";
}
.icon-claims:before {
content: "\e963";
}
.icon-client:before {
content: "\e928";
}
.icon-clone:before {
content: "\e973";
}
.icon-columnadd:before {
content: "\e954";
}
.icon-columndelete:before {
content: "\e953";
}
.icon-components:before {
content: "\e946";
}
.icon-consignatarios:before {
content: "\e93f";
}
.icon-control:before {
content: "\e949";
}
.icon-credit:before {
content: "\e927";
}
.icon-deletedTicket:before {
content: "\e935";
}
.icon-deleteline:before {
content: "\e955";
}
.icon-delivery:before {
content: "\e939";
}
.icon-deliveryprices:before {
content: "\e91c";
}
.icon-details:before {
content: "\e961";
}
.icon-dfiscales:before {
content: "\e984";
}
.icon-disabled:before {
content: "\e921";
}
.icon-doc:before {
content: "\e977";
}
.icon-entry:before {
content: "\e934";
}
.icon-exit:before {
content: "\e92f";
}
.icon-eye:before {
content: "\e976";
}
.icon-fixedPrice:before {
content: "\e90d";
}
.icon-flower:before {
content: "\e90c";
}
.icon-frozen:before {
content: "\e900";
}
.icon-fruit:before {
content: "\e903";
}
.icon-funeral:before {
content: "\e904";
}
.icon-greenery:before {
content: "\e907";
}
.icon-greuge:before {
content: "\e944";
}
.icon-grid:before {
content: "\e980";
}
.icon-handmade:before {
content: "\e909";
}
.icon-handmadeArtificial:before {
content: "\e902";
}
.icon-headercol:before {
content: "\e958";
}
.icon-info:before {
content: "\e952";
}
.icon-inventory:before {
content: "\e92b";
}
.icon-invoice:before {
content: "\e923";
}
.icon-invoice-in:before {
content: "\e911";
}
.icon-invoice-in-create:before {
content: "\e912";
}
.icon-invoice-out:before {
content: "\e910";
}
.icon-isTooLittle:before {
content: "\e91b";
}
.icon-item:before {
content: "\e956";
}
.icon-languaje:before {
content: "\e926";
}
.icon-lines:before {
content: "\e942";
}
.icon-linesprepaired:before {
content: "\e948";
}
.icon-logout:before {
content: "\e936";
}
.icon-mana:before {
content: "\e96a";
}
.icon-mandatory:before {
content: "\e97b";
}
.icon-net:before {
content: "\e931";
}
.icon-niche:before {
content: "\e96c";
}
.icon-no036:before {
content: "\e920";
}
.icon-noPayMethod:before {
content: "\e905";
}
.icon-notes:before {
content: "\e941";
}
.icon-noweb:before {
content: "\e91f";
}
.icon-onlinepayment:before {
content: "\e91d";
}
.icon-package:before {
content: "\e978";
}
.icon-payment:before {
content: "\e97e";
}
.icon-pbx:before {
content: "\e93c";
}
.icon-pets:before {
content: "\e947";
}
.icon-photo:before {
content: "\e924";
}
.icon-plant:before {
content: "\e908";
}
.icon-polizon:before {
content: "\e95e";
}
.icon-preserved:before {
content: "\e906";
}
.icon-recovery:before {
content: "\e97c";
}
.icon-regentry:before {
content: "\e964";
}
.icon-reserva:before {
content: "\e959";
}
.icon-revision:before {
content: "\e94a";
}
.icon-risk:before {
content: "\e91e";
}
.icon-services:before {
content: "\e94c";
}
.icon-settings:before {
content: "\e979";
}
.icon-shipment-01:before {
content: "\e929";
}
.icon-sign:before {
content: "\e95d";
}
.icon-sms:before {
content: "\e975";
}
.icon-solclaim:before {
content: "\e95f";
}
.icon-solunion:before {
content: "\e94e";
}
.icon-stowaway:before {
content: "\e94f";
}
.icon-splitline:before {
content: "\e93e";
}
.icon-splur:before {
content: "\e970";
}
.icon-supplier:before {
content: "\e925";
}
.icon-supplierfalse:before {
content: "\e90f";
}
.icon-tags:before {
content: "\e96d";
}
.icon-tax:before {
content: "\e940";
}
.icon-thermometer:before {
content: "\e933";
}
.icon-ticket:before {
content: "\e96b";
}
.icon-ticketAdd:before {
content: "\e945";
}
.icon-traceability:before {
content: "\e962";
}
.icon-transaction:before {
content: "\e966";
}
.icon-treatments:before {
content: "\e922";
}
.icon-unavailable:before {
content: "\e92c";
}
.icon-volume:before {
content: "\e96e";
}
.icon-wand:before {
content: "\e93a";
}
.icon-web:before {
content: "\e982";
}
.icon-wiki:before {
content: "\e92d";
}
.icon-worker:before {
content: "\e957";
}
.icon-zone:before {
content: "\e943";
}

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 162 KiB

After

Width:  |  Height:  |  Size: 173 KiB

View File

@ -95,7 +95,7 @@ module.exports = Self => {
// When claimState has been changed
if (args.claimStateFk) {
const newState = await models.ClaimState.findById(args.claimStateFk, null, options);
const newState = await models.ClaimState.findById(args.claimStateFk, null, myOptions);
if (newState.hasToNotify) {
if (newState.code == 'incomplete')
notifyStateChange(ctx, salesPerson.id, claim, newState.code);

View File

@ -7,7 +7,7 @@ module.exports = Self => {
arg: 'id',
type: 'number',
required: true,
description: 'The ticket id',
description: 'The client id',
http: {source: 'path'}
},
{
@ -33,6 +33,12 @@ module.exports = Self => {
Self.sendSms = async(ctx, id, destination, message) => {
const models = Self.app.models;
const sms = await models.Sms.send(ctx, destination, message);
await models.ClientSms.create({
clientFk: id,
smsFk: sms.id
});
return sms;
};
};

View File

@ -95,6 +95,9 @@
"ClientSample": {
"dataSource": "vn"
},
"ClientSms": {
"dataSource": "vn"
},
"Sms": {
"dataSource": "vn"
},

View File

@ -0,0 +1,26 @@
{
"name": "ClientSms",
"base": "VnModel",
"options": {
"mysql": {
"table": "clientSms"
}
},
"properties": {
"id": {
"type": "number",
"id": true,
"description": "Identifier"
},
"clientFk": {
"type": "number"
}
},
"relations": {
"sms": {
"type": "belongsTo",
"model": "Sms",
"foreignKey": "smsFk"
}
}
}

View File

@ -41,7 +41,18 @@ module.exports = Self => {
});
async function socialNameIsUnique(err, done) {
if (!this.countryFk)
return done();
const filter = {
include: {
relation: 'country',
scope: {
fields: {
isSocialNameUnique: true,
},
},
},
where: {
and: [
{socialName: this.socialName},
@ -50,9 +61,13 @@ module.exports = Self => {
]
}
};
const client = await Self.app.models.Client.findOne(filter);
if (client)
const client = await Self.app.models.Country.findById(this.countryFk, {fields: ['isSocialNameUnique']});
const existingClient = await Self.findOne(filter);
if (existingClient && (existingClient.country().isSocialNameUnique || client.isSocialNameUnique))
err();
done();
}

View File

@ -181,6 +181,11 @@
"model": "Country",
"foreignKey": "countryFk"
},
"isSocialNameUnique": {
"type": "belongsTo",
"model": "Country",
"foreignKey": "countryFk"
},
"contactChannel": {
"type": "belongsTo",
"model": "ContactChannel",

View File

@ -48,4 +48,5 @@ import './notification';
import './unpaid';
import './extended-list';
import './credit-management';
import './sms';

View File

@ -23,6 +23,7 @@
{"state": "client.card.recovery.index", "icon": "icon-recovery"},
{"state": "client.card.webAccess", "icon": "cloud"},
{"state": "client.card.log", "icon": "history"},
{"state": "client.card.sms", "icon": "sms"},
{
"description": "Credit management",
"icon": "monetization_on",
@ -373,6 +374,12 @@
"component": "vn-client-log",
"description": "Log"
},
{
"url" : "/sms",
"state": "client.card.sms",
"component": "vn-client-sms",
"description": "Sms"
},
{
"url": "/dms",
"state": "client.card.dms",

View File

@ -0,0 +1,40 @@
<vn-crud-model
vn-id="model"
url="ClientSms"
link="{clientFk: $ctrl.$params.id}"
filter="::$ctrl.filter"
data="clientSmsList"
limit="20"
auto-load="true">
</vn-crud-model>
<vn-data-viewer model="model">
<vn-card class="vn-w-md">
<vn-table model="model" auto-load="false">
<vn-thead>
<vn-tr>
<vn-th field="senderFk">Sender</vn-th>
<vn-th field="destination" number>Destination</vn-th>
<vn-th field="message">Message</vn-th>
<vn-th field="status">Status</vn-th>
<vn-th field="created" expand>Created</vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="clientSms in clientSmsList">
<vn-td>
<span class="link" ng-click="workerDescriptor.show($event, clientSms.sms.senderFk)">
{{::clientSms.sms.sender.name}}
</span>
</vn-td>
<vn-td number expand>{{::clientSms.sms.destination}}</vn-td>
<vn-td>{{::clientSms.sms.message}}</vn-td>
<vn-td>{{::clientSms.sms.status}}</vn-td>
<vn-td shrink-datetime>{{::clientSms.sms.created | date:'dd/MM/yyyy HH:mm'}}</vn-td>
</vn-tr>
</vn-tbody>
</vn-table>
</vn-card>
</vn-data-viewer>
<vn-worker-descriptor-popover
vn-id="worker-descriptor">
</vn-worker-descriptor-popover>

View File

@ -0,0 +1,39 @@
import ngModule from '../module';
import Section from 'salix/components/section';
export default class Controller extends Section {
constructor($element, $) {
super($element, $);
this.filter = {
fields: ['id', 'smsFk'],
include: {
relation: 'sms',
scope: {
fields: [
'senderFk',
'sender',
'destination',
'message',
'statusCode',
'status',
'created'],
include: {
relation: 'sender',
scope: {
fields: ['name']
}
}
}
}
};
}
}
ngModule.vnComponent('vnClientSms', {
template: require('./index.html'),
controller: Controller,
bindings: {
client: '<'
}
});

View File

@ -0,0 +1,2 @@
Sender: Remitente
Number sender: Número remitente

View File

@ -8,7 +8,7 @@ vn-client-summary .summary {
}
vn-horizontal h4 .grafana:after {
content: 'contact_support';
font-size: 17px;
font-family: 'salixfont' !important;
content: "\e965";
}
}

View File

@ -3,14 +3,13 @@
vn-entry-buy-index vn-card {
max-width: $width-xl;
.dark-row {
background-color: lighten($color-marginal, 10%);
}
thead tr {
border-left: 1px solid white;
border-right: 1px solid white;
border: 1px solid white;;
}
tbody tr:nth-child(1),
@ -22,7 +21,7 @@ vn-entry-buy-index vn-card {
tbody tr:nth-child(2) {
border-bottom: 1px solid $color-spacer;
}
tbody{
border-bottom: 1px solid $color-spacer;
}
@ -40,4 +39,4 @@ vn-entry-buy-index vn-card {
}
}
$color-font-link-medium: lighten($color-font-link, 20%)
$color-font-link-medium: lighten($color-font-link, 20%)

View File

@ -0,0 +1,20 @@
name: invoice in
columns:
id: id
serialNumber: serial number
serial: serial
supplierFk: supplier
issued: issued
supplierRef: supplierRef
isBooked: is booked
currencyFk: currency
created: created
companyFk: company
docFk: document
booked: booked
operated: operated
bookEntried: book entried
isVatDeductible: is VAT deductible
withholdingSageFk: withholding
expenceFkDeductible: expence deductible
editorFk: editor

View File

@ -0,0 +1,20 @@
name: factura recibida
columns:
id: id
serialNumber: número de serie
serial: serie
supplierFk: proveedor
issued: fecha emisión
supplierRef: referéncia proveedor
isBooked: facturado
currencyFk: moneda
created: creado
companyFk: empresa
docFk: documento
booked: fecha contabilización
operated: fecha entrega
bookEntried: fecha asiento
isVatDeductible: impuesto deducible
withholdingSageFk: código de retención
expenceFkDeductible: gasto deducible
editorFk: editor

View File

@ -0,0 +1,9 @@
name: invoice in due day
columns:
id: id
invoiceInFk: invoice in
dueDated: due date
bankFk: bank
amount: amount
foreignValue : foreign amount
created: created

View File

@ -0,0 +1,9 @@
name: vencimientos factura recibida
columns:
id: id
invoiceInFk: factura
dueDated: fecha vto.
bankFk: banco
amount: importe
foreignValue : importe divisa
created: creado

View File

@ -0,0 +1,12 @@
name: invoice in tax
columns:
id: id
invoiceInFk: invoice in
taxCodeFk: tax
taxableBase: taxable base
expenceFk: expence
foreignValue: foreign amount
taxTypeSageFk: tax type
transactionTypeSageFk: transaction type
created: created
editorFk: editor

View File

@ -0,0 +1,12 @@
name: factura recibida impuesto
columns:
id: id
invoiceInFk: factura recibida
taxCodeFk: código IVA
taxableBase: base imponible
expenceFk: código gasto
foreignValue: importe divisa
taxTypeSageFk: código impuesto
transactionTypeSageFk: código transacción
created: creado
editorFk: editor

View File

@ -0,0 +1,37 @@
module.exports = Self => {
Self.remoteMethod('getInventory', {
description: 'Get list of itemShelving to review between two parking code',
accessType: 'WRITE',
accepts: [{
arg: 'parkingFrom',
type: 'string',
required: true,
description: 'Parking code from'
},
{
arg: 'parkingTo',
type: 'string',
required: true,
description: 'Parking code to'
}],
returns: {
type: ['object'],
root: true
},
http: {
path: `/getInventory`,
verb: 'POST'
}
});
Self.getInventory = async(parkingFrom, parkingTo, options) => {
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const [result] = await Self.rawSql(`CALL vn.itemShelving_inventory(?, ?)`, [parkingFrom, parkingTo], myOptions);
return result;
};
};

View File

@ -0,0 +1,24 @@
const models = require('vn-loopback/server/server').models;
describe('itemShelving getInventory()', () => {
it('should return a list of itemShelvings', async() => {
const tx = await models.ItemShelving.beginTransaction({});
let response;
try {
const options = {transaction: tx};
await models.ItemShelving.rawSql(`
UPDATE vn.config
SET mainWarehouseFk=1
WHERE id=1
`, null, options);
response = await models.ItemShelving.getInventory('100-01', 'LR-02-3', options);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
expect(response.length).toEqual(2);
});
});

View File

@ -145,7 +145,7 @@ module.exports = Self => {
const stmts = [];
const stmt = new ParameterizedSQL(
`SELECT
`SELECT
i.id,
i.image,
i.name,
@ -164,6 +164,8 @@ module.exports = Self => {
i.stemMultiplier,
i.typeFk,
i.isFloramondo,
i.recycledPlastic,
i.nonRecycledPlastic,
pr.name AS producer,
it.name AS typeName,
it.workerFk AS buyerFk,

View File

@ -1,3 +1,4 @@
module.exports = Self => {
require('../methods/item-shelving/deleteItemShelvings')(Self);
require('../methods/item-shelving/getInventory')(Self);
};

View File

@ -23,6 +23,12 @@
},
"isChecked": {
"type": "boolean"
},
"visible": {
"type": "number"
},
"userFk": {
"type": "number"
}
},
"relations": {

View File

@ -125,6 +125,12 @@
"minPrice": {
"type": "number"
},
"recycledPlastic": {
"type": "number"
},
"nonRecycledPlastic": {
"type": "number"
},
"packingOut": {
"type": "number"
},

View File

@ -82,6 +82,8 @@
vn-name="expence"
initial-data="$ctrl.item.expense">
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete
data="originsData"
label="Origin"
@ -91,21 +93,6 @@
vn-name="origin"
initial-data="$ctrl.item.origin">
</vn-autocomplete>
<vn-textfield
label="Reference"
ng-model="$ctrl.item.comment"
vn-name="comment"
rule>
</vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-input-number
min="0"
label="Relevancy"
ng-model="$ctrl.item.relevancy"
vn-name="relevancy"
rule>
</vn-input-number>
<vn-input-number
min="0"
label="Size"
@ -113,6 +100,21 @@
vn-name="size"
rule>
</vn-input-number>
<vn-textfield
label="Reference"
ng-model="$ctrl.item.comment"
vn-name="comment"
rule>
</vn-textfield>
<vn-input-number
min="0"
label="Relevancy"
ng-model="$ctrl.item.relevancy"
vn-name="relevancy"
rule>
</vn-input-number>
</vn-horizontal>
<vn-horizontal>
<vn-input-number
min="0"
label="stems"
@ -126,22 +128,6 @@
ng-model="$ctrl.item.stemMultiplier"
vn-name="stemMultiplier">
</vn-input-number>
</vn-horizontal>
<vn-horizontal>
<vn-input-number
min="0"
label="Weight/Piece"
ng-model="$ctrl.item.weightByPiece"
vn-name="weightByPiece"
rule>
</vn-input-number>
<vn-input-number
min="0"
label="Units/Box"
ng-model="$ctrl.item.packingOut"
vn-name="packingOut"
rule>
</vn-input-number>
<vn-autocomplete
label="Generic"
url="Items/withName"
@ -167,6 +153,36 @@
</append>
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-input-number
min="0"
label="Weight/Piece"
ng-model="$ctrl.item.weightByPiece"
vn-name="weightByPiece"
rule>
</vn-input-number>
<vn-input-number
min="0"
label="Units/Box"
ng-model="$ctrl.item.packingOut"
vn-name="packingOut"
rule>
</vn-input-number>
<vn-input-number
min="0"
label="Recycled Plastic"
ng-model="$ctrl.item.recycledPlastic"
vn-name="recycledPlastic"
rule>
</vn-input-number>
<vn-input-number
min="0"
label="Non recycled plastic"
ng-model="$ctrl.item.nonRecycledPlastic"
vn-name="nonRecycledPlastic"
rule>
</vn-input-number>
</vn-horizontal>
<vn-horizontal>
<vn-textarea
label="Description"

View File

@ -1,7 +1,7 @@
Reference: Referencia
Full name calculates based on tags 1-3. Is not recommended to change it manually: >-
El nombre completo se calcula
basado en los tags 1-3.
Full name calculates based on tags 1-3. Is not recommended to change it manually: >-
El nombre completo se calcula
basado en los tags 1-3.
No se recomienda cambiarlo manualmente
Is active: Activo
Expense: Gasto
@ -13,4 +13,6 @@ Is shown at website, app that this item cannot travel (wreath, palms, ...): Se m
Multiplier: Multiplicador
Generic: Genérico
This item does need a photo: Este artículo necesita una foto
Do photo: Hacer foto
Do photo: Hacer foto
Recycled Plastic: Plástico reciclado
Non recycled plastic: Plástico no reciclado

View File

@ -85,7 +85,7 @@
show-field="id"
value-field="id"
search-function="$ctrl.itemSearchFunc($search)"
on-change="$ctrl.upsertPrice(price, true)"
ng-change="$ctrl.upsertPrice(price, true)"
order="id DESC"
tabindex="1">
<tpl-item>

View File

@ -113,9 +113,21 @@
<vn-label-value label="Weight/Piece"
value="{{$ctrl.summary.item.weightByPiece}}">
</vn-label-value>
<vn-label-value label="Units/Box"
value="{{$ctrl.summary.item.packingOut}}">
</vn-label-value>
<vn-label-value label="Expense"
value="{{$ctrl.summary.item.expense.name}}">
</vn-label-value>
<vn-label-value label="Generic"
value="{{$ctrl.summary.item.genericFk}}">
</vn-label-value>
<vn-label-value label="Recycled Plastic"
value="{{$ctrl.summary.item.recycledPlastic}}">
</vn-label-value>
<vn-label-value label="Non recycled plastic"
value="{{$ctrl.summary.item.nonRecycledPlastic}}">
</vn-label-value>
</vn-one>
<vn-one name="tags">
<h4 ng-show="$ctrl.isBuyer || $ctrl.isReplenisher">

View File

@ -0,0 +1,81 @@
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.remoteMethod('clone', {
description: 'Clones the selected routes',
accessType: 'WRITE',
accepts: [
{
arg: 'ids',
type: ['number'],
required: true,
description: 'The routes ids to clone'
},
{
arg: 'etd',
type: 'date',
required: true,
description: 'The estimated time of departure for all roadmaps'
}
],
returns: {
type: ['Object'],
root: true
},
http: {
path: `/clone`,
verb: 'POST'
}
});
Self.clone = async(ids, etd) => {
const tx = await Self.beginTransaction({});
try {
const models = Self.app.models;
const options = {transaction: tx};
const originalRoadmaps = await models.Roadmap.find({
where: {id: {inq: ids}},
fields: [
'id',
'name',
'tractorPlate',
'trailerPlate',
'phone',
'supplierFk',
'etd',
'observations',
'price'],
include: [{
relation: 'expeditionTruck',
scope: {
fields: ['roadmapFk', 'warehouseFk', 'eta', 'description']
}
}]
}, options);
if (ids.length != originalRoadmaps.length)
throw new UserError(`The amount of roadmaps found don't match`);
for (const roadmap of originalRoadmaps) {
roadmap.id = undefined;
roadmap.etd = etd;
const clone = await models.Roadmap.create(roadmap, options);
const expeditionTrucks = roadmap.expeditionTruck();
expeditionTrucks.map(expeditionTruck => {
expeditionTruck.roadmapFk = clone.id;
return expeditionTruck;
});
await models.ExpeditionTruck.create(expeditionTrucks, options);
}
await tx.commit();
return true;
} catch (e) {
await tx.rollback();
throw e;
}
};
};

View File

@ -0,0 +1,109 @@
const app = require('vn-loopback/server/server');
const models = require('vn-loopback/server/server').models;
describe('AgencyTerm filter()', () => {
const authUserId = 9;
const today = Date.vnNew();
today.setHours(2, 0, 0, 0);
it('should return all results matching the filter', async() => {
const tx = await models.AgencyTerm.beginTransaction({});
try {
const options = {transaction: tx};
const filter = {};
const ctx = {req: {accessToken: {userId: authUserId}}};
const agencyTerms = await models.AgencyTerm.filter(ctx, filter, options);
const firstAgencyTerm = agencyTerms[0];
expect(firstAgencyTerm.routeFk).toEqual(1);
expect(agencyTerms.length).toEqual(5);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return results matching "search" searching by integer', async() => {
let ctx = {
args: {
search: 1,
}
};
let result = await app.models.AgencyTerm.filter(ctx);
expect(result.length).toEqual(1);
expect(result[0].routeFk).toEqual(1);
});
it('should return results matching "search" searching by string', async() => {
let ctx = {
args: {
search: 'Plants SL',
}
};
let result = await app.models.AgencyTerm.filter(ctx);
expect(result.length).toEqual(2);
});
it('should return results matching "from" and "to"', async() => {
const tx = await models.Buy.beginTransaction({});
const options = {transaction: tx};
try {
const from = Date.vnNew();
from.setHours(0, 0, 0, 0);
const to = Date.vnNew();
to.setHours(23, 59, 59, 999);
const ctx = {
args: {
from: from,
to: to
}
};
const results = await models.AgencyTerm.filter(ctx, options);
expect(results.length).toBe(5);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return results matching "agencyModeFk"', async() => {
let ctx = {
args: {
agencyModeFk: 1,
}
};
let result = await app.models.AgencyTerm.filter(ctx);
expect(result.length).toEqual(1);
expect(result[0].routeFk).toEqual(1);
});
it('should return results matching "agencyFk"', async() => {
let ctx = {
args: {
agencyFk: 2,
}
};
let result = await app.models.AgencyTerm.filter(ctx);
expect(result.length).toEqual(1);
expect(result[0].routeFk).toEqual(2);
});
});

View File

@ -0,0 +1,27 @@
module.exports = Self => {
Self.remoteMethod('sorted', {
description: 'Sort the vehicles by warehouse',
accessType: 'WRITE',
accepts: [{
arg: 'warehouseFk',
type: 'number'
}],
returns: {
type: ['object'],
root: true
},
http: {
path: `/sorted`,
verb: `POST`
}
});
Self.sorted = async warehouseFk => {
return Self.rawSql(`
SELECT v.id, v.warehouseFk, v.numberPlate, w.name
FROM vehicle v
JOIN warehouse w ON w.id = v.warehouseFk
ORDER BY v.warehouseFk = ? DESC, w.id, v.numberPlate ASC;
`, [warehouseFk]);
};
};

View File

@ -5,18 +5,22 @@
"AgencyTermConfig": {
"dataSource": "vn"
},
"Route": {
"DeliveryPoint": {
"dataSource": "vn"
},
"Vehicle": {
"ExpeditionTruck": {
"dataSource": "vn"
},
"Roadmap": {
"dataSource": "vn"
},
"Route": {
"dataSource": "vn"
},
"RouteLog": {
"dataSource": "vn"
},
"DeliveryPoint": {
"Vehicle": {
"dataSource": "vn"
}
}

View File

@ -0,0 +1,43 @@
{
"name": "ExpeditionTruck",
"base": "VnModel",
"options": {
"mysql": {
"table": "expeditionTruck"
}
},
"properties": {
"id": {
"type": "number",
"id": true,
"description": "Identifier"
},
"roadmapFk": {
"type": "number"
},
"warehouseFk": {
"type": "number"
},
"eta": {
"type": "date"
},
"description": {
"type": "string"
},
"userFk": {
"type": "number"
}
},
"relations": {
"roadmap": {
"type": "belongsTo",
"model": "Roadmap",
"foreignKey": "roadmapFk"
},
"warehouse": {
"type": "belongsTo",
"model": "Warehouse",
"foreignKey": "warehouseFk"
}
}
}

View File

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

View File

@ -0,0 +1,63 @@
{
"name": "Roadmap",
"base": "VnModel",
"options": {
"mysql": {
"table": "roadmap"
}
},
"properties": {
"id": {
"type": "number",
"id": true,
"description": "Identifier"
},
"name": {
"type": "string"
},
"tractorPlate": {
"type": "string"
},
"trailerPlate": {
"type": "string"
},
"phone": {
"type": "string"
},
"supplierFk": {
"type": "number"
},
"etd": {
"type": "date"
},
"observations": {
"type": "string"
},
"userFk": {
"type": "number"
},
"price": {
"type": "number"
},
"driverName": {
"type": "string"
}
},
"relations": {
"worker": {
"type": "belongsTo",
"model": "Worker",
"foreignKey": "userFk"
},
"supplier": {
"type": "belongsTo",
"model": "Supplier",
"foreignKey": "supplierFk"
},
"expeditionTruck": {
"type": "hasMany",
"model": "ExpeditionTruck",
"foreignKey": "roadmapFk"
}
}
}

View File

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

View File

@ -23,19 +23,21 @@
</tpl-item>
</vn-autocomplete>
<vn-autocomplete
label="Vehicle"
ng-model="$ctrl.route.vehicleFk"
url="Vehicles"
data="$ctrl.vehicles"
show-field="numberPlate"
value-field="id"
label="Vehicle"
order="false"
vn-name="vehicle">
<tpl-item>{{::numberPlate}} - {{::name}}</tpl-item>
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-date-picker
label="Created"
ng-model="$ctrl.route.created"
vn-name="created">
vn-name="created">
</vn-date-picker>
<vn-autocomplete
ng-model="$ctrl.route.agencyModeFk"

View File

@ -2,6 +2,13 @@ import ngModule from '../module';
import Section from 'salix/components/section';
class Controller extends Section {
$onInit() {
this.$http.post(`Vehicles/sorted`, {warehouseFk: this.vnConfig.warehouseFk})
.then(res => {
this.vehicles = res.data;
});
}
onSubmit() {
this.$.watcher.submit().then(() =>
this.card.reload()

View File

@ -16,3 +16,4 @@ import './agency-term/createInvoiceIn';
import './agency-term-search-panel';
import './ticket-popup';
import './sms';
import './roadmap';

View File

@ -0,0 +1,98 @@
<mg-ajax path="Roadmaps/{{patch.params.id}}" options="vnPatch"></mg-ajax>
<vn-watcher
vn-id="watcher"
data="$ctrl.roadmap"
form="form"
save="patch">
</vn-watcher>
<form name="form" ng-submit="$ctrl.onSubmit()" class="vn-w-md">
<vn-card class="vn-pa-lg">
<vn-horizontal>
<vn-textfield vn-focus
vn-one
label="Roadmap"
ng-model="$ctrl.roadmap.name"
rule>
</vn-textfield>
<vn-date-picker
vn-one
label="ETD date"
ng-model="$ctrl.roadmap.etd">
</vn-date-picker>
<vn-input-time
vn-one
label="ETD hour"
ng-model="$ctrl.roadmap.etd">
</vn-input-time>
</vn-horizontal>
<vn-horizontal>
<vn-textfield
vn-one
label="Tractor plate"
ng-model="$ctrl.roadmap.tractorPlate"
rule>
</vn-textfield>
<vn-textfield
vn-one
label="Trailer plate"
ng-model="$ctrl.roadmap.trailerPlate"
rule>
</vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete
vn-one
ng-model="$ctrl.roadmap.supplierFk"
url="Suppliers"
show-field="nickname"
search-function="{or: [{id: $search}, {nickname: {like: '%'+ $search +'%'}}]}"
value-field="id"
order="nickname"
label="Carrier">
<tpl-item>
{{::id}} - {{::nickname}}
</tpl-item>
</vn-autocomplete>
<vn-input-number
vn-one
label="Price"
ng-model="$ctrl.roadmap.price"
rule>
</vn-input-number>
</vn-horizontal>
<vn-horizontal>
<vn-textfield
vn-one
label="Driver name"
ng-model="$ctrl.roadmap.driverName"
rule>
</vn-textfield>
<vn-textfield
vn-one
label="Phone"
ng-model="$ctrl.roadmap.phone"
rule>
</vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-textArea
vn-one
label="Observations"
ng-model="$ctrl.roadmap.observations"
rule>
</vn-textArea>
</vn-horizontal>
</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,16 @@
import ngModule from '../../module';
import Section from 'salix/components/section';
export default class Controller extends Section {
onSubmit() {
this.$.watcher.submit();
}
}
ngModule.component('vnRoadmapBasicData', {
template: require('./index.html'),
controller: Controller,
bindings: {
roadmap: '<'
}
});

View File

@ -0,0 +1,5 @@
<vn-portal slot="menu">
<vn-roadmap-descriptor roadmap="$ctrl.roadmap"></vn-roadmap-descriptor>
<vn-left-menu source="roadmap"></vn-left-menu>
</vn-portal>
<ui-view></ui-view>

View File

@ -0,0 +1,19 @@
import ngModule from '../../module';
import ModuleCard from 'salix/components/module-card';
class Controller extends ModuleCard {
reload() {
const filter = {
include: [
{relation: 'supplier'}
]
};
this.$http.get(`Roadmaps/${this.$params.id}`, {filter})
.then(res => this.roadmap = res.data);
}
}
ngModule.vnComponent('vnRoadmapCard', {
template: require('./index.html'),
controller: Controller
});

View File

@ -0,0 +1,37 @@
<vn-watcher
vn-id="watcher"
url="Roadmaps"
data="$ctrl.roadmap"
insert-mode="true"
form="form">
</vn-watcher>
<form name="form" ng-submit="$ctrl.onSubmit()" class="vn-w-md">
<vn-card class="vn-pa-lg">
<vn-horizontal>
<vn-textfield
label="Roadmap"
ng-model="$ctrl.roadmap.name"
rule>
</vn-textfield>
<vn-date-picker
label="ETD date"
ng-model="$ctrl.roadmap.etd">
</vn-date-picker>
<vn-input-time
label="ETD hour"
ng-model="$ctrl.roadmap.etd">
</vn-input-time>
</vn-horizontal>
</vn-card>
<vn-button-bar>
<vn-submit
disabled="!watcher.dataChanged()"
label="Create">
</vn-submit>
<vn-button
class="cancel"
label="Cancel"
ui-sref="roadmap.index">
</vn-button>
</vn-button-bar>
</form>

View File

@ -0,0 +1,23 @@
import ngModule from '../../module';
import Section from 'salix/components/section';
import './style.scss';
class Controller extends Section {
constructor($element, $, $transclude, vnReport, vnEmail) {
super($element, $, $transclude);
this.roadmap = {etd: Date.vnNew()};
}
onSubmit() {
this.$.watcher.submit().then(
res => this.$state.go('route.roadmap.card.summary', {id: res.data.id})
);
}
}
Controller.$inject = ['$element', '$scope'];
ngModule.vnComponent('vnRoadmapCreate', {
template: require('./index.html'),
controller: Controller
});

View File

@ -0,0 +1,6 @@
vn-ticket-request {
.vn-textfield {
margin: 0!important;
max-width: 100px;
}
}

View File

@ -0,0 +1,39 @@
<vn-descriptor-content
module="route"
base-state="route.roadmap"
description="$ctrl.roadmap.name">
<slot-menu>
<vn-item
ng-click="deleteRoadmap.show()"
name="deleteRoadmap"
translate>
Delete roadmap
</vn-item>
</slot-menu>
<slot-body>
<div class="attributes">
<vn-label-value
label="Roadmap"
value="{{$ctrl.roadmap.name}}">
</vn-label-value>
<vn-label-value
label="ETD"
value="{{$ctrl.roadmap.etd | date:'dd/MM/yyyy HH:mm'}}">
</vn-label-value>
<vn-label-value label="Carrier">
<span ng-click="supplierDescriptor.show($event, $ctrl.roadmap.supplier.id)" class="link">
{{$ctrl.roadmap.supplier.nickname}}
</span>
</vn-label-value>
</div>
</slot-body>
</vn-descriptor-content>
<vn-confirm
vn-id="deleteRoadmap"
on-accept="$ctrl.onDelete()"
question="Are you sure you want to continue?"
message="The roadmap will be removed">
</vn-confirm>
<vn-supplier-descriptor-popover
vn-id="supplierDescriptor">
</vn-supplier-descriptor-popover>

View File

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

View File

@ -0,0 +1,3 @@
Delete roadmap: Eliminar troncal
The roadmap will be removed: La troncal será eliminada
Roadmap removed: Troncal eliminada

View File

@ -0,0 +1,9 @@
import './main';
import './index/';
import './summary';
import './card';
import './descriptor';
import './create';
import './basic-data';
import './search-panel';
import './stops';

View File

@ -0,0 +1,112 @@
<vn-auto-search
model="model">
</vn-auto-search>
<vn-data-viewer
model="model"
class="vn-w-lg">
<vn-card class="vn-pa-md vn-w-lg">
<vn-tool-bar class="vn-ma-md">
<vn-button
disabled="$ctrl.totalChecked == 0"
ng-click="$ctrl.openClonationDialog()"
icon="icon-clone"
vn-tooltip="Clone selected roadmaps">
</vn-button>
<vn-button
disabled="$ctrl.totalChecked == 0"
ng-click="deleteRoadmaps.show()"
vn-tooltip="Delete roadmap(s)"
icon="delete">
</vn-button>
</vn-tool-bar>
<vn-table model="model">
<vn-thead>
<vn-tr>
<vn-th shrink>
<vn-multi-check
model="model">
</vn-multi-check>
</vn-th>
<vn-th field="description">Roadmap</vn-th>
<vn-th field="etd" expand date>ETD</vn-th>
<vn-th field="supplierFk">Carrier</vn-th>
<vn-th field="plate">Plate</vn-th>
<vn-th field="price">Price</vn-th>
<vn-th field="observations" expand>Observations</vn-th>
<vn-th></vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<a ng-repeat="roadmap in model.data"
class="clickable vn-tr search-result"
ui-sref="route.roadmap.card.summary({id: {{::roadmap.id}}})">
<vn-td>
<vn-check
ng-model="roadmap.checked"
vn-click-stop>
</vn-check>
</vn-td>
<vn-td>{{::roadmap.name}}</vn-td>
<vn-td expand date>{{::roadmap.etd | date:'dd/MM/yyyy HH:mm'}}</vn-td>
<vn-td expand>
<span
class="link"
vn-click-stop="supplierDescriptor.show($event, roadmap.supplierFk)">
{{::roadmap.supplier.nickname}}
</span>
</vn-td>
<vn-td>{{::roadmap.tractorPlate | dashIfEmpty}}</vn-td>
<vn-td expand>{{::roadmap.price | currency: 'EUR':2 | dashIfEmpty}}</vn-td>
<vn-td expand>{{::roadmap.observations | dashIfEmpty}}</vn-td>
<vn-td shrink>
<vn-icon-button
vn-click-stop="$ctrl.preview(roadmap)"
vn-tooltip="Preview"
icon="preview">
</vn-icon-button>
</vn-td>
</a>
</vn-tbody>
</vn-table>
</vn-card>
</vn-data-viewer>
<a
ui-sref="route.roadmap.create"
vn-tooltip="Create roadmap"
vn-bind="+"
fixed-bottom-right>
<vn-float-button icon="add"></vn-float-button>
</a>
<vn-popup vn-id="summary">
<vn-roadmap-summary
roadmap="$ctrl.roadmapSelected">
</vn-roadmap-summary>
</vn-popup>
<vn-supplier-descriptor-popover
vn-id="supplierDescriptor">
</vn-supplier-descriptor-popover>
<!-- Clonation dialog -->
<vn-dialog class="edit"
vn-id="clonationDialog"
on-accept="$ctrl.cloneSelectedRoadmaps()"
message="Select the estimated time of departure (ETD)">
<tpl-body>
<vn-horizontal>
<vn-date-picker
label="ETD"
ng-model="$ctrl.etd">
</vn-date-picker>
</vn-horizontal>
</tpl-body>
<tpl-buttons>
<input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/>
<button response="accept" translate>Clone</button>
</tpl-buttons>
</vn-dialog>
<vn-confirm
vn-id="deleteRoadmaps"
question="Are you sure you want to continue?"
message="Selected roadmaps will be removed"
on-accept="$ctrl.deleteRoadmaps()">
</vn-confirm>

View File

@ -0,0 +1,62 @@
import ngModule from '../../module';
import Section from 'salix/components/section';
class Controller extends Section {
get checked() {
const roadmaps = this.$.model.data || [];
const checkedRoadmap = [];
for (let roadmap of roadmaps) {
if (roadmap.checked)
checkedRoadmap.push(roadmap);
}
return checkedRoadmap;
}
get totalChecked() {
return this.checked.length;
}
preview(roadmap) {
this.roadmapSelected = roadmap;
this.$.summary.show();
}
openClonationDialog() {
this.$.clonationDialog.show();
this.etd = Date.vnNew();
}
cloneSelectedRoadmaps() {
try {
if (!this.etd)
throw new Error(`The date can't be empty`);
const roadmapsIds = [];
for (let roadmap of this.checked)
roadmapsIds.push(roadmap.id);
return this.$http.post('Roadmaps/clone', {ids: roadmapsIds, etd: this.etd}).then(() => {
this.$.model.refresh();
this.vnApp.showSuccess(this.$t('Data saved!'));
});
} catch (e) {
this.vnApp.showError(this.$t(e.message));
}
}
deleteRoadmaps() {
console.log(this.checked);
for (const roadmap of this.checked) {
this.$http.delete(`Roadmaps/${roadmap.id}`)
.then(() => this.$.model.refresh())
.then(() => this.vnApp.showSuccess(this.$t('Roadmaps removed')));
}
}
}
ngModule.vnComponent('vnRoadmapIndex', {
template: require('./index.html'),
controller: Controller
});

View File

@ -0,0 +1,3 @@
Delete roadmap(s): Eliminar troncal(es)
Selected roadmaps will be removed: Los troncales seleccionados serán eliminados
Roadmaps removed: Troncales eliminados

View File

@ -0,0 +1,14 @@
Roadmaps: Troncales
Roadmap: Troncal
Driver name: Nombre conductor
Plate: Matrícula
Price: Precio
Observations: Observaciones
Clone selected roadmaps: Clonar troncales seleccionadas
Select the estimated time of departure (ETD): Seleccione la hora estimada de salida (ETD)
Create roadmap: Crear troncal
Tractor plate: Matrícula tractor
Trailer plate: Matrícula trailer
Carrier: Transportista
ETD date: Fecha ETD
ETD hour: Hora ETD

View File

@ -0,0 +1,20 @@
<vn-crud-model
vn-id="model"
url="Roadmaps"
include="$ctrl.include"
auto-load="true"
limit="20">
</vn-crud-model>
<vn-portal slot="topbar">
<vn-searchbar
info="Search roadmap by id or trunk"
panel="vn-roadmap-search-panel"
model="model"
filter="$ctrl.filterParams"
expr-builder="$ctrl.exprBuilder(param, value)"
base-state="route.roadmap">
</vn-searchbar>
</vn-portal>
<ui-view>
<vn-roadmap-index></vn-roadmap-index>
</ui-view>

View File

@ -0,0 +1,61 @@
import ngModule from '../../module';
import ModuleMain from 'salix/components/module-main';
export default class Roadmap extends ModuleMain {
constructor($element, $) {
super($element, $);
this.include = {
relation: 'supplier',
scope: {
fields: ['nickname']
}
};
}
$postLink() {
const from = Date.vnNew();
from.setHours(0, 0, 0, 0);
const to = Date.vnNew();
to.setHours(23, 59, 59, 999);
this.filterParams = {
from: from,
to: to
};
this.$.model.addFilter({where: {
and: [
{etd: {gte: from}},
{etd: {lte: to}}
]
}});
}
exprBuilder(param, value) {
switch (param) {
case 'search':
return /^\d+$/.test(value)
? {id: value}
: {name: {like: `%${value}%`}};
case 'from':
return {etd: {gte: value}};
case 'to':
return {etd: {lte: value}};
case 'supplierFk':
case 'price':
return {[param]: value};
case 'tractorPlate':
case 'trailerPlate':
case 'phone':
case 'driverName':
return {[param]: {like: `%${value}%`}};
}
}
}
ngModule.vnComponent('vnRoadmap', {
controller: Roadmap,
template: require('./index.html')
});

View File

@ -0,0 +1 @@
Search roadmap by id or trunk: Buscar troncales por id o troncal

View File

@ -0,0 +1,74 @@
<div class="search-panel">
<form id="manifold-form" ng-submit="$ctrl.onSearch()">
<vn-horizontal class="vn-px-lg vn-pt-lg">
<vn-textfield
vn-one
label="General search"
ng-model="filter.search"
info="Search routes by id"
vn-focus>
</vn-textfield>
</vn-horizontal>
<section class="vn-px-md">
<vn-horizontal class="manifold-panel vn-pa-md">
<vn-date-picker
vn-one
label="From"
ng-model="filter.from">
</vn-date-picker>
<vn-date-picker
vn-one
label="To"
ng-model="filter.to">
</vn-date-picker>
</vn-horizontal>
</section>
<vn-horizontal class="vn-px-lg">
<vn-textfield
vn-one
label="Tractor plate"
ng-model="filter.tractorPlate">
</vn-textfield>
<vn-textfield
vn-one
label="Trailer plate"
ng-model="filter.trailerPlate">
</vn-textfield>
</vn-horizontal>
<vn-horizontal class="vn-px-lg">
<vn-autocomplete
vn-one
ng-model="filter.supplierFk"
url="Suppliers"
show-field="nickname"
search-function="{or: [{id: $search}, {nickname: {like: '%'+ $search +'%'}}]}"
value-field="id"
order="nickname"
label="Carrier">
<tpl-item>
{{::id}} - {{::nickname}}
</tpl-item>
</vn-autocomplete>
<vn-input-number
vn-one
label="Price"
ng-model="filter.price">
</vn-input-number>
</vn-horizontal>
<vn-horizontal class="vn-px-lg">
<vn-textfield
vn-one
label="Driver name"
ng-model="filter.driverName">
</vn-textfield>
<vn-textfield
vn-one
label="Phone"
ng-model="filter.phone">
</vn-textfield>
</vn-horizontal>
<vn-horizontal class="vn-px-lg vn-pb-lg 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.component('vnRoadmapSearchPanel', {
template: require('./index.html'),
controller: SearchPanel
});

View File

@ -0,0 +1,71 @@
<vn-crud-model
vn-id="model"
url="ExpeditionTrucks"
where="{roadmapFk: $ctrl.$params.id}"
order="eta ASC"
data="$ctrl.expeditionTrucks"
auto-load="true">
</vn-crud-model>
<vn-watcher
vn-id="watcher"
data="$ctrl.expeditionTrucks"
form="form">
</vn-watcher>
<form class="vn-w-md" name="form" ng-submit="$ctrl.onSubmit()">
<vn-card class="vn-pa-lg">
<vn-horizontal ng-repeat="expeditionTruck in $ctrl.expeditionTrucks">
<vn-autocomplete vn-one
label="Warehouse"
ng-model="expeditionTruck.warehouseFk"
url="Warehouses"
show-field="name"
value-field="id"
vn-focus
rule>
</vn-autocomplete>
<vn-date-picker vn-one
label="ETA date"
ng-model="expeditionTruck.eta"
rule>
</vn-date-picker>
<vn-input-time
vn-one
label="ETA hour"
ng-model="expeditionTruck.eta">
</vn-input-time>
<vn-textArea
vn-one
label="Description"
ng-model="expeditionTruck.description"
rule>
</vn-textArea>
<vn-none>
<vn-icon-button
vn-tooltip="Remove stop"
icon="delete"
ng-click="model.remove($index)"
tabindex="-1">
</vn-icon-button>
</vn-none>
</vn-horizontal>
<vn-one>
<vn-icon-button
vn-bind="+"
vn-tooltip="Add stop"
icon="add_circle"
ng-click="$ctrl.add()">
</vn-icon-button>
</vn-one>
</vn-card>
<vn-button-bar>
<vn-submit
disabled="!watcher.dataChanged()"
label="Save">
</vn-submit>
</vn-button-bar>
</form>
<vn-confirm
vn-id="confirm"
question="Delete stop?"
on-accept="$ctrl.removeTicketFromRoute($index)">
</vn-confirm>

View File

@ -0,0 +1,39 @@
import ngModule from '../../module';
import Section from 'salix/components/section';
export default class Controller extends Section {
add() {
const filter = {
fields: ['etd']
};
this.$http.get(`Roadmaps/${this.$params.id}`, {filter})
.then(res => {
this.roadmap = res.data;
const eta = new Date(this.roadmap.etd);
eta.setDate(eta.getDate() + 1);
this.$.model.insert({
roadmapFk: this.$params.id,
eta: eta
});
});
}
onSubmit() {
this.$.watcher.check();
this.$.model.save().then(() => {
this.$.watcher.notifySaved();
this.$.watcher.updateOriginalData();
this.$.model.refresh();
});
}
}
ngModule.component('vnRoadmapStops', {
template: require('./index.html'),
controller: Controller,
bindings: {
roadmap: '<'
}
});

View File

@ -0,0 +1,4 @@
Remove stop: Eliminar parada
Add stop: Añadir parada
ETA date: Fecha ETA
ETA hour: Hora ETA

View File

@ -0,0 +1,113 @@
<vn-card class="summary">
<h5>
<span>{{summary.id}} - {{summary.name}}</span>
</h5>
<vn-horizontal class="vn-pa-md">
<vn-one>
<vn-label-value label="Carrier">
<span ng-click="supplierDescriptor.show($event, summary.supplier.id)" class="link">
{{summary.supplier.nickname}}
</span>
</vn-label-value>
<vn-label-value
label="ETD"
value="{{summary.etd | date:'dd/MM/yyyy HH:mm'}}">
</vn-label-value>
<vn-label-value
label="Tractor plate"
value="{{summary.tractorPlate}}">
</vn-label-value>
<vn-label-value
label="Trailer plate"
value="{{summary.trailerPlate}}">
</vn-label-value>
</vn-one>
<vn-one>
<vn-label-value
label="Phone"
value="{{summary.phone}}">
</vn-label-value>
<vn-label-value
label="Worker"
value="{{summary.worker.firstName}} {{summary.worker.lastName}}">
</vn-label-value>
<vn-label-value
label="Observations"
value="{{summary.observations}}">
</vn-label-value>
</vn-one>
<vn-auto>
<h4>
<a
ui-sref="route.roadmap.card.stops({id:summary.id})"
target="_self">
<span translate vn-tooltip="Go to">Stops</span>
<vn-icon-button
vn-bind="+"
vn-tooltip="Add stop"
icon="add_circle"
vn-click-stop="addExpeditionTruck.show()">
</vn-icon-button>
</a>
</h4>
<vn-table model="model">
<vn-thead>
<vn-tr>
<vn-th>Wharehouse</vn-th>
<vn-th>ETA</vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="expeditionTruck in summary.expeditionTruck">
<vn-td>{{expeditionTruck.warehouse.name}}</vn-td>
<vn-td expand>{{expeditionTruck.eta | date:'dd/MM/yyyy HH:mm'}}</vn-td>
</vn-tr>
</vn-tbody>
</vn-table>
</vn-auto>
</vn-horizontal>
</vn-card>
<vn-supplier-descriptor-popover
vn-id="supplierDescriptor">
</vn-supplier-descriptor-popover>
<vn-dialog
vn-id="addExpeditionTruck"
on-open="$ctrl.getETD()"
on-accept="$ctrl.onAddAccept()">
<tpl-body>
<vn-horizontal>
<vn-autocomplete
label="Warehouse"
ng-model="$ctrl.expeditionTruck.warehouseFk"
url="Warehouses"
show-field="name"
value-field="id"
vn-focus
rule>
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-date-picker
label="ETA date"
ng-model="$ctrl.expeditionTruck.eta"
rule>
</vn-date-picker>
<vn-input-time
label="ETA hour"
ng-model="$ctrl.expeditionTruck.eta">
</vn-input-time>
</vn-horizontal>
<vn-horizontal>
<vn-textArea
label="Description"
ng-model="$ctrl.expeditionTruck.description"
rule>
</vn-textArea>
</vn-horizontal>
</tpl-body>
<tpl-buttons>
<input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/>
<button response="accept" translate>Confirm</button>
</tpl-buttons>
</vn-dialog>

View File

@ -0,0 +1,68 @@
import ngModule from '../../module';
import Component from 'core/lib/component';
import './style.scss';
class Controller extends Component {
set roadmap(value) {
this._roadmap = value;
this.$.summary = null;
if (!value) return;
this.loadData();
}
get roadmap() {
return this._roadmap;
}
loadData() {
const filter = {
include: [
{relation: 'supplier'},
{relation: 'worker'},
{relation: 'expeditionTruck',
scope: {
include: [
{relation: 'warehouse'}
]
}}
]
};
this.$http.get(`Roadmaps/${this.roadmap.id}`, {filter})
.then(res => this.$.summary = res.data);
}
getETD() {
const eta = new Date(this.roadmap.etd);
eta.setDate(eta.getDate() + 1);
this.expeditionTruck = {eta: eta};
}
onAddAccept() {
try {
const data = {
roadmapFk: this.roadmap.id,
warehouseFk: this.expeditionTruck.warehouseFk,
eta: this.expeditionTruck.eta,
description: this.expeditionTruck.description
};
this.$http.post(`ExpeditionTrucks`, data)
.then(() => {
this.loadData();
this.vnApp.showSuccess(this.$t('Data saved!'));
});
} catch (e) {
this.vnApp.showError(this.$t(e.message));
}
}
}
ngModule.component('vnRoadmapSummary', {
template: require('./index.html'),
controller: Controller,
bindings: {
roadmap: '<'
}
});

View File

@ -0,0 +1,3 @@
Stops: Paradas
Wharehouse: Almacén
You must fill all the fields: Debes rellenar todos los campos

View File

@ -0,0 +1,10 @@
@import "variables";
vn-roadmap-summary .summary {
a {
display: flex;
align-items: center;
height: 18.328px;
}
}

View File

@ -7,12 +7,17 @@
"menus": {
"main": [
{"state": "route.index", "icon": "icon-delivery"},
{"state": "route.agencyTerm.index", "icon": "icon-agency-term"}
{"state": "route.agencyTerm.index", "icon": "icon-agency-term"},
{"state": "route.roadmap", "icon": "icon-trailer"}
],
"card": [
{"state": "route.card.basicData", "icon": "settings"},
{"state": "route.card.tickets", "icon": "icon-ticket"},
{"state": "route.card.log", "icon": "history"}
],
"roadmap": [
{"state": "route.roadmap.card.basicData", "icon": "settings"},
{"state": "route.roadmap.card.stops", "icon": "icon-lines"}
]
},
"routes": [
@ -90,6 +95,46 @@
"route": "$ctrl.route"
},
"acl": ["delivery"]
}, {
"url": "/roadmap?q",
"state": "route.roadmap",
"component": "vn-roadmap",
"description": "Roadmaps"
}, {
"url": "/create",
"state": "route.roadmap.create",
"component": "vn-roadmap-create",
"description": "Create roadmap"
},{
"url": "/:id",
"state": "route.roadmap.card",
"component": "vn-roadmap-card",
"abstract": true,
"description": "Detail"
},{
"url": "/summary",
"state": "route.roadmap.card.summary",
"component": "vn-roadmap-summary",
"description": "Summary",
"params": {
"roadmap": "$ctrl.roadmap"
}
},{
"url": "/basic-data",
"state": "route.roadmap.card.basicData",
"component": "vn-roadmap-basic-data",
"description": "Basic data",
"params": {
"roadmap": "$ctrl.roadmap"
}
}, {
"url": "/stops",
"state": "route.roadmap.card.stops",
"component": "vn-roadmap-stops",
"description": "Stops",
"params": {
"route": "$ctrl.roadmap"
}
}
]
}

View File

@ -7,7 +7,7 @@
ng-click="deleteShelving.show()"
name="deleteShelving"
translate>
Delete
Delete shelving
</vn-item>
</slot-menu>
<slot-body>
@ -32,7 +32,7 @@
</slot-body>
</vn-descriptor-content>
<vn-confirm
vn-id="delete-shelving"
vn-id="deleteShelving"
on-accept="$ctrl.onDelete()"
question="Are you sure you want to continue?"
message="Shelving will be removed">
@ -40,6 +40,6 @@
<vn-popup vn-id="summary">
<vn-shelving-summary shelving="$ctrl.shelving"></vn-shelving-summary>
</vn-popup>
<vn-worker-descriptor-popover
<vn-worker-descriptor-popover
vn-id="workerDescriptor">
</vn-worker-descriptor-popover>
</vn-worker-descriptor-popover>

View File

@ -0,0 +1,3 @@
Delete shelving: Eliminar carro
Shelving will be removed: El carro será eliminado
Shelving removed: Carro eliminado

View File

@ -67,7 +67,7 @@ module.exports = function(Self) {
throw new UserError(`This ticket is already invoiced`);
const priceZero = ticket.totalWithVat == 0;
if (priceZero)
if (ticketsIds.length == 1 && priceZero)
throw new UserError(`A ticket with an amount of zero can't be invoiced`);
});

View File

@ -60,6 +60,9 @@
},
"totalWithoutVat": {
"type": "number"
},
"weight": {
"type": "number"
}
},
"relations": {

View File

@ -101,23 +101,33 @@
translate>
Change shipped hour
</vn-item>
<vn-item
ng-click="$ctrl.sendPaymentSms()"
name="sendPaymentSms"
<vn-item class="dropdown"
vn-click-stop="sendDeliveryNoteMenu.show($event, 'left');"
name="smsOptions"
translate>
SMS Pending payment
</vn-item>
<vn-item
ng-click="$ctrl.sendImportSms()"
name="sendImportSms"
translate>
SMS Minimum import
</vn-item>
<vn-item
ng-click="$ctrl.sendChangesSms()"
name="sendChangesSms"
translate>
SMS Notify changes
Send SMS...
<vn-menu vn-id="sendDeliveryNoteMenu">
<vn-list>
<vn-item
ng-click="$ctrl.sendPaymentSms()"
name="sendPaymentSms"
translate>
Pending payment
</vn-item>
<vn-item
ng-click="$ctrl.sendImportSms()"
name="sendImportSms"
translate>
Minimum import
</vn-item>
<vn-item
ng-click="$ctrl.sendChangesSms()"
name="sendChangesSms"
translate>
Notify changes
</vn-item>
</vn-list>
</vn-menu>
</vn-item>
<vn-item
ng-click="makeInvoiceConfirmation.show()"
@ -163,6 +173,12 @@
</vn-list>
</vn-menu>
</vn-item>
<vn-item
ng-click="setTicketWeight.show()"
vn-acl="deliveryBoss"
translate>
Set ticket weight
</vn-item>
</vn-list>
</vn-menu>
@ -348,3 +364,28 @@
question="Are you sure you want to replace this delivery note?"
message="Already exist signed delivery note">
</vn-confirm>
<!-- Set ticket weight -->
<vn-dialog
vn-id="setTicketWeight"
title="TicketWeight"
size="sm"
on-accept="$ctrl.setTicketWeight($ctrl.ticket.weight)">
<tpl-body>
<vn-input-number
label="Ticket weight"
ng-model="$ctrl.ticket.weight">
</vn-input-number>
</tpl-body>
<tpl-buttons>
<button response="accept" translate>Accept</button>
</tpl-buttons>
</vn-dialog>
<!-- Without weight confirmation dialog -->
<vn-confirm
vn-id="withoutWeightConfirmation"
on-accept="$ctrl.makeInvoice(true)"
question="This address has incoterms, you should set the weight before invoice it"
message="Are you sure you want to invoice this ticket?">
</vn-confirm>

View File

@ -249,16 +249,11 @@ class Controller extends Section {
this.$.sms.open();
}
makeInvoice() {
const params = {ticketsIds: [this.id]};
/*
This should call the notification sistem to insert a new notification
in te queue, yet to check how to handle user permissions,
as of 08-11-2022 every employee can insert a new notification in the queue
makeInvoice(force) {
if (this.ticket.address.incotermsFk && !this.ticket.weight && !force)
return this.$.withoutWeightConfirmation.show();
*/
const client = this.ticket.client;
if (client.hasElectronicInvoice) {
this.$http.post(`NotificationQueues`, {
notificationFk: 'invoice-electronic',
@ -275,7 +270,7 @@ class Controller extends Section {
});
}
return this.$http.post(`Tickets/invoiceTickets`, params)
return this.$http.post(`Tickets/invoiceTickets`, {ticketsIds: [this.id]})
.then(() => this.reload())
.then(() => this.vnApp.showSuccess(this.$t('Ticket invoiced')));
}
@ -331,6 +326,15 @@ class Controller extends Section {
this.vnApp.showSuccess(this.$t('PDF sent!'));
});
}
setTicketWeight(weight) {
return this.$http.patch(`Tickets/${this.ticket.id}`, {weight})
.then(() => {
this.$.setTicketWeight.hide();
this.vnApp.showSuccess(this.$t('Data saved!'));
this.reload();
});
}
}
Controller.$inject = ['$element', '$scope', 'vnReport', 'vnEmail'];

View File

@ -198,6 +198,17 @@ describe('Ticket Component vnTicketDescriptorMenu', () => {
expect(controller.reload).toHaveBeenCalledWith();
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
});
it('should show withoutWeightConfirmation', () => {
controller.$.withoutWeightConfirmation = {show: () => {}};
jest.spyOn(controller.$.withoutWeightConfirmation, 'show');
controller.ticket.address.incotermsFk = true;
controller.makeInvoice();
controller.ticket.address.incotermsFk = false;
expect(controller.$.withoutWeightConfirmation.show).toHaveBeenCalled();
});
});
describe('createPdfInvoice()', () => {

View File

@ -16,8 +16,14 @@ without warehouse: sin almacén
Invoice sent: Factura enviada
The following refund ticket have been created: "Se ha creado siguiente ticket de abono: {{ticketId}}"
Transfer client: Transferir cliente
SMS Notify changes: SMS Notificar cambios
Send SMS...: Enviar SMS...
Notify changes: Notificar cambios
Minimum import: Importe mínimo
Pending payment: Pago pendiente
PDF sent!: ¡PDF enviado!
Already exist signed delivery note: Ya existe albarán de entrega firmado
Are you sure you want to replace this delivery note?: ¿Seguro que quieres reemplazar este albarán de entrega?
Create a single ticket with all the content of the current ticket: Crea un ticket único con todo el contenido del ticket actual
Set ticket weight: Establecer peso al ticket
Ticket weight: Peso del ticket
This address has incoterms, you should set the weight before invoice it: Este consigatario tiene incoterms, deberías establecer el peso antes de facturar

View File

@ -17,8 +17,6 @@ Shipped hour updated: Hora de envio modificada
Deleted ticket: Ticket eliminado
Recalculate components: Recalcular componentes
Are you sure you want to recalculate the components?: ¿Seguro que quieres recalcular los componentes?
SMS Minimum import: 'SMS Importe minimo'
SMS Pending payment: 'SMS Pago pendiente'
Restore ticket: Restaurar ticket
You are going to restore this ticket: Vas a restaurar este ticket
Are you sure you want to restore this ticket?: ¿Seguro que quieres restaurar el ticket?

View File

@ -65,6 +65,11 @@
{{$ctrl.summary.refFk | dashIfEmpty}}
</span>
</vn-label-value>
<vn-label-value label="Weight">
<span>
{{$ctrl.summary.weight | dashIfEmpty}}
</span>
</vn-label-value>
</vn-one>
<vn-two>
<vn-label-value label="Shipped"

View File

@ -25,8 +25,7 @@
"type" : "string"
},
"userFk": {
"type" : "number",
"required": true
"type" : "number"
},
"bossFk": {
"type" : "number"

View File

@ -38,7 +38,7 @@
</vn-textfield>
<vn-textfield
vn-one
label="Code"
label="Worker code"
ng-model="$ctrl.worker.code"
maxLength="3"
on-change="$ctrl.worker.code = $ctrl.worker.code.toUpperCase()"

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