Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into 2087-snackbar_show_counter

This commit is contained in:
Carlos Jimenez Ruiz 2020-02-25 15:13:54 +01:00
commit 4750195c44
117 changed files with 1051 additions and 246 deletions

View File

@ -0,0 +1,2 @@
ALTER TABLE `vn`.`zoneEvent`
ADD COLUMN m3Max DECIMAL(10,2) UNSIGNED NULL DEFAULT NULL AFTER bonus;

View File

@ -35,7 +35,7 @@ INSERT INTO `vn`.`packagingConfig`(`upperGap`)
UPDATE `account`.`role` SET id = 100 WHERE id = 0;
INSERT INTO `account`.`user`(`id`,`name`, `nickname`, `password`,`role`,`active`,`email`, `lang`)
SELECT id, name, CONCAT(name, 'Nick'),MD5('nightmare'), id, 1, CONCAT(name, '@mydomain.com'), 'EN'
SELECT id, name, CONCAT(name, 'Nick'),MD5('nightmare'), id, 1, CONCAT(name, '@mydomain.com'), 'en'
FROM `account`.`role` WHERE id <> 20
ORDER BY id;
@ -55,18 +55,18 @@ INSERT INTO `hedera`.`tpvConfig`(`id`, `currency`, `terminal`, `transactionType`
INSERT INTO `account`.`user`(`id`,`name`,`nickname`, `password`,`role`,`active`,`email`,`lang`)
VALUES
(101, 'BruceWayne', 'Bruce Wayne', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'BruceWayne@mydomain.com', 'ES'),
(102, 'PetterParker', 'Petter Parker', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'PetterParker@mydomain.com', 'EN'),
(103, 'ClarkKent', 'Clark Kent', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'ClarkKent@mydomain.com', 'FR'),
(104, 'TonyStark', 'Tony Stark', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'TonyStark@mydomain.com', 'ES'),
(105, 'MaxEisenhardt', 'Max Eisenhardt', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'MaxEisenhardt@mydomain.com', 'PT'),
(106, 'DavidCharlesHaller', 'David Charles Haller', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'DavidCharlesHaller@mydomain.com', 'EN'),
(107, 'HankPym', 'Hank Pym', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'HankPym@mydomain.com', 'EN'),
(108, 'CharlesXavier', 'Charles Xavier', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'CharlesXavier@mydomain.com', 'EN'),
(109, 'BruceBanner', 'Bruce Banner', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'BruceBanner@mydomain.com', 'EN'),
(110, 'JessicaJones', 'Jessica Jones', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'JessicaJones@mydomain.com', 'EN'),
(111, 'Missing', 'Missing', 'ac754a330530832ba1bf7687f577da91', 2, 0, NULL, 'EN'),
(112, 'Trash', 'Trash', 'ac754a330530832ba1bf7687f577da91', 2, 0, NULL, 'EN');
(101, 'BruceWayne', 'Bruce Wayne', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'BruceWayne@mydomain.com', 'es'),
(102, 'PetterParker', 'Petter Parker', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'PetterParker@mydomain.com', 'en'),
(103, 'ClarkKent', 'Clark Kent', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'ClarkKent@mydomain.com', 'fr'),
(104, 'TonyStark', 'Tony Stark', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'TonyStark@mydomain.com', 'es'),
(105, 'MaxEisenhardt', 'Max Eisenhardt', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'MaxEisenhardt@mydomain.com', 'pt'),
(106, 'DavidCharlesHaller', 'David Charles Haller', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'DavidCharlesHaller@mydomain.com', 'en'),
(107, 'HankPym', 'Hank Pym', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'HankPym@mydomain.com', 'en'),
(108, 'CharlesXavier', 'Charles Xavier', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'CharlesXavier@mydomain.com', 'en'),
(109, 'BruceBanner', 'Bruce Banner', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'BruceBanner@mydomain.com', 'en'),
(110, 'JessicaJones', 'Jessica Jones', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'JessicaJones@mydomain.com', 'en'),
(111, 'Missing', 'Missing', 'ac754a330530832ba1bf7687f577da91', 2, 0, NULL, 'en'),
(112, 'Trash', 'Trash', 'ac754a330530832ba1bf7687f577da91', 2, 0, NULL, 'en');
INSERT INTO `vn`.`worker`(`id`, `code`, `firstName`, `lastName`, `userFk`,`bossFk`, `phone`)
VALUES
@ -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

View File

@ -788,7 +788,7 @@ export default {
createdThermograph: 'vn-travel-thermograph-index vn-tbody > vn-tr',
upload: 'vn-travel-thermograph-create button[type=submit]'
},
agencyBasicData: {
zoneBasicData: {
name: 'vn-zone-basic-data vn-textfield[ng-model="$ctrl.zone.name"]',
agency: 'vn-zone-basic-data vn-autocomplete[ng-model="$ctrl.zone.agencyModeFk"]',
maxVolume: 'vn-zone-basic-data vn-input-number[ng-model="$ctrl.zone.m3Max"]',
@ -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"]',
}
};

View File

@ -1,103 +0,0 @@
import selectors from '../../helpers/selectors.js';
import getBrowser from '../../helpers/puppeteer';
describe('Agency basic data path', () => {
let browser;
let page;
beforeAll(async() => {
browser = await getBrowser();
page = browser.page;
await page.loginAndModule('deliveryBoss', 'zone'); // turns up the agency module name and route aint the same lol
await page.accessToSearchResult('10');
await page.accessToSection('zone.card.basicData');
});
afterAll(async() => {
await browser.close();
});
it('should reach the basic data section', async() => {
let url = await page.expectURL('#!/zone/10/basic-data');
expect(url).toBe(true);
});
it('should edit de form and then save', async() => {
await page.clearInput(selectors.agencyBasicData.name);
await page.write(selectors.agencyBasicData.name, 'Brimstone teleportation');
await page.autocompleteSearch(selectors.agencyBasicData.agency, 'Quantum break device');
await page.write(selectors.agencyBasicData.maxVolume, '10');
await page.clearInput(selectors.agencyBasicData.travelingDays);
await page.write(selectors.agencyBasicData.travelingDays, '1');
await page.clearInput(selectors.agencyBasicData.closing);
await page.type(selectors.agencyBasicData.closing, '2100');
await page.clearInput(selectors.agencyBasicData.price);
await page.write(selectors.agencyBasicData.price, '999');
await page.clearInput(selectors.agencyBasicData.bonus);
await page.write(selectors.agencyBasicData.bonus, '100');
await page.clearInput(selectors.agencyBasicData.inflation);
await page.write(selectors.agencyBasicData.inflation, '200');
await page.waitToClick(selectors.agencyBasicData.volumetric);
await page.waitToClick(selectors.agencyBasicData.saveButton);
});
it('should reload the section', async() => {
await page.reloadSection('zone.card.basicData');
let url = await page.expectURL('#!/zone/10/basic-data');
expect(url).toBe(true);
});
it('should confirm the name was updated', async() => {
const result = await page.waitToGetProperty(selectors.agencyBasicData.name, 'value');
expect(result).toEqual('Brimstone teleportation');
});
it('should confirm the agency was updated', async() => {
const result = await page.waitToGetProperty(selectors.agencyBasicData.agency, 'value');
expect(result).toEqual('Quantum break device');
});
it('should confirm the max volume was updated', async() => {
const result = await page.waitToGetProperty(selectors.agencyBasicData.maxVolume, 'value');
expect(result).toEqual('10');
});
it('should confirm the traveling days were updated', async() => {
const result = await page.waitToGetProperty(selectors.agencyBasicData.travelingDays, 'value');
expect(result).toEqual('1');
});
it('should confirm the closing hour was updated', async() => {
const result = await page.waitToGetProperty(selectors.agencyBasicData.closing, 'value');
expect(result).toEqual('21:00');
});
it('should confirm the price was updated', async() => {
const result = await page.waitToGetProperty(selectors.agencyBasicData.price, 'value');
expect(result).toEqual('999');
});
it('should confirm the bonus was updated', async() => {
const result = await page.waitToGetProperty(selectors.agencyBasicData.bonus, 'value');
expect(result).toEqual('100');
});
it('should confirm the inflation was updated', async() => {
const result = await page.waitToGetProperty(selectors.agencyBasicData.inflation, 'value');
expect(result).toEqual('200');
});
it('should confirm the volumetric checkbox was checked', async() => {
await page.waitForClassPresent(selectors.agencyBasicData.volumetric, 'checked');
});
});

View File

@ -0,0 +1,103 @@
import selectors from '../../helpers/selectors.js';
import getBrowser from '../../helpers/puppeteer';
describe('Zone basic data path', () => {
let browser;
let page;
beforeAll(async() => {
browser = await getBrowser();
page = browser.page;
await page.loginAndModule('deliveryBoss', 'zone'); // turns up the zone module name and route aint the same lol
await page.accessToSearchResult('10');
await page.accessToSection('zone.card.basicData');
});
afterAll(async() => {
await browser.close();
});
it('should reach the basic data section', async() => {
let url = await page.expectURL('#!/zone/10/basic-data');
expect(url).toBe(true);
});
it('should edit de form and then save', async() => {
await page.clearInput(selectors.zoneBasicData.name);
await page.write(selectors.zoneBasicData.name, 'Brimstone teleportation');
await page.autocompleteSearch(selectors.zoneBasicData.agency, 'Quantum break device');
await page.write(selectors.zoneBasicData.maxVolume, '10');
await page.clearInput(selectors.zoneBasicData.travelingDays);
await page.write(selectors.zoneBasicData.travelingDays, '1');
await page.clearInput(selectors.zoneBasicData.closing);
await page.type(selectors.zoneBasicData.closing, '2100');
await page.clearInput(selectors.zoneBasicData.price);
await page.write(selectors.zoneBasicData.price, '999');
await page.clearInput(selectors.zoneBasicData.bonus);
await page.write(selectors.zoneBasicData.bonus, '100');
await page.clearInput(selectors.zoneBasicData.inflation);
await page.write(selectors.zoneBasicData.inflation, '200');
await page.waitToClick(selectors.zoneBasicData.volumetric);
await page.waitToClick(selectors.zoneBasicData.saveButton);
});
it('should reload the section', async() => {
await page.reloadSection('zone.card.basicData');
let url = await page.expectURL('#!/zone/10/basic-data');
expect(url).toBe(true);
});
it('should confirm the name was updated', async() => {
const result = await page.waitToGetProperty(selectors.zoneBasicData.name, 'value');
expect(result).toEqual('Brimstone teleportation');
});
it('should confirm the agency was updated', async() => {
const result = await page.waitToGetProperty(selectors.zoneBasicData.agency, 'value');
expect(result).toEqual('Quantum break device');
});
it('should confirm the max volume was updated', async() => {
const result = await page.waitToGetProperty(selectors.zoneBasicData.maxVolume, 'value');
expect(result).toEqual('10');
});
it('should confirm the traveling days were updated', async() => {
const result = await page.waitToGetProperty(selectors.zoneBasicData.travelingDays, 'value');
expect(result).toEqual('1');
});
it('should confirm the closing hour was updated', async() => {
const result = await page.waitToGetProperty(selectors.zoneBasicData.closing, 'value');
expect(result).toEqual('21:00');
});
it('should confirm the price was updated', async() => {
const result = await page.waitToGetProperty(selectors.zoneBasicData.price, 'value');
expect(result).toEqual('999');
});
it('should confirm the bonus was updated', async() => {
const result = await page.waitToGetProperty(selectors.zoneBasicData.bonus, 'value');
expect(result).toEqual('100');
});
it('should confirm the inflation was updated', async() => {
const result = await page.waitToGetProperty(selectors.zoneBasicData.inflation, 'value');
expect(result).toEqual('200');
});
it('should confirm the volumetric checkbox was checked', async() => {
await page.waitForClassPresent(selectors.zoneBasicData.volumetric, 'checked');
});
});

View File

@ -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');
});
});

