diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql
index bb33487a3..2f3a9378d 100644
--- a/db/dump/fixtures.sql
+++ b/db/dump/fixtures.sql
@@ -1103,11 +1103,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
diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js
index 1f1ab4b26..563b8d89a 100644
--- a/e2e/helpers/selectors.js
+++ b/e2e/helpers/selectors.js
@@ -799,5 +799,10 @@ export default {
inflation: 'vn-zone-basic-data vn-input-number[ng-model="$ctrl.zone.inflation"]',
volumetric: 'vn-zone-basic-data vn-check[ng-model="$ctrl.zone.isVolumetric"]',
saveButton: 'vn-zone-basic-data vn-submit > button',
+ },
+ entrySummary: {
+ header: 'vn-entry-summary > vn-card > h5',
+ reference: 'vn-entry-summary vn-label-value[label="Reference"]',
+ confirmed: 'vn-entry-summary vn-check[label="Confirmed"]',
}
};
diff --git a/e2e/paths/12-entry/01_summary.spec.js b/e2e/paths/12-entry/01_summary.spec.js
new file mode 100644
index 000000000..39b12b840
--- /dev/null
+++ b/e2e/paths/12-entry/01_summary.spec.js
@@ -0,0 +1,43 @@
+import selectors from '../../helpers/selectors.js';
+import getBrowser from '../../helpers/puppeteer';
+
+describe('Entry summary path', () => {
+ let browser;
+ let page;
+
+ beforeAll(async() => {
+ browser = await getBrowser();
+ page = browser.page;
+ await page.loginAndModule('buyer', 'entry');
+ await page.waitToClick('vn-entry-index vn-tbody > a:nth-child(2)');
+ });
+
+ afterAll(async() => {
+ await browser.close();
+ });
+
+ it('should reach the second entry summary section', async() => {
+ let url = await page.expectURL('#!/entry/2/summary');
+
+ expect(url).toBe(true);
+ });
+
+ it(`should display details from the entry on the header`, async() => {
+ await page.waitForTextInElement(selectors.entrySummary.header, 'The king');
+ const result = await page.waitToGetProperty(selectors.entrySummary.header, 'innerText');
+
+ expect(result).toContain('The king');
+ });
+
+ it('should display some entry details like the reference', async() => {
+ const result = await page.waitToGetProperty(selectors.entrySummary.reference, 'innerText');
+
+ expect(result).toContain('Movement 2');
+ });
+
+ it('should display other entry details like the confirmed', async() => {
+ const result = await page.checkboxState(selectors.entrySummary.confirmed, 'innerText');
+
+ expect(result).toContain('unchecked');
+ });
+});
diff --git a/front/core/styles/icons/salixfont.css b/front/core/styles/icons/salixfont.css
index 64f2776ea..505fb8520 100644
--- a/front/core/styles/icons/salixfont.css
+++ b/front/core/styles/icons/salixfont.css
@@ -23,6 +23,12 @@
-moz-osx-font-smoothing: grayscale;
}
+.icon-net:before {
+ content: "\e95b";
+}
+.icon-anonymous:before {
+ content: "\e95c";
+}
.icon-buyrequest:before {
content: "\e914";
}
diff --git a/front/core/styles/icons/salixfont.svg b/front/core/styles/icons/salixfont.svg
index 2c13f601b..7cd1af528 100644
--- a/front/core/styles/icons/salixfont.svg
+++ b/front/core/styles/icons/salixfont.svg
@@ -98,4 +98,6 @@
+
+
\ No newline at end of file
diff --git a/front/core/styles/icons/salixfont.ttf b/front/core/styles/icons/salixfont.ttf
index 7a6ad2721..08a36a48b 100644
Binary files a/front/core/styles/icons/salixfont.ttf and b/front/core/styles/icons/salixfont.ttf differ
diff --git a/front/core/styles/icons/salixfont.woff b/front/core/styles/icons/salixfont.woff
index 0e6d9a21a..325a1bc2d 100644
Binary files a/front/core/styles/icons/salixfont.woff and b/front/core/styles/icons/salixfont.woff differ
diff --git a/modules/client/front/balance/index/index.spec.js b/modules/client/front/balance/index/index.spec.js
index e10f903d0..e044b7979 100644
--- a/modules/client/front/balance/index/index.spec.js
+++ b/modules/client/front/balance/index/index.spec.js
@@ -44,12 +44,6 @@ describe('Client', () => {
});
describe('company setter/getter', () => {
- it('should return the company', () => {
- controller.companyId = null;
-
- expect(controller._companyId).toEqual(jasmine.any(Object));
- });
-
it('should return the company and then call getData()', () => {
spyOn(controller, 'getData');
controller.companyId = 442;
diff --git a/modules/client/front/descriptor/index.html b/modules/client/front/descriptor/index.html
index 30777bcda..d8e035942 100644
--- a/modules/client/front/descriptor/index.html
+++ b/modules/client/front/descriptor/index.html
@@ -77,18 +77,15 @@
- From date
+ Send consumer report
-
- To date
-
{
type: 'Number',
description: 'The currency id to filter',
http: {source: 'query'}
+ }, {
+ arg: 'from',
+ type: 'Date',
+ description: `The from date filter`
+ }, {
+ arg: 'to',
+ type: 'Date',
+ description: `The to date filter`
}
],
returns: {
@@ -91,6 +99,10 @@ module.exports = Self => {
return {[param]: {like: `%${value}%`}};
case 'created':
return {'e.created': {gte: value}};
+ case 'from':
+ return {'t.landed': {gte: value}};
+ case 'to':
+ return {'t.landed': {lte: value}};
case 'id':
case 'isBooked':
case 'isConfirmed':
diff --git a/modules/entry/back/methods/entry/getEntry.js b/modules/entry/back/methods/entry/getEntry.js
new file mode 100644
index 000000000..008ee8148
--- /dev/null
+++ b/modules/entry/back/methods/entry/getEntry.js
@@ -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;
+ };
+};
diff --git a/modules/entry/back/methods/entry/specs/getEntry.spec.js b/modules/entry/back/methods/entry/specs/getEntry.spec.js
new file mode 100644
index 000000000..3791a3703
--- /dev/null
+++ b/modules/entry/back/methods/entry/specs/getEntry.spec.js
@@ -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(entryId);
+ });
+
+ 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');
+ });
+});
diff --git a/modules/entry/back/models/entry.js b/modules/entry/back/models/entry.js
index 4034b7e0a..b1f71b4bd 100644
--- a/modules/entry/back/models/entry.js
+++ b/modules/entry/back/models/entry.js
@@ -1,4 +1,5 @@
module.exports = Self => {
require('../methods/entry/filter')(Self);
+ require('../methods/entry/getEntry')(Self);
};
diff --git a/modules/entry/back/models/entry.json b/modules/entry/back/models/entry.json
index a2eef4cd2..c2a7d7c42 100644
--- a/modules/entry/back/models/entry.json
+++ b/modules/entry/back/models/entry.json
@@ -39,6 +39,9 @@
"commission": {
"type": "Number"
},
+ "isOrdered": {
+ "type": "Boolean"
+ },
"created": {
"type": "date"
},
diff --git a/modules/entry/front/card/index.js b/modules/entry/front/card/index.js
index 62fed7db0..83f47c83d 100644
--- a/modules/entry/front/card/index.js
+++ b/modules/entry/front/card/index.js
@@ -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
});
diff --git a/modules/entry/front/descriptor/index.html b/modules/entry/front/descriptor/index.html
index 372479c79..cd4057c43 100644
--- a/modules/entry/front/descriptor/index.html
+++ b/modules/entry/front/descriptor/index.html
@@ -6,16 +6,37 @@
-
+
+
diff --git a/modules/entry/front/descriptor/index.js b/modules/entry/front/descriptor/index.js
index a9f5cd679..8f51308f2 100644
--- a/modules/entry/front/descriptor/index.js
+++ b/modules/entry/front/descriptor/index.js
@@ -1,17 +1,80 @@
import ngModule from '../module';
+import Component from 'core/lib/component';
-class Controller {
- constructor($scope) {
- this.$ = $scope;
+class Controller extends Component {
+ constructor($element, $, $httpParamSerializer, vnConfig) {
+ super($element, $);
+ this.vnConfig = vnConfig;
+ this.$httpParamSerializer = $httpParamSerializer;
+ this.moreOptions = [
+ {name: 'Show entry report', callback: this.showEntryReport}
+ ];
+ }
+
+ onMoreChange(callback) {
+ callback.call(this);
+ }
+
+ 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);
+ }
+
+ showEntryReport() {
+ const params = {
+ clientId: this.vnConfig.storage.currentUserWorkerId,
+ entryId: this.entry.id
+ };
+ const serializedParams = this.$httpParamSerializer(params);
+ let url = `api/report/entry-order?${serializedParams}`;
+ window.open(url);
}
}
-Controller.$inject = ['$scope'];
+Controller.$inject = ['$element', '$scope', '$httpParamSerializer', 'vnConfig'];
ngModule.component('vnEntryDescriptor', {
template: require('./index.html'),
bindings: {
- entry: '<'
+ entry: '<',
+ quicklinks: '<'
},
require: {
card: '^?vnEntryCard'
diff --git a/modules/entry/front/descriptor/index.spec.js b/modules/entry/front/descriptor/index.spec.js
new file mode 100644
index 000000000..a63abc0f1
--- /dev/null
+++ b/modules/entry/front/descriptor/index.spec.js
@@ -0,0 +1,35 @@
+import './index.js';
+
+describe('Entry Component vnEntryDescriptor', () => {
+ let $httpParamSerializer;
+ let controller;
+ let $element;
+
+ beforeEach(ngModule('entry'));
+
+ beforeEach(angular.mock.inject(($componentController, _$httpBackend_, $rootScope, _$httpParamSerializer_) => {
+ $httpParamSerializer = _$httpParamSerializer_;
+ $element = angular.element(``);
+ controller = $componentController('vnEntryDescriptor', {$element});
+ controller._entry = {id: 2};
+ controller.vnConfig.storage = {currentUserWorkerId: 9};
+ controller.cardReload = ()=> {
+ return true;
+ };
+ }));
+
+ describe('showEntryReport()', () => {
+ it('should open a new window showing a delivery note PDF document', () => {
+ const params = {
+ clientId: controller.vnConfig.storage.currentUserWorkerId,
+ entryId: controller.entry.id
+ };
+ const serializedParams = $httpParamSerializer(params);
+ let expectedPath = `api/report/entry-order?${serializedParams}`;
+ spyOn(window, 'open');
+ controller.showEntryReport();
+
+ expect(window.open).toHaveBeenCalledWith(expectedPath);
+ });
+ });
+});
diff --git a/modules/entry/front/descriptor/locale/es.yml b/modules/entry/front/descriptor/locale/es.yml
index e5b926f1d..5e1eb25c2 100644
--- a/modules/entry/front/descriptor/locale/es.yml
+++ b/modules/entry/front/descriptor/locale/es.yml
@@ -1 +1,4 @@
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
+Show entry report: Ver informe del pedido
\ No newline at end of file
diff --git a/modules/entry/front/index.js b/modules/entry/front/index.js
index a0272fccf..25e054a71 100644
--- a/modules/entry/front/index.js
+++ b/modules/entry/front/index.js
@@ -5,7 +5,4 @@ import './index/';
import './search-panel';
import './descriptor';
import './card';
-// import './summary';
-// import './basic-data';
-// import './log';
-// import './create';
+import './summary';
diff --git a/modules/entry/front/index/index.html b/modules/entry/front/index/index.html
index f0f540489..60bbe46d5 100644
--- a/modules/entry/front/index/index.html
+++ b/modules/entry/front/index/index.html
@@ -16,7 +16,7 @@
-
+
Id
Landed
Reference
@@ -33,18 +33,18 @@
-
+
+ icon="icon-anonymous">
+ icon="icon-net">
{{::entry.id}}
diff --git a/modules/entry/front/routes.json b/modules/entry/front/routes.json
index bd1ace3f2..612edc157 100644
--- a/modules/entry/front/routes.json
+++ b/modules/entry/front/routes.json
@@ -28,6 +28,14 @@
"state": "entry.card",
"abstract": true,
"component": "vn-entry-card"
+ }, {
+ "url": "/summary",
+ "state": "entry.card.summary",
+ "component": "vn-entry-summary",
+ "description": "Summary",
+ "params": {
+ "entry": "$ctrl.entry"
+ }
}
]
}
\ No newline at end of file
diff --git a/modules/entry/front/search-panel/index.html b/modules/entry/front/search-panel/index.html
index d648edcdd..a3daa8f0f 100644
--- a/modules/entry/front/search-panel/index.html
+++ b/modules/entry/front/search-panel/index.html
@@ -54,6 +54,18 @@
ng-model="filter.created">
+
+
+
+
+
+
+ Entry #{{$ctrl.entryData.id}} - {{$ctrl.entryData.supplier.nickname}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/modules/entry/front/summary/index.js b/modules/entry/front/summary/index.js
new file mode 100644
index 000000000..3b26907d7
--- /dev/null
+++ b/modules/entry/front/summary/index.js
@@ -0,0 +1,37 @@
+import ngModule from '../module';
+import './style.scss';
+import Component from 'core/lib/component';
+
+class Controller extends Component {
+ constructor($element, $, $httpParamSerializer) {
+ super($element, $);
+ this.$httpParamSerializer = $httpParamSerializer;
+ }
+
+ get entry() {
+ return this._entry;
+ }
+
+ set entry(value) {
+ this._entry = value;
+
+ if (value && value.id)
+ this.getEntryData();
+ }
+
+ getEntryData() {
+ return this.$http.get(`/api/Entries/${this.entry.id}/getEntry`).then(response => {
+ this.entryData = response.data;
+ });
+ }
+}
+
+Controller.$inject = ['$element', '$scope', '$httpParamSerializer'];
+
+ngModule.component('vnEntrySummary', {
+ template: require('./index.html'),
+ controller: Controller,
+ bindings: {
+ entry: '<'
+ }
+});
diff --git a/modules/entry/front/summary/index.spec.js b/modules/entry/front/summary/index.spec.js
new file mode 100644
index 000000000..ea4a5a7c1
--- /dev/null
+++ b/modules/entry/front/summary/index.spec.js
@@ -0,0 +1,50 @@
+import './index';
+
+describe('component vnEntrySummary', () => {
+ let controller;
+ let $httpBackend;
+ let $scope;
+ let $element;
+
+ beforeEach(angular.mock.module('entry', $translateProvider => {
+ $translateProvider.translations('en', {});
+ }));
+
+ beforeEach(angular.mock.inject(($componentController, $rootScope, _$httpBackend_, _$httpParamSerializer_) => {
+ $httpBackend = _$httpBackend_;
+ $scope = $rootScope.$new();
+ $element = angular.element(``);
+ controller = $componentController('vnEntrySummary', {$element, $scope});
+ }));
+
+ describe('entry setter/getter', () => {
+ it('should check if value.id is defined', () => {
+ spyOn(controller, 'getEntryData');
+
+ controller.entry = {id: 1};
+
+ expect(controller.getEntryData).toHaveBeenCalledWith();
+ });
+
+ it('should return the entry and then call getEntryData()', () => {
+ spyOn(controller, 'getEntryData');
+ controller.entry = {id: 99};
+
+ expect(controller._entry.id).toEqual(99);
+ expect(controller.getEntryData).toHaveBeenCalledWith();
+ });
+ });
+
+ describe('getEntryData()', () => {
+ it('should perform a get and then store data on the controller', () => {
+ controller._entry = {id: 999};
+
+ const query = `/api/Entries/${controller._entry.id}/getEntry`;
+ $httpBackend.expectGET(query).respond('I am the entryData');
+ controller.getEntryData();
+ $httpBackend.flush();
+
+ expect(controller.entryData).toEqual('I am the entryData');
+ });
+ });
+});
diff --git a/modules/entry/front/summary/locale/es.yml b/modules/entry/front/summary/locale/es.yml
new file mode 100644
index 000000000..1673d6a17
--- /dev/null
+++ b/modules/entry/front/summary/locale/es.yml
@@ -0,0 +1,3 @@
+Inventory: Inventario
+Virtual: Redada
+Entry: Entrada
\ No newline at end of file
diff --git a/modules/entry/front/summary/style.scss b/modules/entry/front/summary/style.scss
new file mode 100644
index 000000000..8887e15b9
--- /dev/null
+++ b/modules/entry/front/summary/style.scss
@@ -0,0 +1,10 @@
+@import "variables";
+
+
+vn-entry-summary .summary {
+ max-width: $width-lg;
+
+ vn-icon[icon=insert_drive_file]{
+ color: $color-font-secondary;
+ }
+}
\ No newline at end of file
diff --git a/modules/travel/front/summary/index.spec.js b/modules/travel/front/summary/index.spec.js
index 5411d8a0d..593d2cfcc 100644
--- a/modules/travel/front/summary/index.spec.js
+++ b/modules/travel/front/summary/index.spec.js
@@ -20,12 +20,6 @@ describe('component vnTravelSummary', () => {
}));
describe('travel setter/getter', () => {
- it('should return the travel', () => {
- controller.travel = {id: null};
-
- expect(controller.travel).toEqual(jasmine.any(Object));
- });
-
it('should return the travel and then call both getTravel() and getEntries()', () => {
spyOn(controller, 'getTravel');
spyOn(controller, 'getEntries');