Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into 3092-module_transactions
gitea/salix/pipeline/head This commit looks good Details

This commit is contained in:
Carlos Jimenez Ruiz 2021-10-15 14:47:34 +02:00
commit 05df98939b
15 changed files with 194 additions and 69 deletions

View File

@ -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 ;

View File

@ -1,9 +1,10 @@
<div ng-if="$ctrl.model.moreRows">
<vn-button
<div ng-if="$ctrl.model.moreRows" class="vn-py-md">
<div
ng-if="!$ctrl.model.isPaging"
label="Load more results"
ng-click="$ctrl.onLoadClick()">
</vn-button>
<vn-button label="Load more results"></vn-button>
<vn-icon icon="arrow_drop_down"/>
</div>
<vn-spinner
ng-if="$ctrl.model.isPaging"
enable="::true">

View File

@ -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;

View File

@ -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);

View File

@ -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() => {

View File

@ -70,7 +70,7 @@
<vn-autocomplete vn-one
data="$ctrl.groupedStates"
label="Grouped States"
value-field="alertLevel"
value-field="id"
show-field="name"
ng-model="filter.alertLevel">
<tpl-item>

View File

@ -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)
});

View File

@ -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'
}]);

View File

@ -50,7 +50,7 @@
<a ng-repeat="ticket in model.data"
class="clickable vn-tr search-result"
ui-sref="ticket.card.summary({id: {{::ticket.id}}})" target="_blank">
<vn-td class="icon-field">
<vn-td expand>
<vn-icon
ng-show="::ticket.isTaxDataChecked === 0"
translate-attr="{title: 'No verified data'}"

View File

@ -119,7 +119,7 @@ module.exports = Self => {
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];
};
};

View File

@ -17,7 +17,7 @@
<vn-th field="landed" shrink-date>Landed</vn-th>
<vn-th field="created" center>Hour</vn-th>
<vn-th field="agencyName" center>Agency</vn-th>
<vn-th center>Total</vn-th>
<vn-th field="total" center>Total</vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>

View File

@ -89,7 +89,7 @@
<vn-autocomplete vn-one
data="$ctrl.groupedStates"
label="Grouped States"
value-field="alertLevel"
value-field="id"
show-field="name"
ng-model="filter.alertLevel">
<tpl-item>

View File

@ -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)
});

View File

@ -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'
}]);