refactor(sale): ticket.sale endpoints now use transactions

This commit is contained in:
Carlos Jimenez Ruiz 2021-09-29 08:27:18 +02:00
parent e690febc7f
commit 392c4dcba3
15 changed files with 589 additions and 395 deletions

View File

@ -26,11 +26,22 @@ module.exports = Self => {
} }
}); });
Self.deleteSales = async(ctx, sales, ticketId) => { Self.deleteSales = async(ctx, sales, ticketId, options) => {
const $t = ctx.req.__; // $translate const $t = ctx.req.__; // $translate
const models = Self.app.models; const models = Self.app.models;
const myOptions = {};
let tx;
const canEditSales = await models.Sale.canEdit(ctx, sales); if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
const canEditSales = await models.Sale.canEdit(ctx, sales, myOptions);
const ticket = await models.Ticket.findById(ticketId, { const ticket = await models.Ticket.findById(ticketId, {
include: { include: {
@ -44,9 +55,9 @@ module.exports = Self => {
} }
} }
} }
}); }, myOptions);
const isTicketEditable = await models.Ticket.isEditable(ctx, ticketId); const isTicketEditable = await models.Ticket.isEditable(ctx, ticketId, myOptions);
if (!isTicketEditable) if (!isTicketEditable)
throw new UserError(`The sales of this ticket can't be modified`); throw new UserError(`The sales of this ticket can't be modified`);
@ -56,7 +67,7 @@ module.exports = Self => {
const promises = []; const promises = [];
let deletions = ''; let deletions = '';
for (let sale of sales) { for (let sale of sales) {
const deletedSale = models.Sale.destroyById(sale.id); const deletedSale = models.Sale.destroyById(sale.id, myOptions);
deletions += `\r\n-${sale.itemFk}: ${sale.concept} (${sale.quantity})`; deletions += `\r\n-${sale.itemFk}: ${sale.concept} (${sale.quantity})`;
promises.push(deletedSale); promises.push(deletedSale);
@ -71,9 +82,17 @@ module.exports = Self => {
ticketUrl: `${origin}/#!/ticket/${ticketId}/sale`, ticketUrl: `${origin}/#!/ticket/${ticketId}/sale`,
deletions: deletions deletions: deletions
}); });
await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message); await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message, myOptions);
} }
return Promise.all(promises); const deletedSales = await Promise.all(promises);
if (tx) await tx.commit();
return deletedSales;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
}; };
}; };

View File

@ -18,8 +18,14 @@ module.exports = Self => {
} }
}); });
Self.getClaimableFromTicket = async ticketFk => { Self.getClaimableFromTicket = async(ticketFk, options) => {
let query = `SELECT const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const query = `
SELECT
s.id AS saleFk, s.id AS saleFk,
t.id AS ticketFk, t.id AS ticketFk,
t.landed, t.landed,
@ -37,7 +43,7 @@ module.exports = Self => {
AND t.id = ? AND cb.id IS NULL AND t.id = ? AND cb.id IS NULL
ORDER BY t.landed DESC, t.id DESC`; ORDER BY t.landed DESC, t.id DESC`;
let claimableSales = await Self.rawSql(query, [ticketFk]); const claimableSales = await Self.rawSql(query, [ticketFk], myOptions);
return claimableSales; return claimableSales;
}; };

View File

@ -20,20 +20,39 @@ module.exports = Self => {
} }
}); });
Self.recalculatePrice = async(ctx, id) => { Self.recalculatePrice = async(ctx, id, options) => {
const models = Self.app.models; const models = Self.app.models;
const myOptions = {};
let tx;
const sale = await Self.findById(id); if (typeof options == 'object')
const isEditable = await models.Ticket.isEditable(ctx, sale.ticketFk); Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
const sale = await Self.findById(id, null, myOptions);
const isEditable = await models.Ticket.isEditable(ctx, sale.ticketFk, myOptions);
if (!isEditable) if (!isEditable)
throw new UserError(`The sales of this ticket can't be modified`); throw new UserError(`The sales of this ticket can't be modified`);
const canEditSale = await models.Sale.canEdit(ctx, [id]); const canEditSale = await models.Sale.canEdit(ctx, [id], myOptions);
if (!canEditSale) if (!canEditSale)
throw new UserError(`Sale(s) blocked, please contact production`); throw new UserError(`Sale(s) blocked, please contact production`);
return Self.rawSql('CALL vn.sale_calculateComponent(?, null)', [id]); const recalculation = await Self.rawSql('CALL vn.sale_calculateComponent(?, null)', [id], myOptions);
if (tx) await tx.commit();
return recalculation;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
}; };
}; };

