This commit is contained in:
Alex Moreno 2023-06-15 07:27:04 +02:00
commit a206f64e3c
295 changed files with 14076 additions and 15831 deletions

View File

@ -1,6 +1,6 @@
extends: [eslint:recommended, google, plugin:jasmine/recommended] extends: [eslint:recommended, google, plugin:jasmine/recommended]
parserOptions: parserOptions:
ecmaVersion: 2018 ecmaVersion: 2020
sourceType: "module" sourceType: "module"
plugins: plugins:
- jasmine - jasmine
@ -35,4 +35,4 @@ rules:
space-in-parens: ["error", "never"] space-in-parens: ["error", "never"]
jasmine/no-focused-tests: 0 jasmine/no-focused-tests: 0
jasmine/prefer-toHaveBeenCalledWith: 0 jasmine/prefer-toHaveBeenCalledWith: 0
arrow-spacing: ["error", { "before": true, "after": true }] arrow-spacing: ["error", { "before": true, "after": true }]

View File

@ -5,6 +5,33 @@ 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).
## [2326.01] - 2023-06-29
### Added
### Changed
### Fixed
-
## [2324.01] - 2023-06-08
### Added
- (Tickets -> Abono) Al abonar permite crear el ticket abono con almacén o sin almmacén
- (General -> Desplegables) Mejorada eficiencia de carga de datos
- (General -> Históricos) Ahora, ademas de los ids, se muestra la descripión de los atributos
- (General -> Históricos) Botón para hacer más ágil mostrar sólo los cambios en un registro
- (General -> Históricos) Filtro por cambios
### Changed
- (General -> Permisos) Mejorada seguridad
- (General -> Históricos) Elementos de la interfaz reorganizados para hacerla más ágil e intuitiva
### Fixed
-
## [2322.01] - 2023-06-01 ## [2322.01] - 2023-06-01
### Added ### Added
@ -14,7 +41,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed ### Changed
- (Trabajadores -> Nuevo trabajador) Los clientes se crean sin 'TR' pero se añade tipo de negocio 'Trabajador' - (Trabajadores -> Nuevo trabajador) Los clientes se crean sin 'TR' pero se añade tipo de negocio 'Trabajador'
- (Tickets -> Expediciones) Interfaz mejorada y contador añadido
### Fixed ### Fixed
- (Tickets -> Líneas) Se permite hacer split de líneas al mismo ticket - (Tickets -> Líneas) Se permite hacer split de líneas al mismo ticket
- (Tickets -> Cambiar estado) Ahora muestra la lista completa de todos los estados - (Tickets -> Cambiar estado) Ahora muestra la lista completa de todos los estados

View File

@ -11,9 +11,9 @@ RUN apt-get update \
ca-certificates \ ca-certificates \
gnupg2 \ gnupg2 \
graphicsmagick \ graphicsmagick \
&& curl -fsSL https://deb.nodesource.com/setup_14.x | bash - \ && curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
&& apt-get install -y --no-install-recommends nodejs \ && apt-get install -y --no-install-recommends nodejs \
&& npm install -g npm@8.19.2 && npm install -g npm@9.6.6
# Puppeteer # Puppeteer

8
Jenkinsfile vendored
View File

@ -39,7 +39,7 @@ pipeline {
NODE_ENV = "" NODE_ENV = ""
} }
steps { steps {
nodejs('node-v14') { nodejs('node-v20') {
sh 'npm install --no-audit --prefer-offline' sh 'npm install --no-audit --prefer-offline'
sh 'gulp install --ci' sh 'gulp install --ci'
} }
@ -57,14 +57,14 @@ pipeline {
parallel { parallel {
stage('Frontend') { stage('Frontend') {
steps { steps {
nodejs('node-v14') { nodejs('node-v20') {
sh 'jest --ci --reporters=default --reporters=jest-junit --maxWorkers=2' sh 'jest --ci --reporters=default --reporters=jest-junit --maxWorkers=2'
} }
} }
} }
stage('Backend') { stage('Backend') {
steps { steps {
nodejs('node-v14') { nodejs('node-v20') {
sh 'npm run test:back:ci' sh 'npm run test:back:ci'
} }
} }
@ -80,7 +80,7 @@ pipeline {
CREDENTIALS = credentials('docker-registry') CREDENTIALS = credentials('docker-registry')
} }
steps { steps {
nodejs('node-v14') { nodejs('node-v20') {
sh 'gulp build' sh 'gulp build'
} }

View File

@ -30,11 +30,11 @@ module.exports = Self => {
Self.newCollection = async(ctx, collectionFk, sectorFk, vWagons) => { Self.newCollection = async(ctx, collectionFk, sectorFk, vWagons) => {
let query = ''; let query = '';
const userId = ctx.req.accessToken.userId;
if (!collectionFk) { if (!collectionFk) {
const userId = ctx.req.accessToken.userId;
query = `CALL vn.collectionTrain_newBeta(?,?,?)`; query = `CALL vn.collectionTrain_newBeta(?,?,?)`;
const [result] = await Self.rawSql(query, [sectorFk, vWagons, userId]); const [result] = await Self.rawSql(query, [sectorFk, vWagons, userId], {userId});
if (result.length == 0) if (result.length == 0)
throw new Error(`No collections for today`); throw new Error(`No collections for today`);
@ -42,16 +42,16 @@ module.exports = Self => {
} }
query = `CALL vn.collectionTicket_get(?)`; query = `CALL vn.collectionTicket_get(?)`;
const [tickets] = await Self.rawSql(query, [collectionFk]); const [tickets] = await Self.rawSql(query, [collectionFk], {userId});
query = `CALL vn.collectionSale_get(?)`; query = `CALL vn.collectionSale_get(?)`;
const [sales] = await Self.rawSql(query, [collectionFk]); const [sales] = await Self.rawSql(query, [collectionFk], {userId});
query = `CALL vn.collectionPlacement_get(?)`; query = `CALL vn.collectionPlacement_get(?)`;
const [placements] = await Self.rawSql(query, [collectionFk]); const [placements] = await Self.rawSql(query, [collectionFk], {userId});
query = `CALL vn.collectionSticker_print(?,?)`; query = `CALL vn.collectionSticker_print(?,?)`;
await Self.rawSql(query, [collectionFk, sectorFk]); await Self.rawSql(query, [collectionFk, sectorFk], {userId});
return makeCollection(tickets, sales, placements, collectionFk); return makeCollection(tickets, sales, placements, collectionFk);
}; };

View File

@ -3,237 +3,237 @@ const path = require('path');
const fs = require('fs-extra'); const fs = require('fs-extra');
module.exports = Self => { module.exports = Self => {
Self.remoteMethodCtx('updateData', { Self.remoteMethodCtx('updateData', {
description: 'Updates schema data from external provider', description: 'Updates schema data from external provider',
accessType: 'WRITE', accessType: 'WRITE',
returns: { returns: {
type: 'object', type: 'object',
root: true root: true
}, },
http: { http: {
path: `/updateData`, path: `/updateData`,
verb: 'POST' verb: 'POST'
} }
}); });
Self.updateData = async() => { Self.updateData = async ctx => {
const models = Self.app.models; const models = Self.app.models;
// Get files checksum // Get files checksum
const tx = await Self.beginTransaction({}); const tx = await Self.beginTransaction({});
try { try {
const options = {transaction: tx}; const options = {transaction: tx, userId: ctx.req.accessToken.userId};
const files = await Self.rawSql('SELECT name, checksum, keyValue FROM edi.fileConfig', null, options); const files = await Self.rawSql('SELECT name, checksum, keyValue FROM edi.fileConfig', null, options);
const updatableFiles = []; const updatableFiles = [];
for (const file of files) { for (const file of files) {
const fileChecksum = await getChecksum(file); const fileChecksum = await getChecksum(file);
if (file.checksum != fileChecksum) { if (file.checksum != fileChecksum) {
updatableFiles.push({ updatableFiles.push({
name: file.name, name: file.name,
checksum: fileChecksum checksum: fileChecksum
}); });
} else } else
console.debug(`File already updated, skipping...`); console.debug(`File already updated, skipping...`);
} }
if (updatableFiles.length === 0) if (updatableFiles.length === 0)
return false; return false;
// Download files // Download files
const container = await models.TempContainer.container('edi'); const container = await models.TempContainer.container('edi');
const tempPath = path.join(container.client.root, container.name); const tempPath = path.join(container.client.root, container.name);
let remoteFile; let remoteFile;
let tempDir; let tempDir;
let tempFile; let tempFile;
const fileNames = updatableFiles.map(file => file.name); const fileNames = updatableFiles.map(file => file.name);
const tables = await Self.rawSql(` const tables = await Self.rawSql(`
SELECT fileName, toTable, file SELECT fileName, toTable, file
FROM edi.tableConfig FROM edi.tableConfig
WHERE file IN (?)`, [fileNames], options); WHERE file IN (?)`, [fileNames], options);
for (const table of tables) { for (const table of tables) {
const fileName = table.file; const fileName = table.file;
remoteFile = `codes/${fileName}.ZIP`; remoteFile = `codes/${fileName}.ZIP`;
tempDir = `${tempPath}/${fileName}`; tempDir = `${tempPath}/${fileName}`;
tempFile = `${tempPath}/${fileName}.zip`; tempFile = `${tempPath}/${fileName}.zip`;
try { try {
await fs.readFile(tempFile); await fs.readFile(tempFile);
} catch (error) { } catch (error) {
if (error.code === 'ENOENT') { if (error.code === 'ENOENT') {
console.debug(`Downloading file ${fileName}...`); console.debug(`Downloading file ${fileName}...`);
const downloadOutput = await downloadFile(remoteFile, tempFile); const downloadOutput = await downloadFile(remoteFile, tempFile);
if (downloadOutput.error) if (downloadOutput.error)
continue; continue;
} }
} }
await extractFile(fileName, tempFile, tempDir); await extractFile(fileName, tempFile, tempDir);
console.debug(`Updating table ${table.toTable}...`); console.debug(`Updating table ${table.toTable}...`);
await dumpData(tempDir, table, options); await dumpData(tempDir, table, options);
} }
// Update files checksum // Update files checksum
for (const file of updatableFiles) { for (const file of updatableFiles) {
console.log(`Updating file ${file.name} checksum...`); console.log(`Updating file ${file.name} checksum...`);
await Self.rawSql(` await Self.rawSql(`
UPDATE edi.fileConfig UPDATE edi.fileConfig
SET checksum = ? SET checksum = ?
WHERE name = ?`, WHERE name = ?`,
[file.checksum, file.name], options); [file.checksum, file.name], options);
} }
await tx.commit(); await tx.commit();
// Clean files // Clean files
try { try {
console.debug(`Cleaning files...`); console.debug(`Cleaning files...`);
await fs.remove(tempPath); await fs.remove(tempPath);
} catch (error) { } catch (error) {
if (error.code !== 'ENOENT') if (error.code !== 'ENOENT')
throw e; throw e;
} }
return true; return true;
} catch (error) { } catch (error) {
await tx.rollback(); await tx.rollback();
throw error; throw error;
} }
}; };
let ftpClient; let ftpClient;
async function getFtpClient() { async function getFtpClient() {
if (!ftpClient) { if (!ftpClient) {
const [ftpConfig] = await Self.rawSql('SELECT host, user, password FROM edi.ftpConfig'); const [ftpConfig] = await Self.rawSql('SELECT host, user, password FROM edi.ftpConfig');
console.debug(`Openning FTP connection to ${ftpConfig.host}...\n`); console.debug(`Openning FTP connection to ${ftpConfig.host}...\n`);
const FtpClient = require('ftps'); const FtpClient = require('ftps');
ftpClient = new FtpClient({ ftpClient = new FtpClient({
host: ftpConfig.host, host: ftpConfig.host,
username: ftpConfig.user, username: ftpConfig.user,
password: ftpConfig.password, password: ftpConfig.password,
procotol: 'ftp', procotol: 'ftp',
additionalLftpCommands: 'set ssl:verify-certificate no' additionalLftpCommands: 'set ssl:verify-certificate no'
}); });
} }
return ftpClient; return ftpClient;
} }
async function getChecksum(file) { async function getChecksum(file) {
const ftpClient = await getFtpClient(); const ftpClient = await getFtpClient();
console.debug(`Checking checksum for file ${file.name}...`); console.debug(`Checking checksum for file ${file.name}...`);
ftpClient.cat(`codes/${file.name}.TXT`); ftpClient.cat(`codes/${file.name}.TXT`);
const response = await new Promise((resolve, reject) => { const response = await new Promise((resolve, reject) => {
ftpClient.exec((err, response) => { ftpClient.exec((err, response) => {
if (err || response.error) { if (err || response.error) {
console.debug(`Error downloading checksum file... ${response.error}`); console.debug(`Error downloading checksum file... ${response.error}`);
return reject(err); return reject(err);
} }
resolve(response); resolve(response);
}); });
}); });
if (response && response.data) { if (response && response.data) {
const fileContents = response.data; const fileContents = response.data;
const rows = fileContents.split('\n'); const rows = fileContents.split('\n');
const row = rows[4]; const row = rows[4];
const columns = row.split(/\s+/); const columns = row.split(/\s+/);
let fileChecksum; let fileChecksum;
if (file.keyValue) if (file.keyValue)
fileChecksum = columns[1]; fileChecksum = columns[1];
if (!file.keyValue) if (!file.keyValue)
fileChecksum = columns[0]; fileChecksum = columns[0];
return fileChecksum; return fileChecksum;
} }
} }
async function downloadFile(remoteFile, tempFile) { async function downloadFile(remoteFile, tempFile) {
const ftpClient = await getFtpClient(); const ftpClient = await getFtpClient();
ftpClient.get(remoteFile, tempFile); ftpClient.get(remoteFile, tempFile);
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
ftpClient.exec((err, response) => { ftpClient.exec((err, response) => {
if (err || response.error) { if (err || response.error) {
console.debug(`Error downloading file... ${response.error}`); console.debug(`Error downloading file... ${response.error}`);
return reject(err); return reject(err);
} }
resolve(response); resolve(response);
}); });
}); });
} }
async function extractFile(fileName, tempFile, tempDir) { async function extractFile(fileName, tempFile, tempDir) {
const JSZip = require('jszip'); const JSZip = require('jszip');
try { try {
await fs.mkdir(tempDir); await fs.mkdir(tempDir);
console.debug(`Extracting file ${fileName}...`); console.debug(`Extracting file ${fileName}...`);
} catch (error) { } catch (error) {
if (error.code !== 'EEXIST') if (error.code !== 'EEXIST')
throw e; throw e;
} }
const fileStream = await fs.readFile(tempFile); const fileStream = await fs.readFile(tempFile);
if (fileStream) { if (fileStream) {
const zip = new JSZip(); const zip = new JSZip();
const zipContents = await zip.loadAsync(fileStream); const zipContents = await zip.loadAsync(fileStream);
if (!zipContents) return; if (!zipContents) return;
const fileNames = Object.keys(zipContents.files); const fileNames = Object.keys(zipContents.files);
for (const fileName of fileNames) { for (const fileName of fileNames) {
const fileContent = await zip.file(fileName).async('nodebuffer'); const fileContent = await zip.file(fileName).async('nodebuffer');
const dest = path.join(tempDir, fileName); const dest = path.join(tempDir, fileName);
await fs.writeFile(dest, fileContent); await fs.writeFile(dest, fileContent);
} }
} }
} }
async function dumpData(tempDir, table, options) { async function dumpData(tempDir, table, options) {
const toTable = table.toTable; const toTable = table.toTable;
const baseName = table.fileName; const baseName = table.fileName;
console.log(`Emptying table ${toTable}...`); console.log(`Emptying table ${toTable}...`);
const tableName = `edi.${toTable}`; const tableName = `edi.${toTable}`;
await Self.rawSql(`DELETE FROM ??`, [tableName]); await Self.rawSql(`DELETE FROM ??`, [tableName]);
const dirFiles = await fs.readdir(tempDir); const dirFiles = await fs.readdir(tempDir);
const files = dirFiles.filter(file => file.startsWith(baseName)); const files = dirFiles.filter(file => file.startsWith(baseName));
for (const file of files) { for (const file of files) {
console.log(`Dumping data from file ${file}...`); console.log(`Dumping data from file ${file}...`);
const templatePath = path.join(__dirname, `./sql/${toTable}.sql`); const templatePath = path.join(__dirname, `./sql/${toTable}.sql`);
const sqlTemplate = await fs.readFile(templatePath, 'utf8'); const sqlTemplate = await fs.readFile(templatePath, 'utf8');
const filePath = path.join(tempDir, file); const filePath = path.join(tempDir, file);
await Self.rawSql(sqlTemplate, [filePath], options); await Self.rawSql(sqlTemplate, [filePath], options);
await Self.rawSql(` await Self.rawSql(`
UPDATE edi.tableConfig UPDATE edi.tableConfig
SET updated = ? SET updated = ?
WHERE fileName = ? WHERE fileName = ?
`, [Date.vnNew(), baseName], options); `, [Date.vnNew(), baseName], options);
} }
console.log(`Updated table ${toTable}\n`); console.log(`Updated table ${toTable}\n`);
} }
}; };

View File

@ -67,7 +67,7 @@ module.exports = Self => {
if (!image) return false; if (!image) return false;
const hasReadRole = models.ImageCollection.hasReadRole(ctx, collection); const hasReadRole = await models.ImageCollection.hasReadRole(ctx, collection);
if (!hasReadRole) if (!hasReadRole)
throw new UserError(`You don't have enough privileges`); throw new UserError(`You don't have enough privileges`);

View File

@ -24,6 +24,7 @@ module.exports = Self => {
fields: ['email'], fields: ['email'],
where: {name: user} where: {name: user}
}); });
if (!account) return;
user = account.email; user = account.email;
} }

View File

@ -27,33 +27,47 @@ module.exports = Self => {
}); });
Self.signIn = async function(user, password) { Self.signIn = async function(user, password) {
let models = Self.app.models; const models = Self.app.models;
const usesEmail = user.indexOf('@') !== -1;
let token; let token;
let usesEmail = user.indexOf('@') !== -1;
let userInfo = usesEmail const userInfo = usesEmail
? {email: user} ? {email: user}
: {username: user}; : {username: user};
let instance = await Self.findOne({ const instance = await Self.findOne({
fields: ['username', 'password'], fields: ['username', 'password'],
where: userInfo where: userInfo
}); });
let where = usesEmail const where = usesEmail
? {email: user} ? {email: user}
: {name: user}; : {name: user};
let vnUser = await Self.findOne({ const vnUser = await Self.findOne({
fields: ['active'], fields: ['id', 'active', 'passExpired'],
where where
}); });
let validCredentials = instance const today = Date.vnNew();
today.setHours(0, 0, 0, 0);
const validCredentials = instance
&& await instance.hasPassword(password); && await instance.hasPassword(password);
if (validCredentials) { if (validCredentials) {
if (!vnUser.active) if (!vnUser.active)
throw new UserError('User disabled'); throw new UserError('User disabled');
if (vnUser.passExpired && vnUser.passExpired.getTime() <= today.getTime()) {
const changePasswordToken = await models.AccessToken.create({
scopes: ['change-password'],
userId: vnUser.id
});
throw new UserError('Pass expired', 'passExpired', {
id: vnUser.id,
token: changePasswordToken.id
});
}
try { try {
await models.Account.sync(instance.username, password); await models.Account.sync(instance.username, password);
} catch (err) { } catch (err) {

View File

@ -44,4 +44,4 @@
"principalId": "$everyone", "principalId": "$everyone",
"permission": "ALLOW" "permission": "ALLOW"
}] }]
} }

