diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 000000000..f0821349b Binary files /dev/null and b/.DS_Store differ diff --git a/.gitignore b/.gitignore index 8cb76a829..f4b1ab270 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ e2e/dms/*/ !e2e/dms/c4c !e2e/dms/c81 !e2e/dms/ecc +!e2e/dms/a87 npm-debug.log .eslintcache datasources.*.json diff --git a/README.md b/README.md index ae3d01f1d..8960c8d00 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/back/.DS_Store b/back/.DS_Store new file mode 100644 index 000000000..a15d86adb Binary files /dev/null and b/back/.DS_Store differ diff --git a/back/methods/.DS_Store b/back/methods/.DS_Store new file mode 100644 index 000000000..810045cc9 Binary files /dev/null and b/back/methods/.DS_Store differ diff --git a/back/methods/chat/send.js b/back/methods/chat/send.js index 53e5da7cc..6205bd03e 100644 --- a/back/methods/chat/send.js +++ b/back/methods/chat/send.js @@ -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); diff --git a/back/methods/collection/collectionFaults.js b/back/methods/collection/collectionFaults.js new file mode 100644 index 000000000..395c7e581 --- /dev/null +++ b/back/methods/collection/collectionFaults.js @@ -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]); + }; +}; diff --git a/back/methods/collection/getCollection.js b/back/methods/collection/getCollection.js new file mode 100644 index 000000000..caf9cc521 --- /dev/null +++ b/back/methods/collection/getCollection.js @@ -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; + }; +}; diff --git a/back/methods/collection/getSectors.js b/back/methods/collection/getSectors.js new file mode 100644 index 000000000..12ad0dc06 --- /dev/null +++ b/back/methods/collection/getSectors.js @@ -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; + }; +}; diff --git a/back/methods/collection/newCollection.js b/back/methods/collection/newCollection.js new file mode 100644 index 000000000..31e419b67 --- /dev/null +++ b/back/methods/collection/newCollection.js @@ -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; + } +}; diff --git a/back/methods/collection/spec/collectionFauls.spec.js b/back/methods/collection/spec/collectionFauls.spec.js new file mode 100644 index 000000000..210dcdf63 --- /dev/null +++ b/back/methods/collection/spec/collectionFauls.spec.js @@ -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'); + }); +}); diff --git a/back/methods/collection/spec/getCollection.spec.js b/back/methods/collection/spec/getCollection.spec.js new file mode 100644 index 000000000..44c7af62f --- /dev/null +++ b/back/methods/collection/spec/getCollection.spec.js @@ -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); + }); +}); diff --git a/back/methods/collection/spec/getSectors.spec.js b/back/methods/collection/spec/getSectors.spec.js new file mode 100644 index 000000000..d453220a0 --- /dev/null +++ b/back/methods/collection/spec/getSectors.spec.js @@ -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'); + }); +}); diff --git a/back/methods/collection/spec/newCollection.spec.js b/back/methods/collection/spec/newCollection.spec.js new file mode 100644 index 000000000..bd574db0f --- /dev/null +++ b/back/methods/collection/spec/newCollection.spec.js @@ -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); + }); +}); diff --git a/back/methods/collection/spec/updateCollectionSale.spec.js b/back/methods/collection/spec/updateCollectionSale.spec.js new file mode 100644 index 000000000..4695f6eec --- /dev/null +++ b/back/methods/collection/spec/updateCollectionSale.spec.js @@ -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); + }); +}); diff --git a/back/methods/collection/updateCollectionSale.js b/back/methods/collection/updateCollectionSale.js new file mode 100644 index 000000000..01575c972 --- /dev/null +++ b/back/methods/collection/updateCollectionSale.js @@ -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]); + }; +}; diff --git a/back/methods/dms/downloadFile.js b/back/methods/dms/downloadFile.js index f3096aabb..1b9150053 100644 --- a/back/methods/dms/downloadFile.js +++ b/back/methods/dms/downloadFile.js @@ -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); }; }; diff --git a/back/methods/dms/specs/downloadFile.spec.js b/back/methods/dms/specs/downloadFile.spec.js index 99820ed38..701a484df 100644 --- a/back/methods/dms/specs/downloadFile.spec.js +++ b/back/methods/dms/specs/downloadFile.spec.js @@ -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}}}; diff --git a/back/model-config.json b/back/model-config.json index 50603be3f..872f2239e 100644 --- a/back/model-config.json +++ b/back/model-config.json @@ -14,6 +14,9 @@ "Container": { "dataSource": "storage" }, + "Collection": { + "dataSource": "vn" + }, "Chat": { "dataSource": "vn" }, diff --git a/back/models/collection.js b/back/models/collection.js new file mode 100644 index 000000000..d3670d56b --- /dev/null +++ b/back/models/collection.js @@ -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); +}; diff --git a/back/models/collection.json b/back/models/collection.json new file mode 100644 index 000000000..3e428ef60 --- /dev/null +++ b/back/models/collection.json @@ -0,0 +1,12 @@ +{ + "name": "Collection", + "base": "VnModel", + "acls": [{ + "property": "validations", + "accessType": "EXECUTE", + "principalType": "ROLE", + "principalId": "$everyone", + "permission": "ALLOW" + }] +} + \ No newline at end of file diff --git a/back/models/dms.js b/back/models/dms.js index 9a06928db..8be539a0f 100644 --- a/back/models/dms.js +++ b/back/models/dms.js @@ -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}"`]; + }; }; diff --git a/back/models/specs/dms.spec.js b/back/models/specs/dms.spec.js new file mode 100644 index 000000000..8e76a4956 --- /dev/null +++ b/back/models/specs/dms.spec.js @@ -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(); + }); + }); +}); + diff --git a/db/changes/10161-postValentineDay/00-borrame.sql b/db/changes/10161-postValentineDay/00-borrame.sql new file mode 100644 index 000000000..22d1f5dec --- /dev/null +++ b/db/changes/10161-postValentineDay/00-borrame.sql @@ -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'); diff --git a/db/changes/10162-postValentineDay/00-collectionPlacement_get.sql b/db/changes/10162-postValentineDay/00-collectionPlacement_get.sql new file mode 100644 index 000000000..d89f6a801 --- /dev/null +++ b/db/changes/10162-postValentineDay/00-collectionPlacement_get.sql @@ -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 ; \ No newline at end of file diff --git a/db/changes/10162-postValentineDay/00-collection_faults.sql b/db/changes/10162-postValentineDay/00-collection_faults.sql new file mode 100644 index 000000000..5faa42ca4 --- /dev/null +++ b/db/changes/10162-postValentineDay/00-collection_faults.sql @@ -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 ; \ No newline at end of file diff --git a/db/changes/10162-postValentineDay/00-collection_updateSale.sql b/db/changes/10162-postValentineDay/00-collection_updateSale.sql new file mode 100644 index 000000000..cce8f4ff5 --- /dev/null +++ b/db/changes/10162-postValentineDay/00-collection_updateSale.sql @@ -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 ; \ No newline at end of file diff --git a/db/changes/10162-postValentineDay/00-coolerPathDetail.sql b/db/changes/10162-postValentineDay/00-coolerPathDetail.sql new file mode 100644 index 000000000..7d3006544 --- /dev/null +++ b/db/changes/10162-postValentineDay/00-coolerPathDetail.sql @@ -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`*/ \ No newline at end of file diff --git a/db/changes/10162-postValentineDay/00-sale_updateOriginalQuantity.sql b/db/changes/10162-postValentineDay/00-sale_updateOriginalQuantity.sql new file mode 100644 index 000000000..debdd3ac2 --- /dev/null +++ b/db/changes/10162-postValentineDay/00-sale_updateOriginalQuantity.sql @@ -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 ; \ No newline at end of file diff --git a/db/changes/10162-postValentineDay/00-sector_getWarehouse.sql b/db/changes/10162-postValentineDay/00-sector_getWarehouse.sql new file mode 100644 index 000000000..90611b559 --- /dev/null +++ b/db/changes/10162-postValentineDay/00-sector_getWarehouse.sql @@ -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 ; \ No newline at end of file diff --git a/db/changes/10170-NOFallas/00-aclWorkerDms.sql b/db/changes/10170-NOFallas/00-aclWorkerDms.sql new file mode 100644 index 000000000..46e56f77e --- /dev/null +++ b/db/changes/10170-NOFallas/00-aclWorkerDms.sql @@ -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'); diff --git a/db/changes/10180-holyWeek/00-ticketWeekly.sql b/db/changes/10180-holyWeek/00-ticketWeekly.sql new file mode 100644 index 000000000..05d65e124 --- /dev/null +++ b/db/changes/10180-holyWeek/00-ticketWeekly.sql @@ -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' ; diff --git a/db/changes/10180-holyWeek/00-ticket_cloneWeekly.sql b/db/changes/10180-holyWeek/00-ticket_cloneWeekly.sql new file mode 100644 index 000000000..544296feb --- /dev/null +++ b/db/changes/10180-holyWeek/00-ticket_cloneWeekly.sql @@ -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 ; + diff --git a/db/changes/10180-holyWeek/01-componentRenameMismatchXImbalance.sql b/db/changes/10180-holyWeek/01-componentRenameMismatchXImbalance.sql new file mode 100644 index 000000000..34dd3be3c --- /dev/null +++ b/db/changes/10180-holyWeek/01-componentRenameMismatchXImbalance.sql @@ -0,0 +1 @@ +UPDATE `vn`.`component` SET `code` = 'imbalance' WHERE (`id` = '36'); diff --git a/db/changes/10180-holyWeek/01-migrateFromTicketToTicketWeekly.sql b/db/changes/10180-holyWeek/01-migrateFromTicketToTicketWeekly.sql new file mode 100644 index 000000000..939a8e73c --- /dev/null +++ b/db/changes/10180-holyWeek/01-migrateFromTicketToTicketWeekly.sql @@ -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%'; + diff --git a/db/changes/10180-holyWeek/02-catalog_calculate.sql b/db/changes/10180-holyWeek/02-catalog_calculate.sql new file mode 100644 index 000000000..eeadb7241 --- /dev/null +++ b/db/changes/10180-holyWeek/02-catalog_calculate.sql @@ -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 ; + diff --git a/db/changes/10180-holyWeek/02-catalog_componentCalculate.sql b/db/changes/10180-holyWeek/02-catalog_componentCalculate.sql new file mode 100644 index 000000000..04ec1330a --- /dev/null +++ b/db/changes/10180-holyWeek/02-catalog_componentCalculate.sql @@ -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 ; + diff --git a/db/changes/10180-holyWeek/02-catalog_componentPrepare.sql b/db/changes/10180-holyWeek/02-catalog_componentPrepare.sql new file mode 100644 index 000000000..98b93a97e --- /dev/null +++ b/db/changes/10180-holyWeek/02-catalog_componentPrepare.sql @@ -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 ; + diff --git a/db/changes/10180-holyWeek/02-catalog_componentPurge.sql b/db/changes/10180-holyWeek/02-catalog_componentPurge.sql new file mode 100644 index 000000000..2b744b5f0 --- /dev/null +++ b/db/changes/10180-holyWeek/02-catalog_componentPurge.sql @@ -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 ; +; diff --git a/db/changes/10180-holyWeek/02-order_confirmWithUser.sql b/db/changes/10180-holyWeek/02-order_confirmWithUser.sql new file mode 100644 index 000000000..c9acdc038 --- /dev/null +++ b/db/changes/10180-holyWeek/02-order_confirmWithUser.sql @@ -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 ; \ No newline at end of file diff --git a/db/changes/10180-holyWeek/02-sale_calculateComponent.sql b/db/changes/10180-holyWeek/02-sale_calculateComponent.sql new file mode 100644 index 000000000..979608a35 --- /dev/null +++ b/db/changes/10180-holyWeek/02-sale_calculateComponent.sql @@ -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 ; + diff --git a/db/changes/10180-holyWeek/02-ticketCalculateClon.sql b/db/changes/10180-holyWeek/02-ticketCalculateClon.sql new file mode 100644 index 000000000..6c9518b3b --- /dev/null +++ b/db/changes/10180-holyWeek/02-ticketCalculateClon.sql @@ -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 ; + diff --git a/db/changes/10180-holyWeek/02-ticketCalculateSaleForcePrice.sql b/db/changes/10180-holyWeek/02-ticketCalculateSaleForcePrice.sql new file mode 100644 index 000000000..99ecf739e --- /dev/null +++ b/db/changes/10180-holyWeek/02-ticketCalculateSaleForcePrice.sql @@ -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 ; + diff --git a/db/changes/10180-holyWeek/02-ticketComponentUpdateSale.sql b/db/changes/10180-holyWeek/02-ticketComponentUpdateSale.sql new file mode 100644 index 000000000..b58189ae6 --- /dev/null +++ b/db/changes/10180-holyWeek/02-ticketComponentUpdateSale.sql @@ -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 ; + diff --git a/db/changes/10180-holyWeek/02-ticket_componentMakeUpdate.sql b/db/changes/10180-holyWeek/02-ticket_componentMakeUpdate.sql new file mode 100644 index 000000000..7fdf3f193 --- /dev/null +++ b/db/changes/10180-holyWeek/02-ticket_componentMakeUpdate.sql @@ -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 ; \ No newline at end of file diff --git a/db/changes/10180-holyWeek/02-ticket_componentPreview.sql b/db/changes/10180-holyWeek/02-ticket_componentPreview.sql new file mode 100644 index 000000000..d69435bb7 --- /dev/null +++ b/db/changes/10180-holyWeek/02-ticket_componentPreview.sql @@ -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 ; + diff --git a/db/changes/10180-holyWeek/02-ticket_priceDifference.sql b/db/changes/10180-holyWeek/02-ticket_priceDifference.sql new file mode 100644 index 000000000..b80ea7f88 --- /dev/null +++ b/db/changes/10180-holyWeek/02-ticket_priceDifference.sql @@ -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 ; + diff --git a/db/changes/10180-holyWeek/02-ticket_recalcComponents.sql b/db/changes/10180-holyWeek/02-ticket_recalcComponents.sql new file mode 100644 index 000000000..9ac4942f9 --- /dev/null +++ b/db/changes/10180-holyWeek/02-ticket_recalcComponents.sql @@ -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 ; + diff --git a/db/changes/10180-holyWeek/02-ticket_recalcComponentsForcePrice__.sql b/db/changes/10180-holyWeek/02-ticket_recalcComponentsForcePrice__.sql new file mode 100644 index 000000000..995bfbfcd --- /dev/null +++ b/db/changes/10180-holyWeek/02-ticket_recalcComponentsForcePrice__.sql @@ -0,0 +1,2 @@ +USE `vn`; +DROP procedure IF EXISTS `ticket_recalcComponentsForcePrice`; diff --git a/db/changes/10180-holyWeek/02-ticket_withoutComponents.sql b/db/changes/10180-holyWeek/02-ticket_withoutComponents.sql new file mode 100644 index 000000000..de789b956 --- /dev/null +++ b/db/changes/10180-holyWeek/02-ticket_withoutComponents.sql @@ -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 ; + diff --git a/db/changes/10180-holyWeek/03-ekt_load.sql b/db/changes/10180-holyWeek/03-ekt_load.sql new file mode 100644 index 000000000..0c83569b8 --- /dev/null +++ b/db/changes/10180-holyWeek/03-ekt_load.sql @@ -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 \ No newline at end of file diff --git a/db/changes/10180-holyWeek/03-itemDiary.sql b/db/changes/10180-holyWeek/03-itemDiary.sql new file mode 100644 index 000000000..d30597e14 --- /dev/null +++ b/db/changes/10180-holyWeek/03-itemDiary.sql @@ -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 ; \ No newline at end of file diff --git a/db/changes/10180-holyWeek/03-ticketCalculateSaleForcePrice2__.sql b/db/changes/10180-holyWeek/03-ticketCalculateSaleForcePrice2__.sql new file mode 100644 index 000000000..a880135ba --- /dev/null +++ b/db/changes/10180-holyWeek/03-ticketCalculateSaleForcePrice2__.sql @@ -0,0 +1,2 @@ +USE `vn`; +DROP procedure IF EXISTS `ticketCalculateSaleForcePrice2`; \ No newline at end of file diff --git a/db/changes/10180-holyWeek/03-ticketCalculateSaleForcePrice__ .sql b/db/changes/10180-holyWeek/03-ticketCalculateSaleForcePrice__ .sql new file mode 100644 index 000000000..d7eb5d32b --- /dev/null +++ b/db/changes/10180-holyWeek/03-ticketCalculateSaleForcePrice__ .sql @@ -0,0 +1,2 @@ +USE `vn`; +DROP procedure IF EXISTS `ticketCalculateSaleForcePrice`; \ No newline at end of file diff --git a/db/changes/10180-holyWeek/03-ticketCalculateSale__.sql b/db/changes/10180-holyWeek/03-ticketCalculateSale__.sql new file mode 100644 index 000000000..acefc29d5 --- /dev/null +++ b/db/changes/10180-holyWeek/03-ticketCalculateSale__.sql @@ -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 ; + diff --git a/db/changes/10180-holyWeek/03-ticket_componentUpdate__.sql b/db/changes/10180-holyWeek/03-ticket_componentUpdate__.sql new file mode 100644 index 000000000..f75f157e8 --- /dev/null +++ b/db/changes/10180-holyWeek/03-ticket_componentUpdate__.sql @@ -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 ; +; diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index effd1a348..792787154 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -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 diff --git a/db/dump/structure.sql b/db/dump/structure.sql index 8e783c833..2a1a168d7 100644 --- a/db/dump/structure.sql +++ b/db/dump/structure.sql @@ -4055,16 +4055,16 @@ BEGIN * La tabla mana_spellers es una caché * */ - - UPDATE mana_spellers me - JOIN - (SELECT Id_Trabajador, FLOOR(SUM(importe)/12) as pesoCarteraMensual - FROM bs.vendedores - WHERE año * 100 + mes >= (YEAR(CURDATE()) -1) * 100 + MONTH(CURDATE()) - GROUP BY Id_Trabajador - ) lastYearSales USING(Id_Trabajador) - SET me.prices_modifier_rate = GREATEST(me.minRate,LEAST(me.maxRate,ROUND(- me.used/lastYearSales.pesoCarteraMensual,3))) ; - + + UPDATE mana_spellers me + JOIN + (SELECT Id_Trabajador, FLOOR(SUM(importe)/12) as pesoCarteraMensual + FROM bs.vendedores + WHERE año * 100 + mes >= (YEAR(CURDATE()) -1) * 100 + MONTH(CURDATE()) + GROUP BY Id_Trabajador + ) lastYearSales USING(Id_Trabajador) + SET me.prices_modifier_rate = GREATEST(me.minRate,LEAST(me.maxRate,ROUND(- me.used/lastYearSales.pesoCarteraMensual,3))) ; + END ;; DELIMITER ; /*!50003 SET sql_mode = @saved_sql_mode */ ; @@ -6703,9 +6703,9 @@ DELIMITER ; /*!50003 SET sql_mode = 'NO_ENGINE_SUBSTITUTION' */ ; DELIMITER ;; CREATE DEFINER=`root`@`%` PROCEDURE `cacheCalc_clean`() -BEGIN - DECLARE vCleanTime DATETIME DEFAULT TIMESTAMPADD(MINUTE, -5, NOW()); - DELETE FROM cache_calc WHERE expires < vCleanTime; +BEGIN + DECLARE vCleanTime DATETIME DEFAULT TIMESTAMPADD(MINUTE, -5, NOW()); + DELETE FROM cache_calc WHERE expires < vCleanTime; END ;; DELIMITER ; /*!50003 SET sql_mode = @saved_sql_mode */ ; @@ -6723,27 +6723,27 @@ DELIMITER ; /*!50003 SET sql_mode = 'NO_ENGINE_SUBSTITUTION' */ ; DELIMITER ;; CREATE DEFINER=`root`@`%` PROCEDURE `cache_calc_end`(IN `v_calc` INT) -BEGIN - DECLARE v_cache_name VARCHAR(255); - DECLARE v_params VARCHAR(255); - - -- Libera el bloqueo y actualiza la fecha de ultimo refresco. - - UPDATE cache_calc cc JOIN cache c ON c.id = cc.cache_id - SET - cc.last_refresh = NOW(), - cc.expires = ADDTIME(NOW(), c.lifetime), - cc.connection_id = NULL - WHERE cc.id = v_calc; - - SELECT c.name, ca.params INTO v_cache_name, v_params - FROM cache c - JOIN cache_calc ca ON c.id = ca.cache_id - WHERE ca.id = v_calc; - - IF v_cache_name IS NOT NULL THEN - DO RELEASE_LOCK(CONCAT_WS('/', v_cache_name, IFNULL(v_params, ''))); - END IF; +BEGIN + DECLARE v_cache_name VARCHAR(255); + DECLARE v_params VARCHAR(255); + + -- Libera el bloqueo y actualiza la fecha de ultimo refresco. + + UPDATE cache_calc cc JOIN cache c ON c.id = cc.cache_id + SET + cc.last_refresh = NOW(), + cc.expires = ADDTIME(NOW(), c.lifetime), + cc.connection_id = NULL + WHERE cc.id = v_calc; + + SELECT c.name, ca.params INTO v_cache_name, v_params + FROM cache c + JOIN cache_calc ca ON c.id = ca.cache_id + WHERE ca.id = v_calc; + + IF v_cache_name IS NOT NULL THEN + DO RELEASE_LOCK(CONCAT_WS('/', v_cache_name, IFNULL(v_params, ''))); + END IF; END ;; DELIMITER ; /*!50003 SET sql_mode = @saved_sql_mode */ ; @@ -6761,88 +6761,88 @@ DELIMITER ; /*!50003 SET sql_mode = 'NO_ENGINE_SUBSTITUTION' */ ; DELIMITER ;; CREATE DEFINER=`root`@`%` PROCEDURE `cache_calc_start`(OUT `v_calc` INT, INOUT `v_refresh` INT, IN `v_cache_name` VARCHAR(50), IN `v_params` VARCHAR(100)) -proc: BEGIN - DECLARE v_valid BOOL; - DECLARE v_lock_id VARCHAR(100); - DECLARE v_cache_id INT; - DECLARE v_expires DATETIME; - DECLARE v_clean_time DATETIME; - - DECLARE EXIT HANDLER FOR SQLEXCEPTION - BEGIN - IF v_lock_id IS NOT NULL THEN - DO RELEASE_LOCK(v_lock_id); - END IF; - - RESIGNAL; - END; - - SET v_params = IFNULL(v_params, ''); - - -- Si el servidor se ha reiniciado invalida todos los calculos. - - SELECT COUNT(*) > 0 INTO v_valid FROM cache_valid; - - IF !v_valid - THEN - DELETE FROM cache_calc; - INSERT INTO cache_valid (valid) VALUES (TRUE); - END IF; - - -- Obtiene un bloqueo exclusivo para que no haya problemas de concurrencia. - - SET v_lock_id = CONCAT_WS('/', v_cache_name, v_params); - - IF !GET_LOCK(v_lock_id, 30) - THEN - SET v_calc = NULL; - SET v_refresh = FALSE; - LEAVE proc; - END IF; - - -- Comprueba si el calculo solicitado existe y esta actualizado. - - SELECT c.id, ca.id, ca.expires - INTO v_cache_id, v_calc, v_expires - FROM cache c - LEFT JOIN cache_calc ca - ON ca.cache_id = c.id AND ca.params = v_params COLLATE 'utf8_general_ci' - WHERE c.name = v_cache_name COLLATE 'utf8_general_ci'; - - -- Si existe una calculo valido libera el bloqueo y devuelve su identificador. - - IF !v_refresh AND NOW() < v_expires - THEN - DO RELEASE_LOCK(v_lock_id); - SET v_refresh = FALSE; - LEAVE proc; - END IF; - - -- Si el calculo no existe le crea una entrada en la tabla de calculos. - - IF v_calc IS NULL - THEN - INSERT INTO cache_calc SET - cache_id = v_cache_id, - cacheName = v_cache_name, - params = v_params, - last_refresh = NULL, - expires = NULL, - connection_id = CONNECTION_ID(); - - SET v_calc = LAST_INSERT_ID(); - ELSE - UPDATE cache_calc - SET - last_refresh = NULL, - expires = NULL, - connection_id = CONNECTION_ID() - WHERE id = v_calc; - END IF; - - -- Si se debe recalcular mantiene el bloqueo y devuelve su identificador. - - SET v_refresh = TRUE; +proc: BEGIN + DECLARE v_valid BOOL; + DECLARE v_lock_id VARCHAR(100); + DECLARE v_cache_id INT; + DECLARE v_expires DATETIME; + DECLARE v_clean_time DATETIME; + + DECLARE EXIT HANDLER FOR SQLEXCEPTION + BEGIN + IF v_lock_id IS NOT NULL THEN + DO RELEASE_LOCK(v_lock_id); + END IF; + + RESIGNAL; + END; + + SET v_params = IFNULL(v_params, ''); + + -- Si el servidor se ha reiniciado invalida todos los calculos. + + SELECT COUNT(*) > 0 INTO v_valid FROM cache_valid; + + IF !v_valid + THEN + DELETE FROM cache_calc; + INSERT INTO cache_valid (valid) VALUES (TRUE); + END IF; + + -- Obtiene un bloqueo exclusivo para que no haya problemas de concurrencia. + + SET v_lock_id = CONCAT_WS('/', v_cache_name, v_params); + + IF !GET_LOCK(v_lock_id, 30) + THEN + SET v_calc = NULL; + SET v_refresh = FALSE; + LEAVE proc; + END IF; + + -- Comprueba si el calculo solicitado existe y esta actualizado. + + SELECT c.id, ca.id, ca.expires + INTO v_cache_id, v_calc, v_expires + FROM cache c + LEFT JOIN cache_calc ca + ON ca.cache_id = c.id AND ca.params = v_params COLLATE 'utf8_general_ci' + WHERE c.name = v_cache_name COLLATE 'utf8_general_ci'; + + -- Si existe una calculo valido libera el bloqueo y devuelve su identificador. + + IF !v_refresh AND NOW() < v_expires + THEN + DO RELEASE_LOCK(v_lock_id); + SET v_refresh = FALSE; + LEAVE proc; + END IF; + + -- Si el calculo no existe le crea una entrada en la tabla de calculos. + + IF v_calc IS NULL + THEN + INSERT INTO cache_calc SET + cache_id = v_cache_id, + cacheName = v_cache_name, + params = v_params, + last_refresh = NULL, + expires = NULL, + connection_id = CONNECTION_ID(); + + SET v_calc = LAST_INSERT_ID(); + ELSE + UPDATE cache_calc + SET + last_refresh = NULL, + expires = NULL, + connection_id = CONNECTION_ID() + WHERE id = v_calc; + END IF; + + -- Si se debe recalcular mantiene el bloqueo y devuelve su identificador. + + SET v_refresh = TRUE; END ;; DELIMITER ; /*!50003 SET sql_mode = @saved_sql_mode */ ; @@ -6860,24 +6860,24 @@ DELIMITER ; /*!50003 SET sql_mode = 'NO_ENGINE_SUBSTITUTION' */ ; DELIMITER ;; CREATE DEFINER=`root`@`%` PROCEDURE `cache_calc_unlock`(IN `v_calc` INT) -proc: BEGIN - DECLARE v_cache_name VARCHAR(50); - DECLARE v_params VARCHAR(100); - - IF v_calc IS NULL THEN - LEAVE proc; - END IF; - - SELECT c.name, ca.params INTO v_cache_name, v_params - FROM cache c - JOIN cache_calc ca ON c.id = ca.cache_id - WHERE ca.id = v_calc; - - DELETE FROM cache_calc WHERE id = v_calc; - - IF v_cache_name IS NOT NULL THEN - DO RELEASE_LOCK(CONCAT_WS('/', v_cache_name, IFNULL(v_params, ''))); - END IF; +proc: BEGIN + DECLARE v_cache_name VARCHAR(50); + DECLARE v_params VARCHAR(100); + + IF v_calc IS NULL THEN + LEAVE proc; + END IF; + + SELECT c.name, ca.params INTO v_cache_name, v_params + FROM cache c + JOIN cache_calc ca ON c.id = ca.cache_id + WHERE ca.id = v_calc; + + DELETE FROM cache_calc WHERE id = v_calc; + + IF v_cache_name IS NOT NULL THEN + DO RELEASE_LOCK(CONCAT_WS('/', v_cache_name, IFNULL(v_params, ''))); + END IF; END ;; DELIMITER ; /*!50003 SET sql_mode = @saved_sql_mode */ ; @@ -6896,9 +6896,9 @@ DELIMITER ; DELIMITER ;; CREATE DEFINER=`root`@`%` PROCEDURE `cache_clean`() NO SQL -BEGIN - CALL available_clean; - CALL visible_clean; +BEGIN + CALL available_clean; + CALL visible_clean; END ;; DELIMITER ; /*!50003 SET sql_mode = @saved_sql_mode */ ; @@ -6916,13 +6916,13 @@ DELIMITER ; /*!50003 SET sql_mode = 'NO_ENGINE_SUBSTITUTION' */ ; DELIMITER ;; CREATE DEFINER=`root`@`%` PROCEDURE `clean`() -BEGIN - - DECLARE vDateShort DATETIME; - - SET vDateShort = TIMESTAMPADD(MONTH, -1, CURDATE()); - - DELETE FROM cache.departure_limit WHERE Fecha < vDateShort; +BEGIN + + DECLARE vDateShort DATETIME; + + SET vDateShort = TIMESTAMPADD(MONTH, -1, CURDATE()); + + DELETE FROM cache.departure_limit WHERE Fecha < vDateShort; END ;; DELIMITER ; /*!50003 SET sql_mode = @saved_sql_mode */ ; @@ -8386,158 +8386,158 @@ DELIMITER ; /*!50003 SET sql_mode = 'NO_ENGINE_SUBSTITUTION' */ ; DELIMITER ;; 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 - ) - 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) - 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; +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 + ) + 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) + 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 ;; DELIMITER ; /*!50003 SET sql_mode = @saved_sql_mode */ ; @@ -8587,154 +8587,154 @@ CREATE DEFINER=`root`@`%` PROCEDURE `exchange_new`( IN `vAuction` SMALLINT, IN `vPackage` INT, IN `vPutOrderFk` INT) -BEGIN +BEGIN /** * Adds a new exchange, generates it's barcode and * inserts/updates the transaction. When the referenced * transaction exists as provisional, updates it with - * the new values. - */ - DECLARE vEkt INT; - DECLARE vRewriteKop INT DEFAULT NULL; - DECLARE vBarcode CHAR(15) DEFAULT NULL; - DECLARE vIsDuplicated BOOL; + * the new values. + */ + DECLARE vEkt INT; + DECLARE vRewriteKop INT DEFAULT NULL; + DECLARE vBarcode CHAR(15) DEFAULT NULL; + DECLARE vIsDuplicated BOOL; DECLARE vUpdateExistent BOOL DEFAULT FALSE; - DECLARE duplicateKey CONDITION FOR 1062; - - DECLARE CONTINUE HANDLER FOR duplicateKey - SET vIsDuplicated = TRUE; - - -- Generates the barcode - - IF vAgj != 0 AND vAgj IS NOT NULL - THEN - SET vBarcode = CONCAT( - LPAD(vAuction, 2, 0), - LPAD(IFNULL(vClock, 99), 2, 0), - LPAD(DAYOFYEAR(vDate), 3, 0), - IF(vClock IS NULL OR vClock = 99, - LPAD(vAgj, 7, 0), - CONCAT(LPAD(vAgj, 5, 0), '01') - ), - '0' - ); - END IF; - - -- Rewrites the kop parameter - - IF vKop IS NULL THEN - SELECT defaultKop INTO vKop FROM exchangeConfig; - END IF; - - SELECT e.kop INTO vRewriteKop - FROM mailSender e - JOIN mail m ON m.senderFk = e.id - WHERE m.id = vMailFk; - - SET vKop = IFNULL(vRewriteKop, vKop); - - -- Inserts the new transaction + DECLARE duplicateKey CONDITION FOR 1062; - SET vIsDuplicated = FALSE; - INSERT INTO ekt SET - barcode = IFNULL(vBarcode, barcode) - ,deliveryNumber = vDeliveryNumber - ,entryYear = YEAR(vDate) - ,fec = vDate - ,hor = vHour - ,ref = vRef - ,item = vItem - ,agj = vAgj - ,cat = vCat - ,pac = vPac - ,sub = vSub - ,kop = vKop - ,ptd = vPtd - ,pro = vPro - ,ori = vOrigin - ,ptj = vPtj - ,qty = vQuantiy - ,pri = vPrice - ,klo = vClock - ,s1 = vS1 - ,s2 = vS2 - ,s3 = vS3 - ,s4 = vS4 - ,s5 = vS5 - ,s6 = vS6 - ,k1 = vK1 - ,k2 = vK2 - ,k3 = vP1 - ,k4 = vP2 - ,auction = vAuction - ,package = vPackage - ,putOrderFk = vPutOrderFk; - - -- If it exists duplicado updates it - - IF NOT vIsDuplicated - THEN - SET vEkt = LAST_INSERT_ID(); - CALL ekt_load (vEkt); - - ELSEIF vDeliveryNumber != 0 - AND vDeliveryNumber IS NOT NULL - THEN - SELECT id INTO vEkt - FROM ekt - WHERE deliveryNumber = vDeliveryNumber; - - SELECT COUNT(*) = 0 INTO vUpdateExistent - FROM ekt t - JOIN `exchange` b ON b.ektFk = t.id - JOIN exchangeConfig c - WHERE t.deliveryNumber = vDeliveryNumber - AND t.entryYear = YEAR(vDate) - AND b.typeFk != c.presaleFk; - END IF; - - IF vUpdateExistent - THEN - UPDATE ekt SET - barcode = IFNULL(vBarcode, barcode) - ,fec = vDate - ,hor = vHour - ,ref = vRef - ,item = vItem - ,agj = vAgj - ,cat = vCat - ,pac = vPac - ,sub = vSub - ,kop = vKop - ,ptd = vPtd - ,pro = vPro - ,ori = vOrigin - ,ptj = vPtj - ,qty = vQuantiy - ,pri = vPrice - ,klo = vClock - ,s1 = vS1 - ,s2 = vS2 - ,s3 = vS3 - ,s4 = vS4 - ,s5 = vS5 - ,s6 = vS6 - ,k1 = vK1 - ,k2 = vK2 - ,k3 = vP1 - ,k4 = vP2 - ,auction = vAuction - ,package = vPackage - ,putOrderFk = vPutOrderFk - WHERE id = vEkt; - END IF; - - -- Registers the exchange - - INSERT INTO `exchange` SET - mailFk = vMailFk - ,typeFk = vType - ,ektFk = vEkt; + DECLARE CONTINUE HANDLER FOR duplicateKey + SET vIsDuplicated = TRUE; + + -- Generates the barcode + + IF vAgj != 0 AND vAgj IS NOT NULL + THEN + SET vBarcode = CONCAT( + LPAD(vAuction, 2, 0), + LPAD(IFNULL(vClock, 99), 2, 0), + LPAD(DAYOFYEAR(vDate), 3, 0), + IF(vClock IS NULL OR vClock = 99, + LPAD(vAgj, 7, 0), + CONCAT(LPAD(vAgj, 5, 0), '01') + ), + '0' + ); + END IF; + + -- Rewrites the kop parameter + + IF vKop IS NULL THEN + SELECT defaultKop INTO vKop FROM exchangeConfig; + END IF; + + SELECT e.kop INTO vRewriteKop + FROM mailSender e + JOIN mail m ON m.senderFk = e.id + WHERE m.id = vMailFk; + + SET vKop = IFNULL(vRewriteKop, vKop); + + -- Inserts the new transaction + + SET vIsDuplicated = FALSE; + INSERT INTO ekt SET + barcode = IFNULL(vBarcode, barcode) + ,deliveryNumber = vDeliveryNumber + ,entryYear = YEAR(vDate) + ,fec = vDate + ,hor = vHour + ,ref = vRef + ,item = vItem + ,agj = vAgj + ,cat = vCat + ,pac = vPac + ,sub = vSub + ,kop = vKop + ,ptd = vPtd + ,pro = vPro + ,ori = vOrigin + ,ptj = vPtj + ,qty = vQuantiy + ,pri = vPrice + ,klo = vClock + ,s1 = vS1 + ,s2 = vS2 + ,s3 = vS3 + ,s4 = vS4 + ,s5 = vS5 + ,s6 = vS6 + ,k1 = vK1 + ,k2 = vK2 + ,k3 = vP1 + ,k4 = vP2 + ,auction = vAuction + ,package = vPackage + ,putOrderFk = vPutOrderFk; + + -- If it exists duplicado updates it + + IF NOT vIsDuplicated + THEN + SET vEkt = LAST_INSERT_ID(); + CALL ekt_load (vEkt); + + ELSEIF vDeliveryNumber != 0 + AND vDeliveryNumber IS NOT NULL + THEN + SELECT id INTO vEkt + FROM ekt + WHERE deliveryNumber = vDeliveryNumber; + + SELECT COUNT(*) = 0 INTO vUpdateExistent + FROM ekt t + JOIN `exchange` b ON b.ektFk = t.id + JOIN exchangeConfig c + WHERE t.deliveryNumber = vDeliveryNumber + AND t.entryYear = YEAR(vDate) + AND b.typeFk != c.presaleFk; + END IF; + + IF vUpdateExistent + THEN + UPDATE ekt SET + barcode = IFNULL(vBarcode, barcode) + ,fec = vDate + ,hor = vHour + ,ref = vRef + ,item = vItem + ,agj = vAgj + ,cat = vCat + ,pac = vPac + ,sub = vSub + ,kop = vKop + ,ptd = vPtd + ,pro = vPro + ,ori = vOrigin + ,ptj = vPtj + ,qty = vQuantiy + ,pri = vPrice + ,klo = vClock + ,s1 = vS1 + ,s2 = vS2 + ,s3 = vS3 + ,s4 = vS4 + ,s5 = vS5 + ,s6 = vS6 + ,k1 = vK1 + ,k2 = vK2 + ,k3 = vP1 + ,k4 = vP2 + ,auction = vAuction + ,package = vPackage + ,putOrderFk = vPutOrderFk + WHERE id = vEkt; + END IF; + + -- Registers the exchange + + INSERT INTO `exchange` SET + mailFk = vMailFk + ,typeFk = vType + ,ektFk = vEkt; END ;; DELIMITER ; /*!50003 SET sql_mode = @saved_sql_mode */ ; @@ -10810,30 +10810,30 @@ DELIMITER ; /*!50003 SET sql_mode = 'NO_ENGINE_SUBSTITUTION' */ ; DELIMITER ;; CREATE DEFINER=`root`@`%` PROCEDURE `item_listAllocation`(IN `vWh` TINYINT, IN `vDate` DATE, IN `vType` INT, IN `vPrefix` VARCHAR(255), IN `vUseIds` BOOLEAN) -BEGIN -/** - * Lists visible items and it's box sizes of the specified - * type at specified date. - * - * @param vWh The warehouse id - * @param vDate The visible date - * @param vType The type id - * @param vPrefix The article prefix to filter or %NULL for all - * @param vUseIds Whether to order the result by item id - * @select List of visible items with it's box sizes - */ - CALL item_getVisible(vWh, vDate, vType, vPrefix); - - IF vUseIds - THEN - SELECT * FROM tmp.itemVisible - ORDER BY Id_Article; - ELSE - SELECT * FROM tmp.itemVisible - ORDER BY Article, packing; - END IF; - - DROP TEMPORARY TABLE tmp.itemVisible; +BEGIN +/** + * Lists visible items and it's box sizes of the specified + * type at specified date. + * + * @param vWh The warehouse id + * @param vDate The visible date + * @param vType The type id + * @param vPrefix The article prefix to filter or %NULL for all + * @param vUseIds Whether to order the result by item id + * @select List of visible items with it's box sizes + */ + CALL item_getVisible(vWh, vDate, vType, vPrefix); + + IF vUseIds + THEN + SELECT * FROM tmp.itemVisible + ORDER BY Id_Article; + ELSE + SELECT * FROM tmp.itemVisible + ORDER BY Article, packing; + END IF; + + DROP TEMPORARY TABLE tmp.itemVisible; END ;; DELIMITER ; /*!50003 SET sql_mode = @saved_sql_mode */ ; @@ -16189,8 +16189,8 @@ DELIMITER ; /*!50003 SET sql_mode = 'NO_ENGINE_SUBSTITUTION' */ ; DELIMITER ;; CREATE DEFINER=`root`@`%` PROCEDURE `log_add_beta`(IN `vTableName` VARCHAR(255), IN `vNewId` VARCHAR(255), IN `vOldId` VARCHAR(255)) -proc: BEGIN - -- XXX: Disabled while testing +proc: BEGIN + -- XXX: Disabled while testing DECLARE vLanded DATE; DECLARE vWarehouseFk INT; DECLARE vBuyerFk INT; @@ -16198,20 +16198,20 @@ proc: BEGIN DECLARE vItemFk INT; DECLARE vItemName VARCHAR(50); - -- LEAVE proc; + -- LEAVE proc; - IF vOldId IS NOT NULL AND !(vOldId <=> vNewId) THEN - INSERT IGNORE INTO `log` SET - tableName = vTableName, - tableId = vOldId, - operation = 'delete'; - END IF; - - IF vNewId IS NOT NULL THEN - INSERT IGNORE INTO `log` SET - tableName = vTableName, - tableId = vNewId, - operation = 'insert'; + IF vOldId IS NOT NULL AND !(vOldId <=> vNewId) THEN + INSERT IGNORE INTO `log` SET + tableName = vTableName, + tableId = vOldId, + operation = 'delete'; + END IF; + + IF vNewId IS NOT NULL THEN + INSERT IGNORE INTO `log` SET + tableName = vTableName, + tableId = vNewId, + operation = 'insert'; END IF; IF vTableName = 'buy' THEN @@ -16241,7 +16241,7 @@ proc: BEGIN END IF; END IF; - + END ;; DELIMITER ; /*!50003 SET sql_mode = @saved_sql_mode */ ; @@ -16509,29 +16509,29 @@ CREATE DEFINER=`root`@`%` PROCEDURE `log_refreshSale`( BEGIN DROP TEMPORARY TABLE IF EXISTS tValues; CREATE TEMPORARY TABLE tValues - ENGINE = MEMORY - SELECT - m.id saleFk, - m.ticketFk, - m.itemFk, - t.warehouseFk, - t.shipped, + ENGINE = MEMORY + SELECT + m.id saleFk, + m.ticketFk, + m.itemFk, + t.warehouseFk, + t.shipped, ABS(m.quantity) quantity, m.created, TIMESTAMPADD(DAY, tp.life, t.shipped) expired, m.quantity < 0 isIn, - m.isPicked OR s.alertLevel > 1 isPicked - FROM vn.sale m - JOIN vn.ticket t ON t.id = m.ticketFk + m.isPicked OR s.alertLevel > 1 isPicked + FROM vn.sale m + JOIN vn.ticket t ON t.id = m.ticketFk JOIN vn.ticketState s ON s.ticketFk = t.id JOIN vn.item i ON i.id = m.itemFk - JOIN vn.itemType tp ON tp.id = i.typeFk + JOIN vn.itemType tp ON tp.id = i.typeFk WHERE ( - vTableId IS NULL - OR (vTableName = 'ticket' AND t.id = vTableId) - OR (vTableName = 'sale' AND m.id = vTableId) - ) - AND t.shipped >= vn.getInventoryDate() + vTableId IS NULL + OR (vTableName = 'ticket' AND t.id = vTableId) + OR (vTableName = 'sale' AND m.id = vTableId) + ) + AND t.shipped >= vn.getInventoryDate() AND m.quantity != 0; REPLACE INTO inbound ( @@ -16564,7 +16564,7 @@ BEGIN FROM tValues WHERE !isIn; - DROP TEMPORARY TABLE tValues; + DROP TEMPORARY TABLE tValues; END ;; DELIMITER ; /*!50003 SET sql_mode = @saved_sql_mode */ ; @@ -29495,90 +29495,90 @@ DELIMITER ;; /*!50003 SET sql_mode = 'NO_ENGINE_SUBSTITUTION' */ ;; /*!50003 SET @saved_time_zone = @@time_zone */ ;; /*!50003 SET time_zone = 'SYSTEM' */ ;; -/*!50106 CREATE*/ /*!50117 DEFINER=`root`@`%`*/ /*!50106 EVENT `printQueue_check` ON SCHEDULE EVERY 10 MINUTE STARTS '2019-11-08 00:00:00' ON COMPLETION PRESERVE ENABLE COMMENT 'Notifica en caso de que el servidor de impresión este parado' DO BEGIN - - DECLARE vCurrentCount INT; - DECLARE vCheckSum INT; - DECLARE vIsAlreadyNotified BOOLEAN; - DECLARE vTableQueue TEXT; - DECLARE vLineQueue TEXT; - DECLARE vDone BOOL DEFAULT FALSE; - DECLARE vCur CURSOR FOR - SELECT CONCAT(' - ', IFNULL(pq.id, ''), ' - ', IFNULL(p.path, ''),' - ', IFNULL(i.Informe, ''),' - ', IFNULL(e.Estado, ''),' - ', IFNULL(w.firstname, ''), " ", IFNULL(w.lastName, ''),' - ', IFNULL(pq.`error`, ''),' - ') - FROM vn.printingQueue pq - LEFT JOIN vn.worker w ON w.id = pq.worker - LEFT JOIN vn.printer p ON p.id = pq.printer - LEFT JOIN vn2008.Informes i ON i.Id_Informe = pq.report - JOIN vn2008.Estados e ON e.Id_Estado = pq.state - LIMIT 30; - - DECLARE CONTINUE HANDLER FOR NOT FOUND - SET vDone = TRUE; - - SELECT COUNT(*), IFNULL(SUM(id),0) INTO vCurrentCount, vCheckSum - FROM vn.printingQueue WHERE state = 1; - - SELECT isAlreadyNotified INTO vIsAlreadyNotified - FROM printingQueueCheck; - - IF (SELECT lastCount FROM printingQueueCheck) = vCurrentCount AND - (SELECT lastCheckSum FROM printingQueueCheck) = vCheckSum AND - vIsAlreadyNotified = FALSE AND vCurrentCount > 0 - THEN - - SELECT ' - - - - - - - - ' INTO vTableQueue; - - OPEN vCur; - - l: LOOP - - SET vDone = FALSE; - - FETCH vCur INTO vLineQueue; - - IF vDone THEN - LEAVE l; - END IF; - - SELECT CONCAT(vTableQueue, vLineQueue) INTO vTableQueue; - - END LOOP; - - CLOSE vCur; - - INSERT INTO vn2008.mail (`to`, subject, text) - VALUES ('cau@verdnatura.es, sysadmin@verdnatura.es', - 'servidor de impresion parado', - CONCAT('Hay ', vCurrentCount, ' lineas bloqueadas', vTableQueue, '
Id ColaRuta ImpresoraInformeEstadoTrabajadorError
')); - - UPDATE printingQueueCheck SET isAlreadyNotified = TRUE; - END IF; - - IF (SELECT lastCount FROM printingQueueCheck) > vCurrentCount AND - vIsAlreadyNotified = TRUE - THEN - UPDATE printingQueueCheck SET isAlreadyNotified = FALSE; - END IF; - - UPDATE printingQueueCheck - SET lastCount = vCurrentCount, - lastCheckSum = vCheckSum; - +/*!50106 CREATE*/ /*!50117 DEFINER=`root`@`%`*/ /*!50106 EVENT `printQueue_check` ON SCHEDULE EVERY 10 MINUTE STARTS '2019-11-08 00:00:00' ON COMPLETION PRESERVE ENABLE COMMENT 'Notifica en caso de que el servidor de impresión este parado' DO BEGIN + + DECLARE vCurrentCount INT; + DECLARE vCheckSum INT; + DECLARE vIsAlreadyNotified BOOLEAN; + DECLARE vTableQueue TEXT; + DECLARE vLineQueue TEXT; + DECLARE vDone BOOL DEFAULT FALSE; + DECLARE vCur CURSOR FOR + SELECT CONCAT(' + ', IFNULL(pq.id, ''), ' + ', IFNULL(p.path, ''),' + ', IFNULL(i.Informe, ''),' + ', IFNULL(e.Estado, ''),' + ', IFNULL(w.firstname, ''), " ", IFNULL(w.lastName, ''),' + ', IFNULL(pq.`error`, ''),' + ') + FROM vn.printingQueue pq + LEFT JOIN vn.worker w ON w.id = pq.worker + LEFT JOIN vn.printer p ON p.id = pq.printer + LEFT JOIN vn2008.Informes i ON i.Id_Informe = pq.report + JOIN vn2008.Estados e ON e.Id_Estado = pq.state + LIMIT 30; + + DECLARE CONTINUE HANDLER FOR NOT FOUND + SET vDone = TRUE; + + SELECT COUNT(*), IFNULL(SUM(id),0) INTO vCurrentCount, vCheckSum + FROM vn.printingQueue WHERE state = 1; + + SELECT isAlreadyNotified INTO vIsAlreadyNotified + FROM printingQueueCheck; + + IF (SELECT lastCount FROM printingQueueCheck) = vCurrentCount AND + (SELECT lastCheckSum FROM printingQueueCheck) = vCheckSum AND + vIsAlreadyNotified = FALSE AND vCurrentCount > 0 + THEN + + SELECT ' + + + + + + + + ' INTO vTableQueue; + + OPEN vCur; + + l: LOOP + + SET vDone = FALSE; + + FETCH vCur INTO vLineQueue; + + IF vDone THEN + LEAVE l; + END IF; + + SELECT CONCAT(vTableQueue, vLineQueue) INTO vTableQueue; + + END LOOP; + + CLOSE vCur; + + INSERT INTO vn2008.mail (`to`, subject, text) + VALUES ('cau@verdnatura.es, sysadmin@verdnatura.es', + 'servidor de impresion parado', + CONCAT('Hay ', vCurrentCount, ' lineas bloqueadas', vTableQueue, '
Id ColaRuta ImpresoraInformeEstadoTrabajadorError
')); + + UPDATE printingQueueCheck SET isAlreadyNotified = TRUE; + END IF; + + IF (SELECT lastCount FROM printingQueueCheck) > vCurrentCount AND + vIsAlreadyNotified = TRUE + THEN + UPDATE printingQueueCheck SET isAlreadyNotified = FALSE; + END IF; + + UPDATE printingQueueCheck + SET lastCount = vCurrentCount, + lastCheckSum = vCheckSum; + END */ ;; /*!50003 SET time_zone = @saved_time_zone */ ;; /*!50003 SET sql_mode = @saved_sql_mode */ ;; @@ -35117,27 +35117,27 @@ DELIMITER ; /*!50003 SET sql_mode = 'NO_ENGINE_SUBSTITUTION' */ ; DELIMITER ;; CREATE DEFINER=`root`@`%` PROCEDURE `clean__`() -BEGIN - DECLARE vDateShort DATETIME; - DECLARE oneYearAgo DATE; - DECLARE twoYearsAgo DATE; - DECLARE fourYearsAgo DATE; - - SET vDateShort = TIMESTAMPADD(MONTH, -2, CURDATE()); - SET oneYearAgo = TIMESTAMPADD(YEAR,-1,CURDATE()); - SET twoYearsAgo = TIMESTAMPADD(YEAR,-2,CURDATE()); - SET fourYearsAgo = TIMESTAMPADD(YEAR,-4,CURDATE()); - - DELETE FROM vn.message WHERE sendDate < vDateShort; - DELETE FROM vn.messageInbox WHERE sendDate < vDateShort; - DELETE FROM vn.messageInbox WHERE sendDate < vDateShort; - DELETE FROM vn.workerTimeControl WHERE timed < fourYearsAgo; - DELETE FROM vn.itemShelving WHERE created < CURDATE() AND visible = 0; - DELETE FROM vn.ticketDown WHERE created < TIMESTAMPADD(DAY,-1,CURDATE()); - CALL shelving_clean; - +BEGIN + DECLARE vDateShort DATETIME; + DECLARE oneYearAgo DATE; + DECLARE twoYearsAgo DATE; + DECLARE fourYearsAgo DATE; + + SET vDateShort = TIMESTAMPADD(MONTH, -2, CURDATE()); + SET oneYearAgo = TIMESTAMPADD(YEAR,-1,CURDATE()); + SET twoYearsAgo = TIMESTAMPADD(YEAR,-2,CURDATE()); + SET fourYearsAgo = TIMESTAMPADD(YEAR,-4,CURDATE()); + + DELETE FROM vn.message WHERE sendDate < vDateShort; + DELETE FROM vn.messageInbox WHERE sendDate < vDateShort; + DELETE FROM vn.messageInbox WHERE sendDate < vDateShort; + DELETE FROM vn.workerTimeControl WHERE timed < fourYearsAgo; + DELETE FROM vn.itemShelving WHERE created < CURDATE() AND visible = 0; + DELETE FROM vn.ticketDown WHERE created < TIMESTAMPADD(DAY,-1,CURDATE()); + CALL shelving_clean; + CALL vn.ticketPackagingRecovery; - + END ;; DELIMITER ; /*!50003 SET sql_mode = @saved_sql_mode */ ; @@ -35980,54 +35980,54 @@ DELIMITER ; /*!50003 SET sql_mode = 'NO_ENGINE_SUBSTITUTION' */ ; DELIMITER ;; CREATE DEFINER=`root`@`%` PROCEDURE `clientRemoveWorker__`() -BEGIN - DECLARE done BOOL DEFAULT FALSE; - DECLARE vClientFk INT; - - DECLARE rs CURSOR FOR - SELECT c.clientFk - FROM tmp.clientGetDebt c - LEFT JOIN tmp.risk r ON r.clientFk = c.clientFk - WHERE IFNULL(r.risk,0) = 0; - - DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; - - DROP TEMPORARY TABLE IF EXISTS tmp.clientGetDebt; - CREATE TEMPORARY TABLE tmp.clientGetDebt - SELECT cd.id as clientFk - FROM bs.clientDied cd - LEFT JOIN vn.clientProtected cp ON cp.clientFk = cd.id - JOIN vn.client c ON c.id = cd.id - JOIN vn.province p ON p.id = c.provinceFk - JOIN vn.country co ON co.id = p.countryFk - WHERE cd.Aviso = 'TERCER AVISO' - AND cp.clientFk IS NULL - AND co.country NOT IN ('Portugal','Francia','España exento') - AND c.salesPersonFk IS NOT NULL; - - CALL vn.clientGetDebt(curdate()); - - DROP TEMPORARY TABLE IF EXISTS tmp.contador; - CREATE TEMPORARY TABLE tmp.contador (id INT) - ENGINE = MEMORY; - - OPEN rs; - FETCH rs INTO vClientFk; - - WHILE NOT done DO - INSERT INTO tmp.contador SET id = vClientFk; - CALL vn.clientGreugeSpray(vClientFk, TRUE, '',TRUE); +BEGIN + DECLARE done BOOL DEFAULT FALSE; + DECLARE vClientFk INT; + + DECLARE rs CURSOR FOR + SELECT c.clientFk + FROM tmp.clientGetDebt c + LEFT JOIN tmp.risk r ON r.clientFk = c.clientFk + WHERE IFNULL(r.risk,0) = 0; + + DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; + + DROP TEMPORARY TABLE IF EXISTS tmp.clientGetDebt; + CREATE TEMPORARY TABLE tmp.clientGetDebt + SELECT cd.id as clientFk + FROM bs.clientDied cd + LEFT JOIN vn.clientProtected cp ON cp.clientFk = cd.id + JOIN vn.client c ON c.id = cd.id + JOIN vn.province p ON p.id = c.provinceFk + JOIN vn.country co ON co.id = p.countryFk + WHERE cd.Aviso = 'TERCER AVISO' + AND cp.clientFk IS NULL + AND co.country NOT IN ('Portugal','Francia','España exento') + AND c.salesPersonFk IS NOT NULL; + + CALL vn.clientGetDebt(curdate()); + + DROP TEMPORARY TABLE IF EXISTS tmp.contador; + CREATE TEMPORARY TABLE tmp.contador (id INT) + ENGINE = MEMORY; + + OPEN rs; + FETCH rs INTO vClientFk; + + WHILE NOT done DO + INSERT INTO tmp.contador SET id = vClientFk; + CALL vn.clientGreugeSpray(vClientFk, TRUE, '',TRUE); UPDATE vn.client SET salesPersonFk = NULL WHERE id = vClientFk; INSERT INTO vn.clientLog (originFk, userFk, `action`, description) VALUES (vClientFk, account.userGetId(), 'update', CONCAT('Se ha desasignado el cliente por que no ha comprado en 3 meses')); - + REPLACE bs.clientNewBorn(clientFk, shipped) - VALUES(vClientFk, CURDATE()); - FETCH rs INTO vClientFk; - END WHILE; - - CLOSE rs; + VALUES(vClientFk, CURDATE()); + FETCH rs INTO vClientFk; + END WHILE; + + CLOSE rs; END ;; DELIMITER ; /*!50003 SET sql_mode = @saved_sql_mode */ ; @@ -38951,216 +38951,216 @@ DELIMITER ; /*!50003 SET sql_mode = 'NO_ENGINE_SUBSTITUTION' */ ; DELIMITER ;; CREATE DEFINER=`root`@`%` PROCEDURE `entryConverter`(IN `vEntry` INT) -BEGIN - - DECLARE vWarehouseIn INT; - DECLARE vWarehouseOut INT; - DECLARE vTravel INT; - - DECLARE done BOOL DEFAULT FALSE; - - DECLARE vId_Entrada INT; - DECLARE vId_Article INT; - DECLARE vEtiquetas INT; - DECLARE vId_Cubo VARCHAR(10); - DECLARE vPacking INT; - DECLARE vGrouping INT; - DECLARE vCantidad INT; - DECLARE vCostefijo DECIMAL(10,3); - DECLARE vPortefijo DECIMAL(10,3); - DECLARE vEmbalajefijo DECIMAL(10); - DECLARE vComisionfija DECIMAL(10,3); - DECLARE vCaja INT; - DECLARE vNicho VARCHAR(5); - DECLARE vTarifa1 DECIMAL(10,2); - DECLARE vTarifa2 DECIMAL(10,2); - DECLARE vTarifa3 DECIMAL(10,2); - DECLARE vPVP DECIMAL(10,2); - DECLARE vCompra INT; - - DECLARE rs CURSOR FOR - SELECT - b.Id_Entrada, - b.Id_Article, - b.Etiquetas, - b.Id_Cubo, - b.Packing, - b.`grouping`, - b.Cantidad, - b.Costefijo, - b.Portefijo, - b.Embalajefijo, - b.Comisionfija, - b.caja, - b.Nicho, - b.Tarifa1, - b.Tarifa2, - b.Tarifa3, - b.PVP - FROM vn2008.Compres b - JOIN vn.itemConversor ic ON ic.espItemFk = b.Id_Article - WHERE Id_Entrada = vEntry; - - DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; - - SELECT warehouseInFk, warehouseOutFk, tr.id - INTO vWarehouseIn, vWarehouseOut, vTravel - FROM travel tr - JOIN entry e ON e.travelFk = tr.id - WHERE e.id = vEntry; - - UPDATE travel - SET warehouseInFk = vWarehouseOut, - warehouseOutFk = vWarehouseIn - WHERE id = vTravel; - - UPDATE vn2008.Compres c - LEFT JOIN vn.itemConversor ic ON ic.espItemFk = c.Id_Article - SET Etiquetas = 0, Cantidad = 0 - WHERE c.Id_Entrada = vEntry - AND ic.espItemFk IS NULL; - - OPEN rs; - - DELETE FROM vn2008.Compres WHERE Id_Entrada = vEntry; - - FETCH rs INTO - vId_Entrada, - vId_Article, - vEtiquetas, - vId_Cubo, - vPacking, - vGrouping, - vCantidad, - vCostefijo, - vPortefijo, - vEmbalajefijo, - vComisionfija, - vCaja, - vNicho, - vTarifa1, - vTarifa2, - vTarifa3, - vPVP; - - WHILE NOT done DO - - -- Primero la linea original con las cantidades invertidas - INSERT INTO vn2008.Compres - ( - Id_Entrada, - Id_Article, - Etiquetas, - Id_Cubo, - Packing, - `grouping`, - Cantidad, - Costefijo, - Portefijo, - Embalajefijo, - Comisionfija, - caja, - Nicho, - Tarifa1, - Tarifa2, - Tarifa3, - PVP - ) - VALUES - ( - vId_Entrada, - vId_Article, - - vEtiquetas, - vId_Cubo, - vPacking, - vGrouping, - - vCantidad, - vCostefijo, - vPortefijo, - vEmbalajefijo, - vComisionfija, - vCaja, - vNicho, - vTarifa1, - vTarifa2, - vTarifa3, - vPVP); - - -- Ahora la linea nueva, con el item genérico - INSERT INTO vn2008.Compres - ( - Id_Entrada, - Id_Article, - Etiquetas, - Id_Cubo, - Packing, - `grouping`, - Cantidad, - Costefijo, - Portefijo, - Embalajefijo, - Comisionfija, - caja, - Nicho, - Tarifa1, - Tarifa2, - Tarifa3, - PVP - ) - SELECT - vId_Entrada, - genItemFk as Id_Article, - vEtiquetas, - vId_Cubo, - vPacking, - vGrouping, - vCantidad, - vCostefijo, - vPortefijo, - vEmbalajefijo, - vComisionfija, - vCaja, - vNicho, - vTarifa1, - vTarifa2, - vTarifa3, - vPVP - FROM itemConversor - WHERE espItemFk = vId_Article; - - SELECT LAST_INSERT_ID() - INTO vCompra; - - REPLACE vn2008.Compres_mark(Id_Compra,`comment`) - SELECT vCompra, vId_Article; - - - FETCH rs INTO - vId_Entrada, - vId_Article, - vEtiquetas, - vId_Cubo, - vPacking, - vGrouping, - vCantidad, - vCostefijo, - vPortefijo, - vEmbalajefijo, - vComisionfija, - vCaja, - vNicho, - vTarifa1, - vTarifa2, - vTarifa3, - vPVP; - - END WHILE; - - - CLOSE rs; - - - +BEGIN + + DECLARE vWarehouseIn INT; + DECLARE vWarehouseOut INT; + DECLARE vTravel INT; + + DECLARE done BOOL DEFAULT FALSE; + + DECLARE vId_Entrada INT; + DECLARE vId_Article INT; + DECLARE vEtiquetas INT; + DECLARE vId_Cubo VARCHAR(10); + DECLARE vPacking INT; + DECLARE vGrouping INT; + DECLARE vCantidad INT; + DECLARE vCostefijo DECIMAL(10,3); + DECLARE vPortefijo DECIMAL(10,3); + DECLARE vEmbalajefijo DECIMAL(10); + DECLARE vComisionfija DECIMAL(10,3); + DECLARE vCaja INT; + DECLARE vNicho VARCHAR(5); + DECLARE vTarifa1 DECIMAL(10,2); + DECLARE vTarifa2 DECIMAL(10,2); + DECLARE vTarifa3 DECIMAL(10,2); + DECLARE vPVP DECIMAL(10,2); + DECLARE vCompra INT; + + DECLARE rs CURSOR FOR + SELECT + b.Id_Entrada, + b.Id_Article, + b.Etiquetas, + b.Id_Cubo, + b.Packing, + b.`grouping`, + b.Cantidad, + b.Costefijo, + b.Portefijo, + b.Embalajefijo, + b.Comisionfija, + b.caja, + b.Nicho, + b.Tarifa1, + b.Tarifa2, + b.Tarifa3, + b.PVP + FROM vn2008.Compres b + JOIN vn.itemConversor ic ON ic.espItemFk = b.Id_Article + WHERE Id_Entrada = vEntry; + + DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; + + SELECT warehouseInFk, warehouseOutFk, tr.id + INTO vWarehouseIn, vWarehouseOut, vTravel + FROM travel tr + JOIN entry e ON e.travelFk = tr.id + WHERE e.id = vEntry; + + UPDATE travel + SET warehouseInFk = vWarehouseOut, + warehouseOutFk = vWarehouseIn + WHERE id = vTravel; + + UPDATE vn2008.Compres c + LEFT JOIN vn.itemConversor ic ON ic.espItemFk = c.Id_Article + SET Etiquetas = 0, Cantidad = 0 + WHERE c.Id_Entrada = vEntry + AND ic.espItemFk IS NULL; + + OPEN rs; + + DELETE FROM vn2008.Compres WHERE Id_Entrada = vEntry; + + FETCH rs INTO + vId_Entrada, + vId_Article, + vEtiquetas, + vId_Cubo, + vPacking, + vGrouping, + vCantidad, + vCostefijo, + vPortefijo, + vEmbalajefijo, + vComisionfija, + vCaja, + vNicho, + vTarifa1, + vTarifa2, + vTarifa3, + vPVP; + + WHILE NOT done DO + + -- Primero la linea original con las cantidades invertidas + INSERT INTO vn2008.Compres + ( + Id_Entrada, + Id_Article, + Etiquetas, + Id_Cubo, + Packing, + `grouping`, + Cantidad, + Costefijo, + Portefijo, + Embalajefijo, + Comisionfija, + caja, + Nicho, + Tarifa1, + Tarifa2, + Tarifa3, + PVP + ) + VALUES + ( + vId_Entrada, + vId_Article, + - vEtiquetas, + vId_Cubo, + vPacking, + vGrouping, + - vCantidad, + vCostefijo, + vPortefijo, + vEmbalajefijo, + vComisionfija, + vCaja, + vNicho, + vTarifa1, + vTarifa2, + vTarifa3, + vPVP); + + -- Ahora la linea nueva, con el item genérico + INSERT INTO vn2008.Compres + ( + Id_Entrada, + Id_Article, + Etiquetas, + Id_Cubo, + Packing, + `grouping`, + Cantidad, + Costefijo, + Portefijo, + Embalajefijo, + Comisionfija, + caja, + Nicho, + Tarifa1, + Tarifa2, + Tarifa3, + PVP + ) + SELECT + vId_Entrada, + genItemFk as Id_Article, + vEtiquetas, + vId_Cubo, + vPacking, + vGrouping, + vCantidad, + vCostefijo, + vPortefijo, + vEmbalajefijo, + vComisionfija, + vCaja, + vNicho, + vTarifa1, + vTarifa2, + vTarifa3, + vPVP + FROM itemConversor + WHERE espItemFk = vId_Article; + + SELECT LAST_INSERT_ID() + INTO vCompra; + + REPLACE vn2008.Compres_mark(Id_Compra,`comment`) + SELECT vCompra, vId_Article; + + + FETCH rs INTO + vId_Entrada, + vId_Article, + vEtiquetas, + vId_Cubo, + vPacking, + vGrouping, + vCantidad, + vCostefijo, + vPortefijo, + vEmbalajefijo, + vComisionfija, + vCaja, + vNicho, + vTarifa1, + vTarifa2, + vTarifa3, + vPVP; + + END WHILE; + + + CLOSE rs; + + + END ;; DELIMITER ; /*!50003 SET sql_mode = @saved_sql_mode */ ; @@ -39222,62 +39222,62 @@ DELIMITER ; /*!50003 SET sql_mode = 'NO_ENGINE_SUBSTITUTION' */ ; DELIMITER ;; CREATE DEFINER=`root`@`%` PROCEDURE `entryPrepare`(IN `idE` BIGINT) -BEGIN - SELECT - b.quantity / b.packing AS Paquetes, - b.packing AS `Grouping`, - barcode, - 'ASEGURADO' AS asegurado, - ic.name, - ic.order, - s.name AS Consignatario, - e.supplierFk AS Id_Cliente, - e.isOrdered, - e.isConfirmed, - 10 AS Calidad, - LPAD(IFNULL(cpd.id, ip.code), - 5, - '0') AS path, - b.entryFk AS Id_Ticket, - t.landed AS Fecha, - b.itemFk, - b.quantity, - i.name AS Concepte, - i.size, - i.inkFk, - i.category, - o.code AS Origen, - 0 AS Bultos, - wIn.`name` AS Tipo, - 0 AS OK, - 0 AS Reservado, - i.stems, - b.id AS Id_Movimiento, - ip.code, - 'PEDIDO ASEGURADO' AS MSG, - 0 AS Seguro, - i.image, - pr.name AS producer - FROM vn.buy b - JOIN vn.entry e ON b.entryFk = e.id - JOIN vn.travel t ON t.id = e.travelFk - JOIN vn.warehouse wIn ON wIn.id = t.warehouseInFk - JOIN vn.warehouse wOut ON wOut.id = t.warehouseOutFk - JOIN vn.item i ON i.id = b.itemFk - JOIN vn.itemType it ON it.id =i.typeFk - JOIN vn.itemCategory ic ON ic.id = it.categoryFk - JOIN vn.packaging pkg ON pkg.id = b.packageFk - LEFT JOIN vn.itemPlacement ip ON i.id = ip.itemFk AND ip.warehouseFk = wIn.id AND ip.warehouseFk = t.warehouseOutFk - LEFT JOIN (SELECT itemFk, code AS barcode FROM vn.itemBarcode GROUP BY itemFk) ib ON ib.itemFk = b.itemFk - LEFT JOIN vn.origin o ON o.id = i.originFk - LEFT JOIN vn.supplier s ON s.id = e.supplierFk - LEFT JOIN vn.producer pr on pr.id = i.producerFk - LEFT JOIN vn.coolerPathDetail cpd ON LEFT(ip.code, 3) = cpd.hallway - WHERE - NOT wIn.isFeedStock AND NOT e.isInventory AND NOT e.isRaid - AND e.id = 158772 - AND i.typeFk IS NOT NULL - AND ic.merchandise IS NOT FALSE; +BEGIN + SELECT + b.quantity / b.packing AS Paquetes, + b.packing AS `Grouping`, + barcode, + 'ASEGURADO' AS asegurado, + ic.name, + ic.order, + s.name AS Consignatario, + e.supplierFk AS Id_Cliente, + e.isOrdered, + e.isConfirmed, + 10 AS Calidad, + LPAD(IFNULL(cpd.id, ip.code), + 5, + '0') AS path, + b.entryFk AS Id_Ticket, + t.landed AS Fecha, + b.itemFk, + b.quantity, + i.name AS Concepte, + i.size, + i.inkFk, + i.category, + o.code AS Origen, + 0 AS Bultos, + wIn.`name` AS Tipo, + 0 AS OK, + 0 AS Reservado, + i.stems, + b.id AS Id_Movimiento, + ip.code, + 'PEDIDO ASEGURADO' AS MSG, + 0 AS Seguro, + i.image, + pr.name AS producer + FROM vn.buy b + JOIN vn.entry e ON b.entryFk = e.id + JOIN vn.travel t ON t.id = e.travelFk + JOIN vn.warehouse wIn ON wIn.id = t.warehouseInFk + JOIN vn.warehouse wOut ON wOut.id = t.warehouseOutFk + JOIN vn.item i ON i.id = b.itemFk + JOIN vn.itemType it ON it.id =i.typeFk + JOIN vn.itemCategory ic ON ic.id = it.categoryFk + JOIN vn.packaging pkg ON pkg.id = b.packageFk + LEFT JOIN vn.itemPlacement ip ON i.id = ip.itemFk AND ip.warehouseFk = wIn.id AND ip.warehouseFk = t.warehouseOutFk + LEFT JOIN (SELECT itemFk, code AS barcode FROM vn.itemBarcode GROUP BY itemFk) ib ON ib.itemFk = b.itemFk + LEFT JOIN vn.origin o ON o.id = i.originFk + LEFT JOIN vn.supplier s ON s.id = e.supplierFk + LEFT JOIN vn.producer pr on pr.id = i.producerFk + LEFT JOIN vn.coolerPathDetail cpd ON LEFT(ip.code, 3) = cpd.hallway + WHERE + NOT wIn.isFeedStock AND NOT e.isInventory AND NOT e.isRaid + AND e.id = 158772 + AND i.typeFk IS NOT NULL + AND ic.merchandise IS NOT FALSE; END ;; DELIMITER ; /*!50003 SET sql_mode = @saved_sql_mode */ ; @@ -43012,38 +43012,38 @@ DELIMITER ; /*!50003 SET sql_mode = 'NO_ENGINE_SUBSTITUTION' */ ; DELIMITER ;; CREATE DEFINER=`root`@`%` PROCEDURE `itemLastEntries`(IN `vItem` INT, IN `vDays` DATE) -BEGIN - SELECT - w.id AS warehouseFk, - w.name AS warehouse, - tr.landed, - b.entryFk, - b.isIgnored, - b.price2, - b.price3, - b.stickers, - b.packing, - b.`grouping`, - b.groupingMode, - i.stems, - b.quantity, - b.buyingValue, - b.packageFk , - s.id AS supplierFk, - s.name AS supplier - FROM itemType it - RIGHT JOIN (entry e - LEFT JOIN supplier s ON s.id = e.supplierFk - RIGHT JOIN buy b ON b.entryFk = e.id - LEFT JOIN item i ON i.id = b.itemFk - LEFT JOIN ink ON ink.id = i.inkFk - LEFT JOIN travel tr ON tr.id = e.travelFk - LEFT JOIN warehouse w ON w.id = tr.warehouseInFk - LEFT JOIN origin o ON o.id = i.originFk - ) ON it.id = i.typeFk - LEFT JOIN edi.ekt ek ON b.ektFk = ek.id - WHERE b.itemFk = vItem And tr.shipped BETWEEN vDays AND DATE_ADD(CURDATE(), INTERVAl + 10 DAY) - ORDER BY tr.landed DESC , b.id DESC; +BEGIN + SELECT + w.id AS warehouseFk, + w.name AS warehouse, + tr.landed, + b.entryFk, + b.isIgnored, + b.price2, + b.price3, + b.stickers, + b.packing, + b.`grouping`, + b.groupingMode, + i.stems, + b.quantity, + b.buyingValue, + b.packageFk , + s.id AS supplierFk, + s.name AS supplier + FROM itemType it + RIGHT JOIN (entry e + LEFT JOIN supplier s ON s.id = e.supplierFk + RIGHT JOIN buy b ON b.entryFk = e.id + LEFT JOIN item i ON i.id = b.itemFk + LEFT JOIN ink ON ink.id = i.inkFk + LEFT JOIN travel tr ON tr.id = e.travelFk + LEFT JOIN warehouse w ON w.id = tr.warehouseInFk + LEFT JOIN origin o ON o.id = i.originFk + ) ON it.id = i.typeFk + LEFT JOIN edi.ekt ek ON b.ektFk = ek.id + WHERE b.itemFk = vItem And tr.shipped BETWEEN vDays AND DATE_ADD(CURDATE(), INTERVAl + 10 DAY) + ORDER BY tr.landed DESC , b.id DESC; END ;; DELIMITER ; /*!50003 SET sql_mode = @saved_sql_mode */ ; @@ -47362,77 +47362,77 @@ DELIMITER ; /*!50003 SET sql_mode = 'NO_ENGINE_SUBSTITUTION' */ ; DELIMITER ;; CREATE DEFINER=`root`@`%` PROCEDURE `saleItemShelvingMake`(IN `vTicketFk` INT, IN `vSectorFk` INT) -BEGIN - - SET @rest:= CAST(0 AS DECIMAL(10,0)); - SET @saleFk := CAST(0 AS DECIMAL(10,0)); - SET @reserved := CAST(0 AS DECIMAL(10,0)); - - UPDATE vn.itemShelving ish - JOIN vn.saleItemShelving sis ON sis.itemShelvingFk = ish.id - JOIN sale s ON s.id = sis.saleFk - SET ish.visible = sis.quantity + ish.visible, - ish.available = sis.quantity + ish.visible - WHERE s.ticketFk = vTicketFk; - - DELETE sis.* - FROM saleItemShelving sis - JOIN sale s ON s.id = sis.saleFk - WHERE s.ticketFk = vTicketFk; - - INSERT INTO saleItemShelving( saleFk, - itemShelvingFk, - quantity, - ubication) - SELECT saleFk, - itemShelvingFk, - CAST(Reserved as DECIMAL(10,0)) as Reserved, - ubication - FROM - (SELECT saleFk, - itemShelvingFk, - ubication, - @rest := IF(@saleFk = saleFk, @rest, quantity) as Falta, - @reserved := IF(available < @rest, available, IF(@rest < packing,0,@rest)) as Reserved, - @rest := @rest - @reserved, - @saleFk := saleFk - FROM - ( SELECT s.id as saleFk, - ish.created, - ish.id as itemShelvingFk, - ish.available, - s.quantity, - ish.packing, - CONCAT(p.`column`, '-',p.`row`,': ', sh.code ) as ubication - FROM vn.sale s - JOIN vn.ticket t ON t.id = s.ticketFk - JOIN vn.sector sc ON sc.warehouseFk = t.warehouseFk - JOIN vn.parking p ON p.sectorFk = sc.id - JOIN vn.shelving sh ON sh.parkingFk = p.id - JOIN vn.itemShelving ish ON ish.shelvingFk = sh.code AND ish.itemFk = s.itemFk - WHERE t.id = vTicketFk - AND sc.id = vSectorFk - AND s.quantity MOD ish.packing = 0 - AND s.quantity >= ish.packing - ORDER BY s.id, - sh.priority DESC, - ish.packing DESC, - ish.created - ) sub - ) sub2 - WHERE Reserved > 0; - - UPDATE vn.itemShelving ish - JOIN vn.saleItemShelving sis ON sis.itemShelvingFk = ish.id - JOIN vn.sale s ON s.id = sis.saleFk - SET ish.available = ish.visible - sis.quantity, - ish.visible = ish.visible - sis.quantity - WHERE s.ticketFk = vTicketFk - AND s.isPicked = FALSE; - - CALL vn.saleItemShelvingIsPicked(vTicketFk, TRUE); - - +BEGIN + + SET @rest:= CAST(0 AS DECIMAL(10,0)); + SET @saleFk := CAST(0 AS DECIMAL(10,0)); + SET @reserved := CAST(0 AS DECIMAL(10,0)); + + UPDATE vn.itemShelving ish + JOIN vn.saleItemShelving sis ON sis.itemShelvingFk = ish.id + JOIN sale s ON s.id = sis.saleFk + SET ish.visible = sis.quantity + ish.visible, + ish.available = sis.quantity + ish.visible + WHERE s.ticketFk = vTicketFk; + + DELETE sis.* + FROM saleItemShelving sis + JOIN sale s ON s.id = sis.saleFk + WHERE s.ticketFk = vTicketFk; + + INSERT INTO saleItemShelving( saleFk, + itemShelvingFk, + quantity, + ubication) + SELECT saleFk, + itemShelvingFk, + CAST(Reserved as DECIMAL(10,0)) as Reserved, + ubication + FROM + (SELECT saleFk, + itemShelvingFk, + ubication, + @rest := IF(@saleFk = saleFk, @rest, quantity) as Falta, + @reserved := IF(available < @rest, available, IF(@rest < packing,0,@rest)) as Reserved, + @rest := @rest - @reserved, + @saleFk := saleFk + FROM + ( SELECT s.id as saleFk, + ish.created, + ish.id as itemShelvingFk, + ish.available, + s.quantity, + ish.packing, + CONCAT(p.`column`, '-',p.`row`,': ', sh.code ) as ubication + FROM vn.sale s + JOIN vn.ticket t ON t.id = s.ticketFk + JOIN vn.sector sc ON sc.warehouseFk = t.warehouseFk + JOIN vn.parking p ON p.sectorFk = sc.id + JOIN vn.shelving sh ON sh.parkingFk = p.id + JOIN vn.itemShelving ish ON ish.shelvingFk = sh.code AND ish.itemFk = s.itemFk + WHERE t.id = vTicketFk + AND sc.id = vSectorFk + AND s.quantity MOD ish.packing = 0 + AND s.quantity >= ish.packing + ORDER BY s.id, + sh.priority DESC, + ish.packing DESC, + ish.created + ) sub + ) sub2 + WHERE Reserved > 0; + + UPDATE vn.itemShelving ish + JOIN vn.saleItemShelving sis ON sis.itemShelvingFk = ish.id + JOIN vn.sale s ON s.id = sis.saleFk + SET ish.available = ish.visible - sis.quantity, + ish.visible = ish.visible - sis.quantity + WHERE s.ticketFk = vTicketFk + AND s.isPicked = FALSE; + + CALL vn.saleItemShelvingIsPicked(vTicketFk, TRUE); + + END ;; DELIMITER ; /*!50003 SET sql_mode = @saved_sql_mode */ ; @@ -47925,33 +47925,33 @@ DELIMITER ; /*!50003 SET sql_mode = 'NO_ENGINE_SUBSTITUTION' */ ; DELIMITER ;; CREATE DEFINER=`root`@`%` PROCEDURE `scanTreeCreate`() -BEGIN - CALL nestTree( - 'vn2008', - 'scan', - 'vn2008', - 'scanTree' - ); - - UPDATE vn2008.scanTree st - JOIN ( - SELECT sl.scan_id, - MAX(sl.odbc_date) lastScanned, - COUNT(DISTINCT t.routeFk) routeCount, - MIN(t.routeFk) mod 1000 as minRoute, - MAX(t.routeFk) mod 1000 as maxRoute, - COUNT(sl.scan_line_id) as scanned - FROM vn2008.scan_line sl - JOIN expedition e ON e.id = sl.`code` - JOIN ticket t ON t.id = e.ticketFk - WHERE t.routeFk - GROUP BY sl.scan_id - ) rs ON rs.scan_id = st.id - SET st.lastScanned = rs.lastScanned, - st.routeCount = rs.routeCount, - st.minRoute = rs.minRoute, - st.maxRoute = IF(rs.minRoute != rs.maxRoute, rs.maxRoute,NULL), - st.scanned = rs.scanned; +BEGIN + CALL nestTree( + 'vn2008', + 'scan', + 'vn2008', + 'scanTree' + ); + + UPDATE vn2008.scanTree st + JOIN ( + SELECT sl.scan_id, + MAX(sl.odbc_date) lastScanned, + COUNT(DISTINCT t.routeFk) routeCount, + MIN(t.routeFk) mod 1000 as minRoute, + MAX(t.routeFk) mod 1000 as maxRoute, + COUNT(sl.scan_line_id) as scanned + FROM vn2008.scan_line sl + JOIN expedition e ON e.id = sl.`code` + JOIN ticket t ON t.id = e.ticketFk + WHERE t.routeFk + GROUP BY sl.scan_id + ) rs ON rs.scan_id = st.id + SET st.lastScanned = rs.lastScanned, + st.routeCount = rs.routeCount, + st.minRoute = rs.minRoute, + st.maxRoute = IF(rs.minRoute != rs.maxRoute, rs.maxRoute,NULL), + st.scanned = rs.scanned; END ;; DELIMITER ; /*!50003 SET sql_mode = @saved_sql_mode */ ; diff --git a/db/tests/vn/ticket_recalcComponents.spec.js b/db/tests/vn/ticket_recalcComponents.spec.js index e140db34c..1256528e6 100644 --- a/db/tests/vn/ticket_recalcComponents.spec.js +++ b/db/tests/vn/ticket_recalcComponents.spec.js @@ -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); diff --git a/db/tests/vn/zone_getFromGeo.spec.js b/db/tests/vn/zone_getFromGeo.spec.js new file mode 100644 index 000000000..0dccf92cc --- /dev/null +++ b/db/tests/vn/zone_getFromGeo.spec.js @@ -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); + }); +}); diff --git a/db/tests/vn/zone_getLanded.spec.js b/db/tests/vn/zone_getLanded.spec.js new file mode 100644 index 000000000..92c3f435b --- /dev/null +++ b/db/tests/vn/zone_getLanded.spec.js @@ -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); + }); +}); diff --git a/e2e/dms/a87/4.txt b/e2e/dms/a87/4.txt new file mode 100644 index 000000000..a46bfbeda --- /dev/null +++ b/e2e/dms/a87/4.txt @@ -0,0 +1 @@ +File: 4.txt. It works! \ No newline at end of file diff --git a/e2e/helpers/extensions.js b/e2e/helpers/extensions.js index 2484728f4..636819860 100644 --- a/e2e/helpers/extensions.js +++ b/e2e/helpers/extensions.js @@ -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(); } }; diff --git a/e2e/helpers/puppeteer.js b/e2e/helpers/puppeteer.js index 67f9da427..02ef82b1b 100644 --- a/e2e/helpers/puppeteer.js +++ b/e2e/helpers/puppeteer.js @@ -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, diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js index 826f5b6ec..6ec1d8ebe 100644 --- a/e2e/helpers/selectors.js +++ b/e2e/helpers/selectors.js @@ -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: { diff --git a/e2e/paths/01-login/01_login.spec.js b/e2e/paths/01-login/01_login.spec.js index 6b101b00b..ed507df4e 100644 --- a/e2e/paths/01-login/01_login.spec.js +++ b/e2e/paths/01-login/01_login.spec.js @@ -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'); + }); + }); }); diff --git a/e2e/paths/02-client/01_create_client.spec.js b/e2e/paths/02-client/01_create_client.spec.js index 0b8c96c16..2fdc4b091 100644 --- a/e2e/paths/02-client/01_create_client.spec.js +++ b/e2e/paths/02-client/01_create_client.spec.js @@ -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() => { diff --git a/e2e/paths/02-client/02_edit_basic_data.spec.js b/e2e/paths/02-client/02_edit_basic_data.spec.js index 6ae512542..2e53a6ef8 100644 --- a/e2e/paths/02-client/02_edit_basic_data.spec.js +++ b/e2e/paths/02-client/02_edit_basic_data.spec.js @@ -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() => { diff --git a/e2e/paths/02-client/03_edit_fiscal_data.spec.js b/e2e/paths/02-client/03_edit_fiscal_data.spec.js index 10a29cdfa..978627a60 100644 --- a/e2e/paths/02-client/03_edit_fiscal_data.spec.js +++ b/e2e/paths/02-client/03_edit_fiscal_data.spec.js @@ -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 diff --git a/e2e/paths/02-client/04_edit_billing_data.spec.js b/e2e/paths/02-client/04_edit_billing_data.spec.js index b757940be..394324509 100644 --- a/e2e/paths/02-client/04_edit_billing_data.spec.js +++ b/e2e/paths/02-client/04_edit_billing_data.spec.js @@ -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'); }); diff --git a/e2e/paths/02-client/05_add_address.spec.js b/e2e/paths/02-client/05_add_address.spec.js index f22798453..2fe238fea 100644 --- a/e2e/paths/02-client/05_add_address.spec.js +++ b/e2e/paths/02-client/05_add_address.spec.js @@ -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() => { diff --git a/e2e/paths/02-client/06_add_address_notes.spec.js b/e2e/paths/02-client/06_add_address_notes.spec.js index abfa1ae34..bf367f5ae 100644 --- a/e2e/paths/02-client/06_add_address_notes.spec.js +++ b/e2e/paths/02-client/06_add_address_notes.spec.js @@ -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'); }); }); diff --git a/e2e/paths/02-client/07_edit_web_access.spec.js b/e2e/paths/02-client/07_edit_web_access.spec.js index f9b023716..95886f57c 100644 --- a/e2e/paths/02-client/07_edit_web_access.spec.js +++ b/e2e/paths/02-client/07_edit_web_access.spec.js @@ -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'); diff --git a/e2e/paths/02-client/08_add_notes.spec.js b/e2e/paths/02-client/08_add_notes.spec.js index 3d6a8a915..d0b117ac9 100644 --- a/e2e/paths/02-client/08_add_notes.spec.js +++ b/e2e/paths/02-client/08_add_notes.spec.js @@ -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() => { diff --git a/e2e/paths/02-client/09_add_credit.spec.js b/e2e/paths/02-client/09_add_credit.spec.js index 639d850f6..8d1c9be1c 100644 --- a/e2e/paths/02-client/09_add_credit.spec.js +++ b/e2e/paths/02-client/09_add_credit.spec.js @@ -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() => { diff --git a/e2e/paths/02-client/10_add_greuge.spec.js b/e2e/paths/02-client/10_add_greuge.spec.js index 1dda319be..b7e130683 100644 --- a/e2e/paths/02-client/10_add_greuge.spec.js +++ b/e2e/paths/02-client/10_add_greuge.spec.js @@ -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() => { diff --git a/e2e/paths/02-client/12_lock_of_verified_data.spec.js b/e2e/paths/02-client/12_lock_of_verified_data.spec.js index c8e590c34..79a9e17ac 100644 --- a/e2e/paths/02-client/12_lock_of_verified_data.spec.js +++ b/e2e/paths/02-client/12_lock_of_verified_data.spec.js @@ -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() => { diff --git a/e2e/paths/02-client/13_log.spec.js b/e2e/paths/02-client/13_log.spec.js index fc4b98b8b..93397d301 100644 --- a/e2e/paths/02-client/13_log.spec.js +++ b/e2e/paths/02-client/13_log.spec.js @@ -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() => { diff --git a/e2e/paths/02-client/14_balance.spec.js b/e2e/paths/02-client/14_balance.spec.js index 87dc84a8e..108f76710 100644 --- a/e2e/paths/02-client/14_balance.spec.js +++ b/e2e/paths/02-client/14_balance.spec.js @@ -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() => { diff --git a/e2e/paths/02-client/15_user_config.spec.js b/e2e/paths/02-client/15_user_config.spec.js index 89d4e004a..28f2ef29e 100644 --- a/e2e/paths/02-client/15_user_config.spec.js +++ b/e2e/paths/02-client/15_user_config.spec.js @@ -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'); }); }); }); diff --git a/e2e/paths/02-client/17_dms.spec.js b/e2e/paths/02-client/17_dms.spec.js index 95b37093a..32cca05f3 100644 --- a/e2e/paths/02-client/17_dms.spec.js +++ b/e2e/paths/02-client/17_dms.spec.js @@ -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() => { diff --git a/e2e/paths/02-client/18_contacts.spec.js b/e2e/paths/02-client/18_contacts.spec.js index fd8b68283..87e75a975 100644 --- a/e2e/paths/02-client/18_contacts.spec.js +++ b/e2e/paths/02-client/18_contacts.spec.js @@ -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'); }); }); diff --git a/e2e/paths/03-worker/02_basicData.spec.js b/e2e/paths/03-worker/02_basicData.spec.js index 21443c517..a24ffd033 100644 --- a/e2e/paths/03-worker/02_basicData.spec.js +++ b/e2e/paths/03-worker/02_basicData.spec.js @@ -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() => { diff --git a/e2e/paths/03-worker/03_pbx.spec.js b/e2e/paths/03-worker/03_pbx.spec.js index 83849a5dd..f2a567af2 100644 --- a/e2e/paths/03-worker/03_pbx.spec.js +++ b/e2e/paths/03-worker/03_pbx.spec.js @@ -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'); }); }); diff --git a/e2e/paths/03-worker/04_time_control.spec.js b/e2e/paths/03-worker/04_time_control.spec.js index 36340e880..c94137e2f 100644 --- a/e2e/paths/03-worker/04_time_control.spec.js +++ b/e2e/paths/03-worker/04_time_control.spec.js @@ -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() => { diff --git a/e2e/paths/04-item/01_summary.spec.js b/e2e/paths/04-item/01_summary.spec.js index 6f2c2c926..7658cb752 100644 --- a/e2e/paths/04-item/01_summary.spec.js +++ b/e2e/paths/04-item/01_summary.spec.js @@ -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() => { diff --git a/e2e/paths/04-item/02_basic_data.spec.js b/e2e/paths/04-item/02_basic_data.spec.js index ce56b9a5c..7a9b9a1e7 100644 --- a/e2e/paths/04-item/02_basic_data.spec.js +++ b/e2e/paths/04-item/02_basic_data.spec.js @@ -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() => { diff --git a/e2e/paths/04-item/03_tax.spec.js b/e2e/paths/04-item/03_tax.spec.js index ef2d68096..b05dcb286 100644 --- a/e2e/paths/04-item/03_tax.spec.js +++ b/e2e/paths/04-item/03_tax.spec.js @@ -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() => { diff --git a/e2e/paths/04-item/04_tags.spec.js b/e2e/paths/04-item/04_tags.spec.js index 098ac75eb..f53ff3582 100644 --- a/e2e/paths/04-item/04_tags.spec.js +++ b/e2e/paths/04-item/04_tags.spec.js @@ -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() => { diff --git a/e2e/paths/04-item/05_niche.spec.js b/e2e/paths/04-item/05_niche.spec.js index 4da8ed5fe..4ad0398c2 100644 --- a/e2e/paths/04-item/05_niche.spec.js +++ b/e2e/paths/04-item/05_niche.spec.js @@ -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() => { diff --git a/e2e/paths/04-item/06_botanical.spec.js b/e2e/paths/04-item/06_botanical.spec.js index edcc94f28..84a144f1d 100644 --- a/e2e/paths/04-item/06_botanical.spec.js +++ b/e2e/paths/04-item/06_botanical.spec.js @@ -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() => { diff --git a/e2e/paths/04-item/07_barcode.spec.js b/e2e/paths/04-item/07_barcode.spec.js index 7750b4b6d..0220b3a9d 100644 --- a/e2e/paths/04-item/07_barcode.spec.js +++ b/e2e/paths/04-item/07_barcode.spec.js @@ -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() => { diff --git a/e2e/paths/04-item/08_create_and_clone.spec.js b/e2e/paths/04-item/08_create_and_clone.spec.js index 73249a0b9..4d035a4c3 100644 --- a/e2e/paths/04-item/08_create_and_clone.spec.js +++ b/e2e/paths/04-item/08_create_and_clone.spec.js @@ -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); }); }); }); diff --git a/e2e/paths/04-item/09_regularize.spec.js b/e2e/paths/04-item/09_regularize.spec.js index a37d97fa3..6de995515 100644 --- a/e2e/paths/04-item/09_regularize.spec.js +++ b/e2e/paths/04-item/09_regularize.spec.js @@ -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() => { diff --git a/e2e/paths/04-item/10_index.spec.js b/e2e/paths/04-item/10_index.spec.js index e15469283..b4c4b636e 100644 --- a/e2e/paths/04-item/10_index.spec.js +++ b/e2e/paths/04-item/10_index.spec.js @@ -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() => { diff --git a/e2e/paths/04-item/11_item_log.spec.js b/e2e/paths/04-item/11_item_log.spec.js index 82800b9b8..7ea679f4a 100644 --- a/e2e/paths/04-item/11_item_log.spec.js +++ b/e2e/paths/04-item/11_item_log.spec.js @@ -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() => { diff --git a/e2e/paths/04-item/12_descriptor.spec.js b/e2e/paths/04-item/12_descriptor.spec.js index 84614cf30..35be1135e 100644 --- a/e2e/paths/04-item/12_descriptor.spec.js +++ b/e2e/paths/04-item/12_descriptor.spec.js @@ -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'); }); }); diff --git a/e2e/paths/05-ticket/01-sale/01_list_sales.spec.js b/e2e/paths/05-ticket/01-sale/01_list_sales.spec.js index a6d34a473..e8b0ad8e7 100644 --- a/e2e/paths/05-ticket/01-sale/01_list_sales.spec.js +++ b/e2e/paths/05-ticket/01-sale/01_list_sales.spec.js @@ -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() => { diff --git a/e2e/paths/05-ticket/01-sale/02_edit_sale.spec.js b/e2e/paths/05-ticket/01-sale/02_edit_sale.spec.js index f2265797c..a22b0e022 100644 --- a/e2e/paths/05-ticket/01-sale/02_edit_sale.spec.js +++ b/e2e/paths/05-ticket/01-sale/02_edit_sale.spec.js @@ -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(); }); diff --git a/e2e/paths/05-ticket/01_observations.spec.js b/e2e/paths/05-ticket/01_observations.spec.js index cccfa8b67..d919b8ed3 100644 --- a/e2e/paths/05-ticket/01_observations.spec.js +++ b/e2e/paths/05-ticket/01_observations.spec.js @@ -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'); }); }); diff --git a/e2e/paths/05-ticket/02_expeditions_and_log.spec.js b/e2e/paths/05-ticket/02_expeditions_and_log.spec.js index f0accedaf..2d046e3a9 100644 --- a/e2e/paths/05-ticket/02_expeditions_and_log.spec.js +++ b/e2e/paths/05-ticket/02_expeditions_and_log.spec.js @@ -30,7 +30,7 @@ describe('Ticket expeditions and log path', () => { }); it(`should confirm the expedition deleted is shown now in the ticket log`, async() => { - await page.waitToClick(selectors.ticketLog.logButton); + await page.accessToSection('ticket.card.log'); const changedBy = await page .waitToGetProperty(selectors.ticketLog.changedBy, 'innerText'); diff --git a/e2e/paths/05-ticket/04_packages.spec.js b/e2e/paths/05-ticket/04_packages.spec.js index fd2945877..3db53587c 100644 --- a/e2e/paths/05-ticket/04_packages.spec.js +++ b/e2e/paths/05-ticket/04_packages.spec.js @@ -22,18 +22,18 @@ describe('Ticket Create packages path', () => { await page.waitToClick(selectors.ticketPackages.addPackageButton); await page.write(selectors.ticketPackages.firstQuantity, '99'); await page.waitToClick(selectors.ticketPackages.savePackagesButton); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('Package cannot be blank'); + expect(message.text).toBe('Package cannot be blank'); }); it(`should delete the first package and receive and error to save a new one with blank quantity`, async() => { await page.clearInput(selectors.ticketPackages.firstQuantity); await page.autocompleteSearch(selectors.ticketPackages.firstPackage, 'Container medical box 1m'); await page.waitToClick(selectors.ticketPackages.savePackagesButton); - 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 the quantity input isn't invalid yet`, async() => { @@ -49,9 +49,9 @@ describe('Ticket Create packages path', () => { await page.clearInput(selectors.ticketPackages.firstQuantity); await page.write(selectors.ticketPackages.firstQuantity, '-99'); await page.waitToClick(selectors.ticketPackages.savePackagesButton); - 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 select is the expected one`, async() => { diff --git a/e2e/paths/05-ticket/05_tracking_state.spec.js b/e2e/paths/05-ticket/05_tracking_state.spec.js index 2623966be..34f3c4d44 100644 --- a/e2e/paths/05-ticket/05_tracking_state.spec.js +++ b/e2e/paths/05-ticket/05_tracking_state.spec.js @@ -26,17 +26,17 @@ describe('Ticket Create new tracking state path', () => { it(`should attempt create a new state but receive an error if state is empty`, async() => { await page.waitToClick(selectors.createStateView.saveStateButton); - let result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('State cannot be blank'); + expect(message.text).toBe('State cannot be blank'); }); it(`should create a new state`, async() => { await page.autocompleteSearch(selectors.createStateView.state, '¿Fecha?'); await page.waitToClick(selectors.createStateView.saveStateButton); - let result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('Data saved!'); + expect(message.type).toBe('success'); }); }); @@ -56,14 +56,14 @@ describe('Ticket Create new tracking state path', () => { await page.waitFor(1500); await page.autocompleteSearch(selectors.createStateView.state, 'Encajado'); await page.waitToClick(selectors.createStateView.saveStateButton); - let result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual(`You don't have enough privileges`); + expect(message.text).toBe(`You don't have enough privileges`); }); it(`should make sure the worker gets autocomplete uppon selecting the assigned state`, async() => { await page.autocompleteSearch(selectors.createStateView.state, 'asignado'); - let result = await page + const result = await page .waitToGetProperty(selectors.createStateView.worker, 'value'); expect(result).toEqual('salesPersonNick'); @@ -71,9 +71,9 @@ describe('Ticket Create new tracking state path', () => { it(`should succesfully create a valid state`, async() => { await page.waitToClick(selectors.createStateView.saveStateButton); - let result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('Data saved!'); + expect(message.type).toBe('success'); }); }); }); diff --git a/e2e/paths/05-ticket/09_weekly.spec.js b/e2e/paths/05-ticket/09_weekly.spec.js index 1629107fb..79722d2f7 100644 --- a/e2e/paths/05-ticket/09_weekly.spec.js +++ b/e2e/paths/05-ticket/09_weekly.spec.js @@ -17,7 +17,6 @@ describe('Ticket descriptor path', () => { }); it('should count the amount of tickets in the turns section', async() => { - await page.waitForNumberOfElements(selectors.ticketsIndex.weeklyTicket, 5); const result = await page.countElement(selectors.ticketsIndex.weeklyTicket); expect(result).toEqual(5); @@ -32,9 +31,9 @@ describe('Ticket descriptor path', () => { await page.waitToClick(selectors.ticketDescriptor.moreMenu); await page.waitToClick(selectors.ticketDescriptor.moreMenuAddToTurn); await page.waitToClick(selectors.ticketDescriptor.thursdayButton); - 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() => { @@ -67,9 +66,9 @@ describe('Ticket descriptor path', () => { await page.waitToClick(selectors.ticketDescriptor.moreMenu); await page.waitToClick(selectors.ticketDescriptor.moreMenuAddToTurn); await page.waitToClick(selectors.ticketDescriptor.saturdayButton); - 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 once again', async() => { @@ -87,29 +86,36 @@ describe('Ticket descriptor path', () => { }); it('should now search for the weekly ticket 11', async() => { - await page.write(selectors.ticketsIndex.topbarSearch, '11'); - await page.waitToClick(selectors.ticketsIndex.searchButton); - await page.waitForNumberOfElements(selectors.ticketsIndex.searchWeeklyResult, 1); - const result = await page.countElement(selectors.ticketsIndex.searchWeeklyResult); + await page.doSearch('11'); + const nResults = await page.countElement(selectors.ticketsIndex.searchWeeklyResult); - expect(result).toEqual(1); + expect(nResults).toEqual(1); }); it('should delete the weekly ticket 11', async() => { await page.waitToClick(selectors.ticketsIndex.firstWeeklyTicketDeleteIcon); await page.waitToClick(selectors.ticketsIndex.acceptDeleteTurn); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('Data saved!'); + expect(message.type).toBe('success'); }); it('should confirm the sixth weekly ticket was deleted', async() => { - await page.waitForContentLoaded(); - await page.clearInput('vn-searchbar'); - await page.waitToClick(selectors.ticketsIndex.searchWeeklyButton); - await page.waitForNumberOfElements(selectors.ticketsIndex.searchWeeklyResult, 5); - const result = await page.countElement(selectors.ticketsIndex.searchWeeklyResult); + await page.doSearch(); + const nResults = await page.countElement(selectors.ticketsIndex.searchWeeklyResult); - expect(result).toEqual(5); + expect(nResults).toEqual(5); + }); + + it('should update the agency then remove it afterwards', async() => { + await page.autocompleteSearch(selectors.ticketsIndex.firstWeeklyTicketAgency, 'Silla247'); + let message = await page.waitForSnackbar(); + + expect(message.type).toBe('success'); + + await page.clearInput(selectors.ticketsIndex.firstWeeklyTicketAgency); + message = await page.waitForSnackbar(); + + expect(message.type).toBe('success'); }); }); diff --git a/e2e/paths/05-ticket/10_request.spec.js b/e2e/paths/05-ticket/10_request.spec.js index 2bb0cbb73..334b8ba5e 100644 --- a/e2e/paths/05-ticket/10_request.spec.js +++ b/e2e/paths/05-ticket/10_request.spec.js @@ -24,9 +24,9 @@ describe('Ticket purchase request path', () => { await page.autocompleteSearch(selectors.ticketRequests.atender, 'buyerNick'); await page.write(selectors.ticketRequests.price, '999'); await page.waitToClick(selectors.ticketRequests.saveButton); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('Data saved!'); + expect(message.type).toBe('success'); }); it('should have been redirected to the request index', async() => { @@ -36,9 +36,9 @@ describe('Ticket purchase request path', () => { it(`should edit the third request quantity as it's state is still new`, async() => { await page.write(selectors.ticketRequests.thirdRequestQuantity, '9'); 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 confirm the new request was added', async() => { @@ -64,9 +64,9 @@ describe('Ticket purchase request path', () => { it('should delete the added request', async() => { await page.waitToClick(selectors.ticketRequests.thirdRemoveRequestButton); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('Data saved!'); + expect(message.type).toBe('success'); }); it('should confirm the request was deleted', async() => { diff --git a/e2e/paths/05-ticket/11_diary.spec.js b/e2e/paths/05-ticket/11_diary.spec.js index 5e900fd25..e4c63855a 100644 --- a/e2e/paths/05-ticket/11_diary.spec.js +++ b/e2e/paths/05-ticket/11_diary.spec.js @@ -1,66 +1,31 @@ import selectors from '../../helpers/selectors.js'; import getBrowser from '../../helpers/puppeteer'; -// #2026 Fallo en relocate de descriptor popover +// #2221 Local MySQL8 crashes when rest method Items/getBalance is called xdescribe('Ticket diary path', () => { - let browser; let page; beforeAll(async() => { - browser = await getBrowser(); - page = browser.page; + page = (await getBrowser()).page; await page.loginAndModule('employee', 'ticket'); }); afterAll(async() => { - await browser.close(); + await page.browser().close(); }); - it('should search for a specific ticket', async() => { - await page.write(selectors.ticketsIndex.topbarSearch, '1'); - await page.waitToClick(selectors.ticketsIndex.searchButton); - await page.waitForNumberOfElements(selectors.ticketsIndex.searchResult, 1); - const result = await page.countElement(selectors.ticketsIndex.searchResult); - - expect(result).toEqual(1); - }); - - it(`should click on the search result to access to the ticket summary`, async() => { - await page.waitForTextInElement(selectors.ticketsIndex.searchResult, 'Bat cave'); - await page.waitToClick(selectors.ticketsIndex.searchResult); - let url = await page.expectURL('/summary'); // use waitForState instead - - expect(url).toBe(true); - }); - - it(`should navigate to the item diary from the 1st sale item id descriptor popover`, async() => { + it(`should navigate to item diary from ticket sale and check the lines`, async() => { + await page.accessToSearchResult('1'); await page.waitToClick(selectors.ticketSummary.firstSaleItemId); - await page.waitForTransitionEnd('.vn-popover'); await page.waitToClick(selectors.ticketSummary.popoverDiaryButton); - let url = await page.expectURL('/diary'); // use waitForState instead + await page.waitForState('item.card.diary'); - expect(url).toBe(true); - }); + const secondIdClass = await page.getClassName(selectors.itemDiary.secondTicketId); + const fourthBalanceClass = await page.getClassName(selectors.itemDiary.fourthBalance); + const firstBalanceClass = await page.getClassName(selectors.itemDiary.firstBalance); - it(`should check the second line id is marked as message`, async() => { - const result = await page - .waitToGetProperty(selectors.itemDiary.secondTicketId, 'className'); - - expect(result).toContain('message'); - }); - - it(`should check the third line balance is marked as message`, async() => { - const result = await page - .waitToGetProperty(`${selectors.itemDiary.fourthBalance} > span`, 'className'); - - expect(result).toContain('message'); - }); - - it(`should change to the warehouse two and check there are sales marked as negative balance`, async() => { - await page.autocompleteSearch(selectors.itemDiary.warehouse, 'Warehouse Two'); - const result = await page - .waitToGetProperty(selectors.itemDiary.firstBalance, 'className'); - - expect(result).toContain('balance'); + expect(secondIdClass).toContain('message'); + expect(fourthBalanceClass).toContain('message'); + expect(firstBalanceClass).toContain('balance'); }); }); diff --git a/e2e/paths/05-ticket/12_descriptor.spec.js b/e2e/paths/05-ticket/12_descriptor.spec.js index ce9f064dd..faeae0c3f 100644 --- a/e2e/paths/05-ticket/12_descriptor.spec.js +++ b/e2e/paths/05-ticket/12_descriptor.spec.js @@ -26,9 +26,9 @@ describe('Ticket descriptor path', () => { await page.waitToClick(selectors.ticketDescriptor.moreMenuChangeShippedHour); await page.pickTime(selectors.ticketDescriptor.changeShippedHour, '08:15'); await page.waitToClick(selectors.ticketDescriptor.acceptChangeHourButton); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('Shipped hour updated'); + expect(message.text).toBe('Shipped hour updated'); }); it(`should confirm the ticket descriptor shows the correct shipping hour`, async() => { @@ -42,9 +42,9 @@ describe('Ticket descriptor path', () => { await page.waitToClick(selectors.ticketDescriptor.moreMenu); await page.waitToClick(selectors.ticketDescriptor.moreMenuDeleteTicket); await page.waitToClick(selectors.ticketDescriptor.acceptDeleteButton); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('Ticket deleted'); + expect(message.text).toBe('Ticket deleted'); }); it('should have been relocated to the ticket index', async() => { @@ -82,12 +82,13 @@ describe('Ticket descriptor path', () => { it('should add a ticket as stowaway', async() => { await page.waitToClick(selectors.ticketDescriptor.addStowawayDialogFirstTicket); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('Data saved!'); + expect(message.type).toBe('success'); }); - it(`should check the state of the stowaway ticket is embarked`, async() => { + xit(`should check the state of the stowaway ticket is embarked`, async() => { + await page.wait(500); const state = await page.waitToGetProperty(selectors.ticketDescriptor.stateLabelValue, 'innerText'); expect(state).toEqual('State Embarcando'); @@ -99,13 +100,13 @@ describe('Ticket descriptor path', () => { }); it('should delete the stowaway', async() => { - await page.waitForContentLoaded(); await page.waitToClick(selectors.ticketDescriptor.moreMenu); + await page.waitForContentLoaded(); await page.waitToClick(selectors.ticketDescriptor.moreMenuDeleteStowawayButton); await page.waitToClick(selectors.ticketDescriptor.acceptDeleteStowawayButton); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('Data saved!'); + expect(message.type).toBe('success'); }); it(`should confirm the ship buton doesn't exisist any more`, async() => { @@ -130,13 +131,13 @@ describe('Ticket descriptor path', () => { }); it('should invoice the ticket using the descriptor more menu', async() => { - await page.waitForContentLoaded(); await page.waitToClick(selectors.ticketDescriptor.moreMenu); + await page.waitForContentLoaded(); await page.waitToClick(selectors.ticketDescriptor.moreMenuMakeInvoice); await page.waitToClick(selectors.ticketDescriptor.acceptInvoiceOutButton); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('Ticket invoiced'); + expect(message.text).toBe('Ticket invoiced'); }); it(`should make sure the ticket summary have an invoiceOutFk`, async() => { diff --git a/e2e/paths/05-ticket/13_services.spec.js b/e2e/paths/05-ticket/13_services.spec.js index 1a32ea944..08b9219a5 100644 --- a/e2e/paths/05-ticket/13_services.spec.js +++ b/e2e/paths/05-ticket/13_services.spec.js @@ -32,9 +32,9 @@ describe('Ticket services path', () => { await page.clearInput(selectors.ticketService.firstPrice); await page.write(selectors.ticketService.firstPrice, '999'); await page.waitToClick(selectors.ticketService.saveServiceButton); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual(`The current ticket can't be modified`); + expect(message.text).toBe(`The current ticket can't be modified`); }); }); @@ -56,9 +56,9 @@ describe('Ticket services path', () => { it('should receive an error if you attempt to save it with empty fields', async() => { await page.waitToClick(selectors.ticketService.saveServiceButton); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual(`can't be blank`); + expect(message.text).toBe(`can't be blank`); }); it('should click on the add new service type to open the dialog', async() => { @@ -71,9 +71,9 @@ describe('Ticket services path', () => { it('should receive an error if service type is empty on submit', async() => { await page.waitToClick(selectors.ticketService.saveServiceTypeButton); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual(`Name can't be empty`); + expect(message.text).toBe(`Name can't be empty`); }); it('should create a new service type then add price then create the service', async() => { @@ -81,11 +81,10 @@ describe('Ticket services path', () => { await page.autocompleteSearch(selectors.ticketService.newServiceTypeExpense, 'Retencion'); await page.waitToClick(selectors.ticketService.saveServiceTypeButton); await page.write(selectors.ticketService.firstPrice, '999'); - await page.waitFor(1000); // time needed for the button to be clickable await page.waitToClick(selectors.ticketService.saveServiceButton); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('Data saved!'); + expect(message.type).toBe('success'); }); it('should confirm the service description was created correctly', async() => { @@ -120,19 +119,17 @@ describe('Ticket services path', () => { it('should delete the service', async() => { await page.waitToClick(selectors.ticketService.fistDeleteServiceButton); await page.waitForNumberOfElements(selectors.ticketService.serviceLine, 0); - await page.waitFor(1000); // without this wait it fails to click the save button await page.waitToClick(selectors.ticketService.saveServiceButton); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('Data saved!'); + expect(message.type).toBe('success'); }); it(`should confirm the service was removed`, async() => { await page.reloadSection('ticket.card.service'); - await page.waitForNumberOfElements(selectors.ticketService.serviceLine, 0); - const result = await page.countElement(selectors.ticketService.serviceLine); + const nResults = await page.countElement(selectors.ticketService.serviceLine); - expect(result).toEqual(0); + expect(nResults).toEqual(0); }); }); }); diff --git a/e2e/paths/05-ticket/14_create_ticket.spec.js b/e2e/paths/05-ticket/14_create_ticket.spec.js index 176e89930..4ce2e5156 100644 --- a/e2e/paths/05-ticket/14_create_ticket.spec.js +++ b/e2e/paths/05-ticket/14_create_ticket.spec.js @@ -30,9 +30,9 @@ describe('Ticket create path', () => { await page.autocompleteSearch(selectors.createTicketView.warehouse, 'Warehouse One'); await page.autocompleteSearch(selectors.createTicketView.agency, 'Silla247'); await page.waitToClick(selectors.createTicketView.createButton); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('Data saved!'); + expect(message.type).toBe('success'); }); it('should check the url is now the summary of the ticket', async() => { diff --git a/e2e/paths/05-ticket/16_summary.spec.js b/e2e/paths/05-ticket/16_summary.spec.js index 7ead648a2..f6808651e 100644 --- a/e2e/paths/05-ticket/16_summary.spec.js +++ b/e2e/paths/05-ticket/16_summary.spec.js @@ -78,14 +78,14 @@ describe('Ticket Summary path', () => { it('should click on the SET OK button', async() => { await page.waitToClick(selectors.ticketSummary.setOk); - let result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('Data saved!'); + expect(message.type).toBe('success'); }); it('should confirm the ticket state was updated', async() => { await page.waitForSpinnerLoad(); - let result = await page.waitToGetProperty(selectors.ticketSummary.state, 'innerText'); + const result = await page.waitToGetProperty(selectors.ticketSummary.state, 'innerText'); expect(result).toContain('OK'); }); diff --git a/e2e/paths/05-ticket/17_log.spec.js b/e2e/paths/05-ticket/17_log.spec.js index c677d2e62..97e121460 100644 --- a/e2e/paths/05-ticket/17_log.spec.js +++ b/e2e/paths/05-ticket/17_log.spec.js @@ -27,14 +27,13 @@ describe('Ticket log 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 navigate to the log section', async() => { await page.accessToSection('ticket.card.log'); - await page.waitForState('ticket.card.log'); }); it('should set the viewport width to 1920 to see the table full width', async() => { diff --git a/e2e/paths/05-ticket/18_index_payout.spec.js b/e2e/paths/05-ticket/18_index_payout.spec.js index 749428c44..b1dc06e51 100644 --- a/e2e/paths/05-ticket/18_index_payout.spec.js +++ b/e2e/paths/05-ticket/18_index_payout.spec.js @@ -16,9 +16,7 @@ describe('Ticket index payout path', () => { it('should navigate to the ticket index', async() => { await page.loginAndModule('administrative', 'ticket'); - let url = await page.expectURL('#!/ticket/index'); - - expect(url).toBe(true); + await page.waitForState('ticket.index'); }); it('should check three tickets 2 of a clinet and 1 of another', async() => { @@ -26,9 +24,9 @@ describe('Ticket index payout path', () => { await page.waitToClick(selectors.ticketsIndex.secondTicketCheckbox); await page.waitToClick(selectors.ticketsIndex.sixthTicketCheckbox); await page.waitToClick(selectors.ticketsIndex.payoutButton); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('You cannot make a payment on account from multiple clients'); + expect(message.text).toBe('You cannot make a payment on account from multiple clients'); }); it('should uncheck the sixth ticket result and check the third which is from the same client then open the payout form', async() => { @@ -42,9 +40,9 @@ describe('Ticket index payout path', () => { it('should fill the company and bank to perform a payout', async() => { await page.autocompleteSearch(selectors.ticketsIndex.payoutBank, 'cash'); await page.waitToClick(selectors.ticketsIndex.submitPayout); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('Data saved!'); + expect(message.type).toBe('success'); }); it('should navigate to the client balance section and check a new balance line was entered', async() => { diff --git a/e2e/paths/06-claim/01_basic_data.spec.js b/e2e/paths/06-claim/01_basic_data.spec.js index 222cb558b..a255188e2 100644 --- a/e2e/paths/06-claim/01_basic_data.spec.js +++ b/e2e/paths/06-claim/01_basic_data.spec.js @@ -25,9 +25,9 @@ describe('Claim edit basic data path', () => { await page.clearTextarea(selectors.claimBasicData.observation); await page.write(selectors.claimBasicData.observation, 'edited observation'); await page.waitToClick(selectors.claimBasicData.saveButton); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('Data saved!'); + expect(message.type).toBe('success'); }); it(`should have been redirected to the next section of claims as the role is salesAssistant`, async() => { @@ -54,8 +54,8 @@ describe('Claim edit basic data path', () => { await page.clearTextarea(selectors.claimBasicData.observation); await page.write(selectors.claimBasicData.observation, 'Observation one'); await page.waitToClick(selectors.claimBasicData.saveButton); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('Data saved!'); + expect(message.type).toBe('success'); }); }); diff --git a/e2e/paths/06-claim/02_development.spec.js b/e2e/paths/06-claim/02_development.spec.js index 970a801ee..8efae48d4 100644 --- a/e2e/paths/06-claim/02_development.spec.js +++ b/e2e/paths/06-claim/02_development.spec.js @@ -26,9 +26,9 @@ describe('Claim development', () => { await page.autocompleteSearch(selectors.claimDevelopment.secondClaimWorker, 'deliveryNick'); await page.autocompleteSearch(selectors.claimDevelopment.secondClaimRedelivery, 'Reparto'); await page.waitToClick(selectors.claimDevelopment.saveDevelopmentButton); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('Data saved!'); + expect(message.type).toBe('success'); }); it(`should redirect to the next section of claims as the role is salesAssistant`, async() => { @@ -43,9 +43,9 @@ describe('Claim development', () => { await page.autocompleteSearch(selectors.claimDevelopment.firstClaimWorker, 'adminAssistantNick'); await page.autocompleteSearch(selectors.claimDevelopment.firstClaimRedelivery, 'Cliente'); await page.waitToClick(selectors.claimDevelopment.saveDevelopmentButton); - 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 development is the expected one', async() => { diff --git a/e2e/paths/06-claim/03_detail.spec.js b/e2e/paths/06-claim/03_detail.spec.js index 93d2cba4c..9d1f6eee1 100644 --- a/e2e/paths/06-claim/03_detail.spec.js +++ b/e2e/paths/06-claim/03_detail.spec.js @@ -21,9 +21,9 @@ xdescribe('Claim detail', () => { it('should add the first claimable item from ticket to the claim', async() => { await page.waitToClick(selectors.claimDetail.addItemButton); await page.waitToClick(selectors.claimDetail.firstClaimableSaleFromTicket); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('Data saved!'); + expect(message.type).toBe('success'); }); it('should confirm the claim contains now two items', async() => { @@ -36,9 +36,9 @@ xdescribe('Claim detail', () => { await page.clearInput(selectors.claimDetail.firstItemQuantityInput); // selector deleted, find new upon fixes await page.write(selectors.claimDetail.firstItemQuantityInput, '4'); // selector deleted, find new upon fixes 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 confirm the first item quantity, and the claimed total were correctly edited', async() => { @@ -65,9 +65,9 @@ xdescribe('Claim detail', () => { await page.waitToClick(selectors.claimDetail.secondItemDiscount); await page.write(selectors.claimDetail.discount, '100'); 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 check the mana is the expected one', async() => { @@ -79,9 +79,9 @@ xdescribe('Claim detail', () => { it('should delete the second item from the claim', async() => { await page.waitToClick(selectors.claimDetail.secondItemDeleteButton); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('Data saved!'); + expect(message.type).toBe('success'); }); it('should confirm the claim contains now one item', async() => { @@ -93,9 +93,9 @@ xdescribe('Claim detail', () => { it('should add the deleted ticket from to the claim', async() => { await page.waitToClick(selectors.claimDetail.addItemButton); await page.waitToClick(selectors.claimDetail.firstClaimableSaleFromTicket); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('Data saved!'); + expect(message.type).toBe('success'); }); it(`should have been redirected to the next section in claims`, async() => { diff --git a/e2e/paths/06-claim/04_claim_action.spec.js b/e2e/paths/06-claim/04_claim_action.spec.js index a482e21c3..9897a3ef3 100644 --- a/e2e/paths/06-claim/04_claim_action.spec.js +++ b/e2e/paths/06-claim/04_claim_action.spec.js @@ -19,33 +19,36 @@ describe('Claim action path', () => { it('should import the claim', async() => { await page.waitToClick(selectors.claimAction.importClaimButton); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('Data saved!'); + expect(message.type).toBe('success'); }); it('should import the second importable ticket', async() => { - await page.waitFor(3000); // the animation adding the header element for the claimed total obscures somehow other elements for about 2 seconds + // the animation adding the header element for the claimed total + // obscures somehow other elements for about 2 seconds + await page.waitFor(3000); + await page.waitToClick(selectors.claimAction.importTicketButton); await page.waitToClick(selectors.claimAction.secondImportableTicket); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('Data saved!'); + expect(message.type).toBe('success'); }); it('should edit the second line destination field', async() => { await page.waitForContentLoaded(); await page.autocompleteSearch(selectors.claimAction.secondLineDestination, 'Bueno'); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('Data saved!'); + expect(message.type).toBe('success'); }); it('should delete the first line', async() => { await page.waitToClick(selectors.claimAction.firstDeleteLine); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toContain('Data saved!'); + expect(message.type).toBe('success'); }); it('should refresh the view to check the remaining line is the expected one', async() => { @@ -57,17 +60,17 @@ describe('Claim action path', () => { it('should delete the current first line', async() => { await page.waitToClick(selectors.claimAction.firstDeleteLine); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('Data saved!'); + expect(message.type).toBe('success'); }); it('should check the "is paid with mana" checkbox', async() => { page.waitFor(3000); // can't use waitForNavigation here and needs more time than a single second to get the section ready... await page.waitToClick(selectors.claimAction.isPaidWithManaCheckbox); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('Data saved!'); + expect(message.type).toBe('success'); }); it('should confirm the "is paid with mana" checkbox is checked', async() => { diff --git a/e2e/paths/06-claim/06_descriptor.spec.js b/e2e/paths/06-claim/06_descriptor.spec.js index ee49fe245..43d046d62 100644 --- a/e2e/paths/06-claim/06_descriptor.spec.js +++ b/e2e/paths/06-claim/06_descriptor.spec.js @@ -40,9 +40,9 @@ describe('claim Descriptor path', () => { it(`should delete the claim`, async() => { await page.waitToClick(selectors.claimDescriptor.moreMenuDeleteClaim); await page.waitToClick(selectors.claimDescriptor.acceptDeleteClaim); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('Claim deleted!'); + expect(message.text).toBe('Claim deleted!'); }); it(`should have been relocated to the claim index`, async() => { @@ -50,11 +50,9 @@ describe('claim Descriptor path', () => { }); it(`should search for the deleted claim to find no results`, async() => { - await page.write(selectors.claimsIndex.searchClaimInput, claimId); - await page.waitToClick(selectors.claimsIndex.searchButton); - await page.waitForNumberOfElements(selectors.claimsIndex.searchResult, 0); - const result = await page.countElement(selectors.claimsIndex.searchResult); + await page.doSearch(claimId); + const nResults = await page.countElement(selectors.claimsIndex.searchResult); - expect(result).toEqual(0); + expect(nResults).toEqual(0); }); }); diff --git a/e2e/paths/07-order/02_basic_data.spec.js b/e2e/paths/07-order/02_basic_data.spec.js index 2c3292b61..38d6619e0 100644 --- a/e2e/paths/07-order/02_basic_data.spec.js +++ b/e2e/paths/07-order/02_basic_data.spec.js @@ -23,9 +23,9 @@ describe('Order edit basic data path', () => { await page.autocompleteSearch(selectors.orderBasicData.client, 'Tony Stark'); await page.autocompleteSearch(selectors.orderBasicData.address, 'Tony Stark'); await page.waitToClick(selectors.orderBasicData.saveButton); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual(`You can't make changes on the basic data of an confirmed order or with rows`); + expect(message.text).toBe(`You can't make changes on the basic data of an confirmed order or with rows`); }); }); @@ -45,9 +45,9 @@ describe('Order edit basic data path', () => { it('should not be able to change anything', async() => { await page.write(selectors.orderBasicData.observation, 'observation'); await page.waitToClick(selectors.orderBasicData.saveButton); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual(`You can't make changes on the basic data of an confirmed order or with rows`); + expect(message.text).toBe(`You can't make changes on the basic data of an confirmed order or with rows`); }); }); @@ -79,9 +79,9 @@ describe('Order edit basic data path', () => { await page.autocompleteSearch(selectors.orderBasicData.agency, 'Silla247'); await page.write(selectors.orderBasicData.observation, 'my observation'); await page.waitToClick(selectors.orderBasicData.saveButton); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toContain('Data saved!'); + expect(message.type).toBe('success'); }); it('should now confirm the client have been edited', async() => { diff --git a/e2e/paths/07-order/03_lines.spec.js b/e2e/paths/07-order/03_lines.spec.js index 450e1b9c9..6f87b45f0 100644 --- a/e2e/paths/07-order/03_lines.spec.js +++ b/e2e/paths/07-order/03_lines.spec.js @@ -26,9 +26,9 @@ describe('Order lines', () => { it('should delete the first line in the order', async() => { await page.waitToClick(selectors.orderLine.firstLineDeleteButton); await page.waitToClick(selectors.orderLine.confirmButton); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('Data saved!'); + expect(message.type).toBe('success'); }); it('should confirm the order subtotal has changed', async() => { diff --git a/e2e/paths/08-route/02_basic_data.spec.js b/e2e/paths/08-route/02_basic_data.spec.js index 66e516366..10edbcd8a 100644 --- a/e2e/paths/08-route/02_basic_data.spec.js +++ b/e2e/paths/08-route/02_basic_data.spec.js @@ -31,9 +31,9 @@ describe('Route basic Data path', () => { await page.type(`${selectors.routeBasicData.startedHour} input`, '0800'); await page.type(`${selectors.routeBasicData.finishedHour} input`, '1230'); await page.waitToClick(selectors.routeBasicData.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 worker was edited', async() => { diff --git a/e2e/paths/08-route/03_create.spec.js b/e2e/paths/08-route/03_create.spec.js index dafccff7f..80c0071b6 100644 --- a/e2e/paths/08-route/03_create.spec.js +++ b/e2e/paths/08-route/03_create.spec.js @@ -17,7 +17,6 @@ describe('Route create path', () => { describe('as employee', () => { it('should click on the add new route button and open the creation form', async() => { - await page.waitForContentLoaded(); await page.waitToClick(selectors.routeIndex.addNewRouteButton); await page.waitForState('route.create'); }); @@ -25,9 +24,9 @@ describe('Route create path', () => { it(`should attempt to create a new route but fail since employee has no access rights`, async() => { await page.write(selectors.createRouteView.description, 'faster faster!!'); await page.waitToClick(selectors.createRouteView.submitButton); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('Access denied'); + expect(message.text).toBe('Access denied'); }); }); @@ -49,9 +48,9 @@ describe('Route create path', () => { await page.autocompleteSearch(selectors.createRouteView.agency, 'Teleportation device'); await page.write(selectors.createRouteView.description, 'faster faster!!'); await page.waitToClick(selectors.createRouteView.submitButton); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('Data saved!'); + expect(message.type).toBe('success'); }); it(`should confirm the redirection to the created route summary`, async() => { diff --git a/e2e/paths/08-route/04_tickets.spec.js b/e2e/paths/08-route/04_tickets.spec.js index 53b8f56c8..938c98574 100644 --- a/e2e/paths/08-route/04_tickets.spec.js +++ b/e2e/paths/08-route/04_tickets.spec.js @@ -19,17 +19,15 @@ xdescribe('Route basic Data path', () => { }); it('should modify the first ticket priority', async() => { - const result = await nightmare; await page.write(selectors.routeTickets.firstTicketPriority, '2'); await page.keyboard.press('Enter'); - await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('Data saved!'); + expect(message.type).toBe('success'); }); it('should confirm the buscamanButton is disabled', async() => { - const result = await nightmare; - await page.evaluate(selector => { + const result = await page.evaluate(selector => { return document.querySelector(selector); }, `${selectors.routeTickets.buscamanButton} :disabled`); @@ -37,9 +35,8 @@ xdescribe('Route basic Data path', () => { }); it('should check the first ticket checkbox and confirm the buscamanButton button is no longer disabled', async() => { - const result = await nightmare; await page.waitToClick(selectors.routeTickets.firstTicketCheckbox); - await page.evaluate(selector => { + const result = await page.evaluate(selector => { return document.querySelector(selector); }, `${selectors.routeTickets.buscamanButton} :disabled`); @@ -47,47 +44,41 @@ xdescribe('Route basic Data path', () => { }); it('should check the route volume on the descriptor', async() => { - const result = await nightmare; - await page.waitToGetProperty(selectors.routeDescriptor.volume, 'innerText'); + const result = await page.waitToGetProperty(selectors.routeDescriptor.volume, 'innerText'); expect(result).toEqual('1.1 / 18 m³'); }); it('should count how many tickets are in route', async() => { - const result = await nightmare; - await page.countElement('vn-route-tickets vn-textfield[ng-model="ticket.priority"]'); + const result = await page.countElement('vn-route-tickets vn-textfield[ng-model="ticket.priority"]'); expect(result).toEqual(11); }); it('should delete the first ticket in route', async() => { - const result = await nightmare; await page.waitToClick(selectors.routeTickets.firstTicketDeleteButton); await page.waitToClick(selectors.routeTickets.confirmButton); - await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('Ticket removed from route'); + expect(message.text).toBe('Ticket removed from route'); }); it('should again delete the first ticket in route', async() => { - const result = await nightmare; await page.waitToClick(selectors.routeTickets.firstTicketDeleteButton); await page.waitToClick(selectors.routeTickets.confirmButton); - await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('Ticket removed from route'); + expect(message.text).toBe('Ticket removed from route'); }); it('should now count how many tickets are in route to find one less', async() => { - const result = await nightmare; - await page.countElement('vn-route-tickets vn-textfield[ng-model="ticket.priority"]'); + const result = await page.countElement('vn-route-tickets vn-textfield[ng-model="ticket.priority"]'); expect(result).toEqual(9); }); it('should confirm the route volume on the descriptor has been updated by the changes made', async() => { - const result = await nightmare; - await page.waitToGetProperty(selectors.routeDescriptor.volume, 'innerText'); + const result = await page.waitToGetProperty(selectors.routeDescriptor.volume, 'innerText'); expect(result).toEqual('0.9 / 18 m³'); }); diff --git a/e2e/paths/09-invoice-out/02_descriptor.spec.js b/e2e/paths/09-invoice-out/02_descriptor.spec.js index ceb2175e2..ade121a8b 100644 --- a/e2e/paths/09-invoice-out/02_descriptor.spec.js +++ b/e2e/paths/09-invoice-out/02_descriptor.spec.js @@ -40,9 +40,9 @@ describe('InvoiceOut descriptor path', () => { await page.waitToClick(selectors.invoiceOutDescriptor.moreMenu); await page.waitToClick(selectors.invoiceOutDescriptor.moreMenuDeleteInvoiceOut); await page.waitToClick(selectors.invoiceOutDescriptor.acceptDeleteButton); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('InvoiceOut deleted'); + expect(message.text).toBe('InvoiceOut deleted'); }); it('should have been relocated to the invoiceOut index', async() => { @@ -50,12 +50,10 @@ describe('InvoiceOut descriptor path', () => { }); it(`should search for the deleted invouceOut to find no results`, async() => { - await page.write(selectors.invoiceOutIndex.topbarSearch, 'T2222222'); - await page.waitToClick(selectors.invoiceOutIndex.searchButton); - await page.waitForNumberOfElements(selectors.invoiceOutIndex.searchResult, 0); - const result = await page.countElement(selectors.invoiceOutIndex.searchResult); + await page.doSearch('T2222222'); + const nResults = await page.countElement(selectors.invoiceOutIndex.searchResult); - expect(result).toEqual(0); + expect(nResults).toEqual(0); }); it('should navigate to the ticket index', async() => { @@ -66,17 +64,13 @@ describe('InvoiceOut descriptor path', () => { }); it('should search for tickets with an specific invoiceOut to find no results', async() => { - await page.waitToClick(selectors.ticketsIndex.openAdvancedSearchButton); - await page.write(selectors.ticketsIndex.advancedSearchInvoiceOut, 'T2222222'); - await page.waitToClick(selectors.ticketsIndex.advancedSearchButton); - await page.waitForNumberOfElements(selectors.ticketsIndex.searchResult, 0); - const result = await page.countElement(selectors.ticketsIndex.searchResult); + await page.doSearch('T2222222'); + const nResults = await page.countElement(selectors.ticketsIndex.searchResult); - expect(result).toEqual(0); + expect(nResults).toEqual(0); }); it('should now navigate to the invoiceOut index', async() => { - await page.waitForContentLoaded(); await page.waitToClick(selectors.globalItems.applicationsMenuButton); await page.wait(selectors.globalItems.applicationsMenuVisible); await page.waitToClick(selectors.globalItems.invoiceOutButton); @@ -99,9 +93,9 @@ describe('InvoiceOut descriptor path', () => { await page.waitToClick(selectors.invoiceOutDescriptor.moreMenu); await page.waitToClick(selectors.invoiceOutDescriptor.moreMenuBookInvoiceOut); await page.waitToClick(selectors.invoiceOutDescriptor.acceptBookingButton); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('InvoiceOut booked'); + expect(message.text).toBe('InvoiceOut booked'); }); it(`should check the invoiceOut booked in the summary data`, async() => { diff --git a/e2e/paths/10-travel/02_basic_data_and_log.spec.js b/e2e/paths/10-travel/02_basic_data_and_log.spec.js index 85c7231c8..c631e7131 100644 --- a/e2e/paths/10-travel/02_basic_data_and_log.spec.js +++ b/e2e/paths/10-travel/02_basic_data_and_log.spec.js @@ -27,17 +27,17 @@ describe('Travel basic data path', () => { await page.pickDate(selectors.travelBasicDada.deliveryDate, lastMonth); await page.waitToClick(selectors.travelBasicDada.save); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('Landing cannot be lesser than shipment'); + expect(message.text).toBe('Landing cannot be lesser than shipment'); }); it('should undo the changes', async() => { await page.waitToClick(selectors.travelBasicDada.undoChanges); await page.waitToClick(selectors.travelBasicDada.save); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('No changes to save'); + expect(message.text).toBe('No changes to save'); }); it('should now edit the whole form then save', async() => { @@ -50,9 +50,9 @@ describe('Travel basic data path', () => { await page.waitToClick(selectors.travelBasicDada.delivered); await page.waitToClick(selectors.travelBasicDada.received); await page.waitToClick(selectors.travelBasicDada.save); - 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 and check the reference was saved', async() => { diff --git a/e2e/paths/11-zone/01_basic-data.spec.js b/e2e/paths/11-zone/01_basic-data.spec.js index 7044ab70c..f28be5194 100644 --- a/e2e/paths/11-zone/01_basic-data.spec.js +++ b/e2e/paths/11-zone/01_basic-data.spec.js @@ -38,9 +38,9 @@ describe('Zone basic data path', () => { await page.write(selectors.zoneBasicData.inflation, '200'); await page.waitToClick(selectors.zoneBasicData.volumetric); await page.waitToClick(selectors.zoneBasicData.saveButton); - const result = await page.waitForLastSnackbar(); + const message = await page.waitForSnackbar(); - expect(result).toEqual('Data saved!'); + expect(message.type).toBe('success'); }); it('should now reload the section', async() => { diff --git a/front/core/components/autocomplete/index.html b/front/core/components/autocomplete/index.html index 725d38977..feaa47bdb 100755 --- a/front/core/components/autocomplete/index.html +++ b/front/core/components/autocomplete/index.html @@ -1,5 +1,6 @@
vn-icon { vertical-align: middle; color: inherit; - font-size: 1.7em; } } &.colored { color: white; background-color: $color-button; - box-shadow: 0 .15em .15em 0 rgba(0, 0, 0, .3); + box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .3); transition: background 200ms ease-in-out; &:not(.disabled) { @@ -80,27 +79,27 @@ } &.round { border-radius: 50%; - height: 3.8em; - width: 3.8em; + height: 54px; + width: 54px; & > button > span { display: none; } &.xs { - font-size: 0.5em; + font-size: .5rem; } &.sm { - font-size: 0.7em; + font-size: .7rem; } &.md { - font-size: 0.9em; + font-size: .875rem; } &.lg { - font-size: 1.2em; + font-size: 1.2rem; } } &.disabled { diff --git a/front/core/components/calendar/style.scss b/front/core/components/calendar/style.scss index 8492d09f1..28c87793b 100644 --- a/front/core/components/calendar/style.scss +++ b/front/core/components/calendar/style.scss @@ -6,14 +6,14 @@ & > div { & > .header { display: flex; - margin-bottom: 0.5em; + margin-bottom: 8px; align-items: center; - height: 2.4em; + height: 38px; & > .title { flex: 1; text-align: center; - padding: 0.2em 0; + padding: 3px 0; } & > .vn-button { color: inherit; @@ -22,10 +22,10 @@ & > .weekdays { display: flex; color: $color-font-secondary; - margin-bottom: 0.5em; - padding: 0.5em 0; + margin-bottom: 8px; + padding: 8px 0; font-weight: bold; - font-size: 0.8em; + font-size: .8rem; text-align: center; & > section { @@ -62,9 +62,9 @@ justify-content: center; align-items: center; border-radius: 50%; - font-size: 14px; - width: 2.2em; - height: 2.2em; + font-size: .9rem; + width: 30px; + height: 30px; cursor: pointer; outline: 0; transition: background-color 300ms ease-in-out; diff --git a/front/core/components/chip/style.scss b/front/core/components/chip/style.scss index 974a55a82..34ee947ba 100644 --- a/front/core/components/chip/style.scss +++ b/front/core/components/chip/style.scss @@ -1,23 +1,23 @@ @import "variables"; vn-chip { - border-radius: 1em; + border-radius: 16px; background-color: $color-bg; color: $color-font; font-size: .9rem; - margin: .25em; + margin: 4px; display: inline-flex; align-items: center; - height: 2em; + height: 28px; max-width: 100%; box-sizing: border-box; &.small { - height: 1.5em; + height: 24px; & > div { - padding: 0.6em; - font-size: 0.8rem; + padding: 9px; + font-size: .8rem; } } @@ -46,22 +46,22 @@ vn-chip { display: flex; align-items: center; height: 100%; - padding: 0 .7em; + padding: 0 11px; text-overflow: ellipsis; white-space: nowrap; overflow: hidden; & > vn-avatar { - margin-left: -0.7em; - margin-right: .3em; + margin-left: -11px; + margin-right: 6px; vertical-align: middle; - height: 2em; - width: 2em; + height: 28px; + width: 28px; } } & > vn-icon { - margin-right: .12em; - margin-left: -.12em; + margin-right: 2px; + margin-left: -2px; vertical-align: middle; opacity: .6; cursor: pointer; @@ -76,6 +76,6 @@ vn-chip { vn-avatar { display: inline-block; - min-width: 2em; + min-width: 28px; border-radius: 50%; } \ No newline at end of file diff --git a/front/core/components/confirm/confirm.js b/front/core/components/confirm/confirm.js index f187a3cb4..c0a1cc0c5 100644 --- a/front/core/components/confirm/confirm.js +++ b/front/core/components/confirm/confirm.js @@ -6,10 +6,7 @@ import './style.scss'; export default class Confirm extends Dialog { constructor($element, $, $transclude) { super($element, $, $transclude); - - let $template = angular.element(template); - this.fillSlot('body', $template.find('tpl-body')); - this.fillSlot('buttons', $template.find('tpl-buttons')); + this.fillSlots(template); } } diff --git a/front/core/components/confirm/style.scss b/front/core/components/confirm/style.scss index d3cea6cb1..154e3b478 100644 --- a/front/core/components/confirm/style.scss +++ b/front/core/components/confirm/style.scss @@ -1,3 +1,3 @@ .vn-confirm .window { - max-width: 30em + max-width: 480px } \ No newline at end of file diff --git a/front/core/components/data-viewer/style.scss b/front/core/components/data-viewer/style.scss index d0b3c727d..bb2cc2a83 100644 --- a/front/core/components/data-viewer/style.scss +++ b/front/core/components/data-viewer/style.scss @@ -6,9 +6,9 @@ vn-data-viewer { & > .empty-rows { display: block; text-align: center; - padding: 1.5em; + padding: 24px; box-sizing: border-box; color: $color-font-secondary; - font-size: 1.4em; + font-size: 1.375rem; } } \ No newline at end of file diff --git a/front/core/components/debug-info/style.scss b/front/core/components/debug-info/style.scss index 95c024a6d..b6171d4da 100644 --- a/front/core/components/debug-info/style.scss +++ b/front/core/components/debug-info/style.scss @@ -2,10 +2,10 @@ vn-debug-info { position: fixed; - bottom: 1em; - left: 1em; - padding: 1em; - min-width: 8em; + bottom: 16px; + left: 16px; + padding: 16px; + min-width: 128px; background-color: #3f51b5; color: $color-font-dark; border-radius: 4px; @@ -19,7 +19,7 @@ vn-debug-info { & > h6 { font-weight: normal; color: rgba(255, 255, 255, .5); - font-size: 1em; + font-size: 1rem; } ul { list-style-type: none; @@ -27,11 +27,11 @@ vn-debug-info { margin: 0; & > li { - margin-top: .2em; - font-size: .95em; + margin-top: 3px; + font-size: .94rem; & > span { - padding: .05em .2em; + padding: 1px 3px; border-radius: 4px; transition: background-color 200ms ease-in-out; diff --git a/front/core/components/dialog/index.js b/front/core/components/dialog/index.js index 7a7cb5f9f..dfc1e5d3a 100644 --- a/front/core/components/dialog/index.js +++ b/front/core/components/dialog/index.js @@ -21,6 +21,17 @@ export default class Dialog extends Popup { this.fillDefaultSlot(template); } + /** + * Fills the dialog slots, it is intended to be used by child classes. + * + * @param {String} template The HTML template string + */ + fillSlots(template) { + let $template = angular.element(template); + this.fillSlot('body', $template.find('tpl-body')); + this.fillSlot('buttons', $template.find('tpl-buttons')); + } + /** * Shows the dialog and optionally registers a handler for the response. * @@ -68,7 +79,17 @@ export default class Dialog extends Popup { respond(response) { if (!this.shown) return this.$q.resolve(); + return this.responseHandler(response); + } + /** + * The default response handler, it can be overriden by child classes to + * add custom logic. + * + * @param {String} response The response code + * @return {Boolean} The response handler return + */ + responseHandler(response) { let handlerArgs = { $response: response, $data: this.data diff --git a/front/core/components/dialog/style.scss b/front/core/components/dialog/style.scss index 2f3d9a028..e4884c362 100644 --- a/front/core/components/dialog/style.scss +++ b/front/core/components/dialog/style.scss @@ -8,11 +8,11 @@ text-transform: uppercase; background-color: transparent; border: none; - border-radius: .1em; + border-radius: 1px; position: absolute; top: 0; right: 0; - padding: .3em; + padding: 4px; color: #666; } & > form { @@ -20,11 +20,11 @@ & > .body > tpl-body { display: block; - min-width: 16em; + min-width: 256px; } & > .buttons > tpl-buttons { display: block; - margin-top: 1.5em; + margin-top: 24px; text-align: right; button, @@ -35,12 +35,12 @@ text-transform: uppercase; background-color: transparent; border: none; - border-radius: .1em; + border-radius: 1px; color: $color-button; font-family: vn-font-bold; - padding: .7em; - margin: -0.7em; - margin-left: .7em; + padding: 11px; + margin: -11px; + margin-left: 11px; } } } diff --git a/front/core/components/drop-down/style.scss b/front/core/components/drop-down/style.scss index fb346135f..085f94c97 100755 --- a/front/core/components/drop-down/style.scss +++ b/front/core/components/drop-down/style.scss @@ -19,13 +19,13 @@ display: none; cursor: pointer; position: absolute; - right: .5em; - top: .6em; - height: 1em; + right: 8px; + top: 9px; + height: 16px; color: #888; border-radius: 50%; background-color: rgba(255, 255, 255, .8); - font-size: 18px; + font-size: 1.125rem; &:hover { color: $color-font; @@ -36,7 +36,7 @@ } } & > .list { - max-height: 20em; + max-height: 320px; overflow: auto; ul { @@ -46,13 +46,13 @@ } li, .status { @extend %clickable; - padding: .6em; + padding: 9px; white-space: nowrap; display: flex; & > input[type=checkbox] { margin: 0; - margin-right: .6em; + margin-right: 9px; } &.active { @extend %active; diff --git a/front/core/components/field/index.html b/front/core/components/field/index.html index d614d157f..c31fe2862 100644 --- a/front/core/components/field/index.html +++ b/front/core/components/field/index.html @@ -1,4 +1,4 @@ -
+
diff --git a/front/core/components/field/index.js b/front/core/components/field/index.js index 62adf3233..81fd4cc6a 100644 --- a/front/core/components/field/index.js +++ b/front/core/components/field/index.js @@ -9,20 +9,17 @@ export default class Field extends FormInput { this.prefix = null; this.suffix = null; - this.control = this.element.querySelector('.control'); - this.element.addEventListener('click', e => this.onClick(e)); - this.container = this.element.querySelector('.container'); - this.container.addEventListener('mousedown', e => this.onMouseDown(e)); + this.container.addEventListener('focusout', () => this.onFocus(false)); + this.container.addEventListener('focusin', () => this.onFocus(true)); + + this.control = this.element.querySelector('.control'); } $onInit() { super.$onInit(); if (this.info) this.classList.add('has-icons'); - - this.input.addEventListener('focus', () => this.onFocus(true)); - this.input.addEventListener('blur', () => this.onFocus(false)); this.input.addEventListener('change', () => this.onChange()); } @@ -160,19 +157,6 @@ export default class Field extends FormInput { fix.innerText = text || ''; } - onClick() { - // if (event.defaultPrevented) return; - - if (this.input !== document.activeElement) - this.focus(); - } - - onMouseDown(event) { - if (event.target == this.input) return; - event.preventDefault(); - this.focus(); - } - onFocus(hasFocus) { this.classList.toggle('focused', hasFocus); } diff --git a/front/core/components/field/style.scss b/front/core/components/field/style.scss index f3bc0ae04..5f77e904e 100644 --- a/front/core/components/field/style.scss +++ b/front/core/components/field/style.scss @@ -9,6 +9,7 @@ display: flex; align-items: stretch; position: relative; + outline: none; & > .infix { position: relative; @@ -30,7 +31,6 @@ & > .required { display: none; - color: $color-alert } } & > .fix { @@ -135,7 +135,7 @@ align-items: center; & > vn-icon { - font-size: 24px; + font-size: 1.5rem; } } & > .prepend > prepend { @@ -197,7 +197,7 @@ } } &.standout { - border-radius: .1em; + border-radius: 1px; background-color: rgba(255, 255, 255, .1); padding: 0 12px; transition-property: background-color, color; @@ -248,7 +248,7 @@ top: 5px; color: $color-primary; padding: 0; - font-size: 12px; + font-size: .75rem; } & > .control > * { &[type=time], @@ -298,7 +298,7 @@ padding: 4px 0; height: 12px; color: rgba(0, 0, 0, .4); - font-size: 12px; + font-size: .75rem; transform: translateY(-12px); transition-property: opacity, transform, color; transition-duration: 200ms; diff --git a/front/core/components/icon-button/style.scss b/front/core/components/icon-button/style.scss index d59980a62..2b52d48bd 100644 --- a/front/core/components/icon-button/style.scss +++ b/front/core/components/icon-button/style.scss @@ -5,7 +5,7 @@ color: $color-button; & > button { - padding: .2em !important; + padding: 3px !important; } &:focus { opacity: .6; diff --git a/front/core/components/icon/style.scss b/front/core/components/icon/style.scss index 07a1584e3..86345cbf4 100644 --- a/front/core/components/icon/style.scss +++ b/front/core/components/icon/style.scss @@ -1,6 +1,6 @@ vn-icon { display: inline-block; - font-size: 18pt; + font-size: 1.7em; text-align: center; outline: 0; diff --git a/front/core/components/input-number/index.html b/front/core/components/input-number/index.html index 2c6f7d824..acce849e2 100644 --- a/front/core/components/input-number/index.html +++ b/front/core/components/input-number/index.html @@ -1,4 +1,4 @@ -
+
diff --git a/front/core/components/label-value/style.scss b/front/core/components/label-value/style.scss index e4a2cca03..10f3c016c 100644 --- a/front/core/components/label-value/style.scss +++ b/front/core/components/label-value/style.scss @@ -4,6 +4,6 @@ vn-label-value > section { & > vn-icon { vertical-align: middle; color: $color-font-secondary; - font-size: 1.2em + font-size: 1.2rem } } \ No newline at end of file diff --git a/front/core/components/list/style.scss b/front/core/components/list/style.scss index 6f12ce7c6..fdadf460b 100644 --- a/front/core/components/list/style.scss +++ b/front/core/components/list/style.scss @@ -11,7 +11,7 @@ ul.menu { @extend %clickable; display: block; color: inherit; - padding: .6em 2em; + padding: 9px 32px; } } */ @@ -76,7 +76,7 @@ vn-item, margin-right: $spacing-md; & > .vn-icon { - font-size: 1.2em; + font-size: 1.2rem; } } &[side] { @@ -86,10 +86,10 @@ vn-item, & > .vn-button { opacity: .4; - margin-left: .5em; + margin-left: 8px; transition: opacity 250ms ease-out; padding: 0; - font-size: 1.05em; + font-size: 1rem; &:hover { opacity: 1; diff --git a/front/core/components/multi-check/style.scss b/front/core/components/multi-check/style.scss index bc6a0e8c5..79c2397bc 100644 --- a/front/core/components/multi-check/style.scss +++ b/front/core/components/multi-check/style.scss @@ -1,5 +1,5 @@ vn-multi-check { .vn-check { - margin-bottom: 0.8em + margin-bottom: 12px } } \ No newline at end of file diff --git a/front/core/components/pagination/style.scss b/front/core/components/pagination/style.scss index 2610bc502..413a6fb5f 100644 --- a/front/core/components/pagination/style.scss +++ b/front/core/components/pagination/style.scss @@ -4,7 +4,7 @@ vn-pagination { text-align: center; & > div > vn-icon-button { - font-size: 2em; + font-size: 2rem; padding: 0; } } \ No newline at end of file diff --git a/front/core/components/popover/style.scss b/front/core/components/popover/style.scss index decfc4733..e27ef6012 100644 --- a/front/core/components/popover/style.scss +++ b/front/core/components/popover/style.scss @@ -10,7 +10,7 @@ color: $color-font; opacity: 0; - transform: translateY(-.6em); + transform: translateY(-9px); transition-property: opacity, transform; transition-duration: 200ms; transition-timing-function: ease-in-out; @@ -21,21 +21,21 @@ } & > .window { position: absolute; - box-shadow: 0 .1em .4em $color-shadow; + box-shadow: 0 1px 6px $color-shadow; z-index: 0; & > .arrow { - width: 1em; - height: 1em; - margin: -.5em; + width: 16px; + height: 16px; + margin: -8px; background-color: $color-bg-panel; - box-shadow: 0 .1em .4em $color-shadow; + box-shadow: 0 1px 6px $color-shadow; position: absolute; transform: rotate(45deg); z-index: -1; } & > .content { - border-radius: .1em; + border-radius: 1px; background-color: $color-bg-panel; height: inherit; overflow: auto; diff --git a/front/core/components/popup/index.html b/front/core/components/popup/index.html index 3e542d51f..ad8fb2598 100644 --- a/front/core/components/popup/index.html +++ b/front/core/components/popup/index.html @@ -2,6 +2,7 @@
\ No newline at end of file diff --git a/front/core/components/popup/index.js b/front/core/components/popup/index.js index 994f4a0e7..0dea66254 100644 --- a/front/core/components/popup/index.js +++ b/front/core/components/popup/index.js @@ -51,6 +51,7 @@ export default class Popup extends Component { {parentBoundTranscludeFn: this.$transclude} )[0]; this.windowEl = this.popup.querySelector('.window'); + this.windowEl.focus(); let classList = this.popup.classList; classList.add(this.displayMode); diff --git a/front/core/components/popup/style.scss b/front/core/components/popup/style.scss index 42d69141d..c3e45ccf0 100644 --- a/front/core/components/popup/style.scss +++ b/front/core/components/popup/style.scss @@ -19,19 +19,20 @@ justify-content: center; align-items: center; background-color: rgba(0, 0, 0, .6); - padding: 1em; + padding: 16px; box-sizing: border-box; & > .window { position: relative; - box-shadow: 0 0 .4em $color-shadow; + box-shadow: 0 0 6px $color-shadow; background-color: $color-bg-panel; - border-radius: .2em; + border-radius: 3px; overflow: auto; box-sizing: border-box; max-height: 100%; transform: scale3d(.9, .9, .9); transition: transform 200ms ease-in-out; + outline: none; } &.shown > .window { transform: scale3d(1, 1, 1); diff --git a/front/core/components/range/style.scss b/front/core/components/range/style.scss index 6898f8cda..2a894492e 100644 --- a/front/core/components/range/style.scss +++ b/front/core/components/range/style.scss @@ -37,7 +37,7 @@ .vn-range { & > label { - font-size: 12px; + font-size: .75rem; &.main { color: $color-button; @@ -57,7 +57,7 @@ background: transparent; border-color: transparent; -webkit-appearance: none; - margin: .2em 0; + margin: 3px 0; &:focus { outline: none; diff --git a/front/core/components/scroll-up/style.scss b/front/core/components/scroll-up/style.scss index 1bf7ea982..44d12f14f 100644 --- a/front/core/components/scroll-up/style.scss +++ b/front/core/components/scroll-up/style.scss @@ -1,6 +1,6 @@ vn-scroll-up { - top: 5.5em; - right: 2em; + top: 88px; + right: 32px; display: none; position: fixed; } \ No newline at end of file diff --git a/front/core/components/searchbar/style.scss b/front/core/components/searchbar/style.scss index 31907792c..c1d4be21c 100644 --- a/front/core/components/searchbar/style.scss +++ b/front/core/components/searchbar/style.scss @@ -2,24 +2,24 @@ vn-searchbar { display: block; - max-width: 35em; + max-width: 560px; margin: 0 auto; .search-params { flex: 1; - margin: .05em 0; + margin: 1px 0; overflow: visible; display: flex; - max-width: 24em; + max-width: 384px; & > .search-param { color: rgba(0, 0, 0, .6); background-color: rgba(0, 0, 0, .1); - padding: .1em .4em; - margin-left: .2em; + padding: 1px 6px; + margin-left: 3px; display: inline-block; - border-radius: .8em; - max-width: 12em; + border-radius: 12px; + max-width: 192px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; @@ -39,7 +39,7 @@ vn-searchbar { } .search-panel { - max-height: 48em; + max-height: 768px; & > form { padding: $spacing-lg; diff --git a/front/core/components/snackbar/style.scss b/front/core/components/snackbar/style.scss index deaf010fc..465c53851 100644 --- a/front/core/components/snackbar/style.scss +++ b/front/core/components/snackbar/style.scss @@ -1,33 +1,33 @@ @import "variables"; vn-snackbar #shapes { - max-height: 20.625em; - margin-left: -12.5em; + max-height: 330px; + margin-left: -160px; position: fixed; z-index: 100; - width: 25em; + width: 320px; left: 50%; bottom: 0 } vn-snackbar .shape { - background-color: rgba(0, 0, 0, 0.8); - box-shadow: 0 0 .4em $color-shadow; + background-color: rgba(0, 0, 0, .8); + box-shadow: 0 0 6px $color-shadow; transition: transform 300ms ease-in-out; - transform: translateY(20em); + transform: translateY(320px); box-sizing: border-box; - border-radius: .2em; + border-radius: 3px; margin-bottom: 15px; color: white; - padding: 0.8em; + padding: 12px; & > .text { text-align: center; vn-chip { position: absolute; - left: -1em; - top: -1em; + left: -16px; + top: -16px; } } @@ -36,32 +36,32 @@ vn-snackbar .shape { } &.success { - background-color: rgba(163, 209, 49, 0.8); + background-color: rgba(163, 209, 49, .8); color: #445911; & > button { - color: rgba(1, 1, 1, 0.6); + color: rgba(1, 1, 1, .6); } } &.error { - background-color: rgba(198, 40, 40, 0.8); + background-color: rgba(198, 40, 40, .8); & > button { - color: rgba(1, 1, 1, 0.6); + color: rgba(1, 1, 1, .6); } } & > button { background-color: transparent; text-transform: uppercase; - margin-left: .5em; + margin-left: 8px; font-weight: bold; cursor: pointer; color: $color-main; float: right; border: none; - padding: .5em; - margin: -.5em + padding: 8px; + margin: -8px; } } \ No newline at end of file diff --git a/front/core/components/step-control/style.scss b/front/core/components/step-control/style.scss index 9acc1f314..b4d0d5afe 100644 --- a/front/core/components/step-control/style.scss +++ b/front/core/components/step-control/style.scss @@ -22,11 +22,11 @@ vn-step-control { border: 2px solid $color-main; background-color: white; align-content: center; - margin-top: -9.5px; + margin-top: -10px; border-radius: 50%; cursor: pointer; height: 15px; - width: 15px + width: 15px; } & > .steps > .step .circle.active { background-color: $color-main; @@ -36,7 +36,7 @@ vn-step-control { flex: auto; flex-direction: row; justify-content: space-between; - margin-top: 10px + margin-top: 10px; } & > .buttons > .step { display: flex diff --git a/front/core/components/table/style.scss b/front/core/components/table/style.scss index 41d1f6db8..7dd69d89f 100644 --- a/front/core/components/table/style.scss +++ b/front/core/components/table/style.scss @@ -14,7 +14,7 @@ vn-table { & > vn-thead, & > thead { display: table-header-group; - border-bottom: .15em solid $color-spacer; + border-bottom: 2px solid $color-spacer; & > * > th { font-weight: normal; @@ -52,14 +52,14 @@ vn-table { } & > vn-tfoot, & > tfoot { - border-top: .15em solid $color-spacer; + border-top: 2px solid $color-spacer; display: table-footer-group } & > * > vn-tr, & > * > a.vn-tr, & > * > tr { display: table-row; - height: 3em; + height: 48px; } vn-thead, vn-tbody, vn-tfoot, thead, tbody, tfoot { @@ -69,8 +69,8 @@ vn-table { & > vn-th, & > th { color: $color-font-light; - padding-top: 1em; - padding-bottom: .8em; + padding-top: 16px; + padding-bottom: 12px; } & > vn-th, & > vn-td, @@ -86,14 +86,14 @@ vn-table { vertical-align: middle; display: table-cell; text-align: left; - padding: .6em .5em; + padding: 9px 8px; white-space: nowrap; text-overflow: ellipsis; - max-width: 5em; + max-width: 80px; &[number] { text-align: right; - width: 6em; + width: 96px; } &[center] { text-align: center; @@ -103,7 +103,7 @@ vn-table { text-align: center; } &[expand] { - max-width: 25em; + max-width: 400px; min-width: 0; } vn-icon.bright, i.bright { @@ -111,10 +111,10 @@ vn-table { } } & > :last-child { - padding-right: 1.4em; + padding-right: 22px; } & > :first-child { - padding-left: 1.4em; + padding-left: 22px; } } & > a.vn-tr { @@ -123,7 +123,7 @@ vn-table { } vn-tbody > *, tbody > * { - border-bottom: .1em solid $color-spacer-light; + border-bottom: 1px solid $color-spacer-light; &:last-child { border-bottom: none; @@ -134,8 +134,8 @@ vn-table { & > vn-td, & > td { .chip { - padding: .3em; - border-radius: .3em; + padding: 4px; + border-radius: 4px; color: $color-font-bg; &.notice { @@ -158,7 +158,7 @@ vn-table { vn-icon-menu { display: inline-block; color: $color-main; - padding: .25em + padding: 4px } } & > [actions] { diff --git a/front/core/components/td-editable/style.scss b/front/core/components/td-editable/style.scss index e37e1086c..a1fe4664e 100644 --- a/front/core/components/td-editable/style.scss +++ b/front/core/components/td-editable/style.scss @@ -8,7 +8,7 @@ vn-td-editable { text { border: 1px dashed rgba(0, 0, 0, .15); - border-radius: 1em; + border-radius: 16px; padding: 5px 10px; min-height: 15px; display: block; @@ -36,16 +36,16 @@ vn-td-editable { left: 0; box-sizing: border-box; align-items: center; - padding: .6em; + padding: 9px; overflow: visible; & > field { flex: 1; background-color: $color-bg-panel; - padding: .5em; - box-shadow: 0 0 .4em rgba(0, 0, 0, .2); - border-radius: .1em; - min-width: 6em; + padding: 8px; + box-shadow: 0 0 6px rgba(0, 0, 0, .2); + border-radius: 1px; + min-width: 96px; & > * { width: 100%; diff --git a/front/core/components/toggle/style.scss b/front/core/components/toggle/style.scss index 31769d2a5..5213215d6 100644 --- a/front/core/components/toggle/style.scss +++ b/front/core/components/toggle/style.scss @@ -22,7 +22,7 @@ height: 20px; min-width: 20px; margin: 6px 0; - margin-right: .6em; + margin-right: 9px; border: 2px solid #666; } & > .btn > .focus-mark { diff --git a/front/core/components/tooltip/style.scss b/front/core/components/tooltip/style.scss index 926142582..926419c24 100644 --- a/front/core/components/tooltip/style.scss +++ b/front/core/components/tooltip/style.scss @@ -6,7 +6,7 @@ z-index: 150; background-color: $color-bg-dark; color: $color-active-font; - border-radius: .2em; + border-radius: 3px; &.show { display: inherit; diff --git a/front/core/components/treeview/style.scss b/front/core/components/treeview/style.scss index 7cd8c8bea..b8af114c1 100644 --- a/front/core/components/treeview/style.scss +++ b/front/core/components/treeview/style.scss @@ -11,7 +11,7 @@ vn-treeview-childs { list-style: none; ul { - padding-left: 2.2em; + padding-left: 35px; } } } @@ -37,7 +37,7 @@ vn-treeview-childs { vn-treeview-child { line-height: 38px; - font-size: 16px; + font-size: 1rem; display: block; .node { diff --git a/front/core/components/wday-picker/style.scss b/front/core/components/wday-picker/style.scss index be610c733..a8e3a65ab 100644 --- a/front/core/components/wday-picker/style.scss +++ b/front/core/components/wday-picker/style.scss @@ -9,11 +9,11 @@ & > span { @extend %clickable; border-radius: 50%; - padding: .4em; - margin: .2em; + padding: 6px; + margin: 3px; display: inline-flex; - width: 1.5em; - height: 1.5em; + width: 24px; + height: 24px; justify-content: center; align-items: center; outline: none; diff --git a/front/core/directives/droppable.scss b/front/core/directives/droppable.scss index f2e18a3ad..02261b5bc 100644 --- a/front/core/directives/droppable.scss +++ b/front/core/directives/droppable.scss @@ -5,8 +5,8 @@ .vn-draggable, [vn-droppable] { border: 2px dashed transparent; - border-radius: 0.5em; - transition: all 0.5s; + border-radius: 8px; + transition: all .5s; } .vn-droppable, diff --git a/front/core/directives/focus.js b/front/core/directives/focus.js index 869e9a7f0..8b75adcbc 100644 --- a/front/core/directives/focus.js +++ b/front/core/directives/focus.js @@ -1,11 +1,11 @@ import ngModule from '../module'; import isMobile from '../lib/is-mobile'; -export function focus($scope, input) { +export function focus($timeout, input) { if (isMobile) return; const element = input; - let selector = 'input, textarea, button, submit'; + const selector = 'input, textarea, button, submit'; if (!input.matches(selector)) input = input.querySelector(selector); @@ -20,26 +20,24 @@ export function focus($scope, input) { return; } - input.focus(); - - if (input.select) { - $scope.$applyAsync(() => { + $timeout(() => { + input.focus(); + if (input.select) input.select(); - }); - } + }); } -/** +/* * Sets the focus and selects the text on the input. - * - * @return {Object} The directive */ -export function directive() { +export function directive($timeout) { return { restrict: 'A', link: function($scope, $element) { - $scope.$watch('', () => focus($scope, $element[0])); + $scope.$watch('', () => focus($timeout, $element[0])); } }; } +directive.$inject = ['$timeout']; + ngModule.directive('vnFocus', directive); diff --git a/front/core/directives/specs/dialog.spec.js b/front/core/directives/specs/dialog.spec.js index fe84cdcc7..e43fca7cf 100644 --- a/front/core/directives/specs/dialog.spec.js +++ b/front/core/directives/specs/dialog.spec.js @@ -1,5 +1,4 @@ describe('Directive dialog', () => { - let $scope; let $element; let element; let compile; @@ -9,7 +8,7 @@ describe('Directive dialog', () => { compile = _element => { inject(($compile, $rootScope) => { - $scope = $rootScope.$new(); + let $scope = $rootScope.$new(); $scope.myDialog = controller; element = angular.element(_element); $compile(element)($scope); @@ -17,7 +16,7 @@ describe('Directive dialog', () => { }); }; - beforeEach(angular.mock.inject(($rootScope, $compile) => { + beforeEach(inject(($rootScope, $compile) => { $element = $compile('')($rootScope); controller = $element.controller('vnDialog'); })); diff --git a/front/core/directives/specs/focus.spec.js b/front/core/directives/specs/focus.spec.js index 11c60688a..dd917dc29 100644 --- a/front/core/directives/specs/focus.spec.js +++ b/front/core/directives/specs/focus.spec.js @@ -6,7 +6,7 @@ describe('Directive focus', () => { beforeEach(ngModule('vnCore')); compile = (_element, _childElement) => { - inject(($compile, $rootScope) => { + inject(($compile, $rootScope, $flushPendingTasks) => { $scope = $rootScope.$new(); $element = angular.element(_element); if (_childElement) @@ -15,7 +15,7 @@ describe('Directive focus', () => { $element[0].focus = jasmine.createSpy('focus'); $element[0].select = jasmine.createSpy('select'); $compile($element)($scope); - $scope.$digest(); + $flushPendingTasks(); }); }; diff --git a/front/core/directives/uvc.scss b/front/core/directives/uvc.scss index 5221b8bdd..0cdf0ba1a 100644 --- a/front/core/directives/uvc.scss +++ b/front/core/directives/uvc.scss @@ -1,6 +1,6 @@ vn-table vn-dialog[vn-id="uvc"]{ & > div { - min-width: 18em; + min-width: 288px; align-items: center; } diff --git a/front/core/directives/zoom-image.scss b/front/core/directives/zoom-image.scss index e075ff3a1..7debed995 100644 --- a/front/core/directives/zoom-image.scss +++ b/front/core/directives/zoom-image.scss @@ -5,7 +5,7 @@ position: fixed; top: 0; z-index: 25; - background-color: rgba(1, 1, 1, 0.6); + background-color: rgba(1, 1, 1, .6); & > div { display: flex; @@ -14,13 +14,13 @@ width: inherit; height: inherit; box-sizing: border-box; - padding: 1em; + padding: 16px; & > img { cursor: zoom-out; max-height: 100%; max-width: 100%; - border-radius: .2em; + border-radius: 3px; } } } diff --git a/front/core/filters/specs/currency.spec.js b/front/core/filters/specs/currency.spec.js index 28a4a3640..ecb94efe0 100644 --- a/front/core/filters/specs/currency.spec.js +++ b/front/core/filters/specs/currency.spec.js @@ -1,41 +1,23 @@ describe('Currency filter', () => { - let compile; - let $element; - beforeEach(ngModule('vnCore')); - - compile = html => { - inject(($compile, $rootScope) => { - $element = $compile(html)($rootScope); - $rootScope.$digest(); - }); - }; + let currencyFilter; + beforeEach(inject(_currencyFilter_ => { + currencyFilter = _currencyFilter_; + })); it('should return a ONE decimal number as per the argument', () => { - let html = `
{{200 | currency: 'EUR': 1}}
`; - compile(html); - - expect($element[0].innerHTML).toContain('200.0'); + expect(currencyFilter(200, 'EUR', 1)).toContain('200.0'); }); it('should return a TWO decimals number as per the argument', () => { - let html = `
{{200 | currency: 'EUR': 2}}
`; - compile(html); - - expect($element[0].innerHTML).toContain('200.00'); + expect(currencyFilter(200, 'EUR', 2)).toContain('200.00'); }); it('should return a TEN decimals number as per the argument', () => { - let html = `
{{200 | currency: 'EUR': 10}}
`; - compile(html); - - expect($element[0].innerHTML).toContain('200.0000000000'); + expect(currencyFilter(200, 'EUR', 10)).toContain('200.0000000000'); }); it('sould return nothing when the value is not set', () => { - let html = `
{{null | currency: 'EUR': 2}}
`; - compile(html); - - expect($element[0].innerHTML).toEqual(''); + expect(currencyFilter(null, 'EUR', 2)).toBeUndefined(); }); }); diff --git a/front/core/filters/specs/dash-if-empty.spec.js b/front/core/filters/specs/dash-if-empty.spec.js new file mode 100644 index 000000000..552e97445 --- /dev/null +++ b/front/core/filters/specs/dash-if-empty.spec.js @@ -0,0 +1,21 @@ +describe('Dash-if-empty filter', () => { + let dashIfEmptyFilter; + + beforeEach(ngModule('vnCore')); + + beforeEach(inject(_dashIfEmptyFilter_ => { + dashIfEmptyFilter = _dashIfEmptyFilter_; + })); + + it('should return a dash if input is null', () => { + expect(dashIfEmptyFilter(null)).toBe('-'); + }); + + it('should return a dash if input is empty', () => { + expect(dashIfEmptyFilter('')).toBe('-'); + }); + + it('should return same input is there is something', () => { + expect(dashIfEmptyFilter('something')).toBe('something'); + }); +}); diff --git a/front/core/filters/specs/percentage.spec.js b/front/core/filters/specs/percentage.spec.js new file mode 100644 index 000000000..0936c50ae --- /dev/null +++ b/front/core/filters/specs/percentage.spec.js @@ -0,0 +1,25 @@ +describe('Percentage filter', () => { + let percentageFilter; + + beforeEach(ngModule('vnCore')); + + beforeEach(inject(_percentageFilter_ => { + percentageFilter = _percentageFilter_; + })); + + it('should return null for input null', () => { + expect(percentageFilter(null, null)).toBeNull(); + }); + + it('should return null for input empty', () => { + expect(percentageFilter('', 2)).toBeNull(); + }); + + it('should return a TWO decimals number', () => { + expect(percentageFilter(0, 2)).toBe('0.00%'); + }); + + it('should return zero decimals number', () => { + expect(percentageFilter(0.5, 0)).toBe('50%'); + }); +}); diff --git a/front/core/filters/specs/phone.spec.js b/front/core/filters/specs/phone.spec.js new file mode 100644 index 000000000..04de345e7 --- /dev/null +++ b/front/core/filters/specs/phone.spec.js @@ -0,0 +1,21 @@ +describe('Phone filter', () => { + let phoneFilter; + + beforeEach(ngModule('vnCore')); + + beforeEach(inject(_phoneFilter_ => { + phoneFilter = _phoneFilter_; + })); + + it('should return empty string for input null', () => { + expect(phoneFilter(null)).toBe(''); + }); + + it('should return empty stringfor input empty', () => { + expect(phoneFilter('')).toBe(''); + }); + + it('should format putting a space every three digits', () => { + expect(phoneFilter('999999999')).toBe('999 999 999 '); + }); +}); diff --git a/front/core/filters/specs/ucwords.spec.js b/front/core/filters/specs/ucwords.spec.js new file mode 100644 index 000000000..0f13bd2a5 --- /dev/null +++ b/front/core/filters/specs/ucwords.spec.js @@ -0,0 +1,21 @@ +describe('Ucwords filter', () => { + let ucwordsFilter; + + beforeEach(ngModule('vnCore')); + + beforeEach(inject(_ucwordsFilter_ => { + ucwordsFilter = _ucwordsFilter_; + })); + + it('should return empty string for input null', () => { + expect(ucwordsFilter(null)).toBe(''); + }); + + it('should return empty stringfor input empty', () => { + expect(ucwordsFilter('')).toBe(''); + }); + + it('should format a string uppercasing the first character of each word', () => { + expect(ucwordsFilter('abc def')).toBe('Abc Def'); + }); +}); diff --git a/front/core/filters/specs/zero-fill.spec.js b/front/core/filters/specs/zero-fill.spec.js new file mode 100644 index 000000000..97f04c655 --- /dev/null +++ b/front/core/filters/specs/zero-fill.spec.js @@ -0,0 +1,25 @@ +describe('ZeroFill filter', () => { + let zeroFillFilter; + + beforeEach(ngModule('vnCore')); + + beforeEach(inject(_zeroFillFilter_ => { + zeroFillFilter = _zeroFillFilter_; + })); + + it('should return null for a input null', () => { + expect(zeroFillFilter(null, null)).toBeNull(); + }); + + it('should return a positive number pads a number with five zeros', () => { + expect(zeroFillFilter(1, 5)).toBe('00001'); + }); + + it('should return negative number pads a number with five zeros', () => { + expect(zeroFillFilter(-1, 5)).toBe('-00001'); + }); + + it('should return zero number with zero zeros', () => { + expect(zeroFillFilter(0, 1)).toBe('0'); + }); +}); diff --git a/front/core/services/auth.js b/front/core/services/auth.js index f59c4c0dd..a1dcfa395 100644 --- a/front/core/services/auth.js +++ b/front/core/services/auth.js @@ -45,8 +45,11 @@ export default class Auth { } login(user, password, remember) { - if (!user) - return this.$q.reject(new UserError('Please enter your username')); + if (!user) { + let err = new UserError('Please enter your username'); + err.code = 'EmptyLogin'; + return this.$q.reject(err); + } let params = { user, diff --git a/front/core/services/week-days.js b/front/core/services/week-days.js index 698d6df2c..cf5722520 100644 --- a/front/core/services/week-days.js +++ b/front/core/services/week-days.js @@ -1,12 +1,7 @@ import ngModule from '../module'; /** - * @property {Array} days Weekdays data array with the same indexes as Date.getDay() - * @property {Object} map Weekdays data map using weekday codes as key - * @property {Array} localeCodes Locale weekday codes indexes depend on current locale - * @property {Array} locale Weekday data array with indexes depending on current locale - * - * Weekday properties: + * Stores useful information about a weekday. * * @property {Number} index The weekday index acording to Date.getDay() * @property {String} code The weekday code @@ -17,33 +12,34 @@ import ngModule from '../module'; * @property {String} localeChar The first weekday letter in current locale * @property {String} localeAbr The abreviated 3 letters weekday name in current locale */ -class WeekDays { +export class WeekDay { + constructor(code, name) { + this.code = code; + this.name = name; + } +} + +/** + * Stores information about weekdays in many formats to be accessed in different + * ways depending on the context. + * + * @property {Array} days Weekdays array with the same indexes as Date.getDay() + * @property {Object} map Weekdays map using weekday codes as keys + * @property {Array} locale Weekday data array with indexes depending on current locale + * @property {Array} localeCodes Locale weekday codes with indexes depending on current locale + */ +export default class WeekDays { constructor($translate) { this.$translate = $translate; this.days = [ - { - code: 'sun', - name: 'Sunday' - }, { - code: 'mon', - name: 'Monday' - }, { - code: 'tue', - name: 'Tuesday' - }, { - code: 'wed', - name: 'Wednesday' - }, { - code: 'thu', - name: 'Thursday' - }, { - code: 'fri', - name: 'Friday' - }, { - code: 'sat', - name: 'Saturday' - } + new WeekDay('sun', 'Sunday'), + new WeekDay('mon', 'Monday'), + new WeekDay('tue', 'Tuesday'), + new WeekDay('wed', 'Wednesday'), + new WeekDay('thu', 'Thursday'), + new WeekDay('fri', 'Friday'), + new WeekDay('sat', 'Friday') ]; this.map = {}; @@ -83,6 +79,13 @@ class WeekDays { this.locales.push(this.map[code]); } + /** + * Transforms weekday set into an array whose indexes are weekday index + * with selected days set to %true. + * + * @param {String} weekDays Weekday codes separated by commas + * @return {Array} Array with selected days set to %true + */ fromSet(weekDays) { let wdays = []; @@ -97,6 +100,14 @@ class WeekDays { return wdays; } + /** + * Perform the inverse operation of fromSet() method. Transforms an + * array whose indexes are weekday index with selected days set to %true to + * weekday codes separated by commas. + * + * @param {Array} wdays Array with selected days set to %true + * @return {String} weekDays Weekday codes separated by commas + */ toSet(wdays) { let weekDays = []; diff --git a/front/core/styles/animations.scss b/front/core/styles/animations.scss index 039f79c77..8ae119fb4 100644 --- a/front/core/styles/animations.scss +++ b/front/core/styles/animations.scss @@ -2,7 +2,7 @@ @keyframes nothing {} @keyframes slideIn { from { - transform: translate3d(-2em, 0, 0); + transform: translate3d(-32px, 0, 0); opacity: 0; } to { diff --git a/front/core/styles/border.scss b/front/core/styles/border.scss index 7450b5857..757ab453f 100644 --- a/front/core/styles/border.scss +++ b/front/core/styles/border.scss @@ -19,5 +19,5 @@ /* Border Radius */ .border-radius { - border-radius: .3em; + border-radius: 4px; } \ No newline at end of file diff --git a/front/core/styles/font-family.scss b/front/core/styles/font-family.scss index b461917ce..db41ad750 100644 --- a/front/core/styles/font-family.scss +++ b/front/core/styles/font-family.scss @@ -21,7 +21,7 @@ font-family: 'Material Icons'; font-weight: normal; font-style: normal; - font-size: 24px; /* Preferred icon size */ + font-size: 1.5rem; /* Preferred icon size */ display: inline-block; line-height: 1; text-transform: none; diff --git a/front/core/styles/global.scss b/front/core/styles/global.scss index 8b3d465f1..555b54f9e 100644 --- a/front/core/styles/global.scss +++ b/front/core/styles/global.scss @@ -1,6 +1,7 @@ @import "variables"; html { + font-size: $font-size; background-color: $color-bg; overflow: auto; height: 100%; @@ -9,7 +10,6 @@ body { height: 100%; font-family: vn-font; color: $color-font; - font-size: $font-size; margin: 0; padding: 0; } @@ -44,4 +44,4 @@ a { .ng-leave, .ng-enter { transition: none; -} \ No newline at end of file +} diff --git a/front/core/styles/layout.scss b/front/core/styles/layout.scss index 925526dca..85088db6a 100644 --- a/front/core/styles/layout.scss +++ b/front/core/styles/layout.scss @@ -40,7 +40,7 @@ html [vn-nine], html [vn-ten], html [vn-eleven], html [vn-twelve]{ - flex-basis: 0.000000001px; + flex-basis: .1px; } html [vn-auto], vn-auto, .vn-auto { flex-basis: auto; diff --git a/front/core/styles/responsive.scss b/front/core/styles/responsive.scss index 9cc58dd12..3e16cf128 100644 --- a/front/core/styles/responsive.scss +++ b/front/core/styles/responsive.scss @@ -1,52 +1,53 @@ @import "variables"; - -/* Desktop - Laptop 1360x768 */ +/* +// Desktop - Laptop 1360x768 @media (max-resolution: 119dpi) and (min-device-width: 1340px) and (max-device-width: 1899px) { - body { font-size: 10pt; } + html { font-size: 10pt; } } -/* Mobile - Low DPI */ +// Mobile - Low DPI @media (min-resolution: 120dpi), (-webkit-min-device-pixel-ratio: 1.5) { - body { font-size: 9pt; } + html { font-size: 9pt; } } @media (min-resolution: 144dpi), (-webkit-min-device-pixel-ratio: 1.5) { - body { font-size: 11pt; } + html { font-size: 11pt; } } -/* Mobile - Normal DPI */ +// Mobile - Normal DPI @media (max-device-width: 383px) and (min-resolution: 192dpi), (max-device-width: 383px) and (-webkit-min-device-pixel-ratio: 2) { - body { font-size: 10pt; } + html { font-size: 10pt; } } @media (min-device-width: 384px) and (min-resolution: 192dpi), (min-device-width: 384px) and (-webkit-min-device-pixel-ratio: 2) { - body { font-size: 11pt; } + html { font-size: 11pt; } } -/* Mobile - High DPI */ +// Mobile - High DPI @media (max-device-width: 411px) and (min-resolution: 249dpi), (max-device-width: 411px) and (-webkit-min-device-pixel-ratio: 3) { - body { font-size: 10pt; } + html { font-size: 10pt; } } @media (min-device-width: 412px) and (min-resolution: 249dpi), (min-device-width: 412px) and (-webkit-min-device-pixel-ratio: 3) { - body { font-size: 11pt; } + html { font-size: 11pt; } } +*/ .vn-hide-narrow { @media (max-width: $mobile-width) { diff --git a/front/core/styles/text.scss b/front/core/styles/text.scss index b1624cd26..751a5594b 100644 --- a/front/core/styles/text.scss +++ b/front/core/styles/text.scss @@ -3,46 +3,46 @@ /* Headings */ .text-h1, h1 { - font-size: 32pt; + font-size: 2.3rem; } .text-h2, h2 { - font-size: 28pt; + font-size: 2.25rem; } .text-h3, h3 { - font-size: 24pt; + font-size: 2rem; } .text-h4, h4 { - font-size: 20pt; + font-size: 1.6rem; } .text-h5, h5 { - font-size: 16pt; + font-size: 1.3rem; } .text-h6, h6 { - font-size: 14pt; + font-size: 1.125rem; } .text-subtitle1 { - font-size: 13pt; + font-size: 1.06rem; } .text-subtitle2 { - font-size: 12pt; + font-size: 1rem; } .text-body1 { - font-size: 11pt; + font-size: .875rem; } .text-body2 { - font-size: 11pt; + font-size: .875rem; } .text-caption { - font-size: 11pt; + font-size: .875rem; } .text-overline { - font-size: 10pt; + font-size: .8rem; } h1, h2, h3, h4, h5, h6 { padding: 0; margin-top: 0; - margin-bottom: .3em; + margin-bottom: 4px; } /* Colors */ diff --git a/front/core/styles/variables.scss b/front/core/styles/variables.scss index 89e487ad7..0958c88b8 100644 --- a/front/core/styles/variables.scss +++ b/front/core/styles/variables.scss @@ -1,17 +1,17 @@ @import "./util"; -$menu-width: 16em; -$topbar-height: 4em; +$font-size: 12pt; +$menu-width: 256px; +$topbar-height: 56px; $mobile-width: 800px; -$font-size: 16px; // Width -$width-xs: 25em; -$width-sm: 34em; -$width-md: 50em; -$width-lg: 80em; -$width-xl: 100em; +$width-xs: 400px; +$width-sm: 544px; +$width-md: 800px; +$width-lg: 1280px; +$width-xl: 1600px; // Spacing @@ -115,6 +115,6 @@ $color-alert-light: darken($color-alert, 35%); // Border -$border-thin: .05em solid $color-spacer; -$border-thin-light: .05em solid $color-spacer-light; -$shadow: 0 .15em .15em 0 rgba(0, 0, 0, .3); +$border-thin: 1px solid $color-spacer; +$border-thin-light: 1px solid $color-spacer-light; +$shadow: 0 2px 2px 0 rgba(0, 0, 0, .3); diff --git a/front/salix/components/descriptor/style.scss b/front/salix/components/descriptor/style.scss index af719cc0d..a048c12b3 100644 --- a/front/salix/components/descriptor/style.scss +++ b/front/salix/components/descriptor/style.scss @@ -3,7 +3,7 @@ @import "./variables"; .vn-descriptor { - box-shadow: 0 .1em .2em $color-shadow; + box-shadow: 0 1px 3px $color-shadow; & > .header { display: flex; @@ -26,7 +26,7 @@ padding: 10px; } vn-icon { - font-size: 1.8em; + font-size: 1.75rem; } } } @@ -51,7 +51,7 @@ & > vn-icon { padding: $spacing-sm; color: $color-marginal; - font-size: 1.5em; + font-size: 1.5rem; &.bright { color: $color-main; @@ -70,7 +70,7 @@ margin: 0 $spacing-sm; & > vn-icon { - font-size: 1.8em; + font-size: 1.75rem; padding: 0; } } diff --git a/front/salix/components/home/style.scss b/front/salix/components/home/style.scss index 268260bbd..7524d2be3 100644 --- a/front/salix/components/home/style.scss +++ b/front/salix/components/home/style.scss @@ -2,7 +2,7 @@ vn-home { display: block; - padding: .5em; + padding: 8px; & > div { & > h6 { @@ -16,7 +16,7 @@ vn-home { flex-direction: row; justify-content: center; flex-wrap: wrap; - max-width: 44em; + max-width: 704px; margin: 0 auto; & > a { @@ -27,10 +27,10 @@ vn-home { color: $color-font-dark; display: flex; flex-direction: column; - height: 8em; - width: 8em; - margin: .5em; - padding: 1em; + height: 128px; + width: 128px; + margin: 8px; + padding: 16px; justify-content: center; & > div { @@ -41,21 +41,21 @@ vn-home { & > vn-icon { display: block; - font-size: 3.5em; + font-size: 3.5rem; } } & > span { - font-size: 0.9em; + font-size: .875rem; text-align: center; } & > h4 { max-width: 100%; text-align: center; - font-size: 12pt; + font-size: 1rem; overflow: hidden; color: inherit; margin: 0; - line-height: 1.5em; + line-height: 24px; /* & > .bind-letter { color: #FD0; diff --git a/front/salix/components/layout/style.scss b/front/salix/components/layout/style.scss index 1a483ab96..14af8ac23 100644 --- a/front/salix/components/layout/style.scss +++ b/front/salix/components/layout/style.scss @@ -7,42 +7,42 @@ vn-layout { right: 0; left: 0; z-index: 10; - box-shadow: 0 .1em .2em $color-shadow; + box-shadow: 0 1px 3px $color-shadow; height: $topbar-height; - padding: 0 1em; + padding: 0 16px; justify-content: space-between; & > .side { flex: auto; display: flex; align-items: center; - width: 5em; + width: 80px; transition: width 200ms; } & > .start { - padding-right: 1em; + padding-right: 16px; overflow: hidden; & > .logo > img { - height: 2em; + height: 32px; display: block; } & > .main-title { - font-size: 1.6em; + font-size: 1.56rem; text-overflow: ellipsis; white-space: nowrap; overflow: hidden; - padding-left: .4em; + padding-left: 6px; } & > vn-spinner { - padding: 0 .4em; + padding: 0 6px; } } & > vn-slot { flex: auto; } & > .end { - padding-left: 1em; + padding-left: 16px; justify-content: flex-end; } .show-menu { @@ -50,7 +50,7 @@ vn-layout { } .vn-button { color: inherit; - font-size: 1.05em; + font-size: 1.05rem; padding: 0; } } @@ -66,7 +66,7 @@ vn-layout { } &.left-menu { & > vn-topbar > .start { - width: 5em + $menu-width; + width: 80px + $menu-width; } & > .main-view { padding-left: $menu-width; @@ -74,11 +74,14 @@ vn-layout { } &.right-menu { & > vn-topbar > .end { - width: 5em + $menu-width; + width: 80px + $menu-width; } & > .main-view { padding-right: $menu-width; } + [fixed-bottom-right] { + right: 64px + $menu-width; + } } & > .main-view { padding-top: $topbar-height; @@ -89,6 +92,11 @@ vn-layout { padding: $spacing-md; box-sizing: border-box } + [fixed-bottom-right] { + position: fixed; + bottom: 32px; + right: 32px; + } &.ng-enter { vn-side-menu { opacity: 0; @@ -124,6 +132,9 @@ vn-layout { & > .main-view { padding-right: 0; } + [fixed-bottom-right] { + right: 32px; + } } ui-view > * { padding-left: 0; @@ -139,22 +150,22 @@ vn-layout { & > li { @extend %clickable-light; background-color: $color-main; - margin-bottom: .6em; - padding: .8em; - border-radius: .1em; - min-width: 8em; + margin-bottom: 9px; + padding: 12px; + border-radius: 1px; + min-width: 128px; white-space: nowrap; &:last-child { margin-bottom: 0; } & > vn-icon { - padding-right: .3em; + padding-right: 4px; vertical-align: middle; } } } #user { - font-size: 1.5em; + font-size: 1.5rem; height: auto; } diff --git a/front/salix/components/left-menu/left-menu.html b/front/salix/components/left-menu/left-menu.html index 73488a24b..7db36177b 100644 --- a/front/salix/components/left-menu/left-menu.html +++ b/front/salix/components/left-menu/left-menu.html @@ -1,10 +1,11 @@