Added saleTracking section #351. CR: Juan + Javi
This commit is contained in:
parent
d461e8e2fa
commit
7dc1d5c811
|
@ -195,6 +195,18 @@
|
||||||
"description": "Components",
|
"description": "Components",
|
||||||
"icon": "icon-components"
|
"icon": "icon-components"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url" : "/sale-tracking",
|
||||||
|
"state": "ticket.card.saleTracking",
|
||||||
|
"component": "vn-ticket-sale-tracking",
|
||||||
|
"params": {
|
||||||
|
"ticket": "$ctrl.ticket"
|
||||||
|
},
|
||||||
|
"menu": {
|
||||||
|
"description": "Sale tracking",
|
||||||
|
"icon": "assignment"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
|
@ -35,6 +35,7 @@ New : Nuevo
|
||||||
New state: Nuevo estado
|
New state: Nuevo estado
|
||||||
Next: Siguiente
|
Next: Siguiente
|
||||||
Observation type: Tipo de observación
|
Observation type: Tipo de observación
|
||||||
|
Original quantity: Cantidad original
|
||||||
Package size: Bultos
|
Package size: Bultos
|
||||||
Package type: Tipo de porte
|
Package type: Tipo de porte
|
||||||
Phone: Teléfono
|
Phone: Teléfono
|
||||||
|
@ -58,4 +59,6 @@ Volume: Volumen
|
||||||
Warehouse: Almacén
|
Warehouse: Almacén
|
||||||
Worker: Trabajador
|
Worker: Trabajador
|
||||||
VAT: IVA
|
VAT: IVA
|
||||||
Hour: Hora
|
Hour: Hora
|
||||||
|
Sale tracking: Líneas preparadas
|
||||||
|
The quantity do not match: Las cantidades no coinciden
|
|
@ -0,0 +1,62 @@
|
||||||
|
<vn-crud-model
|
||||||
|
vn-id="model"
|
||||||
|
url="/ticket/api/SaleTrackings/listSaleTracking"
|
||||||
|
filter="::$ctrl.filter"
|
||||||
|
limit="20"
|
||||||
|
data="sales"
|
||||||
|
auto-load="true" on-data-change="$ctrl.getTags()">
|
||||||
|
</vn-crud-model>
|
||||||
|
<vn-vertical>
|
||||||
|
<vn-card pad-large>
|
||||||
|
<vn-vertical>
|
||||||
|
<vn-title>Sale tracking</vn-title>
|
||||||
|
<vn-table model="model">
|
||||||
|
<vn-thead>
|
||||||
|
<vn-tr>
|
||||||
|
<vn-th></vn-th>
|
||||||
|
<vn-th field="itemFk" number default-order="DESC">Item</vn-th>
|
||||||
|
<vn-th>Description</vn-th>
|
||||||
|
<vn-th field="quantity">Quantity</vn-th>
|
||||||
|
<vn-th field="originalQuantity">Original quantity</vn-th>
|
||||||
|
<vn-th class="ellipsize" style="max-width: 5em" field="workerFk">Worker</vn-th>
|
||||||
|
<vn-th field="state">State</vn-th>
|
||||||
|
<vn-th field="created">Created</vn-th>
|
||||||
|
</vn-tr>
|
||||||
|
</vn-thead>
|
||||||
|
<vn-tbody>
|
||||||
|
<vn-tr ng-repeat="sale in sales">
|
||||||
|
<vn-td>
|
||||||
|
<vn-icon
|
||||||
|
class="bright"
|
||||||
|
icon="warning"
|
||||||
|
ng-if="sale.quantity != sale.originalQuantity"
|
||||||
|
vn-tooltip="The quantity do not match"></vn-icon>
|
||||||
|
</vn-td>
|
||||||
|
<vn-td number pointer ng-click="$ctrl.showDescriptor($event, sale.itemFk)">
|
||||||
|
{{::sale.itemFk}}
|
||||||
|
</vn-td>
|
||||||
|
<vn-td><vn-fetched-tags sale="sale"/></vn-td>
|
||||||
|
<vn-td>{{::sale.quantity}}</vn-td>
|
||||||
|
<vn-td>{{::sale.originalQuantity}}</vn-td>
|
||||||
|
<vn-td title="{{::sale.firstName}} {{::sale.name}}"
|
||||||
|
class="ellipsize" style="max-width: 5em">
|
||||||
|
{{::sale.firstName}} {{::sale.name}}
|
||||||
|
</vn-td>
|
||||||
|
<vn-td>{{::sale.state}}</vn-td>
|
||||||
|
<vn-td>{{::sale.created | date: 'dd/MM/yyyy HH:mm'}}</vn-td>
|
||||||
|
</vn-tr>
|
||||||
|
</vn-tbody>
|
||||||
|
<vn-empty-rows ng-if="model.data.length === 0" translate>
|
||||||
|
No results
|
||||||
|
</vn-empty-rows>
|
||||||
|
</vn-table>
|
||||||
|
</vn-vertical>
|
||||||
|
</vn-card>
|
||||||
|
|
||||||
|
<vn-pagination
|
||||||
|
model="model"
|
||||||
|
scroll-selector="ui-view">
|
||||||
|
</vn-pagination>
|
||||||
|
</vn-vertical>
|
||||||
|
<vn-item-descriptor-popover vn-id="descriptor"></vn-item-descriptor-popover>
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
import ngModule from '../module';
|
||||||
|
|
||||||
|
class Controller {
|
||||||
|
constructor($scope, $state, $http) {
|
||||||
|
this.$scope = $scope;
|
||||||
|
this.$http = $http;
|
||||||
|
this.filter = {
|
||||||
|
where: {ticketFk: $state.params.id}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
showDescriptor(event, itemFk) {
|
||||||
|
this.$scope.descriptor.itemFk = itemFk;
|
||||||
|
this.$scope.descriptor.parent = event.target;
|
||||||
|
this.$scope.descriptor.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
onDescriptorLoad() {
|
||||||
|
this.$scope.popover.relocate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Controller.$inject = ['$scope', '$state', '$http'];
|
||||||
|
|
||||||
|
ngModule.component('vnTicketSaleTracking', {
|
||||||
|
template: require('./index.html'),
|
||||||
|
controller: Controller,
|
||||||
|
bindings: {
|
||||||
|
ticket: '<'
|
||||||
|
}
|
||||||
|
});
|
|
@ -21,3 +21,4 @@ import './tracking/edit';
|
||||||
import './fetched-tags';
|
import './fetched-tags';
|
||||||
import './sale-checked';
|
import './sale-checked';
|
||||||
import './component';
|
import './component';
|
||||||
|
import './sale-tracking';
|
||||||
|
|
|
@ -56,6 +56,11 @@
|
||||||
"type": "hasMany",
|
"type": "hasMany",
|
||||||
"model": "SaleComponent",
|
"model": "SaleComponent",
|
||||||
"foreignKey": "saleFk"
|
"foreignKey": "saleFk"
|
||||||
}
|
},
|
||||||
|
"saleTracking": {
|
||||||
|
"type": "hasOne",
|
||||||
|
"model": "SaleTracking",
|
||||||
|
"foreignKey": "saleFk"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethod('listSaleTracking', {
|
||||||
|
description: 'Returns all ticket sale trackings',
|
||||||
|
accessType: 'READ',
|
||||||
|
accepts: [{
|
||||||
|
arg: 'filter',
|
||||||
|
type: 'Object',
|
||||||
|
required: false,
|
||||||
|
description: 'Filter defining where and paginated data',
|
||||||
|
http: {source: 'query'}
|
||||||
|
}],
|
||||||
|
returns: {
|
||||||
|
type: ["Object"],
|
||||||
|
root: true
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
path: `/listSaleTracking`,
|
||||||
|
verb: 'get'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.listSaleTracking = async filter => {
|
||||||
|
let where = '';
|
||||||
|
let limit = '';
|
||||||
|
let order = '';
|
||||||
|
let params;
|
||||||
|
|
||||||
|
if (filter) {
|
||||||
|
let connector = Self.dataSource.connector;
|
||||||
|
if (filter.where) {
|
||||||
|
where = 'WHERE s.ticketFk = ?';
|
||||||
|
params = [filter.where.ticketFk];
|
||||||
|
}
|
||||||
|
|
||||||
|
limit = connector._buildLimit(null, filter.limit, filter.skip);
|
||||||
|
order = connector.buildOrderBy('Item', filter.order);
|
||||||
|
}
|
||||||
|
|
||||||
|
let query = `SELECT
|
||||||
|
st.id,
|
||||||
|
s.quantity,
|
||||||
|
s.concept,
|
||||||
|
s.itemFk,
|
||||||
|
st.originalQuantity,
|
||||||
|
st.created,
|
||||||
|
st.workerFk,
|
||||||
|
w.firstName,
|
||||||
|
w.name,
|
||||||
|
ste.name AS state
|
||||||
|
FROM saleTracking st
|
||||||
|
JOIN sale s ON s.id = st.saleFK
|
||||||
|
JOIN worker w ON w.id = st.workerFk
|
||||||
|
JOIN ticketState ts ON ts.ticketFk = s.ticketFk
|
||||||
|
JOIN state ste ON ste.id = ts.stateFK ${where} ${order} ${limit}`;
|
||||||
|
|
||||||
|
let trackings = await Self.rawSql(query, params);
|
||||||
|
|
||||||
|
let salesFilter = {
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
relation: 'item',
|
||||||
|
scope: {
|
||||||
|
fields: ['itemFk', 'name'],
|
||||||
|
include: {
|
||||||
|
relation: 'tags',
|
||||||
|
scope: {
|
||||||
|
fields: ['tagFk', 'value'],
|
||||||
|
include: {
|
||||||
|
relation: 'tag',
|
||||||
|
scope: {
|
||||||
|
fields: ['name']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
limit: 6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
where: {ticketFk: filter.where.ticketFk}
|
||||||
|
};
|
||||||
|
|
||||||
|
let sales = await Self.app.models.Sale.find(salesFilter);
|
||||||
|
|
||||||
|
trackings.forEach(tracking => {
|
||||||
|
sales.forEach(sale => {
|
||||||
|
if (tracking.itemFk == sale.itemFk)
|
||||||
|
tracking.item = sale.item();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return trackings;
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,22 @@
|
||||||
|
const app = require(`${servicesDir}/ticket/server/server`);
|
||||||
|
|
||||||
|
describe('ticket listSaleTracking()', () => {
|
||||||
|
it('should call the listSaleTracking method and return the response', done => {
|
||||||
|
let filter = {where: {ticketFk: 1}};
|
||||||
|
app.models.SaleTracking.listSaleTracking(filter)
|
||||||
|
.then(response => {
|
||||||
|
expect(response[0].concept).toEqual('Gem of Time');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should call the listSaleTracking method and return zero if doesn't have lines`, done => {
|
||||||
|
let filter = {where: {ticketFk: 2}};
|
||||||
|
app.models.SaleTracking.listSaleTracking(filter)
|
||||||
|
.then(response => {
|
||||||
|
expect(response.length).toEqual(0);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
module.exports = Self => {
|
||||||
|
require('../methods/sale-tracking/listSaleTracking')(Self);
|
||||||
|
};
|
|
@ -24,6 +24,7 @@ jasmine.loadConfig({
|
||||||
'auth/server/**/*[sS]pec.js',
|
'auth/server/**/*[sS]pec.js',
|
||||||
'client/common/**/*[sS]pec.js',
|
'client/common/**/*[sS]pec.js',
|
||||||
'item/common/**/*[sS]pec.js',
|
'item/common/**/*[sS]pec.js',
|
||||||
|
'ticket/common/**/*[sS]pec.js',
|
||||||
'loopback/common/**/*[sS]pec.js'
|
'loopback/common/**/*[sS]pec.js'
|
||||||
],
|
],
|
||||||
helpers: [
|
helpers: [
|
||||||
|
|
Loading…
Reference in New Issue