Merge branch 'dev' of https://git.verdnatura.es/salix into dev
This commit is contained in:
commit
7918484156
|
@ -25,7 +25,7 @@ export default class Table {
|
|||
}
|
||||
|
||||
$onChanges() {
|
||||
if (this.model)
|
||||
if (this.model && this.model.filter)
|
||||
this.applyFilter();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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 './sale-checked';
|
||||
import './component';
|
||||
import './sale-tracking';
|
||||
|
|
|
@ -56,6 +56,11 @@
|
|||
"type": "hasMany",
|
||||
"model": "SaleComponent",
|
||||
"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',
|
||||
'client/common/**/*[sS]pec.js',
|
||||
'item/common/**/*[sS]pec.js',
|
||||
'ticket/common/**/*[sS]pec.js',
|
||||
'loopback/common/**/*[sS]pec.js'
|
||||
],
|
||||
helpers: [
|
||||
|
|
Loading…
Reference in New Issue