Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into 2211-fix_tooltip_unit_test

This commit is contained in:
Carlos Jimenez Ruiz 2020-05-13 09:21:09 +02:00
commit 3946155e24
296 changed files with 5871 additions and 2945 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

1
.gitignore vendored
View File

@ -5,6 +5,7 @@ e2e/dms/*/
!e2e/dms/c4c
!e2e/dms/c81
!e2e/dms/ecc
!e2e/dms/a87
npm-debug.log
.eslintcache
datasources.*.json

View File

@ -19,7 +19,7 @@ ext install dbaeumer.vscode-eslint
You will need to install globally the following items.
```
# npm install -g jest gulp-cli nodemon
# sudo npm install -g jest gulp-cli nodemon
```
## Linux Only Prerequisites

BIN
back/.DS_Store vendored Normal file

Binary file not shown.

BIN
back/methods/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -47,8 +47,7 @@ module.exports = Self => {
'alias': sender.nickname,
'text': message
}).catch(async error => {
if (error.statusCode === 401 && !this.resendAttempted) {
this.resendAttempted = true;
if (error.statusCode === 401) {
this.auth = null;
return sendMessage(sender, channel, message);

View File

@ -0,0 +1,35 @@
module.exports = Self => {
Self.remoteMethod('collectionFaults', {
description: 'Update sale of a collection',
accessType: 'WRITE',
accepts: [{
arg: 'shelvingFk',
type: 'String',
required: true,
description: 'The shalving id'
}, {
arg: 'quantity',
type: 'Number',
required: true,
description: 'The quantity to sale'
}, {
arg: 'itemFk',
type: 'Number',
required: true,
description: 'The ticket id'
}],
returns: {
type: 'Object',
root: true
},
http: {
path: `/collectionFaults`,
verb: 'POST'
}
});
Self.collectionFaults = async(shelvingFk, quantity, itemFk) => {
query = `CALL vn.collection_faults(?,?,?)`;
return await Self.rawSql(query, [shelvingFk, quantity, itemFk]);
};
};

View File

@ -0,0 +1,22 @@
module.exports = Self => {
Self.remoteMethodCtx('getCollection', {
description: 'Get pending collections from a worker',
accessType: 'READ',
returns: {
type: 'Object',
root: true
},
http: {
path: `/getCollection`,
verb: 'GET'
}
});
Self.getCollection = async ctx => {
const userId = ctx.req.accessToken.userId;
const query = `CALL vn.collection_get(?)`;
const [result] = await Self.rawSql(query, [userId]);
return result;
};
};

View File

@ -0,0 +1,20 @@
module.exports = Self => {
Self.remoteMethod('getSectors', {
description: 'Get all sectors',
accessType: 'READ',
returns: {
type: 'Object',
root: true
},
http: {
path: `/getSectors`,
verb: 'GET'
}
});
Self.getSectors = async() => {
const query = `CALL vn.sector_get()`;
const [result] = await Self.rawSql(query);
return result;
};
};

View File

@ -0,0 +1,133 @@
module.exports = Self => {
Self.remoteMethodCtx('newCollection', {
description: 'Make a new collection of tickets',
accessType: 'WRITE',
accepts: [{
arg: 'collectionFk',
type: 'Number',
required: false,
description: 'The collection id'
}, {
arg: 'sectorFk',
type: 'Number',
required: true,
description: 'The sector of worker'
}, {
arg: 'vWagons',
type: 'Number',
required: true,
description: 'The number of wagons'
}],
returns: {
type: 'Object',
root: true
},
http: {
path: `/newCollection`,
verb: 'POST'
}
});
Self.newCollection = async(ctx, collectionFk, sectorFk, vWagons) => {
let query = '';
if (!collectionFk) {
const userId = ctx.req.accessToken.userId;
query = `CALL vn.collectionTrain_newBeta(?,?,?)`;
const [result] = await Self.rawSql(query, [sectorFk, vWagons, userId]);
if (result.length == 0)
throw new Error(`No collections for today`);
collectionFk = result[0].vCollectionFk;
}
query = `CALL vn.collectionTicket_get(?)`;
const [tickets] = await Self.rawSql(query, [collectionFk]);
query = `CALL vn.collectionSale_get(?)`;
const [sales] = await Self.rawSql(query, [collectionFk]);
query = `CALL vn.collectionPlacement_get(?)`;
const [placements] = await Self.rawSql(query, [collectionFk]);
query = `CALL vn.collectionSticker_print(?,?)`;
await Self.rawSql(query, [collectionFk, sectorFk]);
return makeCollection(tickets, sales, placements, collectionFk);
};
/**
* Returns a collection json
* @param {*} tickets - Request tickets
* @param {*} sales - Request sales
* @param {*} placements - Request placements
* @param {*} collectionFk - Request placements
* @return {Object} Collection JSON
*/
async function makeCollection(tickets, sales, placements, collectionFk) {
let collection = [];
for (let i = 0; i < tickets.length; i++) {
let ticket = {};
ticket['ticketFk'] = tickets[i]['ticketFk'];
ticket['level'] = tickets[i]['level'];
ticket['agencyName'] = tickets[i]['agencyName'];
ticket['warehouseFk'] = tickets[i]['warehouseFk'];
ticket['salesPersonFk'] = tickets[i]['salesPersonFk'];
let ticketSales = [];
for (let x = 0; x < sales.length; x++) {
if (sales[x]['ticketFk'] == ticket['ticketFk']) {
let sale = {};
sale['collectionFk'] = collectionFk;
sale['ticketFk'] = sales[x]['ticketFk'];
sale['saleFk'] = sales[x]['saleFk'];
sale['itemFk'] = sales[x]['itemFk'];
sale['quantity'] = sales[x]['quantity'];
if (sales[x]['quantityPicked'] != null)
sale['quantityPicked'] = sales[x]['quantityPicked'];
else
sale['quantityPicked'] = 0;
sale['longName'] = sales[x]['longName'];
sale['size'] = sales[x]['size'];
sale['color'] = sales[x]['color'];
sale['discount'] = sales[x]['discount'];
sale['price'] = sales[x]['price'];
sale['stems'] = sales[x]['stems'];
sale['category'] = sales[x]['category'];
sale['origin'] = sales[x]['origin'];
sale['clientFk'] = sales[x]['clientFk'];
sale['productor'] = sales[x]['productor'];
sale['reserved'] = sales[x]['reserved'];
sale['isPreviousPrepared'] = sales[x]['isPreviousPrepared'];
sale['isPrepared'] = sales[x]['isPrepared'];
sale['isControlled'] = sales[x]['isControlled'];
let salePlacements = [];
for (let z = 0; z < placements.length; z++) {
if (placements[z]['saleFk'] == sale['saleFk']) {
let placement = {};
placement['saleFk'] = placements[z]['saleFk'];
placement['itemFk'] = placements[z]['itemFk'];
placement['placement'] = placements[z]['placement'];
placement['shelving'] = placements[z]['shelving'];
placement['created'] = placements[z]['created'];
placement['visible'] = placements[z]['visible'];
placement['order'] = placements[z]['order'];
placement['grouping'] = placements[z]['grouping'];
salePlacements.push(placement);
}
}
sale['placements'] = salePlacements;
ticketSales.push(sale);
}
}
ticket['sales'] = ticketSales;
collection.push(ticket);
}
return collection;
}
};

View File

@ -0,0 +1,9 @@
const app = require('vn-loopback/server/server');
describe('collectionFaults()', () => {
it('return shelving afected', async() => {
let response = await app.models.Collection.collectionFaults('UXN', 0, 1);
expect(response.length).toBeGreaterThan(0);
expect(response[0][0].shelvingFk).toEqual('UXN');
});
});

View File

@ -0,0 +1,11 @@
const app = require('vn-loopback/server/server');
describe('getCollection()', () => {
it('return list of collection', async() => {
let ctx = {req: {accessToken: {userId: 106}}};
let response = await app.models.Collection.getCollection(ctx);
expect(response.length).toBeGreaterThan(0);
expect(response[0].collectionFk).toEqual(1);
});
});

View File

@ -0,0 +1,11 @@
const app = require('vn-loopback/server/server');
describe('getSectors()', () => {
it('return list of sectors', async() => {
let response = await app.models.Collection.getSectors();
expect(response.length).toBeGreaterThan(0);
expect(response[0].id).toEqual(1);
expect(response[0].description).toEqual('First sector');
});
});

View File

@ -0,0 +1,11 @@
const app = require('vn-loopback/server/server');
describe('newCollection()', () => {
it('return a new collection', async() => {
let ctx = {req: {accessToken: {userId: 106}}};
let response = await app.models.Collection.newCollection(ctx, 1, 1, 1);
expect(response.length).toBeGreaterThan(0);
expect(response[0].ticketFk).toEqual(1);
});
});

View File

@ -0,0 +1,12 @@
const app = require('vn-loopback/server/server');
describe('updateCollectionSale()', () => {
it('return a new collection', async() => {
let ctx = {req: {accessToken: {userId: 106}}};
let response = await app.models.Collection.updateCollectionSale(ctx, 1, 5, 5, 5, 1, 4, false, 'UXN', 1, 1);
expect(response.length).toBeGreaterThan(0);
expect(response[0][0].id).toEqual(1);
expect(response[0][0].quantity).toEqual(5);
});
});

View File

@ -0,0 +1,89 @@
module.exports = Self => {
Self.remoteMethodCtx('updateCollectionSale', {
description: 'Update sale of a collection',
accessType: 'WRITE',
accepts: [{
arg: 'sale',
type: 'Number',
required: true,
description: 'The sale id'
}, {
arg: 'originalQuantity',
type: 'Number',
required: true,
description: 'The quantity to sale'
},
{
arg: 'quantity',
type: 'Number',
required: true,
description: 'The quantity to picked'
},
{
arg: 'quantityPicked',
type: 'Number',
required: true,
description: 'The quantity to picked'
}, {
arg: 'ticketFk',
type: 'Number',
required: true,
description: 'The ticket id'
}, {
arg: 'stateFk',
type: 'Number',
required: true,
description: 'The state id'
}, {
arg: 'isNicho',
type: 'Boolean',
required: true,
description: 'Determine if sale is picked from nicho or not'
}, {
arg: 'shelvingFk',
type: 'String',
required: false,
description: 'The shelving id'
}, {
arg: 'itemFk',
type: 'Number',
required: true,
description: 'The item id'
}, {
arg: 'sectorFk',
type: 'Number',
required: true,
description: 'The sector id'
}],
returns: {
type: 'Object',
root: true
},
http: {
path: `/updateCollectionSale`,
verb: 'POST'
}
});
Self.updateCollectionSale = async(ctx, sale, originalQuantity, quantity, quantityPicked, ticketFk, stateFk, isNicho, shelvingFk, itemFk, sectorFk) => {
const userId = ctx.req.accessToken.userId;
if (originalQuantity == quantity) {
query = `CALL vn.collection_updateSale(?,?,?,?,?)`;
await Self.rawSql(query, [sale, originalQuantity, userId, stateFk, ticketFk]);
}
if (!isNicho) {
query = `CALL vn.collection_faults(?,?,?)`;
await Self.rawSql(query, [shelvingFk, quantityPicked, itemFk]);
} else {
query = `CALL vn.sector_getWarehouse(?)`;
const [result] = await Self.rawSql(query, [sectorFk]);
query = `CALL vn.itemPlacementSave(?,?,?)`;
await Self.rawSql(query, [shelvingFk, quantityPicked, result[0]['warehouseFk']]);
}
query = `CALL vn.sale_updateOriginalQuantity(?,?)`;
return await Self.rawSql(query, [sale, quantity]);
};
};

View File

@ -1,5 +1,4 @@
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.remoteMethodCtx('downloadFile', {
description: 'Download a document',
@ -34,29 +33,8 @@ module.exports = Self => {
});
Self.downloadFile = async function(ctx, id) {
const storageConnector = Self.app.dataSources.storage.connector;
const models = Self.app.models;
const dms = await Self.findById(id);
const hasReadRole = await models.DmsType.hasReadRole(ctx, dms.dmsTypeFk);
if (!hasReadRole)
if (!await Self.checkRole(ctx, id))
throw new UserError(`You don't have enough privileges`);
const pathHash = storageConnector.getPathHash(dms.id);
try {
await models.Container.getFile(pathHash, dms.file);
} catch (e) {
if (e.code != 'ENOENT')
throw e;
const error = new UserError(`File doesn't exists`);
error.statusCode = 404;
throw error;
}
const stream = models.Container.downloadStream(pathHash, dms.file);
return [stream, dms.contentType, `filename="${dms.file}"`];
return await Self.getFile(id);
};
};

View File

