#1356 advanced search refactor

This commit is contained in:
Carlos Jimenez Ruiz 2019-04-25 08:28:08 +02:00
parent a6fa9f98fb
commit 4e5c6ff882
12 changed files with 295 additions and 117 deletions

View File

@ -0,0 +1,128 @@
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
const buildFilter = require('vn-loopback/util/filter').buildFilter;
const mergeFilters = require('vn-loopback/util/filter').mergeFilters;
module.exports = Self => {
Self.remoteMethodCtx('filter', {
description: 'Find all instances of the model matched by filter from the data source.',
accessType: 'READ',
accepts: [
{
arg: 'filter',
type: 'Object',
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string',
http: {source: 'query'}
},
{
arg: 'search',
type: 'String',
description: 'Searchs the invoiceOut by id',
http: {source: 'query'}
}, {
arg: 'clientFk',
type: 'Integer',
description: 'The client id',
http: {source: 'query'}
}, {
arg: 'hasPdf',
type: 'Boolean',
description: 'Whether the the invoiceOut has PDF or not',
http: {source: 'query'}
}, {
arg: 'amount',
type: 'Number',
description: 'The amount filter',
http: {source: 'query'}
}, {
arg: 'min',
type: 'Number',
description: 'The minimun amount flter',
http: {source: 'query'}
}, {
arg: 'max',
type: 'Number',
description: 'The maximun amount flter',
http: {source: 'query'}
}, {
arg: 'issued',
type: 'Date',
description: 'The issued date filter',
http: {source: 'query'}
}, {
arg: 'created',
type: 'Date',
description: 'The created date filter',
http: {source: 'query'}
}, {
arg: 'dued',
type: 'Date',
description: 'The due date filter',
http: {source: 'query'}
}
],
returns: {
type: ['Object'],
root: true
},
http: {
path: `/filter`,
verb: 'GET'
}
});
Self.filter = async(ctx, filter) => {
let conn = Self.dataSource.connector;
let where = buildFilter(ctx.args, (param, value) => {
switch (param) {
case 'search':
return {ref: {like: `%${value}%`}};
case 'min':
return {amount: {gte: value}};
case 'max':
return {amount: {lte: value}};
case 'hasPdf':
return {'i.pdf': value};
case 'created':
return {'i.created': value};
case 'amount':
case 'clientFk':
case 'companyFk':
case 'issued':
case 'dued':
return {[param]: value};
}
});
filter = mergeFilters(ctx.args.filter, {where});
let stmts = [];
let stmt;
stmt = new ParameterizedSQL(
`SELECT
i.id,
i.ref,
i.issued,
i.amount,
i.created,
i.dued,
i.clientFk,
i.pdf AS hasPdf,
c.socialName AS clientSocialName,
co.code AS companyCode
FROM invoiceOut i
LEFT JOIN client c ON c.id = i.clientFk
LEFT JOIN company co ON co.id = i.companyFk`
);
stmt.merge(conn.makeSuffix(filter));
let itemsIndex = stmts.push(stmt) - 1;
let sql = ParameterizedSQL.join(stmts, ';');
let result = await conn.executeStmt(sql);
return itemsIndex === 0 ? result : result[itemsIndex];
};
};

View File

@ -1,4 +1,5 @@
module.exports = Self => {
require('../methods/invoiceOut/filter')(Self);
require('../methods/invoiceOut/summary')(Self);
require('../methods/invoiceOut/download')(Self);
};

View File

@ -1,20 +1,16 @@
<vn-crud-model
vn-id="model"
url="/api/InvoiceOuts"
filter="::$ctrl.filter"
url="/api/InvoiceOuts/filter"
limit="20"
data="invoicesOut"
order="issued DESC"
auto-load="false">
data="invoiceOuts"
order="issued DESC">
</vn-crud-model>
<div class="content-block">
<div class="vn-list">
<vn-card pad-medium-h>
<vn-searchbar
panel="vn-invoice-search-panel"
model="model"
expr-builder="$ctrl.exprBuilder(param, value)"
auto-load="true"
on-search="$ctrl.onSearch($params)"
info="Search invoices by reference"
vn-focus>
</vn-searchbar>
@ -36,7 +32,7 @@
</vn-tr>
</vn-thead>
<vn-tbody>
<a ng-repeat="invoiceOut in invoicesOut"
<a ng-repeat="invoiceOut in invoiceOuts"
class="clickable vn-tr searchResult"
ui-sref="invoiceOut.card.summary({id: {{::invoiceOut.id}}})">
<vn-td>{{::invoiceOut.ref | dashIfEmpty}}</vn-td>
@ -46,11 +42,11 @@
<span
class="link"
ng-click="$ctrl.showClientDescriptor($event, invoiceOut.clientFk)">
{{::invoiceOut.client.name | dashIfEmpty}}
{{::invoiceOut.clientSocialName | dashIfEmpty}}
</span>
</vn-td>
<vn-td>{{::invoiceOut.created | dateTime:'dd/MM/yyyy' | dashIfEmpty}}</vn-td>
<vn-td>{{::invoiceOut.company.code | dashIfEmpty}}</vn-td>
<vn-td>{{::invoiceOut.companyCode | dashIfEmpty}}</vn-td>
<vn-td>{{::invoiceOut.dued | dateTime:'dd/MM/yyyy' | dashIfEmpty}}</vn-td>
<vn-td>
<vn-icon-button

