Merge pull request 'Download route PDF on route index' (#357) from 2358-route_download_pdf into dev
gitea/salix/pipeline/head This commit looks good
Details
gitea/salix/pipeline/head This commit looks good
Details
Reviewed-on: #357 Reviewed-by: Carlos Jimenez <carlosjr@verdnatura.es>
This commit is contained in:
commit
17cd808015
|
@ -371,7 +371,7 @@ export default {
|
|||
ticketsIndex: {
|
||||
openAdvancedSearchButton: 'vn-searchbar .append vn-icon[icon="arrow_drop_down"]',
|
||||
advancedSearchInvoiceOut: 'vn-ticket-search-panel vn-textfield[ng-model="filter.refFk"]',
|
||||
newTicketButton: 'vn-ticket-index a',
|
||||
newTicketButton: 'vn-ticket-index a[ui-sref="ticket.create"]',
|
||||
searchResult: 'vn-ticket-index vn-card > vn-table > div > vn-tbody > a.vn-tr',
|
||||
secondTicketCheckbox: 'vn-ticket-index vn-tbody > a:nth-child(2) > vn-td:nth-child(1) > vn-check',
|
||||
thirdTicketCheckbox: 'vn-ticket-index vn-tbody > a:nth-child(3) > vn-td:nth-child(1) > vn-check',
|
||||
|
@ -689,7 +689,7 @@ export default {
|
|||
confirmButton: '.vn-confirm.shown button[response="accept"]',
|
||||
},
|
||||
routeIndex: {
|
||||
addNewRouteButton: 'vn-route-index > a[ui-sref="route.create"]'
|
||||
addNewRouteButton: 'vn-route-index a[ui-sref="route.create"]'
|
||||
},
|
||||
createRouteView: {
|
||||
worker: 'vn-route-create vn-autocomplete[ng-model="$ctrl.route.workerFk"]',
|
||||
|
|
|
@ -8,6 +8,11 @@
|
|||
<vn-table model="model">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th shrink>
|
||||
<vn-multi-check
|
||||
model="model">
|
||||
</vn-multi-check>
|
||||
</vn-th>
|
||||
<vn-th field="id" number>Id</vn-th>
|
||||
<vn-th th-id="worker">Worker</vn-th>
|
||||
<vn-th th-id="agency">Agency</vn-th>
|
||||
|
@ -22,6 +27,12 @@
|
|||
<a ng-repeat="route in model.data"
|
||||
class="clickable vn-tr search-result"
|
||||
ui-sref="route.card.summary({id: {{::route.id}}})">
|
||||
<vn-td shrink>
|
||||
<vn-check
|
||||
ng-model="route.checked"
|
||||
vn-click-stop>
|
||||
</vn-check>
|
||||
</vn-td>
|
||||
<vn-td number>{{::route.id | dashIfEmpty}}</vn-td>
|
||||
<vn-td expand>
|
||||
<span
|
||||
|
@ -55,9 +66,26 @@
|
|||
<vn-worker-descriptor-popover
|
||||
vn-id="workerDescriptor">
|
||||
</vn-worker-descriptor-popover>
|
||||
<a ui-sref="route.create"
|
||||
vn-tooltip="New route"
|
||||
vn-bind="+"
|
||||
fixed-bottom-right>
|
||||
<vn-float-button icon="add"></vn-float-button>
|
||||
</a>
|
||||
|
||||
|
||||
</vn-data-viewer>
|
||||
<div fixed-bottom-right>
|
||||
<vn-vertical style="align-items: center;">
|
||||
<vn-button class="round sm vn-mb-sm"
|
||||
icon="cloud_download"
|
||||
ng-show="$ctrl.totalChecked > 0"
|
||||
ng-click="$ctrl.showRouteReport()"
|
||||
vn-tooltip="Download selected routes as PDF"
|
||||
tooltip-position="left">
|
||||
</vn-button>
|
||||
|
||||
<a ui-sref="route.create">
|
||||
<vn-button class="round md vn-mb-sm"
|
||||
icon="add"
|
||||
vn-bind="+"
|
||||
vn-tooltip="New route"
|
||||
tooltip-position="left">
|
||||
</vn-button>
|
||||
</a>
|
||||
</vn-vertical>
|
||||
</div>
|
|
@ -2,12 +2,46 @@ import ngModule from '../module';
|
|||
import Section from 'salix/components/section';
|
||||
|
||||
export default class Controller extends Section {
|
||||
constructor($element, $, vnReport) {
|
||||
super($element, $);
|
||||
this.vnReport = vnReport;
|
||||
}
|
||||
|
||||
preview(route) {
|
||||
this.routeSelected = route;
|
||||
this.$.summary.show();
|
||||
}
|
||||
|
||||
get checked() {
|
||||
const rows = this.$.model.data || [];
|
||||
const checkedRows = [];
|
||||
for (let row of rows) {
|
||||
if (row.checked)
|
||||
checkedRows.push(row);
|
||||
}
|
||||
|
||||
return checkedRows;
|
||||
}
|
||||
|
||||
get totalChecked() {
|
||||
return this.checked.length;
|
||||
}
|
||||
|
||||
showRouteReport() {
|
||||
const routes = [];
|
||||
for (let route of this.checked)
|
||||
routes.push(route.id);
|
||||
const routesId = routes.join(',');
|
||||
|
||||
this.vnReport.show('driver-route', {
|
||||
authorization: this.vnToken.token,
|
||||
routeId: routesId
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$element', '$scope', 'vnReport'];
|
||||
|
||||
ngModule.vnComponent('vnRouteIndex', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
import './index.js';
|
||||
import crudModel from 'core/mocks/crud-model';
|
||||
|
||||
describe('Component vnRouteIndex', () => {
|
||||
let controller;
|
||||
|
||||
beforeEach(ngModule('route'));
|
||||
|
||||
beforeEach(inject($componentController => {
|
||||
const $element = angular.element('<vn-route-index></vn-route-index>');
|
||||
controller = $componentController('vnRouteIndex', {$element});
|
||||
controller.$.model = crudModel;
|
||||
controller.$.model.data = [{id: 1}, {id: 2}, {id: 3}];
|
||||
}));
|
||||
|
||||
describe('checked() getter', () => {
|
||||
it('should return the checked lines', () => {
|
||||
const data = controller.$.model.data;
|
||||
data[0].checked = true;
|
||||
data[2].checked = true;
|
||||
|
||||
const checkedRows = controller.checked;
|
||||
|
||||
const firstCheckedRow = checkedRows[0];
|
||||
const secondCheckedRow = checkedRows[1];
|
||||
|
||||
expect(firstCheckedRow.id).toEqual(1);
|
||||
expect(secondCheckedRow.id).toEqual(3);
|
||||
});
|
||||
});
|
||||
|
||||
describe('totalCheked() getter', () => {
|
||||
it('should return the total checked lines', () => {
|
||||
const data = controller.$.model.data;
|
||||
data[0].checked = true;
|
||||
|
||||
const checkedRows = controller.totalChecked;
|
||||
|
||||
expect(checkedRows).toEqual(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('showRouteReport()', () => {
|
||||
it('should call to the vnReport show method', () => {
|
||||
controller.vnReport.show = jest.fn();
|
||||
|
||||
const data = controller.$.model.data;
|
||||
data[0].checked = true;
|
||||
data[2].checked = true;
|
||||
const expectedParams = {
|
||||
authorization: null,
|
||||
routeId: '1,3'
|
||||
};
|
||||
|
||||
controller.showRouteReport();
|
||||
|
||||
expect(controller.vnReport.show).toHaveBeenCalledWith('driver-route', expectedParams);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1 +1,2 @@
|
|||
Vehicle: Vehículo
|
||||
Download selected routes as PDF: Descargar rutas seleccionadas como PDF
|
|
@ -24,8 +24,9 @@ p.privacy {
|
|||
text-align: center
|
||||
}
|
||||
|
||||
.page .pageCount {
|
||||
text-align: right
|
||||
.pageCount {
|
||||
text-align: right;
|
||||
float: right
|
||||
}
|
||||
|
||||
.footer .page > div {
|
||||
|
|
|
@ -33,6 +33,7 @@ class Report extends Component {
|
|||
args: ['--no-sandbox', '--disable-setuid-sandbox']
|
||||
});
|
||||
const page = await browser.newPage();
|
||||
await page.emulateMedia('screen');
|
||||
await page.setContent(template);
|
||||
|
||||
const element = await page.$('#pageFooter');
|
||||
|
|
|
@ -47,3 +47,8 @@ section.text-area {
|
|||
padding-right: 1em;
|
||||
background-color: #e5e5e5;
|
||||
}
|
||||
|
||||
.route-block {
|
||||
margin-bottom: 100px;
|
||||
page-break-after: always;
|
||||
}
|
|
@ -8,9 +8,9 @@
|
|||
<!-- Header block -->
|
||||
<report-header v-bind="$props"></report-header>
|
||||
<!-- Block -->
|
||||
<div class="grid-row">
|
||||
<div class="grid-row route-block" v-for="route in routes">
|
||||
<div class="grid-block">
|
||||
<h1 class="title uppercase">{{route.id}}</h1>
|
||||
<h1 class="title uppercase">{{$t('route')}} {{route.id}}</h1>
|
||||
<div class="panel">
|
||||
<div class="header">{{$t('information')}}</div>
|
||||
<div class="body">
|
||||
|
@ -80,7 +80,8 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="no-page-break" v-for="ticket in tickets">
|
||||
<!-- Route ticket list -->
|
||||
<div class="no-page-break" v-for="ticket in route.tickets">
|
||||
<div>
|
||||
<table class="column-oriented repeatable">
|
||||
<thead>
|
||||
|
@ -151,7 +152,7 @@
|
|||
</div>
|
||||
<!-- Footer block -->
|
||||
<report-footer id="pageFooter"
|
||||
v-bind:left-text="$t('routeId', [route.id])"
|
||||
v-bind:left-text="$t('routeId', [routeId])"
|
||||
v-bind="$props">
|
||||
</report-footer>
|
||||
</td>
|
||||
|
|
|
@ -6,15 +6,26 @@ const reportFooter = new Component('report-footer');
|
|||
module.exports = {
|
||||
name: 'driver-route',
|
||||
async serverPrefetch() {
|
||||
this.route = await this.fetchRoute(this.routeId);
|
||||
this.tickets = await this.fetchTickets(this.routeId);
|
||||
const routesId = this.routeId.split(',');
|
||||
const routes = await this.fetchRoutes(routesId);
|
||||
const tickets = await this.fetchTickets(routesId);
|
||||
|
||||
if (!this.route)
|
||||
for (let route of routes) {
|
||||
const routeTickets = tickets.filter(ticket => {
|
||||
return ticket.routeFk == route.id;
|
||||
});
|
||||
|
||||
route.tickets = routeTickets;
|
||||
}
|
||||
|
||||
this.routes = routes;
|
||||
|
||||
if (!this.routes)
|
||||
throw new Error('Something went wrong');
|
||||
},
|
||||
methods: {
|
||||
fetchRoute(id) {
|
||||
return db.findOne(
|
||||
fetchRoutes(routesId) {
|
||||
return db.rawSql(
|
||||
`SELECT
|
||||
r.id,
|
||||
r.m3,
|
||||
|
@ -30,9 +41,9 @@ module.exports = {
|
|||
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 = :routeId`, {routeId: id});
|
||||
WHERE r.id IN(:routesId)`, {routesId});
|
||||
},
|
||||
fetchTickets(routeId) {
|
||||
fetchTickets(routesId) {
|
||||
return db.rawSql(
|
||||
`SELECT
|
||||
t.nickname addressName,
|
||||
|
@ -41,6 +52,7 @@ module.exports = {
|
|||
t.id,
|
||||
t.clientFk,
|
||||
t.companyFk,
|
||||
t.routeFk,
|
||||
if(a.phone, a.phone, c.phone) AS phone,
|
||||
if(a.mobile, a.mobile, c.mobile) AS mobile,
|
||||
wh.name warehouseName,
|
||||
|
@ -65,8 +77,8 @@ module.exports = {
|
|||
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`, [routeId]);
|
||||
WHERE r.id IN(:routesId)
|
||||
ORDER BY t.priority, t.id`, {routesId});
|
||||
}
|
||||
},
|
||||
components: {
|
||||
|
|
Loading…
Reference in New Issue