Merge branch 'dev' into 5867-Driver-Route-Pdf
gitea/salix/pipeline/head This commit looks good Details

This commit is contained in:
Sergio De la torre 2023-10-27 04:49:16 +00:00
commit 60ffc21d5a
236 changed files with 4046 additions and 993 deletions

View File

@ -5,7 +5,13 @@ 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/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [2342.01] - 2023-10-19
## [2346.01] - 2023-11-16
### Added
### Changed
### Fixed
## [2342.01] - 2023-11-02
### Added
### Changed

View File

@ -26,15 +26,14 @@ module.exports = Self => {
Self.sendCheckingPresence = async(ctx, recipientId, message) => {
if (!recipientId) return false;
const models = Self.app.models;
const userId = ctx.req.accessToken.userId;
const sender = await models.VnUser.findById(userId, {fields: ['id']});
const recipient = await models.VnUser.findById(recipientId, null);
// Prevent sending messages to yourself
if (recipientId == userId) return false;
if (!recipient)
throw new Error(`Could not send message "${message}" to worker id ${recipientId} from user ${userId}`);

View File

@ -26,7 +26,7 @@ module.exports = Self => {
Self.getTickets = async(ctx, id, print, options) => {
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 myOptions = {};
@ -36,7 +36,6 @@ module.exports = Self => {
myOptions.userId = userId;
const promises = [];
const [tickets] = await Self.rawSql(`CALL vn.collection_getTickets(?)`, [id], myOptions);
const sales = await Self.rawSql(`
SELECT s.ticketFk,
@ -86,24 +85,19 @@ module.exports = Self => {
if (tickets && tickets.length) {
for (const ticket of tickets) {
const ticketId = ticket.ticketFk;
// SEND ROCKET
if (ticket.observaciones != '') {
for (observation of ticket.observaciones.split(' ')) {
if (['#', '@'].includes(observation.charAt(0))) {
promises.push(Self.app.models.Chat.send(ctx, observation,
$t('The ticket is in preparation', {
ticketId: ticketId,
ticketUrl: `${origin}/#!/ticket/${ticketId}/summary`,
ticketUrl: `${url}ticket/${ticketId}/summary`,
salesPersonId: ticket.salesPersonFk
})));
}
}
}
// SET COLLECTION
if (sales && sales.length) {
// GET BARCODES
const barcodes = await Self.rawSql(`
SELECT s.id saleFk, b.code, c.id
FROM vn.sale s
@ -114,13 +108,10 @@ module.exports = Self => {
WHERE s.ticketFk = ?
AND tr.landed >= util.VN_CURDATE() - INTERVAL 1 YEAR`,
[ticketId], myOptions);
// BINDINGS
ticket.sales = [];
for (const sale of sales) {
if (sale.ticketFk === ticketId) {
sale.Barcodes = [];
if (barcodes && barcodes.length) {
for (const barcode of barcodes) {
if (barcode.saleFk === sale.saleFk) {
@ -131,7 +122,6 @@ module.exports = Self => {
}
}
}
ticket.sales.push(sale);
}
}
@ -140,7 +130,6 @@ module.exports = Self => {
}
}
await Promise.all(promises);
return collection;
};
};

View File

@ -18,6 +18,14 @@ describe('setSaleQuantity()', () => {
it('should change quantity sale', async() => {
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 {
const options = {transaction: tx};

View File

@ -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);
};
};

View File

@ -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;
};
};

View File

@ -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');
});
});

View File

@ -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});
};
};

View File