View File

@ -5,42 +5,6 @@ export default class Controller {
this.accessToken = vnToken.token;
this.$ = $scope;
this.selectedInvoiceOut = null;
this.filter = {
include: [
{
relation: 'client',
scope: {
fields: ['name']
}
},
{
relation: 'company',
scope: {
fields: ['code']
}
}
]
};
}
exprBuilder(param, value) {
switch (param) {
case 'search':
return {ref: {like: `%${value}%`}};
case 'min':
return {amount: {gte: value}};
case 'max':
return {amount: {lte: value}};
case 'hasPdf':
case 'amount':
case 'clientFk':
case 'companyFk':
case 'issued':
case 'created':
case 'dued':
return {[param]: value};
}
}
showClientDescriptor(event, clientFk) {
@ -68,6 +32,13 @@ export default class Controller {
event.preventDefault();
event.stopImmediatePropagation();
}
onSearch(params) {
if (params)
this.$.model.applyFilter(null, params);
else
this.$.model.clear();
}
}
Controller.$inject = ['$scope', 'vnToken'];

View File

@ -19,9 +19,9 @@
</vn-label-value>
</vn-one>
<vn-two>
<h4 translate>Desglose impositivo</h4>
<vn-table model="model">
<vn-thead>
<h4 translate>Desglose impositivo</h4>
<vn-tr>
<vn-th>Type</vn-th>
<vn-th>Taxable base</vn-th>

View File

@ -1,11 +1,3 @@
Driver: Conductor
Vehicle: Vehículo
Packages: Bultos
Starting time: H. Inicio
Finishing time: H. Fin
Km Start: Km de inicio
Km End: Km de fin
PC: CP
Date: Fecha
Created: Creada
Due: Vencimiento

View File

