Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into 5327-ticket.sale_ordenarPorColumnas
gitea/salix/pipeline/head Build queued... Details

This commit is contained in:
Vicent Llopis 2023-05-11 10:03:07 +02:00
commit f00643505d
729 changed files with 18211 additions and 6307 deletions

View File

@ -6,5 +6,9 @@
"source.fixAll.eslint": true "source.fixAll.eslint": true
}, },
"search.useIgnoreFiles": false, "search.useIgnoreFiles": false,
"editor.defaultFormatter": "dbaeumer.vscode-eslint" "editor.defaultFormatter": "dbaeumer.vscode-eslint",
"eslint.format.enable": true,
"[javascript]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
}
} }

View File

@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [2312.01] - 2023-04-06 ## [2320.01] - 2023-05-25
### Added ### Added
- -
@ -16,6 +16,44 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed ### Fixed
- -
## [2318.01] - 2023-05-08
### Added
- (Usuarios -> Histórico) Nueva sección
- (Roles -> Histórico) Nueva sección
- (General -> Traducciones) Correo de bienvenida a clientes al portugués y al francés
### Changed
- (Artículo -> Precio fijado) Modificado el buscador superior por uno lateral
### Fixed
- (Ticket -> Boxing) Arreglado selección de horas
- (Cesta -> Índice) Optimizada búsqueda
## [2314.01] - 2023-04-20
### Added
- (Clientes -> Morosos) Ahora se puede filtrar por las columnas "Desde" y "Fecha Ú. O.". También se envia un email al comercial cuando se añade una nota.
- (Monitor tickets) Muestra un icono al lado de la zona, si el ticket es frágil y se envía por agencia
- (Facturas recibidas -> Bases negativas) Nueva sección
### Fixed
- (Clientes -> Morosos) Ahora se mantienen los elementos seleccionados al hacer sroll.
## [2312.01] - 2023-04-06
### Added
- (Monitor tickets) Muestra un icono al lado de la zona, si el ticket es frágil y se envía por agencia
### Changed
- (Monitor tickets) Cuando se filtra por 'Pendiente' ya no muestra los estados de 'Previa'
- (Envíos -> Extra comunitarios) Se agrupan las entradas del mismo travel. Añadidos campos Referencia y Importe.
- (Envíos -> Índice) Cambiado el buscador superior por uno lateral
## [2310.01] - 2023-03-23 ## [2310.01] - 2023-03-23
### Added ### Added

1
Jenkinsfile vendored
View File

