merge(master): refs #6403 merge master fix conflicts
gitea/salix/pipeline/pr-master There was a failure building this commit Details

This commit is contained in:
Pablo Natek 2024-02-07 16:55:09 +01:00
commit d2d28889b6
282 changed files with 6427 additions and 2774 deletions

View File

@ -16,6 +16,7 @@
}, },
"cSpell.words": [ "cSpell.words": [
"salix", "salix",
"fdescribe" "fdescribe",
"Loggable"
] ]
} }

View File

@ -5,6 +5,19 @@ 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).
## [2404.01] - 2024-01-25
### Added
### Changed
### Fixed
## [2402.01] - 2024-01-11
### Added
### Changed
### Fixed
## [2400.01] - 2024-01-04 ## [2400.01] - 2024-01-04
### Added ### Added

3
Jenkinsfile vendored
View File

@ -12,6 +12,9 @@ pipeline {
stage('Checkout') { stage('Checkout') {
steps { steps {
script { script {
// Uncomment to enable debugging
// env.DEBUG = 'strong-remoting:shared-method,puppeteer-cluster:*'
switch (env.BRANCH_NAME) { switch (env.BRANCH_NAME) {
case 'master': case 'master':
env.NODE_ENV = 'production' env.NODE_ENV = 'production'

View File

@ -24,15 +24,40 @@ describe('docuware upload()', () => {
}); });
it('should try upload file', async() => { it('should try upload file', async() => {
const tx = await models.Docuware.beginTransaction({});
spyOn(ticketModel, 'deliveryNotePdf').and.returnValue(new Promise(resolve => resolve({}))); spyOn(ticketModel, 'deliveryNotePdf').and.returnValue(new Promise(resolve => resolve({})));
let error; let error;
try { try {
await models.Docuware.upload(ctx, ticketIds, fileCabinetName); const options = {transaction: tx};
const user = await models.UserConfig.findById(userId, null, options);
await user.updateAttribute('tabletFk', 'Tablet1', options);
await models.Docuware.upload(ctx, ticketIds, fileCabinetName, options);
await tx.rollback();
} catch (e) { } catch (e) {
error = e.message; error = e;
await tx.rollback();
} }
expect(error).toEqual('Action not allowed on the test environment'); expect(error.message).toEqual('Action not allowed on the test environment');
});
it('should throw error when not have tablet assigned', async() => {
const tx = await models.Docuware.beginTransaction({});
spyOn(ticketModel, 'deliveryNotePdf').and.returnValue(new Promise(resolve => resolve({})));
let error;
try {
const options = {transaction: tx};
await models.Docuware.upload(ctx, ticketIds, fileCabinetName, options);
await tx.rollback();
} catch (e) {
error = e;
await tx.rollback();
}
expect(error.message).toEqual('This user does not have an assigned tablet');
}); });
}); });

View File

@ -29,12 +29,24 @@ module.exports = Self => {
} }
}); });
Self.upload = async function(ctx, ticketIds, fileCabinet) { Self.upload = async function(ctx, ticketIds, fileCabinet, options) {
delete ctx.args.ticketIds; delete ctx.args.ticketIds;
const models = Self.app.models; const models = Self.app.models;
const action = 'store'; const action = 'store';
const options = await Self.getOptions(); const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const userConfig = await models.UserConfig.findById(ctx.req.accessToken.userId, {
fields: ['tabletFk']
}, myOptions);
if (!userConfig?.tabletFk)
throw new UserError('This user does not have an assigned tablet');
const docuwareOptions = await Self.getOptions();
const fileCabinetId = await Self.getFileCabinet(fileCabinet); const fileCabinetId = await Self.getFileCabinet(fileCabinet);
const dialogId = await Self.getDialog(fileCabinet, action, fileCabinetId); const dialogId = await Self.getDialog(fileCabinet, action, fileCabinetId);
@ -45,7 +57,7 @@ module.exports = Self => {
const deliveryNote = await models.Ticket.deliveryNotePdf(ctx, { const deliveryNote = await models.Ticket.deliveryNotePdf(ctx, {
id, id,
type: 'deliveryNote' type: 'deliveryNote'
}); }, myOptions);
// get ticket data // get ticket data
const ticket = await models.Ticket.findById(id, { const ticket = await models.Ticket.findById(id, {
include: [{ include: [{
@ -54,7 +66,7 @@ module.exports = Self => {
fields: ['id', 'name', 'fi'] fields: ['id', 'name', 'fi']
} }
}] }]
}); }, myOptions);
// upload file // upload file
const templateJson = { const templateJson = {
@ -102,7 +114,7 @@ module.exports = Self => {
{ {
'FieldName': 'FILTRO_TABLET', 'FieldName': 'FILTRO_TABLET',
'ItemElementName': 'string', 'ItemElementName': 'string',
'Item': 'Tablet1', 'Item': userConfig.tabletFk,
} }
] ]
}; };
@ -116,11 +128,11 @@ module.exports = Self => {
const deleteJson = { const deleteJson = {
'Field': [{'FieldName': 'ESTADO', 'Item': 'Pendiente eliminar', 'ItemElementName': 'String'}] 'Field': [{'FieldName': 'ESTADO', 'Item': 'Pendiente eliminar', 'ItemElementName': 'String'}]
}; };
const deleteUri = `${options.url}/FileCabinets/${fileCabinetId}/Documents/${docuwareFile.id}/Fields`; const deleteUri = `${docuwareOptions.url}/FileCabinets/${fileCabinetId}/Documents/${docuwareFile.id}/Fields`;
await axios.put(deleteUri, deleteJson, options.headers); await axios.put(deleteUri, deleteJson, docuwareOptions.headers);
} }
const uploadUri = `${options.url}/FileCabinets/${fileCabinetId}/Documents?StoreDialogId=${dialogId}`; const uploadUri = `${docuwareOptions.url}/FileCabinets/${fileCabinetId}/Documents?StoreDialogId=${dialogId}`;
const FormData = require('form-data'); const FormData = require('form-data');
const data = new FormData(); const data = new FormData();
@ -130,7 +142,7 @@ module.exports = Self => {
headers: { headers: {
'Content-Type': 'multipart/form-data', 'Content-Type': 'multipart/form-data',
'X-File-ModifiedDate': Date.vnNew(), 'X-File-ModifiedDate': Date.vnNew(),
'Cookie': options.headers.headers.Cookie, 'Cookie': docuwareOptions.headers.headers.Cookie,
...data.getHeaders() ...data.getHeaders()
}, },
}; };
@ -141,11 +153,11 @@ module.exports = Self => {
const $t = ctx.req.__; const $t = ctx.req.__;
const message = $t('Failed to upload delivery note', {id}); const message = $t('Failed to upload delivery note', {id});
if (uploaded.length) if (uploaded.length)
await models.TicketTracking.setDelivered(ctx, uploaded); await models.TicketTracking.setDelivered(ctx, uploaded, myOptions);
throw new UserError(message); throw new UserError(message);
} }
uploaded.push(id); uploaded.push(id);
} }
return models.TicketTracking.setDelivered(ctx, ticketIds); return models.TicketTracking.setDelivered(ctx, ticketIds, myOptions);
}; };
}; };

View File

@ -35,10 +35,17 @@ module.exports = Self => {
let html = `<strong>Motivo</strong>:<br/>${reason}<br/>`; let html = `<strong>Motivo</strong>:<br/>${reason}<br/>`;
html += `<strong>Usuario</strong>:<br/>${ctx.req.accessToken.userId} ${emailUser.email}<br/>`; html += `<strong>Usuario</strong>:<br/>${ctx.req.accessToken.userId} ${emailUser.email}<br/>`;
delete additionalData.backError.config.headers.Authorization;
const httpRequest = JSON.parse(additionalData?.httpRequest);
if (httpRequest)
delete httpRequest.config.headers.Authorization;
additionalData.httpRequest = httpRequest;
for (const data in additionalData) for (const data in additionalData)
html += `<strong>${data}</strong>:<br/>${tryParse(additionalData[data])}<br/>`; html += `<strong>${data}</strong>:<br/>${tryParse(additionalData[data])}<br/>`;
const subjectReason = JSON.parse(additionalData?.httpRequest)?.data?.error; const subjectReason = httpRequest?.data?.error;
smtp.send({ smtp.send({
to: `${config.app.reportEmail}, ${emailUser.email}`, to: `${config.app.reportEmail}, ${emailUser.email}`,
subject: subject:

View File

@ -20,7 +20,7 @@ module.exports = Self => {
} }
}); });
Self.internationalExpedition = async expeditionFk => { Self.internationalExpedition = async (expeditionFk) => {
const models = Self.app.models; const models = Self.app.models;
const viaexpressConfig = await models.ViaexpressConfig.findOne({ const viaexpressConfig = await models.ViaexpressConfig.findOne({

View File

@ -20,11 +20,11 @@ module.exports = Self => {
} }
}); });
Self.renderer = async expeditionFk => { Self.renderer = async (expeditionFk) => {
const models = Self.app.models; const models = Self.app.models;
const viaexpressConfig = await models.ViaexpressConfig.findOne({ const viaexpressConfig = await models.ViaexpressConfig.findOne({
fields: ['client', 'user', 'password', 'defaultWeight', 'deliveryType'] fields: ['client', 'user', 'password', 'defaultWeight', 'deliveryType', 'agencyModeFk']
}); });
const expedition = await models.Expedition.findOne({ const expedition = await models.Expedition.findOne({
@ -34,7 +34,7 @@ module.exports = Self => {
{ {
relation: 'ticket', relation: 'ticket',
scope: { scope: {
fields: ['shipped', 'addressFk', 'clientFk', 'companyFk'], fields: ['shipped', 'addressFk', 'clientFk', 'companyFk', 'agencyModeFk'],
include: [ include: [
{ {
relation: 'client', relation: 'client',
@ -102,7 +102,6 @@ module.exports = Self => {
} }
] ]
} }
} }
] ]
}); });
@ -110,13 +109,15 @@ module.exports = Self => {
const ticket = expedition.ticket(); const ticket = expedition.ticket();
const sender = ticket.company().client(); const sender = ticket.company().client();
const shipped = ticket.shipped.toISOString(); const shipped = ticket.shipped.toISOString();
const isInterdia = (ticket.agencyModeFk === viaexpressConfig.agencyModeFk)
const data = { const data = {
viaexpressConfig, viaexpressConfig,
sender, sender,
senderAddress: sender.defaultAddress(), senderAddress: sender.defaultAddress(),
client: ticket.client(), client: ticket.client(),
address: ticket.address(), address: ticket.address(),
shipped shipped,
isInterdia
}; };
const template = fs.readFileSync(__dirname + '/template.ejs', 'utf-8'); const template = fs.readFileSync(__dirname + '/template.ejs', 'utf-8');

View File

@ -13,7 +13,7 @@
<Asegurado>0</Asegurado> <Asegurado>0</Asegurado>
<Imprimir>0</Imprimir> <Imprimir>0</Imprimir>
<ConDevolucionAlbaran>0</ConDevolucionAlbaran> <ConDevolucionAlbaran>0</ConDevolucionAlbaran>
<Intradia>0</Intradia> <Intradia><%= isInterdia %></Intradia>
<Observaciones></Observaciones> <Observaciones></Observaciones>
<AlbaranRemitente></AlbaranRemitente> <AlbaranRemitente></AlbaranRemitente>
<Modo>0</Modo> <Modo>0</Modo>

View File

@ -68,7 +68,7 @@ module.exports = Self => {
userToUpdate.hasGrant = hasGrant; userToUpdate.hasGrant = hasGrant;
if (roleFk) { if (roleFk) {
const role = await models.Role.findById(roleFk, {fields: ['name']}, myOptions); const role = await models.VnRole.findById(roleFk, {fields: ['name']}, myOptions);
const hasRole = await Self.hasRole(userId, role.name, myOptions); const hasRole = await Self.hasRole(userId, role.name, myOptions);
if (!hasRole) if (!hasRole)

View File

@ -1,14 +1,5 @@
const UserError = require('vn-loopback/util/user-error');
const {models} = require('vn-loopback/server/server'); const {models} = require('vn-loopback/server/server');
const handlePromiseLogout = (Self, {id}, courtesyTime) => {
new Promise(res => {
setTimeout(() => {
res(Self.logout(id));
}
, courtesyTime * 1000);
});
};
module.exports = Self => { module.exports = Self => {
Self.remoteMethodCtx('renewToken', { Self.remoteMethodCtx('renewToken', {
description: 'Checks if the token has more than renewPeriod seconds to live and if so, renews it', description: 'Checks if the token has more than renewPeriod seconds to live and if so, renews it',
@ -28,14 +19,26 @@ module.exports = Self => {
const {accessToken: token} = ctx.req; const {accessToken: token} = ctx.req;
// Check if current token is valid // Check if current token is valid
const isValid = await validateToken(token);
if (isValid) const {renewPeriod, courtesyTime} = await models.AccessTokenConfig.findOne({
fields: ['renewPeriod', 'courtesyTime']
});
const now = Date.now();
const differenceMilliseconds = now - token.created;
const differenceSeconds = Math.floor(differenceMilliseconds / 1000);
const isNotExceeded = differenceSeconds < renewPeriod - courtesyTime;
if (isNotExceeded)
return token; return token;
const {courtesyTime} = await models.AccessTokenConfig.findOne({fields: ['courtesyTime']});
// Schedule to remove current token // Schedule to remove current token
handlePromiseLogout(Self, token, courtesyTime); setTimeout(async() => {
try {
await Self.logout(token.id);
} catch (err) {
// eslint-disable-next-line no-console
console.error(err);
}
}, courtesyTime * 1000);
// Create new accessToken // Create new accessToken
const user = await Self.findById(token.userId); const user = await Self.findById(token.userId);
@ -43,14 +46,4 @@ module.exports = Self => {
return {id: accessToken.id, ttl: accessToken.ttl}; return {id: accessToken.id, ttl: accessToken.ttl};
}; };
async function validateToken(token) {
const accessTokenConfig = await models.AccessTokenConfig.findOne({fields: ['renewPeriod', 'courtesyTime']});
const now = Date.now();
const differenceMilliseconds = now - token.created;
const differenceSeconds = Math.floor(differenceMilliseconds / 1000);
const isValid = differenceSeconds < accessTokenConfig.renewPeriod - accessTokenConfig.courtesyTime;
return isValid;
}
}; };

View File

@ -70,7 +70,7 @@ describe('VnUser privileges()', () => {
const tx = await models.VnUser.beginTransaction({}); const tx = await models.VnUser.beginTransaction({});
const options = {transaction: tx}; const options = {transaction: tx};
const agency = await models.Role.findOne({ const agency = await models.VnRole.findOne({
where: { where: {
name: 'agency' name: 'agency'
} }

View File

@ -27,8 +27,9 @@ describe('Renew Token', () => {
jasmine.clock().uninstall(); jasmine.clock().uninstall();
}); });
it('should renew process', async() => { it('should renew token', async() => {
jasmine.clock().mockDate(new Date(startingTime + 21600000)); const mockDate = new Date(startingTime + 26600000);
jasmine.clock().mockDate(mockDate);
const {id} = await models.VnUser.renewToken(ctx); const {id} = await models.VnUser.renewToken(ctx);
expect(id).not.toEqual(ctx.req.accessToken.id); expect(id).not.toEqual(ctx.req.accessToken.id);

View File

@ -20,10 +20,7 @@ describe('VnUser Sign-in()', () => {
let ctx = {req: {accessToken: accessToken}}; let ctx = {req: {accessToken: accessToken}};
let signInLog = await SignInLog.find({where: {token: accessToken.id}}); let signInLog = await SignInLog.find({where: {token: accessToken.id}});
expect(signInLog.length).toEqual(1); expect(signInLog.length).toEqual(0);
expect(signInLog[0].userFk).toEqual(accessToken.userId);
expect(signInLog[0].owner).toEqual(true);
expect(login.token).toBeDefined();
await VnUser.logout(ctx.req.accessToken.id); await VnUser.logout(ctx.req.accessToken.id);
}); });

View File

@ -139,9 +139,6 @@
"Warehouse": { "Warehouse": {
"dataSource": "vn" "dataSource": "vn"
}, },
"VnUser": {
"dataSource": "vn"
},
"OsTicket": { "OsTicket": {
"dataSource": "osticket" "dataSource": "osticket"
}, },
@ -157,6 +154,12 @@
"ViaexpressConfig": { "ViaexpressConfig": {
"dataSource": "vn" "dataSource": "vn"
}, },
"VnUser": {
"dataSource": "vn"
},
"VnRole": {
"dataSource": "vn"
},
"MrwConfig": { "MrwConfig": {
"dataSource": "vn" "dataSource": "vn"
} }

View File

@ -17,10 +17,6 @@
"type": "string", "type": "string",
"required": true "required": true
}, },
"path": {
"type": "string",
"required": true
},
"code": { "code": {
"type": "string", "type": "string",
"required": true "required": true
@ -29,12 +25,12 @@
"relations": { "relations": {
"readRole": { "readRole": {
"type": "belongsTo", "type": "belongsTo",
"model": "Role", "model": "VnRole",
"foreignKey": "readRoleFk" "foreignKey": "readRoleFk"
}, },
"writeRole": { "writeRole": {
"type": "belongsTo", "type": "belongsTo",
"model": "Role", "model": "VnRole",
"foreignKey": "writeRoleFk" "foreignKey": "writeRoleFk"
} }
}, },

View File

@ -0,0 +1,17 @@
{
"name": "docuwareTablet",
"base": "VnModel",
"options": {
"mysql": {
"table": "docuwareTablet"
}
},
"properties": {
"tablet": {
"type": "string"
},
"description": {
"type": "string"
}
}
}

View File

@ -46,12 +46,12 @@
}, },
"readRole": { "readRole": {
"type": "belongsTo", "type": "belongsTo",
"model": "Role", "model": "VnRole",
"foreignKey": "readRoleFk" "foreignKey": "readRoleFk"
}, },
"writeRole": { "writeRole": {
"type": "belongsTo", "type": "belongsTo",
"model": "Role", "model": "VnRole",
"foreignKey": "writeRoleFk" "foreignKey": "writeRoleFk"
} }
}, },
@ -64,4 +64,3 @@
} }
] ]
} }

View File

@ -24,8 +24,8 @@
}, },
"role": { "role": {
"type": "belongsTo", "type": "belongsTo",
"model": "Role", "model": "VnRole",
"foreignKey": "roleFk" "foreignKey": "roleFk"
} }
} }
} }

View File

@ -0,0 +1,56 @@
const models = require('vn-loopback/server/server').models;
describe('loopback model MailAliasAccount', () => {
it('should add a mail Alias', async() => {
const tx = await models.MailAliasAccount.beginTransaction({});
let error;
try {
const options = {transaction: tx, accessToken: {userId: 9}};
await models.MailAliasAccount.create({mailAlias: 2, account: 5}, options);
await tx.rollback();
} catch (e) {
await tx.rollback();
error = e;
}
expect(error).toBeUndefined();
});
it('should add a mail Alias of an inherit role', async() => {
const tx = await models.MailAliasAccount.beginTransaction({});
let error;
try {
const options = {transaction: tx, accessToken: {userId: 9}};
await models.MailAliasAccount.create({mailAlias: 3, account: 5}, options);
await tx.rollback();
} catch (e) {
await tx.rollback();
error = e;
}
expect(error).toBeUndefined();
});
it('should delete a mail Alias', async() => {
const tx = await models.MailAliasAccount.beginTransaction({});
let error;
try {
const options = {transaction: tx, accessToken: {userId: 1}};
const mailAclId = 2;
await models.MailAliasAccount.destroyAll({id: mailAclId}, options);
await tx.rollback();
} catch (e) {
await tx.rollback();
error = e;
}
expect(error).toBeUndefined();
});
});

View File

@ -26,6 +26,9 @@
}, },
"darkMode": { "darkMode": {
"type": "boolean" "type": "boolean"
},
"tabletFk": {
"type": "string"
} }
}, },
"relations": { "relations": {
@ -43,6 +46,11 @@
"type": "belongsTo", "type": "belongsTo",
"model": "VnUser", "model": "VnUser",
"foreignKey": "userFk" "foreignKey": "userFk"
} },
"Tablet": {
"type": "belongsTo",
"model": "docuwareTablet",
"foreignKey": "tabletFk"
}
} }
} }

