entry summary and descriptor

This commit is contained in:
Bernat Exposito Domenech 2020-02-21 12:48:34 +01:00
parent 773963e7ab
commit 9779c6d2ba
15 changed files with 283 additions and 242 deletions

View File

@ -1101,11 +1101,11 @@ INSERT INTO `vn`.`annualAverageInvoiced`(`clientFk`, `invoiced`)
(104, 500),
(105, 5000);
INSERT INTO `vn`.`supplier`(`id`, `name`,`account`,`countryFk`,`nif`,`isFarmer`,`retAccount`,`commission`, `created`, `postcodeFk`, `isActive`, `street`, `city`, `provinceFk`, `postCode`, `payMethodFk`, `payDemFk`)
INSERT INTO `vn`.`supplier`(`id`, `name`, `nickname`,`account`,`countryFk`,`nif`,`isFarmer`,`retAccount`,`commission`, `created`, `postcodeFk`, `isActive`, `street`, `city`, `provinceFk`, `postCode`, `payMethodFk`, `payDemFk`)
VALUES
(1, 'Plants SL', 4000000001, 1, 'A11111111', 0, NULL, 0, CURDATE(), 1111, 1, 'supplier address 1', 'PONTEVEDRA', 1, 15214, 1, 1),
(2, 'Flower King', 4000000002, 1, 'B22222222', 0, NULL, 0, CURDATE(), 2222, 1, 'supplier address 2', 'LONDON', 2, 45671, 1, 2),
(442, 'Verdnatura Levante SL', 4000000442, 1, 'C33333333', 0, NULL, 0, CURDATE(), 3333, 1, 'supplier address 3', 'SILLA', 1, 43022, 1, 2);
(1, 'Plants SL', 'Plants nick', 4000000001, 1, 'A11111111', 0, NULL, 0, CURDATE(), 1111, 1, 'supplier address 1', 'PONTEVEDRA', 1, 15214, 1, 1),
(2, 'Flower King', 'The king', 4000000002, 1, 'B22222222', 0, NULL, 0, CURDATE(), 2222, 1, 'supplier address 2', 'LONDON', 2, 45671, 1, 2),
(442, 'Verdnatura Levante SL', 'Verdnatura', 4000000442, 1, 'C33333333', 0, NULL, 0, CURDATE(), 3333, 1, 'supplier address 3', 'SILLA', 1, 43022, 1, 2);
INSERT INTO `cache`.`cache_calc`(`id`, `cache_id`, `cacheName`, `params`, `last_refresh`, `expires`, `created`, `connection_id`)
VALUES

View File

@ -0,0 +1,76 @@
module.exports = Self => {
Self.remoteMethod('getEntry', {
description: 'Returns an entry',
accessType: 'READ',
accepts: {
arg: 'id',
type: 'number',
required: true,
description: 'The entry id',
http: {source: 'path'}
},
returns: {
type: 'object',
root: true
},
http: {
path: `/:id/getEntry`,
verb: 'GET'
}
});
Self.getEntry = async id => {
let filter = {
where: {id: id},
include: [
{
relation: 'supplier',
scope: {
fields: ['id', 'nickname']
}
},
{
relation: 'travel',
scope: {
fields: ['id', 'name', 'shipped', 'landed', 'agencyFk', 'warehouseOutFk', 'warehouseInFk'],
include: [
{
relation: 'agency',
scope: {
fields: ['name']
}
},
{
relation: 'warehouseOut',
scope: {
fields: ['name']
}
},
{
relation: 'warehouseIn',
scope: {
fields: ['name']
}
}
]
}
},
{
relation: 'currency',
scope: {
fields: ['id', 'name']
}
},
{
relation: 'company',
scope: {
fields: ['id', 'code']
}
}
],
};
let entry = await Self.app.models.Entry.findOne(filter);
return entry;
};
};

View File

@ -0,0 +1,31 @@
const app = require('vn-loopback/server/server');
describe('travel getEntry()', () => {
const entryId = 1;
it('should check the entry contains the id', async() => {
const entry = await app.models.Entry.getEntry(entryId);
expect(entry.id).toEqual(1);
});
it('should check the entry contains the supplier name', async() => {
const entry = await app.models.Entry.getEntry(entryId);
const supplierName = entry.supplier().nickname;
expect(supplierName).toEqual('Plants nick');
});
it('should check the entry contains the receiver warehouse name', async() => {
const entry = await app.models.Entry.getEntry(entryId);
const receiverWarehouseName = entry.travel().warehouseIn().name;
expect(receiverWarehouseName).toEqual('Warehouse One');
});
it('should check the entry contains the company code', async() => {
const entry = await app.models.Entry.getEntry(entryId);
const companyCode = entry.company().code;
expect(companyCode).toEqual('VNL');
});
});

