Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into 4045-incoterms_authorization
gitea/salix/pipeline/head This commit is unstable
Details
gitea/salix/pipeline/head This commit is unstable
Details
This commit is contained in:
commit
9ab8b84290
|
@ -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();
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,5 +1,5 @@
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
Self.remoteMethodCtx('setSaleQuantity', {
|
Self.remoteMethod('setSaleQuantity', {
|
||||||
description: 'Update sale quantity',
|
description: 'Update sale quantity',
|
||||||
accessType: 'WRITE',
|
accessType: 'WRITE',
|
||||||
accepts: [{
|
accepts: [{
|
||||||
|
@ -24,11 +24,13 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Self.setSaleQuantity = async ctx => {
|
Self.setSaleQuantity = async(saleId, quantity) => {
|
||||||
const args = ctx.args;
|
|
||||||
const models = Self.app.models;
|
const models = Self.app.models;
|
||||||
|
|
||||||
const sale = await models.Sale.findById(args.saleId);
|
const sale = await models.Sale.findById(saleId);
|
||||||
return await sale.updateAttribute('quantity', args.quantity);
|
return await sale.updateAttributes({
|
||||||
|
originalQuantity: sale.quantity,
|
||||||
|
quantity: quantity
|
||||||
|
});
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,19 +5,12 @@ describe('setSaleQuantity()', () => {
|
||||||
const saleId = 30;
|
const saleId = 30;
|
||||||
const newQuantity = 10;
|
const newQuantity = 10;
|
||||||
|
|
||||||
const ctx = {
|
|
||||||
args: {
|
|
||||||
saleId: saleId,
|
|
||||||
quantity: newQuantity
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const originalSale = await models.Sale.findById(saleId);
|
const originalSale = await models.Sale.findById(saleId);
|
||||||
|
|
||||||
await models.Collection.setSaleQuantity(ctx);
|
await models.Collection.setSaleQuantity(saleId, newQuantity);
|
||||||
const updateSale = await models.Sale.findById(saleId);
|
const updateSale = await models.Sale.findById(saleId);
|
||||||
|
|
||||||
expect(updateSale.quantity).toBeLessThan(originalSale.quantity);
|
expect(updateSale.originalQuantity).toEqual(originalSale.quantity);
|
||||||
expect(updateSale.quantity).toEqual(newQuantity);
|
expect(updateSale.quantity).toEqual(newQuantity);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
LOAD DATA LOCAL INFILE ?
|
LOAD DATA LOCAL INFILE ?
|
||||||
INTO TABLE bucket
|
INTO TABLE `edi`.`bucket`
|
||||||
FIELDS TERMINATED BY ';'
|
FIELDS TERMINATED BY ';'
|
||||||
LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6, @col7, @col8, @col9, @col10, @col11, @col12)
|
LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6, @col7, @col8, @col9, @col10, @col11, @col12)
|
||||||
SET
|
SET
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
LOAD DATA LOCAL INFILE ?
|
LOAD DATA LOCAL INFILE ?
|
||||||
INTO TABLE bucket_type
|
INTO TABLE `edi`.`bucket_type`
|
||||||
FIELDS TERMINATED BY ';'
|
FIELDS TERMINATED BY ';'
|
||||||
LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6)
|
LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6)
|
||||||
SET
|
SET
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
LOAD DATA LOCAL INFILE ?
|
LOAD DATA LOCAL INFILE ?
|
||||||
INTO TABLE `feature`
|
INTO TABLE `edi`.`feature`
|
||||||
FIELDS TERMINATED BY ';'
|
FIELDS TERMINATED BY ';'
|
||||||
LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6, @col7)
|
LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6, @col7)
|
||||||
SET
|
SET
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
LOAD DATA LOCAL INFILE ?
|
LOAD DATA LOCAL INFILE ?
|
||||||
INTO TABLE genus
|
INTO TABLE `edi`.`genus`
|
||||||
FIELDS TERMINATED BY ';'
|
FIELDS TERMINATED BY ';'
|
||||||
LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6)
|
LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6)
|
||||||
SET
|
SET
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
LOAD DATA LOCAL INFILE ?
|
LOAD DATA LOCAL INFILE ?
|
||||||
INTO TABLE item
|
INTO TABLE `edi`.`item`
|
||||||
FIELDS TERMINATED BY ';'
|
FIELDS TERMINATED BY ';'
|
||||||
LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6, @col7, @col8, @col9, @col10, @col11, @col12)
|
LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6, @col7, @col8, @col9, @col10, @col11, @col12)
|
||||||
SET
|
SET
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
LOAD DATA LOCAL INFILE ?
|
LOAD DATA LOCAL INFILE ?
|
||||||
INTO TABLE `item_feature`
|
INTO TABLE `edi`.`item_feature`
|
||||||
FIELDS TERMINATED BY ';'
|
FIELDS TERMINATED BY ';'
|
||||||
LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6, @col7, @col8)
|
LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6, @col7, @col8)
|
||||||
SET
|
SET
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
LOAD DATA LOCAL INFILE ?
|
LOAD DATA LOCAL INFILE ?
|
||||||
INTO TABLE item_group
|
INTO TABLE `edi`.`item_group`
|
||||||
FIELDS TERMINATED BY ';'
|
FIELDS TERMINATED BY ';'
|
||||||
LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6)
|
LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6)
|
||||||
SET
|
SET
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
LOAD DATA LOCAL INFILE ?
|
LOAD DATA LOCAL INFILE ?
|
||||||
INTO TABLE plant
|
INTO TABLE `edi`.`plant`
|
||||||
FIELDS TERMINATED BY ';'
|
FIELDS TERMINATED BY ';'
|
||||||
LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6, @col7, @col8, @col9)
|
LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6, @col7, @col8, @col9)
|
||||||
SET
|
SET
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
LOAD DATA LOCAL INFILE ?
|
LOAD DATA LOCAL INFILE ?
|
||||||
INTO TABLE specie
|
INTO TABLE `edi`.`specie`
|
||||||
FIELDS TERMINATED BY ';'
|
FIELDS TERMINATED BY ';'
|
||||||
LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6, @col7)
|
LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6, @col7)
|
||||||
SET
|
SET
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
LOAD DATA LOCAL INFILE ?
|
LOAD DATA LOCAL INFILE ?
|
||||||
INTO TABLE edi.supplier
|
INTO TABLE `edi`.`supplier`
|
||||||
FIELDS TERMINATED BY ';'
|
FIELDS TERMINATED BY ';'
|
||||||
LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6, @col7, @col8, @col9, @col10, @col11, @col12, @col13, @col14, @col15, @col16, @col17, @col18, @col19, @col20)
|
LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6, @col7, @col8, @col9, @col10, @col11, @col12, @col13, @col14, @col15, @col16, @col17, @col18, @col19, @col20)
|
||||||
SET
|
SET
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
LOAD DATA LOCAL INFILE ?
|
LOAD DATA LOCAL INFILE ?
|
||||||
INTO TABLE `type`
|
INTO TABLE `edi`.`type`
|
||||||
FIELDS TERMINATED BY ';'
|
FIELDS TERMINATED BY ';'
|
||||||
LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6, @col7)
|
LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6, @col7)
|
||||||
SET
|
SET
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
LOAD DATA LOCAL INFILE ?
|
LOAD DATA LOCAL INFILE ?
|
||||||
INTO TABLE `value`
|
INTO TABLE `edi`.`value`
|
||||||
FIELDS TERMINATED BY ';'
|
FIELDS TERMINATED BY ';'
|
||||||
LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6, @col7)
|
LINES TERMINATED BY '\n' (@col1, @col2, @col3, @col4, @col5, @col6, @col7)
|
||||||
SET
|
SET
|
||||||
|
|
|
@ -19,137 +19,218 @@ 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);
|
||||||
|
|
||||||
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`;
|
|
||||||
|
|
||||||
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)
|
||||||
await fs.rmdir(tempDir, {recursive: true});
|
continue;
|
||||||
console.error(error);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
if (fs.existsSync(paths.tempFile))
|
async function getChecksum(file) {
|
||||||
await fs.unlink(paths.tempFile);
|
const ftpClient = await getFtpClient();
|
||||||
|
console.debug(`Checking checksum for file ${file.name}...`);
|
||||||
|
|
||||||
await dumpData({file, entries, paths});
|
ftpClient.cat(`codes/${file.name}.txt`);
|
||||||
|
|
||||||
await fs.rmdir(paths.tempDir, {recursive: true});
|
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;
|
|
||||||
|
|
||||||
for (const zipEntry of entries) {
|
try {
|
||||||
const entryName = zipEntry.entryName;
|
await fs.mkdir(tempDir);
|
||||||
console.log(`Reading file ${entryName}...`);
|
} catch (error) {
|
||||||
|
if (error.code !== 'EEXIST')
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
const startIndex = (entryName.length - 10);
|
const fileStream = await fs.readFile(tempFile);
|
||||||
const endIndex = (entryName.length - 4);
|
if (fileStream) {
|
||||||
const dateString = entryName.substring(startIndex, endIndex);
|
const zip = new JSZip();
|
||||||
const lastUpdated = new Date();
|
const zipContents = await zip.loadAsync(fileStream);
|
||||||
|
|
||||||
// Format string date to a date object
|
if (!zipContents) return;
|
||||||
let updated = null;
|
|
||||||
if (file.updated) {
|
const fileNames = Object.keys(zipContents.files);
|
||||||
updated = new Date(file.updated);
|
|
||||||
updated.setHours(0, 0, 0, 0);
|
for (const fileName of fileNames) {
|
||||||
|
const fileContent = await zip.file(fileName).async('nodebuffer');
|
||||||
|
const dest = path.join(tempDir, fileName);
|
||||||
|
await fs.writeFile(dest, fileContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
lastUpdated.setFullYear(`20${dateString.substring(4, 6)}`);
|
|
||||||
lastUpdated.setMonth(parseInt(dateString.substring(2, 4)) - 1);
|
|
||||||
lastUpdated.setDate(dateString.substring(0, 2));
|
|
||||||
lastUpdated.setHours(0, 0, 0, 0);
|
|
||||||
|
|
||||||
if (updated && lastUpdated <= updated) {
|
|
||||||
console.debug(`Table ${toTable} already updated, skipping...`);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('Dumping data...');
|
|
||||||
const templatePath = path.join(__dirname, `./sql/${toTable}.sql`);
|
|
||||||
const sqlTemplate = fs.readFileSync(templatePath, 'utf8');
|
|
||||||
|
|
||||||
const rawPath = path.join(paths.tempDir, entryName);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const tx = await Self.beginTransaction({});
|
|
||||||
const options = {transaction: tx};
|
|
||||||
|
|
||||||
await Self.rawSql(`DELETE FROM edi.${toTable}`, null, options);
|
|
||||||
await Self.rawSql(sqlTemplate, [rawPath], options);
|
|
||||||
await Self.rawSql(`
|
|
||||||
UPDATE edi.fileConfig
|
|
||||||
SET updated = ?
|
|
||||||
WHERE fileName = ?
|
|
||||||
`, [lastUpdated, baseName], options);
|
|
||||||
|
|
||||||
tx.commit();
|
|
||||||
} catch (error) {
|
|
||||||
tx.rollback();
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`Updated table ${toTable}\n`);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function dumpData(tempDir, table) {
|
||||||
|
const toTable = table.toTable;
|
||||||
|
const baseName = table.fileName;
|
||||||
|
|
||||||
|
const tx = await Self.beginTransaction({});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
const tableName = `edi.${toTable}`;
|
||||||
|
await Self.rawSql(`DELETE FROM ??`, [tableName], options);
|
||||||
|
|
||||||
|
const dirFiles = await fs.readdir(tempDir);
|
||||||
|
const files = dirFiles.filter(file => file.startsWith(baseName));
|
||||||
|
|
||||||
|
for (const file of files) {
|
||||||
|
console.log(`Dumping data from file ${file}...`);
|
||||||
|
|
||||||
|
const templatePath = path.join(__dirname, `./sql/${toTable}.sql`);
|
||||||
|
const sqlTemplate = await fs.readFile(templatePath, 'utf8');
|
||||||
|
const filePath = path.join(tempDir, file);
|
||||||
|
|
||||||
|
await Self.rawSql(sqlTemplate, [filePath], options);
|
||||||
|
await Self.rawSql(`
|
||||||
|
UPDATE edi.tableConfig
|
||||||
|
SET updated = ?
|
||||||
|
WHERE fileName = ?
|
||||||
|
`, [new Date(), baseName], options);
|
||||||
|
}
|
||||||
|
|
||||||
|
tx.commit();
|
||||||
|
} catch (error) {
|
||||||
|
tx.rollback();
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
console.log(`Updated table ${toTable}\n`);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -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,14 +0,0 @@
|
||||||
create table `vn`.`invoiceOut_queue`
|
|
||||||
(
|
|
||||||
invoiceFk int(10) unsigned not null,
|
|
||||||
queued datetime default now() not null,
|
|
||||||
printed datetime null,
|
|
||||||
`status` VARCHAR(50) default '' null,
|
|
||||||
constraint invoiceOut_queue_pk
|
|
||||||
primary key (invoiceFk),
|
|
||||||
constraint invoiceOut_queue_invoiceOut_id_fk
|
|
||||||
foreign key (invoiceFk) references invoiceOut (id)
|
|
||||||
on update cascade on delete cascade
|
|
||||||
)
|
|
||||||
comment 'Queue for PDF invoicing';
|
|
||||||
|
|
|
@ -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 ;
|
|
|
@ -3,8 +3,8 @@ CREATE TABLE `vn`.`clientUnpaid` (
|
||||||
`dated` date NOT NULL,
|
`dated` date NOT NULL,
|
||||||
`amount` double DEFAULT 0,
|
`amount` double DEFAULT 0,
|
||||||
PRIMARY KEY (`clientFk`),
|
PRIMARY KEY (`clientFk`),
|
||||||
CONSTRAINT `clientUnpaid_clientFk` FOREIGN KEY (`clientFk`) REFERENCES `client` (`id`) ON UPDATE CASCADE
|
CONSTRAINT `clientUnpaid_clientFk` FOREIGN KEY (`clientFk`) REFERENCES `vn`.`client` (`id`) ON UPDATE CASCADE
|
||||||
);
|
);
|
||||||
|
|
||||||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||||
VALUES('ClientUnpaid', '*', '*', 'ALLOW', 'ROLE', 'administrative');
|
VALUES('ClientUnpaid', '*', '*', 'ALLOW', 'ROLE', 'administrative');
|
|
@ -0,0 +1,8 @@
|
||||||
|
CREATE TABLE `vn`.`invoiceOut_queue` (
|
||||||
|
`invoiceFk` int(10) unsigned not null,
|
||||||
|
`queued` datetime default now() not null,
|
||||||
|
`printed` datetime null,
|
||||||
|
`status` VARCHAR(50) DEFAULT '' NULL,
|
||||||
|
CONSTRAINT `invoiceOut_queue_pk` PRIMARY KEY (`invoiceFk`),
|
||||||
|
CONSTRAINT `invoiceOut_queue_invoiceOut_id_fk` FOREIGN KEY (`invoiceFk`) REFERENCES `vn`.`invoiceOut` (`id`) ON UPDATE CASCADE ON DELETE CASCADE
|
||||||
|
) comment 'Queue for PDF invoicing';
|
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE `vn`.`accountingType` ADD daysInFuture INT NULL;
|
||||||
|
ALTER TABLE `vn`.`accountingType` MODIFY COLUMN daysInFuture int(11) DEFAULT 0 NULL;
|
|
@ -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 `vn`.`mdbBranch` (
|
||||||
|
`name` VARCHAR(255),
|
||||||
|
PRIMARY KEY(`name`)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE `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 INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||||
|
VALUES('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,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 @@
|
||||||
|
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);
|
||||||
|
|
|
@ -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,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 ;
|
|
@ -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
|
||||||
|
@ -113,7 +119,7 @@ INSERT INTO `vn`.`currency`(`id`, `code`, `name`, `ratio`)
|
||||||
(2, 'USD', 'Dollar USA', 1.4),
|
(2, 'USD', 'Dollar USA', 1.4),
|
||||||
(3, 'GBP', 'Libra', 1),
|
(3, 'GBP', 'Libra', 1),
|
||||||
(4, 'JPY', 'Yen Japones', 1);
|
(4, 'JPY', 'Yen Japones', 1);
|
||||||
|
|
||||||
INSERT INTO `vn`.`country`(`id`, `country`, `isUeeMember`, `code`, `currencyFk`, `ibanLength`, `continentFk`, `hasDailyInvoice`, `CEE`)
|
INSERT INTO `vn`.`country`(`id`, `country`, `isUeeMember`, `code`, `currencyFk`, `ibanLength`, `continentFk`, `hasDailyInvoice`, `CEE`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, 'España', 1, 'ES', 1, 24, 4, 0, 1),
|
(1, 'España', 1, 'ES', 1, 24, 4, 0, 1),
|
||||||
|
@ -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
|
||||||
|
@ -1621,51 +1633,59 @@ INSERT INTO `hedera`.`orderRowComponent`(`rowFk`, `componentFk`, `price`)
|
||||||
|
|
||||||
INSERT INTO `hedera`.`visit`(`id`, `firstAgentFk`)
|
INSERT INTO `hedera`.`visit`(`id`, `firstAgentFk`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, NULL),
|
(1, NULL),
|
||||||
(2, NULL),
|
(2, NULL),
|
||||||
(3, NULL),
|
(3, NULL),
|
||||||
(4, NULL),
|
(4, NULL),
|
||||||
(5, NULL),
|
(5, NULL),
|
||||||
(6, NULL),
|
(6, NULL),
|
||||||
(7, NULL),
|
(7, NULL),
|
||||||
(8, NULL),
|
(8, NULL),
|
||||||
(9, NULL);
|
(9, NULL),
|
||||||
|
(10, NULL),
|
||||||
|
(11, NULL);
|
||||||
|
|
||||||
INSERT INTO `hedera`.`visitAgent`(`id`, `visitFk`)
|
INSERT INTO `hedera`.`visitAgent`(`id`, `visitFk`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, 1),
|
(1, 1),
|
||||||
(2, 2),
|
(2, 2),
|
||||||
(3, 3),
|
(3, 3),
|
||||||
(4, 4),
|
(4, 4),
|
||||||
(5, 5),
|
(5, 5),
|
||||||
(6, 6),
|
(6, 6),
|
||||||
(7, 7),
|
(7, 7),
|
||||||
(8, 8),
|
(8, 8),
|
||||||
(9, 9);
|
(9, 9),
|
||||||
|
(10, 10),
|
||||||
|
(11, 11);
|
||||||
|
|
||||||
INSERT INTO `hedera`.`visitAccess`(`id`, `agentFk`, `stamp`)
|
INSERT INTO `hedera`.`visitAccess`(`id`, `agentFk`, `stamp`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, 1, CURDATE()),
|
(1, 1, CURDATE()),
|
||||||
(2, 2, CURDATE()),
|
(2, 2, CURDATE()),
|
||||||
(3, 3, CURDATE()),
|
(3, 3, CURDATE()),
|
||||||
(4, 4, CURDATE()),
|
(4, 4, CURDATE()),
|
||||||
(5, 5, CURDATE()),
|
(5, 5, CURDATE()),
|
||||||
(6, 6, CURDATE()),
|
(6, 6, CURDATE()),
|
||||||
(7, 7, CURDATE()),
|
(7, 7, CURDATE()),
|
||||||
(8, 8, CURDATE()),
|
(8, 8, CURDATE()),
|
||||||
(9, 9, CURDATE());
|
(9, 9, CURDATE()),
|
||||||
|
(10, 10, CURDATE()),
|
||||||
|
(11, 11, CURDATE());
|
||||||
|
|
||||||
INSERT INTO `hedera`.`visitUser`(`id`, `accessFk`, `userFk`, `stamp`)
|
INSERT INTO `hedera`.`visitUser`(`id`, `accessFk`, `userFk`, `stamp`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, 1, 1101, CURDATE()),
|
(1, 1, 1101, CURDATE()),
|
||||||
(2, 2, 1101, CURDATE()),
|
(2, 2, 1101, CURDATE()),
|
||||||
(3, 3, 1101, CURDATE()),
|
(3, 3, 1101, CURDATE()),
|
||||||
(4, 4, 1102, CURDATE()),
|
(4, 4, 1102, CURDATE()),
|
||||||
(5, 5, 1102, CURDATE()),
|
(5, 5, 1102, CURDATE()),
|
||||||
(6, 6, 1102, CURDATE()),
|
(6, 6, 1102, CURDATE()),
|
||||||
(7, 7, 1103, CURDATE()),
|
(7, 7, 1103, CURDATE()),
|
||||||
(8, 8, 1103, CURDATE()),
|
(8, 8, 1103, CURDATE()),
|
||||||
(9, 9, 1103, CURDATE());
|
(9, 9, 1103, CURDATE()),
|
||||||
|
(10, 10, 1102, DATE_SUB(CURDATE(), INTERVAL 1 DAY)),
|
||||||
|
(11, 11, 1103, DATE_SUB(CURDATE(), INTERVAL 1 DAY));
|
||||||
|
|
||||||
INSERT INTO `hedera`.`userSession`(`created`, `lastUpdate`, `ssid`, `data`, `userVisitFk`)
|
INSERT INTO `hedera`.`userSession`(`created`, `lastUpdate`, `ssid`, `data`, `userVisitFk`)
|
||||||
VALUES
|
VALUES
|
||||||
|
@ -2290,11 +2310,6 @@ INSERT INTO `vn`.`workerTimeControlParams` (`id`, `dayBreak`, `weekBreak`, `week
|
||||||
(1, 43200, 129600, 734400, 43200, 50400, 259200, 1296000, 36000);
|
(1, 43200, 129600, 734400, 43200, 50400, 259200, 1296000, 36000);
|
||||||
|
|
||||||
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
|
||||||
|
@ -2543,4 +2558,37 @@ INSERT INTO `vn`.`supplierAgencyTerm` (`agencyFk`, `supplierFk`, `minimumPackage
|
||||||
(2, 1, 60, 0.00, 0.00, NULL, 0, 5.00, 33),
|
(2, 1, 60, 0.00, 0.00, NULL, 0, 5.00, 33),
|
||||||
(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');
|
|
@ -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`
|
||||||
--
|
--
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -32,6 +32,7 @@ services:
|
||||||
- /mnt/appdata/pdfs:/var/lib/salix/pdfs
|
- /mnt/appdata/pdfs:/var/lib/salix/pdfs
|
||||||
- /mnt/appdata/dms:/var/lib/salix/dms
|
- /mnt/appdata/dms:/var/lib/salix/dms
|
||||||
- /mnt/appdata/image:/var/lib/salix/image
|
- /mnt/appdata/image:/var/lib/salix/image
|
||||||
|
- /mnt/appdata/vn-access:/var/lib/salix/vn-access
|
||||||
deploy:
|
deploy:
|
||||||
replicas: ${BACK_REPLICAS:?}
|
replicas: ${BACK_REPLICAS:?}
|
||||||
placement:
|
placement:
|
||||||
|
|
|
@ -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`
|
||||||
},
|
},
|
||||||
|
|
|
@ -123,19 +123,19 @@ describe('Client lock verified data path', () => {
|
||||||
await page.accessToSection('client.card.fiscalData');
|
await page.accessToSection('client.card.fiscalData');
|
||||||
}, 20000);
|
}, 20000);
|
||||||
|
|
||||||
it('should confirm verified data button is disabled for salesAssistant', async() => {
|
it('should confirm verified data button is enabled for salesAssistant', async() => {
|
||||||
const isDisabled = await page.isDisabled(selectors.clientFiscalData.verifiedDataCheckbox);
|
const isDisabled = await page.isDisabled(selectors.clientFiscalData.verifiedDataCheckbox);
|
||||||
|
|
||||||
expect(isDisabled).toBeTrue();
|
expect(isDisabled).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return error when edit the social name', async() => {
|
it('should now edit the social name', async() => {
|
||||||
await page.clearInput(selectors.clientFiscalData.socialName);
|
await page.clearInput(selectors.clientFiscalData.socialName);
|
||||||
await page.write(selectors.clientFiscalData.socialName, 'new social name edition');
|
await page.write(selectors.clientFiscalData.socialName, 'new social name edition');
|
||||||
await page.waitToClick(selectors.clientFiscalData.saveButton);
|
await page.waitToClick(selectors.clientFiscalData.saveButton);
|
||||||
const message = await page.waitForSnackbar();
|
const message = await page.waitForSnackbar();
|
||||||
|
|
||||||
expect(message.text).toContain(`Not enough privileges to edit a client with verified data`);
|
expect(message.text).toContain(`Data saved!`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should now confirm the social name have been edited once and for all', async() => {
|
it('should now confirm the social name have been edited once and for all', async() => {
|
||||||
|
|
|
@ -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!');
|
||||||
|
});
|
||||||
|
});
|
|
@ -146,16 +146,17 @@ export default class MultiCheck extends FormInput {
|
||||||
if (!this.model || !this.model.data) return;
|
if (!this.model || !this.model.data) return;
|
||||||
|
|
||||||
const data = this.model.data;
|
const data = this.model.data;
|
||||||
const modelParams = this.model.userParams;
|
|
||||||
const params = {
|
const params = {
|
||||||
filter: {
|
filter: {
|
||||||
modelParams: modelParams,
|
|
||||||
limit: null
|
limit: null
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
if (this.model.userFilter)
|
||||||
|
Object.assign(params.filter, this.model.userFilter);
|
||||||
|
if (this.model.userParams)
|
||||||
|
Object.assign(params, this.model.userParams);
|
||||||
|
|
||||||
this.rows = data.length;
|
this.rows = data.length;
|
||||||
|
|
||||||
this.$http.get(this.model.url, {params})
|
this.$http.get(this.model.url, {params})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
this.allRowsCount = res.data.length;
|
this.allRowsCount = res.data.length;
|
||||||
|
|
|
@ -46,11 +46,13 @@
|
||||||
</div>
|
</div>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
<div id="table"></div>
|
<div id="table"></div>
|
||||||
<vn-pagination
|
<div ng-transclude="pagination">
|
||||||
ng-if="$ctrl.model"
|
<vn-pagination
|
||||||
model="$ctrl.model"
|
ng-if="$ctrl.model"
|
||||||
class="vn-pt-md">
|
model="$ctrl.model"
|
||||||
</vn-pagination>
|
class="vn-pt-md">
|
||||||
|
</vn-pagination>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<vn-confirm
|
<vn-confirm
|
||||||
|
|
|
@ -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();
|
||||||
|
@ -497,7 +520,8 @@ ngModule.vnComponent('smartTable', {
|
||||||
controller: SmartTable,
|
controller: SmartTable,
|
||||||
transclude: {
|
transclude: {
|
||||||
table: '?slotTable',
|
table: '?slotTable',
|
||||||
actions: '?slotActions'
|
actions: '?slotActions',
|
||||||
|
pagination: '?slotPagination'
|
||||||
},
|
},
|
||||||
bindings: {
|
bindings: {
|
||||||
model: '<?',
|
model: '<?',
|
||||||
|
|
|
@ -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";
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,7 +86,6 @@ module.exports = Self => {
|
||||||
};
|
};
|
||||||
ticketFk = await createTicket(ctx, myOptions);
|
ticketFk = await createTicket(ctx, myOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
await models.Sale.create({
|
await models.Sale.create({
|
||||||
ticketFk: ticketFk,
|
ticketFk: ticketFk,
|
||||||
itemFk: sale.itemFk,
|
itemFk: sale.itemFk,
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -129,10 +129,10 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const isAdministrative = await models.Account.hasRole(userId, 'administrative', myOptions);
|
const isSalesAssistant = await models.Account.hasRole(userId, 'salesAssistant', myOptions);
|
||||||
const client = await models.Client.findById(clientId, null, myOptions);
|
const client = await models.Client.findById(clientId, null, myOptions);
|
||||||
|
|
||||||
if (!isAdministrative && client.isTaxDataChecked)
|
if (!isSalesAssistant && client.isTaxDataChecked)
|
||||||
throw new UserError(`Not enough privileges to edit a client with verified data`);
|
throw new UserError(`Not enough privileges to edit a client with verified data`);
|
||||||
|
|
||||||
// Sage data validation
|
// Sage data validation
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
@ -232,7 +233,6 @@ module.exports = Self => {
|
||||||
const loopBackContext = LoopBackContext.getCurrentContext();
|
const loopBackContext = LoopBackContext.getCurrentContext();
|
||||||
const userId = loopBackContext.active.accessToken.userId;
|
const userId = loopBackContext.active.accessToken.userId;
|
||||||
|
|
||||||
const isAdministrative = await models.Account.hasRole(userId, 'administrative', ctx.options);
|
|
||||||
const isSalesAssistant = await models.Account.hasRole(userId, 'salesAssistant', ctx.options);
|
const isSalesAssistant = await models.Account.hasRole(userId, 'salesAssistant', ctx.options);
|
||||||
const hasChanges = orgData && changes;
|
const hasChanges = orgData && changes;
|
||||||
|
|
||||||
|
@ -245,7 +245,7 @@ module.exports = Self => {
|
||||||
const sageTransactionType = hasChanges && (changes.sageTransactionTypeFk || orgData.sageTransactionTypeFk);
|
const sageTransactionType = hasChanges && (changes.sageTransactionTypeFk || orgData.sageTransactionTypeFk);
|
||||||
const sageTransactionTypeChanged = hasChanges && orgData.sageTransactionTypeFk != sageTransactionType;
|
const sageTransactionTypeChanged = hasChanges && orgData.sageTransactionTypeFk != sageTransactionType;
|
||||||
|
|
||||||
const cantEditVerifiedData = isTaxDataCheckedChanged && !isAdministrative;
|
const cantEditVerifiedData = isTaxDataCheckedChanged && !isSalesAssistant;
|
||||||
const cantChangeSageData = (sageTaxTypeChanged || sageTransactionTypeChanged) && !isSalesAssistant;
|
const cantChangeSageData = (sageTaxTypeChanged || sageTransactionTypeChanged) && !isSalesAssistant;
|
||||||
|
|
||||||
if (cantEditVerifiedData || cantChangeSageData)
|
if (cantEditVerifiedData || cantChangeSageData)
|
||||||
|
|
|
@ -139,6 +139,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
|
||||||
|
}
|
|
@ -182,7 +182,7 @@
|
||||||
vn-one
|
vn-one
|
||||||
label="Verified data"
|
label="Verified data"
|
||||||
ng-model="$ctrl.client.isTaxDataChecked"
|
ng-model="$ctrl.client.isTaxDataChecked"
|
||||||
vn-acl="administrative">
|
vn-acl="salesAssistant">
|
||||||
</vn-check>
|
</vn-check>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
<vn-horizontal>
|
<vn-horizontal>
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -98,9 +98,6 @@ module.exports = Self => {
|
||||||
Self.latestBuysFilter = async(ctx, filter, options) => {
|
Self.latestBuysFilter = async(ctx, filter, options) => {
|
||||||
const myOptions = {};
|
const myOptions = {};
|
||||||
|
|
||||||
if (filter && filter.modelParams)
|
|
||||||
ctx.args = filter.modelParams;
|
|
||||||
|
|
||||||
if (typeof options == 'object')
|
if (typeof options == 'object')
|
||||||
Object.assign(myOptions, options);
|
Object.assign(myOptions, options);
|
||||||
|
|
||||||
|
|
|
@ -148,12 +148,12 @@
|
||||||
</td>
|
</td>
|
||||||
<td number>
|
<td number>
|
||||||
<vn-chip class="transparent" translate-attr="buy.groupingMode == 2 ? {title: 'Minimun amount'} : {title: 'Packing'}" ng-class="{'message': buy.groupingMode == 2}">
|
<vn-chip class="transparent" translate-attr="buy.groupingMode == 2 ? {title: 'Minimun amount'} : {title: 'Packing'}" ng-class="{'message': buy.groupingMode == 2}">
|
||||||
<span translate>{{::buy.packing | dashIfEmpty}}</span>
|
<span>{{::buy.packing | dashIfEmpty}}</span>
|
||||||
</vn-chip>
|
</vn-chip>
|
||||||
</td>
|
</td>
|
||||||
<td number>
|
<td number>
|
||||||
<vn-chip class="transparent" translate-attr="buy.groupingMode == 1 ? {title: 'Minimun amount'} : {title: 'Grouping'}" ng-class="{'message': buy.groupingMode == 1}">
|
<vn-chip class="transparent" translate-attr="buy.groupingMode == 1 ? {title: 'Minimun amount'} : {title: 'Grouping'}" ng-class="{'message': buy.groupingMode == 1}">
|
||||||
<span translate>{{::buy.grouping | dashIfEmpty}}</span>
|
<span>{{::buy.grouping | dashIfEmpty}}</span>
|
||||||
</vn-chip>
|
</vn-chip>
|
||||||
</td>
|
</td>
|
||||||
<td number>{{::buy.quantity}}</td>
|
<td number>{{::buy.quantity}}</td>
|
||||||
|
|
|
@ -159,8 +159,22 @@ export default class Controller extends Section {
|
||||||
lines: rowsToEdit
|
lines: rowsToEdit
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this.checkedDummyCount && this.checkedDummyCount > 0)
|
if (this.checkedDummyCount && this.checkedDummyCount > 0) {
|
||||||
data.filter = this.$.model.userParams;
|
const params = {};
|
||||||
|
if (this.$.model.userParams) {
|
||||||
|
const userParams = this.$.model.userParams;
|
||||||
|
for (let param in userParams) {
|
||||||
|
let newParam = this.exprBuilder(param, userParams[param]);
|
||||||
|
if (!newParam)
|
||||||
|
newParam = {[param]: userParams[param]};
|
||||||
|
Object.assign(params, newParam);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.$.model.userFilter)
|
||||||
|
Object.assign(params, this.$.model.userFilter.where);
|
||||||
|
|
||||||
|
data.filter = params;
|
||||||
|
}
|
||||||
|
|
||||||
return this.$http.post('Buys/editLatestBuys', data)
|
return this.$http.post('Buys/editLatestBuys', data)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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';
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue