diff --git a/CHANGELOG.md b/CHANGELOG.md index 41374b4df..b6f258a19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [2304.01] - 2023-02-09 ### Added +- (Rutas) Al descargar varias facturas se comprime en un zip - (Trabajadores -> Nuevo trabajador) Nueva sección ### Changed diff --git a/modules/route/back/methods/route/downloadZip.js b/modules/route/back/methods/route/downloadZip.js new file mode 100644 index 000000000..597f1d1f6 --- /dev/null +++ b/modules/route/back/methods/route/downloadZip.js @@ -0,0 +1,62 @@ +const JSZip = require('jszip'); + +module.exports = Self => { + Self.remoteMethodCtx('downloadZip', { + description: 'Download a zip file with multiple routes pdfs', + accessType: 'READ', + accepts: [ + { + arg: 'id', + type: 'string', + description: 'The routes ids', + } + ], + returns: [ + { + arg: 'body', + type: 'file', + root: true + }, { + arg: 'Content-Type', + type: 'string', + http: {target: 'header'} + }, { + arg: 'Content-Disposition', + type: 'string', + http: {target: 'header'} + } + ], + http: { + path: '/downloadZip', + verb: 'GET' + } + }); + + Self.downloadZip = async function(ctx, id, options) { + const models = Self.app.models; + const myOptions = {}; + const zip = new JSZip(); + + if (typeof options == 'object') + Object.assign(myOptions, options); + + const ids = id.split(','); + for (let id of ids) { + ctx.args.id = id; + const routePdf = await models.Route.driverRoutePdf(ctx, id); + const fileName = extractFileName(routePdf[2]); + const body = routePdf[0]; + + zip.file(fileName, body); + } + + const stream = zip.generateNodeStream({streamFiles: true}); + + return [stream, 'application/zip', `filename="download.zip"`]; + }; + + function extractFileName(str) { + const matches = str.match(/"(.*?)"/); + return matches ? matches[1] : str; + } +}; diff --git a/modules/route/back/models/route.js b/modules/route/back/models/route.js index 08cabd30e..883f4597e 100644 --- a/modules/route/back/models/route.js +++ b/modules/route/back/models/route.js @@ -13,6 +13,7 @@ module.exports = Self => { require('../methods/route/driverRoutePdf')(Self); require('../methods/route/driverRouteEmail')(Self); require('../methods/route/sendSms')(Self); + require('../methods/route/downloadZip')(Self); Self.validate('kmStart', validateDistance, { message: 'Distance must be lesser than 1000' diff --git a/modules/route/front/index/index.js b/modules/route/front/index/index.js index 9258c8fac..94f6db09c 100644 --- a/modules/route/front/index/index.js +++ b/modules/route/front/index/index.js @@ -34,12 +34,22 @@ export default class Controller extends Section { } showRouteReport() { - const routes = []; + const routesIds = []; for (let route of this.checked) - routes.push(route.id); - const routesId = routes.join(','); + routesIds.push(route.id); + const stringRoutesIds = routesIds.join(','); - this.vnReport.show(`Routes/${routesId}/driver-route-pdf`); + if (this.checked.length <= 1) { + const url = `api/Routes/${stringRoutesIds}/driver-route-pdf?access_token=${this.vnToken.token}`; + window.open(url, '_blank'); + } else { + const serializedParams = this.$httpParamSerializer({ + access_token: this.vnToken.token, + id: stringRoutesIds + }); + const url = `api/Routes/downloadZip?${serializedParams}`; + window.open(url, '_blank'); + } } openClonationDialog() { diff --git a/modules/route/front/index/index.spec.js b/modules/route/front/index/index.spec.js index 05dd56433..c1f414d5e 100644 --- a/modules/route/front/index/index.spec.js +++ b/modules/route/front/index/index.spec.js @@ -44,17 +44,15 @@ describe('Component vnRouteIndex', () => { describe('showRouteReport()', () => { it('should call to the vnReport show method', () => { - controller.vnReport.show = jest.fn(); + jest.spyOn(window, 'open').mockReturnThis(); const data = controller.$.model.data; data[0].checked = true; data[2].checked = true; - const routeIds = '1,3'; - controller.showRouteReport(); - expect(controller.vnReport.show).toHaveBeenCalledWith(`Routes/${routeIds}/driver-route-pdf`); + expect(window.open).toHaveBeenCalled(); }); }); diff --git a/modules/shelving/front/routes.json b/modules/shelving/front/routes.json index 09a8e389b..4059e5095 100644 --- a/modules/shelving/front/routes.json +++ b/modules/shelving/front/routes.json @@ -1,12 +1,12 @@ { "module": "shelving", "name": "Shelvings", - "icon" : "contact_support", + "icon" : "icon-inventory", "dependencies": ["worker"], "validations" : true, "menus": { "main": [ - {"state": "shelving.index", "icon": "contact_support"} + {"state": "shelving.index", "icon": "icon-inventory"} ], "card": [ {"state": "shelving.card.basicData", "icon": "settings"}, @@ -20,7 +20,7 @@ "abstract": true, "component": "vn-shelving", "description": "Shelvings" - }, + }, { "url": "/index?q", "state": "shelving.index", @@ -32,13 +32,13 @@ "state": "shelving.create", "component": "vn-shelving-create", "description": "New shelving" - }, + }, { "url": "/:id", "state": "shelving.card", "abstract": true, "component": "vn-shelving-card" - }, + }, { "url": "/summary", "state": "shelving.card.summary", @@ -47,7 +47,7 @@ "params": { "shelving": "$ctrl.shelving" } - }, + }, { "url": "/basic-data", "state": "shelving.card.basicData", @@ -56,7 +56,7 @@ "params": { "shelving": "$ctrl.shelving" } - }, + }, { "url" : "/log", "state": "shelving.card.log", @@ -64,4 +64,4 @@ "description": "Log" } ] -} \ No newline at end of file +}