View File

@ -23,6 +23,12 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-net:before {
content: "\e95b";
}
.icon-anonymous:before {
content: "\e95c";
}
.icon-buyrequest:before {
content: "\e914";
}

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 96 KiB

View File

@ -12,7 +12,7 @@ export default function moduleImport(moduleName) {
case 'ticket' : return import('ticket/front');
case 'order' : return import('order/front');
case 'claim' : return import('claim/front');
case 'agency' : return import('agency/front');
case 'zone' : return import('zone/front');
case 'travel' : return import('travel/front');
case 'worker' : return import('worker/front');
case 'invoiceOut' : return import('invoiceOut/front');

View File

@ -32,7 +32,7 @@ Remove: Quitar
# Modules
Agencies: Agencias
Zones: Zonas
Claims: Reclamaciones
Clients: Clientes
Items: Artículos

View File

@ -2,7 +2,7 @@ import 'angular';
import 'angular-mocks';
import core from './front/core/module.js';
import './front/salix/components/app/app.js';
import './modules/agency/front/module.js';
import './modules/zone/front/module.js';
import './modules/claim/front/module.js';
import './modules/client/front/module.js';
import './modules/invoiceOut/front/module.js';

View File

@ -1,3 +0,0 @@
import {ng} from 'core/vendor';
export default ng.module('agency', ['vnCore']);

View File

@ -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;

View File

@ -77,18 +77,15 @@
<tpl-body>
<div>
<h5 style="text-align: center">
<span translate>From date</span>
<span translate>Send consumer report</span>
</h5>
<vn-date-picker
vn-id="from"
vn-one
ng-model="$ctrl.from"
label="From hour"
label="From date"
vn-focus>
</vn-date-picker>
<h5 style="text-align: center">
<span translate>To date</span>
</h5>
<vn-date-picker
vn-id="to"
vn-one

View File

@ -1,2 +1,4 @@
Simple ticket: Ticket simple
Send consumer report: Enviar informe de consumo
From date: Fecha desde
To date: Fecha hasta

View File

@ -68,6 +68,14 @@ module.exports = Self => {
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':

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(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');
});
});

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