View File

@ -34,15 +34,26 @@ module.exports = Self => {
} }
}); });
Self.reserve = async(ctx, ticketId, sales, reserved) => { Self.reserve = async(ctx, ticketId, sales, reserved, options) => {
const $t = ctx.req.__; // $translate const $t = ctx.req.__; // $translate
const models = Self.app.models; const models = Self.app.models;
const myOptions = {};
let tx;
const isTicketEditable = await models.Ticket.isEditable(ctx, ticketId); if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
const isTicketEditable = await models.Ticket.isEditable(ctx, ticketId, myOptions);
if (!isTicketEditable) if (!isTicketEditable)
throw new UserError(`The sales of this ticket can't be modified`); throw new UserError(`The sales of this ticket can't be modified`);
const canEditSale = await models.Sale.canEdit(ctx, sales); const canEditSale = await models.Sale.canEdit(ctx, sales, myOptions);
if (!canEditSale) if (!canEditSale)
throw new UserError(`Sale(s) blocked, please contact production`); throw new UserError(`Sale(s) blocked, please contact production`);
@ -55,7 +66,7 @@ module.exports = Self => {
const oldState = sale.reserved ? 'reserved' : 'regular'; const oldState = sale.reserved ? 'reserved' : 'regular';
const newState = reserved ? 'reserved' : 'regular'; const newState = reserved ? 'reserved' : 'regular';
const reservedSale = models.Sale.update({id: sale.id}, {reserved: reserved}); const reservedSale = models.Sale.updateAll({id: sale.id}, {reserved: reserved}, myOptions);
promises.push(reservedSale); promises.push(reservedSale);
@ -77,7 +88,7 @@ module.exports = Self => {
} }
} }
} }
}); }, myOptions);
const salesPerson = ticket.client().salesPersonUser(); const salesPerson = ticket.client().salesPersonUser();
if (salesPerson) { if (salesPerson) {
@ -88,9 +99,15 @@ module.exports = Self => {
ticketUrl: `${origin}/#!/ticket/${ticketId}/sale`, ticketUrl: `${origin}/#!/ticket/${ticketId}/sale`,
changes: changesMade changes: changesMade
}); });
await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message); await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message, myOptions);
} }
if (tx) await tx.commit();
return result; return result;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
}; };
}; };

View File