@ -7,17 +7,14 @@ module.exports = Self => {
Self.observe('before save', async function(ctx) {
if (!ctx.isNewInstance) return;
let {message} = ctx.instance;
if (!message) return;
const parts = message.match(/(?<=\[)[a-zA-Z0-9_\-+!@#$%^&*()={};':"\\|,.<>/?\s]*(?=])/g);
if (!parts) return;
const replacedParts = parts.map(part => {
return part.replace(/[!$%^&*()={};':"\\,.<>/?]/g, '');
});
for (const [index, part] of parts.entries())
message = message.replace(part, replacedParts[index]);

View File

@ -1,4 +1,5 @@
const models = require('vn-loopback/server/server').models;
const ForbiddenError = require('vn-loopback/util/forbiddenError');
describe('loopback model VnUser', () => {
it('should return true if the user has the given role', async() => {
@ -12,4 +13,42 @@ describe('loopback model VnUser', () => {
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());
}
});
});
});

4
back/models/url.js Normal file
View File

@ -0,0 +1,4 @@
module.exports = Self => {
require('../methods/url/getByUser')(Self);
require('../methods/url/getUrl')(Self);
};

View File

@ -1,6 +1,7 @@
const vnModel = require('vn-loopback/common/models/vn-model');
const LoopBackContext = require('loopback-context');
const {Email} = require('vn-print');
const ForbiddenError = require('vn-loopback/util/forbiddenError');
const LoopBackContext = require('loopback-context');
module.exports = function(Self) {
vnModel(Self);
@ -12,6 +13,7 @@ module.exports = function(Self) {
require('../methods/vn-user/privileges')(Self);
require('../methods/vn-user/validate-auth')(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');
@ -90,11 +92,7 @@ module.exports = function(Self) {
};
Self.on('resetPasswordRequest', async function(info) {
const loopBackContext = LoopBackContext.getCurrentContext();
const httpCtx = {req: loopBackContext.active};
const httpRequest = httpCtx.req.http.req;
const headers = httpRequest.headers;
const origin = headers.origin;
const url = await Self.app.models.Url.getUrl();
const defaultHash = '/reset-password?access_token=$token$';
const recoverHashes = {
@ -110,7 +108,7 @@ module.exports = function(Self) {
const params = {
recipient: info.email,
lang: user.lang,
url: origin + '/#!' + recoverHash
url: url.slice(0, -1) + recoverHash
};
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
.filter(acl => acl.property != 'changePassword');
// FIXME: https://redmine.verdnatura.es/issues/5761
// Self.afterRemote('prototype.patchAttributes', async(ctx, instance) => {
// if (!ctx.args || !ctx.args.data.email) return;
Self.userSecurity = async(ctx, userId, options) => {
const models = Self.app.models;
const accessToken = ctx?.options?.accessToken || LoopBackContext.getCurrentContext().active.accessToken;
const ctxToken = {req: {accessToken}};
// const loopBackContext = LoopBackContext.getCurrentContext();
// const httpCtx = {req: loopBackContext.active};
// const httpRequest = httpCtx.req.http.req;
// const headers = httpRequest.headers;
// const origin = headers.origin;
// const url = origin.split(':');
if (userId === accessToken.userId) return;
// class Mailer {
// async send(verifyOptions, cb) {
// const params = {
// url: verifyOptions.verifyHref,
// recipient: verifyOptions.to,
// lang: ctx.req.getLocale()
// };
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
// const email = new Email('email-verify', params);
// email.send();
const hasHigherPrivileges = await models.ACL.checkAccessAcl(ctxToken, 'VnUser', 'higherPrivileges', myOptions);
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 = {
// type: 'email',
// to: instance.email,
// from: {},
// redirect: `${origin}/#!/account/${instance.id}/basic-data?emailConfirmed`,
// template: false,
// mailer: new Mailer,
// host: url[1].split('/')[2],
// port: url[2],
// protocol: url[0],
// user: Self
// };
throw new ForbiddenError();
};
// await instance.verify(options);
// });
Self.observe('after save', async ctx => {
const instance = ctx?.instance;
const newEmail = instance?.email;
const oldEmail = ctx?.hookState?.oldInstance?.email;
if (!ctx.isNewInstance && (!newEmail || !oldEmail || newEmail == oldEmail)) return;
const loopBackContext = LoopBackContext.getCurrentContext();
const httpCtx = {req: loopBackContext.active};
const httpRequest = httpCtx.req.http.req;
const headers = httpRequest.headers;
const origin = headers.origin;
const url = origin.split(':');
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);
});
};

View File

@ -13,19 +13,12 @@
"type": "number",
"id": true
},
"name": {
"name": {
"type": "string",
"required": true
},
"username": {
"type": "string",
"mysql": {
"columnName": "name"
}
},
"password": {
"type": "string",
"required": true
"type": "string"
},
"roleFk": {
"type": "number",
@ -45,6 +38,9 @@
"email": {
"type": "string"
},
"emailVerified": {
"type": "boolean"
},
"created": {
"type": "date"
},
@ -144,7 +140,8 @@
"image",
"hasGrant",
"realm",
"email"
"email",
"emailVerified"
]
}
}

View File

@ -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 ;

View File

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

View File

@ -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;

View File

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

View File

@ -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');

View File

@ -0,0 +1 @@
DROP PROCEDURE IF EXISTS `vn`.`workerCreate`;

View File

@ -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;

View File

@ -0,0 +1,146 @@
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`)
);
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);

View File

@ -0,0 +1,26 @@
ALTER TABLE `vn`.`zoneIncluded`
ADD COLUMN `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT FIRST,
DROP PRIMARY KEY,
DROP FOREIGN KEY `zoneFk2`,
DROP FOREIGN KEY `zoneGeoFk2`,
DROP KEY `geoFk_idx`,
ADD PRIMARY KEY (`id`),
ADD CONSTRAINT `zoneIncluded_FK_1` FOREIGN KEY (zoneFk) REFERENCES `vn`.`zone`(id) ON DELETE CASCADE ON UPDATE CASCADE,
ADD CONSTRAINT `zoneIncluded_FK_2` FOREIGN KEY (geoFk) REFERENCES `vn`.`zoneGeo`(id) ON DELETE CASCADE ON UPDATE CASCADE,
ADD CONSTRAINT `unique_zone_geo` UNIQUE (`zoneFk`, `geoFk`);
DROP TRIGGER IF EXISTS `vn`.`zoneIncluded_afterDelete`;
USE `vn`;
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`zoneIncluded_afterDelete`
AFTER DELETE ON `zoneIncluded`
FOR EACH ROW
BEGIN
INSERT INTO zoneLog
SET `action` = 'delete',
`changedModel` = 'zoneIncluded',
`changedModelId` = OLD.zoneFk,
`userFk` = account.myUser_getId();
END$$
DELIMITER ;

View File

@ -0,0 +1,57 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`buy_afterUpdate`
AFTER UPDATE ON `buy`
FOR EACH ROW
trig: BEGIN
DECLARE vLanded DATE;
DECLARE vBuyerFk INT;
DECLARE vIsBuyerToBeEmailed BOOL;
DECLARE vItemName VARCHAR(50);
IF @isModeInventory OR @isTriggerDisabled THEN
LEAVE trig;
END IF;
IF !(NEW.id <=> OLD.id)
OR !(NEW.entryFk <=> OLD.entryFk)
OR !(NEW.itemFk <=> OLD.itemFk)
OR !(NEW.quantity <=> OLD.quantity)
OR !(NEW.created <=> OLD.created) THEN
CALL stock.log_add('buy', NEW.id, OLD.id);
END IF;
CALL buy_afterUpsert(NEW.id);
SELECT w.isBuyerToBeEmailed, t.landed
INTO vIsBuyerToBeEmailed, vLanded
FROM entry e
JOIN travel t ON t.id = e.travelFk
JOIN warehouse w ON w.id = t.warehouseInFk
WHERE e.id = NEW.entryFk;
SELECT it.workerFk, i.longName
INTO vBuyerFk, vItemName
FROM itemCategory k
JOIN itemType it ON it.categoryFk = k.id
JOIN item i ON i.typeFk = it.id
WHERE i.id = OLD.itemFk;
IF vIsBuyerToBeEmailed AND
vBuyerFk != account.myUser_getId() AND
vLanded = util.VN_CURDATE() THEN
IF !(NEW.itemFk <=> OLD.itemFk) OR
!(NEW.quantity <=> OLD.quantity) OR
!(NEW.packing <=> OLD.packing) OR
!(NEW.grouping <=> OLD.grouping) OR
!(NEW.packagingFk <=> OLD.packagingFk) OR
!(NEW.weight <=> OLD.weight) THEN
CALL vn.mail_insert(
CONCAT(account.user_getNameFromId(vBuyerFk),'@verdnatura.es'),
CONCAT(account.myUser_getName(),'@verdnatura.es'),
CONCAT('E ', NEW.entryFk ,' Se ha modificado item ', NEW.itemFk, ' ', vItemName),
'Este email se ha generado automáticamente'
);
END IF;
END IF;
END$$
DELIMITER ;

File diff suppressed because it is too large Load Diff

View File

View File

@ -0,0 +1,6 @@
INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
VALUES
('CplusRectificationType', '*', 'READ', 'ALLOW', 'ROLE', 'administrative'),
('CplusInvoiceType477', '*', 'READ', 'ALLOW', 'ROLE', 'administrative'),
('InvoiceCorrectionType', '*', 'READ', 'ALLOW', 'ROLE', 'administrative'),
('InvoiceOut', 'transferInvoice', 'WRITE', 'ALLOW', 'ROLE', 'administrative');

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