fixes #4962 Refactor Ticket Tour a Futuro #1212

Merged
alexandre merged 9 commits from 4700-split-tour into dev 2022-12-20 14:17:41 +00:00
25 changed files with 346 additions and 498 deletions

View File

@ -0,0 +1,73 @@
DROP PROCEDURE IF EXISTS `vn`.`ticket_canbePostponed`;
DELIMITER $$
$$
CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticket_canbePostponed`(vOriginDated DATE, vFutureDated DATE, vWarehouseFk INT)
BEGIN
/**
* Devuelve un listado de tickets susceptibles de fusionarse con otros tickets en el futuro
*
* @param vOriginDated Fecha en cuestión
* @param vFutureDated Fecha en el futuro a sondear
* @param vWarehouseFk Identificador de vn.warehouse
*/
DROP TEMPORARY TABLE IF EXISTS tmp.filter;
CREATE TEMPORARY TABLE tmp.filter
(INDEX (id))
SELECT sv.ticketFk id,
sub2.id futureId,
GROUP_CONCAT(DISTINCT i.itemPackingTypeFk ORDER BY i.itemPackingTypeFk) ipt,
CAST(sum(litros) AS DECIMAL(10,0)) liters,
CAST(count(*) AS DECIMAL(10,0)) `lines`,
st.name state,
sub2.iptd futureIpt,
sub2.state futureState,
t.clientFk,
t.warehouseFk,
ts.alertLevel,
t.shipped,
sub2.shipped futureShipped,
t.workerFk,
st.code stateCode,
sub2.code futureStateCode
FROM vn.saleVolume sv
JOIN vn.sale s ON s.id = sv.saleFk
JOIN vn.item i ON i.id = s.itemFk
JOIN vn.ticket t ON t.id = sv.ticketFk
JOIN vn.address a ON a.id = t.addressFk
JOIN vn.province p ON p.id = a.provinceFk
JOIN vn.country c ON c.id = p.countryFk
JOIN vn.ticketState ts ON ts.ticketFk = t.id
JOIN vn.state st ON st.id = ts.stateFk
JOIN vn.alertLevel al ON al.id = ts.alertLevel
LEFT JOIN vn.ticketParking tp ON tp.ticketFk = t.id
LEFT JOIN (
SELECT *
FROM (
SELECT
t.addressFk,
t.id,
t.shipped,
st.name state,
st.code code,
GROUP_CONCAT(DISTINCT i.itemPackingTypeFk ORDER BY i.itemPackingTypeFk) iptd
FROM vn.ticket t
JOIN vn.ticketState ts ON ts.ticketFk = t.id
JOIN vn.state st ON st.id = ts.stateFk
JOIN vn.sale s ON s.ticketFk = t.id
JOIN vn.item i ON i.id = s.itemFk
WHERE t.shipped BETWEEN vFutureDated
AND util.dayend(vFutureDated)
AND t.warehouseFk = vWarehouseFk
GROUP BY t.id
) sub
GROUP BY sub.addressFk
) sub2 ON sub2.addressFk = t.addressFk AND t.id != sub2.id
WHERE t.shipped BETWEEN vOriginDated AND util.dayend(vOriginDated)
AND t.warehouseFk = vWarehouseFk
AND al.code = 'FREE'
AND tp.ticketFk IS NULL
GROUP BY sv.ticketFk
HAVING futureId;
END$$
DELIMITER ;

View File

@ -735,18 +735,16 @@ export default {
}, },
ticketFuture: { ticketFuture: {
openAdvancedSearchButton: 'vn-searchbar .append vn-icon[icon="arrow_drop_down"]', openAdvancedSearchButton: 'vn-searchbar .append vn-icon[icon="arrow_drop_down"]',
originDated: 'vn-date-picker[label="Origin ETD"]', originDated: 'vn-date-picker[label="Origin date"]',
futureDated: 'vn-date-picker[label="Destination ETD"]', futureDated: 'vn-date-picker[label="Destination date"]',
shipped: 'vn-date-picker[label="Origin date"]',
tfShipped: 'vn-date-picker[label="Destination date"]',
linesMax: 'vn-textfield[label="Max Lines"]', linesMax: 'vn-textfield[label="Max Lines"]',
litersMax: 'vn-textfield[label="Max Liters"]', litersMax: 'vn-textfield[label="Max Liters"]',
ipt: 'vn-autocomplete[label="Origin IPT"]', ipt: 'vn-autocomplete[label="Origin IPT"]',
tfIpt: 'vn-autocomplete[label="Destination IPT"]', futureIpt: 'vn-autocomplete[label="Destination IPT"]',
tableIpt: 'vn-autocomplete[name="ipt"]', tableIpt: 'vn-autocomplete[name="ipt"]',
tableTfIpt: 'vn-autocomplete[name="tfIpt"]', tableFutureIpt: 'vn-autocomplete[name="futureIpt"]',
state: 'vn-autocomplete[label="Origin Grouped State"]', state: 'vn-autocomplete[label="Origin Grouped State"]',
tfState: 'vn-autocomplete[label="Destination Grouped State"]', futureState: 'vn-autocomplete[label="Destination Grouped State"]',
warehouseFk: 'vn-autocomplete[label="Warehouse"]', warehouseFk: 'vn-autocomplete[label="Warehouse"]',
problems: 'vn-check[label="With problems"]', problems: 'vn-check[label="With problems"]',
tableButtonSearch: 'vn-button[vn-tooltip="Search"]', tableButtonSearch: 'vn-button[vn-tooltip="Search"]',
@ -755,9 +753,9 @@ export default {
firstCheck: 'tbody > tr:nth-child(1) > td > vn-check', firstCheck: 'tbody > tr:nth-child(1) > td > vn-check',
multiCheck: 'vn-multi-check', multiCheck: 'vn-multi-check',
tableId: 'vn-textfield[name="id"]', tableId: 'vn-textfield[name="id"]',
tableTfId: 'vn-textfield[name="ticketFuture"]', tableFutureId: 'vn-textfield[name="futureId"]',
tableLiters: 'vn-textfield[name="litersMax"]', tableLiters: 'vn-textfield[name="liters"]',
Review

perque canvies el nom? l'anterior a mi em pareixia correcte, no son litros exactes, sino litros màxims

perque canvies el nom? l'anterior a mi em pareixia correcte, no son litros exactes, sino litros màxims
Review

Ho he tingut que posar aixina perque com en el procediment se diu 'lines' i 'liters' al ordenar me donava error. En veritat no passa res perque en el buscador ja apareix que son litres i linies màximes.

Ho he tingut que posar aixina perque com en el procediment se diu 'lines' i 'liters' al ordenar me donava error. En veritat no passa res perque en el buscador ja apareix que son litres i linies màximes.
tableLines: 'vn-textfield[name="linesMax"]', tableLines: 'vn-textfield[name="lines"]',
submit: 'vn-submit[label="Search"]', submit: 'vn-submit[label="Search"]',
table: 'tbody > tr:not(.empty-rows)' table: 'tbody > tr:not(.empty-rows)'
}, },

View File

@ -16,9 +16,6 @@ describe('Ticket Future path', () => {
await browser.close(); await browser.close();
}); });
const now = new Date();
const tomorrow = new Date(now.getDate() + 1);
it('should show errors snackbar because of the required data', async() => { it('should show errors snackbar because of the required data', async() => {
await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton); await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
await page.clearInput(selectors.ticketFuture.warehouseFk); await page.clearInput(selectors.ticketFuture.warehouseFk);
@ -27,20 +24,6 @@ describe('Ticket Future path', () => {
expect(message.text).toContain('warehouseFk is a required argument'); expect(message.text).toContain('warehouseFk is a required argument');
await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
await page.clearInput(selectors.ticketFuture.litersMax);
await page.waitToClick(selectors.ticketFuture.submit);
message = await page.waitForSnackbar();
expect(message.text).toContain('litersMax is a required argument');
await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
await page.clearInput(selectors.ticketFuture.linesMax);
await page.waitToClick(selectors.ticketFuture.submit);
message = await page.waitForSnackbar();
expect(message.text).toContain('linesMax is a required argument');
await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton); await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
await page.clearInput(selectors.ticketFuture.futureDated); await page.clearInput(selectors.ticketFuture.futureDated);
await page.waitToClick(selectors.ticketFuture.submit); await page.waitToClick(selectors.ticketFuture.submit);
@ -62,44 +45,13 @@ describe('Ticket Future path', () => {
await page.waitForNumberOfElements(selectors.ticketFuture.table, 4); await page.waitForNumberOfElements(selectors.ticketFuture.table, 4);
}); });
it('should search with the origin shipped today', async() => {
await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
await page.pickDate(selectors.ticketFuture.shipped, now);
await page.waitToClick(selectors.ticketFuture.submit);
await page.waitForNumberOfElements(selectors.ticketFuture.table, 4);
});
it('should search with the origin shipped tomorrow', async() => {
await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
await page.pickDate(selectors.ticketFuture.shipped, tomorrow);
await page.waitToClick(selectors.ticketFuture.submit);
await page.waitForNumberOfElements(selectors.ticketFuture.table, 0);
});
it('should search with the destination shipped today', async() => {
await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
await page.clearInput(selectors.ticketFuture.shipped);
await page.pickDate(selectors.ticketFuture.tfShipped, now);
await page.waitToClick(selectors.ticketFuture.submit);
await page.waitForNumberOfElements(selectors.ticketFuture.table, 4);
});
it('should search with the destination shipped tomorrow', async() => {
await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
await page.pickDate(selectors.ticketFuture.tfShipped, tomorrow);
await page.waitToClick(selectors.ticketFuture.submit);
await page.waitForNumberOfElements(selectors.ticketFuture.table, 0);
});
it('should search with the origin IPT', async() => { it('should search with the origin IPT', async() => {
await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton); await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
await page.clearInput(selectors.ticketFuture.shipped);
await page.clearInput(selectors.ticketFuture.tfShipped);
await page.clearInput(selectors.ticketFuture.ipt); await page.clearInput(selectors.ticketFuture.ipt);
await page.clearInput(selectors.ticketFuture.tfIpt); await page.clearInput(selectors.ticketFuture.futureIpt);
await page.clearInput(selectors.ticketFuture.state); await page.clearInput(selectors.ticketFuture.state);
await page.clearInput(selectors.ticketFuture.tfState); await page.clearInput(selectors.ticketFuture.futureState);
await page.autocompleteSearch(selectors.ticketFuture.ipt, 'Horizontal'); await page.autocompleteSearch(selectors.ticketFuture.ipt, 'Horizontal');
await page.waitToClick(selectors.ticketFuture.submit); await page.waitToClick(selectors.ticketFuture.submit);
@ -109,14 +61,12 @@ describe('Ticket Future path', () => {
it('should search with the destination IPT', async() => { it('should search with the destination IPT', async() => {
await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton); await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
await page.clearInput(selectors.ticketFuture.shipped);
await page.clearInput(selectors.ticketFuture.tfShipped);
await page.clearInput(selectors.ticketFuture.ipt); await page.clearInput(selectors.ticketFuture.ipt);
await page.clearInput(selectors.ticketFuture.tfIpt); await page.clearInput(selectors.ticketFuture.futureIpt);
await page.clearInput(selectors.ticketFuture.state); await page.clearInput(selectors.ticketFuture.state);
await page.clearInput(selectors.ticketFuture.tfState); await page.clearInput(selectors.ticketFuture.futureState);
await page.autocompleteSearch(selectors.ticketFuture.tfIpt, 'Horizontal'); await page.autocompleteSearch(selectors.ticketFuture.futureIpt, 'Horizontal');
await page.waitToClick(selectors.ticketFuture.submit); await page.waitToClick(selectors.ticketFuture.submit);
await page.waitForNumberOfElements(selectors.ticketFuture.table, 0); await page.waitForNumberOfElements(selectors.ticketFuture.table, 0);
}); });
@ -124,12 +74,10 @@ describe('Ticket Future path', () => {
it('should search with the origin grouped state', async() => { it('should search with the origin grouped state', async() => {
await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton); await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
await page.clearInput(selectors.ticketFuture.shipped);
await page.clearInput(selectors.ticketFuture.tfShipped);
await page.clearInput(selectors.ticketFuture.ipt); await page.clearInput(selectors.ticketFuture.ipt);
await page.clearInput(selectors.ticketFuture.tfIpt); await page.clearInput(selectors.ticketFuture.futureIpt);
await page.clearInput(selectors.ticketFuture.state); await page.clearInput(selectors.ticketFuture.state);
await page.clearInput(selectors.ticketFuture.tfState); await page.clearInput(selectors.ticketFuture.futureState);
await page.autocompleteSearch(selectors.ticketFuture.state, 'Free'); await page.autocompleteSearch(selectors.ticketFuture.state, 'Free');
await page.waitToClick(selectors.ticketFuture.submit); await page.waitToClick(selectors.ticketFuture.submit);
@ -139,24 +87,20 @@ describe('Ticket Future path', () => {
it('should search with the destination grouped state', async() => { it('should search with the destination grouped state', async() => {
await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton); await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
await page.clearInput(selectors.ticketFuture.shipped);
await page.clearInput(selectors.ticketFuture.tfShipped);
await page.clearInput(selectors.ticketFuture.ipt); await page.clearInput(selectors.ticketFuture.ipt);
await page.clearInput(selectors.ticketFuture.tfIpt); await page.clearInput(selectors.ticketFuture.futureIpt);
await page.clearInput(selectors.ticketFuture.state); await page.clearInput(selectors.ticketFuture.state);
await page.clearInput(selectors.ticketFuture.tfState); await page.clearInput(selectors.ticketFuture.futureState);
await page.autocompleteSearch(selectors.ticketFuture.tfState, 'Free'); await page.autocompleteSearch(selectors.ticketFuture.futureState, 'Free');
await page.waitToClick(selectors.ticketFuture.submit); await page.waitToClick(selectors.ticketFuture.submit);
await page.waitForNumberOfElements(selectors.ticketFuture.table, 0); await page.waitForNumberOfElements(selectors.ticketFuture.table, 0);
await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton); await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
await page.clearInput(selectors.ticketFuture.shipped);
await page.clearInput(selectors.ticketFuture.tfShipped);
await page.clearInput(selectors.ticketFuture.ipt); await page.clearInput(selectors.ticketFuture.ipt);
await page.clearInput(selectors.ticketFuture.tfIpt); await page.clearInput(selectors.ticketFuture.futureIpt);
await page.clearInput(selectors.ticketFuture.state); await page.clearInput(selectors.ticketFuture.state);
await page.clearInput(selectors.ticketFuture.tfState); await page.clearInput(selectors.ticketFuture.futureState);
await page.waitToClick(selectors.ticketFuture.submit); await page.waitToClick(selectors.ticketFuture.submit);
await page.waitForNumberOfElements(selectors.ticketFuture.table, 4); await page.waitForNumberOfElements(selectors.ticketFuture.table, 4);
@ -176,7 +120,7 @@ describe('Ticket Future path', () => {
it('should search in smart-table with an ID Destination', async() => { it('should search in smart-table with an ID Destination', async() => {
await page.waitToClick(selectors.ticketFuture.tableButtonSearch); await page.waitToClick(selectors.ticketFuture.tableButtonSearch);
await page.write(selectors.ticketFuture.tableTfId, '12'); await page.write(selectors.ticketFuture.tableFutureId, '12');
await page.keyboard.press('Enter'); await page.keyboard.press('Enter');
await page.waitForNumberOfElements(selectors.ticketFuture.table, 5); await page.waitForNumberOfElements(selectors.ticketFuture.table, 5);
@ -199,7 +143,7 @@ describe('Ticket Future path', () => {
it('should search in smart-table with an IPT Destination', async() => { it('should search in smart-table with an IPT Destination', async() => {
await page.waitToClick(selectors.ticketFuture.tableButtonSearch); await page.waitToClick(selectors.ticketFuture.tableButtonSearch);
await page.autocompleteSearch(selectors.ticketFuture.tableTfIpt, 'Vertical'); await page.autocompleteSearch(selectors.ticketFuture.tableFutureIpt, 'Vertical');
await page.waitForNumberOfElements(selectors.ticketFuture.table, 1); await page.waitForNumberOfElements(selectors.ticketFuture.table, 1);
await page.waitToClick(selectors.ticketFuture.tableButtonSearch); await page.waitToClick(selectors.ticketFuture.tableButtonSearch);

View File

@ -147,7 +147,7 @@ export default class SmartTable extends Component {
for (const column of this.columns) { for (const column of this.columns) {
if (viewConfig.configuration[column.field] == false) { if (viewConfig.configuration[column.field] == false) {
const baseSelector = `smart-table[view-config-id="${this.viewConfigId}"] table`; const baseSelector = `smart-table[view-config-id="${this.viewConfigId}"] table`;
selectors.push(`${baseSelector} thead > tr > th:nth-child(${column.index + 1})`); selectors.push(`${baseSelector} thead > tr:not([second-header]) > th:nth-child(${column.index + 1})`);
selectors.push(`${baseSelector} tbody > tr > td:nth-child(${column.index + 1})`); selectors.push(`${baseSelector} tbody > tr > td:nth-child(${column.index + 1})`);
} }
} }
@ -235,7 +235,7 @@ export default class SmartTable extends Component {
} }
registerColumns() { registerColumns() {
const header = this.element.querySelector('thead > tr'); const header = this.element.querySelector('thead > tr:not([second-header])');
if (!header) return; if (!header) return;
const columns = header.querySelectorAll('th'); const columns = header.querySelectorAll('th');
@ -254,7 +254,7 @@ export default class SmartTable extends Component {
} }
emptyDataRows() { emptyDataRows() {
const header = this.element.querySelector('thead > tr'); const header = this.element.querySelector('thead > tr:not([second-header])');
const columns = header.querySelectorAll('th'); const columns = header.querySelectorAll('th');
const tbody = this.element.querySelector('tbody'); const tbody = this.element.querySelector('tbody');
if (tbody) { if (tbody) {
@ -333,7 +333,7 @@ export default class SmartTable extends Component {
} }
displaySearch() { displaySearch() {
const header = this.element.querySelector('thead > tr'); const header = this.element.querySelector('thead > tr:not([second-header])');
if (!header) return; if (!header) return;
const tbody = this.element.querySelector('tbody'); const tbody = this.element.querySelector('tbody');

View File

@ -8,6 +8,16 @@ smart-table table {
& > thead { & > thead {
border-bottom: $border; border-bottom: $border;
& > tr[second-header] {
& > th
{
text-align: center;
border-bottom-style: groove;
font-weight: bold;
text-transform: uppercase;
}
}
& > * > th { & > * > th {
font-weight: normal; font-weight: normal;
} }
@ -60,6 +70,9 @@ smart-table table {
vertical-align: middle; vertical-align: middle;
} }
} }
&[separator]{
border-left-style: groove;
}
vn-icon.bright, i.bright { vn-icon.bright, i.bright {
color: #f7931e; color: #f7931e;
} }
@ -108,4 +121,4 @@ smart-table table {
font-size: 1.375rem; font-size: 1.375rem;
text-align: center; text-align: center;
} }
} }

View File

@ -140,7 +140,7 @@
"You don't have grant privilege": "You don't have grant privilege", "You don't have grant privilege": "You don't have grant privilege",
"You don't own the role and you can't assign it to another user": "You don't own the role and you can't assign it to another user", "You don't own the role and you can't assign it to another user": "You don't own the role and you can't assign it to another user",
"Email verify": "Email verify", "Email verify": "Email verify",
"Ticket merged": "Ticket [{{id}}]({{{fullPath}}}) ({{{originDated}}}) merged with [{{tfId}}]({{{fullPathFuture}}}) ({{{futureDated}}})", "Ticket merged": "Ticket [{{originId}}]({{{originFullPath}}}) ({{{originDated}}}) merged with [{{destinationId}}]({{{destinationFullPath}}}) ({{{destinationDated}}})",
"Sale(s) blocked, please contact production": "Sale(s) blocked, please contact production", "Sale(s) blocked, please contact production": "Sale(s) blocked, please contact production",
"Receipt's bank was not found": "Receipt's bank was not found", "Receipt's bank was not found": "Receipt's bank was not found",
"This receipt was not compensated": "This receipt was not compensated", "This receipt was not compensated": "This receipt was not compensated",

View File

@ -241,7 +241,7 @@
"Claim pickup order sent": "Reclamación Orden de recogida enviada [{{claimId}}]({{{claimUrl}}}) al cliente *{{clientName}}*", "Claim pickup order sent": "Reclamación Orden de recogida enviada [{{claimId}}]({{{claimUrl}}}) al cliente *{{clientName}}*",
"You don't have grant privilege": "No tienes privilegios para dar privilegios", "You don't have grant privilege": "No tienes privilegios para dar privilegios",
"You don't own the role and you can't assign it to another user": "No eres el propietario del rol y no puedes asignarlo a otro usuario", "You don't own the role and you can't assign it to another user": "No eres el propietario del rol y no puedes asignarlo a otro usuario",
"Ticket merged": "Ticket [{{id}}]({{{fullPath}}}) ({{{originDated}}}) fusionado con [{{tfId}}]({{{fullPathFuture}}}) ({{{futureDated}}})", "Ticket merged": "Ticket [{{originId}}]({{{originFullPath}}}) ({{{originDated}}}) fusionado con [{{destinationId}}]({{{destinationFullPath}}}) ({{{destinationDated}}})",
"Already has this status": "Ya tiene este estado", "Already has this status": "Ya tiene este estado",
"There aren't records for this week": "No existen registros para esta semana", "There aren't records for this week": "No existen registros para esta semana",
"Empty data source": "Origen de datos vacio", "Empty data source": "Origen de datos vacio",

View File

@ -20,3 +20,4 @@ routeFk: route
companyFk: company companyFk: company
agencyModeFk: agency agencyModeFk: agency
ticketFk: ticket ticketFk: ticket
mergedTicket: merged ticket

View File

@ -20,3 +20,4 @@ routeFk: ruta
companyFk: empresa companyFk: empresa
agencyModeFk: agencia agencyModeFk: agencia
ticketFk: ticket ticketFk: ticket
mergedTicket: ticket fusionado

View File

@ -20,18 +20,6 @@ module.exports = Self => {
description: 'The date to probe', description: 'The date to probe',
required: true required: true
}, },
{
arg: 'litersMax',
type: 'number',
description: 'Maximum volume of tickets to catapult',
required: true
},
{
arg: 'linesMax',
type: 'number',
description: 'Maximum number of lines of tickets to catapult',
required: true
},
{ {
arg: 'warehouseFk', arg: 'warehouseFk',
type: 'number', type: 'number',
@ -39,15 +27,15 @@ module.exports = Self => {
required: true required: true
}, },
{ {
arg: 'shipped', arg: 'litersMax',
type: 'date', type: 'number',
description: 'Origin shipped', description: 'Maximum volume of tickets to catapult',
required: false required: false
}, },
{ {
arg: 'tfShipped', arg: 'linesMax',
type: 'date', type: 'number',
description: 'Destination shipped', description: 'Maximum number of lines of tickets to catapult',
required: false required: false
}, },
{ {
@ -57,7 +45,7 @@ module.exports = Self => {
required: false required: false
}, },
{ {
arg: 'tfIpt', arg: 'futureIpt',
type: 'string', type: 'string',
description: 'Destination Item Packaging Type', description: 'Destination Item Packaging Type',
required: false required: false
@ -69,7 +57,7 @@ module.exports = Self => {
required: false required: false
}, },
{ {
arg: 'tfId', arg: 'futureId',
type: 'number', type: 'number',
description: 'Destination id', description: 'Destination id',
required: false required: false
@ -81,7 +69,7 @@ module.exports = Self => {
required: false required: false
}, },
{ {
arg: 'tfState', arg: 'futureState',
type: 'string', type: 'string',
description: 'Destination state', description: 'Destination state',
required: false required: false
@ -108,7 +96,7 @@ module.exports = Self => {
} }
}); });
Self.getTicketsFuture = async (ctx, options) => { Self.getTicketsFuture = async(ctx, options) => {
const args = ctx.args; const args = ctx.args;
const conn = Self.dataSource.connector; const conn = Self.dataSource.connector;
const myOptions = {}; const myOptions = {};
@ -118,32 +106,32 @@ module.exports = Self => {
const where = buildFilter(ctx.args, (param, value) => { const where = buildFilter(ctx.args, (param, value) => {
switch (param) { switch (param) {
case 'id': case 'id':
return { 'f.id': value }; return {'f.id': value};
case 'tfId': case 'lines':
return { 'f.ticketFuture': value }; return {'f.lines': {lte: value}};
case 'shipped': case 'liters':
return { 'f.shipped': value }; return {'f.liters': {lte: value}};
case 'tfShipped': case 'futureId':
return { 'f.tfShipped': value }; return {'f.futureId': value};
case 'ipt': case 'ipt':
return { 'f.ipt': value }; return {'f.ipt': value};
case 'tfIpt': case 'futureIpt':
return { 'f.tfIpt': value }; return {'f.futureIpt': value};
case 'state': case 'state':
return { 'f.code': { like: `%${value}%` } }; return {'f.stateCode': {like: `%${value}%`}};
case 'tfState': case 'futureState':
return { 'f.tfCode': { like: `%${value}%` } }; return {'f.futureStateCode': {like: `%${value}%`}};
} }
}); });
let filter = mergeFilters(ctx.args.filter, { where }); let filter = mergeFilters(ctx.args.filter, {where});
const stmts = []; const stmts = [];
let stmt; let stmt;
stmt = new ParameterizedSQL( stmt = new ParameterizedSQL(
`CALL vn.ticket_canbePostponed(?,?,?,?,?)`, `CALL vn.ticket_canbePostponed(?,?,?)`,
[args.originDated, args.futureDated, args.litersMax, args.linesMax, args.warehouseFk]); [args.originDated, args.futureDated, args.warehouseFk]);
stmts.push(stmt); stmts.push(stmt);
@ -153,7 +141,7 @@ module.exports = Self => {
CREATE TEMPORARY TABLE tmp.sale_getProblems CREATE TEMPORARY TABLE tmp.sale_getProblems
(INDEX (ticketFk)) (INDEX (ticketFk))
ENGINE = MEMORY ENGINE = MEMORY
SELECT f.id ticketFk, f.clientFk, f.warehouseFk, f.shipped SELECT f.id ticketFk, f.clientFk, f.warehouseFk, f.shipped, f.lines, f.liters
FROM tmp.filter f FROM tmp.filter f
LEFT JOIN alertLevel al ON al.id = f.alertLevel LEFT JOIN alertLevel al ON al.id = f.alertLevel
WHERE (al.code = 'FREE' OR f.alertLevel IS NULL)`); WHERE (al.code = 'FREE' OR f.alertLevel IS NULL)`);
@ -174,35 +162,34 @@ module.exports = Self => {
let range; let range;
let hasWhere; let hasWhere;
switch (args.problems) { switch (args.problems) {
case true: case true:
condition = `or`; condition = `or`;
hasProblem = true; hasProblem = true;
range = { neq: null }; range = {neq: null};
hasWhere = true; hasWhere = true;
break; break;
case false: case false:
condition = `and`; condition = `and`;
hasProblem = null; hasProblem = null;
range = null; range = null;
hasWhere = true; hasWhere = true;
break; break;
} }
const problems = { const problems = {
[condition]: [ [condition]: [
{ 'tp.isFreezed': hasProblem }, {'tp.isFreezed': hasProblem},
{ 'tp.risk': hasProblem }, {'tp.risk': hasProblem},
{ 'tp.hasTicketRequest': hasProblem }, {'tp.hasTicketRequest': hasProblem},
{ 'tp.itemShortage': range }, {'tp.itemShortage': range},
{ 'tp.hasComponentLack': hasProblem }, {'tp.hasComponentLack': hasProblem},
{ 'tp.isTooLittle': hasProblem } {'tp.isTooLittle': hasProblem}
] ]
}; };
if (hasWhere) { if (hasWhere)
filter = mergeFilters(filter, { where: problems }); filter = mergeFilters(filter, {where: problems});
}
stmt.merge(conn.makeWhere(filter.where)); stmt.merge(conn.makeWhere(filter.where));
stmt.merge(conn.makeOrderBy(filter.order)); stmt.merge(conn.makeOrderBy(filter.order));

View File

@ -40,19 +40,32 @@ module.exports = Self => {
try { try {
for (let ticket of tickets) { for (let ticket of tickets) {
const fullPath = `${origin}/#!/ticket/${ticket.id}/summary`; const originFullPath = `${origin}/#!/ticket/${ticket.originId}/summary`;
const fullPathFuture = `${origin}/#!/ticket/${ticket.ticketFuture}/summary`; const destinationFullPath = `${origin}/#!/ticket/${ticket.destinationId}/summary`;
const message = $t('Ticket merged', { const message = $t('Ticket merged', {
originDated: dateUtil.toString(new Date(ticket.originETD)), originDated: dateUtil.toString(new Date(ticket.originShipped)),
futureDated: dateUtil.toString(new Date(ticket.destETD)), destinationDated: dateUtil.toString(new Date(ticket.destinationShipped)),
alexandre marked this conversation as resolved Outdated

que es tf? llegint veig que es abreviatura de ticket future.
Com ticket ja es sap jo posaria ticket.futureShipped

que es tf? llegint veig que es abreviatura de ticket future. Com ticket ja es sap jo posaria ticket.futureShipped
id: ticket.id, originId: ticket.originId,
tfId: ticket.ticketFuture, destinationId: ticket.destinationId,
fullPath, originFullPath,
fullPathFuture destinationFullPath
}); });
if (!ticket.id || !ticket.ticketFuture) continue; if (!ticket.originId || !ticket.destinationId) continue;
await models.Sale.updateAll({ticketFk: ticket.id}, {ticketFk: ticket.ticketFuture}, myOptions);
await models.Ticket.setDeleted(ctx, ticket.id, myOptions); const ticketDestinationLogRecord = {
originFk: ticket.destinationId,
userFk: ctx.req.accessToken.userId,
action: 'update',
changedModel: 'Ticket',
changedModelId: ticket.destinationId,
changedModelValue: ticket.destinationId,
oldInstance: {},
newInstance: {mergedTicket: ticket.originId}
};
await models.TicketLog.create(ticketDestinationLogRecord, myOptions);
await models.Sale.updateAll({ticketFk: ticket.originId}, {ticketFk: ticket.destinationId}, myOptions);
await models.Ticket.setDeleted(ctx, ticket.originId, myOptions);
await models.Chat.sendCheckingPresence(ctx, ticket.workerFk, message); await models.Chat.sendCheckingPresence(ctx, ticket.workerFk, message);
} }
if (tx) if (tx)