@ -1,7 +1,7 @@
@import "variables";
vn-route-summary .summary {
vn-invoice-out-summary .summary {
max-width: $width-large;
vn-icon[icon=insert_drive_file]{

View File

@ -41,7 +41,7 @@ module.exports = Self => {
}, {
arg: 'hasVisible',
type: 'Boolean',
description: 'Whether the the item has o not visible',
description: 'Whether the the item has visible or not',
http: {source: 'query'}
}, {
arg: 'isActive',

View File

@ -0,0 +1,131 @@
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
const buildFilter = require('vn-loopback/util/filter').buildFilter;
const mergeFilters = require('vn-loopback/util/filter').mergeFilters;
module.exports = Self => {
Self.remoteMethodCtx('filter', {
description: 'Find all instances of the model matched by filter from the data source.',
accessType: 'READ',
accepts: [
{
arg: 'filter',
type: 'Object',
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string',
http: {source: 'query'}
}, {
arg: 'search',
type: 'String',
description: 'Searchs the route by id',
http: {source: 'query'}
}, {
arg: 'workerFk',
type: 'Integer',
description: 'The worker id',
http: {source: 'query'}
}, {
arg: 'agencyModeFk',
type: 'Integer',
description: 'The agencyMode id',
http: {source: 'query'}
}, {
arg: 'to',
type: 'Date',
description: 'The to date filter',
http: {source: 'query'}
}, {
arg: 'from',
type: 'Date',
description: 'The to date filter',
http: {source: 'query'}
}, {
arg: 'vehicleFk',
type: 'Integer',
description: 'The vehicle id',
http: {source: 'query'}
}, {
arg: 'm3',
type: 'Number',
description: 'The m3 filter',
http: {source: 'query'}
}, {
arg: 'description',
type: 'String',
description: 'The description filter',
http: {source: 'query'}
}
],
returns: {
type: ['Object'],
root: true
},
http: {
path: `/filter`,
verb: 'GET'
}
});
Self.filter = async(ctx, filter) => {
let conn = Self.dataSource.connector;
let where = buildFilter(ctx.args, (param, value) => {
switch (param) {
case 'search':
return {'r.id': value};
case 'from':
return {'r.created': {gte: value}};
case 'to':
return {'r.created': {lte: value}};
case 'm3':
return {'r.m3': value};
case 'description':
return {'r.description': {like: `%${value}%`}};
case 'workerFk':
case 'vehicleFk':
case 'agencyModeFk':
return {[param]: value};
}
});
filter = mergeFilters(ctx.args.filter, {where});
let stmts = [];
let stmt;
stmt = new ParameterizedSQL(
`SELECT
r.id,
r.workerFk,
r.created,
r.vehicleFk,
r.agencyModeFk,
r.time,
r.isOk,
r.kmStart,
r.kmEnd,
r.started,
r.finished,
r.gestdocFk,
r.cost,
r.m3,
r.description,
am.name agencyName,
u.nickname AS workerNickname,
v.numberPlate AS vehiclePlateNumber
FROM route r
LEFT JOIN agencyMode am ON am.id = r.agencyModeFk
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`
);
stmt.merge(conn.makeSuffix(filter));
let itemsIndex = stmts.push(stmt) - 1;
let sql = ParameterizedSQL.join(stmts, ';');
let result = await conn.executeStmt(sql);
return itemsIndex === 0 ? result : result[itemsIndex];
};
};

View File

@ -1,4 +1,5 @@
module.exports = Self => {
require('../methods/route/filter')(Self);
require('../methods/route/summary')(Self);
require('../methods/route/getTickets')(Self);
require('../methods/route/guessPriority')(Self);

View File

@ -1,7 +1,6 @@
<vn-crud-model
vn-id="model"
url="/api/Routes"
filter="::$ctrl.filter"
url="/api/Routes/filter"
limit="20"
data="routes"
order="created DESC">
@ -11,9 +10,7 @@
<vn-card pad-medium-h>
<vn-searchbar
panel="vn-route-search-panel"
model="model"
expr-builder="$ctrl.exprBuilder(param, value)"
auto-load="true"
on-search="$ctrl.onSearch($params)"
info="Search routes by id"
vn-focus>
</vn-searchbar>
@ -41,12 +38,12 @@
<vn-td expand>
<span
class="link"
ng-click="$ctrl.showWorkerDescriptor($event, route.worker.id)">
{{::route.worker.user.nickname}}
ng-click="$ctrl.showWorkerDescriptor($event, route.workerFk)">
{{::route.workerNickname}}
</span>
</vn-td>
<vn-td>{{::route.agencyMode.name | dashIfEmpty}}</vn-td>
<vn-td>{{::route.vehicle.numberPlate | dashIfEmpty}}</vn-td>
<vn-td>{{::route.agencyName | dashIfEmpty}}</vn-td>
<vn-td>{{::route.vehiclePlateNumber | dashIfEmpty}}</vn-td>
<vn-td>{{::route.created | dateTime:'dd/MM/yyyy' | dashIfEmpty}}</vn-td>
<vn-td number>{{::route.m3 | dashIfEmpty}}</vn-td>
<vn-td>{{::route.description | dashIfEmpty}}</vn-td>
@ -72,7 +69,7 @@
</vn-dialog>
<vn-worker-descriptor-popover
vn-id="workerDescriptor"
user-id="$ctrl.selectedWorker">
worker-fk="$ctrl.selectedWorker">
</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>

View File

@ -4,61 +4,15 @@ export default class Controller {
constructor($scope, vnToken) {
this.accessToken = vnToken.token;
this.$ = $scope;
this.filter = {
include: [
{
relation: 'agencyMode',
scope: {
fields: ['name']
}
},
{
relation: 'vehicle',
scope: {
fields: ['numberPlate']
}
},
{
relation: 'worker',
scope: {
fields: ['userFk'],
include: {
relation: 'user',
scope: {
fields: ['nickname']
}
}
}
},
]
};
}
exprBuilder(param, value) {
switch (param) {
case 'search':
return {id: value};
case 'from':
return {created: {gte: value}};
case 'to':
return {created: {lte: value}};
case 'workerFk':
case 'vehicleFk':
case 'agencyModeFk':
case 'm3':
case 'description':
return {[param]: value};
}
}
showWorkerDescriptor(event, userId) {
showWorkerDescriptor(event, workerFk) {
if (event.defaultPrevented) return;
event.preventDefault();
event.stopPropagation();
event.stopImmediatePropagation();
this.selectedWorker = userId;
this.selectedWorker = workerFk;
this.$.workerDescriptor.parent = event.target;
this.$.workerDescriptor.show();
}
@ -69,6 +23,13 @@ export default class Controller {
event.preventDefault();
event.stopImmediatePropagation();
}
onSearch(params) {
if (params)
this.$.model.applyFilter(null, params);
else
this.$.model.clear();
}
}
Controller.$inject = ['$scope', 'vnToken'];