Ticket summary
This commit is contained in:
parent
a82260d4fb
commit
4b8ae91705
|
@ -56,7 +56,7 @@
|
|||
}
|
||||
|
||||
.buttons {
|
||||
margin: 0
|
||||
margin-top: 2em
|
||||
}
|
||||
|
||||
vn-check label span {
|
||||
|
|
|
@ -37,15 +37,18 @@
|
|||
{
|
||||
"url" : "/data",
|
||||
"state": "ticket.card.data",
|
||||
"component": "ui-view",
|
||||
"abstract": true
|
||||
"component": "vn-ticket-data",
|
||||
"abstract": true,
|
||||
"params": {
|
||||
"ticket": "$ctrl.ticket"
|
||||
}
|
||||
},
|
||||
{
|
||||
"url" : "/step-one",
|
||||
"state": "ticket.card.data.stepOne",
|
||||
"component": "vn-ticket-data-step-one",
|
||||
"params": {
|
||||
"ticket": "$ctrl.ticket"
|
||||
"ticket": "$ctrl.data"
|
||||
},
|
||||
"menu": {
|
||||
"description": "Basic data",
|
||||
|
@ -55,12 +58,18 @@
|
|||
{
|
||||
"url" : "/step-two",
|
||||
"state": "ticket.card.data.stepTwo",
|
||||
"component": "vn-ticket-data-step-two"
|
||||
"component": "vn-ticket-data-step-two",
|
||||
"params": {
|
||||
"ticket": "$ctrl.data"
|
||||
}
|
||||
},
|
||||
{
|
||||
"url" : "/step-three",
|
||||
"state": "ticket.card.data.stepThree",
|
||||
"component": "vn-ticket-data-step-three"
|
||||
"component": "vn-ticket-data-step-three",
|
||||
"params": {
|
||||
"ticket": "$ctrl.data"
|
||||
}
|
||||
},
|
||||
{
|
||||
"url": "/observation",
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
<vn-button-bar>
|
||||
<vn-step-control
|
||||
step-count="10"
|
||||
steps="[
|
||||
{name: 'Basic data', state: 'ticket.card.data.stepOne'},
|
||||
{name: 'Price gap', state: 'ticket.card.data.stepTwo'},
|
||||
{name: 'Step 3', state: 'ticket.card.data.stepThree'}]"
|
||||
on-step-change="$ctrl.onStepChange(state)"
|
||||
on-step-end="$ctrl.onSubmit()">
|
||||
</vn-step-control>
|
||||
</vn-button-bar>
|
||||
<ui-view></ui-view>
|
|
@ -0,0 +1,32 @@
|
|||
import ngModule from '../module';
|
||||
|
||||
class Controller {
|
||||
constructor($scope, $state) {
|
||||
this.$scope = $scope;
|
||||
this.$state = $state;
|
||||
}
|
||||
|
||||
set ticket(data) {
|
||||
this.data = Object.assign({}, data);
|
||||
}
|
||||
|
||||
onSubmit() {
|
||||
//post data
|
||||
alert('Data saved');
|
||||
console.log(this.data);
|
||||
}
|
||||
|
||||
onStepChange(state) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$scope', '$state'];
|
||||
|
||||
ngModule.component('vnTicketData', {
|
||||
template: require('./data.html'),
|
||||
bindings: {
|
||||
ticket: '<'
|
||||
},
|
||||
controller: Controller
|
||||
});
|
|
@ -1,6 +1,6 @@
|
|||
<a
|
||||
ui-sref="ticket.card.summary({ id: {{::$ctrl.ticket.id}} })"
|
||||
translate-attr="{title: 'View client'}"
|
||||
translate-attr="{title: 'View ticket'}"
|
||||
class="vn-list-item">
|
||||
<vn-horizontal ng-click="$ctrl.onClick($event)">
|
||||
<vn-one>
|
||||
|
@ -9,8 +9,9 @@
|
|||
</vn-one>
|
||||
<vn-horizontal class="buttons">
|
||||
<vn-icon
|
||||
ng-click="$ctrl.preview($event)"
|
||||
vn-tooltip="Preview"
|
||||
icon="icon-preview">
|
||||
icon="desktop_windows">
|
||||
</vn-icon>
|
||||
</vn-horizontal>
|
||||
</vn-horizontal>
|
||||
|
|
|
@ -8,6 +8,7 @@ class Controller {
|
|||
|
||||
preview(event) {
|
||||
event.preventDefault();
|
||||
this.list.openSummary(this.ticket);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,5 +17,8 @@ ngModule.component('vnTicketItem', {
|
|||
template: require('./ticket-item.html'),
|
||||
bindings: {
|
||||
ticket: '<'
|
||||
},
|
||||
require: {
|
||||
list: '^vnTicketList'
|
||||
}
|
||||
});
|
||||
|
|
|
@ -22,3 +22,9 @@
|
|||
<a ui-sref="ticket.create" fixed-bottom-right>
|
||||
<vn-float-button icon="add"></vn-float-button>
|
||||
</a>
|
||||
<vn-dialog class="dialog-summary"
|
||||
vn-id="dialog-summary-ticket">
|
||||
<tpl-body>
|
||||
<vn-ticket-summary ticket="$ctrl.ticketSelected"></vn-ticket-summary>
|
||||
</tpl-body>
|
||||
</vn-dialog>
|
|
@ -3,11 +3,22 @@ import './ticket-item';
|
|||
import './style.scss';
|
||||
|
||||
export default class Controller {
|
||||
constructor($scope) {
|
||||
this.$scope = $scope;
|
||||
this.ticketSelected = null;
|
||||
}
|
||||
|
||||
search(index) {
|
||||
index.accept();
|
||||
}
|
||||
|
||||
openSummary(ticket) {
|
||||
this.ticketSelected = ticket;
|
||||
this.$scope.dialogSummaryTicket.show();
|
||||
}
|
||||
}
|
||||
Controller.$inject = [];
|
||||
|
||||
Controller.$inject = ['$scope'];
|
||||
|
||||
ngModule.component('vnTicketList', {
|
||||
template: require('./ticket-list.html'),
|
||||
|
|
|
@ -39,3 +39,5 @@ Is checked: Comprobado
|
|||
Volume: Volumen
|
||||
m³ per unit: m³ por unidad
|
||||
m³ per quantity: m³ por cantidad
|
||||
New price: Nuevo precio
|
||||
Price gap: Diferencia de precio
|
|
@ -1,9 +1,69 @@
|
|||
<vn-card class="summary">
|
||||
<vn-vertical pad-medium>
|
||||
<vn-auto>
|
||||
<h5 text-center pad-small-v class="tittle">Ticket Summary</h5>
|
||||
<h5 text-center pad-small-v class="tittle">{{$ctrl.summary.id}} - {{$ctrl.summary.client.name}} - {{$ctrl.summary.nickname}}</h5>
|
||||
</vn-auto>
|
||||
<vn-horizontal>
|
||||
<vn-one>
|
||||
<p><vn-label translate>State</vn-label> {{$ctrl.summary.ticketTracking.state.name}}</p>
|
||||
<p>
|
||||
<vn-label translate>Comercial Name</vn-label>
|
||||
{{$ctrl.summary.client.salesPerson.firstName}}
|
||||
{{$ctrl.summary.client.salesPerson.name}}
|
||||
</p>
|
||||
<p><vn-label translate>Agency</vn-label> {{$ctrl.summary.agencyMode.name}}</p>
|
||||
<p><vn-label translate>Warehouse</vn-label> {{$ctrl.summary.warehouse.name}}</p>
|
||||
<p><vn-label translate>Packages</vn-label> {{$ctrl.summary.packages}}</p>
|
||||
</vn-one>
|
||||
<vn-one>
|
||||
<p><vn-label translate>Shipped</vn-label> {{$ctrl.summary.shipped | date: 'dd/MM/yyyy'}}</p>
|
||||
<p><vn-label translate>Landed</vn-label> {{$ctrl.summary.landed | date: 'dd/MM/yyyy'}}</p>
|
||||
<p><vn-label translate>Route</vn-label> {{$ctrl.summary.routeFk}}</p>
|
||||
<p><vn-label translate>Address</vn-label> {{$ctrl.summary.address.street}}</p>
|
||||
<p><vn-label translate>Phone</vn-label> {{$ctrl.summary.address.phone}}</p>
|
||||
</vn-one>
|
||||
<vn-one>
|
||||
<p ng-repeat="note in $ctrl.summary.notes track by note.id">
|
||||
<vn-label translate>{{note.observationType.description}}</vn-label>
|
||||
{{note.description}}
|
||||
</p>
|
||||
</vn-one>
|
||||
<vn-one>
|
||||
<p><vn-label translate>Subtotal</vn-label> {{0}}</p>
|
||||
<p><vn-label translate>IVA(n%)</vn-label> {{0}}</p>
|
||||
<p><vn-label translate>TOTAL</vn-label> {{0}}</p>
|
||||
</vn-one>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<table class="vn-grid">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th number translate>Item</th>
|
||||
<th translate style="text-align:center">Description</th>
|
||||
<th number translate>Quantity</th>
|
||||
<th number translate>Price</th>
|
||||
<th number translate>Discount</th>
|
||||
<th number translate>Amount</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="sale in $ctrl.summary.sales track by sale.id">
|
||||
<td>
|
||||
<!-- <i pointer
|
||||
class="material-icons"
|
||||
vn-tooltip="delete expedition"
|
||||
ng-click="$ctrl.deleteExpedition(expedition)">warning</i> -->
|
||||
</td>
|
||||
<td number>{{("000000"+sale.itemFk).slice(-6)}}</td>
|
||||
<td><vn-fetched-tags sale="sale"/></td>
|
||||
<td number>{{::sale.quantity}}</td>
|
||||
<td number>{{::sale.price | currency:'€':2}}</td>
|
||||
<td number>{{::sale.discount}} %</td>
|
||||
<td number>{{::sale.quantity * sale.price | currency:'€':2}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</vn-horizontal>
|
||||
</vn-vertical>
|
||||
</vn-card>
|
|
@ -1,11 +1,26 @@
|
|||
import ngModule from '../module';
|
||||
|
||||
class TicketSummary {}
|
||||
TicketSummary.$inject = [];
|
||||
class Controller {
|
||||
constructor($http) {
|
||||
this.$http = $http;
|
||||
}
|
||||
|
||||
$onChanges() {
|
||||
if (!this.ticket)
|
||||
return;
|
||||
|
||||
this.$http.get(`/client/api/Tickets/${this.ticket.id}/summary`).then(res => {
|
||||
if (res && res.data)
|
||||
this.summary = res.data;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$http'];
|
||||
|
||||
ngModule.component('vnTicketSummary', {
|
||||
template: require('./ticket-summary.html'),
|
||||
controller: TicketSummary,
|
||||
controller: Controller,
|
||||
bindings: {
|
||||
ticket: '<'
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
module.exports = Self => {
|
||||
Self.installMethod('filter', filterParams);
|
||||
|
||||
function filterParams(params) {
|
||||
return {
|
||||
where: {
|
||||
ticketFk: params.ticketFk
|
||||
},
|
||||
skip: (params.page - 1) * params.size,
|
||||
limit: params.size,
|
||||
order: params.order || 'concept ASC',
|
||||
include: [{
|
||||
relation: "item",
|
||||
scope: {
|
||||
include: {
|
||||
relation: "itemTag",
|
||||
scope: {
|
||||
fields: ["tagFk", "value"],
|
||||
include: {
|
||||
relation: "tag",
|
||||
scope: {
|
||||
fields: ["name"]
|
||||
}
|
||||
},
|
||||
limit: 6
|
||||
}
|
||||
},
|
||||
fields: ["itemFk", "name"]
|
||||
}
|
||||
},
|
||||
{
|
||||
relation: "isChecked",
|
||||
scope: {
|
||||
fields: ["isChecked"]
|
||||
}
|
||||
}]
|
||||
};
|
||||
}
|
||||
};
|
|
@ -0,0 +1,51 @@
|
|||
module.exports = Self => {
|
||||
Self.remoteMethod('priceGap', {
|
||||
description: 'Returns a sale price gap',
|
||||
accessType: 'READ',
|
||||
accepts: [{
|
||||
arg: 'ticketFk',
|
||||
type: 'number',
|
||||
required: true,
|
||||
description: 'ticket id',
|
||||
http: {source: 'path'}
|
||||
}],
|
||||
returns: {
|
||||
type: ['Object'],
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/:ticketFk/priceGap`,
|
||||
verb: 'GET'
|
||||
}
|
||||
});
|
||||
|
||||
Self.priceGap = async ticketFk => {
|
||||
let filter = {
|
||||
where: {
|
||||
ticketFk: ticketFk
|
||||
},
|
||||
order: 'concept ASC',
|
||||
include: [{
|
||||
relation: 'item',
|
||||
scope: {
|
||||
include: {
|
||||
relation: 'itemTag',
|
||||
scope: {
|
||||
fields: ['tagFk', 'value'],
|
||||
include: {
|
||||
relation: 'tag',
|
||||
scope: {
|
||||
fields: ['name']
|
||||
}
|
||||
},
|
||||
limit: 6
|
||||
}
|
||||
},
|
||||
fields: ['itemFk', 'name']
|
||||
}
|
||||
}]
|
||||
};
|
||||
|
||||
return await Self.find(filter);
|
||||
};
|
||||
};
|
|
@ -0,0 +1,120 @@
|
|||
module.exports = Self => {
|
||||
Self.remoteMethod('summary', {
|
||||
description: 'Returns a ticket summary',
|
||||
accessType: 'READ',
|
||||
accepts: [{
|
||||
arg: 'id',
|
||||
type: 'number',
|
||||
required: true,
|
||||
description: 'ticket id',
|
||||
http: {source: 'path'}
|
||||
}],
|
||||
returns: {
|
||||
type: [this.modelName],
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/:id/summary`,
|
||||
verb: 'GET'
|
||||
}
|
||||
});
|
||||
|
||||
Self.summary = async ticketFk => {
|
||||
let models = Self.app.models;
|
||||
let summaryObj = await getTicketData(Self, ticketFk);
|
||||
|
||||
summaryObj.sales = await getSales(models.Sale, ticketFk);
|
||||
|
||||
return summaryObj;
|
||||
};
|
||||
|
||||
async function getTicketData(Self, ticketFk) {
|
||||
let filter = {
|
||||
include: [
|
||||
{relation: 'warehouse', scope: {fields: ['name']}},
|
||||
{relation: 'agencyMode', scope: {fields: ['name']}},
|
||||
{
|
||||
relation: 'client',
|
||||
scope: {
|
||||
fields: ['salesPersonFk', 'name'],
|
||||
include: {
|
||||
relation: 'salesPerson',
|
||||
fields: ['firstName', 'name']
|
||||
}
|
||||
}
|
||||
},
|
||||
{relation: 'address', scope: {fields: ['street', 'phone']}},
|
||||
{
|
||||
relation: 'notes',
|
||||
scope: {
|
||||
fields: ['id', 'observationTypeFk', 'description'],
|
||||
include: {
|
||||
relation: 'observationType',
|
||||
fields: ['description']
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
relation: 'ticketTracking',
|
||||
scope: {
|
||||
fields: ['stateFk'],
|
||||
include: {
|
||||
relation: 'state',
|
||||
fields: ['name']
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
where: {id: ticketFk}
|
||||
};
|
||||
|
||||
return await Self.findOne(filter);
|
||||
}
|
||||
|
||||
async function getSales(Sale, ticketFk) {
|
||||
let filter = {
|
||||
where: {
|
||||
ticketFk: ticketFk
|
||||
},
|
||||
order: 'concept ASC',
|
||||
include: [{
|
||||
relation: 'item',
|
||||
scope: {
|
||||
include: {
|
||||
relation: 'itemTag',
|
||||
scope: {
|
||||
fields: ['tagFk', 'value'],
|
||||
include: {
|
||||
relation: 'tag',
|
||||
scope: {
|
||||
fields: ['name']
|
||||
}
|
||||
},
|
||||
limit: 6
|
||||
}
|
||||
},
|
||||
fields: ['itemFk', 'name']
|
||||
}
|
||||
},
|
||||
{
|
||||
relation: 'isChecked',
|
||||
scope: {
|
||||
fields: ['isChecked']
|
||||
}
|
||||
}]
|
||||
};
|
||||
|
||||
return await Sale.find(filter);
|
||||
}
|
||||
|
||||
/* async function getRecoveries(recovery, clientId) {
|
||||
let filter = {
|
||||
where: {
|
||||
and: [{clientFk: clientId}, {or: [{finished: null}, {finished: {gt: Date.now()}}]}]
|
||||
},
|
||||
limit: 1
|
||||
};
|
||||
|
||||
return await recovery.findOne(filter);
|
||||
} */
|
||||
};
|
|
@ -0,0 +1,4 @@
|
|||
module.exports = function(Self) {
|
||||
require('../methods/sale/filter')(Self);
|
||||
require('../methods/sale/priceGap')(Self);
|
||||
};
|
|
@ -0,0 +1,56 @@
|
|||
{
|
||||
"name": "Sale",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "sale"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"id": true,
|
||||
"type": "Number",
|
||||
"description": "Identifier"
|
||||
},
|
||||
"concept": {
|
||||
"type": "String"
|
||||
},
|
||||
"quantity": {
|
||||
"type": "Number"
|
||||
},
|
||||
"price": {
|
||||
"type": "Number"
|
||||
},
|
||||
"discount": {
|
||||
"type": "Number"
|
||||
},
|
||||
"reserved": {
|
||||
"type": "Number"
|
||||
},
|
||||
"isPicked": {
|
||||
"type": "Number"
|
||||
},
|
||||
"created": {
|
||||
"type": "date"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"item": {
|
||||
"type": "belongsTo",
|
||||
"model": "Item",
|
||||
"foreignKey": "itemFk",
|
||||
"required": true
|
||||
},
|
||||
"ticket": {
|
||||
"type": "belongsTo",
|
||||
"model": "Ticket",
|
||||
"foreignKey": "ticketFk",
|
||||
"required": true
|
||||
},
|
||||
"isChecked": {
|
||||
"type": "hasOne",
|
||||
"model": "SaleChecked",
|
||||
"foreignKey": "saleFk"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
module.exports = function(Self) {
|
||||
require('../methods/ticket/change-time.js')(Self);
|
||||
require('../methods/ticket/change-worker.js')(Self);
|
||||
require('../methods/ticket/filter.js')(Self);
|
||||
require('../methods/ticket/get-volume.js')(Self);
|
||||
require('../methods/ticket/change-time')(Self);
|
||||
require('../methods/ticket/change-worker')(Self);
|
||||
require('../methods/ticket/filter')(Self);
|
||||
require('../methods/ticket/get-volume')(Self);
|
||||
require('../methods/ticket/summary')(Self);
|
||||
};
|
||||
|
|
|
@ -76,6 +76,16 @@
|
|||
"type": "hasMany",
|
||||
"model": "TicketPackaging",
|
||||
"foreignKey": "ticketFk"
|
||||
},
|
||||
"ticketTracking": {
|
||||
"type": "hasOne",
|
||||
"model": "TicketTracking",
|
||||
"foreignKey": "ticketFk"
|
||||
},
|
||||
"notes": {
|
||||
"type": "hasMany",
|
||||
"model": "TicketObservation",
|
||||
"foreignKey": "ticketFk"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -69,6 +69,9 @@
|
|||
"State":{
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"Sale": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"TicketState":{
|
||||
"dataSource": "vn"
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue