/* eslint max-len: ["error", { "code": 150 }]*/ const {models} = require('vn-loopback/server/server'); const LoopBackContext = require('loopback-context'); describe('sale model ', () => { const developerId = 9; const buyerId = 35; const employeeId = 1; const productionId = 49; const salesPersonId = 18; const reviewerId = 130; const barcode = '4444444444'; const ticketCollectionProd = 34; const ticketCollectionSalesPerson = 35; const previaTicketSalesPerson = 36; const previaTicketProd = 37; const notEditableError = 'This ticket is not editable.'; const ctx = getCtx(developerId); let tx; let opts; function getCtx(userId, active = false) { const accessToken = {userId}; const headers = {origin: 'localhost:5000'}; if (!active) return {req: {accessToken, headers, __: () => {}}}; return {active: {accessToken, http: {req: {headers}}}}; } beforeEach(async() => { tx = await models.Sale.beginTransaction({}); opts = {transaction: tx}; }); afterEach(async() => await tx.rollback()); describe('quantity field ', () => { it('should add quantity if the quantity is greater than it should be and is role advanced', async() => { const saleId = 17; const ctx = getCtx(buyerId); spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(buyerId, true)); spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, opts) => { if (sqlStatement.includes('catalog_calcFromItem')) { sqlStatement = `CREATE OR REPLACE TEMPORARY TABLE tmp.ticketCalculateItem ENGINE = MEMORY SELECT 100 as available;`; params = null; } return models.Ticket.rawSql(sqlStatement, params, opts); }); const isRoleAdvanced = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'isRoleAdvanced', '*'); expect(isRoleAdvanced).toEqual(true); const originalLine = await models.Sale.findOne({where: {id: saleId}, fields: ['quantity']}, opts); expect(originalLine.quantity).toEqual(30); const newQuantity = originalLine.quantity + 1; await models.Sale.updateQuantity(ctx, saleId, newQuantity, opts); const modifiedLine = await models.Sale.findOne({where: {id: saleId}, fields: ['quantity']}, opts); expect(modifiedLine.quantity).toEqual(newQuantity); }); it('should update the quantity of a given sale current line', async() => { spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(developerId, true)); const saleId = 25; const newQuantity = 4; const originalLine = await models.Sale.findOne({where: {id: saleId}, fields: ['quantity']}, opts); expect(originalLine.quantity).toEqual(20); await models.Sale.updateQuantity(ctx, saleId, newQuantity, opts); const modifiedLine = await models.Sale.findOne({where: {id: saleId}, fields: ['quantity']}, opts); expect(modifiedLine.quantity).toEqual(newQuantity); }); it('should throw an error if the quantity is negative and it is not a refund ticket', async() => { spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true)); const saleId = 17; const newQuantity = -10; try { await models.Sale.updateQuantity(ctx, saleId, newQuantity, opts); } catch (e) { expect(e).toEqual(new Error('You can only add negative amounts in refund tickets')); } }); it('should update a negative quantity when is a ticket refund', async() => { spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(developerId, true)); const saleId = 32; const newQuantity = -10; await models.Sale.updateQuantity(ctx, saleId, newQuantity, opts); const modifiedLine = await models.Sale.findOne({where: {id: saleId}, fields: ['quantity']}, opts); expect(modifiedLine.quantity).toEqual(newQuantity); }); it('should throw an error if the quantity is less than the minimum quantity of the item', async() => { spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true)); const saleId = 17; const newQuantity = 1; try { spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, opts) => { if (sqlStatement.includes('catalog_calcFromItem')) { sqlStatement = `CREATE OR REPLACE TEMPORARY TABLE tmp.ticketCalculateItem ENGINE = MEMORY SELECT 100 as available;`; params = null; } return models.Ticket.rawSql(sqlStatement, params, opts); }); await models.Sale.updateQuantity(ctx, saleId, newQuantity, opts); } catch (e) { expect(e).toEqual(new Error('The amount cannot be less than the minimum')); } }); it('should change quantity if has minimum quantity and new quantity is equal than item available', async() => { spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true)); const saleId = 17; const newQuantity = 8; spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, opts) => { if (sqlStatement.includes('catalog_calcFromItem')) { sqlStatement = `CREATE OR REPLACE TEMPORARY TABLE tmp.ticketCalculateItem ENGINE = MEMORY SELECT ${newQuantity} as available;`; params = null; } return models.Ticket.rawSql(sqlStatement, params, opts); }); await models.Sale.updateQuantity(ctx, saleId, newQuantity, opts); }); describe('newPrice', () => { it('should increase quantity if you have enough available and the new price is the same as the previous one', async() => { spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true)); const saleId = 17; const newQuantity = 31; spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, opts) => { if (sqlStatement.includes('catalog_calcFromItem')) { sqlStatement = ` CREATE OR REPLACE TEMPORARY TABLE tmp.ticketCalculateItem ENGINE = MEMORY SELECT ${newQuantity} as available; CREATE OR REPLACE TEMPORARY TABLE tmp.ticketComponentPrice ENGINE = MEMORY SELECT 1 as grouping, 7.07 as price;`; params = null; } return models.Ticket.rawSql(sqlStatement, params, opts); }); await models.Sale.updateQuantity(ctx, saleId, newQuantity, opts); }); it('should increase quantity when the new price is lower than the previous one', async() => { spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true)); const saleId = 17; const newQuantity = 31; spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, opts) => { if (sqlStatement.includes('catalog_calcFromItem')) { sqlStatement = ` CREATE OR REPLACE TEMPORARY TABLE tmp.ticketCalculateItem ENGINE = MEMORY SELECT ${newQuantity} as available; CREATE OR REPLACE TEMPORARY TABLE tmp.ticketComponentPrice ENGINE = MEMORY SELECT 1 as grouping, 1 as price;`; params = null; } return models.Ticket.rawSql(sqlStatement, params, opts); }); await models.Sale.updateQuantity(ctx, saleId, newQuantity, opts); }); it('should throw error when increase quantity and the new price is higher than the previous one', async() => { spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true)); const saleId = 17; const newQuantity = 31; try { spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, opts) => { if (sqlStatement.includes('catalog_calcFromItem')) { sqlStatement = ` CREATE OR REPLACE TEMPORARY TABLE tmp.ticketCalculateItem ENGINE = MEMORY SELECT ${newQuantity} as available; CREATE OR REPLACE TEMPORARY TABLE tmp.ticketComponentPrice ENGINE = MEMORY SELECT 1 as grouping, 100000 as price;`; params = null; } return models.Ticket.rawSql(sqlStatement, params, opts); }); await models.Sale.updateQuantity(ctx, saleId, newQuantity, opts); } catch (e) { expect(e).toEqual(new Error('The price of the item changed')); } }); it('should throw an error if the quantity is lower than the minimum quantity of the item and is in range', async() => { spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true)); const saleId = 25; const newQuantity = 5; try { spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, opts) => { if (sqlStatement.includes('catalog_calcFromItem')) { sqlStatement = ` CREATE OR REPLACE TEMPORARY TABLE tmp.ticketCalculateItem ENGINE = MEMORY SELECT ${newQuantity} as available; CREATE OR REPLACE TEMPORARY TABLE tmp.ticketComponentPrice ENGINE = MEMORY SELECT 1 as grouping, 100000 as price;`; params = null; } return models.Ticket.rawSql(sqlStatement, params, opts); }); await models.Sale.updateQuantity(ctx, saleId, newQuantity, opts); } catch (e) { expect(e).toEqual(new Error('The amount cannot be less than the minimum')); } }); it('should update the quantity if the quantity is lower than the minimum quantity of the item and is out of the range', async() => { spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(employeeId, true)); const saleId = 17; const newQuantity = 8; spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, opts) => { if (sqlStatement.includes('catalog_calcFromItem')) { sqlStatement = ` CREATE OR REPLACE TEMPORARY TABLE tmp.ticketCalculateItem ENGINE = MEMORY SELECT ${newQuantity} as available; CREATE OR REPLACE TEMPORARY TABLE tmp.ticketComponentPrice ENGINE = MEMORY SELECT 1 as grouping, 100000 as price;`; params = null; } return models.Ticket.rawSql(sqlStatement, params, opts); }); await models.Sale.updateQuantity(ctx, saleId, newQuantity, opts); }); }); }); describe('add a sale from a collection or previa ticket', () => { it('if is allocated to them and alert level higher than 0 as Production role', async() => { const ctx = getCtx(productionId); spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(productionId, true)); const beforeSalesCollection = await models.Sale.count({ticketFk: ticketCollectionProd}, opts); await models.Ticket.addSale(ctx, ticketCollectionProd, barcode, 20, opts); const afterSalesCollection = await models.Sale.count({ticketFk: ticketCollectionProd}, opts); expect(afterSalesCollection).toEqual(beforeSalesCollection + 1); const beforeSalesPrevia = await models.Sale.count({ticketFk: previaTicketProd}, opts); await models.Ticket.addSale(ctx, previaTicketProd, barcode, 20, opts); const afterSalesPrevia = await models.Sale.count({ticketFk: previaTicketProd}, opts); expect(afterSalesPrevia).toEqual(beforeSalesPrevia + 1); }); it('should throw an error if is not allocated to them and alert level higher than 0 as Production role', async() => { const ctx = getCtx(productionId); spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(productionId, true)); try { await models.Ticket.addSale(ctx, ticketCollectionSalesPerson, barcode, 20, opts); } catch ({message}) { expect(message).toEqual(notEditableError); } try { await models.Ticket.addSale(ctx, previaTicketSalesPerson, barcode, 20, opts); } catch ({message}) { expect(message).toEqual(notEditableError); } }); it('if is allocated to them and alert level higher than 0 as salesPerson role', async() => { const ctx = getCtx(salesPersonId); spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(salesPersonId, true)); const beforeSalesCollection = await models.Sale.count({ticketFk: ticketCollectionSalesPerson}, opts); await models.Ticket.addSale(ctx, ticketCollectionSalesPerson, barcode, 20, opts); const afterSalesCollection = await models.Sale.count({ticketFk: ticketCollectionSalesPerson}, opts); expect(afterSalesCollection).toEqual(beforeSalesCollection + 1); const beforeSalesPrevia = await models.Sale.count({ticketFk: previaTicketSalesPerson}, opts); await models.Ticket.addSale(ctx, previaTicketSalesPerson, barcode, 20, opts); const afterSalesPrevia = await models.Sale.count({ticketFk: previaTicketSalesPerson}, opts); expect(afterSalesPrevia).toEqual(beforeSalesPrevia + 1); }); it('should throw an error if is not allocated to them and alert level higher than 0 as salesPerson role', async() => { const ctx = getCtx(salesPersonId); spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(salesPersonId, true)); try { await models.Ticket.addSale(ctx, ticketCollectionProd, barcode, 20, opts); } catch ({message}) { expect(message).toEqual(notEditableError); } }); it('if is a reviewer', async() => { const ctx = getCtx(reviewerId); spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getCtx(reviewerId, true)); const beforeSalesCollection = await models.Sale.count({ticketFk: ticketCollectionSalesPerson}, opts); await models.Ticket.addSale(ctx, ticketCollectionSalesPerson, barcode, 20, opts); const afterSalesCollection = await models.Sale.count({ticketFk: ticketCollectionSalesPerson}, opts); expect(afterSalesCollection).toEqual(beforeSalesCollection + 1); const beforeSalesPrevia = await models.Sale.count({ticketFk: previaTicketSalesPerson}, opts); await models.Ticket.addSale(ctx, previaTicketSalesPerson, barcode, 20, opts); const afterSalesPrevia = await models.Sale.count({ticketFk: previaTicketSalesPerson}, opts); expect(afterSalesPrevia).toEqual(beforeSalesPrevia + 1); }); }); });