From cf7016c28afa0fa096ebacc52a35c5b1b6f1a8ee Mon Sep 17 00:00:00 2001 From: alexm Date: Wed, 14 Sep 2022 15:18:11 +0200 Subject: [PATCH 01/58] feat(login): recover-password section --- front/core/services/auth.js | 2 +- front/salix/components/index.js | 1 + front/salix/components/login/locale/es.yml | 3 ++- front/salix/components/login/login.html | 5 +++++ .../components/login/recover-password.html | 11 ++++++++++ .../components/login/recover-password.js | 22 +++++++++++++++++++ front/salix/components/login/style.scss | 4 ++++ front/salix/routes.js | 7 ++++++ 8 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 front/salix/components/login/recover-password.html create mode 100644 front/salix/components/login/recover-password.js diff --git a/front/core/services/auth.js b/front/core/services/auth.js index a1dcfa395..d14c0bafd 100644 --- a/front/core/services/auth.js +++ b/front/core/services/auth.js @@ -23,7 +23,7 @@ export default class Auth { initialize() { let criteria = { - to: state => state.name != 'login' + to: state => !state.name.includes('login') }; this.$transitions.onStart(criteria, transition => { if (this.loggedIn) diff --git a/front/salix/components/index.js b/front/salix/components/index.js index ce4ad585a..e5e98acf4 100644 --- a/front/salix/components/index.js +++ b/front/salix/components/index.js @@ -6,6 +6,7 @@ import './home/home'; import './layout'; import './left-menu/left-menu'; import './login/login'; +import './login/recover-password'; import './module-card'; import './module-main'; import './side-menu/side-menu'; diff --git a/front/salix/components/login/locale/es.yml b/front/salix/components/login/locale/es.yml index 9c9ba5905..c34861bfb 100644 --- a/front/salix/components/login/locale/es.yml +++ b/front/salix/components/login/locale/es.yml @@ -1,4 +1,5 @@ User: Usuario Password: Contraseña Do not close session: No cerrar sesión -Enter: Entrar \ No newline at end of file +Enter: Entrar +I do not remember my password: No recuerdo mi contraseña diff --git a/front/salix/components/login/login.html b/front/salix/components/login/login.html index b15714a23..00ad67553 100644 --- a/front/salix/components/login/login.html +++ b/front/salix/components/login/login.html @@ -22,6 +22,11 @@
+
+ + I do not remember my password + +
diff --git a/front/salix/components/login/recover-password.html b/front/salix/components/login/recover-password.html new file mode 100644 index 000000000..4633a098d --- /dev/null +++ b/front/salix/components/login/recover-password.html @@ -0,0 +1,11 @@ +
+ +
+ + +
+
diff --git a/front/salix/components/login/recover-password.js b/front/salix/components/login/recover-password.js new file mode 100644 index 000000000..7841329bb --- /dev/null +++ b/front/salix/components/login/recover-password.js @@ -0,0 +1,22 @@ +import ngModule from '../../module'; +import './style.scss'; + +/** + * A simple login form. + */ +export default class Controller { + constructor($, $element) { + Object.assign(this, { + $, + $element, + user: localStorage.getItem('lastUser'), + remember: true + }); + } +} +Controller.$inject = ['$scope', '$element']; + +ngModule.vnComponent('vnRecoverPassword', { + template: require('./recover-password.html'), + controller: Controller +}); diff --git a/front/salix/components/login/style.scss b/front/salix/components/login/style.scss index 8ebf2a68c..0568b7f5e 100644 --- a/front/salix/components/login/style.scss +++ b/front/salix/components/login/style.scss @@ -71,4 +71,8 @@ vn-login { box-shadow: none; } } + + a{ + color: $color-primary; + } } diff --git a/front/salix/routes.js b/front/salix/routes.js index 600907ff1..36e52688d 100644 --- a/front/salix/routes.js +++ b/front/salix/routes.js @@ -13,6 +13,13 @@ function config($stateProvider, $urlRouterProvider) { login: {template: ''} } }) + .state('login.recover-password', { + url: '/recover-password', + description: 'Recover-password', + views: { + recoverPassword: {template: ''} + } + }) .state('home', { url: '/', description: 'Home', From 310557427ae533d81d489a3a5cc309644eb10742 Mon Sep 17 00:00:00 2001 From: alexm Date: Thu, 15 Sep 2022 10:21:30 +0200 Subject: [PATCH 02/58] feat(recover-password): create section and route --- front/salix/components/app/app.html | 6 +++++- front/salix/components/app/app.js | 7 ++++++- front/salix/components/login/locale/es.yml | 3 +++ .../components/login/recover-password.html | 18 ++++++++++++++---- front/salix/components/login/style.scss | 13 ++++++++++++- front/salix/routes.js | 8 +++----- 6 files changed, 43 insertions(+), 12 deletions(-) diff --git a/front/salix/components/app/app.html b/front/salix/components/app/app.html index d32c9f68b..87728d630 100644 --- a/front/salix/components/app/app.html +++ b/front/salix/components/app/app.html @@ -3,7 +3,11 @@ + ng-if="!$ctrl.showLayout && !$ctrl.isRecover"> + + diff --git a/front/salix/components/app/app.js b/front/salix/components/app/app.js index 1f8cdb46e..3990aac13 100644 --- a/front/salix/components/app/app.js +++ b/front/salix/components/app/app.js @@ -15,7 +15,12 @@ export default class App extends Component { get showLayout() { let state = this.$state.current.name; - return state && state != 'login'; + return state && !state.includes('login'); + } + + get isRecover() { + let state = this.$state.current.name; + return state == 'login.recover-password'; } $onDestroy() { diff --git a/front/salix/components/login/locale/es.yml b/front/salix/components/login/locale/es.yml index c34861bfb..24ad53a08 100644 --- a/front/salix/components/login/locale/es.yml +++ b/front/salix/components/login/locale/es.yml @@ -1,5 +1,8 @@ User: Usuario Password: Contraseña +Email: Correo electrónico Do not close session: No cerrar sesión Enter: Entrar I do not remember my password: No recuerdo mi contraseña +Recover password: Recuperar contraseña +We will sent you an email to recover your password: Te enviaremos un correo para restablecer tu contraseña diff --git a/front/salix/components/login/recover-password.html b/front/salix/components/login/recover-password.html index 4633a098d..9461970c1 100644 --- a/front/salix/components/login/recover-password.html +++ b/front/salix/components/login/recover-password.html @@ -1,11 +1,21 @@
-
+
Recover password
+
+ We will sent you an email to recover your password +
+
diff --git a/front/salix/components/login/style.scss b/front/salix/components/login/style.scss index 0568b7f5e..ba48c8781 100644 --- a/front/salix/components/login/style.scss +++ b/front/salix/components/login/style.scss @@ -1,6 +1,7 @@ @import "variables"; -vn-login { +vn-login, +vn-recover-password{ position: absolute; height: 100%; width: 100%; @@ -61,6 +62,16 @@ vn-login { } } } + + h5{ + color: $color-primary; + } + + .text-secondary{ + text-align: center; + padding-bottom: 16px; + } + } @media screen and (max-width: 600px) { diff --git a/front/salix/routes.js b/front/salix/routes.js index 36e52688d..c015fbfbc 100644 --- a/front/salix/routes.js +++ b/front/salix/routes.js @@ -10,15 +10,13 @@ function config($stateProvider, $urlRouterProvider) { url: '/login?continue', description: 'Login', views: { - login: {template: ''} + 'login': {template: ''}, + 'recover-password': {template: ''} } }) .state('login.recover-password', { url: '/recover-password', - description: 'Recover-password', - views: { - recoverPassword: {template: ''} - } + description: 'Recover-password' }) .state('home', { url: '/', From 918863ee8e1e672fa952440472627ddcf6e83f97 Mon Sep 17 00:00:00 2001 From: alexm Date: Tue, 20 Sep 2022 15:21:01 +0200 Subject: [PATCH 03/58] feat(account): recover-password --- back/methods/account/recover-password.js | 40 +++++++++++++++++++ back/models/account.js | 3 +- .../00-acl_recover-password.sql | 3 ++ front/core/services/auth.js | 4 +- .../components/login/recover-password.js | 16 ++++++-- loopback/locale/es.json | 3 +- 6 files changed, 60 insertions(+), 9 deletions(-) create mode 100644 back/methods/account/recover-password.js create mode 100644 db/changes/10500-motherOfGod/00-acl_recover-password.sql diff --git a/back/methods/account/recover-password.js b/back/methods/account/recover-password.js new file mode 100644 index 000000000..df3faab6b --- /dev/null +++ b/back/methods/account/recover-password.js @@ -0,0 +1,40 @@ +const UserError = require('vn-loopback/util/user-error'); + +module.exports = Self => { + Self.remoteMethod('recoverPassword', { + description: 'Send email to the user', + accepts: [ + { + arg: 'email', + type: 'string', + description: 'The email of user', + required: false + } + ], + http: { + path: `/recoverPassword`, + verb: 'GET' + } + }); + + Self.recoverPassword = async function(email) { + console.log('ENTRY'); + const models = Self.app.models; + const user = await models.User.findOne({ + where: { + email: email + } + }); + + if (!user) + throw new UserError(`This email does not belong to a user`); + + const token = await models.Account.login({ + user: email, + password: user.password + }); + + await Self.rawSql(`CALL vn.mail_insert(?,?,?,?)`, + [email, null, 'Recovery Password', `?token=${token}`]); + }; +}; diff --git a/back/models/account.js b/back/models/account.js index ba703c68d..5ace3b858 100644 --- a/back/models/account.js +++ b/back/models/account.js @@ -6,6 +6,7 @@ module.exports = Self => { require('../methods/account/acl')(Self); require('../methods/account/change-password')(Self); require('../methods/account/set-password')(Self); + require('../methods/account/recover-password')(Self); require('../methods/account/validate-token')(Self); // Validations @@ -77,7 +78,7 @@ module.exports = Self => { `SELECT r.name FROM account.user u JOIN account.roleRole rr ON rr.role = u.role - JOIN account.role r ON r.id = rr.inheritsFrom + JOIN account.role r ON r.id = rr.inheritsFrom WHERE u.id = ?`, [userId], options); let roles = []; diff --git a/db/changes/10500-motherOfGod/00-acl_recover-password.sql b/db/changes/10500-motherOfGod/00-acl_recover-password.sql new file mode 100644 index 000000000..65e7b7cf3 --- /dev/null +++ b/db/changes/10500-motherOfGod/00-acl_recover-password.sql @@ -0,0 +1,3 @@ +INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) + VALUES + ('Account', 'recoverPassword', 'READ', 'ALLOW', 'ROLE', 'account'); diff --git a/front/core/services/auth.js b/front/core/services/auth.js index d14c0bafd..57e8226f8 100644 --- a/front/core/services/auth.js +++ b/front/core/services/auth.js @@ -30,9 +30,7 @@ export default class Auth { return true; let redirectToLogin = () => { - return transition.router.stateService.target('login', { - continue: this.$window.location.hash - }); + return transition.router.stateService.target('login'); }; if (this.vnToken.token) { diff --git a/front/salix/components/login/recover-password.js b/front/salix/components/login/recover-password.js index 7841329bb..c02fa4619 100644 --- a/front/salix/components/login/recover-password.js +++ b/front/salix/components/login/recover-password.js @@ -5,16 +5,24 @@ import './style.scss'; * A simple login form. */ export default class Controller { - constructor($, $element) { + constructor($, $element, $http) { Object.assign(this, { $, $element, - user: localStorage.getItem('lastUser'), - remember: true + $http }); } + + submit() { + const params = { + email: this.email + }; + + this.$http.get('Accounts/recoverPassword', params) + .then(() => console.log('try')); // this.vnApp.showMessage(this.$t('Notification sent!'))); + } } -Controller.$inject = ['$scope', '$element']; +Controller.$inject = ['$scope', '$element', '$http']; ngModule.vnComponent('vnRecoverPassword', { template: require('./recover-password.html'), diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 07a00024a..5ff630a41 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -232,5 +232,6 @@ "Fichadas impares": "Fichadas impares", "Descanso diario 12h.": "Descanso diario 12h.", "Descanso semanal 36h. / 72h.": "Descanso semanal 36h. / 72h.", - "Dirección incorrecta": "Dirección incorrecta" + "Dirección incorrecta": "Dirección incorrecta", + "This email does not belong to a user": "This email does not belong to a user" } \ No newline at end of file From 00f5689825678bff42cb440dd589eea0a7954316 Mon Sep 17 00:00:00 2001 From: alexm Date: Wed, 21 Sep 2022 15:15:19 +0200 Subject: [PATCH 04/58] feat(account): recover-password --- back/methods/account/recover-password.js | 25 +++++++++++-------- back/models/account.json | 15 ++++++++--- front/core/services/auth.js | 17 ++++++++----- front/core/services/interceptor.js | 2 +- front/salix/components/login/locale/es.yml | 1 + .../components/login/recover-password.js | 18 ++++++++----- front/salix/module.js | 4 +-- 7 files changed, 52 insertions(+), 30 deletions(-) diff --git a/back/methods/account/recover-password.js b/back/methods/account/recover-password.js index df3faab6b..76c3401df 100644 --- a/back/methods/account/recover-password.js +++ b/back/methods/account/recover-password.js @@ -1,26 +1,29 @@ const UserError = require('vn-loopback/util/user-error'); module.exports = Self => { - Self.remoteMethod('recoverPassword', { + Self.remoteMethodCtx('recoverPassword', { description: 'Send email to the user', accepts: [ { arg: 'email', type: 'string', description: 'The email of user', - required: false + required: true } ], http: { path: `/recoverPassword`, - verb: 'GET' + verb: 'POST' } }); - Self.recoverPassword = async function(email) { - console.log('ENTRY'); + Self.recoverPassword = async function(ctx, email) { const models = Self.app.models; - const user = await models.User.findOne({ + const origin = ctx.req.headers.origin; + const ttl = 1209600; + + const user = await models.Account.findOne({ + fields: ['id', 'name', 'password'], where: { email: email } @@ -29,12 +32,12 @@ module.exports = Self => { if (!user) throw new UserError(`This email does not belong to a user`); - const token = await models.Account.login({ - user: email, - password: user.password + const token = await models.AccessToken.create({ + ttl: ttl, + userId: user.id }); - await Self.rawSql(`CALL vn.mail_insert(?,?,?,?)`, - [email, null, 'Recovery Password', `?token=${token}`]); + return await Self.rawSql(`CALL vn.mail_insert(?,?,?,?)`, + [email, null, 'Recovery Password', `${origin}/#!/account/${user.id}/basic-data?access_token=${token.id}`]); }; }; diff --git a/back/models/account.json b/back/models/account.json index 5f0b05f9b..b07c982f8 100644 --- a/back/models/account.json +++ b/back/models/account.json @@ -85,20 +85,27 @@ "principalType": "ROLE", "principalId": "$everyone", "permission": "ALLOW" - }, + }, + { + "property": "recoverPassword", + "accessType": "EXECUTE", + "principalType": "ROLE", + "principalId": "$everyone", + "permission": "ALLOW" + }, { - "property": "logout", + "property": "logout", "accessType": "EXECUTE", "principalType": "ROLE", "principalId": "$authenticated", "permission": "ALLOW" }, { - "property": "validateToken", + "property": "validateToken", "accessType": "EXECUTE", "principalType": "ROLE", "principalId": "$authenticated", "permission": "ALLOW" - } + } ] } diff --git a/front/core/services/auth.js b/front/core/services/auth.js index 57e8226f8..28ac7e624 100644 --- a/front/core/services/auth.js +++ b/front/core/services/auth.js @@ -7,7 +7,7 @@ import UserError from 'core/lib/user-error'; * @property {Boolean} loggedIn Whether the user is currently logged */ export default class Auth { - constructor($http, $q, $state, $transitions, $window, vnToken, vnModules, aclService) { + constructor($http, $q, $state, $transitions, $window, vnToken, vnModules, aclService, $location) { Object.assign(this, { $http, $q, @@ -17,7 +17,8 @@ export default class Auth { vnToken, vnModules, aclService, - loggedIn: false + loggedIn: false, + $location }); } @@ -25,15 +26,18 @@ export default class Auth { let criteria = { to: state => !state.name.includes('login') }; + + this.vnToken.set(this.$location.$$search.access_token, false); + console.log(this.$location.$$search.access_token, false); this.$transitions.onStart(criteria, transition => { if (this.loggedIn) return true; let redirectToLogin = () => { - return transition.router.stateService.target('login'); + // return transition.router.stateService.target('login'); }; - if (this.vnToken.token) { + if (this.vnToken.token || this) { return this.loadAcls() .then(() => true) .catch(redirectToLogin); @@ -59,6 +63,7 @@ export default class Auth { } onLoginOk(json, remember) { + console.log(json.data.token); this.vnToken.set(json.data.token, remember); return this.loadAcls().then(() => { @@ -79,7 +84,7 @@ export default class Auth { this.loggedIn = false; this.vnModules.reset(); this.aclService.reset(); - this.$state.go('login'); + // this.$state.go('login'); return promise; } @@ -96,6 +101,6 @@ export default class Auth { }); } } -Auth.$inject = ['$http', '$q', '$state', '$transitions', '$window', 'vnToken', 'vnModules', 'aclService']; +Auth.$inject = ['$http', '$q', '$state', '$transitions', '$window', 'vnToken', 'vnModules', 'aclService', '$location']; ngModule.service('vnAuth', Auth); diff --git a/front/core/services/interceptor.js b/front/core/services/interceptor.js index 3f3d9912b..a071018bf 100644 --- a/front/core/services/interceptor.js +++ b/front/core/services/interceptor.js @@ -11,7 +11,7 @@ function interceptor($q, vnApp, vnToken, $translate) { }, request(config) { vnApp.pushLoader(); - + console.log(vnToken.token); if (config.url.charAt(0) !== '/' && apiPath) config.url = `${apiPath}${config.url}`; if (vnToken.token) diff --git a/front/salix/components/login/locale/es.yml b/front/salix/components/login/locale/es.yml index 24ad53a08..afb538513 100644 --- a/front/salix/components/login/locale/es.yml +++ b/front/salix/components/login/locale/es.yml @@ -6,3 +6,4 @@ Enter: Entrar I do not remember my password: No recuerdo mi contraseña Recover password: Recuperar contraseña We will sent you an email to recover your password: Te enviaremos un correo para restablecer tu contraseña +Notification sent!: ¡Notificación enviada! diff --git a/front/salix/components/login/recover-password.js b/front/salix/components/login/recover-password.js index c02fa4619..f09208b9b 100644 --- a/front/salix/components/login/recover-password.js +++ b/front/salix/components/login/recover-password.js @@ -5,11 +5,14 @@ import './style.scss'; * A simple login form. */ export default class Controller { - constructor($, $element, $http) { + constructor($scope, $element, $http, vnApp, $translate, $state) { Object.assign(this, { - $, + $scope, $element, - $http + $http, + vnApp, + $translate, + $state }); } @@ -18,11 +21,14 @@ export default class Controller { email: this.email }; - this.$http.get('Accounts/recoverPassword', params) - .then(() => console.log('try')); // this.vnApp.showMessage(this.$t('Notification sent!'))); + this.$http.post('Accounts/recoverPassword', params) + .then(() => { + this.vnApp.showSuccess(this.$translate.instant('Notification sent!')); + this.$state.go('login'); + }); } } -Controller.$inject = ['$scope', '$element', '$http']; +Controller.$inject = ['$scope', '$element', '$http', 'vnApp', '$translate', '$state']; ngModule.vnComponent('vnRecoverPassword', { template: require('./recover-password.html'), diff --git a/front/salix/module.js b/front/salix/module.js index a8de61ae0..4aec5e061 100644 --- a/front/salix/module.js +++ b/front/salix/module.js @@ -112,10 +112,10 @@ function $exceptionHandler(vnApp, $window, $state, $injector) { switch (exception.status) { case 401: - if ($state.current.name != 'login') { + if (!$state.current.name.includes('login')) { messageT = 'Session has expired'; let params = {continue: $window.location.hash}; - $state.go('login', params); + // $state.go('login', params); } else messageT = 'Invalid login'; break; From c79f884526cffa863f4e405193923cda588068bd Mon Sep 17 00:00:00 2001 From: alexm Date: Thu, 22 Sep 2022 09:22:24 +0200 Subject: [PATCH 05/58] feat(recover-password): open changePass in front and tests done --- back/methods/account/recover-password.js | 11 ++++-- .../account/specs/recover-password.spec.js | 36 +++++++++++++++++++ .../account/specs/set-password.spec.js | 2 +- front/core/services/auth.js | 10 +++--- front/core/services/interceptor.js | 1 - front/salix/module.js | 2 +- loopback/locale/es.json | 5 +-- modules/account/front/descriptor/index.js | 12 +++++++ .../account/front/descriptor/index.spec.js | 11 ++++++ 9 files changed, 78 insertions(+), 12 deletions(-) create mode 100644 back/methods/account/specs/recover-password.spec.js diff --git a/back/methods/account/recover-password.js b/back/methods/account/recover-password.js index 76c3401df..66f2fbcda 100644 --- a/back/methods/account/recover-password.js +++ b/back/methods/account/recover-password.js @@ -20,6 +20,7 @@ module.exports = Self => { Self.recoverPassword = async function(ctx, email) { const models = Self.app.models; const origin = ctx.req.headers.origin; + const $t = ctx.req.__; // $translate const ttl = 1209600; const user = await models.Account.findOne({ @@ -37,7 +38,13 @@ module.exports = Self => { userId: user.id }); - return await Self.rawSql(`CALL vn.mail_insert(?,?,?,?)`, - [email, null, 'Recovery Password', `${origin}/#!/account/${user.id}/basic-data?access_token=${token.id}`]); + await Self.rawSql(`CALL vn.mail_insert(?,?,?,?)`, [ + email, + null, + $t('Recovery password'), + `${origin}/#!/account/${user.id}/basic-data?access_token=${token.id}` + ]); + + return; }; }; diff --git a/back/methods/account/specs/recover-password.spec.js b/back/methods/account/specs/recover-password.spec.js new file mode 100644 index 000000000..2917b3e56 --- /dev/null +++ b/back/methods/account/specs/recover-password.spec.js @@ -0,0 +1,36 @@ +const models = require('vn-loopback/server/server').models; + +describe('account recoverPassword()', () => { + const ctx = { + req: { + headers: {origin: 'http://localhost:5000'} + } + }; + ctx.req.__ = value => { + return value; + }; + + it('should throw an error when email does not belong to a user', async() => { + let error; + try { + await models.Account.recoverPassword(ctx, 'thor@mydomain.com'); + } catch (e) { + error = e; + } + + expect(error.message).toEqual('This email does not belong to a user'); + }); + + it('should update password when it passes requirements', async() => { + const user = await models.Account.findById(1107); + await models.Account.recoverPassword(ctx, user.email); + + const [result] = await models.AccessToken.find({ + where: { + userId: user.id + } + }); + + expect(result).toBeDefined(); + }); +}); diff --git a/back/methods/account/specs/set-password.spec.js b/back/methods/account/specs/set-password.spec.js index c76fd52b8..fe71873de 100644 --- a/back/methods/account/specs/set-password.spec.js +++ b/back/methods/account/specs/set-password.spec.js @@ -1,6 +1,6 @@ const app = require('vn-loopback/server/server'); -describe('account changePassword()', () => { +describe('account setPassword()', () => { it('should throw an error when password does not meet requirements', async() => { let req = app.models.Account.setPassword(1, 'insecurePass'); diff --git a/front/core/services/auth.js b/front/core/services/auth.js index 28ac7e624..61f64b3d6 100644 --- a/front/core/services/auth.js +++ b/front/core/services/auth.js @@ -27,14 +27,15 @@ export default class Auth { to: state => !state.name.includes('login') }; - this.vnToken.set(this.$location.$$search.access_token, false); - console.log(this.$location.$$search.access_token, false); + if (this.$location.$$search.access_token) + this.vnToken.set(this.$location.$$search.access_token, false); + this.$transitions.onStart(criteria, transition => { if (this.loggedIn) return true; let redirectToLogin = () => { - // return transition.router.stateService.target('login'); + return transition.router.stateService.target('login'); }; if (this.vnToken.token || this) { @@ -63,7 +64,6 @@ export default class Auth { } onLoginOk(json, remember) { - console.log(json.data.token); this.vnToken.set(json.data.token, remember); return this.loadAcls().then(() => { @@ -84,7 +84,7 @@ export default class Auth { this.loggedIn = false; this.vnModules.reset(); this.aclService.reset(); - // this.$state.go('login'); + this.$state.go('login'); return promise; } diff --git a/front/core/services/interceptor.js b/front/core/services/interceptor.js index a071018bf..d3039e9b5 100644 --- a/front/core/services/interceptor.js +++ b/front/core/services/interceptor.js @@ -11,7 +11,6 @@ function interceptor($q, vnApp, vnToken, $translate) { }, request(config) { vnApp.pushLoader(); - console.log(vnToken.token); if (config.url.charAt(0) !== '/' && apiPath) config.url = `${apiPath}${config.url}`; if (vnToken.token) diff --git a/front/salix/module.js b/front/salix/module.js index 4aec5e061..01df01a67 100644 --- a/front/salix/module.js +++ b/front/salix/module.js @@ -115,7 +115,7 @@ function $exceptionHandler(vnApp, $window, $state, $injector) { if (!$state.current.name.includes('login')) { messageT = 'Session has expired'; let params = {continue: $window.location.hash}; - // $state.go('login', params); + $state.go('login', params); } else messageT = 'Invalid login'; break; diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 5ff630a41..c85757c1f 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -233,5 +233,6 @@ "Descanso diario 12h.": "Descanso diario 12h.", "Descanso semanal 36h. / 72h.": "Descanso semanal 36h. / 72h.", "Dirección incorrecta": "Dirección incorrecta", - "This email does not belong to a user": "This email does not belong to a user" -} \ No newline at end of file + "This email does not belong to a user": "Este correo electrónico no pertenece a un usuario.", + "Recovery password": "Recuperar contraseña" +} diff --git a/modules/account/front/descriptor/index.js b/modules/account/front/descriptor/index.js index 3f27b1f76..e61b8fa4e 100644 --- a/modules/account/front/descriptor/index.js +++ b/modules/account/front/descriptor/index.js @@ -3,6 +3,11 @@ import Descriptor from 'salix/components/descriptor'; import UserError from 'core/lib/user-error'; class Controller extends Descriptor { + constructor($element, $scope, $location) { + super($element, $scope); + this.$location = $location; + } + get user() { return this.entity; } @@ -24,6 +29,11 @@ class Controller extends Descriptor { .then(res => this.hasAccount = res.data.exists); } + $onInit() { + if (this.$location.$$search.access_token) + this.onChangePassClick(false); + } + onDelete() { return this.$http.delete(`Accounts/${this.id}`) .then(() => this.$state.go('account.index')) @@ -114,6 +124,8 @@ class Controller extends Descriptor { } } +Controller.$inject = ['$element', '$scope', '$location']; + ngModule.component('vnUserDescriptor', { template: require('./index.html'), controller: Controller, diff --git a/modules/account/front/descriptor/index.spec.js b/modules/account/front/descriptor/index.spec.js index 8ee67a304..6c1df8fc7 100644 --- a/modules/account/front/descriptor/index.spec.js +++ b/modules/account/front/descriptor/index.spec.js @@ -105,4 +105,15 @@ describe('component vnUserDescriptor', () => { expect(controller.emit).toHaveBeenCalledWith('change'); }); }); + + describe('onInit()', () => { + it('should open onChangePassClick popup', () => { + controller.$location = {$$search: {access_token: 'RANDOM_TOKEN'}}; + jest.spyOn(controller, 'onChangePassClick'); + + controller.$onInit(); + + expect(controller.onChangePassClick).toHaveBeenCalled(); + }); + }); }); From fc5460dc9e537a997df23f6f762e9245da3ee685 Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 26 Sep 2022 08:21:58 +0200 Subject: [PATCH 06/58] feat(account): send verifyEmail when change email and tests --- back/methods/account/recover-password.js | 14 ++++- back/models/account.js | 36 +++++++++++++ back/models/account.json | 3 ++ back/models/specs/account.spec.js | 52 +++++++++++++++++-- .../00-acl_recover-password.sql | 3 -- loopback/locale/en.json | 4 +- loopback/locale/es.json | 5 +- modules/account/front/basic-data/index.js | 12 +++++ modules/account/front/descriptor/index.js | 2 +- .../account/front/descriptor/index.spec.js | 2 +- modules/account/front/routes.json | 4 +- 11 files changed, 123 insertions(+), 14 deletions(-) delete mode 100644 db/changes/10500-motherOfGod/00-acl_recover-password.sql diff --git a/back/methods/account/recover-password.js b/back/methods/account/recover-password.js index 66f2fbcda..54ccc56bc 100644 --- a/back/methods/account/recover-password.js +++ b/back/methods/account/recover-password.js @@ -38,11 +38,21 @@ module.exports = Self => { userId: user.id }); + const title = $t('Recover password'); + const body = ` +

+ ${$t('Click on the following link to change your password')}: +

+ + + ${title} + `; + await Self.rawSql(`CALL vn.mail_insert(?,?,?,?)`, [ email, null, - $t('Recovery password'), - `${origin}/#!/account/${user.id}/basic-data?access_token=${token.id}` + title, + body ]); return; diff --git a/back/models/account.js b/back/models/account.js index 5ace3b858..506dc37ac 100644 --- a/back/models/account.js +++ b/back/models/account.js @@ -1,4 +1,6 @@ +/* eslint max-len: ["error", { "code": 150 }]*/ const md5 = require('md5'); +const LoopBackContext = require('loopback-context'); module.exports = Self => { require('../methods/account/login')(Self); @@ -27,6 +29,40 @@ module.exports = Self => { ctx.data.password = md5(ctx.data.password); }); + Self.observe('before save', async ctx => { + const models = Self.app.models; + const loopBackContext = LoopBackContext.getCurrentContext(); + const changes = ctx.data || ctx.instance; + if (ctx.isNewInstance || !changes.email) return; + + const userId = ctx.currentInstance.id; + const user = await models.Account.findById(userId); + if (user.email == changes.email) return; + + const httpCtx = {req: loopBackContext.active}; + const httpRequest = httpCtx.req.http.req; + const headers = httpRequest.headers; + const origin = headers.origin; + const $t = httpRequest.__; + + const title = $t('Verify email'); + const body = ` +

+ ${$t(`Click on the following link to verify this email. If you haven't requested this email, just ignore it`)}: +

+ + + ${title} + `; + + result = await Self.rawSql(`CALL vn.mail_insert(?,?,?,?)`, [ + changes.email, + null, + title, + body + ], ctx.options); + }); + Self.remoteMethod('getCurrentUserData', { description: 'Gets the current user data', accepts: [ diff --git a/back/models/account.json b/back/models/account.json index b07c982f8..b4c1ca4be 100644 --- a/back/models/account.json +++ b/back/models/account.json @@ -40,6 +40,9 @@ "email": { "type": "string" }, + "emailVerified": { + "type": "boolean" + }, "created": { "type": "date" }, diff --git a/back/models/specs/account.spec.js b/back/models/specs/account.spec.js index c52bc4378..7e4d877f1 100644 --- a/back/models/specs/account.spec.js +++ b/back/models/specs/account.spec.js @@ -1,15 +1,61 @@ -const app = require('vn-loopback/server/server'); +const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); describe('loopback model Account', () => { + const userId = 1105; + const activeCtx = { + accessToken: {userId: userId}, + http: { + req: { + headers: {origin: 'http://localhost'}, + [`__`]: value => { + return value; + } + } + } + }; + + beforeEach(() => { + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); + it('should return true if the user has the given role', async() => { - let result = await app.models.Account.hasRole(1, 'employee'); + let result = await models.Account.hasRole(1, 'employee'); expect(result).toBeTruthy(); }); it('should return false if the user doesnt have the given role', async() => { - let result = await app.models.Account.hasRole(1, 'administrator'); + let result = await models.Account.hasRole(1, 'administrator'); expect(result).toBeFalsy(); }); + + it('should send email when change email', async() => { + const tx = await models.Account.beginTransaction({}); + const newEmail = 'emailNotVerified@mydomain.com'; + + let lastEmail; + try { + const options = {transaction: tx}; + + const account = await models.Account.findById(userId, null, options); + await account.updateAttribute('email', newEmail, options); + + [lastEmail] = await models.Mail.find({ + where: { + receiver: newEmail + } + }, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + + expect(lastEmail.receiver).toEqual(newEmail); + }); }); diff --git a/db/changes/10500-motherOfGod/00-acl_recover-password.sql b/db/changes/10500-motherOfGod/00-acl_recover-password.sql deleted file mode 100644 index 65e7b7cf3..000000000 --- a/db/changes/10500-motherOfGod/00-acl_recover-password.sql +++ /dev/null @@ -1,3 +0,0 @@ -INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) - VALUES - ('Account', 'recoverPassword', 'READ', 'ALLOW', 'ROLE', 'account'); diff --git a/loopback/locale/en.json b/loopback/locale/en.json index ccf16cce0..23d999f5b 100644 --- a/loopback/locale/en.json +++ b/loopback/locale/en.json @@ -130,5 +130,7 @@ "Descanso diario 12h.": "Daily rest 12h.", "Fichadas impares": "Odd signs", "Descanso diario 9h.": "Daily rest 9h.", - "Descanso semanal 36h. / 72h.": "Weekly rest 36h. / 72h." + "Descanso semanal 36h. / 72h.": "Weekly rest 36h. / 72h.", + "Verify email": "Verify email", + "Click on the following link to verify this email. If you haven't requested this email, just ignore it": "Click on the following link to verify this email. If you haven't requested this email, just ignore it" } \ No newline at end of file diff --git a/loopback/locale/es.json b/loopback/locale/es.json index c85757c1f..79bb9a458 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -234,5 +234,8 @@ "Descanso semanal 36h. / 72h.": "Descanso semanal 36h. / 72h.", "Dirección incorrecta": "Dirección incorrecta", "This email does not belong to a user": "Este correo electrónico no pertenece a un usuario.", - "Recovery password": "Recuperar contraseña" + "Recover password": "Recuperar contraseña", + "Click on the following link to change your password.": "Pulsa en el siguiente link para cambiar tu contraseña.", + "Verify email": "Verificar correo", + "Click on the following link to verify this email. If you haven't requested this email, just ignore it": "Pulsa en el siguiente link para verificar este correo. Si no has pedido este correo, simplemente ignóralo." } diff --git a/modules/account/front/basic-data/index.js b/modules/account/front/basic-data/index.js index 342297e45..1d27477b7 100644 --- a/modules/account/front/basic-data/index.js +++ b/modules/account/front/basic-data/index.js @@ -2,6 +2,18 @@ import ngModule from '../module'; import Section from 'salix/components/section'; export default class Controller extends Section { + $onInit() { + if (this.$params.emailVerified) { + const params = { + emailVerified: true + }; + return this.$http.patch(`Accounts/${this.$params.id}`, params) + .then(() => { + this.vnApp.showSuccess(this.$t('Data saved!')); + }); + } + } + onSubmit() { this.$.watcher.submit() .then(() => this.card.reload()); diff --git a/modules/account/front/descriptor/index.js b/modules/account/front/descriptor/index.js index e61b8fa4e..ce4a60305 100644 --- a/modules/account/front/descriptor/index.js +++ b/modules/account/front/descriptor/index.js @@ -30,7 +30,7 @@ class Controller extends Descriptor { } $onInit() { - if (this.$location.$$search.access_token) + if (this.$params.access_token) this.onChangePassClick(false); } diff --git a/modules/account/front/descriptor/index.spec.js b/modules/account/front/descriptor/index.spec.js index 6c1df8fc7..d330f6287 100644 --- a/modules/account/front/descriptor/index.spec.js +++ b/modules/account/front/descriptor/index.spec.js @@ -108,7 +108,7 @@ describe('component vnUserDescriptor', () => { describe('onInit()', () => { it('should open onChangePassClick popup', () => { - controller.$location = {$$search: {access_token: 'RANDOM_TOKEN'}}; + controller.$params = {access_token: 'RANDOM_TOKEN'}; jest.spyOn(controller, 'onChangePassClick'); controller.$onInit(); diff --git a/modules/account/front/routes.json b/modules/account/front/routes.json index 66b26f427..c5a3d159b 100644 --- a/modules/account/front/routes.json +++ b/modules/account/front/routes.json @@ -73,7 +73,7 @@ } }, { - "url": "/basic-data", + "url": "/basic-data?access_token&emailVerified", "state": "account.card.basicData", "component": "vn-user-basic-data", "description": "Basic data", @@ -249,4 +249,4 @@ "acl": ["developer"] } ] -} \ No newline at end of file +} From d2cbaa565e15a22f879e5af8ac64af234d0dcad8 Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 26 Sep 2022 08:48:46 +0200 Subject: [PATCH 07/58] add translation --- front/core/services/auth.js | 6 ++++-- front/core/services/interceptor.js | 1 + loopback/locale/es.json | 6 ++++-- modules/account/front/basic-data/index.js | 2 +- modules/account/front/basic-data/locale/es.yml | 1 + 5 files changed, 11 insertions(+), 5 deletions(-) create mode 100644 modules/account/front/basic-data/locale/es.yml diff --git a/front/core/services/auth.js b/front/core/services/auth.js index 61f64b3d6..5b3e445c3 100644 --- a/front/core/services/auth.js +++ b/front/core/services/auth.js @@ -35,10 +35,12 @@ export default class Auth { return true; let redirectToLogin = () => { - return transition.router.stateService.target('login'); + return transition.router.stateService.target('login', { + continue: this.$window.location.hash + }); }; - if (this.vnToken.token || this) { + if (this.vnToken.token) { return this.loadAcls() .then(() => true) .catch(redirectToLogin); diff --git a/front/core/services/interceptor.js b/front/core/services/interceptor.js index d3039e9b5..3f3d9912b 100644 --- a/front/core/services/interceptor.js +++ b/front/core/services/interceptor.js @@ -11,6 +11,7 @@ function interceptor($q, vnApp, vnToken, $translate) { }, request(config) { vnApp.pushLoader(); + if (config.url.charAt(0) !== '/' && apiPath) config.url = `${apiPath}${config.url}`; if (vnToken.token) diff --git a/loopback/locale/es.json b/loopback/locale/es.json index ec60c89c0..36403a1ed 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -237,5 +237,7 @@ "Recover password": "Recuperar contraseña", "Click on the following link to change your password.": "Pulsa en el siguiente link para cambiar tu contraseña.", "Verify email": "Verificar correo", - "Click on the following link to verify this email. If you haven't requested this email, just ignore it": "Pulsa en el siguiente link para verificar este correo. Si no has pedido este correo, simplemente ignóralo." -} + "Click on the following link to verify this email. If you haven't requested this email, just ignore it": "Pulsa en el siguiente link para verificar este correo. Si no has pedido este correo, simplemente ignóralo.", + "Click on the following link to change your password": "Click on the following link to change your password", + "Landing cannot be lesser than shipment": "Landing cannot be lesser than shipment" +} \ No newline at end of file diff --git a/modules/account/front/basic-data/index.js b/modules/account/front/basic-data/index.js index 1d27477b7..915357138 100644 --- a/modules/account/front/basic-data/index.js +++ b/modules/account/front/basic-data/index.js @@ -9,7 +9,7 @@ export default class Controller extends Section { }; return this.$http.patch(`Accounts/${this.$params.id}`, params) .then(() => { - this.vnApp.showSuccess(this.$t('Data saved!')); + this.vnApp.showSuccess(this.$t('Email verified successfully!')); }); } } diff --git a/modules/account/front/basic-data/locale/es.yml b/modules/account/front/basic-data/locale/es.yml new file mode 100644 index 000000000..2ca7bf698 --- /dev/null +++ b/modules/account/front/basic-data/locale/es.yml @@ -0,0 +1 @@ +Email verified successfully!: Correo verificado correctamente! From 63acbc50d5a435d996a0569c924c1b5c2a179b5d Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 26 Sep 2022 09:08:09 +0200 Subject: [PATCH 08/58] quit comment --- front/salix/components/login/recover-password.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/front/salix/components/login/recover-password.js b/front/salix/components/login/recover-password.js index f09208b9b..8b7b86ce3 100644 --- a/front/salix/components/login/recover-password.js +++ b/front/salix/components/login/recover-password.js @@ -1,9 +1,6 @@ import ngModule from '../../module'; import './style.scss'; -/** - * A simple login form. - */ export default class Controller { constructor($scope, $element, $http, vnApp, $translate, $state) { Object.assign(this, { From 81752e7f30f0f1c6ca0d2602bf0fd1302eeb343f Mon Sep 17 00:00:00 2001 From: alexm Date: Wed, 28 Sep 2022 12:20:29 +0200 Subject: [PATCH 09/58] quit userError --- back/methods/account/recover-password.js | 4 +-- .../account/specs/recover-password.spec.js | 11 -------- back/models/account.js | 27 ++++++++++++++----- front/salix/components/app/app.js | 2 +- loopback/locale/es.json | 3 +-- 5 files changed, 23 insertions(+), 24 deletions(-) diff --git a/back/methods/account/recover-password.js b/back/methods/account/recover-password.js index 54ccc56bc..b0923b61b 100644 --- a/back/methods/account/recover-password.js +++ b/back/methods/account/recover-password.js @@ -31,7 +31,7 @@ module.exports = Self => { }); if (!user) - throw new UserError(`This email does not belong to a user`); + return; const token = await models.AccessToken.create({ ttl: ttl, @@ -54,7 +54,5 @@ module.exports = Self => { title, body ]); - - return; }; }; diff --git a/back/methods/account/specs/recover-password.spec.js b/back/methods/account/specs/recover-password.spec.js index 2917b3e56..82d0d8e59 100644 --- a/back/methods/account/specs/recover-password.spec.js +++ b/back/methods/account/specs/recover-password.spec.js @@ -10,17 +10,6 @@ describe('account recoverPassword()', () => { return value; }; - it('should throw an error when email does not belong to a user', async() => { - let error; - try { - await models.Account.recoverPassword(ctx, 'thor@mydomain.com'); - } catch (e) { - error = e; - } - - expect(error.message).toEqual('This email does not belong to a user'); - }); - it('should update password when it passes requirements', async() => { const user = await models.Account.findById(1107); await models.Account.recoverPassword(ctx, user.email); diff --git a/back/models/account.js b/back/models/account.js index 506dc37ac..42618e322 100644 --- a/back/models/account.js +++ b/back/models/account.js @@ -1,5 +1,7 @@ /* eslint max-len: ["error", { "code": 150 }]*/ const md5 = require('md5'); +const app = require('../../loopback/server/server.js'); +const dataSources = require('../../loopback/server/datasources.json'); const LoopBackContext = require('loopback-context'); module.exports = Self => { @@ -29,7 +31,8 @@ module.exports = Self => { ctx.data.password = md5(ctx.data.password); }); - Self.observe('before save', async ctx => { + Self.observe('before save', async(ctx, instance) => { + console.log(instance); const models = Self.app.models; const loopBackContext = LoopBackContext.getCurrentContext(); const changes = ctx.data || ctx.instance; @@ -55,12 +58,22 @@ module.exports = Self => { ${title} `; - result = await Self.rawSql(`CALL vn.mail_insert(?,?,?,?)`, [ - changes.email, - null, - title, - body - ], ctx.options); + const url = app.get('rootUrl') || app.get('url'); + console.log(app.get('rootUrl')); + console.log(app.get('url')); + const options = { + type: 'email', + to: instance.email, + from: 'dataSources.email.settings.transports[0].auth.from', + subject: title, + template: body, + redirect: `${origin}#/login/${instance.email}?emailConfirmed`, + host: url.hostname, + port: url.port, + protocol: url.protocol.split(':')[0], + user: Self + }; + instance.verify(options); }); Self.remoteMethod('getCurrentUserData', { diff --git a/front/salix/components/app/app.js b/front/salix/components/app/app.js index 3990aac13..7af43d325 100644 --- a/front/salix/components/app/app.js +++ b/front/salix/components/app/app.js @@ -15,7 +15,7 @@ export default class App extends Component { get showLayout() { let state = this.$state.current.name; - return state && !state.includes('login'); + return state && state != 'login' && !this.isRecover; } get isRecover() { diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 36403a1ed..e2bb9bdf1 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -233,11 +233,10 @@ "Descanso diario 12h.": "Descanso diario 12h.", "Descanso semanal 36h. / 72h.": "Descanso semanal 36h. / 72h.", "Dirección incorrecta": "Dirección incorrecta", - "This email does not belong to a user": "Este correo electrónico no pertenece a un usuario.", "Recover password": "Recuperar contraseña", "Click on the following link to change your password.": "Pulsa en el siguiente link para cambiar tu contraseña.", "Verify email": "Verificar correo", "Click on the following link to verify this email. If you haven't requested this email, just ignore it": "Pulsa en el siguiente link para verificar este correo. Si no has pedido este correo, simplemente ignóralo.", "Click on the following link to change your password": "Click on the following link to change your password", "Landing cannot be lesser than shipment": "Landing cannot be lesser than shipment" -} \ No newline at end of file +} From ce2ad32ac951b38140c37223cdd97bf8ee9092af Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 10 Oct 2022 15:16:56 +0200 Subject: [PATCH 10/58] add email template --- back/methods/account/recover-password.js | 26 ++++------ loopback/locale/es.json | 2 - .../recover-password/assets/css/import.js | 13 +++++ .../recover-password/assets/css/style.css | 5 ++ .../email/recover-password/locale/es.yml | 3 ++ .../recover-password/recover-password.html | 48 +++++++++++++++++++ .../recover-password/recover-password.js | 17 +++++++ 7 files changed, 95 insertions(+), 19 deletions(-) create mode 100644 print/templates/email/recover-password/assets/css/import.js create mode 100644 print/templates/email/recover-password/assets/css/style.css create mode 100644 print/templates/email/recover-password/locale/es.yml create mode 100644 print/templates/email/recover-password/recover-password.html create mode 100755 print/templates/email/recover-password/recover-password.js diff --git a/back/methods/account/recover-password.js b/back/methods/account/recover-password.js index b0923b61b..ac89027c4 100644 --- a/back/methods/account/recover-password.js +++ b/back/methods/account/recover-password.js @@ -1,4 +1,4 @@ -const UserError = require('vn-loopback/util/user-error'); +const {Email} = require('vn-print'); module.exports = Self => { Self.remoteMethodCtx('recoverPassword', { @@ -20,7 +20,6 @@ module.exports = Self => { Self.recoverPassword = async function(ctx, email) { const models = Self.app.models; const origin = ctx.req.headers.origin; - const $t = ctx.req.__; // $translate const ttl = 1209600; const user = await models.Account.findOne({ @@ -38,21 +37,14 @@ module.exports = Self => { userId: user.id }); - const title = $t('Recover password'); - const body = ` -

- ${$t('Click on the following link to change your password')}: -

- - - ${title} - `; + const url = `${origin}/#!/account/${user.id}/basic-data?access_token=${token.id}`; + const params = { + recipient: 'alexm@verdnatura.es', + url: url + }; - await Self.rawSql(`CALL vn.mail_insert(?,?,?,?)`, [ - email, - null, - title, - body - ]); + const sendEmail = new Email('recover-password', params); + + return sendEmail.send(); }; }; diff --git a/loopback/locale/es.json b/loopback/locale/es.json index b6d806608..174f5921e 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -234,10 +234,8 @@ "Descanso semanal 36h. / 72h.": "Descanso semanal 36h. / 72h.", "Dirección incorrecta": "Dirección incorrecta", "Recover password": "Recuperar contraseña", - "Click on the following link to change your password.": "Pulsa en el siguiente link para cambiar tu contraseña.", "Verify email": "Verificar correo", "Click on the following link to verify this email. If you haven't requested this email, just ignore it": "Pulsa en el siguiente link para verificar este correo. Si no has pedido este correo, simplemente ignóralo.", - "Click on the following link to change your password": "Click on the following link to change your password", "Landing cannot be lesser than shipment": "Landing cannot be lesser than shipment", "Modifiable user details only by an administrator": "Detalles de usuario modificables solo por un administrador", "Modifiable password only via recovery or by an administrator": "Contraseña modificable solo a través de la recuperación o por un administrador", diff --git a/print/templates/email/recover-password/assets/css/import.js b/print/templates/email/recover-password/assets/css/import.js new file mode 100644 index 000000000..7360587f7 --- /dev/null +++ b/print/templates/email/recover-password/assets/css/import.js @@ -0,0 +1,13 @@ +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); + +module.exports = new Stylesheet([ + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/email.css`, + `${__dirname}/style.css`]) + .mergeStyles(); + diff --git a/print/templates/email/recover-password/assets/css/style.css b/print/templates/email/recover-password/assets/css/style.css new file mode 100644 index 000000000..5db85befa --- /dev/null +++ b/print/templates/email/recover-password/assets/css/style.css @@ -0,0 +1,5 @@ +.external-link { + border: 2px dashed #8dba25; + border-radius: 3px; + text-align: center +} \ No newline at end of file diff --git a/print/templates/email/recover-password/locale/es.yml b/print/templates/email/recover-password/locale/es.yml new file mode 100644 index 000000000..c72b108ee --- /dev/null +++ b/print/templates/email/recover-password/locale/es.yml @@ -0,0 +1,3 @@ +subject: Recuperar contraseña +title: Recuperar contraseña +Click on the following link to change your password.: Pulsa en el siguiente link para cambiar tu contraseña. diff --git a/print/templates/email/recover-password/recover-password.html b/print/templates/email/recover-password/recover-password.html new file mode 100644 index 000000000..a654b3d5f --- /dev/null +++ b/print/templates/email/recover-password/recover-password.html @@ -0,0 +1,48 @@ + + + + + + {{ $t('subject') }} + + + + + + + + +
+ +
+
+
+ +
+
+ +
+
+ +
+
+

+ {{ $t('Click on the following link to change your password.') }} + {{ $t('subject') }} +

+
+
+ + +
+
+ +
+
+ +
+
+
+
+ + diff --git a/print/templates/email/recover-password/recover-password.js b/print/templates/email/recover-password/recover-password.js new file mode 100755 index 000000000..b589411a9 --- /dev/null +++ b/print/templates/email/recover-password/recover-password.js @@ -0,0 +1,17 @@ +const Component = require(`vn-print/core/component`); +const emailHeader = new Component('email-header'); +const emailFooter = new Component('email-footer'); + +module.exports = { + name: 'recover-password', + components: { + 'email-header': emailHeader.build(), + 'email-footer': emailFooter.build() + }, + props: { + url: { + type: [String], + required: true + } + } +}; From 2e36164a98771f14a621290f3ee17afffa49ea0c Mon Sep 17 00:00:00 2001 From: alexm Date: Tue, 11 Oct 2022 10:06:25 +0200 Subject: [PATCH 11/58] fix(recover-password): use pint/Email --- back/methods/account/recover-password.js | 2 +- back/models/account.js | 26 +++++++--- .../email/email-verify/assets/css/import.js | 13 +++++ .../email/email-verify/assets/css/style.css | 5 ++ .../email/email-verify/email-verify.html | 48 +++++++++++++++++++ .../email/email-verify/email-verify.js | 17 +++++++ .../email/email-verify/locale/es.yml | 3 ++ 7 files changed, 106 insertions(+), 8 deletions(-) create mode 100644 print/templates/email/email-verify/assets/css/import.js create mode 100644 print/templates/email/email-verify/assets/css/style.css create mode 100644 print/templates/email/email-verify/email-verify.html create mode 100755 print/templates/email/email-verify/email-verify.js create mode 100644 print/templates/email/email-verify/locale/es.yml diff --git a/back/methods/account/recover-password.js b/back/methods/account/recover-password.js index ac89027c4..b48c76811 100644 --- a/back/methods/account/recover-password.js +++ b/back/methods/account/recover-password.js @@ -39,7 +39,7 @@ module.exports = Self => { const url = `${origin}/#!/account/${user.id}/basic-data?access_token=${token.id}`; const params = { - recipient: 'alexm@verdnatura.es', + recipient: email, url: url }; diff --git a/back/models/account.js b/back/models/account.js index e4e52f63b..5082b2351 100644 --- a/back/models/account.js +++ b/back/models/account.js @@ -1,8 +1,9 @@ /* eslint max-len: ["error", { "code": 150 }]*/ const md5 = require('md5'); const app = require('../../loopback/server/server.js'); -const dataSources = require('../../loopback/server/datasources.json'); +const dataSources = require('../../print/config/print.json'); const LoopBackContext = require('loopback-context'); +const {Email} = require('vn-print'); module.exports = Self => { require('../methods/account/login')(Self); @@ -62,19 +63,30 @@ module.exports = Self => { const url = app.get('rootUrl') || app.get('url'); console.log(app.get('rootUrl')); console.log(app.get('url')); + console.log(dataSources); const options = { type: 'email', - to: instance.email, - from: 'dataSources.email.settings.transports[0].auth.from', + to: 'alexm@verdnatura.es', + from: dataSources.app.senderEmail, subject: title, template: body, redirect: `${origin}#/login/${instance.email}?emailConfirmed`, - host: url.hostname, - port: url.port, - protocol: url.protocol.split(':')[0], + host: dataSources.smtp.host, + port: dataSources.smtp.port, + protocol: 'https', user: Self }; - instance.verify(options); + + const params = { + recipient: 'alexm@verdnatura.es', + url: `${origin}/#!/verified` + }; + + console.log(params); + const sendEmail = new Email('email-verify', params); + + // ctx.instance.verify(options); + sendEmail.send(); }); Self.remoteMethod('getCurrentUserData', { diff --git a/print/templates/email/email-verify/assets/css/import.js b/print/templates/email/email-verify/assets/css/import.js new file mode 100644 index 000000000..7360587f7 --- /dev/null +++ b/print/templates/email/email-verify/assets/css/import.js @@ -0,0 +1,13 @@ +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); + +module.exports = new Stylesheet([ + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/email.css`, + `${__dirname}/style.css`]) + .mergeStyles(); + diff --git a/print/templates/email/email-verify/assets/css/style.css b/print/templates/email/email-verify/assets/css/style.css new file mode 100644 index 000000000..5db85befa --- /dev/null +++ b/print/templates/email/email-verify/assets/css/style.css @@ -0,0 +1,5 @@ +.external-link { + border: 2px dashed #8dba25; + border-radius: 3px; + text-align: center +} \ No newline at end of file diff --git a/print/templates/email/email-verify/email-verify.html b/print/templates/email/email-verify/email-verify.html new file mode 100644 index 000000000..0eae8c57a --- /dev/null +++ b/print/templates/email/email-verify/email-verify.html @@ -0,0 +1,48 @@ + + + + + + {{ $t('subject') }} + + + + + + + + +
+ +
+
+
+ +
+
+ +
+
+ +
+
+

+ {{ $t(`Click on the following link to verify this email. If you haven't requested this email, just ignore it.`) }} + {{ $t('subject') }} +

+
+
+ + +
+
+ +
+
+ +
+
+
+
+ + diff --git a/print/templates/email/email-verify/email-verify.js b/print/templates/email/email-verify/email-verify.js new file mode 100755 index 000000000..b589411a9 --- /dev/null +++ b/print/templates/email/email-verify/email-verify.js @@ -0,0 +1,17 @@ +const Component = require(`vn-print/core/component`); +const emailHeader = new Component('email-header'); +const emailFooter = new Component('email-footer'); + +module.exports = { + name: 'recover-password', + components: { + 'email-header': emailHeader.build(), + 'email-footer': emailFooter.build() + }, + props: { + url: { + type: [String], + required: true + } + } +}; diff --git a/print/templates/email/email-verify/locale/es.yml b/print/templates/email/email-verify/locale/es.yml new file mode 100644 index 000000000..43f35f587 --- /dev/null +++ b/print/templates/email/email-verify/locale/es.yml @@ -0,0 +1,3 @@ +subject: Verificar correo +title: Verificar correo +Click on the following link to verify this email. If you haven't requested this email, just ignore it: Click on the following link to verify this email. If you haven't requested this email, just ignore it, From acc88c8239d34c5f468070ac02905b45e8854a85 Mon Sep 17 00:00:00 2001 From: alexm Date: Tue, 11 Oct 2022 14:56:33 +0200 Subject: [PATCH 12/58] use ejs template --- back/models/account.js | 67 ++++++++++++++++++++++++++++---- back/views/newVerify.ejs | 6 +++ back/views/verify.ejs | 3 ++ loopback/server/datasources.json | 19 ++++++++- 4 files changed, 85 insertions(+), 10 deletions(-) create mode 100644 back/views/newVerify.ejs create mode 100644 back/views/verify.ejs diff --git a/back/models/account.js b/back/models/account.js index 5082b2351..55c3ec8f6 100644 --- a/back/models/account.js +++ b/back/models/account.js @@ -1,7 +1,7 @@ /* eslint max-len: ["error", { "code": 150 }]*/ const md5 = require('md5'); const app = require('../../loopback/server/server.js'); -const dataSources = require('../../print/config/print.json'); +const dataSources = require('../../loopback/server/datasources.json'); const LoopBackContext = require('loopback-context'); const {Email} = require('vn-print'); @@ -33,10 +33,35 @@ module.exports = Self => { ctx.data.password = md5(ctx.data.password); }); - Self.observe('before save', async(ctx, instance) => { + Self.afterRemote('create', async(ctx, instance) => { console.log(instance); const models = Self.app.models; + const userId = ctx.instance.id; const loopBackContext = LoopBackContext.getCurrentContext(); + const httpCtx = {req: loopBackContext.active}; + const httpRequest = httpCtx.req.http.req; + const headers = httpRequest.headers; + const origin = headers.origin; + + const user = await models.User.findById(userId); + console.log(user); + + const options = { + type: 'email', + to: 'alexm@verdnatura.es', + from: dataSources.transports[0].host, + subject: 'Thanks for registering', + template: path.resolve(__dirname, '../../views/verify.ejs'), + redirect: `${origin}/!#/login/${instance.email}?emailConfirmed`, + host: 'verdnatura.es', + port: '1234', + protocol: 'https', + user: Self + }; + + await models.User.verify(options) + .then(res => console.log('> Verification email sent:', res)); + /* const changes = ctx.data || ctx.instance; if (ctx.isNewInstance || !changes.email) return; @@ -86,7 +111,33 @@ module.exports = Self => { const sendEmail = new Email('email-verify', params); // ctx.instance.verify(options); - sendEmail.send(); + sendEmail.send();*/ + }); + + Self.afterRemote('prototype.patchAttributes', async(ctx, instance) => { + console.log(instance); + const models = Self.app.models; + const userId = ctx.instance.id; + const loopBackContext = LoopBackContext.getCurrentContext(); + const httpCtx = {req: loopBackContext.active}; + const httpRequest = httpCtx.req.http.req; + const headers = httpRequest.headers; + const origin = headers.origin; + + const options = { + type: 'email', + to: 'alexm@verdnatura.es', + from: dataSources.email.transports[0].host, + subject: 'Thanks for registering', + template: '../views/verify.ejs', + redirect: `${origin}/!#/login/${instance.email}?emailConfirmed`, + host: 'verdnatura.es', + port: '1234', + protocol: 'https', + user: Self + }; + await models.user.verify(options) + .then(res => console.log('> Verification email sent:', res)); }); Self.remoteMethod('getCurrentUserData', { @@ -94,12 +145,12 @@ module.exports = Self => { accepts: [ { arg: 'ctx', - type: 'Object', + type: 'object', http: {source: 'context'} } ], returns: { - type: 'Object', + type: 'object', root: true }, http: { @@ -120,7 +171,7 @@ module.exports = Self => { * * @param {Integer} userId The user id * @param {String} name The role name - * @param {Object} options Options + * @param {object} options Options * @return {Boolean} %true if user has the role, %false otherwise */ Self.hasRole = async function(userId, name, options) { @@ -132,8 +183,8 @@ module.exports = Self => { * Get all user roles. * * @param {Integer} userId The user id - * @param {Object} options Options - * @return {Object} User role list + * @param {object} options Options + * @return {object} User role list */ Self.getRoles = async(userId, options) => { let result = await Self.rawSql( diff --git a/back/views/newVerify.ejs b/back/views/newVerify.ejs new file mode 100644 index 000000000..49f4e981a --- /dev/null +++ b/back/views/newVerify.ejs @@ -0,0 +1,6 @@ +

+ Thanks for registering, +

+

+ Click here to confirm your email address. +

diff --git a/back/views/verify.ejs b/back/views/verify.ejs new file mode 100644 index 000000000..90a434463 --- /dev/null +++ b/back/views/verify.ejs @@ -0,0 +1,3 @@ +

+ Click here to confirm your email address. +

diff --git a/loopback/server/datasources.json b/loopback/server/datasources.json index 5dade9c2e..2a410f0b5 100644 --- a/loopback/server/datasources.json +++ b/loopback/server/datasources.json @@ -108,5 +108,20 @@ "allowedContentTypes": [ "application/x-7z-compressed" ] - } -} \ No newline at end of file + }, + "email": { + "name": "email", + "connector": "mail", + "transports": [{ + "type": "smtp", + "host": "smtp.verdnatura.es", + "secure": true, + "port": 465, + "auth": { + "user": "nocontestar", + "pass": "", + "from": "nocontestar@verdnatura.es" + } + }] + } +} From e2407028844d01d7b7a4a1863f1e308e55915b35 Mon Sep 17 00:00:00 2001 From: alexm Date: Thu, 13 Oct 2022 14:55:34 +0200 Subject: [PATCH 13/58] use user --- back/models/account.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/back/models/account.js b/back/models/account.js index 55c3ec8f6..db66ca905 100644 --- a/back/models/account.js +++ b/back/models/account.js @@ -34,7 +34,7 @@ module.exports = Self => { }); Self.afterRemote('create', async(ctx, instance) => { - console.log(instance); + /* console.log(instance); const models = Self.app.models; const userId = ctx.instance.id; const loopBackContext = LoopBackContext.getCurrentContext(); @@ -43,9 +43,6 @@ module.exports = Self => { const headers = httpRequest.headers; const origin = headers.origin; - const user = await models.User.findById(userId); - console.log(user); - const options = { type: 'email', to: 'alexm@verdnatura.es', @@ -58,8 +55,9 @@ module.exports = Self => { protocol: 'https', user: Self }; - - await models.User.verify(options) + console.log('userId', userId); + const user = await models.user.findById(userId); + user.verify(options) .then(res => console.log('> Verification email sent:', res)); /* const changes = ctx.data || ctx.instance; @@ -115,7 +113,6 @@ module.exports = Self => { }); Self.afterRemote('prototype.patchAttributes', async(ctx, instance) => { - console.log(instance); const models = Self.app.models; const userId = ctx.instance.id; const loopBackContext = LoopBackContext.getCurrentContext(); @@ -136,7 +133,9 @@ module.exports = Self => { protocol: 'https', user: Self }; - await models.user.verify(options) + console.log(userId); + const user = await models.user.findById(userId); + user.verify(options) .then(res => console.log('> Verification email sent:', res)); }); From 6bfd54fc71e365ebdab17511873329424eaa7560 Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 17 Oct 2022 07:22:22 +0200 Subject: [PATCH 14/58] feat(verify): use user.verify --- back/model-config.json | 3 + back/models/account.js | 103 ++++++---------------- loopback/server/datasources.json | 9 +- modules/account/front/basic-data/index.js | 11 +-- modules/account/front/routes.json | 2 +- 5 files changed, 36 insertions(+), 92 deletions(-) diff --git a/back/model-config.json b/back/model-config.json index 830a78fd4..f7456ac4b 100644 --- a/back/model-config.json +++ b/back/model-config.json @@ -53,6 +53,9 @@ "EmailUser": { "dataSource": "vn" }, + "Email": { + "dataSource": "email" + }, "Image": { "dataSource": "vn" }, diff --git a/back/models/account.js b/back/models/account.js index db66ca905..c9b0941b6 100644 --- a/back/models/account.js +++ b/back/models/account.js @@ -3,7 +3,7 @@ const md5 = require('md5'); const app = require('../../loopback/server/server.js'); const dataSources = require('../../loopback/server/datasources.json'); const LoopBackContext = require('loopback-context'); -const {Email} = require('vn-print'); +const path = require('path'); module.exports = Self => { require('../methods/account/login')(Self); @@ -34,109 +34,58 @@ module.exports = Self => { }); Self.afterRemote('create', async(ctx, instance) => { - /* console.log(instance); const models = Self.app.models; - const userId = ctx.instance.id; + const loopBackContext = LoopBackContext.getCurrentContext(); const httpCtx = {req: loopBackContext.active}; const httpRequest = httpCtx.req.http.req; const headers = httpRequest.headers; const origin = headers.origin; + const userId = ctx.instance.id; const options = { type: 'email', - to: 'alexm@verdnatura.es', - from: dataSources.transports[0].host, - subject: 'Thanks for registering', - template: path.resolve(__dirname, '../../views/verify.ejs'), - redirect: `${origin}/!#/login/${instance.email}?emailConfirmed`, - host: 'verdnatura.es', - port: '1234', - protocol: 'https', + to: instance.email, + from: dataSources.email.transports[0].auth.from, + subject: 'hanks for registering', + template: path.resolve(__dirname, '../views/newVerify.ejs'), + redirect: `${origin}/#!/account/${instance.id}/basic-data?emailConfirmed`, + host: origin.split(':')[1].split('/')[2], + port: origin.split(':')[2], + protocol: origin.split(':')[0], user: Self }; - console.log('userId', userId); + const user = await models.user.findById(userId); - user.verify(options) - .then(res => console.log('> Verification email sent:', res)); - /* - const changes = ctx.data || ctx.instance; - if (ctx.isNewInstance || !changes.email) return; - - const userId = ctx.currentInstance.id; - const user = await models.Account.findById(userId); - if (user.email == changes.email) return; - - const httpCtx = {req: loopBackContext.active}; - const httpRequest = httpCtx.req.http.req; - const headers = httpRequest.headers; - const origin = headers.origin; - const $t = httpRequest.__; - - const title = $t('Verify email'); - const body = ` -

- ${$t(`Click on the following link to verify this email. If you haven't requested this email, just ignore it`)}: -

- - - ${title} - `; - - const url = app.get('rootUrl') || app.get('url'); - console.log(app.get('rootUrl')); - console.log(app.get('url')); - console.log(dataSources); - const options = { - type: 'email', - to: 'alexm@verdnatura.es', - from: dataSources.app.senderEmail, - subject: title, - template: body, - redirect: `${origin}#/login/${instance.email}?emailConfirmed`, - host: dataSources.smtp.host, - port: dataSources.smtp.port, - protocol: 'https', - user: Self - }; - - const params = { - recipient: 'alexm@verdnatura.es', - url: `${origin}/#!/verified` - }; - - console.log(params); - const sendEmail = new Email('email-verify', params); - - // ctx.instance.verify(options); - sendEmail.send();*/ + await user.verify(options); }); Self.afterRemote('prototype.patchAttributes', async(ctx, instance) => { + if (!ctx.args || !ctx.args.data.email) return; const models = Self.app.models; - const userId = ctx.instance.id; + const loopBackContext = LoopBackContext.getCurrentContext(); const httpCtx = {req: loopBackContext.active}; const httpRequest = httpCtx.req.http.req; const headers = httpRequest.headers; const origin = headers.origin; + const userId = ctx.instance.id; const options = { type: 'email', - to: 'alexm@verdnatura.es', - from: dataSources.email.transports[0].host, - subject: 'Thanks for registering', - template: '../views/verify.ejs', - redirect: `${origin}/!#/login/${instance.email}?emailConfirmed`, - host: 'verdnatura.es', - port: '1234', - protocol: 'https', + to: instance.email, + from: dataSources.email.transports[0].auth.from, + subject: 'Verify email', + template: path.resolve(__dirname, '../views/verify.ejs'), + redirect: `${origin}/#!/account/${instance.id}/basic-data?emailConfirmed`, + host: origin.split(':')[1].split('/')[2], + port: origin.split(':')[2], + protocol: origin.split(':')[0], user: Self }; - console.log(userId); + const user = await models.user.findById(userId); - user.verify(options) - .then(res => console.log('> Verification email sent:', res)); + await user.verify(options); }); Self.remoteMethod('getCurrentUserData', { diff --git a/loopback/server/datasources.json b/loopback/server/datasources.json index 2a410f0b5..12c8d05bd 100644 --- a/loopback/server/datasources.json +++ b/loopback/server/datasources.json @@ -114,14 +114,13 @@ "connector": "mail", "transports": [{ "type": "smtp", - "host": "smtp.verdnatura.es", + "host": "localhost", "secure": true, "port": 465, "auth": { - "user": "nocontestar", - "pass": "", - "from": "nocontestar@verdnatura.es" + "user": "", + "pass": "" } }] - } + } } diff --git a/modules/account/front/basic-data/index.js b/modules/account/front/basic-data/index.js index 915357138..77d3eab26 100644 --- a/modules/account/front/basic-data/index.js +++ b/modules/account/front/basic-data/index.js @@ -3,15 +3,8 @@ import Section from 'salix/components/section'; export default class Controller extends Section { $onInit() { - if (this.$params.emailVerified) { - const params = { - emailVerified: true - }; - return this.$http.patch(`Accounts/${this.$params.id}`, params) - .then(() => { - this.vnApp.showSuccess(this.$t('Email verified successfully!')); - }); - } + if (this.$params.emailConfirmed) + this.vnApp.showSuccess(this.$t('Email verified successfully!')); } onSubmit() { diff --git a/modules/account/front/routes.json b/modules/account/front/routes.json index e186d7586..c71e4e904 100644 --- a/modules/account/front/routes.json +++ b/modules/account/front/routes.json @@ -74,7 +74,7 @@ } }, { - "url": "/basic-data?access_token&emailVerified", + "url": "/basic-data?access_token&emailConfirmed", "state": "account.card.basicData", "component": "vn-user-basic-data", "description": "Basic data", From 41d2d14d390a7eede71d46f8d6f54d3d8e5f19ef Mon Sep 17 00:00:00 2001 From: alexm Date: Fri, 21 Oct 2022 13:46:53 +0200 Subject: [PATCH 15/58] try --- back/models/account.js | 39 +++++++++++++++++-- back/views/{newVerify.ejs => verifyES.ejs} | 3 -- .../email/email-verify/email-verify.js | 2 +- 3 files changed, 36 insertions(+), 8 deletions(-) rename back/views/{newVerify.ejs => verifyES.ejs} (69%) diff --git a/back/models/account.js b/back/models/account.js index c9b0941b6..480a84e77 100644 --- a/back/models/account.js +++ b/back/models/account.js @@ -4,6 +4,8 @@ const app = require('../../loopback/server/server.js'); const dataSources = require('../../loopback/server/datasources.json'); const LoopBackContext = require('loopback-context'); const path = require('path'); +// const {Email} = require('vn-print'); +// const qs = require('querystring'); module.exports = Self => { require('../methods/account/login')(Self); @@ -71,21 +73,50 @@ module.exports = Self => { const origin = headers.origin; const userId = ctx.instance.id; + const user = await models.user.findById(userId); + + /* //generate verification url + const generateVerificationToken = models.User.generateVerificationToken(user); + verifyOptions.verifyHref = + verifyOptions.protocol + + '://' + + verifyOptions.host + + displayPort + + urlPath + + '?' + qs.stringify({ + uid: '' + verifyOptions.user[pkName], + redirect: verifyOptions.redirect, + }); + verifyOptions.verifyHref += + verifyOptions.verifyHref.indexOf('?') === -1 ? '?' : '&'; + verifyOptions.verifyHref += 'token=' + user.verificationToken; + + verifyOptions.verificationToken = user.verificationToken; + verifyOptions.text = verifyOptions.text || g.f('Please verify your email by opening ' + + 'this link in a web browser:\n\t%s', verifyOptions.verifyHref); + verifyOptions.text = verifyOptions.text.replace(/\{href\}/g, verifyOptions.verifyHref); + const email = new Email('email-verify', { + recipient: instance.email, + lang: ctx.req.getLocale(), + url: + }); + await email.send(); +*/ const options = { type: 'email', to: instance.email, - from: dataSources.email.transports[0].auth.from, + from: 'test@test.es', // dataSources.email.transports[0].auth.from, subject: 'Verify email', - template: path.resolve(__dirname, '../views/verify.ejs'), + template: path.resolve(__dirname, '../views/verify.ejs'), // user.country.code = 'es' ? verifyES.ejs : verify.ejs redirect: `${origin}/#!/account/${instance.id}/basic-data?emailConfirmed`, host: origin.split(':')[1].split('/')[2], port: origin.split(':')[2], protocol: origin.split(':')[0], user: Self }; + console.log(options); - const user = await models.user.findById(userId); - await user.verify(options); + // await user.verify(options); }); Self.remoteMethod('getCurrentUserData', { diff --git a/back/views/newVerify.ejs b/back/views/verifyES.ejs similarity index 69% rename from back/views/newVerify.ejs rename to back/views/verifyES.ejs index 49f4e981a..90a434463 100644 --- a/back/views/newVerify.ejs +++ b/back/views/verifyES.ejs @@ -1,6 +1,3 @@ -

- Thanks for registering, -

Click here to confirm your email address.

diff --git a/print/templates/email/email-verify/email-verify.js b/print/templates/email/email-verify/email-verify.js index b589411a9..7f0b80a13 100755 --- a/print/templates/email/email-verify/email-verify.js +++ b/print/templates/email/email-verify/email-verify.js @@ -3,7 +3,7 @@ const emailHeader = new Component('email-header'); const emailFooter = new Component('email-footer'); module.exports = { - name: 'recover-password', + name: 'email-verify', components: { 'email-header': emailHeader.build(), 'email-footer': emailFooter.build() From cf24301bfe8dde02ae8a43efc2f71404b14b849e Mon Sep 17 00:00:00 2001 From: alexm Date: Wed, 26 Oct 2022 13:28:26 +0200 Subject: [PATCH 16/58] feat(account): email-verify refs #4077 --- back/model-config.json | 3 - back/models/account.js | 89 +++++-------------- back/models/specs/account.spec.js | 26 ------ loopback/locale/en.json | 3 +- loopback/locale/es.json | 3 +- loopback/server/datasources.json | 14 --- package.json | 2 +- .../email/email-verify/email-verify.html | 2 +- .../email/email-verify/locale/en.yml | 3 + .../email/email-verify/locale/es.yml | 2 +- 10 files changed, 33 insertions(+), 114 deletions(-) create mode 100644 print/templates/email/email-verify/locale/en.yml diff --git a/back/model-config.json b/back/model-config.json index f7456ac4b..830a78fd4 100644 --- a/back/model-config.json +++ b/back/model-config.json @@ -53,9 +53,6 @@ "EmailUser": { "dataSource": "vn" }, - "Email": { - "dataSource": "email" - }, "Image": { "dataSource": "vn" }, diff --git a/back/models/account.js b/back/models/account.js index 480a84e77..c2502380a 100644 --- a/back/models/account.js +++ b/back/models/account.js @@ -1,11 +1,7 @@ /* eslint max-len: ["error", { "code": 150 }]*/ const md5 = require('md5'); -const app = require('../../loopback/server/server.js'); -const dataSources = require('../../loopback/server/datasources.json'); const LoopBackContext = require('loopback-context'); -const path = require('path'); -// const {Email} = require('vn-print'); -// const qs = require('querystring'); +const {Email} = require('vn-print'); module.exports = Self => { require('../methods/account/login')(Self); @@ -35,33 +31,6 @@ module.exports = Self => { ctx.data.password = md5(ctx.data.password); }); - Self.afterRemote('create', async(ctx, instance) => { - const models = Self.app.models; - - const loopBackContext = LoopBackContext.getCurrentContext(); - const httpCtx = {req: loopBackContext.active}; - const httpRequest = httpCtx.req.http.req; - const headers = httpRequest.headers; - const origin = headers.origin; - - const userId = ctx.instance.id; - const options = { - type: 'email', - to: instance.email, - from: dataSources.email.transports[0].auth.from, - subject: 'hanks for registering', - template: path.resolve(__dirname, '../views/newVerify.ejs'), - redirect: `${origin}/#!/account/${instance.id}/basic-data?emailConfirmed`, - host: origin.split(':')[1].split('/')[2], - port: origin.split(':')[2], - protocol: origin.split(':')[0], - user: Self - }; - - const user = await models.user.findById(userId); - await user.verify(options); - }); - Self.afterRemote('prototype.patchAttributes', async(ctx, instance) => { if (!ctx.args || !ctx.args.data.email) return; const models = Self.app.models; @@ -71,52 +40,40 @@ module.exports = Self => { const httpRequest = httpCtx.req.http.req; const headers = httpRequest.headers; const origin = headers.origin; + const url = origin.split(':'); const userId = ctx.instance.id; const user = await models.user.findById(userId); - /* //generate verification url - const generateVerificationToken = models.User.generateVerificationToken(user); - verifyOptions.verifyHref = - verifyOptions.protocol + - '://' + - verifyOptions.host + - displayPort + - urlPath + - '?' + qs.stringify({ - uid: '' + verifyOptions.user[pkName], - redirect: verifyOptions.redirect, - }); - verifyOptions.verifyHref += - verifyOptions.verifyHref.indexOf('?') === -1 ? '?' : '&'; - verifyOptions.verifyHref += 'token=' + user.verificationToken; + class Mailer { + async send(verifyOptions, cb) { + const params = { + url: verifyOptions.verifyHref, + recipient: verifyOptions.to, + lang: ctx.req.getLocale() + }; + + const email = new Email('email-verify', params); + email.send(); + + cb(null, verifyOptions.to); + } + } - verifyOptions.verificationToken = user.verificationToken; - verifyOptions.text = verifyOptions.text || g.f('Please verify your email by opening ' + - 'this link in a web browser:\n\t%s', verifyOptions.verifyHref); - verifyOptions.text = verifyOptions.text.replace(/\{href\}/g, verifyOptions.verifyHref); - const email = new Email('email-verify', { - recipient: instance.email, - lang: ctx.req.getLocale(), - url: - }); - await email.send(); -*/ const options = { type: 'email', to: instance.email, - from: 'test@test.es', // dataSources.email.transports[0].auth.from, - subject: 'Verify email', - template: path.resolve(__dirname, '../views/verify.ejs'), // user.country.code = 'es' ? verifyES.ejs : verify.ejs + from: {}, redirect: `${origin}/#!/account/${instance.id}/basic-data?emailConfirmed`, - host: origin.split(':')[1].split('/')[2], - port: origin.split(':')[2], - protocol: origin.split(':')[0], + template: false, + mailer: new Mailer, + host: url[1].split('/')[2], + port: url[2], + protocol: url[0], user: Self }; - console.log(options); - // await user.verify(options); + await user.verify(options); }); Self.remoteMethod('getCurrentUserData', { diff --git a/back/models/specs/account.spec.js b/back/models/specs/account.spec.js index 7e4d877f1..81496a15f 100644 --- a/back/models/specs/account.spec.js +++ b/back/models/specs/account.spec.js @@ -32,30 +32,4 @@ describe('loopback model Account', () => { expect(result).toBeFalsy(); }); - - it('should send email when change email', async() => { - const tx = await models.Account.beginTransaction({}); - const newEmail = 'emailNotVerified@mydomain.com'; - - let lastEmail; - try { - const options = {transaction: tx}; - - const account = await models.Account.findById(userId, null, options); - await account.updateAttribute('email', newEmail, options); - - [lastEmail] = await models.Mail.find({ - where: { - receiver: newEmail - } - }, options); - - await tx.rollback(); - } catch (e) { - await tx.rollback(); - throw e; - } - - expect(lastEmail.receiver).toEqual(newEmail); - }); }); diff --git a/loopback/locale/en.json b/loopback/locale/en.json index 4d1f63130..c6351d5bd 100644 --- a/loopback/locale/en.json +++ b/loopback/locale/en.json @@ -135,5 +135,6 @@ "Click on the following link to verify this email. If you haven't requested this email, just ignore it": "Click on the following link to verify this email. If you haven't requested this email, just ignore it", "Password does not meet requirements": "Password does not meet requirements", "You don't have privileges to change the zone": "You don't have privileges to change the zone or for these parameters there are more than one shipping options, talk to agencies", - "Not enough privileges to edit a client": "Not enough privileges to edit a client" + "Not enough privileges to edit a client": "Not enough privileges to edit a client", + "Email verify": "Email verify" } diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 174f5921e..ad8e44bde 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -239,5 +239,6 @@ "Landing cannot be lesser than shipment": "Landing cannot be lesser than shipment", "Modifiable user details only by an administrator": "Detalles de usuario modificables solo por un administrador", "Modifiable password only via recovery or by an administrator": "Contraseña modificable solo a través de la recuperación o por un administrador", - "Not enough privileges to edit a client": "No tienes suficientes privilegios para editar un cliente" + "Not enough privileges to edit a client": "No tienes suficientes privilegios para editar un cliente", + "Email verify": "Correo de verificación" } diff --git a/loopback/server/datasources.json b/loopback/server/datasources.json index 3a7083318..00f6bf624 100644 --- a/loopback/server/datasources.json +++ b/loopback/server/datasources.json @@ -112,19 +112,5 @@ "allowedContentTypes": [ "application/x-7z-compressed" ] - }, - "email": { - "name": "email", - "connector": "mail", - "transports": [{ - "type": "smtp", - "host": "localhost", - "secure": true, - "port": 465, - "auth": { - "user": "", - "pass": "" - } - }] } } diff --git a/package.json b/package.json index 26c164832..abf7c9e4b 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "jsdom": "^16.7.0", "jszip": "^3.10.0", "ldapjs": "^2.2.0", - "loopback": "^3.26.0", + "loopback": "^3.28.0", "loopback-boot": "3.3.1", "loopback-component-explorer": "^6.5.0", "loopback-component-storage": "3.6.1", diff --git a/print/templates/email/email-verify/email-verify.html b/print/templates/email/email-verify/email-verify.html index 0eae8c57a..b8a6e263c 100644 --- a/print/templates/email/email-verify/email-verify.html +++ b/print/templates/email/email-verify/email-verify.html @@ -24,7 +24,7 @@

- {{ $t(`Click on the following link to verify this email. If you haven't requested this email, just ignore it.`) }} + {{ $t(`click`) }} {{ $t('subject') }}

diff --git a/print/templates/email/email-verify/locale/en.yml b/print/templates/email/email-verify/locale/en.yml new file mode 100644 index 000000000..0298f53b4 --- /dev/null +++ b/print/templates/email/email-verify/locale/en.yml @@ -0,0 +1,3 @@ +subject: Email Verify +title: Email Verify +click: Click on the following link to verify this email. If you haven't requested this email, just ignore it diff --git a/print/templates/email/email-verify/locale/es.yml b/print/templates/email/email-verify/locale/es.yml index 43f35f587..37bd6ef27 100644 --- a/print/templates/email/email-verify/locale/es.yml +++ b/print/templates/email/email-verify/locale/es.yml @@ -1,3 +1,3 @@ subject: Verificar correo title: Verificar correo -Click on the following link to verify this email. If you haven't requested this email, just ignore it: Click on the following link to verify this email. If you haven't requested this email, just ignore it, +click: Pulsa en el siguiente link para verificar este correo. Si no has pedido este correo, simplemente ignóralo From a9a20758bd9480a2f05450383da43078e7fa76e8 Mon Sep 17 00:00:00 2001 From: alexm Date: Wed, 26 Oct 2022 13:33:02 +0200 Subject: [PATCH 17/58] remove unnecesary --- back/models/specs/account.spec.js | 20 -------------------- back/views/verify.ejs | 3 --- back/views/verifyES.ejs | 3 --- 3 files changed, 26 deletions(-) delete mode 100644 back/views/verify.ejs delete mode 100644 back/views/verifyES.ejs diff --git a/back/models/specs/account.spec.js b/back/models/specs/account.spec.js index 81496a15f..f31c81b75 100644 --- a/back/models/specs/account.spec.js +++ b/back/models/specs/account.spec.js @@ -1,26 +1,6 @@ const models = require('vn-loopback/server/server').models; -const LoopBackContext = require('loopback-context'); describe('loopback model Account', () => { - const userId = 1105; - const activeCtx = { - accessToken: {userId: userId}, - http: { - req: { - headers: {origin: 'http://localhost'}, - [`__`]: value => { - return value; - } - } - } - }; - - beforeEach(() => { - spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ - active: activeCtx - }); - }); - it('should return true if the user has the given role', async() => { let result = await models.Account.hasRole(1, 'employee'); diff --git a/back/views/verify.ejs b/back/views/verify.ejs deleted file mode 100644 index 90a434463..000000000 --- a/back/views/verify.ejs +++ /dev/null @@ -1,3 +0,0 @@ -

- Click here to confirm your email address. -

diff --git a/back/views/verifyES.ejs b/back/views/verifyES.ejs deleted file mode 100644 index 90a434463..000000000 --- a/back/views/verifyES.ejs +++ /dev/null @@ -1,3 +0,0 @@ -

- Click here to confirm your email address. -

From 5c9bc47235ed12990fcfa7cfbbd36d9ed019d546 Mon Sep 17 00:00:00 2001 From: alexm Date: Thu, 3 Nov 2022 14:59:12 +0100 Subject: [PATCH 18/58] user model --- back/models/user.js | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 back/models/user.js diff --git a/back/models/user.js b/back/models/user.js new file mode 100644 index 000000000..0dd699884 --- /dev/null +++ b/back/models/user.js @@ -0,0 +1,26 @@ +const path = require('path'); + +module.exports = function(Self) { + function getUrl() { + return Self.app.get('rootUrl') || app.get('url'); + } + + function getFrom() { + return Self.dataSources.email.settings.transports[0].auth.from; + } + + Self.on('resetPasswordRequest', async function(info) { + const renderer = loopback.template(path.resolve(__dirname, '../../views/reset-password.ejs')); + const html = renderer({ + url: `${getUrl()}#/reset-password?access_token=${info.accessToken.id}` + }); + + await app.models.Email.send({ + to: info.email, + from: getFrom(), + subject: 'Password reset', + html + }); + console.log('> Sending password reset email to:', info.email); + }); +}; From fcf46ade7dbcd7c5268182f627821e121ab9dece Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 7 Nov 2022 15:15:00 +0100 Subject: [PATCH 19/58] feat: reset-password section --- back/models/user.js | 34 +++++------- front/core/services/auth.js | 11 ++-- front/salix/components/app/app.html | 6 ++- front/salix/components/app/app.js | 9 ++-- front/salix/components/index.js | 1 + .../components/login/recover-password.js | 2 +- .../components/login/reset-password.html | 23 ++++++++ .../salix/components/login/reset-password.js | 53 +++++++++++++++++++ front/salix/components/login/style.scss | 1 + front/salix/routes.js | 7 ++- 10 files changed, 113 insertions(+), 34 deletions(-) create mode 100644 front/salix/components/login/reset-password.html create mode 100644 front/salix/components/login/reset-password.js diff --git a/back/models/user.js b/back/models/user.js index 0dd699884..0bbd39055 100644 --- a/back/models/user.js +++ b/back/models/user.js @@ -1,26 +1,20 @@ -const path = require('path'); +const LoopBackContext = require('loopback-context'); +const {Email} = require('vn-print'); module.exports = function(Self) { - function getUrl() { - return Self.app.get('rootUrl') || app.get('url'); - } - - function getFrom() { - return Self.dataSources.email.settings.transports[0].auth.from; - } - Self.on('resetPasswordRequest', async function(info) { - const renderer = loopback.template(path.resolve(__dirname, '../../views/reset-password.ejs')); - const html = renderer({ - url: `${getUrl()}#/reset-password?access_token=${info.accessToken.id}` - }); + const loopBackContext = LoopBackContext.getCurrentContext(); + const httpCtx = {req: loopBackContext.active}; + const httpRequest = httpCtx.req.http.req; + const headers = httpRequest.headers; + const origin = headers.origin; - await app.models.Email.send({ - to: info.email, - from: getFrom(), - subject: 'Password reset', - html - }); - console.log('> Sending password reset email to:', info.email); + const params = { + url: `${origin}/#!/login/reset-password?access_token=${info.accessToken.id}` + }; + + const sendEmail = new Email('recover-password', params); + + return sendEmail.send(); }); }; diff --git a/front/core/services/auth.js b/front/core/services/auth.js index 5b3e445c3..d14c0bafd 100644 --- a/front/core/services/auth.js +++ b/front/core/services/auth.js @@ -7,7 +7,7 @@ import UserError from 'core/lib/user-error'; * @property {Boolean} loggedIn Whether the user is currently logged */ export default class Auth { - constructor($http, $q, $state, $transitions, $window, vnToken, vnModules, aclService, $location) { + constructor($http, $q, $state, $transitions, $window, vnToken, vnModules, aclService) { Object.assign(this, { $http, $q, @@ -17,8 +17,7 @@ export default class Auth { vnToken, vnModules, aclService, - loggedIn: false, - $location + loggedIn: false }); } @@ -26,10 +25,6 @@ export default class Auth { let criteria = { to: state => !state.name.includes('login') }; - - if (this.$location.$$search.access_token) - this.vnToken.set(this.$location.$$search.access_token, false); - this.$transitions.onStart(criteria, transition => { if (this.loggedIn) return true; @@ -103,6 +98,6 @@ export default class Auth { }); } } -Auth.$inject = ['$http', '$q', '$state', '$transitions', '$window', 'vnToken', 'vnModules', 'aclService', '$location']; +Auth.$inject = ['$http', '$q', '$state', '$transitions', '$window', 'vnToken', 'vnModules', 'aclService']; ngModule.service('vnAuth', Auth); diff --git a/front/salix/components/app/app.html b/front/salix/components/app/app.html index 87728d630..420a6895c 100644 --- a/front/salix/components/app/app.html +++ b/front/salix/components/app/app.html @@ -3,11 +3,15 @@ + ng-if="!$ctrl.showLayout && !$ctrl.isRecover && !$ctrl.isRecover2"> + + diff --git a/front/salix/components/app/app.js b/front/salix/components/app/app.js index 7af43d325..50aee2f9f 100644 --- a/front/salix/components/app/app.js +++ b/front/salix/components/app/app.js @@ -15,12 +15,15 @@ export default class App extends Component { get showLayout() { let state = this.$state.current.name; - return state && state != 'login' && !this.isRecover; + return state && state != 'login' && !this.isRecover && !this.isReset; } get isRecover() { - let state = this.$state.current.name; - return state == 'login.recover-password'; + return this.$state.current.name == 'login.recover-password'; + } + + get isReset() { + return this.$state.current.name == 'login.reset-password'; } $onDestroy() { diff --git a/front/salix/components/index.js b/front/salix/components/index.js index e5e98acf4..d99e4e9db 100644 --- a/front/salix/components/index.js +++ b/front/salix/components/index.js @@ -7,6 +7,7 @@ import './layout'; import './left-menu/left-menu'; import './login/login'; import './login/recover-password'; +import './login/reset-password'; import './module-card'; import './module-main'; import './side-menu/side-menu'; diff --git a/front/salix/components/login/recover-password.js b/front/salix/components/login/recover-password.js index 8b7b86ce3..5171c911d 100644 --- a/front/salix/components/login/recover-password.js +++ b/front/salix/components/login/recover-password.js @@ -18,7 +18,7 @@ export default class Controller { email: this.email }; - this.$http.post('Accounts/recoverPassword', params) + this.$http.post('users/reset', params) .then(() => { this.vnApp.showSuccess(this.$translate.instant('Notification sent!')); this.$state.go('login'); diff --git a/front/salix/components/login/reset-password.html b/front/salix/components/login/reset-password.html new file mode 100644 index 000000000..431af16fd --- /dev/null +++ b/front/salix/components/login/reset-password.html @@ -0,0 +1,23 @@ +
+
+
Reset password
+ + + + + +
+
diff --git a/front/salix/components/login/reset-password.js b/front/salix/components/login/reset-password.js new file mode 100644 index 000000000..455b98d93 --- /dev/null +++ b/front/salix/components/login/reset-password.js @@ -0,0 +1,53 @@ +import ngModule from '../../module'; +import './style.scss'; +const axios = require('axios'); + +export default class Controller { + constructor($scope, $element, $http, vnApp, $translate, $state, $location) { + Object.assign(this, { + $scope, + $element, + $http, + vnApp, + $translate, + $state, + $location + }); + } + + $onInit() { + const headers = { + Authorization: this.$location.$$search.access_token + }; + + axios.post('api/UserPasswords/findOne', null, {headers}) + .then(res => { + this.passRequirements = res.data; + }); + } + + submit() { + if (!this.newPassword) + throw new UserError(`You must enter a new password`); + if (this.newPassword != this.repeatPassword) + throw new UserError(`Passwords don't match`); + + const headers = { + Authorization: this.$location.$$search.access_token + }; + + const newPassword = this.newPassword; + + axios.post('api/users/reset-password', {newPassword}, {headers}) + .then(() => { + this.vnApp.showSuccess(this.$translate.instant('Password changed!')); + this.$state.go('login'); + }); + } +} +Controller.$inject = ['$scope', '$element', '$http', 'vnApp', '$translate', '$state', '$location']; + +ngModule.vnComponent('vnResetPassword', { + template: require('./reset-password.html'), + controller: Controller +}); diff --git a/front/salix/components/login/style.scss b/front/salix/components/login/style.scss index ba48c8781..a2f94f7fe 100644 --- a/front/salix/components/login/style.scss +++ b/front/salix/components/login/style.scss @@ -1,6 +1,7 @@ @import "variables"; vn-login, +vn-reset-password, vn-recover-password{ position: absolute; height: 100%; diff --git a/front/salix/routes.js b/front/salix/routes.js index c015fbfbc..7f8c77e14 100644 --- a/front/salix/routes.js +++ b/front/salix/routes.js @@ -11,13 +11,18 @@ function config($stateProvider, $urlRouterProvider) { description: 'Login', views: { 'login': {template: ''}, - 'recover-password': {template: ''} + 'recover-password': {template: ''}, + 'reset-password': {template: ''} } }) .state('login.recover-password', { url: '/recover-password', description: 'Recover-password' }) + .state('login.reset-password', { + url: '/reset-password', + description: 'Reset-password' + }) .state('home', { url: '/', description: 'Home', From 5339bc11432ed36dad58c5efe67218eb5e6219ac Mon Sep 17 00:00:00 2001 From: alexm Date: Wed, 9 Nov 2022 14:51:30 +0100 Subject: [PATCH 20/58] feat(recoverPassword): use loopback --- back/methods/account/recover-password.js | 35 ++---------- .../account/specs/recover-password.spec.js | 25 --------- back/models/specs/user.spec.js | 32 +++++++++++ back/models/user.js | 7 ++- e2e/helpers/selectors.js | 5 ++ e2e/paths/01-salix/04_recoverPassword.spec.js | 40 +++++++++++++ front/salix/components/app/app.html | 6 +- front/salix/components/app/app.js | 6 +- front/salix/components/login/locale/en.yml | 6 +- front/salix/components/login/locale/es.yml | 7 +++ .../components/login/recover-password.js | 10 +++- .../components/login/reset-password.html | 2 +- modules/account/front/descriptor/index.js | 12 ---- .../account/front/descriptor/index.spec.js | 11 ---- modules/account/front/routes.json | 2 +- print/core/smtp.js | 56 +++++++++++-------- 16 files changed, 149 insertions(+), 113 deletions(-) delete mode 100644 back/methods/account/specs/recover-password.spec.js create mode 100644 back/models/specs/user.spec.js create mode 100644 e2e/paths/01-salix/04_recoverPassword.spec.js diff --git a/back/methods/account/recover-password.js b/back/methods/account/recover-password.js index b48c76811..618b46946 100644 --- a/back/methods/account/recover-password.js +++ b/back/methods/account/recover-password.js @@ -1,7 +1,5 @@ -const {Email} = require('vn-print'); - module.exports = Self => { - Self.remoteMethodCtx('recoverPassword', { + Self.remoteMethod('recoverPassword', { description: 'Send email to the user', accepts: [ { @@ -17,34 +15,13 @@ module.exports = Self => { } }); - Self.recoverPassword = async function(ctx, email) { + Self.recoverPassword = async function(email) { const models = Self.app.models; - const origin = ctx.req.headers.origin; - const ttl = 1209600; - const user = await models.Account.findOne({ - fields: ['id', 'name', 'password'], - where: { - email: email - } - }); - - if (!user) + try { + await models.user.resetPassword({email}); + } catch (e) { return; - - const token = await models.AccessToken.create({ - ttl: ttl, - userId: user.id - }); - - const url = `${origin}/#!/account/${user.id}/basic-data?access_token=${token.id}`; - const params = { - recipient: email, - url: url - }; - - const sendEmail = new Email('recover-password', params); - - return sendEmail.send(); + } }; }; diff --git a/back/methods/account/specs/recover-password.spec.js b/back/methods/account/specs/recover-password.spec.js deleted file mode 100644 index 82d0d8e59..000000000 --- a/back/methods/account/specs/recover-password.spec.js +++ /dev/null @@ -1,25 +0,0 @@ -const models = require('vn-loopback/server/server').models; - -describe('account recoverPassword()', () => { - const ctx = { - req: { - headers: {origin: 'http://localhost:5000'} - } - }; - ctx.req.__ = value => { - return value; - }; - - it('should update password when it passes requirements', async() => { - const user = await models.Account.findById(1107); - await models.Account.recoverPassword(ctx, user.email); - - const [result] = await models.AccessToken.find({ - where: { - userId: user.id - } - }); - - expect(result).toBeDefined(); - }); -}); diff --git a/back/models/specs/user.spec.js b/back/models/specs/user.spec.js new file mode 100644 index 000000000..124afdc0c --- /dev/null +++ b/back/models/specs/user.spec.js @@ -0,0 +1,32 @@ +const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); + +describe('account recoverPassword()', () => { + const userId = 1107; + + const activeCtx = { + accessToken: {userId: userId}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + + beforeEach(() => { + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); + + it('should send email with token', async() => { + const userId = 1107; + const user = await models.Account.findById(userId); + + await models.Account.recoverPassword(user.email); + + const result = await models.AccessToken.findOne({where: {userId: userId}}); + + expect(result).toBeDefined(); + }); +}); diff --git a/back/models/user.js b/back/models/user.js index 0bbd39055..082d90500 100644 --- a/back/models/user.js +++ b/back/models/user.js @@ -9,12 +9,15 @@ module.exports = function(Self) { const headers = httpRequest.headers; const origin = headers.origin; + const user = await Self.app.models.Account.findById(info.user.id); const params = { + recipient: info.email, + lang: user.lang, url: `${origin}/#!/login/reset-password?access_token=${info.accessToken.id}` }; - const sendEmail = new Email('recover-password', params); + const email = new Email('recover-password', params); - return sendEmail.send(); + return email.send(); }); }; diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js index f0d726ed6..0ff938484 100644 --- a/e2e/helpers/selectors.js +++ b/e2e/helpers/selectors.js @@ -29,6 +29,11 @@ export default { firstModulePinIcon: 'vn-home a:nth-child(1) vn-icon[icon="push_pin"]', firstModuleRemovePinIcon: 'vn-home a:nth-child(1) vn-icon[icon="remove_circle"]' }, + recoverPassword: { + recoverPasswordButton: 'vn-login a[ui-sref="login.recover-password"]', + email: 'vn-recover-password vn-textfield[ng-model="$ctrl.email"]', + sendEmailButton: 'vn-recover-password vn-submit', + }, accountIndex: { addAccount: 'vn-user-index button vn-icon[icon="add"]', newName: 'vn-user-create vn-textfield[ng-model="$ctrl.user.name"]', diff --git a/e2e/paths/01-salix/04_recoverPassword.spec.js b/e2e/paths/01-salix/04_recoverPassword.spec.js new file mode 100644 index 000000000..f0dd884b2 --- /dev/null +++ b/e2e/paths/01-salix/04_recoverPassword.spec.js @@ -0,0 +1,40 @@ +import selectors from '../../helpers/selectors'; +import getBrowser from '../../helpers/puppeteer'; + +fdescribe('Login path', async() => { + let browser; + let page; + + beforeAll(async() => { + browser = await getBrowser(); + page = browser.page; + + await page.waitToClick(selectors.recoverPassword.recoverPasswordButton); + await page.waitForState('login.recover-password'); + }); + + afterAll(async() => { + await browser.close(); + }); + + it('should not throw error if not exist user', async() => { + await page.write(selectors.recoverPassword.email, 'fakeEmail@mydomain.com'); + await page.waitToClick(selectors.recoverPassword.sendEmailButton); + + const message = await page.waitForSnackbar(); + + expect(message.text).toContain('Notification sent!'); + }); + + it('should send email', async() => { + await page.waitForState('login'); + await page.waitToClick(selectors.recoverPassword.recoverPasswordButton); + + await page.write(selectors.recoverPassword.email, 'BruceWayne@mydomain.com'); + await page.waitToClick(selectors.recoverPassword.sendEmailButton); + const message = await page.waitForSnackbar(); + await page.waitForState('login'); + + expect(message.text).toContain('Notification sent!'); + }); +}); diff --git a/front/salix/components/app/app.html b/front/salix/components/app/app.html index 420a6895c..5ad284857 100644 --- a/front/salix/components/app/app.html +++ b/front/salix/components/app/app.html @@ -3,15 +3,15 @@ + ng-if="$ctrl.isLogin"> + ng-if="$ctrl.isRecover"> + ng-if="$ctrl.isReset"> diff --git a/front/salix/components/app/app.js b/front/salix/components/app/app.js index 50aee2f9f..dbb0d5af5 100644 --- a/front/salix/components/app/app.js +++ b/front/salix/components/app/app.js @@ -15,7 +15,11 @@ export default class App extends Component { get showLayout() { let state = this.$state.current.name; - return state && state != 'login' && !this.isRecover && !this.isReset; + return state && !this.isLogin && !this.isRecover && !this.isReset; + } + + get isLogin() { + return this.$state.current.name == 'login'; } get isRecover() { diff --git a/front/salix/components/login/locale/en.yml b/front/salix/components/login/locale/en.yml index c59a6dd8e..1ddd454b7 100644 --- a/front/salix/components/login/locale/en.yml +++ b/front/salix/components/login/locale/en.yml @@ -1,4 +1,8 @@ User: User Password: Password Do not close session: Do not close session -Enter: Enter \ No newline at end of file +Enter: Enter +Password requirements: > + The password must have at least {{ length }} length characters, + {{nAlpha}} alphabetic characters, {{nUpper}} capital letters, {{nDigits}} + digits and {{nPunct}} symbols (Ex: $%&.) diff --git a/front/salix/components/login/locale/es.yml b/front/salix/components/login/locale/es.yml index afb538513..e3a5815c1 100644 --- a/front/salix/components/login/locale/es.yml +++ b/front/salix/components/login/locale/es.yml @@ -7,3 +7,10 @@ I do not remember my password: No recuerdo mi contraseña Recover password: Recuperar contraseña We will sent you an email to recover your password: Te enviaremos un correo para restablecer tu contraseña Notification sent!: ¡Notificación enviada! +Reset password: Restrablecer contraseña +New password: Nueva contraseña +Repeat password: Repetir contraseña +Password requirements: > + La contraseña debe tener al menos {{ length }} caracteres de longitud, + {{nAlpha}} caracteres alfabéticos, {{nUpper}} letras mayúsculas, {{nDigits}} + dígitos y {{nPunct}} símbolos (Ej: $%&.) diff --git a/front/salix/components/login/recover-password.js b/front/salix/components/login/recover-password.js index 5171c911d..fa9bfc459 100644 --- a/front/salix/components/login/recover-password.js +++ b/front/salix/components/login/recover-password.js @@ -13,15 +13,19 @@ export default class Controller { }); } + goToLogin() { + this.vnApp.showSuccess(this.$translate.instant('Notification sent!')); + this.$state.go('login'); + } + submit() { const params = { email: this.email }; - this.$http.post('users/reset', params) + this.$http.post('Accounts/recoverPassword', params) .then(() => { - this.vnApp.showSuccess(this.$translate.instant('Notification sent!')); - this.$state.go('login'); + this.goToLogin(); }); } } diff --git a/front/salix/components/login/reset-password.html b/front/salix/components/login/reset-password.html index 431af16fd..eaf58494f 100644 --- a/front/salix/components/login/reset-password.html +++ b/front/salix/components/login/reset-password.html @@ -14,7 +14,7 @@ type="password"> diff --git a/front/salix/routes.js b/front/salix/routes.js index 5a5539c96..be893800f 100644 --- a/front/salix/routes.js +++ b/front/salix/routes.js @@ -9,14 +9,14 @@ function config($stateProvider, $urlRouterProvider) { .state('login', { url: '/login?continue', description: 'Login', - component: '' + template: '' }) - .state('login.recover-password', { + .state('recoverPassword', { url: '/recover-password', description: 'Recover-password', - template: '' + template: 'asd' }) - .state('login.reset-password', { + .state('resetPassword', { url: '/reset-password', description: 'Reset-password', template: '' diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 62c9b5c83..4da6c0f39 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -245,5 +245,6 @@ "Already has this status": "Ya tiene este estado", "There aren't records for this week": "No existen registros para esta semana", "Empty data source": "Origen de datos vacio", - "Email verify": "Correo de verificación" -} + "Email verify": "Correo de verificación", + "Landing cannot be lesser than shipment": "Landing cannot be lesser than shipment" +} \ No newline at end of file From 0f8eca4700708416fb7548b672a35ccb93068e11 Mon Sep 17 00:00:00 2001 From: alexm Date: Wed, 23 Nov 2022 08:23:58 +0100 Subject: [PATCH 28/58] fix: e2e --- e2e/helpers/selectors.js | 2 +- e2e/paths/01-salix/04_recoverPassword.spec.js | 2 +- e2e/paths/05-ticket/20_future.spec.js | 76 +++++++++---------- 3 files changed, 39 insertions(+), 41 deletions(-) diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js index 69aa7e436..643bf6b8a 100644 --- a/e2e/helpers/selectors.js +++ b/e2e/helpers/selectors.js @@ -30,7 +30,7 @@ export default { firstModuleRemovePinIcon: 'vn-home a:nth-child(1) vn-icon[icon="remove_circle"]' }, recoverPassword: { - recoverPasswordButton: 'vn-login a[ui-sref="login.recover-password"]', + recoverPasswordButton: 'vn-login a[ui-sref="recoverPassword"]', email: 'vn-recover-password vn-textfield[ng-model="$ctrl.email"]', sendEmailButton: 'vn-recover-password vn-submit', }, diff --git a/e2e/paths/01-salix/04_recoverPassword.spec.js b/e2e/paths/01-salix/04_recoverPassword.spec.js index cee807081..80ef32cb5 100644 --- a/e2e/paths/01-salix/04_recoverPassword.spec.js +++ b/e2e/paths/01-salix/04_recoverPassword.spec.js @@ -10,7 +10,7 @@ describe('Login path', async() => { page = browser.page; await page.waitToClick(selectors.recoverPassword.recoverPasswordButton); - await page.waitForState('login.recover-password'); + await page.waitForState('recoverPassword'); }); afterAll(async() => { diff --git a/e2e/paths/05-ticket/20_future.spec.js b/e2e/paths/05-ticket/20_future.spec.js index 4fee9523b..6db2bf4f0 100644 --- a/e2e/paths/05-ticket/20_future.spec.js +++ b/e2e/paths/05-ticket/20_future.spec.js @@ -5,80 +5,78 @@ describe('Ticket Future path', () => { let browser; let page; - beforeAll(async () => { + beforeAll(async() => { browser = await getBrowser(); page = browser.page; await page.loginAndModule('employee', 'ticket'); await page.accessToSection('ticket.future'); }); - afterAll(async () => { + afterAll(async() => { await browser.close(); }); const now = new Date(); const tomorrow = new Date(now.getDate() + 1); - const ticket = { - originDated: now, - futureDated: now, - linesMax: '9999', - litersMax: '9999', - warehouseFk: 'Warehouse One' - }; - it('should show errors snackbar because of the required data', async () => { + it('should show errors snackbar because of the required data', async() => { await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton); await page.clearInput(selectors.ticketFuture.warehouseFk); await page.waitToClick(selectors.ticketFuture.submit); let message = await page.waitForSnackbar(); + expect(message.text).toContain('warehouseFk is a required argument'); await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton); await page.clearInput(selectors.ticketFuture.litersMax); await page.waitToClick(selectors.ticketFuture.submit); message = await page.waitForSnackbar(); + expect(message.text).toContain('litersMax is a required argument'); await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton); await page.clearInput(selectors.ticketFuture.linesMax); await page.waitToClick(selectors.ticketFuture.submit); message = await page.waitForSnackbar(); + expect(message.text).toContain('linesMax is a required argument'); await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton); await page.clearInput(selectors.ticketFuture.futureDated); await page.waitToClick(selectors.ticketFuture.submit); message = await page.waitForSnackbar(); + expect(message.text).toContain('futureDated is a required argument'); await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton); await page.clearInput(selectors.ticketFuture.originDated); await page.waitToClick(selectors.ticketFuture.submit); message = await page.waitForSnackbar(); + expect(message.text).toContain('originDated is a required argument'); }); - it('should search with the required data', async () => { + it('should search with the required data', async() => { await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton); await page.waitToClick(selectors.ticketFuture.submit); await page.waitForNumberOfElements(selectors.ticketFuture.table, 4); }); - it('should search with the origin shipped today', async () => { + it('should search with the origin shipped today', async() => { await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton); await page.pickDate(selectors.ticketFuture.shipped, now); await page.waitToClick(selectors.ticketFuture.submit); await page.waitForNumberOfElements(selectors.ticketFuture.table, 4); }); - it('should search with the origin shipped tomorrow', async () => { + it('should search with the origin shipped tomorrow', async() => { await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton); await page.pickDate(selectors.ticketFuture.shipped, tomorrow); await page.waitToClick(selectors.ticketFuture.submit); await page.waitForNumberOfElements(selectors.ticketFuture.table, 0); }); - it('should search with the destination shipped today', async () => { + it('should search with the destination shipped today', async() => { await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton); await page.clearInput(selectors.ticketFuture.shipped); await page.pickDate(selectors.ticketFuture.tfShipped, now); @@ -86,14 +84,14 @@ describe('Ticket Future path', () => { await page.waitForNumberOfElements(selectors.ticketFuture.table, 4); }); - it('should search with the destination shipped tomorrow', async () => { + it('should search with the destination shipped tomorrow', async() => { await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton); await page.pickDate(selectors.ticketFuture.tfShipped, tomorrow); await page.waitToClick(selectors.ticketFuture.submit); await page.waitForNumberOfElements(selectors.ticketFuture.table, 0); }); - it('should search with the origin IPT', async () => { + it('should search with the origin IPT', async() => { await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton); await page.clearInput(selectors.ticketFuture.shipped); @@ -108,7 +106,7 @@ describe('Ticket Future path', () => { await page.waitForNumberOfElements(selectors.ticketFuture.table, 0); }); - it('should search with the destination IPT', async () => { + it('should search with the destination IPT', async() => { await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton); await page.clearInput(selectors.ticketFuture.shipped); @@ -123,7 +121,7 @@ describe('Ticket Future path', () => { await page.waitForNumberOfElements(selectors.ticketFuture.table, 0); }); - it('should search with the origin grouped state', async () => { + it('should search with the origin grouped state', async() => { await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton); await page.clearInput(selectors.ticketFuture.shipped); @@ -138,7 +136,7 @@ describe('Ticket Future path', () => { await page.waitForNumberOfElements(selectors.ticketFuture.table, 3); }); - it('should search with the destination grouped state', async () => { + it('should search with the destination grouped state', async() => { await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton); await page.clearInput(selectors.ticketFuture.shipped); @@ -164,10 +162,10 @@ describe('Ticket Future path', () => { await page.waitForNumberOfElements(selectors.ticketFuture.table, 4); }); - it('should search in smart-table with an ID Origin', async () => { + it('should search in smart-table with an ID Origin', async() => { await page.waitToClick(selectors.ticketFuture.tableButtonSearch); - await page.write(selectors.ticketFuture.tableId, "13"); - await page.keyboard.press("Enter"); + await page.write(selectors.ticketFuture.tableId, '13'); + await page.keyboard.press('Enter'); await page.waitForNumberOfElements(selectors.ticketFuture.table, 2); await page.waitToClick(selectors.ticketFuture.tableButtonSearch); @@ -176,10 +174,10 @@ describe('Ticket Future path', () => { await page.waitForNumberOfElements(selectors.ticketFuture.table, 4); }); - it('should search in smart-table with an ID Destination', async () => { + it('should search in smart-table with an ID Destination', async() => { await page.waitToClick(selectors.ticketFuture.tableButtonSearch); - await page.write(selectors.ticketFuture.tableTfId, "12"); - await page.keyboard.press("Enter"); + await page.write(selectors.ticketFuture.tableTfId, '12'); + await page.keyboard.press('Enter'); await page.waitForNumberOfElements(selectors.ticketFuture.table, 5); await page.waitToClick(selectors.ticketFuture.tableButtonSearch); @@ -188,7 +186,7 @@ describe('Ticket Future path', () => { await page.waitForNumberOfElements(selectors.ticketFuture.table, 4); }); - it('should search in smart-table with an IPT Origin', async () => { + it('should search in smart-table with an IPT Origin', async() => { await page.waitToClick(selectors.ticketFuture.tableButtonSearch); await page.autocompleteSearch(selectors.ticketFuture.tableIpt, 'Vertical'); await page.waitForNumberOfElements(selectors.ticketFuture.table, 1); @@ -199,7 +197,7 @@ describe('Ticket Future path', () => { await page.waitForNumberOfElements(selectors.ticketFuture.table, 4); }); - it('should search in smart-table with an IPT Destination', async () => { + it('should search in smart-table with an IPT Destination', async() => { await page.waitToClick(selectors.ticketFuture.tableButtonSearch); await page.autocompleteSearch(selectors.ticketFuture.tableTfIpt, 'Vertical'); await page.waitForNumberOfElements(selectors.ticketFuture.table, 1); @@ -210,10 +208,10 @@ describe('Ticket Future path', () => { await page.waitForNumberOfElements(selectors.ticketFuture.table, 4); }); - it('should search in smart-table with especified Lines', async () => { + it('should search in smart-table with especified Lines', async() => { await page.waitToClick(selectors.ticketFuture.tableButtonSearch); - await page.write(selectors.ticketFuture.tableLines, "0"); - await page.keyboard.press("Enter"); + await page.write(selectors.ticketFuture.tableLines, '0'); + await page.keyboard.press('Enter'); await page.waitForNumberOfElements(selectors.ticketFuture.table, 1); await page.waitToClick(selectors.ticketFuture.tableButtonSearch); @@ -222,8 +220,8 @@ describe('Ticket Future path', () => { await page.waitForNumberOfElements(selectors.ticketFuture.table, 4); await page.waitToClick(selectors.ticketFuture.tableButtonSearch); - await page.write(selectors.ticketFuture.tableLines, "1"); - await page.keyboard.press("Enter"); + await page.write(selectors.ticketFuture.tableLines, '1'); + await page.keyboard.press('Enter'); await page.waitForNumberOfElements(selectors.ticketFuture.table, 5); await page.waitToClick(selectors.ticketFuture.tableButtonSearch); @@ -232,10 +230,10 @@ describe('Ticket Future path', () => { await page.waitForNumberOfElements(selectors.ticketFuture.table, 4); }); - it('should search in smart-table with especified Liters', async () => { + it('should search in smart-table with especified Liters', async() => { await page.waitToClick(selectors.ticketFuture.tableButtonSearch); - await page.write(selectors.ticketFuture.tableLiters, "0"); - await page.keyboard.press("Enter"); + await page.write(selectors.ticketFuture.tableLiters, '0'); + await page.keyboard.press('Enter'); await page.waitForNumberOfElements(selectors.ticketFuture.table, 1); await page.waitToClick(selectors.ticketFuture.tableButtonSearch); @@ -244,8 +242,8 @@ describe('Ticket Future path', () => { await page.waitForNumberOfElements(selectors.ticketFuture.table, 4); await page.waitToClick(selectors.ticketFuture.tableButtonSearch); - await page.write(selectors.ticketFuture.tableLiters, "28"); - await page.keyboard.press("Enter"); + await page.write(selectors.ticketFuture.tableLiters, '28'); + await page.keyboard.press('Enter'); await page.waitForNumberOfElements(selectors.ticketFuture.table, 5); await page.waitToClick(selectors.ticketFuture.tableButtonSearch); @@ -254,13 +252,13 @@ describe('Ticket Future path', () => { await page.waitForNumberOfElements(selectors.ticketFuture.table, 4); }); - it('should check the three last tickets and move to the future', async () => { + it('should check the three last tickets and move to the future', async() => { await page.waitToClick(selectors.ticketFuture.multiCheck); await page.waitToClick(selectors.ticketFuture.firstCheck); await page.waitToClick(selectors.ticketFuture.moveButton); await page.waitToClick(selectors.ticketFuture.acceptButton); const message = await page.waitForSnackbar(); + expect(message.text).toContain('Tickets moved successfully!'); }); - }); From e854fd248e4ccf9432243b0650a671f44142b4ab Mon Sep 17 00:00:00 2001 From: vicent Date: Wed, 23 Nov 2022 10:08:58 +0100 Subject: [PATCH 29/58] feat: add checkInBox --- .../worker-time-control-mail/checkInbox.js | 181 ++++++++++++++++++ .../back/models/worker-time-control-mail.js | 3 + 2 files changed, 184 insertions(+) create mode 100644 modules/worker/back/methods/worker-time-control-mail/checkInbox.js create mode 100644 modules/worker/back/models/worker-time-control-mail.js diff --git a/modules/worker/back/methods/worker-time-control-mail/checkInbox.js b/modules/worker/back/methods/worker-time-control-mail/checkInbox.js new file mode 100644 index 000000000..7825f38b8 --- /dev/null +++ b/modules/worker/back/methods/worker-time-control-mail/checkInbox.js @@ -0,0 +1,181 @@ +const Imap = require('imap'); +module.exports = Self => { + Self.remoteMethod('checkInbox', { + description: 'Check an email inbox and process it', + accessType: 'READ', + returns: + { + arg: 'body', + type: 'file', + root: true + }, + http: { + path: `/checkInbox`, + verb: 'POST' + } + }); + + Self.checkInbox = async() => { + let imapConfig = await Self.app.models.WorkerTimeControlParams.findOne(); + let imap = new Imap({ + user: imapConfig.mailUser, + password: imapConfig.mailPass, + host: imapConfig.mailHost, + port: 993, + tls: true + }); + let isEmailOk; + let uid; + let emailBody; + + function openInbox(cb) { + imap.openBox('INBOX', true, cb); + } + + imap.once('ready', function() { + openInbox(function(err, box) { + if (err) throw err; + const totalMessages = box.messages.total; + if (totalMessages == 0) + imap.end(); + + let f = imap.seq.fetch('1:*', { + bodies: ['HEADER.FIELDS (FROM SUBJECT)', '1'], + struct: true + }); + f.on('message', function(msg, seqno) { + isEmailOk = false; + msg.on('body', function(stream, info) { + let buffer = ''; + let bufferCopy = ''; + stream.on('data', function(chunk) { + buffer = chunk.toString('utf8'); + if (info.which === '1' && bufferCopy.length == 0) + bufferCopy = buffer.replace(/\s/g, ' '); + }); + stream.on('end', function() { + if (bufferCopy.length > 0) { + emailBody = bufferCopy.toUpperCase().trim(); + + const bodyPositionOK = emailBody.match(/\bOK\b/i); + if (bodyPositionOK != null && (bodyPositionOK.index == 0 || bodyPositionOK.index == 122)) + isEmailOk = true; + else + isEmailOk = false; + } + }); + msg.once('attributes', function(attrs) { + uid = attrs.uid; + }); + msg.once('end', function() { + if (info.which === 'HEADER.FIELDS (FROM SUBJECT)') { + if (isEmailOk) { + imap.move(uid, 'exito', function(err) { + }); + emailConfirm(buffer); + } else { + imap.move(uid, 'error', function(err) { + }); + emailReply(buffer, emailBody); + } + } + }); + }); + }); + f.once('end', function() { + imap.end(); + }); + }); + }); + + imap.connect(); + return 'Leer emails de gestion horaria'; + }; + + async function emailConfirm(buffer) { + const now = new Date(); + const from = JSON.stringify(Imap.parseHeader(buffer).from); + const subject = JSON.stringify(Imap.parseHeader(buffer).subject); + + const timeControlDate = await getEmailDate(subject); + const week = timeControlDate[0]; + const year = timeControlDate[1]; + const user = await getUser(from); + let workerMail; + + if (user.id != null) { + workerMail = await Self.app.models.WorkerTimeControlMail.findOne({ + where: { + week: week, + year: year, + workerFk: user.id + } + }); + } + if (workerMail != null) { + await workerMail.updateAttributes({ + updated: now, + state: 'CONFIRMED' + }); + } + } + + async function emailReply(buffer, emailBody) { + const now = new Date(); + const from = JSON.stringify(Imap.parseHeader(buffer).from); + const subject = JSON.stringify(Imap.parseHeader(buffer).subject); + + const timeControlDate = await getEmailDate(subject); + const week = timeControlDate[0]; + const year = timeControlDate[1]; + const user = await getUser(from); + let workerMail; + + if (user.id != null) { + workerMail = await Self.app.models.WorkerTimeControlMail.findOne({ + where: { + week: week, + year: year, + workerFk: user.id + } + }); + + if (workerMail != null) { + await workerMail.updateAttributes({ + updated: now, + state: 'REVISE', + reason: emailBody + }); + } else + await sendMail(user, subject, emailBody); + } + } + + async function getUser(workerEmail) { + const userEmail = workerEmail.match(/(?<=<)(.*?)(?=>)/); + + let [user] = await Self.rawSql(`SELECT u.id,u.name FROM account.user u + LEFT JOIN account.mailForward m on m.account = u.id + WHERE forwardTo =? OR + CONCAT(u.name,'@verdnatura.es') = ?`, + [userEmail[0], userEmail[0]]); + + return user; + } + + async function getEmailDate(subject) { + const date = subject.match(/\d+/g); + return date; + } + + async function sendMail(user, subject, emailBody) { + const sendTo = 'rrhh@verdnatura.es'; + const emailSubject = subject + ' ' + user.name; + + await Self.app.models.Mail.create({ + receiver: sendTo, + subject: emailSubject, + body: emailBody + }); + } +}; diff --git a/modules/worker/back/models/worker-time-control-mail.js b/modules/worker/back/models/worker-time-control-mail.js new file mode 100644 index 000000000..36f3851b6 --- /dev/null +++ b/modules/worker/back/models/worker-time-control-mail.js @@ -0,0 +1,3 @@ +module.exports = Self => { + require('../methods/worker-time-control-mail/checkInbox')(Self); +}; From bf782c378273c97314763d8d0c48e31f763b52b4 Mon Sep 17 00:00:00 2001 From: vicent Date: Wed, 23 Nov 2022 10:09:09 +0100 Subject: [PATCH 30/58] =?UTF-8?q?fix:=20a=C3=B1adido=20esquema=20account?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/worker/back/methods/worker-time-control/sendMail.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/worker/back/methods/worker-time-control/sendMail.js b/modules/worker/back/methods/worker-time-control/sendMail.js index 2f9559b3a..cd9cacbd7 100644 --- a/modules/worker/back/methods/worker-time-control/sendMail.js +++ b/modules/worker/back/methods/worker-time-control/sendMail.js @@ -133,7 +133,7 @@ module.exports = Self => { tb.permissionRate, d.isTeleworking FROM tmp.timeBusinessCalculate tb - JOIN user u ON u.id = tb.userFk + JOIN account.user u ON u.id = tb.userFk JOIN department d ON d.id = tb.departmentFk JOIN business b ON b.id = tb.businessFk LEFT JOIN tmp.timeControlCalculate tc ON tc.userFk = tb.userFk AND tc.dated = tb.dated @@ -143,7 +143,7 @@ module.exports = Self => { IF(tc.timeWorkDecimal > 0, FALSE, IF(tb.timeWorkDecimal > 0, TRUE, FALSE)), TRUE))isTeleworkingWeek FROM tmp.timeBusinessCalculate tb - LEFT JOIN tmp.timeControlCalculate tc ON tc.userFk = tb.userFk + LEFT JOIN tmp.timeControlCalculate tc ON tc.userFk = tb.userFk AND tc.dated = tb.dated GROUP BY tb.userFk HAVING isTeleworkingWeek > 0 From 30a25664de17dec6a766dd6f4b721e9c55ee939a Mon Sep 17 00:00:00 2001 From: alexm Date: Wed, 23 Nov 2022 13:49:50 +0100 Subject: [PATCH 31/58] out-layout component --- front/salix/components/login/index.html | 7 ++- front/salix/components/login/index.js | 8 ++- front/salix/components/login/login.html | 57 +++++++++---------- .../components/login/recover-password.html | 36 ++++++------ .../components/login/reset-password.html | 40 ++++++------- front/salix/components/login/style.scss | 44 +++++++------- 6 files changed, 96 insertions(+), 96 deletions(-) diff --git a/front/salix/components/login/index.html b/front/salix/components/login/index.html index 5105d5113..186979f8c 100644 --- a/front/salix/components/login/index.html +++ b/front/salix/components/login/index.html @@ -1 +1,6 @@ - +
+ +
+ +
+
diff --git a/front/salix/components/login/index.js b/front/salix/components/login/index.js index 16683c679..f0e21fa29 100644 --- a/front/salix/components/login/index.js +++ b/front/salix/components/login/index.js @@ -2,7 +2,13 @@ import ngModule from '../../module'; import Component from 'core/lib/component'; import './style.scss'; -export class OutLayout extends Component {} +export default class OutLayout extends Component { + constructor($element, $scope) { + super($element, $scope); + } +} + +OutLayout.$inject = ['$element', '$scope']; ngModule.vnComponent('vnOutLayout', { template: require('./index.html'), diff --git a/front/salix/components/login/login.html b/front/salix/components/login/login.html index abd7c593a..a078fa0af 100644 --- a/front/salix/components/login/login.html +++ b/front/salix/components/login/login.html @@ -1,32 +1,27 @@ -
- -
- - - - - - - -
+ + + + + + + diff --git a/front/salix/components/login/recover-password.html b/front/salix/components/login/recover-password.html index 9461970c1..73f5401d9 100644 --- a/front/salix/components/login/recover-password.html +++ b/front/salix/components/login/recover-password.html @@ -1,21 +1,17 @@ -
-
-
Recover password
- - -
- We will sent you an email to recover your password -
- -
+
Recover password
+ + +
+ We will sent you an email to recover your password +
+ diff --git a/front/salix/components/login/reset-password.html b/front/salix/components/login/reset-password.html index eaf58494f..bdbdc113e 100644 --- a/front/salix/components/login/reset-password.html +++ b/front/salix/components/login/reset-password.html @@ -1,23 +1,19 @@ -
-
-
Reset password
- - - - - -
+
Reset password
+ + + + + diff --git a/front/salix/components/login/style.scss b/front/salix/components/login/style.scss index a2f94f7fe..8985893f2 100644 --- a/front/salix/components/login/style.scss +++ b/front/salix/components/login/style.scss @@ -3,6 +3,29 @@ vn-login, vn-reset-password, vn-recover-password{ + .footer { + margin-top: 32px; + text-align: center; + position: relative; + & > .vn-submit { + display: block; + + & > input { + display: block; + width: 100%; + } + } + & > .spinner-wrapper { + position: absolute; + width: 0; + top: 3px; + right: -8px; + overflow: visible; + } + } +} + +vn-out-layout{ position: absolute; height: 100%; width: 100%; @@ -41,27 +64,6 @@ vn-recover-password{ white-space: inherit; } } - & > .footer { - margin-top: 32px; - text-align: center; - position: relative; - - & > vn-submit { - display: block; - - & > input { - display: block; - width: 100%; - } - } - & > .spinner-wrapper { - position: absolute; - width: 0; - top: 3px; - right: -8px; - overflow: visible; - } - } } h5{ From 7651dcb473f81b384e70ed2c74f79ae7f0b745e6 Mon Sep 17 00:00:00 2001 From: alexm Date: Wed, 23 Nov 2022 14:43:18 +0100 Subject: [PATCH 32/58] feat: resetPasswordRequest use more params --- back/methods/account/recover-password.js | 2 +- back/models/user.js | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/back/methods/account/recover-password.js b/back/methods/account/recover-password.js index f08ff8968..ddea76829 100644 --- a/back/methods/account/recover-password.js +++ b/back/methods/account/recover-password.js @@ -19,7 +19,7 @@ module.exports = Self => { const models = Self.app.models; try { - await models.user.resetPassword({email}); + await models.user.resetPassword({email, emailTemplate: 'recover-password'}); } catch (err) { if (err.code === 'EMAIL_NOT_FOUND') return; diff --git a/back/models/user.js b/back/models/user.js index d0992923c..b24d702b3 100644 --- a/back/models/user.js +++ b/back/models/user.js @@ -16,7 +16,11 @@ module.exports = function(Self) { url: `${origin}/#!/reset-password?access_token=${info.accessToken.id}` }; - const email = new Email('recover-password', params); + const options = Object.assign({}, info.options); + for (const param in options) + params[param] = options[param]; + + const email = new Email(options.emailTemplate, params); return email.send(); }); From 37a7a12f8759bf03cd23d3524dbc737eb803f39c Mon Sep 17 00:00:00 2001 From: Pau Navarro Date: Thu, 24 Nov 2022 11:47:32 +0100 Subject: [PATCH 33/58] requested change --- .../route/back/methods/route/getTickets.js | 61 ++++++++++--------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/modules/route/back/methods/route/getTickets.js b/modules/route/back/methods/route/getTickets.js index 81b4c5781..a72868120 100644 --- a/modules/route/back/methods/route/getTickets.js +++ b/modules/route/back/methods/route/getTickets.js @@ -33,36 +33,37 @@ module.exports = Self => { const stmt = new ParameterizedSQL( `SELECT - t.id, - t.packages, - t.warehouseFk, - t.nickname, - t.clientFk, - t.priority, - t.addressFk, - st.code AS ticketStateCode, - st.name AS ticketStateName, - wh.name AS warehouseName, - tob.description AS ticketObservation, - a.street, - a.postalCode, - a.city, - am.name AS agencyModeName, - u.nickname AS userNickname, - vn.ticketTotalVolume(t.id) AS volume, - tob.description - FROM route r - JOIN ticket t ON t.routeFk = r.id - LEFT JOIN ticketState ts ON ts.ticketFk = t.id - LEFT JOIN state st ON st.id = ts.stateFk - LEFT JOIN warehouse wh ON wh.id = t.warehouseFk - LEFT JOIN ticketObservation tob ON tob.ticketFk = t.id AND tob.observationTypeFk = 3 - LEFT JOIN observationType ot ON tob.observationTypeFk = ot.id - AND ot.code = 'delivery' - LEFT JOIN address a ON a.id = t.addressFk - LEFT JOIN agencyMode am ON am.id = t.agencyModeFk - LEFT JOIN account.user u ON u.id = r.workerFk - LEFT JOIN vehicle v ON v.id = r.vehicleFk` + t.id, + t.packages, + t.warehouseFk, + t.nickname, + t.clientFk, + t.priority, + t.addressFk, + st.code AS ticketStateCode, + st.name AS ticketStateName, + wh.name AS warehouseName, + tob.description AS ticketObservation, + a.street, + a.postalCode, + a.city, + am.name AS agencyModeName, + u.nickname AS userNickname, + vn.ticketTotalVolume(t.id) AS volume, + tob.description + FROM vn.route r + JOIN ticket t ON t.routeFk = r.id + LEFT JOIN ticketState ts ON ts.ticketFk = t.id + LEFT JOIN state st ON st.id = ts.stateFk + LEFT JOIN warehouse wh ON wh.id = t.warehouseFk + LEFT JOIN ticketObservation tob ON tob.ticketFk = t.id + AND tob.observationTypeFk = (SELECT ot2.id from vn.observationType ot2 WHERE ot2.code = 'delivery') + LEFT JOIN observationType ot ON tob.observationTypeFk = ot.id + AND ot.code = 'delivery' + LEFT JOIN address a ON a.id = t.addressFk + LEFT JOIN agencyMode am ON am.id = t.agencyModeFk + LEFT JOIN account.user u ON u.id = r.workerFk + LEFT JOIN vehicle v ON v.id = r.vehicleFk` ); if (!filter.where) filter.where = {}; From 001c3ec2ace757f911ec495cfbbe6412ed29e9a1 Mon Sep 17 00:00:00 2001 From: Pau Navarro Date: Thu, 24 Nov 2022 12:06:13 +0100 Subject: [PATCH 34/58] requested changes --- modules/route/back/methods/route/getTickets.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/route/back/methods/route/getTickets.js b/modules/route/back/methods/route/getTickets.js index a72868120..708644c1a 100644 --- a/modules/route/back/methods/route/getTickets.js +++ b/modules/route/back/methods/route/getTickets.js @@ -56,10 +56,9 @@ module.exports = Self => { LEFT JOIN ticketState ts ON ts.ticketFk = t.id LEFT JOIN state st ON st.id = ts.stateFk LEFT JOIN warehouse wh ON wh.id = t.warehouseFk + LEFT JOIN observationType ot ON ot.code = 'delivery' LEFT JOIN ticketObservation tob ON tob.ticketFk = t.id - AND tob.observationTypeFk = (SELECT ot2.id from vn.observationType ot2 WHERE ot2.code = 'delivery') - LEFT JOIN observationType ot ON tob.observationTypeFk = ot.id - AND ot.code = 'delivery' + AND tob.observationTypeFk = ot.id LEFT JOIN address a ON a.id = t.addressFk LEFT JOIN agencyMode am ON am.id = t.agencyModeFk LEFT JOIN account.user u ON u.id = r.workerFk From 8d2e532167646c291128d4fdb1126394affe5139 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Andr=C3=A9s?= Date: Fri, 25 Nov 2022 09:32:54 +0100 Subject: [PATCH 35/58] #4613 eliminar uso de portfolio --- db/dump/fixtures.sql | 6 +- .../client/specs/updatePortfolio.spec.js | 75 ------------ .../back/methods/client/updatePortfolio.js | 25 ---- modules/client/back/models/client-methods.js | 1 - modules/client/front/basic-data/index.js | 2 - package-lock.json | 111 ++++++++++++++++-- 6 files changed, 104 insertions(+), 116 deletions(-) delete mode 100644 modules/client/back/methods/client/specs/updatePortfolio.spec.js delete mode 100644 modules/client/back/methods/client/updatePortfolio.js diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 41cd84638..2f55662c0 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -2563,10 +2563,10 @@ UPDATE `vn`.`route` UPDATE `vn`.`route` SET `invoiceInFk`=2 WHERE `id`=2; -INSERT INTO `bs`.`salesPerson` (`workerFk`, `year`, `month`, `portfolioWeight`) +INSERT INTO `bs`.`salesPerson` (`workerFk`, `year`, `month`) VALUES - (18, YEAR(util.VN_CURDATE()), MONTH(util.VN_CURDATE()), 807.23), - (19, YEAR(util.VN_CURDATE()), MONTH(util.VN_CURDATE()), 34.40); + (18, YEAR(util.VN_CURDATE()), MONTH(util.VN_CURDATE())), + (19, YEAR(util.VN_CURDATE()), MONTH(util.VN_CURDATE())); INSERT INTO `bs`.`sale` (`saleFk`, `amount`, `dated`, `typeFk`, `clientFk`) VALUES diff --git a/modules/client/back/methods/client/specs/updatePortfolio.spec.js b/modules/client/back/methods/client/specs/updatePortfolio.spec.js deleted file mode 100644 index bf681eb2e..000000000 --- a/modules/client/back/methods/client/specs/updatePortfolio.spec.js +++ /dev/null @@ -1,75 +0,0 @@ -const models = require('vn-loopback/server/server').models; -const LoopBackContext = require('loopback-context'); - -describe('Client updatePortfolio', () => { - const activeCtx = { - accessToken: {userId: 9}, - http: { - req: { - headers: {origin: 'http://localhost'}, - [`__`]: value => { - return value; - } - } - } - }; - - beforeAll(() => { - spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ - active: activeCtx - }); - }); - - it('should update the portfolioWeight when the salesPerson of a client changes', async() => { - const clientId = 1108; - const salesPersonId = 18; - - const tx = await models.Client.beginTransaction({}); - - try { - const options = {transaction: tx}; - const expectedResult = 841.63; - - const client = await models.Client.findById(clientId, null, options); - await client.updateAttribute('salesPersonFk', salesPersonId, options); - - await models.Client.updatePortfolio(options); - - const portfolioQuery = `SELECT portfolioWeight FROM bs.salesPerson WHERE workerFk = ${salesPersonId}; `; - const [salesPerson] = await models.Client.rawSql(portfolioQuery, null, options); - - expect(salesPerson.portfolioWeight).toEqual(expectedResult); - - await tx.rollback(); - } catch (e) { - await tx.rollback(); - throw e; - } - }); - - it('should keep the same portfolioWeight when a salesperson is unassigned of a client', async() => { - const clientId = 1107; - const salesPersonId = 19; - const tx = await models.Client.beginTransaction({}); - - try { - const options = {transaction: tx}; - const expectedResult = 34.40; - - const client = await models.Client.findById(clientId, null, options); - await client.updateAttribute('salesPersonFk', null, options); - - await models.Client.updatePortfolio(); - - const portfolioQuery = `SELECT portfolioWeight FROM bs.salesPerson WHERE workerFk = ${salesPersonId}; `; - const [salesPerson] = await models.Client.rawSql(portfolioQuery); - - expect(salesPerson.portfolioWeight).toEqual(expectedResult); - - await tx.rollback(); - } catch (e) { - await tx.rollback(); - throw e; - } - }); -}); diff --git a/modules/client/back/methods/client/updatePortfolio.js b/modules/client/back/methods/client/updatePortfolio.js deleted file mode 100644 index 809a84636..000000000 --- a/modules/client/back/methods/client/updatePortfolio.js +++ /dev/null @@ -1,25 +0,0 @@ -module.exports = function(Self) { - Self.remoteMethodCtx('updatePortfolio', { - description: 'Update salesPeson potfolio weight', - accessType: 'READ', - accepts: [], - returns: { - type: 'Object', - root: true - }, - http: { - path: `/updatePortfolio`, - verb: 'GET' - } - }); - - Self.updatePortfolio = async options => { - const myOptions = {}; - - if (typeof options == 'object') - Object.assign(myOptions, options); - - query = `CALL bs.salesPerson_updatePortfolio()`; - return Self.rawSql(query, null, myOptions); - }; -}; diff --git a/modules/client/back/models/client-methods.js b/modules/client/back/models/client-methods.js index 5134e3942..4b20a822c 100644 --- a/modules/client/back/models/client-methods.js +++ b/modules/client/back/models/client-methods.js @@ -22,7 +22,6 @@ module.exports = Self => { require('../methods/client/summary')(Self); require('../methods/client/updateAddress')(Self); require('../methods/client/updateFiscalData')(Self); - require('../methods/client/updatePortfolio')(Self); require('../methods/client/updateUser')(Self); require('../methods/client/uploadFile')(Self); require('../methods/client/campaignMetricsPdf')(Self); diff --git a/modules/client/front/basic-data/index.js b/modules/client/front/basic-data/index.js index 418663952..b08d642d1 100644 --- a/modules/client/front/basic-data/index.js +++ b/modules/client/front/basic-data/index.js @@ -10,8 +10,6 @@ export default class Controller extends Section { onSubmit() { return this.$.watcher.submit().then(() => { - const query = `Clients/updatePortfolio`; - this.$http.get(query); this.$http.get(`Clients/${this.$params.id}/checkDuplicatedData`); }); } diff --git a/package-lock.json b/package-lock.json index 30562d14d..a8e939eb0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,7 +24,7 @@ "jsdom": "^16.7.0", "jszip": "^3.10.0", "ldapjs": "^2.2.0", - "loopback": "^3.26.0", + "loopback": "^3.28.0", "loopback-boot": "3.3.1", "loopback-component-explorer": "^6.5.0", "loopback-component-storage": "3.6.1", @@ -4878,13 +4878,20 @@ "license": "MIT" }, "node_modules/caniuse-lite": { - "version": "1.0.30001299", + "version": "1.0.30001434", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001434.tgz", + "integrity": "sha512-aOBHrLmTQw//WFa2rcF1If9fa3ypkC1wzqqiKHgfdrXTWcU8C4gKVZT77eQAPWN1APys3+uQ0Df07rKauXGEYA==", "dev": true, - "license": "CC-BY-4.0", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] }, "node_modules/canonical-json": { "version": "0.0.4", @@ -12881,6 +12888,66 @@ "xmlcreate": "^1.0.1" } }, + "node_modules/jsbarcode": { + "version": "3.11.5", + "resolved": "https://registry.npmjs.org/jsbarcode/-/jsbarcode-3.11.5.tgz", + "integrity": "sha512-zv3KsH51zD00I/LrFzFSM6dst7rDn0vIMzaiZFL7qusTjPZiPtxg3zxetp0RR7obmjTw4f6NyGgbdkBCgZUIrA==", + "bin": { + "auto.js": "bin/barcodes/CODE128/auto.js", + "Barcode.js": "bin/barcodes/Barcode.js", + "barcodes": "bin/barcodes", + "canvas.js": "bin/renderers/canvas.js", + "checksums.js": "bin/barcodes/MSI/checksums.js", + "codabar": "bin/barcodes/codabar", + "CODE128": "bin/barcodes/CODE128", + "CODE128_AUTO.js": "bin/barcodes/CODE128/CODE128_AUTO.js", + "CODE128.js": "bin/barcodes/CODE128/CODE128.js", + "CODE128A.js": "bin/barcodes/CODE128/CODE128A.js", + "CODE128B.js": "bin/barcodes/CODE128/CODE128B.js", + "CODE128C.js": "bin/barcodes/CODE128/CODE128C.js", + "CODE39": "bin/barcodes/CODE39", + "constants.js": "bin/barcodes/ITF/constants.js", + "defaults.js": "bin/options/defaults.js", + "EAN_UPC": "bin/barcodes/EAN_UPC", + "EAN.js": "bin/barcodes/EAN_UPC/EAN.js", + "EAN13.js": "bin/barcodes/EAN_UPC/EAN13.js", + "EAN2.js": "bin/barcodes/EAN_UPC/EAN2.js", + "EAN5.js": "bin/barcodes/EAN_UPC/EAN5.js", + "EAN8.js": "bin/barcodes/EAN_UPC/EAN8.js", + "encoder.js": "bin/barcodes/EAN_UPC/encoder.js", + "ErrorHandler.js": "bin/exceptions/ErrorHandler.js", + "exceptions": "bin/exceptions", + "exceptions.js": "bin/exceptions/exceptions.js", + "fixOptions.js": "bin/help/fixOptions.js", + "GenericBarcode": "bin/barcodes/GenericBarcode", + "getOptionsFromElement.js": "bin/help/getOptionsFromElement.js", + "getRenderProperties.js": "bin/help/getRenderProperties.js", + "help": "bin/help", + "index.js": "bin/renderers/index.js", + "index.tmp.js": "bin/barcodes/index.tmp.js", + "ITF": "bin/barcodes/ITF", + "ITF.js": "bin/barcodes/ITF/ITF.js", + "ITF14.js": "bin/barcodes/ITF/ITF14.js", + "JsBarcode.js": "bin/JsBarcode.js", + "linearizeEncodings.js": "bin/help/linearizeEncodings.js", + "merge.js": "bin/help/merge.js", + "MSI": "bin/barcodes/MSI", + "MSI.js": "bin/barcodes/MSI/MSI.js", + "MSI10.js": "bin/barcodes/MSI/MSI10.js", + "MSI1010.js": "bin/barcodes/MSI/MSI1010.js", + "MSI11.js": "bin/barcodes/MSI/MSI11.js", + "MSI1110.js": "bin/barcodes/MSI/MSI1110.js", + "object.js": "bin/renderers/object.js", + "options": "bin/options", + "optionsFromStrings.js": "bin/help/optionsFromStrings.js", + "pharmacode": "bin/barcodes/pharmacode", + "renderers": "bin/renderers", + "shared.js": "bin/renderers/shared.js", + "svg.js": "bin/renderers/svg.js", + "UPC.js": "bin/barcodes/EAN_UPC/UPC.js", + "UPCE.js": "bin/barcodes/EAN_UPC/UPCE.js" + } + }, "node_modules/jsbn": { "version": "0.1.1", "license": "MIT" @@ -23759,6 +23826,14 @@ "version": "1.0.2", "license": "Apache-2.0" }, + "node_modules/xmldom": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.6.0.tgz", + "integrity": "sha512-iAcin401y58LckRZ0TkI4k0VSM1Qg0KGSc3i8rU+xrxe19A/BN1zHyVSJY7uoutVlaTSzYyk/v5AmkewAP7jtg==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/xtend": { "version": "4.0.2", "license": "MIT", @@ -23938,6 +24013,7 @@ "fs-extra": "^7.0.1", "intl": "^1.2.5", "js-yaml": "^3.13.1", + "jsbarcode": "^3.11.5", "jsonexport": "^3.2.0", "juice": "^5.2.0", "log4js": "^6.7.0", @@ -23948,7 +24024,8 @@ "strftime": "^0.10.0", "vue": "^2.6.10", "vue-i18n": "^8.15.0", - "vue-server-renderer": "^2.6.10" + "vue-server-renderer": "^2.6.10", + "xmldom": "^0.6.0" } }, "print/node_modules/fs-extra": { @@ -27170,7 +27247,9 @@ "version": "1.0.0" }, "caniuse-lite": { - "version": "1.0.30001299", + "version": "1.0.30001434", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001434.tgz", + "integrity": "sha512-aOBHrLmTQw//WFa2rcF1If9fa3ypkC1wzqqiKHgfdrXTWcU8C4gKVZT77eQAPWN1APys3+uQ0Df07rKauXGEYA==", "dev": true }, "canonical-json": { @@ -32586,6 +32665,11 @@ "xmlcreate": "^1.0.1" } }, + "jsbarcode": { + "version": "3.11.5", + "resolved": "https://registry.npmjs.org/jsbarcode/-/jsbarcode-3.11.5.tgz", + "integrity": "sha512-zv3KsH51zD00I/LrFzFSM6dst7rDn0vIMzaiZFL7qusTjPZiPtxg3zxetp0RR7obmjTw4f6NyGgbdkBCgZUIrA==" + }, "jsbn": { "version": "0.1.1" }, @@ -38977,6 +39061,7 @@ "fs-extra": "^7.0.1", "intl": "^1.2.5", "js-yaml": "^3.13.1", + "jsbarcode": "^3.11.5", "jsonexport": "^3.2.0", "juice": "^5.2.0", "log4js": "^6.7.0", @@ -38987,7 +39072,8 @@ "strftime": "^0.10.0", "vue": "^2.6.10", "vue-i18n": "^8.15.0", - "vue-server-renderer": "^2.6.10" + "vue-server-renderer": "^2.6.10", + "xmldom": "^0.6.0" }, "dependencies": { "fs-extra": { @@ -40134,6 +40220,11 @@ "xmlcreate": { "version": "1.0.2" }, + "xmldom": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.6.0.tgz", + "integrity": "sha512-iAcin401y58LckRZ0TkI4k0VSM1Qg0KGSc3i8rU+xrxe19A/BN1zHyVSJY7uoutVlaTSzYyk/v5AmkewAP7jtg==" + }, "xtend": { "version": "4.0.2" }, From d58e56729583c9fe21af64d36b4be722c6ac7530 Mon Sep 17 00:00:00 2001 From: vicent Date: Mon, 28 Nov 2022 08:51:04 +0100 Subject: [PATCH 36/58] fix: maneja si el dms no tiene file. Simplemente borra el registro --- back/methods/dms/deleteTrashFiles.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/back/methods/dms/deleteTrashFiles.js b/back/methods/dms/deleteTrashFiles.js index 63d7021c5..f14e65e9f 100644 --- a/back/methods/dms/deleteTrashFiles.js +++ b/back/methods/dms/deleteTrashFiles.js @@ -51,7 +51,7 @@ module.exports = Self => { const dstFile = path.join(dmsContainer.client.root, pathHash, dms.file); await fs.unlink(dstFile); } catch (err) { - if (err.code != 'ENOENT') + if (err.code != 'ENOENT' && dms.file) throw err; } From 2b0e6ab5ed54cb185a0953d8d45e49d25543fc5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Andr=C3=A9s?= Date: Mon, 28 Nov 2022 10:07:18 +0100 Subject: [PATCH 37/58] test --- db/dump/structure.sql | 1 - 1 file changed, 1 deletion(-) diff --git a/db/dump/structure.sql b/db/dump/structure.sql index 9f2370832..971113279 100644 --- a/db/dump/structure.sql +++ b/db/dump/structure.sql @@ -81043,4 +81043,3 @@ USE `vncontrol`; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; -- Dump completed on 2022-09-16 10:44:31 - From 0d6e424a3e8bce45439e2b590e5d615d81bef649 Mon Sep 17 00:00:00 2001 From: Pau Navarro Date: Mon, 28 Nov 2022 10:21:01 +0100 Subject: [PATCH 38/58] allow client search by socialname --- modules/client/back/methods/client/filter.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/client/back/methods/client/filter.js b/modules/client/back/methods/client/filter.js index 3e1ea43bb..6a545b594 100644 --- a/modules/client/back/methods/client/filter.js +++ b/modules/client/back/methods/client/filter.js @@ -91,7 +91,10 @@ module.exports = Self => { case 'search': return /^\d+$/.test(value) ? {'c.id': {inq: value}} - : {'c.name': {like: `%${value}%`}}; + : {or: [ + {'c.name': {like: `%${value}%`}}, + {'c.socialName': {like: `%${value}%`}}, + ]}; case 'name': case 'salesPersonFk': case 'fi': From d9e4ff6772d223a96f642b067c475c1e3cca0a93 Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 28 Nov 2022 11:48:25 +0100 Subject: [PATCH 40/58] fix: use $location --- front/core/lib/component.js | 7 ++++--- front/salix/components/app/app.js | 8 +++++++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/front/core/lib/component.js b/front/core/lib/component.js index f17db68a2..5695d9449 100644 --- a/front/core/lib/component.js +++ b/front/core/lib/component.js @@ -12,9 +12,10 @@ export default class Component extends EventEmitter { * @param {HTMLElement} $element The main component element * @param {$rootScope.Scope} $scope The element scope * @param {Function} $transclude The transclusion function + * @param {Function} $location The location function */ - constructor($element, $scope, $transclude) { - super(); + constructor($element, $scope, $transclude, $location) { + super($element, $scope, $transclude, $location); this.$ = $scope; if (!$element) return; @@ -164,7 +165,7 @@ export default class Component extends EventEmitter { $transclude.$$boundTransclude.$$slots[slot]; } } -Component.$inject = ['$element', '$scope']; +Component.$inject = ['$element', '$scope', '$location', '$state']; /* * Automatically adds the most used services to the prototype, so they are diff --git a/front/salix/components/app/app.js b/front/salix/components/app/app.js index 035c11d22..20f0ad969 100644 --- a/front/salix/components/app/app.js +++ b/front/salix/components/app/app.js @@ -9,12 +9,18 @@ import Component from 'core/lib/component'; * @property {SideMenu} rightMenu The left menu, if it's present */ export default class App extends Component { + constructor($element, $, $location, $state) { + super($element, $, $location, $state); + this.$location = $location; + this.$state = $state; + } + $postLink() { this.vnApp.logger = this; } get showLayout() { - const state = this.$state.current.name; + const state = this.$state.current.name || this.$location.$$path.substring(1).replace('/', '.'); const outLayout = ['login', 'recoverPassword', 'resetPassword']; return state && !outLayout.some(ol => ol == state); } From 4b54cf954b2aba9fd837f74216d167ce5a9ae35f Mon Sep 17 00:00:00 2001 From: vicent Date: Mon, 28 Nov 2022 13:56:21 +0100 Subject: [PATCH 41/58] refactor: envia el email con formato Verdnatura --- .../methods/worker-time-control/sendMail.js | 13 +---- .../weeklyHourRecordEmail.js | 53 +++++++++++++++++++ .../worker/back/models/worker-time-control.js | 1 + .../weekly-hour-record/assets/css/import.js | 12 +++++ .../email/weekly-hour-record/locale/en.yml | 6 +++ .../email/weekly-hour-record/locale/es.yml | 6 +++ .../weekly-hour-record.html | 9 ++++ .../weekly-hour-record/weekly-hour-record.js | 23 ++++++++ 8 files changed, 112 insertions(+), 11 deletions(-) create mode 100644 modules/worker/back/methods/worker-time-control/weeklyHourRecordEmail.js create mode 100644 print/templates/email/weekly-hour-record/assets/css/import.js create mode 100644 print/templates/email/weekly-hour-record/locale/en.yml create mode 100644 print/templates/email/weekly-hour-record/locale/es.yml create mode 100644 print/templates/email/weekly-hour-record/weekly-hour-record.html create mode 100755 print/templates/email/weekly-hour-record/weekly-hour-record.js diff --git a/modules/worker/back/methods/worker-time-control/sendMail.js b/modules/worker/back/methods/worker-time-control/sendMail.js index 2f9559b3a..a1d6ea2ac 100644 --- a/modules/worker/back/methods/worker-time-control/sendMail.js +++ b/modules/worker/back/methods/worker-time-control/sendMail.js @@ -332,18 +332,9 @@ module.exports = Self => { }, myOptions); const timestamp = started.getTime() / 1000; - await models.Mail.create({ - receiver: previousReceiver, - subject: $t('Record of hours week', { - week: args.week, - year: args.year - }), - body: `${salix.url}worker/${previousWorkerFk}/time-control?timestamp=${timestamp}` - }, myOptions); + const url = `${salix.url}worker/${previousWorkerFk}/time-control?timestamp=${timestamp}`; - query = `INSERT IGNORE INTO workerTimeControlMail (workerFk, year, week) - VALUES (?, ?, ?);`; - await Self.rawSql(query, [previousWorkerFk, args.year, args.week], myOptions); + await models.WorkerTimeControl.weeklyHourRecordEmail(ctx, previousReceiver, args.week, args.year, url); previousWorkerFk = day.workerFk; previousReceiver = day.receiver; diff --git a/modules/worker/back/methods/worker-time-control/weeklyHourRecordEmail.js b/modules/worker/back/methods/worker-time-control/weeklyHourRecordEmail.js new file mode 100644 index 000000000..0cf614e57 --- /dev/null +++ b/modules/worker/back/methods/worker-time-control/weeklyHourRecordEmail.js @@ -0,0 +1,53 @@ +const {Email} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('weeklyHourRecordEmail', { + description: 'Sends the buyer waste email', + accessType: 'WRITE', + accepts: [ + { + arg: 'recipient', + type: 'string', + description: 'The recipient email', + required: true, + }, + { + arg: 'week', + type: 'number', + required: true, + }, + { + arg: 'year', + type: 'number', + required: true + }, + { + arg: 'url', + type: 'string', + required: true + } + ], + returns: { + type: ['object'], + root: true + }, + http: { + path: '/weekly-hour-hecord-email', + verb: 'POST' + } + }); + + Self.weeklyHourRecordEmail = async(ctx, recipient, week, year, url) => { + const params = { + recipient: recipient, + lang: ctx.req.getLocale(), + week: week, + year: year, + url: url + }; + + const email = new Email('weekly-hour-record', params); + + return email.send(); + }; +}; diff --git a/modules/worker/back/models/worker-time-control.js b/modules/worker/back/models/worker-time-control.js index 9f802511a..7339f5d15 100644 --- a/modules/worker/back/models/worker-time-control.js +++ b/modules/worker/back/models/worker-time-control.js @@ -7,6 +7,7 @@ module.exports = Self => { require('../methods/worker-time-control/updateTimeEntry')(Self); require('../methods/worker-time-control/sendMail')(Self); require('../methods/worker-time-control/updateWorkerTimeControlMail')(Self); + require('../methods/worker-time-control/weeklyHourRecordEmail')(Self); Self.rewriteDbError(function(err) { if (err.code === 'ER_DUP_ENTRY') diff --git a/print/templates/email/weekly-hour-record/assets/css/import.js b/print/templates/email/weekly-hour-record/assets/css/import.js new file mode 100644 index 000000000..1582b82c5 --- /dev/null +++ b/print/templates/email/weekly-hour-record/assets/css/import.js @@ -0,0 +1,12 @@ +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); + +module.exports = new Stylesheet([ + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/email.css`]) + .mergeStyles(); + diff --git a/print/templates/email/weekly-hour-record/locale/en.yml b/print/templates/email/weekly-hour-record/locale/en.yml new file mode 100644 index 000000000..817e5451e --- /dev/null +++ b/print/templates/email/weekly-hour-record/locale/en.yml @@ -0,0 +1,6 @@ +subject: Weekly time log +title: Record of hours week {0} year {1} +dear: Dear worker +description: Access the following link:

+ {0}

+ Click 'SATISFIED' if you agree with the hours worked. Otherwise, press 'NOT SATISFIED', detailing the cause of the disagreement. diff --git a/print/templates/email/weekly-hour-record/locale/es.yml b/print/templates/email/weekly-hour-record/locale/es.yml new file mode 100644 index 000000000..b70862f16 --- /dev/null +++ b/print/templates/email/weekly-hour-record/locale/es.yml @@ -0,0 +1,6 @@ +subject: Registro de horas semanal +title: Registro de horas semana {0} año {1} +dear: Estimado trabajador +description: Acceda al siguiente enlace:

+ {0}

+ Pulse 'CONFORME' si esta de acuerdo con las horas trabajadas. En caso contrario pulse 'NO CONFORME', detallando la causa de la disconformidad. diff --git a/print/templates/email/weekly-hour-record/weekly-hour-record.html b/print/templates/email/weekly-hour-record/weekly-hour-record.html new file mode 100644 index 000000000..84abb4c61 --- /dev/null +++ b/print/templates/email/weekly-hour-record/weekly-hour-record.html @@ -0,0 +1,9 @@ + +
+
+

{{ $t('title', [week, year]) }}

+

{{$t('dear')}},

+

+
+
+
diff --git a/print/templates/email/weekly-hour-record/weekly-hour-record.js b/print/templates/email/weekly-hour-record/weekly-hour-record.js new file mode 100755 index 000000000..8fdaea0ce --- /dev/null +++ b/print/templates/email/weekly-hour-record/weekly-hour-record.js @@ -0,0 +1,23 @@ +const Component = require(`vn-print/core/component`); +const emailBody = new Component('email-body'); + +module.exports = { + name: 'weekly-hour-record', + components: { + 'email-body': emailBody.build() + }, + props: { + week: { + type: Number, + required: true + }, + year: { + type: Number, + required: true + }, + url: { + type: String, + required: true + } + } +}; From e3e337c02ecd23daf265db96fbe79cee7853ef52 Mon Sep 17 00:00:00 2001 From: vicent Date: Mon, 28 Nov 2022 14:28:47 +0100 Subject: [PATCH 42/58] fix: backTest --- .../worker-time-control/specs/sendMail.spec.js | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/modules/worker/back/methods/worker-time-control/specs/sendMail.spec.js b/modules/worker/back/methods/worker-time-control/specs/sendMail.spec.js index 4cc6e54e3..24bfd6904 100644 --- a/modules/worker/back/methods/worker-time-control/specs/sendMail.spec.js +++ b/modules/worker/back/methods/worker-time-control/specs/sendMail.spec.js @@ -2,15 +2,12 @@ const models = require('vn-loopback/server/server').models; describe('workerTimeControl sendMail()', () => { const workerId = 18; - const ctx = { - req: { - __: value => { - return value; - } - }, - args: {} - + const activeCtx = { + getLocale: () => { + return 'en'; + } }; + const ctx = {req: activeCtx, args: {}}; it('should fill time control of a worker without records in Journey and with rest', async() => { const tx = await models.WorkerTimeControl.beginTransaction({}); From c3d06ca5dbec264bac18adbaa6af1534aa9adbf9 Mon Sep 17 00:00:00 2001 From: vicent Date: Mon, 28 Nov 2022 14:47:23 +0100 Subject: [PATCH 43/58] fix: crashea cuando el log no tiene changedModel --- front/salix/components/log/index.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/front/salix/components/log/index.js b/front/salix/components/log/index.js index 2796931a0..fda465ae4 100644 --- a/front/salix/components/log/index.js +++ b/front/salix/components/log/index.js @@ -34,10 +34,11 @@ export default class Controller extends Section { set logs(value) { this._logs = value; if (!value) return; - + console.log(value); const validations = window.validations; value.forEach(log => { - const locale = validations[log.changedModel].locale ? validations[log.changedModel].locale : {}; + console.log(log.changedModel); + const locale = validations[log.changedModel] && validations[log.changedModel].locale ? validations[log.changedModel].locale : {}; log.oldProperties = this.getInstance(log.oldInstance, locale); log.newProperties = this.getInstance(log.newInstance, locale); From a0f5cf14499cca2c81510ddd7cc033160d3e5f4c Mon Sep 17 00:00:00 2001 From: vicent Date: Mon, 28 Nov 2022 14:48:37 +0100 Subject: [PATCH 44/58] refactor: borrados saltos de linea --- front/salix/components/log/index.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/front/salix/components/log/index.js b/front/salix/components/log/index.js index fda465ae4..f30878b9f 100644 --- a/front/salix/components/log/index.js +++ b/front/salix/components/log/index.js @@ -34,10 +34,9 @@ export default class Controller extends Section { set logs(value) { this._logs = value; if (!value) return; - console.log(value); + const validations = window.validations; value.forEach(log => { - console.log(log.changedModel); const locale = validations[log.changedModel] && validations[log.changedModel].locale ? validations[log.changedModel].locale : {}; log.oldProperties = this.getInstance(log.oldInstance, locale); From 8a0c810a8437ea5317ab4b50cf02e25bde14cb03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Andr=C3=A9s?= Date: Mon, 28 Nov 2022 17:45:19 +0100 Subject: [PATCH 45/58] refs #4613 --- db/dump/fixtures.sql | 4 ---- 1 file changed, 4 deletions(-) diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index f0cbf880e..92b84be43 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -2564,10 +2564,6 @@ UPDATE `vn`.`route` UPDATE `vn`.`route` SET `invoiceInFk`=2 WHERE `id`=2; -INSERT INTO `bs`.`salesPerson` (`workerFk`, `year`, `month`) - VALUES - (18, YEAR(util.VN_CURDATE()), MONTH(util.VN_CURDATE())), - (19, YEAR(util.VN_CURDATE()), MONTH(util.VN_CURDATE())); INSERT INTO `bs`.`sale` (`saleFk`, `amount`, `dated`, `typeFk`, `clientFk`) VALUES From b262b29627cd0b481b4c8529d6242928f4473589 Mon Sep 17 00:00:00 2001 From: guillermo Date: Tue, 29 Nov 2022 08:22:32 +0100 Subject: [PATCH 46/58] refs #4550 collection-label fixes --- .../collection-label/assets/css/style.css | 3 +- .../collection-label/collection-label.html | 67 +++++++++---------- .../collection-label/collection-label.js | 2 +- .../reports/collection-label/options.json | 4 +- .../collection-label/sql/labelsData.sql | 6 +- 5 files changed, 40 insertions(+), 42 deletions(-) diff --git a/print/templates/reports/collection-label/assets/css/style.css b/print/templates/reports/collection-label/assets/css/style.css index fe1975445..ad80af5bf 100644 --- a/print/templates/reports/collection-label/assets/css/style.css +++ b/print/templates/reports/collection-label/assets/css/style.css @@ -1,6 +1,6 @@ html { font-family: "Roboto"; - margin-top: -7px; + margin-top: -6px; } * { box-sizing: border-box; @@ -18,6 +18,7 @@ html { } #nickname { font-size: 22px; + max-width: 50px; } #agencyDescripton { font-size: 32px; diff --git a/print/templates/reports/collection-label/collection-label.html b/print/templates/reports/collection-label/collection-label.html index eeb82ac4a..8d7cc3655 100644 --- a/print/templates/reports/collection-label/collection-label.html +++ b/print/templates/reports/collection-label/collection-label.html @@ -1,35 +1,32 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{{labelData.levelV}}{{labelData.ticketFk}} ⬸ {{labelData.clientFk}}{{labelData.shipped}}
{{labelData.workerCode}}
{{labelData.labelCount}}
{{labelData.size}}
{{labelData.agencyDescription}}
{{labelData.lineCount}}
{{labelData.nickName}}{{labelData.agencyHour}}
- -
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{{labelData.levelV}}{{labelData.ticketFk}} / {{labelData.clientFk}}{{labelData.shipped}}
{{labelData.workerCode}}
{{labelData.labelCount}}
{{labelData.value}}
{{labelData.agencyDescription}}
{{labelData.lineCount}}
{{labelData.nickName}}{{labelData.agencyHour}}
+ + \ No newline at end of file diff --git a/print/templates/reports/collection-label/collection-label.js b/print/templates/reports/collection-label/collection-label.js index 7bc25ad79..d2d5f6417 100644 --- a/print/templates/reports/collection-label/collection-label.js +++ b/print/templates/reports/collection-label/collection-label.js @@ -40,7 +40,7 @@ module.exports = { format: 'code128', displayValue: false, width: 3.8, - height: 110, + height: 115, }); return xmlSerializer.serializeToString(svgNode); }, diff --git a/print/templates/reports/collection-label/options.json b/print/templates/reports/collection-label/options.json index 175b3c1db..f6e68a5ea 100644 --- a/print/templates/reports/collection-label/options.json +++ b/print/templates/reports/collection-label/options.json @@ -2,8 +2,8 @@ "width": "10.4cm", "height": "4.8cm", "margin": { - "top": "0cm", - "right": "0.5cm", + "top": "0.2cm", + "right": "0.6cm", "bottom": "0cm", "left": "0cm" }, diff --git a/print/templates/reports/collection-label/sql/labelsData.sql b/print/templates/reports/collection-label/sql/labelsData.sql index 6f5b47a54..1a2977f74 100644 --- a/print/templates/reports/collection-label/sql/labelsData.sql +++ b/print/templates/reports/collection-label/sql/labelsData.sql @@ -1,18 +1,18 @@ SELECT c.itemPackingTypeFk, CONCAT(tc.collectionFk, ' ', LEFT(cc.code, 4)) color, - CONCAT(tc.collectionFk, ' ', SUBSTRING('ABCDEFGH',tc.wagon, 1), '-', tc.`level`) levelV, + CONCAT(tc.collectionFk, ' ', SUBSTRING('ABCDEFGH', tc.wagon, 1), '-', tc.`level`) levelV, tc.ticketFk, LEFT(COALESCE(et.description, zo.name, am.name),12) agencyDescription, am.name, t.clientFk, CONCAT(CAST(SUM(sv.volume) AS DECIMAL(5, 2)), 'm³') m3 , - CAST(IF(ic.code = 'plant', CONCAT(MAX(i.`size`),' cm'), COUNT(*)) AS CHAR) size, + IF(ic.code = 'plant', CONCAT(MAX(i.`size`),' cm'), CONCAT(CAST(SUM(sv.volume) AS DECIMAL(5, 2)), 'm³')) `value`, w.code workerCode, tt.labelCount, IF(HOUR(t.shipped), TIME_FORMAT(t.shipped, '%H:%i'), TIME_FORMAT(zo.`hour`, '%H:%i')) agencyHour, DATE_FORMAT(t.shipped, '%d/%m/%y') shipped, COUNT(*) lineCount, - t.nickName + LEFT(t.nickName, 29) nickName FROM vn.ticket t JOIN vn.ticketCollection tc ON tc.ticketFk = t.id JOIN vn.collection c ON c.id = tc.collectionFk From 2faacb169ae9ca5add85a6737a2d8b3af2cfad2a Mon Sep 17 00:00:00 2001 From: guillermo Date: Tue, 29 Nov 2022 11:56:05 +0100 Subject: [PATCH 47/58] refs #4550 collection-label more fixes --- print/common/css/misc.css | 6 ++++ .../collection-label/assets/css/style.css | 2 +- .../collection-label/collection-label.html | 24 ++++++++------ .../reports/collection-label/options.json | 2 +- .../collection-label/sql/labelsData.sql | 32 ++++++++++--------- 5 files changed, 39 insertions(+), 27 deletions(-) diff --git a/print/common/css/misc.css b/print/common/css/misc.css index df8bf571a..ce6c641a0 100644 --- a/print/common/css/misc.css +++ b/print/common/css/misc.css @@ -49,4 +49,10 @@ .page-break-after { page-break-after: always; +} + +.ellipsize { + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; } \ No newline at end of file diff --git a/print/templates/reports/collection-label/assets/css/style.css b/print/templates/reports/collection-label/assets/css/style.css index ad80af5bf..597921c92 100644 --- a/print/templates/reports/collection-label/assets/css/style.css +++ b/print/templates/reports/collection-label/assets/css/style.css @@ -9,7 +9,7 @@ html { } #vertical { writing-mode: vertical-rl; - height: 226px; + height: 240px; margin-left: -13px; } .outline { diff --git a/print/templates/reports/collection-label/collection-label.html b/print/templates/reports/collection-label/collection-label.html index 8d7cc3655..6716d1fe5 100644 --- a/print/templates/reports/collection-label/collection-label.html +++ b/print/templates/reports/collection-label/collection-label.html @@ -4,27 +4,31 @@ - - - + + + - + - + - + - - + + - - + +
{{labelData.levelV}}{{labelData.ticketFk}} / {{labelData.clientFk}}{{labelData.shipped}} + {{labelData.collectionFk ? `${labelData.collectionFk} ~ ${labelData.wagon}-${labelData.level}` : '-'.repeat(23)}} + + {{labelData.clientFk ? `${labelData.ticketFk} « ${labelData.clientFk}` : labelData.ticketFk}} + {{labelData.shipped ? labelData.shipped : '---'}}
{{labelData.workerCode}}{{labelData.workerCode ? labelData.workerCode : '---'}}
{{labelData.labelCount}}{{labelData.labelCount ? labelData.labelCount : 0}}
{{labelData.value}}{{labelData.code == 'plant' ? labelData.size + 'cm' : labelData.volume + 'm³'}}
{{labelData.agencyDescription}}
{{labelData.lineCount}}
{{labelData.agencyDescription}}
{{labelData.lineCount ? labelData.lineCount : 0}}
{{labelData.nickName}}{{labelData.agencyHour}}{{labelData.nickName ? labelData.nickName : '---'}}{{labelData.shipped ? labelData.shippedHour : labelData.zoneHour}}
diff --git a/print/templates/reports/collection-label/options.json b/print/templates/reports/collection-label/options.json index f6e68a5ea..ae88e6c0c 100644 --- a/print/templates/reports/collection-label/options.json +++ b/print/templates/reports/collection-label/options.json @@ -2,7 +2,7 @@ "width": "10.4cm", "height": "4.8cm", "margin": { - "top": "0.2cm", + "top": "0.3cm", "right": "0.6cm", "bottom": "0cm", "left": "0cm" diff --git a/print/templates/reports/collection-label/sql/labelsData.sql b/print/templates/reports/collection-label/sql/labelsData.sql index 1a2977f74..b799b289b 100644 --- a/print/templates/reports/collection-label/sql/labelsData.sql +++ b/print/templates/reports/collection-label/sql/labelsData.sql @@ -1,21 +1,23 @@ -SELECT c.itemPackingTypeFk, - CONCAT(tc.collectionFk, ' ', LEFT(cc.code, 4)) color, - CONCAT(tc.collectionFk, ' ', SUBSTRING('ABCDEFGH', tc.wagon, 1), '-', tc.`level`) levelV, - tc.ticketFk, - LEFT(COALESCE(et.description, zo.name, am.name),12) agencyDescription, +SELECT tc.collectionFk, + SUBSTRING('ABCDEFGH', tc.wagon, 1) wagon, + tc.`level`, + t.id ticketFk, + COALESCE(et.description, zo.name, am.name) agencyDescription, am.name, t.clientFk, - CONCAT(CAST(SUM(sv.volume) AS DECIMAL(5, 2)), 'm³') m3 , - IF(ic.code = 'plant', CONCAT(MAX(i.`size`),' cm'), CONCAT(CAST(SUM(sv.volume) AS DECIMAL(5, 2)), 'm³')) `value`, + CAST(SUM(sv.volume) AS DECIMAL(5, 2)) volume, + MAX(i.`size`) `size`, + ic.code, w.code workerCode, - tt.labelCount, - IF(HOUR(t.shipped), TIME_FORMAT(t.shipped, '%H:%i'), TIME_FORMAT(zo.`hour`, '%H:%i')) agencyHour, + TIME_FORMAT(t.shipped, '%H:%i') shippedHour, + TIME_FORMAT(zo.`hour`, '%H:%i') zoneHour, DATE_FORMAT(t.shipped, '%d/%m/%y') shipped, - COUNT(*) lineCount, - LEFT(t.nickName, 29) nickName + t.nickName, + tt.labelCount, + COUNT(*) lineCount FROM vn.ticket t - JOIN vn.ticketCollection tc ON tc.ticketFk = t.id - JOIN vn.collection c ON c.id = tc.collectionFk + LEFT JOIN vn.ticketCollection tc ON tc.ticketFk = t.id + LEFT JOIN vn.collection c ON c.id = tc.collectionFk LEFT JOIN vn.collectionColors cc ON cc.shelve = tc.`level` AND cc.wagon = tc.wagon AND cc.trainFk = c.trainFk @@ -24,12 +26,12 @@ SELECT c.itemPackingTypeFk, JOIN vn.item i ON i.id = s.itemFk JOIN vn.itemType it ON it.id = i.typeFk JOIN vn.itemCategory ic ON ic.id = it.categoryFk - JOIN vn.worker w ON w.id = c.workerFk + LEFT JOIN vn.worker w ON w.id = c.workerFk JOIN vn.agencyMode am ON am.id = t.agencyModeFk LEFT JOIN vn.ticketTrolley tt ON tt.ticket = t.id LEFT JOIN vn.`zone` zo ON t.zoneFk = zo.id LEFT JOIN vn.routesMonitor rm ON rm.routeFk = t.routeFk LEFT JOIN vn.expeditionTruck et ON et.id = rm.expeditionTruckFk - WHERE tc.ticketFk IN (?) + WHERE t.id IN (?) GROUP BY t.id ORDER BY cc.`code`; \ No newline at end of file From b7fa4dca4c450b47a65c886c2797e50963fa8797 Mon Sep 17 00:00:00 2001 From: guillermo Date: Tue, 29 Nov 2022 14:16:44 +0100 Subject: [PATCH 48/58] refs #4550 changed font-family of collection-label --- .../templates/reports/collection-label/assets/css/style.css | 3 ++- .../reports/collection-label/collection-label.html | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/print/templates/reports/collection-label/assets/css/style.css b/print/templates/reports/collection-label/assets/css/style.css index 597921c92..f62d35c97 100644 --- a/print/templates/reports/collection-label/assets/css/style.css +++ b/print/templates/reports/collection-label/assets/css/style.css @@ -1,5 +1,5 @@ html { - font-family: "Roboto"; + font-family: Arial, Helvetica, sans-serif; margin-top: -6px; } * { @@ -15,6 +15,7 @@ html { .outline { border: 1px solid black; padding: 5px; + height: 37px; } #nickname { font-size: 22px; diff --git a/print/templates/reports/collection-label/collection-label.html b/print/templates/reports/collection-label/collection-label.html index 6716d1fe5..c64c12aed 100644 --- a/print/templates/reports/collection-label/collection-label.html +++ b/print/templates/reports/collection-label/collection-label.html @@ -5,7 +5,7 @@ - {{labelData.collectionFk ? `${labelData.collectionFk} ~ ${labelData.wagon}-${labelData.level}` : '-'.repeat(23)}} + {{labelData.collectionFk ? `${labelData.collectionFk} ~ ${labelData.wagon}-${labelData.level}` : '-'.repeat(19)}} {{labelData.clientFk ? `${labelData.ticketFk} « ${labelData.clientFk}` : labelData.ticketFk}} @@ -23,11 +23,11 @@ {{labelData.code == 'plant' ? labelData.size + 'cm' : labelData.volume + 'm³'}} -
{{labelData.agencyDescription}}
+
{{labelData.agencyDescription.toUpperCase()}}
{{labelData.lineCount ? labelData.lineCount : 0}} - {{labelData.nickName ? labelData.nickName : '---'}} + {{labelData.nickName ? labelData.nickName.toUpperCase() : '---'}} {{labelData.shipped ? labelData.shippedHour : labelData.zoneHour}} From d0acd3e4c0eee2c8a55d50908fd14af3a6bb4cbd Mon Sep 17 00:00:00 2001 From: guillermo Date: Wed, 30 Nov 2022 08:18:37 +0100 Subject: [PATCH 49/58] refs #4550 collection-label changes --- .../collection-label/assets/css/style.css | 7 ++++--- .../collection-label/collection-label.html | 16 ++++++++-------- .../reports/collection-label/collection-label.js | 9 ++++++++- .../reports/collection-label/sql/labelsData.sql | 16 ++++++++-------- 4 files changed, 28 insertions(+), 20 deletions(-) diff --git a/print/templates/reports/collection-label/assets/css/style.css b/print/templates/reports/collection-label/assets/css/style.css index f62d35c97..f9ead378a 100644 --- a/print/templates/reports/collection-label/assets/css/style.css +++ b/print/templates/reports/collection-label/assets/css/style.css @@ -9,7 +9,8 @@ html { } #vertical { writing-mode: vertical-rl; - height: 240px; + height: 235px; + font-size: 30px; margin-left: -13px; } .outline { @@ -34,6 +35,6 @@ html { #shipped { font-weight: bold; } -#ticketFk, #vertical { - font-size: 34px; +#ticketFk { + font-size: 32px; } \ No newline at end of file diff --git a/print/templates/reports/collection-label/collection-label.html b/print/templates/reports/collection-label/collection-label.html index c64c12aed..de9e5fcc3 100644 --- a/print/templates/reports/collection-label/collection-label.html +++ b/print/templates/reports/collection-label/collection-label.html @@ -5,30 +5,30 @@ - {{labelData.collectionFk ? `${labelData.collectionFk} ~ ${labelData.wagon}-${labelData.level}` : '-'.repeat(19)}} + {{labelData.collectionFk ? `${labelData.collectionFk} ~ ${getVertical(labelData.code, labelData.wagon, labelData.level, labelData.color)}` : '-'.repeat(19)}} {{labelData.clientFk ? `${labelData.ticketFk} « ${labelData.clientFk}` : labelData.ticketFk}} - {{labelData.shipped ? labelData.shipped : '---'}} + {{labelData.shipped || '---'}}
- {{labelData.workerCode ? labelData.workerCode : '---'}} + {{labelData.workerCode || '---'}} - {{labelData.labelCount ? labelData.labelCount : 0}} + {{labelData.labelCount || 0}} - {{labelData.code == 'plant' ? labelData.size + 'cm' : labelData.volume + 'm³'}} + {{labelData.code == 'V' ? (labelData.size || 0) + 'cm' : (labelData.volume || 0) + 'm³'}} -
{{labelData.agencyDescription.toUpperCase()}}
- {{labelData.lineCount ? labelData.lineCount : 0}} +
{{labelData.agencyDescription ? labelData.agencyDescription.toUpperCase() : '---'}}
+ {{labelData.lineCount || 0}} {{labelData.nickName ? labelData.nickName.toUpperCase() : '---'}} - {{labelData.shipped ? labelData.shippedHour : labelData.zoneHour}} + {{labelData.shippedHour || labelData.zoneHour}} diff --git a/print/templates/reports/collection-label/collection-label.js b/print/templates/reports/collection-label/collection-label.js index d2d5f6417..93c13e49b 100644 --- a/print/templates/reports/collection-label/collection-label.js +++ b/print/templates/reports/collection-label/collection-label.js @@ -25,7 +25,6 @@ module.exports = { ticketIds = [this.id]; this.labelsData = await this.rawSqlFromDef('labelsData', [ticketIds]); - if (!this.labelsData.length) throw new UserError('Empty data source'); }, @@ -44,6 +43,14 @@ module.exports = { }); return xmlSerializer.serializeToString(svgNode); }, + getVertical(code, wagon, level, color) { + let value; + if (code == 'V') + value = `${wagon}-${level}`; + else + value = `${color.substring(0, 4)}`; + return value; + }, }, components: { 'report-body': reportBody.build() diff --git a/print/templates/reports/collection-label/sql/labelsData.sql b/print/templates/reports/collection-label/sql/labelsData.sql index b799b289b..d2dafea1d 100644 --- a/print/templates/reports/collection-label/sql/labelsData.sql +++ b/print/templates/reports/collection-label/sql/labelsData.sql @@ -1,13 +1,13 @@ -SELECT tc.collectionFk, +SELECT c.itemPackingTypeFk code, + tc.collectionFk, SUBSTRING('ABCDEFGH', tc.wagon, 1) wagon, tc.`level`, t.id ticketFk, COALESCE(et.description, zo.name, am.name) agencyDescription, - am.name, + cc.code color, t.clientFk, CAST(SUM(sv.volume) AS DECIMAL(5, 2)) volume, MAX(i.`size`) `size`, - ic.code, w.code workerCode, TIME_FORMAT(t.shipped, '%H:%i') shippedHour, TIME_FORMAT(zo.`hour`, '%H:%i') zoneHour, @@ -21,13 +21,13 @@ SELECT tc.collectionFk, LEFT JOIN vn.collectionColors cc ON cc.shelve = tc.`level` AND cc.wagon = tc.wagon AND cc.trainFk = c.trainFk - JOIN vn.sale s ON s.ticketFk = t.id + LEFT JOIN vn.sale s ON s.ticketFk = t.id LEFT JOIN vn.saleVolume sv ON sv.saleFk = s.id - JOIN vn.item i ON i.id = s.itemFk - JOIN vn.itemType it ON it.id = i.typeFk - JOIN vn.itemCategory ic ON ic.id = it.categoryFk + LEFT JOIN vn.item i ON i.id = s.itemFk + LEFT JOIN vn.itemType it ON it.id = i.typeFk + LEFT JOIN vn.itemCategory ic ON ic.id = it.categoryFk LEFT JOIN vn.worker w ON w.id = c.workerFk - JOIN vn.agencyMode am ON am.id = t.agencyModeFk + LEFT JOIN vn.agencyMode am ON am.id = t.agencyModeFk LEFT JOIN vn.ticketTrolley tt ON tt.ticket = t.id LEFT JOIN vn.`zone` zo ON t.zoneFk = zo.id LEFT JOIN vn.routesMonitor rm ON rm.routeFk = t.routeFk From 27078595ce1828356b5f34d50426212d84346722 Mon Sep 17 00:00:00 2001 From: alexandre Date: Wed, 30 Nov 2022 08:39:04 +0100 Subject: [PATCH 50/58] fix balances --- modules/client/back/methods/receipt/filter.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/client/back/methods/receipt/filter.js b/modules/client/back/methods/receipt/filter.js index 9549fb001..c4ebc6fcf 100644 --- a/modules/client/back/methods/receipt/filter.js +++ b/modules/client/back/methods/receipt/filter.js @@ -57,14 +57,16 @@ module.exports = Self => { r.clientFk, FALSE hasPdf, FALSE isInvoice, - CASE WHEN at2.code LIKE 'compensation' THEN True ELSE False END as isCompensation + at2.id IS NOT NULL as isCompensation FROM vn.receipt r LEFT JOIN vn.worker w ON w.id = r.workerFk LEFT JOIN account.user u ON u.id = w.userFk JOIN vn.company c ON c.id = r.companyFk - JOIN vn.accounting a ON a.id = r.bankFk - JOIN vn.accountingType at2 ON at2.id = a.accountingTypeFk - WHERE r.clientFk = ? AND r.companyFk = ? + LEFT JOIN vn.accounting a ON a.id = r.bankFk + LEFT JOIN vn.accountingType at2 ON at2.id = a.accountingTypeFk AND at2.code = 'compensation' + WHERE + r.clientFk = ? + AND r.companyFk = ? UNION ALL SELECT i.id, @@ -81,11 +83,9 @@ module.exports = Self => { i.clientFk, i.hasPdf, TRUE isInvoice, - CASE WHEN at2.code LIKE 'compensation' THEN True ELSE False END as isCompensation + NULL FROM vn.invoiceOut i JOIN vn.company c ON c.id = i.companyFk - JOIN vn.accounting a ON a.id = i.bankFk - JOIN vn.accountingType at2 ON at2.id = a.accountingTypeFk WHERE i.clientFk = ? AND i.companyFk = ? ORDER BY payed DESC, created DESC ) t ORDER BY payed DESC, created DESC`, From bef1071316e0f01327e0c28a4057bda7ab160373 Mon Sep 17 00:00:00 2001 From: Pau Navarro Date: Wed, 30 Nov 2022 09:22:03 +0100 Subject: [PATCH 51/58] refs #4914 @1h --- modules/client/back/methods/client/filter.js | 22 +++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/modules/client/back/methods/client/filter.js b/modules/client/back/methods/client/filter.js index 3e1ea43bb..1ae569fd3 100644 --- a/modules/client/back/methods/client/filter.js +++ b/modules/client/back/methods/client/filter.js @@ -91,7 +91,18 @@ module.exports = Self => { case 'search': return /^\d+$/.test(value) ? {'c.id': {inq: value}} - : {'c.name': {like: `%${value}%`}}; + : {or: [ + {'c.name': {like: `%${value}%`}}, + {'c.socialName': {like: `%${value}%`}}, + ]}; + case 'phone': + return {or: [ + {'c.phone': {like: `%${value}%`}}, + {'c.mobile': {like: `%${value}%`}}, + ]}; + case 'zoneFk': + param = 'a.postalCode'; + return {[param]: {inq: postalCode}}; case 'name': case 'salesPersonFk': case 'fi': @@ -100,12 +111,8 @@ module.exports = Self => { case 'postcode': case 'provinceFk': case 'email': - case 'phone': param = `c.${param}`; - return {[param]: value}; - case 'zoneFk': - param = 'a.postalCode'; - return {[param]: {inq: postalCode}}; + return {[param]: {like: `%${value}%`}}; } }); @@ -119,6 +126,7 @@ module.exports = Self => { c.fi, c.socialName, c.phone, + c.mobile, c.city, c.postcode, c.email, @@ -132,7 +140,7 @@ module.exports = Self => { LEFT JOIN account.user u ON u.id = c.salesPersonFk LEFT JOIN province p ON p.id = c.provinceFk JOIN vn.address a ON a.clientFk = c.id - ` + ` ); stmt.merge(conn.makeWhere(filter.where)); From 492b852be8597ca297dd205349515b290b937ab6 Mon Sep 17 00:00:00 2001 From: alexandre Date: Wed, 30 Nov 2022 09:22:53 +0100 Subject: [PATCH 52/58] delete orderBy --- modules/client/back/methods/receipt/filter.js | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/client/back/methods/receipt/filter.js b/modules/client/back/methods/receipt/filter.js index c4ebc6fcf..6df5e73f8 100644 --- a/modules/client/back/methods/receipt/filter.js +++ b/modules/client/back/methods/receipt/filter.js @@ -87,7 +87,6 @@ module.exports = Self => { FROM vn.invoiceOut i JOIN vn.company c ON c.id = i.companyFk WHERE i.clientFk = ? AND i.companyFk = ? - ORDER BY payed DESC, created DESC ) t ORDER BY payed DESC, created DESC`, [ clientId, From 497e3e54a2a171068543c3e91caadaf5db832fbc Mon Sep 17 00:00:00 2001 From: guillermo Date: Wed, 30 Nov 2022 10:52:52 +0100 Subject: [PATCH 53/58] refs #4550 changes --- .../collection-label/collection-label.html | 4 +--- .../reports/collection-label/collection-label.js | 15 ++++++++++----- .../reports/collection-label/sql/labelsData.sql | 16 ++++++++-------- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/print/templates/reports/collection-label/collection-label.html b/print/templates/reports/collection-label/collection-label.html index de9e5fcc3..b7f783a88 100644 --- a/print/templates/reports/collection-label/collection-label.html +++ b/print/templates/reports/collection-label/collection-label.html @@ -4,9 +4,7 @@ - + diff --git a/print/templates/reports/collection-label/collection-label.js b/print/templates/reports/collection-label/collection-label.js index 93c13e49b..fd412791b 100644 --- a/print/templates/reports/collection-label/collection-label.js +++ b/print/templates/reports/collection-label/collection-label.js @@ -43,12 +43,17 @@ module.exports = { }); return xmlSerializer.serializeToString(svgNode); }, - getVertical(code, wagon, level, color) { + getVertical(labelData) { let value; - if (code == 'V') - value = `${wagon}-${level}`; - else - value = `${color.substring(0, 4)}`; + if (labelData.collectionFk) { + value = `${labelData.collectionFk} ~ `; + if (labelData.code == 'V') + value = value + `${labelData.wagon}-${labelData.level}`; + else + value = value + `${labelData.color.substring(0, 4)}`; + } else + value = '-'.repeat(19); + return value; }, }, diff --git a/print/templates/reports/collection-label/sql/labelsData.sql b/print/templates/reports/collection-label/sql/labelsData.sql index d2dafea1d..9afac79d0 100644 --- a/print/templates/reports/collection-label/sql/labelsData.sql +++ b/print/templates/reports/collection-label/sql/labelsData.sql @@ -16,18 +16,18 @@ SELECT c.itemPackingTypeFk code, tt.labelCount, COUNT(*) lineCount FROM vn.ticket t - LEFT JOIN vn.ticketCollection tc ON tc.ticketFk = t.id - LEFT JOIN vn.collection c ON c.id = tc.collectionFk + JOIN vn.ticketCollection tc ON tc.ticketFk = t.id + JOIN vn.collection c ON c.id = tc.collectionFk LEFT JOIN vn.collectionColors cc ON cc.shelve = tc.`level` AND cc.wagon = tc.wagon AND cc.trainFk = c.trainFk - LEFT JOIN vn.sale s ON s.ticketFk = t.id + JOIN vn.sale s ON s.ticketFk = t.id LEFT JOIN vn.saleVolume sv ON sv.saleFk = s.id - LEFT JOIN vn.item i ON i.id = s.itemFk - LEFT JOIN vn.itemType it ON it.id = i.typeFk - LEFT JOIN vn.itemCategory ic ON ic.id = it.categoryFk - LEFT JOIN vn.worker w ON w.id = c.workerFk - LEFT JOIN vn.agencyMode am ON am.id = t.agencyModeFk + JOIN vn.item i ON i.id = s.itemFk + JOIN vn.itemType it ON it.id = i.typeFk + JOIN vn.itemCategory ic ON ic.id = it.categoryFk + JOIN vn.worker w ON w.id = c.workerFk + JOIN vn.agencyMode am ON am.id = t.agencyModeFk LEFT JOIN vn.ticketTrolley tt ON tt.ticket = t.id LEFT JOIN vn.`zone` zo ON t.zoneFk = zo.id LEFT JOIN vn.routesMonitor rm ON rm.routeFk = t.routeFk From 23f429d94a1c960d15ccac4d98eb1db06eea4046 Mon Sep 17 00:00:00 2001 From: guillermo Date: Wed, 30 Nov 2022 12:44:33 +0100 Subject: [PATCH 54/58] refs #4550 fixed no ellipsize in agencyDescription --- .../reports/collection-label/assets/css/style.css | 10 +++++++--- print/templates/reports/collection-label/options.json | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/print/templates/reports/collection-label/assets/css/style.css b/print/templates/reports/collection-label/assets/css/style.css index f9ead378a..f92d5bf1e 100644 --- a/print/templates/reports/collection-label/assets/css/style.css +++ b/print/templates/reports/collection-label/assets/css/style.css @@ -9,14 +9,15 @@ html { } #vertical { writing-mode: vertical-rl; - height: 235px; - font-size: 30px; + height: 230px; + font-size: 29px; margin-left: -13px; } .outline { border: 1px solid black; padding: 5px; height: 37px; + width: 100px; } #nickname { font-size: 22px; @@ -24,16 +25,19 @@ html { } #agencyDescripton { font-size: 32px; + width: 375px; font-weight: bold; } #bold { font-weight: bold; } #barcode{ - width: 390px; + width: 370px; } #shipped { font-weight: bold; + width: 50px; + max-width: 100px; } #ticketFk { font-size: 32px; diff --git a/print/templates/reports/collection-label/options.json b/print/templates/reports/collection-label/options.json index ae88e6c0c..a555c5723 100644 --- a/print/templates/reports/collection-label/options.json +++ b/print/templates/reports/collection-label/options.json @@ -1,6 +1,6 @@ { "width": "10.4cm", - "height": "4.8cm", + "height": "4.9cm", "margin": { "top": "0.3cm", "right": "0.6cm", From b769845a287f25e4c67b8c268e1a20eca429b2b2 Mon Sep 17 00:00:00 2001 From: alexm Date: Wed, 30 Nov 2022 14:29:44 +0100 Subject: [PATCH 55/58] hotFix: not transfer all sales if all sales is negatives --- modules/ticket/back/methods/ticket/componentUpdate.js | 4 +++- modules/ticket/front/basic-data/step-two/index.js | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/modules/ticket/back/methods/ticket/componentUpdate.js b/modules/ticket/back/methods/ticket/componentUpdate.js index baa6a0b41..e33428bf0 100644 --- a/modules/ticket/back/methods/ticket/componentUpdate.js +++ b/modules/ticket/back/methods/ticket/componentUpdate.js @@ -137,9 +137,11 @@ module.exports = Self => { const params = [args.id, args.shipped, args.warehouseFk]; const [salesMovable] = await Self.rawSql(query, params, myOptions); + const sales = await models.Sale.find({ticketFk: args.id}, myOptions); const salesNewTicket = salesMovable.filter(sale => (sale.movable ? sale.movable : 0) >= sale.quantity); - if (salesNewTicket.length) { + const salesNewTicketLength = salesNewTicket.length; + if (salesNewTicketLength && sales.length != salesNewTicketLength) { const newTicket = await models.Ticket.transferSales(ctx, args.id, null, salesNewTicket, myOptions); args.id = newTicket.id; } diff --git a/modules/ticket/front/basic-data/step-two/index.js b/modules/ticket/front/basic-data/step-two/index.js index 32d6b2cd6..4ac9f292e 100644 --- a/modules/ticket/front/basic-data/step-two/index.js +++ b/modules/ticket/front/basic-data/step-two/index.js @@ -67,6 +67,7 @@ class Controller extends Component { ticketHaveNegatives() { let haveNegatives = false; let haveNotNegatives = false; + this.ticket.withoutNegatives = false; const haveDifferences = this.ticket.sale.haveDifferences; this.ticket.sale.items.forEach(item => { @@ -76,8 +77,9 @@ class Controller extends Component { haveNotNegatives = true; }); - this.ticket.withoutNegatives = true; this.haveNegatives = (haveNegatives && haveNotNegatives && haveDifferences); + if (this.haveNegatives) + this.ticket.withoutNegatives = true; } onSubmit() { From 67384b724d39f7c62c5b7e9c61a041a607bdafd3 Mon Sep 17 00:00:00 2001 From: Pau Navarro Date: Wed, 30 Nov 2022 14:41:03 +0100 Subject: [PATCH 56/58] refs #4875 skipped failing test --- .../invoiceOut/back/methods/invoiceOut/specs/createPdf.spec.js | 3 ++- .../back/methods/invoiceOut/specs/downloadZip.spec.js | 3 ++- .../invoiceOut/back/methods/invoiceOut/specs/filter.spec.js | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/modules/invoiceOut/back/methods/invoiceOut/specs/createPdf.spec.js b/modules/invoiceOut/back/methods/invoiceOut/specs/createPdf.spec.js index 803338ef3..6c48c7c5f 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/specs/createPdf.spec.js +++ b/modules/invoiceOut/back/methods/invoiceOut/specs/createPdf.spec.js @@ -10,7 +10,8 @@ describe('InvoiceOut createPdf()', () => { }; const ctx = {req: activeCtx}; - it('should create a new PDF file and set true the hasPdf property', async() => { + // https://redmine.verdnatura.es/issues/4875 + xit('should create a new PDF file and set true the hasPdf property', async() => { const invoiceId = 1; spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ active: activeCtx diff --git a/modules/invoiceOut/back/methods/invoiceOut/specs/downloadZip.spec.js b/modules/invoiceOut/back/methods/invoiceOut/specs/downloadZip.spec.js index 08f049783..4518528d1 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/specs/downloadZip.spec.js +++ b/modules/invoiceOut/back/methods/invoiceOut/specs/downloadZip.spec.js @@ -29,7 +29,8 @@ describe('InvoiceOut downloadZip()', () => { } }); - it('should return an error if the size of the files is too large', async() => { + // https://redmine.verdnatura.es/issues/4875 + xit('should return an error if the size of the files is too large', async() => { const tx = await models.InvoiceOut.beginTransaction({}); let error; diff --git a/modules/invoiceOut/back/methods/invoiceOut/specs/filter.spec.js b/modules/invoiceOut/back/methods/invoiceOut/specs/filter.spec.js index 02f982011..6f1b510ab 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/specs/filter.spec.js +++ b/modules/invoiceOut/back/methods/invoiceOut/specs/filter.spec.js @@ -50,7 +50,8 @@ describe('InvoiceOut filter()', () => { } }); - it('should return the invoice out matching hasPdf', async() => { + // https://redmine.verdnatura.es/issues/4875 + xit('should return the invoice out matching hasPdf', async() => { const tx = await models.InvoiceOut.beginTransaction({}); const options = {transaction: tx}; From 79f8e30ded9af8ef7c2ffc2a32454df18b50bc5a Mon Sep 17 00:00:00 2001 From: Pau Navarro Date: Wed, 30 Nov 2022 14:49:00 +0100 Subject: [PATCH 57/58] add pending to the tests --- .../back/methods/invoiceOut/specs/createPdf.spec.js | 4 ++-- .../back/methods/invoiceOut/specs/downloadZip.spec.js | 4 ++-- .../invoiceOut/back/methods/invoiceOut/specs/filter.spec.js | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/invoiceOut/back/methods/invoiceOut/specs/createPdf.spec.js b/modules/invoiceOut/back/methods/invoiceOut/specs/createPdf.spec.js index 6c48c7c5f..ee3310368 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/specs/createPdf.spec.js +++ b/modules/invoiceOut/back/methods/invoiceOut/specs/createPdf.spec.js @@ -10,8 +10,8 @@ describe('InvoiceOut createPdf()', () => { }; const ctx = {req: activeCtx}; - // https://redmine.verdnatura.es/issues/4875 - xit('should create a new PDF file and set true the hasPdf property', async() => { + it('should create a new PDF file and set true the hasPdf property', async() => { + pending('https://redmine.verdnatura.es/issues/4875'); const invoiceId = 1; spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ active: activeCtx diff --git a/modules/invoiceOut/back/methods/invoiceOut/specs/downloadZip.spec.js b/modules/invoiceOut/back/methods/invoiceOut/specs/downloadZip.spec.js index 4518528d1..536fa07a0 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/specs/downloadZip.spec.js +++ b/modules/invoiceOut/back/methods/invoiceOut/specs/downloadZip.spec.js @@ -29,8 +29,8 @@ describe('InvoiceOut downloadZip()', () => { } }); - // https://redmine.verdnatura.es/issues/4875 - xit('should return an error if the size of the files is too large', async() => { + it('should return an error if the size of the files is too large', async() => { + pending('https://redmine.verdnatura.es/issues/4875'); const tx = await models.InvoiceOut.beginTransaction({}); let error; diff --git a/modules/invoiceOut/back/methods/invoiceOut/specs/filter.spec.js b/modules/invoiceOut/back/methods/invoiceOut/specs/filter.spec.js index 6f1b510ab..7b5886236 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/specs/filter.spec.js +++ b/modules/invoiceOut/back/methods/invoiceOut/specs/filter.spec.js @@ -50,8 +50,8 @@ describe('InvoiceOut filter()', () => { } }); - // https://redmine.verdnatura.es/issues/4875 - xit('should return the invoice out matching hasPdf', async() => { + it('should return the invoice out matching hasPdf', async() => { + pending('https://redmine.verdnatura.es/issues/4875'); const tx = await models.InvoiceOut.beginTransaction({}); const options = {transaction: tx}; From ac447d4981695aeceab34cdc30c48cfe26f559b0 Mon Sep 17 00:00:00 2001 From: joan Date: Fri, 2 Dec 2022 12:48:12 +0100 Subject: [PATCH 58/58] Updated SQL version nomenclature --- db/changes/10470-family/00-accountingType.sql | 3 - db/changes/10470-family/00-aclItemType.sql | 4 - db/changes/10470-family/00-aclMdb.sql | 14 -- db/changes/10470-family/00-chat.sql | 13 -- .../10470-family/00-creditInsurance.sql | 8 -- .../10470-family/00-defaultViewConfig.sql | 3 - .../10470-family/00-ticket_doRefund.sql | 127 ------------------ .../01-creditInsuranceTriggers.sql | 11 -- db/changes/10470-family/01-tableConfig.sql | 1 - db/changes/10470-family/02-fileConfig.sql | 22 --- db/changes/10471-family/00-chat.sql | 3 - .../10472-family/00-creditInsurance.sql | 3 - db/changes/10480-june/00-ACL.sql | 21 --- db/changes/10480-june/00-aclShelvingLog.sql | 3 - .../10480-june/00-aclZoneExclusionGeos.sql | 4 - db/changes/10480-june/00-albaran_gestdoc.sql | 2 - db/changes/10480-june/00-client.sql | 3 - db/changes/10480-june/00-deprecations.sql | 13 -- db/changes/10480-june/00-item.sql | 1 - db/changes/10480-june/00-route.sql | 10 -- db/changes/10480-june/00-sample.sql | 2 - db/changes/10480-june/00-shelving.sql | 18 --- .../00-ticketRefund_beforeUpsert.sql | 21 --- db/changes/10480-june/01-claimObservation.sql | 13 -- .../10480-june/02-claimTextMigration.sql | 2 - db/changes/10480-june/04-aclParking.sql | 2 - db/changes/10480-june/04-aclShelving.sql | 2 - db/changes/10481-june/00-aclOsTicket.sql | 3 - .../10481-june/00-aclOsTicketConfig.sql | 3 - db/changes/10481-june/00-osTicketConfig.sql | 16 --- .../{10490-august => 224701}/00-ACL.sql | 0 .../00-acl_receiptPdf.sql | 0 .../00-clientConsumptionQueue.sql | 0 .../00-invoiceOutQueue.sql | 0 .../00-itemConfig.sql | 0 .../00-printConfig.sql | 0 .../00-sale_afterUpdate.sql | 0 .../{10490-august => 224701}/00-sample.sql | 0 .../00-user_hasGrant.sql | 0 .../00-ACL_workerDisableExcluded.sql | 0 .../00-aclBusiness.sql | 0 .../00-aclUsesMana.sql | 0 .../00-defaultPayDem_sameAs_production.sql | 0 .../00-invoiceInPdf.sql | 0 .../00-newSupplier_ACL.sql | 0 .../00-notificationProc.sql | 0 .../00-notificationTables.sql | 0 .../00-payMethodFk_Allow_Null.sql | 0 .../00-supplierActivityFk_Allow_Null.sql | 0 .../00-ticket_closeByTicket.sql | 0 .../{10491-august => 224702}/00-zipConfig.sql | 0 .../{10500-november => 224801}/00-ACL.sql | 0 .../{10500-november => 224801}/00-claim.sql | 0 .../00-claimRma.sql | 0 .../00-aclNotification.sql | 0 .../00-packingSiteConfig.sql | 0 .../00-packingSiteUpdate.sql | 0 .../00-salix_url.sql | 0 .../00-aclUserPassword.sql | 0 .../00-deletePickupContact.sql | 0 .../00-itemShelvingACL.sql | 0 ...00-itemShelvingPlacementSupplyStockACL.sql | 0 .../00-workerTimeControlMail.sql | 0 .../00-zone_getPostalCode.sql | 0 .../00-ACL_notification_InvoiceE.sql | 0 .../00-aclInvoiceOut.sql | 0 .../00-alter_expedition_itemFk.sql | 0 .../00-clientHasInvoiceElectronic.sql | 0 .../00-collection_missingTrash.sql | 0 .../00-deleteInvoiceOutQueue.sql | 0 .../00-editTrackedACL.sql | 0 .../{10503-november => 224903}/00-greuge.sql | 0 .../00-insert_notification_invoiceE.sql | 0 .../00-isCompensationACL.sql | 0 .../00-osTicketConfig.sql | 0 .../00-ticket_canMerge.sql | 0 .../00-ticket_canbePostponed.sql | 0 .../00-timeBusiness_calculate.sql | 0 .../01-updateClientHasInvoiceElectronic.sql | 0 .../deleteMe.keep => 225001/.gitkeep} | 0 db/dump/dumpedFixtures.sql | 2 +- db/import-changes.sh | 4 +- 82 files changed, 3 insertions(+), 354 deletions(-) delete mode 100644 db/changes/10470-family/00-accountingType.sql delete mode 100644 db/changes/10470-family/00-aclItemType.sql delete mode 100644 db/changes/10470-family/00-aclMdb.sql delete mode 100644 db/changes/10470-family/00-chat.sql delete mode 100644 db/changes/10470-family/00-creditInsurance.sql delete mode 100644 db/changes/10470-family/00-defaultViewConfig.sql delete mode 100644 db/changes/10470-family/00-ticket_doRefund.sql delete mode 100644 db/changes/10470-family/01-creditInsuranceTriggers.sql delete mode 100644 db/changes/10470-family/01-tableConfig.sql delete mode 100644 db/changes/10470-family/02-fileConfig.sql delete mode 100644 db/changes/10471-family/00-chat.sql delete mode 100644 db/changes/10472-family/00-creditInsurance.sql delete mode 100644 db/changes/10480-june/00-ACL.sql delete mode 100644 db/changes/10480-june/00-aclShelvingLog.sql delete mode 100644 db/changes/10480-june/00-aclZoneExclusionGeos.sql delete mode 100644 db/changes/10480-june/00-albaran_gestdoc.sql delete mode 100644 db/changes/10480-june/00-client.sql delete mode 100644 db/changes/10480-june/00-deprecations.sql delete mode 100644 db/changes/10480-june/00-item.sql delete mode 100644 db/changes/10480-june/00-route.sql delete mode 100644 db/changes/10480-june/00-sample.sql delete mode 100644 db/changes/10480-june/00-shelving.sql delete mode 100644 db/changes/10480-june/00-ticketRefund_beforeUpsert.sql delete mode 100644 db/changes/10480-june/01-claimObservation.sql delete mode 100644 db/changes/10480-june/02-claimTextMigration.sql delete mode 100644 db/changes/10480-june/04-aclParking.sql delete mode 100644 db/changes/10480-june/04-aclShelving.sql delete mode 100644 db/changes/10481-june/00-aclOsTicket.sql delete mode 100644 db/changes/10481-june/00-aclOsTicketConfig.sql delete mode 100644 db/changes/10481-june/00-osTicketConfig.sql rename db/changes/{10490-august => 224701}/00-ACL.sql (100%) rename db/changes/{10490-august => 224701}/00-acl_receiptPdf.sql (100%) rename db/changes/{10490-august => 224701}/00-clientConsumptionQueue.sql (100%) rename db/changes/{10490-august => 224701}/00-invoiceOutQueue.sql (100%) rename db/changes/{10490-august => 224701}/00-itemConfig.sql (100%) rename db/changes/{10490-august => 224701}/00-printConfig.sql (100%) rename db/changes/{10490-august => 224701}/00-sale_afterUpdate.sql (100%) rename db/changes/{10490-august => 224701}/00-sample.sql (100%) rename db/changes/{10490-august => 224701}/00-user_hasGrant.sql (100%) rename db/changes/{10491-august => 224702}/00-ACL_workerDisableExcluded.sql (100%) rename db/changes/{10491-august => 224702}/00-aclBusiness.sql (100%) rename db/changes/{10491-august => 224702}/00-aclUsesMana.sql (100%) rename db/changes/{10491-august => 224702}/00-defaultPayDem_sameAs_production.sql (100%) rename db/changes/{10491-august => 224702}/00-invoiceInPdf.sql (100%) rename db/changes/{10491-august => 224702}/00-newSupplier_ACL.sql (100%) rename db/changes/{10491-august => 224702}/00-notificationProc.sql (100%) rename db/changes/{10491-august => 224702}/00-notificationTables.sql (100%) rename db/changes/{10491-august => 224702}/00-payMethodFk_Allow_Null.sql (100%) rename db/changes/{10491-august => 224702}/00-supplierActivityFk_Allow_Null.sql (100%) rename db/changes/{10491-august => 224702}/00-ticket_closeByTicket.sql (100%) rename db/changes/{10491-august => 224702}/00-zipConfig.sql (100%) rename db/changes/{10500-november => 224801}/00-ACL.sql (100%) rename db/changes/{10500-november => 224801}/00-claim.sql (100%) rename db/changes/{10500-november => 224801}/00-claimRma.sql (100%) rename db/changes/{10501-november => 224901}/00-aclNotification.sql (100%) rename db/changes/{10501-november => 224901}/00-packingSiteConfig.sql (100%) rename db/changes/{10501-november => 224901}/00-packingSiteUpdate.sql (100%) rename db/changes/{10501-november => 224901}/00-salix_url.sql (100%) rename db/changes/{10502-november => 224902}/00-aclUserPassword.sql (100%) rename db/changes/{10502-november => 224902}/00-deletePickupContact.sql (100%) rename db/changes/{10502-november => 224902}/00-itemShelvingACL.sql (100%) rename db/changes/{10502-november => 224902}/00-itemShelvingPlacementSupplyStockACL.sql (100%) rename db/changes/{10502-november => 224902}/00-workerTimeControlMail.sql (100%) rename db/changes/{10502-november => 224902}/00-zone_getPostalCode.sql (100%) rename db/changes/{10503-november => 224903}/00-ACL_notification_InvoiceE.sql (100%) rename db/changes/{10503-november => 224903}/00-aclInvoiceOut.sql (100%) rename db/changes/{10503-november => 224903}/00-alter_expedition_itemFk.sql (100%) rename db/changes/{10503-november => 224903}/00-clientHasInvoiceElectronic.sql (100%) rename db/changes/{10503-november => 224903}/00-collection_missingTrash.sql (100%) rename db/changes/{10503-november => 224903}/00-deleteInvoiceOutQueue.sql (100%) rename db/changes/{10503-november => 224903}/00-editTrackedACL.sql (100%) rename db/changes/{10503-november => 224903}/00-greuge.sql (100%) rename db/changes/{10503-november => 224903}/00-insert_notification_invoiceE.sql (100%) rename db/changes/{10503-november => 224903}/00-isCompensationACL.sql (100%) rename db/changes/{10503-november => 224903}/00-osTicketConfig.sql (100%) rename db/changes/{10503-november => 224903}/00-ticket_canMerge.sql (100%) rename db/changes/{10503-november => 224903}/00-ticket_canbePostponed.sql (100%) rename db/changes/{10503-november => 224903}/00-timeBusiness_calculate.sql (100%) rename db/changes/{10503-november => 224903}/01-updateClientHasInvoiceElectronic.sql (100%) rename db/changes/{10510-december/deleteMe.keep => 225001/.gitkeep} (100%) diff --git a/db/changes/10470-family/00-accountingType.sql b/db/changes/10470-family/00-accountingType.sql deleted file mode 100644 index 964027e3a..000000000 --- a/db/changes/10470-family/00-accountingType.sql +++ /dev/null @@ -1,3 +0,0 @@ -ALTER TABLE `vn`.`accountingType` ADD daysInFuture INT NULL; -ALTER TABLE `vn`.`accountingType` MODIFY COLUMN daysInFuture int(11) DEFAULT 0 NULL; -UPDATE `vn`.`accountingType` SET daysInFuture=1 WHERE id=8; \ No newline at end of file diff --git a/db/changes/10470-family/00-aclItemType.sql b/db/changes/10470-family/00-aclItemType.sql deleted file mode 100644 index 836a69dfd..000000000 --- a/db/changes/10470-family/00-aclItemType.sql +++ /dev/null @@ -1,4 +0,0 @@ -INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) - VALUES - ('ItemType', '*', 'READ', 'ALLOW', 'ROLE', 'employee'), - ('ItemType', '*', 'WRITE', 'ALLOW', 'ROLE', 'buyer'); \ No newline at end of file diff --git a/db/changes/10470-family/00-aclMdb.sql b/db/changes/10470-family/00-aclMdb.sql deleted file mode 100644 index b02ddc451..000000000 --- a/db/changes/10470-family/00-aclMdb.sql +++ /dev/null @@ -1,14 +0,0 @@ -CREATE TABLE IF NOT EXISTS `vn`.`mdbBranch` ( - `name` VARCHAR(255), - PRIMARY KEY(`name`) -); - -CREATE TABLE IF NOT EXISTS `vn`.`mdbVersion` ( - `app` VARCHAR(255) NOT NULL, - `branchFk` VARCHAR(255) NOT NULL, - `version` INT, - CONSTRAINT `mdbVersion_branchFk` FOREIGN KEY (`branchFk`) REFERENCES `vn`.`mdbBranch` (`name`) ON DELETE CASCADE ON UPDATE CASCADE -); - -INSERT IGNORE INTO `salix`.`ACL` (`id`, `model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) - VALUES(318, 'MdbVersion', '*', '*', 'ALLOW', 'ROLE', 'developer'); diff --git a/db/changes/10470-family/00-chat.sql b/db/changes/10470-family/00-chat.sql deleted file mode 100644 index d4a8f068a..000000000 --- a/db/changes/10470-family/00-chat.sql +++ /dev/null @@ -1,13 +0,0 @@ -CREATE TABLE `vn`.`chat` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `senderFk` int(10) unsigned DEFAULT NULL, - `recipient` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL, - `dated` date DEFAULT NULL, - `checkUserStatus` tinyint(1) DEFAULT NULL, - `message` varchar(200) COLLATE utf8_unicode_ci DEFAULT NULL, - `status` tinyint(1) DEFAULT NULL, - `attempts` int(1) DEFAULT NULL, - PRIMARY KEY (`id`), - KEY `chat_FK` (`senderFk`), - CONSTRAINT `chat_FK` FOREIGN KEY (`senderFk`) REFERENCES `account`.`user` (`id`) ON UPDATE CASCADE -) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; \ No newline at end of file diff --git a/db/changes/10470-family/00-creditInsurance.sql b/db/changes/10470-family/00-creditInsurance.sql deleted file mode 100644 index 9d4db470b..000000000 --- a/db/changes/10470-family/00-creditInsurance.sql +++ /dev/null @@ -1,8 +0,0 @@ -ALTER TABLE `vn`.`creditInsurance` ADD creditClassificationFk int(11) NULL; - -UPDATE `vn`.`creditInsurance` AS `destiny` - SET `destiny`.`creditClassificationFk`= (SELECT creditClassification FROM `vn`.`creditInsurance` AS `origin` WHERE `origin`.id = `destiny`.id); - -ALTER TABLE `vn`.`creditInsurance` - ADD CONSTRAINT `creditInsurance_creditClassificationFk` FOREIGN KEY (`creditClassificationFk`) - REFERENCES `vn`.`creditClassification` (`id`) ON DELETE CASCADE ON UPDATE CASCADE; \ No newline at end of file diff --git a/db/changes/10470-family/00-defaultViewConfig.sql b/db/changes/10470-family/00-defaultViewConfig.sql deleted file mode 100644 index d423599b1..000000000 --- a/db/changes/10470-family/00-defaultViewConfig.sql +++ /dev/null @@ -1,3 +0,0 @@ -INSERT INTO `salix`.`defaultViewConfig` (tableCode, columns) -VALUES ('clientsDetail', '{"id":true,"phone":true,"city":true,"socialName":true,"salesPersonFk":true,"email":true,"name":false,"fi":false,"credit":false,"creditInsurance":false,"mobile":false,"street":false,"countryFk":false,"provinceFk":false,"postcode":false,"created":false,"businessTypeFk":false,"payMethodFk":false,"sageTaxTypeFk":false,"sageTransactionTypeFk":false,"isActive":false,"isVies":false,"isTaxDataChecked":false,"isEqualizated":false,"isFreezed":false,"hasToInvoice":false,"hasToInvoiceByAddress":false,"isToBeMailed":false,"hasLcr":false,"hasCoreVnl":false,"hasSepaVnl":false}'); - diff --git a/db/changes/10470-family/00-ticket_doRefund.sql b/db/changes/10470-family/00-ticket_doRefund.sql deleted file mode 100644 index f4ecf29d7..000000000 --- a/db/changes/10470-family/00-ticket_doRefund.sql +++ /dev/null @@ -1,127 +0,0 @@ -DROP PROCEDURE IF EXISTS `vn`.`ticket_doRefund`; - -DELIMITER $$ -$$ -CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticket_doRefund`(OUT vNewTicket INT) -BEGIN -/** - * Crea un ticket de abono a partir de tmp.sale y/o tmp.ticketService - * - * @return vNewTicket - */ - DECLARE vDone BIT DEFAULT 0; - DECLARE vClientFk MEDIUMINT; - DECLARE vWarehouse TINYINT; - DECLARE vCompany MEDIUMINT; - DECLARE vAddress MEDIUMINT; - DECLARE vRefundAgencyMode INT; - DECLARE vItemFk INT; - DECLARE vQuantity DECIMAL (10,2); - DECLARE vConcept VARCHAR(50); - DECLARE vPrice DECIMAL (10,2); - DECLARE vDiscount TINYINT; - DECLARE vSaleNew INT; - DECLARE vSaleMain INT; - DECLARE vZoneFk INT; - DECLARE vDescription VARCHAR(50); - DECLARE vTaxClassFk INT; - DECLARE vTicketServiceTypeFk INT; - DECLARE vOriginTicket INT; - - DECLARE cSales CURSOR FOR - SELECT s.id, s.itemFk, - s.quantity, s.concept, s.price, s.discount - FROM tmp.sale s; - - DECLARE cTicketServices CURSOR FOR - SELECT ts.description, - ts.quantity, ts.price, ts.taxClassFk, ts.ticketServiceTypeFk - FROM tmp.ticketService ts; - - DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE; - - SELECT sub.ticketFk INTO vOriginTicket - FROM ( - SELECT s.ticketFk - FROM tmp.sale s - UNION ALL - SELECT ts.ticketFk - FROM tmp.ticketService ts - ) sub - LIMIT 1; - - SELECT id INTO vRefundAgencyMode - FROM agencyMode WHERE `name` = 'ABONO'; - - SELECT clientFk, warehouseFk, companyFk, addressFk - INTO vClientFk, vWarehouse, vCompany, vAddress - FROM ticket - WHERE id = vOriginTicket; - - SELECT id INTO vZoneFk - FROM zone WHERE agencyModeFk = vRefundAgencyMode - LIMIT 1; - - INSERT INTO vn.ticket ( - clientFk, - shipped, - addressFk, - agencyModeFk, - nickname, - warehouseFk, - companyFk, - landed, - zoneFk - ) - SELECT - vClientFk, - CURDATE(), - vAddress, - vRefundAgencyMode, - a.nickname, - vWarehouse, - vCompany, - CURDATE(), - vZoneFk - FROM address a - WHERE a.id = vAddress; - - SET vNewTicket = LAST_INSERT_ID(); - - SET vDone := FALSE; - OPEN cSales; - FETCH cSales INTO vSaleMain, vItemFk, vQuantity, vConcept, vPrice, vDiscount; - - WHILE NOT vDone DO - - INSERT INTO vn.sale(ticketFk, itemFk, quantity, concept, price, discount) - VALUES( vNewTicket, vItemFk, vQuantity, vConcept, vPrice, vDiscount ); - - SET vSaleNew = LAST_INSERT_ID(); - - INSERT INTO vn.saleComponent(saleFk,componentFk,`value`) - SELECT vSaleNew,componentFk,`value` - FROM vn.saleComponent - WHERE saleFk = vSaleMain; - - FETCH cSales INTO vSaleMain, vItemFk, vQuantity, vConcept, vPrice, vDiscount; - - END WHILE; - CLOSE cSales; - - SET vDone := FALSE; - OPEN cTicketServices; - FETCH cTicketServices INTO vDescription, vQuantity, vPrice, vTaxClassFk, vTicketServiceTypeFk; - - WHILE NOT vDone DO - - INSERT INTO vn.ticketService(description, quantity, price, taxClassFk, ticketFk, ticketServiceTypeFk) - VALUES(vDescription, vQuantity, vPrice, vTaxClassFk, vNewTicket, vTicketServiceTypeFk); - - FETCH cTicketServices INTO vDescription, vQuantity, vPrice, vTaxClassFk, vTicketServiceTypeFk; - - END WHILE; - CLOSE cTicketServices; - - INSERT INTO vn.ticketRefund(refundTicketFk, originalTicketFk) - VALUES(vNewTicket, vOriginTicket); -END$$ -DELIMITER ; diff --git a/db/changes/10470-family/01-creditInsuranceTriggers.sql b/db/changes/10470-family/01-creditInsuranceTriggers.sql deleted file mode 100644 index 53ba3ba11..000000000 --- a/db/changes/10470-family/01-creditInsuranceTriggers.sql +++ /dev/null @@ -1,11 +0,0 @@ -DELIMITER $$ -$$ -CREATE DEFINER=`root`@`localhost` TRIGGER `vn`.`creditInsurance_beforeInsert` - BEFORE INSERT ON `creditInsurance` - FOR EACH ROW -BEGIN - IF NEW.creditClassificationFk THEN - SET NEW.creditClassification = NEW.creditClassificationFk; - END IF; -END$$ -DELIMITER ; \ No newline at end of file diff --git a/db/changes/10470-family/01-tableConfig.sql b/db/changes/10470-family/01-tableConfig.sql deleted file mode 100644 index 685981d90..000000000 --- a/db/changes/10470-family/01-tableConfig.sql +++ /dev/null @@ -1 +0,0 @@ -RENAME TABLE `edi`.`fileConfig` to `edi`.`tableConfig`; \ No newline at end of file diff --git a/db/changes/10470-family/02-fileConfig.sql b/db/changes/10470-family/02-fileConfig.sql deleted file mode 100644 index 3109a4616..000000000 --- a/db/changes/10470-family/02-fileConfig.sql +++ /dev/null @@ -1,22 +0,0 @@ -CREATE TABLE `edi`.`fileConfig` -( - name varchar(25) NOT NULL, - checksum text NULL, - keyValue tinyint(1) default true NOT NULL, - constraint fileConfig_pk - primary key (name) -); - -create unique index fileConfig_name_uindex - on `edi`.`fileConfig` (name); - - -INSERT INTO `edi`.`fileConfig` (name, checksum, keyValue) -VALUES ('FEC010104', null, 0); - -INSERT INTO `edi`.`fileConfig` (name, checksum, keyValue) -VALUES ('VBN020101', null, 1); - -INSERT INTO `edi`.`fileConfig` (name, checksum, keyValue) -VALUES ('florecompc2', null, 1); - diff --git a/db/changes/10471-family/00-chat.sql b/db/changes/10471-family/00-chat.sql deleted file mode 100644 index 6f3c9d437..000000000 --- a/db/changes/10471-family/00-chat.sql +++ /dev/null @@ -1,3 +0,0 @@ -ALTER TABLE `vn`.`chat` MODIFY COLUMN message TEXT CHARACTER SET utf8mb3 COLLATE utf8mb3_unicode_ci DEFAULT NULL NULL; -ALTER TABLE `vn`.`chat` MODIFY COLUMN dated DATETIME DEFAULT NULL NULL; -ALTER TABLE `vn`.`chat` ADD error TEXT NULL; diff --git a/db/changes/10472-family/00-creditInsurance.sql b/db/changes/10472-family/00-creditInsurance.sql deleted file mode 100644 index 4731cfb2a..000000000 --- a/db/changes/10472-family/00-creditInsurance.sql +++ /dev/null @@ -1,3 +0,0 @@ -ALTER TABLE `vn`.`creditInsurance` - ADD CONSTRAINT `creditInsurance_creditClassificationFk` FOREIGN KEY (`creditClassificationFk`) - REFERENCES `vn`.`creditClassification` (`id`) ON DELETE CASCADE ON UPDATE CASCADE; \ No newline at end of file diff --git a/db/changes/10480-june/00-ACL.sql b/db/changes/10480-june/00-ACL.sql deleted file mode 100644 index b13e56e21..000000000 --- a/db/changes/10480-june/00-ACL.sql +++ /dev/null @@ -1,21 +0,0 @@ -INSERT INTO `salix`.`ACL` (model,property,accessType,permission,principalType,principalId) - VALUES - ('InvoiceOut','refund','WRITE','ALLOW','ROLE','invoicing'), - ('InvoiceOut','refund','WRITE','ALLOW','ROLE','salesAssistant'), - ('InvoiceOut','refund','WRITE','ALLOW','ROLE','claimManager'), - ('Ticket','refund','WRITE','ALLOW','ROLE','invoicing'), - ('Ticket','refund','WRITE','ALLOW','ROLE','salesAssistant'), - ('Ticket','refund','WRITE','ALLOW','ROLE','claimManager'), - ('Sale','refund','WRITE','ALLOW','ROLE','salesAssistant'), - ('Sale','refund','WRITE','ALLOW','ROLE','claimManager'), - ('TicketRefund','*','WRITE','ALLOW','ROLE','invoicing'), - ('ClaimObservation','*','WRITE','ALLOW','ROLE','salesPerson'), - ('ClaimObservation','*','READ','ALLOW','ROLE','salesPerson'), - ('Client','setPassword','WRITE','ALLOW','ROLE','salesPerson'), - ('Client','updateUser','WRITE','ALLOW','ROLE','salesPerson'); - -DELETE FROM `salix`.`ACL` WHERE id=313; - -UPDATE `salix`.`ACL` - SET principalId='invoicing' - WHERE id=297; \ No newline at end of file diff --git a/db/changes/10480-june/00-aclShelvingLog.sql b/db/changes/10480-june/00-aclShelvingLog.sql deleted file mode 100644 index dc75142d1..000000000 --- a/db/changes/10480-june/00-aclShelvingLog.sql +++ /dev/null @@ -1,3 +0,0 @@ -INSERT INTO `salix`.`ACL` (model,property,accessType,permission,principalType,principalId) - VALUES - ('ShelvingLog','*','READ','ALLOW','ROLE','employee'); \ No newline at end of file diff --git a/db/changes/10480-june/00-aclZoneExclusionGeos.sql b/db/changes/10480-june/00-aclZoneExclusionGeos.sql deleted file mode 100644 index 4c0f6c991..000000000 --- a/db/changes/10480-june/00-aclZoneExclusionGeos.sql +++ /dev/null @@ -1,4 +0,0 @@ -INSERT INTO `salix`.`ACL`(`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) - VALUES - ('ZoneExclusionGeo', '*', 'READ', 'ALLOW', 'ROLE', 'employee'), - ('ZoneExclusionGeo', '*', 'WRITE', 'ALLOW', 'ROLE', 'deliveryBoss'); \ No newline at end of file diff --git a/db/changes/10480-june/00-albaran_gestdoc.sql b/db/changes/10480-june/00-albaran_gestdoc.sql deleted file mode 100644 index a0ba93bd3..000000000 --- a/db/changes/10480-june/00-albaran_gestdoc.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE `vn2008`.`albaran_gestdoc` DROP FOREIGN KEY fk_albaran_gestdoc_gestdoc1; -ALTER TABLE `vn2008`.`albaran_gestdoc` ADD CONSTRAINT albaran_gestdoc_FK FOREIGN KEY (gestdoc_id) REFERENCES `vn`.`dms`(id) ON DELETE CASCADE ON UPDATE CASCADE; \ No newline at end of file diff --git a/db/changes/10480-june/00-client.sql b/db/changes/10480-june/00-client.sql deleted file mode 100644 index 4a39bbdf9..000000000 --- a/db/changes/10480-june/00-client.sql +++ /dev/null @@ -1,3 +0,0 @@ -alter table `vn`.`client` - add hasIncoterms tinyint(1) default 0 not null comment 'Received incoterms authorization from client'; - diff --git a/db/changes/10480-june/00-deprecations.sql b/db/changes/10480-june/00-deprecations.sql deleted file mode 100644 index 68becd13e..000000000 --- a/db/changes/10480-june/00-deprecations.sql +++ /dev/null @@ -1,13 +0,0 @@ -DROP FUNCTION `account`.`userGetId`; -DROP FUNCTION `account`.`myUserGetName`; -DROP FUNCTION `account`.`myUserGetId`; -DROP FUNCTION `account`.`myUserHasRole`; -DROP FUNCTION `account`.`myUserHasRoleId`; -DROP FUNCTION `account`.`userGetName`; -DROP FUNCTION `account`.`userHasRole`; -DROP FUNCTION `account`.`userHasRoleId`; -DROP PROCEDURE `account`.`myUserLogout`; -DROP PROCEDURE `account`.`userLogin`; -DROP PROCEDURE `account`.`userLoginWithKey`; -DROP PROCEDURE `account`.`userLoginWithName`; -DROP PROCEDURE `account`.`userSetPassword`; \ No newline at end of file diff --git a/db/changes/10480-june/00-item.sql b/db/changes/10480-june/00-item.sql deleted file mode 100644 index a08d3f4c1..000000000 --- a/db/changes/10480-june/00-item.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE `vn`.`item` MODIFY COLUMN description TEXT CHARACTER SET utf8mb3 COLLATE utf8mb3_unicode_ci DEFAULT NULL NULL; diff --git a/db/changes/10480-june/00-route.sql b/db/changes/10480-june/00-route.sql deleted file mode 100644 index beb7d5e41..000000000 --- a/db/changes/10480-june/00-route.sql +++ /dev/null @@ -1,10 +0,0 @@ -UPDATE `vn`.`route` r - JOIN(SELECT r.id, wl.workcenterFk - FROM `vn`.`route` r - JOIN `vn`.`routeLog` rl ON rl.originFk = r.id - JOIN `vn`.`workerLabour` wl ON wl.workerFk = rl.userFk - AND r.created BETWEEN wl.started AND IFNULL(wl.ended, r.created) - WHERE r.created BETWEEN '2021-12-01' AND CURDATE() - AND rl.action = 'insert' - )sub ON sub.id = r.id - SET r.commissionWorkCenterFk = sub.workcenterFk; \ No newline at end of file diff --git a/db/changes/10480-june/00-sample.sql b/db/changes/10480-june/00-sample.sql deleted file mode 100644 index 18beb736d..000000000 --- a/db/changes/10480-june/00-sample.sql +++ /dev/null @@ -1,2 +0,0 @@ -INSERT INTO `vn`.`sample` (code, description, isVisible, hasCompany, hasPreview, datepickerEnabled) -VALUES ('incoterms-authorization', 'Autorización de incoterms', 1, 1, 1, 0); \ No newline at end of file diff --git a/db/changes/10480-june/00-shelving.sql b/db/changes/10480-june/00-shelving.sql deleted file mode 100644 index c66d164c4..000000000 --- a/db/changes/10480-june/00-shelving.sql +++ /dev/null @@ -1,18 +0,0 @@ -ALTER TABLE `vn`.`itemShelving` DROP FOREIGN KEY itemShelving_fk2; -ALTER TABLE `vn`.`shelvingLog` DROP FOREIGN KEY shelvingLog_FK_ibfk_1; -ALTER TABLE `vn`.`smartTag` DROP FOREIGN KEY smartTag_shelving_fk; -ALTER TABLE `vn`.`workerShelving` DROP FOREIGN KEY workerShelving_shelving_fk; - -ALTER TABLE `vn`.`shelving` DROP PRIMARY KEY; -ALTER TABLE `vn`.`shelving` ADD id INT auto_increment PRIMARY KEY NULL; -ALTER TABLE `vn`.`shelving` CHANGE id id int(11) auto_increment NOT NULL FIRST; -ALTER TABLE `vn`.`shelving` ADD CONSTRAINT shelving_UN UNIQUE KEY (code); - -ALTER TABLE `vn`.`itemShelving` ADD CONSTRAINT itemShelving_fk2 FOREIGN KEY (shelvingFk) REFERENCES `vn`.`shelving`(code) ON DELETE CASCADE ON UPDATE CASCADE; -ALTER TABLE `vn`.`shelvingLog` ADD CONSTRAINT shelvingLog_FK_ibfk_1 FOREIGN KEY (originFk) REFERENCES `vn`.`shelving`(code) ON DELETE CASCADE ON UPDATE CASCADE; -ALTER TABLE `vn`.`smartTag` ADD CONSTRAINT smartTag_FK FOREIGN KEY (shelvingFk) REFERENCES `vn`.`shelving`(code) ON DELETE RESTRICT ON UPDATE CASCADE; -ALTER TABLE `vn`.`workerShelving` ADD CONSTRAINT workerShelving_FK_1 FOREIGN KEY (shelvingFk) REFERENCES `vn`.`shelving`(code) ON DELETE RESTRICT ON UPDATE CASCADE; - -ALTER TABLE vn.shelvingLog DROP FOREIGN KEY shelvingLog_FK_ibfk_1; -ALTER TABLE vn.shelvingLog MODIFY COLUMN originFk INT NOT NULL; -ALTER TABLE vn.shelvingLog ADD CONSTRAINT shelvingLog_FK FOREIGN KEY (originFk) REFERENCES vn.shelving(id) ON DELETE CASCADE ON UPDATE CASCADE; \ No newline at end of file diff --git a/db/changes/10480-june/00-ticketRefund_beforeUpsert.sql b/db/changes/10480-june/00-ticketRefund_beforeUpsert.sql deleted file mode 100644 index e6506c5d7..000000000 --- a/db/changes/10480-june/00-ticketRefund_beforeUpsert.sql +++ /dev/null @@ -1,21 +0,0 @@ -DROP PROCEDURE IF EXISTS `vn`.`ticketRefund_beforeUpsert`; - -DELIMITER $$ -$$ -CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticketRefund_beforeUpsert`(vRefundTicketFk INT, vOriginalTicketFk INT) -BEGIN - DECLARE vAlreadyExists BOOLEAN DEFAULT FALSE; - - IF vRefundTicketFk = vOriginalTicketFk THEN - CALL util.throw('Original ticket and refund ticket has same id'); - END IF; - - SELECT COUNT(*) INTO vAlreadyExists - FROM ticketRefund - WHERE originalTicketFk = vOriginalTicketFk; - - IF vAlreadyExists > 0 THEN - CALL util.throw('This ticket is already a refund'); - END IF; -END$$ -DELIMITER ; diff --git a/db/changes/10480-june/01-claimObservation.sql b/db/changes/10480-june/01-claimObservation.sql deleted file mode 100644 index 8dc126a9e..000000000 --- a/db/changes/10480-june/01-claimObservation.sql +++ /dev/null @@ -1,13 +0,0 @@ -CREATE TABLE `vn`.`claimObservation` ( - `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT, - `claimFk` int(10) unsigned NOT NULL, - `workerFk` int(10) unsigned DEFAULT NULL, - `text` text COLLATE utf8_unicode_ci NOT NULL, - `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - PRIMARY KEY (`id`), - KEY `worker_key` (`workerFk`), - KEY `claim_key` (`claimFk`), - KEY `claimObservation_created_IDX` (`created`) USING BTREE, - CONSTRAINT `claimObservation_ibfk_1` FOREIGN KEY (`claimFk`) REFERENCES `vn`.`claim` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, - CONSTRAINT `claimObservation_ibfk_2` FOREIGN KEY (`workerFk`) REFERENCES `vn`.`worker` (`id`) ON UPDATE CASCADE -) COMMENT='Todas las observaciones referentes a una reclamación' \ No newline at end of file diff --git a/db/changes/10480-june/02-claimTextMigration.sql b/db/changes/10480-june/02-claimTextMigration.sql deleted file mode 100644 index fa5f6fe83..000000000 --- a/db/changes/10480-june/02-claimTextMigration.sql +++ /dev/null @@ -1,2 +0,0 @@ -INSERT INTO `vn`.`claimObservation` (`claimFk`, `text`, `created`) -SELECT `id`, `observation`, `created` FROM `vn`.`claim` \ No newline at end of file diff --git a/db/changes/10480-june/04-aclParking.sql b/db/changes/10480-june/04-aclParking.sql deleted file mode 100644 index 05acd68b1..000000000 --- a/db/changes/10480-june/04-aclParking.sql +++ /dev/null @@ -1,2 +0,0 @@ -INSERT INTO `salix`.`ACL` (model,property,accessType,permission,principalType,principalId) - VALUES ('Parking','*','*','ALLOW','ROLE','employee') \ No newline at end of file diff --git a/db/changes/10480-june/04-aclShelving.sql b/db/changes/10480-june/04-aclShelving.sql deleted file mode 100644 index b237dfe0d..000000000 --- a/db/changes/10480-june/04-aclShelving.sql +++ /dev/null @@ -1,2 +0,0 @@ -INSERT INTO `salix`.`ACL` (model,property,accessType,permission,principalType,principalId) - VALUES ('Shelving','*','*','ALLOW','ROLE','employee') \ No newline at end of file diff --git a/db/changes/10481-june/00-aclOsTicket.sql b/db/changes/10481-june/00-aclOsTicket.sql deleted file mode 100644 index ae2a121f5..000000000 --- a/db/changes/10481-june/00-aclOsTicket.sql +++ /dev/null @@ -1,3 +0,0 @@ -INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) - VALUES - ('OsTicket', '*', '*', 'ALLOW', 'ROLE', 'employee'); \ No newline at end of file diff --git a/db/changes/10481-june/00-aclOsTicketConfig.sql b/db/changes/10481-june/00-aclOsTicketConfig.sql deleted file mode 100644 index ad53ea6ae..000000000 --- a/db/changes/10481-june/00-aclOsTicketConfig.sql +++ /dev/null @@ -1,3 +0,0 @@ -INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) - VALUES - ('OsTicketConfig', '*', '*', 'ALLOW', 'ROLE', 'it'); \ No newline at end of file diff --git a/db/changes/10481-june/00-osTicketConfig.sql b/db/changes/10481-june/00-osTicketConfig.sql deleted file mode 100644 index 8727c816d..000000000 --- a/db/changes/10481-june/00-osTicketConfig.sql +++ /dev/null @@ -1,16 +0,0 @@ -CREATE TABLE `vn`.`osTicketConfig` ( - `id` int(11) NOT NULL, - `host` varchar(100) COLLATE utf8mb3_unicode_ci DEFAULT NULL, - `user` varchar(100) COLLATE utf8mb3_unicode_ci DEFAULT NULL, - `password` varchar(100) COLLATE utf8mb3_unicode_ci DEFAULT NULL, - `oldStatus` varchar(100) COLLATE utf8mb3_unicode_ci DEFAULT NULL, - `newStatusId` int(11) DEFAULT NULL, - `action` varchar(100) COLLATE utf8mb3_unicode_ci DEFAULT NULL, - `day` int(11) DEFAULT NULL, - `comment` varchar(100) COLLATE utf8mb3_unicode_ci DEFAULT NULL, - `hostDb` varchar(100) COLLATE utf8mb3_unicode_ci DEFAULT NULL, - `userDb` varchar(100) COLLATE utf8mb3_unicode_ci DEFAULT NULL, - `passwordDb` varchar(100) COLLATE utf8mb3_unicode_ci DEFAULT NULL, - `portDb` int(11) DEFAULT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci; \ No newline at end of file diff --git a/db/changes/10490-august/00-ACL.sql b/db/changes/224701/00-ACL.sql similarity index 100% rename from db/changes/10490-august/00-ACL.sql rename to db/changes/224701/00-ACL.sql diff --git a/db/changes/10490-august/00-acl_receiptPdf.sql b/db/changes/224701/00-acl_receiptPdf.sql similarity index 100% rename from db/changes/10490-august/00-acl_receiptPdf.sql rename to db/changes/224701/00-acl_receiptPdf.sql diff --git a/db/changes/10490-august/00-clientConsumptionQueue.sql b/db/changes/224701/00-clientConsumptionQueue.sql similarity index 100% rename from db/changes/10490-august/00-clientConsumptionQueue.sql rename to db/changes/224701/00-clientConsumptionQueue.sql diff --git a/db/changes/10490-august/00-invoiceOutQueue.sql b/db/changes/224701/00-invoiceOutQueue.sql similarity index 100% rename from db/changes/10490-august/00-invoiceOutQueue.sql rename to db/changes/224701/00-invoiceOutQueue.sql diff --git a/db/changes/10490-august/00-itemConfig.sql b/db/changes/224701/00-itemConfig.sql similarity index 100% rename from db/changes/10490-august/00-itemConfig.sql rename to db/changes/224701/00-itemConfig.sql diff --git a/db/changes/10490-august/00-printConfig.sql b/db/changes/224701/00-printConfig.sql similarity index 100% rename from db/changes/10490-august/00-printConfig.sql rename to db/changes/224701/00-printConfig.sql diff --git a/db/changes/10490-august/00-sale_afterUpdate.sql b/db/changes/224701/00-sale_afterUpdate.sql similarity index 100% rename from db/changes/10490-august/00-sale_afterUpdate.sql rename to db/changes/224701/00-sale_afterUpdate.sql diff --git a/db/changes/10490-august/00-sample.sql b/db/changes/224701/00-sample.sql similarity index 100% rename from db/changes/10490-august/00-sample.sql rename to db/changes/224701/00-sample.sql diff --git a/db/changes/10490-august/00-user_hasGrant.sql b/db/changes/224701/00-user_hasGrant.sql similarity index 100% rename from db/changes/10490-august/00-user_hasGrant.sql rename to db/changes/224701/00-user_hasGrant.sql diff --git a/db/changes/10491-august/00-ACL_workerDisableExcluded.sql b/db/changes/224702/00-ACL_workerDisableExcluded.sql similarity index 100% rename from db/changes/10491-august/00-ACL_workerDisableExcluded.sql rename to db/changes/224702/00-ACL_workerDisableExcluded.sql diff --git a/db/changes/10491-august/00-aclBusiness.sql b/db/changes/224702/00-aclBusiness.sql similarity index 100% rename from db/changes/10491-august/00-aclBusiness.sql rename to db/changes/224702/00-aclBusiness.sql diff --git a/db/changes/10491-august/00-aclUsesMana.sql b/db/changes/224702/00-aclUsesMana.sql similarity index 100% rename from db/changes/10491-august/00-aclUsesMana.sql rename to db/changes/224702/00-aclUsesMana.sql diff --git a/db/changes/10491-august/00-defaultPayDem_sameAs_production.sql b/db/changes/224702/00-defaultPayDem_sameAs_production.sql similarity index 100% rename from db/changes/10491-august/00-defaultPayDem_sameAs_production.sql rename to db/changes/224702/00-defaultPayDem_sameAs_production.sql diff --git a/db/changes/10491-august/00-invoiceInPdf.sql b/db/changes/224702/00-invoiceInPdf.sql similarity index 100% rename from db/changes/10491-august/00-invoiceInPdf.sql rename to db/changes/224702/00-invoiceInPdf.sql diff --git a/db/changes/10491-august/00-newSupplier_ACL.sql b/db/changes/224702/00-newSupplier_ACL.sql similarity index 100% rename from db/changes/10491-august/00-newSupplier_ACL.sql rename to db/changes/224702/00-newSupplier_ACL.sql diff --git a/db/changes/10491-august/00-notificationProc.sql b/db/changes/224702/00-notificationProc.sql similarity index 100% rename from db/changes/10491-august/00-notificationProc.sql rename to db/changes/224702/00-notificationProc.sql diff --git a/db/changes/10491-august/00-notificationTables.sql b/db/changes/224702/00-notificationTables.sql similarity index 100% rename from db/changes/10491-august/00-notificationTables.sql rename to db/changes/224702/00-notificationTables.sql diff --git a/db/changes/10491-august/00-payMethodFk_Allow_Null.sql b/db/changes/224702/00-payMethodFk_Allow_Null.sql similarity index 100% rename from db/changes/10491-august/00-payMethodFk_Allow_Null.sql rename to db/changes/224702/00-payMethodFk_Allow_Null.sql diff --git a/db/changes/10491-august/00-supplierActivityFk_Allow_Null.sql b/db/changes/224702/00-supplierActivityFk_Allow_Null.sql similarity index 100% rename from db/changes/10491-august/00-supplierActivityFk_Allow_Null.sql rename to db/changes/224702/00-supplierActivityFk_Allow_Null.sql diff --git a/db/changes/10491-august/00-ticket_closeByTicket.sql b/db/changes/224702/00-ticket_closeByTicket.sql similarity index 100% rename from db/changes/10491-august/00-ticket_closeByTicket.sql rename to db/changes/224702/00-ticket_closeByTicket.sql diff --git a/db/changes/10491-august/00-zipConfig.sql b/db/changes/224702/00-zipConfig.sql similarity index 100% rename from db/changes/10491-august/00-zipConfig.sql rename to db/changes/224702/00-zipConfig.sql diff --git a/db/changes/10500-november/00-ACL.sql b/db/changes/224801/00-ACL.sql similarity index 100% rename from db/changes/10500-november/00-ACL.sql rename to db/changes/224801/00-ACL.sql diff --git a/db/changes/10500-november/00-claim.sql b/db/changes/224801/00-claim.sql similarity index 100% rename from db/changes/10500-november/00-claim.sql rename to db/changes/224801/00-claim.sql diff --git a/db/changes/10500-november/00-claimRma.sql b/db/changes/224801/00-claimRma.sql similarity index 100% rename from db/changes/10500-november/00-claimRma.sql rename to db/changes/224801/00-claimRma.sql diff --git a/db/changes/10501-november/00-aclNotification.sql b/db/changes/224901/00-aclNotification.sql similarity index 100% rename from db/changes/10501-november/00-aclNotification.sql rename to db/changes/224901/00-aclNotification.sql diff --git a/db/changes/10501-november/00-packingSiteConfig.sql b/db/changes/224901/00-packingSiteConfig.sql similarity index 100% rename from db/changes/10501-november/00-packingSiteConfig.sql rename to db/changes/224901/00-packingSiteConfig.sql diff --git a/db/changes/10501-november/00-packingSiteUpdate.sql b/db/changes/224901/00-packingSiteUpdate.sql similarity index 100% rename from db/changes/10501-november/00-packingSiteUpdate.sql rename to db/changes/224901/00-packingSiteUpdate.sql diff --git a/db/changes/10501-november/00-salix_url.sql b/db/changes/224901/00-salix_url.sql similarity index 100% rename from db/changes/10501-november/00-salix_url.sql rename to db/changes/224901/00-salix_url.sql diff --git a/db/changes/10502-november/00-aclUserPassword.sql b/db/changes/224902/00-aclUserPassword.sql similarity index 100% rename from db/changes/10502-november/00-aclUserPassword.sql rename to db/changes/224902/00-aclUserPassword.sql diff --git a/db/changes/10502-november/00-deletePickupContact.sql b/db/changes/224902/00-deletePickupContact.sql similarity index 100% rename from db/changes/10502-november/00-deletePickupContact.sql rename to db/changes/224902/00-deletePickupContact.sql diff --git a/db/changes/10502-november/00-itemShelvingACL.sql b/db/changes/224902/00-itemShelvingACL.sql similarity index 100% rename from db/changes/10502-november/00-itemShelvingACL.sql rename to db/changes/224902/00-itemShelvingACL.sql diff --git a/db/changes/10502-november/00-itemShelvingPlacementSupplyStockACL.sql b/db/changes/224902/00-itemShelvingPlacementSupplyStockACL.sql similarity index 100% rename from db/changes/10502-november/00-itemShelvingPlacementSupplyStockACL.sql rename to db/changes/224902/00-itemShelvingPlacementSupplyStockACL.sql diff --git a/db/changes/10502-november/00-workerTimeControlMail.sql b/db/changes/224902/00-workerTimeControlMail.sql similarity index 100% rename from db/changes/10502-november/00-workerTimeControlMail.sql rename to db/changes/224902/00-workerTimeControlMail.sql diff --git a/db/changes/10502-november/00-zone_getPostalCode.sql b/db/changes/224902/00-zone_getPostalCode.sql similarity index 100% rename from db/changes/10502-november/00-zone_getPostalCode.sql rename to db/changes/224902/00-zone_getPostalCode.sql diff --git a/db/changes/10503-november/00-ACL_notification_InvoiceE.sql b/db/changes/224903/00-ACL_notification_InvoiceE.sql similarity index 100% rename from db/changes/10503-november/00-ACL_notification_InvoiceE.sql rename to db/changes/224903/00-ACL_notification_InvoiceE.sql diff --git a/db/changes/10503-november/00-aclInvoiceOut.sql b/db/changes/224903/00-aclInvoiceOut.sql similarity index 100% rename from db/changes/10503-november/00-aclInvoiceOut.sql rename to db/changes/224903/00-aclInvoiceOut.sql diff --git a/db/changes/10503-november/00-alter_expedition_itemFk.sql b/db/changes/224903/00-alter_expedition_itemFk.sql similarity index 100% rename from db/changes/10503-november/00-alter_expedition_itemFk.sql rename to db/changes/224903/00-alter_expedition_itemFk.sql diff --git a/db/changes/10503-november/00-clientHasInvoiceElectronic.sql b/db/changes/224903/00-clientHasInvoiceElectronic.sql similarity index 100% rename from db/changes/10503-november/00-clientHasInvoiceElectronic.sql rename to db/changes/224903/00-clientHasInvoiceElectronic.sql diff --git a/db/changes/10503-november/00-collection_missingTrash.sql b/db/changes/224903/00-collection_missingTrash.sql similarity index 100% rename from db/changes/10503-november/00-collection_missingTrash.sql rename to db/changes/224903/00-collection_missingTrash.sql diff --git a/db/changes/10503-november/00-deleteInvoiceOutQueue.sql b/db/changes/224903/00-deleteInvoiceOutQueue.sql similarity index 100% rename from db/changes/10503-november/00-deleteInvoiceOutQueue.sql rename to db/changes/224903/00-deleteInvoiceOutQueue.sql diff --git a/db/changes/10503-november/00-editTrackedACL.sql b/db/changes/224903/00-editTrackedACL.sql similarity index 100% rename from db/changes/10503-november/00-editTrackedACL.sql rename to db/changes/224903/00-editTrackedACL.sql diff --git a/db/changes/10503-november/00-greuge.sql b/db/changes/224903/00-greuge.sql similarity index 100% rename from db/changes/10503-november/00-greuge.sql rename to db/changes/224903/00-greuge.sql diff --git a/db/changes/10503-november/00-insert_notification_invoiceE.sql b/db/changes/224903/00-insert_notification_invoiceE.sql similarity index 100% rename from db/changes/10503-november/00-insert_notification_invoiceE.sql rename to db/changes/224903/00-insert_notification_invoiceE.sql diff --git a/db/changes/10503-november/00-isCompensationACL.sql b/db/changes/224903/00-isCompensationACL.sql similarity index 100% rename from db/changes/10503-november/00-isCompensationACL.sql rename to db/changes/224903/00-isCompensationACL.sql diff --git a/db/changes/10503-november/00-osTicketConfig.sql b/db/changes/224903/00-osTicketConfig.sql similarity index 100% rename from db/changes/10503-november/00-osTicketConfig.sql rename to db/changes/224903/00-osTicketConfig.sql diff --git a/db/changes/10503-november/00-ticket_canMerge.sql b/db/changes/224903/00-ticket_canMerge.sql similarity index 100% rename from db/changes/10503-november/00-ticket_canMerge.sql rename to db/changes/224903/00-ticket_canMerge.sql diff --git a/db/changes/10503-november/00-ticket_canbePostponed.sql b/db/changes/224903/00-ticket_canbePostponed.sql similarity index 100% rename from db/changes/10503-november/00-ticket_canbePostponed.sql rename to db/changes/224903/00-ticket_canbePostponed.sql diff --git a/db/changes/10503-november/00-timeBusiness_calculate.sql b/db/changes/224903/00-timeBusiness_calculate.sql similarity index 100% rename from db/changes/10503-november/00-timeBusiness_calculate.sql rename to db/changes/224903/00-timeBusiness_calculate.sql diff --git a/db/changes/10503-november/01-updateClientHasInvoiceElectronic.sql b/db/changes/224903/01-updateClientHasInvoiceElectronic.sql similarity index 100% rename from db/changes/10503-november/01-updateClientHasInvoiceElectronic.sql rename to db/changes/224903/01-updateClientHasInvoiceElectronic.sql diff --git a/db/changes/10510-december/deleteMe.keep b/db/changes/225001/.gitkeep similarity index 100% rename from db/changes/10510-december/deleteMe.keep rename to db/changes/225001/.gitkeep diff --git a/db/dump/dumpedFixtures.sql b/db/dump/dumpedFixtures.sql index c9c265ae7..a4870e2df 100644 --- a/db/dump/dumpedFixtures.sql +++ b/db/dump/dumpedFixtures.sql @@ -22,7 +22,7 @@ USE `util`; LOCK TABLES `config` WRITE; /*!40000 ALTER TABLE `config` DISABLE KEYS */; -INSERT INTO `config` VALUES (1,'10480',0,'production',NULL); +INSERT INTO `config` VALUES (1,'224602',0,'production',NULL); /*!40000 ALTER TABLE `config` ENABLE KEYS */; UNLOCK TABLES; diff --git a/db/import-changes.sh b/db/import-changes.sh index 2b80654d3..5461f003b 100755 --- a/db/import-changes.sh +++ b/db/import-changes.sh @@ -81,9 +81,9 @@ N_CHANGES=0 for DIR_PATH in "$DIR/changes/"*; do DIR_NAME=$(basename $DIR_PATH) - DIR_VERSION=${DIR_NAME:0:5} + DIR_VERSION=${DIR_NAME:0:6} - if [[ ! "$DIR_NAME" =~ ^[0-9]{5}(-[a-zA-Z0-9]+)?$ ]]; then + if [[ ! "$DIR_NAME" =~ ^[0-9]{6}$ ]]; then echo "[WARN] Ignoring wrong directory name: $DIR_NAME" continue fi
- {{labelData.collectionFk ? `${labelData.collectionFk} ~ ${getVertical(labelData.code, labelData.wagon, labelData.level, labelData.color)}` : '-'.repeat(19)}} - {{getVertical(labelData)}} {{labelData.clientFk ? `${labelData.ticketFk} « ${labelData.clientFk}` : labelData.ticketFk}}