diff --git a/db/dump/fixtures.before.sql b/db/dump/fixtures.before.sql index 0a797f7ec2..5235f5f455 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/routines/vn/procedures/collection_new.sql b/db/routines/vn/procedures/collection_new.sql index a5a9a61c7f..53f5500a07 100644 --- a/db/routines/vn/procedures/collection_new.sql +++ b/db/routines/vn/procedures/collection_new.sql @@ -167,7 +167,8 @@ BEGIN OR LENGTH(pb.problem) OR pb.lines > vLinesLimit OR pb.m3 > vVolumeLimit - OR sub.maxSize > vSizeLimit; + OR sub.maxSize > vSizeLimit + OR pb.hasPlantTray; END IF; -- Hay que excluir aquellos que no tengan la misma hora de preparacion, si procede diff --git a/db/routines/vn/procedures/itemShelving_add.sql b/db/routines/vn/procedures/itemShelving_add.sql index 16e7713cd3..92d1609e48 100644 --- a/db/routines/vn/procedures/itemShelving_add.sql +++ b/db/routines/vn/procedures/itemShelving_add.sql @@ -46,7 +46,8 @@ BEGIN AND buyFk = vBuyFk) THEN UPDATE itemShelving - SET visible = visible + vQuantity + SET visible = visible + vQuantity, + available = available + vQuantity WHERE shelvingFk COLLATE utf8_unicode_ci = vShelvingFk AND itemFk = vItemFk AND packing = vPacking; ELSE @@ -68,6 +69,6 @@ BEGIN id FROM buy b WHERE id = vBuyFk; - END IF; + END IF; END$$ DELIMITER ; \ No newline at end of file diff --git a/db/routines/vn/procedures/productionControl.sql b/db/routines/vn/procedures/productionControl.sql index e5323e84ef..842a306b49 100644 --- a/db/routines/vn/procedures/productionControl.sql +++ b/db/routines/vn/procedures/productionControl.sql @@ -211,8 +211,6 @@ proc: BEGIN salesInParkingCount INT DEFAULT 0) ENGINE = MEMORY; - -- Insertamos todos los tickets que tienen productos parkineados - -- en sectores de previa, segun el sector CREATE OR REPLACE TEMPORARY TABLE tItemShelvingStock (PRIMARY KEY(itemFk, sectorFk)) ENGINE = MEMORY @@ -245,7 +243,6 @@ proc: BEGIN AND s.quantity > 0 GROUP BY pb.ticketFk; - -- Se calcula la cantidad de productos que estan ya preparados porque su saleGroup está aparcado UPDATE tmp.ticketWithPrevia twp JOIN ( SELECT pb.ticketFk, COUNT(DISTINCT s.id) salesInParkingCount @@ -259,12 +256,28 @@ proc: BEGIN ) sub ON twp.ticketFk = sub.ticketFk SET twp.salesInParkingCount = sub.salesInParkingCount; - -- Marcamos como pendientes aquellos que no coinciden las cantidades UPDATE tmp.productionBuffer pb JOIN tmp.ticketWithPrevia twp ON twp.ticketFk = pb.ticketFk SET pb.previousWithoutParking = TRUE WHERE twp.salesCount > twp.salesInParkingCount; + -- hasPlantTray + ALTER TABLE tmp.productionBuffer + ADD hasPlantTray BOOL DEFAULT FALSE; + + UPDATE tmp.productionBuffer pb + JOIN sale s ON s.ticketFk = pb.ticketFk + JOIN item i ON i.id = s.itemFk + JOIN itemType it ON it.id = i.typeFk + JOIN itemCategory ic ON ic.id = it.categoryFk + JOIN cache.last_buy lb ON lb.warehouse_id = vWarehouseFk AND lb.item_id = s.itemFk + JOIN buy b ON b.id = lb.buy_id + JOIN packaging p ON p.id = b.packagingFk + JOIN productionConfig pc + SET hasPlantTray = TRUE + WHERE ic.code = 'plant' + AND p.`depth` >= pc.minPlantTrayLength; + DROP TEMPORARY TABLE tmp.productionTicket, tmp.ticket, diff --git a/db/routines/vn/procedures/sale_boxPickingPrint.sql b/db/routines/vn/procedures/sale_boxPickingPrint.sql index acb60ed31d..6bb954a783 100644 --- a/db/routines/vn/procedures/sale_boxPickingPrint.sql +++ b/db/routines/vn/procedures/sale_boxPickingPrint.sql @@ -160,7 +160,10 @@ w1: WHILE vQuantity >= vPacking DO UPDATE sale SET quantity = quantity - vPacking WHERE id = vSaleFk; - UPDATE itemShelving SET visible = visible - vPacking WHERE id = vItemShelvingFk; + UPDATE itemShelving + SET visible = visible - vPacking, + available = available - vPacking + WHERE id = vItemShelvingFk; SET vNewSaleFk = NULL; diff --git a/db/versions/11088-bronzeAspidistra/00-firstScript.sql b/db/versions/11088-bronzeAspidistra/00-firstScript.sql new file mode 100644 index 0000000000..751bbf7e32 --- /dev/null +++ b/db/versions/11088-bronzeAspidistra/00-firstScript.sql @@ -0,0 +1,19 @@ +ALTER TABLE vn.collectionWagonTicket DROP FOREIGN KEY IF EXISTS collectionWagonTicket_tray; +ALTER TABLE vn.wagonConfig DROP FOREIGN KEY IF EXISTS wagonConfig_wagonTypeColor_FK; +CREATE OR REPLACE TABLE vn.wagonTypeTray ( + id INT(11) UNSIGNED, + wagonTypeFk INT(11) unsigned NULL, + height INT(11) UNSIGNED NULL, + wagonTypeColorFk int(11) unsigned NULL, + CONSTRAINT wagonTypeTray_pk PRIMARY KEY (id), + CONSTRAINT wagonTypeTray_wagonType_FK FOREIGN KEY (wagonTypeFk) REFERENCES vn.wagonType(id) ON DELETE CASCADE ON UPDATE RESTRICT, + 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.collectionWagonTicket ADD CONSTRAINT collectionWagonTicket_tray FOREIGN KEY (trayFk) REFERENCES vn.wagonTypeTray(id); diff --git a/db/versions/11224-whiteMastic/00-firstScript.sql b/db/versions/11224-whiteMastic/00-firstScript.sql index 52267cd91f..de74dfc554 100644 --- a/db/versions/11224-whiteMastic/00-firstScript.sql +++ b/db/versions/11224-whiteMastic/00-firstScript.sql @@ -1,2 +1,3 @@ +ALTER TABLE vn.creditInsurance DROP FOREIGN KEY CreditInsurance_Fk1; ALTER TABLE vn.creditInsurance CHANGE creditClassification creditClassification__ int(11) DEFAULT NULL COMMENT '@deprecated 2024-09-11'; diff --git a/db/versions/11229-salmonAsparagus/00-firstScript.sql b/db/versions/11229-salmonAsparagus/00-firstScript.sql new file mode 100644 index 0000000000..d590ed958d --- /dev/null +++ b/db/versions/11229-salmonAsparagus/00-firstScript.sql @@ -0,0 +1,3 @@ +-- Place your SQL code here +ALTER TABLE vn.productionConfig ADD minPlantTrayLength INT DEFAULT 53 NOT NULL +COMMENT 'minimum length for plant tray restriction. Avoid to make collection of the ticket with this kind of item'; diff --git a/loopback/locale/en.json b/loopback/locale/en.json index d9d9c8511b..1753d1d072 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 064ea4a958..1093fe326e 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 fed915b28e..0000000000 --- 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 46b65e32f8..0000000000 --- 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 bd5ad1f168..0000000000 --- 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 92ac61060a..96f0980f98 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 0000000000..783c1a6210 --- /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 3d96e28645..d765585642 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 0000000000..219f20bfb2 --- /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 b61510bcf6..61b32694db 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 bebf7a9d9b..0610adcb44 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); + } + }); }; diff --git a/modules/worker/back/methods/worker-dms/filter.js b/modules/worker/back/methods/worker-dms/filter.js index 0d13276b1d..597084e60f 100644 --- a/modules/worker/back/methods/worker-dms/filter.js +++ b/modules/worker/back/methods/worker-dms/filter.js @@ -50,7 +50,7 @@ module.exports = Self => { or: [ {and: [ {isReadableByWorker: true}, - {worker: userId} + {'wd.workerFk': userId} ]}, { role: {