@ -11,7 +11,7 @@ describe('dms downloadFile()', () => {
expect(result[1]).toEqual('text/plain');
});
it(`should return an error for a user without enough privileges`, async() => {
it('should return an error for a user without enough privileges', async() => {
let clientId = 101;
let ctx = {req: {accessToken: {userId: clientId}}};

View File

@ -14,6 +14,9 @@
"Container": {
"dataSource": "storage"
},
"Collection": {
"dataSource": "vn"
},
"Chat": {
"dataSource": "vn"
},

View File

@ -0,0 +1,7 @@
module.exports = Self => {
require('../methods/collection/getCollection')(Self);
require('../methods/collection/newCollection')(Self);
require('../methods/collection/getSectors')(Self);
require('../methods/collection/updateCollectionSale')(Self);
require('../methods/collection/collectionFaults')(Self);
};

View File

@ -0,0 +1,12 @@
{
"name": "Collection",
"base": "VnModel",
"acls": [{
"property": "validations",
"accessType": "EXECUTE",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
}]
}

View File

@ -1,6 +1,37 @@
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
require('../methods/dms/downloadFile')(Self);
require('../methods/dms/uploadFile')(Self);
require('../methods/dms/removeFile')(Self);
require('../methods/dms/updateFile')(Self);
Self.checkRole = async function(ctx, id) {
const models = Self.app.models;
const dms = await Self.findById(id);
return await models.DmsType.hasReadRole(ctx, dms.dmsTypeFk);
};
Self.getFile = async function(id) {
const storageConnector = Self.app.dataSources.storage.connector;
const models = Self.app.models;
const dms = await Self.findById(id);
const pathHash = storageConnector.getPathHash(dms.id);
try {
await models.Container.getFile(pathHash, dms.file);
} catch (e) {
if (e.code != 'ENOENT')
throw e;
const error = new UserError(`File doesn't exists`);
error.statusCode = 404;
throw error;
}
const stream = models.Container.downloadStream(pathHash, dms.file);
return [stream, dms.contentType, `filename="${dms.file}"`];
};
};

View File

@ -0,0 +1,53 @@
const app = require('vn-loopback/server/server');
describe('Dms', () => {
const Dms = app.models.Dms;
describe('getFile()', () => {
it('should return a response with text content-type', async() => {
const result = await Dms.getFile(1);
expect(result[1]).toEqual('text/plain');
});
it('should return an error for a file does not exists', async() => {
let error = {};
try {
await Dms.getFile(6);
} catch (e) {
error = e;
}
expect(error.statusCode).toBe(404);
});
it('should return an error for a record does not exists', async() => {
let error = {};
try {
await app.models.Dms.getFile('NotExistentId');
} catch (e) {
error = e;
}
expect(error.statusCode).not.toBe(404);
expect(error).toEqual(jasmine.any(Error));
});
});
describe('checkRole()', () => {
const dmsId = 1;
it('should return a true for an employee with permission', async() => {
let ctx = {req: {accessToken: {userId: 107}}};
const result = await Dms.checkRole(ctx, dmsId);
expect(result).toBeTruthy();
});
it('should return false for an employee without permission', async() => {
let ctx = {req: {accessToken: {userId: 101}}};
const result = await Dms.checkRole(ctx, dmsId);
expect(result).toBeFalsy();
});
});
});

View File

@ -0,0 +1,4 @@
ALTER TABLE `vn`.`workerDocument`
ADD COLUMN `isReadableByWorker` TINYINT(1) NOT NULL DEFAULT 0 AFTER `document`;
UPDATE `vn`.`workerDocument` SET `isReadableByWorker` = '1' WHERE (`id` = '1');

View File

@ -0,0 +1,108 @@
DROP procedure IF EXISTS `vn`.`collectionPlacement_get`;
DELIMITER $$
CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`collectionPlacement_get`(vCollectionFk INT)
BEGIN
DECLARE vCalcFk INT;
DECLARE vWarehouseFk INT;
DECLARE vWarehouseAliasFk INT;
SELECT t.warehouseFk, w.aliasFk
INTO vWarehouseFk, vWarehouseAliasFk
FROM vn.ticket t
JOIN vn.ticketCollection tc ON tc.ticketFk = t.id
JOIN vn.warehouse w ON w.id = t.warehouseFk
WHERE tc.collectionFk = vCollectionFk
LIMIT 1;
CALL cache.visible_refresh(vCalcFk,FALSE,vWarehouseFk);
DROP TEMPORARY TABLE IF EXISTS tmp.parked;
CREATE TEMPORARY TABLE tmp.parked
ENGINE MEMORY
SELECT s.itemFk, 0 as quantity
FROM vn.ticketCollection tc
JOIN vn.sale s ON s.ticketFk = tc.ticketFk
WHERE tc.collectionFk = vCollectionFk;
UPDATE tmp.parked pk
JOIN ( SELECT itemFk, sum(visible) as visible
FROM vn.itemShelvingStock iss
JOIN vn.warehouse w ON w.id = iss.warehouseFk
WHERE w.aliasFk = vWarehouseAliasFk
GROUP BY iss.itemFk ) iss ON iss.itemFk = pk.itemFk
SET pk.quantity = iss.visible;
DROP TEMPORARY TABLE IF EXISTS tmp.`grouping`;
CREATE TEMPORARY TABLE tmp.`grouping`
ENGINE MEMORY
SELECT itemFk, `grouping`
FROM (
SELECT itemFk,
CASE groupingMode
WHEN 0 THEN 1
WHEN 2 THEN packing
ELSE `grouping`
END AS `grouping`
FROM buy b
JOIN entry e ON e.id = b.entryFk
JOIN travel tr ON tr.id = e.travelFk
WHERE tr.warehouseInFk = vWarehouseFk
AND landed BETWEEN (SELECT inventoried FROM vn.config LIMIT 1) AND CURDATE()
AND b.isIgnored = FALSE
ORDER BY tr.landed DESC
) sub
GROUP BY sub.itemFk ;
DROP TEMPORARY TABLE IF EXISTS tmp.grouping2;
CREATE TEMPORARY TABLE tmp.grouping2
ENGINE MEMORY
SELECT * FROM tmp.`grouping`;
SELECT s.id as saleFk, s.itemFk,
p.code COLLATE utf8_general_ci as placement ,
sh.code COLLATE utf8_general_ci as shelving,
ish.created,
ish.visible,
0 as `order`,
IF(sc.isPreviousPreparedByPacking, ish.packing, g.`grouping`) as `grouping`
FROM vn.ticketCollection tc
JOIN vn.sale s ON s.ticketFk = tc.ticketFk
JOIN vn.itemShelving ish ON ish.itemFk = s.itemFk
JOIN vn.shelving sh ON sh.code = ish.shelvingFk
JOIN vn.parking p ON p.id = sh.parkingFk
JOIN vn.sector sc ON sc.id = p.sectorFk
JOIN vn.warehouse w ON w.id = sc.warehouseFk
JOIN tmp.`grouping` g ON g.itemFk = s.itemFk
WHERE tc.collectionFk = vCollectionFk
AND w.aliasFk = vWarehouseAliasFk
AND ish.visible > 0
UNION ALL
SELECT s.id as saleFk, s.itemFk,
ip.code COLLATE utf8_general_ci as placement,
'' COLLATE latin1_general_ci as shelving,
modificationDate as created,
v.visible - p.quantity as visible,
0 as `order`,
g.`grouping`
FROM vn.ticketCollection tc
JOIN vn.sale s ON s.ticketFk = tc.ticketFk
JOIN vn.itemPlacement ip ON ip.itemFk = s.itemFk AND ip.warehouseFk = vWarehouseFk
JOIN tmp.parked p ON p.itemFk = s.itemFk
JOIN cache.visible v ON v.item_id = s.itemFk AND v.calc_id = vCalcFk
LEFT JOIN tmp.grouping2 g ON g.itemFk = s.itemFk
WHERE tc.collectionFk = vCollectionFk
AND v.visible - p.quantity > 0;
DROP TEMPORARY TABLE
tmp.parked,
tmp.`grouping`,
tmp.grouping2;
END
$$
DELIMITER ;

View File

@ -0,0 +1,39 @@
DROP procedure IF EXISTS `vn`.`collection_faults`;
DELIMITER $$
CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`collection_faults`(
vShelvingFk VARCHAR(10),
vQuantity INT,
vItemFk INT)
BEGIN
DECLARE vQuantityTotal INT DEFAULT 0;
DECLARE vshelve VARCHAR(2);
DECLARE vdeep INT(11);
DECLARE vpriority INT(11);
DECLARE vgrouping SMALLINT(5);
DECLARE vpacking INT(11);
DECLARE vpackagingFk VARCHAR(10);
DECLARE vlevel VARCHAR(45);
DECLARE vuserFk INT(10);
SELECT SUM(quantity),shelve,deep,priority,`grouping`,packing,packagingFk,`level`,userFk
INTO vQuantityTotal,vshelve,vdeep,vpriority,vgrouping,vpacking,vpackagingFk,vlevel,vuserFk
FROM vn.itemShelving
WHERE shelvingFk = vShelvingFk COLLATE utf8mb4_unicode_ci AND itemFk = vItemFk
GROUP BY itemFk;
SELECT vQuantityTotal - vQuantity INTO vQuantityTotal;
DELETE FROM vn.itemShelving WHERE shelvingFk = vShelvingFk COLLATE utf8mb4_unicode_ci AND itemFk = vItemFk;
INSERT INTO vn.itemShelving (itemFk, shelvingFk,shelve,deep,quantity,visible,available,priority,`grouping`,packing,packagingFk,`level`,userFk )
VALUES (vItemFk,vShelvingFk,vshelve,vdeep,vQuantityTotal,vQuantityTotal,vQuantityTotal,vpriority,vgrouping,vpacking,vpackagingFk,vlevel,vuserFk );
SELECT * FROM vn.itemShelving
WHERE shelvingFk = vShelvingFk COLLATE utf8mb4_unicode_ci AND itemFk = vItemFk;
END$$
DELIMITER ;

View File

@ -0,0 +1,42 @@
DROP procedure IF EXISTS `vn`.`collection_updateSale`;
DELIMITER $$
CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`collection_updateSale`(
vSaleFk INT,
vOriginalQuantity INT,
vWorkerFk INT,
vStateFk INT,
vTicketFk INT)
BEGIN
DECLARE vNumPrepared INT;
DECLARE vNumTotal INT;
REPLACE INTO vn.saleTracking(saleFk,isChecked, originalQuantity, workerFk, actionFk,stateFk)
VALUES(vSaleFk,1,vOriginalQuantity,vWorkerFk,vStateFk,vStateFk);
UPDATE vn.sale SET isPicked = 1
WHERE id = vSaleFk;
SELECT COUNT(s.id) INTO vNumPrepared
FROM vn.sale s
WHERE s.ticketFk = vTicketFk AND s.isPicked = 1;
SELECT COUNT(s.id) INTO vNumTotal
FROM vn.sale s
WHERE s.ticketFk = vTicketFk;
IF vNumPrepared = vNumTotal THEN
INSERT INTO vncontrol.inter
SET state_id = vStateFk, Id_Ticket = vTicketFk, Id_Trabajador = vWorkerFk;
CALL vn.collection_update(vTicketFk);
END IF;
END$$
DELIMITER ;

View File

@ -0,0 +1,13 @@
/*DROP view IF EXISTS `vn`.`coolerPathDetail`;
CREATE
ALGORITHM = UNDEFINED
DEFINER = `root`@`%`
SQL SECURITY DEFINER
VIEW `vn`.`coolerPathDetail` AS
SELECT
`c`.`cooler_path_detail_id` AS `id`,
`c`.`cooler_path_id` AS `coolerPathFk`,
`c`.`pasillo` AS `hallway`
FROM
`vn2008`.`cooler_path_detail` `c`*/

View File

@ -0,0 +1,15 @@
DROP procedure IF EXISTS `vn`.`sale_updateOriginalQuantity`;
DELIMITER $$
CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`sale_updateOriginalQuantity`(vSale INT, vQuantity INT)
proc: BEGIN
UPDATE vn.sale SET originalQuantity = vQuantity
WHERE id = vSale;
SELECT * FROM vn.sale WHERE id = vSale;
END$$
DELIMITER ;

View File

@ -0,0 +1,14 @@
DROP procedure IF EXISTS `vn`.`sector_getWarehouse`;
DELIMITER $$
CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`sector_getWarehouse`(vSectorFk INT)
BEGIN
SELECT s.warehouseFk
FROM vn.sector s
WHERE s.id = vSectorFk;
END$$
DELIMITER ;

View File

@ -0,0 +1,5 @@
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('WorkerDms', 'filter', 'READ', 'ALLOW', 'ROLE', 'employee'),
('WorkerDms', 'downloadFile', 'READ', 'ALLOW', 'ROLE', 'employee');
DELETE FROM `salix`.`ACL` WHERE (`id` = '205');

View File

@ -0,0 +1,13 @@
ALTER TABLE `vn`.`ticketWeekly`
ADD COLUMN `agencyModeFk` INT(11) NULL DEFAULT NULL AFTER `weekDay`,
ADD INDEX `agencyModeFk_idx` (`agencyModeFk` ASC);
ALTER TABLE `vn`.`ticketWeekly`
ADD CONSTRAINT `agencyModeFk`
FOREIGN KEY (`agencyModeFk`)
REFERENCES `vn`.`agencyMode` (`id`)
ON DELETE SET NULL
ON UPDATE CASCADE;
ALTER TABLE `vn`.`ticketWeekly`
CHANGE COLUMN `weekDay` `weekDay` TINYINT(1) NOT NULL COMMENT 'funcion de mysql Lunes = 0, Domingo = 6' ;

View File

@ -0,0 +1,130 @@
DELIMITER $$
USE `vn`$$
CREATE DEFINER=`root`@`%` PROCEDURE `ticket_cloneWeekly`(IN vWeek INT)
BEGIN
DECLARE vIsDone BOOL;
DECLARE vLanding DATE;
DECLARE vShipment DATE;
DECLARE vWarehouse INT;
DECLARE vTicket INT;
DECLARE vWeekDay INT;
DECLARE vClient INT;
DECLARE vEmpresa INT;
DECLARE vAddressFk INT;
DECLARE vAgencyModeFk INT;
DECLARE vNewTicket INT;
DECLARE vYear INT;
DECLARE rsTicket CURSOR FOR
SELECT tw.ticketFk, weekDay, t.clientFk, t.warehouseFk, t.companyFk, t.addressFk, tw.agencyModeFk
FROM ticketWeekly tw
JOIN ticket t ON tt.ticketFk = t.id;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vIsDone = TRUE;
SET vYear = YEAR(CURDATE()) + IF(vWeek < WEEK(CURDATE()),1, 0);
OPEN rsTicket;
myLoop: LOOP
BEGIN
DECLARE vError TEXT;
DECLARE vSalesPersonEmail VARCHAR(150);
DECLARE vMailSent BOOL;
DECLARE vSubject VARCHAR(150);
DECLARE vMessage TEXT;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
BEGIN
GET DIAGNOSTICS CONDITION 1
vError = MESSAGE_TEXT;
END;
SET vIsDone = FALSE;
FETCH rsTicket INTO vTicket, vWeekDay, vClient, vWarehouse, vEmpresa, vAddressFk, vAgencyModeFk;
IF vIsDone THEN
LEAVE myLoop;
END IF;
SELECT date INTO vShipment
FROM `time`
WHERE `year` = vYear AND `week` = vWeek
AND WEEKDAY(date) = vWeekDay;
-- busca si el ticket ya ha sido clonado
IF (SELECT COUNT(*) FROM vn.ticket tOrig
JOIN vn.sale saleOrig ON tOrig.id = saleOrig.ticketFk
JOIN vn.saleCloned sc ON sc.saleOriginalFk = saleOrig.id
JOIN vn.sale saleClon ON saleClon.id = sc.saleClonedFk
JOIN vn.ticket tClon ON tClon.id = saleClon.ticketFk
WHERE tOrig.id = vTicket AND DATE(tClon.shipped) = vShipment) > 0
THEN
ITERATE myLoop;
END IF;
CALL vn.zone_getLanded(vShipment, vAddressFk, vAgencyModeFk, vWarehouse);
SELECT landed INTO vLanding from tmp.zoneGetLanded LIMIT 1;
CALL vn.ticketCreateWithoutZone(vClient, vShipment, vWarehouse, vEmpresa, vAddressFk, vAgencyModeFk, NULL, vLanding, account.userGetId(), vNewTicket);
IF (vLanding IS NULL) THEN
SELECT e.email INTO vSalesPersonEmail
FROM vn.client c
JOIN vn.worker sp ON sp.id = c.salesPersonFk
JOIN account.emailUser e ON e.userFk = sp.userFk
WHERE c.id = vClient;
SET vSubject = CONCAT('Turnos - No se ha podido clonar correctamente el ticket ', vTicket,
' para el dia: ', vShipment);
SET vMessage = CONCAT('No se ha podido clonar el ticket ', vTicket,
' para el dia: ', vShipment,
' porque no hay una zona de envío disponible. Se ha creado el ticket: ', vNewTicket,
' pero ha que revisar las fechas y la agencia');
SELECT COUNT(*) INTO vMailSent
FROM vn.mail
WHERE sender = vSalesPersonEmail
AND subject = vSubject;
IF NOT vMailSent THEN
INSERT INTO vn.mail (sender,`subject`,body)
VALUES (vSalesPersonEmail, vSubject, vMessage);
END IF;
CALL vn.ticketStateUpdate (vNewTicket, 'FIXING');
END IF;
INSERT INTO vn.sale (ticketFk, itemFk, concept, quantity, price, discount, priceFixed, isPriceFixed)
SELECT vNewTicket, saleOrig.itemFk , saleOrig.concept , saleOrig.quantity, saleOrig.price , saleOrig.discount, saleOrig.priceFixed, saleOrig.isPriceFixed
FROM vn.ticket tOrig
JOIN vn.sale saleOrig ON tOrig.id = saleOrig.ticketFk
LEFT JOIN vn.saleCloned sc ON sc.saleOriginalFk = saleOrig.id
LEFT JOIN vn.sale saleClon ON saleClon.id = sc.saleClonedFk
LEFT JOIN vn.ticket tClon ON tClon.id = saleClon.ticketFk AND DATE(tClon.shipped) = vShipment
WHERE tOrig.id = vTicket AND saleClon.id IS NULL;
INSERT IGNORE INTO vn.saleCloned(saleOriginalFk, saleClonedFk)
SELECT saleOriginal.id, saleClon.id
FROM vn.sale saleOriginal
JOIN vn.sale saleClon ON saleOriginal.itemFk = saleClon.itemFk AND saleOriginal.quantity = saleClon.quantity
WHERE saleOriginal.ticketFk = vTicket AND saleClon.ticketFk = vNewTicket;
INSERT INTO ticketRequest (description, ordered, shipped, salesPersonCode, buyerCode, quantity, price,
itemFk ,clientFk, response, total, buyed, saleFk)
SELECT tr.description, tr.ordered, tr.shipped, tr.salesPersonCode, tr.buyerCode, tr.quantity, tr.price,
tr.itemFk, tr.clientFk, tr.response, tr.total, tr.buyed, tr.saleFk
FROM sale s JOIN ticketRequest tr ON tr.saleFk = s.id
JOIN sale s2 ON s.concept = s2.concept AND s.quantity = s2.quantity AND m.Id_Article = m2.Id_Article
WHERE s.ticketFk = vTicket AND s2.ticketFk = vNewTicket;
CALL vn.ticketCalculateClon(vNewTicket, vTicket);
END;
END LOOP;
CLOSE rsTicket;
END$$
DELIMITER ;

View File

@ -0,0 +1 @@
UPDATE `vn`.`component` SET `code` = 'imbalance' WHERE (`id` = '36');

View File

@ -0,0 +1,6 @@
UPDATE vn.ticketWeekly tw
JOIN vn.ticket t ON t.id = tw.ticketFk
JOIN vn.agencyMode am ON am.id = t.agencyModeFk
SET tw.agencyModeFk = t.agencyModeFk
WHERE am.name NOT LIKE '%turno%';

View File

@ -0,0 +1,148 @@
USE `vn`;
DROP procedure IF EXISTS `catalog_calculate`;
DELIMITER $$
USE `vn`$$
CREATE DEFINER=`root`@`%` PROCEDURE `catalog_calculate`(
vLanded DATE,
vAddressFk INT,
vAgencyModeFk INT)
proc: BEGIN
/**
* Calcula los articulos disponibles y sus precios
*
* @table tmp.item(itemFk) Listado de artículos a calcular
* @param vLanded Fecha de recepcion de mercancia
* @param vAddressFk Id del consignatario
* @param vAgencyModeFk Id de la agencia
* @return tmp.ticketCalculateItem(itemFk, available, producer,
* item, size, stems, category, inkFk, image, origin, price)
* @return tmp.ticketLot(warehouseFk, itemFk, available, buyFk)
* @return tmp.ticketComponent
* @return tmp.ticketComponentPrice
* @return tmp.zoneGetShipped
*/
DECLARE vAvailableCalc INT;
DECLARE vShipped DATE;
DECLARE vWarehouseFk SMALLINT;
DECLARE vZoneFk INT;
DECLARE vDone BOOL;
DECLARE cTravelTree CURSOR FOR
SELECT zoneFk, warehouseFk, shipped FROM tmp.zoneGetShipped;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE;
-- Establece los almacenes y las fechas que van a entrar al disponible
CALL vn.zone_getShipped (vLanded, vAddressFk, vAgencyModeFk, FALSE);
DROP TEMPORARY TABLE IF EXISTS tmp.ticketLot;
CREATE TEMPORARY TABLE tmp.ticketLot(
`warehouseFk` smallint(5) unsigned NOT NULL,
`itemFk` int(11) NOT NULL,
`available` double DEFAULT NULL,
`buyFk` int(11) DEFAULT NULL,
`fix` tinyint(3) unsigned DEFAULT '0',
`zoneFk` int(11) NOT NULL,
KEY `itemFk` (`itemFk`),
KEY `item_warehouse` (`itemFk`,`warehouseFk`) USING HASH
) ENGINE=MEMORY DEFAULT CHARSET=utf8;
CALL catalog_componentPrepare();
DROP TEMPORARY TABLE IF EXISTS tmp.ticketCalculateItem;
CREATE TEMPORARY TABLE tmp.ticketCalculateItem(
itemFk INT(11) NOT NULL,
available INT(11),
producer VARCHAR(50),
item VARCHAR(50),
size INT(10) UNSIGNED,
stems INT(11),
category VARCHAR(3),
inkFk VARCHAR(3),
image VARCHAR(50),
origin VARCHAR(3),
price DECIMAL(10,2),
priceKg DECIMAL(10,2),
KEY `itemFk` (`itemFk`)
) ENGINE = MEMORY DEFAULT CHARSET=utf8;
OPEN cTravelTree;
l: LOOP
SET vDone = FALSE;
FETCH cTravelTree INTO vZoneFk, vWarehouseFk, vShipped;
IF vDone THEN
LEAVE l;
END IF;
CALL `cache`.available_refresh (vAvailableCalc, FALSE, vWarehouseFk, vShipped);
CALL buyUltimate (vWarehouseFk, vShipped);
INSERT INTO tmp.ticketLot (warehouseFk, itemFk, available, buyFk, zoneFk)
SELECT vWarehouseFk,
i.item_id,
IFNULL(i.available, 0),
bu.buyFk,
vZoneFk
FROM `cache`.available i
JOIN tmp.item br ON br.itemFk = i.item_id
LEFT JOIN item it ON it.id = i.item_id
LEFT JOIN tmp.buyUltimate bu ON bu.itemFk = i.item_id
WHERE i.calc_id = vAvailableCalc
AND i.available > 0;
DROP TEMPORARY TABLE tmp.buyUltimate;
CALL vn.catalog_componentCalculate(vZoneFk, vAddressFk, vShipped, vWarehouseFk);
INSERT INTO tmp.ticketCalculateItem (
itemFk,
available,
producer,
item,
size,
stems,
category,
inkFk,
image,
origin,
price,
priceKg)
SELECT
tl.itemFk,
SUM(tl.available) available,
p.name producer,
i.name item,
i.size size,
i.stems,
i.category,
i.inkFk,
i.image,
o.code origin,
bl.price,
bl.priceKg
FROM tmp.ticketLot tl
JOIN item i ON tl.itemFk = i.id
LEFT JOIN producer p ON p.id = i.producerFk AND p.isVisible
JOIN origin o ON o.id = i.originFk
JOIN (
SELECT MIN(price) price, itemFk, priceKg
FROM tmp.ticketComponentPrice
WHERE warehouseFk = vWarehouseFk
GROUP BY itemFk
) bl ON bl.itemFk = tl.itemFk
WHERE tl.zoneFk = vZoneFk AND tl.warehouseFk = vWarehouseFk
GROUP BY tl.itemFk;
-- on duplicatekey update
END LOOP;
CLOSE cTravelTree;
END$$
DELIMITER ;

View File

@ -0,0 +1,262 @@
USE `vn`;
DROP procedure IF EXISTS `catalog_componentCalculate`;
DELIMITER $$
USE `vn`$$
CREATE DEFINER=`root`@`%` PROCEDURE `catalog_componentCalculate`(
vZoneFk INT,
vAddressFk INT,
vShipped DATE,
vWarehouseFk INT)
proc: BEGIN
/**
* Calcula los componentes de los articulos de tmp.ticketLot
*
* @param vZoneFk para calcular el transporte
* @param vAddressFk Consignatario
* @param vShipped dia de salida del pedido
* @param tmp.ticketLot (warehouseFk, available, itemFk, buyFk, zoneFk)
*
* @return tmp.ticketComponent(itemFk, warehouseFk, available, rate2, rate3, minPrice,
* packing, grouping, groupingMode, buyFk, typeFk)
* @return tmp.ticketComponentPrice (warehouseFk, itemFk, rate, grouping, price)
*/
DECLARE vClientFk INT;
DECLARE vGeneralInflationCoefficient INT DEFAULT 1;
DECLARE vMinimumDensityWeight INT DEFAULT 167;
DECLARE vBoxVolume BIGINT; -- DEFAULT 138000;
DECLARE vSpecialPriceComponent INT DEFAULT 10;
DECLARE vDeliveryComponent INT DEFAULT 15;
DECLARE vRecoveryComponent INT DEFAULT 17;
DECLARE vSellByPacketComponent INT DEFAULT 22;
DECLARE vBuyValueComponent INT DEFAULT 28;
DECLARE vMarginComponent INT DEFAULT 29;
DECLARE vDiscountLastItemComponent INT DEFAULT 32;
DECLARE vExtraBaggedComponent INT DEFAULT 38;
DECLARE vManaAutoComponent INT DEFAULT 39;
SELECT volume INTO vBoxVolume
FROM vn.packaging
WHERE id = '94';
SELECT clientFk INTO vClientFK
FROM address
WHERE id = vAddressFk;
SET @rate2 := 0;
SET @rate3 := 0;
DROP TEMPORARY TABLE IF EXISTS tmp.ticketComponentCalculate;
CREATE TEMPORARY TABLE tmp.ticketComponentCalculate
(PRIMARY KEY (itemFk, warehouseFk))
ENGINE = MEMORY
SELECT
tl.itemFk, tl.warehouseFk, tl.available,
IF((@rate2 := IFNULL(pf.rate2, b.price2)) < i.minPrice AND i.hasMinPrice, i.minPrice, @rate2) * 1.0 rate2,
IF((@rate3 := IFNULL(pf.rate3, b.price3)) < i.minPrice AND i.hasMinPrice, i.minPrice, @rate3) * 1.0 rate3,
IFNULL(pf.rate3, 0) AS minPrice,
IFNULL(pf.packing, b.packing) packing,
IFNULL(pf.`grouping`, b.`grouping`) `grouping`,
ABS(IFNULL(pf.box, b.groupingMode)) groupingMode,
tl.buyFk,
i.typeFk,
IF(i.hasKgPrice, b.weight / b.packing, NULL) weightGrouping
FROM tmp.ticketLot tl
JOIN buy b ON b.id = tl.buyFk
JOIN item i ON i.id = tl.itemFk
JOIN itemType it ON it.id = i.typeFk
LEFT JOIN itemCategory ic ON ic.id = it.categoryFk
LEFT JOIN specialPrice sp ON sp.itemFk = i.id AND sp.clientFk = vClientFk
LEFT JOIN (
SELECT * FROM (
SELECT pf.itemFk, pf.`grouping`, pf.packing, pf.box, pf.rate2, pf.rate3, zw.warehouseFk
FROM priceFixed pf
JOIN zoneWarehouse zw ON zw.zoneFk = vZoneFk AND (zw.warehouseFk = pf.warehouseFk OR pf.warehouseFk = 0)
WHERE vShipped BETWEEN pf.started AND pf.ended ORDER BY pf.itemFk, pf.warehouseFk DESC
) tpf
GROUP BY tpf.itemFk, tpf.warehouseFk
) pf ON pf.itemFk = tl.itemFk AND pf.warehouseFk = tl.warehouseFk
WHERE b.buyingValue + b.freightValue + b.packageValue + b.comissionValue > 0.01 AND ic.display <> 0
AND tl.zoneFk = vZoneFk AND tl.warehouseFk = vWarehouseFk;
INSERT INTO tmp.ticketComponent (warehouseFk, itemFk, componentFk, cost)
SELECT
tcc.warehouseFk,
tcc.itemFk,
vBuyValueComponent,
b.buyingValue + b.freightValue + b.packageValue + b.comissionValue
FROM tmp.ticketComponentCalculate tcc
JOIN buy b ON b.id = tcc.buyFk;
INSERT INTO tmp.ticketComponent (warehouseFk, itemFk, componentFk, cost)
SELECT
tcc.warehouseFk,
tcc.itemFk,
vMarginComponent,
tcc.rate3 - b.buyingValue - b.freightValue - b.packageValue - b.comissionValue
FROM tmp.ticketComponentCalculate tcc
JOIN buy b ON b.id = tcc.buyFk;
DROP TEMPORARY TABLE IF EXISTS tmp.ticketComponentBase;
CREATE TEMPORARY TABLE tmp.ticketComponentBase ENGINE = MEMORY
SELECT tc.itemFk, ROUND(SUM(tc.cost), 4) AS base, tc.warehouseFk
FROM tmp.ticketComponent tc
JOIN tmp.ticketComponentCalculate tcc ON tcc.itemFk = tc.itemFk AND tcc.warehouseFk = tc.warehouseFk
GROUP BY tc.itemFk, warehouseFk;
INSERT INTO tmp.ticketComponent
SELECT tcb.warehouseFk, tcb.itemFk, vRecoveryComponent, ROUND(tcb.base * LEAST(cr.priceIncreasing, 0.25), 3)
FROM tmp.ticketComponentBase tcb
JOIN claimRatio cr ON cr.clientFk = vClientFk
WHERE cr.priceIncreasing > 0.009;
INSERT INTO tmp.ticketComponent
SELECT tcb.warehouseFk, tcb.itemFk, vManaAutoComponent, ROUND(base * (0.01 + wm.pricesModifierRate), 3) as manaAuto
FROM tmp.ticketComponentBase tcb
JOIN `client` c on c.id = vClientFk
JOIN workerMana wm ON c.salesPersonFk = wm.workerFk
WHERE wm.isPricesModifierActivated
HAVING manaAuto <> 0;
INSERT INTO tmp.ticketComponent
SELECT tcb.warehouseFk,
tcb.itemFk,
c.id,
GREATEST(IFNULL(ROUND(tcb.base * c.tax, 4), 0), tcc.minPrice - tcc.rate3)
FROM tmp.ticketComponentBase tcb
JOIN component c
JOIN tmp.ticketComponentCalculate tcc ON tcc.itemFk = tcb.itemFk AND tcc.warehouseFk = tcb.warehouseFk
LEFT JOIN specialPrice sp ON sp.clientFk = vClientFk AND sp.itemFk = tcc.itemFk
WHERE c.id = vDiscountLastItemComponent AND c.tax <> 0 AND tcc.minPrice < tcc.rate3 AND sp.value IS NULL;
INSERT INTO tmp.ticketComponent
SELECT tcc.warehouseFk, tcc.itemFk, vSellByPacketComponent, tcc.rate2 - tcc.rate3
FROM tmp.ticketComponentCalculate tcc
JOIN buy b ON b.id = tcc.buyFk
LEFT JOIN specialPrice sp ON sp.clientFk = vClientFk AND sp.itemFk = tcc.itemFk
WHERE sp.value IS NULL;
DROP TEMPORARY TABLE IF EXISTS tmp.zone;
CREATE TEMPORARY TABLE IF NOT EXISTS tmp.zone (INDEX (id))
ENGINE = MEMORY
SELECT vZoneFk id;
CALL zone_getOptionsForShipment(vShipped, TRUE);
INSERT INTO tmp.ticketComponent
SELECT tcc.warehouseFK,
tcc.itemFk,
vDeliveryComponent,
vGeneralInflationCoefficient
* ROUND((
i.compression
* ic.cm3
* IF(am.deliveryMethodFk = 1, (GREATEST(i.density, vMinimumDensityWeight) / vMinimumDensityWeight), 1)
* IFNULL((zo.price - zo.bonus)
* 1/*amz.inflation*/ , 50)) / vBoxVolume, 4
) cost
FROM tmp.ticketComponentCalculate tcc
JOIN item i ON i.id = tcc.itemFk
JOIN tmp.zoneOption zo ON zo.zoneFk = vZoneFk
JOIN zone z ON z.id = vZoneFk
JOIN agencyMode am ON am.id = z.agencyModeFk
LEFT JOIN itemCost ic ON ic.warehouseFk = tcc.warehouseFk
AND ic.itemFk = tcc.itemFk
HAVING cost <> 0;
DROP TEMPORARY TABLE tmp.zoneOption;
IF (SELECT COUNT(*) FROM vn.addressForPackaging WHERE addressFk = vAddressFk) THEN
INSERT INTO tmp.ticketComponent
SELECT tcc.warehouseFk, b.itemFk, vExtraBaggedComponent, ap.packagingValue cost
FROM tmp.ticketComponentCalculate tcc
JOIN vn.addressForPackaging ap
WHERE ap.addressFk = vAddressFk;
END IF;
DROP TEMPORARY TABLE IF EXISTS tmp.ticketComponentCopy;
CREATE TEMPORARY TABLE tmp.ticketComponentCopy ENGINE = MEMORY
SELECT * FROM tmp.ticketComponent;
INSERT INTO tmp.ticketComponent
SELECT tcc.warehouseFk,
tcc.itemFk,
vSpecialPriceComponent,
sp.value - SUM(tcc.cost) sumCost
FROM tmp.ticketComponentCopy tcc
JOIN component c ON c.id = tcc.componentFk
JOIN specialPrice sp ON sp.clientFk = vClientFK AND sp.itemFk = tcc.itemFk
WHERE c.classRate IS NULL
GROUP BY tcc.itemFk, tcc.warehouseFk
HAVING ABS(sumCost) > 0.001;
DROP TEMPORARY TABLE IF EXISTS tmp.ticketComponentSum;
CREATE TEMPORARY TABLE tmp.ticketComponentSum
(INDEX (itemFk, warehouseFk))
ENGINE = MEMORY
SELECT SUM(cost) sumCost, tc.itemFk, tc.warehouseFk, c.classRate
FROM tmp.ticketComponent tc
JOIN component c ON c.id = tc.componentFk
GROUP BY tc.itemFk, tc.warehouseFk, c.classRate;
DROP TEMPORARY TABLE IF EXISTS tmp.ticketComponentRate;
CREATE TEMPORARY TABLE tmp.ticketComponentRate ENGINE = MEMORY
SELECT tcc.warehouseFk,
tcc.itemFk,
1 rate,
IF(tcc.groupingMode = 1, tcc.`grouping`, 1) `grouping`,
CAST(SUM(tcs.sumCost) AS DECIMAL(10,2)) price,
CAST(SUM(tcs.sumCost) AS DECIMAL(10,2)) / weightGrouping priceKg
FROM tmp.ticketComponentCalculate tcc
JOIN tmp.ticketComponentSum tcs ON tcs.itemFk = tcc.itemFk
AND tcs.warehouseFk = tcc.warehouseFk
WHERE IFNULL(tcs.classRate, 1) = 1
AND tcc.groupingMode < 2 AND (tcc.packing > tcc.`grouping` or tcc.groupingMode = 0)
GROUP BY tcs.warehouseFk, tcs.itemFk;
INSERT INTO tmp.ticketComponentRate (warehouseFk, itemFk, rate, `grouping`, price, priceKg)
SELECT
tcc.warehouseFk,
tcc.itemFk,
2 rate,
tcc.packing `grouping`,
SUM(tcs.sumCost) price,
SUM(tcs.sumCost) / weightGrouping priceKg
FROM tmp.ticketComponentCalculate tcc
JOIN tmp.ticketComponentSum tcs ON tcs.itemFk = tcc.itemFk
AND tcs.warehouseFk = tcc.warehouseFk
WHERE tcc.available IS NULL OR (IFNULL(tcs.classRate, 2) = 2
AND tcc.packing > 0 AND tcc.available >= tcc.packing)
GROUP BY tcs.warehouseFk, tcs.itemFk;
INSERT INTO tmp.ticketComponentRate (warehouseFk, itemFk, rate, `grouping`, price, priceKg)
SELECT
tcc.warehouseFk,
tcc.itemFk,
3 rate,
tcc.available `grouping`,
SUM(tcs.sumCost) price,
SUM(tcs.sumCost) / weightGrouping priceKg
FROM tmp.ticketComponentCalculate tcc
JOIN tmp.ticketComponentSum tcs ON tcs.itemFk = tcc.itemFk
AND tcs.warehouseFk = tcc.warehouseFk
WHERE IFNULL(tcs.classRate, 3) = 3
GROUP BY tcs.warehouseFk, tcs.itemFk;
INSERT INTO tmp.ticketComponentPrice (warehouseFk, itemFk, rate, `grouping`, price, priceKg)
SELECT * FROM (
SELECT * FROM tmp.ticketComponentRate ORDER BY price
) t
GROUP BY itemFk, warehouseFk, `grouping`;
DROP TEMPORARY TABLE
tmp.ticketComponentCalculate,
tmp.ticketComponentSum,
tmp.ticketComponentBase,
tmp.ticketComponentRate,
tmp.ticketComponentCopy;
END$$
DELIMITER ;

View File

@ -0,0 +1,33 @@
USE `vn`;
DROP procedure IF EXISTS `catalog_componentPrepare`;
DELIMITER $$
USE `vn`$$
CREATE PROCEDURE `catalog_componentPrepare` ()
BEGIN
DROP TEMPORARY TABLE IF EXISTS tmp.ticketComponent;
CREATE TEMPORARY TABLE tmp.ticketComponent (
`warehouseFk` INT UNSIGNED NOT NULL,
`itemFk` INT NOT NULL,
`componentFk` INT UNSIGNED NOT NULL,
`cost` DECIMAL(10,4) NOT NULL,
INDEX `itemWarehouse` USING BTREE (`itemFk` ASC, `warehouseFk` ASC),
UNIQUE `fkItemWarehouseComponent` (`itemFk` ASC, `warehouseFk` ASC, `componentFk` ASC)
)ENGINE=MEMORY DEFAULT CHARSET=utf8;
DROP TEMPORARY TABLE IF EXISTS tmp.ticketComponentPrice;
CREATE TEMPORARY TABLE tmp.ticketComponentPrice (
`warehouseFk` INT UNSIGNED NOT NULL,
`itemFk` INT NOT NULL,
`rate` INT NOT NULL,
`grouping` INT UNSIGNED NOT NULL,
`price` DECIMAL(10,4) NOT NULL,
`priceKg` DECIMAL(10,4),
INDEX `itemWarehouse` USING BTREE (`itemFk` ASC, `warehouseFk` ASC),
UNIQUE `fkItemWarehouseRate` (`itemFk` ASC, `warehouseFk` ASC, `rate` ASC)
)ENGINE=MEMORY DEFAULT CHARSET=utf8;
END$$
DELIMITER ;

View File

@ -0,0 +1,16 @@
USE `vn`;
DROP procedure IF EXISTS `vn`.`catalog_componentPurge`;
DELIMITER $$
USE `vn`$$
CREATE DEFINER=`root`@`%` PROCEDURE `catalog_componentPurge`()
BEGIN
DROP TEMPORARY TABLE
tmp.ticketComponentPrice,
tmp.ticketComponent,
tmp.ticketLot;
END$$
DELIMITER ;
;

View File

@ -0,0 +1,250 @@
USE `hedera`;
DROP procedure IF EXISTS `order_confirmWithUser`;
DELIMITER $$
USE `hedera`$$
CREATE DEFINER=`root`@`%` PROCEDURE `order_confirmWithUser`(IN `vOrder` INT, IN `vUserId` INT)
BEGIN
/**
* Confirms an order, creating each of its tickets on the corresponding
* date, store and user.
*
* @param vOrder The order identifier
* @param vUser The user identifier
*/
DECLARE vOk BOOL;
DECLARE vDone BOOL DEFAULT FALSE;
DECLARE vWarehouse INT;
DECLARE vShipment DATETIME;
DECLARE vTicket INT;
DECLARE vNotes VARCHAR(255);
DECLARE vItem INT;
DECLARE vConcept VARCHAR(30);
DECLARE vAmount INT;
DECLARE vPrice DECIMAL(10,2);
DECLARE vSale INT;
DECLARE vRate INT;
DECLARE vRowId INT;
DECLARE vDelivery DATE;
DECLARE vAddress INT;
DECLARE vIsConfirmed BOOL;
DECLARE vClientId INT;
DECLARE vCompanyId INT;
DECLARE vAgencyModeId INT;
DECLARE TICKET_FREE INT DEFAULT 2;
DECLARE cDates CURSOR FOR
SELECT zgs.shipped, r.warehouse_id
FROM `order` o
JOIN order_row r ON r.order_id = o.id
LEFT JOIN tmp.zoneGetShipped zgs ON zgs.warehouseFk = r.warehouse_id
WHERE o.id = vOrder AND r.amount != 0
GROUP BY r.warehouse_id;
DECLARE cRows CURSOR FOR
SELECT r.id, r.item_id, i.name, r.amount, r.price, r.rate
FROM order_row r
JOIN vn.item i ON i.id = r.item_id
WHERE r.amount != 0
AND r.warehouse_id = vWarehouse
AND r.order_id = vOrder
ORDER BY r.rate DESC;
DECLARE CONTINUE HANDLER FOR NOT FOUND
SET vDone = TRUE;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
RESIGNAL;
END;
-- Carga los datos del pedido
SELECT o.date_send, o.address_id, o.note,
o.confirmed, a.clientFk, o.company_id, o.agency_id
INTO vDelivery, vAddress, vNotes,
vIsConfirmed, vClientId, vCompanyId, vAgencyModeId
FROM hedera.`order` o
JOIN vn.address a ON a.id = o.address_id
WHERE o.id = vOrder;
-- Comprueba que el pedido no está confirmado
IF vIsConfirmed THEN
CALL util.throw ('ORDER_ALREADY_CONFIRMED');
END IF;
-- Comprueba que el pedido no está vacío
SELECT COUNT(*) > 0 INTO vOk
FROM order_row WHERE order_id = vOrder AND amount > 0;
IF NOT vOk THEN
CALL util.throw ('ORDER_EMPTY');
END IF;
-- Carga las fechas de salida de cada almacén
CALL vn.zone_getShipped (vDelivery, vAddress, vAgencyModeId, FALSE);
-- Trabajador que realiza la acción
IF vUserId IS NULL THEN
SELECT employeeFk INTO vUserId FROM orderConfig;
END IF;
-- Crea los tickets del pedido
START TRANSACTION;
OPEN cDates;
lDates:
LOOP
SET vTicket = NULL;
SET vDone = FALSE;
FETCH cDates INTO vShipment, vWarehouse;
IF vDone THEN
LEAVE lDates;
END IF;
-- Busca un ticket existente que coincida con los parametros
SELECT t.id INTO vTicket
FROM vn.ticket t
LEFT JOIN vn.ticketState tls on tls.ticket = t.id
JOIN `order` o
ON o.address_id = t.addressFk
AND vWarehouse = t.warehouseFk
AND o.agency_id = t.agencyModeFk
AND o.date_send = t.landed
AND vShipment = DATE(t.shipped)
WHERE o.id = vOrder
AND t.invoiceOutFk IS NULL
AND IFNULL(tls.alertLevel,0) = 0
AND t.clientFk <> 1118
LIMIT 1;
-- Crea el ticket en el caso de no existir uno adecuado
IF vTicket IS NULL
THEN
CALL vn.ticketCreateWithUser(
vClientId,
IFNULL(vShipment, CURDATE()),
vWarehouse,
vCompanyId,
vAddress,
vAgencyModeId,
NULL,
vDelivery,
vUserId,
vTicket
);
ELSE
INSERT INTO vncontrol.inter
SET Id_Ticket = vTicket,
Id_Trabajador = vUserId,
state_id = TICKET_FREE;
END IF;
INSERT IGNORE INTO vn.orderTicket
SET orderFk = vOrder,
ticketFk = vTicket;
-- Añade las notas
IF vNotes IS NOT NULL AND vNotes != ''
THEN
INSERT INTO vn.ticketObservation SET
ticketFk = vTicket,
observationTypeFk = 4 /* salesperson */ ,
`description` = vNotes
ON DUPLICATE KEY UPDATE
`description` = CONCAT(VALUES(`description`),'. ', `description`);
END IF;
-- Añade los movimientos y sus componentes
OPEN cRows;
lRows:
LOOP
SET vDone = FALSE;
FETCH cRows INTO vRowId, vItem, vConcept, vAmount, vPrice, vRate;
IF vDone THEN
LEAVE lRows;
END IF;
SET vSale = NULL;
SELECT s.id INTO vSale
FROM vn.sale s
WHERE ticketFk = vTicket
AND price = vPrice
AND itemFk = vItem
LIMIT 1;
IF vSale THEN
UPDATE vn.sale
SET quantity = quantity + vAmount
WHERE id = vSale;
ELSE
INSERT INTO vn.sale
SET
itemFk = vItem,
ticketFk = vTicket,
concept = vConcept,
quantity = vAmount,
price = vPrice,
priceFixed = 0,
isPriceFixed = TRUE;
SET vSale = LAST_INSERT_ID();
INSERT INTO vn.saleComponent
(saleFk, componentFk, `value`)
SELECT vSale, cm.component_id, cm.price
FROM order_component cm
JOIN vn.component c ON c.id = cm.component_id
WHERE cm.order_row_id = vRowId
GROUP BY vSale, cm.component_id;
END IF;
UPDATE order_row SET Id_Movimiento = vSale
WHERE id = vRowId;
END LOOP;
CLOSE cRows;
-- Fija el coste
DROP TEMPORARY TABLE IF EXISTS tComponents;
CREATE TEMPORARY TABLE tComponents
(INDEX (saleFk))
ENGINE = MEMORY
SELECT SUM(sc.`value`) valueSum, sc.saleFk
FROM vn.saleComponent sc
JOIN vn.component c ON c.id = sc.componentFk
JOIN vn.componentType ct ON ct.id = c.typeFk AND ct.isBase
JOIN vn.sale s ON s.id = sc.saleFk
WHERE s.ticketFk = vTicket
GROUP BY sc.saleFk;
UPDATE vn.sale s
JOIN tComponents mc ON mc.saleFk = s.id
SET s.priceFixed = valueSum;
DROP TEMPORARY TABLE tComponents;
END LOOP;
CLOSE cDates;
DELETE FROM basketOrder WHERE orderFk = vOrder;
UPDATE `order` SET confirmed = TRUE, confirm_date = NOW()
WHERE id = vOrder;
COMMIT;
END$$
DELIMITER ;

View File

@ -0,0 +1,103 @@
USE `vn`;
DROP procedure IF EXISTS `sale_calculateComponent`;
DELIMITER $$
USE `vn`$$
CREATE DEFINER=`root`@`%` PROCEDURE `sale_calculateComponent`(vSale INT, vOption INT)
proc: BEGIN
/**
* Actualiza los componentes
*
* @param vSale Delivery date
* @param vOption indica en que componente pone el descuadre, NULL en casos habituales
*/
DECLARE vShipped DATE;
DECLARE vWarehouseFk SMALLINT;
DECLARE vAgencyModeFk INT;
DECLARE vAddressFk INT;
DECLARE vTicketFk BIGINT;
DECLARE vItemFk BIGINT;
DECLARE vLanded DATE;
DECLARE vIsEditable BOOLEAN;
DECLARE vZoneFk INTEGER;
SELECT t.refFk IS NULL AND (IFNULL(ts.alertLevel, 0) = 0 OR s.price = 0),
s.ticketFk,
s.itemFk ,
t.zoneFk,
t.warehouseFk,
t.shipped,
t.addressFk,
t.agencyModeFk,
t.landed
INTO vIsEditable,
vTicketFk,
vItemFk,
vZoneFk,
vWarehouseFk,
vShipped,
vAddressFk,
vAgencyModeFk,
vLanded
FROM ticket t
JOIN sale s ON s.ticketFk = t.id
LEFT JOIN ticketState ts ON ts.ticketFk = t.id
WHERE s.id = vSale;
IF vLanded IS NULL OR vZoneFk IS NULL THEN
CALL zone_getLanded(vShipped, vAddressFk, vAgencyModeFk, vWarehouseFk);
IF (SELECT COUNT(*) FROM tmp.zoneGetLanded LIMIT 1) = 0 THEN
CALL util.throw('There is no zone for these parameters');
END IF;
UPDATE ticket t
SET t.landed = (SELECT landed FROM tmp.zoneGetLanded LIMIT 1)
WHERE t.id = vTicketFk AND t.landed IS NULL;
IF vZoneFk IS NULL THEN
SELECT zoneFk INTO vZoneFk FROM tmp.zoneGetLanded LIMIT 1;
UPDATE ticket t
SET t.zoneFk = vZoneFk
WHERE t.id = vTicketFk AND t.zoneFk IS NULL;
END IF;
DROP TEMPORARY TABLE tmp.zoneGetLanded;
END IF;
-- rellena la tabla buyUltimate con la ultima compra
CALL buyUltimate (vWarehouseFk, vShipped);
DELETE FROM tmp.buyUltimate WHERE itemFk != vItemFk;
DROP TEMPORARY TABLE IF EXISTS tmp.ticketLot;
CREATE TEMPORARY TABLE tmp.ticketLot
SELECT vWarehouseFk warehouseFk, NULL available, vItemFk itemFk, buyFk, vZoneFk zoneFk
FROM tmp.buyUltimate
WHERE itemFk = vItemFk;
CALL catalog_componentPrepare();
CALL catalog_componentCalculate(vZoneFk, vAddressFk, vShipped, vWarehouseFk);
DROP TEMPORARY TABLE IF EXISTS tmp.sale;
CREATE TEMPORARY TABLE tmp.sale
(PRIMARY KEY (saleFk)) ENGINE = MEMORY
SELECT vSale saleFk,vWarehouseFk warehouseFk;
IF vOption IS NULL THEN
SET vOption = IF(vIsEditable, 1, 6);
END IF;
CALL ticketComponentUpdateSale(vOption);
INSERT INTO ticketLog (originFk, userFk, `action`, description)
VALUES (vTicketFk, account.userGetId(), 'update', CONCAT('Bionizo linea id ', vSale));
CALL catalog_componentPurge();
DROP TEMPORARY TABLE tmp.buyUltimate;
DROP TEMPORARY TABLE tmp.sale;
END$$
DELIMITER ;

View File

@ -0,0 +1,93 @@
USE `vn`;
DROP procedure IF EXISTS `ticketCalculateClon`;
DELIMITER $$
USE `vn`$$
CREATE DEFINER=`root`@`%` PROCEDURE `ticketCalculateClon`(IN vTicketNew INT, vTicketOld INT)
BEGIN
/*
* Recalcula los componentes un ticket clonado,
* las lineas a precio cero fuerza para que tengan precio, el resto lo respeta
* @param vTicketNew nuevo ticket clonado
* @param vTicketOld icket original, a partir del qual se clonara el nuevo
*/
DECLARE vShipped DATE;
DECLARE vClient INT;
DECLARE vWarehouse SMALLINT;
DECLARE vAgencyMode INT;
DECLARE vAddress INT;
DECLARE vLanded DATE;
DECLARE vAgency INT;
DECLARE vZoneFk INT;
REPLACE INTO orderTicket(orderFk,ticketFk)
SELECT orderFk, vTicketNew
FROM orderTicket
WHERE ticketFk = vTicketOld;
SELECT t.clientFk, t.warehouseFk, date(t.shipped), t.addressFk, t.agencyModeFk, t.landed, a.agencyFk, t.zoneFk
INTO vClient, vWarehouse, vShipped, vAddress, vAgencyMode, vLanded, vAgency, vZoneFk
FROM agencyMode a
JOIN ticket t ON t.agencyModeFk = a.id
WHERE t.id = vTicketNew;
IF vLanded IS NULL THEN
CALL zone_getLanded(vShipped, vAddress, vAgency, vWarehouse);
UPDATE ticket t
JOIN tmp.zoneGetLanded zgl ON t.warehouseFk = zgl.warehouseFk
SET t.landed = zgl.landed,
t.zone = zgl.zoneFk
WHERE t.id = vTicketNew;
SELECT zoneFk INTO vZoneFk FROM tmp.zoneGetLanded LIMIT 1;
DROP TEMPORARY TABLE IF EXISTS tmp.zoneGetLanded;
END IF;
-- rellena la tabla tmp.buyUltimate con la ultima compra
CALL buyUltimate(vWarehouse, vShipped);
DROP TEMPORARY TABLE IF EXISTS tmp.ticketLot;
CREATE TEMPORARY TABLE tmp.ticketLot
SELECT vWarehouse warehouseFk, NULL available, s.itemFk, bu.buyFk, vZoneFk zoneFk
FROM sale s
LEFT JOIN tmp.buyUltimate bu ON bu.itemFk = s.itemFk
WHERE s.ticketFk = vTicketOld GROUP BY s.itemFk;
CALL catalog_componentPrepare();
CALL catalog_componentCalculate(vZoneFk, vAddress, vAgencyMode, vWarehouse);
-- Bionizamos lineas con Preu = 0
DROP TEMPORARY TABLE IF EXISTS tmp.sale;
CREATE TEMPORARY TABLE tmp.sale
(PRIMARY KEY (saleFk)) ENGINE = MEMORY
SELECT s.id saleFk, vWarehouse warehouseFk
FROM sale s
JOIN ticket t on t.id = s.ticketFk WHERE s.ticketFk = vTicketNew AND s.price = 0;
CALL ticketComponentUpdateSale(1);
-- Bionizamos lineas con Preu > 0
DROP TEMPORARY TABLE IF EXISTS tmp.sale;
CREATE TEMPORARY TABLE tmp.sale
(PRIMARY KEY (saleFk)) ENGINE = MEMORY
SELECT s.id saleFk, vWarehouse warehouseFk
FROM sale s
JOIN ticket t on t.id = s.ticketFk WHERE s.ticketFk = vTicketNew
AND s.price > 0;
CALL ticketComponentUpdateSale(6);
-- Log
CALL `logAdd`(vTicketNew, 'update', ' ticket' , 'Bioniza Ticket');
-- Limpieza
CALL catalog_componentPurge();
DROP TEMPORARY TABLE IF EXISTS
tmp.buyUltimate,
tmp.sale,
tmp.zoneGetLanded;
END$$
DELIMITER ;

View File

@ -0,0 +1,61 @@
USE `vn`;
DROP procedure IF EXISTS `ticketCalculateSaleForcePrice`;
DELIMITER $$
USE `vn`$$
CREATE DEFINER=`root`@`%` PROCEDURE `ticketCalculateSaleForcePrice`(IN vSale BIGINT)
proc: BEGIN
DECLARE vShipped DATE;
DECLARE vWarehouseFk SMALLINT;
DECLARE vAddressFk INT;
DECLARE vTicket BIGINT;
DECLARE vItem BIGINT;
DECLARE vZoneFk INT;
SELECT ticketFk, itemFk
INTO vTicket, vItem
FROM sale
WHERE id = vSale;
SELECT t.warehouseFk, DATE(t.shipped), t.addressFk, t.zoneFk
INTO vWarehouseFk, vShipped, vAddressFk, vZoneFk
FROM agencyMode a
JOIN ticket t ON t.agencyModeFk = a.id
WHERE t.id = vTicket;
IF vZoneFk IS NULL THEN
CALL util.throw('ticket without zone');
END IF;
CALL buyUltimate (vWarehouseFk, vShipped);
DELETE FROM tmp.buyUltimate WHERE itemFk != vItem;
DROP TEMPORARY TABLE IF EXISTS tmp.ticketLot;
CREATE TEMPORARY TABLE tmp.ticketLot
SELECT vWarehouseFk warehouseFk, NULL available, vItem itemFk, buyFk, vZoneFk zoneFk
FROM tmp.buyUltimate
WHERE itemFk = vItem;
CALL catalog_componentPrepare();
CALL catalog_componentCalculate(vZoneFk, vAddressFk, vShipped, vWarehouseFk);
DROP TEMPORARY TABLE IF EXISTS tmp.sale;
CREATE TEMPORARY TABLE tmp.sale
(PRIMARY KEY (saleFk)) ENGINE = MEMORY
SELECT vSale saleFk,vWarehouseFk warehouseFk;
CALL ticketComponentUpdateSale(1);
INSERT INTO vn.ticketLog (originFk, userFk, `action`, description)
VALUES (vTicket, account.userGetId(), 'update', CONCAT('Bionizo linea id ', vSale));
CALL catalog_componentPurge();
DROP TEMPORARY TABLE tmp.buyUltimate;
DROP TEMPORARY TABLE tmp.sale;
END$$
DELIMITER ;

View File

@ -0,0 +1,154 @@
USE `vn`;
DROP procedure IF EXISTS `ticketComponentUpdateSale`;
DELIMITER $$
USE `vn`$$
CREATE DEFINER=`root`@`%` PROCEDURE `ticketComponentUpdateSale`(vOption INT)
BEGIN
/**
* A partir de la tabla tmp.sale, crea los Movimientos_componentes
* y modifica el campo Preu de la tabla Movimientos
*
* @param i_option integer tipo de actualizacion
* @param table tmp.sale tabla memory con el campo saleFk, warehouseFk
**/
DECLARE vComponentFk INT;
DECLARE vRenewComponents BOOLEAN;
DECLARE vKeepPrices BOOLEAN;
CASE vOption
WHEN 1 THEN
SET vRenewComponents = TRUE;
SET vKeepPrices = FALSE;
WHEN 2 THEN
SELECT id INTO vComponentFk FROM component WHERE `code` = 'debtCollection';
SET vRenewComponents = TRUE;
SET vKeepPrices = TRUE;
WHEN 3 THEN
SELECT id INTO vComponentFk FROM component WHERE `code` = 'mana';
SET vRenewComponents = TRUE;
SET vKeepPrices = TRUE;
WHEN 4 THEN
SELECT id INTO vComponentFk FROM component WHERE `code` = 'buyerDiscount';
SET vRenewComponents = TRUE;
SET vKeepPrices = TRUE;
/* WHEN 5 THEN
SET vComponentFk = 35;
SET vRenewComponents = TRUE;
SET vKeepPrices = TRUE;*/
WHEN 6 THEN
SELECT id INTO vComponentFk FROM component WHERE `code` = 'imbalance';
SET vRenewComponents = TRUE;
SET vKeepPrices = TRUE;
WHEN 7 THEN
REPLACE INTO saleComponent(saleFk, componentFk, value)
SELECT s.id, 28, ROUND(((s.price * (100 - s.discount) / 100) - SUM(IFNULL(sc.value, 0))) * 0.8, 3)
FROM sale s
JOIN tmp.sale tmps ON tmps.saleFk = s.id
LEFT JOIN saleComponent sc ON sc.saleFk = s.id
AND sc.componentFk NOT IN (28, 29)
GROUP BY s.id;
REPLACE INTO saleComponent(saleFk, componentFk, value)
SELECT s.id, 29, ROUND(((s.price * (100 - s.discount) / 100) - SUM(IFNULL(sc.value, 0))) * 0.2, 3)
FROM sale s
JOIN tmp.sale tmps ON tmps.saleFk = s.id
LEFT JOIN saleComponent sc ON sc.saleFk = s.id
AND sc.componentFk NOT IN (28, 29)
GROUP BY s.id;
SET vRenewComponents = FALSE;
SET vKeepPrices = FALSE;
WHEN 8 THEN
DELETE sc.*
FROM tmp.sale tmps JOIN saleComponent sc ON sc.saleFk = tmps.saleFk;
REPLACE INTO saleComponent(saleFk, componentFk, value)
SELECT s.id, 28, ROUND(((s.price * (100 - s.discount) / 100)), 3)
FROM sale s
JOIN tmp.sale tmps ON tmps.saleFk = s.id;
SET vRenewComponents = FALSE;
SET vKeepPrices = FALSE;
WHEN 9 THEN
SET vRenewComponents = TRUE;
SET vKeepPrices = TRUE;
END CASE;
IF vRenewComponents THEN
DELETE sc.*
FROM tmp.sale tmps
JOIN saleComponent sc ON sc.saleFk = tmps.saleFk
JOIN `component` c ON c.id = sc.componentFk
WHERE c.isRenewable;
REPLACE INTO saleComponent(saleFk, componentFk, value)
SELECT s.id, tc.componentFk, tc.cost
FROM sale s
JOIN tmp.sale tmps ON tmps.saleFk = s.id
JOIN tmp.ticketComponent tc ON tc.itemFk = s.itemFk AND tc.warehouseFk = tmps.warehouseFk
LEFT JOIN saleComponent sc ON sc.saleFk = s.id
AND sc.componentFk = tc.componentFk
LEFT JOIN `component` c ON c.id = tc.componentFk
WHERE IF(sc.componentFk IS NULL AND NOT c.isRenewable, FALSE, TRUE);
END IF;
IF vKeepPrices THEN
REPLACE INTO saleComponent(saleFk, componentFk, value)
SELECT s.id, vComponentFk, ROUND((s.price * (100 - s.discount) / 100) - SUM(sc.value), 3) dif
FROM sale s
JOIN tmp.sale tmps ON tmps.saleFk = s.id
LEFT JOIN saleComponent sc ON sc.saleFk = s.id
WHERE sc.saleFk <> vComponentFk
GROUP BY s.id
HAVING dif <> 0;
ELSE
UPDATE sale s
JOIN item i on i.id = s.itemFk
JOIN itemType it on it.id = i.typeFk
JOIN (SELECT SUM(sc.value) sumValue, sc.saleFk
FROM saleComponent sc
JOIN tmp.sale tmps ON tmps.saleFk = sc.saleFk
GROUP BY sc.saleFk) sc ON sc.saleFk = s.id
SET s.price = sumValue
WHERE it.code != 'PRT' ;
REPLACE INTO saleComponent(saleFk, componentFk, value)
SELECT s.id, 21, ROUND((s.price * (100 - s.discount) / 100) - SUM(value), 3) saleValue
FROM sale s
JOIN tmp.sale tmps ON tmps.saleFk = s.id
LEFT JOIN saleComponent sc ON sc.saleFk = s.id
WHERE sc.componentFk != 21
GROUP BY s.id
HAVING ROUND(saleValue, 4) <> 0;
END IF;
UPDATE sale s
JOIN (
SELECT SUM(sc.value) sumValue, sc.saleFk
FROM saleComponent sc
JOIN tmp.sale tmps ON tmps.saleFk = sc.saleFk
JOIN `component` c ON c.id = sc.componentFk
JOIN componentType ct on ct.id = c.typeFk AND ct.isBase
GROUP BY sc.saleFk) sc ON sc.saleFk = s.id
SET s.priceFixed = sumValue, s.isPriceFixed = 1;
DELETE sc.*
FROM saleComponent sc
JOIN tmp.sale tmps ON tmps.saleFk = sc.saleFk
JOIN sale s on s.id = sc.saleFk
JOIN item i ON i.id = s.itemFk
JOIN itemType it ON it.id = i.typeFk
WHERE it.code = 'PRT';
INSERT INTO saleComponent(saleFk, componentFk, value)
SELECT s.id, 15, s.price
FROM sale s
JOIN tmp.sale tmps ON tmps.saleFk = s.id
JOIN item i ON i.id = s.itemFK
JOIN itemType it ON it.id = i.typeFk
WHERE it.code = 'PRT' AND s.price > 0;
END$$
DELIMITER ;

View File

@ -0,0 +1,107 @@
USE `vn`;
DROP procedure IF EXISTS `ticket_componentMakeUpdate`;
DELIMITER $$
USE `vn`$$
CREATE DEFINER=`root`@`%` PROCEDURE `ticket_componentMakeUpdate`(
vTicketFk INT,
vClientFk INT,
vAgencyModeFk INT,
vAddressFk INT,
vZoneFk INT,
vWarehouseFk TINYINT,
vCompanyFk SMALLINT,
vShipped DATETIME,
vLanded DATE,
vIsDeleted BOOLEAN,
vHasToBeUnrouted BOOLEAN,
vOption INT)
BEGIN
/**
* Modifica en el ticket los campos que se le pasan por parámetro
* y cambia sus componentes
*
* @param vTicketFk Id del ticket a modificar
* @param vClientFk nuevo cliente
* @param vAgencyModeFk nueva agencia
* @param vAddressFk nuevo consignatario
* @param vZoneFk nueva zona
* @param vWarehouseFk nuevo almacen
* @param vCompanyFk nueva empresa
* @param vShipped nueva fecha del envio de mercancia
* @param vLanded nueva fecha de recepcion de mercancia
* @param vIsDeleted si se borra el ticket
* @param vHasToBeUnrouted si se le elimina la ruta al ticket
* @param vOption opcion para el case del proc ticketComponentUpdateSale
*/
DECLARE vPrice DECIMAL(10,2);
DECLARE vBonus DECIMAL(10,2);
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
RESIGNAL;
END;
CALL ticket_componentPreview (vTicketFk, vLanded, vAddressFk, vZoneFk, vWarehouseFk);
START TRANSACTION;
IF (SELECT addressFk FROM ticket WHERE id = vTicketFk) <> vAddressFk THEN
UPDATE ticket t
JOIN address a ON a.id = vAddressFk
SET t.nickname = a.nickname
WHERE t.id = vTicketFk;
END IF;
CALL zone_getShippedWarehouse(vlanded, vAddressFk, vAgencyModeFk);
SELECT zoneFk, price, bonus INTO vZoneFk, vPrice, vBonus
FROM tmp.zoneGetShipped
WHERE shipped = vShipped AND warehouseFk = vWarehouseFk LIMIT 1;
UPDATE ticket t
SET
t.clientFk = vClientFk,
t.agencyModeFk = vAgencyModeFk,
t.addressFk = vAddressFk,
t.zoneFk = vZoneFk,
t.zonePrice = vPrice,
t.zoneBonus = vBonus,
t.warehouseFk = vWarehouseFk,
t.companyFk = vCompanyFk,
t.landed = vLanded,
t.shipped = vShipped,
t.isDeleted = vIsDeleted
WHERE
t.id = vTicketFk;
IF vHasToBeUnrouted THEN
UPDATE ticket t SET t.routeFk = NULL
WHERE t.id = vTicketFk;
END IF;
IF vOption <> 8 THEN
DROP TEMPORARY TABLE IF EXISTS tmp.sale;
CREATE TEMPORARY TABLE tmp.sale
(PRIMARY KEY (saleFk))
ENGINE = MEMORY
SELECT id AS saleFk, vWarehouseFk warehouseFk
FROM sale s WHERE s.ticketFk = vTicketFk;
DROP TEMPORARY TABLE IF EXISTS tmp.ticketComponent;
CREATE TEMPORARY TABLE tmp.ticketComponent
SELECT * FROM tmp.ticketComponentPreview;
CALL ticketComponentUpdateSale (vOption);
DROP TEMPORARY TABLE tmp.sale;
DROP TEMPORARY TABLE IF EXISTS tmp.ticketComponent;
END IF;
COMMIT;
DROP TEMPORARY TABLE tmp.zoneGetShipped, tmp.ticketComponentPreview;
END$$
DELIMITER ;

View File

@ -0,0 +1,111 @@
USE `vn`;
DROP procedure IF EXISTS `ticket_componentPreview`;
DELIMITER $$
USE `vn`$$
CREATE DEFINER=`root`@`%` PROCEDURE `ticket_componentPreview`(
vTicketFk INT,
vLanded DATE,
vAddressFk INT,
vZoneFk INT,
vWarehouseFk SMALLINT)
BEGIN
/**
* Calcula los componentes de los articulos de un ticket
*
* @param vTicketFk id del ticket
* @param vLanded nueva fecha de entrega
* @param vAddressFk nuevo consignatario
* @param vZoneFk nueva zona
* @param vWarehouseFk nuevo warehouse
*
* @return tmp.ticketComponentPreview (warehouseFk, itemFk, componentFk, cost)
*/
DECLARE vHasDataChanged BOOL DEFAULT FALSE;
DECLARE vHasAddressChanged BOOL;
DECLARE vHasZoneChanged BOOL DEFAULT FALSE;
DECLARE vHasWarehouseChanged BOOL DEFAULT FALSE;
DECLARE vShipped DATE;
DECLARE vAddressTypeRateFk INT DEFAULT NULL;
DECLARE vAgencyModeTypeRateFk INT DEFAULT NULL;
DECLARE vHasChangeAll BOOL DEFAULT FALSE;
SELECT DATE(landed) <> vLanded,
addressFk <> vAddressFk,
zoneFk <> vZoneFk,
warehouseFk <> vWarehouseFk
INTO
vHasDataChanged,
vHasAddressChanged,
vHasZoneChanged,
vHasWarehouseChanged
FROM vn.ticket t
WHERE t.id = vTicketFk;
IF vHasDataChanged OR vHasWarehouseChanged THEN
SET vHasChangeAll = TRUE;
END IF;
IF vHasAddressChanged THEN
SET vAddressTypeRateFk = 5;
END IF;
IF vHasZoneChanged THEN
SET vAgencyModeTypeRateFk = 6;
END IF;
SELECT TIMESTAMPADD(DAY, -travelingDays, vLanded) INTO vShipped
FROM zone
WHERE id = vZoneFk;
CALL buyUltimate(vWarehouseFk, vShipped);
DROP TEMPORARY TABLE IF EXISTS tmp.ticketLot;
CREATE TEMPORARY TABLE tmp.ticketLot ENGINE = MEMORY (
SELECT
vWarehouseFk AS warehouseFk,
NULL AS available,
s.itemFk,
bu.buyFk,
vZoneFk zoneFk
FROM sale s
LEFT JOIN tmp.buyUltimate bu ON bu.itemFk = s.itemFk
WHERE s.ticketFk = vTicketFk
GROUP BY bu.warehouseFk, bu.itemFk);
CALL catalog_componentPrepare();
CALL catalog_componentCalculate(vZoneFk, vAddressFk, vShipped, vWarehouseFk);
REPLACE INTO tmp.ticketComponent (warehouseFk, itemFk, componentFk, cost)
SELECT t.warehouseFk, s.itemFk, sc.componentFk, sc.value
FROM saleComponent sc
JOIN sale s ON s.id = sc.saleFk
JOIN ticket t ON t.id = s.ticketFk
JOIN `component` c ON c.id = sc.componentFk
WHERE s.ticketFk = vTicketFk
AND (c.isRenewable = FALSE
OR
(NOT vHasChangeAll
AND (NOT (c.typeFk <=> vAddressTypeRateFk
OR c.typeFk <=> vAgencyModeTypeRateFk))));
DROP TEMPORARY TABLE IF EXISTS tmp.ticketComponentPreview;
CREATE TEMPORARY TABLE tmp.ticketComponentPreview
SELECT * FROM tmp.ticketComponent;
CALL catalog_componentPurge();
DROP TEMPORARY TABLE tmp.buyUltimate;
IF vShipped IS NULL THEN
CALL util.throw('NO_ZONE_AVAILABLE');
END IF;
IF vShipped < CURDATE() THEN
CALL util.throw('ERROR_PAST_SHIPMENT');
END IF;
END$$
DELIMITER ;

View File

@ -0,0 +1,50 @@
USE `vn`;
DROP procedure IF EXISTS `ticket_priceDifference`;
DELIMITER $$
USE `vn`$$
CREATE DEFINER=`root`@`%` PROCEDURE `ticket_priceDifference`(
vTicketFk INT,
vLanded DATE,
vAddressFk INT,
vZoneFk INT,
vWarehouseFk INT)
BEGIN
/**
* Devuelve las diferencias de precio de los movimientos de un ticket.
*
* @param vTicketFk Id del ticket
* @param vLanded Fecha de recepcion
* @param vAddressFk Id del consignatario
* @param vZoneFk Id de la zona
* @param vWarehouseFk Id del almacén
*/
CALL vn.ticket_componentPreview(vTicketFk, vLanded, vAddressFk, vZoneFk, vWarehouseFk);
SELECT s.itemFk,
i.name,
i.size,
i.category,
IFNULL(s.quantity, 0) AS quantity,
IFNULL(s.price, 0) AS price,
ROUND(SUM(tc.cost), 2) AS newPrice,
s.quantity * (s.price - ROUND(SUM(tc.cost), 2)) difference,
s.id AS saleFk
FROM sale s
JOIN item i ON i.id = s.itemFk
JOIN ticket t ON t.id = s.ticketFk
LEFT JOIN tmp.ticketComponentPreview tc ON tc.itemFk = s.itemFk
AND tc.warehouseFk = t.warehouseFk
LEFT JOIN saleComponent sc ON sc.saleFk = s.id
AND sc.componentFk = tc.componentFk
LEFT JOIN `component` c ON c.id = tc.componentFk
WHERE t.id = vTicketFk
AND IF(sc.componentFk IS NULL
AND c.classRate IS NOT NULL, FALSE, TRUE)
GROUP BY s.id ORDER BY s.id;
DROP TEMPORARY TABLE tmp.ticketComponentPreview;
END$$
DELIMITER ;

View File

@ -0,0 +1,94 @@
USE `vn`;
DROP procedure IF EXISTS `ticket_recalcComponents`;
DELIMITER $$
USE `vn`$$
CREATE DEFINER=`root`@`%` PROCEDURE `ticket_recalcComponents`(IN vTicketFk BIGINT, vIsTicketEditable BOOLEAN)
proc: BEGIN
/**
* Este procedimiento recalcula los componentes de un ticket,
* eliminando los componentes existentes e insertandolos de nuevo
*
* @param vTicketFk Id del ticket
* @param vIsTicketEditable si no se quiere forzar llamar con NULL
*/
DECLARE vShipped DATE;
DECLARE vWarehouseFk SMALLINT;
DECLARE vAgencyModeFk INT;
DECLARE vAddressFk INT;
DECLARE vLanded DATE;
DECLARE vZoneFk INTEGER;
IF vIsTicketEditable IS NULL THEN
SELECT IFNULL(ts.alertLevel,0) = 0 AND IFNULL(t.refFk,'') = ''
INTO vIsTicketEditable
FROM ticket t LEFT JOIN ticketState ts ON t.id = ts.ticket
WHERE id = vTicketFk;
END IF;
SELECT t.warehouseFk,
t.shipped,
t.addressFk,
t.agencyModeFk,
t.landed,
t.zoneFk
INTO vWarehouseFk, vShipped, vAddressFk, vAgencyModeFk, vLanded, vZoneFk
FROM ticket t LEFT JOIN ticketState ts ON t.id = ts.ticket
WHERE t.id = vTicketFk;
IF vLanded IS NULL OR vZoneFk IS NULL THEN
CALL zone_getLanded(vShipped, vAddressFk, vAgencyModeFk, vWarehouseFk);
IF (SELECT COUNT(*) FROM tmp.zoneGetLanded LIMIT 1) = 0 THEN
CALL util.throw('There is no zone for these parameters');
END IF;
UPDATE ticket t
SET t.landed = (SELECT landed FROM tmp.zoneGetLanded LIMIT 1)
WHERE t.id = vTicketFk AND t.landed IS NULL;
IF vZoneFk IS NULL THEN
SELECT zoneFk INTO vZoneFk FROM tmp.zoneGetLanded LIMIT 1;
UPDATE ticket t
SET t.zoneFk = vZoneFk
WHERE t.id = vTicketFk AND t.zoneFk IS NULL;
END IF;
DROP TEMPORARY TABLE tmp.zoneGetLanded;
END IF;
-- rellena la tabla buyUltimate con la ultima compra
CALL buyUltimate (vWarehouseFk, vShipped);
DROP TEMPORARY TABLE IF EXISTS tmp.ticketLot;
CREATE TEMPORARY TABLE tmp.ticketLot
SELECT vWarehouseFk warehouseFk, NULL available,
s.itemFk, bu.buyFk, vZoneFk zoneFk
FROM sale s
LEFT JOIN tmp.buyUltimate bu ON bu.itemFk = s.itemFk
WHERE s.ticketFk = vTicketFk
GROUP BY s.itemFk;
CALL catalog_componentPrepare();
CALL catalog_componentCalculate(vZoneFk, vAddressFk, vShipped, vWarehouseFk);
DROP TEMPORARY TABLE IF EXISTS tmp.sale;
CREATE TEMPORARY TABLE tmp.sale
(PRIMARY KEY (saleFk)) ENGINE = MEMORY
SELECT id saleFk, vWarehouseFk warehouseFk
FROM sale s
WHERE s.ticketFk = vTicketFk;
-- si el ticket esta facturado, respeta los precios
CALL ticketComponentUpdateSale(IF(vIsTicketEditable, 1, 6));
CALL catalog_componentPurge();
DROP TEMPORARY TABLE
tmp.buyUltimate,
tmp.sale;
END$$
DELIMITER ;

View File

@ -0,0 +1,2 @@
USE `vn`;
DROP procedure IF EXISTS `ticket_recalcComponentsForcePrice`;

View File

@ -0,0 +1,72 @@
USE `vn`;
DROP procedure IF EXISTS `ticket_withoutComponents`;
DROP procedure IF EXISTS `ticket_checkNoComponents`;
DELIMITER $$
USE `vn`$$
CREATE DEFINER=`root`@`%` PROCEDURE `ticket_checkNoComponents`(vShippedFrom DATETIME, vShippedTo DATETIME)
BEGIN
/**
* Comprueba que los tickets entre un rango de fechas tienen componentes
*
* @param vDatedFrom Id del ticket
* @param vIsTicketEditable si no se quiere forzar llamar con NULL
*/
DECLARE v_done BOOL DEFAULT FALSE;
DECLARE vSaleFk INTEGER;
DECLARE vCur CURSOR FOR
SELECT s.id
FROM ticket t
JOIN client clt ON clt.id = t.clientFk
JOIN sale s ON s.ticketFk = t.id
JOIN item i ON i.id = s.itemFk
JOIN itemType tp ON tp.id = i.typeFk
JOIN itemCategory ic ON ic.id = tp.categoryFk
LEFT JOIN tmp.coste c ON c.id = s.id
WHERE t.shipped >= vDatedFrom AND t.shipped <= vDatedTo
AND c.id IS NULL
AND clt.isActive != 0
AND ic.merchandise != 0
GROUP BY s.id;
DECLARE CONTINUE HANDLER FOR NOT FOUND
SET v_done = TRUE;
DROP TEMPORARY TABLE IF EXISTS tmp.coste;
DROP TEMPORARY TABLE IF EXISTS tmp.coste;
CREATE TEMPORARY TABLE tmp.coste
(primary key (id)) ENGINE = MEMORY
SELECT s.id
FROM ticket t
JOIN client clt ON clt.id = t.clientFk
JOIN sale s ON s.ticketFk = t.id
JOIN item i ON i.id = s.itemFk
JOIN itemType tp ON tp.id = i.typeFk
JOIN itemCategory ic ON ic.id = tp.categoryFk
JOIN saleComponent sc ON sc.saleFk = s.id
JOIN component c ON c.id = sc.componentFk
JOIN componentType ct ON ct.id = c.typeFk AND ct.id = 1
WHERE t.shipped >= vDatedFrom
AND ic.merchandise != 0;
OPEN vCur;
l: LOOP
SET v_done = FALSE;
FETCH vCur INTO vSaleFk;
IF v_done THEN
LEAVE l;
END IF;
CALL sale_calculateComponent(vSaleFk, 1);
END LOOP;
CLOSE vCur;
DROP TEMPORARY TABLE tmp.coste;
END$$
DELIMITER ;

View File

@ -0,0 +1,156 @@
CREATE DEFINER=`root`@`%` PROCEDURE `ekt_load`(IN `vSelf` INT)
BEGIN
DECLARE vRef INT;
DECLARE vBuy INT;
DECLARE vItem INT;
DECLARE vQty INT;
DECLARE vPackage INT;
DECLARE vIsLot BOOLEAN;
DECLARE vForceToPacking INT DEFAULT 2;
-- Carga los datos necesarios del EKT
SELECT ref, qty, package INTO vRef, vQty, vPackage
FROM ekt e
LEFT JOIN item i ON e.ref = i.id
WHERE e.id = vSelf;
-- Inserta el cubo si no existe
IF vPackage = 800
THEN
SET vPackage = 800 + vQty;
INSERT IGNORE INTO vn2008.Cubos SET
Id_Cubo = vPackage,
x = 7200 / vQty,
y = 1;
ELSE
INSERT IGNORE INTO vn2008.Cubos (Id_Cubo, X, Y, Z)
SELECT bucket_id, ROUND(x_size/10), ROUND(y_size/10), ROUND(z_size/10)
FROM bucket WHERE bucket_id = vPackage;
IF ROW_COUNT() > 0
THEN
INSERT INTO vn2008.mail SET
`subject` = 'Cubo añadido',
`text` = CONCAT('Se ha añadido el cubo: ', vPackage),
`to` = 'ekt@verdnatura.es';
END IF;
END IF;
-- Intenta obtener el artículo en base a los atributos holandeses
INSERT IGNORE INTO item_track SET
item_id = vRef;
SELECT c.Id_Compra, c.Id_Article INTO vBuy, vItem
FROM vn2008.buy_edi e
JOIN item_track t ON t.item_id = e.ref
LEFT JOIN vn2008.buy_edi l ON l.ref = e.ref
LEFT JOIN vn2008.Compres c ON c.buy_edi_id = l.id
JOIN vn2008.config cfg
WHERE e.id = vSelf
AND l.id != vSelf
AND c.Id_Article != cfg.generic_item
AND IF(t.s1, l.s1 = e.s1, TRUE)
AND IF(t.s2, l.s2 = e.s2, TRUE)
AND IF(t.s3, l.s3 = e.s3, TRUE)
AND IF(t.s4, l.s4 = e.s4, TRUE)
AND IF(t.s5, l.s5 = e.s5, TRUE)
AND IF(t.s6, l.s6 = e.s6, TRUE)
AND IF(t.kop, l.kop = e.kop, TRUE)
AND IF(t.pac, l.pac = e.pac, TRUE)
AND IF(t.cat, l.cat = e.cat, TRUE)
AND IF(t.ori, l.ori = e.ori, TRUE)
AND IF(t.pro, l.pro = e.pro, TRUE)
AND IF(t.sub, l.sub = e.sub, TRUE)
AND IF(t.package, l.package = e.package, TRUE)
AND c.Id_Article < 170000
ORDER BY l.now DESC, c.Id_Compra ASC LIMIT 1;
-- Determina si el articulo se vende por lotes
IF vItem
THEN
SELECT COUNT(*) > 0 INTO vIsLot
FROM vn2008.Articles a
LEFT JOIN vn2008.Tipos t ON t.tipo_id = a.tipo_id
WHERE a.Id_Article = vItem
AND t.`transaction`;
-- Si el articulo se vende por lotes se inserta un nuevo artículo
IF vIsLot
THEN
INSERT INTO vn2008.Articles (
Article
,Medida
,Categoria
,Id_Origen
,iva_group_id
,Foto
,Color
,Codintrastat
,tipo_id
,Tallos
)
SELECT
i.`name`
,IFNULL(e.s1, e.pac)
,e.cat
,IFNULL(o.id, 17)
,IFNULL(a.iva_group_id, 1)
,a.Foto
,a.Color
,a.Codintrastat
,IFNULL(a.tipo_id, 10)
,IF(a.tipo_id = 15, 0, 1)
FROM vn2008.buy_edi e
LEFT JOIN item i ON i.id = e.ref
LEFT JOIN vn2008.Origen o ON o.Abreviatura = e.ori
LEFT JOIN vn2008.Articles a ON a.Id_Article = vItem
WHERE e.id = vSelf;
SET vItem = LAST_INSERT_ID();
END IF;
END IF;
-- Inserta la compra asociada al EKT
INSERT INTO vn2008.Compres
(
Id_Entrada
,buy_edi_id
,Costefijo
,Id_Article
,`grouping`
,caja
,Packing
,Cantidad
,Productor
,Etiquetas
,Id_Cubo
,`weight`
)
SELECT
cfg.edi_entry
,vSelf
,(@t := IF(a.Tallos, a.Tallos, 1)) * e.pri
,IFNULL(vItem, cfg.generic_item)
,IFNULL(c.`grouping`, e.pac)
,vForceToPacking
,@pac := e.pac / @t
,@pac * e.qty
,s.company_name
,e.qty
,IFNULL(c.Id_Cubo, e.package)
,a.density * (vn.item_getVolume(a.Id_Article, IFNULL(c.Id_Cubo, e.package)) / 1000000)
FROM vn2008.buy_edi e
LEFT JOIN vn2008.Compres c ON c.Id_Compra = vBuy
LEFT JOIN vn2008.Articles a ON a.Id_Article = c.Id_Article
LEFT JOIN supplier s ON e.pro = s.supplier_id
JOIN vn2008.config cfg
WHERE e.id = vSelf
LIMIT 1;
END

View File

@ -0,0 +1,130 @@
DROP procedure IF EXISTS `vn`.`item_getBalance`;
DELIMITER $$
USE `vn`$$
CREATE DEFINER=`root`@`%` PROCEDURE `item_getBalance`(IN vItemId INT, IN vWarehouse INT)
BEGIN
DECLARE vDateInventory DATETIME;
DECLARE vCurdate DATE DEFAULT CURDATE();
DECLARE vDayEnd DATETIME DEFAULT util.dayEnd(vCurdate);
SELECT inventoried INTO vDateInventory FROM config;
SET @a = 0;
SET @currentLineFk = 0;
SET @shipped = '';
SELECT DATE(@shipped:= shipped) shipped,
alertLevel,
stateName,
origin,
reference,
clientFk,
name,
`in`,
`out`,
@a := @a + IFNULL(`in`,0) - IFNULL(`out`,0) as balance,
@currentLineFk := IF (@shipped < CURDATE()
OR (@shipped = CURDATE() AND (isPicked OR alertLevel >= 2)),
lineFk,@currentLineFk) lastPreparedLineFk,
isTicket,
lineFk,isPicked
FROM
( SELECT tr.landed as shipped,
b.quantity as `in`,
NULL as `out`,
al.alertLevel as alertLevel,
st.name AS stateName,
s.name as name,
e.ref as reference,
e.id as origin,
s.id as clientFk,
IF(al.alertLevel = 3, TRUE, FALSE) isPicked,
FALSE AS isTicket,
b.id lineFk,
NULL `order`
FROM buy b
JOIN entry e ON e.id = b.entryFk
JOIN travel tr ON tr.id = e.travelFk
JOIN supplier s ON s.id = e.supplierFk
JOIN alertLevel al ON al.alertLevel =
CASE
WHEN tr.shipped < CURDATE() THEN 3
WHEN tr.shipped = CURDATE() AND tr.isReceived = TRUE THEN 3
ELSE 0
END
JOIN state st ON st.code = al.code
WHERE tr.landed >= vDateInventory
AND vWarehouse = tr.warehouseInFk
AND b.itemFk = vItemId
AND e.isInventory = FALSE
AND e.isRaid = FALSE
UNION ALL
SELECT tr.shipped,
NULL as `in`,
b.quantity as `out`,
al.alertLevel as alertLevel,
st.name AS stateName,
s.name as name,
e.ref as reference,
e.id as origin,
s.id as clientFk,
IF(al.alertLevel = 3, TRUE, FALSE) isPicked,
FALSE AS isTicket,
b.id,
NULL `order`
FROM buy b
JOIN entry e ON e.id = b.entryFk
JOIN travel tr ON tr.id = e.travelFk
JOIN warehouse w ON w.id = tr.warehouseOutFk
JOIN supplier s ON s.id = e.supplierFk
JOIN alertLevel al ON al.alertLevel =
CASE
WHEN tr.shipped < CURDATE() THEN 3
WHEN tr.shipped = CURDATE() AND tr.isReceived = TRUE THEN 3
ELSE 0
END
JOIN state st ON st.code = al.code
WHERE tr.shipped >= vDateInventory
AND vWarehouse =tr.warehouseOutFk
AND s.id <> 4
AND b.itemFk = vItemId
AND e.isInventory = FALSE
AND w.isFeedStock = FALSE
AND e.isRaid = FALSE
UNION ALL
SELECT DATE(t.shipped),
NULL as `in`,
s.quantity as `out`,
al.alertLevel as alertLevel,
st.name AS stateName,
t.nickname as name,
t.refFk as reference,
t.id as origin,
t.clientFk,
stk.id as isPicked,
TRUE as isTicket,
s.id,
st.`order`
FROM sale s
JOIN ticket t ON t.id = s.ticketFk
LEFT JOIN ticketState ts ON ts.ticket = t.id
LEFT JOIN state st ON st.code = ts.code
JOIN client c ON c.id = t.clientFk
JOIN alertLevel al ON al.alertLevel =
CASE
WHEN t.shipped < curdate() THEN 3
WHEN t.shipped > util.dayEnd(curdate()) THEN 0
ELSE IFNULL(ts.alertLevel, 0)
END
LEFT JOIN state stPrep ON stPrep.`code` = 'PREPARED'
LEFT JOIN saleTracking stk ON stk.saleFk = s.id AND stk.stateFk = stPrep.id
WHERE t.shipped >= vDateInventory
AND s.itemFk = vItemId
AND vWarehouse =t.warehouseFk
ORDER BY shipped, alertLevel DESC, isTicket, `order` DESC, isPicked DESC, `in` DESC, `out` DESC
) AS itemDiary;
END$$
delimiter ;

View File

@ -0,0 +1,2 @@
USE `vn`;
DROP procedure IF EXISTS `ticketCalculateSaleForcePrice2`;

View File

@ -0,0 +1,2 @@
USE `vn`;
DROP procedure IF EXISTS `ticketCalculateSaleForcePrice`;

View File

@ -0,0 +1,68 @@
USE `vn`;
DROP procedure IF EXISTS `ticketCalculateSale`;
DROP procedure IF EXISTS `ticketCalculateSale__`;
DELIMITER $$
USE `vn`$$
CREATE DEFINER=`root`@`%` PROCEDURE `ticketCalculateSale__`(IN vSale BIGINT)
proc: BEGIN
-- OBSOLETO USAR: sale_calculateComponent(vSale, NULL)
DECLARE vShipped DATE;
DECLARE vWarehouseFk SMALLINT;
DECLARE vAgencyModeFk INT;
DECLARE vAddressFk INT;
DECLARE vTicket BIGINT;
DECLARE vItem BIGINT;
DECLARE vLanded DATE;
DECLARE vTicketFree BOOLEAN DEFAULT TRUE;
DECLARE vZoneFk INTEGER;
SELECT NOT (t.refFk IS NOT NULL OR ts.alertLevel > 0) OR s.price = 0, s.ticketFk, s.itemFk , t.zoneFk
INTO vTicketFree, vTicket, vItem, vZoneFk
FROM vn.ticket t
JOIN vn.sale s ON s.ticketFk = t.id
LEFT JOIN vn.ticketState ts ON ts.ticketFk = t.id
WHERE s.id = vSale
LIMIT 1;
SELECT t.warehouseFk, DATE(t.shipped), t.addressFk, t.agencyModeFk, t.landed
INTO vWarehouseFk, vShipped, vAddressFk, vAgencyModeFk, vLanded
FROM agencyMode a
JOIN ticket t ON t.agencyModeFk = a.id
WHERE t.id = vTicket;
IF IFNULL(vZoneFk,0) = 0 THEN
CALL util.throw('ticket dont have zone');
END IF;
CALL buyUltimate (vWarehouseFk, vShipped);
DELETE FROM tmp.buyUltimate WHERE itemFk != vItem;
DROP TEMPORARY TABLE IF EXISTS tmp.ticketLot;
CREATE TEMPORARY TABLE tmp.ticketLot
SELECT vWarehouseFk warehouseFk, NULL available, vItem itemFk, buyFk, vZoneFk zoneFk
FROM tmp.buyUltimate
WHERE itemFk = vItem;
CALL vn.catalog_componentCalculate;
CALL catalog_componentCalculate(vZoneFk, vAddressFk, vShipped, vWarehouseFk);
DROP TEMPORARY TABLE IF EXISTS tmp.sale;
CREATE TEMPORARY TABLE tmp.sale
(PRIMARY KEY (saleFk)) ENGINE = MEMORY
SELECT vSale saleFk,vWarehouseFk warehouseFk;
CALL ticketComponentUpdateSale(IF(vTicketFree,1,6));
INSERT INTO vn.ticketLog (originFk, userFk, `action`, description)
VALUES (vTicket, account.userGetId(), 'update', CONCAT('Bionizo linea id ', vSale));
CALL catalog_componentPurge();
DROP TEMPORARY TABLE tmp.buyUltimate;
DROP TEMPORARY TABLE IF EXISTS tmp.sale;
END$$
DELIMITER ;

View File

@ -0,0 +1,83 @@
USE `vn`;
DROP procedure IF EXISTS `vn`.`ticket_componentUpdate`;
DROP procedure IF EXISTS `vn`.`ticket_componentUpdate__`;
DELIMITER $$
USE `vn`$$
CREATE DEFINER=`root`@`%` PROCEDURE `ticket_componentUpdate__`(
vTicketFk INT,
vClientFk INT,
vAgencyModeFk INT,
vAddressFk INT,
vZoneFk INT,
vWarehouseFk TINYINT,
vCompanyFk SMALLINT,
vShipped DATETIME,
vLanded DATE,
vIsDeleted BOOLEAN,
vHasToBeUnrouted BOOLEAN,
vOption INT)
BEGIN
DECLARE vPrice DECIMAL(10,2);
DECLARE vBonus DECIMAL(10,2);
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
RESIGNAL;
END;
START TRANSACTION;
IF (SELECT addressFk FROM ticket WHERE id = vTicketFk) <> vAddressFk THEN
UPDATE ticket t
JOIN address a ON a.id = vAddressFk
SET t.nickname = a.nickname
WHERE t.id = vTicketFk;
END IF;
CALL vn.zone_getShippedWarehouse(vlanded, vAddressFk, vAgencyModeFk);
SELECT zoneFk, price, bonus INTO vZoneFk, vPrice, vBonus
FROM tmp.zoneGetShipped
WHERE shipped = vShipped AND warehouseFk = vWarehouseFk LIMIT 1;
UPDATE ticket t
SET
t.clientFk = vClientFk,
t.agencyModeFk = vAgencyModeFk,
t.addressFk = vAddressFk,
t.zoneFk = vZoneFk,
t.zonePrice = vPrice,
t.zoneBonus = vBonus,
t.warehouseFk = vWarehouseFk,
t.companyFk = vCompanyFk,
t.landed = vLanded,
t.shipped = vShipped,
t.isDeleted = vIsDeleted
WHERE
t.id = vTicketFk;
IF vHasToBeUnrouted THEN
UPDATE ticket t SET t.routeFk = NULL
WHERE t.id = vTicketFk;
END IF;
IF vOption <> 8 THEN
DROP TEMPORARY TABLE IF EXISTS tmp.sale;
CREATE TEMPORARY TABLE tmp.sale
(PRIMARY KEY (saleFk))
ENGINE = MEMORY
SELECT id AS saleFk, vWarehouseFk warehouseFk
FROM sale s WHERE s.ticketFk = vTicketFk;
CALL ticketComponentUpdateSale (vOption);
DROP TEMPORARY TABLE tmp.sale;
END IF;
COMMIT;
END$$
DELIMITER ;
;

View File

@ -21,7 +21,7 @@ INSERT INTO `vn`.`bionicConfig` (`generalInflationCoeficient`, `minimumDensityVo
(1.30, 167.00, 138000, 71);
INSERT INTO `vn`.`chatConfig` (`host`, `api`)
VALUES
VALUES
('https://chat.verdnatura.es', 'https://chat.verdnatura.es/api/v1');
INSERT IGNORE INTO `vn`.`greugeConfig`(`id`, `freightPickUpPrice`)
@ -980,6 +980,29 @@ INSERT INTO `vn`.`itemPlacement`(`id`, `itemFk`, `warehouseFk`, `code`)
(3, 1, 3, 'A3'),
(4, 2, 1, 'A4');
INSERT INTO `vn`.`collection`(`id`, `workerFk`, `stateFk`)
VALUES
(1, 106, 5),
(2, 106, 14);
INSERT INTO `vn`.`parking` (`column`, `row`, `sectorFk`, `code`, `pickingOrder`)
VALUES
('100', '01', 1, '100-01', 1);
INSERT INTO `vn`.`shelving` (`code`, `parkingFk`, `priority`, `userFk`)
VALUES
('UXN', 1, 1, 106);
INSERT INTO `vn`.`itemShelving` (`itemFk`, `shelvingFk`, `shelve`, `deep`, `quantity`, `visible`, `available`, `grouping`, `packing`, `level`, `userFk`)
VALUES
(1, 'UXN', 'A', 2, 12, 12, 12, 12, 12, 1, 106);
INSERT INTO `vn`.`ticketCollection` (`ticketFk`, `collectionFk`, `level`)
VALUES
(1, 1, 1);
INSERT INTO `edi`.`genus`(`genus_id`, `latin_genus_name`, `entry_date`, `expiry_date`, `change_date_time`)
VALUES
(1, 'Abelia' , CURDATE(), NULL, CURDATE()),
@ -1953,11 +1976,13 @@ INSERT INTO `vn`.`dmsType`(`id`, `name`, `path`, `readRoleFk`, `writeRoleFk`, `c
INSERT INTO `vn`.`dms`(`id`, `dmsTypeFk`, `file`, `contentType`, `workerFk`, `warehouseFk`, `companyFk`, `hardCopyNumber`, `hasFile`, `reference`, `description`, `created`)
VALUES
(1, 14, '1.txt', 'text/plain', 5, 1, 442, NULL, FALSE, 'Ticket:11', 'Ticket:11 dms for the ticket', CURDATE()),
(2, 5, '2.txt', 'text/plain', 5, 1, 442, 1, TRUE, 'Client:104', 'Client:104 dms for the client', CURDATE()),
(3, 5, '3.txt', 'text/plain', 5, 1, 442, NULL, TRUE, 'Client: 104', 'Client:104 readme', CURDATE()),
(4, 3, '4.txt', 'text/plain', 5, 1, 442, NULL, TRUE, 'Worker: 106', 'Worker:106 readme', CURDATE()),
(5, 5, '5.txt', 'text/plain', 5, 1, 442, NULL, TRUE, 'travel: 1', 'dmsForThermograph', CURDATE());
(1, 14, '1.txt', 'text/plain', 5, 1, 442, NULL, FALSE, 'Ticket:11', 'Ticket:11 dms for the ticket', CURDATE()),
(2, 5, '2.txt', 'text/plain', 5, 1, 442, 1, TRUE, 'Client:104', 'Client:104 dms for the client', CURDATE()),
(3, 5, '3.txt', 'text/plain', 5, 1, 442, NULL, TRUE, 'Client: 104', 'Client:104 readme', CURDATE()),
(4, 3, '4.txt', 'text/plain', 5, 1, 442, NULL, TRUE, 'Worker: 106', 'Worker:106 readme', CURDATE()),
(5, 5, '5.txt', 'text/plain', 5, 1, 442, NULL, TRUE, 'travel: 1', 'dmsForThermograph', CURDATE()),
(6, 5, '6.txt', 'text/plain', 5, 1, 442, NULL, TRUE, 'NotExists', 'DoesNotExists', CURDATE());
INSERT INTO `vn`.`ticketDms`(`ticketFk`, `dmsFk`)
VALUES
@ -1968,9 +1993,10 @@ INSERT INTO `vn`.`clientDms`(`clientFk`, `dmsFk`)
(104, 2),
(104, 3);
INSERT INTO `vn`.`workerDocument`(`id`, `worker`, `document`)
INSERT INTO `vn`.`workerDocument`(`id`, `worker`, `document`,`isReadableByWorker`)
VALUES
(1, 106, 4);
(1, 106, 4, TRUE),
(2, 107, 3, FALSE);
INSERT INTO `vn`.`device` (`sn`, `model`, `userFk`)
VALUES

File diff suppressed because it is too large Load Diff

View File

@ -24,7 +24,7 @@ describe('ticket_recalcComponents()', () => {
let modifiedSales = stmts.push(stmt) - 1;
stmt = new ParameterizedSQL('CALL vn.ticket_recalcComponents(?)', [
stmt = new ParameterizedSQL('CALL vn.ticket_recalcComponents(?, NULL)', [
ticketId,
]);
stmts.push(stmt);

View File

@ -0,0 +1,28 @@
const app = require('vn-loopback/server/server');
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
describe('zone zone_getFromGeo()', () => {
it(`should check that there are some results in table zone`, async() => {
let stmts = [];
let stmt;
stmts.push('START TRANSACTION');
let geoFk = 17;
stmt = new ParameterizedSQL('CALL zone_getFromGeo(?)', [
geoFk,
]);
stmts.push(stmt);
let tableIndex = stmts.push('SELECT count(*) countZone FROM tmp.zone WHERE id IN (1, 2, 3, 4, 5, 6, 7, 8)') - 1;
stmts.push('ROLLBACK');
let sql = ParameterizedSQL.join(stmts, ';');
let result = await app.models.Ticket.rawStmt(sql);
let [zoneTable] = result[tableIndex];
expect(zoneTable.countZone).toBe(8);
});
});

View File

@ -0,0 +1,66 @@
const app = require('vn-loopback/server/server');
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
describe('zone zone_getLanded()', () => {
it(`should return data for a shipped in the past`, async() => {
let stmts = [];
let stmt;
stmts.push('START TRANSACTION');
let params = {
addressFk: 121,
agencyModeFk: 7,
warehouseFk: 1};
stmt = new ParameterizedSQL('CALL zone_getLanded(DATE_ADD(CURDATE(), INTERVAL -1 DAY), ?, ?, ?)', [
params.addressFk,
params.agencyModeFk,
params.warehouseFk
]);
stmts.push(stmt);
let tableIndex = stmts.push('SELECT count(*) countZone FROM tmp.zoneGetLanded') - 1;
stmts.push('ROLLBACK');
let sql = ParameterizedSQL.join(stmts, ';');
let result = await app.models.Ticket.rawStmt(sql);
let [zoneTable] = result[tableIndex];
expect(zoneTable.countZone).toBe(1);
});
it(`should return data for a shipped tomorrow`, async() => {
let stmts = [];
let stmt;
stmts.push('START TRANSACTION');
let params = {
addressFk: 121,
agencyModeFk: 7,
warehouseFk: 1};
stmt = new ParameterizedSQL('CALL zone_getLanded(DATE_ADD(CURDATE(), INTERVAL +2 DAY), ?, ?, ?)', [
params.addressFk,
params.agencyModeFk,
params.warehouseFk
]);
stmts.push(stmt);
let tableIndex = stmts.push('SELECT count(*) countZone FROM tmp.zoneGetLanded') - 1;
stmts.push('ROLLBACK');
let sql = ParameterizedSQL.join(stmts, ';');
let result = await app.models.Ticket.rawStmt(sql);
let [zoneTable] = result[tableIndex];
expect(zoneTable.countZone).toBe(1);
});
});

1
e2e/dms/a87/4.txt Normal file
View File

@ -0,0 +1 @@
File: 4.txt. It works!

View File

@ -65,15 +65,6 @@ let actions = {
},
doLogin: async function(userName, password = 'nightmare') {
await this.waitForSelector(`vn-login vn-textfield[ng-model="$ctrl.user"]`, {visible: true});
await this.clearInput(`vn-login vn-textfield[ng-model="$ctrl.user"]`);
await this.write(`vn-login vn-textfield[ng-model="$ctrl.user"]`, userName);
await this.clearInput(`vn-login vn-textfield[ng-model="$ctrl.password"]`);
await this.write(`vn-login vn-textfield[ng-model="$ctrl.password"]`, password);
await this.waitToClick('vn-login button[type=submit]');
},
login: async function(userName) {
let state = await this.getState();
if (state != 'login') {
@ -91,6 +82,16 @@ let actions = {
}
await this.waitForState('login');
await this.waitForSelector(`vn-login vn-textfield[ng-model="$ctrl.user"]`, {visible: true});
await this.clearInput(`vn-login vn-textfield[ng-model="$ctrl.user"]`);
await this.write(`vn-login vn-textfield[ng-model="$ctrl.user"]`, userName);
await this.clearInput(`vn-login vn-textfield[ng-model="$ctrl.password"]`);
await this.write(`vn-login vn-textfield[ng-model="$ctrl.password"]`, password);
await this.waitToClick('vn-login button[type=submit]');
},
login: async function(userName) {
await this.doLogin(userName);
await this.waitForState('home');
},
@ -114,10 +115,11 @@ let actions = {
},
gotoState: async function(state, params) {
return await this.evaluate((state, params) => {
await this.evaluate((state, params) => {
let $state = angular.element(document.body).injector().get('$state');
return $state.go(state, params);
}, state, params);
await this.waitForSpinnerLoad();
},
waitForState: async function(state) {
@ -125,7 +127,7 @@ let actions = {
let $state = angular.element(document.body).injector().get('$state');
return !$state.transition && $state.is(state);
}, {}, state);
await this.waitForSpinnerLoad(state);
await this.waitForSpinnerLoad();
},
waitForTransition: async function() {
@ -133,6 +135,7 @@ let actions = {
const $state = angular.element(document.body).injector().get('$state');
return !$state.transition;
});
await this.waitForSpinnerLoad();
},
accessToSection: async function(state) {
@ -142,7 +145,11 @@ let actions = {
}, state);
if (nested) {
await this.waitToClick('vn-left-menu vn-item-section > vn-icon[icon=keyboard_arrow_down]');
let selector = 'vn-left-menu vn-item-section > vn-icon[icon=keyboard_arrow_down]';
await this.evaluate(selector => {
document.querySelector(selector).scrollIntoViewIfNeeded();
}, selector);
await this.waitToClick(selector);
await this.wait('vn-left-menu .expanded');
}
@ -167,11 +174,17 @@ let actions = {
await this.waitToClick(`vn-left-menu li > a[ui-sref="${sectionRoute}"]`);
},
accessToSearchResult: async function(searchValue) {
doSearch: async function(searchValue) {
await this.clearInput('vn-searchbar');
await this.write('vn-searchbar', searchValue);
if (searchValue)
await this.write('vn-searchbar', searchValue);
await this.waitToClick('vn-searchbar vn-icon[icon="search"]');
await this.waitForTransition();
},
accessToSearchResult: async function(searchValue) {
await this.doSearch(searchValue);
await this.waitFor('.vn-descriptor');
},
@ -181,6 +194,12 @@ let actions = {
}, selector, property);
},
getClassName: async function(selector) {
const element = await this.$(selector);
const handle = await element.getProperty('className');
return await handle.jsonValue();
},
waitPropertyLength: async function(selector, property, minLength) {
await this.waitForFunction((selector, property, minLength) => {
const element = document.querySelector(selector);
@ -228,6 +247,11 @@ let actions = {
await this.waitForTextInField(selector, text);
},
overwrite: async function(selector, text) {
await this.clearInput(selector);
await this.write(selector, text);
},
waitToClick: async function(selector) {
await this.waitForSelector(selector);
await this.waitForFunction(checkVisibility, {}, selector);
@ -335,28 +359,41 @@ let actions = {
hideSnackbar: async function() {
// Holds up for the snackbar to be visible for a small period of time.
if (process.env.DEBUG)
if (process.env.E2E_DEBUG)
await this.waitFor(300);
await this.evaluate(() => {
let hideButton = document.querySelector('#shapes .shown button');
let hideButton = document
.querySelector('vn-snackbar .shape.shown button');
if (hideButton)
return document.querySelector('#shapes .shown button').click();
return hideButton.click();
});
await this.waitFor('#shapes > .shape', {hidden: true});
await this.waitFor('vn-snackbar .shape.shown', {hidden: true});
},
waitForLastSnackbar: async function() {
const selector = 'vn-snackbar .shown .text';
waitForSnackbar: async function() {
const selector = 'vn-snackbar .shape.shown';
await this.waitForSelector(selector);
let snackBarText = await this.evaluate(selector => {
const shape = document.querySelector(selector);
return shape.innerText;
let message = await this.evaluate(selector => {
const shape = document.querySelector(selector);
const message = {
text: shape.querySelector('.text').innerText
};
const types = ['error', 'success'];
for (let type of types) {
if (shape.classList.contains(type)) {
message.type = type;
break;
}
}
return message;
}, selector);
await this.hideSnackbar();
return snackBarText;
return message;
},
pickDate: async function(selector, date) {
@ -438,7 +475,6 @@ let actions = {
.includes(searchValue.toLowerCase());
}, {}, builtSelector, searchValue);
await this.waitForMutation('.vn-drop-down', 'childList');
await this.waitFor('.vn-drop-down', {hidden: true});
},
@ -546,7 +582,7 @@ let actions = {
},
waitForContentLoaded: async function() {
// await this.waitFor(250);
await this.waitForSpinnerLoad();
}
};

View File

@ -9,10 +9,14 @@ export async function getBrowser() {
`--window-size=${ 1920 },${ 1080 }`
];
if (process.env.DEBUG)
args.push('--auto-open-devtools-for-tabs');
let env = process.env;
const headless = !(process.env.E2E_SHOW || process.env.DEBUG);
if (env.E2E_DEBUG) {
args.push('--auto-open-devtools-for-tabs');
env.E2E_SHOW = true;
}
const headless = !env.E2E_SHOW;
const browser = await Puppeteer.launch({
args,
defaultViewport: null,

View File

@ -2,6 +2,8 @@
export default {
globalItems: {
applicationsMenuButton: '#apps',
userMenuButton: '#user',
logoutButton: '#logout',
applicationsMenuVisible: '.modules-menu',
clientsButton: '.modules-menu > li[ui-sref="client.index"]',
itemsButton: '.modules-menu > li[ui-sref="item.index"]',
@ -10,7 +12,6 @@ export default {
claimsButton: '.modules-menu > li[ui-sref="claim.index"]',
returnToModuleIndexButton: 'a[ui-sref="order.index"]',
homeButton: 'vn-topbar > div.side.start > a',
userMenuButton: '#user',
userLocalWarehouse: '.user-popover vn-autocomplete[ng-model="$ctrl.localWarehouseFk"]',
userLocalBank: '.user-popover vn-autocomplete[ng-model="$ctrl.localBankFk"]',
userLocalCompany: '.user-popover vn-autocomplete[ng-model="$ctrl.localCompanyFk"]',
@ -99,7 +100,6 @@ export default {
receivedCoreVNLCheckbox: 'vn-client-billing-data vn-check[label="Received core VNL"]',
receivedB2BVNLCheckbox: 'vn-client-billing-data vn-check[label="Received B2B VNL"]',
swiftBic: 'vn-client-billing-data vn-autocomplete[ng-model="$ctrl.client.bankEntityFk"]',
clearswiftBicButton: 'vn-client-billing-data vn-autocomplete[ng-model="$ctrl.client.bankEntityFk"] .icons > vn-icon[icon=clear]',
newBankEntityButton: 'vn-client-billing-data vn-icon-button[vn-tooltip="New bank entity"] > button',
newBankEntityName: '.vn-dialog.shown vn-textfield[ng-model="$ctrl.newBankEntity.name"]',
newBankEntityBIC: '.vn-dialog.shown vn-textfield[ng-model="$ctrl.newBankEntity.bic"]',
@ -178,12 +178,11 @@ export default {
},
clientBalance: {
balanceButton: 'vn-left-menu a[ui-sref="client.card.balance.index"]',
company: 'vn-client-balance-index vn-autocomplete[ng-model="$ctrl.companyId"]',
newPaymentButton: `vn-float-button`,
newPaymentBank: '.vn-dialog.shown vn-autocomplete[ng-model="$ctrl.receipt.bankFk"]',
newPaymentAmount: '.vn-dialog.shown vn-input-number[ng-model="$ctrl.receipt.amountPaid"]',
saveButton: '.vn-dialog.shown vn-button[label="Save"]',
saveButton: '.vn-dialog.shown [response="accept"]',
firstBalanceLine: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(8)'
},
@ -338,8 +337,8 @@ export default {
},
itemDiary: {
secondTicketId: 'vn-item-diary vn-tbody > vn-tr:nth-child(2) > vn-td:nth-child(2) > span',
fourthBalance: 'vn-item-diary vn-tbody > vn-tr:nth-child(4) > vn-td.balance > span',
firstBalance: 'vn-item-diary vn-tbody > vn-tr:nth-child(1) > vn-td.balance',
fourthBalance: 'vn-item-diary vn-tbody > vn-tr:nth-child(4) > vn-td.balance',
warehouse: 'vn-item-diary vn-autocomplete[ng-model="$ctrl.warehouseFk"]',
},
itemLog: {
@ -352,10 +351,10 @@ export default {
route: 'vn-ticket-summary vn-label-value[label="Route"] > section > span > span',
total: 'vn-ticket-summary vn-one.taxes > p:nth-child(3) > strong',
sale: 'vn-ticket-summary [name="sales"] vn-table > div > vn-tbody > vn-tr',
firstSaleItemId: 'vn-ticket-summary [name="sales"] vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > span',
firstSaleItemId: 'vn-ticket-summary [name="sales"] vn-table vn-tbody > :nth-child(1) > vn-td:nth-child(2) > span',
firstSaleDescriptorImage: '.vn-popover.shown vn-item-descriptor img',
itemDescriptorPopover: '.vn-popover.shown vn-item-descriptor',
itemDescriptorPopoverItemDiaryButton: 'vn-item-descriptor a[href="#!/item/2/diary?warehouseFk=5&ticketFk=20"]',
itemDescriptorPopoverItemDiaryButton: 'vn-item-descriptor a[href="#!/item/2/diary?warehouseFk=5&lineFk=16"]',
popoverDiaryButton: '.vn-popover.shown vn-item-descriptor vn-icon[icon="icon-transaction"]',
firstSaleQuantity: 'vn-ticket-summary [name="sales"] vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(3)',
firstSaleDiscount: 'vn-ticket-summary [name="sales"] vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(6)',
@ -373,17 +372,17 @@ export default {
payoutButton: 'vn-ticket-index vn-button[icon="icon-recovery"]',
payoutCompany: '.vn-dialog vn-autocomplete[ng-model="$ctrl.receipt.companyFk"]',
payoutBank: '.vn-dialog vn-autocomplete[ng-model="$ctrl.receipt.bankFk"]',
submitPayout: '.vn-dialog vn-button[label="Save"]',
submitPayout: '.vn-dialog button[response="accept"]',
searchWeeklyResult: 'vn-ticket-weekly-index vn-table vn-tbody > vn-tr',
searchResultDate: 'vn-ticket-summary [label=Landed] span',
topbarSearch: 'vn-searchbar',
advancedSearchButton: 'vn-ticket-search-panel button[type=submit]',
searchButton: 'vn-searchbar vn-icon[icon="search"]',
searchWeeklyButton: 'vn-searchbar vn-icon[icon="search"]',
moreMenu: 'vn-ticket-index vn-icon-menu[icon=more_vert]',
sixthWeeklyTicket: 'vn-ticket-weekly-index vn-table vn-tr:nth-child(6)',
weeklyTicket: 'vn-ticket-weekly-index vn-table > div > vn-tbody > vn-tr',
firstWeeklyTicketDeleteIcon: 'vn-ticket-weekly-index vn-tr:nth-child(1) vn-icon-button[icon="delete"]',
firstWeeklyTicketAgency: 'vn-ticket-weekly-index vn-tr:nth-child(1) [ng-model="weekly.agencyModeFk"]',
acceptDeleteTurn: '.vn-confirm.shown button[response="accept"]'
},
createTicketView: {
@ -436,7 +435,6 @@ export default {
firstQuantity: 'vn-ticket-package vn-horizontal:nth-child(1) vn-input-number[ng-model="package.quantity"]',
firstRemovePackageButton: 'vn-icon-button[vn-tooltip="Remove package"]',
addPackageButton: 'vn-icon-button[vn-tooltip="Add package"]',
clearPackageAutocompleteButton: 'vn-autocomplete[label="Package"] .icons > vn-icon[icon=clear]',
savePackagesButton: `button[type=submit]`
},
ticketSales: {
@ -461,7 +459,6 @@ export default {
firstSaleZoomedImage: 'body > div > div > img',
firstSaleQuantity: 'vn-ticket-sale [ng-model="sale.quantity"]',
firstSaleQuantityCell: 'vn-ticket-sale vn-tr:nth-child(1) > vn-td-editable:nth-child(5)',
firstSaleQuantityClearInput: 'vn-textfield[ng-model="sale.quantity"] div.suffix > i',
firstSaleIdAutocomplete: 'vn-ticket-sale vn-table vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(4) > vn-autocomplete',
firstSalePrice: 'vn-ticket-sale vn-table vn-tr:nth-child(1) > vn-td:nth-child(7) > span',
firstSalePriceInput: '.vn-popover.shown [ng-model="$ctrl.editedPrice"]',
@ -491,7 +488,6 @@ export default {
deleteSaleButton: 'vn-ticket-sale vn-tool-bar > vn-button[icon="delete"]',
transferSaleButton: 'vn-ticket-sale vn-tool-bar > vn-button[icon="call_split"]',
moveToTicketInput: '.vn-popover.shown vn-textfield[ng-model="$ctrl.transfer.ticketId"]',
moveToTicketInputClearButton: '.vn-popover.shown i[title="Clear"]',
moveToTicketButton: '.vn-popover.shown vn-icon[icon="arrow_forward_ios"]',
moveToNewTicketButton: '.vn-popover.shown vn-button[label="New ticket"]',
acceptDeleteLineButton: '.vn-confirm.shown button[response=accept]',
@ -545,8 +541,8 @@ export default {
firstPrice: 'vn-ticket-service vn-horizontal:nth-child(1) vn-input-number[ng-model="service.price"]',
firstVatType: 'vn-ticket-service vn-autocomplete[label="Tax class"]',
fistDeleteServiceButton: 'vn-ticket-service form vn-horizontal:nth-child(1) vn-icon-button[icon="delete"]',
newServiceTypeName: '.vn-dialog.shown vn-textfield[ng-model="$ctrl.newServiceType.name"]',
newServiceTypeExpense: '.vn-dialog.shown vn-autocomplete[ng-model="$ctrl.newServiceType.expenseFk"]',
newServiceTypeName: '.vn-dialog.shown vn-textfield[ng-model="newServiceType.name"]',
newServiceTypeExpense: '.vn-dialog.shown vn-autocomplete[ng-model="newServiceType.expenseFk"]',
serviceLine: 'vn-ticket-service > form > vn-card > vn-one:nth-child(2) > vn-horizontal',
saveServiceButton: 'button[type=submit]',
saveServiceTypeButton: '.vn-dialog.shown tpl-buttons > button'
@ -554,7 +550,6 @@ export default {
createStateView: {
state: 'vn-autocomplete[ng-model="$ctrl.stateFk"]',
worker: 'vn-autocomplete[ng-model="$ctrl.workerFk"]',
clearStateInputButton: 'vn-autocomplete[ng-model="$ctrl.stateFk"] .icons > vn-icon[icon=clear]',
saveStateButton: `button[type=submit]`
},
claimsIndex: {

View File

@ -1,3 +1,4 @@
import selectors from '../../helpers/selectors';
import getBrowser from '../../helpers/puppeteer';
describe('Login path', async() => {
@ -13,41 +14,54 @@ describe('Login path', async() => {
});
describe('Bad login', async() => {
it('should receive an error when the username is incorrect', async() => {
await page.doLogin('badUser', '');
const result = await page.waitForLastSnackbar();
it('should receive an error when the password is invalid', async() => {
await page.doLogin('employee', 'badPassword');
const message = await page.waitForSnackbar();
const state = await page.getState();
expect(result.length).toBeGreaterThan(0);
expect(message.type).toBe('error');
expect(state).toBe('login');
});
it('should receive an error when the username is invalid', async() => {
await page.doLogin('badUser', '');
const message = await page.waitForSnackbar();
const state = await page.getState();
expect(message.type).toBe('error');
expect(state).toBe('login');
});
it('should receive an error when the username is blank', async() => {
await page.doLogin('', '');
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
const state = await page.getState();
expect(result.length).toBeGreaterThan(0);
expect(state).toBe('login');
});
it('should receive an error when the password is incorrect', async() => {
await page.doLogin('employee', 'badPassword');
const result = await page.waitForLastSnackbar();
const state = await page.getState();
expect(result.length).toBeGreaterThan(0);
expect(message.type).toBe('error');
expect(state).toBe('login');
});
});
describe('Successful login', async() => {
it('should log in', async() => {
await page.doLogin('employee', 'nightmare');
await page.waitForNavigation();
it('should log in and go to home state', async() => {
await page.doLogin('employee');
await page.waitFor('vn-home');
const state = await page.getState();
expect(state).toBe('home');
});
});
describe('Logout', async() => {
it('should logout and return to login state', async() => {
await page.doLogin('employee');
await page.waitToClick(selectors.globalItems.userMenuButton);
await page.waitToClick(selectors.globalItems.logoutButton);
await page.waitFor('vn-login');
const state = await page.getState();
expect(state).toBe('login');
});
});
});

View File

@ -1,9 +1,10 @@
import selectors from '../../helpers/selectors';
import getBrowser from '../../helpers/puppeteer';
describe('Client create path', async() => {
describe('Client create path', () => {
let browser;
let page;
beforeAll(async() => {
browser = await getBrowser();
page = browser.page;
@ -15,9 +16,7 @@ describe('Client create path', async() => {
});
it(`should search for the user Carol Danvers to confirm it isn't created yet`, async() => {
await page.write(selectors.clientsIndex.topbarSearch, 'Carol Danvers');
await page.waitToClick(selectors.clientsIndex.searchButton);
await page.waitForNumberOfElements(selectors.clientsIndex.searchResult, 0);
await page.doSearch('Carol Danvers');
const result = await page.countElement(selectors.clientsIndex.searchResult);
expect(result).toEqual(0);
@ -30,9 +29,9 @@ describe('Client create path', async() => {
it('should receive an error when clicking the create button having all the form fields empty', async() => {
await page.waitToClick(selectors.createClientView.createButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Some fields are invalid');
expect(message.text).toBe('Some fields are invalid');
});
it('should receive an error when clicking the create button having name and Business name fields empty', async() => {
@ -41,9 +40,9 @@ describe('Client create path', async() => {
await page.write(selectors.createClientView.email, 'CarolDanvers@verdnatura.es');
await page.autocompleteSearch(selectors.createClientView.salesPerson, 'replenisher');
await page.waitToClick(selectors.createClientView.createButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Some fields are invalid');
expect(message.text).toBe('Some fields are invalid');
});
it(`should attempt to create a new user with all it's data but wrong email`, async() => {
@ -57,9 +56,9 @@ describe('Client create path', async() => {
await page.clearInput(selectors.createClientView.email);
await page.write(selectors.createClientView.email, 'incorrect email format');
await page.waitToClick(selectors.createClientView.createButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Some fields are invalid');
expect(message.text).toBe('Some fields are invalid');
});
it(`should attempt to create a new user with all it's data but wrong postal code`, async() => {
@ -68,9 +67,9 @@ describe('Client create path', async() => {
await page.clearInput(selectors.createClientView.postcode);
await page.write(selectors.createClientView.postcode, '479999');
await page.waitToClick(selectors.createClientView.createButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual(`The postcode doesn't exist. Please enter a correct one`);
expect(message.text).toBe(`The postcode doesn't exist. Please enter a correct one`);
});
it(`should check for autocompleted city, province and country`, async() => {
@ -92,9 +91,9 @@ describe('Client create path', async() => {
await page.clearInput(selectors.createClientView.postcode);
await page.write(selectors.createClientView.postcode, '46000');
await page.waitToClick(selectors.createClientView.createButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it('should click on the Clients button of the top bar menu', async() => {

View File

@ -35,9 +35,9 @@ describe('Client Edit basicData path', () => {
await page.write(selectors.clientBasicData.email, 'PWallace@verdnatura.es');
await page.autocompleteSearch(selectors.clientBasicData.channel, 'Rumors on the streets');
await page.waitToClick(selectors.clientBasicData.saveButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it('should confirm the name have been edited', async() => {
@ -99,9 +99,9 @@ describe('Client Edit basicData path', () => {
await page.autocompleteSearch(selectors.clientBasicData.salesPerson, 'replenisherNick');
await page.autocompleteSearch(selectors.clientBasicData.channel, 'Metropolis newspaper');
await page.waitToClick(selectors.clientBasicData.saveButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it('should now confirm the name have been edited', async() => {

View File

@ -78,9 +78,9 @@ describe('Client Edit fiscalData path', () => {
await page.waitToClick(selectors.clientFiscalData.verifiedDataCheckbox);
await page.waitToClick(selectors.clientFiscalData.saveButton);
await page.waitToClick(selectors.clientFiscalData.acceptDuplicationButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Invalid Tax number');
expect(message.text).toBe('Invalid Tax number');
});
it(`should edit the fiscal this time with a valid fiscal id`, async() => {
@ -88,16 +88,16 @@ describe('Client Edit fiscalData path', () => {
await page.write(selectors.clientFiscalData.fiscalId, '94980061C');
await page.waitToClick(selectors.clientFiscalData.saveButton);
await page.waitToClick(selectors.clientFiscalData.acceptDuplicationButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it('should propagate the Equalization tax', async() => {
await page.waitToClick(selectors.clientFiscalData.acceptPropagationButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Equivalent tax spreaded');
expect(message.text).toBe('Equivalent tax spreaded');
});
it('should receive an error if the fiscal id contains A or B at the beginning', async() => {
@ -105,18 +105,18 @@ describe('Client Edit fiscalData path', () => {
await page.clearInput(selectors.clientFiscalData.fiscalId);
await page.write(selectors.clientFiscalData.fiscalId, 'A94980061C');
await page.waitToClick(selectors.clientFiscalData.saveButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Cannot check Equalization Tax in this NIF/CIF');
expect(message.text).toBe('Cannot check Equalization Tax in this NIF/CIF');
});
it('should finally edit the fixcal data correctly as VIES isnt checked and fiscal id is valid for EQtax', async() => {
await page.clearInput(selectors.clientFiscalData.fiscalId);
await page.write(selectors.clientFiscalData.fiscalId, '94980061C');
await page.waitToClick(selectors.clientFiscalData.saveButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
// confirm all addresses have now EQtax checked step 1
@ -150,17 +150,17 @@ describe('Client Edit fiscalData path', () => {
await page.waitToClick(selectors.clientFiscalData.invoiceByAddressCheckbox);
await page.waitToClick(selectors.clientFiscalData.equalizationTaxCheckbox);
await page.waitToClick(selectors.clientFiscalData.saveButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it('should propagate the Equalization tax changes', async() => {
await page.waitFor(1000);
await page.waitToClick(selectors.clientFiscalData.acceptPropagationButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Equivalent tax spreaded');
expect(message.text).toBe('Equivalent tax spreaded');
});
it('should confirm its name have been edited', async() => {
@ -266,9 +266,9 @@ describe('Client Edit fiscalData path', () => {
await page.waitForTextInField(selectors.clientAddresses.city, 'Silla');
await page.waitToClick(selectors.clientAddresses.equalizationTaxCheckbox);
await page.waitToClick(selectors.clientAddresses.saveButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
// confirm invoice by address checkbox gets checked if the EQtax differs between addresses step 3

View File

@ -26,25 +26,26 @@ describe('Client Edit billing data path', () => {
await page.waitToClick(selectors.clientBillingData.receivedCoreVNLCheckbox);
await page.waitToClick(selectors.clientBillingData.receivedB2BVNLCheckbox);
await page.waitToClick(selectors.clientBillingData.saveButton);
let snackbarMessage = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(snackbarMessage).toEqual('That payment method requires an IBAN');
expect(message.text).toBe('That payment method requires an IBAN');
});
it(`should create a new BIC code`, async() => {
// 2215: Windows (hidden mode): Entity code doesn't get the focus, '9999' is written in entity name.
xit(`should create a new BIC code`, async() => {
await page.waitToClick(selectors.clientBillingData.newBankEntityButton);
await page.write(selectors.clientBillingData.newBankEntityName, 'Gotham City Bank');
await page.write(selectors.clientBillingData.newBankEntityCode, '9999');
await page.write(selectors.clientBillingData.newBankEntityBIC, 'GTHMCT');
await page.waitToClick(selectors.clientBillingData.acceptBankEntityButton);
await page.waitForTextInField(selectors.clientBillingData.swiftBic, 'Gotham City Bank');
let newcode = await page.waitToGetProperty(selectors.clientBillingData.swiftBic, 'value');
const newcode = await page.waitToGetProperty(selectors.clientBillingData.swiftBic, 'value');
expect(newcode).toEqual('GTHMCT Gotham City Bank');
});
it(`should confirm the IBAN pay method was sucessfully saved`, async() => {
let payMethod = await page.waitToGetProperty(selectors.clientBillingData.payMethod, 'value');
xit(`should confirm the IBAN pay method was sucessfully saved`, async() => {
const payMethod = await page.waitToGetProperty(selectors.clientBillingData.payMethod, 'value');
expect(payMethod).toEqual('PayMethod with IBAN');
});
@ -60,46 +61,45 @@ describe('Client Edit billing data path', () => {
});
it(`should save the form with all its new data`, async() => {
await page.waitFor(3000);
await page.waitForWatcherData(selectors.clientBillingData.watcher);
await page.waitToClick(selectors.clientBillingData.saveButton);
let snackbarMessage = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(snackbarMessage).toEqual('Notification sent!');
expect(message.text).toBe('Notification sent!');
});
it('should confirm the due day have been edited', async() => {
let dueDate = await page.waitToGetProperty(selectors.clientBillingData.dueDay, 'value');
const dueDate = await page.waitToGetProperty(selectors.clientBillingData.dueDay, 'value');
expect(dueDate).toEqual('60');
});
it('should confirm the IBAN was saved', async() => {
let IBAN = await page.waitToGetProperty(selectors.clientBillingData.IBAN, 'value');
const IBAN = await page.waitToGetProperty(selectors.clientBillingData.IBAN, 'value');
expect(IBAN).toEqual('ES9121000418450200051332');
});
it('should confirm the swift / BIC code was saved', async() => {
let code = await page.waitToGetProperty(selectors.clientBillingData.swiftBic, 'value');
const code = await page.waitToGetProperty(selectors.clientBillingData.swiftBic, 'value');
expect(code).toEqual('CAIXESBB Caixa Bank');
});
it('should confirm Received LCR checkbox is checked', async() => {
let result = await page.checkboxState(selectors.clientBillingData.receivedCoreLCRCheckbox);
const result = await page.checkboxState(selectors.clientBillingData.receivedCoreLCRCheckbox);
expect(result).toBe('checked');
});
it('should confirm Received core VNL checkbox is unchecked', async() => {
let result = await page.checkboxState(selectors.clientBillingData.receivedCoreVNLCheckbox);
const result = await page.checkboxState(selectors.clientBillingData.receivedCoreVNLCheckbox);
expect(result).toBe('unchecked');
});
it('should confirm Received B2B VNL checkbox is unchecked', async() => {
let result = await page.checkboxState(selectors.clientBillingData.receivedB2BVNLCheckbox);
const result = await page.checkboxState(selectors.clientBillingData.receivedB2BVNLCheckbox);
expect(result).toBe('unchecked');
});

View File

@ -28,9 +28,9 @@ describe('Client Add address path', () => {
await page.write(selectors.clientAddresses.phone, '999887744');
await page.write(selectors.clientAddresses.mobileInput, '999887744');
await page.waitToClick(selectors.clientFiscalData.saveButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Some fields are invalid');
expect(message.text).toBe('Some fields are invalid');
});
it('should confirm that the city and province are propertly filled', async() => {
@ -48,25 +48,25 @@ describe('Client Add address path', () => {
await page.write(selectors.clientAddresses.consignee, 'Bruce Bunner');
await page.write(selectors.clientAddresses.streetAddress, '320 Park Avenue New York');
await page.waitToClick(selectors.clientAddresses.saveButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Incoterms is required for a non UEE member');
expect(message.text).toBe('Incoterms is required for a non UEE member');
});
it(`should receive an error after clicking save button as customsAgent is empty`, async() => {
await page.autocompleteSearch(selectors.clientAddresses.incoterms, 'Free Alongside Ship');
await page.waitToClick(selectors.clientAddresses.saveButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Customs agent is required for a non UEE member');
expect(message.text).toBe('Customs agent is required for a non UEE member');
});
it(`should create a new address with all it's data`, async() => {
await page.autocompleteSearch(selectors.clientAddresses.customsAgent, 'Agent one');
await page.waitToClick(selectors.clientAddresses.saveButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it(`should navigate back to the addresses index`, async() => {
@ -82,9 +82,9 @@ describe('Client Add address path', () => {
it('should click on the make default icon of the second address', async() => {
await page.waitToClick(selectors.clientAddresses.secondMakeDefaultStar);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it(`should confirm the default address is the expected one`, async() => {
@ -104,9 +104,9 @@ describe('Client Add address path', () => {
await page.waitForWatcherData(selectors.clientAddresses.watcher);
await page.waitToClick(selectors.clientAddresses.activeCheckbox);
await page.waitToClick(selectors.clientAddresses.saveButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('The default consignee can not be unchecked');
expect(message.text).toBe('The default consignee can not be unchecked');
});
it(`should go back to the addreses section by clicking the cancel button`, async() => {

View File

@ -26,18 +26,18 @@ describe('Client add address notes path', () => {
await page.waitToClick(selectors.clientAddresses.addObservationButton);
await page.write(selectors.clientAddresses.firstObservationDescription, 'first description');
await page.waitToClick(selectors.clientAddresses.saveButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Some fields are invalid');
expect(message.text).toBe('Some fields are invalid');
});
it('should not save an observation type without description', async() => {
await page.clearInput(selectors.clientAddresses.firstObservationDescription);
await page.autocompleteSearch(selectors.clientAddresses.firstObservationType, 'comercial');
await page.waitToClick(selectors.clientAddresses.saveButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Some fields are invalid');
expect(message.text).toBe('Some fields are invalid');
});
it('should create two new observations', async() => {
@ -46,8 +46,8 @@ describe('Client add address notes path', () => {
await page.autocompleteSearch(selectors.clientAddresses.secondObservationType, 'observation one');
await page.write(selectors.clientAddresses.secondObservationDescription, 'second description');
await page.waitToClick(selectors.clientAddresses.saveButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
});

View File

@ -21,16 +21,14 @@ describe('Client Edit web access path', () => {
await page.clearInput(selectors.clientWebAccess.userName);
await page.write(selectors.clientWebAccess.userName, 'Hulk');
await page.waitToClick(selectors.clientWebAccess.saveButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it('should confirm web access is now unchecked', async() => {
await page.waitToClick(selectors.clientBasicData.basicDataButton);
await page.wait(selectors.clientBasicData.name);
await page.waitToClick(selectors.clientsIndex.othersButton);
await page.waitToClick(selectors.clientWebAccess.webAccessButton);
await page.accessToSection('client.card.basicData');
await page.accessToSection('client.card.webAccess');
const result = await page.checkboxState(selectors.clientWebAccess.enableWebAccessCheckbox);
expect(result).toBe('unchecked');

View File

@ -29,9 +29,9 @@ describe('Client Add notes path', () => {
await page.waitFor(selectors.clientNotes.note);
await page.type(`${selectors.clientNotes.note} textarea`, 'Meeting with Black Widow 21st 9am');
await page.waitToClick(selectors.clientNotes.saveButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it('should confirm the note was created', async() => {

View File

@ -25,9 +25,9 @@ describe('Client Add credit path', () => {
await page.clearInput(selectors.clientCredit.credit);
await page.write(selectors.clientCredit.credit, '999');
await page.waitToClick(selectors.clientCredit.saveButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it('should confirm the credit was updated', async() => {

View File

@ -24,9 +24,9 @@ describe('Client Add greuge path', () => {
it(`should receive an error if all fields are empty but date and type on submit`, async() => {
await page.autocompleteSearch(selectors.clientGreuge.type, 'Diff');
await page.waitToClick(selectors.clientGreuge.saveButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Some fields are invalid');
expect(message.text).toBe('Some fields are invalid');
});
it(`should create a new greuge with all its data`, async() => {
@ -34,9 +34,9 @@ describe('Client Add greuge path', () => {
await page.waitForTextInField(selectors.clientGreuge.amount, '999');
await page.write(selectors.clientGreuge.description, 'new armor for Batman!');
await page.waitToClick(selectors.clientGreuge.saveButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it('should confirm the greuge was added to the list', async() => {

View File

@ -30,9 +30,9 @@ describe('Client lock verified data path', () => {
await page.clearInput(selectors.clientFiscalData.socialName);
await page.write(selectors.clientFiscalData.socialName, 'Captain America Civil War');
await page.waitToClick(selectors.clientFiscalData.saveButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it('should confirm the social name have been edited', async() => {
@ -60,9 +60,9 @@ describe('Client lock verified data path', () => {
await page.waitToClick(selectors.clientFiscalData.verifiedDataCheckbox);
await page.waitToClick(selectors.clientFiscalData.saveButton);
await page.waitToClick(selectors.clientFiscalData.acceptDuplicationButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it('should confirm Verified data checkbox is checked', async() => {
@ -77,9 +77,9 @@ describe('Client lock verified data path', () => {
await page.clearInput(selectors.clientFiscalData.socialName);
await page.write(selectors.clientFiscalData.socialName, 'Ant man and the Wasp');
await page.waitToClick(selectors.clientFiscalData.saveButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it('should again confirm the social name have been edited', async() => {
@ -107,9 +107,9 @@ describe('Client lock verified data path', () => {
await page.clearInput(selectors.clientFiscalData.socialName);
await page.write(selectors.clientFiscalData.socialName, 'This wont happen');
await page.waitToClick(selectors.clientFiscalData.saveButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual(`You can't make changes on a client with verified data`);
expect(message.text).toBe(`You can't make changes on a client with verified data`);
});
});
@ -131,9 +131,9 @@ describe('Client lock verified data path', () => {
await page.clearInput(selectors.clientFiscalData.socialName);
await page.write(selectors.clientFiscalData.socialName, 'new social name edition');
await page.waitToClick(selectors.clientFiscalData.saveButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it('should now confirm the social name have been edited once and for all', async() => {

View File

@ -20,14 +20,13 @@ describe('Client log path', () => {
await page.clearInput(selectors.clientBasicData.name);
await page.write(selectors.clientBasicData.name, 'this is a test');
await page.waitToClick(selectors.clientBasicData.saveButton);
let result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it('should navigate to the log section', async() => {
await page.waitToClick(selectors.clientLog.logButton);
await page.waitForState('client.card.log');
await page.accessToSection('client.card.log');
});
it('should check the previous value of the last logged change', async() => {

View File

@ -18,9 +18,9 @@ describe('Client balance path', () => {
it('should now edit the local user config data', async() => {
await page.waitToClick(selectors.globalItems.userMenuButton);
await page.autocompleteSearch(selectors.globalItems.userLocalCompany, 'CCs');
let result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it('should access to the balance section to check the data shown matches the local settings', async() => {
@ -33,9 +33,9 @@ describe('Client balance path', () => {
it('should now clear the user local settings', async() => {
await page.waitToClick(selectors.globalItems.userMenuButton);
await page.clearInput(selectors.globalItems.userConfigThirdAutocomplete);
let result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toContain('Data saved!');
expect(message.type).toBe('success');
});
it('should click the new payment button', async() => {
@ -48,9 +48,9 @@ describe('Client balance path', () => {
await page.waitToClick(selectors.clientBalance.newPaymentButton);
await page.autocompleteSearch(selectors.clientBalance.newPaymentBank, 'Pay on receipt');
await page.waitToClick(selectors.clientBalance.saveButton);
let result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toContain('Data saved!');
expect(message.type).toBe('success');
});
it('should check balance is now 0 and the company is now VNL becouse the user local settings were removed', async() => {
@ -67,13 +67,11 @@ describe('Client balance path', () => {
it('should create a new payment that sets the balance to positive value', async() => {
await page.waitToClick(selectors.clientBalance.newPaymentButton);
await page.waitFor(3000); // didn't manage to make this dynamic to allow clearInput to find the icon clear... :(
await page.clearInput(selectors.clientBalance.newPaymentAmount);
await page.write(selectors.clientBalance.newPaymentAmount, '100');
await page.overwrite(selectors.clientBalance.newPaymentAmount, '100');
await page.waitToClick(selectors.clientBalance.saveButton);
let result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toContain('Data saved!');
expect(message.type).toBe('success');
});
it('should check balance is now -100', async() => {
@ -85,14 +83,11 @@ describe('Client balance path', () => {
it('should create a new payment that sets the balance back to the original negative value', async() => {
await page.waitToClick(selectors.clientBalance.newPaymentButton);
await page.waitFor(3000); // didn't manage to make this dynamic to allow clearInput to find the icon clear... :(
await page.waitForSelector('.vn-dialog.vn-popup.shown', {visible: true});
await page.clearInput(selectors.clientBalance.newPaymentAmount);
await page.write(selectors.clientBalance.newPaymentAmount, '-150');
await page.overwrite(selectors.clientBalance.newPaymentAmount, '-150');
await page.waitToClick(selectors.clientBalance.saveButton);
let result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toContain('Data saved!');
expect(message.type).toBe('success');
});
it('should check balance is now 50', async() => {
@ -113,8 +108,7 @@ describe('Client balance path', () => {
it('should now search for the user Petter Parker', async() => {
await page.accessToSearchResult('Petter Parker');
await page.waitToClick(selectors.clientBalance.balanceButton);
await page.waitForState('client.card.balance.index');
await page.accessToSection('client.card.balance.index');
});
it('should not be able to click the new payment button as it isnt present', async() => {

View File

@ -16,7 +16,6 @@ describe('User config', () => {
describe('as salesPerson', () => {
it('should login', async() => {
await page.login('salesPerson');
await page.waitForContentLoaded();
});
it('should now open the user config form to check the settings', async() => {
@ -26,7 +25,6 @@ describe('User config', () => {
let expectedLocalWarehouse = await page
.expectPropertyValue(selectors.globalItems.userLocalWarehouse, 'value', '');
let expectedLocalBank = await page
.expectPropertyValue(selectors.globalItems.userLocalBank, 'value', '');
@ -50,7 +48,6 @@ describe('User config', () => {
describe('as employee', () => {
it('should log in', async() => {
await page.login('employee');
await page.waitForContentLoaded();
});
it('should open the user config form to check the settings', async() => {
@ -59,7 +56,6 @@ describe('User config', () => {
let expectedLocalWarehouse = await page
.expectPropertyValue(selectors.globalItems.userLocalWarehouse, 'value', '');
let expectedLocalBank = await page
.expectPropertyValue(selectors.globalItems.userLocalBank, 'value', '');
@ -83,16 +79,15 @@ describe('User config', () => {
await page.autocompleteSearch(selectors.globalItems.userLocalWarehouse, 'Warehouse Four');
await page.autocompleteSearch(selectors.globalItems.userLocalBank, 'Pay on receipt');
await page.autocompleteSearch(selectors.globalItems.userLocalCompany, 'VNL');
let result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toContain('Data saved!');
expect(message.type).toBe('success');
});
});
describe('as salesPerson 2nd run', () => {
it('should log in once more', async() => {
await page.login('salesPerson');
await page.waitForContentLoaded();
});
it('should again open the user config form to check the local settings', async() => {
@ -123,9 +118,9 @@ describe('User config', () => {
await page.clearInput(selectors.globalItems.userConfigFirstAutocomplete);
await page.clearInput(selectors.globalItems.userConfigSecondAutocomplete);
await page.clearInput(selectors.globalItems.userConfigThirdAutocomplete);
let result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toContain('Data saved!');
expect(message.type).toBe('success');
});
});
});

View File

@ -20,9 +20,9 @@ describe('Client DMS', () => {
it('should delete de first file', async() => {
await page.waitToClick(selectors.dms.deleteFileButton);
await page.respondToDialog('accept');
let result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it(`should click on the first document line worker name making the descriptor visible`, async() => {

View File

@ -22,17 +22,17 @@ describe('Client contacts', () => {
await page.write(selectors.clientContacts.name, 'Ansible');
await page.write(selectors.clientContacts.phone, 'FTL comms');
await page.waitToClick(selectors.clientContacts.saveButton);
let result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it('should delete de contact', async() => {
await page.waitFor(3000);
await page.waitToClick(selectors.clientContacts.deleteFirstPhone);
await page.waitToClick(selectors.clientContacts.saveButton);
let result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toContain('Data saved!');
expect(message.type).toBe('success');
});
});

View File

@ -24,9 +24,9 @@ describe('Worker basic data path', () => {
await page.clearInput(selectors.workerBasicData.phone);
await page.write(selectors.workerBasicData.phone, '444332211');
await page.waitToClick(selectors.workerBasicData.saveButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it('should reload the section then check the name was edited', async() => {

View File

@ -19,17 +19,17 @@ describe('Worker pbx path', () => {
it('should receive an error when the extension exceeds 4 characters', async() => {
await page.write(selectors.workerPbx.extension, '55555');
await page.waitToClick(selectors.workerPbx.saveButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Extension format is invalid');
expect(message.text).toBe('Extension format is invalid');
});
it('should sucessfully save the changes', async() => {
await page.clearInput(selectors.workerPbx.extension);
await page.write(selectors.workerPbx.extension, '4444');
await page.waitToClick(selectors.workerPbx.saveButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved! User must access web');
expect(message.text).toBe('Data saved! User must access web');
});
});

View File

@ -57,9 +57,9 @@ describe('Worker time control path', () => {
await page.waitForTextInElement(selectors.workerTimeControl.thirdEntryOfMonday, wrongScanTime);
await page.waitToClick(selectors.workerTimeControl.thirdEntryOfMondayDelete);
await page.respondToDialog('accept');
let result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Entry removed');
expect(message.text).toBe('Entry removed');
});
it(`should scan out Hank Pym to leave early`, async() => {

View File

@ -15,14 +15,14 @@ describe('Item summary path', () => {
});
it('should search for an item', async() => {
await page.clearInput(selectors.itemsIndex.topbarSearch);
await page.write(selectors.itemsIndex.topbarSearch, 'Ranged weapon');
await page.waitToClick(selectors.itemsIndex.searchButton);
await page.waitForNumberOfElements(selectors.itemsIndex.searchResult, 3);
await page.doSearch('Ranged weapon');
const nResults = await page.countElement(selectors.itemsIndex.searchResult);
await page.waitForTextInElement(selectors.itemsIndex.searchResult, 'Ranged weapon');
await page.waitToClick(selectors.itemsIndex.firstResultPreviewButton);
const isVisible = await page.isVisible(selectors.itemSummary.basicData);
expect(nResults).toBe(3);
expect(isVisible).toBeTruthy();
});
@ -67,12 +67,13 @@ describe('Item summary path', () => {
});
it('should search for other item', async() => {
await page.clearInput('vn-searchbar');
await page.write(selectors.itemsIndex.topbarSearch, 'Melee Reinforced');
await page.keyboard.press('Enter');
await page.waitForNumberOfElements(selectors.itemsIndex.searchResult, 2);
await page.doSearch('Melee Reinforced');
const nResults = await page.countElement(selectors.itemsIndex.searchResult);
await page.waitToClick(selectors.itemsIndex.firstResultPreviewButton);
await page.waitForSelector(selectors.itemSummary.basicData, {visible: true});
expect(nResults).toBe(2);
});
it(`should now check the item summary preview shows fields from basic data`, async() => {

View File

@ -34,9 +34,9 @@ describe('Item Edit basic data path', () => {
await page.waitToClick(selectors.itemBasicData.isActiveCheckbox);
await page.waitToClick(selectors.itemBasicData.priceInKgCheckbox);
await page.waitToClick(selectors.itemBasicData.submitBasicDataButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it(`should create a new intrastat`, async() => {
@ -53,9 +53,9 @@ describe('Item Edit basic data path', () => {
it('should save with the new intrastat', async() => {
await page.waitToClick(selectors.itemBasicData.submitBasicDataButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it(`should confirm the item name was edited`, async() => {

View File

@ -21,9 +21,9 @@ describe('Item edit tax path', () => {
await page.autocompleteSearch(selectors.itemTax.secondClass, 'General VAT');
await page.autocompleteSearch(selectors.itemTax.thirdClass, 'General VAT');
await page.waitToClick(selectors.itemTax.submitTaxButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it(`should confirm the first item tax class was edited`, async() => {

View File

@ -24,9 +24,9 @@ describe('Item create tags path', () => {
await page.clearInput(selectors.itemTags.seventhRelevancy);
await page.write(selectors.itemTags.seventhRelevancy, '4');
await page.waitToClick(selectors.itemTags.submitItemTagsButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it(`should confirm the fourth row data is the expected one`, async() => {

View File

@ -23,9 +23,9 @@ describe('Item create niche path', () => {
await page.autocompleteSearch(selectors.itemNiches.thirdWarehouse, 'Warehouse Two');
await page.write(selectors.itemNiches.thirdCode, 'A4');
await page.waitToClick(selectors.itemNiches.submitNichesButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it(`should confirm the first niche is the expected one`, async() => {

View File

@ -21,9 +21,9 @@ describe('Item Create botanical path', () => {
await page.autocompleteSearch(selectors.itemBotanical.genus, 'Abelia');
await page.autocompleteSearch(selectors.itemBotanical.species, 'dealbata');
await page.waitToClick(selectors.itemBotanical.submitBotanicalButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it(`should confirm the botanical for the item was created`, async() => {
@ -56,9 +56,9 @@ describe('Item Create botanical path', () => {
await page.autocompleteSearch(selectors.itemBotanical.genus, 'Abies');
await page.autocompleteSearch(selectors.itemBotanical.species, 'decurrens');
await page.waitToClick(selectors.itemBotanical.submitBotanicalButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it(`should confirm the botanical for the item was edited`, async() => {

View File

@ -21,9 +21,9 @@ describe('Item Create barcodes path', () => {
await page.waitToClick(selectors.itemBarcodes.addBarcodeButton);
await page.write(selectors.itemBarcodes.thirdCode, '5');
await page.waitToClick(selectors.itemBarcodes.submitBarcodesButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it(`should confirm the barcode 5 is created and it is now the third barcode as the first was deleted`, async() => {

View File

@ -16,13 +16,10 @@ describe('Item Create/Clone path', () => {
describe('create', () => {
it(`should search for the item Infinity Gauntlet to confirm it isn't created yet`, async() => {
await page.clearInput(selectors.itemsIndex.topbarSearch);
await page.write(selectors.itemsIndex.topbarSearch, 'Infinity Gauntlet');
await page.waitToClick(selectors.itemsIndex.searchButton);
await page.waitForNumberOfElements(selectors.itemsIndex.searchResult, 0);
const result = await page.countElement(selectors.itemsIndex.searchResult);
await page.doSearch('Infinity Gauntlet');
const nResults = await page.countElement(selectors.itemsIndex.searchResult);
expect(result).toEqual(0);
expect(nResults).toEqual(0);
});
it('should access to the create item view by clicking the create floating button', async() => {
@ -46,9 +43,9 @@ describe('Item Create/Clone path', () => {
await page.autocompleteSearch(selectors.itemCreateView.intrastat, 'Coral y materiales similares');
await page.autocompleteSearch(selectors.itemCreateView.origin, 'Holand');
await page.waitToClick(selectors.itemCreateView.createButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it('should confirm Infinity Gauntlet item was created', async() => {
@ -85,13 +82,10 @@ describe('Item Create/Clone path', () => {
});
it(`should search for the item Infinity Gauntlet`, async() => {
await page.clearInput(selectors.itemsIndex.topbarSearch);
await page.write(selectors.itemsIndex.topbarSearch, 'Infinity Gauntlet');
await page.waitToClick(selectors.itemsIndex.searchButton);
await page.waitForNumberOfElements(selectors.itemsIndex.searchResult, 1);
const result = await page.countElement(selectors.itemsIndex.searchResult);
await page.doSearch('Infinity Gauntlet');
const nResults = await page.countElement(selectors.itemsIndex.searchResult);
expect(result).toEqual(1);
expect(nResults).toEqual(1);
});
it(`should clone the Infinity Gauntlet`, async() => {
@ -102,14 +96,10 @@ describe('Item Create/Clone path', () => {
});
it('should search for the item Infinity Gauntlet and find two', async() => {
await page.waitToClick(selectors.itemTags.goToItemIndexButton);
await page.clearInput(selectors.itemsIndex.topbarSearch);
await page.write(selectors.itemsIndex.topbarSearch, 'Infinity Gauntlet');
await page.waitToClick(selectors.itemsIndex.searchButton);
await page.waitForNumberOfElements(selectors.itemsIndex.searchResult, 2);
const result = await page.countElement(selectors.itemsIndex.searchResult);
await page.doSearch('Infinity Gauntlet');
const nResults = await page.countElement(selectors.itemsIndex.searchResult);
expect(result).toEqual(2);
expect(nResults).toEqual(2);
});
});
});

View File

@ -18,9 +18,9 @@ describe('Item regularize path', () => {
await page.waitForSpinnerLoad();
await page.waitToClick(selectors.globalItems.userMenuButton);
await page.autocompleteSearch(selectors.globalItems.userLocalWarehouse, 'Warehouse Four');
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it('should check the local settings were saved', async() => {
@ -49,9 +49,9 @@ describe('Item regularize path', () => {
await page.write(selectors.itemDescriptor.regularizeQuantity, '100');
await page.autocompleteSearch(selectors.itemDescriptor.regularizeWarehouse, 'Warehouse One');
await page.waitToClick(selectors.itemDescriptor.regularizeSaveButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it('should click on the Tickets button of the top bar menu', async() => {
@ -65,12 +65,12 @@ describe('Item regularize path', () => {
});
it('should clear the user local settings now', async() => {
await page.waitForContentLoaded();
await page.waitToClick(selectors.globalItems.userMenuButton);
await page.waitForContentLoaded();
await page.clearInput(selectors.globalItems.userConfigFirstAutocomplete);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it('should search for the ticket with alias missing', async() => {
@ -112,9 +112,9 @@ describe('Item regularize path', () => {
await page.write(selectors.itemDescriptor.regularizeQuantity, '100');
await page.autocompleteSearch(selectors.itemDescriptor.regularizeWarehouse, 'Warehouse One');
await page.waitToClick(selectors.itemDescriptor.regularizeSaveButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it('should again click on the Tickets button of the top bar menu', async() => {

View File

@ -34,9 +34,9 @@ describe('Item index path', () => {
await page.waitToClick(selectors.itemsIndex.buyerCheckbox);
await page.waitToClick(selectors.itemsIndex.destinyCheckbox);
await page.waitToClick(selectors.itemsIndex.saveFieldsButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it('should navigate forth and back to see the images column is still visible', async() => {
@ -68,9 +68,9 @@ describe('Item index path', () => {
await page.waitToClick(selectors.itemsIndex.buyerCheckbox);
await page.waitToClick(selectors.itemsIndex.destinyCheckbox);
await page.waitToClick(selectors.itemsIndex.saveFieldsButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it('should now navigate forth and back to see the ids column is now visible', async() => {

View File

@ -15,12 +15,10 @@ describe('Item log path', () => {
});
it(`should search for the Knowledge artifact to confirm it isn't created yet`, async() => {
await page.write(selectors.itemsIndex.topbarSearch, 'Knowledge artifact');
await page.waitToClick(selectors.itemsIndex.searchButton);
await page.waitForNumberOfElements(selectors.itemsIndex.searchResult, 0);
const result = await page.countElement(selectors.itemsIndex.searchResult);
await page.doSearch('Knowledge artifact');
const nResults = await page.countElement(selectors.itemsIndex.searchResult);
expect(result).toEqual(0);
expect(nResults).toEqual(0);
});
it('should access to the create item view by clicking the create floating button', async() => {
@ -34,9 +32,9 @@ describe('Item log path', () => {
await page.autocompleteSearch(selectors.itemCreateView.intrastat, 'Coral y materiales similares');
await page.autocompleteSearch(selectors.itemCreateView.origin, 'Holand');
await page.waitToClick(selectors.itemCreateView.createButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it('should return to the items index by clicking the return to items button', async() => {

View File

@ -19,7 +19,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.waitForClassNotPresent(selectors.itemDescriptor.inactiveIcon, 'bright');
let darkIcon = await page.isVisible(selectors.itemDescriptor.inactiveIcon);
const darkIcon = await page.isVisible(selectors.itemDescriptor.inactiveIcon);
expect(darkIcon).toBeTruthy();
});
@ -27,15 +27,15 @@ describe('Item descriptor path', () => {
it('should set the item to inactive', async() => {
await page.waitToClick(selectors.itemBasicData.isActiveCheckbox);
await page.waitToClick(selectors.itemBasicData.submitBasicDataButton);
let result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it('should reload the section and check the inactive icon is bright', async() => {
await page.reloadSection('item.card.basicData');
await page.waitForClassPresent(selectors.itemDescriptor.inactiveIcon, 'bright');
let brightIcon = await page.isVisible(selectors.itemDescriptor.inactiveIcon);
const brightIcon = await page.isVisible(selectors.itemDescriptor.inactiveIcon);
expect(brightIcon).toBeTruthy();
});
@ -43,8 +43,8 @@ describe('Item descriptor path', () => {
it('should set the item back to active', async() => {
await page.waitToClick(selectors.itemBasicData.isActiveCheckbox);
await page.waitToClick(selectors.itemBasicData.submitBasicDataButton);
let result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
});

View File

@ -74,9 +74,9 @@ describe('Ticket List sale path', () => {
await page.keyboard.press('Enter');
await page.write(selectors.ticketSales.secondSaleQuantity, '1');
await page.keyboard.press('Enter');
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
// #1865
@ -84,9 +84,9 @@ describe('Ticket List sale path', () => {
await page.focusElement(selectors.ticketSales.secondSaleConceptCell);
await page.write(selectors.ticketSales.secondSaleConceptInput, 'Aegis of Valor');
await page.keyboard.press('Enter');
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it('should add a third empty item to the sale list', async() => {
@ -102,9 +102,9 @@ describe('Ticket List sale path', () => {
await page.waitToClick(selectors.ticketSales.thirdSaleCheckbox);
await page.waitToClick(selectors.ticketSales.deleteSaleButton);
await page.waitToClick(selectors.ticketSales.acceptDeleteLineButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it(`should verify there's only 1 single line remaining`, async() => {

View File

@ -19,245 +19,218 @@ xdescribe('Ticket Edit sale path', () => {
});
it(`should click on the first sale claim icon to navigate over there`, async() => {
const url = await nightmare
.waitToClick(selectors.ticketSales.firstSaleClaimIcon)
.wait(selectors.claimBasicData.claimState)
.parsedUrl();
await page.waitToClick(selectors.ticketSales.firstSaleClaimIcon);
await page.wait(selectors.claimBasicData.claimState);
const url = await page.parsedUrl();
expect(url.hash).toEqual('#!/claim/2/basic-data');
});
it('should navigate to the tickets index', async() => {
const url = await nightmare
.waitToClick(selectors.globalItems.applicationsMenuButton)
.wait(selectors.globalItems.applicationsMenuVisible)
.waitToClick(selectors.globalItems.ticketsButton)
.wait(selectors.ticketsIndex.topbarSearch)
.parsedUrl();
await page.waitToClick(selectors.globalItems.applicationsMenuButton);
await page.wait(selectors.globalItems.applicationsMenuVisible);
await page.waitToClick(selectors.globalItems.ticketsButton);
await page.wait(selectors.ticketsIndex.topbarSearch);
const url = await page.parsedUrl();
expect(url.hash).toEqual('#!/ticket/index');
});
it(`should search for a ticket and then navigate to it's sales`, async() => {
const url = await nightmare
.accessToSearchResult(16)
.accessToSection('ticket.card.sale')
.waitForURL('/sale')
.parsedUrl();
await page.accessToSearchResult(16);
await page.accessToSection('ticket.card.sale');
await page.waitForURL('/sale');
const url = await page.parsedUrl();
expect(url.hash).toContain('/sale');
});
it(`should check the zoomed image isn't present`, async() => {
const result = await nightmare
.countElement(selectors.ticketSales.firstSaleZoomedImage);
const result = await page.countElement(selectors.ticketSales.firstSaleZoomedImage);
expect(result).toEqual(0);
});
it(`should click on the thumbnail image of the 1st sale and see the zoomed image`, async() => {
const result = await nightmare
.clickIfVisible(selectors.ticketSales.firstSaleThumbnailImage)
.countElement(selectors.ticketSales.firstSaleZoomedImage);
await page.clickIfVisible(selectors.ticketSales.firstSaleThumbnailImage);
const result = await page.countElement(selectors.ticketSales.firstSaleZoomedImage);
expect(result).toEqual(1);
});
it(`should click on the zoomed image to close it`, async() => {
const result = await nightmare
.clickIfVisible(selectors.ticketSales.firstSaleZoomedImage)
.countElement(selectors.ticketSales.firstSaleZoomedImage);
await page.clickIfVisible(selectors.ticketSales.firstSaleZoomedImage);
const result = await page.countElement(selectors.ticketSales.firstSaleZoomedImage);
expect(result).toEqual(0);
});
it(`should confirm the item descriptor insnt visible yet`, async() => {
const visible = await nightmare
.isVisible(selectors.ticketSales.saleDescriptorPopover);
const visible = await page.isVisible(selectors.ticketSales.saleDescriptorPopover);
expect(visible).toBeFalsy();
});
it(`should click on the first sale ID making the item descriptor visible`, async() => {
const visible = await nightmare
.waitToClick(selectors.ticketSales.firstSaleId)
.waitImgLoad(selectors.ticketSales.firstSaleDescriptorImage)
.isVisible(selectors.ticketSales.saleDescriptorPopover);
await page.waitToClick(selectors.ticketSales.firstSaleId);
await page.waitImgLoad(selectors.ticketSales.firstSaleDescriptorImage);
const visible = await page.isVisible(selectors.ticketSales.saleDescriptorPopover);
expect(visible).toBeTruthy();
});
it(`should click on the descriptor image of the 1st sale and see the zoomed image`, async() => {
const result = await nightmare
.clickIfVisible('vn-item-descriptor img')
.countElement(selectors.ticketSales.firstSaleZoomedImage);
await page.clickIfVisible('vn-item-descriptor img');
const result = await page.countElement(selectors.ticketSales.firstSaleZoomedImage);
expect(result).toEqual(1);
});
it(`should now click on the zoomed image to close it`, async() => {
const result = await nightmare
.clickIfVisible(selectors.ticketSales.firstSaleZoomedImage)
.countElement(selectors.ticketSales.firstSaleZoomedImage);
await page.clickIfVisible(selectors.ticketSales.firstSaleZoomedImage);
const result = await page.countElement(selectors.ticketSales.firstSaleZoomedImage);
expect(result).toEqual(0);
});
it(`should click on the summary icon of the item-descriptor to access to the item summary`, async() => {
const url = await nightmare
.waitToClick(selectors.ticketSales.saleDescriptorPopoverSummaryButton)
.waitForURL('/summary')
.parsedUrl();
await page.waitToClick(selectors.ticketSales.saleDescriptorPopoverSummaryButton);
await page.waitForURL('/summary');
const url = await page.parsedUrl();
expect(url.hash).toContain('/summary');
});
it('should return to ticket sales section', async() => {
const url = await nightmare
.waitToClick(selectors.globalItems.applicationsMenuButton)
.wait(selectors.globalItems.applicationsMenuVisible)
.waitToClick(selectors.globalItems.ticketsButton)
.accessToSearchResult(16)
.accessToSection('ticket.card.sale')
.waitForURL('/sale')
.parsedUrl();
await page.waitToClick(selectors.globalItems.applicationsMenuButton);
await page.wait(selectors.globalItems.applicationsMenuVisible);
await page.waitToClick(selectors.globalItems.ticketsButton);
await page.accessToSearchResult(16);
await page.accessToSection('ticket.card.sale');
await page.waitForURL('/sale');
const url = await page.parsedUrl();
expect(url.hash).toContain('/sale');
});
it('should try to add a higher quantity value and then receive an error', async() => {
const result = await nightmare
.focusElement(selectors.ticketSales.firstSaleQuantityCell)
.write(selectors.ticketSales.firstSaleQuantity, '11\u000d')
.waitForLastSnackbar();
await page.focusElement(selectors.ticketSales.firstSaleQuantityCell);
await page.write(selectors.ticketSales.firstSaleQuantity, '11\u000d');
const message = await page.waitForSnackbar();
expect(result).toEqual('The new quantity should be smaller than the old one');
expect(message.text).toBe('The new quantity should be smaller than the old one');
});
it('should remove 1 from the first sale quantity', async() => {
const result = await nightmare
.focusElement(selectors.ticketSales.firstSaleQuantityCell)
.write(selectors.ticketSales.firstSaleQuantity, '9\u000d')
.waitForLastSnackbar();
await page.focusElement(selectors.ticketSales.firstSaleQuantityCell);
await page.write(selectors.ticketSales.firstSaleQuantity, '9\u000d');
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it('should update the price', async() => {
const result = await nightmare
.waitToClick(`${selectors.ticketSales.firstSalePrice} > span`)
.write(selectors.ticketSales.firstSalePriceInput, '5\u000d')
.waitForLastSnackbar();
await page.waitToClick(`${selectors.ticketSales.firstSalePrice} > span`);
await page.write(selectors.ticketSales.firstSalePriceInput, '5\u000d');
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it('should confirm the price have been updated', async() => {
const result = await nightmare
.waitToGetProperty(`${selectors.ticketSales.firstSalePrice} span`, 'innerText');
const result = await page.waitToGetProperty(`${selectors.ticketSales.firstSalePrice} span`, 'innerText');
expect(result).toContain('5.00');
});
it('should confirm the total price for that item have been updated', async() => {
const result = await nightmare
.waitToGetProperty(selectors.ticketSales.firstSaleImport, 'innerText');
const result = await page.waitToGetProperty(selectors.ticketSales.firstSaleImport, 'innerText');
expect(result).toContain('45.00');
});
it('should update the discount', async() => {
const result = await nightmare
.waitToClick(`${selectors.ticketSales.firstSaleDiscount} > span`)
.write(selectors.ticketSales.firstSaleDiscountInput, '50\u000d')
.waitForLastSnackbar();
await page.waitToClick(`${selectors.ticketSales.firstSaleDiscount} > span`);
await page.write(selectors.ticketSales.firstSaleDiscountInput, '50\u000d');
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it('should confirm the discount have been updated', async() => {
const result = await nightmare
.waitForTextInElement(`${selectors.ticketSales.firstSaleDiscount} > span`, '50.00%')
.waitToGetProperty(`${selectors.ticketSales.firstSaleDiscount} > span`, 'innerText');
await page.waitForTextInElement(`${selectors.ticketSales.firstSaleDiscount} > span`, '50.00%');
const result = await page.waitToGetProperty(`${selectors.ticketSales.firstSaleDiscount} > span`, 'innerText');
expect(result).toContain('50.00%');
});
it('should confirm the total import for that item have been updated', async() => {
const result = await nightmare
.waitForTextInElement(selectors.ticketSales.firstSaleImport, '22.50')
.waitToGetProperty(selectors.ticketSales.firstSaleImport, 'innerText');
await page.waitForTextInElement(selectors.ticketSales.firstSaleImport, '22.50');
const result = await page.waitToGetProperty(selectors.ticketSales.firstSaleImport, 'innerText');
expect(result).toContain('22.50');
});
it('should select the third sale and create a claim of it', async() => {
const url = await nightmare
.waitToClick(selectors.ticketSales.thirdSaleCheckbox)
.waitToClick(selectors.ticketSales.moreMenu)
.waitToClick(selectors.ticketSales.moreMenuCreateClaim)
.wait(selectors.claimBasicData.claimState)
.parsedUrl();
await page.waitToClick(selectors.ticketSales.thirdSaleCheckbox);
await page.waitToClick(selectors.ticketSales.moreMenu);
await page.waitToClick(selectors.ticketSales.moreMenuCreateClaim);
await page.wait(selectors.claimBasicData.claimState);
const url = await page.parsedUrl();
expect(url.hash).toContain('basic-data');
});
it('should click on the Claims button of the top bar menu', async() => {
const url = await nightmare
.waitToClick(selectors.globalItems.applicationsMenuButton)
.wait(selectors.globalItems.applicationsMenuVisible)
.waitToClick(selectors.globalItems.claimsButton)
.wait(selectors.claimsIndex.searchClaimInput)
.parsedUrl();
await page.waitToClick(selectors.globalItems.applicationsMenuButton);
await page.wait(selectors.globalItems.applicationsMenuVisible);
await page.waitToClick(selectors.globalItems.claimsButton);
await page.wait(selectors.claimsIndex.searchClaimInput);
const url = await page.parsedUrl();
expect(url.hash).toEqual('#!/claim/index');
});
it('should search for the claim with id 4', async() => {
const result = await nightmare
.write(selectors.claimsIndex.searchClaimInput, 4)
.waitToClick(selectors.claimsIndex.searchButton)
.waitForNumberOfElements(selectors.claimsIndex.searchResult, 1)
.countElement(selectors.claimsIndex.searchResult);
await page.write(selectors.claimsIndex.searchClaimInput, 4);
await page.waitToClick(selectors.claimsIndex.searchButton);
await page.waitForNumberOfElements(selectors.claimsIndex.searchResult, 1);
const result = await page.countElement(selectors.claimsIndex.searchResult);
expect(result).toEqual(1);
});
it('should click the Tickets button of the top bar menu', async() => {
const url = await nightmare
.waitToClick(selectors.globalItems.applicationsMenuButton)
.wait(selectors.globalItems.applicationsMenuVisible)
.waitToClick(selectors.globalItems.ticketsButton)
.wait(selectors.ticketsIndex.topbarSearch)
.parsedUrl();
await page.waitToClick(selectors.globalItems.applicationsMenuButton);
await page.wait(selectors.globalItems.applicationsMenuVisible);
await page.waitToClick(selectors.globalItems.ticketsButton);
await page.wait(selectors.ticketsIndex.topbarSearch);
const url = await page.parsedUrl();
expect(url.hash).toEqual('#!/ticket/index');
});
it('should search for a ticket then access to the sales section', async() => {
const url = await nightmare
.accessToSearchResult(16)
.accessToSection('ticket.card.sale')
.waitForURL('/sale')
.parsedUrl();
await page.accessToSearchResult(16);
await page.accessToSection('ticket.card.sale');
await page.waitForURL('/sale');
const url = await page.parsedUrl();
expect(url.hash).toContain('/sale');
});
it('should select the third sale and delete it', async() => {
const result = await nightmare
.waitToClick(selectors.ticketSales.thirdSaleCheckbox)
.waitToClick(selectors.ticketSales.deleteSaleButton)
.waitToClick(selectors.ticketSales.acceptDeleteLineButton)
.waitForSpinnerLoad()
.waitForLastSnackbar();
await page.waitToClick(selectors.ticketSales.thirdSaleCheckbox);
await page.waitToClick(selectors.ticketSales.deleteSaleButton);
await page.waitToClick(selectors.ticketSales.acceptDeleteLineButton);
await page.waitForSpinnerLoad();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it(`should confirm the third sale was deleted`, async() => {
const result = await nightmare
.countElement(selectors.ticketSales.saleLine);
const result = await page.countElement(selectors.ticketSales.saleLine);
expect(result).toEqual(3);
});
@ -265,67 +238,60 @@ xdescribe('Ticket Edit sale path', () => {
it('should select the second sale and transfer it to a valid ticket', async() => {
const targetTicketId = 12;
const result = await nightmare
.waitToClick(selectors.ticketSales.secondSaleCheckbox)
.waitToClick(selectors.ticketSales.transferSaleButton)
.focusElement(selectors.ticketSales.transferQuantityCell)
.write(selectors.ticketSales.transferQuantityInput, '10\u000d')
.write(selectors.ticketSales.moveToTicketInput, targetTicketId)
.waitToClick(selectors.ticketSales.moveToTicketButton)
.waitForURL(`ticket/${targetTicketId}/sale`)
.parsedUrl();
await page.waitToClick(selectors.ticketSales.secondSaleCheckbox);
await page.waitToClick(selectors.ticketSales.transferSaleButton);
await page.focusElement(selectors.ticketSales.transferQuantityCell);
await page.write(selectors.ticketSales.transferQuantityInput, '10\u000d');
await page.write(selectors.ticketSales.moveToTicketInput, targetTicketId);
await page.waitToClick(selectors.ticketSales.moveToTicketButton);
await page.waitForURL(`ticket/${targetTicketId}/sale`);
const result = await page.parsedUrl();
expect(result.hash).toContain(`ticket/${targetTicketId}/sale`);
});
it('should confirm the transfered line is the correct one', async() => {
const result = await nightmare
.wait(selectors.ticketSales.secondSaleText)
.waitToGetProperty(selectors.ticketSales.secondSaleText, 'innerText');
await page.wait(selectors.ticketSales.secondSaleText);
const result = await page.waitToGetProperty(selectors.ticketSales.secondSaleText, 'innerText');
expect(result).toContain(`Melee weapon heavy shield`);
});
it('should confirm the transfered quantity is the correct one', async() => {
const result = await nightmare
.waitToGetProperty(selectors.ticketSales.secondSaleQuantityCell, 'innerText');
const result = await page.waitToGetProperty(selectors.ticketSales.secondSaleQuantityCell, 'innerText');
expect(result).toContain('10');
});
it('should go back to the original ticket sales section', async() => {
const url = await nightmare
.waitToClick(selectors.ticketDescriptor.goBackToModuleIndexButton)
.accessToSearchResult(16)
.accessToSection('ticket.card.sale')
.waitForURL('/sale')
.parsedUrl();
await page.waitToClick(selectors.ticketDescriptor.goBackToModuleIndexButton);
await page.accessToSearchResult(16);
await page.accessToSection('ticket.card.sale');
await page.waitForURL('/sale');
const url = await page.parsedUrl();
expect(url.hash).toContain('/sale');
});
it(`should confirm the original ticket has still three lines`, async() => {
const result = await nightmare
.wait(selectors.ticketSales.saleLine)
.countElement(selectors.ticketSales.saleLine);
await page.wait(selectors.ticketSales.saleLine);
const result = await page.countElement(selectors.ticketSales.saleLine);
expect(result).toEqual(3);
});
it(`should confirm the second sale quantity is now half of it's original value after the transfer`, async() => {
const result = await nightmare
.waitToGetProperty(selectors.ticketSales.secondSaleQuantityCell, 'innerText');
const result = await page.waitToGetProperty(selectors.ticketSales.secondSaleQuantityCell, 'innerText');
expect(result).toContain('10');
});
it('should go back to the receiver ticket sales section', async() => {
const url = await nightmare
.waitToClick(selectors.ticketDescriptor.goBackToModuleIndexButton)
.accessToSearchResult(12)
.accessToSection('ticket.card.sale')
.waitForURL('/sale')
.parsedUrl();
await page.waitToClick(selectors.ticketDescriptor.goBackToModuleIndexButton);
await page.accessToSearchResult(12);
await page.accessToSection('ticket.card.sale');
await page.waitForURL('/sale');
const url = await page.parsedUrl();
expect(url.hash).toContain('/sale');
});
@ -333,44 +299,40 @@ xdescribe('Ticket Edit sale path', () => {
it('should transfer the sale back to the original ticket', async() => {
const targetTicketId = 16;
const result = await nightmare
.waitToClick(selectors.ticketSales.secondSaleCheckbox)
.waitToClick(selectors.ticketSales.transferSaleButton)
.write(selectors.ticketSales.moveToTicketInput, targetTicketId)
.waitToClick(selectors.ticketSales.moveToTicketButton)
.waitForURL(`ticket/${targetTicketId}/sale`)
.parsedUrl();
await page.waitToClick(selectors.ticketSales.secondSaleCheckbox);
await page.waitToClick(selectors.ticketSales.transferSaleButton);
await page.write(selectors.ticketSales.moveToTicketInput, targetTicketId);
await page.waitToClick(selectors.ticketSales.moveToTicketButton);
await page.waitForURL(`ticket/${targetTicketId}/sale`);
const result = await page.parsedUrl();
expect(result.hash).toContain(`ticket/${targetTicketId}/sale`);
});
it('should confirm the original ticket received the line', async() => {
const expectedLines = 4;
const result = await nightmare
.waitForNumberOfElements(selectors.ticketSales.saleLine, expectedLines)
.countElement(selectors.ticketSales.saleLine);
await page.waitForNumberOfElements(selectors.ticketSales.saleLine, expectedLines);
const result = await page.countElement(selectors.ticketSales.saleLine);
expect(result).toEqual(expectedLines);
});
it(`should throw an error when attempting to create a ticket for an inactive client`, async() => {
const result = await nightmare
.waitToClick(selectors.ticketSales.firstSaleCheckbox)
.waitToClick(selectors.ticketSales.transferSaleButton)
.waitToClick(selectors.ticketSales.moveToNewTicketButton)
.waitToClick(selectors.ticketSales.acceptDeleteTicketButton)
.waitForLastSnackbar();
await page.waitToClick(selectors.ticketSales.firstSaleCheckbox);
await page.waitToClick(selectors.ticketSales.transferSaleButton);
await page.waitToClick(selectors.ticketSales.moveToNewTicketButton);
await page.waitToClick(selectors.ticketSales.acceptDeleteTicketButton);
const message = await page.waitForSnackbar();
expect(result).toEqual(`You can't create a ticket for a inactive client`);
expect(message.text).toBe(`You can't create a ticket for a inactive client`);
});
it('should go now to the ticket sales section of an active, not frozen client', async() => {
const url = await nightmare
.waitToClick(selectors.ticketDescriptor.goBackToModuleIndexButton)
.accessToSearchResult(13)
.accessToSection('ticket.card.sale')
.waitForURL('/sale')
.parsedUrl();
await page.waitToClick(selectors.ticketDescriptor.goBackToModuleIndexButton);
await page.accessToSearchResult(13);
await page.accessToSection('ticket.card.sale');
await page.waitForURL('/sale');
const url = await page.parsedUrl();
expect(url.hash).toContain('/sale');
});
@ -378,118 +340,106 @@ xdescribe('Ticket Edit sale path', () => {
it(`should select all sales, tranfer them to a new ticket and delete the sender ticket as it would've been left empty`, async() => {
const senderTicketId = 13;
const url = await nightmare
.waitToClick(selectors.ticketSales.selectAllSalesCheckbox)
.waitToClick(selectors.ticketSales.transferSaleButton)
.waitToClick(selectors.ticketSales.moveToNewTicketButton)
.waitToClick(selectors.ticketSales.acceptDeleteTicketButton)
.wait((selector, ticketId) => {
return document.querySelector(selector).innerText.toLowerCase().indexOf(`${ticketId}`) == -1;
}, selectors.ticketDescriptor.idLabelValue, senderTicketId)
.parsedUrl();
await page.waitToClick(selectors.ticketSales.selectAllSalesCheckbox);
await page.waitToClick(selectors.ticketSales.transferSaleButton);
await page.waitToClick(selectors.ticketSales.moveToNewTicketButton);
await page.waitToClick(selectors.ticketSales.acceptDeleteTicketButton);
await page.wait((selector, ticketId) => {
return document.querySelector(selector).innerText.toLowerCase().indexOf(`${ticketId}`) == -1;
}, selectors.ticketDescriptor.idLabelValue, senderTicketId);
const url = await page.parsedUrl();
expect(url.hash).toContain('/sale');
});
it('should confirm the new ticket received the line', async() => {
const result = await nightmare
.countElement(selectors.ticketSales.saleLine);
const result = await page.countElement(selectors.ticketSales.saleLine);
expect(result).toEqual(1);
});
it('should check the first sale reserved icon isnt visible', async() => {
const result = await nightmare
.isVisible(selectors.ticketSales.firstSaleReservedIcon);
const result = await page.isVisible(selectors.ticketSales.firstSaleReservedIcon);
expect(result).toBeFalsy();
});
it('should mark the first sale as reserved', async() => {
const result = await nightmare
.waitToClick(selectors.ticketSales.firstSaleCheckbox)
.waitToClick(selectors.ticketSales.moreMenu)
.waitToClick(selectors.ticketSales.moreMenuReserve)
.waitForClassNotPresent(selectors.ticketSales.firstSaleReservedIcon, 'ng-hide')
.isVisible(selectors.ticketSales.firstSaleReservedIcon);
await page.waitToClick(selectors.ticketSales.firstSaleCheckbox);
await page.waitToClick(selectors.ticketSales.moreMenu);
await page.waitToClick(selectors.ticketSales.moreMenuReserve);
await page.waitForClassNotPresent(selectors.ticketSales.firstSaleReservedIcon, 'ng-hide');
const result = await page.isVisible(selectors.ticketSales.firstSaleReservedIcon);
expect(result).toBeTruthy();
});
it('should unmark the first sale as reserved', async() => {
const result = await nightmare
.waitToClick(selectors.ticketSales.moreMenu)
.waitToClick(selectors.ticketSales.moreMenuUnmarkReseved)
.waitForClassPresent(selectors.ticketSales.firstSaleReservedIcon, 'ng-hide')
.isVisible(selectors.ticketSales.firstSaleReservedIcon);
await page.waitToClick(selectors.ticketSales.moreMenu);
await page.waitToClick(selectors.ticketSales.moreMenuUnmarkReseved);
await page.waitForClassPresent(selectors.ticketSales.firstSaleReservedIcon, 'ng-hide');
const result = await page.isVisible(selectors.ticketSales.firstSaleReservedIcon);
expect(result).toBeFalsy();
});
it('should update all sales discount', async() => {
const result = await nightmare
.waitToClick(selectors.ticketSales.moreMenu)
.waitToClick(selectors.ticketSales.moreMenuUpdateDiscount)
// .write(selectors.ticketSales.moreMenuUpdateDiscountInput, 100) can't find the selector on app (deleted the selector), menu option was removed?
.write('body', '\u000d')
.waitForTextInElement(selectors.ticketSales.totalImport, '0.00')
.waitToGetProperty(selectors.ticketSales.totalImport, 'innerText');
await page.waitToClick(selectors.ticketSales.moreMenu);
await page.waitToClick(selectors.ticketSales.moreMenuUpdateDiscount);
// .write(selectors.ticketSales.moreMenuUpdateDiscountInput, 100) can't find the selector on app (deleted the selector), menu option was removed?
await page.write('body', '\u000d');
await page.waitForTextInElement(selectors.ticketSales.totalImport, '0.00');
const result = await page.waitToGetProperty(selectors.ticketSales.totalImport, 'innerText');
expect(result).toContain('0.00');
});
it('should log in as Production role and go to a target ticket summary', async() => {
const url = await nightmare
.loginAndModule('production', 'ticket')
.accessToSearchResult(13)
.waitForURL('/summary')
.parsedUrl();
await page.loginAndModule('production', 'ticket');
await page.accessToSearchResult(13);
await page.waitForURL('/summary');
const url = await page.parsedUrl();
expect(url.hash).toContain('/summary');
});
it(`should check it's state is deleted`, async() => {
const result = await nightmare
.waitToGetProperty(selectors.ticketDescriptor.stateLabelValue, 'innerText');
const result = await page.waitToGetProperty(selectors.ticketDescriptor.stateLabelValue, 'innerText');
expect(result).toEqual('State Eliminado');
});
describe('when state is preparation and loged as Production', () => {
it(`should not be able to edit the sale price`, async() => {
const result = await nightmare
.waitToClick(selectors.ticketDescriptor.goBackToModuleIndexButton)
.accessToSearchResult(8)
.accessToSection('ticket.card.sale')
.waitToClick(selectors.ticketSales.firstSalePrice)
.exists(selectors.ticketSales.firstSalePriceInput);
await page.waitToClick(selectors.ticketDescriptor.goBackToModuleIndexButton);
await page.accessToSearchResult(8);
await page.accessToSection('ticket.card.sale');
await page.waitToClick(selectors.ticketSales.firstSalePrice);
const result = await page.exists(selectors.ticketSales.firstSalePriceInput);
expect(result).toBeFalsy();
});
it(`should not be able to edit the sale discount`, async() => {
const result = await nightmare
.waitToClick(selectors.ticketSales.firstSaleDiscount)
.exists(selectors.ticketSales.firstSaleDiscountInput);
await page.waitToClick(selectors.ticketSales.firstSaleDiscount);
const result = await page.exists(selectors.ticketSales.firstSaleDiscountInput);
expect(result).toBeFalsy();
});
it(`should not be able to edit the sale state`, async() => {
const result = await nightmare
.waitToClick(selectors.ticketSales.stateMenuButton)
.exists(selectors.ticketSales.stateMenuOptions);
await page.waitToClick(selectors.ticketSales.stateMenuButton);
const result = await page.exists(selectors.ticketSales.stateMenuOptions);
expect(result).toBeFalsy();
});
it('should log in as salesPerson then go to the sales of a target ticket', async() => {
const url = await nightmare
.loginAndModule('salesPerson', 'ticket')
.accessToSearchResult(8)
.accessToSection('ticket.card.sale')
.waitForURL('/sale')
.parsedUrl();
await page.loginAndModule('salesPerson', 'ticket');
await page.accessToSearchResult(8);
await page.accessToSection('ticket.card.sale');
await page.waitForURL('/sale');
const url = await page.parsedUrl();
expect(url.hash).toContain('/sale');
});
@ -497,25 +447,22 @@ xdescribe('Ticket Edit sale path', () => {
describe('when state is preparation and loged as salesPerson', () => {
it(`shouldn't be able to edit the sale price`, async() => {
const result = await nightmare
.waitToClick(selectors.ticketSales.firstSalePrice)
.exists(selectors.ticketSales.firstSalePriceInput);
await page.waitToClick(selectors.ticketSales.firstSalePrice);
const result = await page.exists(selectors.ticketSales.firstSalePriceInput);
expect(result).toBeFalsy();
});
it(`should be able to edit the sale discount`, async() => {
const result = await nightmare
.waitToClick(selectors.ticketSales.firstSaleDiscount)
.exists(selectors.ticketSales.firstSaleDiscountInput);
await page.waitToClick(selectors.ticketSales.firstSaleDiscount);
const result = await page.exists(selectors.ticketSales.firstSaleDiscountInput);
expect(result).toBeFalsy();
});
it(`should not be able to edit the sale state`, async() => {
const result = await nightmare
.waitToClick(selectors.ticketSales.stateMenuButton)
.exists(selectors.ticketSales.stateMenuOptions);
await page.waitToClick(selectors.ticketSales.stateMenuButton);
const result = await page.exists(selectors.ticketSales.stateMenuOptions);
expect(result).toBeFalsy();
});

View File

@ -22,9 +22,9 @@ describe('Ticket Create notes path', () => {
await page.autocompleteSearch(selectors.ticketNotes.firstNoteType, 'observation one');
await page.write(selectors.ticketNotes.firstDescription, 'description');
await page.waitToClick(selectors.ticketNotes.submitNotesButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
it('should confirm the note is the expected one', async() => {
@ -43,8 +43,8 @@ describe('Ticket Create notes path', () => {
it('should delete the note', async() => {
await page.waitToClick(selectors.ticketNotes.firstNoteRemoveButton);
await page.waitToClick(selectors.ticketNotes.submitNotesButton);
const result = await page.waitForLastSnackbar();
const message = await page.waitForSnackbar();
expect(result).toEqual('Data saved!');
expect(message.type).toBe('success');
});
});

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