diff --git a/back/methods/chat/sendQueued.js b/back/methods/chat/sendQueued.js index c34642c7e..cf80817e5 100644 --- a/back/methods/chat/sendQueued.js +++ b/back/methods/chat/sendQueued.js @@ -10,7 +10,7 @@ module.exports = Self => { }, http: { path: `/sendQueued`, - verb: 'POST' + verb: 'GET' } }); diff --git a/back/methods/dms/deleteTrashFiles.js b/back/methods/dms/deleteTrashFiles.js index 9d16e9d81..7cfb9f8d1 100644 --- a/back/methods/dms/deleteTrashFiles.js +++ b/back/methods/dms/deleteTrashFiles.js @@ -1,3 +1,4 @@ +const UserError = require('vn-loopback/util/user-error'); const fs = require('fs-extra'); const path = require('path'); @@ -11,11 +12,11 @@ module.exports = Self => { }, http: { path: `/deleteTrashFiles`, - verb: 'POST' + verb: 'GET' } }); - Self.deleteTrashFiles = async(options) => { + Self.deleteTrashFiles = async options => { const tx = await Self.beginTransaction({}); const myOptions = {}; @@ -26,6 +27,9 @@ module.exports = Self => { myOptions.transaction = tx; try { + if (process.env.NODE_ENV == 'test') + throw new UserError(`Action not allowed on the test environment`); + const models = Self.app.models; const DmsContainer = models.DmsContainer; @@ -33,9 +37,15 @@ module.exports = Self => { where: {code: 'trash'} }, myOptions); + const date = new Date(); + date.setMonth(date.getMonth() - 4); + const dmsToDelete = await models.Dms.find({ where: { - dmsTypeFk: trashDmsType.id + and: [ + {dmsTypeFk: trashDmsType.id}, + {created: {lt: date}} + ] } }, myOptions); @@ -43,14 +53,19 @@ module.exports = Self => { const pathHash = DmsContainer.getHash(dms.id); const dmsContainer = await DmsContainer.container(pathHash); const dstFile = path.join(dmsContainer.client.root, pathHash, dms.file); + const dstFolder = path.join(dmsContainer.client.root, pathHash); await fs.unlink(dstFile); - await dms.destroy(myOptions); + try { + await fs.rmdir(dstFolder); + await dms.destroy(myOptions); + } catch (err) { + await dms.destroy(myOptions); + } } if (tx) await tx.commit(); - } catch (e) { if (tx) await tx.rollback(); - + throw e; } }; diff --git a/db/changes/10470-family/00-accountingType.sql b/db/changes/10470-family/00-accountingType.sql index f3c092a34..964027e3a 100644 --- a/db/changes/10470-family/00-accountingType.sql +++ b/db/changes/10470-family/00-accountingType.sql @@ -1,2 +1,3 @@ ALTER TABLE `vn`.`accountingType` ADD daysInFuture INT NULL; -ALTER TABLE `vn`.`accountingType` MODIFY COLUMN daysInFuture int(11) DEFAULT 0 NULL; \ No newline at end of file +ALTER TABLE `vn`.`accountingType` MODIFY COLUMN daysInFuture int(11) DEFAULT 0 NULL; +UPDATE `vn`.`accountingType` SET daysInFuture=1 WHERE id=8; \ No newline at end of file diff --git a/db/changes/10471-family/00-chat.sql b/db/changes/10471-family/00-chat.sql new file mode 100644 index 000000000..6f3c9d437 --- /dev/null +++ b/db/changes/10471-family/00-chat.sql @@ -0,0 +1,3 @@ +ALTER TABLE `vn`.`chat` MODIFY COLUMN message TEXT CHARACTER SET utf8mb3 COLLATE utf8mb3_unicode_ci DEFAULT NULL NULL; +ALTER TABLE `vn`.`chat` MODIFY COLUMN dated DATETIME DEFAULT NULL NULL; +ALTER TABLE `vn`.`chat` ADD error TEXT NULL; diff --git a/db/changes/10472-family/00-creditInsurance.sql b/db/changes/10472-family/00-creditInsurance.sql new file mode 100644 index 000000000..4731cfb2a --- /dev/null +++ b/db/changes/10472-family/00-creditInsurance.sql @@ -0,0 +1,3 @@ +ALTER TABLE `vn`.`creditInsurance` + ADD CONSTRAINT `creditInsurance_creditClassificationFk` FOREIGN KEY (`creditClassificationFk`) + REFERENCES `vn`.`creditClassification` (`id`) ON DELETE CASCADE ON UPDATE CASCADE; \ No newline at end of file diff --git a/db/changes/10480-june/00-aclZoneExclusionGeos.sql b/db/changes/10480-june/00-aclZoneExclusionGeos.sql new file mode 100644 index 000000000..4c0f6c991 --- /dev/null +++ b/db/changes/10480-june/00-aclZoneExclusionGeos.sql @@ -0,0 +1,4 @@ +INSERT INTO `salix`.`ACL`(`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) + VALUES + ('ZoneExclusionGeo', '*', 'READ', 'ALLOW', 'ROLE', 'employee'), + ('ZoneExclusionGeo', '*', 'WRITE', 'ALLOW', 'ROLE', 'deliveryBoss'); \ No newline at end of file diff --git a/db/changes/10480-june/00-albaran_gestdoc.sql b/db/changes/10480-june/00-albaran_gestdoc.sql new file mode 100644 index 000000000..a0ba93bd3 --- /dev/null +++ b/db/changes/10480-june/00-albaran_gestdoc.sql @@ -0,0 +1,2 @@ +ALTER TABLE `vn2008`.`albaran_gestdoc` DROP FOREIGN KEY fk_albaran_gestdoc_gestdoc1; +ALTER TABLE `vn2008`.`albaran_gestdoc` ADD CONSTRAINT albaran_gestdoc_FK FOREIGN KEY (gestdoc_id) REFERENCES `vn`.`dms`(id) ON DELETE CASCADE ON UPDATE CASCADE; \ No newline at end of file diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 265968ec0..db60210bd 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -1351,7 +1351,7 @@ INSERT INTO `vn`.`travel`(`id`,`shipped`, `landed`, `warehouseInFk`, `warehouseO (7, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 5, 4, 1, 50.00, 500, 'seventh travel', 2, 1), (8, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 5, 1, 1, 50.00, 500, 'eight travel', 1, 2); -INSERT INTO `vn`.`entry`(`id`, `supplierFk`, `created`, `travelFk`, `isConfirmed`, `companyFk`, `ref`,`isInventory`, `isRaid`, `notes`, `evaNotes`) +INSERT INTO `vn`.`entry`(`id`, `supplierFk`, `created`, `travelFk`, `isConfirmed`, `companyFk`, `ref`,`isExcludedFromAvailable`, `isRaid`, `notes`, `evaNotes`) VALUES (1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1, 1, 442, 'Movement 1', 0, 0, '', ''), (2, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 2, 0, 442, 'Movement 2', 0, 0, 'this is the note two', 'observation two'), @@ -2582,6 +2582,15 @@ INSERT INTO `vn`.`machineWorker` (`workerFk`, `machineFk`, `inTimed`, `outTimed` (1106, 2, util.VN_CURDATE(), NULL), (1106, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL +1 DAY)); +INSERT INTO `vn`.`zoneExclusion` (`id`, `zoneFk`, `dated`, `created`, `userFk`) +VALUES + (1, 1, DATE_ADD(CURDATE(), INTERVAL (IF(DAYOFWEEK(CURDATE())<=7, 7, 14) - DAYOFWEEK(CURDATE())) DAY), CURDATE(), 100), + (2, 1, DATE_ADD(CURDATE(), INTERVAL (IF(DAYOFWEEK(CURDATE())<=8, 8, 15) - DAYOFWEEK(CURDATE())) DAY), CURDATE(), 100); + +INSERT INTO `vn`.`zoneExclusionGeo` (`zoneExclusionFk`, `geoFk`) + VALUES + (2, 1); + INSERT INTO `vn`.`mdbBranch` (`name`) VALUES ('test'), @@ -2614,4 +2623,4 @@ INSERT INTO `vn`.`workerTimeControlConfig` (`id`, `dayBreak`, `dayBreakDriver`, INSERT INTO `vn`.`routeConfig` (`id`, `defaultWorkCenterFk`) VALUES - (1, 9); \ No newline at end of file + (1, 9); diff --git a/db/dump/structure.sql b/db/dump/structure.sql index 719ec8fea..da7e77124 100644 --- a/db/dump/structure.sql +++ b/db/dump/structure.sql @@ -23,6 +23,7 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `account` /*!40100 DEFAULT CHARACTER SE USE `account`; + -- -- Table structure for table `account` -- @@ -7388,7 +7389,7 @@ proc: BEGIN JOIN vn.warehouse w ON w.id = t.warehouseInFk WHERE t.landed BETWEEN vInventoryDate AND vStartDate AND t.warehouseInFk = vWarehouse - AND NOT e.isInventory + AND NOT e.isExcludedFromAvailable GROUP BY b.itemFk ) c JOIN vn.item i ON i.id = c.item_id @@ -27101,7 +27102,7 @@ CREATE TABLE `entry` ( `dated` datetime NOT NULL, `ref` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL, `isBooked` tinyint(1) NOT NULL DEFAULT '0', - `isInventory` tinyint(1) NOT NULL DEFAULT '0', + `isExcludedFromAvailable` tinyint(1) NOT NULL DEFAULT 0, `notes` longtext COLLATE utf8_unicode_ci, `isConfirmed` tinyint(1) NOT NULL DEFAULT '0', `isOrdered` tinyint(1) NOT NULL DEFAULT '0', @@ -59607,7 +59608,7 @@ BEGIN WHERE tr.landed >= vDateInventory AND vWarehouse = tr.warehouseInFk AND b.itemFk = vItemId - AND e.isInventory = FALSE + AND e.isExcludedFromAvailable = FALSE AND e.isRaid = FALSE UNION ALL @@ -59642,7 +59643,7 @@ BEGIN AND vWarehouse =tr.warehouseOutFk AND s.id <> 4 AND b.itemFk = vItemId - AND e.isInventory = FALSE + AND e.isExcludedFromAvailable = FALSE AND w.isFeedStock = FALSE AND e.isRaid = FALSE UNION ALL @@ -59896,7 +59897,7 @@ BEGIN LEFT JOIN travel t ON t.id = e.travelFk WHERE t.landed BETWEEN vDatedFrom AND vDatedTo AND (vWarehouseFk IS NULL OR t.warehouseInFk = vWarehouseFk) - AND !e.isInventory + AND !e.isExcludedFromAvailable AND b.quantity != 0 AND (vItemFk IS NULL OR b.itemFk = vItemFk) UNION ALL @@ -59909,7 +59910,7 @@ BEGIN LEFT JOIN travel t ON t.id = e.travelFk WHERE t.shipped BETWEEN vDatedFrom AND vDatedTo AND (vWarehouseFk IS NULL OR t.warehouseOutFk = vWarehouseFk) - AND !e.isInventory + AND !e.isExcludedFromAvailable AND b.quantity != 0 AND (vItemFk IS NULL OR b.itemFk = vItemFk) AND !e.isRaid @@ -68727,7 +68728,7 @@ BEGIN * Devuelve los tickets y la cantidad de lineas de venta que se pueden adelantar. * * @param vDated Fecha de los tickets que se quieren adelantar. - * @param vWarehouseFk Almacén + * @param vWarehouseFk AlmacénitemEntryIn */ DECLARE vDateInventory DATE; DECLARE vDateToAdvance DATE; @@ -79992,7 +79993,7 @@ USE `vn`; /*!50001 SET collation_connection = utf8mb4_unicode_ci */; /*!50001 CREATE ALGORITHM=UNDEFINED */ /*!50013 DEFINER=`root`@`localhost` SQL SECURITY DEFINER */ -/*!50001 VIEW `itemEntryIn` AS select `t`.`warehouseInFk` AS `warehouseInFk`,`t`.`landed` AS `landed`,`b`.`itemFk` AS `itemFk`,`b`.`quantity` AS `quantity`,`t`.`isReceived` AS `isReceived`,`e`.`isRaid` AS `isVirtualStock`,`e`.`id` AS `entryFk` from ((`buy` `b` join `entry` `e` on((`b`.`entryFk` = `e`.`id`))) join `travel` `t` on((`e`.`travelFk` = `t`.`id`))) where ((`e`.`isInventory` = 0) and (`b`.`quantity` <> 0)) */; +/*!50001 VIEW `itemEntryIn` AS select `t`.`warehouseInFk` AS `warehouseInFk`,`t`.`landed` AS `landed`,`b`.`itemFk` AS `itemFk`,`b`.`quantity` AS `quantity`,`t`.`isReceived` AS `isReceived`,`e`.`isRaid` AS `isVirtualStock`,`e`.`id` AS `entryFk` from ((`buy` `b` join `entry` `e` on((`b`.`entryFk` = `e`.`id`))) join `travel` `t` on((`e`.`travelFk` = `t`.`id`))) where ((`e`.`isExcludedFromAvailable` = 0) and (`b`.`quantity` <> 0)) */; /*!50001 SET character_set_client = @saved_cs_client */; /*!50001 SET character_set_results = @saved_cs_results */; /*!50001 SET collation_connection = @saved_col_connection */; @@ -80011,7 +80012,7 @@ USE `vn`; /*!50001 SET collation_connection = utf8mb4_unicode_ci */; /*!50001 CREATE ALGORITHM=UNDEFINED */ /*!50013 DEFINER=`root`@`localhost` SQL SECURITY DEFINER */ -/*!50001 VIEW `itemEntryOut` AS select `t`.`warehouseOutFk` AS `warehouseOutFk`,`t`.`shipped` AS `shipped`,`b`.`itemFk` AS `itemFk`,-(`b`.`quantity`) AS `quantity`,`t`.`isDelivered` AS `isDelivered`,`e`.`id` AS `entryFk` from ((`buy` `b` join `entry` `e` on((`b`.`entryFk` = `e`.`id`))) join `travel` `t` on((`e`.`travelFk` = `t`.`id`))) where ((`e`.`isInventory` = 0) and (`e`.`isRaid` = 0) and (`b`.`quantity` <> 0)) */; +/*!50001 VIEW `itemEntryOut` AS select `t`.`warehouseOutFk` AS `warehouseOutFk`,`t`.`shipped` AS `shipped`,`b`.`itemFk` AS `itemFk`,-(`b`.`quantity`) AS `quantity`,`t`.`isDelivered` AS `isDelivered`,`e`.`id` AS `entryFk` from ((`buy` `b` join `entry` `e` on((`b`.`entryFk` = `e`.`id`))) join `travel` `t` on((`e`.`travelFk` = `t`.`id`))) where ((`e`.`isExcludedFromAvailable` = 0) and (`e`.`isRaid` = 0) and (`b`.`quantity` <> 0)) */; /*!50001 SET character_set_client = @saved_cs_client */; /*!50001 SET character_set_results = @saved_cs_results */; /*!50001 SET collation_connection = @saved_col_connection */; diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js index e939838cb..37f7308a5 100644 --- a/e2e/helpers/selectors.js +++ b/e2e/helpers/selectors.js @@ -1102,7 +1102,7 @@ export default { company: 'vn-entry-basic-data vn-autocomplete[ng-model="$ctrl.entry.companyFk"]', ordered: 'vn-entry-basic-data vn-check[ng-model="$ctrl.entry.isOrdered"]', confirmed: 'vn-entry-basic-data vn-check[ng-model="$ctrl.entry.isConfirmed"]', - inventory: 'vn-entry-basic-data vn-check[ng-model="$ctrl.entry.isInventory"]', + inventory: 'vn-entry-basic-data vn-check[ng-model="$ctrl.entry.isExcludedFromAvailable"]', raid: 'vn-entry-basic-data vn-check[ng-model="$ctrl.entry.isRaid"]', booked: 'vn-entry-basic-data vn-check[ng-model="$ctrl.entry.isBooked"]', save: 'vn-entry-basic-data button[type=submit]', diff --git a/modules/entry/back/methods/entry/filter.js b/modules/entry/back/methods/entry/filter.js index 13690d3ac..1ba4166dc 100644 --- a/modules/entry/back/methods/entry/filter.js +++ b/modules/entry/back/methods/entry/filter.js @@ -156,7 +156,7 @@ module.exports = Self => { e.dated, e.ref, e.isBooked, - e.isInventory, + e.isExcludedFromAvailable, e.notes, e.evaNotes AS observation, e.isConfirmed, diff --git a/modules/entry/back/models/entry.json b/modules/entry/back/models/entry.json index d8bd079a2..c456859a5 100644 --- a/modules/entry/back/models/entry.json +++ b/modules/entry/back/models/entry.json @@ -24,7 +24,7 @@ "isBooked": { "type": "boolean" }, - "isInventory": { + "isExcludedFromAvailable": { "type": "boolean" }, "notes": { diff --git a/modules/entry/front/basic-data/index.html b/modules/entry/front/basic-data/index.html index a05630dd6..8787853a5 100644 --- a/modules/entry/front/basic-data/index.html +++ b/modules/entry/front/basic-data/index.html @@ -103,7 +103,7 @@ + ng-model="$ctrl.entry.isExcludedFromAvailable"> + ng-if="$ctrl.entry.isExcludedFromAvailable"> diff --git a/modules/entry/front/summary/index.html b/modules/entry/front/summary/index.html index a95b2f18a..3dd9a4be5 100644 --- a/modules/entry/front/summary/index.html +++ b/modules/entry/front/summary/index.html @@ -91,7 +91,7 @@ diff --git a/modules/item/back/methods/item-image-queue/downloadImages.js b/modules/item/back/methods/item-image-queue/downloadImages.js index 05b223598..ec8244f49 100644 --- a/modules/item/back/methods/item-image-queue/downloadImages.js +++ b/modules/item/back/methods/item-image-queue/downloadImages.js @@ -12,7 +12,7 @@ module.exports = Self => { }, http: { path: `/downloadImages`, - verb: 'POST' + verb: 'GET' } }); diff --git a/modules/zone/back/methods/zone/exclusionGeo.js b/modules/zone/back/methods/zone/exclusionGeo.js new file mode 100644 index 000000000..5026c58c5 --- /dev/null +++ b/modules/zone/back/methods/zone/exclusionGeo.js @@ -0,0 +1,64 @@ + +const UserError = require('vn-loopback/util/user-error'); + +module.exports = Self => { + Self.remoteMethod('exclusionGeo', { + description: 'Exclude a geo from a zone', + accepts: [ + { + arg: 'zoneFk', + type: 'number', + description: 'The zone id' + }, + { + arg: 'date', + type: 'date', + description: 'The date to exclude' + }, + { + arg: 'geoIds', + type: ['number'], + description: 'The geos id' + } + + ], + returns: { + type: 'object', + root: true + }, + http: { + path: `/exclusionGeo`, + verb: 'POST' + } + }); + + Self.exclusionGeo = async(zoneFk, date, geoIds, options) => { + const models = Self.app.models; + const myOptions = {}; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + if (!geoIds[0]) throw new UserError(`You must select a location`); + + const newZoneExclusion = await models.ZoneExclusion.create({ + zoneFk: zoneFk, + dated: date + }, myOptions); + + const promises = []; + + for (const geoId of geoIds) { + const newZoneExclusionGeo = await models.ZoneExclusionGeo.create({ + zoneExclusionFk: newZoneExclusion.id, + geoFk: geoId + }, myOptions); + + promises.push(newZoneExclusionGeo); + } + + const newZoneExclusionGeos = await Promise.all(promises); + + return newZoneExclusionGeos; + }; +}; diff --git a/modules/zone/back/methods/zone/getEventsFiltered.js b/modules/zone/back/methods/zone/getEventsFiltered.js index 316652fa3..b7875785d 100644 --- a/modules/zone/back/methods/zone/getEventsFiltered.js +++ b/modules/zone/back/methods/zone/getEventsFiltered.js @@ -56,12 +56,23 @@ module.exports = Self => { [zoneFk, started, ended, started, ended, started, ended, started, ended], myOptions); query = ` - SELECT * - FROM vn.zoneExclusion - WHERE zoneFk = ? - AND dated BETWEEN ? AND ?;`; + SELECT e.* + FROM vn.zoneExclusion e + LEFT JOIN vn.zoneExclusionGeo eg ON eg.zoneExclusionFk = e.id + WHERE e.zoneFk = ? + AND e.dated BETWEEN ? AND ? + AND eg.zoneExclusionFk IS NULL;`; const exclusions = await Self.rawSql(query, [zoneFk, started, ended], myOptions); - return {events, exclusions}; + query = ` + SELECT eg.*, e.zoneFk, e.dated, e.created, e.userFk + FROM vn.zoneExclusion e + LEFT JOIN vn.zoneExclusionGeo eg ON eg.zoneExclusionFk = e.id + WHERE e.zoneFk = ? + AND e.dated BETWEEN ? AND ? + AND eg.zoneExclusionFk IS NOT NULL;`; + const geoExclusions = await Self.rawSql(query, [zoneFk, started, ended], myOptions); + + return {events, exclusions, geoExclusions}; }; }; diff --git a/modules/zone/back/methods/zone/specs/exclusionGeo.spec.js b/modules/zone/back/methods/zone/specs/exclusionGeo.spec.js new file mode 100644 index 000000000..3a345f2ce --- /dev/null +++ b/modules/zone/back/methods/zone/specs/exclusionGeo.spec.js @@ -0,0 +1,41 @@ +const models = require('vn-loopback/server/server').models; + +describe('zone exclusionGeo()', () => { + const zoneId = 1; + const today = new Date(); + + it(`should show an error when location isn't selected`, async() => { + const tx = await models.Zone.beginTransaction({}); + + try { + const options = {transaction: tx}; + const geoIds = []; + + await models.Zone.exclusionGeo(zoneId, today, geoIds, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error.message).toContain(`You must select a location`); + }); + + it('should create two exclusion by geo', async() => { + const tx = await models.Zone.beginTransaction({}); + + try { + const options = {transaction: tx}; + const geoIds = [1, 2]; + const result = await models.Zone.exclusionGeo(zoneId, today, geoIds, options); + + expect(result.length).toEqual(2); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); +}); diff --git a/modules/zone/back/methods/zone/specs/updateExclusionGeo.spec.js b/modules/zone/back/methods/zone/specs/updateExclusionGeo.spec.js new file mode 100644 index 000000000..9db2e24be --- /dev/null +++ b/modules/zone/back/methods/zone/specs/updateExclusionGeo.spec.js @@ -0,0 +1,40 @@ +const models = require('vn-loopback/server/server').models; + +describe('zone updateExclusionGeo()', () => { + it(`should show an error when location isn't selected`, async() => { + const tx = await models.Zone.beginTransaction({}); + + try { + const options = {transaction: tx}; + const zoneId = 1; + const geoIds = []; + + await models.Zone.updateExclusionGeo(zoneId, geoIds, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error.message).toContain(`You must select a location`); + }); + + it('should delete all exclusion and then create two exclusion by geo for a zone', async() => { + const tx = await models.Zone.beginTransaction({}); + + try { + const options = {transaction: tx}; + const zoneId = 2; + const geoIds = [1, 2]; + const result = await models.Zone.updateExclusionGeo(zoneId, geoIds, options); + + expect(result.length).toEqual(2); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); +}); diff --git a/modules/zone/back/methods/zone/updateExclusionGeo.js b/modules/zone/back/methods/zone/updateExclusionGeo.js new file mode 100644 index 000000000..237e336e0 --- /dev/null +++ b/modules/zone/back/methods/zone/updateExclusionGeo.js @@ -0,0 +1,55 @@ +const UserError = require('vn-loopback/util/user-error'); + +module.exports = Self => { + Self.remoteMethod('updateExclusionGeo', { + description: 'Update the geos excluded from a zone', + accepts: [ + { + arg: 'zoneExclusionFk', + type: 'number', + description: 'The zoneExclusion id' + }, + { + arg: 'geoIds', + type: ['number'], + description: 'The geos id' + } + + ], + returns: { + type: 'object', + root: true + }, + http: { + path: `/updateExclusionGeo`, + verb: 'POST' + } + }); + + Self.updateExclusionGeo = async(zoneExclusionFk, geoIds, options) => { + const models = Self.app.models; + const myOptions = {}; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + if (!geoIds[0]) throw new UserError(`You must select a location`); + + await models.ZoneExclusionGeo.destroyAll({ + zoneExclusionFk: zoneExclusionFk + }, myOptions); + + const promises = []; + + for (const geoId of geoIds) { + const params = { + zoneExclusionFk: zoneExclusionFk, + geoFk: geoId + }; + const deletedZoneExclusionGeos = models.ZoneExclusionGeo.create(params, myOptions); + promises.push(deletedZoneExclusionGeos); + } + + return Promise.all(promises); + }; +}; diff --git a/modules/zone/back/model-config.json b/modules/zone/back/model-config.json index ee555f3f4..261a89902 100644 --- a/modules/zone/back/model-config.json +++ b/modules/zone/back/model-config.json @@ -23,6 +23,9 @@ "ZoneExclusion": { "dataSource": "vn" }, + "ZoneExclusionGeo": { + "dataSource": "vn" + }, "ZoneGeo": { "dataSource": "vn" }, diff --git a/modules/zone/back/models/zone-exclusion-geo.json b/modules/zone/back/models/zone-exclusion-geo.json new file mode 100644 index 000000000..816e4b650 --- /dev/null +++ b/modules/zone/back/models/zone-exclusion-geo.json @@ -0,0 +1,21 @@ +{ + "name": "ZoneExclusionGeo", + "base": "VnModel", + "options": { + "mysql": { + "table": "zoneExclusionGeo" + } + }, + "properties": { + "id": { + "id": true, + "type": "number" + }, + "zoneExclusionFk": { + "type": "number" + }, + "geoFk": { + "type": "number" + } + } +} \ No newline at end of file diff --git a/modules/zone/back/models/zone.js b/modules/zone/back/models/zone.js index ef1c8c5d9..6d5a6cdca 100644 --- a/modules/zone/back/models/zone.js +++ b/modules/zone/back/models/zone.js @@ -8,6 +8,8 @@ module.exports = Self => { require('../methods/zone/deleteZone')(Self); require('../methods/zone/includingExpired')(Self); require('../methods/zone/getZoneClosing')(Self); + require('../methods/zone/exclusionGeo')(Self); + require('../methods/zone/updateExclusionGeo')(Self); Self.validatesPresenceOf('agencyModeFk', { message: `Agency cannot be blank` diff --git a/modules/zone/front/calendar/index.js b/modules/zone/front/calendar/index.js index a24d10aef..3bc7158ef 100644 --- a/modules/zone/front/calendar/index.js +++ b/modules/zone/front/calendar/index.js @@ -75,6 +75,17 @@ class Controller extends Component { } } + this.geoExclusions = {}; + let geoExclusions = value.geoExclusions; + + if (geoExclusions) { + for (let geoExclusion of geoExclusions) { + let stamp = toStamp(geoExclusion.dated); + if (!this.geoExclusions[stamp]) this.geoExclusions[stamp] = []; + this.geoExclusions[stamp].push(geoExclusion); + } + } + let events = value.events; if (events) { @@ -135,11 +146,13 @@ class Controller extends Component { onSelection($event, $days, $type, $weekday) { let $events = []; let $exclusions = []; + let $geoExclusions = []; for (let day of $days) { let stamp = day.getTime(); $events = $events.concat(this.days[stamp] || []); $exclusions = $exclusions.concat(this.exclusions[stamp] || []); + $geoExclusions = $geoExclusions.concat(this.geoExclusions[stamp] || []); } this.emit('selection', { @@ -148,19 +161,23 @@ class Controller extends Component { $type, $weekday, $events, - $exclusions + $exclusions, + $geoExclusions }); } hasEvents(day) { let stamp = day.getTime(); - return this.days[stamp] || this.exclusions[stamp]; + return this.days[stamp] || this.exclusions[stamp] || this.geoExclusions[stamp]; } getClass(day) { let stamp = day.getTime(); - return this.exclusions[stamp] && !this.days[stamp] - ? 'excluded' : ''; + if (this.geoExclusions[stamp]) + return 'geoExcluded'; + else if (this.exclusions[stamp]) + return 'excluded'; + else return ''; } } Controller.$inject = ['$element', '$scope', 'vnWeekDays']; diff --git a/modules/zone/front/calendar/index.spec.js b/modules/zone/front/calendar/index.spec.js index be002925e..338f47917 100644 --- a/modules/zone/front/calendar/index.spec.js +++ b/modules/zone/front/calendar/index.spec.js @@ -15,6 +15,7 @@ describe('component vnZoneCalendar', () => { controller.zone = {id: 1}; controller.days = []; controller.exclusions = []; + controller.geoExclusions = []; })); describe('date() setter', () => { @@ -57,7 +58,7 @@ describe('component vnZoneCalendar', () => { }); describe('data() setter', () => { - it('should set the events and exclusions and then call the refreshEvents() method', () => { + it('should set the events, exclusions and geoExclusions and then call the refreshEvents() method', () => { jest.spyOn(controller, 'refreshEvents').mockReturnThis(); controller.data = { @@ -66,13 +67,17 @@ describe('component vnZoneCalendar', () => { }], events: [{ dated: new Date() - }] + }], + geoExclusions: [{ + dated: new Date() + }], }; expect(controller.refreshEvents).toHaveBeenCalledWith(); expect(controller.events).toBeDefined(); expect(controller.events.length).toEqual(1); expect(controller.exclusions).toBeDefined(); + expect(controller.geoExclusions).toBeDefined(); expect(Object.keys(controller.exclusions).length).toEqual(1); }); }); @@ -122,7 +127,8 @@ describe('component vnZoneCalendar', () => { $events: [], $exclusions: [], $type: 'day', - $weekday: 1 + $weekday: 1, + $geoExclusions: [], } ); }); @@ -151,5 +157,16 @@ describe('component vnZoneCalendar', () => { expect(result).toEqual('excluded'); }); + + it('should return the className "geoExcluded" for a date with geo excluded', () => { + const dated = new Date(); + + controller.geoExclusions = []; + controller.geoExclusions[dated.getTime()] = true; + + const result = controller.getClass(dated); + + expect(result).toEqual('geoExcluded'); + }); }); }); diff --git a/modules/zone/front/calendar/style.scss b/modules/zone/front/calendar/style.scss index 25b6a87d1..38491af58 100644 --- a/modules/zone/front/calendar/style.scss +++ b/modules/zone/front/calendar/style.scss @@ -33,6 +33,9 @@ vn-zone-calendar { &.excluded .day-number { background-color: $color-alert; } + &.geoExcluded .day-number { + background-color: $color-main; + } } } } diff --git a/modules/zone/front/events/index.html b/modules/zone/front/events/index.html index e71a1ae26..46ba87dea 100644 --- a/modules/zone/front/events/index.html +++ b/modules/zone/front/events/index.html @@ -2,7 +2,7 @@ id="calendar" vn-id="calendar" data="data" - on-selection="$ctrl.onSelection($days, $type, $weekday, $events, $exclusions)" + on-selection="$ctrl.onSelection($days, $type, $weekday, $events, $exclusions, $geoExclusions)" on-step="$ctrl.refresh()" class="vn-w-md"> @@ -98,7 +98,7 @@ fixed-bottom-right> @@ -198,3 +198,80 @@ message="This item will be deleted" question="Are you sure you want to continue?"> + + + + + + + + + + + + + +
+ + + + + +
+ + + + +
+
+
+
+ + + + + + + +
diff --git a/modules/zone/front/events/index.js b/modules/zone/front/events/index.js index 0df16a42a..b86330126 100644 --- a/modules/zone/front/events/index.js +++ b/modules/zone/front/events/index.js @@ -1,5 +1,6 @@ import ngModule from '../module'; import Section from 'salix/components/section'; +import './style.scss'; class Controller extends Section { constructor($element, $, vnWeekDays) { @@ -20,6 +21,16 @@ class Controller extends Section { return `Zones/${this.$params.id}/exclusions`; } + get checked() { + const geos = this.$.model.data || []; + const checkedLines = []; + for (let geo of geos) { + if (geo.checked) + checkedLines.push(geo); + } + return checkedLines; + } + refresh() { this.$.data = null; this.$.$applyAsync(() => { @@ -48,33 +59,56 @@ class Controller extends Section { : this.$t('Everyday'); } - onSelection(days, type, weekday, events, exclusions) { + onSelection(days, type, weekday, events, exclusions, exclusionGeos) { if (this.editMode == 'include') { if (events.length) - this.edit(events[0]); - else - this.create(type, days, weekday); - } else { - if (exclusions.length) - this.exclusionDelete(exclusions); - else - this.exclusionCreate(days); + return this.editInclusion(events[0]); + return this.createInclusion(type, days, weekday); + } else if (this.editMode == 'exclude') { + if (exclusions.length || exclusionGeos.length) + return this.editExclusion(exclusions[0] || {}, exclusionGeos); + return this.createExclusion(days); } } + editExclusion(exclusion, exclusionGeos) { + this.isNew = false; + this.excludeSelected = angular.copy(exclusion); + this.excludeSelected.type = exclusionGeos.length ? + 'specificLocations' : 'all'; + + this.exclusionGeos = new Set(); + if (exclusionGeos.length) { + this.excludeSelected.id = exclusionGeos[0].zoneExclusionFk; + exclusionGeos.forEach(x => this.exclusionGeos.add(x.geoFk)); + } + + this.$.excludeDialog.show(); + } + + createExclusion(days) { + this.isNew = true; + this.excludeSelected = { + type: 'all', + dated: days[0] + }; + this.exclusionGeos = new Set(); + this.$.excludeDialog.show(); + } + onEditClick(row, event) { if (event.defaultPrevented) return; - this.edit(row); + this.editInclusion(row); } - edit(row) { + editInclusion(row) { this.isNew = false; this.selected = angular.copy(row); this.selected.wdays = this.vnWeekDays.fromSet(row.weekDays); - this.$.dialog.show(); + this.$.includeDialog.show(); } - create(type, days, weekday) { + createInclusion(type, days, weekday) { this.isNew = true; if (type == 'weekday') { @@ -92,7 +126,7 @@ class Controller extends Section { }; } - this.$.dialog.show(); + this.$.includeDialog.show(); } onIncludeResponse(response) { @@ -132,6 +166,19 @@ class Controller extends Section { } } + onExcludeResponse(response) { + const type = this.excludeSelected.type; + switch (response) { + case 'accept': { + if (type == 'all') + return this.exclusionCreate(); + return this.exclusionGeoCreate(); + } + case 'delete': + return this.exclusionDelete(this.excludeSelected); + } + } + onDeleteClick(id, event) { if (event.defaultPrevented) return; event.preventDefault(); @@ -149,31 +196,121 @@ class Controller extends Section { .then(() => this.refresh()); } - exclusionCreate(days) { - let exclusions = days.map(dated => { - return {dated}; - }); + exclusionCreate() { + const excludeSelected = this.excludeSelected; + const dated = excludeSelected.dated; + let req; - this.$http.post(this.exclusionsPath, exclusions) + if (this.isNew) + req = this.$http.post(this.exclusionsPath, [{dated}]); + if (!this.isNew) + req = this.$http.put(`${this.exclusionsPath}/${excludeSelected.id}`, {dated}); + + return req.then(() => { + this.refresh(); + }); + } + + exclusionGeoCreate() { + const excludeSelected = this.excludeSelected; + let req; + const geoIds = []; + this.exclusionGeos.forEach(id => geoIds.push(id)); + + if (this.isNew) { + const params = { + zoneFk: parseInt(this.$params.id), + date: excludeSelected.dated, + geoIds + }; + req = this.$http.post(`Zones/exclusionGeo`, params); + } else { + const params = { + zoneExclusionFk: this.excludeSelected.id, + geoIds + }; + req = this.$http.post(`Zones/updateExclusionGeo`, params); + } + return req.then(() => this.refresh()); + } + + exclusionDelete(exclusion) { + const path = `${this.exclusionsPath}/${exclusion.id}`; + return this.$http.delete(path) .then(() => this.refresh()); } - exclusionDelete(exclusions) { - let reqs = []; + set excludeSearch(value) { + this._excludeSearch = value; + if (!value) this.onSearch(); + } - for (let exclusion of exclusions) { - if (!exclusion.id) continue; - let path = `${this.exclusionsPath}/${exclusion.id}`; - reqs.push(this.$http.delete(path)); + get excludeSearch() { + return this._excludeSearch; + } + + onKeyDown(event) { + if (event.key == 'Enter') { + event.preventDefault(); + this.onSearch(); + } + } + + onSearch() { + const params = {search: this._excludeSearch}; + if (this.excludeSelected.type == 'specificLocations') { + this.$.model.applyFilter({}, params).then(() => { + const data = this.$.model.data; + this.getChecked(data); + this.$.treeview.data = data; + }); + } + } + + onFetch(item) { + const params = item ? {parentId: item.id} : null; + return this.$.model.applyFilter({}, params).then(() => { + const data = this.$.model.data; + this.getChecked(data); + return data; + }); + } + + onSort(a, b) { + if (b.selected !== a.selected) { + if (a.selected == null) + return 1; + if (b.selected == null) + return -1; + return b.selected - a.selected; } - this.$q.all(reqs) - .then(() => this.refresh()); + return a.name.localeCompare(b.name); + } + + getChecked(data) { + for (let geo of data) { + geo.checked = this.exclusionGeos.has(geo.id); + if (geo.childs) this.getChecked(geo.childs); + } + } + + onItemCheck(geoId, checked) { + if (checked) + this.exclusionGeos.add(geoId); + else + this.exclusionGeos.delete(geoId); } } Controller.$inject = ['$element', '$scope', 'vnWeekDays']; ngModule.vnComponent('vnZoneEvents', { template: require('./index.html'), - controller: Controller + controller: Controller, + bindings: { + zone: '<' + }, + require: { + card: '^vnZoneCard' + } }); diff --git a/modules/zone/front/events/index.spec.js b/modules/zone/front/events/index.spec.js index ed2c91c31..b4ff800d6 100644 --- a/modules/zone/front/events/index.spec.js +++ b/modules/zone/front/events/index.spec.js @@ -1,4 +1,5 @@ import './index'; +import crudModel from 'core/mocks/crud-model'; describe('component vnZoneEvents', () => { let $scope; @@ -34,7 +35,8 @@ describe('component vnZoneEvents', () => { const query = `Zones/getEventsFiltered?ended=${date}&started=${date}&zoneFk=${params.zoneFk}`; const response = { events: 'myEvents', - exclusions: 'myExclusions' + exclusions: 'myExclusions', + geoExclusions: 'myGeoExclusions', }; $httpBackend.whenGET(query).respond(response); controller.refresh(); @@ -48,71 +50,129 @@ describe('component vnZoneEvents', () => { }); describe('onSelection()', () => { - it('should call the edit() method', () => { - jest.spyOn(controller, 'edit').mockReturnThis(); + it('should call the editInclusion() method', () => { + jest.spyOn(controller, 'editInclusion').mockReturnThis(); const weekday = {}; const days = []; const type = 'EventType'; const events = [{name: 'Event'}]; const exclusions = []; + const exclusionsGeo = []; controller.editMode = 'include'; - controller.onSelection(days, type, weekday, events, exclusions); + controller.onSelection(days, type, weekday, events, exclusions, exclusionsGeo); - expect(controller.edit).toHaveBeenCalledWith({name: 'Event'}); + expect(controller.editInclusion).toHaveBeenCalledWith({name: 'Event'}); }); - it('should call the create() method', () => { - jest.spyOn(controller, 'create').mockReturnThis(); + it('should call the createInclusion() method', () => { + jest.spyOn(controller, 'createInclusion').mockReturnThis(); const weekday = {dated: new Date()}; const days = [weekday]; const type = 'EventType'; const events = []; const exclusions = []; + const exclusionsGeo = []; controller.editMode = 'include'; - controller.onSelection(days, type, weekday, events, exclusions); + controller.onSelection(days, type, weekday, events, exclusions, exclusionsGeo); - expect(controller.create).toHaveBeenCalledWith(type, days, weekday); + expect(controller.createInclusion).toHaveBeenCalledWith(type, days, weekday); }); - it('should call the exclusionDelete() method', () => { - jest.spyOn(controller, 'exclusionDelete').mockReturnThis(); + it('should call the editExclusion() method with exclusions', () => { + jest.spyOn(controller, 'editExclusion').mockReturnThis(); const weekday = {}; const days = []; const type = 'EventType'; const events = []; - const exclusions = [{id: 1}]; - controller.editMode = 'delete'; - controller.onSelection(days, type, weekday, events, exclusions); + const exclusions = [{name: 'Exclusion'}]; + const exclusionsGeo = []; + controller.editMode = 'exclude'; + controller.onSelection(days, type, weekday, events, exclusions, exclusionsGeo); - expect(controller.exclusionDelete).toHaveBeenCalledWith(exclusions); + expect(controller.editExclusion).toHaveBeenCalled(); }); - it('should call the exclusionCreate() method', () => { - jest.spyOn(controller, 'exclusionCreate').mockReturnThis(); + it('should call the editExclusion() method with exclusionsGeo', () => { + jest.spyOn(controller, 'editExclusion').mockReturnThis(); + + const weekday = {}; + const days = []; + const type = 'EventType'; + const events = []; + const exclusions = []; + const exclusionsGeo = [{name: 'GeoExclusion'}]; + controller.editMode = 'exclude'; + controller.onSelection(days, type, weekday, events, exclusions, exclusionsGeo); + + expect(controller.editExclusion).toHaveBeenCalled(); + }); + + it('should call the createExclusion() method', () => { + jest.spyOn(controller, 'createExclusion').mockReturnThis(); const weekday = {}; const days = [{dated: new Date()}]; const type = 'EventType'; const events = []; const exclusions = []; - controller.editMode = 'delete'; - controller.onSelection(days, type, weekday, events, exclusions); + const exclusionsGeo = []; + controller.editMode = 'exclude'; + controller.onSelection(days, type, weekday, events, exclusions, exclusionsGeo); - expect(controller.exclusionCreate).toHaveBeenCalledWith(days); + expect(controller.createExclusion).toHaveBeenCalledWith(days); }); }); - describe('create()', () => { - it('shoud set the selected property and then call the dialog show() method', () => { - controller.$.dialog = {show: jest.fn()}; + describe('editExclusion()', () => { + it('shoud set the excludeSelected.type = "specificLocations" and then call the excludeDialog show() method', () => { + controller.$.excludeDialog = {show: jest.fn()}; + + const exclusionGeos = [{id: 1}]; + const exclusions = []; + + controller.editExclusion(exclusions, exclusionGeos); + + expect(controller.excludeSelected.type).toEqual('specificLocations'); + expect(controller.$.excludeDialog.show).toHaveBeenCalledWith(); + }); + + it('shoud set the excludeSelected.type = "all" and then call the excludeDialog show() method', () => { + controller.$.excludeDialog = {show: jest.fn()}; + + const exclusionGeos = []; + const exclusions = [{id: 1}]; + + controller.editExclusion(exclusions, exclusionGeos); + + expect(controller.excludeSelected.type).toEqual('all'); + expect(controller.$.excludeDialog.show).toHaveBeenCalledWith(); + }); + }); + + describe('createExclusion()', () => { + it('shoud set the excludeSelected property and then call the excludeDialog show() method', () => { + controller.$.excludeDialog = {show: jest.fn()}; + + const days = [new Date()]; + controller.createExclusion(days); + + expect(controller.excludeSelected).toBeDefined(); + expect(controller.isNew).toBeTruthy(); + expect(controller.$.excludeDialog.show).toHaveBeenCalledWith(); + }); + }); + + describe('createInclusion()', () => { + it('shoud set the selected property and then call the includeDialog show() method', () => { + controller.$.includeDialog = {show: jest.fn()}; const type = 'weekday'; const days = [new Date()]; const weekday = 1; - controller.create(type, days, weekday); + controller.createInclusion(type, days, weekday); const selection = controller.selected; const firstWeekday = selection.wdays[weekday]; @@ -120,23 +180,23 @@ describe('component vnZoneEvents', () => { expect(selection.type).toEqual('indefinitely'); expect(firstWeekday).toBeTruthy(); expect(controller.isNew).toBeTruthy(); - expect(controller.$.dialog.show).toHaveBeenCalledWith(); + expect(controller.$.includeDialog.show).toHaveBeenCalledWith(); }); - it('shoud set the selected property with the first day and then call the dialog show() method', () => { - controller.$.dialog = {show: jest.fn()}; + it('shoud set the selected property with the first day and then call the includeDialog show() method', () => { + controller.$.includeDialog = {show: jest.fn()}; const type = 'nonListedType'; const days = [new Date()]; const weekday = 1; - controller.create(type, days, weekday); + controller.createInclusion(type, days, weekday); const selection = controller.selected; expect(selection.type).toEqual('day'); expect(selection.dated).toEqual(days[0]); expect(controller.isNew).toBeTruthy(); - expect(controller.$.dialog.show).toHaveBeenCalledWith(); + expect(controller.$.includeDialog.show).toHaveBeenCalledWith(); }); }); @@ -180,6 +240,35 @@ describe('component vnZoneEvents', () => { }); }); + describe('onExcludeResponse()', () => { + it('should call the exclusionCreate() method', () => { + jest.spyOn(controller, 'exclusionCreate').mockReturnThis(); + + controller.excludeSelected = {type: 'all'}; + controller.onExcludeResponse('accept'); + + expect(controller.exclusionCreate).toHaveBeenCalledWith(); + }); + + it('should call the exclusionGeoCreate() method', () => { + jest.spyOn(controller, 'exclusionGeoCreate').mockReturnThis(); + + controller.excludeSelected = {type: 'specificLocations'}; + controller.onExcludeResponse('accept'); + + expect(controller.exclusionGeoCreate).toHaveBeenCalledWith(); + }); + + it('should call the exclusionDelete() method', () => { + jest.spyOn(controller, 'exclusionDelete').mockReturnThis(); + + controller.excludeSelected = {id: 1, type: 'all'}; + controller.onExcludeResponse('delete'); + + expect(controller.exclusionDelete).toHaveBeenCalledWith(controller.excludeSelected); + }); + }); + describe('onDeleteResponse()', () => { it('shoud make an HTTP DELETE query and then call the refresh() method', () => { jest.spyOn(controller, 'refresh').mockReturnThis(); @@ -197,9 +286,10 @@ describe('component vnZoneEvents', () => { it('shoud make an HTTP POST query and then call the refresh() method', () => { jest.spyOn(controller, 'refresh').mockReturnThis(); - const dates = [new Date()]; + controller.excludeSelected = {}; + controller.isNew = true; $httpBackend.expect('POST', `Zones/1/exclusions`).respond({id: 1}); - controller.exclusionCreate(dates); + controller.exclusionCreate(); $httpBackend.flush(); expect(controller.refresh).toHaveBeenCalledWith(); @@ -210,25 +300,41 @@ describe('component vnZoneEvents', () => { it('shoud make an HTTP DELETE query once and then call the refresh() method', () => { jest.spyOn(controller, 'refresh').mockReturnThis(); - const exclusions = [{id: 1}]; + const exclusions = {id: 1}; const firstExclusionId = 1; - $httpBackend.when('DELETE', `Zones/1/exclusions/${firstExclusionId}`).respond(200); + $httpBackend.expectDELETE(`Zones/1/exclusions/${firstExclusionId}`).respond(200); controller.exclusionDelete(exclusions); $httpBackend.flush(); expect(controller.refresh).toHaveBeenCalledWith(); }); + }); - it('shoud make an HTTP DELETE query for every event and then call the refresh() method', () => { - jest.spyOn(controller, 'refresh').mockReturnThis(); - jest.spyOn(controller.$http, 'delete').mockReturnValue(200); + describe('onSearch()', () => { + it('should call the applyFilter() method and then set the data', () => { + jest.spyOn(controller, 'getChecked').mockReturnValue([1, 2, 3]); - const exclusions = [{id: 1}, {id: 2}, {id: 3}, {id: 4}]; - controller.exclusionDelete(exclusions); - $scope.$apply(); + controller.$.treeview = {}; + controller.$.model = crudModel; + controller.excludeSelected = {type: 'specificLocations'}; + controller._excludeSearch = 'es'; - expect(controller.$http.delete).toHaveBeenCalledTimes(4); - expect(controller.refresh).toHaveBeenCalledWith(); + controller.onSearch(); + const treeviewData = controller.$.treeview.data; + + expect(treeviewData).toBeDefined(); + expect(treeviewData.length).toEqual(3); + }); + }); + + describe('onFetch()', () => { + it('should call the applyFilter() method and then return the model data', () => { + jest.spyOn(controller, 'getChecked').mockReturnValue([1, 2, 3]); + + controller.$.model = crudModel; + const result = controller.onFetch(); + + expect(result.length).toEqual(3); }); }); }); diff --git a/modules/zone/front/events/locale/es.yml b/modules/zone/front/events/locale/es.yml index eb581a719..1fb114720 100644 --- a/modules/zone/front/events/locale/es.yml +++ b/modules/zone/front/events/locale/es.yml @@ -4,3 +4,7 @@ Exclude: Excluir Events: Eventos Add event: Añadir evento Edit event: Editar evento +All: Todo +Specific locations: Localizaciones concretas +Locations where it is not distributed: Localizaciones en las que no se reparte +You must select a location: Debes seleccionar una localización diff --git a/modules/zone/front/events/style.scss b/modules/zone/front/events/style.scss new file mode 100644 index 000000000..49a6e87a6 --- /dev/null +++ b/modules/zone/front/events/style.scss @@ -0,0 +1,11 @@ +@import "variables"; + + .width{ + width: 600px + } + + .treeview{ + max-height: 300px; + overflow: auto; + } + diff --git a/modules/zone/front/location/style.scss b/modules/zone/front/location/style.scss index 2316a2622..24d685a51 100644 --- a/modules/zone/front/location/style.scss +++ b/modules/zone/front/location/style.scss @@ -1,19 +1,21 @@ @import "variables"; -vn-treeview-child { - .content > .vn-check:not(.indeterminate):not(.checked) { - color: $color-alert; +vn-zone-location { + vn-treeview-child { + .content > .vn-check:not(.indeterminate):not(.checked) { + color: $color-alert; - & > .btn { - border-color: $color-alert; + & > .btn { + border-color: $color-alert; + } + } + .content > .vn-check.checked { + color: $color-notice; + + & > .btn { + background-color: $color-notice; + border-color: $color-notice + } } } - .content > .vn-check.checked { - color: $color-notice; - - & > .btn { - background-color: $color-notice; - border-color: $color-notice - } - } -} \ No newline at end of file +} diff --git a/modules/zone/front/routes.json b/modules/zone/front/routes.json index e08f97314..7f67260da 100644 --- a/modules/zone/front/routes.json +++ b/modules/zone/front/routes.json @@ -85,10 +85,13 @@ "description": "Warehouses" }, { - "url": "/events", + "url": "/events?q", "state": "zone.card.events", "component": "vn-zone-events", - "description": "Calendar" + "description": "Calendar", + "params": { + "zone": "$ctrl.zone" + } }, { "url": "/location?q", diff --git a/package.json b/package.json index cb66a79a3..13a7096d6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "salix-back", - "version": "6.8.0", + "version": "8.6.0", "author": "Verdnatura Levante SL", "description": "Salix backend", "license": "GPL-3.0",