diff --git a/back/methods/chat/send.js b/back/methods/chat/send.js
index b0a9431c79..53e5da7cc0 100644
--- a/back/methods/chat/send.js
+++ b/back/methods/chat/send.js
@@ -32,6 +32,8 @@ module.exports = Self => {
if (sender.name != recipient)
return sendMessage(sender, to, message);
+
+ return false;
};
async function sendMessage(sender, channel, message) {
diff --git a/back/methods/chat/sendCheckingPresence.js b/back/methods/chat/sendCheckingPresence.js
index 70b4da58f4..b2a3ca725f 100644
--- a/back/methods/chat/sendCheckingPresence.js
+++ b/back/methods/chat/sendCheckingPresence.js
@@ -36,7 +36,7 @@ module.exports = Self => {
relation: 'department'
}
});
- const department = workerDepartment.department();
+ const department = workerDepartment && workerDepartment.department();
const channelName = department.chatName;
if (channelName)
diff --git a/back/methods/chat/spec/send.spec.js b/back/methods/chat/spec/send.spec.js
index b2585a9a15..56f2a9c275 100644
--- a/back/methods/chat/spec/send.spec.js
+++ b/back/methods/chat/spec/send.spec.js
@@ -9,10 +9,10 @@ describe('chat send()', () => {
expect(response.message).toEqual('Fake notification sent');
});
- it('should not return a response', async() => {
+ it('should retrun false as response', async() => {
let ctx = {req: {accessToken: {userId: 18}}};
let response = await app.models.Chat.send(ctx, '@salesPerson', 'I changed something');
- expect(response).toBeUndefined();
+ expect(response).toBeFalsy();
});
});
diff --git a/db/changes/10141-zoneDoCalc/00-ticket.sql b/db/changes/10141-zoneDoCalc/00-ticket.sql
index c116e51399..a756a11afe 100644
--- a/db/changes/10141-zoneDoCalc/00-ticket.sql
+++ b/db/changes/10141-zoneDoCalc/00-ticket.sql
@@ -3,9 +3,9 @@ ADD COLUMN `zonePrice` DECIMAL(10,2) NULL DEFAULT NULL AFTER `collectionFk`,
ADD COLUMN `zoneBonus` DECIMAL(10,2) NULL DEFAULT NULL AFTER `zonePrice`,
ADD COLUMN `zoneClosure` TIME NULL AFTER `zoneBonus`;
-CREATE TABLE vn.`zoneCalcTicket` (
+CREATE TABLE `vn`.`zoneCalcTicket` (
`zoneFk` int(11) NOT NULL PRIMARY KEY,
- CONSTRAINT `zoneCalcTicketfk_1` FOREIGN KEY (`zoneFk`) REFERENCES `zone` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
+ CONSTRAINT `zoneCalcTicketfk_1` FOREIGN KEY (`zoneFk`) REFERENCES `vn`.`zone` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
DROP EVENT IF EXISTS vn.`zone_doCalc`;
diff --git a/db/changes/10141-zoneDoCalc/01-zoneClosure_recalc.sql b/db/changes/10141-zoneDoCalc/01-zoneClosure_recalc.sql
deleted file mode 100644
index f015eb894b..0000000000
--- a/db/changes/10141-zoneDoCalc/01-zoneClosure_recalc.sql
+++ /dev/null
@@ -1 +0,0 @@
-USE `vn`;
diff --git a/db/changes/10141-zoneDoCalc/02-insertPastTickets.sql b/db/changes/10141-zoneDoCalc/02-insertPastTickets.sql
new file mode 100644
index 0000000000..4314e5d7d9
--- /dev/null
+++ b/db/changes/10141-zoneDoCalc/02-insertPastTickets.sql
@@ -0,0 +1,62 @@
+USE `vn`;
+DROP procedure IF EXISTS `zone_doCalcInitialize`;
+
+DELIMITER $$
+USE `vn`$$
+CREATE DEFINER=`root`@`%` PROCEDURE `zone_doCalcInitialize`()
+proc: BEGIN
+/**
+ * Initialize ticket
+ */
+ DECLARE vDone BOOL;
+ DECLARE vTicketFk INT;
+ DECLARE vLanded DATE;
+ DECLARE vZoneFk INT;
+
+ DECLARE cCur CURSOR FOR
+ SELECT t.id, t.landed, t.zoneFk
+ FROM ticket t
+ WHERE (zonePrice IS NULL OR zoneBonus IS NULL OR zoneClosure IS NULL)
+ AND landed >= '2019-01-01' AND shipped >= '2019-01-01'
+ GROUP BY landed, zoneFk;
+
+ DECLARE CONTINUE HANDLER FOR NOT FOUND
+ SET vDone = TRUE;
+
+ OPEN cCur;
+
+ myLoop: LOOP
+ SET vDone = FALSE;
+ FETCH cCur INTO vTicketFk, vLanded, vZoneFk;
+
+ IF vDone THEN
+ LEAVE myLoop;
+ END IF;
+
+ DROP TEMPORARY TABLE IF EXISTS tmp.zone;
+ CREATE TEMPORARY TABLE tmp.zone
+ (INDEX (id))
+ ENGINE = MEMORY
+ SELECT vZoneFk id;
+
+ CALL zone_getOptionsForLanding(vLanded, TRUE);
+
+ UPDATE ticket t
+ LEFT JOIN tmp.zoneOption zo ON TRUE
+ SET zonePrice = zo.price, zoneBonus = zo.bonus, zoneClosure = zo.`hour`
+ WHERE t.zoneFk = vZoneFk AND landed = vLanded;
+
+ UPDATE ticket t
+ LEFT JOIN vn.zone z ON z.id = t.zoneFk
+ SET zonePrice = z.price, zoneBonus = z.bonus, zoneClosure = z.`hour`
+ WHERE t.zonePrice IS NULL AND z.id = vZoneFk
+ AND landed >= '2019-01-01' AND shipped >= '2019-01-01';
+
+ END LOOP;
+
+ CLOSE cCur;
+
+ DELETE FROM zoneCalcTicket;
+END$$
+
+DELIMITER ;
\ No newline at end of file
diff --git a/db/changes/10141-zoneDoCalc/03-getOptionsForLanding.sql b/db/changes/10141-zoneDoCalc/03-getOptionsForLanding.sql
new file mode 100644
index 0000000000..e0f5f9a48b
--- /dev/null
+++ b/db/changes/10141-zoneDoCalc/03-getOptionsForLanding.sql
@@ -0,0 +1,66 @@
+USE `vn`;
+DROP procedure IF EXISTS `zone_getOptionsForLanding`;
+
+DELIMITER $$
+USE `vn`$$
+CREATE DEFINER=`root`@`%` PROCEDURE `zone_getOptionsForLanding`(vLanded DATE, vShowExpiredZones BOOLEAN)
+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
+ */
+ DROP TEMPORARY TABLE IF EXISTS tmp.zoneOption;
+ CREATE TEMPORARY TABLE tmp.zoneOption
+ ENGINE = MEMORY
+ SELECT
+ zoneFk,
+ `hour`,
+ travelingDays,
+ price,
+ bonus,
+ TIMESTAMPADD(DAY, -travelingDays, vLanded) shipped
+ FROM (
+ SELECT t.id zoneFk,
+ TIME(IFNULL(e.`hour`, z.`hour`)) `hour`,
+ IFNULL(e.travelingDays, z.travelingDays) travelingDays,
+ IFNULL(e.price, z.price) price,
+ IFNULL(e.bonus, z.bonus) bonus
+ 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`)
+ )
+ ORDER BY
+ zoneFk,
+ CASE
+ WHEN e.`type` = 'day'
+ THEN 1
+ WHEN e.`type` = 'range'
+ THEN 2
+ ELSE 3
+ END
+ ) t
+ GROUP BY zoneFk;
+
+ DELETE t FROM tmp.zoneOption t
+ JOIN zoneExclusion e
+ ON e.zoneFk = t.zoneFk AND e.`dated` = vLanded;
+
+ IF NOT vShowExpiredZones THEN
+ DELETE FROM tmp.zoneOption
+ WHERE shipped < CURDATE()
+ OR (shipped = CURDATE() AND CURTIME() > `hour`);
+ END IF;
+END$$
+
+DELIMITER ;
\ No newline at end of file
diff --git a/db/changes/10141-zoneDoCalc/03-rutasAnalyze.sql b/db/changes/10141-zoneDoCalc/03-rutasAnalyze.sql
new file mode 100644
index 0000000000..313f2f797a
--- /dev/null
+++ b/db/changes/10141-zoneDoCalc/03-rutasAnalyze.sql
@@ -0,0 +1,171 @@
+USE `vn`;
+DROP procedure IF EXISTS `rutasAnalyze`;
+
+DELIMITER $$
+USE `vn`$$
+CREATE DEFINER=`root`@`%` PROCEDURE `rutasAnalyze`(vYear INT, vMonth INT)
+BEGIN
+
+/* Analiza los costes de las rutas de reparto y lo almacena en la tabla Rutas_Master
+*
+* PAK 15/4/2019
+*/
+
+ DELETE FROM bi.rutasBoard
+ WHERE year = vYear AND month = vMonth;
+
+ -- Rellenamos la tabla con los datos de las rutas VOLUMETRICAS, especialmente con los bultos "virtuales"
+ INSERT INTO bi.rutasBoard(year,
+ month,
+ warehouse_id,
+ Id_Ruta,
+ Id_Agencia,
+ km,
+ Dia,
+ Fecha,
+ Bultos,
+ Matricula,
+ Tipo,
+ Terceros)
+ SELECT YEAR(r.created),
+ MONTH(r.created),
+ GREATEST(1,a.warehouseFk),
+ r.id,
+ r.agencyModeFk,
+ r.kmEnd - r.kmStart,
+ DAYNAME(r.created),
+ r.created,
+ SUM(sv.volume / ebv.m3),
+ v.numberPlate,
+ IF(ISNULL(`r`.`cost`), 'P', 'A'),
+ r.cost
+ FROM vn.route r
+ JOIN vn.ticket t ON t.routeFk = r.id
+ LEFT JOIN vn.zone z ON z.id = t.zoneFk
+ LEFT JOIN vn.agencyMode am ON am.id = r.agencyModeFk
+ LEFT JOIN vn.agency a ON a.id = am.agencyFk
+ LEFT JOIN vn.vehicle v ON v.id = r.vehicleFk
+ JOIN vn.saleVolume sv ON sv.ticketFk = t.id
+ JOIN vn.expeditionBoxVol ebv ON ebv.boxFk = 71
+ WHERE YEAR(r.created) = vYear AND MONTH(r.created) = vMonth
+ AND z.isVolumetric
+ GROUP BY r.id;
+
+ -- Rellenamos la tabla con los datos de las rutas NO VOLUMETRICAS, especialmente con los bultos "virtuales"
+ INSERT INTO bi.rutasBoard(year,
+ month,
+ warehouse_id,
+ Id_Ruta,
+ Id_Agencia,
+ km,
+ Dia,
+ Fecha,
+ Bultos,
+ Matricula,
+ Tipo,
+ Terceros)
+ SELECT YEAR(r.created),
+ MONTH(r.created),
+ GREATEST(1,a.warehouseFk),
+ r.id,
+ r.agencyModeFk,
+ r.kmEnd - r.kmStart,
+ DAYNAME(r.created),
+ r.created,
+ SUM(t.packages),
+ v.numberPlate,
+ IF(ISNULL(`r`.`cost`), 'P', 'A'),
+ r.cost
+ FROM vn.route r
+ JOIN vn.ticket t ON t.routeFk = r.id
+ LEFT JOIN vn.zone z ON z.id = t.zoneFk
+ LEFT JOIN vn.agencyMode am ON am.id = r.agencyModeFk
+ LEFT JOIN vn.agency a ON a.id = am.agencyFk
+ LEFT JOIN vn.vehicle v ON v.id = r.vehicleFk
+ WHERE YEAR(r.created) = vYear AND MONTH(r.created) = vMonth
+ AND z.isVolumetric = FALSE
+ GROUP BY r.id
+ ON DUPLICATE KEY UPDATE Bultos = Bultos + VALUES(Bultos);
+
+ -- Coste REAL de cada bulto "virtual", de acuerdo con el valor apuntado a mano en la ruta
+ UPDATE bi.rutasBoard r
+ INNER JOIN vn2008.Rutas_Master rm ON rm.año = r.year AND rm.mes = r.month AND rm.warehouse_id = r.warehouse_id
+ SET r.coste_bulto = IF(r.Tipo ='A', r.Terceros, r.km * rm.coste_km ) / r.Bultos
+ WHERE r.Bultos > 0
+ AND rm.año = vYear
+ AND rm.mes = vMonth;
+
+ -- Coste PRACTICO de cada bulto, de acuerdo con los componentes de tipo AGENCIA en cada linea de venta
+ UPDATE bi.rutasBoard r
+ JOIN (
+ SELECT t.routeFk, sum(s.quantity * sc.value) practicoTotal
+ FROM vn.route r
+ JOIN vn.time tm ON tm.dated = r.created
+ JOIN vn.ticket t ON t.routeFk = r.id
+ JOIN vn.sale s ON s.ticketFk = t.id
+ JOIN vn.saleComponent sc ON sc.saleFk = s.id
+ JOIN vn.`component` c ON c.id = sc.componentFk
+ JOIN vn.componentType ct ON ct.id = c.typeFk
+ WHERE ct.type = 'agencia'
+ AND tm.year = vYear
+ AND tm.month = vMonth
+ GROUP BY r.id
+ ) sub ON sub.routeFk = r.Id_Ruta
+ SET r.practico = sub.practicoTotal / r.Bultos;
+
+ -- Coste TEORICO de una caja "virtual" para cada ruta, teniendo en cuenta que hay carros, pallets, etc
+ UPDATE bi.rutasBoard r
+ JOIN (
+ SELECT t.routeFk,
+ SUM(t.zonePrice/ ebv.ratio)/ count(*) AS BultoTeoricoMedio
+ FROM vn.ticket t
+ JOIN vn.route r ON r.id = t.routeFk
+ JOIN vn.time tm ON tm.dated = r.created
+ JOIN vn.expedition e ON e.ticketFk = t.id
+ JOIN vn.expeditionBoxVol ebv ON ebv.boxFk = e.isBox
+ JOIN vn.address ad ON ad.id = t.addressFk
+ JOIN vn.client c ON c.id = ad.clientFk
+ LEFT JOIN vn.zone z ON z.id = t.zoneFk
+ WHERE tm.year = vYear
+ AND tm.month = vMonth
+ AND z.isVolumetric = FALSE
+ GROUP BY t.routeFk) sub ON r.Id_Ruta = sub.routeFk
+ SET r.teorico = sub.BultoTeoricoMedio;
+
+ -- Coste VOLUMETRICO TEORICO de una caja "virtual" para cada ruta
+ UPDATE bi.rutasBoard r
+ JOIN (
+ SELECT t.routeFk,
+ SUM(freight) AS BultoTeoricoMedio
+ FROM vn.ticket t
+ JOIN vn.route r ON r.id = t.routeFk
+ JOIN vn.time tm ON tm.dated = r.created
+ JOIN vn.saleVolume sf ON sf.ticketFk = t.id
+ JOIN vn.client c ON c.id = t.clientFk
+ JOIN vn.zone z ON z.id = t.zoneFk
+ WHERE tm.year = vYear
+ AND tm.month = vMonth
+ AND z.isVolumetric != FALSE
+ GROUP BY t.routeFk) sub ON r.Id_Ruta = sub.routeFk
+ SET r.teorico = sub.BultoTeoricoMedio / r.Bultos;
+
+ -- La diferencia entre el teorico y el practico se deberia de cobrar en greuges, cada noche
+ UPDATE bi.rutasBoard r
+ JOIN (
+ SELECT t.routeFk,
+ Sum(g.amount) AS greuge
+ FROM vn.ticket t
+ JOIN vn.route r ON r.id = t.routeFk
+ JOIN vn.time tm ON tm.dated = r.created
+ JOIN vn.greuge g ON g.ticketFk = t.id
+ JOIN vn.greugeType gt ON gt.id = g.greugeTypeFk
+ WHERE tm.year = vYear
+ AND tm.month = vMonth
+ AND gt.name = 'Diferencia portes'
+ GROUP BY t.routeFk) sub ON r.Id_Ruta = sub.routeFk
+ SET r.greuge = sub.greuge / r.Bultos;
+
+END$$
+
+DELIMITER ;
+
diff --git a/db/changes/10141-zoneDoCalc/03-saleVolume.sql b/db/changes/10141-zoneDoCalc/03-saleVolume.sql
new file mode 100644
index 0000000000..2ded49a8d3
--- /dev/null
+++ b/db/changes/10141-zoneDoCalc/03-saleVolume.sql
@@ -0,0 +1,26 @@
+USE `vn`;
+CREATE
+ OR REPLACE ALGORITHM = UNDEFINED
+ DEFINER = `root`@`%`
+ SQL SECURITY DEFINER
+VIEW `saleVolume` AS
+ SELECT
+ `s`.`ticketFk` AS `ticketFk`,
+ `s`.`id` AS `saleFk`,
+ IFNULL(ROUND(((((`i`.`compression` * (GREATEST(`i`.`density`, 167) / 167)) * `ic`.`cm3`) * `s`.`quantity`) / 1000),
+ 2),
+ 0) AS `litros`,
+ `t`.`routeFk` AS `routeFk`,
+ `t`.`shipped` AS `shipped`,
+ (((`s`.`quantity` * `ic`.`cm3`) * `i`.`compression`) / 1000000) AS `volume`,
+ ((((`s`.`quantity` * `ic`.`cm3`) * `i`.`compression`) * (GREATEST(`i`.`density`, 167) / 167)) / 1000000) AS `physicalWeight`,
+ (((`s`.`quantity` * `ic`.`cm3`) * `i`.`density`) / 1000000) AS `weight`,
+ (((`s`.`quantity` * `ic`.`cm3`) * `i`.`compression`) / 1000000) AS `physicalVolume`,
+ ((((`s`.`quantity` * `ic`.`cm3`) * `t`.`zonePrice`) * `i`.`compression`) / `cb`.`volume`) AS `freight`
+ FROM
+ ((((`sale` `s`
+ JOIN `item` `i` ON ((`i`.`id` = `s`.`itemFk`)))
+ JOIN `ticket` `t` ON ((`t`.`id` = `s`.`ticketFk`)))
+ JOIN `packaging` `cb` ON ((`cb`.`id` = '94')))
+ JOIN `itemCost` `ic` ON (((`ic`.`itemFk` = `s`.`itemFk`)
+ AND (`ic`.`warehouseFk` = `t`.`warehouseFk`))));
diff --git a/db/changes/10141-zoneDoCalc/03-viewSaleFreight__.sql b/db/changes/10141-zoneDoCalc/03-viewSaleFreight__.sql
new file mode 100644
index 0000000000..903c8b48ac
--- /dev/null
+++ b/db/changes/10141-zoneDoCalc/03-viewSaleFreight__.sql
@@ -0,0 +1,24 @@
+DROP VIEW IF EXISTS `vn`.`saleFreight` ;
+USE `vn`;
+CREATE
+ OR REPLACE ALGORITHM = UNDEFINED
+ DEFINER = `root`@`%`
+ SQL SECURITY DEFINER
+VIEW `saleFreight__` AS
+ SELECT
+ `s`.`ticketFk` AS `ticketFk`,
+ `t`.`clientFk` AS `clientFk`,
+ `t`.`routeFk` AS `routeFk`,
+ `s`.`id` AS `saleFk`,
+ `t`.`zoneFk` AS `zoneFk`,
+ `t`.`companyFk` AS `companyFk`,
+ `t`.`shipped` AS `shipped`,
+ `t`.`zonePrice` AS `price`,
+ ((((`s`.`quantity` * `r`.`cm3`) * `t`.`zonePrice`) * `i`.`compression`) / `cb`.`volume`) AS `freight`
+ FROM
+ ((((`vn`.`sale` `s`
+ JOIN `vn`.`item` `i` ON ((`i`.`id` = `s`.`itemFk`)))
+ JOIN `vn`.`ticket` `t` ON ((`t`.`id` = `s`.`ticketFk`)))
+ JOIN `vn`.`packaging` `cb` ON ((`cb`.`id` = '94')))
+ JOIN `bi`.`rotacion` `r` ON (((`r`.`Id_Article` = `s`.`itemFk`)
+ AND (`r`.`warehouse_id` = `t`.`warehouseFk`))));
diff --git a/db/changes/10141-zoneDoCalc/03-zone_geShippedWarehouse.sql b/db/changes/10141-zoneDoCalc/03-zone_geShippedWarehouse.sql
new file mode 100644
index 0000000000..14d5d8cd9a
--- /dev/null
+++ b/db/changes/10141-zoneDoCalc/03-zone_geShippedWarehouse.sql
@@ -0,0 +1,41 @@
+USE `vn`;
+DROP procedure IF EXISTS `zone_getShippedWarehouse`;
+
+DELIMITER $$
+USE `vn`$$
+CREATE DEFINER=`root`@`%` PROCEDURE `zone_getShippedWarehouse`(vLanded DATE, vAddressFk INT, vAgencyModeFk INT)
+BEGIN
+/**
+ * Devuelve la mÃnima fecha de envÃo para cada warehouse
+ *
+ * @param vLanded La fecha de recepcion
+ * @param vAddressFk Id del consignatario
+ * @param vAgencyModeFk Id de la agencia
+ * @return tmp.zoneGetShipped
+ */
+
+ CALL zone_getFromGeo(address_getGeo(vAddressFk));
+ CALL zone_getOptionsForLanding(vLanded,TRUE);
+
+ DROP TEMPORARY TABLE IF EXISTS tmp.zoneGetShipped;
+ CREATE TEMPORARY TABLE tmp.zoneGetShipped
+ ENGINE = MEMORY
+ SELECT * FROM (
+ SELECT zo.zoneFk,
+ TIMESTAMPADD(DAY,-zo.travelingDays, vLanded) shipped,
+ zo.`hour`,
+ zw.warehouseFk,
+ z.agencyModeFk
+ FROM tmp.zoneOption zo
+ JOIN zoneWarehouse zw ON zw.zoneFk = zo.zoneFk
+ JOIN zone z ON z.id = zo.zoneFk
+ WHERE z.agencyModeFk = vAgencyModeFk
+ ORDER BY shipped) t
+ GROUP BY warehouseFk;
+
+ DROP TEMPORARY TABLE
+ tmp.zone,
+ tmp.zoneOption;
+END$$
+
+DELIMITER ;
\ No newline at end of file
diff --git a/db/changes/10141-zoneDoCalc/03-zone_getAgency.sql b/db/changes/10141-zoneDoCalc/03-zone_getAgency.sql
new file mode 100644
index 0000000000..b2837d43cd
--- /dev/null
+++ b/db/changes/10141-zoneDoCalc/03-zone_getAgency.sql
@@ -0,0 +1,42 @@
+USE `vn`;
+DROP procedure IF EXISTS `zone_getAgency`;
+
+DELIMITER $$
+USE `vn`$$
+CREATE DEFINER=`root`@`%` PROCEDURE `zone_getAgency`(vAddress INT, vLanded DATE)
+BEGIN
+/**
+ * Devuelve el listado de agencias disponibles para la fecha
+ * y dirección pasadas.
+ *
+ * @param vAddress Id de dirección de envío, %NULL si es recogida
+ * @param vLanded Fecha de recogida
+ * @select Listado de agencias disponibles
+ */
+
+ CALL zone_getFromGeo(address_getGeo(vAddress));
+ CALL zone_getOptionsForLanding(vLanded, FALSE);
+
+ DROP TEMPORARY TABLE IF EXISTS tmp.zoneGetAgency;
+ CREATE TEMPORARY TABLE tmp.zoneGetAgency
+ (INDEX (agencyModeFk)) ENGINE = MEMORY
+ SELECT am.name agencyMode,
+ am.description,
+ z.agencyModeFk,
+ am.deliveryMethodFk,
+ TIMESTAMPADD(DAY,-zo.travelingDays, vLanded) shipped,
+ TRUE isIncluded,
+ zo.zoneFk
+ FROM tmp.zoneOption zo
+ JOIN zone z ON z.id = zo.zoneFk
+ JOIN agencyMode am ON am.id = z.agencyModeFk
+ GROUP BY agencyModeFk;
+
+ DROP TEMPORARY TABLE
+ tmp.zone,
+ tmp.zoneOption;
+
+END$$
+
+DELIMITER ;
+
diff --git a/db/changes/10141-zoneDoCalc/03-zone_getAvailable.sql b/db/changes/10141-zoneDoCalc/03-zone_getAvailable.sql
new file mode 100644
index 0000000000..2ef1a1ae96
--- /dev/null
+++ b/db/changes/10141-zoneDoCalc/03-zone_getAvailable.sql
@@ -0,0 +1,18 @@
+USE `vn`;
+DROP procedure IF EXISTS `zone_getAvailable`;
+
+DELIMITER $$
+USE `vn`$$
+CREATE DEFINER=`root`@`%` PROCEDURE `zone_getAvailable`(vAddress INT, vLanded DATE)
+BEGIN
+ CALL zone_getFromGeo(address_getGeo(vAddress));
+ CALL zone_getOptionsForLanding(vLanded, FALSE);
+
+ SELECT * FROM tmp.zoneOption;
+
+ DROP TEMPORARY TABLE
+ tmp.zone,
+ tmp.zoneOption;
+END$$
+
+DELIMITER ;
\ No newline at end of file
diff --git a/db/changes/10141-zoneDoCalc/03-zone_getWarehouse.sql b/db/changes/10141-zoneDoCalc/03-zone_getWarehouse.sql
new file mode 100644
index 0000000000..c1cea8b136
--- /dev/null
+++ b/db/changes/10141-zoneDoCalc/03-zone_getWarehouse.sql
@@ -0,0 +1,41 @@
+USE `vn`;
+DROP procedure IF EXISTS `zone_getWarehouse`;
+
+DELIMITER $$
+USE `vn`$$
+CREATE DEFINER=`root`@`%` PROCEDURE `zone_getWarehouse`(vAddress INT, vLanded DATE, vWarehouse INT)
+BEGIN
+/**
+ * Devuelve el listado de agencias disponibles para la fecha,
+ * dirección y almacén pasados.
+ *
+ * @param vAddress
+ * @param vWarehouse warehouse
+ * @param vLanded Fecha de recogida
+ * @select Listado de agencias disponibles
+ */
+
+ CALL zone_getFromGeo(address_getGeo(vAddress));
+ CALL zone_getOptionsForLanding(vLanded, FALSE);
+
+ SELECT am.id agencyModeFk,
+ am.name agencyMode,
+ am.description,
+ am.deliveryMethodFk,
+ TIMESTAMPADD(DAY, -zo.travelingDays, vLanded) shipped,
+ zw.warehouseFk,
+ z.id zoneFk
+ FROM tmp.zoneOption zo
+ JOIN zone z ON z.id = zo.zoneFk
+ JOIN agencyMode am ON am.id = z.agencyModeFk
+ JOIN zoneWarehouse zw ON zw.zoneFk = zo.zoneFk
+ WHERE zw.warehouseFk
+ GROUP BY z.agencyModeFk
+ ORDER BY agencyMode;
+
+ DROP TEMPORARY TABLE
+ tmp.zone,
+ tmp.zoneOption;
+END$$
+
+DELIMITER ;
\ No newline at end of file
diff --git a/db/changes/10160-postValentineDay/00-ACL.sql b/db/changes/10160-postValentineDay/00-ACL.sql
new file mode 100644
index 0000000000..5b6301e3df
--- /dev/null
+++ b/db/changes/10160-postValentineDay/00-ACL.sql
@@ -0,0 +1,2 @@
+INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
+ VALUES ('Intrastat', '*', '*', 'ALLOW', 'ROLE', 'buyer');
diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql
index f3dd36976b..f7d5d94f1c 100644
--- a/db/dump/fixtures.sql
+++ b/db/dump/fixtures.sql
@@ -684,8 +684,14 @@ INSERT INTO `vn`.`taxCode`(`id`, `dated`, `code`, `taxTypeFk`, `rate`, `equaliza
INSERT INTO `vn`.`taxClass`(`id`, `description`, `code`)
VALUES
- (1, 'Reduced VAT','R'),
+ (1, 'Reduced VAT', 'R'),
(2, 'General VAT', 'G');
+
+INSERT INTO `vn`.`taxClassCode`(`taxClassFk`, `effectived`, `taxCodeFk`)
+ VALUES
+ (1, CURDATE(), 1),
+ (1, CURDATE(), 21),
+ (2, CURDATE(), 2);
INSERT INTO `vn`.`intrastat`(`id`, `description`, `taxClassFk`, `taxCodeFk`)
VALUES
@@ -1123,17 +1129,19 @@ INSERT INTO `vn`.`travel`(`id`,`shipped`, `landed`, `warehouseInFk`, `warehouseO
(4, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 1, 2, 1, 50.00, 500, 'fourth travel', 0),
(5, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 3, 2, 1, 50.00, 500, 'fifth travel', 1),
(6, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 4, 2, 1, 50.00, 500, 'sixth travel', 1),
- (7, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 5, 2, 1, 50.00, 500, 'seventh travel', 1);
+ (7, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 5, 2, 1, 50.00, 500, 'seventh travel', 1),
+ (8, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 5, 2, 1, 50.00, 500, 'eight travel', 1);
-INSERT INTO `vn`.`entry`(`id`, `supplierFk`, `created`, `travelFk`, `companyFk`, `ref`, `notes`, `evaNotes`)
+INSERT INTO `vn`.`entry`(`id`, `supplierFk`, `created`, `travelFk`, `companyFk`, `ref`,`isInventory`, `isRaid`, `notes`, `evaNotes`)
VALUES
- (1, 1, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 1, 442, 'Movement 1', 'this is the note one', 'observation one'),
- (2, 2, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 2, 442, 'Movement 2', 'this is the note two', 'observation two'),
- (3, 1, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 3, 442, 'Movement 3', 'this is the note three', 'observation three'),
- (4, 2, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 2, 69, 'Movement 4', 'this is the note four', 'observation four'),
- (5, 2, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 5, 442, 'Movement 5', 'this is the note five', 'observation five'),
- (6, 2, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 6, 442, 'Movement 6', 'this is the note six', 'observation six'),
- (7, 2, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 7, 442, 'Movement 7', 'this is the note seven', 'observation seven');
+ (1, 1, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 1, 442, 'Movement 1', 0, 0, '', ''),
+ (2, 2, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 2, 442, 'Movement 2', 0, 0, 'this is the note two', 'observation two'),
+ (3, 1, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 3, 442, 'Movement 3', 0, 0, 'this is the note three', 'observation three'),
+ (4, 2, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 2, 69, 'Movement 4', 0, 0, 'this is the note four', 'observation four'),
+ (5, 2, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 5, 442, 'Movement 5', 0, 0, 'this is the note five', 'observation five'),
+ (6, 2, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 6, 442, 'Movement 6', 0, 0, 'this is the note six', 'observation six'),
+ (7, 2, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 7, 442, 'Movement 7', 0, 0, 'this is the note seven', 'observation seven'),
+ (8, 2, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 7, 442, 'Movement 8', 1, 1, '', '');
INSERT INTO `vn`.`claimRatio`(`clientFk`, `yearSale`, `claimAmount`, `claimingRate`, `priceIncreasing`, `packingRate`)
VALUES
diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js
index 16a9bb3991..1e6a30bb5e 100644
--- a/e2e/helpers/selectors.js
+++ b/e2e/helpers/selectors.js
@@ -272,6 +272,10 @@ export default {
longName: 'vn-textfield[ng-model="$ctrl.item.longName"]',
isActiveCheckbox: 'vn-check[label="Active"]',
priceInKgCheckbox: 'vn-check[label="Price in kg"]',
+ newIntrastatButton: 'vn-item-basic-data vn-icon-button[vn-tooltip="New intrastat"] > button',
+ newIntrastatId: '.vn-dialog.shown vn-input-number[ng-model="$ctrl.newIntrastat.intrastatId"]',
+ newIntrastatDescription: '.vn-dialog.shown vn-textfield[ng-model="$ctrl.newIntrastat.description"]',
+ acceptIntrastatButton: '.vn-dialog.shown button[response="accept"]',
submitBasicDataButton: `button[type=submit]`
},
itemTags: {
@@ -627,8 +631,8 @@ export default {
plantRealmButton: 'vn-order-catalog > vn-side-menu vn-icon[icon="icon-plant"]',
type: 'vn-autocomplete[data="$ctrl.itemTypes"]',
itemId: 'vn-order-catalog > vn-side-menu vn-textfield[ng-model="$ctrl.itemId"]',
- itemTagValue: 'vn-order-catalog > vn-side-menu vn-textfield[ng-model="$ctrl.value"]',
- openTagSearch: 'vn-order-catalog > vn-side-menu > div > vn-vertical > vn-textfield[ng-model="$ctrl.value"] .append i',
+ itemTagValue: 'vn-order-catalog > vn-side-menu vn-datalist[ng-model="$ctrl.value"]',
+ openTagSearch: 'vn-order-catalog > vn-side-menu > div > vn-vertical > vn-datalist[ng-model="$ctrl.value"] .append i',
tag: 'vn-order-catalog-search-panel vn-autocomplete[ng-model="filter.tagFk"]',
tagValue: 'vn-order-catalog-search-panel vn-textfield[ng-model="filter.value"]',
searchTagButton: 'vn-order-catalog-search-panel button[type=submit]',
diff --git a/e2e/paths/04-item/02_basic_data.spec.js b/e2e/paths/04-item/02_basic_data.spec.js
index 2c8a8a7a10..64827ed9ba 100644
--- a/e2e/paths/04-item/02_basic_data.spec.js
+++ b/e2e/paths/04-item/02_basic_data.spec.js
@@ -39,6 +39,26 @@ describe('Item Edit basic data path', () => {
expect(result).toEqual('Data saved!');
}, 20000);
+ it(`should create a new intrastat`, async() => {
+ await page.waitToClick(selectors.itemBasicData.newIntrastatButton);
+ await page.write(selectors.itemBasicData.newIntrastatId, '588420239');
+ await page.write(selectors.itemBasicData.newIntrastatDescription, 'Tropical Flowers');
+ await page.waitToClick(selectors.itemBasicData.acceptIntrastatButton);
+ await page.waitForTextInField(selectors.itemBasicData.intrastat, 'Tropical Flowers');
+ let newcode = await page.waitToGetProperty(selectors.itemBasicData.intrastat, 'value');
+
+ expect(newcode).toEqual('588420239 Tropical Flowers');
+ });
+
+ it(`should save with the new intrastat`, async() => {
+ await page.waitFor(250);
+ await page.waitForTextInField(selectors.itemBasicData.intrastat, 'Tropical Flowers');
+ await page.waitToClick(selectors.itemBasicData.submitBasicDataButton);
+ const result = await page.waitForLastSnackbar();
+
+ expect(result).toEqual('Data saved!');
+ });
+
it(`should confirm the item name was edited`, async() => {
await page.reloadSection('item.card.basicData');
const result = await page.waitToGetProperty(selectors.itemBasicData.name, 'value');
@@ -53,11 +73,11 @@ describe('Item Edit basic data path', () => {
expect(result).toEqual('Anthurium');
});
- it(`should confirm the item intrastad was edited`, async() => {
+ it(`should confirm the item intrastat was edited`, async() => {
const result = await page
.waitToGetProperty(selectors.itemBasicData.intrastat, 'value');
- expect(result).toEqual('5080000 Coral y materiales similares');
+ expect(result).toEqual('588420239 Tropical Flowers');
});
it(`should confirm the item relevancy was edited`, async() => {
diff --git a/front/core/components/datalist/index.js b/front/core/components/datalist/index.js
index d5feb18932..bf3cab9a18 100644
--- a/front/core/components/datalist/index.js
+++ b/front/core/components/datalist/index.js
@@ -3,6 +3,7 @@ import ArrayModel from '../array-model/array-model';
import CrudModel from '../crud-model/crud-model';
import {mergeWhere} from 'vn-loopback/util/filter';
import Textfield from '../textfield/textfield';
+import './style.scss';
export default class Datalist extends Textfield {
constructor($element, $scope, $compile, $transclude) {
@@ -12,7 +13,6 @@ export default class Datalist extends Textfield {
this._selection = null;
this.buildInput('text');
-
this.input.setAttribute('autocomplete', 'off');
}
@@ -157,8 +157,6 @@ export default class Datalist extends Textfield {
this.destroyList();
} else
this.buildList();
-
- this.emit('select', {selection});
});
}
diff --git a/front/core/components/datalist/style.scss b/front/core/components/datalist/style.scss
new file mode 100755
index 0000000000..db4ed2bb09
--- /dev/null
+++ b/front/core/components/datalist/style.scss
@@ -0,0 +1,7 @@
+@import "effects";
+
+vn-datalist {
+ input::-webkit-calendar-picker-indicator {
+ display: none
+ }
+}
\ No newline at end of file
diff --git a/loopback/locale/en.json b/loopback/locale/en.json
index 23717ba8f3..49cd0f1719 100644
--- a/loopback/locale/en.json
+++ b/loopback/locale/en.json
@@ -61,7 +61,7 @@
"MESSAGE_BOUGHT_UNITS": "Bought {{quantity}} units of {{concept}} (#{{itemId}}) for the ticket id [#{{ticketId}}]({{{url}}})",
"MESSAGE_INSURANCE_CHANGE": "I have changed the insurence credit of client [{{clientName}} (#{{clientId}})]({{{url}}}) to *{{credit}} €*",
"MESSAGE_CHANGED_PAYMETHOD": "I have changed the pay method for client [{{clientName}} (#{{clientId}})]({{{url}}})",
- "MESSAGE_CLAIM_ITEM_REGULARIZE": "I sent *{{quantity}}* units of [{{concept}} (#{{itemId}})]({{{itemUrl}}}) to {{nickname}} coming from ticket id [#{{ticketId}}]({{{ticketUrl}}})",
+ "Sent units from ticket": "I sent *{{quantity}}* units of [{{concept}} (#{{itemId}})]({{{itemUrl}}}) to *\"{{nickname}}\"* coming from ticket id [#{{ticketId}}]({{{ticketUrl}}})",
"Customs agent is required for a non UEE member": "Customs agent is required for a non UEE member",
"Incoterms is required for a non UEE member": "Incoterms is required for a non UEE member",
"Client checked as validated despite of duplication": "Client checked as validated despite of duplication from client id {{clientId}}"
diff --git a/loopback/locale/es.json b/loopback/locale/es.json
index 90d4f8793d..7577c5349a 100644
--- a/loopback/locale/es.json
+++ b/loopback/locale/es.json
@@ -124,7 +124,8 @@
"MESSAGE_BOUGHT_UNITS": "Se ha comprado {{quantity}} unidades de {{concept}} (#{{itemId}}) para el ticket id [#{{ticketId}}]({{{url}}})",
"MESSAGE_INSURANCE_CHANGE": "He cambiado el crédito asegurado del cliente [{{clientName}} (#{{clientId}})]({{{url}}}) a *{{credit}} €*",
"MESSAGE_CHANGED_PAYMETHOD": "He cambiado la forma de pago del cliente [{{clientName}} (#{{clientId}})]({{{url}}})",
- "MESSAGE_CLAIM_ITEM_REGULARIZE": "Envio *{{quantity}}* unidades de [{{concept}} (#{{itemId}})]({{{itemUrl}}}) a {{nickname}} provenientes del ticket id [#{{ticketId}}]({{{ticketUrl}}})",
+ "Sent units from ticket": "Envio *{{quantity}}* unidades de [{{concept}} (#{{itemId}})]({{{itemUrl}}}) a *\"{{nickname}}\"* provenientes del ticket id [#{{ticketId}}]({{{ticketUrl}}})",
"Client checked as validated despite of duplication": "Cliente comprobado a pesar de que existe el cliente id {{clientId}}",
- "ORDER_ROW_UNAVAILABLE": "No hay disponibilidad de este producto"
+ "ORDER_ROW_UNAVAILABLE": "No hay disponibilidad de este producto",
+ "Distance must be lesser than 1000": "La distancia debe ser inferior a 1000"
}
\ No newline at end of file
diff --git a/modules/claim/back/methods/claim/regularizeClaim.js b/modules/claim/back/methods/claim/regularizeClaim.js
index 8a4f6dc957..adf1623c66 100644
--- a/modules/claim/back/methods/claim/regularizeClaim.js
+++ b/modules/claim/back/methods/claim/regularizeClaim.js
@@ -37,27 +37,43 @@ module.exports = Self => {
for (let i = 0; i < claimEnds.length; i++) {
const claimEnd = claimEnds[i];
const destination = claimEnd.claimDestination();
- const addressFk = destination && destination.addressFk;
+ const sale = await getSale(claimEnd.saleFk, options);
+ const addressId = destination && destination.addressFk;
- if (!addressFk) continue;
+ let address;
+ if (addressId)
+ address = await models.Address.findById(addressId, null, options);
+
+ const salesPerson = sale.ticket().client().salesPerson();
+ if (salesPerson) {
+ const nickname = address && address.nickname || destination.description;
+ const origin = ctx.req.headers.origin;
+ const message = $t('Sent units from ticket', {
+ quantity: sale.quantity,
+ concept: sale.concept,
+ itemId: sale.itemFk,
+ ticketId: sale.ticketFk,
+ nickname: nickname,
+ ticketUrl: `${origin}/#!/ticket/${sale.ticketFk}/summary`,
+ itemUrl: `${origin}/#!/item/${sale.itemFk}/summary`
+ });
+ await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message);
+ }
+
+ if (!address) continue;
- let sale = await getSale(claimEnd.saleFk, options);
let ticketFk = await getTicketId({
- addressFk: addressFk,
+ addressFk: addressId,
companyFk: sale.ticket().companyFk,
warehouseFk: sale.ticket().warehouseFk
}, options);
- let address = await models.Address.findOne({
- where: {id: addressFk}
- }, options);
-
if (!ticketFk) {
ticketFk = await createTicket(ctx, {
clientId: address.clientFk,
warehouseId: sale.ticket().warehouseFk,
companyId: sale.ticket().companyFk,
- addressId: addressFk
+ addressId: addressId
}, options);
}
@@ -69,21 +85,6 @@ module.exports = Self => {
price: sale.price,
discount: 100
}, options);
-
- const salesPerson = sale.ticket().client().salesPerson();
- if (salesPerson) {
- const origin = ctx.req.headers.origin;
- const message = $t('MESSAGE_CLAIM_ITEM_REGULARIZE', {
- quantity: sale.quantity,
- concept: sale.concept,
- itemId: sale.itemFk,
- ticketId: sale.ticketFk,
- nickname: address.nickname,
- ticketUrl: `${origin}/#!/ticket/${sale.ticketFk}/summary`,
- itemUrl: `${origin}/#!/item/${sale.itemFk}/summary`
- });
- await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message);
- }
}
let claim = await Self.findById(params.claimFk, null, options);
diff --git a/modules/claim/back/methods/claim/specs/regularizeClaim.spec.js b/modules/claim/back/methods/claim/specs/regularizeClaim.spec.js
index fd3fb3c3de..c7aa1cf0a9 100644
--- a/modules/claim/back/methods/claim/specs/regularizeClaim.spec.js
+++ b/modules/claim/back/methods/claim/specs/regularizeClaim.spec.js
@@ -5,6 +5,7 @@ describe('regularizeClaim()', () => {
const pendentState = 1;
const resolvedState = 3;
const trashDestination = 2;
+ const okDestination = 1;
const trashAddress = 12;
let claimEnds = [];
let trashTicket;
@@ -21,15 +22,20 @@ describe('regularizeClaim()', () => {
done();
});
- it('should change claim state to resolved', async() => {
- const ctx = {req: {
- accessToken: {userId: 18},
- headers: {origin: 'http://localhost'}}
+ it('should send a chat message with value "Trash" and then change claim state to resolved', async() => {
+ const ctx = {
+ req: {
+ accessToken: {userId: 18},
+ headers: {origin: 'http://localhost'}
+ }
};
- ctx.req.__ = value => {
- return value;
+ ctx.req.__ = (value, params) => {
+ return params.nickname;
};
+
let params = {claimFk: claimFk};
+ const chatModel = app.models.Chat;
+ spyOn(chatModel, 'sendCheckingPresence').and.callThrough();
claimEnds = await app.models.ClaimEnd.importTicketSales(ctx, {
claimFk: claimFk,
@@ -49,5 +55,32 @@ describe('regularizeClaim()', () => {
expect(trashTicket.addressFk).toEqual(trashAddress);
expect(claimBefore.claimStateFk).toEqual(pendentState);
expect(claimAfter.claimStateFk).toEqual(resolvedState);
+ expect(chatModel.sendCheckingPresence).toHaveBeenCalledWith(ctx, 18, 'Trash');
+ expect(chatModel.sendCheckingPresence).toHaveBeenCalledTimes(4);
+ });
+
+ it('should send a chat message with value "Bueno" and then change claim state to resolved', async() => {
+ const ctx = {
+ req: {
+ accessToken: {userId: 18},
+ headers: {origin: 'http://localhost'}
+ }
+ };
+ ctx.req.__ = (value, params) => {
+ return params.nickname;
+ };
+
+ let params = {claimFk: claimFk};
+ const chatModel = app.models.Chat;
+ spyOn(chatModel, 'sendCheckingPresence').and.callThrough();
+
+ claimEnds.forEach(async claimEnd => {
+ claimEnd.updateAttributes({claimDestinationFk: okDestination});
+ });
+
+ await app.models.Claim.regularizeClaim(ctx, params);
+
+ expect(chatModel.sendCheckingPresence).toHaveBeenCalledWith(ctx, 18, 'Bueno');
+ expect(chatModel.sendCheckingPresence).toHaveBeenCalledTimes(4);
});
});
diff --git a/modules/client/front/balance/index/index.html b/modules/client/front/balance/index/index.html
index f42998bbd9..8cdb5c9712 100644
--- a/modules/client/front/balance/index/index.html
+++ b/modules/client/front/balance/index/index.html
@@ -85,9 +85,9 @@
{{::balance.bankFk}}
- {{::balance.debit | currency: 'EUR':2}}
- {{::balance.credit | currency: 'EUR':2}}
- {{balance.balance | currency: 'EUR':2}}
+ {{::balance.debit | currency: 'EUR':2}}
+ {{::balance.credit | currency: 'EUR':2}}
+ {{balance.balance | currency: 'EUR':2}}
{
expect(expectedBalances[2].balance).toEqual(213.24);
});
});
+
+ describe('balances() setter', () => {
+ it('should set the balances data and not call the getBalances() method', () => {
+ spyOn(controller, 'getBalances');
+ controller.$.riskModel.data = null;
+ controller.balances = [{
+ id: 1,
+ debit: 1000,
+ credit: null
+ }, {
+ id: 2,
+ debit: null,
+ credit: 500
+ }, {
+ id: 3,
+ debit: null,
+ credit: 300
+ }];
+
+ expect(controller.balances).toBeDefined();
+ expect(controller.getBalances).not.toHaveBeenCalledWith();
+ });
+
+ it('should set the balances data and then call the getBalances() method', () => {
+ spyOn(controller, 'getBalances');
+ controller.balances = [{
+ id: 1,
+ debit: 1000,
+ credit: null
+ }, {
+ id: 2,
+ debit: null,
+ credit: 500
+ }, {
+ id: 3,
+ debit: null,
+ credit: 300
+ }];
+
+ expect(controller.balances).toBeDefined();
+ expect(controller.getBalances).toHaveBeenCalledWith();
+ });
+ });
});
});
diff --git a/modules/client/front/sample/create/index.html b/modules/client/front/sample/create/index.html
index 6a87d55b68..cd3412868b 100644
--- a/modules/client/front/sample/create/index.html
+++ b/modules/client/front/sample/create/index.html
@@ -15,7 +15,8 @@
+ ng-model="$ctrl.clientSample.recipient"
+ info="Its only used when sample is sent">
@@ -30,7 +31,7 @@
{
- this.$.showPreview.show();
- let dialog = document.body.querySelector('div.vn-dialog');
- let body = dialog.querySelector('tpl-body');
- let scroll = dialog.querySelector('div:first-child');
-
- body.innerHTML = res.data;
- scroll.scrollTop = 0;
- });
+ this.clientSample.companyId = value;
}
onSubmit() {
@@ -73,28 +42,49 @@ class Controller extends Component {
);
}
+ showPreview() {
+ this.send(true, res => {
+ this.$.showPreview.show();
+ const dialog = document.body.querySelector('div.vn-dialog');
+ const body = dialog.querySelector('tpl-body');
+ const scroll = dialog.querySelector('div:first-child');
+
+ body.innerHTML = res.data;
+ scroll.scrollTop = 0;
+ });
+ }
+
sendSample() {
- let sampleType = this.$.sampleType.selection;
- let params = {
+ this.send(false, () => {
+ this.vnApp.showSuccess(this.$translate.instant('Notification sent!'));
+ this.$state.go('client.card.sample.index');
+ });
+ }
+
+ send(isPreview, cb) {
+ const sampleType = this.$.sampleType.selection;
+ const params = {
clientId: this.$params.id,
recipient: this.clientSample.recipient
};
+ if (!params.recipient)
+ return this.vnApp.showError(this.$translate.instant('Email cannot be blank'));
+
if (!sampleType)
return this.vnApp.showError(this.$translate.instant('Choose a sample'));
- if (sampleType.hasCompany && !this.clientSample.companyFk)
+ if (sampleType.hasCompany && !this.clientSample.companyId)
return this.vnApp.showError(this.$translate.instant('Choose a company'));
if (sampleType.hasCompany)
- params.companyId = this.clientSample.companyFk;
+ params.companyId = this.clientSample.companyId;
+
+ if (isPreview) params.isPreview = true;
const serializedParams = this.$httpParamSerializer(params);
const query = `email/${sampleType.code}?${serializedParams}`;
- this.$http.get(query).then(res => {
- this.vnApp.showSuccess(this.$translate.instant('Notification sent!'));
- this.$state.go('client.card.sample.index');
- });
+ this.$http.get(query).then(cb);
}
}
Controller.$inject = ['$element', '$scope', 'vnApp', '$httpParamSerializer', 'vnConfig'];
diff --git a/modules/client/front/sample/create/index.spec.js b/modules/client/front/sample/create/index.spec.js
index efcda54012..da9a557f1e 100644
--- a/modules/client/front/sample/create/index.spec.js
+++ b/modules/client/front/sample/create/index.spec.js
@@ -40,84 +40,16 @@ describe('Client', () => {
$httpParamSerializer = _$httpParamSerializer_;
$element = angular.element('');
controller = $componentController('vnClientSampleCreate', {$element, $scope});
+ const element = document.createElement('div');
+ document.body.querySelector = () => {
+ return {
+ querySelector: () => {
+ return element;
+ }
+ };
+ };
}));
- describe('showPreview()', () => {
- it(`should perform a query (GET) and open a sample preview`, () => {
- spyOn(controller.$.showPreview, 'show');
- const element = document.createElement('div');
- document.body.querySelector = () => {
- return {
- querySelector: () => {
- return element;
- }
- };
- };
-
- controller.$.sampleType.selection = {
- hasCompany: false,
- code: 'MyReport'
- };
-
- controller.clientSample = {
- clientFk: 101
- };
-
- let event = {preventDefault: () => {}};
-
- const params = {
- clientId: 101,
- isPreview: true
- };
- const serializedParams = $httpParamSerializer(params);
-
- $httpBackend.when('GET', `email/MyReport?${serializedParams}`).respond(true);
- $httpBackend.expect('GET', `email/MyReport?${serializedParams}`);
- controller.showPreview(event);
- $httpBackend.flush();
-
- expect(controller.$.showPreview.show).toHaveBeenCalledWith();
- });
-
- it(`should perform a query (GET) with companyFk param and open a sample preview`, () => {
- spyOn(controller.$.showPreview, 'show');
- const element = document.createElement('div');
- document.body.querySelector = () => {
- return {
- querySelector: () => {
- return element;
- }
- };
- };
-
- controller.$.sampleType.selection = {
- hasCompany: true,
- code: 'MyReport'
- };
-
- controller.clientSample = {
- clientFk: 101,
- companyFk: 442
- };
-
- let event = {preventDefault: () => {}};
-
- const params = {
- clientId: 101,
- companyId: 442,
- isPreview: true
- };
- const serializedParams = $httpParamSerializer(params);
-
- $httpBackend.when('GET', `email/MyReport?${serializedParams}`).respond(true);
- $httpBackend.expect('GET', `email/MyReport?${serializedParams}`);
- controller.showPreview(event);
- $httpBackend.flush();
-
- expect(controller.$.showPreview.show).toHaveBeenCalledWith();
- });
- });
-
describe('onSubmit()', () => {
it(`should call sendSample() method`, () => {
spyOn(controller, 'sendSample');
@@ -127,55 +59,113 @@ describe('Client', () => {
});
});
- describe('sendSample()', () => {
- it(`should perform a query (GET) and call go() method`, () => {
- spyOn(controller.$state, 'go');
+ describe('send()', () => {
+ it(`should not perform an HTTP query if no recipient is specified`, () => {
+ spyOn(controller.$http, 'get');
controller.$.sampleType.selection = {
hasCompany: false,
code: 'MyReport'
};
-
controller.clientSample = {
- clientFk: 101
- };
-
- const params = {
clientId: 101
};
- const serializedParams = $httpParamSerializer(params);
- $httpBackend.when('GET', `email/MyReport?${serializedParams}`).respond(true);
- $httpBackend.expect('GET', `email/MyReport?${serializedParams}`);
- controller.sendSample();
- $httpBackend.flush();
+ controller.send(false, () => {});
- expect(controller.$state.go).toHaveBeenCalledWith('client.card.sample.index');
+ expect(controller.$http.get).not.toHaveBeenCalled();
});
- it(`should perform a query (GET) with companyFk param and call go() method`, () => {
- spyOn(controller.$state, 'go');
+ it(`should not perform an HTTP query if no sample is specified`, () => {
+ spyOn(controller.$http, 'get');
+
+ controller.$.sampleType.selection = null;
+ controller.clientSample = {
+ clientId: 101,
+ recipient: 'client@email.com'
+ };
+
+ controller.send(false, () => {});
+
+ expect(controller.$http.get).not.toHaveBeenCalled();
+ });
+
+ it(`should not perform an HTTP query if company is required and not specified`, () => {
+ spyOn(controller.$http, 'get');
controller.$.sampleType.selection = {
hasCompany: true,
code: 'MyReport'
};
-
controller.clientSample = {
- clientFk: 101,
- companyFk: 442
+ clientId: 101,
+ recipient: 'client@email.com'
};
- const params = {
+ controller.send(false, () => {});
+
+ expect(controller.$http.get).not.toHaveBeenCalled();
+ });
+
+ it(`should perform an HTTP query without passing companyId param`, () => {
+ controller.$.sampleType.selection = {
+ hasCompany: false,
+ code: 'MyReport'
+ };
+ controller.clientSample = {
clientId: 101,
+ recipient: 'client@email.com'
+ };
+
+ const serializedParams = $httpParamSerializer(controller.clientSample);
+ $httpBackend.expect('GET', `email/MyReport?${serializedParams}`).respond(true);
+ controller.send(false, () => {});
+ $httpBackend.flush();
+ });
+
+ it(`should perform an HTTP query passing companyId param`, () => {
+ controller.$.sampleType.selection = {
+ hasCompany: true,
+ code: 'MyReport'
+ };
+ controller.clientSample = {
+ clientId: 101,
+ recipient: 'client@email.com',
companyId: 442
};
- const serializedParams = $httpParamSerializer(params);
- $httpBackend.when('GET', `email/MyReport?${serializedParams}`).respond(true);
- $httpBackend.expect('GET', `email/MyReport?${serializedParams}`);
- controller.sendSample();
+ const serializedParams = $httpParamSerializer(controller.clientSample);
+ $httpBackend.expect('GET', `email/MyReport?${serializedParams}`).respond(true);
+ controller.send(false, () => {});
$httpBackend.flush();
+ });
+ });
+
+ describe('showPreview()', () => {
+ it(`should open a sample preview`, () => {
+ spyOn(controller.$.showPreview, 'show');
+
+ controller.send = (isPreview, cb) => {
+ cb({
+ data: ''
+ });
+ };
+ controller.showPreview();
+
+ expect(controller.$.showPreview.show).toHaveBeenCalledWith();
+ });
+ });
+
+ describe('sendSample()', () => {
+ it(`should perform a query (GET) and call go() method`, () => {
+ spyOn(controller.$state, 'go');
+
+ controller.send = (isPreview, cb) => {
+ cb({
+ data: true
+ });
+ };
+ controller.sendSample();
expect(controller.$state.go).toHaveBeenCalledWith('client.card.sample.index');
});
diff --git a/modules/client/front/sample/create/locale/es.yml b/modules/client/front/sample/create/locale/es.yml
index d1ef82c0ee..6828e3e489 100644
--- a/modules/client/front/sample/create/locale/es.yml
+++ b/modules/client/front/sample/create/locale/es.yml
@@ -1,3 +1,5 @@
Choose a sample: Selecciona una plantilla
Choose a company: Selecciona una empresa
-Recipient: Destinatario
\ No newline at end of file
+Email cannot be blank: Debes introducir un email
+Recipient: Destinatario
+Its only used when sample is sent: Se utiliza únicamente cuando se envía la plantilla
\ No newline at end of file
diff --git a/modules/client/front/sms/index.html b/modules/client/front/sms/index.html
index facbb76948..fb2f1dfff2 100644
--- a/modules/client/front/sms/index.html
+++ b/modules/client/front/sms/index.html
@@ -13,20 +13,27 @@
rule>
-
+
- {{'Characters remaining' | translate}}: {{$ctrl.charactersRemaining()}}
+ {{'Characters remaining' | translate}}:
+
+ {{$ctrl.charactersRemaining()}}
+
diff --git a/modules/client/front/sms/index.js b/modules/client/front/sms/index.js
index 851ce1a66e..c7d89e7170 100644
--- a/modules/client/front/sms/index.js
+++ b/modules/client/front/sms/index.js
@@ -17,13 +17,12 @@ class Controller extends Component {
}
charactersRemaining() {
- let elementMaxLength;
- let textAreaLength;
const element = this.$scope.message;
+ const value = element.input.value;
- textAreaLength = element.input.textLength;
- elementMaxLength = element.maxlength;
- return elementMaxLength - textAreaLength;
+ const maxLength = 160;
+ const textAreaLength = new Blob([value]).size;
+ return maxLength - textAreaLength;
}
onResponse(response) {
@@ -33,6 +32,8 @@ class Controller extends Component {
throw new Error(`The destination can't be empty`);
if (!this.sms.message)
throw new Error(`The message can't be empty`);
+ if (this.charactersRemaining() < 0)
+ throw new Error(`The message it's too long`);
this.$http.post(`Clients/${this.$params.id}/sendSms`, this.sms).then(res => {
this.vnApp.showMessage(this.$translate.instant('SMS sent!'));
diff --git a/modules/client/front/sms/index.spec.js b/modules/client/front/sms/index.spec.js
index 26a597c174..03d9cbf1d9 100644
--- a/modules/client/front/sms/index.spec.js
+++ b/modules/client/front/sms/index.spec.js
@@ -15,6 +15,11 @@ describe('Client', () => {
controller = $componentController('vnClientSms', {$element, $scope});
controller.client = {id: 101};
controller.$params = {id: 101};
+ controller.$scope.message = {
+ input: {
+ value: 'My SMS'
+ }
+ };
}));
describe('onResponse()', () => {
@@ -56,14 +61,13 @@ describe('Client', () => {
it('should return the characters remaining in a element', () => {
controller.$scope.message = {
input: {
- textLength: 50
- },
- maxlength: 150
+ value: 'My message 0€'
+ }
};
let result = controller.charactersRemaining();
- expect(result).toEqual(100);
+ expect(result).toEqual(145);
});
});
});
diff --git a/modules/client/front/sms/locale/es.yml b/modules/client/front/sms/locale/es.yml
index 4438e4fce4..64c3fcca67 100644
--- a/modules/client/front/sms/locale/es.yml
+++ b/modules/client/front/sms/locale/es.yml
@@ -4,4 +4,6 @@ Message: Mensaje
SMS sent!: ¡SMS enviado!
Characters remaining: Carácteres restantes
The destination can't be empty: El destinatario no puede estar vacio
-The message can't be empty: El mensaje no puede estar vacio
\ No newline at end of file
+The message can't be empty: El mensaje no puede estar vacio
+The message it's too long: El mensaje es demasiado largo
+Special characters like accents counts as a multiple: Carácteres especiales como los acentos cuentan como varios
\ No newline at end of file
diff --git a/modules/entry/back/methods/entry/filter.js b/modules/entry/back/methods/entry/filter.js
index 8cbe5e15e6..93e9558a96 100644
--- a/modules/entry/back/methods/entry/filter.js
+++ b/modules/entry/back/methods/entry/filter.js
@@ -127,6 +127,7 @@ module.exports = Self => {
e.companyFk,
e.gestDocFk,
e.invoiceInFk,
+ t.landed,
s.name AS supplierName,
co.code AS companyCode,
cu.code AS currencyCode
diff --git a/modules/entry/back/methods/entry/specs/filter.spec.js b/modules/entry/back/methods/entry/specs/filter.spec.js
index 9b935d831a..25d2da0b42 100644
--- a/modules/entry/back/methods/entry/specs/filter.spec.js
+++ b/modules/entry/back/methods/entry/specs/filter.spec.js
@@ -23,7 +23,7 @@ describe('Entry filter()', () => {
let result = await app.models.Entry.filter(ctx);
- expect(result.length).toEqual(7);
+ expect(result.length).toEqual(8);
});
it('should return the entry matching the supplier', async() => {
@@ -35,7 +35,7 @@ describe('Entry filter()', () => {
let result = await app.models.Entry.filter(ctx);
- expect(result.length).toEqual(5);
+ expect(result.length).toEqual(6);
});
it('should return the entry matching the company', async() => {
@@ -47,7 +47,7 @@ describe('Entry filter()', () => {
let result = await app.models.Entry.filter(ctx);
- expect(result.length).toEqual(6);
+ expect(result.length).toEqual(7);
});
it('should return the entries matching isBooked', async() => {
diff --git a/modules/entry/front/index/index.html b/modules/entry/front/index/index.html
index 8ddd4d3a39..f0f5404899 100644
--- a/modules/entry/front/index/index.html
+++ b/modules/entry/front/index/index.html
@@ -16,45 +16,68 @@
+
Id
- Created
- Travel
- Notes
+ Landed
Reference
- Booked
- Is inventory
- Confirmed
- Ordered
- Is raid
- Commission
Supplier
Currency
Company
+ Booked
+ Confirmed
+ Ordered
+ Notes
+
+
+
+
+
+
{{::entry.id}}
- {{::entry.created | date:'dd/MM/yyyy'}}
- {{::entry.travelFk}}
- {{::entry.notes}}
+
+
+ {{::entry.landed | date:'dd/MM/yyyy'}}
+
+
{{::entry.ref}}
-
-
-
-
-
- {{::entry.commission}}
{{::entry.supplierName}}
{{::entry.currencyCode}}
{{::entry.companyCode}}
+
+
+
+
+
+
+
+
+
diff --git a/modules/entry/front/index/index.js b/modules/entry/front/index/index.js
index ec78c06dfa..53d2f45e07 100644
--- a/modules/entry/front/index/index.js
+++ b/modules/entry/front/index/index.js
@@ -1,5 +1,5 @@
import ngModule from '../module';
-
+import './style.scss';
export default class Controller {
constructor($scope) {
this.$ = $scope;
@@ -11,6 +11,16 @@ export default class Controller {
else
this.$.model.clear();
}
+
+ showTravelDescriptor(event, travelFk) {
+ if (event.defaultPrevented) return;
+ event.preventDefault();
+ event.stopPropagation();
+
+ this.selectedTravel = travelFk;
+ this.$.travelDescriptor.parent = event.target;
+ this.$.travelDescriptor.show();
+ }
}
Controller.$inject = ['$scope'];
diff --git a/modules/entry/front/index/locale/es.yml b/modules/entry/front/index/locale/es.yml
new file mode 100644
index 0000000000..8ef9b2c7af
--- /dev/null
+++ b/modules/entry/front/index/locale/es.yml
@@ -0,0 +1,15 @@
+Inventory entry: Es inventario
+Virtual entry: Es una redada
+Supplier: Proveedor
+Currency: Moneda
+Company: Empresa
+Confirmed: Confirmada
+Ordered: Pedida
+Is raid: Redada
+Commission: Comisión
+Landed: F. entrega
+Reference: Referencia
+Created: Creado
+Booked: Facturado
+Is inventory: Inventario
+Notes: Notas
\ No newline at end of file
diff --git a/modules/entry/front/index/style.scss b/modules/entry/front/index/style.scss
new file mode 100644
index 0000000000..ab759d2ccb
--- /dev/null
+++ b/modules/entry/front/index/style.scss
@@ -0,0 +1,5 @@
+@import "variables";
+
+ vn-icon[icon=insert_drive_file]{
+ color: $color-font-secondary;
+ }
diff --git a/modules/entry/front/locale/es.yml b/modules/entry/front/locale/es.yml
index 214be93d4d..3de6c59a83 100644
--- a/modules/entry/front/locale/es.yml
+++ b/modules/entry/front/locale/es.yml
@@ -1,15 +1,3 @@
#Ordenar alfabeticamente
-Reference: Referencia
-Created: Creado
-Booked: Facturado
-Is inventory: Inventario
-Notes: Notas
-Travel: Envío
-Supplier: Proveedor
-Currency: Moneda
-Company: Empresa
-Confirmed: Confirmada
-Ordered: Pedida
-Is raid: Redada
-Commission: Comisión
+
# Sections
diff --git a/modules/entry/front/routes.json b/modules/entry/front/routes.json
index f23ff02bfb..bd1ace3f25 100644
--- a/modules/entry/front/routes.json
+++ b/modules/entry/front/routes.json
@@ -2,6 +2,7 @@
"module": "entry",
"name": "Entries",
"icon": "icon-entry",
+ "dependencies": ["travel"],
"validations": true,
"menus": {
"main": [
diff --git a/modules/item/back/methods/item/createIntrastat.js b/modules/item/back/methods/item/createIntrastat.js
new file mode 100644
index 0000000000..1a88d16e25
--- /dev/null
+++ b/modules/item/back/methods/item/createIntrastat.js
@@ -0,0 +1,61 @@
+let UserError = require('vn-loopback/util/user-error');
+
+module.exports = Self => {
+ Self.remoteMethod('createIntrastat', {
+ description: 'Creates a new item intrastat',
+ accessType: 'WRITE',
+ accepts: [{
+ arg: 'id',
+ type: 'number',
+ required: true,
+ description: 'The item id',
+ http: {source: 'path'}
+ },
+ {
+ arg: 'intrastatId',
+ type: 'number',
+ required: true
+ },
+ {
+ arg: 'description',
+ type: 'string',
+ required: true
+ }],
+ returns: {
+ type: 'boolean',
+ root: true
+ },
+ http: {
+ path: `/:id/createIntrastat`,
+ verb: 'PATCH'
+ }
+ });
+
+ Self.createIntrastat = async(id, intrastatId, description) => {
+ const models = Self.app.models;
+ const country = await models.Country.findOne({
+ where: {code: 'ES'}
+ });
+
+ const itemTaxCountry = await models.ItemTaxCountry.findOne({
+ where: {
+ itemFk: id,
+ countryFk: country.id
+ },
+ order: 'effectived DESC'
+ });
+ const taxClassCode = await models.TaxClassCode.findOne({
+ where: {
+ taxClassFk: itemTaxCountry.taxClassFk
+ },
+ order: 'effectived DESC'
+ });
+
+ return models.Intrastat.create({
+ id: intrastatId,
+ description: description,
+ taxClassFk: itemTaxCountry.taxClassFk,
+ taxCodeFk: taxClassCode.taxCodeFk
+ });
+ };
+};
diff --git a/modules/item/back/methods/item/getLastEntries.js b/modules/item/back/methods/item/getLastEntries.js
index bab808cef1..a438afcb63 100644
--- a/modules/item/back/methods/item/getLastEntries.js
+++ b/modules/item/back/methods/item/getLastEntries.js
@@ -22,6 +22,7 @@ module.exports = Self => {
let where = filter.where;
let query = `CALL vn.itemLastEntries(?, ?)`;
let [lastEntries] = await Self.rawSql(query, [where.itemFk, where.date]);
+
return lastEntries;
};
};
diff --git a/modules/item/back/methods/item/specs/createIntrastat.spec.js b/modules/item/back/methods/item/specs/createIntrastat.spec.js
new file mode 100644
index 0000000000..fb10de858a
--- /dev/null
+++ b/modules/item/back/methods/item/specs/createIntrastat.spec.js
@@ -0,0 +1,22 @@
+const app = require('vn-loopback/server/server');
+
+describe('createIntrastat()', () => {
+ let newIntrastat;
+
+ afterAll(async done => {
+ await app.models.Intrastat.destroyById(newIntrastat.id);
+
+ done();
+ });
+
+ it('should create a new intrastat', async() => {
+ const intrastatId = 588420239;
+ const description = 'Tropical Flowers';
+ const itemId = 9;
+ newIntrastat = await app.models.Item.createIntrastat(itemId, intrastatId, description);
+
+ expect(newIntrastat.description).toEqual(description);
+ expect(newIntrastat.taxClassFk).toEqual(1);
+ expect(newIntrastat.taxCodeFk).toEqual(21);
+ });
+});
diff --git a/modules/item/back/model-config.json b/modules/item/back/model-config.json
index db8eed9d56..d8ec5914a1 100644
--- a/modules/item/back/model-config.json
+++ b/modules/item/back/model-config.json
@@ -62,6 +62,9 @@
"TaxClass": {
"dataSource": "vn"
},
+ "TaxClassCode": {
+ "dataSource": "vn"
+ },
"TaxCode": {
"dataSource": "vn"
},
diff --git a/modules/item/back/models/item.js b/modules/item/back/models/item.js
index 6c221e94df..01061ce999 100644
--- a/modules/item/back/models/item.js
+++ b/modules/item/back/models/item.js
@@ -12,6 +12,7 @@ module.exports = Self => {
require('../methods/item/getVisibleAvailable')(Self);
require('../methods/item/new')(Self);
require('../methods/item/getWasteDetail')(Self);
+ require('../methods/item/createIntrastat')(Self);
Self.validatesPresenceOf('originFk', {message: 'Cannot be blank'});
diff --git a/modules/item/back/models/item.json b/modules/item/back/models/item.json
index d8d1cb64d1..dbaa3a4090 100644
--- a/modules/item/back/models/item.json
+++ b/modules/item/back/models/item.json
@@ -1,13 +1,13 @@
{
"name": "Item",
- "base": "Loggable",
- "log": {
- "model":"ItemLog",
+ "base": "Loggable",
+ "log": {
+ "model": "ItemLog",
"showField": "id"
- },
+ },
"options": {
"mysql": {
- "table": "item"
+ "table": "item"
}
},
"properties": {
@@ -125,55 +125,55 @@
}
},
"relations": {
- "itemType": {
- "type": "belongsTo",
- "model": "ItemType",
- "foreignKey": "typeFk"
- },
- "ink": {
- "type": "belongsTo",
- "model": "Ink",
- "foreignKey": "inkFk"
- },
- "origin": {
- "type": "belongsTo",
- "model": "Origin",
- "foreignKey": "originFk"
- },
- "producer": {
- "type": "belongsTo",
- "model": "Producer",
- "foreignKey": "producerFk"
- },
- "intrastat": {
- "type": "belongsTo",
- "model": "Intrastat",
- "foreignKey": "intrastatFk"
- },
- "expense": {
- "type": "belongsTo",
- "model": "Expense",
- "foreignKey": "expenseFk"
- },
- "tags": {
- "type": "hasMany",
- "model": "ItemTag",
- "foreignKey": "itemFk"
- },
- "itemBarcode": {
- "type": "hasMany",
- "model": "ItemBarcode",
- "foreignKey": "itemFk"
- },
- "taxes": {
- "type": "hasMany",
- "model": "ItemTaxCountry",
- "foreignKey": "itemFk"
- },
- "itemNiche": {
- "type": "hasMany",
- "model": "ItemNiche",
- "foreignKey": "itemFk"
- }
+ "itemType": {
+ "type": "belongsTo",
+ "model": "ItemType",
+ "foreignKey": "typeFk"
+ },
+ "ink": {
+ "type": "belongsTo",
+ "model": "Ink",
+ "foreignKey": "inkFk"
+ },
+ "origin": {
+ "type": "belongsTo",
+ "model": "Origin",
+ "foreignKey": "originFk"
+ },
+ "producer": {
+ "type": "belongsTo",
+ "model": "Producer",
+ "foreignKey": "producerFk"
+ },
+ "intrastat": {
+ "type": "belongsTo",
+ "model": "Intrastat",
+ "foreignKey": "intrastatFk"
+ },
+ "expense": {
+ "type": "belongsTo",
+ "model": "Expense",
+ "foreignKey": "expenseFk"
+ },
+ "tags": {
+ "type": "hasMany",
+ "model": "ItemTag",
+ "foreignKey": "itemFk"
+ },
+ "itemBarcode": {
+ "type": "hasMany",
+ "model": "ItemBarcode",
+ "foreignKey": "itemFk"
+ },
+ "taxes": {
+ "type": "hasMany",
+ "model": "ItemTaxCountry",
+ "foreignKey": "itemFk"
+ },
+ "itemNiche": {
+ "type": "hasMany",
+ "model": "ItemNiche",
+ "foreignKey": "itemFk"
+ }
}
- }
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/modules/item/back/models/tax-class-code.json b/modules/item/back/models/tax-class-code.json
new file mode 100644
index 0000000000..ef8c529d96
--- /dev/null
+++ b/modules/item/back/models/tax-class-code.json
@@ -0,0 +1,46 @@
+{
+ "name": "TaxClassCode",
+ "base": "VnModel",
+ "options": {
+ "mysql": {
+ "table": "taxClassCode"
+ }
+ },
+ "properties": {
+ "taxClassFk": {
+ "type": "number",
+ "required": true,
+ "id": 1
+ },
+ "taxCodeFk": {
+ "type": "number",
+ "required": true,
+ "id": 2
+ },
+ "effectived": {
+ "type": "date",
+ "required": true,
+ "id": 3
+ }
+ },
+ "relations": {
+ "taxClass": {
+ "type": "belongsTo",
+ "model": "TaxClass",
+ "foreignKey": "taxClassFk"
+ },
+ "taxCode": {
+ "type": "belongsTo",
+ "model": "TaxCode",
+ "foreignKey": "taxCodeFk"
+ }
+ },
+ "acls": [
+ {
+ "accessType": "READ",
+ "principalType": "ROLE",
+ "principalId": "$everyone",
+ "permission": "ALLOW"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/modules/item/front/basic-data/__snapshots__/index.spec.js.snap b/modules/item/front/basic-data/__snapshots__/index.spec.js.snap
deleted file mode 100644
index 92219bb339..0000000000
--- a/modules/item/front/basic-data/__snapshots__/index.spec.js.snap
+++ /dev/null
@@ -1,3 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`vnItemBasicData Component vnItemBasicData $onChanges() should pass the data to the watcher 1`] = `"the current value of an item"`;
diff --git a/modules/item/front/basic-data/index.html b/modules/item/front/basic-data/index.html
index bd0cec86de..3cd879945d 100644
--- a/modules/item/front/basic-data/index.html
+++ b/modules/item/front/basic-data/index.html
@@ -55,6 +55,13 @@
{{::id}}
{{::description}}
+
+
+
+
-
+
@@ -134,3 +141,30 @@
+
+
+
+
+ New intrastat
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/item/front/basic-data/index.js b/modules/item/front/basic-data/index.js
index 123aa59cdc..33a60b32d4 100644
--- a/modules/item/front/basic-data/index.js
+++ b/modules/item/front/basic-data/index.js
@@ -1,20 +1,23 @@
import ngModule from '../module';
+import Component from 'core/lib/component';
+class Controller extends Component {
+ showIntrastat(event) {
+ if (event.defaultPrevented) return;
+ event.preventDefault();
-class Controller {
- constructor($scope, $timeout) {
- this.$scope = $scope;
- this.$timeout = $timeout;
+ this.newIntrastat = {
+ taxClassFk: this.item.taxClassFk
+ };
+ this.$.intrastat.show();
}
- $onChanges(data) {
- this.$timeout(() => {
- this.$scope.watcher.data = data.item.currentValue;
- });
+ onIntrastatAccept() {
+ const query = `Items/${this.$params.id}/createIntrastat`;
+ return this.$http.patch(query, this.newIntrastat)
+ .then(res => this.item.intrastatFk = res.data.id);
}
}
-Controller.$inject = ['$scope', '$timeout'];
-
ngModule.component('vnItemBasicData', {
template: require('./index.html'),
bindings: {
diff --git a/modules/item/front/basic-data/index.spec.js b/modules/item/front/basic-data/index.spec.js
index e7578b54c0..178fac2784 100644
--- a/modules/item/front/basic-data/index.spec.js
+++ b/modules/item/front/basic-data/index.spec.js
@@ -2,26 +2,31 @@ import './index.js';
describe('vnItemBasicData', () => {
describe('Component vnItemBasicData', () => {
+ let $httpBackend;
let $scope;
let controller;
- let $timeout;
+ let $element;
beforeEach(ngModule('item'));
- beforeEach(angular.mock.inject(($componentController, $rootScope, _$timeout_) => {
- $timeout = _$timeout_;
+ beforeEach(angular.mock.inject(($componentController, $rootScope, _$httpBackend_) => {
+ $httpBackend = _$httpBackend_;
$scope = $rootScope.$new();
- controller = $componentController('vnItemBasicData', {$scope, $timeout});
- controller.$scope.watcher = {};
+ $element = angular.element('');
+ controller = $componentController('vnItemBasicData', {$element, $scope});
+ controller.$.watcher = {};
+ controller.$params.id = 1;
+ controller.item = {id: 1, name: 'Rainbow Coral'};
}));
- describe('$onChanges()', () => {
+ describe('onIntrastatAccept()', () => {
it('should pass the data to the watcher', () => {
- const data = {item: {currentValue: 'the current value of an item'}};
- controller.$onChanges(data);
- $timeout.flush();
+ const newIntrastatId = 20;
+ $httpBackend.expect('PATCH', 'Items/1/createIntrastat').respond({id: 20});
+ controller.onIntrastatAccept();
+ $httpBackend.flush();
- expect(controller.$scope.watcher.data).toMatchSnapshot();
+ expect(controller.item.intrastatFk).toEqual(newIntrastatId);
});
});
});
diff --git a/modules/item/front/basic-data/locale/es.yml b/modules/item/front/basic-data/locale/es.yml
index 67780557a3..07e6817709 100644
--- a/modules/item/front/basic-data/locale/es.yml
+++ b/modules/item/front/basic-data/locale/es.yml
@@ -5,4 +5,6 @@ Full name calculates based on tags 1-3. Is not recommended to change it manually
No se recomienda cambiarlo manualmente
Is active: Activo
Expense: Gasto
-Price in kg: Precio en kg
\ No newline at end of file
+Price in kg: Precio en kg
+New intrastat: Nuevo intrastat
+Identifier: Identificador
\ No newline at end of file
diff --git a/modules/order/back/methods/order/catalogFilter.js b/modules/order/back/methods/order/catalogFilter.js
index 3814aa12d1..114cd27864 100644
--- a/modules/order/back/methods/order/catalogFilter.js
+++ b/modules/order/back/methods/order/catalogFilter.js
@@ -162,6 +162,7 @@ module.exports = Self => {
`SELECT
it.tagFk,
it.itemFk,
+ it.value,
t.name
FROM tmp.ticketCalculateItem tci
JOIN vn.itemTag it ON it.itemFk = tci.itemFk
diff --git a/modules/order/front/catalog/index.html b/modules/order/front/catalog/index.html
index 5cc72e3c8f..37767e81bb 100644
--- a/modules/order/front/catalog/index.html
+++ b/modules/order/front/catalog/index.html
@@ -85,12 +85,15 @@
-
+ show-field="value"
+ value-field="value"
+ label="Search tag">
@@ -101,7 +104,7 @@
style="cursor: pointer;">
-
+
{
- // Add new tag filters
- item.tags.forEach(itemTag => {
- const alreadyAdded = newFilterList.findIndex(filter => {
- return filter.field == itemTag.tagFk;
- });
-
- if (alreadyAdded == -1) {
- newFilterList.push({
- name: itemTag.name,
- field: itemTag.tagFk,
- isTag: true
- });
- }
- });
- });
-
- // Add default filters - Replaces tags with same name
- this.defaultOrderFields.forEach(orderField => {
- const index = newFilterList.findIndex(newfield => {
- return newfield.name == orderField.name;
- });
-
- if (index > -1)
- newFilterList[index] = orderField;
- else
- newFilterList.push(orderField);
- });
-
- this.orderFields = newFilterList;
+ this.buildTagsFilter(value);
+ this.buildOrderFilter(value);
}
get categoryId() {
@@ -273,6 +244,43 @@ class Controller {
this.$state.go(this.$state.current.name, params);
}
+
+ buildTagsFilter(items) {
+ const tagValues = [];
+ items.forEach(item => {
+ item.tags.forEach(itemTag => {
+ const alreadyAdded = tagValues.findIndex(tag => {
+ return tag.value == itemTag.value;
+ });
+
+ if (alreadyAdded == -1)
+ tagValues.push(itemTag);
+ });
+ });
+ this.tagValues = tagValues;
+ }
+
+ buildOrderFilter(items) {
+ const tags = [];
+ items.forEach(item => {
+ item.tags.forEach(itemTag => {
+ const alreadyAdded = tags.findIndex(tag => {
+ return tag.field == itemTag.tagFk;
+ });
+
+ if (alreadyAdded == -1) {
+ tags.push({
+ name: itemTag.name,
+ field: itemTag.tagFk,
+ isTag: true
+ });
+ }
+ });
+ });
+ let newFilterList = [].concat(this.defaultOrderFields);
+ newFilterList = newFilterList.concat(tags);
+ this.orderFields = newFilterList;
+ }
}
Controller.$inject = ['$http', '$scope', '$state', '$compile', '$transitions'];
diff --git a/modules/order/front/catalog/index.spec.js b/modules/order/front/catalog/index.spec.js
index dd9e132577..01da618009 100644
--- a/modules/order/front/catalog/index.spec.js
+++ b/modules/order/front/catalog/index.spec.js
@@ -37,16 +37,19 @@ describe('Order', () => {
describe('items() setter', () => {
it(`should return an object with order params`, () => {
- let expectedResult = [{field: 'showOrder, price', name: 'Color'}];
- let unexpectedResult = [{tagFk: 5, name: 'Color'}];
- controller.items = [{id: 1, name: 'My Item', tags: [
+ spyOn(controller, 'buildTagsFilter');
+ spyOn(controller, 'buildOrderFilter').and.callThrough();
+ const expectedResult = [{field: 'showOrder, price', name: 'Color and price'}];
+ const items = [{id: 1, name: 'My Item', tags: [
{tagFk: 4, name: 'Length'},
{tagFk: 5, name: 'Color'}
]}];
+ controller.items = items;
- expect(controller.orderFields.length).toEqual(5);
+ expect(controller.orderFields.length).toEqual(6);
expect(controller.orderFields).toEqual(jasmine.arrayContaining(expectedResult));
- expect(controller.orderFields).not.toEqual(jasmine.arrayContaining(unexpectedResult));
+ expect(controller.buildTagsFilter).toHaveBeenCalledWith(items);
+ expect(controller.buildOrderFilter).toHaveBeenCalledWith(items);
});
});
@@ -222,6 +225,48 @@ describe('Order', () => {
expect(controller.$.model.addFilter).toHaveBeenCalledWith(null, expectedOrder);
});
});
+
+ describe('buildTagsFilter()', () => {
+ it(`should create an array of non repeated tag values and then set the tagValues property`, () => {
+ const items = [
+ {
+ id: 1, name: 'My Item 1', tags: [
+ {tagFk: 4, name: 'Length', value: 1},
+ {tagFk: 5, name: 'Color', value: 'red'}
+ ]
+ },
+ {
+ id: 2, name: 'My Item 2', tags: [
+ {tagFk: 4, name: 'Length', value: 1},
+ {tagFk: 5, name: 'Color', value: 'blue'}
+ ]
+ }];
+ controller.buildTagsFilter(items);
+
+ expect(controller.tagValues.length).toEqual(3);
+ });
+ });
+
+ describe('buildOrderFilter()', () => {
+ it(`should create an array of non repeated tags plus default filters and then set the orderFields property`, () => {
+ const items = [
+ {
+ id: 1, name: 'My Item 1', tags: [
+ {tagFk: 4, name: 'Length'},
+ {tagFk: 5, name: 'Color'}
+ ]
+ },
+ {
+ id: 2, name: 'My Item 2', tags: [
+ {tagFk: 5, name: 'Color'},
+ {tagFk: 6, name: 'Relevancy'}
+ ]
+ }];
+ controller.buildOrderFilter(items);
+
+ expect(controller.orderFields.length).toEqual(7);
+ });
+ });
});
});
diff --git a/modules/order/front/locale/es.yml b/modules/order/front/locale/es.yml
index 0ada37bfd0..565d4f2518 100644
--- a/modules/order/front/locale/es.yml
+++ b/modules/order/front/locale/es.yml
@@ -16,6 +16,7 @@ Item id: Id de artículo
Order by: Ordenar por
Order: Orden
Price: Precio
+Color and price: Color y precio
Ascendant: Ascendente
Descendant: Descendente
Created from: Creado desde
diff --git a/modules/route/back/models/route.js b/modules/route/back/models/route.js
index 4dd9f3dc02..6d93cfe405 100644
--- a/modules/route/back/models/route.js
+++ b/modules/route/back/models/route.js
@@ -5,4 +5,21 @@ module.exports = Self => {
require('../methods/route/guessPriority')(Self);
require('../methods/route/updateVolume')(Self);
require('../methods/route/getDeliveryPoint')(Self);
+
+ Self.validate('kmStart', validateDistance, {
+ message: 'Distance must be lesser than 1000'
+ });
+
+ Self.validate('kmEnd', validateDistance, {
+ message: 'Distance must be lesser than 1000'
+ });
+
+ function validateDistance(err) {
+ const routeTotalKm = this.kmEnd - this.kmStart;
+ const routeMaxKm = 1000;
+ if ( routeTotalKm > routeMaxKm || this.kmStart > this.kmEnd)
+ err();
+ }
};
+
+
diff --git a/modules/route/front/basic-data/index.js b/modules/route/front/basic-data/index.js
index 810fd75112..d4a481dc5f 100644
--- a/modules/route/front/basic-data/index.js
+++ b/modules/route/front/basic-data/index.js
@@ -1,8 +1,10 @@
import ngModule from '../module';
class Controller {
- constructor($scope) {
+ constructor($scope, vnApp, $translate) {
this.$ = $scope;
+ this.vnApp = vnApp;
+ this.$translate = $translate;
}
onSubmit() {
@@ -11,7 +13,7 @@ class Controller {
});
}
}
-Controller.$inject = ['$scope'];
+Controller.$inject = ['$scope', 'vnApp', '$translate'];
ngModule.component('vnRouteBasicData', {
template: require('./index.html'),
diff --git a/modules/route/front/basic-data/locale/es.yml b/modules/route/front/basic-data/locale/es.yml
index 442a4fa828..f0414b5b15 100644
--- a/modules/route/front/basic-data/locale/es.yml
+++ b/modules/route/front/basic-data/locale/es.yml
@@ -2,4 +2,4 @@ Date finished: Fecha fin
Date started: Fecha inicio
Km start: Km de inicio
Km end: Km de fin
-Description: Descripción
\ No newline at end of file
+Description: Descripción
diff --git a/modules/ticket/front/create/card.js b/modules/ticket/front/create/card.js
index 2e775c18b0..54cc56c684 100644
--- a/modules/ticket/front/create/card.js
+++ b/modules/ticket/front/create/card.js
@@ -14,7 +14,7 @@ class Controller {
$onInit() {
if (this.$stateParams && this.$stateParams.clientFk)
- this.clientId = this.$stateParams.clientFk;
+ this.clientId = parseInt(this.$stateParams.clientFk);
this.warehouseId = this.vnConfig.warehouseFk;
}
diff --git a/modules/ticket/front/sms/index.html b/modules/ticket/front/sms/index.html
index f74bc29e5e..2003aa4fd4 100644
--- a/modules/ticket/front/sms/index.html
+++ b/modules/ticket/front/sms/index.html
@@ -18,15 +18,22 @@
vn-id="message"
label="Message"
ng-model="$ctrl.sms.message"
+ info="Special characters like accents counts as a multiple"
rows="5"
- maxlength="160"
required="true"
rule>
- {{'Characters remaining' | translate}}: {{$ctrl.charactersRemaining()}}
+ {{'Characters remaining' | translate}}:
+
+ {{$ctrl.charactersRemaining()}}
+
diff --git a/modules/ticket/front/sms/index.js b/modules/ticket/front/sms/index.js
index 0d639d46e2..ac11315132 100644
--- a/modules/ticket/front/sms/index.js
+++ b/modules/ticket/front/sms/index.js
@@ -17,13 +17,12 @@ class Controller extends Component {
}
charactersRemaining() {
- let elementMaxLength;
- let textAreaLength;
const element = this.$scope.message;
+ const value = element.input.value;
- textAreaLength = element.input.textLength;
- elementMaxLength = element.maxlength;
- return elementMaxLength - textAreaLength;
+ const maxLength = 160;
+ const textAreaLength = new Blob([value]).size;
+ return maxLength - textAreaLength;
}
onResponse(response) {
@@ -33,6 +32,8 @@ class Controller extends Component {
throw new Error(`The destination can't be empty`);
if (!this.sms.message)
throw new Error(`The message can't be empty`);
+ if (this.charactersRemaining() < 0)
+ throw new Error(`The message it's too long`);
this.$http.post(`Tickets/${this.$params.id}/sendSms`, this.sms).then(res => {
this.vnApp.showMessage(this.$translate.instant('SMS sent!'));
diff --git a/modules/ticket/front/sms/index.spec.js b/modules/ticket/front/sms/index.spec.js
index d02b3f3eb6..96c10edd10 100644
--- a/modules/ticket/front/sms/index.spec.js
+++ b/modules/ticket/front/sms/index.spec.js
@@ -14,6 +14,11 @@ describe('Ticket', () => {
$element = angular.element('');
controller = $componentController('vnTicketSms', {$element, $scope});
controller.$params = {id: 11};
+ controller.$scope.message = {
+ input: {
+ value: 'My SMS'
+ }
+ };
}));
describe('onResponse()', () => {
@@ -55,14 +60,13 @@ describe('Ticket', () => {
it('should return the characters remaining in a element', () => {
controller.$scope.message = {
input: {
- textLength: 50
- },
- maxlength: 150
+ value: 'My message 0€'
+ }
};
let result = controller.charactersRemaining();
- expect(result).toEqual(100);
+ expect(result).toEqual(145);
});
});
});
diff --git a/modules/ticket/front/sms/locale/es.yml b/modules/ticket/front/sms/locale/es.yml
index 4438e4fce4..64c3fcca67 100644
--- a/modules/ticket/front/sms/locale/es.yml
+++ b/modules/ticket/front/sms/locale/es.yml
@@ -4,4 +4,6 @@ Message: Mensaje
SMS sent!: ¡SMS enviado!
Characters remaining: Carácteres restantes
The destination can't be empty: El destinatario no puede estar vacio
-The message can't be empty: El mensaje no puede estar vacio
\ No newline at end of file
+The message can't be empty: El mensaje no puede estar vacio
+The message it's too long: El mensaje es demasiado largo
+Special characters like accents counts as a multiple: Carácteres especiales como los acentos cuentan como varios
\ No newline at end of file
diff --git a/modules/travel/back/methods/travel/specs/filter.spec.js b/modules/travel/back/methods/travel/specs/filter.spec.js
index f2fe44989d..03849f2b0e 100644
--- a/modules/travel/back/methods/travel/specs/filter.spec.js
+++ b/modules/travel/back/methods/travel/specs/filter.spec.js
@@ -23,7 +23,7 @@ describe('Travel filter()', () => {
let result = await app.models.Travel.filter(ctx);
- expect(result.length).toEqual(7);
+ expect(result.length).toEqual(8);
});
it('should return the travel matching "total entries"', async() => {
diff --git a/modules/travel/front/descriptor-popover/index.html b/modules/travel/front/descriptor-popover/index.html
new file mode 100644
index 0000000000..fc0fb0301d
--- /dev/null
+++ b/modules/travel/front/descriptor-popover/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/travel/front/descriptor-popover/index.js b/modules/travel/front/descriptor-popover/index.js
new file mode 100644
index 0000000000..cb13d7f068
--- /dev/null
+++ b/modules/travel/front/descriptor-popover/index.js
@@ -0,0 +1,88 @@
+import ngModule from '../module';
+import Component from 'core/lib/component';
+
+class Controller extends Component {
+ constructor($element, $scope, $http, $timeout, $q) {
+ super($element, $scope);
+ this.$timeout = $timeout;
+ this.$http = $http;
+ this.$q = $q;
+ this.travel = null;
+ this._quicklinks = {};
+ }
+
+ set travelId(travelId) {
+ if (travelId == this._travelId) return;
+
+ this._travelId = travelId;
+ this.travel = null;
+ this.loadData();
+ }
+
+ get travelId() {
+ return this._travelId;
+ }
+
+ get quicklinks() {
+ return this._quicklinks;
+ }
+
+ set quicklinks(value = {}) {
+ Object.keys(value).forEach(key => {
+ this._quicklinks[key] = value[key];
+ });
+ }
+
+ show() {
+ this.$.popover.parent = this.parent;
+ this.$.popover.show();
+ }
+
+ loadData() {
+ let query = `Travels/findOne`;
+ let filter = {
+ fields: [
+ 'id',
+ 'ref',
+ 'shipped',
+ 'landed',
+ 'totalEntries',
+ 'warehouseInFk',
+ 'warehouseOutFk'
+ ],
+ where: {
+ id: this._travelId
+ },
+ include: [
+ {
+ relation: 'warehouseIn',
+ scope: {
+ fields: ['name']
+ }
+ }, {
+ relation: 'warehouseOut',
+ scope: {
+ fields: ['name']
+ }
+ }
+ ]
+ };
+
+ this.$http.get(query, {params: {filter}}).then(res => {
+ this.travel = res.data;
+ this.$.$applyAsync(() => {
+ this.$.popover.relocate();
+ });
+ });
+ }
+}
+Controller.$inject = ['$element', '$scope', '$http', '$timeout', '$q'];
+
+ngModule.component('vnTravelDescriptorPopover', {
+ template: require('./index.html'),
+ controller: Controller,
+ bindings: {
+ travelId: '<',
+ quicklinks: '<'
+ }
+});
diff --git a/modules/travel/front/descriptor-popover/index.spec.js b/modules/travel/front/descriptor-popover/index.spec.js
new file mode 100644
index 0000000000..12ad364bf4
--- /dev/null
+++ b/modules/travel/front/descriptor-popover/index.spec.js
@@ -0,0 +1,100 @@
+import './index.js';
+
+describe('travel Component vnTravelDescriptorPopover', () => {
+ let $httpBackend;
+ let $httpParamSerializer;
+ let $scope;
+ let controller;
+ let $element;
+
+ beforeEach(ngModule('travel'));
+
+ beforeEach(angular.mock.inject(($componentController, $rootScope, _$httpBackend_, _$httpParamSerializer_) => {
+ $httpBackend = _$httpBackend_;
+ $httpParamSerializer = _$httpParamSerializer_;
+ $element = angular.element(``);
+ $scope = $rootScope.$new();
+ $scope.popover = {relocate: () => {}, show: () => {}};
+ controller = $componentController('vnTravelDescriptorPopover', {$scope, $element});
+ }));
+
+ describe('travelId()', () => {
+ it(`should not apply any changes if the received id is the same stored in _travelId`, () => {
+ controller.travel = 'I exist!';
+ controller._travelId = 1;
+ spyOn(controller, 'loadData');
+ controller.travelId = 1;
+
+ expect(controller.travel).toEqual('I exist!');
+ expect(controller._travelId).toEqual(1);
+ expect(controller.loadData).not.toHaveBeenCalled();
+ });
+
+ it(`should set the received id into _travelId, set the travel to null and then call loadData()`, () => {
+ controller.travel = `Please don't`;
+ controller._travelId = 1;
+ spyOn(controller, 'loadData');
+ controller.travelId = 999;
+
+ expect(controller.travel).toBeNull();
+ expect(controller._travelId).toEqual(999);
+ expect(controller.loadData).toHaveBeenCalledWith();
+ });
+ });
+
+ describe('show()', () => {
+ it(`should call the show()`, () => {
+ spyOn(controller.$.popover, 'show');
+ controller.show();
+
+ expect(controller.$.popover.show).toHaveBeenCalledWith();
+ });
+ });
+
+ describe('loadData()', () => {
+ it(`should perform a get query to store the worker data into the controller`, () => {
+ controller.travelId = 1;
+ controller.canceler = null;
+ let response = {};
+
+ let config = {
+ filter: {
+ fields: [
+ 'id',
+ 'ref',
+ 'shipped',
+ 'landed',
+ 'totalEntries',
+ 'warehouseInFk',
+ 'warehouseOutFk'
+ ],
+ where: {
+ id: controller.travelId
+ },
+ include: [
+ {
+ relation: 'warehouseIn',
+ scope: {
+ fields: ['name']
+ }
+ }, {
+ relation: 'warehouseOut',
+ scope: {
+ fields: ['name']
+ }
+ }
+ ]
+ }
+ };
+
+ let json = $httpParamSerializer(config);
+
+ $httpBackend.whenGET(`Travels/findOne?${json}`).respond(response);
+ $httpBackend.expectGET(`Travels/findOne?${json}`);
+ controller.loadData();
+ $httpBackend.flush();
+
+ expect(controller.travel).toEqual(response);
+ });
+ });
+});
diff --git a/modules/travel/front/index.js b/modules/travel/front/index.js
index 1f5346e987..b72f9fd51c 100644
--- a/modules/travel/front/index.js
+++ b/modules/travel/front/index.js
@@ -11,4 +11,4 @@ import './log';
import './create';
import './thermograph/index/';
import './thermograph/create/';
-
+import './descriptor-popover';
diff --git a/modules/worker/front/descriptor-popover/index.js b/modules/worker/front/descriptor-popover/index.js
index b648e8bd20..55843a67da 100644
--- a/modules/worker/front/descriptor-popover/index.js
+++ b/modules/worker/front/descriptor-popover/index.js
@@ -1,6 +1,5 @@
import ngModule from '../module';
import Component from 'core/lib/component';
-import './style.scss';
class Controller extends Component {
constructor($element, $scope, $http, $timeout, $q) {
diff --git a/modules/worker/front/descriptor-popover/style.scss b/modules/worker/front/descriptor-popover/style.scss
deleted file mode 100644
index 58e65d3206..0000000000
--- a/modules/worker/front/descriptor-popover/style.scss
+++ /dev/null
@@ -1,11 +0,0 @@
-vn-ticket-descriptor-popover {
- vn-ticket-descriptor {
- display: block;
- width: 16em;
- max-height: 28em;
-
- & > vn-card {
- margin: 0!important;
- }
- }
-}
\ No newline at end of file