@ -6,16 +6,37 @@
<a translate-attr="{title: 'Preview'}" ui-sref="entry.card.summary({id: $ctrl.entry.id})">
<vn-icon icon="desktop_windows"></vn-icon>
</a>
<span></span>
<vn-icon-menu
vn-id="more-button"
icon="more_vert"
show-filter="false"
value-field="callback"
translate-fields="['name']"
data="$ctrl.moreOptions"
on-change="$ctrl.onMoreChange(value)"
on-open="$ctrl.onMoreOpen()">
</vn-icon-menu>
</div>
<div class="body">
<div class="attributes">
<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

@ -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'

View File

@ -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(`<vn-entry-descriptor></vn-entry-descriptor>`);
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);
});
});
});

View File

@ -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

View File

@ -5,7 +5,4 @@ import './index/';
import './search-panel';
import './descriptor';
import './card';
// import './summary';
// import './basic-data';
// import './log';
// import './create';
import './summary';

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

@ -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"
}
}
]
}

View File

@ -54,6 +54,18 @@
ng-model="filter.created">
</vn-date-picker>
</vn-horizontal>
<vn-horizontal>
<vn-date-picker
vn-one
label="From"
ng-model="filter.from">
</vn-date-picker>
<vn-date-picker
vn-one
label="To"
ng-model="filter.to">
</vn-date-picker>
</vn-horizontal>
<vn-horizontal>
<vn-check
vn-one

