diff --git a/db/routines/bs/procedures/ventas_contables_add.sql b/db/routines/bs/procedures/ventas_contables_add.sql index 72b0c0feed..c82cb96d9c 100644 --- a/db/routines/bs/procedures/ventas_contables_add.sql +++ b/db/routines/bs/procedures/ventas_contables_add.sql @@ -15,7 +15,7 @@ BEGIN DELETE FROM bs.ventas_contables WHERE year = vYear - AND month = vMonth; + AND month = vMonth; DROP TEMPORARY TABLE IF EXISTS tmp.ticket_list; CREATE TEMPORARY TABLE tmp.ticket_list diff --git a/db/routines/vn/procedures/entry_clone.sql b/db/routines/vn/procedures/entry_clone.sql index a0ed39c295..511ff4837f 100644 --- a/db/routines/vn/procedures/entry_clone.sql +++ b/db/routines/vn/procedures/entry_clone.sql @@ -1,20 +1,31 @@ DELIMITER $$ -CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`entry_clone`(vSelf INT) +CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`entry_clone`( + vSelf INT, + OUT vOutputEntryFk INT +) BEGIN /** * clones an entry. * * @param vSelf The entry id + * @param vOutputEntryFk The new entry id */ DECLARE vNewEntryFk INT; - START TRANSACTION; + DECLARE vIsRequiredTx BOOL DEFAULT NOT @@in_transaction; + DECLARE EXIT HANDLER FOR SQLEXCEPTION + BEGIN + CALL util.tx_rollback(vIsRequiredTx); + RESIGNAL; + END; + + CALL util.tx_start(vIsRequiredTx); CALL entry_cloneHeader(vSelf, vNewEntryFk, NULL); CALL entry_copyBuys(vSelf, vNewEntryFk); - COMMIT; + CALL util.tx_commit(vIsRequiredTx); + SET vOutputEntryFk = vNewEntryFk; - SELECT vNewEntryFk; END$$ DELIMITER ; diff --git a/db/routines/vn/procedures/entry_splitByShelving.sql b/db/routines/vn/procedures/entry_splitByShelving.sql index f5de360980..019abe6cb1 100644 --- a/db/routines/vn/procedures/entry_splitByShelving.sql +++ b/db/routines/vn/procedures/entry_splitByShelving.sql @@ -39,14 +39,14 @@ BEGIN read_loop: LOOP SET vDone = FALSE; - + FETCH cur INTO vBuyFk, vIshStickers, vBuyStickers; IF vDone THEN LEAVE read_loop; END IF; - IF vIshStickers = vBuyStickers THEN + IF vIshStickers = vBuyStickers THEN UPDATE buy SET entryFk = vToEntryFk WHERE id = vBuyFk; diff --git a/db/routines/vn/procedures/entry_transfer.sql b/db/routines/vn/procedures/entry_transfer.sql new file mode 100644 index 0000000000..5b83ae5321 --- /dev/null +++ b/db/routines/vn/procedures/entry_transfer.sql @@ -0,0 +1,158 @@ +DELIMITER $$ +CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`entry_transfer`( + vOriginalEntry INT, + OUT vNewEntryFk INT + ) +BEGIN +/** + * Adelanta a mañana la mercancia de una entrada a partir de lo que hay ubicado en el almacén + * + * @param vOriginalEntry entrada que se quiera adelantar + * @param vNewEntry nueva entrada creada + */ + DECLARE vTravelFk INT; + DECLARE vWarehouseFk INT; + DECLARE vWarehouseInFk INT; + DECLARE vWarehouseOutFk INT; + DECLARE vRef INT; + DECLARE vIsReceived INT; + DECLARE vAgencyModeFk INT; + DECLARE vTomorrow DATETIME DEFAULT util.tomorrow(); + DECLARE vCurDate DATE DEFAULT util.VN_CURDATE(); + + DECLARE vIsRequiredTx BOOL DEFAULT NOT @@in_transaction; + DECLARE EXIT HANDLER FOR SQLEXCEPTION + BEGIN + CALL util.tx_rollback(vIsRequiredTx); + RESIGNAL; + END; + + -- Clonar la entrada + CALL entry_clone(vOriginalEntry, vNewEntryFk); + + CALL util.tx_start(vIsRequiredTx); + + /* Hay que crear un nuevo travel, con salida hoy y llegada mañana y + asignar la entrada nueva al nuevo travel.*/ + SELECT t.warehouseInFk, t.warehouseOutFk, t.`ref`, t.isReceived, t.agencyModeFk + INTO vWarehouseInFk, vWarehouseOutFk, vRef, vIsReceived, vAgencyModeFk + FROM travel t + JOIN entry e ON e.travelFk = t.id + WHERE e.id = vOriginalEntry; + + SELECT id INTO vTravelFk + FROM travel t + WHERE shipped = vCurDate + AND landed = vTomorrow + AND warehouseInFk = vWarehouseInFk + AND warehouseOutFk = vWarehouseOutFk + AND `ref` = vRef + AND isReceived =vIsReceived + AND agencyModeFk = vAgencyModeFk; + + IF vTravelFk IS NULL THEN + INSERT INTO travel( + shipped, + landed, + warehouseInFk, + warehouseOutFk, + `ref`, + isReceived, + agencyModeFk) + SELECT vCurDate, + vTomorrow, + t.warehouseInFk, + t.warehouseOutFk, + t.`ref`, + t.isReceived, + t.agencyModeFk + FROM travel t + JOIN entry e ON e.travelFk = t.id + WHERE e.id = vOriginalEntry; + + SET vTravelFk = LAST_INSERT_ID(); + END IF; + + UPDATE entry + SET travelFk = vTravelFk, + evaNotes = vOriginalEntry + WHERE id = vNewEntryFk; + + -- Poner a 0 las cantidades + UPDATE buy b + SET b.quantity = 0, b.stickers = 0 + WHERE b.entryFk = vNewEntryFk; + + -- Eliminar duplicados + DELETE b + FROM buy b + LEFT JOIN (SELECT b.id, b.itemFk + FROM buy b + WHERE b.entryFk = vNewEntryFk + GROUP BY b.itemFk) tBuy ON tBuy.id = b.id + WHERE b.entryFk = vNewEntryFk + AND tBuy.id IS NULL; + + SELECT t.warehouseInFk INTO vWarehouseFk + FROM travel t + JOIN entry e ON e.travelFk = t.id + WHERE e.id = vOriginalEntry; + + /* Actualizar nueva entrada con lo que no está ubicado HOY, + descontando lo vendido HOY de esas ubicaciones*/ + CREATE OR REPLACE TEMPORARY TABLE buys + WITH tBuy AS ( + SELECT b.itemFk, SUM(b.quantity) totalQuantity + FROM vn.buy b + WHERE b.entryFk = vOriginalEntry + GROUP BY b.itemFk + ), + itemShelvings AS ( + SELECT ish.itemFk, SUM(ish.visible) visible + FROM vn.itemShelving ish + JOIN vn.shelving sh ON sh.id = ish.shelvingFk + JOIN vn.parking p ON p.id = sh.parkingFk + JOIN vn.sector s ON s.id = p.sectorFk + JOIN vn.buy b ON b.id = ish.buyFk + JOIN vn.entry e ON e.id = b.entryFk + JOIN tBuy t ON t.itemFk = ish.itemFk + WHERE s.warehouseFk = vWarehouseFk + AND sh.parked >= vCurDate + GROUP BY ish.itemFk + ), + sales AS ( + SELECT s.itemFk, SUM(s.quantity) sold + FROM vn.ticket t + JOIN vn.sale s ON s.ticketFk = t.id + JOIN vn.itemShelvingSale iss ON iss.saleFk = s.id + JOIN vn.itemShelving is2 ON is2.id = iss.itemShelvingFk + JOIN vn.shelving s2 ON s2.id = is2.shelvingFk + JOIN tBuy t ON t.itemFk = s.itemFk + WHERE t.shipped BETWEEN vCurDate AND util.dayend(vCurDate) + AND s2.parked >= vCurDate + GROUP BY s.itemFk + ) + SELECT tmp.itemFk, + IFNULL(iss.visible, 0) visible, + tmp.totalQuantity, + IFNULL(s.sold, 0) sold + FROM tBuy tmp + LEFT JOIN itemShelvings iss ON tmp.itemFk = iss.itemFk + LEFT JOIN sales s ON s.itemFk = tmp.itemFk + WHERE visible < tmp.totalQuantity + OR iss.itemFk IS NULL; + + UPDATE buy b + JOIN buys tmp ON tmp.itemFk = b.itemFk + SET b.quantity = tmp.totalQuantity - tmp.visible - tmp.sold + WHERE b.entryFk = vNewEntryFk; + + -- Limpia la nueva entrada + DELETE FROM buy WHERE entryFk = vNewEntryFk AND quantity = 0; + + CALL util.tx_commit(vIsRequiredTx); + + CALL cache.visible_refresh(@c,TRUE,vWarehouseFk); + CALL cache.available_refresh(@c, TRUE, vWarehouseFk, vCurDate); +END$$ +DELIMITER ; diff --git a/modules/entry/back/methods/entry/specs/transfer.spec.js b/modules/entry/back/methods/entry/specs/transfer.spec.js new file mode 100644 index 0000000000..bf0b2b974a --- /dev/null +++ b/modules/entry/back/methods/entry/specs/transfer.spec.js @@ -0,0 +1,43 @@ +const models = require('vn-loopback/server/server').models; + +describe('Transfer merchandise from one entry to the next day()', () => { + it('should Transfer buys not located', async() => { + const tx = await models.ItemShelving.beginTransaction({}); + const options = {transaction: tx}; + + try { + const id = 3; + const item = 8; + const buy = 6; + const originalEntry = 4; + const ctx = {req: {accessToken: {userId: 48}}}; + + const currentItemShelving = await models.ItemShelving.findOne({where: {id}}, options); + await currentItemShelving.updateAttributes({itemFk: item, buyFk: buy}, options); + + const {newEntryFk} = await models.Entry.transfer(ctx, originalEntry, options); + const originalEntrybuys = await models.Buy.find({where: {entryFk: originalEntry}}, options); + + const newEntrybuys = await models.Buy.find({where: {entryFk: newEntryFk}}, options); + + const itemShelvingsWithBuys = await models.Buy.find({ + include: { + relation: 'itemShelving', + scope: { + fields: ['id'], + }, + }, + where: {entryFk: originalEntry}, + }, options); + + const hasItemShelving = await itemShelvingsWithBuys.filter(buy => buy.itemShelving().length); + + expect(newEntrybuys.length).toEqual(originalEntrybuys.length - hasItemShelving.length); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); +}); diff --git a/modules/entry/back/methods/entry/transfer.js b/modules/entry/back/methods/entry/transfer.js new file mode 100644 index 0000000000..db68736633 --- /dev/null +++ b/modules/entry/back/methods/entry/transfer.js @@ -0,0 +1,45 @@ +module.exports = Self => { + Self.remoteMethodCtx('transfer', { + description: 'Transfer merchandise from one entry to the next day', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + http: {source: 'path'} + } + ], + http: { + path: '/:id/transfer', + verb: 'POST' + }, + returns: { + arg: 'newEntryFk', + type: 'number' + } + }); + + Self.transfer = async(ctx, id, options) => { + const myOptions = {userId: ctx.req.accessToken.userId}; + let tx; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + if (!myOptions.transaction) { + tx = await Self.beginTransaction({}); + myOptions.transaction = tx; + } + + try { + await Self.rawSql('CALL vn.entry_transfer(?, @vNewEntry)', [id], myOptions); + const [newEntryFk] = await Self.rawSql('SELECT @vNewEntry newEntryFk', null, myOptions); + + if (tx) await tx.commit(); + return newEntryFk; + } catch (e) { + if (tx) await tx.rollback(); + throw e; + } + }; +}; diff --git a/modules/entry/back/models/buy.json b/modules/entry/back/models/buy.json index 14cafde06b..cd1e54de73 100644 --- a/modules/entry/back/models/buy.json +++ b/modules/entry/back/models/buy.json @@ -114,6 +114,11 @@ "type": "belongsTo", "model": "Delivery", "foreignKey": "deliveryFk" - } + }, + "itemShelving": { + "type": "hasMany", + "model": "ItemShelving", + "foreignKey": "buyFk" + } } } diff --git a/modules/entry/back/models/entry.js b/modules/entry/back/models/entry.js index 55a23bb0a2..03cbd6e7f9 100644 --- a/modules/entry/back/models/entry.js +++ b/modules/entry/back/models/entry.js @@ -12,6 +12,7 @@ module.exports = Self => { require('../methods/entry/addFromPackaging')(Self); require('../methods/entry/addFromBuy')(Self); require('../methods/entry/buyLabel')(Self); + require('../methods/entry/transfer')(Self); require('../methods/entry/labelSupplier')(Self); require('../methods/entry/buyLabelSupplier')(Self); diff --git a/modules/item/back/models/item-shelving.json b/modules/item/back/models/item-shelving.json index 483d6bf3dc..5c31e9e4e1 100644 --- a/modules/item/back/models/item-shelving.json +++ b/modules/item/back/models/item-shelving.json @@ -61,6 +61,11 @@ "type": "belongsTo", "model": "Shelving", "foreignKey": "shelvingFk" - } + }, + "buy": { + "type": "belongsTo", + "model": "Buy", + "foreignKey": "buyFk" + } } -} \ No newline at end of file +}