2891 - Get ticket problems for every sale #629

Merged
carlosjr merged 7 commits from 2891-ticket_sale_problems into dev 2021-05-27 09:49:44 +00:00
12 changed files with 240 additions and 64 deletions
Showing only changes of commit 920e7b1daf - Show all commits

View File

@ -5,6 +5,13 @@ $$
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;
@ -140,7 +147,7 @@ BEGIN
AND NOT i.generic
AND CURDATE() = vDate
AND t.warehouseFk = vWarehouse
GROUP BY tl.ticketFk) sub
GROUP BY tl.ticketFk LIMIT 1) sub
ON DUPLICATE KEY UPDATE
itemShortage = sub.problem, saleFk = sub.saleFk;
@ -163,7 +170,7 @@ BEGIN
AND NOT i.generic
AND CURDATE() = vDate
AND t.warehouseFk = vWarehouse
GROUP BY tl.ticketFk) sub
GROUP BY tl.ticketFk LIMIT 1) sub
ON DUPLICATE KEY UPDATE
itemDelay = sub.problem, saleFk = sub.saleFk;
END WHILE;

View File

@ -5,6 +5,12 @@ $$
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))

View File

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

View File

@ -5,6 +5,13 @@ $$
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;

View File

@ -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',

View File

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

View File

@ -4,3 +4,4 @@ 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?
Component lack: Faltan componentes

View File

@ -67,7 +67,6 @@
ng-show="::ticket.isAvailable === 0"
translate-attr="{title: 'Not available'}"
class="bright"
vn-tooltip="Not available"
icon="icon-unavailable">
</vn-icon>
<vn-icon
@ -86,7 +85,6 @@
ng-show="::ticket.hasComponentLack"
translate-attr="{title: 'Component lack'}"
class="bright"
vn-tooltip="Component lack"
icon="icon-components">
</vn-icon>
</vn-td>

View File

@ -35,8 +35,8 @@ describe('sale reserve()', () => {
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);
});
});

View File

@ -20,9 +20,14 @@ module.exports = Self => {
}
});
Self.getSales = async id => {
// implementar transacciones
Self.getSales = async(id, options) => {
const models = Self.app.models;
let myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const sales = await models.Sale.find({
include: {
relation: 'item',
@ -45,12 +50,13 @@ module.exports = Self => {
]
}
},
where: {ticketFk: id}
});
where: {ticketFk: id},
order: 'concept'
}, myOptions);
// Get items available
const query = `CALL ticketGetVisibleAvailable(?)`;
const [salesAvailable] = await Self.rawSql(query, [id]);
const [salesAvailable] = await Self.rawSql(query, [id], myOptions);
const itemAvailable = new Map();
for (let sale of salesAvailable)
@ -61,7 +67,7 @@ module.exports = Self => {
const claims = await models.ClaimBeginning.find({
fields: ['claimFk', 'saleFk'],
where: {saleFk: {inq: saleIds}},
});
}, myOptions);
const claimedSales = new Map();
for (let claim of claims)
@ -69,14 +75,12 @@ module.exports = Self => {
// Get problems
const problemsQuery = `CALL sale_getProblemsByTicket(?, FALSE)`;
const [problems] = await Self.rawSql(problemsQuery, [id]);
const [problems] = await Self.rawSql(problemsQuery, [id], myOptions);
const saleProblems = new Map();
for (let problem of problems)
saleProblems.set(problem.saleFk, problem);
console.log(problems);
for (let sale of sales) {
const problems = saleProblems.get(sale.id);
sale.available = itemAvailable.get(sale.itemFk);
@ -89,41 +93,5 @@ module.exports = Self => {
}
return sales;
/* let query = `CALL vn.ticketGetVisibleAvailable(?)`;
let [lines] = await Self.rawSql(query, [ticketFk]);
let ids = [];
let salesIds = [];
for (line of lines) {
ids.push(line.itemFk);
salesIds.push(line.id);
}
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);
filter = {
fields: ['claimFk', 'saleFk'],
where: {saleFk: {inq: salesIds}},
};
let claims = await Self.app.models.ClaimBeginning.find(filter);
let map = {};
for (item of items)
map[item.id] = item;
let claimMap = {};
for (claim of claims)
claimMap[claim.saleFk] = claim;
for (line of lines) {
line.item = map[line.itemFk];
line.claim = claimMap[line.id];
}
return lines; */
};
};

View File

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

View File

@ -11,3 +11,4 @@ Remove filter: Quitar filtro por selección
Remove all filters: Eliminar todos los filtros
Copy value: Copiar valor
No verified data: Sin datos comprobados
Component lack: Faltan componentes