diff --git a/.eslintrc.yml b/.eslintrc.yml index 3b82d0a90..247319137 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -31,4 +31,3 @@ rules: curly: [error, multi-or-nest] indent: [error, 4] arrow-parens: [error, as-needed] - jasmine/no-focused-tests: 0 \ No newline at end of file diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 3b409aca3..ccc722c44 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -440,9 +440,12 @@ INSERT INTO `vn`.`ticket`(`id`, `agencyModeFk`,`warehouseFk`,`routeFk`, `shipped INSERT INTO `vn`.`ticketObservation`(`id`, `ticketFk`, `observationTypeFk`, `description`) VALUES - ( 1, 1 , 1, 'ready' ), - ( 2, 2 , 2, 'do it fast please'), - ( 3, 3 , 3, ''); + (1, 1 , 1, 'ready' ), + (2, 2 , 2, 'do it fast please'), + (3, 3 , 3, 'Faster faster fasteeeeeer!!!'), + (4, 4 , 3, 'Deliver before 8am'), + (5, 13 , 3, 'You can run from the disappointments you are trying to forget. But its only when you embrace your past that you truly move forward. Maybe I never get to go home again, but I found my way there. And I am glad I did.'), + (6, 14, 3, 'Careful, armed warhead'); INSERT INTO `vn`.`ticketTracking`(`id`, `ticketFk`, `stateFk`, `workerFk`, `created`) VALUES diff --git a/modules/route/front/descriptor/index.html b/modules/route/front/descriptor/index.html index 9ccd7444b..2a2600177 100644 --- a/modules/route/front/descriptor/index.html +++ b/modules/route/front/descriptor/index.html @@ -6,6 +6,15 @@ + +
diff --git a/modules/route/front/descriptor/index.js b/modules/route/front/descriptor/index.js index 5c47c864f..ca2a3de0c 100644 --- a/modules/route/front/descriptor/index.js +++ b/modules/route/front/descriptor/index.js @@ -1,6 +1,16 @@ import ngModule from '../module'; class Controller { + constructor($, $http, vnApp, $translate) { + this.$http = $http; + this.vnApp = vnApp; + this.$translate = $translate; + this.$ = $; + this.moreOptions = [ + {callback: this.showRouteReport, name: 'Show route report'}, + {callback: this.sendRouteReport, name: 'Send route report'} + ]; + } set quicklinks(value = {}) { this._quicklinks = Object.assign(value, this._quicklinks); } @@ -8,9 +18,25 @@ class Controller { get quicklinks() { return this._quicklinks; } + + onMoreChange(callback) { + callback.call(this); + } + + showRouteReport() { + let url = `/api/report/rpt-route?routeFk=${this.route.id}`; + window.open(url); + } + + sendRouteReport() { + let url = `/api/email/driver-route?routeFk=${this.route.id}`; + this.$http.post(url).then(() => { + this.vnApp.showSuccess(this.$translate.instant('Report sent')); + }); + } } -Controller.$inject = ['$http', '$state']; +Controller.$inject = ['$scope', '$http', 'vnApp', '$translate']; ngModule.component('vnRouteDescriptor', { template: require('./index.html'), diff --git a/modules/route/front/descriptor/locale/es.yml b/modules/route/front/descriptor/locale/es.yml index 3f7596ae0..3fd58aed6 100644 --- a/modules/route/front/descriptor/locale/es.yml +++ b/modules/route/front/descriptor/locale/es.yml @@ -1,2 +1,4 @@ Volume exceded: Volumen excedido -Volume: Volumen \ No newline at end of file +Volume: Volumen +Send route report: Enviar informe de ruta +Show route report: Ver informe de ruta \ No newline at end of file diff --git a/modules/ticket/front/descriptor/index.js b/modules/ticket/front/descriptor/index.js index 1708a73d3..0e153b8fc 100644 --- a/modules/ticket/front/descriptor/index.js +++ b/modules/ticket/front/descriptor/index.js @@ -65,13 +65,13 @@ class Controller { } onMoreOpen() { - let options = this.moreOptions.filter(o => { - const hasShowProperty = Object.hasOwnProperty.call(o, 'show'); - const hasAclProperty = Object.hasOwnProperty.call(o, 'acl'); - const hasAcl = !hasAclProperty || (hasAclProperty && this.aclService.hasAny([o.acl])); + let options = this.moreOptions.filter(option => { + const hasShowProperty = Object.hasOwnProperty.call(option, 'show'); + const hasAclProperty = Object.hasOwnProperty.call(option, 'acl'); + const hasAcl = !hasAclProperty || (hasAclProperty && this.aclService.hasAny([option.acl])); - return (!hasShowProperty || o.show === true || - typeof o.show === 'function' && o.show()) && hasAcl; + return (!hasShowProperty || option.show === true || + typeof option.show === 'function' && option.show()) && hasAcl; }); this.$scope.moreButton.data = options; } diff --git a/modules/ticket/front/request/index/index.html b/modules/ticket/front/request/index/index.html index 2a1937052..eb2de0af0 100644 --- a/modules/ticket/front/request/index/index.html +++ b/modules/ticket/front/request/index/index.html @@ -61,7 +61,8 @@ diff --git a/print/common/css/layout.css b/print/common/css/layout.css index 560309a0d..3e302d675 100644 --- a/print/common/css/layout.css +++ b/print/common/css/layout.css @@ -99,6 +99,11 @@ width: 35.4px } +.field.rectangle span { + height: 2em; + width: 8em +} + .pull-left { float: left !important } diff --git a/print/common/css/misc.css b/print/common/css/misc.css index a31279ee2..16a37b6c3 100644 --- a/print/common/css/misc.css +++ b/print/common/css/misc.css @@ -10,6 +10,14 @@ text-align: center } +.align-right { + text-align: right +} + +.align-left { + text-align: left +} + .number { text-align: right } @@ -28,4 +36,8 @@ .font.bold { font-weight: bold +} + +.non-page-break { + page-break-inside: avoid; } \ No newline at end of file diff --git a/print/config/routes.json b/print/config/routes.json index 95e881f0a..69b94a6e4 100644 --- a/print/config/routes.json +++ b/print/config/routes.json @@ -6,12 +6,13 @@ {"type": "email", "name": "letter-debtor-nd"}, {"type": "email", "name": "claim-pickup-order"}, {"type": "email", "name": "sepa-core"}, + {"type": "email", "name": "driver-route"}, {"type": "report", "name": "rpt-delivery-note"}, - {"type": "report", "name": "rpt-invoice"}, {"type": "report", "name": "rpt-claim-pickup-order"}, {"type": "report", "name": "rpt-letter-debtor"}, {"type": "report", "name": "rpt-sepa-core"}, {"type": "report", "name": "rpt-receipt"}, + {"type": "report", "name": "rpt-zone"}, {"type": "report", "name": "rpt-route"}, {"type": "static", "name": "email-header"}, {"type": "static", "name": "email-footer"}, diff --git a/print/report/driver-route/assets/css/index.js b/print/report/driver-route/assets/css/index.js new file mode 100644 index 000000000..321c632dc --- /dev/null +++ b/print/report/driver-route/assets/css/index.js @@ -0,0 +1,7 @@ +const CssReader = require(`${appPath}/lib/cssReader`); + +module.exports = new CssReader([ + `${appPath}/common/css/layout.css`, + `${appPath}/common/css/email.css`, + `${appPath}/common/css/misc.css`]) + .mergeStyles(); diff --git a/print/report/driver-route/index.html b/print/report/driver-route/index.html new file mode 100644 index 000000000..45dbd3e1f --- /dev/null +++ b/print/report/driver-route/index.html @@ -0,0 +1,24 @@ + + + + {{ $t('subject') }} + + +
+ + + +
+ +
+

{{ $t('title') }}

+
+ +

{{$t('description.instructions')}}

+
+ + + +
+ + \ No newline at end of file diff --git a/print/report/driver-route/index.js b/print/report/driver-route/index.js new file mode 100755 index 000000000..2a142856f --- /dev/null +++ b/print/report/driver-route/index.js @@ -0,0 +1,54 @@ +const UserException = require(`${appPath}/lib/exceptions/userException`); +const reportEngine = require(`${appPath}/lib/reportEngine`); +const database = require(`${appPath}/lib/database`); +const emailHeader = require('../email-header'); +const emailFooter = require('../email-footer'); + + +module.exports = { + name: 'driver-route', + async asyncData(ctx, params) { + const promises = []; + const data = { + isPreview: ctx.method === 'GET', + }; + + if (!params.routeFk) + throw new UserException('No route id specified'); + + promises.push(reportEngine.toPdf('rpt-route', ctx)); + promises.push(this.methods.fetchRoute(params.routeFk)); + + return Promise.all(promises).then(result => { + const stream = result[0]; + const [[route]] = result[1]; + + Object.assign(data, route); + Object.assign(data, {attachments: [{filename: 'driver-route.pdf', content: stream}]}); + + return data; + }); + }, + created() { + if (this.locale) + this.$i18n.locale = this.locale; + }, + methods: { + fetchRoute(routeFk) { + return database.pool.query(` + SELECT + u.id, + u.lang AS locale, + mu.email AS recipient + FROM route r + LEFT JOIN worker w ON w.id = r.workerFk + LEFT JOIN account.user u ON u.id = w.userFk + LEFT JOIN account.emailUser mu ON mu.userFk = u.id + WHERE r.id = ?`, [routeFk]); + }, + }, + components: { + emailHeader, + emailFooter, + }, +}; diff --git a/print/report/driver-route/locale.js b/print/report/driver-route/locale.js new file mode 100644 index 000000000..9255f8f97 --- /dev/null +++ b/print/report/driver-route/locale.js @@ -0,0 +1,11 @@ +module.exports = { + messages: { + es: { + subject: 'Hoja de ruta', + title: 'Hoja de ruta', + description: { + instructions: 'Adjuntamos tu hoja de ruta.' + }, + }, + }, +}; diff --git a/print/report/rpt-route/assets/css/index.js b/print/report/rpt-route/assets/css/index.js index 06417fcee..515dea750 100644 --- a/print/report/rpt-route/assets/css/index.js +++ b/print/report/rpt-route/assets/css/index.js @@ -3,5 +3,6 @@ const CssReader = require(`${appPath}/lib/cssReader`); module.exports = new CssReader([ `${appPath}/common/css/layout.css`, `${appPath}/common/css/report.css`, + `${appPath}/common/css/misc.css`, `${__dirname}/style.css`]) .mergeStyles(); diff --git a/print/report/rpt-route/assets/css/style.css b/print/report/rpt-route/assets/css/style.css index 82e5c33f1..2e7ec4dab 100644 --- a/print/report/rpt-route/assets/css/style.css +++ b/print/report/rpt-route/assets/css/style.css @@ -1,9 +1,49 @@ -section .text { - font-family: Tahoma; - font-weight: bold; - color: white; - font-size: 7.5em; +h1 { text-align: center; +} + +th.align-right { + padding-right: 1em; +} + +.gap { + width: 3em; +} + +.contained { + padding-top: 20px; +} + +.middle { + margin: auto; +} + +p.small { + width: 8em; +} + +.black-container { + padding-top: 0.19em; + padding-right: 0.2em; + padding-left: 0.2em; background-color: black; - margin-bottom: 0.2em -} \ No newline at end of file + color: white; + font-size: 1.3em; +} + +table.repeatable { + margin-top: 1em; + margin-bottom: 1em; +} + +table.repeatable > tbody > tr > td { + padding-top: 0.5em; +} + +section.text-area { + margin-top: 1em; + padding: 0.19em; + padding-left: 1em; + padding-right: 1em; + background-color: #e5e5e5; +} diff --git a/print/report/rpt-route/index.html b/print/report/rpt-route/index.html index 727088c82..e3b814c50 100644 --- a/print/report/rpt-route/index.html +++ b/print/report/rpt-route/index.html @@ -2,14 +2,155 @@
+ + +
- -
{{route.agencyName}}
-
{{route.id}}
-
{{route.plateNumber}} {{routeTime(route.time)}}
-
- +

{{$t('Title')}}

+
+
{{$t('Information')}}
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
{{$t('Route')}}{{route.id}}{{$t('Driver')}}{{route.userNickName}}
{{$t('Date')}}{{date(route.created)}}{{$t('Vehicle')}}{{route.vehicleTradeMark}} {{route.vehicleModel}}
{{$t('Time')}}{{time(route.time)}}{{route.plateNumber}}
{{$t('Volume')}}{{route.m3}}{{$t('Agency')}}{{route.agencyName}}
+
+ + + + + + + + + + + + + + + +
+

Hora inicio

+
+

Hora fin

+
+

Km inicio

+
+

Km fin

+
+
+ +
+
+
+ +
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + +
{{$t('Order')}}{{$t('Ticket')}}{{$t('Client')}}{{$t('Address')}}{{$t('Packages')}}
{{ticket.priority}}{{ticket.id}}{{ticket.clientFk}} {{ticket.addressName}} + {{ticket.addressFk.toString().substr(0, ticket.addressFk.toString().length - 3)}} + + {{ticket.addressFk.toString().substr(-3, 3)}} + + {{ticket.packages}}
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{{$t('Street')}}{{ticket.street}}{{$t('Postcode')}}{{ticket.postalCode}}
{{$t('City')}}{{ticket.city}}{{$t('Agency')}}{{ticket.ticketAgency}}
{{$t('Mobile')}}{{ticket.mobile}}{{$t('Phone')}}{{ticket.phone}}
{{$t('Warehouse')}}{{ticket.warehouseName}}{{$t('salesPerson')}}{{ticket.salesPersonName}}
{{$t('Import')}}{{ticket.import}}
+
+

{{ticket.description}}

+

{{$t('stowaway')}}: {{ticket.shipFk}}

+
+
+
+
+ + + + - \ No newline at end of file + diff --git a/print/report/rpt-route/index.js b/print/report/rpt-route/index.js index 7048acc2a..989a27254 100755 --- a/print/report/rpt-route/index.js +++ b/print/report/rpt-route/index.js @@ -5,32 +5,90 @@ const UserException = require(`${appPath}/lib/exceptions/userException`); module.exports = { name: 'rpt-route', async asyncData(ctx, params) { - if (!params.routeFk) - throw new UserException('No route id specified'); + Object.assign(this, this.methods); - let [[route]] = await this.methods.fetchRoute(params.routeFk); + const [[route]] = await this.fetchRoute(params.routeFk); + const [tickets] = await this.fetchTickets(params.routeFk); if (!route) - throw new UserException('Route not ready'); + throw new UserException('No route data found'); - return {route}; + if (!tickets) + throw new UserException('No ticket data found'); + + return {route, tickets}; }, methods: { fetchRoute(routeFk) { return database.pool.query( - `SELECT + `SELECT r.id, + r.m3, + r.created, r.time, - am.name agencyName, - v.numberPlate plateNumber + u.nickName userNickName, + u.lang AS locale, + v.tradeMark vehicleTradeMark, + v.model vehicleModel, + v.numberPlate plateNumber, + am.name agencyName FROM route r - JOIN agencyMode am ON am.id = r.agencyModeFk - JOIN vehicle v ON v.id = r.vehicleFk + LEFT JOIN ticket t ON t.routeFk = r.id + LEFT JOIN sale s ON s.ticketFk = t.id + LEFT JOIN cache.last_buy lb ON lb.item_id = s.itemFk + LEFT JOIN vehicle v ON v.id = r.vehicleFk + LEFT JOIN worker w ON w.id = r.workerFk + LEFT JOIN account.user u ON u.id = w.userFk + LEFT JOIN agencyMode am ON am.id = r.agencyModeFk WHERE r.id = ?`, [routeFk]); }, - routeTime: routeTime => { - if (routeTime) - return strftime('%H:%M', routeTime); + fetchTickets(routeFk) { + return database.pool.query( + `SELECT + t.nickname addressName, + t.packages, + t.priority, + t.id, + t.clientFk, + t.companyFk, + if(a.phone, a.phone, c.phone) AS phone, + if(a.mobile, a.mobile, c.mobile) AS mobile, + wh.name warehouseName, + a.city, + a.street, + a.postalCode, + LPAD(a.id, 5, '0') AS addressFk, + p.name province, + vn.ticketGetTotal(t.id) AS import, + am.name ticketAgency, + tob.description, + s.shipFk, + u.nickName salesPersonName + FROM route r + LEFT JOIN ticket t ON t.routeFk = r.id + LEFT JOIN address a ON a.id = t.addressFk + LEFT JOIN client c ON c.id = t.clientFk + LEFT JOIN worker w ON w.id = vn2008.Averiguar_ComercialCliente_Id(t.clientFk, CURDATE()) + LEFT JOIN account.user u ON u.id = w.userFk + LEFT JOIN ticketObservation tob ON tob.ticketFk = t.id AND tob.observationTypeFk = 3 + LEFT JOIN province p ON a.provinceFk = p.id + LEFT JOIN warehouse wh ON wh.id = t.warehouseFk + LEFT JOIN agencyMode am ON am.id = t.agencyModeFk + LEFT JOIN stowaway s ON s.id = t.id + WHERE r.id = ? + ORDER BY t.priority, t.id`, [routeFk]); + }, + date(date) { + if (date) + return strftime('%d-%m-%Y', date); + }, + time: time => { + if (time) + return strftime('%H:%M', time); }, }, + components: { + 'report-header': require('../report-header'), + 'report-footer': require('../report-footer'), + }, }; diff --git a/print/report/rpt-route/locale.js b/print/report/rpt-route/locale.js index e69de29bb..ef835b20f 100644 --- a/print/report/rpt-route/locale.js +++ b/print/report/rpt-route/locale.js @@ -0,0 +1,29 @@ +module.exports = { + messages: { + es: { + Title: 'Hoja de ruta', + Information: 'Información', + Route: 'Ruta', + Date: 'Fecha', + Time: 'Hora', + Volume: 'Cubicaje', + Driver: 'Conductor', + Vehicle: 'Vehículo', + Agency: 'Agencia', + Order: 'Orden', + Client: 'Cliente', + Address: 'Consignatario', + Packages: 'Bultos', + Street: 'Dirección', + Postcode: 'Código Postal', + City: 'Ciudad', + Mobile: 'Móvil', + Phone: 'Teléfono', + Warehouse: 'Almacén', + salesPerson: 'Comercial', + Import: 'Importe', + stowaway: 'Encajado dentro del ticket', + route: 'Ruta {0}' + } + }, +}; diff --git a/print/report/rpt-zone/assets/css/index.js b/print/report/rpt-zone/assets/css/index.js new file mode 100644 index 000000000..06417fcee --- /dev/null +++ b/print/report/rpt-zone/assets/css/index.js @@ -0,0 +1,7 @@ +const CssReader = require(`${appPath}/lib/cssReader`); + +module.exports = new CssReader([ + `${appPath}/common/css/layout.css`, + `${appPath}/common/css/report.css`, + `${__dirname}/style.css`]) + .mergeStyles(); diff --git a/print/report/rpt-zone/assets/css/style.css b/print/report/rpt-zone/assets/css/style.css new file mode 100644 index 000000000..82e5c33f1 --- /dev/null +++ b/print/report/rpt-zone/assets/css/style.css @@ -0,0 +1,9 @@ +section .text { + font-family: Tahoma; + font-weight: bold; + color: white; + font-size: 7.5em; + text-align: center; + background-color: black; + margin-bottom: 0.2em +} \ No newline at end of file diff --git a/print/report/rpt-zone/index.html b/print/report/rpt-zone/index.html new file mode 100644 index 000000000..5e64da73c --- /dev/null +++ b/print/report/rpt-zone/index.html @@ -0,0 +1,15 @@ + + + +
+
+ +
{{zone.agencyName}}
+
{{zone.id}}
+
{{zone.plateNumber}} {{zoneTime(zone.time)}}
+
+ +
+
+ + \ No newline at end of file diff --git a/print/report/rpt-zone/index.js b/print/report/rpt-zone/index.js new file mode 100755 index 000000000..c6b0a245c --- /dev/null +++ b/print/report/rpt-zone/index.js @@ -0,0 +1,36 @@ +const strftime = require('strftime'); +const database = require(`${appPath}/lib/database`); +const UserException = require(`${appPath}/lib/exceptions/userException`); + +module.exports = { + name: 'rpt-zone', + async asyncData(ctx, params) { + if (!params.routeFk) + throw new UserException('No route id specified'); + + let [[zone]] = await this.methods.fetchRoute(params.routeFk); + + if (!zone) + throw new UserException('Route not ready'); + + return {zone}; + }, + methods: { + fetchRoute(routeFk) { + return database.pool.query( + `SELECT + r.id, + r.time, + am.name agencyName, + v.numberPlate plateNumber + FROM route r + JOIN agencyMode am ON am.id = r.agencyModeFk + JOIN vehicle v ON v.id = r.vehicleFk + WHERE r.id = ?`, [routeFk]); + }, + zoneTime: zoneTime => { + if (zoneTime) + return strftime('%H:%M', zoneTime); + }, + }, +}; diff --git a/print/report/rpt-zone/locale.js b/print/report/rpt-zone/locale.js new file mode 100644 index 000000000..e69de29bb