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

This commit is contained in:
Joan Sanchez 2019-11-19 13:07:21 +01:00
commit 615cfe15cc
114 changed files with 1841 additions and 1492 deletions

View File

@ -62,7 +62,7 @@ module.exports = Self => {
*/ */
Self.hasRole = async function(userId, name) { Self.hasRole = async function(userId, name) {
let roles = await Self.getRoles(userId); let roles = await Self.getRoles(userId);
return roles.find(role => role == name); return roles.some(role => role == name);
}; };
/** /**

View File

@ -26,6 +26,12 @@ CREATE TABLE `vn`.`zoneEvent` (
CONSTRAINT `zoneEvent_ibfk_1` FOREIGN KEY (`zoneFk`) REFERENCES `zone` (`id`) ON DELETE CASCADE ON UPDATE CASCADE CONSTRAINT `zoneEvent_ibfk_1` FOREIGN KEY (`zoneFk`) REFERENCES `zone` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=31 DEFAULT CHARSET=utf8; ) ENGINE=InnoDB AUTO_INCREMENT=31 DEFAULT CHARSET=utf8;
ALTER TABLE `vn`.`zoneEvent`
ADD COLUMN `type` ENUM('day', 'indefinitely', 'range') NOT NULL AFTER `zoneFk`,
ADD COLUMN `dated` DATE NULL DEFAULT NULL AFTER `type`,
CHANGE COLUMN `from` `started` DATE NULL DEFAULT NULL ,
CHANGE COLUMN `to` `ended` DATE NULL DEFAULT NULL ;
CREATE TABLE `vn`.`zoneExclusion` ( CREATE TABLE `vn`.`zoneExclusion` (
`id` int(11) NOT NULL AUTO_INCREMENT, `id` int(11) NOT NULL AUTO_INCREMENT,
`zoneFk` int(11) NOT NULL, `zoneFk` int(11) NOT NULL,
@ -45,3 +51,6 @@ ADD CONSTRAINT `fk_zone_1`
REFERENCES `vn`.`warehouse` (`id`) REFERENCES `vn`.`warehouse` (`id`)
ON DELETE NO ACTION ON DELETE NO ACTION
ON UPDATE CASCADE; ON UPDATE CASCADE;
ALTER TABLE `vn`.`zoneExclusion`
CHANGE COLUMN `day` `dated` DATE NOT NULL ;

View File

@ -37,11 +37,11 @@ BEGIN
WHERE z.agencyModeFk != vAgencyModeFk; WHERE z.agencyModeFk != vAgencyModeFk;
END IF; END IF;
SELECT e.`from`, e.`to`, e.weekDays SELECT e.`type`, e.dated, e.`started`, e.`ended`, e.weekDays
FROM tmp.zone t FROM tmp.zone t
JOIN zoneEvent e ON e.zoneFk = t.id; JOIN zoneEvent e ON e.zoneFk = t.id;
SELECT DISTINCT e.`day` SELECT DISTINCT e.dated
FROM tmp.zone t FROM tmp.zone t
JOIN zoneExclusion e ON e.zoneFk = t.id; JOIN zoneExclusion e ON e.zoneFk = t.id;

View File

@ -1,79 +0,0 @@
DROP PROCEDURE IF EXISTS `vn`.`zone_getOptionsForLanding`;
DELIMITER $$
CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`zone_getOptionsForLanding`(vLanded DATE)
BEGIN
/**
* Gets computed options for the passed zones and delivery date.
*
* @table tmp.zones(id) The zones ids
* @param vLanded The delivery date
* @return tmp.zoneOption The computed options
*/
DECLARE vHour TIME DEFAULT TIME(NOW());
DROP TEMPORARY TABLE IF EXISTS tTemp;
CREATE TEMPORARY TABLE tTemp
ENGINE = MEMORY
SELECT t.id zoneFk,
TIME(e.`hour`) `hour`,
e.travelingDays,
e.price,
e.bonus,
CASE
WHEN e.`from` IS NULL AND e.`to` IS NULL
THEN 3
WHEN e.`to` IS NULL
THEN 2
ELSE 1
END specificity
FROM tmp.zone t
JOIN zoneEvent e ON e.zoneFk = t.id
WHERE (e.`from` = vLanded AND e.`to` IS NULL)
OR (
(e.`from` IS NULL OR vLanded BETWEEN e.`from` AND e.`to`)
AND e.weekDays & (1 << WEEKDAY(vLanded))
);
-- XXX: Compatibility with the deprecated #zoneCalendar table
INSERT INTO tTemp
SELECT t.id zoneFk,
NULL,
NULL,
c.price,
c.bonus,
4
FROM tmp.zone t
JOIN zoneCalendar c ON c.zoneFk = t.id
WHERE c.delivered = vLanded;
DELETE t FROM tTemp t
JOIN zoneExclusion e
ON e.zoneFk = t.zoneFk AND e.`day` = vLanded;
UPDATE tTemp t
JOIN zone z ON z.id = t.zoneFk
SET t.`hour` = IFNULL(t.`hour`, TIME(z.`hour`)),
t.travelingDays = IFNULL(t.travelingDays, z.travelingDays),
t.price = IFNULL(t.price, z.price),
t.bonus = IFNULL(t.bonus, z.bonus);
DELETE FROM tTemp
WHERE (@shipped := TIMESTAMPADD(DAY, -travelingDays, vLanded)) < CURDATE()
OR @shipped = CURDATE() AND vHour > `hour`;
DROP TEMPORARY TABLE IF EXISTS tmp.zoneOption;
CREATE TEMPORARY TABLE tmp.zoneOption
ENGINE = MEMORY
SELECT *
FROM (
SELECT * FROM tTemp
ORDER BY zoneFk, specificity
) t
GROUP BY zoneFk;
DROP TEMPORARY TABLE tTemp;
END$$
DELIMITER ;

View File

@ -28,7 +28,7 @@ BEGIN
JOIN zone z ON z.id = zo.zoneFk JOIN zone z ON z.id = zo.zoneFk
JOIN zoneWarehouse zw ON zw.zoneFk = z.id JOIN zoneWarehouse zw ON zw.zoneFk = z.id
WHERE agencyModeFk = vAgencyModeFk WHERE agencyModeFk = vAgencyModeFk
AND warehouseFk = vWarehouseFk; AND zw.warehouseFk = vWarehouseFk;
DROP TEMPORARY TABLE DROP TEMPORARY TABLE
tmp.zone, tmp.zone,

View File

@ -0,0 +1,67 @@
USE `vn`;
DROP procedure IF EXISTS `zone_getOptionsForLanding`;
DELIMITER $$
USE `vn`$$
CREATE DEFINER=`root`@`%` PROCEDURE `zone_getOptionsForLanding`(vLanded DATE)
BEGIN
/**
* Gets computed options for the passed zones and delivery date.
*
* @table tmp.zones(id) The zones ids
* @param vLanded The delivery date
* @return tmp.zoneOption The computed options
*/
DECLARE vHour TIME DEFAULT TIME(NOW());
DROP TEMPORARY TABLE IF EXISTS tTemp;
CREATE TEMPORARY TABLE tTemp
ENGINE = MEMORY
SELECT t.id zoneFk,
IFNULL(TIME(e.`hour`), TIME(z.`hour`)) `hour`,
IFNULL(e.travelingDays, z.travelingDays) travelingDays,
IFNULL(e.price, z.price) price,
IFNULL(e.bonus, z.bonus) bonus,
CASE
WHEN e.`type` = 'day'
THEN 1
WHEN e.`type` = 'range'
THEN 2
ELSE 3
END specificity
FROM tmp.zone t
JOIN zone z ON z.id = t.id
JOIN zoneEvent e ON e.zoneFk = t.id
WHERE (
e.`type` = 'day'
AND e.dated = vLanded
) OR (
e.`type` != 'day'
AND e.weekDays & (1 << WEEKDAY(vLanded))
AND (e.`started` IS NULL OR vLanded >= e.`started`)
AND (e.`ended` IS NULL OR vLanded <= e.`ended`)
);
DELETE t FROM tTemp t
JOIN zoneExclusion e
ON e.zoneFk = t.zoneFk AND e.`dated` = vLanded;
DELETE FROM tTemp
WHERE (@shipped := TIMESTAMPADD(DAY, -travelingDays, vLanded)) < CURDATE()
OR @shipped = CURDATE() AND vHour > `hour`;
DROP TEMPORARY TABLE IF EXISTS tmp.zoneOption;
CREATE TEMPORARY TABLE tmp.zoneOption
ENGINE = MEMORY
SELECT *
FROM (
SELECT * FROM tTemp
ORDER BY zoneFk, specificity
) t
GROUP BY zoneFk;
DROP TEMPORARY TABLE tTemp;
END$$
DELIMITER ;

View File

@ -0,0 +1,76 @@
USE `vn`;
DROP procedure IF EXISTS `zone_getOptionsForShipment`;
DELIMITER $$
USE `vn`$$
CREATE DEFINER=`root`@`%` PROCEDURE `zone_getOptionsForShipment`(vShipped DATE)
BEGIN
/**
* Gets computed options for the passed zones and shipping date.
*
* @table tmp.zones(id) The zones ids
* @param vShipped The shipping date
* @return tmp.zoneOption(zoneFk, hour, travelingDays, price, bonus, specificity) The computed options
*/
DROP TEMPORARY TABLE IF EXISTS tLandings;
CREATE TEMPORARY TABLE tLandings
(INDEX (eventFk))
ENGINE = MEMORY
SELECT e.id eventFk,
@travelingDays := IFNULL(e.travelingDays, z.travelingDays) travelingDays,
TIMESTAMPADD(DAY, @travelingDays, vShipped) landed
FROM tmp.zone t
JOIN zone z ON z.id = t.id
JOIN zoneEvent e ON e.zoneFk = t.id;
DROP TEMPORARY TABLE IF EXISTS tTemp;
CREATE TEMPORARY TABLE tTemp
ENGINE = MEMORY
SELECT t.id zoneFk,
IFNULL(TIME(e.`hour`), TIME(z.`hour`)) `hour`,
IFNULL(e.price, z.price) price,
IFNULL(e.bonus, z.bonus) bonus,
CASE
WHEN e.`type` = 'day'
THEN 1
WHEN e.`type` = 'range'
THEN 2
ELSE 3
END specificity,
l.travelingDays,
l.landed
FROM tmp.zone t
JOIN zone z ON z.id = t.id
JOIN zoneEvent e ON e.zoneFk = t.id
JOIN tLandings l ON l.eventFk = e.id
WHERE (
e.`type` = 'day'
AND e.`dated` = l.landed
) OR (
e.`type` != 'day'
AND e.weekDays & (1 << WEEKDAY(l.landed))
AND (e.`started` IS NULL OR l.landed >= e.`started`)
AND (e.`ended` IS NULL OR l.landed <= e.`ended`)
);
DELETE t FROM tTemp t
JOIN zoneExclusion e
ON e.zoneFk = t.zoneFk AND e.`dated` = t.landed;
DROP TEMPORARY TABLE IF EXISTS tmp.zoneOption;
CREATE TEMPORARY TABLE tmp.zoneOption
ENGINE = MEMORY
SELECT *
FROM (
SELECT * FROM tTemp
ORDER BY zoneFk, specificity
) t
GROUP BY zoneFk;
DROP TEMPORARY TABLE
tTemp,
tLandings;
END$$
DELIMITER ;

View File

@ -1,88 +0,0 @@
USE `vn`;
DROP procedure IF EXISTS `ticketCreateWithUser`;
DELIMITER $$
USE `vn`$$
CREATE DEFINER=`root`@`%` PROCEDURE `ticketCreateWithUser`(
vClientId INT
,vShipped DATE
,vWarehouseFk INT
,vCompanyFk INT
,vAddressFk INT
,vAgencyModeFk INT
,vRouteFk INT
,vlanded DATE
,vUserId INT
,OUT vNewTicket INT)
BEGIN
DECLARE vZoneFk INT;
IF vClientId IS NULL THEN
CALL util.throw ('CLIENT_NOT_ESPECIFIED');
END IF;
IF NOT vAddressFk OR vAddressFk IS NULL THEN
SELECT id INTO vAddressFk
FROM address
WHERE clientFk = vClientId AND isDefaultAddress;
END IF;
IF vAgencyModeFk IS NOT NULL THEN
CALL vn.zone_getShippedWarehouse(vlanded, vAddressFk, vAgencyModeFk);
SELECT zoneFk INTO vZoneFk FROM tmp.zoneGetShipped
WHERE shipped = vShipped AND warehouseFk = vWarehouseFk LIMIT 1;
IF vZoneFk IS NULL OR vZoneFk = 0 THEN
CALL util.throw ('NOT_ZONE_WITH_THIS_PARAMETERS');
END IF;
END IF;
INSERT INTO vn2008.Tickets (
Id_Cliente,
Fecha,
Id_Consigna,
Id_Agencia,
Alias,
warehouse_id,
Id_Ruta,
empresa_id,
landing,
zoneFk
)
SELECT
vClientId,
vShipped,
a.id,
vAgencyModeFk,
a.nickname,
vWarehouseFk,
IF(vRouteFk,vRouteFk,NULL),
vCompanyFk,
vlanded,
vZoneFk
FROM address a
JOIN agencyMode am ON am.id = a.agencyModeFk
WHERE a.id = vAddressFk;
SET vNewTicket = LAST_INSERT_ID();
INSERT INTO ticketObservation(ticketFk, observationTypeFk, description)
SELECT vNewTicket, ao.observationTypeFk, ao.description
FROM addressObservation ao
JOIN address a ON a.id = ao.addressFk
WHERE a.id = vAddressFk;
INSERT INTO vn.ticketLog
SET originFk = vNewTicket, userFk = vUserId, `action` = 'insert', description = CONCAT('Ha creado el ticket:', ' ', vNewTicket);
IF (SELECT ct.isCreatedAsServed FROM vn.clientType ct JOIN vn.client c ON c.typeFk = ct.code WHERE c.id = vClientId ) <> FALSE THEN
INSERT INTO vncontrol.inter(state_id, Id_Ticket, Id_Trabajador)
SELECT id, vNewTicket, getWorker()
FROM state
WHERE `code` = 'DELIVERED';
END IF;
END$$
DELIMITER ;

View File

@ -1,83 +0,0 @@
USE `vn`;
DROP procedure IF EXISTS `vn`.`zone_getOptionsForLanding`;
DELIMITER $$
USE `vn`$$
CREATE DEFINER=`root`@`%` PROCEDURE `zone_getOptionsForLanding`(vLanded DATE)
BEGIN
/**
* Gets computed options for the passed zones and delivery date.
*
* @table tmp.zones(id) The zones ids
* @param vLanded The delivery date
* @return tmp.zoneOption The computed options
*/
DECLARE vHour TIME DEFAULT TIME(NOW());
DROP TEMPORARY TABLE IF EXISTS tTemp;
CREATE TEMPORARY TABLE tTemp
ENGINE = MEMORY
SELECT t.id zoneFk,
TIME(e.`hour`) `hour`,
e.travelingDays,
e.price,
e.bonus,
CASE
WHEN e.`from` IS NULL AND e.`to` IS NULL
THEN 3
WHEN e.`to` IS NULL
THEN 2
ELSE 1
END specificity
FROM tmp.zone t
JOIN zoneEvent e ON e.zoneFk = t.id
WHERE (e.`from` = vLanded AND e.`to` IS NULL)
OR (
(e.`from` IS NULL OR vLanded BETWEEN e.`from` AND e.`to`)
AND e.weekDays & (1 << WEEKDAY(vLanded))
);
-- XXX: Compatibility with the deprecated #zoneCalendar table
INSERT INTO tTemp
SELECT t.id zoneFk,
NULL,
NULL,
c.price,
c.bonus,
4
FROM tmp.zone t
JOIN zoneCalendar c ON c.zoneFk = t.id
WHERE c.delivered = vLanded;
DELETE t FROM tTemp t
JOIN zoneExclusion e
ON e.zoneFk = t.zoneFk AND e.`day` = vLanded;
UPDATE tTemp t
JOIN zone z ON z.id = t.zoneFk
SET t.`hour` = IFNULL(t.`hour`, TIME(z.`hour`)),
t.travelingDays = IFNULL(t.travelingDays, z.travelingDays),
t.price = IFNULL(t.price, z.price),
t.bonus = IFNULL(t.bonus, z.bonus);
DELETE FROM tTemp
WHERE (@shipped := TIMESTAMPADD(DAY, -travelingDays, vLanded)) < CURDATE()
OR @shipped = CURDATE() AND vHour > `hour`;
DROP TEMPORARY TABLE IF EXISTS tmp.zoneOption;
CREATE TEMPORARY TABLE tmp.zoneOption
ENGINE = MEMORY
SELECT *
FROM (
SELECT * FROM tTemp
ORDER BY zoneFk, specificity
) t
GROUP BY zoneFk;
DROP TEMPORARY TABLE tTemp;
END$$
DELIMITER ;
;

View File

@ -1,65 +0,0 @@
USE `vn`;
DROP procedure IF EXISTS `zone_getOptionsForShipment`;
DELIMITER $$
USE `vn`$$
CREATE DEFINER=`root`@`%` PROCEDURE `zone_getOptionsForShipment`(vShipped DATE)
BEGIN
/**
* Gets computed options for the passed zones and shipping date.
*
* @table tmp.zones(id) The zones ids
* @param vShipped The shipping date
* @return tmp.zoneOption(zoneFk, hour, travelingDays, price, bonus, specificity) The computed options
*/
DECLARE vHour TIME DEFAULT TIME(NOW());
DROP TEMPORARY TABLE IF EXISTS tTemp;
CREATE TEMPORARY TABLE tTemp
ENGINE = MEMORY
SELECT t.id zoneFk,
TIME(e.`hour`) `hour`,
e.travelingDays,
e.price,
e.bonus,
CASE
WHEN e.`from` IS NULL AND e.`to` IS NULL
THEN 3
WHEN e.`to` IS NULL
THEN 2
ELSE 1
END specificity
FROM tmp.zone t
JOIN zoneEvent e ON e.zoneFk = t.id
WHERE (e.`from` = TIMESTAMPADD(DAY, e.travelingDays, vShipped) AND e.`to` IS NULL)
OR (
(e.`from` IS NULL OR TIMESTAMPADD(DAY, e.travelingDays, vShipped) BETWEEN e.`from` AND e.`to`)
AND e.weekDays & (1 << WEEKDAY(TIMESTAMPADD(DAY, e.travelingDays, vShipped)))
);
DELETE t FROM tTemp t
JOIN zoneExclusion e
ON e.zoneFk = t.zoneFk AND TIMESTAMPADD(DAY,-t.travelingDays, e.`day`) = vShipped;
UPDATE tTemp t
JOIN zone z ON z.id = t.zoneFk
SET t.`hour` = IFNULL(t.`hour`, TIME(z.`hour`)),
t.travelingDays = IFNULL(t.travelingDays, z.travelingDays),
t.price = IFNULL(t.price, z.price),
t.bonus = IFNULL(t.bonus, z.bonus);
DROP TEMPORARY TABLE IF EXISTS tmp.zoneOption;
CREATE TEMPORARY TABLE tmp.zoneOption
ENGINE = MEMORY
SELECT *
FROM (
SELECT * FROM tTemp
ORDER BY zoneFk, specificity
) t
GROUP BY zoneFk;
DROP TEMPORARY TABLE tTemp;
END$$
DELIMITER ;

View File

@ -0,0 +1,7 @@
USE `vn`;
ALTER TABLE `vn`.`payMethod`
ADD COLUMN `code` VARCHAR(50) CHARACTER SET 'utf8' COLLATE 'utf8_general_ci' NULL AFTER `id`;
UPDATE `vn`.`payMethod` SET `code` = 'bankDraft' WHERE (`id` = '4');
UPDATE `vn`.`payMethod` SET `code` = 'card' WHERE (`id` = '5');

View File

@ -0,0 +1,116 @@
USE `vn`;
DROP procedure IF EXISTS `ticketClosure`;
DELIMITER $$
USE `vn`$$
CREATE DEFINER=`root`@`%` PROCEDURE `ticketClosure`()
BEGIN
/**
* Realiza el cierre de todos los
* tickets de la table ticketClosure.
*/
DECLARE vDone BOOL;
DECLARE vClientFk INT;
DECLARE vTicketFk INT;
DECLARE vIsTaxDataChecked BOOL;
DECLARE vCompanyFk INT;
DECLARE vShipped DATE;
DECLARE vPriority INT DEFAULT 1;
DECLARE vReportDeliveryNote INT DEFAULT 1;
DECLARE vNewInvoiceId INT;
DECLARE vHasDailyInvoice BOOL;
DECLARE vWithPackage BOOL;
DECLARE cur CURSOR FOR
SELECT ticketFk FROM tmp.ticketClosure;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE;
DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN
RESIGNAL;
END;
DROP TEMPORARY TABLE IF EXISTS tmp.ticketClosure2;
CREATE TEMPORARY TABLE tmp.ticketClosure2
SELECT ticketFk FROM tmp.ticketClosure;
INSERT INTO tmp.ticketClosure
SELECT id FROM stowaway s
JOIN tmp.ticketClosure2 tc ON s.shipFk = tc.ticketFk;
OPEN cur;
proc: LOOP
SET vDone = FALSE;
FETCH cur INTO vTicketFk;
IF vDone THEN
LEAVE proc;
END IF;
-- ticketClosure start
SELECT
c.id,
c.isTaxDataChecked,
t.companyFk,
t.shipped,
co.hasDailyInvoice,
w.isManaged
INTO vClientFk,
vIsTaxDataChecked,
vCompanyFk,
vShipped,
vHasDailyInvoice,
vWithPackage
FROM ticket t
JOIN `client` c ON c.id = t.clientFk
JOIN province p ON p.id = c.provinceFk
JOIN country co ON co.id = p.countryFk
JOIN warehouse w ON w.id = t.warehouseFk
WHERE t.id = vTicketFk;
INSERT INTO ticketPackaging (ticketFk, packagingFk, quantity)
(SELECT vTicketFk, p.id, COUNT(*)
FROM expedition e
JOIN packaging p ON p.itemFk = e.itemFk
WHERE e.ticketFk = vTicketFk AND p.isPackageReturnable
AND vWithPackage
GROUP BY p.itemFk);
-- No retornables o no catalogados
INSERT INTO sale (itemFk, ticketFk, concept, quantity, price, isPriceFixed)
(SELECT e.itemFk, vTicketFk, i.name, COUNT(*) AS amount, getSpecialPrice(e.itemFk, vClientFk), 1
FROM expedition e
JOIN item i ON i.id = e.itemFk
LEFT JOIN packaging p ON p.itemFk = i.id
WHERE e.ticketFk = vTicketFk AND IFNULL(p.isPackageReturnable, 0) = 0
AND getSpecialPrice(e.itemFk, vClientFk) > 0
GROUP BY e.itemFk);
IF(vHasDailyInvoice) THEN
-- Facturacion rapida
CALL ticketTrackingAdd(vTicketFk, 'DELIVERED', NULL);
-- Facturar si está contabilizado
IF vIsTaxDataChecked THEN
CALL invoiceOut_newFromClient(
vClientFk,
(SELECT invoiceSerial(vClientFk, vCompanyFk, 'M')),
vShipped,
vCompanyFk,
NULL,
vNewInvoiceId);
END IF;
ELSE
-- Albaran_print
CALL ticketTrackingAdd(vTicketFk, (SELECT vn.getAlert3State(vTicketFk)), NULL);
END IF;
-- ticketClosure end
END LOOP;
CLOSE cur;
DROP TEMPORARY TABLE IF EXISTS tmp.ticketClosure2;
END$$
DELIMITER ;

View File

@ -84,3 +84,25 @@ BEGIN
END IF; END IF;
END$$ END$$
DELIMITER ; DELIMITER ;
USE `vn`;
CREATE
OR REPLACE ALGORITHM = UNDEFINED
DEFINER = `root`@`%`
SQL SECURITY DEFINER
VIEW `vn`.`ticketRequest__` AS
SELECT
`t`.`Id_ORDEN` AS `id`,
`t`.`ORDEN` AS `description`,
`t`.`requesterFk` AS `requesterFk`,
`t`.`attenderFk` AS `attenderFk`,
`t`.`CANTIDAD` AS `quantity`,
`t`.`Id_ARTICLE` AS `itemFk`,
`t`.`PRECIOMAX` AS `price`,
`t`.`isOk` AS `isOk`,
`t`.`Id_Movimiento` AS `saleFk`,
`t`.`ticketFk` AS `ticketFk`,
`t`.`COMENTARIO` AS `response`,
`t`.`odbc_date` AS `created`
FROM
`vn2008`.`Ordenes` `t`;

View File

@ -62,13 +62,13 @@ INSERT INTO `vn`.`country`(`id`, `country`, `isUeeMember`, `code`, `currencyFk`,
(19,'Francia', 1, 'FR', 1, 27), (19,'Francia', 1, 'FR', 1, 27),
(30,'Canarias', 1, 'IC', 1, 24); (30,'Canarias', 1, 'IC', 1, 24);
INSERT INTO `vn`.`warehouse`(`id`, `name`, `isComparative`, `isInventory`, `hasAvailable`, `isManaged`, `hasStowaway`, `hasDms`) INSERT INTO `vn`.`warehouse`(`id`, `name`, `isComparative`, `isInventory`, `hasAvailable`, `isManaged`, `hasStowaway`, `hasDms`, `hasComission`)
VALUES VALUES
(1, 'Warehouse One', 1, 1, 1, 1, 1, 1), (1, 'Warehouse One', 1, 1, 1, 1, 1, 1, 1),
(2, 'Warehouse Two', 1, 1, 1, 1, 0, 0), (2, 'Warehouse Two', 1, 1, 1, 1, 0, 0, 1),
(3, 'Warehouse Three', 1, 1, 1, 1, 0, 0), (3, 'Warehouse Three', 1, 1, 1, 1, 0, 0, 0),
(4, 'Warehouse Four', 1, 1, 1, 1, 0, 0), (4, 'Warehouse Four', 1, 1, 1, 1, 0, 0, 0),
(5, 'Warehouse Five', 1, 1, 1, 1, 0, 0); (5, 'Warehouse Five', 1, 1, 1, 1, 0, 0, 0);
INSERT INTO `vn`.`sector`(`id`, `description`, `warehouseFk`, `isPreviousPreparedByPacking`, `code`, `pickingPlacement`, `path`) INSERT INTO `vn`.`sector`(`id`, `description`, `warehouseFk`, `isPreviousPreparedByPacking`, `code`, `pickingPlacement`, `path`)
VALUES VALUES
@ -1619,227 +1619,227 @@ INSERT INTO `vn`.`zoneIncluded` (`zoneFk`, `geoFk`, `isIncluded`)
(8, 5, 0), (8, 5, 0),
(8, 1, 1); (8, 1, 1);
INSERT INTO `vn`.`zoneEvent`(`zoneFk`, `from`) INSERT INTO `vn`.`zoneEvent`(`zoneFk`, `type`, `dated`)
VALUES VALUES
(1, DATE_ADD(CURDATE(), INTERVAL (IF(DAYOFWEEK(CURDATE())<=2, 2, 9 ) - DAYOFWEEK(CURDATE())) DAY)), (1, 'day', DATE_ADD(CURDATE(), INTERVAL (IF(DAYOFWEEK(CURDATE())<=2, 2, 9 ) - DAYOFWEEK(CURDATE())) DAY)),
(1, DATE_ADD(CURDATE(), INTERVAL (IF(DAYOFWEEK(CURDATE())<=3, 3, 10) - DAYOFWEEK(CURDATE())) DAY)), (1, 'day', DATE_ADD(CURDATE(), INTERVAL (IF(DAYOFWEEK(CURDATE())<=3, 3, 10) - DAYOFWEEK(CURDATE())) DAY)),
(1, DATE_ADD(CURDATE(), INTERVAL (IF(DAYOFWEEK(CURDATE())<=4, 4, 11) - DAYOFWEEK(CURDATE())) DAY)), (1, 'day', DATE_ADD(CURDATE(), INTERVAL (IF(DAYOFWEEK(CURDATE())<=4, 4, 11) - DAYOFWEEK(CURDATE())) DAY)),
(1, DATE_ADD(CURDATE(), INTERVAL (IF(DAYOFWEEK(CURDATE())<=5, 5, 12) - DAYOFWEEK(CURDATE())) DAY)), (1, 'day', DATE_ADD(CURDATE(), INTERVAL (IF(DAYOFWEEK(CURDATE())<=5, 5, 12) - DAYOFWEEK(CURDATE())) DAY)),
(1, DATE_ADD(CURDATE(), INTERVAL (IF(DAYOFWEEK(CURDATE())<=6, 6, 13) - DAYOFWEEK(CURDATE())) DAY)), (1, 'day', DATE_ADD(CURDATE(), INTERVAL (IF(DAYOFWEEK(CURDATE())<=6, 6, 13) - DAYOFWEEK(CURDATE())) DAY)),
(2, DATE_ADD(CURDATE(), INTERVAL (IF(DAYOFWEEK(CURDATE())<=2, 2, 9 ) - DAYOFWEEK(CURDATE())) DAY)), (2, 'day', DATE_ADD(CURDATE(), INTERVAL (IF(DAYOFWEEK(CURDATE())<=2, 2, 9 ) - DAYOFWEEK(CURDATE())) DAY)),
(2, DATE_ADD(CURDATE(), INTERVAL (IF(DAYOFWEEK(CURDATE())<=3, 3, 10) - DAYOFWEEK(CURDATE())) DAY)), (2, 'day', DATE_ADD(CURDATE(), INTERVAL (IF(DAYOFWEEK(CURDATE())<=3, 3, 10) - DAYOFWEEK(CURDATE())) DAY)),
(2, DATE_ADD(CURDATE(), INTERVAL (IF(DAYOFWEEK(CURDATE())<=4, 4, 11) - DAYOFWEEK(CURDATE())) DAY)), (2, 'day', DATE_ADD(CURDATE(), INTERVAL (IF(DAYOFWEEK(CURDATE())<=4, 4, 11) - DAYOFWEEK(CURDATE())) DAY)),
(2, DATE_ADD(CURDATE(), INTERVAL (IF(DAYOFWEEK(CURDATE())<=5, 5, 12) - DAYOFWEEK(CURDATE())) DAY)), (2, 'day', DATE_ADD(CURDATE(), INTERVAL (IF(DAYOFWEEK(CURDATE())<=5, 5, 12) - DAYOFWEEK(CURDATE())) DAY)),
(2, DATE_ADD(CURDATE(), INTERVAL (IF(DAYOFWEEK(CURDATE())<=6, 6, 13) - DAYOFWEEK(CURDATE())) DAY)), (2, 'day', DATE_ADD(CURDATE(), INTERVAL (IF(DAYOFWEEK(CURDATE())<=6, 6, 13) - DAYOFWEEK(CURDATE())) DAY)),
(3, CURDATE()), (3, 'day', CURDATE()),
(3, DATE_ADD(CURDATE(), INTERVAL +1 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +1 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +2 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +2 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +3 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +3 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +4 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +4 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +5 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +5 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +6 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +6 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +7 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +7 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +8 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +8 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +9 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +9 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +10 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +10 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +11 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +11 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +12 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +12 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +13 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +13 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +14 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +14 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +15 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +15 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +16 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +16 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +17 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +17 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +18 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +18 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +19 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +19 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +20 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +20 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +21 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +21 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +22 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +22 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +23 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +23 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +24 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +24 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +25 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +25 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +26 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +26 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +27 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +27 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +28 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +28 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +29 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +29 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +30 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +30 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +31 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +31 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +32 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +32 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +33 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +33 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +34 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +34 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +35 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +35 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +36 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +36 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +37 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +37 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +38 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +38 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +39 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +39 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +40 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +40 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +41 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +41 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +42 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +42 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +43 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +43 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +44 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +44 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +45 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +45 DAY)),
(3, DATE_ADD(CURDATE(), INTERVAL +46 DAY)), (3, 'day', DATE_ADD(CURDATE(), INTERVAL +46 DAY)),
(4, CURDATE()), (4, 'day', CURDATE()),
(4, DATE_ADD(CURDATE(), INTERVAL +1 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +1 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +2 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +2 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +3 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +3 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +4 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +4 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +5 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +5 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +6 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +6 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +7 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +7 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +8 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +8 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +9 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +9 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +10 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +10 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +11 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +11 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +12 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +12 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +13 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +13 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +14 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +14 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +15 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +15 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +16 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +16 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +17 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +17 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +18 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +18 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +19 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +19 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +20 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +20 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +21 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +21 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +22 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +22 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +23 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +23 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +24 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +24 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +25 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +25 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +26 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +26 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +27 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +27 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +28 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +28 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +29 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +29 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +30 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +30 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +31 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +31 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +32 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +32 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +33 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +33 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +34 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +34 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +35 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +35 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +36 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +36 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +37 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +37 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +38 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +38 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +39 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +39 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +40 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +40 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +41 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +41 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +42 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +42 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +43 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +43 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +44 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +44 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +45 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +45 DAY)),
(4, DATE_ADD(CURDATE(), INTERVAL +46 DAY)), (4, 'day', DATE_ADD(CURDATE(), INTERVAL +46 DAY)),
(5, CURDATE()), (5, 'day', CURDATE()),
(5, DATE_ADD(CURDATE(), INTERVAL +1 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +1 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +2 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +2 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +3 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +3 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +4 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +4 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +5 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +5 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +6 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +6 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +7 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +7 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +8 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +8 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +9 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +9 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +10 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +10 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +11 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +11 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +12 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +12 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +13 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +13 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +14 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +14 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +15 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +15 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +16 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +16 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +17 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +17 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +18 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +18 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +19 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +19 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +20 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +20 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +21 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +21 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +22 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +22 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +23 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +23 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +24 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +24 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +25 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +25 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +26 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +26 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +27 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +27 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +28 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +28 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +29 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +29 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +30 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +30 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +31 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +31 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +32 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +32 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +33 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +33 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +34 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +34 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +35 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +35 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +36 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +36 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +37 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +37 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +38 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +38 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +39 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +39 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +40 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +40 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +41 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +41 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +42 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +42 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +43 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +43 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +44 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +44 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +45 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +45 DAY)),
(5, DATE_ADD(CURDATE(), INTERVAL +46 DAY)), (5, 'day', DATE_ADD(CURDATE(), INTERVAL +46 DAY)),
(6, CURDATE()), (6, 'day', CURDATE()),
(6, DATE_ADD(CURDATE(), INTERVAL +1 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +1 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +2 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +2 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +3 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +3 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +4 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +4 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +5 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +5 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +6 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +6 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +7 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +7 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +8 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +8 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +9 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +9 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +10 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +10 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +11 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +11 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +12 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +12 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +13 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +13 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +14 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +14 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +15 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +15 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +16 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +16 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +17 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +17 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +18 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +18 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +19 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +19 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +20 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +20 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +21 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +21 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +22 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +22 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +23 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +23 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +24 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +24 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +25 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +25 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +26 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +26 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +27 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +27 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +28 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +28 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +29 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +29 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +30 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +30 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +31 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +31 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +32 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +32 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +33 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +33 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +34 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +34 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +35 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +35 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +36 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +36 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +37 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +37 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +38 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +38 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +39 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +39 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +40 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +40 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +41 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +41 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +42 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +42 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +43 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +43 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +44 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +44 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +45 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +45 DAY)),
(6, DATE_ADD(CURDATE(), INTERVAL +46 DAY)), (6, 'day', DATE_ADD(CURDATE(), INTERVAL +46 DAY)),
(7, CURDATE()), (7, 'day', CURDATE()),
(7, DATE_ADD(CURDATE(), INTERVAL +1 DAY)), (7, 'day', DATE_ADD(CURDATE(), INTERVAL +1 DAY)),
(7, DATE_ADD(CURDATE(), INTERVAL +2 DAY)), (7, 'day', DATE_ADD(CURDATE(), INTERVAL +2 DAY)),
(7, DATE_ADD(CURDATE(), INTERVAL +3 DAY)), (7, 'day', DATE_ADD(CURDATE(), INTERVAL +3 DAY)),
(7, DATE_ADD(CURDATE(), INTERVAL +4 DAY)), (7, 'day', DATE_ADD(CURDATE(), INTERVAL +4 DAY)),
(7, DATE_ADD(CURDATE(), INTERVAL +5 DAY)), (7, 'day', DATE_ADD(CURDATE(), INTERVAL +5 DAY)),
(7, DATE_ADD(CURDATE(), INTERVAL +6 DAY)), (7, 'day', DATE_ADD(CURDATE(), INTERVAL +6 DAY)),
(8, CURDATE()), (8, 'day', CURDATE()),
(8, DATE_ADD(CURDATE(), INTERVAL +1 DAY)), (8, 'day', DATE_ADD(CURDATE(), INTERVAL +1 DAY)),
(8, DATE_ADD(CURDATE(), INTERVAL +2 DAY)), (8, 'day', DATE_ADD(CURDATE(), INTERVAL +2 DAY)),
(8, DATE_ADD(CURDATE(), INTERVAL +3 DAY)), (8, 'day', DATE_ADD(CURDATE(), INTERVAL +3 DAY)),
(8, DATE_ADD(CURDATE(), INTERVAL +4 DAY)), (8, 'day', DATE_ADD(CURDATE(), INTERVAL +4 DAY)),
(8, DATE_ADD(CURDATE(), INTERVAL +5 DAY)), (8, 'day', DATE_ADD(CURDATE(), INTERVAL +5 DAY)),
(8, DATE_ADD(CURDATE(), INTERVAL +6 DAY)); (8, 'day', DATE_ADD(CURDATE(), INTERVAL +6 DAY));
INSERT INTO `vn`.`workerTimeControl`(`userFk`,`timed`,`manual`) INSERT INTO `vn`.`workerTimeControl`(`userFk`,`timed`,`manual`, `direction`)
VALUES VALUES
(106, CONCAT(CURDATE(), ' 07:00'), TRUE), (106, CONCAT(CURDATE(), ' 07:00'), TRUE, 'in'),
(106, CONCAT(CURDATE(), ' 10:00'), TRUE), (106, CONCAT(CURDATE(), ' 10:00'), TRUE, 'middle'),
(106, CONCAT(CURDATE(), ' 10:10'), TRUE), (106, CONCAT(CURDATE(), ' 10:10'), TRUE, 'middle'),
(106, CONCAT(CURDATE(), ' 15:00'), TRUE); (106, CONCAT(CURDATE(), ' 15:00'), TRUE, 'out');
INSERT INTO `vn`.`dmsType`(`id`, `name`, `path`, `readRoleFk`, `writeRoleFk`, `code`) INSERT INTO `vn`.`dmsType`(`id`, `name`, `path`, `readRoleFk`, `writeRoleFk`, `code`)
VALUES VALUES
@ -1951,3 +1951,8 @@ INSERT INTO `vn`.`userPhone`(`id`, `userFk`, `typeFk`, `phone`)
(65, 107, 'businessPhone', 700987987), (65, 107, 'businessPhone', 700987987),
(67, 106, 'businessPhone', 1111111112), (67, 106, 'businessPhone', 1111111112),
(68, 106, 'personalPhone', 1111111113); (68, 106, 'personalPhone', 1111111113);
INSERT INTO `vn`.`workerTimeControlParams` (`id`, `dayBreak`, `weekBreak`, `weekScope`, `dayWorkMax`, `dayStayMax`)
VALUES
(1, 43200, 129600, 734400, 43200, 50400);

View File

@ -0,0 +1,37 @@
const app = require('vn-loopback/server/server');
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
// #1885
xdescribe('order_confirmWithUser()', () => {
it('should confirm an order', async() => {
let stmts = [];
let stmt;
stmts.push('START TRANSACTION');
let params = {
orderFk: 10,
userId: 9
};
// problema: la funcion order_confirmWithUser tiene una transacción, por tanto esta nunca hace rollback
stmt = new ParameterizedSQL('CALL hedera.order_confirmWithUser(?, ?)', [
params.orderFk,
params.userId
]);
stmts.push(stmt);
stmt = new ParameterizedSQL('SELECT confirmed FROM hedera.order WHERE id = ?', [
params.orderFk
]);
let orderIndex = stmts.push(stmt) - 1;
stmts.push('ROLLBACK');
let sql = ParameterizedSQL.join(stmts, ';');
let result = await app.models.Ticket.rawStmt(sql);
savedDescription = result[orderIndex][0].confirmed;
expect(savedDescription).toBeTruthy();
});
});

View File

@ -679,34 +679,35 @@ export default {
saturdayAddTimeButton: 'vn-worker-time-control vn-table > div > vn-tfoot > vn-tr:nth-child(2) > vn-td:nth-child(6) > vn-icon-button', saturdayAddTimeButton: 'vn-worker-time-control vn-table > div > vn-tfoot > vn-tr:nth-child(2) > vn-td:nth-child(6) > vn-icon-button',
sundayAddTimeButton: 'vn-worker-time-control vn-table > div > vn-tfoot > vn-tr:nth-child(2) > vn-td:nth-child(7) > vn-icon-button', sundayAddTimeButton: 'vn-worker-time-control vn-table > div > vn-tfoot > vn-tr:nth-child(2) > vn-td:nth-child(7) > vn-icon-button',
confirmButton: '.vn-dialog.shown tpl-buttons > button', confirmButton: '.vn-dialog.shown tpl-buttons > button',
firstEntryOfMonday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(1) > section:nth-child(1) > span', firstEntryOfMonday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(1) > section:nth-child(1) > vn-chip > div',
firstEntryOfTuesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > section:nth-child(1) > span', firstEntryOfTuesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > section:nth-child(1) > vn-chip > div',
firstEntryOfWednesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(3) > section:nth-child(1) > span', firstEntryOfWednesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(3) > section:nth-child(1) > vn-chip > div',
firstEntryOfThursday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(4) > section:nth-child(1) > span', firstEntryOfThursday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(4) > section:nth-child(1) > vn-chip > div',
firstEntryOfFriday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(5) > section:nth-child(1) > span', firstEntryOfFriday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(5) > section:nth-child(1) > vn-chip > div',
firstEntryOfSaturday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(6) > section:nth-child(1) > span', firstEntryOfSaturday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(6) > section:nth-child(1) > vn-chip > div',
firstEntryOfSunday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(7) > section:nth-child(1) > span', firstEntryOfSunday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(7) > section:nth-child(1) > vn-chip > div',
secondEntryOfMonday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(1) > section:nth-child(2) > span', secondEntryOfMonday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(1) > section:nth-child(2) > vn-chip > div',
secondEntryOfTuesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > section:nth-child(2) > span', secondEntryOfTuesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > section:nth-child(2) > vn-chip > div',
secondEntryOfWednesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(3) > section:nth-child(2) > span', secondEntryOfWednesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(3) > section:nth-child(2) > vn-chip > div',
secondEntryOfThursday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(4) > section:nth-child(2) > span', secondEntryOfThursday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(4) > section:nth-child(2) > vn-chip > div',
secondEntryOfFriday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(5) > section:nth-child(2) > span', secondEntryOfFriday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(5) > section:nth-child(2) > vn-chip > div',
secondEntryOfSaturday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(6) > section:nth-child(2) > span', secondEntryOfSaturday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(6) > section:nth-child(2) > vn-chip > div',
secondEntryOfSunday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(7) > section:nth-child(2) > span', secondEntryOfSunday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(7) > section:nth-child(2) > vn-chip > div',
thirdEntryOfMonday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(1) > section:nth-child(3) > span', thirdEntryOfMonday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(1) > section:nth-child(3) > vn-chip > div',
thirdEntryOfTuesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > section:nth-child(3) > span', thirdEntryOfMondayDelete: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(1) > section:nth-child(3) > vn-chip > vn-icon[icon="cancel"]',
thirdEntryOfWednesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(3) > section:nth-child(3) > span', thirdEntryOfTuesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > section:nth-child(3) > vn-chip > div',
thirdEntryOfThursday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(4) > section:nth-child(3) > span', thirdEntryOfWednesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(3) > section:nth-child(3) > vn-chip > div',
thirdEntryOfFriday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(5) > section:nth-child(3) > span', thirdEntryOfThursday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(4) > section:nth-child(3) > vn-chip > div',
thirdEntryOfSaturday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(6) > section:nth-child(3) > span', thirdEntryOfFriday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(5) > section:nth-child(3) > vn-chip > div',
thirdEntryOfSunday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(7) > section:nth-child(3) > span', thirdEntryOfSaturday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(6) > section:nth-child(3) > vn-chip > div',
fourthEntryOfMonday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(1) > section:nth-child(4) > span', thirdEntryOfSunday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(7) > section:nth-child(3) > vn-chip > div',
fourthEntryOfTuesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > section:nth-child(4) > span', fourthEntryOfMonday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(1) > section:nth-child(4) > vn-chip > div',
fourthEntryOfWednesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(3) > section:nth-child(4) > span', fourthEntryOfTuesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > section:nth-child(4) > vn-chip > div',
fourthEntryOfThursday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(4) > section:nth-child(4) > span', fourthEntryOfWednesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(3) > section:nth-child(4) > vn-chip > div',
fourthEntryOfFriday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(5) > section:nth-child(4) > span', fourthEntryOfThursday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(4) > section:nth-child(4) > vn-chip > div',
fourthEntryOfSaturday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(6) > section:nth-child(4) > span', fourthEntryOfFriday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(5) > section:nth-child(4) > vn-chip > div',
fourthEntryOfSunday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(7) > section:nth-child(4) > span', fourthEntryOfSaturday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(6) > section:nth-child(4) > vn-chip > div',
fourthEntryOfSunday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(7) > section:nth-child(4) > vn-chip > div',
mondayWorkedHours: 'vn-worker-time-control vn-table > div > vn-tfoot > vn-tr:nth-child(1) > vn-td:nth-child(1)', mondayWorkedHours: 'vn-worker-time-control vn-table > div > vn-tfoot > vn-tr:nth-child(1) > vn-td:nth-child(1)',
tuesdayWorkedHours: 'vn-worker-time-control vn-table > div > vn-tfoot > vn-tr:nth-child(1) > vn-td:nth-child(2)', tuesdayWorkedHours: 'vn-worker-time-control vn-table > div > vn-tfoot > vn-tr:nth-child(1) > vn-td:nth-child(2)',
wednesdayWorkedHours: 'vn-worker-time-control vn-table > div > vn-tfoot > vn-tr:nth-child(1) > vn-td:nth-child(3)', wednesdayWorkedHours: 'vn-worker-time-control vn-table > div > vn-tfoot > vn-tr:nth-child(1) > vn-td:nth-child(3)',
@ -717,7 +718,8 @@ export default {
weekWorkedHours: 'vn-worker-time-control vn-side-menu vn-label-value > section > span', weekWorkedHours: 'vn-worker-time-control vn-side-menu vn-label-value > section > span',
nextMonthButton: 'vn-worker-time-control vn-side-menu vn-calendar vn-button[icon=keyboard_arrow_right]', nextMonthButton: 'vn-worker-time-control vn-side-menu vn-calendar vn-button[icon=keyboard_arrow_right]',
secondWeekDay: 'vn-worker-time-control vn-side-menu vn-calendar .day:nth-child(8) > .day-number', secondWeekDay: 'vn-worker-time-control vn-side-menu vn-calendar .day:nth-child(8) > .day-number',
navigateBackToIndex: 'vn-worker-descriptor vn-icon[icon="chevron_left"]' navigateBackToIndex: 'vn-worker-descriptor vn-icon[icon="chevron_left"]',
acceptDeleteDialog: '.vn-confirm.shown button[response="accept"]'
}, },
invoiceOutIndex: { invoiceOutIndex: {
searchInvoiceOutInput: `vn-searchbar input`, searchInvoiceOutInput: `vn-searchbar input`,

View File

@ -35,8 +35,30 @@ describe('Worker time control path', () => {
expect(result).toEqual(scanTime); expect(result).toEqual(scanTime);
}); });
it(`should scan out Hank Pym and forget to scan in from the break`, async() => { it(`should scan in Hank Pym for a wrong hour and forget to scan in from the break`, async() => {
const scanTime = '15:00'; const scanTime = '18:00';
const result = await nightmare
.waitToClick(selectors.workerTimeControl.mondayAddTimeButton)
.pickTime(selectors.workerTimeControl.timeDialogInput, scanTime)
.waitToClick(selectors.workerTimeControl.confirmButton)
.waitToGetProperty(selectors.workerTimeControl.thirdEntryOfMonday, 'innerText');
expect(result).toEqual(scanTime);
});
it(`should delete the wrong entry for Hank Pym`, async() => {
const wrongScanTime = '18:00';
const result = await nightmare
.waitForTextInElement(selectors.workerTimeControl.thirdEntryOfMonday, wrongScanTime)
.waitToClick(selectors.workerTimeControl.thirdEntryOfMondayDelete)
.waitToClick(selectors.workerTimeControl.acceptDeleteDialog)
.waitForLastSnackbar();
expect(result).toEqual('Entry removed');
});
it(`should scan out Hank Pym to leave early`, async() => {
const scanTime = '14:00';
const result = await nightmare const result = await nightmare
.waitToClick(selectors.workerTimeControl.mondayAddTimeButton) .waitToClick(selectors.workerTimeControl.mondayAddTimeButton)
.pickTime(selectors.workerTimeControl.timeDialogInput, scanTime) .pickTime(selectors.workerTimeControl.timeDialogInput, scanTime)
@ -54,7 +76,7 @@ describe('Worker time control path', () => {
.waitToClick(selectors.workerTimeControl.confirmButton) .waitToClick(selectors.workerTimeControl.confirmButton)
.waitToGetProperty(selectors.workerTimeControl.fourthEntryOfMonday, 'innerText'); .waitToGetProperty(selectors.workerTimeControl.fourthEntryOfMonday, 'innerText');
expect(result).toEqual('15:00'); expect(result).toEqual('14:00');
}); });
it(`should the third entry be the scan in from break`, async() => { it(`should the third entry be the scan in from break`, async() => {
@ -67,9 +89,10 @@ describe('Worker time control path', () => {
it(`should check Hank Pym worked 8 hours`, async() => { it(`should check Hank Pym worked 8 hours`, async() => {
const result = await nightmare const result = await nightmare
.waitForTextInElement(selectors.workerTimeControl.mondayWorkedHours, '07:00 h.')
.waitToGetProperty(selectors.workerTimeControl.mondayWorkedHours, 'innerText'); .waitToGetProperty(selectors.workerTimeControl.mondayWorkedHours, 'innerText');
expect(result).toEqual('08:00 h.'); expect(result).toEqual('07:00 h.');
}); });
}); });
@ -120,6 +143,7 @@ describe('Worker time control path', () => {
it(`should check Hank Pym worked 8 happy hours`, async() => { it(`should check Hank Pym worked 8 happy hours`, async() => {
const result = await nightmare const result = await nightmare
.waitForTextInElement(selectors.workerTimeControl.tuesdayWorkedHours, '08:00 h.')
.waitToGetProperty(selectors.workerTimeControl.tuesdayWorkedHours, 'innerText'); .waitToGetProperty(selectors.workerTimeControl.tuesdayWorkedHours, 'innerText');
expect(result).toEqual('08:00 h.'); expect(result).toEqual('08:00 h.');
@ -173,6 +197,7 @@ describe('Worker time control path', () => {
it(`should check Hank Pym worked 8 cheerfull hours`, async() => { it(`should check Hank Pym worked 8 cheerfull hours`, async() => {
const result = await nightmare const result = await nightmare
.waitForTextInElement(selectors.workerTimeControl.wednesdayWorkedHours, '08:00 h.')
.waitToGetProperty(selectors.workerTimeControl.wednesdayWorkedHours, 'innerText'); .waitToGetProperty(selectors.workerTimeControl.wednesdayWorkedHours, 'innerText');
expect(result).toEqual('08:00 h.'); expect(result).toEqual('08:00 h.');
@ -226,6 +251,7 @@ describe('Worker time control path', () => {
it(`should check Hank Pym worked 8 joyfull hours`, async() => { it(`should check Hank Pym worked 8 joyfull hours`, async() => {
const result = await nightmare const result = await nightmare
.waitForTextInElement(selectors.workerTimeControl.thursdayWorkedHours, '08:00 h.')
.waitToGetProperty(selectors.workerTimeControl.thursdayWorkedHours, 'innerText'); .waitToGetProperty(selectors.workerTimeControl.thursdayWorkedHours, 'innerText');
expect(result).toEqual('08:00 h.'); expect(result).toEqual('08:00 h.');
@ -279,6 +305,7 @@ describe('Worker time control path', () => {
it(`should check Hank Pym worked 8 hours with a smile on his face`, async() => { it(`should check Hank Pym worked 8 hours with a smile on his face`, async() => {
const result = await nightmare const result = await nightmare
.waitForTextInElement(selectors.workerTimeControl.fridayWorkedHours, '08:00 h.')
.waitToGetProperty(selectors.workerTimeControl.fridayWorkedHours, 'innerText'); .waitToGetProperty(selectors.workerTimeControl.fridayWorkedHours, 'innerText');
expect(result).toEqual('08:00 h.'); expect(result).toEqual('08:00 h.');
@ -319,6 +346,7 @@ describe('Worker time control path', () => {
it(`should check Hank Pym worked 8 hours with all his will`, async() => { it(`should check Hank Pym worked 8 hours with all his will`, async() => {
const result = await nightmare const result = await nightmare
.waitForTextInElement(selectors.workerTimeControl.saturdayWorkedHours, '08:00 h.')
.waitToGetProperty(selectors.workerTimeControl.saturdayWorkedHours, 'innerText'); .waitToGetProperty(selectors.workerTimeControl.saturdayWorkedHours, 'innerText');
expect(result).toEqual('08:00 h.'); expect(result).toEqual('08:00 h.');
@ -350,6 +378,7 @@ describe('Worker time control path', () => {
it(`should check Hank Pym worked 8 glad hours`, async() => { it(`should check Hank Pym worked 8 glad hours`, async() => {
const result = await nightmare const result = await nightmare
.waitForTextInElement(selectors.workerTimeControl.sundayWorkedHours, '08:00 h.')
.waitToGetProperty(selectors.workerTimeControl.sundayWorkedHours, 'innerText'); .waitToGetProperty(selectors.workerTimeControl.sundayWorkedHours, 'innerText');
expect(result).toEqual('08:00 h.'); expect(result).toEqual('08:00 h.');
@ -387,10 +416,10 @@ describe('Worker time control path', () => {
it('should Hank Pym check his hours are alright', async() => { it('should Hank Pym check his hours are alright', async() => {
const wholeWeekHours = await nightmare const wholeWeekHours = await nightmare
.waitForTextInElement(selectors.workerTimeControl.weekWorkedHours, '56:00 h.') .waitForTextInElement(selectors.workerTimeControl.weekWorkedHours, '55:00 h.')
.waitToGetProperty(selectors.workerTimeControl.weekWorkedHours, 'innerText'); .waitToGetProperty(selectors.workerTimeControl.weekWorkedHours, 'innerText');
expect(wholeWeekHours).toEqual('56:00 h.'); expect(wholeWeekHours).toEqual('55:00 h.');
}); });
}); });
}); });

View File

@ -24,13 +24,12 @@ vn-chip {
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
line-height: 2em;
& > vn-avatar { & > vn-avatar {
margin-left: -0.7em; margin-left: -0.7em;
margin-right: .3em; margin-right: .3em;
vertical-align: middle; vertical-align: middle;
height: 1.9em; height: 2em;
width: 2em; width: 2em;
} }
} }

View File

@ -2,7 +2,7 @@
<span <span
ng-repeat="day in $ctrl.days" ng-repeat="day in $ctrl.days"
translate-attr="::{title: day.name}" translate-attr="::{title: day.name}"
ng-class="{marked: $ctrl.field[day.code]}" ng-class="{marked: $ctrl.field[day.index]}"
ng-click="$ctrl.field[day.code] = !$ctrl.field[day.code]"> ng-click="$ctrl.toggleDay(day.index)">
{{day.localeChar}} {{day.localeChar}}
</span> </span>

View File

@ -8,6 +8,13 @@ export default class WdayPicker extends FormInput {
this.days = vnWeekDays.locales; this.days = vnWeekDays.locales;
this.initTabIndex(); this.initTabIndex();
} }
toggleDay(index) {
let field = this.field;
if (!field) field = [];
field[index] = !field[index];
this.change(field);
}
} }
WdayPicker.$inject = ['$element', '$scope', 'vnWeekDays']; WdayPicker.$inject = ['$element', '$scope', 'vnWeekDays'];

View File

@ -1,5 +1,22 @@
import ngModule from '../module'; import ngModule from '../module';
/**
* @property {Array} days Weekdays data array with the same indexes as Date.getDay()
* @property {Object} map Weekdays data map using weekday codes as key
* @property {Array} localeCodes Locale weekday codes indexes depend on current locale
* @property {Array} locale Weekday data array with indexes depending on current locale
*
* Weekday properties:
*
* @property {Number} index The weekday index acording to Date.getDay()
* @property {String} code The weekday code
* @property {String} name The weekday name
* @property {String} char The first weekday letter
* @property {String} abr The abreviated 3 letters weekday name
* @property {String} locale The weekday name in current locale
* @property {String} localeChar The first weekday letter in current locale
* @property {String} localeAbr The abreviated 3 letters weekday name in current locale
*/
class WeekDays { class WeekDays {
constructor($translate) { constructor($translate) {
this.$translate = $translate; this.$translate = $translate;
@ -65,6 +82,34 @@ class WeekDays {
for (let code of this.localeCodes) for (let code of this.localeCodes)
this.locales.push(this.map[code]); this.locales.push(this.map[code]);
} }
fromSet(weekDays) {
let wdays = [];
if (weekDays) {
let codes = weekDays.split(',');
for (let code of codes) {
let data = this.map[code];
if (data) wdays[data.index] = true;
}
}
return wdays;
}
toSet(wdays) {
let weekDays = [];
if (wdays) {
for (let i = 0; i < wdays.length; i++) {
if (!wdays[i]) continue;
let data = this.days[i];
if (data) weekDays.push(data.code);
}
}
return weekDays.join(',');
}
} }
WeekDays.$inject = ['$translate']; WeekDays.$inject = ['$translate'];

View File

@ -113,5 +113,9 @@
"You can't create a claim for a removed ticket": "No puedes crear una reclamación para un ticket eliminado", "You can't create a claim for a removed ticket": "No puedes crear una reclamación para un ticket eliminado",
"You cannot delete a ticket that part of it is being prepared": "No puedes eliminar un ticket en el que una parte que está siendo preparada", "You cannot delete a ticket that part of it is being prepared": "No puedes eliminar un ticket en el que una parte que está siendo preparada",
"You must delete all the buy requests first": "Debes eliminar todas las peticiones de compra primero", "You must delete all the buy requests first": "Debes eliminar todas las peticiones de compra primero",
"Has deleted the ticket id": "Ha eliminado el ticket id [#{{id}}]({{{url}}})" "Has deleted the ticket id": "Ha eliminado el ticket id [#{{id}}]({{{url}}})",
"You should specify a date": "Debes especificar una fecha",
"You should specify at least a start or end date": "Debes especificar al menos una fecha de inicio o de fín",
"Start date should be lower than end date": "La fecha de inicio debe ser menor que la fecha de fín",
"You should mark at least one week day": "Debes marcar al menos un día de la semana"
} }

View File

@ -47,6 +47,7 @@ module.exports = Self => {
let rsIndex = stmts.push( let rsIndex = stmts.push(
`SELECT * FROM tmp.zoneGetLanded`) - 1; `SELECT * FROM tmp.zoneGetLanded`) - 1;
stmts.push(`DROP TEMPORARY TABLE tmp.zoneGetLanded`);
let sql = ParameterizedSQL.join(stmts, ';'); let sql = ParameterizedSQL.join(stmts, ';');
let landed = await Self.rawStmt(sql); let landed = await Self.rawStmt(sql);

View File

@ -1,8 +1,9 @@
const app = require('vn-loopback/server/server'); const app = require('vn-loopback/server/server');
// Petición #1848
xdescribe('agency getLanded()', () => { describe('agency getLanded()', () => {
it('should return a landing date', async() => { it('should return a landing date', async() => {
const shipped = new Date(); const shipped = new Date();
shipped.setDate(shipped.getDate() + 1);
const addressFk = 121; const addressFk = 121;
const agencyModeFk = 7; const agencyModeFk = 7;
const warehouseFk = 1; const warehouseFk = 1;

View File

@ -1,10 +1,9 @@
const app = require('vn-loopback/server/server'); const app = require('vn-loopback/server/server');
// Petición #1848 describe('agency getShipped()', () => {
xdescribe('agency getShipped()', () => {
it('should return a shipment date', async() => { it('should return a shipment date', async() => {
const landed = new Date(); const landed = new Date();
landed.setDate(landed.getDate() + 1);
const addressFk = 121; const addressFk = 121;
const agencyModeFk = 7; const agencyModeFk = 7;
const warehouseFk = 1; const warehouseFk = 1;

View File

@ -1,6 +1,6 @@
const app = require('vn-loopback/server/server'); const app = require('vn-loopback/server/server');
// Petición #1848
xdescribe('Agency landsThatDay()', () => { describe('Agency landsThatDay()', () => {
const today = new Date(); const today = new Date();
it('should return a list of agencies that can land a shipment on a day for an address', async() => { it('should return a list of agencies that can land a shipment on a day for an address', async() => {
let agencies = await app.models.Agency.landsThatDay(101, today); let agencies = await app.models.Agency.landsThatDay(101, today);

View File

@ -1,28 +0,0 @@
module.exports = Self => {
Self.remoteMethod('removeByDate', {
description: 'Removes one or more delivery dates for a zone',
accessType: 'WRITE',
accepts: [{
arg: 'zoneFk',
type: 'Number',
required: true,
},
{
arg: 'dates',
type: ['Date'],
required: true,
}],
returns: {
type: 'object',
root: true
},
http: {
path: `/removeByDate`,
verb: 'POST'
}
});
Self.removeByDate = (zoneFk, dates) => {
return Self.destroyAll({zoneFk, delivered: {inq: dates}});
};
};

View File

@ -31,7 +31,6 @@ module.exports = Self => {
fields: [ fields: [
'name', 'name',
'hour', 'hour',
'warehouseFk',
'agencyModeFk', 'agencyModeFk',
'travelingDays', 'travelingDays',
'price', 'price',
@ -47,7 +46,8 @@ module.exports = Self => {
}, options); }, options);
// Find all original selected days // Find all original selected days
const calendarDays = await models.ZoneCalendar.find({ const calendarDays = await models.ZoneEvent.find({
fields: {id: false},
where: {zoneFk: id} where: {zoneFk: id}
}, options); }, options);
@ -62,7 +62,7 @@ module.exports = Self => {
}); });
await models.ZoneIncluded.create(newIncludedGeo, options); await models.ZoneIncluded.create(newIncludedGeo, options);
await models.ZoneCalendar.create(newCalendayDays, options); await models.ZoneEvent.create(newCalendayDays, options);
await tx.commit(); await tx.commit();
return newZone; return newZone;

View File

@ -1,81 +0,0 @@
const mergeFilters = require('vn-loopback/util/filter').mergeFilters;
module.exports = Self => {
Self.remoteMethod('editPrices', {
description: 'Changes the price and bonus of a delivery day',
accessType: 'WRITE',
accepts: [{
arg: 'id',
type: 'Number',
description: 'The zone id',
http: {source: 'path'}
},
{
arg: 'delivered',
type: 'Date',
required: true,
},
{
arg: 'price',
type: 'Number',
required: true,
},
{
arg: 'bonus',
type: 'Number',
required: true,
},
{
arg: 'option',
type: 'String',
required: true,
}],
returns: {
type: 'object',
root: true
},
http: {
path: `/:id/editPrices`,
verb: 'POST'
}
});
Self.editPrices = async(id, delivered, price, bonus, option) => {
const models = Self.app.models;
let filter = {
where: {
zoneFk: id
}
};
let where;
let shouldPropagate = true;
if (option == 'Only this day') {
shouldPropagate = false;
where = {delivered};
} else if (option == 'From this day') {
where = {
delivered: {
gte: delivered
}
};
}
filter = mergeFilters(filter, {where});
const days = await models.ZoneCalendar.find(filter);
const areAllFromSameZone = days.every(day => day.zoneFk === id);
if (!areAllFromSameZone)
throw new UserError('All delivery days must belong to the same zone');
if (shouldPropagate) {
const zone = await models.Zone.findById(id);
zone.updateAttributes({price, bonus});
}
return models.ZoneCalendar.updateAll(filter.where, {price, bonus});
};
};

View File

@ -1,81 +0,0 @@
const app = require('vn-loopback/server/server');
// Petición #1848
xdescribe('agency editPrices()', () => {
const zoneId = 1;
let originalZone;
beforeAll(async done => {
originalZone = await app.models.Zone.findById(zoneId);
done();
});
afterAll(async done => {
await await app.models.ZoneCalendar.updateAll({zoneFk: zoneId}, {
price: originalZone.price,
bonus: originalZone.bonus
});
done();
});
it('should apply price and bonus for a selected day', async() => {
const delivered = new Date();
delivered.setHours(0, 0, 0, 0);
await app.models.Zone.editPrices(zoneId, delivered, 4.00, 2.00, 'Only this day');
const editedDays = await app.models.ZoneCalendar.find({
where: {
zoneFk: zoneId,
delivered: delivered
}
});
const firstEditedDay = editedDays[0];
expect(editedDays.length).toEqual(1);
expect(firstEditedDay.price).toEqual(4.00);
expect(firstEditedDay.bonus).toEqual(2.00);
});
it('should apply price and bonus for all delivery days starting from selected day', async() => {
const delivered = new Date();
delivered.setHours(0, 0, 0, 0);
await app.models.Zone.editPrices(1, delivered, 5.50, 1.00, 'From this day');
const editedDays = await app.models.ZoneCalendar.find({
where: {
zoneFk: zoneId,
delivered: {
gte: delivered
}
}
});
const firstEditedDay = editedDays[0];
const lastEditedDay = editedDays[editedDays.length - 1];
expect(editedDays.length).toEqual(5);
expect(firstEditedDay.price).toEqual(5.50);
expect(firstEditedDay.bonus).toEqual(1.00);
expect(lastEditedDay.price).toEqual(5.50);
expect(lastEditedDay.bonus).toEqual(1.00);
});
it('should apply price and bonus for all delivery days', async() => {
const delivered = new Date();
delivered.setHours(0, 0, 0, 0);
await app.models.Zone.editPrices(1, delivered, 7.00, 0.00, 'All days');
const editedDays = await app.models.ZoneCalendar.find({
where: {
zoneFk: zoneId
}
});
const firstEditedDay = editedDays[0];
const lastEditedDay = editedDays[editedDays.length - 1];
expect(editedDays.length).toEqual(5);
expect(firstEditedDay.price).toEqual(7.00);
expect(firstEditedDay.bonus).toEqual(0.00);
expect(lastEditedDay.price).toEqual(7.00);
expect(lastEditedDay.bonus).toEqual(0.00);
});
});

View File

@ -20,9 +20,6 @@
"ZoneExclusion": { "ZoneExclusion": {
"dataSource": "vn" "dataSource": "vn"
}, },
"ZoneCalendar": {
"dataSource": "vn"
},
"ZoneIncluded": { "ZoneIncluded": {
"dataSource": "vn" "dataSource": "vn"
}, },

View File

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

View File

@ -1,32 +0,0 @@
{
"name": "ZoneCalendar",
"base": "VnModel",
"options": {
"mysql": {
"table": "zoneCalendar"
}
},
"properties": {
"zoneFk": {
"id": true,
"type": "Number"
},
"delivered": {
"id": true,
"type": "Date"
},
"price": {
"type": "Number"
},
"bonus": {
"type": "Number"
}
},
"relations": {
"zone": {
"type": "belongsTo",
"model": "Zone",
"foreignKey": "zoneFk"
}
}
}

View File

@ -1,9 +1,35 @@
module.exports = Self => { module.exports = Self => {
function rangeValid(err) { Self.validate('range', function(err) {
if (this.from && this.to && this.from >= this.to) if (this.type == 'range'
&& !this.started
&& !this.ended)
err(); err();
} }, {
Self.validate('rangeValid', rangeValid, { message: `You should specify at least a start or end date`
});
Self.validate('validRange', function(err) {
if (this.type == 'range'
&& this.started
&& this.ended
&& this.started >= this.ended)
err();
}, {
message: `Start date should be lower than end date` message: `Start date should be lower than end date`
}); });
Self.validate('dated', function(err) {
if (this.type == 'day' && !this.dated)
err();
}, {
message: `You should specify a date`
});
Self.validate('weekDays', function(err) {
if (['range', 'indefinitely'].indexOf(this.type) !== -1
&& !this.weekDays)
err();
}, {
message: `You should mark at least one week day`
});
}; };

View File

@ -15,10 +15,16 @@
"id": true, "id": true,
"type": "Number" "type": "Number"
}, },
"from": { "type": {
"type": "String"
},
"dated": {
"type": "Date" "type": "Date"
}, },
"to": { "started": {
"type": "Date"
},
"ended": {
"type": "Date" "type": "Date"
}, },
"weekDays": { "weekDays": {

View File

@ -11,7 +11,7 @@
"id": true, "id": true,
"type": "Number" "type": "Number"
}, },
"day": { "dated": {
"type": "Date", "type": "Date",
"required": true "required": true
} }

View File

@ -1,6 +1,5 @@
module.exports = Self => { module.exports = Self => {
require('../methods/zone/clone')(Self); require('../methods/zone/clone')(Self);
require('../methods/zone/editPrices')(Self);
require('../methods/zone/getLeaves')(Self); require('../methods/zone/getLeaves')(Self);
require('../methods/zone/getEvents')(Self); require('../methods/zone/getEvents')(Self);
require('../methods/zone/toggleIsIncluded')(Self); require('../methods/zone/toggleIsIncluded')(Self);

View File

@ -3,8 +3,9 @@ import Component from 'core/lib/component';
import './style.scss'; import './style.scss';
class Controller extends Component { class Controller extends Component {
constructor($element, $) { constructor($element, $, vnWeekDays) {
super($element, $); super($element, $);
this.vnWeekDays = vnWeekDays;
this.nMonths = 4; this.nMonths = 4;
let date = new Date(); let date = new Date();
@ -54,19 +55,29 @@ class Controller extends Component {
this._data = value; this._data = value;
value = value || {}; value = value || {};
this.events = value.events;
this.exclusions = value.exclusions;
if (this.events) { this.events = value.events;
let codes = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
for (event of this.events) { function toStamp(date) {
event.wdays = []; return date && new Date(date).setHours(0, 0, 0, 0);
if (!event.weekDays) continue; }
let weekDays = event.weekDays.split(',');
for (let wday of weekDays) { this.exclusionsMap = {};
let index = codes.indexOf(wday); let exclusions = value.exclusions;
if (index !== -1) event.wdays[index] = true;
} if (exclusions) {
for (let exclusion of exclusions)
this.exclusionsMap[toStamp(exclusion.dated)] = exclusion;
}
let events = value.events;
if (events) {
for (event of events) {
event.dated = toStamp(event.dated);
event.ended = toStamp(event.ended);
event.started = toStamp(event.started);
event.wdays = this.vnWeekDays.fromSet(event.weekDays);
} }
} }
@ -78,17 +89,9 @@ class Controller extends Component {
} }
refreshEvents() { refreshEvents() {
function getDate(date) {
return date && new Date(date).setHours(0, 0, 0, 0);
}
let exclusionsMap = {};
if (this.exclusions) {
for (let exclusion of this.exclusions)
exclusionsMap[getDate(exclusion.day)] = exclusion;
}
this.days = {}; this.days = {};
if (!this.data) return;
let day = new Date(this.firstDay.getTime()); let day = new Date(this.firstDay.getTime());
while (day <= this.lastDay) { while (day <= this.lastDay) {
@ -99,23 +102,24 @@ class Controller extends Component {
if (this.events) { if (this.events) {
for (let event of this.events) { for (let event of this.events) {
let match; let match;
let from = getDate(event.from);
let to = getDate(event.to);
if (event.from && event.to) { switch (event.type) {
match = stamp >= from && stamp <= to case 'day':
&& event.wdays[wday]; match = event.dated == stamp;
} else if (event.from) break;
match = from == stamp; default:
else match = event.wdays[wday]
match = event.wdays[wday]; && (!event.started || stamp >= event.started)
&& (!event.ended || stamp <= event.ended);
break;
}
if (match) if (match)
dayEvents.push(event); dayEvents.push(event);
} }
} }
let exclusion = exclusionsMap[stamp]; let exclusion = this.exclusionsMap[stamp];
if (dayEvents.length || exclusion) { if (dayEvents.length || exclusion) {
let dayData = {}; let dayData = {};
@ -152,6 +156,7 @@ class Controller extends Component {
return dayData && dayData.exclusion ? 'excluded' : ''; return dayData && dayData.exclusion ? 'excluded' : '';
} }
} }
Controller.$inject = ['$element', '$scope', 'vnWeekDays'];
ngModule.component('vnZoneCalendar', { ngModule.component('vnZoneCalendar', {
template: require('./index.html'), template: require('./index.html'),

View File

@ -1,80 +0,0 @@
<mg-ajax path="Zones/{{patch.params.id}}" options="vnPatch"></mg-ajax>
<vn-watcher
vn-id="watcher"
data="$ctrl.zone"
form="form"
save="patch">
</vn-watcher>
<form
name="form"
ng-submit="$ctrl.onSubmit()">
<vn-card class="vn-pa-lg">
<vn-horizontal>
<vn-textfield
vn-one
vn-focus
label="Name"
ng-model="$ctrl.zone.name"
rule>
</vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete
vn-one
ng-model="$ctrl.zone.warehouseFk"
url="Warehouses"
show-field="name"
value-field="id"
label="Warehouse"
rule>
</vn-autocomplete>
<vn-autocomplete
vn-one
ng-model="$ctrl.zone.agencyModeFk"
url="AgencyModes/isActive"
show-field="name"
value-field="id"
label="Agency"
rule>
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-input-number
vn-one
min="0"
step="1"
label="Traveling days"
ng-model="$ctrl.zone.travelingDays"
rule>
</vn-input-number>
<vn-input-time
vn-one
label="Estimated hour (ETD)"
ng-model="$ctrl.zone.hour"
rule>
</vn-input-time>
</vn-horizontal>
<vn-horizontal>
<vn-input-number
vn-one
label="Price"
ng-model="$ctrl.zone.price"
min="0.00"
step="0.50"
rule>
</vn-input-number>
<vn-input-number
vn-one
label="Bonus"
ng-model="$ctrl.zone.bonus"
min="0.00"
step="0.50"
rule>
</vn-input-number>
</vn-horizontal>
</vn-card>
<vn-button-bar>
<vn-submit label="Save"></vn-submit>
<vn-button ui-sref="zone.card.location" label="Cancel"></vn-button>
</vn-button-bar>
</form>

View File

@ -42,17 +42,17 @@
class="vn-item"> class="vn-item">
<vn-item-section> <vn-item-section>
<div <div
ng-if="::row.from && !row.to" ng-if="::row.type == 'day'"
class="vn-mb-sm"> class="vn-mb-sm">
{{::row.from | date:'dd/MM/yy'}} {{::row.dated | date:'dd/MM/yy'}}
</div> </div>
<div <div
ng-if="::!row.from || row.to" ng-if="::row.type != 'day'"
class="vn-mb-sm ellipsize"> class="vn-mb-sm ellipsize">
<span ng-if="row.to"> <span ng-if="row.type == 'range'">
{{::row.from | date:'dd/MM/yy'}} - {{::row.to | date:'dd/MM/yy'}} {{::row.started | date:'dd/MM/yy'}} - {{::row.ended | date:'dd/MM/yy'}}
</span> </span>
<span ng-if="!row.to" translate> <span ng-if="row.type == 'indefinitely'" translate>
Indefinitely Indefinitely
</span> </span>
<span ng-if="row.weekDays"> <span ng-if="row.weekDays">
@ -94,40 +94,40 @@
<vn-vertical> <vn-vertical>
<vn-vertical class="vn-pb-md"> <vn-vertical class="vn-pb-md">
<vn-radio <vn-radio
ng-model="$ctrl.eventType" ng-model="$ctrl.selected.type"
label="One day" label="One day"
val="day"> val="day">
</vn-radio> </vn-radio>
<vn-radio <vn-radio
ng-model="$ctrl.eventType" ng-model="$ctrl.selected.type"
label="Indefinitely" label="Indefinitely"
val="indefinitely"> val="indefinitely">
</vn-radio> </vn-radio>
<vn-radio <vn-radio
ng-model="$ctrl.eventType" ng-model="$ctrl.selected.type"
label="Range of dates" label="Range of dates"
val="range"> val="range">
</vn-radio> </vn-radio>
</vn-vertical> </vn-vertical>
<vn-wday-picker <vn-wday-picker
ng-if="$ctrl.eventType != 'day'" ng-if="$ctrl.selected.type != 'day'"
ng-model="$ctrl.selected.wdays" ng-model="$ctrl.selected.wdays"
class="vn-mt-sm vn-mb-md"> class="vn-mt-sm vn-mb-md">
</vn-wday-picker> </vn-wday-picker>
<vn-date-picker <vn-date-picker
ng-if="$ctrl.eventType == 'day'" ng-if="$ctrl.selected.type == 'day'"
label="Day" label="Day"
ng-model="$ctrl.selected.from"> ng-model="$ctrl.selected.dated">
</vn-date-picker> </vn-date-picker>
<vn-horizontal <vn-horizontal
ng-if="$ctrl.eventType == 'range'"> ng-if="$ctrl.selected.type == 'range'">
<vn-date-picker <vn-date-picker
label="From" label="From"
ng-model="$ctrl.selected.from"> ng-model="$ctrl.selected.started">
</vn-date-picker> </vn-date-picker>
<vn-date-picker <vn-date-picker
label="To" label="To"
ng-model="$ctrl.selected.to"> ng-model="$ctrl.selected.ended">
</vn-date-picker> </vn-date-picker>
</vn-horizontal> </vn-horizontal>
<vn-input-time <vn-input-time
@ -162,7 +162,7 @@
</input> </input>
<button <button
ng-if="!$ctrl.isNew" ng-if="!$ctrl.isNew"
response="DELETE" response="delete"
translate> translate>
Delete Delete
</button> </button>

View File

@ -1,7 +1,7 @@
import ngModule from '../module'; import ngModule from '../module';
import Component from 'core/lib/component'; import Section from 'salix/components/section';
class Controller extends Component { class Controller extends Section {
constructor($element, $, vnWeekDays) { constructor($element, $, vnWeekDays) {
super($element, $); super($element, $);
this.vnWeekDays = vnWeekDays; this.vnWeekDays = vnWeekDays;
@ -27,13 +27,13 @@ class Controller extends Component {
formatWdays(weekDays) { formatWdays(weekDays) {
if (!weekDays) return; if (!weekDays) return;
let abrWdays = []; let abrWdays = weekDays
for (let wday of weekDays.split(',')) .split(',')
abrWdays.push(this.vnWeekDays.map[wday].localeAbr); .map(wday => this.vnWeekDays.map[wday].localeAbr);
return abrWdays.length < 7 return abrWdays.length < 7
? abrWdays.join(', ') ? abrWdays.join(', ')
: this._('Everyday'); : this.$t('Everyday');
} }
onSelection(days, type, weekday, data) { onSelection(days, type, weekday, data) {
@ -66,37 +66,28 @@ class Controller extends Component {
edit(row) { edit(row) {
this.isNew = false; this.isNew = false;
if (row.from && !row.to)
this.eventType = 'day';
else if (!row.from)
this.eventType = 'indefinitely';
else
this.eventType = 'range';
this.selected = angular.copy(row); this.selected = angular.copy(row);
this.selected.wdays = {}; this.selected.wdays = this.vnWeekDays.fromSet(row.weekDays);
if (row.weekDays) {
let weekDays = row.weekDays.split(',');
for (let day of weekDays)
this.selected.wdays[day] = true;
}
this.$.dialog.show(); this.$.dialog.show();
} }
create(days, type, weekday) { create(days, type, weekday) {
this.isNew = true; this.isNew = true;
this.eventType = type == 'day' ? 'day' : 'indefinitely';
if (type == 'weekday') { if (type == 'weekday') {
let wdays = []; let wdays = [];
let code = this.vnWeekDays.days[weekday].code; wdays[weekday] = true;
wdays[code] = true;
this.selected = {wdays}; this.selected = {
} else type: 'indefinitely',
this.selected = {from: days[0]}; wdays
};
} else {
this.selected = {
type: 'day',
dated: days[0]
};
}
this.$.dialog.show(); this.$.dialog.show();
} }
@ -105,24 +96,18 @@ class Controller extends Component {
switch (response) { switch (response) {
case 'accept': { case 'accept': {
let selected = this.selected; let selected = this.selected;
let type = selected.type;
if (this.eventType == 'indefinitely') { selected.weekDays = this.vnWeekDays.toSet(selected.wdays);
selected.from = null;
selected.to = null;
}
if (this.eventType != 'day') { if (type == 'day')
let weekDays = [];
for (let wday in selected.wdays) {
if (selected.wdays[wday])
weekDays.push(wday);
}
selected.weekDays = weekDays.join(',');
} else {
selected.to = null;
selected.weekDays = ''; selected.weekDays = '';
else
selected.dated = null;
if (type != 'range') {
selected.started = null;
selected.ended = null;
} }
let req; let req;
@ -138,7 +123,7 @@ class Controller extends Component {
this.refresh(); this.refresh();
}); });
} }
case 'DELETE': case 'delete':
return this.onDelete(this.selected.id) return this.onDelete(this.selected.id)
.then(response => response == 'accept'); .then(response => response == 'accept');
} }
@ -162,8 +147,8 @@ class Controller extends Component {
} }
exclusionCreate(days) { exclusionCreate(days) {
let exclusions = days.map(day => { let exclusions = days.map(dated => {
return {day}; return {dated};
}); });
this.$http.post(this.exclusionsPath, exclusions) this.$http.post(this.exclusionsPath, exclusions)

View File

@ -1,40 +0,0 @@
<div class="search-panel">
<form ng-submit="$ctrl.onSearch()">
<vn-horizontal>
<vn-textfield
vn-one
label="General search"
ng-model="filter.search"
vn-focus>
</vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-textfield
vn-one
label="Name"
ng-model="filter.name">
</vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete
vn-one
label="Agency"
ng-model="filter.agencyModeFk"
url="AgencyModes/isActive"
show-field="name"
value-field="id">
</vn-autocomplete>
<vn-autocomplete
vn-one
label="Warehouse"
ng-model="filter.warehouseFk"
url="Warehouses"
show-field="name"
value-field="id">
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal class="vn-mt-lg">
<vn-submit label="Search"></vn-submit>
</vn-horizontal>
</form>
</div>

View File

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

View File

@ -1,6 +1,6 @@
const app = require('vn-loopback/server/server'); const app = require('vn-loopback/server/server');
// Petición #1848
xdescribe('claimBeginning', () => { describe('claimBeginning', () => {
let ticket; let ticket;
let refundTicketSales; let refundTicketSales;
let salesInsertedInClaimEnd; let salesInsertedInClaimEnd;

View File

@ -16,7 +16,7 @@
<section class="photo" ng-repeat="photo in $ctrl.photos"> <section class="photo" ng-repeat="photo in $ctrl.photos">
<section class="image vn-shadow" on-error-src <section class="image vn-shadow" on-error-src
ng-style="{'background': 'url(/api/dms/' + photo.dmsFk + '/downloadFile?access_token=' + $ctrl.accessToken + ')'}" ng-style="{'background': 'url(/api/dms/' + photo.dmsFk + '/downloadFile?access_token=' + $ctrl.accessToken + ')'}"
zoom-image="dms/{{::photo.dmsFk}}/downloadFile?access_token={{::$ctrl.accessToken}}"> zoom-image="/api/dms/{{::photo.dmsFk}}/downloadFile?access_token={{::$ctrl.accessToken}}">
</section> </section>
<section class="actions"> <section class="actions">
<vn-button <vn-button

View File

@ -1,7 +1,6 @@
const app = require('vn-loopback/server/server'); const app = require('vn-loopback/server/server');
// Petición #1848 describe('order catalogFilter()', () => {
xdescribe('order catalogFilter()', () => {
it('should return an array of items', async() => { it('should return an array of items', async() => {
let filter = { let filter = {
where: { where: {

View File

@ -1,7 +1,6 @@
const app = require('vn-loopback/server/server'); const app = require('vn-loopback/server/server');
// Petición #1848
xdescribe('order getItemTypeAvailable()', () => { describe('order getItemTypeAvailable()', () => {
it('should call the getItemTypeAvailable method with a valid order and item category', async() => { it('should call the getItemTypeAvailable method with a valid order and item category', async() => {
let orderId = 11; let orderId = 11;
let itemCategoryId = 1; let itemCategoryId = 1;

View File

@ -1,6 +1,6 @@
const app = require('vn-loopback/server/server'); const app = require('vn-loopback/server/server');
// Petición #1848
xdescribe('ticket componentUpdate()', () => { describe('ticket componentUpdate()', () => {
const ticketId = 11; const ticketId = 11;
const today = new Date(); const today = new Date();
const tomorrow = new Date(); const tomorrow = new Date();

View File

@ -2,7 +2,7 @@ const app = require('vn-loopback/server/server');
let UserError = require('vn-loopback/util/user-error'); let UserError = require('vn-loopback/util/user-error');
xdescribe('ticket new()', () => { describe('ticket new()', () => {
let ticket; let ticket;
let today = new Date(); let today = new Date();
let ctx = {req: {accessToken: {userId: 1}}}; let ctx = {req: {accessToken: {userId: 1}}};

View File

@ -1,7 +1,7 @@
const app = require('vn-loopback/server/server'); const app = require('vn-loopback/server/server');
let UserError = require('vn-loopback/util/user-error'); let UserError = require('vn-loopback/util/user-error');
xdescribe('sale priceDifference()', () => { describe('sale priceDifference()', () => {
it('should return ticket price differences', async() => { it('should return ticket price differences', async() => {
let tomorrow = new Date(); let tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1); tomorrow.setDate(tomorrow.getDate() + 1);

View File

@ -46,7 +46,8 @@ class Controller {
this.getShipped({ this.getShipped({
landed: this.ticket.landed, landed: this.ticket.landed,
addressFk: value, addressFk: value,
agencyModeFk: this.ticket.agencyModeFk agencyModeFk: this.ticket.agencyModeFk,
warehouseFk: this.ticket.warehouseFk
}); });
} }
} }
@ -77,7 +78,8 @@ class Controller {
this.getLanded({ this.getLanded({
shipped: value, shipped: value,
addressFk: this.ticket.addressFk, addressFk: this.ticket.addressFk,
agencyModeFk: this.ticket.agencyModeFk agencyModeFk: this.ticket.agencyModeFk,
warehouseFk: this.ticket.warehouseFk
}); });
} }
@ -90,7 +92,8 @@ class Controller {
this.getShipped({ this.getShipped({
landed: value, landed: value,
addressFk: this.ticket.addressFk, addressFk: this.ticket.addressFk,
agencyModeFk: this.ticket.agencyModeFk agencyModeFk: this.ticket.agencyModeFk,
warehouseFk: this.ticket.warehouseFk
}); });
} }
@ -104,7 +107,8 @@ class Controller {
this.getLanded({ this.getLanded({
shipped: this.ticket.shipped, shipped: this.ticket.shipped,
addressFk: this.ticket.addressFk, addressFk: this.ticket.addressFk,
agencyModeFk: value agencyModeFk: value,
warehouseFk: this.ticket.warehouseFk
}); });
} }
} }
@ -197,7 +201,6 @@ class Controller {
this.$http.get(query, {params}).then(res => { this.$http.get(query, {params}).then(res => {
if (res.data) { if (res.data) {
this.ticket.zoneFk = res.data.zoneFk; this.ticket.zoneFk = res.data.zoneFk;
this.ticket.agencyModeFk = res.data.agencyModeFk;
this.ticket.landed = res.data.landed; this.ticket.landed = res.data.landed;
this.ticket.shipped = params.shipped; this.ticket.shipped = params.shipped;
} else { } else {
@ -217,7 +220,6 @@ class Controller {
this.$http.get(query, {params}).then(res => { this.$http.get(query, {params}).then(res => {
if (res.data) { if (res.data) {
this.ticket.zoneFk = res.data.zoneFk; this.ticket.zoneFk = res.data.zoneFk;
this.ticket.agencyModeFk = res.data.agencyModeFk;
this.ticket.landed = params.landed; this.ticket.landed = params.landed;
this.ticket.shipped = res.data.shipped; this.ticket.shipped = res.data.shipped;
} else { } else {

View File

@ -69,14 +69,15 @@ describe('Ticket', () => {
controller.ticket.addressFk = 99; controller.ticket.addressFk = 99;
controller.addressId = 100; controller.addressId = 100;
const landed = new Date(); const landed = new Date();
const spectedResult = { const expectedResult = {
landed: landed, landed: landed,
addressFk: 100, addressFk: 100,
agencyModeFk: 7 agencyModeFk: 7,
warehouseFk: 1
}; };
controller.landed = landed; controller.landed = landed;
expect(controller.getShipped).toHaveBeenCalledWith(spectedResult); expect(controller.getShipped).toHaveBeenCalledWith(expectedResult);
expect(controller.ticket.addressFk).toEqual(100); expect(controller.ticket.addressFk).toEqual(100);
}); });
}); });
@ -95,14 +96,15 @@ describe('Ticket', () => {
controller.ticket.warehouseId = 1; controller.ticket.warehouseId = 1;
controller.warehouseId = 2; controller.warehouseId = 2;
const landed = new Date(); const landed = new Date();
const spectedResult = { const expectedResult = {
landed: landed, landed: landed,
addressFk: 121, addressFk: 121,
agencyModeFk: 7 agencyModeFk: 7,
warehouseFk: 2
}; };
controller.landed = landed; controller.landed = landed;
expect(controller.getShipped).toHaveBeenCalledWith(spectedResult); expect(controller.getShipped).toHaveBeenCalledWith(expectedResult);
expect(controller.ticket.warehouseFk).toEqual(2); expect(controller.ticket.warehouseFk).toEqual(2);
}); });
}); });
@ -120,14 +122,15 @@ describe('Ticket', () => {
it('should set shipped property and call getLanded() method ', () => { it('should set shipped property and call getLanded() method ', () => {
spyOn(controller, 'getLanded'); spyOn(controller, 'getLanded');
const shipped = new Date(); const shipped = new Date();
const spectedResult = { const expectedResult = {
shipped: shipped, shipped: shipped,
addressFk: 121, addressFk: 121,
agencyModeFk: 7 agencyModeFk: 7,
warehouseFk: 1
}; };
controller.shipped = shipped; controller.shipped = shipped;
expect(controller.getLanded).toHaveBeenCalledWith(spectedResult); expect(controller.getLanded).toHaveBeenCalledWith(expectedResult);
}); });
}); });
@ -144,15 +147,16 @@ describe('Ticket', () => {
it('should set shipped property and call getShipped() method ', () => { it('should set shipped property and call getShipped() method ', () => {
spyOn(controller, 'getShipped'); spyOn(controller, 'getShipped');
const landed = new Date(); const landed = new Date();
const spectedResult = { const expectedResult = {
landed: landed, landed: landed,
addressFk: 121, addressFk: 121,
agencyModeFk: 7 agencyModeFk: 7,
warehouseFk: 1
}; };
controller.landed = landed; controller.landed = landed;
expect(controller.getShipped).toHaveBeenCalledWith(spectedResult); expect(controller.getShipped).toHaveBeenCalledWith(expectedResult);
}); });
}); });
@ -169,30 +173,32 @@ describe('Ticket', () => {
spyOn(controller, 'getLanded'); spyOn(controller, 'getLanded');
const shipped = new Date(); const shipped = new Date();
const agencyModeId = 8; const agencyModeId = 8;
const spectedResult = { const expectedResult = {
shipped: shipped, shipped: shipped,
addressFk: 121, addressFk: 121,
agencyModeFk: agencyModeId agencyModeFk: agencyModeId,
warehouseFk: 1
}; };
controller.ticket.shipped = shipped; controller.ticket.shipped = shipped;
controller.agencyModeId = 8; controller.agencyModeId = 8;
expect(controller.getLanded).toHaveBeenCalledWith(spectedResult); expect(controller.getLanded).toHaveBeenCalledWith(expectedResult);
}); });
it('should do nothing if attempting to set the same agencyMode id', () => { it('should do nothing if attempting to set the same agencyMode id', () => {
spyOn(controller, 'getShipped'); spyOn(controller, 'getShipped');
const landed = new Date(); const landed = new Date();
const agencyModeId = 7; const agencyModeId = 7;
const spectedResult = { const expectedResult = {
landed: landed, landed: landed,
addressFk: 121, addressFk: 121,
agencyModeFk: agencyModeId agencyModeFk: agencyModeId,
warehouseFk: 1
}; };
controller.ticket.landed = landed; controller.ticket.landed = landed;
controller.agencyModeId = 7; controller.agencyModeId = 7;
expect(controller.getShipped).not.toHaveBeenCalledWith(spectedResult); expect(controller.getShipped).not.toHaveBeenCalledWith(expectedResult);
}); });
}); });

View File

@ -1,7 +1,7 @@
const UserError = require('vn-loopback/util/user-error'); const UserError = require('vn-loopback/util/user-error');
module.exports = Self => { module.exports = Self => {
Self.remoteMethodCtx('addTime', { Self.remoteMethodCtx('addTimeEntry', {
description: 'Adds a new hour registry', description: 'Adds a new hour registry',
accessType: 'WRITE', accessType: 'WRITE',
accepts: [{ accepts: [{
@ -16,12 +16,12 @@ module.exports = Self => {
root: true root: true
}], }],
http: { http: {
path: `/addTime`, path: `/addTimeEntry`,
verb: 'POST' verb: 'POST'
} }
}); });
Self.addTime = async(ctx, data) => { Self.addTimeEntry = async(ctx, data) => {
const Worker = Self.app.models.Worker; const Worker = Self.app.models.Worker;
const myUserId = ctx.req.accessToken.userId; const myUserId = ctx.req.accessToken.userId;
const myWorker = await Worker.findOne({where: {userFk: myUserId}}); const myWorker = await Worker.findOne({where: {userFk: myUserId}});

View File

@ -0,0 +1,41 @@
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.remoteMethodCtx('deleteTimeEntry', {
description: 'Deletes a manual time entry for a worker if the user role is above the worker',
accessType: 'READ',
accepts: [{
arg: 'id',
type: 'number',
required: true,
description: 'The time entry id',
http: {source: 'path'}
}],
returns: {
type: 'boolean',
root: true
},
http: {
path: `/:id/deleteTimeEntry`,
verb: 'POST'
}
});
Self.deleteTimeEntry = async(ctx, id) => {
const currentUserId = ctx.req.accessToken.userId;
const workerModel = Self.app.models.Worker;
const targetTimeEntry = await Self.findById(id);
const isSubordinate = await workerModel.isSubordinate(ctx, targetTimeEntry.userFk);
const isHHRR = await Self.app.models.Account.hasRole(currentUserId, 'hr');
const notAllowed = isSubordinate === false || (isSubordinate && currentUserId == targetTimeEntry.userFk && !isHHRR);
if (notAllowed)
throw new UserError(`You don't have enough privileges`);
return Self.rawSql('CALL vn.workerTimeControl_remove(?, ?)', [
targetTimeEntry.userFk, targetTimeEntry.timed]);
};
};

View File

@ -0,0 +1,99 @@
const app = require('vn-loopback/server/server');
describe('workerTimeControl addTimeEntry()', () => {
let insertedTime;
it('should fail to add a time entry if the target user is not a subordinate', async() => {
let error;
let ctx = {req: {accessToken: {userId: 1}}};
let data = {
workerFk: 2,
timed: new Date()
};
try {
await app.models.WorkerTimeControl.addTimeEntry(ctx, data);
} catch (e) {
error = e;
}
expect(error).toBeDefined();
expect(error.statusCode).toBe(400);
expect(error.message).toBe(`You don't have enough privileges`);
});
it('should fail to add if the current and the target user are the same and is not team boss', async() => {
let error;
let ctx = {req: {accessToken: {userId: 1}}};
let data = {
workerFk: 1,
timed: new Date()
};
try {
await app.models.WorkerTimeControl.addTimeEntry(ctx, data);
} catch (e) {
error = e;
}
expect(error).toBeDefined();
expect(error.statusCode).toBe(400);
expect(error.message).toBe(`You don't have enough privileges`);
});
it('should add if the current user is team boss and the target user is a subordinate', async() => {
todayAtSix = new Date();
todayAtSix.setHours(18, 30, 0, 0);
let teamBossId = 13;
let ctx = {req: {accessToken: {userId: teamBossId}}};
let data = {
workerFk: teamBossId,
timed: todayAtSix
};
await app.models.WorkerTimeControl.addTimeEntry(ctx, data);
insertedTime = await app.models.WorkerTimeControl.findOne({where: {timed: data.timed}});
let createdTimeEntry = await app.models.WorkerTimeControl.findById(insertedTime.id);
expect(createdTimeEntry).toBeDefined();
});
it('should try but fail to delete the created time entry for the team boss as team boss', async() => {
let error;
let teamBossId = 13;
let ctx = {req: {accessToken: {userId: teamBossId}}};
let createdTimeEntry = await app.models.WorkerTimeControl.findById(insertedTime.id);
expect(createdTimeEntry).toBeDefined();
try {
await app.models.WorkerTimeControl.deleteTimeEntry(ctx, createdTimeEntry.id);
} catch (e) {
error = e;
}
expect(error).toBeDefined();
expect(error.statusCode).toBe(400);
expect(error.message).toBe(`You don't have enough privileges`);
});
it('should delete the created time entry for the team boss as HHRR', async() => {
let HHRRId = 37;
let ctx = {req: {accessToken: {userId: HHRRId}}};
let createdTimeEntry = await app.models.WorkerTimeControl.findById(insertedTime.id);
expect(createdTimeEntry).toBeDefined();
ctx.req.accessToken.userId = HHRRId;
await app.models.WorkerTimeControl.deleteTimeEntry(ctx, insertedTime.id);
createdTimeEntry = await app.models.WorkerTimeControl.findById(insertedTime.id);
expect(createdTimeEntry).toBeNull();
});
});

View File

@ -0,0 +1,67 @@
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
module.exports = Self => {
Self.remoteMethod('getWorkedHours', {
description: 'returns the total worked hours per day for a given range of dates in format YYYY-mm-dd hh:mm:ss',
accessType: 'READ',
accepts: [{
arg: 'id',
type: 'number',
required: true,
description: 'The worker id',
http: {source: 'path'}
},
{
arg: 'from',
type: 'Date',
required: true,
description: `The from date`
},
{
arg: 'to',
type: 'Date',
required: true,
description: `The to date`
}],
returns: {
type: ['Object'],
root: true
},
http: {
path: `/:id/getWorkedHours`,
verb: 'GET'
}
});
Self.getWorkedHours = async(id, from, to) => {
const conn = Self.dataSource.connector;
const stmts = [];
let worker = await Self.app.models.Worker.findById(id);
let userId = worker.userFk;
stmts.push(`
DROP TEMPORARY TABLE IF EXISTS
tmp.timeControlCalculate,
tmp.timeBusinessCalculate
`);
stmts.push(new ParameterizedSQL('CALL vn.timeControl_calculateByUser(?, ?, ?)', [userId, from, to]));
stmts.push(new ParameterizedSQL('CALL vn.timeBusiness_calculateByUser(?, ?, ?)', [userId, from, to]));
let resultIndex = stmts.push(`
SELECT tbc.dated, tbc.timeWorkSeconds expectedHours, tcc.timeWorkSeconds workedHours
FROM tmp.timeBusinessCalculate tbc
LEFT JOIN tmp.timeControlCalculate tcc ON tcc.dated = tbc.dated
`) - 1;
stmts.push(`
DROP TEMPORARY TABLE IF EXISTS
tmp.timeControlCalculate,
tmp.timeBusinessCalculate
`);
let sql = ParameterizedSQL.join(stmts, ';');
let result = await conn.executeStmt(sql);
return result[resultIndex];
};
};

View File

@ -1,98 +0,0 @@
/*
Author : Enrique Blasco BLanquer
Date: 28 de mayo de 2019
*/
module.exports = Self => {
Self.remoteMethodCtx('getWorkerInfo', {
description: 'Get worker info (name, isWorking, total worked hours ...)',
accessType: 'WRITE',
returns: [{
type: 'Object',
root: true
}],
http: {
path: `/getWorkerInfo`,
verb: 'GET'
}
});
Self.getWorkerInfo = async(ctx, data) => {
let prevHour = new Date(); // default value to start work
let diff = 0; // difference of value between two dates
let isOdd = true; // determine if timed is odd or not in db
const myUserId = ctx.req.accessToken.userId; // get user id
// 1 get name and photo for the user
let [user] = await Self.rawSql(`SELECT u.name, t.Foto FROM vn.user u INNER JOIN vn2008.Trabajadores t ON u.id = t.user_id WHERE id = ?;`, [myUserId]);
// 2 get all jornaly work time registered
let workedHours = await Self.rawSql(`SELECT * FROM vn.workerTimeControl WHERE userFk = ? AND DATE(timed) = CURDATE() ORDER BY timed ASC;`, [myUserId]);
let today = new Date();
// 3 get the number of hours to work in one day
let date = today.getFullYear() + '-' + (today.getMonth() + 1) + '-' + today.getDate();
let [hoursForDay] = await Self.rawSql(`SELECT cl.hours_week AS hoursWeek,
GROUP_CONCAT(DISTINCT LEFT(j.start,2) ORDER BY j.start ASC SEPARATOR '-') start ,
GROUP_CONCAT(DISTINCT LEFT(j.end,2) ORDER BY j.end ASC SEPARATOR '-') end,
CAST(IFNULL((SUM(TIME_TO_SEC(j.end))-SUM(TIME_TO_SEC(j.start)))/3600,if(cl.hours_week=40
AND DAYOFWEEK(t.dated) IN(2,3,4,5,6),8,0)) AS DECIMAL(10,2)) workingHours
FROM vn.time t
LEFT JOIN postgresql.business b ON t.dated BETWEEN b.date_start AND ifnull(b.date_end,? )
LEFT JOIN postgresql.profile AS pr ON b.client_id = pr.profile_id
LEFT JOIN postgresql.person AS p ON pr.person_id = p.person_id
LEFT JOIN vn.worker AS w ON p.id_trabajador = w.id
LEFT JOIN postgresql.business_labour AS bl ON b.business_id = bl.business_id
LEFT JOIN postgresql.calendar_labour_type AS cl ON bl.calendar_labour_type_id = cl.calendar_labour_type_id
LEFT JOIN postgresql.journey AS j ON j.business_id = b.business_id and j.day_id=WEEKDAY(t.dated)+1
WHERE t.dated BETWEEN ? AND ? AND userFk = ?
GROUP BY w.userFk,dated`, [date, date, date, myUserId]);
// 4 Add all the hours and see the total worked
for (hour of workedHours) {
if (!isOdd)
diff += Math.abs((new Date(hour.timed)).getTime() - prevHour.getTime());
else
prevHour = new Date(hour.timed);
isOdd = !isOdd;
}
// 5 calculate hours and minutes from a number value
let decimalTime = diff / 1000 / 3600;
decimalTime = decimalTime * 60 * 60;
let hours = Math.floor((decimalTime / (60 * 60)));
decimalTime = decimalTime - (hours * 60 * 60);
let minutes = Math.floor((decimalTime / 60));
// 6 default total hours
let totalHours = '7:40';
let hoursWeek = 40;
// 7 Get the hours you have to work today and the hours to work in a week
if (hoursForDay != null) {
// If it exceeds 5 hours we take 20 minutes of breakfast.
if (hoursForDay.workingHours > 5)
hoursForDay.workingHours -= 20 * 0.016666;
let decimalTime = parseFloat(hoursForDay.workingHours);
decimalTime = decimalTime * 60 * 60;
let hoursDay = Math.floor((decimalTime / (60 * 60)));
decimalTime = decimalTime - (hoursDay * 60 * 60);
let minutesDay = Math.floor((decimalTime / 60));
totalHours = hoursDay + ':' + minutesDay;
}
// 8 return value
if (hoursForDay != null)
hoursWeek = hoursForDay.hoursWeek;
return {
'name': user.name,
'hours': hours,
'minutes': minutes,
'today': today,
'isWorking': !isOdd,
'lastDate': prevHour,
'totalHours': totalHours,
'hoursWeek': hoursWeek
};
};
};

View File

@ -0,0 +1,50 @@
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
module.exports = Self => {
Self.remoteMethod('timeControl', {
description: 'Returns a range of worked hours for a given worker id',
accessType: 'READ',
accepts: [
{
arg: 'id',
type: 'number',
required: true,
description: 'The worker id',
http: {source: 'path'}
},
{
arg: 'dateFrom',
type: 'datetime',
required: true,
description: 'the date from the time control begins in format YYYY-mm-dd-hh:mm:ss'
},
{
arg: 'dateTo',
type: 'datetime',
required: true,
description: 'the date when the time control finishes in format YYYY-mm-dd-hh:mm:ss'
}],
returns: {
type: ['Object'],
root: true
},
http: {
path: `/:id/timeControl`,
verb: 'GET'
}
});
Self.timeControl = async(id, from, to) => {
const conn = Self.dataSource.connector;
const stmts = [];
stmts.push(new ParameterizedSQL('CALL vn.timeControl_calculateByUser(?, ?, ?)', [id, from, to]));
let sql = ParameterizedSQL.join(stmts, ';');
let result = await conn.executeStmt(sql);
return result[0];
};
};

View File

@ -2,7 +2,8 @@ const UserError = require('vn-loopback/util/user-error');
module.exports = Self => { module.exports = Self => {
require('../methods/worker-time-control/filter')(Self); require('../methods/worker-time-control/filter')(Self);
require('../methods/worker-time-control/addTime')(Self); require('../methods/worker-time-control/addTimeEntry')(Self);
require('../methods/worker-time-control/deleteTimeEntry')(Self);
Self.rewriteDbError(function(err) { Self.rewriteDbError(function(err) {
if (err.code === 'ER_DUP_ENTRY') if (err.code === 'ER_DUP_ENTRY')

View File

@ -19,6 +19,9 @@
}, },
"order": { "order": {
"type": "Number" "type": "Number"
},
"direction": {
"type": "string"
} }
}, },
"relations": { "relations": {
@ -26,6 +29,11 @@
"type": "belongsTo", "type": "belongsTo",
"model": "Account", "model": "Account",
"foreignKey": "userFk" "foreignKey": "userFk"
},
"worker": {
"type": "hasOne",
"model": "Worker",
"foreignKey": "userFk"
}, },
"warehouse": { "warehouse": {
"type": "belongsTo", "type": "belongsTo",

View File

@ -2,5 +2,5 @@ module.exports = Self => {
require('../methods/worker/filter')(Self); require('../methods/worker/filter')(Self);
require('../methods/worker/mySubordinates')(Self); require('../methods/worker/mySubordinates')(Self);
require('../methods/worker/isSubordinate')(Self); require('../methods/worker/isSubordinate')(Self);
require('../methods/worker/getWorkerInfo')(Self); require('../methods/worker/getWorkedHours')(Self);
}; };

View File

@ -8,24 +8,47 @@
<vn-table model="model" auto-load="false"> <vn-table model="model" auto-load="false">
<vn-thead> <vn-thead>
<vn-tr> <vn-tr>
<vn-td ng-repeat="weekday in $ctrl.weekDays" center> <vn-td ng-repeat="weekday in $ctrl.weekDays" center>
<div translate>{{::$ctrl.weekdayNames[$index].name}}</div> <div class="weekday" translate>{{::$ctrl.weekdayNames[$index].name}}</div>
<span>{{::weekday.dated | date: 'dd'}}</span> <div>
<span title="{{::weekday.dated | date: 'MMMM' | translate}}" translate> <span>{{::weekday.dated | date: 'dd'}}</span>
{{::weekday.dated | date: 'MMMM'}} <span title="{{::weekday.dated | date: 'MMMM' | translate}}" translate>
</span> {{::weekday.dated | date: 'MMMM'}}
</span>
</div>
<vn-chip
title="{{::weekday.event.name}}"
ng-class="{invisible: !weekday.event}">
<vn-avatar
ng-style="::{backgroundColor: weekday.event.color}">
</vn-avatar>
<div>
{{::weekday.event.name}}
</div>
</vn-chip>
</vn-td> </vn-td>
</vn-tr> </vn-tr>
</vn-thead> </vn-thead>
<vn-tbody> <vn-tbody>
<vn-tr> <vn-tr>
<vn-td ng-repeat="weekday in $ctrl.weekDays" class="hours vn-pa-none" center> <vn-td ng-repeat="weekday in $ctrl.weekDays" class="hours vn-pa-none" expand center>
<section ng-repeat="hour in weekday.hours" center> <section ng-repeat="hour in weekday.hours" center>
<vn-icon <vn-icon
icon="arrow_{{($index % 2) == 0 ? 'forward' : 'back'}}" icon="{{
title="{{(($index % 2) == 0 ? 'In' : 'Out') | translate}}"> ::hour.direction == 'in' ? 'arrow_forward' : 'arrow_back'
}}"
title="{{
::(hour.direction == 'in' ? 'In' : 'Out') | translate
}}"
ng-class="::{'invisible': hour.direction == 'middle'}">
</vn-icon> </vn-icon>
<span class="chip {{$ctrl.hourColor(hour)}}">{{hour.timed | date: 'HH:mm'}}</span> <vn-chip
ng-class="::{'colored': hour.manual}"
removable="::hour.manual"
translate-attr="{title: 'Category'}"
on-remove="$ctrl.showDeleteDialog(hour)">
{{::hour.timed | date: 'HH:mm'}}
</vn-chip>
</section> </section>
</vn-td> </vn-td>
</vn-tr> </vn-tr>
@ -33,7 +56,7 @@
<vn-tfoot> <vn-tfoot>
<vn-tr> <vn-tr>
<vn-td ng-repeat="weekday in $ctrl.weekDays" center> <vn-td ng-repeat="weekday in $ctrl.weekDays" center>
{{$ctrl.getWeekdayTotalHours(weekday)}} h. {{$ctrl.formatHours(weekday.workedHours)}} h.
</vn-td> </vn-td>
</vn-tr> </vn-tr>
<vn-tr> <vn-tr>
@ -56,6 +79,10 @@
label="Week total" label="Week total"
value="{{$ctrl.weekTotalHours}} h."> value="{{$ctrl.weekTotalHours}} h.">
</vn-label-value> </vn-label-value>
<vn-label-value
label="Finish at"
value="{{$ctrl.getFinishTime()}}">
</vn-label-value>
</div> </div>
<vn-calendar <vn-calendar
class="vn-pt-md" class="vn-pt-md"
@ -85,3 +112,9 @@
<button response="accept" translate>Save</button> <button response="accept" translate>Save</button>
</tpl-buttons> </tpl-buttons>
</vn-dialog> </vn-dialog>
<vn-confirm
vn-id="delete-entry-dialog"
on-accept="$ctrl.deleteTimeEntry()"
message="This time entry will be deleted"
question="Are you sure you want to delete this entry?">
</vn-confirm>

View File

@ -1,12 +1,9 @@
import Component from 'core/lib/component';
import ngModule from '../module'; import ngModule from '../module';
import './style.scss'; import './style.scss';
class Controller extends Component {
class Controller { constructor($element, $, vnWeekDays) {
constructor($scope, $http, $stateParams, $element, vnWeekDays) { super($element, $);
this.$stateParams = $stateParams;
this.$ = $scope;
this.$http = $http;
this.$element = $element;
this.weekDays = []; this.weekDays = [];
this.weekdayNames = vnWeekDays.locales; this.weekdayNames = vnWeekDays.locales;
} }
@ -34,9 +31,20 @@ class Controller {
this.started = started; this.started = started;
let ended = new Date(started.getTime()); let ended = new Date(started.getTime());
ended.setDate(ended.getDate() + 7); ended.setHours(23, 59, 59, 59);
ended.setDate(ended.getDate() + 6);
this.ended = ended; this.ended = ended;
this.weekDays = [];
let dayIndex = new Date(started.getTime());
while (dayIndex < ended) {
this.weekDays.push({
dated: new Date(dayIndex.getTime())
});
dayIndex.setDate(dayIndex.getDate() + 1);
}
this.fetchHours(); this.fetchHours();
} }
@ -49,86 +57,118 @@ class Controller {
set hours(value) { set hours(value) {
this._hours = value; this._hours = value;
this.weekDays = [];
if (!this.hours) return;
let dayIndex = new Date(this.started.getTime()); for (const weekDay of this.weekDays) {
if (value) {
while (dayIndex < this.ended) { let day = weekDay.dated.getDay();
let weekDay = dayIndex.getDay(); weekDay.hours = value
.filter(hour => new Date(hour.timed).getDay() == day)
let hours = this.hours .sort((a, b) => new Date(a.timed) - new Date(b.timed));
.filter(hour => new Date(hour.timed).getDay() == weekDay) } else
.sort((a, b) => new Date(a.timed) - new Date(b.timed)); weekDay.hours = null;
this.weekDays.push({
dated: new Date(dayIndex.getTime()),
hours
});
dayIndex.setDate(dayIndex.getDate() + 1);
} }
} }
fetchHours() { fetchHours() {
const params = {workerFk: this.$stateParams.id}; const params = {workerFk: this.$params.id};
const filter = { const filter = {
where: {and: [ where: {and: [
{timed: {gte: this.started}}, {timed: {gte: this.started}},
{timed: {lt: this.ended}} {timed: {lte: this.ended}}
]} ]}
}; };
this.$.model.applyFilter(filter, params); this.$.model.applyFilter(filter, params);
this.getAbsences();
this.getWorkedHours(this.started, this.ended);
} }
hasEvents(day) { hasEvents(day) {
return day >= this.started && day < this.ended; return day >= this.started && day < this.ended;
} }
hourColor(weekDay) { getWorkedHours(from, to) {
return weekDay.manual ? 'alert' : 'warning'; this.weekTotalHours = null;
let weekTotalHours = 0;
let params = {
id: this.$params.id,
from: from,
to: to
};
const query = `Workers/${this.$params.id}/getWorkedHours`;
return this.$http.get(query, {params}).then(res => {
const workDays = res.data;
const map = new Map();
for (const workDay of workDays) {
workDay.dated = new Date(workDay.dated);
map.set(workDay.dated, workDay);
weekTotalHours += workDay.workedHours;
}
for (const weekDay of this.weekDays) {
const workDay = workDays.find(day => {
let from = new Date(day.dated);
from.setHours(0, 0, 0, 0);
let to = new Date(day.dated);
to.setHours(23, 59, 59, 59);
return weekDay.dated >= from && weekDay.dated <= to;
});
if (workDay) {
weekDay.expectedHours = workDay.expectedHours;
weekDay.workedHours = workDay.workedHours;
}
}
this.weekTotalHours = weekTotalHours;
});
} }
getWeekdayTotalHours(weekday) { getFinishTime() {
if (weekday.hours.length == 0) return 0; if (!this.weekDays) return;
const hours = weekday.hours; let today = new Date();
today.setHours(0, 0, 0, 0);
let totalStamp = 0; let todayInWeek = this.weekDays.find(day => day.dated.getTime() === today.getTime());
hours.forEach((hour, index) => { if (todayInWeek && todayInWeek.hours && todayInWeek.hours.length) {
let currentHour = new Date(hour.timed); const remainingTime = todayInWeek.workedHours ? ((todayInWeek.expectedHours - todayInWeek.workedHours) * 1000) : null;
let previousHour = new Date(hour.timed); const lastKnownEntry = todayInWeek.hours[todayInWeek.hours.length - 1];
const lastKnownTime = new Date(lastKnownEntry.timed).getTime();
const finishTimeStamp = lastKnownTime && remainingTime ? lastKnownTime + remainingTime : null;
if (index > 0 && (index % 2 == 1)) if (finishTimeStamp) {
previousHour = new Date(hours[index - 1].timed); let finishDate = new Date(finishTimeStamp);
let hour = finishDate.getHours();
let minute = finishDate.getMinutes();
const dif = Math.abs(previousHour - currentHour); if (hour < 10) hour = `0${hour}`;
if (minute < 10) minute = `0${minute}`;
totalStamp += dif; return `${hour}:${minute} h.`;
}); }
}
}
if (totalStamp / 3600 / 1000 > 5) set weekTotalHours(totalHours) {
totalStamp += (20 * 60 * 1000); if (!totalHours) return this._weekTotalHours = this.formatHours(0);
weekday.total = totalStamp; this._weekTotalHours = this.formatHours(totalHours);
return this.formatHours(totalStamp);
} }
get weekTotalHours() { get weekTotalHours() {
let total = 0; return this._weekTotalHours;
this.weekDays.forEach(weekday => {
if (weekday.total)
total += weekday.total;
});
return this.formatHours(total);
} }
formatHours(timestamp) { formatHours(timestamp) {
let hour = Math.floor(timestamp / 3600 / 1000); timestamp = timestamp || 0;
let min = Math.floor(timestamp / 60 / 1000 - 60 * hour);
let hour = Math.floor(timestamp / 3600);
let min = Math.floor(timestamp / 60 - 60 * hour);
if (hour < 10) hour = `0${hour}`; if (hour < 10) hour = `0${hour}`;
if (min < 10) min = `0${min}`; if (min < 10) min = `0${min}`;
@ -148,15 +188,76 @@ class Controller {
addTime(response) { addTime(response) {
if (response !== 'accept') return; if (response !== 'accept') return;
let data = { let data = {
workerFk: this.$stateParams.id, workerFk: this.$params.id,
timed: this.newTime timed: this.newTime
}; };
this.$http.post(`WorkerTimeControls/addTime`, data) this.$http.post(`WorkerTimeControls/addTimeEntry`, data)
.then(() => this.fetchHours()); .then(() => this.fetchHours());
} }
showDeleteDialog(hour) {
this.timeEntryToDelete = hour;
this.$.deleteEntryDialog.show();
}
deleteTimeEntry() {
const entryId = this.timeEntryToDelete.id;
this.$http.post(`WorkerTimeControls/${entryId}/deleteTimeEntry`).then(() => {
this.fetchHours();
this.vnApp.showSuccess(this.$t('Entry removed'));
});
}
getAbsences() {
let params = {
workerFk: this.$params.id,
started: this.started,
ended: this.ended
};
return this.$http.get(`WorkerCalendars/absences`, {params})
.then(res => this.onData(res.data));
}
onData(data) {
const events = {};
let addEvent = (day, event) => {
events[new Date(day).getTime()] = event;
};
if (data.holidays) {
data.holidays.forEach(holiday => {
const holidayDetail = holiday.detail && holiday.detail.description;
const holidayType = holiday.type && holiday.type.name;
const holidayName = holidayDetail || holidayType;
addEvent(holiday.dated, {
name: holidayName,
color: '#ff0'
});
});
}
if (data.absences) {
data.absences.forEach(absence => {
const type = absence.absenceType;
addEvent(absence.dated, {
name: type.name,
color: type.rgb
});
});
}
this.weekDays.forEach(day => {
const timestamp = day.dated.getTime();
if (events[timestamp])
day.event = events[timestamp];
});
}
} }
Controller.$inject = ['$scope', '$http', '$stateParams', '$element', 'vnWeekDays']; Controller.$inject = ['$element', '$scope', 'vnWeekDays'];
ngModule.component('vnWorkerTimeControl', { ngModule.component('vnWorkerTimeControl', {
template: require('./index.html'), template: require('./index.html'),

View File

@ -1,111 +1,115 @@
import './index.js'; import './index.js';
describe('Worker', () => {
describe('Component vnWorkerTimeControl', () => {
let $httpBackend;
let $scope;
let $element;
let controller;
beforeEach(ngModule('worker')); describe('Component vnWorkerTimeControl', () => {
let $httpBackend;
let $scope;
let $element;
let controller;
beforeEach(angular.mock.inject(($compile, $rootScope, $stateParams, _$httpBackend_) => { beforeEach(ngModule('worker'));
$stateParams.id = 1;
$httpBackend = _$httpBackend_;
$scope = $rootScope.$new();
$element = $compile('<vn-worker-time-control></vn-worker-time-control>')($scope);
controller = $element.controller('vnWorkerTimeControl');
}));
afterEach(() => { beforeEach(angular.mock.inject(($componentController, $compile, $rootScope, $stateParams, _$httpBackend_) => {
$scope.$destroy(); $stateParams.id = 1;
$element.remove(); $httpBackend = _$httpBackend_;
$scope = $rootScope.$new();
$element = angular.element('<vn-worker-time-control></vn-worker-time-control>');
controller = $componentController('vnWorkerTimeControl', {$element, $scope});
}));
describe('date() setter', () => {
it(`should set the weekDays, the date in the controller and call fetchHours`, () => {
let today = new Date();
spyOn(controller, 'fetchHours');
controller.date = today;
expect(controller._date).toEqual(today);
expect(controller.started).toBeDefined();
expect(controller.ended).toBeDefined();
expect(controller.weekDays.length).toEqual(7);
expect(controller.fetchHours).toHaveBeenCalledWith();
}); });
});
describe('hours() setter', () => { describe('hours() setter', () => {
it(`should set hours data at it's corresponding week day`, () => { it(`should set hours data at it's corresponding week day`, () => {
let wednesday = new Date(controller.started.getTime()); let today = new Date();
wednesday.setDate(wednesday.getDate() + 2); spyOn(controller, 'fetchHours');
$httpBackend.whenRoute('GET', 'WorkerTimeControls/filter') controller.date = today;
.respond([
{
id: 1,
timed: controller.started.toJSON(),
userFk: 1
}, {
id: 2,
timed: wednesday.toJSON(),
userFk: 1
}, {
id: 3,
timed: wednesday.toJSON(),
userFk: 1
}
]);
$httpBackend.flush(); let hours = [
{
id: 1,
timed: controller.started.toJSON(),
userFk: 1
}, {
id: 2,
timed: controller.ended.toJSON(),
userFk: 1
}, {
id: 3,
timed: controller.ended.toJSON(),
userFk: 1
}
];
expect(controller.weekDays.length).toEqual(7); controller.hours = hours;
expect(controller.weekDays[0].hours.length).toEqual(1);
expect(controller.weekDays[2].hours.length).toEqual(2); expect(controller.weekDays.length).toEqual(7);
}); expect(controller.weekDays[0].hours.length).toEqual(1);
expect(controller.weekDays[6].hours.length).toEqual(2);
}); });
});
describe('getWeekdayTotalHours() ', () => { describe('getWorkedHours() ', () => {
it(`should return a total worked hours from 07:00 to 15:00`, () => { it(`should `, () => {
const hourOne = new Date(); let today = new Date();
hourOne.setHours(7, 0, 0, 0); spyOn(controller, 'fetchHours');
const hourTwo = new Date();
hourTwo.setHours(10, 0, 0, 0);
const hourThree = new Date();
hourThree.setHours(10, 20, 0, 0);
const hourFour = new Date();
hourFour.setHours(15, 0, 0, 0);
const weekday = {hours: [ controller.date = today;
{id: 1, timed: hourOne},
{id: 2, timed: hourTwo},
{id: 3, timed: hourThree},
{id: 4, timed: hourFour}
]};
const result = controller.getWeekdayTotalHours(weekday); let sixHoursInSeconds = 6 * 60 * 60;
let tenHoursInSeconds = 10 * 60 * 60;
let response = [
{
dated: today,
expectedHours: sixHoursInSeconds,
workedHours: tenHoursInSeconds,
expect(result).toEqual('08:00'); },
}); ];
}); $httpBackend.whenRoute('GET', 'Workers/:id/getWorkedHours')
.respond(response);
describe('weekTotalHours() ', () => { today.setHours(0, 0, 0, 0);
it(`should return a total worked hours from a week`, () => {
const hourOne = new Date();
hourOne.setHours(7, 0, 0, 0);
const hourTwo = new Date();
hourTwo.setHours(10, 0, 0, 0);
const hourThree = new Date();
hourThree.setHours(10, 20, 0, 0);
const hourFour = new Date();
hourFour.setHours(15, 0, 0, 0);
const weekday = {hours: [ let weekOffset = today.getDay() - 1;
{id: 1, timed: hourOne}, if (weekOffset < 0) weekOffset = 6;
{id: 2, timed: hourTwo},
{id: 3, timed: hourThree},
{id: 4, timed: hourFour}
]};
controller.weekDays = [weekday];
const weekdayHours = controller.getWeekdayTotalHours(weekday); let started = new Date(today.getTime());
const weekHours = controller.weekTotalHours; started.setDate(started.getDate() - weekOffset);
controller.started = started;
expect(weekdayHours).toEqual('08:00'); let ended = new Date(started.getTime());
expect(weekHours).toEqual('08:00'); ended.setHours(23, 59, 59, 59);
}); ended.setDate(ended.getDate() + 6);
controller.ended = ended;
controller.getWorkedHours(controller.started, controller.ended);
$httpBackend.flush();
expect(controller.weekDays.length).toEqual(7);
expect(controller.weekDays[weekOffset].expectedHours).toEqual(response[0].expectedHours);
expect(controller.weekDays[weekOffset].workedHours).toEqual(response[0].workedHours);
expect(controller.weekTotalHours).toEqual('10:00');
}); });
describe('formatHours() ', () => { describe('formatHours() ', () => {
it(`should format a passed timestamp to hours and minutes`, () => { it(`should format a passed timestamp to hours and minutes`, () => {
const result = controller.formatHours(3600000); const result = controller.formatHours(3600);
expect(result).toEqual('01:00'); expect(result).toEqual('01:00');
}); });

View File

@ -5,3 +5,7 @@ Hours: Horas
Add time: Añadir hora Add time: Añadir hora
Week total: Total semana Week total: Total semana
Current week: Semana actual Current week: Semana actual
This time entry will be deleted: Se borrará la hora fichada
Are you sure you want to delete this entry?: ¿Seguro que quieres eliminarla?
Finish at: Termina a las
Entry removed: Fichada borrada

View File

@ -1,11 +1,12 @@
@import "variables"; @import "variables";
vn-worker-time-control { vn-worker-time-control {
vn-thead > vn-tr > vn-td > div { vn-thead > vn-tr > vn-td > div.weekday {
margin-bottom: 5px; margin-bottom: 5px;
color: $color-main color: $color-main
} }
vn-td.hours { vn-td.hours {
min-width: 100px;
vertical-align: top; vertical-align: top;
& > section { & > section {

View File

@ -15,6 +15,7 @@
.grid-block { .grid-block {
box-sizing: border-box; box-sizing: border-box;
background-color: #FFF;
min-height: 40px min-height: 40px
} }
@ -22,10 +23,6 @@
height: 40px height: 40px
} }
.grid-block.white {
background-color: #FFF
}
.columns { .columns {
overflow: hidden; overflow: hidden;
box-sizing: border-box; box-sizing: border-box;

View File

@ -2,7 +2,8 @@
"app": { "app": {
"host": "http://localhost:5000", "host": "http://localhost:5000",
"port": 3000, "port": 3000,
"senderMail": "nocontestar@verdnatura.es", "senderEmail": "nocontestar@verdnatura.es",
"reportEmail": "cau@verdnatura.es",
"senderName": "Verdnatura" "senderName": "Verdnatura"
}, },
"i18n": { "i18n": {

View File

@ -4,13 +4,13 @@ buttons:
privacy: privacy:
fiscalAddress: VERDNATURA LEVANTE SL, B97367486 Avda. Espioca, 100, 46460 Silla fiscalAddress: VERDNATURA LEVANTE SL, B97367486 Avda. Espioca, 100, 46460 Silla
· www.verdnatura.es · clientes@verdnatura.es · www.verdnatura.es · clientes@verdnatura.es
disclaimer: '- AVIS - Ce message est privé et confidentiel et doit être utilisé.exclusivamente disclaimer: "- AVIS - Ce message est privé et confidentiel et doit être utilisé
por la persona destinataria del mismo. Si has recibido este mensajepor error, exclusivement par le destinataire. Si vous avez reçu ce message par erreur,
te rogamos lo comuniques al remitente y borres dicho mensaje y cualquier documentoadjunto veuillez en informer l'expéditeur et supprimer ce message ainsi que tous les
que pudiera contener. Verdnatura Levante SL no renuncia a la confidencialidad documents joints qu'il pourrait contenir. Verdnatura Levante SL ne renonce pas à la
ni aningún privilegio por causa de transmisión errónea o mal funcionamiento. Igualmente confidentialité ni aux privilèges résultant d'une transmission erronée ou d'un dysfonctionnement.
no se haceresponsable de los cambios, alteraciones, errores u omisiones que pudieran De même, il n'est pas responsable des modifications, altérations, erreurs ou
hacerse al mensaje una vez enviado.' omissions qui pourraient être apportées au message une fois envoyé."
law: En cumplimiento de lo dispuesto en la Ley Orgánica 15/1999, de Protección de law: En cumplimiento de lo dispuesto en la Ley Orgánica 15/1999, de Protección de
Datos de Carácter Personal, te comunicamos que los datos personales que facilites Datos de Carácter Personal, te comunicamos que los datos personales que facilites
se incluirán en ficheros automatizados de VERDNATURA LEVANTE S.L.,pudiendo en se incluirán en ficheros automatizados de VERDNATURA LEVANTE S.L.,pudiendo en

View File

@ -10,13 +10,20 @@ module.exports = {
}); });
} }
}, },
find(query, params) { /**
* Makes a query from a raw sql
* @param {String} query - The raw SQL query
* @param {Object} params - Parameterized values
*
* @return {Object} - Result
*/
rawSql(query, params) {
return this.pool.query(query, params).then(([rows]) => { return this.pool.query(query, params).then(([rows]) => {
return rows; return rows;
}); });
}, },
findOne(query, params) { findOne(query, params) {
return this.find(query, params).then(([rows]) => rows); return this.rawSql(query, params).then(([rows]) => rows);
}, },
findFromDef() { findFromDef() {

View File

@ -16,7 +16,7 @@ const validator = {
if (invalidProps.length > 0) { if (invalidProps.length > 0) {
const required = invalidProps.join(', '); const required = invalidProps.join(', ');
throw new Error(`Required params not found [${required}]`); throw new Error(`Required properties not found [${required}]`);
} }
}, },
props: ['isPreview'] props: ['isPreview']

View File

@ -1,51 +1,6 @@
const Report = require('./report');
const Email = require('./email');
module.exports = app => { module.exports = app => {
app.get(`/api/report/:name`, async(req, res, next) => { // Import methods
const args = req.query; require('../methods/closure')(app);
const requiredArgs = ['clientId']; require('../methods/report')(app);
require('../methods/email')(app);
const hasRequiredArgs = requiredArgs.every(arg => {
return args[arg];
});
if (!hasRequiredArgs)
res.json({message: 'Required params recipient, clientId'});
try {
const report = new Report(req.params.name, args);
const stream = await report.toPdfStream();
res.setHeader('Content-type', 'application/pdf');
stream.pipe(res);
} catch (e) {
next(e);
}
});
app.get(`/api/email/:name`, async(req, res, next) => {
const args = req.query;
const requiredArgs = ['recipient', 'clientId'];
const hasRequiredArgs = requiredArgs.every(arg => {
return args[arg];
});
if (!hasRequiredArgs)
res.json({message: 'Required params recipient, clientId'});
try {
const email = new Email(req.params.name, args);
if (args.isPreview === 'true') {
const rendered = await email.render();
res.send(rendered);
} else {
await email.send();
res.status(200).json({message: 'Sent'});
}
} catch (e) {
next(e);
}
});
}; };

View File

@ -1,5 +1,6 @@
const nodemailer = require('nodemailer'); const nodemailer = require('nodemailer');
const config = require('./config'); const config = require('./config');
const db = require('./database');
module.exports = { module.exports = {
init() { init() {
@ -8,15 +9,30 @@ module.exports = {
}, },
send(options) { send(options) {
options.from = `${config.app.senderName} <${config.app.senderMail}>`; options.from = `${config.app.senderName} <${config.app.senderEmail}>`;
if (process.env.NODE_ENV !== 'production') { if (process.env.NODE_ENV !== 'production') {
if (!config.smtp.auth.user) if (!config.smtp.auth.user)
return Promise.resolve(true); return Promise.resolve(true);
options.to = config.app.senderMail; options.to = config.app.senderEmail;
} }
return this.transporter.sendMail(options); let error;
return this.transporter.sendMail(options).catch(err => {
error = err;
throw err;
}).finally(async() => {
await db.rawSql(`
INSERT INTO vn.mail (sender, replyTo, sent, subject, body, status)
VALUES (:recipient, :sender, 1, :subject, :body, :status)`, {
sender: config.app.senderEmail,
recipient: options.to,
subject: options.subject,
body: options.text || options.html,
status: error && error.message || 'Sent'
});
});
} }
}; };

66
print/methods/closure.js Normal file
View File

@ -0,0 +1,66 @@
const db = require('../core/database');
const Email = require('../core/email');
const smtp = require('../core/smtp');
const config = require('../core/config');
module.exports = app => {
app.get('/api/closure', async function(req, res) {
const failedtickets = [];
const tickets = await db.rawSql(`
SELECT
t.id,
t.clientFk,
c.email recipient
FROM expedition e
JOIN ticket t ON t.id = e.ticketFk
JOIN client c ON c.id = t.clientFk
JOIN warehouse w ON w.id = t.warehouseFk AND hasComission
LEFT JOIN ticketState ts ON ts.ticketFk = t.id
WHERE ts.code = 'PACKED'
AND DATE(t.shipped) BETWEEN DATE_ADD(CURDATE(), INTERVAL -2 DAY) AND CURDATE()
AND t.refFk IS NULL
GROUP BY e.ticketFk`);
for (const ticket of tickets) {
try {
await db.rawSql(`CALL vn.ticketClosureTicket(:ticketId)`, {
ticketId: ticket.id
});
const args = {
ticketId: ticket.id,
clientId: ticket.clientFk,
recipient: ticket.recipient
};
const email = new Email('delivery-note-link', args);
await email.send();
} catch (error) {
// Save tickets on a list of failed ids
failedtickets.push({
id: ticket.id,
stacktrace: error
});
}
}
// Send email with failed tickets
if (failedtickets.length > 0) {
let body = 'This following tickets has failed:<br/><br/>';
for (ticket of failedtickets) {
body += `Ticket: <strong>${ticket.id}</strong>
<br/> <strong>${ticket.stacktrace}</strong><br/><br/>`;
}
smtp.send({
to: config.app.reportEmail,
subject: '[API] Nightly ticket closure has failed',
html: body
});
}
res.status(200).json({
message: 'Closure executed successfully'
});
});
};

32
print/methods/email.js Normal file
View File

@ -0,0 +1,32 @@
const Email = require('../core/email');
module.exports = app => {
app.get(`/api/email/:name`, async(req, res, next) => {
const args = req.query;
const requiredArgs = ['clientId', 'recipient'];
const argList = requiredArgs.join(',');
const hasRequiredArgs = requiredArgs.every(arg => {
return args[arg];
});
try {
if (!hasRequiredArgs)
throw new Error(`Required properties not found [${argList}]`);
const email = new Email(req.params.name, args);
if (args.isPreview === 'true') {
const rendered = await email.render();
res.send(rendered);
} else {
await email.send();
res.status(200).json({
message: 'Sent'
});
}
} catch (e) {
next(e);
}
});
};

24
print/methods/report.js Normal file
View File

@ -0,0 +1,24 @@
const Report = require('../core/report');
module.exports = app => {
app.get(`/api/report/:name`, async(req, res, next) => {
const args = req.query;
const requiredArgs = ['clientId'];
const argList = requiredArgs.join(',');
const hasRequiredArgs = requiredArgs.every(arg => {
return args[arg];
});
try {
if (!hasRequiredArgs)
throw new Error(`Required properties not found [${argList}]`);
const report = new Report(req.params.name, args);
const stream = await report.toPdfStream();
res.setHeader('Content-type', 'application/pdf');
stream.pipe(res);
} catch (error) {
next(error);
}
});
};

View File

@ -1,4 +1,6 @@
[{ [
"filename": "claim-pickup-order.pdf", {
"component": "claim-pickup" "filename": "claim-pickup-order.pdf",
}] "component": "claim-pickup"
}
]

View File

@ -25,7 +25,7 @@
</div> </div>
<!-- Block --> <!-- Block -->
<div class="grid-row"> <div class="grid-row">
<div class="grid-block white vn-pa-lg"> <div class="grid-block vn-pa-lg">
<h1>{{ $t('title') }}</h1> <h1>{{ $t('title') }}</h1>
<p>{{$t('description.dear')}},</p> <p>{{$t('description.dear')}},</p>
<p>{{$t('description.instructions')}}</p> <p>{{$t('description.instructions')}}</p>

View File

@ -25,7 +25,7 @@
</div> </div>
<!-- Block --> <!-- Block -->
<div class="grid-row"> <div class="grid-row">
<div class="grid-block white vn-pa-lg"> <div class="grid-block vn-pa-lg">
<h1>{{ $t('title') }}</h1> <h1>{{ $t('title') }}</h1>
<p>{{$t('dearClient')}},</p> <p>{{$t('dearClient')}},</p>
<p v-html="$t('clientData')"></p> <p v-html="$t('clientData')"></p>

View File

@ -0,0 +1,9 @@
const Stylesheet = require(`${appPath}/core/stylesheet`);
module.exports = new Stylesheet([
`${appPath}/common/css/spacing.css`,
`${appPath}/common/css/misc.css`,
`${appPath}/common/css/layout.css`,
`${appPath}/common/css/email.css`,
`${__dirname}/style.css`])
.mergeStyles();

View File

@ -0,0 +1,5 @@
.external-link {
border: 2px dashed #8dba25;
border-radius: 3px;
text-align: center
}

View File

@ -0,0 +1,75 @@
<!DOCTYPE html>
<html v-bind:lang="locale">
<head>
<meta name="viewport" content="width=device-width">
<meta name="format-detection" content="telephone=no">
<title>{{ $t('subject') }}</title>
<style type="text/css">
a {
color: #8dba25
}
</style>
</head>
<body>
<table class="grid">
<tbody>
<tr>
<td>
<!-- Empty block -->
<div class="grid-row">
<div class="grid-block empty"></div>
</div>
<!-- Header block -->
<div class="grid-row">
<div class="grid-block">
<email-header
v-bind:is-preview="isPreview"
v-bind:locale="locale">
</email-header>
</div>
</div>
<!-- Block -->
<div class="grid-row">
<div class="grid-block vn-pa-lg">
<h1>{{ $t('title') }}</h1>
<p>{{$t('dear')}}</p>
<p v-html="$t('description', [ticketId])"></p>
</div>
</div>
<!-- Block -->
<div class="grid-row">
<div class="grid-block vn-px-lg">
<p>{{$t('copyLink')}}</p>
<div class="external-link vn-pa-sm vn-m-md">
https://www.verdnatura.es/#!form=ecomerce/ticket&ticket={{ticketId}}
</div>
</div>
</div>
<!-- Block -->
<div class="grid-row">
<div class="grid-block vn-pa-lg">
<p v-html="$t('poll')"></p>
<p v-html="$t('help')"></p>
<p v-html="$t('conclusion')"></p>
</div>
</div>
<!-- Footer block -->
<div class="grid-row">
<div class="grid-block">
<email-footer
v-bind:is-preview="isPreview"
v-bind:locale="locale">
</email-footer>
</div>
</div>
<!-- Empty block -->
<div class="grid-row">
<div class="grid-block empty"></div>
</div>
</td>
</tr>
</tbody>
</table>
</body>
</html>

View File

@ -0,0 +1,16 @@
const Component = require(`${appPath}/core/component`);
const emailHeader = new Component('email-header');
const emailFooter = new Component('email-footer');
module.exports = {
name: 'delivery-note-link',
components: {
'email-header': emailHeader.build(),
'email-footer': emailFooter.build()
},
props: {
ticketId: {
required: true
}
}
};

View File

@ -0,0 +1,11 @@
subject: Aquí tienes tu albarán
title: "Aquí tienes tu albarán"
dear: Estimado cliente
description: Ya está disponible el albarán correspondiente al pedido <strong>{0}</strong>. <br/>
Puedes verlo haciendo clic <a href="https://www.verdnatura.es/#!form=ecomerce/ticket&ticket={0}">en este enlace</a>.
copyLink: 'Como alternativa, puedes copiar el siguiente enlace en tu navegador:'
poll: Si lo deseas, puedes responder a nuestra encuesta de satisfacción para
ayudarnos a prestar un mejor servicio. ¡Tu opinión es muy importante para nosotros!
help: Cualquier duda que te surja, no dudes en consultarla, <strong>¡estamos para
atenderte!</strong>
conclusion: ¡Gracias por tu atención!

View File

@ -0,0 +1,10 @@
subject: Voici votre bon de livraison
title: "Voici votre bon de livraison"
dear: Cher client,
description: Le bon de livraison correspondant à la commande <strong>{0}</strong> est maintenant disponible.<br/>
Vous pouvez le voir en cliquant <a href="https://www.verdnatura.es/#!form=ecomerce/ticket&ticket={0}" target="_blank">sur ce lien</a>.
copyLink: 'Vous pouvez également copier le lien suivant dans votre navigateur:'
poll: Si vous le souhaitez, vous pouvez répondre à notre questionaire de satisfaction
pour nous aider à améliorer notre service. Votre avis est très important pour nous!
help: N'hésitez pas nous envoyer toute doute ou question, <strong>nous sommes là pour vous aider!</strong>
conclusion: Merci pour votre attention!

View File

@ -1,4 +1,6 @@
[{ [
"filename": "delivery-note.pdf", {
"component": "delivery-note" "filename": "delivery-note.pdf",
}] "component": "delivery-note"
}
]

View File

@ -25,7 +25,7 @@
</div> </div>
<!-- Block --> <!-- Block -->
<div class="grid-row"> <div class="grid-row">
<div class="grid-block white vn-pa-lg"> <div class="grid-block vn-pa-lg">
<h1>{{ $t('title') }}</h1> <h1>{{ $t('title') }}</h1>
<p>{{$t('dear')}},</p> <p>{{$t('dear')}},</p>
<p v-html="$t('description', [ticketId])"></p> <p v-html="$t('description', [ticketId])"></p>

View File

@ -1,4 +1,6 @@
[{ [
"filename": "driver-route.pdf", {
"component": "driver-route" "filename": "driver-route.pdf",
}] "component": "driver-route"
}
]

View File

@ -25,7 +25,7 @@
</div> </div>
<!-- Block --> <!-- Block -->
<div class="grid-row"> <div class="grid-row">
<div class="grid-block white vn-pa-lg"> <div class="grid-block vn-pa-lg">
<h1>{{ $t('title') }}</h1> <h1>{{ $t('title') }}</h1>
<p>{{$t('description.instructions')}}</p> <p>{{$t('description.instructions')}}</p>
</div> </div>

View File

@ -1,4 +1,6 @@
[{ [
"filename": "letter-debtor.pdf", {
"component": "letter-debtor" "filename": "letter-debtor.pdf",
}] "component": "letter-debtor"
}
]

View File

@ -25,7 +25,7 @@
</div> </div>
<!-- Block --> <!-- Block -->
<div class="grid-row"> <div class="grid-row">
<div class="grid-block white vn-pa-lg"> <div class="grid-block vn-pa-lg">
<h1>{{ $t('title') }}</h1> <h1>{{ $t('title') }}</h1>
<p>{{ $t('sections.introduction.title') }},</p> <p>{{ $t('sections.introduction.title') }},</p>
<p>{{ $t('sections.introduction.description') }}</p> <p>{{ $t('sections.introduction.description') }}</p>
@ -65,7 +65,7 @@
</div> </div>
<!-- Block --> <!-- Block -->
<div class="grid-row" v-if="isPreview"> <div class="grid-row" v-if="isPreview">
<div class="grid-block white vn-pa-lg"> <div class="grid-block vn-pa-lg">
<attachment v-for="attachment in attachments" <attachment v-for="attachment in attachments"
v-bind:key="attachment.filename" v-bind:key="attachment.filename"
v-bind:attachment="attachment" v-bind:attachment="attachment"

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