View File

@ -1,4 +1,5 @@
module.exports = Self => {
require('../methods/entry/filter')(Self);
require('../methods/entry/getEntry')(Self);
};

View File

@ -39,6 +39,9 @@
"commission": {
"type": "Number"
},
"isOrdered": {
"type": "Boolean"
},
"created": {
"type": "date"
},

View File

@ -11,11 +11,34 @@ class Controller extends ModuleCard {
fields: ['id', 'code']
}
}, {
relation: 'travel'
relation: 'travel',
scope: {
fields: ['id', 'landed', 'agencyFk', 'warehouseOutFk'],
include: [
{
relation: 'agency',
scope: {
fields: ['name']
}
},
{
relation: 'warehouseOut',
scope: {
fields: ['name']
}
},
{
relation: 'warehouseIn',
scope: {
fields: ['name']
}
}
]
}
}, {
relation: 'supplier',
scope: {
fields: ['id', 'name']
fields: ['id', 'nickname']
}
}, {
relation: 'currency'
@ -27,7 +50,7 @@ class Controller extends ModuleCard {
}
}
ngModule.component('vnEntry Card', {
ngModule.component('vnEntryCard', {
template: require('./index.html'),
controller: Controller
});

View File

@ -13,9 +13,21 @@
<vn-label-value label="Id"
value="{{$ctrl.entry.id}}">
</vn-label-value>
<vn-label-value label="Reference"
value="{{$ctrl.entry.ref}}">
<vn-label-value label="Supplier"
value="{{$ctrl.entry.supplier.nickname}}">
</vn-label-value>
<vn-label-value label="Agency "
value="{{$ctrl.entry.travel.agency.name}}">
</vn-label-value>
<vn-label-value label="Landed"
value="{{$ctrl.entry.travel.landed | date: 'dd/MM/yyyy'}}">
</vn-label-value>
<vn-label-value label="Warehouse Out"
value="{{$ctrl.entry.travel.warehouseOut.name}}">
</vn-label-value>
</div>
<vn-quick-links
links="$ctrl.quicklinks">
</vn-quick-links>
</div>
</div>

View File

@ -4,6 +4,48 @@ class Controller {
constructor($scope) {
this.$ = $scope;
}
get entry() {
return this._entry;
}
set entry(value) {
this._entry = value;
if (!value) return;
const date = value.travel.landed;
let to = new Date(date);
let from = new Date(date);
to.setDate(to.getDate() + 10);
to.setHours(0, 0, 0, 0);
from.setDate(from.getDate() - 10);
from.setHours(0, 0, 0, 0);
let links = {
btnOne: {
icon: 'local_airport',
state: `travel.index({q: '{"agencyFk": ${value.travel.agencyFk}}'})`,
tooltip: 'All travels with current agency'
}};
links.btnTwo = {
icon: 'icon-entry',
state: `entry.index({q: '{"supplierFk": ${value.supplierFk}, "to": "${to}", "from": "${from}"}'})`,
tooltip: 'All entries with current supplier'
};
this._quicklinks = links;
}
get quicklinks() {
return this._quicklinks;
}
set quicklinks(value = {}) {
this._quicklinks = Object.assign(value, this._quicklinks);
}
}
Controller.$inject = ['$scope'];

View File

@ -1 +1,3 @@
Reference: Referencia
All travels with current agency: Todos los envios con la agencia actual
All entries with current supplier: Todas las entradas con el proveedor actual

View File

@ -16,7 +16,7 @@
<vn-table model="model">
<vn-thead>
<vn-tr>
<vn-th></vn-th>
<vn-th shrink></vn-th>
<vn-th field="id" number>Id</vn-th>
<vn-th field="landed" center>Landed</vn-th>
<vn-th>Reference</vn-th>
@ -33,18 +33,18 @@
<a ng-repeat="entry in entries"
class="clickable vn-tr search-result"
ui-sref="entry.card.summary({id: {{::entry.id}}})">
<vn-td>
<vn-td shrink>
<vn-icon
ng-show="entry.isInventory"
class="bright"
vn-tooltip="Inventory entry"
icon="icon-unavailable">
icon="icon-anonymous">
</vn-icon>
<vn-icon
ng-show="entry.isRaid"
class="bright"
vn-tooltip="Virtual entry"
icon="icon-100">
icon="icon-net">
</vn-icon>
</vn-td>
<vn-td number>{{::entry.id}}</vn-td>

View File

@ -1,140 +1,68 @@
<vn-card class="summary">
<h5>{{$ctrl.travelData.id}} - {{$ctrl.travelData.ref}}</h5>
<h5>Entrada #{{$ctrl.entryData.id}} - {{$ctrl.entryData.supplier.nickname}}</h5>
<vn-horizontal>
<vn-one>
<vn-label-value label="Shipped"
value="{{$ctrl.travelData.shipped | date: 'dd/MM/yyyy'}}">
<vn-label-value label="Commission"
value="{{$ctrl.entryData.commission}}">
</vn-label-value>
<vn-label-value label="Warehouse Out"
value="{{$ctrl.travelData.warehouseOut.name}}">
<vn-label-value label="Currency"
value="{{$ctrl.entryData.currency.name}}">
</vn-label-value>
<vn-check
label="Delivered"
value="{{$ctrl.travelData.isDelivered}}"
disabled="true">
</vn-check>
</vn-one>
<vn-one>
<vn-label-value label="Landed"
value="{{$ctrl.travelData.landed | date: 'dd/MM/yyyy'}}">
<vn-label-value label="Company"
value="{{$ctrl.entryData.company.code}}">
</vn-label-value>
<vn-label-value label="Warehouse In"
value="{{$ctrl.travelData.warehouseIn.name}}">
<vn-label-value label="Reference"
value="{{$ctrl.entryData.ref}}">
</vn-label-value>
<vn-label-value label="Notes"
value="{{$ctrl.entryData.notes}}">
</vn-label-value>
<vn-check
label="Received"
value="{{$ctrl.travelData.isReceived}}"
disabled="true">
</vn-check>
</vn-one>
<vn-one>
<vn-label-value label="Agency"
value="{{$ctrl.travelData.agency.name}}">
value="{{$ctrl.entryData.travel.agency.name}}">
</vn-label-value>
<vn-label-value label="Reference"
value="{{$ctrl.travelData.ref}}">
<vn-label-value label="Shipped"
value="{{$ctrl.entryData.travel.shipped | date: 'dd/MM/yyyy'}}">
</vn-label-value>
<vn-label-value label="m3"
value="{{$ctrl.travelData.m3}}">
<vn-label-value label="Warehouse Out"
value="{{$ctrl.entryData.travel.warehouseOut.name}}">
</vn-label-value>
<vn-label-value label="Total entries"
value="{{$ctrl.travelData.totalEntries}}">
<vn-label-value label="Landed"
value="{{$ctrl.entryData.travel.landed | date: 'dd/MM/yyyy'}}">
</vn-label-value>
<vn-label-value label="Warehouse In"
value="{{$ctrl.entryData.travel.warehouseIn.name}}">
</vn-label-value>
</vn-one>
<vn-auto>
<h4 translate>Entries</h4>
<vn-table>
<vn-thead>
<vn-tr>
<vn-th shrink>Confirmed</vn-th>
<vn-th shrink>Entry Id</vn-th>
<vn-th shrink>Supplier</vn-th>
<vn-th shrink>Reference</vn-th>
<vn-th shrink title="Half box">HB</vn-th>
<vn-th shrink>Freight</vn-th>
<vn-th shrink>Package</vn-th>
<vn-th shrink>CC</vn-th>
<vn-th shrink>Pallet</vn-th>
<vn-th shrink>m3</vn-th>
<vn-th shrink></vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="entry in $ctrl.entries">
<vn-td shrink>
<vn-check
value="{{entry.isConfirmed}}"
disabled="true">
</vn-check>
</vn-td>
<vn-td shrink>{{entry.id}} </vn-td>
<vn-td shrink>{{entry.supplierName}}</vn-td>
<vn-td shrink>{{entry.ref}}</vn-td>
<vn-td shrink>{{entry.hb}}</vn-td>
<vn-td shrink>{{entry.freightValue | currency: 'EUR': 2}}</vn-td>
<vn-td shrink>{{entry.packageValue | currency: 'EUR': 2}}</vn-td>
<vn-td shrink>{{entry.cc}}</vn-td>
<vn-td shrink>{{entry.pallet}}</vn-td>
<vn-td shrink>{{entry.m3}}</vn-td>
<vn-td shrink>
<vn-icon
ng-if="entry.notes.length"
vn-tooltip="{{entry.notes}}"
icon="insert_drive_file">
</vn-icon>
<vn-icon
ng-if="entry.observation.length"
vn-tooltip="{{entry.observation}}"
icon="insert_drive_file">
</vn-icon>
</vn-td>
</vn-tr>
</vn-tbody>
<vn-tfoot>
<vn-tr>
<vn-td></vn-td>
<vn-td></vn-td>
<vn-td></vn-td>
<vn-td></vn-td>
<vn-td shrink><strong>{{$ctrl.total('hb')}}</strong></vn-td>
<vn-td shrink><strong>{{$ctrl.total('freightValue') | currency: 'EUR': 2}}</strong></vn-td>
<vn-td shrink><strong>{{$ctrl.total('packageValue') | currency: 'EUR': 2}}</strong></vn-td>
<vn-td shrink><strong>{{$ctrl.total('cc')}}</strong></vn-td>
<vn-td shrink><strong>{{$ctrl.total('pallet')}}</strong></vn-td>
<vn-td shrink><strong>{{$ctrl.total('m3')}}</strong></vn-td>
<vn-td></vn-td>
</vn-tr>
</vn-tfoot>
</vn-table>
</vn-auto>
<vn-auto>
<h4 translate>Thermographs</h4>
<vn-table>
<vn-thead>
<vn-tr>
<vn-th>Code</vn-th>
<vn-th>Temperature</vn-th>
<vn-th expand>State</vn-th>
<vn-th>Destination</vn-th>
<vn-th>Created</vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="thermograph in $ctrl.travelThermographs">
<vn-td>{{thermograph.thermographFk}} </vn-td>
<vn-td>{{thermograph.temperature}}</vn-td>
<vn-td>{{thermograph.result}}</vn-td>
<vn-td>{{thermograph.warehouse.name}}</vn-td>
<vn-td>{{thermograph.created | date: 'dd/MM/yyyy'}}</vn-td>
</vn-tr>
</vn-tbody>
</vn-table>
</vn-auto>
<vn-one>
<vn-vertical>
<vn-check
label="Ordered"
value="{{$ctrl.entryData.isOrdered}}"
disabled="true">
</vn-check>
<vn-check
label="Confirmed"
value="{{$ctrl.entryData.isConfirmed}}"
disabled="true">
</vn-check>
<vn-check
label="Booked"
value="{{$ctrl.entryData.isBooked}}"
disabled="true">
</vn-check>
<vn-check
label="Virtual"
value="{{$ctrl.entryData.isVirtual}}"
disabled="true">
</vn-check>
<vn-check
label="Inventory"
value="{{$ctrl.entryData.isInventory}}"
disabled="true">
</vn-check>
</vn-vertical>
</vn-one>
</vn-horizontal>
</vn-card>
<vn-ticket-descriptor-popover
vn-id="ticketDescriptor">
</vn-ticket-descriptor-popover>
<vn-client-descriptor-popover
vn-id="clientDescriptor">
</vn-client-descriptor-popover>

View File

@ -5,7 +5,6 @@ import Component from 'core/lib/component';
class Controller extends Component {
constructor($element, $, $httpParamSerializer) {
super($element, $);
this.entries = [];
this.$httpParamSerializer = $httpParamSerializer;
}
@ -16,33 +15,15 @@ class Controller extends Component {
set entry(value) {
this._entry = value;
// if (value && value.id) {
// this.getTravel();
// this.getEntries();
// this.getThermographs();
// }
if (value && value.id)
this.getEntry();
}
// getTravel() {
// return this.$http.get(`/api/Travels/${this.travel.id}/getTravel`).then(response => {
// this.travelData = response.data;
// });
// }
// getEntries() {
// return this.$http.get(`/api/Travels/${this.travel.id}/getEntries`).then(response => {
// this.entries = response.data;
// });
// }
// total(field) {
// let total = 0;
// for (let entry of this.entries)
// total += entry[field];
// return total;
// }
getEntry() {
return this.$http.get(`/api/Entries/${this.entry.id}/getEntry`).then(response => {
this.entryData = response.data;
});
}
}
Controller.$inject = ['$element', '$scope', '$httpParamSerializer'];

View File

@ -1,108 +1,48 @@
import './index';
describe('component vnTravelSummary', () => {
describe('component vnEntrySummary', () => {
let controller;
let $httpBackend;
let $scope;
let $element;
let $httpParamSerializer;
beforeEach(angular.mock.module('travel', $translateProvider => {
beforeEach(angular.mock.module('entry', $translateProvider => {
$translateProvider.translations('en', {});
}));
beforeEach(angular.mock.inject(($componentController, $rootScope, _$httpBackend_, _$httpParamSerializer_) => {
$httpBackend = _$httpBackend_;
$httpParamSerializer = _$httpParamSerializer_;
$scope = $rootScope.$new();
$element = angular.element(`<vn-travel-summary></vn-travel-summary>`);
controller = $componentController('vnTravelSummary', {$element, $scope});
$element = angular.element(`<vn-entry-summary></vn-entry-summary>`);
controller = $componentController('vnEntrySummary', {$element, $scope});
}));
describe('travel setter/getter', () => {
it('should return the travel', () => {
controller.travel = {id: null};
describe('entry setter/getter', () => {
it('should return the entry', () => {
controller.entry = {id: 1};
expect(controller.travel).toEqual(jasmine.any(Object));
expect(controller.entry).toEqual(jasmine.any(Object));
});
it('should return the travel and then call both getTravel() and getEntries()', () => {
spyOn(controller, 'getTravel');
spyOn(controller, 'getEntries');
spyOn(controller, 'getThermographs');
controller.travel = {id: 99};
it('should return the entry and then call getEntry()', () => {
spyOn(controller, 'getEntry');
controller.entry = {id: 99};
expect(controller._travel.id).toEqual(99);
expect(controller.getTravel).toHaveBeenCalledWith();
expect(controller.getEntries).toHaveBeenCalledWith();
expect(controller.getThermographs).toHaveBeenCalledWith();
expect(controller._entry.id).toEqual(99);
expect(controller.getEntry).toHaveBeenCalledWith();
});
});
describe('getTravel()', () => {
describe('getEntry()', () => {
it('should perform a get and then store data on the controller', () => {
controller._travel = {id: 999};
controller._entry = {id: 999};
const query = `/api/Travels/${controller._travel.id}/getTravel`;
$httpBackend.expectGET(query).respond('I am the travelData');
controller.getTravel();
const query = `/api/Entries/${controller._entry.id}/getEntry`;
$httpBackend.expectGET(query).respond('I am the entryData');
controller.getEntry();
$httpBackend.flush();
expect(controller.travelData).toEqual('I am the travelData');
});
});
describe('getEntries()', () => {
it('should call the getEntries method to get the entries data', () => {
controller._travel = {id: 999};
const query = `/api/Travels/${controller._travel.id}/getEntries`;
$httpBackend.expectGET(query).respond('I am the entries');
controller.getEntries();
$httpBackend.flush();
expect(controller.entries).toEqual('I am the entries');
});
});
describe('getThermographs()', () => {
it('should call the getThermographs method to get the thermographs', () => {
controller._travel = {id: 2};
const params = {
filter: {
include: {
relation: 'warehouse',
scope: {
fields: ['id', 'name']
}
},
where: {
travelFk: controller._travel.id
}
}
};
const serializedParams = $httpParamSerializer(params);
const query = `TravelThermographs?${serializedParams}`;
$httpBackend.expectGET(query).respond('I am the thermographs');
controller.getThermographs();
$httpBackend.flush();
expect(controller.travelThermographs).toEqual('I am the thermographs');
});
});
describe('total()', () => {
it('should calculate the total amount of a given property for every row', () => {
controller.entries = [
{id: 1, freightValue: 1, packageValue: 2, cc: 0.01},
{id: 2, freightValue: 1, packageValue: 2, cc: 0.01},
{id: 3, freightValue: 1, packageValue: 2, cc: 0.01}
];
expect(controller.total('freightValue')).toEqual(3);
expect(controller.total('packageValue')).toEqual(6);
expect(controller.total('cc')).toEqual(0.03);
expect(controller.entryData).toEqual('I am the entryData');
});
});
});

View File

@ -0,0 +1,2 @@
Inventory: Inventario
Virtual: Redada

View File

@ -1,7 +1,7 @@
@import "variables";
vn-travel-summary .summary {
vn-entry-summary .summary {
max-width: $width-lg;
vn-icon[icon=insert_drive_file]{