View File

@ -0,0 +1,68 @@
<vn-card class="summary">
<h5><span translate>Entry</span> #{{$ctrl.entryData.id}} - {{$ctrl.entryData.supplier.nickname}}</h5>
<vn-horizontal>
<vn-one>
<vn-label-value label="Commission"
value="{{$ctrl.entryData.commission}}">
</vn-label-value>
<vn-label-value label="Currency"
value="{{$ctrl.entryData.currency.name}}">
</vn-label-value>
<vn-label-value label="Company"
value="{{$ctrl.entryData.company.code}}">
</vn-label-value>
<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-one>
<vn-one>
<vn-label-value label="Agency"
value="{{$ctrl.entryData.travel.agency.name}}">
</vn-label-value>
<vn-label-value label="Shipped"
value="{{$ctrl.entryData.travel.shipped | date: 'dd/MM/yyyy'}}">
</vn-label-value>
<vn-label-value label="Warehouse Out"
value="{{$ctrl.entryData.travel.warehouseOut.name}}">
</vn-label-value>
<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-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>

View File

@ -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: '<'
}
});

View File

@ -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(`<vn-entry-summary></vn-entry-summary>`);
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');
});
});
});

View File

@ -0,0 +1,3 @@
Inventory: Inventario
Virtual: Redada
Entry: Entrada