View File

@ -9,10 +9,11 @@ module.exports = Self => {
* @return {boolean} True for user with read privileges * @return {boolean} True for user with read privileges
*/ */
Self.hasReadRole = async(ctx, name, options) => { Self.hasReadRole = async(ctx, name, options) => {
const collection = await Self.findOne({where: {name}}, { const collection = await Self.findOne({
include: { include: {
relation: 'readRole' relation: 'readRole'
} },
where: {name}
}, options); }, options);
return await hasRole(ctx, collection, options); return await hasRole(ctx, collection, options);

View File

@ -107,4 +107,81 @@ module.exports = function(Self) {
return email.send(); return email.send();
}); });
const _setPassword = Self.prototype.setPassword;
Self.prototype.setPassword = async function(newPassword, options, cb) {
if (cb === undefined && typeof options === 'function') {
cb = options;
options = undefined;
}
const myOptions = {};
let tx;
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
options = myOptions;
try {
await Self.rawSql(`CALL account.user_checkPassword(?)`, [newPassword], options);
await _setPassword.call(this, newPassword, options);
await this.updateAttribute('passExpired', null, options);
await Self.app.models.Account.sync(this.name, newPassword, null, options);
tx && await tx.commit();
cb && cb();
} catch (err) {
tx && await tx.rollback();
if (cb) cb(err); else throw err;
}
};
Self.sharedClass._methods.find(method => method.name == 'changePassword')
.accessScopes = ['change-password'];
// FIXME: https://redmine.verdnatura.es/issues/5761
// Self.afterRemote('prototype.patchAttributes', async(ctx, instance) => {
// if (!ctx.args || !ctx.args.data.email) return;
// 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(':');
// 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 instance.verify(options);
// });
}; };

View File

