diff --git a/db/dump/fixtures.before.sql b/db/dump/fixtures.before.sql index 0a797f7ec..5235f5f45 100644 --- a/db/dump/fixtures.before.sql +++ b/db/dump/fixtures.before.sql @@ -3057,9 +3057,6 @@ INSERT INTO `vn`.`workerTimeControlMail` (`id`, `workerFk`, `year`, `week`, `sta (3, 9, 2000, 51, 'CONFIRMED', util.VN_NOW(), 1, NULL), (4, 9, 2001, 1, 'SENDED', util.VN_NOW(), 1, NULL); -INSERT INTO `vn`.`wagonConfig` (`id`, `width`, `height`, `maxWagonHeight`, `minHeightBetweenTrays`, `maxTrays`) - VALUES - (1, 1350, 1900, 200, 50, 6); INSERT INTO `vn`.`wagonTypeColor` (`id`, `name`, `rgb`) VALUES @@ -3068,15 +3065,19 @@ INSERT INTO `vn`.`wagonTypeColor` (`id`, `name`, `rgb`) (3, 'green', '#00ff00'), (4, 'blue', '#0000ff'); +INSERT INTO `vn`.`wagonConfig` (`id`, `width`, `height`, `maxWagonHeight`, `minHeightBetweenTrays`, `maxTrays`, `defaultTrayColorFk`) + VALUES + (1, 1350, 1900, 200, 50, 6, 1); + INSERT INTO `vn`.`wagonType` (`id`, `name`, `divisible`) VALUES (1, 'Wagon Type #1', 1); -INSERT INTO `vn`.`wagonTypeTray` (`id`, `typeFk`, `height`, `colorFk`) +INSERT INTO `vn`.`wagonTypeTray` (`id`, `wagonTypeFk`, `height`, `wagonTypeColorFk`) VALUES - (1, 1, 100, 1), + (1, 1, 0, 1), (2, 1, 50, 2), - (3, 1, 0, 3); + (3, 1, 100, 3); INSERT INTO `salix`.`accessTokenConfig` (`id`, `renewPeriod`, `courtesyTime`, `renewInterval`) VALUES diff --git a/db/versions/11088-bronzeAspidistra/00-firstScript.sql b/db/versions/11088-bronzeAspidistra/00-firstScript.sql new file mode 100644 index 000000000..11effc5d2 --- /dev/null +++ b/db/versions/11088-bronzeAspidistra/00-firstScript.sql @@ -0,0 +1,21 @@ +DROP TABLE IF EXISTS vn.wagonTypeTray; + +CREATE OR REPLACE TABLE vn.wagonTypeTray ( + id INT UNSIGNED auto_increment NULL, + wagonTypeFk int(11) unsigned NULL, + height INT UNSIGNED NULL, + wagonTypeColorFk int(11) unsigned NULL, + CONSTRAINT wagonTypeTray_pk PRIMARY KEY (id), + CONSTRAINT wagonTypeTray_wagonType_FK FOREIGN KEY (wagonTypeFk) REFERENCES vn.wagonType(id), + CONSTRAINT wagonTypeTray_wagonTypeColor_FK FOREIGN KEY (wagonTypeColorFk) REFERENCES vn.wagonTypeColor(id) +) +ENGINE=InnoDB +DEFAULT CHARSET=utf8mb3 +COLLATE=utf8mb3_unicode_ci; + +ALTER TABLE vn.wagonConfig ADD IF NOT EXISTS defaultHeight INT UNSIGNED DEFAULT 0 NULL COMMENT 'Default height in cm for a base tray'; +ALTER TABLE vn.wagonConfig ADD IF NOT EXISTS defaultTrayColorFk int(11) unsigned NULL COMMENT 'Default color for a base tray'; +ALTER TABLE vn.wagonConfig ADD CONSTRAINT wagonConfig_wagonTypeColor_FK FOREIGN KEY (defaultTrayColorFk) REFERENCES vn.wagonTypeColor(id); + +ALTER TABLE vn.wagonTypeTray DROP FOREIGN KEY wagonTypeTray_wagonType_FK; +ALTER TABLE vn.wagonTypeTray ADD CONSTRAINT wagonTypeTray_wagonType_FK FOREIGN KEY (wagonTypeFk) REFERENCES vn.wagonType(id) ON DELETE CASCADE ON UPDATE RESTRICT; diff --git a/loopback/locale/en.json b/loopback/locale/en.json index d9d9c8511..1753d1d07 100644 --- a/loopback/locale/en.json +++ b/loopback/locale/en.json @@ -236,6 +236,8 @@ "Cannot send mail": "Cannot send mail", "CONSTRAINT `chkParkingCodeFormat` failed for `vn`.`parking`": "CONSTRAINT `chkParkingCodeFormat` failed for `vn`.`parking`", "This postcode already exists": "This postcode already exists", - "Original invoice not found": "Original invoice not found" - + "Original invoice not found": "Original invoice not found", + "There is already a tray with the same height": "There is already a tray with the same height", + "The height must be greater than 50cm": "The height must be greater than 50cm", + "The maximum height of the wagon is 200cm": "The maximum height of the wagon is 200cm" } diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 064ea4a95..1093fe326 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -374,5 +374,8 @@ "Original invoice not found": "Factura original no encontrada", "The entry has no lines or does not exist": "La entrada no tiene lineas o no existe", "Weight already set": "El peso ya está establecido", - "This ticket is not allocated to your department": "Este ticket no está asignado a tu departamento" + "This ticket is not allocated to your department": "Este ticket no está asignado a tu departamento", + "There is already a tray with the same height": "Ya existe una bandeja con la misma altura", + "The height must be greater than 50cm": "La altura debe ser superior a 50cm", + "The maximum height of the wagon is 200cm": "La altura máxima es 200cm" } \ No newline at end of file diff --git a/modules/wagon/back/methods/wagonType/createWagonType.js b/modules/wagon/back/methods/wagonType/createWagonType.js deleted file mode 100644 index fed915b28..000000000 --- a/modules/wagon/back/methods/wagonType/createWagonType.js +++ /dev/null @@ -1,57 +0,0 @@ -module.exports = Self => { - Self.remoteMethodCtx('createWagonType', { - description: 'Creates a new wagon type', - accessType: 'WRITE', - accepts: [ - { - arg: 'name', - type: 'String', - required: true - }, - { - arg: 'divisible', - type: 'boolean', - required: true - }, { - arg: 'trays', - type: 'any', - required: true - } - ], - http: { - path: `/createWagonType`, - verb: 'PATCH' - } - }); - - Self.createWagonType = async(ctx, options) => { - const args = ctx.args; - const models = Self.app.models; - const myOptions = {}; - let tx; - - if (typeof options == 'object') - Object.assign(myOptions, options); - - if (!myOptions.transaction) { - tx = await Self.beginTransaction({}); - myOptions.transaction = tx; - } - - try { - const newWagonType = await models.WagonType.create({name: args.name, divisible: args.divisible}, myOptions); - args.trays.forEach(async tray => { - await models.WagonTypeTray.create({ - typeFk: newWagonType.id, - height: tray.position, - colorFk: tray.color.id - }, myOptions); - }); - - if (tx) await tx.commit(); - } catch (e) { - if (tx) await tx.rollback(); - throw e; - } - }; -}; diff --git a/modules/wagon/back/methods/wagonType/deleteWagonType.js b/modules/wagon/back/methods/wagonType/deleteWagonType.js deleted file mode 100644 index 46b65e32f..000000000 --- a/modules/wagon/back/methods/wagonType/deleteWagonType.js +++ /dev/null @@ -1,43 +0,0 @@ -module.exports = Self => { - Self.remoteMethodCtx('deleteWagonType', { - description: 'Deletes a wagon type', - accessType: 'WRITE', - accepts: [ - { - arg: 'id', - type: 'Number', - required: true - } - ], - http: { - path: `/deleteWagonType`, - verb: 'DELETE' - } - }); - - Self.deleteWagonType = async(ctx, options) => { - const args = ctx.args; - const models = Self.app.models; - const myOptions = {}; - let tx; - - if (typeof options == 'object') - Object.assign(myOptions, options); - - if (!myOptions.transaction) { - tx = await Self.beginTransaction({}); - myOptions.transaction = tx; - } - - try { - await models.Wagon.destroyAll({typeFk: args.id}, myOptions); - await models.WagonTypeTray.destroyAll({typeFk: args.id}, myOptions); - await models.WagonType.destroyAll({id: args.id}, myOptions); - - if (tx) await tx.commit(); - } catch (e) { - if (tx) await tx.rollback(); - throw e; - } - }; -}; diff --git a/modules/wagon/back/methods/wagonType/editWagonType.js b/modules/wagon/back/methods/wagonType/editWagonType.js deleted file mode 100644 index bd5ad1f16..000000000 --- a/modules/wagon/back/methods/wagonType/editWagonType.js +++ /dev/null @@ -1,64 +0,0 @@ -module.exports = Self => { - Self.remoteMethodCtx('editWagonType', { - description: 'Edits a new wagon type', - accessType: 'WRITE', - accepts: [ - { - arg: 'id', - type: 'String', - required: true - }, - { - arg: 'name', - type: 'String', - required: true - }, - { - arg: 'divisible', - type: 'boolean', - required: true - }, { - arg: 'trays', - type: 'any', - required: true - } - ], - http: { - path: `/editWagonType`, - verb: 'PATCH' - } - }); - - Self.editWagonType = async(ctx, options) => { - const args = ctx.args; - const models = Self.app.models; - const myOptions = {}; - let tx; - - if (typeof options == 'object') - Object.assign(myOptions, options); - - if (!myOptions.transaction) { - tx = await Self.beginTransaction({}); - myOptions.transaction = tx; - } - - try { - const wagonType = await models.WagonType.findById(args.id, null, myOptions); - wagonType.updateAttributes({name: args.name, divisible: args.divisible}, myOptions); - models.WagonTypeTray.destroyAll({typeFk: args.id}, myOptions); - args.trays.forEach(async tray => { - await models.WagonTypeTray.create({ - typeFk: args.id, - height: tray.position, - colorFk: tray.color.id - }, myOptions); - }); - - if (tx) await tx.commit(); - } catch (e) { - if (tx) await tx.rollback(); - throw e; - } - }; -}; diff --git a/modules/wagon/back/methods/wagonType/specs/crudWagonType.spec.js b/modules/wagon/back/methods/wagonType/specs/crudWagonType.spec.js index 92ac61060..96f0980f9 100644 --- a/modules/wagon/back/methods/wagonType/specs/crudWagonType.spec.js +++ b/modules/wagon/back/methods/wagonType/specs/crudWagonType.spec.js @@ -1,58 +1,16 @@ const models = require('vn-loopback/server/server').models; describe('WagonType crudWagonType()', () => { - const ctx = { - args: { - name: 'Mock wagon type', - divisible: true, - trays: [{position: 0, color: {id: 1}}, - {position: 50, color: {id: 2}}, - {position: 100, color: {id: 3}}] - } - }; - it(`should create, edit and delete a new wagon type and its trays`, async() => { const tx = await models.WagonType.beginTransaction({}); try { const options = {transaction: tx}; - // create - await models.WagonType.createWagonType(ctx, options); + const wagonType = await models.WagonType.create({name: 'Mock wagon type'}, options); + const newWagonTrays = await models.WagonTypeTray.findOne({where: {typeFk: wagonType.id}}, options); - const newWagonType = await models.WagonType.findOne({where: {name: ctx.args.name}}, options); - const newWagonTrays = await models.WagonTypeTray.find({where: {typeFk: newWagonType.id}}, options); - - expect(newWagonType).not.toEqual(null); - expect(newWagonType.name).toEqual(ctx.args.name); - expect(newWagonType.divisible).toEqual(ctx.args.divisible); - expect(newWagonTrays.length).toEqual(ctx.args.trays.length); - - ctx.args = { - id: newWagonType.id, - name: 'Edited wagon type', - divisible: false, - trays: [{position: 0, color: {id: 1}}] - }; - - // edit - await models.WagonType.editWagonType(ctx, options); - - const editedWagonType = await models.WagonType.findById(newWagonType.id, null, options); - const editedWagonTrays = await models.WagonTypeTray.find({where: {typeFk: newWagonType.id}}, options); - - expect(editedWagonType.name).toEqual(ctx.args.name); - expect(editedWagonType.divisible).toEqual(ctx.args.divisible); - expect(editedWagonTrays.length).toEqual(ctx.args.trays.length); - - // delete - await models.WagonType.deleteWagonType(ctx, options); - - const deletedWagonType = await models.WagonType.findById(newWagonType.id, null, options); - const deletedWagonTrays = await models.WagonTypeTray.find({where: {typeFk: newWagonType.id}}, options); - - expect(deletedWagonType).toEqual(null); - expect(deletedWagonTrays).toEqual([]); + expect(newWagonTrays).toBeDefined(); await tx.rollback(); } catch (e) { diff --git a/modules/wagon/back/methods/wagonType/specs/wagonTray.spec.js b/modules/wagon/back/methods/wagonType/specs/wagonTray.spec.js new file mode 100644 index 000000000..783c1a621 --- /dev/null +++ b/modules/wagon/back/methods/wagonType/specs/wagonTray.spec.js @@ -0,0 +1,58 @@ +const models = require('vn-loopback/server/server').models; + +describe('WagonTray max height()', () => { + it(`should throw an error if the tray's height is above the maximum of the wagon`, async() => { + const tx = await models.WagonTypeTray.beginTransaction({}); + + let error; + try { + const options = {transaction: tx}; + + await models.WagonTypeTray.create({height: 210, wagonTypeFk: 1, wagonTypeColorFk: 4}, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error.message).toBe('The maximum height of the wagon is 200cm'); + }); + + it(`should throw an error if the tray's height is already in the wagon`, async() => { + const tx = await models.WagonTypeTray.beginTransaction({}); + + let error; + try { + const options = {transaction: tx}; + + await models.WagonTypeTray.create({height: 50, wagonTypeFk: 1, wagonTypeColorFk: 2}, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error.message).toBe('There is already a tray with the same height'); + }); + + it(`should throw an error if the tray's height is below the minimum between the trays`, async() => { + const tx = await models.WagonTypeTray.beginTransaction({}); + + let error; + try { + const options = {transaction: tx}; + + await models.WagonTypeTray.create({height: 40, wagonTypeFk: 1, wagonTypeColorFk: 4}, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error.message).toBe('The height must be greater than 50cm'); + }); +}); + diff --git a/modules/wagon/back/models/wagon-config.json b/modules/wagon/back/models/wagon-config.json index 3d96e2864..d76558564 100644 --- a/modules/wagon/back/models/wagon-config.json +++ b/modules/wagon/back/models/wagon-config.json @@ -25,6 +25,19 @@ }, "maxTrays": { "type": "number" + }, + "defaultHeight": { + "type": "number" + }, + "defaultTrayColorFk": { + "type": "number" } + }, + "relations": { + "WagonTypeColor": { + "type": "belongsTo", + "model": "WagonTypeColor", + "foreignKey": "defaultTrayColorFk" + } } } diff --git a/modules/wagon/back/models/wagon-type-tray.js b/modules/wagon/back/models/wagon-type-tray.js new file mode 100644 index 000000000..219f20bfb --- /dev/null +++ b/modules/wagon/back/models/wagon-type-tray.js @@ -0,0 +1,25 @@ +const UserError = require('vn-loopback/util/user-error'); + +module.exports = Self => { + Self.observe('before save', async ctx => { + if (ctx.isNewInstance) { + const models = Self.app.models; + const {wagonTypeFk, height} = ctx.instance; + const trays = await models.WagonTypeTray.find({where: {wagonTypeFk}}); + + const config = await models.WagonConfig.findOne(); + const tray = await models.WagonTypeTray.find({where: {wagonTypeFk, height}}); + + if (!trays.length) return; + + if (tray.length) + throw new UserError('There is already a tray with the same height'); + + if (height < config.minHeightBetweenTrays) + throw new UserError('The height must be greater than 50cm'); + + if (height > config.maxWagonHeight) + throw new UserError('The maximum height of the wagon is 200cm'); + } + }); +}; diff --git a/modules/wagon/back/models/wagon-type-tray.json b/modules/wagon/back/models/wagon-type-tray.json index b61510bcf..61b32694d 100644 --- a/modules/wagon/back/models/wagon-type-tray.json +++ b/modules/wagon/back/models/wagon-type-tray.json @@ -11,13 +11,13 @@ "id": true, "type": "number" }, - "typeFk": { + "wagonTypeFk": { "type": "number" }, "height": { "type": "number" }, - "colorFk": { + "wagonTypeColorFk": { "type": "number" } }, @@ -25,12 +25,12 @@ "type": { "type": "belongsTo", "model": "WagonType", - "foreignKey": "typeFk" + "foreignKey": "wagonTypeFk" }, "color": { "type": "belongsTo", "model": "WagonTypeColor", - "foreignKey": "colorFk" + "foreignKey": "wagonTypeColorFk" } } } diff --git a/modules/wagon/back/models/wagon-type.js b/modules/wagon/back/models/wagon-type.js index bebf7a9d9..0610adcb4 100644 --- a/modules/wagon/back/models/wagon-type.js +++ b/modules/wagon/back/models/wagon-type.js @@ -1,5 +1,14 @@ module.exports = Self => { - require('../methods/wagonType/createWagonType')(Self); - require('../methods/wagonType/editWagonType')(Self); - require('../methods/wagonType/deleteWagonType')(Self); + Self.observe('after save', async ctx => { + if (ctx.isNewInstance) { + const models = Self.app.models; + const config = await models.WagonConfig.findOne(); + + await models.WagonTypeTray.create({ + wagonTypeFk: ctx.instance.id, + height: config.defaultHeight, + wagonTypeColorFk: config.defaultTrayColorFk + }, ctx.options); + } + }); };