@ -1,36 +1,69 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('sale canEdit()', () => { describe('sale canEdit()', () => {
it('should return true if the role is production regardless of the saleTrackings', async() => { it('should return true if the role is production regardless of the saleTrackings', async() => {
const tx = await models.Sale.beginTransaction({});
try {
const options = {transaction: tx};
const productionUserID = 49; const productionUserID = 49;
let ctx = {req: {accessToken: {userId: productionUserID}}}; const ctx = {req: {accessToken: {userId: productionUserID}}};
const sales = [{id: 3}]; const sales = [{id: 3}];
const result = await app.models.Sale.canEdit(ctx, sales); const result = await models.Sale.canEdit(ctx, sales, options);
expect(result).toEqual(true); expect(result).toEqual(true);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return true if the role is not production and none of the sales has saleTracking', async() => { it('should return true if the role is not production and none of the sales has saleTracking', async() => {
const tx = await models.Sale.beginTransaction({});
try {
const options = {transaction: tx};
const salesPersonUserID = 18; const salesPersonUserID = 18;
let ctx = {req: {accessToken: {userId: salesPersonUserID}}}; const ctx = {req: {accessToken: {userId: salesPersonUserID}}};
const sales = [{id: 10}]; const sales = [{id: 10}];
const result = await app.models.Sale.canEdit(ctx, sales); const result = await models.Sale.canEdit(ctx, sales, options);
expect(result).toEqual(true); expect(result).toEqual(true);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return false if any of the sales has a saleTracking record', async() => { it('should return false if any of the sales has a saleTracking record', async() => {
const tx = await models.Sale.beginTransaction({});
try {
const options = {transaction: tx};
const salesPersonUserID = 18; const salesPersonUserID = 18;
let ctx = {req: {accessToken: {userId: salesPersonUserID}}}; const ctx = {req: {accessToken: {userId: salesPersonUserID}}};
const sales = [{id: 3}]; const sales = [{id: 3}];
const result = await app.models.Sale.canEdit(ctx, sales); const result = await models.Sale.canEdit(ctx, sales, options);
expect(result).toEqual(false); expect(result).toEqual(false);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -1,23 +1,14 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('sale deleteSales()', () => { describe('sale deleteSales()', () => {
let sale;
let newSale;
beforeAll(async done => {
try {
sale = await app.models.Sale.findOne({where: {id: 9}});
sale.id = null;
newSale = await app.models.Sale.create(sale);
} catch (error) {
console.error(error);
}
done();
});
it('should throw an error if the ticket of the given sales is not editable', async() => { it('should throw an error if the ticket of the given sales is not editable', async() => {
let ctx = { const tx = await models.Sale.beginTransaction({});
let error;
try {
const options = {transaction: tx};
const ctx = {
req: { req: {
accessToken: {userId: 9}, accessToken: {userId: 9},
headers: {origin: 'localhost:5000'}, headers: {origin: 'localhost:5000'},
@ -25,14 +16,14 @@ describe('sale deleteSales()', () => {
} }
}; };
let error;
const sales = [{id: 1, instance: 0}, {id: 2, instance: 1}]; const sales = [{id: 1, instance: 0}, {id: 2, instance: 1}];
const ticketId = 2; const ticketId = 2;
try { await models.Sale.deleteSales(ctx, sales, ticketId, options);
await app.models.Sale.deleteSales(ctx, sales, ticketId);
await tx.rollback();
} catch (e) { } catch (e) {
await tx.rollback();
error = e; error = e;
} }
@ -40,19 +31,33 @@ describe('sale deleteSales()', () => {
}); });
it('should delete the sale', async() => { it('should delete the sale', async() => {
let ctx = { const tx = await models.Sale.beginTransaction({});
try {
const options = {transaction: tx};
const ctx = {
req: { req: {
accessToken: {userId: 9}, accessToken: {userId: 9},
headers: {origin: 'localhost:5000'}, headers: {origin: 'localhost:5000'},
__: () => {} __: () => {}
} }
}; };
const sale = await models.Sale.findOne({where: {id: 9}}, options);
sale.id = null;
const newSale = await models.Sale.create(sale, options);
const sales = [{id: newSale.id, instance: 0}]; const sales = [{id: newSale.id, instance: 0}];
const ticketId = 16; const ticketId = 16;
let res = await app.models.Sale.deleteSales(ctx, sales, ticketId); const deletions = await models.Sale.deleteSales(ctx, sales, ticketId, options);
expect(res).toEqual([{count: 1}]); expect(deletions).toEqual([{count: 1}]);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -1,10 +1,21 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('sale getClaimableFromTicket()', () => { describe('sale getClaimableFromTicket()', () => {
it('should return the claimable sales of a given ticket', async() => { it('should return the claimable sales of a given ticket', async() => {
let claimableFromTicket = await app.models.Sale.getClaimableFromTicket(16); const tx = await models.Sale.beginTransaction({});
try {
const options = {transaction: tx};
const claimableFromTicket = await models.Sale.getClaimableFromTicket(16, options);
expect(claimableFromTicket[0].concept).toBe('Ranged weapon longbow 2m'); expect(claimableFromTicket[0].concept).toBe('Ranged weapon longbow 2m');
expect(claimableFromTicket.length).toBe(3); expect(claimableFromTicket.length).toBe(3);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -1,24 +1,43 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('sale recalculatePrice()', () => { describe('sale recalculatePrice()', () => {
const saleId = 7; const saleId = 7;
it('should update the sale price', async() => { it('should update the sale price', async() => {
const tx = await models.Sale.beginTransaction({});
try {
const options = {transaction: tx};
const ctx = {req: {accessToken: {userId: 9}}}; const ctx = {req: {accessToken: {userId: 9}}};
const response = await app.models.Sale.recalculatePrice(ctx, saleId); const response = await models.Sale.recalculatePrice(ctx, saleId, options);
expect(response.affectedRows).toBeDefined(); expect(response.affectedRows).toBeDefined();
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should throw an error if the ticket is not editable', async() => { it('should throw an error if the ticket is not editable', async() => {
const tx = await models.Sale.beginTransaction({});
let error;
try {
const options = {transaction: tx};
const ctx = {req: {accessToken: {userId: 9}}}; const ctx = {req: {accessToken: {userId: 9}}};
const immutableSaleId = 1; const immutableSaleId = 1;
await app.models.Sale.recalculatePrice(ctx, immutableSaleId) await models.Sale.recalculatePrice(ctx, immutableSaleId, options);
.catch(response => {
expect(response).toEqual(new Error(`The sales of this ticket can't be modified`));
error = response;
});
expect(error).toBeDefined(); await tx.rollback();
} catch (e) {
await tx.rollback();
error = e;
}
expect(error).toEqual(new Error(`The sales of this ticket can't be modified`));
}); });
}); });

View File

@ -1,4 +1,4 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('sale reserve()', () => { describe('sale reserve()', () => {
const ctx = { const ctx = {
@ -9,38 +9,35 @@ describe('sale reserve()', () => {
} }
}; };
afterAll(async done => {
let ctx = {req: {accessToken: {userId: 9}}};
let params = {
sales: [
{id: 7},
{id: 8}],
ticketFk: 11,
reserved: false
};
await app.models.Sale.reserve(ctx, params);
done();
});
it('should throw an error if the ticket can not be modified', async() => { it('should throw an error if the ticket can not be modified', async() => {
const tx = await models.Sale.beginTransaction({});
let error; let error;
try {
const options = {transaction: tx};
const ticketId = 2; const ticketId = 2;
const sales = [{id: 5}]; const sales = [{id: 5}];
const reserved = false; const reserved = false;
await app.models.Sale.reserve(ctx, ticketId, sales, reserved) await models.Sale.reserve(ctx, ticketId, sales, reserved, options);
.catch(response => {
expect(response).toEqual(new Error(`The sales of this ticket can't be modified`));
error = response;
});
expect(error).toBeDefined(); await tx.rollback();
} catch (e) {
await tx.rollback();
error = e;
}
expect(error).toEqual(new Error(`The sales of this ticket can't be modified`));
}); });
it('should update the given sales of a ticket to reserved', async() => { it('should update the given sales of a ticket to reserved', async() => {
originalTicketSales = await app.models.Ticket.getSales(11); const tx = await models.Sale.beginTransaction({});
try {
const options = {transaction: tx};
originalTicketSales = await models.Ticket.getSales(11, options);
expect(originalTicketSales[0].reserved).toEqual(false); expect(originalTicketSales[0].reserved).toEqual(false);
expect(originalTicketSales[1].reserved).toEqual(false); expect(originalTicketSales[1].reserved).toEqual(false);
@ -49,11 +46,17 @@ describe('sale reserve()', () => {
const sales = [{id: 7}, {id: 8}]; const sales = [{id: 7}, {id: 8}];
const reserved = true; const reserved = true;
await app.models.Sale.reserve(ctx, ticketId, sales, reserved); await models.Sale.reserve(ctx, ticketId, sales, reserved, options);
const reservedTicketSales = await app.models.Ticket.getSales(ticketId); const reservedTicketSales = await models.Ticket.getSales(ticketId, options);
expect(reservedTicketSales[0].reserved).toEqual(true); expect(reservedTicketSales[0].reserved).toEqual(true);
expect(reservedTicketSales[1].reserved).toEqual(true); expect(reservedTicketSales[1].reserved).toEqual(true);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -1,40 +1,45 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('sale updateConcept()', () => { describe('sale updateConcept()', () => {
const ctx = {req: {accessToken: {userId: 9}}}; const ctx = {req: {accessToken: {userId: 9}}};
const saleId = 1; const saleId = 1;
let originalSale;
beforeAll(async done => {
originalSale = await app.models.Sale.findById(saleId);
done();
});
afterAll(async done => {
await originalSale.save();
done();
});
it('should throw if ID was undefined', async() => { it('should throw if ID was undefined', async() => {
let err; const tx = await models.Sale.beginTransaction({});
const newConcept = 'I am he new concept';
let error;
try { try {
await app.models.Sale.updateConcept(ctx, undefined, newConcept); const options = {transaction: tx};
const newConcept = 'not going to heppen';
await models.Sale.updateConcept(ctx, undefined, newConcept, options);
await tx.rollback();
} catch (e) { } catch (e) {
err = e; await tx.rollback();
error = e;
} }
expect(err).toBeDefined(); expect(error).toBeDefined();
}); });
it('should update the sale concept', async() => { it('should update the sale concept', async() => {
const tx = await models.Sale.beginTransaction({});
try {
const options = {transaction: tx};
const newConcept = 'I am the new concept'; const newConcept = 'I am the new concept';
let response = await app.models.Sale.updateConcept(ctx, saleId, newConcept); let response = await models.Sale.updateConcept(ctx, saleId, newConcept, options);
expect(response.concept).toEqual(newConcept); expect(response.concept).toEqual(newConcept);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -1,22 +1,6 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('sale updatePrice()', () => { describe('sale updatePrice()', () => {
let originalSale;
let originalSalesPersonMana;
let createdSaleComponent;
let saleId = 7;
let manaComponentId;
beforeAll(async done => {
let component = await app.models.Component.findOne({where: {code: 'mana'}});
manaComponentId = component.id;
originalSale = await app.models.Sale.findById(saleId);
originalSalesPersonMana = await app.models.WorkerMana.findById(18);
done();
});
it('should throw an error if the ticket is not editable', async() => {
const ctx = { const ctx = {
req: { req: {
accessToken: {userId: 18}, accessToken: {userId: 18},
@ -24,81 +8,93 @@ describe('sale updatePrice()', () => {
__: () => {} __: () => {}
} }
}; };
let immutableSaleId = 1; const saleId = 7;
let price = 5;
await app.models.Sale.updatePrice(ctx, immutableSaleId, price) it('should throw an error if the ticket is not editable', async() => {
.catch(response => { const tx = await models.Sale.beginTransaction({});
expect(response).toEqual(new Error(`The sales of this ticket can't be modified`));
error = response;
});
expect(error).toBeDefined(); try {
const options = {transaction: tx};
const immutableSaleId = 1;
const price = 5;
await models.Sale.updatePrice(ctx, immutableSaleId, price, options);
await tx.rollback();
} catch (e) {
await tx.rollback();
error = e;
}
expect(error).toEqual(new Error(`The sales of this ticket can't be modified`));
}); });
it('should return 0 if the price is an empty string', async() => { it('should return 0 if the price is an empty string', async() => {
const ctx = { const tx = await models.Sale.beginTransaction({});
req: {
accessToken: {userId: 18},
headers: {origin: 'localhost:5000'},
__: () => {}
}
};
let price = ''; try {
const options = {transaction: tx};
await app.models.Sale.updatePrice(ctx, saleId, price); const price = '';
let updatedSale = await app.models.Sale.findById(saleId);
await models.Sale.updatePrice(ctx, saleId, price, options);
const updatedSale = await models.Sale.findById(saleId, null, options);
expect(updatedSale.price).toEqual(0); expect(updatedSale.price).toEqual(0);
// restores await tx.rollback();
await originalSale.updateAttributes(originalSale); } catch (e) {
await app.models.SaleComponent.updateAll({componentFk: manaComponentId, saleFk: saleId}, {value: 0}); await tx.rollback();
await originalSalesPersonMana.updateAttributes(originalSalesPersonMana); throw e;
}
}); });
it('should now set price as a number in a string', async() => { it('should now set price as a number in a string', async() => {
const ctx = { const tx = await models.Sale.beginTransaction({});
req: {
accessToken: {userId: 18},
headers: {origin: 'localhost:5000'},
__: () => {}
}
};
let price = '8'; try {
const options = {transaction: tx};
await app.models.Sale.updatePrice(ctx, saleId, price); const price = '8';
let updatedSale = await app.models.Sale.findById(saleId);
await models.Sale.updatePrice(ctx, saleId, price, options);
const updatedSale = await models.Sale.findById(saleId, null, options);
expect(updatedSale.price).toEqual(8); expect(updatedSale.price).toEqual(8);
// restores await tx.rollback();
await originalSale.updateAttributes(originalSale); } catch (e) {
await app.models.SaleComponent.updateAll({componentFk: manaComponentId, saleFk: saleId}, {value: 0}); await tx.rollback();
await originalSalesPersonMana.updateAttributes(originalSalesPersonMana); throw e;
}
}); });
// #2736 sale updatePrice() returns inconsistent values it('should set price as a decimal number and check the sale has the mana component changing the salesPersonMana', async() => {
xit('should set price as a decimal number and check the sale has the mana component changing the salesPersonMana', async() => { const tx = await models.Sale.beginTransaction({});
let ctx = {req: {accessToken: {userId: 18}}};
let price = 5.4;
await app.models.Sale.updatePrice(ctx, saleId, price); try {
let updatedSale = await app.models.Sale.findById(saleId); const options = {transaction: tx};
createdSaleComponent = await app.models.SaleComponent.findOne({where: {saleFk: saleId, componentFk: manaComponentId}});
const price = 5.4;
const originalSalesPersonMana = await models.WorkerMana.findById(18, null, options);
const manaComponent = await models.Component.findOne({where: {code: 'mana'}}, options);
await models.Sale.updatePrice(ctx, saleId, price, options);
const updatedSale = await models.Sale.findById(saleId, null, options);
createdSaleComponent = await models.SaleComponent.findOne({where: {saleFk: saleId, componentFk: manaComponent.id}}, options);
expect(updatedSale.price).toBe(price); expect(updatedSale.price).toBe(price);
expect(createdSaleComponent.value).toEqual(-2.04); expect(createdSaleComponent.value).toEqual(-2.04);
let updatedSalesPersonMana = await app.models.WorkerMana.findById(18); const updatedSalesPersonMana = await models.WorkerMana.findById(18, null, options);
expect(updatedSalesPersonMana.amount).not.toEqual(originalSalesPersonMana.amount); expect(updatedSalesPersonMana.amount).not.toEqual(originalSalesPersonMana.amount);
// restores await tx.rollback();
await originalSale.updateAttributes(originalSale); } catch (e) {
await app.models.SaleComponent.updateAll({componentFk: manaComponentId, saleFk: saleId}, {value: 0}); await tx.rollback();
await originalSalesPersonMana.updateAttributes(originalSalesPersonMana); throw e;
}
}); });
}); });

View File

@ -1,4 +1,4 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('sale updateQuantity()', () => { describe('sale updateQuantity()', () => {
const ctx = { const ctx = {
@ -10,44 +10,61 @@ describe('sale updateQuantity()', () => {
}; };
it('should throw an error if the quantity is not a number', async() => { it('should throw an error if the quantity is not a number', async() => {
const tx = await models.Sale.beginTransaction({});
let error; let error;
try {
const options = {transaction: tx};
await app.models.Sale.updateQuantity(ctx, 1, 'wrong quantity!') await models.Sale.updateQuantity(ctx, 1, 'wrong quantity!', options);
.catch(response => {
expect(response).toEqual(new Error('The value should be a number'));
error = response;
});
expect(error).toBeDefined(); await tx.rollback();
} catch (e) {
await tx.rollback();
error = e;
}
expect(error).toEqual(new Error('The value should be a number'));
}); });
it('should throw an error if the quantity is greater than it should be', async() => { it('should throw an error if the quantity is greater than it should be', async() => {
const tx = await models.Sale.beginTransaction({});
let error; let error;
try {
const options = {transaction: tx};
await app.models.Sale.updateQuantity(ctx, 1, 99) await models.Sale.updateQuantity(ctx, 1, 99, options);
.catch(response => {
expect(response).toEqual(new Error('The new quantity should be smaller than the old one'));
error = response;
});
expect(error).toBeDefined(); await tx.rollback();
} catch (e) {
await tx.rollback();
error = e;
}
expect(error).toEqual(new Error('The new quantity should be smaller than the old one'));
}); });
it('should update the quantity of a given sale current line', async() => { it('should update the quantity of a given sale current line', async() => {
let originalLineData = await app.models.Sale.findOne({where: {id: 1}, fields: ['quantity']}); const tx = await models.Sale.beginTransaction({});
expect(originalLineData.quantity).toEqual(5); try {
const options = {transaction: tx};
await app.models.Sale.updateQuantity(ctx, 1, 4); const originalLine = await models.Sale.findOne({where: {id: 1}, fields: ['quantity']}, options);
let modifiedLineData = await app.models.Sale.findOne({where: {id: 1}, fields: ['quantity']}); expect(originalLine.quantity).toEqual(5);
expect(modifiedLineData.quantity).toEqual(4); await models.Sale.updateQuantity(ctx, 1, 4, options);
await app.models.Sale.update({id: 1}, {quantity: 5}); const modifiedLine = await models.Sale.findOne({where: {id: 1}, fields: ['quantity']}, options);
let resetLineDataValues = await app.models.Sale.findOne({where: {id: 1}, fields: ['quantity']}); expect(modifiedLine.quantity).toEqual(4);
expect(resetLineDataValues.quantity).toEqual(5); await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -24,15 +24,35 @@ module.exports = Self => {
} }
}); });
Self.updateConcept = async(ctx, id, newConcept) => { Self.updateConcept = async(ctx, id, newConcept, options) => {
const models = Self.app.models; const models = Self.app.models;
const currentLine = await models.Sale.findById(id); const myOptions = {};
let tx;
const canEditSale = await models.Sale.canEdit(ctx, [id]); if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
const currentLine = await models.Sale.findById(id, null, myOptions);
const canEditSale = await models.Sale.canEdit(ctx, [id], myOptions);
if (!canEditSale) if (!canEditSale)
throw new UserError(`Sale(s) blocked, please contact production`); throw new UserError(`Sale(s) blocked, please contact production`);
return await currentLine.updateAttributes({concept: newConcept}); const line = await currentLine.updateAttributes({concept: newConcept}, myOptions);
if (tx) await tx.commit();
return line;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
}; };
}; };

View File

@ -28,14 +28,21 @@ module.exports = Self => {
} }
}); });
Self.updatePrice = async(ctx, id, newPrice) => { Self.updatePrice = async(ctx, id, newPrice, options) => {
const $t = ctx.req.__; // $translate const $t = ctx.req.__; // $translate
const models = Self.app.models; const models = Self.app.models;
const tx = await Self.beginTransaction({}); const myOptions = {};
let tx;
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try { try {
const options = {transaction: tx};
const filter = { const filter = {
include: { include: {
relation: 'ticket', relation: 'ticket',
@ -57,22 +64,22 @@ module.exports = Self => {
} }
}; };
const sale = await models.Sale.findById(id, filter, options); const sale = await models.Sale.findById(id, filter, myOptions);
const isEditable = await models.Ticket.isEditable(ctx, sale.ticketFk); const isEditable = await models.Ticket.isEditable(ctx, sale.ticketFk, myOptions);
if (!isEditable) if (!isEditable)
throw new UserError(`The sales of this ticket can't be modified`); throw new UserError(`The sales of this ticket can't be modified`);
const canEditSale = await models.Sale.canEdit(ctx, [id]); const canEditSale = await models.Sale.canEdit(ctx, [id], myOptions);
if (!canEditSale) if (!canEditSale)
throw new UserError(`Sale(s) blocked, please contact production`); throw new UserError(`Sale(s) blocked, please contact production`);
const oldPrice = sale.price; const oldPrice = sale.price;
const userId = ctx.req.accessToken.userId; const userId = ctx.req.accessToken.userId;
const usesMana = await models.WorkerMana.findOne({where: {workerFk: userId}, fields: 'amount'}, options); const usesMana = await models.WorkerMana.findOne({where: {workerFk: userId}, fields: 'amount'}, myOptions);
const componentCode = usesMana ? 'mana' : 'buyerDiscount'; const componentCode = usesMana ? 'mana' : 'buyerDiscount';
const discount = await models.Component.findOne({where: {code: componentCode}}, options); const discount = await models.Component.findOne({where: {code: componentCode}}, myOptions);
const componentId = discount.id; const componentId = discount.id;
const componentValue = newPrice - sale.price; const componentValue = newPrice - sale.price;
@ -80,23 +87,23 @@ module.exports = Self => {
componentFk: componentId, componentFk: componentId,
saleFk: id saleFk: id
}; };
const saleComponent = await models.SaleComponent.findOne({where}, options); const saleComponent = await models.SaleComponent.findOne({where}, myOptions);
if (saleComponent) { if (saleComponent) {
await models.SaleComponent.updateAll(where, { await models.SaleComponent.updateAll(where, {
value: saleComponent.value + componentValue value: saleComponent.value + componentValue
}, options); }, myOptions);
} else { } else {
await models.SaleComponent.create({ await models.SaleComponent.create({
saleFk: id, saleFk: id,
componentFk: componentId, componentFk: componentId,
value: componentValue value: componentValue
}, options); }, myOptions);
} }
await sale.updateAttributes({price: newPrice}, options); await sale.updateAttributes({price: newPrice}, myOptions);
query = `CALL vn.manaSpellersRequery(?)`; query = `CALL vn.manaSpellersRequery(?)`;
await Self.rawSql(query, [userId], options); await Self.rawSql(query, [userId], myOptions);
const salesPerson = sale.ticket().client().salesPersonUser(); const salesPerson = sale.ticket().client().salesPersonUser();
if (salesPerson) { if (salesPerson) {
@ -111,14 +118,14 @@ module.exports = Self => {
ticketUrl: `${origin}/#!/ticket/${sale.ticket().id}/sale`, ticketUrl: `${origin}/#!/ticket/${sale.ticket().id}/sale`,
itemUrl: `${origin}/#!/item/${sale.itemFk}/summary` itemUrl: `${origin}/#!/item/${sale.itemFk}/summary`
}); });
await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message); await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message, myOptions);
} }
await tx.commit(); if (tx) await tx.commit();
return sale; return sale;
} catch (error) { } catch (error) {
await tx.rollback(); if (tx) await tx.rollback();
throw error; throw error;
} }
}; };

View File

@ -26,11 +26,22 @@ module.exports = Self => {
} }
}); });
Self.updateQuantity = async(ctx, id, newQuantity) => { Self.updateQuantity = async(ctx, id, newQuantity, options) => {
const $t = ctx.req.__; // $translate
const models = Self.app.models; const models = Self.app.models;
const $t = ctx.req.__; // $translate
const myOptions = {};
let tx;
const canEditSale = await models.Sale.canEdit(ctx, [id]); if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
const canEditSale = await models.Sale.canEdit(ctx, [id], myOptions);
if (!canEditSale) if (!canEditSale)
throw new UserError(`Sale(s) blocked, please contact production`); throw new UserError(`Sale(s) blocked, please contact production`);
@ -57,13 +68,13 @@ module.exports = Self => {
} }
}; };
const sale = await models.Sale.findById(id, filter); const sale = await models.Sale.findById(id, filter, myOptions);
if (newQuantity > sale.quantity) if (newQuantity > sale.quantity)
throw new UserError('The new quantity should be smaller than the old one'); throw new UserError('The new quantity should be smaller than the old one');
const oldQuantity = sale.quantity; const oldQuantity = sale.quantity;
const result = await sale.updateAttributes({quantity: newQuantity}); const result = await sale.updateAttributes({quantity: newQuantity}, myOptions);
const salesPerson = sale.ticket().client().salesPersonUser(); const salesPerson = sale.ticket().client().salesPersonUser();
if (salesPerson) { if (salesPerson) {
@ -77,9 +88,15 @@ module.exports = Self => {
ticketUrl: `${origin}/#!/ticket/${sale.ticket().id}/sale`, ticketUrl: `${origin}/#!/ticket/${sale.ticket().id}/sale`,
itemUrl: `${origin}/#!/item/${sale.itemFk}/summary` itemUrl: `${origin}/#!/item/${sale.itemFk}/summary`
}); });
await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message); await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message, myOptions);
} }
if (tx) await tx.commit();
return result; return result;
} catch (error) {
if (tx) await tx.rollback();
throw error;
}
}; };
}; };