invoiceOut summary tickets pagination + refactor
This commit is contained in:
parent
7775eb7951
commit
f36b54f97b
|
@ -1,14 +1,22 @@
|
|||
const mergeFilters = require('vn-loopback/util/filter').mergeFilters;
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethod('getBuys', {
|
||||
description: 'Returns buys for one entry',
|
||||
accessType: 'READ',
|
||||
accepts: {
|
||||
accepts: [{
|
||||
arg: 'id',
|
||||
type: 'number',
|
||||
required: true,
|
||||
description: 'The entry id',
|
||||
http: {source: 'path'}
|
||||
},
|
||||
{
|
||||
arg: 'filter',
|
||||
type: 'object',
|
||||
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string'
|
||||
}
|
||||
],
|
||||
returns: {
|
||||
type: ['Object'],
|
||||
root: true
|
||||
|
@ -19,14 +27,14 @@ module.exports = Self => {
|
|||
}
|
||||
});
|
||||
|
||||
Self.getBuys = async(id, options) => {
|
||||
Self.getBuys = async(id, filter, options) => {
|
||||
const models = Self.app.models;
|
||||
let myOptions = {};
|
||||
|
||||
if (typeof options == 'object')
|
||||
Object.assign(myOptions, options);
|
||||
|
||||
const filter = {
|
||||
let defaultFilter = {
|
||||
where: {entryFk: id},
|
||||
fields: [
|
||||
'id',
|
||||
|
@ -74,6 +82,8 @@ module.exports = Self => {
|
|||
}
|
||||
};
|
||||
|
||||
return models.Buy.find(filter, myOptions);
|
||||
defaultFilter = mergeFilters(defaultFilter, filter);
|
||||
|
||||
return models.Buy.find(defaultFilter, myOptions);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
<vn-crud-model
|
||||
vn-id="buysModel"
|
||||
url="Entries/{{$ctrl.$params.id}}/getBuys"
|
||||
limit="5"
|
||||
data="buys"
|
||||
auto-load="true">
|
||||
</vn-crud-model>
|
||||
<vn-card class="summary">
|
||||
<h5>
|
||||
<a ng-if="::$ctrl.entryData.id"
|
||||
|
@ -95,7 +102,7 @@
|
|||
<th translate center expand field="price3">Packing price</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody ng-repeat="line in $ctrl.buys">
|
||||
<tbody ng-repeat="line in buys">
|
||||
<tr>
|
||||
<td center title="{{::line.quantity}}">{{::line.quantity}}</td>
|
||||
<td center title="{{::line.stickers | dashIfEmpty}}">{{::line.stickers | dashIfEmpty}}</td>
|
||||
|
@ -156,6 +163,10 @@
|
|||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<vn-pagination
|
||||
model="buysModel"
|
||||
class="vn-pt-xs">
|
||||
</vn-pagination>
|
||||
</vn-auto>
|
||||
</vn-horizontal>
|
||||
</vn-card>
|
||||
|
|
|
@ -10,10 +10,8 @@ class Controller extends Summary {
|
|||
set entry(value) {
|
||||
this._entry = value;
|
||||
|
||||
if (value && value.id) {
|
||||
if (value && value.id)
|
||||
this.getEntryData();
|
||||
this.getBuys();
|
||||
}
|
||||
}
|
||||
|
||||
getEntryData() {
|
||||
|
@ -21,12 +19,6 @@ class Controller extends Summary {
|
|||
this.entryData = response.data;
|
||||
});
|
||||
}
|
||||
|
||||
getBuys() {
|
||||
return this.$http.get(`Entries/${this.entry.id}/getBuys`).then(response => {
|
||||
this.buys = response.data;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.vnComponent('vnEntrySummary', {
|
||||
|
|
|
@ -46,20 +46,4 @@ describe('component vnEntrySummary', () => {
|
|||
expect(controller.entryData).toEqual('I am the entryData');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getBuys()', () => {
|
||||
it('should perform a get asking for the buys of an entry', () => {
|
||||
controller._entry = {id: 999};
|
||||
|
||||
const thatQuery = `Entries/${controller._entry.id}/getEntry`;
|
||||
const query = `Entries/${controller._entry.id}/getBuys`;
|
||||
|
||||
$httpBackend.whenGET(thatQuery).respond('My Entries');
|
||||
$httpBackend.expectGET(query).respond('Some buys');
|
||||
controller.getBuys();
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.buys).toEqual('Some buys');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
const mergeFilters = require('vn-loopback/util/filter').mergeFilters;
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethod('getTickets', {
|
||||
description: 'Returns tickets for one invoiceOut',
|
||||
accessType: 'READ',
|
||||
accepts: [{
|
||||
arg: 'id',
|
||||
type: 'number',
|
||||
required: true,
|
||||
description: 'The invoiceOut id',
|
||||
http: {source: 'path'}
|
||||
},
|
||||
{
|
||||
arg: 'filter',
|
||||
type: 'object',
|
||||
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string'
|
||||
}
|
||||
],
|
||||
returns: {
|
||||
type: ['object'],
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/:id/getTickets`,
|
||||
verb: 'GET'
|
||||
}
|
||||
});
|
||||
|
||||
Self.getTickets = async(id, filter, options) => {
|
||||
const models = Self.app.models;
|
||||
let myOptions = {};
|
||||
|
||||
if (typeof options == 'object')
|
||||
Object.assign(myOptions, options);
|
||||
|
||||
const invoiceOut = await models.InvoiceOut.findById(id, {fields: 'ref'}, myOptions);
|
||||
|
||||
let defaultFilter = {
|
||||
where: {refFk: invoiceOut.ref},
|
||||
fields: [
|
||||
'id',
|
||||
'nickname',
|
||||
'shipped',
|
||||
'totalWithVat',
|
||||
'clientFk'
|
||||
]
|
||||
|
||||
};
|
||||
|
||||
defaultFilter = mergeFilters(defaultFilter, filter);
|
||||
|
||||
return models.Ticket.find(defaultFilter, myOptions);
|
||||
};
|
||||
};
|
|
@ -0,0 +1,10 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
|
||||
describe('entry getTickets()', () => {
|
||||
const invoiceOutId = 4;
|
||||
it('should get the ticket of an invoiceOut', async() => {
|
||||
const result = await app.models.InvoiceOut.getTickets(invoiceOutId);
|
||||
|
||||
expect(result.length).toEqual(1);
|
||||
});
|
||||
});
|
|
@ -7,14 +7,6 @@ describe('invoiceOut summary()', () => {
|
|||
expect(result.invoiceOut.id).toEqual(1);
|
||||
});
|
||||
|
||||
it(`should return a summary object containing data from it's tickets`, async() => {
|
||||
const summary = await app.models.InvoiceOut.summary(1);
|
||||
const tickets = summary.invoiceOut.tickets();
|
||||
|
||||
expect(summary.invoiceOut.ref).toEqual('T1111111');
|
||||
expect(tickets.length).toEqual(2);
|
||||
});
|
||||
|
||||
it(`should return a summary object containing it's supplier country`, async() => {
|
||||
const summary = await app.models.InvoiceOut.summary(1);
|
||||
const supplier = summary.invoiceOut.supplier();
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethod('summary', {
|
||||
description: 'The invoiceOut summary',
|
||||
|
@ -22,7 +20,6 @@ module.exports = Self => {
|
|||
});
|
||||
|
||||
Self.summary = async id => {
|
||||
const conn = Self.dataSource.connector;
|
||||
let summary = {};
|
||||
|
||||
const filter = {
|
||||
|
@ -57,54 +54,20 @@ module.exports = Self => {
|
|||
scope: {
|
||||
fields: ['id', 'socialName']
|
||||
}
|
||||
},
|
||||
{
|
||||
relation: 'tickets'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
summary.invoiceOut = await Self.app.models.InvoiceOut.findOne(filter);
|
||||
|
||||
let stmts = [];
|
||||
|
||||
stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.ticket');
|
||||
|
||||
stmt = new ParameterizedSQL(`
|
||||
CREATE TEMPORARY TABLE tmp.ticket
|
||||
(INDEX (ticketFk)) ENGINE = MEMORY
|
||||
SELECT id ticketFk FROM vn.ticket WHERE refFk=?`, [summary.invoiceOut.ref]);
|
||||
stmts.push(stmt);
|
||||
|
||||
stmts.push('CALL ticketGetTotal()');
|
||||
|
||||
let ticketTotalsIndex = stmts.push('SELECT * FROM tmp.ticketTotal') - 1;
|
||||
|
||||
stmt = new ParameterizedSQL(`
|
||||
const invoiceOutTaxes = await Self.rawSql(`
|
||||
SELECT iot.* , pgc.*, IF(pe.equFk IS NULL, taxableBase, 0) AS Base, pgc.rate / 100 as vatPercent
|
||||
FROM vn.invoiceOutTax iot
|
||||
JOIN vn.pgc ON pgc.code = iot.pgcFk
|
||||
LEFT JOIN vn.pgcEqu pe ON pe.equFk = pgc.code
|
||||
WHERE invoiceOutFk = ?`, [summary.invoiceOut.id]);
|
||||
let invoiceOutTaxesIndex = stmts.push(stmt) - 1;
|
||||
|
||||
stmts.push(
|
||||
`DROP TEMPORARY TABLE
|
||||
tmp.ticket,
|
||||
tmp.ticketTotal`);
|
||||
|
||||
let sql = ParameterizedSQL.join(stmts, ';');
|
||||
let result = await conn.executeStmt(sql);
|
||||
|
||||
totalMap = {};
|
||||
for (ticketTotal of result[ticketTotalsIndex])
|
||||
totalMap[ticketTotal.ticketFk] = ticketTotal.total;
|
||||
|
||||
summary.invoiceOut.tickets().forEach(ticket => {
|
||||
ticket.total = totalMap[ticket.id];
|
||||
});
|
||||
|
||||
summary.invoiceOut.taxesBreakdown = result[invoiceOutTaxesIndex];
|
||||
summary.invoiceOut.taxesBreakdown = invoiceOutTaxes;
|
||||
|
||||
return summary;
|
||||
};
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
module.exports = Self => {
|
||||
require('../methods/invoiceOut/filter')(Self);
|
||||
require('../methods/invoiceOut/summary')(Self);
|
||||
require('../methods/invoiceOut/getTickets')(Self);
|
||||
require('../methods/invoiceOut/download')(Self);
|
||||
require('../methods/invoiceOut/delete')(Self);
|
||||
require('../methods/invoiceOut/book')(Self);
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
<vn-crud-model
|
||||
vn-id="ticketsModel"
|
||||
url="InvoiceOuts/{{$ctrl.$params.id}}/getTickets"
|
||||
limit="10"
|
||||
data="tickets"
|
||||
auto-load="true">
|
||||
</vn-crud-model>
|
||||
<vn-card class="summary">
|
||||
<h5>
|
||||
<a ng-if="::$ctrl.summary.invoiceOut.id"
|
||||
|
@ -59,7 +66,7 @@
|
|||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="ticket in $ctrl.summary.invoiceOut.tickets">
|
||||
<vn-tr ng-repeat="ticket in tickets">
|
||||
<vn-td number>
|
||||
<span
|
||||
ng-click="ticketDescriptor.show($event, ticket.id)"
|
||||
|
@ -75,10 +82,14 @@
|
|||
</span>
|
||||
</vn-td>
|
||||
<vn-td expand>{{ticket.shipped | date: 'dd/MM/yyyy' | dashIfEmpty}}</vn-td>
|
||||
<vn-td number>{{ticket.total | currency: 'EUR': 2}}</vn-td>
|
||||
<vn-td number>{{ticket.totalWithVat | currency: 'EUR': 2}}</vn-td>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
<vn-pagination
|
||||
model="ticketsModel"
|
||||
class="vn-pt-xs">
|
||||
</vn-pagination>
|
||||
</vn-auto>
|
||||
</vn-horizontal>
|
||||
</vn-card>
|
||||
|
|
|
@ -12,79 +12,98 @@ module.exports = Self => {
|
|||
arg: 'ctx',
|
||||
type: 'object',
|
||||
http: {source: 'context'}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'filter',
|
||||
type: 'object',
|
||||
description: `Filter defining where, order, offset, and limit - must be a JSON-encoded string`
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'search',
|
||||
type: 'string',
|
||||
description: `If it's and number searchs by id, otherwise it searchs by nickname`
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'from',
|
||||
type: 'date',
|
||||
description: `The from date filter`
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'to',
|
||||
type: 'date',
|
||||
description: `The to date filter`
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'nickname',
|
||||
type: 'string',
|
||||
description: `The nickname filter`
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'id',
|
||||
type: 'number',
|
||||
description: `The ticket id filter`
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'clientFk',
|
||||
type: 'number',
|
||||
description: `The client id filter`
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'agencyModeFk',
|
||||
type: 'number',
|
||||
description: `The agency mode id filter`
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'warehouseFk',
|
||||
type: 'number',
|
||||
description: `The warehouse id filter`
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'salesPersonFk',
|
||||
type: 'number',
|
||||
description: `The salesperson id filter`
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'provinceFk',
|
||||
type: 'number',
|
||||
description: `The province id filter`
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'stateFk',
|
||||
type: 'number',
|
||||
description: `The state id filter`
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'myTeam',
|
||||
type: 'boolean',
|
||||
description: `Whether to show only tickets for the current logged user team (For now it shows only the current user tickets)`
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'problems',
|
||||
type: 'boolean',
|
||||
description: `Whether to show only tickets with problems`
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'pending',
|
||||
type: 'boolean',
|
||||
description: `Whether to show only tickets with state 'Pending'`
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'mine',
|
||||
type: 'boolean',
|
||||
description: `Whether to show only tickets for the current logged user`
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'orderFk',
|
||||
type: 'number',
|
||||
description: `The order id filter`
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'refFk',
|
||||
type: 'string',
|
||||
description: `The invoice reference filter`
|
||||
}, {
|
||||
},
|
||||
{
|
||||
arg: 'alertLevel',
|
||||
type: 'number',
|
||||
description: `The alert level of the tickets`
|
||||
|
|
Loading…
Reference in New Issue