Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into 3626-client_basic-data
gitea/salix/pipeline/head This commit looks good
Details
gitea/salix/pipeline/head This commit looks good
Details
This commit is contained in:
commit
527387aad5
|
@ -0,0 +1,55 @@
|
||||||
|
const axios = require('axios');
|
||||||
|
const tokenLifespan = 10;
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethodCtx('getServiceAuth', {
|
||||||
|
description: 'Authenticates with the service and request a new token',
|
||||||
|
accessType: 'READ',
|
||||||
|
accepts: [],
|
||||||
|
returns: {
|
||||||
|
type: 'object',
|
||||||
|
root: true
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
path: `/getServiceAuth`,
|
||||||
|
verb: 'GET'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.getServiceAuth = async() => {
|
||||||
|
if (!this.login)
|
||||||
|
this.login = await requestToken();
|
||||||
|
|
||||||
|
if (!this.login) return;
|
||||||
|
|
||||||
|
if (Date.now() > this.login.expires)
|
||||||
|
this.login = await requestToken();
|
||||||
|
|
||||||
|
return this.login;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests a new Rocketchat token
|
||||||
|
*/
|
||||||
|
async function requestToken() {
|
||||||
|
const models = Self.app.models;
|
||||||
|
const chatConfig = await models.ChatConfig.findOne();
|
||||||
|
|
||||||
|
const {data} = await axios.post(`${chatConfig.api}/login`, {
|
||||||
|
user: chatConfig.user,
|
||||||
|
password: chatConfig.password
|
||||||
|
});
|
||||||
|
|
||||||
|
const requestData = data.data;
|
||||||
|
if (requestData) {
|
||||||
|
return {
|
||||||
|
host: chatConfig.host,
|
||||||
|
api: chatConfig.api,
|
||||||
|
auth: {
|
||||||
|
userId: requestData.userId,
|
||||||
|
token: requestData.authToken
|
||||||
|
},
|
||||||
|
expires: Date.now() + (1000 * 60 * tokenLifespan)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
|
@ -1,4 +1,4 @@
|
||||||
const got = require('got');
|
const axios = require('axios');
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
Self.remoteMethodCtx('send', {
|
Self.remoteMethodCtx('send', {
|
||||||
description: 'Send a RocketChat message',
|
description: 'Send a RocketChat message',
|
||||||
|
@ -30,122 +30,35 @@ module.exports = Self => {
|
||||||
const sender = await models.Account.findById(accessToken.userId);
|
const sender = await models.Account.findById(accessToken.userId);
|
||||||
const recipient = to.replace('@', '');
|
const recipient = to.replace('@', '');
|
||||||
|
|
||||||
if (sender.name != recipient) {
|
if (sender.name != recipient)
|
||||||
let {body} = await sendMessage(sender, to, message);
|
return sendMessage(sender, to, message);
|
||||||
if (body)
|
|
||||||
body = JSON.parse(body);
|
|
||||||
else
|
|
||||||
body = false;
|
|
||||||
|
|
||||||
return body;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
async function sendMessage(sender, channel, message) {
|
async function sendMessage(sender, channel, message) {
|
||||||
const config = await getConfig();
|
|
||||||
const avatar = `${config.host}/avatar/${sender.name}`;
|
|
||||||
const uri = `${config.api}/chat.postMessage`;
|
|
||||||
|
|
||||||
return sendAuth(uri, {
|
|
||||||
'channel': channel,
|
|
||||||
'avatar': avatar,
|
|
||||||
'alias': sender.nickname,
|
|
||||||
'text': message
|
|
||||||
}).catch(async error => {
|
|
||||||
if (error.statusCode === 401) {
|
|
||||||
this.auth = null;
|
|
||||||
|
|
||||||
return sendMessage(sender, channel, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error(error.message);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a rocketchat token
|
|
||||||
* @return {Object} userId and authToken
|
|
||||||
*/
|
|
||||||
async function getAuthToken() {
|
|
||||||
if (!this.auth || this.auth && !this.auth.authToken) {
|
|
||||||
const config = await getConfig();
|
|
||||||
const uri = `${config.api}/login`;
|
|
||||||
let {body} = await send(uri, {
|
|
||||||
user: config.user,
|
|
||||||
password: config.password
|
|
||||||
});
|
|
||||||
|
|
||||||
if (body) {
|
|
||||||
body = JSON.parse(body);
|
|
||||||
this.auth = body.data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.auth;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a rocketchat config
|
|
||||||
* @return {Object} Auth config
|
|
||||||
*/
|
|
||||||
async function getConfig() {
|
|
||||||
if (!this.chatConfig) {
|
|
||||||
const models = Self.app.models;
|
|
||||||
|
|
||||||
this.chatConfig = await models.ChatConfig.findOne();
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.chatConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send unauthenticated request
|
|
||||||
* @param {*} uri - Request uri
|
|
||||||
* @param {*} params - Request params
|
|
||||||
* @param {*} options - Request options
|
|
||||||
*
|
|
||||||
* @return {Object} Request response
|
|
||||||
*/
|
|
||||||
async function send(uri, params, options = {}) {
|
|
||||||
if (process.env.NODE_ENV !== 'production') {
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
return resolve({
|
return resolve({
|
||||||
body: JSON.stringify(
|
statusCode: 200,
|
||||||
{statusCode: 200, message: 'Fake notification sent'}
|
message: 'Fake notification sent'
|
||||||
)
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultOptions = {
|
const login = await Self.getServiceAuth();
|
||||||
form: params
|
const avatar = `${login.host}/avatar/${sender.name}`;
|
||||||
};
|
|
||||||
|
|
||||||
if (options) Object.assign(defaultOptions, options);
|
|
||||||
|
|
||||||
return got.post(uri, defaultOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send authenticated request
|
|
||||||
* @param {*} uri - Request uri
|
|
||||||
* @param {*} body - Request params
|
|
||||||
*
|
|
||||||
* @return {Object} Request response
|
|
||||||
*/
|
|
||||||
async function sendAuth(uri, body) {
|
|
||||||
const login = await getAuthToken();
|
|
||||||
const options = {
|
const options = {
|
||||||
headers: {}
|
headers: {
|
||||||
|
'X-Auth-Token': login.auth.token,
|
||||||
|
'X-User-Id': login.auth.userId
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
if (login) {
|
return axios.post(`${login.api}/chat.postMessage`, {
|
||||||
options.headers['X-Auth-Token'] = login.authToken;
|
'channel': channel,
|
||||||
options.headers['X-User-Id'] = login.userId;
|
'avatar': avatar,
|
||||||
}
|
'alias': sender.nickname,
|
||||||
|
'text': message
|
||||||
return send(uri, body, options);
|
}, options);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,21 +1,23 @@
|
||||||
|
const axios = require('axios');
|
||||||
|
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
Self.remoteMethodCtx('sendCheckingPresence', {
|
Self.remoteMethodCtx('sendCheckingPresence', {
|
||||||
description: 'Sends a RocketChat message to a working worker or department channel',
|
description: 'Sends a RocketChat message to a connected user or department channel',
|
||||||
accessType: 'WRITE',
|
accessType: 'WRITE',
|
||||||
accepts: [{
|
accepts: [{
|
||||||
arg: 'workerId',
|
arg: 'recipientId',
|
||||||
type: 'Number',
|
type: 'number',
|
||||||
required: true,
|
required: true,
|
||||||
description: 'The worker id of the destinatary'
|
description: 'The recipient user id'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
arg: 'message',
|
arg: 'message',
|
||||||
type: 'String',
|
type: 'string',
|
||||||
required: true,
|
required: true,
|
||||||
description: 'The message'
|
description: 'The message'
|
||||||
}],
|
}],
|
||||||
returns: {
|
returns: {
|
||||||
type: 'Object',
|
type: 'object',
|
||||||
root: true
|
root: true
|
||||||
},
|
},
|
||||||
http: {
|
http: {
|
||||||
|
@ -33,30 +35,61 @@ module.exports = Self => {
|
||||||
Object.assign(myOptions, options);
|
Object.assign(myOptions, options);
|
||||||
|
|
||||||
const models = Self.app.models;
|
const models = Self.app.models;
|
||||||
const account = await models.Account.findById(recipientId, null, myOptions);
|
|
||||||
const userId = ctx.req.accessToken.userId;
|
const userId = ctx.req.accessToken.userId;
|
||||||
|
const recipient = await models.Account.findById(recipientId, null, myOptions);
|
||||||
|
|
||||||
|
// Prevent sending messages to yourself
|
||||||
if (recipientId == userId) return false;
|
if (recipientId == userId) return false;
|
||||||
|
|
||||||
if (!account)
|
if (!recipient)
|
||||||
throw new Error(`Could not send message "${message}" to worker id ${recipientId} from user ${userId}`);
|
throw new Error(`Could not send message "${message}" to worker id ${recipientId} from user ${userId}`);
|
||||||
|
|
||||||
const query = `SELECT worker_isWorking(?) isWorking`;
|
const {data} = await Self.getUserStatus(recipient.name);
|
||||||
const [result] = await Self.rawSql(query, [recipientId], myOptions);
|
if (data) {
|
||||||
|
if (data.status === 'offline') {
|
||||||
|
// Send message to department room
|
||||||
|
const workerDepartment = await models.WorkerDepartment.findById(recipientId, {
|
||||||
|
include: {
|
||||||
|
relation: 'department'
|
||||||
|
}
|
||||||
|
}, myOptions);
|
||||||
|
const department = workerDepartment && workerDepartment.department();
|
||||||
|
const channelName = department && department.chatName;
|
||||||
|
|
||||||
if (!result.isWorking) {
|
if (channelName)
|
||||||
const workerDepartment = await models.WorkerDepartment.findById(recipientId, {
|
return Self.send(ctx, `#${channelName}`, `@${recipient.name} ➔ ${message}`);
|
||||||
include: {
|
} else
|
||||||
relation: 'department'
|
return Self.send(ctx, `@${recipient.name}`, message);
|
||||||
}
|
}
|
||||||
}, myOptions);
|
};
|
||||||
const department = workerDepartment && workerDepartment.department();
|
|
||||||
const channelName = department && department.chatName;
|
|
||||||
|
|
||||||
if (channelName)
|
/**
|
||||||
return Self.send(ctx, `#${channelName}`, `@${account.name} ➔ ${message}`);
|
* Returns the current user status on Rocketchat
|
||||||
|
*
|
||||||
|
* @param {string} username - The recipient user name
|
||||||
|
* @return {Promise} - The request promise
|
||||||
|
*/
|
||||||
|
Self.getUserStatus = async function getUserStatus(username) {
|
||||||
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
return resolve({
|
||||||
|
data: {
|
||||||
|
status: 'online'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return Self.send(ctx, `@${account.name}`, message);
|
const login = await Self.getServiceAuth();
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
params: {username},
|
||||||
|
headers: {
|
||||||
|
'X-Auth-Token': login.auth.token,
|
||||||
|
'X-User-Id': login.auth.userId
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return axios.get(`${login.api}/users.getStatus`, options);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,46 +1,62 @@
|
||||||
const app = require('vn-loopback/server/server');
|
const models = require('vn-loopback/server/server').models;
|
||||||
|
|
||||||
describe('Chat sendCheckingPresence()', () => {
|
describe('Chat sendCheckingPresence()', () => {
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
today.setHours(6, 0);
|
today.setHours(6, 0);
|
||||||
const ctx = {req: {accessToken: {userId: 1}}};
|
const ctx = {req: {accessToken: {userId: 1}}};
|
||||||
const chatModel = app.models.Chat;
|
const chatModel = models.Chat;
|
||||||
const departmentId = 23;
|
const departmentId = 23;
|
||||||
const workerId = 1107;
|
const workerId = 1107;
|
||||||
|
|
||||||
it(`should call send() method with the worker name if he's currently working then return a response`, async() => {
|
it(`should call to send() method with "@HankPym" as recipient argument`, async() => {
|
||||||
spyOn(chatModel, 'send').and.callThrough();
|
spyOn(chatModel, 'send').and.callThrough();
|
||||||
|
spyOn(chatModel, 'getUserStatus').and.returnValue(
|
||||||
const timeEntry = await app.models.WorkerTimeControl.create({
|
new Promise(resolve => {
|
||||||
userFk: workerId,
|
return resolve({
|
||||||
timed: today,
|
data: {
|
||||||
manual: false,
|
status: 'online'
|
||||||
direction: 'in'
|
}
|
||||||
});
|
});
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
const response = await chatModel.sendCheckingPresence(ctx, workerId, 'I changed something');
|
const response = await chatModel.sendCheckingPresence(ctx, workerId, 'I changed something');
|
||||||
|
|
||||||
expect(response.statusCode).toEqual(200);
|
expect(response.statusCode).toEqual(200);
|
||||||
expect(response.message).toEqual('Fake notification sent');
|
expect(response.message).toEqual('Fake notification sent');
|
||||||
expect(chatModel.send).toHaveBeenCalledWith(ctx, '@HankPym', 'I changed something');
|
expect(chatModel.send).toHaveBeenCalledWith(ctx, '@HankPym', 'I changed something');
|
||||||
|
|
||||||
// restores
|
|
||||||
await app.models.WorkerTimeControl.destroyById(timeEntry.id);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should call to send() method with the worker department channel if he's not currently working then return a response`, async() => {
|
it(`should call to send() method with "#cooler" as recipient argument`, async() => {
|
||||||
spyOn(chatModel, 'send').and.callThrough();
|
spyOn(chatModel, 'send').and.callThrough();
|
||||||
|
spyOn(chatModel, 'getUserStatus').and.returnValue(
|
||||||
|
new Promise(resolve => {
|
||||||
|
return resolve({
|
||||||
|
data: {
|
||||||
|
status: 'offline'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
const department = await app.models.Department.findById(departmentId);
|
const tx = await models.Claim.beginTransaction({});
|
||||||
await department.updateAttribute('chatName', 'cooler');
|
|
||||||
|
|
||||||
const response = await chatModel.sendCheckingPresence(ctx, workerId, 'I changed something');
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
expect(response.statusCode).toEqual(200);
|
const department = await models.Department.findById(departmentId, null, options);
|
||||||
expect(response.message).toEqual('Fake notification sent');
|
await department.updateAttribute('chatName', 'cooler');
|
||||||
expect(chatModel.send).toHaveBeenCalledWith(ctx, '#cooler', '@HankPym ➔ I changed something');
|
|
||||||
|
|
||||||
// restores
|
const response = await chatModel.sendCheckingPresence(ctx, workerId, 'I changed something');
|
||||||
await department.updateAttribute('chatName', null);
|
|
||||||
|
expect(response.statusCode).toEqual(200);
|
||||||
|
expect(response.message).toEqual('Fake notification sent');
|
||||||
|
expect(chatModel.send).toHaveBeenCalledWith(ctx, '#cooler', '@HankPym ➔ I changed something');
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
const got = require('got');
|
||||||
|
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethodCtx('checkFile', {
|
||||||
|
description: 'Check if exist docuware file',
|
||||||
|
accessType: 'READ',
|
||||||
|
accepts: [
|
||||||
|
{
|
||||||
|
arg: 'id',
|
||||||
|
type: 'number',
|
||||||
|
description: 'The id',
|
||||||
|
http: {source: 'path'}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'fileCabinet',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
description: 'The fileCabinet name'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'dialog',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
description: 'The dialog name'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
returns: {
|
||||||
|
type: 'boolean',
|
||||||
|
root: true
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
path: `/:id/checkFile`,
|
||||||
|
verb: 'POST'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.checkFile = async function(ctx, id, fileCabinet, dialog) {
|
||||||
|
const myUserId = ctx.req.accessToken.userId;
|
||||||
|
if (!myUserId)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const models = Self.app.models;
|
||||||
|
const docuwareConfig = await models.DocuwareConfig.findOne();
|
||||||
|
const docuwareInfo = await models.Docuware.findOne({
|
||||||
|
where: {
|
||||||
|
code: fileCabinet,
|
||||||
|
dialogName: dialog
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const docuwareUrl = docuwareConfig.url;
|
||||||
|
const cookie = docuwareConfig.token;
|
||||||
|
const fileCabinetName = docuwareInfo.fileCabinetName;
|
||||||
|
const find = docuwareInfo.find;
|
||||||
|
const options = {
|
||||||
|
'headers': {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Cookie': cookie
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const searchFilter = {
|
||||||
|
condition: [
|
||||||
|
{
|
||||||
|
DBName: find,
|
||||||
|
Value: [id]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
// get fileCabinetId
|
||||||
|
const fileCabinetResponse = await got.get(`${docuwareUrl}/FileCabinets`, options);
|
||||||
|
const fileCabinetJson = JSON.parse(fileCabinetResponse.body).FileCabinet;
|
||||||
|
const fileCabinetId = fileCabinetJson.find(dialogs => dialogs.Name === fileCabinetName).Id;
|
||||||
|
|
||||||
|
// get dialog
|
||||||
|
const dialogResponse = await got.get(`${docuwareUrl}/FileCabinets/${fileCabinetId}/dialogs`, options);
|
||||||
|
const dialogJson = JSON.parse(dialogResponse.body).Dialog;
|
||||||
|
const dialogId = dialogJson.find(dialogs => dialogs.DisplayName === 'find').Id;
|
||||||
|
|
||||||
|
// get docuwareID
|
||||||
|
Object.assign(options, {'body': JSON.stringify(searchFilter)});
|
||||||
|
const response = await got.post(
|
||||||
|
`${docuwareUrl}/FileCabinets/${fileCabinetId}/Query/DialogExpression?dialogId=${dialogId}`, options);
|
||||||
|
JSON.parse(response.body).Items[0].Id;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,120 @@
|
||||||
|
/* eslint max-len: ["error", { "code": 180 }]*/
|
||||||
|
const got = require('got');
|
||||||
|
const UserError = require('vn-loopback/util/user-error');
|
||||||
|
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethodCtx('download', {
|
||||||
|
description: 'Download an docuware PDF',
|
||||||
|
accessType: 'READ',
|
||||||
|
accepts: [
|
||||||
|
{
|
||||||
|
arg: 'id',
|
||||||
|
type: 'number',
|
||||||
|
description: 'The id',
|
||||||
|
http: {source: 'path'}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'fileCabinet',
|
||||||
|
type: 'string',
|
||||||
|
description: 'The id',
|
||||||
|
http: {source: 'path'}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'dialog',
|
||||||
|
type: 'string',
|
||||||
|
description: 'The id',
|
||||||
|
http: {source: 'path'}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
returns: [
|
||||||
|
{
|
||||||
|
arg: 'body',
|
||||||
|
type: 'file',
|
||||||
|
root: true
|
||||||
|
}, {
|
||||||
|
arg: 'Content-Type',
|
||||||
|
type: 'string',
|
||||||
|
http: {target: 'header'}
|
||||||
|
}, {
|
||||||
|
arg: 'Content-Disposition',
|
||||||
|
type: 'string',
|
||||||
|
http: {target: 'header'}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
http: {
|
||||||
|
path: `/:id/download/:fileCabinet/:dialog`,
|
||||||
|
verb: 'GET'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.download = async function(ctx, id, fileCabinet, dialog) {
|
||||||
|
const myUserId = ctx.req.accessToken.userId;
|
||||||
|
if (!myUserId)
|
||||||
|
throw new UserError(`You don't have enough privileges`);
|
||||||
|
|
||||||
|
const models = Self.app.models;
|
||||||
|
const docuwareConfig = await models.DocuwareConfig.findOne();
|
||||||
|
const docuwareInfo = await models.Docuware.findOne({
|
||||||
|
where: {
|
||||||
|
code: fileCabinet,
|
||||||
|
dialogName: dialog
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const docuwareUrl = docuwareConfig.url;
|
||||||
|
const cookie = docuwareConfig.token;
|
||||||
|
const fileCabinetName = docuwareInfo.fileCabinetName;
|
||||||
|
const find = docuwareInfo.find;
|
||||||
|
const options = {
|
||||||
|
'headers': {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Cookie': cookie
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const searchFilter = {
|
||||||
|
condition: [
|
||||||
|
{
|
||||||
|
DBName: find,
|
||||||
|
Value: [id]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
// get fileCabinetId
|
||||||
|
const fileCabinetResponse = await got.get(`${docuwareUrl}/FileCabinets`, options);
|
||||||
|
const fileCabinetJson = JSON.parse(fileCabinetResponse.body).FileCabinet;
|
||||||
|
const fileCabinetId = fileCabinetJson.find(dialogs => dialogs.Name === fileCabinetName).Id;
|
||||||
|
|
||||||
|
// get dialog
|
||||||
|
const dialogResponse = await got.get(`${docuwareUrl}/FileCabinets/${fileCabinetId}/dialogs`, options);
|
||||||
|
const dialogJson = JSON.parse(dialogResponse.body).Dialog;
|
||||||
|
const dialogId = dialogJson.find(dialogs => dialogs.DisplayName === 'find').Id;
|
||||||
|
|
||||||
|
// get docuwareID
|
||||||
|
Object.assign(options, {'body': JSON.stringify(searchFilter)});
|
||||||
|
const response = await got.post(`${docuwareUrl}/FileCabinets/${fileCabinetId}/Query/DialogExpression?dialogId=${dialogId}`, options);
|
||||||
|
const docuwareId = JSON.parse(response.body).Items[0].Id;
|
||||||
|
|
||||||
|
// download & save file
|
||||||
|
const fileName = `filename="${id}.pdf"`;
|
||||||
|
const contentType = 'application/pdf';
|
||||||
|
const downloadUri = `${docuwareUrl}/FileCabinets/${fileCabinetId}/Documents/${docuwareId}/FileDownload?targetFileType=Auto&keepAnnotations=false`;
|
||||||
|
const downloadOptions = {
|
||||||
|
'headers': {
|
||||||
|
'Cookie': cookie
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const stream = got.stream(downloadUri, downloadOptions);
|
||||||
|
|
||||||
|
return [stream, contentType, fileName];
|
||||||
|
} catch (error) {
|
||||||
|
if (error.code === 'ENOENT')
|
||||||
|
throw new UserError('The DOCUWARE PDF document does not exists');
|
||||||
|
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,64 @@
|
||||||
|
const models = require('vn-loopback/server/server').models;
|
||||||
|
const got = require('got');
|
||||||
|
|
||||||
|
describe('docuware download()', () => {
|
||||||
|
const ticketId = 1;
|
||||||
|
const userId = 9;
|
||||||
|
const ctx = {
|
||||||
|
req: {
|
||||||
|
|
||||||
|
accessToken: {userId: userId},
|
||||||
|
headers: {origin: 'http://localhost:5000'},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const fileCabinetName = 'deliveryClientTest';
|
||||||
|
const dialogDisplayName = 'find';
|
||||||
|
const dialogName = 'findTest';
|
||||||
|
|
||||||
|
const gotGetResponse = {
|
||||||
|
body: JSON.stringify(
|
||||||
|
{
|
||||||
|
FileCabinet: [
|
||||||
|
{Id: 12, Name: fileCabinetName}
|
||||||
|
],
|
||||||
|
Dialog: [
|
||||||
|
{Id: 34, DisplayName: dialogDisplayName}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
it('should return exist file in docuware', async() => {
|
||||||
|
const gotPostResponse = {
|
||||||
|
body: JSON.stringify(
|
||||||
|
{
|
||||||
|
Items: [
|
||||||
|
{Id: 56}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
spyOn(got, 'get').and.returnValue(new Promise(resolve => resolve(gotGetResponse)));
|
||||||
|
spyOn(got, 'post').and.returnValue(new Promise(resolve => resolve(gotPostResponse)));
|
||||||
|
|
||||||
|
const result = await models.Docuware.checkFile(ctx, ticketId, fileCabinetName, dialogName);
|
||||||
|
|
||||||
|
expect(result).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return not exist file in docuware', async() => {
|
||||||
|
const gotPostResponse = {
|
||||||
|
body: JSON.stringify(
|
||||||
|
{
|
||||||
|
Items: [],
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
spyOn(got, 'get').and.returnValue(new Promise(resolve => resolve(gotGetResponse)));
|
||||||
|
spyOn(got, 'post').and.returnValue(new Promise(resolve => resolve(gotPostResponse)));
|
||||||
|
|
||||||
|
const result = await models.Docuware.checkFile(ctx, ticketId, fileCabinetName, dialogName);
|
||||||
|
|
||||||
|
expect(result).toEqual(false);
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,50 @@
|
||||||
|
const models = require('vn-loopback/server/server').models;
|
||||||
|
const got = require('got');
|
||||||
|
const stream = require('stream');
|
||||||
|
|
||||||
|
describe('docuware download()', () => {
|
||||||
|
const userId = 9;
|
||||||
|
const ticketId = 1;
|
||||||
|
const ctx = {
|
||||||
|
req: {
|
||||||
|
|
||||||
|
accessToken: {userId: userId},
|
||||||
|
headers: {origin: 'http://localhost:5000'},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
it('should return the downloaded file name', async() => {
|
||||||
|
const fileCabinetName = 'deliveryClientTest';
|
||||||
|
const dialogDisplayName = 'find';
|
||||||
|
const dialogName = 'findTest';
|
||||||
|
const gotGetResponse = {
|
||||||
|
body: JSON.stringify(
|
||||||
|
{
|
||||||
|
FileCabinet: [
|
||||||
|
{Id: 12, Name: fileCabinetName}
|
||||||
|
],
|
||||||
|
Dialog: [
|
||||||
|
{Id: 34, DisplayName: dialogDisplayName}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
const gotPostResponse = {
|
||||||
|
body: JSON.stringify(
|
||||||
|
{
|
||||||
|
Items: [
|
||||||
|
{Id: 56}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
spyOn(got, 'get').and.returnValue(new Promise(resolve => resolve(gotGetResponse)));
|
||||||
|
spyOn(got, 'post').and.returnValue(new Promise(resolve => resolve(gotPostResponse)));
|
||||||
|
spyOn(got, 'stream').and.returnValue(new stream.PassThrough({objectMode: true}));
|
||||||
|
|
||||||
|
const result = await models.Docuware.download(ctx, ticketId, fileCabinetName, dialogName);
|
||||||
|
|
||||||
|
expect(result[1]).toEqual('application/pdf');
|
||||||
|
expect(result[2]).toEqual(`filename="${ticketId}.pdf"`);
|
||||||
|
});
|
||||||
|
});
|
|
@ -44,6 +44,12 @@
|
||||||
"DmsType": {
|
"DmsType": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
"Docuware": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
|
"DocuwareConfig": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
"EmailUser": {
|
"EmailUser": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
|
require('../methods/chat/getServiceAuth')(Self);
|
||||||
require('../methods/chat/send')(Self);
|
require('../methods/chat/send')(Self);
|
||||||
require('../methods/chat/sendCheckingPresence')(Self);
|
require('../methods/chat/sendCheckingPresence')(Self);
|
||||||
require('../methods/chat/notifyIssues')(Self);
|
require('../methods/chat/notifyIssues')(Self);
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
{
|
||||||
|
"name": "DocuwareConfig",
|
||||||
|
"description": "Docuware config",
|
||||||
|
"base": "VnModel",
|
||||||
|
"options": {
|
||||||
|
"mysql": {
|
||||||
|
"table": "docuwareConfig"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "number",
|
||||||
|
"id": true,
|
||||||
|
"description": "Identifier"
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"token": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"acls": [
|
||||||
|
{
|
||||||
|
"property": "*",
|
||||||
|
"accessType": "*",
|
||||||
|
"principalType": "ROLE",
|
||||||
|
"principalId": "$everyone",
|
||||||
|
"permission": "ALLOW"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
module.exports = Self => {
|
||||||
|
require('../methods/docuware/download')(Self);
|
||||||
|
require('../methods/docuware/checkFile')(Self);
|
||||||
|
};
|
|
@ -0,0 +1,38 @@
|
||||||
|
{
|
||||||
|
"name": "Docuware",
|
||||||
|
"description": "Docuware sections",
|
||||||
|
"base": "VnModel",
|
||||||
|
"options": {
|
||||||
|
"mysql": {
|
||||||
|
"table": "docuware"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "number",
|
||||||
|
"id": true,
|
||||||
|
"description": "Identifier"
|
||||||
|
},
|
||||||
|
"code": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"fileCabinetName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"dialogName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"find": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"acls": [
|
||||||
|
{
|
||||||
|
"property": "*",
|
||||||
|
"accessType": "*",
|
||||||
|
"principalType": "ROLE",
|
||||||
|
"principalId": "$everyone",
|
||||||
|
"permission": "ALLOW"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
DELETE FROM salix.ACL
|
||||||
|
WHERE model = 'ClaimEnd' AND property = 'importTicketSales';
|
|
@ -0,0 +1,3 @@
|
||||||
|
INSERT INTO salix.ACL
|
||||||
|
(model, property, accessType, permission, principalType, principalId)
|
||||||
|
VALUES('Docuware', '*', '*', 'ALLOW', 'ROLE', 'employee');
|
|
@ -0,0 +1,11 @@
|
||||||
|
CREATE TABLE `vn`.`docuware` (
|
||||||
|
`id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
`code` varchar(50) NULL,
|
||||||
|
`fileCabinetName` varchar(50) NULL,
|
||||||
|
`dialogName` varchar(255) DEFAULT NULL,
|
||||||
|
`find` varchar(50) DEFAULT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO `vn`.`docuware` (`code`, `fileCabinetName`, `dialogName` , `find`)
|
||||||
|
VALUES
|
||||||
|
('deliveryClient', 'Albaranes cliente', 'findTicket', 'N__ALBAR_N');
|
|
@ -0,0 +1,9 @@
|
||||||
|
CREATE TABLE `vn`.`docuwareConfig` (
|
||||||
|
`id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
`url` varchar(75) NULL,
|
||||||
|
`token` varchar(1000) DEFAULT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO `vn`.`docuwareConfig` (`url`)
|
||||||
|
VALUES
|
||||||
|
('https://verdnatura.docuware.cloud/docuware/platform');
|
|
@ -6,20 +6,23 @@ CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`ticket_getMovable`(vTicketFk INT, vDat
|
||||||
BEGIN
|
BEGIN
|
||||||
/**
|
/**
|
||||||
* Cálcula el stock movible para los artículos de un ticket
|
* Cálcula el stock movible para los artículos de un ticket
|
||||||
|
* vDatedNew debe ser menor que vDatedOld, en los otros casos se
|
||||||
|
* asume que siempre es posible
|
||||||
*
|
*
|
||||||
* @param vTicketFk -> Ticket
|
* @param vTicketFk -> Ticket
|
||||||
* @param vDatedNew -> Nueva fecha
|
* @param vDatedNew -> Nueva fecha
|
||||||
* @return Sales con Movible
|
* @return Sales con Movible
|
||||||
*/
|
*/
|
||||||
DECLARE vDatedOld DATETIME;
|
DECLARE vDatedOld DATETIME;
|
||||||
|
SET vDatedNew = DATE_ADD(vDatedNew, INTERVAL 1 DAY);
|
||||||
|
|
||||||
SELECT t.shipped INTO vDatedOld
|
SELECT t.shipped INTO vDatedOld
|
||||||
FROM ticket t
|
FROM ticket t
|
||||||
WHERE t.id = vTicketFk;
|
WHERE t.id = vTicketFk;
|
||||||
|
|
||||||
CALL itemStock(vWarehouseFk, DATE_SUB(vDatedNew, INTERVAL 1 DAY), NULL);
|
CALL itemStock(vWarehouseFk, vDatedNew, NULL);
|
||||||
CALL item_getMinacum(vWarehouseFk, vDatedNew, DATEDIFF(vDatedOld, vDatedNew), NULL);
|
CALL item_getMinacum(vWarehouseFk, vDatedNew, DATEDIFF(DATE_SUB(vDatedOld, INTERVAL 1 DAY), vDatedNew), NULL);
|
||||||
|
|
||||||
SELECT s.id,
|
SELECT s.id,
|
||||||
s.itemFk,
|
s.itemFk,
|
||||||
s.quantity,
|
s.quantity,
|
|
@ -0,0 +1,3 @@
|
||||||
|
INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
|
||||||
|
VALUES
|
||||||
|
('ClaimLog', '*', 'READ', 'ALLOW', 'ROLE', 'claimManager');
|
|
@ -1703,10 +1703,10 @@ INSERT INTO `vn`.`claimState`(`id`, `code`, `description`, `roleFk`, `priority`)
|
||||||
|
|
||||||
INSERT INTO `vn`.`claim`(`id`, `ticketCreated`, `claimStateFk`, `observation`, `clientFk`, `workerFk`, `responsibility`, `isChargedToMana`, `created` )
|
INSERT INTO `vn`.`claim`(`id`, `ticketCreated`, `claimStateFk`, `observation`, `clientFk`, `workerFk`, `responsibility`, `isChargedToMana`, `created` )
|
||||||
VALUES
|
VALUES
|
||||||
(1, CURDATE(), 1, 'observation one', 1101, 18, 3, 0, CURDATE()),
|
(1, CURDATE(), 1, 'Cu nam labores lobortis definiebas, ei aliquyam salutatus persequeris quo, cum eu nemore fierent dissentiunt. Per vero dolor id, vide democritum scribentur eu vim, pri erroribus temporibus ex.', 1101, 18, 3, 0, CURDATE()),
|
||||||
(2, CURDATE(), 2, 'observation two', 1101, 18, 3, 0, CURDATE()),
|
(2, CURDATE(), 2, 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.', 1101, 18, 3, 0, CURDATE()),
|
||||||
(3, CURDATE(), 3, 'observation three', 1101, 18, 1, 1, CURDATE()),
|
(3, CURDATE(), 3, 'An vim commodo dolorem volutpat, cu expetendis voluptatum usu, et mutat consul adversarium his. His natum numquam legimus an, diam fabulas mei ut. Melius fabellas sadipscing vel id. Partem diceret mandamus mea ne, has te tempor nostrud. Aeque nostro eum no.', 1101, 18, 1, 1, CURDATE()),
|
||||||
(4, CURDATE(), 3, 'observation four', 1104, 18, 5, 0, CURDATE());
|
(4, CURDATE(), 3, 'Wisi forensibus mnesarchum in cum. Per id impetus abhorreant, his no magna definiebas, inani rationibus in quo. Ut vidisse dolores est, ut quis nominavi mel. Ad pri quod apeirian concludaturque.', 1104, 18, 5, 0, CURDATE());
|
||||||
|
|
||||||
INSERT INTO `vn`.`claimBeginning`(`id`, `claimFk`, `saleFk`, `quantity`)
|
INSERT INTO `vn`.`claimBeginning`(`id`, `claimFk`, `saleFk`, `quantity`)
|
||||||
VALUES
|
VALUES
|
||||||
|
@ -1851,6 +1851,15 @@ INSERT INTO `postgresql`.`business_labour`(`business_id`, `notes`, `department_i
|
||||||
SELECT b.business_id, NULL, 23, 1, 0, 1, 1, 1, 1
|
SELECT b.business_id, NULL, 23, 1, 0, 1, 1, 1, 1
|
||||||
FROM `postgresql`.`business` `b`;
|
FROM `postgresql`.`business` `b`;
|
||||||
|
|
||||||
|
INSERT INTO `postgresql`.`business` (`client_id`, `provider_id`, `date_start`, `date_end`, `workerBusiness`, `reasonEndFk`)
|
||||||
|
SELECT p.profile_id, 1000, CONCAT(YEAR(DATE_ADD(CURDATE(), INTERVAL -2 YEAR)), '-12-25'), CONCAT(YEAR(DATE_ADD(CURDATE(), INTERVAL -1 YEAR)), '-12-24'), CONCAT('E-46-',RPAD(CONCAT(p.profile_id,9),8,p.profile_id)), NULL
|
||||||
|
FROM `postgresql`.`profile` `p`
|
||||||
|
WHERE `p`.`profile_id` = 1109;
|
||||||
|
|
||||||
|
INSERT INTO `postgresql`.`business_labour` (`business_id`, `notes`, `department_id`, `professional_category_id`, `incentivo`, `calendar_labour_type_id`, `porhoras`, `labour_agreement_id`, `workcenter_id`)
|
||||||
|
VALUES
|
||||||
|
(1111, NULL, 23, 1, 0.0, 1, 1, 1, 1);
|
||||||
|
|
||||||
UPDATE `postgresql`.`business_labour` bl
|
UPDATE `postgresql`.`business_labour` bl
|
||||||
JOIN `postgresql`.`business` b ON b.business_id = bl.business_id
|
JOIN `postgresql`.`business` b ON b.business_id = bl.business_id
|
||||||
JOIN `postgresql`.`profile` pr ON pr.profile_id = b.client_id
|
JOIN `postgresql`.`profile` pr ON pr.profile_id = b.client_id
|
||||||
|
@ -2444,15 +2453,22 @@ INSERT INTO `bs`.`defaulter` (`clientFk`, `amount`, `created`, `defaulterSinced`
|
||||||
(1107, 500, CURDATE(), CURDATE()),
|
(1107, 500, CURDATE(), CURDATE()),
|
||||||
(1109, 500, CURDATE(), CURDATE());
|
(1109, 500, CURDATE(), CURDATE());
|
||||||
|
|
||||||
INSERT INTO `bs`.`vendedores` (`Id_Trabajador`, `año`, `mes`, `portfolioWeight`)
|
INSERT INTO `bs`.`salesPerson` (`workerFk`, `year`, `month`, `portfolioWeight`)
|
||||||
VALUES
|
VALUES
|
||||||
(18, YEAR(CURDATE()), MONTH(CURDATE()), 807.23),
|
(18, YEAR(CURDATE()), MONTH(CURDATE()), 807.23),
|
||||||
(19, YEAR(CURDATE()), MONTH(CURDATE()), 34.40);
|
(19, YEAR(CURDATE()), MONTH(CURDATE()), 34.40);
|
||||||
|
|
||||||
INSERT INTO `bs`.`ventas` (`Id_Movimiento`, `importe`, `fecha`, `tipo_id`, `Id_Cliente`)
|
INSERT INTO `bs`.`sale` (`saleFk`, `amount`, `dated`, `typeFk`, `clientFk`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, 501.95, CURDATE(), 2, 1101),
|
(1, 501.95, CURDATE(), 2, 1101),
|
||||||
(2, 70.7, CURDATE(), 2, 1101),
|
(2, 70.7, CURDATE(), 2, 1101),
|
||||||
(3, 200.78, CURDATE(), 2, 1101),
|
(3, 200.78, CURDATE(), 2, 1101),
|
||||||
(4, 33.8, CURDATE(), 1, 1101),
|
(4, 33.8, CURDATE(), 1, 1101),
|
||||||
(30, 34.4, CURDATE(), 1, 1108);
|
(30, 34.4, CURDATE(), 1, 1108);
|
||||||
|
INSERT INTO `vn`.`docuware` (`code`, `fileCabinetName`, `dialogName` , `find`)
|
||||||
|
VALUES
|
||||||
|
('deliveryClientTest', 'deliveryClientTest', 'findTest', 'word');
|
||||||
|
|
||||||
|
INSERT INTO `vn`.`docuwareConfig` (`url`)
|
||||||
|
VALUES
|
||||||
|
('https://verdnatura.docuware.cloud/docuware/platform');
|
||||||
|
|
|
@ -305,12 +305,12 @@ export default {
|
||||||
anyCreditInsuranceLine: 'vn-client-credit-insurance-insurance-index vn-tbody > vn-tr',
|
anyCreditInsuranceLine: 'vn-client-credit-insurance-insurance-index vn-tbody > vn-tr',
|
||||||
},
|
},
|
||||||
clientDefaulter: {
|
clientDefaulter: {
|
||||||
anyClient: 'vn-client-defaulter-index vn-tbody > vn-tr',
|
anyClient: 'vn-client-defaulter tbody > tr',
|
||||||
firstClientName: 'vn-client-defaulter-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(2) > span',
|
firstClientName: 'vn-client-defaulter tbody > tr:nth-child(1) > td:nth-child(2) > span',
|
||||||
firstSalesPersonName: 'vn-client-defaulter-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(3) > span',
|
firstSalesPersonName: 'vn-client-defaulter tbody > tr:nth-child(1) > td:nth-child(3) > span',
|
||||||
firstObservation: 'vn-client-defaulter-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(6) > vn-textarea[ng-model="defaulter.observation"]',
|
firstObservation: 'vn-client-defaulter tbody > tr:nth-child(1) > td:nth-child(6) > vn-textarea[ng-model="defaulter.observation"]',
|
||||||
allDefaulterCheckbox: 'vn-client-defaulter-index vn-thead vn-multi-check',
|
allDefaulterCheckbox: 'vn-client-defaulter thead vn-multi-check',
|
||||||
addObservationButton: 'vn-client-defaulter-index vn-button[icon="icon-notes"]',
|
addObservationButton: 'vn-client-defaulter vn-button[icon="icon-notes"]',
|
||||||
observation: '.vn-dialog.shown vn-textarea[ng-model="$ctrl.defaulter.observation"]',
|
observation: '.vn-dialog.shown vn-textarea[ng-model="$ctrl.defaulter.observation"]',
|
||||||
saveButton: 'button[response="accept"]'
|
saveButton: 'button[response="accept"]'
|
||||||
},
|
},
|
||||||
|
@ -680,13 +680,13 @@ export default {
|
||||||
header: 'vn-claim-summary > vn-card > h5',
|
header: 'vn-claim-summary > vn-card > h5',
|
||||||
state: 'vn-claim-summary vn-label-value[label="State"] > section > span',
|
state: 'vn-claim-summary vn-label-value[label="State"] > section > span',
|
||||||
observation: 'vn-claim-summary vn-textarea[ng-model="$ctrl.summary.claim.observation"]',
|
observation: 'vn-claim-summary vn-textarea[ng-model="$ctrl.summary.claim.observation"]',
|
||||||
firstSaleItemId: 'vn-claim-summary vn-horizontal > vn-auto:nth-child(4) vn-table > div > vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(1) > span',
|
firstSaleItemId: 'vn-claim-summary vn-horizontal > vn-auto:nth-child(5) vn-table > div > vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(1) > span',
|
||||||
firstSaleDescriptorImage: '.vn-popover.shown vn-item-descriptor img',
|
firstSaleDescriptorImage: '.vn-popover.shown vn-item-descriptor img',
|
||||||
itemDescriptorPopover: '.vn-popover.shown vn-item-descriptor',
|
itemDescriptorPopover: '.vn-popover.shown vn-item-descriptor',
|
||||||
itemDescriptorPopoverItemDiaryButton: '.vn-popover vn-item-descriptor vn-quick-link[icon="icon-transaction"] > a',
|
itemDescriptorPopoverItemDiaryButton: '.vn-popover vn-item-descriptor vn-quick-link[icon="icon-transaction"] > a',
|
||||||
firstDevelopmentWorker: 'vn-claim-summary vn-horizontal > vn-auto:nth-child(5) vn-table > div > vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(4) > span',
|
firstDevelopmentWorker: 'vn-claim-summary vn-horizontal > vn-auto:nth-child(4) vn-table > div > vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(4) > span',
|
||||||
firstDevelopmentWorkerGoToClientButton: '.vn-popover vn-worker-descriptor vn-quick-link[icon="person"] > a',
|
firstDevelopmentWorkerGoToClientButton: '.vn-popover vn-worker-descriptor vn-quick-link[icon="person"] > a',
|
||||||
firstActionTicketId: 'vn-claim-summary > vn-card > vn-horizontal > vn-auto:nth-child(6) vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > span',
|
firstActionTicketId: 'vn-claim-summary > vn-card > vn-horizontal > vn-auto:nth-child(5) vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > span',
|
||||||
firstActionTicketDescriptor: '.vn-popover.shown vn-ticket-descriptor'
|
firstActionTicketDescriptor: '.vn-popover.shown vn-ticket-descriptor'
|
||||||
},
|
},
|
||||||
claimBasicData: {
|
claimBasicData: {
|
||||||
|
@ -722,10 +722,7 @@ export default {
|
||||||
},
|
},
|
||||||
claimAction: {
|
claimAction: {
|
||||||
importClaimButton: 'vn-claim-action vn-button[label="Import claim"]',
|
importClaimButton: 'vn-claim-action vn-button[label="Import claim"]',
|
||||||
importTicketButton: 'vn-claim-action vn-button[label="Import ticket"]',
|
anyLine: 'vn-claim-action vn-tbody > vn-tr',
|
||||||
secondImportableTicket: '.vn-popover.shown .content > div > vn-table > div > vn-tbody > vn-tr:nth-child(2)',
|
|
||||||
firstLineDestination: 'vn-claim-action vn-tr:nth-child(1) vn-autocomplete[ng-model="saleClaimed.claimDestinationFk"]',
|
|
||||||
secondLineDestination: 'vn-claim-action vn-tr:nth-child(2) vn-autocomplete[ng-model="saleClaimed.claimDestinationFk"]',
|
|
||||||
firstDeleteLine: 'vn-claim-action vn-tr:nth-child(1) vn-icon-button[icon="delete"]',
|
firstDeleteLine: 'vn-claim-action vn-tr:nth-child(1) vn-icon-button[icon="delete"]',
|
||||||
isPaidWithManaCheckbox: 'vn-claim-action vn-check[ng-model="$ctrl.claim.isChargedToMana"]'
|
isPaidWithManaCheckbox: 'vn-claim-action vn-check[ng-model="$ctrl.claim.isChargedToMana"]'
|
||||||
},
|
},
|
||||||
|
|
|
@ -9,7 +9,7 @@ describe('Client defaulter path', () => {
|
||||||
browser = await getBrowser();
|
browser = await getBrowser();
|
||||||
page = browser.page;
|
page = browser.page;
|
||||||
await page.loginAndModule('insurance', 'client');
|
await page.loginAndModule('insurance', 'client');
|
||||||
await page.accessToSection('client.defaulter.index');
|
await page.accessToSection('client.defaulter');
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async() => {
|
afterAll(async() => {
|
||||||
|
@ -28,8 +28,8 @@ describe('Client defaulter path', () => {
|
||||||
const salesPersonName =
|
const salesPersonName =
|
||||||
await page.waitToGetProperty(selectors.clientDefaulter.firstSalesPersonName, 'innerText');
|
await page.waitToGetProperty(selectors.clientDefaulter.firstSalesPersonName, 'innerText');
|
||||||
|
|
||||||
expect(clientName).toEqual('Ororo Munroe');
|
expect(clientName).toEqual('Batman');
|
||||||
expect(salesPersonName).toEqual('salesPerson');
|
expect(salesPersonName).toEqual('salesPersonNick');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should first observation not changed', async() => {
|
it('should first observation not changed', async() => {
|
||||||
|
@ -52,7 +52,7 @@ describe('Client defaulter path', () => {
|
||||||
|
|
||||||
it('shoul checked all defaulters', async() => {
|
it('shoul checked all defaulters', async() => {
|
||||||
await page.loginAndModule('insurance', 'client');
|
await page.loginAndModule('insurance', 'client');
|
||||||
await page.accessToSection('client.defaulter.index');
|
await page.accessToSection('client.defaulter');
|
||||||
|
|
||||||
await page.waitToClick(selectors.clientDefaulter.allDefaulterCheckbox);
|
await page.waitToClick(selectors.clientDefaulter.allDefaulterCheckbox);
|
||||||
});
|
});
|
||||||
|
@ -65,6 +65,7 @@ describe('Client defaulter path', () => {
|
||||||
|
|
||||||
it('should first observation changed', async() => {
|
it('should first observation changed', async() => {
|
||||||
const message = await page.waitForSnackbar();
|
const message = await page.waitForSnackbar();
|
||||||
|
await page.waitForSelector(selectors.clientDefaulter.firstObservation);
|
||||||
const result = await page.waitToGetProperty(selectors.clientDefaulter.firstObservation, 'value');
|
const result = await page.waitToGetProperty(selectors.clientDefaulter.firstObservation, 'value');
|
||||||
|
|
||||||
expect(message.text).toContain('Observation saved!');
|
expect(message.text).toContain('Observation saved!');
|
||||||
|
|
|
@ -24,22 +24,6 @@ describe('Claim action path', () => {
|
||||||
expect(message.text).toContain('Data saved!');
|
expect(message.text).toContain('Data saved!');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should import the second importable ticket', async() => {
|
|
||||||
await page.waitToClick(selectors.claimAction.importTicketButton);
|
|
||||||
await page.waitToClick(selectors.claimAction.secondImportableTicket);
|
|
||||||
const message = await page.waitForSnackbar();
|
|
||||||
|
|
||||||
expect(message.text).toContain('Data saved!');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should edit the second line destination field', async() => {
|
|
||||||
await page.waitForContentLoaded();
|
|
||||||
await page.autocompleteSearch(selectors.claimAction.secondLineDestination, 'Bueno');
|
|
||||||
const message = await page.waitForSnackbar();
|
|
||||||
|
|
||||||
expect(message.text).toContain('Data saved!');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should delete the first line', async() => {
|
it('should delete the first line', async() => {
|
||||||
await page.waitToClick(selectors.claimAction.firstDeleteLine);
|
await page.waitToClick(selectors.claimAction.firstDeleteLine);
|
||||||
const message = await page.waitForSnackbar();
|
const message = await page.waitForSnackbar();
|
||||||
|
@ -47,18 +31,11 @@ describe('Claim action path', () => {
|
||||||
expect(message.text).toContain('Data saved!');
|
expect(message.text).toContain('Data saved!');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should refresh the view to check the remaining line is the expected one', async() => {
|
it('should refresh the view to check not have lines', async() => {
|
||||||
await page.reloadSection('claim.card.action');
|
await page.reloadSection('claim.card.action');
|
||||||
const result = await page.waitToGetProperty(selectors.claimAction.firstLineDestination, 'value');
|
const result = await page.countElement(selectors.claimAction.anyLine);
|
||||||
|
|
||||||
expect(result).toEqual('Bueno');
|
expect(result).toEqual(0);
|
||||||
});
|
|
||||||
|
|
||||||
it('should delete the current first line', async() => {
|
|
||||||
await page.waitToClick(selectors.claimAction.firstDeleteLine);
|
|
||||||
const message = await page.waitForSnackbar();
|
|
||||||
|
|
||||||
expect(message.text).toContain('Data saved!');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should check the "is paid with mana" checkbox', async() => {
|
it('should check the "is paid with mana" checkbox', async() => {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
import selectors from '../../helpers/selectors.js';
|
import selectors from '../../helpers/selectors.js';
|
||||||
import getBrowser from '../../helpers/puppeteer';
|
import getBrowser from '../../helpers/puppeteer';
|
||||||
|
|
||||||
|
@ -38,7 +39,7 @@ describe('Claim summary path', () => {
|
||||||
it('should display the observation', async() => {
|
it('should display the observation', async() => {
|
||||||
const result = await page.waitToGetProperty(selectors.claimSummary.observation, 'value');
|
const result = await page.waitToGetProperty(selectors.claimSummary.observation, 'value');
|
||||||
|
|
||||||
expect(result).toContain('observation four');
|
expect(result).toContain('Wisi forensibus mnesarchum in cum. Per id impetus abhorreant');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should display the claimed line(s)', async() => {
|
it('should display the claimed line(s)', async() => {
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
|
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
Self.getSynchronizer = async function() {
|
Self.getSynchronizer = async function() {
|
||||||
|
let NODE_ENV = process.env.NODE_ENV;
|
||||||
|
if (!NODE_ENV || NODE_ENV == 'development')
|
||||||
|
return null;
|
||||||
|
|
||||||
return await Self.findOne({
|
return await Self.findOne({
|
||||||
fields: ['id', 'rolePrefix', 'userPrefix', 'userHost']
|
fields: ['id', 'rolePrefix', 'userPrefix', 'userHost']
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
module.exports = Self => {
|
|
||||||
Self.remoteMethodCtx('importTicketSales', {
|
|
||||||
description: 'Imports lines from claimBeginning to a new ticket with specific shipped, landed dates, agency and company',
|
|
||||||
accessType: 'WRITE',
|
|
||||||
accepts: [{
|
|
||||||
arg: 'params',
|
|
||||||
type: 'object',
|
|
||||||
http: {source: 'body'}
|
|
||||||
}],
|
|
||||||
returns: {
|
|
||||||
type: ['Object'],
|
|
||||||
root: true
|
|
||||||
},
|
|
||||||
http: {
|
|
||||||
path: `/importTicketSales`,
|
|
||||||
verb: 'POST'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Self.importTicketSales = async(ctx, params, options) => {
|
|
||||||
let models = Self.app.models;
|
|
||||||
let userId = ctx.req.accessToken.userId;
|
|
||||||
|
|
||||||
let tx;
|
|
||||||
const myOptions = {};
|
|
||||||
|
|
||||||
if (typeof options == 'object')
|
|
||||||
Object.assign(myOptions, options);
|
|
||||||
|
|
||||||
if (!myOptions.transaction) {
|
|
||||||
tx = await Self.beginTransaction({});
|
|
||||||
myOptions.transaction = tx;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const worker = await models.Worker.findOne({where: {userFk: userId}}, myOptions);
|
|
||||||
|
|
||||||
let ticketSales = await models.Sale.find({
|
|
||||||
where: {ticketFk: params.ticketFk}
|
|
||||||
}, myOptions);
|
|
||||||
|
|
||||||
let claimEnds = [];
|
|
||||||
ticketSales.forEach(sale => {
|
|
||||||
claimEnds.push({
|
|
||||||
saleFk: sale.id,
|
|
||||||
claimFk: params.claimFk,
|
|
||||||
workerFk: worker.id
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const createdClaimEnds = await Self.create(claimEnds, myOptions);
|
|
||||||
|
|
||||||
if (tx) await tx.commit();
|
|
||||||
|
|
||||||
return createdClaimEnds;
|
|
||||||
} catch (e) {
|
|
||||||
if (tx) await tx.rollback();
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -1,26 +0,0 @@
|
||||||
const app = require('vn-loopback/server/server');
|
|
||||||
|
|
||||||
describe('Claim importTicketSales()', () => {
|
|
||||||
it('should import sales to a claim actions from an specific ticket', async() => {
|
|
||||||
const ctx = {req: {accessToken: {userId: 5}}};
|
|
||||||
|
|
||||||
const tx = await app.models.Entry.beginTransaction({});
|
|
||||||
try {
|
|
||||||
const options = {transaction: tx};
|
|
||||||
|
|
||||||
const claimEnds = await app.models.ClaimEnd.importTicketSales(ctx, {
|
|
||||||
claimFk: 1,
|
|
||||||
ticketFk: 1
|
|
||||||
}, options);
|
|
||||||
|
|
||||||
expect(claimEnds.length).toEqual(4);
|
|
||||||
expect(claimEnds[0].saleFk).toEqual(1);
|
|
||||||
expect(claimEnds[2].saleFk).toEqual(3);
|
|
||||||
|
|
||||||
await tx.rollback();
|
|
||||||
} catch (e) {
|
|
||||||
await tx.rollback();
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -94,19 +94,14 @@ module.exports = Self => {
|
||||||
? {'cl.id': value}
|
? {'cl.id': value}
|
||||||
: {
|
: {
|
||||||
or: [
|
or: [
|
||||||
{'c.name': {like: `%${value}%`}}
|
{'cl.socialName': {like: `%${value}%`}}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
case 'client':
|
|
||||||
return {'c.name': {like: `%${value}%`}};
|
|
||||||
case 'id':
|
case 'id':
|
||||||
return {'cl.id': value};
|
|
||||||
case 'clientFk':
|
|
||||||
return {'c.id': value};
|
|
||||||
case 'claimStateFk':
|
case 'claimStateFk':
|
||||||
return {'cl.claimStateFk': value};
|
case 'priority':
|
||||||
|
return {[`cl.${param}`]: value};
|
||||||
case 'salesPersonFk':
|
case 'salesPersonFk':
|
||||||
return {'c.salesPersonFk': value};
|
|
||||||
case 'attenderFk':
|
case 'attenderFk':
|
||||||
return {'cl.workerFk': value};
|
return {'cl.workerFk': value};
|
||||||
case 'created':
|
case 'created':
|
||||||
|
@ -123,12 +118,23 @@ module.exports = Self => {
|
||||||
const stmts = [];
|
const stmts = [];
|
||||||
|
|
||||||
const stmt = new ParameterizedSQL(
|
const stmt = new ParameterizedSQL(
|
||||||
`SELECT cl.id, c.name, cl.clientFk, cl.workerFk, u.name AS userName, cs.description, cl.created
|
`SELECT *
|
||||||
FROM claim cl
|
FROM (
|
||||||
LEFT JOIN client c ON c.id = cl.clientFk
|
SELECT
|
||||||
LEFT JOIN worker w ON w.id = cl.workerFk
|
cl.id,
|
||||||
LEFT JOIN account.user u ON u.id = w.userFk
|
cl.clientFk,
|
||||||
LEFT JOIN claimState cs ON cs.id = cl.claimStateFk`
|
c.socialName,
|
||||||
|
cl.workerFk,
|
||||||
|
u.name AS workerName,
|
||||||
|
cs.description,
|
||||||
|
cl.created,
|
||||||
|
cs.priority,
|
||||||
|
cl.claimStateFk
|
||||||
|
FROM claim cl
|
||||||
|
LEFT JOIN client c ON c.id = cl.clientFk
|
||||||
|
LEFT JOIN worker w ON w.id = cl.workerFk
|
||||||
|
LEFT JOIN account.user u ON u.id = w.userFk
|
||||||
|
LEFT JOIN claimState cs ON cs.id = cl.claimStateFk ) cl`
|
||||||
);
|
);
|
||||||
|
|
||||||
stmt.merge(conn.makeSuffix(filter));
|
stmt.merge(conn.makeSuffix(filter));
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
Self.remoteMethod('getSummary', {
|
Self.remoteMethodCtx('getSummary', {
|
||||||
description: 'Return the claim summary',
|
description: 'Return the claim summary',
|
||||||
accessType: 'READ',
|
accessType: 'READ',
|
||||||
accepts: [{
|
accepts: [{
|
||||||
|
@ -19,7 +19,7 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Self.getSummary = async(id, options) => {
|
Self.getSummary = async(ctx, id, options) => {
|
||||||
const myOptions = {};
|
const myOptions = {};
|
||||||
|
|
||||||
if (typeof options == 'object')
|
if (typeof options == 'object')
|
||||||
|
@ -135,6 +135,7 @@ module.exports = Self => {
|
||||||
|
|
||||||
const res = await Promise.all(promises);
|
const res = await Promise.all(promises);
|
||||||
|
|
||||||
|
summary.isEditable = await Self.isEditable(ctx, id, myOptions);
|
||||||
[summary.claim] = res[0];
|
[summary.claim] = res[0];
|
||||||
summary.salesClaimed = res[1];
|
summary.salesClaimed = res[1];
|
||||||
summary.developments = res[2];
|
summary.developments = res[2];
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
Self.remoteMethodCtx('regularizeClaim', {
|
Self.remoteMethodCtx('regularizeClaim', {
|
||||||
description: 'Imports lines from claimBeginning to a new ticket with specific shipped, landed dates, agency and company',
|
description: `Imports lines from claimBeginning to a new ticket
|
||||||
|
with specific shipped, landed dates, agency and company`,
|
||||||
accessType: 'WRITE',
|
accessType: 'WRITE',
|
||||||
accepts: [{
|
accepts: [{
|
||||||
arg: 'id',
|
arg: 'id',
|
||||||
|
|
|
@ -57,7 +57,7 @@ describe('Claim createFromSales()', () => {
|
||||||
const todayMinusEightDays = new Date();
|
const todayMinusEightDays = new Date();
|
||||||
todayMinusEightDays.setDate(todayMinusEightDays.getDate() - 8);
|
todayMinusEightDays.setDate(todayMinusEightDays.getDate() - 8);
|
||||||
|
|
||||||
const ticket = await models.Ticket.findById(ticketId, options);
|
const ticket = await models.Ticket.findById(ticketId, null, options);
|
||||||
await ticket.updateAttribute('landed', todayMinusEightDays, options);
|
await ticket.updateAttribute('landed', todayMinusEightDays, options);
|
||||||
|
|
||||||
const claim = await models.Claim.createFromSales(ctx, ticketId, newSale, options);
|
const claim = await models.Claim.createFromSales(ctx, ticketId, newSale, options);
|
||||||
|
@ -88,7 +88,7 @@ describe('Claim createFromSales()', () => {
|
||||||
const todayMinusEightDays = new Date();
|
const todayMinusEightDays = new Date();
|
||||||
todayMinusEightDays.setDate(todayMinusEightDays.getDate() - 8);
|
todayMinusEightDays.setDate(todayMinusEightDays.getDate() - 8);
|
||||||
|
|
||||||
const ticket = await models.Ticket.findById(ticketId, options);
|
const ticket = await models.Ticket.findById(ticketId, null, options);
|
||||||
await ticket.updateAttribute('landed', todayMinusEightDays, options);
|
await ticket.updateAttribute('landed', todayMinusEightDays, options);
|
||||||
|
|
||||||
await models.Claim.createFromSales(ctx, ticketId, newSale, options);
|
await models.Claim.createFromSales(ctx, ticketId, newSale, options);
|
||||||
|
|
|
@ -25,7 +25,7 @@ describe('claim filter()', () => {
|
||||||
try {
|
try {
|
||||||
const options = {transaction: tx};
|
const options = {transaction: tx};
|
||||||
|
|
||||||
const result = await app.models.Claim.filter({args: {filter: {}, search: 'Tony Stark'}}, null, options);
|
const result = await app.models.Claim.filter({args: {filter: {}, search: 'Iron man'}}, null, options);
|
||||||
|
|
||||||
expect(result.length).toEqual(1);
|
expect(result.length).toEqual(1);
|
||||||
expect(result[0].id).toEqual(4);
|
expect(result[0].id).toEqual(4);
|
||||||
|
|
|
@ -3,17 +3,24 @@ const app = require('vn-loopback/server/server');
|
||||||
describe('claim getSummary()', () => {
|
describe('claim getSummary()', () => {
|
||||||
it('should return summary with claim, salesClaimed, developments and actions defined ', async() => {
|
it('should return summary with claim, salesClaimed, developments and actions defined ', async() => {
|
||||||
const tx = await app.models.Claim.beginTransaction({});
|
const tx = await app.models.Claim.beginTransaction({});
|
||||||
|
const ctx = {
|
||||||
|
req: {
|
||||||
|
accessToken: {
|
||||||
|
userId: 9
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
try {
|
try {
|
||||||
const options = {transaction: tx};
|
const options = {transaction: tx};
|
||||||
|
|
||||||
const result = await app.models.Claim.getSummary(1, options);
|
const result = await app.models.Claim.getSummary(ctx, 1, options);
|
||||||
const keys = Object.keys(result);
|
const keys = Object.keys(result);
|
||||||
|
|
||||||
expect(keys).toContain('claim');
|
expect(keys).toContain('claim');
|
||||||
expect(keys).toContain('salesClaimed');
|
expect(keys).toContain('salesClaimed');
|
||||||
expect(keys).toContain('developments');
|
expect(keys).toContain('developments');
|
||||||
expect(keys).toContain('actions');
|
expect(keys).toContain('actions');
|
||||||
|
expect(keys).toContain('isEditable');
|
||||||
|
|
||||||
await tx.rollback();
|
await tx.rollback();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
const app = require('vn-loopback/server/server');
|
const models = require('vn-loopback/server/server').models;
|
||||||
|
|
||||||
describe('claim regularizeClaim()', () => {
|
describe('claim regularizeClaim()', () => {
|
||||||
|
const userId = 18;
|
||||||
const ctx = {
|
const ctx = {
|
||||||
req: {
|
req: {
|
||||||
accessToken: {userId: 18},
|
accessToken: {userId: userId},
|
||||||
headers: {origin: 'http://localhost'}
|
headers: {origin: 'http://localhost'}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -11,8 +12,9 @@ describe('claim regularizeClaim()', () => {
|
||||||
return params.nickname;
|
return params.nickname;
|
||||||
};
|
};
|
||||||
|
|
||||||
const chatModel = app.models.Chat;
|
const chatModel = models.Chat;
|
||||||
const claimFk = 1;
|
const claimId = 1;
|
||||||
|
const ticketId = 1;
|
||||||
const pendentState = 1;
|
const pendentState = 1;
|
||||||
const resolvedState = 3;
|
const resolvedState = 3;
|
||||||
const trashDestination = 2;
|
const trashDestination = 2;
|
||||||
|
@ -21,27 +23,40 @@ describe('claim regularizeClaim()', () => {
|
||||||
let claimEnds = [];
|
let claimEnds = [];
|
||||||
let trashTicket;
|
let trashTicket;
|
||||||
|
|
||||||
|
async function importTicket(ticketId, claimId, userId, options) {
|
||||||
|
const ticketSales = await models.Sale.find({
|
||||||
|
where: {ticketFk: ticketId}
|
||||||
|
}, options);
|
||||||
|
const claimEnds = [];
|
||||||
|
for (let sale of ticketSales) {
|
||||||
|
claimEnds.push({
|
||||||
|
saleFk: sale.id,
|
||||||
|
claimFk: claimId,
|
||||||
|
workerFk: userId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return await models.ClaimEnd.create(claimEnds, options);
|
||||||
|
}
|
||||||
|
|
||||||
it('should send a chat message with value "Trash" and then change claim state to resolved', async() => {
|
it('should send a chat message with value "Trash" and then change claim state to resolved', async() => {
|
||||||
const tx = await app.models.Claim.beginTransaction({});
|
const tx = await models.Claim.beginTransaction({});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const options = {transaction: tx};
|
const options = {transaction: tx};
|
||||||
|
|
||||||
spyOn(chatModel, 'sendCheckingPresence').and.callThrough();
|
spyOn(chatModel, 'sendCheckingPresence').and.callThrough();
|
||||||
|
|
||||||
claimEnds = await app.models.ClaimEnd.importTicketSales(ctx, {
|
claimEnds = await importTicket(ticketId, claimId, userId, options);
|
||||||
claimFk: claimFk,
|
|
||||||
ticketFk: 1
|
|
||||||
}, options);
|
|
||||||
|
|
||||||
for (claimEnd of claimEnds)
|
for (claimEnd of claimEnds)
|
||||||
await claimEnd.updateAttributes({claimDestinationFk: trashDestination}, options);
|
await claimEnd.updateAttributes({claimDestinationFk: trashDestination}, options);
|
||||||
|
|
||||||
let claimBefore = await app.models.Claim.findById(claimFk, null, options);
|
let claimBefore = await models.Claim.findById(claimId, null, options);
|
||||||
await app.models.Claim.regularizeClaim(ctx, claimFk, options);
|
await models.Claim.regularizeClaim(ctx, claimId, options);
|
||||||
let claimAfter = await app.models.Claim.findById(claimFk, null, options);
|
let claimAfter = await models.Claim.findById(claimId, null, options);
|
||||||
|
|
||||||
trashTicket = await app.models.Ticket.findOne({where: {addressFk: 12}}, options);
|
trashTicket = await models.Ticket.findOne({where: {addressFk: 12}}, options);
|
||||||
|
|
||||||
expect(trashTicket.addressFk).toEqual(trashAddress);
|
expect(trashTicket.addressFk).toEqual(trashAddress);
|
||||||
expect(claimBefore.claimStateFk).toEqual(pendentState);
|
expect(claimBefore.claimStateFk).toEqual(pendentState);
|
||||||
|
@ -57,22 +72,19 @@ describe('claim regularizeClaim()', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should send a chat message with value "Bueno" and then change claim state to resolved', async() => {
|
it('should send a chat message with value "Bueno" and then change claim state to resolved', async() => {
|
||||||
const tx = await app.models.Claim.beginTransaction({});
|
const tx = await models.Claim.beginTransaction({});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const options = {transaction: tx};
|
const options = {transaction: tx};
|
||||||
|
|
||||||
spyOn(chatModel, 'sendCheckingPresence').and.callThrough();
|
spyOn(chatModel, 'sendCheckingPresence').and.callThrough();
|
||||||
|
|
||||||
claimEnds = await app.models.ClaimEnd.importTicketSales(ctx, {
|
claimEnds = await importTicket(ticketId, claimId, userId, options);
|
||||||
claimFk: claimFk,
|
|
||||||
ticketFk: 1
|
|
||||||
}, options);
|
|
||||||
|
|
||||||
for (claimEnd of claimEnds)
|
for (claimEnd of claimEnds)
|
||||||
await claimEnd.updateAttributes({claimDestinationFk: okDestination}, options);
|
await claimEnd.updateAttributes({claimDestinationFk: okDestination}, options);
|
||||||
|
|
||||||
await app.models.Claim.regularizeClaim(ctx, claimFk, options);
|
await models.Claim.regularizeClaim(ctx, claimId, options);
|
||||||
|
|
||||||
expect(chatModel.sendCheckingPresence).toHaveBeenCalledWith(ctx, 18, 'Bueno');
|
expect(chatModel.sendCheckingPresence).toHaveBeenCalledWith(ctx, 18, 'Bueno');
|
||||||
expect(chatModel.sendCheckingPresence).toHaveBeenCalledTimes(4);
|
expect(chatModel.sendCheckingPresence).toHaveBeenCalledTimes(4);
|
||||||
|
@ -85,22 +97,19 @@ describe('claim regularizeClaim()', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should send a chat message to the salesPerson when claim isPickUp is enabled', async() => {
|
it('should send a chat message to the salesPerson when claim isPickUp is enabled', async() => {
|
||||||
const tx = await app.models.Claim.beginTransaction({});
|
const tx = await models.Claim.beginTransaction({});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const options = {transaction: tx};
|
const options = {transaction: tx};
|
||||||
|
|
||||||
spyOn(chatModel, 'sendCheckingPresence').and.callThrough();
|
spyOn(chatModel, 'sendCheckingPresence').and.callThrough();
|
||||||
|
|
||||||
claimEnds = await app.models.ClaimEnd.importTicketSales(ctx, {
|
claimEnds = await importTicket(ticketId, claimId, userId, options);
|
||||||
claimFk: claimFk,
|
|
||||||
ticketFk: 1
|
|
||||||
}, options);
|
|
||||||
|
|
||||||
for (claimEnd of claimEnds)
|
for (claimEnd of claimEnds)
|
||||||
await claimEnd.updateAttributes({claimDestinationFk: okDestination}, options);
|
await claimEnd.updateAttributes({claimDestinationFk: okDestination}, options);
|
||||||
|
|
||||||
await app.models.Claim.regularizeClaim(ctx, claimFk, options);
|
await models.Claim.regularizeClaim(ctx, claimId, options);
|
||||||
|
|
||||||
expect(chatModel.sendCheckingPresence).toHaveBeenCalledWith(ctx, 18, 'Bueno');
|
expect(chatModel.sendCheckingPresence).toHaveBeenCalledWith(ctx, 18, 'Bueno');
|
||||||
expect(chatModel.sendCheckingPresence).toHaveBeenCalledTimes(4);
|
expect(chatModel.sendCheckingPresence).toHaveBeenCalledTimes(4);
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
{
|
{
|
||||||
"name": "ClaimBeginning",
|
"name": "ClaimBeginning",
|
||||||
"base": "VnModel",
|
"base": "Loggable",
|
||||||
|
"log": {
|
||||||
|
"model": "ClaimLog",
|
||||||
|
"relation": "claim",
|
||||||
|
"showField": "quantity"
|
||||||
|
},
|
||||||
"options": {
|
"options": {
|
||||||
"mysql": {
|
"mysql": {
|
||||||
"table": "claimBeginning"
|
"table": "claimBeginning"
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
{
|
{
|
||||||
"name": "ClaimDevelopment",
|
"name": "ClaimDevelopment",
|
||||||
"base": "VnModel",
|
"base": "Loggable",
|
||||||
|
"log": {
|
||||||
|
"model": "ClaimLog",
|
||||||
|
"relation": "claim"
|
||||||
|
},
|
||||||
"options": {
|
"options": {
|
||||||
"mysql": {
|
"mysql": {
|
||||||
"table": "claimDevelopment"
|
"table": "claimDevelopment"
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
module.exports = Self => {
|
|
||||||
require('../methods/claim-end/importTicketSales')(Self);
|
|
||||||
};
|
|
|
@ -1,6 +1,10 @@
|
||||||
{
|
{
|
||||||
"name": "ClaimEnd",
|
"name": "ClaimEnd",
|
||||||
"base": "VnModel",
|
"base": "Loggable",
|
||||||
|
"log": {
|
||||||
|
"model": "ClaimLog",
|
||||||
|
"relation": "claim"
|
||||||
|
},
|
||||||
"options": {
|
"options": {
|
||||||
"mysql": {
|
"mysql": {
|
||||||
"table": "claimEnd"
|
"table": "claimEnd"
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
{
|
{
|
||||||
"name": "ClaimState",
|
"name": "ClaimState",
|
||||||
"base": "VnModel",
|
"base": "Loggable",
|
||||||
|
"log": {
|
||||||
|
"model": "ClaimLog",
|
||||||
|
"relation": "claim",
|
||||||
|
"showField": "description"
|
||||||
|
},
|
||||||
"options": {
|
"options": {
|
||||||
"mysql": {
|
"mysql": {
|
||||||
"table": "claimState"
|
"table": "claimState"
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
{
|
{
|
||||||
"name": "Claim",
|
"name": "Claim",
|
||||||
"base": "VnModel",
|
"base": "Loggable",
|
||||||
|
"log": {
|
||||||
|
"model": "ClaimLog",
|
||||||
|
"showField": "id"
|
||||||
|
},
|
||||||
"options": {
|
"options": {
|
||||||
"mysql": {
|
"mysql": {
|
||||||
"table": "claim"
|
"table": "claim"
|
||||||
|
|
|
@ -24,15 +24,9 @@
|
||||||
<vn-button
|
<vn-button
|
||||||
label="Import claim"
|
label="Import claim"
|
||||||
disabled="$ctrl.claim.claimStateFk == $ctrl.resolvedStateId"
|
disabled="$ctrl.claim.claimStateFk == $ctrl.resolvedStateId"
|
||||||
vn-http-click="$ctrl.importToNewRefundTicket()"p
|
vn-http-click="$ctrl.importToNewRefundTicket()"
|
||||||
translate-attr="{title: 'Imports claim details'}">
|
translate-attr="{title: 'Imports claim details'}">
|
||||||
</vn-button>
|
</vn-button>
|
||||||
<vn-button
|
|
||||||
label="Import ticket"
|
|
||||||
disabled="$ctrl.claim.claimStateFk == $ctrl.resolvedStateId"
|
|
||||||
ng-click="$ctrl.showLastTickets($event)"
|
|
||||||
translate-attr="{title: 'Imports ticket lines'}">
|
|
||||||
</vn-button>
|
|
||||||
<vn-range
|
<vn-range
|
||||||
label="Responsability"
|
label="Responsability"
|
||||||
min-label="Company"
|
min-label="Company"
|
||||||
|
@ -121,38 +115,6 @@
|
||||||
</vn-button>
|
</vn-button>
|
||||||
</vn-button-bar>
|
</vn-button-bar>
|
||||||
</vn-card>
|
</vn-card>
|
||||||
<vn-crud-model
|
|
||||||
vn-id="lastTicketsModel"
|
|
||||||
url="Tickets"
|
|
||||||
limit="20"
|
|
||||||
data="lastTickets" auto-load="false">
|
|
||||||
</vn-crud-model>
|
|
||||||
<!-- Transfer Popover -->
|
|
||||||
<vn-popover class="lastTicketsPopover" vn-id="lastTicketsPopover">
|
|
||||||
<div class="ticketList vn-pa-md">
|
|
||||||
<vn-table model="lastTicketsModel" auto-load="false">
|
|
||||||
<vn-thead>
|
|
||||||
<vn-tr>
|
|
||||||
<vn-th field="id" number>ID</vn-th>
|
|
||||||
<vn-th field="shipped" default-order="DESC">F. envio</vn-th>
|
|
||||||
<vn-th>Agencia</vn-th>
|
|
||||||
<vn-th>Almacen</vn-th>
|
|
||||||
</vn-tr>
|
|
||||||
</vn-thead>
|
|
||||||
<vn-tbody>
|
|
||||||
<vn-tr
|
|
||||||
class="clickable"
|
|
||||||
ng-repeat="ticket in lastTickets"
|
|
||||||
ng-click="$ctrl.importTicketLines(ticket.id)">
|
|
||||||
<vn-td number>{{::ticket.id}}</vn-td>
|
|
||||||
<vn-td>{{::ticket.shipped | date: 'dd/MM/yyyy'}}</vn-td>
|
|
||||||
<vn-td>{{::ticket.agencyMode.name}}</vn-td>
|
|
||||||
<vn-td>{{::ticket.warehouse.name}}</vn-td>
|
|
||||||
</vn-tr>
|
|
||||||
</vn-tbody>
|
|
||||||
</vn-table>
|
|
||||||
</div>
|
|
||||||
</vn-popover>
|
|
||||||
<vn-item-descriptor-popover
|
<vn-item-descriptor-popover
|
||||||
vn-id="item-descriptor"
|
vn-id="item-descriptor"
|
||||||
warehouse-fk="$ctrl.vnConfig.warehouseFk">
|
warehouse-fk="$ctrl.vnConfig.warehouseFk">
|
||||||
|
|
|
@ -60,36 +60,6 @@ export default class Controller extends Section {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
showLastTickets(event) {
|
|
||||||
let pastWeek = new Date();
|
|
||||||
pastWeek.setDate(-7);
|
|
||||||
|
|
||||||
let filter = {
|
|
||||||
include: [
|
|
||||||
{relation: 'agencyMode', fields: ['name']},
|
|
||||||
{relation: 'warehouse', fields: ['name']}
|
|
||||||
],
|
|
||||||
where: {
|
|
||||||
created: {gt: pastWeek},
|
|
||||||
clientFk: this.claim.clientFk
|
|
||||||
}
|
|
||||||
};
|
|
||||||
this.$.lastTicketsModel.filter = filter;
|
|
||||||
this.$.lastTicketsModel.refresh();
|
|
||||||
this.$.lastTicketsPopover.show(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
importTicketLines(ticketFk) {
|
|
||||||
let data = {claimFk: this.$params.id, ticketFk: ticketFk};
|
|
||||||
|
|
||||||
let query = `ClaimEnds/importTicketSales`;
|
|
||||||
this.$http.post(query, data).then(() => {
|
|
||||||
this.vnApp.showSuccess(this.$t('Data saved!'));
|
|
||||||
this.$.lastTicketsPopover.hide();
|
|
||||||
this.$.model.refresh();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
regularize() {
|
regularize() {
|
||||||
const query = `Claims/${this.$params.id}/regularizeClaim`;
|
const query = `Claims/${this.$params.id}/regularizeClaim`;
|
||||||
return this.$http.post(query).then(() => {
|
return this.$http.post(query).then(() => {
|
||||||
|
|
|
@ -67,35 +67,6 @@ describe('claim', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('showLastTickets()', () => {
|
|
||||||
it('should get a list of tickets and call lastTicketsPopover show() method', () => {
|
|
||||||
jest.spyOn(controller.$.lastTicketsModel, 'refresh');
|
|
||||||
jest.spyOn(controller.$.lastTicketsPopover, 'show');
|
|
||||||
|
|
||||||
controller.showLastTickets({});
|
|
||||||
|
|
||||||
expect(controller.$.lastTicketsModel.refresh).toHaveBeenCalled();
|
|
||||||
expect(controller.$.lastTicketsPopover.show).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('importTicketLines()', () => {
|
|
||||||
it('should perform a post query and add lines from an existent ticket', () => {
|
|
||||||
jest.spyOn(controller.$.model, 'refresh');
|
|
||||||
jest.spyOn(controller.vnApp, 'showSuccess');
|
|
||||||
jest.spyOn(controller.$.lastTicketsPopover, 'hide');
|
|
||||||
|
|
||||||
let data = {claimFk: 1, ticketFk: 1};
|
|
||||||
$httpBackend.expect('POST', `ClaimEnds/importTicketSales`, data).respond({});
|
|
||||||
controller.importTicketLines(1);
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.$.model.refresh).toHaveBeenCalledWith();
|
|
||||||
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
|
|
||||||
expect(controller.$.lastTicketsPopover.hide).toHaveBeenCalledWith();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('regularize()', () => {
|
describe('regularize()', () => {
|
||||||
it('should perform a post query and reload the claim card', () => {
|
it('should perform a post query and reload the claim card', () => {
|
||||||
jest.spyOn(controller.card, 'reload');
|
jest.spyOn(controller.card, 'reload');
|
||||||
|
|
|
@ -3,8 +3,6 @@ Action: Actuaciones
|
||||||
Total claimed: Total Reclamado
|
Total claimed: Total Reclamado
|
||||||
Import claim: Importar reclamacion
|
Import claim: Importar reclamacion
|
||||||
Imports claim details: Importa detalles de la reclamacion
|
Imports claim details: Importa detalles de la reclamacion
|
||||||
Import ticket: Importar ticket
|
|
||||||
Imports ticket lines: Importa las lineas de un ticket
|
|
||||||
Regularize: Regularizar
|
Regularize: Regularizar
|
||||||
Do you want to insert greuges?: Desea insertar greuges?
|
Do you want to insert greuges?: Desea insertar greuges?
|
||||||
Insert greuges on client card: Insertar greuges en la ficha del cliente
|
Insert greuges on client card: Insertar greuges en la ficha del cliente
|
||||||
|
|
|
@ -11,3 +11,4 @@ import './development';
|
||||||
import './search-panel';
|
import './search-panel';
|
||||||
import './summary';
|
import './summary';
|
||||||
import './photos';
|
import './photos';
|
||||||
|
import './log';
|
||||||
|
|
|
@ -1,59 +1,74 @@
|
||||||
<vn-auto-search
|
<vn-auto-search
|
||||||
model="model">
|
model="model">
|
||||||
</vn-auto-search>
|
</vn-auto-search>
|
||||||
<vn-data-viewer
|
<vn-card>
|
||||||
model="model"
|
<smart-table
|
||||||
class="vn-w-lg">
|
model="model"
|
||||||
<vn-card>
|
options="$ctrl.smartTableOptions"
|
||||||
<vn-table model="model">
|
expr-builder="$ctrl.exprBuilder(param, value)">
|
||||||
<vn-thead>
|
<slot-table>
|
||||||
<vn-tr>
|
<table>
|
||||||
<vn-th field="id" number>Id</vn-th>
|
<thead>
|
||||||
<vn-th field="clientFk">Client</vn-th>
|
<tr>
|
||||||
<vn-th field="created" center shrink-date>Created</vn-th>
|
<th field="id" shrink>
|
||||||
<vn-th field="workerFk">Worker</vn-th>
|
<span translate>Id</span>
|
||||||
<vn-th field="claimStateFk">State</vn-th>
|
</th>
|
||||||
<vn-th></vn-th>
|
<th field="clientFk">
|
||||||
</vn-tr>
|
<span translate>Client</span>
|
||||||
</vn-thead>
|
</th>
|
||||||
<vn-tbody>
|
<th field="created" center shrink-date>
|
||||||
<a
|
<span translate>Created</span>
|
||||||
ng-repeat="claim in model.data"
|
</th>
|
||||||
class="{{::$ctrl.compareDate(ticket.shipped)}} clickable vn-tr search-result"
|
<th field="salesPersonFk">
|
||||||
ui-sref="claim.card.summary({id: claim.id})">
|
<span translate>Worker</span>
|
||||||
<vn-td number>{{::claim.id}}</vn-td>
|
</th>
|
||||||
<vn-td expand>
|
<th field="claimStateFk">
|
||||||
<span
|
<span translate>State</span>
|
||||||
vn-click-stop="clientDescriptor.show($event, claim.clientFk)"
|
</th>
|
||||||
class="link">
|
<th></th>
|
||||||
{{::claim.name}}
|
</tr>
|
||||||
</span>
|
</thead>
|
||||||
</vn-td>
|
<tbody>
|
||||||
<vn-td center shrink-date>{{::claim.created | date:'dd/MM/yyyy'}}</vn-td>
|
<tr
|
||||||
<vn-td expand>
|
ng-repeat="claim in model.data"
|
||||||
<span
|
vn-anchor="::{
|
||||||
vn-click-stop="workerDescriptor.show($event, claim.workerFk)"
|
state: 'claim.card.summary',
|
||||||
class="link" >
|
params: {id: claim.id}
|
||||||
{{::claim.userName}}
|
}">
|
||||||
</span>
|
<td>{{::claim.id}}</td>
|
||||||
</vn-td>
|
<td>
|
||||||
<vn-td>
|
<span
|
||||||
<span class="chip {{::$ctrl.stateColor(claim)}}">
|
vn-click-stop="clientDescriptor.show($event, claim.clientFk)"
|
||||||
{{::claim.description}}
|
class="link">
|
||||||
</span>
|
{{::claim.socialName}}
|
||||||
</vn-td>
|
</span>
|
||||||
<vn-td shrink>
|
</td>
|
||||||
<vn-icon-button
|
<td center shrink-date>{{::claim.created | date:'dd/MM/yyyy'}}</td>
|
||||||
vn-click-stop="$ctrl.preview(claim)"
|
<td>
|
||||||
vn-tooltip="Preview"
|
<span
|
||||||
icon="preview">
|
vn-click-stop="workerDescriptor.show($event, claim.workerFk)"
|
||||||
</vn-icon-button>
|
class="link" >
|
||||||
</vn-td>
|
{{::claim.workerName}}
|
||||||
</a>
|
</span>
|
||||||
</vn-tbody>
|
</td>
|
||||||
</vn-table>
|
<td>
|
||||||
</vn-card>
|
<span class="chip {{::$ctrl.stateColor(claim)}}">
|
||||||
</vn-data-viewer>
|
{{::claim.description}}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td shrink>
|
||||||
|
<vn-icon-button
|
||||||
|
vn-click-stop="$ctrl.preview(claim)"
|
||||||
|
vn-tooltip="Preview"
|
||||||
|
icon="preview">
|
||||||
|
</vn-icon-button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</slot-table>
|
||||||
|
</smart-table>
|
||||||
|
</vn-card>
|
||||||
<vn-client-descriptor-popover
|
<vn-client-descriptor-popover
|
||||||
vn-id="clientDescriptor">
|
vn-id="clientDescriptor">
|
||||||
</vn-client-descriptor-popover>
|
</vn-client-descriptor-popover>
|
||||||
|
@ -62,6 +77,7 @@
|
||||||
</vn-worker-descriptor-popover>
|
</vn-worker-descriptor-popover>
|
||||||
<vn-popup vn-id="summary">
|
<vn-popup vn-id="summary">
|
||||||
<vn-claim-summary
|
<vn-claim-summary
|
||||||
claim="$ctrl.claimSelected">
|
claim="$ctrl.claimSelected"
|
||||||
|
parent-reload="$ctrl.reload()">
|
||||||
</vn-claim-summary>
|
</vn-claim-summary>
|
||||||
</vn-popup>
|
</vn-popup>
|
||||||
|
|
|
@ -1,7 +1,69 @@
|
||||||
import ngModule from '../module';
|
import ngModule from '../module';
|
||||||
import Section from 'salix/components/section';
|
import Section from 'salix/components/section';
|
||||||
|
|
||||||
export default class Controller extends Section {
|
class Controller extends Section {
|
||||||
|
constructor($element, $) {
|
||||||
|
super($element, $);
|
||||||
|
|
||||||
|
this.smartTableOptions = {
|
||||||
|
activeButtons: {
|
||||||
|
search: true
|
||||||
|
},
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
field: 'clientFk',
|
||||||
|
autocomplete: {
|
||||||
|
url: 'Clients',
|
||||||
|
showField: 'socialName',
|
||||||
|
valueField: 'socialName'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'workerFk',
|
||||||
|
autocomplete: {
|
||||||
|
url: 'Workers/activeWithInheritedRole',
|
||||||
|
where: `{role: 'salesPerson'}`,
|
||||||
|
searchFunction: '{firstName: $search}',
|
||||||
|
showField: 'name',
|
||||||
|
valueField: 'id',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'claimStateFk',
|
||||||
|
autocomplete: {
|
||||||
|
url: 'ClaimStates',
|
||||||
|
showField: 'description',
|
||||||
|
valueField: 'id',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'created',
|
||||||
|
searchable: false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
exprBuilder(param, value) {
|
||||||
|
switch (param) {
|
||||||
|
case 'clientFk':
|
||||||
|
return {['cl.socialName']: value};
|
||||||
|
case 'id':
|
||||||
|
case 'claimStateFk':
|
||||||
|
case 'priority':
|
||||||
|
return {[`cl.${param}`]: value};
|
||||||
|
case 'salesPersonFk':
|
||||||
|
case 'attenderFk':
|
||||||
|
return {'cl.workerFk': value};
|
||||||
|
case 'created':
|
||||||
|
value.setHours(0, 0, 0, 0);
|
||||||
|
to = new Date(value);
|
||||||
|
to.setHours(23, 59, 59, 999);
|
||||||
|
|
||||||
|
return {'cl.created': {between: [value, to]}};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
stateColor(claim) {
|
stateColor(claim) {
|
||||||
switch (claim.description) {
|
switch (claim.description) {
|
||||||
case 'Pendiente':
|
case 'Pendiente':
|
||||||
|
@ -17,6 +79,10 @@ export default class Controller extends Section {
|
||||||
this.claimSelected = claim;
|
this.claimSelected = claim;
|
||||||
this.$.summary.show();
|
this.$.summary.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reload() {
|
||||||
|
this.$.model.refresh();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ngModule.vnComponent('vnClaimIndex', {
|
ngModule.vnComponent('vnClaimIndex', {
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
<vn-log
|
||||||
|
url="ClaimLogs"
|
||||||
|
origin-id="$ctrl.$params.id">
|
||||||
|
</vn-log>
|
|
@ -0,0 +1,7 @@
|
||||||
|
import ngModule from '../module';
|
||||||
|
import Section from 'salix/components/section';
|
||||||
|
|
||||||
|
ngModule.vnComponent('vnClaimLog', {
|
||||||
|
template: require('./index.html'),
|
||||||
|
controller: Section,
|
||||||
|
});
|
|
@ -1,9 +1,7 @@
|
||||||
import ngModule from '../module';
|
import ngModule from '../module';
|
||||||
import ModuleMain from 'salix/components/module-main';
|
import ModuleMain from 'salix/components/module-main';
|
||||||
|
|
||||||
export default class Claim extends ModuleMain {}
|
|
||||||
|
|
||||||
ngModule.vnComponent('vnClaim', {
|
ngModule.vnComponent('vnClaim', {
|
||||||
controller: Claim,
|
controller: ModuleMain,
|
||||||
template: require('./index.html')
|
template: require('./index.html')
|
||||||
});
|
});
|
||||||
|
|
|
@ -13,7 +13,8 @@
|
||||||
{"state": "claim.card.detail", "icon": "icon-details"},
|
{"state": "claim.card.detail", "icon": "icon-details"},
|
||||||
{"state": "claim.card.photos", "icon": "image"},
|
{"state": "claim.card.photos", "icon": "image"},
|
||||||
{"state": "claim.card.development", "icon": "icon-traceability"},
|
{"state": "claim.card.development", "icon": "icon-traceability"},
|
||||||
{"state": "claim.card.action", "icon": "icon-actions"}
|
{"state": "claim.card.action", "icon": "icon-actions"},
|
||||||
|
{"state": "claim.card.log", "icon": "history"}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"keybindings": [
|
"keybindings": [
|
||||||
|
@ -88,6 +89,12 @@
|
||||||
"params": {
|
"params": {
|
||||||
"claim": "$ctrl.claim"
|
"claim": "$ctrl.claim"
|
||||||
}
|
}
|
||||||
|
}, {
|
||||||
|
"url" : "/log",
|
||||||
|
"state": "claim.card.log",
|
||||||
|
"component": "vn-claim-log",
|
||||||
|
"description": "Log",
|
||||||
|
"acl": ["claimManager"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
|
@ -12,6 +12,15 @@
|
||||||
<vn-icon-button icon="launch"></vn-icon-button>
|
<vn-icon-button icon="launch"></vn-icon-button>
|
||||||
</a>
|
</a>
|
||||||
<span>{{::$ctrl.summary.claim.id}} - {{::$ctrl.summary.claim.client.name}}</span>
|
<span>{{::$ctrl.summary.claim.id}} - {{::$ctrl.summary.claim.client.name}}</span>
|
||||||
|
<vn-button-menu
|
||||||
|
disabled="!$ctrl.summary.isEditable"
|
||||||
|
class="message"
|
||||||
|
label="Change state"
|
||||||
|
value-field="id"
|
||||||
|
show-field="description"
|
||||||
|
url="claimStates"
|
||||||
|
on-change="$ctrl.changeState(value)">
|
||||||
|
</vn-button-menu>
|
||||||
</h5>
|
</h5>
|
||||||
<vn-horizontal>
|
<vn-horizontal>
|
||||||
<vn-one>
|
<vn-one>
|
||||||
|
@ -32,28 +41,14 @@
|
||||||
value="{{$ctrl.summary.claim.worker.user.nickname}}">
|
value="{{$ctrl.summary.claim.worker.user.nickname}}">
|
||||||
</vn-label-value>
|
</vn-label-value>
|
||||||
</vn-one>
|
</vn-one>
|
||||||
<vn-one>
|
<vn-two>
|
||||||
<vn-textarea
|
<vn-textarea
|
||||||
vn-three
|
vn-three
|
||||||
disabled="true"
|
disabled="true"
|
||||||
label="Observation"
|
label="Observation"
|
||||||
ng-model="$ctrl.summary.claim.observation">
|
ng-model="$ctrl.summary.claim.observation">
|
||||||
</vn-textarea>
|
</vn-textarea>
|
||||||
</vn-one>
|
</vn-two>
|
||||||
<vn-one>
|
|
||||||
<vn-range
|
|
||||||
vn-one
|
|
||||||
disabled="true"
|
|
||||||
label="Responsability"
|
|
||||||
min-label="Company"
|
|
||||||
max-label="Sales/Client"
|
|
||||||
ng-model="$ctrl.summary.claim.responsibility"
|
|
||||||
max="5"
|
|
||||||
min="1"
|
|
||||||
step="1"
|
|
||||||
vn-acl="claimManager">
|
|
||||||
</vn-range>
|
|
||||||
</vn-one>
|
|
||||||
<vn-auto>
|
<vn-auto>
|
||||||
<h4 ng-show="$ctrl.isSalesPerson">
|
<h4 ng-show="$ctrl.isSalesPerson">
|
||||||
<a
|
<a
|
||||||
|
@ -171,6 +166,22 @@
|
||||||
ng-show="!$ctrl.isClaimManager">
|
ng-show="!$ctrl.isClaimManager">
|
||||||
Action
|
Action
|
||||||
</h4>
|
</h4>
|
||||||
|
<vn-horizontal>
|
||||||
|
<vn-one>
|
||||||
|
<vn-range
|
||||||
|
vn-one
|
||||||
|
disabled="true"
|
||||||
|
label="Responsability"
|
||||||
|
min-label="Company"
|
||||||
|
max-label="Sales/Client"
|
||||||
|
ng-model="$ctrl.summary.claim.responsibility"
|
||||||
|
max="5"
|
||||||
|
min="1"
|
||||||
|
step="1"
|
||||||
|
vn-acl="claimManager">
|
||||||
|
</vn-range>
|
||||||
|
</vn-one>
|
||||||
|
</vn-horizontal>
|
||||||
<vn-data-viewer data="::$ctrl.summary.actions">
|
<vn-data-viewer data="::$ctrl.summary.actions">
|
||||||
<vn-table>
|
<vn-table>
|
||||||
<vn-thead>
|
<vn-thead>
|
||||||
|
|
|
@ -10,7 +10,25 @@ class Controller extends Summary {
|
||||||
|
|
||||||
$onChanges() {
|
$onChanges() {
|
||||||
if (this.claim && this.claim.id)
|
if (this.claim && this.claim.id)
|
||||||
this.getSummary();
|
this.loadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
loadData() {
|
||||||
|
return this.$http.get(`Claims/${this.claim.id}/getSummary`).then(res => {
|
||||||
|
if (res && res.data)
|
||||||
|
this.summary = res.data;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
reload() {
|
||||||
|
this.loadData()
|
||||||
|
.then(() => {
|
||||||
|
if (this.card)
|
||||||
|
this.card.reload();
|
||||||
|
|
||||||
|
if (this.parentReload)
|
||||||
|
this.parentReload();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
get isSalesPerson() {
|
get isSalesPerson() {
|
||||||
|
@ -29,8 +47,10 @@ class Controller extends Summary {
|
||||||
this._claim = value;
|
this._claim = value;
|
||||||
|
|
||||||
// Get DMS on summary load
|
// Get DMS on summary load
|
||||||
if (value)
|
if (value) {
|
||||||
this.$.$applyAsync(() => this.loadDms());
|
this.$.$applyAsync(() => this.loadDms());
|
||||||
|
this.loadData();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadDms() {
|
loadDms() {
|
||||||
|
@ -40,15 +60,24 @@ class Controller extends Summary {
|
||||||
this.$.model.refresh();
|
this.$.model.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
getSummary() {
|
|
||||||
this.$http.get(`Claims/${this.claim.id}/getSummary`).then(response => {
|
|
||||||
this.summary = response.data;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getImagePath(dmsId) {
|
getImagePath(dmsId) {
|
||||||
return this.vnFile.getPath(`/api/dms/${dmsId}/downloadFile`);
|
return this.vnFile.getPath(`/api/dms/${dmsId}/downloadFile`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
changeState(value) {
|
||||||
|
const params = {
|
||||||
|
id: this.claim.id,
|
||||||
|
claimStateFk: value
|
||||||
|
};
|
||||||
|
|
||||||
|
this.$http.patch(`Claims/updateClaim/${this.claim.id}`, params)
|
||||||
|
.then(() => {
|
||||||
|
this.reload();
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
this.vnApp.showSuccess(this.$t('Data saved!'));
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Controller.$inject = ['$element', '$scope', 'vnFile'];
|
Controller.$inject = ['$element', '$scope', 'vnFile'];
|
||||||
|
@ -57,6 +86,11 @@ ngModule.vnComponent('vnClaimSummary', {
|
||||||
template: require('./index.html'),
|
template: require('./index.html'),
|
||||||
controller: Controller,
|
controller: Controller,
|
||||||
bindings: {
|
bindings: {
|
||||||
claim: '<'
|
claim: '<',
|
||||||
|
model: '<?',
|
||||||
|
parentReload: '&'
|
||||||
|
},
|
||||||
|
require: {
|
||||||
|
card: '?^vnClaimCard'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -18,23 +18,37 @@ describe('Claim', () => {
|
||||||
controller.$.model = crudModel;
|
controller.$.model = crudModel;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
describe('getSummary()', () => {
|
describe('loadData()', () => {
|
||||||
it('should perform a query to set summary', () => {
|
it('should perform a query to set summary', () => {
|
||||||
$httpBackend.expect('GET', `Claims/1/getSummary`).respond(200, 24);
|
$httpBackend.when('GET', `Claims/1/getSummary`).respond(200, 24);
|
||||||
controller.getSummary();
|
controller.loadData();
|
||||||
$httpBackend.flush();
|
$httpBackend.flush();
|
||||||
|
|
||||||
expect(controller.summary).toEqual(24);
|
expect(controller.summary).toEqual(24);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('changeState()', () => {
|
||||||
|
it('should make an HTTP post query, then call the showSuccess()', () => {
|
||||||
|
jest.spyOn(controller.vnApp, 'showSuccess').mockReturnThis();
|
||||||
|
|
||||||
|
const expectedParams = {id: 1, claimStateFk: 1};
|
||||||
|
$httpBackend.when('GET', `Claims/1/getSummary`).respond(200, 24);
|
||||||
|
$httpBackend.expect('PATCH', `Claims/updateClaim/1`, expectedParams).respond(200);
|
||||||
|
controller.changeState(1);
|
||||||
|
$httpBackend.flush();
|
||||||
|
|
||||||
|
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('$onChanges()', () => {
|
describe('$onChanges()', () => {
|
||||||
it('should call getSummary when item.id is defined', () => {
|
it('should call loadData when $onChanges is called', () => {
|
||||||
jest.spyOn(controller, 'getSummary');
|
jest.spyOn(controller, 'loadData');
|
||||||
|
|
||||||
controller.$onChanges();
|
controller.$onChanges();
|
||||||
|
|
||||||
expect(controller.getSummary).toHaveBeenCalledWith();
|
expect(controller.loadData).toHaveBeenCalledWith();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,4 +7,7 @@ vn-claim-summary {
|
||||||
.photo .image {
|
.photo .image {
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
vn-textarea *{
|
||||||
|
height: 80px;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,7 +1,8 @@
|
||||||
const models = require('vn-loopback/server/server').models;
|
const models = require('vn-loopback/server/server').models;
|
||||||
const soap = require('soap');
|
const soap = require('soap');
|
||||||
|
|
||||||
describe('client sendSms()', () => {
|
// #3673 sendSms tests excluded
|
||||||
|
xdescribe('client sendSms()', () => {
|
||||||
it('should now send a message and log it', async() => {
|
it('should now send a message and log it', async() => {
|
||||||
spyOn(soap, 'createClientAsync').and.returnValue('a so fake client');
|
spyOn(soap, 'createClientAsync').and.returnValue('a so fake client');
|
||||||
const tx = await models.Client.beginTransaction({});
|
const tx = await models.Client.beginTransaction({});
|
||||||
|
|
|
@ -35,7 +35,7 @@ describe('Client updateFiscalData', () => {
|
||||||
try {
|
try {
|
||||||
const options = {transaction: tx};
|
const options = {transaction: tx};
|
||||||
|
|
||||||
const client = await models.Client.findById(clientId, options);
|
const client = await models.Client.findById(clientId, null, options);
|
||||||
await client.updateAttribute('isTaxDataChecked', false, options);
|
await client.updateAttribute('isTaxDataChecked', false, options);
|
||||||
|
|
||||||
const ctx = {req: {accessToken: {userId: salesAssistantId}}};
|
const ctx = {req: {accessToken: {userId: salesAssistantId}}};
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
const models = require('vn-loopback/server/server').models;
|
const models = require('vn-loopback/server/server').models;
|
||||||
|
|
||||||
describe('Client updatePortfolio', () => {
|
xdescribe('Client updatePortfolio', () => {
|
||||||
const salesPersonId = 18;
|
const salesPersonId = 18;
|
||||||
const clienId = 1108;
|
const clientId = 1108;
|
||||||
it('should update the portfolioWeight', async() => {
|
it('should update the portfolioWeight', async() => {
|
||||||
const tx = await models.Client.beginTransaction({});
|
const tx = await models.Client.beginTransaction({});
|
||||||
|
|
||||||
|
@ -11,9 +11,7 @@ describe('Client updatePortfolio', () => {
|
||||||
|
|
||||||
const expectedResult = 841.63;
|
const expectedResult = 841.63;
|
||||||
|
|
||||||
const client = await models.Client.findById(clienId, null, options);
|
await models.Client.rawSql(`UPDATE vn.client SET salesPersonFk = ${salesPersonId} WHERE id = ${clientId}; `);
|
||||||
// await client.updateAttribute('salesPersonFk', 18);
|
|
||||||
await models.Client.rawSql(`UPDATE vn.client SET salesPersonFk = ${salesPersonId} WHERE id = ${clienId}; `);
|
|
||||||
|
|
||||||
await models.Client.updatePortfolio();
|
await models.Client.updatePortfolio();
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ module.exports = function(Self) {
|
||||||
});
|
});
|
||||||
|
|
||||||
Self.updatePortfolio = async() => {
|
Self.updatePortfolio = async() => {
|
||||||
query = `CALL bs.vendedores_updatePortfolio()`;
|
query = `CALL bs.salesPerson_updatePortfolio()`;
|
||||||
return await Self.rawSql(query);
|
return await Self.rawSql(query);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -56,18 +56,18 @@ module.exports = Self => {
|
||||||
FROM (
|
FROM (
|
||||||
SELECT
|
SELECT
|
||||||
DISTINCT c.id clientFk,
|
DISTINCT c.id clientFk,
|
||||||
c.name clientName,
|
c.socialName clientName,
|
||||||
c.salesPersonFk,
|
c.salesPersonFk,
|
||||||
u.name salesPersonName,
|
u.nickname salesPersonName,
|
||||||
d.amount,
|
d.amount,
|
||||||
co.created,
|
co.created,
|
||||||
CONCAT(DATE(co.created), ' ', co.text) observation,
|
co.text observation,
|
||||||
uw.id workerFk,
|
uw.id workerFk,
|
||||||
uw.name workerName,
|
uw.nickname workerName,
|
||||||
c.creditInsurance,
|
c.creditInsurance,
|
||||||
d.defaulterSinced
|
d.defaulterSinced
|
||||||
FROM vn.defaulter d
|
FROM vn.defaulter d
|
||||||
JOIN vn.client c ON c.id = d.clientFk
|
JOIN vn.client c ON c.id = d.clientFk
|
||||||
LEFT JOIN vn.clientObservation co ON co.clientFk = c.id
|
LEFT JOIN vn.clientObservation co ON co.clientFk = c.id
|
||||||
LEFT JOIN account.user u ON u.id = c.salesPersonFk
|
LEFT JOIN account.user u ON u.id = c.salesPersonFk
|
||||||
LEFT JOIN account.user uw ON uw.id = co.workerFk
|
LEFT JOIN account.user uw ON uw.id = co.workerFk
|
||||||
|
|
|
@ -47,12 +47,12 @@ describe('defaulter filter()', () => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const options = {transaction: tx};
|
const options = {transaction: tx};
|
||||||
const ctx = {req: {accessToken: {userId: authUserId}}, args: {search: 'bruce'}};
|
const ctx = {req: {accessToken: {userId: authUserId}}, args: {search: 'spider'}};
|
||||||
|
|
||||||
const result = await models.Defaulter.filter(ctx, null, options);
|
const result = await models.Defaulter.filter(ctx, null, options);
|
||||||
const firstRow = result[0];
|
const firstRow = result[0];
|
||||||
|
|
||||||
expect(firstRow.clientName).toEqual('Bruce Wayne');
|
expect(firstRow.clientName).toEqual('Spider man');
|
||||||
|
|
||||||
await tx.rollback();
|
await tx.rollback();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
const app = require('vn-loopback/server/server');
|
const app = require('vn-loopback/server/server');
|
||||||
|
|
||||||
describe('sms send()', () => {
|
// #3673 sendSms tests excluded
|
||||||
|
xdescribe('sms send()', () => {
|
||||||
it('should not return status error', async() => {
|
it('should not return status error', async() => {
|
||||||
const ctx = {req: {accessToken: {userId: 1}}};
|
const ctx = {req: {accessToken: {userId: 1}}};
|
||||||
const result = await app.models.Sms.send(ctx, 1105, '123456789', 'My SMS Body');
|
const result = await app.models.Sms.send(ctx, 1105, '123456789', 'My SMS Body');
|
||||||
|
|
|
@ -15,17 +15,18 @@
|
||||||
model="model">
|
model="model">
|
||||||
</vn-searchbar>
|
</vn-searchbar>
|
||||||
</vn-portal>
|
</vn-portal>
|
||||||
<vn-data-viewer
|
<vn-card>
|
||||||
model="model"
|
<smart-table
|
||||||
class="vn-w-xl">
|
model="model"
|
||||||
<vn-card>
|
options="$ctrl.smartTableOptions"
|
||||||
<vn-tool-bar>
|
expr-builder="$ctrl.exprBuilder(param, value)">
|
||||||
<div class="vn-pa-md">
|
<slot-actions>
|
||||||
|
<div>
|
||||||
<div class="totalBox" style="text-align: center;">
|
<div class="totalBox" style="text-align: center;">
|
||||||
<h6 translate>Total</h6>
|
<h6 translate>Total</h6>
|
||||||
<vn-label-value
|
<vn-label-value
|
||||||
label="Balance due"
|
label="Balance due"
|
||||||
value="{{$ctrl.balanceDueTotal}} €">
|
value="{{$ctrl.balanceDueTotal | currency: 'EUR': 2}}">
|
||||||
</vn-label-value>
|
</vn-label-value>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -38,90 +39,109 @@
|
||||||
icon="icon-notes">
|
icon="icon-notes">
|
||||||
</vn-button>
|
</vn-button>
|
||||||
</div>
|
</div>
|
||||||
</vn-tool-bar>
|
</slot-actions>
|
||||||
<vn-table model="model">
|
<slot-table>
|
||||||
<vn-thead>
|
<table>
|
||||||
<vn-tr>
|
<thead>
|
||||||
<vn-th shrink>
|
<tr>
|
||||||
<vn-multi-check
|
<th shrink>
|
||||||
model="model">
|
<vn-multi-check
|
||||||
</vn-multi-check>
|
model="model">
|
||||||
</vn-th>
|
</vn-multi-check>
|
||||||
<vn-th field="clientName">Client</vn-th>
|
</th>
|
||||||
<vn-th field="salesPersonFk">Comercial</vn-th>
|
<th field="clientName">
|
||||||
<vn-th
|
<span translate>Client</span>
|
||||||
field="amount"
|
</th>
|
||||||
vn-tooltip="Balance due"
|
<th field="salesPersonFk">
|
||||||
number>
|
<span translate>Comercial</span>
|
||||||
Balance D.
|
</th>
|
||||||
</vn-th>
|
<th
|
||||||
<vn-th
|
field="amount"
|
||||||
vn-tooltip="Worker who made the last observation"
|
vn-tooltip="Balance due">
|
||||||
shrink>
|
<span translate>Balance D.</span>
|
||||||
Author
|
</th>
|
||||||
</vn-th>
|
<th
|
||||||
<vn-th expand>Last observation</vn-th>
|
field="workerFk"
|
||||||
<vn-th
|
vn-tooltip="Worker who made the last observation">
|
||||||
vn-tooltip="Credit insurance"
|
<span translate>Author</span>
|
||||||
number>
|
</th>
|
||||||
Credit I.
|
<th field="observation" expand>
|
||||||
</vn-th>
|
<span translate>Last observation</span>
|
||||||
<vn-th shrink-datetime>From</vn-th>
|
</th>
|
||||||
</vn-tr>
|
<th
|
||||||
</vn-thead>
|
vn-tooltip="Last observation date"
|
||||||
<vn-tbody>
|
field="created"
|
||||||
<vn-tr ng-repeat="defaulter in defaulters">
|
shrink-datetime>
|
||||||
<vn-td shrink>
|
<span translate>Last observation D.</span>
|
||||||
<vn-check
|
</th>
|
||||||
ng-model="defaulter.checked"
|
<th
|
||||||
vn-click-stop>
|
vn-tooltip="Credit insurance"
|
||||||
</vn-check>
|
field="creditInsurance" >
|
||||||
</vn-td>
|
<span translate>Credit I.</span>
|
||||||
<vn-td>
|
</th>
|
||||||
<span
|
<th field="defaulterSinced">
|
||||||
vn-click-stop="clientDescriptor.show($event, defaulter.clientFk)"
|
<span translate>From</span>
|
||||||
title ="{{::defaulter.clientName}}"
|
</th>
|
||||||
class="link">
|
</tr>
|
||||||
{{::defaulter.clientName}}
|
</thead>
|
||||||
</span>
|
<tbody>
|
||||||
</vn-td>
|
<tr ng-repeat="defaulter in defaulters">
|
||||||
<vn-td>
|
<td shrink>
|
||||||
<span
|
<vn-check
|
||||||
title="{{::defaulter.salesPersonName}}"
|
ng-model="defaulter.checked"
|
||||||
vn-click-stop="workerDescriptor.show($event, defaulter.salesPersonFk)"
|
vn-click-stop>
|
||||||
class="link" >
|
</vn-check>
|
||||||
{{::defaulter.salesPersonName | dashIfEmpty}}
|
</td>
|
||||||
</span>
|
<td title="{{::defaulter.clientName}}">
|
||||||
</vn-td>
|
<span
|
||||||
<vn-td number>{{::defaulter.amount}}</vn-td>
|
vn-click-stop="clientDescriptor.show($event, defaulter.clientFk)"
|
||||||
<vn-td shrink>
|
title ="{{::defaulter.clientName}}"
|
||||||
<span
|
class="link">
|
||||||
title="{{::defaulter.workerName}}"
|
{{::defaulter.clientName}}
|
||||||
vn-click-stop="workerDescriptor.show($event, defaulter.workerFk)"
|
</span>
|
||||||
class="link" >
|
</td>
|
||||||
{{::defaulter.workerName | dashIfEmpty}}
|
<td>
|
||||||
</span>
|
<span
|
||||||
</vn-td>
|
title="{{::defaulter.salesPersonName}}"
|
||||||
<vn-td expand>
|
vn-click-stop="workerDescriptor.show($event, defaulter.salesPersonFk)"
|
||||||
<vn-textarea
|
class="link">
|
||||||
vn-three
|
{{::defaulter.salesPersonName | dashIfEmpty}}
|
||||||
disabled="true"
|
</span>
|
||||||
label="Observation"
|
</td>
|
||||||
ng-model="defaulter.observation">
|
<td>{{::defaulter.amount | currency: 'EUR': 2}}</td>
|
||||||
</vn-textarea>
|
<td>
|
||||||
</vn-td>
|
<span
|
||||||
<vn-td number>{{::defaulter.creditInsurance}}</vn-td>
|
title="{{::defaulter.workerName}}"
|
||||||
<vn-td shrink-datetime>{{::defaulter.defaulterSinced | date: 'dd/MM/yyyy'}}</vn-td>
|
vn-click-stop="workerDescriptor.show($event, defaulter.workerFk)"
|
||||||
</vn-tr>
|
class="link">
|
||||||
</vn-tbody>
|
{{::defaulter.workerName | dashIfEmpty}}
|
||||||
</vn-table>
|
</span>
|
||||||
</vn-card>
|
</td>
|
||||||
</vn-data-viewer>
|
<td expand>
|
||||||
|
<vn-textarea
|
||||||
|
vn-three
|
||||||
|
disabled="true"
|
||||||
|
ng-model="defaulter.observation">
|
||||||
|
</vn-textarea>
|
||||||
|
</td>
|
||||||
|
<td shrink-datetime>
|
||||||
|
<span class="chip {{::$ctrl.chipColor(defaulter.created)}}">
|
||||||
|
{{::defaulter.created | date: 'dd/MM/yyyy'}}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>{{::defaulter.creditInsurance | currency: 'EUR': 2}}</td>
|
||||||
|
<td>{{::defaulter.defaulterSinced | date: 'dd/MM/yyyy'}}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</slot-table>
|
||||||
|
</smart-table>
|
||||||
|
</vn-card>
|
||||||
<vn-client-descriptor-popover
|
<vn-client-descriptor-popover
|
||||||
vn-id="clientDescriptor">
|
vn-id="client-descriptor">
|
||||||
</vn-client-descriptor-popover>
|
</vn-client-descriptor-popover>
|
||||||
<vn-worker-descriptor-popover
|
<vn-worker-descriptor-popover
|
||||||
vn-id="workerDescriptor">
|
vn-id="worker-descriptor">
|
||||||
</vn-worker-descriptor-popover>
|
</vn-worker-descriptor-popover>
|
||||||
<vn-popup vn-id="dialog-summary-client">
|
<vn-popup vn-id="dialog-summary-client">
|
||||||
<vn-client-summary
|
<vn-client-summary
|
||||||
|
@ -129,37 +149,6 @@
|
||||||
</vn-client-summary>
|
</vn-client-summary>
|
||||||
</vn-popup>
|
</vn-popup>
|
||||||
|
|
||||||
<!--Context menu-->
|
|
||||||
<vn-contextmenu vn-id="contextmenu" targets="['vn-data-viewer']" model="model"
|
|
||||||
expr-builder="$ctrl.exprBuilder(param, value)">
|
|
||||||
<slot-menu>
|
|
||||||
<vn-item translate
|
|
||||||
ng-if="contextmenu.isFilterAllowed()"
|
|
||||||
ng-click="contextmenu.filterBySelection()">
|
|
||||||
Filter by selection
|
|
||||||
</vn-item>
|
|
||||||
<vn-item translate
|
|
||||||
ng-if="contextmenu.isFilterAllowed()"
|
|
||||||
ng-click="contextmenu.excludeSelection()">
|
|
||||||
Exclude selection
|
|
||||||
</vn-item>
|
|
||||||
<vn-item translate
|
|
||||||
ng-if="contextmenu.isFilterAllowed()"
|
|
||||||
ng-click="contextmenu.removeFilter()">
|
|
||||||
Remove filter
|
|
||||||
</vn-item>
|
|
||||||
<vn-item translate
|
|
||||||
ng-click="contextmenu.removeAllFilters()">
|
|
||||||
Remove all filters
|
|
||||||
</vn-item>
|
|
||||||
<vn-item translate
|
|
||||||
ng-if="contextmenu.isActionAllowed()"
|
|
||||||
ng-click="contextmenu.copyValue()">
|
|
||||||
Copy value
|
|
||||||
</vn-item>
|
|
||||||
</slot-menu>
|
|
||||||
</vn-contextmenu>
|
|
||||||
|
|
||||||
<!-- Dialog of add notes button -->
|
<!-- Dialog of add notes button -->
|
||||||
<vn-dialog
|
<vn-dialog
|
||||||
vn-id="notesDialog"
|
vn-id="notesDialog"
|
||||||
|
|
|
@ -6,17 +6,61 @@ export default class Controller extends Section {
|
||||||
constructor($element, $) {
|
constructor($element, $) {
|
||||||
super($element, $);
|
super($element, $);
|
||||||
this.defaulter = {};
|
this.defaulter = {};
|
||||||
|
|
||||||
|
this.smartTableOptions = {
|
||||||
|
activeButtons: {
|
||||||
|
search: true
|
||||||
|
},
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
field: 'clientName',
|
||||||
|
autocomplete: {
|
||||||
|
url: 'Clients',
|
||||||
|
showField: 'socialName',
|
||||||
|
valueField: 'socialName'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'salesPersonFk',
|
||||||
|
autocomplete: {
|
||||||
|
url: 'Workers/activeWithInheritedRole',
|
||||||
|
where: `{role: 'salesPerson'}`,
|
||||||
|
searchFunction: '{firstName: $search}',
|
||||||
|
showField: 'nickname',
|
||||||
|
valueField: 'id',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'workerFk',
|
||||||
|
autocomplete: {
|
||||||
|
url: 'Workers/activeWithInheritedRole',
|
||||||
|
searchFunction: '{firstName: $search}',
|
||||||
|
showField: 'nickname',
|
||||||
|
valueField: 'id',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'observation',
|
||||||
|
searchable: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'created',
|
||||||
|
searchable: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'defaulterSinced',
|
||||||
|
searchable: false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
get balanceDueTotal() {
|
get balanceDueTotal() {
|
||||||
let balanceDueTotal = 0;
|
let balanceDueTotal = 0;
|
||||||
|
const defaulters = this.$.model.data || [];
|
||||||
|
|
||||||
if (this.checked.length > 0) {
|
for (let defaulter of defaulters)
|
||||||
for (let defaulter of this.checked)
|
balanceDueTotal += defaulter.amount;
|
||||||
balanceDueTotal += defaulter.amount;
|
|
||||||
|
|
||||||
return balanceDueTotal;
|
|
||||||
}
|
|
||||||
|
|
||||||
return balanceDueTotal;
|
return balanceDueTotal;
|
||||||
}
|
}
|
||||||
|
@ -32,6 +76,22 @@ export default class Controller extends Section {
|
||||||
return checkedLines;
|
return checkedLines;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chipColor(date) {
|
||||||
|
const day = 24 * 60 * 60 * 1000;
|
||||||
|
const today = new Date();
|
||||||
|
today.setHours(0, 0, 0, 0);
|
||||||
|
|
||||||
|
const observationShipped = new Date(date);
|
||||||
|
observationShipped.setHours(0, 0, 0, 0);
|
||||||
|
|
||||||
|
const difference = today - observationShipped;
|
||||||
|
|
||||||
|
if (difference > (day * 20))
|
||||||
|
return 'alert';
|
||||||
|
if (difference > (day * 10))
|
||||||
|
return 'warning';
|
||||||
|
}
|
||||||
|
|
||||||
onResponse() {
|
onResponse() {
|
||||||
if (!this.defaulter.observation)
|
if (!this.defaulter.observation)
|
||||||
throw new UserError(`The message can't be empty`);
|
throw new UserError(`The message can't be empty`);
|
||||||
|
@ -52,14 +112,17 @@ export default class Controller extends Section {
|
||||||
|
|
||||||
exprBuilder(param, value) {
|
exprBuilder(param, value) {
|
||||||
switch (param) {
|
switch (param) {
|
||||||
|
case 'creditInsurance':
|
||||||
|
case 'amount':
|
||||||
case 'clientName':
|
case 'clientName':
|
||||||
|
case 'workerFk':
|
||||||
case 'salesPersonFk':
|
case 'salesPersonFk':
|
||||||
return {[`d.${param}`]: value};
|
return {[`d.${param}`]: value};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ngModule.vnComponent('vnClientDefaulterIndex', {
|
ngModule.vnComponent('vnClientDefaulter', {
|
||||||
template: require('./index.html'),
|
template: require('./index.html'),
|
||||||
controller: Controller
|
controller: Controller
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,7 +2,7 @@ import './index';
|
||||||
import crudModel from 'core/mocks/crud-model';
|
import crudModel from 'core/mocks/crud-model';
|
||||||
|
|
||||||
describe('client defaulter', () => {
|
describe('client defaulter', () => {
|
||||||
describe('Component vnClientDefaulterIndex', () => {
|
describe('Component vnClientDefaulter', () => {
|
||||||
let controller;
|
let controller;
|
||||||
let $httpBackend;
|
let $httpBackend;
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ describe('client defaulter', () => {
|
||||||
beforeEach(inject(($componentController, _$httpBackend_) => {
|
beforeEach(inject(($componentController, _$httpBackend_) => {
|
||||||
$httpBackend = _$httpBackend_;
|
$httpBackend = _$httpBackend_;
|
||||||
const $element = angular.element('<vn-client-defaulter></vn-client-defaulter>');
|
const $element = angular.element('<vn-client-defaulter></vn-client-defaulter>');
|
||||||
controller = $componentController('vnClientDefaulterIndex', {$element});
|
controller = $componentController('vnClientDefaulter', {$element});
|
||||||
controller.$.model = crudModel;
|
controller.$.model = crudModel;
|
||||||
controller.$.model.data = [
|
controller.$.model.data = [
|
||||||
{clientFk: 1101, amount: 125},
|
{clientFk: 1101, amount: 125},
|
||||||
|
@ -39,11 +39,7 @@ describe('client defaulter', () => {
|
||||||
describe('balanceDueTotal() getter', () => {
|
describe('balanceDueTotal() getter', () => {
|
||||||
it('should return balance due total', () => {
|
it('should return balance due total', () => {
|
||||||
const data = controller.$.model.data;
|
const data = controller.$.model.data;
|
||||||
data[1].checked = true;
|
const expectedAmount = data[0].amount + data[1].amount + data[2].amount;
|
||||||
data[2].checked = true;
|
|
||||||
|
|
||||||
const checkedRows = controller.checked;
|
|
||||||
const expectedAmount = checkedRows[0].amount + checkedRows[1].amount;
|
|
||||||
|
|
||||||
const result = controller.balanceDueTotal;
|
const result = controller.balanceDueTotal;
|
||||||
|
|
||||||
|
@ -51,6 +47,31 @@ describe('client defaulter', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('chipColor()', () => {
|
||||||
|
it('should return undefined when the date is the present', () => {
|
||||||
|
let today = new Date();
|
||||||
|
let result = controller.chipColor(today);
|
||||||
|
|
||||||
|
expect(result).toEqual(undefined);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return warning when the date is 10 days in the past', () => {
|
||||||
|
let pastDate = new Date();
|
||||||
|
pastDate = pastDate.setDate(pastDate.getDate() - 11);
|
||||||
|
let result = controller.chipColor(pastDate);
|
||||||
|
|
||||||
|
expect(result).toEqual('warning');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return alert when the date is 20 days in the past', () => {
|
||||||
|
let pastDate = new Date();
|
||||||
|
pastDate = pastDate.setDate(pastDate.getDate() - 21);
|
||||||
|
let result = controller.chipColor(pastDate);
|
||||||
|
|
||||||
|
expect(result).toEqual('alert');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('onResponse()', () => {
|
describe('onResponse()', () => {
|
||||||
it('should return error for empty message', () => {
|
it('should return error for empty message', () => {
|
||||||
let error;
|
let error;
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
Last observation: Última observación
|
|
||||||
Add observation: Añadir observación
|
Add observation: Añadir observación
|
||||||
Search client: Buscar clientes
|
|
||||||
Add observation to all selected clients: Añadir observación a {{total}} cliente(s) seleccionado(s)
|
Add observation to all selected clients: Añadir observación a {{total}} cliente(s) seleccionado(s)
|
||||||
Credit I.: Crédito A.
|
|
||||||
Balance D.: Saldo V.
|
Balance D.: Saldo V.
|
||||||
|
Credit I.: Crédito A.
|
||||||
|
Last observation: Última observación
|
||||||
|
Last observation D.: Fecha última O.
|
||||||
|
Last observation date: Fecha última observación
|
||||||
|
Search client: Buscar clientes
|
||||||
Worker who made the last observation: Trabajador que ha realizado la última observación
|
Worker who made the last observation: Trabajador que ha realizado la última observación
|
|
@ -8,7 +8,7 @@
|
||||||
"main": [
|
"main": [
|
||||||
{"state": "client.index", "icon": "person"},
|
{"state": "client.index", "icon": "person"},
|
||||||
{"state": "client.notification", "icon": "campaign"},
|
{"state": "client.notification", "icon": "campaign"},
|
||||||
{"state": "client.defaulter.index", "icon": "icon-defaulter"}
|
{"state": "client.defaulter", "icon": "icon-defaulter"}
|
||||||
],
|
],
|
||||||
"card": [
|
"card": [
|
||||||
{"state": "client.card.basicData", "icon": "settings"},
|
{"state": "client.card.basicData", "icon": "settings"},
|
||||||
|
@ -366,13 +366,7 @@
|
||||||
{
|
{
|
||||||
"url": "/defaulter",
|
"url": "/defaulter",
|
||||||
"state": "client.defaulter",
|
"state": "client.defaulter",
|
||||||
"component": "ui-view",
|
"component": "vn-client-defaulter",
|
||||||
"description": "Defaulter"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "/index?q",
|
|
||||||
"state": "client.defaulter.index",
|
|
||||||
"component": "vn-client-defaulter-index",
|
|
||||||
"description": "Defaulter"
|
"description": "Defaulter"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
name="showInvoicePdf"
|
name="showInvoicePdf"
|
||||||
translate>
|
translate>
|
||||||
Show invoice...
|
Show invoice...
|
||||||
|
|
||||||
<vn-menu vn-id="showInvoiceMenu">
|
<vn-menu vn-id="showInvoiceMenu">
|
||||||
<vn-list>
|
<vn-list>
|
||||||
<a class="vn-item"
|
<a class="vn-item"
|
||||||
|
@ -33,7 +32,6 @@
|
||||||
name="sendInvoice"
|
name="sendInvoice"
|
||||||
translate>
|
translate>
|
||||||
Send invoice...
|
Send invoice...
|
||||||
|
|
||||||
<vn-menu vn-id="sendInvoiceMenu">
|
<vn-menu vn-id="sendInvoiceMenu">
|
||||||
<vn-list>
|
<vn-list>
|
||||||
<vn-item
|
<vn-item
|
||||||
|
|
|
@ -3,13 +3,21 @@
|
||||||
url="Items/getWasteByWorker"
|
url="Items/getWasteByWorker"
|
||||||
data="details">
|
data="details">
|
||||||
</vn-crud-model>
|
</vn-crud-model>
|
||||||
|
|
||||||
<vn-data-viewer model="model">
|
<vn-data-viewer model="model">
|
||||||
<vn-card>
|
<section ng-repeat="detail in details" class="vn-pa-md">
|
||||||
<section ng-repeat="detail in details" class="vn-pa-md">
|
<vn-horizontal class="header">
|
||||||
<vn-horizontal class="header">
|
<h5><span translate>{{detail.buyer}}</span></h5>
|
||||||
<h5><span><span translate>{{detail.buyer}}</span></h5>
|
<vn-none>
|
||||||
</vn-horizontal>
|
<vn-icon
|
||||||
|
ng-class="{'hidden': !$ctrl.wasteConfig[detail.buyer].hidden}"
|
||||||
|
class="arrow pointer"
|
||||||
|
icon="keyboard_arrow_up"
|
||||||
|
vn-tooltip="Minimize/Maximize"
|
||||||
|
ng-click="$ctrl.toggleHidePanel(detail)">
|
||||||
|
</vn-icon>
|
||||||
|
</vn-none>
|
||||||
|
</vn-horizontal>
|
||||||
|
<vn-card ng-class="{'hidden': !$ctrl.wasteConfig[detail.buyer].hidden}">
|
||||||
<vn-table>
|
<vn-table>
|
||||||
<vn-thead>
|
<vn-thead>
|
||||||
<vn-tr>
|
<vn-tr>
|
||||||
|
@ -21,7 +29,7 @@
|
||||||
</vn-thead>
|
</vn-thead>
|
||||||
<vn-tbody>
|
<vn-tbody>
|
||||||
<a ng-repeat="waste in detail.lines" class="clickable vn-tr"
|
<a ng-repeat="waste in detail.lines" class="clickable vn-tr"
|
||||||
ui-sref="item.waste.detail({buyer: waste.buyer, family: waste.family})" >
|
ui-sref="item.waste.detail({buyer: waste.buyer, family: waste.family})">
|
||||||
<vn-td class="waste-family">{{::waste.family}}</vn-td>
|
<vn-td class="waste-family">{{::waste.family}}</vn-td>
|
||||||
<vn-td number>{{::(waste.percentage / 100) | percentage: 2}}</vn-td>
|
<vn-td number>{{::(waste.percentage / 100) | percentage: 2}}</vn-td>
|
||||||
<vn-td number>{{::waste.dwindle | currency: 'EUR'}}</vn-td>
|
<vn-td number>{{::waste.dwindle | currency: 'EUR'}}</vn-td>
|
||||||
|
@ -29,6 +37,6 @@
|
||||||
</vn-tr>
|
</vn-tr>
|
||||||
</vn-tbody>
|
</vn-tbody>
|
||||||
</vn-table>
|
</vn-table>
|
||||||
</section>
|
</vn-card>
|
||||||
</vn-card>
|
</section>
|
||||||
</vn-data-viewer>
|
</vn-data-viewer>
|
|
@ -2,7 +2,34 @@ import ngModule from '../../module';
|
||||||
import Section from 'salix/components/section';
|
import Section from 'salix/components/section';
|
||||||
import './style.scss';
|
import './style.scss';
|
||||||
|
|
||||||
|
export default class Controller extends Section {
|
||||||
|
constructor($element, $) {
|
||||||
|
super($element, $);
|
||||||
|
|
||||||
|
this.getWasteConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
getWasteConfig() {
|
||||||
|
return this.wasteConfig = JSON.parse(localStorage.getItem('wasteConfig')) || {};
|
||||||
|
}
|
||||||
|
|
||||||
|
setWasteConfig() {
|
||||||
|
localStorage.setItem('wasteConfig', JSON.stringify(this.wasteConfig));
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleHidePanel(detail) {
|
||||||
|
if (!this.wasteConfig[detail.buyer]) {
|
||||||
|
this.wasteConfig[detail.buyer] = {
|
||||||
|
hidden: true
|
||||||
|
};
|
||||||
|
} else
|
||||||
|
this.wasteConfig[detail.buyer].hidden = !this.wasteConfig[detail.buyer].hidden;
|
||||||
|
|
||||||
|
this.setWasteConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ngModule.vnComponent('vnItemWasteIndex', {
|
ngModule.vnComponent('vnItemWasteIndex', {
|
||||||
template: require('./index.html'),
|
template: require('./index.html'),
|
||||||
controller: Section
|
controller: Controller
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
import './index.js';
|
||||||
|
import crudModel from 'core/mocks/crud-model';
|
||||||
|
|
||||||
|
describe('Item', () => {
|
||||||
|
describe('Component vnItemWasteIndex', () => {
|
||||||
|
let $scope;
|
||||||
|
let controller;
|
||||||
|
|
||||||
|
beforeEach(ngModule('item'));
|
||||||
|
|
||||||
|
beforeEach(inject(($componentController, $rootScope) => {
|
||||||
|
$scope = $rootScope.$new();
|
||||||
|
$scope.model = crudModel;
|
||||||
|
const $element = angular.element('<vn-item-waste-index></vn-item-waste-index>');
|
||||||
|
controller = $componentController('vnItemWasteIndex', {$element, $scope});
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('getWasteConfig / setWasteConfig', () => {
|
||||||
|
it('should return the local storage wasteConfig', () => {
|
||||||
|
const result = controller.getWasteConfig();
|
||||||
|
|
||||||
|
expect(result).toEqual({});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set and return the local storage wasteConfig', () => {
|
||||||
|
controller.wasteConfig = {salesPerson: {hidden: true}};
|
||||||
|
controller.setWasteConfig();
|
||||||
|
|
||||||
|
const result = controller.getWasteConfig();
|
||||||
|
|
||||||
|
expect(result).toEqual(controller.wasteConfig);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('toggleHidePanel()', () => {
|
||||||
|
it('should make details hidden by default', () => {
|
||||||
|
controller.wasteConfig = {};
|
||||||
|
|
||||||
|
controller.toggleHidePanel({buyer: 'salesPerson'});
|
||||||
|
|
||||||
|
expect(controller.wasteConfig.salesPerson.hidden).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should toggle hidden false', () => {
|
||||||
|
controller.wasteConfig = {salesPerson: {hidden: true}};
|
||||||
|
|
||||||
|
controller.toggleHidePanel({buyer: 'salesPerson'});
|
||||||
|
|
||||||
|
expect(controller.wasteConfig.salesPerson.hidden).toEqual(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,21 +1,24 @@
|
||||||
@import "variables";
|
@import "variables";
|
||||||
|
@import "effects";
|
||||||
|
|
||||||
vn-item-waste-index,
|
vn-item-waste-index,
|
||||||
vn-item-waste-detail {
|
vn-item-waste-detail {
|
||||||
.header {
|
.header {
|
||||||
margin-bottom: 16px;
|
padding: 12px 0 5px 0;
|
||||||
text-transform: uppercase;
|
color: gray;
|
||||||
font-size: 1.25rem;
|
font-size: 1.2rem;
|
||||||
line-height: 1;
|
border-bottom: $border;
|
||||||
padding: 7px;
|
margin-bottom: 10px;
|
||||||
padding-bottom: 7px;
|
|
||||||
padding-bottom: 4px;
|
& > vn-none > vn-icon {
|
||||||
font-weight: lighter;
|
@extend %clickable-light;
|
||||||
background-color: $color-bg;
|
color: $color-button;
|
||||||
border-bottom: 1px solid #f7931e;
|
font-size: 1.4rem;
|
||||||
white-space: nowrap;
|
}
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
vn-none > .arrow {
|
||||||
|
transition: transform 200ms;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vn-table vn-th.waste-family,
|
vn-table vn-th.waste-family,
|
||||||
|
@ -23,4 +26,12 @@ vn-item-waste-detail {
|
||||||
max-width: 64px;
|
max-width: 64px;
|
||||||
width: 64px
|
width: 64px
|
||||||
}
|
}
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
}
|
||||||
|
.header > vn-none > .arrow.hidden {
|
||||||
|
display: block;
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
Family: Familia
|
Family: Familia
|
||||||
Percentage: Porcentaje
|
Percentage: Porcentaje
|
||||||
Dwindle: Mermas
|
Dwindle: Mermas
|
||||||
|
Minimize/Maximize: Minimizar/Maximizar
|
|
@ -18,7 +18,7 @@ module.exports = Self => {
|
||||||
}, {
|
}, {
|
||||||
arg: 'search',
|
arg: 'search',
|
||||||
type: 'string',
|
type: 'string',
|
||||||
description: `If it's and integer searchs by id, otherwise it searchs by nickname`
|
description: `The general search by ticket id or nickname`
|
||||||
}, {
|
}, {
|
||||||
arg: 'from',
|
arg: 'from',
|
||||||
type: 'date',
|
type: 'date',
|
||||||
|
@ -36,9 +36,9 @@ module.exports = Self => {
|
||||||
type: 'integer',
|
type: 'integer',
|
||||||
description: 'The client id'
|
description: 'The client id'
|
||||||
}, {
|
}, {
|
||||||
arg: 'ticketFk',
|
arg: 'orderFk',
|
||||||
type: 'integer',
|
type: 'integer',
|
||||||
description: 'The ticket id'
|
description: 'The order id'
|
||||||
}, {
|
}, {
|
||||||
arg: 'agencyModeFk',
|
arg: 'agencyModeFk',
|
||||||
type: 'integer',
|
type: 'integer',
|
||||||
|
@ -103,7 +103,7 @@ module.exports = Self => {
|
||||||
switch (param) {
|
switch (param) {
|
||||||
case 'search':
|
case 'search':
|
||||||
return /^\d+$/.test(value)
|
return /^\d+$/.test(value)
|
||||||
? {'o.id': value}
|
? {'t.id': value}
|
||||||
: {or: [
|
: {or: [
|
||||||
{'c.name': {like: `%${value}%`}}
|
{'c.name': {like: `%${value}%`}}
|
||||||
]};
|
]};
|
||||||
|
@ -119,8 +119,8 @@ module.exports = Self => {
|
||||||
return {'o.agency_id': value};
|
return {'o.agency_id': value};
|
||||||
case 'sourceApp':
|
case 'sourceApp':
|
||||||
return {'o.source_app': value};
|
return {'o.source_app': value};
|
||||||
case 'ticketFk':
|
case 'orderFk':
|
||||||
return {'ot.ticketFk': value};
|
return {'o.id': value};
|
||||||
case 'isConfirmed':
|
case 'isConfirmed':
|
||||||
return {'o.confirmed': value ? 1 : 0};
|
return {'o.confirmed': value ? 1 : 0};
|
||||||
case 'myTeam':
|
case 'myTeam':
|
||||||
|
@ -131,7 +131,7 @@ module.exports = Self => {
|
||||||
case 'showEmpty':
|
case 'showEmpty':
|
||||||
return {'o.total': {neq: value}};
|
return {'o.total': {neq: value}};
|
||||||
case 'id':
|
case 'id':
|
||||||
param = `o.${param}`;
|
param = `t.${param}`;
|
||||||
return {[param]: value};
|
return {[param]: value};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
<vn-searchbar
|
<vn-searchbar
|
||||||
vn-focus
|
vn-focus
|
||||||
panel="vn-order-search-panel"
|
panel="vn-order-search-panel"
|
||||||
info="Search orders by id"
|
info="Search orders by ticket id"
|
||||||
model="model"
|
model="model"
|
||||||
filter="$ctrl.filter">
|
filter="$ctrl.filter">
|
||||||
</vn-searchbar>
|
</vn-searchbar>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
vn-one
|
vn-one
|
||||||
label="General search"
|
label="General search"
|
||||||
ng-model="filter.search"
|
ng-model="filter.search"
|
||||||
info="Search orders by id"
|
info="Search orders by ticket id"
|
||||||
vn-focus>
|
vn-focus>
|
||||||
</vn-textfield>
|
</vn-textfield>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
|
@ -51,8 +51,8 @@
|
||||||
<vn-horizontal>
|
<vn-horizontal>
|
||||||
<vn-textfield
|
<vn-textfield
|
||||||
vn-one
|
vn-one
|
||||||
label="Ticket id"
|
label="Order id"
|
||||||
ng-model="filter.ticketFk">
|
ng-model="filter.orderFk">
|
||||||
</vn-textfield>
|
</vn-textfield>
|
||||||
<vn-autocomplete
|
<vn-autocomplete
|
||||||
vn-one
|
vn-one
|
||||||
|
|
|
@ -8,4 +8,4 @@ Application: Aplicación
|
||||||
SalesPerson: Comercial
|
SalesPerson: Comercial
|
||||||
Order confirmed: Pedido confirmado
|
Order confirmed: Pedido confirmado
|
||||||
Show empty: Mostrar vacías
|
Show empty: Mostrar vacías
|
||||||
Search orders by id: Buscar pedido por id
|
Search orders by ticket id: Buscar pedido por id ticket
|
|
@ -25,6 +25,7 @@ module.exports = Self => {
|
||||||
Object.assign(myOptions, options);
|
Object.assign(myOptions, options);
|
||||||
|
|
||||||
const route = await Self.app.models.Route.findById(id, null, myOptions);
|
const route = await Self.app.models.Route.findById(id, null, myOptions);
|
||||||
|
|
||||||
const zoneAgencyModes = await Self.app.models.ZoneAgencyMode.find({
|
const zoneAgencyModes = await Self.app.models.ZoneAgencyMode.find({
|
||||||
where: {
|
where: {
|
||||||
agencyModeFk: route.agencyModeFk
|
agencyModeFk: route.agencyModeFk
|
||||||
|
@ -52,6 +53,12 @@ module.exports = Self => {
|
||||||
fields: ['id', 'name']
|
fields: ['id', 'name']
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
relation: 'zone',
|
||||||
|
scope: {
|
||||||
|
fields: ['id', 'name']
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
relation: 'address',
|
relation: 'address',
|
||||||
scope: {
|
scope: {
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
const models = require('vn-loopback/server/server').models;
|
||||||
|
|
||||||
|
describe('route unlink()', () => {
|
||||||
|
it('should show no tickets since the link between zone and route for the give agencymode was removed', async() => {
|
||||||
|
const tx = await models.ZoneAgencyMode.beginTransaction({});
|
||||||
|
const agencyModeId = 1;
|
||||||
|
const zoneId = 1;
|
||||||
|
routeId = 1;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
let zoneAgencyModes = await models.ZoneAgencyMode.find(null, options);
|
||||||
|
let tickets = await models.Route.getSuggestedTickets(routeId, options);
|
||||||
|
|
||||||
|
expect(zoneAgencyModes.length).toEqual(4);
|
||||||
|
expect(tickets.length).toEqual(3);
|
||||||
|
|
||||||
|
await models.Route.unlink(agencyModeId, zoneId, options);
|
||||||
|
|
||||||
|
zoneAgencyModes = await models.ZoneAgencyMode.find(null, options);
|
||||||
|
tickets = await models.Route.getSuggestedTickets(routeId, options);
|
||||||
|
|
||||||
|
expect(zoneAgencyModes.length).toEqual(3);
|
||||||
|
expect(tickets.length).toEqual(0);
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,42 @@
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethod('unlink', {
|
||||||
|
description: 'Removes the matching entries from zoneAgencyMode',
|
||||||
|
accessType: 'WRITE',
|
||||||
|
accepts: [
|
||||||
|
{
|
||||||
|
arg: 'agencyModeId',
|
||||||
|
type: 'number',
|
||||||
|
required: true,
|
||||||
|
description: 'The agencyMode id',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'zoneId',
|
||||||
|
type: 'number',
|
||||||
|
required: true,
|
||||||
|
description: 'The zone id',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
returns: {
|
||||||
|
type: ['object'],
|
||||||
|
root: true
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
path: `/unlink`,
|
||||||
|
verb: 'POST'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.unlink = async(agencyModeId, zoneId, options) => {
|
||||||
|
const myOptions = {};
|
||||||
|
|
||||||
|
if (typeof options == 'object')
|
||||||
|
Object.assign(myOptions, options);
|
||||||
|
|
||||||
|
const where = {
|
||||||
|
agencyModeFk: agencyModeId,
|
||||||
|
zoneFk: zoneId
|
||||||
|
};
|
||||||
|
|
||||||
|
await Self.app.models.ZoneAgencyMode.destroyAll(where, myOptions);
|
||||||
|
};
|
||||||
|
};
|
|
@ -8,6 +8,7 @@ module.exports = Self => {
|
||||||
require('../methods/route/insertTicket')(Self);
|
require('../methods/route/insertTicket')(Self);
|
||||||
require('../methods/route/clone')(Self);
|
require('../methods/route/clone')(Self);
|
||||||
require('../methods/route/getSuggestedTickets')(Self);
|
require('../methods/route/getSuggestedTickets')(Self);
|
||||||
|
require('../methods/route/unlink')(Self);
|
||||||
|
|
||||||
Self.validate('kmStart', validateDistance, {
|
Self.validate('kmStart', validateDistance, {
|
||||||
message: 'Distance must be lesser than 1000'
|
message: 'Distance must be lesser than 1000'
|
||||||
|
|
|
@ -150,7 +150,7 @@
|
||||||
</vn-th>
|
</vn-th>
|
||||||
<vn-th expand>PC</vn-th>
|
<vn-th expand>PC</vn-th>
|
||||||
<vn-th>Address</vn-th>
|
<vn-th>Address</vn-th>
|
||||||
<vn-th shrink>Warehouse</vn-th>
|
<vn-th shrink>Zone</vn-th>
|
||||||
</vn-tr>
|
</vn-tr>
|
||||||
</vn-thead>
|
</vn-thead>
|
||||||
<vn-tbody>
|
<vn-tbody>
|
||||||
|
@ -174,7 +174,15 @@
|
||||||
<vn-td shrink>{{::ticket.address.city}}</vn-td>
|
<vn-td shrink>{{::ticket.address.city}}</vn-td>
|
||||||
<vn-td number shrink>{{::ticket.address.postalCode}}</vn-td>
|
<vn-td number shrink>{{::ticket.address.postalCode}}</vn-td>
|
||||||
<vn-td expand title="{{::ticket.address.street}}">{{::ticket.address.street}}</vn-td>
|
<vn-td expand title="{{::ticket.address.street}}">{{::ticket.address.street}}</vn-td>
|
||||||
<vn-td expand>{{::ticket.warehouse.name}}</vn-td>
|
<vn-td expand>
|
||||||
|
{{::ticket.zone.name}}
|
||||||
|
<vn-icon-button
|
||||||
|
icon="link_off"
|
||||||
|
class="pointer"
|
||||||
|
translate-attr="{title: 'Unlink zone: {{::ticket.zone.name}} from agency: {{::ticket.agencyMode.name}}'}"
|
||||||
|
ng-click="unlinkZoneConfirmation.show(ticket)">
|
||||||
|
</vn-icon-button>
|
||||||
|
</vn-td>
|
||||||
</vn-tr>
|
</vn-tr>
|
||||||
</vn-tbody>
|
</vn-tbody>
|
||||||
</vn-table>
|
</vn-table>
|
||||||
|
@ -196,3 +204,11 @@
|
||||||
<vn-client-descriptor-popover
|
<vn-client-descriptor-popover
|
||||||
vn-id="client-descriptor">
|
vn-id="client-descriptor">
|
||||||
</vn-client-descriptor-popover>
|
</vn-client-descriptor-popover>
|
||||||
|
|
||||||
|
<!-- Unlink zone confirmation dialog -->
|
||||||
|
<vn-confirm
|
||||||
|
vn-id="unlinkZoneConfirmation"
|
||||||
|
on-accept="$ctrl.unlinkZone($data)"
|
||||||
|
question="{{$ctrl.confirmationMessage}}"
|
||||||
|
message="Unlink selected zone?">
|
||||||
|
</vn-confirm>
|
|
@ -37,6 +37,19 @@ class Controller extends Section {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unlinkZone(ticket) {
|
||||||
|
const params = {
|
||||||
|
agencyModeId: this.route.agencyModeFk,
|
||||||
|
zoneId: ticket.zoneFk,
|
||||||
|
};
|
||||||
|
|
||||||
|
const query = `Routes/unlink`;
|
||||||
|
this.$http.post(query, params).then(() => {
|
||||||
|
this.vnApp.showSuccess(this.$t('Data saved!'));
|
||||||
|
this.$.possibleTicketsModel.refresh();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
getSelectedItems(items) {
|
getSelectedItems(items) {
|
||||||
const selectedItems = [];
|
const selectedItems = [];
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
/* eslint max-len: ["error", { "code": 150 }]*/
|
||||||
import './index';
|
import './index';
|
||||||
|
|
||||||
describe('Route', () => {
|
describe('Route', () => {
|
||||||
|
@ -73,6 +74,32 @@ describe('Route', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('unlink()', () => {
|
||||||
|
it('should call the route unlink endpoint with the agency and zone ids', () => {
|
||||||
|
controller.$.possibleTicketsModel = {refresh: jest.fn()};
|
||||||
|
jest.spyOn(controller.vnApp, 'showSuccess');
|
||||||
|
|
||||||
|
controller.route = {
|
||||||
|
agencyModeFk: 1
|
||||||
|
};
|
||||||
|
|
||||||
|
const ticket = {
|
||||||
|
zoneFk: 2,
|
||||||
|
};
|
||||||
|
const params = {
|
||||||
|
agencyModeId: controller.route.agencyModeFk,
|
||||||
|
zoneId: ticket.zoneFk,
|
||||||
|
};
|
||||||
|
|
||||||
|
$httpBackend.expectPOST(`Routes/unlink`, params).respond('ok');
|
||||||
|
controller.unlinkZone(ticket);
|
||||||
|
$httpBackend.flush();
|
||||||
|
|
||||||
|
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
|
||||||
|
expect(controller.$.possibleTicketsModel.refresh).toHaveBeenCalledWith();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('getSelectedItems()', () => {
|
describe('getSelectedItems()', () => {
|
||||||
it('should return the selected items', () => {
|
it('should return the selected items', () => {
|
||||||
let items = [
|
let items = [
|
||||||
|
|
|
@ -11,4 +11,5 @@ The selected ticket is not suitable for this route: El ticket seleccionado no es
|
||||||
PC: CP
|
PC: CP
|
||||||
The route's vehicle doesn't have a delivery point: El vehículo de la ruta no tiene un punto de entrega
|
The route's vehicle doesn't have a delivery point: El vehículo de la ruta no tiene un punto de entrega
|
||||||
The route doesn't have a vehicle: La ruta no tiene un vehículo
|
The route doesn't have a vehicle: La ruta no tiene un vehículo
|
||||||
Population: Población
|
Population: Población
|
||||||
|
Unlink selected zone?: Desvincular zona seleccionada?
|
||||||
|
|
|
@ -1,16 +1,28 @@
|
||||||
const app = require('vn-loopback/server/server');
|
const models = require('vn-loopback/server/server').models;
|
||||||
const LoopBackContext = require('loopback-context');
|
const LoopBackContext = require('loopback-context');
|
||||||
|
|
||||||
describe('loopback model Supplier-account', () => {
|
describe('loopback model Supplier-account', () => {
|
||||||
describe('create', () => {
|
describe('create', () => {
|
||||||
const supplierId = 1;
|
const supplierId = 1;
|
||||||
const bankEntityId = 2100;
|
const bankEntityId = 2100;
|
||||||
|
const activeCtx = {
|
||||||
|
accessToken: {userId: 5},
|
||||||
|
http: {
|
||||||
|
req: {
|
||||||
|
headers: {origin: 'http://localhost'}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
activeCtx.http.req.__ = value => {
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
it('should throw an error when attempting to set an invalid iban account', async() => {
|
it('should throw an error when attempting to set an invalid iban account', async() => {
|
||||||
let error;
|
let error;
|
||||||
const expectedError = 'The IBAN does not have the correct format';
|
const expectedError = 'The IBAN does not have the correct format';
|
||||||
const iban = 'incorrect format';
|
const iban = 'incorrect format';
|
||||||
try {
|
try {
|
||||||
await app.models.SupplierAccount.create(
|
await models.SupplierAccount.create(
|
||||||
{
|
{
|
||||||
supplierFk: supplierId,
|
supplierFk: supplierId,
|
||||||
bankEntityFk: bankEntityId,
|
bankEntityFk: bankEntityId,
|
||||||
|
@ -26,27 +38,16 @@ describe('loopback model Supplier-account', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create a valid supplier account', async() => {
|
it('should create a valid supplier account', async() => {
|
||||||
const tx = await app.models.Claim.beginTransaction({});
|
const tx = await models.SupplierAccount.beginTransaction({});
|
||||||
try {
|
try {
|
||||||
const options = {transaction: tx};
|
const options = {transaction: tx};
|
||||||
const iban = 'ES91 2100 0418 4502 0005 1332';
|
const iban = 'ES91 2100 0418 4502 0005 1332';
|
||||||
|
|
||||||
const activeCtx = {
|
|
||||||
accessToken: {userId: 5},
|
|
||||||
http: {
|
|
||||||
req: {
|
|
||||||
headers: {origin: 'http://localhost'}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
activeCtx.http.req.__ = value => {
|
|
||||||
return value;
|
|
||||||
};
|
|
||||||
|
|
||||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||||
active: activeCtx
|
active: activeCtx
|
||||||
});
|
});
|
||||||
const createdSupplierAccount = await app.models.SupplierAccount.create({
|
|
||||||
|
const createdSupplierAccount = await models.SupplierAccount.create({
|
||||||
supplierFk: supplierId,
|
supplierFk: supplierId,
|
||||||
bankEntityFk: bankEntityId,
|
bankEntityFk: bankEntityId,
|
||||||
iban: iban
|
iban: iban
|
||||||
|
@ -60,5 +61,35 @@ describe('loopback model Supplier-account', () => {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should change isPayMethodChecked to false', async() => {
|
||||||
|
const tx = await models.SupplierAccount.beginTransaction({});
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
const iban = 'ES91 2100 0418 4502 0005 1332';
|
||||||
|
|
||||||
|
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||||
|
active: activeCtx
|
||||||
|
});
|
||||||
|
|
||||||
|
const supplierBefore = await models.Supplier.findById(supplierId, null, options);
|
||||||
|
|
||||||
|
await models.SupplierAccount.create({
|
||||||
|
supplierFk: supplierId,
|
||||||
|
bankEntityFk: bankEntityId,
|
||||||
|
iban: iban
|
||||||
|
},
|
||||||
|
options);
|
||||||
|
|
||||||
|
const supplierAfter = await models.Supplier.findById(supplierId, null, options);
|
||||||
|
|
||||||
|
expect(supplierBefore.isPayMethodChecked).toBeTruthy();
|
||||||
|
expect(supplierAfter.isPayMethodChecked).toBeFalsy();
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -34,4 +34,15 @@ module.exports = Self => {
|
||||||
ctx.instance.iban + ', entidad: ' + bankEntity.name + ', bic: ' + bankEntity.bic
|
ctx.instance.iban + ', entidad: ' + bankEntity.name + ', bic: ' + bankEntity.bic
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Self.observe('after save', async ctx => {
|
||||||
|
const options = {};
|
||||||
|
|
||||||
|
if (ctx.options && ctx.options.transaction)
|
||||||
|
options.transaction = ctx.options.transaction;
|
||||||
|
const supplier = await Self.app.models.Supplier.findById(ctx.instance.supplierFk, null, options);
|
||||||
|
|
||||||
|
if (supplier.isPayMethodChecked)
|
||||||
|
await supplier.updateAttribute('isPayMethodChecked', false, options);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -45,6 +45,16 @@ class Controller extends Section {
|
||||||
this.$.payMethodToTransfer.show();
|
this.$.payMethodToTransfer.show();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setWireTransfer() {
|
||||||
|
const params = {
|
||||||
|
id: this.$params.id,
|
||||||
|
payMethodFk: this.wireTransferFk
|
||||||
|
};
|
||||||
|
const query = `Suppliers/${this.$params.id}`;
|
||||||
|
return this.$http.patch(query, params)
|
||||||
|
.then(() => this.$.watcher.notifySaved());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ngModule.vnComponent('vnSupplierAccount', {
|
ngModule.vnComponent('vnSupplierAccount', {
|
||||||
|
|
|
@ -5,9 +5,12 @@ import crudModel from 'core/mocks/crud-model';
|
||||||
describe('Supplier Component vnSupplierAccount', () => {
|
describe('Supplier Component vnSupplierAccount', () => {
|
||||||
let $scope;
|
let $scope;
|
||||||
let controller;
|
let controller;
|
||||||
|
let $httpBackend;
|
||||||
|
|
||||||
beforeEach(ngModule('supplier'));
|
beforeEach(ngModule('supplier'));
|
||||||
|
|
||||||
beforeEach(inject(($componentController, $rootScope, _$httpBackend_) => {
|
beforeEach(inject(($componentController, $rootScope, _$httpBackend_) => {
|
||||||
|
$httpBackend = _$httpBackend_;
|
||||||
$scope = $rootScope.$new();
|
$scope = $rootScope.$new();
|
||||||
$scope.model = crudModel;
|
$scope.model = crudModel;
|
||||||
$scope.watcher = watcher;
|
$scope.watcher = watcher;
|
||||||
|
@ -66,5 +69,30 @@ describe('Supplier Component vnSupplierAccount', () => {
|
||||||
}).catch(done.fail);
|
}).catch(done.fail);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('setWireTransfer()', () => {
|
||||||
|
it(`should make HTTP PATCH request to set wire transfer and call notifySaved`, () => {
|
||||||
|
const supplierId = 1;
|
||||||
|
const params = {
|
||||||
|
id: supplierId,
|
||||||
|
payMethodFk: 2
|
||||||
|
};
|
||||||
|
const response = {
|
||||||
|
data: {id: 2}
|
||||||
|
};
|
||||||
|
const uri = 'payMethods/findOne?filter=%7B%22where%22:%7B%22code%22:%22wireTransfer%22%7D%7D';
|
||||||
|
jest.spyOn($scope.watcher, 'notifySaved');
|
||||||
|
|
||||||
|
controller.$params.id = supplierId;
|
||||||
|
controller.wireTransferFk = 2;
|
||||||
|
controller.supplier = {payMethodFk: 1};
|
||||||
|
$httpBackend.expectGET(uri).respond(response);
|
||||||
|
$httpBackend.expectPATCH(`Suppliers/${supplierId}`, params).respond();
|
||||||
|
controller.setWireTransfer();
|
||||||
|
$httpBackend.flush();
|
||||||
|
|
||||||
|
expect($scope.watcher.notifySaved).toHaveBeenCalledWith();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,6 @@ module.exports = Self => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const salesIds = [];
|
const salesIds = [];
|
||||||
const params = [];
|
|
||||||
const userId = ctx.req.accessToken.userId;
|
const userId = ctx.req.accessToken.userId;
|
||||||
|
|
||||||
const isClaimManager = await Self.app.models.Account.hasRole(userId, 'claimManager');
|
const isClaimManager = await Self.app.models.Account.hasRole(userId, 'claimManager');
|
||||||
|
@ -50,23 +49,19 @@ module.exports = Self => {
|
||||||
if (!hasValidRole)
|
if (!hasValidRole)
|
||||||
throw new UserError(`You don't have privileges to create pay back`);
|
throw new UserError(`You don't have privileges to create pay back`);
|
||||||
|
|
||||||
sales.forEach(sale => {
|
for (let sale of sales)
|
||||||
salesIds.push(sale.id);
|
salesIds.push(sale.id);
|
||||||
params.push('?');
|
|
||||||
});
|
|
||||||
|
|
||||||
const paramsString = params.join();
|
|
||||||
|
|
||||||
const query = `
|
const query = `
|
||||||
DROP TEMPORARY TABLE IF EXISTS tmp.sale;
|
DROP TEMPORARY TABLE IF EXISTS tmp.sale;
|
||||||
CREATE TEMPORARY TABLE tmp.sale
|
CREATE TEMPORARY TABLE tmp.sale
|
||||||
SELECT s.id, s.itemFk, - s.quantity, s.concept, s.price, s.discount
|
SELECT s.id, s.itemFk, - s.quantity, s.concept, s.price, s.discount
|
||||||
FROM sale s
|
FROM sale s
|
||||||
WHERE s.id IN (${paramsString});
|
WHERE s.id IN (?);
|
||||||
CALL vn.ticket_doRefund(${ticketId}, @newTicket);
|
CALL vn.ticket_doRefund(?, @newTicket);
|
||||||
DROP TEMPORARY TABLE tmp.sale;`;
|
DROP TEMPORARY TABLE tmp.sale;`;
|
||||||
|
|
||||||
await Self.rawSql(query, salesIds, myOptions);
|
await Self.rawSql(query, [salesIds, ticketId], myOptions);
|
||||||
const [newTicket] = await Self.rawSql('SELECT @newTicket id', null, myOptions);
|
const [newTicket] = await Self.rawSql('SELECT @newTicket id', null, myOptions);
|
||||||
ticketId = newTicket.id;
|
ticketId = newTicket.id;
|
||||||
|
|
||||||
|
|
|
@ -35,11 +35,8 @@ module.exports = Self => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const salesIds = [];
|
const salesIds = [];
|
||||||
const params = [];
|
for (let sale of sales)
|
||||||
sales.forEach(sale => {
|
|
||||||
salesIds.push(sale.id);
|
salesIds.push(sale.id);
|
||||||
params.push('?');
|
|
||||||
});
|
|
||||||
|
|
||||||
const isEditable = await models.Ticket.isEditable(ctx, sales[0].ticketFk, myOptions);
|
const isEditable = await models.Ticket.isEditable(ctx, sales[0].ticketFk, myOptions);
|
||||||
if (!isEditable)
|
if (!isEditable)
|
||||||
|
@ -49,14 +46,12 @@ module.exports = Self => {
|
||||||
if (!canEditSale)
|
if (!canEditSale)
|
||||||
throw new UserError(`Sale(s) blocked, please contact production`);
|
throw new UserError(`Sale(s) blocked, please contact production`);
|
||||||
|
|
||||||
const paramsString = params.join();
|
|
||||||
|
|
||||||
const query = `
|
const query = `
|
||||||
DROP TEMPORARY TABLE IF EXISTS tmp.recalculateSales;
|
DROP TEMPORARY TABLE IF EXISTS tmp.recalculateSales;
|
||||||
CREATE TEMPORARY TABLE tmp.recalculateSales
|
CREATE TEMPORARY TABLE tmp.recalculateSales
|
||||||
SELECT s.id
|
SELECT s.id
|
||||||
FROM sale s
|
FROM sale s
|
||||||
WHERE s.id IN (${paramsString});
|
WHERE s.id IN (?);
|
||||||
CALL vn.sale_recalcComponent(null);
|
CALL vn.sale_recalcComponent(null);
|
||||||
DROP TEMPORARY TABLE tmp.recalculateSales;`;
|
DROP TEMPORARY TABLE tmp.recalculateSales;`;
|
||||||
|
|
||||||
|
|
|
@ -86,8 +86,8 @@ describe('sale priceDifference()', () => {
|
||||||
const firstItem = result.items[0];
|
const firstItem = result.items[0];
|
||||||
const secondtItem = result.items[1];
|
const secondtItem = result.items[1];
|
||||||
|
|
||||||
expect(firstItem.movable).toEqual(440);
|
expect(firstItem.movable).toEqual(410);
|
||||||
expect(secondtItem.movable).toEqual(1980);
|
expect(secondtItem.movable).toEqual(1870);
|
||||||
|
|
||||||
await tx.rollback();
|
await tx.rollback();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
const models = require('vn-loopback/server/server').models;
|
const models = require('vn-loopback/server/server').models;
|
||||||
const soap = require('soap');
|
const soap = require('soap');
|
||||||
|
|
||||||
describe('ticket sendSms()', () => {
|
// #3673 sendSms tests excluded
|
||||||
|
xdescribe('ticket sendSms()', () => {
|
||||||
it('should send a message and log it', async() => {
|
it('should send a message and log it', async() => {
|
||||||
const tx = await models.Ticket.beginTransaction({});
|
const tx = await models.Ticket.beginTransaction({});
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,14 @@
|
||||||
</vn-thead>
|
</vn-thead>
|
||||||
<vn-tbody>
|
<vn-tbody>
|
||||||
<vn-tr ng-repeat="sale in $ctrl.ticket.sale.items track by sale.id">
|
<vn-tr ng-repeat="sale in $ctrl.ticket.sale.items track by sale.id">
|
||||||
<vn-td number>{{("000000"+sale.itemFk).slice(-6)}}</vn-td>
|
<vn-td number>
|
||||||
|
<span
|
||||||
|
title="{{::sale.item.name}}"
|
||||||
|
vn-click-stop="itemDescriptor.show($event, sale.itemFk, sale.id)"
|
||||||
|
class="link">
|
||||||
|
{{::sale.itemFk | zeroFill:6}}
|
||||||
|
</span>
|
||||||
|
</vn-td>
|
||||||
<vn-td vn-fetched-tags>
|
<vn-td vn-fetched-tags>
|
||||||
<div>
|
<div>
|
||||||
<vn-one title="{{::sale.item.name}}">{{::sale.item.name}}</vn-one>
|
<vn-one title="{{::sale.item.name}}">{{::sale.item.name}}</vn-one>
|
||||||
|
@ -83,5 +90,9 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</vn-side-menu>
|
</vn-side-menu>
|
||||||
|
<vn-item-descriptor-popover
|
||||||
|
vn-id="item-descriptor"
|
||||||
|
warehouse-fk="$ctrl.ticket.warehouseFk"
|
||||||
|
ticket-fk="$ctrl.ticket.id">
|
||||||
|
</vn-item-descriptor-popover>
|
||||||
|
|
||||||
|
|
|
@ -20,14 +20,22 @@
|
||||||
<vn-menu vn-id="showDeliveryNoteMenu">
|
<vn-menu vn-id="showDeliveryNoteMenu">
|
||||||
<vn-list>
|
<vn-list>
|
||||||
<vn-item
|
<vn-item
|
||||||
|
ng-if="!$ctrl.hasDocuwareFile"
|
||||||
ng-click="$ctrl.showPdfDeliveryNote()"
|
ng-click="$ctrl.showPdfDeliveryNote()"
|
||||||
translate>
|
translate>
|
||||||
Show as PDF
|
as PDF
|
||||||
</vn-item>
|
</vn-item>
|
||||||
|
<a class="vn-item"
|
||||||
|
ng-if="$ctrl.hasDocuwareFile"
|
||||||
|
href='api/Docuwares/{{$ctrl.ticket.id}}/download/deliveryClient/findTicket?access_token={{$ctrl.vnToken.token}}'
|
||||||
|
target="_blank"
|
||||||
|
translate>
|
||||||
|
as PDF
|
||||||
|
</a>
|
||||||
<vn-item
|
<vn-item
|
||||||
ng-click="$ctrl.showCsvDeliveryNote()"
|
ng-click="$ctrl.showCsvDeliveryNote()"
|
||||||
translate>
|
translate>
|
||||||
Show as CSV
|
as CSV
|
||||||
</vn-item>
|
</vn-item>
|
||||||
</vn-list>
|
</vn-list>
|
||||||
</vn-menu>
|
</vn-menu>
|
||||||
|
|
|
@ -84,6 +84,7 @@ class Controller extends Section {
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.canStowaway();
|
this.canStowaway();
|
||||||
this.isTicketEditable();
|
this.isTicketEditable();
|
||||||
|
this.hasDocuware();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,6 +123,15 @@ class Controller extends Section {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hasDocuware() {
|
||||||
|
const params = {
|
||||||
|
fileCabinet: 'deliveryClient',
|
||||||
|
dialog: 'findTicket'
|
||||||
|
};
|
||||||
|
this.$http.post(`Docuwares/${this.id}/checkFile`, params)
|
||||||
|
.then(res => this.hasDocuwareFile = res.data);
|
||||||
|
}
|
||||||
|
|
||||||
showCsvDeliveryNote() {
|
showCsvDeliveryNote() {
|
||||||
this.vnReport.showCsv('delivery-note', {
|
this.vnReport.showCsv('delivery-note', {
|
||||||
recipientId: this.ticket.client.id,
|
recipientId: this.ticket.client.id,
|
||||||
|
|
|
@ -206,7 +206,8 @@ describe('Ticket Component vnTicketDescriptorMenu', () => {
|
||||||
it('should make a query and show a success snackbar', () => {
|
it('should make a query and show a success snackbar', () => {
|
||||||
jest.spyOn(controller.vnApp, 'showSuccess');
|
jest.spyOn(controller.vnApp, 'showSuccess');
|
||||||
|
|
||||||
$httpBackend.whenGET(`Tickets/16`).respond();
|
$httpBackend.whenPOST(`Docuwares/${ticket.id}/checkFile`).respond();
|
||||||
|
$httpBackend.whenGET(`Tickets/${ticket.id}`).respond();
|
||||||
$httpBackend.expectPOST(`InvoiceOuts/${ticket.invoiceOut.id}/createPdf`).respond();
|
$httpBackend.expectPOST(`InvoiceOuts/${ticket.invoiceOut.id}/createPdf`).respond();
|
||||||
controller.createPdfInvoice();
|
controller.createPdfInvoice();
|
||||||
$httpBackend.flush();
|
$httpBackend.flush();
|
||||||
|
@ -275,4 +276,12 @@ describe('Ticket Component vnTicketDescriptorMenu', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('hasDocuware()', () => {
|
||||||
|
it('should call hasDocuware method', () => {
|
||||||
|
$httpBackend.whenPOST(`Docuwares/${ticket.id}/checkFile`).respond();
|
||||||
|
controller.hasDocuware();
|
||||||
|
$httpBackend.flush();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
Show Delivery Note...: Ver albarán...
|
Show Delivery Note...: Ver albarán...
|
||||||
Send Delivery Note...: Enviar albarán...
|
Send Delivery Note...: Enviar albarán...
|
||||||
Show as PDF: Ver como PDF
|
as PDF: como PDF
|
||||||
Show as CSV: Ver como CSV
|
as CSV: como CSV
|
||||||
Send PDF: Enviar PDF
|
Send PDF: Enviar PDF
|
||||||
Send CSV: Enviar CSV
|
Send CSV: Enviar CSV
|
||||||
Send CSV Delivery Note: Enviar albarán en CSV
|
Send CSV Delivery Note: Enviar albarán en CSV
|
||||||
|
|
|
@ -4,14 +4,24 @@ module.exports = Self => {
|
||||||
Self.remoteMethodCtx('absences', {
|
Self.remoteMethodCtx('absences', {
|
||||||
description: 'Returns an array of absences from an specified contract',
|
description: 'Returns an array of absences from an specified contract',
|
||||||
accepts: [{
|
accepts: [{
|
||||||
arg: 'businessFk',
|
arg: 'workerFk',
|
||||||
type: 'number',
|
type: 'number',
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
arg: 'businessFk',
|
||||||
|
type: 'number',
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
arg: 'year',
|
arg: 'year',
|
||||||
type: 'date',
|
type: 'date',
|
||||||
required: true,
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'all',
|
||||||
|
type: 'boolean',
|
||||||
|
required: false,
|
||||||
}],
|
}],
|
||||||
returns: [{
|
returns: [{
|
||||||
arg: 'absences',
|
arg: 'absences',
|
||||||
|
@ -27,7 +37,7 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Self.absences = async(ctx, businessFk, year, options) => {
|
Self.absences = async(ctx, workerFk, businessFk, year, options) => {
|
||||||
const models = Self.app.models;
|
const models = Self.app.models;
|
||||||
|
|
||||||
const started = new Date();
|
const started = new Date();
|
||||||
|
@ -45,7 +55,17 @@ module.exports = Self => {
|
||||||
if (typeof options == 'object')
|
if (typeof options == 'object')
|
||||||
Object.assign(myOptions, options);
|
Object.assign(myOptions, options);
|
||||||
|
|
||||||
const contract = await models.WorkerLabour.findOne({
|
let condition = {
|
||||||
|
and: [
|
||||||
|
{workerFk: workerFk},
|
||||||
|
{businessFk: businessFk}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
if (businessFk)
|
||||||
|
condition.and.push({workerFk: workerFk});
|
||||||
|
|
||||||
|
const contracts = await models.WorkerLabour.find({
|
||||||
include: [{
|
include: [{
|
||||||
relation: 'holidays',
|
relation: 'holidays',
|
||||||
scope: {
|
scope: {
|
||||||
|
@ -82,31 +102,32 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}],
|
}],
|
||||||
where: {businessFk}
|
where: condition
|
||||||
}, myOptions);
|
}, myOptions);
|
||||||
|
|
||||||
if (!contract) return;
|
if (!contracts) return;
|
||||||
|
|
||||||
const isSubordinate = await models.Worker.isSubordinate(ctx, contract.workerFk, myOptions);
|
const isSubordinate = await models.Worker.isSubordinate(ctx, workerFk, myOptions);
|
||||||
if (!isSubordinate)
|
if (!isSubordinate)
|
||||||
throw new UserError(`You don't have enough privileges`);
|
throw new UserError(`You don't have enough privileges`);
|
||||||
|
|
||||||
const absences = [];
|
const absences = [];
|
||||||
for (let absence of contract.absences()) {
|
|
||||||
absence.dated = new Date(absence.dated);
|
|
||||||
absence.dated.setHours(0, 0, 0, 0);
|
|
||||||
|
|
||||||
absences.push(absence);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Workcenter holidays
|
|
||||||
const holidays = [];
|
const holidays = [];
|
||||||
const holidayList = contract.workCenter().holidays();
|
|
||||||
for (let day of holidayList) {
|
|
||||||
day.dated = new Date(day.dated);
|
|
||||||
day.dated.setHours(0, 0, 0, 0);
|
|
||||||
|
|
||||||
holidays.push(day);
|
for (let contract of contracts) {
|
||||||
|
for (let absence of contract.absences()) {
|
||||||
|
absence.dated = new Date(absence.dated);
|
||||||
|
absence.dated.setHours(0, 0, 0, 0);
|
||||||
|
|
||||||
|
absences.push(absence);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let day of contract.workCenter().holidays()) {
|
||||||
|
day.dated = new Date(day.dated);
|
||||||
|
day.dated.setHours(0, 0, 0, 0);
|
||||||
|
|
||||||
|
holidays.push(day);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return [absences, holidays];
|
return [absences, holidays];
|
||||||
|
|
|
@ -3,12 +3,13 @@ const app = require('vn-loopback/server/server');
|
||||||
describe('Worker absences()', () => {
|
describe('Worker absences()', () => {
|
||||||
it('should get the absence calendar for a full year contract', async() => {
|
it('should get the absence calendar for a full year contract', async() => {
|
||||||
const ctx = {req: {accessToken: {userId: 1106}}};
|
const ctx = {req: {accessToken: {userId: 1106}}};
|
||||||
|
const workerId = 1106;
|
||||||
const businessId = 1106;
|
const businessId = 1106;
|
||||||
|
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const year = now.getFullYear();
|
const year = now.getFullYear();
|
||||||
|
|
||||||
const [absences] = await app.models.Calendar.absences(ctx, businessId, year);
|
const [absences] = await app.models.Calendar.absences(ctx, workerId, businessId, year);
|
||||||
|
|
||||||
const firstType = absences[0].absenceType().name;
|
const firstType = absences[0].absenceType().name;
|
||||||
const sixthType = absences[5].absenceType().name;
|
const sixthType = absences[5].absenceType().name;
|
||||||
|
@ -35,7 +36,7 @@ describe('Worker absences()', () => {
|
||||||
`UPDATE postgresql.business SET date_end = ? WHERE business_id = ?`,
|
`UPDATE postgresql.business SET date_end = ? WHERE business_id = ?`,
|
||||||
[null, worker.businessFk], options);
|
[null, worker.businessFk], options);
|
||||||
|
|
||||||
const [absences] = await app.models.Calendar.absences(ctx, businessId, year, options);
|
const [absences] = await app.models.Calendar.absences(ctx, worker.id, businessId, year, options);
|
||||||
|
|
||||||
let firstType = absences[0].absenceType().name;
|
let firstType = absences[0].absenceType().name;
|
||||||
let sixthType = absences[5].absenceType().name;
|
let sixthType = absences[5].absenceType().name;
|
||||||
|
@ -51,6 +52,8 @@ describe('Worker absences()', () => {
|
||||||
|
|
||||||
it('should give the same holidays as worked days since the holidays amount matches the amount of days in a year', async() => {
|
it('should give the same holidays as worked days since the holidays amount matches the amount of days in a year', async() => {
|
||||||
const businessId = 1106;
|
const businessId = 1106;
|
||||||
|
const workerId = 1106;
|
||||||
|
|
||||||
const userId = 1106;
|
const userId = 1106;
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
|
|
||||||
|
@ -101,7 +104,7 @@ describe('Worker absences()', () => {
|
||||||
|
|
||||||
const ctx = {req: {accessToken: {userId: userId}}};
|
const ctx = {req: {accessToken: {userId: userId}}};
|
||||||
|
|
||||||
const [absences] = await app.models.Calendar.absences(ctx, businessId, currentYear);
|
const [absences] = await app.models.Calendar.absences(ctx, workerId, businessId, currentYear);
|
||||||
|
|
||||||
const firstType = absences[0].absenceType().name;
|
const firstType = absences[0].absenceType().name;
|
||||||
const sixthType = absences[5].absenceType().name;
|
const sixthType = absences[5].absenceType().name;
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue