refactor(ticket): all ticket endpoints are using transactions now
gitea/salix/pipeline/head This commit looks good Details

This commit is contained in:
Carlos Jimenez Ruiz 2021-10-07 09:57:07 +02:00
parent 55a2ec83da
commit cb7d1b24e8
20 changed files with 653 additions and 315 deletions

View File

@ -7,13 +7,13 @@ module.exports = Self => {
accepts: [ accepts: [
{ {
arg: 'filter', arg: 'filter',
type: 'Object', type: 'object',
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string', description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string',
http: {source: 'query'}, http: {source: 'query'},
}, },
], ],
returns: { returns: {
type: ['Object'], type: ['object'],
root: true, root: true,
}, },
http: { http: {
@ -22,7 +22,12 @@ module.exports = Self => {
}, },
}); });
Self.filter = async filter => { Self.filter = async(filter, options) => {
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const stmt = new ParameterizedSQL( const stmt = new ParameterizedSQL(
`SELECT `SELECT
e.id, e.id,
@ -55,6 +60,6 @@ module.exports = Self => {
`); `);
stmt.merge(Self.buildSuffix(filter, 'e')); stmt.merge(Self.buildSuffix(filter, 'e'));
return await Self.rawStmt(stmt); return Self.rawStmt(stmt, myOptions);
}; };
}; };

View File

