refs #6184 saveCmr #1788
25
CHANGELOG.md
25
CHANGELOG.md
|
@ -5,21 +5,29 @@ 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).
|
||||||
|
|
||||||
## [2342.01] - 2023-10-19
|
## [2348.01] - 2023-11-30
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
### Changed
|
### Changed
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
## [2340.01] - 2023-10-05
|
## [2346.01] - 2023-11-16
|
||||||
|
|
||||||
|
### Added
|
||||||
|
### Changed
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
|
||||||
|
## [2342.01] - 2023-11-02
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- (Usuarios -> Foto) Se muestra la foto del trabajador
|
- (Usuarios -> Foto) Se muestra la foto del trabajador
|
||||||
|
|
||||||
### Changed
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- (Usuarios -> Historial) Abre el descriptor del usuario correctamente
|
- (Usuarios -> Historial) Abre el descriptor del usuario correctamente
|
||||||
|
|
||||||
|
|
||||||
|
## [2340.01] - 2023-10-05
|
||||||
|
|
||||||
## [2338.01] - 2023-09-21
|
## [2338.01] - 2023-09-21
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
@ -29,17 +37,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
### Changed
|
### Changed
|
||||||
- (Trabajadores -> Calendario) Icono de check arreglado cuando pulsas un tipo de dia
|
- (Trabajadores -> Calendario) Icono de check arreglado cuando pulsas un tipo de dia
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
## [2336.01] - 2023-09-07
|
## [2336.01] - 2023-09-07
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
|
|
||||||
## [2334.01] - 2023-08-24
|
## [2334.01] - 2023-08-24
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
|
@ -26,15 +26,14 @@ module.exports = Self => {
|
||||||
|
|
||||||
Self.sendCheckingPresence = async(ctx, recipientId, message) => {
|
Self.sendCheckingPresence = async(ctx, recipientId, message) => {
|
||||||
if (!recipientId) return false;
|
if (!recipientId) return false;
|
||||||
|
|
||||||
const models = Self.app.models;
|
const models = Self.app.models;
|
||||||
|
|
||||||
const userId = ctx.req.accessToken.userId;
|
const userId = ctx.req.accessToken.userId;
|
||||||
const sender = await models.VnUser.findById(userId, {fields: ['id']});
|
const sender = await models.VnUser.findById(userId, {fields: ['id']});
|
||||||
const recipient = await models.VnUser.findById(recipientId, null);
|
const recipient = await models.VnUser.findById(recipientId, null);
|
||||||
|
|
||||||
// Prevent sending messages to yourself
|
// Prevent sending messages to yourself
|
||||||
if (recipientId == userId) return false;
|
if (recipientId == userId) return false;
|
||||||
|
|
||||||
if (!recipient)
|
if (!recipient)
|
||||||
throw new Error(`Could not send message "${message}" to worker id ${recipientId} from user ${userId}`);
|
throw new Error(`Could not send message "${message}" to worker id ${recipientId} from user ${userId}`);
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ module.exports = Self => {
|
||||||
|
|
||||||
Self.getTickets = async(ctx, id, print, options) => {
|
Self.getTickets = async(ctx, id, print, options) => {
|
||||||
const userId = ctx.req.accessToken.userId;
|
const userId = ctx.req.accessToken.userId;
|
||||||
const origin = ctx.req.headers.origin;
|
const url = await Self.app.models.Url.getUrl();
|
||||||
const $t = ctx.req.__;
|
const $t = ctx.req.__;
|
||||||
const myOptions = {};
|
const myOptions = {};
|
||||||
|
|
||||||
|
@ -36,7 +36,6 @@ module.exports = Self => {
|
||||||
myOptions.userId = userId;
|
myOptions.userId = userId;
|
||||||
|
|
||||||
const promises = [];
|
const promises = [];
|
||||||
|
|
||||||
const [tickets] = await Self.rawSql(`CALL vn.collection_getTickets(?)`, [id], myOptions);
|
const [tickets] = await Self.rawSql(`CALL vn.collection_getTickets(?)`, [id], myOptions);
|
||||||
const sales = await Self.rawSql(`
|
const sales = await Self.rawSql(`
|
||||||
SELECT s.ticketFk,
|
SELECT s.ticketFk,
|
||||||
|
@ -86,24 +85,19 @@ module.exports = Self => {
|
||||||
if (tickets && tickets.length) {
|
if (tickets && tickets.length) {
|
||||||
for (const ticket of tickets) {
|
for (const ticket of tickets) {
|
||||||
const ticketId = ticket.ticketFk;
|
const ticketId = ticket.ticketFk;
|
||||||
|
|
||||||
// SEND ROCKET
|
|
||||||
if (ticket.observaciones != '') {
|
if (ticket.observaciones != '') {
|
||||||
for (observation of ticket.observaciones.split(' ')) {
|
for (observation of ticket.observaciones.split(' ')) {
|
||||||
if (['#', '@'].includes(observation.charAt(0))) {
|
if (['#', '@'].includes(observation.charAt(0))) {
|
||||||
promises.push(Self.app.models.Chat.send(ctx, observation,
|
promises.push(Self.app.models.Chat.send(ctx, observation,
|
||||||
$t('The ticket is in preparation', {
|
$t('The ticket is in preparation', {
|
||||||
ticketId: ticketId,
|
ticketId: ticketId,
|
||||||
ticketUrl: `${origin}/#!/ticket/${ticketId}/summary`,
|
ticketUrl: `${url}ticket/${ticketId}/summary`,
|
||||||
salesPersonId: ticket.salesPersonFk
|
salesPersonId: ticket.salesPersonFk
|
||||||
})));
|
})));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SET COLLECTION
|
|
||||||
if (sales && sales.length) {
|
if (sales && sales.length) {
|
||||||
// GET BARCODES
|
|
||||||
const barcodes = await Self.rawSql(`
|
const barcodes = await Self.rawSql(`
|
||||||
SELECT s.id saleFk, b.code, c.id
|
SELECT s.id saleFk, b.code, c.id
|
||||||
FROM vn.sale s
|
FROM vn.sale s
|
||||||
|
@ -114,13 +108,10 @@ module.exports = Self => {
|
||||||
WHERE s.ticketFk = ?
|
WHERE s.ticketFk = ?
|
||||||
AND tr.landed >= util.VN_CURDATE() - INTERVAL 1 YEAR`,
|
AND tr.landed >= util.VN_CURDATE() - INTERVAL 1 YEAR`,
|
||||||
[ticketId], myOptions);
|
[ticketId], myOptions);
|
||||||
|
|
||||||
// BINDINGS
|
|
||||||
ticket.sales = [];
|
ticket.sales = [];
|
||||||
for (const sale of sales) {
|
for (const sale of sales) {
|
||||||
if (sale.ticketFk === ticketId) {
|
if (sale.ticketFk === ticketId) {
|
||||||
sale.Barcodes = [];
|
sale.Barcodes = [];
|
||||||
|
|
||||||
if (barcodes && barcodes.length) {
|
if (barcodes && barcodes.length) {
|
||||||
for (const barcode of barcodes) {
|
for (const barcode of barcodes) {
|
||||||
if (barcode.saleFk === sale.saleFk) {
|
if (barcode.saleFk === sale.saleFk) {
|
||||||
|
@ -131,7 +122,6 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ticket.sales.push(sale);
|
ticket.sales.push(sale);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -140,7 +130,6 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
|
|
||||||
return collection;
|
return collection;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,6 +18,14 @@ describe('setSaleQuantity()', () => {
|
||||||
|
|
||||||
it('should change quantity sale', async() => {
|
it('should change quantity sale', async() => {
|
||||||
const tx = await models.Ticket.beginTransaction({});
|
const tx = await models.Ticket.beginTransaction({});
|
||||||
|
spyOn(models.Sale, 'rawSql').and.callFake((sqlStatement, params, options) => {
|
||||||
|
if (sqlStatement.includes('catalog_calcFromItem')) {
|
||||||
|
sqlStatement = `CREATE OR REPLACE TEMPORARY TABLE tmp.ticketCalculateItem ENGINE = MEMORY
|
||||||
|
SELECT 100 as available;`;
|
||||||
|
params = null;
|
||||||
|
}
|
||||||
|
return models.Ticket.rawSql(sqlStatement, params, options);
|
||||||
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const options = {transaction: tx};
|
const options = {transaction: tx};
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
module.exports = function(Self) {
|
||||||
|
Self.remoteMethod('getByUser', {
|
||||||
|
description: 'returns the starred modules for the current user',
|
||||||
|
accessType: 'READ',
|
||||||
|
accepts: [{
|
||||||
|
arg: 'userId',
|
||||||
|
type: 'number',
|
||||||
|
description: 'The user id',
|
||||||
|
required: true,
|
||||||
|
http: {source: 'path'}
|
||||||
|
}],
|
||||||
|
returns: {
|
||||||
|
type: 'object',
|
||||||
|
root: true
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
path: `/:userId/get-by-user`,
|
||||||
|
verb: 'GET'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.getByUser = async userId => {
|
||||||
|
const models = Self.app.models;
|
||||||
|
const appNames = ['hedera'];
|
||||||
|
const filter = {
|
||||||
|
fields: ['appName', 'url'],
|
||||||
|
where: {
|
||||||
|
appName: {inq: appNames},
|
||||||
|
environment: process.env.NODE_ENV ?? 'development',
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const isWorker = await models.Account.findById(userId, {fields: ['id']});
|
||||||
|
if (!isWorker)
|
||||||
|
return models.Url.find(filter);
|
||||||
|
|
||||||
|
appNames.push('salix');
|
||||||
|
return models.Url.find(filter);
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,30 @@
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethod('getUrl', {
|
||||||
|
description: 'Returns the colling app name',
|
||||||
|
accessType: 'READ',
|
||||||
|
accepts: [
|
||||||
|
{
|
||||||
|
arg: 'app',
|
||||||
|
type: 'string',
|
||||||
|
required: false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
returns: {
|
||||||
|
type: 'object',
|
||||||
|
root: true
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
path: `/getUrl`,
|
||||||
|
verb: 'get'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Self.getUrl = async(appName = 'salix') => {
|
||||||
|
const {url} = await Self.app.models.Url.findOne({
|
||||||
|
where: {
|
||||||
|
appName,
|
||||||
|
enviroment: process.env.NODE_ENV || 'development'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return url;
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,19 @@
|
||||||
|
const {models} = require('vn-loopback/server/server');
|
||||||
|
|
||||||
|
describe('getByUser()', () => {
|
||||||
|
const worker = 1;
|
||||||
|
const notWorker = 2;
|
||||||
|
it(`should return only hedera url if not is worker`, async() => {
|
||||||
|
const urls = await models.Url.getByUser(notWorker);
|
||||||
|
|
||||||
|
expect(urls.length).toEqual(1);
|
||||||
|
expect(urls[0].appName).toEqual('hedera');
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should return more than hedera url`, async() => {
|
||||||
|
const urls = await models.Url.getByUser(worker);
|
||||||
|
|
||||||
|
expect(urls.length).toBeGreaterThan(1);
|
||||||
|
expect(urls.find(url => url.appName == 'salix').appName).toEqual('salix');
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,39 @@
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethodCtx('updateUser', {
|
||||||
|
description: 'Update user data',
|
||||||
|
accepts: [
|
||||||
|
{
|
||||||
|
arg: 'id',
|
||||||
|
type: 'integer',
|
||||||
|
description: 'The user id',
|
||||||
|
required: true,
|
||||||
|
http: {source: 'path'}
|
||||||
|
}, {
|
||||||
|
arg: 'name',
|
||||||
|
type: 'string',
|
||||||
|
description: 'The user name',
|
||||||
|
}, {
|
||||||
|
arg: 'nickname',
|
||||||
|
type: 'string',
|
||||||
|
description: 'The user nickname',
|
||||||
|
}, {
|
||||||
|
arg: 'email',
|
||||||
|
type: 'string',
|
||||||
|
description: 'The user email'
|
||||||
|
}, {
|
||||||
|
arg: 'lang',
|
||||||
|
type: 'string',
|
||||||
|
description: 'The user lang'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
http: {
|
||||||
|
path: `/:id/update-user`,
|
||||||
|
verb: 'PATCH'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.updateUser = async(ctx, id, name, nickname, email, lang) => {
|
||||||
|
await Self.userSecurity(ctx, id);
|
||||||
|
await Self.upsertWithWhere({id}, {name, nickname, email, lang});
|
||||||
|
};
|
||||||
|
};
|
|
@ -7,17 +7,14 @@ module.exports = Self => {
|
||||||
|
|
||||||
Self.observe('before save', async function(ctx) {
|
Self.observe('before save', async function(ctx) {
|
||||||
if (!ctx.isNewInstance) return;
|
if (!ctx.isNewInstance) return;
|
||||||
|
|
||||||
let {message} = ctx.instance;
|
let {message} = ctx.instance;
|
||||||
if (!message) return;
|
if (!message) return;
|
||||||
|
|
||||||
const parts = message.match(/(?<=\[)[a-zA-Z0-9_\-+!@#$%^&*()={};':"\\|,.<>/?\s]*(?=])/g);
|
const parts = message.match(/(?<=\[)[a-zA-Z0-9_\-+!@#$%^&*()={};':"\\|,.<>/?\s]*(?=])/g);
|
||||||
if (!parts) return;
|
if (!parts) return;
|
||||||
|
|
||||||
const replacedParts = parts.map(part => {
|
const replacedParts = parts.map(part => {
|
||||||
return part.replace(/[!$%^&*()={};':"\\,.<>/?]/g, '');
|
return part.replace(/[!$%^&*()={};':"\\,.<>/?]/g, '');
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const [index, part] of parts.entries())
|
for (const [index, part] of parts.entries())
|
||||||
message = message.replace(part, replacedParts[index]);
|
message = message.replace(part, replacedParts[index]);
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
const models = require('vn-loopback/server/server').models;
|
const models = require('vn-loopback/server/server').models;
|
||||||
|
const ForbiddenError = require('vn-loopback/util/forbiddenError');
|
||||||
|
|
||||||
describe('loopback model VnUser', () => {
|
describe('loopback model VnUser', () => {
|
||||||
it('should return true if the user has the given role', async() => {
|
it('should return true if the user has the given role', async() => {
|
||||||
|
@ -12,4 +13,42 @@ describe('loopback model VnUser', () => {
|
||||||
|
|
||||||
expect(result).toBeFalsy();
|
expect(result).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('userSecurity', () => {
|
||||||
|
const itManagementId = 115;
|
||||||
|
const hrId = 37;
|
||||||
|
const employeeId = 1;
|
||||||
|
|
||||||
|
it('should check if you are the same user', async() => {
|
||||||
|
const ctx = {options: {accessToken: {userId: employeeId}}};
|
||||||
|
await models.VnUser.userSecurity(ctx, employeeId);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should check for higher privileges', async() => {
|
||||||
|
const ctx = {options: {accessToken: {userId: itManagementId}}};
|
||||||
|
await models.VnUser.userSecurity(ctx, employeeId);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should check if you have medium privileges and the user email is not verified', async() => {
|
||||||
|
const ctx = {options: {accessToken: {userId: hrId}}};
|
||||||
|
await models.VnUser.userSecurity(ctx, employeeId);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error if you have medium privileges and the users email is verified', async() => {
|
||||||
|
const tx = await models.VnUser.beginTransaction({});
|
||||||
|
const ctx = {options: {accessToken: {userId: hrId}}};
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
const userToUpdate = await models.VnUser.findById(1, null, options);
|
||||||
|
userToUpdate.updateAttribute('emailVerified', 1, options);
|
||||||
|
|
||||||
|
await models.VnUser.userSecurity(ctx, employeeId, options);
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (error) {
|
||||||
|
await tx.rollback();
|
||||||
|
|
||||||
|
expect(error).toEqual(new ForbiddenError());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
module.exports = Self => {
|
||||||
|
require('../methods/url/getByUser')(Self);
|
||||||
|
require('../methods/url/getUrl')(Self);
|
||||||
|
};
|
|
@ -1,6 +1,7 @@
|
||||||
const vnModel = require('vn-loopback/common/models/vn-model');
|
const vnModel = require('vn-loopback/common/models/vn-model');
|
||||||
const LoopBackContext = require('loopback-context');
|
|
||||||
const {Email} = require('vn-print');
|
const {Email} = require('vn-print');
|
||||||
|
const ForbiddenError = require('vn-loopback/util/forbiddenError');
|
||||||
|
const LoopBackContext = require('loopback-context');
|
||||||
|
|
||||||
module.exports = function(Self) {
|
module.exports = function(Self) {
|
||||||
vnModel(Self);
|
vnModel(Self);
|
||||||
|
@ -12,6 +13,7 @@ module.exports = function(Self) {
|
||||||
require('../methods/vn-user/privileges')(Self);
|
require('../methods/vn-user/privileges')(Self);
|
||||||
require('../methods/vn-user/validate-auth')(Self);
|
require('../methods/vn-user/validate-auth')(Self);
|
||||||
require('../methods/vn-user/renew-token')(Self);
|
require('../methods/vn-user/renew-token')(Self);
|
||||||
|
require('../methods/vn-user/update-user')(Self);
|
||||||
|
|
||||||
Self.definition.settings.acls = Self.definition.settings.acls.filter(acl => acl.property !== 'create');
|
Self.definition.settings.acls = Self.definition.settings.acls.filter(acl => acl.property !== 'create');
|
||||||
|
|
||||||
|
@ -90,11 +92,7 @@ module.exports = function(Self) {
|
||||||
};
|
};
|
||||||
|
|
||||||
Self.on('resetPasswordRequest', async function(info) {
|
Self.on('resetPasswordRequest', async function(info) {
|
||||||
const loopBackContext = LoopBackContext.getCurrentContext();
|
const url = await Self.app.models.Url.getUrl();
|
||||||
const httpCtx = {req: loopBackContext.active};
|
|
||||||
const httpRequest = httpCtx.req.http.req;
|
|
||||||
const headers = httpRequest.headers;
|
|
||||||
const origin = headers.origin;
|
|
||||||
|
|
||||||
const defaultHash = '/reset-password?access_token=$token$';
|
const defaultHash = '/reset-password?access_token=$token$';
|
||||||
const recoverHashes = {
|
const recoverHashes = {
|
||||||
|
@ -110,7 +108,7 @@ module.exports = function(Self) {
|
||||||
const params = {
|
const params = {
|
||||||
recipient: info.email,
|
recipient: info.email,
|
||||||
lang: user.lang,
|
lang: user.lang,
|
||||||
url: origin + '/#!' + recoverHash
|
url: url.slice(0, -1) + recoverHash
|
||||||
};
|
};
|
||||||
|
|
||||||
const options = Object.assign({}, info.options);
|
const options = Object.assign({}, info.options);
|
||||||
|
@ -178,45 +176,75 @@ module.exports = function(Self) {
|
||||||
Self.sharedClass._methods.find(method => method.name == 'changePassword').ctor.settings.acls
|
Self.sharedClass._methods.find(method => method.name == 'changePassword').ctor.settings.acls
|
||||||
.filter(acl => acl.property != 'changePassword');
|
.filter(acl => acl.property != 'changePassword');
|
||||||
|
|
||||||
// FIXME: https://redmine.verdnatura.es/issues/5761
|
Self.userSecurity = async(ctx, userId, options) => {
|
||||||
// Self.afterRemote('prototype.patchAttributes', async(ctx, instance) => {
|
const models = Self.app.models;
|
||||||
// if (!ctx.args || !ctx.args.data.email) return;
|
const accessToken = ctx?.options?.accessToken || LoopBackContext.getCurrentContext().active.accessToken;
|
||||||
|
const ctxToken = {req: {accessToken}};
|
||||||
|
|
||||||
// const loopBackContext = LoopBackContext.getCurrentContext();
|
if (userId === accessToken.userId) return;
|
||||||
// const httpCtx = {req: loopBackContext.active};
|
|
||||||
// const httpRequest = httpCtx.req.http.req;
|
|
||||||
// const headers = httpRequest.headers;
|
|
||||||
// const origin = headers.origin;
|
|
||||||
// const url = origin.split(':');
|
|
||||||
|
|
||||||
// class Mailer {
|
const myOptions = {};
|
||||||
// async send(verifyOptions, cb) {
|
if (typeof options == 'object')
|
||||||
// const params = {
|
Object.assign(myOptions, options);
|
||||||
// url: verifyOptions.verifyHref,
|
|
||||||
// recipient: verifyOptions.to,
|
|
||||||
// lang: ctx.req.getLocale()
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const email = new Email('email-verify', params);
|
const hasHigherPrivileges = await models.ACL.checkAccessAcl(ctxToken, 'VnUser', 'higherPrivileges', myOptions);
|
||||||
// email.send();
|
if (hasHigherPrivileges) return;
|
||||||
|
|
||||||
// cb(null, verifyOptions.to);
|
const hasMediumPrivileges = await models.ACL.checkAccessAcl(ctxToken, 'VnUser', 'mediumPrivileges', myOptions);
|
||||||
// }
|
const user = await models.VnUser.findById(userId, {fields: ['id', 'emailVerified']}, myOptions);
|
||||||
// }
|
if (!user.emailVerified && hasMediumPrivileges) return;
|
||||||
|
|
||||||
// const options = {
|
throw new ForbiddenError();
|
||||||
// type: 'email',
|
};
|
||||||
// to: instance.email,
|
|
||||||
// from: {},
|
Self.observe('after save', async ctx => {
|
||||||
// redirect: `${origin}/#!/account/${instance.id}/basic-data?emailConfirmed`,
|
const instance = ctx?.instance;
|
||||||
// template: false,
|
const newEmail = instance?.email;
|
||||||
// mailer: new Mailer,
|
const oldEmail = ctx?.hookState?.oldInstance?.email;
|
||||||
// host: url[1].split('/')[2],
|
if (!ctx.isNewInstance && (!newEmail || !oldEmail || newEmail == oldEmail)) return;
|
||||||
// port: url[2],
|
|
||||||
// protocol: url[0],
|
const loopBackContext = LoopBackContext.getCurrentContext();
|
||||||
// user: Self
|
const httpCtx = {req: loopBackContext.active};
|
||||||
// };
|
const httpRequest = httpCtx.req.http.req;
|
||||||
|
const headers = httpRequest.headers;
|
||||||
// await instance.verify(options);
|
const origin = headers.origin;
|
||||||
// });
|
const url = origin.split(':');
|
||||||
|
|
||||||
|
const env = process.env.NODE_ENV;
|
||||||
|
const liliumUrl = await Self.app.models.Url.findOne({
|
||||||
|
where: {and: [
|
||||||
|
{appName: 'lilium'},
|
||||||
|
{environment: env}
|
||||||
|
]}
|
||||||
|
});
|
||||||
|
|
||||||
|
class Mailer {
|
||||||
|
async send(verifyOptions, cb) {
|
||||||
|
const params = {
|
||||||
|
url: verifyOptions.verifyHref,
|
||||||
|
recipient: verifyOptions.to
|
||||||
|
};
|
||||||
|
|
||||||
|
const email = new Email('email-verify', params);
|
||||||
|
email.send();
|
||||||
|
|
||||||
|
cb(null, verifyOptions.to);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
type: 'email',
|
||||||
|
to: newEmail,
|
||||||
|
from: {},
|
||||||
|
redirect: `${liliumUrl.url}verifyEmail?userId=${instance.id}`,
|
||||||
|
template: false,
|
||||||
|
mailer: new Mailer,
|
||||||
|
host: url[1].split('/')[2],
|
||||||
|
port: url[2],
|
||||||
|
protocol: url[0],
|
||||||
|
user: Self
|
||||||
|
};
|
||||||
|
|
||||||
|
await instance.verify(options, ctx.options);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,14 +18,7 @@
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
"username": {
|
"username": {
|
||||||
"type": "string",
|
"type": "string"
|
||||||
"mysql": {
|
|
||||||
"columnName": "name"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"password": {
|
|
||||||
"type": "string",
|
|
||||||
"required": true
|
|
||||||
},
|
},
|
||||||
"roleFk": {
|
"roleFk": {
|
||||||
"type": "number",
|
"type": "number",
|
||||||
|
@ -45,6 +38,9 @@
|
||||||
"email": {
|
"email": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"emailVerified": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
"created": {
|
"created": {
|
||||||
"type": "date"
|
"type": "date"
|
||||||
},
|
},
|
||||||
|
@ -144,7 +140,8 @@
|
||||||
"image",
|
"image",
|
||||||
"hasGrant",
|
"hasGrant",
|
||||||
"realm",
|
"realm",
|
||||||
"email"
|
"email",
|
||||||
|
"emailVerified"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,133 @@
|
||||||
|
DELIMITER $$
|
||||||
|
$$
|
||||||
|
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticket_canAdvance`(vDateFuture DATE, vDateToAdvance DATE, vWarehouseFk INT)
|
||||||
|
BEGIN
|
||||||
|
/**
|
||||||
|
* Devuelve los tickets y la cantidad de lineas de venta que se pueden adelantar.
|
||||||
|
*
|
||||||
|
* @param vDateFuture Fecha de los tickets que se quieren adelantar.
|
||||||
|
* @param vDateToAdvance Fecha a cuando se quiere adelantar.
|
||||||
|
* @param vWarehouseFk Almacén
|
||||||
|
*/
|
||||||
|
DECLARE vDateInventory DATE;
|
||||||
|
|
||||||
|
SELECT inventoried INTO vDateInventory FROM config;
|
||||||
|
|
||||||
|
DROP TEMPORARY TABLE IF EXISTS tmp.stock;
|
||||||
|
CREATE TEMPORARY TABLE tmp.stock
|
||||||
|
(itemFk INT PRIMARY KEY,
|
||||||
|
amount INT)
|
||||||
|
ENGINE = MEMORY;
|
||||||
|
|
||||||
|
INSERT INTO tmp.stock(itemFk, amount)
|
||||||
|
SELECT itemFk, SUM(quantity) amount FROM
|
||||||
|
(
|
||||||
|
SELECT itemFk, quantity
|
||||||
|
FROM itemTicketOut
|
||||||
|
WHERE shipped >= vDateInventory
|
||||||
|
AND shipped < vDateFuture
|
||||||
|
AND warehouseFk = vWarehouseFk
|
||||||
|
UNION ALL
|
||||||
|
SELECT itemFk, quantity
|
||||||
|
FROM itemEntryIn
|
||||||
|
WHERE landed >= vDateInventory
|
||||||
|
AND landed < vDateFuture
|
||||||
|
AND isVirtualStock = FALSE
|
||||||
|
AND warehouseInFk = vWarehouseFk
|
||||||
|
UNION ALL
|
||||||
|
SELECT itemFk, quantity
|
||||||
|
FROM itemEntryOut
|
||||||
|
WHERE shipped >= vDateInventory
|
||||||
|
AND shipped < vDateFuture
|
||||||
|
AND warehouseOutFk = vWarehouseFk
|
||||||
|
) t
|
||||||
|
GROUP BY itemFk HAVING amount != 0;
|
||||||
|
|
||||||
|
CREATE OR REPLACE TEMPORARY TABLE tmp.filter
|
||||||
|
(INDEX (id))
|
||||||
|
SELECT
|
||||||
|
origin.ticketFk futureId,
|
||||||
|
dest.ticketFk id,
|
||||||
|
dest.state,
|
||||||
|
origin.futureState,
|
||||||
|
origin.futureIpt,
|
||||||
|
dest.ipt,
|
||||||
|
origin.workerFk,
|
||||||
|
origin.futureLiters,
|
||||||
|
origin.futureLines,
|
||||||
|
dest.shipped,
|
||||||
|
origin.shipped futureShipped,
|
||||||
|
dest.totalWithVat,
|
||||||
|
origin.totalWithVat futureTotalWithVat,
|
||||||
|
dest.agency,
|
||||||
|
origin.futureAgency,
|
||||||
|
dest.lines,
|
||||||
|
dest.liters,
|
||||||
|
origin.futureLines - origin.hasStock AS notMovableLines,
|
||||||
|
(origin.futureLines = origin.hasStock) AS isFullMovable,
|
||||||
|
origin.futureZoneFk,
|
||||||
|
origin.futureZoneName,
|
||||||
|
origin.classColor futureClassColor,
|
||||||
|
dest.classColor
|
||||||
|
FROM (
|
||||||
|
SELECT
|
||||||
|
s.ticketFk,
|
||||||
|
c.salesPersonFk workerFk,
|
||||||
|
t.shipped,
|
||||||
|
t.totalWithVat,
|
||||||
|
st.name futureState,
|
||||||
|
t.addressFk,
|
||||||
|
am.name futureAgency,
|
||||||
|
count(s.id) futureLines,
|
||||||
|
GROUP_CONCAT(DISTINCT ipt.code ORDER BY ipt.code) futureIpt,
|
||||||
|
CAST(SUM(litros) AS DECIMAL(10,0)) futureLiters,
|
||||||
|
SUM((s.quantity <= IFNULL(st.amount,0))) hasStock,
|
||||||
|
z.id futureZoneFk,
|
||||||
|
z.name futureZoneName,
|
||||||
|
st.classColor
|
||||||
|
FROM ticket t
|
||||||
|
JOIN client c ON c.id = t.clientFk
|
||||||
|
JOIN sale s ON s.ticketFk = t.id
|
||||||
|
JOIN saleVolume sv ON sv.saleFk = s.id
|
||||||
|
JOIN item i ON i.id = s.itemFk
|
||||||
|
JOIN ticketState ts ON ts.ticketFk = t.id
|
||||||
|
JOIN state st ON st.id = ts.stateFk
|
||||||
|
JOIN agencyMode am ON t.agencyModeFk = am.id
|
||||||
|
JOIN zone z ON t.zoneFk = z.id
|
||||||
|
LEFT JOIN itemPackingType ipt ON ipt.code = i.itemPackingTypeFk
|
||||||
|
LEFT JOIN tmp.stock st ON st.itemFk = i.id
|
||||||
|
WHERE t.shipped BETWEEN vDateFuture AND util.dayend(vDateFuture)
|
||||||
|
AND t.warehouseFk = vWarehouseFk
|
||||||
|
GROUP BY t.id
|
||||||
|
) origin
|
||||||
|
JOIN (
|
||||||
|
SELECT
|
||||||
|
t.id ticketFk,
|
||||||
|
t.addressFk,
|
||||||
|
st.name state,
|
||||||
|
GROUP_CONCAT(DISTINCT ipt.code ORDER BY ipt.code) ipt,
|
||||||
|
t.shipped,
|
||||||
|
t.totalWithVat,
|
||||||
|
am.name agency,
|
||||||
|
CAST(SUM(litros) AS DECIMAL(10,0)) liters,
|
||||||
|
CAST(COUNT(*) AS DECIMAL(10,0)) `lines`,
|
||||||
|
st.classColor
|
||||||
|
FROM ticket t
|
||||||
|
JOIN sale s ON s.ticketFk = t.id
|
||||||
|
JOIN saleVolume sv ON sv.saleFk = s.id
|
||||||
|
JOIN item i ON i.id = s.itemFk
|
||||||
|
JOIN ticketState ts ON ts.ticketFk = t.id
|
||||||
|
JOIN state st ON st.id = ts.stateFk
|
||||||
|
JOIN agencyMode am ON t.agencyModeFk = am.id
|
||||||
|
LEFT JOIN itemPackingType ipt ON ipt.code = i.itemPackingTypeFk
|
||||||
|
WHERE t.shipped BETWEEN vDateToAdvance AND util.dayend(vDateToAdvance)
|
||||||
|
AND t.warehouseFk = vWarehouseFk
|
||||||
|
AND st.order <= 5
|
||||||
|
GROUP BY t.id
|
||||||
|
) dest ON dest.addressFk = origin.addressFk
|
||||||
|
WHERE origin.hasStock != 0;
|
||||||
|
|
||||||
|
DROP TEMPORARY TABLE tmp.stock;
|
||||||
|
END$$
|
||||||
|
DELIMITER ;
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
UPDATE `vn`.`workerTimeControlConfig`
|
||||||
|
SET `timeToBreakTime` = 18000;
|
||||||
|
|
||||||
|
ALTER TABLE `vn`.`workerTimeControlConfig`
|
||||||
|
DROP COLUMN IF EXISTS `maxTimeToBreak`;
|
||||||
|
ALTER TABLE `vn`.`workerTimeControlConfig`
|
||||||
|
ADD COLUMN maxTimeToBreak INT DEFAULT 3600 NULL;
|
||||||
|
|
||||||
|
ALTER TABLE `vn`.`workerTimeControlConfig`
|
||||||
|
DROP COLUMN IF EXISTS `maxWorkShortCycle`;
|
||||||
|
|
||||||
|
ALTER TABLE `vn`.`workerTimeControlConfig`
|
||||||
|
ADD COLUMN `maxWorkShortCycle` INT(10) UNSIGNED DEFAULT 561600
|
||||||
|
COMMENT 'Máximo tiempo que un trabajador puede estar trabajando con el que adquirirá el derecho a un descanso semanal corto';
|
||||||
|
|
||||||
|
ALTER TABLE `vn`.`workerTimeControlConfig`
|
||||||
|
DROP COLUMN IF EXISTS `maxWorkLongCycle`;
|
||||||
|
|
||||||
|
ALTER TABLE `vn`.`workerTimeControlConfig`
|
||||||
|
ADD COLUMN `maxWorkLongCycle` INT(10) UNSIGNED DEFAULT 950400
|
||||||
|
COMMENT 'Máximo tiempo que un trabajador puede estar trabajando con el que adquirirá el derecho a un descanso semanal largo';
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `vn`.`workerTimeControlError` (
|
||||||
|
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`code` char(35) NOT NULL,
|
||||||
|
`description` varchar(255) NOT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `code` (`code`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||||
|
|
||||||
|
INSERT IGNORE INTO `vn`.`workerTimeControlError` (`code`, `description`)
|
||||||
|
VALUES
|
||||||
|
('IS_NOT_ALLOWED_FUTURE', 'No se permite fichar a futuro'),
|
||||||
|
('INACTIVE_BUSINESS', 'No hay un contrato en vigor'),
|
||||||
|
('IS_NOT_ALLOWED_WORK', 'No está permitido trabajar'),
|
||||||
|
('ODD_WORKERTIMECONTROL', 'Fichadas impares'),
|
||||||
|
('DAY_MAX_TIME', 'Superado el tiempo máximo entre entrada y salida'),
|
||||||
|
('BREAK_DAY', 'Descanso diario'),
|
||||||
|
('BREAK_WEEK', 'Descanso semanal'),
|
||||||
|
('WRONG_DIRECTION', 'Dirección incorrecta'),
|
||||||
|
('UNDEFINED_ERROR', 'Error sin definir');
|
|
@ -0,0 +1,194 @@
|
||||||
|
DELIMITER $$
|
||||||
|
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`timeControl_calculate`(
|
||||||
|
vDatedFrom DATETIME,
|
||||||
|
vDatedTo DATETIME)
|
||||||
|
BEGIN
|
||||||
|
/*
|
||||||
|
* Agrupa por trabajador y día, el tiempo de trabajo y descanso retribuido(si tiene).
|
||||||
|
* Los registros horarios incorrectos (tmp.timeControlError) no se considerarán.
|
||||||
|
* Si un trabajador ha trabajado más de un cierto umbral de tiempo (vTimeToBreakTime)
|
||||||
|
* y no ha tenido descansos que superen un parámetro determinado(vMaxTimeToBreak),
|
||||||
|
* se le añadirá un tiempo de descanso (vBreakTime) a sus horas trabajadas.
|
||||||
|
* El tiempo de descanso solo se añade si el trabajador realmente disfrutó del descanso.
|
||||||
|
* Si disfrutó de menos tiempo de descanso, solo se añade el tiempo que disfrutó.
|
||||||
|
*
|
||||||
|
* @param vDatedFrom
|
||||||
|
* @param vDatedTo
|
||||||
|
*
|
||||||
|
* @return tmp.timeControlCalculate
|
||||||
|
* (workerFk, dated, timeWorkSeconds, timeWorkSexagesimal, timeWorkDecimal, timed)
|
||||||
|
*/
|
||||||
|
DECLARE vHourSeconds INTEGER;
|
||||||
|
DECLARE vDatedFromYesterday DATETIME;
|
||||||
|
DECLARE vDatedToTomorrow DATETIME;
|
||||||
|
DECLARE vTimeToBreakTime INT;
|
||||||
|
DECLARE vBreakTime INT;
|
||||||
|
DECLARE vMaxTimeToBreak INT;
|
||||||
|
|
||||||
|
SELECT DATE_SUB(vDatedFrom, INTERVAL 1 DAY), DATE_ADD(vDatedTo, INTERVAL 1 DAY)
|
||||||
|
INTO vDatedFromYesterday, vDatedToTomorrow;
|
||||||
|
|
||||||
|
SELECT timeToBreakTime, breakTime, maxTimeToBreak, TIME_TO_SEC('01:00:00')
|
||||||
|
INTO vTimeToBreakTime, vBreakTime, vMaxTimeToBreak, vHourSeconds
|
||||||
|
FROM workerTimeControlConfig
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
CALL timeControl_getError(vDatedFromYesterday, vDatedToTomorrow);
|
||||||
|
|
||||||
|
CREATE OR REPLACE TEMPORARY TABLE tmp.workerTimeControl
|
||||||
|
(INDEX(userFk, timed), INDEX(timed), INDEX(direction))
|
||||||
|
ENGINE = MEMORY
|
||||||
|
SELECT wtc.userFk,
|
||||||
|
wtc.timed,
|
||||||
|
DATE(wtc.timed) dated,
|
||||||
|
wtc.direction,
|
||||||
|
TRUE isReal
|
||||||
|
FROM workerTimeControl wtc
|
||||||
|
JOIN tmp.`user` u ON u.userFk = wtc.userFk
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT wtc.userFk, MIN(wtc.timed) firstIn
|
||||||
|
FROM workerTimeControl wtc
|
||||||
|
JOIN tmp.`user` u ON u.userFk = wtc.userFk
|
||||||
|
LEFT JOIN tmp.timeControlError tce ON tce.id = wtc.id
|
||||||
|
WHERE wtc.timed BETWEEN vDatedFromYesterday AND vDatedToTomorrow
|
||||||
|
AND wtc.direction = 'in'
|
||||||
|
AND tce.id IS NULL
|
||||||
|
GROUP BY userFk
|
||||||
|
) fi ON wtc.userFk = fi.userFk
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT wtc.userFk, MAX(wtc.timed) lastOut
|
||||||
|
FROM workerTimeControl wtc
|
||||||
|
JOIN tmp.`user` u ON u.userFk = wtc.userFk
|
||||||
|
LEFT JOIN tmp.timeControlError tce ON tce.id = wtc.id
|
||||||
|
WHERE wtc.timed BETWEEN vDatedFromYesterday AND vDatedToTomorrow
|
||||||
|
AND wtc.direction = 'out'
|
||||||
|
AND tce.id IS NULL
|
||||||
|
GROUP BY userFk
|
||||||
|
) lo ON wtc.userFk = lo.userFk
|
||||||
|
LEFT JOIN tmp.timeControlError tce ON tce.id = wtc.id
|
||||||
|
WHERE wtc.timed BETWEEN fi.firstIn AND lo.lastOut
|
||||||
|
AND tce.id IS NULL
|
||||||
|
ORDER BY wtc.userFk, wtc.timed;
|
||||||
|
|
||||||
|
CREATE OR REPLACE TEMPORARY TABLE tmp.wtcToinsert
|
||||||
|
(INDEX(timed))
|
||||||
|
ENGINE = MEMORY
|
||||||
|
WITH wtc AS(
|
||||||
|
SELECT timed,
|
||||||
|
userFk,
|
||||||
|
dated,
|
||||||
|
direction,
|
||||||
|
LEAD(dated) OVER
|
||||||
|
(PARTITION BY userFk, dated ORDER BY timed) nextDay,
|
||||||
|
LEAD(userFk) OVER
|
||||||
|
(PARTITION BY userFk ORDER BY timed) nextUserFk,
|
||||||
|
ROW_NUMBER() OVER (ORDER BY userFk, timed) MOD 2 isOdd
|
||||||
|
FROM tmp.workerTimeControl
|
||||||
|
WHERE timed BETWEEN vDatedFromYesterday AND vDatedToTomorrow
|
||||||
|
ORDER BY userFk, timed
|
||||||
|
), wtcToinsert AS(
|
||||||
|
SELECT userFk,
|
||||||
|
dated,
|
||||||
|
IF(userFk = nextUserFk
|
||||||
|
AND nextDay IS NULL
|
||||||
|
AND isOdd
|
||||||
|
AND direction <> 'out', TRUE, FALSE) outNextDay,
|
||||||
|
IF(userFk = nextUserFk
|
||||||
|
AND nextDay IS NULL
|
||||||
|
AND NOT isOdd
|
||||||
|
AND direction <> 'out', TRUE, FALSE) outNextDayWhitBreak
|
||||||
|
FROM wtc
|
||||||
|
HAVING outNextDay OR outNextDayWhitBreak
|
||||||
|
)SELECT userFk, util.dayEnd(dated) timed, 'out' direction
|
||||||
|
FROM wtcToinsert
|
||||||
|
WHERE outNextDay
|
||||||
|
UNION ALL
|
||||||
|
SELECT userFk, dated + INTERVAL 1 DAY, 'in'
|
||||||
|
FROM wtcToinsert
|
||||||
|
WHERE outNextDay
|
||||||
|
UNION ALL
|
||||||
|
SELECT userFk, util.dayEnd(dated) - INTERVAL 1 SECOND, 'middle'
|
||||||
|
FROM wtcToinsert
|
||||||
|
WHERE outNextDayWhitBreak
|
||||||
|
UNION ALL
|
||||||
|
SELECT userFk, util.dayEnd(dated), 'out'
|
||||||
|
FROM wtcToinsert
|
||||||
|
WHERE outNextDayWhitBreak
|
||||||
|
UNION ALL
|
||||||
|
SELECT userFk, dated + INTERVAL 1 DAY, 'in'
|
||||||
|
FROM wtcToinsert
|
||||||
|
WHERE outNextDayWhitBreak
|
||||||
|
UNION ALL
|
||||||
|
SELECT userFk, dated + INTERVAL 1 DAY + INTERVAL 1 SECOND, 'middle'
|
||||||
|
FROM wtcToinsert
|
||||||
|
WHERE outNextDayWhitBreak;
|
||||||
|
|
||||||
|
INSERT INTO tmp.workerTimeControl (userFk, timed, dated, direction, isReal)
|
||||||
|
SELECT userFk, timed, DATE(timed), direction, FALSE
|
||||||
|
FROM tmp.wtcToinsert;
|
||||||
|
|
||||||
|
SET @accumulatedForBreakTime = 0;
|
||||||
|
SET @oldrealDay = NULL;
|
||||||
|
CREATE OR REPLACE TEMPORARY TABLE tmp.timeControlCalculate
|
||||||
|
WITH workerTimed AS (
|
||||||
|
SELECT
|
||||||
|
userFk,
|
||||||
|
dated,
|
||||||
|
timed,
|
||||||
|
(direction ='in' AND isReal) breakPoint,
|
||||||
|
SUM(CASE WHEN (direction ='in' AND isReal) THEN TRUE ELSE FALSE END)
|
||||||
|
OVER (ORDER BY userFk, timed) AS realDay,
|
||||||
|
TIMESTAMPDIFF(SECOND, LAG(timed)
|
||||||
|
OVER (PARTITION BY userFk, dated ORDER BY timed), timed) gapTime,
|
||||||
|
ROW_NUMBER()
|
||||||
|
OVER (PARTITION BY userFk, dated ORDER BY timed) MOD 2 isOdd
|
||||||
|
FROM tmp.workerTimeControl
|
||||||
|
WHERE timed BETWEEN vDatedFromYesterday AND vDatedToTomorrow
|
||||||
|
), accumulated AS (
|
||||||
|
SELECT SUM(IF(isOdd, 0, gapTime))
|
||||||
|
OVER (PARTITION BY userFk,dated ORDER BY userFk,timed) accumulatedWorkTime,
|
||||||
|
SUM(IF(NOT isOdd OR breakPoint, 0, IFNULL(gapTime, 0)))
|
||||||
|
OVER (PARTITION BY realDay ORDER BY realDay,timed) accumulatedBreakTime,
|
||||||
|
IF(realDay <> @oldrealDay OR (isOdd AND gapTime >= vMaxTimeToBreak),
|
||||||
|
@accumulatedForBreakTime := 0,
|
||||||
|
@accumulatedForBreakTime := @accumulatedForBreakTime +
|
||||||
|
IF(isOdd, 0, gapTime )) accumulatedForBreakTime,
|
||||||
|
@oldrealDay := realDay,
|
||||||
|
userFk,
|
||||||
|
dated,
|
||||||
|
realDay
|
||||||
|
FROM workerTimed
|
||||||
|
), totalWorked AS (
|
||||||
|
SELECT userFk,
|
||||||
|
dated,
|
||||||
|
MAX(accumulatedWorkTime) +
|
||||||
|
IF(MAX(accumulatedForBreakTime) >= vTimeToBreakTime,
|
||||||
|
LEAST(vBreakTime, MAX(accumulatedBreakTime)),
|
||||||
|
0) timeWorkSeconds
|
||||||
|
FROM accumulated
|
||||||
|
GROUP BY userFk, dated
|
||||||
|
)SELECT tw.userFk,
|
||||||
|
tw.dated,
|
||||||
|
timeWorkSeconds,
|
||||||
|
SEC_TO_TIME(timeWorkSeconds) timeWorkSexagesimal,
|
||||||
|
timeWorkSeconds / vHourSeconds timeWorkDecimal,
|
||||||
|
sub.tableTimed
|
||||||
|
FROM totalWorked tw
|
||||||
|
JOIN (
|
||||||
|
SELECT userFk,
|
||||||
|
dated,
|
||||||
|
GROUP_CONCAT(DATE_FORMAT(timed, "%H:%i") ORDER BY timed ASC
|
||||||
|
SEPARATOR ' - ')tableTimed
|
||||||
|
FROM tmp.workerTimeControl
|
||||||
|
WHERE timed BETWEEN vDatedFromYesterday AND vDatedToTomorrow
|
||||||
|
AND isReal
|
||||||
|
GROUP BY userFk, dated
|
||||||
|
)sub ON sub.dated = tw.dated
|
||||||
|
AND sub.userFk = tw.userFk
|
||||||
|
WHERE tw.dated BETWEEN vDatedFrom AND vDatedTo;
|
||||||
|
|
||||||
|
DROP TEMPORARY TABLE tmp.timeControlError;
|
||||||
|
DROP TEMPORARY TABLE tmp.wtcToinsert;
|
||||||
|
DROP TEMPORARY TABLE tmp.workerTimeControl;
|
||||||
|
END$$
|
||||||
|
DELIMITER ;
|
|
@ -0,0 +1,286 @@
|
||||||
|
DELIMITER $$
|
||||||
|
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`workerTimeControl_clockIn`(
|
||||||
|
vWorkerFk INT,
|
||||||
|
vTimed DATETIME,
|
||||||
|
vDirection VARCHAR(10)
|
||||||
|
)
|
||||||
|
BEGIN
|
||||||
|
/**
|
||||||
|
* Verifica si el empleado puede fichar
|
||||||
|
* @param vWorkerFk Identificador del trabajador
|
||||||
|
* @param vTimed valor de la fichada, IF vTimed IS NULL vTimed = NOW
|
||||||
|
* @param vDirection solo se pueden pasa los valores del campo
|
||||||
|
* workerTimeControl.direction ENUM('in', 'out', 'middle')
|
||||||
|
* @return Si todo es correcto, retorna el número de id la tabla workerTimeControl.
|
||||||
|
* Si hay algún problema, devuelve el mesaje que se debe mostrar al usuario
|
||||||
|
* Solo retorna el primer problema, en caso de no ocurrir ningún error se añadirá
|
||||||
|
* fichada a la tabla vn.workerTimeControl
|
||||||
|
*/
|
||||||
|
|
||||||
|
DECLARE vLastIn DATETIME;
|
||||||
|
DECLARE vLastOut DATETIME;
|
||||||
|
DECLARE vNextIn DATETIME;
|
||||||
|
DECLARE vNextOut DATETIME;
|
||||||
|
DECLARE vNextDirection ENUM('in', 'out');
|
||||||
|
DECLARE vLastDirection ENUM('in', 'out');
|
||||||
|
DECLARE vDayMaxTime INTEGER;
|
||||||
|
DECLARE vDayBreak INT;
|
||||||
|
DECLARE vShortWeekBreak INT;
|
||||||
|
DECLARE vLongWeekBreak INT;
|
||||||
|
DECLARE vWeekScope INT;
|
||||||
|
DECLARE vMailTo VARCHAR(50) DEFAULT NULL;
|
||||||
|
DECLARE vUserName VARCHAR(50) DEFAULT NULL;
|
||||||
|
DECLARE vIsError BOOLEAN DEFAULT FALSE;
|
||||||
|
DECLARE vErrorMessage VARCHAR(255) DEFAULT NULL;
|
||||||
|
DECLARE vErrorCode VARCHAR(50);
|
||||||
|
DECLARE vDated DATE;
|
||||||
|
DECLARE vIsAllowedToWork VARCHAR(50);
|
||||||
|
DECLARE vIsManual BOOLEAN DEFAULT TRUE;
|
||||||
|
DECLARE vMaxWorkShortCycle INT;
|
||||||
|
DECLARE vMaxWorkLongCycle INT;
|
||||||
|
|
||||||
|
DECLARE EXIT HANDLER FOR SQLSTATE '45000'
|
||||||
|
BEGIN
|
||||||
|
|
||||||
|
SELECT CONCAT(u.name, '@verdnatura.es'),
|
||||||
|
CONCAT(w.firstName, ' ', w.lastName)
|
||||||
|
INTO vMailTo, vUserName
|
||||||
|
FROM account.user u
|
||||||
|
JOIN worker w ON w.bossFk = u.id
|
||||||
|
WHERE w.id = vWorkerFk;
|
||||||
|
|
||||||
|
SELECT `description` INTO vErrorMessage
|
||||||
|
FROM workerTimeControlError
|
||||||
|
WHERE `code` = vErrorCode;
|
||||||
|
|
||||||
|
IF vErrorMessage IS NULL THEN
|
||||||
|
SET vErrorMessage = 'Error sin definir';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
SELECT vErrorMessage `error`;
|
||||||
|
SELECT CONCAT(vUserName,
|
||||||
|
' no ha podido fichar por el siguiente problema: ',
|
||||||
|
vErrorMessage)
|
||||||
|
INTO vErrorMessage;
|
||||||
|
|
||||||
|
CALL mail_insert( vMailTo, vMailTo, 'Error al fichar', vErrorMessage);
|
||||||
|
END;
|
||||||
|
|
||||||
|
IF (vTimed IS NULL) THEN
|
||||||
|
SET vTimed = util.VN_NOW();
|
||||||
|
SET vIsManual = FALSE;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
SET vDated = DATE(vTimed);
|
||||||
|
|
||||||
|
SELECT IF(pc.name = 'Conductor +3500kg',
|
||||||
|
wc.dayBreakDriver,
|
||||||
|
wc.dayBreak),
|
||||||
|
wc.shortWeekBreak,
|
||||||
|
wc.longWeekBreak,
|
||||||
|
wc.weekScope,
|
||||||
|
wc.dayMaxTime,
|
||||||
|
wc.maxWorkShortCycle,
|
||||||
|
wc.maxWorkLongCycle
|
||||||
|
INTO vDayBreak,
|
||||||
|
vShortWeekBreak,
|
||||||
|
vLongWeekBreak,
|
||||||
|
vWeekScope,
|
||||||
|
vDayMaxTime,
|
||||||
|
vMaxWorkShortCycle,
|
||||||
|
vMaxWorkLongCycle
|
||||||
|
FROM business b
|
||||||
|
JOIN professionalCategory pc
|
||||||
|
ON pc.id = b.workerBusinessProfessionalCategoryFk
|
||||||
|
JOIN workerTimeControlConfig wc
|
||||||
|
WHERE b.workerFk = vWorkerFk
|
||||||
|
AND vDated BETWEEN b.started AND IFNULL(b.ended, vDated);
|
||||||
|
|
||||||
|
-- CONTRATO EN VIGOR
|
||||||
|
IF vDayBreak IS NULL THEN
|
||||||
|
SET vErrorCode = 'INACTIVE_BUSINESS';
|
||||||
|
CALL util.throw(vErrorCode);
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- FICHADAS A FUTURO
|
||||||
|
IF vTimed > util.VN_NOW() + INTERVAL 1 MINUTE THEN
|
||||||
|
SET vErrorCode = 'IS_NOT_ALLOWED_FUTURE';
|
||||||
|
CALL util.throw(vErrorCode);
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- VERIFICAR SI ESTÁ PERMITIDO TRABAJAR
|
||||||
|
CALL timeBusiness_calculateByWorker(vWorkerFk, vDated, vDated);
|
||||||
|
SELECT isAllowedToWork INTO vIsAllowedToWork
|
||||||
|
FROM tmp.timeBusinessCalculate;
|
||||||
|
DROP TEMPORARY TABLE tmp.timeBusinessCalculate;
|
||||||
|
|
||||||
|
IF NOT vIsAllowedToWork THEN
|
||||||
|
SET vErrorCode = 'IS_NOT_ALLOWED_WORK';
|
||||||
|
CALL util.throw(vErrorCode);
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- DIRECCION CORRECTA
|
||||||
|
CALL workerTimeControl_direction(vWorkerFk, vTimed);
|
||||||
|
IF (SELECT
|
||||||
|
IF(IF(option1 IN ('inMiddle', 'outMiddle'),
|
||||||
|
'middle',
|
||||||
|
option1) <> vDirection
|
||||||
|
AND IF(option2 IN ('inMiddle', 'outMiddle'),
|
||||||
|
'middle',
|
||||||
|
IFNULL(option2, '')) <> vDirection,
|
||||||
|
TRUE ,
|
||||||
|
FALSE)
|
||||||
|
FROM tmp.workerTimeControlDirection
|
||||||
|
) THEN
|
||||||
|
SET vIsError = TRUE;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
DROP TEMPORARY TABLE tmp.workerTimeControlDirection;
|
||||||
|
IF vIsError THEN
|
||||||
|
SET vErrorCode = 'WRONG_DIRECTION';
|
||||||
|
CALL util.throw(vErrorCode);
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- FICHADAS IMPARES
|
||||||
|
SELECT timed INTO vLastIn
|
||||||
|
FROM workerTimeControl
|
||||||
|
WHERE userFk = vWorkerFk
|
||||||
|
AND direction = 'in'
|
||||||
|
AND timed < vTimed
|
||||||
|
ORDER BY timed DESC
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
IF (SELECT IF(vDirection = 'in',
|
||||||
|
MOD(COUNT(*), 2) ,
|
||||||
|
IF (vDirection = 'out', NOT MOD(COUNT(*), 2), FALSE))
|
||||||
|
FROM workerTimeControl
|
||||||
|
WHERE userFk = vWorkerFk
|
||||||
|
AND timed BETWEEN vLastIn AND vTimed
|
||||||
|
) THEN
|
||||||
|
SET vErrorCode = 'ODD_WORKERTIMECONTROL';
|
||||||
|
CALL util.throw(vErrorCode);
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- DESCANSO DIARIO
|
||||||
|
SELECT timed INTO vLastOut
|
||||||
|
FROM workerTimeControl
|
||||||
|
WHERE userFk = vWorkerFk
|
||||||
|
AND direction = 'out'
|
||||||
|
AND timed < vTimed
|
||||||
|
ORDER BY timed DESC
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
SELECT timed INTO vNextIn
|
||||||
|
FROM workerTimeControl
|
||||||
|
WHERE userFk = vWorkerFk
|
||||||
|
AND direction = 'in'
|
||||||
|
AND timed > vTimed
|
||||||
|
ORDER BY timed ASC
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
CASE vDirection
|
||||||
|
WHEN 'in' THEN
|
||||||
|
IF UNIX_TIMESTAMP(vTimed) - UNIX_TIMESTAMP(vLastOut) <= vDayBreak THEN
|
||||||
|
SET vIsError = TRUE;
|
||||||
|
END IF;
|
||||||
|
WHEN 'out' THEN
|
||||||
|
IF UNIX_TIMESTAMP(vNextIn) - UNIX_TIMESTAMP(vTimed) <= vDayBreak THEN
|
||||||
|
SET vIsError = TRUE;
|
||||||
|
END IF;
|
||||||
|
ELSE BEGIN END;
|
||||||
|
END CASE;
|
||||||
|
|
||||||
|
IF vIsError THEN
|
||||||
|
SET vErrorCode = 'BREAK_DAY';
|
||||||
|
CALL util.throw(vErrorCode);
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
IF (vDirection IN('in', 'out')) THEN
|
||||||
|
-- VERIFICA MAXIMO TIEMPO DESDE ENTRADA HASTA LA SALIDA
|
||||||
|
|
||||||
|
SELECT timed INTO vNextOut
|
||||||
|
FROM workerTimeControl
|
||||||
|
WHERE userFk = vWorkerFk
|
||||||
|
AND direction = 'out'
|
||||||
|
AND timed > vTimed
|
||||||
|
ORDER BY timed ASC
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
SELECT direction INTO vNextDirection
|
||||||
|
FROM workerTimeControl
|
||||||
|
WHERE userFk = vWorkerFk
|
||||||
|
AND direction IN('in','out')
|
||||||
|
AND timed > vTimed
|
||||||
|
ORDER BY timed ASC
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
SELECT direction INTO vLastDirection
|
||||||
|
FROM workerTimeControl
|
||||||
|
WHERE userFk = vWorkerFk
|
||||||
|
AND direction IN('in', 'out')
|
||||||
|
AND timed < vTimed
|
||||||
|
ORDER BY timed ASC
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
IF (vDirection ='in'
|
||||||
|
AND vNextDirection = 'out'
|
||||||
|
AND UNIX_TIMESTAMP(vNextOut) - UNIX_TIMESTAMP(vTimed) > vDayMaxTime) OR
|
||||||
|
(vDirection ='out'
|
||||||
|
AND vLastDirection = 'in'
|
||||||
|
AND UNIX_TIMESTAMP(vTimed) -UNIX_TIMESTAMP(vLastIn) > vDayMaxTime) THEN
|
||||||
|
SET vErrorCode = 'DAY_MAX_TIME';
|
||||||
|
CALL util.throw(vErrorCode);
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- VERIFICA DESCANSO SEMANAL
|
||||||
|
|
||||||
|
WITH wtc AS(
|
||||||
|
(SELECT timed
|
||||||
|
FROM vn.workerTimeControl
|
||||||
|
WHERE userFk = vWorkerFk
|
||||||
|
AND direction IN ('in', 'out')
|
||||||
|
AND timed BETWEEN vTimed - INTERVAL (vWeekScope * 2) SECOND
|
||||||
|
AND vTimed + INTERVAL (vWeekScope * 2) SECOND )
|
||||||
|
UNION
|
||||||
|
(SELECT vTimed)
|
||||||
|
), wtcGap AS(
|
||||||
|
SELECT timed,
|
||||||
|
TIMESTAMPDIFF(SECOND, LAG(timed) OVER (ORDER BY timed), timed) gap
|
||||||
|
FROM wtc
|
||||||
|
ORDER BY timed
|
||||||
|
), wtcBreak AS(
|
||||||
|
SELECT timed,
|
||||||
|
IF(IFNULL(gap, 0) > vShortWeekBreak, TRUE, FALSE) hasShortBreak,
|
||||||
|
IF(IFNULL(gap, 0) > vLongWeekBreak, TRUE, FALSE) hasLongBreak
|
||||||
|
FROM wtcGap
|
||||||
|
ORDER BY timed
|
||||||
|
), wtcBreakCounter AS(
|
||||||
|
SELECT timed,
|
||||||
|
SUM(hasShortBreak) OVER (ORDER BY timed) breakCounter ,
|
||||||
|
LEAD(hasLongBreak) OVER (ORDER BY timed) nextHasLongBreak
|
||||||
|
FROM wtcBreak
|
||||||
|
)SELECT TIMESTAMPDIFF(SECOND, MIN(timed), MAX(timed)) > vMaxWorkLongCycle OR
|
||||||
|
(TIMESTAMPDIFF(SECOND, MIN(timed), MAX(timed))> vMaxWorkShortCycle
|
||||||
|
AND NOT SUM(IFNULL(nextHasLongBreak, 1)))
|
||||||
|
hasError INTO vIsError
|
||||||
|
FROM wtcBreakCounter
|
||||||
|
GROUP BY breakCounter
|
||||||
|
HAVING hasError
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
IF vIsError THEN
|
||||||
|
SET vErrorCode = 'BREAK_WEEK';
|
||||||
|
CALL util.throw(vErrorCode);
|
||||||
|
END IF;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- SE PERMITE FICHAR
|
||||||
|
INSERT INTO workerTimeControl(userFk, timed, direction, `manual`)
|
||||||
|
VALUES(vWorkerFk, vTimed, vDirection, vIsManual);
|
||||||
|
|
||||||
|
SELECT LAST_INSERT_ID() id;
|
||||||
|
|
||||||
|
END$$
|
||||||
|
DELIMITER ;
|
|
@ -0,0 +1,3 @@
|
||||||
|
INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
|
||||||
|
VALUES
|
||||||
|
('WorkerDepartment', '*', '*', 'ALLOW', 'ROLE', 'employee');
|
|
@ -0,0 +1,7 @@
|
||||||
|
INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
|
||||||
|
VALUES
|
||||||
|
('VnUser', 'higherPrivileges', '*', 'ALLOW', 'ROLE', 'itManagement'),
|
||||||
|
('VnUser', 'mediumPrivileges', '*', 'ALLOW', 'ROLE', 'hr'),
|
||||||
|
('VnUser', 'updateUser', '*', 'ALLOW', 'ROLE', 'employee');
|
||||||
|
|
||||||
|
ALTER TABLE `account`.`user` ADD `username` varchar(30) AS (name) VIRTUAL;
|
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
INSERT INTO `salix`.`ACL` ( model, property, accessType, permission, principalType, principalId)
|
||||||
|
VALUES('TicketCollection', '*', 'WRITE', 'ALLOW', 'ROLE', 'production');
|
|
@ -0,0 +1,4 @@
|
||||||
|
INSERT INTO `salix`.`ACL` (model,property,accessType,permission,principalType,principalId)
|
||||||
|
VALUES ('Worker','setPassword','*','ALLOW','ROLE','employee');
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
INSERT INTO `salix`.`url` (`appName`, `environment`, `url`)
|
||||||
|
VALUES
|
||||||
|
('hedera', 'test', 'https://test-shop.verdnatura.es/'),
|
||||||
|
('hedera', 'production', 'https://shop.verdnatura.es/');
|
||||||
|
|
||||||
|
INSERT INTO `salix`.`ACL` ( model, property, accessType, permission, principalType, principalId)
|
||||||
|
VALUES('Url', 'getByUser', 'READ', 'ALLOW', 'ROLE', '$everyone');
|
|
@ -0,0 +1 @@
|
||||||
|
DROP PROCEDURE IF EXISTS `vn`.`workerCreate`;
|
|
@ -0,0 +1,5 @@
|
||||||
|
ALTER TABLE `vn`.`buy` CHANGE `packageFk` `packagingFk` varchar(10)
|
||||||
|
CHARACTER SET utf8mb3 COLLATE utf8mb3_unicode_ci DEFAULT '--' NULL;
|
||||||
|
|
||||||
|
ALTER TABLE `vn`.`buy`
|
||||||
|
ADD COLUMN `packageFk` varchar(10) AS (`packagingFk`) VIRTUAL;
|
|
@ -0,0 +1,150 @@
|
||||||
|
CREATE SCHEMA IF NOT EXISTS `vn2008`;
|
||||||
|
|
||||||
|
CREATE OR REPLACE DEFINER=`root`@`localhost`
|
||||||
|
SQL SECURITY DEFINER
|
||||||
|
VIEW `vn`.`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 (
|
||||||
|
(
|
||||||
|
(
|
||||||
|
(
|
||||||
|
(
|
||||||
|
(
|
||||||
|
(
|
||||||
|
(
|
||||||
|
`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`.`duaEntry` `de` ON(`de`.`entryFk` = `e`.`id`)
|
||||||
|
)
|
||||||
|
JOIN `vn`.`dua` `d` ON(`d`.`id` = `de`.`duaFk`)
|
||||||
|
)
|
||||||
|
JOIN `vn`.`volumeConfig` `vc`
|
||||||
|
)
|
||||||
|
WHERE `t`.`shipped` > makedate(year(`util`.`VN_CURDATE`()) - 1, 1);
|
||||||
|
|
||||||
|
|
||||||
|
CREATE OR REPLACE DEFINER=`root`@`localhost`
|
||||||
|
SQL SECURITY DEFINER
|
||||||
|
VIEW `vn2008`.`Compres`
|
||||||
|
AS SELECT `c`.`id` AS `Id_Compra`,
|
||||||
|
`c`.`entryFk` AS `Id_Entrada`,
|
||||||
|
`c`.`itemFk` AS `Id_Article`,
|
||||||
|
`c`.`buyingValue` AS `Costefijo`,
|
||||||
|
`c`.`quantity` AS `Cantidad`,
|
||||||
|
`c`.`packagingFk` AS `Id_Cubo`,
|
||||||
|
`c`.`stickers` AS `Etiquetas`,
|
||||||
|
`c`.`freightValue` AS `Portefijo`,
|
||||||
|
`c`.`packageValue` AS `Embalajefijo`,
|
||||||
|
`c`.`comissionValue` AS `Comisionfija`,
|
||||||
|
`c`.`packing` AS `Packing`,
|
||||||
|
`c`.`grouping` AS `grouping`,
|
||||||
|
`c`.`groupingMode` AS `caja`,
|
||||||
|
`c`.`location` AS `Nicho`,
|
||||||
|
`c`.`price1` AS `Tarifa1`,
|
||||||
|
`c`.`price2` AS `Tarifa2`,
|
||||||
|
`c`.`price3` AS `Tarifa3`,
|
||||||
|
`c`.`minPrice` AS `PVP`,
|
||||||
|
`c`.`printedStickers` AS `Vida`,
|
||||||
|
`c`.`isChecked` AS `punteo`,
|
||||||
|
`c`.`ektFk` AS `buy_edi_id`,
|
||||||
|
`c`.`created` AS `odbc_date`,
|
||||||
|
`c`.`isIgnored` AS `Novincular`,
|
||||||
|
`c`.`isPickedOff` AS `isPickedOff`,
|
||||||
|
`c`.`workerFk` AS `Id_Trabajador`,
|
||||||
|
`c`.`weight` AS `weight`,
|
||||||
|
`c`.`dispatched` AS `dispatched`,
|
||||||
|
`c`.`containerFk` AS `container_id`,
|
||||||
|
`c`.`itemOriginalFk` AS `itemOriginalFk`
|
||||||
|
FROM `vn`.`buy` `c`;
|
||||||
|
|
||||||
|
CREATE OR REPLACE DEFINER=`root`@`localhost`
|
||||||
|
SQL SECURITY DEFINER
|
||||||
|
VIEW `vn2008`.`buySource`
|
||||||
|
AS SELECT `b`.`entryFk` AS `Id_Entrada`,
|
||||||
|
`b`.`isPickedOff` AS `isPickedOff`,
|
||||||
|
NULL AS `tarifa0`,
|
||||||
|
`e`.`kop` AS `kop`,
|
||||||
|
`b`.`id` AS `Id_Compra`,
|
||||||
|
`i`.`typeFk` AS `tipo_id`,
|
||||||
|
`b`.`itemFk` AS `Id_Article`,
|
||||||
|
`i`.`size` AS `Medida`,
|
||||||
|
`i`.`stems` AS `Tallos`,
|
||||||
|
`b`.`stickers` AS `Etiquetas`,
|
||||||
|
`b`.`packagingFk` AS `Id_Cubo`,
|
||||||
|
`b`.`buyingValue` AS `Costefijo`,
|
||||||
|
`b`.`packing` AS `Packing`,
|
||||||
|
`b`.`grouping` AS `Grouping`,
|
||||||
|
`b`.`quantity` AS `Cantidad`,
|
||||||
|
`b`.`price2` AS `Tarifa2`,
|
||||||
|
`b`.`price3` AS `Tarifa3`,
|
||||||
|
`b`.`isChecked` AS `Punteo`,
|
||||||
|
`b`.`groupingMode` AS `Caja`,
|
||||||
|
`i`.`isToPrint` AS `Imprimir`,
|
||||||
|
`i`.`name` AS `Article`,
|
||||||
|
`vn`.`ink`.`picture` AS `Tinta`,
|
||||||
|
`i`.`originFk` AS `id_origen`,
|
||||||
|
`i`.`minPrice` AS `PVP`,
|
||||||
|
NULL AS `Id_Accion`,
|
||||||
|
`s`.`company_name` AS `pro`,
|
||||||
|
`i`.`hasMinPrice` AS `Min`,
|
||||||
|
`b`.`isIgnored` AS `Novincular`,
|
||||||
|
`b`.`freightValue` AS `Portefijo`,
|
||||||
|
round(`b`.`buyingValue` * `b`.`quantity`, 2) AS `Importe`,
|
||||||
|
`b`.`printedStickers` AS `Vida`,
|
||||||
|
`i`.`comment` AS `reference`,
|
||||||
|
`b`.`workerFk` AS `Id_Trabajador`,
|
||||||
|
`e`.`s1` AS `S1`,
|
||||||
|
`e`.`s2` AS `S2`,
|
||||||
|
`e`.`s3` AS `S3`,
|
||||||
|
`e`.`s4` AS `S4`,
|
||||||
|
`e`.`s5` AS `S5`,
|
||||||
|
`e`.`s6` AS `S6`,
|
||||||
|
0 AS `price_fixed`,
|
||||||
|
`i`.`producerFk` AS `producer_id`,
|
||||||
|
`i`.`subName` AS `tag1`,
|
||||||
|
`i`.`value5` AS `tag2`,
|
||||||
|
`i`.`value6` AS `tag3`,
|
||||||
|
`i`.`value7` AS `tag4`,
|
||||||
|
`i`.`value8` AS `tag5`,
|
||||||
|
`i`.`value9` AS `tag6`,
|
||||||
|
`s`.`company_name` AS `company_name`,
|
||||||
|
`b`.`weight` AS `weightPacking`,
|
||||||
|
`i`.`packingOut` AS `packingOut`,
|
||||||
|
`b`.`itemOriginalFk` AS `itemOriginalFk`,
|
||||||
|
`io`.`longName` AS `itemOriginalName`,
|
||||||
|
`it`.`gramsMax` AS `gramsMax`
|
||||||
|
FROM (
|
||||||
|
(
|
||||||
|
(
|
||||||
|
(
|
||||||
|
(
|
||||||
|
(
|
||||||
|
`vn`.`item` `i`
|
||||||
|
JOIN `vn`.`itemType` `it` ON(`it`.`id` = `i`.`typeFk`)
|
||||||
|
)
|
||||||
|
LEFT JOIN `vn`.`ink` ON(`vn`.`ink`.`id` = `i`.`inkFk`)
|
||||||
|
)
|
||||||
|
LEFT JOIN `vn`.`buy` `b` ON(`b`.`itemFk` = `i`.`id`)
|
||||||
|
)
|
||||||
|
LEFT JOIN `vn`.`item` `io` ON(`io`.`id` = `b`.`itemOriginalFk`)
|
||||||
|
)
|
||||||
|
LEFT JOIN `edi`.`ekt` `e` ON(`e`.`id` = `b`.`ektFk`)
|
||||||
|
)
|
||||||
|
LEFT JOIN `edi`.`supplier` `s` ON(`e`.`pro` = `s`.`supplier_id`)
|
||||||
|
);
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue