Merge branch 'test' of https://gitea.verdnatura.es/verdnatura/salix
gitea/salix/pipeline/head Something is wrong with the build of this commit
Details
gitea/salix/pipeline/head Something is wrong with the build of this commit
Details
This commit is contained in:
commit
bbae986424
|
@ -5,17 +5,17 @@ module.exports = Self => {
|
||||||
accepts: [
|
accepts: [
|
||||||
{
|
{
|
||||||
arg: 'id',
|
arg: 'id',
|
||||||
type: 'Number',
|
type: 'number',
|
||||||
description: 'The user id',
|
description: 'The user id',
|
||||||
http: {source: 'path'}
|
http: {source: 'path'}
|
||||||
}, {
|
}, {
|
||||||
arg: 'oldPassword',
|
arg: 'oldPassword',
|
||||||
type: 'String',
|
type: 'string',
|
||||||
description: 'The old password',
|
description: 'The old password',
|
||||||
required: true
|
required: true
|
||||||
}, {
|
}, {
|
||||||
arg: 'newPassword',
|
arg: 'newPassword',
|
||||||
type: 'String',
|
type: 'string',
|
||||||
description: 'The new password',
|
description: 'The new password',
|
||||||
required: true
|
required: true
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
const axios = require('axios');
|
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
Self.remoteMethodCtx('send', {
|
Self.remoteMethodCtx('send', {
|
||||||
description: 'Send a RocketChat message',
|
description: 'Creates a direct message in the chat model for a user or a channel',
|
||||||
accessType: 'WRITE',
|
accessType: 'WRITE',
|
||||||
accepts: [{
|
accepts: [{
|
||||||
arg: 'to',
|
arg: 'to',
|
||||||
|
@ -31,39 +30,19 @@ module.exports = Self => {
|
||||||
const recipient = to.replace('@', '');
|
const recipient = to.replace('@', '');
|
||||||
|
|
||||||
if (sender.name != recipient) {
|
if (sender.name != recipient) {
|
||||||
await sendMessage(sender, to, message);
|
await models.Chat.create({
|
||||||
|
senderFk: sender.id,
|
||||||
|
recipient: to,
|
||||||
|
dated: new Date(),
|
||||||
|
checkUserStatus: 0,
|
||||||
|
message: message,
|
||||||
|
status: 0,
|
||||||
|
attempts: 0
|
||||||
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
async function sendMessage(sender, channel, message) {
|
|
||||||
if (process.env.NODE_ENV !== 'production') {
|
|
||||||
return new Promise(resolve => {
|
|
||||||
return resolve({
|
|
||||||
statusCode: 200,
|
|
||||||
message: 'Fake notification sent'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const login = await Self.getServiceAuth();
|
|
||||||
const avatar = `${login.host}/avatar/${sender.name}`;
|
|
||||||
|
|
||||||
const options = {
|
|
||||||
headers: {
|
|
||||||
'X-Auth-Token': login.auth.token,
|
|
||||||
'X-User-Id': login.auth.userId
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
return axios.post(`${login.api}/chat.postMessage`, {
|
|
||||||
'channel': channel,
|
|
||||||
'avatar': avatar,
|
|
||||||
'alias': sender.nickname,
|
|
||||||
'text': message
|
|
||||||
}, options);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
const axios = require('axios');
|
|
||||||
|
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
Self.remoteMethodCtx('sendCheckingPresence', {
|
Self.remoteMethodCtx('sendCheckingPresence', {
|
||||||
description: 'Sends a RocketChat message to a connected user or department channel',
|
description: 'Creates a message in the chat model checking the user status',
|
||||||
accessType: 'WRITE',
|
accessType: 'WRITE',
|
||||||
accepts: [{
|
accepts: [{
|
||||||
arg: 'workerId',
|
arg: 'workerId',
|
||||||
|
@ -36,6 +34,7 @@ module.exports = Self => {
|
||||||
|
|
||||||
const models = Self.app.models;
|
const models = Self.app.models;
|
||||||
const userId = ctx.req.accessToken.userId;
|
const userId = ctx.req.accessToken.userId;
|
||||||
|
const sender = await models.Account.findById(userId);
|
||||||
const recipient = await models.Account.findById(recipientId, null, myOptions);
|
const recipient = await models.Account.findById(recipientId, null, myOptions);
|
||||||
|
|
||||||
// Prevent sending messages to yourself
|
// Prevent sending messages to yourself
|
||||||
|
@ -44,54 +43,16 @@ module.exports = Self => {
|
||||||
if (!recipient)
|
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 {data} = await Self.getUserStatus(recipient.name);
|
await models.Chat.create({
|
||||||
if (data) {
|
senderFk: sender.id,
|
||||||
if (data.status === 'offline' || data.status === 'busy') {
|
recipient: `@${recipient.name}`,
|
||||||
// Send message to department room
|
dated: new Date(),
|
||||||
const workerDepartment = await models.WorkerDepartment.findById(recipientId, {
|
checkUserStatus: 1,
|
||||||
include: {
|
message: message,
|
||||||
relation: 'department'
|
status: 0,
|
||||||
}
|
attempts: 0
|
||||||
}, myOptions);
|
});
|
||||||
const department = workerDepartment && workerDepartment.department();
|
|
||||||
const channelName = department && department.chatName;
|
|
||||||
|
|
||||||
if (channelName)
|
return true;
|
||||||
return Self.send(ctx, `#${channelName}`, `@${recipient.name} ➔ ${message}`);
|
|
||||||
else
|
|
||||||
return Self.send(ctx, `@${recipient.name}`, message);
|
|
||||||
} else
|
|
||||||
return Self.send(ctx, `@${recipient.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'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,168 @@
|
||||||
|
const axios = require('axios');
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethodCtx('sendQueued', {
|
||||||
|
description: 'Send a RocketChat message',
|
||||||
|
accessType: 'WRITE',
|
||||||
|
accepts: [],
|
||||||
|
returns: {
|
||||||
|
type: 'object',
|
||||||
|
root: true
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
path: `/sendQueued`,
|
||||||
|
verb: 'POST'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.sendQueued = async() => {
|
||||||
|
const models = Self.app.models;
|
||||||
|
const maxAttempts = 3;
|
||||||
|
const sentStatus = 1;
|
||||||
|
const errorStatus = 2;
|
||||||
|
|
||||||
|
const chats = await models.Chat.find({
|
||||||
|
where: {
|
||||||
|
status: {neq: sentStatus},
|
||||||
|
attempts: {lt: maxAttempts}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for (let chat of chats) {
|
||||||
|
if (chat.checkUserStatus) {
|
||||||
|
try {
|
||||||
|
await Self.sendCheckingUserStatus(chat);
|
||||||
|
await updateChat(chat, sentStatus);
|
||||||
|
} catch (error) {
|
||||||
|
await updateChat(chat, errorStatus);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
await Self.sendMessage(chat.senderFk, chat.recipient, chat.message);
|
||||||
|
await updateChat(chat, sentStatus);
|
||||||
|
} catch (error) {
|
||||||
|
await updateChat(chat, errorStatus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check user status in Rocket
|
||||||
|
*
|
||||||
|
* @param {object} chat - The sender id
|
||||||
|
* @return {Promise} - The request promise
|
||||||
|
*/
|
||||||
|
Self.sendCheckingUserStatus = async function sendCheckingUserStatus(chat) {
|
||||||
|
const models = Self.app.models;
|
||||||
|
|
||||||
|
const recipientName = chat.recipient.slice(1);
|
||||||
|
const recipient = await models.Account.findOne({
|
||||||
|
where: {
|
||||||
|
name: recipientName
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const {data} = await Self.getUserStatus(recipient.name);
|
||||||
|
if (data) {
|
||||||
|
if (data.status === 'offline' || data.status === 'busy') {
|
||||||
|
// Send message to department room
|
||||||
|
const workerDepartment = await models.WorkerDepartment.findById(recipient.id, {
|
||||||
|
include: {
|
||||||
|
relation: 'department'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const department = workerDepartment && workerDepartment.department();
|
||||||
|
const channelName = department && department.chatName;
|
||||||
|
|
||||||
|
if (channelName)
|
||||||
|
return Self.sendMessage(chat.senderFk, `#${channelName}`, `@${recipient.name} ➔ ${message}`);
|
||||||
|
else
|
||||||
|
return Self.sendMessage(chat.senderFk, `@${recipient.name}`, chat.message);
|
||||||
|
} else
|
||||||
|
return Self.sendMessage(chat.senderFk, `@${recipient.name}`, chat.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a rocket message
|
||||||
|
*
|
||||||
|
* @param {object} senderFk - The sender id
|
||||||
|
* @param {string} recipient - The user (@) or channel (#) to send the message
|
||||||
|
* @param {string} message - The message to send
|
||||||
|
* @return {Promise} - The request promise
|
||||||
|
*/
|
||||||
|
Self.sendMessage = async function sendMessage(senderFk, recipient, message) {
|
||||||
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
return resolve({
|
||||||
|
statusCode: 200,
|
||||||
|
message: 'Fake notification sent'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const models = Self.app.models;
|
||||||
|
const sender = await models.Account.findById(senderFk);
|
||||||
|
|
||||||
|
const login = await Self.getServiceAuth();
|
||||||
|
const avatar = `${login.host}/avatar/${sender.name}`;
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
headers: {
|
||||||
|
'X-Auth-Token': login.auth.token,
|
||||||
|
'X-User-Id': login.auth.userId
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return axios.post(`${login.api}/chat.postMessage`, {
|
||||||
|
'channel': recipient,
|
||||||
|
'avatar': avatar,
|
||||||
|
'alias': sender.nickname,
|
||||||
|
'text': message
|
||||||
|
}, options);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update status and attempts of a chat
|
||||||
|
*
|
||||||
|
* @param {object} chat - The chat
|
||||||
|
* @param {string} status - The new status
|
||||||
|
* @return {Promise} - The request promise
|
||||||
|
*/
|
||||||
|
async function updateChat(chat, status) {
|
||||||
|
return chat.updateAttributes({
|
||||||
|
status: status,
|
||||||
|
attempts: ++chat.attempts
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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,14 +1,14 @@
|
||||||
const app = require('vn-loopback/server/server');
|
const app = require('vn-loopback/server/server');
|
||||||
|
|
||||||
describe('Chat send()', () => {
|
describe('Chat send()', () => {
|
||||||
it('should return a "Fake notification sent" as response', async() => {
|
it('should return true as response', async() => {
|
||||||
let ctx = {req: {accessToken: {userId: 1}}};
|
let ctx = {req: {accessToken: {userId: 1}}};
|
||||||
let response = await app.models.Chat.send(ctx, '@salesPerson', 'I changed something');
|
let response = await app.models.Chat.send(ctx, '@salesPerson', 'I changed something');
|
||||||
|
|
||||||
expect(response).toEqual(true);
|
expect(response).toEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should retrun false as response', async() => {
|
it('should return false as response', async() => {
|
||||||
let ctx = {req: {accessToken: {userId: 18}}};
|
let ctx = {req: {accessToken: {userId: 18}}};
|
||||||
let response = await app.models.Chat.send(ctx, '@salesPerson', 'I changed something');
|
let response = await app.models.Chat.send(ctx, '@salesPerson', 'I changed something');
|
||||||
|
|
||||||
|
|
|
@ -1,58 +1,21 @@
|
||||||
const models = require('vn-loopback/server/server').models;
|
const models = require('vn-loopback/server/server').models;
|
||||||
|
|
||||||
describe('Chat sendCheckingPresence()', () => {
|
describe('Chat sendCheckingPresence()', () => {
|
||||||
const today = new Date();
|
it('should return true as response', async() => {
|
||||||
today.setHours(6, 0);
|
const workerId = 1107;
|
||||||
const ctx = {req: {accessToken: {userId: 1}}};
|
|
||||||
const chatModel = models.Chat;
|
|
||||||
const departmentId = 23;
|
|
||||||
const workerId = 1107;
|
|
||||||
|
|
||||||
it(`should call to send() method with "@HankPym" as recipient argument`, async() => {
|
let ctx = {req: {accessToken: {userId: 1}}};
|
||||||
spyOn(chatModel, 'send').and.callThrough();
|
let response = await models.Chat.sendCheckingPresence(ctx, workerId, 'I changed something');
|
||||||
spyOn(chatModel, 'getUserStatus').and.returnValue(
|
|
||||||
new Promise(resolve => {
|
|
||||||
return resolve({
|
|
||||||
data: {
|
|
||||||
status: 'online'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
await chatModel.sendCheckingPresence(ctx, workerId, 'I changed something');
|
expect(response).toEqual(true);
|
||||||
|
|
||||||
expect(chatModel.send).toHaveBeenCalledWith(ctx, '@HankPym', 'I changed something');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should call to send() method with "#cooler" as recipient argument`, async() => {
|
it('should return false as response', async() => {
|
||||||
spyOn(chatModel, 'send').and.callThrough();
|
const salesPersonId = 18;
|
||||||
spyOn(chatModel, 'getUserStatus').and.returnValue(
|
|
||||||
new Promise(resolve => {
|
|
||||||
return resolve({
|
|
||||||
data: {
|
|
||||||
status: 'offline'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
const tx = await models.Claim.beginTransaction({});
|
let ctx = {req: {accessToken: {userId: 18}}};
|
||||||
|
let response = await models.Chat.sendCheckingPresence(ctx, salesPersonId, 'I changed something');
|
||||||
|
|
||||||
try {
|
expect(response).toEqual(false);
|
||||||
const options = {transaction: tx};
|
|
||||||
|
|
||||||
const department = await models.Department.findById(departmentId, null, options);
|
|
||||||
await department.updateAttribute('chatName', 'cooler');
|
|
||||||
|
|
||||||
await chatModel.sendCheckingPresence(ctx, workerId, 'I changed something');
|
|
||||||
|
|
||||||
expect(chatModel.send).toHaveBeenCalledWith(ctx, '#cooler', '@HankPym ➔ I changed something');
|
|
||||||
|
|
||||||
await tx.rollback();
|
|
||||||
} catch (e) {
|
|
||||||
await tx.rollback();
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
const models = require('vn-loopback/server/server').models;
|
||||||
|
|
||||||
|
describe('Chat sendCheckingPresence()', () => {
|
||||||
|
const today = new Date();
|
||||||
|
today.setHours(6, 0);
|
||||||
|
const chatModel = models.Chat;
|
||||||
|
|
||||||
|
it(`should call to sendCheckingUserStatus()`, async() => {
|
||||||
|
spyOn(chatModel, 'sendCheckingUserStatus').and.callThrough();
|
||||||
|
|
||||||
|
const chat = {
|
||||||
|
checkUserStatus: 1,
|
||||||
|
status: 0,
|
||||||
|
attempts: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
await chatModel.destroyAll();
|
||||||
|
await chatModel.create(chat);
|
||||||
|
|
||||||
|
await chatModel.sendQueued();
|
||||||
|
|
||||||
|
expect(chatModel.sendCheckingUserStatus).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should call to sendMessage() method`, async() => {
|
||||||
|
spyOn(chatModel, 'sendMessage').and.callThrough();
|
||||||
|
|
||||||
|
const chat = {
|
||||||
|
checkUserStatus: 0,
|
||||||
|
status: 0,
|
||||||
|
attempts: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
await chatModel.destroyAll();
|
||||||
|
await chatModel.create(chat);
|
||||||
|
|
||||||
|
await chatModel.sendQueued();
|
||||||
|
|
||||||
|
expect(chatModel.sendMessage).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
|
@ -11,11 +11,11 @@ module.exports = Self => {
|
||||||
},
|
},
|
||||||
http: {
|
http: {
|
||||||
path: `/deleteTrashFiles`,
|
path: `/deleteTrashFiles`,
|
||||||
verb: 'POST'
|
verb: 'GET'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Self.deleteTrashFiles = async(options) => {
|
Self.deleteTrashFiles = async options => {
|
||||||
const tx = await Self.beginTransaction({});
|
const tx = await Self.beginTransaction({});
|
||||||
const myOptions = {};
|
const myOptions = {};
|
||||||
|
|
||||||
|
@ -47,7 +47,6 @@ module.exports = Self => {
|
||||||
await dms.destroy(myOptions);
|
await dms.destroy(myOptions);
|
||||||
}
|
}
|
||||||
if (tx) await tx.commit();
|
if (tx) await tx.commit();
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (tx) await tx.rollback();
|
if (tx) await tx.rollback();
|
||||||
|
|
||||||
|
|
|
@ -19,89 +19,186 @@ module.exports = Self => {
|
||||||
Self.updateData = async() => {
|
Self.updateData = async() => {
|
||||||
const models = Self.app.models;
|
const models = Self.app.models;
|
||||||
|
|
||||||
|
// Get files checksum
|
||||||
|
const files = await Self.rawSql('SELECT name, checksum, keyValue FROM edi.fileConfig');
|
||||||
|
|
||||||
|
const updatableFiles = [];
|
||||||
|
for (const file of files) {
|
||||||
|
const fileChecksum = await getChecksum(file);
|
||||||
|
|
||||||
|
if (file.checksum != fileChecksum) {
|
||||||
|
updatableFiles.push({
|
||||||
|
name: file.name,
|
||||||
|
checksum: fileChecksum
|
||||||
|
});
|
||||||
|
} else
|
||||||
|
console.debug(`File already updated, skipping...`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updatableFiles.length === 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Download files
|
||||||
const container = await models.TempContainer.container('edi');
|
const container = await models.TempContainer.container('edi');
|
||||||
const tempPath = path.join(container.client.root, container.name);
|
const tempPath = path.join(container.client.root, container.name);
|
||||||
|
|
||||||
// Temporary file clean
|
|
||||||
await fs.rmdir(`${tempPath}/*`, {recursive: true});
|
|
||||||
fs.emptyDirSync(`${tempPath}`);
|
|
||||||
|
|
||||||
const [ftpConfig] = await Self.rawSql('SELECT host, user, password FROM edi.ftpConfig');
|
|
||||||
console.debug(`Openning FTP connection to ${ftpConfig.host}...\n`);
|
|
||||||
|
|
||||||
const FtpClient = require('ftps');
|
|
||||||
const ftpClient = new FtpClient({
|
|
||||||
host: ftpConfig.host,
|
|
||||||
username: ftpConfig.user,
|
|
||||||
password: ftpConfig.password,
|
|
||||||
procotol: 'ftp'
|
|
||||||
});
|
|
||||||
|
|
||||||
const files = await Self.rawSql('SELECT fileName, toTable, file, updated FROM edi.fileConfig');
|
|
||||||
|
|
||||||
let remoteFile;
|
let remoteFile;
|
||||||
let tempDir;
|
let tempDir;
|
||||||
let tempFile;
|
let tempFile;
|
||||||
for (const file of files) {
|
|
||||||
|
const fileNames = updatableFiles.map(file => file.name);
|
||||||
|
|
||||||
|
const tables = await Self.rawSql(`
|
||||||
|
SELECT fileName, toTable, file
|
||||||
|
FROM edi.tableConfig
|
||||||
|
WHERE file IN (?)`, [fileNames]);
|
||||||
|
|
||||||
|
for (const table of tables) {
|
||||||
|
const fileName = table.file;
|
||||||
|
|
||||||
|
console.debug(`Downloading file ${fileName}...`);
|
||||||
|
|
||||||
|
remoteFile = `codes/${fileName}.ZIP`;
|
||||||
|
tempDir = `${tempPath}/${fileName}`;
|
||||||
|
tempFile = `${tempPath}/${fileName}.zip`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const fileName = file.file;
|
await fs.readFile(tempFile);
|
||||||
|
|
||||||
console.debug(`Downloading file ${fileName}...`);
|
|
||||||
|
|
||||||
remoteFile = `codes/${fileName}.ZIP`;
|
|
||||||
tempDir = `${tempPath}/${fileName}`;
|
|
||||||
tempFile = `${tempPath}/${fileName}.zip`;
|
|
||||||
|
|
||||||
// if (fs.existsSync(tempFile))
|
|
||||||
// await fs.unlink(tempFile);
|
|
||||||
|
|
||||||
// if (fs.existsSync(tempDir))
|
|
||||||
// await fs.rmdir(tempDir, {recursive: true});
|
|
||||||
|
|
||||||
await extractFile({
|
|
||||||
ftpClient: ftpClient,
|
|
||||||
file: file,
|
|
||||||
paths: {
|
|
||||||
remoteFile: remoteFile,
|
|
||||||
tempDir: tempDir,
|
|
||||||
tempFile: tempFile
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (fs.existsSync(tempFile))
|
if (error.code === 'ENOENT') {
|
||||||
await fs.unlink(tempFile);
|
const downloadOutput = await downloadFile(remoteFile, tempFile);
|
||||||
|
if (downloadOutput.error)
|
||||||
console.error(error);
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.debug(`Extracting file ${fileName}...`);
|
||||||
|
await extractFile(tempFile, tempDir);
|
||||||
|
|
||||||
|
console.debug(`Updating table ${table.toTable}...`);
|
||||||
|
await dumpData(tempDir, table);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update files checksum
|
||||||
|
for (const file of updatableFiles) {
|
||||||
|
await Self.rawSql(`
|
||||||
|
UPDATE edi.fileConfig
|
||||||
|
SET checksum = ?
|
||||||
|
WHERE name = ?`,
|
||||||
|
[file.checksum, file.name]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean files
|
||||||
|
try {
|
||||||
|
await fs.remove(tempPath);
|
||||||
|
} catch (error) {
|
||||||
|
if (error.code !== 'ENOENT')
|
||||||
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
async function extractFile({ftpClient, file, paths}) {
|
let ftpClient;
|
||||||
// Download the zip file
|
async function getFtpClient() {
|
||||||
ftpClient.get(paths.remoteFile, paths.tempFile);
|
if (!ftpClient) {
|
||||||
|
const [ftpConfig] = await Self.rawSql('SELECT host, user, password FROM edi.ftpConfig');
|
||||||
|
console.debug(`Openning FTP connection to ${ftpConfig.host}...\n`);
|
||||||
|
|
||||||
// Execute download command
|
const FtpClient = require('ftps');
|
||||||
ftpClient.exec(async(err, response) => {
|
|
||||||
if (response.error) {
|
|
||||||
console.debug(`Error downloading file... ${response.error}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const AdmZip = require('adm-zip');
|
ftpClient = new FtpClient({
|
||||||
const zip = new AdmZip(paths.tempFile);
|
host: ftpConfig.host,
|
||||||
const entries = zip.getEntries();
|
username: ftpConfig.user,
|
||||||
|
password: ftpConfig.password,
|
||||||
|
procotol: 'ftp'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
zip.extractAllTo(paths.tempDir, false);
|
return ftpClient;
|
||||||
|
}
|
||||||
|
|
||||||
await dumpData({file, entries, paths});
|
async function getChecksum(file) {
|
||||||
|
const ftpClient = await getFtpClient();
|
||||||
|
console.debug(`Checking checksum for file ${file.name}...`);
|
||||||
|
|
||||||
|
ftpClient.cat(`codes/${file.name}.txt`);
|
||||||
|
|
||||||
|
const response = await new Promise((resolve, reject) => {
|
||||||
|
ftpClient.exec((err, response) => {
|
||||||
|
if (response.error) {
|
||||||
|
console.debug(`Error downloading checksum file... ${response.error}`);
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(response);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response && response.data) {
|
||||||
|
const fileContents = response.data;
|
||||||
|
const rows = fileContents.split('\n');
|
||||||
|
const row = rows[4];
|
||||||
|
const columns = row.split(/\s+/);
|
||||||
|
|
||||||
|
let fileChecksum;
|
||||||
|
if (file.keyValue)
|
||||||
|
fileChecksum = columns[1];
|
||||||
|
|
||||||
|
if (!file.keyValue)
|
||||||
|
fileChecksum = columns[0];
|
||||||
|
|
||||||
|
return fileChecksum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function downloadFile(remoteFile, tempFile) {
|
||||||
|
const ftpClient = await getFtpClient();
|
||||||
|
|
||||||
|
ftpClient.get(remoteFile, tempFile);
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
ftpClient.exec((err, response) => {
|
||||||
|
if (response.error) {
|
||||||
|
console.debug(`Error downloading file... ${response.error}`);
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(response);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function dumpData({file, entries, paths}) {
|
async function extractFile(tempFile, tempDir) {
|
||||||
const toTable = file.toTable;
|
const JSZip = require('jszip');
|
||||||
const baseName = file.fileName;
|
|
||||||
|
try {
|
||||||
|
await fs.mkdir(tempDir);
|
||||||
|
} catch (error) {
|
||||||
|
if (error.code !== 'EEXIST')
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileStream = await fs.readFile(tempFile);
|
||||||
|
if (fileStream) {
|
||||||
|
const zip = new JSZip();
|
||||||
|
const zipContents = await zip.loadAsync(fileStream);
|
||||||
|
|
||||||
|
if (!zipContents) return;
|
||||||
|
|
||||||
|
const fileNames = Object.keys(zipContents.files);
|
||||||
|
|
||||||
|
for (const fileName of fileNames) {
|
||||||
|
const fileContent = await zip.file(fileName).async('nodebuffer');
|
||||||
|
const dest = path.join(tempDir, fileName);
|
||||||
|
await fs.writeFile(dest, fileContent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function dumpData(tempDir, table) {
|
||||||
|
const toTable = table.toTable;
|
||||||
|
const baseName = table.fileName;
|
||||||
|
|
||||||
const firstEntry = entries[0];
|
const firstEntry = entries[0];
|
||||||
const entryName = firstEntry.entryName;
|
const entryName = firstEntry.entryName;
|
||||||
|
@ -136,20 +233,22 @@ module.exports = Self => {
|
||||||
const tableName = `edi.${toTable}`;
|
const tableName = `edi.${toTable}`;
|
||||||
await Self.rawSql(`DELETE FROM ??`, [tableName], options);
|
await Self.rawSql(`DELETE FROM ??`, [tableName], options);
|
||||||
|
|
||||||
for (const zipEntry of entries) {
|
const dirFiles = await fs.readdir(tempDir);
|
||||||
const entryName = zipEntry.entryName;
|
const files = dirFiles.filter(file => file.startsWith(baseName));
|
||||||
console.log(`Dumping data from file ${entryName}...`);
|
|
||||||
|
for (const file of files) {
|
||||||
|
console.log(`Dumping data from file ${file}...`);
|
||||||
|
|
||||||
const templatePath = path.join(__dirname, `./sql/${toTable}.sql`);
|
const templatePath = path.join(__dirname, `./sql/${toTable}.sql`);
|
||||||
const sqlTemplate = fs.readFileSync(templatePath, 'utf8');
|
const sqlTemplate = await fs.readFile(templatePath, 'utf8');
|
||||||
|
const filePath = path.join(tempDir, file);
|
||||||
|
|
||||||
const rawPath = path.join(paths.tempDir, entryName);
|
await Self.rawSql(sqlTemplate, [filePath], options);
|
||||||
|
|
||||||
await Self.rawSql(sqlTemplate, [rawPath], options);
|
|
||||||
await Self.rawSql(`
|
await Self.rawSql(`
|
||||||
UPDATE edi.fileConfig
|
UPDATE edi.tableConfig
|
||||||
SET updated = ?
|
SET updated = ?
|
||||||
WHERE fileName = ?
|
WHERE fileName = ?
|
||||||
`, [lastUpdated, baseName], options);
|
`, [new Date(), baseName], options);
|
||||||
}
|
}
|
||||||
|
|
||||||
tx.commit();
|
tx.commit();
|
||||||
|
|
|
@ -68,6 +68,12 @@
|
||||||
"Language": {
|
"Language": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
"MachineWorker": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
|
"MobileAppVersionControl": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
"Module": {
|
"Module": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
|
|
@ -28,6 +28,9 @@
|
||||||
},
|
},
|
||||||
"maxAmount": {
|
"maxAmount": {
|
||||||
"type": "number"
|
"type": "number"
|
||||||
|
},
|
||||||
|
"daysInFuture": {
|
||||||
|
"type": "number"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"acls": [{
|
"acls": [{
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
"name": "MobileAppVersionControl",
|
||||||
|
"base": "VnModel",
|
||||||
|
"options": {
|
||||||
|
"mysql": {
|
||||||
|
"table": "vn.mobileAppVersionControl"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "number",
|
||||||
|
"id": true
|
||||||
|
},
|
||||||
|
"appName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"isVersionCritical": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,4 +3,5 @@ module.exports = 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);
|
||||||
|
require('../methods/chat/sendQueued')(Self);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,39 @@
|
||||||
{
|
{
|
||||||
"name": "Chat",
|
"name": "Chat",
|
||||||
"base": "VnModel",
|
"base": "VnModel",
|
||||||
|
"options": {
|
||||||
|
"mysql": {
|
||||||
|
"table": "chat"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"id": true,
|
||||||
|
"type": "number",
|
||||||
|
"description": "Identifier"
|
||||||
|
},
|
||||||
|
"senderFk": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"recipient": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"dated": {
|
||||||
|
"type": "date"
|
||||||
|
},
|
||||||
|
"checkUserStatus": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"attempts": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
"acls": [{
|
"acls": [{
|
||||||
"property": "validations",
|
"property": "validations",
|
||||||
"accessType": "EXECUTE",
|
"accessType": "EXECUTE",
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
{
|
||||||
|
"name": "MachineWorker",
|
||||||
|
"base": "VnModel",
|
||||||
|
"options": {
|
||||||
|
"mysql": {
|
||||||
|
"table": "vn.machineWorker"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "number",
|
||||||
|
"id": true
|
||||||
|
},
|
||||||
|
"workerFk": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"machineFk": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"inTime": {
|
||||||
|
"type": "date",
|
||||||
|
"mysql": {
|
||||||
|
"columnName": "inTimed"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"outTime": {
|
||||||
|
"type": "date",
|
||||||
|
"mysql": {
|
||||||
|
"columnName": "outTimed"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,113 +0,0 @@
|
||||||
DROP PROCEDURE IF EXISTS vn.ticket_doRefund;
|
|
||||||
|
|
||||||
DELIMITER $$
|
|
||||||
$$
|
|
||||||
CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticket_doRefund`(IN vOriginTicket INT, OUT vNewTicket INT)
|
|
||||||
BEGIN
|
|
||||||
|
|
||||||
DECLARE vDone BIT DEFAULT 0;
|
|
||||||
DECLARE vCustomer MEDIUMINT;
|
|
||||||
DECLARE vWarehouse TINYINT;
|
|
||||||
DECLARE vCompany MEDIUMINT;
|
|
||||||
DECLARE vAddress MEDIUMINT;
|
|
||||||
DECLARE vRefundAgencyMode INT;
|
|
||||||
DECLARE vItemFk INT;
|
|
||||||
DECLARE vQuantity DECIMAL (10,2);
|
|
||||||
DECLARE vConcept VARCHAR(50);
|
|
||||||
DECLARE vPrice DECIMAL (10,2);
|
|
||||||
DECLARE vDiscount TINYINT;
|
|
||||||
DECLARE vSaleNew INT;
|
|
||||||
DECLARE vSaleMain INT;
|
|
||||||
DECLARE vZoneFk INT;
|
|
||||||
DECLARE vDescription VARCHAR(50);
|
|
||||||
DECLARE vTaxClassFk INT;
|
|
||||||
DECLARE vTicketServiceTypeFk INT;
|
|
||||||
|
|
||||||
DECLARE cSales CURSOR FOR
|
|
||||||
SELECT *
|
|
||||||
FROM tmp.sale;
|
|
||||||
|
|
||||||
DECLARE cTicketServices CURSOR FOR
|
|
||||||
SELECT *
|
|
||||||
FROM tmp.ticketService;
|
|
||||||
|
|
||||||
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = 1;
|
|
||||||
|
|
||||||
SELECT id INTO vRefundAgencyMode
|
|
||||||
FROM agencyMode WHERE `name` = 'ABONO';
|
|
||||||
|
|
||||||
SELECT clientFk, warehouseFk, companyFk, addressFk
|
|
||||||
INTO vCustomer, vWarehouse, vCompany, vAddress
|
|
||||||
FROM ticket
|
|
||||||
WHERE id = vOriginTicket;
|
|
||||||
|
|
||||||
SELECT id INTO vZoneFk
|
|
||||||
FROM zone WHERE agencyModeFk = vRefundAgencyMode
|
|
||||||
LIMIT 1;
|
|
||||||
|
|
||||||
INSERT INTO vn.ticket (
|
|
||||||
clientFk,
|
|
||||||
shipped,
|
|
||||||
addressFk,
|
|
||||||
agencyModeFk,
|
|
||||||
nickname,
|
|
||||||
warehouseFk,
|
|
||||||
companyFk,
|
|
||||||
landed,
|
|
||||||
zoneFk
|
|
||||||
)
|
|
||||||
SELECT
|
|
||||||
vCustomer,
|
|
||||||
CURDATE(),
|
|
||||||
vAddress,
|
|
||||||
vRefundAgencyMode,
|
|
||||||
a.nickname,
|
|
||||||
vWarehouse,
|
|
||||||
vCompany,
|
|
||||||
CURDATE(),
|
|
||||||
vZoneFk
|
|
||||||
FROM address a
|
|
||||||
WHERE a.id = vAddress;
|
|
||||||
|
|
||||||
SET vNewTicket = LAST_INSERT_ID();
|
|
||||||
|
|
||||||
SET vDone := 0;
|
|
||||||
OPEN cSales;
|
|
||||||
FETCH cSales INTO vSaleMain, vItemFk, vQuantity, vConcept, vPrice, vDiscount;
|
|
||||||
|
|
||||||
WHILE NOT vDone DO
|
|
||||||
|
|
||||||
INSERT INTO vn.sale(ticketFk, itemFk, quantity, concept, price, discount)
|
|
||||||
VALUES( vNewTicket, vItemFk, vQuantity, vConcept, vPrice, vDiscount );
|
|
||||||
|
|
||||||
SET vSaleNew = LAST_INSERT_ID();
|
|
||||||
|
|
||||||
INSERT INTO vn.saleComponent(saleFk,componentFk,`value`)
|
|
||||||
SELECT vSaleNew,componentFk,`value`
|
|
||||||
FROM vn.saleComponent
|
|
||||||
WHERE saleFk = vSaleMain;
|
|
||||||
|
|
||||||
FETCH cSales INTO vSaleMain, vItemFk, vQuantity, vConcept, vPrice, vDiscount;
|
|
||||||
|
|
||||||
END WHILE;
|
|
||||||
CLOSE cSales;
|
|
||||||
|
|
||||||
SET vDone := 0;
|
|
||||||
OPEN cTicketServices;
|
|
||||||
FETCH cTicketServices INTO vDescription, vQuantity, vPrice, vTaxClassFk, vTicketServiceTypeFk;
|
|
||||||
|
|
||||||
WHILE NOT vDone DO
|
|
||||||
|
|
||||||
INSERT INTO vn.ticketService(description, quantity, price, taxClassFk, ticketFk, ticketServiceTypeFk)
|
|
||||||
VALUES(vDescription, vQuantity, vPrice, vTaxClassFk, vNewTicket, vTicketServiceTypeFk);
|
|
||||||
|
|
||||||
FETCH cTicketServices INTO vDescription, vQuantity, vPrice, vTaxClassFk, vTicketServiceTypeFk;
|
|
||||||
|
|
||||||
END WHILE;
|
|
||||||
CLOSE cTicketServices;
|
|
||||||
|
|
||||||
INSERT INTO vn.ticketRefund(refundTicketFk, originalTicketFk)
|
|
||||||
VALUES(vNewTicket, vOriginTicket);
|
|
||||||
|
|
||||||
END$$
|
|
||||||
DELIMITER ;
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
ALTER TABLE `vn`.`accountingType` ADD daysInFuture INT NULL;
|
||||||
|
ALTER TABLE `vn`.`accountingType` MODIFY COLUMN daysInFuture int(11) DEFAULT 0 NULL;
|
||||||
|
UPDATE `vn`.`accountingType` SET daysInFuture=1 WHERE id=8;
|
|
@ -0,0 +1,4 @@
|
||||||
|
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||||
|
VALUES
|
||||||
|
('ItemType', '*', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('ItemType', '*', 'WRITE', 'ALLOW', 'ROLE', 'buyer');
|
|
@ -0,0 +1,14 @@
|
||||||
|
CREATE TABLE IF NOT EXISTS `vn`.`mdbBranch` (
|
||||||
|
`name` VARCHAR(255),
|
||||||
|
PRIMARY KEY(`name`)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `vn`.`mdbVersion` (
|
||||||
|
`app` VARCHAR(255) NOT NULL,
|
||||||
|
`branchFk` VARCHAR(255) NOT NULL,
|
||||||
|
`version` INT,
|
||||||
|
CONSTRAINT `mdbVersion_branchFk` FOREIGN KEY (`branchFk`) REFERENCES `vn`.`mdbBranch` (`name`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT IGNORE INTO `salix`.`ACL` (`id`, `model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||||
|
VALUES(318, 'MdbVersion', '*', '*', 'ALLOW', 'ROLE', 'developer');
|
|
@ -0,0 +1,13 @@
|
||||||
|
CREATE TABLE `vn`.`chat` (
|
||||||
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
`senderFk` int(10) unsigned DEFAULT NULL,
|
||||||
|
`recipient` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
|
||||||
|
`dated` date DEFAULT NULL,
|
||||||
|
`checkUserStatus` tinyint(1) DEFAULT NULL,
|
||||||
|
`message` varchar(200) COLLATE utf8_unicode_ci DEFAULT NULL,
|
||||||
|
`status` tinyint(1) DEFAULT NULL,
|
||||||
|
`attempts` int(1) DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `chat_FK` (`senderFk`),
|
||||||
|
CONSTRAINT `chat_FK` FOREIGN KEY (`senderFk`) REFERENCES `account`.`user` (`id`) ON UPDATE CASCADE
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
|
|
@ -0,0 +1,8 @@
|
||||||
|
ALTER TABLE `vn`.`creditInsurance` ADD creditClassificationFk int(11) NULL;
|
||||||
|
|
||||||
|
UPDATE `vn`.`creditInsurance` AS `destiny`
|
||||||
|
SET `destiny`.`creditClassificationFk`= (SELECT creditClassification FROM `vn`.`creditInsurance` AS `origin` WHERE `origin`.id = `destiny`.id);
|
||||||
|
|
||||||
|
ALTER TABLE `vn`.`creditInsurance`
|
||||||
|
ADD CONSTRAINT `creditInsurance_creditClassificationFk` FOREIGN KEY (`creditClassificationFk`)
|
||||||
|
REFERENCES `vn`.`creditClassification` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
|
@ -0,0 +1,3 @@
|
||||||
|
INSERT INTO `salix`.`defaultViewConfig` (tableCode, columns)
|
||||||
|
VALUES ('clientsDetail', '{"id":true,"phone":true,"city":true,"socialName":true,"salesPersonFk":true,"email":true,"name":false,"fi":false,"credit":false,"creditInsurance":false,"mobile":false,"street":false,"countryFk":false,"provinceFk":false,"postcode":false,"created":false,"businessTypeFk":false,"payMethodFk":false,"sageTaxTypeFk":false,"sageTransactionTypeFk":false,"isActive":false,"isVies":false,"isTaxDataChecked":false,"isEqualizated":false,"isFreezed":false,"hasToInvoice":false,"hasToInvoiceByAddress":false,"isToBeMailed":false,"hasLcr":false,"hasCoreVnl":false,"hasSepaVnl":false}');
|
||||||
|
|
|
@ -0,0 +1,127 @@
|
||||||
|
DROP PROCEDURE IF EXISTS `vn`.`ticket_doRefund`;
|
||||||
|
|
||||||
|
DELIMITER $$
|
||||||
|
$$
|
||||||
|
CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticket_doRefund`(OUT vNewTicket INT)
|
||||||
|
BEGIN
|
||||||
|
/**
|
||||||
|
* Crea un ticket de abono a partir de tmp.sale y/o tmp.ticketService
|
||||||
|
*
|
||||||
|
* @return vNewTicket
|
||||||
|
*/
|
||||||
|
DECLARE vDone BIT DEFAULT 0;
|
||||||
|
DECLARE vClientFk MEDIUMINT;
|
||||||
|
DECLARE vWarehouse TINYINT;
|
||||||
|
DECLARE vCompany MEDIUMINT;
|
||||||
|
DECLARE vAddress MEDIUMINT;
|
||||||
|
DECLARE vRefundAgencyMode INT;
|
||||||
|
DECLARE vItemFk INT;
|
||||||
|
DECLARE vQuantity DECIMAL (10,2);
|
||||||
|
DECLARE vConcept VARCHAR(50);
|
||||||
|
DECLARE vPrice DECIMAL (10,2);
|
||||||
|
DECLARE vDiscount TINYINT;
|
||||||
|
DECLARE vSaleNew INT;
|
||||||
|
DECLARE vSaleMain INT;
|
||||||
|
DECLARE vZoneFk INT;
|
||||||
|
DECLARE vDescription VARCHAR(50);
|
||||||
|
DECLARE vTaxClassFk INT;
|
||||||
|
DECLARE vTicketServiceTypeFk INT;
|
||||||
|
DECLARE vOriginTicket INT;
|
||||||
|
|
||||||
|
DECLARE cSales CURSOR FOR
|
||||||
|
SELECT s.id, s.itemFk, - s.quantity, s.concept, s.price, s.discount
|
||||||
|
FROM tmp.sale s;
|
||||||
|
|
||||||
|
DECLARE cTicketServices CURSOR FOR
|
||||||
|
SELECT ts.description, - ts.quantity, ts.price, ts.taxClassFk, ts.ticketServiceTypeFk
|
||||||
|
FROM tmp.ticketService ts;
|
||||||
|
|
||||||
|
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE;
|
||||||
|
|
||||||
|
SELECT sub.ticketFk INTO vOriginTicket
|
||||||
|
FROM (
|
||||||
|
SELECT s.ticketFk
|
||||||
|
FROM tmp.sale s
|
||||||
|
UNION ALL
|
||||||
|
SELECT ts.ticketFk
|
||||||
|
FROM tmp.ticketService ts
|
||||||
|
) sub
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
SELECT id INTO vRefundAgencyMode
|
||||||
|
FROM agencyMode WHERE `name` = 'ABONO';
|
||||||
|
|
||||||
|
SELECT clientFk, warehouseFk, companyFk, addressFk
|
||||||
|
INTO vClientFk, vWarehouse, vCompany, vAddress
|
||||||
|
FROM ticket
|
||||||
|
WHERE id = vOriginTicket;
|
||||||
|
|
||||||
|
SELECT id INTO vZoneFk
|
||||||
|
FROM zone WHERE agencyModeFk = vRefundAgencyMode
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
INSERT INTO vn.ticket (
|
||||||
|
clientFk,
|
||||||
|
shipped,
|
||||||
|
addressFk,
|
||||||
|
agencyModeFk,
|
||||||
|
nickname,
|
||||||
|
warehouseFk,
|
||||||
|
companyFk,
|
||||||
|
landed,
|
||||||
|
zoneFk
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
vClientFk,
|
||||||
|
CURDATE(),
|
||||||
|
vAddress,
|
||||||
|
vRefundAgencyMode,
|
||||||
|
a.nickname,
|
||||||
|
vWarehouse,
|
||||||
|
vCompany,
|
||||||
|
CURDATE(),
|
||||||
|
vZoneFk
|
||||||
|
FROM address a
|
||||||
|
WHERE a.id = vAddress;
|
||||||
|
|
||||||
|
SET vNewTicket = LAST_INSERT_ID();
|
||||||
|
|
||||||
|
SET vDone := FALSE;
|
||||||
|
OPEN cSales;
|
||||||
|
FETCH cSales INTO vSaleMain, vItemFk, vQuantity, vConcept, vPrice, vDiscount;
|
||||||
|
|
||||||
|
WHILE NOT vDone DO
|
||||||
|
|
||||||
|
INSERT INTO vn.sale(ticketFk, itemFk, quantity, concept, price, discount)
|
||||||
|
VALUES( vNewTicket, vItemFk, vQuantity, vConcept, vPrice, vDiscount );
|
||||||
|
|
||||||
|
SET vSaleNew = LAST_INSERT_ID();
|
||||||
|
|
||||||
|
INSERT INTO vn.saleComponent(saleFk,componentFk,`value`)
|
||||||
|
SELECT vSaleNew,componentFk,`value`
|
||||||
|
FROM vn.saleComponent
|
||||||
|
WHERE saleFk = vSaleMain;
|
||||||
|
|
||||||
|
FETCH cSales INTO vSaleMain, vItemFk, vQuantity, vConcept, vPrice, vDiscount;
|
||||||
|
|
||||||
|
END WHILE;
|
||||||
|
CLOSE cSales;
|
||||||
|
|
||||||
|
SET vDone := FALSE;
|
||||||
|
OPEN cTicketServices;
|
||||||
|
FETCH cTicketServices INTO vDescription, vQuantity, vPrice, vTaxClassFk, vTicketServiceTypeFk;
|
||||||
|
|
||||||
|
WHILE NOT vDone DO
|
||||||
|
|
||||||
|
INSERT INTO vn.ticketService(description, quantity, price, taxClassFk, ticketFk, ticketServiceTypeFk)
|
||||||
|
VALUES(vDescription, vQuantity, vPrice, vTaxClassFk, vNewTicket, vTicketServiceTypeFk);
|
||||||
|
|
||||||
|
FETCH cTicketServices INTO vDescription, vQuantity, vPrice, vTaxClassFk, vTicketServiceTypeFk;
|
||||||
|
|
||||||
|
END WHILE;
|
||||||
|
CLOSE cTicketServices;
|
||||||
|
|
||||||
|
INSERT INTO vn.ticketRefund(refundTicketFk, originalTicketFk)
|
||||||
|
VALUES(vNewTicket, vOriginTicket);
|
||||||
|
END$$
|
||||||
|
DELIMITER ;
|
|
@ -0,0 +1,11 @@
|
||||||
|
DELIMITER $$
|
||||||
|
$$
|
||||||
|
CREATE DEFINER=`root`@`localhost` TRIGGER `vn`.`creditInsurance_beforeInsert`
|
||||||
|
BEFORE INSERT ON `creditInsurance`
|
||||||
|
FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
IF NEW.creditClassificationFk THEN
|
||||||
|
SET NEW.creditClassification = NEW.creditClassificationFk;
|
||||||
|
END IF;
|
||||||
|
END$$
|
||||||
|
DELIMITER ;
|
|
@ -0,0 +1 @@
|
||||||
|
RENAME TABLE `edi`.`fileConfig` to `edi`.`tableConfig`;
|
|
@ -0,0 +1,22 @@
|
||||||
|
CREATE TABLE `edi`.`fileConfig`
|
||||||
|
(
|
||||||
|
name varchar(25) NOT NULL,
|
||||||
|
checksum text NULL,
|
||||||
|
keyValue tinyint(1) default true NOT NULL,
|
||||||
|
constraint fileConfig_pk
|
||||||
|
primary key (name)
|
||||||
|
);
|
||||||
|
|
||||||
|
create unique index fileConfig_name_uindex
|
||||||
|
on `edi`.`fileConfig` (name);
|
||||||
|
|
||||||
|
|
||||||
|
INSERT INTO `edi`.`fileConfig` (name, checksum, keyValue)
|
||||||
|
VALUES ('FEC010104', null, 0);
|
||||||
|
|
||||||
|
INSERT INTO `edi`.`fileConfig` (name, checksum, keyValue)
|
||||||
|
VALUES ('VBN020101', null, 1);
|
||||||
|
|
||||||
|
INSERT INTO `edi`.`fileConfig` (name, checksum, keyValue)
|
||||||
|
VALUES ('florecompc2', null, 1);
|
||||||
|
|
|
@ -99,13 +99,19 @@ INSERT INTO `account`.`mailForward`(`account`, `forwardTo`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, 'employee@domain.local');
|
(1, 'employee@domain.local');
|
||||||
|
|
||||||
INSERT INTO `vn`.`worker`(`id`, `code`, `firstName`, `lastName`, `userFk`,`bossFk`, `phone`)
|
INSERT INTO `vn`.`printer` (`id`, `name`, `path`, `isLabeler`)
|
||||||
VALUES
|
VALUES
|
||||||
(1106, 'LGN', 'David Charles', 'Haller', 1106, 19, 432978106),
|
(1, 'printer1', 'path1', 0),
|
||||||
(1107, 'ANT', 'Hank' , 'Pym' , 1107, 19, 432978107),
|
(2, 'printer2', 'path2', 1);
|
||||||
(1108, 'DCX', 'Charles' , 'Xavier', 1108, 19, 432978108),
|
|
||||||
(1109, 'HLK', 'Bruce' , 'Banner', 1109, 19, 432978109),
|
|
||||||
(1110, 'JJJ', 'Jessica' , 'Jones' , 1110, 19, 432978110);
|
INSERT INTO `vn`.`worker`(`id`, `code`, `firstName`, `lastName`, `userFk`,`bossFk`, `phone`, `sectorFk`, `labelerFk`)
|
||||||
|
VALUES
|
||||||
|
(1106, 'LGN', 'David Charles', 'Haller', 1106, 19, 432978106, NULL, NULL),
|
||||||
|
(1107, 'ANT', 'Hank' , 'Pym' , 1107, 19, 432978107, NULL, 1),
|
||||||
|
(1108, 'DCX', 'Charles' , 'Xavier', 1108, 19, 432978108, 1, NULL),
|
||||||
|
(1109, 'HLK', 'Bruce' , 'Banner', 1109, 19, 432978109, 1, 2),
|
||||||
|
(1110, 'JJJ', 'Jessica' , 'Jones' , 1110, 19, 432978110, 2, 1);
|
||||||
|
|
||||||
INSERT INTO `vn`.`currency`(`id`, `code`, `name`, `ratio`)
|
INSERT INTO `vn`.`currency`(`id`, `code`, `name`, `ratio`)
|
||||||
VALUES
|
VALUES
|
||||||
|
@ -156,22 +162,23 @@ INSERT INTO `vn`.`shelving` (`code`, `parkingFk`, `isPrinted`, `priority`, `park
|
||||||
('HEJ', 2, 0, 1, 0, 1106),
|
('HEJ', 2, 0, 1, 0, 1106),
|
||||||
('UXN', 1, 0, 1, 0, 1106);
|
('UXN', 1, 0, 1, 0, 1106);
|
||||||
|
|
||||||
INSERT INTO `vn`.`accountingType`(`id`, `description`, `receiptDescription`,`code`, `maxAmount`)
|
INSERT INTO `vn`.`accountingType`(`id`, `description`, `receiptDescription`,`code`, `maxAmount`, `daysInFuture`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, 'CC y Polizas de crédito', NULL, NULL, NULL),
|
(1, 'CC and credit policies', 'Transfers', 'wireTransfer', NULL, 1),
|
||||||
(2, 'Cash', 'Cash', 'cash', 1000),
|
(2, 'Cash', 'Cash', 'cash', 1000, 0),
|
||||||
(3, 'Credit card', 'Credit Card', 'creditCard', NULL),
|
(3, 'Credit card', 'Credit Card', 'creditCard', NULL, 0),
|
||||||
(4, 'Finalcial lines', NULL, NULL, NULL),
|
(4, 'Finalcial lines', NULL, NULL, NULL, 0),
|
||||||
(5, 'Other products', NULL, NULL, NULL),
|
(5, 'Other products', NULL, NULL, NULL, 0),
|
||||||
(6, 'Loans', NULL, NULL, NULL),
|
(6, 'Loans', NULL, NULL, NULL, 0),
|
||||||
(7, 'Leasing', NULL, NULL, NULL),
|
(7, 'Leasing', NULL, NULL, NULL, 0),
|
||||||
(8, 'Compensations', 'Compensations', 'compensation', NULL);
|
(8, 'Compensations', 'Compensations', 'compensation', NULL, 0);
|
||||||
|
|
||||||
INSERT INTO `vn`.`bank`(`id`, `bank`, `account`, `cash`, `entityFk`, `isActive`, `currencyFk`)
|
INSERT INTO `vn`.`bank`(`id`, `bank`, `account`, `cash`, `entityFk`, `isActive`, `currencyFk`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, 'Pay on receipt', '5720000001', 3, 0, 1, 1),
|
(1, 'Pay on receipt', '5720000001', 3, 0, 1, 1),
|
||||||
(2, 'Cash', '5700000001', 2, 0, 1, 1),
|
(2, 'Cash', '5700000001', 2, 0, 1, 1),
|
||||||
(3, 'Compensation', '4000000000', 8, 0, 1, 1),
|
(3, 'Compensation', '4000000000', 8, 0, 1, 1),
|
||||||
|
(4, 'Transfers', '4000000001', 1, 0, 1, 1),
|
||||||
(3117, 'Caixa Rural d''Algemesi', '5720000000', 8, 3117, 1, 1);
|
(3117, 'Caixa Rural d''Algemesi', '5720000000', 8, 3117, 1, 1);
|
||||||
|
|
||||||
|
|
||||||
|
@ -451,7 +458,7 @@ INSERT INTO `vn`.`creditClassification`(`id`, `client`, `dateStart`, `dateEnd`)
|
||||||
(4, 1104, CURDATE(), CURDATE()),
|
(4, 1104, CURDATE(), CURDATE()),
|
||||||
(5, 1105, CURDATE(), CURDATE());
|
(5, 1105, CURDATE(), CURDATE());
|
||||||
|
|
||||||
INSERT INTO `vn`.`creditInsurance`(`id`, `creditClassification`, `credit`, `creationDate`, `grade`)
|
INSERT INTO `vn`.`creditInsurance`(`id`, `creditClassificationFk`, `credit`, `creationDate`, `grade`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, 1, 3000, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), NULL),
|
(1, 1, 3000, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), NULL),
|
||||||
(2, 2, 6000, DATE_ADD(CURDATE(), INTERVAL -2 MONTH), NULL),
|
(2, 2, 6000, DATE_ADD(CURDATE(), INTERVAL -2 MONTH), NULL),
|
||||||
|
@ -744,14 +751,19 @@ INSERT INTO `vn`.`itemCategory`(`id`, `name`, `display`, `color`, `icon`, `code`
|
||||||
(7, 'Accessories', 1, NULL, 'icon-accessory', 'accessory'),
|
(7, 'Accessories', 1, NULL, 'icon-accessory', 'accessory'),
|
||||||
(8, 'Fruit', 1, NULL, 'icon-fruit', 'fruit');
|
(8, 'Fruit', 1, NULL, 'icon-fruit', 'fruit');
|
||||||
|
|
||||||
INSERT INTO `vn`.`itemType`(`id`, `code`, `name`, `categoryFk`, `warehouseFk`, `life`,`workerFk`, `isPackaging`)
|
INSERT INTO `vn`.`temperature`(`code`, `name`, `description`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, 'CRI', 'Crisantemo', 2, 1, 31, 35, 0),
|
('warm', 'Warm', 'Warm'),
|
||||||
(2, 'ITG', 'Anthurium', 1, 1, 31, 35, 0),
|
('cool', 'Cool', 'Cool');
|
||||||
(3, 'WPN', 'Paniculata', 2, 1, 31, 35, 0),
|
|
||||||
(4, 'PRT', 'Delivery ports', 3, 1, NULL, 35, 1),
|
INSERT INTO `vn`.`itemType`(`id`, `code`, `name`, `categoryFk`, `warehouseFk`, `life`,`workerFk`, `isPackaging`, `temperatureFk`)
|
||||||
(5, 'CON', 'Container', 3, 1, NULL, 35, 1),
|
VALUES
|
||||||
(6, 'ALS', 'Alstroemeria', 1, 1, 31, 16, 0);
|
(1, 'CRI', 'Crisantemo', 2, 1, 31, 35, 0, 'cool'),
|
||||||
|
(2, 'ITG', 'Anthurium', 1, 1, 31, 35, 0, 'cool'),
|
||||||
|
(3, 'WPN', 'Paniculata', 2, 1, 31, 35, 0, 'cool'),
|
||||||
|
(4, 'PRT', 'Delivery ports', 3, 1, NULL, 35, 1, 'warm'),
|
||||||
|
(5, 'CON', 'Container', 3, 1, NULL, 35, 1, 'warm'),
|
||||||
|
(6, 'ALS', 'Alstroemeria', 1, 1, 31, 16, 0, 'warm');
|
||||||
|
|
||||||
INSERT INTO `vn`.`ink`(`id`, `name`, `picture`, `showOrder`, `hex`)
|
INSERT INTO `vn`.`ink`(`id`, `name`, `picture`, `showOrder`, `hex`)
|
||||||
VALUES
|
VALUES
|
||||||
|
@ -809,25 +821,25 @@ INSERT INTO `vn`.`itemFamily`(`code`, `description`)
|
||||||
('VT', 'Sales');
|
('VT', 'Sales');
|
||||||
|
|
||||||
INSERT INTO `vn`.`item`(`id`, `typeFk`, `size`, `inkFk`, `stems`, `originFk`, `description`, `producerFk`, `intrastatFk`, `expenceFk`,
|
INSERT INTO `vn`.`item`(`id`, `typeFk`, `size`, `inkFk`, `stems`, `originFk`, `description`, `producerFk`, `intrastatFk`, `expenceFk`,
|
||||||
`comment`, `relevancy`, `image`, `subName`, `minPrice`, `stars`, `family`, `isFloramondo`, `genericFk`, `itemPackingTypeFk`, `hasMinPrice`)
|
`comment`, `relevancy`, `image`, `subName`, `minPrice`, `stars`, `family`, `isFloramondo`, `genericFk`, `itemPackingTypeFk`, `hasMinPrice`, `packingShelve`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, 2, 70, 'YEL', 1, 1, NULL, 1, 06021010, 2000000000, NULL, 0, '1', NULL, 0, 1, 'VT', 0, NULL, 'V', 0),
|
(1, 2, 70, 'YEL', 1, 1, NULL, 1, 06021010, 2000000000, NULL, 0, '1', NULL, 0, 1, 'VT', 0, NULL, 'V', 0, 15),
|
||||||
(2, 2, 70, 'BLU', 1, 2, NULL, 1, 06021010, 2000000000, NULL, 0, '2', NULL, 0, 2, 'VT', 0, NULL, 'H', 0),
|
(2, 2, 70, 'BLU', 1, 2, NULL, 1, 06021010, 2000000000, NULL, 0, '2', NULL, 0, 2, 'VT', 0, NULL, 'H', 0, 10),
|
||||||
(3, 1, 60, 'YEL', 1, 3, NULL, 1, 05080000, 4751000000, NULL, 0, '3', NULL, 0, 5, 'VT', 0, NULL, NULL, 0),
|
(3, 1, 60, 'YEL', 1, 3, NULL, 1, 05080000, 4751000000, NULL, 0, '3', NULL, 0, 5, 'VT', 0, NULL, NULL, 0, 5),
|
||||||
(4, 1, 60, 'YEL', 1, 1, 'Increases block', 1, 05080000, 4751000000, NULL, 0, '4', NULL, 0, 3, 'VT', 0, NULL, NULL, 0),
|
(4, 1, 60, 'YEL', 1, 1, 'Increases block', 1, 05080000, 4751000000, NULL, 0, '4', NULL, 0, 3, 'VT', 0, NULL, NULL, 0, NULL),
|
||||||
(5, 3, 30, 'RED', 1, 2, NULL, 2, 06021010, 4751000000, NULL, 0, '5', NULL, 0, 3, 'VT', 0, NULL, NULL, 0),
|
(5, 3, 30, 'RED', 1, 2, NULL, 2, 06021010, 4751000000, NULL, 0, '5', NULL, 0, 3, 'VT', 0, NULL, NULL, 0, NULL),
|
||||||
(6, 5, 30, 'RED', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '6', NULL, 0, 4, 'VT', 0, NULL, NULL, 0),
|
(6, 5, 30, 'RED', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '6', NULL, 0, 4, 'VT', 0, NULL, NULL, 0, NULL),
|
||||||
(7, 5, 90, 'BLU', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '7', NULL, 0, 4, 'VT', 0, NULL, NULL, 0),
|
(7, 5, 90, 'BLU', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '7', NULL, 0, 4, 'VT', 0, NULL, NULL, 0, NULL),
|
||||||
(8, 2, 70, 'YEL', 1, 1, NULL, 1, 06021010, 2000000000, NULL, 0, '8', NULL, 0, 5, 'VT', 0, NULL, NULL, 0),
|
(8, 2, 70, 'YEL', 1, 1, NULL, 1, 06021010, 2000000000, NULL, 0, '8', NULL, 0, 5, 'VT', 0, NULL, NULL, 0, NULL),
|
||||||
(9, 2, 70, 'BLU', 1, 2, NULL, 1, 06021010, 2000000000, NULL, 0, '9', NULL, 0, 4, 'VT', 1, NULL, NULL, 0),
|
(9, 2, 70, 'BLU', 1, 2, NULL, 1, 06021010, 2000000000, NULL, 0, '9', NULL, 0, 4, 'VT', 1, NULL, NULL, 0, NULL),
|
||||||
(10, 1, 60, 'YEL', 1, 3, NULL, 1, 05080000, 4751000000, NULL, 0, '10', NULL, 0, 4, 'VT', 0, NULL, NULL, 0),
|
(10, 1, 60, 'YEL', 1, 3, NULL, 1, 05080000, 4751000000, NULL, 0, '10', NULL, 0, 4, 'VT', 0, NULL, NULL, 0, NULL),
|
||||||
(11, 1, 60, 'YEL', 1, 1, NULL, 1, 05080000, 4751000000, NULL, 0, '11', NULL, 0, 4, 'VT', 0, NULL, NULL, 0),
|
(11, 1, 60, 'YEL', 1, 1, NULL, 1, 05080000, 4751000000, NULL, 0, '11', NULL, 0, 4, 'VT', 0, NULL, NULL, 0, NULL),
|
||||||
(12, 3, 30, 'RED', 1, 2, NULL, 2, 06021010, 4751000000, NULL, 0, '12', NULL, 0, 3, 'VT', 0, NULL, NULL, 0),
|
(12, 3, 30, 'RED', 1, 2, NULL, 2, 06021010, 4751000000, NULL, 0, '12', NULL, 0, 3, 'VT', 0, NULL, NULL, 0, NULL),
|
||||||
(13, 5, 30, 'RED', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '13', NULL, 1, 2, 'VT', 1, NULL, NULL, 1),
|
(13, 5, 30, 'RED', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '13', NULL, 1, 2, 'VT', 1, NULL, NULL, 1, NULL),
|
||||||
(14, 5, 90, 'BLU', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 4, 'VT', 1, NULL, NULL, 0),
|
(14, 5, 90, 'BLU', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 4, 'VT', 1, NULL, NULL, 0, NULL),
|
||||||
(15, 4, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 0, 'EMB', 0, NULL, NULL, 0),
|
(15, 4, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 0, 'EMB', 0, NULL, NULL, 0, NULL),
|
||||||
(16, 6, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 0, 'EMB', 0, NULL, NULL, 0),
|
(16, 6, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 0, 'EMB', 0, NULL, NULL, 0, NULL),
|
||||||
(71, 6, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 0, 'VT', 0, NULL, NULL, 0);
|
(71, 6, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 0, 'VT', 0, NULL, NULL, 0, NULL);
|
||||||
|
|
||||||
-- Update the taxClass after insert of the items
|
-- Update the taxClass after insert of the items
|
||||||
UPDATE `vn`.`itemTaxCountry` SET `taxClassFk` = 2
|
UPDATE `vn`.`itemTaxCountry` SET `taxClassFk` = 2
|
||||||
|
@ -2299,11 +2311,6 @@ INSERT INTO `vn`.`workerTimeControlParams` (`id`, `dayBreak`, `weekBreak`, `week
|
||||||
|
|
||||||
INSERT IGNORE INTO `vn`.`greugeConfig` (`id`, `freightPickUpPrice`) VALUES ('1', '11');
|
INSERT IGNORE INTO `vn`.`greugeConfig` (`id`, `freightPickUpPrice`) VALUES ('1', '11');
|
||||||
|
|
||||||
INSERT INTO `vn`.`temperature`(`code`, `name`, `description`)
|
|
||||||
VALUES
|
|
||||||
('warm', 'Warm', 'Warm'),
|
|
||||||
('cool', 'Cool', 'Cool');
|
|
||||||
|
|
||||||
INSERT INTO `vn`.`thermograph`(`id`, `model`)
|
INSERT INTO `vn`.`thermograph`(`id`, `model`)
|
||||||
VALUES
|
VALUES
|
||||||
('TMM190901395', 'TEMPMATE'),
|
('TMM190901395', 'TEMPMATE'),
|
||||||
|
@ -2552,3 +2559,36 @@ INSERT INTO `vn`.`supplierAgencyTerm` (`agencyFk`, `supplierFk`, `minimumPackage
|
||||||
(3, 2, 0, 15.00, 0.00, NULL, 0, 0.00, 0),
|
(3, 2, 0, 15.00, 0.00, NULL, 0, 0.00, 0),
|
||||||
(4, 2, 0, 20.00, 0.00, NULL, 0, 0.00, 0),
|
(4, 2, 0, 20.00, 0.00, NULL, 0, 0.00, 0),
|
||||||
(5, 442, 0, 0.00, 3.05, NULL, 0, 0.00, 0);
|
(5, 442, 0, 0.00, 3.05, NULL, 0, 0.00, 0);
|
||||||
|
|
||||||
|
INSERT INTO `vn`.`chat` (`senderFk`, `recipient`, `dated`, `checkUserStatus`, `message`, `status`, `attempts`)
|
||||||
|
VALUES
|
||||||
|
(1101, '@PetterParker', CURDATE(), 1, 'First test message', 0, 0),
|
||||||
|
(1101, '@PetterParker', CURDATE(), 0, 'Second test message', 0, 0);
|
||||||
|
|
||||||
|
|
||||||
|
INSERT INTO `vn`.`mobileAppVersionControl` (`appName`, `version`, `isVersionCritical`)
|
||||||
|
VALUES
|
||||||
|
('delivery', '9.2', 0),
|
||||||
|
('warehouse', '8.1', 0);
|
||||||
|
|
||||||
|
INSERT INTO `vn`.`machine` (`plate`, `maker`, `model`, `warehouseFk`, `departmentFk`, `type`, `use`, `productionYear`, `workerFk`, `companyFk`)
|
||||||
|
VALUES
|
||||||
|
('RE-001', 'STILL', 'LTX-20', 60, 23, 'ELECTRIC TOW', 'Drag cars', 2020, 103, 442),
|
||||||
|
('RE-002', 'STILL', 'LTX-20', 60, 23, 'ELECTRIC TOW', 'Drag cars', 2020, 103, 442);
|
||||||
|
|
||||||
|
INSERT INTO `vn`.`machineWorker` (`workerFk`, `machineFk`, `inTimed`, `outTimed`)
|
||||||
|
VALUES
|
||||||
|
(1106, 1, CURDATE(), CURDATE()),
|
||||||
|
(1106, 1, DATE_ADD(CURDATE(), INTERVAL + 1 DAY), DATE_ADD(CURDATE(), INTERVAL +1 DAY)),
|
||||||
|
(1106, 2, CURDATE(), NULL),
|
||||||
|
(1106, 2, DATE_ADD(CURDATE(), INTERVAL + 1 DAY), DATE_ADD(CURDATE(), INTERVAL +1 DAY));
|
||||||
|
|
||||||
|
INSERT INTO `vn`.`mdbBranch` (`name`)
|
||||||
|
VALUES
|
||||||
|
('test'),
|
||||||
|
('master');
|
||||||
|
|
||||||
|
INSERT INTO `vn`.`mdbVersion` (`app`, `branchFk`, `version`)
|
||||||
|
VALUES
|
||||||
|
('tpv', 'test', '1'),
|
||||||
|
('lab', 'master', '1');
|
|
@ -31067,7 +31067,7 @@ CREATE TABLE `entry` (
|
||||||
`dated` datetime NOT NULL,
|
`dated` datetime NOT NULL,
|
||||||
`ref` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
|
`ref` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
|
||||||
`isBooked` tinyint(1) NOT NULL DEFAULT '0',
|
`isBooked` tinyint(1) NOT NULL DEFAULT '0',
|
||||||
`isExcludedFromAvailable` tinyint(1) NOT NULL DEFAULT '0',
|
`isExcludedFromAvailable` tinyint(1) NOT NULL DEFAULT 0,
|
||||||
`notes` longtext COLLATE utf8_unicode_ci,
|
`notes` longtext COLLATE utf8_unicode_ci,
|
||||||
`isConfirmed` tinyint(1) NOT NULL DEFAULT '0',
|
`isConfirmed` tinyint(1) NOT NULL DEFAULT '0',
|
||||||
`isOrdered` tinyint(1) NOT NULL DEFAULT '0',
|
`isOrdered` tinyint(1) NOT NULL DEFAULT '0',
|
||||||
|
@ -37460,6 +37460,31 @@ SET character_set_client = utf8;
|
||||||
) ENGINE=MyISAM */;
|
) ENGINE=MyISAM */;
|
||||||
SET character_set_client = @saved_cs_client;
|
SET character_set_client = @saved_cs_client;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Temporary table structure for view `printer`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `printer`;
|
||||||
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
|
/*!40101 SET character_set_client = utf8 */;
|
||||||
|
CREATE TABLE `printer` (
|
||||||
|
`id` tinyint(3) unsigned NOT NULL,
|
||||||
|
`name` varchar(50) COLLATE utf8mb3_unicode_ci DEFAULT NULL,
|
||||||
|
`path` varchar(50) COLLATE utf8mb3_unicode_ci DEFAULT NULL,
|
||||||
|
`modelFk` varchar(50) COLLATE utf8mb3_unicode_ci DEFAULT NULL,
|
||||||
|
`macWifi` varchar(20) COLLATE utf8mb3_unicode_ci DEFAULT NULL,
|
||||||
|
`ipAddress` varchar(15) COLLATE utf8mb3_unicode_ci DEFAULT NULL,
|
||||||
|
`reference` varchar(50) COLLATE utf8mb3_unicode_ci DEFAULT NULL,
|
||||||
|
`isLabeler` tinyint(1) DEFAULT 0 COMMENT 'Indica si es impresora de etiquetas',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `printer_UN` (`reference`),
|
||||||
|
UNIQUE KEY `printer_UN1` (`macWifi`),
|
||||||
|
UNIQUE KEY `printer_UN2` (`name`),
|
||||||
|
KEY `printer_FK` (`modelFk`),
|
||||||
|
CONSTRAINT `printer_FK` FOREIGN KEY (`modelFk`) REFERENCES `printerModel` (`code`) ON UPDATE CASCADE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||||
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Table structure for table `printingQueueCheck`
|
-- Table structure for table `printingQueueCheck`
|
||||||
--
|
--
|
||||||
|
@ -82023,7 +82048,7 @@ BEGIN
|
||||||
* Devuelve los tickets y la cantidad de lineas de venta que se pueden adelantar.
|
* Devuelve los tickets y la cantidad de lineas de venta que se pueden adelantar.
|
||||||
*
|
*
|
||||||
* @param vDated Fecha de los tickets que se quieren adelantar.
|
* @param vDated Fecha de los tickets que se quieren adelantar.
|
||||||
* @param vWarehouseFk Almacén
|
* @param vWarehouseFk AlmacénitemEntryIn
|
||||||
*/
|
*/
|
||||||
DECLARE vDateInventory DATE;
|
DECLARE vDateInventory DATE;
|
||||||
DECLARE vDateToAdvance DATE;
|
DECLARE vDateToAdvance DATE;
|
||||||
|
|
|
@ -60,7 +60,6 @@ IGNORETABLES=(
|
||||||
--ignore-table=vn.plantpassportAuthority__
|
--ignore-table=vn.plantpassportAuthority__
|
||||||
--ignore-table=vn.preparationException
|
--ignore-table=vn.preparationException
|
||||||
--ignore-table=vn.priceFixed__
|
--ignore-table=vn.priceFixed__
|
||||||
--ignore-table=vn.printer
|
|
||||||
--ignore-table=vn.printingQueue
|
--ignore-table=vn.printingQueue
|
||||||
--ignore-table=vn.printServerQueue__
|
--ignore-table=vn.printServerQueue__
|
||||||
--ignore-table=vn.promissoryNote
|
--ignore-table=vn.promissoryNote
|
||||||
|
|
|
@ -101,6 +101,47 @@ export default {
|
||||||
email: 'vn-user-mail-forwarding vn-textfield[ng-model="data.forwardTo"]',
|
email: 'vn-user-mail-forwarding vn-textfield[ng-model="data.forwardTo"]',
|
||||||
save: 'vn-user-mail-forwarding vn-submit'
|
save: 'vn-user-mail-forwarding vn-submit'
|
||||||
},
|
},
|
||||||
|
accountAcl: {
|
||||||
|
addAcl: 'vn-acl-index button vn-icon[icon="add"]',
|
||||||
|
thirdAcl: 'vn-acl-index vn-list> a:nth-child(3)',
|
||||||
|
deleteThirdAcl: 'vn-acl-index vn-list > a:nth-child(3) > vn-item-section > vn-icon-button[icon="delete"]',
|
||||||
|
role: 'vn-acl-create vn-autocomplete[ng-model="$ctrl.acl.principalId"]',
|
||||||
|
model: 'vn-acl-create vn-autocomplete[ng-model="$ctrl.acl.model"]',
|
||||||
|
property: 'vn-acl-create vn-autocomplete[ng-model="$ctrl.acl.property"]',
|
||||||
|
accessType: 'vn-acl-create vn-autocomplete[ng-model="$ctrl.acl.accessType"]',
|
||||||
|
permission: 'vn-acl-create vn-autocomplete[ng-model="$ctrl.acl.permission"]',
|
||||||
|
save: 'vn-acl-create vn-submit'
|
||||||
|
},
|
||||||
|
accountConnections: {
|
||||||
|
firstConnection: 'vn-connections vn-list > a:nth-child(1)',
|
||||||
|
deleteFirstConnection: 'vn-connections vn-list > a:nth-child(1) > vn-item-section > vn-icon-button[icon="exit_to_app"]'
|
||||||
|
},
|
||||||
|
accountAccounts: {
|
||||||
|
syncRoles: 'vn-account-accounts vn-button[label="Synchronize roles"]',
|
||||||
|
syncUser: 'vn-account-accounts vn-button[label="Synchronize user"]',
|
||||||
|
syncAll: 'vn-account-accounts vn-button[label="Synchronize all"]',
|
||||||
|
syncUserName: 'vn-textfield[ng-model="$ctrl.syncUser"]',
|
||||||
|
syncUserPassword: 'vn-textfield[ng-model="$ctrl.syncPassword"]',
|
||||||
|
buttonAccept: 'button[response="accept"]'
|
||||||
|
},
|
||||||
|
accountLdap: {
|
||||||
|
checkEnable: 'vn-account-ldap vn-check[ng-model="watcher.hasData"]',
|
||||||
|
server: 'vn-account-ldap vn-textfield[ng-model="$ctrl.config.server"]',
|
||||||
|
rdn: 'vn-account-ldap vn-textfield[ng-model="$ctrl.config.rdn"]',
|
||||||
|
password: 'vn-account-ldap vn-textfield[ng-model="$ctrl.config.password"]',
|
||||||
|
userDn: 'vn-account-ldap vn-textfield[ng-model="$ctrl.config.userDn"]',
|
||||||
|
groupDn: 'vn-account-ldap vn-textfield[ng-model="$ctrl.config.groupDn"]',
|
||||||
|
save: 'vn-account-ldap vn-submit'
|
||||||
|
},
|
||||||
|
accountSamba: {
|
||||||
|
checkEnable: 'vn-account-samba vn-check[ng-model="watcher.hasData"]',
|
||||||
|
adDomain: 'vn-account-samba vn-textfield[ng-model="$ctrl.config.adDomain"]',
|
||||||
|
adController: 'vn-account-samba vn-textfield[ng-model="$ctrl.config.adController"]',
|
||||||
|
adUser: 'vn-account-samba vn-textfield[ng-model="$ctrl.config.adUser"]',
|
||||||
|
adPassword: 'vn-account-samba vn-textfield[ng-model="$ctrl.config.adPassword"]',
|
||||||
|
verifyCert: 'vn-account-samba vn-check[ng-model="$ctrl.config.verifyCert"]',
|
||||||
|
save: 'vn-account-samba vn-submit'
|
||||||
|
},
|
||||||
clientsIndex: {
|
clientsIndex: {
|
||||||
createClientButton: `vn-float-button`
|
createClientButton: `vn-float-button`
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
import selectors from '../../helpers/selectors.js';
|
||||||
|
import getBrowser from '../../helpers/puppeteer';
|
||||||
|
|
||||||
|
describe('Account ACL path', () => {
|
||||||
|
let browser;
|
||||||
|
let page;
|
||||||
|
|
||||||
|
beforeAll(async() => {
|
||||||
|
browser = await getBrowser();
|
||||||
|
page = browser.page;
|
||||||
|
await page.loginAndModule('developer', 'account');
|
||||||
|
await page.accessToSection('account.acl');
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async() => {
|
||||||
|
await browser.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should go to create new acl', async() => {
|
||||||
|
await page.waitToClick(selectors.accountAcl.addAcl);
|
||||||
|
await page.waitForState('account.acl.create');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create new acl', async() => {
|
||||||
|
await page.autocompleteSearch(selectors.accountAcl.role, 'sysadmin');
|
||||||
|
await page.autocompleteSearch(selectors.accountAcl.model, 'UserAccount');
|
||||||
|
await page.autocompleteSearch(selectors.accountAcl.accessType, '*');
|
||||||
|
await page.autocompleteSearch(selectors.accountAcl.permission, 'ALLOW');
|
||||||
|
await page.waitToClick(selectors.accountAcl.save);
|
||||||
|
const message = await page.waitForSnackbar();
|
||||||
|
|
||||||
|
expect(message.text).toContain('Data saved!');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should navigate to edit', async() => {
|
||||||
|
await page.doSearch();
|
||||||
|
await page.waitToClick(selectors.accountAcl.thirdAcl);
|
||||||
|
await page.waitForState('account.acl.edit');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should edit the third acl', async() => {
|
||||||
|
await page.autocompleteSearch(selectors.accountAcl.model, 'Supplier');
|
||||||
|
await page.autocompleteSearch(selectors.accountAcl.accessType, 'READ');
|
||||||
|
await page.waitToClick(selectors.accountAcl.save);
|
||||||
|
const message = await page.waitForSnackbar();
|
||||||
|
|
||||||
|
expect(message.text).toContain('Data saved!');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should delete the third result', async() => {
|
||||||
|
const result = await page.waitToGetProperty(selectors.accountAcl.thirdAcl, 'innerText');
|
||||||
|
await page.waitToClick(selectors.accountAcl.deleteThirdAcl);
|
||||||
|
await page.waitToClick(selectors.globalItems.acceptButton);
|
||||||
|
const message = await page.waitForSnackbar();
|
||||||
|
const newResult = await page.waitToGetProperty(selectors.accountAcl.thirdAcl, 'innerText');
|
||||||
|
|
||||||
|
expect(message.text).toContain('ACL removed');
|
||||||
|
expect(result).not.toEqual(newResult);
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,33 @@
|
||||||
|
import selectors from '../../helpers/selectors.js';
|
||||||
|
import getBrowser from '../../helpers/puppeteer';
|
||||||
|
|
||||||
|
describe('Account Connections path', () => {
|
||||||
|
let browser;
|
||||||
|
let page;
|
||||||
|
const account = 'sysadmin';
|
||||||
|
|
||||||
|
beforeAll(async() => {
|
||||||
|
browser = await getBrowser();
|
||||||
|
page = browser.page;
|
||||||
|
await page.loginAndModule(account, 'account');
|
||||||
|
await page.accessToSection('account.connections');
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async() => {
|
||||||
|
await browser.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should check this is the last connection', async() => {
|
||||||
|
const firstResult = await page.waitToGetProperty(selectors.accountConnections.firstConnection, 'innerText');
|
||||||
|
|
||||||
|
expect(firstResult).toContain(account);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should kill this connection and then get redirected to the login page', async() => {
|
||||||
|
await page.waitToClick(selectors.accountConnections.deleteFirstConnection);
|
||||||
|
await page.waitToClick(selectors.globalItems.acceptButton);
|
||||||
|
const message = await page.waitForSnackbar();
|
||||||
|
|
||||||
|
expect(message.text).toContain('Your session has expired, please login again');
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,49 @@
|
||||||
|
import selectors from '../../helpers/selectors.js';
|
||||||
|
import getBrowser from '../../helpers/puppeteer';
|
||||||
|
|
||||||
|
describe('Account Accounts path', () => {
|
||||||
|
let browser;
|
||||||
|
let page;
|
||||||
|
|
||||||
|
beforeAll(async() => {
|
||||||
|
browser = await getBrowser();
|
||||||
|
page = browser.page;
|
||||||
|
await page.loginAndModule('sysadmin', 'account');
|
||||||
|
await page.accessToSection('account.accounts');
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async() => {
|
||||||
|
await browser.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should sync roles', async() => {
|
||||||
|
await page.waitToClick(selectors.accountAccounts.syncRoles);
|
||||||
|
const message = await page.waitForSnackbar();
|
||||||
|
|
||||||
|
expect(message.text).toContain('Roles synchronized!');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should sync user', async() => {
|
||||||
|
await page.waitToClick(selectors.accountAccounts.syncUser);
|
||||||
|
await page.write(selectors.accountAccounts.syncUserName, 'sysadmin');
|
||||||
|
await page.write(selectors.accountAccounts.syncUserPassword, 'nightmare');
|
||||||
|
|
||||||
|
await page.waitToClick(selectors.accountAccounts.buttonAccept);
|
||||||
|
|
||||||
|
const message = await page.waitForSnackbar();
|
||||||
|
|
||||||
|
expect(message.text).toContain('User synchronized!');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should relogin', async() => {
|
||||||
|
await page.loginAndModule('sysadmin', 'account');
|
||||||
|
await page.accessToSection('account.accounts');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should sync all', async() => {
|
||||||
|
await page.waitToClick(selectors.accountAccounts.syncAll);
|
||||||
|
const message = await page.waitForSnackbar();
|
||||||
|
|
||||||
|
expect(message.text).toContain('Synchronizing in the background');
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,32 @@
|
||||||
|
import selectors from '../../helpers/selectors.js';
|
||||||
|
import getBrowser from '../../helpers/puppeteer';
|
||||||
|
|
||||||
|
describe('Account LDAP path', () => {
|
||||||
|
let browser;
|
||||||
|
let page;
|
||||||
|
|
||||||
|
beforeAll(async() => {
|
||||||
|
browser = await getBrowser();
|
||||||
|
page = browser.page;
|
||||||
|
await page.loginAndModule('sysadmin', 'account');
|
||||||
|
await page.accessToSection('account.ldap');
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async() => {
|
||||||
|
await browser.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set data and save', async() => {
|
||||||
|
await page.waitToClick(selectors.accountLdap.checkEnable);
|
||||||
|
await page.write(selectors.accountLdap.server, '1234');
|
||||||
|
await page.write(selectors.accountLdap.rdn, '1234');
|
||||||
|
await page.write(selectors.accountLdap.password, 'nightmare');
|
||||||
|
await page.write(selectors.accountLdap.userDn, 'sysadmin');
|
||||||
|
await page.write(selectors.accountLdap.groupDn, '1234');
|
||||||
|
await page.waitToClick(selectors.accountLdap.save);
|
||||||
|
|
||||||
|
const message = await page.waitForSnackbar();
|
||||||
|
|
||||||
|
expect(message.text).toContain('Data saved!');
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,32 @@
|
||||||
|
import selectors from '../../helpers/selectors.js';
|
||||||
|
import getBrowser from '../../helpers/puppeteer';
|
||||||
|
|
||||||
|
describe('Account Samba path', () => {
|
||||||
|
let browser;
|
||||||
|
let page;
|
||||||
|
|
||||||
|
beforeAll(async() => {
|
||||||
|
browser = await getBrowser();
|
||||||
|
page = browser.page;
|
||||||
|
await page.loginAndModule('sysadmin', 'account');
|
||||||
|
await page.accessToSection('account.samba');
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async() => {
|
||||||
|
await browser.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set data and save', async() => {
|
||||||
|
await page.waitToClick(selectors.accountSamba.checkEnable);
|
||||||
|
await page.write(selectors.accountSamba.adDomain, '1234');
|
||||||
|
await page.write(selectors.accountSamba.adController, '1234');
|
||||||
|
await page.write(selectors.accountSamba.adUser, 'nightmare');
|
||||||
|
await page.write(selectors.accountSamba.adPassword, 'sysadmin');
|
||||||
|
await page.waitToClick(selectors.accountSamba.verifyCert);
|
||||||
|
await page.waitToClick(selectors.accountSamba.save);
|
||||||
|
|
||||||
|
const message = await page.waitForSnackbar();
|
||||||
|
|
||||||
|
expect(message.text).toContain('Data saved!');
|
||||||
|
});
|
||||||
|
});
|
|
@ -318,6 +318,8 @@ export default class SmartTable extends Component {
|
||||||
for (let column of columns) {
|
for (let column of columns) {
|
||||||
const field = column.getAttribute('field');
|
const field = column.getAttribute('field');
|
||||||
const cell = document.createElement('td');
|
const cell = document.createElement('td');
|
||||||
|
cell.setAttribute('centered', '');
|
||||||
|
|
||||||
if (field) {
|
if (field) {
|
||||||
let input;
|
let input;
|
||||||
let options;
|
let options;
|
||||||
|
@ -331,6 +333,15 @@ export default class SmartTable extends Component {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input = this.$compile(`
|
||||||
|
<vn-textfield
|
||||||
|
class="dense"
|
||||||
|
name="${field}"
|
||||||
|
ng-model="searchProps['${field}']"
|
||||||
|
ng-keydown="$ctrl.searchWithEvent($event, '${field}')"
|
||||||
|
clear-disabled="true"
|
||||||
|
/>`)(this.$inputsScope);
|
||||||
|
|
||||||
if (options && options.autocomplete) {
|
if (options && options.autocomplete) {
|
||||||
let props = ``;
|
let props = ``;
|
||||||
|
|
||||||
|
@ -346,16 +357,29 @@ export default class SmartTable extends Component {
|
||||||
on-change="$ctrl.searchByColumn('${field}')"
|
on-change="$ctrl.searchByColumn('${field}')"
|
||||||
clear-disabled="true"
|
clear-disabled="true"
|
||||||
/>`)(this.$inputsScope);
|
/>`)(this.$inputsScope);
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
if (options && options.checkbox) {
|
||||||
input = this.$compile(`
|
input = this.$compile(`
|
||||||
<vn-textfield
|
<vn-check
|
||||||
class="dense"
|
class="dense"
|
||||||
name="${field}"
|
name="${field}"
|
||||||
ng-model="searchProps['${field}']"
|
ng-model="searchProps['${field}']"
|
||||||
ng-keydown="$ctrl.searchWithEvent($event, '${field}')"
|
on-change="$ctrl.searchByColumn('${field}')"
|
||||||
clear-disabled="true"
|
triple-state="true"
|
||||||
/>`)(this.$inputsScope);
|
/>`)(this.$inputsScope);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options && options.datepicker) {
|
||||||
|
input = this.$compile(`
|
||||||
|
<vn-date-picker
|
||||||
|
class="dense"
|
||||||
|
name="${field}"
|
||||||
|
ng-model="searchProps['${field}']"
|
||||||
|
on-change="$ctrl.searchByColumn('${field}')"
|
||||||
|
/>`)(this.$inputsScope);
|
||||||
|
}
|
||||||
|
|
||||||
cell.appendChild(input[0]);
|
cell.appendChild(input[0]);
|
||||||
}
|
}
|
||||||
searchRow.appendChild(cell);
|
searchRow.appendChild(cell);
|
||||||
|
@ -372,13 +396,12 @@ export default class SmartTable extends Component {
|
||||||
|
|
||||||
searchByColumn(field) {
|
searchByColumn(field) {
|
||||||
const searchCriteria = this.$inputsScope.searchProps[field];
|
const searchCriteria = this.$inputsScope.searchProps[field];
|
||||||
const emptySearch = searchCriteria == '' || null;
|
const emptySearch = searchCriteria === '' || searchCriteria == null;
|
||||||
|
|
||||||
const filters = this.filterSanitizer(field);
|
const filters = this.filterSanitizer(field);
|
||||||
|
|
||||||
if (filters && filters.userFilter)
|
if (filters && filters.userFilter)
|
||||||
this.model.userFilter = filters.userFilter;
|
this.model.userFilter = filters.userFilter;
|
||||||
|
|
||||||
if (!emptySearch)
|
if (!emptySearch)
|
||||||
this.addFilter(field, this.$inputsScope.searchProps[field]);
|
this.addFilter(field, this.$inputsScope.searchProps[field]);
|
||||||
else this.model.refresh();
|
else this.model.refresh();
|
||||||
|
|
|
@ -85,7 +85,6 @@
|
||||||
}
|
}
|
||||||
.icon-bucket:before {
|
.icon-bucket:before {
|
||||||
content: "\e97a";
|
content: "\e97a";
|
||||||
color: #000;
|
|
||||||
}
|
}
|
||||||
.icon-buscaman:before {
|
.icon-buscaman:before {
|
||||||
content: "\e93b";
|
content: "\e93b";
|
||||||
|
@ -95,32 +94,26 @@
|
||||||
}
|
}
|
||||||
.icon-calc_volum .path1:before {
|
.icon-calc_volum .path1:before {
|
||||||
content: "\e915";
|
content: "\e915";
|
||||||
color: rgb(0, 0, 0);
|
|
||||||
}
|
}
|
||||||
.icon-calc_volum .path2:before {
|
.icon-calc_volum .path2:before {
|
||||||
content: "\e916";
|
content: "\e916";
|
||||||
margin-left: -1em;
|
margin-left: -1em;
|
||||||
color: rgb(0, 0, 0);
|
|
||||||
}
|
}
|
||||||
.icon-calc_volum .path3:before {
|
.icon-calc_volum .path3:before {
|
||||||
content: "\e917";
|
content: "\e917";
|
||||||
margin-left: -1em;
|
margin-left: -1em;
|
||||||
color: rgb(0, 0, 0);
|
|
||||||
}
|
}
|
||||||
.icon-calc_volum .path4:before {
|
.icon-calc_volum .path4:before {
|
||||||
content: "\e918";
|
content: "\e918";
|
||||||
margin-left: -1em;
|
margin-left: -1em;
|
||||||
color: rgb(0, 0, 0);
|
|
||||||
}
|
}
|
||||||
.icon-calc_volum .path5:before {
|
.icon-calc_volum .path5:before {
|
||||||
content: "\e919";
|
content: "\e919";
|
||||||
margin-left: -1em;
|
margin-left: -1em;
|
||||||
color: rgb(0, 0, 0);
|
|
||||||
}
|
}
|
||||||
.icon-calc_volum .path6:before {
|
.icon-calc_volum .path6:before {
|
||||||
content: "\e91a";
|
content: "\e91a";
|
||||||
margin-left: -1em;
|
margin-left: -1em;
|
||||||
color: rgb(255, 255, 255);
|
|
||||||
}
|
}
|
||||||
.icon-calendar:before {
|
.icon-calendar:before {
|
||||||
content: "\e93d";
|
content: "\e93d";
|
||||||
|
|
|
@ -224,5 +224,7 @@
|
||||||
"The agency is already assigned to another autonomous": "La agencia ya está asignada a otro autónomo",
|
"The agency is already assigned to another autonomous": "La agencia ya está asignada a otro autónomo",
|
||||||
"date in the future": "Fecha en el futuro",
|
"date in the future": "Fecha en el futuro",
|
||||||
"reference duplicated": "Referencia duplicada",
|
"reference duplicated": "Referencia duplicada",
|
||||||
"This ticket is already a refund": "Este ticket ya es un abono"
|
"This ticket is already a refund": "Este ticket ya es un abono",
|
||||||
|
"isWithoutNegatives": "isWithoutNegatives",
|
||||||
|
"routeFk": "routeFk"
|
||||||
}
|
}
|
|
@ -98,5 +98,15 @@
|
||||||
"image/jpg",
|
"image/jpg",
|
||||||
"video/mp4"
|
"video/mp4"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"accessStorage": {
|
||||||
|
"name": "accessStorage",
|
||||||
|
"connector": "loopback-component-storage",
|
||||||
|
"provider": "filesystem",
|
||||||
|
"root": "./storage/access",
|
||||||
|
"maxFileSize": "524288000",
|
||||||
|
"allowedContentTypes": [
|
||||||
|
"application/x-7z-compressed"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -6,7 +6,6 @@ class Controller extends Component {
|
||||||
this._role = value;
|
this._role = value;
|
||||||
this.$.summary = null;
|
this.$.summary = null;
|
||||||
if (!value) return;
|
if (!value) return;
|
||||||
|
|
||||||
this.$http.get(`Roles/${value.id}`)
|
this.$http.get(`Roles/${value.id}`)
|
||||||
.then(res => this.$.summary = res.data);
|
.then(res => this.$.summary = res.data);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<vn-crud-model vn-id="model"
|
<vn-crud-model vn-id="model"
|
||||||
url="ClaimDms"
|
url="ClaimDms"
|
||||||
|
filter="::$ctrl.filter"
|
||||||
data="photos">
|
data="photos">
|
||||||
</vn-crud-model>
|
</vn-crud-model>
|
||||||
<vn-card class="summary">
|
<vn-card class="summary">
|
||||||
|
@ -106,8 +107,13 @@
|
||||||
<section class="photo" ng-repeat="photo in photos">
|
<section class="photo" ng-repeat="photo in photos">
|
||||||
<section class="image" on-error-src
|
<section class="image" on-error-src
|
||||||
ng-style="{'background': 'url(' + $ctrl.getImagePath(photo.dmsFk) + ')'}"
|
ng-style="{'background': 'url(' + $ctrl.getImagePath(photo.dmsFk) + ')'}"
|
||||||
zoom-image="{{$ctrl.getImagePath(photo.dmsFk)}}">
|
zoom-image="{{$ctrl.getImagePath(photo.dmsFk)}}"
|
||||||
|
ng-if="photo.dms.contentType != 'video/mp4'">
|
||||||
</section>
|
</section>
|
||||||
|
<video id="videobcg" muted="muted" controls ng-if="photo.dms.contentType == 'video/mp4'"
|
||||||
|
class="video">
|
||||||
|
<source src="{{$ctrl.getImagePath(photo.dmsFk)}}" type="video/mp4">
|
||||||
|
</video>
|
||||||
</section>
|
</section>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
</vn-auto>
|
</vn-auto>
|
||||||
|
|
|
@ -6,6 +6,13 @@ class Controller extends Summary {
|
||||||
constructor($element, $, vnFile) {
|
constructor($element, $, vnFile) {
|
||||||
super($element, $);
|
super($element, $);
|
||||||
this.vnFile = vnFile;
|
this.vnFile = vnFile;
|
||||||
|
this.filter = {
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
relation: 'dms'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
$onChanges() {
|
$onChanges() {
|
||||||
|
|
|
@ -10,4 +10,19 @@ vn-claim-summary {
|
||||||
vn-textarea *{
|
vn-textarea *{
|
||||||
height: 80px;
|
height: 80px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.video {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
cursor: pointer;
|
||||||
|
box-shadow: 0 2px 2px 0 rgba(0,0,0,.14),
|
||||||
|
0 3px 1px -2px rgba(0,0,0,.2),
|
||||||
|
0 1px 5px 0 rgba(0,0,0,.12);
|
||||||
|
border: 2px solid transparent;
|
||||||
|
|
||||||
|
}
|
||||||
|
.video:hover {
|
||||||
|
border: 2px solid $color-primary
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,159 @@
|
||||||
|
|
||||||
|
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
|
||||||
|
const buildFilter = require('vn-loopback/util/filter').buildFilter;
|
||||||
|
const mergeFilters = require('vn-loopback/util/filter').mergeFilters;
|
||||||
|
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethodCtx('extendedListFilter', {
|
||||||
|
description: 'Find all clients matched by the filter',
|
||||||
|
accessType: 'READ',
|
||||||
|
accepts: [
|
||||||
|
{
|
||||||
|
arg: 'filter',
|
||||||
|
type: 'object',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'search',
|
||||||
|
type: 'string',
|
||||||
|
description: `If it's and integer searchs by id, otherwise it searchs by name`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'name',
|
||||||
|
type: 'string',
|
||||||
|
description: 'The client name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'salesPersonFk',
|
||||||
|
type: 'number',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'fi',
|
||||||
|
type: 'string',
|
||||||
|
description: 'The client fiscal id',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'socialName',
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'city',
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'postcode',
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'provinceFk',
|
||||||
|
type: 'number',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'email',
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'phone',
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
returns: {
|
||||||
|
type: ['object'],
|
||||||
|
root: true
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
path: `/extendedListFilter`,
|
||||||
|
verb: 'GET'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.extendedListFilter = async(ctx, filter, options) => {
|
||||||
|
const conn = Self.dataSource.connector;
|
||||||
|
const myOptions = {};
|
||||||
|
|
||||||
|
if (typeof options == 'object')
|
||||||
|
Object.assign(myOptions, options);
|
||||||
|
|
||||||
|
const where = buildFilter(ctx.args, (param, value) => {
|
||||||
|
switch (param) {
|
||||||
|
case 'search':
|
||||||
|
return /^\d+$/.test(value)
|
||||||
|
? {'c.id': {inq: value}}
|
||||||
|
: {'c.name': {like: `%${value}%`}};
|
||||||
|
case 'name':
|
||||||
|
case 'salesPersonFk':
|
||||||
|
case 'fi':
|
||||||
|
case 'socialName':
|
||||||
|
case 'city':
|
||||||
|
case 'postcode':
|
||||||
|
case 'provinceFk':
|
||||||
|
case 'email':
|
||||||
|
case 'phone':
|
||||||
|
param = `c.${param}`;
|
||||||
|
return {[param]: value};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
filter = mergeFilters(filter, {where});
|
||||||
|
|
||||||
|
const stmts = [];
|
||||||
|
const stmt = new ParameterizedSQL(
|
||||||
|
`SELECT
|
||||||
|
c.id,
|
||||||
|
c.name,
|
||||||
|
c.socialName,
|
||||||
|
c.fi,
|
||||||
|
c.credit,
|
||||||
|
c.creditInsurance,
|
||||||
|
c.phone,
|
||||||
|
c.mobile,
|
||||||
|
c.street,
|
||||||
|
c.city,
|
||||||
|
c.postcode,
|
||||||
|
c.email,
|
||||||
|
c.created,
|
||||||
|
c.isActive,
|
||||||
|
c.isVies,
|
||||||
|
c.isTaxDataChecked,
|
||||||
|
c.isEqualizated,
|
||||||
|
c.isFreezed,
|
||||||
|
c.hasToInvoice,
|
||||||
|
c.hasToInvoiceByAddress,
|
||||||
|
c.isToBeMailed,
|
||||||
|
c.hasSepaVnl,
|
||||||
|
c.hasLcr,
|
||||||
|
c.hasCoreVnl,
|
||||||
|
ct.id AS countryFk,
|
||||||
|
ct.country,
|
||||||
|
p.id AS provinceFk,
|
||||||
|
p.name AS province,
|
||||||
|
u.id AS salesPersonFk,
|
||||||
|
u.name AS salesPerson,
|
||||||
|
bt.code AS businessTypeFk,
|
||||||
|
bt.description AS businessType,
|
||||||
|
pm.id AS payMethodFk,
|
||||||
|
pm.name AS payMethod,
|
||||||
|
sti.CodigoIva AS sageTaxTypeFk,
|
||||||
|
sti.Iva AS sageTaxType,
|
||||||
|
stt.CodigoTransaccion AS sageTransactionTypeFk,
|
||||||
|
stt.Transaccion AS sageTransactionType
|
||||||
|
FROM client c
|
||||||
|
LEFT JOIN account.user u ON u.id = c.salesPersonFk
|
||||||
|
LEFT JOIN country ct ON ct.id = c.countryFk
|
||||||
|
LEFT JOIN province p ON p.id = c.provinceFk
|
||||||
|
LEFT JOIN businessType bt ON bt.code = c.businessTypeFk
|
||||||
|
LEFT JOIN payMethod pm ON pm.id = c.payMethodFk
|
||||||
|
LEFT JOIN sage.TiposIva sti ON sti.CodigoIva = c.taxTypeSageFk
|
||||||
|
LEFT JOIN sage.TiposTransacciones stt ON stt.CodigoTransaccion = c.transactionTypeSageFk
|
||||||
|
`
|
||||||
|
);
|
||||||
|
|
||||||
|
stmt.merge(conn.makeWhere(filter.where));
|
||||||
|
stmt.merge(conn.makePagination(filter));
|
||||||
|
|
||||||
|
const clientsIndex = stmts.push(stmt) - 1;
|
||||||
|
const sql = ParameterizedSQL.join(stmts, ';');
|
||||||
|
const result = await conn.executeStmt(sql, myOptions);
|
||||||
|
|
||||||
|
return clientsIndex === 0 ? result : result[clientsIndex];
|
||||||
|
};
|
||||||
|
};
|
|
@ -39,7 +39,7 @@ module.exports = Self => {
|
||||||
|
|
||||||
const userId = ctx.req.accessToken.userId;
|
const userId = ctx.req.accessToken.userId;
|
||||||
|
|
||||||
const sms = await models.Sms.send(ctx, id, destination, message);
|
const sms = await models.Sms.send(ctx, destination, message);
|
||||||
const logRecord = {
|
const logRecord = {
|
||||||
originFk: id,
|
originFk: id,
|
||||||
userFk: userId,
|
userFk: userId,
|
||||||
|
|
|
@ -0,0 +1,180 @@
|
||||||
|
const { models } = require('vn-loopback/server/server');
|
||||||
|
|
||||||
|
describe('client extendedListFilter()', () => {
|
||||||
|
it('should return the clients matching the filter with a limit of 20 rows', async() => {
|
||||||
|
const tx = await models.Client.beginTransaction({});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
const ctx = {req: {accessToken: {userId: 1}}, args: {}};
|
||||||
|
const filter = {limit: '20'};
|
||||||
|
const result = await models.Client.extendedListFilter(ctx, filter, options);
|
||||||
|
|
||||||
|
expect(result.length).toEqual(20);
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the client "Bruce Wayne" matching the search argument with his name', async() => {
|
||||||
|
const tx = await models.Client.beginTransaction({});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
const ctx = {req: {accessToken: {userId: 1}}, args: {search: 'Bruce Wayne'}};
|
||||||
|
const filter = {};
|
||||||
|
const result = await models.Client.extendedListFilter(ctx, filter, options);
|
||||||
|
|
||||||
|
const firstResult = result[0];
|
||||||
|
|
||||||
|
expect(result.length).toEqual(1);
|
||||||
|
expect(firstResult.name).toEqual('Bruce Wayne');
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the client "Bruce Wayne" matching the search argument with his id', async() => {
|
||||||
|
const tx = await models.Client.beginTransaction({});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
const ctx = {req: {accessToken: {userId: 1}}, args: {search: '1101'}};
|
||||||
|
const filter = {};
|
||||||
|
const result = await models.Client.extendedListFilter(ctx, filter, options);
|
||||||
|
|
||||||
|
const firstResult = result[0];
|
||||||
|
|
||||||
|
expect(result.length).toEqual(1);
|
||||||
|
expect(firstResult.name).toEqual('Bruce Wayne');
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the client "Bruce Wayne" matching the name argument', async() => {
|
||||||
|
const tx = await models.Client.beginTransaction({});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
const ctx = {req: {accessToken: {userId: 1}}, args: {name: 'Bruce Wayne'}};
|
||||||
|
const filter = {};
|
||||||
|
const result = await models.Client.extendedListFilter(ctx, filter, options);
|
||||||
|
|
||||||
|
const firstResult = result[0];
|
||||||
|
|
||||||
|
expect(result.length).toEqual(1);
|
||||||
|
expect(firstResult.name).toEqual('Bruce Wayne');
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the clients matching the "salesPersonFk" argument', async() => {
|
||||||
|
const tx = await models.Client.beginTransaction({});
|
||||||
|
const salesPersonId = 18;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
const ctx = {req: {accessToken: {userId: 1}}, args: {salesPersonFk: salesPersonId}};
|
||||||
|
const filter = {};
|
||||||
|
const result = await models.Client.extendedListFilter(ctx, filter, options);
|
||||||
|
|
||||||
|
const randomIndex = Math.floor(Math.random() * result.length);
|
||||||
|
const randomResultClient = result[randomIndex];
|
||||||
|
|
||||||
|
expect(result.length).toBeGreaterThanOrEqual(5);
|
||||||
|
expect(randomResultClient.salesPersonFk).toEqual(salesPersonId);
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the clients matching the "fi" argument', async() => {
|
||||||
|
const tx = await models.Client.beginTransaction({});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
const ctx = {req: {accessToken: {userId: 1}}, args: {fi: '251628698'}};
|
||||||
|
const filter = {};
|
||||||
|
const result = await models.Client.extendedListFilter(ctx, filter, options);
|
||||||
|
|
||||||
|
const firstClient = result[0];
|
||||||
|
|
||||||
|
expect(result.length).toEqual(1);
|
||||||
|
expect(firstClient.name).toEqual('Max Eisenhardt');
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the clients matching the "city" argument', async() => {
|
||||||
|
const tx = await models.Client.beginTransaction({});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
const ctx = {req: {accessToken: {userId: 1}}, args: {city: 'Silla'}};
|
||||||
|
const filter = {};
|
||||||
|
const result = await models.Client.extendedListFilter(ctx, filter, options);
|
||||||
|
|
||||||
|
const randomIndex = Math.floor(Math.random() * result.length);
|
||||||
|
const randomResultClient = result[randomIndex];
|
||||||
|
|
||||||
|
expect(result.length).toBeGreaterThanOrEqual(20);
|
||||||
|
expect(randomResultClient.city.toLowerCase()).toEqual('silla');
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the clients matching the "postcode" argument', async() => {
|
||||||
|
const tx = await models.Client.beginTransaction({});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
const ctx = {req: {accessToken: {userId: 1}}, args: {postcode: '46460'}};
|
||||||
|
const filter = {};
|
||||||
|
const result = await models.Client.extendedListFilter(ctx, filter, options);
|
||||||
|
|
||||||
|
const randomIndex = Math.floor(Math.random() * result.length);
|
||||||
|
const randomResultClient = result[randomIndex];
|
||||||
|
|
||||||
|
expect(result.length).toBeGreaterThanOrEqual(20);
|
||||||
|
expect(randomResultClient.postcode).toEqual('46460');
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,21 +1,39 @@
|
||||||
const models = require('vn-loopback/server/server').models;
|
const models = require('vn-loopback/server/server').models;
|
||||||
|
const LoopBackContext = require('loopback-context');
|
||||||
|
|
||||||
describe('Client updatePortfolio', () => {
|
describe('Client updatePortfolio', () => {
|
||||||
const clientId = 1108;
|
const activeCtx = {
|
||||||
|
accessToken: {userId: 9},
|
||||||
|
http: {
|
||||||
|
req: {
|
||||||
|
headers: {origin: 'http://localhost'},
|
||||||
|
[`__`]: value => {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||||
|
active: activeCtx
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should update the portfolioWeight when the salesPerson of a client changes', async() => {
|
it('should update the portfolioWeight when the salesPerson of a client changes', async() => {
|
||||||
|
const clientId = 1108;
|
||||||
const salesPersonId = 18;
|
const salesPersonId = 18;
|
||||||
|
|
||||||
const tx = await models.Client.beginTransaction({});
|
const tx = await models.Client.beginTransaction({});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const options = {transaction: tx};
|
const options = {transaction: tx};
|
||||||
|
|
||||||
const expectedResult = 841.63;
|
const expectedResult = 841.63;
|
||||||
|
|
||||||
const clientQuery = `UPDATE vn.client SET salesPersonFk = ${salesPersonId} WHERE id = ${clientId}; `;
|
const client = await models.Client.findById(clientId, null, options);
|
||||||
await models.Client.rawSql(clientQuery);
|
await client.updateAttribute('salesPersonFk', salesPersonId, options);
|
||||||
|
|
||||||
await models.Client.updatePortfolio();
|
await models.Client.updatePortfolio(options);
|
||||||
|
|
||||||
const portfolioQuery = `SELECT portfolioWeight FROM bs.salesPerson WHERE workerFk = ${salesPersonId}; `;
|
const portfolioQuery = `SELECT portfolioWeight FROM bs.salesPerson WHERE workerFk = ${salesPersonId}; `;
|
||||||
const [salesPerson] = await models.Client.rawSql(portfolioQuery, null, options);
|
const [salesPerson] = await models.Client.rawSql(portfolioQuery, null, options);
|
||||||
|
@ -30,21 +48,21 @@ describe('Client updatePortfolio', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should keep the same portfolioWeight when a salesperson is unassigned of a client', async() => {
|
it('should keep the same portfolioWeight when a salesperson is unassigned of a client', async() => {
|
||||||
pending('task 3817');
|
const clientId = 1107;
|
||||||
const salesPersonId = 19;
|
const salesPersonId = 19;
|
||||||
const tx = await models.Client.beginTransaction({});
|
const tx = await models.Client.beginTransaction({});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const options = {transaction: tx};
|
const options = {transaction: tx};
|
||||||
|
|
||||||
const expectedResult = 34.40;
|
const expectedResult = 34.40;
|
||||||
|
|
||||||
await models.Client.rawSql(`UPDATE vn.client SET salesPersonFk = NULL WHERE id = ${clientId}; `);
|
const client = await models.Client.findById(clientId, null, options);
|
||||||
|
await client.updateAttribute('salesPersonFk', null, options);
|
||||||
|
|
||||||
await models.Client.updatePortfolio();
|
await models.Client.updatePortfolio();
|
||||||
|
|
||||||
const portfolioQuery = `SELECT portfolioWeight FROM bs.salesPerson WHERE workerFk = ${salesPersonId}; `;
|
const portfolioQuery = `SELECT portfolioWeight FROM bs.salesPerson WHERE workerFk = ${salesPersonId}; `;
|
||||||
const [salesPerson] = await models.Client.rawSql(portfolioQuery, null, options);
|
const [salesPerson] = await models.Client.rawSql(portfolioQuery);
|
||||||
|
|
||||||
expect(salesPerson.portfolioWeight).toEqual(expectedResult);
|
expect(salesPerson.portfolioWeight).toEqual(expectedResult);
|
||||||
|
|
||||||
|
|
|
@ -13,8 +13,13 @@ module.exports = function(Self) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Self.updatePortfolio = async() => {
|
Self.updatePortfolio = async options => {
|
||||||
|
const myOptions = {};
|
||||||
|
|
||||||
|
if (typeof options == 'object')
|
||||||
|
Object.assign(myOptions, options);
|
||||||
|
|
||||||
query = `CALL bs.salesPerson_updatePortfolio()`;
|
query = `CALL bs.salesPerson_updatePortfolio()`;
|
||||||
return await Self.rawSql(query);
|
return Self.rawSql(query, null, myOptions);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -38,7 +38,7 @@ module.exports = Self => {
|
||||||
}, myOptions);
|
}, myOptions);
|
||||||
|
|
||||||
await models.CreditInsurance.create({
|
await models.CreditInsurance.create({
|
||||||
creditClassification: newClassification.id,
|
creditClassificationFk: newClassification.id,
|
||||||
credit: data.credit,
|
credit: data.credit,
|
||||||
grade: data.grade
|
grade: data.grade
|
||||||
}, myOptions);
|
}, myOptions);
|
||||||
|
|
|
@ -6,10 +6,6 @@ module.exports = Self => {
|
||||||
description: 'Sends SMS to a destination phone',
|
description: 'Sends SMS to a destination phone',
|
||||||
accessType: 'WRITE',
|
accessType: 'WRITE',
|
||||||
accepts: [
|
accepts: [
|
||||||
{
|
|
||||||
arg: 'destinationFk',
|
|
||||||
type: 'integer'
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
arg: 'destination',
|
arg: 'destination',
|
||||||
type: 'string',
|
type: 'string',
|
||||||
|
@ -31,7 +27,7 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Self.send = async(ctx, destinationFk, destination, message) => {
|
Self.send = async(ctx, destination, message) => {
|
||||||
const userId = ctx.req.accessToken.userId;
|
const userId = ctx.req.accessToken.userId;
|
||||||
const smsConfig = await Self.app.models.SmsConfig.findOne();
|
const smsConfig = await Self.app.models.SmsConfig.findOne();
|
||||||
|
|
||||||
|
@ -68,7 +64,6 @@ module.exports = Self => {
|
||||||
|
|
||||||
const newSms = {
|
const newSms = {
|
||||||
senderFk: userId,
|
senderFk: userId,
|
||||||
destinationFk: destinationFk || null,
|
|
||||||
destination: destination,
|
destination: destination,
|
||||||
message: message,
|
message: message,
|
||||||
status: error
|
status: error
|
||||||
|
|
|
@ -3,7 +3,7 @@ const app = require('vn-loopback/server/server');
|
||||||
describe('sms send()', () => {
|
describe('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, '123456789', 'My SMS Body');
|
||||||
|
|
||||||
expect(result.status).toBeUndefined();
|
expect(result.status).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
|
@ -31,6 +31,7 @@ module.exports = Self => {
|
||||||
require('../methods/client/createReceipt')(Self);
|
require('../methods/client/createReceipt')(Self);
|
||||||
require('../methods/client/updatePortfolio')(Self);
|
require('../methods/client/updatePortfolio')(Self);
|
||||||
require('../methods/client/checkDuplicated')(Self);
|
require('../methods/client/checkDuplicated')(Self);
|
||||||
|
require('../methods/client/extendedListFilter')(Self);
|
||||||
|
|
||||||
// Validations
|
// Validations
|
||||||
|
|
||||||
|
|
|
@ -136,6 +136,9 @@
|
||||||
"mysql": {
|
"mysql": {
|
||||||
"columnName": "businessTypeFk"
|
"columnName": "businessTypeFk"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"salesPersonFk": {
|
||||||
|
"type": "number"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"relations": {
|
"relations": {
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
"insurances": {
|
"insurances": {
|
||||||
"type": "hasMany",
|
"type": "hasMany",
|
||||||
"model": "CreditInsurance",
|
"model": "CreditInsurance",
|
||||||
"foreignKey": "creditClassification"
|
"foreignKey": "creditClassificationFk"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -24,7 +24,7 @@ module.exports = function(Self) {
|
||||||
let filter = {
|
let filter = {
|
||||||
fields: ['grade'],
|
fields: ['grade'],
|
||||||
where: {
|
where: {
|
||||||
creditClassification: this.creditClassification
|
creditClassificationFk: this.creditClassificationFk
|
||||||
},
|
},
|
||||||
order: 'created DESC'
|
order: 'created DESC'
|
||||||
};
|
};
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
"classification": {
|
"classification": {
|
||||||
"type": "belongsTo",
|
"type": "belongsTo",
|
||||||
"model": "CreditClassification",
|
"model": "CreditClassification",
|
||||||
"foreignKey": "creditClassification"
|
"foreignKey": "creditClassificationFk"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"scope": {
|
"scope": {
|
||||||
|
|
|
@ -6,12 +6,7 @@ class Controller extends Dialog {
|
||||||
super($element, $, $transclude);
|
super($element, $, $transclude);
|
||||||
|
|
||||||
this.vnReport = vnReport;
|
this.vnReport = vnReport;
|
||||||
|
this.receipt = {};
|
||||||
const tomorrow = new Date();
|
|
||||||
tomorrow.setDate(tomorrow.getDate() + 1);
|
|
||||||
this.receipt = {
|
|
||||||
payed: tomorrow
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
set payed(value) {
|
set payed(value) {
|
||||||
|
@ -72,6 +67,10 @@ class Controller extends Dialog {
|
||||||
`${accountingType && accountingType.receiptDescription}`;
|
`${accountingType && accountingType.receiptDescription}`;
|
||||||
}
|
}
|
||||||
this.maxAmount = accountingType && accountingType.maxAmount;
|
this.maxAmount = accountingType && accountingType.maxAmount;
|
||||||
|
|
||||||
|
this.receipt.payed = new Date();
|
||||||
|
if (accountingType.daysInFuture)
|
||||||
|
this.receipt.payed.setDate(this.receipt.payed.getDate() + accountingType.daysInFuture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,14 +54,7 @@
|
||||||
show-field="bic"
|
show-field="bic"
|
||||||
vn-acl="salesAssistant"
|
vn-acl="salesAssistant"
|
||||||
disabled="$ctrl.ibanCountry == 'ES'">
|
disabled="$ctrl.ibanCountry == 'ES'">
|
||||||
<tpl-item>
|
<tpl-item>{{bic}} {{name}}</tpl-item>
|
||||||
<vn-horizontal>
|
|
||||||
<vn-one>{{bic}}</vn-one>
|
|
||||||
<vn-one>
|
|
||||||
<div class="ellipsize" style="max-width: 10em">{{name}}</div>
|
|
||||||
</vn-one>
|
|
||||||
</vn-horizontal>
|
|
||||||
</tpl-item>
|
|
||||||
<append>
|
<append>
|
||||||
<vn-icon-button
|
<vn-icon-button
|
||||||
vn-auto
|
vn-auto
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<vn-crud-model
|
<vn-crud-model
|
||||||
vn-id="model"
|
vn-id="model"
|
||||||
url="CreditInsurances"
|
url="CreditInsurances"
|
||||||
link="{creditClassification: $ctrl.$params.classificationId}"
|
link="{creditClassificationFk: $ctrl.$params.classificationId}"
|
||||||
limit="20"
|
limit="20"
|
||||||
data="insurances"
|
data="insurances"
|
||||||
auto-load="true">
|
auto-load="true">
|
||||||
|
|
|
@ -0,0 +1,319 @@
|
||||||
|
<vn-crud-model
|
||||||
|
vn-id="model"
|
||||||
|
url="Clients/extendedListFilter"
|
||||||
|
limit="20">
|
||||||
|
</vn-crud-model>
|
||||||
|
<vn-portal slot="topbar">
|
||||||
|
<vn-searchbar
|
||||||
|
vn-focus
|
||||||
|
panel="vn-client-search-panel"
|
||||||
|
placeholder="Search client"
|
||||||
|
info="Search client by id or name"
|
||||||
|
auto-state="false"
|
||||||
|
model="model">
|
||||||
|
</vn-searchbar>
|
||||||
|
</vn-portal>
|
||||||
|
<vn-card>
|
||||||
|
<smart-table
|
||||||
|
model="model"
|
||||||
|
view-config-id="clientsDetail"
|
||||||
|
options="$ctrl.smartTableOptions"
|
||||||
|
expr-builder="$ctrl.exprBuilder(param, value)">
|
||||||
|
<slot-table>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th></th>
|
||||||
|
<th field="id">
|
||||||
|
<span translate>Identifier</span>
|
||||||
|
</th>
|
||||||
|
<th field="name">
|
||||||
|
<span translate>Name</span>
|
||||||
|
</th>
|
||||||
|
<th field="socialName">
|
||||||
|
<span translate>Social name</span>
|
||||||
|
</th>
|
||||||
|
<th field="fi">
|
||||||
|
<span translate>Tax number</span>
|
||||||
|
</th>
|
||||||
|
<th field="salesPersonFk">
|
||||||
|
<span translate>Salesperson</span>
|
||||||
|
</th>
|
||||||
|
<th field="credit">
|
||||||
|
<span translate>Credit</span>
|
||||||
|
</th>
|
||||||
|
<th field="creditInsurance">
|
||||||
|
<span translate>Credit insurance</span>
|
||||||
|
</th>
|
||||||
|
<th field="phone">
|
||||||
|
<span translate>Phone</span>
|
||||||
|
</th>
|
||||||
|
<th field="mobile">
|
||||||
|
<span translate>Mobile</span>
|
||||||
|
</th>
|
||||||
|
<th field="street">
|
||||||
|
<span translate>Street</span>
|
||||||
|
</th>
|
||||||
|
<th field="countryFk">
|
||||||
|
<span translate>Country</span>
|
||||||
|
</th>
|
||||||
|
<th field="provinceFk">
|
||||||
|
<span translate>Province</span>
|
||||||
|
</th>
|
||||||
|
<th field="city">
|
||||||
|
<span translate>City</span>
|
||||||
|
</th>
|
||||||
|
<th field="postcode">
|
||||||
|
<span translate>Postcode</span>
|
||||||
|
</th>
|
||||||
|
<th field="email">
|
||||||
|
<span translate>Email</span>
|
||||||
|
</th>
|
||||||
|
<th field="created">
|
||||||
|
<span translate>Created</span>
|
||||||
|
</th>
|
||||||
|
<th field="businessTypeFk">
|
||||||
|
<span translate>Business type</span>
|
||||||
|
</th>
|
||||||
|
<th field="payMethodFk">
|
||||||
|
<span translate>Billing data</span>
|
||||||
|
</th>
|
||||||
|
<th field="sageTaxTypeFk">
|
||||||
|
<span translate>Sage tax type</span>
|
||||||
|
</th>
|
||||||
|
<th field="sageTransactionTypeFk">
|
||||||
|
<span translate>Sage tr. type</span>
|
||||||
|
</th>
|
||||||
|
<th field="isActive" centered>
|
||||||
|
<span translate>Active</span>
|
||||||
|
</th>
|
||||||
|
<th field="isVies" centered>
|
||||||
|
<span translate>Vies</span>
|
||||||
|
</th>
|
||||||
|
<th field="isTaxDataChecked" centered>
|
||||||
|
<span translate>Verified data</span>
|
||||||
|
</th>
|
||||||
|
<th field="isEqualizated" centered>
|
||||||
|
<span translate>Is equalizated</span>
|
||||||
|
</th>
|
||||||
|
<th field="isFreezed" centered>
|
||||||
|
<span translate>Freezed</span>
|
||||||
|
</th>
|
||||||
|
<th field="hasToInvoice" centered>
|
||||||
|
<span translate>Invoice</span>
|
||||||
|
</th>
|
||||||
|
<th field="hasToInvoiceByAddress" centered>
|
||||||
|
<span translate>Invoice by address</span>
|
||||||
|
</th>
|
||||||
|
<th field="isToBeMailed" centered>
|
||||||
|
<span translate>Mailing</span>
|
||||||
|
</th>
|
||||||
|
<th field="hasLcr" centered>
|
||||||
|
<span translate>Received LCR</span>
|
||||||
|
</th>
|
||||||
|
<th field="hasCoreVnl" centered>
|
||||||
|
<span translate>Received core VNL</span>
|
||||||
|
</th>
|
||||||
|
<th field="hasSepaVnl" centered>
|
||||||
|
<span translate>Received B2B VNL</span>
|
||||||
|
</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr ng-repeat="client in model.data"
|
||||||
|
vn-anchor="::{
|
||||||
|
state: 'client.card.summary',
|
||||||
|
params: {id: client.id}
|
||||||
|
}">
|
||||||
|
<td>
|
||||||
|
<vn-icon-button ng-show="::client.isActive == false"
|
||||||
|
vn-tooltip="Client inactive"
|
||||||
|
icon="icon-disabled">
|
||||||
|
</vn-icon-button>
|
||||||
|
<vn-icon-button ng-show="::client.isActive && client.isFreezed == true"
|
||||||
|
vn-tooltip="Client frozen"
|
||||||
|
icon="icon-frozen">
|
||||||
|
</vn-icon-button>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span
|
||||||
|
vn-click-stop="clientDescriptor.show($event, client.id)"
|
||||||
|
class="link">
|
||||||
|
{{::client.id}}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>{{::client.name}}</td>
|
||||||
|
<td>{{::client.socialName}}</td>
|
||||||
|
<td>{{::client.fi}}</td>
|
||||||
|
<td>
|
||||||
|
<span
|
||||||
|
vn-click-stop="workerDescriptor.show($event, client.salesPersonFk)"
|
||||||
|
ng-class="{'link': client.salesPersonFk}">
|
||||||
|
{{::client.salesPerson | dashIfEmpty}}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>{{::client.credit}}</td>
|
||||||
|
<td>{{::client.creditInsurance | dashIfEmpty}}</td>
|
||||||
|
<td>{{::client.phone | dashIfEmpty}}</td>
|
||||||
|
<td>{{::client.mobile | dashIfEmpty}}</td>
|
||||||
|
<td>{{::client.street | dashIfEmpty}}</td>
|
||||||
|
<td>{{::client.country | dashIfEmpty}}</td>
|
||||||
|
<td>{{::client.province | dashIfEmpty}}</td>
|
||||||
|
<td>{{::client.city | dashIfEmpty}}</td>
|
||||||
|
<td>{{::client.postcode | dashIfEmpty}}</td>
|
||||||
|
<td>{{::client.email | dashIfEmpty}}</td>
|
||||||
|
<td>{{::client.created | date:'dd/MM/yyyy'}}</td>
|
||||||
|
<td>{{::client.businessType | dashIfEmpty}}</td>
|
||||||
|
<td>{{::client.payMethod | dashIfEmpty}}</td>
|
||||||
|
<td>{{::client.sageTaxType | dashIfEmpty}}</td>
|
||||||
|
<td>{{::client.sageTransactionType | dashIfEmpty}}</td>
|
||||||
|
<td centered>
|
||||||
|
<vn-chip ng-class="::{
|
||||||
|
'success': client.isActive,
|
||||||
|
'alert': !client.isActive,
|
||||||
|
}">
|
||||||
|
{{ ::client.isActive ? 'Yes' : 'No' | translate}}
|
||||||
|
</vn-chip>
|
||||||
|
</td>
|
||||||
|
<td centered>
|
||||||
|
<vn-chip ng-class="::{
|
||||||
|
'success': client.isVies,
|
||||||
|
'alert': !client.isVies,
|
||||||
|
}">
|
||||||
|
{{ ::client.isVies ? 'Yes' : 'No' | translate}}
|
||||||
|
</vn-chip>
|
||||||
|
</td>
|
||||||
|
<td centered>
|
||||||
|
<vn-chip ng-class="::{
|
||||||
|
'success': client.isTaxDataChecked,
|
||||||
|
'alert': !client.isTaxDataChecked,
|
||||||
|
}">
|
||||||
|
{{ ::client.isTaxDataChecked ? 'Yes' : 'No' | translate}}
|
||||||
|
</vn-chip>
|
||||||
|
</td>
|
||||||
|
<td centered>
|
||||||
|
<vn-chip ng-class="::{
|
||||||
|
'success': client.isEqualizated,
|
||||||
|
'alert': !client.isEqualizated,
|
||||||
|
}">
|
||||||
|
{{ ::client.isEqualizated ? 'Yes' : 'No' | translate}}
|
||||||
|
</vn-chip>
|
||||||
|
</td>
|
||||||
|
<td centered>
|
||||||
|
<vn-chip ng-class="::{
|
||||||
|
'success': client.isFreezed,
|
||||||
|
'alert': !client.isFreezed,
|
||||||
|
}">
|
||||||
|
{{ ::client.isFreezed ? 'Yes' : 'No' | translate}}
|
||||||
|
</vn-chip>
|
||||||
|
</td>
|
||||||
|
<td centered>
|
||||||
|
<vn-chip ng-class="::{
|
||||||
|
'success': client.hasToInvoice,
|
||||||
|
'alert': !client.hasToInvoice,
|
||||||
|
}">
|
||||||
|
{{ ::client.hasToInvoice ? 'Yes' : 'No' | translate}}
|
||||||
|
</vn-chip>
|
||||||
|
</td>
|
||||||
|
<td centered>
|
||||||
|
<vn-chip ng-class="::{
|
||||||
|
'success': client.hasToInvoiceByAddress,
|
||||||
|
'alert': !client.hasToInvoiceByAddress,
|
||||||
|
}">
|
||||||
|
{{ ::client.hasToInvoiceByAddress ? 'Yes' : 'No' | translate}}
|
||||||
|
</vn-chip>
|
||||||
|
</td>
|
||||||
|
<td centered>
|
||||||
|
<vn-chip ng-class="::{
|
||||||
|
'success': client.isToBeMailed,
|
||||||
|
'alert': !client.isToBeMailed,
|
||||||
|
}">
|
||||||
|
{{ ::client.isToBeMailed ? 'Yes' : 'No' | translate}}
|
||||||
|
</vn-chip>
|
||||||
|
</td>
|
||||||
|
<td centered>
|
||||||
|
<vn-chip ng-class="::{
|
||||||
|
'success': client.hasLcr,
|
||||||
|
'alert': !client.hasLcr,
|
||||||
|
}">
|
||||||
|
{{ ::client.hasLcr ? 'Yes' : 'No' | translate}}
|
||||||
|
</vn-chip>
|
||||||
|
</td>
|
||||||
|
<td centered>
|
||||||
|
<vn-chip ng-class="::{
|
||||||
|
'success': client.hasCoreVnl,
|
||||||
|
'alert': !client.hasCoreVnl,
|
||||||
|
}">
|
||||||
|
{{ ::client.hasCoreVnl ? 'Yes' : 'No' | translate}}
|
||||||
|
</vn-chip>
|
||||||
|
</td>
|
||||||
|
<td centered>
|
||||||
|
<vn-chip ng-class="::{
|
||||||
|
'success': client.hasSepaVnl,
|
||||||
|
'alert': !client.hasSepaVnl,
|
||||||
|
}">
|
||||||
|
{{ ::client.hasSepaVnl ? 'Yes' : 'No' | translate}}
|
||||||
|
</vn-chip>
|
||||||
|
</td>
|
||||||
|
<td shrink>
|
||||||
|
<vn-horizontal class="buttons">
|
||||||
|
<vn-icon-button vn-anchor="{state: 'ticket.index', params: {q: {clientFk: client.id} } }"
|
||||||
|
vn-tooltip="Client tickets"
|
||||||
|
icon="icon-ticket">
|
||||||
|
</vn-icon-button>
|
||||||
|
<vn-icon-button
|
||||||
|
vn-click-stop="$ctrl.preview(client)"
|
||||||
|
vn-tooltip="Preview"
|
||||||
|
icon="preview">
|
||||||
|
</vn-icon-button>
|
||||||
|
</vn-horizontal>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</slot-table>
|
||||||
|
</smart-table>
|
||||||
|
</vn-card>
|
||||||
|
<a ui-sref="client.create" vn-tooltip="New client" vn-bind="+" fixed-bottom-right>
|
||||||
|
<vn-float-button icon="add"></vn-float-button>
|
||||||
|
</a>
|
||||||
|
<vn-client-descriptor-popover
|
||||||
|
vn-id="client-descriptor">
|
||||||
|
</vn-client-descriptor-popover>
|
||||||
|
<vn-worker-descriptor-popover
|
||||||
|
vn-id="worker-descriptor">
|
||||||
|
</vn-worker-descriptor-popover>
|
||||||
|
|
||||||
|
<vn-popup vn-id="preview">
|
||||||
|
<vn-client-summary
|
||||||
|
client="$ctrl.clientSelected">
|
||||||
|
</vn-client-summary>
|
||||||
|
</vn-popup>
|
||||||
|
<vn-contextmenu
|
||||||
|
vn-id="contextmenu"
|
||||||
|
targets="['smart-table']"
|
||||||
|
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>
|
||||||
|
</slot-menu>
|
||||||
|
</vn-contextmenu>
|
|
@ -0,0 +1,184 @@
|
||||||
|
import ngModule from '../module';
|
||||||
|
import Section from 'salix/components/section';
|
||||||
|
import './style.scss';
|
||||||
|
|
||||||
|
class Controller extends Section {
|
||||||
|
constructor($element, $) {
|
||||||
|
super($element, $);
|
||||||
|
|
||||||
|
this.smartTableOptions = {
|
||||||
|
activeButtons: {
|
||||||
|
search: true,
|
||||||
|
shownColumns: true,
|
||||||
|
},
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
field: 'socialName',
|
||||||
|
autocomplete: {
|
||||||
|
url: 'Clients',
|
||||||
|
showField: 'socialName',
|
||||||
|
valueField: 'socialName',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'created',
|
||||||
|
datepicker: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'countryFk',
|
||||||
|
autocomplete: {
|
||||||
|
url: 'Countries',
|
||||||
|
showField: 'country',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'provinceFk',
|
||||||
|
autocomplete: {
|
||||||
|
url: 'Provinces'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'salesPersonFk',
|
||||||
|
autocomplete: {
|
||||||
|
url: 'Workers/activeWithInheritedRole',
|
||||||
|
where: `{role: 'salesPerson'}`,
|
||||||
|
searchFunction: '{firstName: $search}',
|
||||||
|
showField: 'nickname',
|
||||||
|
valueField: 'id',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'businessTypeFk',
|
||||||
|
autocomplete: {
|
||||||
|
url: 'BusinessTypes',
|
||||||
|
valueField: 'code',
|
||||||
|
showField: 'description',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'payMethodFk',
|
||||||
|
autocomplete: {
|
||||||
|
url: 'PayMethods',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'sageTaxTypeFk',
|
||||||
|
autocomplete: {
|
||||||
|
url: 'SageTaxTypes',
|
||||||
|
showField: 'vat',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'sageTransactionTypeFk',
|
||||||
|
autocomplete: {
|
||||||
|
url: 'SageTransactionTypes',
|
||||||
|
showField: 'transaction',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'isActive',
|
||||||
|
checkbox: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'isVies',
|
||||||
|
checkbox: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'isTaxDataChecked',
|
||||||
|
checkbox: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'isEqualizated',
|
||||||
|
checkbox: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'isFreezed',
|
||||||
|
checkbox: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'hasToInvoice',
|
||||||
|
checkbox: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'hasToInvoiceByAddress',
|
||||||
|
checkbox: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'isToBeMailed',
|
||||||
|
checkbox: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'hasSepaVnl',
|
||||||
|
checkbox: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'hasLcr',
|
||||||
|
checkbox: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'hasCoreVnl',
|
||||||
|
checkbox: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
exprBuilder(param, value) {
|
||||||
|
switch (param) {
|
||||||
|
case 'created':
|
||||||
|
return {'c.created': {
|
||||||
|
between: this.dateRange(value)}
|
||||||
|
};
|
||||||
|
case 'id':
|
||||||
|
case 'name':
|
||||||
|
case 'socialName':
|
||||||
|
case 'fi':
|
||||||
|
case 'credit':
|
||||||
|
case 'creditInsurance':
|
||||||
|
case 'phone':
|
||||||
|
case 'mobile':
|
||||||
|
case 'street':
|
||||||
|
case 'city':
|
||||||
|
case 'postcode':
|
||||||
|
case 'email':
|
||||||
|
case 'isActive':
|
||||||
|
case 'isVies':
|
||||||
|
case 'isTaxDataChecked':
|
||||||
|
case 'isEqualizated':
|
||||||
|
case 'isFreezed':
|
||||||
|
case 'hasToInvoice':
|
||||||
|
case 'hasToInvoiceByAddress':
|
||||||
|
case 'isToBeMailed':
|
||||||
|
case 'hasSepaVnl':
|
||||||
|
case 'hasLcr':
|
||||||
|
case 'hasCoreVnl':
|
||||||
|
case 'countryFk':
|
||||||
|
case 'provinceFk':
|
||||||
|
case 'salesPersonFk':
|
||||||
|
case 'businessTypeFk':
|
||||||
|
case 'payMethodFk':
|
||||||
|
case 'sageTaxTypeFk':
|
||||||
|
case 'sageTransactionTypeFk':
|
||||||
|
return {[`c.${param}`]: value};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dateRange(value) {
|
||||||
|
const minHour = new Date(value);
|
||||||
|
minHour.setHours(0, 0, 0, 0);
|
||||||
|
const maxHour = new Date(value);
|
||||||
|
maxHour.setHours(23, 59, 59, 59);
|
||||||
|
|
||||||
|
return [minHour, maxHour];
|
||||||
|
}
|
||||||
|
|
||||||
|
preview(client) {
|
||||||
|
this.clientSelected = client;
|
||||||
|
this.$.preview.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngModule.vnComponent('vnClientExtendedList', {
|
||||||
|
template: require('./index.html'),
|
||||||
|
controller: Controller
|
||||||
|
});
|
|
@ -0,0 +1,3 @@
|
||||||
|
Mailing: Env. emails
|
||||||
|
Sage tr. type: Tipo tr. sage
|
||||||
|
Yes: Sí
|
|
@ -0,0 +1,6 @@
|
||||||
|
@import "variables";
|
||||||
|
|
||||||
|
vn-chip.success,
|
||||||
|
vn-chip.alert {
|
||||||
|
color: $color-font-bg
|
||||||
|
}
|
|
@ -47,3 +47,4 @@ import './consumption-search-panel';
|
||||||
import './defaulter';
|
import './defaulter';
|
||||||
import './notification';
|
import './notification';
|
||||||
import './unpaid';
|
import './unpaid';
|
||||||
|
import './extended-list';
|
||||||
|
|
|
@ -33,6 +33,7 @@ Search client by id or name: Buscar clientes por identificador o nombre
|
||||||
# Sections
|
# Sections
|
||||||
|
|
||||||
Clients: Clientes
|
Clients: Clientes
|
||||||
|
Extended list: Listado extendido
|
||||||
Defaulter: Morosos
|
Defaulter: Morosos
|
||||||
New client: Nuevo cliente
|
New client: Nuevo cliente
|
||||||
Fiscal data: Datos fiscales
|
Fiscal data: Datos fiscales
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
"menus": {
|
"menus": {
|
||||||
"main": [
|
"main": [
|
||||||
{"state": "client.index", "icon": "person"},
|
{"state": "client.index", "icon": "person"},
|
||||||
|
{"state": "client.extendedList", "icon": "person"},
|
||||||
{"state": "client.notification", "icon": "campaign"},
|
{"state": "client.notification", "icon": "campaign"},
|
||||||
{"state": "client.defaulter", "icon": "icon-defaulter"}
|
{"state": "client.defaulter", "icon": "icon-defaulter"}
|
||||||
],
|
],
|
||||||
|
@ -381,6 +382,12 @@
|
||||||
"component": "vn-client-unpaid",
|
"component": "vn-client-unpaid",
|
||||||
"acl": ["administrative"],
|
"acl": ["administrative"],
|
||||||
"description": "Unpaid"
|
"description": "Unpaid"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "/extended-list",
|
||||||
|
"state": "client.extendedList",
|
||||||
|
"component": "vn-client-extended-list",
|
||||||
|
"description": "Extended list"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
Client id: Id cliente
|
Client id: Id cliente
|
||||||
Tax number: NIF/CIF
|
Tax number: NIF/CIF
|
||||||
Name: Nombre
|
Name: Nombre
|
||||||
Social name: Razon social
|
Social name: Razón social
|
||||||
Town/City: Ciudad
|
Town/City: Ciudad
|
||||||
Postcode: Código postal
|
Postcode: Código postal
|
||||||
Email: E-mail
|
Email: E-mail
|
||||||
|
|
|
@ -76,6 +76,13 @@
|
||||||
translate>
|
translate>
|
||||||
Show CITES letter
|
Show CITES letter
|
||||||
</vn-item>
|
</vn-item>
|
||||||
|
<vn-item
|
||||||
|
ng-click="refundConfirmation.show()"
|
||||||
|
name="refundInvoice"
|
||||||
|
vn-tooltip="Create a single ticket with all the content of the current invoice"
|
||||||
|
translate>
|
||||||
|
Refund
|
||||||
|
</vn-item>
|
||||||
</vn-list>
|
</vn-list>
|
||||||
</vn-menu>
|
</vn-menu>
|
||||||
<vn-confirm
|
<vn-confirm
|
||||||
|
@ -88,6 +95,11 @@
|
||||||
on-accept="$ctrl.bookInvoiceOut()"
|
on-accept="$ctrl.bookInvoiceOut()"
|
||||||
question="Are you sure you want to book this invoice?">
|
question="Are you sure you want to book this invoice?">
|
||||||
</vn-confirm>
|
</vn-confirm>
|
||||||
|
<vn-confirm
|
||||||
|
vn-id="refundConfirmation"
|
||||||
|
on-accept="$ctrl.refundInvoiceOut()"
|
||||||
|
question="Are you sure you want to refund this invoice?">
|
||||||
|
</vn-confirm>
|
||||||
<vn-client-descriptor-popover
|
<vn-client-descriptor-popover
|
||||||
vn-id="clientDescriptor">
|
vn-id="clientDescriptor">
|
||||||
</vn-client-descriptor-popover>
|
</vn-client-descriptor-popover>
|
||||||
|
|
|
@ -116,6 +116,35 @@ class Controller extends Section {
|
||||||
invoiceId: this.id
|
invoiceId: this.id
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async refundInvoiceOut() {
|
||||||
|
let filter = {
|
||||||
|
where: {refFk: this.invoiceOut.ref}
|
||||||
|
};
|
||||||
|
const tickets = await this.$http.get('Tickets', {filter});
|
||||||
|
this.tickets = tickets.data;
|
||||||
|
this.ticketsIds = [];
|
||||||
|
for (let ticket of this.tickets)
|
||||||
|
this.ticketsIds.push(ticket.id);
|
||||||
|
|
||||||
|
filter = {
|
||||||
|
where: {ticketFk: {inq: this.ticketsIds}}
|
||||||
|
};
|
||||||
|
const sales = await this.$http.get('Sales', {filter});
|
||||||
|
this.sales = sales.data;
|
||||||
|
|
||||||
|
const ticketServices = await this.$http.get('TicketServices', {filter});
|
||||||
|
this.services = ticketServices.data;
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
sales: this.sales,
|
||||||
|
services: this.services
|
||||||
|
};
|
||||||
|
const query = `Sales/refund`;
|
||||||
|
return this.$http.post(query, params).then(res => {
|
||||||
|
this.$state.go('ticket.card.sale', {id: res.data});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Controller.$inject = ['$element', '$scope', 'vnReport', 'vnEmail'];
|
Controller.$inject = ['$element', '$scope', 'vnReport', 'vnEmail'];
|
||||||
|
|
|
@ -122,4 +122,34 @@ describe('vnInvoiceOutDescriptorMenu', () => {
|
||||||
expect(controller.vnApp.showMessage).toHaveBeenCalled();
|
expect(controller.vnApp.showMessage).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// #4084 review with Juan
|
||||||
|
xdescribe('refundInvoiceOut()', () => {
|
||||||
|
it('should make a query and go to ticket.card.sale', () => {
|
||||||
|
controller.$state.go = jest.fn();
|
||||||
|
|
||||||
|
const invoiceOut = {
|
||||||
|
id: 1,
|
||||||
|
ref: 'T1111111'
|
||||||
|
};
|
||||||
|
controller.invoiceOut = invoiceOut;
|
||||||
|
const tickets = [{id: 1}];
|
||||||
|
const sales = [{id: 1}];
|
||||||
|
const services = [{id: 2}];
|
||||||
|
|
||||||
|
$httpBackend.expectGET(`Tickets`).respond(tickets);
|
||||||
|
$httpBackend.expectGET(`Sales`).respond(sales);
|
||||||
|
$httpBackend.expectGET(`TicketServices`).respond(services);
|
||||||
|
|
||||||
|
const expectedParams = {
|
||||||
|
sales: sales,
|
||||||
|
services: services
|
||||||
|
};
|
||||||
|
$httpBackend.expectPOST(`Sales/refund`, expectedParams).respond();
|
||||||
|
controller.refundInvoiceOut();
|
||||||
|
$httpBackend.flush();
|
||||||
|
|
||||||
|
expect(controller.$state.go).toHaveBeenCalledWith('ticket.card.sale', {id: undefined});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -12,6 +12,8 @@ Are you sure you want to delete this invoice?: Estas seguro de eliminar esta fac
|
||||||
Are you sure you want to clone this invoice?: Estas seguro de clonar esta factura?
|
Are you sure you want to clone this invoice?: Estas seguro de clonar esta factura?
|
||||||
InvoiceOut booked: Factura asentada
|
InvoiceOut booked: Factura asentada
|
||||||
Are you sure you want to book this invoice?: Estas seguro de querer asentar esta factura?
|
Are you sure you want to book this invoice?: Estas seguro de querer asentar esta factura?
|
||||||
|
Are you sure you want to refund this invoice?: Estas seguro de querer abonar esta factura?
|
||||||
|
Create a single ticket with all the content of the current invoice: Crear un ticket unico con todo el contenido de la factura actual
|
||||||
Regenerate PDF invoice: Regenerar PDF factura
|
Regenerate PDF invoice: Regenerar PDF factura
|
||||||
The invoice PDF document has been regenerated: El documento PDF de la factura ha sido regenerado
|
The invoice PDF document has been regenerated: El documento PDF de la factura ha sido regenerado
|
||||||
The email can't be empty: El correo no puede estar vacío
|
The email can't be empty: El correo no puede estar vacío
|
||||||
|
|
|
@ -12,7 +12,7 @@ module.exports = Self => {
|
||||||
},
|
},
|
||||||
http: {
|
http: {
|
||||||
path: `/downloadImages`,
|
path: `/downloadImages`,
|
||||||
verb: 'POST'
|
verb: 'GET'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -21,8 +21,11 @@
|
||||||
"life": {
|
"life": {
|
||||||
"type": "number"
|
"type": "number"
|
||||||
},
|
},
|
||||||
"isPackaging": {
|
"promo": {
|
||||||
"type": "boolean"
|
"type": "number"
|
||||||
|
},
|
||||||
|
"isUnconventionalSize": {
|
||||||
|
"type": "number"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"relations": {
|
"relations": {
|
||||||
|
@ -40,6 +43,16 @@
|
||||||
"type": "belongsTo",
|
"type": "belongsTo",
|
||||||
"model": "ItemCategory",
|
"model": "ItemCategory",
|
||||||
"foreignKey": "categoryFk"
|
"foreignKey": "categoryFk"
|
||||||
|
},
|
||||||
|
"itemPackingType": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "ItemPackingType",
|
||||||
|
"foreignKey": "itemPackingTypeFk"
|
||||||
|
},
|
||||||
|
"temperature": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "Temperature",
|
||||||
|
"foreignKey": "temperatureFk"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"acls": [
|
"acls": [
|
||||||
|
|
|
@ -140,6 +140,9 @@
|
||||||
},
|
},
|
||||||
"isFloramondo": {
|
"isFloramondo": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"packingShelve": {
|
||||||
|
"type": "number"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"relations": {
|
"relations": {
|
||||||
|
|
|
@ -23,4 +23,4 @@ import './waste/index/';
|
||||||
import './waste/detail';
|
import './waste/detail';
|
||||||
import './fixed-price';
|
import './fixed-price';
|
||||||
import './fixed-price-search-panel';
|
import './fixed-price-search-panel';
|
||||||
|
import './item-type';
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
<vn-watcher
|
||||||
|
vn-id="watcher"
|
||||||
|
url="ItemTypes"
|
||||||
|
data="$ctrl.itemType"
|
||||||
|
form="form">
|
||||||
|
</vn-watcher>
|
||||||
|
<form
|
||||||
|
name="form"
|
||||||
|
ng-submit="watcher.submit()"
|
||||||
|
class="vn-w-md">
|
||||||
|
<vn-card class="vn-pa-lg">
|
||||||
|
<vn-vertical>
|
||||||
|
<vn-textfield
|
||||||
|
label="Code"
|
||||||
|
ng-model="$ctrl.itemType.code"
|
||||||
|
rule
|
||||||
|
vn-focus>
|
||||||
|
</vn-textfield>
|
||||||
|
<vn-textfield
|
||||||
|
label="Name"
|
||||||
|
ng-model="$ctrl.itemType.name"
|
||||||
|
rule>
|
||||||
|
</vn-textfield>
|
||||||
|
<vn-autocomplete
|
||||||
|
label="Worker"
|
||||||
|
ng-model="$ctrl.itemType.workerFk"
|
||||||
|
url="Workers"
|
||||||
|
show-field="firstName"
|
||||||
|
value-field="id"
|
||||||
|
rule>
|
||||||
|
</vn-autocomplete>
|
||||||
|
<vn-autocomplete
|
||||||
|
label="Category"
|
||||||
|
ng-model="$ctrl.itemType.categoryFk"
|
||||||
|
url="ItemCategories"
|
||||||
|
show-field="name"
|
||||||
|
value-field="id"
|
||||||
|
rule>
|
||||||
|
</vn-autocomplete>
|
||||||
|
<vn-autocomplete
|
||||||
|
label="Temperature"
|
||||||
|
ng-model="$ctrl.itemType.temperatureFk"
|
||||||
|
url="Temperatures"
|
||||||
|
show-field="name"
|
||||||
|
value-field="code"
|
||||||
|
rule>
|
||||||
|
</vn-autocomplete>
|
||||||
|
</vn-vertical>
|
||||||
|
</vn-card>
|
||||||
|
<vn-button-bar>
|
||||||
|
<vn-submit
|
||||||
|
disabled="!watcher.dataChanged()"
|
||||||
|
label="Save">
|
||||||
|
</vn-submit>
|
||||||
|
<vn-button
|
||||||
|
class="cancel"
|
||||||
|
label="Undo changes"
|
||||||
|
disabled="!watcher.dataChanged()"
|
||||||
|
ng-click="watcher.loadOriginalData()">
|
||||||
|
</vn-button>
|
||||||
|
</vn-button-bar>
|
||||||
|
</form>
|
|
@ -0,0 +1,12 @@
|
||||||
|
import ngModule from '../../module';
|
||||||
|
import Section from 'salix/components/section';
|
||||||
|
|
||||||
|
export default class Controller extends Section {}
|
||||||
|
|
||||||
|
ngModule.component('vnItemTypeBasicData', {
|
||||||
|
template: require('./index.html'),
|
||||||
|
controller: Controller,
|
||||||
|
bindings: {
|
||||||
|
itemType: '<'
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vn-portal slot="menu">
|
||||||
|
<vn-item-type-descriptor item-type="$ctrl.itemType"></vn-item-type-descriptor>
|
||||||
|
<vn-left-menu source="itemType"></vn-left-menu>
|
||||||
|
</vn-portal>
|
||||||
|
<ui-view></ui-view>
|
|
@ -0,0 +1,23 @@
|
||||||
|
import ngModule from '../../module';
|
||||||
|
import ModuleCard from 'salix/components/module-card';
|
||||||
|
|
||||||
|
class Controller extends ModuleCard {
|
||||||
|
reload() {
|
||||||
|
const filter = {
|
||||||
|
include: [
|
||||||
|
{relation: 'worker'},
|
||||||
|
{relation: 'category'},
|
||||||
|
{relation: 'itemPackingType'},
|
||||||
|
{relation: 'temperature'}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
this.$http.get(`ItemTypes/${this.$params.id}`, {filter})
|
||||||
|
.then(res => this.itemType = res.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngModule.vnComponent('vnItemTypeCard', {
|
||||||
|
template: require('./index.html'),
|
||||||
|
controller: Controller
|
||||||
|
});
|
|
@ -0,0 +1,27 @@
|
||||||
|
import './index';
|
||||||
|
|
||||||
|
describe('component vnItemTypeCard', () => {
|
||||||
|
let controller;
|
||||||
|
let $httpBackend;
|
||||||
|
|
||||||
|
beforeEach(ngModule('item'));
|
||||||
|
|
||||||
|
beforeEach(inject(($componentController, _$httpBackend_) => {
|
||||||
|
$httpBackend = _$httpBackend_;
|
||||||
|
controller = $componentController('vnItemTypeCard', {$element: null});
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('reload()', () => {
|
||||||
|
it('should reload the controller data', () => {
|
||||||
|
controller.$params.id = 1;
|
||||||
|
|
||||||
|
const itemType = {id: 1};
|
||||||
|
|
||||||
|
$httpBackend.expectGET('ItemTypes/1').respond(itemType);
|
||||||
|
controller.reload();
|
||||||
|
$httpBackend.flush();
|
||||||
|
|
||||||
|
expect(controller.itemType).toEqual(itemType);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,62 @@
|
||||||
|
<vn-watcher
|
||||||
|
vn-id="watcher"
|
||||||
|
url="ItemTypes"
|
||||||
|
data="$ctrl.itemType"
|
||||||
|
insert-mode="true"
|
||||||
|
form="form">
|
||||||
|
</vn-watcher>
|
||||||
|
<form
|
||||||
|
name="form"
|
||||||
|
vn-http-submit="$ctrl.onSubmit()"
|
||||||
|
class="vn-w-md">
|
||||||
|
<vn-card class="vn-pa-lg">
|
||||||
|
<vn-vertical>
|
||||||
|
<vn-textfield
|
||||||
|
label="Code"
|
||||||
|
ng-model="$ctrl.itemType.code"
|
||||||
|
rule
|
||||||
|
vn-focus>
|
||||||
|
</vn-textfield>
|
||||||
|
<vn-textfield
|
||||||
|
label="Name"
|
||||||
|
ng-model="$ctrl.itemType.name"
|
||||||
|
rule>
|
||||||
|
</vn-textfield>
|
||||||
|
<vn-autocomplete
|
||||||
|
label="Worker"
|
||||||
|
ng-model="$ctrl.itemType.workerFk"
|
||||||
|
url="Workers"
|
||||||
|
show-field="firstName"
|
||||||
|
value-field="id"
|
||||||
|
rule>
|
||||||
|
</vn-autocomplete>
|
||||||
|
<vn-autocomplete
|
||||||
|
label="Category"
|
||||||
|
ng-model="$ctrl.itemType.categoryFk"
|
||||||
|
url="ItemCategories"
|
||||||
|
show-field="name"
|
||||||
|
value-field="id"
|
||||||
|
rule>
|
||||||
|
</vn-autocomplete>
|
||||||
|
<vn-autocomplete
|
||||||
|
label="Temperature"
|
||||||
|
ng-model="$ctrl.itemType.temperatureFk"
|
||||||
|
url="Temperatures"
|
||||||
|
show-field="name"
|
||||||
|
value-field="code"
|
||||||
|
rule>
|
||||||
|
</vn-autocomplete>
|
||||||
|
</vn-vertical>
|
||||||
|
</vn-card>
|
||||||
|
<vn-button-bar>
|
||||||
|
<vn-submit
|
||||||
|
disabled="!watcher.dataChanged()"
|
||||||
|
label="Create">
|
||||||
|
</vn-submit>
|
||||||
|
<vn-button
|
||||||
|
class="cancel"
|
||||||
|
label="Cancel"
|
||||||
|
ui-sref="item.itemType">
|
||||||
|
</vn-button>
|
||||||
|
</vn-button-bar>
|
||||||
|
</form>
|
|
@ -0,0 +1,15 @@
|
||||||
|
import ngModule from '../../module';
|
||||||
|
import Section from 'salix/components/section';
|
||||||
|
|
||||||
|
export default class Controller extends Section {
|
||||||
|
onSubmit() {
|
||||||
|
return this.$.watcher.submit().then(res =>
|
||||||
|
this.$state.go('item.itemType.card.basicData', {id: res.data.id})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngModule.component('vnItemTypeCreate', {
|
||||||
|
template: require('./index.html'),
|
||||||
|
controller: Controller
|
||||||
|
});
|
|
@ -0,0 +1,34 @@
|
||||||
|
import './index';
|
||||||
|
|
||||||
|
describe('component vnItemTypeCreate', () => {
|
||||||
|
let $scope;
|
||||||
|
let $state;
|
||||||
|
let controller;
|
||||||
|
|
||||||
|
beforeEach(ngModule('item'));
|
||||||
|
|
||||||
|
beforeEach(inject(($componentController, $rootScope, _$state_) => {
|
||||||
|
$scope = $rootScope.$new();
|
||||||
|
$state = _$state_;
|
||||||
|
$scope.watcher = {
|
||||||
|
submit: () => {
|
||||||
|
return {
|
||||||
|
then: callback => {
|
||||||
|
callback({data: {id: '1234'}});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const $element = angular.element('<vn-item-type-create></vn-item-type-create>');
|
||||||
|
controller = $componentController('vnItemTypeCreate', {$element, $scope});
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('onSubmit()', () => {
|
||||||
|
it(`should call submit() on the watcher then expect a callback`, () => {
|
||||||
|
jest.spyOn($state, 'go');
|
||||||
|
controller.onSubmit();
|
||||||
|
|
||||||
|
expect(controller.$state.go).toHaveBeenCalledWith('item.itemType.card.basicData', {id: '1234'});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,25 @@
|
||||||
|
<vn-descriptor-content
|
||||||
|
module="item"
|
||||||
|
base-state="item.itemType"
|
||||||
|
description="$ctrl.itemType.code">
|
||||||
|
<slot-body>
|
||||||
|
<div class="attributes">
|
||||||
|
<vn-label-value
|
||||||
|
label="Code"
|
||||||
|
value="{{$ctrl.itemType.code}}">
|
||||||
|
</vn-label-value>
|
||||||
|
<vn-label-value
|
||||||
|
label="Name"
|
||||||
|
value="{{$ctrl.itemType.name}}">
|
||||||
|
</vn-label-value>
|
||||||
|
<vn-label-value
|
||||||
|
label="Worker"
|
||||||
|
value="{{$ctrl.itemType.worker.firstName}} {{$ctrl.itemType.worker.lastName}}">
|
||||||
|
</vn-label-value>
|
||||||
|
<vn-label-value
|
||||||
|
label="Category"
|
||||||
|
value="{{$ctrl.itemType.category.name}}">
|
||||||
|
</vn-label-value>
|
||||||
|
</div>
|
||||||
|
</slot-body>
|
||||||
|
</vn-descriptor-content>
|
|
@ -0,0 +1,20 @@
|
||||||
|
import ngModule from '../../module';
|
||||||
|
import Descriptor from 'salix/components/descriptor';
|
||||||
|
|
||||||
|
class Controller extends Descriptor {
|
||||||
|
get itemType() {
|
||||||
|
return this.entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
set itemType(value) {
|
||||||
|
this.entity = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngModule.component('vnItemTypeDescriptor', {
|
||||||
|
template: require('./index.html'),
|
||||||
|
controller: Controller,
|
||||||
|
bindings: {
|
||||||
|
itemType: '<'
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,8 @@
|
||||||
|
import './main';
|
||||||
|
import './index/';
|
||||||
|
import './summary';
|
||||||
|
import './card';
|
||||||
|
import './descriptor';
|
||||||
|
import './create';
|
||||||
|
import './basic-data';
|
||||||
|
import './search-panel';
|
|
@ -0,0 +1,43 @@
|
||||||
|
|
||||||
|
<vn-crud-model
|
||||||
|
vn-id="model"
|
||||||
|
auto-load="true"
|
||||||
|
url="ItemTypes"
|
||||||
|
data="itemTypes"
|
||||||
|
order="name">
|
||||||
|
</vn-crud-model>
|
||||||
|
<vn-data-viewer
|
||||||
|
model="model"
|
||||||
|
class="vn-w-sm">
|
||||||
|
<vn-card>
|
||||||
|
<div class="vn-list separated">
|
||||||
|
<a
|
||||||
|
ng-repeat="itemType in itemTypes track by itemType.id"
|
||||||
|
ui-sref="item.itemType.card.summary(::{id: itemType.id})"
|
||||||
|
ui-sref-opts="{inherit: false}"
|
||||||
|
translate-attr="{title: 'View itemType'}"
|
||||||
|
class="vn-item search-result">
|
||||||
|
<vn-item-section>
|
||||||
|
<h6>{{::itemType.code}}</h6>
|
||||||
|
<div>{{::itemType.name}}</div>
|
||||||
|
</vn-item-section>
|
||||||
|
<vn-item-section side>
|
||||||
|
<vn-icon-button
|
||||||
|
vn-click-stop="$ctrl.preview(itemType)"
|
||||||
|
vn-tooltip="Preview"
|
||||||
|
icon="preview">
|
||||||
|
</vn-icon-button>
|
||||||
|
</vn-item-section>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</vn-card>
|
||||||
|
</vn-data-viewer>
|
||||||
|
<vn-popup vn-id="summary">
|
||||||
|
<vn-item-type-summary item-type="$ctrl.selectedItemType"></vn-item-type-summary>
|
||||||
|
</vn-popup>
|
||||||
|
<a ui-sref="item.itemType.create"
|
||||||
|
vn-tooltip="New itemType"
|
||||||
|
vn-bind="+"
|
||||||
|
fixed-bottom-right>
|
||||||
|
<vn-float-button icon="add"></vn-float-button>
|
||||||
|
</a>
|
|
@ -0,0 +1,14 @@
|
||||||
|
import ngModule from '../../module';
|
||||||
|
import Section from 'salix/components/section';
|
||||||
|
|
||||||
|
export default class Controller extends Section {
|
||||||
|
preview(itemType) {
|
||||||
|
this.selectedItemType = itemType;
|
||||||
|
this.$.summary.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngModule.component('vnItemTypeIndex', {
|
||||||
|
template: require('./index.html'),
|
||||||
|
controller: Controller
|
||||||
|
});
|
|
@ -0,0 +1,34 @@
|
||||||
|
import './index';
|
||||||
|
|
||||||
|
describe('Item', () => {
|
||||||
|
describe('Component vnItemTypeIndex', () => {
|
||||||
|
let controller;
|
||||||
|
let $window;
|
||||||
|
|
||||||
|
beforeEach(ngModule('item'));
|
||||||
|
|
||||||
|
beforeEach(inject(($componentController, _$window_) => {
|
||||||
|
$window = _$window_;
|
||||||
|
const $element = angular.element('<vn-item-type-summary></vn-item-type-summary>');
|
||||||
|
controller = $componentController('vnItemTypeIndex', {$element});
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('preview()', () => {
|
||||||
|
it('should show the dialog summary', () => {
|
||||||
|
controller.$.summary = {show: () => {}};
|
||||||
|
jest.spyOn(controller.$.summary, 'show');
|
||||||
|
|
||||||
|
const itemType = {id: 1};
|
||||||
|
|
||||||
|
const event = new MouseEvent('click', {
|
||||||
|
view: $window,
|
||||||
|
bubbles: true,
|
||||||
|
cancelable: true
|
||||||
|
});
|
||||||
|
controller.preview(event, itemType);
|
||||||
|
|
||||||
|
expect(controller.$.summary.show).toHaveBeenCalledWith();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,2 @@
|
||||||
|
Item Type: Familia
|
||||||
|
New itemType: Nueva familia
|
|
@ -0,0 +1,18 @@
|
||||||
|
<vn-crud-model
|
||||||
|
vn-id="model"
|
||||||
|
url="ItemTypes"
|
||||||
|
filter="::$ctrl.filter"
|
||||||
|
limit="20">
|
||||||
|
</vn-crud-model>
|
||||||
|
<vn-portal slot="topbar">
|
||||||
|
<vn-searchbar
|
||||||
|
info="Search itemType by id, name or code"
|
||||||
|
panel="vn-item-type-search-panel"
|
||||||
|
model="model"
|
||||||
|
expr-builder="$ctrl.exprBuilder(param, value)"
|
||||||
|
base-state="item.itemType">
|
||||||
|
</vn-searchbar>
|
||||||
|
</vn-portal>
|
||||||
|
<ui-view>
|
||||||
|
<vn-item-type-index></vn-item-type-index>
|
||||||
|
</ui-view>
|
|
@ -0,0 +1,24 @@
|
||||||
|
import ngModule from '../../module';
|
||||||
|
import ModuleMain from 'salix/components/module-main';
|
||||||
|
|
||||||
|
export default class ItemType extends ModuleMain {
|
||||||
|
exprBuilder(param, value) {
|
||||||
|
switch (param) {
|
||||||
|
case 'search':
|
||||||
|
return /^\d+$/.test(value)
|
||||||
|
? {id: value}
|
||||||
|
: {or: [
|
||||||
|
{name: {like: `%${value}%`}},
|
||||||
|
{code: {like: `%${value}%`}}
|
||||||
|
]};
|
||||||
|
case 'name':
|
||||||
|
case 'code':
|
||||||
|
return {[param]: {like: `%${value}%`}};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngModule.vnComponent('vnItemType', {
|
||||||
|
controller: ItemType,
|
||||||
|
template: require('./index.html')
|
||||||
|
});
|
|
@ -0,0 +1,31 @@
|
||||||
|
import './index';
|
||||||
|
|
||||||
|
describe('Item', () => {
|
||||||
|
describe('Component vnItemType', () => {
|
||||||
|
let controller;
|
||||||
|
|
||||||
|
beforeEach(ngModule('item'));
|
||||||
|
|
||||||
|
beforeEach(inject($componentController => {
|
||||||
|
const $element = angular.element('<vn-item-type></vn-item-type>');
|
||||||
|
controller = $componentController('vnItemType', {$element});
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('exprBuilder()', () => {
|
||||||
|
it('should return a filter based on a search by id', () => {
|
||||||
|
const filter = controller.exprBuilder('search', '123');
|
||||||
|
|
||||||
|
expect(filter).toEqual({id: '123'});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return a filter based on a search by name or code', () => {
|
||||||
|
const filter = controller.exprBuilder('search', 'Alstroemeria');
|
||||||
|
|
||||||
|
expect(filter).toEqual({or: [
|
||||||
|
{name: {like: '%Alstroemeria%'}},
|
||||||
|
{code: {like: '%Alstroemeria%'}},
|
||||||
|
]});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1 @@
|
||||||
|
Search itemType by id, name or code: Buscar familia por id, nombre o código
|
|
@ -0,0 +1,22 @@
|
||||||
|
<div class="search-panel">
|
||||||
|
<form ng-submit="$ctrl.onSearch()">
|
||||||
|
<vn-horizontal>
|
||||||
|
<vn-textfield
|
||||||
|
vn-one
|
||||||
|
label="Name"
|
||||||
|
ng-model="filter.name"
|
||||||
|
vn-focus>
|
||||||
|
</vn-textfield>
|
||||||
|
</vn-horizontal>
|
||||||
|
<vn-horizontal>
|
||||||
|
<vn-textfield
|
||||||
|
vn-one
|
||||||
|
label="Code"
|
||||||
|
ng-model="filter.code">
|
||||||
|
</vn-textfield>
|
||||||
|
</vn-horizontal>
|
||||||
|
<vn-horizontal class="vn-mt-lg">
|
||||||
|
<vn-submit label="Search"></vn-submit>
|
||||||
|
</vn-horizontal>
|
||||||
|
</form>
|
||||||
|
</div>
|
|
@ -0,0 +1,7 @@
|
||||||
|
import ngModule from '../../module';
|
||||||
|
import SearchPanel from 'core/components/searchbar/search-panel';
|
||||||
|
|
||||||
|
ngModule.component('vnItemTypeSearchPanel', {
|
||||||
|
template: require('./index.html'),
|
||||||
|
controller: SearchPanel
|
||||||
|
});
|
|
@ -0,0 +1,50 @@
|
||||||
|
<vn-card class="summary">
|
||||||
|
<h5>
|
||||||
|
<span>{{summary.id}} - {{summary.name}} - {{summary.worker.firstName}} {{summary.worker.lastName}}</span>
|
||||||
|
</h5>
|
||||||
|
<vn-horizontal class="vn-pa-md">
|
||||||
|
<vn-one>
|
||||||
|
<h4 translate>Basic data</h4>
|
||||||
|
<vn-label-value
|
||||||
|
label="Id"
|
||||||
|
value="{{summary.id}}">
|
||||||
|
</vn-label-value>
|
||||||
|
<vn-label-value
|
||||||
|
label="Code"
|
||||||
|
value="{{summary.code}}">
|
||||||
|
</vn-label-value>
|
||||||
|
<vn-label-value
|
||||||
|
label="Name"
|
||||||
|
value="{{summary.name}}">
|
||||||
|
</vn-label-value>
|
||||||
|
<vn-label-value
|
||||||
|
label="Worker"
|
||||||
|
value="{{summary.worker.firstName}} {{summary.worker.lastName}}">
|
||||||
|
</vn-label-value>
|
||||||
|
<vn-label-value
|
||||||
|
label="Category"
|
||||||
|
value="{{summary.category.name}}">
|
||||||
|
</vn-label-value>
|
||||||
|
<vn-label-value
|
||||||
|
label="Temperature"
|
||||||
|
value="{{summary.temperature.name}}">
|
||||||
|
</vn-label-value>
|
||||||
|
<vn-label-value
|
||||||
|
label="Life"
|
||||||
|
value="{{summary.life}}">
|
||||||
|
</vn-label-value>
|
||||||
|
<vn-label-value
|
||||||
|
label="Promo"
|
||||||
|
value="{{summary.promo}}">
|
||||||
|
</vn-label-value>
|
||||||
|
<vn-label-value
|
||||||
|
label="Item packing type"
|
||||||
|
value="{{summary.itemPackingType.description}}">
|
||||||
|
</vn-label-value>
|
||||||
|
<vn-label-value
|
||||||
|
label="Is unconventional size"
|
||||||
|
value="{{summary.isUnconventionalSize}}">
|
||||||
|
</vn-label-value>
|
||||||
|
</vn-one>
|
||||||
|
</vn-horizontal>
|
||||||
|
</vn-card>
|
|
@ -0,0 +1,33 @@
|
||||||
|
import ngModule from '../../module';
|
||||||
|
import Component from 'core/lib/component';
|
||||||
|
|
||||||
|
class Controller extends Component {
|
||||||
|
set itemType(value) {
|
||||||
|
this._itemType = value;
|
||||||
|
this.$.summary = null;
|
||||||
|
if (!value) return;
|
||||||
|
|
||||||
|
const filter = {
|
||||||
|
include: [
|
||||||
|
{relation: 'worker'},
|
||||||
|
{relation: 'category'},
|
||||||
|
{relation: 'itemPackingType'},
|
||||||
|
{relation: 'temperature'}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
this.$http.get(`ItemTypes/${value.id}`, {filter})
|
||||||
|
.then(res => this.$.summary = res.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
get itemType() {
|
||||||
|
return this._itemType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngModule.component('vnItemTypeSummary', {
|
||||||
|
template: require('./index.html'),
|
||||||
|
controller: Controller,
|
||||||
|
bindings: {
|
||||||
|
itemType: '<'
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,4 @@
|
||||||
|
Life: Vida
|
||||||
|
Promo: Promoción
|
||||||
|
Item packing type: Tipo de embalaje
|
||||||
|
Is unconventional size: Es de tamaño poco convencional
|
|
@ -9,7 +9,8 @@
|
||||||
{"state": "item.index", "icon": "icon-item"},
|
{"state": "item.index", "icon": "icon-item"},
|
||||||
{"state": "item.request", "icon": "icon-buyrequest"},
|
{"state": "item.request", "icon": "icon-buyrequest"},
|
||||||
{"state": "item.waste.index", "icon": "icon-claims"},
|
{"state": "item.waste.index", "icon": "icon-claims"},
|
||||||
{"state": "item.fixedPrice", "icon": "icon-fixedPrice"}
|
{"state": "item.fixedPrice", "icon": "icon-fixedPrice"},
|
||||||
|
{"state": "item.itemType", "icon": "contact_support"}
|
||||||
],
|
],
|
||||||
"card": [
|
"card": [
|
||||||
{"state": "item.card.basicData", "icon": "settings"},
|
{"state": "item.card.basicData", "icon": "settings"},
|
||||||
|
@ -20,6 +21,9 @@
|
||||||
{"state": "item.card.diary", "icon": "icon-transaction"},
|
{"state": "item.card.diary", "icon": "icon-transaction"},
|
||||||
{"state": "item.card.last-entries", "icon": "icon-regentry"},
|
{"state": "item.card.last-entries", "icon": "icon-regentry"},
|
||||||
{"state": "item.card.log", "icon": "history"}
|
{"state": "item.card.log", "icon": "history"}
|
||||||
|
],
|
||||||
|
"itemType": [
|
||||||
|
{"state": "item.itemType.card.basicData", "icon": "settings"}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"keybindings": [
|
"keybindings": [
|
||||||
|
@ -169,6 +173,47 @@
|
||||||
"component": "vn-fixed-price",
|
"component": "vn-fixed-price",
|
||||||
"description": "Fixed prices",
|
"description": "Fixed prices",
|
||||||
"acl": ["buyer"]
|
"acl": ["buyer"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url" : "/item-type?q",
|
||||||
|
"state": "item.itemType",
|
||||||
|
"component": "vn-item-type",
|
||||||
|
"description": "Item Type",
|
||||||
|
"acl": ["buyer"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "/create",
|
||||||
|
"state": "item.itemType.create",
|
||||||
|
"component": "vn-item-type-create",
|
||||||
|
"description": "New itemType",
|
||||||
|
"acl": ["buyer"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "/:id",
|
||||||
|
"state": "item.itemType.card",
|
||||||
|
"component": "vn-item-type-card",
|
||||||
|
"abstract": true,
|
||||||
|
"description": "Detail"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "/summary",
|
||||||
|
"state": "item.itemType.card.summary",
|
||||||
|
"component": "vn-item-type-summary",
|
||||||
|
"description": "Summary",
|
||||||
|
"params": {
|
||||||
|
"item-type": "$ctrl.itemType"
|
||||||
|
},
|
||||||
|
"acl": ["buyer"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "/basic-data",
|
||||||
|
"state": "item.itemType.card.basicData",
|
||||||
|
"component": "vn-item-type-basic-data",
|
||||||
|
"description": "Basic data",
|
||||||
|
"params": {
|
||||||
|
"item-type": "$ctrl.itemType"
|
||||||
|
},
|
||||||
|
"acl": ["buyer"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue