From 5d0f72af4e85e7725471bedd8197704ed89eb933 Mon Sep 17 00:00:00 2001 From: jgallego Date: Thu, 6 Feb 2020 16:04:23 +0100 Subject: [PATCH 1/3] zoneDoCalc --- db/changes/10141-zoneDoCalc/00-ticket.sql | 19 +++++++ .../10141-zoneDoCalc/01-ticket_doCalc.sql | 56 +++++++++++++++++++ .../01-zoneClosure_recalc.sql | 1 + .../10141-zoneDoCalc/02-procNoOverlap.sql | 30 ++++++++++ modules/agency/back/model-config.json | 2 +- .../agency/back/models/zone-calc-ticket.js | 24 ++++++++ ...one-closure.json => zone-calc-ticket.json} | 12 +--- modules/agency/back/models/zone-closure.js | 13 ----- modules/agency/back/models/zone-event.js | 8 --- modules/agency/back/models/zone-exclusion.js | 11 ---- modules/agency/back/models/zone.js | 10 ---- 11 files changed, 133 insertions(+), 53 deletions(-) create mode 100644 db/changes/10141-zoneDoCalc/00-ticket.sql create mode 100644 db/changes/10141-zoneDoCalc/01-ticket_doCalc.sql create mode 100644 db/changes/10141-zoneDoCalc/01-zoneClosure_recalc.sql create mode 100644 db/changes/10141-zoneDoCalc/02-procNoOverlap.sql create mode 100644 modules/agency/back/models/zone-calc-ticket.js rename modules/agency/back/models/{zone-closure.json => zone-calc-ticket.json} (62%) delete mode 100644 modules/agency/back/models/zone-closure.js delete mode 100644 modules/agency/back/models/zone-exclusion.js diff --git a/db/changes/10141-zoneDoCalc/00-ticket.sql b/db/changes/10141-zoneDoCalc/00-ticket.sql new file mode 100644 index 0000000000..c116e51399 --- /dev/null +++ b/db/changes/10141-zoneDoCalc/00-ticket.sql @@ -0,0 +1,19 @@ +ALTER TABLE `vn`.`ticket` +ADD COLUMN `zonePrice` DECIMAL(10,2) NULL DEFAULT NULL AFTER `collectionFk`, +ADD COLUMN `zoneBonus` DECIMAL(10,2) NULL DEFAULT NULL AFTER `zonePrice`, +ADD COLUMN `zoneClosure` TIME NULL AFTER `zoneBonus`; + +CREATE TABLE vn.`zoneCalcTicket` ( + `zoneFk` int(11) NOT NULL PRIMARY KEY, + CONSTRAINT `zoneCalcTicketfk_1` FOREIGN KEY (`zoneFk`) REFERENCES `zone` (`id`) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +DROP EVENT IF EXISTS vn.`zone_doCalc`; +CREATE DEFINER=`root`@`%` EVENT vn.`zone_doCalc` + ON SCHEDULE EVERY 15 SECOND STARTS '2020-01-31 11:32:30' + ON COMPLETION PRESERVE ENABLE + DO CALL util.procNoOverlap('vn.zone_doCalc'); + +DROP TABLE `vn`.`zoneConfig`; + +DROP procedure IF EXISTS vn.`zoneClosure_recalc`; \ No newline at end of file diff --git a/db/changes/10141-zoneDoCalc/01-ticket_doCalc.sql b/db/changes/10141-zoneDoCalc/01-ticket_doCalc.sql new file mode 100644 index 0000000000..d7538ff84e --- /dev/null +++ b/db/changes/10141-zoneDoCalc/01-ticket_doCalc.sql @@ -0,0 +1,56 @@ +USE `vn`; +DROP procedure IF EXISTS `zone_doCalc`; + +DELIMITER $$ +USE `vn`$$ +CREATE DEFINER=`root`@`%` PROCEDURE `zone_doCalc`() +proc: BEGIN +/** + * Updates ticket fields related with zone + */ + DECLARE vDone BOOL; + DECLARE vTicketFk INT; + DECLARE vShipped DATE; + DECLARE vZoneFk INT; + + DECLARE cCur CURSOR FOR + SELECT t.id, t.shipped, t.zoneFk + FROM zoneCalcTicket zct + JOIN ticket t ON t.zoneFk = zct.zoneFk + WHERE shipped >= CURDATE(); + + DECLARE CONTINUE HANDLER FOR NOT FOUND + SET vDone = TRUE; + + OPEN cCur; + + myLoop: LOOP + SET vDone = FALSE; + FETCH cCur INTO vTicketFk, vShipped, vZoneFk; + + IF vDone THEN + LEAVE myLoop; + END IF; + + DROP TEMPORARY TABLE IF EXISTS tmp.zone; + CREATE TEMPORARY TABLE tmp.zone + (INDEX (id)) + ENGINE = MEMORY + SELECT vZoneFk id; + + CALL zone_getOptionsForShipment(vShipped, TRUE); + + UPDATE ticket t + LEFT JOIN tmp.zoneOption zo ON TRUE + SET zonePrice = zo.price, zoneBonus = zo.bonus, zoneClosure = zo.`hour` + WHERE t.id = vTicketFk; + + END LOOP; + + CLOSE cCur; + + DELETE FROM zoneCalcTicket; +END$$ + +DELIMITER ; + diff --git a/db/changes/10141-zoneDoCalc/01-zoneClosure_recalc.sql b/db/changes/10141-zoneDoCalc/01-zoneClosure_recalc.sql new file mode 100644 index 0000000000..f015eb894b --- /dev/null +++ b/db/changes/10141-zoneDoCalc/01-zoneClosure_recalc.sql @@ -0,0 +1 @@ +USE `vn`; diff --git a/db/changes/10141-zoneDoCalc/02-procNoOverlap.sql b/db/changes/10141-zoneDoCalc/02-procNoOverlap.sql new file mode 100644 index 0000000000..253264ce99 --- /dev/null +++ b/db/changes/10141-zoneDoCalc/02-procNoOverlap.sql @@ -0,0 +1,30 @@ +USE `util`; +DROP procedure IF EXISTS `procNoOverlap`; + +DELIMITER $$ +USE `util`$$ +CREATE PROCEDURE `procNoOverlap` (procName VARCHAR(255)) +SQL SECURITY INVOKER +proc: BEGIN +/** + * call procedure without overlap + */ + DECLARE vIsChanged BOOL; + + DECLARE CONTINUE HANDLER FOR SQLEXCEPTION + BEGIN + DO RELEASE_LOCK(procName); + RESIGNAL; + END; + + IF !GET_LOCK(procName, 0) THEN + LEAVE proc; + END IF; + + CALL exec(CONCAT('CALL ', procName)); + + DO RELEASE_LOCK(procName); +END$$ + +DELIMITER ; + diff --git a/modules/agency/back/model-config.json b/modules/agency/back/model-config.json index 7638e3f6c5..c9a49ffe9b 100644 --- a/modules/agency/back/model-config.json +++ b/modules/agency/back/model-config.json @@ -11,7 +11,7 @@ "Zone": { "dataSource": "vn" }, - "ZoneClosure": { + "ZoneCalcTicket": { "dataSource": "vn" }, "ZoneEvent": { diff --git a/modules/agency/back/models/zone-calc-ticket.js b/modules/agency/back/models/zone-calc-ticket.js new file mode 100644 index 0000000000..c3633e8f42 --- /dev/null +++ b/modules/agency/back/models/zone-calc-ticket.js @@ -0,0 +1,24 @@ +const app = require('vn-loopback/server/server'); + + +module.exports = Self => { + app.on('started', function() { + let models = ['Zone', 'ZoneEvent', 'ZoneExclusion']; + + for (let modelName of models) { + let Model = app.models[modelName]; + + Model.observe('after save', doCalc); + Model.observe('after delete', doCalc); + } + + async function doCalc(ctx) { + try { + await Self.create({zoneFk: ctx.instance.zoneFk || ctx.instance.id}); + } catch (err) { + if (err.code != 'ER_DUP_ENTRY') + throw err; + } + } + }); +}; diff --git a/modules/agency/back/models/zone-closure.json b/modules/agency/back/models/zone-calc-ticket.json similarity index 62% rename from modules/agency/back/models/zone-closure.json rename to modules/agency/back/models/zone-calc-ticket.json index 8953748389..5083d08eda 100644 --- a/modules/agency/back/models/zone-closure.json +++ b/modules/agency/back/models/zone-calc-ticket.json @@ -1,23 +1,15 @@ { - "name": "ZoneClosure", + "name": "ZoneCalcTicket", "base": "VnModel", "options": { "mysql": { - "table": "zoneClosure" + "table": "zoneCalcTicket" } }, "properties": { "zoneFk": { "id": true, "type": "Number" - }, - "dated": { - "type": "Date", - "required": true - }, - "hour": { - "type": "date", - "required": true } }, "relations": { diff --git a/modules/agency/back/models/zone-closure.js b/modules/agency/back/models/zone-closure.js deleted file mode 100644 index 8b66e31ae7..0000000000 --- a/modules/agency/back/models/zone-closure.js +++ /dev/null @@ -1,13 +0,0 @@ -module.exports = Self => { - Self.doRecalc = async function() { - try { - await Self.rawSql(` - CREATE EVENT zoneClosure_doRecalc - ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 15 SECOND - DO CALL zoneClosure_recalc; - `); - } catch (err) { - if (err.code != 'ER_EVENT_ALREADY_EXISTS') throw err; - } - }; -}; diff --git a/modules/agency/back/models/zone-event.js b/modules/agency/back/models/zone-event.js index 46b2df2029..d4fad8e965 100644 --- a/modules/agency/back/models/zone-event.js +++ b/modules/agency/back/models/zone-event.js @@ -34,12 +34,4 @@ module.exports = Self => { }, { message: `You should mark at least one week day` }); - - Self.observe('after save', async function() { - await app.models.ZoneClosure.doRecalc(); - }); - - Self.observe('after delete', async function() { - await app.models.ZoneClosure.doRecalc(); - }); }; diff --git a/modules/agency/back/models/zone-exclusion.js b/modules/agency/back/models/zone-exclusion.js deleted file mode 100644 index 51998aab87..0000000000 --- a/modules/agency/back/models/zone-exclusion.js +++ /dev/null @@ -1,11 +0,0 @@ -const app = require('vn-loopback/server/server'); - -module.exports = Self => { - Self.observe('after save', async function() { - await app.models.ZoneClosure.doRecalc(); - }); - - Self.observe('after delete', async function() { - await app.models.ZoneClosure.doRecalc(); - }); -}; diff --git a/modules/agency/back/models/zone.js b/modules/agency/back/models/zone.js index 9d715a8d88..0c3ac24f66 100644 --- a/modules/agency/back/models/zone.js +++ b/modules/agency/back/models/zone.js @@ -1,5 +1,3 @@ -const app = require('vn-loopback/server/server'); - module.exports = Self => { require('../methods/zone/clone')(Self); require('../methods/zone/getLeaves')(Self); @@ -9,12 +7,4 @@ module.exports = Self => { Self.validatesPresenceOf('agencyModeFk', { message: `Agency cannot be blank` }); - - Self.observe('after save', async function() { - await app.models.ZoneClosure.doRecalc(); - }); - - Self.observe('after delete', async function() { - await app.models.ZoneClosure.doRecalc(); - }); }; From d1c8c8ad5884496fcd2a31952312bfe2541ecd0e Mon Sep 17 00:00:00 2001 From: Bernat Exposito Domenech Date: Mon, 10 Feb 2020 13:22:43 +0100 Subject: [PATCH 2/3] ticket/client.sms validations --- modules/client/front/sms/index.html | 5 ++++- modules/client/front/sms/index.js | 19 +++++++++++++++---- modules/client/front/sms/index.spec.js | 20 ++++++++++++++++++++ modules/client/front/sms/locale/es.yml | 4 +++- modules/ticket/front/sms/index.html | 5 ++++- modules/ticket/front/sms/index.js | 19 +++++++++++++++---- modules/ticket/front/sms/index.spec.js | 20 ++++++++++++++++++++ modules/ticket/front/sms/locale/es.yml | 4 +++- 8 files changed, 84 insertions(+), 12 deletions(-) diff --git a/modules/client/front/sms/index.html b/modules/client/front/sms/index.html index ac7a206512..facbb76948 100644 --- a/modules/client/front/sms/index.html +++ b/modules/client/front/sms/index.html @@ -8,7 +8,9 @@ + ng-model="$ctrl.sms.destination" + required="true" + rule> @@ -18,6 +20,7 @@ ng-model="$ctrl.sms.message" rows="5" maxlength="160" + required="true" rule> diff --git a/modules/client/front/sms/index.js b/modules/client/front/sms/index.js index 1bf2fb99c8..851ce1a66e 100644 --- a/modules/client/front/sms/index.js +++ b/modules/client/front/sms/index.js @@ -28,12 +28,23 @@ class Controller extends Component { onResponse(response) { if (response === 'accept') { - this.$http.post(`Clients/${this.$params.id}/sendSms`, this.sms).then(res => { - this.vnApp.showMessage(this.$translate.instant('SMS sent!')); + try { + if (!this.sms.destination) + throw new Error(`The destination can't be empty`); + if (!this.sms.message) + throw new Error(`The message can't be empty`); - if (res.data) this.emit('send', {response: res.data}); - }); + this.$http.post(`Clients/${this.$params.id}/sendSms`, this.sms).then(res => { + this.vnApp.showMessage(this.$translate.instant('SMS sent!')); + + if (res.data) this.emit('send', {response: res.data}); + }); + } catch (e) { + this.vnApp.showError(this.$translate.instant(e.message)); + return false; + } } + return true; } } diff --git a/modules/client/front/sms/index.spec.js b/modules/client/front/sms/index.spec.js index c2a7eb9352..26a597c174 100644 --- a/modules/client/front/sms/index.spec.js +++ b/modules/client/front/sms/index.spec.js @@ -30,6 +30,26 @@ describe('Client', () => { expect(controller.vnApp.showMessage).toHaveBeenCalledWith('SMS sent!'); }); + + it('should call onResponse without the destination and show an error snackbar', () => { + controller.sms = {destinationFk: 101, message: 'My SMS'}; + + spyOn(controller.vnApp, 'showError'); + + controller.onResponse('accept'); + + expect(controller.vnApp.showError).toHaveBeenCalledWith(`The destination can't be empty`); + }); + + it('should call onResponse without the message and show an error snackbar', () => { + controller.sms = {destinationFk: 101, destination: 222222222}; + + spyOn(controller.vnApp, 'showError'); + + controller.onResponse('accept'); + + expect(controller.vnApp.showError).toHaveBeenCalledWith(`The message can't be empty`); + }); }); describe('charactersRemaining()', () => { diff --git a/modules/client/front/sms/locale/es.yml b/modules/client/front/sms/locale/es.yml index f26c8ba24f..4438e4fce4 100644 --- a/modules/client/front/sms/locale/es.yml +++ b/modules/client/front/sms/locale/es.yml @@ -2,4 +2,6 @@ Send SMS: Enviar SMS Destination: Destinatario Message: Mensaje SMS sent!: ¡SMS enviado! -Characters remaining: Carácteres restantes \ No newline at end of file +Characters remaining: Carácteres restantes +The destination can't be empty: El destinatario no puede estar vacio +The message can't be empty: El mensaje no puede estar vacio \ No newline at end of file diff --git a/modules/ticket/front/sms/index.html b/modules/ticket/front/sms/index.html index ac7a206512..f74bc29e5e 100644 --- a/modules/ticket/front/sms/index.html +++ b/modules/ticket/front/sms/index.html @@ -8,7 +8,9 @@ + ng-model="$ctrl.sms.destination" + required="true" + rule> @@ -18,6 +20,7 @@ ng-model="$ctrl.sms.message" rows="5" maxlength="160" + required="true" rule> diff --git a/modules/ticket/front/sms/index.js b/modules/ticket/front/sms/index.js index 1f2c7f9c05..0d639d46e2 100644 --- a/modules/ticket/front/sms/index.js +++ b/modules/ticket/front/sms/index.js @@ -28,12 +28,23 @@ class Controller extends Component { onResponse(response) { if (response === 'accept') { - this.$http.post(`Tickets/${this.$params.id}/sendSms`, this.sms).then(res => { - this.vnApp.showMessage(this.$translate.instant('SMS sent!')); + try { + if (!this.sms.destination) + throw new Error(`The destination can't be empty`); + if (!this.sms.message) + throw new Error(`The message can't be empty`); - if (res.data) this.emit('send', {response: res.data}); - }); + this.$http.post(`Tickets/${this.$params.id}/sendSms`, this.sms).then(res => { + this.vnApp.showMessage(this.$translate.instant('SMS sent!')); + + if (res.data) this.emit('send', {response: res.data}); + }); + } catch (e) { + this.vnApp.showError(this.$translate.instant(e.message)); + return false; + } } + return true; } } diff --git a/modules/ticket/front/sms/index.spec.js b/modules/ticket/front/sms/index.spec.js index 5565c36230..d02b3f3eb6 100644 --- a/modules/ticket/front/sms/index.spec.js +++ b/modules/ticket/front/sms/index.spec.js @@ -29,6 +29,26 @@ describe('Ticket', () => { expect(controller.vnApp.showMessage).toHaveBeenCalledWith('SMS sent!'); }); + + it('should call onResponse without the destination and show an error snackbar', () => { + controller.sms = {destinationFk: 101, message: 'My SMS'}; + + spyOn(controller.vnApp, 'showError'); + + controller.onResponse('accept'); + + expect(controller.vnApp.showError).toHaveBeenCalledWith(`The destination can't be empty`); + }); + + it('should call onResponse without the message and show an error snackbar', () => { + controller.sms = {destinationFk: 101, destination: 222222222}; + + spyOn(controller.vnApp, 'showError'); + + controller.onResponse('accept'); + + expect(controller.vnApp.showError).toHaveBeenCalledWith(`The message can't be empty`); + }); }); describe('charactersRemaining()', () => { diff --git a/modules/ticket/front/sms/locale/es.yml b/modules/ticket/front/sms/locale/es.yml index f26c8ba24f..4438e4fce4 100644 --- a/modules/ticket/front/sms/locale/es.yml +++ b/modules/ticket/front/sms/locale/es.yml @@ -2,4 +2,6 @@ Send SMS: Enviar SMS Destination: Destinatario Message: Mensaje SMS sent!: ¡SMS enviado! -Characters remaining: Carácteres restantes \ No newline at end of file +Characters remaining: Carácteres restantes +The destination can't be empty: El destinatario no puede estar vacio +The message can't be empty: El mensaje no puede estar vacio \ No newline at end of file From d26597c395837415f2023a54b8000fc0925bbe00 Mon Sep 17 00:00:00 2001 From: Bernat Exposito Domenech Date: Mon, 10 Feb 2020 09:36:40 +0100 Subject: [PATCH 3/3] fix ticket.sale sms --- modules/ticket/front/sale/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/ticket/front/sale/index.html b/modules/ticket/front/sale/index.html index 998f481ead..42699d8d12 100644 --- a/modules/ticket/front/sale/index.html +++ b/modules/ticket/front/sale/index.html @@ -370,10 +370,10 @@ - - +