@ -0,0 +1,21 @@
const models = require('vn-loopback/server/server').models;
describe('expedition filter()', () => {
it('should return the expeditions matching the filter', async() => {
const tx = await models.Expedition.beginTransaction({});
try {
const options = {transaction: tx};
const filter = {where: {packagingFk: 1}};
const response = await models.Expedition.filter(filter, options);
expect(response.length).toEqual(10);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -7,13 +7,13 @@ module.exports = Self => {
accessType: 'READ', accessType: 'READ',
accepts: [{ accepts: [{
arg: 'filter', arg: 'filter',
type: 'Object', type: 'object',
required: false, required: false,
description: 'Filter defining where and paginated data', description: 'Filter defining where and paginated data',
http: {source: 'query'} http: {source: 'query'}
}], }],
returns: { returns: {
type: ['Object'], type: ['object'],
root: true root: true
}, },
http: { http: {
@ -22,9 +22,14 @@ module.exports = Self => {
} }
}); });
Self.listPackaging = async filter => { Self.listPackaging = async(filter, options) => {
let conn = Self.dataSource.connector; const conn = Self.dataSource.connector;
let stmt = new ParameterizedSQL( const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const stmt = new ParameterizedSQL(
`SELECT name, itemFk, packagingFk `SELECT name, itemFk, packagingFk
FROM (SELECT i.name, i.id itemFk, p.id packagingFk FROM (SELECT i.name, i.id itemFk, p.id packagingFk
FROM item i FROM item i
@ -33,6 +38,7 @@ module.exports = Self => {
); );
stmt.merge(conn.makeSuffix(filter)); stmt.merge(conn.makeSuffix(filter));
return conn.executeStmt(stmt);
return conn.executeStmt(stmt, myOptions);
}; };
}; };

View File

@ -1,12 +1,22 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('ticket listPackaging()', () => { describe('ticket listPackaging()', () => {
it('should return the packaging', async() => { it('should return the packaging', async() => {
let filter = {where: {packagingFk: 1}}; const tx = await models.Packaging.beginTransaction({});
let response = await app.models.Packaging.listPackaging(filter);
expect(response[0].name).toBeDefined(); try {
expect(response[0].name).toEqual('Container ammo box 1m'); const options = {transaction: tx};
const filter = {where: {packagingFk: 1}};
const response = await models.Packaging.listPackaging(filter, options);
expect(response[0].name).toEqual('Container ammo box 1m');
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -7,11 +7,11 @@ module.exports = Self => {
accessType: 'READ', accessType: 'READ',
accepts: [{ accepts: [{
arg: 'filter', arg: 'filter',
type: 'Object', type: 'object',
description: 'Filter defining where and paginated data' description: 'Filter defining where and paginated data'
}], }],
returns: { returns: {
type: ['Object'], type: ['object'],
root: true root: true
}, },
http: { http: {
@ -20,8 +20,13 @@ module.exports = Self => {
} }
}); });
Self.listSaleTracking = async filter => { Self.listSaleTracking = async(filter, options) => {
let stmt = new ParameterizedSQL(` const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const stmt = new ParameterizedSQL(`
SELECT SELECT
st.id, st.id,
s.ticketFk, s.ticketFk,
@ -41,9 +46,9 @@ module.exports = Self => {
stmt.merge(Self.makeSuffix(filter)); stmt.merge(Self.makeSuffix(filter));
let trackings = await Self.rawStmt(stmt); const trackings = await Self.rawStmt(stmt, myOptions);
let salesFilter = { const salesFilter = {
include: [ include: [
{ {
relation: 'item' relation: 'item'
@ -52,14 +57,14 @@ module.exports = Self => {
where: {ticketFk: filter.where.ticketFk} where: {ticketFk: filter.where.ticketFk}
}; };
let sales = await Self.app.models.Sale.find(salesFilter); const sales = await Self.app.models.Sale.find(salesFilter, myOptions);
trackings.forEach(tracking => { for (const tracking of trackings) {
sales.forEach(sale => { for (const sale of sales) {
if (tracking.itemFk == sale.itemFk) if (tracking.itemFk == sale.itemFk)
tracking.item = sale.item(); tracking.item = sale.item();
}); }
}); }
return trackings; return trackings;
}; };

View File

@ -1,17 +1,39 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('ticket listSaleTracking()', () => { describe('ticket listSaleTracking()', () => {
it('should call the listSaleTracking method and return the response', async() => { it('should call the listSaleTracking method and return the response', async() => {
let filter = {where: {ticketFk: 1}}; const tx = await models.SaleTracking.beginTransaction({});
let result = await app.models.SaleTracking.listSaleTracking(filter);
expect(result.length).toEqual(4); try {
const options = {transaction: tx};
const filter = {where: {ticketFk: 1}};
const result = await models.SaleTracking.listSaleTracking(filter, options);
expect(result.length).toEqual(4);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it(`should call the listSaleTracking method and return zero if doesn't have lines`, async() => { it(`should call the listSaleTracking method and return zero if doesn't have lines`, async() => {
let filter = {where: {ticketFk: 2}}; const tx = await models.SaleTracking.beginTransaction({});
let result = await app.models.SaleTracking.listSaleTracking(filter);
expect(result.length).toEqual(0); try {
const options = {transaction: tx};
const filter = {where: {ticketFk: 2}};
const result = await models.SaleTracking.listSaleTracking(filter, options);
expect(result.length).toEqual(0);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -1,4 +1,3 @@
module.exports = Self => { module.exports = Self => {
Self.remoteMethodCtx('editableStates', { Self.remoteMethodCtx('editableStates', {
description: 'Gets the editable states according the user role ', description: 'Gets the editable states according the user role ',
@ -8,7 +7,7 @@ module.exports = Self => {
type: 'object' type: 'object'
}, },
returns: { returns: {
type: ['Object'], type: ['object'],
root: true root: true
}, },
http: { http: {
@ -17,14 +16,18 @@ module.exports = Self => {
} }
}); });
Self.editableStates = async(ctx, filter) => { Self.editableStates = async(ctx, filter, options) => {
let userId = ctx.req.accessToken.userId; const models = Self.app.models;
let models = Self.app.models; const userId = ctx.req.accessToken.userId;
let statesList = await models.State.find({where: filter.where}); const myOptions = {};
let isProduction = await models.Account.hasRole(userId, 'production'); if (typeof options == 'object')
let isSalesPerson = await models.Account.hasRole(userId, 'salesPerson'); Object.assign(myOptions, options);
let isAdministrative = await models.Account.hasRole(userId, 'administrative');
let statesList = await models.State.find({where: filter.where}, myOptions);
const isProduction = await models.Account.hasRole(userId, 'production', myOptions);
const isSalesPerson = await models.Account.hasRole(userId, 'salesPerson', myOptions);
const isAdministrative = await models.Account.hasRole(userId, 'administrative', myOptions);
if (isProduction || isAdministrative) if (isProduction || isAdministrative)
return statesList; return statesList;

View File

@ -1,34 +1,73 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('ticket editableStates()', () => { describe('ticket editableStates()', () => {
const filter = {where: {name: {like: '%%'}}}; const filter = {where: {name: {like: '%%'}}};
it('should return the expected state for the given role', async() => { it('should return the expected state for the given role', async() => {
const productionRole = 49; const tx = await models.State.beginTransaction({});
const ctx = {req: {accessToken: {userId: productionRole}}};
let result = await app.models.State.editableStates(ctx, filter); try {
let deliveredState = result.some(state => state.code == 'DELIVERED'); const options = {transaction: tx};
expect(deliveredState).toBeTruthy(); const productionRole = 49;
const ctx = {req: {accessToken: {userId: productionRole}}};
const editableStates = await models.State.editableStates(ctx, filter, options);
const deliveredState = editableStates.some(state => state.code == 'DELIVERED');
expect(deliveredState).toBeTruthy();
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it(`should return the expected states by a specific role`, async() => { it(`should return the expected states by a specific role`, async() => {
const productionRole = 18; const tx = await models.State.beginTransaction({});
const ctx = {req: {accessToken: {userId: productionRole}}};
let result = await app.models.State.editableStates(ctx, filter);
let deliveredState = result.some(state => state.code == 'DELIVERED');
let pickerDesignedState = result.some(state => state.code == 'PICKER_DESIGNED');
expect(deliveredState).toBeFalsy(); try {
expect(pickerDesignedState).toBeTruthy(); const options = {transaction: tx};
const productionRole = 18;
const ctx = {req: {accessToken: {userId: productionRole}}};
const editableStates = await models.State.editableStates(ctx, filter, options);
const deliveredState = editableStates.some(state => state.code == 'DELIVERED');
const pickerDesignedState = editableStates.some(state => state.code == 'PICKER_DESIGNED');
expect(deliveredState).toBeFalsy();
expect(pickerDesignedState).toBeTruthy();
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it(`should return again the expected state by a specific role`, async() => { it(`should return again the expected state by a specific role`, async() => {
const employeeRole = 1; const tx = await models.State.beginTransaction({});
const ctx = {req: {accessToken: {userId: employeeRole}}};
let result = await app.models.State.editableStates(ctx, filter);
let pickerDesignedState = result.some(state => state.code == 'PICKER_DESIGNED');
expect(pickerDesignedState).toBeTruthy(); try {
const options = {transaction: tx};
const employeeRole = 1;
const ctx = {req: {accessToken: {userId: employeeRole}}};
const editableStates = await models.State.editableStates(ctx, filter, options);
const pickerDesignedState = editableStates.some(state => state.code == 'PICKER_DESIGNED');
expect(pickerDesignedState).toBeTruthy();
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -4,12 +4,12 @@ module.exports = Self => {
accessType: 'WRITE', accessType: 'WRITE',
accepts: { accepts: {
arg: 'id', arg: 'id',
type: 'Number', type: 'number',
description: 'The document id', description: 'The document id',
http: {source: 'path'} http: {source: 'path'}
}, },
returns: { returns: {
type: 'Object', type: 'object',
root: true root: true
}, },
http: { http: {
@ -18,16 +18,36 @@ module.exports = Self => {
} }
}); });
Self.removeFile = async(ctx, id) => { Self.removeFile = async(ctx, id, options) => {
const models = Self.app.models; const models = Self.app.models;
const targetTicketDms = await models.TicketDms.findById(id); const myOptions = {};
const targetDms = await models.Dms.findById(targetTicketDms.dmsFk); let tx;
const trashDmsType = await models.DmsType.findOne({where: {code: 'trash'}});
await models.Dms.removeFile(ctx, targetTicketDms.dmsFk); if (typeof options == 'object')
await targetTicketDms.destroy(); Object.assign(myOptions, options);
return targetDms.updateAttribute('dmsTypeFk', trashDmsType.id); if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
const targetTicketDms = await models.TicketDms.findById(id, null, myOptions);
const targetDms = await models.Dms.findById(targetTicketDms.dmsFk, null, myOptions);
const trashDmsType = await models.DmsType.findOne({where: {code: 'trash'}}, myOptions);
await models.Dms.removeFile(ctx, targetTicketDms.dmsFk, myOptions);
await targetTicketDms.destroy(myOptions);
await targetDms.updateAttribute('dmsTypeFk', trashDmsType.id, myOptions);
if (tx) await tx.commit();
return targetDms;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
}; };
}; };

View File

@ -1,18 +1,25 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('TicketDms removeFile()', () => { describe('TicketDms removeFile()', () => {
const ticketDmsId = 1; const ticketDmsId = 1;
it(`should return an error for a user without enough privileges`, async() => { it(`should return an error for a user without enough privileges`, async() => {
let clientId = 1101; const tx = await models.TicketDms.beginTransaction({});
let ctx = {req: {accessToken: {userId: clientId}}};
let error; let error;
await app.models.TicketDms.removeFile(ctx, ticketDmsId).catch(e => { try {
error = e; const options = {transaction: tx};
}).finally(() => {
expect(error.message).toEqual(`You don't have enough privileges`);
});
expect(error).toBeDefined(); const clientId = 1101;
const ctx = {req: {accessToken: {userId: clientId}}};
await models.TicketDms.removeFile(ctx, ticketDmsId, options);
await tx.rollback();
} catch (e) {
await tx.rollback();
error = e;
}
expect(error.message).toEqual(`You don't have enough privileges`);
}); });
}); });

View File

@ -6,22 +6,22 @@ module.exports = Self => {
accessType: 'WRITE', accessType: 'WRITE',
accepts: [{ accepts: [{
arg: 'id', arg: 'id',
type: 'Integer', type: 'number',
required: true, required: true,
description: 'The request ID', description: 'The request ID',
}, { }, {
arg: 'itemFk', arg: 'itemFk',
type: 'Integer', type: 'number',
required: true, required: true,
description: 'The requested item ID', description: 'The requested item ID',
}, { }, {
arg: 'quantity', arg: 'quantity',
type: 'Integer', type: 'number',
required: true, required: true,
description: 'The requested item quantity', description: 'The requested item quantity',
}], }],
returns: { returns: {
type: 'Object', type: 'object',
root: true root: true
}, },
http: { http: {
@ -30,25 +30,37 @@ module.exports = Self => {
} }
}); });
Self.confirm = async ctx => { Self.confirm = async(ctx, options) => {
const userId = ctx.req.accessToken.userId; const userId = ctx.req.accessToken.userId;
const models = Self.app.models; const models = Self.app.models;
const tx = await Self.beginTransaction({});
const $t = ctx.req.__; // $translate const $t = ctx.req.__; // $translate
let sale; const myOptions = {};
let tx;
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try { try {
let options = {transaction: tx}; const item = await models.Item.findById(ctx.args.itemFk, null, myOptions);
let item = await models.Item.findById(ctx.args.itemFk, null, options);
if (!item) if (!item)
throw new UserError(`That item doesn't exists`); throw new UserError(`That item doesn't exists`);
let request = await models.TicketRequest.findById(ctx.args.id, { const request = await models.TicketRequest.findById(ctx.args.id, {
include: {relation: 'ticket'} include: {relation: 'ticket'}
}, options); }, myOptions);
const itemStock = await models.Item.getVisibleAvailable(
ctx.args.itemFk,
request.ticket().warehouseFk,
request.ticket().shipped,
myOptions
);
const itemStock = await models.Item.getVisibleAvailable(ctx.args.itemFk, request.ticket().warehouseFk, request.ticket().shipped);
const isAvailable = itemStock.available > 0; const isAvailable = itemStock.available > 0;
if (!isAvailable) if (!isAvailable)
@ -57,23 +69,24 @@ module.exports = Self => {
if (request.saleFk) if (request.saleFk)
throw new UserError(`This request already contains a sale`); throw new UserError(`This request already contains a sale`);
sale = await models.Sale.create({ const sale = await models.Sale.create({
ticketFk: request.ticketFk, ticketFk: request.ticketFk,
itemFk: ctx.args.itemFk, itemFk: ctx.args.itemFk,
quantity: ctx.args.quantity, quantity: ctx.args.quantity,
concept: item.name concept: item.name
}, options); }, myOptions);
await request.updateAttributes({ await request.updateAttributes({
saleFk: sale.id, saleFk: sale.id,
itemFk: sale.itemFk, itemFk: sale.itemFk,
isOk: true isOk: true
}, options); }, myOptions);
query = `CALL vn.sale_calculateComponent(?, NULL)`; const query = `CALL vn.sale_calculateComponent(?, NULL)`;
await Self.rawSql(query, [sale.id], options); await Self.rawSql(query, [sale.id], myOptions);
const origin = ctx.req.headers.origin; const origin = ctx.req.headers.origin;
const requesterId = request.requesterFk; const requesterId = request.requesterFk;
const message = $t('Bought units from buy request', { const message = $t('Bought units from buy request', {
quantity: sale.quantity, quantity: sale.quantity,
concept: sale.concept, concept: sale.concept,
@ -82,10 +95,9 @@ module.exports = Self => {
url: `${origin}/#!/ticket/${sale.ticketFk}/summary`, url: `${origin}/#!/ticket/${sale.ticketFk}/summary`,
urlItem: `${origin}/#!/item/${sale.itemFk}/summary` urlItem: `${origin}/#!/item/${sale.itemFk}/summary`
}); });
await models.Chat.sendCheckingPresence(ctx, requesterId, message); await models.Chat.sendCheckingPresence(ctx, requesterId, message, myOptions);
// log const logRecord = {
let logRecord = {
originFk: sale.ticketFk, originFk: sale.ticketFk,
userFk: userId, userFk: userId,
action: 'update', action: 'update',
@ -99,14 +111,14 @@ module.exports = Self => {
} }
}; };
await Self.app.models.TicketLog.create(logRecord); await Self.app.models.TicketLog.create(logRecord, myOptions);
await tx.commit(); if (tx) await tx.commit();
return sale; return sale;
} catch (error) { } catch (e) {
await tx.rollback(); if (tx) await tx.rollback();
throw error; throw e;
} }
}; };
}; };

View File

@ -4,7 +4,7 @@ module.exports = Self => {
accessType: 'WRITE', accessType: 'WRITE',
accepts: [{ accepts: [{
arg: 'id', arg: 'id',
type: 'Integer', type: 'number',
required: true, required: true,
description: 'The request ID', description: 'The request ID',
}, { }, {
@ -23,17 +23,37 @@ module.exports = Self => {
} }
}); });
Self.deny = async ctx => { Self.deny = async(ctx, options) => {
let userId = ctx.req.accessToken.userId; const myOptions = {};
let worker = await Self.app.models.Worker.findOne({where: {userFk: userId}}); let tx;
let params = { if (typeof options == 'object')
isOk: false, Object.assign(myOptions, options);
attenderFk: worker.id,
response: ctx.args.observation,
};
let request = await Self.app.models.TicketRequest.findById(ctx.args.id); if (!myOptions.transaction) {
return request.updateAttributes(params); tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
const userId = ctx.req.accessToken.userId;
const worker = await Self.app.models.Worker.findOne({where: {userFk: userId}}, myOptions);
const params = {
isOk: false,
attenderFk: worker.id,
response: ctx.args.observation,
};
const request = await Self.app.models.TicketRequest.findById(ctx.args.id, null, myOptions);
await request.updateAttributes(params, myOptions);
if (tx) await tx.commit();
return request;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
}; };
}; };

View File

@ -68,9 +68,13 @@ module.exports = Self => {
} }
}); });
Self.filter = async(ctx, filter) => { Self.filter = async(ctx, filter, options) => {
let conn = Self.dataSource.connector; const conn = Self.dataSource.connector;
let userId = ctx.req.accessToken.userId; const userId = ctx.req.accessToken.userId;
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
if (ctx.args.mine) if (ctx.args.mine)
ctx.args.attenderFk = userId; ctx.args.attenderFk = userId;
@ -111,9 +115,7 @@ module.exports = Self => {
filter = mergeFilters(filter, {where}); filter = mergeFilters(filter, {where});
let stmt; const stmt = new ParameterizedSQL(
stmt = new ParameterizedSQL(
`SELECT `SELECT
tr.id, tr.id,
tr.ticketFk, tr.ticketFk,
@ -149,8 +151,6 @@ module.exports = Self => {
LEFT JOIN account.user ua ON ua.id = wka.userFk`); LEFT JOIN account.user ua ON ua.id = wka.userFk`);
stmt.merge(conn.makeSuffix(filter)); stmt.merge(conn.makeSuffix(filter));
let result = await conn.executeStmt(stmt); return conn.executeStmt(stmt, myOptions);
return result;
}; };
}; };

View File

@ -1,4 +1,4 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('ticket-request confirm()', () => { describe('ticket-request confirm()', () => {
let ctx = { let ctx = {
@ -12,74 +12,89 @@ describe('ticket-request confirm()', () => {
}; };
it(`should throw an error if the item doesn't exist`, async() => { it(`should throw an error if the item doesn't exist`, async() => {
ctx.args = {itemFk: 999}; const tx = await models.TicketRequest.beginTransaction({});
let error; let error;
try { try {
await app.models.TicketRequest.confirm(ctx); const options = {transaction: tx};
} catch (err) {
error = err; ctx.args = {itemFk: 999};
await models.TicketRequest.confirm(ctx, options);
await tx.rollback();
} catch (e) {
await tx.rollback();
error = e;
} }
expect(error.message).toEqual(`That item doesn't exists`); expect(error.message).toEqual(`That item doesn't exists`);
}); });
it('should throw an error if the item is not available', async() => { it('should throw an error if the item is not available', async() => {
const requestId = 5; const tx = await models.TicketRequest.beginTransaction({});
const itemId = 4;
const quantity = 99999;
ctx.args = {
itemFk: itemId,
id: requestId,
quantity: quantity
};
let error; let error;
try { try {
await app.models.TicketRequest.confirm(ctx); const options = {transaction: tx};
} catch (err) {
error = err; const requestId = 5;
const itemId = 4;
const quantity = 99999;
ctx.args = {
itemFk: itemId,
id: requestId,
quantity: quantity
};
await models.TicketRequest.confirm(ctx, options);
await tx.rollback();
} catch (e) {
await tx.rollback();
error = e;
} }
expect(error.message).toEqual(`This item is not available`); expect(error.message).toEqual(`This item is not available`);
}); });
it(`should throw if there's a sale id`, async() => { it(`should throw if there's a sale id`, async() => {
const requestId = 4; const tx = await models.TicketRequest.beginTransaction({});
const itemId = 1;
const quantity = 10;
ctx.args = {
itemFk: itemId,
id: requestId,
quantity: quantity
};
const request = await app.models.TicketRequest.findById(requestId);
expect(request.saleFk).toBeNull();
await request.updateAttributes({saleFk: 2});
ctx.args = {
itemFk: itemId,
id: requestId,
quantity: quantity
};
let error; let error;
try { try {
await app.models.TicketRequest.confirm(ctx); const options = {transaction: tx};
} catch (err) {
error = err; const requestId = 4;
const itemId = 1;
const quantity = 10;
ctx.args = {
itemFk: itemId,
id: requestId,
quantity: quantity
};
const request = await models.TicketRequest.findById(requestId, null, options);
expect(request.saleFk).toBeNull();
await request.updateAttributes({saleFk: 2}, options);
ctx.args = {
itemFk: itemId,
id: requestId,
quantity: quantity
};
await models.TicketRequest.confirm(ctx, options);
await tx.rollback();
} catch (e) {
await tx.rollback();
error = e;
} }
expect(error.message).toEqual(`This request already contains a sale`); expect(error.message).toEqual(`This request already contains a sale`);
// restores
await request.updateAttributes({saleFk: null});
}); });
}); });

View File

@ -1,25 +1,22 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('ticket-request deny()', () => { describe('ticket-request deny()', () => {
let request; it('should return the dinied ticket request', async() => {
afterAll(async done => { const tx = await models.TicketRequest.beginTransaction({});
let params = {
isOk: null,
attenderFk: request.attenderFk,
response: null,
};
await request.updateAttributes(params); try {
done(); const options = {transaction: tx};
});
it('should return all ticket requests', async() => { const ctx = {req: {accessToken: {userId: 9}}, args: {id: 4, observation: 'my observation'}};
let ctx = {req: {accessToken: {userId: 9}}, args: {id: 4, observation: 'my observation'}};
request = await app.models.TicketRequest.findById(ctx.args.id); const result = await models.TicketRequest.deny(ctx, options);
let result = await app.models.TicketRequest.deny(ctx); expect(result.id).toEqual(4);
expect(result.id).toEqual(4); await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -1,85 +1,184 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('ticket-request filter()', () => { describe('ticket-request filter()', () => {
const userId = 9; const userId = 9;
let ctx = {req: {accessToken: {userId: userId}}}; let ctx = {req: {accessToken: {userId: userId}}};
it('should now return all ticket requests', async() => { it('should now return all ticket requests', async() => {
ctx.args = {}; const tx = await models.TicketRequest.beginTransaction({});
const result = await app.models.TicketRequest.filter(ctx); try {
const options = {transaction: tx};
expect(result.length).toEqual(3); ctx.args = {};
const result = await models.TicketRequest.filter(ctx, options);
expect(result.length).toEqual(3);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return the ticket request matching a generic search value which is the ticket ID', async() => { it('should return the ticket request matching a generic search value which is the ticket ID', async() => {
ctx.args = {search: 11}; const tx = await models.TicketRequest.beginTransaction({});
const result = await app.models.TicketRequest.filter(ctx); try {
const requestId = result[0].id; const options = {transaction: tx};
expect(requestId).toEqual(4); ctx.args = {search: 11};
const result = await models.TicketRequest.filter(ctx, options);
const requestId = result[0].id;
expect(requestId).toEqual(4);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return the ticket request matching a generic search value which is the client address alias', async() => { it('should return the ticket request matching a generic search value which is the client address alias', async() => {
ctx.args = {search: 'NY roofs'}; const tx = await models.TicketRequest.beginTransaction({});
const result = await app.models.TicketRequest.filter(ctx); try {
const requestId = result[0].id; const options = {transaction: tx};
expect(requestId).toEqual(4); ctx.args = {search: 'NY roofs'};
const result = await models.TicketRequest.filter(ctx, options);
const requestId = result[0].id;
expect(requestId).toEqual(4);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return the ticket request matching the ticket ID', async() => { it('should return the ticket request matching the ticket ID', async() => {
ctx.args = {ticketFk: 11}; const tx = await models.TicketRequest.beginTransaction({});
const result = await app.models.TicketRequest.filter(ctx);
const requestId = result[0].id;
expect(requestId).toEqual(4); try {
const options = {transaction: tx};
ctx.args = {ticketFk: 11};
const result = await models.TicketRequest.filter(ctx, options);
const requestId = result[0].id;
expect(requestId).toEqual(4);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return the ticket request matching the atender ID', async() => { it('should return the ticket request matching the atender ID', async() => {
ctx.args = {attenderFk: 35}; const tx = await models.TicketRequest.beginTransaction({});
const result = await app.models.TicketRequest.filter(ctx); try {
const requestId = result[0].id; const options = {transaction: tx};
expect(requestId).toEqual(3); ctx.args = {attenderFk: 35};
const result = await models.TicketRequest.filter(ctx, options);
const requestId = result[0].id;
expect(requestId).toEqual(3);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return the ticket request matching the isOk triple-state', async() => { it('should return the ticket request matching the isOk triple-state', async() => {
ctx.args = {isOk: null}; const tx = await models.TicketRequest.beginTransaction({});
const result = await app.models.TicketRequest.filter(ctx); try {
const requestId = result[0].id; const options = {transaction: tx};
expect(requestId).toEqual(3); ctx.args = {isOk: null};
const result = await models.TicketRequest.filter(ctx, options);
const requestId = result[0].id;
expect(requestId).toEqual(3);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return the ticket request matching the client ID', async() => { it('should return the ticket request matching the client ID', async() => {
ctx.args = {clientFk: 1102}; const tx = await models.TicketRequest.beginTransaction({});
const result = await app.models.TicketRequest.filter(ctx); try {
const requestId = result[0].id; const options = {transaction: tx};
expect(requestId).toEqual(4); ctx.args = {clientFk: 1102};
const result = await models.TicketRequest.filter(ctx, options);
const requestId = result[0].id;
expect(requestId).toEqual(4);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return the ticket request matching the warehouse ID', async() => { it('should return the ticket request matching the warehouse ID', async() => {
ctx.args = {warehouse: 1}; const tx = await models.TicketRequest.beginTransaction({});
const result = await app.models.TicketRequest.filter(ctx, {order: 'id'}); try {
const requestId = result[0].id; const options = {transaction: tx};
expect(requestId).toEqual(3); ctx.args = {warehouse: 1};
const result = await models.TicketRequest.filter(ctx, {order: 'id'}, options);
const requestId = result[0].id;
expect(requestId).toEqual(3);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return the ticket request matching the salesPerson ID', async() => { it('should return the ticket request matching the salesPerson ID', async() => {
ctx.args = {salesPersonFk: 18}; const tx = await models.TicketRequest.beginTransaction({});
const result = await app.models.TicketRequest.filter(ctx); try {
const requestId = result[0].id; const options = {transaction: tx};
expect(requestId).toEqual(3); ctx.args = {salesPersonFk: 18};
const result = await models.TicketRequest.filter(ctx, options);
const requestId = result[0].id;
expect(requestId).toEqual(3);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -6,13 +6,13 @@ module.exports = Self => {
{ {
arg: 'ticketIds', arg: 'ticketIds',
description: 'the array of ticket ids to set as delivered', description: 'the array of ticket ids to set as delivered',
type: ['Number'], type: ['number'],
required: true, required: true,
http: {source: 'body'} http: {source: 'body'}
} }
], ],
returns: { returns: {
type: 'Object', type: 'object',
root: true root: true
}, },
http: { http: {
@ -21,30 +21,47 @@ module.exports = Self => {
} }
}); });
Self.setDelivered = async(ctx, ticketIds) => { Self.setDelivered = async(ctx, ticketIds, options) => {
let userId = ctx.req.accessToken.userId; const userId = ctx.req.accessToken.userId;
let models = Self.app.models; const models = Self.app.models;
const myOptions = {};
let tx;
let state = await models.State.findOne({ if (typeof options == 'object')
where: { Object.assign(myOptions, options);
code: 'delivered'
},
fields: ['id', 'name', 'alertLevel', 'code']
});
let worker = await models.Worker.findOne({where: {userFk: userId}}); if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
let promises = []; myOptions.transaction = tx;
for (let id of ticketIds) {
let promise = models.TicketTracking.changeState(ctx, {
stateFk: state.id,
workerFk: worker.id,
ticketFk: id
});
promises.push(promise);
} }
await Promise.all(promises);
return state; try {
const state = await models.State.findOne({
where: {
code: 'delivered'
},
fields: ['id', 'name', 'alertLevel', 'code']
}, myOptions);
const worker = await models.Worker.findOne({where: {userFk: userId}}, myOptions);
const promises = [];
for (const id of ticketIds) {
const promise = models.TicketTracking.changeState(ctx, {
stateFk: state.id,
workerFk: worker.id,
ticketFk: id
}, myOptions);
promises.push(promise);
}
await Promise.all(promises);
if (tx) await tx.commit();
return state;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
}; };
}; };

View File

@ -1,4 +1,4 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context'); const LoopBackContext = require('loopback-context');
describe('ticket setDelivered()', () => { describe('ticket setDelivered()', () => {
@ -7,50 +7,41 @@ describe('ticket setDelivered()', () => {
accessToken: {userId: userId}, accessToken: {userId: userId},
}; };
let ticketOne;
let ticketTwo;
beforeAll(async done => { beforeAll(async done => {
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx active: activeCtx
}); });
try {
let originalTicketOne = await app.models.Ticket.findById(8);
let originalTicketTwo = await app.models.Ticket.findById(10);
originalTicketOne.id = null;
originalTicketTwo.id = null;
ticketOne = await app.models.Ticket.create(originalTicketOne);
ticketTwo = await app.models.Ticket.create(originalTicketTwo);
} catch (error) {
console.error(error);
}
done();
});
afterAll(async done => {
try {
await app.models.Ticket.destroyById(ticketOne.id);
await app.models.Ticket.destroyById(ticketTwo.id);
} catch (error) {
console.error(error);
}
done(); done();
}); });
it('should return the state which has been applied to the given tickets', async() => { it('should return the state which has been applied to the given tickets', async() => {
let ctx = {req: {accessToken: {userId: 49}}}; const tx = await models.TicketTracking.beginTransaction({});
let delivered = await app.models.State.findOne({where: {code: 'delivered'}, fields: ['id']});
let params = [ticketOne.id, ticketTwo.id]; try {
let state = await app.models.TicketTracking.setDelivered(ctx, params); const options = {transaction: tx};
expect(state.id).toEqual(delivered.id); const ctx = {req: {accessToken: {userId: 49}}};
// restores const originalTicketOne = await models.Ticket.findById(8, null, options);
await app.models.TicketTracking.destroyById(state.id); const originalTicketTwo = await models.Ticket.findById(10, null, options);
originalTicketOne.id = null;
originalTicketTwo.id = null;
const ticketOne = await models.Ticket.create(originalTicketOne, options);
const ticketTwo = await models.Ticket.create(originalTicketTwo, options);
const delivered = await models.State.findOne({where: {code: 'delivered'}, fields: ['id']}, options);
const params = [ticketOne.id, ticketTwo.id];
const state = await models.TicketTracking.setDelivered(ctx, params, options);
expect(state.id).toEqual(delivered.id);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -10,18 +10,18 @@ module.exports = Self => {
accepts: [ accepts: [
{ {
arg: 'filter', arg: 'filter',
type: 'Object', type: 'object',
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string', description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string',
http: {source: 'query'} http: {source: 'query'}
}, { }, {
arg: 'search', arg: 'search',
type: 'String', type: 'string',
description: `If it's and integer searchs by id, otherwise it searchs by client id`, description: `If it's and integer searchs by id, otherwise it searchs by client id`,
http: {source: 'query'} http: {source: 'query'}
} }
], ],
returns: { returns: {
type: ['Object'], type: ['object'],
root: true root: true
}, },
http: { http: {
@ -30,10 +30,14 @@ module.exports = Self => {
} }
}); });
Self.filter = async(ctx, filter) => { Self.filter = async(ctx, filter, options) => {
let conn = Self.dataSource.connector; const conn = Self.dataSource.connector;
const myOptions = {};
let where = buildFilter(ctx.args, (param, value) => { if (typeof options == 'object')
Object.assign(myOptions, options);
const where = buildFilter(ctx.args, (param, value) => {
switch (param) { switch (param) {
case 'search': case 'search':
return {or: [ return {or: [
@ -46,10 +50,9 @@ module.exports = Self => {
filter = mergeFilters(ctx.args.filter, {where}); filter = mergeFilters(ctx.args.filter, {where});
let stmts = []; const stmts = [];
let stmt;
stmt = new ParameterizedSQL( const stmt = new ParameterizedSQL(
`SELECT t.id AS ticketFk, c.id AS clientFk, c.name AS clientName, tw.weekDay, `SELECT t.id AS ticketFk, c.id AS clientFk, c.name AS clientName, tw.weekDay,
wh.name AS warehouseName, u.id AS workerFk, u.name AS userName, u.nickName, tw.agencyModeFk wh.name AS warehouseName, u.id AS workerFk, u.name AS userName, u.nickName, tw.agencyModeFk
FROM ticketWeekly tw FROM ticketWeekly tw
@ -60,10 +63,10 @@ module.exports = Self => {
); );
stmt.merge(conn.makeSuffix(filter)); stmt.merge(conn.makeSuffix(filter));
let itemsIndex = stmts.push(stmt) - 1; const itemsIndex = stmts.push(stmt) - 1;
let sql = ParameterizedSQL.join(stmts, ';'); const sql = ParameterizedSQL.join(stmts, ';');
let result = await conn.executeStmt(sql); const result = await conn.executeStmt(sql, myOptions);
return itemsIndex === 0 ? result : result[itemsIndex]; return itemsIndex === 0 ? result : result[itemsIndex];
}; };
}; };

View File

@ -1,43 +1,89 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('ticket-weekly filter()', () => { describe('ticket-weekly filter()', () => {
const authUserId = 9; const authUserId = 9;
it('should all return the tickets matching the filter', async() => { it('should all return the tickets matching the filter', async() => {
const filter = {order: 't.id ASC'}; const tx = await models.TicketWeekly.beginTransaction({});
const ctx = {req: {accessToken: {userId: authUserId}}, args: {filter: filter}};
const result = await app.models.TicketWeekly.filter(ctx);
const firstRow = result[0]; try {
const options = {transaction: tx};
expect(firstRow.ticketFk).toEqual(1); const filter = {order: 't.id ASC'};
expect(result.length).toEqual(5);
const ctx = {req: {accessToken: {userId: authUserId}}, args: {filter: filter}};
const result = await models.TicketWeekly.filter(ctx, null, options);
const firstRow = result[0];
expect(firstRow.ticketFk).toEqual(1);
expect(result.length).toEqual(5);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return the ticket with id one', async() => { it('should return the ticket with id one', async() => {
const ctx = {req: {accessToken: {userId: authUserId}}, args: {search: 2}}; const tx = await models.TicketWeekly.beginTransaction({});
const filter = {};
const result = await app.models.TicketWeekly.filter(ctx, filter);
const firstRow = result[0];
expect(firstRow.ticketFk).toEqual(2); try {
const options = {transaction: tx};
const ctx = {req: {accessToken: {userId: authUserId}}, args: {search: 2}};
const result = await models.TicketWeekly.filter(ctx, null, options);
const firstRow = result[0];
expect(firstRow.ticketFk).toEqual(2);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return the ticket matching the client name', async() => { it('should return the ticket matching the client name', async() => {
const ctx = {req: {accessToken: {userId: authUserId}}, args: {search: 'bruce'}}; const tx = await models.TicketWeekly.beginTransaction({});
const filter = {};
const result = await app.models.TicketWeekly.filter(ctx, filter);
const firstRow = result[0];
expect(firstRow.clientName).toEqual('Bruce Wayne'); try {
const options = {transaction: tx};
const ctx = {req: {accessToken: {userId: authUserId}}, args: {search: 'bruce'}};
const result = await models.TicketWeekly.filter(ctx, null, options);
const firstRow = result[0];
expect(firstRow.clientName).toEqual('Bruce Wayne');
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return the ticket matching the client id', async() => { it('should return the ticket matching the client id', async() => {
const ctx = {req: {accessToken: {userId: authUserId}}, args: {search: 1101}}; const tx = await models.TicketWeekly.beginTransaction({});
const filter = {};
const result = await app.models.TicketWeekly.filter(ctx, filter);
const firstRow = result[0];
expect(firstRow.clientFk).toEqual(1101); try {
expect(firstRow.clientName).toEqual('Bruce Wayne'); const options = {transaction: tx};
const ctx = {req: {accessToken: {userId: authUserId}}, args: {search: 1101}};
const result = await models.TicketWeekly.filter(ctx, null, options);
const firstRow = result[0];
expect(firstRow.clientFk).toEqual(1101);
expect(firstRow.clientName).toEqual('Bruce Wayne');
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });