} $
* @property {Object} accountConfig
@@ -18,12 +18,12 @@ module.exports = function(Self, options) {
*/
let Mixin = {
/**
- * Initalizes the synchronizer.
+ * Initalizes the linker.
*/
async init() {},
/**
- * Deinitalizes the synchronizer.
+ * Deinitalizes the linker.
*/
async deinit() {},
@@ -57,7 +57,7 @@ module.exports = function(Self, options) {
async syncRoles() {},
/**
- * Tests synchronizer configuration.
+ * Tests linker configuration.
*/
async test() {
try {
diff --git a/modules/account/back/model-config.json b/modules/account/back/model-config.json
index b4bd6dbaf..0cd43d0ce 100644
--- a/modules/account/back/model-config.json
+++ b/modules/account/back/model-config.json
@@ -14,6 +14,9 @@
"MailAliasAccount": {
"dataSource": "vn"
},
+ "MailAliasAcl": {
+ "dataSource": "vn"
+ },
"MailConfig": {
"dataSource": "vn"
},
diff --git a/modules/account/back/models/account-config.js b/modules/account/back/models/account-config.js
index 0db699b99..2cc6b240d 100644
--- a/modules/account/back/models/account-config.js
+++ b/modules/account/back/models/account-config.js
@@ -3,94 +3,85 @@ const models = require('vn-loopback/server/server').models;
module.exports = Self => {
Object.assign(Self, {
- synchronizers: [],
+ linkers: [],
- addSynchronizer(synchronizer) {
- this.synchronizers.push(synchronizer);
+ addLinker(linker) {
+ this.linkers.push(linker);
},
- async getInstance() {
- let instance = await Self.findOne({
+ async initEngine() {
+ const accountConfig = await Self.findOne({
fields: ['homedir', 'shell', 'idBase']
});
- await instance.synchronizerInit();
- return instance;
+ const mailConfig = await models.MailConfig.findOne({
+ fields: ['domain']
+ });
+
+ const linkers = [];
+
+ for (const Linker of Self.linkers) {
+ const linker = await Linker.getLinker();
+ if (!linker) continue;
+ Object.assign(linker, {accountConfig});
+ await linker.init();
+ linkers.push(linker);
+ }
+
+ Object.assign(accountConfig, {
+ linkers,
+ domain: mailConfig.domain
+ });
+
+ return {
+ accountConfig,
+ linkers
+ };
+ },
+
+ async deinitEngine(engine) {
+ for (const linker of engine.linkers)
+ await linker.deinit();
+ },
+
+ async syncUser(userName, password) {
+ const engine = await Self.initEngine();
+ try {
+ await Self.syncUserBase(engine, userName, password, true);
+ } finally {
+ await Self.deinitEngine(engine);
+ }
},
async syncUsers() {
- let instance = await Self.getInstance();
+ const engine = await Self.initEngine();
+
+ let usersToSync = new Set();
+ for (const linker of engine.linkers)
+ await linker.getUsers(usersToSync);
- let usersToSync = await instance.synchronizerGetUsers();
usersToSync = Array.from(usersToSync.values())
.sort((a, b) => a.localeCompare(b));
for (let userName of usersToSync) {
try {
+ // eslint-disable-next-line no-console
console.log(`Synchronizing user '${userName}'`);
- await instance.synchronizerSyncUser(userName);
+
+ await Self.syncUserBase(engine, userName);
+
+ // eslint-disable-next-line no-console
console.log(` -> User '${userName}' sinchronized`);
} catch (err) {
+ // eslint-disable-next-line no-console
console.error(` -> User '${userName}' synchronization error:`, err.message);
}
}
- await instance.synchronizerDeinit();
+ await Self.deinitEngine(engine);
await Self.syncRoles();
},
- async syncUser(userName, password) {
- let instance = await Self.getInstance();
- try {
- await instance.synchronizerSyncUser(userName, password, true);
- } finally {
- await instance.synchronizerDeinit();
- }
- },
-
- async syncRoles() {
- let instance = await Self.getInstance();
- try {
- await instance.synchronizerSyncRoles();
- } finally {
- await instance.synchronizerDeinit();
- }
- },
-
- async getSynchronizer() {
- return await Self.findOne();
- }
- });
-
- Object.assign(Self.prototype, {
- async synchronizerInit() {
- let mailConfig = await models.MailConfig.findOne({
- fields: ['domain']
- });
-
- let synchronizers = [];
-
- for (let Synchronizer of Self.synchronizers) {
- let synchronizer = await Synchronizer.getSynchronizer();
- if (!synchronizer) continue;
- Object.assign(synchronizer, {
- accountConfig: this
- });
- await synchronizer.init();
- synchronizers.push(synchronizer);
- }
-
- Object.assign(this, {
- synchronizers,
- domain: mailConfig.domain
- });
- },
-
- async synchronizerDeinit() {
- for (let synchronizer of this.synchronizers)
- await synchronizer.deinit();
- },
-
- async synchronizerSyncUser(userName, password, syncGroups) {
+ async syncUserBase(engine, userName, password, syncGroups) {
if (!userName) return;
userName = userName.toLowerCase();
@@ -98,7 +89,7 @@ module.exports = Self => {
if (['administrator', 'root'].indexOf(userName) >= 0)
return;
- let user = await models.VnUser.findOne({
+ const user = await models.VnUser.findOne({
where: {name: userName},
fields: [
'id',
@@ -130,27 +121,28 @@ module.exports = Self => {
]
});
- let info = {
+ const info = {
user,
hasAccount: false
};
if (user) {
- let exists = await models.Account.exists(user.id);
+ const exists = await models.Account.exists(user.id);
+ const {accountConfig} = engine;
Object.assign(info, {
hasAccount: user.active && exists,
- corporateMail: `${userName}@${this.domain}`,
- uidNumber: this.idBase + user.id
+ corporateMail: `${userName}@${accountConfig.domain}`,
+ uidNumber: accountConfig.idBase + user.id
});
}
- let errs = [];
+ const errs = [];
- for (let synchronizer of this.synchronizers) {
+ for (const linker of engine.linkers) {
try {
- await synchronizer.syncUser(userName, info, password);
+ await linker.syncUser(userName, info, password);
if (syncGroups)
- await synchronizer.syncUserGroups(userName, info);
+ await linker.syncUserGroups(userName, info);
} catch (err) {
errs.push(err);
}
@@ -159,18 +151,16 @@ module.exports = Self => {
if (errs.length) throw errs[0];
},
- async synchronizerGetUsers() {
- let usersToSync = new Set();
+ async syncRoles() {
+ const engine = await Self.initEngine();
+ try {
+ await Self.rawSql(`CALL account.role_sync`);
- for (let synchronizer of this.synchronizers)
- await synchronizer.getUsers(usersToSync);
-
- return usersToSync;
- },
-
- async synchronizerSyncRoles() {
- for (let synchronizer of this.synchronizers)
- await synchronizer.syncRoles();
+ for (const linker of engine.linkers)
+ await linker.syncRoles();
+ } finally {
+ await Self.deinitEngine(engine);
+ }
}
});
};
diff --git a/modules/account/back/models/account.json b/modules/account/back/models/account.json
index 3c22521cb..6c2784696 100644
--- a/modules/account/back/models/account.json
+++ b/modules/account/back/models/account.json
@@ -1,49 +1,49 @@
{
- "name": "Account",
- "base": "VnModel",
- "options": {
- "mysql": {
- "table": "account.account"
- }
- },
- "properties": {
- "id": {
- "id": true
- }
- },
- "relations": {
- "user": {
- "type": "belongsTo",
- "model": "VnUser",
- "foreignKey": "id"
- },
- "aliases": {
- "type": "hasMany",
- "model": "MailAliasAccount",
- "foreignKey": "account"
- }
- },
- "acls": [
- {
- "property": "login",
- "accessType": "EXECUTE",
- "principalType": "ROLE",
- "principalId": "$everyone",
- "permission": "ALLOW"
+ "name": "Account",
+ "base": "VnModel",
+ "options": {
+ "mysql": {
+ "table": "account.account"
+ }
+ },
+ "properties": {
+ "id": {
+ "id": true
+ }
+ },
+ "relations": {
+ "user": {
+ "type": "belongsTo",
+ "model": "VnUser",
+ "foreignKey": "id"
},
- {
+ "aliases": {
+ "type": "hasMany",
+ "model": "MailAliasAccount",
+ "foreignKey": "account"
+ }
+ },
+ "acls": [
+ {
+ "property": "login",
+ "accessType": "EXECUTE",
+ "principalType": "ROLE",
+ "principalId": "$everyone",
+ "permission": "ALLOW"
+ },
+ {
"property": "logout",
- "accessType": "EXECUTE",
- "principalType": "ROLE",
- "principalId": "$authenticated",
- "permission": "ALLOW"
- },
- {
+ "accessType": "EXECUTE",
+ "principalType": "ROLE",
+ "principalId": "$authenticated",
+ "permission": "ALLOW"
+ },
+ {
"property": "changePassword",
- "accessType": "EXECUTE",
- "principalType": "ROLE",
- "principalId": "$everyone",
- "permission": "ALLOW"
- }
- ]
+ "accessType": "EXECUTE",
+ "principalType": "ROLE",
+ "principalId": "$everyone",
+ "permission": "ALLOW"
+ }
+ ]
}
diff --git a/modules/account/back/models/ldap-config.js b/modules/account/back/models/ldap-config.js
index 9dcc4136d..89f0add48 100644
--- a/modules/account/back/models/ldap-config.js
+++ b/modules/account/back/models/ldap-config.js
@@ -7,7 +7,7 @@ const nthash = require('smbhash').nthash;
module.exports = Self => {
const shouldSync = process.env.NODE_ENV !== 'test';
- Self.getSynchronizer = async function() {
+ Self.getLinker = async function() {
return await Self.findOne({
fields: [
'server',
@@ -24,6 +24,7 @@ module.exports = Self => {
this.client = ldap.createClient({
url: this.server
});
+ this.client.on('error', () => {});
await this.client.bind(this.rdn, this.password);
},
@@ -238,7 +239,7 @@ module.exports = Self => {
// Prepare data
- let roles = await $.Role.find({
+ let roles = await $.VnRole.find({
fields: ['id', 'name', 'description']
});
let roleRoles = await $.RoleRole.find({
diff --git a/modules/account/back/models/ldap-config.json b/modules/account/back/models/ldap-config.json
index 2fd5aa901..d4d3a094d 100644
--- a/modules/account/back/models/ldap-config.json
+++ b/modules/account/back/models/ldap-config.json
@@ -7,7 +7,7 @@
}
},
"mixins": {
- "AccountSynchronizer": {}
+ "AccountLinker": {}
},
"properties": {
"id": {
diff --git a/modules/account/back/models/mail-alias-account.js b/modules/account/back/models/mail-alias-account.js
index 6f5213f24..5eb561408 100644
--- a/modules/account/back/models/mail-alias-account.js
+++ b/modules/account/back/models/mail-alias-account.js
@@ -2,54 +2,44 @@
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
+ Self.rewriteDbError(function(err) {
+ if (err.code === 'ER_DUP_ENTRY')
+ return new UserError(`You already have the mailAlias`);
+ return err;
+ });
+
Self.observe('before save', async ctx => {
const changes = ctx.currentInstance || ctx.instance;
- await Self.hasGrant(ctx, changes.mailAlias);
+ await checkModifyPermission(ctx, changes.mailAlias);
});
Self.observe('before delete', async ctx => {
const mailAliasAccount = await Self.findById(ctx.where.id);
- await Self.hasGrant(ctx, mailAliasAccount.mailAlias);
+ await checkModifyPermission(ctx, mailAliasAccount.mailAlias);
});
- /**
- * Checks if current user has
- * grant to add/remove alias
- *
- * @param {Object} ctx - Request context
- * @param {Interger} mailAlias - mailAlias id
- * @return {Boolean} True for user with grant
- */
- Self.hasGrant = async function(ctx, mailAlias) {
+ async function checkModifyPermission(ctx, mailAliasFk) {
+ const userId = ctx.options.accessToken.userId;
const models = Self.app.models;
- const accessToken = {req: {accessToken: ctx.options.accessToken}};
- const userId = accessToken.req.accessToken.userId;
- const canEditAlias = await models.ACL.checkAccessAcl(accessToken, 'MailAliasAccount', 'canEditAlias', 'WRITE');
- if (canEditAlias) return true;
+ const roles = await models.RoleMapping.find({
+ fields: ['roleId'],
+ where: {principalId: userId}
+ });
- const user = await models.VnUser.findById(userId, {fields: ['hasGrant']});
- if (!user.hasGrant)
- throw new UserError(`You don't have grant privilege`);
-
- const account = await models.Account.findById(userId, {
- fields: ['id'],
- include: {
- relation: 'aliases',
- scope: {
- fields: ['mailAlias']
- }
+ const availableMailAlias = await models.MailAliasAcl.findOne({
+ fields: ['mailAliasFk'],
+ include: {relation: 'mailAlias'},
+ where: {
+ roleFk: {
+ inq: roles.map(role => role.roleId),
+ },
+ mailAliasFk
}
});
- const aliases = account.aliases().map(alias => alias.mailAlias);
-
- const hasAlias = aliases.includes(mailAlias);
- if (!hasAlias)
- throw new UserError(`You cannot assign/remove an alias that you are not assigned to`);
-
- return true;
- };
+ if (!availableMailAlias) throw new UserError('The alias cant be modified');
+ }
};
diff --git a/modules/account/back/models/mail-alias-acl.json b/modules/account/back/models/mail-alias-acl.json
new file mode 100644
index 000000000..014b95d14
--- /dev/null
+++ b/modules/account/back/models/mail-alias-acl.json
@@ -0,0 +1,31 @@
+{
+ "name": "MailAliasAcl",
+ "base": "VnModel",
+ "options": {
+ "mysql": {
+ "table": "account.mailAliasAcl"
+ }
+ },
+ "properties": {
+ "mailAliasFk": {
+ "id": true,
+ "type": "number"
+ },
+ "roleFk": {
+ "id": true,
+ "type": "number"
+ }
+ },
+ "relations": {
+ "mailAlias": {
+ "type": "belongsTo",
+ "model": "MailAlias",
+ "foreignKey": "mailAliasFk"
+ },
+ "role": {
+ "type": "belongsTo",
+ "model": "Role",
+ "foreignKey": "roleFk"
+ }
+ }
+}
diff --git a/modules/account/back/models/role-config.js b/modules/account/back/models/role-config.js
index b90ef75fb..d6c57b70b 100644
--- a/modules/account/back/models/role-config.js
+++ b/modules/account/back/models/role-config.js
@@ -1,6 +1,6 @@
module.exports = Self => {
- Self.getSynchronizer = async function() {
+ Self.getLinker = async function() {
let NODE_ENV = process.env.NODE_ENV;
if (!NODE_ENV || NODE_ENV == 'development')
return null;
@@ -45,6 +45,7 @@ module.exports = Self => {
}
if (!isUpdatable) {
+ // eslint-disable-next-line no-console
console.warn(`RoleConfig.syncUser(): User '${userName}' cannot be updated, not managed by me`);
return;
}
@@ -82,6 +83,7 @@ module.exports = Self => {
[mysqlUser, this.userHost]);
} catch (err) {
if (err.code == 'ER_REVOKE_GRANTS')
+ // eslint-disable-next-line no-console
console.warn(`${err.code}: ${err.sqlMessage}: ${err.sql}`);
else
throw err;
diff --git a/modules/account/back/models/role-config.json b/modules/account/back/models/role-config.json
index f4138bea8..3b843eaea 100644
--- a/modules/account/back/models/role-config.json
+++ b/modules/account/back/models/role-config.json
@@ -7,7 +7,7 @@
}
},
"mixins": {
- "AccountSynchronizer": {}
+ "AccountLinker": {}
},
"properties": {
"id": {
diff --git a/modules/account/back/models/role-inherit.js b/modules/account/back/models/role-inherit.js
index 7d31e62b1..e994f844e 100644
--- a/modules/account/back/models/role-inherit.js
+++ b/modules/account/back/models/role-inherit.js
@@ -9,7 +9,7 @@ module.exports = Self => {
Self.observe(hook, async() => {
try {
await Self.rawSql(`
- CREATE EVENT account.role_sync
+ CREATE DEFINER = CURRENT_ROLE EVENT account.role_sync
ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 5 SECOND
DO CALL role_sync;
`);
diff --git a/modules/account/back/models/role-inherit.json b/modules/account/back/models/role-inherit.json
index 4b69ffdc2..a89f47b77 100644
--- a/modules/account/back/models/role-inherit.json
+++ b/modules/account/back/models/role-inherit.json
@@ -15,12 +15,12 @@
"relations": {
"owner": {
"type": "belongsTo",
- "model": "Role",
+ "model": "VnRole",
"foreignKey": "role"
},
"inherits": {
"type": "belongsTo",
- "model": "Role",
+ "model": "VnRole",
"foreignKey": "inheritsFrom"
}
}
diff --git a/modules/account/back/models/role-role.json b/modules/account/back/models/role-role.json
index 77df7a920..e59351c59 100644
--- a/modules/account/back/models/role-role.json
+++ b/modules/account/back/models/role-role.json
@@ -14,12 +14,12 @@
"relations": {
"owner": {
"type": "belongsTo",
- "model": "Role",
+ "model": "VnRole",
"foreignKey": "role"
},
"inherits": {
"type": "belongsTo",
- "model": "Role",
+ "model": "VnRole",
"foreignKey": "inheritsFrom"
}
}
diff --git a/modules/account/back/models/samba-config.js b/modules/account/back/models/samba-config.js
index 7714fb01c..f5672ca21 100644
--- a/modules/account/back/models/samba-config.js
+++ b/modules/account/back/models/samba-config.js
@@ -13,7 +13,7 @@ const UserAccountControlFlags = {
module.exports = Self => {
const shouldSync = process.env.NODE_ENV !== 'test';
- Self.getSynchronizer = async function() {
+ Self.getLinker = async function() {
return await Self.findOne({
fields: [
'host',
@@ -39,6 +39,7 @@ module.exports = Self => {
url: `ldaps://${this.adController}:636`,
tlsOptions: {rejectUnauthorized: this.verifyCert}
});
+ adClient.on('error', () => {});
await adClient.bind(bindDn, this.adPassword);
Object.assign(this, {
adClient,
diff --git a/modules/account/back/models/samba-config.json b/modules/account/back/models/samba-config.json
index 28cbb2689..4c9e0a794 100644
--- a/modules/account/back/models/samba-config.json
+++ b/modules/account/back/models/samba-config.json
@@ -7,7 +7,7 @@
}
},
"mixins": {
- "AccountSynchronizer": {}
+ "AccountLinker": {}
},
"properties": {
"id": {
diff --git a/modules/account/back/models/sign_in-log.json b/modules/account/back/models/sign_in-log.json
index c5c014e60..8656e92dc 100644
--- a/modules/account/back/models/sign_in-log.json
+++ b/modules/account/back/models/sign_in-log.json
@@ -25,7 +25,15 @@
"type": "number"
},
"ip": {
- "type": "string"
+ "type": "string"
+ },
+ "userName": {
+ "type": "string"
+ },
+ "owner": {
+ "type": "boolean",
+ "required": true,
+ "default": true
}
},
"relations": {
diff --git a/modules/account/back/models/sip-config.js b/modules/account/back/models/sip-config.js
index 3b5cb2dbb..703783337 100644
--- a/modules/account/back/models/sip-config.js
+++ b/modules/account/back/models/sip-config.js
@@ -2,7 +2,7 @@
const app = require('vn-loopback/server/server');
module.exports = Self => {
- Self.getSynchronizer = async function() {
+ Self.getLinker = async function() {
return await Self.findOne({fields: ['id']});
};
diff --git a/modules/account/back/models/sip-config.json b/modules/account/back/models/sip-config.json
index 6c5ba3db3..a25d09c67 100644
--- a/modules/account/back/models/sip-config.json
+++ b/modules/account/back/models/sip-config.json
@@ -7,7 +7,7 @@
}
},
"mixins": {
- "AccountSynchronizer": {}
+ "AccountLinker": {}
},
"properties": {
"id": {
@@ -16,4 +16,3 @@
}
}
}
-
\ No newline at end of file
diff --git a/modules/account/front/acl/create/index.html b/modules/account/front/acl/create/index.html
index 7f4fa9e46..14332f737 100644
--- a/modules/account/front/acl/create/index.html
+++ b/modules/account/front/acl/create/index.html
@@ -15,7 +15,7 @@
@@ -32,7 +32,7 @@
diff --git a/modules/account/front/acl/search-panel/index.html b/modules/account/front/acl/search-panel/index.html
index b83b9c255..a3efab440 100644
--- a/modules/account/front/acl/search-panel/index.html
+++ b/modules/account/front/acl/search-panel/index.html
@@ -4,7 +4,7 @@
-
\ No newline at end of file
+
diff --git a/modules/account/front/create/index.html b/modules/account/front/create/index.html
index acc07d346..70a518885 100644
--- a/modules/account/front/create/index.html
+++ b/modules/account/front/create/index.html
@@ -30,7 +30,7 @@
-
+
Do you want to synchronize user?
diff --git a/modules/account/front/privileges/index.html b/modules/account/front/privileges/index.html
index 61f2c534e..343c179e3 100644
--- a/modules/account/front/privileges/index.html
+++ b/modules/account/front/privileges/index.html
@@ -22,7 +22,7 @@
+ url="VnRoles">
diff --git a/modules/account/front/role/basic-data/index.html b/modules/account/front/role/basic-data/index.html
index 749927186..846f8b455 100644
--- a/modules/account/front/role/basic-data/index.html
+++ b/modules/account/front/role/basic-data/index.html
@@ -1,25 +1,27 @@
\ No newline at end of file
+
diff --git a/modules/account/front/role/card/index.js b/modules/account/front/role/card/index.js
index 6f888211d..3c7c758ef 100644
--- a/modules/account/front/role/card/index.js
+++ b/modules/account/front/role/card/index.js
@@ -3,7 +3,7 @@ import ModuleCard from 'salix/components/module-card';
class Controller extends ModuleCard {
reload() {
- this.$http.get(`Roles/${this.$params.id}`)
+ this.$http.get(`VnRoles/${this.$params.id}`)
.then(res => this.role = res.data);
}
}
diff --git a/modules/account/front/role/card/index.spec.js b/modules/account/front/role/card/index.spec.js
index f39840e5f..f02c08f28 100644
--- a/modules/account/front/role/card/index.spec.js
+++ b/modules/account/front/role/card/index.spec.js
@@ -1,6 +1,6 @@
import './index';
-describe('component vnRoleCard', () => {
+fdescribe('component vnRoleCard', () => {
let controller;
let $httpBackend;
@@ -15,7 +15,7 @@ describe('component vnRoleCard', () => {
it('should reload the controller data', () => {
controller.$params.id = 1;
- $httpBackend.expectGET('Roles/1').respond('foo');
+ $httpBackend.expectGET('VnRoles/1').respond('foo');
controller.reload();
$httpBackend.flush();
diff --git a/modules/account/front/role/create/index.html b/modules/account/front/role/create/index.html
index 02900d580..77d6fc2c1 100644
--- a/modules/account/front/role/create/index.html
+++ b/modules/account/front/role/create/index.html
@@ -1,6 +1,6 @@
@@ -12,15 +12,15 @@
+ rule="VnRole.description">
diff --git a/modules/account/front/role/descriptor/index.html b/modules/account/front/role/descriptor/index.html
index 4cd4ac822..d8bf4857a 100644
--- a/modules/account/front/role/descriptor/index.html
+++ b/modules/account/front/role/descriptor/index.html
@@ -24,4 +24,4 @@
on-accept="$ctrl.onDelete()"
question="Are you sure you want to continue?"
message="Role will be removed">
-
\ No newline at end of file
+
diff --git a/modules/account/front/role/descriptor/index.js b/modules/account/front/role/descriptor/index.js
index a1b578133..17b585cb7 100644
--- a/modules/account/front/role/descriptor/index.js
+++ b/modules/account/front/role/descriptor/index.js
@@ -11,7 +11,7 @@ class Controller extends Descriptor {
}
onDelete() {
- return this.$http.delete(`Roles/${this.id}`)
+ return this.$http.delete(`VnRoles/${this.id}`)
.then(() => this.$state.go('account.role'))
.then(() => this.vnApp.showSuccess(this.$t('Role removed')));
}
diff --git a/modules/account/front/role/descriptor/index.spec.js b/modules/account/front/role/descriptor/index.spec.js
index e2761c639..eafb96727 100644
--- a/modules/account/front/role/descriptor/index.spec.js
+++ b/modules/account/front/role/descriptor/index.spec.js
@@ -1,6 +1,6 @@
import './index';
-describe('component vnRoleDescriptor', () => {
+fdescribe('component vnRoleDescriptor', () => {
let controller;
let $httpBackend;
@@ -18,7 +18,7 @@ describe('component vnRoleDescriptor', () => {
controller.$state.go = jest.fn();
jest.spyOn(controller.vnApp, 'showSuccess');
- $httpBackend.expectDELETE('Roles/1').respond();
+ $httpBackend.expectDELETE('VnRoles/1').respond();
controller.onDelete();
$httpBackend.flush();
diff --git a/modules/account/front/role/main/index.html b/modules/account/front/role/main/index.html
index 9d7e6e053..cfef28e57 100644
--- a/modules/account/front/role/main/index.html
+++ b/modules/account/front/role/main/index.html
@@ -1,6 +1,6 @@
@@ -15,4 +15,4 @@
-
\ No newline at end of file
+
diff --git a/modules/account/front/role/subroles/index.html b/modules/account/front/role/subroles/index.html
index bc554b9f9..eba1002b0 100644
--- a/modules/account/front/role/subroles/index.html
+++ b/modules/account/front/role/subroles/index.html
@@ -33,14 +33,14 @@
ng-click="$ctrl.onAddClick()"
fixed-bottom-right>
-
@@ -49,7 +49,7 @@
- this.$.summary = res.data);
}
diff --git a/modules/account/front/search-panel/index.html b/modules/account/front/search-panel/index.html
index f80b537aa..a539d9657 100644
--- a/modules/account/front/search-panel/index.html
+++ b/modules/account/front/search-panel/index.html
@@ -19,7 +19,7 @@
vn-one
label="Role"
ng-model="filter.roleFk"
- url="Roles"
+ url="VnRoles"
value-field="id"
show-field="name">
@@ -28,4 +28,4 @@
-
\ No newline at end of file
+
diff --git a/modules/claim/back/methods/claim-beginning/importToNewRefundTicket.js b/modules/claim/back/methods/claim-beginning/importToNewRefundTicket.js
index be3baccd7..a01590f58 100644
--- a/modules/claim/back/methods/claim-beginning/importToNewRefundTicket.js
+++ b/modules/claim/back/methods/claim-beginning/importToNewRefundTicket.js
@@ -123,7 +123,7 @@ module.exports = Self => {
await models.TicketTracking.create({
ticketFk: newRefundTicket.id,
stateFk: state.id,
- workerFk: worker.id
+ userFk: worker.id
}, myOptions);
const salesToRefund = await models.ClaimBeginning.find(salesFilter, myOptions);
diff --git a/modules/claim/back/methods/claim-dms/removeFile.js b/modules/claim/back/methods/claim-dms/removeFile.js
index edc714235..28e78c9d7 100644
--- a/modules/claim/back/methods/claim-dms/removeFile.js
+++ b/modules/claim/back/methods/claim-dms/removeFile.js
@@ -1,3 +1,5 @@
+const UserError = require('vn-loopback/util/user-error');
+
module.exports = Self => {
Self.remoteMethodCtx('removeFile', {
description: 'Removes a claim document',
@@ -19,8 +21,8 @@ module.exports = Self => {
});
Self.removeFile = async(ctx, id, options) => {
- let tx;
const myOptions = {};
+ let tx;
if (typeof options == 'object')
Object.assign(myOptions, options);
@@ -31,19 +33,18 @@ module.exports = Self => {
}
try {
- const models = Self.app.models;
- const targetClaimDms = await models.ClaimDms.findById(id, null, myOptions);
- const targetDms = await models.Dms.findById(targetClaimDms.dmsFk, null, myOptions);
- const trashDmsType = await models.DmsType.findOne({where: {code: 'trash'}}, myOptions);
+ const claimDms = await Self.findById(id, null, myOptions);
- await models.Dms.removeFile(ctx, targetClaimDms.dmsFk, myOptions);
- await targetClaimDms.destroy(myOptions);
+ const targetDms = await Self.app.models.Dms.removeFile(ctx, claimDms.dmsFk, myOptions);
- await targetDms.updateAttribute('dmsTypeFk', trashDmsType.id, myOptions);
+ if (!targetDms || ! claimDms)
+ throw new UserError('Try again');
+
+ const claimDmsDestroyed = await claimDms.destroy(myOptions);
if (tx) await tx.commit();
- return targetDms;
+ return claimDmsDestroyed;
} catch (e) {
if (tx) await tx.rollback();
throw e;
diff --git a/modules/claim/back/methods/claim/uploadFile.js b/modules/claim/back/methods/claim/uploadFile.js
index 3d0737cf8..4fd041456 100644
--- a/modules/claim/back/methods/claim/uploadFile.js
+++ b/modules/claim/back/methods/claim/uploadFile.js
@@ -1,6 +1,3 @@
-const UserError = require('vn-loopback/util/user-error');
-const fs = require('fs-extra');
-const path = require('path');
module.exports = Self => {
Self.remoteMethodCtx('uploadFile', {
@@ -57,96 +54,33 @@ module.exports = Self => {
});
Self.uploadFile = async(ctx, id, options) => {
- const tx = await Self.beginTransaction({});
+ const {Dms, ClaimDms} = Self.app.models;
const myOptions = {};
+ let tx;
if (typeof options == 'object')
Object.assign(myOptions, options);
- if (!myOptions.transaction)
+ if (!myOptions.transaction) {
+ tx = await Self.beginTransaction({});
myOptions.transaction = tx;
+ }
- const models = Self.app.models;
- const promises = [];
- const TempContainer = models.TempContainer;
- const ClaimContainer = models.ClaimContainer;
- const fileOptions = {};
- const args = ctx.args;
-
- let srcFile;
try {
- const hasWriteRole = await models.DmsType.hasWriteRole(ctx, args.dmsTypeId, myOptions);
- if (!hasWriteRole)
- throw new UserError(`You don't have enough privileges`);
+ const uploadedFiles = await Dms.uploadFile(ctx, myOptions);
- // Upload file to temporary path
- const tempContainer = await TempContainer.container('dms');
- const uploaded = await TempContainer.upload(tempContainer.name, ctx.req, ctx.result, fileOptions);
- const files = Object.values(uploaded.files).map(file => {
- return file[0];
- });
-
- const addedDms = [];
- for (const uploadedFile of files) {
- const newDms = await createDms(ctx, uploadedFile, myOptions);
- const pathHash = ClaimContainer.getHash(newDms.id);
-
- const file = await TempContainer.getFile(tempContainer.name, uploadedFile.name);
- srcFile = path.join(file.client.root, file.container, file.name);
-
- const claimContainer = await ClaimContainer.container(pathHash);
- const dstFile = path.join(claimContainer.client.root, pathHash, newDms.file);
-
- await fs.move(srcFile, dstFile, {
- overwrite: true
- });
-
- addedDms.push(newDms);
- }
-
- addedDms.forEach(dms => {
- const newClaimDms = models.ClaimDms.create({
- claimFk: id,
- dmsFk: dms.id
- }, myOptions);
-
- promises.push(newClaimDms);
- });
- const resolvedPromises = await Promise.all(promises);
+ const promises = uploadedFiles.map(dms => ClaimDms.create({
+ claimFk: id,
+ dmsFk: dms.id
+ }, myOptions));
+ await Promise.all(promises);
if (tx) await tx.commit();
- return resolvedPromises;
+ return uploadedFiles;
} catch (e) {
if (tx) await tx.rollback();
-
- if (fs.existsSync(srcFile))
- await fs.unlink(srcFile);
-
throw e;
}
};
-
- async function createDms(ctx, file, myOptions) {
- const models = Self.app.models;
- const myUserId = ctx.req.accessToken.userId;
- const args = ctx.args;
-
- const newDms = await models.Dms.create({
- workerFk: myUserId,
- dmsTypeFk: args.dmsTypeId,
- companyFk: args.companyId,
- warehouseFk: args.warehouseId,
- reference: args.reference,
- description: args.description,
- contentType: file.type,
- hasFile: args.hasFile
- }, myOptions);
-
- let fileName = file.name;
- const extension = models.DmsContainer.getFileExtension(fileName);
- fileName = `${newDms.id}.${extension}`;
-
- return newDms.updateAttribute('file', fileName, myOptions);
- }
};
diff --git a/modules/claim/back/models/claim-beginning.json b/modules/claim/back/models/claim-beginning.json
index d355881e8..d224586da 100644
--- a/modules/claim/back/models/claim-beginning.json
+++ b/modules/claim/back/models/claim-beginning.json
@@ -1,6 +1,9 @@
{
"name": "ClaimBeginning",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "claimBeginning"
diff --git a/modules/claim/back/models/claim-development.json b/modules/claim/back/models/claim-development.json
index b0f352f50..732955660 100644
--- a/modules/claim/back/models/claim-development.json
+++ b/modules/claim/back/models/claim-development.json
@@ -1,6 +1,9 @@
{
"name": "ClaimDevelopment",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "claimDevelopment"
diff --git a/modules/claim/back/models/claim-dms.json b/modules/claim/back/models/claim-dms.json
index 26c90fd69..ed12c925b 100644
--- a/modules/claim/back/models/claim-dms.json
+++ b/modules/claim/back/models/claim-dms.json
@@ -1,6 +1,9 @@
{
"name": "ClaimDms",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "claimDms"
diff --git a/modules/claim/back/models/claim-end.json b/modules/claim/back/models/claim-end.json
index 9f12ff93a..ef5477f50 100644
--- a/modules/claim/back/models/claim-end.json
+++ b/modules/claim/back/models/claim-end.json
@@ -1,6 +1,9 @@
{
"name": "ClaimEnd",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "claimEnd"
diff --git a/modules/claim/back/models/claim-observation.json b/modules/claim/back/models/claim-observation.json
index 2d418b76e..1e4cb6a0f 100644
--- a/modules/claim/back/models/claim-observation.json
+++ b/modules/claim/back/models/claim-observation.json
@@ -1,6 +1,9 @@
{
"name": "ClaimObservation",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "claimObservation"
diff --git a/modules/claim/back/models/claim-state.json b/modules/claim/back/models/claim-state.json
index f5bde4168..c50fdebdf 100644
--- a/modules/claim/back/models/claim-state.json
+++ b/modules/claim/back/models/claim-state.json
@@ -1,6 +1,9 @@
{
"name": "ClaimState",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "claimState"
@@ -32,7 +35,7 @@
"relations": {
"writeRole": {
"type": "belongsTo",
- "model": "Role",
+ "model": "VnRole",
"foreignKey": "roleFk"
}
},
diff --git a/modules/claim/back/models/claim.json b/modules/claim/back/models/claim.json
index a7db1f3e1..b85b9e073 100644
--- a/modules/claim/back/models/claim.json
+++ b/modules/claim/back/models/claim.json
@@ -1,6 +1,9 @@
{
"name": "Claim",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "claim"
diff --git a/modules/client/back/methods/client-dms/removeFile.js b/modules/client/back/methods/client-dms/removeFile.js
index 786a32928..bc9a0f719 100644
--- a/modules/client/back/methods/client-dms/removeFile.js
+++ b/modules/client/back/methods/client-dms/removeFile.js
@@ -19,9 +19,8 @@ module.exports = Self => {
});
Self.removeFile = async(ctx, id, options) => {
- const models = Self.app.models;
- let tx;
const myOptions = {};
+ let tx;
if (typeof options == 'object')
Object.assign(myOptions, options);
@@ -34,13 +33,16 @@ module.exports = Self => {
try {
const clientDms = await Self.findById(id, null, myOptions);
- await models.Dms.removeFile(ctx, clientDms.dmsFk, myOptions);
+ const targetDms = await Self.app.models.Dms.removeFile(ctx, clientDms.dmsFk, myOptions);
- const destroyedClient = await clientDms.destroy(myOptions);
+ if (!targetDms || !clientDms)
+ throw new UserError('Try again');
+
+ const clientDmsDestroyed = await clientDms.destroy(myOptions);
if (tx) await tx.commit();
- return destroyedClient;
+ return clientDmsDestroyed;
} catch (e) {
if (tx) await tx.rollback();
throw e;
diff --git a/modules/client/back/methods/client/canBeInvoiced.js b/modules/client/back/methods/client/canBeInvoiced.js
index 843e9549f..cdb865500 100644
--- a/modules/client/back/methods/client/canBeInvoiced.js
+++ b/modules/client/back/methods/client/canBeInvoiced.js
@@ -1,7 +1,7 @@
const UserError = require('vn-loopback/util/user-error');
module.exports = function(Self) {
- Self.remoteMethodCtx('canBeInvoiced', {
+ Self.remoteMethod('canBeInvoiced', {
description: 'Change property isEqualizated in all client addresses',
accessType: 'READ',
accepts: [
diff --git a/modules/client/back/methods/client/filter.js b/modules/client/back/methods/client/filter.js
index 47d5f6d2f..f805c4be9 100644
--- a/modules/client/back/methods/client/filter.js
+++ b/modules/client/back/methods/client/filter.js
@@ -107,17 +107,29 @@ module.exports = Self => {
return {or: [
{'c.phone': {like: `%${value}%`}},
{'c.mobile': {like: `%${value}%`}},
+ {'a.phone': {like: `%${value}%`}},
]};
case 'zoneFk':
- param = 'a.postalCode';
- return {[param]: {inq: postalCode}};
+ return {'a.postalCode': {inq: postalCode}};
+ case 'city':
+ return {or: [
+ {'c.city': {like: `%${value}%`}},
+ {'a.city': {like: `%${value}%`}}
+ ]};
+ case 'postcode':
+ return {or: [
+ {'c.postcode': value},
+ {'a.postalCode': value}
+ ]};
+ case 'provinceFk':
+ return {or: [
+ {'p.id': value},
+ {'a.provinceFk': value}
+ ]};
case 'name':
case 'salesPersonFk':
case 'fi':
case 'socialName':
- case 'city':
- case 'postcode':
- case 'provinceFk':
case 'email':
param = `c.${param}`;
return {[param]: {like: `%${value}%`}};
@@ -134,24 +146,29 @@ module.exports = Self => {
c.fi,
c.socialName,
c.phone,
+ a.phone,
c.mobile,
c.city,
+ a.city,
c.postcode,
+ a.postalCode,
c.email,
c.isActive,
c.isFreezed,
- p.id AS provinceFk,
+ p.id AS provinceClientFk,
+ a.provinceFk AS provinceAddressFk,
p.name AS province,
u.id AS salesPersonFk,
u.name AS salesPerson
FROM client c
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
+ JOIN address a ON a.clientFk = c.id
`
);
stmt.merge(conn.makeWhere(filter.where));
+ stmt.merge('GROUP BY c.id');
stmt.merge(conn.makePagination(filter));
const clientsIndex = stmts.push(stmt) - 1;
diff --git a/modules/client/back/methods/client/specs/consumption.spec.js b/modules/client/back/methods/client/specs/consumption.spec.js
index 47a495d79..85dbb7422 100644
--- a/modules/client/back/methods/client/specs/consumption.spec.js
+++ b/modules/client/back/methods/client/specs/consumption.spec.js
@@ -16,7 +16,7 @@ describe('client consumption() filter', () => {
};
const result = await models.Client.consumption(ctx, filter, options);
- expect(result.length).toEqual(10);
+ expect(result.length).toEqual(11);
await tx.rollback();
} catch (e) {
@@ -49,7 +49,7 @@ describe('client consumption() filter', () => {
const thirdRow = result[2];
expect(result.length).toEqual(3);
- expect(firstRow.quantity).toEqual(10);
+ expect(firstRow.quantity).toEqual(11);
expect(secondRow.quantity).toEqual(15);
expect(thirdRow.quantity).toEqual(20);
diff --git a/modules/client/back/methods/client/uploadFile.js b/modules/client/back/methods/client/uploadFile.js
index 99ede27c6..1a5965955 100644
--- a/modules/client/back/methods/client/uploadFile.js
+++ b/modules/client/back/methods/client/uploadFile.js
@@ -55,9 +55,9 @@ module.exports = Self => {
});
Self.uploadFile = async(ctx, id, options) => {
- const models = Self.app.models;
- let tx;
+ const {Dms, ClientDms} = Self.app.models;
const myOptions = {};
+ let tx;
if (typeof options == 'object')
Object.assign(myOptions, options);
@@ -67,23 +67,20 @@ module.exports = Self => {
myOptions.transaction = tx;
}
- const promises = [];
-
try {
- const uploadedFiles = await models.Dms.uploadFile(ctx, myOptions);
- uploadedFiles.forEach(dms => {
- const newClientDms = models.ClientDms.create({
+ const uploadedFiles = await Dms.uploadFile(ctx, myOptions);
+ const promises = uploadedFiles.map(dms =>
+ ClientDms.create({
clientFk: id,
dmsFk: dms.id
- }, myOptions);
+ }, myOptions)
- promises.push(newClientDms);
- });
- const resolvedPromises = await Promise.all(promises);
+ );
+ await Promise.all(promises);
if (tx) await tx.commit();
- return resolvedPromises;
+ return uploadedFiles;
} catch (e) {
if (tx) await tx.rollback();
throw e;
diff --git a/modules/client/back/model-config.json b/modules/client/back/model-config.json
index 0cc5df9a2..fc1254dd8 100644
--- a/modules/client/back/model-config.json
+++ b/modules/client/back/model-config.json
@@ -29,7 +29,7 @@
"ClientCredit": {
"dataSource": "vn"
},
- "ClientCreditLimit": {
+ "RoleCreditLimit": {
"dataSource": "vn"
},
"ClientConsumptionQueue": {
@@ -113,9 +113,6 @@
"SageTransactionType": {
"dataSource": "vn"
},
- "TicketSms": {
- "dataSource": "vn"
- },
"TpvError": {
"dataSource": "vn"
},
diff --git a/modules/client/back/models/address.json b/modules/client/back/models/address.json
index 5f962677d..e8bf8d8a0 100644
--- a/modules/client/back/models/address.json
+++ b/modules/client/back/models/address.json
@@ -1,7 +1,10 @@
{
"name": "Address",
"description": "Client addresses",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "address"
diff --git a/modules/client/back/models/client-contact.json b/modules/client/back/models/client-contact.json
index 3f71ab79e..55cc9d436 100644
--- a/modules/client/back/models/client-contact.json
+++ b/modules/client/back/models/client-contact.json
@@ -1,7 +1,10 @@
{
"name": "ClientContact",
"description": "Client phone contacts",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "clientContact"
diff --git a/modules/client/back/models/client-dms.json b/modules/client/back/models/client-dms.json
index 14b19498e..6dbcd0140 100644
--- a/modules/client/back/models/client-dms.json
+++ b/modules/client/back/models/client-dms.json
@@ -1,6 +1,9 @@
{
"name": "ClientDms",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "clientDms"
diff --git a/modules/client/back/models/client-informa.json b/modules/client/back/models/client-informa.json
index 0c652484e..5e536faff 100644
--- a/modules/client/back/models/client-informa.json
+++ b/modules/client/back/models/client-informa.json
@@ -1,6 +1,9 @@
{
"name": "ClientInforma",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"log": {
"model":"ClientLog",
"relation": "client",
diff --git a/modules/client/back/models/client-observation.json b/modules/client/back/models/client-observation.json
index 95d00d374..b204ebeb4 100644
--- a/modules/client/back/models/client-observation.json
+++ b/modules/client/back/models/client-observation.json
@@ -1,7 +1,10 @@
{
"name": "ClientObservation",
"description": "Client notes",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "clientObservation"
diff --git a/modules/client/back/models/client-sample.json b/modules/client/back/models/client-sample.json
index a32f308ab..4cd55d9df 100644
--- a/modules/client/back/models/client-sample.json
+++ b/modules/client/back/models/client-sample.json
@@ -1,6 +1,9 @@
{
"name": "ClientSample",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "clientSample"
diff --git a/modules/client/back/models/client-sms.json b/modules/client/back/models/client-sms.json
index b2244ebbb..df1b58737 100644
--- a/modules/client/back/models/client-sms.json
+++ b/modules/client/back/models/client-sms.json
@@ -21,6 +21,11 @@
"type": "belongsTo",
"model": "Sms",
"foreignKey": "smsFk"
+ },
+ "ticket": {
+ "type": "belongsTo",
+ "model": "Ticket",
+ "foreignKey": "ticketFk"
}
}
}
diff --git a/modules/client/back/models/client.js b/modules/client/back/models/client.js
index 72b702779..a9e14effa 100644
--- a/modules/client/back/models/client.js
+++ b/modules/client/back/models/client.js
@@ -463,7 +463,7 @@ module.exports = Self => {
throw new UserError(`You can't change the credit set to zero from a financialBoss`);
}
- const creditLimits = await models.ClientCreditLimit.find({
+ const creditLimits = await models.RoleCreditLimit.find({
fields: ['roleFk'],
where: {
maxAmount: {gte: changes.credit}
diff --git a/modules/client/back/models/client.json b/modules/client/back/models/client.json
index f32915bb5..bfde05162 100644
--- a/modules/client/back/models/client.json
+++ b/modules/client/back/models/client.json
@@ -1,6 +1,9 @@
{
"name": "Client",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "client"
diff --git a/modules/client/back/models/greuge.json b/modules/client/back/models/greuge.json
index 884cbd34e..f57744f8a 100644
--- a/modules/client/back/models/greuge.json
+++ b/modules/client/back/models/greuge.json
@@ -1,6 +1,9 @@
{
"name": "Greuge",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "greuge"
diff --git a/modules/client/back/models/recovery.json b/modules/client/back/models/recovery.json
index 5ea89197d..89ec54494 100644
--- a/modules/client/back/models/recovery.json
+++ b/modules/client/back/models/recovery.json
@@ -1,6 +1,9 @@
{
"name": "Recovery",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "recovery"
diff --git a/modules/client/back/models/client-credit-limit.json b/modules/client/back/models/role-credit-limit.json
similarity index 79%
rename from modules/client/back/models/client-credit-limit.json
rename to modules/client/back/models/role-credit-limit.json
index 740f0cf53..e36180dfc 100644
--- a/modules/client/back/models/client-credit-limit.json
+++ b/modules/client/back/models/role-credit-limit.json
@@ -1,9 +1,9 @@
{
- "name": "ClientCreditLimit",
+ "name": "RoleCreditLimit",
"base": "VnModel",
"options": {
"mysql": {
- "table": "clientCreditLimit"
+ "table": "roleCreditLimit"
}
},
"properties": {
@@ -19,8 +19,8 @@
"relations": {
"role": {
"type": "belongsTo",
- "model": "Role",
+ "model": "VnRole",
"foreignKey": "roleFk"
}
}
-}
\ No newline at end of file
+}
diff --git a/modules/client/back/models/ticket-sms.json b/modules/client/back/models/ticket-sms.json
deleted file mode 100644
index 03f592f51..000000000
--- a/modules/client/back/models/ticket-sms.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
- "name": "TicketSms",
- "base": "VnModel",
- "options": {
- "mysql": {
- "table": "ticketSms"
- }
- },
- "properties": {
- "smsFk": {
- "type": "number",
- "id": true,
- "description": "Identifier"
- }
- },
- "relations": {
- "ticket": {
- "type": "belongsTo",
- "model": "Ticket",
- "foreignKey": "ticketFk"
- },
- "sms": {
- "type": "belongsTo",
- "model": "Sms",
- "foreignKey": "smsFk"
- }
- }
-}
diff --git a/modules/client/front/basic-data/index.html b/modules/client/front/basic-data/index.html
index e48b39fdc..acab99d91 100644
--- a/modules/client/front/basic-data/index.html
+++ b/modules/client/front/basic-data/index.html
@@ -62,7 +62,7 @@
diff --git a/modules/client/front/sms/index.html b/modules/client/front/sms/index.html
index e2bc0785e..7fb3b870e 100644
--- a/modules/client/front/sms/index.html
+++ b/modules/client/front/sms/index.html
@@ -1,40 +1,2 @@
-
-
-
-
-
-
-
- Sender
- Destination
- Message
- Status
- Created
-
-
-
-
-
-
- {{::clientSms.sms.sender.name}}
-
-
- {{::clientSms.sms.destination}}
- {{::clientSms.sms.message}}
- {{::clientSms.sms.status}}
- {{::clientSms.sms.created | date:'dd/MM/yyyy HH:mm'}}
-
-
-
-
-
-
-
+
+
diff --git a/modules/client/front/sms/index.js b/modules/client/front/sms/index.js
index 6ad64282e..8fa130248 100644
--- a/modules/client/front/sms/index.js
+++ b/modules/client/front/sms/index.js
@@ -1,32 +1,14 @@
import ngModule from '../module';
import Section from 'salix/components/section';
-export default class Controller extends Section {
+class Controller extends Section {
constructor($element, $) {
super($element, $);
+ }
- this.filter = {
- fields: ['id', 'smsFk'],
- include: {
- relation: 'sms',
- scope: {
- fields: [
- 'senderFk',
- 'sender',
- 'destination',
- 'message',
- 'statusCode',
- 'status',
- 'created'],
- include: {
- relation: 'sender',
- scope: {
- fields: ['name']
- }
- }
- }
- }
- };
+ async $onInit() {
+ this.$state.go('client.card.summary', {id: this.$params.id});
+ window.location.href = await this.vnApp.getUrl(`Customer/${this.$params.id}/sms`);
}
}
diff --git a/modules/entry/back/models/buy.json b/modules/entry/back/models/buy.json
index 30379eaf6..fa804f4d8 100644
--- a/modules/entry/back/models/buy.json
+++ b/modules/entry/back/models/buy.json
@@ -1,6 +1,9 @@
{
"name": "Buy",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "buy"
diff --git a/modules/entry/back/models/entry-observation.json b/modules/entry/back/models/entry-observation.json
index cdf0c5e6e..6a1592037 100644
--- a/modules/entry/back/models/entry-observation.json
+++ b/modules/entry/back/models/entry-observation.json
@@ -1,6 +1,9 @@
{
"name": "EntryObservation",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "entryObservation"
diff --git a/modules/entry/back/models/entry.json b/modules/entry/back/models/entry.json
index a7508b4e8..0f3e389b6 100644
--- a/modules/entry/back/models/entry.json
+++ b/modules/entry/back/models/entry.json
@@ -1,6 +1,9 @@
{
"name": "Entry",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "entry"
diff --git a/modules/invoiceIn/back/locale/invoiceIn/en.yml b/modules/invoiceIn/back/locale/invoiceIn/en.yml
index ec9a824b6..9e94eba0d 100644
--- a/modules/invoiceIn/back/locale/invoiceIn/en.yml
+++ b/modules/invoiceIn/back/locale/invoiceIn/en.yml
@@ -16,5 +16,5 @@ columns:
bookEntried: book entried
isVatDeductible: is VAT deductible
withholdingSageFk: withholding
- expenceFkDeductible: expence deductible
+ expenseFkDeductible: expense deductible
editorFk: editor
\ No newline at end of file
diff --git a/modules/invoiceIn/back/locale/invoiceIn/es.yml b/modules/invoiceIn/back/locale/invoiceIn/es.yml
index 64e96b379..bd64c4327 100644
--- a/modules/invoiceIn/back/locale/invoiceIn/es.yml
+++ b/modules/invoiceIn/back/locale/invoiceIn/es.yml
@@ -16,5 +16,5 @@ columns:
bookEntried: fecha asiento
isVatDeductible: impuesto deducible
withholdingSageFk: código de retención
- expenceFkDeductible: gasto deducible
+ expenseFkDeductible: gasto deducible
editorFk: editor
\ No newline at end of file
diff --git a/modules/invoiceIn/back/locale/invoiceInTax/en.yml b/modules/invoiceIn/back/locale/invoiceInTax/en.yml
index c0d12c37d..6af547d3f 100644
--- a/modules/invoiceIn/back/locale/invoiceInTax/en.yml
+++ b/modules/invoiceIn/back/locale/invoiceInTax/en.yml
@@ -4,7 +4,7 @@ columns:
invoiceInFk: invoice in
taxCodeFk: tax
taxableBase: taxable base
- expenceFk: expence
+ expenseFk: expense
foreignValue: foreign amount
taxTypeSageFk: tax type
transactionTypeSageFk: transaction type
diff --git a/modules/invoiceIn/back/locale/invoiceInTax/es.yml b/modules/invoiceIn/back/locale/invoiceInTax/es.yml
index 7cb847ed8..92f3855e4 100644
--- a/modules/invoiceIn/back/locale/invoiceInTax/es.yml
+++ b/modules/invoiceIn/back/locale/invoiceInTax/es.yml
@@ -4,7 +4,7 @@ columns:
invoiceInFk: factura recibida
taxCodeFk: código IVA
taxableBase: base imponible
- expenceFk: código gasto
+ expenseFk: código gasto
foreignValue: importe divisa
taxTypeSageFk: código impuesto
transactionTypeSageFk: código transacción
diff --git a/modules/invoiceIn/back/methods/invoice-in/filter.js b/modules/invoiceIn/back/methods/invoice-in/filter.js
index f5eab9099..dd193af85 100644
--- a/modules/invoiceIn/back/methods/invoice-in/filter.js
+++ b/modules/invoiceIn/back/methods/invoice-in/filter.js
@@ -146,7 +146,7 @@ module.exports = Self => {
ii.docFk AS dmsFk,
dm.file,
ii.supplierFk,
- ii.expenceFkDeductible deductibleExpenseFk,
+ ii.expenseFkDeductible deductibleExpenseFk,
s.name AS supplierName,
s.account,
SUM(iid.amount) AS amount,
diff --git a/modules/invoiceIn/back/methods/invoice-in/summary.js b/modules/invoiceIn/back/methods/invoice-in/summary.js
index 0e55eeaac..fe198b2b4 100644
--- a/modules/invoiceIn/back/methods/invoice-in/summary.js
+++ b/modules/invoiceIn/back/methods/invoice-in/summary.js
@@ -112,7 +112,7 @@ module.exports = Self => {
{
relation: 'taxTypeSage',
scope: {
- fields: ['vat']
+ fields: ['vat', 'rate']
}
}]
}
diff --git a/modules/invoiceIn/back/models/invoice-in-tax.json b/modules/invoiceIn/back/models/invoice-in-tax.json
index 1f68476c3..53b5548b6 100644
--- a/modules/invoiceIn/back/models/invoice-in-tax.json
+++ b/modules/invoiceIn/back/models/invoice-in-tax.json
@@ -1,6 +1,9 @@
{
"name": "InvoiceInTax",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "invoiceInTax"
@@ -19,10 +22,7 @@
"type": "number"
},
"expenseFk": {
- "type": "number",
- "mysql": {
- "columnName": "expenceFk"
- }
+ "type": "number"
},
"created": {
"type": "date"
diff --git a/modules/invoiceIn/back/models/invoice-in.json b/modules/invoiceIn/back/models/invoice-in.json
index 754899866..59c179e76 100644
--- a/modules/invoiceIn/back/models/invoice-in.json
+++ b/modules/invoiceIn/back/models/invoice-in.json
@@ -1,6 +1,9 @@
{
"name": "InvoiceIn",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "invoiceIn"
@@ -51,7 +54,7 @@
"deductibleExpenseFk": {
"type": "number",
"mysql": {
- "columnName": "expenceFkDeductible"
+ "columnName": "expenseFkDeductible"
}
}
},
diff --git a/modules/invoiceOut/back/methods/invoiceOut/createManualInvoice.js b/modules/invoiceOut/back/methods/invoiceOut/createManualInvoice.js
index 18e6903d6..043dfbead 100644
--- a/modules/invoiceOut/back/methods/invoiceOut/createManualInvoice.js
+++ b/modules/invoiceOut/back/methods/invoiceOut/createManualInvoice.js
@@ -85,7 +85,7 @@ module.exports = Self => {
throw new UserError(`A ticket with an amount of zero can't be invoiced`);
// Validates ticket nagative base
- const hasNegativeBase = await getNegativeBase(ticketId, myOptions);
+ const hasNegativeBase = await getNegativeBase(maxShipped, clientId, companyId, myOptions);
if (hasNegativeBase && company.code == 'VNL')
throw new UserError(`A ticket with a negative base can't be invoiced`);
} else {
@@ -162,10 +162,13 @@ module.exports = Self => {
return result.invoiceable;
}
- async function getNegativeBase(ticketId, options) {
+ async function getNegativeBase(maxShipped, clientId, companyId, options) {
const models = Self.app.models;
- const query = 'SELECT vn.hasSomeNegativeBase(?) AS base';
- const [result] = await models.InvoiceOut.rawSql(query, [ticketId], options);
+ await models.InvoiceOut.rawSql('CALL invoiceOut_exportationFromClient(?,?,?)',
+ [maxShipped, clientId, companyId], options
+ );
+ const query = 'SELECT vn.hasAnyNegativeBase() AS base';
+ const [result] = await models.InvoiceOut.rawSql(query, [], options);
return result.base;
}
diff --git a/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js b/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js
index fa22dab1e..530b02353 100644
--- a/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js
+++ b/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js
@@ -80,6 +80,7 @@ module.exports = Self => {
invoiceType,
args.companyFk,
args.invoiceDate,
+ null,
options
);
diff --git a/modules/invoiceOut/back/methods/invoiceOut/negativeBases.js b/modules/invoiceOut/back/methods/invoiceOut/negativeBases.js
index ae9c404af..96c789316 100644
--- a/modules/invoiceOut/back/methods/invoiceOut/negativeBases.js
+++ b/modules/invoiceOut/back/methods/invoiceOut/negativeBases.js
@@ -90,7 +90,7 @@ module.exports = Self => {
AND t.refFk IS NULL
AND c.typeFk IN ('normal','trust')
GROUP BY t.clientFk, negativeBase.taxableBase
- HAVING amount <> 0`, [args.from, args.to]));
+ HAVING amount < 0`, [args.from, args.to]));
stmt = new ParameterizedSQL(`
SELECT f.*
diff --git a/modules/invoiceOut/back/methods/invoiceOut/negativeBasesCsv.js b/modules/invoiceOut/back/methods/invoiceOut/negativeBasesCsv.js
index d70a8fce5..87e9a67ea 100644
--- a/modules/invoiceOut/back/methods/invoiceOut/negativeBasesCsv.js
+++ b/modules/invoiceOut/back/methods/invoiceOut/negativeBasesCsv.js
@@ -10,13 +10,17 @@ module.exports = Self => {
type: 'date',
description: 'From date',
required: true
- },
- {
+ }, {
arg: 'to',
type: 'date',
description: 'To date',
required: true
- }],
+ }, {
+ arg: 'filter',
+ type: 'object',
+ description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string'
+ },
+ ],
returns: [
{
arg: 'body',
diff --git a/modules/invoiceOut/back/methods/invoiceOut/specs/transferinvoice.spec.js b/modules/invoiceOut/back/methods/invoiceOut/specs/transferinvoice.spec.js
index 800a4ea83..11575999a 100644
--- a/modules/invoiceOut/back/methods/invoiceOut/specs/transferinvoice.spec.js
+++ b/modules/invoiceOut/back/methods/invoiceOut/specs/transferinvoice.spec.js
@@ -2,7 +2,7 @@
const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
-describe('InvoiceOut tranferInvoice()', () => {
+describe('InvoiceOut transferInvoice()', () => {
const activeCtx = {
accessToken: {userId: 5},
http: {
@@ -23,20 +23,29 @@ describe('InvoiceOut tranferInvoice()', () => {
const tx = await models.InvoiceOut.beginTransaction({});
const options = {transaction: tx};
const args = {
- id: '1',
- ref: 'T4444444',
+ id: '4',
+ refFk: 'T4444444',
newClientFk: 1,
- cplusRectificationId: 1,
- siiTypeInvoiceOutId: 1,
- invoiceCorrectionTypeId: 1
+ cplusRectificationTypeFk: 1,
+ siiTypeInvoiceOutFk: 1,
+ invoiceCorrectionTypeFk: 1
};
ctx.args = args;
try {
+ const {clientFk: oldClient} = await models.InvoiceOut.findById(args.id, {fields: ['clientFk']});
+ const invoicesBefore = await models.InvoiceOut.find({}, options);
const result = await models.InvoiceOut.transferInvoice(
ctx,
options);
+ const invoicesAfter = await models.InvoiceOut.find({}, options);
+ const rectificativeInvoice = invoicesAfter[invoicesAfter.length - 2];
+ const newInvoice = invoicesAfter[invoicesAfter.length - 1];
expect(result).toBeDefined();
+ expect(invoicesAfter.length - invoicesBefore.length).toEqual(2);
+ expect(rectificativeInvoice.clientFk).toEqual(oldClient);
+ expect(newInvoice.clientFk).toEqual(args.newClientFk);
+
await tx.rollback();
} catch (e) {
await tx.rollback();
@@ -49,20 +58,44 @@ describe('InvoiceOut tranferInvoice()', () => {
const options = {transaction: tx};
const args = {
id: '1',
- ref: 'T1111111',
+ refFk: 'T1111111',
newClientFk: 1101,
- cplusRectificationId: 1,
- siiTypeInvoiceOutId: 1,
- invoiceCorrectionTypeId: 1
+ cplusRectificationTypeFk: 1,
+ siiTypeInvoiceOutFk: 1,
+ invoiceCorrectionTypeFk: 1
};
ctx.args = args;
try {
await models.InvoiceOut.transferInvoice(
ctx,
options);
+ await tx.rollback();
} catch (e) {
expect(e.message).toBe(`Select a different client`);
await tx.rollback();
}
});
+
+ it('should throw an UserError when it is refund', async() => {
+ const tx = await models.InvoiceOut.beginTransaction({});
+ const options = {transaction: tx};
+ const args = {
+ id: '1',
+ refFk: 'T1111111',
+ newClientFk: 1102,
+ cplusRectificationTypeFk: 1,
+ siiTypeInvoiceOutFk: 1,
+ invoiceCorrectionTypeFk: 1
+ };
+ ctx.args = args;
+ try {
+ await models.InvoiceOut.transferInvoice(
+ ctx,
+ options);
+ await tx.rollback();
+ } catch (e) {
+ expect(e.message).toContain(`This ticket is already a refund`);
+ await tx.rollback();
+ }
+ });
});
diff --git a/modules/invoiceOut/back/methods/invoiceOut/transferInvoice.js b/modules/invoiceOut/back/methods/invoiceOut/transferInvoice.js
index dde535c99..5f2428539 100644
--- a/modules/invoiceOut/back/methods/invoiceOut/transferInvoice.js
+++ b/modules/invoiceOut/back/methods/invoiceOut/transferInvoice.js
@@ -12,7 +12,7 @@ module.exports = Self => {
description: 'Issued invoice id'
},
{
- arg: 'ref',
+ arg: 'refFk',
type: 'string',
required: true
},
@@ -22,17 +22,17 @@ module.exports = Self => {
required: true
},
{
- arg: 'cplusRectificationId',
+ arg: 'cplusRectificationTypeFk',
type: 'number',
required: true
},
{
- arg: 'siiTypeInvoiceOutId',
+ arg: 'siiTypeInvoiceOutFk',
type: 'number',
required: true
},
{
- arg: 'invoiceCorrectionTypeId',
+ arg: 'invoiceCorrectionTypeFk',
type: 'number',
required: true
},
@@ -50,14 +50,14 @@ module.exports = Self => {
Self.transferInvoice = async(ctx, options) => {
const models = Self.app.models;
const myOptions = {userId: ctx.req.accessToken.userId};
- const args = ctx.args;
+ const {id, refFk, newClientFk, cplusRectificationTypeFk, siiTypeInvoiceOutFk, invoiceCorrectionTypeFk} = ctx.args;
let tx;
if (typeof options == 'object')
Object.assign(myOptions, options);
- const {clientFk} = await models.InvoiceOut.findById(args.id);
+ const {clientFk} = await models.InvoiceOut.findById(id);
- if (clientFk == args.newClientFk)
+ if (clientFk == newClientFk)
throw new UserError(`Select a different client`);
if (!myOptions.transaction) {
@@ -65,10 +65,10 @@ module.exports = Self => {
myOptions.transaction = tx;
}
try {
- const filterRef = {where: {refFk: args.ref}};
+ const filterRef = {where: {refFk: refFk}};
const tickets = await models.Ticket.find(filterRef, myOptions);
const ticketsIds = tickets.map(ticket => ticket.id);
- await models.Ticket.refund(ctx, ticketsIds, null, myOptions);
+ const refundTickets = await models.Ticket.refund(ctx, ticketsIds, null, myOptions);
const filterTicket = {where: {ticketFk: {inq: ticketsIds}}};
@@ -82,20 +82,16 @@ module.exports = Self => {
const clonedTicketIds = [];
for (const clonedTicket of clonedTickets) {
- await clonedTicket.updateAttribute('clientFk', args.newClientFk, myOptions);
+ await clonedTicket.updateAttribute('clientFk', newClientFk, myOptions);
clonedTicketIds.push(clonedTicket.id);
}
- const invoiceIds = await models.Ticket.invoiceTickets(ctx, clonedTicketIds, myOptions);
- const [invoiceId] = invoiceIds;
+ const invoiceCorrection =
+ {correctedFk: id, cplusRectificationTypeFk, siiTypeInvoiceOutFk, invoiceCorrectionTypeFk};
+ const refundTicketIds = refundTickets.map(ticket => ticket.id);
- await models.InvoiceCorrection.create({
- correctingFk: invoiceId,
- correctedFk: args.id,
- cplusRectificationTypeFk: args.cplusRectificationId,
- siiTypeInvoiceOutFk: args.siiTypeInvoiceOutId,
- invoiceCorrectionTypeFk: args.invoiceCorrectionTypeId
- }, myOptions);
+ await models.Ticket.invoiceTickets(ctx, refundTicketIds, invoiceCorrection, myOptions);
+ const [invoiceId] = await models.Ticket.invoiceTickets(ctx, clonedTicketIds, null, myOptions);
if (tx) {
await tx.commit();
diff --git a/modules/invoiceOut/back/models/invoice-correction.json b/modules/invoiceOut/back/models/invoice-correction.json
index 43e4f07ef..58f6f63b7 100644
--- a/modules/invoiceOut/back/models/invoice-correction.json
+++ b/modules/invoiceOut/back/models/invoice-correction.json
@@ -16,13 +16,43 @@
"type": "number"
},
"cplusRectificationTypeFk": {
- "type": "number"
+ "type": "number",
+ "required": true
},
"siiTypeInvoiceOutFk": {
- "type": "number"
+ "type": "number",
+ "required": true
},
"invoiceCorrectionTypeFk": {
- "type": "number"
+ "type": "number",
+ "required": true
+ },
+ "relations": {
+ "correcting": {
+ "type": "belongsTo",
+ "model": "InvoiceOut",
+ "foreignKey": "correctingFk"
+ },
+ "corrected": {
+ "type": "belongsTo",
+ "model": "InvoiceOut",
+ "foreignKey": "correctedFk"
+ },
+ "cplusRectificationType": {
+ "type": "belongsTo",
+ "model": "cplusRectificationType",
+ "foreignKey": "cplusRectificationTypeFk"
+ },
+ "siiTypeInvoiceOut": {
+ "type": "belongsTo",
+ "model": "siiTypeInvoiceOut",
+ "foreignKey": "siiTypeInvoiceOutFk"
+ },
+ "invoiceCorrectionType": {
+ "type": "belongsTo",
+ "model": "invoiceCorrectionType",
+ "foreignKey": "invoiceCorrectionTypeFk"
+ }
}
}
}
diff --git a/modules/invoiceOut/back/models/sii-type-invoice-out.json b/modules/invoiceOut/back/models/sii-type-invoice-out.json
index 17b312617..58d50a12c 100644
--- a/modules/invoiceOut/back/models/sii-type-invoice-out.json
+++ b/modules/invoiceOut/back/models/sii-type-invoice-out.json
@@ -12,6 +12,9 @@
"type": "number",
"description": "Identifier"
},
+ "code": {
+ "type": "string"
+ },
"description": {
"type": "string"
}
diff --git a/modules/invoiceOut/front/descriptor-menu/index.html b/modules/invoiceOut/front/descriptor-menu/index.html
index 0052f0c03..435db3612 100644
--- a/modules/invoiceOut/front/descriptor-menu/index.html
+++ b/modules/invoiceOut/front/descriptor-menu/index.html
@@ -7,7 +7,8 @@
+ data="siiTypeInvoiceOuts"
+ where="{code: {like: 'R%'}}">
+
+ transferInvoice
+
-
-
-
- #{{id}} - {{::name}}
-
-
-
-
- {{::description}}
-
-
-
-
-
-
-
-
-
-
+
+
+
+ #{{id}} - {{::name}}
+
+
+
+
+ {{::description}}
+
+
+
+
+
+
+ {{::code}} - {{::description}}
+
+
+
+
+
+
diff --git a/modules/invoiceOut/front/descriptor-menu/index.js b/modules/invoiceOut/front/descriptor-menu/index.js
index d3862a753..2c28599e7 100644
--- a/modules/invoiceOut/front/descriptor-menu/index.js
+++ b/modules/invoiceOut/front/descriptor-menu/index.js
@@ -129,15 +129,15 @@ class Controller extends Section {
transferInvoice() {
const params = {
id: this.invoiceOut.id,
- ref: this.invoiceOut.ref,
- newClientFk: this.invoiceOut.client.id,
- cplusRectificationId: this.cplusRectificationType,
- siiTypeInvoiceOutId: this.siiTypeInvoiceOut,
- invoiceCorrectionTypeId: this.invoiceCorrectionType
+ refFk: this.invoiceOut.ref,
+ newClientFk: this.clientId,
+ cplusRectificationTypeFk: this.cplusRectificationType,
+ siiTypeInvoiceOutFk: this.siiTypeInvoiceOut,
+ invoiceCorrectionTypeFk: this.invoiceCorrectionType
};
this.$http.post(`InvoiceOuts/transferInvoice`, params).then(res => {
const invoiceId = res.data;
- this.vnApp.showSuccess(this.$t('Invoice trasfered!'));
+ this.vnApp.showSuccess(this.$t('Transferred invoice'));
this.$state.go('invoiceOut.card.summary', {id: invoiceId});
});
}
diff --git a/modules/invoiceOut/front/descriptor-menu/locale/es.yml b/modules/invoiceOut/front/descriptor-menu/locale/es.yml
index 0f74b5fec..aaeefd9cc 100644
--- a/modules/invoiceOut/front/descriptor-menu/locale/es.yml
+++ b/modules/invoiceOut/front/descriptor-menu/locale/es.yml
@@ -22,4 +22,5 @@ The email can't be empty: El correo no puede estar vacío
The following refund tickets have been created: "Se han creado los siguientes tickets de abono: {{ticketIds}}"
Refund...: Abono...
Transfer invoice to...: Transferir factura a...
-Cplus Type: Cplus Tipo
+Rectificative type: Tipo rectificativa
+Transferred invoice: Factura transferida
diff --git a/modules/invoiceOut/front/index/manual/index.html b/modules/invoiceOut/front/index/manual/index.html
index c3362a319..5872911e4 100644
--- a/modules/invoiceOut/front/index/manual/index.html
+++ b/modules/invoiceOut/front/index/manual/index.html
@@ -6,6 +6,7 @@
auto-load="true"
url="InvoiceOutSerials"
data="invoiceOutSerials"
+ where="{code: {neq: 'R'}}"
order="code">
diff --git a/modules/monitor/back/methods/sales-monitor/specs/salesFilter.spec.js b/modules/monitor/back/methods/sales-monitor/specs/salesFilter.spec.js
index c3da7f08b..bdafd14e2 100644
--- a/modules/monitor/back/methods/sales-monitor/specs/salesFilter.spec.js
+++ b/modules/monitor/back/methods/sales-monitor/specs/salesFilter.spec.js
@@ -151,7 +151,7 @@ describe('SalesMonitor salesFilter()', () => {
const result = await models.SalesMonitor.salesFilter(ctx, filter, options);
const firstRow = result[0];
- expect(result.length).toEqual(15);
+ expect(result.length).toEqual(12);
expect(firstRow.alertLevel).not.toEqual(0);
await tx.rollback();
diff --git a/modules/route/back/locale/route/en.yml b/modules/route/back/locale/route/en.yml
index 96aaddb72..d86cbe342 100644
--- a/modules/route/back/locale/route/en.yml
+++ b/modules/route/back/locale/route/en.yml
@@ -17,3 +17,18 @@ columns:
agencyModeFk: agency
routeFk: route
zoneFk: zone
+ name: name
+ beachFk: beach
+ ticketPacked: tickets packed
+ ticketFree: tickets free
+ ticketProduction: tickets production
+ packages: packages
+ note: note
+ dated: dated
+ dockFk: dock
+ priority: priority
+ etd: etd
+ expeditionTruckFk: truck
+ m3boxes: m3 boxes
+ bufferFk: buffer
+ isPickingAllowed: is picking allowed
\ No newline at end of file
diff --git a/modules/route/back/locale/route/es.yml b/modules/route/back/locale/route/es.yml
index c0a434791..baefb6433 100644
--- a/modules/route/back/locale/route/es.yml
+++ b/modules/route/back/locale/route/es.yml
@@ -17,3 +17,18 @@ columns:
agencyModeFk: agencia
routeFk: ruta
zoneFk: zona
+ name: nombre
+ beachFk: playa
+ ticketPacked: tickets encajados
+ ticketFree: tickets libres
+ ticketProduction: tickets producción
+ packages: paquetes
+ note: nota
+ dated: fecha
+ dockFk: muelle
+ priority: prioridad
+ etd: etd
+ expeditionTruckFk: camión
+ m3boxes: m3 cajas
+ bufferFk: buffer
+ isPickingAllowed: está permitido recoger
\ No newline at end of file
diff --git a/modules/route/back/methods/agency-term/createInvoiceIn.js b/modules/route/back/methods/agency-term/createInvoiceIn.js
index 5a8430e49..f00ab95c6 100644
--- a/modules/route/back/methods/agency-term/createInvoiceIn.js
+++ b/modules/route/back/methods/agency-term/createInvoiceIn.js
@@ -54,7 +54,7 @@ module.exports = Self => {
dmsFk: firstDms.id,
}, myOptions);
- const expence = await models.AgencyTermConfig.findOne(null, myOptions);
+ const expense = await models.AgencyTermConfig.findOne(null, myOptions);
const [taxTypeSage] = await Self.rawSql(`
SELECT IFNULL(s.taxTypeSageFk, CodigoIva) value
@@ -78,7 +78,7 @@ module.exports = Self => {
await models.InvoiceInTax.create({
invoiceInFk: newInvoiceIn.id,
taxableBase: firstRow.totalPrice,
- expenseFk: expence.expenceFk,
+ expenseFk: expense.expenseFk,
taxTypeSageFk: taxTypeSage.value,
transactionTypeSageFk: transactionTypeSage.value
}, myOptions);
diff --git a/modules/route/back/methods/route/filter.js b/modules/route/back/methods/route/filter.js
index afefa77d1..7c2225dc9 100644
--- a/modules/route/back/methods/route/filter.js
+++ b/modules/route/back/methods/route/filter.js
@@ -130,13 +130,15 @@ module.exports = Self => {
am.name agencyName,
u.name AS workerUserName,
v.numberPlate AS vehiclePlateNumber,
- Date_format(r.time, '%H:%i') hour
+ Date_format(r.time, '%H:%i') hour,
+ eu.email
FROM route r
LEFT JOIN agencyMode am ON am.id = r.agencyModeFk
LEFT JOIN agency a ON a.id = am.agencyFk
LEFT JOIN vehicle v ON v.id = r.vehicleFk
LEFT JOIN worker w ON w.id = r.workerFk
- LEFT JOIN account.user u ON u.id = w.id`
+ LEFT JOIN account.user u ON u.id = w.id
+ LEFT JOIN account.emailUser eu ON eu.userFk = r.workerFk`
);
stmt.merge(conn.makeSuffix(filter));
diff --git a/modules/route/back/methods/route/getExpeditionSummary.js b/modules/route/back/methods/route/getExpeditionSummary.js
new file mode 100644
index 000000000..ee89401a8
--- /dev/null
+++ b/modules/route/back/methods/route/getExpeditionSummary.js
@@ -0,0 +1,64 @@
+module.exports = Self => {
+ Self.remoteMethod('getExpeditionSummary', {
+ description: 'Get summary of expeditions for a given route',
+ accepts: [
+ {
+ arg: 'routeFk',
+ type: 'number',
+ required: true,
+ description: 'Foreign key for Route'
+ }
+ ],
+ returns: {
+ type: 'object',
+ root: true
+ },
+ http: {
+ path: '/getExpeditionSummary',
+ verb: 'get'
+ }
+ });
+
+ Self.getExpeditionSummary = async(routeFk, options) => {
+ const myOptions = {};
+
+ if (typeof options == 'object')
+ Object.assign(myOptions, options);
+
+ const query = `
+ SELECT routeFk,
+ addressFk,
+ SUM(total) total,
+ SUM(delivery) delivery,
+ SUM(lost) lost,
+ SUM(delivered) delivered,
+ GROUP_CONCAT(totalPacking ORDER BY total DESC SEPARATOR ' ') itemPackingType
+ FROM (
+ SELECT r.id AS routeFk,
+ t.addressFk,
+ CONCAT (IFNULL(e.itemPackingTypeFk,'-'), '', COUNT(*)) totalPacking,
+ COUNT(*) total,
+ SUM(est.code = 'ON DELIVERY') delivery,
+ SUM(est.code = 'LOST') lost,
+ SUM(est.code = 'DELIVERED') delivered,
+ t.priority
+ FROM vn.ticket t
+ JOIN vn.route r ON r.id = t.routeFk
+ JOIN vn.expedition e ON e.ticketFk = t.id
+ LEFT JOIN vn.expeditionStateType est ON est.id = e.stateTypeFk
+ JOIN vn.agencyMode am ON am.id = r.agencyModeFk
+ JOIN vn.agency ag ON ag.id = am.agencyFk
+ LEFT JOIN vn.userConfig uc ON uc.userFk = account.myUser_getId()
+ WHERE (r.created = util.VN_CURDATE() OR r.created = util.yesterday())
+ AND t.routeFk = ?
+ GROUP BY t.addressFk, e.itemPackingTypeFk
+ ) sub
+ GROUP BY addressFk
+ ORDER BY priority DESC
+ `;
+
+ const results = await Self.rawSql(query, [routeFk], myOptions);
+ return results;
+ };
+};
+
diff --git a/modules/route/back/methods/route/getExternalCmrs.js b/modules/route/back/methods/route/getExternalCmrs.js
index 4750e53a1..3fc9798b0 100644
--- a/modules/route/back/methods/route/getExternalCmrs.js
+++ b/modules/route/back/methods/route/getExternalCmrs.js
@@ -3,99 +3,101 @@ const buildFilter = require('vn-loopback/util/filter').buildFilter;
const mergeFilters = require('vn-loopback/util/filter').mergeFilters;
module.exports = Self => {
- Self.remoteMethod('getExternalCmrs', {
- description: 'Returns an array of external cmrs',
- accessType: 'READ',
- accepts: [
- {
- arg: 'filter',
- type: 'object',
- description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string',
- },
- {
- arg: 'cmrFk',
- type: 'integer',
- description: 'Searchs the route by id',
- },
- {
- arg: 'ticketFk',
- type: 'integer',
- description: 'The worker id',
- },
- {
- arg: 'routeFk',
- type: 'integer',
- description: 'The route id',
- },
- {
- arg: 'country',
- type: 'string',
- description: 'The agencyMode id',
- },
- {
- arg: 'clientFk',
- type: 'integer',
- description: 'The vehicle id',
- },
- {
- arg: 'hasCmrDms',
- type: 'boolean',
- description: 'The vehicle id',
- },
- {
- arg: 'shipped',
- type: 'date',
- description: 'The to date filter',
- },
- ],
- returns: {
- type: ['object'],
- root: true
- },
- http: {
- path: `/getExternalCmrs`,
- verb: 'GET'
- }
- });
+ Self.remoteMethod('getExternalCmrs', {
+ description: 'Returns an array of external cmrs',
+ accessType: 'READ',
+ accepts: [
+ {
+ arg: 'filter',
+ type: 'object',
+ description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string',
+ },
+ {
+ arg: 'cmrFk',
+ type: 'integer',
+ description: 'Searchs the route by id',
+ },
+ {
+ arg: 'ticketFk',
+ type: 'integer',
+ description: 'The worker id',
+ },
+ {
+ arg: 'routeFk',
+ type: 'integer',
+ description: 'The route id',
+ },
+ {
+ arg: 'country',
+ type: 'string',
+ description: 'The agencyMode id',
+ },
+ {
+ arg: 'clientFk',
+ type: 'integer',
+ description: 'The vehicle id',
+ },
+ {
+ arg: 'hasCmrDms',
+ type: 'boolean',
+ description: 'The vehicle id',
+ },
+ {
+ arg: 'shipped',
+ type: 'date',
+ description: 'The to date filter',
+ },
+ ],
+ returns: {
+ type: ['object'],
+ root: true
+ },
+ http: {
+ path: `/getExternalCmrs`,
+ verb: 'GET'
+ }
+ });
- Self.getExternalCmrs = async(
- filter,
- cmrFk,
- ticketFk,
- routeFk,
- country,
- clientFk,
- hasCmrDms,
- shipped,
- options
- ) => {
- const params = {
- cmrFk,
- ticketFk,
- routeFk,
- country,
- clientFk,
- hasCmrDms,
- shipped,
- };
- const conn = Self.dataSource.connector;
+ Self.getExternalCmrs = async(
+ filter,
+ cmrFk,
+ ticketFk,
+ routeFk,
+ country,
+ clientFk,
+ hasCmrDms,
+ shipped,
+ options
+ ) => {
+ const params = {
+ cmrFk,
+ ticketFk,
+ routeFk,
+ country,
+ clientFk,
+ hasCmrDms,
+ shipped,
+ };
+ const conn = Self.dataSource.connector;
- let where = buildFilter(params, (param, value) => {return {[param]: value}});
- filter = mergeFilters(filter, {where});
+ let where = buildFilter(params, (param, value) => {
+ return {[param]: value};
+ });
+ filter = mergeFilters(filter, {where});
- if (!filter.where) {
- const yesterday = new Date();
- yesterday.setDate(yesterday.getDate() - 1);
- filter.where = {'shipped': yesterday.toISOString().split('T')[0]}
- }
+ if (!filter.where) {
+ const yesterday = new Date();
+ yesterday.setDate(yesterday.getDate() - 1);
+ filter.where = {'shipped': yesterday.toISOString().split('T')[0]};
+ }
- const myOptions = {};
+ const myOptions = {};
- if (typeof options == 'object')
- Object.assign(myOptions, options);
+ if (typeof options == 'object')
+ Object.assign(myOptions, options);
- let stmts = [];
- const stmt = new ParameterizedSQL(`
+ let stmts = [];
+ const stmt = new ParameterizedSQL(`
SELECT *
FROM (
SELECT t.cmrFk,
@@ -129,13 +131,13 @@ module.exports = Self => {
AND dm.code = 'DELIVERY'
AND t.cmrFk
) sub
- `);
+ `);
- stmt.merge(conn.makeSuffix(filter));
- const itemsIndex = stmts.push(stmt) - 1;
+ stmt.merge(conn.makeSuffix(filter));
+ const itemsIndex = stmts.push(stmt) - 1;
- const sql = ParameterizedSQL.join(stmts, ';');
- const result = await conn.executeStmt(sql);
- return itemsIndex === 0 ? result : result[itemsIndex];
- };
+ const sql = ParameterizedSQL.join(stmts, ';');
+ const result = await conn.executeStmt(sql);
+ return itemsIndex === 0 ? result : result[itemsIndex];
+ };
};
diff --git a/modules/route/back/methods/route/getTickets.js b/modules/route/back/methods/route/getTickets.js
index 1eb9e27f5..d1ebf9ee7 100644
--- a/modules/route/back/methods/route/getTickets.js
+++ b/modules/route/back/methods/route/getTickets.js
@@ -3,7 +3,7 @@ const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
module.exports = Self => {
Self.remoteMethod('getTickets', {
- description: 'Return the tickets information displayed on the route module',
+ description: 'Find all instances of the model matched by filter from the data source.',
accessType: 'READ',
accepts: [
{
@@ -40,22 +40,32 @@ module.exports = Self => {
t.clientFk,
t.priority,
t.addressFk,
- st.code AS ticketStateCode,
- st.name AS ticketStateName,
- wh.name AS warehouseName,
- tob.description AS ticketObservation,
+ st.code ticketStateCode,
+ st.name ticketStateName,
+ wh.name warehouseName,
+ tob.description ticketObservation,
a.street,
a.postalCode,
a.city,
- am.name AS agencyModeName,
- u.nickname AS userNickname,
- vn.ticketTotalVolume(t.id) AS volume,
+ am.name agencyModeName,
+ u.nickname userNickname,
+ vn.ticketTotalVolume(t.id) volume,
tob.description,
- GROUP_CONCAT(DISTINCT i.itemPackingTypeFk ORDER BY i.itemPackingTypeFk) ipt
+ GROUP_CONCAT(DISTINCT i.itemPackingTypeFk ORDER BY i.itemPackingTypeFk) ipt,
+ c.phone clientPhone,
+ c.mobile clientMobile,
+ a.phone addressPhone,
+ a.mobile addressMobile,
+ a.longitude,
+ a.latitude,
+ wm.mediaValue salePersonPhone,
+ t.cmrFk,
+ t.isSigned signed
FROM vn.route r
JOIN ticket t ON t.routeFk = r.id
- JOIN vn.sale s ON s.ticketFk = t.id
- JOIN vn.item i ON i.id = s.itemFk
+ JOIN client c ON t.clientFk = c.id
+ LEFT JOIN vn.sale s ON s.ticketFk = t.id
+ LEFT JOIN vn.item i ON i.id = s.itemFk
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
@@ -65,7 +75,8 @@ module.exports = Self => {
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`
+ LEFT JOIN vehicle v ON v.id = r.vehicleFk
+ LEFT JOIN workerMedia wm ON wm.workerFk = c.salesPersonFk`
);
if (!filter.where) filter.where = {};
diff --git a/modules/route/back/methods/route/specs/getExpeditionSummary.spec.js b/modules/route/back/methods/route/specs/getExpeditionSummary.spec.js
new file mode 100644
index 000000000..9d70c339a
--- /dev/null
+++ b/modules/route/back/methods/route/specs/getExpeditionSummary.spec.js
@@ -0,0 +1,10 @@
+const app = require('vn-loopback/server/server');
+
+describe('route getExpeditionSummary()', () => {
+ const routeId = 1;
+ it('should return a summary of expeditions for a route', async() => {
+ const result = await app.models.Route.getExpeditionSummary(routeId);
+
+ expect(result.every(route => route.id = routeId)).toBeTruthy();
+ });
+});
diff --git a/modules/route/back/models/agency-term-config.json b/modules/route/back/models/agency-term-config.json
index c94fc266b..81a608acf 100644
--- a/modules/route/back/models/agency-term-config.json
+++ b/modules/route/back/models/agency-term-config.json
@@ -7,7 +7,7 @@
}
},
"properties": {
- "expenceFk": {
+ "expenseFk": {
"type": "string",
"id": true
},
diff --git a/modules/route/back/models/route.js b/modules/route/back/models/route.js
index cbdd75679..9b5f3564f 100644
--- a/modules/route/back/models/route.js
+++ b/modules/route/back/models/route.js
@@ -17,6 +17,7 @@ module.exports = Self => {
require('../methods/route/cmr')(Self);
require('../methods/route/getExternalCmrs')(Self);
require('../methods/route/downloadCmrsZip')(Self);
+ require('../methods/route/getExpeditionSummary')(Self);
require('../methods/route/getByWorker')(Self);
Self.validate('kmStart', validateDistance, {
diff --git a/modules/route/back/models/route.json b/modules/route/back/models/route.json
index cdb64dd71..f8be9023c 100644
--- a/modules/route/back/models/route.json
+++ b/modules/route/back/models/route.json
@@ -1,6 +1,9 @@
{
"name": "Route",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "route"
diff --git a/modules/shelving/back/models/sector.json b/modules/shelving/back/models/sector.json
index 47d66bd8d..5ff67491b 100644
--- a/modules/shelving/back/models/sector.json
+++ b/modules/shelving/back/models/sector.json
@@ -20,18 +20,10 @@
"type": "number",
"required": true
},
- "isPreviousPreparedByPacking": {
- "type": "boolean",
- "required": true
- },
"code": {
"type": "string",
"required": false
},
- "isPreviousPrepared": {
- "type": "boolean",
- "required": true
- },
"isPackagingArea": {
"type": "boolean",
"required": true
diff --git a/modules/shelving/back/models/shelving.json b/modules/shelving/back/models/shelving.json
index 3103b5a4a..46fce31e8 100644
--- a/modules/shelving/back/models/shelving.json
+++ b/modules/shelving/back/models/shelving.json
@@ -1,6 +1,9 @@
{
"name": "Shelving",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "shelving"
diff --git a/modules/supplier/back/models/supplier-account.json b/modules/supplier/back/models/supplier-account.json
index bc9cf0e24..460c435e2 100644
--- a/modules/supplier/back/models/supplier-account.json
+++ b/modules/supplier/back/models/supplier-account.json
@@ -1,6 +1,9 @@
{
"name": "SupplierAccount",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "supplierAccount"
diff --git a/modules/supplier/back/models/supplier-address.json b/modules/supplier/back/models/supplier-address.json
index 001b3a31f..fcd599287 100644
--- a/modules/supplier/back/models/supplier-address.json
+++ b/modules/supplier/back/models/supplier-address.json
@@ -1,7 +1,10 @@
{
"name": "SupplierAddress",
"description": "Supplier addresses",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "supplierAddress"
diff --git a/modules/supplier/back/models/supplier-contact.json b/modules/supplier/back/models/supplier-contact.json
index f928cd204..4ea1b8c2a 100644
--- a/modules/supplier/back/models/supplier-contact.json
+++ b/modules/supplier/back/models/supplier-contact.json
@@ -1,6 +1,9 @@
{
"name": "SupplierContact",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "supplierContact"
diff --git a/modules/supplier/back/models/supplier.json b/modules/supplier/back/models/supplier.json
index b6245ef32..59d23f106 100644
--- a/modules/supplier/back/models/supplier.json
+++ b/modules/supplier/back/models/supplier.json
@@ -1,6 +1,9 @@
{
"name": "Supplier",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "supplier"
diff --git a/modules/ticket/back/methods/boxing/specs/getVideo.spec.js b/modules/ticket/back/methods/boxing/specs/getVideo.spec.js
deleted file mode 100644
index 8e8cdc5b9..000000000
--- a/modules/ticket/back/methods/boxing/specs/getVideo.spec.js
+++ /dev/null
@@ -1,40 +0,0 @@
-const models = require('vn-loopback/server/server').models;
-const https = require('https');
-
-xdescribe('boxing getVideo()', () => {
- it('should return data', async() => {
- const tx = await models.PackingSiteConfig.beginTransaction({});
-
- try {
- const options = {transaction: tx};
-
- const id = 1;
- const video = 'video.mp4';
-
- const response = {
- pipe: () => {},
- on: () => {},
- end: () => {},
- };
-
- const req = {
- headers: 'apiHeader',
- data: {
- pipe: () => {},
- on: () => {},
- }
- };
-
- spyOn(https, 'request').and.returnValue(response);
-
- const result = await models.Boxing.getVideo(id, video, req, null, options);
-
- expect(result[0]).toEqual(response.data.videos[0].filename);
-
- await tx.rollback();
- } catch (e) {
- await tx.rollback();
- throw e;
- }
- });
-});
diff --git a/modules/ticket/back/methods/expedition/deleteExpeditions.js b/modules/ticket/back/methods/expedition/deleteExpeditions.js
index 2419d3a5e..55ca474d7 100644
--- a/modules/ticket/back/methods/expedition/deleteExpeditions.js
+++ b/modules/ticket/back/methods/expedition/deleteExpeditions.js
@@ -1,6 +1,7 @@
+const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
- Self.remoteMethod('deleteExpeditions', {
+ Self.remoteMethodCtx('deleteExpeditions', {
description: 'Delete the selected expeditions',
accessType: 'WRITE',
accepts: [{
@@ -9,44 +10,59 @@ module.exports = Self => {
required: true,
description: 'The expeditions ids to delete'
}],
- returns: {
- type: ['object'],
- root: true
- },
http: {
path: `/deleteExpeditions`,
verb: 'POST'
+ },
+ returns: {
+ type: ['object'],
+ root: true
}
});
- Self.deleteExpeditions = async(expeditionIds, options) => {
+ Self.deleteExpeditions = async(ctx, expeditionIds) => {
const models = Self.app.models;
- const myOptions = {};
- let tx;
+ const $t = ctx.req.__;
+ const notDeletedExpeditions = [];
+ const deletedExpeditions = [];
- if (typeof options == 'object')
- Object.assign(myOptions, options);
+ for (let expeditionId of expeditionIds) {
+ const filter = {
+ fields: [],
+ where: {
+ id: expeditionId
+ },
+ include: [
+ {
+ relation: 'agencyMode',
+ scope: {
+ fields: ['code'],
+ }
+ }
+ ]
+ };
- if (!myOptions.transaction) {
- tx = await Self.beginTransaction({});
- myOptions.transaction = tx;
- }
+ const expedition = await models.Expedition.findOne(filter);
+ const {code} = expedition.agencyMode();
- try {
- const promises = [];
- for (let expeditionId of expeditionIds) {
- const deletedExpedition = models.Expedition.destroyById(expeditionId, myOptions);
- promises.push(deletedExpedition);
+ if (code && code.toLowerCase().substring(0, 10) == 'viaexpress') {
+ const isDeleted = await models.ViaexpressConfig.deleteExpedition(expeditionId);
+
+ if (isDeleted === 'true') {
+ const deletedExpedition = await models.Expedition.destroyById(expeditionId);
+ deletedExpeditions.push(deletedExpedition);
+ } else notDeletedExpeditions.push(expeditionId);
+ } else {
+ const deletedExpedition = await models.Expedition.destroyById(expeditionId);
+ deletedExpeditions.push(deletedExpedition);
}
-
- const deletedExpeditions = await Promise.all(promises);
-
- if (tx) await tx.commit();
-
- return deletedExpeditions;
- } catch (e) {
- if (tx) await tx.rollback();
- throw e;
}
+
+ if (notDeletedExpeditions.length) {
+ throw new UserError(
+ $t(`It was not able to remove the next expeditions:`, {expeditions: notDeletedExpeditions.join()})
+ );
+ }
+ return deletedExpeditions;
};
};
diff --git a/modules/ticket/back/methods/expedition/specs/deleteExpeditions.spec.js b/modules/ticket/back/methods/expedition/specs/deleteExpeditions.spec.js
index 61937989e..bf8bafe34 100644
--- a/modules/ticket/back/methods/expedition/specs/deleteExpeditions.spec.js
+++ b/modules/ticket/back/methods/expedition/specs/deleteExpeditions.spec.js
@@ -2,17 +2,16 @@ const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('ticket deleteExpeditions()', () => {
+ let ctx;
beforeAll(async() => {
- const activeCtx = {
+ ctx = {
accessToken: {userId: 9},
- http: {
- req: {
- headers: {origin: 'http://localhost'}
- }
+ req: {
+ headers: {origin: 'http://localhost'}
}
};
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
- active: activeCtx
+ active: ctx
});
});
@@ -23,7 +22,7 @@ describe('ticket deleteExpeditions()', () => {
const options = {transaction: tx};
const expeditionIds = [12, 13];
- const result = await models.Expedition.deleteExpeditions(expeditionIds, options);
+ const result = await models.Expedition.deleteExpeditions(ctx, expeditionIds, options);
expect(result.length).toEqual(2);
diff --git a/modules/ticket/back/methods/sale/refund.js b/modules/ticket/back/methods/sale/refund.js
index 17b70f12b..a7831e7e3 100644
--- a/modules/ticket/back/methods/sale/refund.js
+++ b/modules/ticket/back/methods/sale/refund.js
@@ -19,7 +19,7 @@ module.exports = Self => {
}
],
returns: {
- type: ['number'],
+ type: ['object'],
root: true
},
http: {
@@ -54,7 +54,7 @@ module.exports = Self => {
if (tx) await tx.commit();
- return refundsTicket[0];
+ return refundsTicket;
} catch (e) {
if (tx) await tx.rollback();
throw e;
diff --git a/modules/ticket/back/methods/sale/specs/canEdit.spec.js b/modules/ticket/back/methods/sale/specs/canEdit.spec.js
index eef9136a8..200ea24cc 100644
--- a/modules/ticket/back/methods/sale/specs/canEdit.spec.js
+++ b/modules/ticket/back/methods/sale/specs/canEdit.spec.js
@@ -102,7 +102,7 @@ describe('sale canEdit()', () => {
try {
const options = {transaction: tx};
- const role = await models.Role.findOne({
+ const role = await models.VnRole.findOne({
where: {
name: roleEnabled.principalId
}
@@ -159,7 +159,7 @@ describe('sale canEdit()', () => {
try {
const options = {transaction: tx};
- const role = await models.Role.findOne({
+ const role = await models.VnRole.findOne({
where: {
name: roleEnabled.principalId
}
diff --git a/modules/ticket/back/methods/sale/specs/refund.spec.js b/modules/ticket/back/methods/sale/specs/refund.spec.js
index 08eb1fabd..60f77e90c 100644
--- a/modules/ticket/back/methods/sale/specs/refund.spec.js
+++ b/modules/ticket/back/methods/sale/specs/refund.spec.js
@@ -23,9 +23,9 @@ describe('Sale refund()', () => {
try {
const options = {transaction: tx};
- const refundedTicket = await models.Sale.refund(ctx, salesIds, servicesIds, withWarehouse, options);
+ const refundedTickets = await models.Sale.refund(ctx, salesIds, servicesIds, withWarehouse, options);
- expect(refundedTicket).toBeDefined();
+ expect(refundedTickets).toBeDefined();
await tx.rollback();
} catch (e) {
@@ -42,11 +42,11 @@ describe('Sale refund()', () => {
const options = {transaction: tx};
const ticketsBefore = await models.Ticket.find({}, options);
- const ticket = await models.Sale.refund(ctx, salesIds, servicesIds, withWarehouse, options);
+ const tickets = await models.Sale.refund(ctx, salesIds, servicesIds, withWarehouse, options);
const refundedTicket = await models.Ticket.findOne({
where: {
- id: ticket.id
+ id: tickets[0].id
},
include: [
{
diff --git a/modules/ticket/back/methods/ticket-dms/removeFile.js b/modules/ticket/back/methods/ticket-dms/removeFile.js
index f48dc7fef..6fba4c552 100644
--- a/modules/ticket/back/methods/ticket-dms/removeFile.js
+++ b/modules/ticket/back/methods/ticket-dms/removeFile.js
@@ -19,7 +19,6 @@ module.exports = Self => {
});
Self.removeFile = async(ctx, id, options) => {
- const models = Self.app.models;
const myOptions = {};
let tx;
@@ -32,18 +31,18 @@ module.exports = Self => {
}
try {
- const targetTicketDms = await models.TicketDms.findById(id, null, myOptions);
- const targetDms = await models.Dms.findById(targetTicketDms.dmsFk, null, myOptions);
- const trashDmsType = await models.DmsType.findOne({where: {code: 'trash'}}, myOptions);
+ const ticketDms = await Self.findById(id, null, myOptions);
- await models.Dms.removeFile(ctx, targetTicketDms.dmsFk, myOptions);
- await targetTicketDms.destroy(myOptions);
+ const targetDms = await Self.app.models.Dms.removeFile(ctx, ticketDms.dmsFk, myOptions);
- await targetDms.updateAttribute('dmsTypeFk', trashDmsType.id, myOptions);
+ if (!targetDms || !ticketDms)
+ throw new UserError('Try again');
+
+ const ticketDmsDestroyed = await ticketDms.destroy(myOptions);
if (tx) await tx.commit();
- return targetDms;
+ return ticketDmsDestroyed;
} catch (e) {
if (tx) await tx.rollback();
throw e;
diff --git a/modules/ticket/back/methods/ticket-request/confirm.js b/modules/ticket/back/methods/ticket-request/confirm.js
index 00310f33c..e782bd66e 100644
--- a/modules/ticket/back/methods/ticket-request/confirm.js
+++ b/modules/ticket/back/methods/ticket-request/confirm.js
@@ -63,7 +63,7 @@ module.exports = Self => {
const isAvailable = itemStock.available > 0;
- if (!isAvailable)
+ if (!isAvailable || !ctx.args.quantity)
throw new UserError(`This item is not available`);
if (request.saleFk)
diff --git a/modules/ticket/back/methods/ticket/canBeInvoiced.js b/modules/ticket/back/methods/ticket/canBeInvoiced.js
index 348f02348..855a864c2 100644
--- a/modules/ticket/back/methods/ticket/canBeInvoiced.js
+++ b/modules/ticket/back/methods/ticket/canBeInvoiced.js
@@ -10,20 +10,20 @@ module.exports = function(Self) {
description: 'The tickets id',
type: ['number'],
required: true
+ },
+ {
+ arg: 'isRectificative',
+ description: 'If it is rectificative',
+ type: 'boolean'
}
],
- returns: {
- arg: 'data',
- type: 'boolean',
- root: true
- },
http: {
path: `/canBeInvoiced`,
verb: 'get'
}
});
- Self.canBeInvoiced = async(ctx, ticketsIds, options) => {
+ Self.canBeInvoiced = async(ctx, ticketsIds, isRectificative, options) => {
const myOptions = {};
const $t = ctx.req.__; // $translate
@@ -34,26 +34,14 @@ module.exports = function(Self) {
where: {
id: {inq: ticketsIds}
},
- fields: ['id', 'refFk', 'shipped', 'totalWithVat', 'companyFk']
+ fields: ['id', 'refFk', 'shipped', 'totalWithVat']
}, myOptions);
- const [firstTicket] = tickets;
- const companyFk = firstTicket.companyFk;
-
- const query =
- `SELECT COUNT(*) isSpanishCompany
- FROM supplier s
- JOIN country c ON c.id = s.countryFk
- AND c.code = 'ES'
- WHERE s.id = ?`;
- const [supplierCompany] = await Self.rawSql(query, [companyFk], options);
-
- const isSpanishCompany = supplierCompany?.isSpanishCompany;
-
- const [result] = await Self.rawSql('SELECT hasAnyNegativeBase() AS base', null, options);
- const hasAnyNegativeBase = result?.base && isSpanishCompany;
- if (hasAnyNegativeBase)
- throw new UserError($t('Negative basis of tickets', {ticketsIds: ticketsIds}));
+ const taxBaseFunction = isRectificative ? 'hasAnyPositiveBase' : 'hasAnyNegativeBase';
+ const [hasAnyIncorrectBase] =
+ await Self.rawSql(`SELECT ${taxBaseFunction}() AS hasBasesProblem`, null, options);
+ if (hasAnyIncorrectBase?.hasBasesProblem)
+ throw new UserError($t(taxBaseFunction, {ticketsIds: ticketsIds}));
const today = Date.vnNew();
tickets.some(ticket => {
@@ -70,7 +58,5 @@ module.exports = function(Self) {
if (ticketsIds.length == 1 && priceZero)
throw new UserError(`A ticket with an amount of zero can't be invoiced`);
});
-
- return true;
};
};
diff --git a/modules/ticket/back/methods/ticket/invoiceTickets.js b/modules/ticket/back/methods/ticket/invoiceTickets.js
index fa3ee93af..06429836e 100644
--- a/modules/ticket/back/methods/ticket/invoiceTickets.js
+++ b/modules/ticket/back/methods/ticket/invoiceTickets.js
@@ -10,7 +10,13 @@ module.exports = function(Self) {
description: 'The tickets id',
type: ['number'],
required: true
+ },
+ {
+ arg: 'invoiceCorrection',
+ description: 'The invoice correction',
+ type: 'object',
}
+
],
returns: {
type: ['object'],
@@ -22,7 +28,7 @@ module.exports = function(Self) {
}
});
- Self.invoiceTickets = async(ctx, ticketsIds, options) => {
+ Self.invoiceTickets = async(ctx, ticketsIds, invoiceCorrection, options) => {
const models = Self.app.models;
const date = Date.vnNew();
date.setHours(0, 0, 0, 0);
@@ -41,10 +47,10 @@ module.exports = function(Self) {
let invoicesIds = [];
try {
const tickets = await models.Ticket.find({
+ fields: ['id', 'clientFk', 'companyFk', 'addressFk'],
where: {
id: {inq: ticketsIds}
- },
- fields: ['id', 'clientFk', 'companyFk']
+ }
}, myOptions);
const [firstTicket] = tickets;
@@ -55,22 +61,20 @@ module.exports = function(Self) {
if (!isSameClient)
throw new UserError(`You can't invoice tickets from multiple clients`);
- const client = await models.Client.findById(clientId, {
- fields: ['id', 'hasToInvoiceByAddress']
+ const {hasToInvoiceByAddress} = await models.Client.findById(clientId, {
+ fields: ['hasToInvoiceByAddress']
}, myOptions);
- if (client.hasToInvoiceByAddress) {
- const query = `
- SELECT DISTINCT addressFk
- FROM ticket t
- WHERE id IN (?)`;
- const result = await Self.rawSql(query, [ticketsIds], myOptions);
+ let ticketsByAddress = hasToInvoiceByAddress
+ ? Object.values(tickets.reduce((group, {id, addressFk}) => {
+ group[addressFk] = group[addressFk] ?? [];
+ group[addressFk].push(id);
+ return group;
+ }, {}))
+ : [ticketsIds];
- const addressIds = result.map(address => address.addressFk);
- for (const address of addressIds)
- await createInvoice(ctx, companyId, ticketsIds, address, invoicesIds, myOptions);
- } else
- await createInvoice(ctx, companyId, ticketsIds, null, invoicesIds, myOptions);
+ for (const ticketIds of ticketsByAddress)
+ invoicesIds.push(await createInvoice(ctx, companyId, ticketIds, invoiceCorrection, myOptions));
if (tx) await tx.commit();
} catch (e) {
@@ -85,9 +89,8 @@ module.exports = function(Self) {
return invoicesIds;
};
- async function createInvoice(ctx, companyId, ticketsIds, address, invoicesIds, myOptions) {
+ async function createInvoice(ctx, companyId, ticketsIds, invoiceCorrection, myOptions) {
const models = Self.app.models;
-
await models.Ticket.rawSql(`
CREATE OR REPLACE TEMPORARY TABLE tmp.ticketToInvoice
(PRIMARY KEY (id))
@@ -95,11 +98,8 @@ module.exports = function(Self) {
SELECT id
FROM vn.ticket
WHERE id IN (?)
- ${address ? `AND addressFk = ${address}` : ''}
`, [ticketsIds], myOptions);
-
- const invoiceId = await models.Ticket.makeInvoice(ctx, 'R', companyId, Date.vnNew(), myOptions);
- invoicesIds.push(invoiceId);
+ return models.Ticket.makeInvoice(ctx, 'R', companyId, Date.vnNew(), invoiceCorrection, myOptions);
}
};
diff --git a/modules/ticket/back/methods/ticket/isEditableOrThrow.js b/modules/ticket/back/methods/ticket/isEditableOrThrow.js
index f8285cecd..41438be3a 100644
--- a/modules/ticket/back/methods/ticket/isEditableOrThrow.js
+++ b/modules/ticket/back/methods/ticket/isEditableOrThrow.js
@@ -41,7 +41,7 @@ module.exports = Self => {
throw new ForbiddenError(`This ticket is not editable.`);
if (isLocked && !isWeekly)
- throw new ForbiddenError(`This ticket is locked.`);
+ throw new ForbiddenError(`This ticket is locked`);
if (isWeekly && !canEditWeeklyTicket)
throw new ForbiddenError(`You don't have enough privileges.`);
diff --git a/modules/ticket/back/methods/ticket/makeInvoice.js b/modules/ticket/back/methods/ticket/makeInvoice.js
index e7ee806c7..83222a4ee 100644
--- a/modules/ticket/back/methods/ticket/makeInvoice.js
+++ b/modules/ticket/back/methods/ticket/makeInvoice.js
@@ -22,6 +22,11 @@ module.exports = function(Self) {
description: 'The invoice date',
type: 'date',
required: true
+ },
+ {
+ arg: 'invoiceCorrection',
+ description: 'The invoice correction',
+ type: 'object',
}
],
returns: {
@@ -34,7 +39,7 @@ module.exports = function(Self) {
}
});
- Self.makeInvoice = async(ctx, invoiceType, companyFk, invoiceDate, options) => {
+ Self.makeInvoice = async(ctx, invoiceType, companyFk, invoiceDate, invoiceCorrection, options) => {
const models = Self.app.models;
invoiceDate.setHours(0, 0, 0, 0);
@@ -62,20 +67,24 @@ module.exports = function(Self) {
fields: ['id', 'clientFk', 'addressFk']
}, myOptions);
- await models.Ticket.canBeInvoiced(ctx, ticketsIds, myOptions);
+ await models.Ticket.canBeInvoiced(ctx, ticketsIds, !!invoiceCorrection, myOptions);
const [firstTicket] = tickets;
const clientId = firstTicket.clientFk;
- const clientCanBeInvoiced = await models.Client.canBeInvoiced(clientId, companyFk, myOptions);
+ const clientCanBeInvoiced =
+ await models.Client.canBeInvoiced(clientId, companyFk, myOptions);
+
if (!clientCanBeInvoiced)
throw new UserError(`This client can't be invoiced`);
- const query = `SELECT vn.invoiceSerial(?, ?, ?) AS serial`;
- const [{serial}] = await Self.rawSql(query, [
- clientId,
- companyFk,
- invoiceType,
- ], myOptions);
+ const [{serial}] = invoiceCorrection ? [{serial: 'R'}] : await Self.rawSql(
+ `SELECT vn.invoiceSerial(?, ?, ?) AS serial`,
+ [
+ clientId,
+ companyFk,
+ invoiceType
+ ],
+ myOptions);
const invoiceOutSerial = await models.InvoiceOutSerial.findById(serial);
if (invoiceOutSerial?.taxAreaFk == 'WORLD') {
@@ -87,11 +96,17 @@ module.exports = function(Self) {
await Self.rawSql('CALL invoiceOut_new(?, ?, null, @invoiceId)', [serial, invoiceDate], myOptions);
const [resultInvoice] = await Self.rawSql('SELECT @invoiceId id', [], myOptions);
- if (!resultInvoice)
+ if (!resultInvoice?.id)
throw new UserError('No tickets to invoice', 'notInvoiced');
- if (serial != 'R' && resultInvoice.id)
- await Self.rawSql('CALL invoiceOutBooking(?)', [resultInvoice.id], myOptions);
+ if (invoiceCorrection) {
+ await models.InvoiceCorrection.create(
+ Object.assign(invoiceCorrection, {correctingFk: resultInvoice.id}),
+ myOptions
+ );
+ }
+
+ await Self.rawSql('CALL invoiceOutBooking(?)', [resultInvoice.id], myOptions);
if (tx) await tx.commit();
diff --git a/modules/ticket/back/methods/ticket/refund.js b/modules/ticket/back/methods/ticket/refund.js
index 758384ae2..4fed02260 100644
--- a/modules/ticket/back/methods/ticket/refund.js
+++ b/modules/ticket/back/methods/ticket/refund.js
@@ -15,7 +15,7 @@ module.exports = Self => {
}
],
returns: {
- type: ['number'],
+ type: ['object'],
root: true
},
http: {
diff --git a/modules/ticket/back/methods/ticket/sendSms.js b/modules/ticket/back/methods/ticket/sendSms.js
index ffc95c6b4..36e52fe3d 100644
--- a/modules/ticket/back/methods/ticket/sendSms.js
+++ b/modules/ticket/back/methods/ticket/sendSms.js
@@ -33,7 +33,9 @@ module.exports = Self => {
Self.sendSms = async(ctx, id, destination, message) => {
const models = Self.app.models;
const sms = await models.Sms.send(ctx, destination, message);
- await models.TicketSms.create({
+ const {clientFk} = await models.Ticket.findById(id);
+ await models.ClientSms.create({
+ clientFk,
ticketFk: id,
smsFk: sms.id
});
diff --git a/modules/ticket/back/methods/ticket/specs/addSale.spec.js b/modules/ticket/back/methods/ticket/specs/addSale.spec.js
index 8c0e39bec..72c9541d9 100644
--- a/modules/ticket/back/methods/ticket/specs/addSale.spec.js
+++ b/modules/ticket/back/methods/ticket/specs/addSale.spec.js
@@ -89,6 +89,6 @@ describe('ticket addSale()', () => {
error = e;
}
- expect(error.message).toEqual(`This ticket is locked.`);
+ expect(error.message).toEqual(`This ticket is locked`);
});
});
diff --git a/modules/ticket/back/methods/ticket/specs/canBeInvoiced.spec.js b/modules/ticket/back/methods/ticket/specs/canBeInvoiced.spec.js
index 538dbc49f..78973e040 100644
--- a/modules/ticket/back/methods/ticket/specs/canBeInvoiced.spec.js
+++ b/modules/ticket/back/methods/ticket/specs/canBeInvoiced.spec.js
@@ -27,10 +27,7 @@ describe('ticket canBeInvoiced()', () => {
WHERE id IN (?)
`, [ticketId], options);
- const canBeInvoiced = await models.Ticket.canBeInvoiced(ctx, [ticketId], options);
-
- expect(canBeInvoiced).toEqual(false);
-
+ await models.Ticket.canBeInvoiced(ctx, [ticketId], false, options);
await tx.rollback();
} catch (e) {
error = e;
@@ -59,10 +56,7 @@ describe('ticket canBeInvoiced()', () => {
WHERE id IN (?)
`, [ticketId], options);
- const canBeInvoiced = await models.Ticket.canBeInvoiced(ctx, [ticketId], options);
-
- expect(canBeInvoiced).toEqual(false);
-
+ await models.Ticket.canBeInvoiced(ctx, [ticketId], false, options);
await tx.rollback();
} catch (e) {
error = e;
@@ -95,10 +89,7 @@ describe('ticket canBeInvoiced()', () => {
WHERE id IN (?)
`, [ticketId], options);
- const canBeInvoiced = await models.Ticket.canBeInvoiced(ctx, [ticketId], options);
-
- expect(canBeInvoiced).toEqual(false);
-
+ await models.Ticket.canBeInvoiced(ctx, [ticketId], false, options);
await tx.rollback();
} catch (e) {
error = e;
@@ -123,14 +114,36 @@ describe('ticket canBeInvoiced()', () => {
WHERE id IN (?)
`, [ticketId], options);
- const canBeInvoiced = await models.Ticket.canBeInvoiced(ctx, [ticketId], options);
-
- expect(canBeInvoiced).toEqual(true);
-
+ await models.Ticket.canBeInvoiced(ctx, [ticketId], false, options);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
+
+ it('should return falsy for a ticket has positiveBase', async() => {
+ const tx = await models.Ticket.beginTransaction({});
+
+ try {
+ const options = {transaction: tx};
+
+ await models.Ticket.rawSql(`
+ CREATE OR REPLACE TEMPORARY TABLE tmp.ticketToInvoice
+ (PRIMARY KEY (id))
+ ENGINE = MEMORY
+ SELECT id
+ FROM vn.ticket
+ WHERE id IN (?)
+ `, [ticketId], options);
+
+ await models.Ticket.canBeInvoiced(ctx, [ticketId], true, options);
+ await tx.rollback();
+ } catch (e) {
+ error = e;
+ await tx.rollback();
+ }
+
+ expect(error.message).toEqual(`hasAnyPositiveBase`);
+ });
});
diff --git a/modules/ticket/back/methods/ticket/specs/filter.spec.js b/modules/ticket/back/methods/ticket/specs/filter.spec.js
index 2e5730980..c1d3f1a9c 100644
--- a/modules/ticket/back/methods/ticket/specs/filter.spec.js
+++ b/modules/ticket/back/methods/ticket/specs/filter.spec.js
@@ -68,7 +68,7 @@ describe('ticket filter()', () => {
const filter = {};
const result = await models.Ticket.filter(ctx, filter, options);
- expect(result.length).toEqual(9);
+ expect(result.length).toEqual(6);
await tx.rollback();
} catch (e) {
@@ -141,7 +141,6 @@ describe('ticket filter()', () => {
});
it('should return the tickets that are not pending', async() => {
- pending('#6010 test intermitente');
const tx = await models.Ticket.beginTransaction({});
try {
diff --git a/modules/ticket/back/methods/ticket/specs/getSalespersonMana.spec.js b/modules/ticket/back/methods/ticket/specs/getSalespersonMana.spec.js
index 12c115ff9..6029ca4a7 100644
--- a/modules/ticket/back/methods/ticket/specs/getSalespersonMana.spec.js
+++ b/modules/ticket/back/methods/ticket/specs/getSalespersonMana.spec.js
@@ -9,7 +9,7 @@ describe('ticket getSalesPersonMana()', () => {
const mana = await models.Ticket.getSalesPersonMana(1, options);
- expect(mana).toEqual(73);
+ expect(mana).toEqual(124);
await tx.rollback();
} catch (e) {
diff --git a/modules/ticket/back/methods/ticket/specs/invoiceTickets.spec.js b/modules/ticket/back/methods/ticket/specs/invoiceTickets.spec.js
index 8971fb24a..162dc066a 100644
--- a/modules/ticket/back/methods/ticket/specs/invoiceTickets.spec.js
+++ b/modules/ticket/back/methods/ticket/specs/invoiceTickets.spec.js
@@ -31,7 +31,7 @@ describe('ticket invoiceTickets()', () => {
const options = {transaction: tx};
const ticketsIds = [11, 16];
- await models.Ticket.invoiceTickets(ctx, ticketsIds, options);
+ await models.Ticket.invoiceTickets(ctx, ticketsIds, null, options);
await tx.rollback();
} catch (e) {
@@ -57,7 +57,7 @@ describe('ticket invoiceTickets()', () => {
await client.updateAttribute('isTaxDataChecked', false, options);
const ticketsIds = [11];
- await models.Ticket.invoiceTickets(ctx, ticketsIds, options);
+ await models.Ticket.invoiceTickets(ctx, ticketsIds, null, options);
await tx.rollback();
} catch (e) {
@@ -80,8 +80,8 @@ describe('ticket invoiceTickets()', () => {
const options = {transaction: tx};
const ticketsIds = [11];
- await models.Ticket.invoiceTickets(ctx, ticketsIds, options);
- await models.Ticket.invoiceTickets(ctx, ticketsIds, options);
+ await models.Ticket.invoiceTickets(ctx, ticketsIds, null, options);
+ await models.Ticket.invoiceTickets(ctx, ticketsIds, null, options);
await tx.rollback();
} catch (e) {
@@ -102,7 +102,7 @@ describe('ticket invoiceTickets()', () => {
const options = {transaction: tx};
const ticketsIds = [11];
- const invoicesIds = await models.Ticket.invoiceTickets(ctx, ticketsIds, options);
+ const invoicesIds = await models.Ticket.invoiceTickets(ctx, ticketsIds, null, options);
expect(invoicesIds.length).toBeGreaterThan(0);
diff --git a/modules/ticket/back/methods/ticket/specs/isEditableOrThrow.spec.js b/modules/ticket/back/methods/ticket/specs/isEditableOrThrow.spec.js
index 6c89bac26..bdf547325 100644
--- a/modules/ticket/back/methods/ticket/specs/isEditableOrThrow.spec.js
+++ b/modules/ticket/back/methods/ticket/specs/isEditableOrThrow.spec.js
@@ -40,7 +40,7 @@ describe('ticket isEditableOrThrow()', () => {
expect(error.message).toEqual(`This ticket is not editable.`);
});
- it('should throw an error as this ticket is locked.', async() => {
+ it('should throw an error as This ticket is locked', async() => {
const tx = await models.Ticket.beginTransaction({});
let error;
try {
@@ -57,7 +57,7 @@ describe('ticket isEditableOrThrow()', () => {
await tx.rollback();
}
- expect(error.message).toEqual(`This ticket is locked.`);
+ expect(error.message).toEqual(`This ticket is locked`);
});
it('should throw an error as you do not have enough privileges.', async() => {
diff --git a/modules/ticket/back/methods/ticket/specs/makeInvoice.spec.js b/modules/ticket/back/methods/ticket/specs/makeInvoice.spec.js
index 9b1fd8f6f..456303602 100644
--- a/modules/ticket/back/methods/ticket/specs/makeInvoice.spec.js
+++ b/modules/ticket/back/methods/ticket/specs/makeInvoice.spec.js
@@ -42,7 +42,7 @@ describe('ticket makeInvoice()', () => {
WHERE id IN (?)
`, [ticketsIds], options);
- const invoiceId = await models.Ticket.makeInvoice(ctx, invoiceType, companyFk, invoiceDate, options);
+ const invoiceId = await models.Ticket.makeInvoice(ctx, invoiceType, companyFk, invoiceDate, null, options);
expect(invoiceId).toBeDefined();
@@ -70,7 +70,7 @@ describe('ticket makeInvoice()', () => {
WHERE id IN (?)
`, [ticketsId], options);
- await models.Ticket.makeInvoice(ctx, invoiceType, companyFk, invoiceDate, options);
+ await models.Ticket.makeInvoice(ctx, invoiceType, companyFk, invoiceDate, null, options);
await tx.rollback();
} catch (e) {
error = e;
diff --git a/modules/ticket/back/methods/ticket/specs/recalculateComponents.spec.js b/modules/ticket/back/methods/ticket/specs/recalculateComponents.spec.js
index 383c2c6d5..d358a79f5 100644
--- a/modules/ticket/back/methods/ticket/specs/recalculateComponents.spec.js
+++ b/modules/ticket/back/methods/ticket/specs/recalculateComponents.spec.js
@@ -39,6 +39,6 @@ describe('ticket recalculateComponents()', () => {
error = e;
}
- expect(error).toEqual(new ForbiddenError(`This ticket is locked.`));
+ expect(error).toEqual(new ForbiddenError(`This ticket is locked`));
});
});
diff --git a/modules/ticket/back/methods/ticket/specs/sendSms.spec.js b/modules/ticket/back/methods/ticket/specs/sendSms.spec.js
index 3f93198d1..afc1ada54 100644
--- a/modules/ticket/back/methods/ticket/specs/sendSms.spec.js
+++ b/modules/ticket/back/methods/ticket/specs/sendSms.spec.js
@@ -14,12 +14,12 @@ describe('ticket sendSms()', () => {
await models.Ticket.sendSms(ctx, id, destination, message, options);
- const filter = {
- ticketFk: id
- };
- const ticketSms = await models.TicketSms.findOne(filter, options);
+ const clientSms = await models.ClientSms.findOne(
+ {where: {ticketFk: id}},
+ options
+ );
- expect(ticketSms.ticketFk).toEqual(id);
+ expect(clientSms.ticketFk).toEqual(id);
await tx.rollback();
} catch (e) {
diff --git a/modules/ticket/back/methods/ticket/specs/state.spec.js b/modules/ticket/back/methods/ticket/specs/state.spec.js
index 9b5e80165..f369932de 100644
--- a/modules/ticket/back/methods/ticket/specs/state.spec.js
+++ b/modules/ticket/back/methods/ticket/specs/state.spec.js
@@ -94,10 +94,10 @@ describe('ticket state()', () => {
const ticketTracking = await models.Ticket.state(ctx, params, options);
- expect(ticketTracking.__data.ticketFk).toBe(params.ticketFk);
- expect(ticketTracking.__data.stateFk).toBe(params.stateFk);
- expect(ticketTracking.__data.workerFk).toBe(49);
- expect(ticketTracking.__data.id).toBeDefined();
+ expect(ticketTracking.ticketFk).toBe(params.ticketFk);
+ expect(ticketTracking.stateFk).toBe(params.stateFk);
+ expect(ticketTracking.userFk).toBe(49);
+ expect(ticketTracking.id).toBeDefined();
await tx.rollback();
} catch (e) {
@@ -116,14 +116,14 @@ describe('ticket state()', () => {
const ticket = await models.Ticket.create(sampleTicket, options);
const ctx = {req: {accessToken: {userId: 18}}};
const assignedState = await models.State.findOne({where: {code: 'PICKER_DESIGNED'}}, options);
- const params = {ticketFk: ticket.id, stateFk: assignedState.id, workerFk: 1};
+ const params = {ticketFk: ticket.id, stateFk: assignedState.id, userFk: 1};
const res = await models.Ticket.state(ctx, params, options);
- expect(res.__data.ticketFk).toBe(params.ticketFk);
- expect(res.__data.stateFk).toBe(params.stateFk);
- expect(res.__data.workerFk).toBe(params.workerFk);
- expect(res.__data.workerFk).toBe(1);
- expect(res.__data.id).toBeDefined();
+ expect(res.ticketFk).toBe(params.ticketFk);
+ expect(res.stateFk).toBe(params.stateFk);
+ expect(res.userFk).toBe(params.userFk);
+ expect(res.userFk).toBe(1);
+ expect(res.id).toBeDefined();
await tx.rollback();
} catch (e) {
diff --git a/modules/ticket/back/methods/ticket/specs/transferClient.spec.js b/modules/ticket/back/methods/ticket/specs/transferClient.spec.js
index c09c20083..5a9edd17e 100644
--- a/modules/ticket/back/methods/ticket/specs/transferClient.spec.js
+++ b/modules/ticket/back/methods/ticket/specs/transferClient.spec.js
@@ -23,7 +23,7 @@ describe('Ticket transferClient()', () => {
error = e;
}
- expect(error.message).toEqual(`This ticket is locked.`);
+ expect(error.message).toEqual(`This ticket is locked`);
});
it('should be assigned a different clientFk', async() => {
diff --git a/modules/ticket/back/methods/ticket/state.js b/modules/ticket/back/methods/ticket/state.js
index 01bfbba20..adac2e42f 100644
--- a/modules/ticket/back/methods/ticket/state.js
+++ b/modules/ticket/back/methods/ticket/state.js
@@ -51,12 +51,12 @@ module.exports = Self => {
params.stateFk = state.id;
}
- if (!params.workerFk) {
+ if (!params.userFk) {
const worker = await models.Worker.findOne({
where: {id: userId}
}, myOptions);
- params.workerFk = worker.id;
+ params.userFk = worker.id;
}
const ticketState = await models.TicketState.findById(params.ticketFk, {
diff --git a/modules/ticket/back/methods/ticket/uploadFile.js b/modules/ticket/back/methods/ticket/uploadFile.js
index 4de9904e1..5b79aa973 100644
--- a/modules/ticket/back/methods/ticket/uploadFile.js
+++ b/modules/ticket/back/methods/ticket/uploadFile.js
@@ -47,7 +47,7 @@ module.exports = Self => {
});
Self.uploadFile = async(ctx, id, options) => {
- const models = Self.app.models;
+ const {Dms, TicketDms} = Self.app.models;
const myOptions = {};
let tx;
@@ -59,22 +59,19 @@ module.exports = Self => {
myOptions.transaction = tx;
}
- const promises = [];
try {
- const uploadedFiles = await models.Dms.uploadFile(ctx, myOptions);
- uploadedFiles.forEach(dms => {
- const newTicketDms = models.TicketDms.create({
- ticketFk: id,
- dmsFk: dms.id
- }, myOptions);
+ const uploadedFiles = await Dms.uploadFile(ctx, myOptions);
- promises.push(newTicketDms);
- });
- const resolvedPromises = await Promise.all(promises);
+ const promises = uploadedFiles.map(dms => TicketDms.create({
+ ticketFk: id,
+ dmsFk: dms.id
+ }, myOptions));
+
+ await Promise.all(promises);
if (tx) await tx.commit();
- return resolvedPromises;
+ return uploadedFiles;
} catch (e) {
if (tx) await tx.rollback();
throw e;
diff --git a/modules/ticket/back/models/expedition-state.json b/modules/ticket/back/models/expedition-state.json
index 262eb2e38..eda0f79fd 100644
--- a/modules/ticket/back/models/expedition-state.json
+++ b/modules/ticket/back/models/expedition-state.json
@@ -24,5 +24,12 @@
"userFk": {
"type": "number"
}
+ },
+ "relations": {
+ "expeditionStateType": {
+ "type": "belongsTo",
+ "model": "ExpeditionStateType",
+ "foreignKey": "typeFk"
+ }
}
}
diff --git a/modules/ticket/back/models/expedition.json b/modules/ticket/back/models/expedition.json
index e32a3b23d..2dcca1e87 100644
--- a/modules/ticket/back/models/expedition.json
+++ b/modules/ticket/back/models/expedition.json
@@ -1,6 +1,9 @@
{
"name": "Expedition",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "expedition"
@@ -20,6 +23,9 @@
},
"counter": {
"type": "number"
+ },
+ "externalId": {
+ "type": "string"
}
},
"relations": {
@@ -30,7 +36,7 @@
},
"agencyMode": {
"type": "belongsTo",
- "model": "agency-mode",
+ "model": "AgencyMode",
"foreignKey": "agencyModeFk"
},
"worker": {
diff --git a/modules/ticket/back/models/sale.json b/modules/ticket/back/models/sale.json
index 72ca1f5e0..96a36bbc9 100644
--- a/modules/ticket/back/models/sale.json
+++ b/modules/ticket/back/models/sale.json
@@ -1,6 +1,9 @@
{
"name": "Sale",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "sale"
diff --git a/modules/ticket/back/models/ticket-dms.json b/modules/ticket/back/models/ticket-dms.json
index 071999be7..a3e697506 100644
--- a/modules/ticket/back/models/ticket-dms.json
+++ b/modules/ticket/back/models/ticket-dms.json
@@ -1,6 +1,9 @@
{
"name": "TicketDms",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "ticketDms"
diff --git a/modules/ticket/back/models/ticket-observation.json b/modules/ticket/back/models/ticket-observation.json
index 64e49b217..26d6f7586 100644
--- a/modules/ticket/back/models/ticket-observation.json
+++ b/modules/ticket/back/models/ticket-observation.json
@@ -1,6 +1,9 @@
{
"name": "TicketObservation",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "ticketObservation"
diff --git a/modules/ticket/back/models/ticket-packaging.json b/modules/ticket/back/models/ticket-packaging.json
index 6c94c810e..0cf494809 100644
--- a/modules/ticket/back/models/ticket-packaging.json
+++ b/modules/ticket/back/models/ticket-packaging.json
@@ -1,6 +1,9 @@
{
"name": "TicketPackaging",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "ticketPackaging"
diff --git a/modules/ticket/back/models/ticket-refund.json b/modules/ticket/back/models/ticket-refund.json
index d344a3f1c..249270c8b 100644
--- a/modules/ticket/back/models/ticket-refund.json
+++ b/modules/ticket/back/models/ticket-refund.json
@@ -1,6 +1,9 @@
{
"name": "TicketRefund",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "ticketRefund"
diff --git a/modules/ticket/back/models/ticket-request.json b/modules/ticket/back/models/ticket-request.json
index f8407792e..2cfcd30a1 100644
--- a/modules/ticket/back/models/ticket-request.json
+++ b/modules/ticket/back/models/ticket-request.json
@@ -1,6 +1,9 @@
{
"name": "TicketRequest",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "ticketRequest"
diff --git a/modules/ticket/back/models/ticket-service-type.json b/modules/ticket/back/models/ticket-service-type.json
index ec2c9232a..9340d6023 100644
--- a/modules/ticket/back/models/ticket-service-type.json
+++ b/modules/ticket/back/models/ticket-service-type.json
@@ -18,7 +18,7 @@
"expenseFk": {
"type": "number",
"mysql": {
- "columnName": "expenceFk"
+ "columnName": "expenseFk"
}
}
},
diff --git a/modules/ticket/back/models/ticket-service.json b/modules/ticket/back/models/ticket-service.json
index f1dbede13..4dfbd2fbd 100644
--- a/modules/ticket/back/models/ticket-service.json
+++ b/modules/ticket/back/models/ticket-service.json
@@ -1,6 +1,9 @@
{
"name": "TicketService",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "ticketService"
diff --git a/modules/ticket/back/models/ticket-state.json b/modules/ticket/back/models/ticket-state.json
index a10938ef0..3dd322939 100644
--- a/modules/ticket/back/models/ticket-state.json
+++ b/modules/ticket/back/models/ticket-state.json
@@ -33,9 +33,9 @@
"model": "State",
"foreignKey": "stateFk"
},
- "worker": {
+ "user": {
"type": "belongsTo",
- "model": "Worker",
+ "model": "VnUser",
"foreignKey": "workerFk"
}
}
diff --git a/modules/ticket/back/models/ticket-tracking.js b/modules/ticket/back/models/ticket-tracking.js
index 92e046d3e..72e1880b9 100644
--- a/modules/ticket/back/models/ticket-tracking.js
+++ b/modules/ticket/back/models/ticket-tracking.js
@@ -2,5 +2,5 @@ module.exports = function(Self) {
require('../methods/ticket-tracking/setDelivered')(Self);
Self.validatesPresenceOf('stateFk', {message: 'State cannot be blank'});
- Self.validatesPresenceOf('workerFk', {message: 'Worker cannot be blank'});
+ Self.validatesPresenceOf('userFk', {message: 'Worker cannot be blank'});
};
diff --git a/modules/ticket/back/models/ticket-tracking.json b/modules/ticket/back/models/ticket-tracking.json
index 8b5ce0b64..025a07bc0 100644
--- a/modules/ticket/back/models/ticket-tracking.json
+++ b/modules/ticket/back/models/ticket-tracking.json
@@ -1,6 +1,9 @@
{
"name": "TicketTracking",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "ticketTracking"
@@ -8,21 +11,18 @@
},
"properties": {
"id": {
- "id": true,
- "type": "number",
- "forceId": false
+ "id": true,
+ "type": "number",
+ "forceId": false
},
"created": {
- "type": "date"
+ "type": "date"
},
"ticketFk": {
- "type": "number"
+ "type": "number"
},
"stateFk": {
- "type": "number"
- },
- "workerFk": {
- "type": "number"
+ "type": "number"
}
},
"relations": {
@@ -36,10 +36,10 @@
"model": "State",
"foreignKey": "stateFk"
},
- "worker": {
+ "user": {
"type": "belongsTo",
- "model": "Worker",
- "foreignKey": "workerFk"
+ "model": "VnUser",
+ "foreignKey": "userFk"
}
}
}
diff --git a/modules/ticket/back/models/ticket-weekly.json b/modules/ticket/back/models/ticket-weekly.json
index c5e485aa2..7494cac79 100644
--- a/modules/ticket/back/models/ticket-weekly.json
+++ b/modules/ticket/back/models/ticket-weekly.json
@@ -1,6 +1,9 @@
{
"name": "TicketWeekly",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "ticketWeekly"
diff --git a/modules/ticket/back/models/ticket.json b/modules/ticket/back/models/ticket.json
index ec4193bed..c55cd82bb 100644
--- a/modules/ticket/back/models/ticket.json
+++ b/modules/ticket/back/models/ticket.json
@@ -1,6 +1,9 @@
{
"name": "Ticket",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "ticket"
diff --git a/modules/ticket/front/advance/index.js b/modules/ticket/front/advance/index.js
index fb539311f..1f47d8242 100644
--- a/modules/ticket/front/advance/index.js
+++ b/modules/ticket/front/advance/index.js
@@ -202,9 +202,9 @@ export default class Controller extends Section {
if (!ticket.landed) {
const newLanded = await this.getLanded({
shipped: this.$.model.userParams.dateToAdvance,
- addressFk: ticket.addressFk,
- agencyModeFk: ticket.agencyModeFk,
- warehouseFk: ticket.warehouseFk
+ addressFk: ticket.futureAddressFk,
+ agencyModeFk: ticket.agencyModeFk ?? ticket.futureAgencyModeFk,
+ warehouseFk: ticket.futureWarehouseFk
});
if (!newLanded)
throw new Error(this.$t(`No delivery zone available for this landing date`));
@@ -213,13 +213,13 @@ export default class Controller extends Section {
ticket.zoneFk = newLanded.zoneFk;
}
const params = {
- clientFk: ticket.clientFk,
+ clientFk: ticket.futureClientFk,
nickname: ticket.nickname,
agencyModeFk: ticket.agencyModeFk ?? ticket.futureAgencyModeFk,
- addressFk: ticket.addressFk,
+ addressFk: ticket.futureAddressFk,
zoneFk: ticket.zoneFk ?? ticket.futureZoneFk,
- warehouseFk: ticket.warehouseFk,
- companyFk: ticket.companyFk,
+ warehouseFk: ticket.futureWarehouseFk,
+ companyFk: ticket.futureCompanyFk,
shipped: this.$.model.userParams.dateToAdvance,
landed: ticket.landed,
isDeleted: false,
diff --git a/modules/ticket/front/descriptor-menu/index.js b/modules/ticket/front/descriptor-menu/index.js
index 18db8c147..cd819e623 100644
--- a/modules/ticket/front/descriptor-menu/index.js
+++ b/modules/ticket/front/descriptor-menu/index.js
@@ -292,7 +292,7 @@ class Controller extends Section {
const query = 'Tickets/refund';
return this.$http.post(query, params)
.then(res => {
- const refundTicket = res.data;
+ const [refundTicket] = res.data;
this.vnApp.showSuccess(this.$t('The following refund ticket have been created', {
ticketId: refundTicket.id
}));
diff --git a/modules/ticket/front/descriptor-menu/index.spec.js b/modules/ticket/front/descriptor-menu/index.spec.js
index 1bb270165..c755b14c3 100644
--- a/modules/ticket/front/descriptor-menu/index.spec.js
+++ b/modules/ticket/front/descriptor-menu/index.spec.js
@@ -262,11 +262,12 @@ describe('Ticket Component vnTicketDescriptorMenu', () => {
const params = {
ticketsIds: [16]
};
- $httpBackend.expectPOST('Tickets/refund', params).respond({id: 99});
+ const response = {id: 99};
+ $httpBackend.expectPOST('Tickets/refund', params).respond([response]);
controller.refund();
$httpBackend.flush();
- expect(controller.$state.go).toHaveBeenCalledWith('ticket.card.sale', {id: 99});
+ expect(controller.$state.go).toHaveBeenCalledWith('ticket.card.sale', response);
});
});
diff --git a/modules/ticket/front/sale/index.js b/modules/ticket/front/sale/index.js
index 4f6a9e757..ed6d9b10a 100644
--- a/modules/ticket/front/sale/index.js
+++ b/modules/ticket/front/sale/index.js
@@ -526,7 +526,7 @@ class Controller extends Section {
const params = {salesIds: salesIds, withWarehouse: withWarehouse};
const query = 'Sales/refund';
this.$http.post(query, params).then(res => {
- const refundTicket = res.data;
+ const [refundTicket] = res.data;
this.vnApp.showSuccess(this.$t('The following refund ticket have been created', {
ticketId: refundTicket.id
}));
diff --git a/modules/ticket/front/sale/index.spec.js b/modules/ticket/front/sale/index.spec.js
index 70781eb58..36be32f52 100644
--- a/modules/ticket/front/sale/index.spec.js
+++ b/modules/ticket/front/sale/index.spec.js
@@ -729,7 +729,7 @@ describe('Ticket', () => {
salesIds: [1, 4],
};
const refundTicket = {id: 99};
- $httpBackend.expect('POST', 'Sales/refund', params).respond(200, refundTicket);
+ $httpBackend.expect('POST', 'Sales/refund', params).respond(200, [refundTicket]);
controller.createRefund();
$httpBackend.flush();
diff --git a/modules/ticket/front/tracking/index/index.html b/modules/ticket/front/tracking/index/index.html
index 12c4778c9..10ee6d848 100644
--- a/modules/ticket/front/tracking/index/index.html
+++ b/modules/ticket/front/tracking/index/index.html
@@ -23,9 +23,9 @@
{{::tracking.state.name}}
- {{::tracking.worker.user.name || 'System' | translate}}
+ ng-class="{'link': tracking.user.id}"
+ ng-click="workerDescriptor.show($event, tracking.user.id)">
+ {{::tracking.user.name || 'System' | translate}}
{{::tracking.created | date:'dd/MM/yyyy HH:mm'}}
diff --git a/modules/ticket/front/tracking/index/index.js b/modules/ticket/front/tracking/index/index.js
index 95665b071..ff3dc881b 100644
--- a/modules/ticket/front/tracking/index/index.js
+++ b/modules/ticket/front/tracking/index/index.js
@@ -7,15 +7,9 @@ class Controller extends Section {
this.filter = {
include: [
{
- relation: 'worker',
+ relation: 'user',
scope: {
- fields: ['id'],
- include: {
- relation: 'user',
- scope: {
- fields: ['name']
- }
- }
+ fields: ['name']
}
}, {
relation: 'state',
diff --git a/modules/travel/back/models/travel-thermograph.json b/modules/travel/back/models/travel-thermograph.json
index 08eec2847..cc8e60aaf 100644
--- a/modules/travel/back/models/travel-thermograph.json
+++ b/modules/travel/back/models/travel-thermograph.json
@@ -1,6 +1,9 @@
{
"name": "TravelThermograph",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "travelThermograph"
diff --git a/modules/travel/back/models/travel.json b/modules/travel/back/models/travel.json
index 95d458121..701894a76 100644
--- a/modules/travel/back/models/travel.json
+++ b/modules/travel/back/models/travel.json
@@ -1,6 +1,9 @@
{
"name": "Travel",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "travel"
diff --git a/modules/worker/back/methods/calendar/absences.js b/modules/worker/back/methods/calendar/absences.js
index 8420ed770..8a5d18987 100644
--- a/modules/worker/back/methods/calendar/absences.js
+++ b/modules/worker/back/methods/calendar/absences.js
@@ -39,6 +39,7 @@ module.exports = Self => {
started.setFullYear(year);
started.setMonth(0);
started.setDate(1);
+ started.setHours(0, 0, 0, 0);
const ended = Date.vnNew();
ended.setFullYear(year);
diff --git a/modules/worker/back/methods/worker-dms/removeFile.js b/modules/worker/back/methods/worker-dms/removeFile.js
index b441c56ce..8eb6c05fd 100644
--- a/modules/worker/back/methods/worker-dms/removeFile.js
+++ b/modules/worker/back/methods/worker-dms/removeFile.js
@@ -18,13 +18,35 @@ module.exports = Self => {
}
});
- Self.removeFile = async(ctx, id) => {
- const models = Self.app.models;
- const workerDms = await Self.findById(id);
+ Self.removeFile = async(ctx, dmsFk, options) => {
+ const myOptions = {};
+ let tx;
+ if (typeof options == 'object')
+ Object.assign(myOptions, options);
- await models.Dms.removeFile(ctx, workerDms.dmsFk);
+ if (!myOptions.transaction) {
+ tx = await Self.beginTransaction({});
+ myOptions.transaction = tx;
+ }
- return workerDms.destroy();
+ try {
+ const WorkerDms = await Self.findOne({
+ where: {document: dmsFk}
+ }, myOptions);
+
+ const targetDms = await Self.app.models.Dms.removeFile(ctx, dmsFk, myOptions);
+
+ if (!targetDms || !WorkerDms)
+ throw new UserError('Try again');
+
+ const workerDmsDestroyed = await WorkerDms.destroy(myOptions);
+ if (tx) await tx.commit();
+
+ return workerDmsDestroyed;
+ } catch (e) {
+ await tx.rollback();
+ throw e;
+ }
};
};
diff --git a/modules/worker/back/methods/worker-time-control/addTimeEntry.js b/modules/worker/back/methods/worker-time-control/addTimeEntry.js
index cc652fb90..5dbac51ca 100644
--- a/modules/worker/back/methods/worker-time-control/addTimeEntry.js
+++ b/modules/worker/back/methods/worker-time-control/addTimeEntry.js
@@ -43,16 +43,9 @@ module.exports = Self => {
const isTeamBoss = await models.ACL.checkAccessAcl(ctx, 'Worker', 'isTeamBoss', 'WRITE');
const isHimself = userId == workerId;
- if (!isSubordinate || (isSubordinate && isHimself && !isTeamBoss))
+ if (!isSubordinate || (isHimself && !isTeamBoss))
throw new UserError(`You don't have enough privileges`);
- query = `CALL vn.workerTimeControl_clockIn(?,?,?)`;
- const [response] = await Self.rawSql(query, [workerId, args.timed, args.direction], myOptions);
- if (response[0] && response[0].error)
- throw new UserError(response[0].error);
-
- await models.WorkerTimeControl.resendWeeklyHourEmail(ctx, workerId, args.timed, myOptions);
-
- return response;
+ return Self.clockIn(workerId, args.timed, args.direction, myOptions);
};
};
diff --git a/modules/worker/back/methods/worker-time-control/clockIn.js b/modules/worker/back/methods/worker-time-control/clockIn.js
new file mode 100644
index 000000000..44e0c547a
--- /dev/null
+++ b/modules/worker/back/methods/worker-time-control/clockIn.js
@@ -0,0 +1,45 @@
+const UserError = require('vn-loopback/util/user-error');
+
+module.exports = Self => {
+ Self.remoteMethod('clockIn', {
+ description: 'Check if the employee can clock in',
+ accessType: 'WRITE',
+ accepts: [
+ {
+ arg: 'workerFk',
+ type: 'number',
+ required: true,
+ },
+ {
+ arg: 'timed',
+ type: 'date'
+ },
+ {
+ arg: 'direction',
+ type: 'string'
+ },
+
+ ],
+ http: {
+ path: `/clockIn`,
+ verb: 'POST'
+ },
+ returns: {
+ type: 'Object',
+ root: true
+ }
+ });
+
+ Self.clockIn = async(workerFk, timed, direction, options) => {
+ const myOptions = {};
+ if (typeof options == 'object')
+ Object.assign(myOptions, options);
+
+ const query = 'CALL vn.workerTimeControl_clockIn(?, ?, ?)';
+ const [[response]] = await Self.rawSql(query, [workerFk, timed, direction], myOptions);
+ if (response && response.error)
+ throw new UserError(response.error);
+
+ return response;
+ };
+};
diff --git a/modules/worker/back/methods/worker-time-control/getClockIn.js b/modules/worker/back/methods/worker-time-control/getClockIn.js
new file mode 100644
index 000000000..470700643
--- /dev/null
+++ b/modules/worker/back/methods/worker-time-control/getClockIn.js
@@ -0,0 +1,32 @@
+module.exports = Self => {
+ Self.remoteMethod('getClockIn', {
+ description: 'Shows the clockings for each day, in columns per day',
+ accessType: 'READ',
+ accepts: [
+ {
+ arg: 'workerFk',
+ type: 'int',
+ required: true,
+ },
+
+ ],
+ http: {
+ path: `/getClockIn`,
+ verb: 'GET'
+ },
+ returns: {
+ type: ['Object'],
+ root: true
+ },
+ });
+
+ Self.getClockIn = async(workerFk, options) => {
+ const myOptions = {};
+ if (typeof options == 'object')
+ Object.assign(myOptions, options);
+
+ const query = `CALL vn.workerTimeControl_getClockIn(?, ?)`;
+ const [result] = await Self.rawSql(query, [workerFk, Date.vnNew()], myOptions);
+ return result;
+ };
+};
diff --git a/modules/worker/back/methods/worker-time-control/login.js b/modules/worker/back/methods/worker-time-control/login.js
new file mode 100644
index 000000000..9aa4bd145
--- /dev/null
+++ b/modules/worker/back/methods/worker-time-control/login.js
@@ -0,0 +1,35 @@
+const UserError = require('vn-loopback/util/user-error');
+
+module.exports = Self => {
+ Self.remoteMethodCtx('login', {
+ description: 'Consult the user\'s information and the buttons that must be activated after logging in',
+ accessType: 'READ',
+ accepts: [
+ {
+ arg: 'pin',
+ type: 'string',
+ required: true
+ },
+ ],
+ returns: {
+ type: 'Object',
+ root: true
+ },
+ http: {
+ path: `/login`,
+ verb: 'POST'
+ }
+ });
+
+ Self.login = async(ctx, pin, options) => {
+ const myOptions = {};
+ const $t = ctx.req.__;
+ if (typeof options == 'object')
+ Object.assign(myOptions, options);
+
+ const query = `CALL vn.workerTimeControl_login(?)`;
+ const [[user]] = await Self.rawSql(query, [pin], myOptions);
+ if (!user) throw new UserError($t('Incorrect pin'));
+ return user;
+ };
+};
diff --git a/modules/worker/back/methods/worker-time-control/resendWeeklyHourEmail.js b/modules/worker/back/methods/worker-time-control/resendWeeklyHourEmail.js
index 2452a29f9..896458455 100644
--- a/modules/worker/back/methods/worker-time-control/resendWeeklyHourEmail.js
+++ b/modules/worker/back/methods/worker-time-control/resendWeeklyHourEmail.js
@@ -1,6 +1,6 @@
module.exports = Self => {
Self.remoteMethodCtx('resendWeeklyHourEmail', {
- description: 'Adds a new hour registry',
+ description: 'Send the records for the week of the date provided',
accessType: 'WRITE',
accepts: [{
arg: 'id',
diff --git a/modules/worker/back/methods/worker-time-control/specs/clockIn.spec.js b/modules/worker/back/methods/worker-time-control/specs/clockIn.spec.js
new file mode 100644
index 000000000..9cd3ed1c0
--- /dev/null
+++ b/modules/worker/back/methods/worker-time-control/specs/clockIn.spec.js
@@ -0,0 +1,581 @@
+const models = require('vn-loopback/server/server').models;
+const LoopBackContext = require('loopback-context');
+
+describe('workerTimeControl clockIn()', () => {
+ const workerId = 9;
+ const salesBossId = 19;
+ const hankPymId = 1107;
+ const jessicaJonesId = 1110;
+ const HHRRId = 37;
+ const teamBossId = 13;
+ const monday = 1;
+ const tuesday = 2;
+ const thursday = 4;
+ const friday = 5;
+ const sunday = 7;
+ const inTime = '2001-01-01T00:00:00.000Z';
+ const activeCtx = {
+ accessToken: {userId: 50},
+ };
+ const ctx = {req: activeCtx};
+
+ beforeAll(() => {
+ spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
+ active: activeCtx
+ });
+ });
+
+ it('should correctly clock in', async() => {
+ const tx = await models.WorkerTimeControl.beginTransaction({});
+
+ try {
+ const options = {transaction: tx};
+ await models.WorkerTimeControl.clockIn(workerId, inTime, 'in', options);
+ const isClockIn = await models.WorkerTimeControl.findOne({
+ where: {
+ userFk: workerId
+ }
+ }, options);
+
+ expect(isClockIn).toBeDefined();
+ expect(isClockIn.direction).toBe('in');
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ throw e;
+ }
+ });
+
+ describe('as Role errors', () => {
+ it('should add if the current user is team boss and the target user is himself', async() => {
+ activeCtx.accessToken.userId = teamBossId;
+ const workerId = teamBossId;
+
+ const tx = await models.WorkerTimeControl.beginTransaction({});
+ try {
+ const options = {transaction: tx};
+
+ const todayAtOne = Date.vnNew();
+ todayAtOne.setHours(1, 0, 0, 0);
+
+ ctx.args = {timed: todayAtOne, direction: 'in'};
+ const createdTimeEntry = await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+
+ expect(createdTimeEntry.id).toBeDefined();
+
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ throw e;
+ }
+ });
+
+ it('should delete the created time entry for the team boss as himself', async() => {
+ activeCtx.accessToken.userId = teamBossId;
+ const workerId = teamBossId;
+
+ const tx = await models.WorkerTimeControl.beginTransaction({});
+ try {
+ const options = {transaction: tx};
+
+ const todayAtOne = Date.vnNew();
+ todayAtOne.setHours(1, 0, 0, 0);
+
+ ctx.args = {timed: todayAtOne, direction: 'in'};
+ const createdTimeEntry = await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+
+ expect(createdTimeEntry.id).toBeDefined();
+
+ await models.WorkerTimeControl.deleteTimeEntry(ctx, createdTimeEntry.id, options);
+
+ const deletedTimeEntry = await models.WorkerTimeControl.findById(createdTimeEntry.id, null, options);
+
+ expect(deletedTimeEntry).toBeNull();
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ throw e;
+ }
+ });
+
+ it('should edit the created time entry for the team boss as HHRR', async() => {
+ activeCtx.accessToken.userId = HHRRId;
+ const workerId = teamBossId;
+
+ const tx = await models.WorkerTimeControl.beginTransaction({});
+ try {
+ const options = {transaction: tx};
+
+ const todayAtOne = Date.vnNew();
+ todayAtOne.setHours(1, 0, 0, 0);
+
+ ctx.args = {timed: todayAtOne, direction: 'in'};
+ const createdTimeEntry = await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+
+ expect(createdTimeEntry.id).toBeDefined();
+
+ ctx.args = {direction: 'out'};
+ const updatedTimeEntry = await models.WorkerTimeControl.updateTimeEntry(
+ ctx, createdTimeEntry.id, options
+ );
+
+ expect(updatedTimeEntry.direction).toEqual('out');
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ throw e;
+ }
+ });
+ });
+
+ describe('as saleBoss editor', () => {
+ let workerId;
+ beforeEach(() => {
+ activeCtx.accessToken.userId = salesBossId;
+ workerId = hankPymId;
+ });
+
+ it('should fail to add a time entry if the target user has an absence that day', async() => {
+ const date = Date.vnNew();
+ date.setHours(8, 0, 0);
+ date.setDate(date.getDate() - 16);
+ const tx = await models.WorkerTimeControl.beginTransaction({});
+ const options = {transaction: tx};
+ try {
+ ctx.args = {timed: date, direction: 'in'};
+ await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ error = e;
+ }
+
+ expect(error.message).toBe(`No está permitido trabajar`);
+ });
+
+ it('should fail to add a time entry for a worker without an existing contract', async() => {
+ const date = Date.vnNew();
+ date.setFullYear(date.getFullYear() - 2);
+
+ const tx = await models.WorkerTimeControl.beginTransaction({});
+ const options = {transaction: tx};
+ try {
+ ctx.args = {timed: date, direction: 'in'};
+ await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ error = e;
+ }
+
+ expect(error.message).toBe(`No hay un contrato en vigor`);
+ });
+
+ it('should fail to add a time entry for a worker without an existing contract and exceeding time', async() => {
+ let date = Date.vnNew();
+ date.setDate(date.getDate() - 2);
+ let error;
+
+ const tx = await models.WorkerTimeControl.beginTransaction({});
+ const options = {transaction: tx};
+ date.setHours(0, 0, 0);
+ ctx.args = {timed: date, direction: 'in'};
+ await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+
+ try {
+ date.setHours(20, 0, 1);
+ ctx.args = {timed: date, direction: 'out'};
+ await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ error = e;
+ }
+
+ expect(error.message).toBe(`Superado el tiempo máximo entre entrada y salida`);
+ });
+
+ describe('direction errors', () => {
+ let date = Date.vnNew();
+ date.setDate(date.getDate() - 1);
+ let error;
+ it('should throw an error when trying "in" direction twice', async() => {
+ const tx = await models.WorkerTimeControl.beginTransaction({});
+ const options = {transaction: tx};
+
+ date.setHours(8, 0, 0);
+ ctx.args = {timed: date, direction: 'in'};
+ await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+
+ try {
+ date.setHours(10, 0, 0);
+ ctx.args = {timed: date, direction: 'in'};
+ await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ error = e;
+ }
+
+ expect(error.message).toBe(`Dirección incorrecta`);
+ });
+
+ it('should throw an error when trying "in" direction after insert "in" and "middle"', async() => {
+ const tx = await models.WorkerTimeControl.beginTransaction({});
+ const options = {transaction: tx};
+
+ date.setHours(8, 0, 0);
+ ctx.args = {timed: date, direction: 'in'};
+ await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+
+ date.setHours(9, 0, 0);
+ ctx.args = {timed: date, direction: 'middle'};
+ await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+
+ try {
+ date.setHours(10, 0, 0);
+ ctx.args = {timed: date, direction: 'in'};
+ await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ error = e;
+ }
+
+ expect(error.message).toBe(`Dirección incorrecta`);
+ });
+
+ it('Should throw an error when trying "out" before closing a "middle" couple', async() => {
+ const tx = await models.WorkerTimeControl.beginTransaction({});
+ const options = {transaction: tx};
+
+ date.setHours(8, 0, 0);
+ ctx.args = {timed: date, direction: 'in'};
+ await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+ date.setHours(9, 0, 0);
+ ctx.args = {timed: date, direction: 'middle'};
+ await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+
+ try {
+ date.setHours(10, 0, 0);
+ ctx.args = {timed: date, direction: 'out'};
+ await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ error = e;
+ }
+
+ expect(error.message).toBe(`Dirección incorrecta`);
+ });
+
+ it('should throw an error when trying "middle" after "out"', async() => {
+ const tx = await models.WorkerTimeControl.beginTransaction({});
+ const options = {transaction: tx};
+
+ date.setHours(8, 0, 0);
+ ctx.args = {timed: date, direction: 'in'};
+ await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+ date.setHours(9, 0, 0);
+ ctx.args = {timed: date, direction: 'out'};
+ await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+
+ try {
+ date.setHours(10, 0, 0);
+ ctx.args = {timed: date, direction: 'middle'};
+ await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ error = e;
+ }
+
+ expect(error.message).toBe(`Dirección incorrecta`);
+ });
+
+ it('should throw an error when trying "out" direction twice', async() => {
+ const tx = await models.WorkerTimeControl.beginTransaction({});
+ const options = {transaction: tx};
+
+ date.setHours(8, 0, 0);
+ ctx.args = {timed: date, direction: 'in'};
+ await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+ date.setHours(9, 0, 0);
+ ctx.args = {timed: date, direction: 'out'};
+ await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+
+ try {
+ date.setHours(10, 0, 0);
+ ctx.args = {timed: date, direction: 'out'};
+ await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ error = e;
+ }
+
+ expect(error.message).toBe(`Dirección incorrecta`);
+ });
+ });
+
+ describe('12h rest', () => {
+ activeCtx.accessToken.userId = salesBossId;
+ const workerId = hankPymId;
+ it('should throw an error when the 12h rest is not fulfilled yet', async() => {
+ let date = Date.vnNew();
+ date.setDate(date.getDate() - 2);
+ date = weekDay(date, monday);
+ let error;
+
+ const tx = await models.WorkerTimeControl.beginTransaction({});
+ const options = {transaction: tx};
+
+ date.setHours(8, 0, 0);
+ ctx.args = {timed: date, direction: 'in'};
+ await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+ date.setHours(16, 0, 0);
+ ctx.args = {timed: date, direction: 'out'};
+ await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+
+ try {
+ date = weekDay(date, tuesday);
+ date.setHours(4, 0, 0);
+ ctx.args = {timed: date, direction: 'in'};
+ await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ error = e;
+ }
+
+ expect(error.message).toBe(`Descanso diario`);
+ });
+
+ it('should not fail as the 12h rest is fulfilled', async() => {
+ let date = Date.vnNew();
+ date.setDate(date.getDate() - 2);
+ date = weekDay(date, monday);
+ let error;
+
+ const tx = await models.WorkerTimeControl.beginTransaction({});
+ const options = {transaction: tx};
+
+ date.setHours(8, 0, 0);
+ ctx.args = {timed: date, direction: 'in'};
+ await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+ date.setHours(16, 0, 0);
+ ctx.args = {timed: date, direction: 'out'};
+ await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+
+ try {
+ date = weekDay(date, tuesday);
+ date.setHours(4, 1, 0);
+ ctx.args = {timed: date, direction: 'in'};
+ await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ error = e;
+ }
+
+ expect(error).not.toBeDefined;
+ });
+ });
+
+ describe('for 3500kg drivers with enforced 9h rest', () => {
+ activeCtx.accessToken.userId = salesBossId;
+ const workerId = jessicaJonesId;
+ it('should throw an error when the 9h enforced rest is not fulfilled', async() => {
+ let date = Date.vnNew();
+ date.setDate(date.getDate() - 2);
+ date = weekDay(date, monday);
+ let error;
+
+ const tx = await models.WorkerTimeControl.beginTransaction({});
+ const options = {transaction: tx};
+
+ date.setHours(8, 0, 0);
+ ctx.args = {timed: date, direction: 'in'};
+ await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+ date.setHours(16, 0, 0);
+ ctx.args = {timed: date, direction: 'out'};
+ await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+
+ try {
+ date = weekDay(date, tuesday);
+ date.setHours(1, 0, 0);
+ ctx.args = {timed: date, direction: 'in'};
+ await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ error = e;
+ }
+
+ expect(error.message).toBe(`Descanso diario`);
+ });
+
+ it('should not fail when the 9h enforced rest is fulfilled', async() => {
+ let date = Date.vnNew();
+ date.setDate(date.getDate() - 2);
+ date = weekDay(date, monday);
+ let error;
+
+ const tx = await models.WorkerTimeControl.beginTransaction({});
+ const options = {transaction: tx};
+
+ date.setHours(8, 0, 0);
+ ctx.args = {timed: date, direction: 'in'};
+ await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+ date.setHours(16, 0, 0);
+ ctx.args = {timed: date, direction: 'out'};
+ await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+
+ try {
+ date = weekDay(date, tuesday);
+ date.setHours(1, 1, 0);
+ ctx.args = {timed: date, direction: 'in'};
+ await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ error = e;
+ }
+
+ expect(error).not.toBeDefined;
+ });
+ });
+
+ describe('for 72h weekly rest', () => {
+
+ it('should throw an error when work 11 consecutive days', async() => {
+ let date = Date.vnNew();
+ date.setMonth(date.getMonth() - 1);
+ date.setDate(1);
+ let error;
+
+ const tx = await models.WorkerTimeControl.beginTransaction({});
+ const options = {transaction: tx};
+
+ await populateWeek(date, monday, sunday, ctx, workerId, options);
+ date = nextWeek(date);
+ await populateWeek(date, monday, thursday, ctx, workerId, options);
+ try {
+ date = weekDay(date, friday);
+ date.setHours(10, 0, 1);
+ ctx.args = {timed: date, direction: 'in'};
+ await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ error = e;
+ }
+
+ expect(error.message).toBe(`Descanso semanal`);
+ });
+
+ it('should throw an error when the 72h weekly rest is not fulfilled', async() => {
+
+ let date = Date.vnNew();
+ date.setMonth(date.getMonth() - 1);
+ date.setDate(1);
+ let error;
+
+ const tx = await models.WorkerTimeControl.beginTransaction({});
+ const options = {transaction: tx};
+
+ await populateWeek(date, monday, sunday, ctx, workerId, options);
+ date = nextWeek(date);
+ await populateWeek(date, monday, thursday, ctx, workerId, options);
+
+ try {
+ date = weekDay(date, sunday);
+ date.setHours(17, 59, 0);
+ ctx.args = {timed: date, direction: 'in'};
+ await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ error = e;
+ }
+
+ expect(error.message).toBe(`Descanso semanal`);
+ });
+
+ it('should throw an error when the 72h weekly rest is fulfilled', async() => {
+
+ let date = Date.vnNew();
+ date.setMonth(date.getMonth() - 1);
+ date.setDate(1);
+ let error;
+
+ const tx = await models.WorkerTimeControl.beginTransaction({});
+ const options = {transaction: tx};
+
+ await populateWeek(date, monday, sunday, ctx, workerId, options);
+ date = nextWeek(date);
+ await populateWeek(date, monday, thursday, ctx, workerId, options);
+
+ try {
+ date = weekDay(date, sunday);
+ date.setHours(18, 00, 0);
+ ctx.args = {timed: date, direction: 'in'};
+ await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ error = e;
+ }
+
+ expect(error).not.toBeDefined;
+ });
+ });
+ });
+});
+
+function weekDay(date, dayToSet) {
+ const currentDay = date.getDay();
+ const distance = dayToSet - currentDay;
+
+ date.setDate(date.getDate() + distance);
+ return date;
+}
+
+function nextWeek(date) {
+ const sunday = 7;
+ const currentDay = date.getDay();
+ let newDate = date;
+ if (currentDay != 0)
+ newDate = weekDay(date, sunday);
+
+ newDate.setDate(newDate.getDate() + 1);
+ return newDate;
+}
+
+async function populateWeek(date, dayStart, dayEnd, ctx, workerId, options) {
+ const dateStart = new Date(weekDay(date, dayStart));
+ const dateEnd = new Date(dateStart);
+ dateEnd.setDate(dateStart.getDate() + dayEnd);
+
+ for (let i = dayStart; i <= dayEnd; i++) {
+ dateStart.setHours(10, 0, 0);
+ ctx.args = {timed: dateStart, direction: 'in'};
+ await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+ dateStart.setHours(18, 0, 0);
+ ctx.args = {timed: dateStart, direction: 'out'};
+ await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+ dateStart.setDate(dateStart.getDate() + 1);
+ }
+}
diff --git a/modules/worker/back/methods/worker-time-control/specs/getClockIn.spec.js b/modules/worker/back/methods/worker-time-control/specs/getClockIn.spec.js
new file mode 100644
index 000000000..d75ffac70
--- /dev/null
+++ b/modules/worker/back/methods/worker-time-control/specs/getClockIn.spec.js
@@ -0,0 +1,16 @@
+const models = require('vn-loopback/server/server').models;
+
+describe('workerTimeControl getClockIn()', () => {
+ it('should correctly get the timetable of a worker', async() => {
+ const response = await models.WorkerTimeControl.getClockIn(1106, {});
+
+ expect(response.length).toEqual(4);
+ const [inHrs, middleOutHrs, middleInHrs, outHrs] = response;
+
+ expect(inHrs['0daysAgo']).toEqual('07:00');
+ expect(middleOutHrs['0daysAgo']).toEqual('10:00');
+ expect(middleInHrs['0daysAgo']).toEqual('10:20');
+ expect(outHrs['0daysAgo']).toEqual('14:50');
+ });
+});
+
diff --git a/modules/worker/back/methods/worker-time-control/specs/login.spec.js b/modules/worker/back/methods/worker-time-control/specs/login.spec.js
new file mode 100644
index 000000000..d9f2dbb39
--- /dev/null
+++ b/modules/worker/back/methods/worker-time-control/specs/login.spec.js
@@ -0,0 +1,34 @@
+const models = require('vn-loopback/server/server').models;
+const LoopBackContext = require('loopback-context');
+const UserError = require('vn-loopback/util/user-error');
+
+describe('workerTimeControl login()', () => {
+ let ctx;
+ beforeAll(async() => {
+ ctx = {
+ accessToken: {userId: 9},
+ req: {
+ headers: {origin: 'http://localhost'},
+ __: key => key
+ }
+ };
+ spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
+ active: ctx
+ });
+ });
+
+ it('should correctly login', async() => {
+ const response = await models.WorkerTimeControl.login(ctx, 9);
+
+ expect(response.name).toBe('developer');
+ });
+
+ it('should throw UserError if pin is not provided', async() => {
+ try {
+ await models.WorkerTimeControl.login(ctx);
+ } catch (error) {
+ expect(error).toBeInstanceOf(UserError);
+ expect(error.message).toBe('Incorrect pin');
+ }
+ });
+});
diff --git a/modules/worker/back/methods/worker-time-control/specs/timeEntry.spec.js b/modules/worker/back/methods/worker-time-control/specs/timeEntry.spec.js
index 42ec6290a..92c01792f 100644
--- a/modules/worker/back/methods/worker-time-control/specs/timeEntry.spec.js
+++ b/modules/worker/back/methods/worker-time-control/specs/timeEntry.spec.js
@@ -3,18 +3,10 @@ const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('workerTimeControl add/delete timeEntry()', () => {
- const HHRRId = 37;
- const teamBossId = 13;
const employeeId = 1;
- const salesPersonId = 1106;
const salesBossId = 19;
const hankPymId = 1107;
- const jessicaJonesId = 1110;
const monday = 1;
- const tuesday = 2;
- const thursday = 4;
- const friday = 5;
- const sunday = 7;
const activeCtx = {
accessToken: {userId: 50},
};
@@ -61,560 +53,11 @@ describe('workerTimeControl add/delete timeEntry()', () => {
expect(error.statusCode).toBe(400);
expect(error.message).toBe(`You don't have enough privileges`);
});
-
- it('should add if the current user is team boss and the target user is himself', async() => {
- activeCtx.accessToken.userId = teamBossId;
- const workerId = teamBossId;
-
- const tx = await models.WorkerTimeControl.beginTransaction({});
- try {
- const options = {transaction: tx};
-
- const todayAtOne = Date.vnNew();
- todayAtOne.setHours(1, 0, 0, 0);
-
- ctx.args = {timed: todayAtOne, direction: 'in'};
- const [createdTimeEntry] = await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
-
- expect(createdTimeEntry.id).toBeDefined();
-
- await tx.rollback();
- } catch (e) {
- await tx.rollback();
- throw e;
- }
- });
-
- it('should try but fail to delete his own time entry', async() => {
- activeCtx.accessToken.userId = salesBossId;
- const workerId = salesBossId;
-
- let error;
- const tx = await models.WorkerTimeControl.beginTransaction({});
- try {
- const options = {transaction: tx};
-
- const todayAtOne = Date.vnNew();
- todayAtOne.setHours(1, 0, 0, 0);
-
- ctx.args = {timed: todayAtOne, direction: 'in'};
- const [createdTimeEntry] = await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
-
- activeCtx.accessToken.userId = salesPersonId;
- await models.WorkerTimeControl.deleteTimeEntry(ctx, createdTimeEntry.id, options);
-
- await tx.rollback();
- } catch (e) {
- error = e;
- await tx.rollback();
- }
-
- expect(error).toBeDefined();
- expect(error.statusCode).toBe(400);
- expect(error.message).toBe(`You don't have enough privileges`);
- });
-
- it('should delete the created time entry for the team boss as himself', async() => {
- activeCtx.accessToken.userId = teamBossId;
- const workerId = teamBossId;
-
- const tx = await models.WorkerTimeControl.beginTransaction({});
- try {
- const options = {transaction: tx};
-
- const todayAtOne = Date.vnNew();
- todayAtOne.setHours(1, 0, 0, 0);
-
- ctx.args = {timed: todayAtOne, direction: 'in'};
- const [createdTimeEntry] = await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
-
- expect(createdTimeEntry.id).toBeDefined();
-
- await models.WorkerTimeControl.deleteTimeEntry(ctx, createdTimeEntry.id, options);
-
- const deletedTimeEntry = await models.WorkerTimeControl.findById(createdTimeEntry.id, null, options);
-
- expect(deletedTimeEntry).toBeNull();
- await tx.rollback();
- } catch (e) {
- await tx.rollback();
- throw e;
- }
- });
-
- it('should delete the created time entry for the team boss as HHRR', async() => {
- activeCtx.accessToken.userId = HHRRId;
- const workerId = teamBossId;
-
- const tx = await models.WorkerTimeControl.beginTransaction({});
- try {
- const options = {transaction: tx};
-
- const todayAtOne = Date.vnNew();
- todayAtOne.setHours(1, 0, 0, 0);
-
- ctx.args = {timed: todayAtOne, direction: 'in'};
- const [createdTimeEntry] = await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
-
- expect(createdTimeEntry.id).toBeDefined();
-
- await models.WorkerTimeControl.deleteTimeEntry(ctx, createdTimeEntry.id, options);
-
- const deletedTimeEntry = await models.WorkerTimeControl.findById(createdTimeEntry.id, null, options);
-
- expect(deletedTimeEntry).toBeNull();
- await tx.rollback();
- } catch (e) {
- await tx.rollback();
- throw e;
- }
- });
-
- it('should edit the created time entry for the team boss as HHRR', async() => {
- activeCtx.accessToken.userId = HHRRId;
- const workerId = teamBossId;
-
- const tx = await models.WorkerTimeControl.beginTransaction({});
- try {
- const options = {transaction: tx};
-
- const todayAtOne = Date.vnNew();
- todayAtOne.setHours(1, 0, 0, 0);
-
- ctx.args = {timed: todayAtOne, direction: 'in'};
- const [createdTimeEntry] = await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
-
- expect(createdTimeEntry.id).toBeDefined();
-
- ctx.args = {direction: 'out'};
- const updatedTimeEntry = await models.WorkerTimeControl.updateTimeEntry(ctx, createdTimeEntry.id, options);
-
- expect(updatedTimeEntry.direction).toEqual('out');
- await tx.rollback();
- } catch (e) {
- await tx.rollback();
- throw e;
- }
- });
});
describe('WorkerTimeControl_clockIn calls', () => {
- let workerId;
- beforeEach(() => {
- activeCtx.accessToken.userId = salesBossId;
- workerId = hankPymId;
- });
- it('should fail to add a time entry if the target user has an absence that day', async() => {
- const date = Date.vnNew();
- date.setHours(8, 0, 0);
- date.setDate(date.getDate() - 16);
- const tx = await models.WorkerTimeControl.beginTransaction({});
- const options = {transaction: tx};
- try {
- ctx.args = {timed: date, direction: 'in'};
- await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
+ beforeEach(() => activeCtx.accessToken.userId = salesBossId);
- await tx.rollback();
- } catch (e) {
- await tx.rollback();
- error = e;
- }
-
- expect(error.message).toBe(`No está permitido trabajar`);
- });
-
- it('should fail to add a time entry for a worker without an existing contract', async() => {
- const date = Date.vnNew();
- date.setFullYear(date.getFullYear() - 2);
-
- const tx = await models.WorkerTimeControl.beginTransaction({});
- const options = {transaction: tx};
- try {
- ctx.args = {timed: date, direction: 'in'};
- await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
-
- await tx.rollback();
- } catch (e) {
- await tx.rollback();
- error = e;
- }
-
- expect(error.message).toBe(`No hay un contrato en vigor`);
- });
-
- it('should fail to add a time entry for a worker without an existing contract', async() => {
- let date = Date.vnNew();
- date.setDate(date.getDate() - 2);
- let error;
-
- const tx = await models.WorkerTimeControl.beginTransaction({});
- const options = {transaction: tx};
- date.setHours(0, 0, 0);
- ctx.args = {timed: date, direction: 'in'};
- await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
-
- try {
- date.setHours(20,0, 1);
- ctx.args = {timed: date, direction: 'out'};
- await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
-
- await tx.rollback();
- } catch (e) {
- await tx.rollback();
- error = e;
- }
-
- expect(error.message).toBe(`Superado el tiempo máximo entre entrada y salida`);
- });
-
- describe('direction errors', () => {
- let date = Date.vnNew();
- date.setDate(date.getDate() - 1);
- let error;
- it('should throw an error when trying "in" direction twice', async() => {
- const tx = await models.WorkerTimeControl.beginTransaction({});
- const options = {transaction: tx};
-
- date.setHours(8, 0, 0);
- ctx.args = {timed: date, direction: 'in'};
- await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
-
- try {
- date.setHours(10, 0, 0);
- ctx.args = {timed: date, direction: 'in'};
- await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
-
- await tx.rollback();
- } catch (e) {
- await tx.rollback();
- error = e;
- }
-
- expect(error.message).toBe(`Dirección incorrecta`);
- });
-
- it('should throw an error when trying "in" direction after insert "in" and "middle"', async() => {
- const tx = await models.WorkerTimeControl.beginTransaction({});
- const options = {transaction: tx};
-
- date.setHours(8, 0, 0);
- ctx.args = {timed: date, direction: 'in'};
- await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
-
- date.setHours(9, 0, 0);
- ctx.args = {timed: date, direction: 'middle'};
- await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
-
- try {
- date.setHours(10, 0, 0);
- ctx.args = {timed: date, direction: 'in'};
- await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
-
- await tx.rollback();
- } catch (e) {
- await tx.rollback();
- error = e;
- }
-
- expect(error.message).toBe(`Dirección incorrecta`);
- });
-
- it('Should throw an error when trying "out" before closing a "middle" couple', async() => {
- const tx = await models.WorkerTimeControl.beginTransaction({});
- const options = {transaction: tx};
-
- date.setHours(8, 0, 0);
- ctx.args = {timed: date, direction: 'in'};
- await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
- date.setHours(9, 0, 0);
- ctx.args = {timed: date, direction: 'middle'};
- await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
-
- try {
- date.setHours(10, 0, 0);
- ctx.args = {timed: date, direction: 'out'};
- await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
-
- await tx.rollback();
- } catch (e) {
- await tx.rollback();
- error = e;
- }
-
- expect(error.message).toBe(`Dirección incorrecta`);
- });
-
- it('should throw an error when trying "middle" after "out"', async() => {
- const tx = await models.WorkerTimeControl.beginTransaction({});
- const options = {transaction: tx};
-
- date.setHours(8, 0, 0);
- ctx.args = {timed: date, direction: 'in'};
- await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
- date.setHours(9, 0, 0);
- ctx.args = {timed: date, direction: 'out'};
- await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
-
- try {
- date.setHours(10, 0, 0);
- ctx.args = {timed: date, direction: 'middle'};
- await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
-
- await tx.rollback();
- } catch (e) {
- await tx.rollback();
- error = e;
- }
-
- expect(error.message).toBe(`Dirección incorrecta`);
- });
-
- it('should throw an error when trying "out" direction twice', async() => {
- const tx = await models.WorkerTimeControl.beginTransaction({});
- const options = {transaction: tx};
-
- date.setHours(8, 0, 0);
- ctx.args = {timed: date, direction: 'in'};
- await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
- date.setHours(9, 0, 0);
- ctx.args = {timed: date, direction: 'out'};
- await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
-
- try {
- date.setHours(10, 0, 0);
- ctx.args = {timed: date, direction: 'out'};
- await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
-
- await tx.rollback();
- } catch (e) {
- await tx.rollback();
- error = e;
- }
-
- expect(error.message).toBe(`Dirección incorrecta`);
- });
- });
-
- describe('12h rest', () => {
- activeCtx.accessToken.userId = salesBossId;
- const workerId = hankPymId;
- it('should throw an error when the 12h rest is not fulfilled yet', async() => {
-
- let date = Date.vnNew();
- date.setDate(date.getDate() - 2);
- date = weekDay(date, monday);
- let error;
-
- const tx = await models.WorkerTimeControl.beginTransaction({});
- const options = {transaction: tx};
-
- date.setHours(8, 0, 0);
- ctx.args = {timed: date, direction: 'in'};
- await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
- date.setHours(16, 0, 0);
- ctx.args = {timed: date, direction: 'out'};
- await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
-
- try {
- date = weekDay(date, tuesday);
- date.setHours(4, 0, 0);
- ctx.args = {timed: date, direction: 'in'};
- await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
-
- await tx.rollback();
- } catch (e) {
- await tx.rollback();
- error = e;
- }
-
- expect(error.message).toBe(`Descanso diario`);
- });
-
- it('should not fail as the 12h rest is fulfilled', async() => {
- let date = Date.vnNew();
- date.setDate(date.getDate() - 2);
- date = weekDay(date, monday);
- let error;
-
- const tx = await models.WorkerTimeControl.beginTransaction({});
- const options = {transaction: tx};
-
- date.setHours(8, 0, 0);
- ctx.args = {timed: date, direction: 'in'};
- await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
- date.setHours(16, 0, 0);
- ctx.args = {timed: date, direction: 'out'};
- await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
-
- try {
- date = weekDay(date, tuesday);
- date.setHours(4, 1, 0);
- ctx.args = {timed: date, direction: 'in'};
- await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
-
- await tx.rollback();
- } catch (e) {
- await tx.rollback();
- error = e;
- }
-
- expect(error).not.toBeDefined;
- });
- });
-
- describe('for 3500kg drivers with enforced 9h rest', () => {
- activeCtx.accessToken.userId = salesBossId;
- const workerId = jessicaJonesId;
- it('should throw an error when the 9h enforced rest is not fulfilled', async() => {
-
- let date = Date.vnNew();
- date.setDate(date.getDate() - 2);
- date = weekDay(date, monday);
- let error;
-
- const tx = await models.WorkerTimeControl.beginTransaction({});
- const options = {transaction: tx};
-
- date.setHours(8, 0, 0);
- ctx.args = {timed: date, direction: 'in'};
- await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
- date.setHours(16, 0, 0);
- ctx.args = {timed: date, direction: 'out'};
- await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
-
- try {
- date = weekDay(date, tuesday);
- date.setHours(1, 0, 0);
- ctx.args = {timed: date, direction: 'in'};
- await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
-
- await tx.rollback();
- } catch (e) {
- await tx.rollback();
- error = e;
- }
-
- expect(error.message).toBe(`Descanso diario`);
- });
-
- it('should not fail when the 9h enforced rest is fulfilled', async() => {
-
- let date = Date.vnNew();
- date.setDate(date.getDate() - 2);
- date = weekDay(date, monday);
- let error;
-
- const tx = await models.WorkerTimeControl.beginTransaction({});
- const options = {transaction: tx};
-
- date.setHours(8, 0, 0);
- ctx.args = {timed: date, direction: 'in'};
- await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
- date.setHours(16, 0, 0);
- ctx.args = {timed: date, direction: 'out'};
- await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
-
- try {
- date = weekDay(date, tuesday);
- date.setHours(1, 1, 0);
- ctx.args = {timed: date, direction: 'in'};
- await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
-
- await tx.rollback();
- } catch (e) {
- await tx.rollback();
- error = e;
- }
-
- expect(error).not.toBeDefined;
- });
- });
-
- describe('for 72h weekly rest', () => {
-
- it('should throw an error when work 11 consecutive days', async() => {
- let date = Date.vnNew();
- date.setMonth(date.getMonth() - 1);
- date.setDate(1);
- let error;
-
- const tx = await models.WorkerTimeControl.beginTransaction({});
- const options = {transaction: tx};
-
- await populateWeek(date, monday, sunday, ctx, workerId, options);
- date = nextWeek(date);
- await populateWeek(date, monday, thursday, ctx, workerId, options);
- try {
- date = weekDay(date, friday);
- date.setHours(10, 0, 1);
- ctx.args = {timed: date, direction: 'in'};
- await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
- await tx.rollback();
- } catch (e) {
- await tx.rollback();
- error = e;
- }
-
- expect(error.message).toBe(`Descanso semanal`);
- });
-
- it('should throw an error when the 72h weekly rest is not fulfilled', async() => {
-
- let date = Date.vnNew();
- date.setMonth(date.getMonth() - 1);
- date.setDate(1);
- let error;
-
- const tx = await models.WorkerTimeControl.beginTransaction({});
- const options = {transaction: tx};
-
- await populateWeek(date, monday, sunday, ctx, workerId, options);
- date = nextWeek(date);
- await populateWeek(date, monday, thursday, ctx, workerId, options);
-
- try {
- date = weekDay(date, sunday);
- date.setHours(17, 59, 0);
- ctx.args = {timed: date, direction: 'in'};
- await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
- await tx.rollback();
- } catch (e) {
- await tx.rollback();
- error = e;
- }
-
- expect(error.message).toBe(`Descanso semanal`);
- });
-
- it('should throw an error when the 72h weekly rest is fulfilled', async() => {
-
- let date = Date.vnNew();
- date.setMonth(date.getMonth() - 1);
- date.setDate(1);
- let error;
-
- const tx = await models.WorkerTimeControl.beginTransaction({});
- const options = {transaction: tx};
-
- await populateWeek(date, monday, sunday, ctx, workerId, options);
- date = nextWeek(date);
- await populateWeek(date, monday, thursday, ctx, workerId, options);
-
- try {
- date = weekDay(date, sunday);
- date.setHours(18, 00, 0);
- ctx.args = {timed: date, direction: 'in'};
- await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options);
- await tx.rollback();
- } catch (e) {
- await tx.rollback();
- error = e;
- }
-
- expect(error).not.toBeDefined;
- });
- });
-
describe('WorkerTimeControl_calculate calls', () => {
let dated = Date.vnNew();
dated.setDate(dated.getDate() - 7);
@@ -836,25 +279,6 @@ function weekDay(date, dayToSet) {
return date;
}
-function nextWeek(date) {
- const sunday = 7;
- const currentDay = date.getDay();
- let newDate = date;
- if (currentDay != 0)
- newDate = weekDay(date, sunday);
-
- newDate.setDate(newDate.getDate() + 1);
- return newDate;
-}
-
-function lastWeek(date) {
- const monday = 1;
- newDate = weekDay(date, monday);
-
- newDate.setDate(newDate.getDate() - 1);
- return newDate;
-}
-
async function populateWeek(date, dayStart, dayEnd, ctx, workerId, options) {
const dateStart = new Date(weekDay(date, dayStart));
const dateEnd = new Date(dateStart);
diff --git a/modules/worker/back/methods/worker/specs/activeWithInheritedRole.spec.js b/modules/worker/back/methods/worker/specs/activeWithInheritedRole.spec.js
index da54f6adb..580e07351 100644
--- a/modules/worker/back/methods/worker/specs/activeWithInheritedRole.spec.js
+++ b/modules/worker/back/methods/worker/specs/activeWithInheritedRole.spec.js
@@ -3,7 +3,7 @@ const app = require('vn-loopback/server/server');
describe('Worker activeWithInheritedRole', () => {
let allRolesCount;
beforeAll(async() => {
- allRolesCount = await app.models.Role.count();
+ allRolesCount = await app.models.VnRole.count();
});
it('should return the workers with an inherited role of salesPerson', async() => {
diff --git a/modules/worker/back/methods/worker/uploadFile.js b/modules/worker/back/methods/worker/uploadFile.js
index 588cfe4bd..c3526cbb1 100644
--- a/modules/worker/back/methods/worker/uploadFile.js
+++ b/modules/worker/back/methods/worker/uploadFile.js
@@ -47,30 +47,33 @@ module.exports = Self => {
});
Self.uploadFile = async(ctx, id) => {
- const models = Self.app.models;
- const promises = [];
- const tx = await Self.beginTransaction({});
+ const {Dms, WorkerDms} = Self.app.models;
+ const myOptions = {};
+ let tx;
+
+ if (typeof options == 'object')
+ Object.assign(myOptions, options);
+
+ if (!myOptions.transaction) {
+ tx = await Self.beginTransaction({});
+ myOptions.transaction = tx;
+ }
try {
- const options = {transaction: tx};
-
- const uploadedFiles = await models.Dms.uploadFile(ctx, options);
- uploadedFiles.forEach(dms => {
- const newWorkerDms = models.WorkerDms.create({
+ const uploadedFiles = await Dms.uploadFile(ctx, myOptions);
+ const promises = uploadedFiles.map(dms =>
+ WorkerDms.create({
workerFk: id,
dmsFk: dms.id
- }, options);
+ }, myOptions));
+ await Promise.all(promises);
- promises.push(newWorkerDms);
- });
- const resolvedPromises = await Promise.all(promises);
+ if (tx) await tx.commit();
- await tx.commit();
-
- return resolvedPromises;
- } catch (err) {
- await tx.rollback();
- throw err;
+ return uploadedFiles;
+ } catch (e) {
+ if (tx) await tx.rollback();
+ throw e;
}
};
};
diff --git a/modules/worker/back/models/device-production-user.json b/modules/worker/back/models/device-production-user.json
index 3eeaae137..35a90fb50 100644
--- a/modules/worker/back/models/device-production-user.json
+++ b/modules/worker/back/models/device-production-user.json
@@ -1,6 +1,9 @@
{
"name": "DeviceProductionUser",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"log": {
"model": "DeviceProductionLog",
"relation": "deviceProduction"
diff --git a/modules/worker/back/models/device-production.json b/modules/worker/back/models/device-production.json
index 35787cccc..f6e5105ad 100644
--- a/modules/worker/back/models/device-production.json
+++ b/modules/worker/back/models/device-production.json
@@ -1,6 +1,9 @@
{
"name": "DeviceProduction",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"log": {
"model": "DeviceProductionLog"
},
diff --git a/modules/worker/back/models/worker-dms.json b/modules/worker/back/models/worker-dms.json
index e9a9f1773..a5c0f30b2 100644
--- a/modules/worker/back/models/worker-dms.json
+++ b/modules/worker/back/models/worker-dms.json
@@ -1,6 +1,9 @@
{
"name": "WorkerDms",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "workerDocument"
diff --git a/modules/worker/back/models/worker-time-control.js b/modules/worker/back/models/worker-time-control.js
index d5da680cf..1457c7a46 100644
--- a/modules/worker/back/models/worker-time-control.js
+++ b/modules/worker/back/models/worker-time-control.js
@@ -10,6 +10,9 @@ module.exports = Self => {
require('../methods/worker-time-control/weeklyHourRecordEmail')(Self);
require('../methods/worker-time-control/getMailStates')(Self);
require('../methods/worker-time-control/resendWeeklyHourEmail')(Self);
+ require('../methods/worker-time-control/login')(Self);
+ require('../methods/worker-time-control/getClockIn')(Self);
+ require('../methods/worker-time-control/clockIn')(Self);
Self.rewriteDbError(function(err) {
if (err.code === 'ER_DUP_ENTRY')
diff --git a/modules/worker/back/models/worker.json b/modules/worker/back/models/worker.json
index 1a777fffe..ed430f133 100644
--- a/modules/worker/back/models/worker.json
+++ b/modules/worker/back/models/worker.json
@@ -1,7 +1,10 @@
{
"name": "Worker",
"description": "Company employees",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "worker"
diff --git a/modules/worker/front/calendar/index.html b/modules/worker/front/calendar/index.html
index d64c22408..1b0608633 100644
--- a/modules/worker/front/calendar/index.html
+++ b/modules/worker/front/calendar/index.html
@@ -70,17 +70,18 @@
fields="['started', 'ended']"
ng-model="$ctrl.businessId"
search-function="{businessFk: $search}"
+ show-field="businessFk"
value-field="businessFk"
order="businessFk DESC"
limit="5">
-
- #{{businessFk}}
-
- {{started | date: 'dd/MM/yyyy'}} - {{ended ? (ended | date: 'dd/MM/yyyy') : 'Indef.'}}
-
-
-
-
+
+ #{{businessFk}}
+
+ {{started | date: 'dd/MM/yyyy'}} - {{ended ? (ended | date: 'dd/MM/yyyy') : 'Indef.'}}
+
+
+
+
@@ -110,3 +111,4 @@
message="This item will be deleted"
question="Are you sure you want to continue?">
+
diff --git a/modules/worker/front/time-control/index.js b/modules/worker/front/time-control/index.js
index 0a955c586..f6a6ed535 100644
--- a/modules/worker/front/time-control/index.js
+++ b/modules/worker/front/time-control/index.js
@@ -173,8 +173,6 @@ class Controller extends Section {
]}
};
this.$.model.applyFilter(filter, params).then(() => {
- if (!this.card.hasWorkCenter) return;
-
this.getWorkedHours(this.started, this.ended);
this.getAbsences();
});
diff --git a/modules/zone/back/methods/zone/deleteZone.js b/modules/zone/back/methods/zone/deleteZone.js
index 13d45428c..38e724cd3 100644
--- a/modules/zone/back/methods/zone/deleteZone.js
+++ b/modules/zone/back/methods/zone/deleteZone.js
@@ -64,7 +64,7 @@ module.exports = Self => {
promises.push(models.TicketTracking.create({
ticketFk: ticket.id,
stateFk: fixingState.id,
- workerFk: worker.id
+ userFk: worker.id
}, myOptions));
}
}
diff --git a/modules/zone/back/methods/zone/getEventsFiltered.js b/modules/zone/back/methods/zone/getEventsFiltered.js
index b7875785d..85db76a58 100644
--- a/modules/zone/back/methods/zone/getEventsFiltered.js
+++ b/modules/zone/back/methods/zone/getEventsFiltered.js
@@ -35,44 +35,39 @@ module.exports = Self => {
if (typeof options == 'object')
Object.assign(myOptions, options);
- query = `
- SELECT *
- FROM vn.zoneEvent
- WHERE zoneFk = ?
- AND ((type = 'indefinitely')
- OR (type = 'day' AND dated BETWEEN ? AND ?)
- OR (type = 'range'
- AND (
- (started BETWEEN ? AND ?)
- OR
- (ended BETWEEN ? AND ?)
- OR
- (started <= ? AND ended >= ?)
- )
- )
- )
- ORDER BY type='indefinitely' DESC, type='range' DESC, type='day' DESC;`;
- const events = await Self.rawSql(query,
- [zoneFk, started, ended, started, ended, started, ended, started, ended], myOptions);
+ ended = simpleDate(ended);
+ started = simpleDate(started);
query = `
- SELECT e.*
- FROM vn.zoneExclusion e
- LEFT JOIN vn.zoneExclusionGeo eg ON eg.zoneExclusionFk = e.id
- WHERE e.zoneFk = ?
- AND e.dated BETWEEN ? AND ?
- AND eg.zoneExclusionFk IS NULL;`;
+ SELECT *
+ FROM vn.zoneEvent
+ WHERE zoneFk = ?
+ AND (IFNULL(started, ?) <= ? AND IFNULL(ended,?) >= ?)
+ ORDER BY type='indefinitely' DESC, type='range' DESC, type='day' DESC;`;
+ const events = await Self.rawSql(query,
+ [zoneFk, started, ended, ended, started], myOptions);
+
+ query = `
+ SELECT e.*
+ FROM vn.zoneExclusion e
+ LEFT JOIN vn.zoneExclusionGeo eg ON eg.zoneExclusionFk = e.id
+ WHERE e.zoneFk = ?
+ AND e.dated BETWEEN ? AND ?
+ AND eg.zoneExclusionFk IS NULL;`;
const exclusions = await Self.rawSql(query, [zoneFk, started, ended], myOptions);
query = `
- SELECT eg.*, e.zoneFk, e.dated, e.created, e.userFk
- FROM vn.zoneExclusion e
- LEFT JOIN vn.zoneExclusionGeo eg ON eg.zoneExclusionFk = e.id
- WHERE e.zoneFk = ?
- AND e.dated BETWEEN ? AND ?
- AND eg.zoneExclusionFk IS NOT NULL;`;
+ SELECT eg.*, e.zoneFk, e.dated, e.created, e.userFk
+ FROM vn.zoneExclusion e
+ LEFT JOIN vn.zoneExclusionGeo eg ON eg.zoneExclusionFk = e.id
+ WHERE e.zoneFk = ?
+ AND e.dated BETWEEN ? AND ?
+ AND eg.zoneExclusionFk IS NOT NULL;`;
const geoExclusions = await Self.rawSql(query, [zoneFk, started, ended], myOptions);
return {events, exclusions, geoExclusions};
};
+ function simpleDate(date) {
+ return date.toISOString().split('T')[0];
+ }
};
diff --git a/modules/zone/back/methods/zone/specs/getEventsFiltered.spec.js b/modules/zone/back/methods/zone/specs/getEventsFiltered.spec.js
index 6fd6bb994..7167b83de 100644
--- a/modules/zone/back/methods/zone/specs/getEventsFiltered.spec.js
+++ b/modules/zone/back/methods/zone/specs/getEventsFiltered.spec.js
@@ -30,7 +30,7 @@ describe('zone getEventsFiltered()', () => {
const result = await models.Zone.getEventsFiltered(9, today, today, options);
- expect(result.events.length).toEqual(1);
+ expect(result.events.length).toEqual(3);
expect(result.exclusions.length).toEqual(0);
await tx.rollback();
@@ -47,11 +47,12 @@ describe('zone getEventsFiltered()', () => {
const options = {transaction: tx};
const date = Date.vnNew();
date.setFullYear(date.getFullYear() - 2);
- const dateTomorrow = new Date(date.setDate(date.getDate() + 1));
+ const dateTomorrow = new Date(date);
+ dateTomorrow.setDate(dateTomorrow.getDate() + 1);
const result = await models.Zone.getEventsFiltered(9, date, dateTomorrow, options);
- expect(result.events.length).toEqual(0);
+ expect(result.events.length).toEqual(1);
expect(result.exclusions.length).toEqual(0);
await tx.rollback();
diff --git a/modules/zone/back/models/zone-closure.js b/modules/zone/back/models/zone-closure.js
index d25d6f707..61350ef56 100644
--- a/modules/zone/back/models/zone-closure.js
+++ b/modules/zone/back/models/zone-closure.js
@@ -14,7 +14,7 @@ module.exports = Self => {
async function doCalc(ctx) {
try {
await Self.rawSql(`
- CREATE EVENT zoneClosure_doRecalc
+ CREATE DEFINER = CURRENT_ROLE EVENT zoneClosure_doRecalc
ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 15 SECOND
DO CALL zoneClosure_recalc;
`);
diff --git a/modules/zone/back/models/zone-event.json b/modules/zone/back/models/zone-event.json
index e477dad6a..366bdec9d 100644
--- a/modules/zone/back/models/zone-event.json
+++ b/modules/zone/back/models/zone-event.json
@@ -1,6 +1,9 @@
{
"name": "ZoneEvent",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "zoneEvent"
diff --git a/modules/zone/back/models/zone-exclusion.json b/modules/zone/back/models/zone-exclusion.json
index 00c9145cd..6e91a0a01 100644
--- a/modules/zone/back/models/zone-exclusion.json
+++ b/modules/zone/back/models/zone-exclusion.json
@@ -1,6 +1,9 @@
{
"name": "ZoneExclusion",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "zoneExclusion"
diff --git a/modules/zone/back/models/zone-included.json b/modules/zone/back/models/zone-included.json
index deba73f34..a34e51091 100644
--- a/modules/zone/back/models/zone-included.json
+++ b/modules/zone/back/models/zone-included.json
@@ -1,6 +1,9 @@
{
"name": "ZoneIncluded",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "zoneIncluded"
diff --git a/modules/zone/back/models/zone-warehouse.json b/modules/zone/back/models/zone-warehouse.json
index b222e95e7..c2cc989f0 100644
--- a/modules/zone/back/models/zone-warehouse.json
+++ b/modules/zone/back/models/zone-warehouse.json
@@ -1,6 +1,9 @@
{
"name": "ZoneWarehouse",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "zoneWarehouse"
diff --git a/modules/zone/back/models/zone.json b/modules/zone/back/models/zone.json
index c86da3d3e..cf7371053 100644
--- a/modules/zone/back/models/zone.json
+++ b/modules/zone/back/models/zone.json
@@ -1,6 +1,9 @@
{
"name": "Zone",
- "base": "Loggable",
+ "base": "VnModel",
+ "mixins": {
+ "Loggable": true
+ },
"options": {
"mysql": {
"table": "zone"
diff --git a/package-lock.json b/package-lock.json
index 12bd0f5bd..114671af9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "salix-back",
- "version": "23.50.01",
+ "version": "24.04.01",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "salix-back",
- "version": "23.50.01",
+ "version": "24.04.01",
"license": "GPL-3.0",
"dependencies": {
"axios": "^1.2.2",
diff --git a/package.json b/package.json
index 18632e00b..bd96b7ece 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "salix-back",
- "version": "23.50.01",
+ "version": "24.04.01",
"author": "Verdnatura Levante SL",
"description": "Salix backend",
"license": "GPL-3.0",
diff --git a/print/templates/reports/driver-route/sql/tickets.sql b/print/templates/reports/driver-route/sql/tickets.sql
index 09e73819b..9d548c2b3 100644
--- a/print/templates/reports/driver-route/sql/tickets.sql
+++ b/print/templates/reports/driver-route/sql/tickets.sql
@@ -20,7 +20,7 @@ SELECT
u.nickName salesPersonName,
ipkg.itemPackingTypes
FROM route r
- LEFT JOIN ticket t ON t.routeFk = r.id
+ JOIN ticket t ON t.routeFk = r.id
LEFT JOIN address a ON a.id = t.addressFk
LEFT JOIN client c ON c.id = t.clientFk
LEFT JOIN worker w ON w.id = client_getSalesPerson(t.clientFk, CURDATE())
diff --git a/print/templates/reports/invoice/invoice.html b/print/templates/reports/invoice/invoice.html
index 45b6c3934..af1aaa423 100644
--- a/print/templates/reports/invoice/invoice.html
+++ b/print/templates/reports/invoice/invoice.html
@@ -16,6 +16,7 @@
{{$t('clientId')}} |
{{client.id}} |
+
{{$t('invoice')}} |
@@ -80,6 +81,9 @@
{{formatDate(ticket.shipped, '%d-%m-%Y')}}
+
+ {{ticket.street}}
+
{{ticket.nickname}}
diff --git a/print/templates/reports/invoice/sql/tickets.sql b/print/templates/reports/invoice/sql/tickets.sql
index a8385599c..35828c5de 100644
--- a/print/templates/reports/invoice/sql/tickets.sql
+++ b/print/templates/reports/invoice/sql/tickets.sql
@@ -2,9 +2,12 @@ SELECT
t.id,
t.shipped,
t.nickname,
- tto.description
+ tto.description,
+ t.addressFk,
+ a.street
FROM invoiceOut io
JOIN ticket t ON t.refFk = io.REF
+ JOIN `address` a ON a.id = t.addressFk
LEFT JOIN observationType ot ON ot.code = 'invoiceOut'
LEFT JOIN ticketObservation tto ON tto.ticketFk = t.id
AND tto.observationTypeFk = ot.id