@ -25,10 +25,7 @@
}, },
"password": { "password": {
"type": "string", "type": "string",
"required": true, "required": true
"mysql": {
"columnName": "bcryptPassword"
}
}, },
"roleFk": { "roleFk": {
"type": "number", "type": "number",
@ -42,9 +39,6 @@
"lang": { "lang": {
"type": "string" "type": "string"
}, },
"bcryptPassword": {
"type": "string"
},
"active": { "active": {
"type": "boolean" "type": "boolean"
}, },
@ -62,7 +56,10 @@
}, },
"hasGrant": { "hasGrant": {
"type": "boolean" "type": "boolean"
} },
"passExpired": {
"type": "date"
}
}, },
"relations": { "relations": {
"role": { "role": {

View File

@ -1,26 +1,18 @@
FROM mariadb:10.7.5 FROM mariadb:10.7.7
ENV MYSQL_ROOT_PASSWORD root ENV MYSQL_ROOT_PASSWORD root
ENV TZ Europe/Madrid ENV TZ Europe/Madrid
ARG MOCKDATE=2001-01-01 11:00:00 ARG MOCKDATE=2001-01-01 11:00:00
ARG DEBIAN_FRONTEND=noninteractive ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update \
&& apt-get install -y --no-install-recommends curl ca-certificates \
&& curl -sL https://apt.verdnatura.es/conf/verdnatura.gpg | apt-key add - \
&& echo "deb http://apt.verdnatura.es/ jessie main" > /etc/apt/sources.list.d/vn.list \
&& apt-get update \
&& apt-get install -y vn-mariadb \
&& apt-get purge -y --auto-remove curl ca-certificates \
&& rm -rf /var/lib/apt/lists/*
COPY docker/docker.cnf /etc/mysql/conf.d/ COPY docker/docker.cnf /etc/mysql/conf.d/
COPY \ COPY \
docker/docker-start.sh \
docker/docker-init.sh \ docker/docker-init.sh \
docker/docker-temp-start.sh \
docker/docker-temp-stop.sh \ docker/docker-temp-stop.sh \
docker/docker-dump.sh \ docker/docker-dump.sh \
docker/docker-start.sh \ docker/docker-structure.sh \
docker/docker-fixtures.sh \
/usr/local/bin/ /usr/local/bin/
RUN mkdir /mysql-data \ RUN mkdir /mysql-data \
@ -31,26 +23,16 @@ WORKDIR /docker-boot
COPY \ COPY \
import-changes.sh \ import-changes.sh \
config.ini \ config.ini \
dump/mysqlPlugins.sql \
dump/structure.sql \ dump/structure.sql \
dump/mockDate.sql \ dump/mockDate.sql \
dump/dumpedFixtures.sql \ dump/dumpedFixtures.sql \
./ ./
RUN gosu mysql docker-init.sh \ RUN sed -i -e 's/@mockDate/'"$MOCKDATE"'/g' mockDate.sql \
&& docker-dump.sh mysqlPlugins \ && gosu mysql docker-structure.sh
&& docker-dump.sh structure \
&& sed -i -e 's/@mockDate/'"$MOCKDATE"'/g' mockDate.sql \
&& docker-dump.sh mockDate \
&& docker-dump.sh dumpedFixtures \
&& gosu mysql docker-temp-stop.sh
COPY changes ./changes COPY changes ./changes
COPY dump/fixtures.sql ./ COPY dump/fixtures.sql ./
ARG STAMP=unknown ARG STAMP=unknown
RUN gosu mysql docker-temp-start.sh \ RUN gosu mysql docker-fixtures.sh
&& ./import-changes.sh \
&& docker-dump.sh fixtures \
&& gosu mysql docker-temp-stop.sh
RUN echo "[INFO] -> Import finished" \ RUN echo "[INFO] -> Import finished" \
&& rm -rf /docker-boot && rm -rf /docker-boot

View File

@ -27,7 +27,6 @@ INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalTyp
('Client', 'summary', '*', 'ALLOW', 'ROLE', 'employee'), ('Client', 'summary', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'updateAddress', '*', 'ALLOW', 'ROLE', 'employee'), ('Client', 'updateAddress', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'updateFiscalData', '*', 'ALLOW', 'ROLE', 'employee'), ('Client', 'updateFiscalData', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'updateUser', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'uploadFile', '*', 'ALLOW', 'ROLE', 'employee'), ('Client', 'uploadFile', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'campaignMetricsPdf', '*', 'ALLOW', 'ROLE', 'employee'), ('Client', 'campaignMetricsPdf', '*', 'ALLOW', 'ROLE', 'employee'),
('Client', 'campaignMetricsEmail', '*', 'ALLOW', 'ROLE', 'employee'), ('Client', 'campaignMetricsEmail', '*', 'ALLOW', 'ROLE', 'employee'),

View File

@ -0,0 +1,28 @@
CREATE TABLE `vn`.`buyConfig` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`monthsAgo` int(11) NOT NULL DEFAULT 6 COMMENT 'Meses desde la última compra',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
CREATE TABLE `vn`.`travelConfig` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`warehouseInFk` smallint(6) unsigned NOT NULL DEFAULT 8 COMMENT 'Warehouse de origen',
`warehouseOutFk` smallint(6) unsigned NOT NULL DEFAULT 60 COMMENT 'Warehouse destino',
`agencyFk` int(11) NOT NULL DEFAULT 1378 COMMENT 'Agencia por defecto',
`companyFk` smallint(5) unsigned NOT NULL DEFAULT 442 COMMENT 'Compañía por defecto',
PRIMARY KEY (`id`),
KEY `travelConfig_FK` (`warehouseInFk`),
KEY `travelConfig_FK_1` (`warehouseOutFk`),
KEY `travelConfig_FK_2` (`agencyFk`),
KEY `travelConfig_FK_3` (`companyFk`),
CONSTRAINT `travelConfig_FK` FOREIGN KEY (`warehouseInFk`) REFERENCES `warehouse` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `travelConfig_FK_1` FOREIGN KEY (`warehouseOutFk`) REFERENCES `warehouse` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `travelConfig_FK_2` FOREIGN KEY (`agencyFk`) REFERENCES `agencyMode` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `travelConfig_FK_3` FOREIGN KEY (`companyFk`) REFERENCES `company` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('Entry', 'addFromPackaging', 'WRITE', 'ALLOW', 'ROLE', 'production'),
('Entry', 'addFromBuy', 'WRITE', 'ALLOW', 'ROLE', 'production'),
('Supplier', 'getItemsPackaging', 'READ', 'ALLOW', 'ROLE', 'production');

View File

@ -0,0 +1,3 @@
ALTER TABLE `vn`.`sector` DROP COLUMN `printerFk`;
ALTER TABLE `vn`.`sector` ADD COLUMN `mainPrinterFk` tinyint(3) unsigned;
ALTER TABLE `vn`.`sector` ADD CONSTRAINT sector_FK_1 FOREIGN KEY (mainPrinterFk) REFERENCES vn.printer(id) ON DELETE CASCADE ON UPDATE CASCADE;

View File

@ -0,0 +1 @@
ALTER TABLE `vn`.`ticket` MODIFY COLUMN warehouseFk smallint(6) unsigned DEFAULT NULL NULL;

View File

@ -0,0 +1,121 @@
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('Ticket', 'editDiscount', 'WRITE', 'ALLOW', 'ROLE', 'claimManager'),
('Ticket', 'editDiscount', 'WRITE', 'ALLOW', 'ROLE', 'salesPerson'),
('Ticket', 'isRoleAdvanced', '*', 'ALLOW', 'ROLE', 'salesAssistant'),
('Ticket', 'isRoleAdvanced', '*', 'ALLOW', 'ROLE', 'deliveryBoss'),
('Ticket', 'isRoleAdvanced', '*', 'ALLOW', 'ROLE', 'buyer'),
('Ticket', 'isRoleAdvanced', '*', 'ALLOW', 'ROLE', 'claimManager'),
('Ticket', 'deleteTicketWithPartPrepared', 'WRITE', 'ALLOW', 'ROLE', 'salesAssistant'),
('Ticket', 'editZone', 'WRITE', 'ALLOW', 'ROLE', 'deliveryBoss'),
('State', 'editableStates', 'READ', 'ALLOW', 'ROLE', 'employee'),
('State', 'seeEditableStates', 'READ', 'ALLOW', 'ROLE', 'administrative'),
('State', 'seeEditableStates', 'READ', 'ALLOW', 'ROLE', 'production'),
('State', 'isSomeEditable', 'READ', 'ALLOW', 'ROLE', 'salesPerson'),
('State', 'isAllEditable', 'READ', 'ALLOW', 'ROLE', 'production'),
('State', 'isAllEditable', 'READ', 'ALLOW', 'ROLE', 'administrative'),
('Agency', 'seeExpired', 'READ', 'ALLOW', 'ROLE', 'administrative'),
('Agency', 'seeExpired', 'READ', 'ALLOW', 'ROLE', 'productionBoss'),
('Claim', 'createAfterDeadline', 'WRITE', 'ALLOW', 'ROLE', 'claimManager'),
('Client', 'editAddressLogifloraAllowed', 'WRITE', 'ALLOW', 'ROLE', 'salesAssistant'),
('Client', 'editFiscalDataWithoutTaxDataCheck', 'WRITE', 'ALLOW', 'ROLE', 'salesAssistant'),
('Client', 'editVerifiedDataWithoutTaxDataCheck', 'WRITE', 'ALLOW', 'ROLE', 'salesAssistant'),
('Client', 'editCredit', 'WRITE', 'ALLOW', 'ROLE', 'financialBoss'),
('Client', 'isNotEditableCredit', 'WRITE', 'ALLOW', 'ROLE', 'financialBoss'),
('InvoiceOut', 'canCreatePdf', 'WRITE', 'ALLOW', 'ROLE', 'invoicing'),
('Supplier', 'editPayMethodCheck', 'WRITE', 'ALLOW', 'ROLE', 'financial'),
('Worker', 'isTeamBoss', 'WRITE', 'ALLOW', 'ROLE', 'teamBoss'),
('Worker', 'forceIsSubordinate', 'READ', 'ALLOW', 'ROLE', 'hr'),
('Claim', 'editState', 'WRITE', 'ALLOW', 'ROLE', 'claimManager');
DELETE FROM `salix`.`ACL`
WHERE
model = 'Claim'
AND property = '*'
AND accessType = '*';
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('Claim', 'find', 'READ', 'ALLOW', 'ROLE', 'salesPerson'),
('Claim', 'findById', 'READ', 'ALLOW', 'ROLE', 'salesPerson'),
('Claim', 'findOne', 'READ', 'ALLOW', 'ROLE', 'salesPerson'),
('Claim', 'getSummary', 'READ', 'ALLOW', 'ROLE', 'salesPerson'),
('Claim', 'updateClaim', 'WRITE', 'ALLOW', 'ROLE', 'salesPerson'),
('Claim', 'regularizeClaim', 'WRITE', 'ALLOW', 'ROLE', 'claimManager'),
('Claim', 'updateClaimDestination', 'WRITE', 'ALLOW', 'ROLE', 'claimManager'),
('Claim', 'downloadFile', 'READ', 'ALLOW', 'ROLE', 'claimManager'),
('Claim', 'deleteById', 'WRITE', 'ALLOW', 'ROLE', 'claimManager'),
('Claim', 'filter', 'READ', 'ALLOW', 'ROLE', 'salesPerson'),
('Claim', 'logs', 'READ', 'ALLOW', 'ROLE', 'claimManager');
DELETE FROM `salix`.`ACL`
WHERE
model = 'Ticket'
AND property = '*'
AND accessType = '*';
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('Ticket', 'find', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'findById', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'findOne', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'getVolume', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'getTotalVolume', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'summary', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'priceDifference', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'componentUpdate', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'new', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'isEditable', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'setDeleted', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'restore', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'getSales', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'getSalesPersonMana', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'filter', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'makeInvoice', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'updateEditableTicket', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'updateDiscount', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'transferSales', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'sendSms', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'isLocked', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'freightCost', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'getComponentsSum', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'updateAttributes', 'WRITE', 'ALLOW', 'ROLE', 'delivery'), -- Change Priority in Route tickets
('Ticket', 'deliveryNoteCsv', 'READ', 'ALLOW', 'ROLE', 'employee');
DELETE FROM `salix`.`ACL`
WHERE
model = 'State'
AND property = '*'
AND accessType = 'READ';
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('State', 'find', 'READ', 'ALLOW', 'ROLE', 'employee'),
('State', 'findById', 'READ', 'ALLOW', 'ROLE', 'employee'),
('State', 'findOne', 'READ', 'ALLOW', 'ROLE', 'employee');
DELETE FROM `salix`.`ACL`
WHERE
model = 'Worker'
AND property = '*'
AND accessType = 'READ';
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('Worker', 'find', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Worker', 'findById', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Worker', 'findOne', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Worker', 'filter', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Worker', 'getWorkedHours', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Worker', 'active', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Worker', 'activeWithRole', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Worker', 'uploadFile', 'WRITE', 'ALLOW', 'ROLE', 'hr'),
('Worker', 'contracts', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Worker', 'holidays', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Worker', 'activeContract', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Worker', 'activeWithInheritedRole', 'READ', 'ALLOW', 'ROLE', 'employee');
DELETE FROM `salix`.`ACL`
WHERE model = 'Client'
AND property = 'updateUser'
AND accessType = '*';

View File

View File

@ -0,0 +1,76 @@
ALTER TABLE `account`.`user` ADD passExpired DATE DEFAULT NULL;
DROP PROCEDURE `account`.`myUser_changePassword`;
DROP PROCEDURE `account`.`myUser_restorePassword`;
DROP PROCEDURE `account`.`user_changePassword`;
DROP PROCEDURE `account`.`user_restorePassword`;
DROP PROCEDURE `account`.`user_setPassword`;
ALTER TABLE account.`user` CHANGE password password__ char(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_unicode_ci NOT NULL COMMENT 'Deprecated';
ALTER TABLE account.`user` CHANGE bcryptPassword password varchar(512) CHARACTER SET utf8mb3 COLLATE utf8mb3_unicode_ci DEFAULT NULL NULL;
DELIMITER $$
$$
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `account`.`user_beforeUpdate`
BEFORE UPDATE ON `user`
FOR EACH ROW
BEGIN
SET NEW.editorFk = account.myUser_getId();
IF !(NEW.`name` <=> OLD.`name`) THEN
CALL user_checkName (NEW.`name`);
END IF;
IF !(NEW.`password` <=> OLD.`password`) THEN
SET NEW.lastPassChange = util.VN_NOW();
END IF;
END$$
DELIMITER ;
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `account`.`accountDovecot` AS
select
`u`.`name` AS `name`,
`u`.`password` AS `password`
from
(`account`.`user` `u`
join `account`.`account` `a` on
(`a`.`id` = `u`.`id`))
where
`u`.`active` <> 0;
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `salix`.`User` AS
select
`account`.`user`.`id` AS `id`,
`account`.`user`.`realm` AS `realm`,
`account`.`user`.`name` AS `username`,
`account`.`user`.`password` AS `password`,
`account`.`user`.`email` AS `email`,
`account`.`user`.`emailVerified` AS `emailVerified`,
`account`.`user`.`verificationToken` AS `verificationToken`
from
`account`.`user`;
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn`.`workerTimeControlUserInfo` AS
select
`u`.`id` AS `userFk`,
`w`.`firstName` AS `name`,
`w`.`lastName` AS `surname`,
`u`.`name` AS `user`,
`u`.`password` AS `password`,
`wd`.`departmentFk` AS `departmentFk`,
left(`c`.`fi`,
8) AS `dni`
from
(((`account`.`user` `u`
join `vn`.`worker` `w` on
(`w`.`userFk` = `u`.`id`))
join `vn`.`client` `c` on
(`c`.`id` = `u`.`id`))
left join `vn`.`workerDepartment` `wd` on
(`wd`.`workerFk` = `w`.`id`));

View File

@ -5,3 +5,6 @@ CMD=mysqld
docker_setup_env "$CMD" docker_setup_env "$CMD"
docker_temp_server_start "$CMD" docker_temp_server_start "$CMD"
bash import-changes.sh
docker-dump.sh fixtures
docker_temp_server_stop

7
db/docker/docker-structure.sh Executable file
View File

@ -0,0 +1,7 @@
#!/bin/bash
. docker-init.sh
docker-dump.sh structure
docker-dump.sh mockDate
docker-dump.sh dumpedFixtures
. docker-temp-stop.sh

0
db/docker/docker-temp-stop.sh Executable file → Normal file
View File

View File

@ -782,6 +782,38 @@ USE `sage`;
-- Dumping data for table `TiposIva` -- Dumping data for table `TiposIva`
-- --
LOCK TABLES `taxType` WRITE;
/*!40000 ALTER TABLE `taxType` DISABLE KEYS */;
INSERT INTO `sage`.`taxType` (id, code, isIntracommunity) VALUES
(2, NULL, 0),
(4, 'national4', 0),
(5, NULL, 0),
(6, NULL, 1),
(7, NULL, 1),
(8, NULL, 1),
(10, 'national10', 0),
(11, NULL, 0),
(16, 'CEEServices21', 1),
(18, NULL, 0),
(20, 'national0', 0),
(21, 'national21', 0),
(22, 'import10', 0),
(26, NULL, 0),
(90, 'import21', 0),
(91, NULL, 0),
(92, NULL, 0),
(93, NULL, 0),
(94, NULL, 0),
(100, NULL, 0),
(108, NULL, 0),
(109, NULL, 0),
(110, NULL, 1),
(111, NULL, 0),
(112, NULL, 0),
(113, 'ISP21', 0),
(114, NULL, 0),
(115, 'import4', 0);
LOCK TABLES `TiposIva` WRITE; LOCK TABLES `TiposIva` WRITE;
/*!40000 ALTER TABLE `TiposIva` DISABLE KEYS */; /*!40000 ALTER TABLE `TiposIva` DISABLE KEYS */;
INSERT INTO `TiposIva` VALUES (2,0,'Operaciones no sujetas',0.0000000000,0.0000000000,0.0000000000,'','4770000020','','','','','','','95B21A93-5910-489D-83BB-C32788C9B19D','','','','','','','','','',0,0),(4,0,'I.V.A. 4%',0.0000000000,4.0000000000,0.0000000000,'4720000004','4770000004','','6310000000','','','','','9E6160D5-984E-4643-ACBC-1EBC3BF73360','','','','','','','','','',0,0),(5,0,'I.V.A. 4% y R.E. 0.5%',0.0000000000,4.0000000000,0.5000000000,'','4770000504','4770000405','','','','','','DBEFA562-63FB-4FFC-8171-64F0C6F065FF','','','','','','','','','',0,0),(6,0,'H.P. IVA 4% CEE',0.0000000000,4.0000000000,0.0000000000,'4721000004','4771000004','','','','','','','DD0ECBA8-2EF5-425E-911B-623580BADA77','','','','','','','','','',0,1),(7,0,'H.P. IVA 10% CEE',0.0000000000,10.0000000000,0.0000000000,'4721000011','4771000010','','','','','','','593208CD-6F28-4489-B6EC-907AD689EAC9','','','','','','','','','',0,1),(8,0,'H.P. IVA 21% CEE',0.0000000000,21.0000000000,0.0000000000,'4721000021','4771000021','','','','','','','27061852-9BC1-4C4F-9B6E-69970E208F23','','','','','','','','','',0,1),(10,0,'I.V.A. 10% Nacional',0.0000000000,10.0000000000,0.0000000000,'4720000011','4770000010','','6290000553','','','','','828A9D6F-5C01-4C3A-918A-B2E4482830D3','','','','','','','','','',0,0),(11,0,'I.V.A. 10% y R.E. 1,4%',0.0000000000,10.0000000000,1.4000000000,'','4770000101','4770000110','','','','','','C1F2D910-83A1-4191-A76C-8B3D7AB98348','','','','','','','','','',0,0),(16,0,'I.V.A. Adqui. servicios CEE',0.0000000000,21.0000000000,0.0000000000,'4721000015','4771000016','','','','','','','E3EDE961-CE8F-41D4-9E6C-D8BCD32275A1','','','','','','','','','',0,1),(18,0,'H.P. Iva Importación 0% ISP',0.0000000000,0.0000000000,0.0000000000,'4720000005','4770000005','','','','','','','27AD4158-2349-49C2-B53A-A4E0EFAC5D09','','','','','','','','','',0,0),(20,0,'I.V.A 0% Nacional',0.0000000000,0.0000000000,0.0000000000,'4720000000','','','','','','','','B90B0FBD-E513-4F04-9721-C873504E08DF','','','','','','','','','',0,0),(21,0,'I.V.A. 21%',0.0000000000,21.0000000000,0.0000000000,'4720000021','4770000021','4770000000','','','','','','BA8C4E28-DCFA-4F7B-AE4F-CA044626B55E','','','','','','','','','',0,0),(22,0,'IVA 10% importaciones',0.0000000000,10.0000000000,0.0000000000,'4722000010','','','','','','','','540450A8-4B41-4607-96D1-E7F296FB6933','','','','','','','','','',0,0),(26,0,'I.V.A. 21% y R.E. 5,2%',0.0000000000,21.0000000000,5.2000000000,'4720000021','4770000215','4770000521','631000000','','','','','2BC0765F-7739-49AE-A5F0-28B648B81677','','','','','','','','','',0,0),(90,0,'IVA 21% importaciones',0.0000000000,21.0000000000,0.0000000000,'4722000021','','','','','','','','EB675F91-5FF2-4E26-A31E-EEB674125945','','','','','','','','','',0,0),(91,0,'IVA 0% importaciones',0.0000000000,0.0000000000,0.0000000000,'4723000000','','','','','','','','5E5EFA56-2A99-4D54-A16B-5D818274CA18','','','','','','','','','',0,0),(92,0,'8.5% comp. ganadera o pesquera',0.0000000000,8.5000000000,0.0000000000,'4720000000','4770000000','477000000','631000000','','','','','','','','','','','','','','',0,0),(93,0,'12% com. agrícola o forestal',0.0000000000,12.0000000000,0.0000000000,'4720000012','','','','','','','','267B1DDB-247F-4A71-AB95-3349FEFC5F92','','','','','','','','','',0,0),(94,0,'10,5% com. ganadera o pesquera',0.0000000000,10.5000000000,0.0000000000,'4770000000','4720000000','631000000','477000000','','','','','','','','','','','','','','',0,0),(100,0,'HP IVA SOPORTADO 5%',0.0000000000,5.0000000000,0.0000000000,'4720000055','','','','','','','','3AD36CB2-4172-4CC9-9F87-2BF2B56AAC80','','','','','','','','','',0,0),(108,0,'I.V.A. 8%',0.0000000000,8.0000000000,0.0000000000,'4720000000','4770000000','477000000','631000000','','','','','','','','','','','','','','',0,0),(109,0,'I.V.A. 8% y R.E. 1%',0.0000000000,8.0000000000,1.0000000000,'4720000000','4770000000','477000000','631000000','','','','','','','','','','','','','','',0,0),(110,0,'HP IVA Devengado Exento CEE',0.0000000000,0.0000000000,0.0000000000,'','4771000000','','','','','','','C605BC32-E161-42FD-83F3-3A66B1FBE399','','','','','','','','','',0,1),(111,0,'H.P. Iva Devengado Exento Ser',0.0000000000,0.0000000000,0.0000000000,'','4771000001','','','','','','','F1AEC4DC-AFE5-498E-A713-2648FFB6DA32','','','','','','','','','',0,0),(112,0,'H.P. IVA Devengado en exportac',0.0000000000,0.0000000000,0.0000000000,'','4770000002','','','','','','','F980AE74-BF75-4F4C-927F-0CCCE0DB8D15','','','','','','','','','',0,0),(113,0,'HP DEVENGADO 21 ISP ',0.0000000000,21.0000000000,0.0000000000,'4720000006','4770000006','','','','','','','728D7A76-E936-438C-AF05-3CA38FE16EA5','','','','','','','','','',0,0),(114,0,'HP.IVA NO DEDUCIBLE 10%',0.0000000000,0.0000000000,0.0000000000,'4720000026','','','','','','','','','','','','','','','','','',0,0),(115,0,'H.P. IVA Soportado Impor 4% ',0.0000000000,4.0000000000,0.0000000000,'4722000004','','','','','','','','','','','','','','','','','',0,0); INSERT INTO `TiposIva` VALUES (2,0,'Operaciones no sujetas',0.0000000000,0.0000000000,0.0000000000,'','4770000020','','','','','','','95B21A93-5910-489D-83BB-C32788C9B19D','','','','','','','','','',0,0),(4,0,'I.V.A. 4%',0.0000000000,4.0000000000,0.0000000000,'4720000004','4770000004','','6310000000','','','','','9E6160D5-984E-4643-ACBC-1EBC3BF73360','','','','','','','','','',0,0),(5,0,'I.V.A. 4% y R.E. 0.5%',0.0000000000,4.0000000000,0.5000000000,'','4770000504','4770000405','','','','','','DBEFA562-63FB-4FFC-8171-64F0C6F065FF','','','','','','','','','',0,0),(6,0,'H.P. IVA 4% CEE',0.0000000000,4.0000000000,0.0000000000,'4721000004','4771000004','','','','','','','DD0ECBA8-2EF5-425E-911B-623580BADA77','','','','','','','','','',0,1),(7,0,'H.P. IVA 10% CEE',0.0000000000,10.0000000000,0.0000000000,'4721000011','4771000010','','','','','','','593208CD-6F28-4489-B6EC-907AD689EAC9','','','','','','','','','',0,1),(8,0,'H.P. IVA 21% CEE',0.0000000000,21.0000000000,0.0000000000,'4721000021','4771000021','','','','','','','27061852-9BC1-4C4F-9B6E-69970E208F23','','','','','','','','','',0,1),(10,0,'I.V.A. 10% Nacional',0.0000000000,10.0000000000,0.0000000000,'4720000011','4770000010','','6290000553','','','','','828A9D6F-5C01-4C3A-918A-B2E4482830D3','','','','','','','','','',0,0),(11,0,'I.V.A. 10% y R.E. 1,4%',0.0000000000,10.0000000000,1.4000000000,'','4770000101','4770000110','','','','','','C1F2D910-83A1-4191-A76C-8B3D7AB98348','','','','','','','','','',0,0),(16,0,'I.V.A. Adqui. servicios CEE',0.0000000000,21.0000000000,0.0000000000,'4721000015','4771000016','','','','','','','E3EDE961-CE8F-41D4-9E6C-D8BCD32275A1','','','','','','','','','',0,1),(18,0,'H.P. Iva Importación 0% ISP',0.0000000000,0.0000000000,0.0000000000,'4720000005','4770000005','','','','','','','27AD4158-2349-49C2-B53A-A4E0EFAC5D09','','','','','','','','','',0,0),(20,0,'I.V.A 0% Nacional',0.0000000000,0.0000000000,0.0000000000,'4720000000','','','','','','','','B90B0FBD-E513-4F04-9721-C873504E08DF','','','','','','','','','',0,0),(21,0,'I.V.A. 21%',0.0000000000,21.0000000000,0.0000000000,'4720000021','4770000021','4770000000','','','','','','BA8C4E28-DCFA-4F7B-AE4F-CA044626B55E','','','','','','','','','',0,0),(22,0,'IVA 10% importaciones',0.0000000000,10.0000000000,0.0000000000,'4722000010','','','','','','','','540450A8-4B41-4607-96D1-E7F296FB6933','','','','','','','','','',0,0),(26,0,'I.V.A. 21% y R.E. 5,2%',0.0000000000,21.0000000000,5.2000000000,'4720000021','4770000215','4770000521','631000000','','','','','2BC0765F-7739-49AE-A5F0-28B648B81677','','','','','','','','','',0,0),(90,0,'IVA 21% importaciones',0.0000000000,21.0000000000,0.0000000000,'4722000021','','','','','','','','EB675F91-5FF2-4E26-A31E-EEB674125945','','','','','','','','','',0,0),(91,0,'IVA 0% importaciones',0.0000000000,0.0000000000,0.0000000000,'4723000000','','','','','','','','5E5EFA56-2A99-4D54-A16B-5D818274CA18','','','','','','','','','',0,0),(92,0,'8.5% comp. ganadera o pesquera',0.0000000000,8.5000000000,0.0000000000,'4720000000','4770000000','477000000','631000000','','','','','','','','','','','','','','',0,0),(93,0,'12% com. agrícola o forestal',0.0000000000,12.0000000000,0.0000000000,'4720000012','','','','','','','','267B1DDB-247F-4A71-AB95-3349FEFC5F92','','','','','','','','','',0,0),(94,0,'10,5% com. ganadera o pesquera',0.0000000000,10.5000000000,0.0000000000,'4770000000','4720000000','631000000','477000000','','','','','','','','','','','','','','',0,0),(100,0,'HP IVA SOPORTADO 5%',0.0000000000,5.0000000000,0.0000000000,'4720000055','','','','','','','','3AD36CB2-4172-4CC9-9F87-2BF2B56AAC80','','','','','','','','','',0,0),(108,0,'I.V.A. 8%',0.0000000000,8.0000000000,0.0000000000,'4720000000','4770000000','477000000','631000000','','','','','','','','','','','','','','',0,0),(109,0,'I.V.A. 8% y R.E. 1%',0.0000000000,8.0000000000,1.0000000000,'4720000000','4770000000','477000000','631000000','','','','','','','','','','','','','','',0,0),(110,0,'HP IVA Devengado Exento CEE',0.0000000000,0.0000000000,0.0000000000,'','4771000000','','','','','','','C605BC32-E161-42FD-83F3-3A66B1FBE399','','','','','','','','','',0,1),(111,0,'H.P. Iva Devengado Exento Ser',0.0000000000,0.0000000000,0.0000000000,'','4771000001','','','','','','','F1AEC4DC-AFE5-498E-A713-2648FFB6DA32','','','','','','','','','',0,0),(112,0,'H.P. IVA Devengado en exportac',0.0000000000,0.0000000000,0.0000000000,'','4770000002','','','','','','','F980AE74-BF75-4F4C-927F-0CCCE0DB8D15','','','','','','','','','',0,0),(113,0,'HP DEVENGADO 21 ISP ',0.0000000000,21.0000000000,0.0000000000,'4720000006','4770000006','','','','','','','728D7A76-E936-438C-AF05-3CA38FE16EA5','','','','','','','','','',0,0),(114,0,'HP.IVA NO DEDUCIBLE 10%',0.0000000000,0.0000000000,0.0000000000,'4720000026','','','','','','','','','','','','','','','','','',0,0),(115,0,'H.P. IVA Soportado Impor 4% ',0.0000000000,4.0000000000,0.0000000000,'4722000004','','','','','','','','','','','','','','','','','',0,0);

View File

@ -71,8 +71,8 @@ INSERT INTO `account`.`roleConfig`(`id`, `mysqlPassword`, `rolePrefix`, `userPre
CALL `account`.`role_sync`; CALL `account`.`role_sync`;
INSERT INTO `account`.`user`(`id`,`name`, `nickname`, `password`,`role`,`active`,`email`, `lang`, `image`, `bcryptPassword`) INSERT INTO `account`.`user`(`id`,`name`, `nickname`, `role`,`active`,`email`, `lang`, `image`, `password`)
SELECT id, name, CONCAT(name, 'Nick'),MD5('nightmare'), id, 1, CONCAT(name, '@mydomain.com'), 'en', '4fa3ada0-3ac4-11eb-9ab8-27f6fc3b85fd', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2' SELECT id, name, CONCAT(name, 'Nick'), id, 1, CONCAT(name, '@mydomain.com'), 'en', '4fa3ada0-3ac4-11eb-9ab8-27f6fc3b85fd', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2'
FROM `account`.`role` WHERE id <> 20 FROM `account`.`role` WHERE id <> 20
ORDER BY id; ORDER BY id;
@ -98,20 +98,24 @@ 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`, `bcryptPassword`, `password`,`role`,`active`,`email`,`lang`, `image`) INSERT INTO `account`.`user`(`id`,`name`,`nickname`, `password`,`role`,`active`,`email`,`lang`, `image`)
VALUES VALUES
(1101, 'BruceWayne', 'Bruce Wayne', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'BruceWayne@mydomain.com', 'es', 'e7723f0b24ff05b32ed09d95196f2f29'), (1101, 'BruceWayne', 'Bruce Wayne', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 2, 1, 'BruceWayne@mydomain.com', 'es', 'e7723f0b24ff05b32ed09d95196f2f29'),
(1102, 'PetterParker', 'Petter Parker', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'PetterParker@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'), (1102, 'PetterParker', 'Petter Parker', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 2, 1, 'PetterParker@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'),
(1103, 'ClarkKent', 'Clark Kent', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'ClarkKent@mydomain.com', 'fr', 'e7723f0b24ff05b32ed09d95196f2f29'), (1103, 'ClarkKent', 'Clark Kent', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 2, 1, 'ClarkKent@mydomain.com', 'fr', 'e7723f0b24ff05b32ed09d95196f2f29'),
(1104, 'TonyStark', 'Tony Stark', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'TonyStark@mydomain.com', 'es', 'e7723f0b24ff05b32ed09d95196f2f29'), (1104, 'TonyStark', 'Tony Stark', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 2, 1, 'TonyStark@mydomain.com', 'es', 'e7723f0b24ff05b32ed09d95196f2f29'),
(1105, 'MaxEisenhardt', 'Max Eisenhardt', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'MaxEisenhardt@mydomain.com', 'pt', 'e7723f0b24ff05b32ed09d95196f2f29'), (1105, 'MaxEisenhardt', 'Max Eisenhardt', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 2, 1, 'MaxEisenhardt@mydomain.com', 'pt', 'e7723f0b24ff05b32ed09d95196f2f29'),
(1106, 'DavidCharlesHaller', 'David Charles Haller', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'DavidCharlesHaller@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'), (1106, 'DavidCharlesHaller', 'David Charles Haller', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 1, 1, 'DavidCharlesHaller@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'),
(1107, 'HankPym', 'Hank Pym', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'HankPym@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'), (1107, 'HankPym', 'Hank Pym', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 1, 1, 'HankPym@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'),
(1108, 'CharlesXavier', 'Charles Xavier', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'CharlesXavier@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'), (1108, 'CharlesXavier', 'Charles Xavier', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 1, 1, 'CharlesXavier@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'),
(1109, 'BruceBanner', 'Bruce Banner', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'BruceBanner@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'), (1109, 'BruceBanner', 'Bruce Banner', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 1, 1, 'BruceBanner@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'),
(1110, 'JessicaJones', 'Jessica Jones', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'JessicaJones@mydomain.com', 'en', NULL), (1110, 'JessicaJones', 'Jessica Jones', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 1, 1, 'JessicaJones@mydomain.com', 'en', NULL),
(1111, 'Missing', 'Missing', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 2, 0, NULL, 'en', NULL), (1111, 'Missing', 'Missing', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 2, 0, NULL, 'en', NULL),
(1112, 'Trash', 'Trash', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 2, 0, NULL, 'en', NULL); (1112, 'Trash', 'Trash', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 2, 0, NULL, 'en', NULL);
UPDATE account.`user`
SET passExpired = DATE_SUB(util.VN_CURDATE(), INTERVAL 1 YEAR)
WHERE name = 'maintenance';
INSERT INTO `account`.`mailAlias`(`id`, `alias`, `description`, `isPublic`) INSERT INTO `account`.`mailAlias`(`id`, `alias`, `description`, `isPublic`)
VALUES VALUES
@ -179,6 +183,8 @@ INSERT INTO `vn`.`printer` (`id`, `name`, `path`, `isLabeler`, `sectorFk`, `ipAd
(2, 'printer2', 'path2', 1, 1 , NULL), (2, 'printer2', 'path2', 1, 1 , NULL),
(4, 'printer4', 'path4', 0, NULL, '10.1.10.4'); (4, 'printer4', 'path4', 0, NULL, '10.1.10.4');
UPDATE `vn`.`sector` SET mainPrinterFk = 1 WHERE id = 1;
INSERT INTO `vn`.`worker`(`id`, `code`, `firstName`, `lastName`, `userFk`,`bossFk`, `phone`, `sectorFk`, `labelerFk`) INSERT INTO `vn`.`worker`(`id`, `code`, `firstName`, `lastName`, `userFk`,`bossFk`, `phone`, `sectorFk`, `labelerFk`)
VALUES VALUES
(1106, 'LGN', 'David Charles', 'Haller', 1106, 19, 432978106, NULL, NULL), (1106, 'LGN', 'David Charles', 'Haller', 1106, 19, 432978106, NULL, NULL),
@ -905,7 +911,7 @@ INSERT INTO `vn`.`itemFamily`(`code`, `description`)
INSERT INTO `vn`.`item`(`id`, `typeFk`, `size`, `inkFk`, `stems`, `originFk`, `description`, `producerFk`, `intrastatFk`, `expenceFk`, INSERT INTO `vn`.`item`(`id`, `typeFk`, `size`, `inkFk`, `stems`, `originFk`, `description`, `producerFk`, `intrastatFk`, `expenceFk`,
`comment`, `relevancy`, `image`, `subName`, `minPrice`, `stars`, `family`, `isFloramondo`, `genericFk`, `itemPackingTypeFk`, `hasMinPrice`, `packingShelve`, `weightByPiece`) `comment`, `relevancy`, `image`, `subName`, `minPrice`, `stars`, `family`, `isFloramondo`, `genericFk`, `itemPackingTypeFk`, `hasMinPrice`, `packingShelve`, `weightByPiece`)
VALUES VALUES
(1, 2, 70, 'YEL', 1, 1, NULL, 1, 06021010, 2000000000, NULL, 0, '1', NULL, 0, 1, 'VT', 0, NULL, 'V', 0, 15,3), (1, 2, 70, 'YEL', 1, 1, NULL, 1, 06021010, 2000000000, NULL, 0, '1', NULL, 0, 1, 'EMB', 0, NULL, 'V', 0, 15,3),
(2, 2, 70, 'BLU', 1, 2, NULL, 1, 06021010, 2000000000, NULL, 0, '2', NULL, 0, 2, 'VT', 0, NULL, 'H', 0, 10,2), (2, 2, 70, 'BLU', 1, 2, NULL, 1, 06021010, 2000000000, NULL, 0, '2', NULL, 0, 2, 'VT', 0, NULL, 'H', 0, 10,2),
(3, 1, 60, 'YEL', 1, 3, NULL, 1, 05080000, 4751000000, NULL, 0, '3', NULL, 0, 5, 'VT', 0, NULL, NULL, 0, 5,5), (3, 1, 60, 'YEL', 1, 3, NULL, 1, 05080000, 4751000000, NULL, 0, '3', NULL, 0, 5, 'VT', 0, NULL, NULL, 0, 5,5),
(4, 1, 60, 'YEL', 1, 1, 'Increases block', 1, 05080000, 4751000000, NULL, 0, '4', NULL, 0, 3, 'VT', 0, NULL, NULL, 0, NULL,NULL), (4, 1, 60, 'YEL', 1, 1, 'Increases block', 1, 05080000, 4751000000, NULL, 0, '4', NULL, 0, 3, 'VT', 0, NULL, NULL, 0, NULL,NULL),
@ -2332,26 +2338,26 @@ INSERT INTO `vn`.`workerTimeControl`(`userFk`, `timed`, `manual`, `direction`, `
INSERT INTO `vn`.`dmsType`(`id`, `name`, `path`, `readRoleFk`, `writeRoleFk`, `code`) INSERT INTO `vn`.`dmsType`(`id`, `name`, `path`, `readRoleFk`, `writeRoleFk`, `code`)
VALUES VALUES
(1, 'Facturas Recibidas', 'recibidas', NULL, NULL, 'invoiceIn'), (1, 'Facturas Recibidas', 'recibidas', NULL, NULL, 'invoiceIn'),
(2, 'Doc oficial', 'oficial', NULL, NULL, 'officialDoc'), (2, 'Doc oficial', 'oficial', NULL, NULL, 'officialDoc'),
(3, 'Laboral', 'laboral', 37, 37, 'hhrrData'), (3, 'Laboral', 'laboral', 37, 37, 'hhrrData'),
(4, 'Albaranes recibidos', 'entradas', NULL, NULL, 'deliveryNote'), (4, 'Albaranes recibidos', 'entradas', NULL, NULL, 'deliveryNote'),
(5, 'Otros', 'otros', 1, 1, 'miscellaneous'), (5, 'Otros', 'otros', 1, 1, 'miscellaneous'),
(6, 'Pruebas', 'pruebas', NULL, NULL, 'tests'), (6, 'Pruebas', 'pruebas', NULL, NULL, 'tests'),
(7, 'IAE Clientes', 'IAE_Clientes', 1, 1, 'economicActivitiesTax'), (7, 'IAE Clientes', 'IAE_Clientes', 1, 1, 'economicActivitiesTax'),
(8, 'Fiscal', 'fiscal', NULL, NULL, 'fiscal'), (8, 'Fiscal', 'fiscal', NULL, NULL, 'fiscal'),
(9, 'Vehiculos', 'vehiculos', NULL, NULL, 'vehicles'), (9, 'Vehiculos', 'vehiculos', NULL, NULL, 'vehicles'),
(10, 'Plantillas', 'plantillas', NULL, NULL, 'templates'), (10, 'Plantillas', 'plantillas', NULL, NULL, 'templates'),
(11, 'Contratos', 'contratos', NULL, NULL, 'contracts'), (11, 'Contratos', 'contratos', NULL, NULL, 'contracts'),
(12, 'ley de pagos', 'ley pagos', 1, 1, 'paymentsLaw'), (12, 'ley de pagos', 'ley pagos', 1, 1, 'paymentsLaw'),
(13, 'Basura', 'basura', 1, 1, 'trash'), (13, 'Basura', 'basura', 1, 1, 'trash'),
(14, 'Ticket', 'tickets', 1, 1, 'ticket'), (14, 'Ticket', 'tickets', 1, 1, 'ticket'),
(15, 'Presupuestos', 'Presupuestos', NULL, NULL, 'budgets'), (15, 'Presupuestos', 'Presupuestos', NULL, NULL, 'budgets'),
(16, 'Logistica', 'logistica', NULL, NULL, 'logistics'), (16, 'Logistica', 'logistica', NULL, NULL, 'logistics'),
(17, 'cmr', 'cmr', NULL, NULL, 'cmr'), (17, 'cmr', 'cmr', NULL, NULL, 'cmr'),
(18, 'dua', 'dua', NULL, NULL, 'dua'), (18, 'dua', 'dua', NULL, NULL, 'dua'),
(19, 'inmovilizado', 'inmovilizado', NULL, NULL, 'fixedAssets'), (19, 'inmovilizado', 'inmovilizado', NULL, NULL, 'fixedAssets'),
(20, 'Reclamación', 'reclamacion', 1, 1, 'claim'); (20, 'Reclamación', 'reclamacion', 1, 1, 'claim');
INSERT INTO `vn`.`dms`(`id`, `dmsTypeFk`, `file`, `contentType`, `workerFk`, `warehouseFk`, `companyFk`, `hardCopyNumber`, `hasFile`, `reference`, `description`, `created`) INSERT INTO `vn`.`dms`(`id`, `dmsTypeFk`, `file`, `contentType`, `workerFk`, `warehouseFk`, `companyFk`, `hardCopyNumber`, `hasFile`, `reference`, `description`, `created`)
VALUES VALUES
@ -2729,6 +2735,7 @@ INSERT INTO `util`.`notification` (`id`, `name`, `description`)
VALUES VALUES
(1, 'print-email', 'notification fixture one'), (1, 'print-email', 'notification fixture one'),
(2, 'invoice-electronic', 'A electronic invoice has been generated'), (2, 'invoice-electronic', 'A electronic invoice has been generated'),
(3, 'not-main-printer-configured', 'A printer distinct than main has been configured'),
(4, 'supplier-pay-method-update', 'A supplier pay method has been updated'); (4, 'supplier-pay-method-update', 'A supplier pay method has been updated');
INSERT INTO `util`.`notificationAcl` (`notificationFk`, `roleFk`) INSERT INTO `util`.`notificationAcl` (`notificationFk`, `roleFk`)
@ -2783,7 +2790,9 @@ INSERT INTO `vn`.`ticketLog` (`originFk`, userFk, `action`, changedModel, oldIns
(7, 18, 'update', 'Sale', '{"quantity":1}', '{"quantity":10}', 1, NULL), (7, 18, 'update', 'Sale', '{"quantity":1}', '{"quantity":10}', 1, NULL),
(7, 18, 'update', 'Ticket', '{"quantity":1,"concept":"Chest ammo box"}', '{"quantity":10,"concept":"Chest ammo box"}', 1, NULL), (7, 18, 'update', 'Ticket', '{"quantity":1,"concept":"Chest ammo box"}', '{"quantity":10,"concept":"Chest ammo box"}', 1, NULL),
(7, 18, 'update', 'Sale', '{"price":3}', '{"price":5}', 1, NULL), (7, 18, 'update', 'Sale', '{"price":3}', '{"price":5}', 1, NULL),
(7, 18, 'update', NULL, NULL, NULL, NULL, "Cambio cantidad Melee weapon heavy shield 1x0.5m de '5' a '10'"); (7, 18, 'update', NULL, NULL, NULL, NULL, "Cambio cantidad Melee weapon heavy shield 1x0.5m de '5' a '10'"),
(16, 9, 'update', 'Sale', '{"quantity":10,"concept":"Shield", "price": 10.5, "itemFk": 1}', '{"quantity":8,"concept":"Shield", "price": 10.5, "itemFk": 1}' , 5689, 'Shield');
INSERT INTO `vn`.`ticketLog` (originFk, userFk, `action`, creationDate, changedModel, changedModelId, changedModelValue, oldInstance, newInstance, description) INSERT INTO `vn`.`ticketLog` (originFk, userFk, `action`, creationDate, changedModel, changedModelId, changedModelValue, oldInstance, newInstance, description)
VALUES VALUES
@ -2797,7 +2806,6 @@ INSERT INTO `vn`.`ticketLog` (originFk, userFk, `action`, creationDate, changedM
(1, 18, 'select', '2000-12-27 03:40:30', 'Ticket', 45, NULL , NULL, NULL, NULL), (1, 18, 'select', '2000-12-27 03:40:30', 'Ticket', 45, NULL , NULL, NULL, NULL),
(1, 18, 'insert', '2000-04-10 09:40:15', 'Sale', 5689, 'Shield' , NULL, '{"quantity":10,"concept":"Shield", "price": 10.5, "itemFk": 1}', NULL), (1, 18, 'insert', '2000-04-10 09:40:15', 'Sale', 5689, 'Shield' , NULL, '{"quantity":10,"concept":"Shield", "price": 10.5, "itemFk": 1}', NULL),
(1, 18, 'insert', '1999-05-09 10:00:00', 'Ticket', 45, 'Super Man' , NULL, '{"id":45,"clientFk":8608,"warehouseFk":60,"shipped":"2023-05-16T22:00:00.000Z","nickname":"Super Man","addressFk":48637,"isSigned":true,"isLabeled":true,"isPrinted":true,"packages":0,"hour":0,"created":"2023-05-16T11:42:56.000Z","isBlocked":false,"hasPriority":false,"companyFk":442,"agencyModeFk":639,"landed":"2023-05-17T22:00:00.000Z","isBoxed":true,"isDeleted":true,"zoneFk":713,"zonePrice":13,"zoneBonus":0}', NULL); (1, 18, 'insert', '1999-05-09 10:00:00', 'Ticket', 45, 'Super Man' , NULL, '{"id":45,"clientFk":8608,"warehouseFk":60,"shipped":"2023-05-16T22:00:00.000Z","nickname":"Super Man","addressFk":48637,"isSigned":true,"isLabeled":true,"isPrinted":true,"packages":0,"hour":0,"created":"2023-05-16T11:42:56.000Z","isBlocked":false,"hasPriority":false,"companyFk":442,"agencyModeFk":639,"landed":"2023-05-17T22:00:00.000Z","isBoxed":true,"isDeleted":true,"zoneFk":713,"zonePrice":13,"zoneBonus":0}', NULL);
INSERT INTO `vn`.`osTicketConfig` (`id`, `host`, `user`, `password`, `oldStatus`, `newStatusId`, `day`, `comment`, `hostDb`, `userDb`, `passwordDb`, `portDb`, `responseType`, `fromEmailId`, `replyTo`) INSERT INTO `vn`.`osTicketConfig` (`id`, `host`, `user`, `password`, `oldStatus`, `newStatusId`, `day`, `comment`, `hostDb`, `userDb`, `passwordDb`, `portDb`, `responseType`, `fromEmailId`, `replyTo`)
VALUES VALUES
(0, 'http://localhost:56596/scp', 'ostadmin', 'Admin1', '1,6', 3, 60, 'Este CAU se ha cerrado automáticamente. Si el problema persiste responda a este mensaje.', 'localhost', 'osticket', 'osticket', 40003, 'reply', 1, 'all'); (0, 'http://localhost:56596/scp', 'ostadmin', 'Admin1', '1,6', 3, 60, 'Este CAU se ha cerrado automáticamente. Si el problema persiste responda a este mensaje.', 'localhost', 'osticket', 'osticket', 40003, 'reply', 1, 'all');
@ -2886,6 +2894,17 @@ INSERT INTO `vn`.`wagonTypeTray` (`id`, `typeFk`, `height`, `colorFk`)
(2, 1, 50, 2), (2, 1, 50, 2),
(3, 1, 0, 3); (3, 1, 0, 3);
INSERT INTO `vn`.`travelConfig` (`id`, `warehouseInFk`, `warehouseOutFk`, `agencyFk`, `companyFk`)
VALUES
(1, 1, 1, 1, 442);
INSERT INTO `vn`.`buyConfig` (`id`, `monthsAgo`)
VALUES
(1, 6);
INSERT INTO `vn`.`invoiceInSerial` (`code`, `description`, `cplusTerIdNifFk`, `taxAreaFk`)
VALUES
('C', 'Asgard', 1, 'WORLD'),
('E', 'Midgard', 1, 'CEE'),
('R', 'Jotunheim', 1, 'NATIONAL'),
('W', 'Vanaheim', 1, 'WORLD');

View File

@ -1,30 +1,19 @@
DROP FUNCTION IF EXISTS `util`.`mockTime`;
DELIMITER $$ DELIMITER $$
$$
CREATE DEFINER=`root`@`localhost` FUNCTION `util`.`mockTime`() RETURNS datetime CREATE OR REPLACE DEFINER=`root`@`localhost` FUNCTION `util`.`mockTime`() RETURNS datetime
DETERMINISTIC DETERMINISTIC
BEGIN BEGIN
RETURN CONVERT_TZ('@mockDate', 'utc', 'Europe/Madrid'); RETURN CONVERT_TZ('@mockDate', 'utc', 'Europe/Madrid');
END$$ END$$
DELIMITER ;
DROP FUNCTION IF EXISTS `util`.`mockUtcTime`; CREATE OR REPLACE DEFINER=`root`@`localhost` FUNCTION `util`.`mockUtcTime`() RETURNS datetime
DELIMITER $$
$$
CREATE DEFINER=`root`@`localhost` FUNCTION `util`.`mockUtcTime`() RETURNS datetime
DETERMINISTIC DETERMINISTIC
BEGIN BEGIN
RETURN CONVERT_TZ('@mockDate', 'utc', 'Europe/Madrid'); RETURN CONVERT_TZ('@mockDate', 'utc', 'Europe/Madrid');
END$$ END$$
DELIMITER ;
DROP FUNCTION IF EXISTS `util`.`mockTimeBase`; CREATE OR REPLACE DEFINER=`root`@`localhost` FUNCTION `util`.`mockTimeBase`(vIsUtc BOOL) RETURNS datetime
DELIMITER $$
$$
CREATE DEFINER=`root`@`localhost` FUNCTION `util`.`mockTimeBase`(vIsUtc BOOL) RETURNS datetime
DETERMINISTIC DETERMINISTIC
BEGIN BEGIN
RETURN CONVERT_TZ('@mockDate', 'utc', 'Europe/Madrid'); RETURN CONVERT_TZ('@mockDate', 'utc', 'Europe/Madrid');

View File

@ -1,4 +0,0 @@
-- Import compiled functions
CREATE AGGREGATE FUNCTION minacum RETURNS INT SONAME 'minacum.so';
CREATE AGGREGATE FUNCTION multimax RETURNS INT SONAME 'multimax.so';

View File

@ -15620,6 +15620,18 @@ CREATE TABLE `ClavesOperacion` (
-- --
-- Table structure for table `Municipios` -- Table structure for table `Municipios`
-- --
DROP TABLE IF EXISTS `taxType`;
CREATE TABLE `taxType` (
id INT(11) NOT NULL,
code VARCHAR(25) DEFAULT NULL NULL,
isIntracommunity TINYINT(1) DEFAULT FALSE NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `taxType_UN` (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci COMMENT='Coincidencia del id con Sage.TiposIVA.CodigoIva(propia de Sage), en ningún caso vincular mediate FK';
ALTER TABLE `sage`.`taxType` ADD CONSTRAINT taxType_PK PRIMARY KEY IF NOT EXISTS (id);
ALTER TABLE `sage`.`taxType` ADD CONSTRAINT taxType_UN UNIQUE KEY IF NOT EXISTS (code);
DROP TABLE IF EXISTS `Municipios`; DROP TABLE IF EXISTS `Municipios`;
/*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET @saved_cs_client = @@character_set_client */;
@ -22074,12 +22086,14 @@ CREATE TABLE `autonomy` (
`name` varchar(100) NOT NULL, `name` varchar(100) NOT NULL,
`countryFk` mediumint(8) unsigned NOT NULL, `countryFk` mediumint(8) unsigned NOT NULL,
`geoFk` int(11) DEFAULT NULL, `geoFk` int(11) DEFAULT NULL,
`isUeeMember` tinyint(1) DEFAULT NULL,
`hasDailyInvoice` tinyint(4) DEFAULT NULL,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
KEY `autonomy_FK` (`countryFk`), KEY `autonomy_FK` (`countryFk`),
KEY `autonomy_FK_1` (`geoFk`), KEY `autonomy_FK_1` (`geoFk`),
CONSTRAINT `autonomy_FK` FOREIGN KEY (`countryFk`) REFERENCES `country` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT `autonomy_FK` FOREIGN KEY (`countryFk`) REFERENCES `country` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `autonomy_FK_1` FOREIGN KEY (`geoFk`) REFERENCES `zoneGeo` (`id`) ON UPDATE CASCADE CONSTRAINT `autonomy_FK_1` FOREIGN KEY (`geoFk`) REFERENCES `zoneGeo` (`id`) ON UPDATE CASCADE
) ENGINE=InnoDBDEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci COMMENT='Comunidades autónomas o su equivalente en otros paises. Agrupación de provincias, en una categoria inferior a country.'; ) ENGINE=InnoDB AUTO_INCREMENT=109 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci COMMENT='Comunidades autónomas o su equivalente en otros paises. Agrupación de provincias, en una categoria inferior a country.';
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
/*!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 */ ;
@ -28805,7 +28819,10 @@ CREATE TABLE `expence` (
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
ALTER TABLE `vn`.`expence`
ADD code VARCHAR(25) DEFAULT NULL NULL;
ALTER TABLE `vn`.`expence`
ADD CONSTRAINT expence_UN UNIQUE KEY IF NOT EXISTS (code);
-- --
-- Table structure for table `farming` -- Table structure for table `farming`
-- --
@ -57317,7 +57334,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 `invoiceInBookingMain` */; /*!50003 DROP PROCEDURE IF EXISTS `invoiceIn_booking` */;
/*!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 */ ;
@ -57326,28 +57343,71 @@ DELIMITER ;
/*!50003 SET collation_connection = utf8mb4_general_ci */ ; /*!50003 SET collation_connection = utf8mb4_general_ci */ ;
/*!50003 SET @saved_sql_mode = @@sql_mode */ ; /*!50003 SET @saved_sql_mode = @@sql_mode */ ;
/*!50003 SET sql_mode = 'NO_ENGINE_SUBSTITUTION' */ ; /*!50003 SET sql_mode = 'NO_ENGINE_SUBSTITUTION' */ ;
DELIMITER ;; DELIMITER ;;
CREATE DEFINER=`root`@`localhost` PROCEDURE `invoiceInBookingMain`(vInvoiceInId INT) CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`invoiceIn_booking`(vSelf INT)
BEGIN BEGIN
DECLARE vTotalAmount,vTotalAmountDivisa DECIMAL(10,2); DECLARE vBookNumber INT;
DECLARE vBookNumber,vSerialNumber INT;
DECLARE vRate DECIMAL(10,4);
CALL invoiceInBookingCommon(vInvoiceInId,vSerialNumber); DROP TEMPORARY TABLE IF EXISTS tInvoiceIn;
CREATE TEMPORARY TABLE tInvoiceIn
SELECT SUM(iit.taxableBase * IF( i.serial= 'R' AND ti.Iva <> 'HP DEVENGADO 21 ISP', 1 +(ti.PorcentajeIva/100),1)), ENGINE = MEMORY
SUM(iit.foreignValue * IF( i.serial= 'R', 1 + (ti.PorcentajeIva/100),1)), SELECT ii.bookEntried,
iit.taxableBase/iit.foreignValue iit.foreignValue,
INTO vTotalAmount, vTotalAmountDivisa, vRate ii.companyFk,
FROM newInvoiceIn i ii.expenceFkDeductible,
JOIN invoiceInTax iit ON iit.invoiceInFk = i.id iit.taxableBase,
LEFT JOIN sage.TiposIva ti ON ti.CodigoIva = iit.taxTypeSageFk; ii.serial,
ii.issued,
ii.operated,
ii.supplierRef,
ii.cplusTrascendency472Fk,
ii.cplusTaxBreakFk,
ii.cplusSubjectOpFk,
ii.cplusInvoiceType472Fk,
ii.cplusRectificationTypeFk,
ii.booked,
IFNULL(a.isUeeMember, c.isUeeMember) isUeeMember,
(c.id = cc.id) isSameCountry,
s.account supplierAccount,
s.name supplierName,
s.nif,
iit.taxTypeSageFk,
tt.code taxCode,
ti.Iva,
ti.CuentaIvaSoportado,
ti.PorcentajeIva,
ti.CuentaIvaRepercutido,
ttr.ClaveOperacionDefecto,
iis.cplusTerIdNifFk,
cit.id invoicesCount,
e.code,
e.isWithheld,
e.id expenceFk,
e.name expenceName
FROM invoiceIn ii
JOIN supplier s ON s.id = ii.supplierFk
LEFT JOIN province p ON p.id = s.provinceFk
LEFT JOIN autonomy a ON a.id = p.autonomyFk
JOIN country c ON c.id = s.countryFk
JOIN supplier sc ON sc.id = ii.companyFk
JOIN country cc ON cc.id = sc.countryFk
JOIN invoiceInSerial iis ON iis.code = ii.serial
JOIN cplusInvoiceType472 cit ON cit.id = ii.cplusInvoiceType472Fk
LEFT JOIN invoiceInTax iit ON iit.invoiceInFk = ii.id
LEFT JOIN sage.TiposTransacciones ttr ON ttr.CodigoTransaccion = iit.transactionTypeSageFk
LEFT JOIN expence e ON e.id = iit.expenceFk
LEFT JOIN sage.TiposIva ti ON ti.CodigoIva = iit.taxTypeSageFk
LEFT JOIN sage.taxType tt ON tt.id = ti.CodigoIva
WHERE ii.id = vSelf;
CALL vn.ledger_next(vBookNumber); CALL vn.ledger_next(vBookNumber);
-- Apunte del proveedor -- Apunte del proveedor
INSERT INTO XDiario(
INSERT INTO XDiario(ASIEN, ASIEN,
FECHA, FECHA,
SUBCTA, SUBCTA,
EUROHABER, EUROHABER,
@ -57356,24 +57416,30 @@ BEGIN
HABERME, HABERME,
NFACTICK, NFACTICK,
CLAVE, CLAVE,
empresa_id empresa_id)
)
SELECT SELECT
vBookNumber, vBookNumber ASIEN,
n.bookEntried, tii.bookEntried FECHA,
s.supplierAccount, tii.supplierAccount SUBCTA,
vTotalAmount EUROHABER, SUM(tii.taxableBase *
n.conceptWithSupplier, IF(tii.serial= 'R' AND ((tii.taxCode IS NULL OR tii.taxCode <> 'ISP21')
vRate, AND tii.taxTypeSageFk IS NOT NULL),
vTotalAmountDivisa, 1 + (tii.PorcentajeIva / 100),
n.invoicesCount, 1)) EUROHABER,
vInvoiceInId, CONCAT('s/fra',
n.companyFk RIGHT(tii.supplierRef, 8),
FROM newInvoiceIn n ':',
JOIN newSupplier s; LEFT(tii.supplierName, 10)) CONCEPTO,
CAST(tii.taxableBase / tii.foreignValue AS DECIMAL (10,4)) CAMBIO,
SUM(tii.foreignValue * IF(tii.serial = 'R', 1 + (tii.PorcentajeIva / 100), 1)) HABERME,
tii.invoicesCount NFACTICK,
vSelf CLAVE,
tii.companyFk empresa_id
FROM tInvoiceIn tii;
-- Línea de Gastos -- Línea de Gastos
INSERT INTO XDiario ( ASIEN, INSERT INTO XDiario(
ASIEN,
FECHA, FECHA,
SUBCTA, SUBCTA,
CONTRA, CONTRA,
@ -57384,30 +57450,29 @@ BEGIN
DEBEME, DEBEME,
HABERME, HABERME,
NFACTICK, NFACTICK,
empresa_id empresa_id)
)
SELECT vBookNumber ASIEN, SELECT vBookNumber ASIEN,
n.bookEntried FECHA, tii.bookEntried FECHA,
IF(e.isWithheld , LPAD(RIGHT(s.supplierAccount,5),10,iit.expenceFk),iit.expenceFk) SUBCTA, IF(tii.isWithheld, LPAD(RIGHT(tii.supplierAccount, 5), 10, tii.expenceFk),tii.expenceFk) SUBCTA,
s.supplierAccount CONTRA, tii.supplierAccount CONTRA,
IF(e.isWithheld AND iit.taxableBase < 0, NULL, ROUND(SUM(iit.taxableBase),2)) EURODEBE, IF(tii.isWithheld AND tii.taxableBase < 0, NULL, ROUND(SUM(tii.taxableBase),2)) EURODEBE,
IF(e.isWithheld AND iit.taxableBase < 0,ROUND(SUM(-iit.taxableBase),2),NULL) EUROHABER, IF(tii.isWithheld AND tii.taxableBase < 0, ROUND(SUM(-tii.taxableBase), 2), NULL) EUROHABER,
n.conceptWithSupplier CONCEPTO, CONCAT('s/fra',
vRate, RIGHT(tii.supplierRef, 8),
IF(e.isWithheld,NULL,ABS(ROUND(SUM(iit.foreignValue),2))) DEBEME, ':',
IF(e.isWithheld,ABS(ROUND(SUM(iit.foreignValue),2)),NULL) HABERME, LEFT(tii.supplierName, 10)) CONCEPTO,
n.invoicesCount NFACTICK, CAST(tii.taxableBase / tii.foreignValue AS DECIMAL (10, 4)) CAMBIO,
n.companyFk empresa_id IF(tii.isWithheld, NULL,ABS(ROUND(SUM(tii.foreignValue), 2))) DEBEME,
FROM newInvoiceIn n IF(tii.isWithheld, ABS(ROUND(SUM(tii.foreignValue), 2)) ,NULL) HABERME,
JOIN newSupplier s tii.invoicesCount NFACTICK,
JOIN invoiceInTax iit ON iit.invoiceInFk = n.id tii.companyFk empresa_id
JOIN (SELECT * FROM expence e GROUP BY e.id)e ON e.id = iit.expenceFk FROM tInvoiceIn tii
WHERE e.name != 'Suplidos Transitarios nacionales' WHERE tii.code IS NULL OR tii.code <> 'suplido'
GROUP BY iit.expenceFk; GROUP BY tii.expenceFk;
-- Líneas de IVA -- Líneas de IVA
INSERT INTO XDiario(
INSERT INTO XDiario( ASIEN, ASIEN,
FECHA, FECHA,
SUBCTA, SUBCTA,
CONTRA, CONTRA,
@ -57434,56 +57499,50 @@ BEGIN
TERNIF, TERNIF,
TERNOM, TERNOM,
FECREGCON, FECREGCON,
empresa_id empresa_id)
)
SELECT vBookNumber ASIEN, SELECT vBookNumber ASIEN,
n.bookEntried FECHA, tii.bookEntried FECHA,
IF(n.expenceFkDeductible>0, n.expenceFkDeductible, ti.CuentaIvaSoportado) SUBCTA, IF(tii.expenceFkDeductible>0, tii.expenceFkDeductible, tii.CuentaIvaSoportado) SUBCTA,
s.supplierAccount CONTRA, tii.supplierAccount CONTRA,
SUM(ROUND(ti.PorcentajeIva * it.taxableBase / 100 /* + 0.0001*/ , 2)) EURODEBE, SUM(ROUND(tii.PorcentajeIva * tii.taxableBase / 100, 2)) EURODEBE,
SUM(it.taxableBase) BASEEURO, SUM(tii.taxableBase) BASEEURO,
GROUP_CONCAT(DISTINCT e.`name` SEPARATOR ', ') CONCEPTO, GROUP_CONCAT(DISTINCT tii.expenceName SEPARATOR ', ') CONCEPTO,
vSerialNumber FACTURA, vSelf FACTURA,
ti.PorcentajeIva IVA, tii.PorcentajeIva IVA,
IF(isUeeMember AND eWithheld.id IS NULL,'','*') AUXILIAR, IF(tii.isUeeMember AND eWithheld.id IS NULL, '', '*') AUXILIAR,
n.serial SERIE, tii.serial SERIE,
ttr.ClaveOperacionDefecto, tii.ClaveOperacionDefecto,
n.issued FECHA_EX, tii.issued FECHA_EX,
n.operated FECHA_OP, tii.operated FECHA_OP,
n.invoicesCount NFACTICK, tii.invoicesCount NFACTICK,
n.supplierRef FACTURAEX, tii.supplierRef FACTURAEX,
TRUE L340, TRUE L340,
(isSameCountry OR NOT isUeeMember) LRECT349, (tii.isSameCountry OR NOT tii.isUeeMember) LRECT349,
n.cplusTrascendency472Fk TIPOCLAVE, tii.cplusTrascendency472Fk TIPOCLAVE,
n.cplusTaxBreakFk TIPOEXENCI, tii.cplusTaxBreakFk TIPOEXENCI,
n.cplusSubjectOpFk TIPONOSUJE, tii.cplusSubjectOpFk TIPONOSUJE,
n.cplusInvoiceType472Fk TIPOFACT, tii.cplusInvoiceType472Fk TIPOFACT,
n.cplusRectificationTypeFk TIPORECTIF, tii.cplusRectificationTypeFk TIPORECTIF,
iis.cplusTerIdNifFk TERIDNIF, tii.cplusTerIdNifFk TERIDNIF,
s.nif AS TERNIF, tii.nif TERNIF,
s.name AS TERNOM, tii.supplierName TERNOM,
n.booked FECREGCON, tii.booked FECREGCON,
n.companyFk tii.companyFk
FROM newInvoiceIn n FROM tInvoiceIn tii
JOIN newSupplier s
JOIN invoiceInTax it ON n.id = it.invoiceInFk
JOIN sage.TiposIva ti ON ti.CodigoIva = it.taxTypeSageFk
JOIN sage.TiposTransacciones ttr ON ttr.CodigoTransaccion = it.transactionTypeSageFk
JOIN invoiceInSerial iis ON iis.code = n.serial
JOIN (SELECT * FROM expence e GROUP BY e.id)e ON e.id = it.expenceFk
LEFT JOIN ( LEFT JOIN (
SELECT eWithheld.id SELECT e.id
FROM invoiceInTax hold FROM tInvoiceIn tii
JOIN expence eWithheld ON eWithheld.id = hold.expenceFk AND eWithheld.isWithheld JOIN expence e ON e.id = tii.expenceFk
WHERE hold.invoiceInFk = vInvoiceInId LIMIT 1 WHERE e.isWithheld
LIMIT 1
) eWithheld ON TRUE ) eWithheld ON TRUE
WHERE it.taxTypeSageFk IS NOT NULL WHERE tii.taxTypeSageFk IS NOT NULL
AND it.taxTypeSageFk NOT IN (22, 90) AND (tii.taxCode IS NULL OR tii.taxCode NOT IN ('import10', 'import21'))
GROUP BY ti.PorcentajeIva, e.id; GROUP BY tii.PorcentajeIva, tii.expenceFk;
-- Línea iva inversor sujeto pasivo -- Línea iva inversor sujeto pasivo
INSERT INTO XDiario(
INSERT INTO XDiario( ASIEN, ASIEN,
FECHA, FECHA,
SUBCTA, SUBCTA,
CONTRA, CONTRA,
@ -57509,50 +57568,43 @@ BEGIN
TERIDNIF, TERIDNIF,
TERNIF, TERNIF,
TERNOM, TERNOM,
empresa_id empresa_id)
)
SELECT vBookNumber ASIEN, SELECT vBookNumber ASIEN,
n.bookEntried FECHA, tii.bookEntried FECHA,
ti.CuentaIvaRepercutido SUBCTA, tii.CuentaIvaRepercutido SUBCTA,
s.supplierAccount CONTRA, tii.supplierAccount CONTRA,
SUM(ROUND(ti.PorcentajeIva * it.taxableBase / 100,2)) EUROHABER, SUM(ROUND(tii.PorcentajeIva * tii.taxableBase / 100,2)) EUROHABER,
ROUND(SUM(it.taxableBase),2) BASEEURO, ROUND(SUM(tii.taxableBase),2) BASEEURO,
GROUP_CONCAT(DISTINCT e.`name` SEPARATOR ', ') CONCEPTO, GROUP_CONCAT(DISTINCT tii.expenceName SEPARATOR ', ') CONCEPTO,
vSerialNumber FACTURA, vSelf FACTURA,
ti.PorcentajeIva IVA, tii.PorcentajeIva IVA,
'*' AUXILIAR, '*' AUXILIAR,
n.serial SERIE, tii.serial SERIE,
ttr.ClaveOperacionDefecto, tii.ClaveOperacionDefecto,
n.issued FECHA_EX, tii.issued FECHA_EX,
n.operated FECHA_OP, tii.operated FECHA_OP,
n.invoicesCount NFACTICK, tii.invoicesCount NFACTICK,
n.supplierRef FACTURAEX, tii.supplierRef FACTURAEX,
FALSE L340, FALSE L340,
(isSameCountry OR NOT isUeeMember) LRECT349, (tii.isSameCountry OR NOT tii.isUeeMember) LRECT349,
1 TIPOCLAVE, 1 TIPOCLAVE,
n.cplusTaxBreakFk TIPOEXENCI, tii.cplusTaxBreakFk TIPOEXENCI,
n.cplusSubjectOpFk TIPONOSUJE, tii.cplusSubjectOpFk TIPONOSUJE,
n.cplusInvoiceType472Fk TIPOFACT, tii.cplusInvoiceType472Fk TIPOFACT,
n.cplusRectificationTypeFk TIPORECTIF, tii.cplusRectificationTypeFk TIPORECTIF,
iis.cplusTerIdNifFk TERIDNIF, tii.cplusTerIdNifFk TERIDNIF,
s.nif AS TERNIF, tii.nif TERNIF,
s.name AS TERNOM, tii.supplierName TERNOM,
n.companyFk tii.companyFk
FROM newInvoiceIn n FROM tInvoiceIn tii
JOIN newSupplier s WHERE tii.taxCode = 'ISP21' OR MID(tii.supplierAccount, 4, 1) = '1'
JOIN invoiceInTax it ON n.id = it.invoiceInFk AND tii.taxTypeSageFk IS NOT NULL
JOIN sage.TiposIva ti ON ti.CodigoIva = it.taxTypeSageFk GROUP BY tii.PorcentajeIva, tii.expenceFk;
JOIN sage.TiposTransacciones ttr ON ttr.CodigoTransaccion = it.transactionTypeSageFk
JOIN invoiceInSerial iis ON iis.code = n.serial
JOIN (SELECT * FROM expence e GROUP BY e.id)e ON e.id = it.expenceFk
WHERE ti.Iva = 'HP DEVENGADO 21 ISP' OR MID(s.account, 4, 1) = '1'
GROUP BY ti.PorcentajeIva, e.id;
-- Actualización del registro original -- Actualización del registro original
UPDATE invoiceIn ii UPDATE invoiceIn ii
JOIN newInvoiceIn ni ON ii.id = ni.id SET ii.isBooked = TRUE
SET ii.serialNumber = vSerialNumber, WHERE ii.id = vSelf;
ii.isBooked = TRUE;
-- Problemas derivados de la precisión en los decimales al calcular los impuestos -- Problemas derivados de la precisión en los decimales al calcular los impuestos
UPDATE XDiario UPDATE XDiario
@ -57569,8 +57621,12 @@ BEGIN
ORDER BY id DESC ORDER BY id DESC
LIMIT 1; LIMIT 1;
DROP TEMPORARY TABLE tInvoiceIn;
END ;; END ;;
DELIMITER ; DELIMITER ;
/*!50003 SET sql_mode = @saved_sql_mode */ ; /*!50003 SET sql_mode = @saved_sql_mode */ ;
/*!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 */ ;

View File

@ -110,5 +110,6 @@ TABLES=(
TiposIva TiposIva
TiposTransacciones TiposTransacciones
TiposRetencion TiposRetencion
taxType
) )
dump_tables ${TABLES[@]} dump_tables ${TABLES[@]}

View File

@ -22,7 +22,8 @@ export async function getBrowser() {
env.E2E_SHOW = true; env.E2E_SHOW = true;
} }
const headless = !env.E2E_SHOW; const headless = env.E2E_SHOW ? false : 'new';
const browser = await Puppeteer.launch({ const browser = await Puppeteer.launch({
args, args,
defaultViewport: null, defaultViewport: null,

View File

@ -572,15 +572,15 @@ export default {
submitNotesButton: 'button[type=submit]' submitNotesButton: 'button[type=submit]'
}, },
ticketExpedition: { ticketExpedition: {
firstSaleCheckbox: 'vn-ticket-expedition vn-tr:nth-child(1) vn-check[ng-model="expedition.checked"]', firstSaleCheckbox: 'vn-ticket-expedition tr:nth-child(1) vn-check[ng-model="expedition.checked"]',
thirdSaleCheckbox: 'vn-ticket-expedition vn-tr:nth-child(3) vn-check[ng-model="expedition.checked"]', thirdSaleCheckbox: 'vn-ticket-expedition tr:nth-child(3) vn-check[ng-model="expedition.checked"]',
deleteExpeditionButton: 'vn-ticket-expedition vn-tool-bar > vn-button[icon="delete"]', deleteExpeditionButton: 'vn-ticket-expedition slot-actions > vn-button[icon="delete"]',
moveExpeditionButton: 'vn-ticket-expedition vn-tool-bar > vn-button[icon="keyboard_arrow_down"]', moveExpeditionButton: 'vn-ticket-expedition slot-actions > vn-button[icon="keyboard_arrow_down"]',
moreMenuWithoutRoute: 'vn-item[name="withoutRoute"]', moreMenuWithoutRoute: 'vn-item[name="withoutRoute"]',
moreMenuWithRoute: 'vn-item[name="withRoute"]', moreMenuWithRoute: 'vn-item[name="withRoute"]',
newRouteId: '.vn-dialog.shown vn-textfield[ng-model="$ctrl.newRoute"]', newRouteId: '.vn-dialog.shown vn-textfield[ng-model="$ctrl.newRoute"]',
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 table tbody > tr'
}, },
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',
@ -595,6 +595,8 @@ export default {
moreMenuUpdateDiscount: 'vn-item[name="discount"]', moreMenuUpdateDiscount: 'vn-item[name="discount"]',
moreMenuRecalculatePrice: 'vn-item[name="calculatePrice"]', moreMenuRecalculatePrice: 'vn-item[name="calculatePrice"]',
moreMenuRefund: 'vn-item[name="refund"]', moreMenuRefund: 'vn-item[name="refund"]',
refundWithWarehouse: 'vn-item[name="refundWithWarehouse"]',
refundWithoutWarehouse: 'vn-item[name="refundWithoutWarehouse"]',
moreMenuUpdateDiscountInput: 'vn-input-number[ng-model="$ctrl.edit.discount"] input', moreMenuUpdateDiscountInput: 'vn-input-number[ng-model="$ctrl.edit.discount"] input',
transferQuantityInput: '.vn-popover.shown vn-table > div > vn-tbody > vn-tr > vn-td-editable > span > text', transferQuantityInput: '.vn-popover.shown vn-table > div > vn-tbody > vn-tr > vn-td-editable > span > text',
transferQuantityCell: '.vn-popover.shown vn-table > div > vn-tbody > vn-tr > vn-td-editable', transferQuantityCell: '.vn-popover.shown vn-table > div > vn-tbody > vn-tr > vn-td-editable',
@ -625,6 +627,7 @@ export default {
selectAllSalesCheckbox: 'vn-ticket-sale vn-thead vn-check', selectAllSalesCheckbox: 'vn-ticket-sale vn-thead vn-check',
secondSaleCheckbox: 'vn-ticket-sale vn-tr:nth-child(2) vn-check[ng-model="sale.checked"]', secondSaleCheckbox: 'vn-ticket-sale vn-tr:nth-child(2) vn-check[ng-model="sale.checked"]',
thirdSaleCheckbox: 'vn-ticket-sale vn-tr:nth-child(3) vn-check[ng-model="sale.checked"]', thirdSaleCheckbox: 'vn-ticket-sale vn-tr:nth-child(3) vn-check[ng-model="sale.checked"]',
fourthSaleCheckbox: 'vn-ticket-sale vn-tr:nth-child(4) vn-check[ng-model="sale.checked"]',
deleteSaleButton: 'vn-ticket-sale vn-tool-bar > vn-button[icon="delete"]', deleteSaleButton: 'vn-ticket-sale vn-tool-bar > vn-button[icon="delete"]',
transferSaleButton: 'vn-ticket-sale vn-tool-bar > vn-button[icon="call_split"]', transferSaleButton: 'vn-ticket-sale vn-tool-bar > vn-button[icon="call_split"]',
moveToTicketInput: 'form vn-input-number[ng-model="$ctrl.transfer.ticketId"] input', moveToTicketInput: 'form vn-input-number[ng-model="$ctrl.transfer.ticketId"] input',

View File

@ -64,6 +64,6 @@ describe('SmartTable SearchBar integration', () => {
await page.reload({ await page.reload({
waitUntil: 'networkidle2' waitUntil: 'networkidle2'
}); });
await page.waitForTextInField(selectors.itemFixedPrice.firstItemID, '13'); await page.waitForTextInField(selectors.itemFixedPrice.firstItemID, '3');
}); });
}); });

View File

@ -0,0 +1,71 @@
import getBrowser from '../../helpers/puppeteer';
const $ = {
form: 'vn-out-layout form'
};
describe('ChangePassword path', async() => {
let browser;
let page;
beforeAll(async() => {
browser = await getBrowser();
page = browser.page;
});
afterAll(async() => {
await browser.close();
});
const oldPassword = 'nightmare';
const newPassword = 'newPass.1234';
describe('Bad login', async() => {
it('should receive an error when the password is expired', async() => {
// Expired login
await page.doLogin('Maintenance', oldPassword);
let message = await page.waitForSnackbar();
expect(message.text).toContain('The password has expired, change it from Salix');
expect(await page.getState()).toContain('change-password');
// Bad attempt: incorrect current password
message = await page.sendForm($.form, {
oldPassword: newPassword,
newPassword: oldPassword,
repeatPassword: oldPassword
});
expect(message.text).toContain('Invalid current password');
// Bad attempt: password not meet requirements
message = await page.sendForm($.form, {
oldPassword: oldPassword,
newPassword: oldPassword,
repeatPassword: oldPassword
});
expect(message.text).toContain('Password does not meet requirements');
// Correct attempt: change password
message = await page.sendForm($.form, {
oldPassword: oldPassword,
newPassword: newPassword,
repeatPassword: newPassword
});
expect(message.text).toContain('Password updated!');
expect(await page.getState()).toContain('login');
// Bad login, old password
await page.doLogin('Maintenance', oldPassword);
message = await page.waitForSnackbar();
expect(message.text).toContain('Invalid login');
// Correct login, new password
await page.doLogin('Maintenance', newPassword);
await page.waitForSelector('vn-home');
expect(await page.getState()).toBe('home');
});
});
});

View File

@ -88,7 +88,8 @@ describe('Item fixed prices path', () => {
it('should reload the section and check the created price has the expected ID', async() => { it('should reload the section and check the created price has the expected ID', async() => {
await page.goto(`http://localhost:5000/#!/item/fixed-price`); await page.goto(`http://localhost:5000/#!/item/fixed-price`);
await page.autocompleteSearch($.warehouseFilter, 'Warehouse one');
await page.click($.chip);
const result = await page.waitToGetProperty($.fourthItemID, 'value'); const result = await page.waitToGetProperty($.fourthItemID, 'value');
expect(result).toContain('13'); expect(result).toContain('13');

View File

@ -220,14 +220,25 @@ describe('Ticket Edit sale path', () => {
it('should log in as salesAssistant and navigate to ticket sales', async() => { it('should log in as salesAssistant and navigate to ticket sales', async() => {
await page.loginAndModule('salesAssistant', 'ticket'); await page.loginAndModule('salesAssistant', 'ticket');
await page.accessToSearchResult('16'); await page.accessToSearchResult('17');
await page.accessToSection('ticket.card.sale'); await page.accessToSection('ticket.card.sale');
}); });
it('should select the third sale and create a refund', async() => { it('should select the first sale and create a refund with warehouse', async() => {
await page.waitToClick(selectors.ticketSales.firstSaleCheckbox); await page.waitToClick(selectors.ticketSales.firstSaleCheckbox);
await page.waitToClick(selectors.ticketSales.moreMenu); await page.waitToClick(selectors.ticketSales.moreMenu);
await page.waitToClick(selectors.ticketSales.moreMenuRefund); await page.waitToClick(selectors.ticketSales.moreMenuRefund);
await page.waitToClick(selectors.ticketSales.refundWithWarehouse);
await page.waitForSnackbar();
await page.waitForState('ticket.card.sale');
});
it('should select the first sale and create a refund without warehouse', async() => {
await page.accessToSearchResult('18');
await page.waitToClick(selectors.ticketSales.firstSaleCheckbox);
await page.waitToClick(selectors.ticketSales.moreMenu);
await page.waitToClick(selectors.ticketSales.moreMenuRefund);
await page.waitToClick(selectors.ticketSales.refundWithoutWarehouse);
await page.waitForSnackbar(); await page.waitForSnackbar();
await page.waitForState('ticket.card.sale'); await page.waitForState('ticket.card.sale');
}); });
@ -246,12 +257,10 @@ describe('Ticket Edit sale path', () => {
it('should select the third sale and create a claim of it', async() => { it('should select the third sale and create a claim of it', async() => {
await page.accessToSearchResult('16'); await page.accessToSearchResult('16');
await page.accessToSection('ticket.card.sale'); await page.accessToSection('ticket.card.sale');
await page.waitToClick(selectors.ticketSales.firstSaleCheckbox);
await page.waitToClick(selectors.ticketSales.thirdSaleCheckbox); await page.waitToClick(selectors.ticketSales.thirdSaleCheckbox);
await page.waitToClick(selectors.ticketSales.moreMenu); await page.waitToClick(selectors.ticketSales.moreMenu);
await page.waitToClick(selectors.ticketSales.moreMenuCreateClaim); await page.waitToClick(selectors.ticketSales.moreMenuCreateClaim);
await page.waitToClick(selectors.globalItems.acceptButton); await page.waitToClick(selectors.globalItems.acceptButton);
await page.waitToClick(selectors.globalItems.acceptButton);
await page.waitForState('claim.card.basicData'); await page.waitForState('claim.card.basicData');
}); });
@ -317,7 +326,7 @@ describe('Ticket Edit sale path', () => {
it('should confirm the transfered quantity is the correct one', async() => { it('should confirm the transfered quantity is the correct one', async() => {
const result = await page.waitToGetProperty(selectors.ticketSales.secondSaleQuantityCell, 'innerText'); const result = await page.waitToGetProperty(selectors.ticketSales.secondSaleQuantityCell, 'innerText');
expect(result).toContain('10'); expect(result).toContain('20');
}); });
it('should go back to the original ticket sales section', async() => { it('should go back to the original ticket sales section', async() => {

View File

@ -1,8 +1,7 @@
import selectors from '../../helpers/selectors.js'; import selectors from '../../helpers/selectors.js';
import getBrowser from '../../helpers/puppeteer'; import getBrowser from '../../helpers/puppeteer';
// 'https:// redmine.verdnatura.es/issues/5642' describe('Ticket Future path', () => {
xdescribe('Ticket Future path', () => {
let browser; let browser;
let page; let page;
let httpRequest; let httpRequest;
@ -22,7 +21,7 @@ xdescribe('Ticket Future path', () => {
await browser.close(); await browser.close();
}); });
it('should show errors snackbar because of the required data', async() => { it('should search with required data, check three last tickets and move to the future', async() => {
await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton); await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
await page.clearInput(selectors.ticketFuture.warehouseFk); await page.clearInput(selectors.ticketFuture.warehouseFk);
await page.waitToClick(selectors.ticketFuture.submit); await page.waitToClick(selectors.ticketFuture.submit);
@ -43,69 +42,58 @@ xdescribe('Ticket Future path', () => {
message = await page.waitForSnackbar(); message = await page.waitForSnackbar();
expect(message.text).toContain('originDated is a required argument'); expect(message.text).toContain('originDated is a required argument');
await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
await page.waitToClick(selectors.ticketFuture.submit);
expect(httpRequest).toBeDefined();
await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
await page.autocompleteSearch(selectors.ticketFuture.ipt, 'H');
await page.waitToClick(selectors.ticketFuture.submit);
expect(httpRequest).toContain('ipt=H');
await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
await page.clearInput(selectors.ticketFuture.ipt);
await page.autocompleteSearch(selectors.ticketFuture.futureIpt, 'H');
await page.waitToClick(selectors.ticketFuture.submit);
expect(httpRequest).toContain('futureIpt=H');
await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
await page.clearInput(selectors.ticketFuture.futureIpt);
await page.autocompleteSearch(selectors.ticketFuture.state, 'Free');
await page.waitToClick(selectors.ticketFuture.submit);
expect(httpRequest).toContain('state=FREE');
await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
await page.clearInput(selectors.ticketFuture.state);
await page.autocompleteSearch(selectors.ticketFuture.futureState, 'Free');
await page.waitToClick(selectors.ticketFuture.submit);
expect(httpRequest).toContain('futureState=FREE');
await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
await page.clearInput(selectors.ticketFuture.state);
await page.clearInput(selectors.ticketFuture.futureState);
await page.waitToClick(selectors.ticketFuture.submit);
await page.waitForNumberOfElements(selectors.ticketFuture.searchResult, 4);
await page.waitToClick(selectors.ticketFuture.multiCheck);
await page.waitToClick(selectors.ticketFuture.firstCheck);
await page.waitToClick(selectors.ticketFuture.moveButton);
await page.waitToClick(selectors.globalItems.acceptButton);
message = await page.waitForSnackbar();
expect(message.text).toContain('Tickets moved successfully!');
}); });
// it('should search with the required data', async() => {
// await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
// await page.waitToClick(selectors.ticketFuture.submit);
// expect(httpRequest).toBeDefined();
// });
// it('should search with the origin IPT', async() => {
// await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
// await page.autocompleteSearch(selectors.ticketFuture.ipt, 'H');
// await page.waitToClick(selectors.ticketFuture.submit);
// expect(httpRequest).toContain('ipt=H');
// });
// it('should search with the destination IPT', async() => {
// await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
// await page.clearInput(selectors.ticketFuture.ipt);
// await page.autocompleteSearch(selectors.ticketFuture.futureIpt, 'H');
// await page.waitToClick(selectors.ticketFuture.submit);
// expect(httpRequest).toContain('futureIpt=H');
// });
// it('should search with the origin grouped state', async() => {
// await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
// await page.clearInput(selectors.ticketFuture.futureIpt);
// await page.autocompleteSearch(selectors.ticketFuture.state, 'Free');
// await page.waitToClick(selectors.ticketFuture.submit);
// expect(httpRequest).toContain('state=FREE');
// });
// it('should search with the destination grouped state', async() => {
// await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
// await page.clearInput(selectors.ticketFuture.state);
// await page.autocompleteSearch(selectors.ticketFuture.futureState, 'Free');
// await page.waitToClick(selectors.ticketFuture.submit);
// expect(httpRequest).toContain('futureState=FREE');
// await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
// await page.clearInput(selectors.ticketFuture.futureState);
// await page.waitToClick(selectors.ticketFuture.submit);
// });
// it('should check the three last tickets and move to the future', async() => {
// await page.waitForNumberOfElements(selectors.ticketFuture.searchResult, 4);
// await page.waitToClick(selectors.ticketFuture.multiCheck);
// await page.waitToClick(selectors.ticketFuture.firstCheck);
// await page.waitToClick(selectors.ticketFuture.moveButton);
// await page.waitToClick(selectors.globalItems.acceptButton);
// const message = await page.waitForSnackbar();
// expect(message.text).toContain('Tickets moved successfully!');
// });
}); });

View File

@ -1,8 +1,7 @@
import selectors from '../../helpers/selectors.js'; import selectors from '../../helpers/selectors.js';
import getBrowser from '../../helpers/puppeteer'; import getBrowser from '../../helpers/puppeteer';
// 'https:// redmine.verdnatura.es/issues/5642' describe('Ticket Advance path', () => {
xdescribe('Ticket Advance path', () => {
let browser; let browser;
let page; let page;
let httpRequest; let httpRequest;
@ -22,7 +21,7 @@ xdescribe('Ticket Advance path', () => {
await browser.close(); await browser.close();
}); });
it('should show errors snackbar because of the required data', async() => { it('should search with the required data, check the first ticket and move to the present', async() => {
await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton); await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
await page.clearInput(selectors.ticketAdvance.warehouseFk); await page.clearInput(selectors.ticketAdvance.warehouseFk);
@ -44,45 +43,37 @@ xdescribe('Ticket Advance path', () => {
message = await page.waitForSnackbar(); message = await page.waitForSnackbar();
expect(message.text).toContain('dateFuture is a required argument'); expect(message.text).toContain('dateFuture is a required argument');
await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
await page.waitToClick(selectors.ticketAdvance.submit);
expect(httpRequest).toBeDefined();
await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
await page.autocompleteSearch(selectors.ticketAdvance.futureIpt, 'H');
await page.waitToClick(selectors.ticketAdvance.submit);
expect(httpRequest).toContain('futureIpt=H');
await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
await page.clearInput(selectors.ticketAdvance.futureIpt);
await page.waitToClick(selectors.ticketAdvance.submit);
await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
await page.autocompleteSearch(selectors.ticketAdvance.ipt, 'H');
await page.waitToClick(selectors.ticketAdvance.submit);
expect(httpRequest).toContain('ipt=H');
await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
await page.clearInput(selectors.ticketAdvance.ipt);
await page.waitToClick(selectors.ticketAdvance.submit);
await page.waitToClick(selectors.ticketAdvance.firstCheck);
await page.waitToClick(selectors.ticketAdvance.moveButton);
await page.waitToClick(selectors.ticketAdvance.acceptButton);
message = await page.waitForSnackbar();
expect(message.text).toContain('Tickets moved successfully!');
}); });
// it('should search with the required data', async() => {
// await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
// await page.waitToClick(selectors.ticketAdvance.submit);
// expect(httpRequest).toBeDefined();
// });
// it('should search with the origin IPT', async() => {
// await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
// await page.autocompleteSearch(selectors.ticketAdvance.futureIpt, 'H');
// await page.waitToClick(selectors.ticketAdvance.submit);
// expect(httpRequest).toContain('futureIpt=H');
// await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
// await page.clearInput(selectors.ticketAdvance.futureIpt);
// await page.waitToClick(selectors.ticketAdvance.submit);
// });
// it('should search with the destination IPT', async() => {
// await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
// await page.autocompleteSearch(selectors.ticketAdvance.ipt, 'H');
// await page.waitToClick(selectors.ticketAdvance.submit);
// expect(httpRequest).toContain('ipt=H');
// await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
// await page.clearInput(selectors.ticketAdvance.ipt);
// await page.waitToClick(selectors.ticketAdvance.submit);
// });
// it('should check the first ticket and move to the present', async() => {
// await page.waitToClick(selectors.ticketAdvance.firstCheck);
// await page.waitToClick(selectors.ticketAdvance.moveButton);
// await page.waitToClick(selectors.ticketAdvance.acceptButton);
// const message = await page.waitForSnackbar();
// expect(message.text).toContain('Tickets moved successfully!');
// });
}); });

View File

@ -17,7 +17,7 @@ describe('Claim summary path', () => {
}); });
it('should navigate to the target claim summary section', async() => { it('should navigate to the target claim summary section', async() => {
await page.loginAndModule('employee', 'claim'); await page.loginAndModule('salesPerson', 'claim');
await page.accessToSearchResult(claimId); await page.accessToSearchResult(claimId);
await page.waitForState('claim.card.summary'); await page.waitForState('claim.card.summary');
}); });
@ -49,7 +49,11 @@ describe('Claim summary path', () => {
}); });
it(`should click on the first sale ID making the item descriptor visible`, async() => { it(`should click on the first sale ID making the item descriptor visible`, async() => {
await page.waitToClick(selectors.claimSummary.firstSaleItemId); const firstItem = selectors.claimSummary.firstSaleItemId;
await page.evaluate(selectors => {
document.querySelector(selectors).scrollIntoView();
}, firstItem);
await page.click(firstItem);
await page.waitImgLoad(selectors.claimSummary.firstSaleDescriptorImage); await page.waitImgLoad(selectors.claimSummary.firstSaleDescriptorImage);
const visible = await page.isVisible(selectors.claimSummary.itemDescriptorPopover); const visible = await page.isVisible(selectors.claimSummary.itemDescriptorPopover);

View File

@ -16,7 +16,7 @@ describe('Claim descriptor path', () => {
}); });
it('should now navigate to the target claim summary section', async() => { it('should now navigate to the target claim summary section', async() => {
await page.loginAndModule('employee', 'claim'); await page.loginAndModule('salesPerson', 'claim');
await page.accessToSearchResult(claimId); await page.accessToSearchResult(claimId);
await page.waitForState('claim.card.summary'); await page.waitForState('claim.card.summary');
}); });

View File

@ -24,7 +24,7 @@ export default class Auth {
initialize() { initialize() {
let criteria = { let criteria = {
to: state => { to: state => {
const outLayout = ['login', 'recover-password', 'reset-password']; const outLayout = ['login', 'recover-password', 'reset-password', 'change-password'];
return !outLayout.some(ol => ol == state.name); return !outLayout.some(ol => ol == state.name);
} }
}; };
@ -59,8 +59,8 @@ export default class Auth {
password: password || undefined password: password || undefined
}; };
return this.$http.post('VnUsers/signIn', params).then( return this.$http.post('VnUsers/signIn', params)
json => this.onLoginOk(json, remember)); .then(json => this.onLoginOk(json, remember));
} }
onLoginOk(json, remember) { onLoginOk(json, remember) {

View File

@ -1,4 +1,11 @@
@import "./variables";
@import "./effects";
@mixin mobile {
@media screen and (max-width: $mobile-width) {
@content;
}
}
@mixin browser($browser) { @mixin browser($browser) {
html[data-browser*="#{$browser}"] & { html[data-browser*="#{$browser}"] & {
@content; @content;

View File

@ -1,5 +1,3 @@
@import "./util";
$font-size: 11pt; $font-size: 11pt;
$menu-width: 256px; $menu-width: 256px;
$topbar-height: 56px; $topbar-height: 56px;

View File

@ -1,4 +1,4 @@
@import "variables"; @import "util";
@keyframes fadein { @keyframes fadein {
from { from {
@ -16,7 +16,7 @@ vn-background {
background-color: black; background-color: black;
z-index: 14; z-index: 14;
@media screen and (max-width: $mobile-width) { @include mobile {
&.shown { &.shown {
display: block; display: block;
opacity: .3; opacity: .3;

View File

@ -0,0 +1,29 @@
<h5 class="vn-mb-md vn-mt-lg" translate>Change password</h5>
<vn-textfield
label="Old password"
ng-model="$ctrl.oldPassword"
vn-name="oldPassword"
type="password"
vn-focus>
</vn-textfield>
<vn-textfield
label="New password"
ng-model="$ctrl.newPassword"
vn-name="newPassword"
type="password"
info="{{'Password requirements' | translate:$ctrl.passRequirements}}"
autocomplete="false">
</vn-textfield>
<vn-textfield
label="Repeat password"
ng-model="$ctrl.repeatPassword"
vn-name="repeatPassword"
type="password"
autocomplete="false">
</vn-textfield>
<div class="footer">
<vn-submit label="Change password" ng-click="$ctrl.submit()"></vn-submit>
<div class="spinner-wrapper">
<vn-spinner enable="$ctrl.loading"></vn-spinner>
</div>
</div>

View File

@ -0,0 +1,63 @@
import ngModule from '../../module';
const UserError = require('vn-loopback/util/user-error');
export default class Controller {
constructor($scope, $element, $http, vnApp, $translate, $state, $location) {
Object.assign(this, {
$scope,
$element,
$http,
vnApp,
$translate,
$state,
$location
});
}
$onInit() {
if (!this.$state.params || !this.$state.params.id || !this.$state.params.token)
this.$state.go('login');
this.$http.get('UserPasswords/findOne')
.then(res => {
this.passRequirements = res.data;
});
}
submit() {
const id = this.$state.params.id;
const newPassword = this.newPassword;
const oldPassword = this.oldPassword;
if (!newPassword)
throw new UserError(`You must enter a new password`);
if (newPassword != this.repeatPassword)
throw new UserError(`Passwords don't match`);
const headers = {
Authorization: this.$state.params.token
};
this.$http.post('VnUsers/change-password',
{
id,
oldPassword,
newPassword
},
{headers}
).then(() => {
this.vnApp.showSuccess(this.$translate.instant('Password updated!'));
this.$state.go('login');
});
}
}
Controller.$inject = ['$scope', '$element', '$http', 'vnApp', '$translate', '$state', '$location'];
ngModule.vnComponent('vnChangePassword', {
template: require('./index.html'),
controller: Controller,
bindings: {
id: '<'
}
});

View File

@ -0,0 +1,4 @@
Password requirements: >
The password must have at least {{ length }} length characters,
{{nAlpha}} alphabetic characters, {{nUpper}} capital letters, {{nDigits}}
digits and {{nPunct}} symbols (Ex: $%&.)

View File

@ -0,0 +1,9 @@
Change password: Cambiar contraseña
Old password: Antigua contraseña
New password: Nueva contraseña
Repeat password: Repetir contraseña
Password updated!: ¡Contraseña actualizada!
Password requirements: >
La contraseña debe tener al menos {{ length }} caracteres de longitud,
{{nAlpha}} caracteres alfabéticos, {{nUpper}} letras mayúsculas, {{nDigits}}
dígitos y {{nPunct}} símbolos (Ej: $%&.)

View File

@ -7,22 +7,24 @@ vn-descriptor-content {
.photo { .photo {
position: relative; position: relative;
width: 100%;
text-align: center;
overflow: hidden;
& > img[ng-src] { & > img[ng-src] {
min-height: 16em; min-height: 16em;
display: block; display: block;
max-width: 100%;
height: 256px; height: 256px;
} }
vn-float-button { vn-float-button {
position: absolute; position: absolute;
margin: 1em; margin: 1em;
bottom: 0; bottom: 0;
right: 0 right: 0
} }
} }
& > vn-spinner { & > vn-spinner {
display: block; display: block;
height: 40px; height: 40px;
@ -39,7 +41,7 @@ vn-descriptor-content {
align-items: stretch; align-items: stretch;
color: $color-font-dark; color: $color-font-dark;
& > a, & > a,
& > vn-icon-button { & > vn-icon-button {
display: flex; display: flex;
min-width: 45px; min-width: 45px;
@ -89,7 +91,7 @@ vn-descriptor-content {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
& > vn-icon { & > vn-icon {
padding: $spacing-xs $spacing-sm; padding: $spacing-xs $spacing-sm;
font-size: 1.5rem; font-size: 1.5rem;

View File

@ -9,6 +9,7 @@ import './login';
import './outLayout'; import './outLayout';
import './recover-password'; import './recover-password';
import './reset-password'; import './reset-password';
import './change-password';
import './module-card'; import './module-card';
import './module-main'; import './module-main';
import './side-menu/side-menu'; import './side-menu/side-menu';

View File

@ -1,4 +1,4 @@
@import "effects"; @import "util";
vn-layout { vn-layout {
& > vn-topbar { & > vn-topbar {
@ -134,7 +134,7 @@ vn-layout {
border-radius: 50%; border-radius: 50%;
} }
} }
@media screen and (max-width: $mobile-width) { @include mobile {
& > vn-topbar { & > vn-topbar {
& > .start > .logo { & > .start > .logo {
display: none; display: none;

View File

@ -16,7 +16,7 @@
</vn-crud-model> </vn-crud-model>
<vn-data-viewer <vn-data-viewer
model="model" model="model"
class="vn-w-sm vn-px-sm"> class="vn-w-sm vn-px-sm vn-pb-xl">
<div class="change vn-mb-sm" ng-repeat="log in $ctrl.logs"> <div class="change vn-mb-sm" ng-repeat="log in $ctrl.logs">
<div class="left"> <div class="left">
<vn-avatar class="vn-mt-xs" <vn-avatar class="vn-mt-xs"
@ -33,17 +33,6 @@
</div> </div>
<vn-card class="detail"> <vn-card class="detail">
<div class="header vn-pa-sm"> <div class="header vn-pa-sm">
<div
class="action-date text-secondary text-caption vn-mr-sm"
title="{{::log.creationDate | date:'dd/MM/yyyy HH:mm:ss'}}">
<vn-icon
class="action vn-mr-xs"
ng-class="::$ctrl.actionsClass[log.action]"
icon="{{::$ctrl.actionsIcon[log.action]}}"
translate-attr="::{title: $ctrl.actionsText[log.action]}">
</vn-icon>
{{::$ctrl.relativeDate(log.creationDate)}}
</div>
<div class="action-model"> <div class="action-model">
<span class="model-name" <span class="model-name"
ng-if="::$ctrl.showModelName && log.changedModel" ng-if="::$ctrl.showModelName && log.changedModel"
@ -52,13 +41,27 @@
{{::log.changedModelI18n}} {{::log.changedModelI18n}}
</span> </span>
</div> </div>
<div
class="action-date text-secondary text-caption vn-ml-sm"
title="{{::log.creationDate | date:'dd/MM/yyyy HH:mm:ss'}}">
{{::$ctrl.relativeDate(log.creationDate)}}
<vn-icon
class="action vn-ml-xs"
ng-class="::$ctrl.actionsClass[log.action]"
icon="{{::$ctrl.actionsIcon[log.action]}}"
translate-attr="::{title: $ctrl.actionsText[log.action]}">
</vn-icon>
</div>
</div> </div>
<div <div class="model vn-pb-sm vn-px-sm"
class="model vn-pb-sm vn-px-sm" ng-if="::$ctrl.showModelName">
title="{{::log.changedModelValue}}"
ng-if="::log.changedModelId || log.changedModelValue">
<span class="model-id" ng-if="::log.changedModelId">#{{::log.changedModelId}}</span> <span class="model-id" ng-if="::log.changedModelId">#{{::log.changedModelId}}</span>
<span class="model-value">{{::log.changedModelValue}}</span> <vn-icon
icon="filter_alt"
translate-attr="{title: 'Show all record changes'}"
ng-click="$ctrl.filterByEntity(log)">
</vn-icon>
<span class="model-value" title="{{::log.changedModelValue}}">{{::log.changedModelValue}}</span>
</div> </div>
<div class="changes vn-pa-sm" <div class="changes vn-pa-sm"
ng-class="{expanded: log.expand}" ng-class="{expanded: log.expand}"
@ -96,10 +99,36 @@
</div> </div>
</div> </div>
</vn-data-viewer> </vn-data-viewer>
<vn-float-button
ng-if="model.userFilter"
icon="filter_alt_off"
translate-attr="{title: 'Quit filter'}"
ng-click="$ctrl.resetFilter()"
fixed-bottom-right>
</vn-float-button>
<vn-side-menu side="right"> <vn-side-menu side="right">
<form vn-vertical <form vn-vertical
ng-model-options="{updateOn: 'change blur'}" ng-model-options="{updateOn: 'change blur'}"
class="vn-pa-md filter"> class="vn-pa-md filter">
<vn-textfield
label="Search"
ng-model="filter.search">
<append>
<vn-icon
icon="info_outline"
vn-tooltip="Search by id or concept"
pointer>
</vn-icon>
</append>
</vn-textfield>
<vn-autocomplete
label="Entity"
ng-model="filter.changedModel"
value-field="changedModel"
show-field="changedModelI18n"
data="$ctrl.models"
class="changed-model">
</vn-autocomplete>
<vn-vertical> <vn-vertical>
<vn-radio <vn-radio
label="All" label="All"
@ -145,30 +174,16 @@
</tpl-item> </tpl-item>
</vn-autocomplete> </vn-autocomplete>
<vn-textfield <vn-textfield
label="Search" label="Changes"
ng-model="filter.search"> ng-model="filter.changes">
<append> <append>
<vn-icon <vn-icon
icon="info_outline" icon="info_outline"
vn-tooltip="Search by id or concept" vn-tooltip="Search by changes"
pointer> pointer>
</vn-icon> </vn-icon>
</append> </append>
</vn-textfield> </vn-textfield>
<vn-autocomplete
label="Entity"
ng-model="filter.changedModel"
value-field="changedModel"
show-field="changedModelI18n"
data="$ctrl.models"
class="changed-model">
</vn-autocomplete>
<!-- FIXME: Cannot use LIKE with JSON columns
<vn-textfield
label="Changes"
ng-model="filter.changes">
</vn-textfield>
-->
<vn-vertical> <vn-vertical>
<vn-check <vn-check
label="Creates" label="Creates"
@ -195,18 +210,6 @@
label="To" label="To"
ng-model="filter.to"> ng-model="filter.to">
</vn-date-picker> </vn-date-picker>
<vn-button-bar vn-vertical>
<vn-button
label="Filter"
ng-click="$ctrl.applyFilter(filter)">
</vn-button>
<vn-button
label="Reset"
class="flat"
ng-click="$ctrl.resetFilter()"
ng-if="model.userFilter">
</vn-button>
</vn-button-bar>
</form> </form>
</vn-side-menu> </vn-side-menu>
<vn-worker-descriptor-popover vn-id="workerDescriptor"> <vn-worker-descriptor-popover vn-id="workerDescriptor">

View File

@ -164,14 +164,15 @@ export default class Controller extends Section {
if (value == null || value == '') return null; if (value == null || value == '') return null;
switch (prop) { switch (prop) {
case 'search': case 'search':
if (/^[0-9]+$/.test(value)) const or = [];
return {changedModelId: value}; if (/^\s*[0-9]+\s*$/.test(value))
return {changedModelId: value.trim()};
else else
return {changedModelValue: {like: `%${value}%`}}; return {changedModelValue: {like: `%${value}%`}};
case 'changes': case 'changes':
return {or: [ return {or: [
{oldInstance: {like: `%${value}%`}}, {oldJson: {like: `%${value}%`}},
{newInstance: {like: `%${value}%`}}, {newJson: {like: `%${value}%`}},
{description: {like: `%${value}%`}} {description: {like: `%${value}%`}}
]}; ]};
case 'who': case 'who':
@ -220,6 +221,14 @@ export default class Controller extends Section {
return this.$.model.applyFilter(lbFilter); return this.$.model.applyFilter(lbFilter);
} }
filterByEntity(log) {
this.$.filter = {
who: 'all',
search: log.changedModelId,
changedModel: log.changedModel
};
}
searchUser(search) { searchUser(search) {
if (/^[0-9]+$/.test(search)) { if (/^[0-9]+$/.test(search)) {
return {id: search}; return {id: search};

View File

@ -2,6 +2,9 @@ Date: Fecha
Concept: Concepto Concept: Concepto
Search: Buscar Search: Buscar
Search by id or concept: Buscar por identificador o concepto Search by id or concept: Buscar por identificador o concepto
Search by changes: |
Buscar por cambios. Los atributos deben buscarse por su nombre interno,
para obtenerlo situar el cursor sobre el atributo.
Entity: Entidad Entity: Entidad
Action: Acción Action: Acción
Author: Autor Author: Autor
@ -13,9 +16,12 @@ Creates: Crea
Edits: Modifica Edits: Modifica
Deletes: Elimina Deletes: Elimina
Accesses: Accede Accesses: Accede
All: Todo
System: Sistema System: Sistema
Details: Detalles Details: Detalles
note: nota note: nota
Changes: Cambios Changes: Cambios
today: hoy today: hoy
yesterday: ayer yesterday: ayer
Show all record changes: Mostrar todos los cambios realizados en el registro
Quit filter: Quitar filtro

View File

@ -1,5 +1,4 @@
@import "variables"; @import "util";
@import "effects";
vn-log { vn-log {
.change { .change {
@ -77,7 +76,7 @@ vn-log {
border-radius: 50%; border-radius: 50%;
width: 24px; width: 24px;
height: 24px; height: 24px;
font-size: 1.4em; font-size: 18px;
&.notice { &.notice {
background-color: $color-notice-medium background-color: $color-notice-medium
@ -98,7 +97,22 @@ vn-log {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
max-height: 18px;
& > vn-icon {
@extend %clickable-light;
vertical-align: middle;
padding: 2px;
margin: -2px;
font-size: 18px;
color: $color-font-secondary;
float: right;
display: none;
@include mobile {
display: initial;
}
}
& > .model-value { & > .model-value {
font-style: italic; font-style: italic;
} }
@ -107,6 +121,9 @@ vn-log {
font-size: .9rem; font-size: .9rem;
} }
} }
&:hover > .model > vn-icon {
display: initial;
}
} }
} }
.changes { .changes {

View File

@ -5,10 +5,11 @@ import './style.scss';
* A simple login form. * A simple login form.
*/ */
export default class Controller { export default class Controller {
constructor($, $element, vnAuth) { constructor($, $element, $state, vnAuth) {
Object.assign(this, { Object.assign(this, {
$, $,
$element, $element,
$state,
vnAuth, vnAuth,
user: localStorage.getItem('lastUser'), user: localStorage.getItem('lastUser'),
remember: true remember: true
@ -22,11 +23,16 @@ export default class Controller {
localStorage.setItem('lastUser', this.user); localStorage.setItem('lastUser', this.user);
this.loading = false; this.loading = false;
}) })
.catch(err => { .catch(req => {
this.loading = false; this.loading = false;
this.password = ''; this.password = '';
this.focusUser(); this.focusUser();
throw err; if (req?.data?.error?.code == 'passExpired') {
const [args] = req.data.error.translateArgs;
this.$state.go('change-password', args);
}
throw req;
}); });
} }
@ -35,7 +41,7 @@ export default class Controller {
this.$.userField.focus(); this.$.userField.focus();
} }
} }
Controller.$inject = ['$scope', '$element', 'vnAuth']; Controller.$inject = ['$scope', '$element', '$state', 'vnAuth'];
ngModule.vnComponent('vnLogin', { ngModule.vnComponent('vnLogin', {
template: require('./index.html'), template: require('./index.html'),

View File

@ -64,4 +64,25 @@ vn-out-layout{
a{ a{
color: $color-primary; color: $color-primary;
} }
.footer {
margin-top: 32px;
text-align: center;
position: relative;
& > .vn-submit {
display: block;
& > input {
display: block;
width: 100%;
}
}
& > .spinner-wrapper {
position: absolute;
width: 0;
top: 3px;
right: -8px;
overflow: visible;
}
}
} }

View File

@ -1,5 +1,4 @@
import ngModule from '../../module'; import ngModule from '../../module';
import './style.scss';
export default class Controller { export default class Controller {
constructor($scope, $element, $http, vnApp, $translate, $state) { constructor($scope, $element, $http, vnApp, $translate, $state) {

View File

@ -1,24 +0,0 @@
@import "variables";
vn-recover-password{
.footer {
margin-top: 32px;
text-align: center;
position: relative;
& > .vn-submit {
display: block;
& > input {
display: block;
width: 100%;
}
}
& > .spinner-wrapper {
position: absolute;
width: 0;
top: 3px;
right: -8px;
overflow: visible;
}
}
}

View File

@ -1,5 +1,5 @@
import ngModule from '../../module'; import ngModule from '../../module';
import './style.scss'; const UserError = require('vn-loopback/util/user-error');
export default class Controller { export default class Controller {
constructor($scope, $element, $http, vnApp, $translate, $state, $location) { constructor($scope, $element, $http, vnApp, $translate, $state, $location) {

View File

@ -1,24 +0,0 @@
@import "variables";
vn-reset-password{
.footer {
margin-top: 32px;
text-align: center;
position: relative;
& > .vn-submit {
display: block;
& > input {
display: block;
width: 100%;
}
}
& > .spinner-wrapper {
position: absolute;
width: 0;
top: 3px;
right: -8px;
overflow: visible;
}
}
}

View File

@ -20,8 +20,6 @@ class Controller {
name: config.languages[code] ? config.languages[code] : code name: config.languages[code] ? config.languages[code] : code
}); });
} }
vnConfig.initialize();
} }
set lang(value) { set lang(value) {

View File

@ -10,6 +10,9 @@ function config($stateProvider, $urlRouterProvider) {
.state('layout', { .state('layout', {
abstract: true, abstract: true,
template: '<vn-layout></vn-layout>', template: '<vn-layout></vn-layout>',
resolve: {
config: ['vnConfig', vnConfig => vnConfig.initialize()]
}
}) })
.state('outLayout', { .state('outLayout', {
abstract: true, abstract: true,
@ -33,6 +36,12 @@ function config($stateProvider, $urlRouterProvider) {
description: 'Reset password', description: 'Reset password',
template: '<vn-reset-password></vn-reset-password>' template: '<vn-reset-password></vn-reset-password>'
}) })
.state('change-password', {
parent: 'outLayout',
url: '/change-password?id&token',
description: 'Change password',
template: '<vn-change-password></vn-change-password>'
})
.state('home', { .state('home', {
parent: 'layout', parent: 'layout',
url: '/', url: '/',

View File

@ -1,5 +1,4 @@
@import "./variables"; @import "./util";
@import "./effects";
form vn-horizontal { form vn-horizontal {
align-items: center; align-items: center;
@ -22,10 +21,10 @@ form vn-horizontal {
} }
} }
@media screen and (max-width: $mobile-width) { @include mobile {
flex-direction: column; flex-direction: column;
align-items: initial; align-items: initial;
& > * { & > * {
&, &,
&:first-child, &:first-child,

View File

@ -1,4 +1,61 @@
{ {
"name": "Log", "name": "Log",
"base": "VnModel" "base": "VnModel",
"properties": {
"id": {
"id": true,
"type": "number",
"forceId": false
},
"originFk": {
"type": "number",
"required": true
},
"userFk": {
"type": "number"
},
"action": {
"type": "string",
"required": true
},
"changedModel": {
"type": "string"
},
"oldInstance": {
"type": "object"
},
"newInstance": {
"type": "object"
},
"oldJson": {
"type": "String",
"mysql": {"columnName": "oldInstance"}
},
"newJson": {
"type": "String",
"mysql": {"columnName": "newInstance"}
},
"creationDate": {
"type": "date"
},
"changedModelId": {
"type": "string"
},
"changedModelValue": {
"type": "string"
},
"description": {
"type": "string"
}
},
"relations": {
"user": {
"type": "belongsTo",
"model": "VnUser",
"foreignKey": "userFk"
}
},
"scope": {
"order": ["creationDate DESC", "id DESC"]
}
} }

View File

@ -1,6 +1,7 @@
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL; const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
const UserError = require('vn-loopback/util/user-error'); const UserError = require('vn-loopback/util/user-error');
const utils = require('loopback/lib/utils');
module.exports = function(Self) { module.exports = function(Self) {
Self.ParameterizedSQL = ParameterizedSQL; Self.ParameterizedSQL = ParameterizedSQL;
@ -164,23 +165,21 @@ module.exports = function(Self) {
function rewriteMethod(methodName) { function rewriteMethod(methodName) {
const realMethod = this[methodName]; const realMethod = this[methodName];
return async(data, options, cb) => { return function(...args) {
if (options instanceof Function) { let cb;
cb = options; const lastArg = args[args.length - 1];
options = null; if (lastArg instanceof Function) {
} cb = lastArg;
args.pop();
} else
cb = utils.createPromiseCallback();
try { args.push(function(err, res) {
const result = await realMethod.call(this, data, options); if (err) err = replaceErr(err, replaceErrFunc);
cb(err, res);
if (cb) cb(null, result); });
else return result; realMethod.apply(this, args);
} catch (err) { return cb.promise;
let myErr = replaceErr(err, replaceErrFunc);
if (cb) cb(myErr);
else
throw myErr;
}
}; };
} }
@ -196,8 +195,48 @@ module.exports = function(Self) {
/* /*
* Shortcut to VnMySQL.executeP() * Shortcut to VnMySQL.executeP()
*/ */
rawSql(query, params, options, cb) { async rawSql(query, params, options) {
return this.dataSource.connector.executeP(query, params, options, cb); const userId = options?.userId;
const connector = this.dataSource.connector;
let conn;
let res;
const opts = Object.assign({}, options);
try {
if (userId) {
conn = await new Promise((resolve, reject) => {
connector.client.getConnection(function(err, conn) {
if (err)
reject(err);
else
resolve(conn);
});
});
const opts = Object.assign({}, options);
if (!opts.transaction) {
opts.transaction = {
connection: conn,
connector
};
}
await connector.executeP(
'CALL account.myUser_loginWithName((SELECT name FROM account.user WHERE id = ?))',
[userId], opts
);
}
res = await connector.executeP(query, params, opts);
if (userId) {
await connector.executeP('CALL account.myUser_logout()', null, opts);
}
} finally {
if (conn) conn.release();
}
return res;
}, },
/* /*

View File

@ -171,5 +171,8 @@
"Added observation": "Added observation", "Added observation": "Added observation",
"Comment added to client": "Comment added to client", "Comment added to client": "Comment added to client",
"This ticket is already a refund": "This ticket is already a refund", "This ticket is already a refund": "This ticket is already a refund",
"A claim with that sale already exists": "A claim with that sale already exists" "A claim with that sale already exists": "A claim with that sale already exists",
"Pass expired": "The password has expired, change it from Salix",
"Can't transfer claimed sales": "Can't transfer claimed sales",
"Invalid quantity": "Invalid quantity"
} }

View File

@ -77,13 +77,13 @@
"This ticket can not be modified": "Este ticket no puede ser modificado", "This ticket can not be modified": "Este ticket no puede ser modificado",
"The introduced hour already exists": "Esta hora ya ha sido introducida", "The introduced hour already exists": "Esta hora ya ha sido introducida",
"INFINITE_LOOP": "Existe una dependencia entre dos Jefes", "INFINITE_LOOP": "Existe una dependencia entre dos Jefes",
"The sales of the current ticket can't be modified": "Las lineas de este ticket no pueden ser modificadas",
"The sales of the receiver ticket can't be modified": "Las lineas del ticket al que envias no pueden ser modificadas", "The sales of the receiver ticket can't be modified": "Las lineas del ticket al que envias no pueden ser modificadas",
"NO_AGENCY_AVAILABLE": "No hay una zona de reparto disponible con estos parámetros", "NO_AGENCY_AVAILABLE": "No hay una zona de reparto disponible con estos parámetros",
"ERROR_PAST_SHIPMENT": "No puedes seleccionar una fecha de envío en pasado", "ERROR_PAST_SHIPMENT": "No puedes seleccionar una fecha de envío en pasado",
"The current ticket can't be modified": "El ticket actual no puede ser modificado", "The current ticket can't be modified": "El ticket actual no puede ser modificado",
"The current claim can't be modified": "La reclamación actual no puede ser modificada", "The current claim can't be modified": "La reclamación actual no puede ser modificada",
"The sales of this ticket can't be modified": "Las lineas de este ticket no pueden ser modificadas", "The sales of this ticket can't be modified": "Las lineas de este ticket no pueden ser modificadas",
"The sales do not exists": "La(s) línea(s) seleccionada(s) no existe(n)",
"Please select at least one sale": "Por favor selecciona al menos una linea", "Please select at least one sale": "Por favor selecciona al menos una linea",
"All sales must belong to the same ticket": "Todas las lineas deben pertenecer al mismo ticket", "All sales must belong to the same ticket": "Todas las lineas deben pertenecer al mismo ticket",
"NO_ZONE_FOR_THIS_PARAMETERS": "Para este día no hay ninguna zona configurada", "NO_ZONE_FOR_THIS_PARAMETERS": "Para este día no hay ninguna zona configurada",
@ -290,6 +290,7 @@
"isTaxDataChecked": "Datos comprobados", "isTaxDataChecked": "Datos comprobados",
"comercialId": "Id comercial", "comercialId": "Id comercial",
"comercialName": "Comercial", "comercialName": "Comercial",
"Pass expired": "La contraseña ha caducado, cambiela desde Salix",
"Invalid NIF for VIES": "Invalid NIF for VIES", "Invalid NIF for VIES": "Invalid NIF for VIES",
"Ticket does not exist": "Este ticket no existe", "Ticket does not exist": "Este ticket no existe",
"Ticket is already signed": "Este ticket ya ha sido firmado" "Ticket is already signed": "Este ticket ya ha sido firmado"

View File

@ -0,0 +1,3 @@
name: account
columns:
id: id

View File

@ -0,0 +1,3 @@
name: cuenta
columns:
id: id

View File

@ -0,0 +1,5 @@
name: mail alias
columns:
id: id
mailAlias: alias
account: account

View File

@ -0,0 +1,5 @@
name: alias de correo
columns:
id: id
mailAlias: alias
account: cuenta

View File

@ -28,8 +28,6 @@ module.exports = Self => {
}); });
Self.changePassword = async function(id, oldPassword, newPassword) { Self.changePassword = async function(id, oldPassword, newPassword) {
await Self.rawSql(`CALL account.user_changePassword(?, ?, ?)`, await Self.app.models.VnUser.changePassword(id, oldPassword, newPassword);
[id, oldPassword, newPassword]);
await Self.app.models.Account.syncById(id, newPassword);
}; };
}; };

View File

@ -22,8 +22,6 @@ module.exports = Self => {
}); });
Self.setPassword = async function(id, newPassword) { Self.setPassword = async function(id, newPassword) {
await Self.rawSql(`CALL account.user_setPassword(?, ?)`, await Self.app.models.VnUser.setPassword(id, newPassword);
[id, newPassword]);
await Self.app.models.Account.syncById(id, newPassword);
}; };
}; };

View File

@ -2,11 +2,21 @@ const {models} = require('vn-loopback/server/server');
describe('account changePassword()', () => { describe('account changePassword()', () => {
it('should throw an error when old password is wrong', async() => { it('should throw an error when old password is wrong', async() => {
let err; let error;
await models.Account.changePassword(1, 'wrongPassword', 'nightmare.9999') try {
.catch(error => err = error.sqlMessage); await models.Account.changePassword(1, 'wrongPassword', 'nightmare.9999');
} catch (e) {
error = e.message;
}
expect(err).toBeDefined(); expect(error).toContain('Invalid current password');
expect(err).toEqual('Invalid password'); });
it('should change password', async() => {
try {
await models.Account.changePassword(70, 'nightmare', 'nightmare.9999');
} catch (e) {
expect(e).toBeUndefined();
}
}); });
}); });

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