View File

@ -0,0 +1,10 @@
@import "variables";
vn-entry-summary .summary {
max-width: $width-lg;
vn-icon[icon=insert_drive_file]{
color: $color-font-secondary;
}
}

View File

@ -1,4 +1,4 @@
<vn-crud-model auto-load="true"
<vn-crud-model
vn-id="model"
url="TicketRequests/filter"
limit="20"

View File

@ -38,7 +38,8 @@ module.exports = Self => {
case 'search':
return {or: [
{'t.id': value},
{'c.id': value}
{'c.id': value},
{'c.name': {like: `%${value}%`}}
]};
}
});

View File

@ -0,0 +1,41 @@
const app = require('vn-loopback/server/server');
describe('ticket-weekly filter()', () => {
const authUserId = 9;
it('should return the tickets matching the filter', async() => {
const ctx = {req: {accessToken: {userId: authUserId}}, args: {}};
const filter = {order: 'id DESC'};
const result = await app.models.TicketWeekly.filter(ctx, filter);
const firstRow = result[0];
expect(firstRow.ticketFk).toEqual(1);
});
it('should return the ticket with id one', async() => {
const ctx = {req: {accessToken: {userId: authUserId}}, args: {search: 2}};
const filter = {};
const result = await app.models.TicketWeekly.filter(ctx, filter);
const firstRow = result[0];
expect(firstRow.ticketFk).toEqual(2);
});
it('should return the ticket matching the client name', async() => {
const ctx = {req: {accessToken: {userId: authUserId}}, args: {search: 'bruce'}};
const filter = {};
const result = await app.models.TicketWeekly.filter(ctx, filter);
const firstRow = result[0];
expect(firstRow.clientName).toEqual('Bruce Wayne');
});
it('should return the ticket matching the client id', async() => {
const ctx = {req: {accessToken: {userId: authUserId}}, args: {search: 101}};
const filter = {};
const result = await app.models.TicketWeekly.filter(ctx, filter);
const firstRow = result[0];
expect(firstRow.clientFk).toEqual(101);
expect(firstRow.clientName).toEqual('Bruce Wayne');
});
});

View File

