diff --git a/db/changes/10320-monitors/00-sale_getProblems.sql b/db/changes/10320-monitors/00-sale_getProblems.sql new file mode 100644 index 000000000..290dcddb2 --- /dev/null +++ b/db/changes/10320-monitors/00-sale_getProblems.sql @@ -0,0 +1,193 @@ +DROP PROCEDURE IF EXISTS `vn`.`sale_getProblems`; + +DELIMITER $$ +$$ +CREATE + DEFINER = root@`%` PROCEDURE `vn`.`sale_getProblems`(IN vIsTodayRelative TINYINT(1)) +BEGIN +/** + * Calcula los problemas de cada venta + * para un conjunto de tickets. + * + * @table tmp.sale_getProblems(ticketFk, clientFk, warehouseFk, shipped) Identificadores de los tickets a calcular + * @return tmp.sale_problems + */ + DECLARE vWarehouse INT; + DECLARE vDate DATE; + DECLARE vAvailableCache INT; + DECLARE vDone INT DEFAULT 0; + DECLARE vComponentCount INT; + + DECLARE vCursor CURSOR FOR + SELECT DISTINCT tt.warehouseFk, IF(vIsTodayRelative, CURDATE(), date(tt.shipped)) + FROM tmp.sale_getProblems tt + WHERE DATE(tt.shipped) BETWEEN CURDATE() + AND TIMESTAMPADD(DAY, IF(vIsTodayRelative, 9.9, 1.9), CURDATE()); + + DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = 1; + + DROP TEMPORARY TABLE IF EXISTS tmp.sale_problems; + CREATE TEMPORARY TABLE tmp.sale_problems ( + ticketFk INT(11), + saleFk INT(11), + isFreezed INTEGER(1) DEFAULT 0, + risk DECIMAL(10,2) DEFAULT 0, + hasTicketRequest INTEGER(1) DEFAULT 0, + isAvailable INTEGER(1) DEFAULT 1, + itemShortage VARCHAR(250), + isTaxDataChecked INTEGER(1) DEFAULT 1, + itemDelay VARCHAR(250), + hasComponentLack INTEGER(1), + PRIMARY KEY (ticketFk, saleFk) + ) ENGINE = MEMORY; + + DROP TEMPORARY TABLE IF EXISTS tmp.ticket_list; + CREATE TEMPORARY TABLE tmp.ticket_list + (PRIMARY KEY (ticketFk)) + ENGINE = MEMORY + SELECT tp.ticketFk, c.id clientFk + FROM tmp.sale_getProblems tp + JOIN vn.client c ON c.id = tp.clientFk; + + SELECT COUNT(*) INTO vComponentCount + FROM vn.component c + WHERE c.isRequired; + + INSERT INTO tmp.sale_problems(ticketFk, hasComponentLack, saleFk) + SELECT tl.ticketFk, (COUNT(DISTINCT s.id) * vComponentCount > COUNT(c.id)), s.id + FROM tmp.ticket_list tl + JOIN vn.sale s ON s.ticketFk = tl.ticketFk + LEFT JOIN vn.saleComponent sc ON sc.saleFk = s.id + LEFT JOIN vn.component c ON c.id = sc.componentFk AND c.isRequired + GROUP BY tl.ticketFk, s.id; + + INSERT INTO tmp.sale_problems(ticketFk, isFreezed) + SELECT DISTINCT tl.ticketFk, TRUE + FROM tmp.ticket_list tl + JOIN vn.client c ON c.id = tl.clientFk + WHERE c.isFreezed + ON DUPLICATE KEY UPDATE + isFreezed = c.isFreezed; + + DROP TEMPORARY TABLE IF EXISTS tmp.clientGetDebt; + CREATE TEMPORARY TABLE tmp.clientGetDebt + (PRIMARY KEY (clientFk)) + ENGINE = MEMORY + SELECT DISTINCT clientFk + FROM tmp.ticket_list; + + CALL clientGetDebt(CURDATE()); + + INSERT INTO tmp.sale_problems(ticketFk, risk) + SELECT DISTINCT tl.ticketFk, r.risk + FROM tmp.ticket_list tl + JOIN vn.ticket t ON t.id = tl.ticketFk + JOIN vn.agencyMode a ON t.agencyModeFk = a.id + JOIN tmp.risk r ON r.clientFk = t.clientFk + JOIN vn.client c ON c.id = t.clientFk + JOIN vn.clientConfig cc + WHERE r.risk - cc.riskTolerance > c.credit + 10 + AND a.isRiskFree = FALSE + ON DUPLICATE KEY UPDATE + risk = r.risk; + + INSERT INTO tmp.sale_problems(ticketFk, hasTicketRequest) + SELECT DISTINCT tl.ticketFk, TRUE + FROM tmp.ticket_list tl + JOIN vn.ticketRequest tr ON tr.ticketFk = tl.ticketFk + WHERE tr.isOK IS NULL + ON DUPLICATE KEY UPDATE + hasTicketRequest = TRUE; + + OPEN vCursor; + + WHILE NOT vDone + DO + FETCH vCursor INTO vWarehouse, vDate; + + CALL cache.available_refresh(vAvailableCache, FALSE, vWarehouse, vDate); + + INSERT INTO tmp.sale_problems(ticketFk, isAvailable, saleFk) + SELECT tl.ticketFk, FALSE, s.id + FROM tmp.ticket_list tl + JOIN vn.ticket t ON t.id = tl.ticketFk + JOIN vn.sale s ON s.ticketFk = t.id + JOIN vn.item i ON i.id = s.itemFk + JOIN vn.itemType it on it.id = i.typeFk + LEFT JOIN cache.available av ON av.item_id = i.id + AND av.calc_id = vAvailableCache + WHERE date(t.shipped) = vDate + AND it.categoryFk != 6 + AND IFNULL(av.available, 0) < 0 + AND s.isPicked = FALSE + AND NOT i.generic + AND vWarehouse = t.warehouseFk + GROUP BY tl.ticketFk + ON DUPLICATE KEY UPDATE + isAvailable = FALSE, saleFk = VALUE(saleFk); + + INSERT INTO tmp.sale_problems(ticketFk, itemShortage, saleFk) + SELECT ticketFk, problem, saleFk + FROM ( + SELECT tl.ticketFk, CONCAT('F: ',GROUP_CONCAT(i.id, ' ', i.longName, ' ')) problem, s.id AS saleFk + FROM tmp.ticket_list tl + JOIN vn.ticket t ON t.id = tl.ticketFk + JOIN vn.sale s ON s.ticketFk = t.id + JOIN vn.item i ON i.id = s.itemFk + JOIN vn.itemType it on it.id = i.typeFk + LEFT JOIN vn.itemShelvingStock_byWarehouse issw ON issw.itemFk = i.id AND issw.warehouseFk = t.warehouseFk + LEFT JOIN cache.available av ON av.item_id = i.id AND av.calc_id = vAvailableCache + WHERE IFNULL(av.available, 0) < 0 + AND s.quantity > IFNULL(issw.visible, 0) + AND s.quantity > 0 + AND s.isPicked = FALSE + AND s.reserved = FALSE + AND it.categoryFk != 6 + AND IF(vIsTodayRelative, TRUE, date(t.shipped) = vDate) + AND NOT i.generic + AND CURDATE() = vDate + AND t.warehouseFk = vWarehouse + GROUP BY tl.ticketFk LIMIT 1) sub + ON DUPLICATE KEY UPDATE + itemShortage = sub.problem, saleFk = sub.saleFk; + + INSERT INTO tmp.sale_problems(ticketFk, itemDelay, saleFk) + SELECT ticketFk, problem, saleFk + FROM ( + SELECT tl.ticketFk, GROUP_CONCAT('I: ',i.id, ' ', i.longName, ' ') problem, s.id AS saleFk + FROM tmp.ticket_list tl + JOIN vn.ticket t ON t.id = tl.ticketFk + JOIN vn.sale s ON s.ticketFk = t.id + JOIN vn.item i ON i.id = s.itemFk + JOIN vn.itemType it on it.id = i.typeFk + LEFT JOIN vn.itemShelvingStock_byWarehouse issw ON issw.itemFk = i.id AND issw.warehouseFk = t.warehouseFk + WHERE s.quantity > IFNULL(issw.visible, 0) + AND s.quantity > 0 + AND s.isPicked = FALSE + AND s.reserved = FALSE + AND it.categoryFk != 6 + AND IF(vIsTodayRelative, TRUE, date(t.shipped) = vDate) + AND NOT i.generic + AND CURDATE() = vDate + AND t.warehouseFk = vWarehouse + GROUP BY tl.ticketFk LIMIT 1) sub + ON DUPLICATE KEY UPDATE + itemDelay = sub.problem, saleFk = sub.saleFk; + END WHILE; + + CLOSE vCursor; + + INSERT INTO tmp.sale_problems(ticketFk, isTaxDataChecked) + SELECT DISTINCT tl.ticketFk, FALSE + FROM tmp.ticket_list tl + JOIN vn.client c ON c.id = tl.clientFk + WHERE c.isTaxDataChecked = FALSE + ON DUPLICATE KEY UPDATE + isTaxDataChecked = FALSE; + + DROP TEMPORARY TABLE + tmp.clientGetDebt, + tmp.ticket_list; +END;;$$ +DELIMITER ; + diff --git a/db/changes/10320-monitors/00-sale_getProblemsByTicket.sql b/db/changes/10320-monitors/00-sale_getProblemsByTicket.sql new file mode 100644 index 000000000..1f30014d4 --- /dev/null +++ b/db/changes/10320-monitors/00-sale_getProblemsByTicket.sql @@ -0,0 +1,30 @@ +DROP PROCEDURE IF EXISTS `vn`.`sale_getProblemsByTicket`; + +DELIMITER $$ +$$ +CREATE + DEFINER = root@`%` PROCEDURE `vn`.`sale_getProblemsByTicket`(IN vTicketFk INT, IN vIsTodayRelative TINYINT(1)) +BEGIN +/** + * Calcula los problemas de cada venta + * para un conjunto de tickets. + * + * @return Problems result + */ + DROP TEMPORARY TABLE IF EXISTS tmp.sale_getProblems; + CREATE TEMPORARY TABLE tmp.sale_getProblems + (INDEX (ticketFk)) + ENGINE = MEMORY + SELECT t.id ticketFk, t.clientFk, t.warehouseFk, t.shipped + FROM ticket t + WHERE t.id = vTicketFk; + + CALL sale_getProblems(vIsTodayRelative); + + SELECT * FROM tmp.sale_problems; + + DROP TEMPORARY TABLE + tmp.sale_getProblems, + tmp.sale_problems; +END;;$$ +DELIMITER ; diff --git a/db/changes/10320-monitors/00-ticketGetProblems.sql b/db/changes/10320-monitors/00-ticketGetProblems.sql new file mode 100644 index 000000000..85d6e4018 --- /dev/null +++ b/db/changes/10320-monitors/00-ticketGetProblems.sql @@ -0,0 +1,188 @@ +DROP PROCEDURE IF EXISTS `vn`.`ticketGetProblems`; + +DELIMITER $$ +$$ +CREATE + DEFINER = root@`%` PROCEDURE `vn`.`ticketGetProblems`(IN vIsTodayRelative TINYINT(1)) +BEGIN +/** + * @deprecated Use ticket_getProblems() instead + * + */ + DECLARE vWarehouse INT; + DECLARE vDate DATE; + DECLARE vAvailableCache INT; + DECLARE vDone INT DEFAULT 0; + DECLARE vComponentCount INT; + + DECLARE vCursor CURSOR FOR + SELECT DISTINCT tt.warehouseFk, IF(vIsTodayRelative, CURDATE(), date(tt.shipped)) + FROM tmp.ticketGetProblems tt + WHERE DATE(tt.shipped) BETWEEN CURDATE() + AND TIMESTAMPADD(DAY, IF(vIsTodayRelative, 9.9, 1.9), CURDATE()); + + DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = 1; + + DROP TEMPORARY TABLE IF EXISTS tmp.ticketProblems; + CREATE TEMPORARY TABLE tmp.ticketProblems ( + ticketFk INT(11) PRIMARY KEY, + isFreezed INTEGER(1) DEFAULT 0, + risk DECIMAL(10,2) DEFAULT 0, + hasTicketRequest INTEGER(1) DEFAULT 0, + isAvailable INTEGER(1) DEFAULT 1, + itemShortage VARCHAR(250), + isTaxDataChecked INTEGER(1) DEFAULT 1, + itemDelay VARCHAR(250), + componentLack INTEGER(1) + ) ENGINE = MEMORY; + + DROP TEMPORARY TABLE IF EXISTS tmp.ticketList; + CREATE TEMPORARY TABLE tmp.ticketList + (PRIMARY KEY (ticketFk)) + ENGINE = MEMORY + SELECT tp.ticketFk, c.id clientFk + FROM tmp.ticketGetProblems tp + JOIN vn.client c ON c.id = tp.clientFk; + + SELECT COUNT(*) INTO vComponentCount + FROM vn.component c + WHERE c.isRequired; + + INSERT INTO tmp.ticketProblems(ticketFk, componentLack) + SELECT tl.ticketFk, (COUNT(DISTINCT s.id) * vComponentCount > COUNT(c.id)) + FROM tmp.ticketList tl + JOIN vn.sale s ON s.ticketFk = tl.ticketFk + LEFT JOIN vn.saleComponent sc ON sc.saleFk = s.id + LEFT JOIN vn.component c ON c.id = sc.componentFk AND c.isRequired + GROUP BY tl.ticketFk; + + INSERT INTO tmp.ticketProblems(ticketFk, isFreezed) + SELECT DISTINCT tl.ticketFk, 1 + FROM tmp.ticketList tl + JOIN vn.client c ON c.id = tl.clientFk + WHERE c.isFreezed + ON DUPLICATE KEY UPDATE + isFreezed = c.isFreezed; + + DROP TEMPORARY TABLE IF EXISTS tmp.clientGetDebt; + CREATE TEMPORARY TABLE tmp.clientGetDebt + (PRIMARY KEY (clientFk)) + ENGINE = MEMORY + SELECT DISTINCT clientFk + FROM tmp.ticketList; + + CALL clientGetDebt(CURDATE()); + + INSERT INTO tmp.ticketProblems(ticketFk, risk) + SELECT DISTINCT tl.ticketFk, r.risk + FROM tmp.ticketList tl + JOIN vn.ticket t ON t.id = tl.ticketFk + JOIN vn.agencyMode a ON t.agencyModeFk = a.id + JOIN tmp.risk r ON r.clientFk = t.clientFk + JOIN vn.client c ON c.id = t.clientFk + JOIN vn.clientConfig cc + WHERE r.risk - cc.riskTolerance > c.credit + 10 + AND a.isRiskFree = FALSE + ON DUPLICATE KEY UPDATE + risk = r.risk; + + INSERT INTO tmp.ticketProblems(ticketFk, hasTicketRequest) + SELECT DISTINCT tl.ticketFk, 1 + FROM tmp.ticketList tl + JOIN vn.ticketRequest tr ON tr.ticketFk = tl.ticketFk + WHERE tr.isOK IS NULL AND tr.saleFk IS NOT NULL + ON DUPLICATE KEY UPDATE + hasTicketRequest = 1; + + OPEN vCursor; + + WHILE NOT vDone + DO + FETCH vCursor INTO vWarehouse, vDate; + + CALL cache.available_refresh(vAvailableCache, FALSE, vWarehouse, vDate); + + INSERT INTO tmp.ticketProblems(ticketFk, isAvailable) + SELECT tl.ticketFk, 0 + FROM tmp.ticketList tl + JOIN vn.ticket t ON t.id = tl.ticketFk + JOIN vn.sale s ON s.ticketFk = t.id + JOIN vn.item i ON i.id = s.itemFk + JOIN vn.itemType it on it.id = i.typeFk + LEFT JOIN cache.available av ON av.item_id = i.id + AND av.calc_id = vAvailableCache + WHERE date(t.shipped) = vDate + AND it.categoryFk != 6 + AND IFNULL(av.available, 0) < 0 + AND s.isPicked = FALSE + AND NOT i.generic + AND vWarehouse = t.warehouseFk + GROUP BY tl.ticketFk + ON DUPLICATE KEY UPDATE + isAvailable = 0; +/* + INSERT INTO tmp.ticketProblems(ticketFk, itemShortage) + SELECT ticketFk, problem + FROM ( + SELECT tl.ticketFk, CONCAT('F: ',GROUP_CONCAT(i.id, ' ', i.longName, ' ')) problem + FROM tmp.ticketList tl + JOIN vn.ticket t ON t.id = tl.ticketFk + JOIN vn.sale s ON s.ticketFk = t.id + JOIN vn.item i ON i.id = s.itemFk + JOIN vn.itemType it on it.id = i.typeFk + LEFT JOIN vn.itemShelvingStock_byWarehouse issw ON issw.itemFk = i.id AND issw.warehouseFk = t.warehouseFk + LEFT JOIN cache.available av ON av.item_id = i.id AND av.calc_id = vAvailableCache + WHERE IFNULL(av.available, 0) < 0 + AND s.quantity > IFNULL(issw.visible, 0) + AND s.quantity > 0 + AND s.isPicked = FALSE + AND s.reserved = FALSE + AND it.categoryFk != 6 + AND IF(vIsTodayRelative, TRUE, date(t.shipped) = vDate) + AND NOT i.generic + AND CURDATE() = vDate + AND t.warehouseFk = vWarehouse + GROUP BY tl.ticketFk LIMIT 1) sub + ON DUPLICATE KEY UPDATE + itemShortage = sub.problem; +*/ + INSERT INTO tmp.ticketProblems(ticketFk, itemDelay) + SELECT ticketFk, problem + FROM ( + SELECT tl.ticketFk, GROUP_CONCAT('I: ',i.id, ' ', i.longName, ' ') problem + FROM tmp.ticketList tl + JOIN vn.ticket t ON t.id = tl.ticketFk + JOIN vn.sale s ON s.ticketFk = t.id + JOIN vn.item i ON i.id = s.itemFk + JOIN vn.itemType it on it.id = i.typeFk + LEFT JOIN vn.itemShelvingStock_byWarehouse issw ON issw.itemFk = i.id AND issw.warehouseFk = t.warehouseFk + WHERE s.quantity > IFNULL(issw.visible, 0) + AND s.quantity > 0 + AND s.isPicked = FALSE + AND s.reserved = FALSE + AND it.categoryFk != 6 + AND IF(vIsTodayRelative, TRUE, date(t.shipped) = vDate) + AND NOT i.generic + AND CURDATE() = vDate + AND t.warehouseFk = vWarehouse + GROUP BY tl.ticketFk LIMIT 1) sub + ON DUPLICATE KEY UPDATE + itemDelay = sub.problem; + END WHILE; + + CLOSE vCursor; + + INSERT INTO tmp.ticketProblems(ticketFk, isTaxDataChecked) + SELECT DISTINCT tl.ticketFk, FALSE + FROM tmp.ticketList tl + JOIN vn.client c ON c.id = tl.clientFk + WHERE c.isTaxDataChecked= FALSE + ON DUPLICATE KEY UPDATE + isTaxDataChecked = FALSE; + + DROP TEMPORARY TABLE + tmp.clientGetDebt, + tmp.ticketList; + +END;;$$ +DELIMITER ; diff --git a/db/changes/10320-monitors/00-ticket_getProblems.sql b/db/changes/10320-monitors/00-ticket_getProblems.sql new file mode 100644 index 000000000..290a083df --- /dev/null +++ b/db/changes/10320-monitors/00-ticket_getProblems.sql @@ -0,0 +1,36 @@ +DROP PROCEDURE IF EXISTS `vn`.`ticket_getProblems`; + +DELIMITER $$ +$$ +CREATE + DEFINER = root@`%` PROCEDURE `vn`.`ticket_getProblems`(IN vIsTodayRelative TINYINT(1)) +BEGIN +/** + * Calcula los problemas para un conjunto de tickets. + * Agrupados por ticket + * + * @table tmp.sale_getProblems(ticketFk, clientFk, warehouseFk, shipped) Identificadores de los tickets a calcular + * @return tmp.ticket_problems + */ + CALL sale_getProblems(vIsTodayRelative); + + DROP TEMPORARY TABLE IF EXISTS tmp.ticket_problems; + CREATE TEMPORARY TABLE tmp.ticket_problems + (INDEX (ticketFk)) + ENGINE = MEMORY + SELECT + ticketFk, + MAX(p.isFreezed) AS isFreezed, + MAX(p.risk) AS risk, + MAX(p.hasTicketRequest) AS hasTicketRequest, + MIN(p.isAvailable) AS isAvailable, + MAX(p.itemShortage) AS itemShortage, + MIN(p.isTaxDataChecked) AS isTaxDataChecked, + MAX(p.hasComponentLack) AS hasComponentLack + FROM tmp.sale_problems p + GROUP BY ticketFk; + + DROP TEMPORARY TABLE + tmp.sale_problems; +END;;$$ +DELIMITER ; diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js index b5bf46dd5..7b50935cc 100644 --- a/e2e/helpers/selectors.js +++ b/e2e/helpers/selectors.js @@ -565,18 +565,18 @@ export default { moreMenuUpdateDiscountInput: 'vn-input-number[ng-model="$ctrl.edit.discount"] input', transferQuantityInput: '.vn-popover.shown vn-table > div > vn-tbody > vn-tr > vn-td-editable > span > text', transferQuantityCell: '.vn-popover.shown vn-table > div > vn-tbody > vn-tr > vn-td-editable', - firstSaleId: 'vn-ticket-sale vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(4) > span', + firstSaleId: 'vn-ticket-sale vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(5) > span', firstSaleClaimIcon: 'vn-ticket-sale vn-table vn-tbody > vn-tr:nth-child(1) vn-icon[icon="icon-claims"]', firstSaleDescriptorImage: '.vn-popover.shown vn-item-descriptor img', firstSaleThumbnailImage: 'vn-ticket-sale:nth-child(1) vn-tr:nth-child(1) vn-td:nth-child(3) > img', 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)', - firstSalePrice: 'vn-ticket-sale vn-table vn-tr:nth-child(1) > vn-td:nth-child(7) > span', + firstSaleQuantityCell: 'vn-ticket-sale vn-tr:nth-child(1) > vn-td-editable:nth-child(6)', + firstSalePrice: 'vn-ticket-sale vn-table vn-tr:nth-child(1) > vn-td:nth-child(8) > span', firstSalePriceInput: '.vn-popover.shown input[ng-model="$ctrl.field"]', - firstSaleDiscount: 'vn-ticket-sale vn-table vn-tr:nth-child(1) > vn-td:nth-child(8) > span', + firstSaleDiscount: 'vn-ticket-sale vn-table vn-tr:nth-child(1) > vn-td:nth-child(9) > span', firstSaleDiscountInput: '.vn-popover.shown [ng-model="$ctrl.field"]', - firstSaleImport: 'vn-ticket-sale:nth-child(1) vn-td:nth-child(9)', + firstSaleImport: 'vn-ticket-sale:nth-child(1) vn-td:nth-child(10)', firstSaleReservedIcon: 'vn-ticket-sale vn-tr:nth-child(1) > vn-td:nth-child(2) > vn-icon:nth-child(3)', firstSaleColour: 'vn-ticket-sale vn-tr:nth-child(1) vn-fetched-tags section', firstSaleCheckbox: 'vn-ticket-sale vn-tr:nth-child(1) vn-check[ng-model="sale.checked"]', @@ -584,8 +584,8 @@ export default { secondSaleId: 'vn-ticket-sale:nth-child(2) vn-td-editable:nth-child(4) text > span', secondSaleIdAutocomplete: 'vn-ticket-sale vn-tr:nth-child(2) vn-autocomplete[ng-model="sale.itemFk"]', secondSaleQuantity: 'vn-ticket-sale vn-table vn-tr:nth-child(2) vn-input-number', - secondSaleQuantityCell: 'vn-ticket-sale > div > vn-card > vn-table > div > vn-tbody > vn-tr:nth-child(2) > vn-td-editable:nth-child(5)', - secondSaleConceptCell: 'vn-ticket-sale vn-tbody > :nth-child(2) > :nth-child(6)', + secondSaleQuantityCell: 'vn-ticket-sale > div > vn-card > vn-table > div > vn-tbody > vn-tr:nth-child(2) > vn-td-editable:nth-child(6)', + secondSaleConceptCell: 'vn-ticket-sale vn-tbody > :nth-child(2) > :nth-child(7)', secondSaleConceptInput: 'vn-ticket-sale vn-tbody > :nth-child(2) > vn-td-editable.ng-isolate-scope.selected vn-textfield', totalImport: 'vn-ticket-sale vn-one.taxes > p:nth-child(3) > strong', selectAllSalesCheckbox: 'vn-ticket-sale vn-thead vn-check', diff --git a/front/core/components/scroll-up/scroll-up.html b/front/core/components/scroll-up/scroll-up.html index a3748acc6..e686bb077 100644 --- a/front/core/components/scroll-up/scroll-up.html +++ b/front/core/components/scroll-up/scroll-up.html @@ -1,6 +1,6 @@ - - \ No newline at end of file + \ No newline at end of file diff --git a/front/core/components/scroll-up/style.scss b/front/core/components/scroll-up/style.scss index c6dae16ef..4b6fe70c1 100644 --- a/front/core/components/scroll-up/style.scss +++ b/front/core/components/scroll-up/style.scss @@ -1,10 +1,14 @@ @import "variables"; vn-scroll-up { - right: 0; + left: 50%; top: $topbar-height; - margin: $float-spacing; + margin: 0; display: none; position: fixed; - z-index: 10 + z-index: 10; + + vn-icon { + font-size: 60px + } } \ No newline at end of file diff --git a/modules/monitor/back/methods/sales-monitor/salesFilter.js b/modules/monitor/back/methods/sales-monitor/salesFilter.js index 726e5bfaf..ecbdc4895 100644 --- a/modules/monitor/back/methods/sales-monitor/salesFilter.js +++ b/modules/monitor/back/methods/sales-monitor/salesFilter.js @@ -247,10 +247,9 @@ module.exports = Self => { stmt.merge(conn.makeWhere(filter.where)); stmts.push(stmt); - stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.ticketGetProblems'); - + stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.sale_getProblems'); stmts.push(` - CREATE TEMPORARY TABLE tmp.ticketGetProblems + CREATE TEMPORARY TABLE tmp.sale_getProblems (INDEX (ticketFk)) ENGINE = MEMORY SELECT f.id ticketFk, f.clientFk, f.warehouseFk, f.shipped @@ -258,15 +257,12 @@ module.exports = Self => { LEFT JOIN alertLevel al ON al.alertLevel = f.alertLevel WHERE (al.code = 'FREE' OR f.alertLevel IS NULL) AND f.shipped >= CURDATE()`); - - stmts.push('CALL ticketGetProblems(FALSE)'); + stmts.push('CALL ticket_getProblems(FALSE)'); stmt = new ParameterizedSQL(` - SELECT - f.*, - tp.* + SELECT f.*, tp.* FROM tmp.filter f - LEFT JOIN tmp.ticketProblems tp ON tp.ticketFk = f.id`); + LEFT JOIN tmp.ticket_problems tp ON tp.ticketFk = f.id`); if (args.problems != undefined && (!args.from && !args.to)) throw new UserError('Choose a date range or days forward'); @@ -309,7 +305,7 @@ module.exports = Self => { `DROP TEMPORARY TABLE tmp.filter, tmp.ticket, - tmp.ticketGetProblems`); + tmp.ticket_problems`); let sql = ParameterizedSQL.join(stmts, ';'); let result = await conn.executeStmt(sql); diff --git a/modules/monitor/back/methods/sales-monitor/specs/salesFilter.spec.js b/modules/monitor/back/methods/sales-monitor/specs/salesFilter.spec.js index 0666544e7..54615b22b 100644 --- a/modules/monitor/back/methods/sales-monitor/specs/salesFilter.spec.js +++ b/modules/monitor/back/methods/sales-monitor/specs/salesFilter.spec.js @@ -23,7 +23,7 @@ describe('SalesMonitor salesFilter()', () => { const filter = {}; const result = await app.models.SalesMonitor.salesFilter(ctx, filter); - expect(result.length).toEqual(3); + expect(result.length).toEqual(4); }); it('should return the tickets matching the problems on false', async() => { diff --git a/modules/monitor/front/index/locale/es.yml b/modules/monitor/front/index/locale/es.yml index 1f69de222..cb94d41a7 100644 --- a/modules/monitor/front/index/locale/es.yml +++ b/modules/monitor/front/index/locale/es.yml @@ -3,4 +3,5 @@ Clients on website: Clientes activos en la web Recent order actions: Acciones recientes en pedidos Search tickets: Buscar tickets Delete selected elements: Eliminar los elementos seleccionados -All the selected elements will be deleted. Are you sure you want to continue?: Todos los elementos seleccionados serán eliminados. ¿Seguro que quieres continuar? \ No newline at end of file +All the selected elements will be deleted. Are you sure you want to continue?: Todos los elementos seleccionados serán eliminados. ¿Seguro que quieres continuar? +Component lack: Faltan componentes \ No newline at end of file diff --git a/modules/monitor/front/index/tickets/index.html b/modules/monitor/front/index/tickets/index.html index e410be4e5..dffc1ee8d 100644 --- a/modules/monitor/front/index/tickets/index.html +++ b/modules/monitor/front/index/tickets/index.html @@ -30,7 +30,7 @@ - + @@ -67,7 +67,6 @@ ng-show="::ticket.isAvailable === 0" translate-attr="{title: 'Not available'}" class="bright" - vn-tooltip="Not available" icon="icon-unavailable"> + + {{::ticket.packages}} - {{::ticket.volume | number:1}} + {{::ticket.volume | number:2}} { it('should update the given sales of a ticket to reserved', async() => { originalTicketSales = await app.models.Ticket.getSales(11); - expect(originalTicketSales[0].reserved).toEqual(0); - expect(originalTicketSales[1].reserved).toEqual(0); + expect(originalTicketSales[0].reserved).toEqual(false); + expect(originalTicketSales[1].reserved).toEqual(false); const ticketId = 11; const sales = [{id: 7}, {id: 8}]; @@ -46,7 +46,7 @@ describe('sale reserve()', () => { const reservedTicketSales = await app.models.Ticket.getSales(ticketId); - expect(reservedTicketSales[0].reserved).toEqual(1); - expect(reservedTicketSales[1].reserved).toEqual(1); + expect(reservedTicketSales[0].reserved).toEqual(true); + expect(reservedTicketSales[1].reserved).toEqual(true); }); }); diff --git a/modules/ticket/back/methods/ticket/filter.js b/modules/ticket/back/methods/ticket/filter.js index 5298700f2..6826f55ec 100644 --- a/modules/ticket/back/methods/ticket/filter.js +++ b/modules/ticket/back/methods/ticket/filter.js @@ -247,10 +247,9 @@ module.exports = Self => { stmt.merge(conn.makeWhere(filter.where)); stmts.push(stmt); - stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.ticketGetProblems'); - + stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.sale_getProblems'); stmts.push(` - CREATE TEMPORARY TABLE tmp.ticketGetProblems + CREATE TEMPORARY TABLE tmp.sale_getProblems (INDEX (ticketFk)) ENGINE = MEMORY SELECT f.id ticketFk, f.clientFk, f.warehouseFk, f.shipped @@ -258,15 +257,12 @@ module.exports = Self => { LEFT JOIN alertLevel al ON al.alertLevel = f.alertLevel WHERE (al.code = 'FREE' OR f.alertLevel IS NULL) AND f.shipped >= CURDATE()`); - - stmts.push('CALL ticketGetProblems(FALSE)'); + stmts.push('CALL ticket_getProblems(FALSE)'); stmt = new ParameterizedSQL(` - SELECT - f.*, - tp.* + SELECT f.*, tp.* FROM tmp.filter f - LEFT JOIN tmp.ticketProblems tp ON tp.ticketFk = f.id`); + LEFT JOIN tmp.ticket_problems tp ON tp.ticketFk = f.id`); if (args.problems != undefined && (!args.from && !args.to)) throw new UserError('Choose a date range or days forward'); @@ -309,7 +305,7 @@ module.exports = Self => { `DROP TEMPORARY TABLE tmp.filter, tmp.ticket, - tmp.ticketGetProblems`); + tmp.ticket_problems`); let sql = ParameterizedSQL.join(stmts, ';'); let result = await conn.executeStmt(sql); diff --git a/modules/ticket/back/methods/ticket/getSales.js b/modules/ticket/back/methods/ticket/getSales.js index d522ffe98..7520e7270 100644 --- a/modules/ticket/back/methods/ticket/getSales.js +++ b/modules/ticket/back/methods/ticket/getSales.js @@ -1,12 +1,13 @@ + module.exports = Self => { Self.remoteMethod('getSales', { description: 'New filter', accessType: 'READ', accepts: [{ - arg: 'ticketFk', + arg: 'id', type: 'number', required: true, - description: 'ticket id', + description: 'The ticket id', http: {source: 'path'} }], returns: { @@ -14,60 +15,83 @@ module.exports = Self => { root: true }, http: { - path: `/:ticketFk/getSales`, + path: `/:id/getSales`, verb: 'get' } }); - Self.getSales = async ticketFk => { - let query = `CALL vn.ticketGetVisibleAvailable(?)`; - let [lines] = await Self.rawSql(query, [ticketFk]); - let ids = []; - let salesIds = []; + Self.getSales = async(id, options) => { + const models = Self.app.models; - for (line of lines) { - ids.push(line.itemFk); - salesIds.push(line.id); - } + let myOptions = {}; - let filter = { - fields: [ - 'id', - 'name', - 'tag5', - 'value5', - 'tag6', - 'value6', - 'tag7', - 'value7', - 'tag8', - 'value8', - 'tag9', - 'value9', - 'tag10', - 'value10'], - where: {id: {inq: ids}} - }; - let items = await Self.app.models.Item.find(filter); + if (typeof options == 'object') + Object.assign(myOptions, options); - filter = { + const sales = await models.Sale.find({ + include: { + relation: 'item', + scope: { + fields: [ + 'id', + 'name', + 'tag5', + 'value5', + 'tag6', + 'value6', + 'tag7', + 'value7', + 'tag8', + 'value8', + 'tag9', + 'value9', + 'tag10', + 'value10' + ] + } + }, + where: {ticketFk: id}, + order: 'concept' + }, myOptions); + + // Get items available + const query = `CALL ticketGetVisibleAvailable(?)`; + const [salesAvailable] = await Self.rawSql(query, [id], myOptions); + + const itemAvailable = new Map(); + for (let sale of salesAvailable) + itemAvailable.set(sale.itemFk, sale.available); + + // Get claimed sales + const saleIds = sales.map(sale => sale.id); + const claims = await models.ClaimBeginning.find({ fields: ['claimFk', 'saleFk'], - where: {saleFk: {inq: salesIds}}, - }; - let claims = await Self.app.models.ClaimBeginning.find(filter); + where: {saleFk: {inq: saleIds}}, + }, myOptions); - let map = {}; - for (item of items) - map[item.id] = item; + const claimedSales = new Map(); + for (let claim of claims) + claimedSales.set(claim.saleFk, claim); - let claimMap = {}; - for (claim of claims) - claimMap[claim.saleFk] = claim; + // Get problems + const problemsQuery = `CALL sale_getProblemsByTicket(?, FALSE)`; + const [problems] = await Self.rawSql(problemsQuery, [id], myOptions); - for (line of lines) { - line.item = map[line.itemFk]; - line.claim = claimMap[line.id]; + const saleProblems = new Map(); + for (let problem of problems) + saleProblems.set(problem.saleFk, problem); + + for (let sale of sales) { + const problems = saleProblems.get(sale.id); + sale.available = itemAvailable.get(sale.itemFk); + sale.claim = claimedSales.get(sale.id); + if (problems) { + sale.isAvailable = problems.isAvailable; + sale.hasTicketRequest = problems.hasTicketRequest; + sale.hasComponentLack = problems.hasComponentLack; + } } - return lines; + + return sales; }; }; diff --git a/modules/ticket/back/methods/ticket/specs/filter.spec.js b/modules/ticket/back/methods/ticket/specs/filter.spec.js index 0f4a1660e..c742de41d 100644 --- a/modules/ticket/back/methods/ticket/specs/filter.spec.js +++ b/modules/ticket/back/methods/ticket/specs/filter.spec.js @@ -23,7 +23,7 @@ describe('ticket filter()', () => { const filter = {}; const result = await app.models.Ticket.filter(ctx, filter); - expect(result.length).toEqual(3); + expect(result.length).toEqual(4); }); it('should return the tickets matching the problems on false', async() => { diff --git a/modules/ticket/front/index/index.html b/modules/ticket/front/index/index.html index 915e16a11..b86aaba9d 100644 --- a/modules/ticket/front/index/index.html +++ b/modules/ticket/front/index/index.html @@ -55,7 +55,6 @@ ng-show="::ticket.isAvailable === 0" translate-attr="{title: 'Not available'}" class="bright" - vn-tooltip="Not available" icon="icon-unavailable"> + + {{::ticket.id}} diff --git a/modules/ticket/front/index/locale/es.yml b/modules/ticket/front/index/locale/es.yml index 1545c5e53..9ff8d1568 100644 --- a/modules/ticket/front/index/locale/es.yml +++ b/modules/ticket/front/index/locale/es.yml @@ -10,4 +10,5 @@ Exclude selection: Excluir selección Remove filter: Quitar filtro por selección Remove all filters: Eliminar todos los filtros Copy value: Copiar valor -No verified data: Sin datos comprobados \ No newline at end of file +No verified data: Sin datos comprobados +Component lack: Faltan componentes \ No newline at end of file diff --git a/modules/ticket/front/sale/index.html b/modules/ticket/front/sale/index.html index 5156206bb..0a5c8e841 100644 --- a/modules/ticket/front/sale/index.html +++ b/modules/ticket/front/sale/index.html @@ -59,6 +59,7 @@ + Available Id Quantity Item @@ -82,14 +83,26 @@ + vn-tooltip="Visible: {{::sale.visible || 0}}"> + translate-attr="{title: 'Reserved'}"> + + + + @@ -98,6 +111,13 @@ zoom-image="{{::$root.imagePath('catalog', '1600x900', sale.itemFk)}}" on-error-src/> + + + {{::sale.available}} + + diff --git a/modules/ticket/front/summary/index.html b/modules/ticket/front/summary/index.html index b2c322633..a2a17fb11 100644 --- a/modules/ticket/front/summary/index.html +++ b/modules/ticket/front/summary/index.html @@ -138,7 +138,28 @@ vn-tooltip="{{::$ctrl.$t('Claim')}}: {{::sale.claimBeginning.claimFk}}"> - + + + + + + + + - {{::sale.available}} + + {{::sale.available}} {{::sale.quantity}} @@ -218,7 +242,11 @@ {{::service.quantity}} {{::service.description}} {{::service.price | currency: 'EUR':2}} - {{::service.taxClass.description}} + + + {{::service.taxClass.description}} + + {{::service.quantity * service.price | currency: 'EUR':2}}