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), (104, 500),
(105, 5000); (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 VALUES
(1, 'Plants SL', 4000000001, 1, 'A11111111', 0, NULL, 0, CURDATE(), 1111, 1, 'supplier address 1', 'PONTEVEDRA', 1, 15214, 1, 1), (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', 4000000002, 1, 'B22222222', 0, NULL, 0, CURDATE(), 2222, 1, 'supplier address 2', 'LONDON', 2, 45671, 1, 2), (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', 4000000442, 1, 'C33333333', 0, NULL, 0, CURDATE(), 3333, 1, 'supplier address 3', 'SILLA', 1, 43022, 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`) INSERT INTO `cache`.`cache_calc`(`id`, `cache_id`, `cacheName`, `params`, `last_refresh`, `expires`, `created`, `connection_id`)
VALUES 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 => { module.exports = Self => {
require('../methods/entry/filter')(Self); require('../methods/entry/filter')(Self);
require('../methods/entry/getEntry')(Self);
}; };

View File

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

View File

@ -11,11 +11,34 @@ class Controller extends ModuleCard {
fields: ['id', 'code'] 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', relation: 'supplier',
scope: { scope: {
fields: ['id', 'name'] fields: ['id', 'nickname']
} }
}, { }, {
relation: 'currency' relation: 'currency'
@ -27,7 +50,7 @@ class Controller extends ModuleCard {
} }
} }
ngModule.component('vnEntry Card', { ngModule.component('vnEntryCard', {
template: require('./index.html'), template: require('./index.html'),
controller: Controller controller: Controller
}); });

View File

@ -13,9 +13,21 @@
<vn-label-value label="Id" <vn-label-value label="Id"
value="{{$ctrl.entry.id}}"> value="{{$ctrl.entry.id}}">
</vn-label-value> </vn-label-value>
<vn-label-value label="Reference" <vn-label-value label="Supplier"
value="{{$ctrl.entry.ref}}"> 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> </vn-label-value>
</div> </div>
<vn-quick-links
links="$ctrl.quicklinks">
</vn-quick-links>
</div> </div>
</div> </div>

View File

@ -4,6 +4,48 @@ class Controller {
constructor($scope) { constructor($scope) {
this.$ = $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']; Controller.$inject = ['$scope'];

View File

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

View File

@ -1,140 +1,68 @@
<vn-card class="summary"> <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-horizontal>
<vn-one> <vn-one>
<vn-label-value label="Shipped" <vn-label-value label="Commission"
value="{{$ctrl.travelData.shipped | date: 'dd/MM/yyyy'}}"> value="{{$ctrl.entryData.commission}}">
</vn-label-value> </vn-label-value>
<vn-label-value label="Warehouse Out" <vn-label-value label="Currency"
value="{{$ctrl.travelData.warehouseOut.name}}"> value="{{$ctrl.entryData.currency.name}}">
</vn-label-value> </vn-label-value>
<vn-check <vn-label-value label="Company"
label="Delivered" value="{{$ctrl.entryData.company.code}}">
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> </vn-label-value>
<vn-label-value label="Warehouse In" <vn-label-value label="Reference"
value="{{$ctrl.travelData.warehouseIn.name}}"> value="{{$ctrl.entryData.ref}}">
</vn-label-value>
<vn-label-value label="Notes"
value="{{$ctrl.entryData.notes}}">
</vn-label-value> </vn-label-value>
<vn-check
label="Received"
value="{{$ctrl.travelData.isReceived}}"
disabled="true">
</vn-check>
</vn-one> </vn-one>
<vn-one> <vn-one>
<vn-label-value label="Agency" <vn-label-value label="Agency"
value="{{$ctrl.travelData.agency.name}}"> value="{{$ctrl.entryData.travel.agency.name}}">
</vn-label-value> </vn-label-value>
<vn-label-value label="Reference" <vn-label-value label="Shipped"
value="{{$ctrl.travelData.ref}}"> value="{{$ctrl.entryData.travel.shipped | date: 'dd/MM/yyyy'}}">
</vn-label-value> </vn-label-value>
<vn-label-value label="m3" <vn-label-value label="Warehouse Out"
value="{{$ctrl.travelData.m3}}"> value="{{$ctrl.entryData.travel.warehouseOut.name}}">
</vn-label-value> </vn-label-value>
<vn-label-value label="Total entries" <vn-label-value label="Landed"
value="{{$ctrl.travelData.totalEntries}}"> 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-label-value>
</vn-one> </vn-one>
<vn-auto> <vn-one>
<h4 translate>Entries</h4> <vn-vertical>
<vn-table> <vn-check
<vn-thead> label="Ordered"
<vn-tr> value="{{$ctrl.entryData.isOrdered}}"
<vn-th shrink>Confirmed</vn-th> disabled="true">
<vn-th shrink>Entry Id</vn-th> </vn-check>
<vn-th shrink>Supplier</vn-th> <vn-check
<vn-th shrink>Reference</vn-th> label="Confirmed"
<vn-th shrink title="Half box">HB</vn-th> value="{{$ctrl.entryData.isConfirmed}}"
<vn-th shrink>Freight</vn-th> disabled="true">
<vn-th shrink>Package</vn-th> </vn-check>
<vn-th shrink>CC</vn-th> <vn-check
<vn-th shrink>Pallet</vn-th> label="Booked"
<vn-th shrink>m3</vn-th> value="{{$ctrl.entryData.isBooked}}"
<vn-th shrink></vn-th> disabled="true">
</vn-tr> </vn-check>
</vn-thead> <vn-check
<vn-tbody> label="Virtual"
<vn-tr ng-repeat="entry in $ctrl.entries"> value="{{$ctrl.entryData.isVirtual}}"
<vn-td shrink> disabled="true">
<vn-check </vn-check>
value="{{entry.isConfirmed}}" <vn-check
disabled="true"> label="Inventory"
</vn-check> value="{{$ctrl.entryData.isInventory}}"
</vn-td> disabled="true">
<vn-td shrink>{{entry.id}} </vn-td> </vn-check>
<vn-td shrink>{{entry.supplierName}}</vn-td> </vn-vertical>
<vn-td shrink>{{entry.ref}}</vn-td> </vn-one>
<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-horizontal> </vn-horizontal>
</vn-card> </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 { class Controller extends Component {
constructor($element, $, $httpParamSerializer) { constructor($element, $, $httpParamSerializer) {
super($element, $); super($element, $);
this.entries = [];
this.$httpParamSerializer = $httpParamSerializer; this.$httpParamSerializer = $httpParamSerializer;
} }
@ -16,33 +15,15 @@ class Controller extends Component {
set entry(value) { set entry(value) {
this._entry = value; this._entry = value;
// if (value && value.id) { if (value && value.id)
// this.getTravel(); this.getEntry();
// this.getEntries();
// this.getThermographs();
// }
} }
// getTravel() { getEntry() {
// return this.$http.get(`/api/Travels/${this.travel.id}/getTravel`).then(response => { return this.$http.get(`/api/Entries/${this.entry.id}/getEntry`).then(response => {
// this.travelData = response.data; this.entryData = 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;
// }
} }
Controller.$inject = ['$element', '$scope', '$httpParamSerializer']; Controller.$inject = ['$element', '$scope', '$httpParamSerializer'];

View File

@ -1,108 +1,48 @@
import './index'; import './index';
describe('component vnTravelSummary', () => { describe('component vnEntrySummary', () => {
let controller; let controller;
let $httpBackend; let $httpBackend;
let $scope; let $scope;
let $element; let $element;
let $httpParamSerializer;
beforeEach(angular.mock.module('travel', $translateProvider => { beforeEach(angular.mock.module('entry', $translateProvider => {
$translateProvider.translations('en', {}); $translateProvider.translations('en', {});
})); }));
beforeEach(angular.mock.inject(($componentController, $rootScope, _$httpBackend_, _$httpParamSerializer_) => { beforeEach(angular.mock.inject(($componentController, $rootScope, _$httpBackend_, _$httpParamSerializer_) => {
$httpBackend = _$httpBackend_; $httpBackend = _$httpBackend_;
$httpParamSerializer = _$httpParamSerializer_;
$scope = $rootScope.$new(); $scope = $rootScope.$new();
$element = angular.element(`<vn-travel-summary></vn-travel-summary>`); $element = angular.element(`<vn-entry-summary></vn-entry-summary>`);
controller = $componentController('vnTravelSummary', {$element, $scope}); controller = $componentController('vnEntrySummary', {$element, $scope});
})); }));
describe('travel setter/getter', () => { describe('entry setter/getter', () => {
it('should return the travel', () => { it('should return the entry', () => {
controller.travel = {id: null}; 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()', () => { it('should return the entry and then call getEntry()', () => {
spyOn(controller, 'getTravel'); spyOn(controller, 'getEntry');
spyOn(controller, 'getEntries'); controller.entry = {id: 99};
spyOn(controller, 'getThermographs');
controller.travel = {id: 99};
expect(controller._entry.id).toEqual(99);
expect(controller._travel.id).toEqual(99); expect(controller.getEntry).toHaveBeenCalledWith();
expect(controller.getTravel).toHaveBeenCalledWith();
expect(controller.getEntries).toHaveBeenCalledWith();
expect(controller.getThermographs).toHaveBeenCalledWith();
}); });
}); });
describe('getTravel()', () => { describe('getEntry()', () => {
it('should perform a get and then store data on the controller', () => { 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`; const query = `/api/Entries/${controller._entry.id}/getEntry`;
$httpBackend.expectGET(query).respond('I am the travelData'); $httpBackend.expectGET(query).respond('I am the entryData');
controller.getTravel(); controller.getEntry();
$httpBackend.flush(); $httpBackend.flush();
expect(controller.travelData).toEqual('I am the travelData'); expect(controller.entryData).toEqual('I am the entryData');
});
});
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);
}); });
}); });
}); });

View File

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

View File

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