@ -52,6 +52,7 @@ pipeline {
}}} }}}
environment { environment {
NODE_ENV = "" NODE_ENV = ""
TZ = 'Europe/Madrid'
} }
parallel { parallel {
stage('Frontend') { stage('Frontend') {

View File

@ -0,0 +1,17 @@
name: account
columns:
id: id
name: name
roleFk: role
nickname: nickname
lang: lang
password: password
bcryptPassword: bcrypt password
active: active
email: email
emailVerified: email verified
created: created
updated: updated
image: image
hasGrant: has grant
userFk: user

View File

@ -0,0 +1,17 @@
name: cuenta
columns:
id: id
name: nombre
roleFk: rol
nickname: apodo
lang: idioma
password: contraseña
bcryptPassword: contraseña bcrypt
active: activo
email: email
emailVerified: email verificado
created: creado
updated: actualizado
image: imagen
hasGrant: tiene permiso
userFk: usuario

View File

@ -1,9 +1,9 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('campaign latest()', () => { describe('campaign latest()', () => {
it('should return the campaigns from the last year', async() => { it('should return the campaigns from the last year', async() => {
const now = Date.vnNew(); const now = Date.vnNew();
const result = await app.models.Campaign.latest(); const result = await models.Campaign.latest();
const randomIndex = Math.floor(Math.random() * result.length); const randomIndex = Math.floor(Math.random() * result.length);
const campaignDated = result[randomIndex].dated; const campaignDated = result[randomIndex].dated;
@ -14,7 +14,7 @@ describe('campaign latest()', () => {
it('should return the campaigns from the current year', async() => { it('should return the campaigns from the current year', async() => {
const now = Date.vnNew(); const now = Date.vnNew();
const currentYear = now.getFullYear(); const currentYear = now.getFullYear();
const result = await app.models.Campaign.latest({ const result = await models.Campaign.latest({
where: {dated: {like: `%${currentYear}%`}} where: {dated: {like: `%${currentYear}%`}}
}); });

View File

@ -1,8 +1,8 @@
const app = require('vn-loopback/server/server'); const {models} = require('vn-loopback/server/server');
describe('campaign upcoming()', () => { describe('campaign upcoming()', () => {
it('should return the upcoming campaign but from the last year', async() => { it('should return the upcoming campaign but from the last year', async() => {
const response = await app.models.Campaign.upcoming(); const response = await models.Campaign.upcoming();
const campaignDated = response.dated; const campaignDated = response.dated;
const now = Date.vnNew(); const now = Date.vnNew();

View File

@ -26,20 +26,27 @@ module.exports = Self => {
Self.send = async(ctx, to, message) => { Self.send = async(ctx, to, message) => {
const models = Self.app.models; const models = Self.app.models;
const accessToken = ctx.req.accessToken; const accessToken = ctx.req.accessToken;
const sender = await models.Account.findById(accessToken.userId); const sender = await models.VnUser.findById(accessToken.userId);
const recipient = to.replace('@', ''); const recipient = to.replace('@', '');
if (sender.name != recipient) { if (sender.name != recipient) {
await models.Chat.create({ const chat = await models.Chat.create({
senderFk: sender.id, senderFk: sender.id,
recipient: to, recipient: to,
dated: Date.vnNew(), dated: Date.vnNew(),
checkUserStatus: 0, checkUserStatus: 0,
message: message, message: message,
status: 0, status: 'sending',
attempts: 0 attempts: 0
}); });
try {
await Self.sendMessage(chat.senderFk, chat.recipient, chat.message);
await Self.updateChat(chat, 'sent');
} catch (error) {
await Self.updateChat(chat, 'error', error);
}
return true; return true;
} }

View File

@ -24,18 +24,13 @@ module.exports = Self => {
} }
}); });
Self.sendCheckingPresence = async(ctx, recipientId, message, options) => { Self.sendCheckingPresence = async(ctx, recipientId, message) => {
if (!recipientId) return false; if (!recipientId) return false;
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
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 sender = await models.VnUser.findById(userId, {fields: ['id']});
const recipient = await models.Account.findById(recipientId, null, myOptions); const recipient = await models.VnUser.findById(recipientId, null);
// Prevent sending messages to yourself // Prevent sending messages to yourself
if (recipientId == userId) return false; if (recipientId == userId) return false;
@ -46,16 +41,23 @@ module.exports = Self => {
if (process.env.NODE_ENV == 'test') if (process.env.NODE_ENV == 'test')
message = `[Test:Environment to user ${userId}] ` + message; message = `[Test:Environment to user ${userId}] ` + message;
await models.Chat.create({ const chat = await models.Chat.create({
senderFk: sender.id, senderFk: sender.id,
recipient: `@${recipient.name}`, recipient: `@${recipient.name}`,
dated: Date.vnNew(), dated: Date.vnNew(),
checkUserStatus: 1, checkUserStatus: 1,
message: message, message: message,
status: 0, status: 'sending',
attempts: 0 attempts: 0
}); });
try {
await Self.sendCheckingUserStatus(chat);
await Self.updateChat(chat, 'sent');
} catch (error) {
await Self.updateChat(chat, 'error', error);
}
return true; return true;
}; };
}; };

View File

@ -3,7 +3,6 @@ module.exports = Self => {
Self.remoteMethodCtx('sendQueued', { Self.remoteMethodCtx('sendQueued', {
description: 'Send a RocketChat message', description: 'Send a RocketChat message',
accessType: 'WRITE', accessType: 'WRITE',
accepts: [],
returns: { returns: {
type: 'object', type: 'object',
root: true root: true
@ -16,14 +15,17 @@ module.exports = Self => {
Self.sendQueued = async() => { Self.sendQueued = async() => {
const models = Self.app.models; const models = Self.app.models;
const maxAttempts = 3;
const sentStatus = 1;
const errorStatus = 2;
const chats = await models.Chat.find({ const chats = await models.Chat.find({
where: { where: {
status: {neq: sentStatus}, status: {
attempts: {lt: maxAttempts} nin: [
'sent',
'sending'
]
},
attempts: {lt: 3}
} }
}); });
@ -31,16 +33,16 @@ module.exports = Self => {
if (chat.checkUserStatus) { if (chat.checkUserStatus) {
try { try {
await Self.sendCheckingUserStatus(chat); await Self.sendCheckingUserStatus(chat);
await updateChat(chat, sentStatus); await Self.updateChat(chat, 'sent');
} catch (error) { } catch (error) {
await updateChat(chat, errorStatus, error); await Self.updateChat(chat, 'error', error);
} }
} else { } else {
try { try {
await Self.sendMessage(chat.senderFk, chat.recipient, chat.message); await Self.sendMessage(chat.senderFk, chat.recipient, chat.message);
await updateChat(chat, sentStatus); await Self.updateChat(chat, 'sent');
} catch (error) { } catch (error) {
await updateChat(chat, errorStatus, error); await Self.updateChat(chat, 'error', error);
} }
} }
} }
@ -56,7 +58,7 @@ module.exports = Self => {
const models = Self.app.models; const models = Self.app.models;
const recipientName = chat.recipient.slice(1); const recipientName = chat.recipient.slice(1);
const recipient = await models.Account.findOne({ const recipient = await models.VnUser.findOne({
where: { where: {
name: recipientName name: recipientName
} }
@ -102,7 +104,7 @@ module.exports = Self => {
} }
const models = Self.app.models; const models = Self.app.models;
const sender = await models.Account.findById(senderFk); const sender = await models.VnUser.findById(senderFk);
const login = await Self.getServiceAuth(); const login = await Self.getServiceAuth();
const avatar = `${login.host}/avatar/${sender.name}`; const avatar = `${login.host}/avatar/${sender.name}`;
@ -128,15 +130,17 @@ module.exports = Self => {
* @param {object} chat - The chat * @param {object} chat - The chat
* @param {string} status - The new status * @param {string} status - The new status
* @param {string} error - The error * @param {string} error - The error
* @param {object} options - Query options
* @return {Promise} - The request promise * @return {Promise} - The request promise
*/ */
async function updateChat(chat, status, error) {
Self.updateChat = async(chat, status, error) => {
return chat.updateAttributes({ return chat.updateAttributes({
status: status, status: status,
attempts: ++chat.attempts, attempts: ++chat.attempts,
error: error error: error
}); });
} };
/** /**
* Returns the current user status on Rocketchat * Returns the current user status on Rocketchat

View File

@ -1,12 +1,12 @@
const app = require('vn-loopback/server/server'); const {models} = require('vn-loopback/server/server');
describe('Chat notifyIssue()', () => { describe('Chat notifyIssue()', () => {
const ctx = {req: {accessToken: {userId: 1}}}; const ctx = {req: {accessToken: {userId: 1}}};
ctx.req.__ = value => { ctx.req.__ = value => {
return value; return value;
}; };
const chatModel = app.models.Chat; const chatModel = models.Chat;
const osTicketModel = app.models.OsTicket; const osTicketModel = models.OsTicket;
const departmentId = 31; const departmentId = 31;
it(`should not call to the send() method and neither return a response`, async() => { it(`should not call to the send() method and neither return a response`, async() => {
@ -29,7 +29,7 @@ describe('Chat notifyIssue()', () => {
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
const expectedMessage = `@all ➔ There's a new urgent ticket:\r\n[ID: 00001 - Issue title @batman](https://cau.verdnatura.es/scp/tickets.php?id=1)`; const expectedMessage = `@all ➔ There's a new urgent ticket:\r\n[ID: 00001 - Issue title @batman](https://cau.verdnatura.es/scp/tickets.php?id=1)`;
const department = await app.models.Department.findById(departmentId); const department = await models.Department.findById(departmentId);
let orgChatName = department.chatName; let orgChatName = department.chatName;
await department.updateAttribute('chatName', 'IT'); await department.updateAttribute('chatName', 'IT');

View File

@ -1,16 +1,16 @@
const app = require('vn-loopback/server/server'); const {models} = require('vn-loopback/server/server');
describe('Chat send()', () => { describe('Chat send()', () => {
it('should return true 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 models.Chat.send(ctx, '@salesPerson', 'I changed something');
expect(response).toEqual(true); expect(response).toEqual(true);
}); });
it('should return 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 models.Chat.send(ctx, '@salesPerson', 'I changed something');
expect(response).toEqual(false); expect(response).toEqual(false);
}); });

View File

@ -10,7 +10,7 @@ describe('Chat sendCheckingPresence()', () => {
const chat = { const chat = {
checkUserStatus: 1, checkUserStatus: 1,
status: 0, status: 'pending',
attempts: 0 attempts: 0
}; };
@ -27,7 +27,7 @@ describe('Chat sendCheckingPresence()', () => {
const chat = { const chat = {
checkUserStatus: 0, checkUserStatus: 0,
status: 0, status: 'pending',
attempts: 0 attempts: 0
}; };

View File

@ -40,8 +40,7 @@ module.exports = Self => {
try { try {
const sale = await models.Sale.findById(saleId, null, myOptions); const sale = await models.Sale.findById(saleId, null, myOptions);
const saleUpdated = await sale.updateAttributes({ const saleUpdated = await sale.updateAttributes({
originalQuantity: sale.quantity, quantity
quantity: quantity
}, myOptions); }, myOptions);
if (tx) await tx.commit(); if (tx) await tx.commit();

View File

@ -1,8 +1,8 @@
const app = require('vn-loopback/server/server'); const {models} = require('vn-loopback/server/server');
describe('getSectors()', () => { describe('getSectors()', () => {
it('return list of sectors', async() => { it('return list of sectors', async() => {
let response = await app.models.Collection.getSectors(); let response = await models.Collection.getSectors();
expect(response.length).toBeGreaterThan(0); expect(response.length).toBeGreaterThan(0);
expect(response[0].id).toEqual(1); expect(response[0].id).toEqual(1);

View File

@ -1,10 +1,10 @@
const app = require('vn-loopback/server/server'); const {models} = require('vn-loopback/server/server');
describe('newCollection()', () => { describe('newCollection()', () => {
it('should return a new collection', async() => { it('should return a new collection', async() => {
pending('#3400 analizar que hacer con rutas de back collection'); pending('#3400 analizar que hacer con rutas de back collection');
let ctx = {req: {accessToken: {userId: 1106}}}; let ctx = {req: {accessToken: {userId: 1106}}};
let response = await app.models.Collection.newCollection(ctx, 1, 1, 1); let response = await models.Collection.newCollection(ctx, 1, 1, 1);
expect(response.length).toBeGreaterThan(0); expect(response.length).toBeGreaterThan(0);
expect(response[0].ticketFk).toEqual(2); expect(response[0].ticketFk).toEqual(2);

View File

@ -1,6 +1,21 @@
const models = require('vn-loopback/server/server').models; const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('setSaleQuantity()', () => { describe('setSaleQuantity()', () => {
beforeAll(async() => {
const activeCtx = {
accessToken: {userId: 9},
http: {
req: {
headers: {origin: 'http://localhost'}
}
}
};
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
});
it('should change quantity sale', async() => { it('should change quantity sale', async() => {
const tx = await models.Ticket.beginTransaction({}); const tx = await models.Ticket.beginTransaction({});
@ -15,7 +30,7 @@ describe('setSaleQuantity()', () => {
await models.Collection.setSaleQuantity(saleId, newQuantity, options); await models.Collection.setSaleQuantity(saleId, newQuantity, options);
const updateSale = await models.Sale.findById(saleId, null, options); const updateSale = await models.Sale.findById(saleId, null, options);
expect(updateSale.originalQuantity).toEqual(originalSale.quantity); expect(updateSale.quantity).not.toEqual(originalSale.quantity);
expect(updateSale.quantity).toEqual(newQuantity); expect(updateSale.quantity).toEqual(newQuantity);
await tx.rollback(); await tx.rollback();

View File

@ -1,4 +1,4 @@
const app = require('vn-loopback/server/server'); const {models} = require('vn-loopback/server/server');
describe('dms downloadFile()', () => { describe('dms downloadFile()', () => {
let dmsId = 1; let dmsId = 1;
@ -6,7 +6,7 @@ describe('dms downloadFile()', () => {
it('should return a response for an employee with text content-type', async() => { it('should return a response for an employee with text content-type', async() => {
let workerId = 1107; let workerId = 1107;
let ctx = {req: {accessToken: {userId: workerId}}}; let ctx = {req: {accessToken: {userId: workerId}}};
const result = await app.models.Dms.downloadFile(ctx, dmsId); const result = await models.Dms.downloadFile(ctx, dmsId);
expect(result[1]).toEqual('text/plain'); expect(result[1]).toEqual('text/plain');
}); });
@ -16,7 +16,7 @@ describe('dms downloadFile()', () => {
let ctx = {req: {accessToken: {userId: clientId}}}; let ctx = {req: {accessToken: {userId: clientId}}};
let error; let error;
await app.models.Dms.downloadFile(ctx, dmsId).catch(e => { await models.Dms.downloadFile(ctx, dmsId).catch(e => {
error = e; error = e;
}).finally(() => { }).finally(() => {
expect(error.message).toEqual(`You don't have enough privileges`); expect(error.message).toEqual(`You don't have enough privileges`);

View File

@ -1,4 +1,4 @@
const app = require('vn-loopback/server/server'); const {models} = require('vn-loopback/server/server');
describe('dms removeFile()', () => { describe('dms removeFile()', () => {
let dmsId = 1; let dmsId = 1;
@ -8,7 +8,7 @@ describe('dms removeFile()', () => {
let ctx = {req: {accessToken: {userId: clientId}}}; let ctx = {req: {accessToken: {userId: clientId}}};
let error; let error;
await app.models.Dms.removeFile(ctx, dmsId).catch(e => { await models.Dms.removeFile(ctx, dmsId).catch(e => {
error = e; error = e;
}).finally(() => { }).finally(() => {
expect(error.message).toEqual(`You don't have enough privileges`); expect(error.message).toEqual(`You don't have enough privileges`);

View File

@ -1,4 +1,4 @@
const app = require('vn-loopback/server/server'); const {models} = require('vn-loopback/server/server');
describe('dms updateFile()', () => { describe('dms updateFile()', () => {
it(`should return an error for a user without enough privileges`, async() => { it(`should return an error for a user without enough privileges`, async() => {
@ -11,7 +11,7 @@ describe('dms updateFile()', () => {
let ctx = {req: {accessToken: {userId: clientId}}, args: {dmsTypeId: dmsTypeId}}; let ctx = {req: {accessToken: {userId: clientId}}, args: {dmsTypeId: dmsTypeId}};
let error; let error;
await app.models.Dms.updateFile(ctx, dmsId, warehouseId, companyId, dmsTypeId).catch(e => { await models.Dms.updateFile(ctx, dmsId, warehouseId, companyId, dmsTypeId).catch(e => {
error = e; error = e;
}).finally(() => { }).finally(() => {
expect(error.message).toEqual(`You don't have enough privileges`); expect(error.message).toEqual(`You don't have enough privileges`);

View File

@ -1,4 +1,4 @@
const app = require('vn-loopback/server/server'); const {models} = require('vn-loopback/server/server');
describe('dms uploadFile()', () => { describe('dms uploadFile()', () => {
it(`should return an error for a user without enough privileges`, async() => { it(`should return an error for a user without enough privileges`, async() => {
@ -7,7 +7,7 @@ describe('dms uploadFile()', () => {
let ctx = {req: {accessToken: {userId: clientId}}, args: {dmsTypeId: ticketDmsTypeId}}; let ctx = {req: {accessToken: {userId: clientId}}, args: {dmsTypeId: ticketDmsTypeId}};
let error; let error;
await app.models.Dms.uploadFile(ctx).catch(e => { await models.Dms.uploadFile(ctx).catch(e => {
error = e; error = e;
}).finally(() => { }).finally(() => {
expect(error.message).toEqual(`You don't have enough privileges`); expect(error.message).toEqual(`You don't have enough privileges`);

130
back/methods/image/scrub.js Normal file
View File

@ -0,0 +1,130 @@
const fs = require('fs-extra');
const path = require('path');
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.remoteMethod('scrub', {
description: 'Deletes images without database reference',
accessType: 'WRITE',
accepts: [
{
arg: 'collection',
type: 'string',
description: 'The collection name',
required: true
}, {
arg: 'remove',
type: 'boolean',
description: 'Delete instead of move images to trash'
}, {
arg: 'limit',
type: 'integer',
description: 'Maximum number of images to clean'
}, {
arg: 'dryRun',
type: 'boolean',
description: 'Simulate actions'
}, {
arg: 'skipLock',
type: 'boolean',
description: 'Wether to skip exclusive lock'
}
],
returns: {
type: 'integer',
root: true
},
http: {
path: `/scrub`,
verb: 'POST'
}
});
Self.scrub = async function(collection, remove, limit, dryRun, skipLock) {
const $ = Self.app.models;
const env = process.env.NODE_ENV;
dryRun = dryRun || (env && env !== 'production');
const instance = await $.ImageCollection.findOne({
fields: ['id'],
where: {name: collection}
});
if (!instance)
throw new UserError('Collection does not exist');
const container = await $.ImageContainer.container(collection);
const rootPath = container.client.root;
let tx;
let opts;
const lockName = 'salix.Image.scrub';
if (!skipLock) {
tx = await Self.beginTransaction({timeout: null});
opts = {transaction: tx};
const [row] = await Self.rawSql(
`SELECT GET_LOCK(?, 10) hasLock`, [lockName], opts);
if (!row.hasLock)
throw new UserError('Cannot obtain exclusive lock');
}
try {
const now = Date.vnNew().toJSON();
const scrubDir = path.join(rootPath, '.scrub', now);
const collectionDir = path.join(rootPath, collection);
const sizes = await fs.readdir(collectionDir);
let cleanCount = 0;
mainLoop: for (const size of sizes) {
const sizeDir = path.join(collectionDir, size);
const scrubSizeDir = path.join(scrubDir, collection, size);
const images = await fs.readdir(sizeDir);
for (const image of images) {
const imageName = path.parse(image).name;
const count = await Self.count({
collectionFk: collection,
name: imageName
}, opts);
const exists = count > 0;
let scrubDirCreated = false;
if (!exists) {
const srcFile = path.join(sizeDir, image);
if (remove !== true) {
if (!scrubDirCreated) {
if (!dryRun)
await fs.mkdir(scrubSizeDir, {recursive: true});
scrubDirCreated = true;
}
const dstFile = path.join(scrubSizeDir, image);
if (!dryRun) await fs.rename(srcFile, dstFile);
} else {
try {
if (!dryRun) await fs.unlink(srcFile);
} catch (err) {
console.error(err.message);
}
}
cleanCount++;
if (limit && cleanCount == limit)
break mainLoop;
}
}
}
return cleanCount;
} finally {
if (!skipLock) {
try {
await Self.rawSql(`DO RELEASE_LOCK(?)`, [lockName], opts);
await tx.rollback();
} catch (err) {
console.error(err.message);
}
}
}
};
};

View File

@ -1,4 +1,4 @@
const app = require('vn-loopback/server/server'); const {models} = require('vn-loopback/server/server');
describe('image download()', () => { describe('image download()', () => {
const collection = 'user'; const collection = 'user';
@ -8,7 +8,7 @@ describe('image download()', () => {
it('should return the image content-type of the user', async() => { it('should return the image content-type of the user', async() => {
const userId = 9; const userId = 9;
const image = await app.models.Image.download(ctx, collection, size, userId); const image = await models.Image.download(ctx, collection, size, userId);
const contentType = image[1]; const contentType = image[1];
expect(contentType).toEqual('image/png'); expect(contentType).toEqual('image/png');
@ -16,7 +16,7 @@ describe('image download()', () => {
it(`should return false if the user doesn't have image`, async() => { it(`should return false if the user doesn't have image`, async() => {
const userId = 1110; const userId = 1110;
const image = await app.models.Image.download(ctx, collection, size, userId); const image = await models.Image.download(ctx, collection, size, userId);
expect(image).toBeFalse(); expect(image).toBeFalse();
}); });

View File

@ -1,4 +1,4 @@
const app = require('vn-loopback/server/server'); const {models} = require('vn-loopback/server/server');
describe('image upload()', () => { describe('image upload()', () => {
describe('as buyer', () => { describe('as buyer', () => {
@ -16,7 +16,7 @@ describe('image upload()', () => {
let error; let error;
try { try {
await app.models.Image.upload(ctx); await models.Image.upload(ctx);
} catch (err) { } catch (err) {
error = err; error = err;
} }
@ -25,7 +25,7 @@ describe('image upload()', () => {
}); });
it('should call to the TempContainer upload method for the collection "catalog"', async() => { it('should call to the TempContainer upload method for the collection "catalog"', async() => {
const containerModel = app.models.TempContainer; const containerModel = models.TempContainer;
spyOn(containerModel, 'upload'); spyOn(containerModel, 'upload');
const ctx = {req: {accessToken: {userId: buyerId}}, const ctx = {req: {accessToken: {userId: buyerId}},
@ -36,7 +36,7 @@ describe('image upload()', () => {
}; };
try { try {
await app.models.Image.upload(ctx); await models.Image.upload(ctx);
} catch (err) { } } catch (err) { }
expect(containerModel.upload).toHaveBeenCalled(); expect(containerModel.upload).toHaveBeenCalled();
@ -49,7 +49,7 @@ describe('image upload()', () => {
const itemId = 4; const itemId = 4;
it('should be able to call to the TempContainer upload method for the collection "user"', async() => { it('should be able to call to the TempContainer upload method for the collection "user"', async() => {
const containerModel = app.models.TempContainer; const containerModel = models.TempContainer;
spyOn(containerModel, 'upload'); spyOn(containerModel, 'upload');
const ctx = {req: {accessToken: {userId: marketingId}}, const ctx = {req: {accessToken: {userId: marketingId}},
@ -60,14 +60,14 @@ describe('image upload()', () => {
}; };
try { try {
await app.models.Image.upload(ctx); await models.Image.upload(ctx);
} catch (err) { } } catch (err) { }
expect(containerModel.upload).toHaveBeenCalled(); expect(containerModel.upload).toHaveBeenCalled();
}); });
it('should be able to call to the TempContainer upload method for the collection "catalog"', async() => { it('should be able to call to the TempContainer upload method for the collection "catalog"', async() => {
const containerModel = app.models.TempContainer; const containerModel = models.TempContainer;
spyOn(containerModel, 'upload'); spyOn(containerModel, 'upload');
const ctx = {req: {accessToken: {userId: marketingId}}, const ctx = {req: {accessToken: {userId: marketingId}},
@ -78,7 +78,7 @@ describe('image upload()', () => {
}; };
try { try {
await app.models.Image.upload(ctx); await models.Image.upload(ctx);
} catch (err) { } } catch (err) { }
expect(containerModel.upload).toHaveBeenCalled(); expect(containerModel.upload).toHaveBeenCalled();
@ -91,7 +91,7 @@ describe('image upload()', () => {
const itemId = 4; const itemId = 4;
it('should upload a file for the collection "user" and call to the TempContainer upload method', async() => { it('should upload a file for the collection "user" and call to the TempContainer upload method', async() => {
const containerModel = app.models.TempContainer; const containerModel = models.TempContainer;
spyOn(containerModel, 'upload'); spyOn(containerModel, 'upload');
const ctx = {req: {accessToken: {userId: hhrrId}}, const ctx = {req: {accessToken: {userId: hhrrId}},
@ -102,7 +102,7 @@ describe('image upload()', () => {
}; };
try { try {
await app.models.Image.upload(ctx); await models.Image.upload(ctx);
} catch (err) { } } catch (err) { }
expect(containerModel.upload).toHaveBeenCalled(); expect(containerModel.upload).toHaveBeenCalled();
@ -118,7 +118,7 @@ describe('image upload()', () => {
let error; let error;
try { try {
await app.models.Image.upload(ctx); await models.Image.upload(ctx);
} catch (err) { } catch (err) {
error = err; error = err;
} }

View File

@ -1,7 +1,6 @@
const UserError = require('vn-loopback/util/user-error'); const UserError = require('vn-loopback/util/user-error');
const fs = require('fs-extra'); const fs = require('fs/promises');
const path = require('path'); const path = require('path');
const uuid = require('uuid');
module.exports = Self => { module.exports = Self => {
Self.remoteMethodCtx('upload', { Self.remoteMethodCtx('upload', {
@ -13,13 +12,13 @@ module.exports = Self => {
type: 'Number', type: 'Number',
description: 'The entity id', description: 'The entity id',
required: true required: true
}, }, {
{
arg: 'collection', arg: 'collection',
type: 'string', type: 'string',
description: 'The collection name', description: 'The collection name',
required: true required: true
}], }
],
returns: { returns: {
type: 'Object', type: 'Object',
root: true root: true
@ -36,7 +35,7 @@ module.exports = Self => {
const fileOptions = {}; const fileOptions = {};
const args = ctx.args; const args = ctx.args;
let srcFile; let tempFilePath;
try { try {
const hasWriteRole = await models.ImageCollection.hasWriteRole(ctx, args.collection); const hasWriteRole = await models.ImageCollection.hasWriteRole(ctx, args.collection);
if (!hasWriteRole) if (!hasWriteRole)
@ -53,15 +52,20 @@ module.exports = Self => {
}); });
const file = await TempContainer.getFile(tempContainer.name, uploadedFile.name); const file = await TempContainer.getFile(tempContainer.name, uploadedFile.name);
srcFile = path.join(file.client.root, file.container, file.name); tempFilePath = path.join(file.client.root, file.container, file.name);
const fileName = `${uuid.v4()}.png`; const fileName = `${args.id}.png`;
await models.Image.registerImage(args.collection, srcFile, fileName, args.id);
} catch (e) {
if (fs.existsSync(srcFile))
await fs.unlink(srcFile);
throw e; await models.Image.resize({
collectionName: args.collection,
srcFile: tempFilePath,
fileName: fileName,
entityId: args.id
});
} finally {
try {
await fs.unlink(tempFilePath);
} catch (error) { }
} }
}; };
}; };

View File

@ -69,15 +69,15 @@ module.exports = Self => {
const result = response.headers.get('set-cookie'); const result = response.headers.get('set-cookie');
const [firtHeader] = result.split(' '); const [firtHeader] = result.split(' ');
const firtCookie = firtHeader.substring(0, firtHeader.length - 1); const cookie = firtHeader.substring(0, firtHeader.length - 1);
const body = await response.text(); const body = await response.text();
const dom = new jsdom.JSDOM(body); const dom = new jsdom.JSDOM(body);
const token = dom.window.document.querySelector('[name="__CSRFToken__"]').value; const token = dom.window.document.querySelector('[name="__CSRFToken__"]').value;
await login(token, firtCookie); await login(token, cookie);
} }
async function login(token, firtCookie) { async function login(token, cookie) {
const data = { const data = {
__CSRFToken__: token, __CSRFToken__: token,
do: 'scplogin', do: 'scplogin',
@ -90,21 +90,18 @@ module.exports = Self => {
body: new URLSearchParams(data), body: new URLSearchParams(data),
headers: { headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Cookie': firtCookie 'Cookie': cookie
} }
}; };
const response = await fetch(ostUri, params); await fetch(ostUri, params);
const result = response.headers.get('set-cookie');
const [firtHeader] = result.split(' ');
const secondCookie = firtHeader.substring(0, firtHeader.length - 1);
await close(token, secondCookie); await close(token, cookie);
} }
async function close(token, secondCookie) { async function close(token, cookie) {
for (const ticketId of ticketsId) { for (const ticketId of ticketsId) {
try { try {
const lock = await getLockCode(token, secondCookie, ticketId); const lock = await getLockCode(token, cookie, ticketId);
if (!lock.code) { if (!lock.code) {
let error = `Can't get lock code`; let error = `Can't get lock code`;
if (lock.msg) error += `: ${lock.msg}`; if (lock.msg) error += `: ${lock.msg}`;
@ -127,7 +124,7 @@ module.exports = Self => {
method: 'POST', method: 'POST',
body: form, body: form,
headers: { headers: {
'Cookie': secondCookie 'Cookie': cookie
} }
}; };
await fetch(ostUri, params); await fetch(ostUri, params);
@ -139,13 +136,13 @@ module.exports = Self => {
} }
} }
async function getLockCode(token, secondCookie, ticketId) { async function getLockCode(token, cookie, ticketId) {
const ostUri = `${config.host}/ajax.php/lock/ticket/${ticketId}`; const ostUri = `${config.host}/ajax.php/lock/ticket/${ticketId}`;
const params = { const params = {
method: 'POST', method: 'POST',
headers: { headers: {
'X-CSRFToken': token, 'X-CSRFToken': token,
'Cookie': secondCookie 'Cookie': cookie
} }
}; };
const response = await fetch(ostUri, params); const response = await fetch(ostUri, params);

View File

@ -1,4 +1,4 @@
const app = require('vn-loopback/server/server'); const {models} = require('vn-loopback/server/server');
const LoopBackContext = require('loopback-context'); const LoopBackContext = require('loopback-context');
describe('getStarredModules()', () => { describe('getStarredModules()', () => {
@ -19,13 +19,13 @@ describe('getStarredModules()', () => {
}); });
it(`should return the starred modules for a given user`, async() => { it(`should return the starred modules for a given user`, async() => {
const newStarred = await app.models.StarredModule.create({workerFk: 9, moduleFk: 'customer', position: 1}); const newStarred = await models.StarredModule.create({workerFk: 9, moduleFk: 'customer', position: 1});
const starredModules = await app.models.StarredModule.getStarredModules(ctx); const starredModules = await models.StarredModule.getStarredModules(ctx);
expect(starredModules.length).toEqual(1); expect(starredModules.length).toEqual(1);
expect(starredModules[0].moduleFk).toEqual('customer'); expect(starredModules[0].moduleFk).toEqual('customer');
// restores // restores
await app.models.StarredModule.destroyById(newStarred.id); await models.StarredModule.destroyById(newStarred.id);
}); });
}); });

View File

@ -1,4 +1,4 @@
const app = require('vn-loopback/server/server'); const {models} = require('vn-loopback/server/server');
const LoopBackContext = require('loopback-context'); const LoopBackContext = require('loopback-context');
describe('setPosition()', () => { describe('setPosition()', () => {
@ -21,7 +21,7 @@ describe('setPosition()', () => {
}); });
it('should increase the orders module position by replacing it with clients and vice versa', async() => { it('should increase the orders module position by replacing it with clients and vice versa', async() => {
const tx = await app.models.StarredModule.beginTransaction({}); const tx = await models.StarredModule.beginTransaction({});
const filter = { const filter = {
where: { where: {
@ -32,24 +32,24 @@ describe('setPosition()', () => {
try { try {
const options = {transaction: tx}; const options = {transaction: tx};
await app.models.StarredModule.toggleStarredModule(ctx, 'order', options); await models.StarredModule.toggleStarredModule(ctx, 'order', options);
await app.models.StarredModule.toggleStarredModule(ctx, 'customer', options); await models.StarredModule.toggleStarredModule(ctx, 'customer', options);
let orders = await app.models.StarredModule.findOne(filter, options); let orders = await models.StarredModule.findOne(filter, options);
filter.where.moduleFk = 'customer'; filter.where.moduleFk = 'customer';
let clients = await app.models.StarredModule.findOne(filter, options); let clients = await models.StarredModule.findOne(filter, options);
expect(orders.position).toEqual(1); expect(orders.position).toEqual(1);
expect(clients.position).toEqual(2); expect(clients.position).toEqual(2);
await app.models.StarredModule.setPosition(ctx, 'customer', 'left', options); await models.StarredModule.setPosition(ctx, 'customer', 'left', options);
filter.where.moduleFk = 'customer'; filter.where.moduleFk = 'customer';
clients = await app.models.StarredModule.findOne(filter, options); clients = await models.StarredModule.findOne(filter, options);
filter.where.moduleFk = 'order'; filter.where.moduleFk = 'order';
orders = await app.models.StarredModule.findOne(filter, options); orders = await models.StarredModule.findOne(filter, options);
expect(clients.position).toEqual(1); expect(clients.position).toEqual(1);
expect(orders.position).toEqual(2); expect(orders.position).toEqual(2);
@ -62,7 +62,7 @@ describe('setPosition()', () => {
}); });
it('should decrease the orders module position by replacing it with clients and vice versa', async() => { it('should decrease the orders module position by replacing it with clients and vice versa', async() => {
const tx = await app.models.StarredModule.beginTransaction({}); const tx = await models.StarredModule.beginTransaction({});
const filter = { const filter = {
where: { where: {
@ -73,24 +73,24 @@ describe('setPosition()', () => {
try { try {
const options = {transaction: tx}; const options = {transaction: tx};
await app.models.StarredModule.toggleStarredModule(ctx, 'order', options); await models.StarredModule.toggleStarredModule(ctx, 'order', options);
await app.models.StarredModule.toggleStarredModule(ctx, 'customer', options); await models.StarredModule.toggleStarredModule(ctx, 'customer', options);
let orders = await app.models.StarredModule.findOne(filter, options); let orders = await models.StarredModule.findOne(filter, options);
filter.where.moduleFk = 'customer'; filter.where.moduleFk = 'customer';
let clients = await app.models.StarredModule.findOne(filter, options); let clients = await models.StarredModule.findOne(filter, options);
expect(orders.position).toEqual(1); expect(orders.position).toEqual(1);
expect(clients.position).toEqual(2); expect(clients.position).toEqual(2);
await app.models.StarredModule.setPosition(ctx, 'order', 'right', options); await models.StarredModule.setPosition(ctx, 'order', 'right', options);
filter.where.moduleFk = 'order'; filter.where.moduleFk = 'order';
orders = await app.models.StarredModule.findOne(filter, options); orders = await models.StarredModule.findOne(filter, options);
filter.where.moduleFk = 'customer'; filter.where.moduleFk = 'customer';
clients = await app.models.StarredModule.findOne(filter, options); clients = await models.StarredModule.findOne(filter, options);
expect(orders.position).toEqual(2); expect(orders.position).toEqual(2);
expect(clients.position).toEqual(1); expect(clients.position).toEqual(1);
@ -103,7 +103,7 @@ describe('setPosition()', () => {
}); });
it('should switch two modules after adding and deleting several modules', async() => { it('should switch two modules after adding and deleting several modules', async() => {
const tx = await app.models.StarredModule.beginTransaction({}); const tx = await models.StarredModule.beginTransaction({});
const filter = { const filter = {
where: { where: {
@ -115,29 +115,29 @@ describe('setPosition()', () => {
try { try {
const options = {transaction: tx}; const options = {transaction: tx};
await app.models.StarredModule.toggleStarredModule(ctx, 'customer', options); await models.StarredModule.toggleStarredModule(ctx, 'customer', options);
await app.models.StarredModule.toggleStarredModule(ctx, 'order', options); await models.StarredModule.toggleStarredModule(ctx, 'order', options);
await app.models.StarredModule.toggleStarredModule(ctx, 'customer', options); await models.StarredModule.toggleStarredModule(ctx, 'customer', options);
await app.models.StarredModule.toggleStarredModule(ctx, 'order', options); await models.StarredModule.toggleStarredModule(ctx, 'order', options);
await app.models.StarredModule.toggleStarredModule(ctx, 'item', options); await models.StarredModule.toggleStarredModule(ctx, 'item', options);
await app.models.StarredModule.toggleStarredModule(ctx, 'claim', options); await models.StarredModule.toggleStarredModule(ctx, 'claim', options);
await app.models.StarredModule.toggleStarredModule(ctx, 'customer', options); await models.StarredModule.toggleStarredModule(ctx, 'customer', options);
await app.models.StarredModule.toggleStarredModule(ctx, 'order', options); await models.StarredModule.toggleStarredModule(ctx, 'order', options);
await app.models.StarredModule.toggleStarredModule(ctx, 'zone', options); await models.StarredModule.toggleStarredModule(ctx, 'zone', options);
const items = await app.models.StarredModule.findOne(filter, options); const items = await models.StarredModule.findOne(filter, options);
filter.where.moduleFk = 'claim'; filter.where.moduleFk = 'claim';
const claims = await app.models.StarredModule.findOne(filter, options); const claims = await models.StarredModule.findOne(filter, options);
filter.where.moduleFk = 'customer'; filter.where.moduleFk = 'customer';
let clients = await app.models.StarredModule.findOne(filter, options); let clients = await models.StarredModule.findOne(filter, options);
filter.where.moduleFk = 'order'; filter.where.moduleFk = 'order';
let orders = await app.models.StarredModule.findOne(filter, options); let orders = await models.StarredModule.findOne(filter, options);
filter.where.moduleFk = 'zone'; filter.where.moduleFk = 'zone';
const zones = await app.models.StarredModule.findOne(filter, options); const zones = await models.StarredModule.findOne(filter, options);
expect(items.position).toEqual(1); expect(items.position).toEqual(1);
expect(claims.position).toEqual(2); expect(claims.position).toEqual(2);
@ -145,13 +145,13 @@ describe('setPosition()', () => {
expect(orders.position).toEqual(4); expect(orders.position).toEqual(4);
expect(zones.position).toEqual(5); expect(zones.position).toEqual(5);
await app.models.StarredModule.setPosition(ctx, 'customer', 'right', options); await models.StarredModule.setPosition(ctx, 'customer', 'right', options);
filter.where.moduleFk = 'order'; filter.where.moduleFk = 'order';
orders = await app.models.StarredModule.findOne(filter, options); orders = await models.StarredModule.findOne(filter, options);
filter.where.moduleFk = 'customer'; filter.where.moduleFk = 'customer';
clients = await app.models.StarredModule.findOne(filter, options); clients = await models.StarredModule.findOne(filter, options);
expect(orders.position).toEqual(3); expect(orders.position).toEqual(3);
expect(clients.position).toEqual(4); expect(clients.position).toEqual(4);
@ -164,7 +164,7 @@ describe('setPosition()', () => {
}); });
it('should switch two modules after adding and deleting a module between them', async() => { it('should switch two modules after adding and deleting a module between them', async() => {
const tx = await app.models.StarredModule.beginTransaction({}); const tx = await models.StarredModule.beginTransaction({});
const filter = { const filter = {
where: { where: {
@ -176,25 +176,25 @@ describe('setPosition()', () => {
try { try {
const options = {transaction: tx}; const options = {transaction: tx};
await app.models.StarredModule.toggleStarredModule(ctx, 'item', options); await models.StarredModule.toggleStarredModule(ctx, 'item', options);
await app.models.StarredModule.toggleStarredModule(ctx, 'customer', options); await models.StarredModule.toggleStarredModule(ctx, 'customer', options);
await app.models.StarredModule.toggleStarredModule(ctx, 'claim', options); await models.StarredModule.toggleStarredModule(ctx, 'claim', options);
await app.models.StarredModule.toggleStarredModule(ctx, 'order', options); await models.StarredModule.toggleStarredModule(ctx, 'order', options);
await app.models.StarredModule.toggleStarredModule(ctx, 'zone', options); await models.StarredModule.toggleStarredModule(ctx, 'zone', options);
const items = await app.models.StarredModule.findOne(filter, options); const items = await models.StarredModule.findOne(filter, options);
filter.where.moduleFk = 'customer'; filter.where.moduleFk = 'customer';
let clients = await app.models.StarredModule.findOne(filter, options); let clients = await models.StarredModule.findOne(filter, options);
filter.where.moduleFk = 'claim'; filter.where.moduleFk = 'claim';
const claims = await app.models.StarredModule.findOne(filter, options); const claims = await models.StarredModule.findOne(filter, options);
filter.where.moduleFk = 'order'; filter.where.moduleFk = 'order';
let orders = await app.models.StarredModule.findOne(filter, options); let orders = await models.StarredModule.findOne(filter, options);
filter.where.moduleFk = 'zone'; filter.where.moduleFk = 'zone';
const zones = await app.models.StarredModule.findOne(filter, options); const zones = await models.StarredModule.findOne(filter, options);
expect(items.position).toEqual(1); expect(items.position).toEqual(1);
expect(clients.position).toEqual(2); expect(clients.position).toEqual(2);
@ -202,14 +202,14 @@ describe('setPosition()', () => {
expect(orders.position).toEqual(4); expect(orders.position).toEqual(4);
expect(zones.position).toEqual(5); expect(zones.position).toEqual(5);
await app.models.StarredModule.toggleStarredModule(ctx, 'claim', options); await models.StarredModule.toggleStarredModule(ctx, 'claim', options);
await app.models.StarredModule.setPosition(ctx, 'customer', 'right', options); await models.StarredModule.setPosition(ctx, 'customer', 'right', options);
filter.where.moduleFk = 'customer'; filter.where.moduleFk = 'customer';
clients = await app.models.StarredModule.findOne(filter, options); clients = await models.StarredModule.findOne(filter, options);
filter.where.moduleFk = 'order'; filter.where.moduleFk = 'order';
orders = await app.models.StarredModule.findOne(filter, options); orders = await models.StarredModule.findOne(filter, options);
expect(orders.position).toEqual(2); expect(orders.position).toEqual(2);
expect(clients.position).toEqual(4); expect(clients.position).toEqual(4);

View File

@ -1,4 +1,4 @@
const app = require('vn-loopback/server/server'); const {models} = require('vn-loopback/server/server');
const LoopBackContext = require('loopback-context'); const LoopBackContext = require('loopback-context');
describe('toggleStarredModule()', () => { describe('toggleStarredModule()', () => {
@ -21,16 +21,16 @@ describe('toggleStarredModule()', () => {
}); });
it('should create a new starred module and then remove it by calling the method again with same args', async() => { it('should create a new starred module and then remove it by calling the method again with same args', async() => {
const starredModule = await app.models.StarredModule.toggleStarredModule(ctx, 'order'); const starredModule = await models.StarredModule.toggleStarredModule(ctx, 'order');
let starredModules = await app.models.StarredModule.getStarredModules(ctx); let starredModules = await models.StarredModule.getStarredModules(ctx);
expect(starredModules.length).toEqual(1); expect(starredModules.length).toEqual(1);
expect(starredModule.moduleFk).toEqual('order'); expect(starredModule.moduleFk).toEqual('order');
expect(starredModule.workerFk).toEqual(activeCtx.accessToken.userId); expect(starredModule.workerFk).toEqual(activeCtx.accessToken.userId);
expect(starredModule.position).toEqual(starredModules.length); expect(starredModule.position).toEqual(starredModules.length);
await app.models.StarredModule.toggleStarredModule(ctx, 'order'); await models.StarredModule.toggleStarredModule(ctx, 'order');
starredModules = await app.models.StarredModule.getStarredModules(ctx); starredModules = await models.StarredModule.getStarredModules(ctx);
expect(starredModules.length).toEqual(0); expect(starredModules.length).toEqual(0);
}); });

View File

@ -22,7 +22,7 @@ module.exports = Self => {
let userId = ctx.req.accessToken.userId; let userId = ctx.req.accessToken.userId;
let models = Self.app.models; let models = Self.app.models;
let user = await models.Account.findById(userId, { let user = await Self.findById(userId, {
fields: ['id', 'name', 'nickname', 'email', 'lang'], fields: ['id', 'name', 'nickname', 'email', 'lang'],
include: { include: {
relation: 'userConfig', relation: 'userConfig',

View File

@ -1,9 +1,14 @@
const UserError = require('vn-loopback/util/user-error'); const UserError = require('vn-loopback/util/user-error');
module.exports = Self => { module.exports = Self => {
Self.remoteMethodCtx('privileges', { Self.remoteMethod('privileges', {
description: 'Change role and hasGrant if user has privileges', description: 'Change role and hasGrant if user has privileges',
accepts: [ accepts: [
{
arg: 'ctx',
type: 'Object',
http: {source: 'context'}
},
{ {
arg: 'id', arg: 'id',
type: 'number', type: 'number',
@ -39,9 +44,9 @@ module.exports = Self => {
if (typeof options == 'object') if (typeof options == 'object')
Object.assign(myOptions, options); Object.assign(myOptions, options);
const user = await models.Account.findById(userId, {fields: ['hasGrant']}, myOptions); const user = await Self.findById(userId, {fields: ['hasGrant']}, myOptions);
const userToUpdate = await models.Account.findById(id, { const userToUpdate = await Self.findById(id, {
fields: ['id', 'name', 'hasGrant', 'roleFk', 'password'], fields: ['id', 'name', 'hasGrant', 'roleFk', 'password'],
include: { include: {
relation: 'role', relation: 'role',
@ -54,7 +59,7 @@ module.exports = Self => {
if (!user.hasGrant) if (!user.hasGrant)
throw new UserError(`You don't have grant privilege`); throw new UserError(`You don't have grant privilege`);
const hasRoleFromUser = await models.Account.hasRole(userId, userToUpdate.role().name, myOptions); const hasRoleFromUser = await Self.hasRole(userId, userToUpdate.role().name, myOptions);
if (!hasRoleFromUser) if (!hasRoleFromUser)
throw new UserError(`You don't own the role and you can't assign it to another user`); throw new UserError(`You don't own the role and you can't assign it to another user`);
@ -64,7 +69,7 @@ module.exports = Self => {
if (roleFk) { if (roleFk) {
const role = await models.Role.findById(roleFk, {fields: ['name']}, myOptions); const role = await models.Role.findById(roleFk, {fields: ['name']}, myOptions);
const hasRole = await models.Account.hasRole(userId, role.name, myOptions); const hasRole = await Self.hasRole(userId, role.name, myOptions);
if (!hasRole) if (!hasRole)
throw new UserError(`You don't own the role and you can't assign it to another user`); throw new UserError(`You don't own the role and you can't assign it to another user`);
@ -73,6 +78,6 @@ module.exports = Self => {
} }
await userToUpdate.save(userToUpdate); await userToUpdate.save(userToUpdate);
await models.UserAccount.sync(userToUpdate.name); await models.Account.sync(userToUpdate.name);
}; };
}; };

View File

@ -20,7 +20,7 @@ module.exports = Self => {
const usesEmail = user.indexOf('@') !== -1; const usesEmail = user.indexOf('@') !== -1;
if (!usesEmail) { if (!usesEmail) {
const account = await models.Account.findOne({ const account = await models.VnUser.findOne({
fields: ['email'], fields: ['email'],
where: {name: user} where: {name: user}
}); });
@ -28,7 +28,7 @@ module.exports = Self => {
} }
try { try {
await models.user.resetPassword({email: user, emailTemplate: 'recover-password'}); await Self.resetPassword({email: user, emailTemplate: 'recover-password'});
} catch (err) { } catch (err) {
if (err.code === 'EMAIL_NOT_FOUND') if (err.code === 'EMAIL_NOT_FOUND')
return; return;

View File

@ -1,14 +1,14 @@
const md5 = require('md5');
const UserError = require('vn-loopback/util/user-error'); const UserError = require('vn-loopback/util/user-error');
module.exports = Self => { module.exports = Self => {
Self.remoteMethod('login', { Self.remoteMethod('signIn', {
description: 'Login a user with username/email and password', description: 'Login a user with username/email and password',
accepts: [ accepts: [
{ {
arg: 'user', arg: 'user',
type: 'String', type: 'String',
description: 'The user name or email', description: 'The user name or email',
http: {source: 'form'},
required: true required: true
}, { }, {
arg: 'password', arg: 'password',
@ -21,20 +21,20 @@ module.exports = Self => {
root: true root: true
}, },
http: { http: {
path: `/login`, path: `/signIn`,
verb: 'POST' verb: 'POST'
} }
}); });
Self.login = async function(user, password) { Self.signIn = async function(user, password) {
let $ = Self.app.models; let models = Self.app.models;
let token; let token;
let usesEmail = user.indexOf('@') !== -1; let usesEmail = user.indexOf('@') !== -1;
let userInfo = usesEmail let userInfo = usesEmail
? {email: user} ? {email: user}
: {username: user}; : {username: user};
let instance = await $.User.findOne({ let instance = await Self.findOne({
fields: ['username', 'password'], fields: ['username', 'password'],
where: userInfo where: userInfo
}); });
@ -42,29 +42,27 @@ module.exports = Self => {
let where = usesEmail let where = usesEmail
? {email: user} ? {email: user}
: {name: user}; : {name: user};
let account = await Self.findOne({ let vnUser = await Self.findOne({
fields: ['active', 'password'], fields: ['active'],
where where
}); });
let validCredentials = instance && ( let validCredentials = instance
await instance.hasPassword(password) || && await instance.hasPassword(password);
account.password == md5(password || '')
);
if (validCredentials) { if (validCredentials) {
if (!account.active) if (!vnUser.active)
throw new UserError('User disabled'); throw new UserError('User disabled');
try { try {
await $.UserAccount.sync(instance.username, password); await models.Account.sync(instance.username, password);
} catch (err) { } catch (err) {
console.warn(err); console.warn(err);
} }
} }
let loginInfo = Object.assign({password}, userInfo); let loginInfo = Object.assign({password}, userInfo);
token = await $.User.login(loginInfo, 'user'); token = await Self.login(loginInfo, 'user');
return {token: token.id}; return {token: token.id};
}; };
}; };

View File

@ -1,6 +1,6 @@
const models = require('vn-loopback/server/server').models; const models = require('vn-loopback/server/server').models;
describe('account privileges()', () => { describe('VnUser privileges()', () => {
const employeeId = 1; const employeeId = 1;
const developerId = 9; const developerId = 9;
const sysadminId = 66; const sysadminId = 66;
@ -10,13 +10,13 @@ describe('account privileges()', () => {
it('should throw an error when user not has privileges', async() => { it('should throw an error when user not has privileges', async() => {
const ctx = {req: {accessToken: {userId: developerId}}}; const ctx = {req: {accessToken: {userId: developerId}}};
const tx = await models.Account.beginTransaction({}); const tx = await models.VnUser.beginTransaction({});
let error; let error;
try { try {
const options = {transaction: tx}; const options = {transaction: tx};
await models.Account.privileges(ctx, employeeId, null, true, options); await models.VnUser.privileges(ctx, employeeId, null, true, options);
await tx.rollback(); await tx.rollback();
} catch (e) { } catch (e) {
@ -29,13 +29,13 @@ describe('account privileges()', () => {
it('should throw an error when user has privileges but not has the role', async() => { it('should throw an error when user has privileges but not has the role', async() => {
const ctx = {req: {accessToken: {userId: sysadminId}}}; const ctx = {req: {accessToken: {userId: sysadminId}}};
const tx = await models.Account.beginTransaction({}); const tx = await models.VnUser.beginTransaction({});
let error; let error;
try { try {
const options = {transaction: tx}; const options = {transaction: tx};
await models.Account.privileges(ctx, employeeId, rootId, null, options); await models.VnUser.privileges(ctx, employeeId, rootId, null, options);
await tx.rollback(); await tx.rollback();
} catch (e) { } catch (e) {
@ -48,13 +48,13 @@ describe('account privileges()', () => {
it('should throw an error when user has privileges but not has the role from user', async() => { it('should throw an error when user has privileges but not has the role from user', async() => {
const ctx = {req: {accessToken: {userId: sysadminId}}}; const ctx = {req: {accessToken: {userId: sysadminId}}};
const tx = await models.Account.beginTransaction({}); const tx = await models.VnUser.beginTransaction({});
let error; let error;
try { try {
const options = {transaction: tx}; const options = {transaction: tx};
await models.Account.privileges(ctx, itBossId, developerId, null, options); await models.VnUser.privileges(ctx, itBossId, developerId, null, options);
await tx.rollback(); await tx.rollback();
} catch (e) { } catch (e) {
@ -67,7 +67,7 @@ describe('account privileges()', () => {
it('should change role', async() => { it('should change role', async() => {
const ctx = {req: {accessToken: {userId: sysadminId}}}; const ctx = {req: {accessToken: {userId: sysadminId}}};
const tx = await models.Account.beginTransaction({}); const tx = await models.VnUser.beginTransaction({});
const options = {transaction: tx}; const options = {transaction: tx};
const agency = await models.Role.findOne({ const agency = await models.Role.findOne({
@ -79,8 +79,8 @@ describe('account privileges()', () => {
let error; let error;
let result; let result;
try { try {
await models.Account.privileges(ctx, clarkKent, agency.id, null, options); await models.VnUser.privileges(ctx, clarkKent, agency.id, null, options);
result = await models.Account.findById(clarkKent, null, options); result = await models.VnUser.findById(clarkKent, null, options);
await tx.rollback(); await tx.rollback();
} catch (e) { } catch (e) {
@ -94,14 +94,14 @@ describe('account privileges()', () => {
it('should change hasGrant', async() => { it('should change hasGrant', async() => {
const ctx = {req: {accessToken: {userId: sysadminId}}}; const ctx = {req: {accessToken: {userId: sysadminId}}};
const tx = await models.Account.beginTransaction({}); const tx = await models.VnUser.beginTransaction({});
let error; let error;
let result; let result;
try { try {
const options = {transaction: tx}; const options = {transaction: tx};
await models.Account.privileges(ctx, clarkKent, null, true, options); await models.VnUser.privileges(ctx, clarkKent, null, true, options);
result = await models.Account.findById(clarkKent, null, options); result = await models.VnUser.findById(clarkKent, null, options);
await tx.rollback(); await tx.rollback();
} catch (e) { } catch (e) {

View File

@ -1,25 +1,25 @@
const app = require('vn-loopback/server/server'); const {models} = require('vn-loopback/server/server');
describe('account login()', () => { describe('VnUser signIn()', () => {
describe('when credentials are correct', () => { describe('when credentials are correct', () => {
it('should return the token', async() => { it('should return the token', async() => {
let login = await app.models.Account.login('salesAssistant', 'nightmare'); let login = await models.VnUser.signIn('salesAssistant', 'nightmare');
let accessToken = await app.models.AccessToken.findById(login.token); let accessToken = await models.AccessToken.findById(login.token);
let ctx = {req: {accessToken: accessToken}}; let ctx = {req: {accessToken: accessToken}};
expect(login.token).toBeDefined(); expect(login.token).toBeDefined();
await app.models.Account.logout(ctx); await models.VnUser.signOut(ctx);
}); });
it('should return the token if the user doesnt exist but the client does', async() => { it('should return the token if the user doesnt exist but the client does', async() => {
let login = await app.models.Account.login('PetterParker', 'nightmare'); let login = await models.VnUser.signIn('PetterParker', 'nightmare');
let accessToken = await app.models.AccessToken.findById(login.token); let accessToken = await models.AccessToken.findById(login.token);
let ctx = {req: {accessToken: accessToken}}; let ctx = {req: {accessToken: accessToken}};
expect(login.token).toBeDefined(); expect(login.token).toBeDefined();
await app.models.Account.logout(ctx); await models.VnUser.signOut(ctx);
}); });
}); });
@ -28,7 +28,7 @@ describe('account login()', () => {
let error; let error;
try { try {
await app.models.Account.login('IDontExist', 'TotallyWrongPassword'); await models.VnUser.signIn('IDontExist', 'TotallyWrongPassword');
} catch (e) { } catch (e) {
error = e; error = e;
} }

View File

@ -1,13 +1,13 @@
const app = require('vn-loopback/server/server'); const {models} = require('vn-loopback/server/server');
describe('account logout()', () => { describe('VnUser signOut()', () => {
it('should logout and remove token after valid login', async() => { it('should logout and remove token after valid login', async() => {
let loginResponse = await app.models.Account.login('buyer', 'nightmare'); let loginResponse = await models.VnUser.signOut('buyer', 'nightmare');
let accessToken = await app.models.AccessToken.findById(loginResponse.token); let accessToken = await models.AccessToken.findById(loginResponse.token);
let ctx = {req: {accessToken: accessToken}}; let ctx = {req: {accessToken: accessToken}};
let logoutResponse = await app.models.Account.logout(ctx); let logoutResponse = await models.VnUser.signOut(ctx);
let tokenAfterLogout = await app.models.AccessToken.findById(loginResponse.token); let tokenAfterLogout = await models.AccessToken.findById(loginResponse.token);
expect(logoutResponse).toBeTrue(); expect(logoutResponse).toBeTrue();
expect(tokenAfterLogout).toBeNull(); expect(tokenAfterLogout).toBeNull();
@ -18,7 +18,7 @@ describe('account logout()', () => {
let ctx = {req: {accessToken: {id: 'invalidToken'}}}; let ctx = {req: {accessToken: {id: 'invalidToken'}}};
try { try {
response = await app.models.Account.logout(ctx); response = await models.VnUser.signOut(ctx);
} catch (e) { } catch (e) {
error = e; error = e;
} }
@ -32,7 +32,7 @@ describe('account logout()', () => {
let ctx = {req: {accessToken: null}}; let ctx = {req: {accessToken: null}};
try { try {
response = await app.models.Account.logout(ctx); response = await models.VnUser.signOut(ctx);
} catch (e) { } catch (e) {
error = e; error = e;
} }

View File

@ -1,7 +1,4 @@
{ {
"Account": {
"dataSource": "vn"
},
"AccountingType": { "AccountingType": {
"dataSource": "vn" "dataSource": "vn"
}, },
@ -125,10 +122,10 @@
"UserConfigView": { "UserConfigView": {
"dataSource": "vn" "dataSource": "vn"
}, },
"UserLog": { "Warehouse": {
"dataSource": "vn" "dataSource": "vn"
}, },
"Warehouse": { "VnUser": {
"dataSource": "vn" "dataSource": "vn"
}, },
"OsTicket": { "OsTicket": {

View File

@ -1,139 +0,0 @@
/* eslint max-len: ["error", { "code": 150 }]*/
const md5 = require('md5');
const LoopBackContext = require('loopback-context');
const {Email} = require('vn-print');
module.exports = Self => {
require('../methods/account/login')(Self);
require('../methods/account/logout')(Self);
require('../methods/account/acl')(Self);
require('../methods/account/change-password')(Self);
require('../methods/account/set-password')(Self);
require('../methods/account/recover-password')(Self);
require('../methods/account/validate-token')(Self);
require('../methods/account/privileges')(Self);
// Validations
Self.validatesFormatOf('email', {
message: 'Invalid email',
allowNull: true,
allowBlank: true,
with: /^[\w|.|-]+@[\w|-]+(\.[\w|-]+)*(,[\w|.|-]+@[\w|-]+(\.[\w|-]+)*)*$/
});
Self.validatesUniquenessOf('name', {
message: `A client with that Web User name already exists`
});
Self.observe('before save', async function(ctx) {
if (ctx.currentInstance && ctx.currentInstance.id && ctx.data && ctx.data.password)
ctx.data.password = md5(ctx.data.password);
});
Self.afterRemote('prototype.patchAttributes', async(ctx, instance) => {
if (!ctx.args || !ctx.args.data.email) return;
const models = Self.app.models;
const loopBackContext = LoopBackContext.getCurrentContext();
const httpCtx = {req: loopBackContext.active};
const httpRequest = httpCtx.req.http.req;
const headers = httpRequest.headers;
const origin = headers.origin;
const url = origin.split(':');
const userId = ctx.instance.id;
const user = await models.user.findById(userId);
class Mailer {
async send(verifyOptions, cb) {
const params = {
url: verifyOptions.verifyHref,
recipient: verifyOptions.to,
lang: ctx.req.getLocale()
};
const email = new Email('email-verify', params);
email.send();
cb(null, verifyOptions.to);
}
}
const options = {
type: 'email',
to: instance.email,
from: {},
redirect: `${origin}/#!/account/${instance.id}/basic-data?emailConfirmed`,
template: false,
mailer: new Mailer,
host: url[1].split('/')[2],
port: url[2],
protocol: url[0],
user: Self
};
await user.verify(options);
});
Self.remoteMethod('getCurrentUserData', {
description: 'Gets the current user data',
accepts: [
{
arg: 'ctx',
type: 'object',
http: {source: 'context'}
}
],
returns: {
type: 'object',
root: true
},
http: {
verb: 'GET',
path: '/getCurrentUserData'
}
});
Self.getCurrentUserData = async function(ctx) {
let userId = ctx.req.accessToken.userId;
return await Self.findById(userId, {
fields: ['id', 'name', 'nickname']
});
};
/**
* Checks if user has a role.
*
* @param {Integer} userId The user id
* @param {String} name The role name
* @param {object} options Options
* @return {Boolean} %true if user has the role, %false otherwise
*/
Self.hasRole = async function(userId, name, options) {
let roles = await Self.getRoles(userId, options);
return roles.some(role => role == name);
};
/**
* Get all user roles.
*
* @param {Integer} userId The user id
* @param {object} options Options
* @return {object} User role list
*/
Self.getRoles = async(userId, options) => {
let result = await Self.rawSql(
`SELECT r.name
FROM account.user u
JOIN account.roleRole rr ON rr.role = u.role
JOIN account.role r ON r.id = rr.inheritsFrom
WHERE u.id = ?`, [userId], options);
let roles = [];
for (const role of result)
roles.push(role.name);
return roles;
};
};

View File

@ -54,8 +54,8 @@ module.exports = Self => {
const writeRole = dmsType.writeRole() && dmsType.writeRole().name; const writeRole = dmsType.writeRole() && dmsType.writeRole().name;
const requiredRole = readRole || writeRole; const requiredRole = readRole || writeRole;
const hasRequiredRole = await models.Account.hasRole(myUserId, requiredRole, options); const hasRequiredRole = await models.VnUser.hasRole(myUserId, requiredRole, options);
const isRoot = await models.Account.hasRole(myUserId, 'root', options); const isRoot = await models.VnUser.hasRole(myUserId, 'root', options);
if (isRoot || hasRequiredRole) if (isRoot || hasRequiredRole)
return true; return true;

View File

@ -20,7 +20,7 @@
"relations": { "relations": {
"user": { "user": {
"type": "belongsTo", "type": "belongsTo",
"model": "Account", "model": "VnUser",
"foreignKey": "userFk" "foreignKey": "userFk"
} }
}, },

View File

@ -53,8 +53,8 @@ module.exports = Self => {
const writeRole = collection.writeRole() && collection.writeRole().name; const writeRole = collection.writeRole() && collection.writeRole().name;
const requiredRole = readRole || writeRole; const requiredRole = readRole || writeRole;
const hasRequiredRole = await models.Account.hasRole(myUserId, requiredRole, options); const hasRequiredRole = await models.VnUser.hasRole(myUserId, requiredRole, options);
const isRoot = await models.Account.hasRole(myUserId, 'root', options); const isRoot = await models.VnUser.hasRole(myUserId, 'root', options);
if (isRoot || hasRequiredRole) if (isRoot || hasRequiredRole)
return true; return true;

View File

@ -1,161 +1,112 @@
const fs = require('fs-extra'); const fs = require('fs-extra');
const sharp = require('sharp');
const path = require('path'); const path = require('path');
const readChunk = require('read-chunk'); const gm = require('gm');
const imageType = require('image-type');
const bmp = require('bmp-js');
module.exports = Self => { module.exports = Self => {
require('../methods/image/download')(Self); require('../methods/image/download')(Self);
require('../methods/image/upload')(Self); require('../methods/image/upload')(Self);
require('../methods/image/scrub')(Self);
// Function extracted from jimp package (utils) Self.resize = async function({collectionName, srcFile, fileName, entityId}) {
function scan(image, x, y, w, h, f) {
// round input
x = Math.round(x);
y = Math.round(y);
w = Math.round(w);
h = Math.round(h);
for (let _y = y; _y < y + h; _y++) {
for (let _x = x; _x < x + w; _x++) {
const idx = (image.bitmap.width * _y + _x) << 2;
f.call(image, _x, _y, idx);
}
}
return image;
}
// Function extracted from jimp package (type-bmp)
function fromAGBR(bitmap) {
return scan({bitmap}, 0, 0, bitmap.width, bitmap.height, function(
x,
y,
index
) {
const alpha = this.bitmap.data[index + 0];
const blue = this.bitmap.data[index + 1];
const green = this.bitmap.data[index + 2];
const red = this.bitmap.data[index + 3];
this.bitmap.data[index + 0] = red;
this.bitmap.data[index + 1] = green;
this.bitmap.data[index + 2] = blue;
this.bitmap.data[index + 3] = bitmap.is_with_alpha ? alpha : 0xff;
}).bitmap;
}
Self.registerImage = async(collectionName, srcFilePath, fileName, entityId) => {
const models = Self.app.models; const models = Self.app.models;
const tx = await Self.beginTransaction({});
const myOptions = {transaction: tx};
try { const collection = await models.ImageCollection.findOne(
const collection = await models.ImageCollection.findOne({ {
fields: [ fields: [
'id', 'id',
'name',
'maxWidth', 'maxWidth',
'maxHeight', 'maxHeight',
'model', 'model',
'property' 'property',
], ],
where: {name: collectionName}, where: {name: collectionName},
include: { include: {
relation: 'sizes', relation: 'sizes',
scope: { scope: {
fields: ['width', 'height', 'crop'] fields: ['width', 'height', 'crop'],
}
}
}, myOptions);
const data = {
name: fileName,
collectionFk: collectionName
};
const newImage = await Self.upsertWithWhere(data, {
name: fileName,
collectionFk: collectionName,
updated: Date.vnNow()
}, myOptions);
// Resizes and saves the image
const container = await models.ImageContainer.container(collectionName);
const rootPath = container.client.root;
const collectionDir = path.join(rootPath, collectionName);
const dstDir = path.join(collectionDir, 'full');
const dstFile = path.join(dstDir, fileName);
const buffer = readChunk.sync(srcFilePath, 0, 12);
const type = imageType(buffer);
let sharpOptions;
let imgSrc = srcFilePath;
if (type.mime == 'image/bmp') {
const bmpBuffer = fs.readFileSync(srcFilePath);
const bmpData = fromAGBR(bmp.decode(bmpBuffer));
imgSrc = bmpData.data;
sharpOptions = {
raw: {
width: bmpData.width,
height: bmpData.height,
channels: 4
}, },
failOn: 'none' },
};
} }
);
const resizeOpts = { // Insert image row
withoutEnlargement: true, const imageName = path.parse(fileName).name;
fit: 'inside' await models.Image.upsertWithWhere(
}; {
name: imageName,
await fs.mkdir(dstDir, {recursive: true}); collectionFk: collectionName
await sharp(imgSrc, sharpOptions) },
.resize(collection.maxWidth, collection.maxHeight, resizeOpts) {
.png() name: imageName,
.toFile(dstFile); collectionFk: collectionName,
updated: Date.vnNow() / 1000,
const sizes = collection.sizes();
for (let size of sizes) {
const dstDir = path.join(collectionDir, `${size.width}x${size.height}`);
const dstFile = path.join(dstDir, fileName);
const resizeOpts = {
withoutEnlargement: true,
fit: size.crop ? 'cover' : 'inside'
};
await fs.mkdir(dstDir, {recursive: true});
await sharp(imgSrc, sharpOptions)
.resize(size.width, size.height, resizeOpts)
.png()
.toFile(dstFile);
} }
);
const model = models[collection.model]; // Update entity image file name
const model = models[collection.model];
if (!model) throw new Error('No matching model found');
if (!model) const entity = await model.findById(entityId);
throw new Error('Matching model not found'); if (entity) {
await entity.updateAttribute(
collection.property,
imageName
);
}
const item = await model.findById(entityId, null, myOptions); // Resize
if (item) { const container = await models.ImageContainer.container(
await item.updateAttribute( collectionName
collection.property, );
fileName, const rootPath = container.client.root;
myOptions const collectionDir = path.join(rootPath, collectionName);
);
}
if (fs.existsSync(srcFilePath)) // To max size
await fs.unlink(srcFilePath); const {maxWidth, maxHeight} = collection;
const fullSizePath = path.join(collectionDir, 'full');
const toFullSizePath = `${fullSizePath}/${fileName}`;
await tx.commit(); await fs.mkdir(fullSizePath, {recursive: true});
await new Promise((resolve, reject) => {
gm(srcFile)
.resize(maxWidth, maxHeight, '>')
.setFormat('png')
.quality(100)
.write(toFullSizePath, function(err) {
if (err) reject(err);
if (!err) resolve();
});
});
return newImage; // To collection sizes
} catch (e) { for (const size of collection.sizes()) {
await tx.rollback(); const {width, height} = size;
throw e;
const sizePath = path.join(collectionDir, `${width}x${height}`);
const toSizePath = `${sizePath}/${fileName}`;
await fs.mkdir(sizePath, {recursive: true});
await new Promise((resolve, reject) => {
const gmInstance = gm(srcFile);
if (size.crop) {
gmInstance
.resize(width, height, '^')
.gravity('Center')
.crop(width, height);
}
if (!size.crop) gmInstance.resize(width, height, '>');
gmInstance
.setFormat('png')
.quality(100)
.write(toSizePath, function(err) {
if (err) reject(err);
if (!err) resolve();
});
});
} }
}; };
}; };

View File

@ -31,7 +31,7 @@
}, },
"author": { "author": {
"type": "belongsTo", "type": "belongsTo",
"model": "Account", "model": "VnUser",
"foreignKey": "authorFk" "foreignKey": "authorFk"
} }
} }

View File

@ -29,7 +29,7 @@
}, },
"user": { "user": {
"type": "belongsTo", "type": "belongsTo",
"model": "Account", "model": "VnUser",
"foreignKey": "userFk" "foreignKey": "userFk"
} }
} }

View File

@ -1,8 +1,8 @@
const app = require('vn-loopback/server/server'); const {models} = require('vn-loopback/server/server');
describe('loopback model Company', () => { describe('loopback model Company', () => {
it('should check that the company FTH doesnt exists', async() => { it('should check that the company FTH doesnt exists', async() => {
let result = await app.models.Company.findOne({where: {code: 'FTH'}}); let result = await models.Company.findOne({where: {code: 'FTH'}});
expect(result).toBeFalsy(); expect(result).toBeFalsy();
}); });

View File

@ -1,6 +1,6 @@
const app = require('vn-loopback/server/server'); const {models} = require('vn-loopback/server/server');
describe('Dms', () => { describe('Dms', () => {
const Dms = app.models.Dms; const Dms = models.Dms;
describe('getFile()', () => { describe('getFile()', () => {
it('should return a response with text content-type', async() => { it('should return a response with text content-type', async() => {
@ -23,7 +23,7 @@ describe('Dms', () => {
it('should return an error for a record does not exists', async() => { it('should return an error for a record does not exists', async() => {
let error = {}; let error = {};
try { try {
await app.models.Dms.getFile('NotExistentId'); await models.Dms.getFile('NotExistentId');
} catch (e) { } catch (e) {
error = e; error = e;
} }

View File

@ -1,7 +1,7 @@
const models = require('vn-loopback/server/server').models; const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context'); const LoopBackContext = require('loopback-context');
describe('account recoverPassword()', () => { describe('VnUser recoverPassword()', () => {
const userId = 1107; const userId = 1107;
const activeCtx = { const activeCtx = {
@ -21,9 +21,9 @@ describe('account recoverPassword()', () => {
it('should send email with token', async() => { it('should send email with token', async() => {
const userId = 1107; const userId = 1107;
const user = await models.Account.findById(userId); const user = await models.VnUser.findById(userId);
await models.Account.recoverPassword(user.email); await models.VnUser.recoverPassword(user.email);
const result = await models.AccessToken.findOne({where: {userId: userId}}); const result = await models.AccessToken.findOne({where: {userId: userId}});

View File

@ -1,14 +1,14 @@
const models = require('vn-loopback/server/server').models; const models = require('vn-loopback/server/server').models;
describe('loopback model Account', () => { describe('loopback model VnUser', () => {
it('should return true if the user has the given role', async() => { it('should return true if the user has the given role', async() => {
let result = await models.Account.hasRole(1, 'employee'); let result = await models.VnUser.hasRole(1, 'employee');
expect(result).toBeTruthy(); expect(result).toBeTruthy();
}); });
it('should return false if the user doesnt have the given role', async() => { it('should return false if the user doesnt have the given role', async() => {
let result = await models.Account.hasRole(1, 'administrator'); let result = await models.VnUser.hasRole(1, 'administrator');
expect(result).toBeFalsy(); expect(result).toBeFalsy();
}); });

View File

@ -26,7 +26,7 @@
"relations": { "relations": {
"user": { "user": {
"type": "belongsTo", "type": "belongsTo",
"model": "Account", "model": "VnUser",
"foreignKey": "userFk" "foreignKey": "userFk"
} }
} }

View File

@ -39,9 +39,9 @@
"model": "Company", "model": "Company",
"foreignKey": "companyFk" "foreignKey": "companyFk"
}, },
"account": { "VnUser": {
"type": "belongsTo", "type": "belongsTo",
"model": "Account", "model": "VnUser",
"foreignKey": "userFk" "foreignKey": "userFk"
} }
} }

View File

@ -1,27 +0,0 @@
const LoopBackContext = require('loopback-context');
const {Email} = require('vn-print');
module.exports = function(Self) {
Self.on('resetPasswordRequest', async function(info) {
const loopBackContext = LoopBackContext.getCurrentContext();
const httpCtx = {req: loopBackContext.active};
const httpRequest = httpCtx.req.http.req;
const headers = httpRequest.headers;
const origin = headers.origin;
const user = await Self.app.models.Account.findById(info.user.id);
const params = {
recipient: info.email,
lang: user.lang,
url: `${origin}/#!/reset-password?access_token=${info.accessToken.id}`
};
const options = Object.assign({}, info.options);
for (const param in options)
params[param] = options[param];
const email = new Email(options.emailTemplate, params);
return email.send();
});
};

View File

@ -1,19 +0,0 @@
{
"name": "user",
"base": "User",
"options": {
"mysql": {
"table": "salix.User"
}
},
"properties": {
"id": {
"id": true,
"type": "number",
"forceId": false
},
"username":{
"type": "string"
}
}
}

110
back/models/vn-user.js Normal file
View File

@ -0,0 +1,110 @@
const vnModel = require('vn-loopback/common/models/vn-model');
const LoopBackContext = require('loopback-context');
const {Email} = require('vn-print');
module.exports = function(Self) {
vnModel(Self);
require('../methods/vn-user/signIn')(Self);
require('../methods/vn-user/acl')(Self);
require('../methods/vn-user/recover-password')(Self);
require('../methods/vn-user/validate-token')(Self);
require('../methods/vn-user/privileges')(Self);
// Validations
Self.validatesFormatOf('email', {
message: 'Invalid email',
allowNull: true,
allowBlank: true,
with: /^[\w|.|-]+@[\w|-]+(\.[\w|-]+)*(,[\w|.|-]+@[\w|-]+(\.[\w|-]+)*)*$/
});
Self.validatesUniquenessOf('name', {
message: `A client with that Web User name already exists`
});
Self.remoteMethod('getCurrentUserData', {
description: 'Gets the current user data',
accepts: [
{
arg: 'ctx',
type: 'Object',
http: {source: 'context'}
}
],
returns: {
type: 'Object',
root: true
},
http: {
verb: 'GET',
path: '/getCurrentUserData'
}
});
Self.getCurrentUserData = async function(ctx) {
let userId = ctx.req.accessToken.userId;
return await Self.findById(userId, {
fields: ['id', 'name', 'nickname']
});
};
/**
* Checks if user has a role.
*
* @param {Integer} userId The user id
* @param {String} name The role name
* @param {Object} options Options
* @return {Boolean} %true if user has the role, %false otherwise
*/
Self.hasRole = async function(userId, name, options) {
const roles = await Self.getRoles(userId, options);
return roles.some(role => role == name);
};
/**
* Get all user roles.
*
* @param {Integer} userId The user id
* @param {Object} options Options
* @return {Object} User role list
*/
Self.getRoles = async(userId, options) => {
const result = await Self.rawSql(
`SELECT r.name
FROM account.user u
JOIN account.roleRole rr ON rr.role = u.role
JOIN account.role r ON r.id = rr.inheritsFrom
WHERE u.id = ?`, [userId], options);
const roles = [];
for (const role of result)
roles.push(role.name);
return roles;
};
Self.on('resetPasswordRequest', async function(info) {
const loopBackContext = LoopBackContext.getCurrentContext();
const httpCtx = {req: loopBackContext.active};
const httpRequest = httpCtx.req.http.req;
const headers = httpRequest.headers;
const origin = headers.origin;
const user = await Self.app.models.VnUser.findById(info.user.id);
const params = {
recipient: info.email,
lang: user.lang,
url: `${origin}/#!/reset-password?access_token=${info.accessToken.id}`
};
const options = Object.assign({}, info.options);
for (const param in options)
params[param] = options[param];
const email = new Email(options.emailTemplate, params);
return email.send();
});
};

View File

@ -1,11 +1,13 @@
{ {
"name": "Account", "name": "VnUser",
"base": "VnModel", "base": "User",
"validateUpsert": true,
"options": { "options": {
"mysql": { "mysql": {
"table": "account.user" "table": "account.user"
} }
}, },
"resetPasswordTokenTTL": "604800",
"properties": { "properties": {
"id": { "id": {
"type": "number", "type": "number",
@ -15,6 +17,19 @@
"type": "string", "type": "string",
"required": true "required": true
}, },
"username": {
"type": "string",
"mysql": {
"columnName": "name"
}
},
"password": {
"type": "string",
"required": true,
"mysql": {
"columnName": "bcryptPassword"
}
},
"roleFk": { "roleFk": {
"type": "number", "type": "number",
"mysql": { "mysql": {
@ -27,10 +42,6 @@
"lang": { "lang": {
"type": "string" "type": "string"
}, },
"password": {
"type": "string",
"required": true
},
"bcryptPassword": { "bcryptPassword": {
"type": "string" "type": "string"
}, },
@ -40,9 +51,6 @@
"email": { "email": {
"type": "string" "type": "string"
}, },
"emailVerified": {
"type": "boolean"
},
"created": { "created": {
"type": "date" "type": "date"
}, },
@ -86,7 +94,7 @@
}, },
"acls": [ "acls": [
{ {
"property": "login", "property": "signIn",
"accessType": "EXECUTE", "accessType": "EXECUTE",
"principalType": "ROLE", "principalType": "ROLE",
"principalId": "$everyone", "principalId": "$everyone",
@ -100,13 +108,6 @@
"permission": "ALLOW" "permission": "ALLOW"
}, },
{ {
"property": "logout",
"accessType": "EXECUTE",
"principalType": "ROLE",
"principalId": "$authenticated",
"permission": "ALLOW"
},
{
"property": "validateToken", "property": "validateToken",
"accessType": "EXECUTE", "accessType": "EXECUTE",
"principalType": "ROLE", "principalType": "ROLE",

View File

@ -53,7 +53,7 @@ async function test() {
const JunitReporter = require('jasmine-reporters'); const JunitReporter = require('jasmine-reporters');
jasmine.addReporter(new JunitReporter.JUnitXmlReporter()); jasmine.addReporter(new JunitReporter.JUnitXmlReporter());
jasmine.jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000; jasmine.jasmine.DEFAULT_TIMEOUT_INTERVAL = 90000;
jasmine.exitOnCompletion = true; jasmine.exitOnCompletion = true;
} }

View File

@ -8,7 +8,7 @@ CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`invoiceOut_new`(
BEGIN BEGIN
/** /**
* Creación de facturas emitidas. * Creación de facturas emitidas.
* requiere previamente tabla ticketToInvoice(id). * requiere previamente tabla tmp.ticketToInvoice(id).
* *
* @param vSerial serie a la cual se hace la factura * @param vSerial serie a la cual se hace la factura
* @param vInvoiceDate fecha de la factura * @param vInvoiceDate fecha de la factura
@ -36,13 +36,13 @@ BEGIN
SELECT t.clientFk, t.companyFk SELECT t.clientFk, t.companyFk
INTO vClient, vCompany INTO vClient, vCompany
FROM ticketToInvoice tt FROM tmp.ticketToInvoice tt
JOIN ticket t ON t.id = tt.id JOIN ticket t ON t.id = tt.id
LIMIT 1; LIMIT 1;
-- Eliminem de ticketToInvoice els tickets que no han de ser facturats -- Eliminem de tmp.ticketToInvoice els tickets que no han de ser facturats
DELETE ti.* DELETE ti.*
FROM ticketToInvoice ti FROM tmp.ticketToInvoice ti
JOIN ticket t ON t.id = ti.id JOIN ticket t ON t.id = ti.id
JOIN sale s ON s.ticketFk = t.id JOIN sale s ON s.ticketFk = t.id
JOIN item i ON i.id = s.itemFk JOIN item i ON i.id = s.itemFk
@ -57,7 +57,7 @@ BEGIN
SELECT SUM(s.quantity * s.price * (100 - s.discount)/100), ts.id SELECT SUM(s.quantity * s.price * (100 - s.discount)/100), ts.id
INTO vIsAnySaleToInvoice, vIsAnyServiceToInvoice INTO vIsAnySaleToInvoice, vIsAnyServiceToInvoice
FROM ticketToInvoice t FROM tmp.ticketToInvoice t
LEFT JOIN sale s ON s.ticketFk = t.id LEFT JOIN sale s ON s.ticketFk = t.id
LEFT JOIN ticketService ts ON ts.ticketFk = t.id; LEFT JOIN ticketService ts ON ts.ticketFk = t.id;
@ -100,13 +100,13 @@ BEGIN
WHERE id = vNewInvoiceId; WHERE id = vNewInvoiceId;
UPDATE ticket t UPDATE ticket t
JOIN ticketToInvoice ti ON ti.id = t.id JOIN tmp.ticketToInvoice ti ON ti.id = t.id
SET t.refFk = vNewRef; SET t.refFk = vNewRef;
DROP TEMPORARY TABLE IF EXISTS tmp.updateInter; DROP TEMPORARY TABLE IF EXISTS tmp.updateInter;
CREATE TEMPORARY TABLE tmp.updateInter ENGINE = MEMORY CREATE TEMPORARY TABLE tmp.updateInter ENGINE = MEMORY
SELECT s.id,ti.id ticket_id,vWorker Id_Trabajador SELECT s.id,ti.id ticket_id,vWorker Id_Trabajador
FROM ticketToInvoice ti FROM tmp.ticketToInvoice ti
LEFT JOIN ticketState ts ON ti.id = ts.ticket LEFT JOIN ticketState ts ON ti.id = ts.ticket
JOIN state s JOIN state s
WHERE IFNULL(ts.alertLevel,0) < 3 and s.`code` = getAlert3State(ti.id); WHERE IFNULL(ts.alertLevel,0) < 3 and s.`code` = getAlert3State(ti.id);
@ -116,7 +116,7 @@ BEGIN
INSERT INTO ticketLog (action, userFk, originFk, description) INSERT INTO ticketLog (action, userFk, originFk, description)
SELECT 'UPDATE', account.myUser_getId(), ti.id, CONCAT('Crea factura ', vNewRef) SELECT 'UPDATE', account.myUser_getId(), ti.id, CONCAT('Crea factura ', vNewRef)
FROM ticketToInvoice ti; FROM tmp.ticketToInvoice ti;
CALL invoiceExpenceMake(vNewInvoiceId); CALL invoiceExpenceMake(vNewInvoiceId);
CALL invoiceTaxMake(vNewInvoiceId,vTaxArea); CALL invoiceTaxMake(vNewInvoiceId,vTaxArea);
@ -159,7 +159,7 @@ BEGIN
(KEY (ticketFk)) (KEY (ticketFk))
ENGINE = MEMORY ENGINE = MEMORY
SELECT id ticketFk SELECT id ticketFk
FROM ticketToInvoice; FROM tmp.ticketToInvoice;
CALL `ticket_getTax`('NATIONAL'); CALL `ticket_getTax`('NATIONAL');
@ -220,6 +220,6 @@ BEGIN
END IF; END IF;
DROP TEMPORARY TABLE `ticketToInvoice`; DROP TEMPORARY TABLE `tmp`.`ticketToInvoice`;
END$$ END$$
DELIMITER ; DELIMITER ;

View File

@ -0,0 +1,18 @@
INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
VALUES ('VnUser', '*', '*', 'ALLOW', 'ROLE', 'employee');
INSERT INTO `salix`.`ACL` (id, model, property, accessType, permission, principalType, principalId)
VALUES ('VnUser', 'acl', 'READ', 'ALLOW', 'ROLE', 'account');
INSERT INTO `salix`.`ACL` (id, model, property, accessType, permission, principalType, principalId)
VALUES ('VnUser', 'getCurrentUserData', 'READ', 'ALLOW', 'ROLE', 'account');
INSERT INTO `salix`.`ACL` (id, model, property, accessType, permission, principalType, principalId)
VALUES ('VnUser', 'changePassword', '*', 'ALLOW', 'ROLE', 'account');
UPDATE `hedera`.`imageCollection` t
SET t.model = 'VnUser'
WHERE t.id = 6;

View File

@ -0,0 +1,3 @@
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('Receipt', 'receiptEmail', '*', 'ALLOW', 'ROLE', 'salesAssistant');

View File

@ -10,14 +10,14 @@ CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`invoiceOut_new`(
BEGIN BEGIN
/** /**
* Creación de facturas emitidas. * Creación de facturas emitidas.
* requiere previamente tabla ticketToInvoice(id). * requiere previamente tabla tmp.ticketToInvoice(id).
* *
* @param vSerial serie a la cual se hace la factura * @param vSerial serie a la cual se hace la factura
* @param vInvoiceDate fecha de la factura * @param vInvoiceDate fecha de la factura
* @param vTaxArea tipo de iva en relacion a la empresa y al cliente * @param vTaxArea tipo de iva en relacion a la empresa y al cliente
* @param vNewInvoiceId id de la factura que se acaba de generar * @param vNewInvoiceId id de la factura que se acaba de generar
* @return vNewInvoiceId * @return vNewInvoiceId
*/ */
DECLARE vIsAnySaleToInvoice BOOL; DECLARE vIsAnySaleToInvoice BOOL;
DECLARE vIsAnyServiceToInvoice BOOL; DECLARE vIsAnyServiceToInvoice BOOL;
DECLARE vNewRef VARCHAR(255); DECLARE vNewRef VARCHAR(255);
@ -37,32 +37,32 @@ BEGIN
DECLARE vMaxShipped DATE; DECLARE vMaxShipped DATE;
SET vInvoiceDate = IFNULL(vInvoiceDate, util.CURDATE()); SET vInvoiceDate = IFNULL(vInvoiceDate, util.CURDATE());
SELECT t.clientFk, SELECT t.clientFk,
t.companyFk, t.companyFk,
MAX(DATE(t.shipped)), MAX(DATE(t.shipped)),
DATE(vInvoiceDate) >= invoiceOut_getMaxIssued( DATE(vInvoiceDate) >= invoiceOut_getMaxIssued(
vSerial, vSerial,
t.companyFk, t.companyFk,
YEAR(vInvoiceDate)) YEAR(vInvoiceDate))
INTO vClientFk, INTO vClientFk,
vCompanyFk, vCompanyFk,
vMaxShipped, vMaxShipped,
vIsCorrectInvoiceDate vIsCorrectInvoiceDate
FROM ticketToInvoice tt FROM tmp.ticketToInvoice tt
JOIN ticket t ON t.id = tt.id; JOIN ticket t ON t.id = tt.id;
IF(vMaxShipped > vInvoiceDate) THEN IF(vMaxShipped > vInvoiceDate) THEN
CALL util.throw("Invoice date can't be less than max date"); CALL util.throw("Invoice date can't be less than max date");
END IF; END IF;
IF NOT vIsCorrectInvoiceDate THEN IF NOT vIsCorrectInvoiceDate THEN
CALL util.throw('Exists an invoice with a previous date'); CALL util.throw('Exists an invoice with a previous date');
END IF; END IF;
-- Eliminem de ticketToInvoice els tickets que no han de ser facturats -- Eliminem de tmp.ticketToInvoice els tickets que no han de ser facturats
DELETE ti.* DELETE ti.*
FROM ticketToInvoice ti FROM tmp.ticketToInvoice ti
JOIN ticket t ON t.id = ti.id JOIN ticket t ON t.id = ti.id
JOIN sale s ON s.ticketFk = t.id JOIN sale s ON s.ticketFk = t.id
JOIN item i ON i.id = s.itemFk JOIN item i ON i.id = s.itemFk
@ -77,11 +77,11 @@ BEGIN
SELECT SUM(s.quantity * s.price * (100 - s.discount)/100) <> 0 SELECT SUM(s.quantity * s.price * (100 - s.discount)/100) <> 0
INTO vIsAnySaleToInvoice INTO vIsAnySaleToInvoice
FROM ticketToInvoice t FROM tmp.ticketToInvoice t
JOIN sale s ON s.ticketFk = t.id; JOIN sale s ON s.ticketFk = t.id;
SELECT COUNT(*) > 0 INTO vIsAnyServiceToInvoice SELECT COUNT(*) > 0 INTO vIsAnyServiceToInvoice
FROM ticketToInvoice t FROM tmp.ticketToInvoice t
JOIN ticketService ts ON ts.ticketFk = t.id; JOIN ticketService ts ON ts.ticketFk = t.id;
IF (vIsAnySaleToInvoice OR vIsAnyServiceToInvoice) IF (vIsAnySaleToInvoice OR vIsAnyServiceToInvoice)
@ -121,13 +121,13 @@ BEGIN
WHERE id = vNewInvoiceId; WHERE id = vNewInvoiceId;
UPDATE ticket t UPDATE ticket t
JOIN ticketToInvoice ti ON ti.id = t.id JOIN tmp.ticketToInvoice ti ON ti.id = t.id
SET t.refFk = vNewRef; SET t.refFk = vNewRef;
DROP TEMPORARY TABLE IF EXISTS tmp.updateInter; DROP TEMPORARY TABLE IF EXISTS tmp.updateInter;
CREATE TEMPORARY TABLE tmp.updateInter ENGINE = MEMORY CREATE TEMPORARY TABLE tmp.updateInter ENGINE = MEMORY
SELECT s.id,ti.id ticket_id,vWorker Id_Trabajador SELECT s.id,ti.id ticket_id,vWorker Id_Trabajador
FROM ticketToInvoice ti FROM tmp.ticketToInvoice ti
LEFT JOIN ticketState ts ON ti.id = ts.ticket LEFT JOIN ticketState ts ON ti.id = ts.ticket
JOIN state s JOIN state s
WHERE IFNULL(ts.alertLevel,0) < 3 and s.`code` = getAlert3State(ti.id); WHERE IFNULL(ts.alertLevel,0) < 3 and s.`code` = getAlert3State(ti.id);
@ -137,7 +137,7 @@ BEGIN
INSERT INTO ticketLog (action, userFk, originFk, description) INSERT INTO ticketLog (action, userFk, originFk, description)
SELECT 'UPDATE', account.myUser_getId(), ti.id, CONCAT('Crea factura ', vNewRef) SELECT 'UPDATE', account.myUser_getId(), ti.id, CONCAT('Crea factura ', vNewRef)
FROM ticketToInvoice ti; FROM tmp.ticketToInvoice ti;
CALL invoiceExpenceMake(vNewInvoiceId); CALL invoiceExpenceMake(vNewInvoiceId);
CALL invoiceTaxMake(vNewInvoiceId,vTaxArea); CALL invoiceTaxMake(vNewInvoiceId,vTaxArea);
@ -157,12 +157,12 @@ BEGIN
WHERE io.id = vNewInvoiceId; WHERE io.id = vNewInvoiceId;
DROP TEMPORARY TABLE tmp.updateInter; DROP TEMPORARY TABLE tmp.updateInter;
SELECT COUNT(*), id SELECT COUNT(*), id
INTO vIsInterCompany, vInterCompanyFk INTO vIsInterCompany, vInterCompanyFk
FROM company FROM company
WHERE clientFk = vClientFk; WHERE clientFk = vClientFk;
IF (vIsInterCompany) THEN IF (vIsInterCompany) THEN
INSERT INTO invoiceIn(supplierFk, supplierRef, issued, companyFk) INSERT INTO invoiceIn(supplierFk, supplierRef, issued, companyFk)
@ -175,7 +175,7 @@ BEGIN
(KEY (ticketFk)) (KEY (ticketFk))
ENGINE = MEMORY ENGINE = MEMORY
SELECT id ticketFk SELECT id ticketFk
FROM ticketToInvoice; FROM tmp.ticketToInvoice;
CALL `ticket_getTax`('NATIONAL'); CALL `ticket_getTax`('NATIONAL');
@ -201,7 +201,7 @@ BEGIN
) sub; ) sub;
INSERT INTO invoiceInTax(invoiceInFk, taxableBase, expenceFk, taxTypeSageFk, transactionTypeSageFk) INSERT INTO invoiceInTax(invoiceInFk, taxableBase, expenceFk, taxTypeSageFk, transactionTypeSageFk)
SELECT vNewInvoiceInFk, SELECT vNewInvoiceInFk,
SUM(tt.taxableBase) - IF(tt.code = @vTaxCodeGeneral, SUM(tt.taxableBase) - IF(tt.code = @vTaxCodeGeneral,
@vTaxableBaseServices, 0) taxableBase, @vTaxableBaseServices, 0) taxableBase,
i.expenceFk, i.expenceFk,
@ -215,13 +215,13 @@ BEGIN
ORDER BY tt.priority; ORDER BY tt.priority;
CALL invoiceInDueDay_calculate(vNewInvoiceInFk); CALL invoiceInDueDay_calculate(vNewInvoiceInFk);
SELECT COUNT(*) INTO vIsCEESerial SELECT COUNT(*) INTO vIsCEESerial
FROM invoiceOutSerial FROM invoiceOutSerial
WHERE code = vSerial; WHERE code = vSerial;
IF vIsCEESerial THEN IF vIsCEESerial THEN
INSERT INTO invoiceInIntrastat ( INSERT INTO invoiceInIntrastat (
invoiceInFk, invoiceInFk,
intrastatFk, intrastatFk,
@ -253,6 +253,6 @@ BEGIN
DROP TEMPORARY TABLE tmp.ticketServiceTax; DROP TEMPORARY TABLE tmp.ticketServiceTax;
END IF; END IF;
END IF; END IF;
DROP TEMPORARY TABLE `ticketToInvoice`; DROP TEMPORARY TABLE tmp.`ticketToInvoice`;
END$$ END$$
DELIMITER ; DELIMITER ;

View File

@ -0,0 +1,16 @@
ALTER TABLE `vn`.`chat` ADD statusNew enum('pending','sent','error','sending') DEFAULT 'pending' NOT NULL;
UPDATE `vn`.`chat`
SET statusNew = 'pending'
WHERE status = 0;
UPDATE `vn`.`chat`
SET statusNew = 'sent'
WHERE status = 1;
UPDATE `vn`.`chat`
SET statusNew = 'error'
WHERE status = 2;
ALTER TABLE `vn`.`chat` CHANGE status status__ tinyint(1) DEFAULT NULL NULL;
ALTER TABLE `vn`.`chat` CHANGE statusNew status enum('pending','sent','error','sending') CHARACTER SET utf8mb3 COLLATE utf8mb3_unicode_ci DEFAULT 'pending' NOT NULL;

View File

@ -0,0 +1,4 @@
ALTER TABLE `vn`.`invoiceInConfig` ADD daysAgo INT UNSIGNED DEFAULT 45 COMMENT 'Días en el pasado para mostrar facturas en invoiceIn series en salix';
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('InvoiceIn', 'getSerial', 'READ', 'ALLOW', 'ROLE', 'administrative');

View File

@ -0,0 +1,14 @@
ALTER TABLE `vn`.`itemType` ADD isFragile tinyint(1) NULL;
ALTER TABLE `vn`.`itemType` MODIFY COLUMN isFragile tinyint(1) DEFAULT 0 NOT NULL;
UPDATE `vn`.`itemType`
SET isFragile = 1
WHERE code IN ('ZKA', 'ZKE');
UPDATE `vn`.`itemType`
SET isFragile = 1
WHERE id IN (SELECT it.id
FROM `vn`.`itemCategory` ic
JOIN `vn`.`itemType` it ON it.categoryFk = ic.id
WHERE ic.code = 'plant');

View File

@ -0,0 +1,2 @@
INSERT INTO `salix`.`ACL` ( model, property, accessType, permission, principalType, principalId)
VALUES('Mail', '*', '*', 'ALLOW', 'ROLE', 'employee');

View File

@ -0,0 +1,3 @@
DROP TRIGGER `vn`.`supplierAccount_afterInsert`;
DROP TRIGGER `vn`.`supplierAccount_afterUpdate`;
DROP TRIGGER `vn`.`supplierAccount_afterDelete`;

View File

@ -0,0 +1,47 @@
DROP PROCEDURE IF EXISTS `vn`.`ticket_getWarnings`;
DELIMITER $$
$$
CREATE PROCEDURE `vn`.`ticket_getWarnings`()
BEGIN
/**
* Calcula las adventencias para un conjunto de tickets.
* Agrupados por ticket
*
* @table tmp.sale_getWarnings(ticketFk) Identificadores de los tickets a calcular
* @return tmp.ticket_warnings
*/
DROP TEMPORARY TABLE IF EXISTS tmp.sale_warnings;
CREATE TEMPORARY TABLE tmp.sale_warnings (
ticketFk INT(11),
saleFk INT(11),
isFragile INTEGER(1) DEFAULT 0,
PRIMARY KEY (ticketFk, saleFk)
) ENGINE = MEMORY;
-- Frágil
INSERT INTO tmp.sale_warnings(ticketFk, saleFk, isFragile)
SELECT tt.ticketFk, s.id, TRUE
FROM tmp.sale_getWarnings tt
LEFT JOIN sale s ON s.ticketFk = tt.ticketFk
LEFT JOIN item i ON i.id = s.itemFk
LEFT JOIN itemType it ON it.id = i.typeFk
LEFT JOIN agencyMode am ON am.id = tt.agencyModeFk
LEFT JOIN deliveryMethod dm ON dm.id = am.deliveryMethodFk
WHERE dm.code IN ('AGENCY')
AND it.isFragile;
DROP TEMPORARY TABLE IF EXISTS tmp.ticket_warnings;
CREATE TEMPORARY TABLE tmp.ticket_warnings
(PRIMARY KEY (ticketFk))
ENGINE = MEMORY
SELECT
sw.ticketFk,
MAX(sw.isFragile) AS isFragile
FROM tmp.sale_warnings sw
GROUP BY sw.ticketFk;
DROP TEMPORARY TABLE
tmp.sale_warnings;
END$$
DELIMITER ;

View File

@ -0,0 +1,72 @@
CREATE TABLE `vn`.`wagonType` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(30) NOT NULL UNIQUE,
`divisible` tinyint(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb3;
CREATE TABLE `vn`.`wagonTypeColor` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(30) NOT NULL UNIQUE,
`rgb` varchar(30) NOT NULL UNIQUE,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb3;
CREATE TABLE `vn`.`wagonTypeTray` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`typeFk` int(11) unsigned,
`height` int(11) unsigned NOT NULL,
`colorFk` int(11) unsigned,
PRIMARY KEY (`id`),
UNIQUE KEY (`typeFk`,`height`),
CONSTRAINT `wagonTypeTray_type` FOREIGN KEY (`typeFk`) REFERENCES `wagonType` (`id`) ON UPDATE CASCADE,
CONSTRAINT `wagonTypeTray_color` FOREIGN KEY (`colorFk`) REFERENCES `wagonTypeColor` (`id`) ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb3;
CREATE TABLE `vn`.`wagonConfig` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`width` int(11) unsigned DEFAULT 1350,
`height` int(11) unsigned DEFAULT 1900,
`maxWagonHeight` int(11) unsigned DEFAULT 200,
`minHeightBetweenTrays` int(11) unsigned DEFAULT 50,
`maxTrays` int(11) unsigned DEFAULT 6,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb3;
CREATE TABLE `vn`.`collectionWagon` (
`collectionFk` int(11) NOT NULL,
`wagonFk` int(11) NOT NULL,
`position` int(11) unsigned,
PRIMARY KEY (`collectionFk`,`position`),
UNIQUE KEY `collectionWagon_unique` (`collectionFk`,`wagonFk`),
CONSTRAINT `collectionWagon_collection` FOREIGN KEY (`collectionFk`) REFERENCES `collection` (`id`) ON UPDATE CASCADE,
CONSTRAINT `collectionWagon_wagon` FOREIGN KEY (`wagonFk`) REFERENCES `wagon` (`id`) ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
CREATE TABLE `vn`.`collectionWagonTicket` (
`ticketFk` int(11) NOT NULL,
`wagonFk` int(11) NOT NULL,
`trayFk` int(11) unsigned NOT NULL,
`side` SET('L', 'R') NULL,
PRIMARY KEY (`ticketFk`),
CONSTRAINT `collectionWagonTicket_ticket` FOREIGN KEY (`ticketFk`) REFERENCES `ticket` (`id`) ON UPDATE CASCADE,
CONSTRAINT `collectionWagonTicket_wagon` FOREIGN KEY (`wagonFk`) REFERENCES `wagon` (`id`) ON UPDATE CASCADE,
CONSTRAINT `collectionWagonTicket_tray` FOREIGN KEY (`trayFk`) REFERENCES `wagonTypeTray` (`id`) ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
ALTER TABLE `vn`.`wagon` ADD `typeFk` int(11) unsigned NOT NULL;
ALTER TABLE `vn`.`wagon` ADD `label` int(11) unsigned NOT NULL;
ALTER TABLE `vn`.`wagon` ADD CONSTRAINT `wagon_type` FOREIGN KEY (`typeFk`) REFERENCES `wagonType` (`id`) ON UPDATE CASCADE;
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('WagonType', '*', '*', 'ALLOW', 'ROLE', 'productionAssi'),
('WagonTypeColor', '*', '*', 'ALLOW', 'ROLE', 'productionAssi'),
('WagonTypeTray', '*', '*', 'ALLOW', 'ROLE', 'productionAssi'),
('WagonConfig', '*', '*', 'ALLOW', 'ROLE', 'productionAssi'),
('CollectionWagon', '*', '*', 'ALLOW', 'ROLE', 'productionAssi'),
('CollectionWagonTicket', '*', '*', 'ALLOW', 'ROLE', 'productionAssi'),
('Wagon', '*', '*', 'ALLOW', 'ROLE', 'productionAssi'),
('WagonType', 'createWagonType', '*', 'ALLOW', 'ROLE', 'productionAssi'),
('WagonType', 'deleteWagonType', '*', 'ALLOW', 'ROLE', 'productionAssi'),
('WagonType', 'editWagonType', '*', 'ALLOW', 'ROLE', 'productionAssi');

View File

@ -0,0 +1,74 @@
DROP TABLE `vn`.`dmsRecover`;
ALTER TABLE `vn`.`delivery` DROP FOREIGN KEY delivery_FK;
ALTER TABLE `vn`.`delivery` DROP COLUMN addressFk;
ALTER TABLE `vn`.`delivery` ADD ticketFk INT NOT NULL;
ALTER TABLE `vn`.`delivery` ADD CONSTRAINT delivery_ticketFk_FK FOREIGN KEY (`ticketFk`) REFERENCES `vn`.`ticket`(`id`);
DELETE FROM `salix`.`ACL` WHERE `property` = 'saveSign';
INSERT INTO `salix`.`ACL` (`model`,`property`,`accessType`,`permission`,`principalId`)
VALUES
('Ticket','saveSign','WRITE','ALLOW','employee');
DROP PROCEDURE IF EXISTS vn.route_getTickets;
DELIMITER $$
$$
CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`route_getTickets`(vRouteFk INT)
BEGIN
/**
* Pasado un RouteFk devuelve la información
* de sus tickets.
*
* @param vRouteFk
*
* @select Información de los tickets
*/
SELECT
t.id Id,
t.clientFk Client,
a.id Address,
t.packages Packages,
a.street AddressName,
a.postalCode PostalCode,
a.city City,
sub2.itemPackingTypeFk PackingType,
c.phone ClientPhone,
c.mobile ClientMobile,
a.phone AddressPhone,
a.mobile AddressMobile,
d.longitude Longitude,
d.latitude Latitude,
wm.mediaValue SalePersonPhone,
tob.Note Note,
t.isSigned Signed
FROM ticket t
JOIN client c ON t.clientFk = c.id
JOIN address a ON t.addressFk = a.id
LEFT JOIN delivery d ON t.id = d.ticketFk
LEFT JOIN workerMedia wm ON wm.workerFk = c.salesPersonFk
LEFT JOIN
(SELECT tob.description Note, t.id
FROM ticketObservation tob
JOIN ticket t ON tob.ticketFk = t.id
JOIN observationType ot ON ot.id = tob.observationTypeFk
WHERE t.routeFk = vRouteFk
AND ot.code = 'delivery'
)tob ON tob.id = t.id
LEFT JOIN
(SELECT sub.ticketFk,
CONCAT('(', GROUP_CONCAT(DISTINCT sub.itemPackingTypeFk ORDER BY sub.items DESC SEPARATOR ','), ') ') itemPackingTypeFk
FROM (SELECT s.ticketFk , i.itemPackingTypeFk, COUNT(*) items
FROM ticket t
JOIN sale s ON s.ticketFk = t.id
JOIN item i ON i.id = s.itemFk
WHERE t.routeFk = vRouteFk
GROUP BY t.id,i.itemPackingTypeFk)sub
GROUP BY sub.ticketFk
) sub2 ON sub2.ticketFk = t.id
WHERE t.routeFk = vRouteFk
GROUP BY t.id
ORDER BY t.priority;
END$$
DELIMITER ;

View File

@ -0,0 +1,67 @@
DELETE FROM `salix`.`ACL` WHERE `property` = 'saveSign';
INSERT INTO `salix`.`ACL` (`model`,`property`,`accessType`,`permission`,`principalId`)
VALUES
('Ticket','saveSign','WRITE','ALLOW','employee');
DROP PROCEDURE IF EXISTS vn.route_getTickets;
DELIMITER $$
$$
CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`route_getTickets`(vRouteFk INT)
BEGIN
/**
* Pasado un RouteFk devuelve la información
* de sus tickets.
*
* @param vRouteFk
*
* @select Información de los tickets
*/
SELECT
t.id Id,
t.clientFk Client,
a.id Address,
t.packages Packages,
a.street AddressName,
a.postalCode PostalCode,
a.city City,
sub2.itemPackingTypeFk PackingType,
c.phone ClientPhone,
c.mobile ClientMobile,
a.phone AddressPhone,
a.mobile AddressMobile,
d.longitude Longitude,
d.latitude Latitude,
wm.mediaValue SalePersonPhone,
tob.Note Note,
t.isSigned Signed
FROM ticket t
JOIN client c ON t.clientFk = c.id
JOIN address a ON t.addressFk = a.id
LEFT JOIN delivery d ON t.id = d.ticketFk
LEFT JOIN workerMedia wm ON wm.workerFk = c.salesPersonFk
LEFT JOIN
(SELECT tob.description Note, t.id
FROM ticketObservation tob
JOIN ticket t ON tob.ticketFk = t.id
JOIN observationType ot ON ot.id = tob.observationTypeFk
WHERE t.routeFk = vRouteFk
AND ot.code = 'delivery'
)tob ON tob.id = t.id
LEFT JOIN
(SELECT sub.ticketFk,
CONCAT('(', GROUP_CONCAT(DISTINCT sub.itemPackingTypeFk ORDER BY sub.items DESC SEPARATOR ','), ') ') itemPackingTypeFk
FROM (SELECT s.ticketFk , i.itemPackingTypeFk, COUNT(*) items
FROM ticket t
JOIN sale s ON s.ticketFk = t.id
JOIN item i ON i.id = s.itemFk
WHERE t.routeFk = vRouteFk
GROUP BY t.id,i.itemPackingTypeFk)sub
GROUP BY sub.ticketFk
) sub2 ON sub2.ticketFk = t.id
WHERE t.routeFk = vRouteFk
GROUP BY t.id
ORDER BY t.priority;
END$$
DELIMITER ;

View File

@ -0,0 +1,83 @@
CREATE TABLE `vn`.`dmsRecover` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`ticketFk` int(11) DEFAULT NULL,
`sign` text DEFAULT NULL,
`created` timestamp NULL DEFAULT current_timestamp(),
PRIMARY KEY (`id`),
KEY `ticketFk_idx` (`ticketFk`),
CONSTRAINT `ticketFk` FOREIGN KEY (`ticketFk`) REFERENCES `ticket` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=31917 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
ALTER TABLE `vn`.`delivery` ADD addressFk INT;
DROP PROCEDURE IF EXISTS `vn`.`route_getTickets`;
DELIMITER $$
$$
CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`route_getTickets`(vRouteFk INT)
BEGIN
/**
* Pasado un RouteFk devuelve la información
* de sus tickets.
*
* @param vRouteFk
* @select Información de los tickets
*/
SELECT *
FROM (
SELECT t.id Id,
t.clientFk Client,
a.id Address,
a.nickname ClientName,
t.packages Packages,
a.street AddressName,
a.postalCode PostalCode,
a.city City,
sub2.itemPackingTypeFk PackingType,
c.phone ClientPhone,
c.mobile ClientMobile,
a.phone AddressPhone,
a.mobile AddressMobile,
d.longitude Longitude,
d.latitude Latitude,
wm.mediaValue SalePersonPhone,
tob.description Note,
t.isSigned Signed,
t.priority
FROM ticket t
JOIN client c ON t.clientFk = c.id
JOIN address a ON t.addressFk = a.id
LEFT JOIN delivery d ON d.addressFk = a.id
LEFT JOIN workerMedia wm ON wm.workerFk = c.salesPersonFk
LEFT JOIN(
SELECT tob.description, t.id
FROM ticketObservation tob
JOIN ticket t ON tob.ticketFk = t.id
JOIN observationType ot ON ot.id = tob.observationTypeFk
WHERE t.routeFk = vRouteFk
AND ot.code = 'delivery'
)tob ON tob.id = t.id
LEFT JOIN(
SELECT sub.ticketFk,
CONCAT('(',
GROUP_CONCAT(DISTINCT sub.itemPackingTypeFk
ORDER BY sub.items DESC SEPARATOR ','),
') ') itemPackingTypeFk
FROM (
SELECT s.ticketFk, i.itemPackingTypeFk, COUNT(*) items
FROM ticket t
JOIN sale s ON s.ticketFk = t.id
JOIN item i ON i.id = s.itemFk
WHERE t.routeFk = vRouteFk
GROUP BY t.id, i.itemPackingTypeFk
)sub
GROUP BY sub.ticketFk
)sub2 ON sub2.ticketFk = t.id
WHERE t.routeFk = vRouteFk
ORDER BY d.id DESC
LIMIT 10000000000000000000
)sub3
GROUP BY sub3.id
ORDER BY sub3.priority;
END$$
DELIMITER ;

View File

@ -0,0 +1 @@
ALTER TABLE `vn`.`printQueueArgs` MODIFY COLUMN value varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_unicode_ci NULL;

View File

@ -0,0 +1 @@
DROP TRIGGER IF EXISTS `vn`.`claimBeginning_afterInsert`;

View File

@ -0,0 +1,72 @@
DROP TRIGGER IF EXISTS `vn`.`client_beforeUpdate`;
USE `vn`;
DELIMITER $$
$$
CREATE DEFINER=`root`@`localhost` TRIGGER `vn`.`client_beforeUpdate`
BEFORE UPDATE ON `client`
FOR EACH ROW
BEGIN
DECLARE vText VARCHAR(255) DEFAULT NULL;
DECLARE vPayMethodFk INT;
-- Comprueba que el formato de los teléfonos es válido
IF !(NEW.phone <=> OLD.phone) AND (NEW.phone <> '') THEN
CALL pbx.phone_isValid(NEW.phone);
END IF;
IF !(NEW.mobile <=> OLD.mobile) AND (NEW.mobile <> '')THEN
CALL pbx.phone_isValid(NEW.mobile);
END IF;
SELECT id INTO vPayMethodFk
FROM vn.payMethod
WHERE code = 'bankDraft';
IF NEW.payMethodFk = vPayMethodFk AND NEW.dueDay = 0 THEN
SET NEW.dueDay = 5;
END IF;
-- Avisar al comercial si ha llegado la documentación sepa/core
IF NEW.hasSepaVnl AND !OLD.hasSepaVnl THEN
SET vText = 'Sepa de VNL';
END IF;
IF NEW.hasCoreVnl AND !OLD.hasCoreVnl THEN
SET vText = 'Core de VNL';
END IF;
IF vText IS NOT NULL
THEN
INSERT INTO mail(receiver, replyTo, `subject`, body)
SELECT
CONCAT(IF(ac.id,u.name, 'jgallego'), '@verdnatura.es'),
'administracion@verdnatura.es',
CONCAT('Cliente ', NEW.id),
CONCAT('Recibida la documentación: ', vText)
FROM worker w
LEFT JOIN account.user u ON w.userFk = u.id AND u.active
LEFT JOIN account.account ac ON ac.id = u.id
WHERE w.id = NEW.salesPersonFk;
END IF;
IF NEW.salespersonFk IS NULL AND OLD.salespersonFk IS NOT NULL THEN
IF (SELECT COUNT(clientFk)
FROM clientProtected
WHERE clientFk = NEW.id
) > 0 THEN
CALL util.throw("HAS_CLIENT_PROTECTED");
END IF;
END IF;
IF !(NEW.salesPersonFk <=> OLD.salesPersonFk) THEN
SET NEW.lastSalesPersonFk = IFNULL(NEW.salesPersonFk, OLD.salesPersonFk);
END IF;
IF !(NEW.businessTypeFk <=> OLD.businessTypeFk) AND (NEW.businessTypeFk = 'individual' OR OLD.businessTypeFk = 'individual') THEN
SET NEW.isTaxDataChecked = 0;
END IF;
END$$
DELIMITER ;

View File

@ -0,0 +1,5 @@
DROP TRIGGER `vn`.`deviceProduction_afterInsert`;
DROP TRIGGER `vn`.`deviceProduction_afterUpdate`;
DROP TRIGGER `vn`.`deviceProductionUser_afterDelete`;

View File

@ -0,0 +1,77 @@
DROP TABLE IF EXISTS `vn`.`dmsRecover`;
DROP PROCEDURE IF EXISTS `vn`.`route_getTickets`;
DELIMITER $$
$$
CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`route_getTickets`(vRouteFk INT)
BEGIN
/**
* Pasado un RouteFk devuelve la información
* de sus tickets.
*
* @param vRouteFk
* @select Información de los tickets
*/
SELECT *
FROM (
SELECT t.id Id,
t.clientFk Client,
a.id Address,
a.nickname ClientName,
t.packages Packages,
a.street AddressName,
a.postalCode PostalCode,
a.city City,
sub2.itemPackingTypeFk PackingType,
c.phone ClientPhone,
c.mobile ClientMobile,
a.phone AddressPhone,
a.mobile AddressMobile,
d.longitude Longitude,
d.latitude Latitude,
wm.mediaValue SalePersonPhone,
tob.description Note,
t.isSigned Signed,
t.priority
FROM ticket t
JOIN client c ON t.clientFk = c.id
JOIN address a ON t.addressFk = a.id
LEFT JOIN delivery d ON d.ticketFk = t.id
LEFT JOIN workerMedia wm ON wm.workerFk = c.salesPersonFk
LEFT JOIN(
SELECT tob.description, t.id
FROM ticketObservation tob
JOIN ticket t ON tob.ticketFk = t.id
JOIN observationType ot ON ot.id = tob.observationTypeFk
WHERE t.routeFk = vRouteFk
AND ot.code = 'delivery'
)tob ON tob.id = t.id
LEFT JOIN(
SELECT sub.ticketFk,
CONCAT('(',
GROUP_CONCAT(DISTINCT sub.itemPackingTypeFk
ORDER BY sub.items DESC SEPARATOR ','),
') ') itemPackingTypeFk
FROM (
SELECT s.ticketFk, i.itemPackingTypeFk, COUNT(*) items
FROM ticket t
JOIN sale s ON s.ticketFk = t.id
JOIN item i ON i.id = s.itemFk
WHERE t.routeFk = vRouteFk
GROUP BY t.id, i.itemPackingTypeFk
)sub
GROUP BY sub.ticketFk
)sub2 ON sub2.ticketFk = t.id
WHERE t.routeFk = vRouteFk
ORDER BY d.id DESC
LIMIT 10000000000000000000
)sub3
GROUP BY sub3.id
ORDER BY sub3.priority;
END$$
DELIMITER ;
ALTER TABLE `vn`.`delivery` DROP FOREIGN KEY delivery_ticketFk_FK;
ALTER TABLE `vn`.`delivery` DROP COLUMN ticketFk;
ALTER TABLE `vn`.`delivery` ADD ticketFk INT DEFAULT NULL;
ALTER TABLE `vn`.`delivery` ADD CONSTRAINT delivery_ticketFk_FK FOREIGN KEY (`ticketFk`) REFERENCES `vn`.`ticket`(`id`);

View File

@ -0,0 +1,13 @@
DROP TRIGGER IF EXISTS `vn`.`invoiceOut_afterInsert`;
USE vn;
DELIMITER $$
$$
CREATE DEFINER=`root`@`localhost` TRIGGER `vn`.`invoiceOut_afterInsert`
AFTER INSERT ON `invoiceOut`
FOR EACH ROW
BEGIN
CALL clientRisk_update(NEW.clientFk, NEW.companyFk, NEW.amount);
END$$
DELIMITER ;

View File

@ -0,0 +1,4 @@
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('InvoiceIn', 'negativeBases', 'READ', 'ALLOW', 'ROLE', 'administrative'),
('InvoiceIn', 'negativeBasesCsv', 'READ', 'ALLOW', 'ROLE', 'administrative');

View File

@ -0,0 +1,14 @@
CREATE TABLE `vn`.`workerObservation` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`workerFk` int(10) unsigned DEFAULT NULL,
`userFk` int(10) unsigned DEFAULT NULL,
`text` text COLLATE utf8mb3_unicode_ci NOT NULL,
`created` timestamp NOT NULL DEFAULT current_timestamp(),
PRIMARY KEY (`id`),
CONSTRAINT `workerFk_workerObservation_FK` FOREIGN KEY (`workerFk`) REFERENCES `vn`.`worker` (`id`) ON UPDATE CASCADE,
CONSTRAINT `userFk_workerObservation_FK` FOREIGN KEY (`userFk`) REFERENCES `account`.`user`(`id`) ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci COMMENT='Todas las observaciones referentes a un trabajador';
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('WorkerObservation', '*', '*', 'ALLOW', 'ROLE', 'hr');

View File

@ -0,0 +1,3 @@
UPDATE `salix`.`ACL`
SET model = 'InvoiceOut'
WHERE property IN ('negativeBases', 'negativeBasesCsv');

View File

@ -0,0 +1,3 @@
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES ('ClientInforma', '*', 'READ', 'ALLOW', 'ROLE', 'employee'),
('ClientInforma', '*', 'WRITE', 'ALLOW', 'ROLE', 'financial');

View File

@ -0,0 +1,16 @@
ALTER TABLE `vn`.`client` ADD rating INT UNSIGNED DEFAULT NULL NULL COMMENT 'información proporcionada por Informa';
ALTER TABLE `vn`.`client` ADD recommendedCredit INT UNSIGNED DEFAULT NULL NULL COMMENT 'información proporcionada por Informa';
CREATE TABLE `vn`.`clientInforma` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`clientFk` int(11) NOT NULL,
`rating` int(10) unsigned DEFAULT NULL,
`recommendedCredit` int(10) unsigned DEFAULT NULL,
`workerFk` int(10) unsigned NOT NULL,
`created` timestamp NOT NULL DEFAULT current_timestamp(),
PRIMARY KEY (`id`),
KEY `informaWorkers_fk_idx` (`workerFk`),
KEY `informaClientFk` (`clientFk`),
CONSTRAINT `informa_ClienteFk` FOREIGN KEY (`clientFk`) REFERENCES `client` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `informa_workers_fk` FOREIGN KEY (`workerFk`) REFERENCES `worker` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci COMMENT='información proporcionada por Informa, se actualiza desde el hook de client (salix)';

View File

@ -0,0 +1,64 @@
DELETE FROM `salix`.`ACL` WHERE id=7;
INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
VALUES
('Client', 'setRating', 'WRITE', 'ALLOW', 'ROLE', 'financial');
INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
VALUES
('Client', '*', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Client', 'addressesPropagateRe', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'canBeInvoiced', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'canCreateTicket', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'consumption', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'createAddress', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'createWithUser', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'extendedListFilter', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'getAverageInvoiced', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'getCard', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'getDebt', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'getMana', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'transactions', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'hasCustomerRole', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'isValidClient', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'lastActiveTickets', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'sendSms', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'setPassword', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'summary', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'updateAddress', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'updateFiscalData', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'updateUser', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'uploadFile', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'campaignMetricsPdf', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'campaignMetricsEmail', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'clientWelcomeHtml', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'clientWelcomeEmail', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'printerSetupHtml', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'printerSetupEmail', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'sepaCoreEmail', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'letterDebtorPdf', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'letterDebtorStHtml', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'letterDebtorStEmail', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'letterDebtorNdHtml', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'letterDebtorNdEmail', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'clientDebtStatementPdf', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'clientDebtStatementHtml', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'clientDebtStatementEmail', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'creditRequestPdf', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'creditRequestHtml', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'creditRequestEmail', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'incotermsAuthorizationPdf', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'incotermsAuthorizationHtml', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'incotermsAuthorizationEmail', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'consumptionSendQueued', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'filter', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'getClientOrSupplierReference', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'upsert', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'create', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'replaceById', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'updateAttributes', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'updateAttributes', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'deleteById', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'replaceOrCreate', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'updateAll', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'upsertWithWhere', '*', 'ALLOW', 'ROLE', 'employee');

View File

@ -0,0 +1,2 @@
DROP PROCEDURE `vn`.`refund`;
DROP PROCEDURE `vn`.`ticket_doRefund`;

View File

@ -0,0 +1 @@
ALTER TABLE `vn`.`entry` DROP COLUMN `notes`;

View File

@ -0,0 +1,9 @@
-- vn.companyI18n definition
CREATE TABLE `vn`.`companyI18n` (
`companyFk` smallint(5) unsigned NOT NULL,
`lang` char(2) CHARACTER SET utf8mb3 NOT NULL,
`footnotes` longtext COLLATE utf8mb3_unicode_ci DEFAULT NULL,
PRIMARY KEY (`companyFk`,`lang`),
CONSTRAINT `companyI18n_FK` FOREIGN KEY (`companyFk`) REFERENCES `company` (`id`) ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;

View File

@ -0,0 +1 @@
ALTER TABLE `vn`.`company` ADD `web` varchar(100) NULL;

View File

@ -0,0 +1,3 @@
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('Defaulter', 'observationEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee');

View File

@ -0,0 +1,77 @@
CREATE OR REPLACE
ALGORITHM = UNDEFINED VIEW `vn`.`zoneEstimatedDelivery` AS
select
`t`.`zoneFk` AS `zoneFk`,
cast(`util`.`VN_CURDATE`() + interval hour(ifnull(`zc`.`hour`, `z`.`hour`)) * 60 + minute(ifnull(`zc`.`hour`, `z`.`hour`)) minute as time) AS `hourTheoretical`,
cast(sum(`sv`.`volume`) as decimal(5, 1)) AS `totalVolume`,
cast(sum(if(`s`.`alertLevel` < 2, `sv`.`volume`, 0)) as decimal(5, 1)) AS `remainingVolume`,
greatest(
ifnull(`lhp`.`m3`, 0),
ifnull(`dl`.`minSpeed`, 0)
) AS `speed`,
cast(`zc`.`hour` + interval -sum(if(`s`.`alertLevel` < 2, `sv`.`volume`, 0)) * 60 / greatest(ifnull(`lhp`.`m3`, 0), ifnull(`dl`.`minSpeed`, 0)) minute as time) AS `hourEffective`,
floor(-sum(if(`s`.`alertLevel` < 2, `sv`.`volume`, 0)) * 60 / greatest(ifnull(`lhp`.`m3`, 0), ifnull(`dl`.`minSpeed`, 0))) AS `minutesLess`,
cast(`zc`.`hour` + interval -sum(if(`s`.`alertLevel` < 2, `sv`.`volume`, 0)) * 60 / greatest(ifnull(`lhp`.`m3`, 0), ifnull(`dl`.`minSpeed`, 0)) minute as time) AS `etc`
from
(
(
(
(
(
(
(
(
(
`vn`.`ticket` `t`
join `vn`.`ticketStateToday` `tst` on
(
`tst`.`ticket` = `t`.`id`
)
)
join `vn`.`state` `s` on
(
`s`.`id` = `tst`.`state`
)
)
join `vn`.`saleVolume` `sv` on
(
`sv`.`ticketFk` = `t`.`id`
)
)
left join `vn`.`lastHourProduction` `lhp` on
(
`lhp`.`warehouseFk` = `t`.`warehouseFk`
)
)
join `vn`.`warehouse` `w` on
(
`w`.`id` = `t`.`warehouseFk`
)
)
join `vn`.`warehouseAlias` `wa` on
(
`wa`.`id` = `w`.`aliasFk`
)
)
straight_join `vn`.`zone` `z` on
(
`z`.`id` = `t`.`zoneFk`
)
)
left join `vn`.`zoneClosure` `zc` on
(
`zc`.`zoneFk` = `t`.`zoneFk`
and `zc`.`dated` = `util`.`VN_CURDATE`()
)
)
left join `cache`.`departure_limit` `dl` on
(
`dl`.`warehouse_id` = `t`.`warehouseFk`
and `dl`.`fecha` = `util`.`VN_CURDATE`()
)
)
where
`w`.`hasProduction` <> 0
and cast(`t`.`shipped` as date) = `util`.`VN_CURDATE`()
group by
`t`.`zoneFk`;

View File

@ -0,0 +1,5 @@
DROP PROCEDURE IF EXISTS `vn`.`sale_setQuantity`;
DROP PROCEDURE IF EXISTS `vn`.`collection_updateSale`;
DROP PROCEDURE IF EXISTS `vn`.`replaceMovimientosMark`;
DROP PROCEDURE IF EXISTS `vn`.`saleTracking_Replace`;
DROP PROCEDURE IF EXISTS `vn`.`sale_updateOriginalQuantity`;

View File

@ -0,0 +1 @@
ALTER TABLE `vn`.`ticketConfig` ADD daysForWarningClaim INT DEFAULT 2 NOT NULL COMMENT 'dias restantes hasta que salte el aviso de reclamación fuera de plazo';

View File

@ -0,0 +1,5 @@
UPDATE `vn`.`supplier` s
JOIN `vn`.`country` c ON c.id = s.countryFk
SET s.nif = MID(REPLACE(s.nif, ' ', ''), 3, LENGTH(REPLACE(s.nif, ' ', '')) - 1)
WHERE s.isVies = TRUE
AND c.code = LEFT(REPLACE(s.nif, ' ', ''), 2);

View File

@ -0,0 +1,5 @@
UPDATE IGNORE `vn`.`client` c
JOIN `vn`.`country` co ON co.id = c.countryFk
SET c.fi = MID(REPLACE(c.fi, ' ', ''), 3, LENGTH(REPLACE(c.fi, ' ', '')) - 1)
WHERE c.isVies = TRUE
AND co.code = LEFT(REPLACE(c.fi, ' ', ''), 2);

View File

@ -0,0 +1,21 @@
INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
VALUES
('VnUser', '*', '*', 'ALLOW', 'ROLE', 'employee'),
('VnUser','acl','READ','ALLOW','ROLE','account'),
('VnUser','getCurrentUserData','READ','ALLOW','ROLE','account'),
('VnUser','changePassword', 'WRITE', 'ALLOW', 'ROLE', 'account'),
('Account','exists','READ','ALLOW','ROLE','account');
INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
VALUES
('Account','exists','READ','ALLOW','ROLE','account');
DELETE FROM `salix`.`ACL` WHERE (model, property) = ('Account', 'acl');
DELETE FROM `salix`.`ACL` WHERE (model, property) = ('Account', 'getCurrentUserData');
DELETE FROM `salix`.`ACL` WHERE (model, property) = ('Account', 'changePassword');
DELETE FROM `salix`.`ACL` WHERE model = 'UserAccount';
UPDATE `hedera`.`imageCollection` t
SET t.model = 'VnUser'
WHERE t.id = 6;

View File

@ -0,0 +1,4 @@
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('UserLog', '*', 'READ', 'ALLOW', 'ROLE', 'employee'),
('RoleLog', '*', 'READ', 'ALLOW', 'ROLE', 'employee');

View File

@ -98,20 +98,20 @@ INSERT INTO `hedera`.`tpvConfig`(`id`, `currency`, `terminal`, `transactionType`
VALUES VALUES
(1, 978, 1, 0, 2000, 9, 0); (1, 978, 1, 0, 2000, 9, 0);
INSERT INTO `account`.`user`(`id`,`name`,`nickname`, `password`,`role`,`active`,`email`,`lang`, `image`) INSERT INTO `account`.`user`(`id`,`name`,`nickname`, `bcryptPassword`, `password`,`role`,`active`,`email`,`lang`, `image`)
VALUES VALUES
(1101, 'BruceWayne', 'Bruce Wayne', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'BruceWayne@mydomain.com', 'es', 'e7723f0b24ff05b32ed09d95196f2f29'), (1101, 'BruceWayne', 'Bruce Wayne', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'BruceWayne@mydomain.com', 'es', 'e7723f0b24ff05b32ed09d95196f2f29'),
(1102, 'PetterParker', 'Petter Parker', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'PetterParker@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'), (1102, 'PetterParker', 'Petter Parker', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'PetterParker@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'),
(1103, 'ClarkKent', 'Clark Kent', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'ClarkKent@mydomain.com', 'fr', 'e7723f0b24ff05b32ed09d95196f2f29'), (1103, 'ClarkKent', 'Clark Kent', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'ClarkKent@mydomain.com', 'fr', 'e7723f0b24ff05b32ed09d95196f2f29'),
(1104, 'TonyStark', 'Tony Stark', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'TonyStark@mydomain.com', 'es', 'e7723f0b24ff05b32ed09d95196f2f29'), (1104, 'TonyStark', 'Tony Stark', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'TonyStark@mydomain.com', 'es', 'e7723f0b24ff05b32ed09d95196f2f29'),
(1105, 'MaxEisenhardt', 'Max Eisenhardt', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'MaxEisenhardt@mydomain.com', 'pt', 'e7723f0b24ff05b32ed09d95196f2f29'), (1105, 'MaxEisenhardt', 'Max Eisenhardt', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'MaxEisenhardt@mydomain.com', 'pt', 'e7723f0b24ff05b32ed09d95196f2f29'),
(1106, 'DavidCharlesHaller', 'David Charles Haller', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'DavidCharlesHaller@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'), (1106, 'DavidCharlesHaller', 'David Charles Haller', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'DavidCharlesHaller@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'),
(1107, 'HankPym', 'Hank Pym', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'HankPym@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'), (1107, 'HankPym', 'Hank Pym', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'HankPym@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'),
(1108, 'CharlesXavier', 'Charles Xavier', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'CharlesXavier@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'), (1108, 'CharlesXavier', 'Charles Xavier', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'CharlesXavier@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'),
(1109, 'BruceBanner', 'Bruce Banner', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'BruceBanner@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'), (1109, 'BruceBanner', 'Bruce Banner', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'BruceBanner@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'),
(1110, 'JessicaJones', 'Jessica Jones', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'JessicaJones@mydomain.com', 'en', NULL), (1110, 'JessicaJones', 'Jessica Jones', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'JessicaJones@mydomain.com', 'en', NULL),
(1111, 'Missing', 'Missing', 'ac754a330530832ba1bf7687f577da91', 2, 0, NULL, 'en', NULL), (1111, 'Missing', 'Missing', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 2, 0, NULL, 'en', NULL),
(1112, 'Trash', 'Trash', 'ac754a330530832ba1bf7687f577da91', 2, 0, NULL, 'en', NULL); (1112, 'Trash', 'Trash', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 2, 0, NULL, 'en', NULL);
INSERT INTO `account`.`mailAlias`(`id`, `alias`, `description`, `isPublic`) INSERT INTO `account`.`mailAlias`(`id`, `alias`, `description`, `isPublic`)
VALUES VALUES
@ -173,10 +173,6 @@ INSERT INTO `vn`.`sector`(`id`, `description`, `warehouseFk`, `isPreviousPrepare
(1, 'First sector', 1, 1, 'FIRST'), (1, 'First sector', 1, 1, 'FIRST'),
(2, 'Second sector', 2, 0, 'SECOND'); (2, 'Second sector', 2, 0, 'SECOND');
INSERT INTO `vn`.`operator` (`workerFk`, `numberOfWagons`, `trainFk`, `itemPackingTypeFk`, `warehouseFk`, `sectorFk`, `labelerFk`)
VALUES ('1106', '1', '1', 'H', '1', '1', '1'),
('1107', '1', '1', 'V', '1', '2', '1');
INSERT INTO `vn`.`printer` (`id`, `name`, `path`, `isLabeler`, `sectorFk`, `ipAddress`) INSERT INTO `vn`.`printer` (`id`, `name`, `path`, `isLabeler`, `sectorFk`, `ipAddress`)
VALUES VALUES
(1, 'printer1', 'path1', 0, 1 , NULL), (1, 'printer1', 'path1', 0, 1 , NULL),
@ -501,7 +497,8 @@ INSERT INTO `vn`.`observationType`(`id`,`description`, `code`)
(3, 'Delivery', 'delivery'), (3, 'Delivery', 'delivery'),
(4, 'SalesPerson', 'salesPerson'), (4, 'SalesPerson', 'salesPerson'),
(5, 'Administrative', 'administrative'), (5, 'Administrative', 'administrative'),
(6, 'Weight', 'weight'); (6, 'Weight', 'weight'),
(7, 'InvoiceOut', 'invoiceOut');
INSERT INTO `vn`.`addressObservation`(`id`,`addressFk`,`observationTypeFk`,`description`) INSERT INTO `vn`.`addressObservation`(`id`,`addressFk`,`observationTypeFk`,`description`)
VALUES VALUES
@ -549,7 +546,8 @@ INSERT INTO `vn`.`supplier`(`id`, `name`, `nickname`,`account`,`countryFk`,`nif`
VALUES VALUES
(1, 'Plants SL', 'Plants nick', 4100000001, 1, '06089160W', 0, util.VN_CURDATE(), 1, 'supplier address 1', 'PONTEVEDRA', 1, 15214, 1, 1, 15, 4, 1, 1, 18, 'flowerPlants', 1, '400664487V'), (1, 'Plants SL', 'Plants nick', 4100000001, 1, '06089160W', 0, util.VN_CURDATE(), 1, 'supplier address 1', 'PONTEVEDRA', 1, 15214, 1, 1, 15, 4, 1, 1, 18, 'flowerPlants', 1, '400664487V'),
(2, 'Farmer King', 'The farmer', 4000020002, 1, '87945234L', 0, util.VN_CURDATE(), 1, 'supplier address 2', 'GOTHAM', 2, 43022, 1, 2, 10, 93, 2, 8, 18, 'animals', 1, '400664487V'), (2, 'Farmer King', 'The farmer', 4000020002, 1, '87945234L', 0, util.VN_CURDATE(), 1, 'supplier address 2', 'GOTHAM', 2, 43022, 1, 2, 10, 93, 2, 8, 18, 'animals', 1, '400664487V'),
(442, 'Verdnatura Levante SL', 'Verdnatura', 5115000442, 1, '06815934E', 0, util.VN_CURDATE(), 1, 'supplier address 3', 'GOTHAM', 1, 43022, 1, 2, 15, 6, 9, 3, 18, 'complements', 1, '400664487V'); (442, 'Verdnatura Levante SL', 'Verdnatura', 5115000442, 1, '06815934E', 0, util.VN_CURDATE(), 1, 'supplier address 3', 'GOTHAM', 1, 43022, 1, 2, 15, 6, 9, 3, 18, 'complements', 1, '400664487V'),
(1381, 'Ornamentales', 'Ornamentales', 7185000440, 1, '03815934E', 0, util.VN_CURDATE(), 1, 'supplier address 4', 'GOTHAM', 1, 43022, 1, 2, 15, 6, 9, 3, 18, 'complements', 1, '400664487V');
INSERT INTO `vn`.`supplierContact`(`id`, `supplierFk`, `phone`, `mobile`, `email`, `observation`, `name`) INSERT INTO `vn`.`supplierContact`(`id`, `supplierFk`, `phone`, `mobile`, `email`, `observation`, `name`)
VALUES VALUES
@ -738,7 +736,9 @@ INSERT INTO `vn`.`ticketObservation`(`id`, `ticketFk`, `observationTypeFk`, `des
(9, 23, 5, 'care with the dog'), (9, 23, 5, 'care with the dog'),
(10, 23, 4, 'Reclama ticket: 8'), (10, 23, 4, 'Reclama ticket: 8'),
(11, 24, 4, 'Reclama ticket: 7'), (11, 24, 4, 'Reclama ticket: 7'),
(12, 11, 3, 'Delivery after 10am'); (12, 11, 3, 'Delivery after 10am'),
(13, 1, 7, 'observation of ticket one'),
(14, 2, 7, 'observation of ticket two');
-- FIX for state hours on local, inter_afterInsert -- FIX for state hours on local, inter_afterInsert
-- UPDATE vncontrol.inter SET odbc_date = DATE_ADD(util.VN_CURDATE(), INTERVAL -10 SECOND); -- UPDATE vncontrol.inter SET odbc_date = DATE_ADD(util.VN_CURDATE(), INTERVAL -10 SECOND);
@ -838,14 +838,14 @@ INSERT INTO `vn`.`temperature`(`code`, `name`, `description`)
('warm', 'Warm', 'Warm'), ('warm', 'Warm', 'Warm'),
('cool', 'Cool', 'Cool'); ('cool', 'Cool', 'Cool');
INSERT INTO `vn`.`itemType`(`id`, `code`, `name`, `categoryFk`, `life`, `workerFk`, `isPackaging`, `temperatureFk`) INSERT INTO `vn`.`itemType`(`id`, `code`, `name`, `categoryFk`, `life`, `workerFk`, `isPackaging`, `temperatureFk`, `isFragile`)
VALUES VALUES
(1, 'CRI', 'Crisantemo', 2, 31, 35, 0, 'cool'), (1, 'CRI', 'Crisantemo', 2, 31, 35, 0, 'cool', 0),
(2, 'ITG', 'Anthurium', 1, 31, 35, 0, 'cool'), (2, 'ITG', 'Anthurium', 1, 31, 35, 0, 'cool', 1),
(3, 'WPN', 'Paniculata', 2, 31, 35, 0, 'cool'), (3, 'WPN', 'Paniculata', 2, 31, 35, 0, 'cool', 0),
(4, 'PRT', 'Delivery ports', 3, NULL, 35, 1, 'warm'), (4, 'PRT', 'Delivery ports', 3, NULL, 35, 1, 'warm', 0),
(5, 'CON', 'Container', 3, NULL, 35, 1, 'warm'), (5, 'CON', 'Container', 3, NULL, 35, 1, 'warm', 0),
(6, 'ALS', 'Alstroemeria', 1, 31, 16, 0, 'warm'); (6, 'ALS', 'Alstroemeria', 1, 31, 16, 0, 'warm', 1);
INSERT INTO `vn`.`ink`(`id`, `name`, `picture`, `showOrder`, `hex`) INSERT INTO `vn`.`ink`(`id`, `name`, `picture`, `showOrder`, `hex`)
VALUES VALUES
@ -1197,6 +1197,11 @@ INSERT INTO `vn`.`train`(`id`, `name`)
(1, 'Train1'), (1, 'Train1'),
(2, 'Train2'); (2, 'Train2');
INSERT INTO `vn`.`operator` (`workerFk`, `numberOfWagons`, `trainFk`, `itemPackingTypeFk`, `warehouseFk`, `sectorFk`, `labelerFk`)
VALUES
('1106', '1', '1', 'H', '1', '1', '1'),
('1107', '1', '1', 'V', '1', '1', '1');
INSERT INTO `vn`.`collection`(`id`, `workerFk`, `stateFk`, `created`, `trainFk`) INSERT INTO `vn`.`collection`(`id`, `workerFk`, `stateFk`, `created`, `trainFk`)
VALUES VALUES
(1, 1106, 5, DATE_ADD(util.VN_CURDATE(),INTERVAL +1 DAY), 1), (1, 1106, 5, DATE_ADD(util.VN_CURDATE(),INTERVAL +1 DAY), 1),
@ -1404,16 +1409,16 @@ INSERT INTO `vn`.`travel`(`id`,`shipped`, `landed`, `warehouseInFk`, `warehouseO
(7, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 5, 4, 1, 50.00, 500, 'seventh travel', 2, 1), (7, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 5, 4, 1, 50.00, 500, 'seventh travel', 2, 1),
(8, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 5, 1, 1, 50.00, 500, 'eight travel', 1, 2); (8, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 5, 1, 1, 50.00, 500, 'eight travel', 1, 2);
INSERT INTO `vn`.`entry`(`id`, `supplierFk`, `created`, `travelFk`, `isConfirmed`, `companyFk`, `invoiceNumber`, `reference`, `isExcludedFromAvailable`, `isRaid`, `notes`, `evaNotes`) INSERT INTO `vn`.`entry`(`id`, `supplierFk`, `created`, `travelFk`, `isConfirmed`, `companyFk`, `invoiceNumber`, `reference`, `isExcludedFromAvailable`, `isRaid`, `evaNotes`)
VALUES VALUES
(1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1, 1, 442, 'IN2001', 'Movement 1', 0, 0, '', ''), (1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1, 1, 442, 'IN2001', 'Movement 1', 0, 0, ''),
(2, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 2, 0, 442, 'IN2002', 'Movement 2', 0, 0, 'this is the note two', 'observation two'), (2, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 2, 0, 442, 'IN2002', 'Movement 2', 0, 0, 'observation two'),
(3, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 3, 0, 442, 'IN2003', 'Movement 3', 0, 0, 'this is the note three', 'observation three'), (3, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 3, 0, 442, 'IN2003', 'Movement 3', 0, 0, 'observation three'),
(4, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 2, 0, 69, 'IN2004', 'Movement 4', 0, 0, 'this is the note four', 'observation four'), (4, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 2, 0, 69, 'IN2004', 'Movement 4', 0, 0, 'observation four'),
(5, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 5, 0, 442, 'IN2005', 'Movement 5', 0, 0, 'this is the note five', 'observation five'), (5, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 5, 0, 442, 'IN2005', 'Movement 5', 0, 0, 'observation five'),
(6, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 6, 0, 442, 'IN2006', 'Movement 6', 0, 0, 'this is the note six', 'observation six'), (6, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 6, 0, 442, 'IN2006', 'Movement 6', 0, 0, 'observation six'),
(7, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 7, 0, 442, 'IN2007', 'Movement 7', 0, 0, 'this is the note seven', 'observation seven'), (7, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 7, 0, 442, 'IN2007', 'Movement 7', 0, 0, 'observation seven'),
(8, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 7, 0, 442, 'IN2008', 'Movement 8', 1, 1, '', ''); (8, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 7, 0, 442, 'IN2008', 'Movement 8', 1, 1, '');
INSERT INTO `bs`.`waste`(`buyer`, `year`, `week`, `family`, `itemFk`, `itemTypeFk`, `saleTotal`, `saleWaste`, `rate`) INSERT INTO `bs`.`waste`(`buyer`, `year`, `week`, `family`, `itemFk`, `itemTypeFk`, `saleTotal`, `saleWaste`, `rate`)
VALUES VALUES
@ -1771,12 +1776,12 @@ INSERT INTO `vn`.`claimState`(`id`, `code`, `description`, `roleFk`, `priority`,
( 6, 'mana', 'Mana', 72, 4, 0), ( 6, 'mana', 'Mana', 72, 4, 0),
( 7, 'lack', 'Faltas', 72, 2, 0); ( 7, 'lack', 'Faltas', 72, 2, 0);
INSERT INTO `vn`.`claim`(`id`, `ticketCreated`, `claimStateFk`, `clientFk`, `workerFk`, `responsibility`, `isChargedToMana`, `created`, `packages`, `rma`) INSERT INTO `vn`.`claim`(`id`, `ticketCreated`, `claimStateFk`, `clientFk`, `workerFk`, `responsibility`, `isChargedToMana`, `created`, `packages`, `rma`, `ticketFk`)
VALUES VALUES
(1, util.VN_CURDATE(), 1, 1101, 18, 3, 0, util.VN_CURDATE(), 0, '02676A049183'), (1, util.VN_CURDATE(), 1, 1101, 18, 3, 0, util.VN_CURDATE(), 0, '02676A049183', 11),
(2, util.VN_CURDATE(), 2, 1101, 18, 3, 0, util.VN_CURDATE(), 1, NULL), (2, util.VN_CURDATE(), 2, 1101, 18, 3, 0, util.VN_CURDATE(), 1, NULL, 16),
(3, util.VN_CURDATE(), 3, 1101, 18, 1, 1, util.VN_CURDATE(), 5, NULL), (3, util.VN_CURDATE(), 3, 1101, 18, 1, 1, util.VN_CURDATE(), 5, NULL, 7),
(4, util.VN_CURDATE(), 3, 1104, 18, 5, 0, util.VN_CURDATE(), 10, NULL); (4, util.VN_CURDATE(), 3, 1104, 18, 5, 0, util.VN_CURDATE(), 10, NULL, 8);
INSERT INTO `vn`.`claimObservation` (`claimFk`, `workerFk`, `text`, `created`) INSERT INTO `vn`.`claimObservation` (`claimFk`, `workerFk`, `text`, `created`)
VALUES VALUES
@ -2487,9 +2492,9 @@ REPLACE INTO `vn`.`invoiceIn`(`id`, `serialNumber`,`serial`, `supplierFk`, `issu
(9, 1009, 'R', 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1242, 1, 442, 1), (9, 1009, 'R', 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1242, 1, 442, 1),
(10, 1010, 'R', 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1243, 1, 442, 1); (10, 1010, 'R', 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1243, 1, 442, 1);
INSERT INTO `vn`.`invoiceInConfig` (`id`, `retentionRate`, `retentionName`, `sageWithholdingFk`) INSERT INTO `vn`.`invoiceInConfig` (`id`, `retentionRate`, `retentionName`, `sageWithholdingFk`, `daysAgo`)
VALUES VALUES
(1, -2, '2% retention', 2); (1, -2, '2% retention', 2, 45);
INSERT INTO `vn`.`invoiceInDueDay`(`invoiceInFk`, `dueDated`, `bankFk`, `amount`) INSERT INTO `vn`.`invoiceInDueDay`(`invoiceInFk`, `dueDated`, `bankFk`, `amount`)
VALUES VALUES
@ -2631,8 +2636,8 @@ INSERT INTO `vn`.`supplierAgencyTerm` (`agencyFk`, `supplierFk`, `minimumPackage
INSERT INTO `vn`.`chat` (`senderFk`, `recipient`, `dated`, `checkUserStatus`, `message`, `status`, `attempts`) INSERT INTO `vn`.`chat` (`senderFk`, `recipient`, `dated`, `checkUserStatus`, `message`, `status`, `attempts`)
VALUES VALUES
(1101, '@PetterParker', util.VN_CURDATE(), 1, 'First test message', 0, 0), (1101, '@PetterParker', util.VN_CURDATE(), 1, 'First test message', 0, 'sent'),
(1101, '@PetterParker', util.VN_CURDATE(), 0, 'Second test message', 0, 0); (1101, '@PetterParker', util.VN_CURDATE(), 0, 'Second test message', 0, 'pending');
INSERT INTO `vn`.`mobileAppVersionControl` (`appName`, `version`, `isVersionCritical`) INSERT INTO `vn`.`mobileAppVersionControl` (`appName`, `version`, `isVersionCritical`)
@ -2785,7 +2790,7 @@ INSERT INTO `vn`.`profileType` (`id`, `name`)
INSERT INTO `salix`.`url` (`appName`, `environment`, `url`) INSERT INTO `salix`.`url` (`appName`, `environment`, `url`)
VALUES VALUES
('lilium', 'dev', 'http://localhost:8080/#/'), ('lilium', 'dev', 'http://localhost:9000/#/'),
('salix', 'dev', 'http://localhost:5000/#!/'); ('salix', 'dev', 'http://localhost:5000/#!/');
INSERT INTO `vn`.`report` (`id`, `name`, `paperSizeFk`, `method`) INSERT INTO `vn`.`report` (`id`, `name`, `paperSizeFk`, `method`)
@ -2837,4 +2842,27 @@ INSERT INTO `vn`.`workerTimeControlMail` (`id`, `workerFk`, `year`, `week`, `sta
(3, 9, 2000, 51, 'CONFIRMED', util.VN_NOW(), 1, NULL), (3, 9, 2000, 51, 'CONFIRMED', util.VN_NOW(), 1, NULL),
(4, 9, 2001, 1, 'SENDED', util.VN_NOW(), 1, NULL); (4, 9, 2001, 1, 'SENDED', util.VN_NOW(), 1, NULL);
INSERT INTO `vn`.`wagonConfig` (`id`, `width`, `height`, `maxWagonHeight`, `minHeightBetweenTrays`, `maxTrays`)
VALUES
(1, 1350, 1900, 200, 50, 6);
INSERT INTO `vn`.`wagonTypeColor` (`id`, `name`, `rgb`)
VALUES
(1, 'white', '#ffffff'),
(2, 'red', '#ff0000'),
(3, 'green', '#00ff00'),
(4, 'blue', '#0000ff');
INSERT INTO `vn`.`wagonType` (`id`, `name`, `divisible`)
VALUES
(1, 'Wagon Type #1', 1);
INSERT INTO `vn`.`wagonTypeTray` (`id`, `typeFk`, `height`, `colorFk`)
VALUES
(1, 1, 100, 1),
(2, 1, 50, 2),
(3, 1, 0, 3);

View File

@ -42776,7 +42776,7 @@ CREATE DEFINER=`root`@`localhost` FUNCTION `hasAnyNegativeBase`() RETURNS tinyin
BEGIN BEGIN
/* Calcula si existe alguna base imponible negativa /* Calcula si existe alguna base imponible negativa
* Requiere la tabla temporal vn.ticketToInvoice(id) * Requiere la tabla temporal tmp.ticketToInvoice(id)
* *
* returns BOOLEAN * returns BOOLEAN
*/ */
@ -42787,7 +42787,7 @@ BEGIN
(KEY (ticketFk)) (KEY (ticketFk))
ENGINE = MEMORY ENGINE = MEMORY
SELECT id ticketFk SELECT id ticketFk
FROM ticketToInvoice; FROM tmp.ticketToInvoice;
CALL ticket_getTax(NULL); CALL ticket_getTax(NULL);
@ -55223,7 +55223,7 @@ DELIMITER ;;
CREATE DEFINER=`root`@`localhost` PROCEDURE `invoiceExpenceMake`(IN vInvoice INT) CREATE DEFINER=`root`@`localhost` PROCEDURE `invoiceExpenceMake`(IN vInvoice INT)
BEGIN BEGIN
/* Inserta las partidas de gasto correspondientes a la factura /* Inserta las partidas de gasto correspondientes a la factura
* REQUIERE tabla ticketToInvoice * REQUIERE tabla tmp.ticketToInvoice
* @param vInvoice Numero de factura * @param vInvoice Numero de factura
*/ */
DELETE FROM invoiceOutExpence DELETE FROM invoiceOutExpence
@ -55233,7 +55233,7 @@ BEGIN
SELECT vInvoice, SELECT vInvoice,
expenceFk, expenceFk,
SUM(ROUND(quantity * price * (100 - discount)/100,2)) amount SUM(ROUND(quantity * price * (100 - discount)/100,2)) amount
FROM ticketToInvoice t FROM tmp.ticketToInvoice t
JOIN sale s ON s.ticketFk = t.id JOIN sale s ON s.ticketFk = t.id
JOIN item i ON i.id = s.itemFk JOIN item i ON i.id = s.itemFk
GROUP BY i.expenceFk GROUP BY i.expenceFk
@ -55243,7 +55243,7 @@ BEGIN
SELECT vInvoice, SELECT vInvoice,
tst.expenceFk, tst.expenceFk,
SUM(ROUND(ts.quantity * ts.price ,2)) amount SUM(ROUND(ts.quantity * ts.price ,2)) amount
FROM ticketToInvoice t FROM tmp.ticketToInvoice t
JOIN ticketService ts ON ts.ticketFk = t.id JOIN ticketService ts ON ts.ticketFk = t.id
JOIN ticketServiceType tst ON tst.id = ts.ticketServiceTypeFk JOIN ticketServiceType tst ON tst.id = ts.ticketServiceTypeFk
HAVING amount != 0; HAVING amount != 0;
@ -55270,9 +55270,9 @@ BEGIN
SET vMaxTicketDate = vn2008.DAYEND(vMaxTicketDate); SET vMaxTicketDate = vn2008.DAYEND(vMaxTicketDate);
DROP TEMPORARY TABLE IF EXISTS `ticketToInvoice`; DROP TEMPORARY TABLE IF EXISTS `tmp`.`ticketToInvoice`;
CREATE TEMPORARY TABLE `ticketToInvoice` CREATE TEMPORARY TABLE `tmp`.`ticketToInvoice`
(PRIMARY KEY (`id`)) (PRIMARY KEY (`id`))
ENGINE = MEMORY ENGINE = MEMORY
SELECT Id_Ticket id FROM vn2008.Tickets WHERE (Fecha BETWEEN vMinDateTicket SELECT Id_Ticket id FROM vn2008.Tickets WHERE (Fecha BETWEEN vMinDateTicket
@ -55305,8 +55305,8 @@ BEGIN
SET vMinTicketDate = util.firstDayOfYear(vMaxTicketDate - INTERVAL 1 YEAR); SET vMinTicketDate = util.firstDayOfYear(vMaxTicketDate - INTERVAL 1 YEAR);
SET vMaxTicketDate = util.dayend(vMaxTicketDate); SET vMaxTicketDate = util.dayend(vMaxTicketDate);
DROP TEMPORARY TABLE IF EXISTS `ticketToInvoice`; DROP TEMPORARY TABLE IF EXISTS `tmp`.`ticketToInvoice`;
CREATE TEMPORARY TABLE `ticketToInvoice` CREATE TEMPORARY TABLE `tmp`.`ticketToInvoice`
(PRIMARY KEY (`id`)) (PRIMARY KEY (`id`))
ENGINE = MEMORY ENGINE = MEMORY
SELECT id FROM ticket t SELECT id FROM ticket t
@ -55333,9 +55333,9 @@ DELIMITER ;;
CREATE DEFINER=`root`@`localhost` PROCEDURE `invoiceFromTicket`(IN vTicket INT) CREATE DEFINER=`root`@`localhost` PROCEDURE `invoiceFromTicket`(IN vTicket INT)
BEGIN BEGIN
DROP TEMPORARY TABLE IF EXISTS `ticketToInvoice`; DROP TEMPORARY TABLE IF EXISTS `tmp`.`ticketToInvoice`;
CREATE TEMPORARY TABLE `ticketToInvoice` CREATE TEMPORARY TABLE `tmp`.`ticketToInvoice`
(PRIMARY KEY (`id`)) (PRIMARY KEY (`id`))
ENGINE = MEMORY ENGINE = MEMORY
SELECT id FROM vn.ticket SELECT id FROM vn.ticket
@ -55931,9 +55931,9 @@ BEGIN
JOIN invoiceOut io ON io.companyFk = s.id JOIN invoiceOut io ON io.companyFk = s.id
WHERE io.id = vInvoiceFk; WHERE io.id = vInvoiceFk;
DROP TEMPORARY TABLE IF EXISTS ticketToInvoice; DROP TEMPORARY TABLE IF EXISTS tmp.ticketToInvoice;
CREATE TEMPORARY TABLE ticketToInvoice CREATE TEMPORARY TABLE tmp.ticketToInvoice
SELECT id SELECT id
FROM ticket FROM ticket
WHERE refFk = vInvoiceRef; WHERE refFk = vInvoiceRef;
@ -56408,9 +56408,9 @@ BEGIN
JOIN client c ON c.id = io.clientFk JOIN client c ON c.id = io.clientFk
WHERE io.id = vInvoice; WHERE io.id = vInvoice;
DROP TEMPORARY TABLE IF EXISTS ticketToInvoice; DROP TEMPORARY TABLE IF EXISTS tmp.ticketToInvoice;
CREATE TEMPORARY TABLE ticketToInvoice CREATE TEMPORARY TABLE tmp.ticketToInvoice
SELECT id SELECT id
FROM ticket FROM ticket
WHERE refFk = vInvoiceRef; WHERE refFk = vInvoiceRef;
@ -56456,7 +56456,7 @@ CREATE DEFINER=`root`@`localhost` PROCEDURE `invoiceOut_exportationFromClient`(
vCompanyFk INT) vCompanyFk INT)
BEGIN BEGIN
/** /**
* Genera tabla temporal ticketToInvoice necesaría para el proceso de facturación * Genera tabla temporal tmp.ticketToInvoice necesaría para el proceso de facturación
* Los abonos quedan excluidos en las exportaciones * Los abonos quedan excluidos en las exportaciones
* *
* @param vMaxTicketDate Fecha hasta la cual cogerá tickets para facturar * @param vMaxTicketDate Fecha hasta la cual cogerá tickets para facturar
@ -56467,8 +56467,8 @@ BEGIN
SET vMinTicketDate = util.firstDayOfYear(vMaxTicketDate - INTERVAL 1 YEAR); SET vMinTicketDate = util.firstDayOfYear(vMaxTicketDate - INTERVAL 1 YEAR);
SET vMaxTicketDate = util.dayend(vMaxTicketDate); SET vMaxTicketDate = util.dayend(vMaxTicketDate);
DROP TEMPORARY TABLE IF EXISTS `ticketToInvoice`; DROP TEMPORARY TABLE IF EXISTS `tmp`.`ticketToInvoice`;
CREATE TEMPORARY TABLE `ticketToInvoice` CREATE TEMPORARY TABLE `tmp`.`ticketToInvoice`
(PRIMARY KEY (`id`)) (PRIMARY KEY (`id`))
ENGINE = MEMORY ENGINE = MEMORY
SELECT t.id SELECT t.id
@ -56503,7 +56503,7 @@ CREATE DEFINER=`root`@`localhost` PROCEDURE `invoiceOut_new`(
BEGIN BEGIN
/** /**
* Creación de facturas emitidas. * Creación de facturas emitidas.
* requiere previamente tabla ticketToInvoice(id). * requiere previamente tabla tmp.ticketToInvoice(id).
* *
* @param vSerial serie a la cual se hace la factura * @param vSerial serie a la cual se hace la factura
* @param vInvoiceDate fecha de la factura * @param vInvoiceDate fecha de la factura
@ -56531,13 +56531,13 @@ BEGIN
SELECT t.clientFk, t.companyFk SELECT t.clientFk, t.companyFk
INTO vClientFk, vCompanyFk INTO vClientFk, vCompanyFk
FROM ticketToInvoice tt FROM tmp.ticketToInvoice tt
JOIN ticket t ON t.id = tt.id JOIN ticket t ON t.id = tt.id
LIMIT 1; LIMIT 1;
-- Eliminem de ticketToInvoice els tickets que no han de ser facturats -- Eliminem de tmp.ticketToInvoice els tickets que no han de ser facturats
DELETE ti.* DELETE ti.*
FROM ticketToInvoice ti FROM tmp.ticketToInvoice ti
JOIN ticket t ON t.id = ti.id JOIN ticket t ON t.id = ti.id
JOIN sale s ON s.ticketFk = t.id JOIN sale s ON s.ticketFk = t.id
JOIN item i ON i.id = s.itemFk JOIN item i ON i.id = s.itemFk
@ -56552,7 +56552,7 @@ BEGIN
SELECT SUM(s.quantity * s.price * (100 - s.discount)/100), ts.id SELECT SUM(s.quantity * s.price * (100 - s.discount)/100), ts.id
INTO vIsAnySaleToInvoice, vIsAnyServiceToInvoice INTO vIsAnySaleToInvoice, vIsAnyServiceToInvoice
FROM ticketToInvoice t FROM tmp.ticketToInvoice t
LEFT JOIN sale s ON s.ticketFk = t.id LEFT JOIN sale s ON s.ticketFk = t.id
LEFT JOIN ticketService ts ON ts.ticketFk = t.id; LEFT JOIN ticketService ts ON ts.ticketFk = t.id;
@ -56593,13 +56593,13 @@ BEGIN
WHERE id = vNewInvoiceId; WHERE id = vNewInvoiceId;
UPDATE ticket t UPDATE ticket t
JOIN ticketToInvoice ti ON ti.id = t.id JOIN tmp.ticketToInvoice ti ON ti.id = t.id
SET t.refFk = vNewRef; SET t.refFk = vNewRef;
DROP TEMPORARY TABLE IF EXISTS tmp.updateInter; DROP TEMPORARY TABLE IF EXISTS tmp.updateInter;
CREATE TEMPORARY TABLE tmp.updateInter ENGINE = MEMORY CREATE TEMPORARY TABLE tmp.updateInter ENGINE = MEMORY
SELECT s.id,ti.id ticket_id,vWorker Id_Trabajador SELECT s.id,ti.id ticket_id,vWorker Id_Trabajador
FROM ticketToInvoice ti FROM tmp.ticketToInvoice ti
LEFT JOIN ticketState ts ON ti.id = ts.ticket LEFT JOIN ticketState ts ON ti.id = ts.ticket
JOIN state s JOIN state s
WHERE IFNULL(ts.alertLevel,0) < 3 and s.`code` = getAlert3State(ti.id); WHERE IFNULL(ts.alertLevel,0) < 3 and s.`code` = getAlert3State(ti.id);
@ -56609,7 +56609,7 @@ BEGIN
INSERT INTO ticketLog (action, userFk, originFk, description) INSERT INTO ticketLog (action, userFk, originFk, description)
SELECT 'UPDATE', account.myUser_getId(), ti.id, CONCAT('Crea factura ', vNewRef) SELECT 'UPDATE', account.myUser_getId(), ti.id, CONCAT('Crea factura ', vNewRef)
FROM ticketToInvoice ti; FROM tmp.ticketToInvoice ti;
CALL invoiceExpenceMake(vNewInvoiceId); CALL invoiceExpenceMake(vNewInvoiceId);
CALL invoiceTaxMake(vNewInvoiceId,vTaxArea); CALL invoiceTaxMake(vNewInvoiceId,vTaxArea);
@ -56647,7 +56647,7 @@ BEGIN
(KEY (ticketFk)) (KEY (ticketFk))
ENGINE = MEMORY ENGINE = MEMORY
SELECT id ticketFk SELECT id ticketFk
FROM ticketToInvoice; FROM tmp.ticketToInvoice;
CALL `ticket_getTax`('NATIONAL'); CALL `ticket_getTax`('NATIONAL');
@ -56725,7 +56725,7 @@ BEGIN
DROP TEMPORARY TABLE tmp.ticketServiceTax; DROP TEMPORARY TABLE tmp.ticketServiceTax;
END IF; END IF;
END IF; END IF;
DROP TEMPORARY TABLE `ticketToInvoice`; DROP TEMPORARY TABLE `tmp`.`ticketToInvoice`;
END ;; END ;;
DELIMITER ; DELIMITER ;
/*!50003 SET sql_mode = @saved_sql_mode */ ; /*!50003 SET sql_mode = @saved_sql_mode */ ;
@ -56876,7 +56876,7 @@ BEGIN
(KEY (ticketFk)) (KEY (ticketFk))
ENGINE = MEMORY ENGINE = MEMORY
SELECT id ticketFk SELECT id ticketFk
FROM ticketToInvoice; FROM tmp.ticketToInvoice;
CALL ticket_getTax(vTaxArea); CALL ticket_getTax(vTaxArea);
@ -68689,7 +68689,7 @@ DELIMITER ;
/*!50003 SET character_set_client = @saved_cs_client */ ; /*!50003 SET character_set_client = @saved_cs_client */ ;
/*!50003 SET character_set_results = @saved_cs_results */ ; /*!50003 SET character_set_results = @saved_cs_results */ ;
/*!50003 SET collation_connection = @saved_col_connection */ ; /*!50003 SET collation_connection = @saved_col_connection */ ;
/*!50003 DROP PROCEDURE IF EXISTS `ticketToInvoiceByAddress` */; /*!50003 DROP PROCEDURE IF EXISTS `tmp`.`ticketToInvoiceByAddress` */;
/*!50003 SET @saved_cs_client = @@character_set_client */ ; /*!50003 SET @saved_cs_client = @@character_set_client */ ;
/*!50003 SET @saved_cs_results = @@character_set_results */ ; /*!50003 SET @saved_cs_results = @@character_set_results */ ;
/*!50003 SET @saved_col_connection = @@collation_connection */ ; /*!50003 SET @saved_col_connection = @@collation_connection */ ;
@ -68709,9 +68709,9 @@ BEGIN
SET vEnded = util.dayEnd(vEnded); SET vEnded = util.dayEnd(vEnded);
DROP TEMPORARY TABLE IF EXISTS vn.ticketToInvoice; DROP TEMPORARY TABLE IF EXISTS tmp.ticketToInvoice;
CREATE TEMPORARY TABLE vn.ticketToInvoice CREATE TEMPORARY TABLE tmp.ticketToInvoice
SELECT id SELECT id
FROM vn.ticket FROM vn.ticket
WHERE addressFk = vAddress WHERE addressFk = vAddress
@ -68745,9 +68745,9 @@ BEGIN
SET vEnded = util.dayEnd(vEnded); SET vEnded = util.dayEnd(vEnded);
DROP TEMPORARY TABLE IF EXISTS vn.ticketToInvoice; DROP TEMPORARY TABLE IF EXISTS tmp.ticketToInvoice;
CREATE TEMPORARY TABLE vn.ticketToInvoice CREATE TEMPORARY TABLE tmp.ticketToInvoice
SELECT id SELECT id
FROM vn.ticket FROM vn.ticket
WHERE clientFk = vClient WHERE clientFk = vClient
@ -68808,9 +68808,9 @@ BEGIN
JOIN vn.client c ON c.id = io.clientFk JOIN vn.client c ON c.id = io.clientFk
WHERE io.id = vInvoice; WHERE io.id = vInvoice;
DROP TEMPORARY TABLE IF EXISTS vn.ticketToInvoice; DROP TEMPORARY TABLE IF EXISTS tmp.ticketToInvoice;
CREATE TEMPORARY TABLE vn.ticketToInvoice CREATE TEMPORARY TABLE tmp.ticketToInvoice
SELECT id SELECT id
FROM vn.ticket FROM vn.ticket
WHERE refFk = vInvoiceRef; WHERE refFk = vInvoiceRef;

View File

@ -68,6 +68,7 @@ TABLES=(
time time
volumeConfig volumeConfig
workCenter workCenter
companyI18n
) )
dump_tables ${TABLES[@]} dump_tables ${TABLES[@]}

View File

@ -156,14 +156,14 @@ let actions = {
await this.waitForSpinnerLoad(); await this.waitForSpinnerLoad();
}, },
accessToSection: async function(state) { accessToSection: async function(state, name = 'Others') {
await this.waitForSelector('vn-left-menu'); await this.waitForSelector('vn-left-menu');
let nested = await this.evaluate(state => { let nested = await this.evaluate(state => {
return document.querySelector(`vn-left-menu li li > a[ui-sref="${state}"]`) != null; return document.querySelector(`vn-left-menu li li > a[ui-sref="${state}"]`) != null;
}, state); }, state);
if (nested) { if (nested) {
let selector = 'vn-left-menu vn-item-section > vn-icon[icon=keyboard_arrow_down]'; let selector = `vn-left-menu li[name="${name}"]`;
await this.evaluate(selector => { await this.evaluate(selector => {
document.querySelector(selector).scrollIntoViewIfNeeded(); document.querySelector(selector).scrollIntoViewIfNeeded();
}, selector); }, selector);
@ -414,7 +414,7 @@ let actions = {
const selector = 'vn-snackbar .shape.shown'; const selector = 'vn-snackbar .shape.shown';
await this.waitForSelector(selector); await this.waitForSelector(selector);
let message = await this.evaluate(selector => { const message = await this.evaluate(selector => {
const shape = document.querySelector(selector); const shape = document.querySelector(selector);
const message = { const message = {
text: shape.querySelector('.text').innerText text: shape.querySelector('.text').innerText
@ -431,6 +431,8 @@ let actions = {
return message; return message;
}, selector); }, selector);
message.isSuccess = message.type == 'success';
await this.hideSnackbar(); await this.hideSnackbar();
return message; return message;
}, },
@ -466,28 +468,6 @@ let actions = {
}, selector); }, selector);
}, },
clearInput: async function(selector) {
await this.waitForSelector(selector);
let field = await this.evaluate(selector => {
return document.querySelector(`${selector} input`).closest('.vn-field').$ctrl.field;
}, selector);
if ((field != null && field != '') || field == '0') {
let coords = await this.evaluate(selector => {
let rect = document.querySelector(selector).getBoundingClientRect();
return {x: rect.x + (rect.width / 2), y: rect.y + (rect.height / 2), width: rect.width};
}, selector);
await this.mouse.move(coords.x, coords.y);
await this.waitForSelector(`${selector} [icon="clear"]`, {visible: true});
await this.waitToClick(`${selector} [icon="clear"]`);
}
await this.evaluate(selector => {
return document.querySelector(`${selector} input`).closest('.vn-field').$ctrl.field == '';
}, selector);
},
autocompleteSearch: async function(selector, searchValue) { autocompleteSearch: async function(selector, searchValue) {
let builtSelector = await this.selectorFormater(selector); let builtSelector = await this.selectorFormater(selector);
@ -519,17 +499,15 @@ let actions = {
checkboxState: async function(selector) { checkboxState: async function(selector) {
await this.waitForSelector(selector); await this.waitForSelector(selector);
return this.evaluate(selector => { const value = await this.getInputValue(selector);
let checkbox = document.querySelector(selector); switch (value) {
switch (checkbox.$ctrl.field) { case null:
case null: return 'intermediate';
return 'intermediate'; case true:
case true: return 'checked';
return 'checked'; default:
default: return 'unchecked';
return 'unchecked'; }
}
}, selector);
}, },
isDisabled: async function(selector) { isDisabled: async function(selector) {
@ -622,6 +600,138 @@ let actions = {
waitForContentLoaded: async function() { waitForContentLoaded: async function() {
await this.waitForSpinnerLoad(); await this.waitForSpinnerLoad();
},
async getInputValue(selector) {
return this.evaluate(selector => {
const input = document.querySelector(selector);
return input.$ctrl.field;
}, selector);
},
async getValue(selector) {
return await this.waitToGetProperty(selector, 'value');
},
async innerText(selector) {
const element = await this.$(selector);
const handle = await element.getProperty('innerText');
return handle.jsonValue();
},
async setInput(selector, value) {
const input = await this.$(selector);
const tagName = (await input.evaluate(e => e.tagName)).toLowerCase();
switch (tagName) {
case 'vn-textfield':
case 'vn-datalist':
case 'vn-input-number':
await this.clearInput(selector);
if (value)
await this.write(selector, value.toString());
break;
case 'vn-autocomplete':
if (value)
await this.autocompleteSearch(selector, value.toString());
else
await this.clearInput(selector);
break;
case 'vn-date-picker':
if (value)
await this.pickDate(selector, value);
else
await this.clearInput(selector);
break;
case 'vn-input-time':
if (value)
await this.pickTime(selector, value);
else
await this.clearInput(selector);
break;
case 'vn-check':
for (let i = 0; i < 3; i++) {
if (await this.getInput(selector) == value) break;
await this.click(selector);
}
break;
}
},
async getInput(selector) {
const input = await this.$(selector);
const tagName = (await input.evaluate(e => e.tagName)).toLowerCase();
let el;
let value;
switch (tagName) {
case 'vn-textfield':
case 'vn-autocomplete':
case 'vn-input-time':
case 'vn-datalist':
el = await input.$('input');
value = await el.getProperty('value');
return value.jsonValue();
case 'vn-check':
case 'vn-input-number':
return await this.getInputValue(selector);
case 'vn-textarea':
el = await input.$('textarea');
value = await el.getProperty('value');
return value.jsonValue();
case 'vn-date-picker':
el = await input.$('input');
value = await el.getProperty('value');
if (value) {
const date = new Date(await value.jsonValue());
date.setUTCHours(0, 0, 0, 0);
return date;
} else
return null;
default:
value = await this.innerText(selector);
return value.jsonValue();
}
},
async clearInput(selector) {
await this.waitForSelector(selector);
let field = await this.evaluate(selector => {
return document.querySelector(`${selector} input`).closest('.vn-field').$ctrl.field;
}, selector);
if ((field != null && field != '') || field == '0') {
let coords = await this.evaluate(selector => {
let rect = document.querySelector(selector).getBoundingClientRect();
return {x: rect.x + (rect.width / 2), y: rect.y + (rect.height / 2), width: rect.width};
}, selector);
await this.mouse.move(coords.x, coords.y);
await this.waitForSelector(`${selector} [icon="clear"]`, {visible: true});
await this.waitToClick(`${selector} [icon="clear"]`);
}
await this.evaluate(selector => {
return document.querySelector(`${selector} input`).closest('.vn-field').$ctrl.field == '';
}, selector);
},
async fetchForm(selector, inputNames) {
const values = {};
for (const inputName of inputNames)
values[inputName] = await this.getInput(`${selector} [vn-name="${inputName}"]`);
return values;
},
async fillForm(selector, values) {
for (const inputName in values)
await this.setInput(`${selector} [vn-name="${inputName}"]`, values[inputName]);
},
async sendForm(selector, values) {
if (values) await this.fillForm(selector, values);
await this.click(`${selector} button[type=submit]`);
return await this.waitForSnackbar();
} }
}; };
@ -629,12 +739,14 @@ export function extendPage(page) {
for (let name in actions) { for (let name in actions) {
page[name] = async(...args) => { page[name] = async(...args) => {
try { try {
return actions[name].apply(page, args); return await actions[name].apply(page, args);
} catch (err) { } catch (err) {
let stringArgs = args let stringArgs = args
.map(i => typeof i == 'function' ? 'Function' : i) .map(i => typeof i == 'function' ? 'Function' : `'${i}'`)
.join(', '); .join(', ');
throw new Error(`.${name}(${stringArgs}): ${err.message}`); const myErr = new Error(`${err.message}\n at Page.${name}(${stringArgs})`);
myErr.stack = err.stack;
throw myErr;
} }
}; };
} }

View File

@ -193,10 +193,6 @@ export default {
saveNewPoscode: '#savePostcode', saveNewPoscode: '#savePostcode',
createButton: 'vn-client-create button[type=submit]' createButton: 'vn-client-create button[type=submit]'
}, },
clientDescriptor: {
moreMenu: 'vn-client-descriptor vn-icon-button[icon=more_vert]',
simpleTicketButton: '.vn-menu [name="simpleTicket"]'
},
clientBasicData: { clientBasicData: {
name: 'vn-client-basic-data vn-textfield[ng-model="$ctrl.client.name"]', name: 'vn-client-basic-data vn-textfield[ng-model="$ctrl.client.name"]',
contact: 'vn-client-basic-data vn-textfield[ng-model="$ctrl.client.contact"]', contact: 'vn-client-basic-data vn-textfield[ng-model="$ctrl.client.contact"]',
@ -231,23 +227,6 @@ export default {
saveButton: 'button[type=submit]', saveButton: 'button[type=submit]',
watcher: 'vn-client-fiscal-data vn-watcher' watcher: 'vn-client-fiscal-data vn-watcher'
}, },
clientBillingData: {
payMethod: 'vn-client-billing-data vn-autocomplete[ng-model="$ctrl.client.payMethodFk"]',
IBAN: 'vn-client-billing-data vn-textfield[ng-model="$ctrl.client.iban"]',
dueDay: 'vn-client-billing-data vn-input-number[ng-model="$ctrl.client.dueDay"]',
receivedCoreLCRCheckbox: 'vn-client-billing-data vn-check[label="Received LCR"]',
receivedCoreVNLCheckbox: 'vn-client-billing-data vn-check[label="Received core VNL"]',
receivedB2BVNLCheckbox: 'vn-client-billing-data vn-check[label="Received B2B VNL"]',
swiftBic: 'vn-client-billing-data vn-autocomplete[ng-model="$ctrl.client.bankEntityFk"]',
newBankEntityButton: 'vn-client-billing-data vn-icon-button[vn-tooltip="New bank entity"] > button',
newBankEntityName: '.vn-dialog.shown vn-textfield[ng-model="$ctrl.data.name"]',
newBankEntityBIC: '.vn-dialog.shown vn-textfield[ng-model="$ctrl.data.bic"]',
newBankEntityCountry: '.vn-dialog.shown vn-autocomplete[ng-model="$ctrl.data.countryFk"]',
newBankEntityCode: '.vn-dialog.shown vn-textfield[ng-model="$ctrl.data.id"]',
acceptBankEntityButton: '.vn-dialog.shown button[response="accept"]',
saveButton: 'vn-client-billing-data button[type=submit]',
watcher: 'vn-client-billing-data vn-watcher'
},
clientAddresses: { clientAddresses: {
addressesButton: 'vn-left-menu a[ui-sref="client.card.address.index"]', addressesButton: 'vn-left-menu a[ui-sref="client.card.address.index"]',
createAddress: 'vn-client-address-index vn-float-button', createAddress: 'vn-client-address-index vn-float-button',
@ -283,12 +262,6 @@ export default {
cancelEditAddressButton: 'vn-client-address-edit > form > vn-button-bar > vn-button > button', cancelEditAddressButton: 'vn-client-address-edit > form > vn-button-bar > vn-button > button',
watcher: 'vn-client-address-edit vn-watcher' watcher: 'vn-client-address-edit vn-watcher'
}, },
clientWebAccess: {
enableWebAccessCheckbox: 'vn-check[label="Enable web access"]',
userName: 'vn-client-web-access vn-textfield[ng-model="$ctrl.account.name"]',
email: 'vn-client-web-access vn-textfield[ng-model="$ctrl.account.email"]',
saveButton: 'button[type=submit]'
},
clientNotes: { clientNotes: {
addNoteFloatButton: 'vn-float-button', addNoteFloatButton: 'vn-float-button',
note: 'vn-textarea[ng-model="$ctrl.note.text"]', note: 'vn-textarea[ng-model="$ctrl.note.text"]',
@ -312,30 +285,6 @@ export default {
clientMandate: { clientMandate: {
firstMandateText: 'vn-client-mandate vn-card vn-table vn-tbody > vn-tr' firstMandateText: 'vn-client-mandate vn-card vn-table vn-tbody > vn-tr'
}, },
clientLog: {
lastModificationPreviousValue: 'vn-client-log vn-tr table tr td.before',
lastModificationCurrentValue: 'vn-client-log vn-tr table tr td.after',
namePreviousValue: 'vn-client-log vn-tr table tr:nth-child(1) td.before',
nameCurrentValue: 'vn-client-log vn-tr table tr:nth-child(1) td.after',
activePreviousValue: 'vn-client-log vn-tr:nth-child(2) table tr:nth-child(2) td.before',
activeCurrentValue: 'vn-client-log vn-tr:nth-child(2) table tr:nth-child(2) td.after'
},
clientBalance: {
company: 'vn-client-balance-index vn-autocomplete[ng-model="$ctrl.companyId"]',
newPaymentButton: `vn-float-button`,
newPaymentBank: '.vn-dialog.shown vn-autocomplete[ng-model="$ctrl.bankFk"]',
newPaymentAmount: '.vn-dialog.shown vn-input-number[ng-model="$ctrl.amountPaid"]',
newDescription: 'vn-textfield[ng-model="$ctrl.receipt.description"]',
deliveredAmount: '.vn-dialog vn-input-number[ng-model="$ctrl.deliveredAmount"]',
refundAmount: '.vn-dialog vn-input-number[ng-model="$ctrl.amountToReturn"]',
saveButton: '.vn-dialog.shown [response="accept"]',
anyBalanceLine: 'vn-client-balance-index vn-tbody > vn-tr',
firstLineBalance: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(8)',
firstLineReference: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td-editable',
firstLineReferenceInput: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td-editable > div > field > vn-textfield',
compensationButton: 'vn-client-balance-index vn-icon-button[vn-dialog="send_compensation"]'
},
webPayment: { webPayment: {
confirmFirstPaymentButton: 'vn-client-web-payment vn-tr:nth-child(1) vn-icon-button[icon="done_all"]', confirmFirstPaymentButton: 'vn-client-web-payment vn-tr:nth-child(1) vn-icon-button[icon="done_all"]',
firstPaymentConfirmed: 'vn-client-web-payment vn-tr:nth-child(1) vn-icon[icon="check"]' firstPaymentConfirmed: 'vn-client-web-payment vn-tr:nth-child(1) vn-icon[icon="check"]'
@ -414,7 +363,7 @@ export default {
saveFieldsButton: '.vn-popover.shown vn-button[label="Save"] > button' saveFieldsButton: '.vn-popover.shown vn-button[label="Save"] > button'
}, },
itemFixedPrice: { itemFixedPrice: {
add: 'vn-fixed-price vn-icon-button[icon="add_circle"]', add: 'vn-fixed-price vn-icon-button[vn-tooltip="Add fixed price"]',
firstItemID: 'vn-fixed-price tr:nth-child(2) vn-autocomplete[ng-model="price.itemFk"]', firstItemID: 'vn-fixed-price tr:nth-child(2) vn-autocomplete[ng-model="price.itemFk"]',
fourthFixedPrice: 'vn-fixed-price tr:nth-child(5)', fourthFixedPrice: 'vn-fixed-price tr:nth-child(5)',
fourthItemID: 'vn-fixed-price tr:nth-child(5) vn-autocomplete[ng-model="price.itemFk"]', fourthItemID: 'vn-fixed-price tr:nth-child(5) vn-autocomplete[ng-model="price.itemFk"]',
@ -426,7 +375,19 @@ export default {
fourthStarted: 'vn-fixed-price tr:nth-child(5) vn-date-picker[ng-model="price.started"]', fourthStarted: 'vn-fixed-price tr:nth-child(5) vn-date-picker[ng-model="price.started"]',
fourthEnded: 'vn-fixed-price tr:nth-child(5) vn-date-picker[ng-model="price.ended"]', fourthEnded: 'vn-fixed-price tr:nth-child(5) vn-date-picker[ng-model="price.ended"]',
fourthDeleteIcon: 'vn-fixed-price tr:nth-child(5) > td:nth-child(9) > vn-icon-button[icon="delete"]', fourthDeleteIcon: 'vn-fixed-price tr:nth-child(5) > td:nth-child(9) > vn-icon-button[icon="delete"]',
orderColumnId: 'vn-fixed-price th[field="itemFk"]' orderColumnId: 'vn-fixed-price th[field="itemFk"]',
removeWarehouseFilter: 'vn-searchbar > form > vn-textfield > div.container > div.prepend > prepend > div > span:nth-child(1) > vn-icon > i',
generalSearchFilter: 'vn-fixed-price-search-panel vn-textfield[ng-model="$ctrl.filter.search"]',
reignFilter: 'vn-fixed-price-search-panel vn-horizontal.item-category vn-one',
typeFilter: 'vn-fixed-price-search-panel vn-autocomplete[ng-model="$ctrl.filter.typeFk"]',
buyerFilter: 'vn-fixed-price-search-panel vn-autocomplete[ng-model="$ctrl.filter.buyerFk"]',
warehouseFilter: 'vn-fixed-price-search-panel vn-autocomplete[ng-model="$ctrl.filter.warehouseFk"]',
mineFilter: 'vn-fixed-price-search-panel vn-check[ng-model="$ctrl.filter.mine"]',
hasMinPriceFilter: 'vn-fixed-price-search-panel vn-check[ng-model="$ctrl.filter.hasMinPrice"]',
addTag: 'vn-fixed-price-search-panel vn-icon-button[icon="add_circle"]',
tagFilter: 'vn-fixed-price-search-panel vn-autocomplete[ng-model="itemTag.tagFk"]',
tagValueFilter: 'vn-fixed-price-search-panel vn-autocomplete[ng-model="itemTag.value"]',
chip: 'vn-fixed-price-search-panel vn-chip > vn-icon'
}, },
itemCreateView: { itemCreateView: {
temporalName: 'vn-item-create vn-textfield[ng-model="$ctrl.item.provisionalName"]', temporalName: 'vn-item-create vn-textfield[ng-model="$ctrl.item.provisionalName"]',
@ -469,10 +430,6 @@ export default {
packingOut: 'vn-input-number[ng-model="$ctrl.item.packingOut"]', packingOut: 'vn-input-number[ng-model="$ctrl.item.packingOut"]',
isActiveCheckbox: 'vn-check[label="Active"]', isActiveCheckbox: 'vn-check[label="Active"]',
priceInKgCheckbox: 'vn-check[label="Price in kg"]', priceInKgCheckbox: 'vn-check[label="Price in kg"]',
newIntrastatButton: 'vn-item-basic-data vn-icon-button[vn-tooltip="New intrastat"] > button',
newIntrastatId: '.vn-dialog.shown vn-input-number[ng-model="$ctrl.newIntrastat.intrastatId"]',
newIntrastatDescription: '.vn-dialog.shown vn-textfield[ng-model="$ctrl.newIntrastat.description"]',
acceptIntrastatButton: '.vn-dialog.shown button[response="accept"]',
submitBasicDataButton: `button[type=submit]` submitBasicDataButton: `button[type=submit]`
}, },
itemTags: { itemTags: {
@ -524,7 +481,6 @@ export default {
}, },
itemLog: { itemLog: {
anyLineCreated: 'vn-item-log > vn-log vn-tbody > vn-tr', anyLineCreated: 'vn-item-log > vn-log vn-tbody > vn-tr',
fifthLineCreatedProperty: 'vn-item-log > vn-log vn-tbody > vn-tr:nth-child(5) table tr:nth-child(5) td.after',
}, },
ticketSummary: { ticketSummary: {
header: 'vn-ticket-summary > vn-card > h5', header: 'vn-ticket-summary > vn-card > h5',
@ -626,13 +582,6 @@ export default {
saveButton: '.vn-dialog.shown [response="accept"]', saveButton: '.vn-dialog.shown [response="accept"]',
expeditionRow: 'vn-ticket-expedition vn-table vn-tbody > vn-tr' expeditionRow: 'vn-ticket-expedition vn-table vn-tbody > vn-tr'
}, },
ticketPackages: {
firstPackage: 'vn-autocomplete[label="Package"]',
firstQuantity: 'vn-ticket-package vn-horizontal:nth-child(1) vn-input-number[ng-model="package.quantity"]',
firstRemovePackageButton: 'vn-icon-button[vn-tooltip="Remove package"]',
addPackageButton: 'vn-icon-button[vn-tooltip="Add package"]',
savePackagesButton: `button[type=submit]`
},
ticketSales: { ticketSales: {
setOk: 'vn-ticket-sale vn-tool-bar > vn-button[label="Ok"] > button', setOk: 'vn-ticket-sale vn-tool-bar > vn-button[label="Ok"] > button',
saleLine: 'vn-table div > vn-tbody > vn-tr vn-check', saleLine: 'vn-table div > vn-tbody > vn-tr vn-check',
@ -744,6 +693,7 @@ export default {
anyDocument: 'vn-ticket-dms-index > vn-data-viewer vn-tbody vn-tr' anyDocument: 'vn-ticket-dms-index > vn-data-viewer vn-tbody vn-tr'
}, },
ticketFuture: { ticketFuture: {
searchResult: 'vn-ticket-future tbody tr',
openAdvancedSearchButton: 'vn-searchbar .append vn-icon[icon="arrow_drop_down"]', openAdvancedSearchButton: 'vn-searchbar .append vn-icon[icon="arrow_drop_down"]',
originDated: 'vn-date-picker[label="Origin date"]', originDated: 'vn-date-picker[label="Origin date"]',
futureDated: 'vn-date-picker[label="Destination date"]', futureDated: 'vn-date-picker[label="Destination date"]',
@ -759,7 +709,6 @@ export default {
problems: 'vn-check[label="With problems"]', problems: 'vn-check[label="With problems"]',
tableButtonSearch: 'vn-button[vn-tooltip="Search"]', tableButtonSearch: 'vn-button[vn-tooltip="Search"]',
moveButton: 'vn-button[vn-tooltip="Future tickets"]', moveButton: 'vn-button[vn-tooltip="Future tickets"]',
acceptButton: '.vn-confirm.shown button[response="accept"]',
firstCheck: 'tbody > tr:nth-child(1) > td > vn-check', firstCheck: 'tbody > tr:nth-child(1) > td > vn-check',
multiCheck: 'vn-multi-check', multiCheck: 'vn-multi-check',
tableId: 'vn-textfield[name="id"]', tableId: 'vn-textfield[name="id"]',
@ -877,15 +826,6 @@ export default {
landedDatePicker: 'vn-date-picker[label="Landed"]', landedDatePicker: 'vn-date-picker[label="Landed"]',
createButton: 'button[type=submit]' createButton: 'button[type=submit]'
}, },
orderSummary: {
id: 'vn-order-summary vn-one:nth-child(1) > vn-label-value:nth-child(1) span',
alias: 'vn-order-summary vn-one:nth-child(1) > vn-label-value:nth-child(2) span',
consignee: 'vn-order-summary vn-one:nth-child(2) > vn-label-value:nth-child(6) span',
subtotal: 'vn-order-summary vn-one.taxes > p:nth-child(1)',
vat: 'vn-order-summary vn-one.taxes > p:nth-child(2)',
total: 'vn-order-summary vn-one.taxes > p:nth-child(3)',
sale: 'vn-order-summary vn-tbody > vn-tr',
},
orderCatalog: { orderCatalog: {
plantRealmButton: 'vn-order-catalog > vn-side-menu vn-icon[icon="icon-plant"]', plantRealmButton: 'vn-order-catalog > vn-side-menu vn-icon[icon="icon-plant"]',
type: 'vn-order-catalog vn-autocomplete[data="$ctrl.itemTypes"]', type: 'vn-order-catalog vn-autocomplete[data="$ctrl.itemTypes"]',
@ -903,14 +843,6 @@ export default {
fifthFilterRemoveButton: 'vn-order-catalog > vn-side-menu .chips > vn-chip:nth-child(5) vn-icon[icon=cancel]', fifthFilterRemoveButton: 'vn-order-catalog > vn-side-menu .chips > vn-chip:nth-child(5) vn-icon[icon=cancel]',
sixthFilterRemoveButton: 'vn-order-catalog > vn-side-menu .chips > vn-chip:nth-child(6) vn-icon[icon=cancel]', sixthFilterRemoveButton: 'vn-order-catalog > vn-side-menu .chips > vn-chip:nth-child(6) vn-icon[icon=cancel]',
}, },
orderBasicData: {
client: 'vn-autocomplete[label="Client"]',
address: 'vn-autocomplete[label="Address"]',
agency: 'vn-autocomplete[label="Agency"]',
observation: 'vn-textarea[label="Notes"]',
saveButton: `button[type=submit]`,
acceptButton: '.vn-confirm.shown button[response="accept"]'
},
orderLine: { orderLine: {
orderSubtotal: 'vn-order-line .header :first-child', orderSubtotal: 'vn-order-line .header :first-child',
firstLineDeleteButton: 'vn-order-line vn-tbody > vn-tr:nth-child(1) vn-icon[icon="delete"]', firstLineDeleteButton: 'vn-order-line vn-tbody > vn-tr:nth-child(1) vn-icon[icon="delete"]',
@ -950,16 +882,6 @@ export default {
goToRouteSummaryButton: 'vn-route-summary > vn-card > h5 > a', goToRouteSummaryButton: 'vn-route-summary > vn-card > h5 > a',
}, },
routeBasicData: {
worker: 'vn-route-basic-data vn-autocomplete[ng-model="$ctrl.route.workerFk"]',
vehicle: 'vn-route-basic-data vn-autocomplete[ng-model="$ctrl.route.vehicleFk"]',
kmStart: 'vn-route-basic-data vn-input-number[ng-model="$ctrl.route.kmStart"]',
kmEnd: 'vn-route-basic-data vn-input-number[ng-model="$ctrl.route.kmEnd"]',
createdDate: 'vn-route-basic-data vn-date-picker[ng-model="$ctrl.route.created"]',
startedHour: 'vn-route-basic-data vn-input-time[ng-model="$ctrl.route.started"]',
finishedHour: 'vn-route-basic-data vn-input-time[ng-model="$ctrl.route.finished"]',
saveButton: 'vn-route-basic-data button[type=submit]'
},
routeTickets: { routeTickets: {
firstTicketPriority: 'vn-route-tickets vn-tr:nth-child(1) vn-input-number[ng-model="ticket.priority"]', firstTicketPriority: 'vn-route-tickets vn-tr:nth-child(1) vn-input-number[ng-model="ticket.priority"]',
firstTicketCheckbox: 'vn-route-tickets vn-tr:nth-child(1) vn-check', firstTicketCheckbox: 'vn-route-tickets vn-tr:nth-child(1) vn-check',
@ -988,6 +910,12 @@ export default {
locker: 'vn-worker-basic-data vn-input-number[ng-model="$ctrl.worker.locker"]', locker: 'vn-worker-basic-data vn-input-number[ng-model="$ctrl.worker.locker"]',
saveButton: 'vn-worker-basic-data button[type=submit]' saveButton: 'vn-worker-basic-data button[type=submit]'
}, },
workerNotes: {
addNoteFloatButton: 'vn-worker-note vn-icon[icon="add"]',
note: 'vn-note-worker-create vn-textarea[ng-model="$ctrl.note.text"]',
saveButton: 'vn-note-worker-create button[type=submit]',
firstNoteText: 'vn-worker-note .text'
},
workerPbx: { workerPbx: {
extension: 'vn-worker-pbx vn-textfield[ng-model="$ctrl.worker.sip.extension"]', extension: 'vn-worker-pbx vn-textfield[ng-model="$ctrl.worker.sip.extension"]',
saveButton: 'vn-worker-pbx button[type=submit]' saveButton: 'vn-worker-pbx button[type=submit]'
@ -1128,6 +1056,15 @@ export default {
saveButton: 'vn-invoice-in-tax vn-submit', saveButton: 'vn-invoice-in-tax vn-submit',
}, },
invoiceInIndex: {
topbarSearchParams: 'vn-searchbar div.search-params > span',
},
invoiceInSerial: {
daysAgo: 'vn-invoice-in-serial-search-panel vn-input-number[ng-model="$ctrl.filter.daysAgo"]',
serial: 'vn-invoice-in-serial-search-panel vn-textfield[ng-model="$ctrl.filter.serial"]',
chip: 'vn-chip > vn-icon',
goToIndex: 'vn-invoice-in-serial vn-icon-button[icon="icon-invoice-in"]',
},
travelIndex: { travelIndex: {
anySearchResult: 'vn-travel-index vn-tbody > a', anySearchResult: 'vn-travel-index vn-tbody > a',
firstSearchResult: 'vn-travel-index vn-tbody > a:nth-child(1)', firstSearchResult: 'vn-travel-index vn-tbody > a:nth-child(1)',
@ -1139,7 +1076,16 @@ export default {
landingDate: 'vn-travel-create vn-date-picker[ng-model="$ctrl.travel.landed"]', landingDate: 'vn-travel-create vn-date-picker[ng-model="$ctrl.travel.landed"]',
warehouseOut: 'vn-travel-create vn-autocomplete[ng-model="$ctrl.travel.warehouseOutFk"]', warehouseOut: 'vn-travel-create vn-autocomplete[ng-model="$ctrl.travel.warehouseOutFk"]',
warehouseIn: 'vn-travel-create vn-autocomplete[ng-model="$ctrl.travel.warehouseInFk"]', warehouseIn: 'vn-travel-create vn-autocomplete[ng-model="$ctrl.travel.warehouseInFk"]',
save: 'vn-travel-create vn-submit > button' save: 'vn-travel-create vn-submit > button',
generalSearchFilter: 'vn-travel-search-panel vn-textfield[ng-model="$ctrl.search"]',
agencyFilter: 'vn-travel-search-panel vn-autocomplete[ng-model="$ctrl.filter.agencyModeFk"]',
warehouseOutFilter: 'vn-travel-search-panel vn-autocomplete[ng-model="$ctrl.filter.warehouseOutFk"]',
warehouseInFilter: 'vn-travel-search-panel vn-autocomplete[ng-model="$ctrl.filter.warehouseInFk"]',
scopeDaysFilter: 'vn-travel-search-panel vn-input-number[ng-model="$ctrl.filter.scopeDays"]',
continentFilter: 'vn-travel-search-panel vn-autocomplete[ng-model="$ctrl.filter.continent"]',
totalEntriesFilter: 'vn-travel-search-panel vn-input-number[ng-model="$ctrl.totalEntries"]',
chip: 'vn-travel-search-panel vn-chip > vn-icon',
}, },
travelExtraCommunity: { travelExtraCommunity: {
anySearchResult: 'vn-travel-extra-community > vn-card div > tbody > tr[ng-attr-id="{{::travel.id}}"]', anySearchResult: 'vn-travel-extra-community > vn-card div > tbody > tr[ng-attr-id="{{::travel.id}}"]',
@ -1220,22 +1166,6 @@ export default {
confirmed: 'vn-entry-summary vn-check[label="Confirmed"]', confirmed: 'vn-entry-summary vn-check[label="Confirmed"]',
anyBuyLine: 'vn-entry-summary tr.dark-row' anyBuyLine: 'vn-entry-summary tr.dark-row'
}, },
entryBasicData: {
reference: 'vn-entry-basic-data vn-textfield[ng-model="$ctrl.entry.reference"]',
invoiceNumber: 'vn-entry-basic-data vn-textfield[ng-model="$ctrl.entry.invoiceNumber"]',
notes: 'vn-entry-basic-data vn-textfield[ng-model="$ctrl.entry.notes"]',
observations: 'vn-entry-basic-data vn-textarea[ng-model="$ctrl.entry.observation"]',
supplier: 'vn-entry-basic-data vn-autocomplete[ng-model="$ctrl.entry.supplierFk"]',
currency: 'vn-entry-basic-data vn-autocomplete[ng-model="$ctrl.entry.currencyFk"]',
commission: 'vn-entry-basic-data vn-input-number[ng-model="$ctrl.entry.commission"]',
company: 'vn-entry-basic-data vn-autocomplete[ng-model="$ctrl.entry.companyFk"]',
ordered: 'vn-entry-basic-data vn-check[ng-model="$ctrl.entry.isOrdered"]',
confirmed: 'vn-entry-basic-data vn-check[ng-model="$ctrl.entry.isConfirmed"]',
inventory: 'vn-entry-basic-data vn-check[ng-model="$ctrl.entry.isExcludedFromAvailable"]',
raid: 'vn-entry-basic-data vn-check[ng-model="$ctrl.entry.isRaid"]',
booked: 'vn-entry-basic-data vn-check[ng-model="$ctrl.entry.isBooked"]',
save: 'vn-entry-basic-data button[type=submit]',
},
entryDescriptor: { entryDescriptor: {
agency: 'vn-entry-descriptor div.body vn-label-value:nth-child(1) span', agency: 'vn-entry-descriptor div.body vn-label-value:nth-child(1) span',
travelsQuicklink: 'vn-entry-descriptor vn-quick-link[icon="local_airport"] > a', travelsQuicklink: 'vn-entry-descriptor vn-quick-link[icon="local_airport"] > a',
@ -1326,18 +1256,6 @@ export default {
notes: 'vn-supplier-basic-data vn-textarea[ng-model="$ctrl.supplier.note"]', notes: 'vn-supplier-basic-data vn-textarea[ng-model="$ctrl.supplier.note"]',
saveButton: 'vn-supplier-basic-data button[type="submit"]', saveButton: 'vn-supplier-basic-data button[type="submit"]',
}, },
supplierFiscalData: {
socialName: 'vn-supplier-fiscal-data vn-textfield[ng-model="$ctrl.supplier.name"]',
taxNumber: 'vn-supplier-fiscal-data vn-textfield[ng-model="$ctrl.supplier.nif"]',
account: 'vn-supplier-fiscal-data vn-textfield[ng-model="$ctrl.supplier.account"]',
sageTaxType: 'vn-supplier-fiscal-data vn-autocomplete[ng-model="$ctrl.supplier.sageTaxTypeFk"]',
sageWihholding: 'vn-supplier-fiscal-data vn-autocomplete[ng-model="$ctrl.supplier.sageWithholdingFk"]',
postCode: 'vn-supplier-fiscal-data vn-datalist[ng-model="$ctrl.supplier.postCode"]',
city: 'vn-supplier-fiscal-data vn-datalist[ng-model="$ctrl.supplier.city"]',
province: 'vn-supplier-fiscal-data vn-autocomplete[ng-model="$ctrl.supplier.provinceFk"]',
country: 'vn-supplier-fiscal-data vn-autocomplete[ng-model="$ctrl.supplier.countryFk"]',
saveButton: 'vn-supplier-fiscal-data button[type="submit"]',
},
supplierBillingData: { supplierBillingData: {
payMethod: 'vn-supplier-billing-data vn-autocomplete[ng-model="$ctrl.supplier.payMethodFk"]', payMethod: 'vn-supplier-billing-data vn-autocomplete[ng-model="$ctrl.supplier.payMethodFk"]',
payDem: 'vn-supplier-billing-data vn-autocomplete[ng-model="$ctrl.supplier.payDemFk"]', payDem: 'vn-supplier-billing-data vn-autocomplete[ng-model="$ctrl.supplier.payDemFk"]',

Some files were not shown because too many files have changed in this diff Show More