diff --git a/db/versions/11178-yellowCamellia/00-aclSetWeight.sql b/db/versions/11178-yellowCamellia/00-aclSetWeight.sql new file mode 100644 index 000000000..d70287738 --- /dev/null +++ b/db/versions/11178-yellowCamellia/00-aclSetWeight.sql @@ -0,0 +1,9 @@ +-- Place your SQL code here +INSERT INTO salix.ACL + SET model = 'Ticket', + property = 'setWeight', + accessType = 'WRITE', + permission = 'ALLOW', + principalType = 'ROLE', + principalId = 'salesPerson'; + \ No newline at end of file diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 8b443d96b..064ea4a95 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -372,5 +372,7 @@ "The entry not have stickers": "La entrada no tiene etiquetas", "Too many records": "Demasiados registros", "Original invoice not found": "Factura original no encontrada", - "The entry has no lines or does not exist": "La entrada no tiene lineas o no existe" + "The entry has no lines or does not exist": "La entrada no tiene lineas o no existe", + "Weight already set": "El peso ya está establecido", + "This ticket is not allocated to your department": "Este ticket no está asignado a tu departamento" } \ No newline at end of file diff --git a/modules/ticket/back/methods/ticket/setWeight.js b/modules/ticket/back/methods/ticket/setWeight.js new file mode 100644 index 000000000..b3b505832 --- /dev/null +++ b/modules/ticket/back/methods/ticket/setWeight.js @@ -0,0 +1,86 @@ +const UserError = require('vn-loopback/util/user-error'); + +module.exports = Self => { + Self.remoteMethodCtx('setWeight', { + description: 'Sets weight of a ticket', + accessType: 'WRITE', + accepts: [{ + arg: 'id', + type: 'number', + required: true, + description: 'The ticket id', + http: {source: 'path'} + }, { + arg: 'weight', + type: 'number', + required: true, + description: 'The weight value', + }], + returns: { + type: 'Array', + root: true + }, + http: { + path: `/:id/setWeight`, + verb: 'POST' + } + }); + + Self.setWeight = async(ctx, ticketId, weight, options) => { + const models = Self.app.models; + const userId = ctx.req.accessToken.userId; + const myOptions = {userId}; + let tx; + + if (typeof options == 'object') Object.assign(myOptions, options); + + if (!myOptions.transaction) { + tx = await Self.beginTransaction({}); + myOptions.transaction = tx; + } + + try { + const ticket = await Self.findById(ticketId, null, myOptions); + if (ticket.weight) throw new UserError('Weight already set'); + + const canEdit = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'updateAttributes'); + const client = await models.Client.findById(ticket.clientFk, { + include: {relation: 'salesPersonUser'}}, + myOptions); + + if (!canEdit) { + const salesPersonUser = client.salesPersonUser(); + const workerDepartments = await models.WorkerDepartment.find({ + include: {relation: 'department'}, + where: {workerFk: {inq: [userId, salesPersonUser.id]}} + }, myOptions); + + if ( + workerDepartments.length == 2 && + workerDepartments[0].departmentFk != workerDepartments[1].departmentFk + ) + throw new UserError('This ticket is not allocated to your department'); + } + + await ticket.updateAttribute('weight', weight, myOptions); + + const packedState = await models.State.findOne({where: {code: 'PACKED'}}, myOptions); + const ticketState = await models.TicketState.findOne({where: {ticketFk: ticketId}}, myOptions); + + const [{taxArea}] = await Self.rawSql('SELECT clientTaxArea(?,?) taxArea', + [ticket.clientFk, ticket.warehouseFk], myOptions); + + const isInvoiceable = ticketState.alertLevel >= packedState.alertLevel && + taxArea == 'WORLD' && client.hasDailyInvoice; + + if (tx) await tx.commit(); + let invoiceIds = []; + if (isInvoiceable) invoiceIds = [...await Self.invoiceTicketsAndPdf(ctx, [ticketId])]; + + return invoiceIds; + } catch (e) { + if (tx) await tx.rollback(); + throw e; + } + }; +}; diff --git a/modules/ticket/back/methods/ticket/specs/setWeight.spec.js b/modules/ticket/back/methods/ticket/specs/setWeight.spec.js new file mode 100644 index 000000000..f6ef1f8e7 --- /dev/null +++ b/modules/ticket/back/methods/ticket/specs/setWeight.spec.js @@ -0,0 +1,70 @@ +const {models} = require('vn-loopback/server/server'); + +describe('ticket setWeight()', () => { + const ctx = beforeAll.getCtx(); + beforeAll.mockLoopBackContext(); + let opts; + let tx; + const employeeId = 1; + const administrativeId = 5; + + beforeEach(async() => { + opts = {transaction: tx}; + tx = await models.Ticket.beginTransaction({}); + opts.transaction = tx; + ctx.req.accessToken.userId = administrativeId; + }); + + afterEach(async() => await tx.rollback()); + + it('should throw an error if the weight is already set', async() => { + try { + const ticketId = 1; + const weight = 10; + + await models.Ticket.setWeight(ctx, ticketId, weight, opts); + } catch (e) { + expect(e.message).toEqual('Weight already set'); + } + }); + + it('should set the weight of a ticket', async() => { + const ticketId = 31; + const weight = 15; + + await models.Ticket.setWeight(ctx, ticketId, weight, opts); + + const ticket = await models.Ticket.findById(ticketId, null, opts); + + expect(ticket.weight).toEqual(weight); + }); + + it('should throw an error if the user is not allocated to the same department', async() => { + ctx.req.accessToken.userId = employeeId; + try { + const ticketId = 10; + const weight = 20; + + await models.Ticket.setWeight(ctx, ticketId, weight, opts); + } catch (e) { + expect(e.message).toEqual('This ticket is not allocated to your department'); + } + }); + + it('should call invoiceTicketsAndPdf if the ticket is invoiceable', async() => { + const ticketId = 10; + const weight = 25; + + spyOn(models.Client, 'findById').and.returnValue({ + hasDailyInvoice: true, + salesPersonUser: () => ({id: 1}) + }); + spyOn(models.TicketState, 'findOne').and.returnValue({alertLevel: 3}); + spyOn(models.Ticket, 'rawSql').and.returnValue([{taxArea: 'WORLD'}]); + spyOn(models.Ticket, 'invoiceTicketsAndPdf').and.returnValue([10]); + + const invoiceIds = await models.Ticket.setWeight(ctx, ticketId, weight, opts); + + expect(invoiceIds.length).toBeGreaterThan(0); + }); +}); diff --git a/modules/ticket/back/models/ticket-methods.js b/modules/ticket/back/models/ticket-methods.js index 462862cb3..12161d5f5 100644 --- a/modules/ticket/back/models/ticket-methods.js +++ b/modules/ticket/back/models/ticket-methods.js @@ -46,4 +46,5 @@ module.exports = function(Self) { require('../methods/ticket/invoiceTicketsAndPdf')(Self); require('../methods/ticket/docuwareDownload')(Self); require('../methods/ticket/myLastModified')(Self); + require('../methods/ticket/setWeight')(Self); }; diff --git a/modules/ticket/front/summary/locale/es.yml b/modules/ticket/front/summary/locale/es.yml index d1e6dba58..9de7ccbf4 100644 --- a/modules/ticket/front/summary/locale/es.yml +++ b/modules/ticket/front/summary/locale/es.yml @@ -3,4 +3,5 @@ Address mobile: Móv. consignatario Client phone: Tel. cliente Client mobile: Móv. cliente Go to the ticket: Ir al ticket -Change state: Cambiar estado \ No newline at end of file +Change state: Cambiar estado +Weight: Peso \ No newline at end of file