View File

@ -1,25 +1,22 @@
const models = require('vn-loopback/server/server').models; const models = require('vn-loopback/server/server').models;
describe('TicketFuture getTicketsFuture()', () => { describe('ticket getTicketsFuture()', () => {
const today = new Date(); const today = new Date();
today.setHours(0, 0, 0, 0); today.setHours(0, 0, 0, 0);
const tomorrow = new Date(today.getDate() + 1);
it('should return the tickets passing the required data', async () => { it('should return the tickets passing the required data', async() => {
const tx = await models.Ticket.beginTransaction({}); const tx = await models.Ticket.beginTransaction({});
try { try {
const options = { transaction: tx }; const options = {transaction: tx};
const args = { const args = {
originDated: today, originDated: today,
futureDated: today, futureDated: today,
litersMax: 9999,
linesMax: 9999,
warehouseFk: 1, warehouseFk: 1,
}; };
const ctx = { req: { accessToken: { userId: 9 } }, args }; const ctx = {req: {accessToken: {userId: 9}}, args};
const result = await models.Ticket.getTicketsFuture(ctx, options); const result = await models.Ticket.getTicketsFuture(ctx, options);
expect(result.length).toEqual(4); expect(result.length).toEqual(4);
@ -30,22 +27,20 @@ describe('TicketFuture getTicketsFuture()', () => {
} }
}); });
it('should return the tickets matching the problems on true', async () => { it('should return the tickets matching the problems on true', async() => {
const tx = await models.Ticket.beginTransaction({}); const tx = await models.Ticket.beginTransaction({});
try { try {
const options = { transaction: tx }; const options = {transaction: tx};
const args = { const args = {
originDated: today, originDated: today,
futureDated: today, futureDated: today,
litersMax: 9999,
linesMax: 9999,
warehouseFk: 1, warehouseFk: 1,
problems: true problems: true
}; };
const ctx = { req: { accessToken: { userId: 9 } }, args }; const ctx = {req: {accessToken: {userId: 9}}, args};
const result = await models.Ticket.getTicketsFuture(ctx, options); const result = await models.Ticket.getTicketsFuture(ctx, options);
expect(result.length).toEqual(4); expect(result.length).toEqual(4);
@ -57,22 +52,20 @@ describe('TicketFuture getTicketsFuture()', () => {
} }
}); });
it('should return the tickets matching the problems on false', async () => { it('should return the tickets matching the problems on false', async() => {
const tx = await models.Ticket.beginTransaction({}); const tx = await models.Ticket.beginTransaction({});
try { try {
const options = { transaction: tx }; const options = {transaction: tx};
const args = { const args = {
originDated: today, originDated: today,
futureDated: today, futureDated: today,
litersMax: 9999,
linesMax: 9999,
warehouseFk: 1, warehouseFk: 1,
problems: false problems: false
}; };
const ctx = { req: { accessToken: { userId: 9 } }, args }; const ctx = {req: {accessToken: {userId: 9}}, args};
const result = await models.Ticket.getTicketsFuture(ctx, options); const result = await models.Ticket.getTicketsFuture(ctx, options);
expect(result.length).toEqual(0); expect(result.length).toEqual(0);
@ -84,22 +77,20 @@ describe('TicketFuture getTicketsFuture()', () => {
} }
}); });
it('should return the tickets matching the problems on null', async () => { it('should return the tickets matching the problems on null', async() => {
const tx = await models.Ticket.beginTransaction({}); const tx = await models.Ticket.beginTransaction({});
try { try {
const options = { transaction: tx }; const options = {transaction: tx};
const args = { const args = {
originDated: today, originDated: today,
futureDated: today, futureDated: today,
litersMax: 9999,
linesMax: 9999,
warehouseFk: 1, warehouseFk: 1,
problems: null problems: null
}; };
const ctx = { req: { accessToken: { userId: 9 } }, args }; const ctx = {req: {accessToken: {userId: 9}}, args};
const result = await models.Ticket.getTicketsFuture(ctx, options); const result = await models.Ticket.getTicketsFuture(ctx, options);
expect(result.length).toEqual(4); expect(result.length).toEqual(4);
@ -111,130 +102,20 @@ describe('TicketFuture getTicketsFuture()', () => {
} }
}); });
it('should return the tickets matching the correct origin shipped', async () => { it('should return the tickets matching the OK State in origin date', async() => {
const tx = await models.Ticket.beginTransaction({}); const tx = await models.Ticket.beginTransaction({});
try { try {
const options = { transaction: tx }; const options = {transaction: tx};
const args = { const args = {
originDated: today, originDated: today,
futureDated: today, futureDated: today,
litersMax: 9999,
linesMax: 9999,
warehouseFk: 1, warehouseFk: 1,
shipped: today state: 'OK'
}; };
const ctx = { req: { accessToken: { userId: 9 } }, args }; const ctx = {req: {accessToken: {userId: 9}}, args};
const result = await models.Ticket.getTicketsFuture(ctx, options);
expect(result.length).toEqual(4);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return the tickets matching the an incorrect origin shipped', async () => {
const tx = await models.Ticket.beginTransaction({});
try {
const options = { transaction: tx };
const args = {
originDated: today,
futureDated: today,
litersMax: 9999,
linesMax: 9999,
warehouseFk: 1,
shipped: tomorrow
};
const ctx = { req: { accessToken: { userId: 9 } }, args };
const result = await models.Ticket.getTicketsFuture(ctx, options);
expect(result.length).toEqual(0);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return the tickets matching the correct destination shipped', async () => {
const tx = await models.Ticket.beginTransaction({});
try {
const options = { transaction: tx };
const args = {
originDated: today,
futureDated: today,
litersMax: 9999,
linesMax: 9999,
warehouseFk: 1,
tfShipped: today
};
const ctx = { req: { accessToken: { userId: 9 } }, args };
const result = await models.Ticket.getTicketsFuture(ctx, options);
expect(result.length).toEqual(4);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return the tickets matching the an incorrect destination shipped', async () => {
const tx = await models.Ticket.beginTransaction({});
try {
const options = { transaction: tx };
const args = {
originDated: today,
futureDated: today,
litersMax: 9999,
linesMax: 9999,
warehouseFk: 1,
tfShipped: tomorrow
};
const ctx = { req: { accessToken: { userId: 9 } }, args };
const result = await models.Ticket.getTicketsFuture(ctx, options);
expect(result.length).toEqual(0);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return the tickets matching the OK State in origin date', async () => {
const tx = await models.Ticket.beginTransaction({});
try {
const options = { transaction: tx };
const args = {
originDated: today,
futureDated: today,
litersMax: 9999,
linesMax: 9999,
warehouseFk: 1,
state: "OK"
};
const ctx = { req: { accessToken: { userId: 9 } }, args };
const result = await models.Ticket.getTicketsFuture(ctx, options); const result = await models.Ticket.getTicketsFuture(ctx, options);
expect(result.length).toEqual(1); expect(result.length).toEqual(1);
@ -246,22 +127,20 @@ describe('TicketFuture getTicketsFuture()', () => {
} }
}); });
it('should return the tickets matching the OK State in destination date', async () => { it('should return the tickets matching the OK State in destination date', async() => {
const tx = await models.Ticket.beginTransaction({}); const tx = await models.Ticket.beginTransaction({});
try { try {
const options = { transaction: tx }; const options = {transaction: tx};
const args = { const args = {
originDated: today, originDated: today,
futureDated: today, futureDated: today,
litersMax: 9999,
linesMax: 9999,
warehouseFk: 1, warehouseFk: 1,
tfState: "OK" futureState: 'OK'
}; };
const ctx = { req: { accessToken: { userId: 9 } }, args }; const ctx = {req: {accessToken: {userId: 9}}, args};
const result = await models.Ticket.getTicketsFuture(ctx, options); const result = await models.Ticket.getTicketsFuture(ctx, options);
expect(result.length).toEqual(4); expect(result.length).toEqual(4);
@ -273,22 +152,20 @@ describe('TicketFuture getTicketsFuture()', () => {
} }
}); });
it('should return the tickets matching the correct IPT in origin date', async () => { it('should return the tickets matching the correct IPT in origin date', async() => {
const tx = await models.Ticket.beginTransaction({}); const tx = await models.Ticket.beginTransaction({});
try { try {
const options = { transaction: tx }; const options = {transaction: tx};
const args = { const args = {
originDated: today, originDated: today,
futureDated: today, futureDated: today,
litersMax: 9999,
linesMax: 9999,
warehouseFk: 1, warehouseFk: 1,
ipt: null ipt: null
}; };
const ctx = { req: { accessToken: { userId: 9 } }, args }; const ctx = {req: {accessToken: {userId: 9}}, args};
const result = await models.Ticket.getTicketsFuture(ctx, options); const result = await models.Ticket.getTicketsFuture(ctx, options);
expect(result.length).toEqual(4); expect(result.length).toEqual(4);
@ -300,22 +177,20 @@ describe('TicketFuture getTicketsFuture()', () => {
} }
}); });
it('should return the tickets matching the incorrect IPT in origin date', async () => { it('should return the tickets matching the incorrect IPT in origin date', async() => {
const tx = await models.Ticket.beginTransaction({}); const tx = await models.Ticket.beginTransaction({});
try { try {
const options = { transaction: tx }; const options = {transaction: tx};
const args = { const args = {
originDated: today, originDated: today,
futureDated: today, futureDated: today,
litersMax: 9999,
linesMax: 9999,
warehouseFk: 1, warehouseFk: 1,
ipt: 0 ipt: 0
}; };
const ctx = { req: { accessToken: { userId: 9 } }, args }; const ctx = {req: {accessToken: {userId: 9}}, args};
const result = await models.Ticket.getTicketsFuture(ctx, options); const result = await models.Ticket.getTicketsFuture(ctx, options);
expect(result.length).toEqual(0); expect(result.length).toEqual(0);
@ -327,22 +202,20 @@ describe('TicketFuture getTicketsFuture()', () => {
} }
}); });
it('should return the tickets matching the correct IPT in destination date', async () => { it('should return the tickets matching the correct IPT in destination date', async() => {
const tx = await models.Ticket.beginTransaction({}); const tx = await models.Ticket.beginTransaction({});
try { try {
const options = { transaction: tx }; const options = {transaction: tx};
const args = { const args = {
originDated: today, originDated: today,
futureDated: today, futureDated: today,
litersMax: 9999,
linesMax: 9999,
warehouseFk: 1, warehouseFk: 1,
tfIpt: null futureIpt: null
}; };
const ctx = { req: { accessToken: { userId: 9 } }, args }; const ctx = {req: {accessToken: {userId: 9}}, args};
const result = await models.Ticket.getTicketsFuture(ctx, options); const result = await models.Ticket.getTicketsFuture(ctx, options);
expect(result.length).toEqual(4); expect(result.length).toEqual(4);
@ -354,22 +227,20 @@ describe('TicketFuture getTicketsFuture()', () => {
} }
}); });
it('should return the tickets matching the incorrect IPT in destination date', async () => { it('should return the tickets matching the incorrect IPT in destination date', async() => {
const tx = await models.Ticket.beginTransaction({}); const tx = await models.Ticket.beginTransaction({});
try { try {
const options = { transaction: tx }; const options = {transaction: tx};
const args = { const args = {
originDated: today, originDated: today,
futureDated: today, futureDated: today,
litersMax: 9999,
linesMax: 9999,
warehouseFk: 1, warehouseFk: 1,
tfIpt: 0 futureIpt: 0
}; };
const ctx = { req: { accessToken: { userId: 9 } }, args }; const ctx = {req: {accessToken: {userId: 9}}, args};
const result = await models.Ticket.getTicketsFuture(ctx, options); const result = await models.Ticket.getTicketsFuture(ctx, options);
expect(result.length).toEqual(0); expect(result.length).toEqual(0);
@ -381,22 +252,20 @@ describe('TicketFuture getTicketsFuture()', () => {
} }
}); });
it('should return the tickets matching the ID in origin date', async () => { it('should return the tickets matching the ID in origin date', async() => {
const tx = await models.Ticket.beginTransaction({}); const tx = await models.Ticket.beginTransaction({});
try { try {
const options = { transaction: tx }; const options = {transaction: tx};
const args = { const args = {
originDated: today, originDated: today,
futureDated: today, futureDated: today,
litersMax: 9999,
linesMax: 9999,
warehouseFk: 1, warehouseFk: 1,
id: 13 id: 13
}; };
const ctx = { req: { accessToken: { userId: 9 } }, args }; const ctx = {req: {accessToken: {userId: 9}}, args};
const result = await models.Ticket.getTicketsFuture(ctx, options); const result = await models.Ticket.getTicketsFuture(ctx, options);
expect(result.length).toEqual(1); expect(result.length).toEqual(1);
@ -408,22 +277,20 @@ describe('TicketFuture getTicketsFuture()', () => {
} }
}); });
it('should return the tickets matching the ID in destination date', async () => { it('should return the tickets matching the ID in destination date', async() => {
const tx = await models.Ticket.beginTransaction({}); const tx = await models.Ticket.beginTransaction({});
try { try {
const options = { transaction: tx }; const options = {transaction: tx};
const args = { const args = {
originDated: today, originDated: today,
futureDated: today, futureDated: today,
litersMax: 9999,
linesMax: 9999,
warehouseFk: 1, warehouseFk: 1,
tfId: 12 futureId: 12
}; };
const ctx = { req: { accessToken: { userId: 9 } }, args }; const ctx = {req: {accessToken: {userId: 9}}, args};
const result = await models.Ticket.getTicketsFuture(ctx, options); const result = await models.Ticket.getTicketsFuture(ctx, options);
expect(result.length).toEqual(4); expect(result.length).toEqual(4);
@ -434,5 +301,4 @@ describe('TicketFuture getTicketsFuture()', () => {
throw e; throw e;
} }
}); });
}); });

View File

@ -3,15 +3,15 @@ const LoopBackContext = require('loopback-context');
describe('ticket merge()', () => { describe('ticket merge()', () => {
const tickets = [{ const tickets = [{
id: 13, originId: 13,
ticketFuture: 12, destinationId: 12,
workerFk: 1, originShipped: new Date(),
originETD: new Date(), destinationShipped: new Date(),
destETD: new Date() workerFk: 1
}]; }];
const activeCtx = { const activeCtx = {
accessToken: { userId: 9 }, accessToken: {userId: 9},
}; };
beforeEach(() => { beforeEach(() => {
@ -22,26 +22,26 @@ describe('ticket merge()', () => {
const ctx = { const ctx = {
req: { req: {
accessToken: { userId: 9 }, accessToken: {userId: 9},
headers: { origin: 'http://localhost:5000' }, headers: {origin: 'http://localhost:5000'},
} }
}; };
ctx.req.__ = value => { ctx.req.__ = value => {
return value; return value;
}; };
it('should merge two tickets', async () => { it('should merge two tickets', async() => {
const tx = await models.Ticket.beginTransaction({}); const tx = await models.Ticket.beginTransaction({});
try { try {
const options = { transaction: tx }; const options = {transaction: tx};
const chatNotificationBeforeMerge = await models.Chat.find(); const chatNotificationBeforeMerge = await models.Chat.find();
await models.Ticket.merge(ctx, tickets, options); await models.Ticket.merge(ctx, tickets, options);
const createdTicketLog = await models.TicketLog.find({ where: { originFk: tickets[0].id } }, options); const createdTicketLog = await models.TicketLog.find({where: {originFk: tickets[0].originId}}, options);
const deletedTicket = await models.Ticket.findOne({ where: { id: tickets[0].id } }, options); const deletedTicket = await models.Ticket.findOne({where: {id: tickets[0].originId}}, options);
const salesTicketFuture = await models.Sale.find({ where: { ticketFk: tickets[0].ticketFuture } }, options); const salesTicketFuture = await models.Sale.find({where: {ticketFk: tickets[0].destinationId}}, options);
const chatNotificationAfterMerge = await models.Chat.find(); const chatNotificationAfterMerge = await models.Chat.find();
expect(createdTicketLog.length).toEqual(1); expect(createdTicketLog.length).toEqual(1);

View File

@ -94,8 +94,5 @@
}, },
"TicketConfig": { "TicketConfig": {
"dataSource": "vn" "dataSource": "vn"
},
"TicketFuture": {
"dataSource": "vn"
} }
} }

View File

@ -1,12 +0,0 @@
{
"name": "TicketFuture",
"base": "PersistedModel",
"acls": [
{
"accessType": "READ",
"principalType": "ROLE",
"principalId": "employee",
"permission": "ALLOW"
}
]
}

View File

@ -33,7 +33,7 @@ module.exports = function(Self) {
require('../methods/ticket/closeByTicket')(Self); require('../methods/ticket/closeByTicket')(Self);
require('../methods/ticket/closeByAgency')(Self); require('../methods/ticket/closeByAgency')(Self);
require('../methods/ticket/closeByRoute')(Self); require('../methods/ticket/closeByRoute')(Self);
require('../methods/ticket-future/getTicketsFuture')(Self); require('../methods/ticket/getTicketsFuture')(Self);
require('../methods/ticket/merge')(Self); require('../methods/ticket/merge')(Self);
require('../methods/ticket/isRoleAdvanced')(Self); require('../methods/ticket/isRoleAdvanced')(Self);
require('../methods/ticket/collectionLabel')(Self); require('../methods/ticket/collectionLabel')(Self);

View File

@ -4,43 +4,26 @@
<vn-date-picker <vn-date-picker
vn-one vn-one
label="Origin date" label="Origin date"
ng-model="filter.shipped" ng-model="filter.originDated"
on-change="$ctrl.from = value"> required="true">
</vn-date-picker> </vn-date-picker>
<vn-date-picker <vn-date-picker
vn-one vn-one
label="Destination date" label="Destination date"
ng-model="filter.tfShipped">
</vn-date-picker>
</vn-horizontal>
<vn-horizontal class="vn-px-lg">
<vn-date-picker
vn-one
label="Origin ETD"
ng-model="filter.originDated"
required="true"
info="ETD">
</vn-date-picker>
<vn-date-picker
vn-one
label="Destination ETD"
ng-model="filter.futureDated" ng-model="filter.futureDated"
required="true" required="true">
info="ETD">
</vn-date-picker> </vn-date-picker>
</vn-horizontal> </vn-horizontal>
<vn-horizontal class="vn-px-lg"> <vn-horizontal class="vn-px-lg">
<vn-textfield
vn-one
label="Max Lines"
ng-model="filter.linesMax"
required="true">
</vn-textfield>
<vn-textfield <vn-textfield
vn-one vn-one
label="Max Liters" label="Max Liters"
ng-model="filter.litersMax" ng-model="filter.litersMax">
required="true"> </vn-textfield>
<vn-textfield
vn-one
label="Max Lines"
ng-model="filter.linesMax">
</vn-textfield> </vn-textfield>
</vn-horizontal> </vn-horizontal>
<vn-horizontal class="vn-px-lg"> <vn-horizontal class="vn-px-lg">
@ -48,22 +31,22 @@
data="$ctrl.itemPackingTypes" data="$ctrl.itemPackingTypes"
label="Origin IPT" label="Origin IPT"
value-field="code" value-field="code"
show-field="name" show-field="description"
ng-model="filter.ipt" ng-model="filter.ipt"
info="IPT"> info="IPT">
<tpl-item> <tpl-item>
{{name}} {{description}}
</tpl-item> </tpl-item>
</vn-autocomplete> </vn-autocomplete>
<vn-autocomplete vn-one <vn-autocomplete vn-one
data="$ctrl.itemPackingTypes" data="$ctrl.itemPackingTypes"
label="Destination IPT" label="Destination IPT"
value-field="code" value-field="code"
show-field="name" show-field="description"
ng-model="filter.tfIpt" ng-model="filter.futureIpt"
info="IPT"> info="IPT">
<tpl-item> <tpl-item>
{{name}} {{description}}
</tpl-item> </tpl-item>
</vn-autocomplete> </vn-autocomplete>
</vn-horizontal> </vn-horizontal>
@ -83,7 +66,7 @@
label="Destination Grouped State" label="Destination Grouped State"
value-field="code" value-field="code"
show-field="name" show-field="name"
ng-model="filter.tfState"> ng-model="filter.futureState">
<tpl-item> <tpl-item>
{{name}} {{name}}
</tpl-item> </tpl-item>

View File

@ -28,9 +28,8 @@ class Controller extends SearchPanel {
this.$http.get('ItemPackingTypes').then(res => { this.$http.get('ItemPackingTypes').then(res => {
for (let ipt of res.data) { for (let ipt of res.data) {
itemPackingTypes.push({ itemPackingTypes.push({
id: ipt.id, description: this.$t(ipt.description),
code: ipt.code, code: ipt.code,
name: this.$t(ipt.code)
}); });
} }
this.itemPackingTypes = itemPackingTypes; this.itemPackingTypes = itemPackingTypes;

View File

@ -1,9 +1 @@
Future tickets: Tickets a futuro Future tickets: Tickets a futuro
FREE: Free
DELIVERED: Delivered
ON_PREPARATION: On preparation
PACKED: Packed
F: Fruits and vegetables
V: Vertical
H: Horizontal
P: Feed

View File

@ -11,13 +11,4 @@ With problems: Con problemas
Warehouse: Almacén Warehouse: Almacén
Origin Grouped State: Estado agrupado origen Origin Grouped State: Estado agrupado origen
Destination Grouped State: Estado agrupado destino Destination Grouped State: Estado agrupado destino
FREE: Libre
DELIVERED: Servido
ON_PREPARATION: En preparacion
PACKED: Encajado
F: Frutas y verduras
V: Vertical
H: Horizontal
P: Pienso
ETD: Tiempo estimado de entrega
IPT: Encajado IPT: Encajado

View File

@ -1,7 +1,7 @@
<vn-crud-model <vn-crud-model
vn-id="model" vn-id="model"
url="Tickets/getTicketsFuture" url="Tickets/getTicketsFuture"
limit="20"> auto-load="false">
</vn-crud-model> </vn-crud-model>
<vn-portal slot="topbar"> <vn-portal slot="topbar">
<vn-searchbar <vn-searchbar
@ -30,6 +30,11 @@
<slot-table> <slot-table>
<table> <table>
<thead> <thead>
<tr second-header>
<td></td>
<th colspan="7" translate>Origin</th>
<th colspan="4" translate>Destination</th>
</tr>
<tr> <tr>
<th shrink> <th shrink>
<vn-multi-check <vn-multi-check
@ -38,39 +43,39 @@
check-field="checked"> check-field="checked">
</vn-multi-check> </vn-multi-check>
</th> </th>
<th field="problems"> <th field="totalProblems">
<span translate>Problems</span> <span translate>Problems</span>
</th> </th>
<th field="id"> <th field="id">
<span translate>Origin ID</span> <span translate>ID</span>
</th> </th>
<th field="originETD"> <th field="shipped">
<span translate>Origin ETD</span> <span translate>Date</span>
</th>
<th field="ipt" title="Item Packing Type">
<span>IPT</span>
</th> </th>
<th field="state"> <th field="state">
<span translate>Origin State</span> <span translate>State</span>
</th> </th>
<th field="ipt"> <th field="liters">
<span>IPT</span>
</th>
<th field="litersMax">
<span translate>Liters</span> <span translate>Liters</span>
</th> </th>
<th field="linesMax"> <th shrink field="lines">
<span translate>Available Lines</span> <span translate>Available Lines</span>
</th> </th>
<th field="ticketFuture"> <th field="futureId" separator>
<span translate>Destination ID</span> <span translate>ID</span>
</th> </th>
<th field="destETD"> <th field="futureShipped">
<span translate>Destination ETD</span> <span translate>Date</span>
</th> </th>
<th field="tfState"> <th field="futureIpt" title="Item Packing Type">
<span translate>Destination State</span>
</th>
<th field="tfIpt">
<span>IPT</span> <span>IPT</span>
</th> </th>
<th shrink field="futureState">
<span translate>State</span>
</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -125,38 +130,38 @@
{{::ticket.id}} {{::ticket.id}}
</span></td> </span></td>
<td shrink-date> <td shrink-date>
<span class="chip {{$ctrl.compareDate(ticket.originETD)}}"> <span class="chip {{$ctrl.compareDate(ticket.shipped)}}">
{{::ticket.originETD | date: 'dd/MM/yyyy'}} {{::ticket.shipped | date: 'dd/MM/yyyy'}}
</span> </span>
</td> </td>
<td>{{::ticket.ipt}}</td>
<td> <td>
<span <span
class="chip {{$ctrl.stateColor(ticket.state)}}"> class="chip {{$ctrl.stateColor(ticket.state)}}">
{{::ticket.state}} {{::ticket.state}}
</span> </span>
</td> </td>
<td>{{::ticket.ipt}}</td>
<td>{{::ticket.liters}}</td> <td>{{::ticket.liters}}</td>
<td>{{::ticket.lines}}</td> <td>{{::ticket.lines}}</td>
<td> <td>
<span <span
ng-click="ticketDescriptor.show($event, ticket.ticketFuture)" ng-click="ticketDescriptor.show($event, ticket.futureId)"
class="link"> class="link">
{{::ticket.ticketFuture}} {{::ticket.futureId}}
</span> </span>
</td> </td>
<td shrink-date> <td shrink-date>
<span class="chip {{$ctrl.compareDate(ticket.destETD)}}"> <span class="chip {{$ctrl.compareDate(ticket.futureShipped)}}">
{{::ticket.destETD | date: 'dd/MM/yyyy'}} {{::ticket.futureShipped | date: 'dd/MM/yyyy'}}
</span> </span>
</td> </td>
<td>{{::ticket.futureIpt}}</td>
<td> <td>
<span <span
class="chip {{$ctrl.stateColor(ticket.tfState)}}"> class="chip {{$ctrl.stateColor(ticket.futureState)}}">
{{::ticket.tfState}} {{::ticket.futureState}}
</span> </span>
</td> </td>
<td>{{::ticket.tfIpt}}</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>

View File

@ -11,15 +11,15 @@ export default class Controller extends Section {
search: true, search: true,
}, },
columns: [{ columns: [{
field: 'problems', field: 'totalProblems',
searchable: false,
},
{
field: 'shipped',
searchable: false searchable: false
}, },
{ {
field: 'originETD', field: 'futureShipped',
searchable: false
},
{
field: 'destETD',
searchable: false searchable: false
}, },
{ {
@ -27,7 +27,7 @@ export default class Controller extends Section {
searchable: false searchable: false
}, },
{ {
field: 'tfState', field: 'futureState',
searchable: false searchable: false
}, },
{ {
@ -39,7 +39,7 @@ export default class Controller extends Section {
} }
}, },
{ {
field: 'tfIpt', field: 'futureIpt',
autocomplete: { autocomplete: {
url: 'ItemPackingTypes', url: 'ItemPackingTypes',
showField: 'description', showField: 'description',
@ -48,6 +48,9 @@ export default class Controller extends Section {
}, },
] ]
}; };
}
$postLink() {
this.setDefaultFilter(); this.setDefaultFilter();
} }
@ -57,10 +60,9 @@ export default class Controller extends Section {
this.filterParams = { this.filterParams = {
originDated: today, originDated: today,
futureDated: today, futureDated: today,
linesMax: '9999', warehouseFk: this.vnConfig.warehouseFk
litersMax: '9999',
warehouseFk: 1
}; };
this.$.model.applyFilter(null, this.filterParams);
} }
compareDate(date) { compareDate(date) {
@ -113,7 +115,17 @@ export default class Controller extends Section {
} }
moveTicketsFuture() { moveTicketsFuture() {
let params = { tickets: this.checked }; let ticketsToMove = [];
this.checked.forEach(ticket => {
ticketsToMove.push({
originId: ticket.id,
destinationId: ticket.futureId,
originShipped: ticket.shipped,
destinationShipped: ticket.futureShipped,
workerFk: ticket.workerFk
});
});
let params = {tickets: ticketsToMove};
return this.$http.post('Tickets/merge', params) return this.$http.post('Tickets/merge', params)
.then(() => { .then(() => {
this.$.model.refresh(); this.$.model.refresh();
@ -123,18 +135,18 @@ export default class Controller extends Section {
exprBuilder(param, value) { exprBuilder(param, value) {
switch (param) { switch (param) {
case 'id': case 'id':
return { 'id': value }; return {'id': value};
case 'ticketFuture': case 'futureId':
return { 'ticketFuture': value }; return {'futureId': value};
case 'litersMax': case 'liters':
return { 'liters': value }; return {'liters': value};
case 'linesMax': case 'lines':
return { 'lines': value }; return {'lines': value};
case 'ipt': case 'ipt':
return { 'ipt': value }; return {'ipt': value};
case 'tfIpt': case 'futureIpt':
return { 'tfIpt': value }; return {'futureIpt': value};
} }
} }
} }

View File

@ -2,33 +2,30 @@ import './index.js';
import crudModel from 'core/mocks/crud-model'; import crudModel from 'core/mocks/crud-model';
describe('Component vnTicketFuture', () => { describe('Component vnTicketFuture', () => {
const today = new Date();
let controller; let controller;
let $httpBackend; let $httpBackend;
let $window;
beforeEach(ngModule('ticket') beforeEach(ngModule('ticket'));
);
beforeEach(inject(($componentController, _$window_, _$httpBackend_) => { beforeEach(inject(($componentController, _$httpBackend_) => {
$httpBackend = _$httpBackend_; $httpBackend = _$httpBackend_;
$window = _$window_;
const $element = angular.element('<vn-ticket-future></vn-ticket-future>'); const $element = angular.element('<vn-ticket-future></vn-ticket-future>');
controller = $componentController('vnTicketFuture', { $element }); controller = $componentController('vnTicketFuture', {$element});
controller.$.model = crudModel; controller.$.model = crudModel;
controller.$.model.data = [{ controller.$.model.data = [{
id: 1, id: 1,
checked: true, checked: true,
state: "OK" state: 'OK'
}, { }, {
id: 2, id: 2,
checked: true, checked: true,
state: "Libre" state: 'Libre'
}]; }];
})); }));
describe('compareDate()', () => { describe('compareDate()', () => {
it('should return warning when the date is the present', () => { it('should return warning when the date is the present', () => {
let today = new Date();
let result = controller.compareDate(today); let result = controller.compareDate(today);
expect(result).toEqual('warning'); expect(result).toEqual('warning');
@ -67,6 +64,7 @@ describe('Component vnTicketFuture', () => {
it('should return success to the OK tickets', () => { it('should return success to the OK tickets', () => {
const ok = controller.stateColor(controller.$.model.data[0].state); const ok = controller.stateColor(controller.$.model.data[0].state);
const notOk = controller.stateColor(controller.$.model.data[1].state); const notOk = controller.stateColor(controller.$.model.data[1].state);
expect(ok).toEqual('success'); expect(ok).toEqual('success');
expect(notOk).not.toEqual('success'); expect(notOk).not.toEqual('success');
}); });
@ -74,6 +72,7 @@ describe('Component vnTicketFuture', () => {
it('should return success to the FREE tickets', () => { it('should return success to the FREE tickets', () => {
const notFree = controller.stateColor(controller.$.model.data[0].state); const notFree = controller.stateColor(controller.$.model.data[0].state);
const free = controller.stateColor(controller.$.model.data[1].state); const free = controller.stateColor(controller.$.model.data[1].state);
expect(free).toEqual('notice'); expect(free).toEqual('notice');
expect(notFree).not.toEqual('notice'); expect(notFree).not.toEqual('notice');
}); });
@ -81,18 +80,14 @@ describe('Component vnTicketFuture', () => {
describe('dateRange()', () => { describe('dateRange()', () => {
it('should return two dates with the hours at the start and end of the given date', () => { it('should return two dates with the hours at the start and end of the given date', () => {
const now = new Date(); const dateRange = controller.dateRange(today);
const today = now.getDate();
const dateRange = controller.dateRange(now);
const start = dateRange[0].toString(); const start = dateRange[0].toString();
const end = dateRange[1].toString(); const end = dateRange[1].toString();
expect(start).toContain(today); expect(start).toContain(today.getDate());
expect(start).toContain('00:00:00'); expect(start).toContain('00:00:00');
expect(end).toContain(today); expect(end).toContain(today.getDate());
expect(end).toContain('23:59:59'); expect(end).toContain('23:59:59');
}); });
}); });

View File

@ -1,6 +1,2 @@
Move confirmation: Do you want to move {{checked}} tickets to the future? Move confirmation: Do you want to move {{checked}} tickets to the future?
FREE: Free
DELIVERED: Delivered
ON_PREPARATION: On preparation
PACKED: Packed
Success: Tickets moved successfully! Success: Tickets moved successfully!

View File

@ -3,20 +3,14 @@ Search tickets: Buscar tickets
Search future tickets by date: Buscar tickets por fecha Search future tickets by date: Buscar tickets por fecha
Problems: Problemas Problems: Problemas
Origin ID: ID origen Origin ID: ID origen
Closing: Cierre
Origin State: Estado origen Origin State: Estado origen
Destination State: Estado destino Destination State: Estado destino
Liters: Litros Liters: Litros
Available Lines: Líneas disponibles Available Lines: Líneas disponibles
Destination ID: ID destino Destination ID: ID destino
Destination ETD: ETD Destino
Origin ETD: ETD Origen
Move tickets: Mover tickets Move tickets: Mover tickets
Move confirmation: ¿Desea mover {{checked}} tickets hacia el futuro? Move confirmation: ¿Desea mover {{checked}} tickets hacia el futuro?
Success: Tickets movidos correctamente Success: Tickets movidos correctamente
ETD: Tiempo estimado de entrega
IPT: Encajado IPT: Encajado
FREE: Libre Origin Date: Fecha origen
DELIVERED: Servido Destination Date: Fecha destino
ON_PREPARATION: En preparacion
PACKED: Encajado