Merge branch 'dev' of https://git.verdnatura.es/salix into dev

This commit is contained in:
gerard 2018-07-03 15:24:08 +02:00
commit 7918484156
14 changed files with 253 additions and 20 deletions

View File

@ -25,7 +25,7 @@ export default class Table {
}
$onChanges() {
if (this.model)
if (this.model && this.model.filter)
this.applyFilter();
}

View File

@ -13,6 +13,7 @@ vn-table {
display: table-header-group;
vn-th[field] {
position: relative;
cursor: pointer
}
@ -84,6 +85,10 @@ vn-table {
&[number]{
text-align: right;
}
vn-icon.bright, i.bright {
color: #f7931e;
}
}
}
}

View File

@ -195,6 +195,18 @@
"description": "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"
}
}
]
}

View File

@ -1,6 +1,6 @@
<vn-horizontal style="vertical-align:middle;">
<vn-horizontal>
<vn-one>{{::$ctrl.sale.concept}}</vn-one>
<vn-two>
<vn-two class="ellipsize">
<section
class="inline-tag ellipsize" ng-class="{'empty': !fetchedTag.value}"
ng-repeat="fetchedTag in $ctrl.sale.item.tags track by $index"

View File

@ -6,37 +6,31 @@ vn-fetched-tags {
flex-direction: column;
text-align: center;
& .inline-tag {
display: inline-block;
float: none
}
& vn-two {
text-align: center;
max-width: 10.5em;
margin: 0 auto
}
}
}
& vn-one:first-child {
padding-top: 0.36em
& vn-one {
padding-top: 6px
}
& .inline-tag {
background-color: $secondary-font-color;
margin: 0.4em 0.4em 0 0;
display: inline-block;
color: $color-white;
margin-right: 0.4em;
text-align: center;
font-size: 0.8em;
height: 1.25em;
padding: 0.4em;
float: left;
width: 5em
}
& .inline-tag.empty {
background-color: $main-bg
}
& .inline-tag.empty:after {
overflow: hidden;
display: block;
content: ' ';
clear: both
}
}

View File

@ -35,6 +35,7 @@ New : Nuevo
New state: Nuevo estado
Next: Siguiente
Observation type: Tipo de observación
Original quantity: Cantidad original
Package size: Bultos
Package type: Tipo de porte
Phone: Teléfono
@ -58,4 +59,6 @@ Volume: Volumen
Warehouse: Almacén
Worker: Trabajador
VAT: IVA
Hour: Hora
Hour: Hora
Sale tracking: Líneas preparadas
The quantity do not match: Las cantidades no coinciden

View File

@ -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>

View File

@ -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: '<'
}
});

View File

@ -21,3 +21,4 @@ import './tracking/edit';
import './fetched-tags';
import './sale-checked';
import './component';
import './sale-tracking';

View File

@ -56,6 +56,11 @@
"type": "hasMany",
"model": "SaleComponent",
"foreignKey": "saleFk"
}
},
"saleTracking": {
"type": "hasOne",
"model": "SaleTracking",
"foreignKey": "saleFk"
}
}
}

View File

@ -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;
};
};

View File

@ -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();
});
});
});

View File

@ -0,0 +1,3 @@
module.exports = Self => {
require('../methods/sale-tracking/listSaleTracking')(Self);
};

View File

@ -24,6 +24,7 @@ jasmine.loadConfig({
'auth/server/**/*[sS]pec.js',
'client/common/**/*[sS]pec.js',
'item/common/**/*[sS]pec.js',
'ticket/common/**/*[sS]pec.js',
'loopback/common/**/*[sS]pec.js'
],
helpers: [