View File

@ -29,6 +29,9 @@
}, },
"deliveryType": { "deliveryType": {
"type": "string" "type": "string"
},
"agencyModeFk": {
"type": "number"
} }
} }
} }

13
back/models/vn-role.json Normal file
View File

@ -0,0 +1,13 @@
{
"name": "VnRole",
"base": "Role",
"validateUpsert": true,
"options": {
"mysql": {
"table": "account.role"
}
},
"mixins": {
"Loggable": true
}
}

View File

@ -134,15 +134,16 @@ module.exports = function(Self) {
Self.signInValidate = async(user, userToken, token, ctx) => { Self.signInValidate = async(user, userToken, token, ctx) => {
const [[key, value]] = Object.entries(Self.userUses(user)); const [[key, value]] = Object.entries(Self.userUses(user));
const isOwner = Self.rawSql(`SELECT ? = ? `, [userToken[key], value]); const isOwner = Self.rawSql(`SELECT ? = ? `, [userToken[key], value]);
await Self.app.models.SignInLog.create({ if (!isOwner) {
userName: user, await Self.app.models.SignInLog.create({
token: token.id, userName: user,
userFk: userToken.id, token: token.id,
ip: ctx.req.ip, userFk: userToken.id,
owner: isOwner ip: ctx.req.ip,
}); owner: isOwner
if (!isOwner) });
throw new UserError('Try again'); throw new UserError('Try again');
}
}; };
/** /**
@ -257,18 +258,20 @@ module.exports = function(Self) {
class Mailer { class Mailer {
async send(verifyOptions, cb) { async send(verifyOptions, cb) {
const url = new URL(verifyOptions.verifyHref); try {
if (process.env.NODE_ENV) url.port = ''; const url = new URL(verifyOptions.verifyHref);
if (process.env.NODE_ENV) url.port = '';
const params = { const email = new Email('email-verify', {
url: url.href, url: url.href,
recipient: verifyOptions.to recipient: verifyOptions.to
}; });
await email.send();
const email = new Email('email-verify', params); cb(null, verifyOptions.to);
email.send(); } catch (err) {
cb(err);
cb(null, verifyOptions.to); }
} }
} }

View File

@ -7,6 +7,9 @@
"table": "account.user" "table": "account.user"
} }
}, },
"mixins": {
"Loggable": true
},
"resetPasswordTokenTTL": "604800", "resetPasswordTokenTTL": "604800",
"properties": { "properties": {
"id": { "id": {
@ -63,7 +66,7 @@
"relations": { "relations": {
"role": { "role": {
"type": "belongsTo", "type": "belongsTo",
"model": "Role", "model": "VnRole",
"foreignKey": "roleFk" "foreignKey": "roleFk"
}, },
"roles": { "roles": {
@ -95,27 +98,30 @@
"principalType": "ROLE", "principalType": "ROLE",
"principalId": "$everyone", "principalId": "$everyone",
"permission": "ALLOW" "permission": "ALLOW"
}, }, {
{ "property": "recoverPassword",
"property": "recoverPassword",
"accessType": "EXECUTE",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
},
{
"property": "validateAuth",
"accessType": "EXECUTE", "accessType": "EXECUTE",
"principalType": "ROLE", "principalType": "ROLE",
"principalId": "$everyone", "principalId": "$everyone",
"permission": "ALLOW" "permission": "ALLOW"
}, }, {
{ "property": "validateAuth",
"accessType": "EXECUTE",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
}, {
"property": "privileges", "property": "privileges",
"accessType": "*", "accessType": "*",
"principalType": "ROLE", "principalType": "ROLE",
"principalId": "$authenticated", "principalId": "$authenticated",
"permission": "ALLOW" "permission": "ALLOW"
}, {
"property": "renewToken",
"accessType": "WRITE",
"principalType": "ROLE",
"principalId": "$authenticated",
"permission": "ALLOW"
} }
], ],
"scopes": { "scopes": {

View File

@ -59,8 +59,8 @@ async function test() {
const JunitReporter = require('jasmine-reporters'); const JunitReporter = require('jasmine-reporters');
jasmine.addReporter(new JunitReporter.JUnitXmlReporter()); jasmine.addReporter(new JunitReporter.JUnitXmlReporter());
jasmine.jasmine.DEFAULT_TIMEOUT_INTERVAL = 90000;
jasmine.exitOnCompletion = true; jasmine.exitOnCompletion = true;
jasmine.jasmine.DEFAULT_TIMEOUT_INTERVAL = 900000;
} }
const backSpecs = [ const backSpecs = [

View File

@ -1,4 +1,4 @@
FROM mariadb:10.7.7 FROM mariadb:10.11.6
ENV MYSQL_ROOT_PASSWORD root ENV MYSQL_ROOT_PASSWORD root
ENV TZ Europe/Madrid ENV TZ Europe/Madrid

View File

View File

@ -0,0 +1,8 @@
-- Definición de la tabla mailAliasACL
CREATE OR REPLACE TABLE `account`.`mailAliasAcl` (
`mailAliasFk` int(10) unsigned NOT NULL,
`roleFk` int(10) unsigned NOT NULL,
FOREIGN KEY (`mailAliasFk`) REFERENCES `account`.`mailAlias` (`id`),
FOREIGN KEY (`roleFk`) REFERENCES `account`.`role` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci;

View File

@ -0,0 +1,7 @@
ALTER TABLE `vn`.`invoiceCorrection` DROP FOREIGN KEY `cplusInvoiceTyoeFk`;
ALTER TABLE `vn`.`invoiceCorrection` DROP FOREIGN KEY `invoiceCorrectionType_Fk33`;
ALTER TABLE `vn`.`invoiceCorrection` DROP FOREIGN KEY `invoiceCorrection_ibfk_1`;
ALTER TABLE `vn`.`invoiceCorrection` ADD CONSTRAINT `siiTypeInvoiceOut_FK` FOREIGN KEY (`siiTypeInvoiceOutFk`) REFERENCES `vn`.`siiTypeInvoiceOut`(id) ON UPDATE CASCADE;
ALTER TABLE `vn`.`invoiceCorrection` ADD CONSTRAINT `invoiceCorrectionType_FK` FOREIGN KEY (`invoiceCorrectionTypeFk`) REFERENCES `vn`.`invoiceCorrectionType`(id) ON UPDATE CASCADE;
ALTER TABLE `vn`.`invoiceCorrection` ADD CONSTRAINT `cplusRectificationType_FK` FOREIGN KEY (`cplusRectificationTypeFk`) REFERENCES `vn`.`cplusRectificationType`(id) ON UPDATE CASCADE;

View File

@ -0,0 +1,33 @@
DELIMITER $$
$$
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`getTaxBases`()
BEGIN
/**
* Calcula y devuelve en número de bases imponibles postivas y negativas
* Requiere la tabla temporal tmp.ticketToInvoice(id)
*
* returns tmp.taxBases
*/
CREATE OR REPLACE TEMPORARY TABLE tmp.ticket
(KEY (ticketFk))
ENGINE = MEMORY
SELECT id ticketFk
FROM tmp.ticketToInvoice;
CALL ticket_getTax(NULL);
DROP TEMPORARY TABLE IF EXISTS tmp.taxBases;
CREATE TEMPORARY TABLE tmp.taxBases
ENGINE = MEMORY
SELECT
SUM(taxableBase > 0) as positive,
SUM(taxableBase < 0) as negative
FROM(
SELECT SUM(taxableBase) taxableBase
FROM tmp.ticketTax
GROUP BY pgcFk
) t;
END$$
DELIMITER ;

View File

@ -0,0 +1,10 @@
-- vn.docuwareTablet definition
CREATE TABLE `vn`.`docuwareTablet` (
`tablet` varchar(100) NOT NULL PRIMARY KEY,
`description` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
ALTER TABLE `vn`.`userConfig`
ADD COLUMN tabletFk varchar(100) DEFAULT NULL,
ADD FOREIGN KEY (tabletFk) REFERENCES `vn`.`docuwareTablet`(tablet);

View File

@ -0,0 +1,17 @@
DELETE FROM `salix`.`ACL`
WHERE model = 'VnUser'
AND property = 'renewToken';
INSERT INTO `account`.`role` (name, description)
VALUES ('timeControl','Tablet para fichar');
INSERT INTO `account`.`roleInherit` (role, inheritsFrom)
VALUES (127, 11);
INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
VALUES
('WorkerTimeControl', 'login', 'READ', 'ALLOW', 'ROLE', 'timeControl'),
('WorkerTimeControl', 'getClockIn', 'READ', 'ALLOW', 'ROLE', 'timeControl'),
('WorkerTimeControl', 'clockIn', 'WRITE', 'ALLOW', 'ROLE', 'timeControl');
CALL `account`.`role_sync`();

View File

@ -0,0 +1,2 @@
DELETE FROM `account`.`signInLog` where owner <> FALSE;

View File

@ -0,0 +1,81 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` FUNCTION `vn`.`ticketPositionInPath`(vTicketId INT)
RETURNS varchar(10) CHARSET utf8mb3 COLLATE utf8mb3_general_ci
DETERMINISTIC
BEGIN
DECLARE vRestTicketsMaxOrder INT;
DECLARE vRestTicketsMinOrder INT;
DECLARE vRestTicketsPacking INT;
DECLARE vMyProductionOrder INT;
DECLARE vPosition VARCHAR(10) DEFAULT 'MID';
DECLARE vMyPath INT;
DECLARE vMyWarehouse INT;
DECLARE PACKING_ORDER INT;
DECLARE vExpeditionsCount INT;
DECLARE vIsValenciaPath BOOLEAN DEFAULT FALSE;
SELECT `order`
INTO PACKING_ORDER
FROM state
WHERE code = 'PACKING';
SELECT t.routeFk, t.warehouseFk, IFNULL(ts.productionOrder,0)
INTO vMyPath, vMyWarehouse, vMyProductionOrder
FROM ticket t
LEFT JOIN ticketState ts on ts.ticketFk = t.id
WHERE t.id = vTicketId;
SELECT (ag.`name` = 'VN_VALENCIA')
INTO vIsValenciaPath
FROM vn2008.Rutas r
JOIN vn2008.Agencias a on a.Id_Agencia = r.Id_Agencia
JOIN vn2008.agency ag on ag.agency_id = a.agency_id
WHERE r.Id_Ruta = vMyPath;
IF vIsValenciaPath THEN -- Rutas Valencia
SELECT COUNT(*)
INTO vExpeditionsCount
FROM expedition e
JOIN ticket t ON t.id = e.ticketFk
WHERE t.routeFk = vMyPath;
SELECT MAX(ts.productionOrder), MIN(ts.productionOrder)
INTO vRestTicketsMaxOrder, vRestTicketsMinOrder
FROM ticket t
LEFT JOIN ticketState ts on t.id = ts.ticketFk
WHERE t.routeFk = vMyPath
AND t.warehouseFk = vMyWarehouse
AND t.id != vTicketid;
SELECT COUNT(*)
INTO vRestTicketsPacking
FROM ticket t
LEFT JOIN ticketState ts on t.id = ts.ticketFk
WHERE ts.productionOrder = PACKING_ORDER
AND t.routeFk = vMyPath
AND t.warehouseFk = vMyWarehouse
AND t.id != vTicketid;
IF vExpeditionsCount = 1 THEN
SET vPosition = 'FIRST';
ELSEIF vRestTicketsMinOrder > PACKING_ORDER THEN
SET vPosition = 'LAST';
ELSEIF vRestTicketsPacking THEN
SET vPosition = 'SHARED';
ELSE
SET vPosition = 'MID';
END IF;
ELSE
SET vPosition = 'MID';
END IF;
RETURN vPosition;
END$$
DELIMITER ;

View File

@ -0,0 +1,30 @@
DELIMITER $$
$$
CREATE OR REPLACE DEFINER=`root`@`localhost` FUNCTION `vn`.`hasAnyPositiveBase`() RETURNS tinyint(1)
DETERMINISTIC
BEGIN
/**
* Calcula si existe alguna base imponible positiva
* Requiere la tabla temporal tmp.ticketToInvoice(id) para getTaxBases()
*
* returns BOOLEAN
*/
DECLARE hasAnyPositiveBase BOOLEAN;
CALL getTaxBases();
SELECT positive INTO hasAnyPositiveBase
FROM tmp.taxBases
LIMIT 1;
DROP TEMPORARY TABLE
tmp.ticketTax,
tmp.ticket,
tmp.taxBases;
RETURN hasAnyPositiveBase;
END$$
DELIMITER ;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,32 @@
DELIMITER $$
$$
CREATE OR REPLACE DEFINER=`root`@`localhost` FUNCTION `vn`.`hasAnyNegativeBase`() RETURNS tinyint(1)
DETERMINISTIC
BEGIN
/**
* Calcula si existe alguna base imponible negativa
* Requiere la tabla temporal tmp.ticketToInvoice(id) para getTaxBases()
*
* returns BOOLEAN
*/
DECLARE hasAnyNegativeBase BOOLEAN;
CALL getTaxBases();
SELECT negative INTO hasAnyNegativeBase
FROM tmp.taxBases
LIMIT 1;
DROP TEMPORARY TABLE
tmp.ticketTax,
tmp.ticket,
tmp.taxBases;
RETURN hasAnyNegativeBase;
END$$
DELIMITER ;

View File

@ -0,0 +1,27 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`expedition_beforeInsert`
BEFORE INSERT ON `expedition`
FOR EACH ROW
BEGIN
DECLARE intcounter INT;
DECLARE vShipFk INT;
SET NEW.editorFk = account.myUser_getId();
IF NEW.freightItemFk IS NOT NULL THEN
UPDATE ticket SET packages = nz(packages) + 1 WHERE id = NEW.ticketFk;
SELECT IFNULL(MAX(counter),0) +1 INTO intcounter
FROM expedition e
INNER JOIN ticket t1 ON e.ticketFk = t1.id
LEFT JOIN ticketState ts ON ts.ticketFk = t1.id
INNER JOIN ticket t2 ON t2.addressFk = t1.addressFk AND DATE(t2.shipped) = DATE(t1.shipped)
AND t1.warehouseFk = t2.warehouseFk
WHERE t2.id = NEW.ticketFk AND ts.alertLevel < 3 AND t1.companyFk = t2.companyFk
AND t1.agencyModeFk = t2.agencyModeFk;
SET NEW.`counter` = intcounter;
END IF;
END$$
DELIMITER ;

View File

@ -0,0 +1,58 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn`.`expeditionRoute_freeTickets` AS
SELECT
`t`.`routeFk` AS `routeFk`,
`tss`.`ticketFk` AS `ticket`,
`s`.`name` AS `code`,
`w`.`name` AS `almacen`,
`tss`.`updated` AS `updated`,
`p`.`code` AS `parkingCode`
FROM `vn`.`ticketState` `tss`
JOIN `vn`.`ticket` `t` ON `t`.`id` = `tss`.`ticketFk`
JOIN `vn`.`warehouse` `w` ON `w`.`id` = `t`.`warehouseFk`
JOIN `vn`.`state` `s` ON `s`.`id` = `tss`.`state`
LEFT JOIN `vn`.`ticketParking` `tp` ON `tp`.`ticketFk` = `t`.`id`
LEFT JOIN `vn`.`parking` `p` ON `p`.`id` = `tp`.`parkingFk`
WHERE IFNULL(`t`.`packages`, 0) = 0;
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn`.`ticketState`
AS SELECT `tt`.`created` AS `updated`,
`tt`.`stateFk` AS `stateFk`,
`tt`.`userFk` AS `userFk`,
`tls`.`ticketFk` AS `ticketFk`,
`s`.`id` AS `state`,
`s`.`order` AS `productionOrder`,
`s`.`alertLevel` AS `alertLevel`,
`s`.`code` AS `code`,
`s`.`isPreviousPreparable` AS `isPreviousPreparable`,
`s`.`isPicked` AS `isPicked`
FROM (
(
`vn`.`ticketLastState` `tls`
JOIN `vn`.`ticketTracking` `tt` ON(`tt`.`id` = `tls`.`ticketTrackingFk`)
)
JOIN `vn`.`state` `s` ON(`s`.`id` = `tt`.`stateFk`)
);
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn`.`ticketStateToday`
AS
SELECT
`ts`.`ticketFk` AS `ticket`,
`ts`.`state` AS `state`,
`ts`.`productionOrder` AS `productionOrder`,
`ts`.`alertLevel` AS `alertLevel`,
`ts`.`userFk` AS `worker`,
`ts`.`code` AS `code`,
`ts`.`updated` AS `updated`,
`ts`.`isPicked` AS `isPicked`
FROM
`vn`.`ticketState` `ts`
JOIN `vn`.`ticket` `t` ON `t`.`id` = `ts`.`ticketFk`
WHERE
`t`.`shipped` BETWEEN `util`.`VN_CURDATE`() AND `util`.`VN_CURDATE`() + INTERVAL 1 DAY;

View File

View File

@ -0,0 +1,14 @@
DELETE FROM salix.ACL
WHERE model = 'WorkerTimeControl'
AND property IN ('*','addTime');
INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
VALUES
('WorkerTimeControl', 'addTimeEntry', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('WorkerTimeControl', 'deleteTimeEntry', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('WorkerTimeControl', 'updateTimeEntry', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('WorkerTimeControl', 'sendMail', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('WorkerTimeControl', 'updateWorkerTimeControlMail', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('WorkerTimeControl', 'weeklyHourRecordEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('WorkerTimeControl', 'getMailStates', 'READ', 'ALLOW', 'ROLE', 'employee'),
('WorkerTimeControl', 'resendWeeklyHourEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee');

View File

View File

@ -0,0 +1,2 @@
ALTER TABLE `vn`.`viaexpressConfig` ADD agencyModeFk int DEFAULT NULL NULL COMMENT 'Indica el agencyMode que es interdia';
ALTER TABLE `vn`.`viaexpressConfig` ADD CONSTRAINT viaexpressConfig_agencyMode_Fk FOREIGN KEY (agencyModeFK) REFERENCES vn.agencyMode(id) ON DELETE RESTRICT ON UPDATE RESTRICT;

View File

View File

@ -0,0 +1 @@
ALTER TABLE `vn`.`item` DROP COLUMN stars;

View File

@ -0,0 +1,4 @@
REVOKE UPDATE ON TABLE `vn`.`item` FROM `employee`;
GRANT UPDATE(id, equivalent, stems, minPrice, isToPrint, family, box, category, doPhoto, image, inkFk, intrastatFk, hasMinPrice, created, comment, typeFk, generic, producerFk, description, density, relevancy, expenseFk, isActive, subName, tag5, value5, tag6, value6, tag7, value7, tag8, value8, tag9, value9, tag10, value10, minimum, upToDown, supplyResponseFk, hasKgPrice, isFloramondo, isFragile, numberOfItemsPerCask, embalageCode, quality, stemMultiplier, itemPackingTypeFk, packingOut, genericFk, packingShelve, isLaid, lastUsed, weightByPiece, weightByPiece, editorFk, recycledPlastic, nonRecycledPlastic, minQuantity) ON TABLE `vn`.`item` TO `employee`;

View File

@ -0,0 +1,12 @@
ALTER TABLE `vn`.`company` MODIFY COLUMN `supplierAccountFk` mediumint(8) unsigned DEFAULT NULL NULL COMMENT 'Cuenta por defecto para ingresos desde este pais';
ALTER TABLE `vn`.`supplierAccount`
ADD COLUMN `countryFk` mediumint(8) unsigned DEFAULT NULL,
ADD CONSTRAINT `fk_supplierAccount_country`
FOREIGN KEY (`countryFk`) REFERENCES `country` (`id`) ON UPDATE CASCADE;
ALTER TABLE `vn`.`supplierAccount`
ADD UNIQUE KEY `uk_supplier_country` (`supplierFk`, `countryFk`);

View File

@ -0,0 +1,9 @@
ALTER TABLE `vn`.`clientSms` ADD `ticketFk` int(11) NULL;
ALTER TABLE `vn`.`clientSms` ADD CONSTRAINT `clientSms_FK_2` FOREIGN KEY (`ticketFk`) REFERENCES `vn`.`ticket`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
INSERT INTO`vn`.`clientSms` (`clientFk`, `smsFk`, `ticketFk`)
SELECT `t`.`clientFk`, `s`.`smsFk`, `s`.`ticketFk`
FROM `vn`.`clientSms` `s`
JOIN `vn`.`ticket` `t` ON `t`.`id` = `s`.`ticketFk`;
RENAME TABLE `vn`.`ticketSms` TO `vn`.`ticketSms__`;

View File

@ -0,0 +1,74 @@
DELIMITER $$
$$
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticket_canbePostponed`(vOriginDated DATE, vFutureDated DATE, vWarehouseFk INT)
BEGIN
/**
* Devuelve un listado de tickets susceptibles de fusionarse con otros tickets en el futuro
*
* @param vOriginDated Fecha en cuestión
* @param vFutureDated Fecha en el futuro a sondear
* @param vWarehouseFk Identificador de vn.warehouse
*/
CREATE OR REPLACE TEMPORARY TABLE tmp.filter
(INDEX (id))
SELECT sv.ticketFk id,
sub2.id futureId,
GROUP_CONCAT(DISTINCT i.itemPackingTypeFk ORDER BY i.itemPackingTypeFk) ipt,
CAST(sum(litros) AS DECIMAL(10,0)) liters,
CAST(count(*) AS DECIMAL(10,0)) `lines`,
st.name state,
sub2.iptd futureIpt,
sub2.state futureState,
t.clientFk,
t.warehouseFk,
ts.alertLevel,
t.shipped,
t.totalWithVat,
sub2.shipped futureShipped,
t.workerFk,
st.code stateCode,
sub2.code futureStateCode,
st.classColor,
sub2.classColor futureClassColor
FROM vn.saleVolume sv
JOIN vn.sale s ON s.id = sv.saleFk
JOIN vn.item i ON i.id = s.itemFk
JOIN vn.ticket t ON t.id = sv.ticketFk
JOIN vn.address a ON a.id = t.addressFk
JOIN vn.province p ON p.id = a.provinceFk
JOIN vn.country c ON c.id = p.countryFk
JOIN vn.ticketState ts ON ts.ticketFk = t.id
JOIN vn.state st ON st.id = ts.stateFk
JOIN vn.alertLevel al ON al.id = ts.alertLevel
LEFT JOIN vn.ticketParking tp ON tp.ticketFk = t.id
LEFT JOIN (
SELECT *
FROM (
SELECT
t.addressFk,
t.id,
t.shipped,
st.name state,
st.code,
st.classColor,
GROUP_CONCAT(DISTINCT i.itemPackingTypeFk ORDER BY i.itemPackingTypeFk) iptd
FROM vn.ticket t
JOIN vn.ticketState ts ON ts.ticketFk = t.id
JOIN vn.state st ON st.id = ts.stateFk
JOIN vn.sale s ON s.ticketFk = t.id
JOIN vn.item i ON i.id = s.itemFk
WHERE t.shipped BETWEEN vFutureDated
AND util.dayend(vFutureDated)
AND t.warehouseFk = vWarehouseFk
GROUP BY t.id
) sub
GROUP BY sub.addressFk
) sub2 ON sub2.addressFk = t.addressFk AND t.id != sub2.id
WHERE t.shipped BETWEEN vOriginDated AND util.dayend(vOriginDated)
AND t.warehouseFk = vWarehouseFk
AND al.code = 'FREE'
AND tp.ticketFk IS NULL
GROUP BY sv.ticketFk
HAVING futureId;
END$$
DELIMITER ;

View File

@ -0,0 +1,6 @@
INSERT INTO `salix`.`ACL` (model,property,accessType,permission,principalType,principalId) VALUES
('VnRole','*','READ','ALLOW','ROLE','employee'),
('VnRole','*','WRITE','ALLOW','ROLE','it');
DELETE FROM`salix`.`ACL` WHERE model='Role';

View File

@ -0,0 +1,2 @@
ALTER TABLE `vn`.`productionConfig` ADD itemPreviousDefaultSize int NULL COMMENT 'Altura por defecto para los artículos de previa';
UPDATE IGNORE `vn`.`productionConfig` SET itemPreviousDefaultSize = 40 WHERE id = 1;

View File

@ -0,0 +1,9 @@
UPDATE `vn`.`supplierAccount` sa
JOIN `vn`.`country` c ON sa.countryFk = c.id AND c.code = 'FR'
SET countryFk = c.id
WHERE iban = 'FR7630003012690002801121597';
UPDATE `vn`.`supplierAccount` sa
JOIN `vn`.`country` c ON sa.countryFk = c.id AND c.code = 'PT'
SET countryFk = c.id
WHERE iban = 'PT50001000005813059150168';

View File

@ -0,0 +1,2 @@
ALTER TABLE `vn`.`invoiceOutConfig`
ADD IF NOT EXISTS refLen TINYINT UNSIGNED DEFAULT 5 NOT NULL COMMENT 'Invoice reference identifier length';

View File

@ -0,0 +1,59 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`invoiceOut_beforeInsert`
BEFORE INSERT ON `invoiceOut`
FOR EACH ROW
BEGIN
/**
* Generates the next reference for the invoice serial. There cannot be gaps
* between identifiers of the same serial!
*
* Reference format:
* {0} Invoice serial
* {1} The company code
* {2-3} Last two digits of issue year
* {4-$} Autoincrement identifier
*/
DECLARE vRef INT DEFAULT 0;
DECLARE vRefLen INT;
DECLARE vRefPrefix VARCHAR(255);
DECLARE vLastRef VARCHAR(255);
DECLARE vCompanyCode INT;
DECLARE vYearLen INT DEFAULT 2;
DECLARE vPrefixLen INT;
SELECT companyCode INTO vCompanyCode
FROM company
WHERE id = NEW.companyFk;
IF vCompanyCode IS NULL THEN
CALL util.throw('companyCodeNotDefined');
END IF;
SELECT MAX(i.ref) INTO vLastRef
FROM invoiceOut i
WHERE i.serial = NEW.serial
AND i.issued BETWEEN util.firstDayOfYear(NEW.issued) AND util.lastDayOfYear(NEW.issued)
AND i.companyFk = NEW.companyFk;
IF vLastRef IS NOT NULL THEN
SET vPrefixLen = LENGTH(NEW.serial) + LENGTH(vCompanyCode) + vYearLen;
SET vRefLen = LENGTH(vLastRef) - vPrefixLen;
SET vRefPrefix = LEFT(vLastRef, vPrefixLen);
SET vRef = RIGHT(vLastRef, vRefLen);
ELSE
SELECT refLen INTO vRefLen FROM invoiceOutConfig;
SET vRefPrefix = CONCAT(
NEW.serial,
vCompanyCode,
RIGHT(YEAR(NEW.issued), vYearLen)
);
END IF;
SET vRef = vRef + 1;
IF LENGTH(vRef) > vRefLen THEN
CALL util.throw('refIdLenExceeded');
END IF;
SET NEW.ref = CONCAT(vRefPrefix, LPAD(vRef, vRefLen, '0'));
END$$
DELIMITER ;

View File

@ -0,0 +1,589 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`sale_calculateComponent`(vSelf INT, vOption VARCHAR(25))
proc: BEGIN
/**
* Crea tabla temporal para vn.sale_recalcComponent() para recalcular los componentes
*
* @param vSelf Id de la venta
* @param vOption indica en que componente pone el descuadre, NULL en casos habituales
*/
CREATE OR REPLACE TEMPORARY TABLE tmp.recalculateSales
SELECT s.id
FROM sale s
WHERE s.id = vSelf;
CALL sale_recalcComponent(vOption);
DROP TEMPORARY TABLE tmp.recalculateSales;
END$$
DELIMITER ;
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`sale_checkNoComponents`(vCreatedFrom DATETIME, vCreatedTo DATETIME)
BEGIN
/**
* Comprueba que las ventas creadas entre un rango de fechas tienen componentes
*
* @param vCreatedFrom inicio del rango
* @param vCreatedTo fin del rango
*/
DECLARE v_done BOOL DEFAULT FALSE;
DECLARE vSaleFk INTEGER;
DECLARE vTicketFk INTEGER;
DECLARE vConcept VARCHAR(50);
DECLARE vCur CURSOR FOR
SELECT s.id
FROM sale s
JOIN ticket t ON t.id = s.ticketFk
JOIN item i ON i.id = s.itemFk
JOIN itemType tp ON tp.id = i.typeFk
JOIN itemCategory ic ON ic.id = tp.categoryFk
LEFT JOIN tmp.coste c ON c.id = s.id
WHERE s.created >= vCreatedFrom AND s.created <= vCreatedTo
AND c.id IS NULL
AND t.agencyModeFk IS NOT NULL
AND t.isDeleted IS FALSE
AND t.warehouseFk = 60
AND ic.merchandise != FALSE
GROUP BY s.id;
DECLARE CONTINUE HANDLER FOR NOT FOUND
SET v_done = TRUE;
DROP TEMPORARY TABLE IF EXISTS tmp.coste;
DROP TEMPORARY TABLE IF EXISTS tmp.coste;
CREATE TEMPORARY TABLE tmp.coste
(PRIMARY KEY (id)) ENGINE = MEMORY
SELECT s.id
FROM sale s
JOIN item i ON i.id = s.itemFk
JOIN itemType tp ON tp.id = i.typeFk
JOIN itemCategory ic ON ic.id = tp.categoryFk
JOIN saleComponent sc ON sc.saleFk = s.id
JOIN component c ON c.id = sc.componentFk
JOIN componentType ct ON ct.id = c.typeFk AND ct.id = 6
WHERE s.created >= vCreatedFrom
AND ic.merchandise != FALSE;
OPEN vCur;
l: LOOP
SET v_done = FALSE;
FETCH vCur INTO vSaleFk;
IF v_done THEN
LEAVE l;
END IF;
SELECT ticketFk, concept
INTO vTicketFk, vConcept
FROM sale
WHERE id = vSaleFk;
CALL sale_calculateComponent(vSaleFk, 'renewPrices');
END LOOP;
CLOSE vCur;
DROP TEMPORARY TABLE tmp.coste;
END$$
DELIMITER ;
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`sale_recalcComponent`(vOption VARCHAR(25))
proc: BEGIN
/**
* Este procedimiento recalcula los componentes de un conjunto de sales,
* eliminando los componentes existentes e insertandolos de nuevo
*
* @param vOption si no se quiere forzar llamar con NULL
* @table tmp.recalculateSales (id)
*/
DECLARE vShipped DATE;
DECLARE vWarehouseFk SMALLINT;
DECLARE vAgencyModeFk INT;
DECLARE vAddressFk INT;
DECLARE vTicketFk INT;
DECLARE vLanded DATE;
DECLARE vIsEditable BOOLEAN;
DECLARE vZoneFk INTEGER;
DECLARE vDone BOOL DEFAULT FALSE;
DECLARE vCur CURSOR FOR
SELECT DISTINCT s.ticketFk
FROM tmp.recalculateSales rs
JOIN vn.sale s ON s.id = rs.id;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE;
OPEN vCur;
l: LOOP
SET vDone = FALSE;
FETCH vCur INTO vTicketFk;
IF vDone THEN
LEAVE l;
END IF;
SELECT (hasToRecalcPrice OR ts.alertLevel IS NULL) AND t.refFk IS NULL,
t.zoneFk,
t.warehouseFk,
t.shipped,
t.addressFk,
t.agencyModeFk,
t.landed
INTO vIsEditable,
vZoneFk,
vWarehouseFk,
vShipped,
vAddressFk,
vAgencyModeFk,
vLanded
FROM ticket t
LEFT JOIN ticketState ts ON t.id = ts.ticketFk
LEFT JOIN alertLevel al ON al.id = ts.alertLevel
WHERE t.id = vTicketFk;
CALL zone_getLanded(vShipped, vAddressFk, vAgencyModeFk, vWarehouseFk, TRUE);
IF NOT EXISTS (SELECT TRUE FROM tmp.zoneGetLanded LIMIT 1) THEN
CALL util.throw(CONCAT('There is no zone for these parameters ', vTicketFk));
END IF;
IF vLanded IS NULL OR vZoneFk IS NULL THEN
UPDATE ticket t
SET t.landed = (SELECT landed FROM tmp.zoneGetLanded LIMIT 1)
WHERE t.id = vTicketFk AND t.landed IS NULL;
IF vZoneFk IS NULL THEN
SELECT zoneFk INTO vZoneFk FROM tmp.zoneGetLanded LIMIT 1;
UPDATE ticket t
SET t.zoneFk = vZoneFk
WHERE t.id = vTicketFk AND t.zoneFk IS NULL;
END IF;
END IF;
DROP TEMPORARY TABLE tmp.zoneGetLanded;
-- rellena la tabla buyUltimate con la ultima compra
CALL buyUltimate (vWarehouseFk, vShipped);
CREATE OR REPLACE TEMPORARY TABLE tmp.sale
(PRIMARY KEY (saleFk)) ENGINE = MEMORY
SELECT s.id saleFk, vWarehouseFk warehouseFk
FROM sale s
JOIN tmp.recalculateSales rs ON s.id = rs.id
WHERE s.ticketFk = vTicketFk;
CREATE OR REPLACE TEMPORARY TABLE tmp.ticketLot
SELECT vWarehouseFk warehouseFk, NULL available, s.itemFk, bu.buyFk, vZoneFk zoneFk
FROM sale s
JOIN tmp.recalculateSales rs ON s.id = rs.id
LEFT JOIN tmp.buyUltimate bu ON bu.itemFk = s.itemFk
WHERE s.ticketFk = vTicketFk
GROUP BY s.itemFk;
CALL catalog_componentPrepare();
CALL catalog_componentCalculate(vZoneFk, vAddressFk, vShipped, vWarehouseFk);
IF vOption IS NULL THEN
SET vOption = IF(vIsEditable, 'renewPrices', 'imbalance');
END IF;
CALL ticketComponentUpdateSale(vOption);
CALL catalog_componentPurge();
DROP TEMPORARY TABLE tmp.buyUltimate;
DROP TEMPORARY TABLE tmp.sale;
END LOOP;
CLOSE vCur;
END$$
DELIMITER ;
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticketCalculateClon`(IN vTicketNew INT, vTicketOld INT)
BEGIN
/*
* Recalcula los componentes un ticket clonado,
* las lineas a precio cero fuerza para que tengan precio, el resto lo respeta
* @param vTicketNew nuevo ticket clonado
* @param vTicketOld icket original, a partir del qual se clonara el nuevo
*/
REPLACE INTO orderTicket(orderFk,ticketFk)
SELECT orderFk, vTicketNew
FROM orderTicket
WHERE ticketFk = vTicketOld;
-- Bionizamos lineas con Preu = 0
CREATE OR REPLACE TEMPORARY TABLE tmp.recalculateSales
(PRIMARY KEY (id)) ENGINE = MEMORY
SELECT id
FROM sale
WHERE ticketFk = vTicketNew AND price = 0;
CALL sale_recalcComponent('renewPrices');
-- Bionizamos lineas con Preu > 0
CREATE OR REPLACE TEMPORARY TABLE tmp.recalculateSales
(PRIMARY KEY (id)) ENGINE = MEMORY
SELECT id
FROM sale
WHERE ticketFk = vTicketNew AND price > 0;
CALL sale_recalcComponent('imbalance');
DROP TEMPORARY TABLE IF EXISTS tmp.recalculateSales;
END$$
DELIMITER ;
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticketComponentUpdate`(
vTicketFk INT,
vClientFk INT,
vAgencyModeFk INT,
vAddressFk INT,
vWarehouseFk TINYINT,
vCompanyFk SMALLINT,
vShipped DATETIME,
vLanded DATE,
vIsDeleted BOOLEAN,
vHasToBeUnrouted BOOLEAN,
vOption VARCHAR(25))
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
RESIGNAL;
END;
START TRANSACTION;
IF (SELECT addressFk FROM ticket WHERE id = vTicketFk) <> vAddressFk THEN
UPDATE ticket t
JOIN address a ON a.id = vAddressFk
SET t.nickname = a.nickname
WHERE t.id = vTicketFk;
END IF;
UPDATE ticket t
SET
t.clientFk = vClientFk,
t.agencyModeFk = vAgencyModeFk,
t.addressFk = vAddressFk,
t.warehouseFk = vWarehouseFk,
t.companyFk = vCompanyFk,
t.landed = vLanded,
t.shipped = vShipped,
t.isDeleted = vIsDeleted
WHERE
t.id = vTicketFk;
IF vHasToBeUnrouted THEN
UPDATE ticket t SET t.routeFk = NULL
WHERE t.id = vTicketFk;
END IF;
DROP TEMPORARY TABLE IF EXISTS tmp.sale;
CREATE TEMPORARY TABLE tmp.sale
(PRIMARY KEY (saleFk))
ENGINE = MEMORY
SELECT id AS saleFk, vWarehouseFk warehouseFk
FROM sale s WHERE s.ticketFk = vTicketFk;
CALL ticketComponentUpdateSale (vOption);
DROP TEMPORARY TABLE tmp.sale;
COMMIT;
END$$
DELIMITER ;
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticketComponentUpdateSale`(vCode VARCHAR(25))
BEGIN
/**
* A partir de la tabla tmp.sale, crea los Movimientos_componentes
* y modifica el campo Preu de la tabla Movimientos
*
* @param i_option integer tipo de actualizacion
* @param table tmp.sale tabla memory con el campo saleFk, warehouseFk
**/
DECLARE vComponentFk INT;
IF vCode <> 'renewPrices' THEN
SELECT id INTO vComponentFk FROM component WHERE `code` = vCode;
END IF;
DELETE sc.*
FROM tmp.sale tmps
JOIN saleComponent sc ON sc.saleFk = tmps.saleFk
JOIN `component` c ON c.id = sc.componentFk
WHERE c.isRenewable;
REPLACE INTO saleComponent(saleFk, componentFk, value)
SELECT s.id, tc.componentFk, tc.cost
FROM sale s
JOIN tmp.sale tmps ON tmps.saleFk = s.id
JOIN tmp.ticketComponent tc ON tc.itemFk = s.itemFk AND tc.warehouseFk = tmps.warehouseFk
LEFT JOIN saleComponent sc ON sc.saleFk = s.id
AND sc.componentFk = tc.componentFk
LEFT JOIN `component` c ON c.id = tc.componentFk
WHERE IF(sc.componentFk IS NULL AND NOT c.isRenewable, FALSE, TRUE);
-- Añadir componente venta por paquete
REPLACE INTO saleComponent(saleFk, componentFk, value)
SELECT t.id, t.componentFk, t.cost
FROM (
SELECT s.id, tc.componentFk, tc.cost, MOD(s.quantity, b.packing) as resto
FROM vn.sale s
JOIN tmp.sale tmps ON tmps.saleFk = s.id
JOIN cache.last_buy lb ON lb.item_id = s.itemFk AND tmps.warehouseFk = lb.warehouse_id
JOIN vn.buy b ON b.id = buy_id
JOIN tmp.ticketComponent tc ON tc.itemFk = s.itemFk AND tc.warehouseFk = tmps.warehouseFk
JOIN `component` c ON c.id = tc.componentFk AND c.code = 'salePerPackage'
LEFT JOIN (
SELECT s.id
FROM vn.sale s
JOIN tmp.sale tmps ON tmps.saleFk = s.id
JOIN tmp.ticketComponent tc ON tc.itemFk = s.itemFk AND tc.warehouseFk = tmps.warehouseFk
JOIN saleComponent sc ON sc.saleFk = s.id AND sc.componentFk = tc.componentFk
JOIN `component` c ON c.id = sc.componentFk AND c.code = 'lastUnitsDiscount'
) tp ON tp.id = s.id
WHERE tp.id IS NULL
HAVING resto <> 0) t;
IF vCode <> 'renewPrices' THEN
REPLACE INTO saleComponent(saleFk, componentFk, value)
SELECT s.id, vComponentFk, ROUND((s.price * (100 - s.discount) / 100) - SUM(sc.value), 3) dif
FROM sale s
JOIN tmp.sale tmps ON tmps.saleFk = s.id
LEFT JOIN saleComponent sc ON sc.saleFk = s.id
WHERE sc.saleFk <> vComponentFk
GROUP BY s.id
HAVING dif <> 0;
ELSE
UPDATE sale s
JOIN item i on i.id = s.itemFk
JOIN itemType it on it.id = i.typeFk
JOIN (SELECT SUM(sc.value) sumValue, sc.saleFk
FROM saleComponent sc
JOIN tmp.sale tmps ON tmps.saleFk = sc.saleFk
GROUP BY sc.saleFk) sc ON sc.saleFk = s.id
SET s.price = sumValue / ((100 - s.discount) / 100)
WHERE it.code != 'PRT' ;
REPLACE INTO saleComponent(saleFk, componentFk, value)
SELECT s.id, 21, ROUND((s.price * (100 - s.discount) / 100) - SUM(value), 3) saleValue
FROM sale s
JOIN tmp.sale tmps ON tmps.saleFk = s.id
LEFT JOIN saleComponent sc ON sc.saleFk = s.id
WHERE sc.componentFk != 21
GROUP BY s.id
HAVING ROUND(saleValue, 4) <> 0;
END IF;
UPDATE sale s
JOIN (
SELECT SUM(sc.value) sumValue, sc.saleFk
FROM saleComponent sc
JOIN tmp.sale tmps ON tmps.saleFk = sc.saleFk
JOIN `component` c ON c.id = sc.componentFk
JOIN componentType ct on ct.id = c.typeFk AND ct.isBase
GROUP BY sc.saleFk) sc ON sc.saleFk = s.id
SET s.priceFixed = sumValue, s.isPriceFixed = 1;
DELETE sc.*
FROM saleComponent sc
JOIN tmp.sale tmps ON tmps.saleFk = sc.saleFk
JOIN sale s on s.id = sc.saleFk
JOIN item i ON i.id = s.itemFk
JOIN itemType it ON it.id = i.typeFk
WHERE it.code = 'PRT';
INSERT INTO saleComponent(saleFk, componentFk, value)
SELECT s.id, 15, s.price
FROM sale s
JOIN tmp.sale tmps ON tmps.saleFk = s.id
JOIN item i ON i.id = s.itemFK
JOIN itemType it ON it.id = i.typeFk
WHERE it.code = 'PRT' AND s.price > 0;
END$$
DELIMITER ;
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticket_checkNoComponents`(vShippedFrom DATETIME, vShippedTo DATETIME)
BEGIN
/**
* Comprueba que los tickets entre un rango de fechas tienen componentes
* y recalcula sus componentes
*
* @param vShippedFrom rango inicial de fecha
* @param vShippedTo rango final de fecha
*/
CREATE OR REPLACE TEMPORARY TABLE tmp.coste
(primary key (id)) ENGINE = MEMORY
SELECT s.id
FROM ticket t
JOIN sale s ON s.ticketFk = t.id
JOIN item i ON i.id = s.itemFk
JOIN itemType tp ON tp.id = i.typeFk
JOIN itemCategory ic ON ic.id = tp.categoryFk
JOIN saleComponent sc ON sc.saleFk = s.id
JOIN component c ON c.id = sc.componentFk
JOIN componentType ct ON ct.id = c.typeFk AND ct.id = 1
WHERE t.shipped BETWEEN vShippedFrom AND vShippedTo
AND ic.merchandise;
CREATE OR REPLACE TEMPORARY TABLE tmp.recalculateSales
(primary key (id)) ENGINE = MEMORY
SELECT DISTINCT s.id
FROM ticket t
JOIN sale s ON s.ticketFk = t.id
JOIN item i ON i.id = s.itemFk
JOIN itemType tp ON tp.id = i.typeFk
JOIN itemCategory ic ON ic.id = tp.categoryFk
LEFT JOIN tmp.coste c ON c.id = s.id
WHERE t.shipped >= vShippedFrom AND t.shipped <= vShippedTo
AND c.id IS NULL
AND ic.merchandise;
CALL sale_recalcComponent('renewPrices');
DROP TEMPORARY TABLE tmp.recalculateSales;
DROP TEMPORARY TABLE tmp.coste;
END$$
DELIMITER ;
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticket_componentMakeUpdate`(
vTicketFk INT,
vClientFk INT,
vNickname VARCHAR(50),
vAgencyModeFk INT,
vAddressFk INT,
vZoneFk INT,
vWarehouseFk INT,
vCompanyFk INT,
vShipped DATETIME,
vLanded DATE,
vIsDeleted BOOLEAN,
vHasToBeUnrouted BOOLEAN,
vOption VARCHAR(25))
BEGIN
/**
* Modifica en el ticket los campos que se le pasan por parámetro
* y cambia sus componentes
*
* @param vTicketFk Id del ticket a modificar
* @param vClientFk nuevo cliente
* @param vNickname nuevo alias
* @param vAgencyModeFk nueva agencia
* @param vAddressFk nuevo consignatario
* @param vZoneFk nueva zona
* @param vWarehouseFk nuevo almacen
* @param vCompanyFk nueva empresa
* @param vShipped nueva fecha del envio de mercancia
* @param vLanded nueva fecha de recepcion de mercancia
* @param vIsDeleted si se borra el ticket
* @param vHasToBeUnrouted si se le elimina la ruta al ticket
* @param vOption opcion para el case del proc ticketComponentUpdateSale
*/
DECLARE vPrice DECIMAL(10,2);
DECLARE vBonus DECIMAL(10,2);
CALL ticket_componentPreview (vTicketFk, vLanded, vAddressFk, vZoneFk, vWarehouseFk);
IF (SELECT addressFk FROM ticket WHERE id = vTicketFk) <> vAddressFk THEN
UPDATE ticket t
JOIN address a ON a.id = vAddressFk
SET t.nickname = a.nickname
WHERE t.id = vTicketFk;
END IF;
CALL zone_getShipped(vLanded, vAddressFk, vAgencyModeFk, TRUE);
SELECT zoneFk, price, bonus INTO vZoneFk, vPrice, vBonus
FROM tmp.zoneGetShipped
WHERE shipped BETWEEN DATE(vShipped) AND util.dayEnd(vShipped) AND warehouseFk = vWarehouseFk LIMIT 1;
UPDATE ticket t
SET
t.clientFk = vClientFk,
t.nickname = vNickname,
t.agencyModeFk = vAgencyModeFk,
t.addressFk = vAddressFk,
t.zoneFk = vZoneFk,
t.zonePrice = vPrice,
t.zoneBonus = vBonus,
t.warehouseFk = vWarehouseFk,
t.companyFk = vCompanyFk,
t.landed = vLanded,
t.shipped = vShipped,
t.isDeleted = vIsDeleted
WHERE
t.id = vTicketFk;
IF vHasToBeUnrouted THEN
UPDATE ticket t SET t.routeFk = NULL
WHERE t.id = vTicketFk;
END IF;
DROP TEMPORARY TABLE IF EXISTS tmp.sale;
CREATE TEMPORARY TABLE tmp.sale
(PRIMARY KEY (saleFk))
ENGINE = MEMORY
SELECT id AS saleFk, vWarehouseFk warehouseFk
FROM sale s WHERE s.ticketFk = vTicketFk;
DROP TEMPORARY TABLE IF EXISTS tmp.ticketComponent;
CREATE TEMPORARY TABLE tmp.ticketComponent
SELECT * FROM tmp.ticketComponentPreview;
CALL ticketComponentUpdateSale (vOption);
DROP TEMPORARY TABLE tmp.sale;
DROP TEMPORARY TABLE IF EXISTS tmp.ticketComponent;
DROP TEMPORARY TABLE tmp.zoneGetShipped, tmp.ticketComponentPreview;
END$$
DELIMITER ;
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticket_recalcComponents`(vSelf INT, vOption VARCHAR(25))
proc: BEGIN
/**
* Crea tabla temporal para sale_recalcComponent() para recalcular los componentes
*
* @param vSelf Id del ticket
* @param vOption si no se quiere forzar llamar con NULL
*/
CREATE OR REPLACE TEMPORARY TABLE tmp.recalculateSales
SELECT s.id
FROM sale s
WHERE s.ticketFk = vSelf;
CALL sale_recalcComponent(vOption);
DROP TEMPORARY TABLE tmp.recalculateSales;
END$$
DELIMITER ;
TRUNCATE TABLE `vn`.`ticketUpdateAction`;
INSERT INTO `vn`.`ticketUpdateAction` (id, description, code) VALUES(1, 'Cambiar los precios en el ticket', 'renewPrices');
INSERT INTO `vn`.`ticketUpdateAction` (id, description, code) VALUES(2, 'Convertir en maná', 'mana');

View File

@ -0,0 +1,5 @@
DELETE FROM salix.ACL
WHERE model = 'MailAliasAccount'
AND property = 'canEditAlias'
AND principalType = 'ROLE'
AND principalId = 'marketingBoss';

View File

@ -600,20 +600,24 @@ INSERT INTO `vn`.`taxArea` (`code`, `claveOperacionFactura`, `CodigoTransaccion`
('NATIONAL', 0, 1), ('NATIONAL', 0, 1),
('WORLD', 2, 15); ('WORLD', 2, 15);
INSERT INTO vn.invoiceOutConfig
SET parallelism = 8;
INSERT INTO `vn`.`invoiceOutSerial` (`code`, `description`, `isTaxed`, `taxAreaFk`, `isCEE`, `type`) INSERT INTO `vn`.`invoiceOutSerial` (`code`, `description`, `isTaxed`, `taxAreaFk`, `isCEE`, `type`)
VALUES VALUES
('A', 'Global nacional', 1, 'NATIONAL', 0, 'global'), ('A', 'Global nacional', 1, 'NATIONAL', 0, 'global'),
('T', 'Española rapida', 1, 'NATIONAL', 0, 'quick'), ('T', 'Española rapida', 1, 'NATIONAL', 0, 'quick'),
('V', 'Intracomunitaria global', 0, 'CEE', 1, 'global'), ('V', 'Intracomunitaria global', 0, 'CEE', 1, 'global'),
('M', 'Múltiple nacional', 1, 'NATIONAL', 0, 'quick'), ('M', 'Múltiple nacional', 1, 'NATIONAL', 0, 'quick'),
('E', 'Exportación rápida', 0, 'WORLD', 0, 'quick'); ('R', 'Rectificativa', 1, 'NATIONAL', 0, NULL),
('E', 'Exportación rápida', 0, 'WORLD', 0, 'quick');
INSERT INTO `vn`.`invoiceOut`(`id`, `serial`, `amount`, `issued`,`clientFk`, `created`, `companyFk`, `dued`, `booked`, `bankFk`, `hasPdf`) INSERT INTO `vn`.`invoiceOut`(`id`, `serial`, `amount`, `issued`,`clientFk`, `created`, `companyFk`, `dued`, `booked`, `bankFk`, `hasPdf`)
VALUES VALUES
(1, 'T', 1026.24, util.VN_CURDATE(), 1101, util.VN_CURDATE(), 442, util.VN_CURDATE(), util.VN_CURDATE(), 1, 0), (1, 'T', 1026.24, util.VN_CURDATE(), 1101, util.VN_CURDATE(), 442, util.VN_CURDATE(), util.VN_CURDATE(), 1, 0),
(2, 'T', 121.36, util.VN_CURDATE(), 1102, util.VN_CURDATE(), 442, util.VN_CURDATE(), util.VN_CURDATE(), 1, 0), (2, 'T', 121.36, util.VN_CURDATE(), 1102, util.VN_CURDATE(), 442, util.VN_CURDATE(), util.VN_CURDATE(), 1, 0),
(3, 'T', 8.88, util.VN_CURDATE(), 1103, util.VN_CURDATE(), 442, util.VN_CURDATE(), util.VN_CURDATE(), 1, 0), (3, 'T', 8.88, util.VN_CURDATE(), 1103, util.VN_CURDATE(), 442, util.VN_CURDATE(), util.VN_CURDATE(), 1, 0),
(4, 'T', 8.88, util.VN_CURDATE(), 1103, util.VN_CURDATE(), 442, util.VN_CURDATE(), util.VN_CURDATE(), 1, 0), (4, 'T', 8.88, util.VN_CURDATE(), 1104, util.VN_CURDATE(), 442, util.VN_CURDATE(), util.VN_CURDATE(), 1, 0),
(5, 'A', 8.88, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1103, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 442, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1, 0); (5, 'A', 8.88, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1103, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 442, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1, 0);
UPDATE `vn`.`invoiceOut` SET ref = 'T1111111' WHERE id = 1; UPDATE `vn`.`invoiceOut` SET ref = 'T1111111' WHERE id = 1;
@ -622,9 +626,6 @@ UPDATE `vn`.`invoiceOut` SET ref = 'T3333333' WHERE id = 3;
UPDATE `vn`.`invoiceOut` SET ref = 'T4444444' WHERE id = 4; UPDATE `vn`.`invoiceOut` SET ref = 'T4444444' WHERE id = 4;
UPDATE `vn`.`invoiceOut` SET ref = 'A1111111' WHERE id = 5; UPDATE `vn`.`invoiceOut` SET ref = 'A1111111' WHERE id = 5;
INSERT INTO vn.invoiceOutConfig
SET parallelism = 8;
INSERT INTO `vn`.`invoiceOutTax` (`invoiceOutFk`, `taxableBase`, `vat`, `pgcFk`) INSERT INTO `vn`.`invoiceOutTax` (`invoiceOutFk`, `taxableBase`, `vat`, `pgcFk`)
VALUES VALUES
(1, 895.76, 89.58, 4722000010), (1, 895.76, 89.58, 4722000010),
@ -719,7 +720,7 @@ INSERT INTO `vn`.`route`(`id`, `time`, `workerFk`, `created`, `vehicleFk`, `agen
INSERT INTO `vn`.`ticket`(`id`, `priority`, `agencyModeFk`,`warehouseFk`,`routeFk`, `shipped`, `landed`, `clientFk`,`nickname`, `addressFk`, `refFk`, `isDeleted`, `zoneFk`, `zonePrice`, `zoneBonus`, `created`, `weight`) INSERT INTO `vn`.`ticket`(`id`, `priority`, `agencyModeFk`,`warehouseFk`,`routeFk`, `shipped`, `landed`, `clientFk`,`nickname`, `addressFk`, `refFk`, `isDeleted`, `zoneFk`, `zonePrice`, `zoneBonus`, `created`, `weight`)
VALUES VALUES
(1 , 3, 1, 1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -1 MONTH), INTERVAL +1 DAY), 1101, 'Bat cave', 121, NULL, 0, 1, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1), (1 , 3, 1, 1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -1 MONTH), INTERVAL +1 DAY), 1101, 'Bat cave', 121, NULL, 0, 1, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1),
(2 , 1, 1, 1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -1 MONTH), INTERVAL +1 DAY), 1104, 'Stark tower', 124, NULL, 0, 1, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 2), (2 , 1, 1, 1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -1 MONTH), INTERVAL +1 DAY), 1101, 'Bat cave', 1, NULL, 0, 1, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 2),
(3 , 1, 7, 1, 6, DATE_ADD(util.VN_CURDATE(), INTERVAL -2 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -2 MONTH), INTERVAL +1 DAY), 1104, 'Stark tower', 124, NULL, 0, 3, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -2 MONTH), NULL), (3 , 1, 7, 1, 6, DATE_ADD(util.VN_CURDATE(), INTERVAL -2 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -2 MONTH), INTERVAL +1 DAY), 1104, 'Stark tower', 124, NULL, 0, 3, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -2 MONTH), NULL),
(4 , 3, 2, 1, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -3 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -3 MONTH), INTERVAL +1 DAY), 1104, 'Stark tower', 124, NULL, 0, 9, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -3 MONTH), NULL), (4 , 3, 2, 1, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -3 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -3 MONTH), INTERVAL +1 DAY), 1104, 'Stark tower', 124, NULL, 0, 9, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -3 MONTH), NULL),
(5 , 3, 3, 3, 3, DATE_ADD(util.VN_CURDATE(), INTERVAL -4 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -4 MONTH), INTERVAL +1 DAY), 1104, 'Stark tower', 124, NULL, 0, 10, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -4 MONTH), NULL), (5 , 3, 3, 3, 3, DATE_ADD(util.VN_CURDATE(), INTERVAL -4 MONTH), DATE_ADD(DATE_ADD(util.VN_CURDATE(),INTERVAL -4 MONTH), INTERVAL +1 DAY), 1104, 'Stark tower', 124, NULL, 0, 10, 5, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -4 MONTH), NULL),
@ -928,25 +929,25 @@ INSERT INTO `vn`.`itemFamily`(`code`, `description`)
('VT', 'Sales'); ('VT', 'Sales');
INSERT INTO `vn`.`item`(`id`, `typeFk`, `stems`, `originFk`, `description`, `producerFk`, `intrastatFk`, `expenseFk`, INSERT INTO `vn`.`item`(`id`, `typeFk`, `stems`, `originFk`, `description`, `producerFk`, `intrastatFk`, `expenseFk`,
`comment`, `relevancy`, `image`, `subName`, `minPrice`, `stars`, `family`, `isFloramondo`, `genericFk`, `itemPackingTypeFk`, `hasMinPrice`, `packingShelve`, `weightByPiece`) `comment`, `relevancy`, `image`, `subName`, `minPrice`, `family`, `isFloramondo`, `genericFk`, `itemPackingTypeFk`, `hasMinPrice`, `packingShelve`, `weightByPiece`)
VALUES VALUES
(1, 2, 1, 1, NULL, 1, 06021010, 2000000000, NULL, 0, '1', NULL, 0, 1, 'EMB', 0, NULL, 'V', 0, 15,3), (1, 2, 1, 1, NULL, 1, 06021010, 2000000000, NULL, 0, '1', NULL, 0, 'EMB', 0, NULL, 'V', 0, 15,3),
(2, 2, 1, 2, NULL, 1, 06021010, 2000000000, NULL, 0, '2', NULL, 0, 2, 'VT', 0, NULL, 'H', 0, 10,2), (2, 2, 1, 2, NULL, 1, 06021010, 2000000000, NULL, 0, '2', NULL, 0, 'VT', 0, NULL, 'H', 0, 10,2),
(3, 1, 1, 3, NULL, 1, 05080000, 4751000000, NULL, 0, '3', NULL, 0, 5, 'VT', 0, NULL, NULL, 0, 5,5), (3, 1, 1, 3, NULL, 1, 05080000, 4751000000, NULL, 0, '3', NULL, 0, 'VT', 0, NULL, NULL, 0, 5,5),
(4, 1, 1, 1, 'Increases block', 1, 05080000, 4751000000, NULL, 0, '4', NULL, 0, 3, 'VT', 0, NULL, NULL, 0, NULL,NULL), (4, 1, 1, 1, 'Increases block', 1, 05080000, 4751000000, NULL, 0, '4', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL,NULL),
(5, 3, 1, 2, NULL, 2, 06021010, 4751000000, NULL, 0, '5', NULL, 0, 3, 'VT', 0, NULL, NULL, 0, NULL,NULL), (5, 3, 1, 2, NULL, 2, 06021010, 4751000000, NULL, 0, '5', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL,NULL),
(6, 5, 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '6', NULL, 0, 4, 'VT', 0, NULL, NULL, 0, NULL,NULL), (6, 5, 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '6', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL,NULL),
(7, 5, 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '7', NULL, 0, 4, 'VT', 0, NULL, NULL, 0, NULL,NULL), (7, 5, 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '7', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL,NULL),
(8, 2, 1, 1, NULL, 1, 06021010, 2000000000, NULL, 0, '8', NULL, 0, 5, 'VT', 0, NULL, NULL, 0, NULL,NULL), (8, 2, 1, 1, NULL, 1, 06021010, 2000000000, NULL, 0, '8', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL,NULL),
(9, 2, 1, 2, NULL, 1, 06021010, 2000000000, NULL, 0, '9', NULL, 0, 4, 'VT', 1, NULL, NULL, 0, NULL,NULL), (9, 2, 1, 2, NULL, 1, 06021010, 2000000000, NULL, 0, '9', NULL, 0, 'VT', 1, NULL, NULL, 0, NULL,NULL),
(10, 1, 1, 3, NULL, 1, 05080000, 4751000000, NULL, 0, '10', NULL, 0, 4, 'VT', 0, NULL, NULL, 0, NULL,NULL), (10, 1, 1, 3, NULL, 1, 05080000, 4751000000, NULL, 0, '10', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL,NULL),
(11, 1, 1, 1, NULL, 1, 05080000, 4751000000, NULL, 0, '11', NULL, 0, 4, 'VT', 0, NULL, NULL, 0, NULL,NULL), (11, 1, 1, 1, NULL, 1, 05080000, 4751000000, NULL, 0, '11', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL,NULL),
(12, 3, 1, 2, NULL, 2, 06021010, 4751000000, NULL, 0, '12', NULL, 0, 3, 'VT', 0, NULL, NULL, 0, NULL,NULL), (12, 3, 1, 2, NULL, 2, 06021010, 4751000000, NULL, 0, '12', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL,NULL),
(13, 5, 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '13', NULL, 1, 2, 'VT', 1, NULL, NULL, 1, NULL,NULL), (13, 5, 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '13', NULL, 1, 'VT', 1, NULL, NULL, 1, NULL,NULL),
(14, 5, 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 4, 'VT', 1, NULL, NULL, 0, NULL,NULL), (14, 5, 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 'VT', 1, NULL, NULL, 0, NULL,NULL),
(15, 4, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 0, 'EMB', 0, NULL, NULL, 0, NULL,NULL), (15, 4, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 'EMB', 0, NULL, NULL, 0, NULL,NULL),
(16, 6, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 0, 'EMB', 0, NULL, NULL, 0, NULL,NULL), (16, 6, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 'EMB', 0, NULL, NULL, 0, NULL,NULL),
(71, 6, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 0, 'VT', 0, NULL, NULL, 0, NULL,NULL); (71, 6, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL,NULL);
-- Update the taxClass after insert of the items -- Update the taxClass after insert of the items
UPDATE `vn`.`itemTaxCountry` SET `taxClassFk` = 2 UPDATE `vn`.`itemTaxCountry` SET `taxClassFk` = 2
@ -1425,16 +1426,29 @@ INSERT INTO `vn`.`ticketWeekly`(`ticketFk`, `weekDay`)
(5, 6), (5, 6),
(15, 6); (15, 6);
INSERT INTO `vn`.`travel`(`id`,`shipped`, `landed`, `warehouseInFk`, `warehouseOutFk`, `agencyModeFk`, `m3`, `kg`,`ref`, `totalEntries`, `cargoSupplierFk`) INSERT INTO `vn`.`awb` (id, code, package, weight, created, amount, transitoryFk, taxFk)
VALUES VALUES
(1, DATE_ADD(util.VN_CURDATE(), INTERVAL -2 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -2 MONTH), 1, 2, 1, 100.00, 1000, 'first travel', 1, 1), (1, '07546501420', 67, 671, util.VN_CURDATE(), 1761, 1, 1),
(2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1, 2, 1, 150, 2000, 'second travel', 2, 2), (2, '07546491421', 252, 2769, util.VN_CURDATE(), 5231, 1, 1),
(3, util.VN_CURDATE(), util.VN_CURDATE(), 1, 2, 1, 0.00, 0.00, 'third travel', 1, 1), (3, '07546500823', 102, 1495, util.VN_CURDATE(), 3221, 1, 1),
(4, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1, 3, 1, 50.00, 500, 'fourth travel', 0, 2), (4, '99610288821', 252, 2777, util.VN_CURDATE(), 3641, 1, 1),
(5, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 3, 3, 1, 50.00, 500, 'fifth travel', 1, 1), (5, '07546500834', 229, 3292, util.VN_CURDATE(), 6601, 2, 1),
(6, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 4, 4, 1, 50.00, 500, 'sixth travel', 1, 2), (6, '22101929561', 37, 458, util.VN_CURDATE(), 441, 2, 1),
(7, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 5, 4, 1, 50.00, 500, 'seventh travel', 2, 1), (7, '07546491432', 258, 3034, util.VN_CURDATE(), 6441, 2, 1),
(8, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 5, 1, 1, 50.00, 500, 'eight travel', 1, 2); (8, '99610288644', 476, 4461, util.VN_CURDATE(), 5751, 442, 1),
(9, '99610289193', 302, 2972, util.VN_CURDATE(), 3871, 442, 1),
(10, '07546500856', 185, 2364, util.VN_CURDATE(), 5321, 442, 1);
INSERT INTO `vn`.`travel`(`id`,`shipped`, `landed`, `warehouseInFk`, `warehouseOutFk`, `agencyModeFk`, `m3`, `kg`,`ref`, `totalEntries`, `cargoSupplierFk`, `awbFK`)
VALUES
(1, DATE_ADD(util.VN_CURDATE(), INTERVAL -2 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -2 MONTH), 1, 2, 1, 100.00, 1000, 'first travel', 1, 1, 1),
(2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1, 2, 1, 150, 2000, 'second travel', 2, 2, 2),
(3, util.VN_CURDATE(), util.VN_CURDATE(), 1, 2, 1, 0.00, 0.00, 'third travel', 1, 1, 3),
(4, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1, 3, 1, 50.00, 500, 'fourth travel', 0, 2, 4),
(5, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 3, 3, 1, 50.00, 500, 'fifth travel', 1, 1, 5),
(6, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 4, 4, 1, 50.00, 500, 'sixth travel', 1, 2, 6),
(7, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 5, 4, 1, 50.00, 500, 'seventh travel', 2, 1, 7),
(8, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 5, 1, 1, 50.00, 500, 'eight travel', 1, 2, 10);
INSERT INTO `vn`.`entry`(`id`, `supplierFk`, `created`, `travelFk`, `isConfirmed`, `companyFk`, `invoiceNumber`, `reference`, `isExcludedFromAvailable`, `isRaid`, `evaNotes`) INSERT INTO `vn`.`entry`(`id`, `supplierFk`, `created`, `travelFk`, `isConfirmed`, `companyFk`, `invoiceNumber`, `reference`, `isExcludedFromAvailable`, `isRaid`, `evaNotes`)
VALUES VALUES
@ -2498,20 +2512,7 @@ INSERT INTO `vn`.`rate`(`dated`, `warehouseFk`, `rate0`, `rate1`, `rate2`, `rate
(DATE_ADD(util.VN_CURDATE(), INTERVAL -1 YEAR), 1, 10, 15, 20, 25), (DATE_ADD(util.VN_CURDATE(), INTERVAL -1 YEAR), 1, 10, 15, 20, 25),
(util.VN_CURDATE(), 1, 12, 17, 22, 27); (util.VN_CURDATE(), 1, 12, 17, 22, 27);
INSERT INTO `vn`.`awb` (id, code, package, weight, created, amount, transitoryFk, taxFk) INSERT INTO `vn`.`dua` (id, code, awbFk__, issued, operated, booked, bookEntried, gestdocFk, customsValue, companyFk)
VALUES
(1, '07546501420', 67, 671, util.VN_CURDATE(), 1761, 1, 1),
(2, '07546491421', 252, 2769, util.VN_CURDATE(), 5231, 1, 1),
(3, '07546500823', 102, 1495, util.VN_CURDATE(), 3221, 1, 1),
(4, '99610288821', 252, 2777, util.VN_CURDATE(), 3641, 1, 1),
(5, '07546500834', 229, 3292, util.VN_CURDATE(), 6601, 2, 1),
(6, '22101929561', 37, 458, util.VN_CURDATE(), 441, 2, 1),
(7, '07546491432', 258, 3034, util.VN_CURDATE(), 6441, 2, 1),
(8, '99610288644', 476, 4461, util.VN_CURDATE(), 5751, 442, 1),
(9, '99610289193', 302, 2972, util.VN_CURDATE(), 3871, 442, 1),
(10, '07546500856', 185, 2364, util.VN_CURDATE(), 5321, 442, 1);
INSERT INTO `vn`.`dua` (id, code, awbFk, issued, operated, booked, bookEntried, gestdocFk, customsValue, companyFk)
VALUES VALUES
(1, '19ES0028013A481523', 1, util.VN_CURDATE(), util.VN_CURDATE(), util.VN_CURDATE(), util.VN_CURDATE(), 1, 11276.95, 442), (1, '19ES0028013A481523', 1, util.VN_CURDATE(), util.VN_CURDATE(), util.VN_CURDATE(), util.VN_CURDATE(), 1, 11276.95, 442),
(2, '21ES00280136115760', 2, util.VN_CURDATE(), util.VN_CURDATE(), util.VN_CURDATE(), util.VN_CURDATE(), 2, 1376.20, 442), (2, '21ES00280136115760', 2, util.VN_CURDATE(), util.VN_CURDATE(), util.VN_CURDATE(), util.VN_CURDATE(), 2, 1376.20, 442),
@ -2524,6 +2525,17 @@ INSERT INTO `vn`.`dua` (id, code, awbFk, issued, operated, booked, bookEntried,
(9, '19ES00280132025491', 9, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), util.VN_CURDATE(), util.VN_CURDATE(), util.VN_CURDATE(), 2, 7126.23, 442), (9, '19ES00280132025491', 9, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), util.VN_CURDATE(), util.VN_CURDATE(), util.VN_CURDATE(), 2, 7126.23, 442),
(10, '19ES00280132025492', 10, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), util.VN_CURDATE(), util.VN_CURDATE(), util.VN_CURDATE(), 2, 4631.45, 442); (10, '19ES00280132025492', 10, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), util.VN_CURDATE(), util.VN_CURDATE(), util.VN_CURDATE(), 2, 4631.45, 442);
INSERT INTO `vn`.`duaEntry` (`duaFk`, `entryFk`, `value`, `customsValue`, `euroValue`)
VALUES
(1, 1, 1.00, 1.00, 1.00),
(2, 2, 1.00, 1.00, 1.00),
(3, 3, 1.00, 1.00, 1.00),
(4, 4, 1.00, 1.00, 1.00),
(5, 5, 1.00, 1.00, 1.00),
(6, 6, 1.00, 1.00, 1.00),
(7, 7, 1.00, 1.00, 1.00),
(8, 8, 1.00, 1.00, 1.00);
REPLACE INTO `vn`.`invoiceIn`(`id`, `serialNumber`,`serial`, `supplierFk`, `issued`, `created`, `supplierRef`, `isBooked`, `companyFk`, `docFk`) REPLACE INTO `vn`.`invoiceIn`(`id`, `serialNumber`,`serial`, `supplierFk`, `issued`, `created`, `supplierRef`, `isBooked`, `companyFk`, `docFk`)
VALUES VALUES
(1, 1001, 'R', 1, util.VN_CURDATE(), util.VN_CURDATE(), 1234, 0, 442, 1), (1, 1001, 'R', 1, util.VN_CURDATE(), util.VN_CURDATE(), 1234, 0, 442, 1),
@ -2910,8 +2922,7 @@ INSERT INTO `vn`.`workerConfig` (`id`, `businessUpdated`, `roleFk`, `payMethodFk
INSERT INTO `vn`.`ticketRefund`(`refundTicketFk`, `originalTicketFk`) INSERT INTO `vn`.`ticketRefund`(`refundTicketFk`, `originalTicketFk`)
VALUES VALUES
(1, 12), (24, 7);
(8, 10);
INSERT INTO `vn`.`deviceProductionModels` (`code`) INSERT INTO `vn`.`deviceProductionModels` (`code`)
VALUES VALUES
@ -3009,3 +3020,37 @@ INSERT INTO `vn`.`invoiceCorrectionType` (`id`, `description`)
(1, 'Error in VAT calculation'), (1, 'Error in VAT calculation'),
(2, 'Error in sales details'), (2, 'Error in sales details'),
(3, 'Error in customer data'); (3, 'Error in customer data');
UPDATE `vn`.`client`
SET fi='65004204V'
WHERE id=1;
UPDATE `vn`.`worker`
SET fi='59328808D'
WHERE id=1106;
INSERT INTO `account`.`mailAliasAcl` (`mailAliasFk`, `roleFk`)
VALUES
(1, 1),
(2, 9),
(3, 15);
INSERT INTO `vn`.`docuwareTablet` (`tablet`,`description`)
VALUES
('Tablet1','Jarvis tablet'),
('Tablet2','Avengers tablet');
INSERT INTO `vn`.`sms` (`id`, `senderFk`, `sender`, `destination`, `message`, `statusCode`, `status`, `created`)
VALUES (1, 66, '111111111', '0001111111111', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', 0, 'OK', util.VN_CURDATE()),
(2, 66, '222222222', '0002222222222', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', 0, 'PENDING', util.VN_CURDATE()),
(3, 66, '333333333', '0003333333333', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', 0, 'ERROR', util.VN_CURDATE()),
(4, 66, '444444444', '0004444444444', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', 0, 'OK', util.VN_CURDATE());
INSERT INTO `vn`.`clientSms` (`id`, `clientFk`, `smsFk`, `ticketFk`)
VALUES(1, 1103, 1, NULL),
(2, 1103, 2, NULL),
(3, 1103, 3, 32),
(4, 1103, 4, 32),
(13, 1101, 1, NULL),
(14, 1101, 4, 27);

View File

@ -27523,7 +27523,7 @@ DROP TABLE IF EXISTS `dua`;
CREATE TABLE `dua` ( CREATE TABLE `dua` (
`id` int(11) NOT NULL AUTO_INCREMENT, `id` int(11) NOT NULL AUTO_INCREMENT,
`code` varchar(45) DEFAULT NULL, `code` varchar(45) DEFAULT NULL,
`awbFk` smallint(11) unsigned NOT NULL, `awbFk__` smallint(11) unsigned NOT NULL,
`issued` date DEFAULT NULL, `issued` date DEFAULT NULL,
`operated` date DEFAULT NULL, `operated` date DEFAULT NULL,
`booked` date DEFAULT NULL, `booked` date DEFAULT NULL,
@ -27534,12 +27534,10 @@ CREATE TABLE `dua` (
`ASIEN` double DEFAULT NULL, `ASIEN` double DEFAULT NULL,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
UNIQUE KEY `code_UNIQUE` (`code`), UNIQUE KEY `code_UNIQUE` (`code`),
KEY `fk_awb_dua_awb_idx` (`awbFk`),
KEY `fk_dua_gestdoc1_idx` (`gestdocFk`), KEY `fk_dua_gestdoc1_idx` (`gestdocFk`),
KEY `dua_fk4_idx` (`companyFk`), KEY `dua_fk4_idx` (`companyFk`),
CONSTRAINT `duaCompany_Fk` FOREIGN KEY (`companyFk`) REFERENCES `company` (`id`) ON UPDATE CASCADE, CONSTRAINT `duaCompany_Fk` FOREIGN KEY (`companyFk`) REFERENCES `company` (`id`) ON UPDATE CASCADE,
CONSTRAINT `dua_fk1` FOREIGN KEY (`gestdocFk`) REFERENCES `dms` (`id`) ON DELETE SET NULL ON UPDATE CASCADE, CONSTRAINT `dua_fk1` FOREIGN KEY (`gestdocFk`) REFERENCES `dms` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
CONSTRAINT `dua_fk2` FOREIGN KEY (`awbFk`) REFERENCES `awb` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDBDEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci; ) ENGINE=InnoDBDEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
@ -41404,6 +41402,7 @@ CREATE TABLE `travel` (
`agencyModeFk` int(11) DEFAULT NULL, `agencyModeFk` int(11) DEFAULT NULL,
`clonedFrom` int(11) DEFAULT NULL, `clonedFrom` int(11) DEFAULT NULL,
`editorFk` int(10) unsigned DEFAULT NULL, `editorFk` int(10) unsigned DEFAULT NULL,
`awbFk` SMALLINT(11) UNSIGNED,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
UNIQUE KEY `shipment_1` (`shipped`,`landed`,`warehouseInFk`,`warehouseOutFk`,`agencyFk`,`agencyModeFk`,`ref`), UNIQUE KEY `shipment_1` (`shipped`,`landed`,`warehouseInFk`,`warehouseOutFk`,`agencyFk`,`agencyModeFk`,`ref`),
KEY `agency_id` (`agencyFk`), KEY `agency_id` (`agencyFk`),
@ -41418,7 +41417,8 @@ CREATE TABLE `travel` (
CONSTRAINT `travel_fk_editor` FOREIGN KEY (`editorFk`) REFERENCES `account`.`user` (`id`), CONSTRAINT `travel_fk_editor` FOREIGN KEY (`editorFk`) REFERENCES `account`.`user` (`id`),
CONSTRAINT `travel_ibfk_1` FOREIGN KEY (`warehouseInFk`) REFERENCES `warehouse` (`id`) ON UPDATE CASCADE, CONSTRAINT `travel_ibfk_1` FOREIGN KEY (`warehouseInFk`) REFERENCES `warehouse` (`id`) ON UPDATE CASCADE,
CONSTRAINT `travel_ibfk_2` FOREIGN KEY (`warehouseOutFk`) REFERENCES `warehouse` (`id`) ON UPDATE CASCADE, CONSTRAINT `travel_ibfk_2` FOREIGN KEY (`warehouseOutFk`) REFERENCES `warehouse` (`id`) ON UPDATE CASCADE,
CONSTRAINT `travel_ibfk_3` FOREIGN KEY (`agencyFk`) REFERENCES `agencyMode` (`id`) ON UPDATE CASCADE CONSTRAINT `travel_ibfk_3` FOREIGN KEY (`agencyFk`) REFERENCES `agencyMode` (`id`) ON UPDATE CASCADE,
CONSTRAINT `travel_FK_1` FOREIGN KEY (`awbFk`) REFERENCES `awb` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDBDEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci ROW_FORMAT=DYNAMIC; ) ENGINE=InnoDBDEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci ROW_FORMAT=DYNAMIC;
/*!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 */ ;
@ -81330,7 +81330,34 @@ USE `vn`;
/*!50001 SET collation_connection = utf8mb3_general_ci */; /*!50001 SET collation_connection = utf8mb3_general_ci */;
/*!50001 CREATE ALGORITHM=UNDEFINED */ /*!50001 CREATE ALGORITHM=UNDEFINED */
/*!50013 DEFINER=`root`@`localhost` SQL SECURITY DEFINER */ /*!50013 DEFINER=`root`@`localhost` SQL SECURITY DEFINER */
/*!50001 VIEW `awbVolume` AS select `d`.`awbFk` AS `awbFk`,`b`.`stickers` * `i`.`density` * if(`p`.`volume` > 0,`p`.`volume`,`p`.`width` * `p`.`depth` * if(`p`.`height` = 0,`i`.`size` + 10,`p`.`height`)) / (`vc`.`aerealVolumetricDensity` * 1000) AS `volume`,`b`.`id` AS `buyFk` from ((((((((`buy` `b` join `item` `i` on(`b`.`itemFk` = `i`.`id`)) join `itemType` `it` on(`i`.`typeFk` = `it`.`id`)) join `packaging` `p` on(`p`.`id` = `b`.`packagingFk`)) join `entry` `e` on(`b`.`entryFk` = `e`.`id`)) join `travel` `t` on(`t`.`id` = `e`.`travelFk`)) join `duaEntry` `de` on(`de`.`entryFk` = `e`.`id`)) join `dua` `d` on(`d`.`id` = `de`.`duaFk`)) join `volumeConfig` `vc`) where `t`.`shipped` > makedate(year(`util`.`VN_CURDATE`()) - 1,1) */; /*!50001 VIEW `awbVolume` AS SELECT `t`.`awbFk` AS `awbFk`,
`b`.`stickers` * `i`.`density` * IF(
`p`.`volume` > 0,
`p`.`volume`,
`p`.`width` * `p`.`depth` * IF(`p`.`height` = 0, `i`.`size` + 10, `p`.`height`)
) / (`vc`.`aerealVolumetricDensity` * 1000) AS `volume`,
`b`.`id` AS `buyFk`
FROM (
(
(
(
(
(
`vn`.`buy` `b`
JOIN `vn`.`item` `i` ON(`b`.`itemFk` = `i`.`id`)
)
JOIN `vn`.`itemType` `it` ON(`i`.`typeFk` = `it`.`id`)
)
JOIN `vn`.`packaging` `p` ON(`p`.`id` = `b`.`packagingFk`)
)
JOIN `vn`.`entry` `e` ON(`b`.`entryFk` = `e`.`id`)
)
JOIN `vn`.`travel` `t` ON(`t`.`id` = `e`.`travelFk`)
)
JOIN `vn`.`volumeConfig` `vc`
)
WHERE `t`.`shipped` > makedate(year(`util`.`VN_CURDATE`()) - 1, 1)
AND t.awbFk*/;
/*!50001 SET character_set_client = @saved_cs_client */; /*!50001 SET character_set_client = @saved_cs_client */;
/*!50001 SET character_set_results = @saved_cs_results */; /*!50001 SET character_set_results = @saved_cs_results */;
/*!50001 SET collation_connection = @saved_col_connection */; /*!50001 SET collation_connection = @saved_col_connection */;

6
db/remotes/dev.ini Normal file
View File

@ -0,0 +1,6 @@
[client]
host = dev-db.verdnatura.es
port = 3307
user = jgallego
password = 9b7620x.
default-character-set=utf8

View File

@ -0,0 +1,6 @@
[client]
host = db.verdnatura.es
port = 3308
user = jgallego
password = 9b7620x.
default-character-set=utf8

View File

@ -1,123 +0,0 @@
const app = require('vn-loopback/server/server');
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
// 2277 solucionar problema al testear procedimiento con start transaction / rollback
xdescribe('ticket_componentMakeUpdate()', () => {
it('should recalculate the ticket components without make modifications', async() => {
let stmts = [];
let stmt;
let params = {
ticketId: 11,
clientId: 1102,
agencyModeId: 2,
addressId: 122,
zoneId: 3,
warehouseId: 1,
companyId: 442,
isDeleted: 0,
hasToBeUnrouted: 0,
componentOption: 1
};
stmts.push('START TRANSACTION');
stmt = new ParameterizedSQL('SELECT * FROM vn.ticket WHERE id = ?', [
params.ticketId
]);
stmts.push(stmt);
let originalTicketIndex = stmts.push(stmt) - 1;
stmt = new ParameterizedSQL('CALL vn.ticket_componentMakeUpdate(?, ?, ?, ?, ?, ?, ?, DATE_ADD(CURDATE(), INTERVAL +1 DAY), DATE_ADD(CURDATE(), INTERVAL +1 DAY), ?, ?, ?)', [
params.ticketId,
params.clientId,
params.agencyModeId,
params.addressId,
params.zoneId,
params.warehouseId,
params.companyId,
params.isDeleted,
params.hasToBeUnrouted,
params.componentOption
]);
stmts.push(stmt);
stmt = new ParameterizedSQL('SELECT * FROM vn.ticket WHERE id = ?', [
params.ticketId
]);
stmts.push(stmt);
let updatedTicketIndex = stmts.push(stmt) - 1;
stmts.push('ROLLBACK');
let sql = ParameterizedSQL.join(stmts, ';');
let result = await app.models.Ticket.rawStmt(sql);
let originalTicketData = result[originalTicketIndex];
let updatedTicketData = result[updatedTicketIndex];
expect(originalTicketData[0].isDeleted).toEqual(updatedTicketData[0].isDeleted);
expect(originalTicketData[0].routeFk).toEqual(updatedTicketData[0].routeFk);
});
it('should delete and unroute a ticket and recalculate the components', async() => {
let stmts = [];
let stmt;
let params = {
ticketId: 11,
clientId: 1102,
agencyModeId: 2,
addressId: 122,
zoneId: 3,
warehouseId: 1,
companyId: 442,
isDeleted: 1,
hasToBeUnrouted: 1,
componentOption: 1
};
stmts.push('START TRANSACTION');
stmt = new ParameterizedSQL('SELECT * FROM vn.ticket WHERE id = ?', [
params.ticketId
]);
stmts.push(stmt);
let originalTicketIndex = stmts.push(stmt) - 1;
stmt = new ParameterizedSQL('CALL vn.ticket_componentMakeUpdate(?, ?, ?, ?, ?, ?, ?, DATE_ADD(CURDATE(), INTERVAL +1 DAY), DATE_ADD(CURDATE(), INTERVAL +1 DAY), ?, ?, ?)', [
params.ticketId,
params.clientId,
params.agencyModeId,
params.addressId,
params.zoneId,
params.warehouseId,
params.companyId,
params.isDeleted,
params.hasToBeUnrouted,
params.componentOption
]);
stmts.push(stmt);
stmt = new ParameterizedSQL('SELECT * FROM vn.ticket WHERE id = ?', [
params.ticketId
]);
stmts.push(stmt);
let updatedTicketIndex = stmts.push(stmt) - 1;
stmts.push('ROLLBACK');
let sql = ParameterizedSQL.join(stmts, ';');
let result = await app.models.Ticket.rawStmt(sql);
let originalTicketData = result[originalTicketIndex];
let updatedTicketData = result[updatedTicketIndex];
expect(originalTicketData[0].isDeleted).not.toEqual(updatedTicketData[0].isDeleted);
expect(originalTicketData[0].routeFk).not.toEqual(updatedTicketData[0].routeFk);
});
});

View File

@ -22,6 +22,7 @@ services:
- 3000 - 3000
environment: environment:
- NODE_ENV - NODE_ENV
- DEBUG
configs: configs:
- source: datasources - source: datasources
target: /etc/salix/datasources.json target: /etc/salix/datasources.json

View File

@ -735,7 +735,7 @@ export default {
}, },
createStateView: { createStateView: {
state: 'vn-autocomplete[ng-model="$ctrl.stateFk"]', state: 'vn-autocomplete[ng-model="$ctrl.stateFk"]',
worker: 'vn-worker-autocomplete[ng-model="$ctrl.workerFk"]', worker: 'vn-worker-autocomplete[ng-model="$ctrl.userFk"]',
saveStateButton: `button[type=submit]` saveStateButton: `button[type=submit]`
}, },
claimsIndex: { claimsIndex: {

View File

@ -56,63 +56,6 @@ describe('Worker time control path', () => {
expect(result).toContain(month); expect(result).toContain(month);
}); });
it(`should return error when insert 'out' of first entry`, async() => {
pending('https://redmine.verdnatura.es/issues/4707');
await page.waitToClick(selectors.workerTimeControl.mondayAddTimeButton);
await page.pickTime(selectors.workerTimeControl.dialogTimeInput, eightAm);
await page.autocompleteSearch(selectors.workerTimeControl.dialogTimeDirection, 'out');
await page.respondToDialog('accept');
const message = await page.waitForSnackbar();
expect(message.text).toBeDefined();
});
it(`should insert 'in' monday`, async() => {
pending('https://redmine.verdnatura.es/issues/4707');
await page.waitToClick(selectors.workerTimeControl.mondayAddTimeButton);
await page.pickTime(selectors.workerTimeControl.dialogTimeInput, eightAm);
await page.autocompleteSearch(selectors.workerTimeControl.dialogTimeDirection, 'in');
await page.respondToDialog('accept');
const result = await page.waitToGetProperty(selectors.workerTimeControl.firstEntryOfMonday, 'innerText');
expect(result).toEqual(eightAm);
});
it(`should insert 'out' monday`, async() => {
pending('https://redmine.verdnatura.es/issues/4707');
await page.waitToClick(selectors.workerTimeControl.mondayAddTimeButton);
await page.pickTime(selectors.workerTimeControl.dialogTimeInput, fourPm);
await page.autocompleteSearch(selectors.workerTimeControl.dialogTimeDirection, 'out');
await page.respondToDialog('accept');
const result = await page.waitToGetProperty(selectors.workerTimeControl.secondEntryOfMonday, 'innerText');
expect(result).toEqual(fourPm);
});
it(`should check Hank Pym worked 8:20 hours`, async() => {
pending('https://redmine.verdnatura.es/issues/4707');
await page.waitForTextInElement(selectors.workerTimeControl.mondayWorkedHours, '08:20 h.');
await page.waitForTextInElement(selectors.workerTimeControl.weekWorkedHours, '08:20 h.');
});
it('should remove first entry of monday', async() => {
pending('https://redmine.verdnatura.es/issues/4707');
await page.waitForTextInElement(selectors.workerTimeControl.firstEntryOfMonday, eightAm);
await page.waitForTextInElement(selectors.workerTimeControl.secondEntryOfMonday, fourPm);
await page.waitToClick(selectors.workerTimeControl.firstEntryOfMondayDelete);
await page.respondToDialog('accept');
const message = await page.waitForSnackbar();
expect(message.text).toContain('Entry removed');
});
it(`should be the 'out' the first entry of monday`, async() => {
pending('https://redmine.verdnatura.es/issues/4707');
const result = await page.waitToGetProperty(selectors.workerTimeControl.firstEntryOfMonday, 'innerText');
expect(result).toEqual(fourPm);
});
it('should change week of month', async() => { it('should change week of month', async() => {
await page.click(selectors.workerTimeControl.thrirdWeekDay); await page.click(selectors.workerTimeControl.thrirdWeekDay);
const result = await page.getProperty(selectors.workerTimeControl.mondayWorkedHours, 'innerText'); const result = await page.getProperty(selectors.workerTimeControl.mondayWorkedHours, 'innerText');

View File

@ -27,11 +27,8 @@ describe('Item Edit basic data path', () => {
it(`should edit the item basic data and confirm the item data was edited`, async() => { it(`should edit the item basic data and confirm the item data was edited`, async() => {
const values = { const values = {
name: 'Rose of Purity',
longName: 'RS Rose of Purity',
type: 'Anthurium', type: 'Anthurium',
intrastat: 'Coral y materiales similares', intrastat: 'Coral y materiales similares',
origin: 'Spain',
relevancy: 1, relevancy: 1,
generic: 'Pallet', generic: 'Pallet',
isActive: false, isActive: false,

View File

@ -188,17 +188,6 @@ describe('Ticket Edit sale path', () => {
expect(result).toContain('22.50'); expect(result).toContain('22.50');
}); });
it('should check in the history that logs has been added', async() => {
pending('https://redmine.verdnatura.es/issues/5455');
await page.reload({waitUntil: ['networkidle0', 'domcontentloaded']});
await page.waitToClick(selectors.ticketSales.firstSaleHistoryButton);
await page.waitForSelector(selectors.ticketSales.firstSaleHistory);
const result = await page.countElement(selectors.ticketSales.firstSaleHistory);
expect(result).toBeGreaterThan(0);
await page.waitToClick(selectors.ticketSales.closeHistory);
});
it('should recalculate price of sales', async() => { it('should recalculate price of sales', async() => {
await page.waitToClick(selectors.ticketSales.firstSaleCheckbox); await page.waitToClick(selectors.ticketSales.firstSaleCheckbox);
await page.waitToClick(selectors.ticketSales.secondSaleCheckbox); await page.waitToClick(selectors.ticketSales.secondSaleCheckbox);
@ -236,7 +225,7 @@ describe('Ticket Edit sale path', () => {
}); });
it('should show error trying to delete a ticket with a refund', async() => { it('should show error trying to delete a ticket with a refund', async() => {
await page.accessToSearchResult('16'); await page.accessToSearchResult('7');
await page.waitToClick(selectors.ticketDescriptor.moreMenu); await page.waitToClick(selectors.ticketDescriptor.moreMenu);
await page.waitToClick(selectors.ticketDescriptor.moreMenuDeleteTicket); await page.waitToClick(selectors.ticketDescriptor.moreMenuDeleteTicket);
await page.waitToClick(selectors.globalItems.acceptButton); await page.waitToClick(selectors.globalItems.acceptButton);

View File

@ -1,31 +0,0 @@
import selectors from '../../helpers/selectors.js';
import getBrowser from '../../helpers/puppeteer';
// #2221 Local MySQL8 crashes when rest method Items/getBalance is called
xdescribe('Ticket diary path', () => {
let page;
beforeAll(async() => {
page = (await getBrowser()).page;
await page.loginAndModule('employee', 'ticket');
});
afterAll(async() => {
await page.browser().close();
});
it(`should navigate to item diary from ticket sale and check the lines`, async() => {
await page.accessToSearchResult('1');
await page.waitToClick(selectors.ticketSummary.firstSaleItemId);
await page.waitToClick(selectors.ticketSummary.popoverDiaryButton);
await page.waitForState('item.card.diary');
const secondIdClass = await page.getClassName(selectors.itemDiary.secondTicketId);
const fourthBalanceClass = await page.getClassName(selectors.itemDiary.fourthBalance);
const firstBalanceClass = await page.getClassName(selectors.itemDiary.firstBalance);
expect(secondIdClass).toContain('message');
expect(fourthBalanceClass).toContain('message');
expect(firstBalanceClass).toContain('balance');
});
});

View File

@ -35,7 +35,7 @@ describe('Ticket index payout path', () => {
await page.waitToClick(selectors.ticketsIndex.openAdvancedSearchButton); await page.waitToClick(selectors.ticketsIndex.openAdvancedSearchButton);
await page.write(selectors.ticketsIndex.advancedSearchClient, '1101'); await page.write(selectors.ticketsIndex.advancedSearchClient, '1101');
await page.keyboard.press('Enter'); await page.keyboard.press('Enter');
await page.waitForNumberOfElements(selectors.ticketsIndex.anySearchResult, 9); await page.waitForNumberOfElements(selectors.ticketsIndex.anySearchResult, 10);
await page.waitToClick(selectors.ticketsIndex.firstTicketCheckbox); await page.waitToClick(selectors.ticketsIndex.firstTicketCheckbox);
await page.waitToClick(selectors.ticketsIndex.secondTicketCheckbox); await page.waitToClick(selectors.ticketsIndex.secondTicketCheckbox);

View File

@ -1,114 +0,0 @@
import selectors from '../../helpers/selectors.js';
import getBrowser from '../../helpers/puppeteer.js';
// #1528 e2e claim/detail
xdescribe('Claim detail', () => {
let browser;
let page;
beforeAll(async() => {
browser = await getBrowser();
page = browser.page;
await page.loginAndModule('salesPerson', 'claim');
await page.accessToSearchResult('1');
await page.accessToSection('claim.card.detail');
});
afterAll(async() => {
await browser.close();
});
it('should add the first claimable item from ticket to the claim', async() => {
await page.waitToClick(selectors.claimDetail.addItemButton);
await page.waitToClick(selectors.claimDetail.firstClaimableSaleFromTicket);
const message = await page.waitForSnackbar();
expect(message.text).toContain('Data saved!');
});
it('should confirm the claim contains now two items', async() => {
const result = await page.countElement(selectors.claimDetail.claimDetailLine);
expect(result).toEqual(2);
});
it('should edit de first item claimed quantity', async() => {
await page.clearInput(selectors.claimDetail.firstItemQuantityInput); // selector deleted, find new upon fixes
await page.write(selectors.claimDetail.firstItemQuantityInput, '4'); // selector deleted, find new upon fixes
await page.keyboard.press('Enter');
const message = await page.waitForSnackbar();
expect(message.text).toContain('Data saved!');
});
it('should confirm the first item quantity, and the claimed total were correctly edited', async() => {
const claimedQuantity = page
.waitToGetProperty(selectors.claimDetail.firstItemQuantityInput, 'value'); // selector deleted, find new upon fixes
const totalClaimed = page
.waitToGetProperty(selectors.claimDetail.totalClaimed, 'innerText');
expect(claimedQuantity).toEqual('4');
expect(totalClaimed).toContain('€47.62');
});
it('should login as salesAssistant and navigate to the claim.detail section', async() => {
await page.loginAndModule('salesAssistant', 'claim');
await page.accessToSearchResult('1');
await page.accessToSection('claim.card.detail');
let url = await page.expectURL('/detail'); // replace with waitForState
expect(url).toBe(true);
});
it('should edit de second item claimed discount', async() => {
await page.waitToClick(selectors.claimDetail.secondItemDiscount);
await page.write(selectors.claimDetail.discount, '100');
await page.keyboard.press('Enter');
const message = await page.waitForSnackbar();
expect(message.text).toContain('Data saved!');
});
it('should check the mana is the expected one', async() => {
await page.waitToClick(selectors.claimDetail.secondItemDiscount);
const result = await page.waitToGetProperty(selectors.claimDetail.discoutPopoverMana, 'innerText');
expect(result).toContain('MANÁ: €106');
});
it('should delete the second item from the claim', async() => {
await page.waitToClick(selectors.claimDetail.secondItemDeleteButton);
const message = await page.waitForSnackbar();
expect(message.text).toContain('Data saved!');
});
it('should confirm the claim contains now one item', async() => {
const result = await page.countElement(selectors.claimDetail.claimDetailLine);
expect(result).toEqual(1);
});
it('should add the deleted ticket from to the claim', async() => {
await page.waitToClick(selectors.claimDetail.addItemButton);
await page.waitToClick(selectors.claimDetail.firstClaimableSaleFromTicket);
const message = await page.waitForSnackbar();
expect(message.text).toContain('Data saved!');
});
it(`should have been redirected to the next section in claims`, async() => {
let url = await page.expectURL('development'); // replace with waitForState
expect(url).toBe(true);
});
it('should navigate back to claim.detail to confirm the claim contains now two items', async() => {
await page.accessToSection('claim.card.detail');
await page.waitForSelector(selectors.claimDetail.claimDetailLine);
const result = await page.countElement(selectors.claimDetail.claimDetailLine);
expect(result).toEqual(2);
});
});

View File

@ -28,7 +28,6 @@ describe('InvoiceOut summary path', () => {
it('should contain the tax breakdown', async() => { it('should contain the tax breakdown', async() => {
const firstTax = await page.waitToGetProperty(selectors.invoiceOutSummary.taxOne, 'innerText'); const firstTax = await page.waitToGetProperty(selectors.invoiceOutSummary.taxOne, 'innerText');
const secondTax = await page.waitToGetProperty(selectors.invoiceOutSummary.taxTwo, 'innerText'); const secondTax = await page.waitToGetProperty(selectors.invoiceOutSummary.taxTwo, 'innerText');
expect(firstTax).toContain('10%'); expect(firstTax).toContain('10%');
@ -37,10 +36,9 @@ describe('InvoiceOut summary path', () => {
it('should contain the tickets info', async() => { it('should contain the tickets info', async() => {
const firstTicket = await page.waitToGetProperty(selectors.invoiceOutSummary.ticketOne, 'innerText'); const firstTicket = await page.waitToGetProperty(selectors.invoiceOutSummary.ticketOne, 'innerText');
const secondTicket = await page.waitToGetProperty(selectors.invoiceOutSummary.ticketTwo, 'innerText'); const secondTicket = await page.waitToGetProperty(selectors.invoiceOutSummary.ticketTwo, 'innerText');
expect(firstTicket).toContain('Bat cave'); expect(firstTicket).toContain('Bat cave');
expect(secondTicket).toContain('Stark tower'); expect(secondTicket).toContain('Bat cave');
}); });
}); });

View File

@ -105,17 +105,4 @@ describe('Travel basic data path', () => {
it(`should check the received checkbox was saved even tho it doesn't make sense`, async() => { it(`should check the received checkbox was saved even tho it doesn't make sense`, async() => {
await page.waitForClassPresent(selectors.travelBasicData.received, 'checked'); await page.waitForClassPresent(selectors.travelBasicData.received, 'checked');
}); });
it('should navigate to the travel logs', async() => {
pending('https://redmine.verdnatura.es/issues/5455');
await page.accessToSection('travel.card.log');
await page.waitForState('travel.card.log');
});
it('should check the 1st log contains details from the changes made', async() => {
pending('https://redmine.verdnatura.es/issues/5455');
const result = await page.waitToGetProperty(selectors.travelLog.firstLogFirstTD, 'innerText');
expect(result).toContain('new reference!');
});
}); });

View File

@ -33,18 +33,6 @@ describe('Component vnTreeview', () => {
$element.remove(); $element.remove();
}); });
// See how to test DOM element in Jest
xdescribe('undrop()', () => {
it(`should reset all drop events and properties`, () => {
controller.dropping = angular.element(`<vn-treeview-child class="dropping"></vn-treeview-child>`);
jest.spyOn(controller.dropping.classList, 'remove');
controller.undrop();
expect(controller.dropping).toBeNull();
});
});
describe('dragOver()', () => { describe('dragOver()', () => {
it(`should set the dragClientY property`, () => { it(`should set the dragClientY property`, () => {
const event = new Event('dragover'); const event = new Event('dragover');

View File

@ -23,7 +23,6 @@ export function directive($translate, $window) {
let rule = $attrs.rule.split('.'); let rule = $attrs.rule.split('.');
let modelName = rule.shift(); let modelName = rule.shift();
let fieldName = rule.shift(); let fieldName = rule.shift();
let split = $attrs.ngModel.split('.'); let split = $attrs.ngModel.split('.');
if (!fieldName) fieldName = split.pop() || null; if (!fieldName) fieldName = split.pop() || null;
if (!modelName) modelName = firstUpper(split.pop() || ''); if (!modelName) modelName = firstUpper(split.pop() || '');

View File

@ -68,3 +68,4 @@ Load more results: Cargar más resultados
Send cau: Enviar cau Send cau: Enviar cau
By sending this ticket, all the data related to the error, the section, the user, etc., are already sent.: Al enviar este cau ya se envían todos los datos relacionados con el error, la sección, el usuario, etc By sending this ticket, all the data related to the error, the section, the user, etc., are already sent.: Al enviar este cau ya se envían todos los datos relacionados con el error, la sección, el usuario, etc
ExplainReason: Explique el motivo por el que no deberia aparecer este fallo ExplainReason: Explique el motivo por el que no deberia aparecer este fallo
You already have the mailAlias: Ya tienes este alias de correo

View File

@ -234,13 +234,13 @@ async function dockerStart() {
const container = new Docker('salix-db'); const container = new Docker('salix-db');
await container.start(); await container.start();
} }
dockerStart.description = `Starts the salix-db container`; dockerStart.description = `Starts the DB container`;
async function docker() { async function docker() {
const container = new Docker('salix-db'); const container = new Docker('salix-db');
await container.run(); await container.run();
} }
docker.description = `Runs the salix-db container`; docker.description = `Builds and starts the DB container`;
module.exports = { module.exports = {
default: defaultTask, default: defaultTask,

View File

@ -0,0 +1,12 @@
const LoopBackContext = require('loopback-context');
async function handleObserve(ctx) {
ctx.options.httpCtx = LoopBackContext.getCurrentContext();
}
module.exports = function(Self) {
let Mixin = {
'before save': handleObserve,
'before delete': handleObserve,
};
for (const [listener, handler] of Object.entries(Mixin))
Self.observe(listener, handler);
};

View File

@ -1,15 +0,0 @@
const LoopBackContext = require('loopback-context');
module.exports = function(Self) {
Self.setup = function() {
Self.super_.setup.call(this);
};
Self.observe('before save', async function(ctx) {
ctx.options.httpCtx = LoopBackContext.getCurrentContext();
});
Self.observe('before delete', async function(ctx) {
ctx.options.httpCtx = LoopBackContext.getCurrentContext();
});
};

View File

@ -1,5 +0,0 @@
{
"name": "Loggable",
"base": "VnModel",
"validateUpsert": true
}

View File

@ -45,6 +45,7 @@
"Extension format is invalid": "Extension format is invalid", "Extension format is invalid": "Extension format is invalid",
"NO_ZONE_FOR_THIS_PARAMETERS": "NO_ZONE_FOR_THIS_PARAMETERS", "NO_ZONE_FOR_THIS_PARAMETERS": "NO_ZONE_FOR_THIS_PARAMETERS",
"This client can't be invoiced": "This client can't be invoiced", "This client can't be invoiced": "This client can't be invoiced",
"You must provide the correction information to generate a corrective invoice": "You must provide the correction information to generate a corrective invoice",
"The introduced hour already exists": "The introduced hour already exists", "The introduced hour already exists": "The introduced hour already exists",
"Invalid parameters to create a new ticket": "Invalid parameters to create a new ticket", "Invalid parameters to create a new ticket": "Invalid parameters to create a new ticket",
"Concept cannot be blank": "Concept cannot be blank", "Concept cannot be blank": "Concept cannot be blank",
@ -68,8 +69,7 @@
"Sent units from ticket": "I sent *{{quantity}}* units of [{{concept}} ({{itemId}})]({{{itemUrl}}}) to *\"{{nickname}}\"* coming from ticket id [{{ticketId}}]({{{ticketUrl}}})", "Sent units from ticket": "I sent *{{quantity}}* units of [{{concept}} ({{itemId}})]({{{itemUrl}}}) to *\"{{nickname}}\"* coming from ticket id [{{ticketId}}]({{{ticketUrl}}})",
"Change quantity": "{{concept}} change of {{oldQuantity}} to {{newQuantity}}", "Change quantity": "{{concept}} change of {{oldQuantity}} to {{newQuantity}}",
"Claim will be picked": "The product from the claim [({{claimId}})]({{{claimUrl}}}) from the client *{{clientName}}* will be picked", "Claim will be picked": "The product from the claim [({{claimId}})]({{{claimUrl}}}) from the client *{{clientName}}* will be picked",
"Claim state has changed to incomplete": "The state of the claim [({{claimId}})]({{{claimUrl}}}) from client *{{clientName}}* has changed to *incomplete*", "Claim state has changed to": "The state of the claim [({{claimId}})]({{{claimUrl}}}) from client *{{clientName}}* has changed to *{{newState}}*",
"Claim state has changed to canceled": "The state of the claim [({{claimId}})]({{{claimUrl}}}) from client *{{clientName}}* has changed to *canceled*",
"Customs agent is required for a non UEE member": "Customs agent is required for a non UEE member", "Customs agent is required for a non UEE member": "Customs agent is required for a non UEE member",
"Incoterms is required for a non UEE member": "Incoterms is required for a non UEE member", "Incoterms is required for a non UEE member": "Incoterms is required for a non UEE member",
"Client checked as validated despite of duplication": "Client checked as validated despite of duplication from client id {{clientId}}", "Client checked as validated despite of duplication": "Client checked as validated despite of duplication from client id {{clientId}}",
@ -178,7 +178,8 @@
"The renew period has not been exceeded": "The renew period has not been exceeded", "The renew period has not been exceeded": "The renew period has not been exceeded",
"You can not use the same password": "You can not use the same password", "You can not use the same password": "You can not use the same password",
"Valid priorities": "Valid priorities: %d", "Valid priorities": "Valid priorities: %d",
"Negative basis of tickets": "Negative basis of tickets: {{ticketsIds}}", "hasAnyNegativeBase": "Negative basis of tickets: {{ticketsIds}}",
"hasAnyPositiveBase": "Positive basis of tickets: {{ticketsIds}}",
"This ticket cannot be left empty.": "This ticket cannot be left empty. %s", "This ticket cannot be left empty.": "This ticket cannot be left empty. %s",
"Social name should be uppercase": "Social name should be uppercase", "Social name should be uppercase": "Social name should be uppercase",
"Street should be uppercase": "Street should be uppercase", "Street should be uppercase": "Street should be uppercase",
@ -200,5 +201,9 @@
"Try again": "Try again", "Try again": "Try again",
"keepPrice": "keepPrice", "keepPrice": "keepPrice",
"Cannot past travels with entries": "Cannot past travels with entries", "Cannot past travels with entries": "Cannot past travels with entries",
"It was not able to remove the next expeditions:": "It was not able to remove the next expeditions: {{expeditions}}" "It was not able to remove the next expeditions:": "It was not able to remove the next expeditions: {{expeditions}}",
"Incorrect pin": "Incorrect pin.",
"The notification subscription of this worker cant be modified": "The notification subscription of this worker cant be modified",
"You are not allowed to modify the alias": "You are not allowed to modify the alias",
"You already have the mailAlias": "You already have the mailAlias"
} }

View File

@ -72,6 +72,7 @@
"The secret can't be blank": "La contraseña no puede estar en blanco", "The secret can't be blank": "La contraseña no puede estar en blanco",
"We weren't able to send this SMS": "No hemos podido enviar el SMS", "We weren't able to send this SMS": "No hemos podido enviar el SMS",
"This client can't be invoiced": "Este cliente no puede ser facturado", "This client can't be invoiced": "Este cliente no puede ser facturado",
"You must provide the correction information to generate a corrective invoice": "Debes informar la información de corrección para generar una factura rectificativa",
"This ticket can't be invoiced": "Este ticket no puede ser facturado", "This ticket can't be invoiced": "Este ticket no puede ser facturado",
"You cannot add or modify services to an invoiced ticket": "No puedes añadir o modificar servicios a un ticket facturado", "You cannot add or modify services to an invoiced ticket": "No puedes añadir o modificar servicios a un ticket facturado",
"This ticket can not be modified": "Este ticket no puede ser modificado", "This ticket can not be modified": "Este ticket no puede ser modificado",
@ -135,11 +136,10 @@
"Sent units from ticket": "Envio *{{quantity}}* unidades de [{{concept}} ({{itemId}})]({{{itemUrl}}}) a *\"{{nickname}}\"* provenientes del ticket id [{{ticketId}}]({{{ticketUrl}}})", "Sent units from ticket": "Envio *{{quantity}}* unidades de [{{concept}} ({{itemId}})]({{{itemUrl}}}) a *\"{{nickname}}\"* provenientes del ticket id [{{ticketId}}]({{{ticketUrl}}})",
"Change quantity": "{{concept}} cambia de {{oldQuantity}} a {{newQuantity}}", "Change quantity": "{{concept}} cambia de {{oldQuantity}} a {{newQuantity}}",
"Claim will be picked": "Se recogerá el género de la reclamación [({{claimId}})]({{{claimUrl}}}) del cliente *{{clientName}}*", "Claim will be picked": "Se recogerá el género de la reclamación [({{claimId}})]({{{claimUrl}}}) del cliente *{{clientName}}*",
"Claim state has changed to incomplete": "Se ha cambiado el estado de la reclamación [({{claimId}})]({{{claimUrl}}}) del cliente *{{clientName}}* a *incompleta*", "Claim state has changed to": "Se ha cambiado el estado de la reclamación [({{claimId}})]({{{claimUrl}}}) del cliente *{{clientName}}* a *{{newState}}*",
"Claim state has changed to canceled": "Se ha cambiado el estado de la reclamación [({{claimId}})]({{{claimUrl}}}) del cliente *{{clientName}}* a *anulado*",
"Client checked as validated despite of duplication": "Cliente comprobado a pesar de que existe el cliente id {{clientId}}", "Client checked as validated despite of duplication": "Cliente comprobado a pesar de que existe el cliente id {{clientId}}",
"ORDER_ROW_UNAVAILABLE": "No hay disponibilidad de este producto", "ORDER_ROW_UNAVAILABLE": "No hay disponibilidad de este producto",
"Distance must be lesser than 1000": "La distancia debe ser inferior a 1000", "Distance must be lesser than 4000": "La distancia debe ser inferior a 4000",
"This ticket is deleted": "Este ticket está eliminado", "This ticket is deleted": "Este ticket está eliminado",
"Unable to clone this travel": "No ha sido posible clonar este travel", "Unable to clone this travel": "No ha sido posible clonar este travel",
"This thermograph id already exists": "La id del termógrafo ya existe", "This thermograph id already exists": "La id del termógrafo ya existe",
@ -305,7 +305,8 @@
"Mail not sent": "Se ha producido un fallo al enviar la factura al cliente [{{clientId}}]({{{clientUrl}}}), por favor revisa la dirección de correo electrónico", "Mail not sent": "Se ha producido un fallo al enviar la factura al cliente [{{clientId}}]({{{clientUrl}}}), por favor revisa la dirección de correo electrónico",
"The renew period has not been exceeded": "El periodo de renovación no ha sido superado", "The renew period has not been exceeded": "El periodo de renovación no ha sido superado",
"Valid priorities": "Prioridades válidas: %d", "Valid priorities": "Prioridades válidas: %d",
"Negative basis of tickets": "Base negativa para los tickets: {{ticketsIds}}", "hasAnyNegativeBase": "Base negativa para los tickets: {{ticketsIds}}",
"hasAnyPositiveBase": "Base positivas para los tickets: {{ticketsIds}}",
"You cannot assign an alias that you are not assigned to": "No puede asignar un alias que no tenga asignado", "You cannot assign an alias that you are not assigned to": "No puede asignar un alias que no tenga asignado",
"This ticket cannot be left empty.": "Este ticket no se puede dejar vacío. %s", "This ticket cannot be left empty.": "Este ticket no se puede dejar vacío. %s",
"The company has not informed the supplier account for bank transfers": "La empresa no tiene informado la cuenta de proveedor para transferencias bancarias", "The company has not informed the supplier account for bank transfers": "La empresa no tiene informado la cuenta de proveedor para transferencias bancarias",
@ -330,12 +331,10 @@
"quantityLessThanMin": "La cantidad no puede ser menor que la cantidad mínima", "quantityLessThanMin": "La cantidad no puede ser menor que la cantidad mínima",
"Cannot past travels with entries": "No se pueden pasar envíos con entradas", "Cannot past travels with entries": "No se pueden pasar envíos con entradas",
"It was not able to remove the next expeditions:": "No se pudo eliminar las siguientes expediciones: {{expeditions}}", "It was not able to remove the next expeditions:": "No se pudo eliminar las siguientes expediciones: {{expeditions}}",
"Esa expedición no es mrw": "Esa expedición no es mrw", "This claim has been updated": "La reclamación con Id: {{claimId}}, ha sido actualizada",
"This expedition is not configured as MRW": "This expedition is not configured as MRW", "This user does not have an assigned tablet": "Este usuario no tiene tablet asignada",
"Some config parameters are not set": "Some config parameters are not set", "Incorrect pin": "Pin incorrecto.",
"The MRW web service is not returning the expected response": "The MRW web service is not returning the expected response", "You already have the mailAlias": "Ya tienes este alias de correo",
"1) No se han encontrado datos con estos criterios.": "1) No se han encontrado datos con estos criterios.", "You are not allowed to modify the alias": "No estás autorizado a modificar el alias",
"1) Fecha de recogida incorrecta (fecha cerrada).": "1) Fecha de recogida incorrecta (fecha cerrada).", "No tickets to invoice": "No hay tickets para facturar"
"1) Falta indicar la Hora Máxima de Recogida en Sábado2) Fecha de recogida incorrecta (fecha cerrada).": "1) Falta indicar la Hora Máxima de Recogida en Sábado2) Fecha de recogida incorrecta (fecha cerrada).", }
"1) Falta indicar la Hora Máxima de Recogida en Sábado2) La fecha de recogida solicitada es 10/02/2024.3) El tipo de servicio no está permitido.4) ": "1) Falta indicar la Hora Máxima de Recogida en Sábado2) La fecha de recogida solicitada es 10/02/2024.3) El tipo de servicio no está permitido.4) "
}

View File

@ -270,8 +270,8 @@ class VnMySQL extends MySQL {
isLoggable(model) { isLoggable(model) {
const Model = this.getModelDefinition(model).model; const Model = this.getModelDefinition(model).model;
const settings = Model.definition.settings; const {settings} = Model.definition;
return settings.base && settings.base === 'Loggable'; return settings.mixins?.Loggable;
} }
invokeMethod(method, args, model, ctx, opts, cb) { invokeMethod(method, args, model, ctx, opts, cb) {
@ -291,7 +291,7 @@ class VnMySQL extends MySQL {
} }
try { try {
const userId = opts.httpCtx && opts.httpCtx.active.accessToken.userId; const userId = opts.httpCtx && opts.httpCtx.active?.accessToken?.userId;
if (userId) { if (userId) {
const user = await Model.app.models.VnUser.findById(userId, {fields: ['name']}, opts); const user = await Model.app.models.VnUser.findById(userId, {fields: ['name']}, opts);
await this.executeP(`CALL account.myUser_loginWithName(?)`, [user.name], opts); await this.executeP(`CALL account.myUser_loginWithName(?)`, [user.name], opts);

View File

@ -25,20 +25,19 @@
"FieldAcl": { "FieldAcl": {
"dataSource": "vn" "dataSource": "vn"
}, },
"Role": {
"dataSource": "vn",
"options": {
"mysql": {
"table": "salix.Role"
}
}
},
"RoleMapping": { "RoleMapping": {
"dataSource": "vn", "dataSource": "vn",
"options": { "options": {
"mysql": { "mysql": {
"table": "salix.RoleMapping" "table": "salix.RoleMapping"
} }
},
"relations": {
"role": {
"type": "belongsTo",
"model": "VnRole",
"foreignKey": "roleId"
}
} }
}, },
"Schema": { "Schema": {

View File

@ -14,6 +14,9 @@
"MailAliasAccount": { "MailAliasAccount": {
"dataSource": "vn" "dataSource": "vn"
}, },
"MailAliasAcl": {
"dataSource": "vn"
},
"MailConfig": { "MailConfig": {
"dataSource": "vn" "dataSource": "vn"
}, },

View File

@ -1,49 +1,49 @@
{ {
"name": "Account", "name": "Account",
"base": "VnModel", "base": "VnModel",
"options": { "options": {
"mysql": { "mysql": {
"table": "account.account" "table": "account.account"
} }
}, },
"properties": { "properties": {
"id": { "id": {
"id": true "id": true
} }
}, },
"relations": { "relations": {
"user": { "user": {
"type": "belongsTo", "type": "belongsTo",
"model": "VnUser", "model": "VnUser",
"foreignKey": "id" "foreignKey": "id"
},
"aliases": {
"type": "hasMany",
"model": "MailAliasAccount",
"foreignKey": "account"
}
},
"acls": [
{
"property": "login",
"accessType": "EXECUTE",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
}, },
{ "aliases": {
"type": "hasMany",
"model": "MailAliasAccount",
"foreignKey": "account"
}
},
"acls": [
{
"property": "login",
"accessType": "EXECUTE",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
},
{
"property": "logout", "property": "logout",
"accessType": "EXECUTE", "accessType": "EXECUTE",
"principalType": "ROLE", "principalType": "ROLE",
"principalId": "$authenticated", "principalId": "$authenticated",
"permission": "ALLOW" "permission": "ALLOW"
}, },
{ {
"property": "changePassword", "property": "changePassword",
"accessType": "EXECUTE", "accessType": "EXECUTE",
"principalType": "ROLE", "principalType": "ROLE",
"principalId": "$everyone", "principalId": "$everyone",
"permission": "ALLOW" "permission": "ALLOW"
} }
] ]
} }

View File

@ -239,7 +239,7 @@ module.exports = Self => {
// Prepare data // Prepare data
let roles = await $.Role.find({ let roles = await $.VnRole.find({
fields: ['id', 'name', 'description'] fields: ['id', 'name', 'description']
}); });
let roleRoles = await $.RoleRole.find({ let roleRoles = await $.RoleRole.find({

View File

@ -1,55 +1,45 @@
const UserError = require('vn-loopback/util/user-error'); const ForbiddenError = require('vn-loopback/util/forbiddenError');
module.exports = Self => { module.exports = Self => {
Self.observe('before save', async ctx => { Self.rewriteDbError(function(err) {
const changes = ctx.currentInstance || ctx.instance; if (err.code === 'ER_DUP_ENTRY')
return new UserError(`You already have the mailAlias`);
await Self.hasGrant(ctx, changes.mailAlias); return err;
}); });
Self.observe('before delete', async ctx => { Self.beforeRemote('create', async function(ctx) {
const mailAliasAccount = await Self.findById(ctx.where.id); const mailAlias = ctx.args.data?.mailAlias;
if (!mailAlias) return;
await Self.hasGrant(ctx, mailAliasAccount.mailAlias); await checkModifyPermission(ctx, mailAlias);
});
Self.beforeRemote('deleteById', async function(ctx) {
const instance = await Self.findById(ctx.args.id,
{fields: ['mailAlias']}
);
await checkModifyPermission(ctx, instance.mailAlias);
}); });
/** async function checkModifyPermission(ctx, mailAliasFk) {
* Checks if current user has
* grant to add/remove alias
*
* @param {Object} ctx - Request context
* @param {Interger} mailAlias - mailAlias id
* @return {Boolean} True for user with grant
*/
Self.hasGrant = async function(ctx, mailAlias) {
const models = Self.app.models; const models = Self.app.models;
const accessToken = {req: {accessToken: ctx.options.accessToken}}; const userId = ctx.req.accessToken.userId;
const userId = accessToken.req.accessToken.userId;
const canEditAlias = await models.ACL.checkAccessAcl(accessToken, 'MailAliasAccount', 'canEditAlias', 'WRITE'); const canEditAlias = await models.ACL.checkAccessAcl(ctx,
if (canEditAlias) return true; 'MailAliasAccount', 'canEditAlias', 'WRITE');
if (canEditAlias) return;
const user = await models.VnUser.findById(userId, {fields: ['hasGrant']}); const allowedRoles = await models.MailAliasAcl.find({
if (!user.hasGrant) fields: ['roleFk'],
throw new UserError(`You don't have grant privilege`); where: {mailAliasFk}
const account = await models.Account.findById(userId, {
fields: ['id'],
include: {
relation: 'aliases',
scope: {
fields: ['mailAlias']
}
}
}); });
const nRoles = allowedRoles.length &&
await models.RoleMapping.count({
principalId: userId,
principalType: 'USER',
roleId: {inq: allowedRoles.map(x => x.roleFk)}
});
const aliases = account.aliases().map(alias => alias.mailAlias); if (!nRoles)
throw new ForbiddenError('You are not allowed to modify the alias');
const hasAlias = aliases.includes(mailAlias); }
if (!hasAlias)
throw new UserError(`You cannot assign/remove an alias that you are not assigned to`);
return true;
};
}; };

View File

@ -0,0 +1,31 @@
{
"name": "MailAliasAcl",
"base": "VnModel",
"options": {
"mysql": {
"table": "account.mailAliasAcl"
}
},
"properties": {
"mailAliasFk": {
"id": true,
"type": "number"
},
"roleFk": {
"id": true,
"type": "number"
}
},
"relations": {
"mailAlias": {
"type": "belongsTo",
"model": "MailAlias",
"foreignKey": "mailAliasFk"
},
"role": {
"type": "belongsTo",
"model": "Role",
"foreignKey": "roleFk"
}
}
}

View File

@ -15,12 +15,12 @@
"relations": { "relations": {
"owner": { "owner": {
"type": "belongsTo", "type": "belongsTo",
"model": "Role", "model": "VnRole",
"foreignKey": "role" "foreignKey": "role"
}, },
"inherits": { "inherits": {
"type": "belongsTo", "type": "belongsTo",
"model": "Role", "model": "VnRole",
"foreignKey": "inheritsFrom" "foreignKey": "inheritsFrom"
} }
} }

View File

@ -14,12 +14,12 @@
"relations": { "relations": {
"owner": { "owner": {
"type": "belongsTo", "type": "belongsTo",
"model": "Role", "model": "VnRole",
"foreignKey": "role" "foreignKey": "role"
}, },
"inherits": { "inherits": {
"type": "belongsTo", "type": "belongsTo",
"model": "Role", "model": "VnRole",
"foreignKey": "inheritsFrom" "foreignKey": "inheritsFrom"
} }
} }

View File

@ -7,7 +7,8 @@ const execFile = require('child_process').execFile;
* https://docs.microsoft.com/en-us/troubleshoot/windows-server/identity/useraccountcontrol-manipulate-account-properties * https://docs.microsoft.com/en-us/troubleshoot/windows-server/identity/useraccountcontrol-manipulate-account-properties
*/ */
const UserAccountControlFlags = { const UserAccountControlFlags = {
ACCOUNTDISABLE: 2 ACCOUNTDISABLE: 0x2,
DONT_EXPIRE_PASSWD: 0x10000
}; };
module.exports = Self => { module.exports = Self => {
@ -118,7 +119,8 @@ module.exports = Self => {
} }
entry = { entry = {
userAccountControl: sambaUser.userAccountControl userAccountControl: (sambaUser.userAccountControl
| UserAccountControlFlags.DONT_EXPIRE_PASSWD)
& ~UserAccountControlFlags.ACCOUNTDISABLE, & ~UserAccountControlFlags.ACCOUNTDISABLE,
uidNumber: info.uidNumber, uidNumber: info.uidNumber,
accountExpires: 0, accountExpires: 0,

View File

@ -15,7 +15,7 @@
<vn-autocomplete <vn-autocomplete
label="Role" label="Role"
ng-model="$ctrl.acl.principalId" ng-model="$ctrl.acl.principalId"
url="Roles" url="VnRoles"
id-field="name" id-field="name"
value-field="name" value-field="name"
vn-focus> vn-focus>
@ -32,7 +32,7 @@
</vn-horizontal> </vn-horizontal>
<vn-horizontal> <vn-horizontal>
<vn-textfield <vn-textfield
label="Property" label="Property"
ng-model="$ctrl.acl.property" ng-model="$ctrl.acl.property"
info="Use * to match all properties"> info="Use * to match all properties">
</vn-textfield> </vn-textfield>

View File

@ -4,7 +4,7 @@
<vn-autocomplete <vn-autocomplete
label="Role" label="Role"
ng-model="filter.principalId" ng-model="filter.principalId"
url="Roles" url="VnRoles"
value-field="name"> value-field="name">
</vn-autocomplete> </vn-autocomplete>
<vn-autocomplete <vn-autocomplete
@ -15,7 +15,7 @@
value-field="name"> value-field="name">
</vn-autocomplete> </vn-autocomplete>
<vn-textfield <vn-textfield
label="Property" label="Property"
ng-model="filter.property"> ng-model="filter.property">
</vn-textfield> </vn-textfield>
<vn-autocomplete <vn-autocomplete
@ -36,4 +36,4 @@
</vn-submit> </vn-submit>
</vn-vertical> </vn-vertical>
</form> </form>
</div> </div>

View File

@ -30,7 +30,7 @@
<vn-autocomplete <vn-autocomplete
label="Role" label="Role"
ng-model="$ctrl.user.roleFk" ng-model="$ctrl.user.roleFk"
url="Roles" url="VnRoles"
rule="VnUser"> rule="VnUser">
</vn-autocomplete> </vn-autocomplete>
<vn-textfield <vn-textfield

View File

@ -22,7 +22,7 @@
<vn-autocomplete <vn-autocomplete
label="Role" label="Role"
ng-model="$ctrl.user.roleFk" ng-model="$ctrl.user.roleFk"
url="Roles"> url="VnRoles">
</vn-autocomplete> </vn-autocomplete>
</vn-vertical> </vn-vertical>
</vn-card> </vn-card>

View File

@ -1,25 +1,27 @@
<vn-watcher <vn-watcher
vn-id="watcher" vn-id="watcher"
url="Roles" url="VnRoles"
data="$ctrl.role" data="$ctrl.role"
form="form"> form="form">
</vn-watcher> </vn-watcher>
<form <form
name="form" name="form"
ng-submit="watcher.submit()" ng-submit="watcher.submit()"
class="vn-w-md"> class="vn-w-md">
<vn-card class="vn-pa-lg"> <vn-card class="vn-pa-lg">
<vn-vertical> <vn-vertical>
<vn-textfield <vn-textfield
label="Name" label="Name"
ng-model="$ctrl.role.name" ng-model="$ctrl.role.name"
rule rule="VnRole.name"
vn-focus> vn-focus>
</vn-textfield> </vn-textfield>
<vn-textfield <vn-textfield
label="Description" label="Description"
ng-model="$ctrl.role.description" ng-model="$ctrl.role.description"
rule> rule="VnRole.description"
>
</vn-textfield> </vn-textfield>
</vn-vertical> </vn-vertical>
</vn-card> </vn-card>
@ -35,4 +37,4 @@
ng-click="watcher.loadOriginalData()"> ng-click="watcher.loadOriginalData()">
</vn-button> </vn-button>
</vn-button-bar> </vn-button-bar>
</form> </form>

View File

@ -3,7 +3,7 @@ import ModuleCard from 'salix/components/module-card';
class Controller extends ModuleCard { class Controller extends ModuleCard {
reload() { reload() {
this.$http.get(`Roles/${this.$params.id}`) this.$http.get(`VnRoles/${this.$params.id}`)
.then(res => this.role = res.data); .then(res => this.role = res.data);
} }
} }

View File

@ -15,7 +15,7 @@ describe('component vnRoleCard', () => {
it('should reload the controller data', () => { it('should reload the controller data', () => {
controller.$params.id = 1; controller.$params.id = 1;
$httpBackend.expectGET('Roles/1').respond('foo'); $httpBackend.expectGET('VnRoles/1').respond('foo');
controller.reload(); controller.reload();
$httpBackend.flush(); $httpBackend.flush();

View File

@ -1,6 +1,6 @@
<vn-watcher <vn-watcher
vn-id="watcher" vn-id="watcher"
url="Roles" url="VnRoles"
data="$ctrl.role" data="$ctrl.role"
insert-mode="true" insert-mode="true"
form="form"> form="form">
@ -12,15 +12,15 @@
<vn-card class="vn-pa-lg"> <vn-card class="vn-pa-lg">
<vn-vertical> <vn-vertical>
<vn-textfield <vn-textfield
label="Name" label="Name"
ng-model="$ctrl.role.name" ng-model="$ctrl.role.name"
rule rule="VnRole.name"
vn-focus> vn-focus>
</vn-textfield> </vn-textfield>
<vn-textfield <vn-textfield
label="Description" label="Description"
ng-model="$ctrl.role.description" ng-model="$ctrl.role.description"
rule> rule="VnRole.description">
</vn-textfield> </vn-textfield>
</vn-vertical> </vn-vertical>
</vn-card> </vn-card>

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