Merge pull request 'Added section' (#452) from 2569-travel_extra_community into dev
gitea/salix/pipeline/head This commit looks good Details

Reviewed-on: #452
Reviewed-by: Carlos Jimenez Ruiz <carlosjr@verdnatura.es>
This commit is contained in:
Joan Sanchez 2020-11-24 10:29:34 +00:00
commit cca33e0945
69 changed files with 1272 additions and 260 deletions

2
Jenkinsfile vendored
View File

@ -65,7 +65,7 @@ pipeline {
stage('Frontend') {
steps {
nodejs('node-lts') {
sh 'jest --ci --reporters=default --reporters=jest-junit --maxWorkers=1'
sh 'jest --ci --reporters=default --reporters=jest-junit --maxWorkers=2'
}
}
}

View File

@ -20,6 +20,9 @@
"Container": {
"dataSource": "storage"
},
"Continent": {
"dataSource": "vn"
},
"Collection": {
"dataSource": "vn"
},

View File

@ -0,0 +1,27 @@
{
"name": "Continent",
"base": "VnModel",
"options": {
"mysql": {
"table": "continent"
}
},
"properties": {
"id": {
"type": "number"
},
"name": {
"type": "string"
},
"code": {
"id": true,
"type": "string"
}
},
"acls": [{
"accessType": "READ",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
}]
}

View File

@ -0,0 +1,20 @@
CREATE TABLE `vn`.continent
(
id TINYINT(4) AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
code VARCHAR(2) NOT NULL COLLATE utf8_general_ci,
CONSTRAINT continent_pk
PRIMARY KEY (id)
)
COMMENT 'World continents';
CREATE UNIQUE INDEX continent_name_uindex
ON `vn`.continent (name);
INSERT IGNORE INTO `vn`.continent (`name`, `code`)
VALUES
('Asia', 'AS'),
('América', 'AM'),
('África', 'AF'),
('Europa', 'EU'),
('Oceanía', 'OC');

View File

@ -0,0 +1,13 @@
ALTER TABLE `vn`.`country`
ADD COLUMN `continentFk` TINYINT(4) NULL AFTER `ibanLength`,
ADD INDEX `continent_id_fk_idx` (`continentFk` ASC);
ALTER TABLE `vn`.`country`
ADD CONSTRAINT `continent_id_fk`
FOREIGN KEY (`continentFk`)
REFERENCES `vn`.`continent` (`id`)
ON DELETE NO ACTION
ON UPDATE CASCADE;
UPDATE `vn`.`country` SET `continentFk` = '2' WHERE (`id` = '11');
UPDATE `vn`.`country` SET `continentFk` = '2' WHERE (`id` = '13');

View File

@ -3,3 +3,4 @@ host = localhost
port = 3306
user = root
password = root
default-character-set=utf8

View File

@ -92,17 +92,17 @@ INSERT INTO `vn`.`worker`(`id`, `code`, `firstName`, `lastName`, `userFk`,`bossF
(109, 'HLK', 'Bruce' , 'Banner', 109, 19, 432978109),
(110, 'JJJ', 'Jessica' , 'Jones' , 110, 19, 432978110);
INSERT INTO `vn`.`country`(`id`, `country`, `isUeeMember`, `code`, `currencyFk`, `ibanLength`)
INSERT INTO `vn`.`country`(`id`, `country`, `isUeeMember`, `code`, `currencyFk`, `ibanLength`, `continentFk`)
VALUES
(1, 'España', 1, 'ES', 1, 24),
(2, 'Italia', 1, 'IT', 1, 27),
(3, 'Alemania', 1, 'DE', 1, 22),
(4, 'Rumania', 1, 'RO', 1, 24),
(5, 'Holanda', 1, 'NL', 1, 18),
(8, 'Portugal', 1, 'PT', 1, 27),
(13,'Ecuador', 0, 'EC', 1, 24),
(19,'Francia', 1, 'FR', 1, 27),
(30,'Canarias', 1, 'IC', 1, 24);
(1, 'España', 1, 'ES', 1, 24, 4),
(2, 'Italia', 1, 'IT', 1, 27, 4),
(3, 'Alemania', 1, 'DE', 1, 22, 4),
(4, 'Rumania', 1, 'RO', 1, 24, 4),
(5, 'Holanda', 1, 'NL', 1, 18, 4),
(8, 'Portugal', 1, 'PT', 1, 27, 4),
(13,'Ecuador', 0, 'EC', 1, 24, 2),
(19,'Francia', 1, 'FR', 1, 27, 4),
(30,'Canarias', 1, 'IC', 1, 24, 4);
INSERT INTO `hedera`.`language` (`code`, `name`, `orgName`, `isActive`)
VALUES
@ -118,13 +118,13 @@ INSERT INTO `vn`.`warehouseAlias`(`id`, `name`)
(1, 'Main Warehouse'),
(2, 'Silla');
INSERT INTO `vn`.`warehouse`(`id`, `name`, `isComparative`, `isInventory`, `hasAvailable`, `isManaged`, `hasStowaway`, `hasDms`, `hasComission`, `aliasFk`)
INSERT INTO `vn`.`warehouse`(`id`, `name`, `isComparative`, `isInventory`, `hasAvailable`, `isManaged`, `hasStowaway`, `hasDms`, `hasComission`, `aliasFk`, `countryFk`)
VALUES
(1, 'Warehouse One', 1, 1, 1, 1, 1, 1, 1, 2),
(2, 'Warehouse Two', 1, 1, 1, 1, 0, 0, 1, 2),
(3, 'Warehouse Three', 1, 1, 1, 1, 0, 0, 0, 2),
(4, 'Warehouse Four', 1, 1, 1, 1, 0, 0, 0, 2),
(5, 'Warehouse Five', 1, 1, 1, 1, 0, 0, 0, 2);
(1, 'Warehouse One', 1, 1, 1, 1, 1, 1, 1, 2, 1),
(2, 'Warehouse Two', 1, 1, 1, 1, 0, 0, 1, 2, 13),
(3, 'Warehouse Three', 1, 1, 1, 1, 0, 0, 0, 2, 1),
(4, 'Warehouse Four', 1, 1, 1, 1, 0, 0, 0, 2, 1),
(5, 'Warehouse Five', 1, 1, 1, 1, 0, 0, 0, 2, 1);
INSERT INTO `vn`.`sector`(`id`, `description`, `warehouseFk`, `isPreviousPreparedByPacking`, `code`, `pickingPlacement`, `path`)
VALUES
@ -1250,11 +1250,11 @@ INSERT INTO `vn`.`travel`(`id`,`shipped`, `landed`, `warehouseInFk`, `warehouseO
(1, DATE_ADD(CURDATE(), INTERVAL -2 MONTH), DATE_ADD(CURDATE(), INTERVAL -2 MONTH), 1, 2, 1, 100.00, 1000, 'first travel', 1, 1),
(2, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 1, 2, 1, 150, 2000, 'second travel', 2, 2),
(3, CURDATE(), CURDATE(), 1, 2, 1, 0.00, 0.00, 'third travel', 1, 1),
(4, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 1, 2, 1, 50.00, 500, 'fourth travel', 0, 2),
(5, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 3, 2, 1, 50.00, 500, 'fifth travel', 1, 1),
(6, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 4, 2, 1, 50.00, 500, 'sixth travel', 1, 2),
(7, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 5, 2, 1, 50.00, 500, 'seventh travel', 2, 1),
(8, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 5, 2, 1, 50.00, 500, 'eight travel', 1, 2);
(4, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 1, 3, 1, 50.00, 500, 'fourth travel', 0, 2),
(5, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 3, 3, 1, 50.00, 500, 'fifth travel', 1, 1),
(6, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 4, 4, 1, 50.00, 500, 'sixth travel', 1, 2),
(7, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 5, 4, 1, 50.00, 500, 'seventh travel', 2, 1),
(8, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 5, 1, 1, 50.00, 500, 'eight travel', 1, 2);
INSERT INTO `vn`.`entry`(`id`, `supplierFk`, `created`, `travelFk`, `isConfirmed`, `companyFk`, `ref`,`isInventory`, `isRaid`, `notes`, `evaNotes`)
VALUES

View File

@ -155,7 +155,7 @@ let actions = {
document.querySelector(selector).scrollIntoViewIfNeeded();
}, selector);
await this.waitToClick(selector);
await this.wait('vn-left-menu .expanded');
await this.waitForSelector('vn-left-menu .expanded');
}
await this.evaluate(state => {
@ -175,7 +175,7 @@ let actions = {
forceReloadSection: async function(sectionRoute) {
await this.waitToClick('vn-icon[icon="preview"]');
await this.waitToClick('button[response="accept"]');
await this.wait('vn-card.summary');
await this.waitForSelector('vn-card.summary');
await this.waitToClick(`vn-left-menu li > a[ui-sref="${sectionRoute}"]`);
},
@ -190,7 +190,7 @@ let actions = {
accessToSearchResult: async function(searchValue) {
await this.doSearch(searchValue);
await this.waitFor('.vn-descriptor');
await this.waitForSelector('.vn-descriptor');
},
getProperty: async function(selector, property) {
@ -267,12 +267,13 @@ let actions = {
writeOnEditableTD: async function(selector, text) {
let builtSelector = await this.selectorFormater(selector);
await this.waitToClick(selector);
await this.waitForSelector(builtSelector, {visible: true});
await this.type(builtSelector, text);
await this.keyboard.press('Enter');
},
focusElement: async function(selector) {
await this.wait(selector);
await this.waitForSelector(selector);
return await this.evaluate(selector => {
let element = document.querySelector(selector);
element.focus();
@ -285,8 +286,8 @@ let actions = {
},
waitImgLoad: async function(selector) {
await this.wait(selector);
return await this.wait(selector => {
await this.waitForSelector(selector);
return await this.waitForFunction(selector => {
const imageReady = document.querySelector(selector).complete;
return imageReady;
}, {}, selector);
@ -305,16 +306,16 @@ let actions = {
},
waitForClassNotPresent: async function(selector, className) {
await this.wait(selector);
return await this.wait((selector, className) => {
await this.waitForSelector(selector);
return await this.waitForFunction((selector, className) => {
if (!document.querySelector(selector).classList.contains(className))
return true;
}, {}, selector, className);
},
waitForClassPresent: async function(selector, className) {
await this.wait(selector);
return await this.wait((elementSelector, targetClass) => {
await this.waitForSelector(selector);
return await this.waitForFunction((elementSelector, targetClass) => {
if (document.querySelector(elementSelector).classList.contains(targetClass))
return true;
}, {}, selector, className);
@ -387,7 +388,7 @@ let actions = {
},
waitForEmptyInnerText: async function(selector) {
return await this.wait(selector => {
return await this.waitFunction(selector => {
return document.querySelector(selector).innerText == '';
}, selector);
},
@ -395,7 +396,7 @@ let actions = {
hideSnackbar: async function() {
// Holds up for the snackbar to be visible for a small period of time.
if (process.env.E2E_DEBUG)
await this.waitFor(300);
await this.waitForTimeout(300);
await this.evaluate(() => {
let hideButton = document
@ -403,7 +404,7 @@ let actions = {
if (hideButton)
return hideButton.click();
});
await this.waitFor('vn-snackbar .shape.shown', {hidden: true});
await this.waitForSelector('vn-snackbar .shape.shown', {hidden: true});
},
waitForSnackbar: async function() {
@ -438,7 +439,7 @@ let actions = {
const localDate = (new Date(date.getTime() - timeZoneOffset))
.toISOString().substr(0, 10);
await this.wait(selector);
await this.waitForSelector(selector);
await this.evaluate((selector, localDate) => {
let input = document.querySelector(selector).$ctrl.input;
input.value = localDate;
@ -447,7 +448,7 @@ let actions = {
},
pickTime: async function(selector, time) {
await this.wait(selector);
await this.waitForSelector(selector);
await this.evaluate((selector, time) => {
let input = document.querySelector(selector).$ctrl.input;
input.value = time;
@ -510,11 +511,11 @@ let actions = {
.includes(searchValue.toLowerCase());
}, {}, builtSelector, searchValue);
await this.waitFor('.vn-drop-down', {hidden: true});
await this.waitForSelector('.vn-drop-down', {hidden: true});
},
checkboxState: async function(selector) {
await this.wait(selector);
await this.waitForSelector(selector);
return await this.evaluate(selector => {
let checkbox = document.querySelector(selector);
switch (checkbox.$ctrl.field) {
@ -537,7 +538,7 @@ let actions = {
},
waitForStylePresent: async function(selector, property, value) {
return await this.wait((selector, property, value) => {
return await this.waitForFunction((selector, property, value) => {
const element = document.querySelector(selector);
return element.style[property] == value;
}, {}, selector, property, value);
@ -548,8 +549,8 @@ let actions = {
},
waitForWatcherData: async function(selector) {
await this.wait(selector);
await this.wait(selector => {
await this.waitForSelector(selector);
await this.waitForFunction(selector => {
let watcher = document.querySelector(selector);
let orgData = watcher.$ctrl.orgData;
return !angular.equals({}, orgData) && orgData != null;
@ -596,7 +597,7 @@ let actions = {
closePopup: async function() {
await Promise.all([
this.keyboard.press('Escape'),
this.waitFor('.vn-popup', {hidden: true}),
this.waitForSelector('.vn-popup', {hidden: true}),
]);
},

View File

@ -823,6 +823,10 @@ export default {
anySearchResult: 'vn-travel-index vn-tbody > a',
firstSearchResult: 'vn-travel-index vn-tbody > a:nth-child(1)'
},
travelExtraCommunity: {
firstTravelReference: 'vn-travel-extra-community > vn-data-viewer div > vn-tbody > vn-tr > vn-td-editable',
removeContinentFilter: 'vn-searchbar > form > vn-textfield > div.container > div.prepend > prepend > div > span:nth-child(3) > vn-icon > i'
},
travelBasicDada: {
reference: 'vn-travel-basic-data vn-textfield[ng-model="$ctrl.travel.ref"]',
agency: 'vn-travel-basic-data vn-autocomplete[ng-model="$ctrl.travel.agencyModeFk"]',

View File

@ -45,7 +45,7 @@ describe('Login path', async() => {
describe('Successful login', async() => {
it('should log in and go to home state', async() => {
await page.doLogin('employee');
await page.waitFor('vn-home');
await page.waitForSelector('vn-home');
const state = await page.getState();
expect(state).toBe('home');
@ -58,7 +58,7 @@ describe('Login path', async() => {
await page.waitToClick(selectors.globalItems.userMenuButton);
await page.waitToClick(selectors.globalItems.logoutButton);
await page.waitFor('vn-login');
await page.waitForSelector('vn-login');
const state = await page.getState();
expect(state).toBe('login');

View File

@ -124,9 +124,9 @@ describe('Client create path', () => {
it('should click on the Clients button of the top bar menu', async() => {
await page.waitToClick(selectors.globalItems.applicationsMenuButton);
await page.wait(selectors.globalItems.applicationsMenuVisible);
await page.waitForSelector(selectors.globalItems.applicationsMenuVisible);
await page.waitToClick(selectors.globalItems.clientsButton);
await page.wait(selectors.clientsIndex.createClientButton);
await page.waitForSelector(selectors.clientsIndex.createClientButton);
await page.waitForState('client.index');
});

View File

@ -18,7 +18,7 @@ describe('Client Edit basicData path', () => {
describe('as employee', () => {
it('should not be able to change the salesPerson', async() => {
await page.wait(selectors.clientBasicData.name);
await page.waitForSelector(selectors.clientBasicData.name);
const result = await page.evaluate(selector => {
return document.querySelector(selector).disabled;
}, `${selectors.clientBasicData.salesPerson} input`);

View File

@ -40,7 +40,7 @@ describe('Client Edit fiscalData path', () => {
});
it('should not be able to edit the verified data checkbox', async() => {
await page.wait(selectors.clientFiscalData.verifiedDataCheckbox);
await page.waitForSelector(selectors.clientFiscalData.verifiedDataCheckbox);
const result = await page.isDisabled(selectors.clientFiscalData.verifiedDataCheckbox);
expect(result).toBeTruthy();
@ -55,7 +55,7 @@ describe('Client Edit fiscalData path', () => {
});
it(`should edit the fiscal data but fail as the fiscal id ain't valid`, async() => {
await page.wait(selectors.clientFiscalData.socialName);
await page.waitForSelector(selectors.clientFiscalData.socialName);
await page.clearInput(selectors.clientFiscalData.socialName);
await page.write(selectors.clientFiscalData.socialName, 'SMASH');
await page.clearInput(selectors.clientFiscalData.fiscalId);
@ -159,7 +159,7 @@ describe('Client Edit fiscalData path', () => {
});
it('should propagate the Equalization tax changes', async() => {
await page.waitFor(1000);
await page.waitForTimeout(1000);
await page.waitToClick(selectors.globalItems.acceptButton);
const message = await page.waitForSnackbar();

View File

@ -17,7 +17,7 @@ describe('Client Add address path', () => {
});
it(`should click on the add new address button to access to the new address form`, async() => {
await page.waitFor(500);
await page.waitForTimeout(500);
await page.waitToClick(selectors.clientAddresses.createAddress);
await page.waitForState('client.card.address.create');
});
@ -81,7 +81,7 @@ describe('Client Add address path', () => {
});
it(`should confirm the new address exists and it's the default one`, async() => {
await page.waitFor(2000); // needs more than a single second to load the section
await page.waitForTimeout(2000); // needs more than a single second to load the section
const result = await page.waitToGetProperty(selectors.clientAddresses.defaultAddress, 'innerText');
expect(result).toContain('320 Park Avenue New York');

View File

@ -26,7 +26,7 @@ describe('Client Add notes path', () => {
});
it(`should create a note`, async() => {
await page.waitFor(selectors.clientNotes.note);
await page.waitForSelector(selectors.clientNotes.note);
await page.type(`${selectors.clientNotes.note} textarea`, 'Meeting with Black Widow 21st 9am');
await page.waitToClick(selectors.clientNotes.saveButton);
const message = await page.waitForSnackbar();

View File

@ -18,15 +18,15 @@ describe('Client lock verified data path', () => {
describe('as salesPerson', () => {
it('should confirm verified data button is disabled for salesPerson', async() => {
await page.wait(200);
await page.wait(selectors.clientFiscalData.verifiedDataCheckbox);
await page.waitForTimeout(200);
await page.waitForSelector(selectors.clientFiscalData.verifiedDataCheckbox);
const result = await page.isDisabled(selectors.clientFiscalData.verifiedDataCheckbox);
expect(result).toBeTruthy();
});
it('should edit the social name', async() => {
await page.wait(selectors.clientFiscalData.socialName);
await page.waitForSelector(selectors.clientFiscalData.socialName);
await page.clearInput(selectors.clientFiscalData.socialName);
await page.write(selectors.clientFiscalData.socialName, 'Captain America Civil War');
await page.waitToClick(selectors.clientFiscalData.saveButton);
@ -75,7 +75,7 @@ describe('Client lock verified data path', () => {
});
it('should again edit the social name', async() => {
await page.wait(selectors.clientFiscalData.socialName);
await page.waitForSelector(selectors.clientFiscalData.socialName);
await page.clearInput(selectors.clientFiscalData.socialName);
await page.write(selectors.clientFiscalData.socialName, 'Ant man and the Wasp');
await page.waitToClick(selectors.clientFiscalData.saveButton);
@ -161,7 +161,7 @@ describe('Client lock verified data path', () => {
});
it('should confirm the form is enabled for salesPerson', async() => {
await page.wait(selectors.clientFiscalData.socialName);
await page.waitForSelector(selectors.clientFiscalData.socialName);
const result = await page.evaluate(selector => {
return document.querySelector(selector).disabled;
}, 'vn-textfield[ng-model="$ctrl.client.socialName"] > div');

View File

@ -113,9 +113,9 @@ describe('Client balance path', () => {
it('should now click on the Clients button of the top bar menu', async() => {
await page.login('employee');
await page.waitToClick(selectors.globalItems.applicationsMenuButton);
await page.wait(selectors.globalItems.applicationsMenuVisible);
await page.waitForSelector(selectors.globalItems.applicationsMenuVisible);
await page.waitToClick(selectors.globalItems.clientsButton);
await page.wait(selectors.clientsIndex.createClientButton);
await page.waitForSelector(selectors.clientsIndex.createClientButton);
await page.waitForState('client.index');
});
@ -125,6 +125,6 @@ describe('Client balance path', () => {
});
it('should not be able to click the new payment button as it isnt present', async() => {
await page.waitFor(selectors.clientBalance.newPaymentButton, {hidden: true});
await page.waitForSelector(selectors.clientBalance.newPaymentButton, {hidden: true});
});
});

View File

@ -52,7 +52,7 @@ describe('User config', () => {
it('should open the user config form to check the settings', async() => {
await page.waitToClick(selectors.globalItems.userMenuButton);
await page.waitFor(1000);
await page.waitForTimeout(1000);
let expectedLocalWarehouse = await page
.expectPropertyValue(selectors.globalItems.userLocalWarehouse, 'value', '');

View File

@ -18,7 +18,7 @@ describe('Client web Payment', () => {
describe('as employee', () => {
it('should not be able to confirm payments', async() => {
await page.waitFor(selectors.webPayment.confirmFirstPaymentButton, {hidden: true});
await page.waitForSelector(selectors.webPayment.confirmFirstPaymentButton, {hidden: true});
});
});
@ -31,7 +31,7 @@ describe('Client web Payment', () => {
it('should be able to confirm payments', async() => {
await page.waitToClick(selectors.webPayment.confirmFirstPaymentButton);
await page.waitFor(selectors.webPayment.firstPaymentConfirmed, {hidden: true});
await page.waitForSelector(selectors.webPayment.firstPaymentConfirmed, {hidden: true});
});
});
});

View File

@ -28,7 +28,7 @@ describe('Client contacts', () => {
});
it('should delete de contact', async() => {
await page.waitFor(3000);
await page.waitForTimeout(3000);
await page.waitToClick(selectors.clientContacts.deleteFirstPhone);
await page.waitToClick(selectors.clientContacts.saveButton);
const message = await page.waitForSnackbar();

View File

@ -26,33 +26,33 @@ describe('Worker calendar path', () => {
it('should set two days as holidays on the calendar and check the total holidays increased by 1.5', async() => {
await page.waitToClick(selectors.workerCalendar.holidays);
await page.waitFor(reasonableTimeBetweenClicks);
await page.waitForTimeout(reasonableTimeBetweenClicks);
await page.waitToClick(selectors.workerCalendar.januaryThirtyFirst);
await page.waitFor(reasonableTimeBetweenClicks);
await page.waitForTimeout(reasonableTimeBetweenClicks);
await page.waitToClick(selectors.workerCalendar.absence);
await page.waitFor(reasonableTimeBetweenClicks);
await page.waitForTimeout(reasonableTimeBetweenClicks);
await page.waitToClick(selectors.workerCalendar.marchTwentyThird);
await page.waitFor(reasonableTimeBetweenClicks);
await page.waitForTimeout(reasonableTimeBetweenClicks);
await page.waitToClick(selectors.workerCalendar.halfHoliday);
await page.waitFor(reasonableTimeBetweenClicks);
await page.waitForTimeout(reasonableTimeBetweenClicks);
await page.waitToClick(selectors.workerCalendar.mayFourth);
await page.waitFor(reasonableTimeBetweenClicks);
await page.waitForTimeout(reasonableTimeBetweenClicks);
await page.waitToClick(selectors.workerCalendar.furlough);
await page.waitFor(reasonableTimeBetweenClicks);
await page.waitForTimeout(reasonableTimeBetweenClicks);
await page.waitToClick(selectors.workerCalendar.mayTwelfth);
await page.waitFor(reasonableTimeBetweenClicks);
await page.waitForTimeout(reasonableTimeBetweenClicks);
await page.waitToClick(selectors.workerCalendar.mayThirteenth);
await page.waitFor(reasonableTimeBetweenClicks);
await page.waitForTimeout(reasonableTimeBetweenClicks);
await page.waitToClick(selectors.workerCalendar.mayFourteenth);
await page.waitFor(reasonableTimeBetweenClicks);
await page.waitForTimeout(reasonableTimeBetweenClicks);
await page.waitToClick(selectors.workerCalendar.halfFurlough);
await page.waitFor(reasonableTimeBetweenClicks);
await page.waitForTimeout(reasonableTimeBetweenClicks);
await page.waitToClick(selectors.workerCalendar.mayEighth);
await page.waitFor(reasonableTimeBetweenClicks);
await page.waitForTimeout(reasonableTimeBetweenClicks);
const result = await page.waitToGetProperty(selectors.workerCalendar.totalHolidaysUsed, 'innerText');
@ -68,33 +68,33 @@ describe('Worker calendar path', () => {
});
it('should undo what was done here', async() => {
await page.waitFor(reasonableTimeBetweenClicks);
await page.waitForTimeout(reasonableTimeBetweenClicks);
await page.waitToClick(selectors.workerCalendar.holidays);
await page.waitFor(reasonableTimeBetweenClicks);
await page.waitForTimeout(reasonableTimeBetweenClicks);
await page.waitToClick(selectors.workerCalendar.januaryThirtyFirst);
await page.waitFor(reasonableTimeBetweenClicks);
await page.waitForTimeout(reasonableTimeBetweenClicks);
await page.waitToClick(selectors.workerCalendar.absence);
await page.waitFor(reasonableTimeBetweenClicks);
await page.waitForTimeout(reasonableTimeBetweenClicks);
await page.waitToClick(selectors.workerCalendar.marchTwentyThird);
await page.waitFor(reasonableTimeBetweenClicks);
await page.waitForTimeout(reasonableTimeBetweenClicks);
await page.waitToClick(selectors.workerCalendar.halfHoliday);
await page.waitFor(reasonableTimeBetweenClicks);
await page.waitForTimeout(reasonableTimeBetweenClicks);
await page.waitToClick(selectors.workerCalendar.mayFourth);
await page.waitFor(reasonableTimeBetweenClicks);
await page.waitForTimeout(reasonableTimeBetweenClicks);
await page.waitToClick(selectors.workerCalendar.furlough);
await page.waitFor(reasonableTimeBetweenClicks);
await page.waitForTimeout(reasonableTimeBetweenClicks);
await page.waitToClick(selectors.workerCalendar.mayTwelfth);
await page.waitFor(reasonableTimeBetweenClicks);
await page.waitForTimeout(reasonableTimeBetweenClicks);
await page.waitToClick(selectors.workerCalendar.mayThirteenth);
await page.waitFor(reasonableTimeBetweenClicks);
await page.waitForTimeout(reasonableTimeBetweenClicks);
await page.waitToClick(selectors.workerCalendar.mayFourteenth);
await page.waitFor(reasonableTimeBetweenClicks);
await page.waitForTimeout(reasonableTimeBetweenClicks);
await page.waitToClick(selectors.workerCalendar.halfFurlough);
await page.waitFor(reasonableTimeBetweenClicks);
await page.waitForTimeout(reasonableTimeBetweenClicks);
await page.waitToClick(selectors.workerCalendar.mayEighth);
});
@ -113,9 +113,9 @@ describe('Worker calendar path', () => {
});
it('should make a futile attempt to add holidays', async() => {
await page.waitFor(reasonableTimeBetweenClicks);
await page.waitForTimeout(reasonableTimeBetweenClicks);
await page.waitToClick(selectors.workerCalendar.holidays);
await page.waitFor(reasonableTimeBetweenClicks);
await page.waitForTimeout(reasonableTimeBetweenClicks);
await page.waitToClick(selectors.workerCalendar.januaryThirtyFirst);
});
@ -131,7 +131,7 @@ describe('Worker calendar path', () => {
await page.autocompleteSearch(selectors.workerCalendar.year, lastYear);
await page.waitFor(reasonableTimeBetweenClicks);
await page.waitForTimeout(reasonableTimeBetweenClicks);
const result = await page.waitToGetProperty(selectors.workerCalendar.totalHolidaysUsed, 'innerText');
expect(result).toContain(' 0 ');

View File

@ -46,7 +46,7 @@ describe('Item Edit basic data path', () => {
await page.write(selectors.itemBasicData.newIntrastatId, '588420239');
await page.write(selectors.itemBasicData.newIntrastatDescription, 'Tropical Flowers');
await page.waitToClick(selectors.itemBasicData.acceptIntrastatButton); // this popover obscures the rest of the form for aprox 2 seconds
await page.waitFor(2000);
await page.waitForTimeout(2000);
await page.waitForTextInField(selectors.itemBasicData.intrastat, 'Tropical Flowers');
let newcode = await page.waitToGetProperty(selectors.itemBasicData.intrastat, 'value');

View File

@ -31,7 +31,7 @@ describe('Item create tags path', () => {
it(`should confirm the fourth row data is the expected one`, async() => {
await page.reloadSection('item.card.tags');
await page.wait('vn-item-tags');
await page.waitForSelector('vn-item-tags');
let result = await page.waitToGetProperty(selectors.itemTags.fourthTag, 'value');
expect(result).toEqual('Ancho de la base');

View File

@ -77,7 +77,7 @@ describe('Item Create/Clone path', () => {
xdescribe('clone', () => {
it('should return to the items index by clicking the return to items button', async() => {
await page.waitToClick(selectors.itemBasicData.goToItemIndexButton);
await page.wait(selectors.itemsIndex.createItemButton);
await page.waitForSelector(selectors.itemsIndex.createItemButton);
await page.waitForState('item.index');
});

View File

@ -56,7 +56,7 @@ describe('Item regularize path', () => {
it('should click on the Tickets button of the top bar menu', async() => {
await page.waitToClick(selectors.globalItems.applicationsMenuButton);
await page.wait(selectors.globalItems.applicationsMenuVisible);
await page.waitForSelector(selectors.globalItems.applicationsMenuVisible);
await Promise.all([
page.waitForNavigation({waitUntil: ['load', 'networkidle0', 'domcontentloaded']}),
page.waitToClick(selectors.globalItems.ticketsButton)
@ -96,7 +96,7 @@ describe('Item regularize path', () => {
it('should now click on the Items button of the top bar menu', async() => {
await page.waitToClick(selectors.globalItems.applicationsMenuButton);
await page.wait(selectors.globalItems.applicationsMenuVisible);
await page.waitForSelector(selectors.globalItems.applicationsMenuVisible);
await page.waitToClick(selectors.globalItems.itemsButton);
await page.waitForState('item.index');
});
@ -119,7 +119,7 @@ describe('Item regularize path', () => {
it('should again click on the Tickets button of the top bar menu', async() => {
await page.waitToClick(selectors.globalItems.applicationsMenuButton);
await page.wait(selectors.globalItems.applicationsMenuVisible);
await page.waitForSelector(selectors.globalItems.applicationsMenuVisible);
await Promise.all([
page.waitForNavigation({waitUntil: ['load', 'networkidle0', 'domcontentloaded']}),
page.waitToClick(selectors.globalItems.ticketsButton)

View File

@ -43,7 +43,7 @@ describe('Item index path', () => {
await page.waitToClick(selectors.itemsIndex.firstSearchResult);
await page.waitToClick(selectors.itemDescriptor.goBackToModuleIndexButton);
await page.waitToClick(selectors.globalItems.searchButton);
await page.wait(selectors.itemsIndex.searchResult);
await page.waitForSelector(selectors.itemsIndex.searchResult);
await page.waitImgLoad(selectors.itemsIndex.firstItemImage);
const imageVisible = await page.isVisible(selectors.itemsIndex.firstItemImageTd);
@ -55,7 +55,7 @@ describe('Item index path', () => {
});
it('should mark all unchecked boxes to leave the index as it was', async() => {
await page.waitFor(500); // otherwise the snackbar doesnt appear some times.
await page.waitForTimeout(500); // otherwise the snackbar doesnt appear some times.
await page.waitToClick(selectors.itemsIndex.fieldsToShowButton);
await page.waitToClick(selectors.itemsIndex.idCheckbox);
await page.waitToClick(selectors.itemsIndex.stemsCheckbox);
@ -77,7 +77,7 @@ describe('Item index path', () => {
await page.waitToClick(selectors.itemsIndex.firstSearchResult);
await page.waitToClick(selectors.itemDescriptor.goBackToModuleIndexButton);
await page.waitToClick(selectors.globalItems.searchButton);
await page.wait(selectors.itemsIndex.searchResult);
await page.waitForSelector(selectors.itemsIndex.searchResult);
const idVisible = await page.isVisible(selectors.itemsIndex.firstItemId);
expect(idVisible).toBeTruthy();

View File

@ -39,7 +39,7 @@ describe('Item log path', () => {
it('should return to the items index by clicking the return to items button', async() => {
await page.waitToClick(selectors.itemBasicData.goToItemIndexButton);
await page.wait(selectors.itemsIndex.createItemButton);
await page.waitForSelector(selectors.itemsIndex.createItemButton);
await page.waitForState('item.index');
});
@ -49,7 +49,7 @@ describe('Item log path', () => {
});
it(`should confirm the log is showing 5 entries`, async() => {
await page.wait(selectors.itemLog.anyLineCreated);
await page.waitForSelector(selectors.itemLog.anyLineCreated);
const anyLineCreatedCount = await page.countElement(selectors.itemLog.anyLineCreated);
expect(anyLineCreatedCount).toEqual(5);

View File

@ -17,7 +17,7 @@ describe('Item descriptor path', () => {
});
it('should check the descriptor inactive icon is dark as the item is active', async() => {
await page.wait(selectors.itemDescriptor.inactiveIcon);
await page.waitForSelector(selectors.itemDescriptor.inactiveIcon);
await page.waitForClassNotPresent(selectors.itemDescriptor.inactiveIcon, 'bright');
const darkIcon = await page.isVisible(selectors.itemDescriptor.inactiveIcon);

View File

@ -24,7 +24,7 @@ describe('Ticket Edit sale path', () => {
it('should navigate to the tickets index', async() => {
await page.waitToClick(selectors.globalItems.applicationsMenuButton);
await page.wait(selectors.globalItems.applicationsMenuVisible);
await page.waitForSelector(selectors.globalItems.applicationsMenuVisible);
await page.waitToClick(selectors.globalItems.ticketsButton);
await page.waitForState('ticket.index');
});
@ -128,7 +128,7 @@ describe('Ticket Edit sale path', () => {
it('should return to ticket sales section', async() => {
await page.waitToClick(selectors.globalItems.applicationsMenuButton);
await page.wait(selectors.globalItems.applicationsMenuVisible);
await page.waitForSelector(selectors.globalItems.applicationsMenuVisible);
await page.waitToClick(selectors.globalItems.ticketsButton);
await page.accessToSearchResult('16');
await page.accessToSection('ticket.card.sale');
@ -143,9 +143,9 @@ describe('Ticket Edit sale path', () => {
});
it('should remove 1 from the first sale quantity', async() => {
await page.waitFor(500);
await page.waitForTimeout(500);
await page.waitToClick(selectors.ticketSales.firstSaleQuantityCell);
await page.waitFor(selectors.ticketSales.firstSaleQuantity);
await page.waitForSelector(selectors.ticketSales.firstSaleQuantity);
await page.type(selectors.ticketSales.firstSaleQuantity, '9\u000d');
const message = await page.waitForSnackbar();
@ -154,7 +154,7 @@ describe('Ticket Edit sale path', () => {
it('should update the price', async() => {
await page.waitToClick(selectors.ticketSales.firstSalePrice);
await page.waitFor(selectors.ticketSales.firstSalePriceInput);
await page.waitForSelector(selectors.ticketSales.firstSalePriceInput);
await page.type(selectors.ticketSales.firstSalePriceInput, '5\u000d');
const message = await page.waitForSnackbar();
@ -175,7 +175,7 @@ describe('Ticket Edit sale path', () => {
it('should update the discount', async() => {
await page.waitToClick(selectors.ticketSales.firstSaleDiscount);
await page.waitFor(selectors.ticketSales.firstSaleDiscountInput);
await page.waitForSelector(selectors.ticketSales.firstSaleDiscountInput);
await page.type(selectors.ticketSales.firstSaleDiscountInput, '50\u000d');
const message = await page.waitForSnackbar();
@ -205,7 +205,7 @@ describe('Ticket Edit sale path', () => {
it('should click on the Claims button of the top bar menu', async() => {
await page.waitToClick(selectors.globalItems.applicationsMenuButton);
await page.wait(selectors.globalItems.applicationsMenuVisible);
await page.waitForSelector(selectors.globalItems.applicationsMenuVisible);
await page.waitToClick(selectors.globalItems.claimsButton);
await page.waitForState('claim.index');
});
@ -217,7 +217,7 @@ describe('Ticket Edit sale path', () => {
it('should click the Tickets button of the top bar menu', async() => {
await page.waitToClick(selectors.globalItems.applicationsMenuButton);
await page.wait(selectors.globalItems.applicationsMenuVisible);
await page.waitForSelector(selectors.globalItems.applicationsMenuVisible);
await page.waitToClick(selectors.globalItems.ticketsButton);
await page.waitForState('ticket.index');
});
@ -225,16 +225,16 @@ describe('Ticket Edit sale path', () => {
it('should search for a ticket then access to the sales section', async() => {
await page.accessToSearchResult('16');
await page.accessToSection('ticket.card.sale');
await page.wait(2000);
await page.waitForTimeout(2000);
});
it('should select the third sale and delete it', async() => {
await page.waitToClick(selectors.ticketSales.thirdSaleCheckbox);
await page.wait(2000);
await page.waitForTimeout(2000);
await page.waitToClick(selectors.ticketSales.deleteSaleButton);
await page.wait(2000);
await page.waitForTimeout(2000);
await page.waitToClick(selectors.globalItems.acceptButton);
await page.wait(2000);
await page.waitForTimeout(2000);
await page.waitForSpinnerLoad();
const message = await page.waitForSnackbar();
@ -260,7 +260,7 @@ describe('Ticket Edit sale path', () => {
});
it('should confirm the transfered line is the correct one', async() => {
await page.wait(selectors.ticketSales.secondSaleText);
await page.waitForSelector(selectors.ticketSales.secondSaleText);
const result = await page.waitToGetProperty(selectors.ticketSales.secondSaleText, 'innerText');
expect(result).toContain(`Melee weapon heavy shield`);
@ -279,7 +279,7 @@ describe('Ticket Edit sale path', () => {
});
it(`should confirm the original ticket has still three lines`, async() => {
await page.wait(selectors.ticketSales.saleLine);
await page.waitForSelector(selectors.ticketSales.saleLine);
const result = await page.countElement(selectors.ticketSales.saleLine);
expect(result).toEqual(3);

View File

@ -48,13 +48,13 @@ describe('Ticket Create new tracking state path', () => {
});
it('should now access to the create state view by clicking the create floating button', async() => {
await page.waitFor('.vn-popup', {hidden: true});
await page.waitForSelector('.vn-popup', {hidden: true});
await page.waitToClick(selectors.ticketTracking.createStateButton);
await page.waitForState('ticket.card.tracking.edit');
});
it(`should attemp to create an state for which salesPerson doesn't have permissions`, async() => {
await page.waitFor(1500);
await page.waitForTimeout(1500);
await page.autocompleteSearch(selectors.createStateView.state, 'Encajado');
await page.waitToClick(selectors.createStateView.saveStateButton);
const message = await page.waitForSnackbar();

View File

@ -34,7 +34,7 @@ describe('Ticket Edit basic data path', () => {
it(`should confirm the zone autocomplete is enabled for the role productionBoss`, async() => {
await page.waitForSpinnerLoad();
await page.wait(selectors.ticketBasicData.zone);
await page.waitForSelector(selectors.ticketBasicData.zone);
const disabled = await page.evaluate(selector => {
return document.querySelector(selector).disabled;
}, `${selectors.ticketBasicData.zone} input`);
@ -51,7 +51,7 @@ describe('Ticket Edit basic data path', () => {
it(`should edit the ticket agency then check there are no zones for it`, async() => {
await page.autocompleteSearch(selectors.ticketBasicData.agency, 'Super-Man delivery');
await page.waitFor(1000);
await page.waitForTimeout(1000);
let emptyZone = await page
.expectPropertyValue(selectors.ticketBasicData.zone, 'value', '');

View File

@ -38,7 +38,7 @@ describe('Ticket descriptor path', () => {
it('should again click on the Tickets button of the top bar menu', async() => {
await page.waitToClick(selectors.globalItems.applicationsMenuButton);
await page.wait(selectors.globalItems.applicationsMenuVisible);
await page.waitForSelector(selectors.globalItems.applicationsMenuVisible);
await page.waitToClick(selectors.globalItems.ticketsButton);
await page.waitForState('ticket.index');
});
@ -52,7 +52,7 @@ describe('Ticket descriptor path', () => {
it('should click on the Tickets button of the top bar menu once more', async() => {
await page.waitToClick(selectors.globalItems.applicationsMenuButton);
await page.wait(selectors.globalItems.applicationsMenuVisible);
await page.waitForSelector(selectors.globalItems.applicationsMenuVisible);
await page.waitToClick(selectors.globalItems.ticketsButton);
await page.waitForState('ticket.index');
});
@ -73,7 +73,7 @@ describe('Ticket descriptor path', () => {
it('should click on the Tickets button of the top bar menu once again', async() => {
await page.waitToClick(selectors.globalItems.applicationsMenuButton);
await page.wait(selectors.globalItems.applicationsMenuVisible);
await page.waitForSelector(selectors.globalItems.applicationsMenuVisible);
await page.waitToClick(selectors.globalItems.ticketsButton);
await page.waitForState('ticket.index');
});

View File

@ -18,7 +18,7 @@ describe('Ticket purchase request path', () => {
});
it('should add a new request', async() => {
await page.waitFor(500);
await page.waitForTimeout(500);
await page.waitToClick(selectors.ticketRequests.addRequestButton);
await page.write(selectors.ticketRequests.descriptionInput, 'New stuff');
await page.write(selectors.ticketRequests.quantity, '9');
@ -72,7 +72,7 @@ describe('Ticket purchase request path', () => {
it('should check the request was deleted', async() => {
await page.reloadSection('ticket.card.request.index');
await page.wait(selectors.ticketRequests.addRequestButton);
await page.waitForSelector(selectors.ticketRequests.addRequestButton);
await page.waitForSelector(selectors.ticketRequests.thirdDescription, {hidden: true});
});
});

View File

@ -92,7 +92,7 @@ describe('Ticket descriptor path', () => {
});
await page.waitToClick(selectors.ticketDescriptor.moreMenu);
await page.waitToClick(selectors.ticketDescriptor.moreMenuAddStowaway);
await page.wait(selectors.ticketDescriptor.addStowawayDialogFirstTicket);
await page.waitForSelector(selectors.ticketDescriptor.addStowawayDialogFirstTicket);
const isVisible = await page.isVisible(selectors.ticketDescriptor.addStowawayDialogFirstTicket);
expect(isVisible).toBeTruthy();

View File

@ -22,7 +22,7 @@ describe('Ticket services path', () => {
it('should find the add descripton button disabled for this user role', async() => {
await page.waitForClassPresent(selectors.ticketService.firstAddServiceTypeButton, 'disabled');
await page.waitToClick(selectors.ticketService.addServiceButton);
await page.wait(selectors.ticketService.firstAddServiceTypeButton);
await page.waitForSelector(selectors.ticketService.firstAddServiceTypeButton);
const result = await page.isDisabled(selectors.ticketService.firstAddServiceTypeButton);
expect(result).toBe(true);
@ -63,7 +63,7 @@ describe('Ticket services path', () => {
it('should click on the add new service type to open the dialog', async() => {
await page.waitToClick(selectors.ticketService.firstAddServiceTypeButton);
await page.wait('.vn-dialog.shown');
await page.waitForSelector('.vn-dialog.shown');
const result = await page.isVisible(selectors.ticketService.newServiceTypeName);
expect(result).toBeTruthy();

View File

@ -42,7 +42,7 @@ describe('Ticket create path', () => {
it('should again open the new ticket form', async() => {
await page.waitToClick(selectors.globalItems.returnToModuleIndexButton);
await page.waitFor(500);
await page.waitForTimeout(500);
await page.waitToClick(selectors.ticketsIndex.newTicketButton);
await page.waitForState('ticket.create');
});

View File

@ -45,7 +45,7 @@ describe('Claim edit basic data path', () => {
it('should confirm the claim state was edited', async() => {
await page.reloadSection('claim.card.basicData');
await page.wait(selectors.claimBasicData.claimState);
await page.waitForSelector(selectors.claimBasicData.claimState);
const result = await page.waitToGetProperty(selectors.claimBasicData.claimState, 'value');
expect(result).toEqual('Gestionado');

View File

@ -106,7 +106,7 @@ xdescribe('Claim detail', () => {
it('should navigate back to claim.detail to confirm the claim contains now two items', async() => {
await page.accessToSection('claim.card.detail');
await page.wait(selectors.claimDetail.claimDetailLine);
await page.waitForSelector(selectors.claimDetail.claimDetailLine);
const result = await page.countElement(selectors.claimDetail.claimDetailLine);
expect(result).toEqual(2);

View File

@ -27,7 +27,7 @@ describe('Claim action path', () => {
it('should import the second importable ticket', async() => {
// the animation adding the header element for the claimed total
// obscures somehow other elements for about 2 seconds
await page.waitFor(3000);
await page.waitForTimeout(3000);
await page.waitToClick(selectors.claimAction.importTicketButton);
await page.waitToClick(selectors.claimAction.secondImportableTicket);

View File

@ -8,7 +8,7 @@ describe('Order summary path', () => {
browser = await getBrowser();
page = browser.page;
await page.loginAndModule('employee', 'order');
await page.waitFor(2000);
await page.waitForTimeout(2000);
await page.accessToSearchResult('16');
});

View File

@ -17,7 +17,7 @@ describe('Route create path', () => {
describe('as employee', () => {
it('should click on the add new route button and open the creation form', async() => {
await page.waitFor(500);
await page.waitForTimeout(500);
await page.waitToClick(selectors.routeIndex.addNewRouteButton);
await page.waitForState('route.create');
});

View File

@ -26,9 +26,9 @@ describe('InvoiceOut descriptor path', () => {
it('should navigate to the invoiceOut index', async() => {
await page.waitToClick(selectors.globalItems.applicationsMenuButton);
await page.wait(selectors.globalItems.applicationsMenuVisible);
await page.waitForSelector(selectors.globalItems.applicationsMenuVisible);
await page.waitToClick(selectors.globalItems.invoiceOutButton);
await page.wait(selectors.invoiceOutIndex.topbarSearch);
await page.waitForSelector(selectors.invoiceOutIndex.topbarSearch);
await page.waitForState('invoiceOut.index');
});
@ -59,7 +59,7 @@ describe('InvoiceOut descriptor path', () => {
it('should navigate to the ticket index', async() => {
await page.waitToClick(selectors.globalItems.applicationsMenuButton);
await page.wait(selectors.globalItems.applicationsMenuVisible);
await page.waitForSelector(selectors.globalItems.applicationsMenuVisible);
await page.waitToClick(selectors.globalItems.ticketsButton);
await page.waitForState('ticket.index');
});
@ -73,7 +73,7 @@ describe('InvoiceOut descriptor path', () => {
it('should now navigate to the invoiceOut index', async() => {
await page.waitToClick(selectors.globalItems.applicationsMenuButton);
await page.wait(selectors.globalItems.applicationsMenuVisible);
await page.waitForSelector(selectors.globalItems.applicationsMenuVisible);
await page.waitToClick(selectors.globalItems.invoiceOutButton);
await page.waitForState('invoiceOut.index');
});
@ -126,7 +126,7 @@ describe('InvoiceOut descriptor path', () => {
it(`should check the salesPerson role doens't see the book option in the more menu`, async() => {
await page.waitToClick(selectors.invoiceOutDescriptor.moreMenu);
await page.wait(selectors.invoiceOutDescriptor.moreMenuShowInvoiceOutPdf);
await page.waitForSelector(selectors.invoiceOutDescriptor.moreMenuShowInvoiceOutPdf);
await page.waitForSelector(selectors.invoiceOutDescriptor.moreMenuBookInvoiceOut, {hidden: true});
});

View File

@ -43,7 +43,7 @@ describe('Travel basic data path', () => {
it('should now edit the whole form then save', async() => {
await page.clearInput(selectors.travelBasicDada.reference);
await page.write(selectors.travelBasicDada.reference, 'new reference!');
await page.waitFor(2000);
await page.waitForTimeout(2000);
await page.autocompleteSearch(selectors.travelBasicDada.agency, 'Entanglement');
await page.autocompleteSearch(selectors.travelBasicDada.outputWarehouse, 'Warehouse Three');
await page.autocompleteSearch(selectors.travelBasicDada.inputWarehouse, 'Warehouse Four');

View File

@ -0,0 +1,33 @@
import selectors from '../../helpers/selectors.js';
import getBrowser from '../../helpers/puppeteer';
describe('Travel extra community path', () => {
let browser;
let page;
beforeAll(async() => {
browser = await getBrowser();
page = browser.page;
await page.loginAndModule('buyer', 'travel');
await page.accessToSection('travel.extraCommunity');
});
afterAll(async() => {
await browser.close();
});
it('should edit the travel reference', async() => {
await page.waitToClick(selectors.travelExtraCommunity.removeContinentFilter);
await page.writeOnEditableTD(selectors.travelExtraCommunity.firstTravelReference, 'edited reference');
});
it('should reload the index and confirm the reference was edited', async() => {
await page.accessToSection('travel.index');
await page.accessToSection('travel.extraCommunity');
await page.waitToClick(selectors.travelExtraCommunity.removeContinentFilter);
await page.waitForTextInElement(selectors.travelExtraCommunity.firstTravelReference, 'edited reference');
const reference = await page.getProperty(selectors.travelExtraCommunity.firstTravelReference, 'innerText');
expect(reference).toContain('edited reference');
});
});

View File

@ -17,7 +17,7 @@ describe('Entry lastest buys path', () => {
it('should access the latest buys seccion and search not seeing the edit buys button yet', async() => {
await page.waitToClick(selectors.entryLatestBuys.latestBuysSectionButton);
await page.waitFor(250);
await page.waitForTimeout(250);
await page.waitToClick(selectors.globalItems.searchButton);
await page.waitForSelector(selectors.entryLatestBuys.editBuysButton, {visible: false});
});

View File

@ -22,28 +22,7 @@ vn-table {
& > * > vn-th[field] {
position: relative;
overflow: visible;
cursor: pointer;
&.active > :after {
color: $color-font;
opacity: 1;
}
&.desc > :after {
content: 'arrow_drop_down';
}
&.asc > :after {
content: 'arrow_drop_up';
}
& > :after {
font-family: 'Material Icons';
content: 'arrow_drop_down';
position: absolute;
color: $color-spacer;
opacity: 0;
}
&:hover > :after {
opacity: 1;
}
cursor: pointer
}
}
& > vn-tbody,

View File

@ -54,7 +54,6 @@ export default class Th {
else
this.table.setOrder(this.field, this.order);
this.updateArrow();
this.table.applyOrder(this.field, this.order);

View File

@ -0,0 +1,33 @@
@import "effects";
@import "variables";
vn-th {
font-weight: normal;
}
vn-th[field] {
&.active > :after {
color: $color-font;
opacity: 1;
}
&.desc > :after {
content: 'arrow_drop_down';
}
&.asc > :after {
content: 'arrow_drop_up';
}
& > :after {
font-family: 'Material Icons';
content: 'arrow_drop_down';
position: absolute;
color: $color-spacer;
font-size: 1.5em;
margin-top: -2px;
opacity: 0
}
&:hover > :after {
opacity: 1;
}
}

View File

@ -17,7 +17,7 @@
ui-sref="{{::$ctrl.summaryState}}({id: $ctrl.descriptor.id})">
<vn-icon icon="preview"></vn-icon>
</a>
<vn-icon-button ng-if="$ctrl.$transclude.isSlotFilled('menu')"
<vn-icon-button ng-if="!$ctrl.$transclude.isSlotFilled('dotMenu')"
ng-class="::{invisible: !$ctrl.$transclude.isSlotFilled('menu')}"
icon="more_vert"
vn-popover="menu">

View File

@ -84,6 +84,32 @@ class VnMySQL extends MySQL {
return wrappedConnector.buildWhere(null, where);
}
/**
* Constructs SQL GROUP BY clause from Loopback filter.
*
* @param {Object} group The group by definition
* @return {String} Built SQL group by
*/
makeGroupBy(group) {
if (!group)
return '';
if (typeof group === 'string')
group = [group];
let clauses = [];
for (let clause of group) {
let sqlGroup = '';
let t = clause.split(/[\s,]+/);
sqlGroup += this.escapeName(t[0]);
clauses.push(sqlGroup);
}
return `GROUP BY ${clauses.join(', ')}`;
}
/**
* Constructs SQL order clause from Loopback filter.
*

View File

@ -34,9 +34,6 @@
"stickers": {
"type": "number"
},
"packageFk": {
"type": "number"
},
"groupingMode": {
"type": "number"
},
@ -68,6 +65,11 @@
"model": "Item",
"foreignKey": "itemFk",
"required": true
}
},
"package": {
"type": "belongsTo",
"model": "Packaging",
"foreignKey": "packageFk"
}
}
}

View File

@ -5,10 +5,8 @@ describe('item getBalance()', () => {
let params = {where: {itemFk: 1, warehouseFk: 2}};
let result = await app.models.Item.getBalance(params);
expect(result.length).toBe(4);
expect(result.length).toBe(2);
expect(result[0].balance).toBe(-100);
expect(result[1].balance).toBe(-110);
expect(result[2].balance).toBe(-110);
expect(result[3].balance).toBe(-210);
expect(result[1].balance).toBe(-200);
});
});

View File

@ -0,0 +1,213 @@
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
const buildFilter = require('vn-loopback/util/filter').buildFilter;
const mergeFilters = require('vn-loopback/util/filter').mergeFilters;
module.exports = Self => {
Self.remoteMethodCtx('extraCommunityFilter', {
description: 'Find all instances of the model matched by filter from the data source.',
accessType: 'READ',
accepts: [
{
arg: 'filter',
type: 'Object',
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string',
http: {source: 'query'}
}, {
arg: 'search',
type: 'String',
description: 'Searchs the travel by id',
http: {source: 'query'}
}, {
arg: 'id',
type: 'Integer',
description: 'The travel id',
http: {source: 'query'}
}, {
arg: 'shippedFrom',
type: 'Date',
description: 'The shipped from date filter',
http: {source: 'query'}
}, {
arg: 'shippedTo',
type: 'Date',
description: 'The shipped to date filter',
http: {source: 'query'}
}, {
arg: 'landedFrom',
type: 'Date',
description: 'The landed from date filter',
http: {source: 'query'}
}, {
arg: 'landedTo',
type: 'Date',
description: 'The landed to date filter',
http: {source: 'query'}
}, {
arg: 'agencyFk',
type: 'Number',
description: 'The agencyModeFk id',
http: {source: 'query'}
}, {
arg: 'warehouseOutFk',
type: 'Number',
description: 'The warehouseOutFk filter',
http: {source: 'query'}
}, {
arg: 'warehouseInFk',
type: 'Number',
description: 'The warehouseInFk filter',
http: {source: 'query'}
}, {
arg: 'totalEntries',
type: 'Number',
description: 'The totalEntries filter',
http: {source: 'query'}
}, {
arg: 'ref',
type: 'string',
description: 'The reference'
}, {
arg: 'continent',
type: 'string',
description: 'The continent code'
}
],
returns: {
type: ['Object'],
root: true
},
http: {
path: `/extraCommunityFilter`,
verb: 'GET'
}
});
Self.extraCommunityFilter = async(ctx, filter) => {
let conn = Self.dataSource.connector;
let where = buildFilter(ctx.args, (param, value) => {
switch (param) {
case 'search':
return /^\d+$/.test(value)
? {'t.id': value}
: {'t.ref': {like: `%${value}%`}};
case 'ref':
return {'t.ref': {like: `%${value}%`}};
case 'shippedFrom':
return {'t.shipped': {gte: value}};
case 'shippedTo':
return {'t.shipped': {lte: value}};
case 'landedFrom':
return {'t.landed': {gte: value}};
case 'landedTo':
return {'t.landed': {lte: value}};
case 'continent':
return {'cnt.code': value};
case 'id':
case 'agencyFk':
case 'warehouseOutFk':
case 'warehouseInFk':
case 'totalEntries':
param = `t.${param}`;
return {[param]: value};
}
});
filter = mergeFilters(filter, {where});
let stmts = [];
let stmt;
stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.travel');
stmt = new ParameterizedSQL(
`CREATE TEMPORARY TABLE tmp.travel
(INDEX (id))
ENGINE = MEMORY
SELECT
t.id,
t.ref,
t.shipped,
t.landed,
t.kg,
am.id AS agencyModeFk,
am.name AS agencyModeName,
wo.id AS warehouseOutFk,
wo.name AS warehouseOutName,
w.name AS warehouseInFk,
w.name AS warehouseInName,
SUM(b.stickers) AS stickers,
s.id AS supplierFk,
s.nickname AS cargoSupplierNickname,
CAST(SUM(i.density * b.stickers * IF(pkg.volume, pkg.volume, pkg.width * pkg.depth * pkg.height) / 1000000 ) as DECIMAL(10,0)) as loadedKg,
CAST(SUM(167.5 * b.stickers * IF(pkg.volume, pkg.volume, pkg.width * pkg.depth * pkg.height) / 1000000 ) as DECIMAL(10,0)) as volumeKg
FROM travel t
LEFT JOIN supplier s ON s.id = t.cargoSupplierFk
LEFT JOIN entry e ON e.travelFk = t.id
LEFT JOIN buy b ON b.entryFk = e.id
LEFT JOIN packaging pkg ON pkg.id = b.packageFk
LEFT JOIN item i ON i.id = b.itemFk
LEFT JOIN itemType it ON it.id = i.typeFk
JOIN warehouse w ON w.id = t.warehouseInFk
JOIN warehouse wo ON wo.id = t.warehouseOutFk
JOIN country c ON c.id = wo.countryFk
LEFT JOIN continent cnt ON cnt.id = c.continentFk
JOIN agencyMode am ON am.id = t.agencyFk`
);
stmt.merge(conn.makeWhere(filter.where));
stmt.merge(conn.makeGroupBy('t.id'));
stmt.merge(conn.makeLimit(filter));
stmts.push(stmt);
const travelsIndex = stmts.push('SELECT * FROM tmp.travel') - 1;
stmt = new ParameterizedSQL(
`SELECT
e.id,
e.travelFk,
e.ref,
e.loadPriority,
s.name AS supplierName,
SUM(b.stickers) AS stickers,
e.evaNotes,
e.notes,
CAST(SUM(i.density * b.stickers * IF(pkg.volume, pkg.volume, pkg.width * pkg.depth * pkg.height) / 1000000 ) as DECIMAL(10,0)) as loadedkg,
CAST(SUM(167.5 * b.stickers * IF(pkg.volume, pkg.volume, pkg.width * pkg.depth * pkg.height) / 1000000 ) as DECIMAL(10,0)) as volumeKg
FROM entry e
JOIN tmp.travel tr ON tr.id = e.travelFk
JOIN buy b ON b.entryFk = e.id
JOIN packaging pkg ON pkg.id = b.packageFk
JOIN item i ON i.id = b.itemFk
JOIN itemType it ON it.id = i.typeFk
JOIN supplier s ON s.id = e.supplierFk`
);
stmt.merge(conn.makeGroupBy('e.id'));
stmt.merge(conn.makeOrderBy(filter.order));
const entriesIndex = stmts.push(stmt) - 1;
stmts.push(`DROP TEMPORARY TABLE tmp.travel`);
const sql = ParameterizedSQL.join(stmts, ';');
const result = await conn.executeStmt(sql);
const travels = result[travelsIndex];
const entries = result[entriesIndex];
const travelsMap = new Map();
for (let travel of travels)
travelsMap.set(travel.id, travel);
for (let entry of entries) {
const travel = travelsMap.get(entry.travelFk);
if (travel) {
if (!travel.entries) travel.entries = [];
travel.entries.push(entry);
}
}
return travels;
};
};

View File

@ -0,0 +1,66 @@
const app = require('vn-loopback/server/server');
describe('Travel extraCommunityFilter()', () => {
const filter = {
order: 'landed ASC, shipped ASC, travelFk, loadPriority, agencyModeFk, evaNotes',
};
it('should return the travel matching "search"', async() => {
const ctx = {
args: {
search: 2
}
};
const result = await app.models.Travel.extraCommunityFilter(ctx, filter);
const firstRow = result[0];
const entries = firstRow.entries;
expect(result.length).toEqual(1);
expect(firstRow.id).toEqual(2);
expect(entries.length).toEqual(2);
});
it('should return the travel matching "search" by ref', async() => {
const ctx = {
args: {
search: 'third'
}
};
const result = await app.models.Travel.extraCommunityFilter(ctx, filter);
const firstRow = result[0];
expect(result.length).toEqual(1);
expect(firstRow.id).toEqual(3);
});
it('should return the travel matching "warehouse out"', async() => {
const ctx = {
args: {
warehouseOutFk: 2
}
};
const result = await app.models.Travel.extraCommunityFilter(ctx, filter);
expect(result.length).toEqual(3);
});
it('should return the routes matching "landed from" and "landed to"', async() => {
const from = new Date();
const to = new Date();
from.setHours(0, 0, 0, 0);
to.setHours(23, 59, 59, 999);
to.setDate(to.getDate() + 14);
const ctx = {
args: {
landedFrom: from,
landedTo: to
}
};
const result = await app.models.Travel.extraCommunityFilter(ctx, filter);
expect(result.length).toEqual(1);
});
});

View File

@ -38,7 +38,7 @@ describe('Travel filter()', () => {
const result = await app.models.Travel.filter(ctx);
expect(result.length).toEqual(8);
expect(result.length).toEqual(3);
});
it('should return the travel matching "total entries"', async() => {

View File

@ -7,6 +7,7 @@ module.exports = Self => {
require('../methods/travel/createThermograph')(Self);
require('../methods/travel/deleteThermograph')(Self);
require('../methods/travel/updateThermograph')(Self);
require('../methods/travel/extraCommunityFilter')(Self);
Self.rewriteDbError(function(err) {
if (err.code === 'ER_DUP_ENTRY')

View File

@ -1,6 +1,6 @@
Reference: Referencia
Wh. In: Almacén entrada
Wh. Out: Almacén salida
Wh. In: Alm. entrada
Wh. Out: Alm. salida
Shipped: F. envío
Landed: F. entrega
Total entries: Entradas totales

View File

@ -0,0 +1,91 @@
<div class="search-panel">
<form ng-submit="$ctrl.onSearch()">
<vn-horizontal>
<vn-textfield
vn-one
label="General search"
ng-model="filter.search"
info="Search travels by id"
vn-focus>
</vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-textfield
vn-one
label="Reference"
ng-model="filter.ref">
</vn-textfield>
<vn-textfield
vn-one
label="Total entries"
ng-model="filter.totalEntries">
</vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-textfield
vn-one
label="Travel id"
ng-model="filter.id">
</vn-textfield>
<vn-autocomplete vn-one
label="Agency"
ng-model="filter.agencyFk"
url="AgencyModes"
show-field="name"
value-field="id">
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-date-picker
vn-one
label="Shipped from"
ng-model="filter.shippedFrom">
</vn-date-picker>
<vn-date-picker
vn-one
label="Shipped to"
ng-model="filter.shippedTo">
</vn-date-picker>
</vn-horizontal>
<vn-horizontal>
<vn-date-picker
vn-one
label="Landed from"
ng-model="filter.landedFrom">
</vn-date-picker>
<vn-date-picker
vn-one
label="Landed to"
ng-model="filter.landedTo">
</vn-date-picker>
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete vn-one
label="Warehouse In"
ng-model="filter.warehouseInFk"
url="Warehouses"
show-field="name"
value-field="id">
</vn-autocomplete>
<vn-autocomplete vn-one
label="Warehouse Out"
ng-model="filter.warehouseOutFk"
url="Warehouses"
show-field="name"
value-field="id">
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete vn-one
label="Continent Out"
ng-model="filter.continent"
url="Continents"
show-field="name"
value-field="code">
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal class="vn-mt-lg">
<vn-submit label="Search"></vn-submit>
</vn-horizontal>
</form>
</div>

View File

@ -0,0 +1,7 @@
import ngModule from '../module';
import SearchPanel from 'core/components/searchbar/search-panel';
ngModule.vnComponent('vnExtraCommunitySearchPanel', {
template: require('./index.html'),
controller: SearchPanel
});

View File

@ -0,0 +1,111 @@
<vn-crud-model auto-load="false"
vn-id="model"
url="Travels/extraCommunityFilter"
data="travels"
order="landed ASC, shipped ASC, travelFk, loadPriority, agencyModeFk, evaNotes"
limit="20">
</vn-crud-model>
<vn-portal slot="topbar">
<vn-searchbar
vn-focus
panel="vn-extra-community-search-panel"
suggested-filter="$ctrl.defaultFilter"
filter="$ctrl.defaultFilter"
info="Search by travel id or reference"
auto-state="false"
model="model">
</vn-searchbar>
</vn-portal>
<vn-data-viewer model="model" class="travel-list">
<vn-card ng-repeat="travel in travels" class="vn-mb-md">
<section class="vn-pa-md">
<vn-table vn-droppable="$ctrl.onDrop($event)" ng-attr-id="{{::travel.id}}">
<vn-thead>
<vn-tr ng-if="$index == 0">
<vn-th shrink>Id</vn-th>
<vn-th expand>Supplier</vn-th>
<vn-th expand>Freighter</vn-th>
<vn-th>Reference</vn-th>
<vn-th number>Packages</vn-th>
<vn-th number>Bl. KG</vn-th>
<vn-th number>Phy. KG</vn-th>
<vn-th number>Vol. KG</vn-th>
<vn-th expand translate-attr="{title: 'Warehouse Out'}">
Wh. Out
</vn-th>
<vn-th expand>Shipped</vn-th>
<vn-th expand translate-attr="{title: 'Warehouse In'}">
Wh. In
</vn-th>
<vn-th expand>Landed</vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr class="header">
<vn-td>
<span class="link"
ng-click="travelDescriptor.show($event, travel.id)">
{{::travel.id}}
</span>
</vn-td>
<vn-td expand>{{::travel.agencyModeName}}</vn-td>
<vn-td expand>{{::travel.cargoSupplierNickname}}</vn-td>
<vn-td-editable expand>
<text>{{travel.ref}}</text>
<field>
<vn-textfield class="dense" vn-focus
ng-model="travel.ref"
on-change="$ctrl.changeReference(travel)">
</vn-textfield>
</field>
</vn-td-editable>
<vn-td number>{{::travel.stickers}}</vn-td>
<vn-td number>{{::travel.kg}}</vn-td>
<vn-td number>{{::travel.loadedKg}}</vn-td>
<vn-td number>{{::travel.volumeKg}}</vn-td>
<vn-td expand>{{::travel.warehouseOutName}}</vn-td>
<vn-td expand>{{::travel.shipped | date: 'dd/MM/yyyy'}}</vn-td>
<vn-td expand>{{::travel.warehouseInName}}</vn-td>
<vn-td expand>{{::travel.landed | date: 'dd/MM/yyyy'}}</vn-td>
</vn-tr>
<a href="#" ng-repeat="entry in travel.entries" class="vn-tr" draggable
ng-attr-id="{{::entry.id}}"
ng-click="$event.preventDefault()">
<vn-td>
<span class="link"
ng-click="entryDescriptor.show($event, entry.id)">
{{::entry.id}}
</span>
</vn-td>
<vn-td>{{::entry.supplierName}}</vn-td>
<vn-td></vn-td>
<vn-td expand>{{::entry.ref}}</vn-td>
<vn-th number>{{::entry.stickers}}</vn-th>
<vn-td number></vn-td>
<vn-td number>{{::entry.loadedkg}}</vn-td>
<vn-td number>{{::entry.volumeKg}}</vn-td>
<vn-td>
<span nf-if="::entry.notes" vn-tooltip="{{::entry.notes}}">
{{::entry.notes}}
</span>
</vn-td>
<vn-td>
<span nf-if="::entry.evaNotes" vn-tooltip="{{::entry.evaNotes}}">
{{::entry.evaNotes}}
</span>
</vn-td>
<vn-td></vn-td>
<vn-td></vn-td>
</a>
</vn-tbody>
</vn-table>
</section>
</vn-card>
</vn-data-viewer>
<vn-travel-descriptor-popover
vn-id="travelDescriptor">
</vn-travel-descriptor-popover>
<vn-entry-descriptor-popover
vn-id="entryDescriptor">
</vn-entry-descriptor-popover>

View File

@ -0,0 +1,91 @@
import ngModule from '../module';
import Section from 'salix/components/section';
import './style.scss';
class Controller extends Section {
constructor($element, $) {
super($element, $);
const draggable = this.element.querySelector('.travel-list');
draggable.addEventListener('dragstart',
event => this.dragStart(event));
draggable.addEventListener('dragend',
event => this.dragEnd(event));
this.draggableElement = 'a[draggable]';
this.droppableElement = 'vn-table[vn-droppable]';
const scopeDays = 14;
const landedFrom = new Date();
landedFrom.setHours(0, 0, 0, 0);
const landedTo = new Date();
landedTo.setDate(landedTo.getDate() + scopeDays);
landedTo.setHours(23, 59, 59, 59);
this.defaultFilter = {
landedFrom: landedFrom,
landedTo: landedTo,
continent: 'AM'
};
}
findDraggable($event) {
const target = $event.target;
const draggable = target.closest(this.draggableElement);
return draggable;
}
findDroppable($event) {
const target = $event.target;
const droppable = target.closest(this.droppableElement);
return droppable;
}
dragStart($event) {
const draggable = this.findDraggable($event);
draggable.classList.add('dragging');
const id = parseInt(draggable.id);
this.entryId = id;
this.entry = draggable;
}
dragEnd($event) {
const draggable = this.findDraggable($event);
draggable.classList.remove('dragging');
this.entryId = null;
this.entry = null;
}
onDrop($event) {
const model = this.$.model;
const droppable = this.findDroppable($event);
const travelId = parseInt(droppable.id);
const currentDroppable = this.entry.closest(this.droppableElement);
if (currentDroppable == droppable) return;
if (this.entryId && travelId) {
const path = `Entries/${this.entryId}`;
this.$http.patch(path, {travelFk: travelId})
.then(() => model.refresh())
.then(() => this.vnApp.showSuccess(this.$t('Data saved!')));
}
}
changeReference(travel) {
const params = {ref: travel.ref};
const endpoint = `Travels/${travel.id}`;
this.$http.patch(endpoint, params)
.then(() => this.vnApp.showSuccess(this.$t('Data saved!')));
}
}
ngModule.vnComponent('vnTravelExtraCommunity', {
template: require('./index.html'),
controller: Controller
});

View File

@ -0,0 +1,127 @@
import './index.js';
describe('Travel Component vnTravelExtraCommunity', () => {
let controller;
let $httpBackend;
beforeEach(ngModule('travel'));
beforeEach(inject(($componentController, _$httpBackend_) => {
$httpBackend = _$httpBackend_;
const $element = angular.element('<vn-travel-extra-community><div class="travel-list"></div></vn-travel-extra-community>');
controller = $componentController('vnTravelExtraCommunity', {$element});
controller.$.model = {};
controller.$.model.refresh = jest.fn();
}));
describe('changeReference()', () => {
it('should make an HTTP query', () => {
jest.spyOn(controller.vnApp, 'showSuccess');
const travel = {id: 1, ref: 'New reference'};
const expectedData = {ref: 'New reference'};
$httpBackend.expect('PATCH', `Travels/${travel.id}`, expectedData).respond(200);
controller.changeReference(travel);
$httpBackend.flush();
expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Data saved!');
});
});
describe('findDraggable()', () => {
it('should find the draggable element', () => {
const draggable = document.createElement('a');
draggable.setAttribute('draggable', true);
const $event = new Event('dragstart');
const target = document.createElement('div');
draggable.appendChild(target);
target.dispatchEvent($event);
const result = controller.findDraggable($event);
expect(result).toEqual(draggable);
});
});
describe('findDroppable()', () => {
it('should find the droppable element', () => {
const droppable = document.createElement('vn-table');
droppable.setAttribute('vn-droppable', true);
const $event = new Event('drop');
const target = document.createElement('div');
droppable.appendChild(target);
target.dispatchEvent($event);
const result = controller.findDroppable($event);
expect(result).toEqual(droppable);
});
});
describe('dragStart()', () => {
it(`should add the class "dragging" to the draggable element
and then set the entryId controller property`, () => {
const draggable = document.createElement('a');
draggable.setAttribute('draggable', true);
draggable.setAttribute('id', 3);
jest.spyOn(controller, 'findDraggable').mockReturnValue(draggable);
const $event = new Event('dragStart');
controller.dragStart($event);
const firstClass = draggable.classList[0];
expect(firstClass).toEqual('dragging');
expect(controller.entryId).toEqual(3);
expect(controller.entry).toEqual(draggable);
});
});
describe('dragEnd()', () => {
it(`should remove the class "dragging" from the draggable element
and then set the entryId controller property to null`, () => {
const draggable = document.createElement('a');
draggable.setAttribute('draggable', true);
draggable.setAttribute('id', 3);
draggable.classList.add('dragging');
jest.spyOn(controller, 'findDraggable').mockReturnValue(draggable);
const $event = new Event('dragStart');
controller.dragEnd($event);
const classList = draggable.classList;
expect(classList.length).toEqual(0);
expect(controller.entryId).toBeNull();
expect(controller.entry).toBeNull();
});
});
describe('onDrop()', () => {
it('should make an HTTP patch query', () => {
const droppable = document.createElement('vn-table');
droppable.setAttribute('vn-droppable', true);
droppable.setAttribute('id', 1);
jest.spyOn(controller, 'findDroppable').mockReturnValue(droppable);
const oldDroppable = document.createElement('vn-table');
oldDroppable.setAttribute('vn-droppable', true);
const entry = document.createElement('div');
oldDroppable.appendChild(entry);
controller.entryId = 3;
controller.entry = entry;
const $event = new Event('drop');
const expectedData = {travelFk: 1};
$httpBackend.expect('PATCH', `Entries/3`, expectedData).respond(200);
controller.onDrop($event);
$httpBackend.flush();
});
});
});

View File

@ -0,0 +1,8 @@
Family: Familia
Extra community: Extra comunitarios
Freighter: Transitario
Bl. KG: KG Bloq.
Phy. KG: KG físico
Vol. KG: KG Vol.
Search by travel id or reference: Buscar por id travel o referencia
Continent Out: Continente salida

View File

@ -0,0 +1,55 @@
@import "variables";
vn-travel-extra-community {
.header {
margin-bottom: 16px;
font-size: 1.25rem;
line-height: 1;
padding: 7px;
padding-bottom: 7px;
padding-bottom: 4px;
font-weight: lighter;
background-color: #fde6ca;
color: $color-font-light;
border-bottom: 1px solid #f7931e;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
vn-td-editable text {
background-color: transparent;
padding: 0;
border: 0;
border-bottom: 1px dashed $color-active;
border-radius: 0;
color: $color-active
}
vn-td-editable text:after {
font-family: 'Material Icons';
content: 'edit';
position: absolute;
margin-left: 5px;
color: $color-spacer
}
vn-table[vn-droppable] {
border-radius: 0;
}
a[draggable] {
transition: all .5s;
cursor: move;
outline: 0;
}
a[draggable]:hover {
background-color: $color-hover-cd
}
a[draggable].dragging {
background-color: $color-success-light;
font-weight:bold
}
}

View File

@ -14,3 +14,5 @@ import './thermograph/create/';
import './thermograph/edit/';
import './descriptor-popover';
import './descriptor-menu';
import './extra-community';
import './extra-community-search-panel';

View File

@ -6,7 +6,8 @@
"dependencies": ["worker", "entry"],
"menus": {
"main": [
{"state": "travel.index", "icon": "local_airport"}
{"state": "travel.index", "icon": "local_airport"},
{"state": "travel.extraCommunity", "icon": "directions_boat"}
],
"card": [
{"state": "travel.card.basicData", "icon": "settings"},
@ -90,6 +91,16 @@
"travel": "$ctrl.travel"
},
"acl": ["buyer"]
},
{
"url": "/extra-community?q",
"state": "travel.extraCommunity",
"component": "vn-travel-extra-community",
"description": "Extra community",
"acl": ["buyer"],
"params": {
"travel": "$ctrl.travel"
}
}
]
}

View File

@ -1,6 +1,6 @@
Reference: Referencia
Warehouse In: Almacen entrada
Warehouse Out: Almacen salida
Warehouse In: Almacén entrada
Warehouse Out: Almacén salida
Shipped: F. envío
Landed: F. entrega
Total entries: Entradas totales

244
package-lock.json generated
View File

@ -5264,6 +5264,16 @@
"integrity": "sha512-gCubfBUZ6KxzoibJ+SCUc/57Ms1jz5NjHe4+dI2krNmU5zCPAphyLJYyTOg06ueIyfj+SaCUqmzun7ImlxDcKg==",
"dev": true
},
"@types/yauzl": {
"version": "2.9.1",
"resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.1.tgz",
"integrity": "sha512-A1b8SU4D10uoPjwb0lnHmmu8wZhR9d+9o2PKBQT2jU5YPTKsxac6M2qGAdY7VcL+dHHhARVUDmeg0rOrcd9EjA==",
"dev": true,
"optional": true,
"requires": {
"@types/node": "*"
}
},
"@webassemblyjs/ast": {
"version": "1.8.5",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz",
@ -8546,6 +8556,12 @@
"integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==",
"dev": true
},
"devtools-protocol": {
"version": "0.0.818844",
"resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.818844.tgz",
"integrity": "sha512-AD1hi7iVJ8OD0aMLQU5VK0XH9LDlA1+BcPIgrAxPfaibx2DbWucuyOhc4oyQCbnvDDO68nN6/LcKfqTP343Jjg==",
"dev": true
},
"diff": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz",
@ -9857,47 +9873,40 @@
}
},
"extract-zip": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz",
"integrity": "sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==",
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz",
"integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==",
"dev": true,
"requires": {
"concat-stream": "^1.6.2",
"debug": "^2.6.9",
"mkdirp": "^0.5.4",
"@types/yauzl": "^2.9.1",
"debug": "^4.1.1",
"get-stream": "^5.1.0",
"yauzl": "^2.10.0"
},
"dependencies": {
"concat-stream": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
"integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
"debug": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
"dev": true,
"requires": {
"buffer-from": "^1.0.0",
"inherits": "^2.0.3",
"readable-stream": "^2.2.2",
"typedarray": "^0.0.6"
"ms": "2.1.2"
}
},
"fd-slicer": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
"integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=",
"get-stream": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
"integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
"dev": true,
"requires": {
"pend": "~1.2.0"
"pump": "^3.0.0"
}
},
"yauzl": {
"version": "2.10.0",
"resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
"integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=",
"dev": true,
"requires": {
"buffer-crc32": "~0.2.3",
"fd-slicer": "~1.1.0"
}
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
}
}
},
@ -9981,6 +9990,15 @@
"bser": "^2.0.0"
}
},
"fd-slicer": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
"integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=",
"dev": true,
"requires": {
"pend": "~1.2.0"
}
},
"feature-policy": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/feature-policy/-/feature-policy-0.3.0.tgz",
@ -21828,9 +21846,9 @@
}
},
"proxy-from-env": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz",
"integrity": "sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=",
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
"dev": true
},
"prr": {
@ -21914,70 +21932,68 @@
}
},
"puppeteer": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-2.0.0.tgz",
"integrity": "sha512-t3MmTWzQxPRP71teU6l0jX47PHXlc4Z52sQv4LJQSZLq1ttkKS2yGM3gaI57uQwZkNaoGd0+HPPMELZkcyhlqA==",
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-5.5.0.tgz",
"integrity": "sha512-OM8ZvTXAhfgFA7wBIIGlPQzvyEETzDjeRa4mZRCRHxYL+GNH5WAuYUQdja3rpWZvkX/JKqmuVgbsxDNsDFjMEg==",
"dev": true,
"requires": {
"debug": "^4.1.0",
"extract-zip": "^1.6.6",
"https-proxy-agent": "^3.0.0",
"mime": "^2.0.3",
"devtools-protocol": "0.0.818844",
"extract-zip": "^2.0.0",
"https-proxy-agent": "^4.0.0",
"node-fetch": "^2.6.1",
"pkg-dir": "^4.2.0",
"progress": "^2.0.1",
"proxy-from-env": "^1.0.0",
"rimraf": "^2.6.1",
"ws": "^6.1.0"
"rimraf": "^3.0.2",
"tar-fs": "^2.0.0",
"unbzip2-stream": "^1.3.3",
"ws": "^7.2.3"
},
"dependencies": {
"agent-base": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz",
"integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==",
"dev": true
},
"debug": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
"dev": true,
"requires": {
"ms": "^2.1.1"
"ms": "2.1.2"
}
},
"glob": {
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
"find-up": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
"dev": true,
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
"locate-path": "^5.0.0",
"path-exists": "^4.0.0"
}
},
"https-proxy-agent": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-3.0.1.tgz",
"integrity": "sha512-+ML2Rbh6DAuee7d07tYGEKOEi2voWPUGan+ExdPbPW6Z3svq+JCqr0v8WmKPOkz1vOVykPCBSuobe7G8GJUtVg==",
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz",
"integrity": "sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==",
"dev": true,
"requires": {
"agent-base": "^4.3.0",
"debug": "^3.1.0"
},
"dependencies": {
"debug": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
"dev": true,
"requires": {
"ms": "^2.1.1"
}
}
"agent-base": "5",
"debug": "4"
}
},
"mime": {
"version": "2.4.4",
"resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz",
"integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==",
"dev": true
"locate-path": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
"dev": true,
"requires": {
"p-locate": "^4.1.0"
}
},
"ms": {
"version": "2.1.2",
@ -21985,14 +22001,44 @@
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
"p-locate": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
"dev": true,
"requires": {
"p-limit": "^2.2.0"
}
},
"path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
"dev": true
},
"pkg-dir": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
"integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
"dev": true,
"requires": {
"find-up": "^4.0.0"
}
},
"rimraf": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
"dev": true,
"requires": {
"glob": "^7.1.3"
}
},
"ws": {
"version": "7.4.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.0.tgz",
"integrity": "sha512-kyFwXuV/5ymf+IXhS6f0+eAFvydbaBW3zjpT6hUdAh/hbVjTIB5EHBGi0bPoCLSK2wcuz3BrEkB9LrYv1Nm4NQ==",
"dev": true
}
}
},
@ -25143,6 +25189,40 @@
"resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.3.tgz",
"integrity": "sha1-SDEm4Rd03y9xuLY53NeZw3YWK4I="
},
"unbzip2-stream": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz",
"integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==",
"dev": true,
"requires": {
"buffer": "^5.2.1",
"through": "^2.3.8"
},
"dependencies": {
"base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
"dev": true
},
"buffer": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
"dev": true,
"requires": {
"base64-js": "^1.3.1",
"ieee754": "^1.1.13"
}
},
"ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
"dev": true
}
}
},
"unc-path-regex": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz",
@ -26908,6 +26988,16 @@
"dev": true
}
}
},
"yauzl": {
"version": "2.10.0",
"resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
"integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=",
"dev": true,
"requires": {
"buffer-crc32": "~0.2.3",
"fd-slicer": "~1.1.0"
}
}
}
}

View File

@ -85,7 +85,7 @@
"node-sass": "^4.14.1",
"nodemon": "^1.19.4",
"plugin-error": "^1.0.1",
"puppeteer": "^2.0.0",
"puppeteer": "^5.5.0",
"raw-loader": "^1.0.0",
"sass-loader": "^7.3.1",
"style-loader": "^0.23.1",