diff --git a/db/changes/10370-pickles/00-ticket_getProblems.sql b/db/changes/10370-pickles/00-ticket_getProblems.sql new file mode 100644 index 000000000..2ee057cd2 --- /dev/null +++ b/db/changes/10370-pickles/00-ticket_getProblems.sql @@ -0,0 +1,48 @@ +drop procedure `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 + (PRIMARY KEY (ticketFk)) + ENGINE = MEMORY + SELECT + ticketFk, + MAX(p.isFreezed) AS isFreezed, + MAX(p.risk) AS risk, + MAX(p.hasHighRisk) AS hasHighRisk, + 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, + 0 AS totalProblems + FROM tmp.sale_problems p + GROUP BY ticketFk; + + UPDATE tmp.ticket_problems tp + SET tp.totalProblems = ( + (tp.isFreezed) + + IF(tp.risk, TRUE, FALSE) + + (tp.hasTicketRequest) + + (tp.isAvailable = 0) + + (tp.isTaxDataChecked = 0) + + (tp.hasComponentLack) + ); + + DROP TEMPORARY TABLE + tmp.sale_problems; +END;;$$ +DELIMITER ; \ No newline at end of file diff --git a/db/changes/10370-pickles/delete.keep b/db/changes/10370-pickles/delete.keep deleted file mode 100644 index e69de29bb..000000000 diff --git a/front/core/components/pagination/pagination.html b/front/core/components/pagination/pagination.html index 6809018dd..72d7c31ff 100644 --- a/front/core/components/pagination/pagination.html +++ b/front/core/components/pagination/pagination.html @@ -1,9 +1,10 @@ -
- +
- + + +
diff --git a/front/core/components/pagination/style.scss b/front/core/components/pagination/style.scss index 413a6fb5f..02dcb43e4 100644 --- a/front/core/components/pagination/style.scss +++ b/front/core/components/pagination/style.scss @@ -1,7 +1,13 @@ +@import "variables"; vn-pagination { display: block; text-align: center; + color: $color-primary; + + vn-button, vn-icon { + display: block + } & > div > vn-icon-button { font-size: 2rem; diff --git a/modules/monitor/back/methods/sales-monitor/salesFilter.js b/modules/monitor/back/methods/sales-monitor/salesFilter.js index b598d79b1..5627975d8 100644 --- a/modules/monitor/back/methods/sales-monitor/salesFilter.js +++ b/modules/monitor/back/methods/sales-monitor/salesFilter.js @@ -129,54 +129,20 @@ module.exports = Self => { const where = buildFilter(ctx.args, (param, value) => { switch (param) { - case 'search': - return /^\d+$/.test(value) - ? {'t.id': {inq: value}} - : {'t.nickname': {like: `%${value}%`}}; case 'from': return {'t.shipped': {gte: value}}; case 'to': return {'t.shipped': {lte: value}}; - case 'nickname': - return {'t.nickname': {like: `%${value}%`}}; - case 'refFk': - return {'t.refFk': value}; case 'salesPersonFk': return {'c.salesPersonFk': value}; - case 'provinceFk': - return {'a.provinceFk': value}; - case 'stateFk': - return {'ts.stateFk': value}; case 'mine': case 'myTeam': if (value) return {'c.salesPersonFk': {inq: teamMembersId}}; else return {'c.salesPersonFk': {nin: teamMembersId}}; - - case 'alertLevel': - return {'ts.alertLevel': value}; - case 'pending': - if (value) { - return {and: [ - {'st.alertLevel': 0}, - {'st.code': {nin: [ - 'OK', - 'BOARDING', - 'PRINTED', - 'PRINTED_AUTO', - 'PICKER_DESIGNED' - ]}} - ]}; - } else { - return {and: [ - {'st.alertLevel': {gt: 0}} - ]}; - } case 'id': case 'clientFk': - case 'agencyModeFk': - case 'warehouseFk': param = `t.${param}`; return {[param]: value}; } @@ -216,6 +182,7 @@ module.exports = Self => { ts.code AS alertLevelCode, u.name AS userName, c.salesPersonFk, + c.credit, z.hour AS zoneLanding, z.name AS zoneName, z.id AS zoneFk, @@ -246,6 +213,47 @@ module.exports = Self => { stmt.merge(conn.makeWhere(filter.where)); stmts.push(stmt); + // Get client debt balance + stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.clientGetDebt'); + stmts.push(` + CREATE TEMPORARY TABLE tmp.clientGetDebt + (INDEX (clientFk)) + ENGINE = MEMORY + SELECT DISTINCT clientFk FROM tmp.filter`); + + stmt = new ParameterizedSQL('CALL clientGetDebt(?)', [args.to]); + stmts.push(stmt); + stmts.push('DROP TEMPORARY TABLE tmp.clientGetDebt'); + + stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.tickets'); + stmt = new ParameterizedSQL(` + CREATE TEMPORARY TABLE tmp.tickets + (INDEX (id)) + ENGINE = MEMORY + SELECT f.*, r.risk AS debt + FROM tmp.filter f + LEFT JOIN tmp.risk r ON f.clientFk = r.clientFk`); + stmts.push(stmt); + + // Sum risk to future + stmts.push(`SET @client:= 0`); + stmts.push('SET @risk := 0'); + stmts.push(` + UPDATE tmp.tickets + SET debt = IF(@client <> @client:= clientFk, + -totalWithVat + @risk:= - debt + totalWithVat, + -totalWithVat + @risk:= @risk + totalWithVat + ) + ORDER BY clientFk, shipped DESC + `); + + // Remove positive risks + stmts.push(` + UPDATE tmp.tickets t + SET debt = 0 + WHERE t.debt + t.credit >= 0 + `); + stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.sale_getProblems'); stmts.push(` CREATE TEMPORARY TABLE tmp.sale_getProblems @@ -258,27 +266,39 @@ module.exports = Self => { AND f.shipped >= CURDATE()`); stmts.push('CALL ticket_getProblems(FALSE)'); + stmts.push(` + INSERT INTO tmp.ticket_problems (ticketFk, risk, totalProblems) + SELECT t.id, t.debt + t.credit AS risk, 1 + FROM tmp.tickets t + WHERE (t.debt + t.credit) < 0 + ON DUPLICATE KEY UPDATE + risk = t.debt + t.credit, totalProblems = totalProblems + 1 + `); + stmt = new ParameterizedSQL(` - SELECT f.*, tp.* - FROM tmp.filter f - LEFT JOIN tmp.ticket_problems tp ON tp.ticketFk = f.id`); + SELECT t.*, tp.*, + ((tp.risk) + cc.riskTolerance < 0) AS hasHighRisk + FROM tmp.tickets t + LEFT JOIN tmp.ticket_problems tp ON tp.ticketFk = t.id + JOIN clientConfig cc`); const hasProblems = args.problems; if (hasProblems != undefined && (!args.from && !args.to)) throw new UserError('Choose a date range or days forward'); - let problemsFilter; + let finalFilter = {}; + let whereProblems; if (hasProblems === true) { - problemsFilter = {or: [ + whereProblems = {or: [ {'tp.isFreezed': true}, - {'tp.risk': {gt: 0}}, + {'tp.risk': {lt: 0}}, {'tp.hasTicketRequest': true}, {'tp.hasComponentLack': true}, {'tp.isTaxDataChecked': false}, {'tp.isAvailable': false} ]}; } else if (hasProblems === false) { - problemsFilter = {and: [ + whereProblems = {and: [ {'tp.isFreezed': false}, {'tp.risk': 0}, {'tp.hasTicketRequest': false}, @@ -288,8 +308,53 @@ module.exports = Self => { ]}; } - if (problemsFilter) - stmt.merge(conn.makeWhere(problemsFilter)); + if (whereProblems) finalFilter.where = whereProblems; + + const myWhere = buildFilter(ctx.args, (param, value) => { + switch (param) { + case 'search': + return /^\d+$/.test(value) + ? {'t.id': {inq: value}} + : {'t.nickname': {like: `%${value}%`}}; + + case 'nickname': + return {'t.nickname': {like: `%${value}%`}}; + case 'refFk': + return {'t.refFk': value}; + + case 'provinceFk': + return {'t.provinceFk': value}; + case 'stateFk': + return {'t.stateFk': value}; + case 'alertLevel': + return {'t.alertLevel': value}; + case 'pending': + if (value) { + return {and: [ + {'t.alertLevel': 0}, + {'t.alertLevelCode': {nin: [ + 'OK', + 'BOARDING', + 'PRINTED', + 'PRINTED_AUTO', + 'PICKER_DESIGNED' + ]}} + ]}; + } else { + return {and: [ + {'t.alertLevel': {gt: 0}} + ]}; + } + case 'agencyModeFk': + case 'warehouseFk': + param = `t.${param}`; + return {[param]: value}; + } + }); + + finalFilter = mergeFilters(finalFilter, {where: myWhere}); + if (finalFilter.where) + stmt.merge(conn.makeWhere(finalFilter.where)); stmt.merge(conn.makeOrderBy(filter.order)); stmt.merge(conn.makeLimit(filter)); @@ -298,7 +363,9 @@ module.exports = Self => { stmts.push( `DROP TEMPORARY TABLE tmp.filter, - tmp.ticket_problems`); + tmp.ticket_problems, + tmp.sale_getProblems, + tmp.risk`); 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 ceea82ca8..28e2b5571 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 models.SalesMonitor.salesFilter(ctx, filter); - expect(result.length).toEqual(9); + expect(result.length).toEqual(13); }); it('should now return the tickets matching the problems on false', async() => { diff --git a/modules/monitor/front/index/search-panel/index.html b/modules/monitor/front/index/search-panel/index.html index dc24c778b..5458202d2 100644 --- a/modules/monitor/front/index/search-panel/index.html +++ b/modules/monitor/front/index/search-panel/index.html @@ -70,7 +70,7 @@ diff --git a/modules/monitor/front/index/search-panel/index.js b/modules/monitor/front/index/search-panel/index.js index 057d555e4..ef6625e8a 100644 --- a/modules/monitor/front/index/search-panel/index.js +++ b/modules/monitor/front/index/search-panel/index.js @@ -14,7 +14,7 @@ class Controller extends SearchPanel { this.$http.get('AlertLevels').then(res => { for (let state of res.data) { groupedStates.push({ - alertLevel: state.alertLevel, + id: state.id, code: state.code, name: this.$t(state.code) }); diff --git a/modules/monitor/front/index/search-panel/index.spec.js b/modules/monitor/front/index/search-panel/index.spec.js index 0d19fd35f..f862e8d77 100644 --- a/modules/monitor/front/index/search-panel/index.spec.js +++ b/modules/monitor/front/index/search-panel/index.spec.js @@ -18,7 +18,7 @@ describe('Monitor Component vnMonitorSalesSearchPanel', () => { jest.spyOn(controller, '$t').mockReturnValue('miCodigo'); const data = [ { - alertLevel: 9999, + id: 9999, code: 'myCode' } ]; @@ -27,7 +27,7 @@ describe('Monitor Component vnMonitorSalesSearchPanel', () => { $httpBackend.flush(); expect(controller.groupedStates).toEqual([{ - alertLevel: 9999, + id: 9999, code: 'myCode', name: 'miCodigo' }]); diff --git a/modules/monitor/front/index/tickets/index.html b/modules/monitor/front/index/tickets/index.html index 690e0cdb0..4a166d51a 100644 --- a/modules/monitor/front/index/tickets/index.html +++ b/modules/monitor/front/index/tickets/index.html @@ -50,7 +50,7 @@ - + { case 'sourceApp': return {'o.source_app': value}; case 'ticketFk': - return {'ort.ticketFk': value}; + return {'ot.ticketFk': value}; case 'isConfirmed': return {'o.confirmed': value ? 1 : 0}; case 'myTeam': @@ -137,7 +137,10 @@ module.exports = Self => { let stmt; stmt = new ParameterizedSQL( - `SELECT + `CREATE TEMPORARY TABLE tmp.filter + (INDEX (id)) + ENGINE = MEMORY + SELECT o.id, o.total, o.date_send landed, @@ -168,20 +171,20 @@ module.exports = Self => { LEFT JOIN ticket t ON t.id = ot.ticketFk LEFT JOIN zoneEstimatedDelivery zed ON zed.zoneFk = t.zoneFk`); - if (args && args.ticketFk) { - stmt.merge({ - sql: `LEFT JOIN orderTicket ort ON ort.orderFk = o.id` - }); - } - stmt.merge(conn.makeWhere(filter.where)); - stmt.merge(`GROUP BY o.id`); stmt.merge(conn.makePagination(filter)); stmts.push(stmt); + stmt = new ParameterizedSQL(`SELECT * FROM tmp.filter`); + stmt.merge(`GROUP BY id`); + stmt.merge(conn.makeOrderBy(filter.order)); + const ordersIndex = stmts.push(stmt) - 1; + + stmts.push(`DROP TEMPORARY TABLE tmp.filter`); + const sql = ParameterizedSQL.join(stmts, ';'); const result = await conn.executeStmt(sql); - return result; + return result[ordersIndex]; }; }; diff --git a/modules/order/front/index/index.html b/modules/order/front/index/index.html index 288e81226..a2a4a5226 100644 --- a/modules/order/front/index/index.html +++ b/modules/order/front/index/index.html @@ -17,7 +17,7 @@ Landed Hour Agency - Total + Total diff --git a/modules/ticket/front/search-panel/index.html b/modules/ticket/front/search-panel/index.html index 79dfabb58..445729952 100644 --- a/modules/ticket/front/search-panel/index.html +++ b/modules/ticket/front/search-panel/index.html @@ -89,7 +89,7 @@ diff --git a/modules/ticket/front/search-panel/index.js b/modules/ticket/front/search-panel/index.js index 6ef47757a..ed86921e0 100644 --- a/modules/ticket/front/search-panel/index.js +++ b/modules/ticket/front/search-panel/index.js @@ -14,7 +14,7 @@ class Controller extends SearchPanel { this.$http.get('AlertLevels').then(res => { for (let state of res.data) { groupedStates.push({ - alertLevel: state.alertLevel, + id: state.id, code: state.code, name: this.$t(state.code) }); diff --git a/modules/ticket/front/search-panel/index.spec.js b/modules/ticket/front/search-panel/index.spec.js index f3a2f39ed..41c32c047 100644 --- a/modules/ticket/front/search-panel/index.spec.js +++ b/modules/ticket/front/search-panel/index.spec.js @@ -18,7 +18,7 @@ describe('Ticket Component vnTicketSearchPanel', () => { jest.spyOn(controller, '$t').mockReturnValue('miCodigo'); const data = [ { - alertLevel: 9999, + id: 9999, code: 'myCode' } ]; @@ -27,7 +27,7 @@ describe('Ticket Component vnTicketSearchPanel', () => { $httpBackend.flush(); expect(controller.groupedStates).toEqual([{ - alertLevel: 9999, + id: 9999, code: 'myCode', name: 'miCodigo' }]);