update insert
gitea/salix/pipeline/head There was a failure building this commit
Details
gitea/salix/pipeline/head There was a failure building this commit
Details
This commit is contained in:
commit
f76727903a
|
@ -4,5 +4,11 @@
|
|||
"files.eol": "\n",
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": true
|
||||
},
|
||||
"search.useIgnoreFiles": false,
|
||||
"editor.defaultFormatter": "dbaeumer.vscode-eslint",
|
||||
"eslint.format.enable": true,
|
||||
"[javascript]": {
|
||||
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
|
||||
}
|
||||
}
|
||||
|
|
30
CHANGELOG.md
30
CHANGELOG.md
|
@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [2310.01] - 2023-03-23
|
||||
## [2316.01] - 2023-05-04
|
||||
|
||||
### Added
|
||||
-
|
||||
|
@ -13,6 +13,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
### Changed
|
||||
-
|
||||
|
||||
### Fixed
|
||||
-
|
||||
|
||||
## [2314.01] - 2023-04-20
|
||||
|
||||
### Added
|
||||
- (Clientes -> Morosos) Ahora se puede filtrar por las columnas "Desde" y "Fecha Ú. O.". También se envia un email al comercial cuando se añade una nota.
|
||||
- (Monitor tickets) Muestra un icono al lado de la zona, si el ticket es frágil y se envía por agencia
|
||||
- (Facturas recibidas -> Bases negativas) Nueva sección
|
||||
|
||||
### Fixed
|
||||
- (Clientes -> Morosos) Ahora se mantienen los elementos seleccionados al hacer sroll.
|
||||
|
||||
## [2312.01] - 2023-04-06
|
||||
|
||||
### Added
|
||||
- (Monitor tickets) Muestra un icono al lado de la zona, si el ticket es frágil y se envía por agencia
|
||||
|
||||
### Changed
|
||||
- (Monitor tickets) Cuando se filtra por 'Pendiente' ya no muestra los estados de 'Previa'
|
||||
- (Envíos -> Extra comunitarios) Se agrupan las entradas del mismo travel. Añadidos campos Referencia y Importe.
|
||||
- (Envíos -> Índice) Cambiado el buscador superior por uno lateral
|
||||
|
||||
## [2310.01] - 2023-03-23
|
||||
|
||||
### Added
|
||||
- (Trabajadores -> Control de horario) Ahora se puede confirmar/no confirmar el registro horario de cada semana desde esta sección
|
||||
|
||||
### Fixed
|
||||
- (Clientes -> Listado extendido) Resuelto error al filtrar por clientes inactivos desde la columna "Activo"
|
||||
- (General) Al pasar el ratón por encima del icono de "Borrar" en un campo, se hacía más grande afectando a la interfaz
|
||||
|
|
|
@ -10,6 +10,7 @@ RUN apt-get update \
|
|||
curl \
|
||||
ca-certificates \
|
||||
gnupg2 \
|
||||
graphicsmagick \
|
||||
&& curl -fsSL https://deb.nodesource.com/setup_14.x | bash - \
|
||||
&& apt-get install -y --no-install-recommends nodejs \
|
||||
&& npm install -g npm@8.19.2
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
module.exports = Self => {
|
||||
Self.remoteMethod('changePassword', {
|
||||
description: 'Changes the user password',
|
||||
accessType: 'WRITE',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'id',
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
module.exports = Self => {
|
||||
Self.remoteMethod('setPassword', {
|
||||
description: 'Sets the user password',
|
||||
accessType: 'WRITE',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'id',
|
||||
|
|
|
@ -30,16 +30,23 @@ module.exports = Self => {
|
|||
const recipient = to.replace('@', '');
|
||||
|
||||
if (sender.name != recipient) {
|
||||
await models.Chat.create({
|
||||
const chat = await models.Chat.create({
|
||||
senderFk: sender.id,
|
||||
recipient: to,
|
||||
dated: Date.vnNew(),
|
||||
checkUserStatus: 0,
|
||||
message: message,
|
||||
status: 0,
|
||||
status: 'sending',
|
||||
attempts: 0
|
||||
});
|
||||
|
||||
try {
|
||||
await Self.sendMessage(chat.senderFk, chat.recipient, chat.message);
|
||||
await Self.updateChat(chat, 'sent');
|
||||
} catch (error) {
|
||||
await Self.updateChat(chat, 'error', error);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,18 +24,13 @@ module.exports = Self => {
|
|||
}
|
||||
});
|
||||
|
||||
Self.sendCheckingPresence = async(ctx, recipientId, message, options) => {
|
||||
Self.sendCheckingPresence = async(ctx, recipientId, message) => {
|
||||
if (!recipientId) return false;
|
||||
|
||||
const myOptions = {};
|
||||
|
||||
if (typeof options == 'object')
|
||||
Object.assign(myOptions, options);
|
||||
|
||||
const models = Self.app.models;
|
||||
const userId = ctx.req.accessToken.userId;
|
||||
const sender = await models.Account.findById(userId);
|
||||
const recipient = await models.Account.findById(recipientId, null, myOptions);
|
||||
const sender = await models.Account.findById(userId, {fields: ['id']});
|
||||
const recipient = await models.Account.findById(recipientId, null);
|
||||
|
||||
// Prevent sending messages to yourself
|
||||
if (recipientId == userId) return false;
|
||||
|
@ -46,16 +41,23 @@ module.exports = Self => {
|
|||
if (process.env.NODE_ENV == 'test')
|
||||
message = `[Test:Environment to user ${userId}] ` + message;
|
||||
|
||||
await models.Chat.create({
|
||||
const chat = await models.Chat.create({
|
||||
senderFk: sender.id,
|
||||
recipient: `@${recipient.name}`,
|
||||
dated: Date.vnNew(),
|
||||
checkUserStatus: 1,
|
||||
message: message,
|
||||
status: 0,
|
||||
status: 'sending',
|
||||
attempts: 0
|
||||
});
|
||||
|
||||
try {
|
||||
await Self.sendCheckingUserStatus(chat);
|
||||
await Self.updateChat(chat, 'sent');
|
||||
} catch (error) {
|
||||
await Self.updateChat(chat, 'error', error);
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -3,7 +3,6 @@ module.exports = Self => {
|
|||
Self.remoteMethodCtx('sendQueued', {
|
||||
description: 'Send a RocketChat message',
|
||||
accessType: 'WRITE',
|
||||
accepts: [],
|
||||
returns: {
|
||||
type: 'object',
|
||||
root: true
|
||||
|
@ -16,14 +15,17 @@ module.exports = Self => {
|
|||
|
||||
Self.sendQueued = async() => {
|
||||
const models = Self.app.models;
|
||||
const maxAttempts = 3;
|
||||
const sentStatus = 1;
|
||||
const errorStatus = 2;
|
||||
|
||||
const chats = await models.Chat.find({
|
||||
where: {
|
||||
status: {neq: sentStatus},
|
||||
attempts: {lt: maxAttempts}
|
||||
status: {
|
||||
nin: [
|
||||
'sent',
|
||||
'sending'
|
||||
]
|
||||
|
||||
},
|
||||
attempts: {lt: 3}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -31,16 +33,16 @@ module.exports = Self => {
|
|||
if (chat.checkUserStatus) {
|
||||
try {
|
||||
await Self.sendCheckingUserStatus(chat);
|
||||
await updateChat(chat, sentStatus);
|
||||
await Self.updateChat(chat, 'sent');
|
||||
} catch (error) {
|
||||
await updateChat(chat, errorStatus, error);
|
||||
await Self.updateChat(chat, 'error', error);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
await Self.sendMessage(chat.senderFk, chat.recipient, chat.message);
|
||||
await updateChat(chat, sentStatus);
|
||||
await Self.updateChat(chat, 'sent');
|
||||
} catch (error) {
|
||||
await updateChat(chat, errorStatus, error);
|
||||
await Self.updateChat(chat, 'error', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -128,15 +130,17 @@ module.exports = Self => {
|
|||
* @param {object} chat - The chat
|
||||
* @param {string} status - The new status
|
||||
* @param {string} error - The error
|
||||
* @param {object} options - Query options
|
||||
* @return {Promise} - The request promise
|
||||
*/
|
||||
async function updateChat(chat, status, error) {
|
||||
*/
|
||||
|
||||
Self.updateChat = async(chat, status, error) => {
|
||||
return chat.updateAttributes({
|
||||
status: status,
|
||||
attempts: ++chat.attempts,
|
||||
error: error
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the current user status on Rocketchat
|
||||
|
|
|
@ -10,7 +10,7 @@ describe('Chat sendCheckingPresence()', () => {
|
|||
|
||||
const chat = {
|
||||
checkUserStatus: 1,
|
||||
status: 0,
|
||||
status: 'pending',
|
||||
attempts: 0
|
||||
};
|
||||
|
||||
|
@ -27,7 +27,7 @@ describe('Chat sendCheckingPresence()', () => {
|
|||
|
||||
const chat = {
|
||||
checkUserStatus: 0,
|
||||
status: 0,
|
||||
status: 'pending',
|
||||
attempts: 0
|
||||
};
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
const {Report} = require('vn-print');
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('previousLabel', {
|
||||
description: 'Returns the previa label pdf',
|
||||
|
@ -33,17 +31,5 @@ module.exports = Self => {
|
|||
}
|
||||
});
|
||||
|
||||
Self.previousLabel = async(ctx, id) => {
|
||||
const args = Object.assign({}, ctx.args);
|
||||
const params = {lang: ctx.req.getLocale()};
|
||||
|
||||
delete args.ctx;
|
||||
for (const param in args)
|
||||
params[param] = args[param];
|
||||
|
||||
const report = new Report('previa-label', params);
|
||||
const stream = await report.toPdfStream();
|
||||
|
||||
return [stream, 'application/pdf', `filename="previa-${id}.pdf"`];
|
||||
};
|
||||
Self.previousLabel = (ctx, id) => Self.printReport(ctx, id, 'previa-label');
|
||||
};
|
||||
|
|
|
@ -1,6 +1,21 @@
|
|||
const models = require('vn-loopback/server/server').models;
|
||||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
describe('setSaleQuantity()', () => {
|
||||
beforeAll(async() => {
|
||||
const activeCtx = {
|
||||
accessToken: {userId: 9},
|
||||
http: {
|
||||
req: {
|
||||
headers: {origin: 'http://localhost'}
|
||||
}
|
||||
}
|
||||
};
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||
active: activeCtx
|
||||
});
|
||||
});
|
||||
|
||||
it('should change quantity sale', async() => {
|
||||
const tx = await models.Ticket.beginTransaction({});
|
||||
|
||||
|
|
|
@ -1,215 +0,0 @@
|
|||
const md5 = require('md5');
|
||||
const fs = require('fs-extra');
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('saveSign', {
|
||||
description: 'Save sign',
|
||||
accessType: 'WRITE',
|
||||
accepts:
|
||||
[
|
||||
{
|
||||
arg: 'signContent',
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'The sign content'
|
||||
}, {
|
||||
arg: 'tickets',
|
||||
type: ['number'],
|
||||
required: true,
|
||||
description: 'The tickets'
|
||||
}, {
|
||||
arg: 'signedTime',
|
||||
type: 'date',
|
||||
description: 'The signed time'
|
||||
}, {
|
||||
arg: 'addressFk',
|
||||
type: 'number',
|
||||
required: true,
|
||||
description: 'The address fk'
|
||||
}
|
||||
],
|
||||
returns: {
|
||||
type: 'Object',
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/saveSign`,
|
||||
verb: 'POST'
|
||||
}
|
||||
});
|
||||
|
||||
async function createGestDoc(ticketId, userFk) {
|
||||
const models = Self.app.models;
|
||||
if (!await gestDocExists(ticketId)) {
|
||||
const result = await models.Ticket.findOne({
|
||||
where: {
|
||||
id: ticketId
|
||||
},
|
||||
include: [
|
||||
{
|
||||
relation: 'warehouse',
|
||||
scope: {
|
||||
fields: ['id']
|
||||
}
|
||||
}, {
|
||||
relation: 'client',
|
||||
scope: {
|
||||
fields: ['name']
|
||||
}
|
||||
}, {
|
||||
relation: 'route',
|
||||
scope: {
|
||||
fields: ['id']
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
const warehouseFk = result.warehouseFk;
|
||||
const companyFk = result.companyFk;
|
||||
const client = result.client.name;
|
||||
const route = result.route.id;
|
||||
|
||||
const resultDmsType = await models.DmsType.findOne({
|
||||
where: {
|
||||
code: 'Ticket'
|
||||
}
|
||||
});
|
||||
|
||||
const resultDms = await models.Dms.create({
|
||||
dmsTypeFk: resultDmsType.id,
|
||||
reference: ticketId,
|
||||
description: `Ticket ${ticketId} Cliente ${client} Ruta ${route}`,
|
||||
companyFk: companyFk,
|
||||
warehouseFk: warehouseFk,
|
||||
workerFk: userFk
|
||||
});
|
||||
|
||||
return resultDms.insertId;
|
||||
}
|
||||
}
|
||||
|
||||
async function gestDocExists(ticket) {
|
||||
const models = Self.app.models;
|
||||
const result = await models.TicketDms.findOne({
|
||||
where: {
|
||||
ticketFk: ticket
|
||||
},
|
||||
fields: ['dmsFk']
|
||||
});
|
||||
|
||||
if (result == null)
|
||||
return false;
|
||||
|
||||
const isSigned = await models.Ticket.findOne({
|
||||
where: {
|
||||
id: ticket
|
||||
},
|
||||
fields: ['isSigned']
|
||||
});
|
||||
|
||||
if (isSigned)
|
||||
return true;
|
||||
else
|
||||
await models.Dms.destroyById(ticket);
|
||||
}
|
||||
|
||||
async function dmsRecover(ticket, signContent) {
|
||||
const models = Self.app.models;
|
||||
await models.DmsRecover.create({
|
||||
ticketFk: ticket,
|
||||
sign: signContent
|
||||
});
|
||||
}
|
||||
|
||||
async function ticketGestdoc(ticket, dmsFk) {
|
||||
const models = Self.app.models;
|
||||
models.TicketDms.replaceOrCreate({
|
||||
ticketFk: ticket,
|
||||
dmsFk: dmsFk
|
||||
});
|
||||
|
||||
const queryVnTicketSetState = `CALL vn.ticket_setState(?, ?)`;
|
||||
|
||||
await Self.rawSql(queryVnTicketSetState, [ticket, 'DELIVERED']);
|
||||
}
|
||||
|
||||
async function updateGestdoc(file, ticket) {
|
||||
const models = Self.app.models;
|
||||
models.Dms.updateOne({
|
||||
where: {
|
||||
id: ticket
|
||||
},
|
||||
file: file,
|
||||
contentType: 'image/png'
|
||||
});
|
||||
}
|
||||
|
||||
Self.saveSign = async(ctx, signContent, tickets, signedTime) => {
|
||||
const models = Self.app.models;
|
||||
let tx = await Self.beginTransaction({});
|
||||
try {
|
||||
const userId = ctx.req.accessToken.userId;
|
||||
|
||||
const dmsDir = `storage/dms`;
|
||||
|
||||
let image = null;
|
||||
|
||||
for (let i = 0; i < tickets.length; i++) {
|
||||
const alertLevel = await models.TicketState.findOne({
|
||||
where: {
|
||||
ticketFk: tickets[i]
|
||||
},
|
||||
fields: ['alertLevel']
|
||||
});
|
||||
|
||||
signedTime ? signedTime != undefined : signedTime = Date.vnNew();
|
||||
|
||||
if (alertLevel >= 2) {
|
||||
let dir;
|
||||
let id = null;
|
||||
let fileName = null;
|
||||
|
||||
if (!await gestDocExists(tickets[i])) {
|
||||
id = await createGestDoc(tickets[i], userId);
|
||||
|
||||
const hashDir = md5(id).substring(0, 3);
|
||||
dir = `${dmsDir}/${hashDir}`;
|
||||
|
||||
if (!fs.existsSync(dir))
|
||||
fs.mkdirSync(dir);
|
||||
|
||||
fileName = `${id}.png`;
|
||||
image = `${dir}/${fileName}`;
|
||||
} else
|
||||
|
||||
if (image != null) {
|
||||
if (!fs.existsSync(dir))
|
||||
dmsRecover(tickets[i], signContent);
|
||||
else {
|
||||
fs.writeFile(image, signContent, 'base64', async function(err) {
|
||||
if (err) {
|
||||
await tx.rollback();
|
||||
return err.message;
|
||||
}
|
||||
});
|
||||
}
|
||||
} else
|
||||
dmsRecover(tickets[i], signContent);
|
||||
|
||||
if (id != null && fileName.length > 0) {
|
||||
ticketGestdoc(tickets[i], id);
|
||||
updateGestdoc(id, fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tx) await tx.commit();
|
||||
|
||||
return 'OK';
|
||||
} catch (err) {
|
||||
await tx.rollback();
|
||||
throw err.message;
|
||||
}
|
||||
};
|
||||
};
|
|
@ -1,7 +1,6 @@
|
|||
const UserError = require('vn-loopback/util/user-error');
|
||||
const fs = require('fs-extra');
|
||||
const fs = require('fs/promises');
|
||||
const path = require('path');
|
||||
const uuid = require('uuid');
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('upload', {
|
||||
|
@ -36,7 +35,7 @@ module.exports = Self => {
|
|||
const fileOptions = {};
|
||||
const args = ctx.args;
|
||||
|
||||
let srcFile;
|
||||
let tempFilePath;
|
||||
try {
|
||||
const hasWriteRole = await models.ImageCollection.hasWriteRole(ctx, args.collection);
|
||||
if (!hasWriteRole)
|
||||
|
@ -53,15 +52,20 @@ module.exports = Self => {
|
|||
});
|
||||
|
||||
const file = await TempContainer.getFile(tempContainer.name, uploadedFile.name);
|
||||
srcFile = path.join(file.client.root, file.container, file.name);
|
||||
tempFilePath = path.join(file.client.root, file.container, file.name);
|
||||
|
||||
const fileName = `${uuid.v4()}.png`;
|
||||
await models.Image.registerImage(args.collection, srcFile, fileName, args.id);
|
||||
} catch (e) {
|
||||
if (fs.existsSync(srcFile))
|
||||
await fs.unlink(srcFile);
|
||||
const fileName = `${args.id}.png`;
|
||||
|
||||
throw e;
|
||||
await models.Image.resize({
|
||||
collectionName: args.collection,
|
||||
srcFile: tempFilePath,
|
||||
fileName: fileName,
|
||||
entityId: args.id
|
||||
});
|
||||
} finally {
|
||||
try {
|
||||
await fs.unlink(tempFilePath);
|
||||
} catch (error) { }
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -69,15 +69,15 @@ module.exports = Self => {
|
|||
|
||||
const result = response.headers.get('set-cookie');
|
||||
const [firtHeader] = result.split(' ');
|
||||
const firtCookie = firtHeader.substring(0, firtHeader.length - 1);
|
||||
const cookie = firtHeader.substring(0, firtHeader.length - 1);
|
||||
const body = await response.text();
|
||||
const dom = new jsdom.JSDOM(body);
|
||||
const token = dom.window.document.querySelector('[name="__CSRFToken__"]').value;
|
||||
|
||||
await login(token, firtCookie);
|
||||
await login(token, cookie);
|
||||
}
|
||||
|
||||
async function login(token, firtCookie) {
|
||||
async function login(token, cookie) {
|
||||
const data = {
|
||||
__CSRFToken__: token,
|
||||
do: 'scplogin',
|
||||
|
@ -90,21 +90,18 @@ module.exports = Self => {
|
|||
body: new URLSearchParams(data),
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
||||
'Cookie': firtCookie
|
||||
'Cookie': cookie
|
||||
}
|
||||
};
|
||||
const response = await fetch(ostUri, params);
|
||||
const result = response.headers.get('set-cookie');
|
||||
const [firtHeader] = result.split(' ');
|
||||
const secondCookie = firtHeader.substring(0, firtHeader.length - 1);
|
||||
await fetch(ostUri, params);
|
||||
|
||||
await close(token, secondCookie);
|
||||
await close(token, cookie);
|
||||
}
|
||||
|
||||
async function close(token, secondCookie) {
|
||||
async function close(token, cookie) {
|
||||
for (const ticketId of ticketsId) {
|
||||
try {
|
||||
const lock = await getLockCode(token, secondCookie, ticketId);
|
||||
const lock = await getLockCode(token, cookie, ticketId);
|
||||
if (!lock.code) {
|
||||
let error = `Can't get lock code`;
|
||||
if (lock.msg) error += `: ${lock.msg}`;
|
||||
|
@ -127,7 +124,7 @@ module.exports = Self => {
|
|||
method: 'POST',
|
||||
body: form,
|
||||
headers: {
|
||||
'Cookie': secondCookie
|
||||
'Cookie': cookie
|
||||
}
|
||||
};
|
||||
await fetch(ostUri, params);
|
||||
|
@ -139,13 +136,13 @@ module.exports = Self => {
|
|||
}
|
||||
}
|
||||
|
||||
async function getLockCode(token, secondCookie, ticketId) {
|
||||
async function getLockCode(token, cookie, ticketId) {
|
||||
const ostUri = `${config.host}/ajax.php/lock/ticket/${ticketId}`;
|
||||
const params = {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-CSRFToken': token,
|
||||
'Cookie': secondCookie
|
||||
'Cookie': cookie
|
||||
}
|
||||
};
|
||||
const response = await fetch(ostUri, params);
|
||||
|
|
|
@ -9,17 +9,29 @@
|
|||
"properties": {
|
||||
"id": {
|
||||
"id": true,
|
||||
"type": "number",
|
||||
"forceId": false
|
||||
"type": "number"
|
||||
},
|
||||
"date": {
|
||||
"created": {
|
||||
"type": "date"
|
||||
},
|
||||
"m3":{
|
||||
"longitude":{
|
||||
"type": "number"
|
||||
},
|
||||
"warehouseFk":{
|
||||
"latitude":{
|
||||
"type": "number"
|
||||
},
|
||||
"dated":{
|
||||
"type": "date"
|
||||
},
|
||||
"ticketFk":{
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"ticket": {
|
||||
"type": "belongsTo",
|
||||
"model": "Ticket",
|
||||
"foreignKey": "ticketFk"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ module.exports = Self => {
|
|||
require('../methods/dms/removeFile')(Self);
|
||||
require('../methods/dms/updateFile')(Self);
|
||||
require('../methods/dms/deleteTrashFiles')(Self);
|
||||
require('../methods/dms/saveSign')(Self);
|
||||
|
||||
Self.checkRole = async function(ctx, id) {
|
||||
const models = Self.app.models;
|
||||
|
|
|
@ -1,161 +1,110 @@
|
|||
const fs = require('fs-extra');
|
||||
const sharp = require('sharp');
|
||||
const path = require('path');
|
||||
const readChunk = require('read-chunk');
|
||||
const imageType = require('image-type');
|
||||
const bmp = require('bmp-js');
|
||||
const gm = require('gm');
|
||||
|
||||
module.exports = Self => {
|
||||
require('../methods/image/download')(Self);
|
||||
require('../methods/image/upload')(Self);
|
||||
|
||||
// Function extracted from jimp package (utils)
|
||||
function scan(image, x, y, w, h, f) {
|
||||
// round input
|
||||
x = Math.round(x);
|
||||
y = Math.round(y);
|
||||
w = Math.round(w);
|
||||
h = Math.round(h);
|
||||
|
||||
for (let _y = y; _y < y + h; _y++) {
|
||||
for (let _x = x; _x < x + w; _x++) {
|
||||
const idx = (image.bitmap.width * _y + _x) << 2;
|
||||
f.call(image, _x, _y, idx);
|
||||
}
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
// Function extracted from jimp package (type-bmp)
|
||||
function fromAGBR(bitmap) {
|
||||
return scan({bitmap}, 0, 0, bitmap.width, bitmap.height, function(
|
||||
x,
|
||||
y,
|
||||
index
|
||||
) {
|
||||
const alpha = this.bitmap.data[index + 0];
|
||||
const blue = this.bitmap.data[index + 1];
|
||||
const green = this.bitmap.data[index + 2];
|
||||
const red = this.bitmap.data[index + 3];
|
||||
|
||||
this.bitmap.data[index + 0] = red;
|
||||
this.bitmap.data[index + 1] = green;
|
||||
this.bitmap.data[index + 2] = blue;
|
||||
this.bitmap.data[index + 3] = bitmap.is_with_alpha ? alpha : 0xff;
|
||||
}).bitmap;
|
||||
}
|
||||
|
||||
Self.registerImage = async(collectionName, srcFilePath, fileName, entityId) => {
|
||||
Self.resize = async function({collectionName, srcFile, fileName, entityId}) {
|
||||
const models = Self.app.models;
|
||||
const tx = await Self.beginTransaction({});
|
||||
const myOptions = {transaction: tx};
|
||||
|
||||
try {
|
||||
const collection = await models.ImageCollection.findOne({
|
||||
const collection = await models.ImageCollection.findOne(
|
||||
{
|
||||
fields: [
|
||||
'id',
|
||||
'name',
|
||||
'maxWidth',
|
||||
'maxHeight',
|
||||
'model',
|
||||
'property'
|
||||
'property',
|
||||
],
|
||||
where: {name: collectionName},
|
||||
include: {
|
||||
relation: 'sizes',
|
||||
scope: {
|
||||
fields: ['width', 'height', 'crop']
|
||||
}
|
||||
}
|
||||
}, myOptions);
|
||||
fields: ['width', 'height', 'crop'],
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const data = {
|
||||
// Insert image row
|
||||
await models.Image.upsertWithWhere(
|
||||
{
|
||||
name: fileName,
|
||||
collectionFk: collectionName
|
||||
};
|
||||
const newImage = await Self.upsertWithWhere(data, {
|
||||
},
|
||||
{
|
||||
name: fileName,
|
||||
collectionFk: collectionName,
|
||||
updated: Date.vnNow()
|
||||
}, myOptions);
|
||||
|
||||
// Resizes and saves the image
|
||||
const container = await models.ImageContainer.container(collectionName);
|
||||
const rootPath = container.client.root;
|
||||
const collectionDir = path.join(rootPath, collectionName);
|
||||
const dstDir = path.join(collectionDir, 'full');
|
||||
const dstFile = path.join(dstDir, fileName);
|
||||
|
||||
const buffer = readChunk.sync(srcFilePath, 0, 12);
|
||||
const type = imageType(buffer);
|
||||
|
||||
let sharpOptions;
|
||||
let imgSrc = srcFilePath;
|
||||
if (type.mime == 'image/bmp') {
|
||||
const bmpBuffer = fs.readFileSync(srcFilePath);
|
||||
const bmpData = fromAGBR(bmp.decode(bmpBuffer));
|
||||
imgSrc = bmpData.data;
|
||||
sharpOptions = {
|
||||
raw: {
|
||||
width: bmpData.width,
|
||||
height: bmpData.height,
|
||||
channels: 4
|
||||
},
|
||||
failOn: 'none'
|
||||
};
|
||||
updated: Date.vnNow() / 1000,
|
||||
}
|
||||
);
|
||||
|
||||
const resizeOpts = {
|
||||
withoutEnlargement: true,
|
||||
fit: 'inside'
|
||||
};
|
||||
// Update entity image file name
|
||||
const model = models[collection.model];
|
||||
if (!model) throw new Error('No matching model found');
|
||||
|
||||
await fs.mkdir(dstDir, {recursive: true});
|
||||
await sharp(imgSrc, sharpOptions)
|
||||
.resize(collection.maxWidth, collection.maxHeight, resizeOpts)
|
||||
.png()
|
||||
.toFile(dstFile);
|
||||
const entity = await model.findById(entityId);
|
||||
if (entity) {
|
||||
await entity.updateAttribute(
|
||||
collection.property,
|
||||
fileName
|
||||
);
|
||||
}
|
||||
|
||||
const sizes = collection.sizes();
|
||||
for (let size of sizes) {
|
||||
const dstDir = path.join(collectionDir, `${size.width}x${size.height}`);
|
||||
const dstFile = path.join(dstDir, fileName);
|
||||
const resizeOpts = {
|
||||
withoutEnlargement: true,
|
||||
fit: size.crop ? 'cover' : 'inside'
|
||||
};
|
||||
// Resize
|
||||
const container = await models.ImageContainer.container(
|
||||
collectionName
|
||||
);
|
||||
const rootPath = container.client.root;
|
||||
const collectionDir = path.join(rootPath, collectionName);
|
||||
|
||||
await fs.mkdir(dstDir, {recursive: true});
|
||||
await sharp(imgSrc, sharpOptions)
|
||||
.resize(size.width, size.height, resizeOpts)
|
||||
.png()
|
||||
.toFile(dstFile);
|
||||
}
|
||||
// To max size
|
||||
const {maxWidth, maxHeight} = collection;
|
||||
const fullSizePath = path.join(collectionDir, 'full');
|
||||
const toFullSizePath = `${fullSizePath}/${fileName}`;
|
||||
|
||||
const model = models[collection.model];
|
||||
await fs.mkdir(fullSizePath, {recursive: true});
|
||||
await new Promise((resolve, reject) => {
|
||||
gm(srcFile)
|
||||
.resize(maxWidth, maxHeight, '>')
|
||||
.setFormat('png')
|
||||
.quality(100)
|
||||
.write(toFullSizePath, function(err) {
|
||||
if (err) reject(err);
|
||||
if (!err) resolve();
|
||||
});
|
||||
});
|
||||
|
||||
if (!model)
|
||||
throw new Error('Matching model not found');
|
||||
// To collection sizes
|
||||
for (const size of collection.sizes()) {
|
||||
const {width, height} = size;
|
||||
|
||||
const item = await model.findById(entityId, null, myOptions);
|
||||
if (item) {
|
||||
await item.updateAttribute(
|
||||
collection.property,
|
||||
fileName,
|
||||
myOptions
|
||||
);
|
||||
}
|
||||
const sizePath = path.join(collectionDir, `${width}x${height}`);
|
||||
const toSizePath = `${sizePath}/${fileName}`;
|
||||
|
||||
if (fs.existsSync(srcFilePath))
|
||||
await fs.unlink(srcFilePath);
|
||||
await fs.mkdir(sizePath, {recursive: true});
|
||||
await new Promise((resolve, reject) => {
|
||||
const gmInstance = gm(srcFile);
|
||||
|
||||
await tx.commit();
|
||||
if (size.crop) {
|
||||
gmInstance
|
||||
.resize(width, height, '^')
|
||||
.gravity('Center')
|
||||
.crop(width, height);
|
||||
}
|
||||
|
||||
return newImage;
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
throw e;
|
||||
if (!size.crop) gmInstance.resize(width, height, '>');
|
||||
|
||||
gmInstance
|
||||
.setFormat('png')
|
||||
.quality(100)
|
||||
.write(toSizePath, function(err) {
|
||||
if (err) reject(err);
|
||||
if (!err) resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
"options": {
|
||||
"mysql": {
|
||||
"table": "salix.User"
|
||||
}
|
||||
},
|
||||
"resetPasswordTokenTTL": "604800"
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE `vn`.`ticketConfig` ADD daysForWarningClaim INT DEFAULT 2 NOT NULL COMMENT 'dias restantes hasta que salte el aviso de reclamación fuerade plazo';
|
|
@ -0,0 +1,74 @@
|
|||
DROP TABLE `vn`.`dmsRecover`;
|
||||
|
||||
ALTER TABLE `vn`.`delivery` DROP FOREIGN KEY delivery_FK;
|
||||
ALTER TABLE `vn`.`delivery` DROP COLUMN addressFk;
|
||||
ALTER TABLE `vn`.`delivery` ADD ticketFk INT NOT NULL;
|
||||
ALTER TABLE `vn`.`delivery` ADD CONSTRAINT delivery_ticketFk_FK FOREIGN KEY (`ticketFk`) REFERENCES `vn`.`ticket`(`id`);
|
||||
|
||||
DELETE FROM `salix`.`ACL` WHERE `property` = 'saveSign';
|
||||
INSERT INTO `salix`.`ACL` (`model`,`property`,`accessType`,`permission`,`principalId`)
|
||||
VALUES
|
||||
('Ticket','saveSign','WRITE','ALLOW','employee');
|
||||
|
||||
DROP PROCEDURE IF EXISTS vn.route_getTickets;
|
||||
|
||||
DELIMITER $$
|
||||
$$
|
||||
CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`route_getTickets`(vRouteFk INT)
|
||||
BEGIN
|
||||
/**
|
||||
* Pasado un RouteFk devuelve la información
|
||||
* de sus tickets.
|
||||
*
|
||||
* @param vRouteFk
|
||||
*
|
||||
* @select Información de los tickets
|
||||
*/
|
||||
|
||||
SELECT
|
||||
t.id Id,
|
||||
t.clientFk Client,
|
||||
a.id Address,
|
||||
t.packages Packages,
|
||||
a.street AddressName,
|
||||
a.postalCode PostalCode,
|
||||
a.city City,
|
||||
sub2.itemPackingTypeFk PackingType,
|
||||
c.phone ClientPhone,
|
||||
c.mobile ClientMobile,
|
||||
a.phone AddressPhone,
|
||||
a.mobile AddressMobile,
|
||||
d.longitude Longitude,
|
||||
d.latitude Latitude,
|
||||
wm.mediaValue SalePersonPhone,
|
||||
tob.Note Note,
|
||||
t.isSigned Signed
|
||||
FROM ticket t
|
||||
JOIN client c ON t.clientFk = c.id
|
||||
JOIN address a ON t.addressFk = a.id
|
||||
LEFT JOIN delivery d ON t.id = d.ticketFk
|
||||
LEFT JOIN workerMedia wm ON wm.workerFk = c.salesPersonFk
|
||||
LEFT JOIN
|
||||
(SELECT tob.description Note, t.id
|
||||
FROM ticketObservation tob
|
||||
JOIN ticket t ON tob.ticketFk = t.id
|
||||
JOIN observationType ot ON ot.id = tob.observationTypeFk
|
||||
WHERE t.routeFk = vRouteFk
|
||||
AND ot.code = 'delivery'
|
||||
)tob ON tob.id = t.id
|
||||
LEFT JOIN
|
||||
(SELECT sub.ticketFk,
|
||||
CONCAT('(', GROUP_CONCAT(DISTINCT sub.itemPackingTypeFk ORDER BY sub.items DESC SEPARATOR ','), ') ') itemPackingTypeFk
|
||||
FROM (SELECT s.ticketFk , i.itemPackingTypeFk, COUNT(*) items
|
||||
FROM ticket t
|
||||
JOIN sale s ON s.ticketFk = t.id
|
||||
JOIN item i ON i.id = s.itemFk
|
||||
WHERE t.routeFk = vRouteFk
|
||||
GROUP BY t.id,i.itemPackingTypeFk)sub
|
||||
GROUP BY sub.ticketFk
|
||||
) sub2 ON sub2.ticketFk = t.id
|
||||
WHERE t.routeFk = vRouteFk
|
||||
GROUP BY t.id
|
||||
ORDER BY t.priority;
|
||||
END$$
|
||||
DELIMITER ;
|
|
@ -1,9 +0,0 @@
|
|||
-- Auto-generated SQL script #202303291013
|
||||
INSERT INTO vn.companyI18n (companyFk,lang,footnotes)
|
||||
VALUES (442,'en','In compliance with the provisions of Organic Law 15/1999, on the Protection of Personal Data, we inform you that the personal data you provide will be included in automated files of VERDNATURA LEVANTE SL, being able at all times to exercise the rights of access, rectification, cancellation and opposition, communicating it in writing to the registered office of the entity. The purpose of the file is administrative management, accounting, and billing.');
|
||||
INSERT INTO vn.companyI18n (companyFk,lang,footnotes)
|
||||
VALUES (442,'es','En cumplimiento de lo dispuesto en la Ley Orgánica 15/1999, de Protección de Datos de Carácter Personal, le comunicamos que los datos personales que facilite se incluirán en ficheros automatizados de VERDNATURA LEVANTE S.L., pudiendo en todo momento ejercitar los derechos de acceso, rectificación, cancelación y oposición, comunicándolo por escrito al domicilio social de la entidad. La finalidad del fichero es la gestión administrativa, contabilidad, y facturación.');
|
||||
INSERT INTO vn.companyI18n (companyFk,lang,footnotes)
|
||||
VALUES (442,'fr','Conformément aux dispositions de la loi organique 15/1999 sur la protection des données personnelles, nous vous informons que les données personnelles que vous fournissez seront incluses dans des dossiers. VERDNATURA LEVANTE S.L., vous pouvez à tout moment, exercer les droits d``accès, de rectification, d``annulation et d``opposition, en communiquant par écrit au siège social de la société. Le dossier a pour objet la gestion administrative, la comptabilité et la facturation.');
|
||||
INSERT INTO vn.companyI18n (companyFk,lang,footnotes)
|
||||
VALUES (442,'pt','Em cumprimento do disposto na lei Orgânica 15/1999, de Protecção de Dados de Carácter Pessoal, comunicamos que os dados pessoais que facilite se incluirão nos ficheiros automatizados de VERDNATURA LEVANTE S.L., podendo em todo momento exercer os direitos de acesso, rectificação, cancelação e oposição, comunicando por escrito ao domicílio social da entidade. A finalidade do ficheiro é a gestão administrativa, contabilidade e facturação.');
|
|
@ -0,0 +1,6 @@
|
|||
ALTER TABLE vn.invoiceOutSerial
|
||||
ADD `type` ENUM('global', 'quick') DEFAULT NULL NULL;
|
||||
|
||||
UPDATE vn.invoiceOutSerial
|
||||
SET type = 'global'
|
||||
WHERE code IN ('A','V');
|
|
@ -2,13 +2,15 @@ DROP FUNCTION IF EXISTS `vn`.`invoiceOut_getWeight`;
|
|||
|
||||
DELIMITER $$
|
||||
$$
|
||||
CREATE DEFINER=`root`@`localhost` FUNCTION `vn`.`invoiceOut_getWeight`(vInvoice VARCHAR(15)) RETURNS decimal(10,2)
|
||||
CREATE DEFINER=`root`@`localhost` FUNCTION `vn`.`invoiceOut_getWeight`(
|
||||
vInvoiceRef VARCHAR(15)
|
||||
)RETURNS decimal(10,2)
|
||||
READS SQL DATA
|
||||
BEGIN
|
||||
/**
|
||||
* Calcula el peso de una factura emitida
|
||||
*
|
||||
* @param vInvoice Id de la factura
|
||||
* @param vInvoiceRef referencia de la factura
|
||||
* @return vTotalWeight peso de la factura
|
||||
*/
|
||||
DECLARE vTotalWeight DECIMAL(10,2);
|
||||
|
@ -22,7 +24,7 @@ BEGIN
|
|||
JOIN item i ON i.id = s.itemFk
|
||||
JOIN itemCost ic ON ic.itemFk = i.id
|
||||
AND ic.warehouseFk = t.warehouseFk
|
||||
WHERE t.refFk = vInvoice
|
||||
WHERE t.refFk = vInvoiceRef
|
||||
AND i.intrastatFk;
|
||||
|
||||
RETURN vTotalWeight;
|
|
@ -0,0 +1,6 @@
|
|||
UPDATE `vn`.`report`
|
||||
SET `method`='InvoiceOuts/{refFk}/invoice-out-pdf'
|
||||
WHERE name='invoice';
|
||||
|
||||
ALTER TABLE `vn`.`printQueue` MODIFY COLUMN printerFk tinyint(3) unsigned DEFAULT 82 NOT NULL;
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
DROP FUNCTION IF EXISTS `vn`.`invoiceOut_getMaxIssued`;
|
||||
|
||||
DELIMITER $$
|
||||
$$
|
||||
CREATE OR REPLACE DEFINER=`root`@`localhost` FUNCTION `vn`.`invoiceOut_getMaxIssued`(
|
||||
vSerial VARCHAR(2),
|
||||
vCompanyFk INT,
|
||||
vYear INT
|
||||
) RETURNS DATE
|
||||
READS SQL DATA
|
||||
BEGIN
|
||||
/**
|
||||
* Retorna la fecha a partir de la cual es válido emitir una factura
|
||||
*
|
||||
* @param vSerial Serie de facturación
|
||||
* @param vCompanyFk Empresa factura emitida
|
||||
* @param vYear Año contable
|
||||
* @return vInvoiceOutIssued fecha factura válida
|
||||
*/
|
||||
DECLARE vInvoiceOutIssued DATE;
|
||||
DECLARE vFirstDayOfYear DATE;
|
||||
|
||||
SET vFirstDayOfYear := MAKEDATE(vYear, 1);
|
||||
|
||||
SELECT IFNULL(MAX(io.issued), vFirstDayOfYear) INTO vInvoiceOutIssued
|
||||
FROM invoiceOut io
|
||||
WHERE io.serial = vSerial
|
||||
AND io.companyFk = vCompanyFk
|
||||
AND io.issued BETWEEN vFirstDayOfYear
|
||||
AND util.lastDayOfYear(vFirstDayOfYear);
|
||||
|
||||
RETURN vInvoiceOutIssued;
|
||||
END$$
|
||||
DELIMITER ;
|
|
@ -0,0 +1,258 @@
|
|||
DROP PROCEDURE IF EXISTS `vn`.`invoiceOut_new`;
|
||||
|
||||
DELIMITER $$
|
||||
$$
|
||||
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`invoiceOut_new`(
|
||||
vSerial VARCHAR(255),
|
||||
vInvoiceDate DATE,
|
||||
vTaxArea VARCHAR(25),
|
||||
OUT vNewInvoiceId INT)
|
||||
BEGIN
|
||||
/**
|
||||
* Creación de facturas emitidas.
|
||||
* requiere previamente tabla ticketToInvoice(id).
|
||||
*
|
||||
* @param vSerial serie a la cual se hace la factura
|
||||
* @param vInvoiceDate fecha de la factura
|
||||
* @param vTaxArea tipo de iva en relacion a la empresa y al cliente
|
||||
* @param vNewInvoiceId id de la factura que se acaba de generar
|
||||
* @return vNewInvoiceId
|
||||
*/
|
||||
DECLARE vIsAnySaleToInvoice BOOL;
|
||||
DECLARE vIsAnyServiceToInvoice BOOL;
|
||||
DECLARE vNewRef VARCHAR(255);
|
||||
DECLARE vWorker INT DEFAULT account.myUser_getId();
|
||||
DECLARE vCompanyFk INT;
|
||||
DECLARE vInterCompanyFk INT;
|
||||
DECLARE vClientFk INT;
|
||||
DECLARE vCplusStandardInvoiceTypeFk INT DEFAULT 1;
|
||||
DECLARE vCplusCorrectingInvoiceTypeFk INT DEFAULT 6;
|
||||
DECLARE vCplusSimplifiedInvoiceTypeFk INT DEFAULT 2;
|
||||
DECLARE vCorrectingSerial VARCHAR(1) DEFAULT 'R';
|
||||
DECLARE vSimplifiedSerial VARCHAR(1) DEFAULT 'S';
|
||||
DECLARE vNewInvoiceInFk INT;
|
||||
DECLARE vIsInterCompany BOOL DEFAULT FALSE;
|
||||
DECLARE vIsCEESerial BOOL DEFAULT FALSE;
|
||||
DECLARE vIsCorrectInvoiceDate BOOL;
|
||||
DECLARE vMaxShipped DATE;
|
||||
|
||||
SET vInvoiceDate = IFNULL(vInvoiceDate, util.CURDATE());
|
||||
|
||||
SELECT t.clientFk,
|
||||
t.companyFk,
|
||||
MAX(DATE(t.shipped)),
|
||||
DATE(vInvoiceDate) >= invoiceOut_getMaxIssued(
|
||||
vSerial,
|
||||
t.companyFk,
|
||||
YEAR(vInvoiceDate))
|
||||
INTO vClientFk,
|
||||
vCompanyFk,
|
||||
vMaxShipped,
|
||||
vIsCorrectInvoiceDate
|
||||
FROM ticketToInvoice tt
|
||||
JOIN ticket t ON t.id = tt.id;
|
||||
|
||||
IF(vMaxShipped > vInvoiceDate) THEN
|
||||
CALL util.throw("Invoice date can't be less than max date");
|
||||
END IF;
|
||||
|
||||
IF NOT vIsCorrectInvoiceDate THEN
|
||||
CALL util.throw('Exists an invoice with a previous date');
|
||||
END IF;
|
||||
|
||||
-- Eliminem de ticketToInvoice els tickets que no han de ser facturats
|
||||
DELETE ti.*
|
||||
FROM ticketToInvoice ti
|
||||
JOIN ticket t ON t.id = ti.id
|
||||
JOIN sale s ON s.ticketFk = t.id
|
||||
JOIN item i ON i.id = s.itemFk
|
||||
JOIN supplier su ON su.id = t.companyFk
|
||||
JOIN client c ON c.id = t.clientFk
|
||||
LEFT JOIN itemTaxCountry itc ON itc.itemFk = i.id AND itc.countryFk = su.countryFk
|
||||
WHERE (YEAR(t.shipped) < 2001 AND t.isDeleted)
|
||||
OR c.isTaxDataChecked = FALSE
|
||||
OR t.isDeleted
|
||||
OR c.hasToInvoice = FALSE
|
||||
OR itc.id IS NULL;
|
||||
|
||||
SELECT SUM(s.quantity * s.price * (100 - s.discount)/100) <> 0
|
||||
INTO vIsAnySaleToInvoice
|
||||
FROM ticketToInvoice t
|
||||
JOIN sale s ON s.ticketFk = t.id;
|
||||
|
||||
SELECT COUNT(*) > 0 INTO vIsAnyServiceToInvoice
|
||||
FROM ticketToInvoice t
|
||||
JOIN ticketService ts ON ts.ticketFk = t.id;
|
||||
|
||||
IF (vIsAnySaleToInvoice OR vIsAnyServiceToInvoice)
|
||||
AND (vCorrectingSerial = vSerial OR NOT hasAnyNegativeBase())
|
||||
THEN
|
||||
|
||||
-- el trigger añade el siguiente Id_Factura correspondiente a la vSerial
|
||||
INSERT INTO invoiceOut(
|
||||
ref,
|
||||
serial,
|
||||
issued,
|
||||
clientFk,
|
||||
dued,
|
||||
companyFk,
|
||||
cplusInvoiceType477Fk
|
||||
)
|
||||
SELECT
|
||||
1,
|
||||
vSerial,
|
||||
vInvoiceDate,
|
||||
vClientFk,
|
||||
getDueDate(vInvoiceDate, dueDay),
|
||||
vCompanyFk,
|
||||
IF(vSerial = vCorrectingSerial,
|
||||
vCplusCorrectingInvoiceTypeFk,
|
||||
IF(vSerial = vSimplifiedSerial,
|
||||
vCplusSimplifiedInvoiceTypeFk,
|
||||
vCplusStandardInvoiceTypeFk))
|
||||
FROM client
|
||||
WHERE id = vClientFk;
|
||||
|
||||
SET vNewInvoiceId = LAST_INSERT_ID();
|
||||
|
||||
SELECT `ref`
|
||||
INTO vNewRef
|
||||
FROM invoiceOut
|
||||
WHERE id = vNewInvoiceId;
|
||||
|
||||
UPDATE ticket t
|
||||
JOIN ticketToInvoice ti ON ti.id = t.id
|
||||
SET t.refFk = vNewRef;
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.updateInter;
|
||||
CREATE TEMPORARY TABLE tmp.updateInter ENGINE = MEMORY
|
||||
SELECT s.id,ti.id ticket_id,vWorker Id_Trabajador
|
||||
FROM ticketToInvoice ti
|
||||
LEFT JOIN ticketState ts ON ti.id = ts.ticket
|
||||
JOIN state s
|
||||
WHERE IFNULL(ts.alertLevel,0) < 3 and s.`code` = getAlert3State(ti.id);
|
||||
|
||||
INSERT INTO ticketTracking(stateFk,ticketFk,workerFk)
|
||||
SELECT * FROM tmp.updateInter;
|
||||
|
||||
INSERT INTO ticketLog (action, userFk, originFk, description)
|
||||
SELECT 'UPDATE', account.myUser_getId(), ti.id, CONCAT('Crea factura ', vNewRef)
|
||||
FROM ticketToInvoice ti;
|
||||
|
||||
CALL invoiceExpenceMake(vNewInvoiceId);
|
||||
CALL invoiceTaxMake(vNewInvoiceId,vTaxArea);
|
||||
|
||||
UPDATE invoiceOut io
|
||||
JOIN (
|
||||
SELECT SUM(amount) total
|
||||
FROM invoiceOutExpence
|
||||
WHERE invoiceOutFk = vNewInvoiceId
|
||||
) base
|
||||
JOIN (
|
||||
SELECT SUM(vat) total
|
||||
FROM invoiceOutTax
|
||||
WHERE invoiceOutFk = vNewInvoiceId
|
||||
) vat
|
||||
SET io.amount = base.total + vat.total
|
||||
WHERE io.id = vNewInvoiceId;
|
||||
|
||||
DROP TEMPORARY TABLE tmp.updateInter;
|
||||
|
||||
SELECT COUNT(*), id
|
||||
INTO vIsInterCompany, vInterCompanyFk
|
||||
FROM company
|
||||
WHERE clientFk = vClientFk;
|
||||
|
||||
IF (vIsInterCompany) THEN
|
||||
|
||||
INSERT INTO invoiceIn(supplierFk, supplierRef, issued, companyFk)
|
||||
SELECT vCompanyFk, vNewRef, vInvoiceDate, vInterCompanyFk;
|
||||
|
||||
SET vNewInvoiceInFk = LAST_INSERT_ID();
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.ticket;
|
||||
CREATE TEMPORARY TABLE tmp.ticket
|
||||
(KEY (ticketFk))
|
||||
ENGINE = MEMORY
|
||||
SELECT id ticketFk
|
||||
FROM ticketToInvoice;
|
||||
|
||||
CALL `ticket_getTax`('NATIONAL');
|
||||
|
||||
SET @vTaxableBaseServices := 0.00;
|
||||
SET @vTaxCodeGeneral := NULL;
|
||||
|
||||
INSERT INTO invoiceInTax(invoiceInFk, taxableBase, expenceFk, taxTypeSageFk, transactionTypeSageFk)
|
||||
SELECT vNewInvoiceInFk,
|
||||
@vTaxableBaseServices,
|
||||
sub.expenceFk,
|
||||
sub.taxTypeSageFk,
|
||||
sub.transactionTypeSageFk
|
||||
FROM (
|
||||
SELECT @vTaxableBaseServices := SUM(tst.taxableBase) taxableBase,
|
||||
i.expenceFk,
|
||||
i.taxTypeSageFk,
|
||||
i.transactionTypeSageFk,
|
||||
@vTaxCodeGeneral := i.taxClassCodeFk
|
||||
FROM tmp.ticketServiceTax tst
|
||||
JOIN invoiceOutTaxConfig i ON i.taxClassCodeFk = tst.code
|
||||
WHERE i.isService
|
||||
HAVING taxableBase
|
||||
) sub;
|
||||
|
||||
INSERT INTO invoiceInTax(invoiceInFk, taxableBase, expenceFk, taxTypeSageFk, transactionTypeSageFk)
|
||||
SELECT vNewInvoiceInFk,
|
||||
SUM(tt.taxableBase) - IF(tt.code = @vTaxCodeGeneral,
|
||||
@vTaxableBaseServices, 0) taxableBase,
|
||||
i.expenceFk,
|
||||
i.taxTypeSageFk ,
|
||||
i.transactionTypeSageFk
|
||||
FROM tmp.ticketTax tt
|
||||
JOIN invoiceOutTaxConfig i ON i.taxClassCodeFk = tt.code
|
||||
WHERE !i.isService
|
||||
GROUP BY tt.pgcFk
|
||||
HAVING taxableBase
|
||||
ORDER BY tt.priority;
|
||||
|
||||
CALL invoiceInDueDay_calculate(vNewInvoiceInFk);
|
||||
|
||||
SELECT COUNT(*) INTO vIsCEESerial
|
||||
FROM invoiceOutSerial
|
||||
WHERE code = vSerial;
|
||||
|
||||
IF vIsCEESerial THEN
|
||||
|
||||
INSERT INTO invoiceInIntrastat (
|
||||
invoiceInFk,
|
||||
intrastatFk,
|
||||
amount,
|
||||
stems,
|
||||
countryFk,
|
||||
net)
|
||||
SELECT
|
||||
vNewInvoiceInFk,
|
||||
i.intrastatFk,
|
||||
SUM(CAST((s.quantity * s.price * (100 - s.discount) / 100 ) AS DECIMAL(10, 2))),
|
||||
SUM(CAST(IFNULL(i.stems, 1) * s.quantity AS DECIMAL(10, 2))),
|
||||
su.countryFk,
|
||||
CAST(SUM(IFNULL(i.stems, 1)
|
||||
* s.quantity
|
||||
* IF(ic.grams, ic.grams, IFNULL(i.weightByPiece, 0)) / 1000) AS DECIMAL(10, 2))
|
||||
FROM sale s
|
||||
JOIN ticket t ON s.ticketFk = t.id
|
||||
JOIN supplier su ON su.id = t.companyFk
|
||||
JOIN item i ON i.id = s.itemFk
|
||||
LEFT JOIN itemCost ic ON ic.itemFk = i.id AND ic.warehouseFk = t.warehouseFk
|
||||
WHERE t.refFk = vNewRef
|
||||
GROUP BY i.intrastatFk;
|
||||
|
||||
END IF;
|
||||
DROP TEMPORARY TABLE tmp.ticket;
|
||||
DROP TEMPORARY TABLE tmp.ticketAmount;
|
||||
DROP TEMPORARY TABLE tmp.ticketTax;
|
||||
DROP TEMPORARY TABLE tmp.ticketServiceTax;
|
||||
END IF;
|
||||
END IF;
|
||||
DROP TEMPORARY TABLE `ticketToInvoice`;
|
||||
END$$
|
||||
DELIMITER ;
|
|
@ -0,0 +1,141 @@
|
|||
DROP PROCEDURE IF EXISTS `vn`.`ticketPackaging_add`;
|
||||
|
||||
DELIMITER $$
|
||||
$$
|
||||
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticketPackaging_add`(
|
||||
vClientFk INT,
|
||||
vDated DATE,
|
||||
vCompanyFk INT,
|
||||
vWithoutPeriodGrace BOOLEAN)
|
||||
BEGIN
|
||||
/**
|
||||
* Genera nuevos tickets de embalajes para los clientes no han los han retornado
|
||||
* y actualiza los valores para la tabla ticketPackaging
|
||||
*
|
||||
* @param vClientFk Cliente en caso de NULL todos los clientes
|
||||
* @param vDated Fecha hasta la cual se revisan los embalajes
|
||||
* @param vCompanyFk Empresa de la cual se comprobaran sus clientes
|
||||
* @param vWithoutPeriodGrace si no se aplica el periodo de gracia de un mes
|
||||
*/
|
||||
DECLARE vNewTicket INT;
|
||||
DECLARE vDateStart DATE;
|
||||
DECLARE vDateEnd DATE;
|
||||
DECLARE vGraceDate DATE DEFAULT vDated;
|
||||
DECLARE vWarehouseInventory INT;
|
||||
DECLARE vComponentCost INT;
|
||||
DECLARE vDone INT DEFAULT FALSE;
|
||||
DECLARE vClientId INT;
|
||||
|
||||
DECLARE vCursor CURSOR FOR
|
||||
SELECT DISTINCT clientFk
|
||||
FROM (
|
||||
SELECT clientFk, SUM(quantity) totalQuantity
|
||||
FROM tmp.packagingToInvoice
|
||||
GROUP BY itemFk, clientFk
|
||||
HAVING totalQuantity > 0)sub;
|
||||
|
||||
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE;
|
||||
|
||||
DECLARE EXIT HANDLER FOR SQLEXCEPTION
|
||||
BEGIN
|
||||
ROLLBACK;
|
||||
RESIGNAL;
|
||||
END;
|
||||
|
||||
SELECT id INTO vWarehouseInventory
|
||||
FROM warehouse
|
||||
WHERE `code`= 'inv';
|
||||
|
||||
SELECT id INTO vComponentCost
|
||||
FROM component
|
||||
WHERE `code`= 'purchaseValue';
|
||||
|
||||
SELECT packagingInvoicingDated INTO vDateStart
|
||||
FROM ticketConfig;
|
||||
|
||||
IF vWarehouseInventory IS NULL THEN
|
||||
CALL util.throw('Warehouse inventory not set');
|
||||
END IF;
|
||||
|
||||
IF vComponentCost IS NULL THEN
|
||||
CALL util.throw('Component cost not set');
|
||||
END IF;
|
||||
|
||||
SET vDateEnd = vDated + INTERVAL 1 DAY;
|
||||
|
||||
IF NOT vWithoutPeriodGrace THEN
|
||||
SET vGraceDate = vGraceDate -INTERVAL 1 MONTH;
|
||||
END IF;
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.packagingToInvoice;
|
||||
CREATE TEMPORARY TABLE tmp.packagingToInvoice
|
||||
(INDEX (clientFk))
|
||||
ENGINE = MEMORY
|
||||
SELECT p.itemFk,
|
||||
tp.packagingFk,
|
||||
tp.quantity,
|
||||
tp.ticketFk,
|
||||
p.price,
|
||||
t.clientFk
|
||||
FROM ticketPackaging tp
|
||||
JOIN packaging p ON p.id = tp.packagingFk
|
||||
JOIN ticket t ON t.id = tp.ticketFk
|
||||
JOIN client c ON c.id = t.clientFk
|
||||
WHERE c.isActive
|
||||
AND (vClientFk IS NULL OR t.clientFk = vClientFk)
|
||||
AND t.shipped BETWEEN vDateStart AND vDateEnd
|
||||
AND (tp.quantity < 0 OR (tp.quantity > 0 AND t.shipped < vGraceDate))
|
||||
AND tp.quantity
|
||||
AND p.itemFk;
|
||||
|
||||
OPEN vCursor;
|
||||
l: LOOP
|
||||
|
||||
FETCH vCursor INTO vClientId;
|
||||
|
||||
IF vDone THEN
|
||||
LEAVE l;
|
||||
END IF;
|
||||
|
||||
START TRANSACTION;
|
||||
|
||||
CALL ticket_add(
|
||||
vClientId,
|
||||
vDateEnd,
|
||||
vWarehouseInventory,
|
||||
vCompanyFk,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
vDateEnd,
|
||||
account.myUser_getId(),
|
||||
TRUE,
|
||||
vNewTicket);
|
||||
|
||||
INSERT INTO ticketPackaging(ticketFk, packagingFk, quantity, pvp)
|
||||
SELECT vNewTicket, packagingFk, - SUM(quantity) totalQuantity, price
|
||||
FROM tmp.packagingToInvoice
|
||||
WHERE clientFk = vClientId
|
||||
GROUP BY packagingFk
|
||||
HAVING IF(vWithoutPeriodGrace, totalQuantity <> 0, totalQuantity < 0);
|
||||
|
||||
INSERT INTO sale(ticketFk, itemFk, concept, quantity, price)
|
||||
SELECT vNewTicket, pti.itemFk, i.name, SUM(pti.quantity) totalQuantity, pti.price
|
||||
FROM tmp.packagingToInvoice pti
|
||||
JOIN item i ON i.id = pti.itemFk
|
||||
WHERE pti.clientFk = vClientId
|
||||
GROUP BY pti.itemFk
|
||||
HAVING IF(vWithoutPeriodGrace, totalQuantity <> 0, totalQuantity > 0);
|
||||
|
||||
INSERT INTO saleComponent(saleFk, componentFk, value)
|
||||
SELECT id, vComponentCost, price
|
||||
FROM sale
|
||||
WHERE ticketFk = vNewTicket;
|
||||
|
||||
COMMIT;
|
||||
END LOOP;
|
||||
CLOSE vCursor;
|
||||
|
||||
DROP TEMPORARY TABLE tmp.packagingToInvoice;
|
||||
END$$
|
||||
DELIMITER ;
|
|
@ -0,0 +1,3 @@
|
|||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||
VALUES ('Operator', '*', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||
('Operator', '*', 'WRITE', 'ALLOW', 'ROLE', 'employee');
|
|
@ -0,0 +1,16 @@
|
|||
ALTER TABLE `vn`.`chat` ADD statusNew enum('pending','sent','error','sending') DEFAULT 'pending' NOT NULL;
|
||||
|
||||
UPDATE `vn`.`chat`
|
||||
SET statusNew = 'pending'
|
||||
WHERE status = 0;
|
||||
|
||||
UPDATE `vn`.`chat`
|
||||
SET statusNew = 'sent'
|
||||
WHERE status = 1;
|
||||
|
||||
UPDATE `vn`.`chat`
|
||||
SET statusNew = 'error'
|
||||
WHERE status = 2;
|
||||
|
||||
ALTER TABLE `vn`.`chat` CHANGE status status__ tinyint(1) DEFAULT NULL NULL;
|
||||
ALTER TABLE `vn`.`chat` CHANGE statusNew status enum('pending','sent','error','sending') CHARACTER SET utf8mb3 COLLATE utf8mb3_unicode_ci DEFAULT 'pending' NOT NULL;
|
|
@ -0,0 +1,4 @@
|
|||
ALTER TABLE `vn`.`invoiceInConfig` ADD daysAgo INT UNSIGNED DEFAULT 45 COMMENT 'Días en el pasado para mostrar facturas en invoiceIn series en salix';
|
||||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||
VALUES
|
||||
('InvoiceIn', 'getSerial', 'READ', 'ALLOW', 'ROLE', 'administrative');
|
|
@ -0,0 +1,14 @@
|
|||
ALTER TABLE `vn`.`itemType` ADD isFragile tinyint(1) NULL;
|
||||
ALTER TABLE `vn`.`itemType` MODIFY COLUMN isFragile tinyint(1) DEFAULT 0 NOT NULL;
|
||||
|
||||
UPDATE `vn`.`itemType`
|
||||
SET isFragile = 1
|
||||
WHERE code IN ('ZKA', 'ZKE');
|
||||
|
||||
UPDATE `vn`.`itemType`
|
||||
SET isFragile = 1
|
||||
WHERE id IN (SELECT it.id
|
||||
FROM `vn`.`itemCategory` ic
|
||||
JOIN `vn`.`itemType` it ON it.categoryFk = ic.id
|
||||
WHERE ic.code = 'plant');
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
INSERT INTO `salix`.`ACL` ( model, property, accessType, permission, principalType, principalId)
|
||||
VALUES('Mail', '*', '*', 'ALLOW', 'ROLE', 'employee');
|
|
@ -0,0 +1,159 @@
|
|||
ALTER TABLE `vn`.`operator` ADD sectorFk int(11) NULL;
|
||||
ALTER TABLE `vn`.`operator` ADD labelerFk tinyint(3) unsigned NULL;
|
||||
ALTER TABLE `vn`.`operator` ADD CONSTRAINT operator_FK_5 FOREIGN KEY (labelerFk) REFERENCES `vn`.`printer`(id) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
UPDATE `vn`.`operator` o
|
||||
JOIN (SELECT id, sectorFk, labelerFk
|
||||
FROM `vn`.`worker`) sub ON sub.id = o.workerFk
|
||||
SET o.sectorFk = sub.sectorFk,
|
||||
o.labelerFk = sub.labelerFk;
|
||||
|
||||
DELIMITER $$
|
||||
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`collection_printSticker`(
|
||||
vSelf INT,
|
||||
vLabelCount INT
|
||||
)
|
||||
BEGIN
|
||||
/**
|
||||
* Prints a yellow label from a collection or a ticket
|
||||
*
|
||||
* @param vSelf collection or ticket
|
||||
* @param vLabelCount number of times the collection has been printed
|
||||
*/
|
||||
DECLARE vPrintArgs JSON DEFAULT JSON_OBJECT('collectionOrTicketFk', vSelf);
|
||||
|
||||
IF vLabelCount IS NULL THEN
|
||||
INSERT INTO ticketTrolley
|
||||
SELECT ticketFk, 1
|
||||
FROM ticketCollection
|
||||
WHERE collectionFk = vSelf
|
||||
ON DUPLICATE KEY UPDATE labelCount = labelCount + 1;
|
||||
ELSE
|
||||
SET vPrintArgs = JSON_MERGE_PATCH(vPrintArgs, JSON_OBJECT('labelCount', vLabelCount));
|
||||
END IF;
|
||||
|
||||
CALL report_print(
|
||||
'LabelCollection',
|
||||
(SELECT o.labelerFk FROM operator o WHERE o.workerFk = account.myUser_getId()),
|
||||
account.myUser_getId(),
|
||||
vPrintArgs,
|
||||
'high'
|
||||
);
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
DELIMITER $$
|
||||
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`expeditionPallet_printLabel`(vSelf INT)
|
||||
BEGIN
|
||||
/**
|
||||
* Calls the report_print procedure and passes it
|
||||
* the necessary parameters for printing.
|
||||
*
|
||||
* @param vSelf expeditioPallet id.
|
||||
*/
|
||||
DECLARE vPrinterFk INT;
|
||||
DECLARE vUserFk INT DEFAULT account.myUser_getId();
|
||||
|
||||
SELECT o.labelerFk INTO vPrinterFk
|
||||
FROM operator o
|
||||
WHERE o.workerFk = vUserFk;
|
||||
|
||||
CALL vn.report_print(
|
||||
'LabelPalletExpedition',
|
||||
vPrinterFk,
|
||||
account.myUser_getId(),
|
||||
JSON_OBJECT('palletFk', vSelf, 'userFk', vUserFk),
|
||||
'high'
|
||||
);
|
||||
|
||||
UPDATE vn.expeditionPallet
|
||||
SET isPrint = TRUE
|
||||
WHERE id = vSelf;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
DELIMITER $$
|
||||
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`itemShelving_getAlternatives`(vShelvingFk VARCHAR(10))
|
||||
BEGIN
|
||||
/**
|
||||
* Devuelve un listado de posibles ubicaciones alternativas a ubicar los item de la matricula
|
||||
* del carro que se le ha pasado.
|
||||
*
|
||||
* @param vShelvingFk matricula del carro
|
||||
*/
|
||||
SELECT is2.id,is2.shelvingFk , p.code, is2.itemFk , is2.visible, p.pickingOrder
|
||||
FROM itemShelving is2
|
||||
JOIN shelving sh ON sh.code = is2.shelvingFk
|
||||
JOIN parking p ON p.id = sh.parkingFk
|
||||
JOIN sector s ON s.id = p.sectorFk
|
||||
LEFT JOIN operator o ON o.sectorFk = s.id
|
||||
LEFT JOIN worker w ON w.sectorFk = s.id AND w.id = account.myUser_getId()
|
||||
JOIN warehouse wh ON wh.id = s.warehouseFk
|
||||
JOIN itemShelving is3 ON is3.itemFk = is2.itemFk AND is3.shelvingFk = vShelvingFk COLLATE utf8_unicode_ci
|
||||
WHERE is2.shelvingFk <> vShelvingFk COLLATE utf8_unicode_ci
|
||||
GROUP BY is2.id
|
||||
ORDER BY p.pickingOrder DESC;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
DELIMITER $$
|
||||
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`operator_beforeInsert`
|
||||
BEFORE INSERT ON `operator`
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
CALL vn.printer_checkSector(NEW.labelerFk, NEW.sectorFk);
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
DELIMITER $$
|
||||
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`operator_beforeUpdate`
|
||||
BEFORE UPDATE ON `operator`
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
IF NOT (NEW.labelerFk <=> OLD.labelerFk AND NEW.sectorFk <=> OLD.sectorFk) THEN
|
||||
CALL vn.printer_checkSector(NEW.labelerFk, NEW.sectorFk);
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
DELIMITER $$
|
||||
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`worker_beforeUpdate`
|
||||
BEFORE UPDATE ON `worker`
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
IF NOT (NEW.labelerFk <=> OLD.labelerFk AND NEW.sectorFk <=> OLD.sectorFk) THEN
|
||||
CALL vn.printer_checkSector(NEW.labelerFk, NEW.sectorFk);
|
||||
|
||||
INSERT IGNORE INTO vn.operator (workerFk)
|
||||
VALUES (NEW.id);
|
||||
|
||||
UPDATE operator
|
||||
SET labelerFk = NEW.labelerFk,
|
||||
sectorFk = NEW.sectorFk
|
||||
WHERE workerFk = NEW.id;
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
CREATE OR REPLACE DEFINER=`root`@`localhost`
|
||||
SQL SECURITY DEFINER
|
||||
VIEW `vn`.`operatorWorkerCode`
|
||||
AS SELECT `o`.`workerFk` AS `workerFk`,
|
||||
concat(`w`.`firstName`, ' ', `w`.`lastName`) AS `fullName`,
|
||||
`w`.`code` AS `code`,
|
||||
`o`.`numberOfWagons` AS `numberOfWagons`
|
||||
FROM (
|
||||
(
|
||||
`vn`.`worker` `w`
|
||||
JOIN `vn`.`operator` `o` ON(`o`.`workerFk` = `w`.`id`)
|
||||
)
|
||||
JOIN `vn`.`sector` `s` ON(`o`.`sectorFk` = `s`.`id`)
|
||||
)
|
||||
WHERE `o`.`sectorFk` IS NOT NULL
|
||||
AND `s`.`code` IN (
|
||||
'H2',
|
||||
'H2',
|
||||
'PEQUES_H',
|
||||
'ALTILLO COMP',
|
||||
'ALTILLO ARTI'
|
||||
)
|
|
@ -0,0 +1,3 @@
|
|||
DROP TRIGGER `vn`.`supplierAccount_afterInsert`;
|
||||
DROP TRIGGER `vn`.`supplierAccount_afterUpdate`;
|
||||
DROP TRIGGER `vn`.`supplierAccount_afterDelete`;
|
|
@ -0,0 +1,47 @@
|
|||
DROP PROCEDURE IF EXISTS `vn`.`ticket_getWarnings`;
|
||||
|
||||
DELIMITER $$
|
||||
$$
|
||||
CREATE PROCEDURE `vn`.`ticket_getWarnings`()
|
||||
BEGIN
|
||||
/**
|
||||
* Calcula las adventencias para un conjunto de tickets.
|
||||
* Agrupados por ticket
|
||||
*
|
||||
* @table tmp.sale_getWarnings(ticketFk) Identificadores de los tickets a calcular
|
||||
* @return tmp.ticket_warnings
|
||||
*/
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.sale_warnings;
|
||||
CREATE TEMPORARY TABLE tmp.sale_warnings (
|
||||
ticketFk INT(11),
|
||||
saleFk INT(11),
|
||||
isFragile INTEGER(1) DEFAULT 0,
|
||||
PRIMARY KEY (ticketFk, saleFk)
|
||||
) ENGINE = MEMORY;
|
||||
|
||||
-- Frágil
|
||||
INSERT INTO tmp.sale_warnings(ticketFk, saleFk, isFragile)
|
||||
SELECT tt.ticketFk, s.id, TRUE
|
||||
FROM tmp.sale_getWarnings tt
|
||||
LEFT JOIN sale s ON s.ticketFk = tt.ticketFk
|
||||
LEFT JOIN item i ON i.id = s.itemFk
|
||||
LEFT JOIN itemType it ON it.id = i.typeFk
|
||||
LEFT JOIN agencyMode am ON am.id = tt.agencyModeFk
|
||||
LEFT JOIN deliveryMethod dm ON dm.id = am.deliveryMethodFk
|
||||
WHERE dm.code IN ('AGENCY')
|
||||
AND it.isFragile;
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.ticket_warnings;
|
||||
CREATE TEMPORARY TABLE tmp.ticket_warnings
|
||||
(PRIMARY KEY (ticketFk))
|
||||
ENGINE = MEMORY
|
||||
SELECT
|
||||
sw.ticketFk,
|
||||
MAX(sw.isFragile) AS isFragile
|
||||
FROM tmp.sale_warnings sw
|
||||
GROUP BY sw.ticketFk;
|
||||
|
||||
DROP TEMPORARY TABLE
|
||||
tmp.sale_warnings;
|
||||
END$$
|
||||
DELIMITER ;
|
|
@ -0,0 +1,72 @@
|
|||
CREATE TABLE `vn`.`wagonType` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(30) NOT NULL UNIQUE,
|
||||
`divisible` tinyint(1) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb3;
|
||||
|
||||
CREATE TABLE `vn`.`wagonTypeColor` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(30) NOT NULL UNIQUE,
|
||||
`rgb` varchar(30) NOT NULL UNIQUE,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb3;
|
||||
|
||||
CREATE TABLE `vn`.`wagonTypeTray` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`typeFk` int(11) unsigned,
|
||||
`height` int(11) unsigned NOT NULL,
|
||||
`colorFk` int(11) unsigned,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY (`typeFk`,`height`),
|
||||
CONSTRAINT `wagonTypeTray_type` FOREIGN KEY (`typeFk`) REFERENCES `wagonType` (`id`) ON UPDATE CASCADE,
|
||||
CONSTRAINT `wagonTypeTray_color` FOREIGN KEY (`colorFk`) REFERENCES `wagonTypeColor` (`id`) ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb3;
|
||||
|
||||
CREATE TABLE `vn`.`wagonConfig` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`width` int(11) unsigned DEFAULT 1350,
|
||||
`height` int(11) unsigned DEFAULT 1900,
|
||||
`maxWagonHeight` int(11) unsigned DEFAULT 200,
|
||||
`minHeightBetweenTrays` int(11) unsigned DEFAULT 50,
|
||||
`maxTrays` int(11) unsigned DEFAULT 6,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb3;
|
||||
|
||||
CREATE TABLE `vn`.`collectionWagon` (
|
||||
`collectionFk` int(11) NOT NULL,
|
||||
`wagonFk` int(11) NOT NULL,
|
||||
`position` int(11) unsigned,
|
||||
PRIMARY KEY (`collectionFk`,`position`),
|
||||
UNIQUE KEY `collectionWagon_unique` (`collectionFk`,`wagonFk`),
|
||||
CONSTRAINT `collectionWagon_collection` FOREIGN KEY (`collectionFk`) REFERENCES `collection` (`id`) ON UPDATE CASCADE,
|
||||
CONSTRAINT `collectionWagon_wagon` FOREIGN KEY (`wagonFk`) REFERENCES `wagon` (`id`) ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
|
||||
|
||||
CREATE TABLE `vn`.`collectionWagonTicket` (
|
||||
`ticketFk` int(11) NOT NULL,
|
||||
`wagonFk` int(11) NOT NULL,
|
||||
`trayFk` int(11) unsigned NOT NULL,
|
||||
`side` SET('L', 'R') NULL,
|
||||
PRIMARY KEY (`ticketFk`),
|
||||
CONSTRAINT `collectionWagonTicket_ticket` FOREIGN KEY (`ticketFk`) REFERENCES `ticket` (`id`) ON UPDATE CASCADE,
|
||||
CONSTRAINT `collectionWagonTicket_wagon` FOREIGN KEY (`wagonFk`) REFERENCES `wagon` (`id`) ON UPDATE CASCADE,
|
||||
CONSTRAINT `collectionWagonTicket_tray` FOREIGN KEY (`trayFk`) REFERENCES `wagonTypeTray` (`id`) ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
|
||||
|
||||
ALTER TABLE `vn`.`wagon` ADD `typeFk` int(11) unsigned NOT NULL;
|
||||
ALTER TABLE `vn`.`wagon` ADD `label` int(11) unsigned NOT NULL;
|
||||
ALTER TABLE `vn`.`wagon` ADD CONSTRAINT `wagon_type` FOREIGN KEY (`typeFk`) REFERENCES `wagonType` (`id`) ON UPDATE CASCADE;
|
||||
|
||||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||
VALUES
|
||||
('WagonType', '*', '*', 'ALLOW', 'ROLE', 'productionAssi'),
|
||||
('WagonTypeColor', '*', '*', 'ALLOW', 'ROLE', 'productionAssi'),
|
||||
('WagonTypeTray', '*', '*', 'ALLOW', 'ROLE', 'productionAssi'),
|
||||
('WagonConfig', '*', '*', 'ALLOW', 'ROLE', 'productionAssi'),
|
||||
('CollectionWagon', '*', '*', 'ALLOW', 'ROLE', 'productionAssi'),
|
||||
('CollectionWagonTicket', '*', '*', 'ALLOW', 'ROLE', 'productionAssi'),
|
||||
('Wagon', '*', '*', 'ALLOW', 'ROLE', 'productionAssi'),
|
||||
('WagonType', 'createWagonType', '*', 'ALLOW', 'ROLE', 'productionAssi'),
|
||||
('WagonType', 'deleteWagonType', '*', 'ALLOW', 'ROLE', 'productionAssi'),
|
||||
('WagonType', 'editWagonType', '*', 'ALLOW', 'ROLE', 'productionAssi');
|
|
@ -0,0 +1,74 @@
|
|||
DROP TABLE `vn`.`dmsRecover`;
|
||||
|
||||
ALTER TABLE `vn`.`delivery` DROP FOREIGN KEY delivery_FK;
|
||||
ALTER TABLE `vn`.`delivery` DROP COLUMN addressFk;
|
||||
ALTER TABLE `vn`.`delivery` ADD ticketFk INT NOT NULL;
|
||||
ALTER TABLE `vn`.`delivery` ADD CONSTRAINT delivery_ticketFk_FK FOREIGN KEY (`ticketFk`) REFERENCES `vn`.`ticket`(`id`);
|
||||
|
||||
DELETE FROM `salix`.`ACL` WHERE `property` = 'saveSign';
|
||||
INSERT INTO `salix`.`ACL` (`model`,`property`,`accessType`,`permission`,`principalId`)
|
||||
VALUES
|
||||
('Ticket','saveSign','WRITE','ALLOW','employee');
|
||||
|
||||
DROP PROCEDURE IF EXISTS vn.route_getTickets;
|
||||
|
||||
DELIMITER $$
|
||||
$$
|
||||
CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`route_getTickets`(vRouteFk INT)
|
||||
BEGIN
|
||||
/**
|
||||
* Pasado un RouteFk devuelve la información
|
||||
* de sus tickets.
|
||||
*
|
||||
* @param vRouteFk
|
||||
*
|
||||
* @select Información de los tickets
|
||||
*/
|
||||
|
||||
SELECT
|
||||
t.id Id,
|
||||
t.clientFk Client,
|
||||
a.id Address,
|
||||
t.packages Packages,
|
||||
a.street AddressName,
|
||||
a.postalCode PostalCode,
|
||||
a.city City,
|
||||
sub2.itemPackingTypeFk PackingType,
|
||||
c.phone ClientPhone,
|
||||
c.mobile ClientMobile,
|
||||
a.phone AddressPhone,
|
||||
a.mobile AddressMobile,
|
||||
d.longitude Longitude,
|
||||
d.latitude Latitude,
|
||||
wm.mediaValue SalePersonPhone,
|
||||
tob.Note Note,
|
||||
t.isSigned Signed
|
||||
FROM ticket t
|
||||
JOIN client c ON t.clientFk = c.id
|
||||
JOIN address a ON t.addressFk = a.id
|
||||
LEFT JOIN delivery d ON t.id = d.ticketFk
|
||||
LEFT JOIN workerMedia wm ON wm.workerFk = c.salesPersonFk
|
||||
LEFT JOIN
|
||||
(SELECT tob.description Note, t.id
|
||||
FROM ticketObservation tob
|
||||
JOIN ticket t ON tob.ticketFk = t.id
|
||||
JOIN observationType ot ON ot.id = tob.observationTypeFk
|
||||
WHERE t.routeFk = vRouteFk
|
||||
AND ot.code = 'delivery'
|
||||
)tob ON tob.id = t.id
|
||||
LEFT JOIN
|
||||
(SELECT sub.ticketFk,
|
||||
CONCAT('(', GROUP_CONCAT(DISTINCT sub.itemPackingTypeFk ORDER BY sub.items DESC SEPARATOR ','), ') ') itemPackingTypeFk
|
||||
FROM (SELECT s.ticketFk , i.itemPackingTypeFk, COUNT(*) items
|
||||
FROM ticket t
|
||||
JOIN sale s ON s.ticketFk = t.id
|
||||
JOIN item i ON i.id = s.itemFk
|
||||
WHERE t.routeFk = vRouteFk
|
||||
GROUP BY t.id,i.itemPackingTypeFk)sub
|
||||
GROUP BY sub.ticketFk
|
||||
) sub2 ON sub2.ticketFk = t.id
|
||||
WHERE t.routeFk = vRouteFk
|
||||
GROUP BY t.id
|
||||
ORDER BY t.priority;
|
||||
END$$
|
||||
DELIMITER ;
|
|
@ -0,0 +1,67 @@
|
|||
DELETE FROM `salix`.`ACL` WHERE `property` = 'saveSign';
|
||||
INSERT INTO `salix`.`ACL` (`model`,`property`,`accessType`,`permission`,`principalId`)
|
||||
VALUES
|
||||
('Ticket','saveSign','WRITE','ALLOW','employee');
|
||||
|
||||
DROP PROCEDURE IF EXISTS vn.route_getTickets;
|
||||
|
||||
DELIMITER $$
|
||||
$$
|
||||
CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`route_getTickets`(vRouteFk INT)
|
||||
BEGIN
|
||||
/**
|
||||
* Pasado un RouteFk devuelve la información
|
||||
* de sus tickets.
|
||||
*
|
||||
* @param vRouteFk
|
||||
*
|
||||
* @select Información de los tickets
|
||||
*/
|
||||
|
||||
SELECT
|
||||
t.id Id,
|
||||
t.clientFk Client,
|
||||
a.id Address,
|
||||
t.packages Packages,
|
||||
a.street AddressName,
|
||||
a.postalCode PostalCode,
|
||||
a.city City,
|
||||
sub2.itemPackingTypeFk PackingType,
|
||||
c.phone ClientPhone,
|
||||
c.mobile ClientMobile,
|
||||
a.phone AddressPhone,
|
||||
a.mobile AddressMobile,
|
||||
d.longitude Longitude,
|
||||
d.latitude Latitude,
|
||||
wm.mediaValue SalePersonPhone,
|
||||
tob.Note Note,
|
||||
t.isSigned Signed
|
||||
FROM ticket t
|
||||
JOIN client c ON t.clientFk = c.id
|
||||
JOIN address a ON t.addressFk = a.id
|
||||
LEFT JOIN delivery d ON t.id = d.ticketFk
|
||||
LEFT JOIN workerMedia wm ON wm.workerFk = c.salesPersonFk
|
||||
LEFT JOIN
|
||||
(SELECT tob.description Note, t.id
|
||||
FROM ticketObservation tob
|
||||
JOIN ticket t ON tob.ticketFk = t.id
|
||||
JOIN observationType ot ON ot.id = tob.observationTypeFk
|
||||
WHERE t.routeFk = vRouteFk
|
||||
AND ot.code = 'delivery'
|
||||
)tob ON tob.id = t.id
|
||||
LEFT JOIN
|
||||
(SELECT sub.ticketFk,
|
||||
CONCAT('(', GROUP_CONCAT(DISTINCT sub.itemPackingTypeFk ORDER BY sub.items DESC SEPARATOR ','), ') ') itemPackingTypeFk
|
||||
FROM (SELECT s.ticketFk , i.itemPackingTypeFk, COUNT(*) items
|
||||
FROM ticket t
|
||||
JOIN sale s ON s.ticketFk = t.id
|
||||
JOIN item i ON i.id = s.itemFk
|
||||
WHERE t.routeFk = vRouteFk
|
||||
GROUP BY t.id,i.itemPackingTypeFk)sub
|
||||
GROUP BY sub.ticketFk
|
||||
) sub2 ON sub2.ticketFk = t.id
|
||||
WHERE t.routeFk = vRouteFk
|
||||
GROUP BY t.id
|
||||
ORDER BY t.priority;
|
||||
END$$
|
||||
DELIMITER ;
|
|
@ -0,0 +1,83 @@
|
|||
CREATE TABLE `vn`.`dmsRecover` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`ticketFk` int(11) DEFAULT NULL,
|
||||
`sign` text DEFAULT NULL,
|
||||
`created` timestamp NULL DEFAULT current_timestamp(),
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `ticketFk_idx` (`ticketFk`),
|
||||
CONSTRAINT `ticketFk` FOREIGN KEY (`ticketFk`) REFERENCES `ticket` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=31917 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||
|
||||
ALTER TABLE `vn`.`delivery` ADD addressFk INT;
|
||||
|
||||
DROP PROCEDURE IF EXISTS `vn`.`route_getTickets`;
|
||||
|
||||
DELIMITER $$
|
||||
$$
|
||||
CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`route_getTickets`(vRouteFk INT)
|
||||
BEGIN
|
||||
/**
|
||||
* Pasado un RouteFk devuelve la información
|
||||
* de sus tickets.
|
||||
*
|
||||
* @param vRouteFk
|
||||
* @select Información de los tickets
|
||||
*/
|
||||
SELECT *
|
||||
FROM (
|
||||
SELECT t.id Id,
|
||||
t.clientFk Client,
|
||||
a.id Address,
|
||||
a.nickname ClientName,
|
||||
t.packages Packages,
|
||||
a.street AddressName,
|
||||
a.postalCode PostalCode,
|
||||
a.city City,
|
||||
sub2.itemPackingTypeFk PackingType,
|
||||
c.phone ClientPhone,
|
||||
c.mobile ClientMobile,
|
||||
a.phone AddressPhone,
|
||||
a.mobile AddressMobile,
|
||||
d.longitude Longitude,
|
||||
d.latitude Latitude,
|
||||
wm.mediaValue SalePersonPhone,
|
||||
tob.description Note,
|
||||
t.isSigned Signed,
|
||||
t.priority
|
||||
FROM ticket t
|
||||
JOIN client c ON t.clientFk = c.id
|
||||
JOIN address a ON t.addressFk = a.id
|
||||
LEFT JOIN delivery d ON d.addressFk = a.id
|
||||
LEFT JOIN workerMedia wm ON wm.workerFk = c.salesPersonFk
|
||||
LEFT JOIN(
|
||||
SELECT tob.description, t.id
|
||||
FROM ticketObservation tob
|
||||
JOIN ticket t ON tob.ticketFk = t.id
|
||||
JOIN observationType ot ON ot.id = tob.observationTypeFk
|
||||
WHERE t.routeFk = vRouteFk
|
||||
AND ot.code = 'delivery'
|
||||
)tob ON tob.id = t.id
|
||||
LEFT JOIN(
|
||||
SELECT sub.ticketFk,
|
||||
CONCAT('(',
|
||||
GROUP_CONCAT(DISTINCT sub.itemPackingTypeFk
|
||||
ORDER BY sub.items DESC SEPARATOR ','),
|
||||
') ') itemPackingTypeFk
|
||||
FROM (
|
||||
SELECT s.ticketFk, i.itemPackingTypeFk, COUNT(*) items
|
||||
FROM ticket t
|
||||
JOIN sale s ON s.ticketFk = t.id
|
||||
JOIN item i ON i.id = s.itemFk
|
||||
WHERE t.routeFk = vRouteFk
|
||||
GROUP BY t.id, i.itemPackingTypeFk
|
||||
)sub
|
||||
GROUP BY sub.ticketFk
|
||||
)sub2 ON sub2.ticketFk = t.id
|
||||
WHERE t.routeFk = vRouteFk
|
||||
ORDER BY d.id DESC
|
||||
LIMIT 10000000000000000000
|
||||
)sub3
|
||||
GROUP BY sub3.id
|
||||
ORDER BY sub3.priority;
|
||||
END$$
|
||||
DELIMITER ;
|
|
@ -0,0 +1 @@
|
|||
DROP TRIGGER IF EXISTS `vn`.`claimBeginning_afterInsert`;
|
|
@ -0,0 +1,72 @@
|
|||
DROP TRIGGER IF EXISTS `vn`.`client_beforeUpdate`;
|
||||
USE `vn`;
|
||||
|
||||
DELIMITER $$
|
||||
$$
|
||||
CREATE DEFINER=`root`@`localhost` TRIGGER `vn`.`client_beforeUpdate`
|
||||
BEFORE UPDATE ON `client`
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
DECLARE vText VARCHAR(255) DEFAULT NULL;
|
||||
DECLARE vPayMethodFk INT;
|
||||
-- Comprueba que el formato de los teléfonos es válido
|
||||
|
||||
IF !(NEW.phone <=> OLD.phone) AND (NEW.phone <> '') THEN
|
||||
CALL pbx.phone_isValid(NEW.phone);
|
||||
END IF;
|
||||
|
||||
IF !(NEW.mobile <=> OLD.mobile) AND (NEW.mobile <> '')THEN
|
||||
CALL pbx.phone_isValid(NEW.mobile);
|
||||
END IF;
|
||||
|
||||
SELECT id INTO vPayMethodFk
|
||||
FROM vn.payMethod
|
||||
WHERE code = 'bankDraft';
|
||||
|
||||
IF NEW.payMethodFk = vPayMethodFk AND NEW.dueDay = 0 THEN
|
||||
SET NEW.dueDay = 5;
|
||||
END IF;
|
||||
|
||||
-- Avisar al comercial si ha llegado la documentación sepa/core
|
||||
|
||||
IF NEW.hasSepaVnl AND !OLD.hasSepaVnl THEN
|
||||
SET vText = 'Sepa de VNL';
|
||||
END IF;
|
||||
|
||||
IF NEW.hasCoreVnl AND !OLD.hasCoreVnl THEN
|
||||
SET vText = 'Core de VNL';
|
||||
END IF;
|
||||
|
||||
IF vText IS NOT NULL
|
||||
THEN
|
||||
INSERT INTO mail(receiver, replyTo, `subject`, body)
|
||||
SELECT
|
||||
CONCAT(IF(ac.id,u.name, 'jgallego'), '@verdnatura.es'),
|
||||
'administracion@verdnatura.es',
|
||||
CONCAT('Cliente ', NEW.id),
|
||||
CONCAT('Recibida la documentación: ', vText)
|
||||
FROM worker w
|
||||
LEFT JOIN account.user u ON w.userFk = u.id AND u.active
|
||||
LEFT JOIN account.account ac ON ac.id = u.id
|
||||
WHERE w.id = NEW.salesPersonFk;
|
||||
END IF;
|
||||
|
||||
IF NEW.salespersonFk IS NULL AND OLD.salespersonFk IS NOT NULL THEN
|
||||
IF (SELECT COUNT(clientFk)
|
||||
FROM clientProtected
|
||||
WHERE clientFk = NEW.id
|
||||
) > 0 THEN
|
||||
CALL util.throw("HAS_CLIENT_PROTECTED");
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
IF !(NEW.salesPersonFk <=> OLD.salesPersonFk) THEN
|
||||
SET NEW.lastSalesPersonFk = IFNULL(NEW.salesPersonFk, OLD.salesPersonFk);
|
||||
END IF;
|
||||
|
||||
IF !(NEW.businessTypeFk <=> OLD.businessTypeFk) AND (NEW.businessTypeFk = 'individual' OR OLD.businessTypeFk = 'individual') THEN
|
||||
SET NEW.isTaxDataChecked = 0;
|
||||
END IF;
|
||||
|
||||
END$$
|
||||
DELIMITER ;
|
|
@ -0,0 +1,70 @@
|
|||
DROP TABLE IF EXISTS `vn`.`dmsRecover`;
|
||||
|
||||
ALTER TABLE `vn`.`delivery` DROP COLUMN addressFk;
|
||||
ALTER TABLE `vn`.`delivery` DROP CONSTRAINT delivery_ticketFk_FK;
|
||||
ALTER TABLE `vn`.`delivery` DROP COLUMN ticketFk;
|
||||
ALTER TABLE `vn`.`delivery` ADD ticketFk INT DEFAULT NULL;
|
||||
ALTER TABLE `vn`.`delivery` ADD CONSTRAINT delivery_ticketFk_FK FOREIGN KEY (`ticketFk`) REFERENCES `vn`.`ticket`(`id`);
|
||||
|
||||
DROP PROCEDURE IF EXISTS vn.route_getTickets;
|
||||
|
||||
DELIMITER $$
|
||||
$$
|
||||
CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`route_getTickets`(vRouteFk INT)
|
||||
BEGIN
|
||||
/**
|
||||
* Pasado un RouteFk devuelve la información
|
||||
* de sus tickets.
|
||||
*
|
||||
* @param vRouteFk
|
||||
*
|
||||
* @select Información de los tickets
|
||||
*/
|
||||
|
||||
SELECT
|
||||
t.id Id,
|
||||
t.clientFk Client,
|
||||
a.id Address,
|
||||
t.packages Packages,
|
||||
a.street AddressName,
|
||||
a.postalCode PostalCode,
|
||||
a.city City,
|
||||
sub2.itemPackingTypeFk PackingType,
|
||||
c.phone ClientPhone,
|
||||
c.mobile ClientMobile,
|
||||
a.phone AddressPhone,
|
||||
a.mobile AddressMobile,
|
||||
d.longitude Longitude,
|
||||
d.latitude Latitude,
|
||||
wm.mediaValue SalePersonPhone,
|
||||
tob.Note Note,
|
||||
t.isSigned Signed
|
||||
FROM ticket t
|
||||
JOIN client c ON t.clientFk = c.id
|
||||
JOIN address a ON t.addressFk = a.id
|
||||
LEFT JOIN delivery d ON t.id = d.ticketFk
|
||||
LEFT JOIN workerMedia wm ON wm.workerFk = c.salesPersonFk
|
||||
LEFT JOIN
|
||||
(SELECT tob.description Note, t.id
|
||||
FROM ticketObservation tob
|
||||
JOIN ticket t ON tob.ticketFk = t.id
|
||||
JOIN observationType ot ON ot.id = tob.observationTypeFk
|
||||
WHERE t.routeFk = vRouteFk
|
||||
AND ot.code = 'delivery'
|
||||
)tob ON tob.id = t.id
|
||||
LEFT JOIN
|
||||
(SELECT sub.ticketFk,
|
||||
CONCAT('(', GROUP_CONCAT(DISTINCT sub.itemPackingTypeFk ORDER BY sub.items DESC SEPARATOR ','), ') ') itemPackingTypeFk
|
||||
FROM (SELECT s.ticketFk , i.itemPackingTypeFk, COUNT(*) items
|
||||
FROM ticket t
|
||||
JOIN sale s ON s.ticketFk = t.id
|
||||
JOIN item i ON i.id = s.itemFk
|
||||
WHERE t.routeFk = vRouteFk
|
||||
GROUP BY t.id,i.itemPackingTypeFk)sub
|
||||
GROUP BY sub.ticketFk
|
||||
) sub2 ON sub2.ticketFk = t.id
|
||||
WHERE t.routeFk = vRouteFk
|
||||
GROUP BY t.id
|
||||
ORDER BY t.priority;
|
||||
END$$
|
||||
DELIMITER ;
|
|
@ -0,0 +1,13 @@
|
|||
DROP TRIGGER IF EXISTS `vn`.`invoiceOut_afterInsert`;
|
||||
USE vn;
|
||||
|
||||
DELIMITER $$
|
||||
$$
|
||||
CREATE DEFINER=`root`@`localhost` TRIGGER `vn`.`invoiceOut_afterInsert`
|
||||
AFTER INSERT ON `invoiceOut`
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
CALL clientRisk_update(NEW.clientFk, NEW.companyFk, NEW.amount);
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||
VALUES
|
||||
('InvoiceIn', 'negativeBases', 'READ', 'ALLOW', 'ROLE', 'administrative'),
|
||||
('InvoiceIn', 'negativeBasesCsv', 'READ', 'ALLOW', 'ROLE', 'administrative');
|
|
@ -0,0 +1,14 @@
|
|||
CREATE TABLE `vn`.`workerObservation` (
|
||||
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`workerFk` int(10) unsigned DEFAULT NULL,
|
||||
`userFk` int(10) unsigned DEFAULT NULL,
|
||||
`text` text COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`created` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
PRIMARY KEY (`id`),
|
||||
CONSTRAINT `workerFk_workerObservation_FK` FOREIGN KEY (`workerFk`) REFERENCES `vn`.`worker` (`id`) ON UPDATE CASCADE,
|
||||
CONSTRAINT `userFk_workerObservation_FK` FOREIGN KEY (`userFk`) REFERENCES `account`.`user`(`id`) ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci COMMENT='Todas las observaciones referentes a un trabajador';
|
||||
|
||||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||
VALUES
|
||||
('WorkerObservation', '*', '*', 'ALLOW', 'ROLE', 'hr');
|
|
@ -0,0 +1,5 @@
|
|||
INSERT INTO `vn`.`companyI18n` (`companyFk`, `lang`, `footnotes`)
|
||||
VALUES (442, 'en', 'In compliance with the provisions of Organic Law 15/1999, on the Protection of Personal Data, we inform you that the personal data you provide will be included in automated files of VERDNATURA LEVANTE SL, being able at all times to exercise the rights of access, rectification, cancellation and opposition, communicating it in writing to the registered office of the entity. The purpose of the file is administrative management, accounting, and billing.'),
|
||||
(442, 'es', 'En cumplimiento de lo dispuesto en la Ley Orgánica 15/1999, de Protección de Datos de Carácter Personal, le comunicamos que los datos personales que facilite se incluirán en ficheros automatizados de VERDNATURA LEVANTE S.L., pudiendo en todo momento ejercitar los derechos de acceso, rectificación, cancelación y oposición, comunicándolo por escrito al domicilio social de la entidad. La finalidad del fichero es la gestión administrativa, contabilidad, y facturación.'),
|
||||
(442, 'fr', 'Conformément aux dispositions de la loi organique 15/1999 sur la protection des données personnelles, nous vous informons que les données personnelles que vous fournissez seront incluses dans des dossiers. VERDNATURA LEVANTE S.L., vous pouvez à tout moment, exercer les droits d``accès, de rectification, d``annulation et d``opposition, en communiquant par écrit au siège social de la société. Le dossier a pour objet la gestion administrative, la comptabilité et la facturation.'),
|
||||
(442, 'pt', 'Em cumprimento do disposto na lei Orgânica 15/1999, de Protecção de Dados de Carácter Pessoal, comunicamos que os dados pessoais que facilite se incluirão nos ficheiros automatizados de VERDNATURA LEVANTE S.L., podendo em todo momento exercer os direitos de acesso, rectificação, cancelação e oposição, comunicando por escrito ao domicílio social da entidade. A finalidade do ficheiro é a gestão administrativa, contabilidade e facturação.');
|
|
@ -0,0 +1,3 @@
|
|||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||
VALUES
|
||||
('Defaulter', 'observationEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee');
|
|
@ -164,7 +164,7 @@ INSERT INTO `vn`.`warehouse`(`id`, `name`, `code`, `isComparative`, `isInventory
|
|||
(3, 'Warehouse Three', NULL, 1, 1, 1, 1, 0, 0, 2, 1, 1),
|
||||
(4, 'Warehouse Four', NULL, 1, 1, 1, 1, 0, 0, 2, 1, 1),
|
||||
(5, 'Warehouse Five', NULL, 1, 1, 1, 1, 0, 0, 2, 1, 1),
|
||||
(13, 'Inventory', NULL, 1, 1, 1, 0, 0, 0, 2, 1, 0),
|
||||
(13, 'Inventory', 'inv', 1, 1, 1, 0, 0, 0, 2, 1, 0),
|
||||
(60, 'Algemesi', NULL, 1, 1, 1, 0, 0, 0, 2, 1, 0);
|
||||
|
||||
|
||||
|
@ -173,10 +173,15 @@ INSERT INTO `vn`.`sector`(`id`, `description`, `warehouseFk`, `isPreviousPrepare
|
|||
(1, 'First sector', 1, 1, 'FIRST'),
|
||||
(2, 'Second sector', 2, 0, 'SECOND');
|
||||
|
||||
INSERT INTO `vn`.`printer` (`id`, `name`, `path`, `isLabeler`, `sectorFk`)
|
||||
INSERT INTO `vn`.`operator` (`workerFk`, `numberOfWagons`, `trainFk`, `itemPackingTypeFk`, `warehouseFk`, `sectorFk`, `labelerFk`)
|
||||
VALUES ('1106', '1', '1', 'H', '1', '1', '1'),
|
||||
('1107', '1', '1', 'V', '1', '2', '1');
|
||||
|
||||
INSERT INTO `vn`.`printer` (`id`, `name`, `path`, `isLabeler`, `sectorFk`, `ipAddress`)
|
||||
VALUES
|
||||
(1, 'printer1', 'path1', 0, 1),
|
||||
(2, 'printer2', 'path2', 1, 1);
|
||||
(1, 'printer1', 'path1', 0, 1 , NULL),
|
||||
(2, 'printer2', 'path2', 1, 1 , NULL),
|
||||
(4, 'printer4', 'path4', 0, NULL, '10.1.10.4');
|
||||
|
||||
INSERT INTO `vn`.`worker`(`id`, `code`, `firstName`, `lastName`, `userFk`,`bossFk`, `phone`, `sectorFk`, `labelerFk`)
|
||||
VALUES
|
||||
|
@ -294,7 +299,8 @@ INSERT INTO `vn`.`payMethod`(`id`,`code`, `name`, `graceDays`, `outstandingDebt
|
|||
INSERT INTO `vn`.`payDem`(`id`, `payDem`)
|
||||
VALUES
|
||||
(1, 10),
|
||||
(2, 20);
|
||||
(2, 20),
|
||||
(7, 0);
|
||||
|
||||
INSERT INTO `vn`.`autonomy`(`id`, `name`, `countryFk`)
|
||||
VALUES
|
||||
|
@ -495,7 +501,8 @@ INSERT INTO `vn`.`observationType`(`id`,`description`, `code`)
|
|||
(3, 'Delivery', 'delivery'),
|
||||
(4, 'SalesPerson', 'salesPerson'),
|
||||
(5, 'Administrative', 'administrative'),
|
||||
(6, 'Weight', 'weight');
|
||||
(6, 'Weight', 'weight'),
|
||||
(7, 'InvoiceOut', 'invoiceOut');
|
||||
|
||||
INSERT INTO `vn`.`addressObservation`(`id`,`addressFk`,`observationTypeFk`,`description`)
|
||||
VALUES
|
||||
|
@ -572,14 +579,13 @@ INSERT INTO `vn`.`taxArea` (`code`, `claveOperacionFactura`, `CodigoTransaccion`
|
|||
('NATIONAL', 0, 1),
|
||||
('WORLD', 2, 15);
|
||||
|
||||
INSERT INTO `vn`.`invoiceOutSerial` (`code`, `description`, `isTaxed`, `taxAreaFk`, `isCEE`)
|
||||
INSERT INTO `vn`.`invoiceOutSerial` (`code`, `description`, `isTaxed`, `taxAreaFk`, `isCEE`, `type`)
|
||||
VALUES
|
||||
('A', 'Global nacional', 1, 'NATIONAL', 0),
|
||||
('T', 'Española rapida', 1, 'NATIONAL', 0),
|
||||
('V', 'Intracomunitaria global', 0, 'CEE', 1),
|
||||
('M', 'Múltiple nacional', 1, 'NATIONAL', 0),
|
||||
('E', 'Exportación rápida', 0, 'WORLD', 0);
|
||||
;
|
||||
('A', 'Global nacional', 1, 'NATIONAL', 0, 'global'),
|
||||
('T', 'Española rapida', 1, 'NATIONAL', 0, 'quick'),
|
||||
('V', 'Intracomunitaria global', 0, 'CEE', 1, 'global'),
|
||||
('M', 'Múltiple nacional', 1, 'NATIONAL', 0, 'quick'),
|
||||
('E', 'Exportación rápida', 0, 'WORLD', 0, 'quick');
|
||||
|
||||
INSERT INTO `vn`.`invoiceOut`(`id`, `serial`, `amount`, `issued`,`clientFk`, `created`, `companyFk`, `dued`, `booked`, `bankFk`, `hasPdf`)
|
||||
VALUES
|
||||
|
@ -734,7 +740,9 @@ INSERT INTO `vn`.`ticketObservation`(`id`, `ticketFk`, `observationTypeFk`, `des
|
|||
(9, 23, 5, 'care with the dog'),
|
||||
(10, 23, 4, 'Reclama ticket: 8'),
|
||||
(11, 24, 4, 'Reclama ticket: 7'),
|
||||
(12, 11, 3, 'Delivery after 10am');
|
||||
(12, 11, 3, 'Delivery after 10am'),
|
||||
(13, 1, 7, 'observation of ticket one'),
|
||||
(14, 2, 7, 'observation of ticket two');
|
||||
|
||||
-- FIX for state hours on local, inter_afterInsert
|
||||
-- UPDATE vncontrol.inter SET odbc_date = DATE_ADD(util.VN_CURDATE(), INTERVAL -10 SECOND);
|
||||
|
@ -834,14 +842,14 @@ INSERT INTO `vn`.`temperature`(`code`, `name`, `description`)
|
|||
('warm', 'Warm', 'Warm'),
|
||||
('cool', 'Cool', 'Cool');
|
||||
|
||||
INSERT INTO `vn`.`itemType`(`id`, `code`, `name`, `categoryFk`, `life`, `workerFk`, `isPackaging`, `temperatureFk`)
|
||||
INSERT INTO `vn`.`itemType`(`id`, `code`, `name`, `categoryFk`, `life`, `workerFk`, `isPackaging`, `temperatureFk`, `isFragile`)
|
||||
VALUES
|
||||
(1, 'CRI', 'Crisantemo', 2, 31, 35, 0, 'cool'),
|
||||
(2, 'ITG', 'Anthurium', 1, 31, 35, 0, 'cool'),
|
||||
(3, 'WPN', 'Paniculata', 2, 31, 35, 0, 'cool'),
|
||||
(4, 'PRT', 'Delivery ports', 3, NULL, 35, 1, 'warm'),
|
||||
(5, 'CON', 'Container', 3, NULL, 35, 1, 'warm'),
|
||||
(6, 'ALS', 'Alstroemeria', 1, 31, 16, 0, 'warm');
|
||||
(1, 'CRI', 'Crisantemo', 2, 31, 35, 0, 'cool', 0),
|
||||
(2, 'ITG', 'Anthurium', 1, 31, 35, 0, 'cool', 1),
|
||||
(3, 'WPN', 'Paniculata', 2, 31, 35, 0, 'cool', 0),
|
||||
(4, 'PRT', 'Delivery ports', 3, NULL, 35, 1, 'warm', 0),
|
||||
(5, 'CON', 'Container', 3, NULL, 35, 1, 'warm', 0),
|
||||
(6, 'ALS', 'Alstroemeria', 1, 31, 16, 0, 'warm', 1);
|
||||
|
||||
INSERT INTO `vn`.`ink`(`id`, `name`, `picture`, `showOrder`, `hex`)
|
||||
VALUES
|
||||
|
@ -1767,12 +1775,12 @@ INSERT INTO `vn`.`claimState`(`id`, `code`, `description`, `roleFk`, `priority`,
|
|||
( 6, 'mana', 'Mana', 72, 4, 0),
|
||||
( 7, 'lack', 'Faltas', 72, 2, 0);
|
||||
|
||||
INSERT INTO `vn`.`claim`(`id`, `ticketCreated`, `claimStateFk`, `clientFk`, `workerFk`, `responsibility`, `isChargedToMana`, `created`, `packages`, `rma`)
|
||||
INSERT INTO `vn`.`claim`(`id`, `ticketCreated`, `claimStateFk`, `clientFk`, `workerFk`, `responsibility`, `isChargedToMana`, `created`, `packages`, `rma`, `ticketFk`)
|
||||
VALUES
|
||||
(1, util.VN_CURDATE(), 1, 1101, 18, 3, 0, util.VN_CURDATE(), 0, '02676A049183'),
|
||||
(2, util.VN_CURDATE(), 2, 1101, 18, 3, 0, util.VN_CURDATE(), 1, NULL),
|
||||
(3, util.VN_CURDATE(), 3, 1101, 18, 1, 1, util.VN_CURDATE(), 5, NULL),
|
||||
(4, util.VN_CURDATE(), 3, 1104, 18, 5, 0, util.VN_CURDATE(), 10, NULL);
|
||||
(1, util.VN_CURDATE(), 1, 1101, 18, 3, 0, util.VN_CURDATE(), 0, '02676A049183', 11),
|
||||
(2, util.VN_CURDATE(), 2, 1101, 18, 3, 0, util.VN_CURDATE(), 1, NULL, 16),
|
||||
(3, util.VN_CURDATE(), 3, 1101, 18, 1, 1, util.VN_CURDATE(), 5, NULL, 7),
|
||||
(4, util.VN_CURDATE(), 3, 1104, 18, 5, 0, util.VN_CURDATE(), 10, NULL, 8);
|
||||
|
||||
INSERT INTO `vn`.`claimObservation` (`claimFk`, `workerFk`, `text`, `created`)
|
||||
VALUES
|
||||
|
@ -2368,11 +2376,11 @@ INSERT INTO `vn`.`device` (`sn`, `model`, `userFk`)
|
|||
VALUES
|
||||
('aaa', 'android', '9');
|
||||
|
||||
INSERT INTO `vn`.`queuePriority`(`id`, `priority`)
|
||||
INSERT INTO `vn`.`queuePriority`(`id`, `priority`, `code`)
|
||||
VALUES
|
||||
(1, 'Alta'),
|
||||
(2, 'Normal'),
|
||||
(3, 'Baja');
|
||||
(1, 'Alta', 'high'),
|
||||
(2, 'Normal', 'normal'),
|
||||
(3, 'Baja', 'low');
|
||||
|
||||
INSERT INTO `vn`.`workerTimeControlParams` (`id`, `dayBreak`, `weekBreak`, `weekScope`, `dayWorkMax`, `dayStayMax`, `weekMaxBreak`, `weekMaxScope`, `askInOut`)
|
||||
VALUES
|
||||
|
@ -2483,9 +2491,9 @@ REPLACE INTO `vn`.`invoiceIn`(`id`, `serialNumber`,`serial`, `supplierFk`, `issu
|
|||
(9, 1009, 'R', 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1242, 1, 442, 1),
|
||||
(10, 1010, 'R', 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1243, 1, 442, 1);
|
||||
|
||||
INSERT INTO `vn`.`invoiceInConfig` (`id`, `retentionRate`, `retentionName`, `sageWithholdingFk`)
|
||||
INSERT INTO `vn`.`invoiceInConfig` (`id`, `retentionRate`, `retentionName`, `sageWithholdingFk`, `daysAgo`)
|
||||
VALUES
|
||||
(1, -2, '2% retention', 2);
|
||||
(1, -2, '2% retention', 2, 45);
|
||||
|
||||
INSERT INTO `vn`.`invoiceInDueDay`(`invoiceInFk`, `dueDated`, `bankFk`, `amount`)
|
||||
VALUES
|
||||
|
@ -2627,8 +2635,8 @@ INSERT INTO `vn`.`supplierAgencyTerm` (`agencyFk`, `supplierFk`, `minimumPackage
|
|||
|
||||
INSERT INTO `vn`.`chat` (`senderFk`, `recipient`, `dated`, `checkUserStatus`, `message`, `status`, `attempts`)
|
||||
VALUES
|
||||
(1101, '@PetterParker', util.VN_CURDATE(), 1, 'First test message', 0, 0),
|
||||
(1101, '@PetterParker', util.VN_CURDATE(), 0, 'Second test message', 0, 0);
|
||||
(1101, '@PetterParker', util.VN_CURDATE(), 1, 'First test message', 0, 'sent'),
|
||||
(1101, '@PetterParker', util.VN_CURDATE(), 0, 'Second test message', 0, 'pending');
|
||||
|
||||
|
||||
INSERT INTO `vn`.`mobileAppVersionControl` (`appName`, `version`, `isVersionCritical`)
|
||||
|
@ -2784,6 +2792,10 @@ INSERT INTO `salix`.`url` (`appName`, `environment`, `url`)
|
|||
('lilium', 'dev', 'http://localhost:8080/#/'),
|
||||
('salix', 'dev', 'http://localhost:5000/#!/');
|
||||
|
||||
INSERT INTO `vn`.`report` (`id`, `name`, `paperSizeFk`, `method`)
|
||||
VALUES
|
||||
(3, 'invoice', NULL, 'InvoiceOuts/{refFk}/invoice-out-pdf');
|
||||
|
||||
INSERT INTO `vn`.`payDemDetail` (`id`, `detail`)
|
||||
VALUES
|
||||
(1, 1);
|
||||
|
@ -2822,4 +2834,34 @@ INSERT INTO `vn`.`deviceProductionUser` (`deviceProductionFk`, `userFk`, `create
|
|||
(1, 1, util.VN_NOW()),
|
||||
(3, 3, util.VN_NOW());
|
||||
|
||||
INSERT INTO `vn`.`workerTimeControlMail` (`id`, `workerFk`, `year`, `week`, `state`, `updated`, `sendedCounter`, `reason`)
|
||||
VALUES
|
||||
(1, 9, 2000, 49, 'REVISE', util.VN_NOW(), 1, 'test2'),
|
||||
(2, 9, 2000, 50, 'SENDED', util.VN_NOW(), 1, NULL),
|
||||
(3, 9, 2000, 51, 'CONFIRMED', util.VN_NOW(), 1, NULL),
|
||||
(4, 9, 2001, 1, 'SENDED', util.VN_NOW(), 1, NULL);
|
||||
|
||||
INSERT INTO `vn`.`wagonConfig` (`id`, `width`, `height`, `maxWagonHeight`, `minHeightBetweenTrays`, `maxTrays`)
|
||||
VALUES
|
||||
(1, 1350, 1900, 200, 50, 6);
|
||||
|
||||
INSERT INTO `vn`.`wagonTypeColor` (`id`, `name`, `rgb`)
|
||||
VALUES
|
||||
(1, 'white', '#ffffff'),
|
||||
(2, 'red', '#ff0000'),
|
||||
(3, 'green', '#00ff00'),
|
||||
(4, 'blue', '#0000ff');
|
||||
|
||||
INSERT INTO `vn`.`wagonType` (`id`, `name`, `divisible`)
|
||||
VALUES
|
||||
(1, 'Wagon Type #1', 1);
|
||||
|
||||
INSERT INTO `vn`.`wagonTypeTray` (`id`, `typeFk`, `height`, `colorFk`)
|
||||
VALUES
|
||||
(1, 1, 100, 1),
|
||||
(2, 1, 50, 2),
|
||||
(3, 1, 0, 3);
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -19742,6 +19742,102 @@ DELIMITER ;
|
|||
/*!50003 SET character_set_client = @saved_cs_client */ ;
|
||||
/*!50003 SET character_set_results = @saved_cs_results */ ;
|
||||
/*!50003 SET collation_connection = @saved_col_connection */ ;
|
||||
/*!50003 DROP FUNCTION IF EXISTS `CURDATE` */;
|
||||
/*!50003 SET @saved_cs_client = @@character_set_client */ ;
|
||||
/*!50003 SET @saved_cs_results = @@character_set_results */ ;
|
||||
/*!50003 SET @saved_col_connection = @@collation_connection */ ;
|
||||
/*!50003 SET character_set_client = utf8mb4 */ ;
|
||||
/*!50003 SET character_set_results = utf8mb4 */ ;
|
||||
/*!50003 SET collation_connection = utf8mb4_unicode_ci */ ;
|
||||
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
|
||||
/*!50003 SET sql_mode = 'IGNORE_SPACE,NO_ENGINE_SUBSTITUTION' */ ;
|
||||
DELIMITER ;;
|
||||
CREATE DEFINER=`root`@`localhost` FUNCTION `util`.`CURDATE`() RETURNS date
|
||||
DETERMINISTIC
|
||||
BEGIN
|
||||
/**
|
||||
* @return The mock date
|
||||
**/
|
||||
|
||||
RETURN DATE(mockTime());
|
||||
END ;;
|
||||
DELIMITER ;
|
||||
/*!50003 SET sql_mode = @saved_sql_mode */ ;
|
||||
/*!50003 SET character_set_client = @saved_cs_client */ ;
|
||||
/*!50003 SET character_set_results = @saved_cs_results */ ;
|
||||
/*!50003 SET collation_connection = @saved_col_connection */ ;
|
||||
/*!50003 DROP FUNCTION IF EXISTS `mockTime` */;
|
||||
/*!50003 SET @saved_cs_client = @@character_set_client */ ;
|
||||
/*!50003 SET @saved_cs_results = @@character_set_results */ ;
|
||||
/*!50003 SET @saved_col_connection = @@collation_connection */ ;
|
||||
/*!50003 SET character_set_client = utf8mb4 */ ;
|
||||
/*!50003 SET character_set_results = utf8mb4 */ ;
|
||||
/*!50003 SET collation_connection = utf8mb4_unicode_ci */ ;
|
||||
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
|
||||
/*!50003 SET sql_mode = 'IGNORE_SPACE,NO_ENGINE_SUBSTITUTION' */ ;
|
||||
DELIMITER ;;
|
||||
CREATE DEFINER=`root`@`localhost` FUNCTION `util`.`mockTime`() RETURNS datetime
|
||||
DETERMINISTIC
|
||||
BEGIN
|
||||
/**
|
||||
* Returns the mockTime with predefined timezone or current dateTime
|
||||
* depending of config.mockEnabled
|
||||
*
|
||||
* @return formatted datetime
|
||||
*/
|
||||
DECLARE vMockEnabled BOOL;
|
||||
|
||||
SELECT mockEnabled INTO vMockEnabled FROM config LIMIT 1;
|
||||
|
||||
IF vMockEnabled THEN
|
||||
RETURN mockTimeBase(FALSE);
|
||||
ELSE
|
||||
RETURN NOW();
|
||||
END IF;
|
||||
END ;;
|
||||
DELIMITER ;
|
||||
/*!50003 SET sql_mode = @saved_sql_mode */ ;
|
||||
/*!50003 SET character_set_client = @saved_cs_client */ ;
|
||||
/*!50003 SET character_set_results = @saved_cs_results */ ;
|
||||
/*!50003 SET collation_connection = @saved_col_connection */ ;
|
||||
/*!50003 DROP FUNCTION IF EXISTS `mockTimeBase` */;
|
||||
/*!50003 SET @saved_cs_client = @@character_set_client */ ;
|
||||
/*!50003 SET @saved_cs_results = @@character_set_results */ ;
|
||||
/*!50003 SET @saved_col_connection = @@collation_connection */ ;
|
||||
/*!50003 SET character_set_client = utf8mb4 */ ;
|
||||
/*!50003 SET character_set_results = utf8mb4 */ ;
|
||||
/*!50003 SET collation_connection = utf8mb4_unicode_ci */ ;
|
||||
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
|
||||
/*!50003 SET sql_mode = 'IGNORE_SPACE,NO_ENGINE_SUBSTITUTION' */ ;
|
||||
DELIMITER ;;
|
||||
CREATE DEFINER=`root`@`localhost` FUNCTION `util`.`mockTimeBase`(vIsUtc BOOL) RETURNS datetime
|
||||
DETERMINISTIC
|
||||
BEGIN
|
||||
/**
|
||||
* Returns the date formatted to utc if vIsUtc or config.mocTz if not
|
||||
*
|
||||
* @param vIsUtc If date must be returned as UTC format
|
||||
* @return The formatted mock time
|
||||
*/
|
||||
DECLARE vMockUtcTime DATETIME;
|
||||
DECLARE vMockTz VARCHAR(255);
|
||||
|
||||
SELECT mockUtcTime, mockTz
|
||||
INTO vMockUtcTime, vMockTz
|
||||
FROM config
|
||||
LIMIT 1;
|
||||
|
||||
IF vIsUtc OR vMockTz IS NULL THEN
|
||||
RETURN vMockUtcTime;
|
||||
ELSE
|
||||
RETURN CONVERT_TZ(vMockUtcTime, '+00:00', vMockTz);
|
||||
END IF;
|
||||
END ;;
|
||||
DELIMITER ;
|
||||
/*!50003 SET sql_mode = @saved_sql_mode */ ;
|
||||
/*!50003 SET character_set_client = @saved_cs_client */ ;
|
||||
/*!50003 SET character_set_results = @saved_cs_results */ ;
|
||||
/*!50003 SET collation_connection = @saved_col_connection */ ;
|
||||
/*!50003 DROP FUNCTION IF EXISTS `firstDayOfYear` */;
|
||||
/*!50003 SET @saved_cs_client = @@character_set_client */ ;
|
||||
/*!50003 SET @saved_cs_results = @@character_set_results */ ;
|
||||
|
@ -32632,7 +32728,7 @@ CREATE TABLE `printQueue` (
|
|||
CONSTRAINT `printQueue_printerFk` FOREIGN KEY (`printerFk`) REFERENCES `printer` (`id`) ON UPDATE CASCADE,
|
||||
CONSTRAINT `printQueue_priorityFk` FOREIGN KEY (`priorityFk`) REFERENCES `queuePriority` (`id`) ON UPDATE CASCADE,
|
||||
CONSTRAINT `printQueue_report` FOREIGN KEY (`reportFk`) REFERENCES `report` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDBDEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
|
@ -68286,11 +68382,11 @@ BEGIN
|
|||
FROM ticketConfig;
|
||||
|
||||
IF vWarehouseInventory IS NULL THEN
|
||||
CALL util.throw('Warehouse inventory not seted');
|
||||
CALL util.throw('Warehouse inventory not set');
|
||||
END IF;
|
||||
|
||||
IF vComponentCost IS NULL THEN
|
||||
CALL util.throw('Component cost not seted');
|
||||
CALL util.throw('Component cost not set');
|
||||
END IF;
|
||||
|
||||
SET vDateEnd = vDated + INTERVAL 1 DAY;
|
||||
|
@ -81124,3 +81220,4 @@ USE `vn`;
|
|||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||
|
||||
-- Dump completed on 2023-02-21 8:14:30
|
||||
|
||||
|
|
|
@ -426,7 +426,8 @@ export default {
|
|||
fourthStarted: 'vn-fixed-price tr:nth-child(5) vn-date-picker[ng-model="price.started"]',
|
||||
fourthEnded: 'vn-fixed-price tr:nth-child(5) vn-date-picker[ng-model="price.ended"]',
|
||||
fourthDeleteIcon: 'vn-fixed-price tr:nth-child(5) > td:nth-child(9) > vn-icon-button[icon="delete"]',
|
||||
orderColumnId: 'vn-fixed-price th[field="itemFk"]'
|
||||
orderColumnId: 'vn-fixed-price th[field="itemFk"]',
|
||||
removeWarehouseFilter: 'vn-searchbar > form > vn-textfield > div.container > div.prepend > prepend > div > span:nth-child(1) > vn-icon > i'
|
||||
},
|
||||
itemCreateView: {
|
||||
temporalName: 'vn-item-create vn-textfield[ng-model="$ctrl.item.provisionalName"]',
|
||||
|
@ -524,7 +525,6 @@ export default {
|
|||
},
|
||||
itemLog: {
|
||||
anyLineCreated: 'vn-item-log > vn-log vn-tbody > vn-tr',
|
||||
fifthLineCreatedProperty: 'vn-item-log > vn-log vn-tbody > vn-tr:nth-child(5) table tr:nth-child(2) td.after',
|
||||
},
|
||||
ticketSummary: {
|
||||
header: 'vn-ticket-summary > vn-card > h5',
|
||||
|
@ -988,6 +988,12 @@ export default {
|
|||
locker: 'vn-worker-basic-data vn-input-number[ng-model="$ctrl.worker.locker"]',
|
||||
saveButton: 'vn-worker-basic-data button[type=submit]'
|
||||
},
|
||||
workerNotes: {
|
||||
addNoteFloatButton: 'vn-worker-note vn-float-button',
|
||||
note: 'vn-textarea[ng-model="$ctrl.note.text"]',
|
||||
saveButton: 'button[type=submit]',
|
||||
firstNoteText: 'vn-worker-note .text'
|
||||
},
|
||||
workerPbx: {
|
||||
extension: 'vn-worker-pbx vn-textfield[ng-model="$ctrl.worker.sip.extension"]',
|
||||
saveButton: 'vn-worker-pbx button[type=submit]'
|
||||
|
@ -1040,7 +1046,6 @@ export default {
|
|||
boss: 'vn-worker-create vn-autocomplete[ng-model="$ctrl.worker.bossFk"]',
|
||||
role: 'vn-worker-create vn-autocomplete[ng-model="$ctrl.worker.roleFk"]',
|
||||
iban: 'vn-worker-create vn-textfield[ng-model="$ctrl.worker.iban"]',
|
||||
switft: 'vn-worker-create vn-autocomplete[ng-model="$ctrl.worker.bankEntityFk"]',
|
||||
createButton: 'vn-worker-create vn-submit[label="Create"]',
|
||||
},
|
||||
workerPda: {
|
||||
|
@ -1052,20 +1057,22 @@ export default {
|
|||
invoiceOutIndex: {
|
||||
topbarSearch: 'vn-searchbar',
|
||||
searchResult: 'vn-invoice-out-index vn-card > vn-table > div > vn-tbody > a.vn-tr',
|
||||
createInvoice: 'vn-invoice-out-index > div > vn-vertical > vn-button > button vn-icon[icon="add"]',
|
||||
createManualInvoice: 'vn-item[name="manualInvoice"]',
|
||||
createGlobalInvoice: 'vn-item[name="globalInvoice"]',
|
||||
createInvoice: 'vn-invoice-out-index > div > vn-button > button vn-icon[icon="add"]',
|
||||
manualInvoiceForm: '.vn-invoice-out-manual',
|
||||
manualInvoiceTicket: 'vn-autocomplete[ng-model="$ctrl.invoice.ticketFk"]',
|
||||
manualInvoiceClient: 'vn-autocomplete[ng-model="$ctrl.invoice.clientFk"]',
|
||||
manualInvoiceSerial: 'vn-autocomplete[ng-model="$ctrl.invoice.serial"]',
|
||||
manualInvoiceTaxArea: 'vn-autocomplete[ng-model="$ctrl.invoice.taxArea"]',
|
||||
saveInvoice: 'button[response="accept"]',
|
||||
globalInvoiceForm: '.vn-invoice-out-global-invoicing',
|
||||
globalInvoiceClientsRange: 'vn-radio[val="clientsRange"]',
|
||||
globalInvoiceDate: '[ng-model="$ctrl.invoice.invoiceDate"]',
|
||||
globalInvoiceFromClient: '[ng-model="$ctrl.invoice.fromClientId"]',
|
||||
globalInvoiceToClient: '[ng-model="$ctrl.invoice.toClientId"]',
|
||||
saveInvoice: 'button[response="accept"]'
|
||||
},
|
||||
invoiceOutGlobalInvoicing: {
|
||||
oneClient: 'vn-invoice-out-global-invoicing vn-side-menu form > vn-vertical > vn-vertical > vn-radio[val="one"]',
|
||||
allClients: 'vn-invoice-out-global-invoicing vn-side-menu form > vn-vertical > vn-vertical > vn-radio[val="all"]',
|
||||
clientId: 'vn-invoice-out-global-invoicing vn-side-menu form > vn-vertical > vn-autocomplete[ng-model="$ctrl.clientId"]',
|
||||
printer: 'vn-invoice-out-global-invoicing vn-side-menu form > vn-vertical > vn-autocomplete[ng-model="$ctrl.printerFk"]',
|
||||
makeInvoice: 'vn-invoice-out-global-invoicing vn-side-menu form > vn-vertical > vn-submit',
|
||||
invoiceDate: 'vn-invoice-out-global-invoicing vn-side-menu form > vn-vertical > vn-date-picker[ng-model="$ctrl.invoiceDate"]',
|
||||
maxShipped: 'vn-invoice-out-global-invoicing vn-side-menu form > vn-vertical > vn-date-picker[ng-model="$ctrl.maxShipped"]'
|
||||
},
|
||||
invoiceOutDescriptor: {
|
||||
moreMenu: 'vn-invoice-out-descriptor vn-icon-button[icon=more_vert]',
|
||||
|
@ -1127,6 +1134,15 @@ export default {
|
|||
saveButton: 'vn-invoice-in-tax vn-submit',
|
||||
|
||||
},
|
||||
invoiceInIndex: {
|
||||
topbarSearchParams: 'vn-searchbar div.search-params > span',
|
||||
},
|
||||
invoiceInSerial: {
|
||||
daysAgo: 'vn-invoice-in-serial-search-panel vn-input-number[ng-model="$ctrl.filter.daysAgo"]',
|
||||
serial: 'vn-invoice-in-serial-search-panel vn-textfield[ng-model="$ctrl.filter.serial"]',
|
||||
chip: 'vn-chip > vn-icon',
|
||||
goToIndex: 'vn-invoice-in-serial vn-icon-button[icon="icon-invoice-in"]',
|
||||
},
|
||||
travelIndex: {
|
||||
anySearchResult: 'vn-travel-index vn-tbody > a',
|
||||
firstSearchResult: 'vn-travel-index vn-tbody > a:nth-child(1)',
|
||||
|
@ -1138,7 +1154,16 @@ export default {
|
|||
landingDate: 'vn-travel-create vn-date-picker[ng-model="$ctrl.travel.landed"]',
|
||||
warehouseOut: 'vn-travel-create vn-autocomplete[ng-model="$ctrl.travel.warehouseOutFk"]',
|
||||
warehouseIn: 'vn-travel-create vn-autocomplete[ng-model="$ctrl.travel.warehouseInFk"]',
|
||||
save: 'vn-travel-create vn-submit > button'
|
||||
save: 'vn-travel-create vn-submit > button',
|
||||
generalSearchFilter: 'vn-travel-search-panel vn-textfield[ng-model="$ctrl.search"]',
|
||||
agencyFilter: 'vn-travel-search-panel vn-autocomplete[ng-model="$ctrl.filter.agencyModeFk"]',
|
||||
warehouseOutFilter: 'vn-travel-search-panel vn-autocomplete[ng-model="$ctrl.filter.warehouseOutFk"]',
|
||||
warehouseInFilter: 'vn-travel-search-panel vn-autocomplete[ng-model="$ctrl.filter.warehouseInFk"]',
|
||||
scopeDaysFilter: 'vn-travel-search-panel vn-input-number[ng-model="$ctrl.filter.scopeDays"]',
|
||||
continentFilter: 'vn-travel-search-panel vn-autocomplete[ng-model="$ctrl.filter.continent"]',
|
||||
totalEntriesFilter: 'vn-travel-search-panel vn-input-number[ng-model="$ctrl.totalEntries"]',
|
||||
chip: 'vn-travel-search-panel vn-chip > vn-icon',
|
||||
|
||||
},
|
||||
travelExtraCommunity: {
|
||||
anySearchResult: 'vn-travel-extra-community > vn-card div > tbody > tr[ng-attr-id="{{::travel.id}}"]',
|
||||
|
|
|
@ -90,7 +90,7 @@ describe('SmartTable SearchBar integration', () => {
|
|||
await page.waitToClick(selectors.itemFixedPrice.orderColumnId);
|
||||
const result = await page.waitToGetProperty(selectors.itemFixedPrice.firstItemID, 'value');
|
||||
|
||||
expect(result).toEqual('13');
|
||||
expect(result).toEqual('3');
|
||||
});
|
||||
|
||||
it('should reload page and have same order', async() => {
|
||||
|
@ -99,7 +99,7 @@ describe('SmartTable SearchBar integration', () => {
|
|||
});
|
||||
const result = await page.waitToGetProperty(selectors.itemFixedPrice.firstItemID, 'value');
|
||||
|
||||
expect(result).toEqual('13');
|
||||
expect(result).toEqual('3');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -28,22 +28,4 @@ describe('Client log path', () => {
|
|||
it('should navigate to the log section', async() => {
|
||||
await page.accessToSection('client.card.log');
|
||||
});
|
||||
|
||||
it('should check the previous value of the last logged change', async() => {
|
||||
let lastModificationPreviousValue = await page
|
||||
.waitToGetProperty(selectors.clientLog.lastModificationPreviousValue, 'innerText');
|
||||
|
||||
expect(lastModificationPreviousValue).toContain('DavidCharlesHaller');
|
||||
});
|
||||
|
||||
it('should check the current value of the last logged change', async() => {
|
||||
let lastModificationPreviousValue = await page
|
||||
.waitToGetProperty(selectors.clientLog.lastModificationPreviousValue, 'innerText');
|
||||
|
||||
let lastModificationCurrentValue = await page.
|
||||
waitToGetProperty(selectors.clientLog.lastModificationCurrentValue, 'innerText');
|
||||
|
||||
expect(lastModificationPreviousValue).toEqual('DavidCharlesHaller');
|
||||
expect(lastModificationCurrentValue).toEqual('this is a test');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -50,7 +50,7 @@ describe('Client defaulter path', () => {
|
|||
expect(message.text).toContain(`The message can't be empty`);
|
||||
});
|
||||
|
||||
it('shoul checked all defaulters', async() => {
|
||||
it('should checked all defaulters', async() => {
|
||||
await page.loginAndModule('insurance', 'client');
|
||||
await page.accessToSection('client.defaulter');
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ describe('Worker time control path', () => {
|
|||
date.setMonth(date.getMonth() + 1);
|
||||
let month = date.toLocaleString('default', {month: 'long'});
|
||||
|
||||
await page.click(selectors.workerTimeControl.nextMonthButton);
|
||||
await page.waitToClick(selectors.workerTimeControl.nextMonthButton);
|
||||
let result = await page.getProperty(selectors.workerTimeControl.monthName, 'innerText');
|
||||
|
||||
expect(result).toContain(month);
|
||||
|
@ -36,7 +36,7 @@ describe('Worker time control path', () => {
|
|||
date.setDate(1);
|
||||
month = date.toLocaleString('default', {month: 'long'});
|
||||
|
||||
await page.click(selectors.workerTimeControl.previousMonthButton);
|
||||
await page.waitToClick(selectors.workerTimeControl.previousMonthButton);
|
||||
result = await page.getProperty(selectors.workerTimeControl.monthName, 'innerText');
|
||||
|
||||
expect(result).toContain(month);
|
||||
|
@ -49,7 +49,7 @@ describe('Worker time control path', () => {
|
|||
|
||||
await page.loginAndModule('salesBoss', 'worker');
|
||||
await page.goto(`http://localhost:5000/#!/worker/${hankPymId}/time-control?timestamp=${timestamp}`);
|
||||
await page.click(selectors.workerTimeControl.secondWeekDay);
|
||||
await page.waitToClick(selectors.workerTimeControl.secondWeekDay);
|
||||
|
||||
result = await page.getProperty(selectors.workerTimeControl.monthName, 'innerText');
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@ describe('Worker create path', () => {
|
|||
await page.write(selectors.workerCreate.street, 'S/ Doomstadt');
|
||||
await page.write(selectors.workerCreate.email, 'doctorDoom@marvel.com');
|
||||
await page.write(selectors.workerCreate.iban, 'ES9121000418450200051332');
|
||||
await page.autocompleteSearch(selectors.workerCreate.switft, 'BBKKESMMMMM');
|
||||
|
||||
// should check for autocompleted worker code and worker user name
|
||||
const workerCode = await page
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
import selectors from '../../helpers/selectors';
|
||||
import getBrowser from '../../helpers/puppeteer';
|
||||
|
||||
describe('Worker Add notes path', () => {
|
||||
let browser;
|
||||
let page;
|
||||
beforeAll(async() => {
|
||||
browser = await getBrowser();
|
||||
page = browser.page;
|
||||
await page.loginAndModule('hr', 'worker');
|
||||
await page.accessToSearchResult('Bruce Banner');
|
||||
await page.accessToSection('worker.card.note.index');
|
||||
});
|
||||
|
||||
afterAll(async() => {
|
||||
await browser.close();
|
||||
});
|
||||
|
||||
it(`should reach the notes index`, async() => {
|
||||
await page.waitForState('worker.card.note.index');
|
||||
});
|
||||
|
||||
it(`should click on the add note button`, async() => {
|
||||
await page.waitToClick(selectors.workerNotes.addNoteFloatButton);
|
||||
await page.waitForState('worker.card.note.create');
|
||||
});
|
||||
|
||||
it(`should create a note`, async() => {
|
||||
await page.waitForSelector(selectors.workerNotes.note);
|
||||
await page.type(`${selectors.workerNotes.note} textarea`, 'Meeting with Black Widow 21st 9am');
|
||||
await page.waitToClick(selectors.workerNotes.saveButton);
|
||||
const message = await page.waitForSnackbar();
|
||||
|
||||
expect(message.text).toContain('Data saved!');
|
||||
});
|
||||
|
||||
it('should confirm the note was created', async() => {
|
||||
const result = await page.waitToGetProperty(selectors.workerNotes.firstNoteText, 'innerText');
|
||||
|
||||
expect(result).toEqual('Meeting with Black Widow 21st 9am');
|
||||
});
|
||||
});
|
|
@ -42,23 +42,4 @@ describe('Item log path', () => {
|
|||
await page.waitForSelector(selectors.itemsIndex.createItemButton);
|
||||
await page.waitForState('item.index');
|
||||
});
|
||||
|
||||
it(`should search for the created item and navigate to it's log section`, async() => {
|
||||
await page.accessToSearchResult('Knowledge artifact');
|
||||
await page.accessToSection('item.card.log');
|
||||
});
|
||||
|
||||
it(`should confirm the log is showing 5 entries`, async() => {
|
||||
await page.waitForSelector(selectors.itemLog.anyLineCreated);
|
||||
const anyLineCreatedCount = await page.countElement(selectors.itemLog.anyLineCreated);
|
||||
|
||||
expect(anyLineCreatedCount).toEqual(5);
|
||||
});
|
||||
|
||||
it(`should confirm the log is showing the intrastat for the created item`, async() => {
|
||||
const fifthLineCreatedProperty = await page
|
||||
.waitToGetProperty(selectors.itemLog.fifthLineCreatedProperty, 'innerText');
|
||||
|
||||
expect(fifthLineCreatedProperty).toEqual('Coral y materiales similares');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -15,8 +15,9 @@ describe('Item fixed prices path', () => {
|
|||
await browser.close();
|
||||
});
|
||||
|
||||
it('should click on the add new foxed price button', async() => {
|
||||
await page.doSearch();
|
||||
it('should click on the add new fixed price button', async() => {
|
||||
await page.waitToClick(selectors.itemFixedPrice.removeWarehouseFilter);
|
||||
await page.waitForSpinnerLoad();
|
||||
await page.waitToClick(selectors.itemFixedPrice.add);
|
||||
await page.waitForSelector(selectors.itemFixedPrice.fourthFixedPrice);
|
||||
});
|
||||
|
@ -37,7 +38,8 @@ describe('Item fixed prices path', () => {
|
|||
it('should reload the section and check the created price has the expected ID', async() => {
|
||||
await page.accessToSection('item.index');
|
||||
await page.accessToSection('item.fixedPrice');
|
||||
await page.doSearch();
|
||||
await page.waitToClick(selectors.itemFixedPrice.removeWarehouseFilter);
|
||||
await page.waitForSpinnerLoad();
|
||||
|
||||
const result = await page.waitToGetProperty(selectors.itemFixedPrice.fourthItemID, 'value');
|
||||
|
||||
|
|
|
@ -197,6 +197,7 @@ describe('Ticket Edit sale path', () => {
|
|||
});
|
||||
|
||||
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);
|
||||
|
@ -248,6 +249,7 @@ describe('Ticket Edit sale path', () => {
|
|||
await page.waitToClick(selectors.ticketSales.thirdSaleCheckbox);
|
||||
await page.waitToClick(selectors.ticketSales.moreMenu);
|
||||
await page.waitToClick(selectors.ticketSales.moreMenuCreateClaim);
|
||||
await page.waitToClick(selectors.globalItems.acceptButton);
|
||||
await page.waitForState('claim.card.basicData');
|
||||
});
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ describe('Ticket Create notes path', () => {
|
|||
browser = await getBrowser();
|
||||
page = browser.page;
|
||||
await page.loginAndModule('employee', 'ticket');
|
||||
await page.accessToSearchResult('1');
|
||||
await page.accessToSearchResult('5');
|
||||
await page.accessToSection('ticket.card.observation');
|
||||
});
|
||||
|
||||
|
|
|
@ -29,20 +29,4 @@ describe('Ticket expeditions and log path', () => {
|
|||
|
||||
expect(result).toEqual(3);
|
||||
});
|
||||
|
||||
it(`should confirm the expedition deleted is shown now in the ticket log`, async() => {
|
||||
await page.accessToSection('ticket.card.log');
|
||||
const user = await page
|
||||
.waitToGetProperty(selectors.ticketLog.user, 'innerText');
|
||||
|
||||
const action = await page
|
||||
.waitToGetProperty(selectors.ticketLog.action, 'innerText');
|
||||
|
||||
const id = await page
|
||||
.waitToGetProperty(selectors.ticketLog.id, 'innerText');
|
||||
|
||||
expect(user).toContain('production');
|
||||
expect(action).toContain('Deletes');
|
||||
expect(id).toEqual('2');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -31,30 +31,4 @@ describe('Ticket log path', () => {
|
|||
|
||||
expect(message.text).toContain('Data saved!');
|
||||
});
|
||||
|
||||
it('should navigate to the log section', async() => {
|
||||
await page.accessToSection('ticket.card.log');
|
||||
});
|
||||
|
||||
it('should set the viewport width to 1920 to see the table full width', async() => {
|
||||
await page.setViewport({
|
||||
width: 1920,
|
||||
height: 0,
|
||||
});
|
||||
|
||||
const result = await page.waitToGetProperty(selectors.ticketLog.firstTD, 'innerText');
|
||||
|
||||
expect(result.length).not.toBeGreaterThan('20');
|
||||
});
|
||||
|
||||
it('should set the viewport width to 800 to see the table shrink and move data to the 1st column', async() => {
|
||||
await page.setViewport({
|
||||
width: 800,
|
||||
height: 0,
|
||||
});
|
||||
|
||||
const result = await page.waitToGetProperty(selectors.ticketLog.firstTD, 'innerText');
|
||||
|
||||
expect(result.length).toBeGreaterThan('15');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -54,7 +54,7 @@ describe('Ticket Future path', () => {
|
|||
it('should search with the origin IPT', async() => {
|
||||
await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
|
||||
|
||||
await page.autocompleteSearch(selectors.ticketFuture.ipt, 'Horizontal');
|
||||
await page.autocompleteSearch(selectors.ticketFuture.ipt, 'H');
|
||||
await page.waitToClick(selectors.ticketFuture.submit);
|
||||
|
||||
expect(httpRequest).toContain('ipt=H');
|
||||
|
@ -65,7 +65,7 @@ describe('Ticket Future path', () => {
|
|||
|
||||
await page.clearInput(selectors.ticketFuture.ipt);
|
||||
|
||||
await page.autocompleteSearch(selectors.ticketFuture.futureIpt, 'Horizontal');
|
||||
await page.autocompleteSearch(selectors.ticketFuture.futureIpt, 'H');
|
||||
await page.waitToClick(selectors.ticketFuture.submit);
|
||||
|
||||
expect(httpRequest).toContain('futureIpt=H');
|
||||
|
@ -108,7 +108,7 @@ describe('Ticket Future path', () => {
|
|||
|
||||
it('should search in smart-table with an IPT Destination', async() => {
|
||||
await page.waitToClick(selectors.ticketFuture.tableButtonSearch);
|
||||
await page.autocompleteSearch(selectors.ticketFuture.tableFutureIpt, 'Horizontal');
|
||||
await page.autocompleteSearch(selectors.ticketFuture.tableFutureIpt, 'H');
|
||||
|
||||
expect(httpRequest).toContain('futureIpt');
|
||||
await page.waitToClick(selectors.ticketFuture.tableButtonSearch);
|
||||
|
|
|
@ -54,7 +54,7 @@ describe('Ticket Advance path', () => {
|
|||
|
||||
it('should search with the origin IPT', async() => {
|
||||
await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
|
||||
await page.autocompleteSearch(selectors.ticketAdvance.futureIpt, 'Horizontal');
|
||||
await page.autocompleteSearch(selectors.ticketAdvance.futureIpt, 'H');
|
||||
await page.waitToClick(selectors.ticketAdvance.submit);
|
||||
|
||||
expect(httpRequest).toContain('futureIpt=H');
|
||||
|
@ -66,7 +66,7 @@ describe('Ticket Advance path', () => {
|
|||
|
||||
it('should search with the destination IPT', async() => {
|
||||
await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
|
||||
await page.autocompleteSearch(selectors.ticketAdvance.ipt, 'Horizontal');
|
||||
await page.autocompleteSearch(selectors.ticketAdvance.ipt, 'H');
|
||||
await page.waitToClick(selectors.ticketAdvance.submit);
|
||||
|
||||
expect(httpRequest).toContain('ipt=H');
|
||||
|
@ -78,7 +78,7 @@ describe('Ticket Advance path', () => {
|
|||
|
||||
it('should search in smart-table with an IPT Origin', async() => {
|
||||
await page.waitToClick(selectors.ticketAdvance.tableButtonSearch);
|
||||
await page.autocompleteSearch(selectors.ticketAdvance.tableFutureIpt, 'Vertical');
|
||||
await page.autocompleteSearch(selectors.ticketAdvance.tableFutureIpt, 'V');
|
||||
|
||||
expect(httpRequest).toContain('futureIpt');
|
||||
|
||||
|
@ -89,7 +89,7 @@ describe('Ticket Advance path', () => {
|
|||
|
||||
it('should search in smart-table with an IPT Destination', async() => {
|
||||
await page.waitToClick(selectors.ticketAdvance.tableButtonSearch);
|
||||
await page.autocompleteSearch(selectors.ticketAdvance.tableIpt, 'Vertical');
|
||||
await page.autocompleteSearch(selectors.ticketAdvance.tableIpt, 'V');
|
||||
|
||||
expect(httpRequest).toContain('ipt');
|
||||
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
import getBrowser from '../../helpers/puppeteer';
|
||||
|
||||
describe('InvoiceIn negative bases path', () => {
|
||||
let browser;
|
||||
let page;
|
||||
const httpRequests = [];
|
||||
|
||||
beforeAll(async() => {
|
||||
browser = await getBrowser();
|
||||
page = browser.page;
|
||||
page.on('request', req => {
|
||||
if (req.url().includes(`InvoiceIns/negativeBases`))
|
||||
httpRequests.push(req.url());
|
||||
});
|
||||
await page.loginAndModule('administrative', 'invoiceIn');
|
||||
await page.accessToSection('invoiceIn.negative-bases');
|
||||
});
|
||||
|
||||
afterAll(async() => {
|
||||
await browser.close();
|
||||
});
|
||||
|
||||
it('should show negative bases in a date range', async() => {
|
||||
const request = httpRequests.find(req =>
|
||||
req.includes(`from`) && req.includes(`to`));
|
||||
|
||||
expect(request).toBeDefined();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,48 @@
|
|||
import selectors from '../../helpers/selectors.js';
|
||||
import getBrowser from '../../helpers/puppeteer';
|
||||
|
||||
describe('InvoiceIn serial path', () => {
|
||||
let browser;
|
||||
let page;
|
||||
let httpRequest;
|
||||
|
||||
beforeAll(async() => {
|
||||
browser = await getBrowser();
|
||||
page = browser.page;
|
||||
await page.loginAndModule('administrative', 'invoiceIn');
|
||||
await page.accessToSection('invoiceIn.serial');
|
||||
page.on('request', req => {
|
||||
if (req.url().includes(`InvoiceIns/getSerial`))
|
||||
httpRequest = req.url();
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(async() => {
|
||||
await browser.close();
|
||||
});
|
||||
|
||||
it('should check that passes the correct params to back', async() => {
|
||||
await page.overwrite(selectors.invoiceInSerial.daysAgo, '30');
|
||||
await page.keyboard.press('Enter');
|
||||
|
||||
expect(httpRequest).toContain('daysAgo=30');
|
||||
|
||||
await page.overwrite(selectors.invoiceInSerial.serial, 'R');
|
||||
await page.keyboard.press('Enter');
|
||||
|
||||
expect(httpRequest).toContain('serial=R');
|
||||
await page.click(selectors.invoiceInSerial.chip);
|
||||
});
|
||||
|
||||
it('should go to index and check if the search-panel has the correct params', async() => {
|
||||
await page.click(selectors.invoiceInSerial.goToIndex);
|
||||
const params = await page.$$(selectors.invoiceInIndex.topbarSearchParams);
|
||||
const serial = await params[0].getProperty('title');
|
||||
const isBooked = await params[1].getProperty('title');
|
||||
const from = await params[2].getProperty('title');
|
||||
|
||||
expect(await serial.jsonValue()).toContain('serial');
|
||||
expect(await isBooked.jsonValue()).toContain('not isBooked');
|
||||
expect(await from.jsonValue()).toContain('from');
|
||||
});
|
||||
});
|
|
@ -17,7 +17,6 @@ describe('InvoiceOut manual invoice path', () => {
|
|||
|
||||
it('should open the manual invoice form', async() => {
|
||||
await page.waitToClick(selectors.invoiceOutIndex.createInvoice);
|
||||
await page.waitToClick(selectors.invoiceOutIndex.createManualInvoice);
|
||||
await page.waitForSelector(selectors.invoiceOutIndex.manualInvoiceForm);
|
||||
});
|
||||
|
||||
|
@ -45,7 +44,6 @@ describe('InvoiceOut manual invoice path', () => {
|
|||
|
||||
it('should now open the manual invoice form', async() => {
|
||||
await page.waitToClick(selectors.invoiceOutIndex.createInvoice);
|
||||
await page.waitToClick(selectors.invoiceOutIndex.createManualInvoice);
|
||||
await page.waitForSelector(selectors.invoiceOutIndex.manualInvoiceForm);
|
||||
});
|
||||
|
||||
|
|
|
@ -17,47 +17,27 @@ describe('InvoiceOut global invoice path', () => {
|
|||
await browser.close();
|
||||
});
|
||||
|
||||
let invoicesBefore;
|
||||
let invoicesBeforeOneClient;
|
||||
let invoicesBeforeAllClients;
|
||||
let now = Date.vnNew();
|
||||
|
||||
it('should count the amount of invoices listed before globla invoces are made', async() => {
|
||||
invoicesBefore = await page.countElement(selectors.invoiceOutIndex.searchResult);
|
||||
invoicesBeforeOneClient = await page.countElement(selectors.invoiceOutIndex.searchResult);
|
||||
|
||||
expect(invoicesBefore).toBeGreaterThanOrEqual(4);
|
||||
expect(invoicesBeforeOneClient).toBeGreaterThanOrEqual(4);
|
||||
});
|
||||
|
||||
it('should open the global invoice form', async() => {
|
||||
await page.waitToClick(selectors.invoiceOutIndex.createInvoice);
|
||||
await page.waitToClick(selectors.invoiceOutIndex.createGlobalInvoice);
|
||||
await page.waitForSelector(selectors.invoiceOutIndex.globalInvoiceForm);
|
||||
await page.accessToSection('invoiceOut.global-invoicing');
|
||||
});
|
||||
|
||||
it('should create a global invoice for charles xavier today', async() => {
|
||||
await page.pickDate(selectors.invoiceOutIndex.globalInvoiceDate);
|
||||
await page.waitToClick(selectors.invoiceOutIndex.globalInvoiceClientsRange);
|
||||
await page.autocompleteSearch(selectors.invoiceOutIndex.globalInvoiceFromClient, 'Petter Parker');
|
||||
await page.autocompleteSearch(selectors.invoiceOutIndex.globalInvoiceToClient, 'Petter Parker');
|
||||
await page.waitToClick(selectors.invoiceOutIndex.saveInvoice);
|
||||
const message = await page.waitForSnackbar();
|
||||
|
||||
expect(message.text).toContain('Data saved!');
|
||||
});
|
||||
|
||||
it('should count the amount of invoices listed after globla invocing', async() => {
|
||||
await page.waitToClick('[icon="search"]');
|
||||
await page.waitForTimeout(1000); // index search needs time to return results
|
||||
const currentInvoices = await page.countElement(selectors.invoiceOutIndex.searchResult);
|
||||
|
||||
expect(currentInvoices).toBeGreaterThan(invoicesBefore);
|
||||
});
|
||||
|
||||
it('should create a global invoice for all clients today', async() => {
|
||||
await page.waitToClick(selectors.invoiceOutIndex.createInvoice);
|
||||
await page.waitToClick(selectors.invoiceOutIndex.createGlobalInvoice);
|
||||
await page.waitForSelector(selectors.invoiceOutIndex.globalInvoiceForm);
|
||||
await page.pickDate(selectors.invoiceOutIndex.globalInvoiceDate);
|
||||
await page.waitToClick(selectors.invoiceOutIndex.saveInvoice);
|
||||
const message = await page.waitForSnackbar();
|
||||
|
||||
expect(message.text).toContain('Data saved!');
|
||||
await page.waitToClick(selectors.invoiceOutGlobalInvoicing.oneClient);
|
||||
await page.autocompleteSearch(selectors.invoiceOutGlobalInvoicing.clientId, '1108');
|
||||
await page.pickDate(selectors.invoiceOutGlobalInvoicing.invoiceDate, now);
|
||||
await page.pickDate(selectors.invoiceOutGlobalInvoicing.maxShipped, now);
|
||||
await page.autocompleteSearch(selectors.invoiceOutGlobalInvoicing.printer, '1');
|
||||
await page.waitToClick(selectors.invoiceOutGlobalInvoicing.makeInvoice);
|
||||
await page.waitForTimeout(1000);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -9,7 +9,8 @@ describe('Travel basic data path', () => {
|
|||
browser = await getBrowser();
|
||||
page = browser.page;
|
||||
await page.loginAndModule('buyer', 'travel');
|
||||
await page.accessToSearchResult('3');
|
||||
await page.write(selectors.travelIndex.generalSearchFilter, '3');
|
||||
await page.keyboard.press('Enter');
|
||||
await page.accessToSection('travel.card.basicData');
|
||||
});
|
||||
|
||||
|
@ -89,11 +90,13 @@ describe('Travel basic data path', () => {
|
|||
});
|
||||
|
||||
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!');
|
||||
|
|
|
@ -9,7 +9,8 @@ describe('Travel descriptor path', () => {
|
|||
browser = await getBrowser();
|
||||
page = browser.page;
|
||||
await page.loginAndModule('buyer', 'travel');
|
||||
await page.accessToSearchResult('1');
|
||||
await page.write(selectors.travelIndex.generalSearchFilter, '1');
|
||||
await page.keyboard.press('Enter');
|
||||
await page.waitForState('travel.card.summary');
|
||||
});
|
||||
|
||||
|
@ -81,7 +82,8 @@ describe('Travel descriptor path', () => {
|
|||
await page.waitToClick('.cancel');
|
||||
await page.waitToClick(selectors.globalItems.homeButton);
|
||||
await page.selectModule('travel');
|
||||
await page.accessToSearchResult('3');
|
||||
await page.write(selectors.travelIndex.generalSearchFilter, '3');
|
||||
await page.keyboard.press('Enter');
|
||||
await page.waitForState('travel.card.summary');
|
||||
const state = await page.getState();
|
||||
|
||||
|
|
|
@ -10,7 +10,8 @@ describe('Travel thermograph path', () => {
|
|||
browser = await getBrowser();
|
||||
page = browser.page;
|
||||
await page.loginAndModule('buyer', 'travel');
|
||||
await page.accessToSearchResult('3');
|
||||
await page.write(selectors.travelIndex.generalSearchFilter, '3');
|
||||
await page.keyboard.press('Enter');
|
||||
await page.accessToSection('travel.card.thermograph.index');
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
import selectors from '../../helpers/selectors.js';
|
||||
import getBrowser from '../../helpers/puppeteer';
|
||||
|
||||
describe('Travel search panel path', () => {
|
||||
let browser;
|
||||
let page;
|
||||
let httpRequest;
|
||||
|
||||
beforeAll(async() => {
|
||||
browser = await getBrowser();
|
||||
page = browser.page;
|
||||
await page.loginAndModule('buyer', 'travel');
|
||||
page.on('request', req => {
|
||||
if (req.url().includes(`Travels/filter`))
|
||||
httpRequest = req.url();
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(async() => {
|
||||
await browser.close();
|
||||
});
|
||||
|
||||
it('should filter using all the fields', async() => {
|
||||
await page.click(selectors.travelIndex.chip);
|
||||
await page.write(selectors.travelIndex.generalSearchFilter, 'travel');
|
||||
await page.keyboard.press('Enter');
|
||||
|
||||
expect(httpRequest).toContain('search=travel');
|
||||
|
||||
await page.click(selectors.travelIndex.chip);
|
||||
await page.autocompleteSearch(selectors.travelIndex.agencyFilter, 'Entanglement');
|
||||
|
||||
expect(httpRequest).toContain('agencyModeFk');
|
||||
|
||||
await page.click(selectors.travelIndex.chip);
|
||||
await page.autocompleteSearch(selectors.travelIndex.warehouseOutFilter, 'Warehouse One');
|
||||
|
||||
expect(httpRequest).toContain('warehouseOutFk');
|
||||
|
||||
await page.click(selectors.travelIndex.chip);
|
||||
await page.autocompleteSearch(selectors.travelIndex.warehouseInFilter, 'Warehouse Two');
|
||||
|
||||
expect(httpRequest).toContain('warehouseInFk');
|
||||
|
||||
await page.click(selectors.travelIndex.chip);
|
||||
await page.overwrite(selectors.travelIndex.scopeDaysFilter, '15');
|
||||
await page.keyboard.press('Enter');
|
||||
|
||||
expect(httpRequest).toContain('scopeDays=15');
|
||||
|
||||
await page.click(selectors.travelIndex.chip);
|
||||
await page.autocompleteSearch(selectors.travelIndex.continentFilter, 'Asia');
|
||||
|
||||
expect(httpRequest).toContain('continent');
|
||||
|
||||
await page.click(selectors.travelIndex.chip);
|
||||
await page.write(selectors.travelIndex.totalEntriesFilter, '1');
|
||||
await page.keyboard.press('Enter');
|
||||
|
||||
expect(httpRequest).toContain('totalEntries=1');
|
||||
});
|
||||
});
|
|
@ -29,14 +29,4 @@ describe('Zone descriptor path', () => {
|
|||
|
||||
expect(count).toEqual(0);
|
||||
});
|
||||
|
||||
it('should check the ticket whom lost the zone and see evidence on the logs', async() => {
|
||||
await page.waitToClick(selectors.globalItems.homeButton);
|
||||
await page.selectModule('ticket');
|
||||
await page.accessToSearchResult('20');
|
||||
await page.accessToSection('ticket.card.log');
|
||||
const lastChanges = await page.waitToGetProperty(selectors.ticketLog.changes, 'innerText');
|
||||
|
||||
expect(lastChanges).toContain('Arreglar');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -64,14 +64,4 @@ describe('Supplier basic data path', () => {
|
|||
|
||||
expect(result).toEqual('Some notes');
|
||||
});
|
||||
|
||||
it('should navigate to the log section', async() => {
|
||||
await page.accessToSection('supplier.card.log');
|
||||
});
|
||||
|
||||
it('should check the changes have been recorded', async() => {
|
||||
const result = await page.waitToGetProperty('vn-tr table tr:nth-child(3) td.after', 'innerText');
|
||||
|
||||
expect(result).toEqual('Some notes');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -15,9 +15,9 @@ export default class Calendar extends FormInput {
|
|||
constructor($element, $scope, vnWeekDays, moment) {
|
||||
super($element, $scope);
|
||||
this.weekDays = vnWeekDays.locales;
|
||||
this.defaultDate = Date.vnNew();
|
||||
this.displayControls = true;
|
||||
this.moment = moment;
|
||||
this.defaultDate = Date.vnNew();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -114,12 +114,14 @@ export default class Calendar extends FormInput {
|
|||
let day = date.getDate();
|
||||
let wday = date.getDay();
|
||||
let month = date.getMonth();
|
||||
let year = date.getFullYear();
|
||||
|
||||
const currentDay = Date.vnNew().getDate();
|
||||
const currentMonth = Date.vnNew().getMonth();
|
||||
const currentYear = Date.vnNew().getFullYear();
|
||||
|
||||
let classes = {
|
||||
today: day === currentDay && month === currentMonth,
|
||||
today: day === currentDay && month === currentMonth && year === currentYear,
|
||||
weekend: wday === 6 || wday === 0,
|
||||
previous: month < this.month,
|
||||
current: month == this.month,
|
||||
|
@ -207,14 +209,23 @@ export default class Calendar extends FormInput {
|
|||
}
|
||||
|
||||
repeatLast() {
|
||||
if (!this.formatDay) return;
|
||||
if (this.formatDay) {
|
||||
const days = this.element.querySelectorAll('.days > .day');
|
||||
for (let i = 0; i < days.length; i++) {
|
||||
this.formatDay({
|
||||
$day: this.days[i],
|
||||
$element: days[i]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let days = this.element.querySelectorAll('.days > .day');
|
||||
for (let i = 0; i < days.length; i++) {
|
||||
this.formatDay({
|
||||
$day: this.days[i],
|
||||
$element: days[i]
|
||||
});
|
||||
if (this.formatWeek) {
|
||||
const weeks = this.element.querySelectorAll('.weeks > .day');
|
||||
for (const week of weeks) {
|
||||
this.formatWeek({
|
||||
$element: week
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -228,6 +239,7 @@ ngModule.vnComponent('vnCalendar', {
|
|||
hasEvents: '&?',
|
||||
getClass: '&?',
|
||||
formatDay: '&?',
|
||||
formatWeek: '&?',
|
||||
displayControls: '<?',
|
||||
hideYear: '<?',
|
||||
hideContiguous: '<?',
|
||||
|
|
|
@ -26,7 +26,7 @@ Value should have at most %s characters: El valor debe tener un máximo de %s ca
|
|||
Enter a new search: Introduce una nueva búsqueda
|
||||
No results: Sin resultados
|
||||
Ups! It seems there was an error: ¡Vaya! Parece que ha habido un error
|
||||
General search: Busqueda general
|
||||
General search: Búsqueda general
|
||||
January: Enero
|
||||
February: Febrero
|
||||
March: Marzo
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
$font-size: 11pt;
|
||||
$menu-width: 256px;
|
||||
$right-menu-width: 318px;
|
||||
$topbar-height: 56px;
|
||||
$mobile-width: 800px;
|
||||
$float-spacing: 20px;
|
||||
|
|
|
@ -25,8 +25,7 @@
|
|||
},
|
||||
"node_modules/@uirouter/angularjs": {
|
||||
"version": "1.0.30",
|
||||
"resolved": "https://registry.npmjs.org/@uirouter/angularjs/-/angularjs-1.0.30.tgz",
|
||||
"integrity": "sha512-qkc3RFZc91S5K0gc/QVAXc9LGDPXjR04vDgG/11j8+yyZEuQojXxKxdLhKIepiPzqLmGRVqzBmBc27gtqaEeZg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@uirouter/core": "6.0.8"
|
||||
},
|
||||
|
@ -39,28 +38,22 @@
|
|||
},
|
||||
"node_modules/@uirouter/core": {
|
||||
"version": "6.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@uirouter/core/-/core-6.0.8.tgz",
|
||||
"integrity": "sha512-Gc/BAW47i4L54p8dqYCJJZuv2s3tqlXQ0fvl6Zp2xrblELPVfxmjnc0eurx3XwfQdaqm3T6uls6tQKkof/4QMw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/angular": {
|
||||
"version": "1.8.3",
|
||||
"resolved": "https://registry.npmjs.org/angular/-/angular-1.8.3.tgz",
|
||||
"integrity": "sha512-5qjkWIQQVsHj4Sb5TcEs4WZWpFeVFHXwxEBHUhrny41D8UrBAd6T/6nPPAsLngJCReIOqi95W3mxdveveutpZw==",
|
||||
"deprecated": "For the actively supported Angular, see https://www.npmjs.com/package/@angular/core. AngularJS support has officially ended. For extended AngularJS support options, see https://goo.gle/angularjs-path-forward."
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/angular-animate": {
|
||||
"version": "1.8.2",
|
||||
"resolved": "https://registry.npmjs.org/angular-animate/-/angular-animate-1.8.2.tgz",
|
||||
"integrity": "sha512-Jbr9+grNMs9Kj57xuBU3Ju3NOPAjS1+g2UAwwDv7su1lt0/PLDy+9zEwDiu8C8xJceoTbmBNKiWGPJGBdCQLlA==",
|
||||
"deprecated": "For the actively supported Angular, see https://www.npmjs.com/package/@angular/core. AngularJS support has officially ended. For extended AngularJS support options, see https://goo.gle/angularjs-path-forward."
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/angular-moment": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/angular-moment/-/angular-moment-1.3.0.tgz",
|
||||
"integrity": "sha512-KG8rvO9MoaBLwtGnxTeUveSyNtrL+RNgGl1zqWN36+HDCCVGk2DGWOzqKWB6o+eTTbO3Opn4hupWKIElc8XETA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"moment": ">=2.8.0 <3.0.0"
|
||||
},
|
||||
|
@ -70,8 +63,7 @@
|
|||
},
|
||||
"node_modules/angular-translate": {
|
||||
"version": "2.19.0",
|
||||
"resolved": "https://registry.npmjs.org/angular-translate/-/angular-translate-2.19.0.tgz",
|
||||
"integrity": "sha512-Z/Fip5uUT2N85dPQ0sMEe1JdF5AehcDe4tg/9mWXNDVU531emHCg53ZND9Oe0dyNiGX5rWcJKmsL1Fujus1vGQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"angular": "^1.8.0"
|
||||
},
|
||||
|
@ -81,29 +73,25 @@
|
|||
},
|
||||
"node_modules/angular-translate-loader-partial": {
|
||||
"version": "2.19.0",
|
||||
"resolved": "https://registry.npmjs.org/angular-translate-loader-partial/-/angular-translate-loader-partial-2.19.0.tgz",
|
||||
"integrity": "sha512-NnMw13LMV4bPQmJK7/pZOZAnPxe0M5OtUHchADs5Gye7V7feonuEnrZ8e1CKhBlv9a7IQyWoqcBa4Lnhg8gk5w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"angular-translate": "~2.19.0"
|
||||
}
|
||||
},
|
||||
"node_modules/argparse": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
|
||||
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"sprintf-js": "~1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/croppie": {
|
||||
"version": "2.6.5",
|
||||
"resolved": "https://registry.npmjs.org/croppie/-/croppie-2.6.5.tgz",
|
||||
"integrity": "sha512-IlChnVUGG5T3w2gRZIaQgBtlvyuYnlUWs2YZIXXR3H9KrlO1PtBT3j+ykxvy9eZIWhk+V5SpBmhCQz5UXKrEKQ=="
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/esprima": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
||||
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
|
||||
"license": "BSD-2-Clause",
|
||||
"bin": {
|
||||
"esparse": "bin/esparse.js",
|
||||
"esvalidate": "bin/esvalidate.js"
|
||||
|
@ -114,8 +102,7 @@
|
|||
},
|
||||
"node_modules/js-yaml": {
|
||||
"version": "3.14.1",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
|
||||
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"argparse": "^1.0.7",
|
||||
"esprima": "^4.0.0"
|
||||
|
@ -126,42 +113,36 @@
|
|||
},
|
||||
"node_modules/mg-crud": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/mg-crud/-/mg-crud-1.1.2.tgz",
|
||||
"integrity": "sha512-mAR6t0aQHKnT0QHKHpLOi0kNPZfO36iMpIoiLjFHxuio6mIJyuveBJ4VNlNXJRxLh32/FLADEb41/sYo7QUKFw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"angular": "^1.6.1"
|
||||
}
|
||||
},
|
||||
"node_modules/moment": {
|
||||
"version": "2.29.4",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
|
||||
"integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/oclazyload": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/oclazyload/-/oclazyload-0.6.3.tgz",
|
||||
"integrity": "sha512-HpOSYUgjtt6sTB/C6+FWsExR+9HCnXKsUA96RWkDXfv11C8Cc9X2DlR0WIZwFIiG6FQU0pwB5dhoYyut8bFAOQ=="
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/require-yaml": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/require-yaml/-/require-yaml-0.0.1.tgz",
|
||||
"integrity": "sha512-M6eVEgLPRbeOhgSCnOTtdrOOEQzbXRchg24Xa13c39dMuraFKdI9emUo97Rih0YEFzSICmSKg8w4RQp+rd9pOQ==",
|
||||
"license": "BSD",
|
||||
"dependencies": {
|
||||
"js-yaml": ""
|
||||
}
|
||||
},
|
||||
"node_modules/require-yaml/node_modules/argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
|
||||
"license": "Python-2.0"
|
||||
},
|
||||
"node_modules/require-yaml/node_modules/js-yaml": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
||||
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"argparse": "^2.0.1"
|
||||
},
|
||||
|
@ -171,13 +152,11 @@
|
|||
},
|
||||
"node_modules/sprintf-js": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
||||
"integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/validator": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/validator/-/validator-6.3.0.tgz",
|
||||
"integrity": "sha512-BylxTwhqwjQI5MDJF7amCy/L0ejJO+74DvCsLV52Lq3+3bhVcVMKqNqOiNcQJm2G48u9EAcw4xFERAmFbwXM9Q==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
|
@ -186,73 +165,51 @@
|
|||
"dependencies": {
|
||||
"@uirouter/angularjs": {
|
||||
"version": "1.0.30",
|
||||
"resolved": "https://registry.npmjs.org/@uirouter/angularjs/-/angularjs-1.0.30.tgz",
|
||||
"integrity": "sha512-qkc3RFZc91S5K0gc/QVAXc9LGDPXjR04vDgG/11j8+yyZEuQojXxKxdLhKIepiPzqLmGRVqzBmBc27gtqaEeZg==",
|
||||
"requires": {
|
||||
"@uirouter/core": "6.0.8"
|
||||
}
|
||||
},
|
||||
"@uirouter/core": {
|
||||
"version": "6.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@uirouter/core/-/core-6.0.8.tgz",
|
||||
"integrity": "sha512-Gc/BAW47i4L54p8dqYCJJZuv2s3tqlXQ0fvl6Zp2xrblELPVfxmjnc0eurx3XwfQdaqm3T6uls6tQKkof/4QMw=="
|
||||
"version": "6.0.8"
|
||||
},
|
||||
"angular": {
|
||||
"version": "1.8.3",
|
||||
"resolved": "https://registry.npmjs.org/angular/-/angular-1.8.3.tgz",
|
||||
"integrity": "sha512-5qjkWIQQVsHj4Sb5TcEs4WZWpFeVFHXwxEBHUhrny41D8UrBAd6T/6nPPAsLngJCReIOqi95W3mxdveveutpZw=="
|
||||
"version": "1.8.3"
|
||||
},
|
||||
"angular-animate": {
|
||||
"version": "1.8.2",
|
||||
"resolved": "https://registry.npmjs.org/angular-animate/-/angular-animate-1.8.2.tgz",
|
||||
"integrity": "sha512-Jbr9+grNMs9Kj57xuBU3Ju3NOPAjS1+g2UAwwDv7su1lt0/PLDy+9zEwDiu8C8xJceoTbmBNKiWGPJGBdCQLlA=="
|
||||
"version": "1.8.2"
|
||||
},
|
||||
"angular-moment": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/angular-moment/-/angular-moment-1.3.0.tgz",
|
||||
"integrity": "sha512-KG8rvO9MoaBLwtGnxTeUveSyNtrL+RNgGl1zqWN36+HDCCVGk2DGWOzqKWB6o+eTTbO3Opn4hupWKIElc8XETA==",
|
||||
"requires": {
|
||||
"moment": ">=2.8.0 <3.0.0"
|
||||
}
|
||||
},
|
||||
"angular-translate": {
|
||||
"version": "2.19.0",
|
||||
"resolved": "https://registry.npmjs.org/angular-translate/-/angular-translate-2.19.0.tgz",
|
||||
"integrity": "sha512-Z/Fip5uUT2N85dPQ0sMEe1JdF5AehcDe4tg/9mWXNDVU531emHCg53ZND9Oe0dyNiGX5rWcJKmsL1Fujus1vGQ==",
|
||||
"requires": {
|
||||
"angular": "^1.8.0"
|
||||
}
|
||||
},
|
||||
"angular-translate-loader-partial": {
|
||||
"version": "2.19.0",
|
||||
"resolved": "https://registry.npmjs.org/angular-translate-loader-partial/-/angular-translate-loader-partial-2.19.0.tgz",
|
||||
"integrity": "sha512-NnMw13LMV4bPQmJK7/pZOZAnPxe0M5OtUHchADs5Gye7V7feonuEnrZ8e1CKhBlv9a7IQyWoqcBa4Lnhg8gk5w==",
|
||||
"requires": {
|
||||
"angular-translate": "~2.19.0"
|
||||
}
|
||||
},
|
||||
"argparse": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
|
||||
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
|
||||
"requires": {
|
||||
"sprintf-js": "~1.0.2"
|
||||
}
|
||||
},
|
||||
"croppie": {
|
||||
"version": "2.6.5",
|
||||
"resolved": "https://registry.npmjs.org/croppie/-/croppie-2.6.5.tgz",
|
||||
"integrity": "sha512-IlChnVUGG5T3w2gRZIaQgBtlvyuYnlUWs2YZIXXR3H9KrlO1PtBT3j+ykxvy9eZIWhk+V5SpBmhCQz5UXKrEKQ=="
|
||||
"version": "2.6.5"
|
||||
},
|
||||
"esprima": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
||||
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
|
||||
"version": "4.0.1"
|
||||
},
|
||||
"js-yaml": {
|
||||
"version": "3.14.1",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
|
||||
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
|
||||
"requires": {
|
||||
"argparse": "^1.0.7",
|
||||
"esprima": "^4.0.0"
|
||||
|
@ -260,39 +217,27 @@
|
|||
},
|
||||
"mg-crud": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/mg-crud/-/mg-crud-1.1.2.tgz",
|
||||
"integrity": "sha512-mAR6t0aQHKnT0QHKHpLOi0kNPZfO36iMpIoiLjFHxuio6mIJyuveBJ4VNlNXJRxLh32/FLADEb41/sYo7QUKFw==",
|
||||
"requires": {
|
||||
"angular": "^1.6.1"
|
||||
}
|
||||
},
|
||||
"moment": {
|
||||
"version": "2.29.4",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
|
||||
"integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w=="
|
||||
"version": "2.29.4"
|
||||
},
|
||||
"oclazyload": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/oclazyload/-/oclazyload-0.6.3.tgz",
|
||||
"integrity": "sha512-HpOSYUgjtt6sTB/C6+FWsExR+9HCnXKsUA96RWkDXfv11C8Cc9X2DlR0WIZwFIiG6FQU0pwB5dhoYyut8bFAOQ=="
|
||||
"version": "0.6.3"
|
||||
},
|
||||
"require-yaml": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/require-yaml/-/require-yaml-0.0.1.tgz",
|
||||
"integrity": "sha512-M6eVEgLPRbeOhgSCnOTtdrOOEQzbXRchg24Xa13c39dMuraFKdI9emUo97Rih0YEFzSICmSKg8w4RQp+rd9pOQ==",
|
||||
"requires": {
|
||||
"js-yaml": ""
|
||||
},
|
||||
"dependencies": {
|
||||
"argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
|
||||
"version": "2.0.1"
|
||||
},
|
||||
"js-yaml": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
||||
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
||||
"requires": {
|
||||
"argparse": "^2.0.1"
|
||||
}
|
||||
|
@ -300,14 +245,10 @@
|
|||
}
|
||||
},
|
||||
"sprintf-js": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
||||
"integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="
|
||||
"version": "1.0.3"
|
||||
},
|
||||
"validator": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/validator/-/validator-6.3.0.tgz",
|
||||
"integrity": "sha512-BylxTwhqwjQI5MDJF7amCy/L0ejJO+74DvCsLV52Lq3+3bhVcVMKqNqOiNcQJm2G48u9EAcw4xFERAmFbwXM9Q=="
|
||||
"version": "6.3.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,13 +88,13 @@ vn-layout {
|
|||
}
|
||||
&.right-menu {
|
||||
& > vn-topbar > .end {
|
||||
width: 80px + $menu-width;
|
||||
width: 80px + $right-menu-width;
|
||||
}
|
||||
& > .main-view {
|
||||
padding-right: $menu-width;
|
||||
padding-right: $right-menu-width;
|
||||
}
|
||||
[fixed-bottom-right] {
|
||||
right: $menu-width;
|
||||
right: $right-menu-width;
|
||||
}
|
||||
}
|
||||
& > .main-view {
|
||||
|
|
|
@ -162,14 +162,8 @@ export default class UploadPhoto extends Component {
|
|||
if (!this.newPhoto.files)
|
||||
throw new Error(`Select an image`);
|
||||
|
||||
const viewportType = this.viewportSelection;
|
||||
const output = viewportType.output;
|
||||
const options = {
|
||||
type: 'blob',
|
||||
size: {
|
||||
width: output.width,
|
||||
height: output.height
|
||||
}
|
||||
};
|
||||
return this.editor.result(options)
|
||||
.then(blob => this.newPhoto.blob = blob)
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
const {Report, Email} = require('vn-print');
|
||||
|
||||
module.exports = Self => {
|
||||
Self.printReport = async function(ctx, id, reportName) {
|
||||
const args = Object.assign({}, ctx.args);
|
||||
const params = {lang: ctx.req.getLocale()};
|
||||
|
||||
delete args.ctx;
|
||||
for (const param in args)
|
||||
params[param] = args[param];
|
||||
|
||||
const report = new Report(reportName, params);
|
||||
const stream = await report.toPdfStream();
|
||||
|
||||
let fileName = `${reportName}`;
|
||||
if (id) fileName += `-${id}`;
|
||||
|
||||
return [stream, 'application/pdf', `filename="${fileName}.pdf"`];
|
||||
};
|
||||
|
||||
Self.printEmail = async function(ctx, id, templateName) {
|
||||
const {accessToken} = ctx.req;
|
||||
const args = Object.assign({}, ctx.args);
|
||||
const params = {lang: ctx.req.getLocale()};
|
||||
|
||||
delete args.ctx;
|
||||
for (const param in args)
|
||||
params[param] = args[param];
|
||||
|
||||
params.isPreview = true;
|
||||
params.access_token = accessToken.id;
|
||||
|
||||
const report = new Email(templateName, params);
|
||||
const html = await report.render();
|
||||
|
||||
let fileName = `${templateName}`;
|
||||
if (id) fileName += `-${id}`;
|
||||
|
||||
return [html, 'text/html', `filename=${fileName}.pdf"`];
|
||||
};
|
||||
|
||||
Self.sendTemplate = async function(ctx, templateName) {
|
||||
const args = Object.assign({}, ctx.args);
|
||||
const params = {
|
||||
recipient: args.recipient,
|
||||
lang: ctx.req.getLocale()
|
||||
};
|
||||
|
||||
delete args.ctx;
|
||||
for (const param in args)
|
||||
params[param] = args[param];
|
||||
|
||||
const email = new Email(templateName, params);
|
||||
|
||||
return email.send();
|
||||
};
|
||||
};
|
|
@ -1,6 +1,20 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
describe('Model crud()', () => {
|
||||
beforeAll(async() => {
|
||||
const activeCtx = {
|
||||
accessToken: {userId: 9},
|
||||
http: {
|
||||
req: {
|
||||
headers: {origin: 'http://localhost'}
|
||||
}
|
||||
}
|
||||
};
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||
active: activeCtx
|
||||
});
|
||||
});
|
||||
let insertId;
|
||||
const barcodeModel = app.models.ItemBarcode;
|
||||
|
||||
|
|
|
@ -1,6 +1,21 @@
|
|||
const models = require('vn-loopback/server/server').models;
|
||||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
describe('Model rewriteDbError()', () => {
|
||||
beforeAll(async() => {
|
||||
const activeCtx = {
|
||||
accessToken: {userId: 9},
|
||||
http: {
|
||||
req: {
|
||||
headers: {origin: 'http://localhost'}
|
||||
}
|
||||
}
|
||||
};
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||
active: activeCtx
|
||||
});
|
||||
});
|
||||
|
||||
it('should extend rewriteDbError properties to any model passed', () => {
|
||||
const exampleModel = models.ItemTag;
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
const pick = require('object.pick');
|
||||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
module.exports = function(Self) {
|
||||
|
@ -6,344 +5,11 @@ module.exports = function(Self) {
|
|||
Self.super_.setup.call(this);
|
||||
};
|
||||
|
||||
Self.observe('after save', async function(ctx) {
|
||||
const loopBackContext = LoopBackContext.getCurrentContext();
|
||||
await logInModel(ctx, loopBackContext);
|
||||
});
|
||||
|
||||
Self.observe('before save', async function(ctx) {
|
||||
const appModels = ctx.Model.app.models;
|
||||
const definition = ctx.Model.definition;
|
||||
const options = {};
|
||||
|
||||
// Check for transactions
|
||||
if (ctx.options && ctx.options.transaction)
|
||||
options.transaction = ctx.options.transaction;
|
||||
|
||||
let oldInstance;
|
||||
let newInstance;
|
||||
|
||||
if (ctx.data) {
|
||||
const changes = pick(ctx.currentInstance, Object.keys(ctx.data));
|
||||
newInstance = ctx.data;
|
||||
oldInstance = changes;
|
||||
|
||||
if (ctx.where && !ctx.currentInstance) {
|
||||
const fields = Object.keys(ctx.data);
|
||||
const modelName = definition.name;
|
||||
|
||||
ctx.oldInstances = await appModels[modelName].find({
|
||||
where: ctx.where,
|
||||
fields: fields
|
||||
}, options);
|
||||
}
|
||||
}
|
||||
|
||||
// Get changes from created instance
|
||||
if (ctx.isNewInstance)
|
||||
newInstance = ctx.instance.__data;
|
||||
|
||||
ctx.hookState.oldInstance = oldInstance;
|
||||
ctx.hookState.newInstance = newInstance;
|
||||
ctx.options.httpCtx = LoopBackContext.getCurrentContext();
|
||||
});
|
||||
|
||||
Self.observe('before delete', async function(ctx) {
|
||||
const appModels = ctx.Model.app.models;
|
||||
const definition = ctx.Model.definition;
|
||||
const relations = ctx.Model.relations;
|
||||
|
||||
let options = {};
|
||||
if (ctx.options && ctx.options.transaction)
|
||||
options.transaction = ctx.options.transaction;
|
||||
|
||||
if (ctx.where) {
|
||||
let affectedModel = definition.name;
|
||||
let deletedInstances = await appModels[affectedModel].find({
|
||||
where: ctx.where
|
||||
}, options);
|
||||
|
||||
let relation = definition.settings.log.relation;
|
||||
|
||||
if (relation) {
|
||||
let primaryKey = relations[relation].keyFrom;
|
||||
|
||||
let arrangedDeletedInstances = [];
|
||||
for (let i = 0; i < deletedInstances.length; i++) {
|
||||
if (primaryKey)
|
||||
deletedInstances[i].originFk = deletedInstances[i][primaryKey];
|
||||
let arrangedInstance = await fkToValue(deletedInstances[i], ctx);
|
||||
arrangedDeletedInstances[i] = arrangedInstance;
|
||||
}
|
||||
ctx.hookState.oldInstance = arrangedDeletedInstances;
|
||||
}
|
||||
}
|
||||
ctx.options.httpCtx = LoopBackContext.getCurrentContext();
|
||||
});
|
||||
|
||||
Self.observe('after delete', async function(ctx) {
|
||||
const loopBackContext = LoopBackContext.getCurrentContext();
|
||||
if (ctx.hookState.oldInstance)
|
||||
logDeletedInstances(ctx, loopBackContext);
|
||||
});
|
||||
|
||||
async function logDeletedInstances(ctx, loopBackContext) {
|
||||
const appModels = ctx.Model.app.models;
|
||||
const definition = ctx.Model.definition;
|
||||
let options = {};
|
||||
if (ctx.options && ctx.options.transaction)
|
||||
options.transaction = ctx.options.transaction;
|
||||
|
||||
ctx.hookState.oldInstance.forEach(async instance => {
|
||||
let userFk;
|
||||
if (loopBackContext)
|
||||
userFk = loopBackContext.active.accessToken.userId;
|
||||
|
||||
let changedModelValue = definition.settings.log.changedModelValue;
|
||||
let logRecord = {
|
||||
originFk: instance.originFk,
|
||||
userFk: userFk,
|
||||
action: 'delete',
|
||||
changedModel: definition.name,
|
||||
changedModelId: instance.id,
|
||||
changedModelValue: instance[changedModelValue],
|
||||
oldInstance: instance,
|
||||
newInstance: {}
|
||||
};
|
||||
|
||||
delete instance.originFk;
|
||||
|
||||
let logModel = definition.settings.log.model;
|
||||
await appModels[logModel].create(logRecord, options);
|
||||
});
|
||||
}
|
||||
|
||||
// Get log values from a foreign key
|
||||
async function fkToValue(instance, ctx) {
|
||||
const appModels = ctx.Model.app.models;
|
||||
const relations = ctx.Model.relations;
|
||||
let options = {};
|
||||
|
||||
// Check for transactions
|
||||
if (ctx.options && ctx.options.transaction)
|
||||
options.transaction = ctx.options.transaction;
|
||||
|
||||
const instanceCopy = JSON.parse(JSON.stringify(instance));
|
||||
const result = {};
|
||||
for (const key in instanceCopy) {
|
||||
let value = instanceCopy[key];
|
||||
|
||||
if (value instanceof Object)
|
||||
continue;
|
||||
|
||||
if (value === undefined) continue;
|
||||
|
||||
if (value) {
|
||||
for (let relationName in relations) {
|
||||
const relation = relations[relationName];
|
||||
if (relation.keyFrom == key && key != 'id') {
|
||||
const model = relation.modelTo;
|
||||
const modelName = relation.modelTo.modelName;
|
||||
const properties = model && model.definition.properties;
|
||||
const settings = model && model.definition.settings;
|
||||
|
||||
const recordSet = await appModels[modelName].findById(value, null, options);
|
||||
|
||||
const hasShowField = settings.log && settings.log.showField;
|
||||
let showField = hasShowField && recordSet
|
||||
&& recordSet[settings.log.showField];
|
||||
|
||||
if (!showField) {
|
||||
const showFieldNames = [
|
||||
'name',
|
||||
'description',
|
||||
'code',
|
||||
'nickname'
|
||||
];
|
||||
for (field of showFieldNames) {
|
||||
const propField = properties && properties[field];
|
||||
const recordField = recordSet && recordSet[field];
|
||||
|
||||
if (propField && recordField) {
|
||||
showField = field;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (showField && recordSet && recordSet[showField]) {
|
||||
value = recordSet[showField];
|
||||
break;
|
||||
}
|
||||
|
||||
value = recordSet && recordSet.id || value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
result[key] = value;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
async function logInModel(ctx, loopBackContext) {
|
||||
const appModels = ctx.Model.app.models;
|
||||
const definition = ctx.Model.definition;
|
||||
const defSettings = ctx.Model.definition.settings;
|
||||
const relations = ctx.Model.relations;
|
||||
|
||||
const options = {};
|
||||
if (ctx.options && ctx.options.transaction)
|
||||
options.transaction = ctx.options.transaction;
|
||||
|
||||
let primaryKey;
|
||||
for (let property in definition.properties) {
|
||||
if (definition.properties[property].id) {
|
||||
primaryKey = property;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!primaryKey) throw new Error('Primary key not found');
|
||||
let originId;
|
||||
|
||||
// RELATIONS LOG
|
||||
let changedModelId;
|
||||
|
||||
if (ctx.instance && !defSettings.log.relation) {
|
||||
originId = ctx.instance.id;
|
||||
changedModelId = ctx.instance.id;
|
||||
} else if (defSettings.log.relation) {
|
||||
primaryKey = relations[defSettings.log.relation].keyFrom;
|
||||
|
||||
if (ctx.where && ctx.where[primaryKey])
|
||||
originId = ctx.where[primaryKey];
|
||||
else if (ctx.instance) {
|
||||
originId = ctx.instance[primaryKey];
|
||||
changedModelId = ctx.instance.id;
|
||||
}
|
||||
} else {
|
||||
originId = ctx.currentInstance.id;
|
||||
changedModelId = ctx.currentInstance.id;
|
||||
}
|
||||
|
||||
// Sets the changedModelValue to save and the instances changed in case its an updateAll
|
||||
let showField = defSettings.log.showField;
|
||||
let where;
|
||||
if (showField && (!ctx.instance || !ctx.instance[showField]) && ctx.where) {
|
||||
changedModelId = [];
|
||||
where = [];
|
||||
let changedInstances = await appModels[definition.name].find({
|
||||
where: ctx.where,
|
||||
fields: ['id', showField, primaryKey]
|
||||
}, options);
|
||||
|
||||
changedInstances.forEach(element => {
|
||||
where.push(element[showField]);
|
||||
changedModelId.push(element.id);
|
||||
originId = element[primaryKey];
|
||||
});
|
||||
} else if (ctx.hookState.oldInstance)
|
||||
where = ctx.instance[showField];
|
||||
|
||||
// Set oldInstance, newInstance, userFk and action
|
||||
let oldInstance = {};
|
||||
if (ctx.hookState.oldInstance)
|
||||
Object.assign(oldInstance, ctx.hookState.oldInstance);
|
||||
|
||||
let newInstance = {};
|
||||
if (ctx.hookState.newInstance)
|
||||
Object.assign(newInstance, ctx.hookState.newInstance);
|
||||
let userFk;
|
||||
if (loopBackContext)
|
||||
userFk = loopBackContext.active.accessToken.userId;
|
||||
|
||||
let action = setActionType(ctx);
|
||||
|
||||
removeUnloggable(definition, oldInstance);
|
||||
removeUnloggable(definition, newInstance);
|
||||
|
||||
oldInstance = await fkToValue(oldInstance, ctx);
|
||||
newInstance = await fkToValue(newInstance, ctx);
|
||||
|
||||
// Prevent log with no new changes
|
||||
const hasNewChanges = Object.keys(newInstance).length;
|
||||
if (!hasNewChanges) return;
|
||||
|
||||
let logRecord = {
|
||||
originFk: originId,
|
||||
userFk: userFk,
|
||||
action: action,
|
||||
changedModel: definition.name,
|
||||
changedModelId: changedModelId, // Model property with an different data type will throw a NaN error
|
||||
changedModelValue: where,
|
||||
oldInstance: oldInstance,
|
||||
newInstance: newInstance
|
||||
};
|
||||
|
||||
let logsToSave = setLogsToSave(where, changedModelId, logRecord, ctx);
|
||||
let logModel = defSettings.log.model;
|
||||
|
||||
await appModels[logModel].create(logsToSave, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes unwanted properties
|
||||
* @param {*} definition Model definition
|
||||
* @param {*} properties Modified object properties
|
||||
*/
|
||||
function removeUnloggable(definition, properties) {
|
||||
const objectCopy = Object.assign({}, properties);
|
||||
const propList = Object.keys(objectCopy);
|
||||
const propDefs = new Map();
|
||||
|
||||
for (let property in definition.properties) {
|
||||
const propertyDef = definition.properties[property];
|
||||
|
||||
propDefs.set(property, propertyDef);
|
||||
}
|
||||
|
||||
for (let property of propList) {
|
||||
const propertyDef = propDefs.get(property);
|
||||
const firstChar = property.substring(0, 1);
|
||||
const isPrivate = firstChar == '$';
|
||||
|
||||
if (isPrivate || !propertyDef)
|
||||
delete properties[property];
|
||||
|
||||
if (!propertyDef) continue;
|
||||
|
||||
if (propertyDef.log === false || isPrivate)
|
||||
delete properties[property];
|
||||
else if (propertyDef.logValue === false)
|
||||
properties[property] = null;
|
||||
}
|
||||
}
|
||||
|
||||
// this function retuns all the instances changed in case this is an updateAll
|
||||
function setLogsToSave(changedInstances, changedInstancesIds, logRecord, ctx) {
|
||||
let promises = [];
|
||||
if (changedInstances && typeof changedInstances == 'object') {
|
||||
for (let i = 0; i < changedInstances.length; i++) {
|
||||
logRecord.changedModelId = changedInstancesIds[i];
|
||||
logRecord.changedModelValue = changedInstances[i];
|
||||
if (ctx.oldInstances)
|
||||
logRecord.oldInstance = ctx.oldInstances[i];
|
||||
promises.push(JSON.parse(JSON.stringify(logRecord)));
|
||||
}
|
||||
} else
|
||||
return logRecord;
|
||||
|
||||
return promises;
|
||||
}
|
||||
|
||||
function setActionType(ctx) {
|
||||
let oldInstance = ctx.hookState.oldInstance;
|
||||
let newInstance = ctx.hookState.newInstance;
|
||||
|
||||
if (oldInstance && newInstance)
|
||||
return 'update';
|
||||
else if (!oldInstance && newInstance)
|
||||
return 'insert';
|
||||
|
||||
return 'delete';
|
||||
}
|
||||
};
|
||||
|
|
|
@ -7,6 +7,7 @@ module.exports = function(Self) {
|
|||
|
||||
require('../methods/vn-model/getSetValues')(Self);
|
||||
require('../methods/vn-model/getEnumValues')(Self);
|
||||
require('../methods/vn-model/printService')(Self);
|
||||
|
||||
Object.assign(Self, {
|
||||
setup() {
|
||||
|
|
|
@ -152,5 +152,7 @@
|
|||
"It is not possible to modify sales that their articles are from Floramondo": "It is not possible to modify sales that their articles are from Floramondo",
|
||||
"It is not possible to modify cloned sales": "It is not possible to modify cloned sales",
|
||||
"Valid priorities: 1,2,3": "Valid priorities: 1,2,3",
|
||||
"Warehouse inventory not set": "Almacén inventario no está establecido",
|
||||
"Component cost not set": "Componente coste no está estabecido",
|
||||
"Tickets with associated refunds can't be deleted. This ticket is associated with refund Nº 2": "Tickets with associated refunds can't be deleted. This ticket is associated with refund Nº 2"
|
||||
}
|
|
@ -251,6 +251,7 @@
|
|||
"Receipt's bank was not found": "No se encontró el banco del recibo",
|
||||
"This receipt was not compensated": "Este recibo no ha sido compensado",
|
||||
"Client's email was not found": "No se encontró el email del cliente",
|
||||
"Negative basis": "Base negativa",
|
||||
"This worker code already exists": "Este codigo de trabajador ya existe",
|
||||
"This personal mail already exists": "Este correo personal ya existe",
|
||||
"This worker already exists": "Este trabajador ya existe",
|
||||
|
@ -264,7 +265,15 @@
|
|||
"It is not possible to modify cloned sales": "No es posible modificar líneas de pedido clonadas",
|
||||
"A supplier with the same name already exists. Change the country.": "Un proveedor con el mismo nombre ya existe. Cambie el país.",
|
||||
"There is no assigned email for this client": "No hay correo asignado para este cliente",
|
||||
"This locker has already been assigned": "Esta taquilla ya ha sido asignada",
|
||||
"Exists an invoice with a previous date": "Existe una factura con fecha anterior",
|
||||
"Invoice date can't be less than max date": "La fecha de factura no puede ser inferior a la fecha límite",
|
||||
"Warehouse inventory not set": "El almacén inventario no está establecido",
|
||||
"This locker has already been assigned": "Esta taquilla ya ha sido asignada",
|
||||
"Tickets with associated refunds": "No se pueden borrar tickets con abonos asociados. Este ticket está asociado al abono Nº {{id}}",
|
||||
"Not exist this branch": "La rama no existe"
|
||||
"Not exist this branch": "La rama no existe",
|
||||
"This ticket cannot be signed because it has not been boxed": "Este ticket no puede firmarse porque no ha sido encajado",
|
||||
"Insert a date range": "Inserte un rango de fechas",
|
||||
"Added observation": "{{user}} añadió esta observacion: {{text}}",
|
||||
"Comment added to client": "Observación añadida al cliente {{clientFk}}",
|
||||
"Cannot create a new claimBeginning from a different ticket": "No se puede crear una línea de reclamación de un ticket diferente al origen"
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
const mysql = require('mysql');
|
||||
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
|
||||
const MySQL = require('loopback-connector-mysql').MySQL;
|
||||
const EnumFactory = require('loopback-connector-mysql').EnumFactory;
|
||||
const {Transaction, SQLConnector, ParameterizedSQL} = require('loopback-connector');
|
||||
const fs = require('fs');
|
||||
|
||||
class VnMySQL extends MySQL {
|
||||
|
@ -219,6 +219,101 @@ class VnMySQL extends MySQL {
|
|||
this.makePagination(filter)
|
||||
]);
|
||||
}
|
||||
|
||||
create(model, data, opts, cb) {
|
||||
const ctx = {data};
|
||||
this.invokeMethod('create',
|
||||
arguments, model, ctx, opts, cb);
|
||||
}
|
||||
|
||||
createAll(model, data, opts, cb) {
|
||||
const ctx = {data};
|
||||
this.invokeMethod('createAll',
|
||||
arguments, model, ctx, opts, cb);
|
||||
}
|
||||
|
||||
save(model, data, opts, cb) {
|
||||
const ctx = {data};
|
||||
this.invokeMethod('save',
|
||||
arguments, model, ctx, opts, cb);
|
||||
}
|
||||
|
||||
updateOrCreate(model, data, opts, cb) {
|
||||
const ctx = {data};
|
||||
this.invokeMethod('updateOrCreate',
|
||||
arguments, model, ctx, opts, cb);
|
||||
}
|
||||
|
||||
replaceOrCreate(model, data, opts, cb) {
|
||||
const ctx = {data};
|
||||
this.invokeMethod('replaceOrCreate',
|
||||
arguments, model, ctx, opts, cb);
|
||||
}
|
||||
|
||||
destroyAll(model, where, opts, cb) {
|
||||
const ctx = {where};
|
||||
this.invokeMethod('destroyAll',
|
||||
arguments, model, ctx, opts, cb);
|
||||
}
|
||||
|
||||
update(model, where, data, opts, cb) {
|
||||
const ctx = {where, data};
|
||||
this.invokeMethod('update',
|
||||
arguments, model, ctx, opts, cb);
|
||||
}
|
||||
|
||||
replaceById(model, id, data, opts, cb) {
|
||||
const ctx = {id, data};
|
||||
this.invokeMethod('replaceById',
|
||||
arguments, model, ctx, opts, cb);
|
||||
}
|
||||
|
||||
isLoggable(model) {
|
||||
const Model = this.getModelDefinition(model).model;
|
||||
const settings = Model.definition.settings;
|
||||
return settings.base && settings.base === 'Loggable';
|
||||
}
|
||||
|
||||
invokeMethod(method, args, model, ctx, opts, cb) {
|
||||
if (!this.isLoggable(model))
|
||||
return super[method].apply(this, args);
|
||||
|
||||
this.invokeMethodP(method, [...args], model, ctx, opts)
|
||||
.then(res => cb(...[null].concat(res)), cb);
|
||||
}
|
||||
|
||||
async invokeMethodP(method, args, model, ctx, opts) {
|
||||
const Model = this.getModelDefinition(model).model;
|
||||
let tx;
|
||||
if (!opts.transaction) {
|
||||
tx = await Transaction.begin(this, {});
|
||||
opts = Object.assign({transaction: tx, httpCtx: opts.httpCtx}, opts);
|
||||
}
|
||||
|
||||
try {
|
||||
const userId = opts.httpCtx && opts.httpCtx.active.accessToken.userId;
|
||||
if (userId) {
|
||||
const user = await Model.app.models.Account.findById(userId, {fields: ['name']}, opts);
|
||||
await this.executeP(`CALL account.myUser_loginWithName(?)`, [user.name], opts);
|
||||
}
|
||||
|
||||
const res = await new Promise((resolve, reject) => {
|
||||
const fnArgs = args.slice(0, -2);
|
||||
fnArgs.push(opts, (err, ...args) => {
|
||||
if (err) return reject(err);
|
||||
resolve(args);
|
||||
});
|
||||
super[method].apply(this, fnArgs);
|
||||
});
|
||||
|
||||
if (userId) await this.executeP(`CALL account.myUser_logout()`, null, opts);
|
||||
if (tx) await tx.commit();
|
||||
return res;
|
||||
} catch (err) {
|
||||
if (tx) tx.rollback();
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exports.VnMySQL = VnMySQL;
|
||||
|
@ -233,7 +328,7 @@ exports.initialize = function initialize(dataSource, callback) {
|
|||
modelBuilder.defineValueType.bind(modelBuilder) :
|
||||
modelBuilder.constructor.registerType.bind(modelBuilder.constructor);
|
||||
|
||||
defineType(function Point() {});
|
||||
defineType(function Point() { });
|
||||
|
||||
dataSource.EnumFactory = EnumFactory;
|
||||
|
||||
|
@ -341,3 +436,28 @@ function generateOptions(settings) {
|
|||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
SQLConnector.prototype.all = function find(model, filter, options, cb) {
|
||||
const self = this;
|
||||
// Order by id if no order is specified
|
||||
filter = filter || {};
|
||||
const stmt = this.buildSelect(model, filter, options);
|
||||
this.execute(stmt.sql, stmt.params, options, function(err, data) {
|
||||
if (err)
|
||||
return cb(err, []);
|
||||
|
||||
try {
|
||||
const objs = data.map(function(obj) {
|
||||
return self.fromRow(model, obj);
|
||||
});
|
||||
if (filter && filter.include) {
|
||||
self.getModelDefinition(model).model.include(
|
||||
objs, filter.include, options, cb,
|
||||
);
|
||||
} else
|
||||
cb(null, objs);
|
||||
} catch (error) {
|
||||
cb(error, []);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
|
@ -91,7 +91,11 @@ exports.getChanges = (original, changes) => {
|
|||
const isPrivate = firstChar == '$';
|
||||
if (isPrivate) return;
|
||||
|
||||
if (changes[property] != original[property]) {
|
||||
const hasChanges = original[property] instanceof Date ?
|
||||
changes[property]?.getTime() != original[property]?.getTime() :
|
||||
changes[property] != original[property];
|
||||
|
||||
if (hasChanges) {
|
||||
newChanges[property] = changes[property];
|
||||
|
||||
if (original[property] != undefined)
|
||||
|
|
|
@ -27,12 +27,12 @@ module.exports = Self => {
|
|||
if (typeof options == 'object')
|
||||
Object.assign(myOptions, options);
|
||||
|
||||
const state = await models.ClaimState.findById(id, {
|
||||
include: {
|
||||
relation: 'writeRole'
|
||||
}
|
||||
}, myOptions);
|
||||
const roleWithGrants = state && state.writeRole().name;
|
||||
return await models.Account.hasRole(userId, roleWithGrants, myOptions);
|
||||
const state = await models.ClaimState.findById(id, {
|
||||
include: {
|
||||
relation: 'writeRole'
|
||||
}
|
||||
}, myOptions);
|
||||
const roleWithGrants = state && state.writeRole().name;
|
||||
return await models.Account.hasRole(userId, roleWithGrants, myOptions);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
const { Report } = require('vn-print');
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('claimPickupPdf', {
|
||||
description: 'Returns the claim pickup order pdf',
|
||||
|
@ -39,17 +37,5 @@ module.exports = Self => {
|
|||
}
|
||||
});
|
||||
|
||||
Self.claimPickupPdf = async(ctx, id) => {
|
||||
const args = Object.assign({}, ctx.args);
|
||||
const params = {lang: ctx.req.getLocale()};
|
||||
|
||||
delete args.ctx;
|
||||
for (const param in args)
|
||||
params[param] = args[param];
|
||||
|
||||
const report = new Report('claim-pickup-order', params);
|
||||
const stream = await report.toPdfStream();
|
||||
|
||||
return [stream, 'application/pdf', `filename="doc-${id}.pdf"`];
|
||||
};
|
||||
Self.claimPickupPdf = (ctx, id) => Self.printReport(ctx, id, 'claim-pickup-order');
|
||||
};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
|
||||
const buildFilter = require('vn-loopback/util/filter').buildFilter;
|
||||
const {mergeFilters, mergeWhere} = require('vn-loopback/util/filter');
|
||||
const { mergeFilters, mergeWhere } = require('vn-loopback/util/filter');
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('logs', {
|
||||
|
@ -12,27 +12,27 @@ module.exports = Self => {
|
|||
arg: 'id',
|
||||
type: 'Number',
|
||||
description: 'The claim id',
|
||||
http: {source: 'path'}
|
||||
http: { source: 'path' }
|
||||
},
|
||||
{
|
||||
arg: 'filter',
|
||||
type: 'object',
|
||||
http: {source: 'query'}
|
||||
http: { source: 'query' }
|
||||
},
|
||||
{
|
||||
arg: 'search',
|
||||
type: 'string',
|
||||
http: {source: 'query'}
|
||||
http: { source: 'query' }
|
||||
},
|
||||
{
|
||||
arg: 'userFk',
|
||||
type: 'number',
|
||||
http: {source: 'query'}
|
||||
http: { source: 'query' }
|
||||
},
|
||||
{
|
||||
arg: 'created',
|
||||
type: 'date',
|
||||
http: {source: 'query'}
|
||||
http: { source: 'query' }
|
||||
},
|
||||
],
|
||||
returns: {
|
||||
|
@ -45,7 +45,7 @@ module.exports = Self => {
|
|||
}
|
||||
});
|
||||
|
||||
Self.logs = async(ctx, id, filter, options) => {
|
||||
Self.logs = async (ctx, id, filter, options) => {
|
||||
const conn = Self.dataSource.connector;
|
||||
const args = ctx.args;
|
||||
const myOptions = {};
|
||||
|
@ -56,25 +56,25 @@ module.exports = Self => {
|
|||
|
||||
let where = buildFilter(args, (param, value) => {
|
||||
switch (param) {
|
||||
case 'search':
|
||||
return {
|
||||
or: [
|
||||
{changedModel: {like: `%${value}%`}},
|
||||
{oldInstance: {like: `%${value}%`}}
|
||||
]
|
||||
};
|
||||
case 'userFk':
|
||||
return {'cl.userFk': value};
|
||||
case 'created':
|
||||
value.setHours(0, 0, 0, 0);
|
||||
to = new Date(value);
|
||||
to.setHours(23, 59, 59, 999);
|
||||
case 'search':
|
||||
return {
|
||||
or: [
|
||||
{ changedModel: { like: `%${value}%` } },
|
||||
{ oldInstance: { like: `%${value}%` } }
|
||||
]
|
||||
};
|
||||
case 'userFk':
|
||||
return { 'cl.userFk': value };
|
||||
case 'created':
|
||||
value.setHours(0, 0, 0, 0);
|
||||
to = new Date(value);
|
||||
to.setHours(23, 59, 59, 999);
|
||||
|
||||
return {creationDate: {between: [value, to]}};
|
||||
return { creationDate: { between: [value, to] } };
|
||||
}
|
||||
});
|
||||
where = mergeWhere(where, {['cl.originFk']: id});
|
||||
filter = mergeFilters(args.filter, {where});
|
||||
where = mergeWhere(where, { ['cl.originFk']: id });
|
||||
filter = mergeFilters(args.filter, { where });
|
||||
|
||||
const stmts = [];
|
||||
|
||||
|
@ -102,8 +102,8 @@ module.exports = Self => {
|
|||
const logs = [];
|
||||
for (const row of result) {
|
||||
const changes = [];
|
||||
const oldInstance = JSON.parse(row.oldInstance);
|
||||
const newInstance = JSON.parse(row.newInstance);
|
||||
const oldInstance = JSON.parse(row.oldInstance) || {};
|
||||
const newInstance = JSON.parse(row.newInstance) || {};
|
||||
const mergedProperties = [...Object.keys(oldInstance), ...Object.keys(newInstance)];
|
||||
const properties = new Set(mergedProperties);
|
||||
for (const property of properties) {
|
||||
|
|
|
@ -2,9 +2,9 @@ const models = require('vn-loopback/server/server').models;
|
|||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
describe('Claim createFromSales()', () => {
|
||||
const ticketId = 16;
|
||||
const ticketId = 23;
|
||||
const newSale = [{
|
||||
id: 3,
|
||||
id: 31,
|
||||
instance: 0,
|
||||
quantity: 10
|
||||
}];
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
const models = require('vn-loopback/server/server').models;
|
||||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
describe('claim regularizeClaim()', () => {
|
||||
const userId = 18;
|
||||
|
@ -39,6 +40,20 @@ describe('claim regularizeClaim()', () => {
|
|||
return await models.ClaimEnd.create(claimEnds, options);
|
||||
}
|
||||
|
||||
beforeAll(async() => {
|
||||
const activeCtx = {
|
||||
accessToken: {userId: 9},
|
||||
http: {
|
||||
req: {
|
||||
headers: {origin: 'http://localhost'}
|
||||
}
|
||||
}
|
||||
};
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||
active: activeCtx
|
||||
});
|
||||
});
|
||||
|
||||
it('should send a chat message with value "Trash" and then change claim state to resolved', async() => {
|
||||
const tx = await models.Claim.beginTransaction({});
|
||||
|
||||
|
|
|
@ -1,6 +1,20 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
describe('Update Claim', () => {
|
||||
beforeAll(async() => {
|
||||
const activeCtx = {
|
||||
accessToken: {userId: 9},
|
||||
http: {
|
||||
req: {
|
||||
headers: {origin: 'http://localhost'}
|
||||
}
|
||||
}
|
||||
};
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||
active: activeCtx
|
||||
});
|
||||
});
|
||||
const newDate = Date.vnNew();
|
||||
const originalData = {
|
||||
ticketFk: 3,
|
||||
|
|
|
@ -1,6 +1,20 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
describe('Update Claim', () => {
|
||||
beforeAll(async() => {
|
||||
const activeCtx = {
|
||||
accessToken: {userId: 9},
|
||||
http: {
|
||||
req: {
|
||||
headers: {origin: 'http://localhost'}
|
||||
}
|
||||
}
|
||||
};
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||
active: activeCtx
|
||||
});
|
||||
});
|
||||
const newDate = Date.vnNew();
|
||||
const original = {
|
||||
ticketFk: 3,
|
||||
|
|
|
@ -10,8 +10,16 @@ module.exports = Self => {
|
|||
});
|
||||
|
||||
Self.observe('before save', async ctx => {
|
||||
if (ctx.isNewInstance) return;
|
||||
//await claimIsEditable(ctx);
|
||||
if (ctx.isNewInstance) {
|
||||
const models = Self.app.models;
|
||||
const options = ctx.options;
|
||||
const instance = ctx.instance;
|
||||
const ticket = await models.Sale.findById(instance.saleFk, {fields: ['ticketFk']}, options);
|
||||
const claim = await models.Claim.findById(instance.claimFk, {fields: ['ticketFk']}, options);
|
||||
if (ticket.ticketFk != claim.ticketFk)
|
||||
throw new UserError(`Cannot create a new claimBeginning from a different ticket`);
|
||||
}
|
||||
// await claimIsEditable(ctx);
|
||||
});
|
||||
|
||||
Self.observe('before delete', async ctx => {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue