diff --git a/db/changes/10050-pentecostes/00-Device.sql b/db/changes/10050-pentecostes/00-Device.sql new file mode 100644 index 000000000..665d2c8e7 --- /dev/null +++ b/db/changes/10050-pentecostes/00-Device.sql @@ -0,0 +1,15 @@ +CREATE TABLE `vn`.`device` ( + `id` INT NOT NULL, + `sn` VARCHAR(50) NULL, + `model` VARCHAR(50) NULL, + `userFk` INT(10) UNSIGNED NOT NULL, + PRIMARY KEY (`id`), + INDEX `device_fk1_idx` (`userFk` ASC), + CONSTRAINT `device_fk1` + FOREIGN KEY (`userFk`) + REFERENCES `account`.`user` (`id`) + ON DELETE NO ACTION + ON UPDATE NO ACTION); + +ALTER TABLE `vn`.`device` +CHANGE COLUMN `id` `id` INT(11) NOT NULL AUTO_INCREMENT ; diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 38318f578..0a9309c1b 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -1468,4 +1468,6 @@ INSERT INTO `vn`.`ticketDms`(`ticketFk`, `dmsFk`) INSERT INTO `vn`.`clientDms`(`clientFk`, `dmsFk`) VALUES (101, 2), - (101, 3); \ No newline at end of file + (101, 3); + +INSERT INTO `vn`.`device` (`sn`, `model`, `userFk`) VALUES ('aaa', 'android', '9'); \ No newline at end of file diff --git a/modules/order/back/methods/order/new.js b/modules/order/back/methods/order/new.js index 259fb3ea2..0d020ccd6 100644 --- a/modules/order/back/methods/order/new.js +++ b/modules/order/back/methods/order/new.js @@ -4,11 +4,24 @@ module.exports = Self => { Self.remoteMethod('new', { description: 'Create a new order and returns the new ID', accessType: 'WRITE', - accepts: [{ - arg: 'params', - type: 'object', - http: {source: 'body'} - }], + accepts: [ + { + arg: 'landed', + description: 'The landed for the order', + type: 'date', + required: true + }, { + arg: 'addressId', + description: 'The address for the order', + type: 'number', + required: true + }, { + arg: 'agencyModeId', + description: 'The agencyMode for the order', + type: 'number', + required: true + } + ], returns: { type: 'number', root: true @@ -19,9 +32,9 @@ module.exports = Self => { } }); - Self.new = async params => { + Self.new = async(landed, addressId, agencyModeId) => { let address = await Self.app.models.Address.findOne({ - where: {id: params.addressFk}, + where: {id: addressId}, fields: ['clientFk'], include: [ {relation: 'client', @@ -44,9 +57,9 @@ module.exports = Self => { query = `CALL vn.orderListCreate(?, ?, ?, ?);`; [result] = await Self.rawSql(query, [ - params.landed, - params.agencyModeFk, - params.addressFk, + landed, + agencyModeId, + addressId, 'SALIX' ]); diff --git a/modules/order/back/methods/order/newFromTicket.js b/modules/order/back/methods/order/newFromTicket.js index 533ec6ff9..285f60ee8 100644 --- a/modules/order/back/methods/order/newFromTicket.js +++ b/modules/order/back/methods/order/newFromTicket.js @@ -23,11 +23,11 @@ module.exports = Self => { where: {id: ticketFk} }); - let orderID = await Self.app.models.Order.new({ - addressFk: ticket.addressFk, - landed: ticket.landed, - agencyModeFk: ticket.agencyModeFk - }); + let landed = ticket.landed; + let addressFk = ticket.addressFk; + let agencyModeFk = ticket.agencyModeFk; + + let orderID = await Self.app.models.Order.new(landed, addressFk, agencyModeFk); return orderID; }; diff --git a/modules/order/back/methods/order/specs/new.spec.js b/modules/order/back/methods/order/specs/new.spec.js index 88f5776b6..9ed55981c 100644 --- a/modules/order/back/methods/order/specs/new.spec.js +++ b/modules/order/back/methods/order/specs/new.spec.js @@ -12,9 +12,11 @@ describe('order new()', () => { it('should throw an error if the client is frozen', async() => { let error; - let params = {addressFk: 121}; + let landed = new Date(); + let addressFk = 121; + let agencyModeFk = 1; - await app.models.Order.new(params) + await app.models.Order.new(landed, addressFk, agencyModeFk) .catch(e => { error = e; }); @@ -24,9 +26,11 @@ describe('order new()', () => { it('should throw an error if the client isnt frozen and isnt active', async() => { let error; - let params = {addressFk: 6}; + let landed = new Date(); + let addressFk = 6; + let agencyModeFk = 1; - await app.models.Order.new(params) + await app.models.Order.new(landed, addressFk, agencyModeFk) .catch(e => { error = e; }); @@ -35,13 +39,11 @@ describe('order new()', () => { }); it('should create a new order for the user with id 105 when all conditions are met', async() => { - let params = { - landed: new Date(), - agencyModeFk: 1, - addressFk: 125 - }; + let landed = new Date(); + let addressFk = 125; + let agencyModeFk = 1; - orderId = await app.models.Order.new(params); + orderId = await app.models.Order.new(landed, addressFk, agencyModeFk); let highestOrderIdInFixtures = 3; diff --git a/modules/order/front/create/card.html b/modules/order/front/create/card.html index 0b0f8822a..7ef5f0243 100644 --- a/modules/order/front/create/card.html +++ b/modules/order/front/create/card.html @@ -31,5 +31,6 @@ label="Agency" show-field="agency" value-field="id" + rule="Order.agencyModeFk" field="$ctrl.order.agencyModeFk"> diff --git a/modules/order/front/create/card.js b/modules/order/front/create/card.js index ad6317f02..e092b4be9 100644 --- a/modules/order/front/create/card.js +++ b/modules/order/front/create/card.js @@ -96,8 +96,8 @@ class Controller { createOrder() { let params = { landed: this.order.landed, - addressFk: this.order.addressFk, - agencyModeFk: this.order.agencyModeFk + addressId: this.order.addressFk, + agencyModeId: this.order.agencyModeFk }; this.$http.post(`order/api/Orders/new`, params).then(res => { this.vnApp.showSuccess(this.translate.instant('Data saved!')); diff --git a/modules/ticket/back/methods/sale/specs/updatePrice.spec.js b/modules/ticket/back/methods/sale/specs/updatePrice.spec.js index f86cb17eb..7c31ab46b 100644 --- a/modules/ticket/back/methods/sale/specs/updatePrice.spec.js +++ b/modules/ticket/back/methods/sale/specs/updatePrice.spec.js @@ -1,121 +1,73 @@ const app = require('vn-loopback/server/server'); // #1489 updatePrice backTest -xdescribe('sale updatePrice()', () => { - it('should set price to 0 if the params price is undefined', async() => { - let params = { - price: undefined, - id: 13, - ticketFk: 8 - }; - await app.models.Sale.updatePrice(params); - let saleUpdated = await app.models.Sale.findById(params.id); +describe('sale updatePrice()', () => { + let originalSale; + let originalSalesPersonMana; + let createdSaleComponent; + let saleId = 13; - expect(saleUpdated.price).toEqual(0); + afterAll(async done => { + originalSale.save(); + createdSaleComponent.destroy(); + originalSalesPersonMana.save(); + + done(); }); - it('should set price as a decimal number', async() => { - let params = { - price: 5.5, - id: 13, - ticketFk: 8 - }; - await app.models.Sale.updatePrice(params); - let saleUpdated = await app.models.Sale.findById(params.id); + beforeAll(async done => { + originalSale = await app.models.Sale.findById(saleId); + originalSalesPersonMana = await app.models.WorkerMana.findById(18); - expect(saleUpdated.price).toEqual(5.5); + done(); }); - it('should now set price as a decimal number in a string', async() => { - let params = { - price: '5.5', - id: 13, - ticketFk: 8 - }; - await app.models.Sale.updatePrice(params); - let saleUpdated = await app.models.Sale.findById(params.id); + it('should throw an error if the ticket is not editable', async() => { + let immutableSaleId = 1; + let price = 5; - expect(saleUpdated.price).toEqual(5.5); + await app.models.Sale.updatePrice(immutableSaleId, price) + .catch(response => { + expect(response).toEqual(new Error(`The sales of this ticket can't be modified`)); + error = response; + }); + + expect(error).toBeDefined(); }); it('should return 0 if the price is an empty string', async() => { - let params = { - price: '', - id: 13, - ticketFk: 8 - }; - await app.models.Sale.updatePrice(params); - let saleUpdated = await app.models.Sale.findById(params.id); + let price = ''; + + await app.models.Sale.updatePrice(saleId, price); + let saleUpdated = await app.models.Sale.findById(saleId); expect(saleUpdated.price).toEqual(0); }); + it('should now set price as a decimal number in a string', async() => { + let price = '8'; - it('should este crea mana', async() => { - let params = { - price: 5.5, - id: 13, - ticketFk: 8 - }; - await app.models.Sale.updatePrice(params); - let saleUpdated = await app.models.Sale.findById(params.id); + await app.models.Sale.updatePrice(saleId, price); + let saleUpdated = await app.models.Sale.findById(saleId); - expect(saleUpdated.price).toEqual(5.5); + expect(saleUpdated.price).toEqual(8); }); - it('should este no crea el mana', async() => { - let params = { - price: 5.5, - id: 13, - ticketFk: 8 - }; - let todosLosComponentes = await app.models.SaleComponent.find({where: {saleFk: 13}}); + it('should set price as a decimal number and check the sale has the mana component', async() => { + let price = 5.5; + let manaComponentId = 37; - expect(todosLosComponentes[0].value).toEqual(''); - expect(todosLosComponentes[1].value).toEqual(''); - expect(todosLosComponentes[2].value).toEqual(''); - expect(todosLosComponentes[3].value).toEqual(''); - expect(todosLosComponentes[4].value).toEqual(''); - - await app.models.Sale.updatePrice(params); - todosLosComponentes = await app.models.SaleComponent.find({where: {saleFk: 13}}); - let saleUpdated = await app.models.Sale.findById(params.id); + await app.models.Sale.updatePrice(saleId, price); + let saleUpdated = await app.models.Sale.findById(saleId); + createdSaleComponent = await app.models.SaleComponent.findOne({where: {saleFk: saleId, componentFk: manaComponentId}}); expect(saleUpdated.price).toEqual(5.5); - - expect(todosLosComponentes[0].value).toEqual(''); - expect(todosLosComponentes[1].value).toEqual(''); - expect(todosLosComponentes[2].value).toEqual(''); - expect(todosLosComponentes[3].value).toEqual(''); - expect(todosLosComponentes[4].value).toEqual(''); + expect(createdSaleComponent.value).toEqual(4.200); }); - // 2 let componentToUse; - // if (usesMana) - // componentToUse = 37; - // 3else - // componentToUse = 34; - // 4 if (saleComponent) - // saleComponent.updateAttributes({value: saleComponent.value + value}); - // 5 else { - // await Self.app.models.SaleComponent.create({ - // saleFk: params.id, - // componentFk: componentToUse, - // value: value - // }); - // } + it('should check that the mana of salesPerson changed', async() => { + let updatedSalesPersonMana = await app.models.WorkerMana.findById(18); - // it(`should throw an error if the price is undefined`, async() => { - // let error; - - // let params = {ticketFk: 1, price: undefined}; - - // await app.models.Sale.updatePrice(params) - // .catch(response => { - // expect(response).toEqual(new Error('The value should be a number')); - // error = response; - // }); - - // expect(error).toBeDefined(); - // }); + expect(updatedSalesPersonMana.amount).not.toEqual(originalSalesPersonMana.amount); + }); }); diff --git a/modules/ticket/back/methods/sale/updatePrice.js b/modules/ticket/back/methods/sale/updatePrice.js index 246a9a4e5..dd6d64c59 100644 --- a/modules/ticket/back/methods/sale/updatePrice.js +++ b/modules/ticket/back/methods/sale/updatePrice.js @@ -2,84 +2,94 @@ let UserError = require('vn-loopback/util/user-error'); module.exports = Self => { Self.remoteMethod('updatePrice', { - description: 'Changes the discount of a sale', + description: 'Changes the price of a sale', accessType: 'WRITE', - accepts: [{ - arg: 'params', - type: 'object', - required: true, - description: 'sale ID, newPrice, ticketFk', - http: {source: 'body'} - }], + accepts: [ + { + arg: 'id', + description: 'The sale id', + type: 'number', + required: true, + http: {source: 'path'} + }, { + arg: 'newPrice', + description: 'The new price', + type: 'number', + required: true + } + ], returns: { type: 'string', root: true }, http: { - path: `/updatePrice`, + path: `/:id/updatePrice`, verb: 'post' } }); - Self.updatePrice = async params => { - if (!params.price) params.price = 0; + Self.updatePrice = async(id, newPrice) => { + let $ = Self.app.models; + let transaction = await Self.beginTransaction({}); + let options = {transaction}; - let model = Self.app.models; - let manaDiscount; - let buyerDiscount = await model.ComponentRate.findOne({where: {code: 'buyerDiscount'}}); - let ticket = await getTicket(params); - let usesMana = await model.WorkerMana.findOne({where: {workerFk: ticket[0].client().salesPersonFk}, fields: 'amount'}); - let currentLine = await Self.app.models.Sale.findOne({where: {id: params.id}}); - let componentId = buyerDiscount.id; - - if (usesMana) { - manaDiscount = await model.ComponentRate.findOne({where: {code: 'mana'}}); - componentId = manaDiscount.id; - } - let value = (params.price - currentLine.price); - - let saleComponent = await Self.app.models.SaleComponent.findOne({ - where: { - componentFk: componentId, - saleFk: params.id - } - }); - - if (saleComponent) { - saleComponent.updateAttributes({value: saleComponent.value + value}).catch(() => { - throw new UserError(`Enter a valid number`); - }); - } else { - await Self.app.models.SaleComponent.create({ - saleFk: params.id, - componentFk: componentId, - value: value - }); - } - - await currentLine.updateAttributes({price: params.price}); - - query = `call vn.manaSpellersRequery(?)`; - await Self.rawSql(query, [ticket[0].client().salesPersonFk]); - }; - - async function getTicket(params) { - let model = Self.app.models; - let thisTicketIsEditable = await model.Ticket.isEditable(params.ticketFk); - if (!thisTicketIsEditable) - throw new UserError(`The sales of this ticket can't be modified`); - - return await model.Ticket.find({ - where: { - id: params.ticketFk - }, - include: [{ - relation: 'client', - scope: { - fields: ['salesPersonFk'] + try { + let filter = { + fields: ['id', 'ticketFk', 'price'], + include: { + relation: 'ticket', + scope: { + include: { + relation: 'client', + scope: { + fields: ['salesPersonFk'] + } + }, + fields: ['id', 'clientFk'] + } } - }], - fields: ['id', 'clientFk'] - }); - } + }; + let sale = await $.Sale.findById(id, filter, options); + + let isEditable = await $.Ticket.isEditable(sale.ticketFk); + if (!isEditable) + throw new UserError(`The sales of this ticket can't be modified`); + + let salesPerson = sale.ticket().client().salesPersonFk; + let usesMana = await $.WorkerMana.findOne({where: {workerFk: salesPerson}, fields: 'amount'}, options); + let componentCode = usesMana ? 'mana' : 'buyerDiscount'; + + let discount = await $.ComponentRate.findOne({where: {code: componentCode}}, options); + let componentId = discount.id; + let componentValue = newPrice - sale.price; + + let where = { + componentFk: componentId, + saleFk: id + }; + let saleComponent = await $.SaleComponent.findOne({where}, options); + + if (saleComponent) { + await $.SaleComponent.updateAll(where, { + value: saleComponent.value + componentValue + }, options); + } else { + await $.SaleComponent.create({ + saleFk: id, + componentFk: componentId, + value: componentValue + }, options); + } + + await sale.updateAttributes({price: newPrice}, options); + + query = `call vn.manaSpellersRequery(?)`; + await Self.rawSql(query, [salesPerson], options); + + await transaction.commit(); + } catch (error) { + await transaction.rollback(); + throw error; + } + }; }; diff --git a/modules/ticket/back/methods/ticket/specs/getSalespersonMana.spec.js b/modules/ticket/back/methods/ticket/specs/getSalespersonMana.spec.js index 3d7e084be..b08220d15 100644 --- a/modules/ticket/back/methods/ticket/specs/getSalespersonMana.spec.js +++ b/modules/ticket/back/methods/ticket/specs/getSalespersonMana.spec.js @@ -4,7 +4,7 @@ describe('ticket getSalesPersonMana()', () => { it('should get the mana of a salesperson of a given ticket', async() => { let mana = await app.models.Ticket.getSalesPersonMana(1); - expect(mana).toEqual(221); + expect(mana).toEqual(222); }); it('should return 0 if the given ticket does not exists', async() => { diff --git a/modules/ticket/back/models/sale-component.json b/modules/ticket/back/models/sale-component.json index e2649e09b..49edab2ae 100644 --- a/modules/ticket/back/models/sale-component.json +++ b/modules/ticket/back/models/sale-component.json @@ -11,7 +11,12 @@ "type": "Number" }, "saleFk": { - "id": true + "type": "Number", + "id": 2 + }, + "componentFk": { + "type": "Number", + "id": 1 } }, "relations": { diff --git a/modules/ticket/front/sale/index.js b/modules/ticket/front/sale/index.js index 535241796..0293f12d0 100644 --- a/modules/ticket/front/sale/index.js +++ b/modules/ticket/front/sale/index.js @@ -260,7 +260,7 @@ class Controller { updatePrice() { if (this.editedPrice != this.sale.price) { - this.$http.post(`/api/Sales/updatePrice`, {id: this.edit.id, price: this.editedPrice, ticketFk: this.ticket.id}).then(() => { + this.$http.post(`/api/Sales/${this.edit.id}/updatePrice`, {newPrice: this.editedPrice}).then(() => { this.sale.price = this.edit.price; this.vnApp.showSuccess(this.$translate.instant('Data saved!')); this.$scope.model.refresh(); diff --git a/modules/worker/back/methods/device/checkUuid.js b/modules/worker/back/methods/device/checkUuid.js new file mode 100644 index 000000000..73c6cb57c --- /dev/null +++ b/modules/worker/back/methods/device/checkUuid.js @@ -0,0 +1,61 @@ +/* +Author : Enrique Blasco BLanquer +Date: 27 de mayo de 2019 +*/ +module.exports = Self => { + Self.remoteMethodCtx('checkUuid', { + description: 'Check UUID from user', + accessType: 'WRITE', + accepts: [{ + arg: 'data', + type: 'object', + required: true, + description: 'uuid,model', + http: {source: 'body'} + }], + returns: [{ + type: 'Object', + root: true + }], + http: { + path: `/checkUuid`, + verb: 'POST' + } + }); + + Self.checkUuid = async(ctx, data) => { + const myUserId = ctx.req.accessToken.userId; + // 1 Check is a registered user with a uuid + let deviceUser = await Self.findOne({where: {userFk: myUserId, sn: data.uuid}}); + + if (deviceUser != null) + return {'state': true, 'mng': ''}; + else { + // 2 If it does not exist it can be for two reasons: + // 2.1 It is the first time that the application enters so we have to register a new user associated with the user + // 2.2 Has the user associated with a different uuid, so we deny access. + + let device = await Self.findOne({where: {userFk: myUserId}}); + if (device != null) { + // The device is already registered by another user, access is denied + return {'state': false, 'mng': 'Ya estas regisgtrado en otro dispositivo, contacta con los dioses de informática.'}; + } else { + // Check that the device is free + let aDevice = await Self.findOne({where: {sn: data.uuid}}); + if (aDevice != null) + return {'state': false, 'mng': 'El dispositivo esta siendo usado por otro usuario'}; + else { + // It's the first time you access the application, insert + /* await Self.rawSql('INSERT INTO vn2008.device (sn, model) VALUES (?,?);', [data.uuid, data.model]);*/ + await Self.create({ + sn: data.uuid, + model: data.model, + userFk: myUserId + }); + + return {'state': true, 'mng': 'Nuevo dispositivo registrado'}; + } + } + } + }; +}; diff --git a/modules/worker/back/methods/device/specs/checkUuid.spec.js b/modules/worker/back/methods/device/specs/checkUuid.spec.js new file mode 100644 index 000000000..c2784809c --- /dev/null +++ b/modules/worker/back/methods/device/specs/checkUuid.spec.js @@ -0,0 +1,11 @@ +const app = require('vn-loopback/server/server'); + +describe('device checkUuid()', () => { + it('should return an state equal to false', async() => { + let ctx = {req: {accessToken: {userId: 9}}}; + let data = {'uuid': '123', 'model': 'ihpne kike molon'}; + let result = await app.models.Device.checkUuid(ctx, data); + + expect(result.name).toBeFalsy(); + }); +}); diff --git a/modules/worker/back/methods/worker-mana/specs/getCurrentWorkerMana.spec.js b/modules/worker/back/methods/worker-mana/specs/getCurrentWorkerMana.spec.js index 1d48eef58..fe0b119f3 100644 --- a/modules/worker/back/methods/worker-mana/specs/getCurrentWorkerMana.spec.js +++ b/modules/worker/back/methods/worker-mana/specs/getCurrentWorkerMana.spec.js @@ -4,7 +4,7 @@ describe('workerMana getCurrentWorkerMana()', () => { it('should get the mana of the logged worker', async() => { let mana = await app.models.WorkerMana.getCurrentWorkerMana({req: {accessToken: {userId: 18}}}); - expect(mana).toEqual(221); + expect(mana).toEqual(222); }); it('should return 0 if the user doesnt uses mana', async() => { diff --git a/modules/worker/back/methods/worker-time-control/addAutoTime.js b/modules/worker/back/methods/worker-time-control/addAutoTime.js new file mode 100644 index 000000000..7d58d2c22 --- /dev/null +++ b/modules/worker/back/methods/worker-time-control/addAutoTime.js @@ -0,0 +1,48 @@ +/* +Author : Enrique Blasco BLanquer +Date: 27 de mayo de 2019 +*/ +module.exports = Self => { + Self.remoteMethodCtx('addAutoTime', { + description: 'Adds a new hour registry by app in manual 0', + accessType: 'WRITE', + accepts: [{ + arg: 'data', + type: 'object', + required: true, + description: 'timed', + http: {source: 'body'} + }], + returns: [{ + type: 'Object', + root: true + }], + http: { + path: `/addAutoTime`, + verb: 'POST' + } + }); + + Self.addAutoTime = async(ctx, data) => { + const myUserId = ctx.req.accessToken.userId; + + // get all worked time control, needed to calculate order + let hours = await Self.rawSql(`SELECT * FROM vn.workerTimeControl + WHERE userFk = ? + AND DATE(timed) = CURDATE() + ORDER BY timed DESC LIMIT 1`, [myUserId]); + + // 1 get next order + let order = 0; + if (hours.length > 0) + order = hours[hours.length - 1].order; + + // 2 create element in db + return Self.create({ + userFk: myUserId, + timed: data.timed, + order: order + 1, + manual: 0 + }); + }; +}; diff --git a/modules/worker/back/methods/worker-time-control/getHoursWorked.js b/modules/worker/back/methods/worker-time-control/getHoursWorked.js new file mode 100644 index 000000000..315b68cd1 --- /dev/null +++ b/modules/worker/back/methods/worker-time-control/getHoursWorked.js @@ -0,0 +1,121 @@ +/* +Author : Enrique Blasco BLanquer +Date: 28 de mayo de 2019 +*/ +module.exports = Self => { + Self.remoteMethodCtx('getHoursWorked', { + description: 'Get worked hours in current week, month and year', + accessType: 'WRITE', + returns: [{ + type: 'Object', + root: true + }], + http: { + path: `/getHoursWorked`, + verb: 'GET' + } + }); + + Self.getHoursWorked = async(ctx, data) => { + let totalHours = 0; // total hours worked in one year + let totalMinutes = 0; // total minutes worked in one year + let totalHoursMonth = 0; // total hours worked in one month + let totalMinutesMonth = 0; // total minutes worked in one month + let totalHoursWeek = 0; // total hours worked in one week + let totalMinutesWeek = 0; // total minutes worked in one week + const myUserId = ctx.req.accessToken.userId; // user id + let today = new Date(); // needed to calculate total hours worked to current date + let fromDate = today.getFullYear() + '-01-01'; // from date, current year + let toDate = today.getFullYear() + '-12-31'; // to date, current year + + + // 1 hours worked in a year + let hoursYear = await Self.rawSql(`SELECT wtc.userFk, DATE(wtc.timed) dated, + UNIX_TIMESTAMP(MIN(timed))timedStart, + SEC_TO_TIME(SUM(if( mod(wtc.order,2)=1, + UNIX_TIMESTAMP(timed) *-1, + UNIX_TIMESTAMP(timed)))) timeWorkDay + FROM vn.workerTimeControl wtc + WHERE wtc.timed BETWEEN ? AND ? AND userFk = ? + GROUP BY wtc.userFk,dated ORDER BY dated DESC`, [fromDate, toDate, myUserId]); + + + // 2 Get days of week + let week = []; + // Starting Monday not Sunday + let current = new Date(); + current.setDate((current.getDate() - current.getDay() + 1)); + for (let i = 0; i < 7; i++) { + week.push( + new Date(current) + ); + current.setDate(current.getDate() + 1); + } + + // 3 I have all timed control for one year... NOW I CALCULATE TOTAL HOURS IN YEAR, MONTH, WEEK, Let's GO! + for (hour of hoursYear) { + if (parseInt(hour.timeWorkDay.split(':')[0]) > 0) { + // YEAR + totalHours += parseInt(hour.timeWorkDay.split(':')[0]); + totalMinutes += parseInt(hour.timeWorkDay.split(':')[1]); + // If it exceeds 5 hours we add 20 minutes of breakfast. + if (parseInt(hour.timeWorkDay.split(':')[0]) >= 5) + totalMinutes += 20; + // MONTH + + if ((new Date(hour.dated)).getMonth() == today.getMonth()) { + totalHoursMonth += parseInt(hour.timeWorkDay.split(':')[0]); + totalMinutesMonth += parseInt(hour.timeWorkDay.split(':')[1]); + // If it exceeds 5 hours we add 20 minutes of breakfast. + if (parseInt(hour.timeWorkDay.split(':')[0]) >= 5) + totalMinutesMonth += 20; + } + // WEEK + for (day of week) { + let dayOfWeek = new Date(day); + let dayOfCurrentWeek = new Date(hour.dated); + if (dayOfWeek.getMonth() == dayOfCurrentWeek.getMonth() && dayOfWeek.getDate() == dayOfCurrentWeek.getDate()) { + totalHoursWeek += parseInt(hour.timeWorkDay.split(':')[0]); + totalMinutesWeek += parseInt(hour.timeWorkDay.split(':')[1]); + // If it exceeds 5 hours we add 20 minutes of breakfast. + if (parseInt(hour.timeWorkDay.split(':')[0]) >= 5) + totalMinutesWeek += 20; + break; + } + } + } + } + + // TOTAL WORKED HOURS IN THE YEAR + totalHours += totalMinutes / 60; + totalHours = decimalToHour(totalHours); + + // TOTAL WORKED HOURS IN THE MONTH + totalHoursMonth += totalMinutesMonth / 60; + totalHoursMonth = decimalToHour(totalHoursMonth); + + // TOTAL WORKED HOURS IN THE WEEK + totalHoursWeek += totalMinutesWeek / 60; + totalHoursWeek = decimalToHour(totalHoursWeek); + + return { + 'totalWorekdYear': totalHours, + 'totalWorekdMonth': totalHoursMonth, + 'totalWorkedWeek': totalHoursWeek + }; + }; +}; + +/* +function to calculate hours and minutes from decimal value +*/ +function decimalToHour(value) { + let decimalTime = parseFloat(value); + decimalTime = decimalTime * 60 * 60; + let hoursDay = Math.floor((decimalTime / (60 * 60))); + decimalTime = decimalTime - (hoursDay * 60 * 60); + let minutesDay = Math.floor((decimalTime / 60)); + return hoursDay + ':' + minutesDay; +} + + diff --git a/modules/worker/back/methods/worker-time-control/getWorkedWeek.js b/modules/worker/back/methods/worker-time-control/getWorkedWeek.js new file mode 100644 index 000000000..67e864344 --- /dev/null +++ b/modules/worker/back/methods/worker-time-control/getWorkedWeek.js @@ -0,0 +1,78 @@ +/* +Author : Enrique Blasco BLanquer +Date: 29 de mayo de 2019 +*/ +module.exports = Self => { + Self.remoteMethodCtx('getWorkedWeek', { + description: 'get worked week info', + accessType: 'WRITE', + returns: [{ + type: 'Object', + root: true + }], + http: { + path: `/getWorkedWeek`, + verb: 'GET' + } + }); + + Self.getWorkedWeek = async(ctx, data) => { + const myUserId = ctx.req.accessToken.userId; // user id + let lastDate = new Date('1986-09-24'); // reference date + let diff = 0; // difference of value between two dates + let total = 0; // total hours + + // 1 Get days of week + let week = []; + // 2 Starting Monday not Sunday + let current = new Date(); + current.setDate((current.getDate() - current.getDay() + 1)); + for (let i = 0; i < 7; i++) { + week.push( + new Date(current) + ); + current.setDate(current.getDate() + 1); + } + + let fromDate = week[0].getFullYear() + '-' + (week[0].getMonth() + 1) + '-' + week[0].getDate(); + let toDate = week[week.length - 1].getFullYear() + '-' + (week[week.length - 1].getMonth() + 1) + '-' + week[week.length - 1].getDate(); + + + // 3 hours worked in a current week + let hoursWeek = await Self.rawSql(`SELECT wtc.timed ,wtc.order + FROM vn.workerTimeControl wtc + WHERE userFk = ? + AND DATE(timed) BETWEEN ? AND ? ORDER BY timed DESC;`, [myUserId, fromDate, toDate]); + + // 4 treat data + let isFirst = true; + for (let i = hoursWeek.length - 1; i >= 0; i--) { + let d = new Date(hoursWeek[i].timed); + if (isFirst) { + lastDate = d; + isFirst = false; + } else { + if (lastDate.getDate() === d.getDate()) { + diff += Math.abs(d.getTime() - lastDate.getTime()); + lastDate = d; + } else { + total += diff; + diff = 0; + lastDate = d; + } + } + } + total += diff; + + // 5 calculate hours and minutes + let decimalTime = total / 1000 / 3600; + decimalTime = decimalTime * 60 * 60; + let hours = Math.floor((decimalTime / (60 * 60))); + decimalTime = decimalTime - (hours * 60 * 60); + let minutes = Math.floor((decimalTime / 60)); + + return {'timeds': hoursWeek, 'totalWorked': hours + ':' + minutes}; + }; +}; + + diff --git a/modules/worker/back/methods/worker-time-control/specs/addAutoTime.spec.js b/modules/worker/back/methods/worker-time-control/specs/addAutoTime.spec.js new file mode 100644 index 000000000..bdc5d6ecb --- /dev/null +++ b/modules/worker/back/methods/worker-time-control/specs/addAutoTime.spec.js @@ -0,0 +1,11 @@ +const app = require('vn-loopback/server/server'); + +describe('workerTimeControl addAutoTime()', () => { + it('should return an undefined value', async() => { + let ctx = {req: {accessToken: {userId: 9}}}; + let data = {'timed': new Date()}; + let result = await app.models.WorkerTimeControl.addAutoTime(ctx, data); + + expect(result).toBeUndefined(); + }); +}); diff --git a/modules/worker/back/methods/worker-time-control/specs/getHoursWorked.spec.js b/modules/worker/back/methods/worker-time-control/specs/getHoursWorked.spec.js new file mode 100644 index 000000000..2cfd28b77 --- /dev/null +++ b/modules/worker/back/methods/worker-time-control/specs/getHoursWorked.spec.js @@ -0,0 +1,10 @@ +const app = require('vn-loopback/server/server'); + +describe('workerTimeControl getHoursWorked()', () => { + it('should return an totalWorkedYear to be defined', async() => { + let ctx = {req: {accessToken: {userId: 9}}}; + let result = await app.models.WorkerTimeControl.getHoursWorked(ctx, null); + + expect(result.totalWorekdYear).toBeDefined(); + }); +}); diff --git a/modules/worker/back/methods/worker-time-control/specs/getWorkedWeek.spec.js b/modules/worker/back/methods/worker-time-control/specs/getWorkedWeek.spec.js new file mode 100644 index 000000000..4ea7bc727 --- /dev/null +++ b/modules/worker/back/methods/worker-time-control/specs/getWorkedWeek.spec.js @@ -0,0 +1,10 @@ +const app = require('vn-loopback/server/server'); + +describe('workerTimeControl getWorkedWeek()', () => { + it('should return an timeds to be defined', async() => { + let ctx = {req: {accessToken: {userId: 9}}}; + let result = await app.models.WorkerTimeControl.getWorkedWeek(ctx, null); + + expect(result.timeds).toBeDefined(); + }); +}); diff --git a/modules/worker/back/methods/worker/getWorkerInfo.js b/modules/worker/back/methods/worker/getWorkerInfo.js new file mode 100644 index 000000000..c91f84078 --- /dev/null +++ b/modules/worker/back/methods/worker/getWorkerInfo.js @@ -0,0 +1,98 @@ +/* +Author : Enrique Blasco BLanquer +Date: 28 de mayo de 2019 +*/ +module.exports = Self => { + Self.remoteMethodCtx('getWorkerInfo', { + description: 'Get worker info (name, isWorking, total worked hours ...)', + accessType: 'WRITE', + returns: [{ + type: 'Object', + root: true + }], + http: { + path: `/getWorkerInfo`, + verb: 'GET' + } + }); + + Self.getWorkerInfo = async(ctx, data) => { + let prevHour = new Date(); // default value to start work + let diff = 0; // difference of value between two dates + let isOdd = true; // determine if timed is odd or not in db + const myUserId = ctx.req.accessToken.userId; // get user id + + + // 1 get name and photo for the user + let [user] = await Self.rawSql(`SELECT u.name, t.Foto FROM vn.user u INNER JOIN vn2008.Trabajadores t ON u.id = t.user_id WHERE id = ?;`, [myUserId]); + // 2 get all jornaly work time registered + let workedHours = await Self.rawSql(`SELECT * FROM vn.workerTimeControl WHERE userFk = ? AND DATE(timed) = CURDATE() ORDER BY timed ASC;`, [myUserId]); + let today = new Date(); + // 3 get the number of hours to work in one day + let date = today.getFullYear() + '-' + (today.getMonth() + 1) + '-' + today.getDate(); + let [hoursForDay] = await Self.rawSql(`SELECT cl.hours_week AS hoursWeek, + GROUP_CONCAT(DISTINCT LEFT(j.start,2) ORDER BY j.start ASC SEPARATOR '-') start , + GROUP_CONCAT(DISTINCT LEFT(j.end,2) ORDER BY j.end ASC SEPARATOR '-') end, + CAST(IFNULL((SUM(TIME_TO_SEC(j.end))-SUM(TIME_TO_SEC(j.start)))/3600,if(cl.hours_week=40 + AND DAYOFWEEK(t.dated) IN(2,3,4,5,6),8,0)) AS DECIMAL(10,2)) workingHours + FROM vn.time t + LEFT JOIN postgresql.business b ON t.dated BETWEEN b.date_start AND ifnull(b.date_end,? ) + LEFT JOIN postgresql.profile AS pr ON b.client_id = pr.profile_id + LEFT JOIN postgresql.person AS p ON pr.person_id = p.person_id + LEFT JOIN vn.worker AS w ON p.id_trabajador = w.id + LEFT JOIN postgresql.business_labour AS bl ON b.business_id = bl.business_id + LEFT JOIN postgresql.calendar_labour_type AS cl ON bl.calendar_labour_type_id = cl.calendar_labour_type_id + LEFT JOIN postgresql.journey AS j ON j.business_id = b.business_id and j.day_id=WEEKDAY(t.dated)+1 + WHERE t.dated BETWEEN ? AND ? AND userFk = ? + GROUP BY w.userFk,dated`, [date, date, date, myUserId]); + + // 4 Add all the hours and see the total worked + for (hour of workedHours) { + if (!isOdd) + diff += Math.abs((new Date(hour.timed)).getTime() - prevHour.getTime()); + else + prevHour = new Date(hour.timed); + + isOdd = !isOdd; + } + + // 5 calculate hours and minutes from a number value + let decimalTime = diff / 1000 / 3600; + decimalTime = decimalTime * 60 * 60; + let hours = Math.floor((decimalTime / (60 * 60))); + decimalTime = decimalTime - (hours * 60 * 60); + let minutes = Math.floor((decimalTime / 60)); + + // 6 default total hours + let totalHours = '7:40'; + let hoursWeek = 40; + + // 7 Get the hours you have to work today and the hours to work in a week + if (hoursForDay != null) { + // If it exceeds 5 hours we take 20 minutes of breakfast. + if (hoursForDay.workingHours > 5) + hoursForDay.workingHours -= 20 * 0.016666; + let decimalTime = parseFloat(hoursForDay.workingHours); + decimalTime = decimalTime * 60 * 60; + let hoursDay = Math.floor((decimalTime / (60 * 60))); + decimalTime = decimalTime - (hoursDay * 60 * 60); + let minutesDay = Math.floor((decimalTime / 60)); + totalHours = hoursDay + ':' + minutesDay; + } + + + // 8 return value + if (hoursForDay != null) + hoursWeek = hoursForDay.hoursWeek; + return { + 'name': user.name, + 'hours': hours, + 'minutes': minutes, + 'today': today, + 'isWorking': !isOdd, + 'lastDate': prevHour, + 'totalHours': totalHours, + 'hoursWeek': hoursWeek + }; + }; +}; diff --git a/modules/worker/back/model-config.json b/modules/worker/back/model-config.json index 3a98fc038..35a039d3c 100644 --- a/modules/worker/back/model-config.json +++ b/modules/worker/back/model-config.json @@ -46,5 +46,8 @@ }, "WorkerTimeControl": { "dataSource": "vn" + }, + "Device": { + "dataSource": "vn" } } diff --git a/modules/worker/back/models/device.js b/modules/worker/back/models/device.js new file mode 100644 index 000000000..ada0ba33b --- /dev/null +++ b/modules/worker/back/models/device.js @@ -0,0 +1,11 @@ +const UserError = require('vn-loopback/util/user-error'); + +module.exports = Self => { + require('../methods/device/checkUuid')(Self); + + Self.rewriteDbError(function(err) { + if (err.code === 'ER_DUP_ENTRY') + return new UserError(``); + return err; + }); +}; diff --git a/modules/worker/back/models/device.json b/modules/worker/back/models/device.json new file mode 100644 index 000000000..5367faedf --- /dev/null +++ b/modules/worker/back/models/device.json @@ -0,0 +1,28 @@ +{ + "name": "Device", + "base": "VnModel", + "options": { + "mysql": { + "table": "device" + } + }, + "properties": { + "id": { + "id": true, + "type": "Number" + }, + "sn": { + "type": "String" + }, + "model": { + "type": "String" + } + }, + "relations": { + "user": { + "type": "belongsTo", + "model": "Account", + "foreignKey": "userFk" + } + } +} diff --git a/modules/worker/back/models/worker-time-control.js b/modules/worker/back/models/worker-time-control.js index 4a065f430..4ec5bf8dd 100644 --- a/modules/worker/back/models/worker-time-control.js +++ b/modules/worker/back/models/worker-time-control.js @@ -3,6 +3,9 @@ const UserError = require('vn-loopback/util/user-error'); module.exports = Self => { require('../methods/worker-time-control/filter')(Self); require('../methods/worker-time-control/addTime')(Self); + require('../methods/worker-time-control/addAutoTime')(Self); + require('../methods/worker-time-control/getHoursWorked')(Self); + require('../methods/worker-time-control/getWorkedWeek')(Self); Self.rewriteDbError(function(err) { if (err.code === 'ER_DUP_ENTRY') diff --git a/modules/worker/back/models/worker.js b/modules/worker/back/models/worker.js index ba4a396ee..1d2a62ce4 100644 --- a/modules/worker/back/models/worker.js +++ b/modules/worker/back/models/worker.js @@ -2,4 +2,5 @@ module.exports = Self => { require('../methods/worker/filter')(Self); require('../methods/worker/mySubordinates')(Self); require('../methods/worker/isSubordinate')(Self); + require('../methods/worker/getWorkerInfo')(Self); };