@ -96,7 +96,8 @@ module.exports = Self => {
});
Self.filter = async(ctx, filter) => {
let conn = Self.dataSource.connector;
const conn = Self.dataSource.connector;
const args = ctx.args;
let worker = await Self.app.models.Worker.findOne({
where: {userFk: ctx.req.accessToken.userId},
@ -107,13 +108,13 @@ module.exports = Self => {
let teamIds = [];
if (worker.collegues().length && ctx.args.myTeam) {
if (worker.collegues().length && args.myTeam) {
worker.collegues().forEach(collegue => {
teamIds.push(collegue.collegueFk);
});
}
if (ctx.args.mine || (worker.collegues().length === 0 && ctx.args.myTeam)) {
if (args.mine || (worker.collegues().length === 0 && args.myTeam)) {
worker = await Self.app.models.Worker.findOne({
fields: ['id'],
where: {userFk: ctx.req.accessToken.userId}
@ -121,23 +122,14 @@ module.exports = Self => {
teamIds = [worker && worker.id];
}
if (ctx.args && (ctx.args.mine || ctx.args.myTeam))
ctx.args.teamIds = teamIds;
if (ctx.args && (args.mine || args.myTeam))
args.teamIds = teamIds;
if (ctx.args && ctx.args.to) {
const dateTo = ctx.args.to;
if (ctx.args && args.to) {
const dateTo = args.to;
dateTo.setHours(23, 59, 0, 0);
}
let orderTickets = [];
if (ctx.args && ctx.args.orderFk) {
let ticketsToSearch = await Self.app.models.OrderTicket.find({where: {orderFk: ctx.args.orderFk}});
ticketsToSearch.forEach(ticket => {
orderTickets.push(ticket.ticketFk);
});
ctx.args.search = orderTickets;
}
let where = buildFilter(ctx.args, (param, value) => {
switch (param) {
case 'search':
@ -215,6 +207,14 @@ module.exports = Self => {
LEFT JOIN client c ON c.id = t.clientFk
LEFT JOIN worker wk ON wk.id = c.salesPersonFk
LEFT JOIN account.user u ON u.id = wk.userFk`);
if (args.orderFk) {
stmt.merge({
sql: `JOIN orderTicket ot ON ot.ticketFk = t.id AND ot.orderFk = ?`,
params: [args.orderFk]
});
}
stmt.merge(conn.makeSuffix(filter));
stmts.push(stmt);
@ -249,7 +249,7 @@ module.exports = Self => {
let hasProblem;
let range;
let hasWhere;
switch (ctx.args.problems) {
switch (args.problems) {
case true:
condition = `or`;
hasProblem = true;

View File

@ -2,39 +2,45 @@ const app = require('vn-loopback/server/server');
describe('ticket filter()', () => {
it('should return the tickets matching the filter', async() => {
let ctx = {req: {accessToken: {userId: 9}}, args: {}};
let filter = {order: 'id DESC'};
let result = await app.models.Ticket.filter(ctx, filter);
let ticketId = result[0].id;
const ctx = {req: {accessToken: {userId: 9}}, args: {}};
const filter = {order: 'id DESC'};
const result = await app.models.Ticket.filter(ctx, filter);
const ticketId = result[0].id;
expect(ticketId).toEqual(24);
});
it('should return the tickets matching the problems on true', async() => {
let ctx = {req: {accessToken: {userId: 9}}, args: {problems: true}};
let filter = {};
let result = await app.models.Ticket.filter(ctx, filter);
const ctx = {req: {accessToken: {userId: 9}}, args: {problems: true}};
const filter = {};
const result = await app.models.Ticket.filter(ctx, filter);
expect(result.length).toEqual(4);
});
it('should return the tickets matching the problems on false', async() => {
let ctx = {req: {accessToken: {userId: 9}}, args: {problems: false}};
let filter = {};
let result = await app.models.Ticket.filter(ctx, filter);
const ctx = {req: {accessToken: {userId: 9}}, args: {problems: false}};
const filter = {};
const result = await app.models.Ticket.filter(ctx, filter);
expect(result.length).toEqual(20);
});
it('should return the tickets matching the problems on null', async() => {
let ctx = {req: {accessToken: {userId: 9}}, args: {problems: null}};
let filter = {};
let result = await app.models.Ticket.filter(ctx, filter);
const ctx = {req: {accessToken: {userId: 9}}, args: {problems: null}};
const filter = {};
const result = await app.models.Ticket.filter(ctx, filter);
expect(result.length).toEqual(24);
});
it('should return the tickets matching the orderId 11', async() => {
const ctx = {req: {accessToken: {userId: 9}}, args: {orderFk: 11}};
const filter = {};
const result = await app.models.Ticket.filter(ctx, filter);
const firstRow = result[0];
expect(result.length).toEqual(1);
expect(firstRow.ticketFk).toEqual(11);
});
});

View File

@ -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');

View File

@ -16,13 +16,10 @@
<vn-thead>
<vn-tr>
<vn-th field="dmsFk" shrink>Id</vn-th>
<vn-th field="dmsTypeFk" shrink>Type</vn-th>
<vn-th field="hardCopyNumber" shrink number>Order</vn-th>
<vn-th field="reference" shrink>Reference</vn-th>
<vn-th expand>Description</vn-th>
<vn-th field="hasFile" shrink>Original</vn-th>
<vn-th shrink>File</vn-th>
<vn-th shrink>Employee</vn-th>
<vn-th field="created">Created</vn-th>
<vn-th shrink></vn-th>
<vn-th shrink></vn-th>
@ -32,17 +29,6 @@
<vn-tbody>
<vn-tr ng-repeat="document in $ctrl.workerDms">
<vn-td number shrink>{{::document.dmsFk}}</vn-td>
<vn-td shrink>
<span title="{{::document.dms.dmsType.name}}">
{{::document.dms.dmsType.name}}
</span>
</vn-td>
<vn-td shrink number>
<span class="chip" title="{{::document.dms.hardCopyNumber}}"
ng-class="{'message': document.dms.hardCopyNumber}">
{{::document.dms.hardCopyNumber}}
</span>
</vn-td>
<vn-td shrink>
<span title="{{::document.dms.reference}}">
{{::document.dms.reference}}
@ -64,12 +50,6 @@
href="api/dms/{{::document.dmsFk}}/downloadFile?access_token={{::$ctrl.accessToken}}">{{::document.dms.file}}
</a>
</vn-td>
<vn-td shrink>
<span class="link"
ng-click="$ctrl.showWorkerDescriptor($event, document.dms.workerFk)">
{{::document.dms.worker.user.nickname | dashIfEmpty}}
</span></vn-td>
<vn-td>
{{::document.dms.created | date:'dd/MM/yyyy HH:mm'}}
</vn-td>
<vn-td shrink>

View File

@ -41,6 +41,9 @@
},
"bonus": {
"type": "Number"
},
"m3Max": {
"type": "Number"
}
},
"relations": {

View File

@ -5,7 +5,7 @@ describe('Agency Component vnZoneCard', () => {
let $httpBackend;
let data = {id: 1, name: 'fooName'};
beforeEach(ngModule('agency'));
beforeEach(ngModule('zone'));
beforeEach(angular.mock.inject(($componentController, _$httpBackend_, $stateParams) => {
$httpBackend = _$httpBackend_;

View File

@ -6,7 +6,7 @@ describe('Agency Component vnZoneCreate', () => {
let $state;
let controller;
beforeEach(ngModule('agency'));
beforeEach(ngModule('zone'));
beforeEach(angular.mock.inject(($componentController, $rootScope, _$state_) => {
$scope = $rootScope.$new();

View File

@ -75,6 +75,10 @@
label="Bonus"
value="{{::row.bonus | currency:'EUR':2}}">
</vn-label-value>
<vn-label-value
label="Max m3"
value="{{::row.m3Max}}">
</vn-label-value>
</vn-item-section>
<vn-item-section side>
<vn-icon-button
@ -130,25 +134,35 @@
ng-model="$ctrl.selected.ended">
</vn-date-picker>
</vn-horizontal>
<vn-input-time
label="Closing"
ng-model="$ctrl.selected.hour">
</vn-input-time>
<vn-horizontal>
<vn-input-time
label="Closing"
ng-model="$ctrl.selected.hour">
</vn-input-time>
<vn-input-number
label="Traveling days"
ng-model="$ctrl.selected.travelingDays"
min="0"
step="1">
</vn-input-number>
</vn-horizontal>
<vn-horizontal>
<vn-input-number
label="Price"
ng-model="$ctrl.selected.price"
min="0"
step="0.01">
</vn-input-number>
<vn-input-number
label="Bonus"
ng-model="$ctrl.selected.bonus"
min="0"
step="0.01">
</vn-input-number>
</vn-horizontal>
<vn-input-number
label="Traveling days"
ng-model="$ctrl.selected.travelingDays"
min="0"
step="1">
</vn-input-number>
<vn-input-number
label="Price"
ng-model="$ctrl.selected.price"
min="0"
step="0.01">
</vn-input-number>
<vn-input-number
label="Bonus"
ng-model="$ctrl.selected.bonus"
label="Max m3"
ng-model="$ctrl.selected.m3Max"
min="0"
step="0.01">
</vn-input-number>

View File

@ -4,7 +4,7 @@ describe('Agency Component vnZoneIndex', () => {
let $componentController;
let controller;
beforeEach(ngModule('agency'));
beforeEach(ngModule('zone'));
beforeEach(angular.mock.inject(_$componentController_ => {
$componentController = _$componentController_;

Some files were not shown because too many files have changed in this diff Show More